@feugene/granularity 0.44.0 → 0.46.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-bjDf8nBf.js +43 -0
  3. package/dist/chunks/config-bjDf8nBf.js.map +1 -0
  4. package/dist/chunks/{generated-Hxu_sWPs.js → generated-CQ4h6Ieq.js} +45 -3
  5. package/dist/chunks/{generated-Hxu_sWPs.js.map → generated-CQ4h6Ieq.js.map} +1 -1
  6. package/dist/chunks/{granular-provider-CCNbQa5U.js → granular-provider-CsN_R9dB.js} +2 -0
  7. package/dist/chunks/granular-provider-CsN_R9dB.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-C6q8dEEZ.js} +1 -1
  11. package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-CwCBMh4h.js.map → GrJsonViewer-C6q8dEEZ.js.map} +1 -1
  12. package/dist/components/GrJsonViewer/index.js +1 -1
  13. package/dist/components/GrTree/chunks/{GrTree-CkHzgYg1.js → GrTree-6yZrncJE.js} +137 -540
  14. package/dist/components/GrTree/chunks/GrTree-6yZrncJE.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-DcmDcLwj.js +149 -0
  18. package/dist/components/GrTreeSections/chunks/GrTreeSections-DcmDcLwj.js.map +1 -0
  19. package/dist/components/GrTreeSections/index.js +3 -0
  20. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DUsv3_mF.js → GrTreeSelect-DBu5nMGA.js} +1 -1
  21. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DUsv3_mF.js.map → GrTreeSelect-DBu5nMGA.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 +23 -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,87 @@ 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": "10px",
112
+ "--gr-tree-content-gap": "6px",
113
+ "--gr-tree-branch-line-width": "1px",
114
+ "--gr-tree-branch-line-default-color": "var(--gr-brd)",
115
+ "--gr-tree-font-size": "12.5px",
116
+ "--gr-tree-toggle-size": "16px",
117
+ "--gr-tree-icon-size": "14px",
118
+ "--gr-tree-branch-font-weight": "400",
119
+ "--gr-tree-row-current-color": "var(--gr-primary-text)"
120
+ },
121
+ /**
122
+ * Навигация: выбранная строка — сплошная плашка, скруглённая только справа.
123
+ * Плоский левый край — не украшение: плашка начинается от отступа уровня, и
124
+ * скругление с той стороны читалось бы как отдельная кнопка, оторванная от
125
+ * рельса. Текст перекрашивается своим токеном, иначе на насыщенной подложке
126
+ * он остался бы нечитаемым.
127
+ */
128
+ rail: {
129
+ "--gr-tree-row-min-height": "30px",
130
+ "--gr-tree-row-py": "3px",
131
+ "--gr-tree-row-radius": "0 999px 999px 0",
132
+ "--gr-tree-row-current-bg": "var(--gr-primary)",
133
+ "--gr-tree-row-current-hover-bg": "var(--gr-primary-hover, var(--gr-primary))",
134
+ "--gr-tree-row-current-color": "var(--gr-primary-fg)",
135
+ "--gr-tree-branch-line-default-color": "var(--gr-brd)"
136
+ },
137
+ /**
138
+ * Отбор: дерево, по которому не ходят, а которое размечают. Строка просторнее
139
+ * остальных видов, потому что цель нажатия здесь — квадрат отметки, а не
140
+ * подпись: 38px и увеличенный квадрат делают её достижимой и пальцем.
141
+ *
142
+ * Сам по себе вид отметок не включает — это ортогональная ось (`showCheckbox`),
143
+ * и она же работает в любом другом виде. Набор задаёт только плотность под неё.
144
+ */
145
+ picker: {
146
+ "--gr-tree-row-min-height": "38px",
147
+ "--gr-tree-row-py": "7px",
148
+ "--gr-tree-row-px": "6px",
149
+ "--gr-tree-row-pr": "10px",
150
+ "--gr-tree-row-radius": "9px",
151
+ "--gr-tree-content-gap": "9px",
152
+ "--gr-tree-indent-step": "22px",
153
+ "--gr-tree-checkbox-size": "17px",
154
+ "--gr-tree-checkbox-radius": "5px",
155
+ "--gr-tree-checkbox-mr": "9px",
156
+ "--gr-tree-checkbox-brd-width": "1.5px"
157
+ },
158
+ /**
159
+ * Оглавление: иерархию несёт набор, а не хром. Направляющие и подложки
160
+ * гасятся, выбор отмечается полосой у края списка, цветом и весом — вид
161
+ * рассчитан на то, чтобы стоять рядом с читаемым текстом и не спорить с ним.
162
+ *
163
+ * Ступени кегля по уровням задаются `rowClass`: это единственное, чего набор
164
+ * значений сделать не может — уровень строки знает только разметка.
165
+ */
166
+ outline: {
167
+ "--gr-tree-row-min-height": "26px",
168
+ "--gr-tree-row-py": "3px",
169
+ "--gr-tree-row-px": "6px",
170
+ "--gr-tree-row-radius": "6px",
171
+ "--gr-tree-row-hover-bg": "transparent",
172
+ "--gr-tree-row-current-bg": "transparent",
173
+ "--gr-tree-row-current-hover-bg": "transparent",
174
+ "--gr-tree-row-current-color": "var(--gr-primary-text)",
175
+ "--gr-tree-row-current-bar-width": "2px",
176
+ "--gr-tree-children-pl": "4px",
177
+ "--gr-tree-branch-line-offset": "6px",
178
+ "--gr-tree-branch-font-weight": "inherit"
179
+ }
180
+ };
591
181
  //#endregion
592
182
  //#region src/components/GrTree/GrTree.vue?vue&type=script&setup=true&lang.ts
593
183
  var _hoisted_1 = ["data-gr-virtual", "aria-multiselectable"];
@@ -663,8 +253,8 @@ var GrTree_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
663
253
  default: true
664
254
  },
665
255
  branchLine: {
666
- type: Boolean,
667
- default: false
256
+ type: [Boolean, String],
257
+ default: "line"
668
258
  },
669
259
  branchLineColor: {
670
260
  type: [String, Function],
@@ -791,17 +381,19 @@ var GrTree_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
791
381
  ]);
792
382
  const props = __props;
793
383
  const emit = __emit;
794
- const treeStore = createGrTreeStore({
795
- adapter: createGrTreeDataAdapter(props),
384
+ const dataAdapter = createGrTreeDataAdapter(props);
385
+ const treeStore = useTree({
386
+ adapter: dataAdapter,
387
+ branchColorFor: branchColorForNode,
796
388
  data: () => props.data,
797
389
  defaultExpandedKeys: () => props.defaultExpandedKeys,
798
390
  defaultExpandAll: () => props.defaultExpandAll,
799
- filterNodeMethod: () => props.filterNodeMethod,
391
+ filterNodeMethod: filterNodeForModel,
800
392
  defaultCheckedKeys: () => props.defaultCheckedKeys,
801
393
  checkedKeys: () => props.checkedKeys,
802
394
  checkStrictly: () => props.checkStrictly,
803
395
  lazy: () => props.lazy,
804
- load: () => props.load
396
+ load: loadForModel
805
397
  });
806
398
  const interactionContext = createGrTreeInteractionContext(props, {
807
399
  emitNodeClick: (data, node) => emit("nodeClick", data, node),
@@ -840,39 +432,11 @@ var GrTree_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
840
432
  }, { immediate: true });
841
433
  const treeRootEl = ref(null);
842
434
  /**
843
- * Видимые строки одним плоским списком в порядке отображения.
844
- *
845
- * Плоскопотому что рекурсивный рендер стоил по инстансу компонента на каждый
846
- * раскрытый узел: дерево на 2 000 видимых строк превращалось в 2 000
847
- * компонентов со своими вычислениями и подписками. Иерархию несут `aria-level`,
848
- * `aria-posinset` и `aria-setsize`, отступ — `padding-left` строки.
435
+ * Видимые строки считает модель (`useTree`): в плоском DOM группы нет, и
436
+ * структуру дерева диктору сообщают `aria-level`, `aria-posinset` и
437
+ * `aria-setsize`всё это приходит из неё готовым.
849
438
  */
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
- });
439
+ const visibleRows = treeStore.visibleRows;
876
440
  /**
877
441
  * Кольцо roving-фокуса: ровно один `treeitem` на всё дерево держит `tabindex=0`.
878
442
  *
@@ -1120,6 +684,38 @@ var GrTree_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
1120
684
  * Направляющая уровня-предка. Считается от того же шага отступа, что и сам
1121
685
  * отступ строки, — иначе линия и содержимое разъедутся на вложенных уровнях.
1122
686
  */
687
+ /**
688
+ * Колено рисуется только у направляющей собственного уровня строки: остальные
689
+ * — это транзит предков, и горизонтальная черта у них указывала бы на строку,
690
+ * к которой они не относятся.
691
+ *
692
+ * У последнего ребёнка вертикаль обрывается на середине: продолжать её значит
693
+ * обещать сиблинга, которого нет.
694
+ */
695
+ /**
696
+ * Цвет направляющей уровня для модели. Объявление функцией, а не стрелкой на
697
+ * месте вызова: `treeProps` определяются ниже, и ссылка на них в выражении
698
+ * читалась бы до объявления.
699
+ */
700
+ /**
701
+ * Обёртки над пропами для модели: объявлением, а не стрелкой на месте вызова —
702
+ * `treeProps` определяются ниже. `undefined` от фильтра означает «решай сам»:
703
+ * так обёртка возвращает модель к её подстрочному матчу, когда своего правила
704
+ * потребитель не задал.
705
+ */
706
+ function filterNodeForModel(value, data, node) {
707
+ return treeProps.filterNodeMethod?.(value, data, node);
708
+ }
709
+ function loadForModel(node, resolve) {
710
+ treeProps.load?.(node, resolve);
711
+ }
712
+ function branchColorForNode(node) {
713
+ return treeProps.branchLine ? resolveBranchLineColor(node) : void 0;
714
+ }
715
+ function branchGuideModifiers(row, index) {
716
+ if (treeProps.branchLine !== "elbow" || index !== row.branchColors.length - 1) return void 0;
717
+ return row.posInSet === row.setSize ? "gr-tree__branch-guide--elbow gr-tree__branch-guide--last" : "gr-tree__branch-guide--elbow";
718
+ }
1123
719
  function branchGuideStyle(row, index) {
1124
720
  return {
1125
721
  "left": `calc(${treeProps.indent && treeProps.indent > 0 ? `${treeProps.indent}px` : "var(--gr-tree-indent-step)"} * ${index} + var(--gr-tree-branch-line-offset))`,
@@ -1333,6 +929,7 @@ var GrTree_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
1333
929
  "data-gr-tree-row": "",
1334
930
  class: normalizeClass(["gr-tree__row", [
1335
931
  unref(treeProps).highlightCurrent && unref(currentKey) === row.node.key ? "gr-tree__row--current" : "",
932
+ row.isLeaf ? "gr-tree__row--leaf" : "",
1336
933
  row.isMatched ? "gr-tree__row--matched" : "",
1337
934
  unref(dropTarget)?.key === row.node.key && unref(dropTarget).allowed && unref(dropTarget).type === "inner" ? "gr-tree__row--drop-inner" : "",
1338
935
  unref(dropTarget)?.key === row.node.key && unref(dropTarget).allowed && unref(dropTarget).type === "prev" ? "gr-tree__row--drop-prev" : "",
@@ -1350,10 +947,10 @@ var GrTree_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
1350
947
  return openBlock(), createElementBlock("span", {
1351
948
  key: guideIndex,
1352
949
  "data-gr-tree-branch-guide": "",
1353
- class: "gr-tree__branch-guide",
950
+ class: normalizeClass(["gr-tree__branch-guide", branchGuideModifiers(row, guideIndex)]),
1354
951
  style: normalizeStyle(branchGuideStyle(row, guideIndex)),
1355
952
  "aria-hidden": "true"
1356
- }, null, 4);
953
+ }, null, 6);
1357
954
  }), 128)),
1358
955
  unref(treeProps).draggable ? (openBlock(), createElementBlock("button", {
1359
956
  key: 0,
@@ -1411,6 +1008,6 @@ var GrTree_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
1411
1008
  }), 128))], 46, _hoisted_1);
1412
1009
  };
1413
1010
  }
1414
- }), [["__scopeId", "data-v-0ff88d29"]]);
1011
+ }), [["__scopeId", "data-v-5a669f90"]]);
1415
1012
  //#endregion
1416
- export { GrTree_default as t };
1013
+ export { grTreeViewVars as n, GrTree_default as t };