@elliemae/ds-treeview 2.0.2 → 2.1.0-rc.4

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 (165) hide show
  1. package/cjs/TreeView.js +5 -103
  2. package/cjs/TreeViewContext.js +44 -47
  3. package/cjs/config/useTreeview.js +137 -0
  4. package/cjs/index.js +1 -7
  5. package/cjs/parts/CheckboxSelectable.js +5 -7
  6. package/cjs/parts/ExpandCaret.js +17 -11
  7. package/cjs/parts/Icon.js +4 -0
  8. package/cjs/parts/NestingSpace.js +15 -22
  9. package/cjs/parts/RadioSelectable.js +7 -9
  10. package/cjs/parts/TreeItem.js +14 -11
  11. package/cjs/parts/TreeList.js +4 -2
  12. package/cjs/plugins/dnd/TreeDndPlugin.js +1 -1
  13. package/cjs/react-desc-prop-types.js +28 -27
  14. package/cjs/related-components/TreeViewSearchBar.js +9 -1
  15. package/cjs/{deprecated/plugins/selectable/helper.js → sharedTypes.js} +0 -0
  16. package/cjs/utils/dnd-helpers.js +2 -4
  17. package/cjs/utils/group-expands-helpers.js +34 -8
  18. package/cjs/utils/keyboard-helpers.js +64 -60
  19. package/cjs/utils/object-helpers.js +25 -7
  20. package/cjs/utils/refs-helpers.js +2 -2
  21. package/cjs/utils/tree-helpers.js +42 -27
  22. package/cjs/utils/useDnDHelpers.js +107 -100
  23. package/cjs/utils/useInstanceRefActions.js +3 -2
  24. package/cjs/utils/useTree.js +25 -6
  25. package/esm/TreeView.js +6 -103
  26. package/esm/TreeViewContext.js +44 -47
  27. package/esm/config/useTreeview.js +129 -0
  28. package/esm/index.js +0 -8
  29. package/esm/parts/CheckboxSelectable.js +5 -7
  30. package/esm/parts/ExpandCaret.js +17 -11
  31. package/esm/parts/Icon.js +4 -0
  32. package/esm/parts/NestingSpace.js +15 -21
  33. package/esm/parts/RadioSelectable.js +7 -9
  34. package/esm/parts/TreeItem.js +14 -11
  35. package/esm/parts/TreeList.js +4 -2
  36. package/esm/plugins/dnd/TreeDndPlugin.js +1 -1
  37. package/esm/react-desc-prop-types.js +28 -27
  38. package/esm/related-components/TreeViewSearchBar.js +9 -1
  39. package/esm/{deprecated/plugins/selectable/helper.js → sharedTypes.js} +0 -0
  40. package/esm/utils/dnd-helpers.js +2 -4
  41. package/esm/utils/group-expands-helpers.js +34 -9
  42. package/esm/utils/keyboard-helpers.js +62 -58
  43. package/esm/utils/object-helpers.js +25 -7
  44. package/esm/utils/refs-helpers.js +2 -2
  45. package/esm/utils/tree-helpers.js +42 -27
  46. package/esm/utils/useDnDHelpers.js +107 -100
  47. package/esm/utils/useInstanceRefActions.js +3 -2
  48. package/esm/utils/useTree.js +25 -6
  49. package/package.json +17 -128
  50. package/types/TreeView.d.ts +4 -148
  51. package/types/TreeViewContext.d.ts +4 -106
  52. package/types/config/useTreeview.d.ts +7 -0
  53. package/types/index.d.ts +0 -1
  54. package/types/parts/CheckboxSelectable.d.ts +5 -6
  55. package/types/parts/ChildrenCountDisplayer.d.ts +6 -6
  56. package/types/parts/ExpandCaret.d.ts +6 -6
  57. package/types/parts/Icon.d.ts +7 -5
  58. package/types/parts/NestingSpace.d.ts +3 -8
  59. package/types/parts/RadioSelectable.d.ts +5 -6
  60. package/types/parts/TreeItem.d.ts +22 -14
  61. package/types/parts/TreeItemText.d.ts +5 -5
  62. package/types/parts/TreeList.d.ts +22 -9
  63. package/types/react-desc-prop-types.d.ts +124 -43
  64. package/types/related-components/TreeViewSearchBar.d.ts +14 -11
  65. package/types/sharedTypes.d.ts +54 -0
  66. package/types/utils/array-helpers.d.ts +2 -2
  67. package/types/utils/dnd-helpers.d.ts +26 -25
  68. package/types/utils/group-expands-helpers.d.ts +13 -10
  69. package/types/utils/keyboard-helpers.d.ts +5 -3
  70. package/types/utils/object-helpers.d.ts +6 -2
  71. package/types/utils/refs-helpers.d.ts +4 -1
  72. package/types/utils/selectable-helper.d.ts +7 -3
  73. package/types/utils/string-helpers.d.ts +1 -1
  74. package/types/utils/tree-helpers.d.ts +25 -11
  75. package/types/utils/useDnDHelpers.d.ts +23 -3
  76. package/types/utils/useInstanceRefActions.d.ts +3 -3
  77. package/types/utils/useTree.d.ts +8 -7
  78. package/cjs/deprecated/TreeView.js +0 -72
  79. package/cjs/deprecated/__testUtils__/utils.js +0 -89
  80. package/cjs/deprecated/index.js +0 -27
  81. package/cjs/deprecated/plugins/dnd/TreeDndPlugin.js +0 -119
  82. package/cjs/deprecated/plugins/dnd/index.js +0 -9
  83. package/cjs/deprecated/plugins/dnd/renderers/DraggableItem.js +0 -67
  84. package/cjs/deprecated/plugins/dnd/renderers/DroppableList.js +0 -181
  85. package/cjs/deprecated/plugins/dnd/utils.js +0 -157
  86. package/cjs/deprecated/plugins/index.js +0 -21
  87. package/cjs/deprecated/plugins/roving/TreeRovingPlugin.js +0 -109
  88. package/cjs/deprecated/plugins/roving/index.js +0 -9
  89. package/cjs/deprecated/plugins/searchable/SearchableTreePlugin.js +0 -109
  90. package/cjs/deprecated/plugins/searchable/index.js +0 -9
  91. package/cjs/deprecated/plugins/searchable/utils.js +0 -7
  92. package/cjs/deprecated/plugins/selectable/SelectablePluginTree.js +0 -290
  93. package/cjs/deprecated/plugins/selectable/index.js +0 -9
  94. package/cjs/deprecated/plugins/selectable/utils.js +0 -19
  95. package/cjs/deprecated/plugins/toolbar/TreeToolbarPlugin.js +0 -128
  96. package/cjs/deprecated/plugins/toolbar/index.js +0 -9
  97. package/cjs/deprecated/plugins/tree/TreeDataPlugin.js +0 -281
  98. package/cjs/deprecated/plugins/tree/index.js +0 -9
  99. package/cjs/deprecated/plugins/tree/useExpandTreeState.js +0 -143
  100. package/cjs/deprecated/plugins/tree/utils.js +0 -43
  101. package/cjs/deprecated/plugins/tree/walkTreeStrategy.js +0 -60
  102. package/cjs/deprecated/plugins/virtualization/TreeVirtualizationPlugin.js +0 -209
  103. package/cjs/deprecated/plugins/virtualization/index.js +0 -9
  104. package/cjs/deprecated/renderers.js +0 -76
  105. package/cjs/prop-types.js +0 -61
  106. package/esm/deprecated/TreeView.js +0 -61
  107. package/esm/deprecated/__testUtils__/utils.js +0 -79
  108. package/esm/deprecated/index.js +0 -14
  109. package/esm/deprecated/plugins/dnd/TreeDndPlugin.js +0 -110
  110. package/esm/deprecated/plugins/dnd/index.js +0 -1
  111. package/esm/deprecated/plugins/dnd/renderers/DraggableItem.js +0 -59
  112. package/esm/deprecated/plugins/dnd/renderers/DroppableList.js +0 -172
  113. package/esm/deprecated/plugins/dnd/utils.js +0 -139
  114. package/esm/deprecated/plugins/index.js +0 -7
  115. package/esm/deprecated/plugins/roving/TreeRovingPlugin.js +0 -96
  116. package/esm/deprecated/plugins/roving/index.js +0 -1
  117. package/esm/deprecated/plugins/searchable/SearchableTreePlugin.js +0 -99
  118. package/esm/deprecated/plugins/searchable/index.js +0 -1
  119. package/esm/deprecated/plugins/searchable/utils.js +0 -3
  120. package/esm/deprecated/plugins/selectable/SelectablePluginTree.js +0 -280
  121. package/esm/deprecated/plugins/selectable/index.js +0 -1
  122. package/esm/deprecated/plugins/selectable/utils.js +0 -15
  123. package/esm/deprecated/plugins/toolbar/TreeToolbarPlugin.js +0 -114
  124. package/esm/deprecated/plugins/toolbar/index.js +0 -1
  125. package/esm/deprecated/plugins/tree/TreeDataPlugin.js +0 -269
  126. package/esm/deprecated/plugins/tree/index.js +0 -1
  127. package/esm/deprecated/plugins/tree/useExpandTreeState.js +0 -135
  128. package/esm/deprecated/plugins/tree/utils.js +0 -28
  129. package/esm/deprecated/plugins/tree/walkTreeStrategy.js +0 -56
  130. package/esm/deprecated/plugins/virtualization/TreeVirtualizationPlugin.js +0 -197
  131. package/esm/deprecated/plugins/virtualization/index.js +0 -1
  132. package/esm/deprecated/renderers.js +0 -59
  133. package/esm/prop-types.js +0 -46
  134. package/types/deprecated/TreeView.d.ts +0 -8
  135. package/types/deprecated/__testUtils__/utils.d.ts +0 -72
  136. package/types/deprecated/index.d.ts +0 -2
  137. package/types/deprecated/plugins/dnd/TreeDndPlugin.d.ts +0 -1
  138. package/types/deprecated/plugins/dnd/index.d.ts +0 -1
  139. package/types/deprecated/plugins/dnd/renderers/DraggableItem.d.ts +0 -3
  140. package/types/deprecated/plugins/dnd/renderers/DroppableList.d.ts +0 -6
  141. package/types/deprecated/plugins/dnd/tests/TreeDndPlugin.test.d.ts +0 -0
  142. package/types/deprecated/plugins/dnd/utils.d.ts +0 -28
  143. package/types/deprecated/plugins/index.d.ts +0 -7
  144. package/types/deprecated/plugins/roving/TreeRovingPlugin.d.ts +0 -1
  145. package/types/deprecated/plugins/roving/index.d.ts +0 -1
  146. package/types/deprecated/plugins/searchable/SearchableTreePlugin.d.ts +0 -1
  147. package/types/deprecated/plugins/searchable/index.d.ts +0 -1
  148. package/types/deprecated/plugins/searchable/utils.d.ts +0 -1
  149. package/types/deprecated/plugins/selectable/SelectablePluginTree.d.ts +0 -1
  150. package/types/deprecated/plugins/selectable/helper.d.ts +0 -0
  151. package/types/deprecated/plugins/selectable/index.d.ts +0 -1
  152. package/types/deprecated/plugins/selectable/tests/SelectablePluginTree.test.d.ts +0 -1
  153. package/types/deprecated/plugins/selectable/utils.d.ts +0 -1
  154. package/types/deprecated/plugins/toolbar/TreeToolbarPlugin.d.ts +0 -1
  155. package/types/deprecated/plugins/toolbar/index.d.ts +0 -1
  156. package/types/deprecated/plugins/tree/TreeDataPlugin.d.ts +0 -1
  157. package/types/deprecated/plugins/tree/index.d.ts +0 -1
  158. package/types/deprecated/plugins/tree/tests/TreeDataPlugin.test.d.ts +0 -1
  159. package/types/deprecated/plugins/tree/useExpandTreeState.d.ts +0 -14
  160. package/types/deprecated/plugins/tree/utils.d.ts +0 -8
  161. package/types/deprecated/plugins/tree/walkTreeStrategy.d.ts +0 -9
  162. package/types/deprecated/plugins/virtualization/TreeVirtualizationPlugin.d.ts +0 -1
  163. package/types/deprecated/plugins/virtualization/index.d.ts +0 -1
  164. package/types/deprecated/renderers.d.ts +0 -19
  165. package/types/prop-types.d.ts +0 -26
@@ -1,15 +1,15 @@
1
1
  import { createRef, createContext } from 'react';
2
2
 
3
3
  /* eslint-disable no-unused-vars */
4
- // import FilePdf from '@elliemae/ds-icons/FilePdf';
4
+
5
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
6
+ function noop() {}
5
7
 
6
8
  const defaultProps = {
7
9
  plugins: [],
8
10
  selection: {},
9
- // { [id]:[state] } -> e.g. {1:true, 2:'mixed'}
10
11
  instanceRef: /*#__PURE__*/createRef(),
11
- disableGroups: false,
12
- disableLeafs: false,
12
+ isItemDisabled: () => false,
13
13
  disableIcons: false,
14
14
  fluid: false,
15
15
  isMultiSelect: false,
@@ -19,30 +19,27 @@ const defaultProps = {
19
19
  sortable: false,
20
20
  isLoading: false,
21
21
  highlightOnlyQuery: false,
22
- onInstanceRefInitialized: istanceRef => {},
23
- onItemClick: (item, e) => {},
24
- onItemFocus: params => {},
25
- // { itemIndex: number, scrollToItem: func }
26
- onVisibleItemsChange: newVisibleItems => {},
27
- onOrderChange: (newData, oldData, draggedItem) => {},
28
- onSelectionChange: (selectionHasmap, item, indexAndScrollTo) => {},
29
- // indexAndScrollTo = { scrollToItem: ()=>{}, itemIndex :number }
30
- onExpandChange: (expandedHashmap, itemToggled) => {},
31
- // expandedHashmap -> {[id]:true, ...[id]:true} itemToggled -> item that caused the change for being toggled
22
+ onItemClick: noop,
23
+ onItemFocus: noop,
24
+ onVisibleItemsChange: noop,
25
+ onOrderChange: noop,
26
+ onSelectionChange: noop,
27
+ onExpandChange: noop,
28
+ onInstanceRefInitialized: noop,
32
29
  rowSize: 'normal',
33
- // ['normal', 'compact']
34
30
  labelOverflow: 'wrap',
35
- // ['wrap', 'wrap-all', 'truncate']
36
31
  noItemsPlaceholder: 'No items found',
37
32
  nameKey: 'name',
38
- // use to retrieve the label text inside ever data item
39
33
  width: '100%',
40
34
  height: '100%',
41
35
  groupIcon: null,
42
- // <Folder />,
43
36
  itemIcon: null,
44
- // <FilePdf />,
45
- searchQuery: ''
37
+ searchQuery: '' // workaround on the typings over the fact that
38
+ // when we instantiate the context we can't have all the props
39
+ // we only have a part of them but the final typings will include missing props
40
+ // this is safe to do because
41
+ // we will "mergeWithDefaults" + "validatePropTypes" when we do instantiate the context
42
+
46
43
  };
47
44
  const defaultRelativeMouseCoord = {
48
45
  isBefore: false,
@@ -54,48 +51,48 @@ const defaultRelativeMouseCoord = {
54
51
  relativeElementDOMRect: null,
55
52
  relativeElementIndex: null
56
53
  };
57
- /** Context for cross component communication */
58
-
59
- const TreeViewContext = /*#__PURE__*/createContext({
54
+ const defaultContext = {
60
55
  props: defaultProps,
61
56
  visibleItems: [],
62
57
  withRadioChecks: false,
63
58
  withCheckboxChecks: false,
64
59
  withDragAndDrop: false,
65
60
  relativeMouseCord: defaultRelativeMouseCoord,
66
- setRelativeMouseCord: () => {},
67
- labelRenderer: value => value,
68
- triggerTreeRerender: () => {},
69
- tree: {},
70
- virtualListHelpers: {},
71
- virtualListRef: {},
72
- treeRoot: {},
61
+ setRelativeMouseCord: noop,
62
+ triggerTreeRerender: noop,
63
+ tree: undefined,
64
+ treeRoot: undefined,
65
+ virtualListHelpers: {
66
+ virtualItems: [],
67
+ totalSize: 0,
68
+ scrollToOffset: noop,
69
+ scrollToIndex: noop
70
+ },
71
+ virtualListRef: undefined,
73
72
  isDragging: false,
74
- setIsDragging: () => {},
73
+ setIsDragging: noop,
75
74
  isKeyboardDragging: false,
76
- setIsKeyboardDragging: () => {},
75
+ setIsKeyboardDragging: noop,
77
76
  draggedItem: null,
78
- // item
79
- setDraggedItem: () => {},
77
+ setDraggedItem: noop,
80
78
  uniqueTreeViewUUID: '',
81
79
  selectedItem: null,
82
- // item
83
- setSelectedItem: () => {},
80
+ setSelectedItem: noop,
84
81
  focusedItem: null,
85
- // item
86
- setFocusedItem: () => {},
82
+ setFocusedItem: noop,
87
83
  selectedCheckboxes: {},
88
- // { [id]:[state] } -> e.g. {1:true, 2:'mixed'}
89
- setSelectedCheckboxes: () => {},
84
+ setSelectedCheckboxes: noop,
90
85
  expandedGroups: {},
91
- // { [id]:true } -> e.g. {1:true, 2:true} // false are not listed
92
- setExpandedGroups: () => {},
86
+ setExpandedGroups: noop,
93
87
  latestToggledItem: null,
94
- // item -> if toggle all -> should be undefined
95
- setLatestToggledItem: () => {},
88
+ setLatestToggledItem: noop,
96
89
  hoverItem: null,
97
- // item
98
- setHoverItem: () => {}
99
- });
90
+ setHoverItem: noop,
91
+ handleExpandGroup: noop,
92
+ updateUserExpandedState: noop
93
+ };
94
+ /** Context for cross component communication */
95
+
96
+ const TreeViewContext = /*#__PURE__*/createContext(defaultContext);
100
97
 
101
98
  export { TreeViewContext as default, defaultProps, defaultRelativeMouseCoord };
@@ -0,0 +1,129 @@
1
+ import 'core-js/modules/esnext.async-iterator.filter.js';
2
+ import 'core-js/modules/esnext.iterator.constructor.js';
3
+ import 'core-js/modules/esnext.iterator.filter.js';
4
+ import 'core-js/modules/esnext.async-iterator.for-each.js';
5
+ import 'core-js/modules/esnext.iterator.for-each.js';
6
+ import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
7
+ import 'core-js/modules/web.dom-collections.iterator.js';
8
+ import { useRef, useState, useCallback, useMemo, useEffect } from 'react';
9
+ import { useVirtual } from 'react-virtual';
10
+ import { useMemoMergePropsWithDefault, useValidateTypescriptPropTypes } from '@elliemae/ds-props-helpers';
11
+ import { v4 } from 'uuid';
12
+ import { TreeViewPropTypes } from '../react-desc-prop-types.js';
13
+ import { defaultProps, defaultRelativeMouseCoord } from '../TreeViewContext.js';
14
+ import { TreeDndPlugin } from '../plugins/dnd/TreeDndPlugin.js';
15
+ import { useTree } from '../utils/useTree.js';
16
+ import { toggleItemExpand, useNotifyExpandedChange } from '../utils/group-expands-helpers.js';
17
+ import { useInstanceRefActions } from '../utils/useInstanceRefActions.js';
18
+ import { useGlobalToggleAllExpandShortcut } from '../utils/keyboard-helpers.js';
19
+
20
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
21
+
22
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
23
+ const useTreeview = props => {
24
+ const propsWithDefault = useMemoMergePropsWithDefault(props, defaultProps);
25
+ useValidateTypescriptPropTypes(propsWithDefault, TreeViewPropTypes);
26
+ const defaultActions = {
27
+ actions: {
28
+ toggleExpandAll: () => {},
29
+ scrollTo: () => {},
30
+ setSelectedItemByVirtualIndex: () => {},
31
+ setFocusedItemByVirtualIndex: () => {}
32
+ }
33
+ };
34
+ const treeRef = useRef(defaultActions);
35
+ const {
36
+ data,
37
+ plugins,
38
+ onOrderChange,
39
+ isMultiSelect,
40
+ isSingleSelect,
41
+ instanceRef,
42
+ selection,
43
+ onInstanceRefInitialized
44
+ } = propsWithDefault;
45
+ const [isDragging, setIsDragging] = useState(false);
46
+ const [isKeyboardDragging, setIsKeyboardDragging] = useState(false);
47
+ const [relativeMouseCord, setRelativeMouseCord] = useState(defaultRelativeMouseCoord);
48
+ const [uniqueTreeViewUUID] = useState(v4());
49
+ const [draggedItem, setDraggedItem] = useState(null);
50
+ const [hoverItem, setHoverItem] = useState(null);
51
+ const [latestToggledItem, setLatestToggledItem] = useState(null);
52
+ const [selectedItem, setSelectedItem] = useState(null);
53
+ const [focusedItem, setFocusedItem] = useState(null);
54
+ const [selectedCheckboxes, setSelectedCheckboxes] = useState(_objectSpread({}, selection));
55
+ const [expandedGroups, setExpandedGroups] = useState({});
56
+ const {
57
+ visibleItems,
58
+ tree,
59
+ treeRoot,
60
+ triggerTreeRerender,
61
+ updateUserExpandedState
62
+ } = useTree(data, propsWithDefault, {
63
+ setExpandedGroups
64
+ });
65
+ const virtualListRef = useRef(); // estimateSize should not be really required given what was stated on
66
+ // https://github.com/tannerlinsley/react-virtual/issues/23
67
+
68
+ const virtualListHelpers = useVirtual({
69
+ size: visibleItems.length,
70
+ parentRef: virtualListRef,
71
+ overscan: 15
72
+ });
73
+ const withDragAndDrop = !!(plugins !== null && plugins !== void 0 && plugins.includes(TreeDndPlugin) && onOrderChange);
74
+ const withRadioChecks = isSingleSelect && !isMultiSelect;
75
+ const withCheckboxChecks = !isSingleSelect && isMultiSelect;
76
+ const handleExpandGroup = useCallback(toggleItemExpand, []);
77
+ const ctx = useMemo(() => ({
78
+ props: propsWithDefault,
79
+ setRelativeMouseCord,
80
+ relativeMouseCord,
81
+ virtualListHelpers,
82
+ virtualListRef,
83
+ tree,
84
+ treeRoot,
85
+ visibleItems,
86
+ triggerTreeRerender,
87
+ isDragging,
88
+ setIsDragging,
89
+ isKeyboardDragging,
90
+ setIsKeyboardDragging,
91
+ draggedItem,
92
+ setDraggedItem,
93
+ withRadioChecks,
94
+ withCheckboxChecks,
95
+ withDragAndDrop,
96
+ uniqueTreeViewUUID,
97
+ selectedCheckboxes,
98
+ setSelectedCheckboxes,
99
+ selectedItem,
100
+ setSelectedItem,
101
+ expandedGroups,
102
+ setExpandedGroups,
103
+ latestToggledItem,
104
+ setLatestToggledItem,
105
+ focusedItem,
106
+ setFocusedItem,
107
+ hoverItem,
108
+ setHoverItem,
109
+ handleExpandGroup,
110
+ updateUserExpandedState
111
+ }), [draggedItem, expandedGroups, focusedItem, handleExpandGroup, hoverItem, isDragging, isKeyboardDragging, latestToggledItem, propsWithDefault, relativeMouseCord, selectedCheckboxes, selectedItem, tree, treeRoot, triggerTreeRerender, uniqueTreeViewUUID, virtualListHelpers, visibleItems, withCheckboxChecks, withDragAndDrop, withRadioChecks, updateUserExpandedState]); // this hooks can't use the context because the context provider doesn't wrap this
112
+ // as such we manually pass the second parameter as fit
113
+
114
+ if (instanceRef) instanceRef.current = treeRef.current;
115
+ useInstanceRefActions(treeRef.current, ctx);
116
+ useGlobalToggleAllExpandShortcut(treeRoot, triggerTreeRerender, setLatestToggledItem, updateUserExpandedState);
117
+ useNotifyExpandedChange(propsWithDefault, ctx); // this is an horrible hack.
118
+ // this is required because there is no "on rendered" react-way to check if every children has finished rendering
119
+ // this should be working for now, in the future we may want to review this for a better solution
120
+
121
+ useEffect(() => {
122
+ setTimeout(() => onInstanceRefInitialized(treeRef), 100); // eslint-disable-next-line react-hooks/exhaustive-deps
123
+ }, []);
124
+ return useMemo(() => ({
125
+ ctx
126
+ }), [ctx]);
127
+ };
128
+
129
+ export { useTreeview };
package/esm/index.js CHANGED
@@ -7,11 +7,3 @@ export { TreePluginList } from './plugins/tree/TreeDataPlugin.js';
7
7
  export { TreeVirtualizationPlugin } from './plugins/virtualization/TreeVirtualizationPlugin.js';
8
8
  export { SearchableTreePlugin } from './plugins/searchable/SearchableTreePlugin.js';
9
9
  export { TreeViewSearchBar } from './related-components/TreeViewSearchBar.js';
10
- import * as index from './deprecated/index.js';
11
- export { index as DEPRECATED };
12
-
13
- /* eslint-disable global-require */
14
- // Polyfill ResizeObserver for demo
15
- if (typeof ResizeObserver === 'undefined') {
16
- global.ResizeObserver = require('resize-observer-polyfill').default;
17
- }
@@ -30,11 +30,8 @@ function CheckboxSelectable(props) {
30
30
  const ctx = useContext(TreeViewContext);
31
31
  const {
32
32
  props: {
33
- disableGroups,
34
- // radio allows disabling this, checkbox doesnt? check specs
35
- disableLeafs,
36
- // radio allows disabling this, checkbox doesnt? check specs
37
- onSelectionChange
33
+ onSelectionChange,
34
+ isItemDisabled
38
35
  },
39
36
  virtualListHelpers: {
40
37
  scrollToIndex
@@ -50,7 +47,7 @@ function CheckboxSelectable(props) {
50
47
  triggerTreeRerender();
51
48
  const indexAndScrollTo = {
52
49
  scrollToItem: () => {
53
- scrollToIndex(item.virtualIndex);
50
+ if (typeof item.virtualIndex === 'number') scrollToIndex(item.virtualIndex);
54
51
  },
55
52
  itemIndex
56
53
  };
@@ -67,9 +64,10 @@ function CheckboxSelectable(props) {
67
64
 
68
65
  return false;
69
66
  }, [selectedCheckboxes, id]);
67
+ const isDisabled = useMemo(() => isItemDisabled(item), [item, isItemDisabled]);
70
68
  return /*#__PURE__*/_jsx(StyledCheckboxWrapper, {}, void 0, /*#__PURE__*/_jsx(DSCheckbox, {
71
69
  checked: isChecked,
72
- disabled: item.isGroup ? disableGroups : disableLeafs,
70
+ disabled: isDisabled,
73
71
  className: "em-ds-tree-item-checkbox",
74
72
  "data-testid": "tree-item-checkbox",
75
73
  onChange: onCheckboxChange,
@@ -26,6 +26,7 @@ const ExpandCaret = props => {
26
26
  },
27
27
  handleExpandGroup = defaultHandleExpandGroup,
28
28
  triggerTreeRerender,
29
+ updateUserExpandedState,
29
30
  setLatestToggledItem,
30
31
  setFocusedItem,
31
32
  virtualListHelpers: {
@@ -51,18 +52,23 @@ const ExpandCaret = props => {
51
52
  },
52
53
  onClick: e => {
53
54
  e.stopPropagation();
54
- handleExpandGroup(item, triggerTreeRerender, scrollToIndex, e);
55
+ if (e) handleExpandGroup(item, triggerTreeRerender, updateUserExpandedState, scrollToIndex, e);
55
56
  setLatestToggledItem(item);
56
- onItemFocus({
57
- itemIndex: item.virtualIndex,
58
- scrollToItem: function () {
59
- let opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
60
- align: 'start'
61
- };
62
- return scrollToIndex(item.virtualIndex, opts);
63
- },
64
- item
65
- });
57
+ const itemVitualIndex = item.virtualIndex;
58
+
59
+ if (typeof itemVitualIndex === 'number') {
60
+ onItemFocus({
61
+ itemIndex: itemVitualIndex,
62
+ scrollToItem: function () {
63
+ let opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
64
+ align: 'start'
65
+ };
66
+ return scrollToIndex(itemVitualIndex, opts);
67
+ },
68
+ item
69
+ });
70
+ }
71
+
66
72
  setFocusedItem(item);
67
73
  focusItem(item);
68
74
  },
package/esm/parts/Icon.js CHANGED
@@ -18,6 +18,10 @@ const Icon = props => {
18
18
  if (!icon) return null;
19
19
  return /*#__PURE__*/React.cloneElement(icon, {
20
20
  'data-testid': isGroupOrHasChildrens ? 'tree-item-group-icon' : 'tree-item-icon',
21
+ // legacy class-name way of handling things,
22
+ // this will eventually be deprecated in favor of styled components
23
+ // untill then, just eslint-ignore and move on
24
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment
21
25
  className: cx(icon.props.className, 'tree-item-icon')
22
26
  });
23
27
  };
@@ -1,21 +1,10 @@
1
- import 'core-js/modules/esnext.async-iterator.filter.js';
2
- import 'core-js/modules/esnext.iterator.constructor.js';
3
- import 'core-js/modules/esnext.iterator.filter.js';
4
- import 'core-js/modules/esnext.async-iterator.for-each.js';
5
- import 'core-js/modules/esnext.iterator.for-each.js';
6
1
  import _jsx from '@babel/runtime/helpers/esm/jsx';
7
- import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
8
2
  import 'react';
9
3
 
10
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
11
-
12
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
13
-
14
4
  const getItemNestingLeftPadding = (level, opts) => {
15
5
  const {
16
6
  spaceForNestingLevel = 1.5
17
- } = _objectSpread({}, opts);
18
-
7
+ } = opts;
19
8
  const groupLeftPadding = spaceForNestingLevel * (level - 1);
20
9
  const finalLeftPadding = groupLeftPadding + spaceForNestingLevel - 0.1; // root level left-padding would be negative and would not be applied
21
10
  // if "root-level" nesting, then defaults to 0 left-padding.
@@ -31,15 +20,20 @@ const NestingSpace = props => {
31
20
  const {
32
21
  treeDepth
33
22
  } = item;
34
- const itemNestingLeftPadding = getItemNestingLeftPadding(treeDepth - 1, {
35
- spaceForNestingLevel
36
- });
37
- return /*#__PURE__*/_jsx("div", {
38
- "data-testid": "tree-item-nested-space",
39
- style: {
40
- width: itemNestingLeftPadding
41
- }
42
- });
23
+
24
+ if (treeDepth) {
25
+ const itemNestingLeftPadding = getItemNestingLeftPadding(treeDepth - 1, {
26
+ spaceForNestingLevel
27
+ });
28
+ return /*#__PURE__*/_jsx("div", {
29
+ "data-testid": "tree-item-nested-space",
30
+ style: {
31
+ width: itemNestingLeftPadding
32
+ }
33
+ });
34
+ }
35
+
36
+ return null;
43
37
  };
44
38
 
45
39
  export { NestingSpace };
@@ -11,11 +11,8 @@ function RadioSelectable(props) {
11
11
  const ctx = useContext(TreeViewContext);
12
12
  const {
13
13
  props: {
14
- disableGroups,
15
- // radio allows disabling this, checkbox doesnt? check specs
16
- disableLeafs,
17
- // radio allows disabling this, checkbox doesnt? check specs
18
- onSelectionChange
14
+ onSelectionChange,
15
+ isItemDisabled
19
16
  },
20
17
  virtualListHelpers: {
21
18
  scrollToIndex
@@ -34,21 +31,22 @@ function RadioSelectable(props) {
34
31
  setSelectedCheckboxes(newSelectionHasmap);
35
32
  const indexAndScrollTo = {
36
33
  scrollToItem: () => {
37
- scrollToIndex(item.virtualIndex);
34
+ if (item.virtualIndex) scrollToIndex(item.virtualIndex);
38
35
  },
39
36
  itemIndex
40
37
  };
41
38
  if (onSelectionChange) onSelectionChange(newSelectionHasmap, item, indexAndScrollTo);
42
- }, [item, id, onSelectionChange, scrollToIndex]);
39
+ }, [id, setSelectedCheckboxes, itemIndex, onSelectionChange, item, scrollToIndex]);
43
40
  const radioName = useMemo(() => "radios-".concat(uniqueTreeViewUUID), [uniqueTreeViewUUID]);
41
+ const isDisabled = useMemo(() => isItemDisabled(item), [item, isItemDisabled]);
44
42
  return /*#__PURE__*/_jsx(DSRadio, {
45
43
  checked: selectedCheckboxes[id] === true,
46
44
  name: radioName,
47
- disabled: item.isGroup ? disableGroups : disableLeafs,
45
+ disabled: isDisabled,
48
46
  className: "em-ds-tree-item-radio",
49
47
  "data-testid": "tree-item-radio",
50
48
  onChange: onRadioChange,
51
- tabIndex: "0"
49
+ tabIndex: 0
52
50
  });
53
51
  }
54
52
 
@@ -27,9 +27,11 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
27
27
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
28
28
  const TreeListItem = aggregatedClasses('li', {
29
29
  'data-testid': treeItemBlockName,
30
- role: 'treeitem'
30
+ role: 'treeitem' // temp fix untill we move to styled components
31
+
31
32
  })(treeItemBlockName);
32
- const TreeListItemAddonsWrapper = aggregatedClasses('div')(treeItemBlockName, 'addons');
33
+ const TreeListItemAddonsWrapper = aggregatedClasses('div')(treeItemBlockName, 'addons' // temp fix untill we move to styled components
34
+ );
33
35
  const DnDHandle = SortableHandle(_ref => {
34
36
  let {
35
37
  id
@@ -63,7 +65,7 @@ const TreeItem = props => {
63
65
  const {
64
66
  nodeItemRef
65
67
  } = node.model;
66
- const openFolderOnHoverTimeout = useRef();
68
+ const openFolderOnHoverTimeout = useRef(null);
67
69
  const [isDraggingOverThis, setIsDraggingOverThis] = useState(false);
68
70
  const onItemKeyDown = useOnItemKeyDown(item);
69
71
  const ctx = useContext(TreeViewContext);
@@ -109,8 +111,8 @@ const TreeItem = props => {
109
111
  if (isBefore) className += '-drop-before';else if (isAfter) className += '-drop-after';else className += '-drop-in';
110
112
  return className;
111
113
  }, [withDragAndDrop, relativeMouseCord, isDraggingOverThis]);
112
- const selectedClassName = useMemo(() => (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.id) === item.id ? 'selected' : '', [selectedItem]);
113
- const hoverClassName = useMemo(() => (hoverItem === null || hoverItem === void 0 ? void 0 : hoverItem.id) !== item.id || withDragAndDrop && isDragging ? '' : 'hover', [hoverItem, withDragAndDrop, isDragging]);
114
+ const selectedClassName = useMemo(() => (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.id) === item.id ? 'selected' : '', [item.id, selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.id]);
115
+ const hoverClassName = useMemo(() => (hoverItem === null || hoverItem === void 0 ? void 0 : hoverItem.id) !== item.id || withDragAndDrop && isDragging ? '' : 'hover', [hoverItem === null || hoverItem === void 0 ? void 0 : hoverItem.id, item.id, withDragAndDrop, isDragging]);
114
116
  const fixedHeightClassname = useMemo(() => {
115
117
  if (labelOverflow === 'truncate') {
116
118
  if (rowSize === 'compact') return "".concat(DSTreeViewPrefix, "-").concat(treeItemBlockName, "--fixed-height-compact");
@@ -124,21 +126,22 @@ const TreeItem = props => {
124
126
  onItemClick(item, e);
125
127
  setFocusedItem(item);
126
128
  setSelectedItem(item);
129
+ const itemVirtualIndex = typeof item.virtualIndex === 'number' ? item.virtualIndex : -1;
127
130
  onItemFocus({
128
- itemIndex: item.virtualIndex,
131
+ itemIndex: itemVirtualIndex,
129
132
  scrollToItem: function () {
130
133
  let opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
131
134
  align: 'start'
132
135
  };
133
- return scrollToIndex(item.virtualIndex, opts);
136
+ return scrollToIndex(itemVirtualIndex, opts);
134
137
  },
135
138
  item
136
139
  });
137
140
  }, [item, scrollToIndex, onItemClick, onItemFocus, setSelectedItem, setFocusedItem]);
138
141
  return /*#__PURE__*/jsxs(TreeListItem, {
139
- tabIndex: "0",
142
+ tabIndex: 0,
140
143
  onMouseMove: event => {
141
- if (withDragAndDrop) {
144
+ if (withDragAndDrop && onMouseDragOverItem) {
142
145
  onMouseDragOverItem({
143
146
  event,
144
147
  item,
@@ -165,8 +168,8 @@ const TreeItem = props => {
165
168
  ref: setItemRefs,
166
169
  style: _objectSpread({}, itemWrapperStyle),
167
170
  className: finalClassName,
168
- "aria-expanded": item.isExpanded,
169
- "aria-selected": selectedCheckboxes[item.id],
171
+ "aria-expanded": !!item.isExpanded,
172
+ "aria-selected": !!selectedCheckboxes[item.id],
170
173
  "data-id": item.id,
171
174
  "data-index": item.virtualIndex,
172
175
  onKeyDown: onItemKeyDown,
@@ -12,8 +12,8 @@ import { SortableContainer } from '@elliemae/react-sortable-hoc';
12
12
  import { aggregatedClasses } from '@elliemae/ds-classnames';
13
13
  import { DSCircularProgressIndicator } from '@elliemae/ds-circular-progress-indicator';
14
14
  import TreeViewContext from '../TreeViewContext.js';
15
- import { DragAndDropTreeItem, TreeItem } from './TreeItem.js';
16
15
  import { treeListBlockName, DSTreeViewPrefix } from '../config/cssClassesConstants.js';
16
+ import { DragAndDropTreeItem, TreeItem } from './TreeItem.js';
17
17
  import { jsxs, jsx } from 'react/jsx-runtime';
18
18
 
19
19
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
@@ -22,7 +22,9 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
22
22
  const treeListNoItemsBn = "".concat(treeListBlockName, "-no-items");
23
23
  const TreeListNoItems = aggregatedClasses('div', {
24
24
  'data-testid': treeListNoItemsBn
25
- })(treeListNoItemsBn);
25
+ })(treeListNoItemsBn); // React.ComponentProps<'ul'> uses LegacyRef typings that existed pre-hook era
26
+ // we omit the LegacyRef typings in favor of hook-era typings
27
+
26
28
  const TreeListWrapper = aggregatedClasses('ul', {
27
29
  'data-testid': treeListBlockName,
28
30
  role: 'tree'
@@ -26,7 +26,7 @@ const TreeDnD = () => {
26
26
  onSortStart: onSortStart,
27
27
  onMouseDragOverItem: onMouseDragOverItem,
28
28
  onSortEnd: onSortEnd,
29
- getContainer: () => virtualListRef.current,
29
+ getContainer: () => virtualListRef === null || virtualListRef === void 0 ? void 0 : virtualListRef.current,
30
30
  keyCodes: keyCodes
31
31
  });
32
32
  };
@@ -1,49 +1,50 @@
1
1
  import { PropTypes } from 'react-desc';
2
2
 
3
3
  /* eslint-disable max-lines */
4
- const InstanceActionsPropTypes = PropTypes.shape({
5
- toggleExpandAll: PropTypes.func,
6
- scrollTo: PropTypes.func
7
- });
8
- const TreeViewItemPropType = PropTypes.shape({
9
- children: PropTypes.arrayOf(PropTypes.object),
10
- id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
11
- isGroup: PropTypes.oneOfType([PropTypes.oneOf([undefined, null]), PropTypes.bool]),
12
- name: PropTypes.string,
13
- node: PropTypes.object
14
- });
15
- const TreeViewInstancePropType = PropTypes.shape({
16
- current: PropTypes.oneOfType([PropTypes.oneOf([null]), PropTypes.shape({
17
- actions: InstanceActionsPropTypes.isRequired
18
- })])
19
- });
20
4
  const TreeViewPropTypes = {
21
- data: PropTypes.arrayOf(TreeViewItemPropType).description('data to populate tree view').isRequired,
5
+ data: PropTypes.arrayOf(PropTypes.shape({
6
+ children: PropTypes.arrayOf(PropTypes.object),
7
+ id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
8
+ isGroup: PropTypes.oneOfType([PropTypes.oneOf([undefined, null]), PropTypes.bool]),
9
+ name: PropTypes.string,
10
+ node: PropTypes.object
11
+ })).description('data to populate tree view').isRequired,
22
12
  plugins: PropTypes.arrayOf(PropTypes.string).description('list of enabled plugins').defaultValue([]),
23
13
  selection: PropTypes.object.description('pre selected items').defaultValue({}),
24
- instanceRef: TreeViewInstancePropType.description('instance ref'),
25
- disableGroups: PropTypes.bool.description('disable grouping funcionality').defaultValue(false),
26
- disableLeafs: PropTypes.bool.description('disable leaf items').defaultValue(false),
14
+ expanded: PropTypes.object.description('control what items are expanded').defaultValue(undefined),
15
+ instanceRef: PropTypes.shape({
16
+ current: PropTypes.oneOfType([PropTypes.oneOf([null, undefined]), PropTypes.shape({
17
+ actions: PropTypes.shape({
18
+ toggleExpandAll: PropTypes.func,
19
+ scrollTo: PropTypes.func
20
+ }).description('').isRequired
21
+ })])
22
+ }).description('instance ref'),
23
+ isItemDisabled: PropTypes.func.description('Function that receives an item, and returns whether that item should be disabled').defaultValue('() => false'),
27
24
  disableIcons: PropTypes.bool.description('disable icons').defaultValue(false),
28
25
  fluid: PropTypes.bool.description('whether is fluid or not').defaultValue(false),
29
26
  isMultiSelect: PropTypes.bool.description('whether the tree view is multi select or not').defaultValue(false),
30
27
  isSingleSelect: PropTypes.bool.description('wheter the tree view is single select or not').defaultValue(false),
28
+ isLoading: PropTypes.bool.description('wheter the tree should show the loading state or not').defaultValue(false),
31
29
  restrictDragAndDrop: PropTypes.bool.description('whether to restrict DnD functionality or not').defaultValue(false),
32
30
  showChildrenAmount: PropTypes.bool.description('whether to show the amount of children or not').defaultValue(false),
33
31
  sortable: PropTypes.bool.description('whether the sortable functionality is active or not').defaultValue(false),
34
- labelRenderer: PropTypes.func.description('custom renderer for labels'),
35
- onItemClick: PropTypes.func.description('function executed when clicking on an item'),
36
- onItemFocus: PropTypes.func.description('function executed when focusing on an item'),
37
- onVisibleItemsChange: PropTypes.func.description('function executed when the visible items change'),
38
- onOrderChange: PropTypes.func.description('function executed when the items order changes'),
39
- onSelectionChange: PropTypes.func.description('function executed when the selection changes'),
40
- onExpandChange: PropTypes.func.description('function executed when expanding an item'),
32
+ onItemClick: PropTypes.func.description('function executed when clicking on an item').defaultValue('() => {}'),
33
+ onItemFocus: PropTypes.func.description('function executed when focusing on an item').defaultValue('() => {}'),
34
+ onVisibleItemsChange: PropTypes.func.description('function executed when the visible items change').defaultValue('() => {}'),
35
+ onOrderChange: PropTypes.func.description('function executed when the items order changes').defaultValue('() => {}'),
36
+ onSelectionChange: PropTypes.func.description('function executed when the selection changes').defaultValue('() => {}'),
37
+ onExpandChange: PropTypes.func.description('function executed when expanding an item').defaultValue('() => {}'),
38
+ onInstanceRefInitialized: PropTypes.func.description('function executed when instanceRef has terminated instanciation').defaultValue('() => {}'),
41
39
  rowSize: PropTypes.oneOf(['normal', 'compact']).description('size of the row').defaultValue('normal'),
40
+ labelOverflow: PropTypes.oneOf(['wrap', 'wrap-all', 'truncate']).description('label truncation preference').defaultValue('wrap'),
42
41
  width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).description('components width').defaultValue('100%'),
43
42
  height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).description('components height').defaultValue('100%'),
44
43
  groupIcon: PropTypes.node.description('icon for groups'),
45
44
  itemIcon: PropTypes.node.description('icon for items'),
46
45
  searchQuery: PropTypes.string.description('search query value'),
46
+ noItemsPlaceholder: PropTypes.string.description('message to be shown when there are no items in the treeview to be displayed').defaultValue('No items found'),
47
+ name: PropTypes.string.description('property key to identifier for items labels').defaultValue('name'),
47
48
  highlightOnlyQuery: PropTypes.bool.description('whether to highlight results or not').defaultValue(false)
48
49
  };
49
50