diff --git a/projects/addon-doc/components/api/api-item.component.ts b/projects/addon-doc/components/api/api-item.component.ts new file mode 100644 index 000000000000..e35f6d803e63 --- /dev/null +++ b/projects/addon-doc/components/api/api-item.component.ts @@ -0,0 +1,59 @@ +import {NgForOf, NgIf, NgSwitch, NgSwitchCase} from '@angular/common'; +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + Output, +} from '@angular/core'; +import {FormsModule} from '@angular/forms'; +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'; +import {TuiSwitch} from '@taiga-ui/kit/components/switch'; +import {TuiChevron} from '@taiga-ui/kit/directives/chevron'; +import {TuiInputNumberModule} from '@taiga-ui/legacy/components/input-number'; +import {TuiTextfieldControllerModule} from '@taiga-ui/legacy/directives/textfield-controller'; + +import {TuiInspectPipe} from '../documentation/pipes/inspect.pipe'; +import {TuiDocTypeReferencePipe} from '../documentation/pipes/type-reference.pipe'; + +@Component({ + standalone: true, + selector: 'tr[tuiDocAPIItem]', + imports: [ + FormsModule, + NgForOf, + NgIf, + NgSwitch, + NgSwitchCase, + TuiChevron, + TuiDataListWrapper, + TuiDocTypeReferencePipe, + TuiIcon, + TuiInputNumberModule, + TuiInspectPipe, + TuiSwitch, + TuiTextfield, + TuiTextfieldControllerModule, + ], + templateUrl: './api-item.template.html', + styleUrls: ['./api-item.style.less'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class TuiDocAPIItem { + @Input() + public name = ''; + + @Input() + public type = ''; + + @Input() + public value?: T; + + @Input() + public items: readonly T[] = []; + + @Output() + public readonly valueChange = new EventEmitter(); +} diff --git a/projects/addon-doc/components/api/api-item.style.less b/projects/addon-doc/components/api/api-item.style.less new file mode 100644 index 000000000000..e4782dbaf6dd --- /dev/null +++ b/projects/addon-doc/components/api/api-item.style.less @@ -0,0 +1,76 @@ +@import '@taiga-ui/core/styles/taiga-ui-local'; + +:host { + box-shadow: inset 0 -1px var(--tui-border-normal); +} + +.t-td { + padding: 1.5rem 2rem 1.5rem 0; + vertical-align: top; + + &:last-child { + padding-inline-end: 0; + text-align: end; + } +} + +.t-name { + display: flex !important; + min-block-size: 1.5rem; + inline-size: fit-content; + margin: 0 0 0.5rem !important; + -webkit-text-fill-color: var(--tui-background-accent-2-pressed); + + &_input { + -webkit-text-fill-color: var(--tui-text-negative); + } + + &_banana { + -webkit-text-fill-color: var(--tui-text-action); + } + + &_output { + -webkit-text-fill-color: var(--tui-status-info); + } +} + +.t-type { + flex-wrap: wrap; + align-items: center; + justify-content: flex-start; + min-block-size: 1.5rem; + margin: 0 !important; +} + +.t-reference { + display: inline-flex; + color: var(--tui-text-action); + text-decoration: none; + align-items: center; + justify-content: center; + gap: 3px; +} + +.t-input { + min-inline-size: 10rem; + margin-block-start: -0.625rem; +} + +@media @tui-mobile { + :host { + gap: 1rem; + padding: 1rem 0; + } + + .t-td { + padding: 0; + + &:last-child { + text-align: start; + } + } + + .t-input { + margin: 0; + } +} diff --git a/projects/addon-doc/components/api/api-item.template.html b/projects/addon-doc/components/api/api-item.template.html new file mode 100644 index 000000000000..9dcde905fca7 --- /dev/null +++ b/projects/addon-doc/components/api/api-item.template.html @@ -0,0 +1,97 @@ + + + {{ name }} + + + + + + + + {{ item.type }} + + + + {{ item.type }} + +  |  + + + + + + + + + + {{ data | tuiInspectAny }} + + + + + + + + + + + + + diff --git a/projects/addon-doc/components/api/api.component.ts b/projects/addon-doc/components/api/api.component.ts new file mode 100644 index 000000000000..f42eb214ab24 --- /dev/null +++ b/projects/addon-doc/components/api/api.component.ts @@ -0,0 +1,19 @@ +import { + ChangeDetectionStrategy, + Component, + inject, + ViewEncapsulation, +} from '@angular/core'; +import {TUI_DOC_DOCUMENTATION_TEXTS} from '@taiga-ui/addon-doc/tokens'; + +@Component({ + standalone: true, + selector: 'table[tuiDocAPI]', + templateUrl: './api.template.html', + styleUrls: ['./api.style.less'], + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class TuiDocAPI { + protected readonly texts = inject(TUI_DOC_DOCUMENTATION_TEXTS); +} diff --git a/projects/addon-doc/components/api/api.style.less b/projects/addon-doc/components/api/api.style.less new file mode 100644 index 000000000000..5410bc3aa379 --- /dev/null +++ b/projects/addon-doc/components/api/api.style.less @@ -0,0 +1,38 @@ +@import '@taiga-ui/core/styles/taiga-ui-local'; + +[tuiDocAPI] { + inline-size: 100%; + + tbody [tuiTitle] { + align-items: flex-start; + color: var(--tui-text-secondary); + padding: 1rem; + box-shadow: 0 1px var(--tui-border-normal); + background: var(--tui-background-base-alt); + } + + th { + padding: 0.5rem 0; + color: var(--tui-text-secondary); + font-weight: normal; + text-align: start; + box-shadow: inset 0 -1px var(--tui-border-normal); + + &:last-child { + text-align: end; + } + } +} + +@media @tui-mobile { + [tuiDocAPI], + [tuiDocAPI] tbody, + [tuiDocAPI] tr { + display: flex; + flex-direction: column; + + th { + display: none; + } + } +} diff --git a/projects/addon-doc/components/api/api.template.html b/projects/addon-doc/components/api/api.template.html new file mode 100644 index 000000000000..340fffdcec61 --- /dev/null +++ b/projects/addon-doc/components/api/api.template.html @@ -0,0 +1,8 @@ + + + {{ texts[2] }} + {{ texts[1] }} + {{ texts[3] }} + + + diff --git a/projects/addon-doc/components/index.ts b/projects/addon-doc/components/index.ts index 67d9e3eddf5b..1242a73b8e26 100644 --- a/projects/addon-doc/components/index.ts +++ b/projects/addon-doc/components/index.ts @@ -1,3 +1,5 @@ +export * from './api/api.component'; +export * from './api/api-item.component'; export * from './code'; export * from './copy'; export * from './demo'; diff --git a/projects/addon-doc/index.ts b/projects/addon-doc/index.ts index 316d60351c39..380856ab8644 100644 --- a/projects/addon-doc/index.ts +++ b/projects/addon-doc/index.ts @@ -1,4 +1,6 @@ import { + TuiDocAPI, + TuiDocAPIItem, TuiDocCode, TuiDocCopy, TuiDocDemo, @@ -16,6 +18,8 @@ import { import {TuiDocText} from '@taiga-ui/addon-doc/directives'; export const TuiAddonDoc = [ + TuiDocAPI, + TuiDocAPIItem, TuiDocCopy, TuiDocTab, TuiDocDemo, diff --git a/projects/addon-doc/tokens/i18n.ts b/projects/addon-doc/tokens/i18n.ts index 308e66d9a8d1..de9a5089a88e 100644 --- a/projects/addon-doc/tokens/i18n.ts +++ b/projects/addon-doc/tokens/i18n.ts @@ -22,16 +22,19 @@ export const TUI_DOC_DEMO_TEXTS = tuiCreateToken<[string, string, string]>([ * @string word 'type', * @string 'name and description', * @string word 'value' - * @string message for tooltip about ng-polymorpheus + * @string @deprecated message for tooltip about ng-polymorpheus * ] */ export const TUI_DOC_DOCUMENTATION_TEXTS = tuiCreateToken< - [string, string, string, string, string] + [argument: string, type: string, name: string, value: string, tooltip: string] >([ 'Argument', 'Type', 'Name and description', 'Value', + /** + * @deprecated + */ 'Learn about our dynamic templates from ', ]); diff --git a/projects/cdk/constants/used-icons.ts b/projects/cdk/constants/used-icons.ts index e212b051826f..3cc8794ce6a3 100644 --- a/projects/cdk/constants/used-icons.ts +++ b/projects/cdk/constants/used-icons.ts @@ -19,6 +19,7 @@ export const TUI_USED_ICONS = [ '@tui.union-pay', '@tui.uzcard', '@tui.verve', + '@tui.external-link', '@tui.search', '@tui.sun', '@tui.moon', diff --git a/projects/core/components/textfield/textfield.component.ts b/projects/core/components/textfield/textfield.component.ts index 1efe512d4f3f..5692fe8d63a6 100644 --- a/projects/core/components/textfield/textfield.component.ts +++ b/projects/core/components/textfield/textfield.component.ts @@ -31,6 +31,7 @@ import { } from '@taiga-ui/core/directives/dropdown'; import {TuiWithIcons} from '@taiga-ui/core/directives/icons'; import {TUI_COMMON_ICONS} from '@taiga-ui/core/tokens'; +import type {TuiSizeL, TuiSizeS} from '@taiga-ui/core/types'; import type {PolymorpheusContent} from '@taiga-ui/polymorpheus'; import {PolymorpheusOutlet} from '@taiga-ui/polymorpheus'; @@ -60,6 +61,7 @@ import {TuiWithTextfieldDropdown} from './textfield-dropdown.directive'; '[style.--t-side.px]': 'side', '[attr.data-size]': 'options.size()', '[class._with-label]': 'hasLabel', + '[class._with-template]': 'content', '[class._disabled]': 'el?.nativeElement.disabled', }, }) @@ -107,6 +109,10 @@ export class TuiTextfieldComponent implements TuiDataListHost { return this.el?.nativeElement.id || this.autoId; } + public get size(): TuiSizeL | TuiSizeS { + return this.options.size(); + } + public handleOption(option: T): void { this.directive?.setValue(this.stringify(option)); this.open.set(false); diff --git a/projects/core/components/textfield/textfield.directive.ts b/projects/core/components/textfield/textfield.directive.ts index 864e3283d724..388c86038202 100644 --- a/projects/core/components/textfield/textfield.directive.ts +++ b/projects/core/components/textfield/textfield.directive.ts @@ -58,8 +58,8 @@ export class TuiTextfieldBase { return null; } - public setValue(value: string): void { - this.el.value = value; + public setValue(value: string | null): void { + this.el.value = value || ''; this.el.dispatchEvent(new Event('input', {bubbles: true})); } } diff --git a/projects/core/components/textfield/textfield.template.html b/projects/core/components/textfield/textfield.template.html index 22e734ea0e13..fd63c7c9cc98 100644 --- a/projects/core/components/textfield/textfield.template.html +++ b/projects/core/components/textfield/textfield.template.html @@ -16,7 +16,7 @@ type="button" class="t-clear" [iconStart]="icons.close" - (click)="directive?.setValue('')" + (click)="directive?.setValue(null)" (pointerdown.silent.prevent)="el?.nativeElement?.focus()" > diff --git a/projects/core/styles/components/textfield.less b/projects/core/styles/components/textfield.less index 882c28b676bb..857cda3124ae 100644 --- a/projects/core/styles/components/textfield.less +++ b/projects/core/styles/components/textfield.less @@ -182,6 +182,15 @@ tui-textfield { padding: inherit; } + .t-template { + display: flex; + align-items: center; + } + + &._with-template select { + color: transparent !important; + } + input:defined, select:defined { pointer-events: auto; diff --git a/projects/demo/src/components/appearance/index.html b/projects/demo/src/components/appearance/index.html new file mode 100644 index 000000000000..f3dce105c240 --- /dev/null +++ b/projects/demo/src/components/appearance/index.html @@ -0,0 +1,50 @@ + + + + + Appearance + + Applied as a host directive + + + + + Appearance of the element + + + Manual interactive state override + + + Manual focus state override + + + Custom manual mode for the appearance + diff --git a/projects/demo/src/components/appearance/index.ts b/projects/demo/src/components/appearance/index.ts new file mode 100644 index 000000000000..1c011f46a4d7 --- /dev/null +++ b/projects/demo/src/components/appearance/index.ts @@ -0,0 +1,56 @@ +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; +import {RouterLink} from '@angular/router'; +import {DemoRoute} from '@demo/routes'; +import {TuiDocAPIItem} from '@taiga-ui/addon-doc'; +import {type TuiInteractiveState, TuiLink, TuiTitle} from '@taiga-ui/core'; + +@Component({ + standalone: true, + selector: 'tbody[tuiDocAppearance]', + imports: [RouterLink, TuiDocAPIItem, TuiLink, TuiTitle], + templateUrl: './index.html', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class TuiDocAppearance { + protected readonly routes = DemoRoute; + protected selected = ''; + protected readonly modes = ['invalid', 'checked']; + protected readonly appearances = [ + 'primary', + 'secondary', + 'destructive', + 'neutral', + 'flat', + 'link', + 'accent', + 'opposite', + 'floating', + 'textfield', + 'whiteblock', + 'outline', + 'error', + 'success', + 'warning', + 'info', + 'glass', + ] as const; + + protected readonly states: readonly TuiInteractiveState[] = [ + 'active', + 'disabled', + 'hover', + ]; + + protected readonly focuses = [true, false]; + + @Input() + public tuiDocAppearance: readonly string[] | '' = ''; + + public state: TuiInteractiveState | null = null; + public focus: boolean | null = null; + public mode: string | null = null; + + public get appearance(): string { + return this.selected || this.tuiDocAppearance[0] || this.appearances[0]; + } +} diff --git a/projects/demo/src/components/icons/index.html b/projects/demo/src/components/icons/index.html new file mode 100644 index 000000000000..f49babaa7eaa --- /dev/null +++ b/projects/demo/src/components/icons/index.html @@ -0,0 +1,26 @@ + + + + Icons + Applied as a host directive + + + + + Icon on the left side + + + Icon on the right side + diff --git a/projects/demo/src/components/icons/index.ts b/projects/demo/src/components/icons/index.ts new file mode 100644 index 000000000000..b5bbd4be3e28 --- /dev/null +++ b/projects/demo/src/components/icons/index.ts @@ -0,0 +1,23 @@ +import {ChangeDetectionStrategy, Component} from '@angular/core'; +import {TuiDocAPIItem} from '@taiga-ui/addon-doc'; +import {TuiTitle} from '@taiga-ui/core'; + +@Component({ + standalone: true, + selector: 'tbody[tuiDocIcons]', + imports: [TuiDocAPIItem, TuiTitle], + templateUrl: './index.html', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class TuiDocIcons { + protected readonly icons = [ + '', + '@tui.search', + '@tui.heart', + '@tui.settings', + '@tui.chevron-down', + ]; + + public iconStart = ''; + public iconEnd = ''; +} diff --git a/projects/demo/src/modules/components/block/index.html b/projects/demo/src/modules/components/block/index.html index d312f48102a1..674de30adcf9 100644 --- a/projects/demo/src/modules/components/block/index.html +++ b/projects/demo/src/modules/components/block/index.html @@ -18,5 +18,48 @@ /> - + + + + + + + Size of the block + + + +
+
+ + diff --git a/projects/demo/src/modules/components/block/index.ts b/projects/demo/src/modules/components/block/index.ts index d2a1cb8b136e..ed791805f9f4 100644 --- a/projects/demo/src/modules/components/block/index.ts +++ b/projects/demo/src/modules/components/block/index.ts @@ -1,13 +1,31 @@ import {Component} from '@angular/core'; +import {FormsModule} from '@angular/forms'; +import {TuiDocAppearance} from '@demo/components/appearance'; +import {TuiDocIcons} from '@demo/components/icons'; import {changeDetection} from '@demo/emulate/change-detection'; import {TuiDemo} from '@demo/utils'; +import {type TuiSizeL, type TuiSizeS, TuiTitle} from '@taiga-ui/core'; +import {TuiBlock, TuiSwitch} from '@taiga-ui/kit'; @Component({ standalone: true, - imports: [TuiDemo], + imports: [ + FormsModule, + TuiBlock, + TuiDemo, + TuiDocAppearance, + TuiDocIcons, + TuiSwitch, + TuiTitle, + ], templateUrl: './index.html', changeDetection, }) export default class Example { protected readonly examples = ['Sizes', 'Groups', 'Custom']; + protected readonly sizes: ReadonlyArray = ['s', 'm', 'l']; + protected readonly appearances = ['whiteblock', 'secondary']; + + protected value = false; + protected size = this.sizes[2]!; } diff --git a/projects/demo/used-icons.ts b/projects/demo/used-icons.ts index 3422af438ac7..977fa3e36ece 100644 --- a/projects/demo/used-icons.ts +++ b/projects/demo/used-icons.ts @@ -6,6 +6,9 @@ */ export const TUI_USED_ICONS = [ '@tui.search', + '@tui.heart', + '@tui.settings', + '@tui.chevron-down', '@tui.calendar', '@tui.visa-mono', '@tui.mastercard-mono', @@ -16,10 +19,8 @@ export const TUI_USED_ICONS = [ '@tui.layout-grid', '@tui.x', '@tui.ellipsis', - '@tui.heart', '@tui.check', '@tui.user', - '@tui.settings', '@tui.chevron-left', '@tui.mastercard', '@tui.box', @@ -28,7 +29,6 @@ export const TUI_USED_ICONS = [ '@tui.gift', '@tui.arrow-right', '@tui.users', - '@tui.chevron-down', '@tui.clock', '@tui.circle-plus', '@tui.circle-arrow-right', diff --git a/tsconfig.json b/tsconfig.json index 87f4a5e1c6a2..dc64e982d487 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,6 +7,7 @@ "paths": { "@demo-cypress/*": ["projects/demo-cypress/cypress/*"], "@demo-playwright/utils": ["projects/demo-playwright/utils/index"], + "@demo/components/*": ["projects/demo/src/components/*"], "@demo/emulate/change-detection": ["projects/demo/src/emulate/change-detection-strategy.ts"], "@demo/emulate/encapsulation": ["projects/demo/src/emulate/view-encapsulation.ts"], "@demo/emulate/ng-zone-options": ["projects/demo/src/emulate/ng-zone-options.ts"],