@rt-tools/ui-kit-v2 0.35.1 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/rt-tools-ui-kit-v2-action-bar.mjs +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-action-bar.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-autocomplete.mjs +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-autocomplete.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-color-palette.mjs +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-color-palette.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-date-picker.mjs +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-date-picker.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-date-range.mjs +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-date-range.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-dynamic-selector.mjs +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-dynamic-selector.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-field.mjs +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-field.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-multiselect.mjs +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-multiselect.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-page-header.mjs +6 -4
- package/fesm2022/rt-tools-ui-kit-v2-page-header.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-popover.mjs +22 -2
- package/fesm2022/rt-tools-ui-kit-v2-popover.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs +20 -5
- package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-select.mjs +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-select.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-speed-menu.mjs +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-speed-menu.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-split-button.mjs +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-split-button.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-table.mjs +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-table.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2-thread-list.mjs +1 -0
- package/fesm2022/rt-tools-ui-kit-v2-thread-list.mjs.map +1 -1
- package/package.json +1 -1
- package/src/lib/components/page-header/rt-page-header-mobile.scss +6 -0
- package/src/lib/components/popover/CONTEXT.md +4 -0
- package/src/rich-editor/lib/components/chat/rt-chat.component.scss +6 -1
- package/types/rt-tools-ui-kit-v2-popover.d.ts +11 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rt-tools-ui-kit-v2-action-bar.mjs","names":["BEM_BLOCK"],"sources":["../../../projects/ui-kit-v2/src/lib/components/action-bar/rt-action-bar.component.ts","../../../projects/ui-kit-v2/src/lib/components/action-bar/rt-action-bar.component.html","../../../projects/ui-kit-v2/src/lib/components/action-bar/rt-action-bar.model.ts","../../../projects/ui-kit-v2/src/lib/components/action-bar/rt-action-bar.service.ts","../../../projects/ui-kit-v2/src/lib/components/action-bar/rt-action-bar-holder.component.ts","../../../projects/ui-kit-v2/src/lib/components/action-bar/rt-action-bar-holder.component.html"],"sourcesContent":["import { NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n InputSignal,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n computed,\n input,\n output,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { rtKitLabel } from '@rt-tools/ui-kit-v2/core';\nimport { IRtIcon, TRtKitLabelParams } from '@rt-tools/ui-kit-v2/core';\nimport { RtIconButtonComponent } from '@rt-tools/ui-kit-v2/icon-button';\nimport { RtIconComponent } from '@rt-tools/ui-kit-v2/icon';\nimport { RtMenuItemComponent } from '@rt-tools/ui-kit-v2/menu';\nimport { RtPopoverDirective } from '@rt-tools/ui-kit-v2/popover';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\nimport { IRtActionBar } from './rt-action-bar.model';\n\nconst BEM_BLOCK: string = 'rt-action-bar';\n\n/** Действие вместе с готовой записью модификаторов: шаблон методов не зовёт. */\ninterface IActionView {\n readonly action: IRtActionBar.Action;\n readonly modifiers: Readonly<Record<string, boolean>>;\n /**\n * Имя кнопки для вспомогательных средств — у действия со значком. На грубом указателе подпись\n * снята правилом стиля, а значок немой: без имени кнопка осталась бы безымянной.\n */\n readonly ariaLabel: string | null;\n}\n\n/**\n * Полоса массовых действий: счёт слева, действия рядом, крестик справа.\n *\n * Своего состояния не держит вовсе — ни выбранного, ни открытости. Ей дают\n * настройку входом, а наружу она сообщает две вещи: что нажали действие и что\n * нажали крестик. Держатель `rt-action-bar-holder` решает, стоит ли она в\n * разметке и где над страницей приколота.\n *\n * Действие с вложенным списком само не срабатывает: оно заголовок группы, и\n * список раскрывается всплывающим слоем кита. Нажатие пункта списка закрывает\n * полосу так же, как нажатие обычного действия: где человек нажал — в полосе\n * или на шаг глубже — о трате выбранного не говорит ничего.\n */\n@Component({\n selector: 'rt-action-bar',\n templateUrl: './rt-action-bar.component.html',\n styleUrl: './rt-action-bar.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n NgTemplateOutlet,\n RtIconComponent,\n RtIconButtonComponent,\n RtMenuItemComponent,\n RtPopoverDirective,\n BlockDirective,\n ElemDirective,\n ModDirective,\n ],\n hostDirectives: [{ directive: RtRadiusDirective, inputs: ['radius'] }],\n host: {\n class: BEM_BLOCK,\n role: 'toolbar',\n },\n})\nexport class RtActionBarComponent {\n /** Подстановки счётчика: подпись собирает словарь, а не склейка слов в шаблоне. */\n readonly #countParams: Signal<TRtKitLabelParams> = computed((): TRtKitLabelParams => ({\n count: this.config().selected,\n total: this.config().total,\n }));\n\n protected readonly countText: Signal<string> = rtKitLabel('uiSelectedOf', this.#countParams);\n\n protected readonly closeLabel: Signal<string> = rtKitLabel('uiClose');\n\n /**\n * Действия с готовыми модификаторами. Признак значка стоит модификатором, а не\n * условием в шаблоне: подпись у действия со значком снимает правило стиля по\n * грубому указателю, и решать это условием значило бы увезти оформление в код.\n */\n protected readonly actions: Signal<readonly IActionView[]> = computed((): readonly IActionView[] =>\n this.config().actions.map((action: IRtActionBar.Action): IActionView => ({\n action,\n modifiers: { danger: action.look === 'danger', withIcon: !!(action.icon || action.glyph) },\n ariaLabel: action.icon || action.glyph ? action.label : null,\n }))\n );\n\n public readonly config: InputSignal<IRtActionBar.Config> = input.required<IRtActionBar.Config>();\n /** Значок кнопки, закрывающей полосу. */\n public readonly closeIcon: InputSignal<IRtIcon.Name> = input<IRtIcon.Name>('close');\n\n public readonly actionRun: OutputEmitterRef<IRtActionBar.Action> = output<IRtActionBar.Action>();\n\n public readonly closed: OutputEmitterRef<void> = output<void>();\n\n protected onAction(action: IRtActionBar.Action): void {\n action.run?.();\n this.actionRun.emit(action);\n this.closed.emit();\n }\n\n protected onClose(): void {\n this.closed.emit();\n }\n}\n","<ng-container rtBlock=\"rt-action-bar\">\n <span rtElem=\"counter\" qa-dataid=\"action-bar-counter\">{{ countText() }}</span>\n\n @if (actions().length) {\n <div rtElem=\"actions\" qa-dataid=\"action-bar-actions\">\n @for (view of actions(); track view.action.label) {\n @if (view.action.menu) {\n <!--\n Действие с вложенным списком само не срабатывает: оно заголовок группы, и\n нажатие раскрывает слой. Список приходит слою контекстом — одного шаблона\n хватает на все такие действия.\n -->\n <button\n type=\"button\"\n rtElem=\"action\"\n qa-dataid=\"action-bar-action\"\n [rtMod]=\"view.modifiers\"\n [attr.aria-label]=\"view.ariaLabel\"\n [rtPopover]=\"menuTpl\"\n [rtPopoverContext]=\"view.action.menu\">\n <ng-container *ngTemplateOutlet=\"actionFace; context: { $implicit: view.action }\" />\n </button>\n } @else {\n <button\n type=\"button\"\n rtElem=\"action\"\n qa-dataid=\"action-bar-action\"\n [rtMod]=\"view.modifiers\"\n [attr.aria-label]=\"view.ariaLabel\"\n (click)=\"onAction(view.action)\">\n <ng-container *ngTemplateOutlet=\"actionFace; context: { $implicit: view.action }\" />\n </button>\n }\n }\n </div>\n }\n\n <rt-icon-button\n rtElem=\"close\"\n qa-dataid=\"action-bar-close\"\n variant=\"ghost\"\n size=\"sm\"\n [icon]=\"closeIcon()\"\n [ariaLabel]=\"closeLabel()\"\n (clicked)=\"onClose()\" />\n\n <!--\n Оба шаблона объявлены внутри блока намеренно: `rtElem` берёт имя блока инъекцией у\n ближайшего предка с `rtBlock`, а у шаблона, объявленного снаружи, такого предка нет\n вовсе — компонент не поднимается совсем, с отказом об отсутствующем поставщике.\n\n Лицо действия: значок и подпись. Подпись стоит в разметке всегда — снимает её правило\n стиля по грубому указателю, и только у действия, у которого значок есть.\n -->\n <ng-template #actionFace let-action>\n @if (action.icon || action.glyph) {\n <rt-icon rtElem=\"action-icon\" size=\"sm\" [name]=\"action.icon ?? null\" [glyph]=\"action.glyph ?? null\" />\n }\n\n <span rtElem=\"action-label\">{{ action.label }}</span>\n </ng-template>\n\n <ng-template #menuTpl let-menu>\n <div rtElem=\"menu\" qa-dataid=\"action-bar-menu\" role=\"menu\">\n @for (item of menu; track item.label) {\n <rt-menu-item\n qa-dataid=\"action-bar-menu-item\"\n [icon]=\"item.icon ?? null\"\n [glyph]=\"item.glyph ?? null\"\n [label]=\"item.label\"\n [danger]=\"item.look === 'danger'\"\n (selected)=\"onAction(item)\" />\n }\n </div>\n </ng-template>\n</ng-container>\n","import { IRtIcon } from '@rt-tools/ui-kit-v2/core';\n\n/**\n * Контракты полосы массовых действий. Один корневой неймспейс с префиксом `I`.\n *\n * Отличие от договора первого кита одно и оно намеренное: произвольного объекта\n * стилей на действии здесь нет. Вид кнопки называется именем из набора кита —\n * значение цвета в разметку не приходит вовсе.\n */\nexport namespace IRtActionBar {\n /** Вид действия: тем же именем, каким его зовёт кнопка кита. */\n export type Look = 'plain' | 'danger';\n\n /**\n * Одно нажатие в полосе. Либо `run` — то, что действие делает, — либо `menu`:\n * вложенный список. Действие с вложенным списком само не срабатывает: оно\n * заголовок группы, и запуск его наравне с раскрытием запустил бы то, чего\n * человек не выбирал.\n */\n export interface Action {\n readonly label: string;\n readonly icon?: IRtIcon.Name;\n /**\n * Имя Material вместо значка кита: рисуется так же, как вход `glyph` у `rt-icon` — парой из\n * перечня кита или лигатурой шрифта. Значок кита, заданный рядом, сильнее.\n */\n readonly glyph?: string;\n readonly look?: IRtActionBar.Look;\n readonly run?: () => void;\n readonly menu?: readonly IRtActionBar.Action[];\n }\n\n /**\n * Настройка полосы целиком. Счёт приходит парой: сколько выбрано и сколько\n * всего. Полоса ничего из этого не считает — ей дают числа.\n */\n export interface Config {\n readonly selected: number;\n readonly total: number;\n readonly actions: readonly IRtActionBar.Action[];\n }\n}\n\n/**\n * Сколько полоса держится в разметке после закрытия — ровно длительность ухода\n * из стилей.\n *\n * Число живёт здесь, а не только в правиле стиля: разметку снимает держатель, и,\n * разойдясь с правилом, он обрывает уход на полпути. Держателю и стилям нужно\n * одно и то же число, поэтому оно объявлено рядом с договором, а не в одном из них.\n */\nexport const RT_ACTION_BAR_LEAVE_MS: number = 300;\n","import { Injectable, Signal, WritableSignal, signal } from '@angular/core';\n\nimport { IRtActionBar } from './rt-action-bar.model';\n\nconst EMPTY_CONFIG: IRtActionBar.Config = { selected: 0, total: 0, actions: [] };\n\n/**\n * Настройка полосы массовых действий: держатель её читает, список — пишет.\n *\n * Служба без корня намеренно. Тот, кто отмечает строки, и тот, кто рисует полосу,\n * стоят на разной глубине одного экрана, и передавать настройку вниз через всё,\n * что между ними, значит рассказать о полосе каждому из них. Потребитель\n * объявляет службу на своём уровне — там, где у него живёт список.\n */\n@Injectable()\nexport class RtActionBarService {\n readonly #config: WritableSignal<IRtActionBar.Config> = signal<IRtActionBar.Config>(EMPTY_CONFIG);\n\n public readonly config: Signal<IRtActionBar.Config> = this.#config.asReadonly();\n\n /** Список действий. Счёт не трогается: он приходит своим вызовом. */\n public setActions(actions: readonly IRtActionBar.Action[]): void {\n this.#config.update((config: IRtActionBar.Config): IRtActionBar.Config => ({ ...config, actions }));\n }\n\n /** Счёт выбранного. Полоса открывается именно им. */\n public setCounts(selected: number, total: number): void {\n this.#config.update((config: IRtActionBar.Config): IRtActionBar.Config => ({ ...config, selected, total }));\n }\n\n /** Отпустить выбранное: счёт обнуляется, список действий остаётся. */\n public clearSelection(): void {\n this.#config.update((config: IRtActionBar.Config): IRtActionBar.Config => ({ ...config, selected: 0, total: 0 }));\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n InputSignal,\n Signal,\n ViewEncapsulation,\n WritableSignal,\n computed,\n effect,\n inject,\n input,\n signal,\n untracked,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { IRtIcon } from '@rt-tools/ui-kit-v2/core';\n\nimport { RtActionBarComponent } from './rt-action-bar.component';\nimport { IRtActionBar, RT_ACTION_BAR_LEAVE_MS } from './rt-action-bar.model';\nimport { RtActionBarService } from './rt-action-bar.service';\n\nconst BEM_BLOCK: string = 'rt-action-bar-holder';\n\n/**\n * Держатель полосы массовых действий: решает, стоит ли она в разметке, и прикалывает\n * её над страницей. Настройку читает у службы, которую потребитель объявил на своём\n * уровне — там, где у него живёт список.\n *\n * Полоса открывается счётом выбранного, а не своим признаком: два источника одного\n * признака расходятся молча, и признак, оставшийся поднятым над опустевшим выбором,\n * держал бы полосу над страницей, где ничего не выбрано.\n *\n * После закрытия полоса остаётся в разметке ровно на длительность ухода — число одно\n * и лежит в договоре рядом. Разойдясь с правилом стиля, держатель обрывал бы уход на\n * полпути.\n */\n@Component({\n selector: 'rt-action-bar-holder',\n templateUrl: './rt-action-bar-holder.component.html',\n styleUrl: './rt-action-bar-holder.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [RtActionBarComponent, BlockDirective, ElemDirective, ModDirective],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtActionBarHolderComponent {\n readonly #service: RtActionBarService = inject(RtActionBarService);\n readonly #destroyRef: DestroyRef = inject(DestroyRef);\n\n /** Уходит ли полоса прямо сейчас: разметка держит её, пока правило стиля не доиграет. */\n readonly #leaving: WritableSignal<boolean> = signal<boolean>(false);\n\n #leaveTimer: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Была ли полоса открыта до этой перемены. Без этого признака уходу не с чего начаться:\n * к минуте, когда выбранное обнулилось, и «открыта», и «стоит в разметке» уже ложь, так\n * что условие по ним не срабатывает никогда. В первом ките оно написано именно так, и\n * уход там не заводится вовсе — образец прочитан, а не перенесён.\n */\n #wasOpened: boolean = false;\n\n protected readonly config: Signal<IRtActionBar.Config> = this.#service.config;\n\n /** Выбрано ли что-нибудь: этим полоса и открывается. */\n protected readonly opened: Signal<boolean> = computed((): boolean => this.config().selected > 0);\n\n /** Стоит ли полоса в разметке: она остаётся в ней и на время ухода. */\n protected readonly shown: Signal<boolean> = computed((): boolean => this.opened() || this.#leaving());\n\n protected readonly leaving: Signal<boolean> = this.#leaving.asReadonly();\n\n /** Значок кнопки, закрывающей полосу, — уходит в саму полосу. */\n public readonly closeIcon: InputSignal<IRtIcon.Name> = input<IRtIcon.Name>('close');\n\n constructor() {\n effect((): void => {\n const opened: boolean = this.opened();\n\n untracked((): void => {\n this.#clearLeaveTimer();\n\n if (opened) {\n this.#wasOpened = true;\n this.#leaving.set(false);\n\n return;\n }\n\n if (this.#wasOpened) {\n this.#wasOpened = false;\n this.#startLeaving();\n }\n });\n });\n\n this.#destroyRef.onDestroy((): void => this.#clearLeaveTimer());\n }\n\n /** Крестик сообщает наружу; выбранное отпускает служба, которой список и владеет. */\n protected onClosed(): void {\n this.#service.clearSelection();\n }\n\n /** Полоса остаётся в разметке на время ухода и снимается по его концу. */\n #startLeaving(): void {\n this.#leaving.set(true);\n this.#leaveTimer = setTimeout((): void => {\n this.#leaving.set(false);\n this.#leaveTimer = null;\n }, RT_ACTION_BAR_LEAVE_MS);\n }\n\n #clearLeaveTimer(): void {\n if (this.#leaveTimer !== null) {\n clearTimeout(this.#leaveTimer);\n this.#leaveTimer = null;\n }\n }\n}\n","<ng-container rtBlock=\"rt-action-bar-holder\">\n @if (shown()) {\n <rt-action-bar\n rtElem=\"bar\"\n qa-dataid=\"action-bar-holder-bar\"\n [rtMod]=\"{ leaving: leaving() }\"\n [config]=\"config()\"\n [closeIcon]=\"closeIcon()\"\n (closed)=\"onClosed()\" />\n }\n</ng-container>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rt-tools-ui-kit-v2-action-bar.mjs","names":["BEM_BLOCK"],"sources":["../../../projects/ui-kit-v2/src/lib/components/action-bar/rt-action-bar.component.ts","../../../projects/ui-kit-v2/src/lib/components/action-bar/rt-action-bar.component.html","../../../projects/ui-kit-v2/src/lib/components/action-bar/rt-action-bar.model.ts","../../../projects/ui-kit-v2/src/lib/components/action-bar/rt-action-bar.service.ts","../../../projects/ui-kit-v2/src/lib/components/action-bar/rt-action-bar-holder.component.ts","../../../projects/ui-kit-v2/src/lib/components/action-bar/rt-action-bar-holder.component.html"],"sourcesContent":["import { NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n InputSignal,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n computed,\n input,\n output,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { rtKitLabel } from '@rt-tools/ui-kit-v2/core';\nimport { IRtIcon, TRtKitLabelParams } from '@rt-tools/ui-kit-v2/core';\nimport { RtIconButtonComponent } from '@rt-tools/ui-kit-v2/icon-button';\nimport { RtIconComponent } from '@rt-tools/ui-kit-v2/icon';\nimport { RtMenuItemComponent } from '@rt-tools/ui-kit-v2/menu';\nimport { RtPopoverDirective } from '@rt-tools/ui-kit-v2/popover';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\nimport { IRtActionBar } from './rt-action-bar.model';\n\nconst BEM_BLOCK: string = 'rt-action-bar';\n\n/** Действие вместе с готовой записью модификаторов: шаблон методов не зовёт. */\ninterface IActionView {\n readonly action: IRtActionBar.Action;\n readonly modifiers: Readonly<Record<string, boolean>>;\n /**\n * Имя кнопки для вспомогательных средств — у действия со значком. На грубом указателе подпись\n * снята правилом стиля, а значок немой: без имени кнопка осталась бы безымянной.\n */\n readonly ariaLabel: string | null;\n}\n\n/**\n * Полоса массовых действий: счёт слева, действия рядом, крестик справа.\n *\n * Своего состояния не держит вовсе — ни выбранного, ни открытости. Ей дают\n * настройку входом, а наружу она сообщает две вещи: что нажали действие и что\n * нажали крестик. Держатель `rt-action-bar-holder` решает, стоит ли она в\n * разметке и где над страницей приколота.\n *\n * Действие с вложенным списком само не срабатывает: оно заголовок группы, и\n * список раскрывается всплывающим слоем кита. Нажатие пункта списка закрывает\n * полосу так же, как нажатие обычного действия: где человек нажал — в полосе\n * или на шаг глубже — о трате выбранного не говорит ничего.\n */\n@Component({\n selector: 'rt-action-bar',\n templateUrl: './rt-action-bar.component.html',\n styleUrl: './rt-action-bar.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n NgTemplateOutlet,\n RtIconComponent,\n RtIconButtonComponent,\n RtMenuItemComponent,\n RtPopoverDirective,\n BlockDirective,\n ElemDirective,\n ModDirective,\n ],\n hostDirectives: [{ directive: RtRadiusDirective, inputs: ['radius'] }],\n host: {\n class: BEM_BLOCK,\n role: 'toolbar',\n },\n})\nexport class RtActionBarComponent {\n /** Подстановки счётчика: подпись собирает словарь, а не склейка слов в шаблоне. */\n readonly #countParams: Signal<TRtKitLabelParams> = computed((): TRtKitLabelParams => ({\n count: this.config().selected,\n total: this.config().total,\n }));\n\n protected readonly countText: Signal<string> = rtKitLabel('uiSelectedOf', this.#countParams);\n\n protected readonly closeLabel: Signal<string> = rtKitLabel('uiClose');\n\n /**\n * Действия с готовыми модификаторами. Признак значка стоит модификатором, а не\n * условием в шаблоне: подпись у действия со значком снимает правило стиля по\n * грубому указателю, и решать это условием значило бы увезти оформление в код.\n */\n protected readonly actions: Signal<readonly IActionView[]> = computed((): readonly IActionView[] =>\n this.config().actions.map((action: IRtActionBar.Action): IActionView => ({\n action,\n modifiers: { danger: action.look === 'danger', withIcon: !!(action.icon || action.glyph) },\n ariaLabel: action.icon || action.glyph ? action.label : null,\n }))\n );\n\n public readonly config: InputSignal<IRtActionBar.Config> = input.required<IRtActionBar.Config>();\n /** Значок кнопки, закрывающей полосу. */\n public readonly closeIcon: InputSignal<IRtIcon.Name> = input<IRtIcon.Name>('close');\n\n public readonly actionRun: OutputEmitterRef<IRtActionBar.Action> = output<IRtActionBar.Action>();\n\n public readonly closed: OutputEmitterRef<void> = output<void>();\n\n protected onAction(action: IRtActionBar.Action): void {\n action.run?.();\n this.actionRun.emit(action);\n this.closed.emit();\n }\n\n protected onClose(): void {\n this.closed.emit();\n }\n}\n","<ng-container rtBlock=\"rt-action-bar\">\n <span rtElem=\"counter\" qa-dataid=\"action-bar-counter\">{{ countText() }}</span>\n\n @if (actions().length) {\n <div rtElem=\"actions\" qa-dataid=\"action-bar-actions\">\n @for (view of actions(); track view.action.label) {\n @if (view.action.menu) {\n <!--\n Действие с вложенным списком само не срабатывает: оно заголовок группы, и\n нажатие раскрывает слой. Список приходит слою контекстом — одного шаблона\n хватает на все такие действия.\n -->\n <button\n type=\"button\"\n rtElem=\"action\"\n qa-dataid=\"action-bar-action\"\n [rtMod]=\"view.modifiers\"\n [attr.aria-label]=\"view.ariaLabel\"\n [rtPopover]=\"menuTpl\"\n [rtPopoverContext]=\"view.action.menu\">\n <ng-container *ngTemplateOutlet=\"actionFace; context: { $implicit: view.action }\" />\n </button>\n } @else {\n <button\n type=\"button\"\n rtElem=\"action\"\n qa-dataid=\"action-bar-action\"\n [rtMod]=\"view.modifiers\"\n [attr.aria-label]=\"view.ariaLabel\"\n (click)=\"onAction(view.action)\">\n <ng-container *ngTemplateOutlet=\"actionFace; context: { $implicit: view.action }\" />\n </button>\n }\n }\n </div>\n }\n\n <rt-icon-button\n rtElem=\"close\"\n qa-dataid=\"action-bar-close\"\n variant=\"ghost\"\n size=\"sm\"\n [icon]=\"closeIcon()\"\n [ariaLabel]=\"closeLabel()\"\n (clicked)=\"onClose()\" />\n\n <!--\n Оба шаблона объявлены внутри блока намеренно: `rtElem` берёт имя блока инъекцией у\n ближайшего предка с `rtBlock`, а у шаблона, объявленного снаружи, такого предка нет\n вовсе — компонент не поднимается совсем, с отказом об отсутствующем поставщике.\n\n Лицо действия: значок и подпись. Подпись стоит в разметке всегда — снимает её правило\n стиля по грубому указателю, и только у действия, у которого значок есть.\n -->\n <ng-template #actionFace let-action>\n @if (action.icon || action.glyph) {\n <rt-icon rtElem=\"action-icon\" size=\"sm\" [name]=\"action.icon ?? null\" [glyph]=\"action.glyph ?? null\" />\n }\n\n <span rtElem=\"action-label\">{{ action.label }}</span>\n </ng-template>\n\n <ng-template #menuTpl let-menu>\n <div rtElem=\"menu\" qa-dataid=\"action-bar-menu\" role=\"menu\">\n @for (item of menu; track item.label) {\n <rt-menu-item\n qa-dataid=\"action-bar-menu-item\"\n [icon]=\"item.icon ?? null\"\n [glyph]=\"item.glyph ?? null\"\n [label]=\"item.label\"\n [danger]=\"item.look === 'danger'\"\n (selected)=\"onAction(item)\" />\n }\n </div>\n </ng-template>\n</ng-container>\n","import { IRtIcon } from '@rt-tools/ui-kit-v2/core';\n\n/**\n * Контракты полосы массовых действий. Один корневой неймспейс с префиксом `I`.\n *\n * Отличие от договора первого кита одно и оно намеренное: произвольного объекта\n * стилей на действии здесь нет. Вид кнопки называется именем из набора кита —\n * значение цвета в разметку не приходит вовсе.\n */\nexport namespace IRtActionBar {\n /** Вид действия: тем же именем, каким его зовёт кнопка кита. */\n export type Look = 'plain' | 'danger';\n\n /**\n * Одно нажатие в полосе. Либо `run` — то, что действие делает, — либо `menu`:\n * вложенный список. Действие с вложенным списком само не срабатывает: оно\n * заголовок группы, и запуск его наравне с раскрытием запустил бы то, чего\n * человек не выбирал.\n */\n export interface Action {\n readonly label: string;\n readonly icon?: IRtIcon.Name;\n /**\n * Имя Material вместо значка кита: рисуется так же, как вход `glyph` у `rt-icon` — парой из\n * перечня кита или лигатурой шрифта. Значок кита, заданный рядом, сильнее.\n */\n readonly glyph?: string;\n readonly look?: IRtActionBar.Look;\n readonly run?: () => void;\n readonly menu?: readonly IRtActionBar.Action[];\n }\n\n /**\n * Настройка полосы целиком. Счёт приходит парой: сколько выбрано и сколько\n * всего. Полоса ничего из этого не считает — ей дают числа.\n */\n export interface Config {\n readonly selected: number;\n readonly total: number;\n readonly actions: readonly IRtActionBar.Action[];\n }\n}\n\n/**\n * Сколько полоса держится в разметке после закрытия — ровно длительность ухода\n * из стилей.\n *\n * Число живёт здесь, а не только в правиле стиля: разметку снимает держатель, и,\n * разойдясь с правилом, он обрывает уход на полпути. Держателю и стилям нужно\n * одно и то же число, поэтому оно объявлено рядом с договором, а не в одном из них.\n */\nexport const RT_ACTION_BAR_LEAVE_MS: number = 300;\n","import { Injectable, Signal, WritableSignal, signal } from '@angular/core';\n\nimport { IRtActionBar } from './rt-action-bar.model';\n\nconst EMPTY_CONFIG: IRtActionBar.Config = { selected: 0, total: 0, actions: [] };\n\n/**\n * Настройка полосы массовых действий: держатель её читает, список — пишет.\n *\n * Служба без корня намеренно. Тот, кто отмечает строки, и тот, кто рисует полосу,\n * стоят на разной глубине одного экрана, и передавать настройку вниз через всё,\n * что между ними, значит рассказать о полосе каждому из них. Потребитель\n * объявляет службу на своём уровне — там, где у него живёт список.\n */\n@Injectable()\nexport class RtActionBarService {\n readonly #config: WritableSignal<IRtActionBar.Config> = signal<IRtActionBar.Config>(EMPTY_CONFIG);\n\n public readonly config: Signal<IRtActionBar.Config> = this.#config.asReadonly();\n\n /** Список действий. Счёт не трогается: он приходит своим вызовом. */\n public setActions(actions: readonly IRtActionBar.Action[]): void {\n this.#config.update((config: IRtActionBar.Config): IRtActionBar.Config => ({ ...config, actions }));\n }\n\n /** Счёт выбранного. Полоса открывается именно им. */\n public setCounts(selected: number, total: number): void {\n this.#config.update((config: IRtActionBar.Config): IRtActionBar.Config => ({ ...config, selected, total }));\n }\n\n /** Отпустить выбранное: счёт обнуляется, список действий остаётся. */\n public clearSelection(): void {\n this.#config.update((config: IRtActionBar.Config): IRtActionBar.Config => ({ ...config, selected: 0, total: 0 }));\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n InputSignal,\n Signal,\n ViewEncapsulation,\n WritableSignal,\n computed,\n effect,\n inject,\n input,\n signal,\n untracked,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { IRtIcon } from '@rt-tools/ui-kit-v2/core';\n\nimport { RtActionBarComponent } from './rt-action-bar.component';\nimport { IRtActionBar, RT_ACTION_BAR_LEAVE_MS } from './rt-action-bar.model';\nimport { RtActionBarService } from './rt-action-bar.service';\n\nconst BEM_BLOCK: string = 'rt-action-bar-holder';\n\n/**\n * Держатель полосы массовых действий: решает, стоит ли она в разметке, и прикалывает\n * её над страницей. Настройку читает у службы, которую потребитель объявил на своём\n * уровне — там, где у него живёт список.\n *\n * Полоса открывается счётом выбранного, а не своим признаком: два источника одного\n * признака расходятся молча, и признак, оставшийся поднятым над опустевшим выбором,\n * держал бы полосу над страницей, где ничего не выбрано.\n *\n * После закрытия полоса остаётся в разметке ровно на длительность ухода — число одно\n * и лежит в договоре рядом. Разойдясь с правилом стиля, держатель обрывал бы уход на\n * полпути.\n */\n@Component({\n selector: 'rt-action-bar-holder',\n templateUrl: './rt-action-bar-holder.component.html',\n styleUrl: './rt-action-bar-holder.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [RtActionBarComponent, BlockDirective, ElemDirective, ModDirective],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtActionBarHolderComponent {\n readonly #service: RtActionBarService = inject(RtActionBarService);\n readonly #destroyRef: DestroyRef = inject(DestroyRef);\n\n /** Уходит ли полоса прямо сейчас: разметка держит её, пока правило стиля не доиграет. */\n readonly #leaving: WritableSignal<boolean> = signal<boolean>(false);\n\n #leaveTimer: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Была ли полоса открыта до этой перемены. Без этого признака уходу не с чего начаться:\n * к минуте, когда выбранное обнулилось, и «открыта», и «стоит в разметке» уже ложь, так\n * что условие по ним не срабатывает никогда. В первом ките оно написано именно так, и\n * уход там не заводится вовсе — образец прочитан, а не перенесён.\n */\n #wasOpened: boolean = false;\n\n protected readonly config: Signal<IRtActionBar.Config> = this.#service.config;\n\n /** Выбрано ли что-нибудь: этим полоса и открывается. */\n protected readonly opened: Signal<boolean> = computed((): boolean => this.config().selected > 0);\n\n /** Стоит ли полоса в разметке: она остаётся в ней и на время ухода. */\n protected readonly shown: Signal<boolean> = computed((): boolean => this.opened() || this.#leaving());\n\n protected readonly leaving: Signal<boolean> = this.#leaving.asReadonly();\n\n /** Значок кнопки, закрывающей полосу, — уходит в саму полосу. */\n public readonly closeIcon: InputSignal<IRtIcon.Name> = input<IRtIcon.Name>('close');\n\n constructor() {\n effect((): void => {\n const opened: boolean = this.opened();\n\n untracked((): void => {\n this.#clearLeaveTimer();\n\n if (opened) {\n this.#wasOpened = true;\n this.#leaving.set(false);\n\n return;\n }\n\n if (this.#wasOpened) {\n this.#wasOpened = false;\n this.#startLeaving();\n }\n });\n });\n\n this.#destroyRef.onDestroy((): void => this.#clearLeaveTimer());\n }\n\n /** Крестик сообщает наружу; выбранное отпускает служба, которой список и владеет. */\n protected onClosed(): void {\n this.#service.clearSelection();\n }\n\n /** Полоса остаётся в разметке на время ухода и снимается по его концу. */\n #startLeaving(): void {\n this.#leaving.set(true);\n this.#leaveTimer = setTimeout((): void => {\n this.#leaving.set(false);\n this.#leaveTimer = null;\n }, RT_ACTION_BAR_LEAVE_MS);\n }\n\n #clearLeaveTimer(): void {\n if (this.#leaveTimer !== null) {\n clearTimeout(this.#leaveTimer);\n this.#leaveTimer = null;\n }\n }\n}\n","<ng-container rtBlock=\"rt-action-bar-holder\">\n @if (shown()) {\n <rt-action-bar\n rtElem=\"bar\"\n qa-dataid=\"action-bar-holder-bar\"\n [rtMod]=\"{ leaving: leaving() }\"\n [config]=\"config()\"\n [closeIcon]=\"closeIcon()\"\n (closed)=\"onClosed()\" />\n }\n</ng-container>\n"],"mappings":"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"}
|
|
@@ -344,6 +344,7 @@ var RtAutocompleteComponent = class RtAutocompleteComponent extends RtFormContro
|
|
|
344
344
|
"rtPopoverFitViewport",
|
|
345
345
|
"rtPopoverContext",
|
|
346
346
|
"rtPopoverPanelClass",
|
|
347
|
+
"rtPopoverBackdropClass",
|
|
347
348
|
"rtPopoverDisabled",
|
|
348
349
|
"rtPopoverOffsetY",
|
|
349
350
|
"rtPopoverOffsetX",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rt-tools-ui-kit-v2-autocomplete.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/autocomplete/rt-autocomplete.component.ts","../../../projects/ui-kit-v2/src/lib/components/autocomplete/rt-autocomplete.component.html"],"sourcesContent":["import { BooleanInput } from '@angular/cdk/coercion';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n booleanAttribute,\n computed,\n forwardRef,\n inject,\n input,\n output,\n signal,\n viewChild,\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n InputSignal,\n InputSignalWithTransform,\n OutputEmitterRef,\n Signal,\n TemplateRef,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { RT_KIT_LABELS, TRtKitLabelMap } from '@rt-tools/ui-kit-v2/core';\nimport { RtFormControlBase } from '@rt-tools/ui-kit-v2/form-control';\nimport { IRtIcon } from '@rt-tools/ui-kit-v2/core';\nimport { RtIconComponent } from '@rt-tools/ui-kit-v2/icon';\nimport { RtIconButtonComponent } from '@rt-tools/ui-kit-v2/icon-button';\nimport { RtSpinnerComponent } from '@rt-tools/ui-kit-v2/spinner';\nimport { RtPopoverDirective } from '@rt-tools/ui-kit-v2/popover';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\nimport { RtOptionList, TRtOptionListAction } from '@rt-tools/ui-kit-v2/core';\nimport { IRtAutocomplete } from './rt-autocomplete.model';\n\n/** Сколько точек до дна панели уже считается концом списка. */\nconst END_THRESHOLD_PX: number = 8;\n\nconst BEM_BLOCK: string = 'rt-autocomplete';\n\nlet panelIdSeed: number = 0;\n\nfunction nextPanelId(): number {\n panelIdSeed += 1;\n return panelIdSeed;\n}\n\n/**\n * Typeahead/autocomplete с server-side filter через `(complete)` event.\n *\n * Panel рендерится через CDK Overlay (`[rtPopover]` trigger=\"manual\" на input'е)\n * — открывается по набору текста (не click/hover), не обрезается overflow.\n * Подписчик получает `(complete)` с текущей строкой и сам грузит подсказки.\n *\n * CVA через общий `RtFormControlBase`. Generic `TItem` — тип подсказки и\n * selected value. Крестик (`clearable`) виден при непустом тексте — очищает и\n * текст, и выбранный объект. Keyboard-nav (activedescendant): ArrowUp/Down —\n * highlight, Enter — выбрать активную, Escape — закрыть. Home/End — deferred.\n */\n@Component({\n selector: 'rt-autocomplete',\n templateUrl: './rt-autocomplete.component.html',\n styleUrl: './rt-autocomplete.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // Angular\n NgTemplateOutlet,\n\n // standalone components / directives\n RtIconButtonComponent,\n RtIconComponent,\n RtPopoverDirective,\n RtSpinnerComponent,\n BlockDirective,\n ElemDirective,\n ModDirective,\n ],\n providers: [\n // Алиас базового токена — для contentChild(RtFormControlBase) в rt-field.\n { provide: RtFormControlBase, useExisting: forwardRef(() => RtAutocompleteComponent) },\n ],\n hostDirectives: [{ directive: RtRadiusDirective, inputs: ['radius'] }],\n host: {\n class: BEM_BLOCK,\n '[class.rt-autocomplete--open]': 'isOpen()',\n '[class.rt-autocomplete--disabled]': 'isDisabled()',\n '[class.rt-autocomplete--readonly]': 'isReadonly()',\n '[class.rt-autocomplete--invalid]': 'isInvalid()',\n '[class.rt-autocomplete--borderless]': '!bordered()',\n '[class.rt-autocomplete--size--sm]': \"size() === 'sm'\",\n '[class.rt-autocomplete--size--lg]': \"size() === 'lg'\",\n },\n})\nexport class RtAutocompleteComponent<TItem> extends RtFormControlBase<TItem | null> {\n /** Длина списка, на которой конец уже сообщён: прокрутка у дна до новой страницы его не повторяет. */\n #endReportedAt: number = -1;\n\n protected readonly t: Signal<TRtKitLabelMap> = inject(RT_KIT_LABELS);\n\n protected readonly panelId: string = `rt-autocomplete-panel-${nextPanelId()}`;\n\n protected readonly popover: Signal<RtPopoverDirective> = viewChild.required(RtPopoverDirective);\n\n protected readonly fieldEl: Signal<ElementRef<HTMLInputElement> | undefined> = viewChild<ElementRef<HTMLInputElement>>('fieldEl');\n\n protected readonly inputText: WritableSignal<string> = signal<string>('');\n\n protected readonly isOpen: Signal<boolean> = computed((): boolean => this.popover().isOpen());\n\n /** Клавиатура списка: подсветка, клавиши открытия, id для `aria-activedescendant`, прокрутка к опции. */\n protected readonly optionList: RtOptionList = new RtOptionList({\n panelId: (): string => this.panelId,\n isOpen: (): boolean => this.isOpen(),\n count: (): number => this.suggestions().length,\n chooseKeys: new Set<string>(['Enter']),\n sideKeys: false,\n edgeKeys: false,\n });\n\n protected readonly activeIndex: WritableSignal<number> = this.optionList.activeIndex;\n\n /** Идентификатор подсвеченной опции — тот же, что уходит в `aria-activedescendant`. */\n protected readonly activeOptionId: Signal<string | null> = this.optionList.activeOptionId;\n\n protected readonly hasValue: Signal<boolean> = computed((): boolean => this.inputText() !== '');\n\n public readonly displayText: Signal<string> = computed((): string => this.displayWith()(this.value()));\n\n public readonly suggestions: InputSignal<ReadonlyArray<TItem>> = input<ReadonlyArray<TItem>>([]);\n\n public readonly displayWith: InputSignal<(item: TItem | null) => string> = input<(item: TItem | null) => string>(\n (item: TItem | null): string => String(item ?? '')\n );\n\n public readonly placeholder: InputSignal<string> = input<string>('');\n public readonly minLength: InputSignal<number> = input<number>(1);\n\n /** Префикс-иконка слева в поле (например, `map` для поиска). */\n public readonly iconLeft: InputSignal<IRtIcon.Name | null> = input<IRtIcon.Name | null>(null);\n\n public readonly openOnFocus: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n public readonly itemTemplate: InputSignal<TemplateRef<{ $implicit: TItem }> | null> = input<TemplateRef<{ $implicit: TItem }> | null>(\n null\n );\n\n /**\n * Подсказки грузятся: в панели строка со спиннером — вместо пустого результата при первой загрузке\n * и под списком при подгрузке следующей страницы.\n */\n public readonly loading: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Свой текст пустого результата; `null` — подпись кита `uiNothingFound`. */\n public readonly emptyText: InputSignal<string | null> = input<string | null>(null);\n\n /** Своя разметка пустого результата; сильнее `emptyText`. Обстановка — набранная строка. */\n public readonly emptyTemplate: InputSignal<TemplateRef<{ $implicit: string }> | null> = input<TemplateRef<{\n $implicit: string;\n }> | null>(null);\n\n /**\n * Панель долистали до конца — пора просить следующую страницу. Не приходит, пока идёт загрузка, и\n * приходит один раз на каждую длину списка: прокрутка у дна до прихода страницы её не повторяет.\n */\n public readonly scrolledToEnd: OutputEmitterRef<void> = output<void>();\n\n public readonly complete: OutputEmitterRef<IRtAutocomplete.CompleteEvent> = output<IRtAutocomplete.CompleteEvent>();\n\n public readonly itemSelect: OutputEmitterRef<TItem> = output<TItem>();\n\n public override writeValue(value: TItem | null): void {\n super.writeValue(value);\n this.inputText.set(this.displayWith()(this.value()));\n }\n\n public override setDisabledState(disabled: boolean): void {\n super.setDisabledState(disabled);\n if (disabled) {\n this.popover().close();\n }\n }\n\n protected getEmptyValue(): TItem | null {\n return null;\n }\n\n protected focusAfterClear(): void {\n this.fieldEl()?.nativeElement.focus();\n }\n\n protected override clearValue(): void {\n super.clearValue();\n this.inputText.set('');\n this.#endReportedAt = -1;\n }\n\n protected onInput(event: Event): void {\n const target: HTMLInputElement = event.target as HTMLInputElement;\n const query: string = target.value;\n this.inputText.set(query);\n this.activeIndex.set(-1);\n // Новый запрос — новый список: его первая страница той же длины, что прошлый список, снова\n // сообщает о дне, иначе подгрузка нового запроса не началась бы вовсе.\n this.#endReportedAt = -1;\n if (query.length >= this.minLength()) {\n this.complete.emit({ query, originalEvent: event });\n this.popover().open();\n } else {\n this.popover().close();\n }\n }\n\n protected onFocus(): void {\n if (!this.openOnFocus()) {\n return;\n }\n this.complete.emit({ query: this.inputText(), originalEvent: new Event('focus') });\n this.popover().open();\n }\n\n protected onBlur(): void {\n this.markTouched();\n }\n\n /** Прокрутка панели: у дна — сообщить, что пора следующая страница. */\n protected onPanelScroll(event: Event): void {\n const panel: HTMLElement = event.target as HTMLElement;\n const atEnd: boolean = panel.scrollTop + panel.clientHeight >= panel.scrollHeight - END_THRESHOLD_PX;\n const length: number = this.suggestions().length;\n if (!atEnd || this.loading() || length === this.#endReportedAt) {\n return;\n }\n this.#endReportedAt = length;\n this.scrolledToEnd.emit();\n }\n\n protected onClosed(): void {\n this.activeIndex.set(-1);\n }\n\n protected onSelect(item: TItem): void {\n this.value.set(item);\n this.inputText.set(this.displayWith()(item));\n this.emitChange(item);\n this.itemSelect.emit(item);\n this.popover().close();\n }\n\n protected onInputKeydown(event: KeyboardEvent): void {\n if (this.isDisabled()) {\n return;\n }\n const key: string = event.key;\n if (!this.isOpen()) {\n return;\n }\n const action: TRtOptionListAction = this.optionList.actionOf(key);\n if (action === 'none' || action === 'side') {\n return;\n }\n event.preventDefault();\n switch (action) {\n case 'next':\n this.optionList.move(1);\n break;\n case 'previous':\n this.optionList.move(-1);\n break;\n case 'choose':\n this.#selectActive();\n break;\n case 'close':\n // Escape закрывает один слой: панель. Без остановки событие всплывает до document,\n // и оверлей под панелью — боковая панель, окно — закрывается вместе с ней.\n event.stopPropagation();\n this.popover().close();\n break;\n }\n }\n\n #selectActive(): void {\n const items: ReadonlyArray<TItem> = this.suggestions();\n const index: number = this.activeIndex();\n if (index >= 0 && index < items.length) {\n this.onSelect(items[index]);\n }\n }\n}\n","<ng-container rtBlock=\"rt-autocomplete\">\n @if (isReadonly()) {\n <span rtElem=\"readonly\" qa-dataid=\"autocomplete-readonly\" [rtMod]=\"{ empty: !displayText() }\">{{ displayText() || '—' }}</span>\n }\n <div rtElem=\"field\" rtPopoverTrigger=\"manual\" rtPopoverWidth=\"trigger\" [rtPopover]=\"panelTpl\" (rtPopoverClosed)=\"onClosed()\">\n @if (iconLeft(); as left) {\n <rt-icon rtElem=\"icon-left\" size=\"sm\" color=\"muted\" [name]=\"left\" />\n }\n <input\n #fieldEl\n rtElem=\"input\"\n qa-dataid=\"autocomplete-input\"\n type=\"text\"\n autocomplete=\"off\"\n role=\"combobox\"\n [attr.id]=\"effectiveControlId()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-invalid]=\"isInvalid() || null\"\n [attr.aria-autocomplete]=\"'list'\"\n [attr.aria-controls]=\"panelId\"\n [attr.aria-activedescendant]=\"activeOptionId()\"\n [placeholder]=\"placeholder()\"\n [value]=\"inputText()\"\n [disabled]=\"isDisabled()\"\n (input)=\"onInput($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n (keydown)=\"onInputKeydown($event)\" />\n @if (showClearButton()) {\n <rt-icon-button\n rtElem=\"clear\"\n qa-dataid=\"autocomplete-clear\"\n icon=\"ico-close\"\n size=\"sm\"\n variant=\"ghost\"\n iconColor=\"muted\"\n [ariaLabel]=\"t().uiClear\"\n [tabIndex]=\"-1\"\n (clicked)=\"clear($event)\" />\n }\n </div>\n\n <ng-template #panelTpl>\n <!--\n Опции выбираются мышью через (click); keyboard-nav — на input'е\n (activedescendant), опции не focusable индивидуально.\n -->\n <!-- eslint-disable @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <ul\n rtElem=\"panel\"\n qa-dataid=\"autocomplete-panel\"\n role=\"listbox\"\n [id]=\"panelId\"\n [attr.aria-busy]=\"loading() || null\"\n (scroll)=\"onPanelScroll($event)\">\n @for (item of suggestions(); track $index; let i = $index) {\n <li\n rtElem=\"option\"\n qa-dataid=\"autocomplete-option\"\n role=\"option\"\n [id]=\"panelId + '-opt-' + i\"\n [rtMod]=\"{ active: i === activeIndex() }\"\n [attr.aria-selected]=\"item === value()\"\n (click)=\"onSelect(item)\">\n @if (itemTemplate(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: item }\" />\n } @else {\n {{ displayWith()(item) }}\n }\n </li>\n } @empty {\n @if (!loading()) {\n <li rtElem=\"empty\" qa-dataid=\"autocomplete-empty\">\n @if (emptyTemplate(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: inputText() }\" />\n } @else {\n {{ emptyText() ?? t().uiNothingFound }}\n }\n </li>\n }\n }\n @if (loading()) {\n <li rtElem=\"loading\" qa-dataid=\"autocomplete-loading\" aria-hidden=\"true\">\n <rt-spinner [diameter]=\"20\" />\n </li>\n }\n </ul>\n </ng-template>\n</ng-container>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rt-tools-ui-kit-v2-autocomplete.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/autocomplete/rt-autocomplete.component.ts","../../../projects/ui-kit-v2/src/lib/components/autocomplete/rt-autocomplete.component.html"],"sourcesContent":["import { BooleanInput } from '@angular/cdk/coercion';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n booleanAttribute,\n computed,\n forwardRef,\n inject,\n input,\n output,\n signal,\n viewChild,\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n InputSignal,\n InputSignalWithTransform,\n OutputEmitterRef,\n Signal,\n TemplateRef,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { RT_KIT_LABELS, TRtKitLabelMap } from '@rt-tools/ui-kit-v2/core';\nimport { RtFormControlBase } from '@rt-tools/ui-kit-v2/form-control';\nimport { IRtIcon } from '@rt-tools/ui-kit-v2/core';\nimport { RtIconComponent } from '@rt-tools/ui-kit-v2/icon';\nimport { RtIconButtonComponent } from '@rt-tools/ui-kit-v2/icon-button';\nimport { RtSpinnerComponent } from '@rt-tools/ui-kit-v2/spinner';\nimport { RtPopoverDirective } from '@rt-tools/ui-kit-v2/popover';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\nimport { RtOptionList, TRtOptionListAction } from '@rt-tools/ui-kit-v2/core';\nimport { IRtAutocomplete } from './rt-autocomplete.model';\n\n/** Сколько точек до дна панели уже считается концом списка. */\nconst END_THRESHOLD_PX: number = 8;\n\nconst BEM_BLOCK: string = 'rt-autocomplete';\n\nlet panelIdSeed: number = 0;\n\nfunction nextPanelId(): number {\n panelIdSeed += 1;\n return panelIdSeed;\n}\n\n/**\n * Typeahead/autocomplete с server-side filter через `(complete)` event.\n *\n * Panel рендерится через CDK Overlay (`[rtPopover]` trigger=\"manual\" на input'е)\n * — открывается по набору текста (не click/hover), не обрезается overflow.\n * Подписчик получает `(complete)` с текущей строкой и сам грузит подсказки.\n *\n * CVA через общий `RtFormControlBase`. Generic `TItem` — тип подсказки и\n * selected value. Крестик (`clearable`) виден при непустом тексте — очищает и\n * текст, и выбранный объект. Keyboard-nav (activedescendant): ArrowUp/Down —\n * highlight, Enter — выбрать активную, Escape — закрыть. Home/End — deferred.\n */\n@Component({\n selector: 'rt-autocomplete',\n templateUrl: './rt-autocomplete.component.html',\n styleUrl: './rt-autocomplete.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // Angular\n NgTemplateOutlet,\n\n // standalone components / directives\n RtIconButtonComponent,\n RtIconComponent,\n RtPopoverDirective,\n RtSpinnerComponent,\n BlockDirective,\n ElemDirective,\n ModDirective,\n ],\n providers: [\n // Алиас базового токена — для contentChild(RtFormControlBase) в rt-field.\n { provide: RtFormControlBase, useExisting: forwardRef(() => RtAutocompleteComponent) },\n ],\n hostDirectives: [{ directive: RtRadiusDirective, inputs: ['radius'] }],\n host: {\n class: BEM_BLOCK,\n '[class.rt-autocomplete--open]': 'isOpen()',\n '[class.rt-autocomplete--disabled]': 'isDisabled()',\n '[class.rt-autocomplete--readonly]': 'isReadonly()',\n '[class.rt-autocomplete--invalid]': 'isInvalid()',\n '[class.rt-autocomplete--borderless]': '!bordered()',\n '[class.rt-autocomplete--size--sm]': \"size() === 'sm'\",\n '[class.rt-autocomplete--size--lg]': \"size() === 'lg'\",\n },\n})\nexport class RtAutocompleteComponent<TItem> extends RtFormControlBase<TItem | null> {\n /** Длина списка, на которой конец уже сообщён: прокрутка у дна до новой страницы его не повторяет. */\n #endReportedAt: number = -1;\n\n protected readonly t: Signal<TRtKitLabelMap> = inject(RT_KIT_LABELS);\n\n protected readonly panelId: string = `rt-autocomplete-panel-${nextPanelId()}`;\n\n protected readonly popover: Signal<RtPopoverDirective> = viewChild.required(RtPopoverDirective);\n\n protected readonly fieldEl: Signal<ElementRef<HTMLInputElement> | undefined> = viewChild<ElementRef<HTMLInputElement>>('fieldEl');\n\n protected readonly inputText: WritableSignal<string> = signal<string>('');\n\n protected readonly isOpen: Signal<boolean> = computed((): boolean => this.popover().isOpen());\n\n /** Клавиатура списка: подсветка, клавиши открытия, id для `aria-activedescendant`, прокрутка к опции. */\n protected readonly optionList: RtOptionList = new RtOptionList({\n panelId: (): string => this.panelId,\n isOpen: (): boolean => this.isOpen(),\n count: (): number => this.suggestions().length,\n chooseKeys: new Set<string>(['Enter']),\n sideKeys: false,\n edgeKeys: false,\n });\n\n protected readonly activeIndex: WritableSignal<number> = this.optionList.activeIndex;\n\n /** Идентификатор подсвеченной опции — тот же, что уходит в `aria-activedescendant`. */\n protected readonly activeOptionId: Signal<string | null> = this.optionList.activeOptionId;\n\n protected readonly hasValue: Signal<boolean> = computed((): boolean => this.inputText() !== '');\n\n public readonly displayText: Signal<string> = computed((): string => this.displayWith()(this.value()));\n\n public readonly suggestions: InputSignal<ReadonlyArray<TItem>> = input<ReadonlyArray<TItem>>([]);\n\n public readonly displayWith: InputSignal<(item: TItem | null) => string> = input<(item: TItem | null) => string>(\n (item: TItem | null): string => String(item ?? '')\n );\n\n public readonly placeholder: InputSignal<string> = input<string>('');\n public readonly minLength: InputSignal<number> = input<number>(1);\n\n /** Префикс-иконка слева в поле (например, `map` для поиска). */\n public readonly iconLeft: InputSignal<IRtIcon.Name | null> = input<IRtIcon.Name | null>(null);\n\n public readonly openOnFocus: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n public readonly itemTemplate: InputSignal<TemplateRef<{ $implicit: TItem }> | null> = input<TemplateRef<{ $implicit: TItem }> | null>(\n null\n );\n\n /**\n * Подсказки грузятся: в панели строка со спиннером — вместо пустого результата при первой загрузке\n * и под списком при подгрузке следующей страницы.\n */\n public readonly loading: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Свой текст пустого результата; `null` — подпись кита `uiNothingFound`. */\n public readonly emptyText: InputSignal<string | null> = input<string | null>(null);\n\n /** Своя разметка пустого результата; сильнее `emptyText`. Обстановка — набранная строка. */\n public readonly emptyTemplate: InputSignal<TemplateRef<{ $implicit: string }> | null> = input<TemplateRef<{\n $implicit: string;\n }> | null>(null);\n\n /**\n * Панель долистали до конца — пора просить следующую страницу. Не приходит, пока идёт загрузка, и\n * приходит один раз на каждую длину списка: прокрутка у дна до прихода страницы её не повторяет.\n */\n public readonly scrolledToEnd: OutputEmitterRef<void> = output<void>();\n\n public readonly complete: OutputEmitterRef<IRtAutocomplete.CompleteEvent> = output<IRtAutocomplete.CompleteEvent>();\n\n public readonly itemSelect: OutputEmitterRef<TItem> = output<TItem>();\n\n public override writeValue(value: TItem | null): void {\n super.writeValue(value);\n this.inputText.set(this.displayWith()(this.value()));\n }\n\n public override setDisabledState(disabled: boolean): void {\n super.setDisabledState(disabled);\n if (disabled) {\n this.popover().close();\n }\n }\n\n protected getEmptyValue(): TItem | null {\n return null;\n }\n\n protected focusAfterClear(): void {\n this.fieldEl()?.nativeElement.focus();\n }\n\n protected override clearValue(): void {\n super.clearValue();\n this.inputText.set('');\n this.#endReportedAt = -1;\n }\n\n protected onInput(event: Event): void {\n const target: HTMLInputElement = event.target as HTMLInputElement;\n const query: string = target.value;\n this.inputText.set(query);\n this.activeIndex.set(-1);\n // Новый запрос — новый список: его первая страница той же длины, что прошлый список, снова\n // сообщает о дне, иначе подгрузка нового запроса не началась бы вовсе.\n this.#endReportedAt = -1;\n if (query.length >= this.minLength()) {\n this.complete.emit({ query, originalEvent: event });\n this.popover().open();\n } else {\n this.popover().close();\n }\n }\n\n protected onFocus(): void {\n if (!this.openOnFocus()) {\n return;\n }\n this.complete.emit({ query: this.inputText(), originalEvent: new Event('focus') });\n this.popover().open();\n }\n\n protected onBlur(): void {\n this.markTouched();\n }\n\n /** Прокрутка панели: у дна — сообщить, что пора следующая страница. */\n protected onPanelScroll(event: Event): void {\n const panel: HTMLElement = event.target as HTMLElement;\n const atEnd: boolean = panel.scrollTop + panel.clientHeight >= panel.scrollHeight - END_THRESHOLD_PX;\n const length: number = this.suggestions().length;\n if (!atEnd || this.loading() || length === this.#endReportedAt) {\n return;\n }\n this.#endReportedAt = length;\n this.scrolledToEnd.emit();\n }\n\n protected onClosed(): void {\n this.activeIndex.set(-1);\n }\n\n protected onSelect(item: TItem): void {\n this.value.set(item);\n this.inputText.set(this.displayWith()(item));\n this.emitChange(item);\n this.itemSelect.emit(item);\n this.popover().close();\n }\n\n protected onInputKeydown(event: KeyboardEvent): void {\n if (this.isDisabled()) {\n return;\n }\n const key: string = event.key;\n if (!this.isOpen()) {\n return;\n }\n const action: TRtOptionListAction = this.optionList.actionOf(key);\n if (action === 'none' || action === 'side') {\n return;\n }\n event.preventDefault();\n switch (action) {\n case 'next':\n this.optionList.move(1);\n break;\n case 'previous':\n this.optionList.move(-1);\n break;\n case 'choose':\n this.#selectActive();\n break;\n case 'close':\n // Escape закрывает один слой: панель. Без остановки событие всплывает до document,\n // и оверлей под панелью — боковая панель, окно — закрывается вместе с ней.\n event.stopPropagation();\n this.popover().close();\n break;\n }\n }\n\n #selectActive(): void {\n const items: ReadonlyArray<TItem> = this.suggestions();\n const index: number = this.activeIndex();\n if (index >= 0 && index < items.length) {\n this.onSelect(items[index]);\n }\n }\n}\n","<ng-container rtBlock=\"rt-autocomplete\">\n @if (isReadonly()) {\n <span rtElem=\"readonly\" qa-dataid=\"autocomplete-readonly\" [rtMod]=\"{ empty: !displayText() }\">{{ displayText() || '—' }}</span>\n }\n <div rtElem=\"field\" rtPopoverTrigger=\"manual\" rtPopoverWidth=\"trigger\" [rtPopover]=\"panelTpl\" (rtPopoverClosed)=\"onClosed()\">\n @if (iconLeft(); as left) {\n <rt-icon rtElem=\"icon-left\" size=\"sm\" color=\"muted\" [name]=\"left\" />\n }\n <input\n #fieldEl\n rtElem=\"input\"\n qa-dataid=\"autocomplete-input\"\n type=\"text\"\n autocomplete=\"off\"\n role=\"combobox\"\n [attr.id]=\"effectiveControlId()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-invalid]=\"isInvalid() || null\"\n [attr.aria-autocomplete]=\"'list'\"\n [attr.aria-controls]=\"panelId\"\n [attr.aria-activedescendant]=\"activeOptionId()\"\n [placeholder]=\"placeholder()\"\n [value]=\"inputText()\"\n [disabled]=\"isDisabled()\"\n (input)=\"onInput($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n (keydown)=\"onInputKeydown($event)\" />\n @if (showClearButton()) {\n <rt-icon-button\n rtElem=\"clear\"\n qa-dataid=\"autocomplete-clear\"\n icon=\"ico-close\"\n size=\"sm\"\n variant=\"ghost\"\n iconColor=\"muted\"\n [ariaLabel]=\"t().uiClear\"\n [tabIndex]=\"-1\"\n (clicked)=\"clear($event)\" />\n }\n </div>\n\n <ng-template #panelTpl>\n <!--\n Опции выбираются мышью через (click); keyboard-nav — на input'е\n (activedescendant), опции не focusable индивидуально.\n -->\n <!-- eslint-disable @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <ul\n rtElem=\"panel\"\n qa-dataid=\"autocomplete-panel\"\n role=\"listbox\"\n [id]=\"panelId\"\n [attr.aria-busy]=\"loading() || null\"\n (scroll)=\"onPanelScroll($event)\">\n @for (item of suggestions(); track $index; let i = $index) {\n <li\n rtElem=\"option\"\n qa-dataid=\"autocomplete-option\"\n role=\"option\"\n [id]=\"panelId + '-opt-' + i\"\n [rtMod]=\"{ active: i === activeIndex() }\"\n [attr.aria-selected]=\"item === value()\"\n (click)=\"onSelect(item)\">\n @if (itemTemplate(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: item }\" />\n } @else {\n {{ displayWith()(item) }}\n }\n </li>\n } @empty {\n @if (!loading()) {\n <li rtElem=\"empty\" qa-dataid=\"autocomplete-empty\">\n @if (emptyTemplate(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: inputText() }\" />\n } @else {\n {{ emptyText() ?? t().uiNothingFound }}\n }\n </li>\n }\n }\n @if (loading()) {\n <li rtElem=\"loading\" qa-dataid=\"autocomplete-loading\" aria-hidden=\"true\">\n <rt-spinner [diameter]=\"20\" />\n </li>\n }\n </ul>\n </ng-template>\n</ng-container>\n"],"mappings":"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"}
|
|
@@ -666,6 +666,7 @@ var RtColorPaletteComponent = class RtColorPaletteComponent extends RtFormContro
|
|
|
666
666
|
"rtPopoverFitViewport",
|
|
667
667
|
"rtPopoverContext",
|
|
668
668
|
"rtPopoverPanelClass",
|
|
669
|
+
"rtPopoverBackdropClass",
|
|
669
670
|
"rtPopoverDisabled",
|
|
670
671
|
"rtPopoverOffsetY",
|
|
671
672
|
"rtPopoverOffsetX",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rt-tools-ui-kit-v2-color-palette.mjs","names":["BEM_BLOCK"],"sources":["../../../projects/ui-kit-v2/src/lib/components/color-palette/rt-color-palette.const.ts","../../../projects/ui-kit-v2/src/lib/components/color-palette/rt-color-palette.logic.ts","../../../projects/ui-kit-v2/src/lib/components/color-palette/picker/rt-color-picker.component.ts","../../../projects/ui-kit-v2/src/lib/components/color-palette/picker/rt-color-picker.component.html","../../../projects/ui-kit-v2/src/lib/components/color-palette/rt-color-palette.component.ts","../../../projects/ui-kit-v2/src/lib/components/color-palette/rt-color-palette.component.html"],"sourcesContent":["/**\n * Набор палитры по умолчанию, восемнадцать цветов: шестнадцать оттенков по кругу, затем коричневый и\n * серо-синий. Набор темы приложение передаёт входом `colors` — он свой у каждого продукта.\n */\nexport const RT_COLOR_PALETTE_DEFAULT: readonly string[] = [\n '#f44336',\n '#e91e63',\n '#9c27b0',\n '#673ab7',\n '#3f51b5',\n '#2196f3',\n '#03a9f4',\n '#00bcd4',\n '#009688',\n '#4caf50',\n '#8bc34a',\n '#cddc39',\n '#ffeb3b',\n '#ffc107',\n '#ff9800',\n '#ff5722',\n '#795548',\n '#607d8b',\n];\n","import { RT_COLOR_PALETTE_DEFAULT } from './rt-color-palette.const';\nimport { IRtColorPalette } from './rt-color-palette.model';\n\nconst SHORT_HEX: RegExp = /^#?([0-9a-f])([0-9a-f])([0-9a-f])$/i;\nconst FULL_HEX: RegExp = /^#?([0-9a-f]{6})$/i;\nconst CHANNEL: RegExp = /^\\d{1,3}$/;\n\n/** Шаг стрелки: по площади — двадцатая доля насыщенности и яркости, по полосе — шесть градусов оттенка. */\nconst AREA_STEP: number = 0.05;\nconst HUE_STEP: number = 6;\n\n/** Сдвиг оттенка стрелкой по полосе: вправо и вверх — дальше по кругу, влево и вниз — назад. */\nconst HUE_MOVES: Readonly<Partial<Record<string, number>>> = {\n ArrowRight: HUE_STEP,\n ArrowUp: HUE_STEP,\n ArrowLeft: -HUE_STEP,\n ArrowDown: -HUE_STEP,\n};\n\n/** Сдвиг стрелкой по площади: вправо и влево — насыщенность, вверх и вниз — яркость. */\nconst AREA_MOVES: Readonly<Partial<Record<string, readonly ['s' | 'v', number]>>> = {\n ArrowRight: ['s', AREA_STEP],\n ArrowLeft: ['s', -AREA_STEP],\n ArrowUp: ['v', AREA_STEP],\n ArrowDown: ['v', -AREA_STEP],\n};\n\n/** Опорные оттенки полосы: шесть вершин круга и возврат к красному. */\nconst SPECTRUM_HUES: readonly number[] = [0, 60, 120, 180, 240, 300, 0];\n\n/** Доля в пределах от нуля до единицы. */\nfunction clamp(value: number): number {\n return Math.min(1, Math.max(0, value));\n}\n\n/**\n * Цвет поля в его единственном виде: `#rrggbb` строчными. Трёхзначная запись разворачивается, решётка\n * дописывается. Всё остальное — не цвет: поле рисует его как «цвет не выбран».\n */\nexport function colorPaletteHex(value: unknown): string | null {\n if (typeof value !== 'string') {\n return null;\n }\n\n const text: string = value.trim();\n const short: RegExpExecArray | null = SHORT_HEX.exec(text);\n\n if (short) {\n return `#${short[1]}${short[1]}${short[2]}${short[2]}${short[3]}${short[3]}`.toLowerCase();\n }\n\n const full: RegExpExecArray | null = FULL_HEX.exec(text);\n\n return full ? `#${full[1].toLowerCase()}` : null;\n}\n\n/**\n * Образцы палитры: цвета входа по порядку, без них — набор кита. Значение, которого среди них нет,\n * встаёт ещё одним образцом в конце: человек видит, что выбран свой цвет, и может вернуться к нему.\n * Неверные цвета входа и повторы отбрасываются — образцу нужен цвет, а номеру в группе единственность.\n */\nexport function colorPaletteSwatches(colors: readonly string[], value: string | null): IRtColorPalette.Swatch[] {\n const source: readonly string[] = colors.length > 0 ? colors : RT_COLOR_PALETTE_DEFAULT;\n const seen: Set<string> = new Set<string>();\n const swatches: IRtColorPalette.Swatch[] = [];\n\n for (const color of source) {\n const hex: string | null = colorPaletteHex(color);\n\n if (hex !== null && !seen.has(hex)) {\n seen.add(hex);\n swatches.push({ hex, custom: false });\n }\n }\n\n if (value !== null && !seen.has(value)) {\n swatches.push({ hex: value, custom: true });\n }\n\n return swatches;\n}\n\n/**\n * Куда клавиша переводит выбор среди образцов: стрелки идут по кругу, Home и End берут крайние.\n * Строки образцов зависят от ширины поля, поэтому вверх и вниз значат «назад» и «вперёд», как в\n * группе переключателей. `null` — клавиша не про выбор.\n */\nexport function colorPaletteNextIndex(key: string, current: number, count: number): number | null {\n if (count === 0) {\n return null;\n }\n\n switch (key) {\n case 'ArrowDown':\n case 'ArrowRight':\n return current < 0 ? 0 : (current + 1) % count;\n case 'ArrowUp':\n case 'ArrowLeft':\n return current < 0 ? count - 1 : (current - 1 + count) % count;\n case 'Home':\n return 0;\n case 'End':\n return count - 1;\n default:\n return null;\n }\n}\n\n/** Цвет `#rrggbb` в оттенке, насыщенности и яркости. Оттенок серого — ноль. */\nexport function colorPaletteToHsv(hex: string): IRtColorPalette.Hsv {\n const r: number = parseInt(hex.slice(1, 3), 16) / 255;\n const g: number = parseInt(hex.slice(3, 5), 16) / 255;\n const b: number = parseInt(hex.slice(5, 7), 16) / 255;\n const max: number = Math.max(r, g, b);\n const delta: number = max - Math.min(r, g, b);\n\n let h: number = 0;\n\n if (delta > 0) {\n if (max === r) {\n h = 60 * (((g - b) / delta + 6) % 6);\n } else if (max === g) {\n h = 60 * ((b - r) / delta + 2);\n } else {\n h = 60 * ((r - g) / delta + 4);\n }\n }\n\n return { h, s: max === 0 ? 0 : delta / max, v: max };\n}\n\n/** Оттенок, насыщенность и яркость в цвете `#rrggbb`. */\nexport function colorPaletteFromHsv(hsv: IRtColorPalette.Hsv): string {\n const h: number = (((hsv.h % 360) + 360) % 360) / 60;\n const s: number = clamp(hsv.s);\n const v: number = clamp(hsv.v);\n const chroma: number = v * s;\n const x: number = chroma * (1 - Math.abs((h % 2) - 1));\n const m: number = v - chroma;\n const sector: number = Math.floor(h);\n const [r, g, b]: [number, number, number] = (\n [\n [chroma, x, 0],\n [x, chroma, 0],\n [0, chroma, x],\n [0, x, chroma],\n [x, 0, chroma],\n [chroma, 0, x],\n ] as [number, number, number][]\n )[sector % 6];\n\n return `#${[r, g, b]\n .map((channel: number): string =>\n Math.round((channel + m) * 255)\n .toString(16)\n .padStart(2, '0')\n )\n .join('')}`;\n}\n\n/**\n * Сдвиг выбранного стрелкой: по площади — насыщенность вправо и влево, яркость вверх и вниз; по полосе —\n * оттенок по кругу. `null` — клавиша не про сдвиг.\n */\nexport function colorPaletteStep(target: 'area' | 'hue', key: string, hsv: IRtColorPalette.Hsv): IRtColorPalette.Hsv | null {\n if (target === 'hue') {\n const delta: number | undefined = HUE_MOVES[key];\n\n return delta === undefined ? null : { ...hsv, h: (hsv.h + delta + 360) % 360 };\n }\n\n const move: readonly ['s' | 'v', number] | undefined = AREA_MOVES[key];\n\n if (move === undefined) {\n return null;\n }\n\n const [axis, delta]: readonly ['s' | 'v', number] = move;\n\n return { ...hsv, [axis]: clamp(hsv[axis] + delta) };\n}\n\n/** Цвет `#rrggbb` в каналах красного, зелёного и синего. */\nexport function colorPaletteToRgb(hex: string): IRtColorPalette.Rgb {\n return {\n r: parseInt(hex.slice(1, 3), 16),\n g: parseInt(hex.slice(3, 5), 16),\n b: parseInt(hex.slice(5, 7), 16),\n };\n}\n\n/** Каналы красного, зелёного и синего в цвете `#rrggbb`. */\nexport function colorPaletteFromRgb(rgb: IRtColorPalette.Rgb): string {\n return `#${[rgb.r, rgb.g, rgb.b].map((channel: number): string => channel.toString(16).padStart(2, '0')).join('')}`;\n}\n\n/**\n * Значение канала из набранного в поле: целое от 0 до 255 без знаков и дробей. Всё остальное — `null`,\n * и поле не меняет выбранного, пока ввод не окончен.\n */\nexport function colorPaletteChannel(text: string): number | null {\n const trimmed: string = text.trim();\n\n if (!CHANNEL.test(trimmed)) {\n return null;\n }\n\n const value: number = Number(trimmed);\n\n return value <= 255 ? value : null;\n}\n\n/** Полоса оттенков слева направо: градиент по вершинам круга в полной насыщенности и яркости. */\nexport function colorPaletteSpectrum(): string {\n const stops: string[] = SPECTRUM_HUES.map((h: number): string => colorPaletteFromHsv({ h, s: 1, v: 1 }));\n\n return `linear-gradient(to right, ${stops.join(', ')})`;\n}\n\n/**\n * Площадь насыщенности и яркости для оттенка `hue`: внизу чёрный, и вверх цвет ярче; слева белый, и\n * вправо цвет насыщеннее до чистого оттенка. Это математика цвета, а не оформление: слои — края\n * пространства цвета.\n */\nexport function colorPaletteArea(hue: string): string {\n const white: string = colorPaletteFromHsv({ h: 0, s: 0, v: 1 });\n const black: string = colorPaletteFromHsv({ h: 0, s: 0, v: 0 });\n\n return `linear-gradient(to top, ${black}, transparent), linear-gradient(to right, ${white}, ${hue})`;\n}\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n effect,\n inject,\n input,\n InputSignal,\n InputSignalWithTransform,\n linkedSignal,\n output,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { FormControl, ReactiveFormsModule } from '@angular/forms';\n\nimport { BlockDirective, ElemDirective } from '@rt-tools/core';\n\nimport { RtButtonDirective } from '@rt-tools/ui-kit-v2/button';\nimport { RT_KIT_LABELS, TRtKitLabelMap } from '@rt-tools/ui-kit-v2/core';\nimport { RtInputComponent } from '@rt-tools/ui-kit-v2/input';\nimport {\n colorPaletteArea,\n colorPaletteChannel,\n colorPaletteFromHsv,\n colorPaletteFromRgb,\n colorPaletteHex,\n colorPaletteSpectrum,\n colorPaletteStep,\n colorPaletteToHsv,\n colorPaletteToRgb,\n} from '../rt-color-palette.logic';\nimport { IRtColorPalette } from '../rt-color-palette.model';\n\nconst BEM_BLOCK: string = 'rt-color-picker';\nconst CHANNELS: readonly IRtColorPalette.Channel[] = ['r', 'g', 'b'];\n\n/** Поле одного канала и канал, который оно правит. */\ninterface IChannelControl {\n channel: IRtColorPalette.Channel;\n /** Буква канала над полем: R, G, B одинаковы во всех языках. */\n name: string;\n control: FormControl<string>;\n}\n\n/**\n * Выбор своего цвета палитры: площадь насыщенности и яркости, полоса оттенка, поле шестнадцатеричной\n * записи, «Отмена» и «Применить». Рисует его кит сам — сторонний выбор цвета в кит не входит.\n *\n * Выбранное живёт здесь до «Применить»: поле палитры меняется только им. Начинается выбор с цвета,\n * который пришёл входом, и «Применить» недоступно, пока выбранное с ним совпадает.\n */\n@Component({\n selector: 'rt-color-picker',\n templateUrl: './rt-color-picker.component.html',\n styleUrls: ['./rt-color-picker.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // Angular\n ReactiveFormsModule,\n\n // standalone components / directives\n RtButtonDirective,\n RtInputComponent,\n BlockDirective,\n ElemDirective,\n ],\n host: { class: BEM_BLOCK },\n})\nexport class RtColorPickerComponent {\n protected readonly t: Signal<TRtKitLabelMap> = inject(RT_KIT_LABELS);\n\n /** Цвет в оттенке, насыщенности и яркости: оттенок серого не теряется, пока человек тянет яркость. */\n protected readonly hsv: WritableSignal<IRtColorPalette.Hsv> = linkedSignal<IRtColorPalette.Hsv>((): IRtColorPalette.Hsv =>\n colorPaletteToHsv(this.value())\n );\n\n protected readonly picked: Signal<string> = computed((): string => colorPaletteFromHsv(this.hsv()));\n protected readonly changed: Signal<boolean> = computed((): boolean => this.picked() !== this.value());\n\n /** Чистый оттенок площади: её правый верхний угол. */\n protected readonly hueColor: Signal<string> = computed((): string => colorPaletteFromHsv({ h: this.hsv().h, s: 1, v: 1 }));\n protected readonly area: Signal<string> = computed((): string => colorPaletteArea(this.hueColor()));\n protected readonly spectrum: string = colorPaletteSpectrum();\n protected readonly hueDegrees: Signal<number> = computed((): number => Math.round(this.hsv().h));\n protected readonly saturation: Signal<number> = computed((): number => Math.round(this.hsv().s * 100));\n protected readonly areaText: Signal<string> = computed((): string => `${this.saturation()}%, ${Math.round(this.hsv().v * 100)}%`);\n\n protected readonly hexControl: FormControl<string> = new FormControl<string>('', { nonNullable: true });\n\n /** Поля каналов по порядку строки: красный, зелёный, синий. */\n protected readonly channelControls: readonly IChannelControl[] = CHANNELS.map((channel: IRtColorPalette.Channel): IChannelControl => ({\n channel,\n name: channel.toUpperCase(),\n control: new FormControl<string>('', { nonNullable: true }),\n }));\n\n /** Доступные имена полей каналов из словаря кита. */\n protected readonly channelLabels: Signal<Readonly<Record<IRtColorPalette.Channel, string>>> = computed(\n (): Readonly<Record<IRtColorPalette.Channel, string>> => ({\n r: this.t().uiColorPickerRed,\n g: this.t().uiColorPickerGreen,\n b: this.t().uiColorPickerBlue,\n })\n );\n\n /** Цвет, с которого начинается выбор, `#rrggbb`. */\n public readonly value: InputSignal<string> = input.required<string>();\n\n /** Строка полей красного, зелёного и синего под записью hex. Без неё — площадь, полоса и hex. */\n public readonly channels: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n public readonly applied: OutputEmitterRef<string> = output<string>();\n public readonly cancelled: OutputEmitterRef<void> = output<void>();\n\n #dragging: boolean = false;\n\n constructor() {\n // Поле записи показывает выбранное и молчит в ответ: иначе его же изменение вернулось бы\n // набранной строкой и перебило бы неоконченный ввод.\n effect((): void => {\n const hex: string = this.picked();\n\n if (colorPaletteHex(this.hexControl.value) !== hex) {\n this.hexControl.setValue(hex, { emitEvent: false });\n }\n });\n\n this.hexControl.valueChanges.pipe(takeUntilDestroyed()).subscribe((text: string): void => {\n const hex: string | null = colorPaletteHex(text);\n\n if (hex !== null && hex !== this.picked()) {\n this.hsv.set(colorPaletteToHsv(hex));\n }\n });\n\n // Поля каналов ведут себя так же: показывают выбранное и молчат в ответ, а набранное целое\n // от 0 до 255 меняет один свой канал.\n effect((): void => {\n const rgb: IRtColorPalette.Rgb = colorPaletteToRgb(this.picked());\n\n for (const { channel, control } of this.channelControls) {\n if (colorPaletteChannel(control.value) !== rgb[channel]) {\n control.setValue(String(rgb[channel]), { emitEvent: false });\n }\n }\n });\n\n for (const { channel, control } of this.channelControls) {\n control.valueChanges.pipe(takeUntilDestroyed()).subscribe((text: string): void => {\n const value: number | null = colorPaletteChannel(text);\n const rgb: IRtColorPalette.Rgb = colorPaletteToRgb(this.picked());\n\n if (value !== null && value !== rgb[channel]) {\n this.hsv.set(colorPaletteToHsv(colorPaletteFromRgb({ ...rgb, [channel]: value })));\n }\n });\n }\n }\n\n protected onAreaPointer(event: PointerEvent): void {\n if (event.type === 'pointerdown') {\n this.#dragging = true;\n (event.currentTarget as HTMLElement).setPointerCapture?.(event.pointerId);\n }\n\n if (!this.#dragging) {\n return;\n }\n\n if (event.type === 'pointerup') {\n this.#dragging = false;\n }\n\n const box: DOMRect = (event.currentTarget as HTMLElement).getBoundingClientRect();\n const s: number = box.width > 0 ? (event.clientX - box.left) / box.width : 0;\n const v: number = box.height > 0 ? 1 - (event.clientY - box.top) / box.height : 0;\n\n this.hsv.update((hsv: IRtColorPalette.Hsv): IRtColorPalette.Hsv => ({\n ...hsv,\n s: Math.min(1, Math.max(0, s)),\n v: Math.min(1, Math.max(0, v)),\n }));\n }\n\n protected onHuePointer(event: PointerEvent): void {\n if (event.type === 'pointerdown') {\n this.#dragging = true;\n (event.currentTarget as HTMLElement).setPointerCapture?.(event.pointerId);\n }\n\n if (!this.#dragging) {\n return;\n }\n\n if (event.type === 'pointerup') {\n this.#dragging = false;\n }\n\n const box: DOMRect = (event.currentTarget as HTMLElement).getBoundingClientRect();\n const share: number = box.width > 0 ? Math.min(1, Math.max(0, (event.clientX - box.left) / box.width)) : 0;\n\n this.hsv.update((hsv: IRtColorPalette.Hsv): IRtColorPalette.Hsv => ({ ...hsv, h: Math.min(359, share * 360) }));\n }\n\n protected onKey(target: 'area' | 'hue', event: KeyboardEvent): void {\n const next: IRtColorPalette.Hsv | null = colorPaletteStep(target, event.key, this.hsv());\n\n if (next === null) {\n return;\n }\n\n event.preventDefault();\n this.hsv.set(next);\n }\n\n protected onApply(): void {\n if (this.changed()) {\n this.applied.emit(this.picked());\n }\n }\n}\n","<ng-container rtBlock=\"rt-color-picker\">\n <!-- Площадь: вправо растёт насыщенность, вверх — яркость. Её фон строит логика палитры по оттенку\n полосы. Указатель тянет точку, стрелки двигают её шагом. -->\n <div\n rtElem=\"area\"\n qa-dataid=\"color-picker-area\"\n role=\"slider\"\n tabindex=\"0\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n [attr.aria-label]=\"t().uiColorPickerArea\"\n [attr.aria-valuenow]=\"saturation()\"\n [attr.aria-valuetext]=\"areaText()\"\n [style.--rt-color-picker-area]=\"area()\"\n [style.--rt-color-picker-x]=\"hsv().s\"\n [style.--rt-color-picker-y]=\"1 - hsv().v\"\n (pointerdown)=\"onAreaPointer($event)\"\n (pointermove)=\"onAreaPointer($event)\"\n (pointerup)=\"onAreaPointer($event)\"\n (keydown)=\"onKey('area', $event)\">\n <span rtElem=\"area-thumb\" [style.--rt-color-picker-color]=\"picked()\"></span>\n </div>\n\n <div\n rtElem=\"hue\"\n qa-dataid=\"color-picker-hue\"\n role=\"slider\"\n tabindex=\"0\"\n aria-valuemin=\"0\"\n aria-valuemax=\"359\"\n [attr.aria-label]=\"t().uiColorPickerHue\"\n [attr.aria-valuenow]=\"hueDegrees()\"\n [style.--rt-color-picker-x]=\"hsv().h / 360\"\n [style.--rt-color-picker-spectrum]=\"spectrum\"\n (pointerdown)=\"onHuePointer($event)\"\n (pointermove)=\"onHuePointer($event)\"\n (pointerup)=\"onHuePointer($event)\"\n (keydown)=\"onKey('hue', $event)\">\n <span rtElem=\"hue-thumb\" [style.--rt-color-picker-color]=\"hueColor()\"></span>\n </div>\n\n <div rtElem=\"row\">\n <span rtElem=\"preview\" aria-hidden=\"true\" [style.--rt-color-picker-color]=\"picked()\"></span>\n <rt-input\n rtElem=\"hex\"\n qa-dataid=\"color-picker-hex\"\n size=\"sm\"\n [clearable]=\"false\"\n [ariaLabel]=\"t().uiColorPickerHex\"\n [formControl]=\"hexControl\" />\n </div>\n\n @if (channels()) {\n <div rtElem=\"channels\">\n @for (item of channelControls; track item.channel) {\n <div rtElem=\"channel\">\n <span rtElem=\"channel-name\" aria-hidden=\"true\">{{ item.name }}</span>\n <rt-input\n rtElem=\"channel-input\"\n qa-dataid=\"color-picker-channel\"\n size=\"sm\"\n [clearable]=\"false\"\n [ariaLabel]=\"channelLabels()[item.channel]\"\n [formControl]=\"item.control\" />\n </div>\n }\n </div>\n }\n\n <div rtElem=\"actions\">\n <button\n type=\"button\"\n rtButton\n qa-dataid=\"color-picker-cancel\"\n appearance=\"text\"\n theme=\"secondary\"\n size=\"sm\"\n (click)=\"cancelled.emit()\">\n {{ t().uiCancel }}\n </button>\n <button type=\"button\" rtButton qa-dataid=\"color-picker-apply\" size=\"sm\" [disabled]=\"!changed()\" (click)=\"onApply()\">\n {{ t().uiApply }}\n </button>\n </div>\n</ng-container>\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n ElementRef,\n forwardRef,\n inject,\n input,\n InputSignal,\n InputSignalWithTransform,\n Signal,\n viewChild,\n viewChildren,\n ViewEncapsulation,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { RtButtonDirective } from '@rt-tools/ui-kit-v2/button';\nimport { RT_KIT_LABELS, TRtKitLabelMap } from '@rt-tools/ui-kit-v2/core';\nimport { RtFormControlBase } from '@rt-tools/ui-kit-v2/form-control';\nimport { RtPopoverDirective } from '@rt-tools/ui-kit-v2/popover';\nimport { RtColorPickerComponent } from './picker/rt-color-picker.component';\nimport { colorPaletteHex, colorPaletteNextIndex, colorPaletteSwatches } from './rt-color-palette.logic';\nimport { IRtColorPalette } from './rt-color-palette.model';\n\nconst BEM_BLOCK: string = 'rt-color-palette';\n\n/** С какого цвета начинается выбор своего, когда поле пусто. */\nconst PICKER_START: string = '#000000';\n\n/**\n * Поле выбора цвета: образцы из набора и свой цвет. Значение — `#rrggbb` строчными или `null`.\n *\n * Образцы — группа переключателей: в порядке Tab стоит один образец, стрелки выбирают соседний.\n * Свой цвет выбирается на панели кита — площадь, полоса оттенка и запись, — и поле меняет только\n * «Применить». Только для чтения рисуется один образец текущего цвета.\n *\n * Договорённость — `docs/specs/ui-kit-v2/color-palette/`.\n */\n@Component({\n selector: 'rt-color-palette',\n templateUrl: './rt-color-palette.component.html',\n styleUrls: ['./rt-color-palette.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // standalone components / directives\n RtButtonDirective,\n RtColorPickerComponent,\n RtPopoverDirective,\n BlockDirective,\n ElemDirective,\n ModDirective,\n ],\n providers: [\n // Алиас базового токена — чтобы rt-field нашёл контрол через contentChild(RtFormControlBase).\n { provide: RtFormControlBase, useExisting: forwardRef(() => RtColorPaletteComponent) },\n ],\n host: {\n class: BEM_BLOCK,\n '[class.rt-color-palette--disabled]': 'isDisabled()',\n '[class.rt-color-palette--invalid]': 'isInvalid()',\n '[class.rt-color-palette--readonly]': 'isReadonlyView()',\n },\n})\nexport class RtColorPaletteComponent extends RtFormControlBase<string | null> {\n protected readonly t: Signal<TRtKitLabelMap> = inject(RT_KIT_LABELS);\n\n protected readonly hasValue: Signal<boolean> = computed((): boolean => this.value() !== null);\n protected readonly swatches: Signal<IRtColorPalette.Swatch[]> = computed((): IRtColorPalette.Swatch[] =>\n colorPaletteSwatches(this.colors(), this.value())\n );\n\n /** Номер выбранного образца; без выбора — `-1`. */\n protected readonly checkedIndex: Signal<number> = computed((): number =>\n this.swatches().findIndex((swatch: IRtColorPalette.Swatch): boolean => swatch.hex === this.value())\n );\n\n /** Образец в порядке Tab: выбранный, а без выбора — первый. */\n protected readonly tabbableIndex: Signal<number> = computed((): number => Math.max(this.checkedIndex(), 0));\n\n /** Свой цвет уже выбран: последний образец стоит вне набора. */\n protected readonly hasCustom: Signal<boolean> = computed((): boolean =>\n this.swatches().some((swatch: IRtColorPalette.Swatch): boolean => swatch.custom)\n );\n\n protected readonly isReadonlyView: Signal<boolean> = computed((): boolean => this.readonly() || this.isReadonly());\n protected readonly pickerStart: Signal<string> = computed((): string => this.value() ?? PICKER_START);\n protected readonly groupLabel: Signal<string> = computed((): string => this.ariaLabel() ?? this.t().uiColorPalette);\n\n protected readonly swatchRefs: Signal<readonly ElementRef<HTMLButtonElement>[]> = viewChildren<ElementRef<HTMLButtonElement>>('swatch');\n protected readonly picker: Signal<RtPopoverDirective | undefined> = viewChild(RtPopoverDirective);\n\n /** Цвета образцов по порядку; без них — набор кита. Неверные цвета и повторы не рисуются. */\n public readonly colors: InputSignal<readonly string[]> = input<readonly string[]>([]);\n\n /** Только для чтения: один образец текущего цвета, нажимать нечего. */\n public readonly readonly: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Кнопка своего цвета и панель выбора. Без неё палитра выбирает только из набора. */\n public readonly customAllowed: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(true, {\n transform: booleanAttribute,\n });\n\n /** Поля красного, зелёного и синего в панели своего цвета, под записью hex. */\n public readonly channels: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n public readonly displayText: Signal<string> = computed((): string => this.value() ?? '');\n\n public override writeValue(value: string | null): void {\n super.writeValue(colorPaletteHex(value));\n }\n\n protected onSwatch(hex: string): void {\n if (this.isDisabled() || this.isReadonlyView()) {\n return;\n }\n\n this.#choose(hex);\n }\n\n protected onSwatchKeydown(event: KeyboardEvent): void {\n if (this.isDisabled()) {\n return;\n }\n\n const next: number | null = colorPaletteNextIndex(event.key, this.checkedIndex(), this.swatches().length);\n\n if (next === null) {\n return;\n }\n\n event.preventDefault();\n this.#choose(this.swatches()[next].hex);\n this.swatchRefs()[next]?.nativeElement.focus();\n }\n\n protected onCustomApply(hex: string): void {\n this.picker()?.close();\n this.#choose(hex);\n }\n\n protected onCustomCancel(): void {\n this.picker()?.close();\n }\n\n protected getEmptyValue(): string | null {\n return null;\n }\n\n protected focusAfterClear(): void {\n this.swatchRefs()[0]?.nativeElement.focus();\n }\n\n #choose(hex: string): void {\n this.value.set(hex);\n this.emitChange(hex);\n this.markTouched();\n }\n}\n","<ng-container rtBlock=\"rt-color-palette\">\n @if (isReadonlyView()) {\n <!-- Только для чтения — один образец текущего цвета; пустой — с одной рамкой. -->\n <span\n rtElem=\"swatch\"\n qa-dataid=\"color-palette-readonly\"\n role=\"img\"\n [rtMod]=\"{ readonly: true, empty: !hasValue() }\"\n [attr.aria-label]=\"value() ?? t().uiColorPaletteEmpty\"\n [style.--rt-color-palette-color]=\"value()\"></span>\n } @else {\n <div\n rtElem=\"swatches\"\n role=\"radiogroup\"\n [attr.id]=\"effectiveControlId()\"\n [attr.aria-label]=\"groupLabel()\"\n [attr.aria-disabled]=\"isDisabled() || null\">\n @for (swatch of swatches(); track swatch.hex; let index = $index) {\n <button\n #swatch\n type=\"button\"\n rtElem=\"swatch\"\n qa-dataid=\"color-palette-swatch\"\n role=\"radio\"\n [rtMod]=\"{ checked: index === checkedIndex(), custom: swatch.custom }\"\n [attr.aria-checked]=\"index === checkedIndex()\"\n [attr.aria-label]=\"swatch.hex\"\n [attr.tabindex]=\"index === tabbableIndex() ? 0 : -1\"\n [disabled]=\"isDisabled()\"\n [style.--rt-color-palette-color]=\"swatch.hex\"\n (click)=\"onSwatch(swatch.hex)\"\n (keydown)=\"onSwatchKeydown($event)\"></button>\n }\n </div>\n\n @if (customAllowed()) {\n <!-- Панель своего цвета висит на кнопке: по ней встаёт и её нажатие не считает внешним. -->\n <button\n type=\"button\"\n rtButton\n rtElem=\"custom\"\n qa-dataid=\"color-palette-custom\"\n appearance=\"text\"\n size=\"sm\"\n [rtPopover]=\"pickerTpl\"\n [disabled]=\"isDisabled()\">\n {{ hasCustom() ? t().uiColorPaletteEditCustom : t().uiColorPaletteCustom }}\n </button>\n\n <ng-template #pickerTpl>\n <rt-color-picker\n [value]=\"pickerStart()\"\n [channels]=\"channels()\"\n (applied)=\"onCustomApply($event)\"\n (cancelled)=\"onCustomCancel()\" />\n </ng-template>\n }\n }\n</ng-container>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rt-tools-ui-kit-v2-color-palette.mjs","names":["BEM_BLOCK"],"sources":["../../../projects/ui-kit-v2/src/lib/components/color-palette/rt-color-palette.const.ts","../../../projects/ui-kit-v2/src/lib/components/color-palette/rt-color-palette.logic.ts","../../../projects/ui-kit-v2/src/lib/components/color-palette/picker/rt-color-picker.component.ts","../../../projects/ui-kit-v2/src/lib/components/color-palette/picker/rt-color-picker.component.html","../../../projects/ui-kit-v2/src/lib/components/color-palette/rt-color-palette.component.ts","../../../projects/ui-kit-v2/src/lib/components/color-palette/rt-color-palette.component.html"],"sourcesContent":["/**\n * Набор палитры по умолчанию, восемнадцать цветов: шестнадцать оттенков по кругу, затем коричневый и\n * серо-синий. Набор темы приложение передаёт входом `colors` — он свой у каждого продукта.\n */\nexport const RT_COLOR_PALETTE_DEFAULT: readonly string[] = [\n '#f44336',\n '#e91e63',\n '#9c27b0',\n '#673ab7',\n '#3f51b5',\n '#2196f3',\n '#03a9f4',\n '#00bcd4',\n '#009688',\n '#4caf50',\n '#8bc34a',\n '#cddc39',\n '#ffeb3b',\n '#ffc107',\n '#ff9800',\n '#ff5722',\n '#795548',\n '#607d8b',\n];\n","import { RT_COLOR_PALETTE_DEFAULT } from './rt-color-palette.const';\nimport { IRtColorPalette } from './rt-color-palette.model';\n\nconst SHORT_HEX: RegExp = /^#?([0-9a-f])([0-9a-f])([0-9a-f])$/i;\nconst FULL_HEX: RegExp = /^#?([0-9a-f]{6})$/i;\nconst CHANNEL: RegExp = /^\\d{1,3}$/;\n\n/** Шаг стрелки: по площади — двадцатая доля насыщенности и яркости, по полосе — шесть градусов оттенка. */\nconst AREA_STEP: number = 0.05;\nconst HUE_STEP: number = 6;\n\n/** Сдвиг оттенка стрелкой по полосе: вправо и вверх — дальше по кругу, влево и вниз — назад. */\nconst HUE_MOVES: Readonly<Partial<Record<string, number>>> = {\n ArrowRight: HUE_STEP,\n ArrowUp: HUE_STEP,\n ArrowLeft: -HUE_STEP,\n ArrowDown: -HUE_STEP,\n};\n\n/** Сдвиг стрелкой по площади: вправо и влево — насыщенность, вверх и вниз — яркость. */\nconst AREA_MOVES: Readonly<Partial<Record<string, readonly ['s' | 'v', number]>>> = {\n ArrowRight: ['s', AREA_STEP],\n ArrowLeft: ['s', -AREA_STEP],\n ArrowUp: ['v', AREA_STEP],\n ArrowDown: ['v', -AREA_STEP],\n};\n\n/** Опорные оттенки полосы: шесть вершин круга и возврат к красному. */\nconst SPECTRUM_HUES: readonly number[] = [0, 60, 120, 180, 240, 300, 0];\n\n/** Доля в пределах от нуля до единицы. */\nfunction clamp(value: number): number {\n return Math.min(1, Math.max(0, value));\n}\n\n/**\n * Цвет поля в его единственном виде: `#rrggbb` строчными. Трёхзначная запись разворачивается, решётка\n * дописывается. Всё остальное — не цвет: поле рисует его как «цвет не выбран».\n */\nexport function colorPaletteHex(value: unknown): string | null {\n if (typeof value !== 'string') {\n return null;\n }\n\n const text: string = value.trim();\n const short: RegExpExecArray | null = SHORT_HEX.exec(text);\n\n if (short) {\n return `#${short[1]}${short[1]}${short[2]}${short[2]}${short[3]}${short[3]}`.toLowerCase();\n }\n\n const full: RegExpExecArray | null = FULL_HEX.exec(text);\n\n return full ? `#${full[1].toLowerCase()}` : null;\n}\n\n/**\n * Образцы палитры: цвета входа по порядку, без них — набор кита. Значение, которого среди них нет,\n * встаёт ещё одним образцом в конце: человек видит, что выбран свой цвет, и может вернуться к нему.\n * Неверные цвета входа и повторы отбрасываются — образцу нужен цвет, а номеру в группе единственность.\n */\nexport function colorPaletteSwatches(colors: readonly string[], value: string | null): IRtColorPalette.Swatch[] {\n const source: readonly string[] = colors.length > 0 ? colors : RT_COLOR_PALETTE_DEFAULT;\n const seen: Set<string> = new Set<string>();\n const swatches: IRtColorPalette.Swatch[] = [];\n\n for (const color of source) {\n const hex: string | null = colorPaletteHex(color);\n\n if (hex !== null && !seen.has(hex)) {\n seen.add(hex);\n swatches.push({ hex, custom: false });\n }\n }\n\n if (value !== null && !seen.has(value)) {\n swatches.push({ hex: value, custom: true });\n }\n\n return swatches;\n}\n\n/**\n * Куда клавиша переводит выбор среди образцов: стрелки идут по кругу, Home и End берут крайние.\n * Строки образцов зависят от ширины поля, поэтому вверх и вниз значат «назад» и «вперёд», как в\n * группе переключателей. `null` — клавиша не про выбор.\n */\nexport function colorPaletteNextIndex(key: string, current: number, count: number): number | null {\n if (count === 0) {\n return null;\n }\n\n switch (key) {\n case 'ArrowDown':\n case 'ArrowRight':\n return current < 0 ? 0 : (current + 1) % count;\n case 'ArrowUp':\n case 'ArrowLeft':\n return current < 0 ? count - 1 : (current - 1 + count) % count;\n case 'Home':\n return 0;\n case 'End':\n return count - 1;\n default:\n return null;\n }\n}\n\n/** Цвет `#rrggbb` в оттенке, насыщенности и яркости. Оттенок серого — ноль. */\nexport function colorPaletteToHsv(hex: string): IRtColorPalette.Hsv {\n const r: number = parseInt(hex.slice(1, 3), 16) / 255;\n const g: number = parseInt(hex.slice(3, 5), 16) / 255;\n const b: number = parseInt(hex.slice(5, 7), 16) / 255;\n const max: number = Math.max(r, g, b);\n const delta: number = max - Math.min(r, g, b);\n\n let h: number = 0;\n\n if (delta > 0) {\n if (max === r) {\n h = 60 * (((g - b) / delta + 6) % 6);\n } else if (max === g) {\n h = 60 * ((b - r) / delta + 2);\n } else {\n h = 60 * ((r - g) / delta + 4);\n }\n }\n\n return { h, s: max === 0 ? 0 : delta / max, v: max };\n}\n\n/** Оттенок, насыщенность и яркость в цвете `#rrggbb`. */\nexport function colorPaletteFromHsv(hsv: IRtColorPalette.Hsv): string {\n const h: number = (((hsv.h % 360) + 360) % 360) / 60;\n const s: number = clamp(hsv.s);\n const v: number = clamp(hsv.v);\n const chroma: number = v * s;\n const x: number = chroma * (1 - Math.abs((h % 2) - 1));\n const m: number = v - chroma;\n const sector: number = Math.floor(h);\n const [r, g, b]: [number, number, number] = (\n [\n [chroma, x, 0],\n [x, chroma, 0],\n [0, chroma, x],\n [0, x, chroma],\n [x, 0, chroma],\n [chroma, 0, x],\n ] as [number, number, number][]\n )[sector % 6];\n\n return `#${[r, g, b]\n .map((channel: number): string =>\n Math.round((channel + m) * 255)\n .toString(16)\n .padStart(2, '0')\n )\n .join('')}`;\n}\n\n/**\n * Сдвиг выбранного стрелкой: по площади — насыщенность вправо и влево, яркость вверх и вниз; по полосе —\n * оттенок по кругу. `null` — клавиша не про сдвиг.\n */\nexport function colorPaletteStep(target: 'area' | 'hue', key: string, hsv: IRtColorPalette.Hsv): IRtColorPalette.Hsv | null {\n if (target === 'hue') {\n const delta: number | undefined = HUE_MOVES[key];\n\n return delta === undefined ? null : { ...hsv, h: (hsv.h + delta + 360) % 360 };\n }\n\n const move: readonly ['s' | 'v', number] | undefined = AREA_MOVES[key];\n\n if (move === undefined) {\n return null;\n }\n\n const [axis, delta]: readonly ['s' | 'v', number] = move;\n\n return { ...hsv, [axis]: clamp(hsv[axis] + delta) };\n}\n\n/** Цвет `#rrggbb` в каналах красного, зелёного и синего. */\nexport function colorPaletteToRgb(hex: string): IRtColorPalette.Rgb {\n return {\n r: parseInt(hex.slice(1, 3), 16),\n g: parseInt(hex.slice(3, 5), 16),\n b: parseInt(hex.slice(5, 7), 16),\n };\n}\n\n/** Каналы красного, зелёного и синего в цвете `#rrggbb`. */\nexport function colorPaletteFromRgb(rgb: IRtColorPalette.Rgb): string {\n return `#${[rgb.r, rgb.g, rgb.b].map((channel: number): string => channel.toString(16).padStart(2, '0')).join('')}`;\n}\n\n/**\n * Значение канала из набранного в поле: целое от 0 до 255 без знаков и дробей. Всё остальное — `null`,\n * и поле не меняет выбранного, пока ввод не окончен.\n */\nexport function colorPaletteChannel(text: string): number | null {\n const trimmed: string = text.trim();\n\n if (!CHANNEL.test(trimmed)) {\n return null;\n }\n\n const value: number = Number(trimmed);\n\n return value <= 255 ? value : null;\n}\n\n/** Полоса оттенков слева направо: градиент по вершинам круга в полной насыщенности и яркости. */\nexport function colorPaletteSpectrum(): string {\n const stops: string[] = SPECTRUM_HUES.map((h: number): string => colorPaletteFromHsv({ h, s: 1, v: 1 }));\n\n return `linear-gradient(to right, ${stops.join(', ')})`;\n}\n\n/**\n * Площадь насыщенности и яркости для оттенка `hue`: внизу чёрный, и вверх цвет ярче; слева белый, и\n * вправо цвет насыщеннее до чистого оттенка. Это математика цвета, а не оформление: слои — края\n * пространства цвета.\n */\nexport function colorPaletteArea(hue: string): string {\n const white: string = colorPaletteFromHsv({ h: 0, s: 0, v: 1 });\n const black: string = colorPaletteFromHsv({ h: 0, s: 0, v: 0 });\n\n return `linear-gradient(to top, ${black}, transparent), linear-gradient(to right, ${white}, ${hue})`;\n}\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n effect,\n inject,\n input,\n InputSignal,\n InputSignalWithTransform,\n linkedSignal,\n output,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { FormControl, ReactiveFormsModule } from '@angular/forms';\n\nimport { BlockDirective, ElemDirective } from '@rt-tools/core';\n\nimport { RtButtonDirective } from '@rt-tools/ui-kit-v2/button';\nimport { RT_KIT_LABELS, TRtKitLabelMap } from '@rt-tools/ui-kit-v2/core';\nimport { RtInputComponent } from '@rt-tools/ui-kit-v2/input';\nimport {\n colorPaletteArea,\n colorPaletteChannel,\n colorPaletteFromHsv,\n colorPaletteFromRgb,\n colorPaletteHex,\n colorPaletteSpectrum,\n colorPaletteStep,\n colorPaletteToHsv,\n colorPaletteToRgb,\n} from '../rt-color-palette.logic';\nimport { IRtColorPalette } from '../rt-color-palette.model';\n\nconst BEM_BLOCK: string = 'rt-color-picker';\nconst CHANNELS: readonly IRtColorPalette.Channel[] = ['r', 'g', 'b'];\n\n/** Поле одного канала и канал, который оно правит. */\ninterface IChannelControl {\n channel: IRtColorPalette.Channel;\n /** Буква канала над полем: R, G, B одинаковы во всех языках. */\n name: string;\n control: FormControl<string>;\n}\n\n/**\n * Выбор своего цвета палитры: площадь насыщенности и яркости, полоса оттенка, поле шестнадцатеричной\n * записи, «Отмена» и «Применить». Рисует его кит сам — сторонний выбор цвета в кит не входит.\n *\n * Выбранное живёт здесь до «Применить»: поле палитры меняется только им. Начинается выбор с цвета,\n * который пришёл входом, и «Применить» недоступно, пока выбранное с ним совпадает.\n */\n@Component({\n selector: 'rt-color-picker',\n templateUrl: './rt-color-picker.component.html',\n styleUrls: ['./rt-color-picker.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // Angular\n ReactiveFormsModule,\n\n // standalone components / directives\n RtButtonDirective,\n RtInputComponent,\n BlockDirective,\n ElemDirective,\n ],\n host: { class: BEM_BLOCK },\n})\nexport class RtColorPickerComponent {\n protected readonly t: Signal<TRtKitLabelMap> = inject(RT_KIT_LABELS);\n\n /** Цвет в оттенке, насыщенности и яркости: оттенок серого не теряется, пока человек тянет яркость. */\n protected readonly hsv: WritableSignal<IRtColorPalette.Hsv> = linkedSignal<IRtColorPalette.Hsv>((): IRtColorPalette.Hsv =>\n colorPaletteToHsv(this.value())\n );\n\n protected readonly picked: Signal<string> = computed((): string => colorPaletteFromHsv(this.hsv()));\n protected readonly changed: Signal<boolean> = computed((): boolean => this.picked() !== this.value());\n\n /** Чистый оттенок площади: её правый верхний угол. */\n protected readonly hueColor: Signal<string> = computed((): string => colorPaletteFromHsv({ h: this.hsv().h, s: 1, v: 1 }));\n protected readonly area: Signal<string> = computed((): string => colorPaletteArea(this.hueColor()));\n protected readonly spectrum: string = colorPaletteSpectrum();\n protected readonly hueDegrees: Signal<number> = computed((): number => Math.round(this.hsv().h));\n protected readonly saturation: Signal<number> = computed((): number => Math.round(this.hsv().s * 100));\n protected readonly areaText: Signal<string> = computed((): string => `${this.saturation()}%, ${Math.round(this.hsv().v * 100)}%`);\n\n protected readonly hexControl: FormControl<string> = new FormControl<string>('', { nonNullable: true });\n\n /** Поля каналов по порядку строки: красный, зелёный, синий. */\n protected readonly channelControls: readonly IChannelControl[] = CHANNELS.map((channel: IRtColorPalette.Channel): IChannelControl => ({\n channel,\n name: channel.toUpperCase(),\n control: new FormControl<string>('', { nonNullable: true }),\n }));\n\n /** Доступные имена полей каналов из словаря кита. */\n protected readonly channelLabels: Signal<Readonly<Record<IRtColorPalette.Channel, string>>> = computed(\n (): Readonly<Record<IRtColorPalette.Channel, string>> => ({\n r: this.t().uiColorPickerRed,\n g: this.t().uiColorPickerGreen,\n b: this.t().uiColorPickerBlue,\n })\n );\n\n /** Цвет, с которого начинается выбор, `#rrggbb`. */\n public readonly value: InputSignal<string> = input.required<string>();\n\n /** Строка полей красного, зелёного и синего под записью hex. Без неё — площадь, полоса и hex. */\n public readonly channels: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n public readonly applied: OutputEmitterRef<string> = output<string>();\n public readonly cancelled: OutputEmitterRef<void> = output<void>();\n\n #dragging: boolean = false;\n\n constructor() {\n // Поле записи показывает выбранное и молчит в ответ: иначе его же изменение вернулось бы\n // набранной строкой и перебило бы неоконченный ввод.\n effect((): void => {\n const hex: string = this.picked();\n\n if (colorPaletteHex(this.hexControl.value) !== hex) {\n this.hexControl.setValue(hex, { emitEvent: false });\n }\n });\n\n this.hexControl.valueChanges.pipe(takeUntilDestroyed()).subscribe((text: string): void => {\n const hex: string | null = colorPaletteHex(text);\n\n if (hex !== null && hex !== this.picked()) {\n this.hsv.set(colorPaletteToHsv(hex));\n }\n });\n\n // Поля каналов ведут себя так же: показывают выбранное и молчат в ответ, а набранное целое\n // от 0 до 255 меняет один свой канал.\n effect((): void => {\n const rgb: IRtColorPalette.Rgb = colorPaletteToRgb(this.picked());\n\n for (const { channel, control } of this.channelControls) {\n if (colorPaletteChannel(control.value) !== rgb[channel]) {\n control.setValue(String(rgb[channel]), { emitEvent: false });\n }\n }\n });\n\n for (const { channel, control } of this.channelControls) {\n control.valueChanges.pipe(takeUntilDestroyed()).subscribe((text: string): void => {\n const value: number | null = colorPaletteChannel(text);\n const rgb: IRtColorPalette.Rgb = colorPaletteToRgb(this.picked());\n\n if (value !== null && value !== rgb[channel]) {\n this.hsv.set(colorPaletteToHsv(colorPaletteFromRgb({ ...rgb, [channel]: value })));\n }\n });\n }\n }\n\n protected onAreaPointer(event: PointerEvent): void {\n if (event.type === 'pointerdown') {\n this.#dragging = true;\n (event.currentTarget as HTMLElement).setPointerCapture?.(event.pointerId);\n }\n\n if (!this.#dragging) {\n return;\n }\n\n if (event.type === 'pointerup') {\n this.#dragging = false;\n }\n\n const box: DOMRect = (event.currentTarget as HTMLElement).getBoundingClientRect();\n const s: number = box.width > 0 ? (event.clientX - box.left) / box.width : 0;\n const v: number = box.height > 0 ? 1 - (event.clientY - box.top) / box.height : 0;\n\n this.hsv.update((hsv: IRtColorPalette.Hsv): IRtColorPalette.Hsv => ({\n ...hsv,\n s: Math.min(1, Math.max(0, s)),\n v: Math.min(1, Math.max(0, v)),\n }));\n }\n\n protected onHuePointer(event: PointerEvent): void {\n if (event.type === 'pointerdown') {\n this.#dragging = true;\n (event.currentTarget as HTMLElement).setPointerCapture?.(event.pointerId);\n }\n\n if (!this.#dragging) {\n return;\n }\n\n if (event.type === 'pointerup') {\n this.#dragging = false;\n }\n\n const box: DOMRect = (event.currentTarget as HTMLElement).getBoundingClientRect();\n const share: number = box.width > 0 ? Math.min(1, Math.max(0, (event.clientX - box.left) / box.width)) : 0;\n\n this.hsv.update((hsv: IRtColorPalette.Hsv): IRtColorPalette.Hsv => ({ ...hsv, h: Math.min(359, share * 360) }));\n }\n\n protected onKey(target: 'area' | 'hue', event: KeyboardEvent): void {\n const next: IRtColorPalette.Hsv | null = colorPaletteStep(target, event.key, this.hsv());\n\n if (next === null) {\n return;\n }\n\n event.preventDefault();\n this.hsv.set(next);\n }\n\n protected onApply(): void {\n if (this.changed()) {\n this.applied.emit(this.picked());\n }\n }\n}\n","<ng-container rtBlock=\"rt-color-picker\">\n <!-- Площадь: вправо растёт насыщенность, вверх — яркость. Её фон строит логика палитры по оттенку\n полосы. Указатель тянет точку, стрелки двигают её шагом. -->\n <div\n rtElem=\"area\"\n qa-dataid=\"color-picker-area\"\n role=\"slider\"\n tabindex=\"0\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n [attr.aria-label]=\"t().uiColorPickerArea\"\n [attr.aria-valuenow]=\"saturation()\"\n [attr.aria-valuetext]=\"areaText()\"\n [style.--rt-color-picker-area]=\"area()\"\n [style.--rt-color-picker-x]=\"hsv().s\"\n [style.--rt-color-picker-y]=\"1 - hsv().v\"\n (pointerdown)=\"onAreaPointer($event)\"\n (pointermove)=\"onAreaPointer($event)\"\n (pointerup)=\"onAreaPointer($event)\"\n (keydown)=\"onKey('area', $event)\">\n <span rtElem=\"area-thumb\" [style.--rt-color-picker-color]=\"picked()\"></span>\n </div>\n\n <div\n rtElem=\"hue\"\n qa-dataid=\"color-picker-hue\"\n role=\"slider\"\n tabindex=\"0\"\n aria-valuemin=\"0\"\n aria-valuemax=\"359\"\n [attr.aria-label]=\"t().uiColorPickerHue\"\n [attr.aria-valuenow]=\"hueDegrees()\"\n [style.--rt-color-picker-x]=\"hsv().h / 360\"\n [style.--rt-color-picker-spectrum]=\"spectrum\"\n (pointerdown)=\"onHuePointer($event)\"\n (pointermove)=\"onHuePointer($event)\"\n (pointerup)=\"onHuePointer($event)\"\n (keydown)=\"onKey('hue', $event)\">\n <span rtElem=\"hue-thumb\" [style.--rt-color-picker-color]=\"hueColor()\"></span>\n </div>\n\n <div rtElem=\"row\">\n <span rtElem=\"preview\" aria-hidden=\"true\" [style.--rt-color-picker-color]=\"picked()\"></span>\n <rt-input\n rtElem=\"hex\"\n qa-dataid=\"color-picker-hex\"\n size=\"sm\"\n [clearable]=\"false\"\n [ariaLabel]=\"t().uiColorPickerHex\"\n [formControl]=\"hexControl\" />\n </div>\n\n @if (channels()) {\n <div rtElem=\"channels\">\n @for (item of channelControls; track item.channel) {\n <div rtElem=\"channel\">\n <span rtElem=\"channel-name\" aria-hidden=\"true\">{{ item.name }}</span>\n <rt-input\n rtElem=\"channel-input\"\n qa-dataid=\"color-picker-channel\"\n size=\"sm\"\n [clearable]=\"false\"\n [ariaLabel]=\"channelLabels()[item.channel]\"\n [formControl]=\"item.control\" />\n </div>\n }\n </div>\n }\n\n <div rtElem=\"actions\">\n <button\n type=\"button\"\n rtButton\n qa-dataid=\"color-picker-cancel\"\n appearance=\"text\"\n theme=\"secondary\"\n size=\"sm\"\n (click)=\"cancelled.emit()\">\n {{ t().uiCancel }}\n </button>\n <button type=\"button\" rtButton qa-dataid=\"color-picker-apply\" size=\"sm\" [disabled]=\"!changed()\" (click)=\"onApply()\">\n {{ t().uiApply }}\n </button>\n </div>\n</ng-container>\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n ElementRef,\n forwardRef,\n inject,\n input,\n InputSignal,\n InputSignalWithTransform,\n Signal,\n viewChild,\n viewChildren,\n ViewEncapsulation,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { RtButtonDirective } from '@rt-tools/ui-kit-v2/button';\nimport { RT_KIT_LABELS, TRtKitLabelMap } from '@rt-tools/ui-kit-v2/core';\nimport { RtFormControlBase } from '@rt-tools/ui-kit-v2/form-control';\nimport { RtPopoverDirective } from '@rt-tools/ui-kit-v2/popover';\nimport { RtColorPickerComponent } from './picker/rt-color-picker.component';\nimport { colorPaletteHex, colorPaletteNextIndex, colorPaletteSwatches } from './rt-color-palette.logic';\nimport { IRtColorPalette } from './rt-color-palette.model';\n\nconst BEM_BLOCK: string = 'rt-color-palette';\n\n/** С какого цвета начинается выбор своего, когда поле пусто. */\nconst PICKER_START: string = '#000000';\n\n/**\n * Поле выбора цвета: образцы из набора и свой цвет. Значение — `#rrggbb` строчными или `null`.\n *\n * Образцы — группа переключателей: в порядке Tab стоит один образец, стрелки выбирают соседний.\n * Свой цвет выбирается на панели кита — площадь, полоса оттенка и запись, — и поле меняет только\n * «Применить». Только для чтения рисуется один образец текущего цвета.\n *\n * Договорённость — `docs/specs/ui-kit-v2/color-palette/`.\n */\n@Component({\n selector: 'rt-color-palette',\n templateUrl: './rt-color-palette.component.html',\n styleUrls: ['./rt-color-palette.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // standalone components / directives\n RtButtonDirective,\n RtColorPickerComponent,\n RtPopoverDirective,\n BlockDirective,\n ElemDirective,\n ModDirective,\n ],\n providers: [\n // Алиас базового токена — чтобы rt-field нашёл контрол через contentChild(RtFormControlBase).\n { provide: RtFormControlBase, useExisting: forwardRef(() => RtColorPaletteComponent) },\n ],\n host: {\n class: BEM_BLOCK,\n '[class.rt-color-palette--disabled]': 'isDisabled()',\n '[class.rt-color-palette--invalid]': 'isInvalid()',\n '[class.rt-color-palette--readonly]': 'isReadonlyView()',\n },\n})\nexport class RtColorPaletteComponent extends RtFormControlBase<string | null> {\n protected readonly t: Signal<TRtKitLabelMap> = inject(RT_KIT_LABELS);\n\n protected readonly hasValue: Signal<boolean> = computed((): boolean => this.value() !== null);\n protected readonly swatches: Signal<IRtColorPalette.Swatch[]> = computed((): IRtColorPalette.Swatch[] =>\n colorPaletteSwatches(this.colors(), this.value())\n );\n\n /** Номер выбранного образца; без выбора — `-1`. */\n protected readonly checkedIndex: Signal<number> = computed((): number =>\n this.swatches().findIndex((swatch: IRtColorPalette.Swatch): boolean => swatch.hex === this.value())\n );\n\n /** Образец в порядке Tab: выбранный, а без выбора — первый. */\n protected readonly tabbableIndex: Signal<number> = computed((): number => Math.max(this.checkedIndex(), 0));\n\n /** Свой цвет уже выбран: последний образец стоит вне набора. */\n protected readonly hasCustom: Signal<boolean> = computed((): boolean =>\n this.swatches().some((swatch: IRtColorPalette.Swatch): boolean => swatch.custom)\n );\n\n protected readonly isReadonlyView: Signal<boolean> = computed((): boolean => this.readonly() || this.isReadonly());\n protected readonly pickerStart: Signal<string> = computed((): string => this.value() ?? PICKER_START);\n protected readonly groupLabel: Signal<string> = computed((): string => this.ariaLabel() ?? this.t().uiColorPalette);\n\n protected readonly swatchRefs: Signal<readonly ElementRef<HTMLButtonElement>[]> = viewChildren<ElementRef<HTMLButtonElement>>('swatch');\n protected readonly picker: Signal<RtPopoverDirective | undefined> = viewChild(RtPopoverDirective);\n\n /** Цвета образцов по порядку; без них — набор кита. Неверные цвета и повторы не рисуются. */\n public readonly colors: InputSignal<readonly string[]> = input<readonly string[]>([]);\n\n /** Только для чтения: один образец текущего цвета, нажимать нечего. */\n public readonly readonly: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Кнопка своего цвета и панель выбора. Без неё палитра выбирает только из набора. */\n public readonly customAllowed: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(true, {\n transform: booleanAttribute,\n });\n\n /** Поля красного, зелёного и синего в панели своего цвета, под записью hex. */\n public readonly channels: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n public readonly displayText: Signal<string> = computed((): string => this.value() ?? '');\n\n public override writeValue(value: string | null): void {\n super.writeValue(colorPaletteHex(value));\n }\n\n protected onSwatch(hex: string): void {\n if (this.isDisabled() || this.isReadonlyView()) {\n return;\n }\n\n this.#choose(hex);\n }\n\n protected onSwatchKeydown(event: KeyboardEvent): void {\n if (this.isDisabled()) {\n return;\n }\n\n const next: number | null = colorPaletteNextIndex(event.key, this.checkedIndex(), this.swatches().length);\n\n if (next === null) {\n return;\n }\n\n event.preventDefault();\n this.#choose(this.swatches()[next].hex);\n this.swatchRefs()[next]?.nativeElement.focus();\n }\n\n protected onCustomApply(hex: string): void {\n this.picker()?.close();\n this.#choose(hex);\n }\n\n protected onCustomCancel(): void {\n this.picker()?.close();\n }\n\n protected getEmptyValue(): string | null {\n return null;\n }\n\n protected focusAfterClear(): void {\n this.swatchRefs()[0]?.nativeElement.focus();\n }\n\n #choose(hex: string): void {\n this.value.set(hex);\n this.emitChange(hex);\n this.markTouched();\n }\n}\n","<ng-container rtBlock=\"rt-color-palette\">\n @if (isReadonlyView()) {\n <!-- Только для чтения — один образец текущего цвета; пустой — с одной рамкой. -->\n <span\n rtElem=\"swatch\"\n qa-dataid=\"color-palette-readonly\"\n role=\"img\"\n [rtMod]=\"{ readonly: true, empty: !hasValue() }\"\n [attr.aria-label]=\"value() ?? t().uiColorPaletteEmpty\"\n [style.--rt-color-palette-color]=\"value()\"></span>\n } @else {\n <div\n rtElem=\"swatches\"\n role=\"radiogroup\"\n [attr.id]=\"effectiveControlId()\"\n [attr.aria-label]=\"groupLabel()\"\n [attr.aria-disabled]=\"isDisabled() || null\">\n @for (swatch of swatches(); track swatch.hex; let index = $index) {\n <button\n #swatch\n type=\"button\"\n rtElem=\"swatch\"\n qa-dataid=\"color-palette-swatch\"\n role=\"radio\"\n [rtMod]=\"{ checked: index === checkedIndex(), custom: swatch.custom }\"\n [attr.aria-checked]=\"index === checkedIndex()\"\n [attr.aria-label]=\"swatch.hex\"\n [attr.tabindex]=\"index === tabbableIndex() ? 0 : -1\"\n [disabled]=\"isDisabled()\"\n [style.--rt-color-palette-color]=\"swatch.hex\"\n (click)=\"onSwatch(swatch.hex)\"\n (keydown)=\"onSwatchKeydown($event)\"></button>\n }\n </div>\n\n @if (customAllowed()) {\n <!-- Панель своего цвета висит на кнопке: по ней встаёт и её нажатие не считает внешним. -->\n <button\n type=\"button\"\n rtButton\n rtElem=\"custom\"\n qa-dataid=\"color-palette-custom\"\n appearance=\"text\"\n size=\"sm\"\n [rtPopover]=\"pickerTpl\"\n [disabled]=\"isDisabled()\">\n {{ hasCustom() ? t().uiColorPaletteEditCustom : t().uiColorPaletteCustom }}\n </button>\n\n <ng-template #pickerTpl>\n <rt-color-picker\n [value]=\"pickerStart()\"\n [channels]=\"channels()\"\n (applied)=\"onCustomApply($event)\"\n (cancelled)=\"onCustomCancel()\" />\n </ng-template>\n }\n }\n</ng-container>\n"],"mappings":"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"}
|
|
@@ -995,6 +995,7 @@ var RtDatePickerComponent = class RtDatePickerComponent extends RtFormControlBas
|
|
|
995
995
|
"rtPopoverFitViewport",
|
|
996
996
|
"rtPopoverContext",
|
|
997
997
|
"rtPopoverPanelClass",
|
|
998
|
+
"rtPopoverBackdropClass",
|
|
998
999
|
"rtPopoverDisabled",
|
|
999
1000
|
"rtPopoverOffsetY",
|
|
1000
1001
|
"rtPopoverOffsetX",
|