@edux-design/tree-select 0.2.1 → 0.2.3

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
@@ -7,9 +7,9 @@ TreeSelect renders hierarchical data with expand/collapse controls, optional inl
7
7
  ## Installation
8
8
 
9
9
  ```bash
10
- pnpm add @edux-design/tree-select @edux-design/forms @edux-design/buttons @edux-design/icons @edux-design/tooltips @dnd-kit/core @dnd-kit/sortable
10
+ pnpm add @edux-design/tree-select @edux-design/forms @edux-design/buttons @edux-design/icons @edux-design/menus @edux-design/tooltips @dnd-kit/core @dnd-kit/sortable
11
11
  # or
12
- npm install @edux-design/tree-select @edux-design/forms @edux-design/buttons @edux-design/icons @edux-design/tooltips @dnd-kit/core @dnd-kit/sortable
12
+ npm install @edux-design/tree-select @edux-design/forms @edux-design/buttons @edux-design/icons @edux-design/menus @edux-design/tooltips @dnd-kit/core @dnd-kit/sortable
13
13
  ```
14
14
 
15
15
  Peer deps include `react@^19.1.0` and `react-dom@^19.1.0`.
@@ -143,6 +143,27 @@ Shows a delete action for each item and removes the node (plus descendants).
143
143
  ### `actionButtonsPosition` (`"start"` | `"end"`, default `"start"`)
144
144
  Positions the action buttons within a row. `"end"` pushes the actions to the end of the row.
145
145
 
146
+ ### `renderAdditionalActionsMenu` (function)
147
+ Renders a kebab (more actions) menu per row. Return `null`/`undefined` to hide the menu for a given item.
148
+
149
+ ```jsx
150
+ import { MenuList, MenuItem } from "@edux-design/menus";
151
+
152
+ <TreeSelect
153
+ data={data}
154
+ renderAdditionalActionsMenu={({ id, node }) => (
155
+ <MenuList>
156
+ <MenuItem onClick={() => console.log("View", id)}>
157
+ View {node.label ?? id}
158
+ </MenuItem>
159
+ <MenuItem onClick={() => console.log("Duplicate", id)}>
160
+ Duplicate
161
+ </MenuItem>
162
+ </MenuList>
163
+ )}
164
+ />;
165
+ ```
166
+
146
167
  ### `maxLabelLength` (number)
147
168
  Limits label width by character count and truncates with an ellipsis when exceeded.
148
169
 
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, }: {
3
+ declare function TreeSelect({ data, onDataChange, allowDragAndDrop, allowMultiDrag, isEditable, allowDelete, useChevron, actionButtonsPosition, maxLabelLength, maxDepth, addChildTooltip, addSiblingTooltip, deleteTooltip, onLabelChange, levelConfig, defaultExpanded, expanded, onExpandedChange, renderAdditionalActionsMenu, }: {
4
4
  data: any;
5
5
  onDataChange: any;
6
6
  allowDragAndDrop?: boolean;
@@ -19,6 +19,7 @@ declare function TreeSelect({ data, onDataChange, allowDragAndDrop, allowMultiDr
19
19
  defaultExpanded: any;
20
20
  expanded: any;
21
21
  onExpandedChange: any;
22
+ renderAdditionalActionsMenu: any;
22
23
  }): react_jsx_runtime.JSX.Element;
23
24
 
24
25
  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, }: {
3
+ declare function TreeSelect({ data, onDataChange, allowDragAndDrop, allowMultiDrag, isEditable, allowDelete, useChevron, actionButtonsPosition, maxLabelLength, maxDepth, addChildTooltip, addSiblingTooltip, deleteTooltip, onLabelChange, levelConfig, defaultExpanded, expanded, onExpandedChange, renderAdditionalActionsMenu, }: {
4
4
  data: any;
5
5
  onDataChange: any;
6
6
  allowDragAndDrop?: boolean;
@@ -19,6 +19,7 @@ declare function TreeSelect({ data, onDataChange, allowDragAndDrop, allowMultiDr
19
19
  defaultExpanded: any;
20
20
  expanded: any;
21
21
  onExpandedChange: any;
22
+ renderAdditionalActionsMenu: any;
22
23
  }): react_jsx_runtime.JSX.Element;
23
24
 
24
25
  export { TreeSelect };
package/dist/index.js CHANGED
@@ -44,6 +44,7 @@ var import_react = __toESM(require("react"));
44
44
  var import_forms = require("@edux-design/forms");
45
45
  var import_buttons = require("@edux-design/buttons");
46
46
  var import_icons = require("@edux-design/icons");
47
+ var import_menus = require("@edux-design/menus");
47
48
  var import_tooltips = require("@edux-design/tooltips");
48
49
 
49
50
  // src/elements/treeSelectConstants.js
@@ -85,14 +86,17 @@ var TreeRow = ({
85
86
  addSiblingTooltip,
86
87
  canDelete,
87
88
  onDelete,
88
- deleteTooltip
89
+ deleteTooltip,
90
+ additionalActionsMenu
89
91
  }) => {
90
92
  const toggleLabel = isExpanded ? "Collapse item" : "Expand item";
91
93
  const label = item.node.label ?? item.node.id;
92
94
  const showToggle = item.hasChildren;
95
+ const [additionalMenuOpen, setAdditionalMenuOpen] = import_react.default.useState(false);
93
96
  const rowBackground = isDragging ? "rgba(0, 0, 0, 0.04)" : isSelected ? "rgba(15, 98, 254, 0.08)" : void 0;
94
- const rowPaddingLeft = depth * INDENT_WIDTH + 8 + (isDraggable ? 0 : HANDLE_WIDTH + 8);
95
- const showActions = canAddChild || canAddSibling || canDelete;
97
+ const rowPaddingLeft = depth * INDENT_WIDTH + 8;
98
+ const hasAdditionalActionsMenu = Boolean(additionalActionsMenu);
99
+ const showActions = canAddChild || canAddSibling || canDelete || hasAdditionalActionsMenu;
96
100
  const actionsStyle = {
97
101
  display: "flex",
98
102
  gap: 4,
@@ -133,14 +137,13 @@ var TreeRow = ({
133
137
  ref: dragRef,
134
138
  "aria-label": "Drag item",
135
139
  onClick: (event) => event.stopPropagation(),
140
+ className: "border border-border-subtle bg-bg-base text-fg-base",
136
141
  style: {
137
142
  width: HANDLE_WIDTH,
138
143
  height: HANDLE_WIDTH,
139
144
  display: "grid",
140
145
  placeItems: "center",
141
- border: "1px solid rgba(0, 0, 0, 0.2)",
142
146
  borderRadius: 6,
143
- background: "white",
144
147
  cursor: "grab",
145
148
  fontSize: 12,
146
149
  lineHeight: 1
@@ -264,7 +267,25 @@ var TreeRow = ({
264
267
  }
265
268
  ) }),
266
269
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tooltips.TooltipContent, { children: deleteTooltip ?? "Delete item" })
267
- ] }) : null
270
+ ] }) : null,
271
+ hasAdditionalActionsMenu ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
272
+ import_menus.Menu,
273
+ {
274
+ align: "end",
275
+ open: additionalMenuOpen,
276
+ onOpenChange: setAdditionalMenuOpen,
277
+ button: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
278
+ import_buttons.IconButton,
279
+ {
280
+ size: "small",
281
+ isBare: true,
282
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.MeatballVertical, { "aria-hidden": "true" }),
283
+ "aria-label": "More actions"
284
+ }
285
+ ),
286
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { onClick: () => setAdditionalMenuOpen(false), children: additionalActionsMenu })
287
+ }
288
+ ) : null
268
289
  ]
269
290
  }
270
291
  ) : null
@@ -304,7 +325,8 @@ var TreeSortableRow = ({
304
325
  addSiblingTooltip,
305
326
  canDelete,
306
327
  onDelete,
307
- deleteTooltip
328
+ deleteTooltip,
329
+ additionalActionsMenu
308
330
  }) => {
309
331
  const {
310
332
  attributes,
@@ -367,7 +389,8 @@ var TreeSortableRow = ({
367
389
  addSiblingTooltip,
368
390
  canDelete,
369
391
  onDelete,
370
- deleteTooltip
392
+ deleteTooltip,
393
+ additionalActionsMenu
371
394
  }
372
395
  );
373
396
  };
@@ -741,7 +764,8 @@ function TreeSelect({
741
764
  levelConfig,
742
765
  defaultExpanded,
743
766
  expanded,
744
- onExpandedChange
767
+ onExpandedChange,
768
+ renderAdditionalActionsMenu
745
769
  }) {
746
770
  var _a, _b;
747
771
  const [uncontrolledExpandedIds, setExpandedIds] = (0, import_react3.useState)(
@@ -1111,6 +1135,13 @@ function TreeSelect({
1111
1135
  ) : null,
1112
1136
  visibleItems.map((item) => {
1113
1137
  const levelSettings = resolvedLevelConfig(item.depth);
1138
+ const additionalActionsMenu = renderAdditionalActionsMenu == null ? void 0 : renderAdditionalActionsMenu({
1139
+ id: item.id,
1140
+ node: item.node,
1141
+ depth: item.depth,
1142
+ parentId: item.parentId,
1143
+ hasChildren: item.hasChildren
1144
+ });
1114
1145
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1115
1146
  TreeSortableRow,
1116
1147
  {
@@ -1142,7 +1173,8 @@ function TreeSelect({
1142
1173
  addSiblingTooltip: levelSettings.tooltips.addSibling,
1143
1174
  canDelete: levelSettings.actions.delete,
1144
1175
  onDelete: handleDelete,
1145
- deleteTooltip: levelSettings.tooltips.delete
1176
+ deleteTooltip: levelSettings.tooltips.delete,
1177
+ additionalActionsMenu
1146
1178
  },
1147
1179
  item.id
1148
1180
  );
@@ -1151,10 +1183,10 @@ function TreeSelect({
1151
1183
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_core.DragOverlay, { children: activeId ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1152
1184
  "div",
1153
1185
  {
1186
+ className: "border border-border-subtle bg-bg-base text-fg-base",
1154
1187
  style: {
1155
1188
  padding: "6px 8px",
1156
1189
  borderRadius: 6,
1157
- background: "white",
1158
1190
  boxShadow: "0 8px 24px rgba(0, 0, 0, 0.12)"
1159
1191
  },
1160
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
@@ -1164,6 +1196,13 @@ function TreeSelect({
1164
1196
  }
1165
1197
  ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref: listRef, style: { position: "relative" }, children: visibleItems.map((item) => {
1166
1198
  const levelSettings = resolvedLevelConfig(item.depth);
1199
+ const additionalActionsMenu = renderAdditionalActionsMenu == null ? void 0 : renderAdditionalActionsMenu({
1200
+ id: item.id,
1201
+ node: item.node,
1202
+ depth: item.depth,
1203
+ parentId: item.parentId,
1204
+ hasChildren: item.hasChildren
1205
+ });
1167
1206
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1168
1207
  TreeRow,
1169
1208
  {
@@ -1194,7 +1233,8 @@ function TreeSelect({
1194
1233
  addSiblingTooltip: levelSettings.tooltips.addSibling,
1195
1234
  canDelete: levelSettings.actions.delete,
1196
1235
  onDelete: handleDelete,
1197
- deleteTooltip: levelSettings.tooltips.delete
1236
+ deleteTooltip: levelSettings.tooltips.delete,
1237
+ additionalActionsMenu
1198
1238
  },
1199
1239
  item.id
1200
1240
  );
package/dist/index.mjs CHANGED
@@ -15,7 +15,15 @@ import { TooltipProvider } from "@edux-design/tooltips";
15
15
  import React from "react";
16
16
  import { Checkbox, Field, Label } from "@edux-design/forms";
17
17
  import { IconButton } from "@edux-design/buttons";
18
- import { Chevron, Close, Draghandle, List, Plus } from "@edux-design/icons";
18
+ import {
19
+ Chevron,
20
+ Close,
21
+ Draghandle,
22
+ List,
23
+ MeatballVertical,
24
+ Plus
25
+ } from "@edux-design/icons";
26
+ import { Menu } from "@edux-design/menus";
19
27
  import {
20
28
  Tooltip,
21
29
  TooltipContent,
@@ -61,14 +69,17 @@ var TreeRow = ({
61
69
  addSiblingTooltip,
62
70
  canDelete,
63
71
  onDelete,
64
- deleteTooltip
72
+ deleteTooltip,
73
+ additionalActionsMenu
65
74
  }) => {
66
75
  const toggleLabel = isExpanded ? "Collapse item" : "Expand item";
67
76
  const label = item.node.label ?? item.node.id;
68
77
  const showToggle = item.hasChildren;
78
+ const [additionalMenuOpen, setAdditionalMenuOpen] = React.useState(false);
69
79
  const rowBackground = isDragging ? "rgba(0, 0, 0, 0.04)" : isSelected ? "rgba(15, 98, 254, 0.08)" : void 0;
70
- const rowPaddingLeft = depth * INDENT_WIDTH + 8 + (isDraggable ? 0 : HANDLE_WIDTH + 8);
71
- const showActions = canAddChild || canAddSibling || canDelete;
80
+ const rowPaddingLeft = depth * INDENT_WIDTH + 8;
81
+ const hasAdditionalActionsMenu = Boolean(additionalActionsMenu);
82
+ const showActions = canAddChild || canAddSibling || canDelete || hasAdditionalActionsMenu;
72
83
  const actionsStyle = {
73
84
  display: "flex",
74
85
  gap: 4,
@@ -109,14 +120,13 @@ var TreeRow = ({
109
120
  ref: dragRef,
110
121
  "aria-label": "Drag item",
111
122
  onClick: (event) => event.stopPropagation(),
123
+ className: "border border-border-subtle bg-bg-base text-fg-base",
112
124
  style: {
113
125
  width: HANDLE_WIDTH,
114
126
  height: HANDLE_WIDTH,
115
127
  display: "grid",
116
128
  placeItems: "center",
117
- border: "1px solid rgba(0, 0, 0, 0.2)",
118
129
  borderRadius: 6,
119
- background: "white",
120
130
  cursor: "grab",
121
131
  fontSize: 12,
122
132
  lineHeight: 1
@@ -240,7 +250,25 @@ var TreeRow = ({
240
250
  }
241
251
  ) }),
242
252
  /* @__PURE__ */ jsx(TooltipContent, { children: deleteTooltip ?? "Delete item" })
243
- ] }) : null
253
+ ] }) : null,
254
+ hasAdditionalActionsMenu ? /* @__PURE__ */ jsx(
255
+ Menu,
256
+ {
257
+ align: "end",
258
+ open: additionalMenuOpen,
259
+ onOpenChange: setAdditionalMenuOpen,
260
+ button: /* @__PURE__ */ jsx(
261
+ IconButton,
262
+ {
263
+ size: "small",
264
+ isBare: true,
265
+ icon: /* @__PURE__ */ jsx(MeatballVertical, { "aria-hidden": "true" }),
266
+ "aria-label": "More actions"
267
+ }
268
+ ),
269
+ children: /* @__PURE__ */ jsx("div", { onClick: () => setAdditionalMenuOpen(false), children: additionalActionsMenu })
270
+ }
271
+ ) : null
244
272
  ]
245
273
  }
246
274
  ) : null
@@ -280,7 +308,8 @@ var TreeSortableRow = ({
280
308
  addSiblingTooltip,
281
309
  canDelete,
282
310
  onDelete,
283
- deleteTooltip
311
+ deleteTooltip,
312
+ additionalActionsMenu
284
313
  }) => {
285
314
  const {
286
315
  attributes,
@@ -343,7 +372,8 @@ var TreeSortableRow = ({
343
372
  addSiblingTooltip,
344
373
  canDelete,
345
374
  onDelete,
346
- deleteTooltip
375
+ deleteTooltip,
376
+ additionalActionsMenu
347
377
  }
348
378
  );
349
379
  };
@@ -717,7 +747,8 @@ function TreeSelect({
717
747
  levelConfig,
718
748
  defaultExpanded,
719
749
  expanded,
720
- onExpandedChange
750
+ onExpandedChange,
751
+ renderAdditionalActionsMenu
721
752
  }) {
722
753
  var _a, _b;
723
754
  const [uncontrolledExpandedIds, setExpandedIds] = useState(
@@ -1087,6 +1118,13 @@ function TreeSelect({
1087
1118
  ) : null,
1088
1119
  visibleItems.map((item) => {
1089
1120
  const levelSettings = resolvedLevelConfig(item.depth);
1121
+ const additionalActionsMenu = renderAdditionalActionsMenu == null ? void 0 : renderAdditionalActionsMenu({
1122
+ id: item.id,
1123
+ node: item.node,
1124
+ depth: item.depth,
1125
+ parentId: item.parentId,
1126
+ hasChildren: item.hasChildren
1127
+ });
1090
1128
  return /* @__PURE__ */ jsx3(
1091
1129
  TreeSortableRow,
1092
1130
  {
@@ -1118,7 +1156,8 @@ function TreeSelect({
1118
1156
  addSiblingTooltip: levelSettings.tooltips.addSibling,
1119
1157
  canDelete: levelSettings.actions.delete,
1120
1158
  onDelete: handleDelete,
1121
- deleteTooltip: levelSettings.tooltips.delete
1159
+ deleteTooltip: levelSettings.tooltips.delete,
1160
+ additionalActionsMenu
1122
1161
  },
1123
1162
  item.id
1124
1163
  );
@@ -1127,10 +1166,10 @@ function TreeSelect({
1127
1166
  /* @__PURE__ */ jsx3(DragOverlay, { children: activeId ? /* @__PURE__ */ jsx3(
1128
1167
  "div",
1129
1168
  {
1169
+ className: "border border-border-subtle bg-bg-base text-fg-base",
1130
1170
  style: {
1131
1171
  padding: "6px 8px",
1132
1172
  borderRadius: 6,
1133
- background: "white",
1134
1173
  boxShadow: "0 8px 24px rgba(0, 0, 0, 0.12)"
1135
1174
  },
1136
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
@@ -1140,6 +1179,13 @@ function TreeSelect({
1140
1179
  }
1141
1180
  ) : /* @__PURE__ */ jsx3("div", { ref: listRef, style: { position: "relative" }, children: visibleItems.map((item) => {
1142
1181
  const levelSettings = resolvedLevelConfig(item.depth);
1182
+ const additionalActionsMenu = renderAdditionalActionsMenu == null ? void 0 : renderAdditionalActionsMenu({
1183
+ id: item.id,
1184
+ node: item.node,
1185
+ depth: item.depth,
1186
+ parentId: item.parentId,
1187
+ hasChildren: item.hasChildren
1188
+ });
1143
1189
  return /* @__PURE__ */ jsx3(
1144
1190
  TreeRow,
1145
1191
  {
@@ -1170,7 +1216,8 @@ function TreeSelect({
1170
1216
  addSiblingTooltip: levelSettings.tooltips.addSibling,
1171
1217
  canDelete: levelSettings.actions.delete,
1172
1218
  onDelete: handleDelete,
1173
- deleteTooltip: levelSettings.tooltips.delete
1219
+ deleteTooltip: levelSettings.tooltips.delete,
1220
+ additionalActionsMenu
1174
1221
  },
1175
1222
  item.id
1176
1223
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edux-design/tree-select",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "private": false,
5
5
  "sideEffects": [
6
6
  "**/*.css"
@@ -29,6 +29,7 @@
29
29
  "@edux-design/buttons": "*",
30
30
  "@edux-design/forms": "*",
31
31
  "@edux-design/icons": "*",
32
+ "@edux-design/menus": "*",
32
33
  "@edux-design/tooltips": "*",
33
34
  "@edux-design/utils": "*"
34
35
  },