From e26cd5386ebcc466df10fa3d70fcac6f92b7adb3 Mon Sep 17 00:00:00 2001 From: Armin Ster Date: Tue, 17 May 2022 12:58:33 +0200 Subject: [PATCH] feat: chip --- apps/docs/src/app/app-routing.module.ts | 5 + apps/docs/src/app/app.component.ts | 4 + apps/docs/src/app/app.module.ts | 6 + .../appearances/appearances.component.html | 2 + .../appearances/appearances.component.scss | 5 + .../chip/appearances/appearances.component.ts | 10 ++ .../app/examples/chip/chip-examples.module.ts | 24 ++++ .../chip/filter/filter.component.html | 24 ++++ .../chip/filter/filter.component.scss | 6 + .../examples/chip/filter/filter.component.ts | 10 ++ .../chip/groups/groups.component.html | 19 +++ .../chip/groups/groups.component.scss | 6 + .../examples/chip/groups/groups.component.ts | 10 ++ .../chip/mandatory/mandatory.component.html | 14 +++ .../chip/mandatory/mandatory.component.scss | 6 + .../chip/mandatory/mandatory.component.ts | 10 ++ .../multiple-mandatory.component.html | 14 +++ .../multiple-mandatory.component.scss | 6 + .../multiple-mandatory.component.ts | 10 ++ .../chip/multiple/multiple.component.html | 14 +++ .../chip/multiple/multiple.component.scss | 6 + .../chip/multiple/multiple.component.ts | 10 ++ .../examples/chip/slots/slots.component.html | 27 ++++ .../examples/chip/slots/slots.component.scss | 5 + .../examples/chip/slots/slots.component.ts | 11 ++ .../chip-page/chip-page.component.html | 28 +++++ .../chip-page/chip-page.component.scss | 0 .../chip-page/chip-page.component.ts | 8 ++ libs/anglify/src/index.ts | 5 + libs/anglify/src/modules/chip/_variables.scss | 14 +++ .../src/modules/chip/chip-settings.token.ts | 10 ++ .../src/modules/chip/chip.component.html | 10 ++ .../src/modules/chip/chip.component.scss | 62 +++++++++ .../src/modules/chip/chip.component.spec.ts | 25 ++++ .../src/modules/chip/chip.component.ts | 118 ++++++++++++++++++ .../src/modules/chip/chip.interface.ts | 7 ++ libs/anglify/src/modules/chip/chip.module.ts | 12 ++ 37 files changed, 563 insertions(+) create mode 100644 apps/docs/src/app/examples/chip/appearances/appearances.component.html create mode 100644 apps/docs/src/app/examples/chip/appearances/appearances.component.scss create mode 100644 apps/docs/src/app/examples/chip/appearances/appearances.component.ts create mode 100644 apps/docs/src/app/examples/chip/chip-examples.module.ts create mode 100644 apps/docs/src/app/examples/chip/filter/filter.component.html create mode 100644 apps/docs/src/app/examples/chip/filter/filter.component.scss create mode 100644 apps/docs/src/app/examples/chip/filter/filter.component.ts create mode 100644 apps/docs/src/app/examples/chip/groups/groups.component.html create mode 100644 apps/docs/src/app/examples/chip/groups/groups.component.scss create mode 100644 apps/docs/src/app/examples/chip/groups/groups.component.ts create mode 100644 apps/docs/src/app/examples/chip/mandatory/mandatory.component.html create mode 100644 apps/docs/src/app/examples/chip/mandatory/mandatory.component.scss create mode 100644 apps/docs/src/app/examples/chip/mandatory/mandatory.component.ts create mode 100644 apps/docs/src/app/examples/chip/multiple-mandatory/multiple-mandatory.component.html create mode 100644 apps/docs/src/app/examples/chip/multiple-mandatory/multiple-mandatory.component.scss create mode 100644 apps/docs/src/app/examples/chip/multiple-mandatory/multiple-mandatory.component.ts create mode 100644 apps/docs/src/app/examples/chip/multiple/multiple.component.html create mode 100644 apps/docs/src/app/examples/chip/multiple/multiple.component.scss create mode 100644 apps/docs/src/app/examples/chip/multiple/multiple.component.ts create mode 100644 apps/docs/src/app/examples/chip/slots/slots.component.html create mode 100644 apps/docs/src/app/examples/chip/slots/slots.component.scss create mode 100644 apps/docs/src/app/examples/chip/slots/slots.component.ts create mode 100644 apps/docs/src/app/pages/component-pages/chip-page/chip-page.component.html create mode 100644 apps/docs/src/app/pages/component-pages/chip-page/chip-page.component.scss create mode 100644 apps/docs/src/app/pages/component-pages/chip-page/chip-page.component.ts create mode 100644 libs/anglify/src/modules/chip/_variables.scss create mode 100644 libs/anglify/src/modules/chip/chip-settings.token.ts create mode 100644 libs/anglify/src/modules/chip/chip.component.html create mode 100644 libs/anglify/src/modules/chip/chip.component.scss create mode 100644 libs/anglify/src/modules/chip/chip.component.spec.ts create mode 100644 libs/anglify/src/modules/chip/chip.component.ts create mode 100644 libs/anglify/src/modules/chip/chip.interface.ts create mode 100644 libs/anglify/src/modules/chip/chip.module.ts diff --git a/apps/docs/src/app/app-routing.module.ts b/apps/docs/src/app/app-routing.module.ts index 1c9f05e5..62afc495 100644 --- a/apps/docs/src/app/app-routing.module.ts +++ b/apps/docs/src/app/app-routing.module.ts @@ -4,6 +4,7 @@ import { BottomNavigationPageComponent } from './pages/component-pages/bottom-na import { ButtonPageComponent } from './pages/component-pages/button-page/button-page.component'; import { CardPageComponent } from './pages/component-pages/card-page/card-page.component'; import { CheckBoxPageComponent } from './pages/component-pages/checkbox-page/checkbox-page.component'; +import { ChipPageComponent } from './pages/component-pages/chip-page/chip-page.component'; import { DialogPageComponent } from './pages/component-pages/dialog-page/dialog-page.component'; import { FormFieldPageComponent } from './pages/component-pages/form-field-page/form-field-page.component'; import { IconPageComponent } from './pages/component-pages/icon-page/icon-page.component'; @@ -38,6 +39,10 @@ const routes: Routes = [ path: 'components/checkbox', component: CheckBoxPageComponent, }, + { + path: 'components/chip', + component: ChipPageComponent, + }, { path: 'components/dialog', component: DialogPageComponent, diff --git a/apps/docs/src/app/app.component.ts b/apps/docs/src/app/app.component.ts index 20b76026..426038fc 100644 --- a/apps/docs/src/app/app.component.ts +++ b/apps/docs/src/app/app.component.ts @@ -60,6 +60,10 @@ export class AppComponent { link: 'components/checkbox', name: 'Checkbox', }, + { + link: 'components/chip', + name: 'Chip', + }, { link: 'components/dialog', name: 'Dialog', diff --git a/apps/docs/src/app/app.module.ts b/apps/docs/src/app/app.module.ts index 909f40a9..eb01637f 100644 --- a/apps/docs/src/app/app.module.ts +++ b/apps/docs/src/app/app.module.ts @@ -3,6 +3,7 @@ import { ButtonModule, CardModule, CheckboxModule, + ChipModule, FormFieldModule, IconModule, ListModule, @@ -30,6 +31,7 @@ import { BottomNavigationExampleModule } from './examples/bottom-navigation/bott import { ButtonExamplesModule } from './examples/button/button-examples.module'; import { CardExamplesModule } from './examples/card/card-examples.module'; import { CheckBoxExamplesModule } from './examples/checkbox/checkbox-examples.module'; +import { ChipExamplesModule } from './examples/chip/chip-examples.module'; import { FormFieldExamplesModule } from './examples/form-field/form-field-examples.module'; import { IconExamplesModule } from './examples/icon/icon-examples.module'; import { ItemGroupExamplesModule } from './examples/item-group/item-group-examples.module'; @@ -48,6 +50,7 @@ import { BottomNavigationPageComponent } from './pages/component-pages/bottom-na import { ButtonPageComponent } from './pages/component-pages/button-page/button-page.component'; import { CardPageComponent } from './pages/component-pages/card-page/card-page.component'; import { CheckBoxPageComponent } from './pages/component-pages/checkbox-page/checkbox-page.component'; +import { ChipPageComponent } from './pages/component-pages/chip-page/chip-page.component'; import { DialogPageComponent } from './pages/component-pages/dialog-page/dialog-page.component'; import { FormFieldPageComponent } from './pages/component-pages/form-field-page/form-field-page.component'; import { IconPageComponent } from './pages/component-pages/icon-page/icon-page.component'; @@ -88,6 +91,7 @@ import { TooltipPageComponent } from './pages/component-pages/tooltip-page/toolt BottomNavigationPageComponent, SnackbarPageComponent, ItemGroupPageComponent, + ChipPageComponent, ], imports: [ BrowserModule, @@ -131,6 +135,8 @@ import { TooltipPageComponent } from './pages/component-pages/tooltip-page/toolt SnackbarModule, SnackbarExamplesModule, ItemGroupExamplesModule, + ChipModule, + ChipExamplesModule, ], providers: [ { diff --git a/apps/docs/src/app/examples/chip/appearances/appearances.component.html b/apps/docs/src/app/examples/chip/appearances/appearances.component.html new file mode 100644 index 00000000..69de85b4 --- /dev/null +++ b/apps/docs/src/app/examples/chip/appearances/appearances.component.html @@ -0,0 +1,2 @@ +Filled +Outlined diff --git a/apps/docs/src/app/examples/chip/appearances/appearances.component.scss b/apps/docs/src/app/examples/chip/appearances/appearances.component.scss new file mode 100644 index 00000000..e8b88706 --- /dev/null +++ b/apps/docs/src/app/examples/chip/appearances/appearances.component.scss @@ -0,0 +1,5 @@ +:host { + display: grid; + grid-template-columns: repeat(2, auto); + gap: 1rem; +} diff --git a/apps/docs/src/app/examples/chip/appearances/appearances.component.ts b/apps/docs/src/app/examples/chip/appearances/appearances.component.ts new file mode 100644 index 00000000..97f33bc0 --- /dev/null +++ b/apps/docs/src/app/examples/chip/appearances/appearances.component.ts @@ -0,0 +1,10 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; + +@Component({ + templateUrl: './appearances.component.html', + styleUrls: ['./appearances.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AppearancesComponent {} + +export default AppearancesComponent; diff --git a/apps/docs/src/app/examples/chip/chip-examples.module.ts b/apps/docs/src/app/examples/chip/chip-examples.module.ts new file mode 100644 index 00000000..8e4c64ee --- /dev/null +++ b/apps/docs/src/app/examples/chip/chip-examples.module.ts @@ -0,0 +1,24 @@ +import { ChipModule, IconModule, ItemGroupModule } from '@anglify/components'; +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { AppearancesComponent } from './appearances/appearances.component'; +import { FilterComponent } from './filter/filter.component'; +import { GroupsComponent } from './groups/groups.component'; +import { MandatoryComponent } from './mandatory/mandatory.component'; +import { MultipleMandatoryComponent } from './multiple-mandatory/multiple-mandatory.component'; +import { MultipleComponent } from './multiple/multiple.component'; +import { SlotsComponent } from './slots/slots.component'; + +@NgModule({ + declarations: [ + AppearancesComponent, + SlotsComponent, + GroupsComponent, + MandatoryComponent, + MultipleComponent, + FilterComponent, + MultipleMandatoryComponent, + ], + imports: [CommonModule, ChipModule, IconModule, ItemGroupModule], +}) +export class ChipExamplesModule {} diff --git a/apps/docs/src/app/examples/chip/filter/filter.component.html b/apps/docs/src/app/examples/chip/filter/filter.component.html new file mode 100644 index 00000000..ed82417e --- /dev/null +++ b/apps/docs/src/app/examples/chip/filter/filter.component.html @@ -0,0 +1,24 @@ + + + + + + + Filled + + + + Filled + + + + + + + + + + Outlined + + + diff --git a/apps/docs/src/app/examples/chip/filter/filter.component.scss b/apps/docs/src/app/examples/chip/filter/filter.component.scss new file mode 100644 index 00000000..027b2f94 --- /dev/null +++ b/apps/docs/src/app/examples/chip/filter/filter.component.scss @@ -0,0 +1,6 @@ +:host { + anglify-item-group { + display: flex; + gap: 1rem; + } +} diff --git a/apps/docs/src/app/examples/chip/filter/filter.component.ts b/apps/docs/src/app/examples/chip/filter/filter.component.ts new file mode 100644 index 00000000..15de259b --- /dev/null +++ b/apps/docs/src/app/examples/chip/filter/filter.component.ts @@ -0,0 +1,10 @@ +import { Component, ChangeDetectionStrategy } from '@angular/core'; + +@Component({ + templateUrl: './filter.component.html', + styleUrls: ['./filter.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class FilterComponent {} + +export default FilterComponent; diff --git a/apps/docs/src/app/examples/chip/groups/groups.component.html b/apps/docs/src/app/examples/chip/groups/groups.component.html new file mode 100644 index 00000000..3d4739de --- /dev/null +++ b/apps/docs/src/app/examples/chip/groups/groups.component.html @@ -0,0 +1,19 @@ + + + + + + + Chip 1 + + + + Chip 2 + + + Chip 3 + + + Chip 4 + + diff --git a/apps/docs/src/app/examples/chip/groups/groups.component.scss b/apps/docs/src/app/examples/chip/groups/groups.component.scss new file mode 100644 index 00000000..027b2f94 --- /dev/null +++ b/apps/docs/src/app/examples/chip/groups/groups.component.scss @@ -0,0 +1,6 @@ +:host { + anglify-item-group { + display: flex; + gap: 1rem; + } +} diff --git a/apps/docs/src/app/examples/chip/groups/groups.component.ts b/apps/docs/src/app/examples/chip/groups/groups.component.ts new file mode 100644 index 00000000..fab96026 --- /dev/null +++ b/apps/docs/src/app/examples/chip/groups/groups.component.ts @@ -0,0 +1,10 @@ +import { Component, ChangeDetectionStrategy } from '@angular/core'; + +@Component({ + templateUrl: './groups.component.html', + styleUrls: ['./groups.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class GroupsComponent {} + +export default GroupsComponent; diff --git a/apps/docs/src/app/examples/chip/mandatory/mandatory.component.html b/apps/docs/src/app/examples/chip/mandatory/mandatory.component.html new file mode 100644 index 00000000..03eba37b --- /dev/null +++ b/apps/docs/src/app/examples/chip/mandatory/mandatory.component.html @@ -0,0 +1,14 @@ + + + Chip 1 + + + Chip 2 + + + Chip 3 + + + Chip 4 + + diff --git a/apps/docs/src/app/examples/chip/mandatory/mandatory.component.scss b/apps/docs/src/app/examples/chip/mandatory/mandatory.component.scss new file mode 100644 index 00000000..027b2f94 --- /dev/null +++ b/apps/docs/src/app/examples/chip/mandatory/mandatory.component.scss @@ -0,0 +1,6 @@ +:host { + anglify-item-group { + display: flex; + gap: 1rem; + } +} diff --git a/apps/docs/src/app/examples/chip/mandatory/mandatory.component.ts b/apps/docs/src/app/examples/chip/mandatory/mandatory.component.ts new file mode 100644 index 00000000..aa808ae7 --- /dev/null +++ b/apps/docs/src/app/examples/chip/mandatory/mandatory.component.ts @@ -0,0 +1,10 @@ +import { Component, ChangeDetectionStrategy } from '@angular/core'; + +@Component({ + templateUrl: './mandatory.component.html', + styleUrls: ['./mandatory.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class MandatoryComponent {} + +export default MandatoryComponent; diff --git a/apps/docs/src/app/examples/chip/multiple-mandatory/multiple-mandatory.component.html b/apps/docs/src/app/examples/chip/multiple-mandatory/multiple-mandatory.component.html new file mode 100644 index 00000000..2f1e9489 --- /dev/null +++ b/apps/docs/src/app/examples/chip/multiple-mandatory/multiple-mandatory.component.html @@ -0,0 +1,14 @@ + + + Chip 1 + + + Chip 2 + + + Chip 3 + + + Chip 4 + + diff --git a/apps/docs/src/app/examples/chip/multiple-mandatory/multiple-mandatory.component.scss b/apps/docs/src/app/examples/chip/multiple-mandatory/multiple-mandatory.component.scss new file mode 100644 index 00000000..027b2f94 --- /dev/null +++ b/apps/docs/src/app/examples/chip/multiple-mandatory/multiple-mandatory.component.scss @@ -0,0 +1,6 @@ +:host { + anglify-item-group { + display: flex; + gap: 1rem; + } +} diff --git a/apps/docs/src/app/examples/chip/multiple-mandatory/multiple-mandatory.component.ts b/apps/docs/src/app/examples/chip/multiple-mandatory/multiple-mandatory.component.ts new file mode 100644 index 00000000..63b4b56c --- /dev/null +++ b/apps/docs/src/app/examples/chip/multiple-mandatory/multiple-mandatory.component.ts @@ -0,0 +1,10 @@ +import { Component, ChangeDetectionStrategy } from '@angular/core'; + +@Component({ + templateUrl: './multiple-mandatory.component.html', + styleUrls: ['./multiple-mandatory.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class MultipleMandatoryComponent {} + +export default MultipleMandatoryComponent; diff --git a/apps/docs/src/app/examples/chip/multiple/multiple.component.html b/apps/docs/src/app/examples/chip/multiple/multiple.component.html new file mode 100644 index 00000000..68eac70e --- /dev/null +++ b/apps/docs/src/app/examples/chip/multiple/multiple.component.html @@ -0,0 +1,14 @@ + + + Chip 1 + + + Chip 2 + + + Chip 3 + + + Chip 4 + + diff --git a/apps/docs/src/app/examples/chip/multiple/multiple.component.scss b/apps/docs/src/app/examples/chip/multiple/multiple.component.scss new file mode 100644 index 00000000..027b2f94 --- /dev/null +++ b/apps/docs/src/app/examples/chip/multiple/multiple.component.scss @@ -0,0 +1,6 @@ +:host { + anglify-item-group { + display: flex; + gap: 1rem; + } +} diff --git a/apps/docs/src/app/examples/chip/multiple/multiple.component.ts b/apps/docs/src/app/examples/chip/multiple/multiple.component.ts new file mode 100644 index 00000000..bdaf69b1 --- /dev/null +++ b/apps/docs/src/app/examples/chip/multiple/multiple.component.ts @@ -0,0 +1,10 @@ +import { Component, ChangeDetectionStrategy } from '@angular/core'; + +@Component({ + templateUrl: './multiple.component.html', + styleUrls: ['./multiple.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class MultipleComponent {} + +export default MultipleComponent; diff --git a/apps/docs/src/app/examples/chip/slots/slots.component.html b/apps/docs/src/app/examples/chip/slots/slots.component.html new file mode 100644 index 00000000..d685b6ec --- /dev/null +++ b/apps/docs/src/app/examples/chip/slots/slots.component.html @@ -0,0 +1,27 @@ + + + + + Icon left + + + + + + + Icon right + + + + + + + Icon left + + + + + + + Icon right + diff --git a/apps/docs/src/app/examples/chip/slots/slots.component.scss b/apps/docs/src/app/examples/chip/slots/slots.component.scss new file mode 100644 index 00000000..19841ba7 --- /dev/null +++ b/apps/docs/src/app/examples/chip/slots/slots.component.scss @@ -0,0 +1,5 @@ +:host { + display: grid; + grid-template-columns: repeat(4, auto); + gap: 1rem; +} diff --git a/apps/docs/src/app/examples/chip/slots/slots.component.ts b/apps/docs/src/app/examples/chip/slots/slots.component.ts new file mode 100644 index 00000000..8c33af97 --- /dev/null +++ b/apps/docs/src/app/examples/chip/slots/slots.component.ts @@ -0,0 +1,11 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; + +@Component({ + selector: 'anglify-slots', + templateUrl: './slots.component.html', + styleUrls: ['./slots.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class SlotsComponent {} + +export default SlotsComponent; diff --git a/apps/docs/src/app/pages/component-pages/chip-page/chip-page.component.html b/apps/docs/src/app/pages/component-pages/chip-page/chip-page.component.html new file mode 100644 index 00000000..fee9cc4f --- /dev/null +++ b/apps/docs/src/app/pages/component-pages/chip-page/chip-page.component.html @@ -0,0 +1,28 @@ +

Chip

+ +

Examples

+ +

Appearances

+ + +

Slots

+ + +

Standard Group

+ + +

Mandatory Chip

+ + +

Multiple Selectable Chips

+ + +

Multiple Mandatory Selectable Chips

+ + +

Filter

+ + +

API

+

Styling

+ diff --git a/apps/docs/src/app/pages/component-pages/chip-page/chip-page.component.scss b/apps/docs/src/app/pages/component-pages/chip-page/chip-page.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/apps/docs/src/app/pages/component-pages/chip-page/chip-page.component.ts b/apps/docs/src/app/pages/component-pages/chip-page/chip-page.component.ts new file mode 100644 index 00000000..e1cc5c15 --- /dev/null +++ b/apps/docs/src/app/pages/component-pages/chip-page/chip-page.component.ts @@ -0,0 +1,8 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'anglify-chip-page', + templateUrl: './chip-page.component.html', + styleUrls: ['./chip-page.component.scss'], +}) +export class ChipPageComponent {} diff --git a/libs/anglify/src/index.ts b/libs/anglify/src/index.ts index 10453fb0..e70efefe 100644 --- a/libs/anglify/src/index.ts +++ b/libs/anglify/src/index.ts @@ -15,6 +15,11 @@ export * from './modules/checkbox/tokens/checkbox.token'; export * from './modules/checkbox/checkbox.component'; export * from './modules/checkbox/functions/register-icons.function'; export * from './modules/checkbox/checkbox.module'; +// Chip +export * from './modules/chip/chip-settings.token'; +export * from './modules/chip/chip.interface'; +export * from './modules/chip/chip.component'; +export * from './modules/chip/chip.module'; // Common export * from './modules/common/directives/slot/slot.directive'; export * from './modules/common/directives/slot-outlet/slot-outlet.directive'; diff --git a/libs/anglify/src/modules/chip/_variables.scss b/libs/anglify/src/modules/chip/_variables.scss new file mode 100644 index 00000000..0bd820c5 --- /dev/null +++ b/libs/anglify/src/modules/chip/_variables.scss @@ -0,0 +1,14 @@ +$chip-border-radius: var(--anglify-chip-border-radius, 16px); +$chip-height: var(--anglify-chip-height, 20px); +$chip-padding: var(--anglify-chip-padding, 6px 12px); +$chip-background-color: var(--anglify-chip-background-color, var(--color-surface-overlay)); +$chip-text-decoration: var(--anglify-chip-text-decoration, none); +$chip-cursor: var(--anglify-chip-cursor, default); +$chip-inline-padding-start-dense: var(--anglify-chip-inline-padding-start-dense, 5px); +$chip-inline-padding-end-dense: var(--anglify-chip-inline-padding-end-dense, 5px); +$chip-outlined-border: var(--anglify-chip-outlined-border, 1px solid var(--border-color-on-surface-low-emphasis)); +$chip-group-gap: var(--anglify-chip-group-gap, 16px); +$chip-filter-prepend-width: var(--anglify-chip-filter-prepend-width, 30px); +$chip-filter-transition-speed: var(--anglify-chip-filter-transition-speed, all 250ms); +$chip-hover-state-color: var(--anglify-hover-state-color, var(--color-primary-state-hover)) !default; +$chip-focus-state-color: var(--anglify-focus-state-color, var(--color-primary-state-focus)) !default; diff --git a/libs/anglify/src/modules/chip/chip-settings.token.ts b/libs/anglify/src/modules/chip/chip-settings.token.ts new file mode 100644 index 00000000..4db613c2 --- /dev/null +++ b/libs/anglify/src/modules/chip/chip-settings.token.ts @@ -0,0 +1,10 @@ +import { InjectionToken } from '@angular/core'; +import type { ChipSettings } from './chip.interface'; + +export const DEFAULT_CHIP_SETTINGS: Required = { + appearance: 'filled', + filter: false, + ripple: false, +}; + +export const CHIP_SETTINGS = new InjectionToken>('Chip Settings'); diff --git a/libs/anglify/src/modules/chip/chip.component.html b/libs/anglify/src/modules/chip/chip.component.html new file mode 100644 index 00000000..e3294af1 --- /dev/null +++ b/libs/anglify/src/modules/chip/chip.component.html @@ -0,0 +1,10 @@ +
+ +
+
+ +
+ +
+ +
diff --git a/libs/anglify/src/modules/chip/chip.component.scss b/libs/anglify/src/modules/chip/chip.component.scss new file mode 100644 index 00000000..f9f09c69 --- /dev/null +++ b/libs/anglify/src/modules/chip/chip.component.scss @@ -0,0 +1,62 @@ +@use 'variables' as *; + +:host { + display: inline-flex; + align-items: center; + text-decoration: $chip-text-decoration; + border-radius: $chip-border-radius; + padding: $chip-padding; + min-height: $chip-height; + height: 1px; + cursor: $chip-cursor; + + &:hover { + --state-container-color: #{$chip-hover-state-color}; + } + + &:focus-visible { + --state-container-color: #{$chip-focus-state-color}; + } + + .prepend, + .append { + --state-container-color: transparent; + } + + &.filter { + .prepend { + opacity: 0; + width: 0; + transform: translate(calc(-1 * $chip-filter-prepend-width), 0); + transition: $chip-filter-transition-speed; + } + + &.active { + .prepend { + opacity: 1; + width: $chip-filter-prepend-width; + transform: translate(0, 0); + } + } + } + + &.active { + --state-container-color: var(--color-primary-state-focus); + } + + &.filled { + background-color: $chip-background-color; + } + + &.outlined { + border: $chip-outlined-border; + } + + &.has-left-icon { + padding-inline-start: $chip-inline-padding-start-dense; + } + + &.has-right-icon { + padding-inline-end: $chip-inline-padding-end-dense; + } +} diff --git a/libs/anglify/src/modules/chip/chip.component.spec.ts b/libs/anglify/src/modules/chip/chip.component.spec.ts new file mode 100644 index 00000000..26af70cc --- /dev/null +++ b/libs/anglify/src/modules/chip/chip.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ChipComponent } from './chip.component'; +import { AnglifyCommonModule } from '../common/anglify-common.module'; + +describe('ChipComponent', () => { + let component: ChipComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ChipComponent], + imports: [AnglifyCommonModule], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ChipComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/libs/anglify/src/modules/chip/chip.component.ts b/libs/anglify/src/modules/chip/chip.component.ts new file mode 100644 index 00000000..61b679d0 --- /dev/null +++ b/libs/anglify/src/modules/chip/chip.component.ts @@ -0,0 +1,118 @@ +import { + ChangeDetectionStrategy, + Component, + ContentChildren, + ElementRef, + EventEmitter, + HostBinding, + HostListener, + Inject, + Input, + OnInit, + Output, + QueryList, + Self, +} from '@angular/core'; +import { UntilDestroy } from '@ngneat/until-destroy'; +import { BehaviorSubject } from 'rxjs'; +import { CHIP_SETTINGS, DEFAULT_CHIP_SETTINGS } from './chip-settings.token'; +import { ChipAppearance, ChipSettings } from './chip.interface'; +import { RIPPLE } from '../../composables/ripple/ripple.provider'; +import { RippleService } from '../../composables/ripple/ripple.service'; +import { createSettingsProvider } from '../../factories/settings.factory'; +import { bindClassToNativeElement, toBoolean } from '../../utils/functions'; +import { BooleanLike } from '../../utils/interfaces'; +import { SlotDirective } from '../common/directives/slot/slot.directive'; + +@UntilDestroy() +@Component({ + selector: 'anglify-chip', + templateUrl: './chip.component.html', + styleUrls: ['./chip.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [createSettingsProvider('anglifyChipSettings', DEFAULT_CHIP_SETTINGS, CHIP_SETTINGS), RIPPLE], +}) +export class ChipComponent implements OnInit { + @ContentChildren(SlotDirective) public readonly slots?: QueryList; + + @Input() + public set active(value: BooleanLike) { + this.active$.next(toBoolean(value)); + } + + public get active() { + return this.active$.value; + } + + @Input('filter') public filter: BooleanLike = this.settings.filter; + + @Input() public appearance: ChipAppearance = this.settings.appearance; + + @Input() + public set ripple(value: BooleanLike) { + this.rippleService.active = toBoolean(value); + } + + public get ripple(): boolean { + return this.rippleService.active; + } + + @Output() public readonly onClick = new EventEmitter(); + + public readonly active$ = new BehaviorSubject(false); + + public constructor( + private readonly elementRef: ElementRef, + @Self() @Inject('anglifyChipSettings') public settings: Required, + private readonly rippleService: RippleService + ) { + bindClassToNativeElement(this, this.active$, this.elementRef.nativeElement, 'active'); + } + + public ngOnInit(): void { + const children = Array.from(this.elementRef.nativeElement.children); + const hasLeftIcon = children.some(child => { + if (child.tagName === 'ANGLIFY-ICON') { + const right = Array.from(child.attributes).some(attribute => attribute.name === 'left'); + return Boolean(right); + } + return false; + }); + + const hasRightIcon = children.some(child => { + if (child.tagName === 'ANGLIFY-ICON') { + const right = Array.from(child.attributes).some(attribute => attribute.name === 'right'); + return Boolean(right); + } + return false; + }); + + if (hasLeftIcon) { + this.elementRef.nativeElement.classList.add('has-left-icon'); + } + if (hasRightIcon) { + this.elementRef.nativeElement.classList.add('has-right-icon'); + } + } + + @HostBinding('class') + protected get classList() { + const classNames: string[] = [this.appearance]; + + if (toBoolean(this.filter)) { + classNames.push('filter'); + } + + return classNames.join(' '); + } + + @HostBinding('tabindex') + // @ts-expect-error + private readonly tabindex = 0; + + @HostListener('click') + // @ts-expect-error + private click() { + this.onClick.next(); + } +} diff --git a/libs/anglify/src/modules/chip/chip.interface.ts b/libs/anglify/src/modules/chip/chip.interface.ts new file mode 100644 index 00000000..c957c38a --- /dev/null +++ b/libs/anglify/src/modules/chip/chip.interface.ts @@ -0,0 +1,7 @@ +export type ChipAppearance = 'filled' | 'outlined'; + +export interface ChipSettings { + appearance?: ChipAppearance; + filter?: boolean; + ripple?: boolean; +} diff --git a/libs/anglify/src/modules/chip/chip.module.ts b/libs/anglify/src/modules/chip/chip.module.ts new file mode 100644 index 00000000..eb3e8d14 --- /dev/null +++ b/libs/anglify/src/modules/chip/chip.module.ts @@ -0,0 +1,12 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { ChipComponent } from './chip.component'; +import { AnglifyCommonModule } from '../common/anglify-common.module'; +import { IconModule } from '../icon/icon.module'; + +@NgModule({ + declarations: [ChipComponent], + imports: [AnglifyCommonModule, CommonModule, IconModule], + exports: [AnglifyCommonModule, ChipComponent], +}) +export class ChipModule {}