UNPKG

@taiga-ui/addon-doc

Version:

Taiga UI based library for developing documentation portals for Angular libraries.

1 lines 184 kB
{"version":3,"file":"taiga-ui-addon-doc-components.mjs","sources":["../../../projects/addon-doc/components/api/api.component.ts","../../../projects/addon-doc/components/api/api.template.html","../../../projects/addon-doc/components/documentation/pipes/inspect.pipe.ts","../../../projects/addon-doc/components/documentation/pipes/type-reference.pipe.ts","../../../projects/addon-doc/components/api/api-item-number.directive.ts","../../../projects/addon-doc/components/api/api-item.component.ts","../../../projects/addon-doc/components/api/api-item.template.html","../../../projects/addon-doc/components/code/index.ts","../../../projects/addon-doc/components/code/index.html","../../../projects/addon-doc/components/copy/index.ts","../../../projects/addon-doc/components/copy/index.html","../../../projects/addon-doc/components/demo/index.ts","../../../projects/addon-doc/components/demo/index.html","../../../projects/addon-doc/components/doc-tab/index.ts","../../../projects/addon-doc/components/doc-tab/index.html","../../../projects/addon-doc/components/documentation/documentation-property-connector.directive.ts","../../../projects/addon-doc/components/documentation/pipes/cleaner.pipe.ts","../../../projects/addon-doc/components/documentation/pipes/optional.pipe.ts","../../../projects/addon-doc/components/documentation/pipes/strip-optional.pipe.ts","../../../projects/addon-doc/components/documentation/documentation.component.ts","../../../projects/addon-doc/components/documentation/documentation.template.html","../../../projects/addon-doc/components/documentation/pipes/color.pipe.ts","../../../projects/addon-doc/components/documentation/pipes/opacity.pipe.ts","../../../projects/addon-doc/components/documentation/pipes/primitive-polymorpheus-content.pipe.ts","../../../projects/addon-doc/components/example/example.options.ts","../../../projects/addon-doc/components/example/example-get-tabs.pipe.ts","../../../projects/addon-doc/components/example/example.component.ts","../../../projects/addon-doc/components/example/example.template.html","../../../projects/addon-doc/components/navigation/navigation.providers.ts","../../../projects/addon-doc/components/navigation/scroll-into-view.directive.ts","../../../projects/addon-doc/components/navigation/navigation.component.ts","../../../projects/addon-doc/components/navigation/navigation.template.html","../../../projects/addon-doc/components/internal/header/index.ts","../../../projects/addon-doc/components/internal/header/index.html","../../../projects/addon-doc/components/internal/see-also/index.ts","../../../projects/addon-doc/components/internal/see-also/index.html","../../../projects/addon-doc/components/internal/source-code/source-code.component.ts","../../../projects/addon-doc/components/internal/source-code/source-code.template.html","../../../projects/addon-doc/components/language-switcher/index.ts","../../../projects/addon-doc/components/language-switcher/index.html","../../../projects/addon-doc/components/main/main.component.ts","../../../projects/addon-doc/components/main/main.template.html","../../../projects/addon-doc/components/page/page.providers.ts","../../../projects/addon-doc/components/page/page-tab.directive.ts","../../../projects/addon-doc/components/page/page.component.ts","../../../projects/addon-doc/components/page/page.template.html","../../../projects/addon-doc/components/theme-switcher/theme-switcher.component.ts","../../../projects/addon-doc/components/theme-switcher/theme-switcher.template.html","../../../projects/addon-doc/components/taiga-ui-addon-doc-components.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n inject,\n ViewEncapsulation,\n} from '@angular/core';\nimport {TUI_DOC_DOCUMENTATION_TEXTS} from '@taiga-ui/addon-doc/tokens';\n\n@Component({\n standalone: true,\n selector: 'table[tuiDocAPI]',\n templateUrl: './api.template.html',\n styleUrls: ['./api.style.less'],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class TuiDocAPI {\n protected readonly texts = inject(TUI_DOC_DOCUMENTATION_TEXTS);\n}\n","<thead>\n <tr>\n <th>{{ texts[2] }}</th>\n <th>{{ texts[1] }}</th>\n <th>{{ texts[3] }}</th>\n </tr>\n</thead>\n<ng-content />\n","import type {PipeTransform} from '@angular/core';\nimport {inject, Pipe, TemplateRef} from '@angular/core';\nimport {tuiInspectAny} from '@taiga-ui/addon-doc/utils';\nimport {TUI_IS_E2E} from '@taiga-ui/cdk/tokens';\n\n@Pipe({\n standalone: true,\n name: 'tuiInspectAny',\n})\nexport class TuiInspectPipe implements PipeTransform {\n private readonly isE2E = inject(TUI_IS_E2E);\n\n public transform(value: unknown, depth = 2): string {\n if (this.isE2E && typeof value === 'function') {\n /**\n * @description:\n * When developing in production mode the webpack bundler minify\n * functions in different ways, then due to which the string content\n * of the function may differ from build to build, which can be to\n * various problems when screenshot testing on e2e.\n */\n return 'λ(x) => y';\n }\n\n return value instanceof TemplateRef ? 'TemplateRef' : tuiInspectAny(value, depth);\n }\n}\n","import type {PipeTransform} from '@angular/core';\nimport {inject, Pipe} from '@angular/core';\nimport {\n TUI_DOC_TYPE_REFERENCE_HANDLER,\n TUI_DOC_TYPE_REFERENCE_PARSER,\n} from '@taiga-ui/addon-doc/tokens';\n\n@Pipe({\n standalone: true,\n name: 'tuiDocTypeReference',\n})\nexport class TuiDocTypeReferencePipe implements PipeTransform {\n private readonly parser = inject(TUI_DOC_TYPE_REFERENCE_PARSER);\n private readonly linkHandler = inject(TUI_DOC_TYPE_REFERENCE_HANDLER);\n\n public transform(original: string): ReadonlyArray<{\n type: string;\n extracted: string;\n reference: string | null;\n }> {\n return this.parser(original)\n .map(({type, extracted}) => ({\n type,\n extracted,\n reference: this.linkHandler?.(extracted) ?? null,\n }))\n .sort((a, b) => b.reference?.localeCompare(a.reference ?? '') ?? -1);\n }\n}\n","import {Directive, Input} from '@angular/core';\n\n@Directive({\n standalone: true,\n selector: 'tr[tuiDocAPIItem][type=number]',\n})\nexport class TuiDocAPINumberItem {\n @Input()\n public min: number | null = null;\n\n @Input()\n public max: number | null = null;\n}\n","import {Location, NgForOf, NgIf, NgSwitch, NgSwitchCase} from '@angular/common';\nimport type {AfterViewInit} from '@angular/core';\nimport {\n ChangeDetectionStrategy,\n Component,\n EventEmitter,\n inject,\n Input,\n Output,\n} from '@angular/core';\nimport {FormsModule} from '@angular/forms';\nimport type {Params} from '@angular/router';\nimport {ActivatedRoute, UrlSerializer} from '@angular/router';\nimport {TUI_DOC_ICONS, TUI_DOC_URL_STATE_HANDLER} from '@taiga-ui/addon-doc/tokens';\nimport {tuiCoerceValue, tuiInspectAny} from '@taiga-ui/addon-doc/utils';\nimport {tuiIsNumber} from '@taiga-ui/cdk/utils/miscellaneous';\nimport {TuiAlertService} from '@taiga-ui/core/components/alert';\nimport {TuiIcon} from '@taiga-ui/core/components/icon';\nimport {TuiTextfield} from '@taiga-ui/core/components/textfield';\nimport {TuiDataListWrapper} from '@taiga-ui/kit/components/data-list-wrapper';\nimport {TuiInputNumber} from '@taiga-ui/kit/components/input-number';\nimport {TuiSwitch} from '@taiga-ui/kit/components/switch';\nimport {TuiChevron} from '@taiga-ui/kit/directives/chevron';\n\nimport {TuiInspectPipe} from '../documentation/pipes/inspect.pipe';\nimport {TuiDocTypeReferencePipe} from '../documentation/pipes/type-reference.pipe';\nimport {TuiDocAPINumberItem} from './api-item-number.directive';\n\nconst SERIALIZED_SUFFIX = '$';\n\n@Component({\n standalone: true,\n selector: 'tr[tuiDocAPIItem]',\n imports: [\n FormsModule,\n NgForOf,\n NgIf,\n NgSwitch,\n NgSwitchCase,\n TuiChevron,\n TuiDataListWrapper,\n TuiDocTypeReferencePipe,\n TuiIcon,\n TuiInputNumber,\n TuiInspectPipe,\n TuiSwitch,\n TuiTextfield,\n ],\n templateUrl: './api-item.template.html',\n styleUrls: ['./api-item.style.less'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class TuiDocAPIItem<T> implements AfterViewInit {\n private readonly locationRef = inject(Location);\n private readonly activatedRoute = inject(ActivatedRoute);\n private readonly urlSerializer = inject(UrlSerializer);\n private readonly urlStateHandler = inject(TUI_DOC_URL_STATE_HANDLER);\n private readonly alerts = inject(TuiAlertService);\n\n protected readonly icons = inject(TUI_DOC_ICONS);\n\n protected readonly numberItem = inject(TuiDocAPINumberItem, {\n self: true,\n optional: true,\n });\n\n @Input()\n public name = '';\n\n @Input()\n public type = '';\n\n @Input()\n public value?: T;\n\n @Input()\n public items: readonly T[] = [];\n\n @Output()\n public readonly valueChange = new EventEmitter<T>();\n\n public ngAfterViewInit(): void {\n this.parseParams(this.activatedRoute.snapshot.queryParams);\n }\n\n public onValueChange(value: T): void {\n this.value = value;\n this.valueChange.emit(value);\n this.setQueryParam(value);\n }\n\n public emitEvent(event: unknown): void {\n console.info('emitEvent', event);\n\n const alert =\n !event || event?.toString() === '[object Object]'\n ? tuiInspectAny(event, 2)\n : (event as string);\n\n this.alerts.open(alert, {label: this.name}).subscribe();\n }\n\n private clearBrackets(value: string): string {\n return value.replaceAll(/[()[\\]]/g, '');\n }\n\n private parseParams(params: Params): void {\n const name = this.clearBrackets(this.name);\n const propertyValue: string | undefined = params[name];\n const propertyValueWithSuffix: number | string | undefined =\n params[`${name}${SERIALIZED_SUFFIX}`];\n\n if (!propertyValue && !propertyValueWithSuffix) {\n return;\n }\n\n let value =\n !!propertyValueWithSuffix && this.items\n ? this.items[propertyValueWithSuffix as number]\n : tuiCoerceValue(propertyValue);\n\n if (this.type === 'string' && tuiIsNumber(value)) {\n value = value.toString();\n }\n\n this.onValueChange(value as T);\n }\n\n private setQueryParam(value: T | boolean | number | string | null): void {\n const tree = this.urlSerializer.parse(this.locationRef.path());\n\n const isValueAvailableByKey = value instanceof Object;\n const computedValue =\n isValueAvailableByKey && this.items ? this.items.indexOf(value as T) : value;\n\n const suffix = isValueAvailableByKey ? SERIALIZED_SUFFIX : '';\n const propName = this.clearBrackets(this.name) + suffix;\n\n tree.queryParams = {\n ...tree.queryParams,\n [propName]: computedValue,\n };\n\n this.locationRef.go(this.urlStateHandler(tree));\n }\n}\n","<td class=\"t-td\">\n <code\n class=\"t-name\"\n [class.t-name_banana]=\"name.startsWith('[(')\"\n [class.t-name_input]=\"name.startsWith('[')\"\n [class.t-name_output]=\"name.startsWith('(')\"\n >\n {{ name }}\n </code>\n <ng-content />\n</td>\n<td class=\"t-td\">\n <code class=\"t-type\">\n <ng-container *ngFor=\"let item of type | tuiDocTypeReference; let last = last\">\n <a\n *ngIf=\"item.reference; else default\"\n target=\"_blank\"\n class=\"t-reference\"\n [attr.href]=\"item.reference\"\n >\n {{ item.type }}\n <tui-icon\n *ngIf=\"icons.externalLink\"\n [icon]=\"icons.externalLink\"\n [style.font-size.rem]=\"1\"\n />\n </a>\n <ng-template #default>\n {{ item.type }}\n </ng-template>\n <span *ngIf=\"!last\">&nbsp;|&nbsp;</span>\n </ng-container>\n </code>\n</td>\n<td class=\"t-td\">\n <tui-textfield\n *ngIf=\"items.length; else noItems\"\n tuiChevron\n tuiTextfieldSize=\"m\"\n class=\"t-input\"\n [content]=\"content\"\n [tuiTextfieldCleaner]=\"type.includes('null') || type.includes('PolymorpheusContent')\"\n >\n <select\n placeholder=\"null\"\n tuiTextfield\n [ngModel]=\"value ?? null\"\n (ngModelChange)=\"onValueChange($event)\"\n ></select>\n <tui-data-list-wrapper\n *tuiTextfieldDropdown\n [itemContent]=\"content\"\n [items]=\"items\"\n />\n </tui-textfield>\n <ng-template\n #content\n let-data\n >\n <code [style.margin]=\"0\">{{ data | tuiInspectAny }}</code>\n </ng-template>\n <ng-template #noItems>\n <ng-container\n *ngIf=\"value !== undefined\"\n [ngSwitch]=\"type\"\n >\n <input\n *ngSwitchCase=\"'boolean'\"\n tuiSwitch\n type=\"checkbox\"\n [id]=\"name\"\n [ngModel]=\"value\"\n (ngModelChange)=\"onValueChange($event)\"\n />\n\n <tui-textfield\n *ngSwitchCase=\"'string'\"\n tuiTextfieldSize=\"m\"\n class=\"t-input\"\n >\n <input\n tuiTextfield\n [id]=\"name\"\n [ngModel]=\"value || ''\"\n (ngModelChange)=\"onValueChange($event)\"\n />\n </tui-textfield>\n\n <tui-textfield\n *ngSwitchCase=\"'number'\"\n tuiTextfieldSize=\"m\"\n >\n <input\n tuiInputNumber\n [id]=\"name\"\n [max]=\"numberItem?.max ?? null\"\n [min]=\"numberItem?.min ?? null\"\n [ngModel]=\"value\"\n [step]=\"1\"\n (ngModelChange)=\"onValueChange($event || 0)\"\n />\n </tui-textfield>\n </ng-container>\n </ng-template>\n</td>\n","import {ClipboardModule} from '@angular/cdk/clipboard';\nimport {isPlatformServer, NgForOf, NgIf} from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n inject,\n Input,\n PLATFORM_ID,\n} from '@angular/core';\nimport {toSignal} from '@angular/core/rxjs-interop';\nimport {\n TUI_DOC_EXAMPLE_MARKDOWN_CODE_PROCESSOR,\n TUI_DOC_ICONS,\n} from '@taiga-ui/addon-doc/tokens';\nimport type {TuiRawLoaderContent} from '@taiga-ui/addon-doc/types';\nimport {tuiRawLoad} from '@taiga-ui/addon-doc/utils';\nimport type {TuiHandler} from '@taiga-ui/cdk/types';\nimport {TuiButton} from '@taiga-ui/core/components/button';\nimport {TUI_COPY_TEXTS} from '@taiga-ui/kit/tokens';\nimport {Highlight} from 'ngx-highlightjs';\nimport {BehaviorSubject, map, startWith, Subject, switchMap, timer} from 'rxjs';\n\n@Component({\n standalone: true,\n selector: 'tui-doc-code',\n imports: [ClipboardModule, Highlight, NgForOf, NgIf, TuiButton],\n templateUrl: './index.html',\n styleUrls: ['./index.less'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[style.visibility]': 'isServer ? \"hidden\" : \"visible\"',\n '[class._has-filename]': 'hasFilename',\n },\n})\nexport class TuiDocCode {\n private readonly icons = inject(TUI_DOC_ICONS);\n private readonly rawLoader$$ = new BehaviorSubject<TuiRawLoaderContent>('');\n\n protected readonly isServer = isPlatformServer(inject(PLATFORM_ID));\n\n protected readonly markdownCodeProcessor: TuiHandler<string, readonly string[]> =\n inject(TUI_DOC_EXAMPLE_MARKDOWN_CODE_PROCESSOR);\n\n protected readonly copy$ = new Subject<void>();\n protected readonly copyText = toSignal(\n inject(TUI_COPY_TEXTS).pipe(map(([copy]) => copy)),\n );\n\n protected readonly icon = toSignal(\n this.copy$.pipe(\n switchMap(() =>\n timer(2000).pipe(\n map(() => this.icons.copy),\n startWith(this.icons.check),\n ),\n ),\n ),\n {initialValue: this.icons.copy},\n );\n\n protected readonly processor = toSignal(\n this.rawLoader$$.pipe(\n switchMap(tuiRawLoad),\n map((value: string) => this.markdownCodeProcessor(value)),\n ),\n {initialValue: []},\n );\n\n @Input()\n public filename = '';\n\n @Input()\n public set code(code: TuiRawLoaderContent) {\n this.rawLoader$$.next(code);\n }\n\n public get hasFilename(): boolean {\n return !!this.filename;\n }\n}\n","<p\n *ngIf=\"filename\"\n class=\"t-header\"\n>\n {{ filename }}\n</p>\n<pre\n *ngFor=\"let content of processor()\"\n class=\"t-code\"\n>\n <code [lineNumbers]=\"true\" [highlight]=\"content\"></code>\n <div class=\"t-code-actions\">\n <button\n tuiIconButton\n type=\"button\"\n appearance=\"outline-grayscale\"\n size=\"s\"\n class=\"t-copy-button\"\n [iconStart]=\"icon()\"\n [cdkCopyToClipboard]=\"content\"\n (click)=\"copy$.next()\"\n >\n {{ copyText()}}\n </button>\n <ng-content />\n </div>\n</pre>\n","import {NgIf} from '@angular/common';\nimport {ChangeDetectionStrategy, Component, inject} from '@angular/core';\nimport {toSignal} from '@angular/core/rxjs-interop';\nimport {TUI_FALSE_HANDLER} from '@taiga-ui/cdk/constants';\nimport {TuiButton} from '@taiga-ui/core/components/button';\nimport {TUI_COPY_TEXTS} from '@taiga-ui/kit/tokens';\nimport {map, startWith, Subject, switchMap, timer} from 'rxjs';\n\nconst COPIED_TIMEOUT = 1500;\n\n@Component({\n standalone: true,\n selector: 'tui-doc-copy',\n imports: [NgIf, TuiButton],\n templateUrl: './index.html',\n styleUrls: ['./index.less'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class TuiDocCopy {\n private readonly copy$ = new Subject<void>();\n\n protected readonly texts = toSignal(inject(TUI_COPY_TEXTS), {\n initialValue: ['', ''] as const,\n });\n\n protected readonly copied = toSignal(\n this.copy$.pipe(\n switchMap(() =>\n timer(COPIED_TIMEOUT).pipe(map(TUI_FALSE_HANDLER), startWith(true)),\n ),\n ),\n {initialValue: false},\n );\n\n protected onClick(): void {\n this.copy$.next();\n }\n}\n","<button\n appearance=\"\"\n size=\"s\"\n tuiButton\n type=\"button\"\n class=\"t-copy\"\n (click)=\"onClick()\"\n>\n <span class=\"t-content\">\n <span\n class=\"t-initial\"\n [attr.data-text]=\"copied() ? '' : texts()[0]\"\n >\n <ng-container *ngIf=\"!copied()\">\n <ng-content />\n </ng-container>\n </span>\n {{ copied() ? texts()[1] : '' }}\n </span>\n</button>\n","import {JsonPipe, Location, NgIf, NgTemplateOutlet} from '@angular/common';\nimport type {AfterViewInit, ElementRef} from '@angular/core';\nimport {\n ChangeDetectionStrategy,\n Component,\n computed,\n ContentChild,\n inject,\n Input,\n signal,\n TemplateRef,\n ViewChild,\n} from '@angular/core';\nimport {takeUntilDestroyed, toObservable} from '@angular/core/rxjs-interop';\nimport type {AbstractControl} from '@angular/forms';\nimport {FormGroup, FormsModule, ReactiveFormsModule} from '@angular/forms';\nimport type {Params, UrlTree} from '@angular/router';\nimport {UrlSerializer} from '@angular/router';\nimport {TUI_DOC_DEMO_TEXTS, TUI_DOC_URL_STATE_HANDLER} from '@taiga-ui/addon-doc/tokens';\nimport type {TuiDemoParams} from '@taiga-ui/addon-doc/types';\nimport {tuiCleanObject, tuiCoerceValueIsTrue} from '@taiga-ui/addon-doc/utils';\nimport {TuiResizable, TuiResizer} from '@taiga-ui/cdk/directives/resizer';\nimport {tuiInjectElement} from '@taiga-ui/cdk/utils/dom';\nimport {tuiClamp, tuiToInteger} from '@taiga-ui/cdk/utils/math';\nimport {tuiPure, tuiPx} from '@taiga-ui/cdk/utils/miscellaneous';\nimport {TuiButton} from '@taiga-ui/core/components/button';\nimport {TuiExpand} from '@taiga-ui/core/components/expand';\nimport {TuiGroup} from '@taiga-ui/core/directives/group';\nimport {TUI_DARK_MODE} from '@taiga-ui/core/tokens';\nimport {TuiDataListWrapper} from '@taiga-ui/kit/components/data-list-wrapper';\nimport {TuiSwitch} from '@taiga-ui/kit/components/switch';\nimport {TuiChevron} from '@taiga-ui/kit/directives/chevron';\nimport {TuiSelectModule} from '@taiga-ui/legacy/components/select';\nimport {TuiTextfieldControllerModule} from '@taiga-ui/legacy/directives/textfield-controller';\nimport {skip} from 'rxjs';\n\nconst MIN_WIDTH = 160;\n\n@Component({\n standalone: true,\n selector: 'tui-doc-demo',\n imports: [\n FormsModule,\n JsonPipe,\n NgIf,\n NgTemplateOutlet,\n ReactiveFormsModule,\n TuiButton,\n TuiChevron,\n TuiDataListWrapper,\n TuiExpand,\n TuiGroup,\n TuiResizable,\n TuiResizer,\n TuiSelectModule,\n TuiSwitch,\n TuiTextfieldControllerModule,\n ],\n templateUrl: './index.html',\n styleUrls: ['./index.less'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class._sticky]': 'sticky',\n '(window:resize)': 'onResize()',\n '(document:mouseup.zoneless)': 'onMouseUp()',\n },\n})\nexport class TuiDocDemo implements AfterViewInit {\n @ViewChild(TuiResizable, {static: true})\n private readonly resizable?: ElementRef<HTMLElement>;\n\n @ViewChild('content', {static: true})\n private readonly content?: ElementRef<HTMLElement>;\n\n @ViewChild('resizer', {static: true})\n private readonly resizer?: ElementRef<HTMLElement>;\n\n private readonly el = tuiInjectElement();\n private readonly locationRef = inject(Location);\n private readonly urlSerializer = inject(UrlSerializer);\n private readonly urlStateHandler = inject(TUI_DOC_URL_STATE_HANDLER);\n private readonly darkMode = inject(TUI_DARK_MODE);\n\n @ContentChild(TemplateRef)\n protected readonly template: TemplateRef<Record<string, unknown>> | null = null;\n\n protected readonly rendered = signal(false);\n\n protected theme = computed(() => (this.dark() ? 'dark' : 'light'));\n\n protected dark = signal(\n tuiCoerceValueIsTrue(this.params.darkMode ?? this.darkMode()),\n );\n\n protected readonly $ = toObservable(this.darkMode)\n .pipe(skip(1), takeUntilDestroyed())\n .subscribe((mode) => this.onModeChange(mode));\n\n protected testForm?: FormGroup;\n\n protected readonly updateOnVariants = ['change', 'blur', 'submit'] as const;\n\n protected updateOn: 'blur' | 'change' | 'submit' =\n this.params.updateOn || this.updateOnVariants[0];\n\n protected opaque = tuiCoerceValueIsTrue(this.params.sandboxOpaque ?? true);\n protected expanded = tuiCoerceValueIsTrue(this.params.sandboxExpanded ?? false);\n protected sandboxWidth = tuiToInteger(this.params.sandboxWidth);\n protected readonly texts = inject(TUI_DOC_DEMO_TEXTS);\n\n @Input()\n public control: AbstractControl | null = null;\n\n @Input()\n public sticky = true;\n\n public ngAfterViewInit(): void {\n this.createForm();\n this.updateWidth(this.sandboxWidth + this.delta);\n this.rendered.set(true);\n }\n\n protected onResize(): void {\n this.updateWidth();\n this.onMouseUp();\n }\n\n protected onMouseUp(): void {\n this.updateUrl({sandboxWidth: this.sandboxWidth});\n }\n\n protected onModeChange(darkMode: boolean): void {\n this.dark.set(darkMode);\n this.updateUrl({sandboxWidth: this.sandboxWidth, darkMode});\n }\n\n protected toggleDetails(): void {\n this.expanded = !this.expanded;\n this.updateUrl({sandboxExpanded: this.expanded});\n }\n\n protected changeOpaque(opaque: boolean): void {\n this.opaque = opaque;\n this.updateUrl({sandboxOpaque: this.opaque});\n }\n\n protected updateOnChange(updateOn: 'blur' | 'change' | 'submit'): void {\n this.updateOn = updateOn;\n this.updateUrl({updateOn});\n this.createForm();\n }\n\n protected updateWidth(width = NaN): void {\n if (!this.resizer || !this.resizable || !this.content) {\n return;\n }\n\n const safe = width || this.resizable.nativeElement.clientWidth;\n const total = this.el.clientWidth;\n const clamped = Math.round(tuiClamp(safe, MIN_WIDTH, total)) - this.delta;\n const validated = safe < total ? clamped : NaN;\n\n this.resizer.nativeElement.textContent = String(clamped || '-');\n this.resizable.nativeElement.style.width = validated ? tuiPx(safe) : '';\n this.sandboxWidth = validated;\n }\n\n private get delta(): number {\n return this.resizable && this.content\n ? this.resizable.nativeElement.clientWidth -\n this.content.nativeElement.clientWidth\n : 0;\n }\n\n private get params(): Params | TuiDemoParams {\n return this.getUrlTree().queryParams;\n }\n\n @tuiPure\n private updateUrl(params: TuiDemoParams): void {\n const tree = this.getUrlTree();\n const {queryParams} = tree;\n\n delete queryParams.sandboxWidth;\n\n tree.queryParams = {\n ...queryParams,\n ...tuiCleanObject({...params}),\n };\n\n this.locationRef.go(this.urlStateHandler(tree));\n }\n\n private createForm(): void {\n const {control, updateOn} = this;\n\n if (control) {\n this.testForm = new FormGroup({testValue: control}, {updateOn});\n }\n }\n\n private getUrlTree(): UrlTree {\n return this.urlSerializer.parse(this.locationRef.path());\n }\n}\n","<div class=\"t-settings\">\n <label class=\"t-label\">\n <input\n size=\"s\"\n tuiSwitch\n type=\"checkbox\"\n [ngModel]=\"dark()\"\n (ngModelChange)=\"onModeChange($event)\"\n />\n {{ texts[0] }}\n </label>\n <label class=\"t-label\">\n <input\n size=\"s\"\n tuiSwitch\n type=\"checkbox\"\n [ngModel]=\"opaque\"\n (ngModelChange)=\"changeOpaque($event)\"\n />\n {{ texts[1] }}\n </label>\n</div>\n<div\n tuiResizable\n class=\"t-wrapper\"\n [attr.tuiTheme]=\"theme()\"\n [class.t-wrapper_transparent]=\"!opaque\"\n [style.visibility]=\"rendered() ? 'visible' : 'hidden'\"\n>\n <div class=\"t-content\">\n <div\n #content\n id=\"demo-content\"\n >\n <form\n *ngIf=\"testForm\"\n class=\"t-form\"\n [formGroup]=\"testForm\"\n >\n <div class=\"t-input-wrapper\">\n <ng-container [ngTemplateOutlet]=\"template\" />\n </div>\n <button\n automation-id=\"tui-demo-button__toggle-details\"\n size=\"s\"\n tuiButton\n type=\"button\"\n class=\"t-button\"\n [tuiChevron]=\"expanded\"\n (click)=\"toggleDetails()\"\n >\n {{ texts[2] }}\n </button>\n <tui-expand\n class=\"t-expand\"\n [expanded]=\"expanded\"\n >\n <ng-template tuiExpandContent>\n <pre class=\"t-value\">Form data: {{ testForm.value | json }}</pre>\n <div\n tuiGroup\n class=\"t-form-controls\"\n >\n <tui-select\n automation-id=\"tui-demo-select__expand-update-on\"\n tuiTextfieldSize=\"s\"\n class=\"t-select\"\n [ngModel]=\"updateOn\"\n [ngModelOptions]=\"{standalone: true}\"\n (ngModelChange)=\"updateOnChange($event)\"\n >\n updateOn\n <tui-data-list-wrapper\n *tuiDataList\n [items]=\"updateOnVariants\"\n />\n </tui-select>\n <button\n automation-id=\"tui-demo-button__reset-state\"\n size=\"s\"\n tuiButton\n type=\"reset\"\n [style.flex]=\"'0 0 auto'\"\n >\n Reset\n </button>\n <button\n automation-id=\"tui-demo-button__submit-state\"\n size=\"s\"\n tuiButton\n type=\"submit\"\n [style.flex]=\"'0 0 auto'\"\n >\n Submit\n </button>\n </div>\n </ng-template>\n </tui-expand>\n </form>\n <ng-content />\n </div>\n </div>\n <div\n #resizer\n class=\"t-resizer\"\n [tuiResizer]=\"[1, 0]\"\n (tuiSizeChange)=\"updateWidth($event[0])\"\n ></div>\n</div>\n","import {ChangeDetectionStrategy, Component, Input} from '@angular/core';\n\n@Component({\n standalone: true,\n selector: 'tui-doc-tab',\n templateUrl: './index.html',\n styleUrls: ['./index.less'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class TuiDocTab {\n @Input()\n public src = '';\n}\n","<div class=\"t-tab\">\n <img\n alt=\"Documentation tab icon\"\n class=\"t-icon\"\n [src]=\"src\"\n />\n <ng-content />\n</div>\n","import {Location} from '@angular/common';\nimport type {OnChanges, OnInit} from '@angular/core';\nimport {\n Directive,\n EventEmitter,\n inject,\n Input,\n Output,\n signal,\n TemplateRef,\n} from '@angular/core';\nimport type {Params} from '@angular/router';\nimport {ActivatedRoute, UrlSerializer} from '@angular/router';\nimport {TUI_DOC_URL_STATE_HANDLER} from '@taiga-ui/addon-doc/tokens';\nimport {tuiCleanObject, tuiCoerceValue, tuiInspectAny} from '@taiga-ui/addon-doc/utils';\nimport {tuiIsNumber} from '@taiga-ui/cdk/utils/miscellaneous';\nimport {TuiAlertService} from '@taiga-ui/core/components/alert';\nimport {Subject} from 'rxjs';\n\nconst SERIALIZED_SUFFIX = '$';\n\nexport type TuiDocumentationPropertyType = 'input-output' | 'input' | 'output' | null;\n\n// @bad TODO: refactor output and value sync\n@Directive({\n standalone: true,\n selector: 'ng-template[documentationPropertyName]',\n exportAs: 'documentationProperty',\n})\nexport class TuiDocDocumentationPropertyConnector<T> implements OnInit, OnChanges {\n private readonly locationRef = inject(Location);\n private readonly activatedRoute = inject(ActivatedRoute);\n private readonly urlSerializer = inject(UrlSerializer);\n private readonly urlStateHandler = inject(TUI_DOC_URL_STATE_HANDLER);\n private readonly alerts = inject(TuiAlertService);\n\n @Input()\n public documentationPropertyName = '';\n\n @Input()\n public documentationPropertyMode: TuiDocumentationPropertyType = null;\n\n @Input()\n public documentationPropertyType = '';\n\n @Input()\n public documentationPropertyValue!: T;\n\n @Input()\n public documentationPropertyDeprecated = false;\n\n @Input()\n public documentationPropertyValues: readonly T[] | null = null;\n\n @Output()\n public readonly documentationPropertyValueChange = new EventEmitter<T>();\n\n public readonly changed$ = new Subject<void>();\n\n public readonly emits = signal(1);\n\n public readonly template = inject(TemplateRef);\n\n public get attrName(): string {\n switch (this.documentationPropertyMode) {\n case 'input':\n return `[${this.documentationPropertyName}]`;\n case 'input-output':\n return `[(${this.documentationPropertyName})]`;\n case 'output':\n return `(${this.documentationPropertyName})`;\n default:\n return this.documentationPropertyName;\n }\n }\n\n public get shouldShowValues(): boolean {\n return this.documentationPropertyMode !== 'output';\n }\n\n public get hasItems(): boolean {\n return !!this.documentationPropertyValues;\n }\n\n public ngOnInit(): void {\n this.parseParams(this.activatedRoute.snapshot.queryParams);\n }\n\n public ngOnChanges(): void {\n this.changed$.next();\n }\n\n public onValueChange(value: T): void {\n this.documentationPropertyValue = value;\n this.documentationPropertyValueChange.emit(value);\n this.setQueryParam(value);\n }\n\n public emitEvent(event: unknown): void {\n // For more convenient debugging\n console.info(this.attrName, event);\n\n this.emits.update((x) => ++x);\n\n let content: string | undefined;\n\n if (event !== undefined) {\n content = tuiInspectAny(event, 2);\n }\n\n this.alerts.open(content, {label: this.attrName}).subscribe();\n }\n\n private parseParams(params: Params): void {\n const propertyValue: string | undefined = params[this.documentationPropertyName];\n const propertyValueWithSuffix: number | string | undefined =\n params[`${this.documentationPropertyName}${SERIALIZED_SUFFIX}`];\n\n if (!propertyValue && !propertyValueWithSuffix) {\n return;\n }\n\n let value =\n !!propertyValueWithSuffix && this.documentationPropertyValues\n ? this.documentationPropertyValues[propertyValueWithSuffix as number]\n : tuiCoerceValue(propertyValue);\n\n if (this.documentationPropertyType === 'string' && tuiIsNumber(value)) {\n value = value.toString();\n }\n\n this.onValueChange(value as T);\n }\n\n private setQueryParam(value: unknown): void {\n const tree = this.urlSerializer.parse(this.locationRef.path());\n const isValueAvailableByKey = value instanceof Object;\n const name = this.documentationPropertyName;\n const nameWithSuffix = `${name}${SERIALIZED_SUFFIX}`;\n\n const computedValue =\n isValueAvailableByKey && this.documentationPropertyValues\n ? this.documentationPropertyValues.indexOf(value as T)\n : value;\n\n tree.queryParams = tuiCleanObject({\n ...tree.queryParams,\n /**\n * Caretaker note: reset previous conflicted param in route\n * issue: https://github.com/taiga-family/taiga-ui/issues/9764\n */\n ...(isValueAvailableByKey\n ? {\n [nameWithSuffix]: computedValue,\n [name]: undefined,\n }\n : {\n [nameWithSuffix]: undefined,\n [name]: computedValue,\n }),\n });\n\n this.locationRef.go(this.urlStateHandler(tree));\n }\n}\n","import type {PipeTransform} from '@angular/core';\nimport {Pipe} from '@angular/core';\n\n@Pipe({\n standalone: true,\n name: 'tuiShowCleanerPipe',\n})\nexport class TuiShowCleanerPipe implements PipeTransform {\n public transform(type: string): boolean {\n return type.includes('null');\n }\n}\n","import type {PipeTransform} from '@angular/core';\nimport {Pipe} from '@angular/core';\n\n@Pipe({\n standalone: true,\n name: 'tuiIsOptionalPipe',\n})\nexport class TuiIsOptionalPipe implements PipeTransform {\n public transform(name: string): boolean {\n return name.includes('?');\n }\n}\n","import type {PipeTransform} from '@angular/core';\nimport {Pipe} from '@angular/core';\n\n@Pipe({\n standalone: true,\n name: 'tuiStripOptionalPipe',\n})\nexport class TuiStripOptionalPipe implements PipeTransform {\n public transform(name: string): string {\n return name.replace('?', '');\n }\n}\n","import {animate, style, transition, trigger} from '@angular/animations';\nimport {NgForOf, NgIf, NgSwitch, NgSwitchCase, NgTemplateOutlet} from '@angular/common';\nimport type {AfterContentInit, QueryList} from '@angular/core';\nimport {\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n ContentChildren,\n DestroyRef,\n inject,\n Input,\n} from '@angular/core';\nimport {takeUntilDestroyed} from '@angular/core/rxjs-interop';\nimport {FormsModule} from '@angular/forms';\nimport {\n TUI_DOC_DOCUMENTATION_TEXTS,\n TUI_DOC_EXCLUDED_PROPERTIES,\n} from '@taiga-ui/addon-doc/tokens';\nimport {EMPTY_QUERY} from '@taiga-ui/cdk/constants';\nimport {tuiQueryListChanges, tuiWatch} from '@taiga-ui/cdk/observables';\nimport {TuiFilterPipe} from '@taiga-ui/cdk/pipes/filter';\nimport {TuiToArrayPipe} from '@taiga-ui/cdk/pipes/to-array';\nimport type {TuiMatcher} from '@taiga-ui/cdk/types';\nimport {TuiNotification} from '@taiga-ui/core/components/notification';\nimport {tuiScrollbarOptionsProvider} from '@taiga-ui/core/components/scrollbar';\nimport {TuiTextfield} from '@taiga-ui/core/components/textfield';\nimport {TuiDropdown} from '@taiga-ui/core/directives/dropdown';\nimport {TuiBadge} from '@taiga-ui/kit/components/badge';\nimport {TuiDataListWrapper} from '@taiga-ui/kit/components/data-list-wrapper';\nimport {TuiInputNumber} from '@taiga-ui/kit/components/input-number';\nimport {TuiSwitch} from '@taiga-ui/kit/components/switch';\nimport {TuiSelectModule} from '@taiga-ui/legacy/components/select';\nimport {TuiTextfieldControllerModule} from '@taiga-ui/legacy/directives/textfield-controller';\nimport {merge, switchMap} from 'rxjs';\n\nimport {TuiDocDocumentationPropertyConnector} from './documentation-property-connector.directive';\nimport {TuiShowCleanerPipe} from './pipes/cleaner.pipe';\nimport {TuiInspectPipe} from './pipes/inspect.pipe';\nimport {TuiIsOptionalPipe} from './pipes/optional.pipe';\nimport {TuiStripOptionalPipe} from './pipes/strip-optional.pipe';\nimport {TuiDocTypeReferencePipe} from './pipes/type-reference.pipe';\n\n// @bad TODO subscribe propertiesConnectors changes\n// @bad TODO refactor to make more flexible\n@Component({\n standalone: true,\n selector: 'tui-doc-documentation',\n imports: [\n FormsModule,\n NgForOf,\n NgIf,\n NgSwitch,\n NgSwitchCase,\n NgTemplateOutlet,\n TuiBadge,\n TuiDataListWrapper,\n TuiDocTypeReferencePipe,\n TuiDropdown,\n TuiFilterPipe,\n TuiInputNumber,\n TuiInspectPipe,\n TuiIsOptionalPipe,\n TuiNotification,\n TuiSelectModule,\n TuiShowCleanerPipe,\n TuiStripOptionalPipe,\n TuiSwitch,\n TuiTextfield,\n TuiTextfieldControllerModule,\n TuiToArrayPipe,\n ],\n templateUrl: './documentation.template.html',\n styleUrls: ['./documentation.style.less'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [tuiScrollbarOptionsProvider({mode: 'hover'})],\n animations: [\n trigger('emitEvent', [\n transition(':increment', [style({opacity: 1}), animate('500ms ease-in')]),\n ]),\n ],\n})\nexport class TuiDocDocumentation implements AfterContentInit {\n private readonly cdr = inject(ChangeDetectorRef);\n private readonly destroyRef = inject(DestroyRef);\n\n @ContentChildren(TuiDocDocumentationPropertyConnector)\n protected propertiesConnectors: QueryList<\n TuiDocDocumentationPropertyConnector<unknown>\n > = EMPTY_QUERY;\n\n protected readonly texts = inject(TUI_DOC_DOCUMENTATION_TEXTS);\n protected readonly excludedProperties = inject(TUI_DOC_EXCLUDED_PROPERTIES);\n protected activeItemIndex = 0;\n\n @Input()\n public heading = '';\n\n @Input()\n public showValues = true;\n\n @Input()\n public isAPI = false;\n\n public ngAfterContentInit(): void {\n tuiQueryListChanges(this.propertiesConnectors)\n .pipe(\n switchMap((items) => merge(...items.map(({changed$}) => changed$))),\n tuiWatch(this.cdr),\n takeUntilDestroyed(this.destroyRef),\n )\n .subscribe();\n }\n\n protected get type(): string {\n return this.isAPI ? this.texts[0] : this.texts[1];\n }\n\n protected matcher: TuiMatcher<\n [TuiDocDocumentationPropertyConnector<unknown>, Set<string>]\n > = (item, exclusions) => !exclusions.has(item.documentationPropertyName);\n}\n","<h1\n *ngIf=\"heading\"\n class=\"t-heading\"\n>\n {{ heading }}\n</h1>\n<ng-content />\n<ng-container *ngIf=\"propertiesConnectors | tuiToArray | tuiFilter: matcher : excludedProperties as properties\">\n <table\n *ngIf=\"properties.length\"\n class=\"t-table\"\n >\n <tr class=\"t-row t-row_header\">\n <th class=\"t-th t-cell t-cell_prop\">{{ texts[2] }}</th>\n <th class=\"t-th\">{{ type }}</th>\n <th\n *ngIf=\"showValues && !isAPI\"\n class=\"t-th t-cell t-th_value\"\n >\n {{ texts[3] }}\n </th>\n </tr>\n <tr\n *ngFor=\"let propertyConnector of properties\"\n class=\"t-row\"\n [class.t-deprecated]=\"propertyConnector.documentationPropertyDeprecated\"\n >\n <td class=\"t-cell t-no-overflow\">\n <div\n automation-id=\"tui-documentation__property-name\"\n class=\"t-property t-additional-info\"\n >\n <code\n *ngIf=\"propertyConnector.attrName\"\n class=\"t-property-code\"\n [style.color]=\"'var(--tui-background-accent-2-pressed)'\"\n >\n {{ propertyConnector.attrName | tuiStripOptionalPipe }}\n </code>\n <tui-badge\n *ngIf=\"propertyConnector.attrName | tuiIsOptionalPipe\"\n appearance=\"neutral\"\n size=\"s\"\n >\n Optional\n </tui-badge>\n <tui-badge\n *ngIf=\"propertyConnector.documentationPropertyDeprecated\"\n appearance=\"negative\"\n size=\"s\"\n >\n Deprecated\n </tui-badge>\n </div>\n <ng-container [ngTemplateOutlet]=\"propertyConnector.template\" />\n </td>\n <td class=\"t-cell t-no-overflow\">\n <span class=\"type\">\n <code class=\"t-code-type\">\n <ng-container\n *ngFor=\"\n let item of propertyConnector.documentationPropertyType | tuiDocTypeReference;\n let last = last\n \"\n >\n <a\n *ngIf=\"item.reference; else default\"\n target=\"_blank\"\n class=\"t-code-reference\"\n [attr.href]=\"item.reference\"\n >\n {{ item.type }}\n </a>\n <ng-template #default>\n {{ item.type }}\n </ng-template>\n <span *ngIf=\"!last\">&nbsp;|&nbsp;</span>\n </ng-container>\n </code>\n </span>\n </td>\n <td\n *ngIf=\"showValues\"\n class=\"t-cell t-cell_value\"\n >\n <ng-container *ngIf=\"propertyConnector.shouldShowValues; else elseEmitter\">\n <tui-select\n *ngIf=\"propertyConnector.hasItems; else noItems\"\n tuiDropdownLimitWidth=\"min\"\n tuiTextfieldSize=\"m\"\n [nativeId]=\"propertyConnector.attrName\"\n [ngModel]=\"propertyConnector.documentationPropertyValue\"\n [tuiTextfieldCleaner]=\"propertyConnector.documentationPropertyType | tuiShowCleanerPipe\"\n [tuiTextfieldLabelOutside]=\"true\"\n [valueContent]=\"selectContent\"\n (ngModelChange)=\"propertyConnector.onValueChange($event)\"\n >\n <code class=\"t-exception\">null</code>\n <tui-data-list-wrapper\n *tuiDataList\n class=\"t-data-list\"\n [itemContent]=\"selectContent\"\n [items]=\"propertyConnector.documentationPropertyValues\"\n />\n </tui-select>\n <ng-template\n #selectContent\n let-data\n >\n <code>{{ data | tuiInspectAny }}</code>\n </ng-template>\n\n <ng-template #noItems>\n <ng-container [ngSwitch]=\"propertyConnector.documentationPropertyType\">\n <input\n *ngSwitchCase=\"'boolean'\"\n tuiSwitch\n type=\"checkbox\"\n class=\"t-switch\"\n [id]=\"propertyConnector.attrName\"\n [ngModel]=\"propertyConnector.documentationPropertyValue\"\n [showIcons]=\"true\"\n (ngModelChange)=\"propertyConnector.onValueChange($event)\"\n />\n\n <tui-textfield\n *ngSwitchCase=\"'string'\"\n tuiTextfieldSize=\"m\"\n >\n <input\n tuiTextfield\n [id]=\"propertyConnector.attrName\"\n [ngModel]=\"propertyConnector.documentationPropertyValue || ''\"\n (ngModelChange)=\"propertyConnector.onValueChange($event)\"\n />\n </tui-textfield>\n\n <tui-textfield\n *ngSwitchCase=\"'number'\"\n tuiTextfieldSize=\"m\"\n >\n <input\n tuiInputNumber\n [id]=\"propertyConnector.attrName\"\n [ngModel]=\"propertyConnector.documentationPropertyValue\"\n [step]=\"1\"\n (ngModelChange)=\"propertyConnector.onValueChange($event || 0)\"\n />\n </tui-textfield>\n </ng-container>\n </ng-template>\n </ng-container>\n\n <ng-template #elseEmitter>\n <tui-notification\n class=\"t-output\"\n [@emitEvent]=\"propertyConnector.emits()\"\n >\n Emit!\n </tui-notification>\n </ng-template>\n </td>\n </tr>\n </table>\n</ng-container>\n","import type {PipeTransform} from '@angular/core';\nimport {Pipe} from '@angular/core';\nimport {tuiRgbToHex} from '@taiga-ui/cdk/utils/color';\n\n@Pipe({\n standalone: true,\n name: 'tuiGetColorPipe',\n})\nexport class TuiGetColorPipe implements PipeTransform {\n public transform(color: string): string {\n if (color.length === 4) {\n return color\n .split('')\n .redu