@edux-design/tree-select 0.2.4 → 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/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.js
29
+ // src/index.ts
30
30
  var index_exports = {};
31
31
  __export(index_exports, {
32
- TreeSelect: () => 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,
@@ -87,13 +109,23 @@ var TreeRow = ({
87
109
  canDelete,
88
110
  onDelete,
89
111
  deleteTooltip,
90
- additionalActionsMenu
112
+ additionalActionsMenu,
113
+ renderLabel
91
114
  }) => {
92
115
  const toggleLabel = isExpanded ? "Collapse item" : "Expand item";
93
116
  const label = item.node.label ?? item.node.id;
117
+ const labelContent = renderLabel ? renderLabel({
118
+ id: item.id,
119
+ node: item.node,
120
+ depth,
121
+ parentId: item.parentId,
122
+ hasChildren: item.hasChildren,
123
+ isExpanded,
124
+ ...labelContext
125
+ }) : label;
94
126
  const showToggle = item.hasChildren;
95
127
  const [additionalMenuOpen, setAdditionalMenuOpen] = import_react.default.useState(false);
96
- const rowBackground = isDragging ? "rgba(0, 0, 0, 0.04)" : isSelected ? "rgba(15, 98, 254, 0.08)" : void 0;
128
+ const rowBackground = isDragging ? DRAG_ROW_BACKGROUND : isSelected ? SELECTED_ROW_BACKGROUND : void 0;
97
129
  const rowPaddingLeft = depth * INDENT_WIDTH + 8;
98
130
  const hasAdditionalActionsMenu = Boolean(additionalActionsMenu);
99
131
  const showActions = canAddChild || canAddSibling || canDelete || hasAdditionalActionsMenu;
@@ -114,9 +146,12 @@ var TreeRow = ({
114
146
  "div",
115
147
  {
116
148
  ref: rowRef,
117
- onClick: (event) => onRowClick == null ? void 0 : onRowClick(event, item.id),
149
+ ...rowAccessibility,
150
+ onClick: (event) => onRowClick?.(event, item.id),
118
151
  "data-tree-row": item.id,
119
- className: "transition-colors hover:bg-bg-primary-subtle",
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(" "),
120
155
  style: {
121
156
  display: "flex",
122
157
  alignItems: "center",
@@ -135,7 +170,7 @@ var TreeRow = ({
135
170
  ...dragAttributes,
136
171
  ...dragHandleProps,
137
172
  ref: dragRef,
138
- "aria-label": "Drag item",
173
+ "aria-label": `Move ${accessibleLabel}`,
139
174
  onClick: (event) => event.stopPropagation(),
140
175
  className: "border border-border-subtle bg-bg-base text-fg-base",
141
176
  style: {
@@ -155,7 +190,8 @@ var TreeRow = ({
155
190
  "button",
156
191
  {
157
192
  type: "button",
158
- "aria-label": toggleLabel,
193
+ "aria-label": `${toggleLabel}: ${accessibleLabel}`,
194
+ "aria-expanded": isExpanded,
159
195
  onClick: () => onToggle(item.id),
160
196
  style: {
161
197
  width: 24,
@@ -177,6 +213,8 @@ var TreeRow = ({
177
213
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
178
214
  import_forms.Checkbox,
179
215
  {
216
+ "aria-label": `${toggleLabel}: ${accessibleLabel}`,
217
+ "aria-expanded": isExpanded,
180
218
  checked: false,
181
219
  plus: !isExpanded,
182
220
  indeterminate: isExpanded,
@@ -188,19 +226,21 @@ var TreeRow = ({
188
226
  "input",
189
227
  {
190
228
  type: "text",
229
+ "aria-label": `Edit ${accessibleLabel}`,
230
+ onClick: (event) => event.stopPropagation(),
191
231
  value: draftLabel,
192
232
  autoFocus: true,
193
233
  "data-tree-input": item.id,
194
234
  onChange: (event) => onDraftChange(event.target.value),
195
235
  onBlur: onCommitEdit,
196
236
  onKeyDown: (event) => {
237
+ event.stopPropagation();
197
238
  if (event.key === "Enter") onCommitEdit();
198
239
  if (event.key === "Escape") onCancelEdit();
199
240
  },
200
241
  style: {
201
242
  fontSize: 14,
202
243
  border: "none",
203
- outline: "none",
204
244
  background: "transparent",
205
245
  padding: 0
206
246
  }
@@ -209,17 +249,32 @@ var TreeRow = ({
209
249
  "span",
210
250
  {
211
251
  onClick: (event) => {
212
- if (!isEditable) return;
252
+ if (!isEditable || event.defaultPrevented || isTreeRowControl(event)) return;
213
253
  event.stopPropagation();
214
- onStartEdit == null ? void 0 : onStartEdit();
254
+ onStartEdit?.();
215
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,
216
267
  "data-tree-label": item.id,
268
+ className: [renderLabel ? "inline-flex items-center gap-6" : "", labelClassName].filter(Boolean).join(" "),
217
269
  style: {
218
270
  fontSize: 14,
271
+ display: "inline-flex",
272
+ alignItems: "center",
273
+ minHeight: isEditable ? 24 : void 0,
219
274
  cursor: isEditable ? "pointer" : "default",
220
- ...labelStyle
275
+ ...!renderLabel ? labelStyle : {}
221
276
  },
222
- children: label
277
+ children: labelContent
223
278
  }
224
279
  ),
225
280
  showActions ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
@@ -237,7 +292,7 @@ var TreeRow = ({
237
292
  isBare: true,
238
293
  icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.Plus, { "aria-hidden": "true" }),
239
294
  "aria-label": "Add child",
240
- onClick: () => onAddChild == null ? void 0 : onAddChild(item.id)
295
+ onClick: () => onAddChild?.(item.id)
241
296
  }
242
297
  ) }),
243
298
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tooltips.TooltipContent, { children: addChildTooltip ?? "Add child" })
@@ -250,7 +305,7 @@ var TreeRow = ({
250
305
  isBare: true,
251
306
  icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.List, { "aria-hidden": "true" }),
252
307
  "aria-label": "Add sibling",
253
- onClick: () => onAddSibling == null ? void 0 : onAddSibling(item.id)
308
+ onClick: () => onAddSibling?.(item.id)
254
309
  }
255
310
  ) }),
256
311
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tooltips.TooltipContent, { children: addSiblingTooltip ?? "Add sibling" })
@@ -263,7 +318,7 @@ var TreeRow = ({
263
318
  isBare: true,
264
319
  icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.Close, { "aria-hidden": "true" }),
265
320
  "aria-label": "Delete item",
266
- onClick: () => onDelete == null ? void 0 : onDelete(item.id)
321
+ onClick: () => onDelete?.(item.id)
267
322
  }
268
323
  ) }),
269
324
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tooltips.TooltipContent, { children: deleteTooltip ?? "Delete item" })
@@ -304,6 +359,12 @@ var TreeSortableRow = ({
304
359
  onToggle,
305
360
  onRowClick,
306
361
  rowRefs,
362
+ rowAccessibility,
363
+ labelContext,
364
+ accessibleLabel,
365
+ rowClassName,
366
+ labelClassName,
367
+ onRowSelect,
307
368
  isActive,
308
369
  isSelected,
309
370
  isGroupDragging,
@@ -326,7 +387,8 @@ var TreeSortableRow = ({
326
387
  canDelete,
327
388
  onDelete,
328
389
  deleteTooltip,
329
- additionalActionsMenu
390
+ additionalActionsMenu,
391
+ renderLabel
330
392
  }) => {
331
393
  const {
332
394
  attributes,
@@ -350,12 +412,11 @@ var TreeSortableRow = ({
350
412
  () => ({
351
413
  ...listeners,
352
414
  onPointerDown: (event) => {
353
- var _a;
354
- (_a = listeners == null ? void 0 : listeners.onPointerDown) == null ? void 0 : _a.call(listeners, event);
355
- onRowClick == null ? void 0 : onRowClick(event, item.id);
415
+ listeners?.onPointerDown?.(event);
416
+ onRowSelect?.(event, item.id);
356
417
  }
357
418
  }),
358
- [item.id, listeners, onRowClick]
419
+ [item.id, listeners, onRowSelect]
359
420
  );
360
421
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
361
422
  TreeRow,
@@ -369,6 +430,11 @@ var TreeSortableRow = ({
369
430
  dragAttributes: attributes,
370
431
  dragRef: setActivatorNodeRef,
371
432
  rowRef: rowRefCallback,
433
+ rowAccessibility,
434
+ labelContext,
435
+ accessibleLabel,
436
+ rowClassName,
437
+ labelClassName,
372
438
  isDragging: isDragging || isActive || isGroupDragging,
373
439
  isSelected,
374
440
  isEditable,
@@ -390,7 +456,8 @@ var TreeSortableRow = ({
390
456
  canDelete,
391
457
  onDelete,
392
458
  deleteTooltip,
393
- additionalActionsMenu
459
+ additionalActionsMenu,
460
+ renderLabel
394
461
  }
395
462
  );
396
463
  };
@@ -442,11 +509,10 @@ var collectDraggedIds = (items, rootIds) => {
442
509
  var getSelectedRootIds = (items, selectedIds) => {
443
510
  const itemById = new Map(items.map((item) => [item.id, item]));
444
511
  return items.filter((item) => selectedIds.has(item.id)).filter((item) => {
445
- var _a, _b;
446
- let parentId = (_a = itemById.get(item.id)) == null ? void 0 : _a.parentId;
512
+ let parentId = itemById.get(item.id)?.parentId;
447
513
  while (parentId) {
448
514
  if (selectedIds.has(parentId)) return false;
449
- parentId = (_b = itemById.get(parentId)) == null ? void 0 : _b.parentId;
515
+ parentId = itemById.get(parentId)?.parentId;
450
516
  }
451
517
  return true;
452
518
  }).map((item) => item.id);
@@ -746,7 +812,7 @@ var getDropIndicator = ({
746
812
 
747
813
  // src/elements/TreeSelect.jsx
748
814
  var import_jsx_runtime3 = require("react/jsx-runtime");
749
- function TreeSelect({
815
+ var TreeSelect = (0, import_react3.forwardRef)(function TreeSelect2({
750
816
  data,
751
817
  onDataChange,
752
818
  allowDragAndDrop = false,
@@ -765,9 +831,17 @@ function TreeSelect({
765
831
  defaultExpanded,
766
832
  expanded,
767
833
  onExpandedChange,
768
- renderAdditionalActionsMenu
769
- }) {
770
- var _a, _b;
834
+ renderAdditionalActionsMenu,
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) {
771
845
  const [uncontrolledExpandedIds, setExpandedIds] = (0, import_react3.useState)(
772
846
  () => getExpandedIds(data ?? [], defaultExpanded)
773
847
  );
@@ -777,6 +851,8 @@ function TreeSelect({
777
851
  const [horizontalOffset, setHorizontalOffset] = (0, import_react3.useState)(0);
778
852
  const [selectedIds, setSelectedIds] = (0, import_react3.useState)(() => /* @__PURE__ */ new Set());
779
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);
780
856
  const [editingId, setEditingId] = (0, import_react3.useState)(null);
781
857
  const [draftLabel, setDraftLabel] = (0, import_react3.useState)("");
782
858
  const idCounterRef = (0, import_react3.useRef)(0);
@@ -796,6 +872,22 @@ function TreeSelect({
796
872
  () => new Map(visibleItems.map((item) => [item.id, item])),
797
873
  [visibleItems]
798
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]);
799
891
  const siblingOrderMap = (0, import_react3.useMemo)(
800
892
  () => buildSiblingOrderMap(treeData),
801
893
  [treeData]
@@ -806,19 +898,18 @@ function TreeSelect({
806
898
  }, [maxDepth]);
807
899
  const resolvedLevelConfig = (0, import_react3.useCallback)(
808
900
  (depth) => {
809
- var _a2, _b2, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
810
- const defaults = (levelConfig == null ? void 0 : levelConfig.default) ?? {};
811
- const perLevel = ((_a2 = levelConfig == null ? void 0 : levelConfig.levels) == null ? void 0 : _a2[depth]) ?? {};
901
+ const defaults = levelConfig?.default ?? {};
902
+ const perLevel = levelConfig?.levels?.[depth] ?? {};
812
903
  const editable = perLevel.editable ?? defaults.editable ?? isEditable;
813
904
  const actions = {
814
- addChild: ((_b2 = perLevel.actions) == null ? void 0 : _b2.addChild) ?? ((_c = defaults.actions) == null ? void 0 : _c.addChild) ?? editable,
815
- addSibling: ((_d = perLevel.actions) == null ? void 0 : _d.addSibling) ?? ((_e = defaults.actions) == null ? void 0 : _e.addSibling) ?? editable,
816
- delete: ((_f = perLevel.actions) == null ? void 0 : _f.delete) ?? ((_g = defaults.actions) == null ? void 0 : _g.delete) ?? (editable && allowDelete)
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)
817
908
  };
818
909
  const tooltips = {
819
- addChild: ((_h = perLevel.tooltips) == null ? void 0 : _h.addChild) ?? ((_i = defaults.tooltips) == null ? void 0 : _i.addChild) ?? addChildTooltip,
820
- addSibling: ((_j = perLevel.tooltips) == null ? void 0 : _j.addSibling) ?? ((_k = defaults.tooltips) == null ? void 0 : _k.addSibling) ?? addSiblingTooltip,
821
- delete: ((_l = perLevel.tooltips) == null ? void 0 : _l.delete) ?? ((_m = defaults.tooltips) == null ? void 0 : _m.delete) ?? deleteTooltip
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
822
913
  };
823
914
  return { editable, actions, tooltips };
824
915
  },
@@ -838,7 +929,7 @@ function TreeSelect({
838
929
  (updater) => {
839
930
  if (isExpandedControlled) {
840
931
  const next = updater(new Set(expandedIds));
841
- onExpandedChange == null ? void 0 : onExpandedChange(next);
932
+ onExpandedChange?.(next);
842
933
  return;
843
934
  }
844
935
  setExpandedIds((prev) => updater(new Set(prev)));
@@ -847,7 +938,7 @@ function TreeSelect({
847
938
  );
848
939
  const emitDataChange = (0, import_react3.useCallback)(
849
940
  (nextTree, meta) => {
850
- onDataChange == null ? void 0 : onDataChange(nextTree, meta);
941
+ onDataChange?.(nextTree, meta);
851
942
  },
852
943
  [onDataChange]
853
944
  );
@@ -861,17 +952,16 @@ function TreeSelect({
861
952
  return prev;
862
953
  });
863
954
  }, [updateExpandedIds]);
864
- const handleRowClick = (0, import_react3.useCallback)(
955
+ const handleRowSelection = (0, import_react3.useCallback)(
865
956
  (event, id) => {
866
- var _a2, _b2;
867
957
  if (!allowMultiDrag) return;
868
958
  const hasMultiKey = event.metaKey || event.ctrlKey;
869
- const parentId = ((_a2 = itemById.get(id)) == null ? void 0 : _a2.parentId) ?? null;
959
+ const parentId = itemById.get(id)?.parentId ?? null;
870
960
  const siblingOrder = siblingOrderMap.get(parentId) ?? [];
871
961
  if (event.shiftKey) {
872
962
  const anchorIndex = siblingOrder.indexOf(lastSelectedId);
873
963
  const targetIndex = siblingOrder.indexOf(id);
874
- if (anchorIndex < 0 || targetIndex < 0 || (((_b2 = itemById.get(lastSelectedId ?? "")) == null ? void 0 : _b2.parentId) ?? null) !== parentId) {
964
+ if (anchorIndex < 0 || targetIndex < 0 || (itemById.get(lastSelectedId ?? "")?.parentId ?? null) !== parentId) {
875
965
  setSelectedIds(/* @__PURE__ */ new Set([id]));
876
966
  setLastSelectedId(id);
877
967
  return;
@@ -893,10 +983,9 @@ function TreeSelect({
893
983
  return;
894
984
  }
895
985
  setSelectedIds((prev) => {
896
- var _a3;
897
986
  if (prev.size) {
898
987
  const firstSelected = prev.values().next().value;
899
- const selectedParent = ((_a3 = itemById.get(firstSelected)) == null ? void 0 : _a3.parentId) ?? null;
988
+ const selectedParent = itemById.get(firstSelected)?.parentId ?? null;
900
989
  if (selectedParent !== parentId) {
901
990
  return /* @__PURE__ */ new Set([id]);
902
991
  }
@@ -923,6 +1012,16 @@ function TreeSelect({
923
1012
  siblingOrderMap
924
1013
  ]
925
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]);
926
1025
  const draggedRootIds = (0, import_react3.useMemo)(
927
1026
  () => getDraggedRootIds({
928
1027
  activeId,
@@ -954,13 +1053,11 @@ function TreeSelect({
954
1053
  setHorizontalOffset(event.delta.x);
955
1054
  }, []);
956
1055
  const handleDragOver = (0, import_react3.useCallback)((event) => {
957
- var _a2;
958
- if ((_a2 = event.over) == null ? void 0 : _a2.id) {
1056
+ if (event.over?.id) {
959
1057
  setOverId(normaliseId(event.over.id));
960
1058
  }
961
1059
  }, []);
962
1060
  const handleDragEnd = (0, import_react3.useCallback)(() => {
963
- var _a2;
964
1061
  const projection = getDropProjection({
965
1062
  items: visibleItems,
966
1063
  activeId,
@@ -976,7 +1073,7 @@ function TreeSelect({
976
1073
  return;
977
1074
  }
978
1075
  const { parentId, siblingIndex, projectedDepth } = projection;
979
- const sourceParentId = ((_a2 = itemById.get(draggedRootIds[0] ?? activeId)) == null ? void 0 : _a2.parentId) ?? null;
1076
+ const sourceParentId = itemById.get(draggedRootIds[0] ?? activeId)?.parentId ?? null;
980
1077
  const { nextNodes, removedNodes } = removeNodes(treeData, draggedRootIds);
981
1078
  if (!removedNodes.length) {
982
1079
  setActiveId(null);
@@ -1089,8 +1186,7 @@ function TreeSelect({
1089
1186
  );
1090
1187
  const startEdit = (0, import_react3.useCallback)(
1091
1188
  (id) => {
1092
- var _a2, _b2, _c, _d;
1093
- const currentLabel = ((_b2 = (_a2 = itemById.get(id)) == null ? void 0 : _a2.node) == null ? void 0 : _b2.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 ?? "";
1094
1190
  setEditingId(id);
1095
1191
  setDraftLabel(String(currentLabel));
1096
1192
  },
@@ -1118,6 +1214,21 @@ function TreeSelect({
1118
1214
  const cancelEdit = (0, import_react3.useCallback)(() => {
1119
1215
  setEditingId(null);
1120
1216
  }, []);
1217
+ const renderLabelContent = (0, import_react3.useCallback)(
1218
+ (item) => {
1219
+ if (!item) return null;
1220
+ if (!renderLabel) return item.node.label ?? item.id;
1221
+ return renderLabel({
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
1228
+ });
1229
+ },
1230
+ [currentId, expandedIds, focusWithinId, renderLabel, selectedIds]
1231
+ );
1121
1232
  const indicator = (0, import_react3.useMemo)(() => {
1122
1233
  if (!allowDragAndDrop) return null;
1123
1234
  return getDropIndicator({
@@ -1139,7 +1250,61 @@ function TreeSelect({
1139
1250
  visibleItems,
1140
1251
  maxDepth
1141
1252
  ]);
1142
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_tooltips2.TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { position: "relative", padding: 8 }, children: allowDragAndDrop ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
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)(
1143
1308
  import_core.DndContext,
1144
1309
  {
1145
1310
  sensors,
@@ -1150,24 +1315,24 @@ function TreeSelect({
1150
1315
  onDragEnd: handleDragEnd,
1151
1316
  onDragCancel: handleDragCancel,
1152
1317
  children: [
1153
- /* @__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: [
1154
1319
  indicator ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1155
1320
  "div",
1156
1321
  {
1322
+ className: "bg-bg-primary-base",
1157
1323
  style: {
1158
1324
  position: "absolute",
1159
1325
  top: indicator.top,
1160
1326
  left: indicator.left,
1161
1327
  right: 8,
1162
1328
  height: 2,
1163
- background: "#0f62fe",
1164
1329
  borderRadius: 999
1165
1330
  }
1166
1331
  }
1167
1332
  ) : null,
1168
1333
  visibleItems.map((item) => {
1169
1334
  const levelSettings = resolvedLevelConfig(item.depth);
1170
- const additionalActionsMenu = renderAdditionalActionsMenu == null ? void 0 : renderAdditionalActionsMenu({
1335
+ const additionalActionsMenu = renderAdditionalActionsMenu?.({
1171
1336
  id: item.id,
1172
1337
  node: item.node,
1173
1338
  depth: item.depth,
@@ -1182,6 +1347,12 @@ function TreeSelect({
1182
1347
  onToggle: toggleExpanded,
1183
1348
  onRowClick: handleRowClick,
1184
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,
1185
1356
  isActive: activeId === item.id,
1186
1357
  isSelected: selectedIds.has(item.id),
1187
1358
  isGroupDragging: Boolean(
@@ -1206,7 +1377,8 @@ function TreeSelect({
1206
1377
  canDelete: levelSettings.actions.delete,
1207
1378
  onDelete: handleDelete,
1208
1379
  deleteTooltip: levelSettings.tooltips.delete,
1209
- additionalActionsMenu
1380
+ additionalActionsMenu,
1381
+ renderLabel
1210
1382
  },
1211
1383
  item.id
1212
1384
  );
@@ -1215,20 +1387,27 @@ function TreeSelect({
1215
1387
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_core.DragOverlay, { children: activeId ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1216
1388
  "div",
1217
1389
  {
1218
- 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",
1219
1391
  style: {
1220
1392
  padding: "6px 8px",
1221
- borderRadius: 6,
1222
- boxShadow: "0 8px 24px rgba(0, 0, 0, 0.12)"
1393
+ borderRadius: 6
1223
1394
  },
1224
- children: draggedRootIds.length > 1 ? `${draggedRootIds.length} items` : ((_b = (_a = visibleItems.find((item) => item.id === activeId)) == null ? void 0 : _a.node) == null ? void 0 : _b.label) ?? activeId
1395
+ children: draggedRootIds.length > 1 ? `${draggedRootIds.length} items` : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1396
+ "span",
1397
+ {
1398
+ className: "inline-flex items-center gap-6",
1399
+ children: renderLabelContent(
1400
+ visibleItems.find((item) => item.id === activeId)
1401
+ ) ?? activeId
1402
+ }
1403
+ )
1225
1404
  }
1226
1405
  ) : null })
1227
1406
  ]
1228
1407
  }
1229
- ) : /* @__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) => {
1230
1409
  const levelSettings = resolvedLevelConfig(item.depth);
1231
- const additionalActionsMenu = renderAdditionalActionsMenu == null ? void 0 : renderAdditionalActionsMenu({
1410
+ const additionalActionsMenu = renderAdditionalActionsMenu?.({
1232
1411
  id: item.id,
1233
1412
  node: item.node,
1234
1413
  depth: item.depth,
@@ -1243,7 +1422,15 @@ function TreeSelect({
1243
1422
  isExpanded: expandedIds.has(item.id),
1244
1423
  onToggle: toggleExpanded,
1245
1424
  onRowClick: handleRowClick,
1246
- rowRef: void 0,
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,
1247
1434
  isDraggable: false,
1248
1435
  isDragging: false,
1249
1436
  isSelected: selectedIds.has(item.id),
@@ -1266,12 +1453,16 @@ function TreeSelect({
1266
1453
  canDelete: levelSettings.actions.delete,
1267
1454
  onDelete: handleDelete,
1268
1455
  deleteTooltip: levelSettings.tooltips.delete,
1269
- additionalActionsMenu
1456
+ additionalActionsMenu,
1457
+ renderLabel
1270
1458
  },
1271
1459
  item.id
1272
1460
  );
1273
1461
  }) }) }) });
1274
- }
1462
+ });
1463
+
1464
+ // src/index.ts
1465
+ var TreeSelect3 = TreeSelect;
1275
1466
  // Annotate the CommonJS export names for ESM import in node:
1276
1467
  0 && (module.exports = {
1277
1468
  TreeSelect