From 8d7f0d4b3ea907d403b411b308deacc62d93d4f7 Mon Sep 17 00:00:00 2001 From: Dima Karimov Date: Sat, 21 Aug 2021 01:42:40 +0300 Subject: [PATCH 1/3] feat(toggle): allow configuration of default options --- .../components/toggle/examples/2/index.html | 13 ++++ .../components/toggle/examples/2/index.ts | 40 +++++++++++ .../toggle/examples/import/define-options.txt | 25 +++++++ .../components/toggle/toggle.component.ts | 9 +++ .../components/toggle/toggle.module.ts | 3 +- .../components/toggle/toggle.template.html | 22 ++++++ projects/kit/components/toggle/index.ts | 1 + .../kit/components/toggle/toggle-options.ts | 28 ++++++++ .../kit/components/toggle/toggle.component.ts | 31 +++++--- .../kit/components/toggle/toggle.module.ts | 2 + .../kit/components/toggle/toggle.style.less | 4 ++ .../components/toggle/toggle.template.html | 71 ++++++++++++------- 12 files changed, 214 insertions(+), 35 deletions(-) create mode 100644 projects/demo/src/modules/components/toggle/examples/2/index.html create mode 100644 projects/demo/src/modules/components/toggle/examples/2/index.ts create mode 100644 projects/demo/src/modules/components/toggle/examples/import/define-options.txt create mode 100644 projects/kit/components/toggle/toggle-options.ts diff --git a/projects/demo/src/modules/components/toggle/examples/2/index.html b/projects/demo/src/modules/components/toggle/examples/2/index.html new file mode 100644 index 000000000000..dbd6fe2d418b --- /dev/null +++ b/projects/demo/src/modules/components/toggle/examples/2/index.html @@ -0,0 +1,13 @@ +
+
+ + + + +
+
diff --git a/projects/demo/src/modules/components/toggle/examples/2/index.ts b/projects/demo/src/modules/components/toggle/examples/2/index.ts new file mode 100644 index 000000000000..c6f884b5e380 --- /dev/null +++ b/projects/demo/src/modules/components/toggle/examples/2/index.ts @@ -0,0 +1,40 @@ +import {Component} from '@angular/core'; +import {FormControl, FormGroup} from '@angular/forms'; +import { + ToggleOptions, + TUI_TOGGLE_DEFAULT_OPTIONS, + TUI_TOGGLE_OPTIONS, +} from '@taiga-ui/kit'; +import {changeDetection} from '../../../../../change-detection-strategy'; +import {encapsulation} from '../../../../../view-encapsulation'; + +const options: ToggleOptions = { + icons: { + toggleOff: ({$implicit}) => + $implicit === 'm' ? 'tuiIconChevronRight' : 'tuiIconChevronRightLarge', + toggleOn: ({$implicit}) => + $implicit === 'm' ? 'tuiIconChevronLeft' : 'tuiIconChevronLeftLarge', + }, +}; + +@Component({ + selector: 'tui-toggle-example-2', + templateUrl: './index.html', + changeDetection, + encapsulation, + providers: [ + { + provide: TUI_TOGGLE_OPTIONS, + useValue: { + ...TUI_TOGGLE_DEFAULT_OPTIONS, + ...options, + }, + }, + ], +}) +export class TuiToggleExample2 { + testForm = new FormGroup({ + testValue1: new FormControl(true), + testValue2: new FormControl(false), + }); +} diff --git a/projects/demo/src/modules/components/toggle/examples/import/define-options.txt b/projects/demo/src/modules/components/toggle/examples/import/define-options.txt new file mode 100644 index 000000000000..c30e9cb93f5c --- /dev/null +++ b/projects/demo/src/modules/components/toggle/examples/import/define-options.txt @@ -0,0 +1,25 @@ +import { + ToggleOptions, + TUI_TOGGLE_DEFAULT_OPTIONS, + TUI_TOGGLE_OPTIONS, +} from '@taiga-ui/kit'; + +... +const options: ToggleOptions = { + icons: { + toggleOff: ({$implicit}) => + $implicit === 'm' ? 'tuiIconChevronRight' : 'tuiIconChevronRightLarge', + toggleOn: ({$implicit}) => + $implicit === 'm' ? 'tuiIconChevronLeft' : 'tuiIconChevronLeftLarge', + }, +}; + +@NgModule({ + providers: [{ + provide: TUI_TOGGLE_OPTIONS, + useValue: { + ...TUI_TOGGLE_DEFAULT_OPTIONS, + ...options, + } + }], +... diff --git a/projects/demo/src/modules/components/toggle/toggle.component.ts b/projects/demo/src/modules/components/toggle/toggle.component.ts index a300c626feb1..a3f4ea4fd2b2 100644 --- a/projects/demo/src/modules/components/toggle/toggle.component.ts +++ b/projects/demo/src/modules/components/toggle/toggle.component.ts @@ -1,7 +1,10 @@ import {default as example1Html} from '!!raw-loader!./examples/1/index.html'; import {default as example1Ts} from '!!raw-loader!./examples/1/index.ts'; +import {default as example2Html} from '!!raw-loader!./examples/2/index.html'; +import {default as example2Ts} from '!!raw-loader!./examples/2/index.ts'; import {default as exampleDeclareForm} from '!!raw-loader!./examples/import/declare-form.txt'; +import {default as exampleDefineOptions} from '!!raw-loader!./examples/import/define-options.txt'; import {default as exampleImportModule} from '!!raw-loader!./examples/import/import-module.txt'; import {default as exampleInsertTemplate} from '!!raw-loader!./examples/import/insert-template.txt'; @@ -28,12 +31,18 @@ export class ExampleTuiToggleComponent extends AbstractExampleTuiInteractive { readonly exampleDeclareForm = exampleDeclareForm; readonly exampleImportModule = exampleImportModule; readonly exampleInsertTemplate = exampleInsertTemplate; + readonly exampleDefineOptions = exampleDefineOptions; readonly example1: FrontEndExample = { TypeScript: example1Ts, HTML: example1Html, }; + readonly example2: FrontEndExample = { + TypeScript: example2Ts, + HTML: example2Html, + }; + showIcons = false; showLoader = false; diff --git a/projects/demo/src/modules/components/toggle/toggle.module.ts b/projects/demo/src/modules/components/toggle/toggle.module.ts index 05ae8f45696e..08355e2a115b 100644 --- a/projects/demo/src/modules/components/toggle/toggle.module.ts +++ b/projects/demo/src/modules/components/toggle/toggle.module.ts @@ -6,6 +6,7 @@ import {generateRoutes, TuiAddonDocModule} from '@taiga-ui/addon-doc'; import {TuiToggleModule} from '@taiga-ui/kit'; import {InheritedDocumentationModule} from '../abstract/inherited-documentation/inherited-documentation.module'; import {TuiToggleExample1} from './examples/1'; +import {TuiToggleExample2} from './examples/2'; import {ExampleTuiToggleComponent} from './toggle.component'; @NgModule({ @@ -18,7 +19,7 @@ import {ExampleTuiToggleComponent} from './toggle.component'; CommonModule, RouterModule.forChild(generateRoutes(ExampleTuiToggleComponent)), ], - declarations: [ExampleTuiToggleComponent, TuiToggleExample1], + declarations: [ExampleTuiToggleComponent, TuiToggleExample1, TuiToggleExample2], exports: [ExampleTuiToggleComponent], }) export class ExampleTuiToggleModule {} diff --git a/projects/demo/src/modules/components/toggle/toggle.template.html b/projects/demo/src/modules/components/toggle/toggle.template.html index 1a03b7a4f920..961f010a13f1 100644 --- a/projects/demo/src/modules/components/toggle/toggle.template.html +++ b/projects/demo/src/modules/components/toggle/toggle.template.html @@ -13,6 +13,15 @@ > + + + + @@ -112,6 +121,19 @@ [code]="exampleInsertTemplate" > + +
  • +

    + Optionally use the + TUI_TOGGLE_OPTIONS injection token to override + the default options for the component. +

    + + +
  • diff --git a/projects/kit/components/toggle/index.ts b/projects/kit/components/toggle/index.ts index 6cec914ec3c8..03464f789b0c 100644 --- a/projects/kit/components/toggle/index.ts +++ b/projects/kit/components/toggle/index.ts @@ -1,2 +1,3 @@ +export * from './toggle-options'; export * from './toggle.component'; export * from './toggle.module'; diff --git a/projects/kit/components/toggle/toggle-options.ts b/projects/kit/components/toggle/toggle-options.ts new file mode 100644 index 000000000000..4a161576dd86 --- /dev/null +++ b/projects/kit/components/toggle/toggle-options.ts @@ -0,0 +1,28 @@ +import {InjectionToken} from '@angular/core'; +import {TuiContextWithImplicit} from '@taiga-ui/cdk'; +import {TuiSizeL} from '@taiga-ui/core'; +import {PolymorpheusContent} from '@tinkoff/ng-polymorpheus'; + +export interface ToggleOptions { + readonly icons: Readonly<{ + toggleOff: PolymorpheusContent>; + toggleOn: PolymorpheusContent>; + }>; +} + +/** Default values for the toggle options. */ +export const TUI_TOGGLE_DEFAULT_OPTIONS: ToggleOptions = { + icons: { + toggleOff: ({$implicit}) => + $implicit === 'm' ? 'tuiIconToggleOff' : 'tuiIconToggleOffLarge', + toggleOn: ({$implicit}) => + $implicit === 'm' ? 'tuiIconToggleOn' : 'tuiIconToggleOnLarge', + }, +}; + +export const TUI_TOGGLE_OPTIONS = new InjectionToken( + 'Default parameters for toggle component', + { + factory: () => TUI_TOGGLE_DEFAULT_OPTIONS, + }, +); diff --git a/projects/kit/components/toggle/toggle.component.ts b/projects/kit/components/toggle/toggle.component.ts index 8f9afa01c714..9a5f316468a0 100644 --- a/projects/kit/components/toggle/toggle.component.ts +++ b/projects/kit/components/toggle/toggle.component.ts @@ -16,9 +16,11 @@ import { AbstractTuiControl, isNativeFocused, TUI_FOCUSABLE_ITEM_ACCESSOR, + TuiContextWithImplicit, tuiDefaultProp, TuiFocusableElementAccessor, TuiNativeFocusableElement, + tuiPure, } from '@taiga-ui/cdk'; import { TuiAppearance, @@ -27,6 +29,8 @@ import { TuiSizeL, TuiSizeXS, } from '@taiga-ui/core'; +import {PolymorpheusContent} from '@tinkoff/ng-polymorpheus'; +import {ToggleOptions, TUI_TOGGLE_OPTIONS} from './toggle-options'; @Component({ selector: 'tui-toggle', @@ -72,10 +76,29 @@ export class TuiToggleComponent @Optional() @Inject(TuiModeDirective) private readonly modeDirective: TuiModeDirective | null, + @Inject(TUI_TOGGLE_OPTIONS) + public readonly options: ToggleOptions, ) { super(control, changeDetectorRef); } + get iconOn(): PolymorpheusContent> { + return this.options.icons.toggleOn; + } + + get iconOff(): PolymorpheusContent> { + return this.options.icons.toggleOff; + } + + get context(): TuiContextWithImplicit { + return this.getContext(this.size); + } + + @tuiPure + private getContext($implicit: TuiSizeL): TuiContextWithImplicit { + return {$implicit}; + } + get nativeFocusableElement(): TuiNativeFocusableElement | null { return this.focusableElement ? this.focusableElement.nativeElement : null; } @@ -99,14 +122,6 @@ export class TuiToggleComponent return this.value; } - get iconOn(): string { - return this.sizeM ? 'tuiIconToggleOn' : 'tuiIconToggleOnLarge'; - } - - get iconOff(): string { - return this.sizeM ? 'tuiIconToggleOff' : 'tuiIconToggleOffLarge'; - } - get loaderSize(): TuiSizeXS { return this.sizeM ? 'xs' : 's'; } diff --git a/projects/kit/components/toggle/toggle.module.ts b/projects/kit/components/toggle/toggle.module.ts index 9f8f85a0ac0f..45ba02463162 100644 --- a/projects/kit/components/toggle/toggle.module.ts +++ b/projects/kit/components/toggle/toggle.module.ts @@ -9,6 +9,7 @@ import { TuiPressedModule, } from '@taiga-ui/cdk'; import {TuiLoaderModule, TuiSvgModule, TuiWrapperModule} from '@taiga-ui/core'; +import {PolymorpheusModule} from '@tinkoff/ng-polymorpheus'; import {TuiToggleComponent} from './toggle.component'; @NgModule({ @@ -23,6 +24,7 @@ import {TuiToggleComponent} from './toggle.component'; TuiWrapperModule, TuiSvgModule, TuiLoaderModule, + PolymorpheusModule, ], declarations: [TuiToggleComponent], exports: [TuiToggleComponent], diff --git a/projects/kit/components/toggle/toggle.style.less b/projects/kit/components/toggle/toggle.style.less index ab28c71a736f..35a58d7fb188 100644 --- a/projects/kit/components/toggle/toggle.style.less +++ b/projects/kit/components/toggle/toggle.style.less @@ -128,6 +128,10 @@ } } +.icon-wrapper { + display: flex; +} + .icon { opacity: 0.8; diff --git a/projects/kit/components/toggle/toggle.template.html b/projects/kit/components/toggle/toggle.template.html index 245014d39911..3478d134995d 100644 --- a/projects/kit/components/toggle/toggle.template.html +++ b/projects/kit/components/toggle/toggle.template.html @@ -7,33 +7,52 @@ [invalid]="computedInvalid" >
    - - + + + + + + +
    - - + + + + + +
    Date: Wed, 1 Sep 2021 19:12:02 +0300 Subject: [PATCH 2/3] fix(toggle): implement review notes --- .../components/toggle/examples/2/index.html | 2 +- .../components/toggle/examples/2/index.ts | 2 +- .../toggle/examples/import/define-options.txt | 2 +- .../kit/components/toggle/toggle-options.ts | 16 ++++++--- .../kit/components/toggle/toggle.component.ts | 16 ++------- .../components/toggle/toggle.template.html | 33 +++++++++---------- 6 files changed, 34 insertions(+), 37 deletions(-) diff --git a/projects/demo/src/modules/components/toggle/examples/2/index.html b/projects/demo/src/modules/components/toggle/examples/2/index.html index dbd6fe2d418b..a341af4451f9 100644 --- a/projects/demo/src/modules/components/toggle/examples/2/index.html +++ b/projects/demo/src/modules/components/toggle/examples/2/index.html @@ -1,6 +1,6 @@
    - + = { icons: { toggleOff: ({$implicit}) => $implicit === 'm' ? 'tuiIconChevronRight' : 'tuiIconChevronRightLarge', diff --git a/projects/demo/src/modules/components/toggle/examples/import/define-options.txt b/projects/demo/src/modules/components/toggle/examples/import/define-options.txt index c30e9cb93f5c..c63fbc9857ff 100644 --- a/projects/demo/src/modules/components/toggle/examples/import/define-options.txt +++ b/projects/demo/src/modules/components/toggle/examples/import/define-options.txt @@ -5,7 +5,7 @@ import { } from '@taiga-ui/kit'; ... -const options: ToggleOptions = { +const options: Partial = { icons: { toggleOff: ({$implicit}) => $implicit === 'm' ? 'tuiIconChevronRight' : 'tuiIconChevronRightLarge', diff --git a/projects/kit/components/toggle/toggle-options.ts b/projects/kit/components/toggle/toggle-options.ts index 4a161576dd86..7e15dbe3ce94 100644 --- a/projects/kit/components/toggle/toggle-options.ts +++ b/projects/kit/components/toggle/toggle-options.ts @@ -8,16 +8,24 @@ export interface ToggleOptions { toggleOff: PolymorpheusContent>; toggleOn: PolymorpheusContent>; }>; + readonly singleColor: boolean; + readonly showIcons: boolean; + readonly size: TuiSizeL; } /** Default values for the toggle options. */ export const TUI_TOGGLE_DEFAULT_OPTIONS: ToggleOptions = { icons: { - toggleOff: ({$implicit}) => - $implicit === 'm' ? 'tuiIconToggleOff' : 'tuiIconToggleOffLarge', - toggleOn: ({$implicit}) => - $implicit === 'm' ? 'tuiIconToggleOn' : 'tuiIconToggleOnLarge', + toggleOff({$implicit}: TuiContextWithImplicit): string { + return $implicit === 'm' ? 'tuiIconToggleOff' : 'tuiIconToggleOffLarge'; + }, + toggleOn({$implicit}: TuiContextWithImplicit): string { + return $implicit === 'm' ? 'tuiIconToggleOn' : 'tuiIconToggleOnLarge'; + }, }, + singleColor: false, + showIcons: false, + size: 'm', }; export const TUI_TOGGLE_OPTIONS = new InjectionToken( diff --git a/projects/kit/components/toggle/toggle.component.ts b/projects/kit/components/toggle/toggle.component.ts index 9a5f316468a0..6e78ef56e746 100644 --- a/projects/kit/components/toggle/toggle.component.ts +++ b/projects/kit/components/toggle/toggle.component.ts @@ -20,7 +20,6 @@ import { tuiDefaultProp, TuiFocusableElementAccessor, TuiNativeFocusableElement, - tuiPure, } from '@taiga-ui/cdk'; import { TuiAppearance, @@ -49,11 +48,11 @@ export class TuiToggleComponent implements TuiFocusableElementAccessor { @Input() @tuiDefaultProp() - singleColor = false; + singleColor = this.options.singleColor; @Input() @tuiDefaultProp() - showIcons = false; + showIcons = this.options.showIcons; @Input() @tuiDefaultProp() @@ -62,7 +61,7 @@ export class TuiToggleComponent @Input() @HostBinding('attr.data-tui-host-size') @tuiDefaultProp() - size: TuiSizeL = 'm'; + size: TuiSizeL = this.options.size; @ViewChild('focusableElement') private readonly focusableElement?: ElementRef; @@ -90,15 +89,6 @@ export class TuiToggleComponent return this.options.icons.toggleOff; } - get context(): TuiContextWithImplicit { - return this.getContext(this.size); - } - - @tuiPure - private getContext($implicit: TuiSizeL): TuiContextWithImplicit { - return {$implicit}; - } - get nativeFocusableElement(): TuiNativeFocusableElement | null { return this.focusableElement ? this.focusableElement.nativeElement : null; } diff --git a/projects/kit/components/toggle/toggle.template.html b/projects/kit/components/toggle/toggle.template.html index 3478d134995d..cacbafa17a6d 100644 --- a/projects/kit/components/toggle/toggle.template.html +++ b/projects/kit/components/toggle/toggle.template.html @@ -7,21 +7,20 @@ [invalid]="computedInvalid" >
    + - -
    + - Date: Wed, 1 Sep 2021 20:38:49 +0300 Subject: [PATCH 3/3] test(toggle): add tests for TUI_TOGGLE_OPTIONS --- .../components/toggle/examples/2/index.html | 4 +- .../components/toggle/examples/2/index.ts | 1 + .../toggle/test/toggle.component.spec.ts | 96 +++++++++++++++++++ 3 files changed, 98 insertions(+), 3 deletions(-) diff --git a/projects/demo/src/modules/components/toggle/examples/2/index.html b/projects/demo/src/modules/components/toggle/examples/2/index.html index a341af4451f9..c8fd26064fa8 100644 --- a/projects/demo/src/modules/components/toggle/examples/2/index.html +++ b/projects/demo/src/modules/components/toggle/examples/2/index.html @@ -1,12 +1,10 @@
    - - +
    diff --git a/projects/demo/src/modules/components/toggle/examples/2/index.ts b/projects/demo/src/modules/components/toggle/examples/2/index.ts index 9c506b0981cc..bb5c3e505455 100644 --- a/projects/demo/src/modules/components/toggle/examples/2/index.ts +++ b/projects/demo/src/modules/components/toggle/examples/2/index.ts @@ -15,6 +15,7 @@ const options: Partial = { toggleOn: ({$implicit}) => $implicit === 'm' ? 'tuiIconChevronLeft' : 'tuiIconChevronLeftLarge', }, + showIcons: true, }; @Component({ diff --git a/projects/kit/components/toggle/test/toggle.component.spec.ts b/projects/kit/components/toggle/test/toggle.component.spec.ts index d2e785bd36f9..da83db77c27b 100644 --- a/projects/kit/components/toggle/test/toggle.component.spec.ts +++ b/projects/kit/components/toggle/test/toggle.component.spec.ts @@ -3,6 +3,7 @@ import {ComponentFixture, TestBed} from '@angular/core/testing'; import {FormControl, ReactiveFormsModule} from '@angular/forms'; import {PageObject} from '@taiga-ui/testing'; import {configureTestSuite} from 'ng-bullet'; +import {TUI_TOGGLE_DEFAULT_OPTIONS, TUI_TOGGLE_OPTIONS} from '../toggle-options'; import {TuiToggleModule} from '../toggle.module'; describe('Toggle', () => { @@ -207,3 +208,98 @@ describe('Toggle', () => { } } }); + +describe('Toggle with TUI_TOGGLE_OPTIONS', () => { + @Component({ + template: ` + + `, + }) + class TestComponent { + control = new FormControl(); + showLoader = false; + } + + let fixture: ComponentFixture; + let testComponent: TestComponent; + let pageObject: PageObject; + const testContext = { + get prefix() { + return 'tui-toggle__'; + }, + }; + + configureTestSuite(() => { + TestBed.configureTestingModule({ + imports: [ReactiveFormsModule, TuiToggleModule], + declarations: [TestComponent], + providers: [ + { + provide: TUI_TOGGLE_OPTIONS, + useValue: { + ...TUI_TOGGLE_DEFAULT_OPTIONS, + showIcons: true, + }, + }, + ], + }); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(TestComponent); + pageObject = new PageObject(fixture); + testComponent = fixture.componentInstance; + }); + + describe('Icons', () => { + describe('showIcons === true', () => { + it('Icons are shown when toggle is "disabled"', () => { + testComponent.control.setValue(false); + fixture.detectChanges(); + + // If icons are enabled, then both are added to the DOM at once - + // implementation feature for smooth animation + isIconVisible(`${testContext.prefix}check-icon`); + isIconVisible(`${testContext.prefix}cancel-icon`); + }); + + it('Icons are shown when toggle is "on"', () => { + testComponent.control.setValue(true); + fixture.detectChanges(); + + isIconVisible(`${testContext.prefix}check-icon`); + isIconVisible(`${testContext.prefix}cancel-icon`); + }); + }); + }); + + describe('Loader', () => { + describe('showLoader === false', () => { + beforeEach(() => { + testComponent.showLoader = false; + }); + + it('Icons are shown when toggle is "disabled"', () => { + testComponent.control.setValue(false); + fixture.detectChanges(); + + isIconVisible(`${testContext.prefix}check-icon`); + isIconVisible(`${testContext.prefix}cancel-icon`); + }); + + it('Icons are shown when toggle is "on"', () => { + testComponent.control.setValue(true); + fixture.detectChanges(); + + isIconVisible(`${testContext.prefix}check-icon`); + isIconVisible(`${testContext.prefix}cancel-icon`); + }); + }); + }); + + function isIconVisible(tuiIconAutomationId: string) { + const icon = pageObject.getByAutomationId(tuiIconAutomationId); + + expect(icon).not.toBeNull(); + } +});