@rt-tools/ui-kit-v2 0.35.0 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/fesm2022/rt-tools-ui-kit-v2-action-bar.mjs +1 -0
  2. package/fesm2022/rt-tools-ui-kit-v2-action-bar.mjs.map +1 -1
  3. package/fesm2022/rt-tools-ui-kit-v2-ai-run-status.mjs +2 -1
  4. package/fesm2022/rt-tools-ui-kit-v2-ai-run-status.mjs.map +1 -1
  5. package/fesm2022/rt-tools-ui-kit-v2-autocomplete.mjs +1 -0
  6. package/fesm2022/rt-tools-ui-kit-v2-autocomplete.mjs.map +1 -1
  7. package/fesm2022/rt-tools-ui-kit-v2-breadcrumbs.mjs +2 -1
  8. package/fesm2022/rt-tools-ui-kit-v2-breadcrumbs.mjs.map +1 -1
  9. package/fesm2022/rt-tools-ui-kit-v2-color-palette.mjs +1 -0
  10. package/fesm2022/rt-tools-ui-kit-v2-color-palette.mjs.map +1 -1
  11. package/fesm2022/rt-tools-ui-kit-v2-data-table.mjs +4 -2
  12. package/fesm2022/rt-tools-ui-kit-v2-data-table.mjs.map +1 -1
  13. package/fesm2022/rt-tools-ui-kit-v2-date-picker.mjs +1 -0
  14. package/fesm2022/rt-tools-ui-kit-v2-date-picker.mjs.map +1 -1
  15. package/fesm2022/rt-tools-ui-kit-v2-date-range.mjs +1 -0
  16. package/fesm2022/rt-tools-ui-kit-v2-date-range.mjs.map +1 -1
  17. package/fesm2022/rt-tools-ui-kit-v2-draggable-tree.mjs +2 -1
  18. package/fesm2022/rt-tools-ui-kit-v2-draggable-tree.mjs.map +1 -1
  19. package/fesm2022/rt-tools-ui-kit-v2-dynamic-selector.mjs +5 -2
  20. package/fesm2022/rt-tools-ui-kit-v2-dynamic-selector.mjs.map +1 -1
  21. package/fesm2022/rt-tools-ui-kit-v2-field.mjs +1 -0
  22. package/fesm2022/rt-tools-ui-kit-v2-field.mjs.map +1 -1
  23. package/fesm2022/rt-tools-ui-kit-v2-file-card.mjs +2 -1
  24. package/fesm2022/rt-tools-ui-kit-v2-file-card.mjs.map +1 -1
  25. package/fesm2022/rt-tools-ui-kit-v2-hybrid-tree-selector.mjs +2 -1
  26. package/fesm2022/rt-tools-ui-kit-v2-hybrid-tree-selector.mjs.map +1 -1
  27. package/fesm2022/rt-tools-ui-kit-v2-hybrid-tree.mjs +2 -1
  28. package/fesm2022/rt-tools-ui-kit-v2-hybrid-tree.mjs.map +1 -1
  29. package/fesm2022/rt-tools-ui-kit-v2-icon-button.mjs +2 -1
  30. package/fesm2022/rt-tools-ui-kit-v2-icon-button.mjs.map +1 -1
  31. package/fesm2022/rt-tools-ui-kit-v2-image-upload.mjs +2 -1
  32. package/fesm2022/rt-tools-ui-kit-v2-image-upload.mjs.map +1 -1
  33. package/fesm2022/rt-tools-ui-kit-v2-inline-edit.mjs +2 -1
  34. package/fesm2022/rt-tools-ui-kit-v2-inline-edit.mjs.map +1 -1
  35. package/fesm2022/rt-tools-ui-kit-v2-multiselect.mjs +1 -0
  36. package/fesm2022/rt-tools-ui-kit-v2-multiselect.mjs.map +1 -1
  37. package/fesm2022/rt-tools-ui-kit-v2-page-header.mjs +10 -6
  38. package/fesm2022/rt-tools-ui-kit-v2-page-header.mjs.map +1 -1
  39. package/fesm2022/rt-tools-ui-kit-v2-popover.mjs +22 -2
  40. package/fesm2022/rt-tools-ui-kit-v2-popover.mjs.map +1 -1
  41. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs +36 -5
  42. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs.map +1 -1
  43. package/fesm2022/rt-tools-ui-kit-v2-scroll-area.mjs +2 -1
  44. package/fesm2022/rt-tools-ui-kit-v2-scroll-area.mjs.map +1 -1
  45. package/fesm2022/rt-tools-ui-kit-v2-select.mjs +1 -0
  46. package/fesm2022/rt-tools-ui-kit-v2-select.mjs.map +1 -1
  47. package/fesm2022/rt-tools-ui-kit-v2-side-menu.mjs +4 -2
  48. package/fesm2022/rt-tools-ui-kit-v2-side-menu.mjs.map +1 -1
  49. package/fesm2022/rt-tools-ui-kit-v2-speed-menu.mjs +3 -1
  50. package/fesm2022/rt-tools-ui-kit-v2-speed-menu.mjs.map +1 -1
  51. package/fesm2022/rt-tools-ui-kit-v2-split-button.mjs +1 -0
  52. package/fesm2022/rt-tools-ui-kit-v2-split-button.mjs.map +1 -1
  53. package/fesm2022/rt-tools-ui-kit-v2-table.mjs +3 -1
  54. package/fesm2022/rt-tools-ui-kit-v2-table.mjs.map +1 -1
  55. package/fesm2022/rt-tools-ui-kit-v2-tabs.mjs +2 -1
  56. package/fesm2022/rt-tools-ui-kit-v2-tabs.mjs.map +1 -1
  57. package/fesm2022/rt-tools-ui-kit-v2-tag.mjs +2 -1
  58. package/fesm2022/rt-tools-ui-kit-v2-tag.mjs.map +1 -1
  59. package/fesm2022/rt-tools-ui-kit-v2-thread-list.mjs +53 -5
  60. package/fesm2022/rt-tools-ui-kit-v2-thread-list.mjs.map +1 -1
  61. package/fesm2022/rt-tools-ui-kit-v2-toggle-button-group.mjs +2 -1
  62. package/fesm2022/rt-tools-ui-kit-v2-toggle-button-group.mjs.map +1 -1
  63. package/fesm2022/rt-tools-ui-kit-v2-tooltip.mjs +37 -0
  64. package/fesm2022/rt-tools-ui-kit-v2-tooltip.mjs.map +1 -1
  65. package/fesm2022/rt-tools-ui-kit-v2-tree-selector.mjs +2 -1
  66. package/fesm2022/rt-tools-ui-kit-v2-tree-selector.mjs.map +1 -1
  67. package/fesm2022/rt-tools-ui-kit-v2-tree.mjs +2 -1
  68. package/fesm2022/rt-tools-ui-kit-v2-tree.mjs.map +1 -1
  69. package/fesm2022/rt-tools-ui-kit-v2-usage-ring.mjs +4 -3
  70. package/fesm2022/rt-tools-ui-kit-v2-usage-ring.mjs.map +1 -1
  71. package/package.json +1 -1
  72. package/src/lib/components/page-header/rt-page-header-mobile.scss +6 -0
  73. package/src/lib/components/popover/CONTEXT.md +4 -0
  74. package/src/lib/components/thread-list/rt-thread-list.component.scss +7 -0
  75. package/src/lib/components/tooltip/CONTEXT.md +4 -0
  76. package/src/rich-editor/lib/components/chat/rt-chat.component.scss +31 -1
  77. package/types/rt-tools-ui-kit-v2-popover.d.ts +11 -0
  78. package/types/rt-tools-ui-kit-v2-rich-editor.d.ts +7 -0
  79. package/types/rt-tools-ui-kit-v2-thread-list.d.ts +7 -1
  80. package/types/rt-tools-ui-kit-v2-tooltip.d.ts +12 -0
@@ -1 +1 @@
1
- {"version":3,"file":"rt-tools-ui-kit-v2-icon-button.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/icon-button/rt-icon-button.component.ts","../../../projects/ui-kit-v2/src/lib/components/icon-button/rt-icon-button.component.html"],"sourcesContent":["import { CdkMonitorFocus } from '@angular/cdk/a11y';\nimport { BooleanInput, NumberInput } from '@angular/cdk/coercion';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n ElementRef,\n input,\n InputSignal,\n InputSignalWithTransform,\n numberAttribute,\n output,\n OutputEmitterRef,\n Signal,\n viewChild,\n ViewEncapsulation,\n} from '@angular/core';\nimport { RouterLink } from '@angular/router';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { RtIconComponent } from '@rt-tools/ui-kit-v2/icon';\nimport { IRtIcon, IRtKitConfig, rtKitDefault } from '@rt-tools/ui-kit-v2/core';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\nimport { RtRippleDirective } from '@rt-tools/ui-kit-v2/ripple';\nimport { RtTooltipDirective } from '@rt-tools/ui-kit-v2/tooltip';\nimport { IRtIconButton } from './rt-icon-button.model';\n\nconst BEM_BLOCK: string = 'rt-icon-button';\n\n/**\n * Универсальная icon-only кнопка кита.\n *\n * Рендерит свой собственный `<button type=\"...\">` внутри template (НЕ host-button), а с входом\n * `link` — ссылку `<a>` с тем же видом: её можно открыть в новой вкладке, и скринридер называет её ссылкой.\n * Все цвета и размеры — через семантические `--rt-*` токены; геометрия квадрата\n * берётся из `--rt-icon-button-size`, а без него — из шага `size`. Свойство, заданное на теге\n * `<rt-icon-button>` или выше, доходит до кнопки; так же и `--rt-icon-button-bg`.\n *\n * Loading state — заменяет иконку на `<rt-icon name=\"spinner\">` и блокирует\n * клики (`button[disabled]`). Active state управляет `aria-pressed` (для toggle-кнопок).\n * Indicator — небольшой dot top-right через BEM-элемент `__indicator`.\n *\n * BEM-разметка — через `rtBlock=\"rt-icon-button\"` + `[rtMod]` объект; камелкейс\n * модификаторов автоматически конвертируется директивой в kebab-case\n * (`hasIndicator` → `rt-icon-button--has-indicator`).\n */\n@Component({\n selector: 'rt-icon-button',\n templateUrl: './rt-icon-button.component.html',\n styleUrls: ['./rt-icon-button.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // standalone components / directives\n NgTemplateOutlet,\n RouterLink,\n RtIconComponent,\n RtRippleDirective,\n CdkMonitorFocus,\n RtTooltipDirective,\n BlockDirective,\n ElemDirective,\n ModDirective,\n ],\n hostDirectives: [{ directive: RtRadiusDirective, inputs: ['radius'] }],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtIconButtonComponent {\n /**\n * Размер дочерней `<rt-icon>`. По умолчанию маппится 1-к-1 от размера кнопки,\n * но потребитель может задать свой: у крупной кнопки-действия (плавающая\n * кнопка чата) иконка во весь диаметр выглядит тяжеловесно, а сама кнопка\n * должна остаться большой — в неё целятся пальцем.\n */\n protected readonly resolvedIconSize: Signal<IRtIcon.Size> = computed((): IRtIcon.Size => {\n const map: Readonly<Record<IRtIconButton.Size, IRtIcon.Size>> = {\n '2xs': 'sm',\n xs: 'sm',\n sm: 'sm',\n md: 'md',\n lg: 'lg',\n xl: 'xl',\n '2xl': '2xl',\n };\n return this.iconSize() ?? map[this.size()];\n });\n\n protected readonly buttonEl: Signal<ElementRef<HTMLButtonElement> | undefined> = viewChild<ElementRef<HTMLButtonElement>>('buttonEl');\n\n protected readonly linkEl: Signal<ElementRef<HTMLAnchorElement> | undefined> = viewChild<ElementRef<HTMLAnchorElement>>('linkEl');\n\n /** Компонент рисует ссылку: задан `link`. */\n protected readonly isLink: Signal<boolean> = computed((): boolean => this.link() !== null);\n\n /** Адрес ссылки: у недоступной или загружающейся его нет, и ссылка никуда не ведёт. */\n protected readonly linkTarget: Signal<RouterLink['routerLink']> = computed((): RouterLink['routerLink'] =>\n this.isDisabled() ? null : this.link()\n );\n\n /** Недоступная ссылка выпадает из порядка Tab, как отключённая кнопка. */\n protected readonly linkTabIndex: Signal<number> = computed((): number => (this.isDisabled() ? -1 : this.tabIndex()));\n\n /** Кнопка отключена, если установлен disabled ИЛИ loading. */\n protected readonly isDisabled: Signal<boolean> = computed((): boolean => this.disabled() || this.loading());\n\n /**\n * BEM-модификаторы для `[rtMod]`. Собираем в .ts (а не в шаблоне), потому что\n * Angular template-parser не поддерживает computed property keys в inline-объектах.\n * camelCase ключи `hasIndicator` директива автоматически конвертирует в `has-indicator`.\n */\n protected readonly bemMods: Signal<Record<string, boolean>> = computed((): Record<string, boolean> => ({\n [this.variant()]: true,\n [this.size()]: true,\n loading: this.loading(),\n active: this.active(),\n hasIndicator: this.indicator(),\n }));\n\n /**\n * Имя иконки в наборе кита. Нужно оно или `glyph`; когда переданы оба, побеждает имя. Нет ни\n * того ни другого — значок кит не рисует, и кнопка показывает вложенное содержимое: свой\n * рисунок приложения встаёт в кнопку с её размером, формой и состояниями.\n */\n public readonly icon: InputSignal<IRtIcon.Name | null> = input<IRtIcon.Name | null>(null);\n\n /** Имя Material вместо имени кита — рисуется так же, как вход `glyph` у `rt-icon`. */\n public readonly glyph: InputSignal<string | null> = input<string | null>(null);\n\n /** Доступное имя для screen-reader'ов — обязательно (icon-only кнопка). */\n public readonly ariaLabel: InputSignal<string> = input.required<string>();\n\n /** Семантическая палитра. */\n public readonly variant: InputSignal<IRtIconButton.Variant> = input<IRtIconButton.Variant>('ghost');\n\n /**\n * Цвет самой иконки. Default `current` — иконка наследует цвет текста кнопки\n * (поведение по умолчанию). Явное значение нужно, когда иконка должна\n * отличаться от текста кнопки — например крестик-очистка внутри поля,\n * который должен совпадать по цвету с иконками-аффордансами самого поля.\n */\n public readonly iconColor: InputSignal<IRtIcon.Color> = input<IRtIcon.Color>('current');\n\n /**\n * Залитый рисунок значка вместо контурного — как `fill` у `rt-icon`. Рисует его материальный\n * набор; значок своего набора один и от признака не меняется.\n */\n public readonly iconFill: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Размер квадрата. */\n public readonly size: InputSignal<IRtIconButton.Size> = input<IRtIconButton.Size>('md');\n\n /** Размер иконки; пусто — берётся от размера кнопки. */\n public readonly iconSize: InputSignal<IRtIcon.Size | null> = input<IRtIcon.Size | null>(null);\n\n /** HTML-type для нативного `<button>`. */\n public readonly type: InputSignal<IRtIconButton.Type> = input<IRtIconButton.Type>('button');\n\n /**\n * Текст styled-tooltip'а (`rtTooltip`), показывается на hover/focus. Пустая\n * строка → tooltip выключен. Для icon-only кнопок обычно дублирует `ariaLabel`.\n */\n public readonly tooltip: InputSignal<string> = input<string>('');\n\n /**\n * Прячет ли клик открытую подсказку (`rtTooltipHideOnClick`). `false` — у переключателя:\n * подсказка остаётся и показывает новое состояние на месте. Умолчание — из настроек кита\n * `components.tooltip.hideOnClick`, как у самой подсказки: иначе своё `true` кнопки перебивало бы их.\n */\n public readonly tooltipHideOnClick: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(\n rtKitDefault('tooltip', (it: IRtKitConfig.Tooltip): boolean | undefined => it.hideOnClick, true),\n {\n transform: booleanAttribute,\n }\n );\n\n /**\n * Tabindex внутренней `<button>`. Default `0` (в обычном таб-порядке).\n * Значение `-1` исключает кнопку из таб-навигации, оставляя клик мышью —\n * нужно для вспомогательных аффордансов вроде крестика-очистки внутри поля.\n */\n public readonly tabIndex: InputSignalWithTransform<number, NumberInput> = input<number, NumberInput>(0, { transform: numberAttribute });\n\n /** Состояние загрузки: показывает spinner вместо иконки + disabled. */\n public readonly loading: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Нативное отключение кнопки. */\n public readonly disabled: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Toggle-состояние — превращается в `aria-pressed=\"true\"`. */\n public readonly active: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /**\n * Раскрыта ли панель, которую кнопка открывает, — превращается в `aria-expanded`. `null` —\n * кнопка ничего не раскрывает, и атрибута нет.\n */\n public readonly expanded: InputSignal<boolean | null> = input<boolean | null>(null);\n\n /**\n * Какую панель открывает кнопка — превращается в `aria-haspopup`: `'menu'` у кнопки, которая\n * раскрывает меню. `null` — атрибута нет.\n */\n public readonly ariaHaspopup: InputSignal<IRtIconButton.HasPopup | null> = input<IRtIconButton.HasPopup | null>(null);\n\n /**\n * Команды маршрута приложения, как у `routerLink`. Задан — компонент рисует ссылку `<a href>` с тем\n * же видом, подсказкой и рябью: Ctrl/Cmd-click, Shift-click, средняя кнопка и контекстное меню\n * браузера открывают её в новой вкладке или окне. `type`, `active` и `aria-pressed` у ссылки не\n * пишутся. `null` — обычная кнопка.\n */\n public readonly link: InputSignal<RouterLink['routerLink']> = input<RouterLink['routerLink']>(null);\n\n /** Бейдж-индикатор (dot top-right через BEM-модификатор). */\n public readonly indicator: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Эмиттит MouseEvent при клике (только когда не disabled и не loading). */\n public readonly clicked: OutputEmitterRef<MouseEvent> = output<MouseEvent>();\n\n /** Фокусирует кнопку или ссылку внутри — например, когда закрылось меню, которое она открыла. */\n public focus(options?: FocusOptions): void {\n (this.linkEl() ?? this.buttonEl())?.nativeElement.focus(options);\n }\n\n protected onClick(event: MouseEvent): void {\n if (this.isDisabled()) {\n // У недоступной ссылки нет адреса, но клик по `<a>` без `href` всё равно не должен уйти наружу.\n event.preventDefault();\n return;\n }\n this.clicked.emit(event);\n }\n}\n","<!-- Ссылка стоит перед кнопкой: в режиме ссылки поиск по `qa-dataid` находит её первой. -->\n@if (isLink()) {\n <a\n #linkEl\n rtBlock=\"rt-icon-button\"\n qa-dataid=\"icon-button-control\"\n rtRipple\n cdkMonitorElementFocus\n [routerLink]=\"linkTarget()\"\n [rippleDisabled]=\"isDisabled()\"\n [rtTooltip]=\"tooltip()\"\n [rtTooltipHideOnClick]=\"tooltipHideOnClick()\"\n [rtMod]=\"bemMods()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : null\"\n [attr.aria-expanded]=\"expanded()\"\n [attr.aria-haspopup]=\"ariaHaspopup()\"\n [attr.tabindex]=\"linkTabIndex()\"\n (click)=\"onClick($event)\">\n <ng-container *ngTemplateOutlet=\"content\" />\n </a>\n}\n\n<!-- Кнопка стоит в шаблоне без условия и появляется с первым проходом, как до входа `link`: в\n блоке `@if` она рождалась бы проходом позже, и родитель, который меряет соседей на первой\n проверке (автовысота поля сообщения), считал бы ряд без неё. У ссылки кнопка спрятана. -->\n<button\n #buttonEl\n rtBlock=\"rt-icon-button\"\n qa-dataid=\"icon-button-control\"\n rtRipple\n cdkMonitorElementFocus\n [hidden]=\"isLink()\"\n [rippleDisabled]=\"isDisabled() || loading()\"\n [rtTooltip]=\"isLink() ? '' : tooltip()\"\n [rtTooltipHideOnClick]=\"tooltipHideOnClick()\"\n [rtMod]=\"bemMods()\"\n [type]=\"type()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-pressed]=\"active() ? 'true' : null\"\n [attr.aria-expanded]=\"expanded()\"\n [attr.aria-haspopup]=\"ariaHaspopup()\"\n [attr.tabindex]=\"tabIndex()\"\n (click)=\"onClick($event)\">\n @if (!isLink()) {\n <ng-container *ngTemplateOutlet=\"content\" />\n }\n</button>\n\n<!-- Содержимое общее у кнопки и ссылки и рисуется один раз — в том, что видно. Шаблон берёт\n инжектор места объявления, поэтому `rtElem` внутри получает блок от `ng-container`. -->\n<ng-container rtBlock=\"rt-icon-button\">\n <ng-template #content>\n @if (loading()) {\n <rt-icon rtElem=\"spinner\" name=\"spinner\" color=\"current\" [size]=\"resolvedIconSize()\" />\n } @else if (icon() || glyph()) {\n <rt-icon\n rtElem=\"icon\"\n [color]=\"iconColor()\"\n [name]=\"icon()\"\n [glyph]=\"glyph()\"\n [size]=\"resolvedIconSize()\"\n [fill]=\"iconFill()\" />\n } @else {\n <span rtElem=\"content\" qa-dataid=\"icon-button-content\"><ng-content /></span>\n }\n @if (indicator()) {\n <span rtElem=\"indicator\" aria-hidden=\"true\"></span>\n }\n </ng-template>\n</ng-container>\n"],"mappings":"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"}
1
+ {"version":3,"file":"rt-tools-ui-kit-v2-icon-button.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/icon-button/rt-icon-button.component.ts","../../../projects/ui-kit-v2/src/lib/components/icon-button/rt-icon-button.component.html"],"sourcesContent":["import { CdkMonitorFocus } from '@angular/cdk/a11y';\nimport { BooleanInput, NumberInput } from '@angular/cdk/coercion';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n ElementRef,\n input,\n InputSignal,\n InputSignalWithTransform,\n numberAttribute,\n output,\n OutputEmitterRef,\n Signal,\n viewChild,\n ViewEncapsulation,\n} from '@angular/core';\nimport { RouterLink } from '@angular/router';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { RtIconComponent } from '@rt-tools/ui-kit-v2/icon';\nimport { IRtIcon, IRtKitConfig, rtKitDefault } from '@rt-tools/ui-kit-v2/core';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\nimport { RtRippleDirective } from '@rt-tools/ui-kit-v2/ripple';\nimport { RtTooltipDirective } from '@rt-tools/ui-kit-v2/tooltip';\nimport { IRtIconButton } from './rt-icon-button.model';\n\nconst BEM_BLOCK: string = 'rt-icon-button';\n\n/**\n * Универсальная icon-only кнопка кита.\n *\n * Рендерит свой собственный `<button type=\"...\">` внутри template (НЕ host-button), а с входом\n * `link` — ссылку `<a>` с тем же видом: её можно открыть в новой вкладке, и скринридер называет её ссылкой.\n * Все цвета и размеры — через семантические `--rt-*` токены; геометрия квадрата\n * берётся из `--rt-icon-button-size`, а без него — из шага `size`. Свойство, заданное на теге\n * `<rt-icon-button>` или выше, доходит до кнопки; так же и `--rt-icon-button-bg`.\n *\n * Loading state — заменяет иконку на `<rt-icon name=\"spinner\">` и блокирует\n * клики (`button[disabled]`). Active state управляет `aria-pressed` (для toggle-кнопок).\n * Indicator — небольшой dot top-right через BEM-элемент `__indicator`.\n *\n * BEM-разметка — через `rtBlock=\"rt-icon-button\"` + `[rtMod]` объект; камелкейс\n * модификаторов автоматически конвертируется директивой в kebab-case\n * (`hasIndicator` → `rt-icon-button--has-indicator`).\n */\n@Component({\n selector: 'rt-icon-button',\n templateUrl: './rt-icon-button.component.html',\n styleUrls: ['./rt-icon-button.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // standalone components / directives\n NgTemplateOutlet,\n RouterLink,\n RtIconComponent,\n RtRippleDirective,\n CdkMonitorFocus,\n RtTooltipDirective,\n BlockDirective,\n ElemDirective,\n ModDirective,\n ],\n hostDirectives: [{ directive: RtRadiusDirective, inputs: ['radius'] }],\n host: {\n class: BEM_BLOCK,\n },\n})\nexport class RtIconButtonComponent {\n /**\n * Размер дочерней `<rt-icon>`. По умолчанию маппится 1-к-1 от размера кнопки,\n * но потребитель может задать свой: у крупной кнопки-действия (плавающая\n * кнопка чата) иконка во весь диаметр выглядит тяжеловесно, а сама кнопка\n * должна остаться большой — в неё целятся пальцем.\n */\n protected readonly resolvedIconSize: Signal<IRtIcon.Size> = computed((): IRtIcon.Size => {\n const map: Readonly<Record<IRtIconButton.Size, IRtIcon.Size>> = {\n '2xs': 'sm',\n xs: 'sm',\n sm: 'sm',\n md: 'md',\n lg: 'lg',\n xl: 'xl',\n '2xl': '2xl',\n };\n return this.iconSize() ?? map[this.size()];\n });\n\n protected readonly buttonEl: Signal<ElementRef<HTMLButtonElement> | undefined> = viewChild<ElementRef<HTMLButtonElement>>('buttonEl');\n\n protected readonly linkEl: Signal<ElementRef<HTMLAnchorElement> | undefined> = viewChild<ElementRef<HTMLAnchorElement>>('linkEl');\n\n /** Компонент рисует ссылку: задан `link`. */\n protected readonly isLink: Signal<boolean> = computed((): boolean => this.link() !== null);\n\n /** Адрес ссылки: у недоступной или загружающейся его нет, и ссылка никуда не ведёт. */\n protected readonly linkTarget: Signal<RouterLink['routerLink']> = computed((): RouterLink['routerLink'] =>\n this.isDisabled() ? null : this.link()\n );\n\n /** Недоступная ссылка выпадает из порядка Tab, как отключённая кнопка. */\n protected readonly linkTabIndex: Signal<number> = computed((): number => (this.isDisabled() ? -1 : this.tabIndex()));\n\n /** Кнопка отключена, если установлен disabled ИЛИ loading. */\n protected readonly isDisabled: Signal<boolean> = computed((): boolean => this.disabled() || this.loading());\n\n /**\n * BEM-модификаторы для `[rtMod]`. Собираем в .ts (а не в шаблоне), потому что\n * Angular template-parser не поддерживает computed property keys в inline-объектах.\n * camelCase ключи `hasIndicator` директива автоматически конвертирует в `has-indicator`.\n */\n protected readonly bemMods: Signal<Record<string, boolean>> = computed((): Record<string, boolean> => ({\n [this.variant()]: true,\n [this.size()]: true,\n loading: this.loading(),\n active: this.active(),\n hasIndicator: this.indicator(),\n }));\n\n /**\n * Имя иконки в наборе кита. Нужно оно или `glyph`; когда переданы оба, побеждает имя. Нет ни\n * того ни другого — значок кит не рисует, и кнопка показывает вложенное содержимое: свой\n * рисунок приложения встаёт в кнопку с её размером, формой и состояниями.\n */\n public readonly icon: InputSignal<IRtIcon.Name | null> = input<IRtIcon.Name | null>(null);\n\n /** Имя Material вместо имени кита — рисуется так же, как вход `glyph` у `rt-icon`. */\n public readonly glyph: InputSignal<string | null> = input<string | null>(null);\n\n /** Доступное имя для screen-reader'ов — обязательно (icon-only кнопка). */\n public readonly ariaLabel: InputSignal<string> = input.required<string>();\n\n /** Семантическая палитра. */\n public readonly variant: InputSignal<IRtIconButton.Variant> = input<IRtIconButton.Variant>('ghost');\n\n /**\n * Цвет самой иконки. Default `current` — иконка наследует цвет текста кнопки\n * (поведение по умолчанию). Явное значение нужно, когда иконка должна\n * отличаться от текста кнопки — например крестик-очистка внутри поля,\n * который должен совпадать по цвету с иконками-аффордансами самого поля.\n */\n public readonly iconColor: InputSignal<IRtIcon.Color> = input<IRtIcon.Color>('current');\n\n /**\n * Залитый рисунок значка вместо контурного — как `fill` у `rt-icon`. Рисует его материальный\n * набор; значок своего набора один и от признака не меняется.\n */\n public readonly iconFill: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Размер квадрата. */\n public readonly size: InputSignal<IRtIconButton.Size> = input<IRtIconButton.Size>('md');\n\n /** Размер иконки; пусто — берётся от размера кнопки. */\n public readonly iconSize: InputSignal<IRtIcon.Size | null> = input<IRtIcon.Size | null>(null);\n\n /** HTML-type для нативного `<button>`. */\n public readonly type: InputSignal<IRtIconButton.Type> = input<IRtIconButton.Type>('button');\n\n /**\n * Текст styled-tooltip'а (`rtTooltip`), показывается на hover/focus. Пустая\n * строка → tooltip выключен. Для icon-only кнопок обычно дублирует `ariaLabel`.\n */\n public readonly tooltip: InputSignal<string> = input<string>('');\n\n /**\n * Прячет ли клик открытую подсказку (`rtTooltipHideOnClick`). `false` — у переключателя:\n * подсказка остаётся и показывает новое состояние на месте. Умолчание — из настроек кита\n * `components.tooltip.hideOnClick`, как у самой подсказки: иначе своё `true` кнопки перебивало бы их.\n */\n public readonly tooltipHideOnClick: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(\n rtKitDefault('tooltip', (it: IRtKitConfig.Tooltip): boolean | undefined => it.hideOnClick, true),\n {\n transform: booleanAttribute,\n }\n );\n\n /**\n * Tabindex внутренней `<button>`. Default `0` (в обычном таб-порядке).\n * Значение `-1` исключает кнопку из таб-навигации, оставляя клик мышью —\n * нужно для вспомогательных аффордансов вроде крестика-очистки внутри поля.\n */\n public readonly tabIndex: InputSignalWithTransform<number, NumberInput> = input<number, NumberInput>(0, { transform: numberAttribute });\n\n /** Состояние загрузки: показывает spinner вместо иконки + disabled. */\n public readonly loading: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Нативное отключение кнопки. */\n public readonly disabled: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Toggle-состояние — превращается в `aria-pressed=\"true\"`. */\n public readonly active: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /**\n * Раскрыта ли панель, которую кнопка открывает, — превращается в `aria-expanded`. `null` —\n * кнопка ничего не раскрывает, и атрибута нет.\n */\n public readonly expanded: InputSignal<boolean | null> = input<boolean | null>(null);\n\n /**\n * Какую панель открывает кнопка — превращается в `aria-haspopup`: `'menu'` у кнопки, которая\n * раскрывает меню. `null` — атрибута нет.\n */\n public readonly ariaHaspopup: InputSignal<IRtIconButton.HasPopup | null> = input<IRtIconButton.HasPopup | null>(null);\n\n /**\n * Команды маршрута приложения, как у `routerLink`. Задан — компонент рисует ссылку `<a href>` с тем\n * же видом, подсказкой и рябью: Ctrl/Cmd-click, Shift-click, средняя кнопка и контекстное меню\n * браузера открывают её в новой вкладке или окне. `type`, `active` и `aria-pressed` у ссылки не\n * пишутся. `null` — обычная кнопка.\n */\n public readonly link: InputSignal<RouterLink['routerLink']> = input<RouterLink['routerLink']>(null);\n\n /** Бейдж-индикатор (dot top-right через BEM-модификатор). */\n public readonly indicator: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Эмиттит MouseEvent при клике (только когда не disabled и не loading). */\n public readonly clicked: OutputEmitterRef<MouseEvent> = output<MouseEvent>();\n\n /** Фокусирует кнопку или ссылку внутри — например, когда закрылось меню, которое она открыла. */\n public focus(options?: FocusOptions): void {\n (this.linkEl() ?? this.buttonEl())?.nativeElement.focus(options);\n }\n\n protected onClick(event: MouseEvent): void {\n if (this.isDisabled()) {\n // У недоступной ссылки нет адреса, но клик по `<a>` без `href` всё равно не должен уйти наружу.\n event.preventDefault();\n return;\n }\n this.clicked.emit(event);\n }\n}\n","<!-- Ссылка стоит перед кнопкой: в режиме ссылки поиск по `qa-dataid` находит её первой. -->\n@if (isLink()) {\n <a\n #linkEl\n rtBlock=\"rt-icon-button\"\n qa-dataid=\"icon-button-control\"\n rtRipple\n cdkMonitorElementFocus\n [routerLink]=\"linkTarget()\"\n [rippleDisabled]=\"isDisabled()\"\n [rtTooltip]=\"tooltip()\"\n [rtTooltipHideOnClick]=\"tooltipHideOnClick()\"\n [rtMod]=\"bemMods()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : null\"\n [attr.aria-expanded]=\"expanded()\"\n [attr.aria-haspopup]=\"ariaHaspopup()\"\n [attr.tabindex]=\"linkTabIndex()\"\n (click)=\"onClick($event)\">\n <ng-container *ngTemplateOutlet=\"content\" />\n </a>\n}\n\n<!-- Кнопка стоит в шаблоне без условия и появляется с первым проходом, как до входа `link`: в\n блоке `@if` она рождалась бы проходом позже, и родитель, который меряет соседей на первой\n проверке (автовысота поля сообщения), считал бы ряд без неё. У ссылки кнопка спрятана. -->\n<button\n #buttonEl\n rtBlock=\"rt-icon-button\"\n qa-dataid=\"icon-button-control\"\n rtRipple\n cdkMonitorElementFocus\n [hidden]=\"isLink()\"\n [rippleDisabled]=\"isDisabled() || loading()\"\n [rtTooltip]=\"isLink() ? '' : tooltip()\"\n [rtTooltipHideOnClick]=\"tooltipHideOnClick()\"\n [rtMod]=\"bemMods()\"\n [type]=\"type()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-pressed]=\"active() ? 'true' : null\"\n [attr.aria-expanded]=\"expanded()\"\n [attr.aria-haspopup]=\"ariaHaspopup()\"\n [attr.tabindex]=\"tabIndex()\"\n (click)=\"onClick($event)\">\n @if (!isLink()) {\n <ng-container *ngTemplateOutlet=\"content\" />\n }\n</button>\n\n<!-- Содержимое общее у кнопки и ссылки и рисуется один раз — в том, что видно. Шаблон берёт\n инжектор места объявления, поэтому `rtElem` внутри получает блок от `ng-container`. -->\n<ng-container rtBlock=\"rt-icon-button\">\n <ng-template #content>\n @if (loading()) {\n <rt-icon rtElem=\"spinner\" name=\"spinner\" color=\"current\" [size]=\"resolvedIconSize()\" />\n } @else if (icon() || glyph()) {\n <rt-icon\n rtElem=\"icon\"\n [color]=\"iconColor()\"\n [name]=\"icon()\"\n [glyph]=\"glyph()\"\n [size]=\"resolvedIconSize()\"\n [fill]=\"iconFill()\" />\n } @else {\n <span rtElem=\"content\" qa-dataid=\"icon-button-content\"><ng-content /></span>\n }\n @if (indicator()) {\n <span rtElem=\"indicator\" aria-hidden=\"true\"></span>\n }\n </ng-template>\n</ng-container>\n"],"mappings":"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"}
@@ -316,7 +316,8 @@ var RtImageUploadComponent = class RtImageUploadComponent {
316
316
  "rtTooltipPlacement",
317
317
  "rtTooltipShowDelay",
318
318
  "rtTooltipWhenTruncated",
319
- "rtTooltipHideOnClick"
319
+ "rtTooltipHideOnClick",
320
+ "rtTooltipShowOnTap"
320
321
  ],
321
322
  exportAs: ["rtTooltip"]
322
323
  },
@@ -1 +1 @@
1
- {"version":3,"file":"rt-tools-ui-kit-v2-image-upload.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/image-upload/rt-image-upload.logic.ts","../../../projects/ui-kit-v2/src/lib/components/image-upload/rt-image-upload.component.ts","../../../projects/ui-kit-v2/src/lib/components/image-upload/rt-image-upload.component.html"],"sourcesContent":["import { IRtImageUpload } from './rt-image-upload.model';\n\n/**\n * Какое состояние занимает место. Загрузка приложения важнее всего, выбранный исходник важнее\n * картинки, картинка важнее зоны загрузки.\n */\nexport function uploadState(loading: boolean, hasSource: boolean, image: string | null): IRtImageUpload.State {\n if (loading) {\n return 'loading';\n }\n if (hasSource) {\n return 'cropping';\n }\n return image ? 'image' : 'empty';\n}\n\n/** Берётся только файл изображения: брошенный файл другого типа загрузчик пропускает */\nexport function isImageFile(file: File | null | undefined): file is File {\n return !!file && file.type.startsWith('image/');\n}\n","import { BooleanInput, NumberInput } from '@angular/cdk/coercion';\nimport { DOCUMENT } from '@angular/common';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n ElementRef,\n inject,\n input,\n InputSignal,\n InputSignalWithTransform,\n linkedSignal,\n numberAttribute,\n output,\n OutputEmitterRef,\n Signal,\n signal,\n viewChild,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective, ModDirective, WINDOW } from '@rt-tools/core';\n\nimport { RT_KIT_LABELS, TRtKitLabelMap } from '@rt-tools/ui-kit-v2/core';\nimport { IButton } from '@rt-tools/ui-kit-v2/core';\nimport { RtButtonDirective } from '@rt-tools/ui-kit-v2/button';\nimport { RtEmptyStateComponent } from '@rt-tools/ui-kit-v2/empty-state';\nimport { RtFileDropComponent } from '@rt-tools/ui-kit-v2/file-drop';\nimport { IRtIcon } from '@rt-tools/ui-kit-v2/core';\nimport { RtIconButtonComponent } from '@rt-tools/ui-kit-v2/icon-button';\nimport { IRtImageCropper, RT_IMAGE_CROPPER_QUALITY, RtImageCropperComponent } from '@rt-tools/ui-kit-v2/image-cropper';\nimport { TRtRadius } from '@rt-tools/ui-kit-v2/core';\nimport { RtSpinnerComponent } from '@rt-tools/ui-kit-v2/spinner';\nimport { RtTooltipDirective } from '@rt-tools/ui-kit-v2/tooltip';\nimport { isImageFile, uploadState } from './rt-image-upload.logic';\nimport { IRtImageUpload } from './rt-image-upload.model';\n\nconst BEM_BLOCK: string = 'rt-image-upload';\n\n/**\n * Загрузчик одного изображения: одно место, в котором по очереди стоят зона загрузки, обрезка и\n * сама картинка. Файл выбирают кнопкой зоны или бросают на неё; выбранный открывает обрезку, а\n * «Применить» ставит результат на место картинки и отдаёт файл приложению. Нажатие на картинку\n * выбирает другой файл.\n *\n * Картинка — адрес: приложение даёт свой, а адрес применённого файла загрузчик делает сам и\n * отпускает его, когда картинку сменили или компонент ушёл. Файл приложение получает в\n * `imageChanged`.\n */\n@Component({\n selector: 'rt-image-upload',\n templateUrl: './rt-image-upload.component.html',\n styleUrl: './rt-image-upload.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // directives\n BlockDirective,\n ElemDirective,\n ModDirective,\n RtButtonDirective,\n RtTooltipDirective,\n\n // components\n RtEmptyStateComponent,\n RtFileDropComponent,\n RtIconButtonComponent,\n RtImageCropperComponent,\n RtSpinnerComponent,\n ],\n host: {\n class: BEM_BLOCK,\n '[class.rt-image-upload--disabled]': 'disabled()',\n },\n})\nexport class RtImageUploadComponent {\n readonly #window: Window & typeof globalThis = inject(WINDOW) as Window & typeof globalThis;\n\n readonly #document: Document = inject(DOCUMENT);\n\n /** Адрес, сделанный загрузчиком под применённый файл: его и только его он отпускает */\n #ownUrl: string | null = null;\n\n protected readonly picker: Signal<ElementRef<HTMLInputElement>> = viewChild.required<ElementRef<HTMLInputElement>>('picker');\n\n protected readonly t: Signal<TRtKitLabelMap> = inject(RT_KIT_LABELS);\n\n /** Выбранный файл, который сейчас режет обрезка */\n protected readonly source: WritableSignal<File | null> = signal(null);\n\n /** Последний результат обрезки — его берёт «Применить» */\n protected readonly result: WritableSignal<IRtImageCropper.Result | null> = signal(null);\n\n /** Что сейчас стоит в месте загрузчика */\n protected readonly state: Signal<IRtImageUpload.State> = computed((): IRtImageUpload.State =>\n uploadState(this.loading(), this.source() !== null, this.image())\n );\n\n /** Подсказка над картинкой: своя приложения или подпись кита */\n protected readonly hint: Signal<string> = computed((): string => this.tooltip() || this.t().uiImageUploadChange);\n\n /** Круглая ли кнопка скачивания: подложка под размытием повторяет её скругление */\n protected readonly downloadRound: Signal<boolean> = computed((): boolean => this.downloadShape() === 'circle');\n\n /** Шаг скругления кнопки скачивания: круг — полный шаг, квадрат — скругление кнопки по умолчанию */\n protected readonly downloadRadius: Signal<TRtRadius | null> = computed((): TRtRadius | null => (this.downloadRound() ? 'full' : null));\n\n /**\n * Адрес текущей картинки: данный приложением или сделанный под применённый файл. Новый адрес от\n * приложения снова берёт верх над применённым.\n */\n protected readonly image: WritableSignal<string | null> = linkedSignal((): string | null => this.imageUrl());\n\n /** Адрес картинки от приложения */\n public readonly imageUrl: InputSignal<string | null> = input<string | null>(null);\n\n /** Имя файла, под которым картинку скачивают и отдают приложению */\n public readonly fileName: InputSignal<string> = input<string>('image');\n\n /** Подсказка над картинкой; пустая — подпись кита */\n public readonly tooltip: InputSignal<string> = input<string>('');\n\n /** Кнопка скачивания рядом с картинкой */\n public readonly downloadable: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Форма кнопки скачивания; она заходит за правый верхний угол картинки при любой форме */\n public readonly downloadShape: InputSignal<IRtImageUpload.DownloadShape> = input<IRtImageUpload.DownloadShape>('circle');\n\n /** Размер значка кнопки скачивания; пусто — от размера кнопки */\n public readonly downloadIconSize: InputSignal<IRtIcon.Size | null> = input<IRtIcon.Size | null>(null);\n\n /** Вид кнопки выбора файла в пустом загрузчике */\n public readonly chooseAppearance: InputSignal<IButton.Appearance> = input<IButton.Appearance>('outlined');\n\n /** Значок кнопки выбора файла; пусто — кнопка без значка */\n public readonly chooseIcon: InputSignal<string | null> = input<string | null>('ico-upload');\n\n /** Без кнопок «Отмена» и «Применить»: каждый результат обрезки применяется сразу */\n public readonly autoApply: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Приложение загружает картинку: на месте стоит индикатор */\n public readonly loading: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Недоступный загрузчик не берёт файлов и не отзывается на нажатие картинки */\n public readonly disabled: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Соотношение рамки обрезки; пусто — свободная рамка */\n public readonly ratio: InputSignalWithTransform<number | null, NumberInput> = input<number | null, NumberInput>(null, {\n transform: (value: NumberInput): number | null => (value === null || value === '' ? null : numberAttribute(value, 0) || null),\n });\n\n /** Круглая маска обрезки для аватара */\n public readonly round: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Формат результата; пусто — формат исходника */\n public readonly format: InputSignal<IRtImageCropper.Format | null> = input<IRtImageCropper.Format | null>(null);\n\n /** Качество результата, от 0 до 100 */\n public readonly quality: InputSignalWithTransform<number, NumberInput> = input<number, NumberInput>(RT_IMAGE_CROPPER_QUALITY, {\n transform: (value: NumberInput): number => numberAttribute(value, RT_IMAGE_CROPPER_QUALITY),\n });\n\n /** Применённый файл — его приложение отправляет, куда ему надо */\n public readonly imageChanged: OutputEmitterRef<File> = output<File>();\n\n /** Картинку скачали */\n public readonly downloaded: OutputEmitterRef<void> = output<void>();\n\n constructor() {\n inject(DestroyRef).onDestroy((): void => this.#release());\n }\n\n /** Открывает выбор файла, если загрузчик доступен */\n public pick(): void {\n if (!this.disabled()) {\n this.picker().nativeElement.click();\n }\n }\n\n /** Файл выбран кнопкой или брошен: изображение открывает обрезку, остальное пропускается */\n public choose(file: File | null | undefined): void {\n if (this.disabled() || !isImageFile(file)) {\n return;\n }\n this.result.set(null);\n this.source.set(file);\n }\n\n protected onPicked(event: Event): void {\n const input: HTMLInputElement = event.target as HTMLInputElement;\n this.choose(input.files?.[0]);\n // Тот же файл, выбранный второй раз, иначе не даёт события\n input.value = '';\n }\n\n protected onSpace(event: Event): void {\n event.preventDefault();\n this.pick();\n }\n\n protected onCropped(result: IRtImageCropper.Result): void {\n this.result.set(result);\n if (this.autoApply()) {\n this.#applyResult(result, false);\n }\n }\n\n protected apply(): void {\n const result: IRtImageCropper.Result | null = this.result();\n if (result !== null) {\n this.#applyResult(result, true);\n }\n }\n\n protected cancel(): void {\n this.source.set(null);\n this.result.set(null);\n }\n\n protected download(): void {\n const url: string | null = this.image();\n if (url === null) {\n return;\n }\n const link: HTMLAnchorElement = this.#document.createElement('a');\n link.href = url;\n link.download = this.fileName();\n this.#document.body.appendChild(link);\n link.click();\n link.remove();\n this.downloaded.emit();\n }\n\n /** Результат становится картинкой; `close` убирает обрезку — при автоприменении она остаётся */\n #applyResult(result: IRtImageCropper.Result, close: boolean): void {\n const file: File = new File([result.file], this.fileName(), { type: result.file.type });\n this.#release();\n this.#ownUrl = this.#window.URL.createObjectURL(file);\n this.image.set(this.#ownUrl);\n this.imageChanged.emit(file);\n if (close) {\n this.cancel();\n }\n }\n\n #release(): void {\n if (this.#ownUrl !== null) {\n this.#window.URL.revokeObjectURL(this.#ownUrl);\n this.#ownUrl = null;\n }\n }\n}\n","<ng-container rtBlock=\"rt-image-upload\">\n <input\n #picker\n hidden\n type=\"file\"\n accept=\"image/*\"\n qa-dataid=\"image-upload-native\"\n [disabled]=\"disabled()\"\n (change)=\"onPicked($event)\" />\n\n @switch (state()) {\n @case ('loading') {\n <div rtElem=\"loading\" qa-dataid=\"image-upload-loading\">\n <rt-spinner />\n </div>\n }\n @case ('cropping') {\n <rt-image-cropper\n qa-dataid=\"image-upload-cropper\"\n [file]=\"source()\"\n [ratio]=\"ratio()\"\n [round]=\"round()\"\n [format]=\"format()\"\n [quality]=\"quality()\"\n (cropped)=\"onCropped($event)\"\n (loadFailed)=\"cancel()\" />\n\n @if (!autoApply()) {\n <div rtElem=\"actions\">\n <button\n rtButton\n appearance=\"text\"\n type=\"button\"\n qa-dataid=\"image-upload-cancel\"\n [label]=\"t().uiImageUploadCancel\"\n [attr.aria-label]=\"t().uiImageUploadCancel\"\n (click)=\"cancel()\"></button>\n <button\n rtButton\n type=\"button\"\n qa-dataid=\"image-upload-apply\"\n [label]=\"t().uiImageUploadApply\"\n [attr.aria-label]=\"t().uiImageUploadApply\"\n [disabled]=\"!result()\"\n (click)=\"apply()\"></button>\n </div>\n }\n }\n @case ('image') {\n <rt-file-drop accept=\"image/*\" [disabled]=\"disabled()\" (filesDropped)=\"choose($event[0])\">\n <div rtElem=\"preview\">\n <img\n rtElem=\"image\"\n role=\"button\"\n qa-dataid=\"image-upload-image\"\n [attr.tabindex]=\"disabled() ? -1 : 0\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.alt]=\"t().uiImageUploadImage\"\n [rtTooltip]=\"disabled() ? '' : hint()\"\n [rtMod]=\"{ active: !disabled() }\"\n [src]=\"image()\"\n (click)=\"pick()\"\n (keydown.enter)=\"pick()\"\n (keydown.space)=\"onSpace($event)\" />\n\n @if (downloadable()) {\n <rt-icon-button\n rtElem=\"download\"\n icon=\"ico-download\"\n qa-dataid=\"image-upload-download\"\n [radius]=\"downloadRadius()\"\n [iconSize]=\"downloadIconSize()\"\n [rtMod]=\"{ round: downloadRound() }\"\n [ariaLabel]=\"t().uiDownload\"\n [tooltip]=\"t().uiDownload\"\n (click)=\"download()\" />\n }\n </div>\n </rt-file-drop>\n }\n @default {\n <rt-file-drop accept=\"image/*\" qa-dataid=\"image-upload-drop\" [disabled]=\"disabled()\" (filesDropped)=\"choose($event[0])\">\n <rt-empty-state framed icon=\"cloud-upload\" [title]=\"t().uiImageUploadDrop\">\n <button\n rtButton\n type=\"button\"\n qa-dataid=\"image-upload-choose\"\n [appearance]=\"chooseAppearance()\"\n [icon]=\"chooseIcon()\"\n [label]=\"t().uiImageUploadChoose\"\n [attr.aria-label]=\"t().uiImageUploadChoose\"\n [disabled]=\"disabled()\"\n (click)=\"pick()\"></button>\n </rt-empty-state>\n </rt-file-drop>\n }\n }\n</ng-container>\n"],"mappings":"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"}
1
+ {"version":3,"file":"rt-tools-ui-kit-v2-image-upload.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/image-upload/rt-image-upload.logic.ts","../../../projects/ui-kit-v2/src/lib/components/image-upload/rt-image-upload.component.ts","../../../projects/ui-kit-v2/src/lib/components/image-upload/rt-image-upload.component.html"],"sourcesContent":["import { IRtImageUpload } from './rt-image-upload.model';\n\n/**\n * Какое состояние занимает место. Загрузка приложения важнее всего, выбранный исходник важнее\n * картинки, картинка важнее зоны загрузки.\n */\nexport function uploadState(loading: boolean, hasSource: boolean, image: string | null): IRtImageUpload.State {\n if (loading) {\n return 'loading';\n }\n if (hasSource) {\n return 'cropping';\n }\n return image ? 'image' : 'empty';\n}\n\n/** Берётся только файл изображения: брошенный файл другого типа загрузчик пропускает */\nexport function isImageFile(file: File | null | undefined): file is File {\n return !!file && file.type.startsWith('image/');\n}\n","import { BooleanInput, NumberInput } from '@angular/cdk/coercion';\nimport { DOCUMENT } from '@angular/common';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n ElementRef,\n inject,\n input,\n InputSignal,\n InputSignalWithTransform,\n linkedSignal,\n numberAttribute,\n output,\n OutputEmitterRef,\n Signal,\n signal,\n viewChild,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective, ModDirective, WINDOW } from '@rt-tools/core';\n\nimport { RT_KIT_LABELS, TRtKitLabelMap } from '@rt-tools/ui-kit-v2/core';\nimport { IButton } from '@rt-tools/ui-kit-v2/core';\nimport { RtButtonDirective } from '@rt-tools/ui-kit-v2/button';\nimport { RtEmptyStateComponent } from '@rt-tools/ui-kit-v2/empty-state';\nimport { RtFileDropComponent } from '@rt-tools/ui-kit-v2/file-drop';\nimport { IRtIcon } from '@rt-tools/ui-kit-v2/core';\nimport { RtIconButtonComponent } from '@rt-tools/ui-kit-v2/icon-button';\nimport { IRtImageCropper, RT_IMAGE_CROPPER_QUALITY, RtImageCropperComponent } from '@rt-tools/ui-kit-v2/image-cropper';\nimport { TRtRadius } from '@rt-tools/ui-kit-v2/core';\nimport { RtSpinnerComponent } from '@rt-tools/ui-kit-v2/spinner';\nimport { RtTooltipDirective } from '@rt-tools/ui-kit-v2/tooltip';\nimport { isImageFile, uploadState } from './rt-image-upload.logic';\nimport { IRtImageUpload } from './rt-image-upload.model';\n\nconst BEM_BLOCK: string = 'rt-image-upload';\n\n/**\n * Загрузчик одного изображения: одно место, в котором по очереди стоят зона загрузки, обрезка и\n * сама картинка. Файл выбирают кнопкой зоны или бросают на неё; выбранный открывает обрезку, а\n * «Применить» ставит результат на место картинки и отдаёт файл приложению. Нажатие на картинку\n * выбирает другой файл.\n *\n * Картинка — адрес: приложение даёт свой, а адрес применённого файла загрузчик делает сам и\n * отпускает его, когда картинку сменили или компонент ушёл. Файл приложение получает в\n * `imageChanged`.\n */\n@Component({\n selector: 'rt-image-upload',\n templateUrl: './rt-image-upload.component.html',\n styleUrl: './rt-image-upload.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // directives\n BlockDirective,\n ElemDirective,\n ModDirective,\n RtButtonDirective,\n RtTooltipDirective,\n\n // components\n RtEmptyStateComponent,\n RtFileDropComponent,\n RtIconButtonComponent,\n RtImageCropperComponent,\n RtSpinnerComponent,\n ],\n host: {\n class: BEM_BLOCK,\n '[class.rt-image-upload--disabled]': 'disabled()',\n },\n})\nexport class RtImageUploadComponent {\n readonly #window: Window & typeof globalThis = inject(WINDOW) as Window & typeof globalThis;\n\n readonly #document: Document = inject(DOCUMENT);\n\n /** Адрес, сделанный загрузчиком под применённый файл: его и только его он отпускает */\n #ownUrl: string | null = null;\n\n protected readonly picker: Signal<ElementRef<HTMLInputElement>> = viewChild.required<ElementRef<HTMLInputElement>>('picker');\n\n protected readonly t: Signal<TRtKitLabelMap> = inject(RT_KIT_LABELS);\n\n /** Выбранный файл, который сейчас режет обрезка */\n protected readonly source: WritableSignal<File | null> = signal(null);\n\n /** Последний результат обрезки — его берёт «Применить» */\n protected readonly result: WritableSignal<IRtImageCropper.Result | null> = signal(null);\n\n /** Что сейчас стоит в месте загрузчика */\n protected readonly state: Signal<IRtImageUpload.State> = computed((): IRtImageUpload.State =>\n uploadState(this.loading(), this.source() !== null, this.image())\n );\n\n /** Подсказка над картинкой: своя приложения или подпись кита */\n protected readonly hint: Signal<string> = computed((): string => this.tooltip() || this.t().uiImageUploadChange);\n\n /** Круглая ли кнопка скачивания: подложка под размытием повторяет её скругление */\n protected readonly downloadRound: Signal<boolean> = computed((): boolean => this.downloadShape() === 'circle');\n\n /** Шаг скругления кнопки скачивания: круг — полный шаг, квадрат — скругление кнопки по умолчанию */\n protected readonly downloadRadius: Signal<TRtRadius | null> = computed((): TRtRadius | null => (this.downloadRound() ? 'full' : null));\n\n /**\n * Адрес текущей картинки: данный приложением или сделанный под применённый файл. Новый адрес от\n * приложения снова берёт верх над применённым.\n */\n protected readonly image: WritableSignal<string | null> = linkedSignal((): string | null => this.imageUrl());\n\n /** Адрес картинки от приложения */\n public readonly imageUrl: InputSignal<string | null> = input<string | null>(null);\n\n /** Имя файла, под которым картинку скачивают и отдают приложению */\n public readonly fileName: InputSignal<string> = input<string>('image');\n\n /** Подсказка над картинкой; пустая — подпись кита */\n public readonly tooltip: InputSignal<string> = input<string>('');\n\n /** Кнопка скачивания рядом с картинкой */\n public readonly downloadable: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Форма кнопки скачивания; она заходит за правый верхний угол картинки при любой форме */\n public readonly downloadShape: InputSignal<IRtImageUpload.DownloadShape> = input<IRtImageUpload.DownloadShape>('circle');\n\n /** Размер значка кнопки скачивания; пусто — от размера кнопки */\n public readonly downloadIconSize: InputSignal<IRtIcon.Size | null> = input<IRtIcon.Size | null>(null);\n\n /** Вид кнопки выбора файла в пустом загрузчике */\n public readonly chooseAppearance: InputSignal<IButton.Appearance> = input<IButton.Appearance>('outlined');\n\n /** Значок кнопки выбора файла; пусто — кнопка без значка */\n public readonly chooseIcon: InputSignal<string | null> = input<string | null>('ico-upload');\n\n /** Без кнопок «Отмена» и «Применить»: каждый результат обрезки применяется сразу */\n public readonly autoApply: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Приложение загружает картинку: на месте стоит индикатор */\n public readonly loading: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Недоступный загрузчик не берёт файлов и не отзывается на нажатие картинки */\n public readonly disabled: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Соотношение рамки обрезки; пусто — свободная рамка */\n public readonly ratio: InputSignalWithTransform<number | null, NumberInput> = input<number | null, NumberInput>(null, {\n transform: (value: NumberInput): number | null => (value === null || value === '' ? null : numberAttribute(value, 0) || null),\n });\n\n /** Круглая маска обрезки для аватара */\n public readonly round: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Формат результата; пусто — формат исходника */\n public readonly format: InputSignal<IRtImageCropper.Format | null> = input<IRtImageCropper.Format | null>(null);\n\n /** Качество результата, от 0 до 100 */\n public readonly quality: InputSignalWithTransform<number, NumberInput> = input<number, NumberInput>(RT_IMAGE_CROPPER_QUALITY, {\n transform: (value: NumberInput): number => numberAttribute(value, RT_IMAGE_CROPPER_QUALITY),\n });\n\n /** Применённый файл — его приложение отправляет, куда ему надо */\n public readonly imageChanged: OutputEmitterRef<File> = output<File>();\n\n /** Картинку скачали */\n public readonly downloaded: OutputEmitterRef<void> = output<void>();\n\n constructor() {\n inject(DestroyRef).onDestroy((): void => this.#release());\n }\n\n /** Открывает выбор файла, если загрузчик доступен */\n public pick(): void {\n if (!this.disabled()) {\n this.picker().nativeElement.click();\n }\n }\n\n /** Файл выбран кнопкой или брошен: изображение открывает обрезку, остальное пропускается */\n public choose(file: File | null | undefined): void {\n if (this.disabled() || !isImageFile(file)) {\n return;\n }\n this.result.set(null);\n this.source.set(file);\n }\n\n protected onPicked(event: Event): void {\n const input: HTMLInputElement = event.target as HTMLInputElement;\n this.choose(input.files?.[0]);\n // Тот же файл, выбранный второй раз, иначе не даёт события\n input.value = '';\n }\n\n protected onSpace(event: Event): void {\n event.preventDefault();\n this.pick();\n }\n\n protected onCropped(result: IRtImageCropper.Result): void {\n this.result.set(result);\n if (this.autoApply()) {\n this.#applyResult(result, false);\n }\n }\n\n protected apply(): void {\n const result: IRtImageCropper.Result | null = this.result();\n if (result !== null) {\n this.#applyResult(result, true);\n }\n }\n\n protected cancel(): void {\n this.source.set(null);\n this.result.set(null);\n }\n\n protected download(): void {\n const url: string | null = this.image();\n if (url === null) {\n return;\n }\n const link: HTMLAnchorElement = this.#document.createElement('a');\n link.href = url;\n link.download = this.fileName();\n this.#document.body.appendChild(link);\n link.click();\n link.remove();\n this.downloaded.emit();\n }\n\n /** Результат становится картинкой; `close` убирает обрезку — при автоприменении она остаётся */\n #applyResult(result: IRtImageCropper.Result, close: boolean): void {\n const file: File = new File([result.file], this.fileName(), { type: result.file.type });\n this.#release();\n this.#ownUrl = this.#window.URL.createObjectURL(file);\n this.image.set(this.#ownUrl);\n this.imageChanged.emit(file);\n if (close) {\n this.cancel();\n }\n }\n\n #release(): void {\n if (this.#ownUrl !== null) {\n this.#window.URL.revokeObjectURL(this.#ownUrl);\n this.#ownUrl = null;\n }\n }\n}\n","<ng-container rtBlock=\"rt-image-upload\">\n <input\n #picker\n hidden\n type=\"file\"\n accept=\"image/*\"\n qa-dataid=\"image-upload-native\"\n [disabled]=\"disabled()\"\n (change)=\"onPicked($event)\" />\n\n @switch (state()) {\n @case ('loading') {\n <div rtElem=\"loading\" qa-dataid=\"image-upload-loading\">\n <rt-spinner />\n </div>\n }\n @case ('cropping') {\n <rt-image-cropper\n qa-dataid=\"image-upload-cropper\"\n [file]=\"source()\"\n [ratio]=\"ratio()\"\n [round]=\"round()\"\n [format]=\"format()\"\n [quality]=\"quality()\"\n (cropped)=\"onCropped($event)\"\n (loadFailed)=\"cancel()\" />\n\n @if (!autoApply()) {\n <div rtElem=\"actions\">\n <button\n rtButton\n appearance=\"text\"\n type=\"button\"\n qa-dataid=\"image-upload-cancel\"\n [label]=\"t().uiImageUploadCancel\"\n [attr.aria-label]=\"t().uiImageUploadCancel\"\n (click)=\"cancel()\"></button>\n <button\n rtButton\n type=\"button\"\n qa-dataid=\"image-upload-apply\"\n [label]=\"t().uiImageUploadApply\"\n [attr.aria-label]=\"t().uiImageUploadApply\"\n [disabled]=\"!result()\"\n (click)=\"apply()\"></button>\n </div>\n }\n }\n @case ('image') {\n <rt-file-drop accept=\"image/*\" [disabled]=\"disabled()\" (filesDropped)=\"choose($event[0])\">\n <div rtElem=\"preview\">\n <img\n rtElem=\"image\"\n role=\"button\"\n qa-dataid=\"image-upload-image\"\n [attr.tabindex]=\"disabled() ? -1 : 0\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.alt]=\"t().uiImageUploadImage\"\n [rtTooltip]=\"disabled() ? '' : hint()\"\n [rtMod]=\"{ active: !disabled() }\"\n [src]=\"image()\"\n (click)=\"pick()\"\n (keydown.enter)=\"pick()\"\n (keydown.space)=\"onSpace($event)\" />\n\n @if (downloadable()) {\n <rt-icon-button\n rtElem=\"download\"\n icon=\"ico-download\"\n qa-dataid=\"image-upload-download\"\n [radius]=\"downloadRadius()\"\n [iconSize]=\"downloadIconSize()\"\n [rtMod]=\"{ round: downloadRound() }\"\n [ariaLabel]=\"t().uiDownload\"\n [tooltip]=\"t().uiDownload\"\n (click)=\"download()\" />\n }\n </div>\n </rt-file-drop>\n }\n @default {\n <rt-file-drop accept=\"image/*\" qa-dataid=\"image-upload-drop\" [disabled]=\"disabled()\" (filesDropped)=\"choose($event[0])\">\n <rt-empty-state framed icon=\"cloud-upload\" [title]=\"t().uiImageUploadDrop\">\n <button\n rtButton\n type=\"button\"\n qa-dataid=\"image-upload-choose\"\n [appearance]=\"chooseAppearance()\"\n [icon]=\"chooseIcon()\"\n [label]=\"t().uiImageUploadChoose\"\n [attr.aria-label]=\"t().uiImageUploadChoose\"\n [disabled]=\"disabled()\"\n (click)=\"pick()\"></button>\n </rt-empty-state>\n </rt-file-drop>\n }\n }\n</ng-container>\n"],"mappings":"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"}
@@ -450,7 +450,8 @@ var RtInlineEditComponent = class RtInlineEditComponent {
450
450
  "rtTooltipPlacement",
451
451
  "rtTooltipShowDelay",
452
452
  "rtTooltipWhenTruncated",
453
- "rtTooltipHideOnClick"
453
+ "rtTooltipHideOnClick",
454
+ "rtTooltipShowOnTap"
454
455
  ],
455
456
  exportAs: ["rtTooltip"]
456
457
  }
@@ -1 +1 @@
1
- {"version":3,"file":"rt-tools-ui-kit-v2-inline-edit.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/inline-edit/rt-inline-edit.logic.ts","../../../projects/ui-kit-v2/src/lib/components/inline-edit/rt-inline-edit.component.ts","../../../projects/ui-kit-v2/src/lib/components/inline-edit/rt-inline-edit.component.html"],"sourcesContent":["import { IRtInlineEdit } from './rt-inline-edit.model';\n\n/** Сколько знаков конца текста видно всегда при обрезке посередине. */\nconst MIDDLE_TAIL: number = 10;\n\n/**\n * Чем кончается сохранение черновика. Черновик обрезается по краям; пустой не уходит, пока его не\n * разрешили; равный значению закрывает поле и ничего не шлёт.\n */\nexport function inlineEditOutcome(value: string, draft: string, allowEmpty: boolean): IRtInlineEdit.Outcome {\n const next: string = draft.trim();\n\n if (next === '' && !allowEmpty) {\n return { kind: 'refuse' };\n }\n\n return next === value ? { kind: 'close' } : { kind: 'save', value: next };\n}\n\n/**\n * Текст для обрезки посередине: последние десять знаков видны всегда, многоточие встаёт в начале.\n * Текст не длиннее двух концов не режется — весь он идёт началом. Знаки считаются по кодовым точкам,\n * поэтому пара суррогатов не рвётся.\n */\nexport function inlineEditMiddle(text: string): IRtInlineEdit.MiddleParts {\n const chars: string[] = Array.from(text);\n\n if (chars.length <= MIDDLE_TAIL * 2) {\n return { head: text, tail: '' };\n }\n\n return { head: chars.slice(0, -MIDDLE_TAIL).join(''), tail: chars.slice(-MIDDLE_TAIL).join('') };\n}\n\n/**\n * Ушёл ли фокус из компонента. Переход на свои кнопки уходом не считается: нажатие «Сохранить» или\n * «Отмена» начинается с ухода фокуса из поля. Неизвестная цель — окно или пустое место — уход.\n */\nexport function inlineEditLeaves(host: Node, target: EventTarget | null): boolean {\n return !(target instanceof Node && host.contains(target));\n}\n","import {\n afterNextRender,\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n effect,\n ElementRef,\n inject,\n Injector,\n input,\n InputSignal,\n InputSignalWithTransform,\n model,\n ModelSignal,\n output,\n OutputEmitterRef,\n signal,\n Signal,\n untracked,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\nimport { FormControl, ReactiveFormsModule } from '@angular/forms';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { IRtIcon, IRtInput, rtKitLabel } from '@rt-tools/ui-kit-v2/core';\nimport { RtIconComponent } from '@rt-tools/ui-kit-v2/icon';\nimport { RtIconButtonComponent } from '@rt-tools/ui-kit-v2/icon-button';\nimport { RtInputComponent } from '@rt-tools/ui-kit-v2/input';\nimport { RtTooltipDirective } from '@rt-tools/ui-kit-v2/tooltip';\nimport { inlineEditLeaves, inlineEditMiddle, inlineEditOutcome } from './rt-inline-edit.logic';\nimport { IRtInlineEdit } from './rt-inline-edit.model';\n\nconst BEM_BLOCK: string = 'rt-inline-edit';\n\n/**\n * Правка короткого значения на месте. В покое значение — кнопка с карандашом; нажатие открывает поле\n * кита с черновиком, кнопкой сохранения и кнопкой отмены. Enter сохраняет, Escape отменяет.\n *\n * Значение принадлежит приложению: компонент отдаёт новое выходом и сам его не хранит. Приложение,\n * которое отвечает позже, держит поле открытым входом `closeOnSave` и закрывает его само.\n */\n@Component({\n selector: 'rt-inline-edit',\n templateUrl: './rt-inline-edit.component.html',\n styleUrl: './rt-inline-edit.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n ReactiveFormsModule,\n BlockDirective,\n ElemDirective,\n ModDirective,\n RtIconComponent,\n RtIconButtonComponent,\n RtInputComponent,\n RtTooltipDirective,\n ],\n host: {\n class: BEM_BLOCK,\n '[class.rt-inline-edit--chip]': \"look() === 'chip'\",\n '[class.rt-inline-edit--chip-field]': 'isChipField()',\n '[class.rt-inline-edit--size-md]': \"size() === 'md'\",\n '[class.rt-inline-edit--size-lg]': \"size() === 'lg'\",\n '(focusin)': 'onFocusIn()',\n '(focusout)': 'onFocusOut($event)',\n },\n})\nexport class RtInlineEditComponent {\n readonly #host: ElementRef<HTMLElement> = inject(ElementRef);\n readonly #injector: Injector = inject(Injector);\n\n readonly #t_uiEdit: Signal<string> = rtKitLabel('uiEdit');\n\n /**\n * Фокус был внутри и не ушёл на другой элемент страницы. Недоступное на время сохранения поле\n * роняет фокус в никуда, и без этой отметки его некуда вернуть, когда поле закроет приложение.\n */\n #focusInside: boolean = false;\n #wasEditing: boolean = false;\n #wasSaving: boolean = false;\n /** Фокус в поле плашки: пока человек правит, новое значение приложения не переписывает черновик. */\n #chipFocused: boolean = false;\n /** Enter или Escape уже сохранили черновик и снимают фокус сами: уход не сохраняет второй раз. */\n #chipLeaving: boolean = false;\n\n protected readonly saveLabel: Signal<string> = rtKitLabel('uiSave');\n protected readonly cancelLabel: Signal<string> = rtKitLabel('uiCancel');\n\n /** Что видно в покое: значение, а пустое — подсказка. */\n protected readonly shown: Signal<string> = computed((): string => this.value() || this.placeholder());\n protected readonly isEmpty: Signal<boolean> = computed((): boolean => this.value() === '');\n /** Имя кнопки покоя: действие и то, что правится. */\n protected readonly startLabel: Signal<string> = computed((): string => `${this.#t_uiEdit()}: ${this.shown()}`);\n\n /** Что набрано в открытом поле; зеркало поля для расчёта доступности сохранения. */\n readonly #draft: WritableSignal<string> = signal('');\n\n /**\n * Поле черновика. Форма, а не двусторонняя привязка: форма пишет значение в поле в том же\n * проходе отрисовки, и выделение текста при открытии застаёт его на месте.\n */\n protected readonly draftControl: FormControl<string> = new FormControl<string>('', { nonNullable: true });\n protected readonly canSave: Signal<boolean> = computed(\n (): boolean => inlineEditOutcome(this.value(), this.#draft(), this.allowEmpty()).kind !== 'refuse'\n );\n\n /** Плашка сама остаётся полем: нет покоя и открытия, нет кнопок. */\n protected readonly isChipField: Signal<boolean> = computed((): boolean => this.look() === 'chip-field');\n /** Текст, по которому плашка-поле берёт ширину: черновик, а пустой — подсказка. */\n protected readonly chipText: Signal<string> = computed((): string => this.#draft() || this.placeholder());\n /** Видимый вне фокуса текст плашки-поля, разрезанный посередине; пустой черновик не режется. */\n protected readonly middleParts: Signal<IRtInlineEdit.MiddleParts | null> = computed((): IRtInlineEdit.MiddleParts | null =>\n this.truncate() === 'middle' && this.#draft() !== '' ? inlineEditMiddle(this.#draft()) : null\n );\n\n /** Значение приложения: видно в покое и встаёт в поле при открытии. */\n public readonly value: InputSignal<string> = input.required<string>();\n /** Подсказка пустого значения в покое и пустого поля. */\n public readonly placeholder: InputSignal<string> = input<string>('');\n /** Вид в покое: строка текста или плашка. */\n public readonly look: InputSignal<IRtInlineEdit.Look> = input<IRtInlineEdit.Look>('text');\n /** Где плашка-поле режет длинный текст вне фокуса. Читается только видом `chip-field`. */\n public readonly truncate: InputSignal<IRtInlineEdit.Truncate> = input<IRtInlineEdit.Truncate>('end');\n /** Ступень поля и кнопок. */\n public readonly size: InputSignal<IRtInput.Size> = input<IRtInput.Size>('sm');\n /** Имя поля для чтения экрана; пусто — подсказка поля. */\n public readonly fieldLabel: InputSignal<string> = input<string>('');\n /** Компонент недоступен: поле не открывается. */\n public readonly disabled: InputSignalWithTransform<boolean, unknown> = input<boolean, unknown>(false, { transform: booleanAttribute });\n /** Приложение сохраняет: кнопка сохранения крутится, поле и отмена недоступны. */\n public readonly saving: InputSignalWithTransform<boolean, unknown> = input<boolean, unknown>(false, { transform: booleanAttribute });\n /** Пустой черновик сохраняется; выключено — кнопка сохранения недоступна. */\n public readonly allowEmpty: InputSignalWithTransform<boolean, unknown> = input<boolean, unknown>(false, {\n transform: booleanAttribute,\n });\n /** Поле закрывается при сохранении; выключено — его закрывает приложение через `editing`. */\n public readonly closeOnSave: InputSignalWithTransform<boolean, unknown> = input<boolean, unknown>(true, {\n transform: booleanAttribute,\n });\n /** Что делает уход фокуса из компонента. */\n public readonly blurAction: InputSignal<IRtInlineEdit.BlurAction> = input<IRtInlineEdit.BlurAction>('keep');\n /** Значок перед текстом плашки-поля: имя значка кита. */\n public readonly fieldIcon: InputSignal<IRtIcon.Name> = input<IRtIcon.Name>('pencil');\n\n /** Поле открыто. Приложение может открыть и закрыть его само. */\n public readonly editing: ModelSignal<boolean> = model<boolean>(false);\n\n /** Новое значение, уже обрезанное по краям. Равное прежнему не уходит. */\n public readonly saved: OutputEmitterRef<string> = output<string>();\n /** Правка отменена: поле закрыто, значение прежнее. */\n public readonly cancelled: OutputEmitterRef<void> = output<void>();\n\n constructor() {\n this.draftControl.valueChanges.pipe(takeUntilDestroyed()).subscribe((draft: string): void => this.#draft.set(draft));\n\n // Поле открылось — нажатием или входом приложения: черновик берёт значение, фокус встаёт в поле.\n // Поле закрылось — своей кнопкой или входом приложения: фокус возвращается на значение.\n effect((): void => {\n const editing: boolean = this.editing();\n\n if (editing) {\n this.draftControl.setValue(untracked(this.value));\n afterNextRender((): void => this.focusField(), { injector: this.#injector });\n } else if (this.#wasEditing) {\n this.#restoreFocus('.rt-inline-edit__value');\n } else {\n // Покой без перехода: фокус никто не трогает.\n }\n this.#wasEditing = editing;\n });\n\n // Плашка-поле показывает значение приложения, пока человек её не правит.\n effect((): void => {\n const value: string = this.value();\n\n if (this.isChipField() && !this.#chipFocused) {\n this.draftControl.setValue(value);\n }\n });\n\n // Пока приложение сохраняет, поле недоступно; отказ оставил поле открытым — фокус снова в нём.\n // Плашка-поле всегда на месте, и недоступный компонент запирает её саму.\n effect((): void => {\n const saving: boolean = this.saving();\n\n if (saving || (this.isChipField() && this.disabled())) {\n this.draftControl.disable({ emitEvent: false });\n } else {\n this.draftControl.enable({ emitEvent: false });\n if (this.#wasSaving && untracked(this.editing)) {\n this.#restoreFocus('.rt-inline-edit__field input');\n }\n }\n this.#wasSaving = saving;\n });\n }\n\n /** Нажатие на значение в покое. */\n public open(): void {\n if (this.disabled() || this.editing()) {\n return;\n }\n this.editing.set(true);\n }\n\n public save(): void {\n if (this.saving()) {\n return;\n }\n const outcome: IRtInlineEdit.Outcome = inlineEditOutcome(this.value(), this.draftControl.value, this.allowEmpty());\n\n if (outcome.kind === 'refuse') {\n return;\n }\n if (outcome.kind === 'save') {\n this.saved.emit(outcome.value);\n if (!this.closeOnSave()) {\n return;\n }\n }\n this.#close();\n }\n\n public cancel(): void {\n if (this.saving()) {\n return;\n }\n this.#close();\n this.cancelled.emit();\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n if (event.key === 'Enter') {\n event.preventDefault();\n this.save();\n } else if (event.key === 'Escape') {\n // Escape принадлежит полю: окно или панель вокруг не закрываются вместе с правкой.\n event.preventDefault();\n event.stopPropagation();\n this.cancel();\n } else {\n // Остальные клавиши правят черновик в самом поле.\n }\n }\n\n protected onFocusIn(): void {\n this.#focusInside = true;\n }\n\n protected onFocusOut(event: FocusEvent): void {\n if (event.relatedTarget instanceof Node && !this.#host.nativeElement.contains(event.relatedTarget)) {\n this.#focusInside = false;\n }\n if (!this.editing() || this.saving() || !inlineEditLeaves(this.#host.nativeElement, event.relatedTarget)) {\n return;\n }\n if (this.blurAction() === 'save') {\n this.save();\n } else if (this.blurAction() === 'cancel') {\n this.cancel();\n } else {\n // Поле держится открытым: случайное нажатие мимо не теряет набранное.\n }\n }\n\n /** Фокус пришёл в плашку-поле: весь текст выделен, и первое нажатие заменяет значение целиком. */\n protected onChipFocus(event: FocusEvent): void {\n this.#chipFocused = true;\n if (event.target instanceof HTMLInputElement) {\n event.target.select();\n }\n }\n\n /** Уход из плашки-поля сохраняет черновик. */\n protected onChipBlur(): void {\n this.#chipFocused = false;\n if (!this.#chipLeaving) {\n this.#commitChip();\n }\n }\n\n protected onChipKeydown(event: KeyboardEvent): void {\n if (event.key === 'Enter') {\n event.preventDefault();\n this.#leaveChip(event);\n } else if (event.key === 'Escape') {\n // Escape принадлежит полю: окно или панель вокруг не закрываются вместе с правкой.\n event.preventDefault();\n event.stopPropagation();\n this.draftControl.setValue(this.value());\n this.#leaveChip(event);\n this.cancelled.emit();\n } else {\n // Остальные клавиши правят черновик в самом поле.\n }\n }\n\n /** Фокус в поле и весь текст выделен: первое нажатие клавиши заменяет значение целиком. */\n protected focusField(): void {\n const field: HTMLInputElement | null = this.#host.nativeElement.querySelector('.rt-inline-edit__field input');\n\n field?.focus();\n field?.select();\n }\n\n #close(): void {\n this.editing.set(false);\n }\n\n /**\n * Черновик плашки-поля уходит приложению. Пустой, который не разрешён, и равный значению молча\n * возвращают значение: у плашки нет недоступной кнопки, которой можно было бы отказать.\n */\n #commitChip(): void {\n if (this.saving()) {\n return;\n }\n const outcome: IRtInlineEdit.Outcome = inlineEditOutcome(this.value(), this.draftControl.value, this.allowEmpty());\n\n if (outcome.kind === 'save') {\n this.saved.emit(outcome.value);\n this.draftControl.setValue(outcome.value);\n } else {\n this.draftControl.setValue(this.value());\n }\n }\n\n /** Enter и Escape сохраняют сами и снимают фокус: уход, который за этим следует, не сохраняет второй раз. */\n #leaveChip(event: KeyboardEvent): void {\n const target: EventTarget | null = event.target;\n\n this.#commitChip();\n if (target instanceof HTMLElement && target.ownerDocument.activeElement === target) {\n this.#chipLeaving = true;\n target.blur();\n this.#chipLeaving = false;\n }\n }\n\n /**\n * Фокус, бывший внутри, возвращается на элемент компонента после отрисовки. Ушедший на другой\n * элемент страницы не трогается: человек уже там.\n */\n #restoreFocus(selector: string): void {\n const host: HTMLElement = this.#host.nativeElement;\n const active: Element | null = host.ownerDocument.activeElement;\n\n if (!this.#focusInside || (active !== null && active !== host.ownerDocument.body && !host.contains(active))) {\n return;\n }\n afterNextRender((): void => host.querySelector<HTMLElement>(selector)?.focus(), { injector: this.#injector });\n }\n}\n","<ng-container rtBlock=\"rt-inline-edit\">\n @if (isChipField()) {\n <!-- Плашка-поле: значок и поле внутри одной плашки. Ширину задаёт невидимая копия текста под\n полем — плашка растёт с текстом до своего предела, дальше поле прокручивается. -->\n <label rtElem=\"chip-field\" [rtMod]=\"{ disabled: disabled() }\">\n <rt-icon rtElem=\"chip-icon\" size=\"sm\" [name]=\"fieldIcon()\" />\n <span rtElem=\"sizer\" rtTooltipWhenTruncated [rtTooltip]=\"chipText()\">\n <span rtElem=\"mirror\" aria-hidden=\"true\">{{ chipText() }}</span>\n <!-- Обрезка посередине: копия выше по-прежнему задаёт ширину и будит подсказку, а этот\n слой в той же клетке показывает начало с многоточием и конец, пока поле не в фокусе. -->\n @if (middleParts(); as parts) {\n <span rtElem=\"middle\" aria-hidden=\"true\">\n <span rtElem=\"head\">{{ parts.head }}</span>\n <span rtElem=\"tail\">{{ parts.tail }}</span>\n </span>\n }\n <input\n type=\"text\"\n rtElem=\"chip-input\"\n qa-dataid=\"inline-edit-chip-input\"\n [placeholder]=\"placeholder()\"\n [attr.aria-label]=\"fieldLabel() || placeholder() || null\"\n [formControl]=\"draftControl\"\n (focus)=\"onChipFocus($event)\"\n (blur)=\"onChipBlur()\"\n (keydown)=\"onChipKeydown($event)\" />\n </span>\n </label>\n } @else if (editing()) {\n <rt-input\n rtElem=\"field\"\n qa-dataid=\"inline-edit-field\"\n [size]=\"size()\"\n [placeholder]=\"placeholder()\"\n [ariaLabel]=\"fieldLabel() || placeholder() || null\"\n [clearable]=\"false\"\n [formControl]=\"draftControl\"\n (keydown)=\"onKeydown($event)\" />\n\n <rt-icon-button\n rtElem=\"save\"\n qa-dataid=\"inline-edit-save\"\n icon=\"check\"\n [size]=\"size()\"\n [ariaLabel]=\"saveLabel()\"\n [tooltip]=\"saveLabel()\"\n [loading]=\"saving()\"\n [disabled]=\"!canSave()\"\n (clicked)=\"save()\" />\n\n <rt-icon-button\n rtElem=\"cancel\"\n qa-dataid=\"inline-edit-cancel\"\n icon=\"close\"\n [size]=\"size()\"\n [ariaLabel]=\"cancelLabel()\"\n [tooltip]=\"cancelLabel()\"\n [disabled]=\"saving()\"\n (clicked)=\"cancel()\" />\n } @else {\n <button\n type=\"button\"\n rtElem=\"value\"\n qa-dataid=\"inline-edit-value\"\n [rtMod]=\"{ empty: isEmpty() }\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"startLabel()\"\n (click)=\"open()\">\n <span rtElem=\"text\" rtTooltipWhenTruncated [rtTooltip]=\"shown()\">{{ shown() }}</span>\n\n @if (!disabled()) {\n <rt-icon rtElem=\"pencil\" name=\"pencil\" size=\"sm\" />\n }\n </button>\n }\n</ng-container>\n"],"mappings":"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"}
1
+ {"version":3,"file":"rt-tools-ui-kit-v2-inline-edit.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/inline-edit/rt-inline-edit.logic.ts","../../../projects/ui-kit-v2/src/lib/components/inline-edit/rt-inline-edit.component.ts","../../../projects/ui-kit-v2/src/lib/components/inline-edit/rt-inline-edit.component.html"],"sourcesContent":["import { IRtInlineEdit } from './rt-inline-edit.model';\n\n/** Сколько знаков конца текста видно всегда при обрезке посередине. */\nconst MIDDLE_TAIL: number = 10;\n\n/**\n * Чем кончается сохранение черновика. Черновик обрезается по краям; пустой не уходит, пока его не\n * разрешили; равный значению закрывает поле и ничего не шлёт.\n */\nexport function inlineEditOutcome(value: string, draft: string, allowEmpty: boolean): IRtInlineEdit.Outcome {\n const next: string = draft.trim();\n\n if (next === '' && !allowEmpty) {\n return { kind: 'refuse' };\n }\n\n return next === value ? { kind: 'close' } : { kind: 'save', value: next };\n}\n\n/**\n * Текст для обрезки посередине: последние десять знаков видны всегда, многоточие встаёт в начале.\n * Текст не длиннее двух концов не режется — весь он идёт началом. Знаки считаются по кодовым точкам,\n * поэтому пара суррогатов не рвётся.\n */\nexport function inlineEditMiddle(text: string): IRtInlineEdit.MiddleParts {\n const chars: string[] = Array.from(text);\n\n if (chars.length <= MIDDLE_TAIL * 2) {\n return { head: text, tail: '' };\n }\n\n return { head: chars.slice(0, -MIDDLE_TAIL).join(''), tail: chars.slice(-MIDDLE_TAIL).join('') };\n}\n\n/**\n * Ушёл ли фокус из компонента. Переход на свои кнопки уходом не считается: нажатие «Сохранить» или\n * «Отмена» начинается с ухода фокуса из поля. Неизвестная цель — окно или пустое место — уход.\n */\nexport function inlineEditLeaves(host: Node, target: EventTarget | null): boolean {\n return !(target instanceof Node && host.contains(target));\n}\n","import {\n afterNextRender,\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n effect,\n ElementRef,\n inject,\n Injector,\n input,\n InputSignal,\n InputSignalWithTransform,\n model,\n ModelSignal,\n output,\n OutputEmitterRef,\n signal,\n Signal,\n untracked,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\nimport { FormControl, ReactiveFormsModule } from '@angular/forms';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { IRtIcon, IRtInput, rtKitLabel } from '@rt-tools/ui-kit-v2/core';\nimport { RtIconComponent } from '@rt-tools/ui-kit-v2/icon';\nimport { RtIconButtonComponent } from '@rt-tools/ui-kit-v2/icon-button';\nimport { RtInputComponent } from '@rt-tools/ui-kit-v2/input';\nimport { RtTooltipDirective } from '@rt-tools/ui-kit-v2/tooltip';\nimport { inlineEditLeaves, inlineEditMiddle, inlineEditOutcome } from './rt-inline-edit.logic';\nimport { IRtInlineEdit } from './rt-inline-edit.model';\n\nconst BEM_BLOCK: string = 'rt-inline-edit';\n\n/**\n * Правка короткого значения на месте. В покое значение — кнопка с карандашом; нажатие открывает поле\n * кита с черновиком, кнопкой сохранения и кнопкой отмены. Enter сохраняет, Escape отменяет.\n *\n * Значение принадлежит приложению: компонент отдаёт новое выходом и сам его не хранит. Приложение,\n * которое отвечает позже, держит поле открытым входом `closeOnSave` и закрывает его само.\n */\n@Component({\n selector: 'rt-inline-edit',\n templateUrl: './rt-inline-edit.component.html',\n styleUrl: './rt-inline-edit.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n ReactiveFormsModule,\n BlockDirective,\n ElemDirective,\n ModDirective,\n RtIconComponent,\n RtIconButtonComponent,\n RtInputComponent,\n RtTooltipDirective,\n ],\n host: {\n class: BEM_BLOCK,\n '[class.rt-inline-edit--chip]': \"look() === 'chip'\",\n '[class.rt-inline-edit--chip-field]': 'isChipField()',\n '[class.rt-inline-edit--size-md]': \"size() === 'md'\",\n '[class.rt-inline-edit--size-lg]': \"size() === 'lg'\",\n '(focusin)': 'onFocusIn()',\n '(focusout)': 'onFocusOut($event)',\n },\n})\nexport class RtInlineEditComponent {\n readonly #host: ElementRef<HTMLElement> = inject(ElementRef);\n readonly #injector: Injector = inject(Injector);\n\n readonly #t_uiEdit: Signal<string> = rtKitLabel('uiEdit');\n\n /**\n * Фокус был внутри и не ушёл на другой элемент страницы. Недоступное на время сохранения поле\n * роняет фокус в никуда, и без этой отметки его некуда вернуть, когда поле закроет приложение.\n */\n #focusInside: boolean = false;\n #wasEditing: boolean = false;\n #wasSaving: boolean = false;\n /** Фокус в поле плашки: пока человек правит, новое значение приложения не переписывает черновик. */\n #chipFocused: boolean = false;\n /** Enter или Escape уже сохранили черновик и снимают фокус сами: уход не сохраняет второй раз. */\n #chipLeaving: boolean = false;\n\n protected readonly saveLabel: Signal<string> = rtKitLabel('uiSave');\n protected readonly cancelLabel: Signal<string> = rtKitLabel('uiCancel');\n\n /** Что видно в покое: значение, а пустое — подсказка. */\n protected readonly shown: Signal<string> = computed((): string => this.value() || this.placeholder());\n protected readonly isEmpty: Signal<boolean> = computed((): boolean => this.value() === '');\n /** Имя кнопки покоя: действие и то, что правится. */\n protected readonly startLabel: Signal<string> = computed((): string => `${this.#t_uiEdit()}: ${this.shown()}`);\n\n /** Что набрано в открытом поле; зеркало поля для расчёта доступности сохранения. */\n readonly #draft: WritableSignal<string> = signal('');\n\n /**\n * Поле черновика. Форма, а не двусторонняя привязка: форма пишет значение в поле в том же\n * проходе отрисовки, и выделение текста при открытии застаёт его на месте.\n */\n protected readonly draftControl: FormControl<string> = new FormControl<string>('', { nonNullable: true });\n protected readonly canSave: Signal<boolean> = computed(\n (): boolean => inlineEditOutcome(this.value(), this.#draft(), this.allowEmpty()).kind !== 'refuse'\n );\n\n /** Плашка сама остаётся полем: нет покоя и открытия, нет кнопок. */\n protected readonly isChipField: Signal<boolean> = computed((): boolean => this.look() === 'chip-field');\n /** Текст, по которому плашка-поле берёт ширину: черновик, а пустой — подсказка. */\n protected readonly chipText: Signal<string> = computed((): string => this.#draft() || this.placeholder());\n /** Видимый вне фокуса текст плашки-поля, разрезанный посередине; пустой черновик не режется. */\n protected readonly middleParts: Signal<IRtInlineEdit.MiddleParts | null> = computed((): IRtInlineEdit.MiddleParts | null =>\n this.truncate() === 'middle' && this.#draft() !== '' ? inlineEditMiddle(this.#draft()) : null\n );\n\n /** Значение приложения: видно в покое и встаёт в поле при открытии. */\n public readonly value: InputSignal<string> = input.required<string>();\n /** Подсказка пустого значения в покое и пустого поля. */\n public readonly placeholder: InputSignal<string> = input<string>('');\n /** Вид в покое: строка текста или плашка. */\n public readonly look: InputSignal<IRtInlineEdit.Look> = input<IRtInlineEdit.Look>('text');\n /** Где плашка-поле режет длинный текст вне фокуса. Читается только видом `chip-field`. */\n public readonly truncate: InputSignal<IRtInlineEdit.Truncate> = input<IRtInlineEdit.Truncate>('end');\n /** Ступень поля и кнопок. */\n public readonly size: InputSignal<IRtInput.Size> = input<IRtInput.Size>('sm');\n /** Имя поля для чтения экрана; пусто — подсказка поля. */\n public readonly fieldLabel: InputSignal<string> = input<string>('');\n /** Компонент недоступен: поле не открывается. */\n public readonly disabled: InputSignalWithTransform<boolean, unknown> = input<boolean, unknown>(false, { transform: booleanAttribute });\n /** Приложение сохраняет: кнопка сохранения крутится, поле и отмена недоступны. */\n public readonly saving: InputSignalWithTransform<boolean, unknown> = input<boolean, unknown>(false, { transform: booleanAttribute });\n /** Пустой черновик сохраняется; выключено — кнопка сохранения недоступна. */\n public readonly allowEmpty: InputSignalWithTransform<boolean, unknown> = input<boolean, unknown>(false, {\n transform: booleanAttribute,\n });\n /** Поле закрывается при сохранении; выключено — его закрывает приложение через `editing`. */\n public readonly closeOnSave: InputSignalWithTransform<boolean, unknown> = input<boolean, unknown>(true, {\n transform: booleanAttribute,\n });\n /** Что делает уход фокуса из компонента. */\n public readonly blurAction: InputSignal<IRtInlineEdit.BlurAction> = input<IRtInlineEdit.BlurAction>('keep');\n /** Значок перед текстом плашки-поля: имя значка кита. */\n public readonly fieldIcon: InputSignal<IRtIcon.Name> = input<IRtIcon.Name>('pencil');\n\n /** Поле открыто. Приложение может открыть и закрыть его само. */\n public readonly editing: ModelSignal<boolean> = model<boolean>(false);\n\n /** Новое значение, уже обрезанное по краям. Равное прежнему не уходит. */\n public readonly saved: OutputEmitterRef<string> = output<string>();\n /** Правка отменена: поле закрыто, значение прежнее. */\n public readonly cancelled: OutputEmitterRef<void> = output<void>();\n\n constructor() {\n this.draftControl.valueChanges.pipe(takeUntilDestroyed()).subscribe((draft: string): void => this.#draft.set(draft));\n\n // Поле открылось — нажатием или входом приложения: черновик берёт значение, фокус встаёт в поле.\n // Поле закрылось — своей кнопкой или входом приложения: фокус возвращается на значение.\n effect((): void => {\n const editing: boolean = this.editing();\n\n if (editing) {\n this.draftControl.setValue(untracked(this.value));\n afterNextRender((): void => this.focusField(), { injector: this.#injector });\n } else if (this.#wasEditing) {\n this.#restoreFocus('.rt-inline-edit__value');\n } else {\n // Покой без перехода: фокус никто не трогает.\n }\n this.#wasEditing = editing;\n });\n\n // Плашка-поле показывает значение приложения, пока человек её не правит.\n effect((): void => {\n const value: string = this.value();\n\n if (this.isChipField() && !this.#chipFocused) {\n this.draftControl.setValue(value);\n }\n });\n\n // Пока приложение сохраняет, поле недоступно; отказ оставил поле открытым — фокус снова в нём.\n // Плашка-поле всегда на месте, и недоступный компонент запирает её саму.\n effect((): void => {\n const saving: boolean = this.saving();\n\n if (saving || (this.isChipField() && this.disabled())) {\n this.draftControl.disable({ emitEvent: false });\n } else {\n this.draftControl.enable({ emitEvent: false });\n if (this.#wasSaving && untracked(this.editing)) {\n this.#restoreFocus('.rt-inline-edit__field input');\n }\n }\n this.#wasSaving = saving;\n });\n }\n\n /** Нажатие на значение в покое. */\n public open(): void {\n if (this.disabled() || this.editing()) {\n return;\n }\n this.editing.set(true);\n }\n\n public save(): void {\n if (this.saving()) {\n return;\n }\n const outcome: IRtInlineEdit.Outcome = inlineEditOutcome(this.value(), this.draftControl.value, this.allowEmpty());\n\n if (outcome.kind === 'refuse') {\n return;\n }\n if (outcome.kind === 'save') {\n this.saved.emit(outcome.value);\n if (!this.closeOnSave()) {\n return;\n }\n }\n this.#close();\n }\n\n public cancel(): void {\n if (this.saving()) {\n return;\n }\n this.#close();\n this.cancelled.emit();\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n if (event.key === 'Enter') {\n event.preventDefault();\n this.save();\n } else if (event.key === 'Escape') {\n // Escape принадлежит полю: окно или панель вокруг не закрываются вместе с правкой.\n event.preventDefault();\n event.stopPropagation();\n this.cancel();\n } else {\n // Остальные клавиши правят черновик в самом поле.\n }\n }\n\n protected onFocusIn(): void {\n this.#focusInside = true;\n }\n\n protected onFocusOut(event: FocusEvent): void {\n if (event.relatedTarget instanceof Node && !this.#host.nativeElement.contains(event.relatedTarget)) {\n this.#focusInside = false;\n }\n if (!this.editing() || this.saving() || !inlineEditLeaves(this.#host.nativeElement, event.relatedTarget)) {\n return;\n }\n if (this.blurAction() === 'save') {\n this.save();\n } else if (this.blurAction() === 'cancel') {\n this.cancel();\n } else {\n // Поле держится открытым: случайное нажатие мимо не теряет набранное.\n }\n }\n\n /** Фокус пришёл в плашку-поле: весь текст выделен, и первое нажатие заменяет значение целиком. */\n protected onChipFocus(event: FocusEvent): void {\n this.#chipFocused = true;\n if (event.target instanceof HTMLInputElement) {\n event.target.select();\n }\n }\n\n /** Уход из плашки-поля сохраняет черновик. */\n protected onChipBlur(): void {\n this.#chipFocused = false;\n if (!this.#chipLeaving) {\n this.#commitChip();\n }\n }\n\n protected onChipKeydown(event: KeyboardEvent): void {\n if (event.key === 'Enter') {\n event.preventDefault();\n this.#leaveChip(event);\n } else if (event.key === 'Escape') {\n // Escape принадлежит полю: окно или панель вокруг не закрываются вместе с правкой.\n event.preventDefault();\n event.stopPropagation();\n this.draftControl.setValue(this.value());\n this.#leaveChip(event);\n this.cancelled.emit();\n } else {\n // Остальные клавиши правят черновик в самом поле.\n }\n }\n\n /** Фокус в поле и весь текст выделен: первое нажатие клавиши заменяет значение целиком. */\n protected focusField(): void {\n const field: HTMLInputElement | null = this.#host.nativeElement.querySelector('.rt-inline-edit__field input');\n\n field?.focus();\n field?.select();\n }\n\n #close(): void {\n this.editing.set(false);\n }\n\n /**\n * Черновик плашки-поля уходит приложению. Пустой, который не разрешён, и равный значению молча\n * возвращают значение: у плашки нет недоступной кнопки, которой можно было бы отказать.\n */\n #commitChip(): void {\n if (this.saving()) {\n return;\n }\n const outcome: IRtInlineEdit.Outcome = inlineEditOutcome(this.value(), this.draftControl.value, this.allowEmpty());\n\n if (outcome.kind === 'save') {\n this.saved.emit(outcome.value);\n this.draftControl.setValue(outcome.value);\n } else {\n this.draftControl.setValue(this.value());\n }\n }\n\n /** Enter и Escape сохраняют сами и снимают фокус: уход, который за этим следует, не сохраняет второй раз. */\n #leaveChip(event: KeyboardEvent): void {\n const target: EventTarget | null = event.target;\n\n this.#commitChip();\n if (target instanceof HTMLElement && target.ownerDocument.activeElement === target) {\n this.#chipLeaving = true;\n target.blur();\n this.#chipLeaving = false;\n }\n }\n\n /**\n * Фокус, бывший внутри, возвращается на элемент компонента после отрисовки. Ушедший на другой\n * элемент страницы не трогается: человек уже там.\n */\n #restoreFocus(selector: string): void {\n const host: HTMLElement = this.#host.nativeElement;\n const active: Element | null = host.ownerDocument.activeElement;\n\n if (!this.#focusInside || (active !== null && active !== host.ownerDocument.body && !host.contains(active))) {\n return;\n }\n afterNextRender((): void => host.querySelector<HTMLElement>(selector)?.focus(), { injector: this.#injector });\n }\n}\n","<ng-container rtBlock=\"rt-inline-edit\">\n @if (isChipField()) {\n <!-- Плашка-поле: значок и поле внутри одной плашки. Ширину задаёт невидимая копия текста под\n полем — плашка растёт с текстом до своего предела, дальше поле прокручивается. -->\n <label rtElem=\"chip-field\" [rtMod]=\"{ disabled: disabled() }\">\n <rt-icon rtElem=\"chip-icon\" size=\"sm\" [name]=\"fieldIcon()\" />\n <span rtElem=\"sizer\" rtTooltipWhenTruncated [rtTooltip]=\"chipText()\">\n <span rtElem=\"mirror\" aria-hidden=\"true\">{{ chipText() }}</span>\n <!-- Обрезка посередине: копия выше по-прежнему задаёт ширину и будит подсказку, а этот\n слой в той же клетке показывает начало с многоточием и конец, пока поле не в фокусе. -->\n @if (middleParts(); as parts) {\n <span rtElem=\"middle\" aria-hidden=\"true\">\n <span rtElem=\"head\">{{ parts.head }}</span>\n <span rtElem=\"tail\">{{ parts.tail }}</span>\n </span>\n }\n <input\n type=\"text\"\n rtElem=\"chip-input\"\n qa-dataid=\"inline-edit-chip-input\"\n [placeholder]=\"placeholder()\"\n [attr.aria-label]=\"fieldLabel() || placeholder() || null\"\n [formControl]=\"draftControl\"\n (focus)=\"onChipFocus($event)\"\n (blur)=\"onChipBlur()\"\n (keydown)=\"onChipKeydown($event)\" />\n </span>\n </label>\n } @else if (editing()) {\n <rt-input\n rtElem=\"field\"\n qa-dataid=\"inline-edit-field\"\n [size]=\"size()\"\n [placeholder]=\"placeholder()\"\n [ariaLabel]=\"fieldLabel() || placeholder() || null\"\n [clearable]=\"false\"\n [formControl]=\"draftControl\"\n (keydown)=\"onKeydown($event)\" />\n\n <rt-icon-button\n rtElem=\"save\"\n qa-dataid=\"inline-edit-save\"\n icon=\"check\"\n [size]=\"size()\"\n [ariaLabel]=\"saveLabel()\"\n [tooltip]=\"saveLabel()\"\n [loading]=\"saving()\"\n [disabled]=\"!canSave()\"\n (clicked)=\"save()\" />\n\n <rt-icon-button\n rtElem=\"cancel\"\n qa-dataid=\"inline-edit-cancel\"\n icon=\"close\"\n [size]=\"size()\"\n [ariaLabel]=\"cancelLabel()\"\n [tooltip]=\"cancelLabel()\"\n [disabled]=\"saving()\"\n (clicked)=\"cancel()\" />\n } @else {\n <button\n type=\"button\"\n rtElem=\"value\"\n qa-dataid=\"inline-edit-value\"\n [rtMod]=\"{ empty: isEmpty() }\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"startLabel()\"\n (click)=\"open()\">\n <span rtElem=\"text\" rtTooltipWhenTruncated [rtTooltip]=\"shown()\">{{ shown() }}</span>\n\n @if (!disabled()) {\n <rt-icon rtElem=\"pencil\" name=\"pencil\" size=\"sm\" />\n }\n </button>\n }\n</ng-container>\n"],"mappings":"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"}
@@ -362,6 +362,7 @@ var RtMultiselectComponent = class RtMultiselectComponent extends RtFormControlB
362
362
  "rtPopoverFitViewport",
363
363
  "rtPopoverContext",
364
364
  "rtPopoverPanelClass",
365
+ "rtPopoverBackdropClass",
365
366
  "rtPopoverDisabled",
366
367
  "rtPopoverOffsetY",
367
368
  "rtPopoverOffsetX",