@edux-design/tree-select 0.2.0 → 0.2.1

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
@@ -125,6 +125,9 @@ Tree data to render. This component is controlled; updates are emitted through `
125
125
  ### `onDataChange` (function)
126
126
  Called with the updated tree when edits, add actions, or drag-and-drop reordering occur.
127
127
 
128
+ ### `onLabelChange` (function)
129
+ Called with `(id, nextLabel)` when a label edit is committed. When provided, label edits do not emit `onDataChange`.
130
+
128
131
  ### `allowDragAndDrop` (boolean, default `false`)
129
132
  Enables drag-and-drop. When `false`, drag handles are hidden and items cannot be reordered.
130
133
 
@@ -137,6 +140,12 @@ Enables inline label editing and add-item controls.
137
140
  ### `allowDelete` (boolean, default `false`)
138
141
  Shows a delete action for each item and removes the node (plus descendants).
139
142
 
143
+ ### `actionButtonsPosition` (`"start"` | `"end"`, default `"start"`)
144
+ Positions the action buttons within a row. `"end"` pushes the actions to the end of the row.
145
+
146
+ ### `maxLabelLength` (number)
147
+ Limits label width by character count and truncates with an ellipsis when exceeded.
148
+
140
149
  ### `useChevron` (boolean, default `false`)
141
150
  Uses a chevron control for expand/collapse instead of the checkbox toggle.
142
151
 
@@ -155,20 +164,35 @@ Limits how deep new items can be added. For example, `maxDepth={3}` allows at mo
155
164
  ### `addChildTooltip` (string)
156
165
  Tooltip copy for the add-child button.
157
166
 
158
- ### `addChildTooltipByLevel` (string[])
159
- Tooltip copy for add-child, keyed by depth. Overrides `addChildTooltip` when provided.
160
-
161
167
  ### `addSiblingTooltip` (string)
162
168
  Tooltip copy for the add-sibling button.
163
169
 
164
- ### `addSiblingTooltipByLevel` (string[])
165
- Tooltip copy for add-sibling, keyed by depth. Overrides `addSiblingTooltip` when provided.
166
-
167
170
  ### `deleteTooltip` (string)
168
171
  Tooltip copy for the delete button.
169
172
 
170
- ### `deleteTooltipByLevel` (string[])
171
- Tooltip copy for delete, keyed by depth. Overrides `deleteTooltip` when provided.
173
+ ### `levelConfig` (object)
174
+ Per-level configuration for editing, actions, and tooltips. Use `default` for global settings and `levels` to override by depth.
175
+ Values in `levelConfig` override `isEditable`, `allowDelete`, and tooltip props for the matching depth.
176
+
177
+ ```js
178
+ levelConfig={{
179
+ default: {
180
+ editable: true,
181
+ actions: { addChild: true, addSibling: true, delete: false },
182
+ tooltips: {
183
+ addChild: "Add child",
184
+ addSibling: "Add sibling",
185
+ delete: "Delete item",
186
+ },
187
+ },
188
+ levels: {
189
+ 0: {
190
+ editable: false,
191
+ tooltips: { addChild: "Add chapter" },
192
+ },
193
+ },
194
+ }}
195
+ ```
172
196
 
173
197
  ---
174
198
 
@@ -181,6 +205,7 @@ Tooltip copy for delete, keyed by depth. Overrides `deleteTooltip` when provided
181
205
  - `defaultExpanded` only seeds the initial state; use `expanded` for controlled expansion.
182
206
  - When `expanded` is provided, `onExpandedChange` is called with the next set of expanded ids.
183
207
  - Deleting a node removes the entire subtree and clears any selected/expanded state for those ids.
208
+ - `levelConfig` can override editability, actions, and tooltips per depth.
184
209
  - Drag-and-drop supports reordering within a level and moving items between levels.
185
210
  - Drag handle alignment is set so child handles align under the parent toggle.
186
211
 
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, maxDepth, addChildTooltip, addSiblingTooltip, deleteTooltip, addChildTooltipByLevel, addSiblingTooltipByLevel, deleteTooltipByLevel, defaultExpanded, expanded, onExpandedChange, }: {
3
+ declare function TreeSelect({ data, onDataChange, allowDragAndDrop, allowMultiDrag, isEditable, allowDelete, useChevron, actionButtonsPosition, maxLabelLength, maxDepth, addChildTooltip, addSiblingTooltip, deleteTooltip, onLabelChange, levelConfig, defaultExpanded, expanded, onExpandedChange, }: {
4
4
  data: any;
5
5
  onDataChange: any;
6
6
  allowDragAndDrop?: boolean;
@@ -8,13 +8,14 @@ declare function TreeSelect({ data, onDataChange, allowDragAndDrop, allowMultiDr
8
8
  isEditable?: boolean;
9
9
  allowDelete?: boolean;
10
10
  useChevron?: boolean;
11
+ actionButtonsPosition?: string;
12
+ maxLabelLength: any;
11
13
  maxDepth: any;
12
14
  addChildTooltip: any;
13
15
  addSiblingTooltip: any;
14
16
  deleteTooltip: any;
15
- addChildTooltipByLevel: any;
16
- addSiblingTooltipByLevel: any;
17
- deleteTooltipByLevel: any;
17
+ onLabelChange: any;
18
+ levelConfig: any;
18
19
  defaultExpanded: any;
19
20
  expanded: any;
20
21
  onExpandedChange: any;
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, maxDepth, addChildTooltip, addSiblingTooltip, deleteTooltip, addChildTooltipByLevel, addSiblingTooltipByLevel, deleteTooltipByLevel, defaultExpanded, expanded, onExpandedChange, }: {
3
+ declare function TreeSelect({ data, onDataChange, allowDragAndDrop, allowMultiDrag, isEditable, allowDelete, useChevron, actionButtonsPosition, maxLabelLength, maxDepth, addChildTooltip, addSiblingTooltip, deleteTooltip, onLabelChange, levelConfig, defaultExpanded, expanded, onExpandedChange, }: {
4
4
  data: any;
5
5
  onDataChange: any;
6
6
  allowDragAndDrop?: boolean;
@@ -8,13 +8,14 @@ declare function TreeSelect({ data, onDataChange, allowDragAndDrop, allowMultiDr
8
8
  isEditable?: boolean;
9
9
  allowDelete?: boolean;
10
10
  useChevron?: boolean;
11
+ actionButtonsPosition?: string;
12
+ maxLabelLength: any;
11
13
  maxDepth: any;
12
14
  addChildTooltip: any;
13
15
  addSiblingTooltip: any;
14
16
  deleteTooltip: any;
15
- addChildTooltipByLevel: any;
16
- addSiblingTooltipByLevel: any;
17
- deleteTooltipByLevel: any;
17
+ onLabelChange: any;
18
+ levelConfig: any;
18
19
  defaultExpanded: any;
19
20
  expanded: any;
20
21
  onExpandedChange: any;
package/dist/index.js CHANGED
@@ -69,6 +69,8 @@ var TreeRow = ({
69
69
  isSelected,
70
70
  onRowClick,
71
71
  isEditable,
72
+ actionButtonsPosition = "start",
73
+ maxLabelLength,
72
74
  isEditing,
73
75
  draftLabel,
74
76
  onDraftChange,
@@ -91,6 +93,19 @@ var TreeRow = ({
91
93
  const rowBackground = isDragging ? "rgba(0, 0, 0, 0.04)" : isSelected ? "rgba(15, 98, 254, 0.08)" : void 0;
92
94
  const rowPaddingLeft = depth * INDENT_WIDTH + 8 + (isDraggable ? 0 : HANDLE_WIDTH + 8);
93
95
  const showActions = canAddChild || canAddSibling || canDelete;
96
+ const actionsStyle = {
97
+ display: "flex",
98
+ gap: 4,
99
+ marginLeft: actionButtonsPosition === "end" ? "auto" : void 0
100
+ };
101
+ const labelStyle = typeof maxLabelLength === "number" ? {
102
+ maxWidth: `${maxLabelLength}ch`,
103
+ overflow: "hidden",
104
+ textOverflow: "ellipsis",
105
+ whiteSpace: "nowrap",
106
+ display: "inline-block",
107
+ verticalAlign: "top"
108
+ } : void 0;
94
109
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
95
110
  "div",
96
111
  {
@@ -198,7 +213,8 @@ var TreeRow = ({
198
213
  "data-tree-label": item.id,
199
214
  style: {
200
215
  fontSize: 14,
201
- cursor: isEditable ? "pointer" : "default"
216
+ cursor: isEditable ? "pointer" : "default",
217
+ ...labelStyle
202
218
  },
203
219
  children: label
204
220
  }
@@ -206,8 +222,9 @@ var TreeRow = ({
206
222
  showActions ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
207
223
  "div",
208
224
  {
225
+ "data-tree-actions": item.id,
209
226
  onClick: (event) => event.stopPropagation(),
210
- style: { display: "flex", gap: 4 },
227
+ style: actionsStyle,
211
228
  children: [
212
229
  canAddChild ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_tooltips.Tooltip, { children: [
213
230
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tooltips.TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -270,6 +287,8 @@ var TreeSortableRow = ({
270
287
  isSelected,
271
288
  isGroupDragging,
272
289
  isEditable,
290
+ actionButtonsPosition,
291
+ maxLabelLength,
273
292
  useChevron,
274
293
  isEditing,
275
294
  draftLabel,
@@ -331,6 +350,8 @@ var TreeSortableRow = ({
331
350
  isDragging: isDragging || isActive || isGroupDragging,
332
351
  isSelected,
333
352
  isEditable,
353
+ actionButtonsPosition,
354
+ maxLabelLength,
334
355
  useChevron,
335
356
  isEditing,
336
357
  draftLabel,
@@ -710,13 +731,14 @@ function TreeSelect({
710
731
  isEditable = false,
711
732
  allowDelete = false,
712
733
  useChevron = false,
734
+ actionButtonsPosition = "start",
735
+ maxLabelLength,
713
736
  maxDepth,
714
737
  addChildTooltip,
715
738
  addSiblingTooltip,
716
739
  deleteTooltip,
717
- addChildTooltipByLevel,
718
- addSiblingTooltipByLevel,
719
- deleteTooltipByLevel,
740
+ onLabelChange,
741
+ levelConfig,
720
742
  defaultExpanded,
721
743
  expanded,
722
744
  onExpandedChange
@@ -758,6 +780,33 @@ function TreeSelect({
758
780
  if (typeof maxDepth !== "number") return null;
759
781
  return Math.max(maxDepth - 1, 0);
760
782
  }, [maxDepth]);
783
+ const resolvedLevelConfig = (0, import_react3.useCallback)(
784
+ (depth) => {
785
+ var _a2, _b2, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
786
+ const defaults = (levelConfig == null ? void 0 : levelConfig.default) ?? {};
787
+ const perLevel = ((_a2 = levelConfig == null ? void 0 : levelConfig.levels) == null ? void 0 : _a2[depth]) ?? {};
788
+ const editable = perLevel.editable ?? defaults.editable ?? isEditable;
789
+ const actions = {
790
+ addChild: ((_b2 = perLevel.actions) == null ? void 0 : _b2.addChild) ?? ((_c = defaults.actions) == null ? void 0 : _c.addChild) ?? editable,
791
+ addSibling: ((_d = perLevel.actions) == null ? void 0 : _d.addSibling) ?? ((_e = defaults.actions) == null ? void 0 : _e.addSibling) ?? editable,
792
+ delete: ((_f = perLevel.actions) == null ? void 0 : _f.delete) ?? ((_g = defaults.actions) == null ? void 0 : _g.delete) ?? (editable && allowDelete)
793
+ };
794
+ const tooltips = {
795
+ addChild: ((_h = perLevel.tooltips) == null ? void 0 : _h.addChild) ?? ((_i = defaults.tooltips) == null ? void 0 : _i.addChild) ?? addChildTooltip,
796
+ addSibling: ((_j = perLevel.tooltips) == null ? void 0 : _j.addSibling) ?? ((_k = defaults.tooltips) == null ? void 0 : _k.addSibling) ?? addSiblingTooltip,
797
+ delete: ((_l = perLevel.tooltips) == null ? void 0 : _l.delete) ?? ((_m = defaults.tooltips) == null ? void 0 : _m.delete) ?? deleteTooltip
798
+ };
799
+ return { editable, actions, tooltips };
800
+ },
801
+ [
802
+ addChildTooltip,
803
+ addSiblingTooltip,
804
+ allowDelete,
805
+ deleteTooltip,
806
+ isEditable,
807
+ levelConfig
808
+ ]
809
+ );
761
810
  const sensors = (0, import_core.useSensors)(
762
811
  (0, import_core.useSensor)(import_core.PointerSensor, { activationConstraint: { distance: 4 } })
763
812
  );
@@ -962,11 +1011,6 @@ function TreeSelect({
962
1011
  },
963
1012
  [createNewNode, onDataChange, treeData]
964
1013
  );
965
- const resolveTooltipByLevel = (0, import_react3.useCallback)((levels, depth, fallback) => {
966
- if (!Array.isArray(levels)) return fallback;
967
- if (depth < 0 || depth >= levels.length) return fallback;
968
- return levels[depth] ?? fallback;
969
- }, []);
970
1014
  const handleDelete = (0, import_react3.useCallback)(
971
1015
  (targetId) => {
972
1016
  const { nextNodes, removed } = removeNode(treeData, targetId);
@@ -1002,10 +1046,19 @@ function TreeSelect({
1002
1046
  const commitEdit = (0, import_react3.useCallback)(() => {
1003
1047
  const trimmedLabel = draftLabel.trim();
1004
1048
  const nextLabel = trimmedLabel.length ? trimmedLabel : draftLabel;
1049
+ if (!editingId) {
1050
+ setEditingId(null);
1051
+ return;
1052
+ }
1053
+ if (onLabelChange) {
1054
+ onLabelChange(editingId, nextLabel);
1055
+ setEditingId(null);
1056
+ return;
1057
+ }
1005
1058
  const nextTree = updateNodeLabel(treeData, editingId, nextLabel);
1006
1059
  onDataChange == null ? void 0 : onDataChange(nextTree);
1007
1060
  setEditingId(null);
1008
- }, [draftLabel, editingId, onDataChange, treeData]);
1061
+ }, [draftLabel, editingId, onDataChange, onLabelChange, treeData]);
1009
1062
  const cancelEdit = (0, import_react3.useCallback)(() => {
1010
1063
  setEditingId(null);
1011
1064
  }, []);
@@ -1056,51 +1109,44 @@ function TreeSelect({
1056
1109
  }
1057
1110
  }
1058
1111
  ) : null,
1059
- visibleItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1060
- TreeSortableRow,
1061
- {
1062
- item,
1063
- isExpanded: expandedIds.has(item.id),
1064
- onToggle: toggleExpanded,
1065
- onRowClick: handleRowClick,
1066
- rowRefs,
1067
- isActive: activeId === item.id,
1068
- isSelected: selectedIds.has(item.id),
1069
- isGroupDragging: Boolean(
1070
- activeId && draggedIds.has(item.id)
1071
- ),
1072
- isEditable,
1073
- useChevron,
1074
- isEditing: editingId === item.id,
1075
- draftLabel,
1076
- onDraftChange: setDraftLabel,
1077
- onCommitEdit: commitEdit,
1078
- onCancelEdit: cancelEdit,
1079
- onStartEdit: () => startEdit(item.id),
1080
- canAddChild: isEditable && (maxDepthLimit === null || item.depth + 1 <= maxDepthLimit),
1081
- canAddSibling: isEditable && (maxDepthLimit === null || item.depth <= maxDepthLimit),
1082
- onAddChild: handleAddChild,
1083
- onAddSibling: handleAddSibling,
1084
- addChildTooltip: resolveTooltipByLevel(
1085
- addChildTooltipByLevel,
1086
- item.depth,
1087
- addChildTooltip
1088
- ),
1089
- addSiblingTooltip: resolveTooltipByLevel(
1090
- addSiblingTooltipByLevel,
1091
- item.depth,
1092
- addSiblingTooltip
1093
- ),
1094
- canDelete: isEditable && allowDelete,
1095
- onDelete: handleDelete,
1096
- deleteTooltip: resolveTooltipByLevel(
1097
- deleteTooltipByLevel,
1098
- item.depth,
1099
- deleteTooltip
1100
- )
1101
- },
1102
- item.id
1103
- ))
1112
+ visibleItems.map((item) => {
1113
+ const levelSettings = resolvedLevelConfig(item.depth);
1114
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1115
+ TreeSortableRow,
1116
+ {
1117
+ item,
1118
+ isExpanded: expandedIds.has(item.id),
1119
+ onToggle: toggleExpanded,
1120
+ onRowClick: handleRowClick,
1121
+ rowRefs,
1122
+ isActive: activeId === item.id,
1123
+ isSelected: selectedIds.has(item.id),
1124
+ isGroupDragging: Boolean(
1125
+ activeId && draggedIds.has(item.id)
1126
+ ),
1127
+ isEditable: levelSettings.editable,
1128
+ actionButtonsPosition,
1129
+ maxLabelLength,
1130
+ useChevron,
1131
+ isEditing: editingId === item.id,
1132
+ draftLabel,
1133
+ onDraftChange: setDraftLabel,
1134
+ onCommitEdit: commitEdit,
1135
+ onCancelEdit: cancelEdit,
1136
+ onStartEdit: () => startEdit(item.id),
1137
+ canAddChild: levelSettings.actions.addChild && (maxDepthLimit === null || item.depth + 1 <= maxDepthLimit),
1138
+ canAddSibling: levelSettings.actions.addSibling && (maxDepthLimit === null || item.depth <= maxDepthLimit),
1139
+ onAddChild: handleAddChild,
1140
+ onAddSibling: handleAddSibling,
1141
+ addChildTooltip: levelSettings.tooltips.addChild,
1142
+ addSiblingTooltip: levelSettings.tooltips.addSibling,
1143
+ canDelete: levelSettings.actions.delete,
1144
+ onDelete: handleDelete,
1145
+ deleteTooltip: levelSettings.tooltips.delete
1146
+ },
1147
+ item.id
1148
+ );
1149
+ })
1104
1150
  ] }) }),
1105
1151
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_core.DragOverlay, { children: activeId ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1106
1152
  "div",
@@ -1116,50 +1162,43 @@ function TreeSelect({
1116
1162
  ) : null })
1117
1163
  ]
1118
1164
  }
1119
- ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref: listRef, style: { position: "relative" }, children: visibleItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1120
- TreeRow,
1121
- {
1122
- item,
1123
- depth: item.depth,
1124
- isExpanded: expandedIds.has(item.id),
1125
- onToggle: toggleExpanded,
1126
- onRowClick: handleRowClick,
1127
- rowRef: void 0,
1128
- isDraggable: false,
1129
- isDragging: false,
1130
- isSelected: selectedIds.has(item.id),
1131
- isEditable,
1132
- useChevron,
1133
- isEditing: editingId === item.id,
1134
- draftLabel,
1135
- onDraftChange: setDraftLabel,
1136
- onCommitEdit: commitEdit,
1137
- onCancelEdit: cancelEdit,
1138
- onStartEdit: () => startEdit(item.id),
1139
- canAddChild: isEditable && (maxDepthLimit === null || item.depth + 1 <= maxDepthLimit),
1140
- canAddSibling: isEditable && (maxDepthLimit === null || item.depth <= maxDepthLimit),
1141
- onAddChild: handleAddChild,
1142
- onAddSibling: handleAddSibling,
1143
- addChildTooltip: resolveTooltipByLevel(
1144
- addChildTooltipByLevel,
1145
- item.depth,
1146
- addChildTooltip
1147
- ),
1148
- addSiblingTooltip: resolveTooltipByLevel(
1149
- addSiblingTooltipByLevel,
1150
- item.depth,
1151
- addSiblingTooltip
1152
- ),
1153
- canDelete: isEditable && allowDelete,
1154
- onDelete: handleDelete,
1155
- deleteTooltip: resolveTooltipByLevel(
1156
- deleteTooltipByLevel,
1157
- item.depth,
1158
- deleteTooltip
1159
- )
1160
- },
1161
- item.id
1162
- )) }) }) });
1165
+ ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref: listRef, style: { position: "relative" }, children: visibleItems.map((item) => {
1166
+ const levelSettings = resolvedLevelConfig(item.depth);
1167
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1168
+ TreeRow,
1169
+ {
1170
+ item,
1171
+ depth: item.depth,
1172
+ isExpanded: expandedIds.has(item.id),
1173
+ onToggle: toggleExpanded,
1174
+ onRowClick: handleRowClick,
1175
+ rowRef: void 0,
1176
+ isDraggable: false,
1177
+ isDragging: false,
1178
+ isSelected: selectedIds.has(item.id),
1179
+ isEditable: levelSettings.editable,
1180
+ actionButtonsPosition,
1181
+ maxLabelLength,
1182
+ useChevron,
1183
+ isEditing: editingId === item.id,
1184
+ draftLabel,
1185
+ onDraftChange: setDraftLabel,
1186
+ onCommitEdit: commitEdit,
1187
+ onCancelEdit: cancelEdit,
1188
+ onStartEdit: () => startEdit(item.id),
1189
+ canAddChild: levelSettings.actions.addChild && (maxDepthLimit === null || item.depth + 1 <= maxDepthLimit),
1190
+ canAddSibling: levelSettings.actions.addSibling && (maxDepthLimit === null || item.depth <= maxDepthLimit),
1191
+ onAddChild: handleAddChild,
1192
+ onAddSibling: handleAddSibling,
1193
+ addChildTooltip: levelSettings.tooltips.addChild,
1194
+ addSiblingTooltip: levelSettings.tooltips.addSibling,
1195
+ canDelete: levelSettings.actions.delete,
1196
+ onDelete: handleDelete,
1197
+ deleteTooltip: levelSettings.tooltips.delete
1198
+ },
1199
+ item.id
1200
+ );
1201
+ }) }) }) });
1163
1202
  }
1164
1203
  // Annotate the CommonJS export names for ESM import in node:
1165
1204
  0 && (module.exports = {
package/dist/index.mjs CHANGED
@@ -45,6 +45,8 @@ var TreeRow = ({
45
45
  isSelected,
46
46
  onRowClick,
47
47
  isEditable,
48
+ actionButtonsPosition = "start",
49
+ maxLabelLength,
48
50
  isEditing,
49
51
  draftLabel,
50
52
  onDraftChange,
@@ -67,6 +69,19 @@ var TreeRow = ({
67
69
  const rowBackground = isDragging ? "rgba(0, 0, 0, 0.04)" : isSelected ? "rgba(15, 98, 254, 0.08)" : void 0;
68
70
  const rowPaddingLeft = depth * INDENT_WIDTH + 8 + (isDraggable ? 0 : HANDLE_WIDTH + 8);
69
71
  const showActions = canAddChild || canAddSibling || canDelete;
72
+ const actionsStyle = {
73
+ display: "flex",
74
+ gap: 4,
75
+ marginLeft: actionButtonsPosition === "end" ? "auto" : void 0
76
+ };
77
+ const labelStyle = typeof maxLabelLength === "number" ? {
78
+ maxWidth: `${maxLabelLength}ch`,
79
+ overflow: "hidden",
80
+ textOverflow: "ellipsis",
81
+ whiteSpace: "nowrap",
82
+ display: "inline-block",
83
+ verticalAlign: "top"
84
+ } : void 0;
70
85
  return /* @__PURE__ */ jsxs(
71
86
  "div",
72
87
  {
@@ -174,7 +189,8 @@ var TreeRow = ({
174
189
  "data-tree-label": item.id,
175
190
  style: {
176
191
  fontSize: 14,
177
- cursor: isEditable ? "pointer" : "default"
192
+ cursor: isEditable ? "pointer" : "default",
193
+ ...labelStyle
178
194
  },
179
195
  children: label
180
196
  }
@@ -182,8 +198,9 @@ var TreeRow = ({
182
198
  showActions ? /* @__PURE__ */ jsxs(
183
199
  "div",
184
200
  {
201
+ "data-tree-actions": item.id,
185
202
  onClick: (event) => event.stopPropagation(),
186
- style: { display: "flex", gap: 4 },
203
+ style: actionsStyle,
187
204
  children: [
188
205
  canAddChild ? /* @__PURE__ */ jsxs(Tooltip, { children: [
189
206
  /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
@@ -246,6 +263,8 @@ var TreeSortableRow = ({
246
263
  isSelected,
247
264
  isGroupDragging,
248
265
  isEditable,
266
+ actionButtonsPosition,
267
+ maxLabelLength,
249
268
  useChevron,
250
269
  isEditing,
251
270
  draftLabel,
@@ -307,6 +326,8 @@ var TreeSortableRow = ({
307
326
  isDragging: isDragging || isActive || isGroupDragging,
308
327
  isSelected,
309
328
  isEditable,
329
+ actionButtonsPosition,
330
+ maxLabelLength,
310
331
  useChevron,
311
332
  isEditing,
312
333
  draftLabel,
@@ -686,13 +707,14 @@ function TreeSelect({
686
707
  isEditable = false,
687
708
  allowDelete = false,
688
709
  useChevron = false,
710
+ actionButtonsPosition = "start",
711
+ maxLabelLength,
689
712
  maxDepth,
690
713
  addChildTooltip,
691
714
  addSiblingTooltip,
692
715
  deleteTooltip,
693
- addChildTooltipByLevel,
694
- addSiblingTooltipByLevel,
695
- deleteTooltipByLevel,
716
+ onLabelChange,
717
+ levelConfig,
696
718
  defaultExpanded,
697
719
  expanded,
698
720
  onExpandedChange
@@ -734,6 +756,33 @@ function TreeSelect({
734
756
  if (typeof maxDepth !== "number") return null;
735
757
  return Math.max(maxDepth - 1, 0);
736
758
  }, [maxDepth]);
759
+ const resolvedLevelConfig = useCallback2(
760
+ (depth) => {
761
+ var _a2, _b2, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
762
+ const defaults = (levelConfig == null ? void 0 : levelConfig.default) ?? {};
763
+ const perLevel = ((_a2 = levelConfig == null ? void 0 : levelConfig.levels) == null ? void 0 : _a2[depth]) ?? {};
764
+ const editable = perLevel.editable ?? defaults.editable ?? isEditable;
765
+ const actions = {
766
+ addChild: ((_b2 = perLevel.actions) == null ? void 0 : _b2.addChild) ?? ((_c = defaults.actions) == null ? void 0 : _c.addChild) ?? editable,
767
+ addSibling: ((_d = perLevel.actions) == null ? void 0 : _d.addSibling) ?? ((_e = defaults.actions) == null ? void 0 : _e.addSibling) ?? editable,
768
+ delete: ((_f = perLevel.actions) == null ? void 0 : _f.delete) ?? ((_g = defaults.actions) == null ? void 0 : _g.delete) ?? (editable && allowDelete)
769
+ };
770
+ const tooltips = {
771
+ addChild: ((_h = perLevel.tooltips) == null ? void 0 : _h.addChild) ?? ((_i = defaults.tooltips) == null ? void 0 : _i.addChild) ?? addChildTooltip,
772
+ addSibling: ((_j = perLevel.tooltips) == null ? void 0 : _j.addSibling) ?? ((_k = defaults.tooltips) == null ? void 0 : _k.addSibling) ?? addSiblingTooltip,
773
+ delete: ((_l = perLevel.tooltips) == null ? void 0 : _l.delete) ?? ((_m = defaults.tooltips) == null ? void 0 : _m.delete) ?? deleteTooltip
774
+ };
775
+ return { editable, actions, tooltips };
776
+ },
777
+ [
778
+ addChildTooltip,
779
+ addSiblingTooltip,
780
+ allowDelete,
781
+ deleteTooltip,
782
+ isEditable,
783
+ levelConfig
784
+ ]
785
+ );
737
786
  const sensors = useSensors(
738
787
  useSensor(PointerSensor, { activationConstraint: { distance: 4 } })
739
788
  );
@@ -938,11 +987,6 @@ function TreeSelect({
938
987
  },
939
988
  [createNewNode, onDataChange, treeData]
940
989
  );
941
- const resolveTooltipByLevel = useCallback2((levels, depth, fallback) => {
942
- if (!Array.isArray(levels)) return fallback;
943
- if (depth < 0 || depth >= levels.length) return fallback;
944
- return levels[depth] ?? fallback;
945
- }, []);
946
990
  const handleDelete = useCallback2(
947
991
  (targetId) => {
948
992
  const { nextNodes, removed } = removeNode(treeData, targetId);
@@ -978,10 +1022,19 @@ function TreeSelect({
978
1022
  const commitEdit = useCallback2(() => {
979
1023
  const trimmedLabel = draftLabel.trim();
980
1024
  const nextLabel = trimmedLabel.length ? trimmedLabel : draftLabel;
1025
+ if (!editingId) {
1026
+ setEditingId(null);
1027
+ return;
1028
+ }
1029
+ if (onLabelChange) {
1030
+ onLabelChange(editingId, nextLabel);
1031
+ setEditingId(null);
1032
+ return;
1033
+ }
981
1034
  const nextTree = updateNodeLabel(treeData, editingId, nextLabel);
982
1035
  onDataChange == null ? void 0 : onDataChange(nextTree);
983
1036
  setEditingId(null);
984
- }, [draftLabel, editingId, onDataChange, treeData]);
1037
+ }, [draftLabel, editingId, onDataChange, onLabelChange, treeData]);
985
1038
  const cancelEdit = useCallback2(() => {
986
1039
  setEditingId(null);
987
1040
  }, []);
@@ -1032,51 +1085,44 @@ function TreeSelect({
1032
1085
  }
1033
1086
  }
1034
1087
  ) : null,
1035
- visibleItems.map((item) => /* @__PURE__ */ jsx3(
1036
- TreeSortableRow,
1037
- {
1038
- item,
1039
- isExpanded: expandedIds.has(item.id),
1040
- onToggle: toggleExpanded,
1041
- onRowClick: handleRowClick,
1042
- rowRefs,
1043
- isActive: activeId === item.id,
1044
- isSelected: selectedIds.has(item.id),
1045
- isGroupDragging: Boolean(
1046
- activeId && draggedIds.has(item.id)
1047
- ),
1048
- isEditable,
1049
- useChevron,
1050
- isEditing: editingId === item.id,
1051
- draftLabel,
1052
- onDraftChange: setDraftLabel,
1053
- onCommitEdit: commitEdit,
1054
- onCancelEdit: cancelEdit,
1055
- onStartEdit: () => startEdit(item.id),
1056
- canAddChild: isEditable && (maxDepthLimit === null || item.depth + 1 <= maxDepthLimit),
1057
- canAddSibling: isEditable && (maxDepthLimit === null || item.depth <= maxDepthLimit),
1058
- onAddChild: handleAddChild,
1059
- onAddSibling: handleAddSibling,
1060
- addChildTooltip: resolveTooltipByLevel(
1061
- addChildTooltipByLevel,
1062
- item.depth,
1063
- addChildTooltip
1064
- ),
1065
- addSiblingTooltip: resolveTooltipByLevel(
1066
- addSiblingTooltipByLevel,
1067
- item.depth,
1068
- addSiblingTooltip
1069
- ),
1070
- canDelete: isEditable && allowDelete,
1071
- onDelete: handleDelete,
1072
- deleteTooltip: resolveTooltipByLevel(
1073
- deleteTooltipByLevel,
1074
- item.depth,
1075
- deleteTooltip
1076
- )
1077
- },
1078
- item.id
1079
- ))
1088
+ visibleItems.map((item) => {
1089
+ const levelSettings = resolvedLevelConfig(item.depth);
1090
+ return /* @__PURE__ */ jsx3(
1091
+ TreeSortableRow,
1092
+ {
1093
+ item,
1094
+ isExpanded: expandedIds.has(item.id),
1095
+ onToggle: toggleExpanded,
1096
+ onRowClick: handleRowClick,
1097
+ rowRefs,
1098
+ isActive: activeId === item.id,
1099
+ isSelected: selectedIds.has(item.id),
1100
+ isGroupDragging: Boolean(
1101
+ activeId && draggedIds.has(item.id)
1102
+ ),
1103
+ isEditable: levelSettings.editable,
1104
+ actionButtonsPosition,
1105
+ maxLabelLength,
1106
+ useChevron,
1107
+ isEditing: editingId === item.id,
1108
+ draftLabel,
1109
+ onDraftChange: setDraftLabel,
1110
+ onCommitEdit: commitEdit,
1111
+ onCancelEdit: cancelEdit,
1112
+ onStartEdit: () => startEdit(item.id),
1113
+ canAddChild: levelSettings.actions.addChild && (maxDepthLimit === null || item.depth + 1 <= maxDepthLimit),
1114
+ canAddSibling: levelSettings.actions.addSibling && (maxDepthLimit === null || item.depth <= maxDepthLimit),
1115
+ onAddChild: handleAddChild,
1116
+ onAddSibling: handleAddSibling,
1117
+ addChildTooltip: levelSettings.tooltips.addChild,
1118
+ addSiblingTooltip: levelSettings.tooltips.addSibling,
1119
+ canDelete: levelSettings.actions.delete,
1120
+ onDelete: handleDelete,
1121
+ deleteTooltip: levelSettings.tooltips.delete
1122
+ },
1123
+ item.id
1124
+ );
1125
+ })
1080
1126
  ] }) }),
1081
1127
  /* @__PURE__ */ jsx3(DragOverlay, { children: activeId ? /* @__PURE__ */ jsx3(
1082
1128
  "div",
@@ -1092,50 +1138,43 @@ function TreeSelect({
1092
1138
  ) : null })
1093
1139
  ]
1094
1140
  }
1095
- ) : /* @__PURE__ */ jsx3("div", { ref: listRef, style: { position: "relative" }, children: visibleItems.map((item) => /* @__PURE__ */ jsx3(
1096
- TreeRow,
1097
- {
1098
- item,
1099
- depth: item.depth,
1100
- isExpanded: expandedIds.has(item.id),
1101
- onToggle: toggleExpanded,
1102
- onRowClick: handleRowClick,
1103
- rowRef: void 0,
1104
- isDraggable: false,
1105
- isDragging: false,
1106
- isSelected: selectedIds.has(item.id),
1107
- isEditable,
1108
- useChevron,
1109
- isEditing: editingId === item.id,
1110
- draftLabel,
1111
- onDraftChange: setDraftLabel,
1112
- onCommitEdit: commitEdit,
1113
- onCancelEdit: cancelEdit,
1114
- onStartEdit: () => startEdit(item.id),
1115
- canAddChild: isEditable && (maxDepthLimit === null || item.depth + 1 <= maxDepthLimit),
1116
- canAddSibling: isEditable && (maxDepthLimit === null || item.depth <= maxDepthLimit),
1117
- onAddChild: handleAddChild,
1118
- onAddSibling: handleAddSibling,
1119
- addChildTooltip: resolveTooltipByLevel(
1120
- addChildTooltipByLevel,
1121
- item.depth,
1122
- addChildTooltip
1123
- ),
1124
- addSiblingTooltip: resolveTooltipByLevel(
1125
- addSiblingTooltipByLevel,
1126
- item.depth,
1127
- addSiblingTooltip
1128
- ),
1129
- canDelete: isEditable && allowDelete,
1130
- onDelete: handleDelete,
1131
- deleteTooltip: resolveTooltipByLevel(
1132
- deleteTooltipByLevel,
1133
- item.depth,
1134
- deleteTooltip
1135
- )
1136
- },
1137
- item.id
1138
- )) }) }) });
1141
+ ) : /* @__PURE__ */ jsx3("div", { ref: listRef, style: { position: "relative" }, children: visibleItems.map((item) => {
1142
+ const levelSettings = resolvedLevelConfig(item.depth);
1143
+ return /* @__PURE__ */ jsx3(
1144
+ TreeRow,
1145
+ {
1146
+ item,
1147
+ depth: item.depth,
1148
+ isExpanded: expandedIds.has(item.id),
1149
+ onToggle: toggleExpanded,
1150
+ onRowClick: handleRowClick,
1151
+ rowRef: void 0,
1152
+ isDraggable: false,
1153
+ isDragging: false,
1154
+ isSelected: selectedIds.has(item.id),
1155
+ isEditable: levelSettings.editable,
1156
+ actionButtonsPosition,
1157
+ maxLabelLength,
1158
+ useChevron,
1159
+ isEditing: editingId === item.id,
1160
+ draftLabel,
1161
+ onDraftChange: setDraftLabel,
1162
+ onCommitEdit: commitEdit,
1163
+ onCancelEdit: cancelEdit,
1164
+ onStartEdit: () => startEdit(item.id),
1165
+ canAddChild: levelSettings.actions.addChild && (maxDepthLimit === null || item.depth + 1 <= maxDepthLimit),
1166
+ canAddSibling: levelSettings.actions.addSibling && (maxDepthLimit === null || item.depth <= maxDepthLimit),
1167
+ onAddChild: handleAddChild,
1168
+ onAddSibling: handleAddSibling,
1169
+ addChildTooltip: levelSettings.tooltips.addChild,
1170
+ addSiblingTooltip: levelSettings.tooltips.addSibling,
1171
+ canDelete: levelSettings.actions.delete,
1172
+ onDelete: handleDelete,
1173
+ deleteTooltip: levelSettings.tooltips.delete
1174
+ },
1175
+ item.id
1176
+ );
1177
+ }) }) }) });
1139
1178
  }
1140
1179
  export {
1141
1180
  TreeSelect
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edux-design/tree-select",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "private": false,
5
5
  "sideEffects": [
6
6
  "**/*.css"