@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,8 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.useTreeItem2Utils = void 0;
7
7
  var _TreeViewProvider = require("../../internals/TreeViewProvider");
8
+ var _useTreeViewLabel = require("../../internals/plugins/useTreeViewLabel");
9
+ var _plugins = require("../../internals/utils/plugins");
8
10
  const isItemExpandable = reactChildren => {
9
11
  if (Array.isArray(reactChildren)) {
10
12
  return reactChildren.length > 0 && reactChildren.some(isItemExpandable);
@@ -35,7 +37,9 @@ const useTreeItem2Utils = ({
35
37
  expanded: instance.isItemExpanded(itemId),
36
38
  focused: instance.isItemFocused(itemId),
37
39
  selected: instance.isItemSelected(itemId),
38
- disabled: instance.isItemDisabled(itemId)
40
+ disabled: instance.isItemDisabled(itemId),
41
+ editing: instance?.isItemBeingEdited ? instance?.isItemBeingEdited(itemId) : false,
42
+ editable: instance.isItemEditable ? instance.isItemEditable(itemId) : false
39
43
  };
40
44
  const handleExpansion = event => {
41
45
  if (status.disabled) {
@@ -90,10 +94,49 @@ const useTreeItem2Utils = ({
90
94
  });
91
95
  }
92
96
  };
97
+ const toggleItemEditing = () => {
98
+ if (!(0, _plugins.hasPlugin)(instance, _useTreeViewLabel.useTreeViewLabel)) {
99
+ return;
100
+ }
101
+ if (instance.isItemEditable(itemId)) {
102
+ if (instance.isItemBeingEdited(itemId)) {
103
+ instance.setEditedItemId(null);
104
+ } else {
105
+ instance.setEditedItemId(itemId);
106
+ }
107
+ }
108
+ };
109
+ const handleSaveItemLabel = (event, label) => {
110
+ if (!(0, _plugins.hasPlugin)(instance, _useTreeViewLabel.useTreeViewLabel)) {
111
+ return;
112
+ }
113
+
114
+ // As a side effect of `instance.focusItem` called here and in `handleCancelItemLabelEditing` the `labelInput` is blurred
115
+ // The `onBlur` event is triggered, which calls `handleSaveItemLabel` again.
116
+ // To avoid creating an unwanted behavior we need to check if the item is being edited before calling `updateItemLabel`
117
+ // using `instance.isItemBeingEditedRef` instead of `instance.isItemBeingEdited` since the state is not yet updated in this point
118
+ if (instance.isItemBeingEditedRef(itemId)) {
119
+ instance.updateItemLabel(itemId, label);
120
+ toggleItemEditing();
121
+ instance.focusItem(event, itemId);
122
+ }
123
+ };
124
+ const handleCancelItemLabelEditing = event => {
125
+ if (!(0, _plugins.hasPlugin)(instance, _useTreeViewLabel.useTreeViewLabel)) {
126
+ return;
127
+ }
128
+ if (instance.isItemBeingEditedRef(itemId)) {
129
+ toggleItemEditing();
130
+ instance.focusItem(event, itemId);
131
+ }
132
+ };
93
133
  const interactions = {
94
134
  handleExpansion,
95
135
  handleSelection,
96
- handleCheckboxSelection
136
+ handleCheckboxSelection,
137
+ toggleItemEditing,
138
+ handleSaveItemLabel,
139
+ handleCancelItemLabelEditing
97
140
  };
98
141
  return {
99
142
  interactions,
package/node/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-tree-view v7.12.1
2
+ * @mui/x-tree-view v7.13.0
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -81,6 +81,12 @@ Object.defineProperty(exports, "useTreeViewKeyboardNavigation", {
81
81
  return _useTreeViewKeyboardNavigation.useTreeViewKeyboardNavigation;
82
82
  }
83
83
  });
84
+ Object.defineProperty(exports, "useTreeViewLabel", {
85
+ enumerable: true,
86
+ get: function () {
87
+ return _useTreeViewLabel.useTreeViewLabel;
88
+ }
89
+ });
84
90
  Object.defineProperty(exports, "useTreeViewSelection", {
85
91
  enumerable: true,
86
92
  get: function () {
@@ -102,6 +108,7 @@ var _useTreeViewFocus = require("./plugins/useTreeViewFocus");
102
108
  var _useTreeViewKeyboardNavigation = require("./plugins/useTreeViewKeyboardNavigation");
103
109
  var _useTreeViewIcons = require("./plugins/useTreeViewIcons");
104
110
  var _useTreeViewItems = require("./plugins/useTreeViewItems");
111
+ var _useTreeViewLabel = require("./plugins/useTreeViewLabel");
105
112
  var _useTreeViewJSXItems = require("./plugins/useTreeViewJSXItems");
106
113
  var _tree = require("./utils/tree");
107
114
  var _warning = require("./utils/warning");
@@ -66,8 +66,11 @@ const useTreeViewExpansion = ({
66
66
  if (params.expansionTrigger) {
67
67
  return params.expansionTrigger;
68
68
  }
69
+ if (instance.isTreeViewEditable) {
70
+ return 'iconContainer';
71
+ }
69
72
  return 'content';
70
- }, [params.expansionTrigger]);
73
+ }, [params.expansionTrigger, instance.isTreeViewEditable]);
71
74
  return {
72
75
  publicAPI: {
73
76
  setItemExpansion
@@ -9,6 +9,8 @@ var React = _interopRequireWildcard(require("react"));
9
9
  var _RtlProvider = require("@mui/system/RtlProvider");
10
10
  var _useEventCallback = _interopRequireDefault(require("@mui/utils/useEventCallback"));
11
11
  var _tree = require("../../utils/tree");
12
+ var _plugins = require("../../utils/plugins");
13
+ var _useTreeViewLabel = require("../useTreeViewLabel");
12
14
  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); }
13
15
  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; }
14
16
  function isPrintableCharacter(string) {
@@ -98,7 +100,9 @@ const useTreeViewKeyboardNavigation = ({
98
100
  // If the focused item has no children, we select it.
99
101
  case key === 'Enter':
100
102
  {
101
- if (canToggleItemExpansion(itemId)) {
103
+ if ((0, _plugins.hasPlugin)(instance, _useTreeViewLabel.useTreeViewLabel) && instance.isItemEditable(itemId) && !instance.isItemBeingEdited(itemId)) {
104
+ instance.setEditedItemId(itemId);
105
+ } else if (canToggleItemExpansion(itemId)) {
102
106
  instance.toggleItemExpansion(event, itemId);
103
107
  event.preventDefault();
104
108
  } else if (canToggleItemSelection(itemId)) {
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "useTreeViewLabel", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _useTreeViewLabel.useTreeViewLabel;
10
+ }
11
+ });
12
+ var _useTreeViewLabel = require("./useTreeViewLabel");
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useTreeViewLabelItemPlugin = exports.isAndroid = void 0;
7
+ var React = _interopRequireWildcard(require("react"));
8
+ var _TreeViewProvider = require("../../TreeViewProvider");
9
+ 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); }
10
+ 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; }
11
+ const isAndroid = () => navigator.userAgent.toLowerCase().includes('android');
12
+ exports.isAndroid = isAndroid;
13
+ const useTreeViewLabelItemPlugin = ({
14
+ props
15
+ }) => {
16
+ const {
17
+ instance
18
+ } = (0, _TreeViewProvider.useTreeViewContext)();
19
+ const {
20
+ label,
21
+ itemId
22
+ } = props;
23
+ const [labelInputValue, setLabelInputValue] = React.useState(label);
24
+ const isItemBeingEdited = instance.isItemBeingEdited(itemId);
25
+ React.useEffect(() => {
26
+ if (!isItemBeingEdited) {
27
+ setLabelInputValue(label);
28
+ }
29
+ }, [isItemBeingEdited, label]);
30
+ return {
31
+ propsEnhancers: {
32
+ labelInput: ({
33
+ externalEventHandlers
34
+ }) => {
35
+ const editable = instance.isItemEditable(itemId);
36
+ if (!editable) {
37
+ return {};
38
+ }
39
+ const handleInputChange = event => {
40
+ externalEventHandlers.onChange?.(event);
41
+ setLabelInputValue(event.target.value);
42
+ };
43
+ return {
44
+ value: labelInputValue ?? '',
45
+ 'data-element': 'labelInput',
46
+ onChange: handleInputChange,
47
+ autoFocus: true,
48
+ type: 'text'
49
+ };
50
+ }
51
+ }
52
+ };
53
+ };
54
+ exports.useTreeViewLabelItemPlugin = useTreeViewLabelItemPlugin;
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.useTreeViewLabel = void 0;
8
+ var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
9
+ var React = _interopRequireWildcard(require("react"));
10
+ var _warning = require("../../utils/warning");
11
+ var _useTreeViewLabel = require("./useTreeViewLabel.itemPlugin");
12
+ 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); }
13
+ 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; }
14
+ const useTreeViewLabel = ({
15
+ instance,
16
+ state,
17
+ setState,
18
+ params,
19
+ experimentalFeatures
20
+ }) => {
21
+ if (process.env.NODE_ENV !== 'production') {
22
+ if (params.isItemEditable && !experimentalFeatures?.labelEditing) {
23
+ (0, _warning.warnOnce)(['MUI X: The label editing feature requires the `labelEditing` experimental feature to be enabled.', 'You can do it by passing `experimentalFeatures={{ labelEditing: true}}` to the `RichTreeViewPro` component.', 'Check the documentation for more details: https://mui.com/x/react-tree-view/rich-tree-view/editing/']);
24
+ }
25
+ }
26
+ const editedItemRef = React.useRef(state.editedItemId);
27
+ const isItemBeingEditedRef = itemId => editedItemRef.current === itemId;
28
+ const setEditedItemId = editedItemId => {
29
+ setState(prevState => (0, _extends2.default)({}, prevState, {
30
+ editedItemId
31
+ }));
32
+ editedItemRef.current = editedItemId;
33
+ };
34
+ const isItemBeingEdited = itemId => itemId === state.editedItemId;
35
+ const isTreeViewEditable = Boolean(params.isItemEditable) && !!experimentalFeatures.labelEditing;
36
+ const isItemEditable = itemId => {
37
+ if (itemId == null || !isTreeViewEditable) {
38
+ return false;
39
+ }
40
+ const item = instance.getItem(itemId);
41
+ if (!item) {
42
+ return false;
43
+ }
44
+ return typeof params.isItemEditable === 'function' ? params.isItemEditable(item) : Boolean(params.isItemEditable);
45
+ };
46
+ const updateItemLabel = (itemId, label) => {
47
+ if (!label) {
48
+ throw new Error(['MUI X: The Tree View component requires all items to have a `label` property.', 'The label of an item cannot be empty.', itemId].join('\n'));
49
+ }
50
+ setState(prevState => {
51
+ const item = prevState.items.itemMetaMap[itemId];
52
+ if (item.label !== label) {
53
+ return (0, _extends2.default)({}, prevState, {
54
+ items: (0, _extends2.default)({}, prevState.items, {
55
+ itemMetaMap: (0, _extends2.default)({}, prevState.items.itemMetaMap, {
56
+ [itemId]: (0, _extends2.default)({}, item, {
57
+ label
58
+ })
59
+ })
60
+ })
61
+ });
62
+ }
63
+ return prevState;
64
+ });
65
+ if (params.onItemLabelChange) {
66
+ params.onItemLabelChange(itemId, label);
67
+ }
68
+ };
69
+ return {
70
+ instance: {
71
+ setEditedItemId,
72
+ isItemBeingEdited,
73
+ updateItemLabel,
74
+ isItemEditable,
75
+ isTreeViewEditable,
76
+ isItemBeingEditedRef
77
+ },
78
+ publicAPI: {
79
+ updateItemLabel
80
+ }
81
+ };
82
+ };
83
+ exports.useTreeViewLabel = useTreeViewLabel;
84
+ useTreeViewLabel.itemPlugin = _useTreeViewLabel.useTreeViewLabelItemPlugin;
85
+ useTreeViewLabel.getInitialState = () => ({
86
+ editedItemId: null
87
+ });
88
+ useTreeViewLabel.params = {
89
+ onItemLabelChange: true,
90
+ isItemEditable: true
91
+ };
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
@@ -12,6 +12,7 @@ var _useForkRef = _interopRequireDefault(require("@mui/utils/useForkRef"));
12
12
  var _TreeViewProvider = require("../internals/TreeViewProvider");
13
13
  var _useTreeItem2Utils = require("../hooks/useTreeItem2Utils");
14
14
  var _TreeViewItemDepthContext = require("../internals/TreeViewItemDepthContext");
15
+ var _tree = require("../internals/utils/tree");
15
16
  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); }
16
17
  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; }
17
18
  const useTreeItem2 = parameters => {
@@ -59,6 +60,7 @@ const useTreeItem2 = parameters => {
59
60
  const handleRootRef = (0, _useForkRef.default)(rootRef, pluginRootRef, rootRefObject);
60
61
  const handleContentRef = (0, _useForkRef.default)(contentRef, contentRefObject);
61
62
  const checkboxRef = React.useRef(null);
63
+ const rootTabIndex = instance.canItemBeTabbed(itemId) ? 0 : -1;
62
64
  const createRootHandleFocus = otherHandlers => event => {
63
65
  otherHandlers.onFocus?.(event);
64
66
  if (event.defaultMuiPrevented) {
@@ -74,15 +76,33 @@ const useTreeItem2 = parameters => {
74
76
  if (event.defaultMuiPrevented) {
75
77
  return;
76
78
  }
79
+ const rootElement = instance.getItemDOMElement(itemId);
80
+
81
+ // Don't blur the root when switching to editing mode
82
+ // the input that triggers the root blur can be either the relatedTarget (when entering editing state) or the target (when exiting editing state)
83
+ // when we enter the editing state, we focus the input -> we don't want to remove the focused item from the state
84
+ if (status.editing ||
85
+ // 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
86
+ // 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
87
+ event.relatedTarget && (0, _tree.isTargetInDescendants)(event.relatedTarget, rootElement) && (event.target && event.target?.dataset?.element === 'labelInput' && (0, _tree.isTargetInDescendants)(event.target, rootElement) || event.relatedTarget?.dataset?.element === 'labelInput')) {
88
+ return;
89
+ }
77
90
  instance.removeFocusedItem();
78
91
  };
79
92
  const createRootHandleKeyDown = otherHandlers => event => {
80
93
  otherHandlers.onKeyDown?.(event);
81
- if (event.defaultMuiPrevented) {
94
+ if (event.defaultMuiPrevented || event.target?.dataset?.element === 'labelInput') {
82
95
  return;
83
96
  }
84
97
  instance.handleItemKeyDown(event, itemId);
85
98
  };
99
+ const createLabelHandleDoubleClick = otherHandlers => event => {
100
+ otherHandlers.onDoubleClick?.(event);
101
+ if (event.defaultMuiPrevented) {
102
+ return;
103
+ }
104
+ interactions.toggleItemEditing();
105
+ };
86
106
  const createContentHandleClick = otherHandlers => event => {
87
107
  otherHandlers.onClick?.(event);
88
108
  onItemClick?.(event, itemId);
@@ -117,6 +137,27 @@ const useTreeItem2 = parameters => {
117
137
  }
118
138
  interactions.handleCheckboxSelection(event);
119
139
  };
140
+ const createInputHandleKeydown = otherHandlers => event => {
141
+ otherHandlers.onKeyDown?.(event);
142
+ if (event.defaultMuiPrevented) {
143
+ return;
144
+ }
145
+ const target = event.target;
146
+ if (event.key === 'Enter' && target.value) {
147
+ interactions.handleSaveItemLabel(event, target.value);
148
+ } else if (event.key === 'Escape') {
149
+ interactions.handleCancelItemLabelEditing(event);
150
+ }
151
+ };
152
+ const createInputHandleBlur = otherHandlers => event => {
153
+ otherHandlers.onBlur?.(event);
154
+ if (event.defaultMuiPrevented) {
155
+ return;
156
+ }
157
+ if (event.target.value) {
158
+ interactions.handleSaveItemLabel(event, event.target.value);
159
+ }
160
+ };
120
161
  const createIconContainerHandleClick = otherHandlers => event => {
121
162
  otherHandlers.onClick?.(event);
122
163
  if (event.defaultMuiPrevented) {
@@ -143,7 +184,7 @@ const useTreeItem2 = parameters => {
143
184
  const props = (0, _extends2.default)({}, externalEventHandlers, {
144
185
  ref: handleRootRef,
145
186
  role: 'treeitem',
146
- tabIndex: instance.canItemBeTabbed(itemId) ? 0 : -1,
187
+ tabIndex: rootTabIndex,
147
188
  id: idAttribute,
148
189
  'aria-expanded': status.expandable ? status.expanded : undefined,
149
190
  'aria-selected': ariaSelected,
@@ -197,9 +238,28 @@ const useTreeItem2 = parameters => {
197
238
  };
198
239
  const getLabelProps = (externalProps = {}) => {
199
240
  const externalEventHandlers = (0, _extends2.default)({}, (0, _extractEventHandlers.default)(externalProps));
200
- return (0, _extends2.default)({}, externalEventHandlers, {
241
+ const props = (0, _extends2.default)({}, externalEventHandlers, {
201
242
  children: label
202
- }, externalProps);
243
+ }, externalProps, {
244
+ onDoubleClick: createLabelHandleDoubleClick(externalEventHandlers)
245
+ });
246
+ if (instance.isTreeViewEditable) {
247
+ props.editable = status.editable;
248
+ }
249
+ return props;
250
+ };
251
+ const getLabelInputProps = (externalProps = {}) => {
252
+ const externalEventHandlers = (0, _extractEventHandlers.default)(externalProps);
253
+ const props = (0, _extends2.default)({}, externalEventHandlers, externalProps, {
254
+ onKeyDown: createInputHandleKeydown(externalEventHandlers),
255
+ onBlur: createInputHandleBlur(externalEventHandlers)
256
+ });
257
+ const enhancedlabelInputProps = propsEnhancers.labelInput?.({
258
+ rootRefObject,
259
+ contentRefObject,
260
+ externalEventHandlers
261
+ }) ?? {};
262
+ return (0, _extends2.default)({}, props, enhancedlabelInputProps);
203
263
  };
204
264
  const getIconContainerProps = (externalProps = {}) => {
205
265
  const externalEventHandlers = (0, _extractEventHandlers.default)(externalProps);
@@ -237,6 +297,7 @@ const useTreeItem2 = parameters => {
237
297
  getIconContainerProps,
238
298
  getCheckboxProps,
239
299
  getLabelProps,
300
+ getLabelInputProps,
240
301
  getDragAndDropOverlayProps,
241
302
  rootRef: handleRootRef,
242
303
  status,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mui/x-tree-view",
3
- "version": "7.12.1",
3
+ "version": "7.13.0",
4
4
  "description": "The community edition of the Tree View components (MUI X).",
5
5
  "author": "MUI Team",
6
6
  "main": "./node/index.js",
@@ -40,7 +40,7 @@
40
40
  "clsx": "^2.1.1",
41
41
  "prop-types": "^15.8.1",
42
42
  "react-transition-group": "^4.4.5",
43
- "@mui/x-internals": "7.12.0"
43
+ "@mui/x-internals": "7.13.0"
44
44
  },
45
45
  "peerDependencies": {
46
46
  "@emotion/react": "^11.9.0",
@@ -1,2 +1,2 @@
1
1
  export { useTreeItem2 as unstable_useTreeItem2 } from './useTreeItem2';
2
- export type { UseTreeItem2Parameters, UseTreeItem2ReturnValue, UseTreeItem2Status, UseTreeItem2RootSlotOwnProps, UseTreeItem2ContentSlotOwnProps, UseTreeItem2LabelSlotOwnProps, UseTreeItem2IconContainerSlotOwnProps, UseTreeItem2GroupTransitionSlotOwnProps, UseTreeItem2DragAndDropOverlaySlotOwnProps, } from './useTreeItem2.types';
2
+ export type { UseTreeItem2Parameters, UseTreeItem2ReturnValue, UseTreeItem2Status, UseTreeItem2RootSlotOwnProps, UseTreeItem2ContentSlotOwnProps, UseTreeItem2LabelInputSlotOwnProps, UseTreeItem2LabelSlotOwnProps, UseTreeItem2IconContainerSlotOwnProps, UseTreeItem2GroupTransitionSlotOwnProps, UseTreeItem2DragAndDropOverlaySlotOwnProps, } from './useTreeItem2.types';
@@ -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,