diff --git a/libs/design-system/button-toggle/README.md b/libs/design-system/button-toggle/README.md new file mode 100644 index 000000000..09bf81768 --- /dev/null +++ b/libs/design-system/button-toggle/README.md @@ -0,0 +1,3 @@ +# @hra-ui/design-system/button-toggle + +Secondary entry point of `@hra-ui/design-system`. It can be used by importing from `@hra-ui/design-system/button-toggle`. diff --git a/libs/design-system/button-toggle/ng-package.json b/libs/design-system/button-toggle/ng-package.json new file mode 100644 index 000000000..c781f0df4 --- /dev/null +++ b/libs/design-system/button-toggle/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "src/index.ts" + } +} diff --git a/libs/design-system/button-toggle/src/index.ts b/libs/design-system/button-toggle/src/index.ts new file mode 100644 index 000000000..e194182f8 --- /dev/null +++ b/libs/design-system/button-toggle/src/index.ts @@ -0,0 +1 @@ +export * from './lib/providers'; diff --git a/libs/design-system/button-toggle/src/lib/button-toggle-size/button-toggle-size.directive.ts b/libs/design-system/button-toggle/src/lib/button-toggle-size/button-toggle-size.directive.ts new file mode 100644 index 000000000..0350a3b8b --- /dev/null +++ b/libs/design-system/button-toggle/src/lib/button-toggle-size/button-toggle-size.directive.ts @@ -0,0 +1,50 @@ +import { computed, Directive, input } from '@angular/core'; + +/** Input options for icon button size */ +export type IconButtonSize = 'medium' | 'large'; + +/** Interface for ButtonToggle Config */ +interface ButtonToggleConfig { + /** Line height of the button */ + lineHeight: number; + /** Font variable of the button toggle */ + font: string; +} + +/** Record of button sizes (number in rem) */ +const BUTTON_CONFIG: Record = { + medium: { + lineHeight: 21, + font: '--sys-label-medium', + }, + large: { + lineHeight: 24, + font: '--sys-label-large', + }, +}; + +/** + * Directive for icon buttons + */ +@Directive({ + selector: '[hraButtonToggleSize]', + standalone: true, + host: { + '[style.--mat-standard-button-toggle-height]': 'lineHeight()', + '[style.--mat-standard-button-toggle-label-text-line-height]': 'lineHeight()', + '[style.font]': 'fontVar()', + }, +}) +export class ToggleButtonSizeDirective { + /** Size of icon button to use */ + readonly size = input.required({ alias: 'hraButtonToggleSize' }); + + /** Gets size of button in rem */ + protected readonly buttonSize = computed(() => BUTTON_CONFIG[this.size()]); + + /** Gets the font variable for the current button size */ + protected readonly fontVar = computed(() => `var(${BUTTON_CONFIG[this.size()].font})`); + + /** Gets the line height for the current button size */ + protected readonly lineHeight = computed(() => `${BUTTON_CONFIG[this.size()].lineHeight}px`); +} diff --git a/libs/design-system/button-toggle/src/lib/button-toggle-styles/button-toggle-styles.component.scss b/libs/design-system/button-toggle/src/lib/button-toggle-styles/button-toggle-styles.component.scss new file mode 100644 index 000000000..4d3196477 --- /dev/null +++ b/libs/design-system/button-toggle/src/lib/button-toggle-styles/button-toggle-styles.component.scss @@ -0,0 +1,43 @@ +mat-button-toggle-group { + --mat-standard-button-toggle-shape: 0.25rem; + --mat-standard-button-toggle-divider-color: var(--sys-primary); + --mat-standard-button-toggle-selected-state-background-color: var(--sys-tertiary); + --mat-standard-button-toggle-selected-state-text-color: var(--sys-on-primary); + --mat-standard-button-toggle-hover-state-layer-opacity: 0.04; + width: 100%; + + &.mat-button-toggle-group-appearance-standard { + border: unset; + outline: solid 1px var(--mat-standard-button-toggle-divider-color); + } + + .mat-button-toggle { + width: 100%; + + &:active { + --mat-standard-button-toggle-hover-state-layer-opacity: 0.08; + } + } + + .mat-button-toggle:not(.mat-button-toggle-checked) .mat-button-toggle-button { + padding: 0.5rem 1.15rem; + } + + .mat-button-toggle.mat-button-toggle-checked .mat-button-toggle-button { + padding: 0.5rem 0.2rem; + } + + &[hraButtonToggleSize='medium'] { + .mat-button-toggle:not(.mat-button-toggle-checked) .mat-button-toggle-button { + padding: 0.3438rem 1.15rem; + } + + .mat-button-toggle.mat-button-toggle-checked .mat-button-toggle-button { + padding: 0.3438rem 0.2rem; + } + + .mat-button-toggle .mat-button-toggle-label-content { + vertical-align: middle; + } + } +} diff --git a/libs/design-system/button-toggle/src/lib/button-toggle-styles/button-toggle-styles.component.ts b/libs/design-system/button-toggle/src/lib/button-toggle-styles/button-toggle-styles.component.ts new file mode 100644 index 000000000..9f1a2c490 --- /dev/null +++ b/libs/design-system/button-toggle/src/lib/button-toggle-styles/button-toggle-styles.component.ts @@ -0,0 +1,14 @@ +import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core'; + +/** + * Applies button toggle styles globally + */ +@Component({ + selector: 'hra-button-toggle-styles', + standalone: true, + template: '', + styleUrls: ['./button-toggle-styles.component.scss'], + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ButtonToggleStylesComponent {} diff --git a/libs/design-system/button-toggle/src/lib/button-toggle.component.stories.ts b/libs/design-system/button-toggle/src/lib/button-toggle.component.stories.ts new file mode 100644 index 000000000..42a59416b --- /dev/null +++ b/libs/design-system/button-toggle/src/lib/button-toggle.component.stories.ts @@ -0,0 +1,69 @@ +import { applicationConfig, Meta, moduleMetadata, StoryObj } from '@storybook/angular'; +import { MatButtonToggleModule } from '@angular/material/button-toggle'; +import { provideButtonToggle } from './providers'; +import { ToggleButtonSizeDirective } from './button-toggle-size/button-toggle-size.directive'; +const meta: Meta = { + title: 'ButtonToggleComponent', + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/design/BCEJn9KCIbBJ5MzqnojKQp/Design-System-Components?node-id=853-284', + }, + }, + decorators: [ + applicationConfig({ + providers: [provideButtonToggle()], + }), + moduleMetadata({ + imports: [MatButtonToggleModule, ToggleButtonSizeDirective], + }), + ], +}; +export default meta; +type Story = StoryObj; + +export const SingleSelect: Story = { + args: { + size: 'large', + }, + argTypes: { + size: { + control: 'select', + options: ['medium', 'large'], + }, + }, + render: (args) => ({ + props: args, + template: ` + + Button + Button + Button + + `, + }), +}; + +export const MultiSelect: Story = { + args: { + size: 'large', + }, + argTypes: { + size: { + control: 'select', + options: ['medium', 'large'], + }, + }, + render: (args) => ({ + props: args, + template: ` + + Button + Button + Button + + `, + }), +}; diff --git a/libs/design-system/button-toggle/src/lib/providers.ts b/libs/design-system/button-toggle/src/lib/providers.ts new file mode 100644 index 000000000..f489b1f55 --- /dev/null +++ b/libs/design-system/button-toggle/src/lib/providers.ts @@ -0,0 +1,10 @@ +import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core'; +import { provideStyleComponents } from '@hra-ui/cdk/styling'; +import { ButtonToggleStylesComponent } from './button-toggle-styles/button-toggle-styles.component'; + +/** + * Returns providers for button toggle + */ +export function provideButtonToggle(): EnvironmentProviders { + return makeEnvironmentProviders([provideStyleComponents(ButtonToggleStylesComponent)]); +} diff --git a/tsconfig.base.json b/tsconfig.base.json index 5a5c9fd6f..2fb91e8bc 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -77,6 +77,9 @@ "@hra-ui/design-system/button": [ "libs/design-system/button/src/index.ts" ], + "@hra-ui/design-system/button-toggle": [ + "libs/design-system/button-toggle/src/index.ts" + ], "@hra-ui/design-system/footer": [ "libs/design-system/footer/src/index.ts" ],