@rt-tools/ui-kit-v2 0.34.3 → 0.34.5

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.
Files changed (93) hide show
  1. package/fesm2022/rt-tools-ui-kit-v2-action-bar.mjs +2 -0
  2. package/fesm2022/rt-tools-ui-kit-v2-action-bar.mjs.map +1 -1
  3. package/fesm2022/rt-tools-ui-kit-v2-aside.mjs +78 -10
  4. package/fesm2022/rt-tools-ui-kit-v2-aside.mjs.map +1 -1
  5. package/fesm2022/rt-tools-ui-kit-v2-autocomplete.mjs +2 -0
  6. package/fesm2022/rt-tools-ui-kit-v2-autocomplete.mjs.map +1 -1
  7. package/fesm2022/rt-tools-ui-kit-v2-button.mjs +18 -9
  8. package/fesm2022/rt-tools-ui-kit-v2-button.mjs.map +1 -1
  9. package/fesm2022/rt-tools-ui-kit-v2-calendar.mjs +2 -0
  10. package/fesm2022/rt-tools-ui-kit-v2-calendar.mjs.map +1 -1
  11. package/fesm2022/rt-tools-ui-kit-v2-confirm-popover.mjs +2 -2
  12. package/fesm2022/rt-tools-ui-kit-v2-confirm-popover.mjs.map +1 -1
  13. package/fesm2022/rt-tools-ui-kit-v2-copy-value.mjs +2 -0
  14. package/fesm2022/rt-tools-ui-kit-v2-copy-value.mjs.map +1 -1
  15. package/fesm2022/rt-tools-ui-kit-v2-core.mjs +4 -1
  16. package/fesm2022/rt-tools-ui-kit-v2-core.mjs.map +1 -1
  17. package/fesm2022/rt-tools-ui-kit-v2-counter.mjs +2 -0
  18. package/fesm2022/rt-tools-ui-kit-v2-counter.mjs.map +1 -1
  19. package/fesm2022/rt-tools-ui-kit-v2-data-list.mjs +4 -0
  20. package/fesm2022/rt-tools-ui-kit-v2-data-list.mjs.map +1 -1
  21. package/fesm2022/rt-tools-ui-kit-v2-data-table.mjs +4 -0
  22. package/fesm2022/rt-tools-ui-kit-v2-data-table.mjs.map +1 -1
  23. package/fesm2022/rt-tools-ui-kit-v2-date-picker.mjs +4 -0
  24. package/fesm2022/rt-tools-ui-kit-v2-date-picker.mjs.map +1 -1
  25. package/fesm2022/rt-tools-ui-kit-v2-date-range.mjs +2 -0
  26. package/fesm2022/rt-tools-ui-kit-v2-date-range.mjs.map +1 -1
  27. package/fesm2022/rt-tools-ui-kit-v2-dialog.mjs +2 -0
  28. package/fesm2022/rt-tools-ui-kit-v2-dialog.mjs.map +1 -1
  29. package/fesm2022/rt-tools-ui-kit-v2-dynamic-list.mjs +2 -0
  30. package/fesm2022/rt-tools-ui-kit-v2-dynamic-list.mjs.map +1 -1
  31. package/fesm2022/rt-tools-ui-kit-v2-dynamic-selector.mjs +2 -0
  32. package/fesm2022/rt-tools-ui-kit-v2-dynamic-selector.mjs.map +1 -1
  33. package/fesm2022/rt-tools-ui-kit-v2-file-card.mjs +2 -0
  34. package/fesm2022/rt-tools-ui-kit-v2-file-card.mjs.map +1 -1
  35. package/fesm2022/rt-tools-ui-kit-v2-header.mjs +2 -0
  36. package/fesm2022/rt-tools-ui-kit-v2-header.mjs.map +1 -1
  37. package/fesm2022/rt-tools-ui-kit-v2-icon-button.mjs +103 -6
  38. package/fesm2022/rt-tools-ui-kit-v2-icon-button.mjs.map +1 -1
  39. package/fesm2022/rt-tools-ui-kit-v2-image-upload.mjs +2 -0
  40. package/fesm2022/rt-tools-ui-kit-v2-image-upload.mjs.map +1 -1
  41. package/fesm2022/rt-tools-ui-kit-v2-inline-edit.mjs +2 -0
  42. package/fesm2022/rt-tools-ui-kit-v2-inline-edit.mjs.map +1 -1
  43. package/fesm2022/rt-tools-ui-kit-v2-input-number.mjs +2 -0
  44. package/fesm2022/rt-tools-ui-kit-v2-input-number.mjs.map +1 -1
  45. package/fesm2022/rt-tools-ui-kit-v2-input.mjs +6 -1
  46. package/fesm2022/rt-tools-ui-kit-v2-input.mjs.map +1 -1
  47. package/fesm2022/rt-tools-ui-kit-v2-menu.mjs +2 -0
  48. package/fesm2022/rt-tools-ui-kit-v2-menu.mjs.map +1 -1
  49. package/fesm2022/rt-tools-ui-kit-v2-message.mjs +2 -0
  50. package/fesm2022/rt-tools-ui-kit-v2-message.mjs.map +1 -1
  51. package/fesm2022/rt-tools-ui-kit-v2-multiselect.mjs +2 -0
  52. package/fesm2022/rt-tools-ui-kit-v2-multiselect.mjs.map +1 -1
  53. package/fesm2022/rt-tools-ui-kit-v2-pagination.mjs +2 -0
  54. package/fesm2022/rt-tools-ui-kit-v2-pagination.mjs.map +1 -1
  55. package/fesm2022/rt-tools-ui-kit-v2-pdf-viewer.mjs +2 -0
  56. package/fesm2022/rt-tools-ui-kit-v2-pdf-viewer.mjs.map +1 -1
  57. package/fesm2022/rt-tools-ui-kit-v2-photo-viewer.mjs +2 -0
  58. package/fesm2022/rt-tools-ui-kit-v2-photo-viewer.mjs.map +1 -1
  59. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs +10 -0
  60. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs.map +1 -1
  61. package/fesm2022/rt-tools-ui-kit-v2-select.mjs +2 -0
  62. package/fesm2022/rt-tools-ui-kit-v2-select.mjs.map +1 -1
  63. package/fesm2022/rt-tools-ui-kit-v2-side-menu.mjs +6 -0
  64. package/fesm2022/rt-tools-ui-kit-v2-side-menu.mjs.map +1 -1
  65. package/fesm2022/rt-tools-ui-kit-v2-speed-menu.mjs +2 -0
  66. package/fesm2022/rt-tools-ui-kit-v2-speed-menu.mjs.map +1 -1
  67. package/fesm2022/rt-tools-ui-kit-v2-table.mjs +8 -0
  68. package/fesm2022/rt-tools-ui-kit-v2-table.mjs.map +1 -1
  69. package/fesm2022/rt-tools-ui-kit-v2-tag.mjs +2 -0
  70. package/fesm2022/rt-tools-ui-kit-v2-tag.mjs.map +1 -1
  71. package/fesm2022/rt-tools-ui-kit-v2-theme-toggle.mjs +2 -0
  72. package/fesm2022/rt-tools-ui-kit-v2-theme-toggle.mjs.map +1 -1
  73. package/fesm2022/rt-tools-ui-kit-v2-thread-list.mjs +2 -0
  74. package/fesm2022/rt-tools-ui-kit-v2-thread-list.mjs.map +1 -1
  75. package/fesm2022/rt-tools-ui-kit-v2-toast.mjs +2 -0
  76. package/fesm2022/rt-tools-ui-kit-v2-toast.mjs.map +1 -1
  77. package/fesm2022/rt-tools-ui-kit-v2-workspace-details.mjs +2 -0
  78. package/fesm2022/rt-tools-ui-kit-v2-workspace-details.mjs.map +1 -1
  79. package/fesm2022/rt-tools-ui-kit-v2-workspace.mjs +2 -0
  80. package/fesm2022/rt-tools-ui-kit-v2-workspace.mjs.map +1 -1
  81. package/package.json +1 -1
  82. package/src/lib/components/aside/footer/rt-aside-footer.component.scss +3 -1
  83. package/src/lib/components/aside/unsaved-dialog/rt-aside-unsaved-dialog.component.scss +10 -3
  84. package/src/lib/components/icon-button/CONTEXT.md +32 -16
  85. package/src/lib/components/icon-button/rt-icon-button.component.scss +17 -9
  86. package/src/lib/components/input/CONTEXT.md +6 -0
  87. package/src/styles/_form.scss +14 -1
  88. package/styles/tokens.css +13 -1
  89. package/types/rt-tools-ui-kit-v2-aside.d.ts +17 -7
  90. package/types/rt-tools-ui-kit-v2-button.d.ts +6 -1
  91. package/types/rt-tools-ui-kit-v2-core.d.ts +18 -0
  92. package/types/rt-tools-ui-kit-v2-icon-button.d.ts +38 -2
  93. package/types/rt-tools-ui-kit-v2-input.d.ts +2 -0
@@ -1 +1 @@
1
- {"version":3,"file":"rt-tools-ui-kit-v2-button.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/button/rt-button.directive.ts"],"sourcesContent":["import { FocusMonitor } from '@angular/cdk/a11y';\nimport { BooleanInput } from '@angular/cdk/coercion';\nimport { DOCUMENT } from '@angular/common';\nimport {\n afterNextRender,\n booleanAttribute,\n computed,\n DestroyRef,\n Directive,\n effect,\n ElementRef,\n HostBinding,\n inject,\n input,\n InputSignal,\n InputSignalWithTransform,\n Renderer2,\n Signal,\n untracked,\n} from '@angular/core';\n\nimport { IRtKitConfig } from '@rt-tools/ui-kit-v2/core';\nimport { rtKitDefault } from '@rt-tools/ui-kit-v2/core';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\nimport { RT_RADIUS_DEFAULT, TRtRadius } from '@rt-tools/ui-kit-v2/core';\nimport { IRtIcon } from '@rt-tools/ui-kit-v2/core';\nimport {\n RT_ICON_GLYPH_STRATEGY,\n RT_ICON_MATERIAL_PRESET_SELECTOR,\n RtIconFontService,\n RtIconRegistry,\n resolveIconGlyph,\n} from '@rt-tools/ui-kit-v2/icon';\nimport { iconMaterialDrawn } from '@rt-tools/ui-kit-v2/icon';\nimport { RtRippleDirective } from '@rt-tools/ui-kit-v2/ripple';\nimport { IButton } from '@rt-tools/ui-kit-v2/core';\n\nconst BEM_BLOCK: string = 'rt-button';\n\n/** Длительность затухания спиннера при выходе из загрузки. */\nconst LOADING_FADE_OUT_MS: number = 300;\n\n/** Запас поверх затухания, после которого подпись возвращается без анимации. */\nconst LOADING_FADE_OUT_BUFFER_MS: number = 50;\n\n/**\n * Директива стилизованной кнопки. Применяется к `<button>` или `<a>`\n * (для ссылок-кнопок с `routerLink`/`href`).\n *\n * Иконка и лейбл рендерятся внутрь элемента через `Renderer2`, чтобы можно\n * было применять директиву к существующему элементу без обёртки.\n * Поддерживает анимированный переход в/из loading.\n *\n * @example\n * ```html\n * <button rtButton label=\"Войти\" theme=\"primary\"></button>\n * <button rtButton label=\"Скачать\" icon=\"ico-download\" theme=\"success\"></button>\n * <button rtButton icon=\"pencil\" theme=\"info\" appearance=\"text\"></button>\n * <button rtButton label=\"Сохранение...\" [loading]=\"saving()\" [disabled]=\"saving()\"></button>\n * <a rtButton label=\"Главная\" [routerLink]=\"'/'\"></a>\n * ```\n */\n@Directive({\n selector: 'button[rtButton], a[rtButton]',\n hostDirectives: [\n { directive: RtRippleDirective, inputs: ['rippleDisabled'] },\n { directive: RtRadiusDirective, inputs: ['radius'] },\n ],\n /* Шаг скругления без входа берётся из настроек кита: приложение, скруглившее все кнопки разом,\n называет шаг один раз, а вход на кнопке по-прежнему сильнее. */\n providers: [\n {\n provide: RT_RADIUS_DEFAULT,\n useFactory: (): TRtRadius | null =>\n rtKitDefault('button', (it: IRtKitConfig.Button): TRtRadius | null | undefined => it.radius, null),\n },\n ],\n})\nexport class RtButtonDirective {\n readonly #el: ElementRef<HTMLButtonElement | HTMLAnchorElement> = inject<ElementRef<HTMLButtonElement | HTMLAnchorElement>>(ElementRef);\n readonly #renderer: Renderer2 = inject(Renderer2);\n readonly #focusMonitor: FocusMonitor = inject(FocusMonitor);\n readonly #doc: Document = inject(DOCUMENT);\n readonly #iconRegistry: RtIconRegistry = inject(RtIconRegistry);\n readonly #glyphStrategy: IRtIcon.GlyphStrategy = inject(RT_ICON_GLYPH_STRATEGY);\n readonly #fontReady: Signal<boolean> = inject(RtIconFontService).ready;\n\n /* С чего стартуют три входа, которые приложение вправе задать киту разом. Значение считается\n из настроек при объявлении входа: так публичный вид входа не меняется — ни тип, ни имя, — а\n вход, написанный в разметке, по-прежнему перебивает всё. Цена — настройки читаются один раз,\n когда узел создан. */\n readonly #appearance: IButton.Appearance = rtKitDefault(\n 'button',\n (it: IRtKitConfig.Button): IButton.Appearance | undefined => it.appearance,\n 'filled'\n );\n readonly #size: IButton.Size = rtKitDefault('button', (it: IRtKitConfig.Button): IButton.Size | undefined => it.size, 'md');\n\n #iconEl: HTMLElement | null = null;\n #labelEl: HTMLElement | null = null;\n #spinnerEl: HTMLElement | null = null;\n #wasLoading: boolean = false;\n\n protected readonly isIconOnly: Signal<boolean> = computed(() => !!this.icon() && !this.label());\n\n /** Текстовый лейбл кнопки. Если null — кнопка только с иконкой. */\n public readonly label: InputSignal<string | null> = input<string | null>(null);\n /**\n * Значок кнопки: имя кита (`check`) или имя Material (`arrow_back`). Имя Material рисуется\n * так же, как вход `glyph` у `rt-icon`: парой из перечня кита или лигатурой шрифта — по\n * настройке `glyphStrategy` у `provideRtIcons()`. Если null — без иконки.\n */\n public readonly icon: InputSignal<string | null> = input<string | null>(null);\n /** Сторона размещения иконки относительно лейбла. */\n public readonly iconPos: InputSignal<IButton.IconPos> = input<IButton.IconPos>('left');\n /** Семантическая палитра. */\n public readonly theme: InputSignal<IButton.Theme> = input<IButton.Theme>('primary');\n /** Внешний вид (filled / outlined / text). Умолчание — из настроек кита. */\n public readonly appearance: InputSignal<IButton.Appearance> = input<IButton.Appearance>(this.#appearance);\n /** Размер. Умолчание — из настроек кита. */\n public readonly size: InputSignal<IButton.Size> = input<IButton.Size>(this.#size);\n /** Состояние загрузки: показывает спиннер вместо иконки, блокирует клики. */\n public readonly loading: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n /** Кастомный CSS-класс иконки в loading. Если null — встроенный CSS-спиннер. */\n public readonly loadingIcon: InputSignal<string | null> = input<string | null>(null);\n /**\n * Подпись во время загрузки. `hide` оставляет подпись и иконку в кнопке невидимыми — ширина\n * не скачет, — а спиннер ставит по центру; имя кнопки для скринридера остаётся.\n */\n public readonly loadingLabel: InputSignal<IButton.LoadingLabel> = input<IButton.LoadingLabel>('keep');\n\n /**\n * Положение двухпозиционной кнопки: `true` — нажата, `false` — отжата, `null` — положения нет\n * вовсе.\n *\n * Три значения, а не два, потому что обычная кнопка переключателем не является и объявлять\n * себя двухпозиционной не должна: сказанное вспомогательным средствам «эта кнопка отжата» на\n * кнопке, которая просто запускает действие, — ложь, а не умолчание. Отжатое положение при\n * этом объявляется наравне с нажатым: молчащая в отжатом виде кнопка неотличима от обычной, и\n * о втором положении узнают только нажав.\n *\n * Само по нажатию положение не меняется: кнопка говорит о нажатии наружу, а положение\n * возвращает вызывающий — иначе вид кнопки и состояние приложения расходятся при первом же\n * отказе сохранения.\n */\n public readonly pressed: InputSignal<boolean | null> = input<boolean | null>(null);\n\n constructor() {\n afterNextRender(() => untracked(() => this.#updateContent()));\n\n /* Источник фокуса пишет CDK классами `cdk-keyboard-focused`, `cdk-mouse-focused` и\n соседними, как у Material: кольцо фокуса рисуется только не от мыши и не от касания.\n Сам монитор, а не `CdkMonitorFocus` хозяином: приложение вправе поставить на ту же\n кнопку `cdkMonitorElementFocus`, и директива дважды на узле — ошибка NG0309. */\n this.#focusMonitor.monitor(this.#el);\n inject(DestroyRef).onDestroy((): void => this.#focusMonitor.stopMonitoring(this.#el));\n\n effect(() => {\n this.label();\n this.icon();\n this.iconPos();\n this.loading();\n this.loadingIcon();\n this.loadingLabel();\n // Лигатура до готовности шрифтов скрыта: готовность перерисовывает содержимое.\n this.#fontReady();\n\n untracked(() => this.#updateContent());\n });\n }\n\n /** Положение наружу: атрибута нет вовсе там, где положения у кнопки не бывает. */\n @HostBinding('attr.aria-pressed')\n protected get ariaPressed(): string | null {\n const pressed: boolean | null = this.pressed();\n\n return pressed === null ? null : String(pressed);\n }\n\n @HostBinding('class')\n protected get hostClasses(): Record<string, boolean> {\n const theme: IButton.Theme = this.theme();\n const appearance: IButton.Appearance = this.appearance();\n const size: IButton.Size = this.size();\n\n return {\n [BEM_BLOCK]: true,\n [`${BEM_BLOCK}--${theme}`]: theme !== 'primary',\n [`${BEM_BLOCK}--outlined`]: appearance === 'outlined',\n [`${BEM_BLOCK}--text`]: appearance === 'text',\n [`${BEM_BLOCK}--loading`]: this.loading(),\n [`${BEM_BLOCK}--loading-label-hidden`]: this.loading() && this.loadingLabel() === 'hide',\n [`${BEM_BLOCK}--icon-only`]: this.isIconOnly(),\n [`${BEM_BLOCK}--${size}`]: size !== 'md',\n [`${BEM_BLOCK}--pressed`]: this.pressed() === true,\n };\n }\n\n #updateContent(): void {\n const button: HTMLButtonElement | HTMLAnchorElement = this.#el.nativeElement;\n const isLoading: boolean = this.loading();\n const wasLoading: boolean = this.#wasLoading;\n this.#wasLoading = isLoading;\n\n if (wasLoading && !isLoading) {\n this.#transitionFromLoading(button);\n return;\n }\n\n this.#clearContent(button);\n\n if (isLoading) {\n this.#renderLoading(button);\n return;\n }\n\n this.#renderIconAndLabel(button);\n }\n\n #transitionFromLoading(button: HTMLElement): void {\n const spinnerEl: HTMLElement | null = this.#spinnerEl;\n\n if (spinnerEl === null) {\n this.#restoreContent(button);\n return;\n }\n\n spinnerEl.style.animation = `rt-button-fade-out ${LOADING_FADE_OUT_MS}ms ease-out forwards`;\n\n // settled-гард делает animationend и страховочный таймаут взаимно\n // идемпотентными — сработает и снимет listener только то, что раньше.\n // Без таймаута подпись возвращалась бы только по анимации, а она не\n // идёт, пока кнопка спрятана (свёрнутая панель, неактивная вкладка):\n // выход из загрузки не наступал никогда, и на кнопке навсегда\n // оставался голый спиннер.\n let settled: boolean = false;\n\n const finish: () => void = (): void => {\n if (settled) {\n return;\n }\n settled = true;\n spinnerEl.removeEventListener('animationend', finish);\n this.#restoreContent(button);\n };\n\n spinnerEl.addEventListener('animationend', finish);\n setTimeout(finish, LOADING_FADE_OUT_MS + LOADING_FADE_OUT_BUFFER_MS);\n }\n\n #restoreContent(button: HTMLElement): void {\n this.#clearContent(button);\n this.#renderIconAndLabel(button);\n }\n\n /**\n * Чистим по классу, а не по своим ссылкам. Под серверным рендером разметку\n * кнопки рисует сервер: после гидратации лейбл и иконка уже лежат в DOM, но создавал их\n * другой экземпляр директивы, и `#labelEl` у клиентского — пустой. Ссылки\n * тогда не находят ничего, а `#renderIconAndLabel` дорисовывает второй\n * лейбл — подпись кнопки удваивается («СохранитьСохранить»).\n */\n #clearContent(button: HTMLElement): void {\n const ownClasses: ReadonlyArray<string> = [`${BEM_BLOCK}__icon`, `${BEM_BLOCK}__label`, `${BEM_BLOCK}__spinner`];\n\n // Обход по детям, а не селектором `:scope >`: тот же код исполняется на\n // сервере, где DOM эмулированный и селекторный движок урезан\n for (const child of Array.from(button.children)) {\n if (ownClasses.some((ownClass: string): boolean => child.classList.contains(ownClass))) {\n this.#renderer.removeChild(button, child);\n }\n }\n\n this.#iconEl = null;\n this.#labelEl = null;\n this.#spinnerEl = null;\n }\n\n #renderLoading(button: HTMLElement): void {\n const loadingIcon: string | null = this.loadingIcon();\n const loader: HTMLElement = loadingIcon ? this.#createIcon(loadingIcon) : this.#createSpinner();\n\n if (this.loadingLabel() === 'hide') {\n // Обычное содержимое остаётся и держит ширину; стили гасят его и ставят\n // загрузчик поверх по центру\n this.#renderIconAndLabel(button);\n this.#renderer.addClass(loader, `${BEM_BLOCK}__loader`);\n this.#renderer.appendChild(button, loader);\n if (!loadingIcon) {\n this.#spinnerEl = loader;\n }\n return;\n }\n\n if (loadingIcon) {\n this.#iconEl = loader;\n this.#renderer.appendChild(button, this.#iconEl);\n } else {\n this.#spinnerEl = loader;\n this.#renderer.appendChild(button, this.#spinnerEl);\n }\n\n const label: string | null = this.label();\n if (label) {\n this.#labelEl = this.#createLabel(label);\n this.#renderer.appendChild(button, this.#labelEl);\n }\n }\n\n #renderIconAndLabel(button: HTMLElement): void {\n const iconClass: string | null = this.icon();\n const label: string | null = this.label();\n const pos: IButton.IconPos = this.iconPos();\n\n const iconEl: HTMLElement | null = iconClass ? this.#createIcon(iconClass) : null;\n const labelEl: HTMLElement | null = label ? this.#createLabel(label) : null;\n\n if (pos === 'left') {\n if (iconEl) {\n this.#renderer.appendChild(button, iconEl);\n }\n if (labelEl) {\n this.#renderer.appendChild(button, labelEl);\n }\n } else {\n if (labelEl) {\n this.#renderer.appendChild(button, labelEl);\n }\n if (iconEl) {\n this.#renderer.appendChild(button, iconEl);\n }\n }\n\n this.#iconEl = iconEl;\n this.#labelEl = labelEl;\n }\n\n #createIcon(iconName: string): HTMLElement {\n const resolved: IRtIcon.Resolved | null = resolveIconGlyph(null, iconName, this.#glyphStrategy);\n if (resolved?.kind === 'kit') {\n return this.#createKitIcon(resolved.name);\n }\n return this.#createGlyph(iconName);\n }\n\n #createKitIcon(name: IRtIcon.Name): HTMLElement {\n const svg: SVGSVGElement = this.#doc.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttribute('focusable', 'false');\n svg.setAttribute('aria-hidden', 'true');\n svg.setAttribute('viewBox', '0 0 24 24');\n svg.classList.add(`${BEM_BLOCK}__icon`);\n\n // Тот же путь, что и у компонента значка: имя просится у реестра, а он ходит за файлом\n // один раз на страницу — значок, спрошенный обеими разметками сразу, едет одним запросом.\n const drawing: IRtIcon.Drawing = this.#drawingOf(name);\n this.#iconRegistry.request(name, drawing);\n\n const use: SVGUseElement = this.#doc.createElementNS('http://www.w3.org/2000/svg', 'use');\n use.setAttribute('href', this.#iconRegistry.symbolHref(name, drawing));\n svg.appendChild(use);\n\n return svg as unknown as HTMLElement;\n }\n\n /**\n * Набор рисунка — как у компонента значка: материальный рисунок под разметкой с признаком\n * материального набора, если у имени он есть. Признак читается при каждой отрисовке\n * содержимого, а после первой отрисовки она повторяется — контейнер к тому времени на месте.\n */\n #drawingOf(name: IRtIcon.Name): IRtIcon.Drawing {\n const underMaterial: boolean = this.#el.nativeElement.closest(RT_ICON_MATERIAL_PRESET_SELECTOR) !== null;\n return underMaterial && iconMaterialDrawn.has(name) ? 'material' : 'base';\n }\n\n /** Лигатура шрифта Material Symbols для имени без пары. Шрифт подключает приложение. */\n #createGlyph(glyph: string): HTMLElement {\n const el: HTMLElement = this.#renderer.createElement('span') as HTMLElement;\n this.#renderer.addClass(el, `${BEM_BLOCK}__icon`);\n this.#renderer.addClass(el, `${BEM_BLOCK}__glyph`);\n if (!this.#fontReady()) {\n this.#renderer.addClass(el, `${BEM_BLOCK}__glyph--pending`);\n }\n this.#renderer.setAttribute(el, 'aria-hidden', 'true');\n this.#renderer.appendChild(el, this.#renderer.createText(glyph));\n return el;\n }\n\n #createLabel(text: string): HTMLElement {\n const el: HTMLElement = this.#renderer.createElement('span') as HTMLElement;\n this.#renderer.addClass(el, `${BEM_BLOCK}__label`);\n this.#renderer.appendChild(el, this.#renderer.createText(text));\n return el;\n }\n\n #createSpinner(): HTMLElement {\n const wrapper: HTMLElement = this.#renderer.createElement('span') as HTMLElement;\n this.#renderer.addClass(wrapper, `${BEM_BLOCK}__spinner`);\n\n const circle: HTMLElement = this.#renderer.createElement('span') as HTMLElement;\n this.#renderer.addClass(circle, `${BEM_BLOCK}__spinner-circle`);\n this.#renderer.appendChild(wrapper, circle);\n\n return wrapper;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"rt-tools-ui-kit-v2-button.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/button/rt-button.directive.ts"],"sourcesContent":["import { FocusMonitor } from '@angular/cdk/a11y';\nimport { BooleanInput } from '@angular/cdk/coercion';\nimport { DOCUMENT } from '@angular/common';\nimport {\n afterNextRender,\n booleanAttribute,\n computed,\n DestroyRef,\n Directive,\n effect,\n ElementRef,\n HostBinding,\n inject,\n input,\n InputSignal,\n InputSignalWithTransform,\n Renderer2,\n signal,\n Signal,\n untracked,\n WritableSignal,\n} from '@angular/core';\n\nimport { IRtKitConfig } from '@rt-tools/ui-kit-v2/core';\nimport { rtKitDefault } from '@rt-tools/ui-kit-v2/core';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\nimport { RT_RADIUS_DEFAULT, TRtRadius } from '@rt-tools/ui-kit-v2/core';\nimport { IRtIcon } from '@rt-tools/ui-kit-v2/core';\nimport {\n RT_ICON_GLYPH_STRATEGY,\n RT_ICON_MATERIAL_PRESET_SELECTOR,\n RtIconFontService,\n RtIconRegistry,\n resolveIconGlyph,\n} from '@rt-tools/ui-kit-v2/icon';\nimport { iconMaterialDrawn } from '@rt-tools/ui-kit-v2/icon';\nimport { RtRippleDirective } from '@rt-tools/ui-kit-v2/ripple';\nimport { IButton } from '@rt-tools/ui-kit-v2/core';\n\nconst BEM_BLOCK: string = 'rt-button';\n\n/** Длительность затухания спиннера при выходе из загрузки. */\nconst LOADING_FADE_OUT_MS: number = 300;\n\n/** Запас поверх затухания, после которого подпись возвращается без анимации. */\nconst LOADING_FADE_OUT_BUFFER_MS: number = 50;\n\n/**\n * Директива стилизованной кнопки. Применяется к `<button>` или `<a>`\n * (для ссылок-кнопок с `routerLink`/`href`).\n *\n * Иконка и лейбл рендерятся внутрь элемента через `Renderer2`, чтобы можно\n * было применять директиву к существующему элементу без обёртки.\n * Поддерживает анимированный переход в/из loading.\n *\n * @example\n * ```html\n * <button rtButton label=\"Войти\" theme=\"primary\"></button>\n * <button rtButton label=\"Скачать\" icon=\"ico-download\" theme=\"success\"></button>\n * <button rtButton icon=\"pencil\" theme=\"info\" appearance=\"text\"></button>\n * <button rtButton label=\"Сохранение...\" [loading]=\"saving()\" [disabled]=\"saving()\"></button>\n * <a rtButton label=\"Главная\" [routerLink]=\"'/'\"></a>\n * ```\n */\n@Directive({\n selector: 'button[rtButton], a[rtButton]',\n hostDirectives: [\n { directive: RtRippleDirective, inputs: ['rippleDisabled'] },\n { directive: RtRadiusDirective, inputs: ['radius'] },\n ],\n /* Шаг скругления без входа берётся из настроек кита: приложение, скруглившее все кнопки разом,\n называет шаг один раз, а вход на кнопке по-прежнему сильнее. */\n providers: [\n {\n provide: RT_RADIUS_DEFAULT,\n useFactory: (): TRtRadius | null =>\n rtKitDefault('button', (it: IRtKitConfig.Button): TRtRadius | null | undefined => it.radius, null),\n },\n ],\n})\nexport class RtButtonDirective {\n readonly #el: ElementRef<HTMLButtonElement | HTMLAnchorElement> = inject<ElementRef<HTMLButtonElement | HTMLAnchorElement>>(ElementRef);\n readonly #renderer: Renderer2 = inject(Renderer2);\n readonly #focusMonitor: FocusMonitor = inject(FocusMonitor);\n readonly #doc: Document = inject(DOCUMENT);\n readonly #iconRegistry: RtIconRegistry = inject(RtIconRegistry);\n readonly #glyphStrategy: IRtIcon.GlyphStrategy = inject(RT_ICON_GLYPH_STRATEGY);\n readonly #fontReady: Signal<boolean> = inject(RtIconFontService).ready;\n\n /* С чего стартуют три входа, которые приложение вправе задать киту разом. Значение считается\n из настроек при объявлении входа: так публичный вид входа не меняется — ни тип, ни имя, — а\n вход, написанный в разметке, по-прежнему перебивает всё. Цена — настройки читаются один раз,\n когда узел создан. */\n readonly #appearance: IButton.Appearance = rtKitDefault(\n 'button',\n (it: IRtKitConfig.Button): IButton.Appearance | undefined => it.appearance,\n 'filled'\n );\n readonly #size: IButton.Size = rtKitDefault('button', (it: IRtKitConfig.Button): IButton.Size | undefined => it.size, 'md');\n\n #iconEl: HTMLElement | null = null;\n #labelEl: HTMLElement | null = null;\n #spinnerEl: HTMLElement | null = null;\n #wasLoading: boolean = false;\n\n readonly #theme: Signal<IButton.Theme> = computed(() => this.placeLook()?.theme ?? this.theme());\n readonly #appearanceShown: Signal<IButton.Appearance> = computed(() => this.placeLook()?.appearance ?? this.appearance());\n readonly #icon: Signal<string | null> = computed(() => (this.placeLook()?.icon === null ? null : this.icon()));\n readonly #label: Signal<string | null> = computed(() => this.placeLook()?.label ?? this.label());\n\n protected readonly isIconOnly: Signal<boolean> = computed(() => !!this.#icon() && !this.#label());\n\n /**\n * Вид, который задаёт место кнопки: слот подвала панели. Пишет его хозяин места, а не\n * приложение, — входы кнопки при этом не трогаются и вернутся, когда место вид снимет.\n */\n public readonly placeLook: WritableSignal<IButton.PlaceLook | null> = signal<IButton.PlaceLook | null>(null);\n\n /** Текстовый лейбл кнопки. Если null — кнопка только с иконкой. */\n public readonly label: InputSignal<string | null> = input<string | null>(null);\n /**\n * Значок кнопки: имя кита (`check`) или имя Material (`arrow_back`). Имя Material рисуется\n * так же, как вход `glyph` у `rt-icon`: парой из перечня кита или лигатурой шрифта — по\n * настройке `glyphStrategy` у `provideRtIcons()`. Если null — без иконки.\n */\n public readonly icon: InputSignal<string | null> = input<string | null>(null);\n /** Сторона размещения иконки относительно лейбла. */\n public readonly iconPos: InputSignal<IButton.IconPos> = input<IButton.IconPos>('left');\n /** Семантическая палитра. */\n public readonly theme: InputSignal<IButton.Theme> = input<IButton.Theme>('primary');\n /** Внешний вид (filled / outlined / text). Умолчание — из настроек кита. */\n public readonly appearance: InputSignal<IButton.Appearance> = input<IButton.Appearance>(this.#appearance);\n /** Размер. Умолчание — из настроек кита. */\n public readonly size: InputSignal<IButton.Size> = input<IButton.Size>(this.#size);\n /** Состояние загрузки: показывает спиннер вместо иконки, блокирует клики. */\n public readonly loading: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n /** Кастомный CSS-класс иконки в loading. Если null — встроенный CSS-спиннер. */\n public readonly loadingIcon: InputSignal<string | null> = input<string | null>(null);\n /**\n * Подпись во время загрузки. `hide` оставляет подпись и иконку в кнопке невидимыми — ширина\n * не скачет, — а спиннер ставит по центру; имя кнопки для скринридера остаётся.\n */\n public readonly loadingLabel: InputSignal<IButton.LoadingLabel> = input<IButton.LoadingLabel>('keep');\n\n /**\n * Положение двухпозиционной кнопки: `true` — нажата, `false` — отжата, `null` — положения нет\n * вовсе.\n *\n * Три значения, а не два, потому что обычная кнопка переключателем не является и объявлять\n * себя двухпозиционной не должна: сказанное вспомогательным средствам «эта кнопка отжата» на\n * кнопке, которая просто запускает действие, — ложь, а не умолчание. Отжатое положение при\n * этом объявляется наравне с нажатым: молчащая в отжатом виде кнопка неотличима от обычной, и\n * о втором положении узнают только нажав.\n *\n * Само по нажатию положение не меняется: кнопка говорит о нажатии наружу, а положение\n * возвращает вызывающий — иначе вид кнопки и состояние приложения расходятся при первом же\n * отказе сохранения.\n */\n public readonly pressed: InputSignal<boolean | null> = input<boolean | null>(null);\n\n constructor() {\n afterNextRender(() => untracked(() => this.#updateContent()));\n\n /* Источник фокуса пишет CDK классами `cdk-keyboard-focused`, `cdk-mouse-focused` и\n соседними, как у Material: кольцо фокуса рисуется только не от мыши и не от касания.\n Сам монитор, а не `CdkMonitorFocus` хозяином: приложение вправе поставить на ту же\n кнопку `cdkMonitorElementFocus`, и директива дважды на узле — ошибка NG0309. */\n this.#focusMonitor.monitor(this.#el);\n inject(DestroyRef).onDestroy((): void => this.#focusMonitor.stopMonitoring(this.#el));\n\n effect(() => {\n this.#label();\n this.#icon();\n this.iconPos();\n this.loading();\n this.loadingIcon();\n this.loadingLabel();\n // Лигатура до готовности шрифтов скрыта: готовность перерисовывает содержимое.\n this.#fontReady();\n\n untracked(() => this.#updateContent());\n });\n }\n\n /** Положение наружу: атрибута нет вовсе там, где положения у кнопки не бывает. */\n @HostBinding('attr.aria-pressed')\n protected get ariaPressed(): string | null {\n const pressed: boolean | null = this.pressed();\n\n return pressed === null ? null : String(pressed);\n }\n\n @HostBinding('class')\n protected get hostClasses(): Record<string, boolean> {\n const theme: IButton.Theme = this.#theme();\n const appearance: IButton.Appearance = this.#appearanceShown();\n const size: IButton.Size = this.size();\n\n return {\n [BEM_BLOCK]: true,\n [`${BEM_BLOCK}--${theme}`]: theme !== 'primary',\n [`${BEM_BLOCK}--outlined`]: appearance === 'outlined',\n [`${BEM_BLOCK}--text`]: appearance === 'text',\n [`${BEM_BLOCK}--loading`]: this.loading(),\n [`${BEM_BLOCK}--loading-label-hidden`]: this.loading() && this.loadingLabel() === 'hide',\n [`${BEM_BLOCK}--icon-only`]: this.isIconOnly(),\n [`${BEM_BLOCK}--${size}`]: size !== 'md',\n [`${BEM_BLOCK}--pressed`]: this.pressed() === true,\n };\n }\n\n #updateContent(): void {\n const button: HTMLButtonElement | HTMLAnchorElement = this.#el.nativeElement;\n const isLoading: boolean = this.loading();\n const wasLoading: boolean = this.#wasLoading;\n this.#wasLoading = isLoading;\n\n if (wasLoading && !isLoading) {\n this.#transitionFromLoading(button);\n return;\n }\n\n this.#clearContent(button);\n\n if (isLoading) {\n this.#renderLoading(button);\n return;\n }\n\n this.#renderIconAndLabel(button);\n }\n\n #transitionFromLoading(button: HTMLElement): void {\n const spinnerEl: HTMLElement | null = this.#spinnerEl;\n\n if (spinnerEl === null) {\n this.#restoreContent(button);\n return;\n }\n\n spinnerEl.style.animation = `rt-button-fade-out ${LOADING_FADE_OUT_MS}ms ease-out forwards`;\n\n // settled-гард делает animationend и страховочный таймаут взаимно\n // идемпотентными — сработает и снимет listener только то, что раньше.\n // Без таймаута подпись возвращалась бы только по анимации, а она не\n // идёт, пока кнопка спрятана (свёрнутая панель, неактивная вкладка):\n // выход из загрузки не наступал никогда, и на кнопке навсегда\n // оставался голый спиннер.\n let settled: boolean = false;\n\n const finish: () => void = (): void => {\n if (settled) {\n return;\n }\n settled = true;\n spinnerEl.removeEventListener('animationend', finish);\n this.#restoreContent(button);\n };\n\n spinnerEl.addEventListener('animationend', finish);\n setTimeout(finish, LOADING_FADE_OUT_MS + LOADING_FADE_OUT_BUFFER_MS);\n }\n\n #restoreContent(button: HTMLElement): void {\n this.#clearContent(button);\n this.#renderIconAndLabel(button);\n }\n\n /**\n * Чистим по классу, а не по своим ссылкам. Под серверным рендером разметку\n * кнопки рисует сервер: после гидратации лейбл и иконка уже лежат в DOM, но создавал их\n * другой экземпляр директивы, и `#labelEl` у клиентского — пустой. Ссылки\n * тогда не находят ничего, а `#renderIconAndLabel` дорисовывает второй\n * лейбл — подпись кнопки удваивается («СохранитьСохранить»).\n */\n #clearContent(button: HTMLElement): void {\n const ownClasses: ReadonlyArray<string> = [`${BEM_BLOCK}__icon`, `${BEM_BLOCK}__label`, `${BEM_BLOCK}__spinner`];\n\n // Обход по детям, а не селектором `:scope >`: тот же код исполняется на\n // сервере, где DOM эмулированный и селекторный движок урезан\n for (const child of Array.from(button.children)) {\n if (ownClasses.some((ownClass: string): boolean => child.classList.contains(ownClass))) {\n this.#renderer.removeChild(button, child);\n }\n }\n\n this.#iconEl = null;\n this.#labelEl = null;\n this.#spinnerEl = null;\n }\n\n #renderLoading(button: HTMLElement): void {\n const loadingIcon: string | null = this.loadingIcon();\n const loader: HTMLElement = loadingIcon ? this.#createIcon(loadingIcon) : this.#createSpinner();\n\n if (this.loadingLabel() === 'hide') {\n // Обычное содержимое остаётся и держит ширину; стили гасят его и ставят\n // загрузчик поверх по центру\n this.#renderIconAndLabel(button);\n this.#renderer.addClass(loader, `${BEM_BLOCK}__loader`);\n this.#renderer.appendChild(button, loader);\n if (!loadingIcon) {\n this.#spinnerEl = loader;\n }\n return;\n }\n\n if (loadingIcon) {\n this.#iconEl = loader;\n this.#renderer.appendChild(button, this.#iconEl);\n } else {\n this.#spinnerEl = loader;\n this.#renderer.appendChild(button, this.#spinnerEl);\n }\n\n const label: string | null = this.#label();\n if (label) {\n this.#labelEl = this.#createLabel(label);\n this.#renderer.appendChild(button, this.#labelEl);\n }\n }\n\n #renderIconAndLabel(button: HTMLElement): void {\n const iconClass: string | null = this.#icon();\n const label: string | null = this.#label();\n const pos: IButton.IconPos = this.iconPos();\n\n const iconEl: HTMLElement | null = iconClass ? this.#createIcon(iconClass) : null;\n const labelEl: HTMLElement | null = label ? this.#createLabel(label) : null;\n\n if (pos === 'left') {\n if (iconEl) {\n this.#renderer.appendChild(button, iconEl);\n }\n if (labelEl) {\n this.#renderer.appendChild(button, labelEl);\n }\n } else {\n if (labelEl) {\n this.#renderer.appendChild(button, labelEl);\n }\n if (iconEl) {\n this.#renderer.appendChild(button, iconEl);\n }\n }\n\n this.#iconEl = iconEl;\n this.#labelEl = labelEl;\n }\n\n #createIcon(iconName: string): HTMLElement {\n const resolved: IRtIcon.Resolved | null = resolveIconGlyph(null, iconName, this.#glyphStrategy);\n if (resolved?.kind === 'kit') {\n return this.#createKitIcon(resolved.name);\n }\n return this.#createGlyph(iconName);\n }\n\n #createKitIcon(name: IRtIcon.Name): HTMLElement {\n const svg: SVGSVGElement = this.#doc.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttribute('focusable', 'false');\n svg.setAttribute('aria-hidden', 'true');\n svg.setAttribute('viewBox', '0 0 24 24');\n svg.classList.add(`${BEM_BLOCK}__icon`);\n\n // Тот же путь, что и у компонента значка: имя просится у реестра, а он ходит за файлом\n // один раз на страницу — значок, спрошенный обеими разметками сразу, едет одним запросом.\n const drawing: IRtIcon.Drawing = this.#drawingOf(name);\n this.#iconRegistry.request(name, drawing);\n\n const use: SVGUseElement = this.#doc.createElementNS('http://www.w3.org/2000/svg', 'use');\n use.setAttribute('href', this.#iconRegistry.symbolHref(name, drawing));\n svg.appendChild(use);\n\n return svg as unknown as HTMLElement;\n }\n\n /**\n * Набор рисунка — как у компонента значка: материальный рисунок под разметкой с признаком\n * материального набора, если у имени он есть. Признак читается при каждой отрисовке\n * содержимого, а после первой отрисовки она повторяется — контейнер к тому времени на месте.\n */\n #drawingOf(name: IRtIcon.Name): IRtIcon.Drawing {\n const underMaterial: boolean = this.#el.nativeElement.closest(RT_ICON_MATERIAL_PRESET_SELECTOR) !== null;\n return underMaterial && iconMaterialDrawn.has(name) ? 'material' : 'base';\n }\n\n /** Лигатура шрифта Material Symbols для имени без пары. Шрифт подключает приложение. */\n #createGlyph(glyph: string): HTMLElement {\n const el: HTMLElement = this.#renderer.createElement('span') as HTMLElement;\n this.#renderer.addClass(el, `${BEM_BLOCK}__icon`);\n this.#renderer.addClass(el, `${BEM_BLOCK}__glyph`);\n if (!this.#fontReady()) {\n this.#renderer.addClass(el, `${BEM_BLOCK}__glyph--pending`);\n }\n this.#renderer.setAttribute(el, 'aria-hidden', 'true');\n this.#renderer.appendChild(el, this.#renderer.createText(glyph));\n return el;\n }\n\n #createLabel(text: string): HTMLElement {\n const el: HTMLElement = this.#renderer.createElement('span') as HTMLElement;\n this.#renderer.addClass(el, `${BEM_BLOCK}__label`);\n this.#renderer.appendChild(el, this.#renderer.createText(text));\n return el;\n }\n\n #createSpinner(): HTMLElement {\n const wrapper: HTMLElement = this.#renderer.createElement('span') as HTMLElement;\n this.#renderer.addClass(wrapper, `${BEM_BLOCK}__spinner`);\n\n const circle: HTMLElement = this.#renderer.createElement('span') as HTMLElement;\n this.#renderer.addClass(circle, `${BEM_BLOCK}__spinner-circle`);\n this.#renderer.appendChild(wrapper, circle);\n\n return wrapper;\n }\n}\n"],"mappings":"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"}
@@ -259,6 +259,8 @@ var RtCalendarComponent = class RtCalendarComponent {
259
259
  "disabled",
260
260
  "active",
261
261
  "expanded",
262
+ "ariaHaspopup",
263
+ "link",
262
264
  "indicator"
263
265
  ],
264
266
  outputs: ["clicked"]
@@ -1 +1 @@
1
- {"version":3,"file":"rt-tools-ui-kit-v2-calendar.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/calendar/rt-calendar.model.ts","../../../projects/ui-kit-v2/src/lib/components/calendar/rt-calendar.component.ts","../../../projects/ui-kit-v2/src/lib/components/calendar/rt-calendar.component.html"],"sourcesContent":["/**\n * Контракты `rt-calendar` — презентационный месячный грид с range-выбором.\n *\n * Компонент домен-агностичен: состояния/цены/доступность дней вычисляет\n * consumer и передаёт готовые view-модели месяцев. Клики по дням и навигация\n * по месяцам эмитятся наружу; никакой доменной логики внутри нет.\n */\n\n/** Состояние ячейки дня — модификатор `data-state` на кнопке дня. */\nexport enum ERtCalendarDayState {\n Free = 'free',\n Busy = 'busy',\n Past = 'past',\n Blocked = 'blocked',\n Start = 'start',\n End = 'end',\n InRange = 'in-range',\n /** Выбранный день одиночного выбора — залит. */\n Chosen = 'chosen',\n}\n\nexport namespace IRtCalendar {\n /** View-модель дня. `key` — стабильный ключ (ISO-дата). */\n export interface Day {\n key: string;\n dayOfMonth: number;\n /** Подпись под числом (цена за ночь и т.п.); пустая строка не рендерится. */\n sublabel: string;\n state: ERtCalendarDayState;\n disabled: boolean;\n /** Сегодняшний день — обведён рамкой поверх любого состояния. */\n today?: boolean;\n }\n\n /** Клавиша сетки, нажатая на дне. */\n export interface GridKey {\n key: string;\n day: Day;\n }\n\n /** View-модель месяца: подпись, пустые ячейки до первого дня, дни. */\n export interface Month {\n key: string;\n label: string;\n leadingBlanks: readonly number[];\n days: readonly Day[];\n }\n}\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n afterRenderEffect,\n booleanAttribute,\n computed,\n signal,\n viewChildren,\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n input,\n InputSignal,\n InputSignalWithTransform,\n output,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\n\n// rt-tools\nimport { BlockDirective, ElemDirective } from '@rt-tools/core';\n\nimport { RtIconButtonComponent } from '@rt-tools/ui-kit-v2/icon-button';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\nimport { RtSkeletonComponent } from '@rt-tools/ui-kit-v2/skeleton';\nimport { ERtCalendarDayState, IRtCalendar } from './rt-calendar.model';\n\nconst BEM_BLOCK: string = 'rt-calendar';\n\n/** Клавиши, что календарь в режиме сетки отдаёт наружу вместо прокрутки страницы. */\nconst GRID_KEYS: ReadonlySet<string> = new Set(['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'PageUp', 'PageDown', 'Home', 'End']);\n\n@Component({\n selector: 'rt-calendar',\n templateUrl: './rt-calendar.component.html',\n styleUrl: './rt-calendar.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // angular\n NgTemplateOutlet,\n\n // rt-tools\n BlockDirective,\n ElemDirective,\n\n // components\n RtIconButtonComponent,\n RtSkeletonComponent,\n ],\n hostDirectives: [{ directive: RtRadiusDirective, inputs: ['radius'] }],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtCalendarComponent {\n /** Фокус двигала клавиша: только тогда календарь переводит фокус на `activeKey`. */\n readonly #keyed: WritableSignal<boolean> = signal(false);\n\n protected readonly sublabelSkeletonHeight: string = '12px';\n protected readonly chosenState: ERtCalendarDayState = ERtCalendarDayState.Chosen;\n\n protected readonly dayButtons: Signal<readonly ElementRef<HTMLButtonElement>[]> =\n viewChildren<ElementRef<HTMLButtonElement>>('dayButton');\n\n /**\n * День, что стоит в порядке обхода Tab в режиме сетки: `activeKey`, иначе выбранный, иначе\n * сегодняшний, иначе первый доступный. Вне режима сетки — `null`, и каждый день обходится Tab.\n */\n protected readonly rovingKey: Signal<string | null> = computed((): string | null => {\n if (!this.grid()) {\n return null;\n }\n const days: IRtCalendar.Day[] = this.months().flatMap((month: IRtCalendar.Month): IRtCalendar.Day[] => [...month.days]);\n const active: string | null = this.activeKey();\n const pick: IRtCalendar.Day | undefined =\n days.find((day: IRtCalendar.Day): boolean => day.key === active) ??\n days.find((day: IRtCalendar.Day): boolean => day.state === ERtCalendarDayState.Chosen) ??\n days.find((day: IRtCalendar.Day): boolean => day.today === true) ??\n days.find((day: IRtCalendar.Day): boolean => !day.disabled);\n return pick?.key ?? null;\n });\n\n public readonly months: InputSignal<readonly IRtCalendar.Month[]> = input.required<readonly IRtCalendar.Month[]>();\n public readonly weekdayLabels: InputSignal<readonly string[]> = input.required<readonly string[]>();\n public readonly canPrev: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n public readonly canNext: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n /** Локализованные aria-подписи кнопок навигации — задаёт consumer. */\n public readonly prevAriaLabel: InputSignal<string> = input<string>('');\n public readonly nextAriaLabel: InputSignal<string> = input<string>('');\n public readonly sublabelsLoading: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /**\n * Режим сетки: один день в обходе Tab, клавиши стрелок, PageUp/PageDown, Home и End уходят\n * наружу событием `gridKey`, а фокус встаёт на `activeKey`. Выключен — поведение прежнее.\n */\n public readonly grid: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n /** День с фокусом в режиме сетки, ключ `YYYY-MM-DD`; его ставит consumer по `gridKey`. */\n public readonly activeKey: InputSignal<string | null> = input<string | null>(null);\n /** Заголовок месяца — кнопка, что шлёт `titleClick`: так consumer открывает выбор месяца. */\n public readonly titleAction: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n /** Заголовок первого месяца стоит в шапке между стрелками, а не над сеткой. */\n public readonly headerTitle: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n public readonly prevMonth: OutputEmitterRef<void> = output<void>();\n public readonly nextMonth: OutputEmitterRef<void> = output<void>();\n public readonly dayClick: OutputEmitterRef<IRtCalendar.Day> = output<IRtCalendar.Day>();\n /** Клавиша сетки на дне: куда перевести фокус, решает consumer. */\n public readonly gridKey: OutputEmitterRef<IRtCalendar.GridKey> = output<IRtCalendar.GridKey>();\n public readonly titleClick: OutputEmitterRef<IRtCalendar.Month> = output<IRtCalendar.Month>();\n /** День под указателем или с фокусом; `null` — указатель ушёл с месяцев. По нему рисуется будущий диапазон. */\n public readonly dayHover: OutputEmitterRef<IRtCalendar.Day | null> = output<IRtCalendar.Day | null>();\n\n constructor() {\n afterRenderEffect((): void => {\n const key: string | null = this.rovingKey();\n if (!this.#keyed() || key === null) {\n return;\n }\n this.dayButtons()\n .find((button: ElementRef<HTMLButtonElement>): boolean => button.nativeElement.dataset['iso'] === key)\n ?.nativeElement.focus();\n });\n }\n\n protected onDayKey(event: KeyboardEvent, day: IRtCalendar.Day): void {\n if (!this.grid() || !GRID_KEYS.has(event.key)) {\n return;\n }\n event.preventDefault();\n this.#keyed.set(true);\n this.gridKey.emit({ key: event.key, day });\n }\n\n protected onDayHover(day: IRtCalendar.Day): void {\n if (!day.disabled) {\n this.dayHover.emit(day);\n }\n }\n\n protected onDayClick(day: IRtCalendar.Day): void {\n if (!day.disabled) {\n this.dayClick.emit(day);\n }\n }\n}\n","<ng-container rtBlock=\"rt-calendar\">\n <div rtElem=\"header\">\n <rt-icon-button\n rtElem=\"nav\"\n qa-dataid=\"calendar-prev-month\"\n icon=\"chevron-left\"\n variant=\"secondary\"\n radius=\"full\"\n [ariaLabel]=\"prevAriaLabel()\"\n [disabled]=\"!canPrev()\"\n (clicked)=\"prevMonth.emit()\" />\n @if (headerTitle() && months()[0]; as first) {\n <ng-container *ngTemplateOutlet=\"titleTpl; context: { $implicit: first }\" />\n }\n <ng-content select=\"[calendarHint]\" />\n <rt-icon-button\n rtElem=\"nav\"\n qa-dataid=\"calendar-next-month\"\n icon=\"chevron-right\"\n variant=\"secondary\"\n radius=\"full\"\n [ariaLabel]=\"nextAriaLabel()\"\n [disabled]=\"!canNext()\"\n (clicked)=\"nextMonth.emit()\" />\n </div>\n\n <div rtElem=\"months\" qa-dataid=\"calendar-months\" (mouseleave)=\"dayHover.emit(null)\">\n @for (month of months(); track month.key) {\n <div rtElem=\"month\" qa-dataid=\"calendar-month\">\n @if (!headerTitle()) {\n <ng-container *ngTemplateOutlet=\"titleTpl; context: { $implicit: month }\" />\n }\n <div rtElem=\"grid\" qa-dataid=\"calendar-grid\">\n @for (weekday of weekdayLabels(); track $index) {\n <span rtElem=\"weekday\" qa-dataid=\"calendar-weekday\">{{ weekday }}</span>\n }\n @for (blank of month.leadingBlanks; track blank) {\n <!-- Пустая ячейка сетки до первого дня месяца: занимает место и ничего не красит. -->\n <span qa-dataid=\"calendar-blank\" aria-hidden=\"true\"></span>\n }\n @for (day of month.days; track day.key) {\n <button\n #dayButton\n rtElem=\"day\"\n qa-dataid=\"calendar-day\"\n type=\"button\"\n [attr.data-iso]=\"day.key\"\n [attr.data-state]=\"day.state\"\n [attr.data-today]=\"day.today ? '' : null\"\n [attr.aria-current]=\"day.today ? 'date' : null\"\n [attr.aria-pressed]=\"day.state === chosenState ? true : null\"\n [attr.tabindex]=\"rovingKey() === null ? null : day.key === rovingKey() ? 0 : -1\"\n [disabled]=\"day.disabled\"\n (keydown)=\"onDayKey($event, day)\"\n (mouseenter)=\"onDayHover(day)\"\n (focus)=\"onDayHover(day)\"\n (click)=\"onDayClick(day)\">\n <span rtElem=\"day-num\" qa-dataid=\"calendar-day-num\">{{ day.dayOfMonth }}</span>\n @if (sublabelsLoading()) {\n <rt-skeleton\n rtElem=\"day-sublabel\"\n qa-dataid=\"calendar-day-price-skeleton\"\n width=\"80%\"\n radius=\"sm\"\n [height]=\"sublabelSkeletonHeight\" />\n } @else if (day.sublabel) {\n <span rtElem=\"day-sublabel\" qa-dataid=\"calendar-day-price\">{{ day.sublabel }}</span>\n }\n </button>\n }\n </div>\n </div>\n }\n </div>\n\n <ng-content />\n\n <ng-template #titleTpl let-month>\n @if (titleAction()) {\n <button rtElem=\"month-title\" qa-dataid=\"calendar-month-title\" type=\"button\" (click)=\"titleClick.emit(month)\">\n {{ month.label }}\n </button>\n } @else {\n <p rtElem=\"month-title\" qa-dataid=\"calendar-month-title\">{{ month.label }}</p>\n }\n </ng-template>\n</ng-container>\n"],"mappings":";;;;;;;;AASA,IAAY;CAAZ,SAAY,qBAAmB;CAC3B,oBAAA,UAAA;CACA,oBAAA,UAAA;CACA,oBAAA,UAAA;CACA,oBAAA,aAAA;CACA,oBAAA,WAAA;CACA,oBAAA,SAAA;CACA,oBAAA,aAAA;CAEA,oBAAA,YAAA;AACJ,EAAA,CAVY,wBAAA,sBAAmB,CAAA,EAAA;ACoB/B,MAAM,YAAoB;AAG1B,MAAM,4BAAiC,IAAI,IAAI;CAAC;CAAa;CAAc;CAAW;CAAa;CAAU;CAAY;CAAQ;AAAK,CAAC;AAyBvI,IAAa,sBAAb,MAAa,oBAAmB;CAEnB;CAoET,cAAA;EApES,KAAA,SAAkC,OAAO,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;EAErC,KAAA,yBAAiC;EACjC,KAAA,cAAmC,oBAAoB;EAEvD,KAAA,aACf,aAA4C,aAAY,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;EAMzC,KAAA,YAAmC,eAA6B;GAC/E,IAAI,CAAC,KAAK,KAAI,GACV,OAAO;GAEX,MAAM,OAA0B,KAAK,OAAM,CAAE,CAAC,SAAS,UAAgD,CAAC,GAAG,MAAM,IAAI,CAAC;GACtH,MAAM,SAAwB,KAAK,UAAS;GAM5C,QAJI,KAAK,MAAM,QAAkC,IAAI,QAAQ,MAAM,KAC/D,KAAK,MAAM,QAAkC,IAAI,UAAU,oBAAoB,MAAM,KACrF,KAAK,MAAM,QAAkC,IAAI,UAAU,IAAI,KAC/D,KAAK,MAAM,QAAkC,CAAC,IAAI,QAAQ,EACvD,EAAM,OAAO;EACxB,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;EAEc,KAAA,SAAoD,MAAM,SAAwC,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;EAClG,KAAA,gBAAgD,MAAM,SAA6B,GAAA,YAAA,CAAA,EAAA,WAAA,gBAAA,CAAA,+BAAA,CAAA,CAAA;EACnF,KAAA,UAA2D,MAA6B,OAAK;GAAA,GAAA,YAAA,EAAA,WAAA,UAAA,+BAAA,CAAA;GACzG,WAAW;EAAgB,CAAA;EAEf,KAAA,UAA2D,MAA6B,OAAK;GAAA,GAAA,YAAA,EAAA,WAAA,UAAA,+BAAA,CAAA;GACzG,WAAW;EAAgB,CAAA;EAGf,KAAA,gBAAqC,MAAc,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,gBAAA,CAAA,+BAAA,CAAA,CAAA;EACtD,KAAA,gBAAqC,MAAc,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,gBAAA,CAAA,+BAAA,CAAA,CAAA;EACtD,KAAA,mBAAoE,MAA6B,OAAK;GAAA,GAAA,YAAA,EAAA,WAAA,mBAAA,+BAAA,CAAA;GAClH,WAAW;EAAgB,CAAA;EAOf,KAAA,OAAwD,MAA6B,OAAK;GAAA,GAAA,YAAA,EAAA,WAAA,OAAA,+BAAA,CAAA;GACtG,WAAW;EAAgB,CAAA;EAGf,KAAA,YAAwC,MAAqB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;EAElE,KAAA,cAA+D,MAA6B,OAAK;GAAA,GAAA,YAAA,EAAA,WAAA,cAAA,+BAAA,CAAA;GAC7G,WAAW;EAAgB,CAAA;EAGf,KAAA,cAA+D,MAA6B,OAAK;GAAA,GAAA,YAAA,EAAA,WAAA,cAAA,+BAAA,CAAA;GAC7G,WAAW;EAAgB,CAAA;EAGf,KAAA,YAAoC,OAAM;EAC1C,KAAA,YAAoC,OAAM;EAC1C,KAAA,WAA8C,OAAM;EAEpD,KAAA,UAAiD,OAAM;EACvD,KAAA,aAAkD,OAAM;EAExD,KAAA,WAAqD,OAAM;EAGvE,wBAA6B;GACzB,MAAM,MAAqB,KAAK,UAAS;GACzC,IAAI,CAAC,KAAK,OAAM,KAAM,QAAQ,MAC1B;GAEJ,KAAK,WAAU,CAAE,CACZ,MAAM,WAAmD,OAAO,cAAc,QAAQ,WAAW,GAAG,CAAC,EACpG,cAAc,MAAK;EAC7B,CAAC;CACL;CAEU,SAAS,OAAsB,KAAoB;EACzD,IAAI,CAAC,KAAK,KAAI,KAAM,CAAC,UAAU,IAAI,MAAM,GAAG,GACxC;EAEJ,MAAM,eAAc;EACpB,KAAK,OAAO,IAAI,IAAI;EACpB,KAAK,QAAQ,KAAK;GAAE,KAAK,MAAM;GAAK;EAAG,CAAE;CAC7C;CAEU,WAAW,KAAoB;EACrC,IAAI,CAAC,IAAI,UACL,KAAK,SAAS,KAAK,GAAG;CAE9B;CAEU,WAAW,KAAoB;EACrC,IAAI,CAAC,IAAI,UACL,KAAK,SAAS,KAAK,GAAG;CAE9B;CArGS;EAAA,KAAA,OAAA,GAAA,mBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAmB,MAAA,CAAA;GAAA,QAAA,GAAA,gBAAA;EAAA,CAAA;CAAA;CAAnB;EAAA,KAAA,OAAA,GAAA,qBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,MAAA;GAAmB,cAAA;GAAA,UAAA;GAAA,QAAA;IAAA,QAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,eAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,SAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,SAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,eAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,eAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,kBAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,MAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,WAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,aAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,aAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;GAAA;GAAA,SAAA;IAAA,WAAA;IAAA,WAAA;IAAA,UAAA;IAAA,SAAA;IAAA,YAAA;IAAA,UAAA;GAAA;GAAA,MAAA,EAAA,gBAAA,cAAA;GAAA,aAAA,CAAA;IAAA,cAAA;IAAA,WAAA,CAAA,WAAA;IAAA,aAAA;IAAA,UAAA;GAAA,CAAA;GAAA,gBAAA,CAAA;IAAA,WAAA,GAAA;IAAA,QAAA,CAAA,UAAA,QAAA;GAAA,CAAA;GAAA,UAAA;GAAA,UCzDhC;GAuFA,QAAA,CAAA,y3JAAA;GAAA,cAAA;IAAA;KAAA,MAAA;KAAA,MD7CQ;KAAgB,UAAA;KAAA,QAAA;MAAA;MAAA;MAAA;KAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MAGhB;KAAc,UAAA;KAAA,QAAA,CAAA,OAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MACd;KAAa,UAAA;KAAA,QAAA,CAAA,OAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MAGb;KAAqB,UAAA;KAAA,QAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;KAAA;KAAA,SAAA,CAAA,SAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MACrB;KAAmB,UAAA;KAAA,QAAA;MAAA;MAAA;MAAA;MAAA;MAAA;KAAA;IAAA;GAAA;GAAA,iBAAA,GAAA,wBAAA;GAAA,eAAA,GAAA,kBAAA;EAAA,CAAA;CAAA;;AAOd,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAmB,YAAA,CAAA;EAvB/B,MAAA;EACa,MAAA,CAAA;GAAA,UAAA;GAAa,iBAGN,wBAAwB;GAAM,eAChC,kBAAkB;GAAI,SAC5B;IAEL;IAGA;IACA;IAGA;IACA;GACH;GAAA,gBACe,CAAC;IAAE,WAAW;IAAmB,QAAQ,CAAC,QAAQ;GAAC,CAAE;GAAC,MAChE,EACF,OAAO,UACV;GAAA,UAAA;GAAA,QAAA,CAAA,y3JAAA;EAAA,CAAA;CAU+C,CAAA;CAAA,sBAAA,CAAA;CAAA,gBAAA;EAAA,YAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,aAAW,EAAA,UAAA,KAAA,CAAA;EAAA,CAAA;EAAA,QAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,eAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,SAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,SAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,eAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,eAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,kBAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,MAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,WAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,aAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,aAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,WAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,WAAA;EAAA,CAAA;EAAA,WAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,WAAA;EAAA,CAAA;EAAA,UAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,UAAA;EAAA,CAAA;EAAA,SAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,SAAA;EAAA,CAAA;EAAA,YAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,YAAA;EAAA,CAAA;EAAA,UAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,UAAA;EAAA,CAAA;CAAA;AAAA,CAAA"}
1
+ {"version":3,"file":"rt-tools-ui-kit-v2-calendar.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/calendar/rt-calendar.model.ts","../../../projects/ui-kit-v2/src/lib/components/calendar/rt-calendar.component.ts","../../../projects/ui-kit-v2/src/lib/components/calendar/rt-calendar.component.html"],"sourcesContent":["/**\n * Контракты `rt-calendar` — презентационный месячный грид с range-выбором.\n *\n * Компонент домен-агностичен: состояния/цены/доступность дней вычисляет\n * consumer и передаёт готовые view-модели месяцев. Клики по дням и навигация\n * по месяцам эмитятся наружу; никакой доменной логики внутри нет.\n */\n\n/** Состояние ячейки дня — модификатор `data-state` на кнопке дня. */\nexport enum ERtCalendarDayState {\n Free = 'free',\n Busy = 'busy',\n Past = 'past',\n Blocked = 'blocked',\n Start = 'start',\n End = 'end',\n InRange = 'in-range',\n /** Выбранный день одиночного выбора — залит. */\n Chosen = 'chosen',\n}\n\nexport namespace IRtCalendar {\n /** View-модель дня. `key` — стабильный ключ (ISO-дата). */\n export interface Day {\n key: string;\n dayOfMonth: number;\n /** Подпись под числом (цена за ночь и т.п.); пустая строка не рендерится. */\n sublabel: string;\n state: ERtCalendarDayState;\n disabled: boolean;\n /** Сегодняшний день — обведён рамкой поверх любого состояния. */\n today?: boolean;\n }\n\n /** Клавиша сетки, нажатая на дне. */\n export interface GridKey {\n key: string;\n day: Day;\n }\n\n /** View-модель месяца: подпись, пустые ячейки до первого дня, дни. */\n export interface Month {\n key: string;\n label: string;\n leadingBlanks: readonly number[];\n days: readonly Day[];\n }\n}\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n afterRenderEffect,\n booleanAttribute,\n computed,\n signal,\n viewChildren,\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n input,\n InputSignal,\n InputSignalWithTransform,\n output,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\n\n// rt-tools\nimport { BlockDirective, ElemDirective } from '@rt-tools/core';\n\nimport { RtIconButtonComponent } from '@rt-tools/ui-kit-v2/icon-button';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\nimport { RtSkeletonComponent } from '@rt-tools/ui-kit-v2/skeleton';\nimport { ERtCalendarDayState, IRtCalendar } from './rt-calendar.model';\n\nconst BEM_BLOCK: string = 'rt-calendar';\n\n/** Клавиши, что календарь в режиме сетки отдаёт наружу вместо прокрутки страницы. */\nconst GRID_KEYS: ReadonlySet<string> = new Set(['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'PageUp', 'PageDown', 'Home', 'End']);\n\n@Component({\n selector: 'rt-calendar',\n templateUrl: './rt-calendar.component.html',\n styleUrl: './rt-calendar.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // angular\n NgTemplateOutlet,\n\n // rt-tools\n BlockDirective,\n ElemDirective,\n\n // components\n RtIconButtonComponent,\n RtSkeletonComponent,\n ],\n hostDirectives: [{ directive: RtRadiusDirective, inputs: ['radius'] }],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtCalendarComponent {\n /** Фокус двигала клавиша: только тогда календарь переводит фокус на `activeKey`. */\n readonly #keyed: WritableSignal<boolean> = signal(false);\n\n protected readonly sublabelSkeletonHeight: string = '12px';\n protected readonly chosenState: ERtCalendarDayState = ERtCalendarDayState.Chosen;\n\n protected readonly dayButtons: Signal<readonly ElementRef<HTMLButtonElement>[]> =\n viewChildren<ElementRef<HTMLButtonElement>>('dayButton');\n\n /**\n * День, что стоит в порядке обхода Tab в режиме сетки: `activeKey`, иначе выбранный, иначе\n * сегодняшний, иначе первый доступный. Вне режима сетки — `null`, и каждый день обходится Tab.\n */\n protected readonly rovingKey: Signal<string | null> = computed((): string | null => {\n if (!this.grid()) {\n return null;\n }\n const days: IRtCalendar.Day[] = this.months().flatMap((month: IRtCalendar.Month): IRtCalendar.Day[] => [...month.days]);\n const active: string | null = this.activeKey();\n const pick: IRtCalendar.Day | undefined =\n days.find((day: IRtCalendar.Day): boolean => day.key === active) ??\n days.find((day: IRtCalendar.Day): boolean => day.state === ERtCalendarDayState.Chosen) ??\n days.find((day: IRtCalendar.Day): boolean => day.today === true) ??\n days.find((day: IRtCalendar.Day): boolean => !day.disabled);\n return pick?.key ?? null;\n });\n\n public readonly months: InputSignal<readonly IRtCalendar.Month[]> = input.required<readonly IRtCalendar.Month[]>();\n public readonly weekdayLabels: InputSignal<readonly string[]> = input.required<readonly string[]>();\n public readonly canPrev: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n public readonly canNext: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n /** Локализованные aria-подписи кнопок навигации — задаёт consumer. */\n public readonly prevAriaLabel: InputSignal<string> = input<string>('');\n public readonly nextAriaLabel: InputSignal<string> = input<string>('');\n public readonly sublabelsLoading: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /**\n * Режим сетки: один день в обходе Tab, клавиши стрелок, PageUp/PageDown, Home и End уходят\n * наружу событием `gridKey`, а фокус встаёт на `activeKey`. Выключен — поведение прежнее.\n */\n public readonly grid: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n /** День с фокусом в режиме сетки, ключ `YYYY-MM-DD`; его ставит consumer по `gridKey`. */\n public readonly activeKey: InputSignal<string | null> = input<string | null>(null);\n /** Заголовок месяца — кнопка, что шлёт `titleClick`: так consumer открывает выбор месяца. */\n public readonly titleAction: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n /** Заголовок первого месяца стоит в шапке между стрелками, а не над сеткой. */\n public readonly headerTitle: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n public readonly prevMonth: OutputEmitterRef<void> = output<void>();\n public readonly nextMonth: OutputEmitterRef<void> = output<void>();\n public readonly dayClick: OutputEmitterRef<IRtCalendar.Day> = output<IRtCalendar.Day>();\n /** Клавиша сетки на дне: куда перевести фокус, решает consumer. */\n public readonly gridKey: OutputEmitterRef<IRtCalendar.GridKey> = output<IRtCalendar.GridKey>();\n public readonly titleClick: OutputEmitterRef<IRtCalendar.Month> = output<IRtCalendar.Month>();\n /** День под указателем или с фокусом; `null` — указатель ушёл с месяцев. По нему рисуется будущий диапазон. */\n public readonly dayHover: OutputEmitterRef<IRtCalendar.Day | null> = output<IRtCalendar.Day | null>();\n\n constructor() {\n afterRenderEffect((): void => {\n const key: string | null = this.rovingKey();\n if (!this.#keyed() || key === null) {\n return;\n }\n this.dayButtons()\n .find((button: ElementRef<HTMLButtonElement>): boolean => button.nativeElement.dataset['iso'] === key)\n ?.nativeElement.focus();\n });\n }\n\n protected onDayKey(event: KeyboardEvent, day: IRtCalendar.Day): void {\n if (!this.grid() || !GRID_KEYS.has(event.key)) {\n return;\n }\n event.preventDefault();\n this.#keyed.set(true);\n this.gridKey.emit({ key: event.key, day });\n }\n\n protected onDayHover(day: IRtCalendar.Day): void {\n if (!day.disabled) {\n this.dayHover.emit(day);\n }\n }\n\n protected onDayClick(day: IRtCalendar.Day): void {\n if (!day.disabled) {\n this.dayClick.emit(day);\n }\n }\n}\n","<ng-container rtBlock=\"rt-calendar\">\n <div rtElem=\"header\">\n <rt-icon-button\n rtElem=\"nav\"\n qa-dataid=\"calendar-prev-month\"\n icon=\"chevron-left\"\n variant=\"secondary\"\n radius=\"full\"\n [ariaLabel]=\"prevAriaLabel()\"\n [disabled]=\"!canPrev()\"\n (clicked)=\"prevMonth.emit()\" />\n @if (headerTitle() && months()[0]; as first) {\n <ng-container *ngTemplateOutlet=\"titleTpl; context: { $implicit: first }\" />\n }\n <ng-content select=\"[calendarHint]\" />\n <rt-icon-button\n rtElem=\"nav\"\n qa-dataid=\"calendar-next-month\"\n icon=\"chevron-right\"\n variant=\"secondary\"\n radius=\"full\"\n [ariaLabel]=\"nextAriaLabel()\"\n [disabled]=\"!canNext()\"\n (clicked)=\"nextMonth.emit()\" />\n </div>\n\n <div rtElem=\"months\" qa-dataid=\"calendar-months\" (mouseleave)=\"dayHover.emit(null)\">\n @for (month of months(); track month.key) {\n <div rtElem=\"month\" qa-dataid=\"calendar-month\">\n @if (!headerTitle()) {\n <ng-container *ngTemplateOutlet=\"titleTpl; context: { $implicit: month }\" />\n }\n <div rtElem=\"grid\" qa-dataid=\"calendar-grid\">\n @for (weekday of weekdayLabels(); track $index) {\n <span rtElem=\"weekday\" qa-dataid=\"calendar-weekday\">{{ weekday }}</span>\n }\n @for (blank of month.leadingBlanks; track blank) {\n <!-- Пустая ячейка сетки до первого дня месяца: занимает место и ничего не красит. -->\n <span qa-dataid=\"calendar-blank\" aria-hidden=\"true\"></span>\n }\n @for (day of month.days; track day.key) {\n <button\n #dayButton\n rtElem=\"day\"\n qa-dataid=\"calendar-day\"\n type=\"button\"\n [attr.data-iso]=\"day.key\"\n [attr.data-state]=\"day.state\"\n [attr.data-today]=\"day.today ? '' : null\"\n [attr.aria-current]=\"day.today ? 'date' : null\"\n [attr.aria-pressed]=\"day.state === chosenState ? true : null\"\n [attr.tabindex]=\"rovingKey() === null ? null : day.key === rovingKey() ? 0 : -1\"\n [disabled]=\"day.disabled\"\n (keydown)=\"onDayKey($event, day)\"\n (mouseenter)=\"onDayHover(day)\"\n (focus)=\"onDayHover(day)\"\n (click)=\"onDayClick(day)\">\n <span rtElem=\"day-num\" qa-dataid=\"calendar-day-num\">{{ day.dayOfMonth }}</span>\n @if (sublabelsLoading()) {\n <rt-skeleton\n rtElem=\"day-sublabel\"\n qa-dataid=\"calendar-day-price-skeleton\"\n width=\"80%\"\n radius=\"sm\"\n [height]=\"sublabelSkeletonHeight\" />\n } @else if (day.sublabel) {\n <span rtElem=\"day-sublabel\" qa-dataid=\"calendar-day-price\">{{ day.sublabel }}</span>\n }\n </button>\n }\n </div>\n </div>\n }\n </div>\n\n <ng-content />\n\n <ng-template #titleTpl let-month>\n @if (titleAction()) {\n <button rtElem=\"month-title\" qa-dataid=\"calendar-month-title\" type=\"button\" (click)=\"titleClick.emit(month)\">\n {{ month.label }}\n </button>\n } @else {\n <p rtElem=\"month-title\" qa-dataid=\"calendar-month-title\">{{ month.label }}</p>\n }\n </ng-template>\n</ng-container>\n"],"mappings":"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"}
@@ -90,7 +90,7 @@ var RtConfirmPopoverComponent = class RtConfirmPopoverComponent {
90
90
  },
91
91
  host: { classAttribute: "rt-confirm-popover" },
92
92
  ngImport: i0,
93
- template: "<ng-container rtBlock=\"rt-confirm-popover\">\n @if (title()) {\n <p rtElem=\"title\">{{ title() }}</p>\n }\n\n <p rtElem=\"message\">{{ message() }}</p>\n\n <div rtElem=\"actions\">\n <button\n rtButton\n qa-dataid=\"confirm-cancel\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"text\"\n [label]=\"cancelText()\"\n [attr.aria-label]=\"cancelText()\"\n (click)=\"onCancel()\"></button>\n <button\n rtButton\n qa-dataid=\"confirm-accept\"\n type=\"button\"\n [theme]=\"tone()\"\n [label]=\"confirmText()\"\n [attr.aria-label]=\"confirmText()\"\n (click)=\"onConfirm()\"></button>\n </div>\n</ng-container>\n",
93
+ template: "<ng-container rtBlock=\"rt-confirm-popover\">\n @if (title()) {\n <p rtElem=\"title\">{{ title() }}</p>\n }\n\n <p rtElem=\"message\">{{ message() }}</p>\n\n <div rtElem=\"actions\">\n <button\n rtButton\n qa-dataid=\"confirm-cancel\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"outlined\"\n [label]=\"cancelText()\"\n [attr.aria-label]=\"cancelText()\"\n (click)=\"onCancel()\"></button>\n <button\n rtButton\n qa-dataid=\"confirm-accept\"\n type=\"button\"\n [theme]=\"tone()\"\n [label]=\"confirmText()\"\n [attr.aria-label]=\"confirmText()\"\n (click)=\"onConfirm()\"></button>\n </div>\n</ng-container>\n",
94
94
  styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-confirm-popover{--rt-confirm-popover-radius: var(--rt-radius-md);--rt-confirm-popover-border-width: var(--rt-border-width-thin);--rt-confirm-popover-shadow: var(--rt-shadow-lg);display:flex;width:280px;max-width:280px;flex-direction:column;padding:var(--rt-space-md);border:var(--rt-confirm-popover-border-width) solid var(--rt-color-border-subtle);border-radius:var(--rt-confirm-popover-radius);background:var(--rt-color-bg-surface);box-shadow:var(--rt-confirm-popover-shadow);gap:var(--rt-space-sm)}.rt-confirm-popover__title{margin:0;color:var(--rt-color-text-primary);font-size:var(--rt-text-sm);font-weight:var(--rt-font-weight-semibold)}.rt-confirm-popover__message{margin:0;color:var(--rt-color-text-primary);font-size:var(--rt-text-sm);line-height:var(--rt-leading-normal)}.rt-confirm-popover__actions{display:flex;justify-content:space-between;gap:var(--rt-space-sm);margin-block-start:var(--rt-space-xs)}}\n"],
95
95
  dependencies: [
96
96
  {
@@ -145,7 +145,7 @@ i0.ɵɵngDeclareClassMetadata({
145
145
  ElemDirective
146
146
  ],
147
147
  host: { class: BEM_BLOCK },
148
- template: "<ng-container rtBlock=\"rt-confirm-popover\">\n @if (title()) {\n <p rtElem=\"title\">{{ title() }}</p>\n }\n\n <p rtElem=\"message\">{{ message() }}</p>\n\n <div rtElem=\"actions\">\n <button\n rtButton\n qa-dataid=\"confirm-cancel\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"text\"\n [label]=\"cancelText()\"\n [attr.aria-label]=\"cancelText()\"\n (click)=\"onCancel()\"></button>\n <button\n rtButton\n qa-dataid=\"confirm-accept\"\n type=\"button\"\n [theme]=\"tone()\"\n [label]=\"confirmText()\"\n [attr.aria-label]=\"confirmText()\"\n (click)=\"onConfirm()\"></button>\n </div>\n</ng-container>\n",
148
+ template: "<ng-container rtBlock=\"rt-confirm-popover\">\n @if (title()) {\n <p rtElem=\"title\">{{ title() }}</p>\n }\n\n <p rtElem=\"message\">{{ message() }}</p>\n\n <div rtElem=\"actions\">\n <button\n rtButton\n qa-dataid=\"confirm-cancel\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"outlined\"\n [label]=\"cancelText()\"\n [attr.aria-label]=\"cancelText()\"\n (click)=\"onCancel()\"></button>\n <button\n rtButton\n qa-dataid=\"confirm-accept\"\n type=\"button\"\n [theme]=\"tone()\"\n [label]=\"confirmText()\"\n [attr.aria-label]=\"confirmText()\"\n (click)=\"onConfirm()\"></button>\n </div>\n</ng-container>\n",
149
149
  styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-confirm-popover{--rt-confirm-popover-radius: var(--rt-radius-md);--rt-confirm-popover-border-width: var(--rt-border-width-thin);--rt-confirm-popover-shadow: var(--rt-shadow-lg);display:flex;width:280px;max-width:280px;flex-direction:column;padding:var(--rt-space-md);border:var(--rt-confirm-popover-border-width) solid var(--rt-color-border-subtle);border-radius:var(--rt-confirm-popover-radius);background:var(--rt-color-bg-surface);box-shadow:var(--rt-confirm-popover-shadow);gap:var(--rt-space-sm)}.rt-confirm-popover__title{margin:0;color:var(--rt-color-text-primary);font-size:var(--rt-text-sm);font-weight:var(--rt-font-weight-semibold)}.rt-confirm-popover__message{margin:0;color:var(--rt-color-text-primary);font-size:var(--rt-text-sm);line-height:var(--rt-leading-normal)}.rt-confirm-popover__actions{display:flex;justify-content:space-between;gap:var(--rt-space-sm);margin-block-start:var(--rt-space-xs)}}\n"]
150
150
  }]
151
151
  }],
@@ -1 +1 @@
1
- {"version":3,"file":"rt-tools-ui-kit-v2-confirm-popover.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/confirm-popover/rt-confirm-popover.component.ts","../../../projects/ui-kit-v2/src/lib/components/confirm-popover/rt-confirm-popover.component.html","../../../projects/ui-kit-v2/src/lib/components/confirm-popover/rt-confirm.directive.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n input,\n InputSignal,\n output,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective } from '@rt-tools/core';\n\nimport { rtKitLabel } from '@rt-tools/ui-kit-v2/core';\nimport { RtButtonDirective } from '@rt-tools/ui-kit-v2/button';\nimport { IRtConfirmPopover } from './rt-confirm-popover.model';\n\nconst BEM_BLOCK: string = 'rt-confirm-popover';\n\n/**\n * Презентационная панель подтверждения. Рендерится директивой `[rtConfirm]`\n * через CDK `ComponentPortal` под host-кнопкой. Содержит опциональный заголовок,\n * текст вопроса и две кнопки: «Отмена» (text/secondary) и подтверждающую\n * (`tone` — danger по умолчанию для деструктивных действий).\n *\n * `ViewEncapsulation.None` — стили префиксованы `.rt-confirm-popover`. Inputs\n * выставляются директивой через `setInput`; outputs (`confirm`/`cancel`) она\n * слушает и транслирует в `(confirmed)` / закрытие.\n */\n@Component({\n selector: 'rt-confirm-popover',\n templateUrl: './rt-confirm-popover.component.html',\n styleUrl: './rt-confirm-popover.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [RtButtonDirective, BlockDirective, ElemDirective],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtConfirmPopoverComponent {\n readonly #t_uiConfirm: Signal<string> = rtKitLabel('uiConfirm');\n readonly #t_uiCancel: Signal<string> = rtKitLabel('uiCancel');\n\n protected readonly confirmText: Signal<string> = computed((): string => this.confirmLabel() || this.#t_uiConfirm());\n protected readonly cancelText: Signal<string> = computed((): string => this.cancelLabel() || this.#t_uiCancel());\n\n public readonly message: InputSignal<string> = input<string>('');\n\n public readonly title: InputSignal<string | null> = input<string | null>(null);\n\n /** Пусто — берётся переведённая подпись по умолчанию */\n public readonly confirmLabel: InputSignal<string> = input<string>('');\n\n public readonly cancelLabel: InputSignal<string> = input<string>('');\n\n public readonly tone: InputSignal<IRtConfirmPopover.Tone> = input<IRtConfirmPopover.Tone>('danger');\n\n public readonly accepted: OutputEmitterRef<void> = output<void>();\n\n public readonly cancelled: OutputEmitterRef<void> = output<void>();\n\n protected onConfirm(): void {\n this.accepted.emit();\n }\n\n protected onCancel(): void {\n this.cancelled.emit();\n }\n}\n","<ng-container rtBlock=\"rt-confirm-popover\">\n @if (title()) {\n <p rtElem=\"title\">{{ title() }}</p>\n }\n\n <p rtElem=\"message\">{{ message() }}</p>\n\n <div rtElem=\"actions\">\n <button\n rtButton\n qa-dataid=\"confirm-cancel\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"text\"\n [label]=\"cancelText()\"\n [attr.aria-label]=\"cancelText()\"\n (click)=\"onCancel()\"></button>\n <button\n rtButton\n qa-dataid=\"confirm-accept\"\n type=\"button\"\n [theme]=\"tone()\"\n [label]=\"confirmText()\"\n [attr.aria-label]=\"confirmText()\"\n (click)=\"onConfirm()\"></button>\n </div>\n</ng-container>\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport {\n ConnectedPosition,\n FlexibleConnectedPositionStrategy,\n Overlay,\n OverlayConfig,\n OverlayRef,\n ScrollStrategyOptions,\n} from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport {\n booleanAttribute,\n ComponentRef,\n DestroyRef,\n Directive,\n ElementRef,\n inject,\n input,\n InputSignal,\n InputSignalWithTransform,\n OnDestroy,\n output,\n OutputEmitterRef,\n signal,\n Signal,\n WritableSignal,\n} from '@angular/core';\nimport { outputToObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { map, merge, Observable, Subject, switchMap } from 'rxjs';\n\nimport { setRtComponentInputs } from '@rt-tools/core';\n\nimport { carryThemeScope, materialPresetClassesOf } from '@rt-tools/ui-kit-v2/core';\nimport { RtConfirmPopoverComponent } from './rt-confirm-popover.component';\nimport { IRtConfirmPopover } from './rt-confirm-popover.model';\n\nconst VIEWPORT_MARGIN: number = 8;\n\n/**\n * Confirm-popover директива поверх CDK Overlay. Вешается на host-кнопку\n * (обычно `rt-icon-button` деструктивного действия). По клику показывает прямо\n * под кнопкой панель `rt-confirm-popover` с вопросом и кнопками\n * «Отмена» / подтверждение. Подтверждение → `(confirmed)` + закрытие; отмена,\n * outside-click, Escape → просто закрытие.\n *\n * Движок — CDK `flexibleConnectedTo` (end-выравнивание + flip), чтобы панель у\n * правого края aside'а раскрывалась влево и не резалась `overflow: hidden`.\n *\n * @example\n * ```html\n * <rt-icon-button\n * icon=\"ico-error\"\n * variant=\"danger\"\n * ariaLabel=\"Отклонить\"\n * tooltip=\"Отклонить\"\n * [rtConfirm]=\"'Отклонить заявку? Оператор получит уведомление.'\"\n * rtConfirmTitle=\"Отклонить заявку\"\n * rtConfirmLabel=\"Отклонить\"\n * (confirmed)=\"rejectTour()\" />\n * ```\n */\n@Directive({\n selector: '[rtConfirm]',\n exportAs: 'rtConfirm',\n host: {\n '(click)': 'onHostClick()',\n },\n})\nexport class RtConfirmDirective implements OnDestroy {\n readonly #overlay: Overlay = inject(Overlay);\n readonly #elementRef: ElementRef<HTMLElement> = inject<ElementRef<HTMLElement>>(ElementRef);\n readonly #scrollStrategies: ScrollStrategyOptions = inject(ScrollStrategyOptions);\n readonly #destroyRef: DestroyRef = inject(DestroyRef);\n\n readonly #overlayCreatedSource: Subject<OverlayRef> = new Subject<OverlayRef>();\n readonly #panelAttachedSource: Subject<ComponentRef<RtConfirmPopoverComponent>> = new Subject<\n ComponentRef<RtConfirmPopoverComponent>\n >();\n\n #overlayRef: OverlayRef | null = null;\n #panelRef: ComponentRef<RtConfirmPopoverComponent> | null = null;\n\n protected readonly isOpenState: WritableSignal<boolean> = signal<boolean>(false);\n\n public readonly message: InputSignal<string> = input<string>('', { alias: 'rtConfirm' });\n\n public readonly title: InputSignal<string | null> = input<string | null>(null, {\n alias: 'rtConfirmTitle',\n });\n\n /** Пусто — панель подставит переведённое умолчание */\n public readonly label: InputSignal<string> = input<string>('', {\n alias: 'rtConfirmLabel',\n });\n\n public readonly cancelLabel: InputSignal<string> = input<string>('', {\n alias: 'rtConfirmCancelLabel',\n });\n\n public readonly tone: InputSignal<IRtConfirmPopover.Tone> = input<IRtConfirmPopover.Tone>('danger', { alias: 'rtConfirmTone' });\n\n public readonly disabled: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n alias: 'rtConfirmDisabled',\n transform: booleanAttribute,\n });\n\n public readonly confirmed: OutputEmitterRef<void> = output<void>();\n\n public readonly isOpen: Signal<boolean> = this.isOpenState.asReadonly();\n\n constructor() {\n // Per-attach подписки на outputs панели (accepted / cancelled) живут в\n // одном конструкторном стриме: open() эмитит свежий ComponentRef,\n // switchMap переключается на его outputs (предыдущая панель к этому\n // моменту уже detach'нута — outputs комплитятся при destroy componentRef).\n // Бэкстоп takeUntilDestroyed — на жизнь директивы.\n this.#panelAttachedSource\n .pipe(\n switchMap((panelRef: ComponentRef<RtConfirmPopoverComponent>): Observable<() => void> =>\n merge(\n outputToObservable(panelRef.instance.accepted).pipe(\n map((): (() => void) => (): void => {\n this.confirmed.emit();\n this.close();\n })\n ),\n outputToObservable(panelRef.instance.cancelled).pipe(map((): (() => void) => (): void => this.close()))\n )\n ),\n takeUntilDestroyed(this.#destroyRef)\n )\n .subscribe((handleCloseIntent: () => void): void => handleCloseIntent());\n\n // Outside-click / ESC подписки на единожды создаваемый overlay:\n // #ensureOverlay эмитит OverlayRef после создания (ровно один раз за\n // жизнь директивы), стрим живёт до destroy директивы.\n this.#overlayCreatedSource\n .pipe(\n switchMap((overlayRef: OverlayRef): Observable<() => void> =>\n merge(\n overlayRef.outsidePointerEvents().pipe(\n map((event: MouseEvent): (() => void) => (): void => {\n // Клик по host обрабатывает onHostClick (toggle) — не закрываем\n // здесь, иначе двойной toggle.\n if (this.#elementRef.nativeElement.contains(event.target as Node)) {\n return;\n }\n this.close();\n })\n ),\n overlayRef.keydownEvents().pipe(\n map((event: KeyboardEvent): (() => void) => (): void => {\n if (event.key === 'Escape') {\n event.preventDefault();\n this.close();\n }\n })\n )\n )\n ),\n takeUntilDestroyed(this.#destroyRef)\n )\n .subscribe((handleCloseIntent: () => void): void => handleCloseIntent());\n }\n\n public ngOnDestroy(): void {\n this.#disposeOverlay();\n }\n\n public open(): void {\n if (this.disabled() || this.isOpenState() || this.message().trim() === '') {\n return;\n }\n const overlayRef: OverlayRef = this.#ensureOverlay();\n // Коробка переживает закрытие, а кусок темы вокруг host'а мог смениться — переносим на каждом открытии.\n carryThemeScope(overlayRef.overlayElement, this.#elementRef.nativeElement);\n const portal: ComponentPortal<RtConfirmPopoverComponent> = new ComponentPortal(RtConfirmPopoverComponent);\n this.#panelRef = overlayRef.attach(portal);\n // Одним набором, а не пятью строками с именами: имя, написанное строкой, не проверяет\n // ничто — опечатка собирается и падает на подъёме сообщением о входе, которого нет.\n setRtComponentInputs(this.#panelRef, {\n message: this.message(),\n title: this.title(),\n confirmLabel: this.label(),\n cancelLabel: this.cancelLabel(),\n tone: this.tone(),\n });\n\n // Подписки на accepted/cancelled объявлены один раз в конструкторе —\n // здесь только эмит свежего ComponentRef (см. #panelAttachedSource-стрим).\n this.#panelAttachedSource.next(this.#panelRef);\n\n this.isOpenState.set(true);\n }\n\n public close(): void {\n if (!this.isOpenState()) {\n return;\n }\n this.#overlayRef?.detach();\n this.#panelRef = null;\n this.isOpenState.set(false);\n }\n\n protected onHostClick(): void {\n if (this.disabled()) {\n return;\n }\n if (this.isOpenState()) {\n this.close();\n } else {\n this.open();\n }\n }\n\n #ensureOverlay(): OverlayRef {\n if (this.#overlayRef !== null) {\n return this.#overlayRef;\n }\n const positions: ConnectedPosition[] = [\n {\n originX: 'end',\n originY: 'bottom',\n overlayX: 'end',\n overlayY: 'top',\n offsetY: 6,\n },\n {\n originX: 'end',\n originY: 'top',\n overlayX: 'end',\n overlayY: 'bottom',\n offsetY: -6,\n },\n ];\n const positionStrategy: FlexibleConnectedPositionStrategy = this.#overlay\n .position()\n .flexibleConnectedTo(this.#elementRef)\n .withPush(true)\n .withViewportMargin(VIEWPORT_MARGIN)\n .withFlexibleDimensions(false)\n .withPositions(positions);\n\n const config: OverlayConfig = new OverlayConfig({\n positionStrategy,\n scrollStrategy: this.#scrollStrategies.reposition(),\n hasBackdrop: false,\n panelClass: ['rt-confirm-popover-panel', ...materialPresetClassesOf(this.#elementRef.nativeElement)],\n });\n const overlayRef: OverlayRef = this.#overlay.create(config);\n\n // Outside-click / ESC подписки объявлены один раз в конструкторе —\n // здесь только эмит созданного OverlayRef (см. #overlayCreatedSource-стрим).\n this.#overlayCreatedSource.next(overlayRef);\n\n this.#overlayRef = overlayRef;\n return overlayRef;\n }\n\n #disposeOverlay(): void {\n this.#overlayRef?.dispose();\n this.#overlayRef = null;\n this.#panelRef = null;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"rt-tools-ui-kit-v2-confirm-popover.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/confirm-popover/rt-confirm-popover.component.ts","../../../projects/ui-kit-v2/src/lib/components/confirm-popover/rt-confirm-popover.component.html","../../../projects/ui-kit-v2/src/lib/components/confirm-popover/rt-confirm.directive.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n input,\n InputSignal,\n output,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective } from '@rt-tools/core';\n\nimport { rtKitLabel } from '@rt-tools/ui-kit-v2/core';\nimport { RtButtonDirective } from '@rt-tools/ui-kit-v2/button';\nimport { IRtConfirmPopover } from './rt-confirm-popover.model';\n\nconst BEM_BLOCK: string = 'rt-confirm-popover';\n\n/**\n * Презентационная панель подтверждения. Рендерится директивой `[rtConfirm]`\n * через CDK `ComponentPortal` под host-кнопкой. Содержит опциональный заголовок,\n * текст вопроса и две кнопки: «Отмена» (text/secondary) и подтверждающую\n * (`tone` — danger по умолчанию для деструктивных действий).\n *\n * `ViewEncapsulation.None` — стили префиксованы `.rt-confirm-popover`. Inputs\n * выставляются директивой через `setInput`; outputs (`confirm`/`cancel`) она\n * слушает и транслирует в `(confirmed)` / закрытие.\n */\n@Component({\n selector: 'rt-confirm-popover',\n templateUrl: './rt-confirm-popover.component.html',\n styleUrl: './rt-confirm-popover.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [RtButtonDirective, BlockDirective, ElemDirective],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtConfirmPopoverComponent {\n readonly #t_uiConfirm: Signal<string> = rtKitLabel('uiConfirm');\n readonly #t_uiCancel: Signal<string> = rtKitLabel('uiCancel');\n\n protected readonly confirmText: Signal<string> = computed((): string => this.confirmLabel() || this.#t_uiConfirm());\n protected readonly cancelText: Signal<string> = computed((): string => this.cancelLabel() || this.#t_uiCancel());\n\n public readonly message: InputSignal<string> = input<string>('');\n\n public readonly title: InputSignal<string | null> = input<string | null>(null);\n\n /** Пусто — берётся переведённая подпись по умолчанию */\n public readonly confirmLabel: InputSignal<string> = input<string>('');\n\n public readonly cancelLabel: InputSignal<string> = input<string>('');\n\n public readonly tone: InputSignal<IRtConfirmPopover.Tone> = input<IRtConfirmPopover.Tone>('danger');\n\n public readonly accepted: OutputEmitterRef<void> = output<void>();\n\n public readonly cancelled: OutputEmitterRef<void> = output<void>();\n\n protected onConfirm(): void {\n this.accepted.emit();\n }\n\n protected onCancel(): void {\n this.cancelled.emit();\n }\n}\n","<ng-container rtBlock=\"rt-confirm-popover\">\n @if (title()) {\n <p rtElem=\"title\">{{ title() }}</p>\n }\n\n <p rtElem=\"message\">{{ message() }}</p>\n\n <div rtElem=\"actions\">\n <button\n rtButton\n qa-dataid=\"confirm-cancel\"\n type=\"button\"\n theme=\"secondary\"\n appearance=\"outlined\"\n [label]=\"cancelText()\"\n [attr.aria-label]=\"cancelText()\"\n (click)=\"onCancel()\"></button>\n <button\n rtButton\n qa-dataid=\"confirm-accept\"\n type=\"button\"\n [theme]=\"tone()\"\n [label]=\"confirmText()\"\n [attr.aria-label]=\"confirmText()\"\n (click)=\"onConfirm()\"></button>\n </div>\n</ng-container>\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport {\n ConnectedPosition,\n FlexibleConnectedPositionStrategy,\n Overlay,\n OverlayConfig,\n OverlayRef,\n ScrollStrategyOptions,\n} from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport {\n booleanAttribute,\n ComponentRef,\n DestroyRef,\n Directive,\n ElementRef,\n inject,\n input,\n InputSignal,\n InputSignalWithTransform,\n OnDestroy,\n output,\n OutputEmitterRef,\n signal,\n Signal,\n WritableSignal,\n} from '@angular/core';\nimport { outputToObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { map, merge, Observable, Subject, switchMap } from 'rxjs';\n\nimport { setRtComponentInputs } from '@rt-tools/core';\n\nimport { carryThemeScope, materialPresetClassesOf } from '@rt-tools/ui-kit-v2/core';\nimport { RtConfirmPopoverComponent } from './rt-confirm-popover.component';\nimport { IRtConfirmPopover } from './rt-confirm-popover.model';\n\nconst VIEWPORT_MARGIN: number = 8;\n\n/**\n * Confirm-popover директива поверх CDK Overlay. Вешается на host-кнопку\n * (обычно `rt-icon-button` деструктивного действия). По клику показывает прямо\n * под кнопкой панель `rt-confirm-popover` с вопросом и кнопками\n * «Отмена» / подтверждение. Подтверждение → `(confirmed)` + закрытие; отмена,\n * outside-click, Escape → просто закрытие.\n *\n * Движок — CDK `flexibleConnectedTo` (end-выравнивание + flip), чтобы панель у\n * правого края aside'а раскрывалась влево и не резалась `overflow: hidden`.\n *\n * @example\n * ```html\n * <rt-icon-button\n * icon=\"ico-error\"\n * variant=\"danger\"\n * ariaLabel=\"Отклонить\"\n * tooltip=\"Отклонить\"\n * [rtConfirm]=\"'Отклонить заявку? Оператор получит уведомление.'\"\n * rtConfirmTitle=\"Отклонить заявку\"\n * rtConfirmLabel=\"Отклонить\"\n * (confirmed)=\"rejectTour()\" />\n * ```\n */\n@Directive({\n selector: '[rtConfirm]',\n exportAs: 'rtConfirm',\n host: {\n '(click)': 'onHostClick()',\n },\n})\nexport class RtConfirmDirective implements OnDestroy {\n readonly #overlay: Overlay = inject(Overlay);\n readonly #elementRef: ElementRef<HTMLElement> = inject<ElementRef<HTMLElement>>(ElementRef);\n readonly #scrollStrategies: ScrollStrategyOptions = inject(ScrollStrategyOptions);\n readonly #destroyRef: DestroyRef = inject(DestroyRef);\n\n readonly #overlayCreatedSource: Subject<OverlayRef> = new Subject<OverlayRef>();\n readonly #panelAttachedSource: Subject<ComponentRef<RtConfirmPopoverComponent>> = new Subject<\n ComponentRef<RtConfirmPopoverComponent>\n >();\n\n #overlayRef: OverlayRef | null = null;\n #panelRef: ComponentRef<RtConfirmPopoverComponent> | null = null;\n\n protected readonly isOpenState: WritableSignal<boolean> = signal<boolean>(false);\n\n public readonly message: InputSignal<string> = input<string>('', { alias: 'rtConfirm' });\n\n public readonly title: InputSignal<string | null> = input<string | null>(null, {\n alias: 'rtConfirmTitle',\n });\n\n /** Пусто — панель подставит переведённое умолчание */\n public readonly label: InputSignal<string> = input<string>('', {\n alias: 'rtConfirmLabel',\n });\n\n public readonly cancelLabel: InputSignal<string> = input<string>('', {\n alias: 'rtConfirmCancelLabel',\n });\n\n public readonly tone: InputSignal<IRtConfirmPopover.Tone> = input<IRtConfirmPopover.Tone>('danger', { alias: 'rtConfirmTone' });\n\n public readonly disabled: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n alias: 'rtConfirmDisabled',\n transform: booleanAttribute,\n });\n\n public readonly confirmed: OutputEmitterRef<void> = output<void>();\n\n public readonly isOpen: Signal<boolean> = this.isOpenState.asReadonly();\n\n constructor() {\n // Per-attach подписки на outputs панели (accepted / cancelled) живут в\n // одном конструкторном стриме: open() эмитит свежий ComponentRef,\n // switchMap переключается на его outputs (предыдущая панель к этому\n // моменту уже detach'нута — outputs комплитятся при destroy componentRef).\n // Бэкстоп takeUntilDestroyed — на жизнь директивы.\n this.#panelAttachedSource\n .pipe(\n switchMap((panelRef: ComponentRef<RtConfirmPopoverComponent>): Observable<() => void> =>\n merge(\n outputToObservable(panelRef.instance.accepted).pipe(\n map((): (() => void) => (): void => {\n this.confirmed.emit();\n this.close();\n })\n ),\n outputToObservable(panelRef.instance.cancelled).pipe(map((): (() => void) => (): void => this.close()))\n )\n ),\n takeUntilDestroyed(this.#destroyRef)\n )\n .subscribe((handleCloseIntent: () => void): void => handleCloseIntent());\n\n // Outside-click / ESC подписки на единожды создаваемый overlay:\n // #ensureOverlay эмитит OverlayRef после создания (ровно один раз за\n // жизнь директивы), стрим живёт до destroy директивы.\n this.#overlayCreatedSource\n .pipe(\n switchMap((overlayRef: OverlayRef): Observable<() => void> =>\n merge(\n overlayRef.outsidePointerEvents().pipe(\n map((event: MouseEvent): (() => void) => (): void => {\n // Клик по host обрабатывает onHostClick (toggle) — не закрываем\n // здесь, иначе двойной toggle.\n if (this.#elementRef.nativeElement.contains(event.target as Node)) {\n return;\n }\n this.close();\n })\n ),\n overlayRef.keydownEvents().pipe(\n map((event: KeyboardEvent): (() => void) => (): void => {\n if (event.key === 'Escape') {\n event.preventDefault();\n this.close();\n }\n })\n )\n )\n ),\n takeUntilDestroyed(this.#destroyRef)\n )\n .subscribe((handleCloseIntent: () => void): void => handleCloseIntent());\n }\n\n public ngOnDestroy(): void {\n this.#disposeOverlay();\n }\n\n public open(): void {\n if (this.disabled() || this.isOpenState() || this.message().trim() === '') {\n return;\n }\n const overlayRef: OverlayRef = this.#ensureOverlay();\n // Коробка переживает закрытие, а кусок темы вокруг host'а мог смениться — переносим на каждом открытии.\n carryThemeScope(overlayRef.overlayElement, this.#elementRef.nativeElement);\n const portal: ComponentPortal<RtConfirmPopoverComponent> = new ComponentPortal(RtConfirmPopoverComponent);\n this.#panelRef = overlayRef.attach(portal);\n // Одним набором, а не пятью строками с именами: имя, написанное строкой, не проверяет\n // ничто — опечатка собирается и падает на подъёме сообщением о входе, которого нет.\n setRtComponentInputs(this.#panelRef, {\n message: this.message(),\n title: this.title(),\n confirmLabel: this.label(),\n cancelLabel: this.cancelLabel(),\n tone: this.tone(),\n });\n\n // Подписки на accepted/cancelled объявлены один раз в конструкторе —\n // здесь только эмит свежего ComponentRef (см. #panelAttachedSource-стрим).\n this.#panelAttachedSource.next(this.#panelRef);\n\n this.isOpenState.set(true);\n }\n\n public close(): void {\n if (!this.isOpenState()) {\n return;\n }\n this.#overlayRef?.detach();\n this.#panelRef = null;\n this.isOpenState.set(false);\n }\n\n protected onHostClick(): void {\n if (this.disabled()) {\n return;\n }\n if (this.isOpenState()) {\n this.close();\n } else {\n this.open();\n }\n }\n\n #ensureOverlay(): OverlayRef {\n if (this.#overlayRef !== null) {\n return this.#overlayRef;\n }\n const positions: ConnectedPosition[] = [\n {\n originX: 'end',\n originY: 'bottom',\n overlayX: 'end',\n overlayY: 'top',\n offsetY: 6,\n },\n {\n originX: 'end',\n originY: 'top',\n overlayX: 'end',\n overlayY: 'bottom',\n offsetY: -6,\n },\n ];\n const positionStrategy: FlexibleConnectedPositionStrategy = this.#overlay\n .position()\n .flexibleConnectedTo(this.#elementRef)\n .withPush(true)\n .withViewportMargin(VIEWPORT_MARGIN)\n .withFlexibleDimensions(false)\n .withPositions(positions);\n\n const config: OverlayConfig = new OverlayConfig({\n positionStrategy,\n scrollStrategy: this.#scrollStrategies.reposition(),\n hasBackdrop: false,\n panelClass: ['rt-confirm-popover-panel', ...materialPresetClassesOf(this.#elementRef.nativeElement)],\n });\n const overlayRef: OverlayRef = this.#overlay.create(config);\n\n // Outside-click / ESC подписки объявлены один раз в конструкторе —\n // здесь только эмит созданного OverlayRef (см. #overlayCreatedSource-стрим).\n this.#overlayCreatedSource.next(overlayRef);\n\n this.#overlayRef = overlayRef;\n return overlayRef;\n }\n\n #disposeOverlay(): void {\n this.#overlayRef?.dispose();\n this.#overlayRef = null;\n this.#panelRef = null;\n }\n}\n"],"mappings":"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"}
@@ -132,6 +132,8 @@ var RtCopyValueComponent = class RtCopyValueComponent {
132
132
  "disabled",
133
133
  "active",
134
134
  "expanded",
135
+ "ariaHaspopup",
136
+ "link",
135
137
  "indicator"
136
138
  ],
137
139
  outputs: ["clicked"]
@@ -1 +1 @@
1
- {"version":3,"file":"rt-tools-ui-kit-v2-copy-value.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/copy-value/rt-copy-value.component.ts","../../../projects/ui-kit-v2/src/lib/components/copy-value/rt-copy-value.component.html"],"sourcesContent":["import { Clipboard } from '@angular/cdk/clipboard';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n inject,\n input,\n InputSignal,\n InputSignalWithTransform,\n output,\n OutputEmitterRef,\n signal,\n Signal,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective } from '@rt-tools/core';\n\nimport { IRtIcon, rtKitLabel } from '@rt-tools/ui-kit-v2/core';\nimport { RtIconButtonComponent } from '@rt-tools/ui-kit-v2/icon-button';\n\nconst BEM_BLOCK: string = 'rt-copy-value';\n\n/** Сколько держать состояние «скопировано» перед сбросом иконки и подписи. */\nconst RESET_DELAY_MS: number = 2000;\n\n/**\n * Значение, которое человек переносит в другое место: номер обращения, ключ, идентификатор.\n * Подпись слева, значение на подложке и кнопка копирования с подсказкой. После нажатия иконка\n * на две секунды меняется на галочку, подпись — на «Copied».\n */\n@Component({\n selector: 'rt-copy-value',\n templateUrl: './rt-copy-value.component.html',\n styleUrl: './rt-copy-value.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // standalone components / directives\n BlockDirective,\n ElemDirective,\n RtIconButtonComponent,\n ],\n host: {\n class: BEM_BLOCK,\n '[class.rt-copy-value--wrap]': 'wrap()',\n },\n})\nexport class RtCopyValueComponent {\n readonly #clipboard: Clipboard = inject(Clipboard);\n\n #resetTimer: ReturnType<typeof setTimeout> | null = null;\n\n readonly #t_uiCopy: Signal<string> = rtKitLabel('uiCopy');\n readonly #t_uiCopied: Signal<string> = rtKitLabel('uiCopied');\n\n protected readonly copied: WritableSignal<boolean> = signal(false);\n\n protected readonly iconName: Signal<IRtIcon.Name> = computed((): IRtIcon.Name => (this.copied() ? 'check' : 'copy'));\n\n protected readonly actionLabel: Signal<string> = computed((): string =>\n this.copied() ? this.#t_uiCopied() : this.copyLabel() || this.#t_uiCopy()\n );\n\n /** Что уходит в буфер и что показано на подложке. */\n public readonly value: InputSignal<string> = input.required<string>();\n\n /** Подпись слева от значения; пусто — не рисуется. */\n public readonly label: InputSignal<string> = input<string>('');\n\n /** Подсказка и имя кнопки в покое; пусто — переведённое «Copy». */\n public readonly copyLabel: InputSignal<string> = input<string>('');\n\n /**\n * Значение переносится по строкам и прокручивается в своей высоте, а не режется многоточием:\n * так копируют текст ошибки или журнал, который читают целиком.\n */\n public readonly wrap: InputSignalWithTransform<boolean, unknown> = input(false, { transform: booleanAttribute });\n\n /** Значение ушло в буфер. */\n public readonly copiedValue: OutputEmitterRef<string> = output<string>();\n\n constructor() {\n inject(DestroyRef).onDestroy((): void => this.#clearTimer());\n }\n\n protected onCopy(): void {\n const value: string = this.value();\n\n this.#clipboard.copy(value);\n this.copied.set(true);\n this.copiedValue.emit(value);\n\n this.#clearTimer();\n this.#resetTimer = setTimeout((): void => this.copied.set(false), RESET_DELAY_MS);\n }\n\n #clearTimer(): void {\n if (this.#resetTimer !== null) {\n clearTimeout(this.#resetTimer);\n this.#resetTimer = null;\n }\n }\n}\n","<ng-container rtBlock=\"rt-copy-value\">\n @if (label()) {\n <span rtElem=\"label\" qa-dataid=\"copy-value-label\">{{ label() }}</span>\n }\n <span rtElem=\"value\" qa-dataid=\"copy-value-value\">{{ value() }}</span>\n <rt-icon-button\n rtElem=\"button\"\n qa-dataid=\"copy-value-button\"\n size=\"sm\"\n [icon]=\"iconName()\"\n [ariaLabel]=\"actionLabel()\"\n [tooltip]=\"actionLabel()\"\n (clicked)=\"onCopy()\" />\n</ng-container>\n"],"mappings":"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"}
1
+ {"version":3,"file":"rt-tools-ui-kit-v2-copy-value.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/copy-value/rt-copy-value.component.ts","../../../projects/ui-kit-v2/src/lib/components/copy-value/rt-copy-value.component.html"],"sourcesContent":["import { Clipboard } from '@angular/cdk/clipboard';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n inject,\n input,\n InputSignal,\n InputSignalWithTransform,\n output,\n OutputEmitterRef,\n signal,\n Signal,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective } from '@rt-tools/core';\n\nimport { IRtIcon, rtKitLabel } from '@rt-tools/ui-kit-v2/core';\nimport { RtIconButtonComponent } from '@rt-tools/ui-kit-v2/icon-button';\n\nconst BEM_BLOCK: string = 'rt-copy-value';\n\n/** Сколько держать состояние «скопировано» перед сбросом иконки и подписи. */\nconst RESET_DELAY_MS: number = 2000;\n\n/**\n * Значение, которое человек переносит в другое место: номер обращения, ключ, идентификатор.\n * Подпись слева, значение на подложке и кнопка копирования с подсказкой. После нажатия иконка\n * на две секунды меняется на галочку, подпись — на «Copied».\n */\n@Component({\n selector: 'rt-copy-value',\n templateUrl: './rt-copy-value.component.html',\n styleUrl: './rt-copy-value.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // standalone components / directives\n BlockDirective,\n ElemDirective,\n RtIconButtonComponent,\n ],\n host: {\n class: BEM_BLOCK,\n '[class.rt-copy-value--wrap]': 'wrap()',\n },\n})\nexport class RtCopyValueComponent {\n readonly #clipboard: Clipboard = inject(Clipboard);\n\n #resetTimer: ReturnType<typeof setTimeout> | null = null;\n\n readonly #t_uiCopy: Signal<string> = rtKitLabel('uiCopy');\n readonly #t_uiCopied: Signal<string> = rtKitLabel('uiCopied');\n\n protected readonly copied: WritableSignal<boolean> = signal(false);\n\n protected readonly iconName: Signal<IRtIcon.Name> = computed((): IRtIcon.Name => (this.copied() ? 'check' : 'copy'));\n\n protected readonly actionLabel: Signal<string> = computed((): string =>\n this.copied() ? this.#t_uiCopied() : this.copyLabel() || this.#t_uiCopy()\n );\n\n /** Что уходит в буфер и что показано на подложке. */\n public readonly value: InputSignal<string> = input.required<string>();\n\n /** Подпись слева от значения; пусто — не рисуется. */\n public readonly label: InputSignal<string> = input<string>('');\n\n /** Подсказка и имя кнопки в покое; пусто — переведённое «Copy». */\n public readonly copyLabel: InputSignal<string> = input<string>('');\n\n /**\n * Значение переносится по строкам и прокручивается в своей высоте, а не режется многоточием:\n * так копируют текст ошибки или журнал, который читают целиком.\n */\n public readonly wrap: InputSignalWithTransform<boolean, unknown> = input(false, { transform: booleanAttribute });\n\n /** Значение ушло в буфер. */\n public readonly copiedValue: OutputEmitterRef<string> = output<string>();\n\n constructor() {\n inject(DestroyRef).onDestroy((): void => this.#clearTimer());\n }\n\n protected onCopy(): void {\n const value: string = this.value();\n\n this.#clipboard.copy(value);\n this.copied.set(true);\n this.copiedValue.emit(value);\n\n this.#clearTimer();\n this.#resetTimer = setTimeout((): void => this.copied.set(false), RESET_DELAY_MS);\n }\n\n #clearTimer(): void {\n if (this.#resetTimer !== null) {\n clearTimeout(this.#resetTimer);\n this.#resetTimer = null;\n }\n }\n}\n","<ng-container rtBlock=\"rt-copy-value\">\n @if (label()) {\n <span rtElem=\"label\" qa-dataid=\"copy-value-label\">{{ label() }}</span>\n }\n <span rtElem=\"value\" qa-dataid=\"copy-value-value\">{{ value() }}</span>\n <rt-icon-button\n rtElem=\"button\"\n qa-dataid=\"copy-value-button\"\n size=\"sm\"\n [icon]=\"iconName()\"\n [ariaLabel]=\"actionLabel()\"\n [tooltip]=\"actionLabel()\"\n (clicked)=\"onCopy()\" />\n</ng-container>\n"],"mappings":"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"}
@@ -641,6 +641,8 @@ function rtTreeToggle(open, value) {
641
641
  }
642
642
  const RT_NARROW_WIDTH = 1080;
643
643
  const NARROW_VIEWPORT_QUERY = `(max-width: ${RT_NARROW_WIDTH}px)`;
644
+ const RT_PHONE_WIDTH = 480;
645
+ const PHONE_VIEWPORT_QUERY = `(max-width: 480px)`;
644
646
  function rtNarrowByWidth(placeWidth, viewportNarrow) {
645
647
  return placeWidth === null ? viewportNarrow : placeWidth <= RT_NARROW_WIDTH;
646
648
  }
@@ -655,6 +657,7 @@ var BreakpointsService = class BreakpointsService {
655
657
  this.tablet = toSignal(this.#match([Breakpoints.TabletPortrait, Breakpoints.TabletLandscape]), { initialValue: false });
656
658
  this.desktop = toSignal(this.#match([Breakpoints.WebPortrait, Breakpoints.WebLandscape]), { initialValue: true });
657
659
  this.viewportNarrow = toSignal(this.#match([NARROW_VIEWPORT_QUERY]), { initialValue: false });
660
+ this.phone = toSignal(this.#match([PHONE_VIEWPORT_QUERY]), { initialValue: false });
658
661
  this.narrow = computed(() => rtNarrowByWidth(this.#placeWidth(), this.viewportNarrow()), ...ngDevMode ? [{ debugName: "narrow" }] : /* istanbul ignore next */ []);
659
662
  }
660
663
  #observer;
@@ -2828,6 +2831,6 @@ const iconsName = [
2828
2831
  "window-maximize",
2829
2832
  "window-minimize"
2830
2833
  ];
2831
- export { BreakpointsService, ERtDataTableCellColor, ERtDataTableColumnType, ERtDataTableFilterType, ERtMarkdownBlock, ERtMarkdownInline, ERtStorageKeys, MessageBus, NotificationBus, NotificationRef, RT_CONSUMER_HANDLE_NAMES, RT_DATA_TABLE_PRESET_FROM_HOST, RT_DESIGN_TOKEN_NAMES, RT_KIT_CONFIG, RT_KIT_LABELS, RT_KIT_LABELS_EN, RT_KIT_LOCALE, RT_KIT_TRANSLATOR, RT_MATERIAL_PRESET_CLASS, RT_MATERIAL_PRESET_SELECTOR, RT_NARROW_WIDTH, RT_PRESET_MATERIAL_CLASS, RT_RADIUS_DEFAULT, RT_RADIUS_STEPS, RT_THEME_SCOPE_ATTRIBUTE, RtDayStampPipe, RtInfiniteScrollDirective, RtKitLabelPipe, RtOptionList, RtThemeScopeDirective, SEARCH_DEBOUNCE_MS, ThemeService, breakNode, carryThemeScope, carryThemeScopeOfFocus, coerceQuillDeltaOutput, fileNameFromUrl, formatFileSize, iconsName, markdownToPlainText, materialPresetClassesOf, materialPresetClassesOfFocus, normalizeQuillDelta, parseInline, parseMarkdown, provideRtKit, provideRtKitLabels, rtKitDefault, rtKitLabel, rtMatchParts, rtNarrowByWidth, rtScrollActiveOptionIntoView, rtSearchFold, rtSearchMatches, rtSearchWords, rtTreeBranchState, rtTreeFind, rtTreeIsTree, rtTreeLeaves, rtTreeOpenFor, rtTreeRows, rtTreeSideKey, rtTreeToggle, searchDebounce, themeScopeOf, themeScopeOfFocus };
2834
+ export { BreakpointsService, ERtDataTableCellColor, ERtDataTableColumnType, ERtDataTableFilterType, ERtMarkdownBlock, ERtMarkdownInline, ERtStorageKeys, MessageBus, NotificationBus, NotificationRef, RT_CONSUMER_HANDLE_NAMES, RT_DATA_TABLE_PRESET_FROM_HOST, RT_DESIGN_TOKEN_NAMES, RT_KIT_CONFIG, RT_KIT_LABELS, RT_KIT_LABELS_EN, RT_KIT_LOCALE, RT_KIT_TRANSLATOR, RT_MATERIAL_PRESET_CLASS, RT_MATERIAL_PRESET_SELECTOR, RT_NARROW_WIDTH, RT_PHONE_WIDTH, RT_PRESET_MATERIAL_CLASS, RT_RADIUS_DEFAULT, RT_RADIUS_STEPS, RT_THEME_SCOPE_ATTRIBUTE, RtDayStampPipe, RtInfiniteScrollDirective, RtKitLabelPipe, RtOptionList, RtThemeScopeDirective, SEARCH_DEBOUNCE_MS, ThemeService, breakNode, carryThemeScope, carryThemeScopeOfFocus, coerceQuillDeltaOutput, fileNameFromUrl, formatFileSize, iconsName, markdownToPlainText, materialPresetClassesOf, materialPresetClassesOfFocus, normalizeQuillDelta, parseInline, parseMarkdown, provideRtKit, provideRtKitLabels, rtKitDefault, rtKitLabel, rtMatchParts, rtNarrowByWidth, rtScrollActiveOptionIntoView, rtSearchFold, rtSearchMatches, rtSearchWords, rtTreeBranchState, rtTreeFind, rtTreeIsTree, rtTreeLeaves, rtTreeOpenFor, rtTreeRows, rtTreeSideKey, rtTreeToggle, searchDebounce, themeScopeOf, themeScopeOfFocus };
2832
2835
 
2833
2836
  //# sourceMappingURL=rt-tools-ui-kit-v2-core.mjs.map