From a73e99b15ad39d698c33815101f6e8fa19c2c898 Mon Sep 17 00:00:00 2001 From: German Panov Date: Fri, 27 Sep 2024 17:08:27 +0300 Subject: [PATCH] chore(demo): `DocAPIItem` value reflect in URL (#9225) --- .../components/api/api-item.component.ts | 71 ++++++++++++++++++- .../components/api/api-item.template.html | 8 +-- .../tests/core/button/button.spec.ts | 2 +- 3 files changed, 74 insertions(+), 7 deletions(-) diff --git a/projects/addon-doc/components/api/api-item.component.ts b/projects/addon-doc/components/api/api-item.component.ts index e35f6d803e63..c88011668237 100644 --- a/projects/addon-doc/components/api/api-item.component.ts +++ b/projects/addon-doc/components/api/api-item.component.ts @@ -1,12 +1,18 @@ -import {NgForOf, NgIf, NgSwitch, NgSwitchCase} from '@angular/common'; +import {Location, NgForOf, NgIf, NgSwitch, NgSwitchCase} from '@angular/common'; import { ChangeDetectionStrategy, Component, EventEmitter, + inject, Input, + type OnInit, Output, } from '@angular/core'; import {FormsModule} from '@angular/forms'; +import {ActivatedRoute, type Params, UrlSerializer} from '@angular/router'; +import {TUI_DOC_URL_STATE_HANDLER} from '@taiga-ui/addon-doc/tokens'; +import {tuiCoerceValue} from '@taiga-ui/addon-doc/utils'; +import {tuiIsNumber} from '@taiga-ui/cdk/utils/miscellaneous'; import {TuiIcon} from '@taiga-ui/core/components/icon'; import {TuiTextfield} from '@taiga-ui/core/components/textfield'; import {TuiDataListWrapper} from '@taiga-ui/kit/components/data-list-wrapper'; @@ -18,6 +24,8 @@ import {TuiTextfieldControllerModule} from '@taiga-ui/legacy/directives/textfiel import {TuiInspectPipe} from '../documentation/pipes/inspect.pipe'; import {TuiDocTypeReferencePipe} from '../documentation/pipes/type-reference.pipe'; +const SERIALIZED_SUFFIX = '$'; + @Component({ standalone: true, selector: 'tr[tuiDocAPIItem]', @@ -41,7 +49,12 @@ import {TuiDocTypeReferencePipe} from '../documentation/pipes/type-reference.pip styleUrls: ['./api-item.style.less'], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class TuiDocAPIItem { +export class TuiDocAPIItem implements OnInit { + private readonly locationRef = inject(Location); + private readonly activatedRoute = inject(ActivatedRoute); + private readonly urlSerializer = inject(UrlSerializer); + private readonly urlStateHandler = inject(TUI_DOC_URL_STATE_HANDLER); + @Input() public name = ''; @@ -56,4 +69,58 @@ export class TuiDocAPIItem { @Output() public readonly valueChange = new EventEmitter(); + + public ngOnInit(): void { + this.parseParams(this.activatedRoute.snapshot.queryParams); + } + + public onValueChange(value: T): void { + this.value = value; + this.valueChange.emit(value); + this.setQueryParam(value); + } + + private clearBrackets(value: string): string { + return value.replaceAll(/[()[\]]/g, ''); + } + + private parseParams(params: Params): void { + const name = this.clearBrackets(this.name); + const propertyValue: string | undefined = params[name]; + const propertyValueWithSuffix: number | string | undefined = + params[`${name}${SERIALIZED_SUFFIX}`]; + + if (!propertyValue && !propertyValueWithSuffix) { + return; + } + + let value = + !!propertyValueWithSuffix && this.items + ? this.items[propertyValueWithSuffix as number] + : tuiCoerceValue(propertyValue); + + if (this.type === 'string' && tuiIsNumber(value)) { + value = value.toString(); + } + + this.onValueChange(value as T); + } + + private setQueryParam(value: T | boolean | number | string | null): void { + const tree = this.urlSerializer.parse(this.locationRef.path()); + + const isValueAvailableByKey = value instanceof Object; + const computedValue = + isValueAvailableByKey && this.items ? this.items.indexOf(value as T) : value; + + const suffix = isValueAvailableByKey ? SERIALIZED_SUFFIX : ''; + const propName = this.clearBrackets(this.name) + suffix; + + tree.queryParams = { + ...tree.queryParams, + [propName]: computedValue, + }; + + this.locationRef.go(this.urlStateHandler(tree)); + } } diff --git a/projects/addon-doc/components/api/api-item.template.html b/projects/addon-doc/components/api/api-item.template.html index 9dcde905fca7..06993cd8f01b 100644 --- a/projects/addon-doc/components/api/api-item.template.html +++ b/projects/addon-doc/components/api/api-item.template.html @@ -44,7 +44,7 @@ placeholder="null" tuiTextfield [ngModel]="value ?? null" - (ngModelChange)="valueChange.emit($event)" + (ngModelChange)="onValueChange($event)" > @@ -90,7 +90,7 @@ [ngModel]="value" [step]="1" [tuiTextfieldLabelOutside]="true" - (ngModelChange)="valueChange.emit($event || 0)" + (ngModelChange)="onValueChange($event || 0)" /> diff --git a/projects/demo-playwright/tests/core/button/button.spec.ts b/projects/demo-playwright/tests/core/button/button.spec.ts index 73afb6b6bc39..3ce0f34a6d8c 100644 --- a/projects/demo-playwright/tests/core/button/button.spec.ts +++ b/projects/demo-playwright/tests/core/button/button.spec.ts @@ -5,7 +5,7 @@ test.describe('Button', () => { test('darkMode=true + appearance=icon + hovered state', async ({page}) => { await tuiGoto( page, - '/components/button/API?darkMode=true&appearance=icon&icon=tuiIconEyeOff', + '/components/button/API?darkMode=true&appearance=icon&iconStart=@tui.eye-off', ); const {apiPageExample} = new TuiDocumentationPagePO(page);