@react-fabric/data 1.0.0-beta.55 → 1.0.0-beta.57

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.
@@ -66,6 +66,7 @@ var TreeNode = function TreeNode(_ref) {
66
66
  className: classNames("flex flex-nowrap items-center"),
67
67
  "data-testid": node["data-testid"],
68
68
  "data-test-value": node["data-test-value"],
69
+ "data-id": node.id,
69
70
  children: [filler, node.loading && /*#__PURE__*/jsxRuntime.jsx("div", {
70
71
  className: "flex-initial w-6",
71
72
  children: /*#__PURE__*/jsxRuntime.jsx(core.Icon, {
@@ -58,10 +58,12 @@ var TreePanel = function TreePanel(_ref) {
58
58
  }),
59
59
  tree = _useTree.tree,
60
60
  query = _useTree.query,
61
+ currentSelected = _useTree.selected,
61
62
  toggleExpand = _useTree.toggleExpand,
62
63
  toggleCheck = _useTree.toggleCheck,
63
64
  expandAll = _useTree.expandAll,
64
65
  collapseAll = _useTree.collapseAll,
66
+ expandAndLoad = _useTree.expandAndLoad,
65
67
  _select = _useTree.select,
66
68
  expand = _useTree.expand,
67
69
  onFilter = _useTree.onFilter;
@@ -87,11 +89,22 @@ var TreePanel = function TreePanel(_ref) {
87
89
  open: function open(id) {
88
90
  return expand(id);
89
91
  },
92
+ openAndLoad: function openAndLoad(list) {
93
+ return expandAndLoad(list);
94
+ },
90
95
  select: function select(id) {
91
96
  return _select(id);
92
97
  }
93
98
  };
94
99
  }, []);
100
+ react.useEffect(function () {
101
+ var index = tree.findIndex(function (n) {
102
+ return n.id === currentSelected;
103
+ });
104
+ virtualizer.scrollToIndex(index, {
105
+ align: "auto"
106
+ });
107
+ }, [currentSelected]);
95
108
  return /*#__PURE__*/jsxRuntime.jsxs(core.Section, {
96
109
  children: [/*#__PURE__*/jsxRuntime.jsxs(core.Header, {
97
110
  flex: true,
@@ -2,6 +2,7 @@
2
2
 
3
3
  var _defineProperty = require('@babel/runtime/helpers/defineProperty');
4
4
  var _slicedToArray = require('@babel/runtime/helpers/slicedToArray');
5
+ var _toConsumableArray = require('@babel/runtime/helpers/toConsumableArray');
5
6
  var core = require('@react-fabric/core');
6
7
  var utilities = require('@react-fabric/utilities');
7
8
  var memoizeOne = require('memoize-one');
@@ -31,7 +32,7 @@ var useTree = function useTree(_ref) {
31
32
  onSelect: onSelect,
32
33
  onChecked: onChecked
33
34
  });
34
- var intialExpand = react.useRef(defaultExpanded !== null && defaultExpanded !== void 0 ? defaultExpanded : utilities.EMPTY_ARRAY);
35
+ var intialExpand = react.useRef(_toConsumableArray(defaultExpanded !== null && defaultExpanded !== void 0 ? defaultExpanded : utilities.EMPTY_ARRAY));
35
36
  var itemList = createItemList(items);
36
37
  var fireExpandToggle = react.useCallback(function (itemMap) {
37
38
  var expandedList = itemMap.filter(function (node) {
@@ -47,26 +48,29 @@ var useTree = function useTree(_ref) {
47
48
  var _node$children;
48
49
  if (node.open && !node.leaf && !((_node$children = node.children) !== null && _node$children !== void 0 && _node$children.length)) {
49
50
  node.loading = true;
50
- void Promise.resolve(onLoad === null || onLoad === void 0 ? void 0 : onLoad(node.id)).then(function () {
51
- var resp = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : utilities.EMPTY_ARRAY;
52
- node.children = utils.refactorTree(resp, {
53
- sorter: sorter,
54
- defaultExpanded: defaultExpanded
55
- }, {
56
- level: node.level + 1,
57
- parent: node.id
58
- });
59
- })["finally"](function () {
60
- var _intialExpand$current;
61
- node.loading = false;
62
- dispatch({
63
- type: "loaded"
64
- });
65
- ((_intialExpand$current = intialExpand.current) === null || _intialExpand$current === void 0 ? void 0 : _intialExpand$current.length) > 0 && dispatch({
66
- type: "expand",
67
- id: intialExpand.current.shift()
51
+ // delay onload callback to avoid state issues
52
+ setTimeout(function () {
53
+ void Promise.resolve(onLoad === null || onLoad === void 0 ? void 0 : onLoad(node.id)).then(function () {
54
+ var resp = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : utilities.EMPTY_ARRAY;
55
+ node.children = utils.refactorTree(resp, {
56
+ sorter: sorter,
57
+ defaultExpanded: defaultExpanded
58
+ }, {
59
+ level: node.level + 1,
60
+ parent: node.id
61
+ });
62
+ })["finally"](function () {
63
+ var _intialExpand$current;
64
+ node.loading = false;
65
+ dispatch({
66
+ type: "loaded"
67
+ });
68
+ ((_intialExpand$current = intialExpand.current) === null || _intialExpand$current === void 0 ? void 0 : _intialExpand$current.length) > 0 && dispatch({
69
+ type: "expand",
70
+ id: intialExpand.current.shift()
71
+ });
68
72
  });
69
- });
73
+ }, 100);
70
74
  } else {
71
75
  var _intialExpand$current2;
72
76
  dispatch({
@@ -86,6 +90,9 @@ var useTree = function useTree(_ref) {
86
90
  var _componentEvents$curr3, _componentEvents$curr4;
87
91
  (_componentEvents$curr3 = (_componentEvents$curr4 = componentEvents.current).onChecked) === null || _componentEvents$curr3 === void 0 || _componentEvents$curr3.call(_componentEvents$curr4, leafs, nodes, partials);
88
92
  }, [onChecked]);
93
+ var fireQuery = core.useDebounce(function (query) {
94
+ onQuery === null || onQuery === void 0 || onQuery(query);
95
+ }, [onQuery]);
89
96
  var _useReducer = react.useReducer(function (state, action) {
90
97
  if (action.type === "load") {
91
98
  state.items = utils.refactorTree(action.items, {
@@ -112,7 +119,7 @@ var useTree = function useTree(_ref) {
112
119
  state.itemMap = utils.makeTreeMap(state.items);
113
120
  fireExpandToggle(Array.from(state.itemMap.values()));
114
121
  state.tree = utils.flattenTree(state.items);
115
- state.selected && utils.updateSelection(state.itemMap, state.selected, true);
122
+ state.selected = utils.updateSelection(state.itemMap, selected, true);
116
123
  (_state$checked = state.checked) === null || _state$checked === void 0 || _state$checked.forEach(function (id) {
117
124
  return utils.updateChecked(state.itemMap, id, 1);
118
125
  });
@@ -151,8 +158,13 @@ var useTree = function useTree(_ref) {
151
158
  }
152
159
  if (action.type === "filter") {
153
160
  if (onQuery) {
154
- var _action$query;
155
- onQuery((_action$query = action.query) !== null && _action$query !== void 0 ? _action$query : "");
161
+ // TODO: onQuery should provide new tree listing
162
+ // save current tree state as preQueryState
163
+ // on clearing filter restore preQueryState
164
+ if (!utilities.isEmpty(action.query)) {
165
+ // state.prevItems = state.items;
166
+ fireQuery(action.query);
167
+ }
156
168
  } else {
157
169
  utils.filterTree(state.itemMap, action.query, matcher);
158
170
  state.tree = utils.flattenTree(state.items);
@@ -162,12 +174,11 @@ var useTree = function useTree(_ref) {
162
174
  });
163
175
  }
164
176
  if (action.type === "toggleSelect") {
165
- if (state.selected) {
166
- utils.updateSelection(state.itemMap, state.selected);
167
- }
168
177
  if (!onSelect) {
169
- utils.updateSelection(state.itemMap, action.id, true);
170
- state.selected = action.id;
178
+ if (state.selected) {
179
+ utils.updateSelection(state.itemMap, state.selected);
180
+ }
181
+ state.selected = utils.updateSelection(state.itemMap, action.id, true);
171
182
  state.tree = utils.flattenTree(state.items);
172
183
  } else {
173
184
  var _state$itemMap$get;
@@ -179,8 +190,7 @@ var useTree = function useTree(_ref) {
179
190
  if (state.selected) {
180
191
  utils.updateSelection(state.itemMap, state.selected);
181
192
  }
182
- utils.updateSelection(state.itemMap, action.id, true);
183
- state.selected = action.id;
193
+ state.selected = utils.updateSelection(state.itemMap, action.id, true);
184
194
  state.tree = utils.flattenTree(state.items);
185
195
  return _objectSpread({}, state);
186
196
  }
@@ -285,6 +295,15 @@ var useTree = function useTree(_ref) {
285
295
  id: id
286
296
  });
287
297
  }, []);
298
+ var expandAndLoad = react.useCallback(function (expandList) {
299
+ if (expandList.length > 0) {
300
+ intialExpand.current = _toConsumableArray(expandList);
301
+ dispatch({
302
+ type: "expand",
303
+ id: intialExpand.current.shift()
304
+ });
305
+ }
306
+ }, []);
288
307
  var expandAll = react.useCallback(function () {
289
308
  dispatch({
290
309
  type: "expandAll"
@@ -304,10 +323,12 @@ var useTree = function useTree(_ref) {
304
323
  return {
305
324
  tree: state.tree,
306
325
  query: state.query,
326
+ selected: state.selected,
307
327
  toggleExpand: toggleExpand,
308
328
  expandAll: expandAll,
309
329
  collapseAll: collapseAll,
310
330
  toggleCheck: toggleCheck,
331
+ expandAndLoad: expandAndLoad,
311
332
  select: select,
312
333
  expand: expand,
313
334
  onFilter: onFilter
@@ -96,7 +96,7 @@ var flattenTree = function flattenTree(nodes) {
96
96
  return list;
97
97
  };
98
98
  var updateSelection = function updateSelection(nodes, id, selected) {
99
- var node = nodes.get(id);
99
+ var node = nodes.get(id !== null && id !== void 0 ? id : "");
100
100
  if (node) {
101
101
  // change selection
102
102
  node.selected = selected;
@@ -108,6 +108,7 @@ var updateSelection = function updateSelection(nodes, id, selected) {
108
108
  // selected && parentNode && (parentNode.open = true);
109
109
  parent = parentNode === null || parentNode === void 0 ? void 0 : parentNode.parent;
110
110
  }
111
+ return id;
111
112
  }
112
113
  };
113
114
  var updateChecked = function updateChecked(list, id, checked) {
@@ -211,9 +211,8 @@ var _VirtualGallery = function _VirtualGallery(_ref) {
211
211
  }, "".concat(key, ":").concat(col));
212
212
  })
213
213
  }, key);
214
- }), onLoadMore && /*#__PURE__*/jsxRuntime.jsx("div", {
215
- className: "h-16",
216
- children: loading && /*#__PURE__*/jsxRuntime.jsx(core.Skeleton, {})
214
+ }), loading && /*#__PURE__*/jsxRuntime.jsx("div", {
215
+ children: /*#__PURE__*/jsxRuntime.jsx(core.Skeleton, {})
217
216
  })]
218
217
  })
219
218
  }), !hideScroller && /*#__PURE__*/jsxRuntime.jsx("div", {
@@ -66,6 +66,7 @@ var TreeNode = function TreeNode(_ref) {
66
66
  className: classNames("flex flex-nowrap items-center"),
67
67
  "data-testid": node["data-testid"],
68
68
  "data-test-value": node["data-test-value"],
69
+ "data-id": node.id,
69
70
  children: [filler, node.loading && /*#__PURE__*/jsx("div", {
70
71
  className: "flex-initial w-6",
71
72
  children: /*#__PURE__*/jsx(Icon, {
@@ -5,7 +5,7 @@ import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProper
5
5
  import { CoreIcons, Section, Header, Icon, ButtonGroup, Button } from '@react-fabric/core';
6
6
  import { Search } from '@react-fabric/form';
7
7
  import { useVirtualizer } from '@tanstack/react-virtual';
8
- import { useRef, useMemo, useImperativeHandle } from 'react';
8
+ import { useRef, useMemo, useImperativeHandle, useEffect } from 'react';
9
9
  import { TreeNode } from './TreeNode.js';
10
10
  import { iconExpandAll, iconCollapseAll } from './types.js';
11
11
  import { useTree } from './useTree.js';
@@ -58,10 +58,12 @@ var TreePanel = function TreePanel(_ref) {
58
58
  }),
59
59
  tree = _useTree.tree,
60
60
  query = _useTree.query,
61
+ currentSelected = _useTree.selected,
61
62
  toggleExpand = _useTree.toggleExpand,
62
63
  toggleCheck = _useTree.toggleCheck,
63
64
  expandAll = _useTree.expandAll,
64
65
  collapseAll = _useTree.collapseAll,
66
+ expandAndLoad = _useTree.expandAndLoad,
65
67
  _select = _useTree.select,
66
68
  expand = _useTree.expand,
67
69
  onFilter = _useTree.onFilter;
@@ -87,11 +89,22 @@ var TreePanel = function TreePanel(_ref) {
87
89
  open: function open(id) {
88
90
  return expand(id);
89
91
  },
92
+ openAndLoad: function openAndLoad(list) {
93
+ return expandAndLoad(list);
94
+ },
90
95
  select: function select(id) {
91
96
  return _select(id);
92
97
  }
93
98
  };
94
99
  }, []);
100
+ useEffect(function () {
101
+ var index = tree.findIndex(function (n) {
102
+ return n.id === currentSelected;
103
+ });
104
+ virtualizer.scrollToIndex(index, {
105
+ align: "auto"
106
+ });
107
+ }, [currentSelected]);
95
108
  return /*#__PURE__*/jsxs(Section, {
96
109
  children: [/*#__PURE__*/jsxs(Header, {
97
110
  flex: true,
@@ -2,8 +2,9 @@
2
2
 
3
3
  import _defineProperty from '@babel/runtime/helpers/defineProperty';
4
4
  import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
5
+ import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
5
6
  import { useDebounce } from '@react-fabric/core';
6
- import { EMPTY_ARRAY } from '@react-fabric/utilities';
7
+ import { EMPTY_ARRAY, isEmpty } from '@react-fabric/utilities';
7
8
  import memoizeOne from 'memoize-one';
8
9
  import { useRef, useCallback, useReducer, useEffect } from 'react';
9
10
  import { refactorTree, makeTreeMap, flattenTree, updateSelection, updateChecked, filterTree } from './utils.js';
@@ -31,7 +32,7 @@ var useTree = function useTree(_ref) {
31
32
  onSelect: onSelect,
32
33
  onChecked: onChecked
33
34
  });
34
- var intialExpand = useRef(defaultExpanded !== null && defaultExpanded !== void 0 ? defaultExpanded : EMPTY_ARRAY);
35
+ var intialExpand = useRef(_toConsumableArray(defaultExpanded !== null && defaultExpanded !== void 0 ? defaultExpanded : EMPTY_ARRAY));
35
36
  var itemList = createItemList(items);
36
37
  var fireExpandToggle = useCallback(function (itemMap) {
37
38
  var expandedList = itemMap.filter(function (node) {
@@ -47,26 +48,29 @@ var useTree = function useTree(_ref) {
47
48
  var _node$children;
48
49
  if (node.open && !node.leaf && !((_node$children = node.children) !== null && _node$children !== void 0 && _node$children.length)) {
49
50
  node.loading = true;
50
- void Promise.resolve(onLoad === null || onLoad === void 0 ? void 0 : onLoad(node.id)).then(function () {
51
- var resp = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : EMPTY_ARRAY;
52
- node.children = refactorTree(resp, {
53
- sorter: sorter,
54
- defaultExpanded: defaultExpanded
55
- }, {
56
- level: node.level + 1,
57
- parent: node.id
58
- });
59
- })["finally"](function () {
60
- var _intialExpand$current;
61
- node.loading = false;
62
- dispatch({
63
- type: "loaded"
64
- });
65
- ((_intialExpand$current = intialExpand.current) === null || _intialExpand$current === void 0 ? void 0 : _intialExpand$current.length) > 0 && dispatch({
66
- type: "expand",
67
- id: intialExpand.current.shift()
51
+ // delay onload callback to avoid state issues
52
+ setTimeout(function () {
53
+ void Promise.resolve(onLoad === null || onLoad === void 0 ? void 0 : onLoad(node.id)).then(function () {
54
+ var resp = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : EMPTY_ARRAY;
55
+ node.children = refactorTree(resp, {
56
+ sorter: sorter,
57
+ defaultExpanded: defaultExpanded
58
+ }, {
59
+ level: node.level + 1,
60
+ parent: node.id
61
+ });
62
+ })["finally"](function () {
63
+ var _intialExpand$current;
64
+ node.loading = false;
65
+ dispatch({
66
+ type: "loaded"
67
+ });
68
+ ((_intialExpand$current = intialExpand.current) === null || _intialExpand$current === void 0 ? void 0 : _intialExpand$current.length) > 0 && dispatch({
69
+ type: "expand",
70
+ id: intialExpand.current.shift()
71
+ });
68
72
  });
69
- });
73
+ }, 100);
70
74
  } else {
71
75
  var _intialExpand$current2;
72
76
  dispatch({
@@ -86,6 +90,9 @@ var useTree = function useTree(_ref) {
86
90
  var _componentEvents$curr3, _componentEvents$curr4;
87
91
  (_componentEvents$curr3 = (_componentEvents$curr4 = componentEvents.current).onChecked) === null || _componentEvents$curr3 === void 0 || _componentEvents$curr3.call(_componentEvents$curr4, leafs, nodes, partials);
88
92
  }, [onChecked]);
93
+ var fireQuery = useDebounce(function (query) {
94
+ onQuery === null || onQuery === void 0 || onQuery(query);
95
+ }, [onQuery]);
89
96
  var _useReducer = useReducer(function (state, action) {
90
97
  if (action.type === "load") {
91
98
  state.items = refactorTree(action.items, {
@@ -112,7 +119,7 @@ var useTree = function useTree(_ref) {
112
119
  state.itemMap = makeTreeMap(state.items);
113
120
  fireExpandToggle(Array.from(state.itemMap.values()));
114
121
  state.tree = flattenTree(state.items);
115
- state.selected && updateSelection(state.itemMap, state.selected, true);
122
+ state.selected = updateSelection(state.itemMap, selected, true);
116
123
  (_state$checked = state.checked) === null || _state$checked === void 0 || _state$checked.forEach(function (id) {
117
124
  return updateChecked(state.itemMap, id, 1);
118
125
  });
@@ -151,8 +158,13 @@ var useTree = function useTree(_ref) {
151
158
  }
152
159
  if (action.type === "filter") {
153
160
  if (onQuery) {
154
- var _action$query;
155
- onQuery((_action$query = action.query) !== null && _action$query !== void 0 ? _action$query : "");
161
+ // TODO: onQuery should provide new tree listing
162
+ // save current tree state as preQueryState
163
+ // on clearing filter restore preQueryState
164
+ if (!isEmpty(action.query)) {
165
+ // state.prevItems = state.items;
166
+ fireQuery(action.query);
167
+ }
156
168
  } else {
157
169
  filterTree(state.itemMap, action.query, matcher);
158
170
  state.tree = flattenTree(state.items);
@@ -162,12 +174,11 @@ var useTree = function useTree(_ref) {
162
174
  });
163
175
  }
164
176
  if (action.type === "toggleSelect") {
165
- if (state.selected) {
166
- updateSelection(state.itemMap, state.selected);
167
- }
168
177
  if (!onSelect) {
169
- updateSelection(state.itemMap, action.id, true);
170
- state.selected = action.id;
178
+ if (state.selected) {
179
+ updateSelection(state.itemMap, state.selected);
180
+ }
181
+ state.selected = updateSelection(state.itemMap, action.id, true);
171
182
  state.tree = flattenTree(state.items);
172
183
  } else {
173
184
  var _state$itemMap$get;
@@ -179,8 +190,7 @@ var useTree = function useTree(_ref) {
179
190
  if (state.selected) {
180
191
  updateSelection(state.itemMap, state.selected);
181
192
  }
182
- updateSelection(state.itemMap, action.id, true);
183
- state.selected = action.id;
193
+ state.selected = updateSelection(state.itemMap, action.id, true);
184
194
  state.tree = flattenTree(state.items);
185
195
  return _objectSpread({}, state);
186
196
  }
@@ -285,6 +295,15 @@ var useTree = function useTree(_ref) {
285
295
  id: id
286
296
  });
287
297
  }, []);
298
+ var expandAndLoad = useCallback(function (expandList) {
299
+ if (expandList.length > 0) {
300
+ intialExpand.current = _toConsumableArray(expandList);
301
+ dispatch({
302
+ type: "expand",
303
+ id: intialExpand.current.shift()
304
+ });
305
+ }
306
+ }, []);
288
307
  var expandAll = useCallback(function () {
289
308
  dispatch({
290
309
  type: "expandAll"
@@ -304,10 +323,12 @@ var useTree = function useTree(_ref) {
304
323
  return {
305
324
  tree: state.tree,
306
325
  query: state.query,
326
+ selected: state.selected,
307
327
  toggleExpand: toggleExpand,
308
328
  expandAll: expandAll,
309
329
  collapseAll: collapseAll,
310
330
  toggleCheck: toggleCheck,
331
+ expandAndLoad: expandAndLoad,
311
332
  select: select,
312
333
  expand: expand,
313
334
  onFilter: onFilter
@@ -96,7 +96,7 @@ var flattenTree = function flattenTree(nodes) {
96
96
  return list;
97
97
  };
98
98
  var updateSelection = function updateSelection(nodes, id, selected) {
99
- var node = nodes.get(id);
99
+ var node = nodes.get(id !== null && id !== void 0 ? id : "");
100
100
  if (node) {
101
101
  // change selection
102
102
  node.selected = selected;
@@ -108,6 +108,7 @@ var updateSelection = function updateSelection(nodes, id, selected) {
108
108
  // selected && parentNode && (parentNode.open = true);
109
109
  parent = parentNode === null || parentNode === void 0 ? void 0 : parentNode.parent;
110
110
  }
111
+ return id;
111
112
  }
112
113
  };
113
114
  var updateChecked = function updateChecked(list, id, checked) {
@@ -211,9 +211,8 @@ var _VirtualGallery = function _VirtualGallery(_ref) {
211
211
  }, "".concat(key, ":").concat(col));
212
212
  })
213
213
  }, key);
214
- }), onLoadMore && /*#__PURE__*/jsx("div", {
215
- className: "h-16",
216
- children: loading && /*#__PURE__*/jsx(Skeleton, {})
214
+ }), loading && /*#__PURE__*/jsx("div", {
215
+ children: /*#__PURE__*/jsx(Skeleton, {})
217
216
  })]
218
217
  })
219
218
  }), !hideScroller && /*#__PURE__*/jsx("div", {
@@ -77,6 +77,7 @@ export interface TreeNodeProps extends ChildProp {
77
77
  export interface TreeRef {
78
78
  select: (id: string) => void;
79
79
  open: (id: string) => void;
80
+ openAndLoad: (list: string[]) => void;
80
81
  }
81
82
  export interface TreePanelProps<T extends KeyValue = KeyValue> extends TestProps, RefProp<TreeRef> {
82
83
  items?: Array<TreeNodeType<T>>;
@@ -2,10 +2,12 @@ import { type InternalNode, type TreePanelProps } from "./types";
2
2
  export declare const useTree: <T extends KeyValue>({ items, checked, selected, sorter, matcher, onLoad, onQuery, onSelect, onChecked, defaultExpanded, onExpandToggle, }: Partial<TreePanelProps<T>>) => {
3
3
  tree: InternalNode[];
4
4
  query: string | undefined;
5
+ selected: string | undefined;
5
6
  toggleExpand: (id: string) => void;
6
7
  expandAll: () => void;
7
8
  collapseAll: () => void;
8
9
  toggleCheck: (id: string) => void;
10
+ expandAndLoad: (expandList: string[]) => void;
9
11
  select: (id: string) => void;
10
12
  expand: (id: string) => void;
11
13
  onFilter: {
@@ -8,6 +8,6 @@ export declare const refactorTree: (nodes: TreeNodeType[], { sorter, defaultExpa
8
8
  }) => InternalNode[];
9
9
  export declare const makeTreeMap: (nodes: InternalNode[], map?: Map<any, any>) => Map<any, any>;
10
10
  export declare const flattenTree: (nodes: InternalNode[], lines?: Array<0 | 1 | 2 | 3>) => InternalNode[];
11
- export declare const updateSelection: (nodes: Map<string, InternalNode>, id: string, selected?: true) => void;
11
+ export declare const updateSelection: (nodes: Map<string, InternalNode>, id?: string, selected?: true) => string | undefined;
12
12
  export declare const updateChecked: (list: Map<string, AnyObject>, id: string, checked?: 0 | 1 | 2) => void;
13
13
  export declare const filterTree: (nodes: Map<string, InternalNode>, query?: string, matcher?: AnyObject) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-fabric/data",
3
- "version": "1.0.0-beta.55",
3
+ "version": "1.0.0-beta.57",
4
4
  "description": "RUF: Data package",
5
5
  "author": "Adarsh Pastakia <adarshpastakia@outlook.com>",
6
6
  "license": "MIT",
@@ -35,9 +35,9 @@
35
35
  "watch": "npm-run-all -p watch:rollup watch:dts"
36
36
  },
37
37
  "dependencies": {
38
- "@react-fabric/core": "^1.0.0-beta.55",
39
- "@react-fabric/date": "^1.0.0-beta.55",
40
- "@react-fabric/form": "^1.0.0-beta.55",
38
+ "@react-fabric/core": "^1.0.0-beta.57",
39
+ "@react-fabric/date": "^1.0.0-beta.57",
40
+ "@react-fabric/form": "^1.0.0-beta.57",
41
41
  "@react-fabric/utilities": "^1.0.0-beta.52",
42
42
  "@tanstack/react-virtual": "^3.13.9",
43
43
  "classnames": "^2.5.1",
@@ -54,5 +54,5 @@
54
54
  "node": ">=18.12.0",
55
55
  "npm": ">=8.19.0"
56
56
  },
57
- "gitHead": "c8454798fb7546174ee8c7ea10e491c5e903e789"
57
+ "gitHead": "9b596a0a8d6cecaa8479f80c495b64fb42ce739f"
58
58
  }
@@ -100,6 +100,7 @@ export const TreeNode = ({
100
100
  className={classNames("flex flex-nowrap items-center")}
101
101
  data-testid={node["data-testid"]}
102
102
  data-test-value={node["data-test-value"]}
103
+ data-id={node.id}
103
104
  >
104
105
  {filler}
105
106
  {node.loading && (
@@ -31,7 +31,7 @@ import {
31
31
  } from "@react-fabric/core";
32
32
  import { Search } from "@react-fabric/form";
33
33
  import { useVirtualizer } from "@tanstack/react-virtual";
34
- import { useImperativeHandle, useMemo, useRef } from "react";
34
+ import { useEffect, useImperativeHandle, useMemo, useRef } from "react";
35
35
  import { TreeNode } from "./TreeNode";
36
36
  import { iconCollapseAll, iconExpandAll, type TreePanelProps } from "./types";
37
37
  import { useTree } from "./useTree";
@@ -110,10 +110,12 @@ export const TreePanel = <T extends KeyValue>({
110
110
  const {
111
111
  tree,
112
112
  query,
113
+ selected: currentSelected,
113
114
  toggleExpand,
114
115
  toggleCheck,
115
116
  expandAll,
116
117
  collapseAll,
118
+ expandAndLoad,
117
119
  select,
118
120
  expand,
119
121
  onFilter,
@@ -154,11 +156,17 @@ export const TreePanel = <T extends KeyValue>({
154
156
  ref,
155
157
  () => ({
156
158
  open: (id: string) => expand(id),
159
+ openAndLoad: (list: string[]) => expandAndLoad(list),
157
160
  select: (id: string) => select(id),
158
161
  }),
159
162
  [],
160
163
  );
161
164
 
165
+ useEffect(() => {
166
+ const index = tree.findIndex((n) => n.id === currentSelected);
167
+ virtualizer.scrollToIndex(index, { align: "auto" });
168
+ }, [currentSelected]);
169
+
162
170
  return (
163
171
  <Section>
164
172
  <Header
package/src/tree/types.ts CHANGED
@@ -21,7 +21,6 @@
21
21
  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
  */
23
23
 
24
- import { AvatarProps } from "@react-fabric/core/dist/types/components/avatar/Avatar";
25
24
  import {
26
25
  type BadgeType,
27
26
  type ChildProp,
@@ -31,7 +30,6 @@ import {
31
30
  type RefProp,
32
31
  type TestProps,
33
32
  } from "@react-fabric/core/dist/types/types";
34
- import { type ElementType } from "react";
35
33
 
36
34
  interface TreeBaseNode<T> extends Omit<IconProps, "icon">, CssProp, TestProps {
37
35
  id: string;
@@ -120,6 +118,7 @@ export interface TreeNodeProps extends ChildProp {
120
118
  export interface TreeRef {
121
119
  select: (id: string) => void;
122
120
  open: (id: string) => void;
121
+ openAndLoad: (list: string[]) => void;
123
122
  }
124
123
 
125
124
  export interface TreePanelProps<T extends KeyValue = KeyValue>
@@ -22,7 +22,7 @@
22
22
  */
23
23
 
24
24
  import { useDebounce } from "@react-fabric/core";
25
- import { EMPTY_ARRAY } from "@react-fabric/utilities";
25
+ import { EMPTY_ARRAY, isEmpty } from "@react-fabric/utilities";
26
26
  import memoizeOne from "memoize-one";
27
27
  import { useCallback, useEffect, useReducer, useRef } from "react";
28
28
  import {
@@ -110,7 +110,7 @@ export const useTree = <T extends KeyValue>({
110
110
  onExpandToggle,
111
111
  }: Partial<TreePanelProps<T>>) => {
112
112
  const componentEvents = useRef({ onSelect, onChecked });
113
- const intialExpand = useRef(defaultExpanded ?? EMPTY_ARRAY);
113
+ const intialExpand = useRef([...(defaultExpanded ?? EMPTY_ARRAY)]);
114
114
  const itemList = createItemList(items);
115
115
 
116
116
  const fireExpandToggle = useCallback(
@@ -127,23 +127,26 @@ export const useTree = <T extends KeyValue>({
127
127
  (node: InternalNode) => {
128
128
  if (node.open && !node.leaf && !node.children?.length) {
129
129
  node.loading = true;
130
- void Promise.resolve(onLoad?.(node.id))
131
- .then((resp = EMPTY_ARRAY) => {
132
- node.children = refactorTree(
133
- resp,
134
- { sorter, defaultExpanded },
135
- { level: node.level + 1, parent: node.id },
136
- );
137
- })
138
- .finally(() => {
139
- node.loading = false;
140
- dispatch({ type: "loaded" });
141
- intialExpand.current?.length > 0 &&
142
- dispatch({
143
- type: "expand",
144
- id: intialExpand.current.shift() as unknown as string,
145
- });
146
- });
130
+ // delay onload callback to avoid state issues
131
+ setTimeout(() => {
132
+ void Promise.resolve(onLoad?.(node.id))
133
+ .then((resp = EMPTY_ARRAY) => {
134
+ node.children = refactorTree(
135
+ resp,
136
+ { sorter, defaultExpanded },
137
+ { level: node.level + 1, parent: node.id },
138
+ );
139
+ })
140
+ .finally(() => {
141
+ node.loading = false;
142
+ dispatch({ type: "loaded" });
143
+ intialExpand.current?.length > 0 &&
144
+ dispatch({
145
+ type: "expand",
146
+ id: intialExpand.current.shift() as unknown as string,
147
+ });
148
+ });
149
+ }, 100);
147
150
  } else {
148
151
  dispatch({ type: "loaded" });
149
152
  intialExpand.current?.length > 0 &&
@@ -170,6 +173,13 @@ export const useTree = <T extends KeyValue>({
170
173
  [onChecked],
171
174
  );
172
175
 
176
+ const fireQuery = useDebounce(
177
+ (query: string) => {
178
+ onQuery?.(query);
179
+ },
180
+ [onQuery],
181
+ );
182
+
173
183
  const [state, dispatch] = useReducer(
174
184
  (state: TreeState, action: TreeActions) => {
175
185
  if (action.type === "load") {
@@ -193,7 +203,7 @@ export const useTree = <T extends KeyValue>({
193
203
  state.itemMap = makeTreeMap(state.items);
194
204
  fireExpandToggle(Array.from(state.itemMap.values()));
195
205
  state.tree = flattenTree(state.items);
196
- state.selected && updateSelection(state.itemMap, state.selected, true);
206
+ state.selected = updateSelection(state.itemMap, selected, true);
197
207
  state.checked?.forEach((id) => updateChecked(state.itemMap, id, 1));
198
208
  return { ...state };
199
209
  }
@@ -229,7 +239,16 @@ export const useTree = <T extends KeyValue>({
229
239
  }
230
240
  if (action.type === "filter") {
231
241
  if (onQuery) {
232
- onQuery(action.query ?? "");
242
+ // TODO: onQuery should provide new tree listing
243
+ // save current tree state as preQueryState
244
+ // on clearing filter restore preQueryState
245
+ if (!isEmpty(action.query)) {
246
+ // state.prevItems = state.items;
247
+ fireQuery(action.query);
248
+ } else {
249
+ // state.items = state.prevItems;
250
+ // build tree map
251
+ }
233
252
  } else {
234
253
  filterTree(state.itemMap, action.query, matcher);
235
254
  state.tree = flattenTree(state.items);
@@ -237,12 +256,11 @@ export const useTree = <T extends KeyValue>({
237
256
  return { ...state, query: action.query };
238
257
  }
239
258
  if (action.type === "toggleSelect") {
240
- if (state.selected) {
241
- updateSelection(state.itemMap, state.selected);
242
- }
243
259
  if (!onSelect) {
244
- updateSelection(state.itemMap, action.id, true);
245
- state.selected = action.id;
260
+ if (state.selected) {
261
+ updateSelection(state.itemMap, state.selected);
262
+ }
263
+ state.selected = updateSelection(state.itemMap, action.id, true);
246
264
  state.tree = flattenTree(state.items);
247
265
  } else {
248
266
  fireSelected(action.id, state.itemMap.get(action.id)?.data);
@@ -253,8 +271,7 @@ export const useTree = <T extends KeyValue>({
253
271
  if (state.selected) {
254
272
  updateSelection(state.itemMap, state.selected);
255
273
  }
256
- updateSelection(state.itemMap, action.id, true);
257
- state.selected = action.id;
274
+ state.selected = updateSelection(state.itemMap, action.id, true);
258
275
  state.tree = flattenTree(state.items);
259
276
  return { ...state };
260
277
  }
@@ -329,6 +346,13 @@ export const useTree = <T extends KeyValue>({
329
346
  dispatch({ type: "expand", id });
330
347
  }, []);
331
348
 
349
+ const expandAndLoad = useCallback((expandList: string[]) => {
350
+ if (expandList.length > 0) {
351
+ intialExpand.current = [...expandList];
352
+ dispatch({ type: "expand", id: intialExpand.current.shift() as string });
353
+ }
354
+ }, []);
355
+
332
356
  const expandAll = useCallback(() => {
333
357
  dispatch({ type: "expandAll" });
334
358
  }, []);
@@ -348,10 +372,12 @@ export const useTree = <T extends KeyValue>({
348
372
  return {
349
373
  tree: state.tree,
350
374
  query: state.query,
375
+ selected: state.selected,
351
376
  toggleExpand,
352
377
  expandAll,
353
378
  collapseAll,
354
379
  toggleCheck,
380
+ expandAndLoad,
355
381
  select,
356
382
  expand,
357
383
  onFilter,
package/src/tree/utils.ts CHANGED
@@ -127,10 +127,10 @@ export const flattenTree = (
127
127
 
128
128
  export const updateSelection = (
129
129
  nodes: Map<string, InternalNode>,
130
- id: string,
130
+ id?: string,
131
131
  selected?: true,
132
132
  ) => {
133
- const node = nodes.get(id);
133
+ const node = nodes.get(id ?? "");
134
134
  if (node) {
135
135
  // change selection
136
136
  node.selected = selected;
@@ -142,6 +142,7 @@ export const updateSelection = (
142
142
  // selected && parentNode && (parentNode.open = true);
143
143
  parent = parentNode?.parent;
144
144
  }
145
+ return id;
145
146
  }
146
147
  };
147
148
 
@@ -337,8 +337,10 @@ const _VirtualGallery = <T extends AnyObject>({
337
337
  ))}
338
338
  </div>
339
339
  ))}
340
- {onLoadMore && (
341
- <div className="h-16">{loading && <Skeleton />}</div>
340
+ {loading && (
341
+ <div>
342
+ <Skeleton />
343
+ </div>
342
344
  )}
343
345
  </div>
344
346
  </div>