@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/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,
@@ -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 ? "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;
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
- onClick: (event) => onRowClick == null ? void 0 : onRowClick(event, item.id),
149
+ ...rowAccessibility,
150
+ onClick: (event) => onRowClick?.(event, item.id),
127
151
  "data-tree-row": item.id,
128
- 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(" "),
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": "Drag item",
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 == null ? void 0 : 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
- ...renderLabel ? {
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 == null ? void 0 : onAddChild(item.id)
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 == null ? void 0 : onAddSibling(item.id)
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 == null ? void 0 : onDelete(item.id)
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
- var _a;
368
- (_a = listeners == null ? void 0 : listeners.onPointerDown) == null ? void 0 : _a.call(listeners, event);
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, onRowClick]
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
- var _a, _b;
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 = (_b = itemById.get(parentId)) == null ? void 0 : _b.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
- function TreeSelect({
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
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
825
- const defaults = (levelConfig == null ? void 0 : levelConfig.default) ?? {};
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: ((_b = perLevel.actions) == null ? void 0 : _b.addChild) ?? ((_c = defaults.actions) == null ? void 0 : _c.addChild) ?? editable,
830
- addSibling: ((_d = perLevel.actions) == null ? void 0 : _d.addSibling) ?? ((_e = defaults.actions) == null ? void 0 : _e.addSibling) ?? editable,
831
- 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)
832
908
  };
833
909
  const tooltips = {
834
- addChild: ((_h = perLevel.tooltips) == null ? void 0 : _h.addChild) ?? ((_i = defaults.tooltips) == null ? void 0 : _i.addChild) ?? addChildTooltip,
835
- addSibling: ((_j = perLevel.tooltips) == null ? void 0 : _j.addSibling) ?? ((_k = defaults.tooltips) == null ? void 0 : _k.addSibling) ?? addSiblingTooltip,
836
- 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
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 == null ? void 0 : onExpandedChange(next);
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 == null ? void 0 : onDataChange(nextTree, meta);
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 handleRowClick = (0, import_react3.useCallback)(
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 = ((_a = itemById.get(id)) == null ? void 0 : _a.parentId) ?? null;
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 || (((_b = itemById.get(lastSelectedId ?? "")) == null ? void 0 : _b.parentId) ?? null) !== parentId) {
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 = ((_a2 = itemById.get(firstSelected)) == null ? void 0 : _a2.parentId) ?? null;
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
- var _a;
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 = ((_a = itemById.get(draggedRootIds[0] ?? activeId)) == null ? void 0 : _a.parentId) ?? null;
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
- var _a, _b, _c, _d;
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
- id: item.id,
1142
- node: item.node,
1143
- depth: item.depth,
1144
- parentId: item.parentId,
1145
- hasChildren: item.hasChildren,
1146
- isExpanded: expandedIds.has(item.id)
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
- 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)(
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 == null ? void 0 : 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
- style: {
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 == null ? void 0 : 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: 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,
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