@edux-design/tree-select 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -134,18 +134,42 @@ Allows multi-select drag using CMD/CTRL or SHIFT. Selection is restricted to adj
134
134
  ### `isEditable` (boolean, default `false`)
135
135
  Enables inline label editing and add-item controls.
136
136
 
137
+ ### `allowDelete` (boolean, default `false`)
138
+ Shows a delete action for each item and removes the node (plus descendants).
139
+
137
140
  ### `useChevron` (boolean, default `false`)
138
141
  Uses a chevron control for expand/collapse instead of the checkbox toggle.
139
142
 
143
+ ### `defaultExpanded` (`"all"` | number | string[] | Set<string | number>)
144
+ Defines the initial expansion state. Use `"all"` to expand every node with children, a number to expand up to that level (1 expands top-level nodes), or an array/set of ids to expand specific items.
145
+
146
+ ### `expanded` (`"all"` | number | string[] | Set<string | number>)
147
+ Controlled expansion state. When provided, the tree expansion is driven by this value.
148
+
149
+ ### `onExpandedChange` (function)
150
+ Called with a `Set` of expanded ids when the user toggles expansion in controlled mode.
151
+
140
152
  ### `maxDepth` (number)
141
153
  Limits how deep new items can be added. For example, `maxDepth={3}` allows at most 3 levels.
142
154
 
143
155
  ### `addChildTooltip` (string)
144
156
  Tooltip copy for the add-child button.
145
157
 
158
+ ### `addChildTooltipByLevel` (string[])
159
+ Tooltip copy for add-child, keyed by depth. Overrides `addChildTooltip` when provided.
160
+
146
161
  ### `addSiblingTooltip` (string)
147
162
  Tooltip copy for the add-sibling button.
148
163
 
164
+ ### `addSiblingTooltipByLevel` (string[])
165
+ Tooltip copy for add-sibling, keyed by depth. Overrides `addSiblingTooltip` when provided.
166
+
167
+ ### `deleteTooltip` (string)
168
+ Tooltip copy for the delete button.
169
+
170
+ ### `deleteTooltipByLevel` (string[])
171
+ Tooltip copy for delete, keyed by depth. Overrides `deleteTooltip` when provided.
172
+
149
173
  ---
150
174
 
151
175
  ## Behaviour details
@@ -154,6 +178,9 @@ Tooltip copy for the add-sibling button.
154
178
  - Leaf nodes do not render a checkbox/chevron toggle.
155
179
  - Expansion only controls visibility of children.
156
180
  - When `useChevron` is `false`, the toggle uses the Checkbox plus/indeterminate states.
181
+ - `defaultExpanded` only seeds the initial state; use `expanded` for controlled expansion.
182
+ - When `expanded` is provided, `onExpandedChange` is called with the next set of expanded ids.
183
+ - Deleting a node removes the entire subtree and clears any selected/expanded state for those ids.
157
184
  - Drag-and-drop supports reordering within a level and moving items between levels.
158
185
  - Drag handle alignment is set so child handles align under the parent toggle.
159
186
 
package/dist/index.d.mts CHANGED
@@ -1,15 +1,23 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
 
3
- declare function TreeSelect({ data, onDataChange, allowDragAndDrop, allowMultiDrag, isEditable, useChevron, maxDepth, addChildTooltip, addSiblingTooltip, }: {
3
+ declare function TreeSelect({ data, onDataChange, allowDragAndDrop, allowMultiDrag, isEditable, allowDelete, useChevron, maxDepth, addChildTooltip, addSiblingTooltip, deleteTooltip, addChildTooltipByLevel, addSiblingTooltipByLevel, deleteTooltipByLevel, defaultExpanded, expanded, onExpandedChange, }: {
4
4
  data: any;
5
5
  onDataChange: any;
6
6
  allowDragAndDrop?: boolean;
7
7
  allowMultiDrag?: boolean;
8
8
  isEditable?: boolean;
9
+ allowDelete?: boolean;
9
10
  useChevron?: boolean;
10
11
  maxDepth: any;
11
12
  addChildTooltip: any;
12
13
  addSiblingTooltip: any;
14
+ deleteTooltip: any;
15
+ addChildTooltipByLevel: any;
16
+ addSiblingTooltipByLevel: any;
17
+ deleteTooltipByLevel: any;
18
+ defaultExpanded: any;
19
+ expanded: any;
20
+ onExpandedChange: any;
13
21
  }): react_jsx_runtime.JSX.Element;
14
22
 
15
23
  export { TreeSelect };
package/dist/index.d.ts CHANGED
@@ -1,15 +1,23 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
 
3
- declare function TreeSelect({ data, onDataChange, allowDragAndDrop, allowMultiDrag, isEditable, useChevron, maxDepth, addChildTooltip, addSiblingTooltip, }: {
3
+ declare function TreeSelect({ data, onDataChange, allowDragAndDrop, allowMultiDrag, isEditable, allowDelete, useChevron, maxDepth, addChildTooltip, addSiblingTooltip, deleteTooltip, addChildTooltipByLevel, addSiblingTooltipByLevel, deleteTooltipByLevel, defaultExpanded, expanded, onExpandedChange, }: {
4
4
  data: any;
5
5
  onDataChange: any;
6
6
  allowDragAndDrop?: boolean;
7
7
  allowMultiDrag?: boolean;
8
8
  isEditable?: boolean;
9
+ allowDelete?: boolean;
9
10
  useChevron?: boolean;
10
11
  maxDepth: any;
11
12
  addChildTooltip: any;
12
13
  addSiblingTooltip: any;
14
+ deleteTooltip: any;
15
+ addChildTooltipByLevel: any;
16
+ addSiblingTooltipByLevel: any;
17
+ deleteTooltipByLevel: any;
18
+ defaultExpanded: any;
19
+ expanded: any;
20
+ onExpandedChange: any;
13
21
  }): react_jsx_runtime.JSX.Element;
14
22
 
15
23
  export { TreeSelect };
package/dist/index.js CHANGED
@@ -5764,13 +5764,17 @@ var TreeRow = ({
5764
5764
  onAddChild,
5765
5765
  onAddSibling,
5766
5766
  addChildTooltip,
5767
- addSiblingTooltip
5767
+ addSiblingTooltip,
5768
+ canDelete,
5769
+ onDelete,
5770
+ deleteTooltip
5768
5771
  }) => {
5769
5772
  const toggleLabel = isExpanded ? "Collapse item" : "Expand item";
5770
5773
  const label = item.node.label ?? item.node.id;
5771
5774
  const showToggle = item.hasChildren;
5772
5775
  const rowBackground = isDragging ? "rgba(0, 0, 0, 0.04)" : isSelected ? "rgba(15, 98, 254, 0.08)" : void 0;
5773
5776
  const rowPaddingLeft = depth * INDENT_WIDTH + 8 + (isDraggable ? 0 : HANDLE_WIDTH + 8);
5777
+ const showActions = canAddChild || canAddSibling || canDelete;
5774
5778
  return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
5775
5779
  "div",
5776
5780
  {
@@ -5883,7 +5887,7 @@ var TreeRow = ({
5883
5887
  children: label
5884
5888
  }
5885
5889
  ),
5886
- canAddChild || canAddSibling ? /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
5890
+ showActions ? /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
5887
5891
  "div",
5888
5892
  {
5889
5893
  onClick: (event) => event.stopPropagation(),
@@ -5914,6 +5918,19 @@ var TreeRow = ({
5914
5918
  }
5915
5919
  ) }),
5916
5920
  /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(TooltipContent2, { children: addSiblingTooltip ?? "Add sibling" })
5921
+ ] }) : null,
5922
+ canDelete ? /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(Tooltip2, { children: [
5923
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(TooltipTrigger2, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
5924
+ IconButton,
5925
+ {
5926
+ size: "small",
5927
+ isBare: true,
5928
+ icon: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(import_icons.Close, { "aria-hidden": "true" }),
5929
+ "aria-label": "Delete item",
5930
+ onClick: () => onDelete == null ? void 0 : onDelete(item.id)
5931
+ }
5932
+ ) }),
5933
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(TooltipContent2, { children: deleteTooltip ?? "Delete item" })
5917
5934
  ] }) : null
5918
5935
  ]
5919
5936
  }
@@ -5949,7 +5966,10 @@ var TreeSortableRow = ({
5949
5966
  onAddChild,
5950
5967
  onAddSibling,
5951
5968
  addChildTooltip,
5952
- addSiblingTooltip
5969
+ addSiblingTooltip,
5970
+ canDelete,
5971
+ onDelete,
5972
+ deleteTooltip
5953
5973
  }) => {
5954
5974
  const {
5955
5975
  attributes,
@@ -6007,7 +6027,10 @@ var TreeSortableRow = ({
6007
6027
  onAddChild,
6008
6028
  onAddSibling,
6009
6029
  addChildTooltip,
6010
- addSiblingTooltip
6030
+ addSiblingTooltip,
6031
+ canDelete,
6032
+ onDelete,
6033
+ deleteTooltip
6011
6034
  }
6012
6035
  );
6013
6036
  };
@@ -6190,6 +6213,53 @@ var addSiblingNode = (nodes, targetId, newNode) => {
6190
6213
  });
6191
6214
  return { nextNodes, inserted };
6192
6215
  };
6216
+ var collectNodeIds = (node, ids = /* @__PURE__ */ new Set()) => {
6217
+ if (!node) return ids;
6218
+ ids.add(normaliseId(node.id));
6219
+ if (hasChildren(node)) {
6220
+ node.children.forEach((child) => collectNodeIds(child, ids));
6221
+ }
6222
+ return ids;
6223
+ };
6224
+ var collectExpandableIds = (nodes, ids = /* @__PURE__ */ new Set()) => {
6225
+ nodes.forEach((node) => {
6226
+ if (!hasChildren(node)) return;
6227
+ const nodeId = normaliseId(node.id);
6228
+ ids.add(nodeId);
6229
+ collectExpandableIds(node.children, ids);
6230
+ });
6231
+ return ids;
6232
+ };
6233
+ var collectExpandedIdsByLevel = (nodes, level, depth = 0, ids = /* @__PURE__ */ new Set()) => {
6234
+ if (level <= 0) return ids;
6235
+ nodes.forEach((node) => {
6236
+ if (!hasChildren(node)) return;
6237
+ if (depth < level) {
6238
+ ids.add(normaliseId(node.id));
6239
+ }
6240
+ if (depth + 1 < level) {
6241
+ collectExpandedIdsByLevel(node.children, level, depth + 1, ids);
6242
+ }
6243
+ });
6244
+ return ids;
6245
+ };
6246
+ var getExpandedIds = (nodes, expanded) => {
6247
+ if (!expanded) return /* @__PURE__ */ new Set();
6248
+ if (expanded === true || expanded === "all") {
6249
+ return collectExpandableIds(nodes);
6250
+ }
6251
+ if (typeof expanded === "number" && Number.isFinite(expanded)) {
6252
+ const level = Math.max(Math.floor(expanded), 0);
6253
+ return collectExpandedIdsByLevel(nodes, level);
6254
+ }
6255
+ if (expanded instanceof Set) {
6256
+ return new Set(Array.from(expanded, normaliseId));
6257
+ }
6258
+ if (Array.isArray(expanded)) {
6259
+ return new Set(expanded.map(normaliseId));
6260
+ }
6261
+ return /* @__PURE__ */ new Set();
6262
+ };
6193
6263
 
6194
6264
  // src/elements/treeSelectDrag.js
6195
6265
  var clamp2 = (value, min2, max2) => Math.min(Math.max(value, min2), max2);
@@ -6322,13 +6392,24 @@ function TreeSelect({
6322
6392
  allowDragAndDrop = false,
6323
6393
  allowMultiDrag = false,
6324
6394
  isEditable = false,
6395
+ allowDelete = false,
6325
6396
  useChevron = false,
6326
6397
  maxDepth,
6327
6398
  addChildTooltip,
6328
- addSiblingTooltip
6399
+ addSiblingTooltip,
6400
+ deleteTooltip,
6401
+ addChildTooltipByLevel,
6402
+ addSiblingTooltipByLevel,
6403
+ deleteTooltipByLevel,
6404
+ defaultExpanded,
6405
+ expanded,
6406
+ onExpandedChange
6329
6407
  }) {
6330
6408
  var _a, _b;
6331
- const [expandedIds, setExpandedIds] = (0, import_react11.useState)(() => /* @__PURE__ */ new Set());
6409
+ const [uncontrolledExpandedIds, setExpandedIds] = (0, import_react11.useState)(
6410
+ () => getExpandedIds(data ?? [], defaultExpanded)
6411
+ );
6412
+ const isExpandedControlled = expanded !== void 0;
6332
6413
  const [activeId, setActiveId] = (0, import_react11.useState)(null);
6333
6414
  const [overId, setOverId] = (0, import_react11.useState)(null);
6334
6415
  const [horizontalOffset, setHorizontalOffset] = (0, import_react11.useState)(0);
@@ -6338,6 +6419,11 @@ function TreeSelect({
6338
6419
  const [draftLabel, setDraftLabel] = (0, import_react11.useState)("");
6339
6420
  const idCounterRef = (0, import_react11.useRef)(0);
6340
6421
  const treeData = data ?? [];
6422
+ const controlledExpandedIds = (0, import_react11.useMemo)(
6423
+ () => getExpandedIds(treeData, expanded),
6424
+ [expanded, treeData]
6425
+ );
6426
+ const expandedIds = isExpandedControlled ? controlledExpandedIds : uncontrolledExpandedIds;
6341
6427
  const listRef = (0, import_react11.useRef)(null);
6342
6428
  const rowRefs = (0, import_react11.useRef)(/* @__PURE__ */ new Map());
6343
6429
  const visibleItems = (0, import_react11.useMemo)(
@@ -6359,17 +6445,27 @@ function TreeSelect({
6359
6445
  const sensors = (0, import_core2.useSensors)(
6360
6446
  (0, import_core2.useSensor)(import_core2.PointerSensor, { activationConstraint: { distance: 4 } })
6361
6447
  );
6448
+ const updateExpandedIds = (0, import_react11.useCallback)(
6449
+ (updater) => {
6450
+ if (isExpandedControlled) {
6451
+ const next = updater(new Set(expandedIds));
6452
+ onExpandedChange == null ? void 0 : onExpandedChange(next);
6453
+ return;
6454
+ }
6455
+ setExpandedIds((prev) => updater(new Set(prev)));
6456
+ },
6457
+ [expandedIds, isExpandedControlled, onExpandedChange]
6458
+ );
6362
6459
  const toggleExpanded = (0, import_react11.useCallback)((id) => {
6363
- setExpandedIds((prev) => {
6364
- const next = new Set(prev);
6365
- if (next.has(id)) {
6366
- next.delete(id);
6460
+ updateExpandedIds((prev) => {
6461
+ if (prev.has(id)) {
6462
+ prev.delete(id);
6367
6463
  } else {
6368
- next.add(id);
6464
+ prev.add(id);
6369
6465
  }
6370
- return next;
6466
+ return prev;
6371
6467
  });
6372
- }, []);
6468
+ }, [updateExpandedIds]);
6373
6469
  const handleRowClick = (0, import_react11.useCallback)(
6374
6470
  (event, id) => {
6375
6471
  var _a2, _b2;
@@ -6497,10 +6593,9 @@ function TreeSelect({
6497
6593
  });
6498
6594
  onDataChange == null ? void 0 : onDataChange(nextTree);
6499
6595
  if (parentId && projectedDepth > 0) {
6500
- setExpandedIds((prev) => {
6501
- const next = new Set(prev);
6502
- next.add(parentId);
6503
- return next;
6596
+ updateExpandedIds((prev) => {
6597
+ prev.add(parentId);
6598
+ return prev;
6504
6599
  });
6505
6600
  }
6506
6601
  setActiveId(null);
@@ -6514,7 +6609,9 @@ function TreeSelect({
6514
6609
  onDataChange,
6515
6610
  overId,
6516
6611
  treeData,
6517
- visibleItems
6612
+ updateExpandedIds,
6613
+ visibleItems,
6614
+ maxDepth
6518
6615
  ]);
6519
6616
  const handleDragCancel = (0, import_react11.useCallback)(() => {
6520
6617
  setActiveId(null);
@@ -6533,13 +6630,12 @@ function TreeSelect({
6533
6630
  const newNode = createNewNode();
6534
6631
  const nextTree = addChildNode(treeData, parentId, newNode);
6535
6632
  onDataChange == null ? void 0 : onDataChange(nextTree);
6536
- setExpandedIds((prev) => {
6537
- const next = new Set(prev);
6538
- next.add(parentId);
6539
- return next;
6633
+ updateExpandedIds((prev) => {
6634
+ prev.add(parentId);
6635
+ return prev;
6540
6636
  });
6541
6637
  },
6542
- [createNewNode, onDataChange, treeData]
6638
+ [createNewNode, onDataChange, treeData, updateExpandedIds]
6543
6639
  );
6544
6640
  const handleAddSibling = (0, import_react11.useCallback)(
6545
6641
  (targetId) => {
@@ -6550,6 +6646,34 @@ function TreeSelect({
6550
6646
  },
6551
6647
  [createNewNode, onDataChange, treeData]
6552
6648
  );
6649
+ const resolveTooltipByLevel = (0, import_react11.useCallback)((levels, depth, fallback) => {
6650
+ if (!Array.isArray(levels)) return fallback;
6651
+ if (depth < 0 || depth >= levels.length) return fallback;
6652
+ return levels[depth] ?? fallback;
6653
+ }, []);
6654
+ const handleDelete = (0, import_react11.useCallback)(
6655
+ (targetId) => {
6656
+ const { nextNodes, removed } = removeNode(treeData, targetId);
6657
+ if (!removed) return;
6658
+ const removedIds = collectNodeIds(removed);
6659
+ onDataChange == null ? void 0 : onDataChange(nextNodes);
6660
+ updateExpandedIds((prev) => {
6661
+ removedIds.forEach((id) => prev.delete(id));
6662
+ return prev;
6663
+ });
6664
+ setSelectedIds((prev) => {
6665
+ if (!prev.size) return prev;
6666
+ const next = new Set(prev);
6667
+ removedIds.forEach((id) => next.delete(id));
6668
+ return next;
6669
+ });
6670
+ setLastSelectedId(
6671
+ (prev) => prev && removedIds.has(prev) ? null : prev
6672
+ );
6673
+ setEditingId((prev) => prev && removedIds.has(prev) ? null : prev);
6674
+ },
6675
+ [onDataChange, treeData, updateExpandedIds]
6676
+ );
6553
6677
  const startEdit = (0, import_react11.useCallback)(
6554
6678
  (id) => {
6555
6679
  var _a2, _b2, _c, _d;
@@ -6641,8 +6765,23 @@ function TreeSelect({
6641
6765
  canAddSibling: isEditable && (maxDepthLimit === null || item.depth <= maxDepthLimit),
6642
6766
  onAddChild: handleAddChild,
6643
6767
  onAddSibling: handleAddSibling,
6644
- addChildTooltip,
6645
- addSiblingTooltip
6768
+ addChildTooltip: resolveTooltipByLevel(
6769
+ addChildTooltipByLevel,
6770
+ item.depth,
6771
+ addChildTooltip
6772
+ ),
6773
+ addSiblingTooltip: resolveTooltipByLevel(
6774
+ addSiblingTooltipByLevel,
6775
+ item.depth,
6776
+ addSiblingTooltip
6777
+ ),
6778
+ canDelete: isEditable && allowDelete,
6779
+ onDelete: handleDelete,
6780
+ deleteTooltip: resolveTooltipByLevel(
6781
+ deleteTooltipByLevel,
6782
+ item.depth,
6783
+ deleteTooltip
6784
+ )
6646
6785
  },
6647
6786
  item.id
6648
6787
  ))
@@ -6685,8 +6824,23 @@ function TreeSelect({
6685
6824
  canAddSibling: isEditable && (maxDepthLimit === null || item.depth <= maxDepthLimit),
6686
6825
  onAddChild: handleAddChild,
6687
6826
  onAddSibling: handleAddSibling,
6688
- addChildTooltip,
6689
- addSiblingTooltip
6827
+ addChildTooltip: resolveTooltipByLevel(
6828
+ addChildTooltipByLevel,
6829
+ item.depth,
6830
+ addChildTooltip
6831
+ ),
6832
+ addSiblingTooltip: resolveTooltipByLevel(
6833
+ addSiblingTooltipByLevel,
6834
+ item.depth,
6835
+ addSiblingTooltip
6836
+ ),
6837
+ canDelete: isEditable && allowDelete,
6838
+ onDelete: handleDelete,
6839
+ deleteTooltip: resolveTooltipByLevel(
6840
+ deleteTooltipByLevel,
6841
+ item.depth,
6842
+ deleteTooltip
6843
+ )
6690
6844
  },
6691
6845
  item.id
6692
6846
  )) }) }) });
package/dist/index.mjs CHANGED
@@ -5708,7 +5708,7 @@ function ButtonGroupItem(_props) {
5708
5708
  ButtonGroupItem.displayName = "ButtonGroupItem";
5709
5709
 
5710
5710
  // src/elements/TreeRow.jsx
5711
- import { Chevron, Draghandle, List, Plus } from "@edux-design/icons";
5711
+ import { Chevron, Close, Draghandle, List, Plus } from "@edux-design/icons";
5712
5712
 
5713
5713
  // src/elements/treeSelectConstants.js
5714
5714
  var HANDLE_WIDTH = 28;
@@ -5744,13 +5744,17 @@ var TreeRow = ({
5744
5744
  onAddChild,
5745
5745
  onAddSibling,
5746
5746
  addChildTooltip,
5747
- addSiblingTooltip
5747
+ addSiblingTooltip,
5748
+ canDelete,
5749
+ onDelete,
5750
+ deleteTooltip
5748
5751
  }) => {
5749
5752
  const toggleLabel = isExpanded ? "Collapse item" : "Expand item";
5750
5753
  const label = item.node.label ?? item.node.id;
5751
5754
  const showToggle = item.hasChildren;
5752
5755
  const rowBackground = isDragging ? "rgba(0, 0, 0, 0.04)" : isSelected ? "rgba(15, 98, 254, 0.08)" : void 0;
5753
5756
  const rowPaddingLeft = depth * INDENT_WIDTH + 8 + (isDraggable ? 0 : HANDLE_WIDTH + 8);
5757
+ const showActions = canAddChild || canAddSibling || canDelete;
5754
5758
  return /* @__PURE__ */ jsxs3(
5755
5759
  "div",
5756
5760
  {
@@ -5863,7 +5867,7 @@ var TreeRow = ({
5863
5867
  children: label
5864
5868
  }
5865
5869
  ),
5866
- canAddChild || canAddSibling ? /* @__PURE__ */ jsxs3(
5870
+ showActions ? /* @__PURE__ */ jsxs3(
5867
5871
  "div",
5868
5872
  {
5869
5873
  onClick: (event) => event.stopPropagation(),
@@ -5894,6 +5898,19 @@ var TreeRow = ({
5894
5898
  }
5895
5899
  ) }),
5896
5900
  /* @__PURE__ */ jsx11(TooltipContent2, { children: addSiblingTooltip ?? "Add sibling" })
5901
+ ] }) : null,
5902
+ canDelete ? /* @__PURE__ */ jsxs3(Tooltip2, { children: [
5903
+ /* @__PURE__ */ jsx11(TooltipTrigger2, { asChild: true, children: /* @__PURE__ */ jsx11(
5904
+ IconButton,
5905
+ {
5906
+ size: "small",
5907
+ isBare: true,
5908
+ icon: /* @__PURE__ */ jsx11(Close, { "aria-hidden": "true" }),
5909
+ "aria-label": "Delete item",
5910
+ onClick: () => onDelete == null ? void 0 : onDelete(item.id)
5911
+ }
5912
+ ) }),
5913
+ /* @__PURE__ */ jsx11(TooltipContent2, { children: deleteTooltip ?? "Delete item" })
5897
5914
  ] }) : null
5898
5915
  ]
5899
5916
  }
@@ -5929,7 +5946,10 @@ var TreeSortableRow = ({
5929
5946
  onAddChild,
5930
5947
  onAddSibling,
5931
5948
  addChildTooltip,
5932
- addSiblingTooltip
5949
+ addSiblingTooltip,
5950
+ canDelete,
5951
+ onDelete,
5952
+ deleteTooltip
5933
5953
  }) => {
5934
5954
  const {
5935
5955
  attributes,
@@ -5987,7 +6007,10 @@ var TreeSortableRow = ({
5987
6007
  onAddChild,
5988
6008
  onAddSibling,
5989
6009
  addChildTooltip,
5990
- addSiblingTooltip
6010
+ addSiblingTooltip,
6011
+ canDelete,
6012
+ onDelete,
6013
+ deleteTooltip
5991
6014
  }
5992
6015
  );
5993
6016
  };
@@ -6170,6 +6193,53 @@ var addSiblingNode = (nodes, targetId, newNode) => {
6170
6193
  });
6171
6194
  return { nextNodes, inserted };
6172
6195
  };
6196
+ var collectNodeIds = (node, ids = /* @__PURE__ */ new Set()) => {
6197
+ if (!node) return ids;
6198
+ ids.add(normaliseId(node.id));
6199
+ if (hasChildren(node)) {
6200
+ node.children.forEach((child) => collectNodeIds(child, ids));
6201
+ }
6202
+ return ids;
6203
+ };
6204
+ var collectExpandableIds = (nodes, ids = /* @__PURE__ */ new Set()) => {
6205
+ nodes.forEach((node) => {
6206
+ if (!hasChildren(node)) return;
6207
+ const nodeId = normaliseId(node.id);
6208
+ ids.add(nodeId);
6209
+ collectExpandableIds(node.children, ids);
6210
+ });
6211
+ return ids;
6212
+ };
6213
+ var collectExpandedIdsByLevel = (nodes, level, depth = 0, ids = /* @__PURE__ */ new Set()) => {
6214
+ if (level <= 0) return ids;
6215
+ nodes.forEach((node) => {
6216
+ if (!hasChildren(node)) return;
6217
+ if (depth < level) {
6218
+ ids.add(normaliseId(node.id));
6219
+ }
6220
+ if (depth + 1 < level) {
6221
+ collectExpandedIdsByLevel(node.children, level, depth + 1, ids);
6222
+ }
6223
+ });
6224
+ return ids;
6225
+ };
6226
+ var getExpandedIds = (nodes, expanded) => {
6227
+ if (!expanded) return /* @__PURE__ */ new Set();
6228
+ if (expanded === true || expanded === "all") {
6229
+ return collectExpandableIds(nodes);
6230
+ }
6231
+ if (typeof expanded === "number" && Number.isFinite(expanded)) {
6232
+ const level = Math.max(Math.floor(expanded), 0);
6233
+ return collectExpandedIdsByLevel(nodes, level);
6234
+ }
6235
+ if (expanded instanceof Set) {
6236
+ return new Set(Array.from(expanded, normaliseId));
6237
+ }
6238
+ if (Array.isArray(expanded)) {
6239
+ return new Set(expanded.map(normaliseId));
6240
+ }
6241
+ return /* @__PURE__ */ new Set();
6242
+ };
6173
6243
 
6174
6244
  // src/elements/treeSelectDrag.js
6175
6245
  var clamp2 = (value, min2, max2) => Math.min(Math.max(value, min2), max2);
@@ -6302,13 +6372,24 @@ function TreeSelect({
6302
6372
  allowDragAndDrop = false,
6303
6373
  allowMultiDrag = false,
6304
6374
  isEditable = false,
6375
+ allowDelete = false,
6305
6376
  useChevron = false,
6306
6377
  maxDepth,
6307
6378
  addChildTooltip,
6308
- addSiblingTooltip
6379
+ addSiblingTooltip,
6380
+ deleteTooltip,
6381
+ addChildTooltipByLevel,
6382
+ addSiblingTooltipByLevel,
6383
+ deleteTooltipByLevel,
6384
+ defaultExpanded,
6385
+ expanded,
6386
+ onExpandedChange
6309
6387
  }) {
6310
6388
  var _a, _b;
6311
- const [expandedIds, setExpandedIds] = useState11(() => /* @__PURE__ */ new Set());
6389
+ const [uncontrolledExpandedIds, setExpandedIds] = useState11(
6390
+ () => getExpandedIds(data ?? [], defaultExpanded)
6391
+ );
6392
+ const isExpandedControlled = expanded !== void 0;
6312
6393
  const [activeId, setActiveId] = useState11(null);
6313
6394
  const [overId, setOverId] = useState11(null);
6314
6395
  const [horizontalOffset, setHorizontalOffset] = useState11(0);
@@ -6318,6 +6399,11 @@ function TreeSelect({
6318
6399
  const [draftLabel, setDraftLabel] = useState11("");
6319
6400
  const idCounterRef = useRef10(0);
6320
6401
  const treeData = data ?? [];
6402
+ const controlledExpandedIds = useMemo8(
6403
+ () => getExpandedIds(treeData, expanded),
6404
+ [expanded, treeData]
6405
+ );
6406
+ const expandedIds = isExpandedControlled ? controlledExpandedIds : uncontrolledExpandedIds;
6321
6407
  const listRef = useRef10(null);
6322
6408
  const rowRefs = useRef10(/* @__PURE__ */ new Map());
6323
6409
  const visibleItems = useMemo8(
@@ -6339,17 +6425,27 @@ function TreeSelect({
6339
6425
  const sensors = useSensors(
6340
6426
  useSensor(PointerSensor, { activationConstraint: { distance: 4 } })
6341
6427
  );
6428
+ const updateExpandedIds = useCallback8(
6429
+ (updater) => {
6430
+ if (isExpandedControlled) {
6431
+ const next = updater(new Set(expandedIds));
6432
+ onExpandedChange == null ? void 0 : onExpandedChange(next);
6433
+ return;
6434
+ }
6435
+ setExpandedIds((prev) => updater(new Set(prev)));
6436
+ },
6437
+ [expandedIds, isExpandedControlled, onExpandedChange]
6438
+ );
6342
6439
  const toggleExpanded = useCallback8((id) => {
6343
- setExpandedIds((prev) => {
6344
- const next = new Set(prev);
6345
- if (next.has(id)) {
6346
- next.delete(id);
6440
+ updateExpandedIds((prev) => {
6441
+ if (prev.has(id)) {
6442
+ prev.delete(id);
6347
6443
  } else {
6348
- next.add(id);
6444
+ prev.add(id);
6349
6445
  }
6350
- return next;
6446
+ return prev;
6351
6447
  });
6352
- }, []);
6448
+ }, [updateExpandedIds]);
6353
6449
  const handleRowClick = useCallback8(
6354
6450
  (event, id) => {
6355
6451
  var _a2, _b2;
@@ -6477,10 +6573,9 @@ function TreeSelect({
6477
6573
  });
6478
6574
  onDataChange == null ? void 0 : onDataChange(nextTree);
6479
6575
  if (parentId && projectedDepth > 0) {
6480
- setExpandedIds((prev) => {
6481
- const next = new Set(prev);
6482
- next.add(parentId);
6483
- return next;
6576
+ updateExpandedIds((prev) => {
6577
+ prev.add(parentId);
6578
+ return prev;
6484
6579
  });
6485
6580
  }
6486
6581
  setActiveId(null);
@@ -6494,7 +6589,9 @@ function TreeSelect({
6494
6589
  onDataChange,
6495
6590
  overId,
6496
6591
  treeData,
6497
- visibleItems
6592
+ updateExpandedIds,
6593
+ visibleItems,
6594
+ maxDepth
6498
6595
  ]);
6499
6596
  const handleDragCancel = useCallback8(() => {
6500
6597
  setActiveId(null);
@@ -6513,13 +6610,12 @@ function TreeSelect({
6513
6610
  const newNode = createNewNode();
6514
6611
  const nextTree = addChildNode(treeData, parentId, newNode);
6515
6612
  onDataChange == null ? void 0 : onDataChange(nextTree);
6516
- setExpandedIds((prev) => {
6517
- const next = new Set(prev);
6518
- next.add(parentId);
6519
- return next;
6613
+ updateExpandedIds((prev) => {
6614
+ prev.add(parentId);
6615
+ return prev;
6520
6616
  });
6521
6617
  },
6522
- [createNewNode, onDataChange, treeData]
6618
+ [createNewNode, onDataChange, treeData, updateExpandedIds]
6523
6619
  );
6524
6620
  const handleAddSibling = useCallback8(
6525
6621
  (targetId) => {
@@ -6530,6 +6626,34 @@ function TreeSelect({
6530
6626
  },
6531
6627
  [createNewNode, onDataChange, treeData]
6532
6628
  );
6629
+ const resolveTooltipByLevel = useCallback8((levels, depth, fallback) => {
6630
+ if (!Array.isArray(levels)) return fallback;
6631
+ if (depth < 0 || depth >= levels.length) return fallback;
6632
+ return levels[depth] ?? fallback;
6633
+ }, []);
6634
+ const handleDelete = useCallback8(
6635
+ (targetId) => {
6636
+ const { nextNodes, removed } = removeNode(treeData, targetId);
6637
+ if (!removed) return;
6638
+ const removedIds = collectNodeIds(removed);
6639
+ onDataChange == null ? void 0 : onDataChange(nextNodes);
6640
+ updateExpandedIds((prev) => {
6641
+ removedIds.forEach((id) => prev.delete(id));
6642
+ return prev;
6643
+ });
6644
+ setSelectedIds((prev) => {
6645
+ if (!prev.size) return prev;
6646
+ const next = new Set(prev);
6647
+ removedIds.forEach((id) => next.delete(id));
6648
+ return next;
6649
+ });
6650
+ setLastSelectedId(
6651
+ (prev) => prev && removedIds.has(prev) ? null : prev
6652
+ );
6653
+ setEditingId((prev) => prev && removedIds.has(prev) ? null : prev);
6654
+ },
6655
+ [onDataChange, treeData, updateExpandedIds]
6656
+ );
6533
6657
  const startEdit = useCallback8(
6534
6658
  (id) => {
6535
6659
  var _a2, _b2, _c, _d;
@@ -6621,8 +6745,23 @@ function TreeSelect({
6621
6745
  canAddSibling: isEditable && (maxDepthLimit === null || item.depth <= maxDepthLimit),
6622
6746
  onAddChild: handleAddChild,
6623
6747
  onAddSibling: handleAddSibling,
6624
- addChildTooltip,
6625
- addSiblingTooltip
6748
+ addChildTooltip: resolveTooltipByLevel(
6749
+ addChildTooltipByLevel,
6750
+ item.depth,
6751
+ addChildTooltip
6752
+ ),
6753
+ addSiblingTooltip: resolveTooltipByLevel(
6754
+ addSiblingTooltipByLevel,
6755
+ item.depth,
6756
+ addSiblingTooltip
6757
+ ),
6758
+ canDelete: isEditable && allowDelete,
6759
+ onDelete: handleDelete,
6760
+ deleteTooltip: resolveTooltipByLevel(
6761
+ deleteTooltipByLevel,
6762
+ item.depth,
6763
+ deleteTooltip
6764
+ )
6626
6765
  },
6627
6766
  item.id
6628
6767
  ))
@@ -6665,8 +6804,23 @@ function TreeSelect({
6665
6804
  canAddSibling: isEditable && (maxDepthLimit === null || item.depth <= maxDepthLimit),
6666
6805
  onAddChild: handleAddChild,
6667
6806
  onAddSibling: handleAddSibling,
6668
- addChildTooltip,
6669
- addSiblingTooltip
6807
+ addChildTooltip: resolveTooltipByLevel(
6808
+ addChildTooltipByLevel,
6809
+ item.depth,
6810
+ addChildTooltip
6811
+ ),
6812
+ addSiblingTooltip: resolveTooltipByLevel(
6813
+ addSiblingTooltipByLevel,
6814
+ item.depth,
6815
+ addSiblingTooltip
6816
+ ),
6817
+ canDelete: isEditable && allowDelete,
6818
+ onDelete: handleDelete,
6819
+ deleteTooltip: resolveTooltipByLevel(
6820
+ deleteTooltipByLevel,
6821
+ item.depth,
6822
+ deleteTooltip
6823
+ )
6670
6824
  },
6671
6825
  item.id
6672
6826
  )) }) }) });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edux-design/tree-select",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "private": false,
5
5
  "sideEffects": [
6
6
  "**/*.css"
@@ -18,8 +18,8 @@
18
18
  },
19
19
  "scripts": {
20
20
  "lint": "eslint . --max-warnings 0",
21
- "build": "tsup src/index.js --format esm,cjs --dts",
22
- "dev": "tsup src/index.js --watch --format esm,cjs --dts",
21
+ "build": "tsup src/index.js --format esm,cjs --dts --external react,react-dom",
22
+ "dev": "tsup src/index.js --watch --format esm,cjs --dts --external react,react-dom",
23
23
  "check-types": "tsc --noEmit"
24
24
  },
25
25
  "dependencies": {