@mui/x-tree-view 7.12.1 → 7.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/RichTreeView/RichTreeView.js +20 -2
  3. package/RichTreeView/RichTreeView.plugins.d.ts +3 -2
  4. package/RichTreeView/RichTreeView.plugins.js +2 -1
  5. package/TreeItem/TreeItem.js +24 -0
  6. package/TreeItem/TreeItemContent.d.ts +8 -0
  7. package/TreeItem/TreeItemContent.js +48 -8
  8. package/TreeItem/treeItemClasses.d.ts +6 -0
  9. package/TreeItem/treeItemClasses.js +1 -1
  10. package/TreeItem/useTreeItemState.d.ts +6 -0
  11. package/TreeItem/useTreeItemState.js +46 -1
  12. package/TreeItem2/TreeItem2.d.ts +3 -1
  13. package/TreeItem2/TreeItem2.js +29 -5
  14. package/TreeItem2/TreeItem2.types.d.ts +6 -0
  15. package/TreeItem2Icon/TreeItem2Icon.js +2 -0
  16. package/TreeItem2LabelInput/TreeItem2LabelInput.d.ts +2 -0
  17. package/TreeItem2LabelInput/TreeItem2LabelInput.js +20 -0
  18. package/TreeItem2LabelInput/TreeItem2LabelInput.types.d.ts +8 -0
  19. package/TreeItem2LabelInput/TreeItem2LabelInput.types.js +1 -0
  20. package/TreeItem2LabelInput/index.d.ts +2 -0
  21. package/TreeItem2LabelInput/index.js +1 -0
  22. package/TreeItem2LabelInput/package.json +6 -0
  23. package/hooks/useTreeItem2Utils/useTreeItem2Utils.d.ts +5 -1
  24. package/hooks/useTreeItem2Utils/useTreeItem2Utils.js +45 -2
  25. package/hooks/useTreeViewApiRef.d.ts +1 -1
  26. package/index.js +1 -1
  27. package/internals/index.d.ts +2 -0
  28. package/internals/index.js +1 -0
  29. package/internals/models/itemPlugin.d.ts +2 -1
  30. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +4 -1
  31. package/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.types.d.ts +2 -0
  32. package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +5 -1
  33. package/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.types.d.ts +2 -0
  34. package/internals/plugins/useTreeViewLabel/index.d.ts +2 -0
  35. package/internals/plugins/useTreeViewLabel/index.js +1 -0
  36. package/internals/plugins/useTreeViewLabel/useTreeViewLabel.d.ts +3 -0
  37. package/internals/plugins/useTreeViewLabel/useTreeViewLabel.itemPlugin.d.ts +3 -0
  38. package/internals/plugins/useTreeViewLabel/useTreeViewLabel.itemPlugin.js +44 -0
  39. package/internals/plugins/useTreeViewLabel/useTreeViewLabel.js +81 -0
  40. package/internals/plugins/useTreeViewLabel/useTreeViewLabel.types.d.ts +75 -0
  41. package/internals/plugins/useTreeViewLabel/useTreeViewLabel.types.js +1 -0
  42. package/modern/RichTreeView/RichTreeView.js +20 -2
  43. package/modern/RichTreeView/RichTreeView.plugins.js +2 -1
  44. package/modern/TreeItem/TreeItem.js +24 -0
  45. package/modern/TreeItem/TreeItemContent.js +48 -8
  46. package/modern/TreeItem/treeItemClasses.js +1 -1
  47. package/modern/TreeItem/useTreeItemState.js +46 -1
  48. package/modern/TreeItem2/TreeItem2.js +29 -5
  49. package/modern/TreeItem2Icon/TreeItem2Icon.js +2 -0
  50. package/modern/TreeItem2LabelInput/TreeItem2LabelInput.js +20 -0
  51. package/modern/TreeItem2LabelInput/TreeItem2LabelInput.types.js +1 -0
  52. package/modern/TreeItem2LabelInput/index.js +1 -0
  53. package/modern/hooks/useTreeItem2Utils/useTreeItem2Utils.js +45 -2
  54. package/modern/index.js +1 -1
  55. package/modern/internals/index.js +1 -0
  56. package/modern/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +4 -1
  57. package/modern/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +5 -1
  58. package/modern/internals/plugins/useTreeViewLabel/index.js +1 -0
  59. package/modern/internals/plugins/useTreeViewLabel/useTreeViewLabel.itemPlugin.js +44 -0
  60. package/modern/internals/plugins/useTreeViewLabel/useTreeViewLabel.js +81 -0
  61. package/modern/internals/plugins/useTreeViewLabel/useTreeViewLabel.types.js +1 -0
  62. package/modern/useTreeItem2/useTreeItem2.js +65 -4
  63. package/node/RichTreeView/RichTreeView.js +20 -2
  64. package/node/RichTreeView/RichTreeView.plugins.js +2 -1
  65. package/node/TreeItem/TreeItem.js +24 -0
  66. package/node/TreeItem/TreeItemContent.js +48 -8
  67. package/node/TreeItem/treeItemClasses.js +1 -1
  68. package/node/TreeItem/useTreeItemState.js +46 -1
  69. package/node/TreeItem2/TreeItem2.js +29 -5
  70. package/node/TreeItem2Icon/TreeItem2Icon.js +2 -0
  71. package/node/TreeItem2LabelInput/TreeItem2LabelInput.js +26 -0
  72. package/node/TreeItem2LabelInput/TreeItem2LabelInput.types.js +5 -0
  73. package/node/TreeItem2LabelInput/index.js +12 -0
  74. package/node/hooks/useTreeItem2Utils/useTreeItem2Utils.js +45 -2
  75. package/node/index.js +1 -1
  76. package/node/internals/index.js +7 -0
  77. package/node/internals/plugins/useTreeViewExpansion/useTreeViewExpansion.js +4 -1
  78. package/node/internals/plugins/useTreeViewKeyboardNavigation/useTreeViewKeyboardNavigation.js +5 -1
  79. package/node/internals/plugins/useTreeViewLabel/index.js +12 -0
  80. package/node/internals/plugins/useTreeViewLabel/useTreeViewLabel.itemPlugin.js +54 -0
  81. package/node/internals/plugins/useTreeViewLabel/useTreeViewLabel.js +91 -0
  82. package/node/internals/plugins/useTreeViewLabel/useTreeViewLabel.types.js +5 -0
  83. package/node/useTreeItem2/useTreeItem2.js +65 -4
  84. package/package.json +2 -2
  85. package/useTreeItem2/index.d.ts +1 -1
  86. package/useTreeItem2/useTreeItem2.js +65 -4
  87. package/useTreeItem2/useTreeItem2.types.d.ts +35 -15
@@ -5,6 +5,7 @@ import useForkRef from '@mui/utils/useForkRef';
5
5
  import { useTreeViewContext } from '../internals/TreeViewProvider';
6
6
  import { useTreeItem2Utils } from '../hooks/useTreeItem2Utils';
7
7
  import { TreeViewItemDepthContext } from '../internals/TreeViewItemDepthContext';
8
+ import { isTargetInDescendants } from '../internals/utils/tree';
8
9
  export const useTreeItem2 = parameters => {
9
10
  const {
10
11
  runItemPlugins,
@@ -50,6 +51,7 @@ export const useTreeItem2 = parameters => {
50
51
  const handleRootRef = useForkRef(rootRef, pluginRootRef, rootRefObject);
51
52
  const handleContentRef = useForkRef(contentRef, contentRefObject);
52
53
  const checkboxRef = React.useRef(null);
54
+ const rootTabIndex = instance.canItemBeTabbed(itemId) ? 0 : -1;
53
55
  const createRootHandleFocus = otherHandlers => event => {
54
56
  otherHandlers.onFocus?.(event);
55
57
  if (event.defaultMuiPrevented) {
@@ -65,15 +67,33 @@ export const useTreeItem2 = parameters => {
65
67
  if (event.defaultMuiPrevented) {
66
68
  return;
67
69
  }
70
+ const rootElement = instance.getItemDOMElement(itemId);
71
+
72
+ // Don't blur the root when switching to editing mode
73
+ // the input that triggers the root blur can be either the relatedTarget (when entering editing state) or the target (when exiting editing state)
74
+ // when we enter the editing state, we focus the input -> we don't want to remove the focused item from the state
75
+ if (status.editing ||
76
+ // we can exit the editing state by clicking outside the input (within the tree item) or by pressing Enter or Escape -> we don't want to remove the focused item from the state in these cases
77
+ // we can also exit the editing state by clicking on the root itself -> want to remove the focused item from the state in this case
78
+ event.relatedTarget && isTargetInDescendants(event.relatedTarget, rootElement) && (event.target && event.target?.dataset?.element === 'labelInput' && isTargetInDescendants(event.target, rootElement) || event.relatedTarget?.dataset?.element === 'labelInput')) {
79
+ return;
80
+ }
68
81
  instance.removeFocusedItem();
69
82
  };
70
83
  const createRootHandleKeyDown = otherHandlers => event => {
71
84
  otherHandlers.onKeyDown?.(event);
72
- if (event.defaultMuiPrevented) {
85
+ if (event.defaultMuiPrevented || event.target?.dataset?.element === 'labelInput') {
73
86
  return;
74
87
  }
75
88
  instance.handleItemKeyDown(event, itemId);
76
89
  };
90
+ const createLabelHandleDoubleClick = otherHandlers => event => {
91
+ otherHandlers.onDoubleClick?.(event);
92
+ if (event.defaultMuiPrevented) {
93
+ return;
94
+ }
95
+ interactions.toggleItemEditing();
96
+ };
77
97
  const createContentHandleClick = otherHandlers => event => {
78
98
  otherHandlers.onClick?.(event);
79
99
  onItemClick?.(event, itemId);
@@ -108,6 +128,27 @@ export const useTreeItem2 = parameters => {
108
128
  }
109
129
  interactions.handleCheckboxSelection(event);
110
130
  };
131
+ const createInputHandleKeydown = otherHandlers => event => {
132
+ otherHandlers.onKeyDown?.(event);
133
+ if (event.defaultMuiPrevented) {
134
+ return;
135
+ }
136
+ const target = event.target;
137
+ if (event.key === 'Enter' && target.value) {
138
+ interactions.handleSaveItemLabel(event, target.value);
139
+ } else if (event.key === 'Escape') {
140
+ interactions.handleCancelItemLabelEditing(event);
141
+ }
142
+ };
143
+ const createInputHandleBlur = otherHandlers => event => {
144
+ otherHandlers.onBlur?.(event);
145
+ if (event.defaultMuiPrevented) {
146
+ return;
147
+ }
148
+ if (event.target.value) {
149
+ interactions.handleSaveItemLabel(event, event.target.value);
150
+ }
151
+ };
111
152
  const createIconContainerHandleClick = otherHandlers => event => {
112
153
  otherHandlers.onClick?.(event);
113
154
  if (event.defaultMuiPrevented) {
@@ -134,7 +175,7 @@ export const useTreeItem2 = parameters => {
134
175
  const props = _extends({}, externalEventHandlers, {
135
176
  ref: handleRootRef,
136
177
  role: 'treeitem',
137
- tabIndex: instance.canItemBeTabbed(itemId) ? 0 : -1,
178
+ tabIndex: rootTabIndex,
138
179
  id: idAttribute,
139
180
  'aria-expanded': status.expandable ? status.expanded : undefined,
140
181
  'aria-selected': ariaSelected,
@@ -188,9 +229,28 @@ export const useTreeItem2 = parameters => {
188
229
  };
189
230
  const getLabelProps = (externalProps = {}) => {
190
231
  const externalEventHandlers = _extends({}, extractEventHandlers(externalProps));
191
- return _extends({}, externalEventHandlers, {
232
+ const props = _extends({}, externalEventHandlers, {
192
233
  children: label
193
- }, externalProps);
234
+ }, externalProps, {
235
+ onDoubleClick: createLabelHandleDoubleClick(externalEventHandlers)
236
+ });
237
+ if (instance.isTreeViewEditable) {
238
+ props.editable = status.editable;
239
+ }
240
+ return props;
241
+ };
242
+ const getLabelInputProps = (externalProps = {}) => {
243
+ const externalEventHandlers = extractEventHandlers(externalProps);
244
+ const props = _extends({}, externalEventHandlers, externalProps, {
245
+ onKeyDown: createInputHandleKeydown(externalEventHandlers),
246
+ onBlur: createInputHandleBlur(externalEventHandlers)
247
+ });
248
+ const enhancedlabelInputProps = propsEnhancers.labelInput?.({
249
+ rootRefObject,
250
+ contentRefObject,
251
+ externalEventHandlers
252
+ }) ?? {};
253
+ return _extends({}, props, enhancedlabelInputProps);
194
254
  };
195
255
  const getIconContainerProps = (externalProps = {}) => {
196
256
  const externalEventHandlers = extractEventHandlers(externalProps);
@@ -228,6 +288,7 @@ export const useTreeItem2 = parameters => {
228
288
  getIconContainerProps,
229
289
  getCheckboxProps,
230
290
  getLabelProps,
291
+ getLabelInputProps,
231
292
  getDragAndDropOverlayProps,
232
293
  rootRef: handleRootRef,
233
294
  status,
@@ -149,7 +149,8 @@ process.env.NODE_ENV !== "production" ? RichTreeView.propTypes = {
149
149
  getItemOrderedChildrenIds: _propTypes.default.func.isRequired,
150
150
  getItemTree: _propTypes.default.func.isRequired,
151
151
  selectItem: _propTypes.default.func.isRequired,
152
- setItemExpansion: _propTypes.default.func.isRequired
152
+ setItemExpansion: _propTypes.default.func.isRequired,
153
+ updateItemLabel: _propTypes.default.func.isRequired
153
154
  })
154
155
  }),
155
156
  /**
@@ -200,7 +201,8 @@ process.env.NODE_ENV !== "production" ? RichTreeView.propTypes = {
200
201
  * the feature will be fully disabled and any property / method call will not have any effect.
201
202
  */
202
203
  experimentalFeatures: _propTypes.default.shape({
203
- indentationAtItemLevel: _propTypes.default.bool
204
+ indentationAtItemLevel: _propTypes.default.bool,
205
+ labelEditing: _propTypes.default.bool
204
206
  }),
205
207
  /**
206
208
  * Used to determine the id of a given item.
@@ -232,6 +234,16 @@ process.env.NODE_ENV !== "production" ? RichTreeView.propTypes = {
232
234
  * @returns {boolean} `true` if the item should be disabled.
233
235
  */
234
236
  isItemDisabled: _propTypes.default.func,
237
+ /**
238
+ * Determines if a given item is editable or not.
239
+ * Make sure to also enable the `labelEditing` experimental feature:
240
+ * `<RichTreeViewPro experimentalFeatures={{ labelEditing: true }} />`.
241
+ * By default, the items are not editable.
242
+ * @template R
243
+ * @param {R} item The item to check.
244
+ * @returns {boolean} `true` if the item is editable.
245
+ */
246
+ isItemEditable: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.bool]),
235
247
  /**
236
248
  * Horizontal indentation between an item and its children.
237
249
  * Examples: 24, "24px", "2rem", "2em".
@@ -269,6 +281,12 @@ process.env.NODE_ENV !== "production" ? RichTreeView.propTypes = {
269
281
  * @param {string} itemId The id of the focused item.
270
282
  */
271
283
  onItemFocus: _propTypes.default.func,
284
+ /**
285
+ * Callback fired when the label of an item changes.
286
+ * @param {TreeViewItemId} itemId The id of the item that was edited.
287
+ * @param {string} newLabel The new label of the items.
288
+ */
289
+ onItemLabelChange: _propTypes.default.func,
272
290
  /**
273
291
  * Callback fired when a tree item is selected or deselected.
274
292
  * @param {React.SyntheticEvent} event The DOM event that triggered the change.
@@ -10,6 +10,7 @@ var _useTreeViewSelection = require("../internals/plugins/useTreeViewSelection")
10
10
  var _useTreeViewFocus = require("../internals/plugins/useTreeViewFocus");
11
11
  var _useTreeViewKeyboardNavigation = require("../internals/plugins/useTreeViewKeyboardNavigation");
12
12
  var _useTreeViewIcons = require("../internals/plugins/useTreeViewIcons");
13
- const RICH_TREE_VIEW_PLUGINS = exports.RICH_TREE_VIEW_PLUGINS = [_useTreeViewItems.useTreeViewItems, _useTreeViewExpansion.useTreeViewExpansion, _useTreeViewSelection.useTreeViewSelection, _useTreeViewFocus.useTreeViewFocus, _useTreeViewKeyboardNavigation.useTreeViewKeyboardNavigation, _useTreeViewIcons.useTreeViewIcons];
13
+ var _useTreeViewLabel = require("../internals/plugins/useTreeViewLabel");
14
+ const RICH_TREE_VIEW_PLUGINS = exports.RICH_TREE_VIEW_PLUGINS = [_useTreeViewItems.useTreeViewItems, _useTreeViewExpansion.useTreeViewExpansion, _useTreeViewSelection.useTreeViewSelection, _useTreeViewFocus.useTreeViewFocus, _useTreeViewKeyboardNavigation.useTreeViewKeyboardNavigation, _useTreeViewIcons.useTreeViewIcons, _useTreeViewLabel.useTreeViewLabel];
14
15
 
15
16
  // We can't infer this type from the plugin, otherwise we would lose the generics.
@@ -28,6 +28,7 @@ var _icons = require("../icons");
28
28
  var _TreeItem2Provider = require("../TreeItem2Provider");
29
29
  var _TreeViewItemDepthContext = require("../internals/TreeViewItemDepthContext");
30
30
  var _useTreeItemState = require("./useTreeItemState");
31
+ var _tree = require("../internals/utils/tree");
31
32
  var _jsxRuntime = require("react/jsx-runtime");
32
33
  const _excluded = ["children", "className", "slots", "slotProps", "ContentComponent", "ContentProps", "itemId", "id", "label", "onClick", "onMouseDown", "onFocus", "onBlur", "onKeyDown"],
33
34
  _excluded2 = ["ownerState"],
@@ -50,6 +51,9 @@ const useUtilityClasses = ownerState => {
50
51
  iconContainer: ['iconContainer'],
51
52
  checkbox: ['checkbox'],
52
53
  label: ['label'],
54
+ labelInput: ['labelInput'],
55
+ editing: ['editing'],
56
+ editable: ['editable'],
53
57
  groupTransition: ['groupTransition']
54
58
  };
55
59
  return (0, _composeClasses.default)(slots, _treeItemClasses.getTreeItemUtilityClass, classes);
@@ -216,6 +220,7 @@ const TreeItem = exports.TreeItem = /*#__PURE__*/React.forwardRef(function TreeI
216
220
  focused,
217
221
  selected,
218
222
  disabled,
223
+ editing,
219
224
  handleExpansion
220
225
  } = (0, _useTreeItemState.useTreeItemState)(itemId);
221
226
  const {
@@ -326,10 +331,19 @@ const TreeItem = exports.TreeItem = /*#__PURE__*/React.forwardRef(function TreeI
326
331
  }
327
332
  function handleBlur(event) {
328
333
  onBlur?.(event);
334
+ if (editing ||
335
+ // we can exit the editing state by clicking outside the input (within the tree item) or by pressing Enter or Escape -> we don't want to remove the focused item from the state in these cases
336
+ // we can also exit the editing state by clicking on the root itself -> want to remove the focused item from the state in this case
337
+ event.relatedTarget && (0, _tree.isTargetInDescendants)(event.relatedTarget, rootRefObject.current) && (event.target && event.target?.dataset?.element === 'labelInput' && (0, _tree.isTargetInDescendants)(event.target, rootRefObject.current) || event.relatedTarget?.dataset?.element === 'labelInput')) {
338
+ return;
339
+ }
329
340
  instance.removeFocusedItem();
330
341
  }
331
342
  const handleKeyDown = event => {
332
343
  onKeyDown?.(event);
344
+ if (event.target?.dataset?.element === 'labelInput') {
345
+ return;
346
+ }
333
347
  instance.handleItemKeyDown(event, itemId);
334
348
  };
335
349
  const idAttribute = instance.getTreeItemIdAttribute(itemId, id);
@@ -349,6 +363,11 @@ const TreeItem = exports.TreeItem = /*#__PURE__*/React.forwardRef(function TreeI
349
363
  contentRefObject,
350
364
  externalEventHandlers: {}
351
365
  }) ?? {};
366
+ const enhancedLabelInputProps = propsEnhancers.labelInput?.({
367
+ rootRefObject,
368
+ contentRefObject,
369
+ externalEventHandlers: {}
370
+ }) ?? {};
352
371
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_TreeItem2Provider.TreeItem2Provider, {
353
372
  itemId: itemId,
354
373
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(TreeItemRoot, (0, _extends2.default)({
@@ -377,8 +396,11 @@ const TreeItem = exports.TreeItem = /*#__PURE__*/React.forwardRef(function TreeI
377
396
  selected: classes.selected,
378
397
  focused: classes.focused,
379
398
  disabled: classes.disabled,
399
+ editable: classes.editable,
400
+ editing: classes.editing,
380
401
  iconContainer: classes.iconContainer,
381
402
  label: classes.label,
403
+ labelInput: classes.labelInput,
382
404
  checkbox: classes.checkbox
383
405
  },
384
406
  label: label,
@@ -391,6 +413,8 @@ const TreeItem = exports.TreeItem = /*#__PURE__*/React.forwardRef(function TreeI
391
413
  ownerState: ownerState
392
414
  }, ContentProps, enhancedContentProps, enhancedDragAndDropOverlayProps.action == null ? {} : {
393
415
  dragAndDropOverlayProps: enhancedDragAndDropOverlayProps
416
+ }, enhancedLabelInputProps.value == null ? {} : {
417
+ labelInputProps: enhancedLabelInputProps
394
418
  }, {
395
419
  ref: handleContentRef
396
420
  })), children && /*#__PURE__*/(0, _jsxRuntime.jsx)(TreeItemGroup, (0, _extends2.default)({
@@ -13,8 +13,9 @@ var _clsx = _interopRequireDefault(require("clsx"));
13
13
  var _Checkbox = _interopRequireDefault(require("@mui/material/Checkbox"));
14
14
  var _useTreeItemState = require("./useTreeItemState");
15
15
  var _TreeItem2DragAndDropOverlay = require("../TreeItem2DragAndDropOverlay");
16
+ var _TreeItem2LabelInput = require("../TreeItem2LabelInput");
16
17
  var _jsxRuntime = require("react/jsx-runtime");
17
- const _excluded = ["classes", "className", "displayIcon", "expansionIcon", "icon", "label", "itemId", "onClick", "onMouseDown", "dragAndDropOverlayProps"];
18
+ const _excluded = ["classes", "className", "displayIcon", "expansionIcon", "icon", "label", "itemId", "onClick", "onMouseDown", "dragAndDropOverlayProps", "labelInputProps"];
18
19
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
19
20
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
20
21
  /**
@@ -31,7 +32,8 @@ const TreeItemContent = exports.TreeItemContent = /*#__PURE__*/React.forwardRef(
31
32
  itemId,
32
33
  onClick,
33
34
  onMouseDown,
34
- dragAndDropOverlayProps
35
+ dragAndDropOverlayProps,
36
+ labelInputProps
35
37
  } = props,
36
38
  other = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded);
37
39
  const {
@@ -39,6 +41,8 @@ const TreeItemContent = exports.TreeItemContent = /*#__PURE__*/React.forwardRef(
39
41
  expanded,
40
42
  selected,
41
43
  focused,
44
+ editing,
45
+ editable,
42
46
  disableSelection,
43
47
  checkboxSelection,
44
48
  handleExpansion,
@@ -46,7 +50,10 @@ const TreeItemContent = exports.TreeItemContent = /*#__PURE__*/React.forwardRef(
46
50
  handleCheckboxSelection,
47
51
  handleContentClick,
48
52
  preventSelection,
49
- expansionTrigger
53
+ expansionTrigger,
54
+ toggleItemEditing,
55
+ handleSaveItemLabel,
56
+ handleCancelItemLabelEditing
50
57
  } = (0, _useTreeItemState.useTreeItemState)(itemId);
51
58
  const icon = iconProp || expansionIcon || displayIcon;
52
59
  const checkboxRef = React.useRef(null);
@@ -71,11 +78,36 @@ const TreeItemContent = exports.TreeItemContent = /*#__PURE__*/React.forwardRef(
71
78
  onClick(event);
72
79
  }
73
80
  };
81
+ const handleLabelDoubleClick = event => {
82
+ if (event.defaultMuiPrevented) {
83
+ return;
84
+ }
85
+ toggleItemEditing();
86
+ };
87
+ const handleLabelInputBlur = event => {
88
+ if (event.defaultMuiPrevented) {
89
+ return;
90
+ }
91
+ if (event.target.value) {
92
+ handleSaveItemLabel(event, event.target.value);
93
+ }
94
+ };
95
+ const handleLabelInputKeydown = event => {
96
+ if (event.defaultMuiPrevented) {
97
+ return;
98
+ }
99
+ const target = event.target;
100
+ if (event.key === 'Enter' && target.value) {
101
+ handleSaveItemLabel(event, target.value);
102
+ } else if (event.key === 'Escape') {
103
+ handleCancelItemLabelEditing(event);
104
+ }
105
+ };
74
106
  return (
75
107
  /*#__PURE__*/
76
108
  /* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions -- Key event is handled by the TreeView */
77
109
  (0, _jsxRuntime.jsxs)("div", (0, _extends2.default)({}, other, {
78
- className: (0, _clsx.default)(className, classes.root, expanded && classes.expanded, selected && classes.selected, focused && classes.focused, disabled && classes.disabled),
110
+ className: (0, _clsx.default)(className, classes.root, expanded && classes.expanded, selected && classes.selected, focused && classes.focused, disabled && classes.disabled, editing && classes.editing, editable && classes.editable),
79
111
  onClick: handleClick,
80
112
  onMouseDown: handleMouseDown,
81
113
  ref: ref,
@@ -89,10 +121,17 @@ const TreeItemContent = exports.TreeItemContent = /*#__PURE__*/React.forwardRef(
89
121
  disabled: disabled || disableSelection,
90
122
  ref: checkboxRef,
91
123
  tabIndex: -1
92
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
93
- className: classes.label,
124
+ }), editing ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_TreeItem2LabelInput.TreeItem2LabelInput, (0, _extends2.default)({}, labelInputProps, {
125
+ className: classes.labelInput,
126
+ onBlur: handleLabelInputBlur,
127
+ onKeyDown: handleLabelInputKeydown
128
+ })) : /*#__PURE__*/(0, _jsxRuntime.jsx)("div", (0, _extends2.default)({
129
+ className: classes.label
130
+ }, editable && {
131
+ onDoubleClick: handleLabelDoubleClick
132
+ }, {
94
133
  children: label
95
- }), dragAndDropOverlayProps && /*#__PURE__*/(0, _jsxRuntime.jsx)(_TreeItem2DragAndDropOverlay.TreeItem2DragAndDropOverlay, (0, _extends2.default)({}, dragAndDropOverlayProps))]
134
+ })), dragAndDropOverlayProps && /*#__PURE__*/(0, _jsxRuntime.jsx)(_TreeItem2DragAndDropOverlay.TreeItem2DragAndDropOverlay, (0, _extends2.default)({}, dragAndDropOverlayProps))]
96
135
  }))
97
136
  );
98
137
  });
@@ -129,5 +168,6 @@ process.env.NODE_ENV !== "production" ? TreeItemContent.propTypes = {
129
168
  /**
130
169
  * The tree item label.
131
170
  */
132
- label: _propTypes.default.node
171
+ label: _propTypes.default.node,
172
+ labelInputProps: _propTypes.default.object
133
173
  } : void 0;
@@ -11,4 +11,4 @@ var _generateUtilityClasses = _interopRequireDefault(require("@mui/utils/generat
11
11
  function getTreeItemUtilityClass(slot) {
12
12
  return (0, _generateUtilityClass.default)('MuiTreeItem', slot);
13
13
  }
14
- const treeItemClasses = exports.treeItemClasses = (0, _generateUtilityClasses.default)('MuiTreeItem', ['root', 'groupTransition', 'content', 'expanded', 'selected', 'focused', 'disabled', 'iconContainer', 'label', 'checkbox', 'dragAndDropOverlay']);
14
+ const treeItemClasses = exports.treeItemClasses = (0, _generateUtilityClasses.default)('MuiTreeItem', ['root', 'groupTransition', 'content', 'expanded', 'selected', 'focused', 'disabled', 'iconContainer', 'label', 'checkbox', 'labelInput', 'editable', 'editing', 'dragAndDropOverlay']);
@@ -5,6 +5,8 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.useTreeItemState = useTreeItemState;
7
7
  var _TreeViewProvider = require("../internals/TreeViewProvider");
8
+ var _useTreeViewLabel = require("../internals/plugins/useTreeViewLabel");
9
+ var _plugins = require("../internals/utils/plugins");
8
10
  function useTreeItemState(itemId) {
9
11
  const {
10
12
  instance,
@@ -25,6 +27,8 @@ function useTreeItemState(itemId) {
25
27
  const focused = instance.isItemFocused(itemId);
26
28
  const selected = instance.isItemSelected(itemId);
27
29
  const disabled = instance.isItemDisabled(itemId);
30
+ const editing = instance?.isItemBeingEdited ? instance?.isItemBeingEdited(itemId) : false;
31
+ const editable = instance.isItemEditable ? instance.isItemEditable(itemId) : false;
28
32
  const handleExpansion = event => {
29
33
  if (!disabled) {
30
34
  if (!focused) {
@@ -85,11 +89,49 @@ function useTreeItemState(itemId) {
85
89
  event.preventDefault();
86
90
  }
87
91
  };
92
+ const toggleItemEditing = () => {
93
+ if (!(0, _plugins.hasPlugin)(instance, _useTreeViewLabel.useTreeViewLabel)) {
94
+ return;
95
+ }
96
+ if (instance.isItemEditable(itemId)) {
97
+ if (instance.isItemBeingEdited(itemId)) {
98
+ instance.setEditedItemId(null);
99
+ } else {
100
+ instance.setEditedItemId(itemId);
101
+ }
102
+ }
103
+ };
104
+ const handleSaveItemLabel = (event, label) => {
105
+ if (!(0, _plugins.hasPlugin)(instance, _useTreeViewLabel.useTreeViewLabel)) {
106
+ return;
107
+ }
108
+
109
+ // As a side effect of `instance.focusItem` called here and in `handleCancelItemLabelEditing` the `labelInput` is blurred
110
+ // The `onBlur` event is triggered, which calls `handleSaveItemLabel` again.
111
+ // To avoid creating an unwanted behavior we need to check if the item is being edited before calling `updateItemLabel`
112
+ // using `instance.isItemBeingEditedRef` instead of `instance.isItemBeingEdited` since the state is not yet updated in this point
113
+ if (instance.isItemBeingEditedRef(itemId)) {
114
+ instance.updateItemLabel(itemId, label);
115
+ toggleItemEditing();
116
+ instance.focusItem(event, itemId);
117
+ }
118
+ };
119
+ const handleCancelItemLabelEditing = event => {
120
+ if (!(0, _plugins.hasPlugin)(instance, _useTreeViewLabel.useTreeViewLabel)) {
121
+ return;
122
+ }
123
+ if (instance.isItemBeingEditedRef(itemId)) {
124
+ toggleItemEditing();
125
+ instance.focusItem(event, itemId);
126
+ }
127
+ };
88
128
  return {
89
129
  disabled,
90
130
  expanded,
91
131
  selected,
92
132
  focused,
133
+ editable,
134
+ editing,
93
135
  disableSelection,
94
136
  checkboxSelection,
95
137
  handleExpansion,
@@ -97,6 +139,9 @@ function useTreeItemState(itemId) {
97
139
  handleCheckboxSelection,
98
140
  handleContentClick: onItemClick,
99
141
  preventSelection,
100
- expansionTrigger
142
+ expansionTrigger,
143
+ toggleItemEditing,
144
+ handleSaveItemLabel,
145
+ handleCancelItemLabelEditing
101
146
  };
102
147
  }
@@ -23,6 +23,7 @@ var _TreeItem = require("../TreeItem");
23
23
  var _TreeItem2Icon = require("../TreeItem2Icon");
24
24
  var _TreeItem2DragAndDropOverlay = require("../TreeItem2DragAndDropOverlay");
25
25
  var _TreeItem2Provider = require("../TreeItem2Provider");
26
+ var _TreeItem2LabelInput = require("../TreeItem2LabelInput");
26
27
  var _jsxRuntime = require("react/jsx-runtime");
27
28
  const _excluded = ["visible"],
28
29
  _excluded2 = ["id", "itemId", "label", "disabled", "children", "slots", "slotProps"];
@@ -113,7 +114,8 @@ const TreeItem2Content = exports.TreeItem2Content = (0, _zeroStyled.styled)('div
113
114
  const TreeItem2Label = exports.TreeItem2Label = (0, _zeroStyled.styled)('div', {
114
115
  name: 'MuiTreeItem2',
115
116
  slot: 'Label',
116
- overridesResolver: (props, styles) => styles.label
117
+ overridesResolver: (props, styles) => styles.label,
118
+ shouldForwardProp: prop => (0, _createStyled.shouldForwardProp)(prop) && prop !== 'editable'
117
119
  })(({
118
120
  theme
119
121
  }) => (0, _extends2.default)({
@@ -122,8 +124,18 @@ const TreeItem2Label = exports.TreeItem2Label = (0, _zeroStyled.styled)('div', {
122
124
  // prevent width + padding to overflow
123
125
  // fixes overflow - see https://github.com/mui/material-ui/issues/27372
124
126
  minWidth: 0,
125
- position: 'relative'
126
- }, theme.typography.body1));
127
+ position: 'relative',
128
+ overflow: 'hidden'
129
+ }, theme.typography.body1, {
130
+ variants: [{
131
+ props: ({
132
+ editable
133
+ }) => editable,
134
+ style: {
135
+ paddingLeft: '2px'
136
+ }
137
+ }]
138
+ }));
127
139
  const TreeItem2IconContainer = exports.TreeItem2IconContainer = (0, _zeroStyled.styled)('div', {
128
140
  name: 'MuiTreeItem2',
129
141
  slot: 'IconContainer',
@@ -181,6 +193,8 @@ const useUtilityClasses = ownerState => {
181
193
  root: ['root'],
182
194
  content: ['content'],
183
195
  expanded: ['expanded'],
196
+ editing: ['editing'],
197
+ editable: ['editable'],
184
198
  selected: ['selected'],
185
199
  focused: ['focused'],
186
200
  disabled: ['disabled'],
@@ -188,6 +202,7 @@ const useUtilityClasses = ownerState => {
188
202
  checkbox: ['checkbox'],
189
203
  label: ['label'],
190
204
  groupTransition: ['groupTransition'],
205
+ labelInput: ['labelInput'],
191
206
  dragAndDropOverlay: ['dragAndDropOverlay']
192
207
  };
193
208
  return (0, _composeClasses.default)(slots, _TreeItem.getTreeItemUtilityClass, classes);
@@ -224,6 +239,7 @@ const TreeItem2 = exports.TreeItem2 = /*#__PURE__*/React.forwardRef(function Tre
224
239
  getCheckboxProps,
225
240
  getLabelProps,
226
241
  getGroupTransitionProps,
242
+ getLabelInputProps,
227
243
  getDragAndDropOverlayProps,
228
244
  status
229
245
  } = (0, _useTreeItem.unstable_useTreeItem2)({
@@ -253,7 +269,7 @@ const TreeItem2 = exports.TreeItem2 = /*#__PURE__*/React.forwardRef(function Tre
253
269
  getSlotProps: getContentProps,
254
270
  externalSlotProps: slotProps.content,
255
271
  ownerState: {},
256
- className: (0, _clsx.default)(classes.content, status.expanded && classes.expanded, status.selected && classes.selected, status.focused && classes.focused, status.disabled && classes.disabled)
272
+ className: (0, _clsx.default)(classes.content, status.expanded && classes.expanded, status.selected && classes.selected, status.focused && classes.focused, status.disabled && classes.disabled, status.editing && classes.editing, status.editable && classes.editable)
257
273
  });
258
274
  const IconContainer = slots.iconContainer ?? TreeItem2IconContainer;
259
275
  const iconContainerProps = (0, _useSlotProps.default)({
@@ -287,6 +303,14 @@ const TreeItem2 = exports.TreeItem2 = /*#__PURE__*/React.forwardRef(function Tre
287
303
  ownerState: {},
288
304
  className: classes.groupTransition
289
305
  });
306
+ const LabelInput = slots.labelInput ?? _TreeItem2LabelInput.TreeItem2LabelInput;
307
+ const labelInputProps = (0, _useSlotProps.default)({
308
+ elementType: LabelInput,
309
+ getSlotProps: getLabelInputProps,
310
+ externalSlotProps: slotProps.labelInput,
311
+ ownerState: {},
312
+ className: classes.labelInput
313
+ });
290
314
  const DragAndDropOverlay = slots.dragAndDropOverlay ?? _TreeItem2DragAndDropOverlay.TreeItem2DragAndDropOverlay;
291
315
  const dragAndDropOverlayProps = (0, _useSlotProps.default)({
292
316
  elementType: DragAndDropOverlay,
@@ -305,7 +329,7 @@ const TreeItem2 = exports.TreeItem2 = /*#__PURE__*/React.forwardRef(function Tre
305
329
  slots: slots,
306
330
  slotProps: slotProps
307
331
  })
308
- })), /*#__PURE__*/(0, _jsxRuntime.jsx)(Checkbox, (0, _extends2.default)({}, checkboxProps)), /*#__PURE__*/(0, _jsxRuntime.jsx)(Label, (0, _extends2.default)({}, labelProps)), /*#__PURE__*/(0, _jsxRuntime.jsx)(DragAndDropOverlay, (0, _extends2.default)({}, dragAndDropOverlayProps))]
332
+ })), /*#__PURE__*/(0, _jsxRuntime.jsx)(Checkbox, (0, _extends2.default)({}, checkboxProps)), status.editing ? /*#__PURE__*/(0, _jsxRuntime.jsx)(LabelInput, (0, _extends2.default)({}, labelInputProps)) : /*#__PURE__*/(0, _jsxRuntime.jsx)(Label, (0, _extends2.default)({}, labelProps)), /*#__PURE__*/(0, _jsxRuntime.jsx)(DragAndDropOverlay, (0, _extends2.default)({}, dragAndDropOverlayProps))]
309
333
  })), children && /*#__PURE__*/(0, _jsxRuntime.jsx)(TreeItem2GroupTransition, (0, _extends2.default)({
310
334
  as: GroupTransition
311
335
  }, groupTransitionProps))]
@@ -68,6 +68,8 @@ process.env.NODE_ENV !== "production" ? TreeItem2Icon.propTypes = {
68
68
  slots: _propTypes.default.object,
69
69
  status: _propTypes.default.shape({
70
70
  disabled: _propTypes.default.bool.isRequired,
71
+ editable: _propTypes.default.bool.isRequired,
72
+ editing: _propTypes.default.bool.isRequired,
71
73
  expandable: _propTypes.default.bool.isRequired,
72
74
  expanded: _propTypes.default.bool.isRequired,
73
75
  focused: _propTypes.default.bool.isRequired,
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.TreeItem2LabelInput = void 0;
8
+ var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
9
+ var _zeroStyled = require("../internals/zero-styled");
10
+ const TreeItem2LabelInput = exports.TreeItem2LabelInput = (0, _zeroStyled.styled)('input', {
11
+ name: 'MuiTreeItem2',
12
+ slot: 'LabelInput',
13
+ overridesResolver: (props, styles) => styles.labelInput
14
+ })(({
15
+ theme
16
+ }) => (0, _extends2.default)({}, theme.typography.body1, {
17
+ width: '100%',
18
+ backgroundColor: theme.palette.background.paper,
19
+ borderRadius: theme.shape.borderRadius,
20
+ border: 'none',
21
+ padding: '0 2px',
22
+ boxSizing: 'border-box',
23
+ '&:focus': {
24
+ outline: `1px solid ${theme.palette.primary.main}`
25
+ }
26
+ }));
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "TreeItem2LabelInput", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _TreeItem2LabelInput.TreeItem2LabelInput;
10
+ }
11
+ });
12
+ var _TreeItem2LabelInput = require("./TreeItem2LabelInput");