@feugene/granularity 0.44.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 (46) hide show
  1. package/README.md +3 -3
  2. package/dist/chunks/config-ChnYtO4o.js +28 -0
  3. package/dist/chunks/config-ChnYtO4o.js.map +1 -0
  4. package/dist/chunks/{generated-Hxu_sWPs.js → generated-DAKeOOqm.js} +17 -3
  5. package/dist/chunks/{generated-Hxu_sWPs.js.map → generated-DAKeOOqm.js.map} +1 -1
  6. package/dist/chunks/{granular-provider-CCNbQa5U.js → granular-provider-D_8_l-gM.js} +2 -0
  7. package/dist/chunks/granular-provider-D_8_l-gM.js.map +1 -0
  8. package/dist/chunks/useTree-BebEiBcL.js +525 -0
  9. package/dist/chunks/useTree-BebEiBcL.js.map +1 -0
  10. package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-CwCBMh4h.js → GrJsonViewer-CdlWMGnF.js} +1 -1
  11. package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-CwCBMh4h.js.map → GrJsonViewer-CdlWMGnF.js.map} +1 -1
  12. package/dist/components/GrJsonViewer/index.js +1 -1
  13. package/dist/components/GrTree/chunks/{GrTree-CkHzgYg1.js → GrTree-DnDGW0xO.js} +103 -540
  14. package/dist/components/GrTree/chunks/GrTree-DnDGW0xO.js.map +1 -0
  15. package/dist/components/GrTree/index.js +2 -2
  16. package/dist/components/GrTree/styles.css +1 -1
  17. package/dist/components/GrTreeSections/chunks/GrTreeSections-D2PQ87mw.js +147 -0
  18. package/dist/components/GrTreeSections/chunks/GrTreeSections-D2PQ87mw.js.map +1 -0
  19. package/dist/components/GrTreeSections/index.js +3 -0
  20. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DUsv3_mF.js → GrTreeSelect-DzheDCuZ.js} +1 -1
  21. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DUsv3_mF.js.map → GrTreeSelect-DzheDCuZ.js.map} +1 -1
  22. package/dist/components/GrTreeSelect/index.js +1 -1
  23. package/dist/composables/useTree.js +2 -0
  24. package/dist/granular-provider-node.js +1 -1
  25. package/dist/granular-provider.js +1 -1
  26. package/dist/index.js +7 -4
  27. package/dist/theme.js +1 -1
  28. package/dist/tokens.js +1 -1
  29. package/dist/types/components/GrTree/grTreeProps.d.ts +8 -1
  30. package/dist/types/components/GrTree/grTreeStyles.d.ts +12 -0
  31. package/dist/types/components/GrTree/index.d.ts +3 -2
  32. package/dist/types/components/GrTreeSections/GrTreeSections.vue.d.ts +71 -0
  33. package/dist/types/components/GrTreeSections/config.d.ts +1 -0
  34. package/dist/types/components/GrTreeSections/grTreeSectionsStyles.d.ts +8 -0
  35. package/dist/types/components/GrTreeSections/index.d.ts +8 -0
  36. package/dist/types/components/GrTreeSections/safelist.d.ts +1 -0
  37. package/dist/types/{components/GrTree/grTreeDataAdapter.d.ts → composables/internal/treeAdapter.d.ts} +3 -3
  38. package/dist/types/{components/GrTree/grTreeChecking.d.ts → composables/internal/treeChecking.d.ts} +1 -1
  39. package/dist/types/composables/useTree.d.ts +107 -0
  40. package/dist/types/granular-provider/shared.d.ts +1 -0
  41. package/dist/types/index.d.ts +3 -0
  42. package/dist/web-types.json +143 -3
  43. package/package.json +9 -1
  44. package/dist/chunks/granular-provider-CCNbQa5U.js.map +0 -1
  45. package/dist/components/GrTree/chunks/GrTree-CkHzgYg1.js.map +0 -1
  46. package/dist/types/components/GrTree/grTreeStore.d.ts +0 -71
@@ -12,70 +12,9 @@ import { t as minus_default } from "../../../chunks/minus-oxdbHF33.js";
12
12
  import { t as useTypeahead } from "../../../chunks/useTypeahead-mxPtPBf2.js";
13
13
  import { useDragSort } from "../../../composables/useDragSort.js";
14
14
  import { t as grip_vertical_default } from "../../../chunks/grip-vertical-lRha2S7q.js";
15
- import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, defineComponent, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, shallowRef, toDisplayString, toValue, unref, watch, withModifiers } from "vue";
16
- import '../styles.css';//#region src/components/GrTree/grTreeDataAdapter.ts
17
- var DEFAULT_CHILDREN_KEY = "children";
18
- var DEFAULT_LABEL_KEY = "label";
19
- var DEFAULT_IS_LEAF_KEY = "isLeaf";
20
- function isTreeKey(value) {
21
- return typeof value === "string" || typeof value === "number";
22
- }
23
- function resolveMapValue(map, key, fallback) {
24
- return map?.[key] ?? fallback;
25
- }
26
- function createGrTreeDataAdapter(options) {
27
- function hasNodeKey() {
28
- return options.nodeKey != null;
29
- }
30
- function getChildrenKey() {
31
- return resolveMapValue(options.props, "children", DEFAULT_CHILDREN_KEY);
32
- }
33
- function getLabelKey() {
34
- return resolveMapValue(options.props, "label", DEFAULT_LABEL_KEY);
35
- }
36
- function getLabel(data) {
37
- const value = data[getLabelKey()];
38
- return value == null ? "" : String(value);
39
- }
40
- function getIsLeaf(data) {
41
- const value = data[resolveMapValue(options.props, "isLeaf", DEFAULT_IS_LEAF_KEY)];
42
- return typeof value === "boolean" ? value : void 0;
43
- }
44
- function getChildren(data) {
45
- const value = data[getChildrenKey()];
46
- return Array.isArray(value) ? value : [];
47
- }
48
- function ensureChildren(data) {
49
- const key = getChildrenKey();
50
- const record = data;
51
- if (Array.isArray(record[key])) return record[key];
52
- record[key] = [];
53
- return record[key];
54
- }
55
- function getExplicitNodeKey(data) {
56
- if (options.nodeKey == null) return void 0;
57
- const value = data[options.nodeKey];
58
- return isTreeKey(value) ? value : void 0;
59
- }
60
- function getNodeKey(data, index, parentKey) {
61
- const explicitKey = getExplicitNodeKey(data);
62
- if (explicitKey != null) return explicitKey;
63
- return parentKey == null ? index : `${String(parentKey)}:${index}`;
64
- }
65
- return {
66
- hasNodeKey,
67
- getChildrenKey,
68
- getLabelKey,
69
- getLabel,
70
- getIsLeaf,
71
- getChildren,
72
- ensureChildren,
73
- getNodeKey,
74
- getExplicitNodeKey
75
- };
76
- }
77
- //#endregion
78
- //#region src/components/GrTree/grTreeInteractionContext.ts
15
+ import { n as createGrTreeDataAdapter, t as useTree } from "../../../chunks/useTree-BebEiBcL.js";
16
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, defineComponent, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, shallowRef, toDisplayString, unref, watch, withModifiers } from "vue";
17
+ import '../styles.css';//#region src/components/GrTree/grTreeInteractionContext.ts
79
18
  function createGrTreeInteractionContext(options, emitters) {
80
19
  const hoveredKey = ref(void 0);
81
20
  const draggingNode = shallowRef(null);
@@ -115,442 +54,12 @@ function createGrTreeInteractionContext(options, emitters) {
115
54
  };
116
55
  }
117
56
  //#endregion
118
- //#region src/components/GrTree/grTreeChecking.ts
119
- /**
120
- * Раскладывает отмеченные ключи по всему дереву: родитель отмечен, когда
121
- * отмечены все дети, и наполовину — когда часть.
122
- *
123
- * Считается от листьев вверх, поэтому `checkedKeys` снаружи может содержать
124
- * только листья (типовой формат ответа сервера) — родители посчитаются сами.
125
- * При `strict` дерево не связывает узлы вовсе: каждый отвечает сам за себя.
126
- */
127
- function resolveCheckStates(roots, checkedKeys, strict) {
128
- const states = /* @__PURE__ */ new Map();
129
- const walk = (node) => {
130
- if (strict || node.childNodes.length === 0) {
131
- const state = checkedKeys.has(node.key) ? "checked" : "unchecked";
132
- if (strict) node.childNodes.forEach(walk);
133
- states.set(node.key, state);
134
- return state;
135
- }
136
- const childStates = node.childNodes.map(walk);
137
- const allChecked = childStates.every((s) => s === "checked");
138
- const someMarked = childStates.some((s) => s !== "unchecked");
139
- const state = allChecked ? "checked" : someMarked || checkedKeys.has(node.key) ? "half" : "unchecked";
140
- states.set(node.key, state);
141
- return state;
142
- };
143
- roots.forEach(walk);
144
- return states;
145
- }
146
- /**
147
- * Новый набор отмеченных ключей после переключения узла.
148
- *
149
- * Каскад идёт вниз (все потомки повторяют решение) и вверх (родитель отмечен,
150
- * только если отмечены все его дети). Возвращается набор с родителями —
151
- * `getCheckedKeys({ leafOnly: true })` при необходимости отбросит их обратно.
152
- */
153
- function toggleCheckedKeys(roots, checkedKeys, node, checked, strict) {
154
- const next = new Set(checkedKeys);
155
- if (strict) {
156
- if (checked) next.add(node.key);
157
- else next.delete(node.key);
158
- return next;
159
- }
160
- const applyDown = (target) => {
161
- if (checked) next.add(target.key);
162
- else next.delete(target.key);
163
- target.childNodes.forEach(applyDown);
164
- };
165
- applyDown(node);
166
- for (let parent = node.parent; parent; parent = parent.parent) if (parent.childNodes.every((child) => next.has(child.key))) next.add(parent.key);
167
- else next.delete(parent.key);
168
- return pruneToTree(roots, next);
169
- }
170
- /** Отбрасывает ключи, которых нет в текущей модели (данные могли смениться). */
171
- function pruneToTree(roots, keys) {
172
- const known = /* @__PURE__ */ new Set();
173
- const walk = (node) => {
174
- known.add(node.key);
175
- node.childNodes.forEach(walk);
176
- };
177
- roots.forEach(walk);
178
- const next = /* @__PURE__ */ new Set();
179
- for (const key of keys) if (known.has(key)) next.add(key);
180
- return next;
181
- }
182
- /** Ключи в состоянии `checked`; `leafOnly` оставляет только листья. */
183
- function collectCheckedKeys(roots, states, leafOnly) {
184
- const out = [];
185
- const walk = (node) => {
186
- const isLeaf = node.childNodes.length === 0;
187
- if (states.get(node.key) === "checked" && (!leafOnly || isLeaf)) out.push(node.key);
188
- node.childNodes.forEach(walk);
189
- };
190
- roots.forEach(walk);
191
- return out;
192
- }
193
- /** Ключи в состоянии `half` — родители с частично отмеченными потомками. */
194
- function collectHalfCheckedKeys(states) {
195
- const out = [];
196
- for (const [key, state] of states) if (state === "half") out.push(key);
197
- return out;
198
- }
199
- //#endregion
200
- //#region src/components/GrTree/grTreeStore.ts
201
- function createGrTreeStore(options) {
202
- const filterValue = ref("");
203
- const expandedKeys = shallowRef(/* @__PURE__ */ new Set());
204
- const checkedKeys = shallowRef(new Set(toValue(options.defaultCheckedKeys) ?? []));
205
- const loadingKeys = shallowRef(/* @__PURE__ */ new Set());
206
- const loadedKeys = shallowRef(/* @__PURE__ */ new Set());
207
- const loadedChildren = shallowRef(/* @__PURE__ */ new Map());
208
- const currentKey = ref(void 0);
209
- const getData = () => toValue(options.data) ?? [];
210
- const getFilterNodeMethod = () => toValue(options.filterNodeMethod);
211
- watch(() => toValue(options.defaultExpandedKeys), (keys) => {
212
- expandedKeys.value = new Set(keys ?? []);
213
- }, { immediate: true });
214
- watch(() => toValue(options.checkedKeys), (keys) => {
215
- if (keys) checkedKeys.value = new Set(keys);
216
- }, { immediate: true });
217
- const treeModel = computed(() => {
218
- const byKey = /* @__PURE__ */ new Map();
219
- const byData = /* @__PURE__ */ new WeakMap();
220
- const build = (items, parent, level) => {
221
- return items.map((item, index) => {
222
- const node = {
223
- key: options.adapter.getNodeKey(item, index, parent?.key),
224
- label: options.adapter.getLabel(item),
225
- data: item,
226
- level,
227
- parent,
228
- childNodes: []
229
- };
230
- byKey.set(node.key, node);
231
- byData.set(item, node);
232
- const ownChildren = options.adapter.getChildren(item);
233
- const lazyChildren = loadedChildren.value.get(node.key) ?? [];
234
- node.childNodes = build([...ownChildren, ...lazyChildren], node, level + 1);
235
- return node;
236
- });
237
- };
238
- return {
239
- roots: build(getData(), void 0, 1),
240
- byKey,
241
- byData
242
- };
243
- });
244
- const autoExpandedKeys = /* @__PURE__ */ new Set();
245
- watch(treeModel, (model) => {
246
- if (!toValue(options.defaultExpandAll)) return;
247
- const next = new Set(expandedKeys.value);
248
- let changed = false;
249
- for (const key of model.byKey.keys()) {
250
- if (autoExpandedKeys.has(key)) continue;
251
- autoExpandedKeys.add(key);
252
- next.add(key);
253
- changed = true;
254
- }
255
- if (changed) expandedKeys.value = next;
256
- }, { immediate: true });
257
- const filterInfo = computed(() => {
258
- const value = filterValue.value;
259
- const isActive = value.trim().length > 0;
260
- const valueLower = value.toLowerCase();
261
- const subtreeHasMatch = /* @__PURE__ */ new Map();
262
- const matchedKeys = /* @__PURE__ */ new Set();
263
- const autoExpandKeys = /* @__PURE__ */ new Set();
264
- if (!isActive) return {
265
- isActive,
266
- subtreeHasMatch,
267
- matchedKeys,
268
- autoExpandKeys
269
- };
270
- const match = (node) => {
271
- const filterNodeMethod = getFilterNodeMethod();
272
- if (filterNodeMethod) return filterNodeMethod(value, node.data, node);
273
- return node.label.toLowerCase().includes(valueLower);
274
- };
275
- const walk = (nodes) => {
276
- let any = false;
277
- for (const node of nodes) {
278
- const self = match(node);
279
- const childAny = walk(node.childNodes);
280
- const has = self || childAny;
281
- subtreeHasMatch.set(node.key, has);
282
- if (self) matchedKeys.add(node.key);
283
- if (childAny) autoExpandKeys.add(node.key);
284
- any ||= has;
285
- }
286
- return any;
287
- };
288
- walk(treeModel.value.roots);
289
- return {
290
- isActive,
291
- subtreeHasMatch,
292
- matchedKeys,
293
- autoExpandKeys
294
- };
295
- });
296
- function getNode(key) {
297
- return treeModel.value.byKey.get(key);
298
- }
299
- function findNodeByData(data) {
300
- return treeModel.value.byData.get(data);
301
- }
302
- function isTreeNode(target) {
303
- return typeof target === "object" && target !== null && "key" in target && "data" in target && "childNodes" in target;
304
- }
305
- function resolveNodeTarget(target) {
306
- if (target == null) return void 0;
307
- if (typeof target === "string" || typeof target === "number") return getNode(target);
308
- if (isTreeNode(target)) return getNode(target.key) ?? target;
309
- const key = options.adapter.getExplicitNodeKey(target);
310
- if (key != null) return getNode(key);
311
- return findNodeByData(target);
312
- }
313
- function getNodeContainer(node) {
314
- const items = node.parent ? options.adapter.ensureChildren(node.parent.data) : getData();
315
- let index = items.findIndex((item) => item === node.data);
316
- if (index >= 0) return {
317
- items,
318
- index
319
- };
320
- const key = options.adapter.getExplicitNodeKey(node.data);
321
- if (key == null) return void 0;
322
- index = items.findIndex((item) => options.adapter.getExplicitNodeKey(item) === key);
323
- if (index < 0) return void 0;
324
- return {
325
- items,
326
- index
327
- };
328
- }
329
- function isDescendantNode(ancestor, node) {
330
- let current = node.parent;
331
- while (current) {
332
- if (current.key === ancestor.key) return true;
333
- current = current.parent;
334
- }
335
- return false;
336
- }
337
- function canMoveNode(node, referenceNode, dropType) {
338
- const sourceNode = resolveNodeTarget(node);
339
- const targetNode = resolveNodeTarget(referenceNode);
340
- if (!sourceNode || !targetNode) return false;
341
- if (sourceNode.key === targetNode.key) return false;
342
- if (isDescendantNode(sourceNode, targetNode)) return false;
343
- if (!getNodeContainer(sourceNode)) return false;
344
- if (dropType === "inner") return true;
345
- return Boolean(getNodeContainer(targetNode));
346
- }
347
- function sanitizeTreeState() {
348
- const byKey = treeModel.value.byKey;
349
- if (currentKey.value != null && !byKey.has(currentKey.value)) currentKey.value = void 0;
350
- const nextExpandedKeys = new Set(Array.from(expandedKeys.value).filter((key) => byKey.has(key)));
351
- if (nextExpandedKeys.size !== expandedKeys.value.size) expandedKeys.value = nextExpandedKeys;
352
- const nextCheckedKeys = new Set(Array.from(checkedKeys.value).filter((key) => byKey.has(key)));
353
- if (nextCheckedKeys.size !== checkedKeys.value.size) checkedKeys.value = nextCheckedKeys;
354
- }
355
- function isExpandedKey(key) {
356
- return expandedKeys.value.has(key);
357
- }
358
- function setExpandedKey(key, expanded) {
359
- const next = new Set(expandedKeys.value);
360
- if (expanded) next.add(key);
361
- else next.delete(key);
362
- expandedKeys.value = next;
363
- }
364
- function toggleExpand(node) {
365
- setExpandedKey(node.key, !isExpandedKey(node.key));
366
- }
367
- function setCurrentKey(key) {
368
- currentKey.value = key;
369
- }
370
- function getCurrentKey() {
371
- return currentKey.value;
372
- }
373
- function getCurrentNode() {
374
- const key = currentKey.value;
375
- return key == null ? void 0 : getNode(key);
376
- }
377
- function setCurrentNode(node) {
378
- if (node == null) {
379
- currentKey.value = void 0;
380
- return true;
381
- }
382
- const targetNode = resolveNodeTarget(node);
383
- if (!targetNode) return false;
384
- currentKey.value = targetNode.key;
385
- return true;
386
- }
387
- function resolveInsertedNode(data) {
388
- const key = options.adapter.getExplicitNodeKey(data);
389
- if (key != null) return getNode(key);
390
- return findNodeByData(data);
391
- }
392
- function moveNode(node, referenceNode, dropType) {
393
- const sourceNode = resolveNodeTarget(node);
394
- const targetNode = resolveNodeTarget(referenceNode);
395
- if (!sourceNode || !targetNode) return void 0;
396
- if (!canMoveNode(sourceNode, targetNode, dropType)) return void 0;
397
- const sourceContainer = getNodeContainer(sourceNode);
398
- if (!sourceContainer) return void 0;
399
- let destinationItems;
400
- let destinationIndex;
401
- if (dropType === "inner") {
402
- destinationItems = options.adapter.ensureChildren(targetNode.data);
403
- destinationIndex = destinationItems.length;
404
- } else {
405
- const targetContainer = getNodeContainer(targetNode);
406
- if (!targetContainer) return void 0;
407
- destinationItems = targetContainer.items;
408
- destinationIndex = dropType === "prev" ? targetContainer.index : targetContainer.index + 1;
409
- }
410
- if (destinationItems === sourceContainer.items && sourceContainer.index < destinationIndex) destinationIndex -= 1;
411
- const [movedData] = sourceContainer.items.splice(sourceContainer.index, 1);
412
- destinationItems.splice(destinationIndex, 0, movedData);
413
- if (dropType === "inner") setExpandedKey(targetNode.key, true);
414
- sanitizeTreeState();
415
- return resolveInsertedNode(movedData);
416
- }
417
- function appendNode(data, parent) {
418
- const parentNode = resolveNodeTarget(parent);
419
- if (!parentNode) return void 0;
420
- options.adapter.ensureChildren(parentNode.data).push(data);
421
- setExpandedKey(parentNode.key, true);
422
- sanitizeTreeState();
423
- return resolveInsertedNode(data);
424
- }
425
- function removeNode(node) {
426
- if (!options.adapter.hasNodeKey()) return false;
427
- const targetNode = resolveNodeTarget(node);
428
- if (!targetNode) return false;
429
- const container = getNodeContainer(targetNode);
430
- if (!container) return false;
431
- container.items.splice(container.index, 1);
432
- sanitizeTreeState();
433
- return true;
434
- }
435
- function insertNodeBefore(data, referenceNode) {
436
- const targetNode = resolveNodeTarget(referenceNode);
437
- if (!targetNode) return void 0;
438
- const container = getNodeContainer(targetNode);
439
- if (!container) return void 0;
440
- container.items.splice(container.index, 0, data);
441
- sanitizeTreeState();
442
- return resolveInsertedNode(data);
443
- }
444
- function insertNodeAfter(data, referenceNode) {
445
- const targetNode = resolveNodeTarget(referenceNode);
446
- if (!targetNode) return void 0;
447
- const container = getNodeContainer(targetNode);
448
- if (!container) return void 0;
449
- container.items.splice(container.index + 1, 0, data);
450
- sanitizeTreeState();
451
- return resolveInsertedNode(data);
452
- }
453
- const checkStates = computed(() => resolveCheckStates(treeModel.value.roots, checkedKeys.value, Boolean(toValue(options.checkStrictly))));
454
- function getCheckState(key) {
455
- return checkStates.value.get(key) ?? "unchecked";
456
- }
457
- function setChecked(node, checked) {
458
- const targetNode = resolveNodeTarget(node);
459
- if (!targetNode) return void 0;
460
- checkedKeys.value = toggleCheckedKeys(treeModel.value.roots, checkedKeys.value, targetNode, checked, Boolean(toValue(options.checkStrictly)));
461
- return targetNode;
462
- }
463
- function toggleChecked(node) {
464
- return setChecked(node, getCheckState(node.key) !== "checked");
465
- }
466
- function getCheckedKeys(opts) {
467
- return collectCheckedKeys(treeModel.value.roots, checkStates.value, Boolean(opts?.leafOnly));
468
- }
469
- function setCheckedKeys(keys) {
470
- checkedKeys.value = pruneToTree(treeModel.value.roots, new Set(keys));
471
- }
472
- function getHalfCheckedKeys() {
473
- return collectHalfCheckedKeys(checkStates.value);
474
- }
475
- function isLeafNode(node) {
476
- if (node.childNodes.length > 0) return false;
477
- if (!toValue(options.lazy)) return true;
478
- const declared = options.adapter.getIsLeaf(node.data);
479
- if (declared !== void 0) return declared;
480
- return loadedKeys.value.has(node.key);
481
- }
482
- function isLoadingKey(key) {
483
- return loadingKeys.value.has(key);
484
- }
485
- function markLoading(key, loading) {
486
- const next = new Set(loadingKeys.value);
487
- if (loading) next.add(key);
488
- else next.delete(key);
489
- loadingKeys.value = next;
490
- }
491
- function ensureLoaded(node) {
492
- const load = toValue(options.load);
493
- if (!toValue(options.lazy) || !load) return;
494
- if (loadedKeys.value.has(node.key) || loadingKeys.value.has(node.key) || isLeafNode(node)) return;
495
- markLoading(node.key, true);
496
- let settled = false;
497
- load(node, (children) => {
498
- if (settled) return;
499
- settled = true;
500
- const next = new Map(loadedChildren.value);
501
- next.set(node.key, [...children ?? []]);
502
- loadedChildren.value = next;
503
- loadedKeys.value = new Set(loadedKeys.value).add(node.key);
504
- markLoading(node.key, false);
505
- });
506
- }
507
- function filter(value) {
508
- filterValue.value = value;
509
- }
510
- return {
511
- filterValue,
512
- expandedKeys,
513
- loadedChildren,
514
- checkedKeys,
515
- checkStates,
516
- loadingKeys,
517
- loadedKeys,
518
- currentKey,
519
- treeModel,
520
- filterInfo,
521
- filter,
522
- isExpandedKey,
523
- setExpandedKey,
524
- toggleExpand,
525
- setCurrentKey,
526
- getCurrentKey,
527
- getCurrentNode,
528
- setCurrentNode,
529
- getNode,
530
- canMoveNode,
531
- moveNode,
532
- appendNode,
533
- removeNode,
534
- insertNodeBefore,
535
- insertNodeAfter,
536
- getCheckState,
537
- setChecked,
538
- toggleChecked,
539
- getCheckedKeys,
540
- setCheckedKeys,
541
- getHalfCheckedKeys,
542
- isLeafNode,
543
- isLoadingKey,
544
- ensureLoaded
545
- };
546
- }
547
- //#endregion
548
57
  //#region src/components/GrTree/grTreeStyles.ts
549
58
  var treeSizeVars = {
550
59
  xs: {
551
60
  "--gr-tree-row-min-height": "22px",
552
61
  "--gr-tree-row-px": "4px",
553
- "--gr-tree-row-py": "3px",
62
+ "--gr-tree-row-py": "2px",
554
63
  "--gr-tree-toggle-size": "18px",
555
64
  "--gr-tree-drag-handle-size": "18px",
556
65
  "--gr-tree-icon-size": "12px",
@@ -560,7 +69,7 @@ var treeSizeVars = {
560
69
  sm: {
561
70
  "--gr-tree-row-min-height": "24px",
562
71
  "--gr-tree-row-px": "6px",
563
- "--gr-tree-row-py": "5px",
72
+ "--gr-tree-row-py": "3px",
564
73
  "--gr-tree-toggle-size": "20px",
565
74
  "--gr-tree-drag-handle-size": "20px",
566
75
  "--gr-tree-icon-size": "14px",
@@ -570,7 +79,7 @@ var treeSizeVars = {
570
79
  md: {
571
80
  "--gr-tree-row-min-height": "28px",
572
81
  "--gr-tree-row-px": "8px",
573
- "--gr-tree-row-py": "8px",
82
+ "--gr-tree-row-py": "4px",
574
83
  "--gr-tree-toggle-size": "24px",
575
84
  "--gr-tree-drag-handle-size": "24px",
576
85
  "--gr-tree-icon-size": "16px",
@@ -580,7 +89,7 @@ var treeSizeVars = {
580
89
  lg: {
581
90
  "--gr-tree-row-min-height": "32px",
582
91
  "--gr-tree-row-px": "10px",
583
- "--gr-tree-row-py": "10px",
92
+ "--gr-tree-row-py": "6px",
584
93
  "--gr-tree-toggle-size": "28px",
585
94
  "--gr-tree-drag-handle-size": "28px",
586
95
  "--gr-tree-icon-size": "20px",
@@ -588,6 +97,53 @@ var treeSizeVars = {
588
97
  "--gr-tree-font-size": "15px"
589
98
  }
590
99
  };
100
+ var grTreeViewVars = {
101
+ /**
102
+ * Плотный проводник: максимум узлов на экран, колена связей вместо простых
103
+ * вертикалей. Под мышь — 24px меньше минимальной цели касания.
104
+ */
105
+ explorer: {
106
+ "--gr-tree-row-min-height": "24px",
107
+ "--gr-tree-row-py": "2px",
108
+ "--gr-tree-row-radius": "4px",
109
+ "--gr-tree-children-pl": "6px",
110
+ "--gr-tree-branch-line-offset": "8px",
111
+ "--gr-tree-branch-elbow-width": "6px",
112
+ "--gr-tree-content-gap": "6px"
113
+ },
114
+ /**
115
+ * Навигация: выбранная строка — сплошная плашка, обрезанная слева по отступу
116
+ * уровня. Текст на ней перекрашивается своим токеном, иначе на насыщенной
117
+ * подложке он остался бы нечитаемым.
118
+ */
119
+ /**
120
+ * Оглавление: иерархию несёт набор, а не хром. Направляющие и подложки
121
+ * гасятся, выбор отмечается цветом и весом — вид рассчитан на то, чтобы
122
+ * стоять рядом с читаемым текстом и не спорить с ним.
123
+ *
124
+ * Ступени кегля по уровням задаются `rowClass`: это единственное, чего набор
125
+ * значений сделать не может — уровень строки знает только разметка.
126
+ */
127
+ outline: {
128
+ "--gr-tree-row-min-height": "26px",
129
+ "--gr-tree-row-py": "3px",
130
+ "--gr-tree-row-px": "4px",
131
+ "--gr-tree-row-hover-bg": "transparent",
132
+ "--gr-tree-row-current-bg": "transparent",
133
+ "--gr-tree-row-current-hover-bg": "transparent",
134
+ "--gr-tree-row-current-color": "var(--gr-primary-text)",
135
+ "--gr-tree-children-pl": "4px",
136
+ "--gr-tree-branch-line-offset": "6px"
137
+ },
138
+ rail: {
139
+ "--gr-tree-row-min-height": "30px",
140
+ "--gr-tree-row-py": "5px",
141
+ "--gr-tree-row-radius": "999px",
142
+ "--gr-tree-row-current-bg": "var(--gr-primary)",
143
+ "--gr-tree-row-current-hover-bg": "var(--gr-primary-hover, var(--gr-primary))",
144
+ "--gr-tree-row-current-color": "var(--gr-primary-fg)"
145
+ }
146
+ };
591
147
  //#endregion
592
148
  //#region src/components/GrTree/GrTree.vue?vue&type=script&setup=true&lang.ts
593
149
  var _hoisted_1 = ["data-gr-virtual", "aria-multiselectable"];
@@ -663,8 +219,8 @@ var GrTree_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
663
219
  default: true
664
220
  },
665
221
  branchLine: {
666
- type: Boolean,
667
- default: false
222
+ type: [Boolean, String],
223
+ default: "line"
668
224
  },
669
225
  branchLineColor: {
670
226
  type: [String, Function],
@@ -791,17 +347,19 @@ var GrTree_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
791
347
  ]);
792
348
  const props = __props;
793
349
  const emit = __emit;
794
- const treeStore = createGrTreeStore({
795
- adapter: createGrTreeDataAdapter(props),
350
+ const dataAdapter = createGrTreeDataAdapter(props);
351
+ const treeStore = useTree({
352
+ adapter: dataAdapter,
353
+ branchColorFor: branchColorForNode,
796
354
  data: () => props.data,
797
355
  defaultExpandedKeys: () => props.defaultExpandedKeys,
798
356
  defaultExpandAll: () => props.defaultExpandAll,
799
- filterNodeMethod: () => props.filterNodeMethod,
357
+ filterNodeMethod: filterNodeForModel,
800
358
  defaultCheckedKeys: () => props.defaultCheckedKeys,
801
359
  checkedKeys: () => props.checkedKeys,
802
360
  checkStrictly: () => props.checkStrictly,
803
361
  lazy: () => props.lazy,
804
- load: () => props.load
362
+ load: loadForModel
805
363
  });
806
364
  const interactionContext = createGrTreeInteractionContext(props, {
807
365
  emitNodeClick: (data, node) => emit("nodeClick", data, node),
@@ -840,39 +398,11 @@ var GrTree_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
840
398
  }, { immediate: true });
841
399
  const treeRootEl = ref(null);
842
400
  /**
843
- * Видимые строки одним плоским списком в порядке отображения.
844
- *
845
- * Плоскопотому что рекурсивный рендер стоил по инстансу компонента на каждый
846
- * раскрытый узел: дерево на 2 000 видимых строк превращалось в 2 000
847
- * компонентов со своими вычислениями и подписками. Иерархию несут `aria-level`,
848
- * `aria-posinset` и `aria-setsize`, отступ — `padding-left` строки.
401
+ * Видимые строки считает модель (`useTree`): в плоском DOM группы нет, и
402
+ * структуру дерева диктору сообщают `aria-level`, `aria-posinset` и
403
+ * `aria-setsize`всё это приходит из неё готовым.
849
404
  */
850
- const visibleRows = computed(() => {
851
- const { roots } = treeStore.treeModel.value;
852
- const { isActive, subtreeHasMatch, matchedKeys, autoExpandKeys } = treeStore.filterInfo.value;
853
- const branch = treeProps.branchLine;
854
- const rows = [];
855
- const walk = (nodes, ancestorColors) => {
856
- const siblings = isActive ? nodes.filter((node) => subtreeHasMatch.get(node.key)) : nodes;
857
- siblings.forEach((node, index) => {
858
- const isLeaf = treeStore.isLeafNode(node);
859
- const isExpanded = treeStore.isExpandedKey(node.key) || isActive && autoExpandKeys.has(node.key);
860
- rows.push({
861
- node,
862
- isExpanded,
863
- isLeaf,
864
- isMatched: matchedKeys.has(node.key),
865
- posInSet: index + 1,
866
- setSize: siblings.length,
867
- isLoading: treeStore.isLoadingKey(node.key),
868
- branchColors: ancestorColors
869
- });
870
- if (isExpanded && node.childNodes.length) walk(node.childNodes, branch ? [...ancestorColors, resolveBranchLineColor(node)] : ancestorColors);
871
- });
872
- };
873
- walk(roots, []);
874
- return rows;
875
- });
405
+ const visibleRows = treeStore.visibleRows;
876
406
  /**
877
407
  * Кольцо roving-фокуса: ровно один `treeitem` на всё дерево держит `tabindex=0`.
878
408
  *
@@ -1120,6 +650,38 @@ var GrTree_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
1120
650
  * Направляющая уровня-предка. Считается от того же шага отступа, что и сам
1121
651
  * отступ строки, — иначе линия и содержимое разъедутся на вложенных уровнях.
1122
652
  */
653
+ /**
654
+ * Колено рисуется только у направляющей собственного уровня строки: остальные
655
+ * — это транзит предков, и горизонтальная черта у них указывала бы на строку,
656
+ * к которой они не относятся.
657
+ *
658
+ * У последнего ребёнка вертикаль обрывается на середине: продолжать её значит
659
+ * обещать сиблинга, которого нет.
660
+ */
661
+ /**
662
+ * Цвет направляющей уровня для модели. Объявление функцией, а не стрелкой на
663
+ * месте вызова: `treeProps` определяются ниже, и ссылка на них в выражении
664
+ * читалась бы до объявления.
665
+ */
666
+ /**
667
+ * Обёртки над пропами для модели: объявлением, а не стрелкой на месте вызова —
668
+ * `treeProps` определяются ниже. `undefined` от фильтра означает «решай сам»:
669
+ * так обёртка возвращает модель к её подстрочному матчу, когда своего правила
670
+ * потребитель не задал.
671
+ */
672
+ function filterNodeForModel(value, data, node) {
673
+ return treeProps.filterNodeMethod?.(value, data, node);
674
+ }
675
+ function loadForModel(node, resolve) {
676
+ treeProps.load?.(node, resolve);
677
+ }
678
+ function branchColorForNode(node) {
679
+ return treeProps.branchLine ? resolveBranchLineColor(node) : void 0;
680
+ }
681
+ function branchGuideModifiers(row, index) {
682
+ if (treeProps.branchLine !== "elbow" || index !== row.branchColors.length - 1) return void 0;
683
+ return row.posInSet === row.setSize ? "gr-tree__branch-guide--elbow gr-tree__branch-guide--last" : "gr-tree__branch-guide--elbow";
684
+ }
1123
685
  function branchGuideStyle(row, index) {
1124
686
  return {
1125
687
  "left": `calc(${treeProps.indent && treeProps.indent > 0 ? `${treeProps.indent}px` : "var(--gr-tree-indent-step)"} * ${index} + var(--gr-tree-branch-line-offset))`,
@@ -1333,6 +895,7 @@ var GrTree_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
1333
895
  "data-gr-tree-row": "",
1334
896
  class: normalizeClass(["gr-tree__row", [
1335
897
  unref(treeProps).highlightCurrent && unref(currentKey) === row.node.key ? "gr-tree__row--current" : "",
898
+ row.isLeaf ? "gr-tree__row--leaf" : "",
1336
899
  row.isMatched ? "gr-tree__row--matched" : "",
1337
900
  unref(dropTarget)?.key === row.node.key && unref(dropTarget).allowed && unref(dropTarget).type === "inner" ? "gr-tree__row--drop-inner" : "",
1338
901
  unref(dropTarget)?.key === row.node.key && unref(dropTarget).allowed && unref(dropTarget).type === "prev" ? "gr-tree__row--drop-prev" : "",
@@ -1350,10 +913,10 @@ var GrTree_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
1350
913
  return openBlock(), createElementBlock("span", {
1351
914
  key: guideIndex,
1352
915
  "data-gr-tree-branch-guide": "",
1353
- class: "gr-tree__branch-guide",
916
+ class: normalizeClass(["gr-tree__branch-guide", branchGuideModifiers(row, guideIndex)]),
1354
917
  style: normalizeStyle(branchGuideStyle(row, guideIndex)),
1355
918
  "aria-hidden": "true"
1356
- }, null, 4);
919
+ }, null, 6);
1357
920
  }), 128)),
1358
921
  unref(treeProps).draggable ? (openBlock(), createElementBlock("button", {
1359
922
  key: 0,
@@ -1411,6 +974,6 @@ var GrTree_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
1411
974
  }), 128))], 46, _hoisted_1);
1412
975
  };
1413
976
  }
1414
- }), [["__scopeId", "data-v-0ff88d29"]]);
977
+ }), [["__scopeId", "data-v-05278949"]]);
1415
978
  //#endregion
1416
- export { GrTree_default as t };
979
+ export { grTreeViewVars as n, GrTree_default as t };