@edux-design/tree-select 0.2.5 → 0.3.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.
- package/CHANGELOG.md +83 -0
- package/README.md +94 -3
- package/dist/index.css +39 -0
- package/dist/index.d.mts +92 -19
- package/dist/index.d.ts +92 -19
- package/dist/index.js +222 -75
- package/dist/index.mjs +222 -75
- package/docs/DS15_INVENTORY.md +52 -0
- package/docs/DS15_VERIFICATION.md +62 -0
- package/package.json +7 -14
package/dist/index.js
CHANGED
|
@@ -26,10 +26,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
26
|
));
|
|
27
27
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
28
|
|
|
29
|
-
// src/index.
|
|
29
|
+
// src/index.ts
|
|
30
30
|
var index_exports = {};
|
|
31
31
|
__export(index_exports, {
|
|
32
|
-
TreeSelect: () =>
|
|
32
|
+
TreeSelect: () => TreeSelect3
|
|
33
33
|
});
|
|
34
34
|
module.exports = __toCommonJS(index_exports);
|
|
35
35
|
|
|
@@ -47,6 +47,21 @@ var import_icons = require("@edux-design/icons");
|
|
|
47
47
|
var import_menus = require("@edux-design/menus");
|
|
48
48
|
var import_tooltips = require("@edux-design/tooltips");
|
|
49
49
|
|
|
50
|
+
// src/elements/treeSelectInteraction.js
|
|
51
|
+
function isTreeRowControl(event) {
|
|
52
|
+
const control = event.target?.closest?.(
|
|
53
|
+
'button, input, textarea, select, a[href], [contenteditable="true"], [role="button"], [role="checkbox"], [role="menuitem"], [tabindex]:not([tabindex="-1"]), [data-tree-interactive]'
|
|
54
|
+
);
|
|
55
|
+
return Boolean(control && control !== event.currentTarget && event.currentTarget.contains(control));
|
|
56
|
+
}
|
|
57
|
+
function hasActivationModifier(event) {
|
|
58
|
+
return event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;
|
|
59
|
+
}
|
|
60
|
+
function getTreeItemLabel(node, getItemLabel) {
|
|
61
|
+
if (getItemLabel) return getItemLabel(node);
|
|
62
|
+
return typeof node.label === "string" || typeof node.label === "number" ? String(node.label) : String(node.id);
|
|
63
|
+
}
|
|
64
|
+
|
|
50
65
|
// src/elements/treeSelectConstants.js
|
|
51
66
|
var HANDLE_WIDTH = 28;
|
|
52
67
|
var TOGGLE_WIDTH = 28;
|
|
@@ -55,6 +70,8 @@ var INDICATOR_INSET = HANDLE_WIDTH + TOGGLE_WIDTH + 12;
|
|
|
55
70
|
|
|
56
71
|
// src/elements/TreeRow.jsx
|
|
57
72
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
73
|
+
var DRAG_ROW_BACKGROUND = "color-mix(in srgb, var(--color-fg-base) 4%, transparent)";
|
|
74
|
+
var SELECTED_ROW_BACKGROUND = "color-mix(in srgb, var(--color-primary-600) 8%, transparent)";
|
|
58
75
|
var TreeRow = ({
|
|
59
76
|
item,
|
|
60
77
|
depth,
|
|
@@ -66,6 +83,11 @@ var TreeRow = ({
|
|
|
66
83
|
dragAttributes,
|
|
67
84
|
dragRef,
|
|
68
85
|
rowRef,
|
|
86
|
+
rowAccessibility,
|
|
87
|
+
labelContext,
|
|
88
|
+
accessibleLabel,
|
|
89
|
+
rowClassName,
|
|
90
|
+
labelClassName,
|
|
69
91
|
isDragging,
|
|
70
92
|
isSelected,
|
|
71
93
|
onRowClick,
|
|
@@ -98,11 +120,12 @@ var TreeRow = ({
|
|
|
98
120
|
depth,
|
|
99
121
|
parentId: item.parentId,
|
|
100
122
|
hasChildren: item.hasChildren,
|
|
101
|
-
isExpanded
|
|
123
|
+
isExpanded,
|
|
124
|
+
...labelContext
|
|
102
125
|
}) : label;
|
|
103
126
|
const showToggle = item.hasChildren;
|
|
104
127
|
const [additionalMenuOpen, setAdditionalMenuOpen] = import_react.default.useState(false);
|
|
105
|
-
const rowBackground = isDragging ?
|
|
128
|
+
const rowBackground = isDragging ? DRAG_ROW_BACKGROUND : isSelected ? SELECTED_ROW_BACKGROUND : void 0;
|
|
106
129
|
const rowPaddingLeft = depth * INDENT_WIDTH + 8;
|
|
107
130
|
const hasAdditionalActionsMenu = Boolean(additionalActionsMenu);
|
|
108
131
|
const showActions = canAddChild || canAddSibling || canDelete || hasAdditionalActionsMenu;
|
|
@@ -123,9 +146,12 @@ var TreeRow = ({
|
|
|
123
146
|
"div",
|
|
124
147
|
{
|
|
125
148
|
ref: rowRef,
|
|
126
|
-
|
|
149
|
+
...rowAccessibility,
|
|
150
|
+
onClick: (event) => onRowClick?.(event, item.id),
|
|
127
151
|
"data-tree-row": item.id,
|
|
128
|
-
|
|
152
|
+
"data-selected": isSelected || void 0,
|
|
153
|
+
"data-current": labelContext?.isCurrent || void 0,
|
|
154
|
+
className: ["transition-colors hover:bg-bg-primary-subtle focus-visible:shadow-focus", labelContext?.isCurrent ? "bg-bg-primary-subtle text-fg-primary-emphasis" : "", rowClassName].filter(Boolean).join(" "),
|
|
129
155
|
style: {
|
|
130
156
|
display: "flex",
|
|
131
157
|
alignItems: "center",
|
|
@@ -144,7 +170,7 @@ var TreeRow = ({
|
|
|
144
170
|
...dragAttributes,
|
|
145
171
|
...dragHandleProps,
|
|
146
172
|
ref: dragRef,
|
|
147
|
-
"aria-label":
|
|
173
|
+
"aria-label": `Move ${accessibleLabel}`,
|
|
148
174
|
onClick: (event) => event.stopPropagation(),
|
|
149
175
|
className: "border border-border-subtle bg-bg-base text-fg-base",
|
|
150
176
|
style: {
|
|
@@ -164,7 +190,8 @@ var TreeRow = ({
|
|
|
164
190
|
"button",
|
|
165
191
|
{
|
|
166
192
|
type: "button",
|
|
167
|
-
"aria-label": toggleLabel
|
|
193
|
+
"aria-label": `${toggleLabel}: ${accessibleLabel}`,
|
|
194
|
+
"aria-expanded": isExpanded,
|
|
168
195
|
onClick: () => onToggle(item.id),
|
|
169
196
|
style: {
|
|
170
197
|
width: 24,
|
|
@@ -186,6 +213,8 @@ var TreeRow = ({
|
|
|
186
213
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
187
214
|
import_forms.Checkbox,
|
|
188
215
|
{
|
|
216
|
+
"aria-label": `${toggleLabel}: ${accessibleLabel}`,
|
|
217
|
+
"aria-expanded": isExpanded,
|
|
189
218
|
checked: false,
|
|
190
219
|
plus: !isExpanded,
|
|
191
220
|
indeterminate: isExpanded,
|
|
@@ -197,19 +226,21 @@ var TreeRow = ({
|
|
|
197
226
|
"input",
|
|
198
227
|
{
|
|
199
228
|
type: "text",
|
|
229
|
+
"aria-label": `Edit ${accessibleLabel}`,
|
|
230
|
+
onClick: (event) => event.stopPropagation(),
|
|
200
231
|
value: draftLabel,
|
|
201
232
|
autoFocus: true,
|
|
202
233
|
"data-tree-input": item.id,
|
|
203
234
|
onChange: (event) => onDraftChange(event.target.value),
|
|
204
235
|
onBlur: onCommitEdit,
|
|
205
236
|
onKeyDown: (event) => {
|
|
237
|
+
event.stopPropagation();
|
|
206
238
|
if (event.key === "Enter") onCommitEdit();
|
|
207
239
|
if (event.key === "Escape") onCancelEdit();
|
|
208
240
|
},
|
|
209
241
|
style: {
|
|
210
242
|
fontSize: 14,
|
|
211
243
|
border: "none",
|
|
212
|
-
outline: "none",
|
|
213
244
|
background: "transparent",
|
|
214
245
|
padding: 0
|
|
215
246
|
}
|
|
@@ -218,19 +249,30 @@ var TreeRow = ({
|
|
|
218
249
|
"span",
|
|
219
250
|
{
|
|
220
251
|
onClick: (event) => {
|
|
221
|
-
if (!isEditable) return;
|
|
252
|
+
if (!isEditable || event.defaultPrevented || isTreeRowControl(event)) return;
|
|
222
253
|
event.stopPropagation();
|
|
223
|
-
onStartEdit
|
|
254
|
+
onStartEdit?.();
|
|
224
255
|
},
|
|
256
|
+
role: isEditable ? "button" : void 0,
|
|
257
|
+
tabIndex: isEditable ? 0 : void 0,
|
|
258
|
+
"aria-label": isEditable ? `Edit ${accessibleLabel}` : void 0,
|
|
259
|
+
onKeyDown: isEditable ? (event) => {
|
|
260
|
+
if (event.target !== event.currentTarget) return;
|
|
261
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
262
|
+
event.preventDefault();
|
|
263
|
+
event.stopPropagation();
|
|
264
|
+
onStartEdit?.();
|
|
265
|
+
}
|
|
266
|
+
} : void 0,
|
|
225
267
|
"data-tree-label": item.id,
|
|
268
|
+
className: [renderLabel ? "inline-flex items-center gap-6" : "", labelClassName].filter(Boolean).join(" "),
|
|
226
269
|
style: {
|
|
227
270
|
fontSize: 14,
|
|
271
|
+
display: "inline-flex",
|
|
272
|
+
alignItems: "center",
|
|
273
|
+
minHeight: isEditable ? 24 : void 0,
|
|
228
274
|
cursor: isEditable ? "pointer" : "default",
|
|
229
|
-
|
|
230
|
-
display: "inline-flex",
|
|
231
|
-
alignItems: "center",
|
|
232
|
-
gap: 6
|
|
233
|
-
} : labelStyle
|
|
275
|
+
...!renderLabel ? labelStyle : {}
|
|
234
276
|
},
|
|
235
277
|
children: labelContent
|
|
236
278
|
}
|
|
@@ -250,7 +292,7 @@ var TreeRow = ({
|
|
|
250
292
|
isBare: true,
|
|
251
293
|
icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.Plus, { "aria-hidden": "true" }),
|
|
252
294
|
"aria-label": "Add child",
|
|
253
|
-
onClick: () => onAddChild
|
|
295
|
+
onClick: () => onAddChild?.(item.id)
|
|
254
296
|
}
|
|
255
297
|
) }),
|
|
256
298
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tooltips.TooltipContent, { children: addChildTooltip ?? "Add child" })
|
|
@@ -263,7 +305,7 @@ var TreeRow = ({
|
|
|
263
305
|
isBare: true,
|
|
264
306
|
icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.List, { "aria-hidden": "true" }),
|
|
265
307
|
"aria-label": "Add sibling",
|
|
266
|
-
onClick: () => onAddSibling
|
|
308
|
+
onClick: () => onAddSibling?.(item.id)
|
|
267
309
|
}
|
|
268
310
|
) }),
|
|
269
311
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tooltips.TooltipContent, { children: addSiblingTooltip ?? "Add sibling" })
|
|
@@ -276,7 +318,7 @@ var TreeRow = ({
|
|
|
276
318
|
isBare: true,
|
|
277
319
|
icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.Close, { "aria-hidden": "true" }),
|
|
278
320
|
"aria-label": "Delete item",
|
|
279
|
-
onClick: () => onDelete
|
|
321
|
+
onClick: () => onDelete?.(item.id)
|
|
280
322
|
}
|
|
281
323
|
) }),
|
|
282
324
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tooltips.TooltipContent, { children: deleteTooltip ?? "Delete item" })
|
|
@@ -317,6 +359,12 @@ var TreeSortableRow = ({
|
|
|
317
359
|
onToggle,
|
|
318
360
|
onRowClick,
|
|
319
361
|
rowRefs,
|
|
362
|
+
rowAccessibility,
|
|
363
|
+
labelContext,
|
|
364
|
+
accessibleLabel,
|
|
365
|
+
rowClassName,
|
|
366
|
+
labelClassName,
|
|
367
|
+
onRowSelect,
|
|
320
368
|
isActive,
|
|
321
369
|
isSelected,
|
|
322
370
|
isGroupDragging,
|
|
@@ -364,12 +412,11 @@ var TreeSortableRow = ({
|
|
|
364
412
|
() => ({
|
|
365
413
|
...listeners,
|
|
366
414
|
onPointerDown: (event) => {
|
|
367
|
-
|
|
368
|
-
(
|
|
369
|
-
onRowClick == null ? void 0 : onRowClick(event, item.id);
|
|
415
|
+
listeners?.onPointerDown?.(event);
|
|
416
|
+
onRowSelect?.(event, item.id);
|
|
370
417
|
}
|
|
371
418
|
}),
|
|
372
|
-
[item.id, listeners,
|
|
419
|
+
[item.id, listeners, onRowSelect]
|
|
373
420
|
);
|
|
374
421
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
375
422
|
TreeRow,
|
|
@@ -383,6 +430,11 @@ var TreeSortableRow = ({
|
|
|
383
430
|
dragAttributes: attributes,
|
|
384
431
|
dragRef: setActivatorNodeRef,
|
|
385
432
|
rowRef: rowRefCallback,
|
|
433
|
+
rowAccessibility,
|
|
434
|
+
labelContext,
|
|
435
|
+
accessibleLabel,
|
|
436
|
+
rowClassName,
|
|
437
|
+
labelClassName,
|
|
386
438
|
isDragging: isDragging || isActive || isGroupDragging,
|
|
387
439
|
isSelected,
|
|
388
440
|
isEditable,
|
|
@@ -457,11 +509,10 @@ var collectDraggedIds = (items, rootIds) => {
|
|
|
457
509
|
var getSelectedRootIds = (items, selectedIds) => {
|
|
458
510
|
const itemById = new Map(items.map((item) => [item.id, item]));
|
|
459
511
|
return items.filter((item) => selectedIds.has(item.id)).filter((item) => {
|
|
460
|
-
|
|
461
|
-
let parentId = (_a = itemById.get(item.id)) == null ? void 0 : _a.parentId;
|
|
512
|
+
let parentId = itemById.get(item.id)?.parentId;
|
|
462
513
|
while (parentId) {
|
|
463
514
|
if (selectedIds.has(parentId)) return false;
|
|
464
|
-
parentId =
|
|
515
|
+
parentId = itemById.get(parentId)?.parentId;
|
|
465
516
|
}
|
|
466
517
|
return true;
|
|
467
518
|
}).map((item) => item.id);
|
|
@@ -761,7 +812,7 @@ var getDropIndicator = ({
|
|
|
761
812
|
|
|
762
813
|
// src/elements/TreeSelect.jsx
|
|
763
814
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
764
|
-
|
|
815
|
+
var TreeSelect = (0, import_react3.forwardRef)(function TreeSelect2({
|
|
765
816
|
data,
|
|
766
817
|
onDataChange,
|
|
767
818
|
allowDragAndDrop = false,
|
|
@@ -781,8 +832,16 @@ function TreeSelect({
|
|
|
781
832
|
expanded,
|
|
782
833
|
onExpandedChange,
|
|
783
834
|
renderAdditionalActionsMenu,
|
|
784
|
-
renderLabel
|
|
785
|
-
|
|
835
|
+
renderLabel,
|
|
836
|
+
onNodeActivate,
|
|
837
|
+
currentId,
|
|
838
|
+
getItemLabel,
|
|
839
|
+
rowClassName,
|
|
840
|
+
labelClassName,
|
|
841
|
+
"aria-label": ariaLabel = "Tree",
|
|
842
|
+
"aria-labelledby": ariaLabelledBy,
|
|
843
|
+
...rootProps
|
|
844
|
+
}, forwardedRef) {
|
|
786
845
|
const [uncontrolledExpandedIds, setExpandedIds] = (0, import_react3.useState)(
|
|
787
846
|
() => getExpandedIds(data ?? [], defaultExpanded)
|
|
788
847
|
);
|
|
@@ -792,6 +851,8 @@ function TreeSelect({
|
|
|
792
851
|
const [horizontalOffset, setHorizontalOffset] = (0, import_react3.useState)(0);
|
|
793
852
|
const [selectedIds, setSelectedIds] = (0, import_react3.useState)(() => /* @__PURE__ */ new Set());
|
|
794
853
|
const [lastSelectedId, setLastSelectedId] = (0, import_react3.useState)(null);
|
|
854
|
+
const [focusedId, setFocusedId] = (0, import_react3.useState)(null);
|
|
855
|
+
const [focusWithinId, setFocusWithinId] = (0, import_react3.useState)(null);
|
|
795
856
|
const [editingId, setEditingId] = (0, import_react3.useState)(null);
|
|
796
857
|
const [draftLabel, setDraftLabel] = (0, import_react3.useState)("");
|
|
797
858
|
const idCounterRef = (0, import_react3.useRef)(0);
|
|
@@ -811,6 +872,22 @@ function TreeSelect({
|
|
|
811
872
|
() => new Map(visibleItems.map((item) => [item.id, item])),
|
|
812
873
|
[visibleItems]
|
|
813
874
|
);
|
|
875
|
+
const getRowElement = (0, import_react3.useCallback)((id) => rowRefs.current.get(normaliseId(id)) ?? null, []);
|
|
876
|
+
(0, import_react3.useImperativeHandle)(forwardedRef, () => ({
|
|
877
|
+
getRowElement,
|
|
878
|
+
focusItem(id, options) {
|
|
879
|
+
const row = getRowElement(id);
|
|
880
|
+
if (!row) return false;
|
|
881
|
+
row.focus(options);
|
|
882
|
+
return true;
|
|
883
|
+
},
|
|
884
|
+
scrollToItem(id, options = { block: "nearest", inline: "nearest" }) {
|
|
885
|
+
const row = getRowElement(id);
|
|
886
|
+
if (!row || typeof row.scrollIntoView !== "function") return false;
|
|
887
|
+
row.scrollIntoView(options);
|
|
888
|
+
return true;
|
|
889
|
+
}
|
|
890
|
+
}), [getRowElement]);
|
|
814
891
|
const siblingOrderMap = (0, import_react3.useMemo)(
|
|
815
892
|
() => buildSiblingOrderMap(treeData),
|
|
816
893
|
[treeData]
|
|
@@ -821,19 +898,18 @@ function TreeSelect({
|
|
|
821
898
|
}, [maxDepth]);
|
|
822
899
|
const resolvedLevelConfig = (0, import_react3.useCallback)(
|
|
823
900
|
(depth) => {
|
|
824
|
-
|
|
825
|
-
const
|
|
826
|
-
const perLevel = ((_a = levelConfig == null ? void 0 : levelConfig.levels) == null ? void 0 : _a[depth]) ?? {};
|
|
901
|
+
const defaults = levelConfig?.default ?? {};
|
|
902
|
+
const perLevel = levelConfig?.levels?.[depth] ?? {};
|
|
827
903
|
const editable = perLevel.editable ?? defaults.editable ?? isEditable;
|
|
828
904
|
const actions = {
|
|
829
|
-
addChild:
|
|
830
|
-
addSibling:
|
|
831
|
-
delete:
|
|
905
|
+
addChild: perLevel.actions?.addChild ?? defaults.actions?.addChild ?? editable,
|
|
906
|
+
addSibling: perLevel.actions?.addSibling ?? defaults.actions?.addSibling ?? editable,
|
|
907
|
+
delete: perLevel.actions?.delete ?? defaults.actions?.delete ?? (editable && allowDelete)
|
|
832
908
|
};
|
|
833
909
|
const tooltips = {
|
|
834
|
-
addChild:
|
|
835
|
-
addSibling:
|
|
836
|
-
delete:
|
|
910
|
+
addChild: perLevel.tooltips?.addChild ?? defaults.tooltips?.addChild ?? addChildTooltip,
|
|
911
|
+
addSibling: perLevel.tooltips?.addSibling ?? defaults.tooltips?.addSibling ?? addSiblingTooltip,
|
|
912
|
+
delete: perLevel.tooltips?.delete ?? defaults.tooltips?.delete ?? deleteTooltip
|
|
837
913
|
};
|
|
838
914
|
return { editable, actions, tooltips };
|
|
839
915
|
},
|
|
@@ -853,7 +929,7 @@ function TreeSelect({
|
|
|
853
929
|
(updater) => {
|
|
854
930
|
if (isExpandedControlled) {
|
|
855
931
|
const next = updater(new Set(expandedIds));
|
|
856
|
-
onExpandedChange
|
|
932
|
+
onExpandedChange?.(next);
|
|
857
933
|
return;
|
|
858
934
|
}
|
|
859
935
|
setExpandedIds((prev) => updater(new Set(prev)));
|
|
@@ -862,7 +938,7 @@ function TreeSelect({
|
|
|
862
938
|
);
|
|
863
939
|
const emitDataChange = (0, import_react3.useCallback)(
|
|
864
940
|
(nextTree, meta) => {
|
|
865
|
-
onDataChange
|
|
941
|
+
onDataChange?.(nextTree, meta);
|
|
866
942
|
},
|
|
867
943
|
[onDataChange]
|
|
868
944
|
);
|
|
@@ -876,17 +952,16 @@ function TreeSelect({
|
|
|
876
952
|
return prev;
|
|
877
953
|
});
|
|
878
954
|
}, [updateExpandedIds]);
|
|
879
|
-
const
|
|
955
|
+
const handleRowSelection = (0, import_react3.useCallback)(
|
|
880
956
|
(event, id) => {
|
|
881
|
-
var _a, _b;
|
|
882
957
|
if (!allowMultiDrag) return;
|
|
883
958
|
const hasMultiKey = event.metaKey || event.ctrlKey;
|
|
884
|
-
const parentId =
|
|
959
|
+
const parentId = itemById.get(id)?.parentId ?? null;
|
|
885
960
|
const siblingOrder = siblingOrderMap.get(parentId) ?? [];
|
|
886
961
|
if (event.shiftKey) {
|
|
887
962
|
const anchorIndex = siblingOrder.indexOf(lastSelectedId);
|
|
888
963
|
const targetIndex = siblingOrder.indexOf(id);
|
|
889
|
-
if (anchorIndex < 0 || targetIndex < 0 || (
|
|
964
|
+
if (anchorIndex < 0 || targetIndex < 0 || (itemById.get(lastSelectedId ?? "")?.parentId ?? null) !== parentId) {
|
|
890
965
|
setSelectedIds(/* @__PURE__ */ new Set([id]));
|
|
891
966
|
setLastSelectedId(id);
|
|
892
967
|
return;
|
|
@@ -908,10 +983,9 @@ function TreeSelect({
|
|
|
908
983
|
return;
|
|
909
984
|
}
|
|
910
985
|
setSelectedIds((prev) => {
|
|
911
|
-
var _a2;
|
|
912
986
|
if (prev.size) {
|
|
913
987
|
const firstSelected = prev.values().next().value;
|
|
914
|
-
const selectedParent =
|
|
988
|
+
const selectedParent = itemById.get(firstSelected)?.parentId ?? null;
|
|
915
989
|
if (selectedParent !== parentId) {
|
|
916
990
|
return /* @__PURE__ */ new Set([id]);
|
|
917
991
|
}
|
|
@@ -938,6 +1012,16 @@ function TreeSelect({
|
|
|
938
1012
|
siblingOrderMap
|
|
939
1013
|
]
|
|
940
1014
|
);
|
|
1015
|
+
const activateItem = (0, import_react3.useCallback)((event, id, inputSource) => {
|
|
1016
|
+
if (event.defaultPrevented || event.repeat || inputSource === "pointer" && event.button !== 0 || hasActivationModifier(event) || isTreeRowControl(event)) return;
|
|
1017
|
+
const item = itemById.get(id);
|
|
1018
|
+
if (item && !activeId) onNodeActivate?.({ ...item, event, inputSource });
|
|
1019
|
+
}, [activeId, itemById, onNodeActivate]);
|
|
1020
|
+
const handleRowClick = (0, import_react3.useCallback)((event, id) => {
|
|
1021
|
+
if (event.defaultPrevented || isTreeRowControl(event)) return;
|
|
1022
|
+
handleRowSelection(event, id);
|
|
1023
|
+
activateItem(event, id, "pointer");
|
|
1024
|
+
}, [activateItem, handleRowSelection]);
|
|
941
1025
|
const draggedRootIds = (0, import_react3.useMemo)(
|
|
942
1026
|
() => getDraggedRootIds({
|
|
943
1027
|
activeId,
|
|
@@ -969,13 +1053,11 @@ function TreeSelect({
|
|
|
969
1053
|
setHorizontalOffset(event.delta.x);
|
|
970
1054
|
}, []);
|
|
971
1055
|
const handleDragOver = (0, import_react3.useCallback)((event) => {
|
|
972
|
-
|
|
973
|
-
if ((_a = event.over) == null ? void 0 : _a.id) {
|
|
1056
|
+
if (event.over?.id) {
|
|
974
1057
|
setOverId(normaliseId(event.over.id));
|
|
975
1058
|
}
|
|
976
1059
|
}, []);
|
|
977
1060
|
const handleDragEnd = (0, import_react3.useCallback)(() => {
|
|
978
|
-
var _a;
|
|
979
1061
|
const projection = getDropProjection({
|
|
980
1062
|
items: visibleItems,
|
|
981
1063
|
activeId,
|
|
@@ -991,7 +1073,7 @@ function TreeSelect({
|
|
|
991
1073
|
return;
|
|
992
1074
|
}
|
|
993
1075
|
const { parentId, siblingIndex, projectedDepth } = projection;
|
|
994
|
-
const sourceParentId =
|
|
1076
|
+
const sourceParentId = itemById.get(draggedRootIds[0] ?? activeId)?.parentId ?? null;
|
|
995
1077
|
const { nextNodes, removedNodes } = removeNodes(treeData, draggedRootIds);
|
|
996
1078
|
if (!removedNodes.length) {
|
|
997
1079
|
setActiveId(null);
|
|
@@ -1104,8 +1186,7 @@ function TreeSelect({
|
|
|
1104
1186
|
);
|
|
1105
1187
|
const startEdit = (0, import_react3.useCallback)(
|
|
1106
1188
|
(id) => {
|
|
1107
|
-
|
|
1108
|
-
const currentLabel = ((_b = (_a = itemById.get(id)) == null ? void 0 : _a.node) == null ? void 0 : _b.label) ?? ((_d = (_c = itemById.get(id)) == null ? void 0 : _c.node) == null ? void 0 : _d.id) ?? "";
|
|
1189
|
+
const currentLabel = itemById.get(id)?.node?.label ?? itemById.get(id)?.node?.id ?? "";
|
|
1109
1190
|
setEditingId(id);
|
|
1110
1191
|
setDraftLabel(String(currentLabel));
|
|
1111
1192
|
},
|
|
@@ -1138,15 +1219,15 @@ function TreeSelect({
|
|
|
1138
1219
|
if (!item) return null;
|
|
1139
1220
|
if (!renderLabel) return item.node.label ?? item.id;
|
|
1140
1221
|
return renderLabel({
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1222
|
+
...item,
|
|
1223
|
+
isExpanded: expandedIds.has(item.id),
|
|
1224
|
+
isCurrent: currentId != null && normaliseId(currentId) === item.id,
|
|
1225
|
+
isSelected: selectedIds.has(item.id),
|
|
1226
|
+
isFocused: focusWithinId === item.id,
|
|
1227
|
+
getRowElement: () => null
|
|
1147
1228
|
});
|
|
1148
1229
|
},
|
|
1149
|
-
[expandedIds, renderLabel]
|
|
1230
|
+
[currentId, expandedIds, focusWithinId, renderLabel, selectedIds]
|
|
1150
1231
|
);
|
|
1151
1232
|
const indicator = (0, import_react3.useMemo)(() => {
|
|
1152
1233
|
if (!allowDragAndDrop) return null;
|
|
@@ -1169,7 +1250,61 @@ function TreeSelect({
|
|
|
1169
1250
|
visibleItems,
|
|
1170
1251
|
maxDepth
|
|
1171
1252
|
]);
|
|
1172
|
-
|
|
1253
|
+
const rowContext = (item) => ({
|
|
1254
|
+
...item,
|
|
1255
|
+
isExpanded: expandedIds.has(item.id),
|
|
1256
|
+
isCurrent: currentId != null && normaliseId(currentId) === item.id,
|
|
1257
|
+
isSelected: selectedIds.has(item.id),
|
|
1258
|
+
isFocused: focusWithinId === item.id,
|
|
1259
|
+
getRowElement: () => getRowElement(item.id)
|
|
1260
|
+
});
|
|
1261
|
+
const rowAccessibility = (item) => ({
|
|
1262
|
+
role: "treeitem",
|
|
1263
|
+
"aria-label": getTreeItemLabel(item.node, getItemLabel),
|
|
1264
|
+
"aria-level": item.depth + 1,
|
|
1265
|
+
"aria-expanded": item.hasChildren ? expandedIds.has(item.id) : void 0,
|
|
1266
|
+
"aria-selected": allowMultiDrag ? selectedIds.has(item.id) : void 0,
|
|
1267
|
+
"aria-current": currentId != null && normaliseId(currentId) === item.id ? "page" : void 0,
|
|
1268
|
+
"aria-posinset": (siblingOrderMap.get(item.parentId) || []).indexOf(item.id) + 1,
|
|
1269
|
+
"aria-setsize": (siblingOrderMap.get(item.parentId) || []).length,
|
|
1270
|
+
tabIndex: (focusedId && itemById.has(focusedId) ? focusedId : visibleItems[0]?.id) === item.id ? 0 : -1,
|
|
1271
|
+
onFocus: () => {
|
|
1272
|
+
setFocusedId(item.id);
|
|
1273
|
+
setFocusWithinId(item.id);
|
|
1274
|
+
},
|
|
1275
|
+
onBlur: (event) => {
|
|
1276
|
+
if (!event.currentTarget.contains(event.relatedTarget)) setFocusWithinId(null);
|
|
1277
|
+
},
|
|
1278
|
+
onKeyDown: (event) => {
|
|
1279
|
+
if (event.target !== event.currentTarget || event.defaultPrevented) return;
|
|
1280
|
+
if (event.repeat && (event.key === "Enter" || event.key === " ")) {
|
|
1281
|
+
event.preventDefault();
|
|
1282
|
+
return;
|
|
1283
|
+
}
|
|
1284
|
+
const index = visibleItems.findIndex((row) => row.id === item.id);
|
|
1285
|
+
let target;
|
|
1286
|
+
if (event.key === "ArrowDown") target = visibleItems[Math.min(index + 1, visibleItems.length - 1)];
|
|
1287
|
+
if (event.key === "ArrowUp") target = visibleItems[Math.max(index - 1, 0)];
|
|
1288
|
+
if (event.key === "Home") target = visibleItems[0];
|
|
1289
|
+
if (event.key === "End") target = visibleItems[visibleItems.length - 1];
|
|
1290
|
+
if (event.key === "ArrowRight" && item.hasChildren) {
|
|
1291
|
+
if (!expandedIds.has(item.id)) toggleExpanded(item.id);
|
|
1292
|
+
else target = visibleItems[index + 1];
|
|
1293
|
+
}
|
|
1294
|
+
if (event.key === "ArrowLeft") {
|
|
1295
|
+
if (item.hasChildren && expandedIds.has(item.id)) toggleExpanded(item.id);
|
|
1296
|
+
else target = itemById.get(item.parentId);
|
|
1297
|
+
}
|
|
1298
|
+
if (event.key === "F2" && resolvedLevelConfig(item.depth).editable) startEdit(item.id);
|
|
1299
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
1300
|
+
handleRowSelection(event, item.id);
|
|
1301
|
+
activateItem(event, item.id, "keyboard");
|
|
1302
|
+
}
|
|
1303
|
+
if (["ArrowDown", "ArrowUp", "ArrowRight", "ArrowLeft", "Home", "End", "F2", " ", "Enter"].includes(event.key)) event.preventDefault();
|
|
1304
|
+
if (target) getRowElement(target.id)?.focus();
|
|
1305
|
+
}
|
|
1306
|
+
});
|
|
1307
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_tooltips2.TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ...rootProps, "data-data-component": "tree-select", style: { position: "relative", padding: 8, ...rootProps.style }, children: allowDragAndDrop ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1173
1308
|
import_core.DndContext,
|
|
1174
1309
|
{
|
|
1175
1310
|
sensors,
|
|
@@ -1180,24 +1315,24 @@ function TreeSelect({
|
|
|
1180
1315
|
onDragEnd: handleDragEnd,
|
|
1181
1316
|
onDragCancel: handleDragCancel,
|
|
1182
1317
|
children: [
|
|
1183
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sortable2.SortableContext, { items: visibleItems.map((item) => item.id), children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { ref: listRef, style: { position: "relative" }, children: [
|
|
1318
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_sortable2.SortableContext, { items: visibleItems.map((item) => item.id), children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { ref: listRef, role: "tree", "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-multiselectable": allowMultiDrag || void 0, style: { position: "relative" }, children: [
|
|
1184
1319
|
indicator ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1185
1320
|
"div",
|
|
1186
1321
|
{
|
|
1322
|
+
className: "bg-bg-primary-base",
|
|
1187
1323
|
style: {
|
|
1188
1324
|
position: "absolute",
|
|
1189
1325
|
top: indicator.top,
|
|
1190
1326
|
left: indicator.left,
|
|
1191
1327
|
right: 8,
|
|
1192
1328
|
height: 2,
|
|
1193
|
-
background: "#0f62fe",
|
|
1194
1329
|
borderRadius: 999
|
|
1195
1330
|
}
|
|
1196
1331
|
}
|
|
1197
1332
|
) : null,
|
|
1198
1333
|
visibleItems.map((item) => {
|
|
1199
1334
|
const levelSettings = resolvedLevelConfig(item.depth);
|
|
1200
|
-
const additionalActionsMenu = renderAdditionalActionsMenu
|
|
1335
|
+
const additionalActionsMenu = renderAdditionalActionsMenu?.({
|
|
1201
1336
|
id: item.id,
|
|
1202
1337
|
node: item.node,
|
|
1203
1338
|
depth: item.depth,
|
|
@@ -1212,6 +1347,12 @@ function TreeSelect({
|
|
|
1212
1347
|
onToggle: toggleExpanded,
|
|
1213
1348
|
onRowClick: handleRowClick,
|
|
1214
1349
|
rowRefs,
|
|
1350
|
+
onRowSelect: handleRowSelection,
|
|
1351
|
+
rowAccessibility: rowAccessibility(item),
|
|
1352
|
+
labelContext: rowContext(item),
|
|
1353
|
+
accessibleLabel: getTreeItemLabel(item.node, getItemLabel),
|
|
1354
|
+
rowClassName: typeof rowClassName === "function" ? rowClassName(rowContext(item)) : rowClassName,
|
|
1355
|
+
labelClassName: typeof labelClassName === "function" ? labelClassName(rowContext(item)) : labelClassName,
|
|
1215
1356
|
isActive: activeId === item.id,
|
|
1216
1357
|
isSelected: selectedIds.has(item.id),
|
|
1217
1358
|
isGroupDragging: Boolean(
|
|
@@ -1246,20 +1387,15 @@ function TreeSelect({
|
|
|
1246
1387
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_core.DragOverlay, { children: activeId ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1247
1388
|
"div",
|
|
1248
1389
|
{
|
|
1249
|
-
className: "border border-border-subtle bg-bg-base text-fg-base",
|
|
1390
|
+
className: "border border-border-subtle bg-bg-base text-fg-base shadow-lg",
|
|
1250
1391
|
style: {
|
|
1251
1392
|
padding: "6px 8px",
|
|
1252
|
-
borderRadius: 6
|
|
1253
|
-
boxShadow: "0 8px 24px rgba(0, 0, 0, 0.12)"
|
|
1393
|
+
borderRadius: 6
|
|
1254
1394
|
},
|
|
1255
1395
|
children: draggedRootIds.length > 1 ? `${draggedRootIds.length} items` : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1256
1396
|
"span",
|
|
1257
1397
|
{
|
|
1258
|
-
|
|
1259
|
-
display: "inline-flex",
|
|
1260
|
-
alignItems: "center",
|
|
1261
|
-
gap: 6
|
|
1262
|
-
},
|
|
1398
|
+
className: "inline-flex items-center gap-6",
|
|
1263
1399
|
children: renderLabelContent(
|
|
1264
1400
|
visibleItems.find((item) => item.id === activeId)
|
|
1265
1401
|
) ?? activeId
|
|
@@ -1269,9 +1405,9 @@ function TreeSelect({
|
|
|
1269
1405
|
) : null })
|
|
1270
1406
|
]
|
|
1271
1407
|
}
|
|
1272
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref: listRef, style: { position: "relative" }, children: visibleItems.map((item) => {
|
|
1408
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref: listRef, role: "tree", "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-multiselectable": allowMultiDrag || void 0, style: { position: "relative" }, children: visibleItems.map((item) => {
|
|
1273
1409
|
const levelSettings = resolvedLevelConfig(item.depth);
|
|
1274
|
-
const additionalActionsMenu = renderAdditionalActionsMenu
|
|
1410
|
+
const additionalActionsMenu = renderAdditionalActionsMenu?.({
|
|
1275
1411
|
id: item.id,
|
|
1276
1412
|
node: item.node,
|
|
1277
1413
|
depth: item.depth,
|
|
@@ -1286,7 +1422,15 @@ function TreeSelect({
|
|
|
1286
1422
|
isExpanded: expandedIds.has(item.id),
|
|
1287
1423
|
onToggle: toggleExpanded,
|
|
1288
1424
|
onRowClick: handleRowClick,
|
|
1289
|
-
rowRef:
|
|
1425
|
+
rowRef: (row) => {
|
|
1426
|
+
if (row) rowRefs.current.set(item.id, row);
|
|
1427
|
+
else rowRefs.current.delete(item.id);
|
|
1428
|
+
},
|
|
1429
|
+
rowAccessibility: rowAccessibility(item),
|
|
1430
|
+
labelContext: rowContext(item),
|
|
1431
|
+
accessibleLabel: getTreeItemLabel(item.node, getItemLabel),
|
|
1432
|
+
rowClassName: typeof rowClassName === "function" ? rowClassName(rowContext(item)) : rowClassName,
|
|
1433
|
+
labelClassName: typeof labelClassName === "function" ? labelClassName(rowContext(item)) : labelClassName,
|
|
1290
1434
|
isDraggable: false,
|
|
1291
1435
|
isDragging: false,
|
|
1292
1436
|
isSelected: selectedIds.has(item.id),
|
|
@@ -1315,7 +1459,10 @@ function TreeSelect({
|
|
|
1315
1459
|
item.id
|
|
1316
1460
|
);
|
|
1317
1461
|
}) }) }) });
|
|
1318
|
-
}
|
|
1462
|
+
});
|
|
1463
|
+
|
|
1464
|
+
// src/index.ts
|
|
1465
|
+
var TreeSelect3 = TreeSelect;
|
|
1319
1466
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1320
1467
|
0 && (module.exports = {
|
|
1321
1468
|
TreeSelect
|