@edux-design/tree-select 0.2.3 → 0.2.5

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
@@ -123,7 +123,22 @@ export function ChevronExample() {
123
123
  Tree data to render. This component is controlled; updates are emitted through `onDataChange`.
124
124
 
125
125
  ### `onDataChange` (function)
126
- Called with the updated tree when edits, add actions, or drag-and-drop reordering occur.
126
+ Called with `(nextTree, meta?)` when edits, add actions, deletes, or drag-and-drop reordering occur.
127
+
128
+ ```ts
129
+ type TreeSelectChangeMeta = {
130
+ reason: "drag" | "edit" | "add-child" | "add-sibling" | "delete";
131
+ activeId?: string | null;
132
+ draggedRootIds?: string[];
133
+ draggedIds?: string[];
134
+ sourceParentId?: string | null;
135
+ targetParentId?: string | null;
136
+ targetSiblingIndex?: number | null;
137
+ projectedDepth?: number | null;
138
+ };
139
+ ```
140
+
141
+ For drag-and-drop, `meta.draggedRootIds` identifies the exact root nodes that moved, which removes ambiguity when multiple reorder outcomes can produce the same final tree shape.
127
142
 
128
143
  ### `onLabelChange` (function)
129
144
  Called with `(id, nextLabel)` when a label edit is committed. When provided, label edits do not emit `onDataChange`.
@@ -164,6 +179,29 @@ import { MenuList, MenuItem } from "@edux-design/menus";
164
179
  />;
165
180
  ```
166
181
 
182
+ ### `renderLabel` (function)
183
+ Renders custom inline content where the label normally appears. This is the supported way to compose metadata like `Tag` elements next to the item title.
184
+
185
+ ```jsx
186
+ import { Tag } from "@edux-design/tags";
187
+
188
+ <TreeSelect
189
+ data={data}
190
+ renderLabel={({ id, node, hasChildren }) => (
191
+ <>
192
+ <span>{node.label ?? id}</span>
193
+ <Tag
194
+ size="small"
195
+ tone="subtle"
196
+ variant={hasChildren ? "information" : "neutral"}
197
+ >
198
+ {hasChildren ? "Group" : "Leaf"}
199
+ </Tag>
200
+ </>
201
+ )}
202
+ />;
203
+ ```
204
+
167
205
  ### `maxLabelLength` (number)
168
206
  Limits label width by character count and truncates with an ellipsis when exceeded.
169
207
 
@@ -229,6 +267,7 @@ levelConfig={{
229
267
  - `levelConfig` can override editability, actions, and tooltips per depth.
230
268
  - Drag-and-drop supports reordering within a level and moving items between levels.
231
269
  - Drag handle alignment is set so child handles align under the parent toggle.
270
+ - `renderLabel` customizes both the row content and the single-item drag overlay.
232
271
 
233
272
  ---
234
273
 
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
 
3
- declare function TreeSelect({ data, onDataChange, allowDragAndDrop, allowMultiDrag, isEditable, allowDelete, useChevron, actionButtonsPosition, maxLabelLength, maxDepth, addChildTooltip, addSiblingTooltip, deleteTooltip, onLabelChange, levelConfig, defaultExpanded, expanded, onExpandedChange, renderAdditionalActionsMenu, }: {
3
+ declare function TreeSelect({ data, onDataChange, allowDragAndDrop, allowMultiDrag, isEditable, allowDelete, useChevron, actionButtonsPosition, maxLabelLength, maxDepth, addChildTooltip, addSiblingTooltip, deleteTooltip, onLabelChange, levelConfig, defaultExpanded, expanded, onExpandedChange, renderAdditionalActionsMenu, renderLabel, }: {
4
4
  data: any;
5
5
  onDataChange: any;
6
6
  allowDragAndDrop?: boolean;
@@ -20,6 +20,7 @@ declare function TreeSelect({ data, onDataChange, allowDragAndDrop, allowMultiDr
20
20
  expanded: any;
21
21
  onExpandedChange: any;
22
22
  renderAdditionalActionsMenu: any;
23
+ renderLabel: any;
23
24
  }): react_jsx_runtime.JSX.Element;
24
25
 
25
26
  export { TreeSelect };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
 
3
- declare function TreeSelect({ data, onDataChange, allowDragAndDrop, allowMultiDrag, isEditable, allowDelete, useChevron, actionButtonsPosition, maxLabelLength, maxDepth, addChildTooltip, addSiblingTooltip, deleteTooltip, onLabelChange, levelConfig, defaultExpanded, expanded, onExpandedChange, renderAdditionalActionsMenu, }: {
3
+ declare function TreeSelect({ data, onDataChange, allowDragAndDrop, allowMultiDrag, isEditable, allowDelete, useChevron, actionButtonsPosition, maxLabelLength, maxDepth, addChildTooltip, addSiblingTooltip, deleteTooltip, onLabelChange, levelConfig, defaultExpanded, expanded, onExpandedChange, renderAdditionalActionsMenu, renderLabel, }: {
4
4
  data: any;
5
5
  onDataChange: any;
6
6
  allowDragAndDrop?: boolean;
@@ -20,6 +20,7 @@ declare function TreeSelect({ data, onDataChange, allowDragAndDrop, allowMultiDr
20
20
  expanded: any;
21
21
  onExpandedChange: any;
22
22
  renderAdditionalActionsMenu: any;
23
+ renderLabel: any;
23
24
  }): react_jsx_runtime.JSX.Element;
24
25
 
25
26
  export { TreeSelect };
package/dist/index.js CHANGED
@@ -87,10 +87,19 @@ var TreeRow = ({
87
87
  canDelete,
88
88
  onDelete,
89
89
  deleteTooltip,
90
- additionalActionsMenu
90
+ additionalActionsMenu,
91
+ renderLabel
91
92
  }) => {
92
93
  const toggleLabel = isExpanded ? "Collapse item" : "Expand item";
93
94
  const label = item.node.label ?? item.node.id;
95
+ const labelContent = renderLabel ? renderLabel({
96
+ id: item.id,
97
+ node: item.node,
98
+ depth,
99
+ parentId: item.parentId,
100
+ hasChildren: item.hasChildren,
101
+ isExpanded
102
+ }) : label;
94
103
  const showToggle = item.hasChildren;
95
104
  const [additionalMenuOpen, setAdditionalMenuOpen] = import_react.default.useState(false);
96
105
  const rowBackground = isDragging ? "rgba(0, 0, 0, 0.04)" : isSelected ? "rgba(15, 98, 254, 0.08)" : void 0;
@@ -217,9 +226,13 @@ var TreeRow = ({
217
226
  style: {
218
227
  fontSize: 14,
219
228
  cursor: isEditable ? "pointer" : "default",
220
- ...labelStyle
229
+ ...renderLabel ? {
230
+ display: "inline-flex",
231
+ alignItems: "center",
232
+ gap: 6
233
+ } : labelStyle
221
234
  },
222
- children: label
235
+ children: labelContent
223
236
  }
224
237
  ),
225
238
  showActions ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
@@ -326,7 +339,8 @@ var TreeSortableRow = ({
326
339
  canDelete,
327
340
  onDelete,
328
341
  deleteTooltip,
329
- additionalActionsMenu
342
+ additionalActionsMenu,
343
+ renderLabel
330
344
  }) => {
331
345
  const {
332
346
  attributes,
@@ -390,7 +404,8 @@ var TreeSortableRow = ({
390
404
  canDelete,
391
405
  onDelete,
392
406
  deleteTooltip,
393
- additionalActionsMenu
407
+ additionalActionsMenu,
408
+ renderLabel
394
409
  }
395
410
  );
396
411
  };
@@ -765,9 +780,9 @@ function TreeSelect({
765
780
  defaultExpanded,
766
781
  expanded,
767
782
  onExpandedChange,
768
- renderAdditionalActionsMenu
783
+ renderAdditionalActionsMenu,
784
+ renderLabel
769
785
  }) {
770
- var _a, _b;
771
786
  const [uncontrolledExpandedIds, setExpandedIds] = (0, import_react3.useState)(
772
787
  () => getExpandedIds(data ?? [], defaultExpanded)
773
788
  );
@@ -806,12 +821,12 @@ function TreeSelect({
806
821
  }, [maxDepth]);
807
822
  const resolvedLevelConfig = (0, import_react3.useCallback)(
808
823
  (depth) => {
809
- var _a2, _b2, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
824
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
810
825
  const defaults = (levelConfig == null ? void 0 : levelConfig.default) ?? {};
811
- const perLevel = ((_a2 = levelConfig == null ? void 0 : levelConfig.levels) == null ? void 0 : _a2[depth]) ?? {};
826
+ const perLevel = ((_a = levelConfig == null ? void 0 : levelConfig.levels) == null ? void 0 : _a[depth]) ?? {};
812
827
  const editable = perLevel.editable ?? defaults.editable ?? isEditable;
813
828
  const actions = {
814
- addChild: ((_b2 = perLevel.actions) == null ? void 0 : _b2.addChild) ?? ((_c = defaults.actions) == null ? void 0 : _c.addChild) ?? editable,
829
+ addChild: ((_b = perLevel.actions) == null ? void 0 : _b.addChild) ?? ((_c = defaults.actions) == null ? void 0 : _c.addChild) ?? editable,
815
830
  addSibling: ((_d = perLevel.actions) == null ? void 0 : _d.addSibling) ?? ((_e = defaults.actions) == null ? void 0 : _e.addSibling) ?? editable,
816
831
  delete: ((_f = perLevel.actions) == null ? void 0 : _f.delete) ?? ((_g = defaults.actions) == null ? void 0 : _g.delete) ?? (editable && allowDelete)
817
832
  };
@@ -845,6 +860,12 @@ function TreeSelect({
845
860
  },
846
861
  [expandedIds, isExpandedControlled, onExpandedChange]
847
862
  );
863
+ const emitDataChange = (0, import_react3.useCallback)(
864
+ (nextTree, meta) => {
865
+ onDataChange == null ? void 0 : onDataChange(nextTree, meta);
866
+ },
867
+ [onDataChange]
868
+ );
848
869
  const toggleExpanded = (0, import_react3.useCallback)((id) => {
849
870
  updateExpandedIds((prev) => {
850
871
  if (prev.has(id)) {
@@ -857,15 +878,15 @@ function TreeSelect({
857
878
  }, [updateExpandedIds]);
858
879
  const handleRowClick = (0, import_react3.useCallback)(
859
880
  (event, id) => {
860
- var _a2, _b2;
881
+ var _a, _b;
861
882
  if (!allowMultiDrag) return;
862
883
  const hasMultiKey = event.metaKey || event.ctrlKey;
863
- const parentId = ((_a2 = itemById.get(id)) == null ? void 0 : _a2.parentId) ?? null;
884
+ const parentId = ((_a = itemById.get(id)) == null ? void 0 : _a.parentId) ?? null;
864
885
  const siblingOrder = siblingOrderMap.get(parentId) ?? [];
865
886
  if (event.shiftKey) {
866
887
  const anchorIndex = siblingOrder.indexOf(lastSelectedId);
867
888
  const targetIndex = siblingOrder.indexOf(id);
868
- if (anchorIndex < 0 || targetIndex < 0 || (((_b2 = itemById.get(lastSelectedId ?? "")) == null ? void 0 : _b2.parentId) ?? null) !== parentId) {
889
+ if (anchorIndex < 0 || targetIndex < 0 || (((_b = itemById.get(lastSelectedId ?? "")) == null ? void 0 : _b.parentId) ?? null) !== parentId) {
869
890
  setSelectedIds(/* @__PURE__ */ new Set([id]));
870
891
  setLastSelectedId(id);
871
892
  return;
@@ -887,10 +908,10 @@ function TreeSelect({
887
908
  return;
888
909
  }
889
910
  setSelectedIds((prev) => {
890
- var _a3;
911
+ var _a2;
891
912
  if (prev.size) {
892
913
  const firstSelected = prev.values().next().value;
893
- const selectedParent = ((_a3 = itemById.get(firstSelected)) == null ? void 0 : _a3.parentId) ?? null;
914
+ const selectedParent = ((_a2 = itemById.get(firstSelected)) == null ? void 0 : _a2.parentId) ?? null;
894
915
  if (selectedParent !== parentId) {
895
916
  return /* @__PURE__ */ new Set([id]);
896
917
  }
@@ -948,12 +969,13 @@ function TreeSelect({
948
969
  setHorizontalOffset(event.delta.x);
949
970
  }, []);
950
971
  const handleDragOver = (0, import_react3.useCallback)((event) => {
951
- var _a2;
952
- if ((_a2 = event.over) == null ? void 0 : _a2.id) {
972
+ var _a;
973
+ if ((_a = event.over) == null ? void 0 : _a.id) {
953
974
  setOverId(normaliseId(event.over.id));
954
975
  }
955
976
  }, []);
956
977
  const handleDragEnd = (0, import_react3.useCallback)(() => {
978
+ var _a;
957
979
  const projection = getDropProjection({
958
980
  items: visibleItems,
959
981
  activeId,
@@ -969,6 +991,7 @@ function TreeSelect({
969
991
  return;
970
992
  }
971
993
  const { parentId, siblingIndex, projectedDepth } = projection;
994
+ const sourceParentId = ((_a = itemById.get(draggedRootIds[0] ?? activeId)) == null ? void 0 : _a.parentId) ?? null;
972
995
  const { nextNodes, removedNodes } = removeNodes(treeData, draggedRootIds);
973
996
  if (!removedNodes.length) {
974
997
  setActiveId(null);
@@ -980,7 +1003,16 @@ function TreeSelect({
980
1003
  removedNodes.forEach((node, index) => {
981
1004
  nextTree = insertNode(nextTree, parentId, siblingIndex + index, node);
982
1005
  });
983
- onDataChange == null ? void 0 : onDataChange(nextTree);
1006
+ emitDataChange(nextTree, {
1007
+ reason: "drag",
1008
+ activeId,
1009
+ draggedRootIds,
1010
+ draggedIds: Array.from(draggedIds),
1011
+ sourceParentId,
1012
+ targetParentId: parentId ?? null,
1013
+ targetSiblingIndex: siblingIndex,
1014
+ projectedDepth
1015
+ });
984
1016
  if (parentId && projectedDepth > 0) {
985
1017
  updateExpandedIds((prev) => {
986
1018
  prev.add(parentId);
@@ -994,8 +1026,9 @@ function TreeSelect({
994
1026
  activeId,
995
1027
  draggedIds,
996
1028
  draggedRootIds,
1029
+ emitDataChange,
997
1030
  horizontalOffset,
998
- onDataChange,
1031
+ itemById,
999
1032
  overId,
1000
1033
  treeData,
1001
1034
  updateExpandedIds,
@@ -1018,29 +1051,40 @@ function TreeSelect({
1018
1051
  (parentId) => {
1019
1052
  const newNode = createNewNode();
1020
1053
  const nextTree = addChildNode(treeData, parentId, newNode);
1021
- onDataChange == null ? void 0 : onDataChange(nextTree);
1054
+ emitDataChange(nextTree, {
1055
+ reason: "add-child",
1056
+ activeId: newNode.id,
1057
+ targetParentId: parentId
1058
+ });
1022
1059
  updateExpandedIds((prev) => {
1023
1060
  prev.add(parentId);
1024
1061
  return prev;
1025
1062
  });
1026
1063
  },
1027
- [createNewNode, onDataChange, treeData, updateExpandedIds]
1064
+ [createNewNode, emitDataChange, treeData, updateExpandedIds]
1028
1065
  );
1029
1066
  const handleAddSibling = (0, import_react3.useCallback)(
1030
1067
  (targetId) => {
1031
1068
  const newNode = createNewNode();
1032
1069
  const { nextNodes, inserted } = addSiblingNode(treeData, targetId, newNode);
1033
1070
  if (!inserted) return;
1034
- onDataChange == null ? void 0 : onDataChange(nextNodes);
1071
+ emitDataChange(nextNodes, {
1072
+ reason: "add-sibling",
1073
+ activeId: newNode.id
1074
+ });
1035
1075
  },
1036
- [createNewNode, onDataChange, treeData]
1076
+ [createNewNode, emitDataChange, treeData]
1037
1077
  );
1038
1078
  const handleDelete = (0, import_react3.useCallback)(
1039
1079
  (targetId) => {
1040
1080
  const { nextNodes, removed } = removeNode(treeData, targetId);
1041
1081
  if (!removed) return;
1042
1082
  const removedIds = collectNodeIds(removed);
1043
- onDataChange == null ? void 0 : onDataChange(nextNodes);
1083
+ emitDataChange(nextNodes, {
1084
+ reason: "delete",
1085
+ activeId: targetId,
1086
+ draggedIds: Array.from(removedIds)
1087
+ });
1044
1088
  updateExpandedIds((prev) => {
1045
1089
  removedIds.forEach((id) => prev.delete(id));
1046
1090
  return prev;
@@ -1056,12 +1100,12 @@ function TreeSelect({
1056
1100
  );
1057
1101
  setEditingId((prev) => prev && removedIds.has(prev) ? null : prev);
1058
1102
  },
1059
- [onDataChange, treeData, updateExpandedIds]
1103
+ [emitDataChange, treeData, updateExpandedIds]
1060
1104
  );
1061
1105
  const startEdit = (0, import_react3.useCallback)(
1062
1106
  (id) => {
1063
- var _a2, _b2, _c, _d;
1064
- 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) ?? "";
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) ?? "";
1065
1109
  setEditingId(id);
1066
1110
  setDraftLabel(String(currentLabel));
1067
1111
  },
@@ -1080,12 +1124,30 @@ function TreeSelect({
1080
1124
  return;
1081
1125
  }
1082
1126
  const nextTree = updateNodeLabel(treeData, editingId, nextLabel);
1083
- onDataChange == null ? void 0 : onDataChange(nextTree);
1127
+ emitDataChange(nextTree, {
1128
+ reason: "edit",
1129
+ activeId: editingId
1130
+ });
1084
1131
  setEditingId(null);
1085
- }, [draftLabel, editingId, onDataChange, onLabelChange, treeData]);
1132
+ }, [draftLabel, editingId, emitDataChange, onLabelChange, treeData]);
1086
1133
  const cancelEdit = (0, import_react3.useCallback)(() => {
1087
1134
  setEditingId(null);
1088
1135
  }, []);
1136
+ const renderLabelContent = (0, import_react3.useCallback)(
1137
+ (item) => {
1138
+ if (!item) return null;
1139
+ if (!renderLabel) return item.node.label ?? item.id;
1140
+ 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)
1147
+ });
1148
+ },
1149
+ [expandedIds, renderLabel]
1150
+ );
1089
1151
  const indicator = (0, import_react3.useMemo)(() => {
1090
1152
  if (!allowDragAndDrop) return null;
1091
1153
  return getDropIndicator({
@@ -1174,7 +1236,8 @@ function TreeSelect({
1174
1236
  canDelete: levelSettings.actions.delete,
1175
1237
  onDelete: handleDelete,
1176
1238
  deleteTooltip: levelSettings.tooltips.delete,
1177
- additionalActionsMenu
1239
+ additionalActionsMenu,
1240
+ renderLabel
1178
1241
  },
1179
1242
  item.id
1180
1243
  );
@@ -1189,7 +1252,19 @@ function TreeSelect({
1189
1252
  borderRadius: 6,
1190
1253
  boxShadow: "0 8px 24px rgba(0, 0, 0, 0.12)"
1191
1254
  },
1192
- 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
1255
+ children: draggedRootIds.length > 1 ? `${draggedRootIds.length} items` : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1256
+ "span",
1257
+ {
1258
+ style: {
1259
+ display: "inline-flex",
1260
+ alignItems: "center",
1261
+ gap: 6
1262
+ },
1263
+ children: renderLabelContent(
1264
+ visibleItems.find((item) => item.id === activeId)
1265
+ ) ?? activeId
1266
+ }
1267
+ )
1193
1268
  }
1194
1269
  ) : null })
1195
1270
  ]
@@ -1234,7 +1309,8 @@ function TreeSelect({
1234
1309
  canDelete: levelSettings.actions.delete,
1235
1310
  onDelete: handleDelete,
1236
1311
  deleteTooltip: levelSettings.tooltips.delete,
1237
- additionalActionsMenu
1312
+ additionalActionsMenu,
1313
+ renderLabel
1238
1314
  },
1239
1315
  item.id
1240
1316
  );
package/dist/index.mjs CHANGED
@@ -70,10 +70,19 @@ var TreeRow = ({
70
70
  canDelete,
71
71
  onDelete,
72
72
  deleteTooltip,
73
- additionalActionsMenu
73
+ additionalActionsMenu,
74
+ renderLabel
74
75
  }) => {
75
76
  const toggleLabel = isExpanded ? "Collapse item" : "Expand item";
76
77
  const label = item.node.label ?? item.node.id;
78
+ const labelContent = renderLabel ? renderLabel({
79
+ id: item.id,
80
+ node: item.node,
81
+ depth,
82
+ parentId: item.parentId,
83
+ hasChildren: item.hasChildren,
84
+ isExpanded
85
+ }) : label;
77
86
  const showToggle = item.hasChildren;
78
87
  const [additionalMenuOpen, setAdditionalMenuOpen] = React.useState(false);
79
88
  const rowBackground = isDragging ? "rgba(0, 0, 0, 0.04)" : isSelected ? "rgba(15, 98, 254, 0.08)" : void 0;
@@ -200,9 +209,13 @@ var TreeRow = ({
200
209
  style: {
201
210
  fontSize: 14,
202
211
  cursor: isEditable ? "pointer" : "default",
203
- ...labelStyle
212
+ ...renderLabel ? {
213
+ display: "inline-flex",
214
+ alignItems: "center",
215
+ gap: 6
216
+ } : labelStyle
204
217
  },
205
- children: label
218
+ children: labelContent
206
219
  }
207
220
  ),
208
221
  showActions ? /* @__PURE__ */ jsxs(
@@ -309,7 +322,8 @@ var TreeSortableRow = ({
309
322
  canDelete,
310
323
  onDelete,
311
324
  deleteTooltip,
312
- additionalActionsMenu
325
+ additionalActionsMenu,
326
+ renderLabel
313
327
  }) => {
314
328
  const {
315
329
  attributes,
@@ -373,7 +387,8 @@ var TreeSortableRow = ({
373
387
  canDelete,
374
388
  onDelete,
375
389
  deleteTooltip,
376
- additionalActionsMenu
390
+ additionalActionsMenu,
391
+ renderLabel
377
392
  }
378
393
  );
379
394
  };
@@ -748,9 +763,9 @@ function TreeSelect({
748
763
  defaultExpanded,
749
764
  expanded,
750
765
  onExpandedChange,
751
- renderAdditionalActionsMenu
766
+ renderAdditionalActionsMenu,
767
+ renderLabel
752
768
  }) {
753
- var _a, _b;
754
769
  const [uncontrolledExpandedIds, setExpandedIds] = useState(
755
770
  () => getExpandedIds(data ?? [], defaultExpanded)
756
771
  );
@@ -789,12 +804,12 @@ function TreeSelect({
789
804
  }, [maxDepth]);
790
805
  const resolvedLevelConfig = useCallback2(
791
806
  (depth) => {
792
- var _a2, _b2, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
807
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
793
808
  const defaults = (levelConfig == null ? void 0 : levelConfig.default) ?? {};
794
- const perLevel = ((_a2 = levelConfig == null ? void 0 : levelConfig.levels) == null ? void 0 : _a2[depth]) ?? {};
809
+ const perLevel = ((_a = levelConfig == null ? void 0 : levelConfig.levels) == null ? void 0 : _a[depth]) ?? {};
795
810
  const editable = perLevel.editable ?? defaults.editable ?? isEditable;
796
811
  const actions = {
797
- addChild: ((_b2 = perLevel.actions) == null ? void 0 : _b2.addChild) ?? ((_c = defaults.actions) == null ? void 0 : _c.addChild) ?? editable,
812
+ addChild: ((_b = perLevel.actions) == null ? void 0 : _b.addChild) ?? ((_c = defaults.actions) == null ? void 0 : _c.addChild) ?? editable,
798
813
  addSibling: ((_d = perLevel.actions) == null ? void 0 : _d.addSibling) ?? ((_e = defaults.actions) == null ? void 0 : _e.addSibling) ?? editable,
799
814
  delete: ((_f = perLevel.actions) == null ? void 0 : _f.delete) ?? ((_g = defaults.actions) == null ? void 0 : _g.delete) ?? (editable && allowDelete)
800
815
  };
@@ -828,6 +843,12 @@ function TreeSelect({
828
843
  },
829
844
  [expandedIds, isExpandedControlled, onExpandedChange]
830
845
  );
846
+ const emitDataChange = useCallback2(
847
+ (nextTree, meta) => {
848
+ onDataChange == null ? void 0 : onDataChange(nextTree, meta);
849
+ },
850
+ [onDataChange]
851
+ );
831
852
  const toggleExpanded = useCallback2((id) => {
832
853
  updateExpandedIds((prev) => {
833
854
  if (prev.has(id)) {
@@ -840,15 +861,15 @@ function TreeSelect({
840
861
  }, [updateExpandedIds]);
841
862
  const handleRowClick = useCallback2(
842
863
  (event, id) => {
843
- var _a2, _b2;
864
+ var _a, _b;
844
865
  if (!allowMultiDrag) return;
845
866
  const hasMultiKey = event.metaKey || event.ctrlKey;
846
- const parentId = ((_a2 = itemById.get(id)) == null ? void 0 : _a2.parentId) ?? null;
867
+ const parentId = ((_a = itemById.get(id)) == null ? void 0 : _a.parentId) ?? null;
847
868
  const siblingOrder = siblingOrderMap.get(parentId) ?? [];
848
869
  if (event.shiftKey) {
849
870
  const anchorIndex = siblingOrder.indexOf(lastSelectedId);
850
871
  const targetIndex = siblingOrder.indexOf(id);
851
- if (anchorIndex < 0 || targetIndex < 0 || (((_b2 = itemById.get(lastSelectedId ?? "")) == null ? void 0 : _b2.parentId) ?? null) !== parentId) {
872
+ if (anchorIndex < 0 || targetIndex < 0 || (((_b = itemById.get(lastSelectedId ?? "")) == null ? void 0 : _b.parentId) ?? null) !== parentId) {
852
873
  setSelectedIds(/* @__PURE__ */ new Set([id]));
853
874
  setLastSelectedId(id);
854
875
  return;
@@ -870,10 +891,10 @@ function TreeSelect({
870
891
  return;
871
892
  }
872
893
  setSelectedIds((prev) => {
873
- var _a3;
894
+ var _a2;
874
895
  if (prev.size) {
875
896
  const firstSelected = prev.values().next().value;
876
- const selectedParent = ((_a3 = itemById.get(firstSelected)) == null ? void 0 : _a3.parentId) ?? null;
897
+ const selectedParent = ((_a2 = itemById.get(firstSelected)) == null ? void 0 : _a2.parentId) ?? null;
877
898
  if (selectedParent !== parentId) {
878
899
  return /* @__PURE__ */ new Set([id]);
879
900
  }
@@ -931,12 +952,13 @@ function TreeSelect({
931
952
  setHorizontalOffset(event.delta.x);
932
953
  }, []);
933
954
  const handleDragOver = useCallback2((event) => {
934
- var _a2;
935
- if ((_a2 = event.over) == null ? void 0 : _a2.id) {
955
+ var _a;
956
+ if ((_a = event.over) == null ? void 0 : _a.id) {
936
957
  setOverId(normaliseId(event.over.id));
937
958
  }
938
959
  }, []);
939
960
  const handleDragEnd = useCallback2(() => {
961
+ var _a;
940
962
  const projection = getDropProjection({
941
963
  items: visibleItems,
942
964
  activeId,
@@ -952,6 +974,7 @@ function TreeSelect({
952
974
  return;
953
975
  }
954
976
  const { parentId, siblingIndex, projectedDepth } = projection;
977
+ const sourceParentId = ((_a = itemById.get(draggedRootIds[0] ?? activeId)) == null ? void 0 : _a.parentId) ?? null;
955
978
  const { nextNodes, removedNodes } = removeNodes(treeData, draggedRootIds);
956
979
  if (!removedNodes.length) {
957
980
  setActiveId(null);
@@ -963,7 +986,16 @@ function TreeSelect({
963
986
  removedNodes.forEach((node, index) => {
964
987
  nextTree = insertNode(nextTree, parentId, siblingIndex + index, node);
965
988
  });
966
- onDataChange == null ? void 0 : onDataChange(nextTree);
989
+ emitDataChange(nextTree, {
990
+ reason: "drag",
991
+ activeId,
992
+ draggedRootIds,
993
+ draggedIds: Array.from(draggedIds),
994
+ sourceParentId,
995
+ targetParentId: parentId ?? null,
996
+ targetSiblingIndex: siblingIndex,
997
+ projectedDepth
998
+ });
967
999
  if (parentId && projectedDepth > 0) {
968
1000
  updateExpandedIds((prev) => {
969
1001
  prev.add(parentId);
@@ -977,8 +1009,9 @@ function TreeSelect({
977
1009
  activeId,
978
1010
  draggedIds,
979
1011
  draggedRootIds,
1012
+ emitDataChange,
980
1013
  horizontalOffset,
981
- onDataChange,
1014
+ itemById,
982
1015
  overId,
983
1016
  treeData,
984
1017
  updateExpandedIds,
@@ -1001,29 +1034,40 @@ function TreeSelect({
1001
1034
  (parentId) => {
1002
1035
  const newNode = createNewNode();
1003
1036
  const nextTree = addChildNode(treeData, parentId, newNode);
1004
- onDataChange == null ? void 0 : onDataChange(nextTree);
1037
+ emitDataChange(nextTree, {
1038
+ reason: "add-child",
1039
+ activeId: newNode.id,
1040
+ targetParentId: parentId
1041
+ });
1005
1042
  updateExpandedIds((prev) => {
1006
1043
  prev.add(parentId);
1007
1044
  return prev;
1008
1045
  });
1009
1046
  },
1010
- [createNewNode, onDataChange, treeData, updateExpandedIds]
1047
+ [createNewNode, emitDataChange, treeData, updateExpandedIds]
1011
1048
  );
1012
1049
  const handleAddSibling = useCallback2(
1013
1050
  (targetId) => {
1014
1051
  const newNode = createNewNode();
1015
1052
  const { nextNodes, inserted } = addSiblingNode(treeData, targetId, newNode);
1016
1053
  if (!inserted) return;
1017
- onDataChange == null ? void 0 : onDataChange(nextNodes);
1054
+ emitDataChange(nextNodes, {
1055
+ reason: "add-sibling",
1056
+ activeId: newNode.id
1057
+ });
1018
1058
  },
1019
- [createNewNode, onDataChange, treeData]
1059
+ [createNewNode, emitDataChange, treeData]
1020
1060
  );
1021
1061
  const handleDelete = useCallback2(
1022
1062
  (targetId) => {
1023
1063
  const { nextNodes, removed } = removeNode(treeData, targetId);
1024
1064
  if (!removed) return;
1025
1065
  const removedIds = collectNodeIds(removed);
1026
- onDataChange == null ? void 0 : onDataChange(nextNodes);
1066
+ emitDataChange(nextNodes, {
1067
+ reason: "delete",
1068
+ activeId: targetId,
1069
+ draggedIds: Array.from(removedIds)
1070
+ });
1027
1071
  updateExpandedIds((prev) => {
1028
1072
  removedIds.forEach((id) => prev.delete(id));
1029
1073
  return prev;
@@ -1039,12 +1083,12 @@ function TreeSelect({
1039
1083
  );
1040
1084
  setEditingId((prev) => prev && removedIds.has(prev) ? null : prev);
1041
1085
  },
1042
- [onDataChange, treeData, updateExpandedIds]
1086
+ [emitDataChange, treeData, updateExpandedIds]
1043
1087
  );
1044
1088
  const startEdit = useCallback2(
1045
1089
  (id) => {
1046
- var _a2, _b2, _c, _d;
1047
- 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) ?? "";
1090
+ var _a, _b, _c, _d;
1091
+ 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) ?? "";
1048
1092
  setEditingId(id);
1049
1093
  setDraftLabel(String(currentLabel));
1050
1094
  },
@@ -1063,12 +1107,30 @@ function TreeSelect({
1063
1107
  return;
1064
1108
  }
1065
1109
  const nextTree = updateNodeLabel(treeData, editingId, nextLabel);
1066
- onDataChange == null ? void 0 : onDataChange(nextTree);
1110
+ emitDataChange(nextTree, {
1111
+ reason: "edit",
1112
+ activeId: editingId
1113
+ });
1067
1114
  setEditingId(null);
1068
- }, [draftLabel, editingId, onDataChange, onLabelChange, treeData]);
1115
+ }, [draftLabel, editingId, emitDataChange, onLabelChange, treeData]);
1069
1116
  const cancelEdit = useCallback2(() => {
1070
1117
  setEditingId(null);
1071
1118
  }, []);
1119
+ const renderLabelContent = useCallback2(
1120
+ (item) => {
1121
+ if (!item) return null;
1122
+ if (!renderLabel) return item.node.label ?? item.id;
1123
+ return renderLabel({
1124
+ id: item.id,
1125
+ node: item.node,
1126
+ depth: item.depth,
1127
+ parentId: item.parentId,
1128
+ hasChildren: item.hasChildren,
1129
+ isExpanded: expandedIds.has(item.id)
1130
+ });
1131
+ },
1132
+ [expandedIds, renderLabel]
1133
+ );
1072
1134
  const indicator = useMemo2(() => {
1073
1135
  if (!allowDragAndDrop) return null;
1074
1136
  return getDropIndicator({
@@ -1157,7 +1219,8 @@ function TreeSelect({
1157
1219
  canDelete: levelSettings.actions.delete,
1158
1220
  onDelete: handleDelete,
1159
1221
  deleteTooltip: levelSettings.tooltips.delete,
1160
- additionalActionsMenu
1222
+ additionalActionsMenu,
1223
+ renderLabel
1161
1224
  },
1162
1225
  item.id
1163
1226
  );
@@ -1172,7 +1235,19 @@ function TreeSelect({
1172
1235
  borderRadius: 6,
1173
1236
  boxShadow: "0 8px 24px rgba(0, 0, 0, 0.12)"
1174
1237
  },
1175
- 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
1238
+ children: draggedRootIds.length > 1 ? `${draggedRootIds.length} items` : /* @__PURE__ */ jsx3(
1239
+ "span",
1240
+ {
1241
+ style: {
1242
+ display: "inline-flex",
1243
+ alignItems: "center",
1244
+ gap: 6
1245
+ },
1246
+ children: renderLabelContent(
1247
+ visibleItems.find((item) => item.id === activeId)
1248
+ ) ?? activeId
1249
+ }
1250
+ )
1176
1251
  }
1177
1252
  ) : null })
1178
1253
  ]
@@ -1217,7 +1292,8 @@ function TreeSelect({
1217
1292
  canDelete: levelSettings.actions.delete,
1218
1293
  onDelete: handleDelete,
1219
1294
  deleteTooltip: levelSettings.tooltips.delete,
1220
- additionalActionsMenu
1295
+ additionalActionsMenu,
1296
+ renderLabel
1221
1297
  },
1222
1298
  item.id
1223
1299
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edux-design/tree-select",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "private": false,
5
5
  "sideEffects": [
6
6
  "**/*.css"