@rt-tools/ui-kit-v2 0.32.0 → 0.34.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 (220) hide show
  1. package/README.md +4 -3
  2. package/fesm2022/rt-tools-ui-kit-v2-ai-run-status.mjs +1 -0
  3. package/fesm2022/rt-tools-ui-kit-v2-ai-run-status.mjs.map +1 -1
  4. package/fesm2022/rt-tools-ui-kit-v2-autocomplete.mjs +92 -5
  5. package/fesm2022/rt-tools-ui-kit-v2-autocomplete.mjs.map +1 -1
  6. package/fesm2022/rt-tools-ui-kit-v2-badge.mjs +191 -0
  7. package/fesm2022/rt-tools-ui-kit-v2-badge.mjs.map +1 -0
  8. package/fesm2022/rt-tools-ui-kit-v2-breadcrumbs.mjs +3 -2
  9. package/fesm2022/rt-tools-ui-kit-v2-breadcrumbs.mjs.map +1 -1
  10. package/fesm2022/rt-tools-ui-kit-v2-button.mjs +6 -1
  11. package/fesm2022/rt-tools-ui-kit-v2-button.mjs.map +1 -1
  12. package/fesm2022/rt-tools-ui-kit-v2-checkbox.mjs +35 -4
  13. package/fesm2022/rt-tools-ui-kit-v2-checkbox.mjs.map +1 -1
  14. package/fesm2022/rt-tools-ui-kit-v2-color-palette.mjs +13 -4
  15. package/fesm2022/rt-tools-ui-kit-v2-color-palette.mjs.map +1 -1
  16. package/fesm2022/rt-tools-ui-kit-v2-container.mjs +245 -60
  17. package/fesm2022/rt-tools-ui-kit-v2-container.mjs.map +1 -1
  18. package/fesm2022/rt-tools-ui-kit-v2-copy-value.mjs +30 -5
  19. package/fesm2022/rt-tools-ui-kit-v2-copy-value.mjs.map +1 -1
  20. package/fesm2022/rt-tools-ui-kit-v2-core.mjs +114 -2
  21. package/fesm2022/rt-tools-ui-kit-v2-core.mjs.map +1 -1
  22. package/fesm2022/rt-tools-ui-kit-v2-data-list.mjs +14 -3
  23. package/fesm2022/rt-tools-ui-kit-v2-data-list.mjs.map +1 -1
  24. package/fesm2022/rt-tools-ui-kit-v2-data-table.mjs +17 -3
  25. package/fesm2022/rt-tools-ui-kit-v2-data-table.mjs.map +1 -1
  26. package/fesm2022/rt-tools-ui-kit-v2-date-picker.mjs +6 -3
  27. package/fesm2022/rt-tools-ui-kit-v2-date-picker.mjs.map +1 -1
  28. package/fesm2022/rt-tools-ui-kit-v2-date-range.mjs +2 -2
  29. package/fesm2022/rt-tools-ui-kit-v2-date-range.mjs.map +1 -1
  30. package/fesm2022/rt-tools-ui-kit-v2-divider.mjs +112 -0
  31. package/fesm2022/rt-tools-ui-kit-v2-divider.mjs.map +1 -0
  32. package/fesm2022/rt-tools-ui-kit-v2-draggable-tree.mjs +1 -0
  33. package/fesm2022/rt-tools-ui-kit-v2-draggable-tree.mjs.map +1 -1
  34. package/fesm2022/rt-tools-ui-kit-v2-drawer.mjs +854 -0
  35. package/fesm2022/rt-tools-ui-kit-v2-drawer.mjs.map +1 -0
  36. package/fesm2022/rt-tools-ui-kit-v2-dynamic-list.mjs +16 -5
  37. package/fesm2022/rt-tools-ui-kit-v2-dynamic-list.mjs.map +1 -1
  38. package/fesm2022/rt-tools-ui-kit-v2-dynamic-selector.mjs +580 -65
  39. package/fesm2022/rt-tools-ui-kit-v2-dynamic-selector.mjs.map +1 -1
  40. package/fesm2022/rt-tools-ui-kit-v2-expansion-panel.mjs +203 -15
  41. package/fesm2022/rt-tools-ui-kit-v2-expansion-panel.mjs.map +1 -1
  42. package/fesm2022/rt-tools-ui-kit-v2-field.mjs +40 -8
  43. package/fesm2022/rt-tools-ui-kit-v2-field.mjs.map +1 -1
  44. package/fesm2022/rt-tools-ui-kit-v2-file-card.mjs +1 -0
  45. package/fesm2022/rt-tools-ui-kit-v2-file-card.mjs.map +1 -1
  46. package/fesm2022/rt-tools-ui-kit-v2-filter-control.mjs +7 -3
  47. package/fesm2022/rt-tools-ui-kit-v2-filter-control.mjs.map +1 -1
  48. package/fesm2022/rt-tools-ui-kit-v2-form-control.mjs +53 -2
  49. package/fesm2022/rt-tools-ui-kit-v2-form-control.mjs.map +1 -1
  50. package/fesm2022/rt-tools-ui-kit-v2-hybrid-tree-selector.mjs +14 -4
  51. package/fesm2022/rt-tools-ui-kit-v2-hybrid-tree-selector.mjs.map +1 -1
  52. package/fesm2022/rt-tools-ui-kit-v2-hybrid-tree.mjs +6 -3
  53. package/fesm2022/rt-tools-ui-kit-v2-hybrid-tree.mjs.map +1 -1
  54. package/fesm2022/rt-tools-ui-kit-v2-icon-button.mjs +16 -5
  55. package/fesm2022/rt-tools-ui-kit-v2-icon-button.mjs.map +1 -1
  56. package/fesm2022/rt-tools-ui-kit-v2-image-upload.mjs +1 -0
  57. package/fesm2022/rt-tools-ui-kit-v2-image-upload.mjs.map +1 -1
  58. package/fesm2022/rt-tools-ui-kit-v2-inline-edit.mjs +14 -4
  59. package/fesm2022/rt-tools-ui-kit-v2-inline-edit.mjs.map +1 -1
  60. package/fesm2022/rt-tools-ui-kit-v2-input-number.mjs +3 -2
  61. package/fesm2022/rt-tools-ui-kit-v2-input-number.mjs.map +1 -1
  62. package/fesm2022/rt-tools-ui-kit-v2-input.mjs +207 -7
  63. package/fesm2022/rt-tools-ui-kit-v2-input.mjs.map +1 -1
  64. package/fesm2022/rt-tools-ui-kit-v2-menu.mjs +1 -0
  65. package/fesm2022/rt-tools-ui-kit-v2-menu.mjs.map +1 -1
  66. package/fesm2022/rt-tools-ui-kit-v2-multiselect.mjs +3 -2
  67. package/fesm2022/rt-tools-ui-kit-v2-multiselect.mjs.map +1 -1
  68. package/fesm2022/rt-tools-ui-kit-v2-page-header.mjs +2 -0
  69. package/fesm2022/rt-tools-ui-kit-v2-page-header.mjs.map +1 -1
  70. package/fesm2022/rt-tools-ui-kit-v2-pagination.mjs +3 -2
  71. package/fesm2022/rt-tools-ui-kit-v2-pagination.mjs.map +1 -1
  72. package/fesm2022/rt-tools-ui-kit-v2-profile-menu.mjs +3 -2
  73. package/fesm2022/rt-tools-ui-kit-v2-profile-menu.mjs.map +1 -1
  74. package/fesm2022/rt-tools-ui-kit-v2-progress-bar.mjs +171 -0
  75. package/fesm2022/rt-tools-ui-kit-v2-progress-bar.mjs.map +1 -0
  76. package/fesm2022/rt-tools-ui-kit-v2-radio-button.mjs +176 -6
  77. package/fesm2022/rt-tools-ui-kit-v2-radio-button.mjs.map +1 -1
  78. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs +9 -6
  79. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs.map +1 -1
  80. package/fesm2022/rt-tools-ui-kit-v2-scroll-area.mjs +1 -0
  81. package/fesm2022/rt-tools-ui-kit-v2-scroll-area.mjs.map +1 -1
  82. package/fesm2022/rt-tools-ui-kit-v2-select.mjs +142 -23
  83. package/fesm2022/rt-tools-ui-kit-v2-select.mjs.map +1 -1
  84. package/fesm2022/rt-tools-ui-kit-v2-side-menu.mjs +22 -9
  85. package/fesm2022/rt-tools-ui-kit-v2-side-menu.mjs.map +1 -1
  86. package/fesm2022/rt-tools-ui-kit-v2-speed-menu.mjs +3 -2
  87. package/fesm2022/rt-tools-ui-kit-v2-speed-menu.mjs.map +1 -1
  88. package/fesm2022/rt-tools-ui-kit-v2-stepper.mjs +105 -8
  89. package/fesm2022/rt-tools-ui-kit-v2-stepper.mjs.map +1 -1
  90. package/fesm2022/rt-tools-ui-kit-v2-table.mjs +13 -2
  91. package/fesm2022/rt-tools-ui-kit-v2-table.mjs.map +1 -1
  92. package/fesm2022/rt-tools-ui-kit-v2-tabs.mjs +609 -33
  93. package/fesm2022/rt-tools-ui-kit-v2-tabs.mjs.map +1 -1
  94. package/fesm2022/rt-tools-ui-kit-v2-tag.mjs +1 -0
  95. package/fesm2022/rt-tools-ui-kit-v2-tag.mjs.map +1 -1
  96. package/fesm2022/rt-tools-ui-kit-v2-textarea.mjs +45 -7
  97. package/fesm2022/rt-tools-ui-kit-v2-textarea.mjs.map +1 -1
  98. package/fesm2022/rt-tools-ui-kit-v2-theme-toggle.mjs +2 -2
  99. package/fesm2022/rt-tools-ui-kit-v2-theme-toggle.mjs.map +1 -1
  100. package/fesm2022/rt-tools-ui-kit-v2-thread-list.mjs +11 -2
  101. package/fesm2022/rt-tools-ui-kit-v2-thread-list.mjs.map +1 -1
  102. package/fesm2022/rt-tools-ui-kit-v2-toast.mjs +152 -11
  103. package/fesm2022/rt-tools-ui-kit-v2-toast.mjs.map +1 -1
  104. package/fesm2022/rt-tools-ui-kit-v2-toggle-button-group.mjs +199 -17
  105. package/fesm2022/rt-tools-ui-kit-v2-toggle-button-group.mjs.map +1 -1
  106. package/fesm2022/rt-tools-ui-kit-v2-tooltip.mjs +35 -5
  107. package/fesm2022/rt-tools-ui-kit-v2-tooltip.mjs.map +1 -1
  108. package/fesm2022/rt-tools-ui-kit-v2-tree-selector.mjs +14 -4
  109. package/fesm2022/rt-tools-ui-kit-v2-tree-selector.mjs.map +1 -1
  110. package/fesm2022/rt-tools-ui-kit-v2-tree.mjs +6 -3
  111. package/fesm2022/rt-tools-ui-kit-v2-tree.mjs.map +1 -1
  112. package/fesm2022/rt-tools-ui-kit-v2-workspace-details.mjs +21 -6
  113. package/fesm2022/rt-tools-ui-kit-v2-workspace-details.mjs.map +1 -1
  114. package/fesm2022/rt-tools-ui-kit-v2.mjs +4 -0
  115. package/package.json +17 -1
  116. package/src/assets/icons/volume-off.svg +2 -1
  117. package/src/lib/components/autocomplete/CONTEXT.md +25 -14
  118. package/src/lib/components/autocomplete/rt-autocomplete.component.scss +19 -0
  119. package/src/lib/components/badge/CONTEXT.md +33 -0
  120. package/src/lib/components/badge/rt-badge.directive.scss +104 -0
  121. package/src/lib/components/breadcrumbs/rt-breadcrumbs.component.scss +2 -2
  122. package/src/lib/components/button/CONTEXT.md +5 -0
  123. package/src/lib/components/button/rt-button.directive.scss +3 -1
  124. package/src/lib/components/checkbox/CONTEXT.md +15 -8
  125. package/src/lib/components/color-palette/rt-color-palette.component.scss +2 -2
  126. package/src/lib/components/container/CONTEXT.md +23 -6
  127. package/src/lib/components/container/rt-container.component.scss +90 -1
  128. package/src/lib/components/copy-value/CONTEXT.md +6 -5
  129. package/src/lib/components/copy-value/rt-copy-value.component.scss +16 -0
  130. package/src/lib/components/date-picker/rt-date-picker.component.scss +7 -0
  131. package/src/lib/components/date-range/rt-date-range.component.scss +7 -0
  132. package/src/lib/components/divider/CONTEXT.md +21 -0
  133. package/src/lib/components/divider/rt-divider.component.scss +34 -0
  134. package/src/lib/components/drawer/CONTEXT.md +73 -0
  135. package/src/lib/components/drawer/rt-drawer-container.component.scss +19 -0
  136. package/src/lib/components/drawer/rt-drawer.component.scss +168 -0
  137. package/src/lib/components/drawer/rt-resize-handle.component.scss +42 -0
  138. package/src/lib/components/dynamic-selector/CONTEXT.md +5 -0
  139. package/src/lib/components/expansion-panel/CONTEXT.md +32 -8
  140. package/src/lib/components/expansion-panel/rt-expansion-panel.component.scss +67 -2
  141. package/src/lib/components/field/CONTEXT.md +43 -0
  142. package/src/lib/components/field/rt-field-label-inside.scss +179 -0
  143. package/src/lib/components/field/rt-field.component.scss +51 -2
  144. package/src/lib/components/icon-button/CONTEXT.md +17 -15
  145. package/src/lib/components/icon-button/rt-icon-button.component.scss +3 -1
  146. package/src/lib/components/inline-edit/rt-inline-edit.component.scss +4 -4
  147. package/src/lib/components/input/CONTEXT.md +45 -11
  148. package/src/lib/components/input/rt-input-floating-label.scss +192 -0
  149. package/src/lib/components/input/rt-input-icons.scss +105 -0
  150. package/src/lib/components/input/rt-input.component.scss +91 -13
  151. package/src/lib/components/input-number/CONTEXT.md +7 -0
  152. package/src/lib/components/input-number/rt-input-number.component.scss +58 -1
  153. package/src/lib/components/menu/CONTEXT.md +1 -0
  154. package/src/lib/components/multiselect/CONTEXT.md +2 -1
  155. package/src/lib/components/multiselect/rt-multiselect.component.scss +7 -0
  156. package/src/lib/components/pagination/CONTEXT.md +3 -0
  157. package/src/lib/components/pagination/rt-pagination.component.scss +7 -0
  158. package/src/lib/components/progress-bar/CONTEXT.md +22 -0
  159. package/src/lib/components/progress-bar/rt-progress-bar.component.scss +77 -0
  160. package/src/lib/components/radio-button/CONTEXT.md +9 -0
  161. package/src/lib/components/radio-button/rt-radio-group.component.scss +13 -0
  162. package/src/lib/components/select/CONTEXT.md +28 -0
  163. package/src/lib/components/select/rt-select-clear.scss +88 -0
  164. package/src/lib/components/select/rt-select-floating-label.scss +155 -0
  165. package/src/lib/components/select/rt-select-material.scss +54 -0
  166. package/src/lib/components/select/rt-select.component.scss +54 -16
  167. package/src/lib/components/side-menu/CONTEXT.md +5 -0
  168. package/src/lib/components/speed-menu/rt-speed-menu.component.scss +5 -5
  169. package/src/lib/components/stepper/CONTEXT.md +13 -5
  170. package/src/lib/components/stepper/rt-stepper.component.scss +93 -0
  171. package/src/lib/components/tabs/CONTEXT.md +57 -9
  172. package/src/lib/components/tabs/rt-tabs.component.scss +201 -5
  173. package/src/lib/components/textarea/CONTEXT.md +12 -1
  174. package/src/lib/components/textarea/rt-textarea.component.scss +116 -1
  175. package/src/lib/components/toast/CONTEXT.md +23 -0
  176. package/src/lib/components/toast/rt-toast.component.scss +37 -0
  177. package/src/lib/components/toggle-button-group/CONTEXT.md +24 -4
  178. package/src/lib/components/toggle-button-group/rt-toggle-button-group-chips.scss +151 -0
  179. package/src/lib/components/toggle-button-group/rt-toggle-button-group.component.scss +35 -0
  180. package/src/lib/components/tooltip/CONTEXT.md +7 -1
  181. package/src/lib/components/tree/rt-tree.component.scss +2 -2
  182. package/src/rich-editor/lib/components/chat/CONTEXT.md +3 -0
  183. package/src/rich-editor/lib/components/chat/rt-chat.component.scss +9 -0
  184. package/src/styles/_color-scheme.scss +1 -1
  185. package/src/styles/_density.scss +48 -0
  186. package/src/styles/_index.scss +8 -0
  187. package/src/styles/_preset-material.scss +160 -70
  188. package/src/styles/_primitives.scss +1 -0
  189. package/src/styles/_semantic-navigation.scss +117 -0
  190. package/src/styles/_semantic.scss +29 -98
  191. package/src/styles/_theme-dark.scss +8 -0
  192. package/styles/tokens.css +2066 -1134
  193. package/types/rt-tools-ui-kit-v2-autocomplete.d.ts +34 -0
  194. package/types/rt-tools-ui-kit-v2-badge.d.ts +71 -0
  195. package/types/rt-tools-ui-kit-v2-checkbox.d.ts +17 -3
  196. package/types/rt-tools-ui-kit-v2-container.d.ts +65 -9
  197. package/types/rt-tools-ui-kit-v2-copy-value.d.ts +11 -1
  198. package/types/rt-tools-ui-kit-v2-core.d.ts +110 -4
  199. package/types/rt-tools-ui-kit-v2-divider.d.ts +29 -0
  200. package/types/rt-tools-ui-kit-v2-drawer.d.ts +257 -0
  201. package/types/rt-tools-ui-kit-v2-dynamic-selector.d.ts +240 -25
  202. package/types/rt-tools-ui-kit-v2-expansion-panel.d.ts +87 -3
  203. package/types/rt-tools-ui-kit-v2-field.d.ts +18 -1
  204. package/types/rt-tools-ui-kit-v2-form-control.d.ts +42 -4
  205. package/types/rt-tools-ui-kit-v2-icon-button.d.ts +2 -1
  206. package/types/rt-tools-ui-kit-v2-input-number.d.ts +1 -0
  207. package/types/rt-tools-ui-kit-v2-input.d.ts +98 -4
  208. package/types/rt-tools-ui-kit-v2-progress-bar.d.ts +53 -0
  209. package/types/rt-tools-ui-kit-v2-radio-button.d.ts +80 -1
  210. package/types/rt-tools-ui-kit-v2-rich-editor.d.ts +5 -2
  211. package/types/rt-tools-ui-kit-v2-select.d.ts +65 -1
  212. package/types/rt-tools-ui-kit-v2-side-menu.d.ts +3 -0
  213. package/types/rt-tools-ui-kit-v2-stepper.d.ts +57 -4
  214. package/types/rt-tools-ui-kit-v2-tabs.d.ts +291 -6
  215. package/types/rt-tools-ui-kit-v2-textarea.d.ts +16 -0
  216. package/types/rt-tools-ui-kit-v2-toast.d.ts +38 -2
  217. package/types/rt-tools-ui-kit-v2-toggle-button-group.d.ts +83 -3
  218. package/types/rt-tools-ui-kit-v2-tooltip.d.ts +17 -2
  219. package/types/rt-tools-ui-kit-v2.d.ts +4 -0
  220. package/src/lib/components/dynamic-selector/stories/component/test-dynamic-selector-popup-frame.component.scss +0 -6
@@ -1 +1 @@
1
- {"version":3,"file":"rt-tools-ui-kit-v2-toggle-button-group.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/toggle-button-group/rt-toggle-button-group.component.ts","../../../projects/ui-kit-v2/src/lib/components/toggle-button-group/rt-toggle-button-group.component.html"],"sourcesContent":["import { BooleanInput } from '@angular/cdk/coercion';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n input,\n InputSignal,\n InputSignalWithTransform,\n output,\n OutputEmitterRef,\n Signal,\n ViewEncapsulation,\n} from '@angular/core';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { RtIconComponent } from '@rt-tools/ui-kit-v2/icon';\nimport { IRtIcon } from '@rt-tools/ui-kit-v2/core';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\nimport { RtTooltipDirective } from '@rt-tools/ui-kit-v2/tooltip';\nimport { IRtToggleButtonGroup } from './rt-toggle-button-group.model';\n\nconst BEM_BLOCK: string = 'rt-toggle-button-group';\n\n/**\n * Маппинг размера группы на размер вложенной `<rt-icon>`. rt-icon не имеет\n * промежуточных значений (12 / 16 / 20 / 24 / 32), поэтому `lg` тоже едет\n * на `sm` (16px) — ближе к расчётным 18px у rt-button lg, чем md (20px).\n */\nconst ICON_SIZE_BY_SIZE: Readonly<Record<IRtToggleButtonGroup.Size, IRtIcon.Size>> = Object.freeze({\n sm: 'xs',\n md: 'sm',\n lg: 'sm',\n});\n\n/**\n * Generic segmented control кита.\n *\n * API `toggle-button-group` с тремя особенностями:\n * 1. BEM через `rtBlock/rtElem/rtMod` (camelCase mods → kebab-case в CSS).\n * 2. Tooltip — нативный `[attr.title]` вместо `MatTooltip` (Angular Material\n * запрещён, см. CLAUDE.md).\n * 3. Визуал — текстовые лейблы + опциональная иконка, а не icon-only кнопки.\n * Иконка остаётся опциональной, чтобы покрыть оба сценария.\n *\n * Компонент \"controlled\" — рендерит сегмент с `value === option.value` как\n * активный, эмиттит `valueChange` при клике, обновление `value` остаётся за\n * потребителем.\n *\n * Generic `<T = string>` сохраняет типизацию по value (`'list' | 'grid'`,\n * union'ы, enum'ы). Дефолт `string` нужен, чтобы шаблон-инстанцирование\n * без явного параметра компилировалось.\n */\n@Component({\n selector: 'rt-toggle-button-group',\n templateUrl: './rt-toggle-button-group.component.html',\n styleUrls: ['./rt-toggle-button-group.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // standalone components / directives\n RtIconComponent,\n RtTooltipDirective,\n BlockDirective,\n ElemDirective,\n ModDirective,\n ],\n hostDirectives: [{ directive: RtRadiusDirective, inputs: ['radius'] }],\n host: {\n class: BEM_BLOCK,\n '[class.rt-toggle-button-group--full-width]': 'fullWidth()',\n '[class.rt-toggle-button-group--md]': \"size() === 'md'\",\n '[class.rt-toggle-button-group--lg]': \"size() === 'lg'\",\n },\n})\nexport class RtToggleButtonGroupComponent<T = string> {\n protected readonly iconSize: Signal<IRtIcon.Size> = computed((): IRtIcon.Size => ICON_SIZE_BY_SIZE[this.size()]);\n\n /**\n * Сегменты, готовые к отрисовке: подсветка и недоступность посчитаны здесь, а не в шаблоне.\n *\n * Подсветка читается по-разному в одиночном и множественном выборе, а недоступность приходит\n * с двух сторон — от группы и от самого сегмента. Признак группы главнее: доступный сегмент\n * внутри отключённой группы читался бы как её единственное живое место.\n */\n protected readonly items: Signal<ReadonlyArray<IRtToggleButtonGroup.Rendered<T>>> = computed(\n (): ReadonlyArray<IRtToggleButtonGroup.Rendered<T>> => {\n const multiple: boolean = this.multiple();\n const chosen: ReadonlyArray<T> = this.values();\n const single: T | undefined = this.value();\n const groupDisabled: boolean = this.disabled();\n\n return this.options().map((option: IRtToggleButtonGroup.Option<T>): IRtToggleButtonGroup.Rendered<T> => ({\n option,\n active: multiple ? chosen.includes(option.value) : single === option.value,\n disabled: groupDisabled || !!option.disabled,\n }));\n }\n );\n\n public readonly options: InputSignal<ReadonlyArray<IRtToggleButtonGroup.Option<T>>> =\n input.required<ReadonlyArray<IRtToggleButtonGroup.Option<T>>>();\n\n public readonly value: InputSignal<T | undefined> = input<T | undefined>(undefined);\n\n /**\n * Множественный выбор: нажатие добавляет сегмент или снимает его, а не переносит выбор.\n *\n * Своим входом, а не расширением типа `value`: вход, у которого тип значения меняется от\n * значения другого входа, не проверяет ни сборка, ни линтер — потребитель узнаёт о своей\n * ошибке, когда группа перестаёт подсвечивать выбранное.\n */\n public readonly multiple: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Набор выбранного. Читается только при множественном выборе, одиночный берёт `value`. */\n public readonly values: InputSignal<ReadonlyArray<T>> = input<ReadonlyArray<T>>([]);\n\n public readonly ariaLabel: InputSignal<string | null> = input<string | null>(null);\n\n public readonly size: InputSignal<IRtToggleButtonGroup.Size> = input<IRtToggleButtonGroup.Size>('sm');\n\n public readonly disabled: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Растягивает группу на всю ширину контейнера; опции делят ширину поровну. */\n public readonly fullWidth: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n public readonly valueChange: OutputEmitterRef<T> = output<T>();\n\n /**\n * Весь набор выбранного после нажатия, а не разница с прежним: разницу вызывающий сводит со\n * своим состоянием сам, и каждый сводит по-своему.\n */\n public readonly valuesChange: OutputEmitterRef<ReadonlyArray<T>> = output<ReadonlyArray<T>>();\n\n protected onOptionClick(item: IRtToggleButtonGroup.Rendered<T>): void {\n if (item.disabled) {\n return;\n }\n\n const option: IRtToggleButtonGroup.Option<T> = item.option;\n\n if (!this.multiple()) {\n this.valueChange.emit(option.value);\n\n return;\n }\n\n const chosen: ReadonlyArray<T> = this.values();\n const next: T[] = chosen.includes(option.value)\n ? chosen.filter((one: T): boolean => one !== option.value)\n : [...chosen, option.value];\n\n this.valuesChange.emit(next);\n }\n}\n","<div\n rtBlock=\"rt-toggle-button-group\"\n role=\"group\"\n [rtMod]=\"{\n sm: size() === 'sm',\n md: size() === 'md',\n lg: size() === 'lg',\n disabled: disabled(),\n }\"\n [attr.aria-label]=\"ariaLabel()\">\n @for (item of items(); track item.option.value) {\n <button\n type=\"button\"\n rtElem=\"button\"\n qa-dataid=\"toggle-button-group-option\"\n [attr.data-value]=\"item.option.value\"\n [rtMod]=\"{\n active: item.active,\n first: $first,\n last: $last,\n }\"\n [disabled]=\"item.disabled\"\n [attr.aria-pressed]=\"item.active ? 'true' : 'false'\"\n [rtTooltip]=\"item.option.title ?? ''\"\n (click)=\"onOptionClick(item)\">\n @if (item.option.icon || item.option.glyph) {\n <rt-icon\n rtElem=\"icon\"\n color=\"current\"\n [name]=\"item.option.icon ?? null\"\n [glyph]=\"item.option.glyph ?? null\"\n [size]=\"iconSize()\" />\n }\n <span rtElem=\"label\">{{ item.option.label }}</span>\n </button>\n }\n</div>\n"],"mappings":"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"}
1
+ {"version":3,"file":"rt-tools-ui-kit-v2-toggle-button-group.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/toggle-button-group/rt-toggle-button-option.directive.ts","../../../projects/ui-kit-v2/src/lib/components/toggle-button-group/rt-toggle-button-group.component.ts","../../../projects/ui-kit-v2/src/lib/components/toggle-button-group/rt-toggle-button-group.component.html"],"sourcesContent":["import { Directive, inject, TemplateRef } from '@angular/core';\n\nimport { IRtToggleButtonGroup } from './rt-toggle-button-group.model';\n\n/**\n * Маркер своей разметки сегмента — того, что рисуется внутри кнопки на месте значка и подписи.\n *\n * Кнопка остаётся киту: нажатие, подсветка, недоступность, фокус и связь с формой. Потребитель даёт\n * только содержимое — например картинку-превью раскладки — и получает опцию и признак, нажат ли\n * сегмент.\n *\n * @example\n * ```html\n * <rt-toggle-button-group [options]=\"layouts\" formControlName=\"layout\">\n * <ng-template rtToggleButtonOption let-option let-active=\"active\">\n * <img [src]=\"option.value + '.svg'\" [alt]=\"option.label\" />\n * </ng-template>\n * </rt-toggle-button-group>\n * ```\n */\n@Directive({\n selector: '[rtToggleButtonOption]',\n})\nexport class RtToggleButtonOptionDirective<T = string> {\n public readonly templateRef: TemplateRef<IRtToggleButtonGroup.OptionContext<T>> =\n inject<TemplateRef<IRtToggleButtonGroup.OptionContext<T>>>(TemplateRef);\n}\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n forwardRef,\n input,\n InputSignal,\n InputSignalWithTransform,\n output,\n OutputEmitterRef,\n signal,\n Signal,\n ViewEncapsulation,\n WritableSignal,\n} from '@angular/core';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\n\nimport { BlockDirective, ElemDirective, ModDirective } from '@rt-tools/core';\n\nimport { RtIconComponent } from '@rt-tools/ui-kit-v2/icon';\nimport { IRtIcon } from '@rt-tools/ui-kit-v2/core';\nimport { RtRadiusDirective } from '@rt-tools/ui-kit-v2/radius';\nimport { RtTooltipDirective } from '@rt-tools/ui-kit-v2/tooltip';\nimport { IRtToggleButtonGroup } from './rt-toggle-button-group.model';\nimport { RtToggleButtonOptionDirective } from './rt-toggle-button-option.directive';\n\nconst BEM_BLOCK: string = 'rt-toggle-button-group';\n\n/**\n * Маппинг размера группы на размер вложенной `<rt-icon>`. rt-icon не имеет\n * промежуточных значений (12 / 16 / 20 / 24 / 32), поэтому `lg` тоже едет\n * на `sm` (16px) — ближе к расчётным 18px у rt-button lg, чем md (20px).\n */\nconst ICON_SIZE_BY_SIZE: Readonly<Record<IRtToggleButtonGroup.Size, IRtIcon.Size>> = Object.freeze({\n sm: 'xs',\n md: 'sm',\n lg: 'sm',\n});\n\n/** Форма записала набор, а не одно значение: так пишет множественный выбор. */\nfunction isMany<T>(value: IRtToggleButtonGroup.FormValue<T>): value is ReadonlyArray<T> {\n return Array.isArray(value);\n}\n\n/**\n * Generic segmented control кита.\n *\n * API `toggle-button-group` с тремя особенностями:\n * 1. BEM через `rtBlock/rtElem/rtMod` (camelCase mods → kebab-case в CSS).\n * 2. Tooltip — нативный `[attr.title]` вместо `MatTooltip` (Angular Material\n * запрещён, см. CLAUDE.md).\n * 3. Визуал — текстовые лейблы + опциональная иконка, а не icon-only кнопки.\n * Иконка остаётся опциональной, чтобы покрыть оба сценария.\n *\n * Компонент \"controlled\" — рендерит сегмент с `value === option.value` как\n * активный, эмиттит `valueChange` при клике, обновление `value` остаётся за\n * потребителем.\n *\n * Generic `<T = string>` сохраняет типизацию по value (`'list' | 'grid'`,\n * union'ы, enum'ы). Дефолт `string` нужен, чтобы шаблон-инстанцирование\n * без явного параметра компилировалось.\n */\n@Component({\n selector: 'rt-toggle-button-group',\n templateUrl: './rt-toggle-button-group.component.html',\n styleUrls: ['./rt-toggle-button-group.component.scss', './rt-toggle-button-group-chips.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [\n // angular\n NgTemplateOutlet,\n\n // standalone components / directives\n RtIconComponent,\n RtTooltipDirective,\n BlockDirective,\n ElemDirective,\n ModDirective,\n ],\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef((): typeof RtToggleButtonGroupComponent => RtToggleButtonGroupComponent),\n multi: true,\n },\n ],\n hostDirectives: [{ directive: RtRadiusDirective, inputs: ['radius'] }],\n host: {\n class: BEM_BLOCK,\n '[class.rt-toggle-button-group--full-width]': 'fullWidth()',\n '[class.rt-toggle-button-group--wrap]': \"layout() === 'wrap'\",\n '[class.rt-toggle-button-group--column]': \"layout() === 'column'\",\n '[class.rt-toggle-button-group--md]': \"size() === 'md'\",\n '[class.rt-toggle-button-group--lg]': \"size() === 'lg'\",\n '[class.rt-toggle-button-group--chips]': \"appearance() === 'chips'\",\n },\n})\nexport class RtToggleButtonGroupComponent<T = string> implements ControlValueAccessor {\n #onChange: (value: IRtToggleButtonGroup.FormValue<T>) => void = (): void => undefined;\n #onTouched: () => void = (): void => undefined;\n\n /** Группа связана с формой: нажатие тогда само переносит подсветку, без ответа хозяина. */\n #bound: boolean = false;\n\n /** Значение, записанное формой или нажатием; `undefined`, пока форма ничего не писала. */\n readonly #formValue: WritableSignal<{ readonly value: IRtToggleButtonGroup.FormValue<T> } | undefined> = signal<\n { readonly value: IRtToggleButtonGroup.FormValue<T> } | undefined\n >(undefined);\n\n /** Отключение, назначенное формой через CVA (`setDisabledState`). */\n readonly #disabledByForm: WritableSignal<boolean> = signal<boolean>(false);\n\n /** Выбранное при одиночном выборе: слово формы, если она его сказала, иначе вход. */\n readonly #single: Signal<T | undefined> = computed((): T | undefined => {\n const written: { readonly value: IRtToggleButtonGroup.FormValue<T> } | undefined = this.#formValue();\n if (written === undefined) {\n return this.value();\n }\n\n return isMany(written.value) ? undefined : (written.value ?? undefined);\n });\n\n /** Набор выбранного при множественном выборе: слово формы, если она его сказала, иначе вход. */\n readonly #many: Signal<ReadonlyArray<T>> = computed((): ReadonlyArray<T> => {\n const written: { readonly value: IRtToggleButtonGroup.FormValue<T> } | undefined = this.#formValue();\n if (written === undefined) {\n return this.values();\n }\n\n return isMany(written.value) ? written.value : [];\n });\n\n protected readonly isDisabled: Signal<boolean> = computed((): boolean => this.disabled() || this.#disabledByForm());\n\n /** Своя разметка сегмента; без неё кнопка рисует значок и подпись. */\n protected readonly optionTpl: Signal<RtToggleButtonOptionDirective<T> | undefined> = contentChild(RtToggleButtonOptionDirective);\n\n protected readonly iconSize: Signal<IRtIcon.Size> = computed((): IRtIcon.Size => ICON_SIZE_BY_SIZE[this.size()]);\n\n /**\n * Сегменты, готовые к отрисовке: подсветка и недоступность посчитаны здесь, а не в шаблоне.\n *\n * Подсветка читается по-разному в одиночном и множественном выборе, а недоступность приходит\n * с двух сторон — от группы и от самого сегмента. Признак группы главнее: доступный сегмент\n * внутри отключённой группы читался бы как её единственное живое место.\n */\n protected readonly items: Signal<ReadonlyArray<IRtToggleButtonGroup.Rendered<T>>> = computed(\n (): ReadonlyArray<IRtToggleButtonGroup.Rendered<T>> => {\n const multiple: boolean = this.multiple();\n const chosen: ReadonlyArray<T> = this.#many();\n const single: T | undefined = this.#single();\n const groupDisabled: boolean = this.isDisabled();\n\n return this.options().map((option: IRtToggleButtonGroup.Option<T>): IRtToggleButtonGroup.Rendered<T> => {\n const active: boolean = multiple ? chosen.includes(option.value) : single === option.value;\n\n return { option, active, disabled: groupDisabled || !!option.disabled, context: { $implicit: option, active } };\n });\n }\n );\n\n public readonly options: InputSignal<ReadonlyArray<IRtToggleButtonGroup.Option<T>>> =\n input.required<ReadonlyArray<IRtToggleButtonGroup.Option<T>>>();\n\n public readonly value: InputSignal<T | undefined> = input<T | undefined>(undefined);\n\n /**\n * Множественный выбор: нажатие добавляет сегмент или снимает его, а не переносит выбор.\n *\n * Своим входом, а не расширением типа `value`: вход, у которого тип значения меняется от\n * значения другого входа, не проверяет ни сборка, ни линтер — потребитель узнаёт о своей\n * ошибке, когда группа перестаёт подсвечивать выбранное.\n */\n public readonly multiple: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Набор выбранного. Читается только при множественном выборе, одиночный берёт `value`. */\n public readonly values: InputSignal<ReadonlyArray<T>> = input<ReadonlyArray<T>>([]);\n\n public readonly ariaLabel: InputSignal<string | null> = input<string | null>(null);\n\n public readonly size: InputSignal<IRtToggleButtonGroup.Size> = input<IRtToggleButtonGroup.Size>('sm');\n\n public readonly disabled: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /** Растягивает группу на всю ширину контейнера; опции делят ширину поровну. */\n public readonly fullWidth: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n /**\n * Раскладка сегментов: одна строка, перенос на следующую или столбик. Перенос нужен длинным\n * спискам во всплывающих окнах, столбик — спискам вроде дней недели.\n */\n public readonly layout: InputSignal<IRtToggleButtonGroup.Layout> = input<IRtToggleButtonGroup.Layout>('row');\n\n /**\n * Вид группы: дорожка с сегментами или отдельные чипы. Вид — входом, а не классом потребителя:\n * у чипов своя коробка пункта, свой просвет и своя подсветка, и класс снаружи до неё не достаёт.\n */\n public readonly appearance: InputSignal<IRtToggleButtonGroup.Appearance> = input<IRtToggleButtonGroup.Appearance>('segmented');\n\n /**\n * Галочка перед подписью выбранного пункта, как у фильтр-чипа Material. Выключена по умолчанию:\n * в сегментах выбор и так виден подложкой, а место под галочку раздвигает пункт.\n */\n public readonly checkmark: InputSignalWithTransform<boolean, BooleanInput> = input<boolean, BooleanInput>(false, {\n transform: booleanAttribute,\n });\n\n public readonly valueChange: OutputEmitterRef<T> = output<T>();\n\n /**\n * Весь набор выбранного после нажатия, а не разница с прежним: разницу вызывающий сводит со\n * своим состоянием сам, и каждый сводит по-своему.\n */\n public readonly valuesChange: OutputEmitterRef<ReadonlyArray<T>> = output<ReadonlyArray<T>>();\n\n public writeValue(value: IRtToggleButtonGroup.FormValue<T>): void {\n this.#formValue.set({ value });\n }\n\n public registerOnChange(fn: (value: IRtToggleButtonGroup.FormValue<T>) => void): void {\n this.#bound = true;\n this.#onChange = fn;\n }\n\n public registerOnTouched(fn: () => void): void {\n this.#onTouched = fn;\n }\n\n public setDisabledState(disabled: boolean): void {\n this.#disabledByForm.set(disabled);\n }\n\n protected onOptionClick(item: IRtToggleButtonGroup.Rendered<T>): void {\n if (item.disabled) {\n return;\n }\n\n const option: IRtToggleButtonGroup.Option<T> = item.option;\n\n if (!this.multiple()) {\n this.#commit(option.value);\n this.valueChange.emit(option.value);\n\n return;\n }\n\n const chosen: ReadonlyArray<T> = this.#many();\n const next: T[] = chosen.includes(option.value)\n ? chosen.filter((one: T): boolean => one !== option.value)\n : [...chosen, option.value];\n\n this.#commit(next);\n this.valuesChange.emit(next);\n }\n\n /** Нажатие уходит в форму, если группа с ней связана; без формы подсветку ведёт хозяин входами. */\n #commit(value: IRtToggleButtonGroup.FormValue<T>): void {\n if (!this.#bound) {\n return;\n }\n this.#formValue.set({ value });\n this.#onChange(value);\n this.#onTouched();\n }\n}\n","<div\n rtBlock=\"rt-toggle-button-group\"\n role=\"group\"\n [rtMod]=\"{\n sm: size() === 'sm',\n md: size() === 'md',\n lg: size() === 'lg',\n disabled: isDisabled(),\n wrap: layout() === 'wrap',\n column: layout() === 'column',\n chips: appearance() === 'chips',\n }\"\n [attr.aria-label]=\"ariaLabel()\">\n @for (item of items(); track item.option.value) {\n <button\n type=\"button\"\n rtElem=\"button\"\n qa-dataid=\"toggle-button-group-option\"\n [attr.data-value]=\"item.option.value\"\n [rtMod]=\"{\n active: item.active,\n first: $first,\n last: $last,\n checked: checkmark() && item.active,\n }\"\n [disabled]=\"item.disabled\"\n [attr.aria-pressed]=\"item.active ? 'true' : 'false'\"\n [rtTooltip]=\"item.option.title ?? ''\"\n (click)=\"onOptionClick(item)\">\n @if (checkmark() && item.active) {\n <span rtElem=\"check\" aria-hidden=\"true\">\n <svg rtElem=\"check-svg\" viewBox=\"-2 -3 30 30\" focusable=\"false\">\n <path fill=\"none\" stroke=\"currentColor\" d=\"M1.73,12.91 8.1,19.28 22.79,4.59\" />\n </svg>\n </span>\n }\n @if (optionTpl(); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl.templateRef\" [ngTemplateOutletContext]=\"item.context\" />\n } @else {\n @if (item.option.icon || item.option.glyph) {\n <rt-icon\n rtElem=\"icon\"\n color=\"current\"\n [name]=\"item.option.icon ?? null\"\n [glyph]=\"item.option.glyph ?? null\"\n [size]=\"iconSize()\" />\n }\n <span rtElem=\"label\">{{ item.option.label }}</span>\n }\n </button>\n }\n</div>\n"],"mappings":";;;;;;;;;AAuBA,IAAa,gCAAb,MAAa,8BAA6B;CAH1C,cAAA;EAIoB,KAAA,cACZ,OAA2D,WAAW;CAC7E;CAHY;EAAA,KAAA,OAAA,GAAA,mBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAA6B,MAAA,CAAA;GAAA,QAAA,GAAA,gBAAA;EAAA,CAAA;CAAA;CAA7B;EAAA,KAAA,OAAA,GAAA,qBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,MAAA;GAA6B,cAAA;GAAA,UAAA;GAAA,UAAA;EAAA,CAAA;CAAA;;AAA7B,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAA6B,YAAA,CAAA;EAHzC,MAAA;EAAU,MAAA,CAAA,EACP,UAAU,yBACb,CAAA;;;ACQD,MAAM,YAAoB;AAO1B,MAAM,oBAA+E,OAAO,OAAO;CAC/F,IAAI;CACJ,IAAI;CACJ,IAAI;AACP,CAAA;AAGD,SAAS,OAAU,OAAwC;CACvD,OAAO,MAAM,QAAQ,KAAK;AAC9B;AAuDA,IAAa,+BAAb,MAAa,6BAA4B;CAnCzC,cAAA;EAoCI,KAAA,kBAA4E;EAC5E,KAAA,mBAAqC;EAGrC,KAAA,SAAkB;EAGT,KAAA,aAAgG,OAEvG,QAAU,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;EAGH,KAAA,kBAA2C,OAAgB,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,kBAAA,CAAA,+BAAA,CAAA,CAAA;EAGjE,KAAA,UAAiC,eAA6B;GACnE,MAAM,UAA6E,KAAK,WAAU;GAClG,IAAI,YAAY,QACZ,OAAO,KAAK,MAAK;GAGrB,OAAO,OAAO,QAAQ,KAAK,IAAI,SAAa,QAAQ,SAAS;EACjE,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;EAGO,KAAA,QAAkC,eAAgC;GACvE,MAAM,UAA6E,KAAK,WAAU;GAClG,IAAI,YAAY,QACZ,OAAO,KAAK,OAAM;GAGtB,OAAO,OAAO,QAAQ,KAAK,IAAI,QAAQ,QAAQ,CAAA;EACnD,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;EAEiB,KAAA,aAA8B,eAAwB,KAAK,SAAQ,KAAM,KAAK,gBAAe,GAAG,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;EAGhG,KAAA,YAAkE,aAAa,+BAA8B,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;EAE7G,KAAA,WAAiC,eAA6B,kBAAkB,KAAK,KAAI,IAAI,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;EAS7F,KAAA,QAAiE,eAC1B;GAClD,MAAM,WAAoB,KAAK,SAAQ;GACvC,MAAM,SAA2B,KAAK,MAAK;GAC3C,MAAM,SAAwB,KAAK,QAAO;GAC1C,MAAM,gBAAyB,KAAK,WAAU;GAE9C,OAAO,KAAK,QAAO,CAAE,CAAC,KAAK,WAA4E;IACnG,MAAM,SAAkB,WAAW,OAAO,SAAS,OAAO,KAAK,IAAI,WAAW,OAAO;IAErF,OAAO;KAAE;KAAQ;KAAQ,UAAU,iBAAiB,CAAC,CAAC,OAAO;KAAU,SAAS;MAAE,WAAW;MAAQ;KAAM;IAAE;GACjH,CAAC;EACL,GACH,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;EAEe,KAAA,UACZ,MAAM,SAAyD,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;EAEnD,KAAA,QAAoC,MAAqB,QAAU,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;EASnE,KAAA,WAA4D,MAA6B,OAAK;GAAA,GAAA,YAAA,EAAA,WAAA,WAAA,+BAAA,CAAA;GAC1G,WAAW;EAAgB,CAAA;EAIf,KAAA,SAAwC,MAAwB,CAAA,GAAG,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;EAEnE,KAAA,YAAwC,MAAqB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;EAElE,KAAA,OAA+C,MAAiC,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;EAErF,KAAA,WAA4D,MAA6B,OAAK;GAAA,GAAA,YAAA,EAAA,WAAA,WAAA,+BAAA,CAAA;GAC1G,WAAW;EAAgB,CAAA;EAIf,KAAA,YAA6D,MAA6B,OAAK;GAAA,GAAA,YAAA,EAAA,WAAA,YAAA,+BAAA,CAAA;GAC3G,WAAW;EAAgB,CAAA;EAOf,KAAA,SAAmD,MAAmC,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;EAM5F,KAAA,aAA2D,MAAuC,aAAY,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;EAM9G,KAAA,YAA6D,MAA6B,OAAK;GAAA,GAAA,YAAA,EAAA,WAAA,YAAA,+BAAA,CAAA;GAC3G,WAAW;EAAgB,CAAA;EAGf,KAAA,cAAmC,OAAM;EAMzC,KAAA,eAAmD,OAAM;CAmD5E;CA5KG;CACA;CAGA;CAGS;CAKA;CAGA;CAUA;CAkGF,WAAW,OAAwC;EACtD,KAAK,WAAW,IAAI,EAAE,MAAK,CAAE;CACjC;CAEO,iBAAiB,IAAsD;EAC1E,KAAK,SAAS;EACd,KAAK,YAAY;CACrB;CAEO,kBAAkB,IAAc;EACnC,KAAK,aAAa;CACtB;CAEO,iBAAiB,UAAiB;EACrC,KAAK,gBAAgB,IAAI,QAAQ;CACrC;CAEU,cAAc,MAAsC;EAC1D,IAAI,KAAK,UACL;EAGJ,MAAM,SAAyC,KAAK;EAEpD,IAAI,CAAC,KAAK,SAAQ,GAAI;GAClB,KAAK,QAAQ,OAAO,KAAK;GACzB,KAAK,YAAY,KAAK,OAAO,KAAK;GAElC;EACJ;EAEA,MAAM,SAA2B,KAAK,MAAK;EAC3C,MAAM,OAAY,OAAO,SAAS,OAAO,KAAK,IACxC,OAAO,QAAQ,QAAoB,QAAQ,OAAO,KAAK,IACvD,CAAC,GAAG,QAAQ,OAAO,KAAK;EAE9B,KAAK,QAAQ,IAAI;EACjB,KAAK,aAAa,KAAK,IAAI;CAC/B;CAGA,QAAQ,OAAwC;EAC5C,IAAI,CAAC,KAAK,QACN;EAEJ,KAAK,WAAW,IAAI,EAAE,MAAK,CAAE;EAC7B,KAAK,UAAU,KAAK;EACpB,KAAK,WAAU;CACnB;CA5KS;EAAA,KAAA,OAAA,GAAA,mBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAA4B,MAAA,CAAA;GAAA,QAAA,GAAA,gBAAA;EAAA,CAAA;CAAA;CAA5B;EAAA,KAAA,OAAA,GAAA,qBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,MAAA;GAA4B,cAAA;GAAA,UAAA;GAAA,QAAA;IAAA,SAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,OAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,UAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,QAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,WAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,MAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,UAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,WAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,QAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,YAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;IAAA,WAAA;KAAA,mBAAA;KAAA,YAAA;KAAA,UAAA;KAAA,YAAA;KAAA,mBAAA;IAAA;GAAA;GAAA,SAAA;IAAA,aAAA;IAAA,cAAA;GAAA;GAAA,MAAA;IAAA,YAAA;KAAA,4CAAA;KAAA,sCAAA;KAAA,wCAAA;KAAA,oCAAA;KAAA,oCAAA;KAAA,uCAAA;IAAA;IAAA,gBAAA;GAAA;GAAA,WAlB1B,CACP;IACI,SAAS;IACT,aAAa,iBAAsD,4BAA4B;IAC/F,OAAO;GACV,CACJ;GAAA,SAAA,CAAA;IAAA,cAAA;IAAA,OAAA;IAAA,WAkDiG;IAA6B,aAAA;IAAA,UAAA;GAAA,CAAA;GAAA,gBAAA,CAAA;IAAA,WAAA,GAAA;IAAA,QAAA,CAAA,UAAA,QAAA;GAAA,CAAA;GAAA,UAAA;GAAA,UC3InI;GAoDA,QAAA,CAAA,gvKAAA,oqIAAA;GAAA,cAAA;IAAA;KAAA,MAAA;KAAA,MDsBQ;KAAgB,UAAA;KAAA,QAAA;MAAA;MAAA;MAAA;KAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MAGhB;KAAe,UAAA;KAAA,QAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;KAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MACf;KAAkB,UAAA;KAAA,QAAA;MAAA;MAAA;MAAA;MAAA;MAAA;KAAA;KAAA,UAAA,CAAA,WAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MAClB;KAAc,UAAA;KAAA,QAAA,CAAA,OAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MACd;KAAa,UAAA;KAAA,QAAA,CAAA,OAAA;IAAA;IAAA;KAAA,MAAA;KAAA,MACb;KAAY,UAAA;IAAA;GAAA;GAAA,iBAAA,GAAA,wBAAA;GAAA,eAAA,GAAA,kBAAA;EAAA,CAAA;CAAA;;AAoBP,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAA4B,YAAA,CAAA;EAnCxC,MAAA;EACa,MAAA,CAAA;GAAA,UAAA;GAAwB,iBAGjB,wBAAwB;GAAM,eAChC,kBAAkB;GAAI,SAC5B;IAEL;IAGA;IACA;IACA;IACA;IACA;GACH;GAAA,WACU,CACP;IACI,SAAS;IACT,aAAa,iBAAqD,4BAA6B;IAC/F,OAAO;GACV,CACJ;GAAA,gBACe,CAAC;IAAE,WAAW;IAAmB,QAAQ,CAAC,QAAQ;GAAC,CAAE;GAAC,MAChE;IACF,OAAO;IACP,8CAA8C;IAC9C,wCAAwC;IACxC,0CAA0C;IAC1C,sCAAsC;IACtC,sCAAsC;IACtC,yCAAyC;GAC5C;GAAA,UAAA;GAAA,QAAA,CAAA,gvKAAA,oqIAAA;EAAA,CAAA;CAwCiG,CAAA;CAAA,gBAAA;EAAA,WAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,GAAA,iBAAA,6BAA6B,GAAA,EAAA,UAAA,KAAA,CAAA;EAAA,CAAA;EAAA,SAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,OAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,UAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,QAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,WAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,MAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,UAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,WAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,QAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,YAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,WAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,aAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,aAAA;EAAA,CAAA;EAAA,cAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,cAAA;EAAA,CAAA;CAAA;AAAA,CAAA"}
@@ -1,10 +1,10 @@
1
1
  import * as i0 from "@angular/core";
2
- import { ChangeDetectionStrategy, Component, Directive, ElementRef, ViewEncapsulation, booleanAttribute, effect, inject, input, signal } from "@angular/core";
2
+ import { ChangeDetectionStrategy, Component, Directive, ElementRef, ViewEncapsulation, booleanAttribute, effect, inject, input, numberAttribute, signal } from "@angular/core";
3
3
  import { FocusMonitor } from "@angular/cdk/a11y";
4
4
  import { Overlay, OverlayConfig, ScrollStrategyOptions } from "@angular/cdk/overlay";
5
5
  import { ComponentPortal } from "@angular/cdk/portal";
6
6
  import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
7
- import { carryThemeScope, materialPresetClassesOf } from "@rt-tools/ui-kit-v2/core";
7
+ import { carryThemeScope, materialPresetClassesOf, rtKitDefault } from "@rt-tools/ui-kit-v2/core";
8
8
  const BEM_BLOCK = "rt-tooltip";
9
9
  var RtTooltipComponent = class RtTooltipComponent {
10
10
  constructor() {
@@ -107,6 +107,9 @@ const FALLBACKS = {
107
107
  "bottom"
108
108
  ]
109
109
  };
110
+ function tooltipPlacement(own, configured, materialPreset) {
111
+ return own ?? configured ?? (materialPreset ? "bottom" : "top");
112
+ }
110
113
  function tooltipPositions(placement) {
111
114
  return FALLBACKS[placement].map((side) => ({ ...POSITION_BY_PLACEMENT[side] }));
112
115
  }
@@ -123,6 +126,8 @@ var RtTooltipDirective = class RtTooltipDirective {
123
126
  #overlayRef;
124
127
  #tooltipRef;
125
128
  #showTimer;
129
+ #placementDefault;
130
+ #showDelayDefault;
126
131
  constructor() {
127
132
  this.#overlay = inject(Overlay);
128
133
  this.#elementRef = inject(ElementRef);
@@ -131,6 +136,8 @@ var RtTooltipDirective = class RtTooltipDirective {
131
136
  this.#overlayRef = null;
132
137
  this.#tooltipRef = null;
133
138
  this.#showTimer = null;
139
+ this.#placementDefault = rtKitDefault("tooltip", (it) => it.placement, null);
140
+ this.#showDelayDefault = rtKitDefault("tooltip", (it) => it.showDelay, SHOW_DELAY_MS);
134
141
  this.text = input("", {
135
142
  ...ngDevMode ? { debugName: "text" } : /* istanbul ignore next */ {},
136
143
  alias: "rtTooltip",
@@ -140,12 +147,20 @@ var RtTooltipDirective = class RtTooltipDirective {
140
147
  ...ngDevMode ? { debugName: "placement" } : /* istanbul ignore next */ {},
141
148
  alias: "rtTooltipPlacement"
142
149
  });
150
+ this.showDelay = input(null, {
151
+ ...ngDevMode ? { debugName: "showDelay" } : /* istanbul ignore next */ {},
152
+ alias: "rtTooltipShowDelay",
153
+ transform: (value) => {
154
+ const delay = value === null || value === void 0 || value === "" ? NaN : numberAttribute(value, NaN);
155
+ return delay >= 0 ? delay : null;
156
+ }
157
+ });
143
158
  this.whenTruncated = input(false, {
144
159
  ...ngDevMode ? { debugName: "whenTruncated" } : /* istanbul ignore next */ {},
145
160
  alias: "rtTooltipWhenTruncated",
146
161
  transform: booleanAttribute
147
162
  });
148
- this.hideOnClick = input(true, {
163
+ this.hideOnClick = input(rtKitDefault("tooltip", (it) => it.hideOnClick, true), {
149
164
  ...ngDevMode ? { debugName: "hideOnClick" } : /* istanbul ignore next */ {},
150
165
  alias: "rtTooltipHideOnClick",
151
166
  transform: booleanAttribute
@@ -163,7 +178,7 @@ var RtTooltipDirective = class RtTooltipDirective {
163
178
  show() {
164
179
  if (this.text().trim() === "" || this.#tooltipRef !== null) return;
165
180
  this.#clearTimer();
166
- this.#showTimer = setTimeout(() => this.#attach(), SHOW_DELAY_MS);
181
+ this.#showTimer = setTimeout(() => this.#attach(), this.showDelay() ?? this.#showDelayDefault);
167
182
  }
168
183
  hide() {
169
184
  this.#clearTimer();
@@ -195,7 +210,7 @@ var RtTooltipDirective = class RtTooltipDirective {
195
210
  #ensureOverlay() {
196
211
  if (this.#overlayRef !== null) return this.#overlayRef;
197
212
  const presetClasses = materialPresetClassesOf(this.#elementRef.nativeElement);
198
- const positions = tooltipPositions(this.placement() ?? (presetClasses.length > 0 ? "bottom" : "top"));
213
+ const positions = tooltipPositions(tooltipPlacement(this.placement(), this.#placementDefault, presetClasses.length > 0));
199
214
  const positionStrategy = this.#overlay.position().flexibleConnectedTo(this.#elementRef).withPush(true).withViewportMargin(VIEWPORT_MARGIN).withFlexibleDimensions(false).withPositions(positions);
200
215
  const config = new OverlayConfig({
201
216
  positionStrategy,
@@ -249,6 +264,13 @@ var RtTooltipDirective = class RtTooltipDirective {
249
264
  isRequired: false,
250
265
  transformFunction: null
251
266
  },
267
+ showDelay: {
268
+ classPropertyName: "showDelay",
269
+ publicName: "rtTooltipShowDelay",
270
+ isSignal: true,
271
+ isRequired: false,
272
+ transformFunction: null
273
+ },
252
274
  whenTruncated: {
253
275
  classPropertyName: "whenTruncated",
254
276
  publicName: "rtTooltipWhenTruncated",
@@ -311,6 +333,14 @@ i0.ɵɵngDeclareClassMetadata({
311
333
  required: false
312
334
  }]
313
335
  }],
336
+ showDelay: [{
337
+ type: i0.Input,
338
+ args: [{
339
+ isSignal: true,
340
+ alias: "rtTooltipShowDelay",
341
+ required: false
342
+ }]
343
+ }],
314
344
  whenTruncated: [{
315
345
  type: i0.Input,
316
346
  args: [{
@@ -1 +1 @@
1
- {"version":3,"file":"rt-tools-ui-kit-v2-tooltip.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/tooltip/rt-tooltip.component.ts","../../../projects/ui-kit-v2/src/lib/components/tooltip/rt-tooltip.logic.ts","../../../projects/ui-kit-v2/src/lib/components/tooltip/rt-tooltip.directive.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, signal, ViewEncapsulation, WritableSignal } from '@angular/core';\n\nconst BEM_BLOCK: string = 'rt-tooltip';\n\n/**\n * Презентационная панель tooltip'а. Рендерится директивой `[rtTooltip]` через\n * CDK `ComponentPortal` в overlay; текст выставляется императивно\n * (`ref.instance.text.set(...)`) — отдельного `input()` нет, т.к. компонент\n * создаётся вручную, а не в шаблоне.\n *\n * `ViewEncapsulation.None` — стили префиксованы `.rt-tooltip` (единообразно с\n * остальным common/ui). `role=\"tooltip\"` — вспомогательный ярлык для AT.\n */\n@Component({\n selector: 'rt-tooltip',\n template: '{{ text() }}',\n styleUrl: './rt-tooltip.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: {\n class: BEM_BLOCK,\n role: 'tooltip',\n },\n})\nexport class RtTooltipComponent {\n public readonly text: WritableSignal<string> = signal<string>('');\n}\n","import { ConnectedPosition } from '@angular/cdk/overlay';\n\nimport { IRtTooltip } from './rt-tooltip.model';\n\n/** Зазор между подсказкой и host'ом. */\nconst TOOLTIP_GAP_PX: number = 6;\n\nconst POSITION_BY_PLACEMENT: Readonly<Record<IRtTooltip.Placement, ConnectedPosition>> = {\n top: { originX: 'center', originY: 'top', overlayX: 'center', overlayY: 'bottom', offsetY: -TOOLTIP_GAP_PX },\n bottom: { originX: 'center', originY: 'bottom', overlayX: 'center', overlayY: 'top', offsetY: TOOLTIP_GAP_PX },\n left: { originX: 'start', originY: 'center', overlayX: 'end', overlayY: 'center', offsetX: -TOOLTIP_GAP_PX },\n right: { originX: 'end', originY: 'center', overlayX: 'start', overlayY: 'center', offsetX: TOOLTIP_GAP_PX },\n};\n\nconst FALLBACKS: Readonly<Record<IRtTooltip.Placement, readonly IRtTooltip.Placement[]>> = {\n top: ['top', 'bottom'],\n bottom: ['bottom', 'top'],\n left: ['left', 'right', 'top', 'bottom'],\n right: ['right', 'left', 'top', 'bottom'],\n};\n\n/**\n * Позиции подсказки по порядку попыток: заданная сторона, противоположная, а у боковой ещё\n * верх и низ — на узком экране сбоку не помещается ни одна сторона, и подсказка, придвинутая\n * к краю, легла бы на сам host. Бока заданы логическими `start`/`end`: в письме справа налево\n * `left` встаёт справа — как и вся раскладка кита.\n */\nexport function tooltipPositions(placement: IRtTooltip.Placement): ConnectedPosition[] {\n return FALLBACKS[placement].map((side: IRtTooltip.Placement): ConnectedPosition => ({ ...POSITION_BY_PLACEMENT[side] }));\n}\n\n/** Размеры узла, по которым судят об обрезке: видимая ширина и ширина содержимого. */\nexport interface IRtTooltipBox {\n readonly clientWidth: number;\n readonly scrollWidth: number;\n}\n\n/**\n * Текст узла обрезан: содержимое шире видимой коробки. Высота не судится — узел с видимым\n * переполнением по высоте показывает всё, и его подсказка только повторяла бы текст.\n */\nexport function isTooltipTextCut(box: IRtTooltipBox): boolean {\n return box.scrollWidth > box.clientWidth;\n}\n","import { FocusMonitor, FocusOrigin } from '@angular/cdk/a11y';\nimport {\n ConnectedPosition,\n FlexibleConnectedPositionStrategy,\n Overlay,\n OverlayConfig,\n OverlayRef,\n ScrollStrategyOptions,\n} from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport {\n booleanAttribute,\n ComponentRef,\n Directive,\n effect,\n ElementRef,\n inject,\n input,\n InputSignal,\n InputSignalWithTransform,\n OnDestroy,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { carryThemeScope, materialPresetClassesOf } from '@rt-tools/ui-kit-v2/core';\nimport { RtTooltipComponent } from './rt-tooltip.component';\nimport { isTooltipTextCut, tooltipPositions } from './rt-tooltip.logic';\nimport { IRtTooltip } from './rt-tooltip.model';\n\nconst SHOW_DELAY_MS: number = 300;\nconst VIEWPORT_MARGIN: number = 8;\n\n/**\n * Tooltip-директива поверх CDK Overlay. Показывает короткую подсказку\n * (`rtTooltip` = строка) на hover/focus host'а. Движок — CDK `flexibleConnectedTo`\n * (авто-flip у края viewport, reposition при скролле), так что подсказка не\n * режется `overflow: hidden` предками (таблицы, aside, карточки).\n *\n * Триггеры: `mouseenter` и фокус с клавиатуры показывают (с задержкой `SHOW_DELAY_MS`),\n * `mouseleave`/`focusout`/`click` прячут. Фокус, поставленный мышью или кодом, подсказку не\n * показывает, как у Material: меню возвращает фокус кнопке после выбора пункта мышью, и\n * подсказка кнопки всплывала поверх того, что пункт открыл. Пустой текст → no-op (директива\n * выключена), поэтому её можно безусловно вешать на icon-кнопки и включать\n * выставлением строки.\n *\n * @example\n * ```html\n * <rt-icon-button icon=\"ico-trash\" ariaLabel=\"Удалить\" tooltip=\"Удалить\" />\n * <button rtButton [rtTooltip]=\"'Подсказка'\">…</button>\n * ```\n */\n@Directive({\n selector: '[rtTooltip]',\n exportAs: 'rtTooltip',\n host: {\n '(mouseenter)': 'show()',\n '(mouseleave)': 'hide()',\n '(focusout)': 'hide()',\n '(click)': 'onClick()',\n },\n})\nexport class RtTooltipDirective implements OnDestroy {\n readonly #overlay: Overlay = inject(Overlay);\n readonly #elementRef: ElementRef<HTMLElement> = inject<ElementRef<HTMLElement>>(ElementRef);\n readonly #scrollStrategies: ScrollStrategyOptions = inject(ScrollStrategyOptions);\n readonly #focusMonitor: FocusMonitor = inject(FocusMonitor);\n\n #overlayRef: OverlayRef | null = null;\n #tooltipRef: ComponentRef<RtTooltipComponent> | null = null;\n #showTimer: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Текст подсказки. Принимает `null`/`undefined` (частый результат date-пайпа\n * или nullable-полей модели) и нормализует их в пустую строку — иначе\n * биндинги вида `value | date` ломали бы строгую типизацию шаблона. Пустая\n * строка → no-op (директива выключена).\n */\n public readonly text: InputSignalWithTransform<string, string | null | undefined> = input<string, string | null | undefined>('', {\n alias: 'rtTooltip',\n transform: (value: string | null | undefined): string => value ?? '',\n });\n\n /** Сторона подсказки. Не задана — сверху, а под материальным набором снизу, как у первого кита. */\n public readonly placement: InputSignal<IRtTooltip.Placement | null> = input<IRtTooltip.Placement | null>(null, {\n alias: 'rtTooltipPlacement',\n });\n\n /**\n * Подсказка только у обрезанного текста: хост меряется в момент показа, и подсказка не\n * появляется, пока его содержимое помещается целиком. Мерить заранее не нужно — показ идёт\n * только отсюда, и признак в эту минуту всегда свежий.\n */\n public readonly whenTruncated: InputSignalWithTransform<boolean, unknown> = input<boolean, unknown>(false, {\n alias: 'rtTooltipWhenTruncated',\n transform: booleanAttribute,\n });\n\n /**\n * Клик прячет открытую подсказку — по умолчанию, как раньше. `false` оставляет её открытой:\n * кнопка-переключатель показывает в ней новое состояние сразу после нажатия. Отложенный показ\n * клик снимает при любом значении — касание на тач-экране (mouseenter + click) подсказку не\n * показывает.\n */\n public readonly hideOnClick: InputSignalWithTransform<boolean, unknown> = input<boolean, unknown>(true, {\n alias: 'rtTooltipHideOnClick',\n transform: booleanAttribute,\n });\n\n constructor() {\n // Новый текст доходит до открытой панели на месте, без повторного наведения.\n effect((): void => this.#syncText(this.text()));\n this.#focusMonitor\n .monitor(this.#elementRef, true)\n .pipe(takeUntilDestroyed())\n .subscribe((origin: FocusOrigin): void => {\n if (origin === 'keyboard') {\n this.show();\n }\n });\n }\n\n public ngOnDestroy(): void {\n this.#focusMonitor.stopMonitoring(this.#elementRef);\n this.#clearTimer();\n this.#disposeOverlay();\n }\n\n protected show(): void {\n if (this.text().trim() === '' || this.#tooltipRef !== null) {\n return;\n }\n this.#clearTimer();\n this.#showTimer = setTimeout((): void => this.#attach(), SHOW_DELAY_MS);\n }\n\n protected hide(): void {\n this.#clearTimer();\n this.#overlayRef?.detach();\n this.#tooltipRef = null;\n }\n\n protected onClick(): void {\n if (this.hideOnClick() || this.#tooltipRef === null) {\n this.hide();\n }\n }\n\n #syncText(text: string): void {\n if (this.#tooltipRef === null) {\n return;\n }\n if (text.trim() === '') {\n this.hide();\n return;\n }\n this.#tooltipRef.instance.text.set(text);\n this.#tooltipRef.changeDetectorRef.markForCheck();\n this.#overlayRef?.updatePosition();\n }\n\n #attach(): void {\n if (this.text().trim() === '' || (this.whenTruncated() && !isTooltipTextCut(this.#elementRef.nativeElement))) {\n return;\n }\n const overlayRef: OverlayRef = this.#ensureOverlay();\n // Коробка переживает закрытие, а кусок темы вокруг host'а мог смениться — переносим на каждом показе.\n carryThemeScope(overlayRef.overlayElement, this.#elementRef.nativeElement);\n const portal: ComponentPortal<RtTooltipComponent> = new ComponentPortal(RtTooltipComponent);\n this.#tooltipRef = overlayRef.attach(portal);\n this.#tooltipRef.instance.text.set(this.text());\n this.#tooltipRef.changeDetectorRef.markForCheck();\n }\n\n #ensureOverlay(): OverlayRef {\n if (this.#overlayRef !== null) {\n return this.#overlayRef;\n }\n const presetClasses: string[] = materialPresetClassesOf(this.#elementRef.nativeElement);\n const placement: IRtTooltip.Placement = this.placement() ?? (presetClasses.length > 0 ? 'bottom' : 'top');\n const positions: ConnectedPosition[] = tooltipPositions(placement);\n\n const positionStrategy: FlexibleConnectedPositionStrategy = this.#overlay\n .position()\n .flexibleConnectedTo(this.#elementRef)\n .withPush(true)\n .withViewportMargin(VIEWPORT_MARGIN)\n .withFlexibleDimensions(false)\n .withPositions(positions);\n\n const config: OverlayConfig = new OverlayConfig({\n positionStrategy,\n scrollStrategy: this.#scrollStrategies.reposition(),\n hasBackdrop: false,\n panelClass: ['rt-tooltip-panel', ...presetClasses],\n });\n this.#overlayRef = this.#overlay.create(config);\n return this.#overlayRef;\n }\n\n #clearTimer(): void {\n if (this.#showTimer !== null) {\n clearTimeout(this.#showTimer);\n this.#showTimer = null;\n }\n }\n\n #disposeOverlay(): void {\n this.#overlayRef?.dispose();\n this.#overlayRef = null;\n this.#tooltipRef = null;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"rt-tools-ui-kit-v2-tooltip.mjs","names":[],"sources":["../../../projects/ui-kit-v2/src/lib/components/tooltip/rt-tooltip.component.ts","../../../projects/ui-kit-v2/src/lib/components/tooltip/rt-tooltip.logic.ts","../../../projects/ui-kit-v2/src/lib/components/tooltip/rt-tooltip.directive.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, signal, ViewEncapsulation, WritableSignal } from '@angular/core';\n\nconst BEM_BLOCK: string = 'rt-tooltip';\n\n/**\n * Презентационная панель tooltip'а. Рендерится директивой `[rtTooltip]` через\n * CDK `ComponentPortal` в overlay; текст выставляется императивно\n * (`ref.instance.text.set(...)`) — отдельного `input()` нет, т.к. компонент\n * создаётся вручную, а не в шаблоне.\n *\n * `ViewEncapsulation.None` — стили префиксованы `.rt-tooltip` (единообразно с\n * остальным common/ui). `role=\"tooltip\"` — вспомогательный ярлык для AT.\n */\n@Component({\n selector: 'rt-tooltip',\n template: '{{ text() }}',\n styleUrl: './rt-tooltip.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: {\n class: BEM_BLOCK,\n role: 'tooltip',\n },\n})\nexport class RtTooltipComponent {\n public readonly text: WritableSignal<string> = signal<string>('');\n}\n","import { ConnectedPosition } from '@angular/cdk/overlay';\n\nimport { IRtTooltip } from './rt-tooltip.model';\n\n/** Зазор между подсказкой и host'ом. */\nconst TOOLTIP_GAP_PX: number = 6;\n\nconst POSITION_BY_PLACEMENT: Readonly<Record<IRtTooltip.Placement, ConnectedPosition>> = {\n top: { originX: 'center', originY: 'top', overlayX: 'center', overlayY: 'bottom', offsetY: -TOOLTIP_GAP_PX },\n bottom: { originX: 'center', originY: 'bottom', overlayX: 'center', overlayY: 'top', offsetY: TOOLTIP_GAP_PX },\n left: { originX: 'start', originY: 'center', overlayX: 'end', overlayY: 'center', offsetX: -TOOLTIP_GAP_PX },\n right: { originX: 'end', originY: 'center', overlayX: 'start', overlayY: 'center', offsetX: TOOLTIP_GAP_PX },\n};\n\nconst FALLBACKS: Readonly<Record<IRtTooltip.Placement, readonly IRtTooltip.Placement[]>> = {\n top: ['top', 'bottom'],\n bottom: ['bottom', 'top'],\n left: ['left', 'right', 'top', 'bottom'],\n right: ['right', 'left', 'top', 'bottom'],\n};\n\n/**\n * Позиции подсказки по порядку попыток: заданная сторона, противоположная, а у боковой ещё\n * верх и низ — на узком экране сбоку не помещается ни одна сторона, и подсказка, придвинутая\n * к краю, легла бы на сам host. Бока заданы логическими `start`/`end`: в письме справа налево\n * `left` встаёт справа — как и вся раскладка кита.\n */\n/**\n * Сторона подсказки: своя на элементе, иначе из настроек кита, иначе сверху, а под материальным\n * набором снизу, как у первого кита.\n */\nexport function tooltipPlacement(\n own: IRtTooltip.Placement | null,\n configured: IRtTooltip.Placement | null,\n materialPreset: boolean\n): IRtTooltip.Placement {\n return own ?? configured ?? (materialPreset ? 'bottom' : 'top');\n}\n\nexport function tooltipPositions(placement: IRtTooltip.Placement): ConnectedPosition[] {\n return FALLBACKS[placement].map((side: IRtTooltip.Placement): ConnectedPosition => ({ ...POSITION_BY_PLACEMENT[side] }));\n}\n\n/** Размеры узла, по которым судят об обрезке: видимая ширина и ширина содержимого. */\nexport interface IRtTooltipBox {\n readonly clientWidth: number;\n readonly scrollWidth: number;\n}\n\n/**\n * Текст узла обрезан: содержимое шире видимой коробки. Высота не судится — узел с видимым\n * переполнением по высоте показывает всё, и его подсказка только повторяла бы текст.\n */\nexport function isTooltipTextCut(box: IRtTooltipBox): boolean {\n return box.scrollWidth > box.clientWidth;\n}\n","import { FocusMonitor, FocusOrigin } from '@angular/cdk/a11y';\nimport { NumberInput } from '@angular/cdk/coercion';\nimport {\n ConnectedPosition,\n FlexibleConnectedPositionStrategy,\n Overlay,\n OverlayConfig,\n OverlayRef,\n ScrollStrategyOptions,\n} from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport {\n booleanAttribute,\n ComponentRef,\n Directive,\n effect,\n ElementRef,\n inject,\n input,\n InputSignal,\n InputSignalWithTransform,\n numberAttribute,\n OnDestroy,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { carryThemeScope, IRtKitConfig, materialPresetClassesOf, rtKitDefault } from '@rt-tools/ui-kit-v2/core';\nimport { RtTooltipComponent } from './rt-tooltip.component';\nimport { isTooltipTextCut, tooltipPlacement, tooltipPositions } from './rt-tooltip.logic';\nimport { IRtTooltip } from './rt-tooltip.model';\n\nconst SHOW_DELAY_MS: number = 300;\nconst VIEWPORT_MARGIN: number = 8;\n\n/**\n * Tooltip-директива поверх CDK Overlay. Показывает короткую подсказку\n * (`rtTooltip` = строка) на hover/focus host'а. Движок — CDK `flexibleConnectedTo`\n * (авто-flip у края viewport, reposition при скролле), так что подсказка не\n * режется `overflow: hidden` предками (таблицы, aside, карточки).\n *\n * Триггеры: `mouseenter` и фокус с клавиатуры показывают (с задержкой `SHOW_DELAY_MS`),\n * `mouseleave`/`focusout`/`click` прячут. Фокус, поставленный мышью или кодом, подсказку не\n * показывает, как у Material: меню возвращает фокус кнопке после выбора пункта мышью, и\n * подсказка кнопки всплывала поверх того, что пункт открыл. Пустой текст → no-op (директива\n * выключена), поэтому её можно безусловно вешать на icon-кнопки и включать\n * выставлением строки.\n *\n * @example\n * ```html\n * <rt-icon-button icon=\"ico-trash\" ariaLabel=\"Удалить\" tooltip=\"Удалить\" />\n * <button rtButton [rtTooltip]=\"'Подсказка'\">…</button>\n * ```\n */\n@Directive({\n selector: '[rtTooltip]',\n exportAs: 'rtTooltip',\n host: {\n '(mouseenter)': 'show()',\n '(mouseleave)': 'hide()',\n '(focusout)': 'hide()',\n '(click)': 'onClick()',\n },\n})\nexport class RtTooltipDirective implements OnDestroy {\n readonly #overlay: Overlay = inject(Overlay);\n readonly #elementRef: ElementRef<HTMLElement> = inject<ElementRef<HTMLElement>>(ElementRef);\n readonly #scrollStrategies: ScrollStrategyOptions = inject(ScrollStrategyOptions);\n readonly #focusMonitor: FocusMonitor = inject(FocusMonitor);\n\n #overlayRef: OverlayRef | null = null;\n #tooltipRef: ComponentRef<RtTooltipComponent> | null = null;\n #showTimer: ReturnType<typeof setTimeout> | null = null;\n /**\n * Сторона из настроек кита. Не умолчание входа: обёртка кита, передающая свой `null`, перебила\n * бы настройку приложения.\n */\n readonly #placementDefault: IRtTooltip.Placement | null = rtKitDefault(\n 'tooltip',\n (it: IRtKitConfig.Tooltip): IRtTooltip.Placement | undefined => it.placement,\n null\n );\n /**\n * Задержка показа по умолчанию: из настроек кита `components.tooltip.showDelay`, без них —\n * `SHOW_DELAY_MS`. Не умолчание входа — по той же причине, что и сторона.\n */\n readonly #showDelayDefault: number = rtKitDefault(\n 'tooltip',\n (it: IRtKitConfig.Tooltip): number | undefined => it.showDelay,\n SHOW_DELAY_MS\n );\n\n /**\n * Текст подсказки. Принимает `null`/`undefined` (частый результат date-пайпа\n * или nullable-полей модели) и нормализует их в пустую строку — иначе\n * биндинги вида `value | date` ломали бы строгую типизацию шаблона. Пустая\n * строка → no-op (директива выключена).\n */\n public readonly text: InputSignalWithTransform<string, string | null | undefined> = input<string, string | null | undefined>('', {\n alias: 'rtTooltip',\n transform: (value: string | null | undefined): string => value ?? '',\n });\n\n /**\n * Сторона подсказки. `null` — сторона из настроек кита `components.tooltip.placement`, без них\n * сверху, а под материальным набором снизу, как у первого кита.\n */\n public readonly placement: InputSignal<IRtTooltip.Placement | null> = input<IRtTooltip.Placement | null>(null, {\n alias: 'rtTooltipPlacement',\n });\n\n /**\n * Задержка показа этой подсказки в миллисекундах. `null` — общая задержка из настроек кита, без\n * них 300.\n */\n public readonly showDelay: InputSignalWithTransform<number | null, NumberInput> = input<number | null, NumberInput>(null, {\n alias: 'rtTooltipShowDelay',\n transform: (value: NumberInput): number | null => {\n const delay: number = value === null || value === undefined || value === '' ? Number.NaN : numberAttribute(value, Number.NaN);\n return delay >= 0 ? delay : null;\n },\n });\n\n /**\n * Подсказка только у обрезанного текста: хост меряется в момент показа, и подсказка не\n * появляется, пока его содержимое помещается целиком. Мерить заранее не нужно — показ идёт\n * только отсюда, и признак в эту минуту всегда свежий.\n */\n public readonly whenTruncated: InputSignalWithTransform<boolean, unknown> = input<boolean, unknown>(false, {\n alias: 'rtTooltipWhenTruncated',\n transform: booleanAttribute,\n });\n\n /**\n * Клик прячет открытую подсказку — по умолчанию, как раньше; умолчание на всё приложение —\n * `components.tooltip.hideOnClick` в настройках кита. `false` оставляет её открытой:\n * кнопка-переключатель показывает в ней новое состояние сразу после нажатия. Отложенный показ\n * клик снимает при любом значении — касание на тач-экране (mouseenter + click) подсказку не\n * показывает.\n */\n public readonly hideOnClick: InputSignalWithTransform<boolean, unknown> = input<boolean, unknown>(\n rtKitDefault('tooltip', (it: IRtKitConfig.Tooltip): boolean | undefined => it.hideOnClick, true),\n {\n alias: 'rtTooltipHideOnClick',\n transform: booleanAttribute,\n }\n );\n\n constructor() {\n // Новый текст доходит до открытой панели на месте, без повторного наведения.\n effect((): void => this.#syncText(this.text()));\n this.#focusMonitor\n .monitor(this.#elementRef, true)\n .pipe(takeUntilDestroyed())\n .subscribe((origin: FocusOrigin): void => {\n if (origin === 'keyboard') {\n this.show();\n }\n });\n }\n\n public ngOnDestroy(): void {\n this.#focusMonitor.stopMonitoring(this.#elementRef);\n this.#clearTimer();\n this.#disposeOverlay();\n }\n\n protected show(): void {\n if (this.text().trim() === '' || this.#tooltipRef !== null) {\n return;\n }\n this.#clearTimer();\n this.#showTimer = setTimeout((): void => this.#attach(), this.showDelay() ?? this.#showDelayDefault);\n }\n\n protected hide(): void {\n this.#clearTimer();\n this.#overlayRef?.detach();\n this.#tooltipRef = null;\n }\n\n protected onClick(): void {\n if (this.hideOnClick() || this.#tooltipRef === null) {\n this.hide();\n }\n }\n\n #syncText(text: string): void {\n if (this.#tooltipRef === null) {\n return;\n }\n if (text.trim() === '') {\n this.hide();\n return;\n }\n this.#tooltipRef.instance.text.set(text);\n this.#tooltipRef.changeDetectorRef.markForCheck();\n this.#overlayRef?.updatePosition();\n }\n\n #attach(): void {\n if (this.text().trim() === '' || (this.whenTruncated() && !isTooltipTextCut(this.#elementRef.nativeElement))) {\n return;\n }\n const overlayRef: OverlayRef = this.#ensureOverlay();\n // Коробка переживает закрытие, а кусок темы вокруг host'а мог смениться — переносим на каждом показе.\n carryThemeScope(overlayRef.overlayElement, this.#elementRef.nativeElement);\n const portal: ComponentPortal<RtTooltipComponent> = new ComponentPortal(RtTooltipComponent);\n this.#tooltipRef = overlayRef.attach(portal);\n this.#tooltipRef.instance.text.set(this.text());\n this.#tooltipRef.changeDetectorRef.markForCheck();\n }\n\n #ensureOverlay(): OverlayRef {\n if (this.#overlayRef !== null) {\n return this.#overlayRef;\n }\n const presetClasses: string[] = materialPresetClassesOf(this.#elementRef.nativeElement);\n const placement: IRtTooltip.Placement = tooltipPlacement(this.placement(), this.#placementDefault, presetClasses.length > 0);\n const positions: ConnectedPosition[] = tooltipPositions(placement);\n\n const positionStrategy: FlexibleConnectedPositionStrategy = this.#overlay\n .position()\n .flexibleConnectedTo(this.#elementRef)\n .withPush(true)\n .withViewportMargin(VIEWPORT_MARGIN)\n .withFlexibleDimensions(false)\n .withPositions(positions);\n\n const config: OverlayConfig = new OverlayConfig({\n positionStrategy,\n scrollStrategy: this.#scrollStrategies.reposition(),\n hasBackdrop: false,\n panelClass: ['rt-tooltip-panel', ...presetClasses],\n });\n this.#overlayRef = this.#overlay.create(config);\n return this.#overlayRef;\n }\n\n #clearTimer(): void {\n if (this.#showTimer !== null) {\n clearTimeout(this.#showTimer);\n this.#showTimer = null;\n }\n }\n\n #disposeOverlay(): void {\n this.#overlayRef?.dispose();\n this.#overlayRef = null;\n this.#tooltipRef = null;\n }\n}\n"],"mappings":"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"}
@@ -504,7 +504,7 @@ var RtTreeSelectorComponent = class RtTreeSelectorComponent {
504
504
  isSignal: true
505
505
  }],
506
506
  ngImport: i0,
507
- template: "<ng-container rtBlock=\"rt-tree-selector\">\n <div rtElem=\"head\">\n @if (label()) {\n <div rtElem=\"label\" qa-dataid=\"tree-selector-label\">{{ label() }}</div>\n }\n\n <rt-input\n rtElem=\"search\"\n qa-dataid=\"tree-selector-search\"\n iconLeft=\"search\"\n [disabled]=\"disabled()\"\n [placeholder]=\"searchLabel()\"\n [ariaLabel]=\"searchLabel()\"\n [ngModel]=\"term()\"\n (ngModelChange)=\"onTerm($event)\"\n (keydown)=\"onSearchKeydown($event)\" />\n\n @if (underSearchTpl(); as underSearch) {\n <div rtElem=\"under-search\" qa-dataid=\"tree-selector-under-search\">\n <ng-container [ngTemplateOutlet]=\"underSearch.templateRef\" />\n </div>\n }\n\n <div rtElem=\"controls\">\n <div rtElem=\"row\">\n @if (isExpandShown()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"tree-selector-expand-all\"\n type=\"button\"\n appearance=\"outlined\"\n theme=\"secondary\"\n size=\"sm\"\n icon=\"expand-all\"\n [rtTooltip]=\"expandAllLabel()\"\n [attr.aria-label]=\"expandAllLabel()\"\n [disabled]=\"disabled()\"\n (click)=\"expandAll()\"></button>\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"tree-selector-collapse-all\"\n type=\"button\"\n appearance=\"outlined\"\n theme=\"secondary\"\n size=\"sm\"\n icon=\"collapse-all\"\n [rtTooltip]=\"collapseAllLabel()\"\n [attr.aria-label]=\"collapseAllLabel()\"\n [disabled]=\"disabled()\"\n (click)=\"collapseAll()\"></button>\n }\n @if (isRevertShown()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"tree-selector-revert\"\n type=\"button\"\n appearance=\"outlined\"\n theme=\"secondary\"\n size=\"sm\"\n icon=\"undo\"\n [rtTooltip]=\"revertLabel()\"\n [attr.aria-label]=\"revertLabel()\"\n [disabled]=\"disabled() || !isDraftChanged()\"\n (click)=\"onRevert()\"></button>\n }\n @if (isClearShown()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"tree-selector-clear\"\n type=\"button\"\n appearance=\"outlined\"\n theme=\"danger\"\n size=\"sm\"\n icon=\"trash\"\n [rtTooltip]=\"clearLabel()\"\n [attr.aria-label]=\"clearLabel()\"\n [disabled]=\"disabled()\"\n (click)=\"onClear()\"></button>\n }\n @if (controlsTpl(); as controls) {\n <div rtElem=\"own\">\n <ng-container [ngTemplateOutlet]=\"controls.templateRef\" />\n </div>\n }\n </div>\n\n @if (isMultiToggleShown()) {\n <div rtElem=\"multi\">\n <rt-toggle-switch\n qa-dataid=\"tree-selector-multi\"\n [ariaLabel]=\"multiLabel()\"\n [disabled]=\"disabled()\"\n [ngModel]=\"multiOn()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"onMultiToggle($event)\" />\n <span rtElem=\"multi-label\">{{ multiLabel() }}</span>\n <rt-icon rtElem=\"multi-hint-icon\" name=\"info-circle\" size=\"sm\" [rtTooltip]=\"multiHintLabel()\" />\n </div>\n }\n </div>\n </div>\n\n @if (isNothingFound()) {\n <div rtElem=\"empty\" qa-dataid=\"tree-selector-empty\" [rtMod]=\"{ 'with-icon': !!emptyIcon() }\">\n @if (emptyIcon(); as icon) {\n <rt-icon rtElem=\"empty-icon\" qa-dataid=\"tree-selector-empty-icon\" size=\"lg\" [name]=\"icon\" />\n }\n {{ nothingFoundLabel() }}\n </div>\n } @else {\n @if (hybrid) {\n <rt-hybrid-tree\n rtElem=\"tree\"\n qa-dataid=\"tree-selector-tree\"\n [nodes]=\"shownNodes()\"\n [value]=\"draft()\"\n [mode]=\"mode()\"\n [cascade]=\"cascade()\"\n [branchMarks]=\"branchMarks()\"\n [exclusive]=\"isExclusive()\"\n [showSelectAll]=\"selectAll()\"\n [searchTerm]=\"markTerm()\"\n [filter]=\"false\"\n [emptyIcon]=\"emptyIcon()\"\n [nodeEndTemplate]=\"endTemplate()\"\n [nodeMetaTemplate]=\"metaTemplate()\"\n [ariaLabel]=\"ariaLabel()\"\n [disabled]=\"disabled()\"\n (valueChange)=\"onTreeChange($event)\"\n (picked)=\"onPicked()\" />\n } @else {\n <rt-tree\n rtElem=\"tree\"\n qa-dataid=\"tree-selector-tree\"\n [nodes]=\"shownNodes()\"\n [value]=\"draft()\"\n [mode]=\"mode()\"\n [cascade]=\"cascade()\"\n [branchMarks]=\"branchMarks()\"\n [exclusive]=\"isExclusive()\"\n [showSelectAll]=\"selectAll()\"\n [searchTerm]=\"markTerm()\"\n [filter]=\"false\"\n [emptyIcon]=\"emptyIcon()\"\n [nodeEndTemplate]=\"endTemplate()\"\n [nodeMetaTemplate]=\"metaTemplate()\"\n [ariaLabel]=\"ariaLabel()\"\n [disabled]=\"disabled()\"\n (valueChange)=\"onTreeChange($event)\"\n (picked)=\"onPicked()\" />\n }\n }\n\n @if (isFooterShown()) {\n <div rtElem=\"foot\">\n <button\n rtButton\n qa-dataid=\"tree-selector-cancel\"\n type=\"button\"\n appearance=\"text\"\n [label]=\"cancelLabel()\"\n [attr.aria-label]=\"cancelLabel()\"\n [disabled]=\"disabled()\"\n (click)=\"cancel()\"></button>\n <button\n rtButton\n qa-dataid=\"tree-selector-apply\"\n type=\"button\"\n [label]=\"applyLabel()\"\n [attr.aria-label]=\"applyLabel()\"\n [disabled]=\"!canApply()\"\n (click)=\"apply()\"></button>\n </div>\n }\n</ng-container>\n",
507
+ template: "<ng-container rtBlock=\"rt-tree-selector\">\n <div rtElem=\"head\">\n @if (label()) {\n <div rtElem=\"label\" qa-dataid=\"tree-selector-label\">{{ label() }}</div>\n }\n\n <rt-input\n rtElem=\"search\"\n qa-dataid=\"tree-selector-search\"\n iconLeft=\"search\"\n [disabled]=\"disabled()\"\n [placeholder]=\"searchLabel()\"\n [ariaLabel]=\"searchLabel()\"\n [ngModel]=\"term()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"onTerm($event)\"\n (keydown)=\"onSearchKeydown($event)\" />\n\n @if (underSearchTpl(); as underSearch) {\n <div rtElem=\"under-search\" qa-dataid=\"tree-selector-under-search\">\n <ng-container [ngTemplateOutlet]=\"underSearch.templateRef\" />\n </div>\n }\n\n <div rtElem=\"controls\">\n <div rtElem=\"row\">\n @if (isExpandShown()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"tree-selector-expand-all\"\n type=\"button\"\n appearance=\"outlined\"\n theme=\"secondary\"\n size=\"sm\"\n icon=\"expand-all\"\n [rtTooltip]=\"expandAllLabel()\"\n [attr.aria-label]=\"expandAllLabel()\"\n [disabled]=\"disabled()\"\n (click)=\"expandAll()\"></button>\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"tree-selector-collapse-all\"\n type=\"button\"\n appearance=\"outlined\"\n theme=\"secondary\"\n size=\"sm\"\n icon=\"collapse-all\"\n [rtTooltip]=\"collapseAllLabel()\"\n [attr.aria-label]=\"collapseAllLabel()\"\n [disabled]=\"disabled()\"\n (click)=\"collapseAll()\"></button>\n }\n @if (isRevertShown()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"tree-selector-revert\"\n type=\"button\"\n appearance=\"outlined\"\n theme=\"secondary\"\n size=\"sm\"\n icon=\"undo\"\n [rtTooltip]=\"revertLabel()\"\n [attr.aria-label]=\"revertLabel()\"\n [disabled]=\"disabled() || !isDraftChanged()\"\n (click)=\"onRevert()\"></button>\n }\n @if (isClearShown()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"tree-selector-clear\"\n type=\"button\"\n appearance=\"outlined\"\n theme=\"danger\"\n size=\"sm\"\n icon=\"trash\"\n [rtTooltip]=\"clearLabel()\"\n [attr.aria-label]=\"clearLabel()\"\n [disabled]=\"disabled()\"\n (click)=\"onClear()\"></button>\n }\n @if (controlsTpl(); as controls) {\n <div rtElem=\"own\">\n <ng-container [ngTemplateOutlet]=\"controls.templateRef\" />\n </div>\n }\n </div>\n\n @if (isMultiToggleShown()) {\n <div rtElem=\"multi\">\n <rt-toggle-switch\n qa-dataid=\"tree-selector-multi\"\n [ariaLabel]=\"multiLabel()\"\n [disabled]=\"disabled()\"\n [ngModel]=\"multiOn()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"onMultiToggle($event)\" />\n <span rtElem=\"multi-label\">{{ multiLabel() }}</span>\n <rt-icon rtElem=\"multi-hint-icon\" name=\"info-circle\" size=\"sm\" [rtTooltip]=\"multiHintLabel()\" />\n </div>\n }\n </div>\n </div>\n\n @if (isNothingFound()) {\n <div rtElem=\"empty\" qa-dataid=\"tree-selector-empty\" [rtMod]=\"{ 'with-icon': !!emptyIcon() }\">\n @if (emptyIcon(); as icon) {\n <rt-icon rtElem=\"empty-icon\" qa-dataid=\"tree-selector-empty-icon\" size=\"lg\" [name]=\"icon\" />\n }\n {{ nothingFoundLabel() }}\n </div>\n } @else {\n @if (hybrid) {\n <rt-hybrid-tree\n rtElem=\"tree\"\n qa-dataid=\"tree-selector-tree\"\n [nodes]=\"shownNodes()\"\n [value]=\"draft()\"\n [mode]=\"mode()\"\n [cascade]=\"cascade()\"\n [branchMarks]=\"branchMarks()\"\n [exclusive]=\"isExclusive()\"\n [showSelectAll]=\"selectAll()\"\n [searchTerm]=\"markTerm()\"\n [filter]=\"false\"\n [emptyIcon]=\"emptyIcon()\"\n [nodeEndTemplate]=\"endTemplate()\"\n [nodeMetaTemplate]=\"metaTemplate()\"\n [ariaLabel]=\"ariaLabel()\"\n [disabled]=\"disabled()\"\n (valueChange)=\"onTreeChange($event)\"\n (picked)=\"onPicked()\" />\n } @else {\n <rt-tree\n rtElem=\"tree\"\n qa-dataid=\"tree-selector-tree\"\n [nodes]=\"shownNodes()\"\n [value]=\"draft()\"\n [mode]=\"mode()\"\n [cascade]=\"cascade()\"\n [branchMarks]=\"branchMarks()\"\n [exclusive]=\"isExclusive()\"\n [showSelectAll]=\"selectAll()\"\n [searchTerm]=\"markTerm()\"\n [filter]=\"false\"\n [emptyIcon]=\"emptyIcon()\"\n [nodeEndTemplate]=\"endTemplate()\"\n [nodeMetaTemplate]=\"metaTemplate()\"\n [ariaLabel]=\"ariaLabel()\"\n [disabled]=\"disabled()\"\n (valueChange)=\"onTreeChange($event)\"\n (picked)=\"onPicked()\" />\n }\n }\n\n @if (isFooterShown()) {\n <div rtElem=\"foot\">\n <button\n rtButton\n qa-dataid=\"tree-selector-cancel\"\n type=\"button\"\n appearance=\"text\"\n [label]=\"cancelLabel()\"\n [attr.aria-label]=\"cancelLabel()\"\n [disabled]=\"disabled()\"\n (click)=\"cancel()\"></button>\n <button\n rtButton\n qa-dataid=\"tree-selector-apply\"\n type=\"button\"\n [label]=\"applyLabel()\"\n [attr.aria-label]=\"applyLabel()\"\n [disabled]=\"!canApply()\"\n (click)=\"apply()\"></button>\n </div>\n }\n</ng-container>\n",
508
508
  styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-tree-selector{--rt-tree-selector-border-width: var(--rt-border-width-thin);--rt-tree-selector-bg: var(--rt-color-bg-surface);--rt-tree-selector-gap: var(--rt-space-sm);--rt-tree-selector-empty-color: var(--rt-color-text-muted);--rt-tree-selector-empty-gap: var(--rt-space-sm);display:flex;min-height:0;box-sizing:border-box;flex-direction:column;background-color:var(--rt-tree-selector-bg);color:var(--rt-color-text-primary);gap:var(--rt-tree-selector-gap)}:is(.rt-preset-material,[data-preset=material]) .rt-tree-selector{--rt-tree-selector-gap: calc(var(--rt-space-2) + var(--rt-space-0-5))}.rt-tree-selector__head{display:flex;flex-direction:column;gap:var(--rt-space-sm)}.rt-tree-selector__label{font-size:var(--rt-text-sm);font-weight:var(--rt-font-weight-semibold)}.rt-tree-selector__search{display:block}.rt-tree-selector__controls{display:flex;flex-direction:column;gap:var(--rt-space-sm)}.rt-tree-selector__row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--rt-space-xs)}.rt-tree-selector__control{flex:0 0 auto}.rt-tree-selector__own{display:flex;align-items:center;gap:var(--rt-space-xs);margin-inline-start:auto}.rt-tree-selector__multi{display:flex;align-items:center;gap:var(--rt-space-sm)}.rt-tree-selector__multi-label{font-size:var(--rt-text-sm)}.rt-tree-selector__multi-hint-icon{color:var(--rt-color-text-muted)}.rt-tree-selector__tree{min-height:0;flex:1 1 auto;overflow-y:auto}.rt-tree-selector__empty{flex:1 1 auto;padding:var(--rt-space-md);color:var(--rt-tree-selector-empty-color);text-align:center}.rt-tree-selector__empty--with-icon{display:flex;flex-direction:column;align-items:center;gap:var(--rt-tree-selector-empty-gap)}.rt-tree-selector__empty-icon{flex-shrink:0}.rt-tree-selector__under-search{display:block}.rt-tree-selector__foot{display:flex;align-items:center;justify-content:flex-end;border-top:var(--rt-tree-selector-border-width) solid var(--rt-color-border-subtle);gap:var(--rt-space-sm);padding-block-start:var(--rt-space-sm)}}\n"],
509
509
  dependencies: [
510
510
  {
@@ -599,8 +599,17 @@ var RtTreeSelectorComponent = class RtTreeSelectorComponent {
599
599
  "iconLeft",
600
600
  "iconRight",
601
601
  "passwordToggle",
602
- "autocomplete"
603
- ]
602
+ "autocomplete",
603
+ "maxlength",
604
+ "floatingLabel",
605
+ "iconLeftAction",
606
+ "iconRightAction",
607
+ "iconLeftDisabled",
608
+ "iconRightDisabled",
609
+ "iconLeftTooltip",
610
+ "iconRightTooltip"
611
+ ],
612
+ outputs: ["iconLeftClick", "iconRightClick"]
604
613
  },
605
614
  {
606
615
  kind: "component",
@@ -623,6 +632,7 @@ var RtTreeSelectorComponent = class RtTreeSelectorComponent {
623
632
  inputs: [
624
633
  "rtTooltip",
625
634
  "rtTooltipPlacement",
635
+ "rtTooltipShowDelay",
626
636
  "rtTooltipWhenTruncated",
627
637
  "rtTooltipHideOnClick"
628
638
  ],
@@ -687,7 +697,7 @@ i0.ɵɵngDeclareClassMetadata({
687
697
  RtHybridTreeComponent
688
698
  ],
689
699
  host: { class: BEM_BLOCK },
690
- template: "<ng-container rtBlock=\"rt-tree-selector\">\n <div rtElem=\"head\">\n @if (label()) {\n <div rtElem=\"label\" qa-dataid=\"tree-selector-label\">{{ label() }}</div>\n }\n\n <rt-input\n rtElem=\"search\"\n qa-dataid=\"tree-selector-search\"\n iconLeft=\"search\"\n [disabled]=\"disabled()\"\n [placeholder]=\"searchLabel()\"\n [ariaLabel]=\"searchLabel()\"\n [ngModel]=\"term()\"\n (ngModelChange)=\"onTerm($event)\"\n (keydown)=\"onSearchKeydown($event)\" />\n\n @if (underSearchTpl(); as underSearch) {\n <div rtElem=\"under-search\" qa-dataid=\"tree-selector-under-search\">\n <ng-container [ngTemplateOutlet]=\"underSearch.templateRef\" />\n </div>\n }\n\n <div rtElem=\"controls\">\n <div rtElem=\"row\">\n @if (isExpandShown()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"tree-selector-expand-all\"\n type=\"button\"\n appearance=\"outlined\"\n theme=\"secondary\"\n size=\"sm\"\n icon=\"expand-all\"\n [rtTooltip]=\"expandAllLabel()\"\n [attr.aria-label]=\"expandAllLabel()\"\n [disabled]=\"disabled()\"\n (click)=\"expandAll()\"></button>\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"tree-selector-collapse-all\"\n type=\"button\"\n appearance=\"outlined\"\n theme=\"secondary\"\n size=\"sm\"\n icon=\"collapse-all\"\n [rtTooltip]=\"collapseAllLabel()\"\n [attr.aria-label]=\"collapseAllLabel()\"\n [disabled]=\"disabled()\"\n (click)=\"collapseAll()\"></button>\n }\n @if (isRevertShown()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"tree-selector-revert\"\n type=\"button\"\n appearance=\"outlined\"\n theme=\"secondary\"\n size=\"sm\"\n icon=\"undo\"\n [rtTooltip]=\"revertLabel()\"\n [attr.aria-label]=\"revertLabel()\"\n [disabled]=\"disabled() || !isDraftChanged()\"\n (click)=\"onRevert()\"></button>\n }\n @if (isClearShown()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"tree-selector-clear\"\n type=\"button\"\n appearance=\"outlined\"\n theme=\"danger\"\n size=\"sm\"\n icon=\"trash\"\n [rtTooltip]=\"clearLabel()\"\n [attr.aria-label]=\"clearLabel()\"\n [disabled]=\"disabled()\"\n (click)=\"onClear()\"></button>\n }\n @if (controlsTpl(); as controls) {\n <div rtElem=\"own\">\n <ng-container [ngTemplateOutlet]=\"controls.templateRef\" />\n </div>\n }\n </div>\n\n @if (isMultiToggleShown()) {\n <div rtElem=\"multi\">\n <rt-toggle-switch\n qa-dataid=\"tree-selector-multi\"\n [ariaLabel]=\"multiLabel()\"\n [disabled]=\"disabled()\"\n [ngModel]=\"multiOn()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"onMultiToggle($event)\" />\n <span rtElem=\"multi-label\">{{ multiLabel() }}</span>\n <rt-icon rtElem=\"multi-hint-icon\" name=\"info-circle\" size=\"sm\" [rtTooltip]=\"multiHintLabel()\" />\n </div>\n }\n </div>\n </div>\n\n @if (isNothingFound()) {\n <div rtElem=\"empty\" qa-dataid=\"tree-selector-empty\" [rtMod]=\"{ 'with-icon': !!emptyIcon() }\">\n @if (emptyIcon(); as icon) {\n <rt-icon rtElem=\"empty-icon\" qa-dataid=\"tree-selector-empty-icon\" size=\"lg\" [name]=\"icon\" />\n }\n {{ nothingFoundLabel() }}\n </div>\n } @else {\n @if (hybrid) {\n <rt-hybrid-tree\n rtElem=\"tree\"\n qa-dataid=\"tree-selector-tree\"\n [nodes]=\"shownNodes()\"\n [value]=\"draft()\"\n [mode]=\"mode()\"\n [cascade]=\"cascade()\"\n [branchMarks]=\"branchMarks()\"\n [exclusive]=\"isExclusive()\"\n [showSelectAll]=\"selectAll()\"\n [searchTerm]=\"markTerm()\"\n [filter]=\"false\"\n [emptyIcon]=\"emptyIcon()\"\n [nodeEndTemplate]=\"endTemplate()\"\n [nodeMetaTemplate]=\"metaTemplate()\"\n [ariaLabel]=\"ariaLabel()\"\n [disabled]=\"disabled()\"\n (valueChange)=\"onTreeChange($event)\"\n (picked)=\"onPicked()\" />\n } @else {\n <rt-tree\n rtElem=\"tree\"\n qa-dataid=\"tree-selector-tree\"\n [nodes]=\"shownNodes()\"\n [value]=\"draft()\"\n [mode]=\"mode()\"\n [cascade]=\"cascade()\"\n [branchMarks]=\"branchMarks()\"\n [exclusive]=\"isExclusive()\"\n [showSelectAll]=\"selectAll()\"\n [searchTerm]=\"markTerm()\"\n [filter]=\"false\"\n [emptyIcon]=\"emptyIcon()\"\n [nodeEndTemplate]=\"endTemplate()\"\n [nodeMetaTemplate]=\"metaTemplate()\"\n [ariaLabel]=\"ariaLabel()\"\n [disabled]=\"disabled()\"\n (valueChange)=\"onTreeChange($event)\"\n (picked)=\"onPicked()\" />\n }\n }\n\n @if (isFooterShown()) {\n <div rtElem=\"foot\">\n <button\n rtButton\n qa-dataid=\"tree-selector-cancel\"\n type=\"button\"\n appearance=\"text\"\n [label]=\"cancelLabel()\"\n [attr.aria-label]=\"cancelLabel()\"\n [disabled]=\"disabled()\"\n (click)=\"cancel()\"></button>\n <button\n rtButton\n qa-dataid=\"tree-selector-apply\"\n type=\"button\"\n [label]=\"applyLabel()\"\n [attr.aria-label]=\"applyLabel()\"\n [disabled]=\"!canApply()\"\n (click)=\"apply()\"></button>\n </div>\n }\n</ng-container>\n",
700
+ template: "<ng-container rtBlock=\"rt-tree-selector\">\n <div rtElem=\"head\">\n @if (label()) {\n <div rtElem=\"label\" qa-dataid=\"tree-selector-label\">{{ label() }}</div>\n }\n\n <rt-input\n rtElem=\"search\"\n qa-dataid=\"tree-selector-search\"\n iconLeft=\"search\"\n [disabled]=\"disabled()\"\n [placeholder]=\"searchLabel()\"\n [ariaLabel]=\"searchLabel()\"\n [ngModel]=\"term()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"onTerm($event)\"\n (keydown)=\"onSearchKeydown($event)\" />\n\n @if (underSearchTpl(); as underSearch) {\n <div rtElem=\"under-search\" qa-dataid=\"tree-selector-under-search\">\n <ng-container [ngTemplateOutlet]=\"underSearch.templateRef\" />\n </div>\n }\n\n <div rtElem=\"controls\">\n <div rtElem=\"row\">\n @if (isExpandShown()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"tree-selector-expand-all\"\n type=\"button\"\n appearance=\"outlined\"\n theme=\"secondary\"\n size=\"sm\"\n icon=\"expand-all\"\n [rtTooltip]=\"expandAllLabel()\"\n [attr.aria-label]=\"expandAllLabel()\"\n [disabled]=\"disabled()\"\n (click)=\"expandAll()\"></button>\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"tree-selector-collapse-all\"\n type=\"button\"\n appearance=\"outlined\"\n theme=\"secondary\"\n size=\"sm\"\n icon=\"collapse-all\"\n [rtTooltip]=\"collapseAllLabel()\"\n [attr.aria-label]=\"collapseAllLabel()\"\n [disabled]=\"disabled()\"\n (click)=\"collapseAll()\"></button>\n }\n @if (isRevertShown()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"tree-selector-revert\"\n type=\"button\"\n appearance=\"outlined\"\n theme=\"secondary\"\n size=\"sm\"\n icon=\"undo\"\n [rtTooltip]=\"revertLabel()\"\n [attr.aria-label]=\"revertLabel()\"\n [disabled]=\"disabled() || !isDraftChanged()\"\n (click)=\"onRevert()\"></button>\n }\n @if (isClearShown()) {\n <button\n rtButton\n rtElem=\"control\"\n qa-dataid=\"tree-selector-clear\"\n type=\"button\"\n appearance=\"outlined\"\n theme=\"danger\"\n size=\"sm\"\n icon=\"trash\"\n [rtTooltip]=\"clearLabel()\"\n [attr.aria-label]=\"clearLabel()\"\n [disabled]=\"disabled()\"\n (click)=\"onClear()\"></button>\n }\n @if (controlsTpl(); as controls) {\n <div rtElem=\"own\">\n <ng-container [ngTemplateOutlet]=\"controls.templateRef\" />\n </div>\n }\n </div>\n\n @if (isMultiToggleShown()) {\n <div rtElem=\"multi\">\n <rt-toggle-switch\n qa-dataid=\"tree-selector-multi\"\n [ariaLabel]=\"multiLabel()\"\n [disabled]=\"disabled()\"\n [ngModel]=\"multiOn()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"onMultiToggle($event)\" />\n <span rtElem=\"multi-label\">{{ multiLabel() }}</span>\n <rt-icon rtElem=\"multi-hint-icon\" name=\"info-circle\" size=\"sm\" [rtTooltip]=\"multiHintLabel()\" />\n </div>\n }\n </div>\n </div>\n\n @if (isNothingFound()) {\n <div rtElem=\"empty\" qa-dataid=\"tree-selector-empty\" [rtMod]=\"{ 'with-icon': !!emptyIcon() }\">\n @if (emptyIcon(); as icon) {\n <rt-icon rtElem=\"empty-icon\" qa-dataid=\"tree-selector-empty-icon\" size=\"lg\" [name]=\"icon\" />\n }\n {{ nothingFoundLabel() }}\n </div>\n } @else {\n @if (hybrid) {\n <rt-hybrid-tree\n rtElem=\"tree\"\n qa-dataid=\"tree-selector-tree\"\n [nodes]=\"shownNodes()\"\n [value]=\"draft()\"\n [mode]=\"mode()\"\n [cascade]=\"cascade()\"\n [branchMarks]=\"branchMarks()\"\n [exclusive]=\"isExclusive()\"\n [showSelectAll]=\"selectAll()\"\n [searchTerm]=\"markTerm()\"\n [filter]=\"false\"\n [emptyIcon]=\"emptyIcon()\"\n [nodeEndTemplate]=\"endTemplate()\"\n [nodeMetaTemplate]=\"metaTemplate()\"\n [ariaLabel]=\"ariaLabel()\"\n [disabled]=\"disabled()\"\n (valueChange)=\"onTreeChange($event)\"\n (picked)=\"onPicked()\" />\n } @else {\n <rt-tree\n rtElem=\"tree\"\n qa-dataid=\"tree-selector-tree\"\n [nodes]=\"shownNodes()\"\n [value]=\"draft()\"\n [mode]=\"mode()\"\n [cascade]=\"cascade()\"\n [branchMarks]=\"branchMarks()\"\n [exclusive]=\"isExclusive()\"\n [showSelectAll]=\"selectAll()\"\n [searchTerm]=\"markTerm()\"\n [filter]=\"false\"\n [emptyIcon]=\"emptyIcon()\"\n [nodeEndTemplate]=\"endTemplate()\"\n [nodeMetaTemplate]=\"metaTemplate()\"\n [ariaLabel]=\"ariaLabel()\"\n [disabled]=\"disabled()\"\n (valueChange)=\"onTreeChange($event)\"\n (picked)=\"onPicked()\" />\n }\n }\n\n @if (isFooterShown()) {\n <div rtElem=\"foot\">\n <button\n rtButton\n qa-dataid=\"tree-selector-cancel\"\n type=\"button\"\n appearance=\"text\"\n [label]=\"cancelLabel()\"\n [attr.aria-label]=\"cancelLabel()\"\n [disabled]=\"disabled()\"\n (click)=\"cancel()\"></button>\n <button\n rtButton\n qa-dataid=\"tree-selector-apply\"\n type=\"button\"\n [label]=\"applyLabel()\"\n [attr.aria-label]=\"applyLabel()\"\n [disabled]=\"!canApply()\"\n (click)=\"apply()\"></button>\n </div>\n }\n</ng-container>\n",
691
701
  styles: ["@charset \"UTF-8\";@layer rt-kit.components{.rt-tree-selector{--rt-tree-selector-border-width: var(--rt-border-width-thin);--rt-tree-selector-bg: var(--rt-color-bg-surface);--rt-tree-selector-gap: var(--rt-space-sm);--rt-tree-selector-empty-color: var(--rt-color-text-muted);--rt-tree-selector-empty-gap: var(--rt-space-sm);display:flex;min-height:0;box-sizing:border-box;flex-direction:column;background-color:var(--rt-tree-selector-bg);color:var(--rt-color-text-primary);gap:var(--rt-tree-selector-gap)}:is(.rt-preset-material,[data-preset=material]) .rt-tree-selector{--rt-tree-selector-gap: calc(var(--rt-space-2) + var(--rt-space-0-5))}.rt-tree-selector__head{display:flex;flex-direction:column;gap:var(--rt-space-sm)}.rt-tree-selector__label{font-size:var(--rt-text-sm);font-weight:var(--rt-font-weight-semibold)}.rt-tree-selector__search{display:block}.rt-tree-selector__controls{display:flex;flex-direction:column;gap:var(--rt-space-sm)}.rt-tree-selector__row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--rt-space-xs)}.rt-tree-selector__control{flex:0 0 auto}.rt-tree-selector__own{display:flex;align-items:center;gap:var(--rt-space-xs);margin-inline-start:auto}.rt-tree-selector__multi{display:flex;align-items:center;gap:var(--rt-space-sm)}.rt-tree-selector__multi-label{font-size:var(--rt-text-sm)}.rt-tree-selector__multi-hint-icon{color:var(--rt-color-text-muted)}.rt-tree-selector__tree{min-height:0;flex:1 1 auto;overflow-y:auto}.rt-tree-selector__empty{flex:1 1 auto;padding:var(--rt-space-md);color:var(--rt-tree-selector-empty-color);text-align:center}.rt-tree-selector__empty--with-icon{display:flex;flex-direction:column;align-items:center;gap:var(--rt-tree-selector-empty-gap)}.rt-tree-selector__empty-icon{flex-shrink:0}.rt-tree-selector__under-search{display:block}.rt-tree-selector__foot{display:flex;align-items:center;justify-content:flex-end;border-top:var(--rt-tree-selector-border-width) solid var(--rt-color-border-subtle);gap:var(--rt-space-sm);padding-block-start:var(--rt-space-sm)}}\n"]
692
702
  }]
693
703
  }],