@headless-tree/core 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @headless-tree/core
2
2
 
3
+ ## 0.0.5
4
+
5
+ ### Patch Changes
6
+
7
+ - 751682a: dev release
8
+
3
9
  ## 0.0.4
4
10
 
5
11
  ### Patch Changes
@@ -11,10 +11,10 @@ const buildItemInstance = (features, tree, itemId) => {
11
11
  return itemInstance;
12
12
  };
13
13
  const createTree = (initialConfig) => {
14
- var _a, _b, _c, _d, _e;
14
+ var _a, _b, _c, _d, _e, _f;
15
15
  const treeInstance = {};
16
16
  const additionalFeatures = [feature_1.treeFeature, ...((_a = initialConfig.features) !== null && _a !== void 0 ? _a : [])];
17
- let state = additionalFeatures.reduce((acc, feature) => { var _a, _b; return (_b = (_a = feature.getInitialState) === null || _a === void 0 ? void 0 : _a.call(feature, acc, treeInstance)) !== null && _b !== void 0 ? _b : acc; }, (_b = initialConfig.state) !== null && _b !== void 0 ? _b : {});
17
+ let state = additionalFeatures.reduce((acc, feature) => { var _a, _b; return (_b = (_a = feature.getInitialState) === null || _a === void 0 ? void 0 : _a.call(feature, acc, treeInstance)) !== null && _b !== void 0 ? _b : acc; }, (_c = (_b = initialConfig.initialState) !== null && _b !== void 0 ? _b : initialConfig.state) !== null && _c !== void 0 ? _c : {});
18
18
  let config = additionalFeatures.reduce((acc, feature) => { var _a, _b; return (_b = (_a = feature.getDefaultConfig) === null || _a === void 0 ? void 0 : _a.call(feature, acc, treeInstance)) !== null && _b !== void 0 ? _b : acc; }, initialConfig);
19
19
  let treeElement;
20
20
  const treeDataRef = { current: {} };
@@ -107,8 +107,8 @@ const createTree = (initialConfig) => {
107
107
  // todo sort features
108
108
  const features = [mainFeature, ...additionalFeatures];
109
109
  for (const feature of features) {
110
- Object.assign(treeInstance, (_d = (_c = feature.createTreeInstance) === null || _c === void 0 ? void 0 : _c.call(feature, Object.assign({}, treeInstance), treeInstance)) !== null && _d !== void 0 ? _d : {});
111
- Object.assign(hotkeyPresets, (_e = feature.hotkeys) !== null && _e !== void 0 ? _e : {});
110
+ Object.assign(treeInstance, (_e = (_d = feature.createTreeInstance) === null || _d === void 0 ? void 0 : _d.call(feature, Object.assign({}, treeInstance), treeInstance)) !== null && _e !== void 0 ? _e : {});
111
+ Object.assign(hotkeyPresets, (_f = feature.hotkeys) !== null && _f !== void 0 ? _f : {});
112
112
  }
113
113
  rebuildItemMeta(mainFeature);
114
114
  return treeInstance;
@@ -13,7 +13,7 @@ exports.dragAndDropFeature = {
13
13
  } })),
14
14
  createItemInstance: (prev, item, tree) => (Object.assign(Object.assign({}, prev), { getProps: () => {
15
15
  var _a, _b, _c;
16
- return (Object.assign(Object.assign({}, prev.getProps()), { draggable: (_c = (_b = (_a = tree.getConfig()).isItemDraggable) === null || _b === void 0 ? void 0 : _b.call(_a, item)) !== null && _c !== void 0 ? _c : true, onDragStart: (e) => {
16
+ return (Object.assign(Object.assign({}, prev.getProps()), { draggable: (_c = (_b = (_a = tree.getConfig()).isItemDraggable) === null || _b === void 0 ? void 0 : _b.call(_a, item)) !== null && _c !== void 0 ? _c : true, onDragStart: item.getMemoizedProp("dnd/onDragStart", () => (e) => {
17
17
  var _a, _b, _c, _d, _e;
18
18
  const selectedItems = tree.getSelectedItems();
19
19
  const items = selectedItems.includes(item) ? selectedItems : [item];
@@ -33,7 +33,7 @@ exports.dragAndDropFeature = {
33
33
  draggedItems: items,
34
34
  draggingOverItem: tree.getFocusedItem(),
35
35
  });
36
- }, onDragOver: (e) => {
36
+ }), onDragOver: item.getMemoizedProp("dnd/onDragOver", () => (e) => {
37
37
  var _a, _b, _c, _d, _e;
38
38
  const target = (0, utils_1.getDropTarget)(e, item, tree);
39
39
  const dataRef = tree.getDataRef();
@@ -51,12 +51,12 @@ exports.dragAndDropFeature = {
51
51
  }
52
52
  dataRef.current.lastDragCode = nextDragCode;
53
53
  (_e = (_d = tree.getConfig()).setDndState) === null || _e === void 0 ? void 0 : _e.call(_d, (state) => (Object.assign(Object.assign({}, state), { dragTarget: target, draggingOverItem: item })));
54
- }, onDragLeave: () => {
54
+ }), onDragLeave: item.getMemoizedProp("dnd/onDragLeave", () => () => {
55
55
  var _a, _b;
56
56
  const dataRef = tree.getDataRef();
57
57
  dataRef.current.lastDragCode = "no-drag";
58
58
  (_b = (_a = tree.getConfig()).setDndState) === null || _b === void 0 ? void 0 : _b.call(_a, (state) => (Object.assign(Object.assign({}, state), { draggingOverItem: undefined, dragTarget: undefined })));
59
- }, onDrop: (e) => {
59
+ }), onDrop: item.getMemoizedProp("dnd/onDrop", () => (e) => {
60
60
  var _a, _b, _c, _d, _e;
61
61
  const dataRef = tree.getDataRef();
62
62
  const target = (0, utils_1.getDropTarget)(e, item, tree);
@@ -75,7 +75,7 @@ exports.dragAndDropFeature = {
75
75
  (_e = config.onDropForeignDragObject) === null || _e === void 0 ? void 0 : _e.call(config, e.dataTransfer, target);
76
76
  }
77
77
  // TODO rebuild tree?
78
- } }));
78
+ }) }));
79
79
  }, isDropTarget: () => {
80
80
  const target = tree.getDropTarget();
81
81
  return target ? target.item.getId() === item.getId() : false;
@@ -4,6 +4,7 @@ export type MainFeatureDef<T = any> = {
4
4
  state: {};
5
5
  config: {
6
6
  features?: FeatureImplementation<any>[];
7
+ initialState?: Partial<TreeState<T>>;
7
8
  state?: Partial<TreeState<T>>;
8
9
  setState?: SetStateFn<TreeState<T>>;
9
10
  };
@@ -51,7 +51,7 @@ exports.selectionFeature = {
51
51
  else {
52
52
  item.select();
53
53
  }
54
- }, getProps: () => (Object.assign(Object.assign({}, prev.getProps()), { onClick: (e) => {
54
+ }, getProps: () => (Object.assign(Object.assign({}, prev.getProps()), { onClick: item.getMemoizedProp("selection/onClick", () => (e) => {
55
55
  var _a, _b;
56
56
  if (e.shiftKey) {
57
57
  item.selectUpTo(e.ctrlKey || e.metaKey);
@@ -63,7 +63,7 @@ exports.selectionFeature = {
63
63
  tree.setSelectedItems([item.getItemMeta().itemId]);
64
64
  }
65
65
  (_b = (_a = prev.getProps()).onClick) === null || _b === void 0 ? void 0 : _b.call(_a, e);
66
- } })) })),
66
+ }) })) })),
67
67
  hotkeys: {
68
68
  // setSelectedItem: {
69
69
  // hotkey: "space",
@@ -108,7 +108,8 @@ exports.treeFeature = {
108
108
  }, getId: () => item.getItemMeta().itemId, getProps: () => {
109
109
  var _a;
110
110
  const itemMeta = item.getItemMeta();
111
- return Object.assign(Object.assign({}, (_a = prev.getProps) === null || _a === void 0 ? void 0 : _a.call(prev)), { role: "treeitem", "aria-setsize": itemMeta.setSize, "aria-posinset": itemMeta.posInSet, "aria-selected": false, "aria-label": item.getItemName(), "aria-level": itemMeta.level, tabIndex: item.isFocused() ? 0 : -1, onClick: (e) => {
111
+ return Object.assign(Object.assign({}, (_a = prev.getProps) === null || _a === void 0 ? void 0 : _a.call(prev)), { role: "treeitem", "aria-setsize": itemMeta.setSize, "aria-posinset": itemMeta.posInSet, "aria-selected": false, "aria-label": item.getItemName(), "aria-level": itemMeta.level, tabIndex: item.isFocused() ? 0 : -1, onClick: item.getMemoizedProp("tree/onClick", () => (e) => {
112
+ console.log("onClick", item.getId());
112
113
  item.setFocused();
113
114
  item.primaryAction();
114
115
  if (e.ctrlKey || e.shiftKey || e.metaKey) {
@@ -123,7 +124,7 @@ exports.treeFeature = {
123
124
  else {
124
125
  item.expand();
125
126
  }
126
- } });
127
+ }) });
127
128
  }, expand: () => tree.expandItem(item.getItemMeta().itemId), collapse: () => tree.collapseItem(item.getItemMeta().itemId), getItemData: () => tree.retrieveItemData(item.getItemMeta().itemId), isExpanded: () => tree.getState().expandedItems.includes(item.getItemMeta().itemId), isFocused: () => tree.getState().focusedItem === item.getItemMeta().itemId ||
128
129
  (tree.getState().focusedItem === null && item.getItemMeta().index === 0), isFolder: () => item.getItemMeta().level === -1 ||
129
130
  tree.getConfig().isItemFolder(item), getItemName: () => {
@@ -144,7 +145,23 @@ exports.treeFeature = {
144
145
  1;
145
146
  }, getChildren: () => tree
146
147
  .retrieveChildrenIds(item.getItemMeta().itemId)
147
- .map((id) => tree.getItemInstance(id)), getTree: () => tree, getItemAbove: () => tree.getItems()[item.getItemMeta().index - 1], getItemBelow: () => tree.getItems()[item.getItemMeta().index + 1] })),
148
+ .map((id) => tree.getItemInstance(id)), getTree: () => tree, getItemAbove: () => tree.getItems()[item.getItemMeta().index - 1], getItemBelow: () => tree.getItems()[item.getItemMeta().index + 1], getMemoizedProp: (name, create, deps) => {
149
+ var _a, _b, _c, _d, _e;
150
+ var _f, _g;
151
+ const data = item.getDataRef();
152
+ const memoizedValue = (_a = data.current.memoizedValues) === null || _a === void 0 ? void 0 : _a[name];
153
+ if (memoizedValue &&
154
+ (!deps ||
155
+ ((_c = (_b = data.current.memoizedDeps) === null || _b === void 0 ? void 0 : _b[name]) === null || _c === void 0 ? void 0 : _c.every((d, i) => d === deps[i])))) {
156
+ return memoizedValue;
157
+ }
158
+ (_d = (_f = data.current).memoizedDeps) !== null && _d !== void 0 ? _d : (_f.memoizedDeps = {});
159
+ (_e = (_g = data.current).memoizedValues) !== null && _e !== void 0 ? _e : (_g.memoizedValues = {});
160
+ const value = create();
161
+ data.current.memoizedDeps[name] = deps;
162
+ data.current.memoizedValues[name] = value;
163
+ return value;
164
+ } })),
148
165
  hotkeys: {
149
166
  focusNextItem: {
150
167
  hotkey: "ArrowDown",
@@ -7,6 +7,10 @@ export type ItemMeta = {
7
7
  setSize: number;
8
8
  posInSet: number;
9
9
  };
10
+ export type TreeItemDataRef = {
11
+ memoizedValues: Record<string, any>;
12
+ memoizedDeps: Record<string, any[] | undefined>;
13
+ };
10
14
  export type TreeFeatureDef<T> = {
11
15
  state: {
12
16
  expandedItems: string[];
@@ -52,6 +56,7 @@ export type TreeFeatureDef<T> = {
52
56
  getTree: () => TreeInstance<T>;
53
57
  getItemAbove: () => ItemInstance<T> | null;
54
58
  getItemBelow: () => ItemInstance<T> | null;
59
+ getMemoizedProp: <X>(name: string, create: () => X, deps?: any[]) => X;
55
60
  };
56
61
  hotkeys: "focusNextItem" | "focusPreviousItem" | "expandOrDown" | "collapseOrUp" | "focusFirstItem" | "focusLastItem";
57
62
  };
@@ -8,10 +8,10 @@ const buildItemInstance = (features, tree, itemId) => {
8
8
  return itemInstance;
9
9
  };
10
10
  export const createTree = (initialConfig) => {
11
- var _a, _b, _c, _d, _e;
11
+ var _a, _b, _c, _d, _e, _f;
12
12
  const treeInstance = {};
13
13
  const additionalFeatures = [treeFeature, ...((_a = initialConfig.features) !== null && _a !== void 0 ? _a : [])];
14
- let state = additionalFeatures.reduce((acc, feature) => { var _a, _b; return (_b = (_a = feature.getInitialState) === null || _a === void 0 ? void 0 : _a.call(feature, acc, treeInstance)) !== null && _b !== void 0 ? _b : acc; }, (_b = initialConfig.state) !== null && _b !== void 0 ? _b : {});
14
+ let state = additionalFeatures.reduce((acc, feature) => { var _a, _b; return (_b = (_a = feature.getInitialState) === null || _a === void 0 ? void 0 : _a.call(feature, acc, treeInstance)) !== null && _b !== void 0 ? _b : acc; }, (_c = (_b = initialConfig.initialState) !== null && _b !== void 0 ? _b : initialConfig.state) !== null && _c !== void 0 ? _c : {});
15
15
  let config = additionalFeatures.reduce((acc, feature) => { var _a, _b; return (_b = (_a = feature.getDefaultConfig) === null || _a === void 0 ? void 0 : _a.call(feature, acc, treeInstance)) !== null && _b !== void 0 ? _b : acc; }, initialConfig);
16
16
  let treeElement;
17
17
  const treeDataRef = { current: {} };
@@ -104,8 +104,8 @@ export const createTree = (initialConfig) => {
104
104
  // todo sort features
105
105
  const features = [mainFeature, ...additionalFeatures];
106
106
  for (const feature of features) {
107
- Object.assign(treeInstance, (_d = (_c = feature.createTreeInstance) === null || _c === void 0 ? void 0 : _c.call(feature, Object.assign({}, treeInstance), treeInstance)) !== null && _d !== void 0 ? _d : {});
108
- Object.assign(hotkeyPresets, (_e = feature.hotkeys) !== null && _e !== void 0 ? _e : {});
107
+ Object.assign(treeInstance, (_e = (_d = feature.createTreeInstance) === null || _d === void 0 ? void 0 : _d.call(feature, Object.assign({}, treeInstance), treeInstance)) !== null && _e !== void 0 ? _e : {});
108
+ Object.assign(hotkeyPresets, (_f = feature.hotkeys) !== null && _f !== void 0 ? _f : {});
109
109
  }
110
110
  rebuildItemMeta(mainFeature);
111
111
  return treeInstance;
@@ -10,7 +10,7 @@ export const dragAndDropFeature = {
10
10
  } })),
11
11
  createItemInstance: (prev, item, tree) => (Object.assign(Object.assign({}, prev), { getProps: () => {
12
12
  var _a, _b, _c;
13
- return (Object.assign(Object.assign({}, prev.getProps()), { draggable: (_c = (_b = (_a = tree.getConfig()).isItemDraggable) === null || _b === void 0 ? void 0 : _b.call(_a, item)) !== null && _c !== void 0 ? _c : true, onDragStart: (e) => {
13
+ return (Object.assign(Object.assign({}, prev.getProps()), { draggable: (_c = (_b = (_a = tree.getConfig()).isItemDraggable) === null || _b === void 0 ? void 0 : _b.call(_a, item)) !== null && _c !== void 0 ? _c : true, onDragStart: item.getMemoizedProp("dnd/onDragStart", () => (e) => {
14
14
  var _a, _b, _c, _d, _e;
15
15
  const selectedItems = tree.getSelectedItems();
16
16
  const items = selectedItems.includes(item) ? selectedItems : [item];
@@ -30,7 +30,7 @@ export const dragAndDropFeature = {
30
30
  draggedItems: items,
31
31
  draggingOverItem: tree.getFocusedItem(),
32
32
  });
33
- }, onDragOver: (e) => {
33
+ }), onDragOver: item.getMemoizedProp("dnd/onDragOver", () => (e) => {
34
34
  var _a, _b, _c, _d, _e;
35
35
  const target = getDropTarget(e, item, tree);
36
36
  const dataRef = tree.getDataRef();
@@ -48,12 +48,12 @@ export const dragAndDropFeature = {
48
48
  }
49
49
  dataRef.current.lastDragCode = nextDragCode;
50
50
  (_e = (_d = tree.getConfig()).setDndState) === null || _e === void 0 ? void 0 : _e.call(_d, (state) => (Object.assign(Object.assign({}, state), { dragTarget: target, draggingOverItem: item })));
51
- }, onDragLeave: () => {
51
+ }), onDragLeave: item.getMemoizedProp("dnd/onDragLeave", () => () => {
52
52
  var _a, _b;
53
53
  const dataRef = tree.getDataRef();
54
54
  dataRef.current.lastDragCode = "no-drag";
55
55
  (_b = (_a = tree.getConfig()).setDndState) === null || _b === void 0 ? void 0 : _b.call(_a, (state) => (Object.assign(Object.assign({}, state), { draggingOverItem: undefined, dragTarget: undefined })));
56
- }, onDrop: (e) => {
56
+ }), onDrop: item.getMemoizedProp("dnd/onDrop", () => (e) => {
57
57
  var _a, _b, _c, _d, _e;
58
58
  const dataRef = tree.getDataRef();
59
59
  const target = getDropTarget(e, item, tree);
@@ -72,7 +72,7 @@ export const dragAndDropFeature = {
72
72
  (_e = config.onDropForeignDragObject) === null || _e === void 0 ? void 0 : _e.call(config, e.dataTransfer, target);
73
73
  }
74
74
  // TODO rebuild tree?
75
- } }));
75
+ }) }));
76
76
  }, isDropTarget: () => {
77
77
  const target = tree.getDropTarget();
78
78
  return target ? target.item.getId() === item.getId() : false;
@@ -4,6 +4,7 @@ export type MainFeatureDef<T = any> = {
4
4
  state: {};
5
5
  config: {
6
6
  features?: FeatureImplementation<any>[];
7
+ initialState?: Partial<TreeState<T>>;
7
8
  state?: Partial<TreeState<T>>;
8
9
  setState?: SetStateFn<TreeState<T>>;
9
10
  };
@@ -48,7 +48,7 @@ export const selectionFeature = {
48
48
  else {
49
49
  item.select();
50
50
  }
51
- }, getProps: () => (Object.assign(Object.assign({}, prev.getProps()), { onClick: (e) => {
51
+ }, getProps: () => (Object.assign(Object.assign({}, prev.getProps()), { onClick: item.getMemoizedProp("selection/onClick", () => (e) => {
52
52
  var _a, _b;
53
53
  if (e.shiftKey) {
54
54
  item.selectUpTo(e.ctrlKey || e.metaKey);
@@ -60,7 +60,7 @@ export const selectionFeature = {
60
60
  tree.setSelectedItems([item.getItemMeta().itemId]);
61
61
  }
62
62
  (_b = (_a = prev.getProps()).onClick) === null || _b === void 0 ? void 0 : _b.call(_a, e);
63
- } })) })),
63
+ }) })) })),
64
64
  hotkeys: {
65
65
  // setSelectedItem: {
66
66
  // hotkey: "space",
@@ -105,7 +105,8 @@ export const treeFeature = {
105
105
  }, getId: () => item.getItemMeta().itemId, getProps: () => {
106
106
  var _a;
107
107
  const itemMeta = item.getItemMeta();
108
- return Object.assign(Object.assign({}, (_a = prev.getProps) === null || _a === void 0 ? void 0 : _a.call(prev)), { role: "treeitem", "aria-setsize": itemMeta.setSize, "aria-posinset": itemMeta.posInSet, "aria-selected": false, "aria-label": item.getItemName(), "aria-level": itemMeta.level, tabIndex: item.isFocused() ? 0 : -1, onClick: (e) => {
108
+ return Object.assign(Object.assign({}, (_a = prev.getProps) === null || _a === void 0 ? void 0 : _a.call(prev)), { role: "treeitem", "aria-setsize": itemMeta.setSize, "aria-posinset": itemMeta.posInSet, "aria-selected": false, "aria-label": item.getItemName(), "aria-level": itemMeta.level, tabIndex: item.isFocused() ? 0 : -1, onClick: item.getMemoizedProp("tree/onClick", () => (e) => {
109
+ console.log("onClick", item.getId());
109
110
  item.setFocused();
110
111
  item.primaryAction();
111
112
  if (e.ctrlKey || e.shiftKey || e.metaKey) {
@@ -120,7 +121,7 @@ export const treeFeature = {
120
121
  else {
121
122
  item.expand();
122
123
  }
123
- } });
124
+ }) });
124
125
  }, expand: () => tree.expandItem(item.getItemMeta().itemId), collapse: () => tree.collapseItem(item.getItemMeta().itemId), getItemData: () => tree.retrieveItemData(item.getItemMeta().itemId), isExpanded: () => tree.getState().expandedItems.includes(item.getItemMeta().itemId), isFocused: () => tree.getState().focusedItem === item.getItemMeta().itemId ||
125
126
  (tree.getState().focusedItem === null && item.getItemMeta().index === 0), isFolder: () => item.getItemMeta().level === -1 ||
126
127
  tree.getConfig().isItemFolder(item), getItemName: () => {
@@ -141,7 +142,23 @@ export const treeFeature = {
141
142
  1;
142
143
  }, getChildren: () => tree
143
144
  .retrieveChildrenIds(item.getItemMeta().itemId)
144
- .map((id) => tree.getItemInstance(id)), getTree: () => tree, getItemAbove: () => tree.getItems()[item.getItemMeta().index - 1], getItemBelow: () => tree.getItems()[item.getItemMeta().index + 1] })),
145
+ .map((id) => tree.getItemInstance(id)), getTree: () => tree, getItemAbove: () => tree.getItems()[item.getItemMeta().index - 1], getItemBelow: () => tree.getItems()[item.getItemMeta().index + 1], getMemoizedProp: (name, create, deps) => {
146
+ var _a, _b, _c, _d, _e;
147
+ var _f, _g;
148
+ const data = item.getDataRef();
149
+ const memoizedValue = (_a = data.current.memoizedValues) === null || _a === void 0 ? void 0 : _a[name];
150
+ if (memoizedValue &&
151
+ (!deps ||
152
+ ((_c = (_b = data.current.memoizedDeps) === null || _b === void 0 ? void 0 : _b[name]) === null || _c === void 0 ? void 0 : _c.every((d, i) => d === deps[i])))) {
153
+ return memoizedValue;
154
+ }
155
+ (_d = (_f = data.current).memoizedDeps) !== null && _d !== void 0 ? _d : (_f.memoizedDeps = {});
156
+ (_e = (_g = data.current).memoizedValues) !== null && _e !== void 0 ? _e : (_g.memoizedValues = {});
157
+ const value = create();
158
+ data.current.memoizedDeps[name] = deps;
159
+ data.current.memoizedValues[name] = value;
160
+ return value;
161
+ } })),
145
162
  hotkeys: {
146
163
  focusNextItem: {
147
164
  hotkey: "ArrowDown",
@@ -7,6 +7,10 @@ export type ItemMeta = {
7
7
  setSize: number;
8
8
  posInSet: number;
9
9
  };
10
+ export type TreeItemDataRef = {
11
+ memoizedValues: Record<string, any>;
12
+ memoizedDeps: Record<string, any[] | undefined>;
13
+ };
10
14
  export type TreeFeatureDef<T> = {
11
15
  state: {
12
16
  expandedItems: string[];
@@ -52,6 +56,7 @@ export type TreeFeatureDef<T> = {
52
56
  getTree: () => TreeInstance<T>;
53
57
  getItemAbove: () => ItemInstance<T> | null;
54
58
  getItemBelow: () => ItemInstance<T> | null;
59
+ getMemoizedProp: <X>(name: string, create: () => X, deps?: any[]) => X;
55
60
  };
56
61
  hotkeys: "focusNextItem" | "focusPreviousItem" | "expandOrDown" | "collapseOrUp" | "focusFirstItem" | "focusLastItem";
57
62
  };
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@headless-tree/core",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "main": "lib/cjs/index.js",
5
5
  "module": "lib/esm/index.js",
6
6
  "types": "lib/esm/index.d.ts",
7
7
  "sideEffects": false,
8
8
  "scripts": {
9
- "build:cjs": "tsc",
10
- "build:esm": "tsc -m es2015 --outDir lib/esm",
9
+ "build:cjs": "tsc -m commonjs --outDir lib/cjs",
10
+ "build:esm": "tsc",
11
11
  "start": "tsc -w"
12
12
  },
13
13
  "repository": {
@@ -38,7 +38,7 @@ export const createTree = <T>(
38
38
  const additionalFeatures = [treeFeature, ...(initialConfig.features ?? [])];
39
39
  let state = additionalFeatures.reduce(
40
40
  (acc, feature) => feature.getInitialState?.(acc, treeInstance) ?? acc,
41
- initialConfig.state ?? {}
41
+ initialConfig.initialState ?? initialConfig.state ?? {}
42
42
  ) as TreeState<T>;
43
43
  let config = additionalFeatures.reduce(
44
44
  (acc, feature) => feature.getDefaultConfig?.(acc, treeInstance) ?? acc,
@@ -33,7 +33,7 @@ export const dragAndDropFeature: FeatureImplementation<
33
33
 
34
34
  draggable: tree.getConfig().isItemDraggable?.(item) ?? true,
35
35
 
36
- onDragStart: (e) => {
36
+ onDragStart: item.getMemoizedProp("dnd/onDragStart", () => (e) => {
37
37
  const selectedItems = tree.getSelectedItems();
38
38
  const items = selectedItems.includes(item) ? selectedItems : [item];
39
39
  const config = tree.getConfig();
@@ -56,9 +56,9 @@ export const dragAndDropFeature: FeatureImplementation<
56
56
  draggedItems: items,
57
57
  draggingOverItem: tree.getFocusedItem(),
58
58
  });
59
- },
59
+ }),
60
60
 
61
- onDragOver: (e) => {
61
+ onDragOver: item.getMemoizedProp("dnd/onDragOver", () => (e) => {
62
62
  const target = getDropTarget(e, item, tree);
63
63
  const dataRef = tree.getDataRef<DndDataRef>();
64
64
 
@@ -87,9 +87,9 @@ export const dragAndDropFeature: FeatureImplementation<
87
87
  dragTarget: target,
88
88
  draggingOverItem: item,
89
89
  }));
90
- },
90
+ }),
91
91
 
92
- onDragLeave: () => {
92
+ onDragLeave: item.getMemoizedProp("dnd/onDragLeave", () => () => {
93
93
  const dataRef = tree.getDataRef<DndDataRef>();
94
94
  dataRef.current.lastDragCode = "no-drag";
95
95
  tree.getConfig().setDndState?.((state) => ({
@@ -97,9 +97,9 @@ export const dragAndDropFeature: FeatureImplementation<
97
97
  draggingOverItem: undefined,
98
98
  dragTarget: undefined,
99
99
  }));
100
- },
100
+ }),
101
101
 
102
- onDrop: (e) => {
102
+ onDrop: item.getMemoizedProp("dnd/onDrop", () => (e) => {
103
103
  const dataRef = tree.getDataRef<DndDataRef>();
104
104
  const target = getDropTarget(e, item, tree);
105
105
 
@@ -120,7 +120,7 @@ export const dragAndDropFeature: FeatureImplementation<
120
120
  config.onDropForeignDragObject?.(e.dataTransfer, target);
121
121
  }
122
122
  // TODO rebuild tree?
123
- },
123
+ }),
124
124
  }),
125
125
 
126
126
  isDropTarget: () => {
@@ -12,6 +12,7 @@ export type MainFeatureDef<T = any> = {
12
12
  state: {};
13
13
  config: {
14
14
  features?: FeatureImplementation<any>[];
15
+ initialState?: Partial<TreeState<T>>;
15
16
  state?: Partial<TreeState<T>>;
16
17
  setState?: SetStateFn<TreeState<T>>;
17
18
  };
@@ -91,7 +91,7 @@ export const selectionFeature: FeatureImplementation<
91
91
 
92
92
  getProps: () => ({
93
93
  ...prev.getProps(),
94
- onClick: (e) => {
94
+ onClick: item.getMemoizedProp("selection/onClick", () => (e) => {
95
95
  if (e.shiftKey) {
96
96
  item.selectUpTo(e.ctrlKey || e.metaKey);
97
97
  } else if (e.ctrlKey || e.metaKey) {
@@ -101,7 +101,7 @@ export const selectionFeature: FeatureImplementation<
101
101
  }
102
102
 
103
103
  prev.getProps().onClick?.(e);
104
- },
104
+ }),
105
105
  }),
106
106
  }),
107
107
 
@@ -1,5 +1,5 @@
1
1
  import { FeatureImplementation, ItemInstance } from "../../types/core";
2
- import { ItemMeta, TreeFeatureDef } from "./types";
2
+ import { ItemMeta, TreeFeatureDef, TreeItemDataRef } from "./types";
3
3
  import { makeStateUpdater, memo, poll } from "../../utils";
4
4
  import { MainFeatureDef } from "../main/types";
5
5
  import { HotkeysCoreFeatureDef } from "../hotkeys-core/types";
@@ -174,7 +174,8 @@ export const treeFeature: FeatureImplementation<
174
174
  "aria-label": item.getItemName(),
175
175
  "aria-level": itemMeta.level,
176
176
  tabIndex: item.isFocused() ? 0 : -1,
177
- onClick: (e) => {
177
+ onClick: item.getMemoizedProp("tree/onClick", () => (e) => {
178
+ console.log("onClick", item.getId());
178
179
  item.setFocused();
179
180
  item.primaryAction();
180
181
 
@@ -191,7 +192,7 @@ export const treeFeature: FeatureImplementation<
191
192
  } else {
192
193
  item.expand();
193
194
  }
194
- },
195
+ }),
195
196
  };
196
197
  },
197
198
  expand: () => tree.expandItem(item.getItemMeta().itemId),
@@ -235,6 +236,23 @@ export const treeFeature: FeatureImplementation<
235
236
  getTree: () => tree as any,
236
237
  getItemAbove: () => tree.getItems()[item.getItemMeta().index - 1],
237
238
  getItemBelow: () => tree.getItems()[item.getItemMeta().index + 1],
239
+ getMemoizedProp: (name, create, deps) => {
240
+ const data = item.getDataRef<TreeItemDataRef>();
241
+ const memoizedValue = data.current.memoizedValues?.[name];
242
+ if (
243
+ memoizedValue &&
244
+ (!deps ||
245
+ data.current.memoizedDeps?.[name]?.every((d, i) => d === deps![i]))
246
+ ) {
247
+ return memoizedValue;
248
+ }
249
+ data.current.memoizedDeps ??= {};
250
+ data.current.memoizedValues ??= {};
251
+ const value = create();
252
+ data.current.memoizedDeps[name] = deps;
253
+ data.current.memoizedValues[name] = value;
254
+ return value;
255
+ },
238
256
  }),
239
257
 
240
258
  hotkeys: {
@@ -9,6 +9,11 @@ export type ItemMeta = {
9
9
  posInSet: number;
10
10
  };
11
11
 
12
+ export type TreeItemDataRef = {
13
+ memoizedValues: Record<string, any>;
14
+ memoizedDeps: Record<string, any[] | undefined>;
15
+ };
16
+
12
17
  export type TreeFeatureDef<T> = {
13
18
  state: {
14
19
  expandedItems: string[];
@@ -59,6 +64,7 @@ export type TreeFeatureDef<T> = {
59
64
  getTree: () => TreeInstance<T>;
60
65
  getItemAbove: () => ItemInstance<T> | null;
61
66
  getItemBelow: () => ItemInstance<T> | null;
67
+ getMemoizedProp: <X>(name: string, create: () => X, deps?: any[]) => X;
62
68
  };
63
69
  hotkeys:
64
70
  | "focusNextItem"
package/tsconfig.json CHANGED
@@ -2,6 +2,6 @@
2
2
  "extends": "../../tsconfig.json",
3
3
  "include": ["./src/**/*"],
4
4
  "compilerOptions": {
5
- "outDir": "lib/cjs"
5
+ "outDir": "lib/esm"
6
6
  }
7
7
  }