@feugene/granularity 0.43.0 → 0.45.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 (78) hide show
  1. package/README.md +2 -2
  2. package/dist/chunks/config-BkQ2jvXv.js +49 -0
  3. package/dist/chunks/config-BkQ2jvXv.js.map +1 -0
  4. package/dist/chunks/config-ChnYtO4o.js +28 -0
  5. package/dist/chunks/config-ChnYtO4o.js.map +1 -0
  6. package/dist/chunks/{en-C_QkUTRL.js → en-DiHzFact.js} +3 -1
  7. package/dist/chunks/en-DiHzFact.js.map +1 -0
  8. package/dist/chunks/{es-DemSEhZE.js → es-1ZL6NtkB.js} +3 -1
  9. package/dist/chunks/es-1ZL6NtkB.js.map +1 -0
  10. package/dist/chunks/{es-B4t_3Wnh.js → es-CeKkMxZ_.js} +3 -3
  11. package/dist/chunks/{es-B4t_3Wnh.js.map → es-CeKkMxZ_.js.map} +1 -1
  12. package/dist/chunks/{generated-VcxJTo_q.js → generated-DAKeOOqm.js} +45 -3
  13. package/dist/chunks/{generated-VcxJTo_q.js.map → generated-DAKeOOqm.js.map} +1 -1
  14. package/dist/chunks/{granular-provider-BohXQcNt.js → granular-provider-D_8_l-gM.js} +4 -0
  15. package/dist/chunks/granular-provider-D_8_l-gM.js.map +1 -0
  16. package/dist/chunks/{ru-CLUErjhY.js → ru-Dr2RYn0P.js} +3 -1
  17. package/dist/chunks/ru-Dr2RYn0P.js.map +1 -0
  18. package/dist/chunks/useScrollSpy-CIJpw0RI.js +360 -0
  19. package/dist/chunks/useScrollSpy-CIJpw0RI.js.map +1 -0
  20. package/dist/chunks/useTree-BebEiBcL.js +525 -0
  21. package/dist/chunks/useTree-BebEiBcL.js.map +1 -0
  22. package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-CwCBMh4h.js → GrJsonViewer-CdlWMGnF.js} +1 -1
  23. package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-CwCBMh4h.js.map → GrJsonViewer-CdlWMGnF.js.map} +1 -1
  24. package/dist/components/GrJsonViewer/index.js +1 -1
  25. package/dist/components/GrScrollSpy/chunks/GrScrollSpy-CQCH3zLC.js +207 -0
  26. package/dist/components/GrScrollSpy/chunks/GrScrollSpy-CQCH3zLC.js.map +1 -0
  27. package/dist/components/GrScrollSpy/index.js +3 -0
  28. package/dist/components/GrTree/chunks/{GrTree-CkHzgYg1.js → GrTree-DnDGW0xO.js} +103 -540
  29. package/dist/components/GrTree/chunks/GrTree-DnDGW0xO.js.map +1 -0
  30. package/dist/components/GrTree/index.js +2 -2
  31. package/dist/components/GrTree/styles.css +1 -1
  32. package/dist/components/GrTreeSections/chunks/GrTreeSections-D2PQ87mw.js +147 -0
  33. package/dist/components/GrTreeSections/chunks/GrTreeSections-D2PQ87mw.js.map +1 -0
  34. package/dist/components/GrTreeSections/index.js +3 -0
  35. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DUsv3_mF.js → GrTreeSelect-DzheDCuZ.js} +1 -1
  36. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DUsv3_mF.js.map → GrTreeSelect-DzheDCuZ.js.map} +1 -1
  37. package/dist/components/GrTreeSelect/index.js +1 -1
  38. package/dist/composables/useScrollSpy.js +2 -0
  39. package/dist/composables/useTree.js +2 -0
  40. package/dist/granular-provider-node.js +1 -1
  41. package/dist/granular-provider.js +1 -1
  42. package/dist/i18n/all.js +1 -1
  43. package/dist/i18n/index.js +1 -1
  44. package/dist/index.js +10 -4
  45. package/dist/theme.js +1 -1
  46. package/dist/tokens.js +1 -1
  47. package/dist/types/components/GrScrollSpy/GrScrollSpy.vue.d.ts +105 -0
  48. package/dist/types/components/GrScrollSpy/config.d.ts +1 -0
  49. package/dist/types/components/GrScrollSpy/grScrollSpyStyles.d.ts +26 -0
  50. package/dist/types/components/GrScrollSpy/index.d.ts +9 -0
  51. package/dist/types/components/GrScrollSpy/safelist.d.ts +1 -0
  52. package/dist/types/components/GrScrollSpy/scrollSpyItems.d.ts +44 -0
  53. package/dist/types/components/GrTree/grTreeProps.d.ts +8 -1
  54. package/dist/types/components/GrTree/grTreeStyles.d.ts +12 -0
  55. package/dist/types/components/GrTree/index.d.ts +3 -2
  56. package/dist/types/components/GrTreeSections/GrTreeSections.vue.d.ts +71 -0
  57. package/dist/types/components/GrTreeSections/config.d.ts +1 -0
  58. package/dist/types/components/GrTreeSections/grTreeSectionsStyles.d.ts +8 -0
  59. package/dist/types/components/GrTreeSections/index.d.ts +8 -0
  60. package/dist/types/components/GrTreeSections/safelist.d.ts +1 -0
  61. package/dist/types/composables/internal/scrollSpyGeometry.d.ts +67 -0
  62. package/dist/types/{components/GrTree/grTreeDataAdapter.d.ts → composables/internal/treeAdapter.d.ts} +3 -3
  63. package/dist/types/{components/GrTree/grTreeChecking.d.ts → composables/internal/treeChecking.d.ts} +1 -1
  64. package/dist/types/composables/useScrollSpy.d.ts +59 -0
  65. package/dist/types/composables/useTree.d.ts +107 -0
  66. package/dist/types/granular-provider/shared.d.ts +2 -0
  67. package/dist/types/i18n/messages/en.d.ts +6 -0
  68. package/dist/types/i18n/messages/es.d.ts +6 -0
  69. package/dist/types/i18n/messages/ru.d.ts +6 -0
  70. package/dist/types/index.d.ts +6 -0
  71. package/dist/web-types.json +238 -3
  72. package/package.json +17 -1
  73. package/dist/chunks/en-C_QkUTRL.js.map +0 -1
  74. package/dist/chunks/es-DemSEhZE.js.map +0 -1
  75. package/dist/chunks/granular-provider-BohXQcNt.js.map +0 -1
  76. package/dist/chunks/ru-CLUErjhY.js.map +0 -1
  77. package/dist/components/GrTree/chunks/GrTree-CkHzgYg1.js.map +0 -1
  78. package/dist/types/components/GrTree/grTreeStore.d.ts +0 -71
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GrTree-DnDGW0xO.js","names":[],"sources":["../../../../src/components/GrTree/grTreeInteractionContext.ts","../../../../src/components/GrTree/grTreeStyles.ts","../../../../src/components/GrTree/GrTree.vue","../../../../src/components/GrTree/GrTree.vue"],"sourcesContent":["import type { Ref, ShallowRef } from 'vue'\nimport { ref, shallowRef } from 'vue'\nimport type {\n GrTreeAllowDropType,\n GrTreeKey,\n GrTreeNode,\n GrTreeNodeDropType,\n} from './grTreeTypes'\n\nexport type GrTreeDropTarget = {\n key: GrTreeKey\n type: GrTreeNodeDropType\n allowed: boolean\n}\n\nexport type GrTreeInteractionOptions<T> = {\n draggable?: boolean\n allowDrop?: (draggingNode: GrTreeNode<T>, dropNode: GrTreeNode<T>, type: GrTreeAllowDropType) => boolean\n allowDrag?: (draggingNode: GrTreeNode<T>) => boolean\n}\n\nexport type GrTreeInteractionEmitters<T> = {\n emitNodeClick: (data: T, node: GrTreeNode<T>) => void\n emitNodeExpand: (data: T, node: GrTreeNode<T>) => void\n emitNodeCollapse: (data: T, node: GrTreeNode<T>) => void\n emitNodeDrop: (draggingNode: GrTreeNode<T>, dropNode: GrTreeNode<T>, dropType: GrTreeNodeDropType) => void\n emitNodeContextMenu: (evt: MouseEvent, data: T, node: GrTreeNode<T>) => void\n}\n\nexport type GrTreeInteractionContext<T> = {\n hoveredKey: Ref<GrTreeKey | undefined>\n /** Клавиша узла, держащего roving-фокус (единственный tabindex=0 во всём дереве). */\n /**\n * Реестр DOM-узлов строк, общий на все уровни дерева. Нужен клавиатуре: без\n * него каждое нажатие стрелки обходило бы весь DOM поддерева в поисках\n * строки по `data`-атрибуту.\n */\n nodeEls: Map<GrTreeKey, HTMLElement>\n registerNodeEl: (key: GrTreeKey, el: HTMLElement | null) => void\n draggingNode: ShallowRef<GrTreeNode<T> | null>\n dropTarget: ShallowRef<GrTreeDropTarget | null>\n canDrag: (node: GrTreeNode<T>) => boolean\n canDrop: (drag: GrTreeNode<T>, target: GrTreeNode<T>, type: GrTreeAllowDropType) => boolean\n resetDragState: () => void\n emitNodeClick: (data: T, node: GrTreeNode<T>) => void\n emitNodeExpand: (data: T, node: GrTreeNode<T>) => void\n emitNodeCollapse: (data: T, node: GrTreeNode<T>) => void\n emitNodeDrop: (draggingNode: GrTreeNode<T>, dropNode: GrTreeNode<T>, dropType: GrTreeNodeDropType) => void\n emitNodeContextMenu: (evt: MouseEvent, data: T, node: GrTreeNode<T>) => void\n}\n\nexport function createGrTreeInteractionContext<T>(\n options: GrTreeInteractionOptions<T>,\n emitters: GrTreeInteractionEmitters<T>,\n): GrTreeInteractionContext<T> {\n const hoveredKey = ref<GrTreeKey | undefined>(undefined)\n const draggingNode = shallowRef<GrTreeNode<T> | null>(null)\n const dropTarget = shallowRef<GrTreeDropTarget | null>(null)\n const nodeEls = new Map<GrTreeKey, HTMLElement>()\n\n function registerNodeEl(key: GrTreeKey, el: HTMLElement | null) {\n if (el) {\n nodeEls.set(key, el)\n return\n }\n\n // Перенос узла в другую ветку размонтирует старый элемент уже после того,\n // как зарегистрировался новый: снимаем запись, только если она протухла.\n const previous = nodeEls.get(key)\n if (previous && !previous.isConnected)\n nodeEls.delete(key)\n }\n\n function canDrag(node: GrTreeNode<T>): boolean {\n if (!options.draggable)\n return false\n\n if (options.allowDrag)\n return options.allowDrag(node)\n\n return true\n }\n\n function canDrop(drag: GrTreeNode<T>, target: GrTreeNode<T>, type: GrTreeAllowDropType): boolean {\n if (!options.allowDrop)\n return true\n\n return options.allowDrop(drag, target, type)\n }\n\n function resetDragState() {\n draggingNode.value = null\n dropTarget.value = null\n }\n\n return {\n hoveredKey,\n nodeEls,\n registerNodeEl,\n draggingNode,\n dropTarget,\n canDrag,\n canDrop,\n resetDragState,\n ...emitters,\n }\n}\n","import type { GrComponentSize } from '../shared/sizes'\n\nexport type GrTreeSize = GrComponentSize\n\n/**\n * Размер дерева выражен переменными, а не утилитарными классами: те же\n * `--gr-tree-*` уже объявлены точками кастомизации в `GrTree.vue`, и size\n * обязан задавать им дефолты, а не спорить с ними отдельным каналом.\n *\n * `font-size` на `md` намеренно `inherit`: дерево по умолчанию набирается\n * кеглем родителя, и подстановка конкретных пикселей сменила бы вид всем,\n * кто ничего не просил.\n */\nexport type GrTreeSizeVars = {\n '--gr-tree-row-min-height': string\n '--gr-tree-row-px': string\n '--gr-tree-row-py': string\n '--gr-tree-toggle-size': string\n '--gr-tree-drag-handle-size': string\n '--gr-tree-icon-size': string\n '--gr-tree-content-gap': string\n '--gr-tree-font-size': string\n}\n\nexport const treeSizeVars: Record<GrTreeSize, GrTreeSizeVars> = {\n xs: {\n '--gr-tree-row-min-height': '22px',\n '--gr-tree-row-px': '4px',\n '--gr-tree-row-py': '2px',\n '--gr-tree-toggle-size': '18px',\n '--gr-tree-drag-handle-size': '18px',\n '--gr-tree-icon-size': '12px',\n '--gr-tree-content-gap': '4px',\n '--gr-tree-font-size': '12px',\n },\n sm: {\n '--gr-tree-row-min-height': '24px',\n '--gr-tree-row-px': '6px',\n '--gr-tree-row-py': '3px',\n '--gr-tree-toggle-size': '20px',\n '--gr-tree-drag-handle-size': '20px',\n '--gr-tree-icon-size': '14px',\n '--gr-tree-content-gap': '6px',\n '--gr-tree-font-size': '13px',\n },\n md: {\n '--gr-tree-row-min-height': '28px',\n '--gr-tree-row-px': '8px',\n '--gr-tree-row-py': '4px',\n '--gr-tree-toggle-size': '24px',\n '--gr-tree-drag-handle-size': '24px',\n '--gr-tree-icon-size': '16px',\n '--gr-tree-content-gap': '8px',\n '--gr-tree-font-size': 'inherit',\n },\n lg: {\n '--gr-tree-row-min-height': '32px',\n '--gr-tree-row-px': '10px',\n '--gr-tree-row-py': '6px',\n '--gr-tree-toggle-size': '28px',\n '--gr-tree-drag-handle-size': '28px',\n '--gr-tree-icon-size': '20px',\n '--gr-tree-content-gap': '10px',\n '--gr-tree-font-size': '15px',\n },\n}\n\n/**\n * Готовые виды дерева — наборы значений тех же `--gr-tree-*`, что задаёт\n * `size`. Не проп: второй канал спорил бы с размером за одни переменные, а\n * набор с ним композируется — потребитель раскладывает его в `style` и при\n * необходимости переопределяет по одной строке.\n *\n * Шрифт и значки в набор не входят: семейства у дерева своего токена нет, а\n * значки — это `expandIcon`/`collapseIcon` и слот строки, то есть решение\n * потребителя, а не вида.\n */\nexport type GrTreeView = 'explorer' | 'rail' | 'outline'\n\nexport const grTreeViewVars: Record<GrTreeView, Record<string, string>> = {\n /**\n * Плотный проводник: максимум узлов на экран, колена связей вместо простых\n * вертикалей. Под мышь — 24px меньше минимальной цели касания.\n */\n explorer: {\n '--gr-tree-row-min-height': '24px',\n '--gr-tree-row-py': '2px',\n '--gr-tree-row-radius': '4px',\n '--gr-tree-children-pl': '6px',\n '--gr-tree-branch-line-offset': '8px',\n '--gr-tree-branch-elbow-width': '6px',\n '--gr-tree-content-gap': '6px',\n },\n /**\n * Навигация: выбранная строка — сплошная плашка, обрезанная слева по отступу\n * уровня. Текст на ней перекрашивается своим токеном, иначе на насыщенной\n * подложке он остался бы нечитаемым.\n */\n /**\n * Оглавление: иерархию несёт набор, а не хром. Направляющие и подложки\n * гасятся, выбор отмечается цветом и весом — вид рассчитан на то, чтобы\n * стоять рядом с читаемым текстом и не спорить с ним.\n *\n * Ступени кегля по уровням задаются `rowClass`: это единственное, чего набор\n * значений сделать не может — уровень строки знает только разметка.\n */\n outline: {\n '--gr-tree-row-min-height': '26px',\n '--gr-tree-row-py': '3px',\n '--gr-tree-row-px': '4px',\n '--gr-tree-row-hover-bg': 'transparent',\n '--gr-tree-row-current-bg': 'transparent',\n '--gr-tree-row-current-hover-bg': 'transparent',\n '--gr-tree-row-current-color': 'var(--gr-primary-text)',\n '--gr-tree-children-pl': '4px',\n '--gr-tree-branch-line-offset': '6px',\n },\n\n rail: {\n '--gr-tree-row-min-height': '30px',\n '--gr-tree-row-py': '5px',\n '--gr-tree-row-radius': '999px',\n '--gr-tree-row-current-bg': 'var(--gr-primary)',\n '--gr-tree-row-current-hover-bg': 'var(--gr-primary-hover, var(--gr-primary))',\n '--gr-tree-row-current-color': 'var(--gr-primary-fg)',\n },\n}\n","<script setup lang=\"ts\" generic=\"T extends Record<string, any> = any\">\nimport { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue'\nimport type {\n GrTreeAllowDropType,\n GrTreeInstance,\n GrTreeKey,\n GrTreeNode,\n GrTreeNodeDropType,\n} from './grTreeTypes'\nimport { createGrTreeDataAdapter } from '../../composables/internal/treeAdapter'\nimport type { GrTreeDropTarget } from './grTreeInteractionContext'\nimport { createGrTreeInteractionContext } from './grTreeInteractionContext'\nimport type { GrTreeCheckState } from '../../composables/internal/treeChecking'\nimport { useTree } from '../../composables/useTree'\nimport { treeSizeVars } from './grTreeStyles'\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useAnnouncer } from '../../composables/useAnnouncer'\nimport { useDragSort } from '../../composables/useDragSort'\nimport { useTypeahead } from '../../composables/internal/useTypeahead'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useVirtualList } from '../../composables/useVirtualList'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { iconClass, iconTag } from '../shared/icon'\n\nimport IconCheck from '~icons/lucide/check'\nimport IconChevronRight from '~icons/lucide/chevron-right'\nimport IconGripVertical from '~icons/lucide/grip-vertical'\nimport IconLoaderCircle from '~icons/lucide/loader-circle'\nimport IconMinus from '~icons/lucide/minus'\nimport type {\n GrTreeBranchLineColor,\n GrTreeNodeClass,\n GrTreeProps,\n GrTreeVisibleRow,\n} from './grTreeProps'\n\nexport interface GrTreeEmits<T extends Record<string, any> = any> {\n (e: 'nodeClick', data: T, node: GrTreeNode<T>): void\n (e: 'nodeExpand', data: T, node: GrTreeNode<T>): void\n (e: 'nodeCollapse', data: T, node: GrTreeNode<T>): void\n (e: 'nodeDrop', draggingNode: GrTreeNode<T>, dropNode: GrTreeNode<T>, dropType: GrTreeNodeDropType): void\n (e: 'nodeContextMenu', evt: MouseEvent, data: T, node: GrTreeNode<T>): void\n (e: 'update:currentKey', key: GrTreeKey | undefined): void\n /**\n * Результат фильтрации. Без него потребитель не отличит «данных нет» от\n * «поиск ничего не нашёл» — а это разные пустые экраны: второй пользователь\n * может исправить сам.\n */\n (e: 'filter', info: { value: string, visibleCount: number, matchedCount: number }): void\n (e: 'update:checkedKeys', keys: GrTreeKey[]): void\n (e: 'check', data: T, node: GrTreeNode<T>, info: { checkedKeys: GrTreeKey[], halfCheckedKeys: GrTreeKey[] }): void\n}\n\nconst DEFAULT_BRANCH_LINE_COLOR = 'var(--gr-tree-branch-line-default-color, var(--gr-brd))'\n\n/** Стрелки, которые вместе с `Shift` двигают узел, а не фокус. */\nconst MOVE_KEYS = new Set(['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'])\n\nconst props = withDefaults(defineProps<GrTreeProps<T>>(), {\n props: () => ({\n children: 'children',\n label: 'label',\n }),\n nodeKey: 'id' as any,\n defaultExpandedKeys: () => [],\n defaultExpandAll: false,\n expandOnClickNode: false,\n accordion: false,\n size: undefined,\n highlightCurrent: true,\n indent: 0,\n virtual: false,\n maxHeight: undefined,\n showCheckbox: false,\n currentKey: undefined,\n filterValue: undefined,\n dragHandleVisibility: 'auto',\n checkedKeys: undefined,\n defaultCheckedKeys: () => [],\n checkStrictly: false,\n lazy: false,\n load: undefined,\n expandIcon: undefined,\n collapseIcon: undefined,\n toggleIconRotate: true,\n branchLine: 'line',\n branchLineColor: undefined,\n branchLineActiveColor: undefined,\n draggable: false,\n dragHandleIcon: undefined,\n dragLabel: undefined,\n expandLabel: undefined,\n collapseLabel: undefined,\n rowClass: undefined,\n dragHandleClass: undefined,\n toggleClass: undefined,\n toggleIconClass: undefined,\n toggleSpacerClass: undefined,\n contentClass: undefined,\n})\n\nconst emit = defineEmits<GrTreeEmits<T>>()\n\ndefineSlots<{\n default?: (props: { node: GrTreeNode<T>, data: T }) => any\n}>()\n\nconst dataAdapter = createGrTreeDataAdapter<T>(props)\nconst treeStore = useTree({\n adapter: dataAdapter,\n // Цвет направляющей — решение компонента, а не модели: она лишь копит цепочку\n // предков. Выключенный `branchLine` не даёт цвета вовсе, и цепочка пуста.\n branchColorFor: branchColorForNode,\n data: () => props.data,\n defaultExpandedKeys: () => props.defaultExpandedKeys,\n defaultExpandAll: () => props.defaultExpandAll,\n filterNodeMethod: filterNodeForModel,\n defaultCheckedKeys: () => props.defaultCheckedKeys,\n checkedKeys: () => props.checkedKeys,\n checkStrictly: () => props.checkStrictly,\n lazy: () => props.lazy,\n load: loadForModel,\n})\nconst interactionContext = createGrTreeInteractionContext(props, {\n emitNodeClick: (data, node) => emit('nodeClick', data, node),\n emitNodeExpand: (data, node) => emit('nodeExpand', data, node),\n emitNodeCollapse: (data, node) => emit('nodeCollapse', data, node),\n emitNodeDrop: (draggingNode, dropNode, dropType) => emit('nodeDrop', draggingNode, dropNode, dropType),\n emitNodeContextMenu: (evt, data, node) => emit('nodeContextMenu', evt, data, node),\n})\n\nconst treeProps = props as Readonly<GrTreeProps<T>>\n\nconst { t } = useGranularityTranslations()\nconst { announce } = useAnnouncer()\nconst dragLabel = computed(() => treeProps.dragLabel ?? t('gr.tree.drag', 'Drag'))\nconst expandLabel = computed(() => treeProps.expandLabel ?? t('gr.tree.expand', 'Expand'))\nconst collapseLabel = computed(() => treeProps.collapseLabel ?? t('gr.tree.collapse', 'Collapse'))\nconst currentKey = treeStore.currentKey\nconst hoveredKey = interactionContext.hoveredKey\nconst dropTarget = interactionContext.dropTarget\n\n/**\n * Текущий узел: управляемый режим включает сам факт того, что проп задан.\n *\n * Иначе у одного понятия два владельца — подсветку рисует дерево по своему\n * ключу, а обёртка считает остальное по своему пропу; разойдись они на такт, и\n * строка подсвечена, а подпись не выделена. С `v-model:current-key` источник\n * правды один, и `nextTick` вокруг `setCurrentKey()` больше не нужен.\n */\nconst currentKeyControlled = computed(() => treeProps.currentKey !== undefined)\n\nwatch(() => treeProps.currentKey, (key) => {\n if (!currentKeyControlled.value)\n return\n if (treeStore.currentKey.value === (key ?? undefined))\n return\n\n treeStore.setCurrentKey(key ?? undefined)\n}, { immediate: true })\n\n/** Значение фильтра приходит пропом; метод `filter()` остаётся для императивных сценариев. */\nwatch(() => treeProps.filterValue, (value) => {\n if (value === undefined)\n return\n\n applyFilter(value)\n}, { immediate: true })\n\n// Корневой элемент дерева — область для делегированной клавиатуры (WAI-ARIA tree).\nconst treeRootEl = ref<HTMLElement | null>(null)\n\n/**\n * Видимые строки считает модель (`useTree`): в плоском DOM группы нет, и\n * структуру дерева диктору сообщают `aria-level`, `aria-posinset` и\n * `aria-setsize` — всё это приходит из неё готовым.\n */\nconst visibleRows = treeStore.visibleRows\n\n/**\n * Кольцо roving-фокуса: ровно один `treeitem` на всё дерево держит `tabindex=0`.\n *\n * Ориентация вертикальная намеренно: влево-вправо в дереве заняты раскрытием\n * ветки и переходом к родителю, и примитив их не трогает — это доменная логика,\n * она осталась в `onTreeKeydown`.\n */\nconst roving = useRovingFocus<GrTreeNode<T>['key']>({\n items: () => visibleRows.value.map(row => row.node.key),\n elementFor: key => interactionContext.nodeEls.get(key),\n orientation: () => 'vertical',\n // У дерева есть верх и низ: с последней строки вниз идти некуда.\n wrap: () => false,\n // Но клавишу на краю всё равно гасим: иначе `ArrowDown` на последнем узле\n // прокрутит страницу под деревом.\n onOverflow: () => true,\n // Пока фокус не трогали, остановку держит текущий (выбранный) узел, а если\n // его не видно — первая видимая строка.\n initialKey: () => currentKey.value ?? undefined,\n beforeFocus: key => scrollRowIntoView(key),\n})\n\nfunction onRowClick(node: GrTreeNode<T>) {\n // В управляемом режиме дерево ведёт подсветку до ответа снаружи: строка\n // отзывается на клик сразу, а расхождение снимет наблюдатель за пропом.\n treeStore.setCurrentKey(node.key)\n emit('update:currentKey', node.key)\n roving.setActive(node.key)\n interactionContext.emitNodeClick(node.data, node)\n}\n\n// Клик мышью, в отличие от Enter, умеет ещё и раскрывать узел: `Enter` в\n// паттерне tree закреплён за выбором, и подмешивать в него раскрытие нельзя.\nfunction onRowActivate(row: GrTreeVisibleRow<T>) {\n onRowClick(row.node)\n\n if (treeProps.expandOnClickNode && !row.isLeaf)\n toggleExpand(row.node)\n}\n\nfunction onRowContextMenu(evt: MouseEvent, node: GrTreeNode<T>) {\n interactionContext.emitNodeContextMenu(evt, node.data, node)\n}\n\n// ————— Клавиатурная навигация по WAI-ARIA tree pattern (только корневой инстанс).\n\nfunction isRovingItem(key: GrTreeNode<T>['key']): boolean {\n return roving.rovingKey.value === key\n}\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrTree' })\n\n// Переменные ставим и вложенным уровням тоже: `v-bind=\"props\"` доносит до них\n// `size`, а значения одинаковые — наследование от корня не нарушается.\nconst sizeStyle = computed(() => treeSizeVars[resolvedSize.value])\n\n/**\n * Виртуализация: в DOM живёт только окно вокруг вьюпорта.\n *\n * Корень дерева и есть скроллер — обёрток-распорок между `role=\"tree\"` и\n * `role=\"treeitem\"` быть не должно, поэтому срезанное сверху и снизу держат\n * отступы самого корня.\n */\nconst TREE_ROW_GAP = 2\n\nconst rowEstimate = computed(() => Number.parseFloat(sizeStyle.value['--gr-tree-row-min-height']))\n\nconst virtualMaxHeight = computed(() => {\n const value = treeProps.maxHeight\n if (value == null)\n return undefined\n return typeof value === 'number' ? `${value}px` : value\n})\n\nconst virtualizer = useVirtualList({\n container: treeRootEl,\n count: () => (treeProps.virtual ? visibleRows.value.length : 0),\n // Раскрытие/фильтр сдвигают индексы строк — замеры прошлого набора невалидны.\n source: () => visibleRows.value,\n itemSize: () => rowEstimate.value,\n gap: TREE_ROW_GAP,\n // Первый рендер обязан совпасть с серверным: контейнера ещё нет, и окно\n // считается от объявленной высоты, а не от измеренной.\n viewportSize: () => (typeof treeProps.maxHeight === 'number' ? treeProps.maxHeight : undefined),\n})\n\n/** Строки к отрисовке: при выключенной виртуализации — все. */\nconst renderedRows = computed(() => {\n if (!treeProps.virtual)\n return visibleRows.value\n\n const { start, end } = virtualizer.range.value\n return visibleRows.value.slice(start, end)\n})\n\n/**\n * Срезанное сверху и снизу держат псевдоэлементы контейнера.\n *\n * Ни один из трёх напрашивающихся вариантов не годится:\n *\n * - `padding` контейнера — `max-height` меряет ту же коробку, и распорка в сто\n * тысяч пикселей либо раздувает скроллер до той же сотни тысяч, либо съедает\n * всю его высоту;\n * - обёртка-распорка внутри — между `role=\"tree\"` и `role=\"treeitem\"` не должно\n * быть посторонних узлов, роль потеряла бы обязательных потомков;\n * - отступы крайних отрисованных строк — распорка исчезает ровно в тот момент,\n * когда строки заменяются целиком (прыжок прокрутки), содержимое схлопывается\n * до высоты окна, и браузер обрезает `scrollTop` до почти нуля.\n *\n * `::before`/`::after` не узлы DOM: их не за что размонтировать, в дереве\n * доступности их нет, а высота приезжает переменными в том же патче, что и сами\n * строки, — схлопнуться между кадрами нечему.\n */\nconst rootStyle = computed(() => {\n if (!treeProps.virtual)\n return sizeStyle.value\n\n return {\n ...sizeStyle.value,\n overflow: 'auto',\n maxHeight: virtualMaxHeight.value,\n ...virtualizer.spacerStyle.value,\n }\n})\n\n/** Абсолютный индекс отрисованной строки: поиск по массиву стоил бы O(n) на строку. */\nfunction absoluteIndex(offsetInWindow: number): number {\n return treeProps.virtual ? virtualizer.range.value.start + offsetInWindow : offsetInWindow\n}\n\n/**\n * Строка размонтируется: снимаем регистрацию и, если фокус был на ней, уводим\n * его на корень — делегированный keydown живёт там, первая же стрелка вернёт\n * видимую строку через `focusRow`. Иначе фокус упал бы на `body` и клавиатура\n * дерева умерла бы до клика мышью.\n *\n * Спрашиваем сам элемент, а не `document.activeElement === body`: Vue обнуляет\n * function ref ДО удаления узла, поэтому в момент вызова фокус ещё на строке —\n * а «фокус на body» означает лишь то, что страницу никто не трогал.\n */\nlet isUnmounting = false\n\nfunction releaseNodeEl(key: GrTreeKey): void {\n const el = interactionContext.nodeEls.get(key)\n const active = typeof document === 'undefined' ? null : document.activeElement\n const heldFocus = Boolean(el && active && (el === active || el.contains(active)))\n\n interactionContext.registerNodeEl(key, null)\n\n if (heldFocus && !isUnmounting)\n treeRootEl.value?.focus({ preventScroll: true })\n}\n\n/**\n * При виртуализации узла вне окна в DOM нет: `nodeEls.get` вернул бы\n * `undefined`, а фокус уехал бы на `body` вместе с размонтированной строкой.\n * Поэтому сперва прокрутка, и только следующим тиком — фокус.\n */\nfunction scrollRowIntoView(key: GrTreeNode<T>['key']): Promise<void> {\n if (treeProps.virtual) {\n const index = visibleRows.value.findIndex(row => row.node.key === key)\n if (index >= 0)\n virtualizer.scrollToIndex(index)\n }\n\n return nextTick()\n}\n\nfunction focusRow(key: GrTreeNode<T>['key']): void {\n void roving.focusKey(key)\n}\n\n/**\n * Typeahead паттерна tree: печатные символы копятся в буфер и переводят фокус\n * на первый подходящий видимый узел, начиная со следующего за текущим.\n *\n * Поиск идёт по данным (`visibleRows`), а не по DOM: при виртуализации узла вне\n * окна в разметке нет, и поиск по тексту элементов находил бы только видимое.\n */\nconst typeahead = useTypeahead<GrTreeVisibleRow<T>>({\n items: () => visibleRows.value,\n textOf: row => row.node.label,\n // Без наведённого фокуса ищем с начала списка, а не от конца: `findIndex`\n // вернул бы `-1`, и первая строка выпала бы из обхода.\n currentIndex: rows => Math.max(0, rows.findIndex(row => row.node.key === roving.rovingKey.value)),\n onMatch: row => focusRow(row.node.key),\n})\n\n/** `*` — раскрыть всех соседей узла, на котором фокус (уровень целиком). */\nfunction expandSiblings(node: GrTreeNode<T>): void {\n const siblings = node.parent ? node.parent.childNodes : treeStore.treeModel.value.roots\n\n for (const sibling of siblings) {\n if (sibling.childNodes.length === 0 || treeStore.isExpandedKey(sibling.key))\n continue\n\n treeStore.setExpandedKey(sibling.key, true)\n interactionContext.emitNodeExpand(sibling.data, sibling)\n }\n}\n\nfunction onTreeKeydown(event: KeyboardEvent): void {\n // Делегированная клавиатура уважает интерактивные цели: печать в инпуте слота\n // узла — ввод текста, а не typeahead. Без гарда preventDefault отменял бы это.\n const target = event.target as HTMLElement | null\n const interactive = target?.closest<HTMLElement>('button, a[href], input, select, textarea, [contenteditable]')\n if (interactive && interactive !== event.currentTarget) {\n // Табируемая цель — самостоятельный таб-стоп: клавиатура целиком её.\n if (interactive.tabIndex >= 0)\n return\n\n // Кнопки строки (toggle, drag-handle) не табируемы: фокус попадает на них\n // только мышью. За ними остаётся активация — Enter на toggle это его клик, —\n // а навигация принадлежит дереву, иначе клик мышью убивал бы стрелки.\n if (event.key === 'Enter' || event.key === ' ')\n return\n }\n\n const rows = visibleRows.value\n if (rows.length === 0)\n return\n\n const idx = Math.max(0, rows.findIndex(r => r.node.key === roving.rovingKey.value))\n const cur = rows[idx]\n\n if (event.key === '*') {\n event.preventDefault()\n expandSiblings(cur.node)\n return\n }\n\n // Печатный символ без модификаторов — typeahead, а не команда.\n if (event.key.length === 1 && event.key !== ' ' && !event.ctrlKey && !event.metaKey && !event.altKey) {\n event.preventDefault()\n typeahead.type(event.key)\n return\n }\n\n // `Shift` со стрелкой двигает сам узел — раскладка аутлайнера. Проверяется\n // раньше навигации: иначе примитив увёл бы фокус вместо переноса.\n if (event.shiftKey && MOVE_KEYS.has(event.key)) {\n if (!treeProps.draggable)\n return\n\n event.preventDefault()\n void onNodeMoveKey(cur.node, event.key)\n return\n }\n\n // Вертикаль, `Home` и `End` ведёт примитив. Влево-вправо он не трогает: в\n // дереве это раскрытие ветки и переход к родителю, а не движение по списку.\n if (roving.handleNavigationKeys(event))\n return\n\n switch (event.key) {\n case 'ArrowRight':\n event.preventDefault()\n if (!cur.isLeaf) {\n if (!cur.isExpanded)\n toggleExpand(cur.node)\n else if (idx < rows.length - 1)\n focusRow(rows[idx + 1].node.key)\n }\n break\n case 'ArrowLeft':\n event.preventDefault()\n if (!cur.isLeaf && cur.isExpanded)\n toggleExpand(cur.node)\n else if (cur.node.parent && rows.some(r => r.node.key === cur.node.parent!.key))\n focusRow(cur.node.parent.key)\n break\n case 'Enter':\n event.preventDefault()\n onRowClick(cur.node)\n break\n // Space при чекбоксах переключает отметку — это и есть выбор в\n // multi-select дереве; без них он остаётся вторым способом выбрать узел.\n case ' ':\n event.preventDefault()\n if (treeProps.showCheckbox)\n toggleChecked(cur.node)\n else\n onRowClick(cur.node)\n break\n }\n}\n\nfunction onRowMouseEnter(node: GrTreeNode<T>) {\n hoveredKey.value = node.key\n}\n\nfunction onRowMouseLeave(node: GrTreeNode<T>) {\n if (hoveredKey.value === node.key)\n hoveredKey.value = undefined\n}\n\nfunction collapseSiblings(node: GrTreeNode<T>) {\n const siblings = node.parent ? node.parent.childNodes : treeStore.treeModel.value.roots\n\n for (const sibling of siblings) {\n if (sibling.key === node.key || !treeStore.isExpandedKey(sibling.key))\n continue\n\n treeStore.setExpandedKey(sibling.key, false)\n interactionContext.emitNodeCollapse(sibling.data, sibling)\n }\n}\n\nfunction toggleExpand(node: GrTreeNode<T>) {\n const expanded = !treeStore.isExpandedKey(node.key)\n\n if (expanded && treeProps.accordion)\n collapseSiblings(node)\n\n // Ленивая ветка грузится по первому раскрытию; повторное ничего не запрашивает.\n if (expanded)\n treeStore.ensureLoaded(node)\n\n treeStore.toggleExpand(node)\n\n if (expanded)\n interactionContext.emitNodeExpand(node.data, node)\n else\n interactionContext.emitNodeCollapse(node.data, node)\n}\n\n// ————— Отметки (чекбоксы).\n\nfunction checkStateOf(key: GrTreeKey): GrTreeCheckState {\n return treeStore.getCheckState(key)\n}\n\nfunction ariaCheckedOf(row: GrTreeVisibleRow<T>): 'true' | 'false' | 'mixed' | undefined {\n if (!treeProps.showCheckbox)\n return undefined\n\n const state = checkStateOf(row.node.key)\n return state === 'checked' ? 'true' : state === 'half' ? 'mixed' : 'false'\n}\n\nfunction emitCheck(node: GrTreeNode<T>): void {\n const checkedKeys = treeStore.getCheckedKeys()\n emit('update:checkedKeys', checkedKeys)\n emit('check', node.data, node, { checkedKeys, halfCheckedKeys: treeStore.getHalfCheckedKeys() })\n}\n\nfunction toggleChecked(node: GrTreeNode<T>): void {\n if (!treeProps.showCheckbox)\n return\n\n const changed = treeStore.toggleChecked(node)\n if (changed)\n emitCheck(changed)\n}\n\n// ————— Геометрия строки: отступ уровня и направляющие ветвей.\n\nfunction rowStyle(row: GrTreeVisibleRow<T>) {\n const step = treeProps.indent && treeProps.indent > 0\n ? `${treeProps.indent}px`\n : 'var(--gr-tree-indent-step)'\n\n return { '--gr-tree-row-indent': `calc(${step} * ${row.node.level - 1})` }\n}\n\n/**\n * Направляющая уровня-предка. Считается от того же шага отступа, что и сам\n * отступ строки, — иначе линия и содержимое разъедутся на вложенных уровнях.\n */\n/**\n * Колено рисуется только у направляющей собственного уровня строки: остальные\n * — это транзит предков, и горизонтальная черта у них указывала бы на строку,\n * к которой они не относятся.\n *\n * У последнего ребёнка вертикаль обрывается на середине: продолжать её значит\n * обещать сиблинга, которого нет.\n */\n/**\n * Цвет направляющей уровня для модели. Объявление функцией, а не стрелкой на\n * месте вызова: `treeProps` определяются ниже, и ссылка на них в выражении\n * читалась бы до объявления.\n */\n/**\n * Обёртки над пропами для модели: объявлением, а не стрелкой на месте вызова —\n * `treeProps` определяются ниже. `undefined` от фильтра означает «решай сам»:\n * так обёртка возвращает модель к её подстрочному матчу, когда своего правила\n * потребитель не задал.\n */\nfunction filterNodeForModel(value: string, data: T, node: GrTreeNode<T>) {\n return treeProps.filterNodeMethod?.(value, data, node)\n}\n\nfunction loadForModel(node: GrTreeNode<T>, resolve: (children: T[]) => void) {\n treeProps.load?.(node, resolve)\n}\n\nfunction branchColorForNode(node: GrTreeNode<T>) {\n return treeProps.branchLine ? resolveBranchLineColor(node) : undefined\n}\n\nfunction branchGuideModifiers(row: GrTreeVisibleRow<T>, index: number) {\n if (treeProps.branchLine !== 'elbow' || index !== row.branchColors.length - 1)\n return undefined\n\n return row.posInSet === row.setSize\n ? 'gr-tree__branch-guide--elbow gr-tree__branch-guide--last'\n : 'gr-tree__branch-guide--elbow'\n}\n\nfunction branchGuideStyle(row: GrTreeVisibleRow<T>, index: number) {\n const step = treeProps.indent && treeProps.indent > 0\n ? `${treeProps.indent}px`\n : 'var(--gr-tree-indent-step)'\n\n return {\n 'left': `calc(${step} * ${index} + var(--gr-tree-branch-line-offset))`,\n '--gr-tree-branch-line-color': row.branchColors[index],\n }\n}\n\n// Drag & drop\nfunction canDrag(node: GrTreeNode<T>): boolean {\n return interactionContext.canDrag(node)\n}\n\n/**\n * Ручка «по наведению» на тач-устройстве недостижима: событий наведения там нет,\n * ключ не выставляется, класс видимости не появляется — то есть перетаскивания\n * нет вовсе, хотя `touch-action: none` у ручки стоит ровно ради него.\n *\n * Режим `auto` решает это без JS: класс-модификатор на корне, а показ включает\n * `@media (hover: none)` — так поведение остаётся верным и на сервере, где\n * никакого `matchMedia` спрашивать нельзя.\n */\nfunction shouldShowDragHandle(node: GrTreeNode<T>): boolean {\n if (!canDrag(node))\n return false\n\n return treeProps.dragHandleVisibility === 'always' || hoveredKey.value === node.key\n}\n\n/**\n * Треть строки сверху — «до», треть снизу — «после», середина — «внутрь».\n * Зоны нарезает компонент: примитив отдаёт только долю вдоль строки.\n */\nfunction dropTypeFromFraction(fraction: number): GrTreeNodeDropType {\n if (fraction < 1 / 3)\n return 'prev'\n if (fraction > 2 / 3)\n return 'next'\n\n return 'inner'\n}\n\nfunction canDrop(drag: GrTreeNode<T>, target: GrTreeNode<T>, type: GrTreeAllowDropType): boolean {\n return interactionContext.canDrop(drag, target, type)\n}\n\n/** Перенос состоялся: одна дорога и для указателя, и для клавиатуры. */\nfunction applyMove(source: GrTreeNode<T>, targetKey: GrTreeKey, type: GrTreeNodeDropType): boolean {\n const reference = treeStore.getNode(targetKey)\n if (!reference)\n return false\n\n const movedNode = treeStore.moveNode(source, reference, type)\n if (!movedNode)\n return false\n\n const dropNode = treeStore.getNode(reference.key) ?? reference\n interactionContext.emitNodeDrop(movedNode, dropNode, type)\n\n return true\n}\n\nconst dragSort = useDragSort<GrTreeKey, GrTreeDropTarget>({\n items: () => visibleRows.value.map(row => row.node.key),\n elementFor: key => interactionContext.nodeEls.get(key) ?? null,\n scroller: () => treeRootEl.value,\n disabled: () => !treeProps.draggable,\n canDrag: (key) => {\n const node = treeStore.getNode(key)\n\n return node ? canDrag(node) : false\n },\n resolveTarget: (hit, sourceKey, previous) => {\n const source = treeStore.getNode(sourceKey)\n const node = treeStore.getNode(hit.key)\n if (!source || !node)\n return null\n\n const type = dropTypeFromFraction(hit.fraction)\n const allowed = treeStore.canMoveNode(source, node, type) && canDrop(source, node, type)\n\n // Та же ссылка, пока смысл не изменился: иначе подсветка перерисовывалась бы\n // на каждом движении указателя.\n if (previous && previous.key === node.key && previous.type === type && previous.allowed === allowed)\n return previous\n\n return { key: node.key, type, allowed }\n },\n onDrop: (sourceKey, target) => {\n const source = treeStore.getNode(sourceKey)\n if (!source || !target.allowed)\n return\n\n applyMove(source, target.key, target.type)\n },\n onUpdate: (sourceKey, target) => {\n interactionContext.draggingNode.value = sourceKey === null ? null : treeStore.getNode(sourceKey) ?? null\n interactionContext.dropTarget.value = target\n },\n})\n\nfunction onHandlePointerDown(event: PointerEvent, node: GrTreeNode<T>): void {\n if (!treeProps.draggable)\n return\n\n dragSort.startFrom(node.key)(event)\n}\n\n/**\n * Клавиатурный перенос — раскладка аутлайнера: `Shift` со стрелкой сразу\n * двигает узел, без режима «взято». Режим здесь был бы лишним: `Space` в дереве\n * уже отмечает чекбокс, а стрелки водят фокус по веткам.\n */\nfunction moveByKeyboard(node: GrTreeNode<T>, key: string): boolean {\n const siblings = node.parent ? node.parent.childNodes : treeStore.treeModel.value.roots\n const index = siblings.findIndex(sibling => sibling.key === node.key)\n\n if (key === 'ArrowUp' && index > 0)\n return applyMove(node, siblings[index - 1].key, 'prev')\n\n if (key === 'ArrowDown' && index >= 0 && index < siblings.length - 1)\n return applyMove(node, siblings[index + 1].key, 'next')\n\n // Вправо — в предыдущего соседа: у первого в уровне такого соседа нет.\n if (key === 'ArrowRight' && index > 0)\n return applyMove(node, siblings[index - 1].key, 'inner')\n\n if (key === 'ArrowLeft' && node.parent)\n return applyMove(node, node.parent.key, 'next')\n\n return false\n}\n\nasync function onNodeMoveKey(node: GrTreeNode<T>, key: string): Promise<void> {\n if (!treeProps.draggable || !canDrag(node))\n return\n if (!moveByKeyboard(node, key))\n return\n\n announce(t('gr.tree.moved', 'Moved {label}', { label: node.label }))\n\n // Перестановка перерисовывает уровень: без возврата фокуса следующий Shift\n // уже некуда было бы адресовать.\n await nextTick()\n focusRow(node.key)\n}\n\n/**\n * Фильтрация и отчёт о её результате.\n *\n * Счёт снимается после пересчёта видимых строк: `visibleCount` — то, что\n * пользователь реально видит, а `matchedCount` — сколько узлов совпало само,\n * без учёта родителей, раскрытых ради показа совпадения.\n */\nasync function applyFilter(value: string) {\n treeStore.filter(value)\n await nextTick()\n\n emit('filter', {\n value,\n visibleCount: visibleRows.value.length,\n matchedCount: treeStore.filterInfo.value.matchedKeys.size,\n })\n}\n\nfunction filter(value: string) {\n void applyFilter(value)\n}\n\nfunction resolveNodeClass(classValue: GrTreeNodeClass<T> | undefined, row: GrTreeVisibleRow<T>) {\n if (!classValue)\n return undefined\n\n return typeof classValue === 'function'\n ? classValue(row)\n : classValue\n}\n\nfunction resolveBranchLineColorValue(color: GrTreeBranchLineColor<T> | undefined, node: GrTreeNode<T>) {\n if (!color)\n return undefined\n\n return typeof color === 'function'\n ? color(node) ?? undefined\n : color\n}\n\nfunction isBranchLineActive(node: GrTreeNode<T>) {\n const selectedKey = currentKey.value\n\n if (selectedKey == null)\n return false\n\n if (node.key === selectedKey)\n return true\n\n return node.childNodes.some(child => child.key === selectedKey && !treeStore.isExpandedKey(child.key))\n}\n\nfunction resolveBranchLineColor(node: GrTreeNode<T>) {\n const defaultColor = resolveBranchLineColorValue(treeProps.branchLineColor, node) ?? DEFAULT_BRANCH_LINE_COLOR\n\n if (!isBranchLineActive(node))\n return defaultColor\n\n return resolveBranchLineColorValue(treeProps.branchLineActiveColor, node) ?? defaultColor\n}\n\n/**\n * Переводит фокус на узел (по умолчанию — на тот, что держит roving tabindex).\n * Нужен снаружи: `GrTreeSelect` открывает панель и обязан отдать клавиатуру\n * дереву, иначе стрелки из триггера никуда не ведут.\n */\nfunction focus(key?: GrTreeKey): boolean {\n const rows = visibleRows.value\n if (rows.length === 0)\n return false\n\n const target = key != null && rows.some(row => row.node.key === key)\n ? key\n : roving.rovingKey.value ?? rows[0].node.key\n\n focusRow(target)\n return true\n}\n\n// Дерево уничтожают целиком — строки размонтируются вместе с ним, и возвращать\n// фокус на умирающий корень нельзя: он уедет из документа вместе с деревом.\nonBeforeUnmount(() => {\n isUnmounting = true\n})\n\ndefineExpose<GrTreeInstance<T>>({\n appendNode: treeStore.appendNode,\n getCheckedKeys: options => treeStore.getCheckedKeys(options),\n setCheckedKeys: (keys) => {\n treeStore.setCheckedKeys(keys)\n emit('update:checkedKeys', treeStore.getCheckedKeys())\n },\n getHalfCheckedKeys: treeStore.getHalfCheckedKeys,\n setChecked: (node, checked) => {\n const changed = treeStore.setChecked(node, checked)\n if (changed)\n emitCheck(changed)\n return Boolean(changed)\n },\n filter,\n focus,\n getCurrentNode: treeStore.getCurrentNode,\n setCurrentKey: treeStore.setCurrentKey,\n getCurrentKey: treeStore.getCurrentKey,\n getNode: treeStore.getNode,\n insertNodeAfter: treeStore.insertNodeAfter,\n insertNodeBefore: treeStore.insertNodeBefore,\n removeNode: treeStore.removeNode,\n setCurrentNode: treeStore.setCurrentNode,\n})\n</script>\n\n<template>\n <div\n ref=\"treeRootEl\"\n data-gr-tree\n class=\"gr-tree\"\n :class=\"treeProps.dragHandleVisibility === 'auto' ? 'gr-tree--drag-handle-auto' : ''\"\n tabindex=\"-1\"\n :data-gr-virtual=\"treeProps.virtual ? '' : undefined\"\n role=\"tree\"\n :aria-multiselectable=\"treeProps.showCheckbox ? 'true' : undefined\"\n :style=\"rootStyle\"\n @keydown=\"onTreeKeydown\"\n >\n <div\n v-for=\"(row, windowIndex) in renderedRows\"\n :key=\"row.node.key\"\n :ref=\"(el) => {\n if (el) interactionContext.registerNodeEl(row.node.key, el as HTMLElement)\n else releaseNodeEl(row.node.key)\n if (treeProps.virtual) virtualizer.measure(absoluteIndex(windowIndex), el as Element | null)\n }\"\n data-gr-tree-node\n :data-gr-tree-node-key=\"row.node.key\"\n role=\"treeitem\"\n :aria-level=\"row.node.level\"\n :aria-posinset=\"row.posInSet\"\n :aria-setsize=\"row.setSize\"\n :aria-expanded=\"row.isLeaf ? undefined : row.isExpanded\"\n :aria-selected=\"currentKey === row.node.key ? 'true' : undefined\"\n :aria-checked=\"ariaCheckedOf(row)\"\n :aria-busy=\"row.isLoading ? 'true' : undefined\"\n :tabindex=\"isRovingItem(row.node.key) ? 0 : -1\"\n >\n <div\n data-gr-tree-row\n class=\"gr-tree__row\"\n :class=\"[\n treeProps.highlightCurrent && currentKey === row.node.key ? 'gr-tree__row--current' : '',\n row.isLeaf ? 'gr-tree__row--leaf' : '',\n row.isMatched ? 'gr-tree__row--matched' : '',\n dropTarget?.key === row.node.key && dropTarget.allowed && dropTarget.type === 'inner' ? 'gr-tree__row--drop-inner' : '',\n dropTarget?.key === row.node.key && dropTarget.allowed && dropTarget.type === 'prev' ? 'gr-tree__row--drop-prev' : '',\n dropTarget?.key === row.node.key && dropTarget.allowed && dropTarget.type === 'next' ? 'gr-tree__row--drop-next' : '',\n resolveNodeClass(treeProps.rowClass, row),\n ]\"\n :style=\"rowStyle(row)\"\n @click=\"onRowActivate(row)\"\n @contextmenu=\"onRowContextMenu($event, row.node)\"\n @drop.prevent\n @mouseenter=\"onRowMouseEnter(row.node)\"\n @mouseleave=\"onRowMouseLeave(row.node)\"\n >\n <!--\n Направляющие ветвей: по одной на каждый уровень предка. Вложенной\n обёртки с `border-left` больше нет, поэтому линию рисует сама строка —\n и заходит в зазор между строками, иначе она распалась бы на штрихи.\n -->\n <span\n v-for=\"(color, guideIndex) in row.branchColors\"\n :key=\"guideIndex\"\n data-gr-tree-branch-guide\n class=\"gr-tree__branch-guide\"\n :class=\"branchGuideModifiers(row, guideIndex)\"\n :style=\"branchGuideStyle(row, guideIndex)\"\n aria-hidden=\"true\"\n />\n\n <button\n v-if=\"treeProps.draggable\"\n type=\"button\"\n tabindex=\"-1\"\n data-gr-tree-drag-handle\n class=\"gr-tree__drag-handle\"\n :class=\"[\n shouldShowDragHandle(row.node) ? 'gr-tree__drag-handle--visible' : '',\n canDrag(row.node) ? '' : 'gr-tree__drag-handle--disabled',\n resolveNodeClass(treeProps.dragHandleClass, row),\n ]\"\n :aria-label=\"dragLabel\"\n :aria-disabled=\"canDrag(row.node) ? undefined : 'true'\"\n @click.stop\n @pointerdown=\"onHandlePointerDown($event, row.node)\"\n >\n <component\n :is=\"iconTag(treeProps.dragHandleIcon, IconGripVertical)\"\n class=\"gr-tree__drag-icon\"\n :class=\"iconClass(treeProps.dragHandleIcon)\"\n />\n </button>\n\n <!-- tabindex=\"-1\": внутри roving-композита интерактив не табируется,\n клавиатурный эквивалент — ArrowRight/ArrowLeft на строке. -->\n <button\n v-if=\"!row.isLeaf\"\n data-gr-tree-toggle\n type=\"button\"\n tabindex=\"-1\"\n class=\"gr-tree__toggle\"\n :class=\"resolveNodeClass(treeProps.toggleClass, row)\"\n :aria-label=\"row.isExpanded ? collapseLabel : expandLabel\"\n @click.stop=\"toggleExpand(row.node)\"\n >\n <IconLoaderCircle\n v-if=\"row.isLoading\"\n data-gr-tree-loading\n class=\"gr-tree__toggle-icon animate-spin\"\n />\n <component\n :is=\"iconTag(row.isExpanded ? treeProps.collapseIcon : treeProps.expandIcon, IconChevronRight)\"\n v-else\n class=\"gr-tree__toggle-icon\"\n :class=\"[\n iconClass(row.isExpanded ? treeProps.collapseIcon : treeProps.expandIcon),\n row.isExpanded && treeProps.toggleIconRotate ? 'gr-tree__toggle-icon--expanded' : '',\n resolveNodeClass(treeProps.toggleIconClass, row),\n ]\"\n />\n </button>\n <span\n v-else\n class=\"gr-tree__toggle-spacer\"\n :class=\"resolveNodeClass(treeProps.toggleSpacerClass, row)\"\n />\n\n <!--\n Квадратик отметки декоративен: состояние живёт на самом `treeitem`\n (`aria-checked`), а вложить интерактивный чекбокс внутрь роли-виджета\n нельзя — роль объявляет потомков презентационными.\n -->\n <span\n v-if=\"treeProps.showCheckbox\"\n data-gr-tree-checkbox\n class=\"gr-tree__checkbox\"\n :class=\"[\n checkStateOf(row.node.key) === 'checked' ? 'gr-tree__checkbox--checked' : '',\n checkStateOf(row.node.key) === 'half' ? 'gr-tree__checkbox--half' : '',\n ]\"\n aria-hidden=\"true\"\n @click.stop=\"toggleChecked(row.node)\"\n >\n <component\n :is=\"checkStateOf(row.node.key) === 'half' ? IconMinus : IconCheck\"\n v-if=\"checkStateOf(row.node.key) !== 'unchecked'\"\n class=\"gr-tree__checkbox-mark\"\n />\n </span>\n\n <div class=\"gr-tree__content\" :class=\"resolveNodeClass(treeProps.contentClass, row)\">\n <slot\n :node=\"row.node\"\n :data=\"row.node.data\"\n >\n <span class=\"gr-tree__label\">{{ row.node.label }}</span>\n </slot>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.gr-tree {\n --gr-tree-gap: 2px;\n --gr-tree-children-pl: 10px;\n --gr-tree-row-min-height: 28px;\n --gr-tree-row-radius: 8px;\n --gr-tree-row-px: 8px;\n --gr-tree-row-py: 8px;\n --gr-tree-row-pr: var(--gr-tree-row-px);\n --gr-tree-font-size: inherit;\n --gr-tree-row-color: var(--gr-fg);\n --gr-tree-row-hover-bg: color-mix(in srgb, var(--gr-primary) 10%, transparent);\n --gr-tree-row-current-bg: color-mix(in srgb, var(--gr-primary) 14%, transparent);\n --gr-tree-row-current-hover-bg: color-mix(in srgb, var(--gr-primary) 16%, transparent);\n --gr-tree-drag-handle-size: 24px;\n --gr-tree-drag-handle-mr: 0;\n --gr-tree-drag-handle-radius: 6px;\n --gr-tree-drag-handle-color: inherit;\n --gr-tree-drag-handle-opacity: 0.55;\n --gr-tree-drag-handle-hover-bg: color-mix(in srgb, var(--gr-muted) 22%, transparent);\n --gr-tree-drag-handle-hover-color: var(--gr-tree-drag-handle-color);\n --gr-tree-drag-handle-hover-opacity: 0.9;\n --gr-tree-drag-handle-disabled-opacity: 0.25;\n --gr-tree-toggle-size: 24px;\n --gr-tree-toggle-mr: 0;\n --gr-tree-toggle-radius: 6px;\n --gr-tree-toggle-color: inherit;\n --gr-tree-toggle-hover-bg: color-mix(in srgb, var(--gr-muted) 25%, transparent);\n --gr-tree-toggle-hover-color: var(--gr-tree-toggle-color);\n --gr-tree-icon-size: 16px;\n --gr-tree-content-gap: 8px;\n --gr-tree-branch-line-default-color: var(--gr-tree-row-current-bg);\n --gr-tree-branch-line-width: 2px;\n /* Шаг отступа уровня: переключатель, отступ вложенного списка и толщина\n направляющей — линия обязана попадать между ними. */\n --gr-tree-indent-step: calc(12px + var(--gr-tree-children-pl) + var(--gr-tree-branch-line-width));\n --gr-tree-row-current-color: var(--gr-tree-row-color);\n --gr-tree-branch-elbow-width: 8px;\n --gr-tree-branch-line-offset: 12px;\n --gr-tree-checkbox-size: 16px;\n --gr-tree-checkbox-radius: 4px;\n --gr-tree-checkbox-brd: var(--gr-brd);\n --gr-tree-checkbox-bg: transparent;\n --gr-tree-checkbox-checked-bg: var(--gr-primary);\n --gr-tree-checkbox-checked-fg: var(--gr-primary-fg);\n --gr-tree-checkbox-mr: 4px;\n display: flex;\n flex-direction: column;\n gap: var(--gr-tree-gap);\n}\n\n[data-gr-virtual]::before,\n[data-gr-virtual]::after {\n content: '';\n display: block;\n flex: none;\n}\n\n[data-gr-virtual]::before {\n height: var(--gr-virtual-before, 0px);\n}\n\n[data-gr-virtual]::after {\n height: var(--gr-virtual-after, 0px);\n}\n\n.gr-tree__row {\n position: relative;\n display: flex;\n align-items: center;\n min-height: var(--gr-tree-row-min-height);\n padding: var(--gr-tree-row-py) var(--gr-tree-row-pr) var(--gr-tree-row-py)\n calc(var(--gr-tree-row-px) + var(--gr-tree-row-indent, 0px));\n font-size: var(--gr-tree-font-size);\n cursor: default;\n user-select: none;\n outline: none;\n color: var(--gr-tree-row-color);\n isolation: isolate;\n}\n\n/* Поверхность строки — отдельный слой, вставленный слева на отступ уровня.\n Фон на самой коробке шёл от левого края дерева и накрывал направляющие\n предков: линия ветки исчезала под подсветкой ровно там, где она и нужна.\n Слой лежит ниже направляющих (они — следующие элементы строки), поэтому\n линия остаётся видна при любом наложении.\n\n `z-index: -1` уводит слой под содержимое строки. Без него позиционированный\n `::before` красится ПОВЕРХ потоковых подписи, шеврона и отметки — при\n полупрозрачном фоне это лишь лёгкое затенение, а при непрозрачном значении\n публичного токена содержимое исчезает целиком. Поднимать вместо этого\n содержимое пришлось бы у каждого элемента строки и у каждого нового.\n\n `isolation` на самой строке обязателен в паре: без своего контекста\n наложения отрицательный слой уезжает за фон ближайшего предка с заливкой, и\n подсветка пропадает на карточке. */\n.gr-tree__row::before {\n content: '';\n position: absolute;\n inset: 0 0 0 var(--gr-tree-row-indent, 0px);\n border-radius: var(--gr-tree-row-radius);\n pointer-events: none;\n z-index: -1;\n}\n\n.gr-tree__row:hover::before {\n background: var(--gr-tree-row-hover-bg);\n}\n\n/* Направляющая тянется в зазор между строками: иначе линия ветки распалась бы\n на штрихи по числу строк. */\n/* Колено: горизонтальная черта от направляющей к строке. Цвет берётся\n `inherit`, потому что сама направляющая красится инлайновой переменной —\n повторять её резолв в псевдоэлементе значило бы завести второй источник. */\n.gr-tree__branch-guide--elbow::after {\n content: '';\n position: absolute;\n left: 0;\n top: 50%;\n width: var(--gr-tree-branch-elbow-width);\n height: var(--gr-tree-branch-line-width);\n background-color: inherit;\n transform: translateY(-50%);\n}\n\n.gr-tree__branch-guide--last {\n bottom: 50%;\n}\n\n.gr-tree__branch-guide {\n position: absolute;\n top: calc(var(--gr-tree-gap) / -2);\n bottom: calc(var(--gr-tree-gap) / -2);\n width: var(--gr-tree-branch-line-width);\n background: var(--gr-tree-branch-line-color, var(--gr-tree-branch-line-default-color));\n pointer-events: none;\n}\n\n.gr-tree__checkbox {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: var(--gr-tree-checkbox-size);\n height: var(--gr-tree-checkbox-size);\n margin-right: var(--gr-tree-checkbox-mr);\n border: 1px solid var(--gr-tree-checkbox-brd);\n border-radius: var(--gr-tree-checkbox-radius);\n background: var(--gr-tree-checkbox-bg);\n color: var(--gr-tree-checkbox-checked-fg);\n cursor: pointer;\n}\n\n.gr-tree__checkbox--checked,\n.gr-tree__checkbox--half {\n border-color: var(--gr-tree-checkbox-checked-bg);\n background: var(--gr-tree-checkbox-checked-bg);\n}\n\n.gr-tree__checkbox-mark {\n width: calc(var(--gr-tree-checkbox-size) - 4px);\n height: calc(var(--gr-tree-checkbox-size) - 4px);\n}\n\n[data-gr-tree-node] {\n outline: none;\n}\n\n/* Кольцо фокуса — на той же поверхности, что подсветка: иначе строка читалась бы\n двумя разными прямоугольниками. `outline` для этого не годится — он рисуется по\n границе коробки, а не по инсету. */\n[data-gr-tree-node]:focus-visible > .gr-tree__row::before {\n box-shadow: inset 0 0 0 2px var(--gr-primary);\n}\n\n.gr-tree__row--current {\n color: var(--gr-tree-row-current-color);\n}\n\n.gr-tree__row--current::before {\n background: var(--gr-tree-row-current-bg);\n}\n\n.gr-tree__row--current:hover::before {\n background: var(--gr-tree-row-current-hover-bg);\n}\n\n.gr-tree__row--matched .gr-tree__label {\n font-weight: 600;\n}\n\n/* Ветка набирается плотнее листа: без этого «Операции» и «Эскалации» выглядят\n одним и тем же, и различает их только шеврон, которого у листа нет. */\n.gr-tree__row:not(.gr-tree__row--leaf) .gr-tree__label {\n font-weight: 600;\n}\n\n.gr-tree__drag-handle {\n width: var(--gr-tree-drag-handle-size);\n height: var(--gr-tree-drag-handle-size);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n margin-right: var(--gr-tree-drag-handle-mr);\n border-radius: var(--gr-tree-drag-handle-radius);\n color: var(--gr-tree-drag-handle-color);\n cursor: grab;\n /* Без этого вертикальный свайп по ручке уходит в прокрутку страницы,\n браузер отзывает указатель, и пальцем узел неперетаскиваем. */\n touch-action: none;\n visibility: hidden;\n pointer-events: none;\n opacity: 0;\n}\n\n/* Где наведения не бывает, ручка «по наведению» недостижима — то есть\n перетаскивания нет вовсе. Медиазапрос, а не `matchMedia`: ответ нужен и на\n сервере, а спрашивать среду в первом рендере нельзя. */\n@media (hover: none) {\n .gr-tree--drag-handle-auto .gr-tree__drag-handle {\n visibility: visible;\n pointer-events: auto;\n opacity: var(--gr-tree-drag-handle-opacity);\n }\n}\n\n.gr-tree__drag-handle--visible {\n visibility: visible;\n pointer-events: auto;\n opacity: var(--gr-tree-drag-handle-opacity);\n}\n\n.gr-tree__drag-handle:hover {\n background: var(--gr-tree-drag-handle-hover-bg);\n color: var(--gr-tree-drag-handle-hover-color);\n opacity: var(--gr-tree-drag-handle-hover-opacity);\n}\n\n.gr-tree__drag-handle:active {\n cursor: grabbing;\n}\n\n.gr-tree__drag-handle--disabled {\n cursor: default;\n opacity: var(--gr-tree-drag-handle-disabled-opacity);\n}\n\n.gr-tree__drag-icon {\n width: var(--gr-tree-icon-size);\n height: var(--gr-tree-icon-size);\n}\n\n.gr-tree__toggle {\n width: var(--gr-tree-toggle-size);\n height: var(--gr-tree-toggle-size);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n margin-right: var(--gr-tree-toggle-mr);\n border-radius: var(--gr-tree-toggle-radius);\n color: var(--gr-tree-toggle-color);\n}\n\n.gr-tree__toggle:hover {\n background: var(--gr-tree-toggle-hover-bg);\n color: var(--gr-tree-toggle-hover-color);\n}\n\n.gr-tree__toggle-icon {\n width: var(--gr-tree-icon-size);\n height: var(--gr-tree-icon-size);\n transition: transform var(--gr-duration-fast) var(--gr-ease-out);\n}\n\n.gr-tree__toggle-icon--expanded {\n transform: rotate(90deg);\n}\n\n.gr-tree__toggle-spacer {\n width: var(--gr-tree-toggle-size);\n height: var(--gr-tree-toggle-size);\n margin-right: var(--gr-tree-toggle-mr);\n display: inline-block;\n}\n\n.gr-tree__content {\n min-width: 0;\n display: flex;\n align-items: center;\n gap: var(--gr-tree-content-gap);\n}\n\n.gr-tree__label {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.gr-tree__row--drop-inner {\n outline: 2px solid color-mix(in srgb, var(--gr-primary) 40%, transparent);\n}\n\n.gr-tree__row--drop-prev::before,\n.gr-tree__row--drop-next::after {\n content: '';\n position: absolute;\n left: 8px;\n right: 8px;\n height: 2px;\n background: color-mix(in srgb, var(--gr-primary) 55%, transparent);\n}\n\n.gr-tree__row--drop-prev::before {\n top: 2px;\n}\n\n.gr-tree__row--drop-next::after {\n bottom: 2px;\n}\n</style>\n","<script setup lang=\"ts\" generic=\"T extends Record<string, any> = any\">\nimport { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue'\nimport type {\n GrTreeAllowDropType,\n GrTreeInstance,\n GrTreeKey,\n GrTreeNode,\n GrTreeNodeDropType,\n} from './grTreeTypes'\nimport { createGrTreeDataAdapter } from '../../composables/internal/treeAdapter'\nimport type { GrTreeDropTarget } from './grTreeInteractionContext'\nimport { createGrTreeInteractionContext } from './grTreeInteractionContext'\nimport type { GrTreeCheckState } from '../../composables/internal/treeChecking'\nimport { useTree } from '../../composables/useTree'\nimport { treeSizeVars } from './grTreeStyles'\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useAnnouncer } from '../../composables/useAnnouncer'\nimport { useDragSort } from '../../composables/useDragSort'\nimport { useTypeahead } from '../../composables/internal/useTypeahead'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useVirtualList } from '../../composables/useVirtualList'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { iconClass, iconTag } from '../shared/icon'\n\nimport IconCheck from '~icons/lucide/check'\nimport IconChevronRight from '~icons/lucide/chevron-right'\nimport IconGripVertical from '~icons/lucide/grip-vertical'\nimport IconLoaderCircle from '~icons/lucide/loader-circle'\nimport IconMinus from '~icons/lucide/minus'\nimport type {\n GrTreeBranchLineColor,\n GrTreeNodeClass,\n GrTreeProps,\n GrTreeVisibleRow,\n} from './grTreeProps'\n\nexport interface GrTreeEmits<T extends Record<string, any> = any> {\n (e: 'nodeClick', data: T, node: GrTreeNode<T>): void\n (e: 'nodeExpand', data: T, node: GrTreeNode<T>): void\n (e: 'nodeCollapse', data: T, node: GrTreeNode<T>): void\n (e: 'nodeDrop', draggingNode: GrTreeNode<T>, dropNode: GrTreeNode<T>, dropType: GrTreeNodeDropType): void\n (e: 'nodeContextMenu', evt: MouseEvent, data: T, node: GrTreeNode<T>): void\n (e: 'update:currentKey', key: GrTreeKey | undefined): void\n /**\n * Результат фильтрации. Без него потребитель не отличит «данных нет» от\n * «поиск ничего не нашёл» — а это разные пустые экраны: второй пользователь\n * может исправить сам.\n */\n (e: 'filter', info: { value: string, visibleCount: number, matchedCount: number }): void\n (e: 'update:checkedKeys', keys: GrTreeKey[]): void\n (e: 'check', data: T, node: GrTreeNode<T>, info: { checkedKeys: GrTreeKey[], halfCheckedKeys: GrTreeKey[] }): void\n}\n\nconst DEFAULT_BRANCH_LINE_COLOR = 'var(--gr-tree-branch-line-default-color, var(--gr-brd))'\n\n/** Стрелки, которые вместе с `Shift` двигают узел, а не фокус. */\nconst MOVE_KEYS = new Set(['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'])\n\nconst props = withDefaults(defineProps<GrTreeProps<T>>(), {\n props: () => ({\n children: 'children',\n label: 'label',\n }),\n nodeKey: 'id' as any,\n defaultExpandedKeys: () => [],\n defaultExpandAll: false,\n expandOnClickNode: false,\n accordion: false,\n size: undefined,\n highlightCurrent: true,\n indent: 0,\n virtual: false,\n maxHeight: undefined,\n showCheckbox: false,\n currentKey: undefined,\n filterValue: undefined,\n dragHandleVisibility: 'auto',\n checkedKeys: undefined,\n defaultCheckedKeys: () => [],\n checkStrictly: false,\n lazy: false,\n load: undefined,\n expandIcon: undefined,\n collapseIcon: undefined,\n toggleIconRotate: true,\n branchLine: 'line',\n branchLineColor: undefined,\n branchLineActiveColor: undefined,\n draggable: false,\n dragHandleIcon: undefined,\n dragLabel: undefined,\n expandLabel: undefined,\n collapseLabel: undefined,\n rowClass: undefined,\n dragHandleClass: undefined,\n toggleClass: undefined,\n toggleIconClass: undefined,\n toggleSpacerClass: undefined,\n contentClass: undefined,\n})\n\nconst emit = defineEmits<GrTreeEmits<T>>()\n\ndefineSlots<{\n default?: (props: { node: GrTreeNode<T>, data: T }) => any\n}>()\n\nconst dataAdapter = createGrTreeDataAdapter<T>(props)\nconst treeStore = useTree({\n adapter: dataAdapter,\n // Цвет направляющей — решение компонента, а не модели: она лишь копит цепочку\n // предков. Выключенный `branchLine` не даёт цвета вовсе, и цепочка пуста.\n branchColorFor: branchColorForNode,\n data: () => props.data,\n defaultExpandedKeys: () => props.defaultExpandedKeys,\n defaultExpandAll: () => props.defaultExpandAll,\n filterNodeMethod: filterNodeForModel,\n defaultCheckedKeys: () => props.defaultCheckedKeys,\n checkedKeys: () => props.checkedKeys,\n checkStrictly: () => props.checkStrictly,\n lazy: () => props.lazy,\n load: loadForModel,\n})\nconst interactionContext = createGrTreeInteractionContext(props, {\n emitNodeClick: (data, node) => emit('nodeClick', data, node),\n emitNodeExpand: (data, node) => emit('nodeExpand', data, node),\n emitNodeCollapse: (data, node) => emit('nodeCollapse', data, node),\n emitNodeDrop: (draggingNode, dropNode, dropType) => emit('nodeDrop', draggingNode, dropNode, dropType),\n emitNodeContextMenu: (evt, data, node) => emit('nodeContextMenu', evt, data, node),\n})\n\nconst treeProps = props as Readonly<GrTreeProps<T>>\n\nconst { t } = useGranularityTranslations()\nconst { announce } = useAnnouncer()\nconst dragLabel = computed(() => treeProps.dragLabel ?? t('gr.tree.drag', 'Drag'))\nconst expandLabel = computed(() => treeProps.expandLabel ?? t('gr.tree.expand', 'Expand'))\nconst collapseLabel = computed(() => treeProps.collapseLabel ?? t('gr.tree.collapse', 'Collapse'))\nconst currentKey = treeStore.currentKey\nconst hoveredKey = interactionContext.hoveredKey\nconst dropTarget = interactionContext.dropTarget\n\n/**\n * Текущий узел: управляемый режим включает сам факт того, что проп задан.\n *\n * Иначе у одного понятия два владельца — подсветку рисует дерево по своему\n * ключу, а обёртка считает остальное по своему пропу; разойдись они на такт, и\n * строка подсвечена, а подпись не выделена. С `v-model:current-key` источник\n * правды один, и `nextTick` вокруг `setCurrentKey()` больше не нужен.\n */\nconst currentKeyControlled = computed(() => treeProps.currentKey !== undefined)\n\nwatch(() => treeProps.currentKey, (key) => {\n if (!currentKeyControlled.value)\n return\n if (treeStore.currentKey.value === (key ?? undefined))\n return\n\n treeStore.setCurrentKey(key ?? undefined)\n}, { immediate: true })\n\n/** Значение фильтра приходит пропом; метод `filter()` остаётся для императивных сценариев. */\nwatch(() => treeProps.filterValue, (value) => {\n if (value === undefined)\n return\n\n applyFilter(value)\n}, { immediate: true })\n\n// Корневой элемент дерева — область для делегированной клавиатуры (WAI-ARIA tree).\nconst treeRootEl = ref<HTMLElement | null>(null)\n\n/**\n * Видимые строки считает модель (`useTree`): в плоском DOM группы нет, и\n * структуру дерева диктору сообщают `aria-level`, `aria-posinset` и\n * `aria-setsize` — всё это приходит из неё готовым.\n */\nconst visibleRows = treeStore.visibleRows\n\n/**\n * Кольцо roving-фокуса: ровно один `treeitem` на всё дерево держит `tabindex=0`.\n *\n * Ориентация вертикальная намеренно: влево-вправо в дереве заняты раскрытием\n * ветки и переходом к родителю, и примитив их не трогает — это доменная логика,\n * она осталась в `onTreeKeydown`.\n */\nconst roving = useRovingFocus<GrTreeNode<T>['key']>({\n items: () => visibleRows.value.map(row => row.node.key),\n elementFor: key => interactionContext.nodeEls.get(key),\n orientation: () => 'vertical',\n // У дерева есть верх и низ: с последней строки вниз идти некуда.\n wrap: () => false,\n // Но клавишу на краю всё равно гасим: иначе `ArrowDown` на последнем узле\n // прокрутит страницу под деревом.\n onOverflow: () => true,\n // Пока фокус не трогали, остановку держит текущий (выбранный) узел, а если\n // его не видно — первая видимая строка.\n initialKey: () => currentKey.value ?? undefined,\n beforeFocus: key => scrollRowIntoView(key),\n})\n\nfunction onRowClick(node: GrTreeNode<T>) {\n // В управляемом режиме дерево ведёт подсветку до ответа снаружи: строка\n // отзывается на клик сразу, а расхождение снимет наблюдатель за пропом.\n treeStore.setCurrentKey(node.key)\n emit('update:currentKey', node.key)\n roving.setActive(node.key)\n interactionContext.emitNodeClick(node.data, node)\n}\n\n// Клик мышью, в отличие от Enter, умеет ещё и раскрывать узел: `Enter` в\n// паттерне tree закреплён за выбором, и подмешивать в него раскрытие нельзя.\nfunction onRowActivate(row: GrTreeVisibleRow<T>) {\n onRowClick(row.node)\n\n if (treeProps.expandOnClickNode && !row.isLeaf)\n toggleExpand(row.node)\n}\n\nfunction onRowContextMenu(evt: MouseEvent, node: GrTreeNode<T>) {\n interactionContext.emitNodeContextMenu(evt, node.data, node)\n}\n\n// ————— Клавиатурная навигация по WAI-ARIA tree pattern (только корневой инстанс).\n\nfunction isRovingItem(key: GrTreeNode<T>['key']): boolean {\n return roving.rovingKey.value === key\n}\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrTree' })\n\n// Переменные ставим и вложенным уровням тоже: `v-bind=\"props\"` доносит до них\n// `size`, а значения одинаковые — наследование от корня не нарушается.\nconst sizeStyle = computed(() => treeSizeVars[resolvedSize.value])\n\n/**\n * Виртуализация: в DOM живёт только окно вокруг вьюпорта.\n *\n * Корень дерева и есть скроллер — обёрток-распорок между `role=\"tree\"` и\n * `role=\"treeitem\"` быть не должно, поэтому срезанное сверху и снизу держат\n * отступы самого корня.\n */\nconst TREE_ROW_GAP = 2\n\nconst rowEstimate = computed(() => Number.parseFloat(sizeStyle.value['--gr-tree-row-min-height']))\n\nconst virtualMaxHeight = computed(() => {\n const value = treeProps.maxHeight\n if (value == null)\n return undefined\n return typeof value === 'number' ? `${value}px` : value\n})\n\nconst virtualizer = useVirtualList({\n container: treeRootEl,\n count: () => (treeProps.virtual ? visibleRows.value.length : 0),\n // Раскрытие/фильтр сдвигают индексы строк — замеры прошлого набора невалидны.\n source: () => visibleRows.value,\n itemSize: () => rowEstimate.value,\n gap: TREE_ROW_GAP,\n // Первый рендер обязан совпасть с серверным: контейнера ещё нет, и окно\n // считается от объявленной высоты, а не от измеренной.\n viewportSize: () => (typeof treeProps.maxHeight === 'number' ? treeProps.maxHeight : undefined),\n})\n\n/** Строки к отрисовке: при выключенной виртуализации — все. */\nconst renderedRows = computed(() => {\n if (!treeProps.virtual)\n return visibleRows.value\n\n const { start, end } = virtualizer.range.value\n return visibleRows.value.slice(start, end)\n})\n\n/**\n * Срезанное сверху и снизу держат псевдоэлементы контейнера.\n *\n * Ни один из трёх напрашивающихся вариантов не годится:\n *\n * - `padding` контейнера — `max-height` меряет ту же коробку, и распорка в сто\n * тысяч пикселей либо раздувает скроллер до той же сотни тысяч, либо съедает\n * всю его высоту;\n * - обёртка-распорка внутри — между `role=\"tree\"` и `role=\"treeitem\"` не должно\n * быть посторонних узлов, роль потеряла бы обязательных потомков;\n * - отступы крайних отрисованных строк — распорка исчезает ровно в тот момент,\n * когда строки заменяются целиком (прыжок прокрутки), содержимое схлопывается\n * до высоты окна, и браузер обрезает `scrollTop` до почти нуля.\n *\n * `::before`/`::after` не узлы DOM: их не за что размонтировать, в дереве\n * доступности их нет, а высота приезжает переменными в том же патче, что и сами\n * строки, — схлопнуться между кадрами нечему.\n */\nconst rootStyle = computed(() => {\n if (!treeProps.virtual)\n return sizeStyle.value\n\n return {\n ...sizeStyle.value,\n overflow: 'auto',\n maxHeight: virtualMaxHeight.value,\n ...virtualizer.spacerStyle.value,\n }\n})\n\n/** Абсолютный индекс отрисованной строки: поиск по массиву стоил бы O(n) на строку. */\nfunction absoluteIndex(offsetInWindow: number): number {\n return treeProps.virtual ? virtualizer.range.value.start + offsetInWindow : offsetInWindow\n}\n\n/**\n * Строка размонтируется: снимаем регистрацию и, если фокус был на ней, уводим\n * его на корень — делегированный keydown живёт там, первая же стрелка вернёт\n * видимую строку через `focusRow`. Иначе фокус упал бы на `body` и клавиатура\n * дерева умерла бы до клика мышью.\n *\n * Спрашиваем сам элемент, а не `document.activeElement === body`: Vue обнуляет\n * function ref ДО удаления узла, поэтому в момент вызова фокус ещё на строке —\n * а «фокус на body» означает лишь то, что страницу никто не трогал.\n */\nlet isUnmounting = false\n\nfunction releaseNodeEl(key: GrTreeKey): void {\n const el = interactionContext.nodeEls.get(key)\n const active = typeof document === 'undefined' ? null : document.activeElement\n const heldFocus = Boolean(el && active && (el === active || el.contains(active)))\n\n interactionContext.registerNodeEl(key, null)\n\n if (heldFocus && !isUnmounting)\n treeRootEl.value?.focus({ preventScroll: true })\n}\n\n/**\n * При виртуализации узла вне окна в DOM нет: `nodeEls.get` вернул бы\n * `undefined`, а фокус уехал бы на `body` вместе с размонтированной строкой.\n * Поэтому сперва прокрутка, и только следующим тиком — фокус.\n */\nfunction scrollRowIntoView(key: GrTreeNode<T>['key']): Promise<void> {\n if (treeProps.virtual) {\n const index = visibleRows.value.findIndex(row => row.node.key === key)\n if (index >= 0)\n virtualizer.scrollToIndex(index)\n }\n\n return nextTick()\n}\n\nfunction focusRow(key: GrTreeNode<T>['key']): void {\n void roving.focusKey(key)\n}\n\n/**\n * Typeahead паттерна tree: печатные символы копятся в буфер и переводят фокус\n * на первый подходящий видимый узел, начиная со следующего за текущим.\n *\n * Поиск идёт по данным (`visibleRows`), а не по DOM: при виртуализации узла вне\n * окна в разметке нет, и поиск по тексту элементов находил бы только видимое.\n */\nconst typeahead = useTypeahead<GrTreeVisibleRow<T>>({\n items: () => visibleRows.value,\n textOf: row => row.node.label,\n // Без наведённого фокуса ищем с начала списка, а не от конца: `findIndex`\n // вернул бы `-1`, и первая строка выпала бы из обхода.\n currentIndex: rows => Math.max(0, rows.findIndex(row => row.node.key === roving.rovingKey.value)),\n onMatch: row => focusRow(row.node.key),\n})\n\n/** `*` — раскрыть всех соседей узла, на котором фокус (уровень целиком). */\nfunction expandSiblings(node: GrTreeNode<T>): void {\n const siblings = node.parent ? node.parent.childNodes : treeStore.treeModel.value.roots\n\n for (const sibling of siblings) {\n if (sibling.childNodes.length === 0 || treeStore.isExpandedKey(sibling.key))\n continue\n\n treeStore.setExpandedKey(sibling.key, true)\n interactionContext.emitNodeExpand(sibling.data, sibling)\n }\n}\n\nfunction onTreeKeydown(event: KeyboardEvent): void {\n // Делегированная клавиатура уважает интерактивные цели: печать в инпуте слота\n // узла — ввод текста, а не typeahead. Без гарда preventDefault отменял бы это.\n const target = event.target as HTMLElement | null\n const interactive = target?.closest<HTMLElement>('button, a[href], input, select, textarea, [contenteditable]')\n if (interactive && interactive !== event.currentTarget) {\n // Табируемая цель — самостоятельный таб-стоп: клавиатура целиком её.\n if (interactive.tabIndex >= 0)\n return\n\n // Кнопки строки (toggle, drag-handle) не табируемы: фокус попадает на них\n // только мышью. За ними остаётся активация — Enter на toggle это его клик, —\n // а навигация принадлежит дереву, иначе клик мышью убивал бы стрелки.\n if (event.key === 'Enter' || event.key === ' ')\n return\n }\n\n const rows = visibleRows.value\n if (rows.length === 0)\n return\n\n const idx = Math.max(0, rows.findIndex(r => r.node.key === roving.rovingKey.value))\n const cur = rows[idx]\n\n if (event.key === '*') {\n event.preventDefault()\n expandSiblings(cur.node)\n return\n }\n\n // Печатный символ без модификаторов — typeahead, а не команда.\n if (event.key.length === 1 && event.key !== ' ' && !event.ctrlKey && !event.metaKey && !event.altKey) {\n event.preventDefault()\n typeahead.type(event.key)\n return\n }\n\n // `Shift` со стрелкой двигает сам узел — раскладка аутлайнера. Проверяется\n // раньше навигации: иначе примитив увёл бы фокус вместо переноса.\n if (event.shiftKey && MOVE_KEYS.has(event.key)) {\n if (!treeProps.draggable)\n return\n\n event.preventDefault()\n void onNodeMoveKey(cur.node, event.key)\n return\n }\n\n // Вертикаль, `Home` и `End` ведёт примитив. Влево-вправо он не трогает: в\n // дереве это раскрытие ветки и переход к родителю, а не движение по списку.\n if (roving.handleNavigationKeys(event))\n return\n\n switch (event.key) {\n case 'ArrowRight':\n event.preventDefault()\n if (!cur.isLeaf) {\n if (!cur.isExpanded)\n toggleExpand(cur.node)\n else if (idx < rows.length - 1)\n focusRow(rows[idx + 1].node.key)\n }\n break\n case 'ArrowLeft':\n event.preventDefault()\n if (!cur.isLeaf && cur.isExpanded)\n toggleExpand(cur.node)\n else if (cur.node.parent && rows.some(r => r.node.key === cur.node.parent!.key))\n focusRow(cur.node.parent.key)\n break\n case 'Enter':\n event.preventDefault()\n onRowClick(cur.node)\n break\n // Space при чекбоксах переключает отметку — это и есть выбор в\n // multi-select дереве; без них он остаётся вторым способом выбрать узел.\n case ' ':\n event.preventDefault()\n if (treeProps.showCheckbox)\n toggleChecked(cur.node)\n else\n onRowClick(cur.node)\n break\n }\n}\n\nfunction onRowMouseEnter(node: GrTreeNode<T>) {\n hoveredKey.value = node.key\n}\n\nfunction onRowMouseLeave(node: GrTreeNode<T>) {\n if (hoveredKey.value === node.key)\n hoveredKey.value = undefined\n}\n\nfunction collapseSiblings(node: GrTreeNode<T>) {\n const siblings = node.parent ? node.parent.childNodes : treeStore.treeModel.value.roots\n\n for (const sibling of siblings) {\n if (sibling.key === node.key || !treeStore.isExpandedKey(sibling.key))\n continue\n\n treeStore.setExpandedKey(sibling.key, false)\n interactionContext.emitNodeCollapse(sibling.data, sibling)\n }\n}\n\nfunction toggleExpand(node: GrTreeNode<T>) {\n const expanded = !treeStore.isExpandedKey(node.key)\n\n if (expanded && treeProps.accordion)\n collapseSiblings(node)\n\n // Ленивая ветка грузится по первому раскрытию; повторное ничего не запрашивает.\n if (expanded)\n treeStore.ensureLoaded(node)\n\n treeStore.toggleExpand(node)\n\n if (expanded)\n interactionContext.emitNodeExpand(node.data, node)\n else\n interactionContext.emitNodeCollapse(node.data, node)\n}\n\n// ————— Отметки (чекбоксы).\n\nfunction checkStateOf(key: GrTreeKey): GrTreeCheckState {\n return treeStore.getCheckState(key)\n}\n\nfunction ariaCheckedOf(row: GrTreeVisibleRow<T>): 'true' | 'false' | 'mixed' | undefined {\n if (!treeProps.showCheckbox)\n return undefined\n\n const state = checkStateOf(row.node.key)\n return state === 'checked' ? 'true' : state === 'half' ? 'mixed' : 'false'\n}\n\nfunction emitCheck(node: GrTreeNode<T>): void {\n const checkedKeys = treeStore.getCheckedKeys()\n emit('update:checkedKeys', checkedKeys)\n emit('check', node.data, node, { checkedKeys, halfCheckedKeys: treeStore.getHalfCheckedKeys() })\n}\n\nfunction toggleChecked(node: GrTreeNode<T>): void {\n if (!treeProps.showCheckbox)\n return\n\n const changed = treeStore.toggleChecked(node)\n if (changed)\n emitCheck(changed)\n}\n\n// ————— Геометрия строки: отступ уровня и направляющие ветвей.\n\nfunction rowStyle(row: GrTreeVisibleRow<T>) {\n const step = treeProps.indent && treeProps.indent > 0\n ? `${treeProps.indent}px`\n : 'var(--gr-tree-indent-step)'\n\n return { '--gr-tree-row-indent': `calc(${step} * ${row.node.level - 1})` }\n}\n\n/**\n * Направляющая уровня-предка. Считается от того же шага отступа, что и сам\n * отступ строки, — иначе линия и содержимое разъедутся на вложенных уровнях.\n */\n/**\n * Колено рисуется только у направляющей собственного уровня строки: остальные\n * — это транзит предков, и горизонтальная черта у них указывала бы на строку,\n * к которой они не относятся.\n *\n * У последнего ребёнка вертикаль обрывается на середине: продолжать её значит\n * обещать сиблинга, которого нет.\n */\n/**\n * Цвет направляющей уровня для модели. Объявление функцией, а не стрелкой на\n * месте вызова: `treeProps` определяются ниже, и ссылка на них в выражении\n * читалась бы до объявления.\n */\n/**\n * Обёртки над пропами для модели: объявлением, а не стрелкой на месте вызова —\n * `treeProps` определяются ниже. `undefined` от фильтра означает «решай сам»:\n * так обёртка возвращает модель к её подстрочному матчу, когда своего правила\n * потребитель не задал.\n */\nfunction filterNodeForModel(value: string, data: T, node: GrTreeNode<T>) {\n return treeProps.filterNodeMethod?.(value, data, node)\n}\n\nfunction loadForModel(node: GrTreeNode<T>, resolve: (children: T[]) => void) {\n treeProps.load?.(node, resolve)\n}\n\nfunction branchColorForNode(node: GrTreeNode<T>) {\n return treeProps.branchLine ? resolveBranchLineColor(node) : undefined\n}\n\nfunction branchGuideModifiers(row: GrTreeVisibleRow<T>, index: number) {\n if (treeProps.branchLine !== 'elbow' || index !== row.branchColors.length - 1)\n return undefined\n\n return row.posInSet === row.setSize\n ? 'gr-tree__branch-guide--elbow gr-tree__branch-guide--last'\n : 'gr-tree__branch-guide--elbow'\n}\n\nfunction branchGuideStyle(row: GrTreeVisibleRow<T>, index: number) {\n const step = treeProps.indent && treeProps.indent > 0\n ? `${treeProps.indent}px`\n : 'var(--gr-tree-indent-step)'\n\n return {\n 'left': `calc(${step} * ${index} + var(--gr-tree-branch-line-offset))`,\n '--gr-tree-branch-line-color': row.branchColors[index],\n }\n}\n\n// Drag & drop\nfunction canDrag(node: GrTreeNode<T>): boolean {\n return interactionContext.canDrag(node)\n}\n\n/**\n * Ручка «по наведению» на тач-устройстве недостижима: событий наведения там нет,\n * ключ не выставляется, класс видимости не появляется — то есть перетаскивания\n * нет вовсе, хотя `touch-action: none` у ручки стоит ровно ради него.\n *\n * Режим `auto` решает это без JS: класс-модификатор на корне, а показ включает\n * `@media (hover: none)` — так поведение остаётся верным и на сервере, где\n * никакого `matchMedia` спрашивать нельзя.\n */\nfunction shouldShowDragHandle(node: GrTreeNode<T>): boolean {\n if (!canDrag(node))\n return false\n\n return treeProps.dragHandleVisibility === 'always' || hoveredKey.value === node.key\n}\n\n/**\n * Треть строки сверху — «до», треть снизу — «после», середина — «внутрь».\n * Зоны нарезает компонент: примитив отдаёт только долю вдоль строки.\n */\nfunction dropTypeFromFraction(fraction: number): GrTreeNodeDropType {\n if (fraction < 1 / 3)\n return 'prev'\n if (fraction > 2 / 3)\n return 'next'\n\n return 'inner'\n}\n\nfunction canDrop(drag: GrTreeNode<T>, target: GrTreeNode<T>, type: GrTreeAllowDropType): boolean {\n return interactionContext.canDrop(drag, target, type)\n}\n\n/** Перенос состоялся: одна дорога и для указателя, и для клавиатуры. */\nfunction applyMove(source: GrTreeNode<T>, targetKey: GrTreeKey, type: GrTreeNodeDropType): boolean {\n const reference = treeStore.getNode(targetKey)\n if (!reference)\n return false\n\n const movedNode = treeStore.moveNode(source, reference, type)\n if (!movedNode)\n return false\n\n const dropNode = treeStore.getNode(reference.key) ?? reference\n interactionContext.emitNodeDrop(movedNode, dropNode, type)\n\n return true\n}\n\nconst dragSort = useDragSort<GrTreeKey, GrTreeDropTarget>({\n items: () => visibleRows.value.map(row => row.node.key),\n elementFor: key => interactionContext.nodeEls.get(key) ?? null,\n scroller: () => treeRootEl.value,\n disabled: () => !treeProps.draggable,\n canDrag: (key) => {\n const node = treeStore.getNode(key)\n\n return node ? canDrag(node) : false\n },\n resolveTarget: (hit, sourceKey, previous) => {\n const source = treeStore.getNode(sourceKey)\n const node = treeStore.getNode(hit.key)\n if (!source || !node)\n return null\n\n const type = dropTypeFromFraction(hit.fraction)\n const allowed = treeStore.canMoveNode(source, node, type) && canDrop(source, node, type)\n\n // Та же ссылка, пока смысл не изменился: иначе подсветка перерисовывалась бы\n // на каждом движении указателя.\n if (previous && previous.key === node.key && previous.type === type && previous.allowed === allowed)\n return previous\n\n return { key: node.key, type, allowed }\n },\n onDrop: (sourceKey, target) => {\n const source = treeStore.getNode(sourceKey)\n if (!source || !target.allowed)\n return\n\n applyMove(source, target.key, target.type)\n },\n onUpdate: (sourceKey, target) => {\n interactionContext.draggingNode.value = sourceKey === null ? null : treeStore.getNode(sourceKey) ?? null\n interactionContext.dropTarget.value = target\n },\n})\n\nfunction onHandlePointerDown(event: PointerEvent, node: GrTreeNode<T>): void {\n if (!treeProps.draggable)\n return\n\n dragSort.startFrom(node.key)(event)\n}\n\n/**\n * Клавиатурный перенос — раскладка аутлайнера: `Shift` со стрелкой сразу\n * двигает узел, без режима «взято». Режим здесь был бы лишним: `Space` в дереве\n * уже отмечает чекбокс, а стрелки водят фокус по веткам.\n */\nfunction moveByKeyboard(node: GrTreeNode<T>, key: string): boolean {\n const siblings = node.parent ? node.parent.childNodes : treeStore.treeModel.value.roots\n const index = siblings.findIndex(sibling => sibling.key === node.key)\n\n if (key === 'ArrowUp' && index > 0)\n return applyMove(node, siblings[index - 1].key, 'prev')\n\n if (key === 'ArrowDown' && index >= 0 && index < siblings.length - 1)\n return applyMove(node, siblings[index + 1].key, 'next')\n\n // Вправо — в предыдущего соседа: у первого в уровне такого соседа нет.\n if (key === 'ArrowRight' && index > 0)\n return applyMove(node, siblings[index - 1].key, 'inner')\n\n if (key === 'ArrowLeft' && node.parent)\n return applyMove(node, node.parent.key, 'next')\n\n return false\n}\n\nasync function onNodeMoveKey(node: GrTreeNode<T>, key: string): Promise<void> {\n if (!treeProps.draggable || !canDrag(node))\n return\n if (!moveByKeyboard(node, key))\n return\n\n announce(t('gr.tree.moved', 'Moved {label}', { label: node.label }))\n\n // Перестановка перерисовывает уровень: без возврата фокуса следующий Shift\n // уже некуда было бы адресовать.\n await nextTick()\n focusRow(node.key)\n}\n\n/**\n * Фильтрация и отчёт о её результате.\n *\n * Счёт снимается после пересчёта видимых строк: `visibleCount` — то, что\n * пользователь реально видит, а `matchedCount` — сколько узлов совпало само,\n * без учёта родителей, раскрытых ради показа совпадения.\n */\nasync function applyFilter(value: string) {\n treeStore.filter(value)\n await nextTick()\n\n emit('filter', {\n value,\n visibleCount: visibleRows.value.length,\n matchedCount: treeStore.filterInfo.value.matchedKeys.size,\n })\n}\n\nfunction filter(value: string) {\n void applyFilter(value)\n}\n\nfunction resolveNodeClass(classValue: GrTreeNodeClass<T> | undefined, row: GrTreeVisibleRow<T>) {\n if (!classValue)\n return undefined\n\n return typeof classValue === 'function'\n ? classValue(row)\n : classValue\n}\n\nfunction resolveBranchLineColorValue(color: GrTreeBranchLineColor<T> | undefined, node: GrTreeNode<T>) {\n if (!color)\n return undefined\n\n return typeof color === 'function'\n ? color(node) ?? undefined\n : color\n}\n\nfunction isBranchLineActive(node: GrTreeNode<T>) {\n const selectedKey = currentKey.value\n\n if (selectedKey == null)\n return false\n\n if (node.key === selectedKey)\n return true\n\n return node.childNodes.some(child => child.key === selectedKey && !treeStore.isExpandedKey(child.key))\n}\n\nfunction resolveBranchLineColor(node: GrTreeNode<T>) {\n const defaultColor = resolveBranchLineColorValue(treeProps.branchLineColor, node) ?? DEFAULT_BRANCH_LINE_COLOR\n\n if (!isBranchLineActive(node))\n return defaultColor\n\n return resolveBranchLineColorValue(treeProps.branchLineActiveColor, node) ?? defaultColor\n}\n\n/**\n * Переводит фокус на узел (по умолчанию — на тот, что держит roving tabindex).\n * Нужен снаружи: `GrTreeSelect` открывает панель и обязан отдать клавиатуру\n * дереву, иначе стрелки из триггера никуда не ведут.\n */\nfunction focus(key?: GrTreeKey): boolean {\n const rows = visibleRows.value\n if (rows.length === 0)\n return false\n\n const target = key != null && rows.some(row => row.node.key === key)\n ? key\n : roving.rovingKey.value ?? rows[0].node.key\n\n focusRow(target)\n return true\n}\n\n// Дерево уничтожают целиком — строки размонтируются вместе с ним, и возвращать\n// фокус на умирающий корень нельзя: он уедет из документа вместе с деревом.\nonBeforeUnmount(() => {\n isUnmounting = true\n})\n\ndefineExpose<GrTreeInstance<T>>({\n appendNode: treeStore.appendNode,\n getCheckedKeys: options => treeStore.getCheckedKeys(options),\n setCheckedKeys: (keys) => {\n treeStore.setCheckedKeys(keys)\n emit('update:checkedKeys', treeStore.getCheckedKeys())\n },\n getHalfCheckedKeys: treeStore.getHalfCheckedKeys,\n setChecked: (node, checked) => {\n const changed = treeStore.setChecked(node, checked)\n if (changed)\n emitCheck(changed)\n return Boolean(changed)\n },\n filter,\n focus,\n getCurrentNode: treeStore.getCurrentNode,\n setCurrentKey: treeStore.setCurrentKey,\n getCurrentKey: treeStore.getCurrentKey,\n getNode: treeStore.getNode,\n insertNodeAfter: treeStore.insertNodeAfter,\n insertNodeBefore: treeStore.insertNodeBefore,\n removeNode: treeStore.removeNode,\n setCurrentNode: treeStore.setCurrentNode,\n})\n</script>\n\n<template>\n <div\n ref=\"treeRootEl\"\n data-gr-tree\n class=\"gr-tree\"\n :class=\"treeProps.dragHandleVisibility === 'auto' ? 'gr-tree--drag-handle-auto' : ''\"\n tabindex=\"-1\"\n :data-gr-virtual=\"treeProps.virtual ? '' : undefined\"\n role=\"tree\"\n :aria-multiselectable=\"treeProps.showCheckbox ? 'true' : undefined\"\n :style=\"rootStyle\"\n @keydown=\"onTreeKeydown\"\n >\n <div\n v-for=\"(row, windowIndex) in renderedRows\"\n :key=\"row.node.key\"\n :ref=\"(el) => {\n if (el) interactionContext.registerNodeEl(row.node.key, el as HTMLElement)\n else releaseNodeEl(row.node.key)\n if (treeProps.virtual) virtualizer.measure(absoluteIndex(windowIndex), el as Element | null)\n }\"\n data-gr-tree-node\n :data-gr-tree-node-key=\"row.node.key\"\n role=\"treeitem\"\n :aria-level=\"row.node.level\"\n :aria-posinset=\"row.posInSet\"\n :aria-setsize=\"row.setSize\"\n :aria-expanded=\"row.isLeaf ? undefined : row.isExpanded\"\n :aria-selected=\"currentKey === row.node.key ? 'true' : undefined\"\n :aria-checked=\"ariaCheckedOf(row)\"\n :aria-busy=\"row.isLoading ? 'true' : undefined\"\n :tabindex=\"isRovingItem(row.node.key) ? 0 : -1\"\n >\n <div\n data-gr-tree-row\n class=\"gr-tree__row\"\n :class=\"[\n treeProps.highlightCurrent && currentKey === row.node.key ? 'gr-tree__row--current' : '',\n row.isLeaf ? 'gr-tree__row--leaf' : '',\n row.isMatched ? 'gr-tree__row--matched' : '',\n dropTarget?.key === row.node.key && dropTarget.allowed && dropTarget.type === 'inner' ? 'gr-tree__row--drop-inner' : '',\n dropTarget?.key === row.node.key && dropTarget.allowed && dropTarget.type === 'prev' ? 'gr-tree__row--drop-prev' : '',\n dropTarget?.key === row.node.key && dropTarget.allowed && dropTarget.type === 'next' ? 'gr-tree__row--drop-next' : '',\n resolveNodeClass(treeProps.rowClass, row),\n ]\"\n :style=\"rowStyle(row)\"\n @click=\"onRowActivate(row)\"\n @contextmenu=\"onRowContextMenu($event, row.node)\"\n @drop.prevent\n @mouseenter=\"onRowMouseEnter(row.node)\"\n @mouseleave=\"onRowMouseLeave(row.node)\"\n >\n <!--\n Направляющие ветвей: по одной на каждый уровень предка. Вложенной\n обёртки с `border-left` больше нет, поэтому линию рисует сама строка —\n и заходит в зазор между строками, иначе она распалась бы на штрихи.\n -->\n <span\n v-for=\"(color, guideIndex) in row.branchColors\"\n :key=\"guideIndex\"\n data-gr-tree-branch-guide\n class=\"gr-tree__branch-guide\"\n :class=\"branchGuideModifiers(row, guideIndex)\"\n :style=\"branchGuideStyle(row, guideIndex)\"\n aria-hidden=\"true\"\n />\n\n <button\n v-if=\"treeProps.draggable\"\n type=\"button\"\n tabindex=\"-1\"\n data-gr-tree-drag-handle\n class=\"gr-tree__drag-handle\"\n :class=\"[\n shouldShowDragHandle(row.node) ? 'gr-tree__drag-handle--visible' : '',\n canDrag(row.node) ? '' : 'gr-tree__drag-handle--disabled',\n resolveNodeClass(treeProps.dragHandleClass, row),\n ]\"\n :aria-label=\"dragLabel\"\n :aria-disabled=\"canDrag(row.node) ? undefined : 'true'\"\n @click.stop\n @pointerdown=\"onHandlePointerDown($event, row.node)\"\n >\n <component\n :is=\"iconTag(treeProps.dragHandleIcon, IconGripVertical)\"\n class=\"gr-tree__drag-icon\"\n :class=\"iconClass(treeProps.dragHandleIcon)\"\n />\n </button>\n\n <!-- tabindex=\"-1\": внутри roving-композита интерактив не табируется,\n клавиатурный эквивалент — ArrowRight/ArrowLeft на строке. -->\n <button\n v-if=\"!row.isLeaf\"\n data-gr-tree-toggle\n type=\"button\"\n tabindex=\"-1\"\n class=\"gr-tree__toggle\"\n :class=\"resolveNodeClass(treeProps.toggleClass, row)\"\n :aria-label=\"row.isExpanded ? collapseLabel : expandLabel\"\n @click.stop=\"toggleExpand(row.node)\"\n >\n <IconLoaderCircle\n v-if=\"row.isLoading\"\n data-gr-tree-loading\n class=\"gr-tree__toggle-icon animate-spin\"\n />\n <component\n :is=\"iconTag(row.isExpanded ? treeProps.collapseIcon : treeProps.expandIcon, IconChevronRight)\"\n v-else\n class=\"gr-tree__toggle-icon\"\n :class=\"[\n iconClass(row.isExpanded ? treeProps.collapseIcon : treeProps.expandIcon),\n row.isExpanded && treeProps.toggleIconRotate ? 'gr-tree__toggle-icon--expanded' : '',\n resolveNodeClass(treeProps.toggleIconClass, row),\n ]\"\n />\n </button>\n <span\n v-else\n class=\"gr-tree__toggle-spacer\"\n :class=\"resolveNodeClass(treeProps.toggleSpacerClass, row)\"\n />\n\n <!--\n Квадратик отметки декоративен: состояние живёт на самом `treeitem`\n (`aria-checked`), а вложить интерактивный чекбокс внутрь роли-виджета\n нельзя — роль объявляет потомков презентационными.\n -->\n <span\n v-if=\"treeProps.showCheckbox\"\n data-gr-tree-checkbox\n class=\"gr-tree__checkbox\"\n :class=\"[\n checkStateOf(row.node.key) === 'checked' ? 'gr-tree__checkbox--checked' : '',\n checkStateOf(row.node.key) === 'half' ? 'gr-tree__checkbox--half' : '',\n ]\"\n aria-hidden=\"true\"\n @click.stop=\"toggleChecked(row.node)\"\n >\n <component\n :is=\"checkStateOf(row.node.key) === 'half' ? IconMinus : IconCheck\"\n v-if=\"checkStateOf(row.node.key) !== 'unchecked'\"\n class=\"gr-tree__checkbox-mark\"\n />\n </span>\n\n <div class=\"gr-tree__content\" :class=\"resolveNodeClass(treeProps.contentClass, row)\">\n <slot\n :node=\"row.node\"\n :data=\"row.node.data\"\n >\n <span class=\"gr-tree__label\">{{ row.node.label }}</span>\n </slot>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.gr-tree {\n --gr-tree-gap: 2px;\n --gr-tree-children-pl: 10px;\n --gr-tree-row-min-height: 28px;\n --gr-tree-row-radius: 8px;\n --gr-tree-row-px: 8px;\n --gr-tree-row-py: 8px;\n --gr-tree-row-pr: var(--gr-tree-row-px);\n --gr-tree-font-size: inherit;\n --gr-tree-row-color: var(--gr-fg);\n --gr-tree-row-hover-bg: color-mix(in srgb, var(--gr-primary) 10%, transparent);\n --gr-tree-row-current-bg: color-mix(in srgb, var(--gr-primary) 14%, transparent);\n --gr-tree-row-current-hover-bg: color-mix(in srgb, var(--gr-primary) 16%, transparent);\n --gr-tree-drag-handle-size: 24px;\n --gr-tree-drag-handle-mr: 0;\n --gr-tree-drag-handle-radius: 6px;\n --gr-tree-drag-handle-color: inherit;\n --gr-tree-drag-handle-opacity: 0.55;\n --gr-tree-drag-handle-hover-bg: color-mix(in srgb, var(--gr-muted) 22%, transparent);\n --gr-tree-drag-handle-hover-color: var(--gr-tree-drag-handle-color);\n --gr-tree-drag-handle-hover-opacity: 0.9;\n --gr-tree-drag-handle-disabled-opacity: 0.25;\n --gr-tree-toggle-size: 24px;\n --gr-tree-toggle-mr: 0;\n --gr-tree-toggle-radius: 6px;\n --gr-tree-toggle-color: inherit;\n --gr-tree-toggle-hover-bg: color-mix(in srgb, var(--gr-muted) 25%, transparent);\n --gr-tree-toggle-hover-color: var(--gr-tree-toggle-color);\n --gr-tree-icon-size: 16px;\n --gr-tree-content-gap: 8px;\n --gr-tree-branch-line-default-color: var(--gr-tree-row-current-bg);\n --gr-tree-branch-line-width: 2px;\n /* Шаг отступа уровня: переключатель, отступ вложенного списка и толщина\n направляющей — линия обязана попадать между ними. */\n --gr-tree-indent-step: calc(12px + var(--gr-tree-children-pl) + var(--gr-tree-branch-line-width));\n --gr-tree-row-current-color: var(--gr-tree-row-color);\n --gr-tree-branch-elbow-width: 8px;\n --gr-tree-branch-line-offset: 12px;\n --gr-tree-checkbox-size: 16px;\n --gr-tree-checkbox-radius: 4px;\n --gr-tree-checkbox-brd: var(--gr-brd);\n --gr-tree-checkbox-bg: transparent;\n --gr-tree-checkbox-checked-bg: var(--gr-primary);\n --gr-tree-checkbox-checked-fg: var(--gr-primary-fg);\n --gr-tree-checkbox-mr: 4px;\n display: flex;\n flex-direction: column;\n gap: var(--gr-tree-gap);\n}\n\n[data-gr-virtual]::before,\n[data-gr-virtual]::after {\n content: '';\n display: block;\n flex: none;\n}\n\n[data-gr-virtual]::before {\n height: var(--gr-virtual-before, 0px);\n}\n\n[data-gr-virtual]::after {\n height: var(--gr-virtual-after, 0px);\n}\n\n.gr-tree__row {\n position: relative;\n display: flex;\n align-items: center;\n min-height: var(--gr-tree-row-min-height);\n padding: var(--gr-tree-row-py) var(--gr-tree-row-pr) var(--gr-tree-row-py)\n calc(var(--gr-tree-row-px) + var(--gr-tree-row-indent, 0px));\n font-size: var(--gr-tree-font-size);\n cursor: default;\n user-select: none;\n outline: none;\n color: var(--gr-tree-row-color);\n isolation: isolate;\n}\n\n/* Поверхность строки — отдельный слой, вставленный слева на отступ уровня.\n Фон на самой коробке шёл от левого края дерева и накрывал направляющие\n предков: линия ветки исчезала под подсветкой ровно там, где она и нужна.\n Слой лежит ниже направляющих (они — следующие элементы строки), поэтому\n линия остаётся видна при любом наложении.\n\n `z-index: -1` уводит слой под содержимое строки. Без него позиционированный\n `::before` красится ПОВЕРХ потоковых подписи, шеврона и отметки — при\n полупрозрачном фоне это лишь лёгкое затенение, а при непрозрачном значении\n публичного токена содержимое исчезает целиком. Поднимать вместо этого\n содержимое пришлось бы у каждого элемента строки и у каждого нового.\n\n `isolation` на самой строке обязателен в паре: без своего контекста\n наложения отрицательный слой уезжает за фон ближайшего предка с заливкой, и\n подсветка пропадает на карточке. */\n.gr-tree__row::before {\n content: '';\n position: absolute;\n inset: 0 0 0 var(--gr-tree-row-indent, 0px);\n border-radius: var(--gr-tree-row-radius);\n pointer-events: none;\n z-index: -1;\n}\n\n.gr-tree__row:hover::before {\n background: var(--gr-tree-row-hover-bg);\n}\n\n/* Направляющая тянется в зазор между строками: иначе линия ветки распалась бы\n на штрихи по числу строк. */\n/* Колено: горизонтальная черта от направляющей к строке. Цвет берётся\n `inherit`, потому что сама направляющая красится инлайновой переменной —\n повторять её резолв в псевдоэлементе значило бы завести второй источник. */\n.gr-tree__branch-guide--elbow::after {\n content: '';\n position: absolute;\n left: 0;\n top: 50%;\n width: var(--gr-tree-branch-elbow-width);\n height: var(--gr-tree-branch-line-width);\n background-color: inherit;\n transform: translateY(-50%);\n}\n\n.gr-tree__branch-guide--last {\n bottom: 50%;\n}\n\n.gr-tree__branch-guide {\n position: absolute;\n top: calc(var(--gr-tree-gap) / -2);\n bottom: calc(var(--gr-tree-gap) / -2);\n width: var(--gr-tree-branch-line-width);\n background: var(--gr-tree-branch-line-color, var(--gr-tree-branch-line-default-color));\n pointer-events: none;\n}\n\n.gr-tree__checkbox {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: var(--gr-tree-checkbox-size);\n height: var(--gr-tree-checkbox-size);\n margin-right: var(--gr-tree-checkbox-mr);\n border: 1px solid var(--gr-tree-checkbox-brd);\n border-radius: var(--gr-tree-checkbox-radius);\n background: var(--gr-tree-checkbox-bg);\n color: var(--gr-tree-checkbox-checked-fg);\n cursor: pointer;\n}\n\n.gr-tree__checkbox--checked,\n.gr-tree__checkbox--half {\n border-color: var(--gr-tree-checkbox-checked-bg);\n background: var(--gr-tree-checkbox-checked-bg);\n}\n\n.gr-tree__checkbox-mark {\n width: calc(var(--gr-tree-checkbox-size) - 4px);\n height: calc(var(--gr-tree-checkbox-size) - 4px);\n}\n\n[data-gr-tree-node] {\n outline: none;\n}\n\n/* Кольцо фокуса — на той же поверхности, что подсветка: иначе строка читалась бы\n двумя разными прямоугольниками. `outline` для этого не годится — он рисуется по\n границе коробки, а не по инсету. */\n[data-gr-tree-node]:focus-visible > .gr-tree__row::before {\n box-shadow: inset 0 0 0 2px var(--gr-primary);\n}\n\n.gr-tree__row--current {\n color: var(--gr-tree-row-current-color);\n}\n\n.gr-tree__row--current::before {\n background: var(--gr-tree-row-current-bg);\n}\n\n.gr-tree__row--current:hover::before {\n background: var(--gr-tree-row-current-hover-bg);\n}\n\n.gr-tree__row--matched .gr-tree__label {\n font-weight: 600;\n}\n\n/* Ветка набирается плотнее листа: без этого «Операции» и «Эскалации» выглядят\n одним и тем же, и различает их только шеврон, которого у листа нет. */\n.gr-tree__row:not(.gr-tree__row--leaf) .gr-tree__label {\n font-weight: 600;\n}\n\n.gr-tree__drag-handle {\n width: var(--gr-tree-drag-handle-size);\n height: var(--gr-tree-drag-handle-size);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n margin-right: var(--gr-tree-drag-handle-mr);\n border-radius: var(--gr-tree-drag-handle-radius);\n color: var(--gr-tree-drag-handle-color);\n cursor: grab;\n /* Без этого вертикальный свайп по ручке уходит в прокрутку страницы,\n браузер отзывает указатель, и пальцем узел неперетаскиваем. */\n touch-action: none;\n visibility: hidden;\n pointer-events: none;\n opacity: 0;\n}\n\n/* Где наведения не бывает, ручка «по наведению» недостижима — то есть\n перетаскивания нет вовсе. Медиазапрос, а не `matchMedia`: ответ нужен и на\n сервере, а спрашивать среду в первом рендере нельзя. */\n@media (hover: none) {\n .gr-tree--drag-handle-auto .gr-tree__drag-handle {\n visibility: visible;\n pointer-events: auto;\n opacity: var(--gr-tree-drag-handle-opacity);\n }\n}\n\n.gr-tree__drag-handle--visible {\n visibility: visible;\n pointer-events: auto;\n opacity: var(--gr-tree-drag-handle-opacity);\n}\n\n.gr-tree__drag-handle:hover {\n background: var(--gr-tree-drag-handle-hover-bg);\n color: var(--gr-tree-drag-handle-hover-color);\n opacity: var(--gr-tree-drag-handle-hover-opacity);\n}\n\n.gr-tree__drag-handle:active {\n cursor: grabbing;\n}\n\n.gr-tree__drag-handle--disabled {\n cursor: default;\n opacity: var(--gr-tree-drag-handle-disabled-opacity);\n}\n\n.gr-tree__drag-icon {\n width: var(--gr-tree-icon-size);\n height: var(--gr-tree-icon-size);\n}\n\n.gr-tree__toggle {\n width: var(--gr-tree-toggle-size);\n height: var(--gr-tree-toggle-size);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n margin-right: var(--gr-tree-toggle-mr);\n border-radius: var(--gr-tree-toggle-radius);\n color: var(--gr-tree-toggle-color);\n}\n\n.gr-tree__toggle:hover {\n background: var(--gr-tree-toggle-hover-bg);\n color: var(--gr-tree-toggle-hover-color);\n}\n\n.gr-tree__toggle-icon {\n width: var(--gr-tree-icon-size);\n height: var(--gr-tree-icon-size);\n transition: transform var(--gr-duration-fast) var(--gr-ease-out);\n}\n\n.gr-tree__toggle-icon--expanded {\n transform: rotate(90deg);\n}\n\n.gr-tree__toggle-spacer {\n width: var(--gr-tree-toggle-size);\n height: var(--gr-tree-toggle-size);\n margin-right: var(--gr-tree-toggle-mr);\n display: inline-block;\n}\n\n.gr-tree__content {\n min-width: 0;\n display: flex;\n align-items: center;\n gap: var(--gr-tree-content-gap);\n}\n\n.gr-tree__label {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.gr-tree__row--drop-inner {\n outline: 2px solid color-mix(in srgb, var(--gr-primary) 40%, transparent);\n}\n\n.gr-tree__row--drop-prev::before,\n.gr-tree__row--drop-next::after {\n content: '';\n position: absolute;\n left: 8px;\n right: 8px;\n height: 2px;\n background: color-mix(in srgb, var(--gr-primary) 55%, transparent);\n}\n\n.gr-tree__row--drop-prev::before {\n top: 2px;\n}\n\n.gr-tree__row--drop-next::after {\n bottom: 2px;\n}\n</style>\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import { t as GrTree_default } from "./chunks/GrTree-CkHzgYg1.js";
1
+ import { n as grTreeViewVars, t as GrTree_default } from "./chunks/GrTree-DnDGW0xO.js";
2
2
  import { n as grTreeSafelist, t as grTreeConfig } from "../../chunks/config-CDat1wXf.js";
3
- export { GrTree_default as GrTree, GrTree_default as default, grTreeConfig, grTreeSafelist };
3
+ export { GrTree_default as GrTree, GrTree_default as default, grTreeConfig, grTreeSafelist, grTreeViewVars };
@@ -1 +1 @@
1
- .gr-tree[data-v-0ff88d29]{--gr-tree-gap:2px;--gr-tree-children-pl:10px;--gr-tree-row-min-height:28px;--gr-tree-row-radius:8px;--gr-tree-row-px:8px;--gr-tree-row-py:8px;--gr-tree-row-pr:var(--gr-tree-row-px);--gr-tree-font-size:inherit;--gr-tree-row-color:var(--gr-fg);--gr-tree-row-hover-bg:color-mix(in srgb, var(--gr-primary) 10%, transparent);--gr-tree-row-current-bg:color-mix(in srgb, var(--gr-primary) 5%, transparent);--gr-tree-row-current-hover-bg:color-mix(in srgb, var(--gr-primary) 16%, transparent);--gr-tree-drag-handle-size:24px;--gr-tree-drag-handle-mr:0;--gr-tree-drag-handle-radius:6px;--gr-tree-drag-handle-color:inherit;--gr-tree-drag-handle-opacity:.55;--gr-tree-drag-handle-hover-bg:color-mix(in srgb, var(--gr-muted) 22%, transparent);--gr-tree-drag-handle-hover-color:var(--gr-tree-drag-handle-color);--gr-tree-drag-handle-hover-opacity:.9;--gr-tree-drag-handle-disabled-opacity:.25;--gr-tree-toggle-size:24px;--gr-tree-toggle-mr:0;--gr-tree-toggle-radius:6px;--gr-tree-toggle-color:inherit;--gr-tree-toggle-hover-bg:color-mix(in srgb, var(--gr-muted) 25%, transparent);--gr-tree-toggle-hover-color:var(--gr-tree-toggle-color);--gr-tree-icon-size:16px;--gr-tree-content-gap:8px;--gr-tree-branch-line-default-color:var(--gr-tree-row-current-bg);--gr-tree-branch-line-width:2px;--gr-tree-indent-step:calc(24px + var(--gr-tree-children-pl) + var(--gr-tree-branch-line-width));--gr-tree-branch-line-offset:24px;--gr-tree-checkbox-size:16px;--gr-tree-checkbox-radius:4px;--gr-tree-checkbox-brd:var(--gr-brd);--gr-tree-checkbox-bg:transparent;--gr-tree-checkbox-checked-bg:var(--gr-primary);--gr-tree-checkbox-checked-fg:var(--gr-primary-fg);--gr-tree-checkbox-mr:4px;gap:var(--gr-tree-gap);flex-direction:column;display:flex}[data-gr-virtual][data-v-0ff88d29]:before,[data-gr-virtual][data-v-0ff88d29]:after{content:"";flex:none;display:block}[data-gr-virtual][data-v-0ff88d29]:before{height:var(--gr-virtual-before,0px)}[data-gr-virtual][data-v-0ff88d29]:after{height:var(--gr-virtual-after,0px)}.gr-tree__row[data-v-0ff88d29]{min-height:var(--gr-tree-row-min-height);padding:var(--gr-tree-row-py) var(--gr-tree-row-pr) var(--gr-tree-row-py) calc(var(--gr-tree-row-px) + var(--gr-tree-row-indent,0px));font-size:var(--gr-tree-font-size);cursor:default;user-select:none;color:var(--gr-tree-row-color);isolation:isolate;outline:none;align-items:center;display:flex;position:relative}.gr-tree__row[data-v-0ff88d29]:before{content:"";inset:0 0 0 var(--gr-tree-row-indent,0px);border-radius:var(--gr-tree-row-radius);pointer-events:none;z-index:-1;position:absolute}.gr-tree__row[data-v-0ff88d29]:hover:before{background:var(--gr-tree-row-hover-bg)}.gr-tree__branch-guide[data-v-0ff88d29]{top:calc(var(--gr-tree-gap) / -2);bottom:calc(var(--gr-tree-gap) / -2);width:var(--gr-tree-branch-line-width);background:var(--gr-tree-branch-line-color,var(--gr-tree-branch-line-default-color));pointer-events:none;position:absolute}.gr-tree__checkbox[data-v-0ff88d29]{width:var(--gr-tree-checkbox-size);height:var(--gr-tree-checkbox-size);margin-right:var(--gr-tree-checkbox-mr);border:1px solid var(--gr-tree-checkbox-brd);border-radius:var(--gr-tree-checkbox-radius);background:var(--gr-tree-checkbox-bg);color:var(--gr-tree-checkbox-checked-fg);cursor:pointer;flex-shrink:0;justify-content:center;align-items:center;display:inline-flex}.gr-tree__checkbox--checked[data-v-0ff88d29],.gr-tree__checkbox--half[data-v-0ff88d29]{border-color:var(--gr-tree-checkbox-checked-bg);background:var(--gr-tree-checkbox-checked-bg)}.gr-tree__checkbox-mark[data-v-0ff88d29]{width:calc(var(--gr-tree-checkbox-size) - 4px);height:calc(var(--gr-tree-checkbox-size) - 4px)}[data-gr-tree-node][data-v-0ff88d29]{outline:none}[data-gr-tree-node]:focus-visible>.gr-tree__row[data-v-0ff88d29]:before{box-shadow:inset 0 0 0 2px var(--gr-primary)}.gr-tree__row--current[data-v-0ff88d29]:before{background:var(--gr-tree-row-current-bg)}.gr-tree__row--current[data-v-0ff88d29]:hover:before{background:var(--gr-tree-row-current-hover-bg)}.gr-tree__row--matched .gr-tree__label[data-v-0ff88d29]{font-weight:600}.gr-tree__drag-handle[data-v-0ff88d29]{width:var(--gr-tree-drag-handle-size);height:var(--gr-tree-drag-handle-size);margin-right:var(--gr-tree-drag-handle-mr);border-radius:var(--gr-tree-drag-handle-radius);color:var(--gr-tree-drag-handle-color);cursor:grab;touch-action:none;visibility:hidden;pointer-events:none;opacity:0;justify-content:center;align-items:center;display:inline-flex}@media (hover:none){.gr-tree--drag-handle-auto .gr-tree__drag-handle[data-v-0ff88d29]{visibility:visible;pointer-events:auto;opacity:var(--gr-tree-drag-handle-opacity)}}.gr-tree__drag-handle--visible[data-v-0ff88d29]{visibility:visible;pointer-events:auto;opacity:var(--gr-tree-drag-handle-opacity)}.gr-tree__drag-handle[data-v-0ff88d29]:hover{background:var(--gr-tree-drag-handle-hover-bg);color:var(--gr-tree-drag-handle-hover-color);opacity:var(--gr-tree-drag-handle-hover-opacity)}.gr-tree__drag-handle[data-v-0ff88d29]:active{cursor:grabbing}.gr-tree__drag-handle--disabled[data-v-0ff88d29]{cursor:default;opacity:var(--gr-tree-drag-handle-disabled-opacity)}.gr-tree__drag-icon[data-v-0ff88d29]{width:var(--gr-tree-icon-size);height:var(--gr-tree-icon-size)}.gr-tree__toggle[data-v-0ff88d29]{width:var(--gr-tree-toggle-size);height:var(--gr-tree-toggle-size);margin-right:var(--gr-tree-toggle-mr);border-radius:var(--gr-tree-toggle-radius);color:var(--gr-tree-toggle-color);justify-content:center;align-items:center;display:inline-flex}.gr-tree__toggle[data-v-0ff88d29]:hover{background:var(--gr-tree-toggle-hover-bg);color:var(--gr-tree-toggle-hover-color)}.gr-tree__toggle-icon[data-v-0ff88d29]{width:var(--gr-tree-icon-size);height:var(--gr-tree-icon-size);transition:transform var(--gr-duration-fast) var(--gr-ease-out)}.gr-tree__toggle-icon--expanded[data-v-0ff88d29]{transform:rotate(90deg)}.gr-tree__toggle-spacer[data-v-0ff88d29]{width:var(--gr-tree-toggle-size);height:var(--gr-tree-toggle-size);margin-right:var(--gr-tree-toggle-mr);display:inline-block}.gr-tree__content[data-v-0ff88d29]{align-items:center;gap:var(--gr-tree-content-gap);min-width:0;display:flex}.gr-tree__label[data-v-0ff88d29]{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.gr-tree__row--drop-inner[data-v-0ff88d29]{outline:2px solid color-mix(in srgb, var(--gr-primary) 40%, transparent)}.gr-tree__row--drop-prev[data-v-0ff88d29]:before,.gr-tree__row--drop-next[data-v-0ff88d29]:after{content:"";background:color-mix(in srgb, var(--gr-primary) 55%, transparent);height:2px;position:absolute;left:8px;right:8px}.gr-tree__row--drop-prev[data-v-0ff88d29]:before{top:2px}.gr-tree__row--drop-next[data-v-0ff88d29]:after{bottom:2px}
1
+ .gr-tree[data-v-05278949]{--gr-tree-gap:2px;--gr-tree-children-pl:10px;--gr-tree-row-min-height:28px;--gr-tree-row-radius:8px;--gr-tree-row-px:8px;--gr-tree-row-py:8px;--gr-tree-row-pr:var(--gr-tree-row-px);--gr-tree-font-size:inherit;--gr-tree-row-color:var(--gr-fg);--gr-tree-row-hover-bg:color-mix(in srgb, var(--gr-primary) 10%, transparent);--gr-tree-row-current-bg:color-mix(in srgb, var(--gr-primary) 14%, transparent);--gr-tree-row-current-hover-bg:color-mix(in srgb, var(--gr-primary) 16%, transparent);--gr-tree-drag-handle-size:24px;--gr-tree-drag-handle-mr:0;--gr-tree-drag-handle-radius:6px;--gr-tree-drag-handle-color:inherit;--gr-tree-drag-handle-opacity:.55;--gr-tree-drag-handle-hover-bg:color-mix(in srgb, var(--gr-muted) 22%, transparent);--gr-tree-drag-handle-hover-color:var(--gr-tree-drag-handle-color);--gr-tree-drag-handle-hover-opacity:.9;--gr-tree-drag-handle-disabled-opacity:.25;--gr-tree-toggle-size:24px;--gr-tree-toggle-mr:0;--gr-tree-toggle-radius:6px;--gr-tree-toggle-color:inherit;--gr-tree-toggle-hover-bg:color-mix(in srgb, var(--gr-muted) 25%, transparent);--gr-tree-toggle-hover-color:var(--gr-tree-toggle-color);--gr-tree-icon-size:16px;--gr-tree-content-gap:8px;--gr-tree-branch-line-default-color:var(--gr-tree-row-current-bg);--gr-tree-branch-line-width:2px;--gr-tree-indent-step:calc(12px + var(--gr-tree-children-pl) + var(--gr-tree-branch-line-width));--gr-tree-row-current-color:var(--gr-tree-row-color);--gr-tree-branch-elbow-width:8px;--gr-tree-branch-line-offset:12px;--gr-tree-checkbox-size:16px;--gr-tree-checkbox-radius:4px;--gr-tree-checkbox-brd:var(--gr-brd);--gr-tree-checkbox-bg:transparent;--gr-tree-checkbox-checked-bg:var(--gr-primary);--gr-tree-checkbox-checked-fg:var(--gr-primary-fg);--gr-tree-checkbox-mr:4px;gap:var(--gr-tree-gap);flex-direction:column;display:flex}[data-gr-virtual][data-v-05278949]:before,[data-gr-virtual][data-v-05278949]:after{content:"";flex:none;display:block}[data-gr-virtual][data-v-05278949]:before{height:var(--gr-virtual-before,0px)}[data-gr-virtual][data-v-05278949]:after{height:var(--gr-virtual-after,0px)}.gr-tree__row[data-v-05278949]{min-height:var(--gr-tree-row-min-height);padding:var(--gr-tree-row-py) var(--gr-tree-row-pr) var(--gr-tree-row-py) calc(var(--gr-tree-row-px) + var(--gr-tree-row-indent,0px));font-size:var(--gr-tree-font-size);cursor:default;user-select:none;color:var(--gr-tree-row-color);isolation:isolate;outline:none;align-items:center;display:flex;position:relative}.gr-tree__row[data-v-05278949]:before{content:"";inset:0 0 0 var(--gr-tree-row-indent,0px);border-radius:var(--gr-tree-row-radius);pointer-events:none;z-index:-1;position:absolute}.gr-tree__row[data-v-05278949]:hover:before{background:var(--gr-tree-row-hover-bg)}.gr-tree__branch-guide--elbow[data-v-05278949]:after{content:"";width:var(--gr-tree-branch-elbow-width);height:var(--gr-tree-branch-line-width);background-color:inherit;position:absolute;top:50%;left:0;transform:translateY(-50%)}.gr-tree__branch-guide--last[data-v-05278949]{bottom:50%}.gr-tree__branch-guide[data-v-05278949]{top:calc(var(--gr-tree-gap) / -2);bottom:calc(var(--gr-tree-gap) / -2);width:var(--gr-tree-branch-line-width);background:var(--gr-tree-branch-line-color,var(--gr-tree-branch-line-default-color));pointer-events:none;position:absolute}.gr-tree__checkbox[data-v-05278949]{width:var(--gr-tree-checkbox-size);height:var(--gr-tree-checkbox-size);margin-right:var(--gr-tree-checkbox-mr);border:1px solid var(--gr-tree-checkbox-brd);border-radius:var(--gr-tree-checkbox-radius);background:var(--gr-tree-checkbox-bg);color:var(--gr-tree-checkbox-checked-fg);cursor:pointer;flex-shrink:0;justify-content:center;align-items:center;display:inline-flex}.gr-tree__checkbox--checked[data-v-05278949],.gr-tree__checkbox--half[data-v-05278949]{border-color:var(--gr-tree-checkbox-checked-bg);background:var(--gr-tree-checkbox-checked-bg)}.gr-tree__checkbox-mark[data-v-05278949]{width:calc(var(--gr-tree-checkbox-size) - 4px);height:calc(var(--gr-tree-checkbox-size) - 4px)}[data-gr-tree-node][data-v-05278949]{outline:none}[data-gr-tree-node]:focus-visible>.gr-tree__row[data-v-05278949]:before{box-shadow:inset 0 0 0 2px var(--gr-primary)}.gr-tree__row--current[data-v-05278949]{color:var(--gr-tree-row-current-color)}.gr-tree__row--current[data-v-05278949]:before{background:var(--gr-tree-row-current-bg)}.gr-tree__row--current[data-v-05278949]:hover:before{background:var(--gr-tree-row-current-hover-bg)}.gr-tree__row--matched .gr-tree__label[data-v-05278949],.gr-tree__row:not(.gr-tree__row--leaf) .gr-tree__label[data-v-05278949]{font-weight:600}.gr-tree__drag-handle[data-v-05278949]{width:var(--gr-tree-drag-handle-size);height:var(--gr-tree-drag-handle-size);margin-right:var(--gr-tree-drag-handle-mr);border-radius:var(--gr-tree-drag-handle-radius);color:var(--gr-tree-drag-handle-color);cursor:grab;touch-action:none;visibility:hidden;pointer-events:none;opacity:0;justify-content:center;align-items:center;display:inline-flex}@media (hover:none){.gr-tree--drag-handle-auto .gr-tree__drag-handle[data-v-05278949]{visibility:visible;pointer-events:auto;opacity:var(--gr-tree-drag-handle-opacity)}}.gr-tree__drag-handle--visible[data-v-05278949]{visibility:visible;pointer-events:auto;opacity:var(--gr-tree-drag-handle-opacity)}.gr-tree__drag-handle[data-v-05278949]:hover{background:var(--gr-tree-drag-handle-hover-bg);color:var(--gr-tree-drag-handle-hover-color);opacity:var(--gr-tree-drag-handle-hover-opacity)}.gr-tree__drag-handle[data-v-05278949]:active{cursor:grabbing}.gr-tree__drag-handle--disabled[data-v-05278949]{cursor:default;opacity:var(--gr-tree-drag-handle-disabled-opacity)}.gr-tree__drag-icon[data-v-05278949]{width:var(--gr-tree-icon-size);height:var(--gr-tree-icon-size)}.gr-tree__toggle[data-v-05278949]{width:var(--gr-tree-toggle-size);height:var(--gr-tree-toggle-size);margin-right:var(--gr-tree-toggle-mr);border-radius:var(--gr-tree-toggle-radius);color:var(--gr-tree-toggle-color);justify-content:center;align-items:center;display:inline-flex}.gr-tree__toggle[data-v-05278949]:hover{background:var(--gr-tree-toggle-hover-bg);color:var(--gr-tree-toggle-hover-color)}.gr-tree__toggle-icon[data-v-05278949]{width:var(--gr-tree-icon-size);height:var(--gr-tree-icon-size);transition:transform var(--gr-duration-fast) var(--gr-ease-out)}.gr-tree__toggle-icon--expanded[data-v-05278949]{transform:rotate(90deg)}.gr-tree__toggle-spacer[data-v-05278949]{width:var(--gr-tree-toggle-size);height:var(--gr-tree-toggle-size);margin-right:var(--gr-tree-toggle-mr);display:inline-block}.gr-tree__content[data-v-05278949]{align-items:center;gap:var(--gr-tree-content-gap);min-width:0;display:flex}.gr-tree__label[data-v-05278949]{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.gr-tree__row--drop-inner[data-v-05278949]{outline:2px solid color-mix(in srgb, var(--gr-primary) 40%, transparent)}.gr-tree__row--drop-prev[data-v-05278949]:before,.gr-tree__row--drop-next[data-v-05278949]:after{content:"";background:color-mix(in srgb, var(--gr-primary) 55%, transparent);height:2px;position:absolute;left:8px;right:8px}.gr-tree__row--drop-prev[data-v-05278949]:before{top:2px}.gr-tree__row--drop-next[data-v-05278949]:after{bottom:2px}
@@ -0,0 +1,147 @@
1
+ import { n as createGrTreeDataAdapter } from "../../../chunks/useTree-BebEiBcL.js";
2
+ import { t as GrTree_default } from "../../GrTree/chunks/GrTree-DnDGW0xO.js";
3
+ import { a as treeSectionsHeadClass, i as treeSectionsGroupClass, o as treeSectionsRootClass, r as treeSectionsCountClass } from "../../../chunks/config-ChnYtO4o.js";
4
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createSlots, createTextVNode, createVNode, defineComponent, mergeProps, normalizeClass, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, toDisplayString, unref, watchEffect, withCtx } from "vue";
5
+ //#endregion
6
+ //#region src/components/GrTreeSections/GrTreeSections.vue
7
+ var GrTreeSections_default = /* @__PURE__ */ defineComponent({
8
+ __name: "GrTreeSections",
9
+ props: {
10
+ data: {},
11
+ nodeKey: { default: "id" },
12
+ props: { default: void 0 },
13
+ size: { default: void 0 },
14
+ headingLevel: { default: 3 },
15
+ showCount: {
16
+ type: Boolean,
17
+ default: false
18
+ },
19
+ showCheckbox: {
20
+ type: Boolean,
21
+ default: false
22
+ },
23
+ checkStrictly: {
24
+ type: Boolean,
25
+ default: false
26
+ },
27
+ branchLine: {
28
+ type: [Boolean, String],
29
+ default: void 0
30
+ },
31
+ indent: { default: 0 },
32
+ defaultExpandedKeys: { default: () => [] },
33
+ currentKey: { default: void 0 },
34
+ checkedKeys: { default: void 0 }
35
+ },
36
+ emits: [
37
+ "update:currentKey",
38
+ "update:checkedKeys",
39
+ "nodeClick"
40
+ ],
41
+ setup(__props, { emit: __emit }) {
42
+ const props = __props;
43
+ const emit = __emit;
44
+ const adapter = createGrTreeDataAdapter(props);
45
+ /** Ключ группы: у корня он либо объявлен данными, либо выводится по позиции. */
46
+ function groupKey(data, index) {
47
+ return adapter.getNodeKey(data, index, void 0);
48
+ }
49
+ /**
50
+ * Группы — корни исходных данных. Собственные данные группы — её дети: сам
51
+ * корень строкой уже не рендерится, он стал заголовком.
52
+ */
53
+ const groups = computed(() => (Array.isArray(props.data) ? props.data : []).map((data, index) => {
54
+ const children = adapter.getChildren(data) ?? [];
55
+ return {
56
+ key: groupKey(data, index),
57
+ label: adapter.getLabel(data),
58
+ data,
59
+ children,
60
+ count: children.length
61
+ };
62
+ }));
63
+ const localCurrent = ref(props.currentKey);
64
+ watchEffect(() => {
65
+ localCurrent.value = props.currentKey;
66
+ });
67
+ function onCurrentChange(key) {
68
+ localCurrent.value = key;
69
+ emit("update:currentKey", key);
70
+ }
71
+ /**
72
+ * Отметки собираются объединением: группы — независимые деревья, и наследование
73
+ * внутри каждой считается своё. Свести их в один список можно без потерь именно
74
+ * потому, что общего родителя у групп нет.
75
+ */
76
+ function onCheckedChange(groupKey, keys) {
77
+ const own = new Set(groups.value.find((group) => group.key === groupKey)?.children.flatMap(collectKeys) ?? []);
78
+ const rest = (props.checkedKeys ?? []).filter((key) => !own.has(key));
79
+ emit("update:checkedKeys", [...rest, ...keys]);
80
+ }
81
+ function collectKeys(data) {
82
+ const children = adapter.getChildren(data) ?? [];
83
+ return [adapter.getExplicitNodeKey(data), ...children.flatMap(collectKeys)].filter((key) => key !== void 0);
84
+ }
85
+ if (process.env.NODE_ENV !== "production") watchEffect(() => {
86
+ if (!Array.isArray(props.data)) console.warn(`[granularity] GrTreeSections: обязательный проп \`data\` должен быть массивом — получено ${String(props.data)}.`);
87
+ });
88
+ return (_ctx, _cache) => {
89
+ return openBlock(), createElementBlock("div", {
90
+ "data-gr-tree-sections": "",
91
+ class: normalizeClass(unref(treeSectionsRootClass))
92
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(groups.value, (group) => {
93
+ return openBlock(), createElementBlock("section", {
94
+ key: String(group.key),
95
+ "data-gr-tree-sections-group": "",
96
+ class: normalizeClass(unref(treeSectionsGroupClass))
97
+ }, [(openBlock(), createBlock(resolveDynamicComponent(`h${__props.headingLevel}`), { class: normalizeClass(unref(treeSectionsHeadClass)) }, {
98
+ default: withCtx(() => [renderSlot(_ctx.$slots, "heading", {
99
+ data: group.data,
100
+ label: group.label,
101
+ count: group.count
102
+ }, () => [createTextVNode(toDisplayString(group.label), 1)]), __props.showCount ? (openBlock(), createElementBlock("span", {
103
+ key: 0,
104
+ class: normalizeClass(unref(treeSectionsCountClass))
105
+ }, toDisplayString(group.count), 3)) : createCommentVNode("", true)]),
106
+ _: 2
107
+ }, 1032, ["class"])), createVNode(GrTree_default, {
108
+ data: group.children,
109
+ "node-key": __props.nodeKey,
110
+ props: props.props,
111
+ size: __props.size,
112
+ "show-checkbox": __props.showCheckbox,
113
+ "check-strictly": __props.checkStrictly,
114
+ "branch-line": __props.branchLine,
115
+ indent: __props.indent,
116
+ "default-expanded-keys": __props.defaultExpandedKeys,
117
+ "current-key": localCurrent.value,
118
+ "checked-keys": __props.checkedKeys,
119
+ "aria-label": group.label,
120
+ "onUpdate:currentKey": onCurrentChange,
121
+ "onUpdate:checkedKeys": (keys) => onCheckedChange(group.key, keys),
122
+ onNodeClick: _cache[0] || (_cache[0] = (data, node) => emit("nodeClick", data, node))
123
+ }, createSlots({ _: 2 }, [_ctx.$slots.default ? {
124
+ name: "default",
125
+ fn: withCtx((slotProps) => [renderSlot(_ctx.$slots, "default", mergeProps({ ref_for: true }, slotProps))]),
126
+ key: "0"
127
+ } : void 0]), 1032, [
128
+ "data",
129
+ "node-key",
130
+ "props",
131
+ "size",
132
+ "show-checkbox",
133
+ "check-strictly",
134
+ "branch-line",
135
+ "indent",
136
+ "default-expanded-keys",
137
+ "current-key",
138
+ "checked-keys",
139
+ "aria-label",
140
+ "onUpdate:checkedKeys"
141
+ ])], 2);
142
+ }), 128))], 2);
143
+ };
144
+ }
145
+ });
146
+ //#endregion
147
+ export { GrTreeSections_default as t };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GrTreeSections-D2PQ87mw.js","names":["$slots"],"sources":["../../../../src/components/GrTreeSections/GrTreeSections.vue","../../../../src/components/GrTreeSections/GrTreeSections.vue"],"sourcesContent":["<script setup lang=\"ts\" generic=\"T extends Record<string, any> = any\">\nimport { computed, ref, watchEffect } from 'vue'\n\nimport GrTree from '../GrTree/GrTree.vue'\nimport type { GrTreeKey, GrTreeNode } from '../GrTree/grTreeTypes'\nimport type { GrTreeBranchLine, GrTreeDataProps, GrTreePropsMap } from '../GrTree/grTreeProps'\nimport type { GrComponentSize } from '../shared/sizes'\nimport { createGrTreeDataAdapter } from '../../composables/internal/treeAdapter'\n\nimport {\n treeSectionsCountClass,\n treeSectionsGroupClass,\n treeSectionsHeadClass,\n treeSectionsRootClass,\n} from './grTreeSectionsStyles'\n\n/**\n * GrTreeSections — дерево, у которого верхний уровень стал рубрикой.\n *\n * Внутри это не одно дерево с заголовками между строк, а **несколько деревьев**:\n * `role=\"tree\"` требует, чтобы его детьми были `treeitem`, и заголовок посреди\n * них либо ломал бы паттерн, либо врал диктору, оставаясь строкой. Заголовки\n * между отдельными деревьями законны, и каждая группа объявляется сама собой.\n *\n * Отсюда же граница: клавиатурное кольцо у каждой группы своё, `Tab` переходит\n * между ними. Это верно по существу — группы независимы.\n */\nexport interface GrTreeSectionsProps<TData extends object = any> {\n /** Данные обычного дерева. Корни становятся заголовками, их дети — деревьями. */\n data: TData[]\n nodeKey?: GrTreeDataProps<TData>['nodeKey']\n props?: GrTreePropsMap\n size?: GrComponentSize\n /** Уровень заголовка группы под структуру страницы. */\n headingLevel?: 2 | 3 | 4 | 5 | 6\n /** Показывать число узлов первого уровня в группе. */\n showCount?: boolean\n showCheckbox?: boolean\n checkStrictly?: boolean\n branchLine?: boolean | GrTreeBranchLine\n indent?: number\n defaultExpandedKeys?: GrTreeKey[]\n currentKey?: GrTreeKey\n checkedKeys?: GrTreeKey[]\n}\n\nexport interface GrTreeSectionsEmits {\n (e: 'update:currentKey', key: GrTreeKey | undefined): void\n (e: 'update:checkedKeys', keys: GrTreeKey[]): void\n (e: 'nodeClick', data: any, node: GrTreeNode<any>): void\n}\n\nconst props = withDefaults(defineProps<GrTreeSectionsProps<T>>(), {\n nodeKey: 'id' as never,\n props: undefined,\n size: undefined,\n headingLevel: 3,\n showCount: false,\n showCheckbox: false,\n checkStrictly: false,\n branchLine: undefined,\n indent: 0,\n defaultExpandedKeys: () => [],\n currentKey: undefined,\n checkedKeys: undefined,\n})\n\nconst emit = defineEmits<GrTreeSectionsEmits>()\n\ndefineSlots<{\n /** Заголовок группы целиком — вместо подписи корневого узла. */\n heading?: (props: { data: T, label: string, count: number }) => unknown\n /** Строка внутри группы, как у `GrTree`. */\n default?: (props: { node: GrTreeNode<T>, data: T }) => unknown\n}>()\n\nconst adapter = createGrTreeDataAdapter<T>(props)\n\n/** Ключ группы: у корня он либо объявлен данными, либо выводится по позиции. */\nfunction groupKey(data: T, index: number): GrTreeKey {\n return adapter.getNodeKey(data, index, undefined)\n}\n\n/**\n * Группы — корни исходных данных. Собственные данные группы — её дети: сам\n * корень строкой уже не рендерится, он стал заголовком.\n */\nconst groups = computed(() => (Array.isArray(props.data) ? props.data : []).map((data, index) => {\n const children = (adapter.getChildren(data) ?? []) as T[]\n\n return {\n key: groupKey(data, index),\n label: adapter.getLabel(data),\n data,\n children,\n count: children.length,\n }\n}))\n\nconst localCurrent = ref<GrTreeKey | undefined>(props.currentKey)\n\nwatchEffect(() => {\n localCurrent.value = props.currentKey\n})\n\nfunction onCurrentChange(key: GrTreeKey | undefined): void {\n // Ключи уникальны на всё дерево, поэтому подсветится ровно одна группа:\n // остальные получат чужой ключ и просто не найдут его у себя.\n localCurrent.value = key\n emit('update:currentKey', key)\n}\n\n/**\n * Отметки собираются объединением: группы — независимые деревья, и наследование\n * внутри каждой считается своё. Свести их в один список можно без потерь именно\n * потому, что общего родителя у групп нет.\n */\nfunction onCheckedChange(groupKey: GrTreeKey, keys: GrTreeKey[]): void {\n const own = new Set(groups.value.find(group => group.key === groupKey)?.children.flatMap(collectKeys) ?? [])\n const rest = (props.checkedKeys ?? []).filter(key => !own.has(key))\n\n emit('update:checkedKeys', [...rest, ...keys])\n}\n\nfunction collectKeys(data: T): GrTreeKey[] {\n const children = (adapter.getChildren(data) ?? []) as T[]\n\n return [adapter.getExplicitNodeKey(data), ...children.flatMap(collectKeys)]\n .filter((key): key is GrTreeKey => key !== undefined)\n}\n\nif (__GR_DEV__) {\n watchEffect(() => {\n if (!Array.isArray(props.data)) {\n console.warn(\n `[granularity] GrTreeSections: обязательный проп \\`data\\` должен быть массивом — получено ${String(props.data)}.`,\n )\n }\n })\n}\n</script>\n\n<template>\n <div data-gr-tree-sections :class=\"treeSectionsRootClass\">\n <section\n v-for=\"group in groups\"\n :key=\"String(group.key)\"\n data-gr-tree-sections-group\n :class=\"treeSectionsGroupClass\"\n >\n <component :is=\"`h${headingLevel}`\" :class=\"treeSectionsHeadClass\">\n <slot name=\"heading\" :data=\"group.data\" :label=\"group.label\" :count=\"group.count\">\n {{ group.label }}\n </slot>\n <span v-if=\"showCount\" :class=\"treeSectionsCountClass\">{{ group.count }}</span>\n </component>\n\n <GrTree\n :data=\"group.children\"\n :node-key=\"nodeKey\"\n :props=\"props.props\"\n :size=\"size\"\n :show-checkbox=\"showCheckbox\"\n :check-strictly=\"checkStrictly\"\n :branch-line=\"branchLine\"\n :indent=\"indent\"\n :default-expanded-keys=\"defaultExpandedKeys\"\n :current-key=\"localCurrent\"\n :checked-keys=\"checkedKeys\"\n :aria-label=\"group.label\"\n @update:current-key=\"onCurrentChange\"\n @update:checked-keys=\"keys => onCheckedChange(group.key, keys)\"\n @node-click=\"(data, node) => emit('nodeClick', data, node)\"\n >\n <template v-if=\"$slots.default\" #default=\"slotProps\">\n <slot v-bind=\"slotProps\" />\n </template>\n </GrTree>\n </section>\n </div>\n</template>\n","<script setup lang=\"ts\" generic=\"T extends Record<string, any> = any\">\nimport { computed, ref, watchEffect } from 'vue'\n\nimport GrTree from '../GrTree/GrTree.vue'\nimport type { GrTreeKey, GrTreeNode } from '../GrTree/grTreeTypes'\nimport type { GrTreeBranchLine, GrTreeDataProps, GrTreePropsMap } from '../GrTree/grTreeProps'\nimport type { GrComponentSize } from '../shared/sizes'\nimport { createGrTreeDataAdapter } from '../../composables/internal/treeAdapter'\n\nimport {\n treeSectionsCountClass,\n treeSectionsGroupClass,\n treeSectionsHeadClass,\n treeSectionsRootClass,\n} from './grTreeSectionsStyles'\n\n/**\n * GrTreeSections — дерево, у которого верхний уровень стал рубрикой.\n *\n * Внутри это не одно дерево с заголовками между строк, а **несколько деревьев**:\n * `role=\"tree\"` требует, чтобы его детьми были `treeitem`, и заголовок посреди\n * них либо ломал бы паттерн, либо врал диктору, оставаясь строкой. Заголовки\n * между отдельными деревьями законны, и каждая группа объявляется сама собой.\n *\n * Отсюда же граница: клавиатурное кольцо у каждой группы своё, `Tab` переходит\n * между ними. Это верно по существу — группы независимы.\n */\nexport interface GrTreeSectionsProps<TData extends object = any> {\n /** Данные обычного дерева. Корни становятся заголовками, их дети — деревьями. */\n data: TData[]\n nodeKey?: GrTreeDataProps<TData>['nodeKey']\n props?: GrTreePropsMap\n size?: GrComponentSize\n /** Уровень заголовка группы под структуру страницы. */\n headingLevel?: 2 | 3 | 4 | 5 | 6\n /** Показывать число узлов первого уровня в группе. */\n showCount?: boolean\n showCheckbox?: boolean\n checkStrictly?: boolean\n branchLine?: boolean | GrTreeBranchLine\n indent?: number\n defaultExpandedKeys?: GrTreeKey[]\n currentKey?: GrTreeKey\n checkedKeys?: GrTreeKey[]\n}\n\nexport interface GrTreeSectionsEmits {\n (e: 'update:currentKey', key: GrTreeKey | undefined): void\n (e: 'update:checkedKeys', keys: GrTreeKey[]): void\n (e: 'nodeClick', data: any, node: GrTreeNode<any>): void\n}\n\nconst props = withDefaults(defineProps<GrTreeSectionsProps<T>>(), {\n nodeKey: 'id' as never,\n props: undefined,\n size: undefined,\n headingLevel: 3,\n showCount: false,\n showCheckbox: false,\n checkStrictly: false,\n branchLine: undefined,\n indent: 0,\n defaultExpandedKeys: () => [],\n currentKey: undefined,\n checkedKeys: undefined,\n})\n\nconst emit = defineEmits<GrTreeSectionsEmits>()\n\ndefineSlots<{\n /** Заголовок группы целиком — вместо подписи корневого узла. */\n heading?: (props: { data: T, label: string, count: number }) => unknown\n /** Строка внутри группы, как у `GrTree`. */\n default?: (props: { node: GrTreeNode<T>, data: T }) => unknown\n}>()\n\nconst adapter = createGrTreeDataAdapter<T>(props)\n\n/** Ключ группы: у корня он либо объявлен данными, либо выводится по позиции. */\nfunction groupKey(data: T, index: number): GrTreeKey {\n return adapter.getNodeKey(data, index, undefined)\n}\n\n/**\n * Группы — корни исходных данных. Собственные данные группы — её дети: сам\n * корень строкой уже не рендерится, он стал заголовком.\n */\nconst groups = computed(() => (Array.isArray(props.data) ? props.data : []).map((data, index) => {\n const children = (adapter.getChildren(data) ?? []) as T[]\n\n return {\n key: groupKey(data, index),\n label: adapter.getLabel(data),\n data,\n children,\n count: children.length,\n }\n}))\n\nconst localCurrent = ref<GrTreeKey | undefined>(props.currentKey)\n\nwatchEffect(() => {\n localCurrent.value = props.currentKey\n})\n\nfunction onCurrentChange(key: GrTreeKey | undefined): void {\n // Ключи уникальны на всё дерево, поэтому подсветится ровно одна группа:\n // остальные получат чужой ключ и просто не найдут его у себя.\n localCurrent.value = key\n emit('update:currentKey', key)\n}\n\n/**\n * Отметки собираются объединением: группы — независимые деревья, и наследование\n * внутри каждой считается своё. Свести их в один список можно без потерь именно\n * потому, что общего родителя у групп нет.\n */\nfunction onCheckedChange(groupKey: GrTreeKey, keys: GrTreeKey[]): void {\n const own = new Set(groups.value.find(group => group.key === groupKey)?.children.flatMap(collectKeys) ?? [])\n const rest = (props.checkedKeys ?? []).filter(key => !own.has(key))\n\n emit('update:checkedKeys', [...rest, ...keys])\n}\n\nfunction collectKeys(data: T): GrTreeKey[] {\n const children = (adapter.getChildren(data) ?? []) as T[]\n\n return [adapter.getExplicitNodeKey(data), ...children.flatMap(collectKeys)]\n .filter((key): key is GrTreeKey => key !== undefined)\n}\n\nif (__GR_DEV__) {\n watchEffect(() => {\n if (!Array.isArray(props.data)) {\n console.warn(\n `[granularity] GrTreeSections: обязательный проп \\`data\\` должен быть массивом — получено ${String(props.data)}.`,\n )\n }\n })\n}\n</script>\n\n<template>\n <div data-gr-tree-sections :class=\"treeSectionsRootClass\">\n <section\n v-for=\"group in groups\"\n :key=\"String(group.key)\"\n data-gr-tree-sections-group\n :class=\"treeSectionsGroupClass\"\n >\n <component :is=\"`h${headingLevel}`\" :class=\"treeSectionsHeadClass\">\n <slot name=\"heading\" :data=\"group.data\" :label=\"group.label\" :count=\"group.count\">\n {{ group.label }}\n </slot>\n <span v-if=\"showCount\" :class=\"treeSectionsCountClass\">{{ group.count }}</span>\n </component>\n\n <GrTree\n :data=\"group.children\"\n :node-key=\"nodeKey\"\n :props=\"props.props\"\n :size=\"size\"\n :show-checkbox=\"showCheckbox\"\n :check-strictly=\"checkStrictly\"\n :branch-line=\"branchLine\"\n :indent=\"indent\"\n :default-expanded-keys=\"defaultExpandedKeys\"\n :current-key=\"localCurrent\"\n :checked-keys=\"checkedKeys\"\n :aria-label=\"group.label\"\n @update:current-key=\"onCurrentChange\"\n @update:checked-keys=\"keys => onCheckedChange(group.key, keys)\"\n @node-click=\"(data, node) => emit('nodeClick', data, node)\"\n >\n <template v-if=\"$slots.default\" #default=\"slotProps\">\n <slot v-bind=\"slotProps\" />\n </template>\n </GrTree>\n </section>\n </div>\n</template>\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { n as grTreeSectionsSafelist, t as grTreeSectionsConfig } from "../../chunks/config-ChnYtO4o.js";
2
+ import { t as GrTreeSections_default } from "./chunks/GrTreeSections-D2PQ87mw.js";
3
+ export { GrTreeSections_default as GrTreeSections, GrTreeSections_default as default, grTreeSectionsConfig, grTreeSectionsSafelist };
@@ -15,7 +15,7 @@ import { n as panelPopTransition } from "../../../chunks/overlayPanelSurface-BKe
15
15
  import { t as check_default } from "../../../chunks/check-BZI24Qs4.js";
16
16
  import { t as chevron_down_default } from "../../../chunks/chevron-down-CQS2OG_s.js";
17
17
  import { t as GrInput_default } from "../../GrInput/chunks/GrInput-TFeBm3gQ.js";
18
- import { t as GrTree_default } from "../../GrTree/chunks/GrTree-CkHzgYg1.js";
18
+ import { t as GrTree_default } from "../../GrTree/chunks/GrTree-DnDGW0xO.js";
19
19
  import { a as grTreeSelectStateClass, i as grTreeSelectPanelClass, o as paddingX, r as grTreeSelectClass, s as trailingZoneWidth } from "../../../chunks/config-BGCyyXiD.js";
20
20
  import { Fragment, Teleport, Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, mergeProps, nextTick, normalizeClass, normalizeStyle, openBlock, ref, renderList, renderSlot, toDisplayString, unref, useId, useSlots, vShow, watch, withCtx, withDirectives, withModifiers } from "vue";
21
21
  //#region src/components/GrTreeSelect/GrTreeSelect.vue?vue&type=script&setup=true&lang.ts