@proyecto-viviana/solid-stately 0.2.7 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. package/README.md +30 -283
  2. package/dist/autocomplete/createAutocompleteState.d.ts +2 -2
  3. package/dist/autocomplete/index.d.ts +1 -1
  4. package/dist/calendar/IncompleteDate.d.ts +61 -0
  5. package/dist/calendar/createCalendarState.d.ts +41 -16
  6. package/dist/calendar/createDateFieldState.d.ts +39 -9
  7. package/dist/calendar/createDatePickerState.d.ts +60 -0
  8. package/dist/calendar/createRangeCalendarState.d.ts +37 -10
  9. package/dist/calendar/createTimeFieldState.d.ts +34 -7
  10. package/dist/calendar/index.d.ts +7 -6
  11. package/dist/checkbox/createCheckboxGroupState.d.ts +6 -6
  12. package/dist/checkbox/index.d.ts +1 -1
  13. package/dist/collections/ListCollection.d.ts +1 -1
  14. package/dist/collections/createListState.d.ts +11 -8
  15. package/dist/collections/createMenuState.d.ts +7 -7
  16. package/dist/collections/createSelectionState.d.ts +22 -10
  17. package/dist/collections/getChildNodes.d.ts +11 -0
  18. package/dist/collections/index.d.ts +6 -5
  19. package/dist/collections/types.d.ts +12 -12
  20. package/dist/color/Color.d.ts +1 -1
  21. package/dist/color/createColorAreaState.d.ts +4 -2
  22. package/dist/color/createColorFieldState.d.ts +38 -12
  23. package/dist/color/createColorSliderState.d.ts +9 -2
  24. package/dist/color/createColorWheelState.d.ts +13 -2
  25. package/dist/color/getColorChannels.d.ts +1 -1
  26. package/dist/color/index.d.ts +6 -6
  27. package/dist/color/types.d.ts +4 -4
  28. package/dist/combobox/createComboBoxState.d.ts +34 -13
  29. package/dist/combobox/index.d.ts +1 -1
  30. package/dist/data/createAsyncList.d.ts +4 -4
  31. package/dist/data/createListData.d.ts +2 -2
  32. package/dist/data/createTreeData.d.ts +6 -2
  33. package/dist/data/index.d.ts +3 -3
  34. package/dist/datepicker/index.d.ts +2 -4
  35. package/dist/disclosure/createDisclosureState.d.ts +2 -2
  36. package/dist/disclosure/index.d.ts +1 -1
  37. package/dist/dnd/createDragState.d.ts +2 -2
  38. package/dist/dnd/createDraggableCollectionState.d.ts +2 -2
  39. package/dist/dnd/createDropState.d.ts +2 -2
  40. package/dist/dnd/createDroppableCollectionState.d.ts +3 -3
  41. package/dist/dnd/index.d.ts +5 -5
  42. package/dist/dnd/types.d.ts +19 -17
  43. package/dist/form/createFormValidationState.d.ts +3 -3
  44. package/dist/form/index.d.ts +1 -1
  45. package/dist/grid/createGridState.d.ts +2 -2
  46. package/dist/grid/index.d.ts +2 -2
  47. package/dist/grid/types.d.ts +27 -11
  48. package/dist/index.d.ts +31 -30
  49. package/dist/index.js +9077 -7246
  50. package/dist/index.js.map +1 -1
  51. package/dist/menu/index.d.ts +2 -2
  52. package/dist/numberfield/createNumberFieldState.d.ts +2 -2
  53. package/dist/numberfield/index.d.ts +1 -1
  54. package/dist/overlays/createOverlayTriggerState.d.ts +2 -2
  55. package/dist/overlays/index.d.ts +1 -1
  56. package/dist/radio/createRadioGroupState.d.ts +7 -7
  57. package/dist/radio/index.d.ts +1 -1
  58. package/dist/searchfield/createSearchFieldState.d.ts +2 -2
  59. package/dist/searchfield/index.d.ts +2 -2
  60. package/dist/select/createSelectState.d.ts +14 -8
  61. package/dist/select/index.d.ts +1 -1
  62. package/dist/selection/Selection.d.ts +16 -0
  63. package/dist/selection/SelectionManager.d.ts +110 -0
  64. package/dist/selection/createMultipleSelectionState.d.ts +59 -0
  65. package/dist/selection/index.d.ts +6 -5
  66. package/dist/slider/createSliderState.d.ts +3 -3
  67. package/dist/slider/index.d.ts +2 -2
  68. package/dist/steplist/createStepListState.d.ts +48 -0
  69. package/dist/steplist/index.d.ts +1 -0
  70. package/dist/table/TableCollection.d.ts +33 -3
  71. package/dist/table/createTableColumnResizeState.d.ts +54 -0
  72. package/dist/table/createTableState.d.ts +2 -2
  73. package/dist/table/createTreeGridState.d.ts +15 -0
  74. package/dist/table/index.d.ts +6 -3
  75. package/dist/table/types.d.ts +68 -10
  76. package/dist/tabs/createTabListState.d.ts +5 -5
  77. package/dist/tabs/index.d.ts +1 -1
  78. package/dist/textfield/createTextFieldState.d.ts +2 -2
  79. package/dist/textfield/index.d.ts +1 -1
  80. package/dist/toast/createToastState.d.ts +24 -2
  81. package/dist/toast/index.d.ts +1 -1
  82. package/dist/toggle/createToggleGroupState.d.ts +4 -4
  83. package/dist/toggle/createToggleState.d.ts +2 -2
  84. package/dist/toggle/index.d.ts +2 -2
  85. package/dist/tooltip/createTooltipTriggerState.d.ts +2 -2
  86. package/dist/tooltip/index.d.ts +1 -1
  87. package/dist/tree/TreeCollection.d.ts +2 -2
  88. package/dist/tree/createTreeState.d.ts +2 -2
  89. package/dist/tree/index.d.ts +3 -3
  90. package/dist/tree/types.d.ts +27 -13
  91. package/dist/utils/index.d.ts +1 -1
  92. package/dist/utils/reactivity.d.ts +1 -1
  93. package/package.json +29 -30
  94. package/src/autocomplete/createAutocompleteState.d.ts +19 -17
  95. package/src/autocomplete/createAutocompleteState.ts +24 -30
  96. package/src/autocomplete/index.d.ts +6 -2
  97. package/src/autocomplete/index.ts +1 -1
  98. package/src/calendar/IncompleteDate.ts +430 -0
  99. package/src/calendar/createCalendarState.d.ts +139 -117
  100. package/src/calendar/createCalendarState.ts +308 -94
  101. package/src/calendar/createDateFieldState.d.ts +130 -95
  102. package/src/calendar/createDateFieldState.ts +447 -334
  103. package/src/calendar/createDatePickerState.ts +347 -0
  104. package/src/calendar/createRangeCalendarState.d.ts +154 -129
  105. package/src/calendar/createRangeCalendarState.ts +411 -85
  106. package/src/calendar/createTimeFieldState.d.ts +81 -79
  107. package/src/calendar/createTimeFieldState.ts +187 -108
  108. package/src/calendar/index.d.ts +80 -7
  109. package/src/calendar/index.ts +23 -12
  110. package/src/checkbox/createCheckboxGroupState.d.ts +57 -55
  111. package/src/checkbox/createCheckboxGroupState.ts +20 -29
  112. package/src/checkbox/index.d.ts +6 -2
  113. package/src/checkbox/index.ts +1 -1
  114. package/src/collections/ListCollection.d.ts +25 -22
  115. package/src/collections/ListCollection.ts +6 -6
  116. package/src/collections/createListState.d.ts +73 -58
  117. package/src/collections/createListState.ts +67 -35
  118. package/src/collections/createMenuState.d.ts +36 -31
  119. package/src/collections/createMenuState.ts +21 -12
  120. package/src/collections/createSelectionState.d.ts +78 -65
  121. package/src/collections/createSelectionState.ts +66 -52
  122. package/src/collections/getChildNodes.ts +98 -0
  123. package/src/collections/index.d.ts +38 -6
  124. package/src/collections/index.ts +14 -10
  125. package/src/collections/types.d.ts +101 -101
  126. package/src/collections/types.ts +12 -12
  127. package/src/color/Color.d.ts +20 -5
  128. package/src/color/Color.ts +357 -254
  129. package/src/color/createColorAreaState.d.ts +67 -65
  130. package/src/color/createColorAreaState.ts +21 -13
  131. package/src/color/createColorFieldState.d.ts +46 -44
  132. package/src/color/createColorFieldState.ts +285 -149
  133. package/src/color/createColorSliderState.d.ts +58 -56
  134. package/src/color/createColorSliderState.ts +45 -14
  135. package/src/color/createColorWheelState.d.ts +42 -40
  136. package/src/color/createColorWheelState.ts +101 -64
  137. package/src/color/getColorChannels.ts +7 -5
  138. package/src/color/index.d.ts +36 -7
  139. package/src/color/index.ts +6 -9
  140. package/src/color/types.d.ts +68 -63
  141. package/src/color/types.ts +11 -19
  142. package/src/combobox/createComboBoxState.d.ts +107 -105
  143. package/src/combobox/createComboBoxState.ts +184 -89
  144. package/src/combobox/index.d.ts +10 -2
  145. package/src/combobox/index.ts +1 -1
  146. package/src/data/createAsyncList.ts +89 -63
  147. package/src/data/createListData.ts +67 -67
  148. package/src/data/createTreeData.ts +304 -91
  149. package/src/data/index.ts +3 -3
  150. package/src/datepicker/index.ts +6 -10
  151. package/src/disclosure/createDisclosureState.d.ts +47 -43
  152. package/src/disclosure/createDisclosureState.ts +7 -21
  153. package/src/disclosure/index.d.ts +10 -2
  154. package/src/disclosure/index.ts +1 -1
  155. package/src/dnd/createDragState.d.ts +51 -42
  156. package/src/dnd/createDragState.ts +12 -14
  157. package/src/dnd/createDraggableCollectionState.d.ts +52 -41
  158. package/src/dnd/createDraggableCollectionState.ts +14 -21
  159. package/src/dnd/createDropState.d.ts +64 -45
  160. package/src/dnd/createDropState.ts +22 -32
  161. package/src/dnd/createDroppableCollectionState.d.ts +88 -59
  162. package/src/dnd/createDroppableCollectionState.ts +40 -43
  163. package/src/dnd/index.d.ts +55 -6
  164. package/src/dnd/index.ts +6 -18
  165. package/src/dnd/types.d.ts +170 -157
  166. package/src/dnd/types.ts +24 -22
  167. package/src/form/createFormValidationState.d.ts +47 -45
  168. package/src/form/createFormValidationState.ts +30 -63
  169. package/src/form/index.d.ts +16 -2
  170. package/src/form/index.ts +1 -1
  171. package/src/grid/createGridState.d.ts +7 -4
  172. package/src/grid/createGridState.ts +78 -51
  173. package/src/grid/index.d.ts +3 -3
  174. package/src/grid/index.ts +2 -8
  175. package/src/grid/types.d.ts +136 -129
  176. package/src/grid/types.ts +34 -18
  177. package/src/index.d.ts +311 -26
  178. package/src/index.ts +59 -89
  179. package/src/menu/index.ts +2 -4
  180. package/src/numberfield/createNumberFieldState.d.ts +56 -54
  181. package/src/numberfield/createNumberFieldState.ts +26 -31
  182. package/src/numberfield/index.d.ts +6 -2
  183. package/src/numberfield/index.ts +1 -1
  184. package/src/overlays/createOverlayTriggerState.d.ts +22 -20
  185. package/src/overlays/createOverlayTriggerState.ts +3 -4
  186. package/src/overlays/index.d.ts +6 -2
  187. package/src/overlays/index.ts +1 -1
  188. package/src/radio/createRadioGroupState.d.ts +54 -52
  189. package/src/radio/createRadioGroupState.ts +27 -29
  190. package/src/radio/index.d.ts +7 -2
  191. package/src/radio/index.ts +1 -1
  192. package/src/searchfield/createSearchFieldState.d.ts +16 -14
  193. package/src/searchfield/createSearchFieldState.ts +5 -11
  194. package/src/searchfield/index.d.ts +3 -3
  195. package/src/searchfield/index.ts +2 -5
  196. package/src/select/createSelectState.d.ts +63 -61
  197. package/src/select/createSelectState.ts +42 -29
  198. package/src/select/index.d.ts +2 -2
  199. package/src/select/index.ts +1 -5
  200. package/src/selection/Selection.ts +28 -0
  201. package/src/selection/SelectionManager.ts +526 -0
  202. package/src/selection/createMultipleSelectionState.ts +247 -0
  203. package/src/selection/index.ts +12 -7
  204. package/src/slider/createSliderState.d.ts +60 -60
  205. package/src/slider/createSliderState.ts +55 -33
  206. package/src/slider/index.d.ts +3 -3
  207. package/src/slider/index.ts +2 -6
  208. package/src/ssr/index.d.ts +1 -1
  209. package/src/ssr/index.ts +2 -2
  210. package/src/steplist/createStepListState.ts +191 -0
  211. package/src/steplist/index.ts +5 -0
  212. package/src/table/TableCollection.d.ts +42 -40
  213. package/src/table/TableCollection.ts +266 -99
  214. package/src/table/createTableColumnResizeState.ts +242 -0
  215. package/src/table/createTableState.d.ts +7 -4
  216. package/src/table/createTableState.ts +30 -7
  217. package/src/table/createTreeGridState.ts +146 -0
  218. package/src/table/index.d.ts +14 -4
  219. package/src/table/index.ts +13 -3
  220. package/src/table/types.d.ts +98 -92
  221. package/src/table/types.ts +83 -13
  222. package/src/tabs/createTabListState.d.ts +59 -57
  223. package/src/tabs/createTabListState.ts +34 -39
  224. package/src/tabs/index.d.ts +8 -2
  225. package/src/tabs/index.ts +1 -1
  226. package/src/textfield/createTextFieldState.d.ts +16 -14
  227. package/src/textfield/createTextFieldState.ts +7 -18
  228. package/src/textfield/index.d.ts +6 -2
  229. package/src/textfield/index.ts +1 -1
  230. package/src/toast/createToastState.d.ts +92 -86
  231. package/src/toast/createToastState.ts +90 -52
  232. package/src/toast/index.d.ts +12 -2
  233. package/src/toast/index.ts +2 -1
  234. package/src/toggle/createToggleGroupState.ts +11 -21
  235. package/src/toggle/createToggleState.d.ts +19 -19
  236. package/src/toggle/createToggleState.ts +2 -16
  237. package/src/toggle/index.d.ts +2 -2
  238. package/src/toggle/index.ts +2 -6
  239. package/src/tooltip/createTooltipTriggerState.d.ts +17 -17
  240. package/src/tooltip/createTooltipTriggerState.ts +12 -11
  241. package/src/tooltip/index.d.ts +7 -2
  242. package/src/tooltip/index.ts +1 -1
  243. package/src/tree/TreeCollection.d.ts +26 -23
  244. package/src/tree/TreeCollection.ts +29 -22
  245. package/src/tree/createTreeState.d.ts +7 -4
  246. package/src/tree/createTreeState.ts +70 -41
  247. package/src/tree/index.d.ts +10 -4
  248. package/src/tree/index.ts +3 -3
  249. package/src/tree/types.d.ts +131 -126
  250. package/src/tree/types.ts +30 -13
  251. package/src/utils/index.d.ts +2 -2
  252. package/src/utils/index.ts +1 -1
  253. package/src/utils/reactivity.d.ts +2 -2
  254. package/src/utils/reactivity.ts +3 -3
@@ -5,10 +5,10 @@
5
5
  * convenience methods to update the data over time.
6
6
  */
7
7
 
8
- import { createSignal } from 'solid-js';
8
+ import { createSignal } from "solid-js";
9
9
 
10
10
  export type Key = string | number;
11
- export type Selection = 'all' | Set<Key>;
11
+ export type Selection = "all" | Set<Key>;
12
12
 
13
13
  export interface TreeNode<T> {
14
14
  /** A unique key for the tree node. */
@@ -25,7 +25,7 @@ export interface TreeOptions<T> {
25
25
  /** Initial items in the tree. */
26
26
  initialItems?: T[];
27
27
  /** The keys for the initially selected items. */
28
- initialSelectedKeys?: 'all' | Iterable<Key>;
28
+ initialSelectedKeys?: "all" | Iterable<Key>;
29
29
  /** A function that returns a unique key for an item object. */
30
30
  getKey?: (item: T) => Key;
31
31
  /** A function that returns the children of an item object. */
@@ -57,6 +57,10 @@ export interface TreeData<T> {
57
57
  removeSelectedItems(): void;
58
58
  /** Moves an item to a new parent. */
59
59
  move(key: Key, toParentKey: Key | null, index: number): void;
60
+ /** Moves items before a given key. */
61
+ moveBefore(key: Key, keys: Iterable<Key>): void;
62
+ /** Moves items after a given key. */
63
+ moveAfter(key: Key, keys: Iterable<Key>): void;
60
64
  /** Updates an item in the tree. */
61
65
  update(key: Key, newValue: T): void;
62
66
  }
@@ -71,11 +75,20 @@ interface TreeDataState<T> {
71
75
  * convenience methods to update the data over time.
72
76
  */
73
77
  export function createTreeData<T>(options: TreeOptions<T>): TreeData<T> {
78
+ const defaultGetKey = (item: T): Key => {
79
+ const candidate = item as { id?: Key; key?: Key };
80
+ return candidate.id ?? candidate.key ?? String(item);
81
+ };
82
+ const defaultGetChildren = (item: T): T[] => {
83
+ const candidate = item as { children?: T[] };
84
+ return candidate.children ?? [];
85
+ };
86
+
74
87
  const {
75
88
  initialItems = [],
76
89
  initialSelectedKeys,
77
- getKey = (item: any) => item.id ?? item.key,
78
- getChildren = (item: any) => item.children ?? [],
90
+ getKey = defaultGetKey,
91
+ getChildren = defaultGetChildren,
79
92
  } = options;
80
93
 
81
94
  // Build initial tree
@@ -83,7 +96,7 @@ export function createTreeData<T>(options: TreeOptions<T>): TreeData<T> {
83
96
 
84
97
  const [treeState, setTreeState] = createSignal<TreeDataState<T>>(initialTree);
85
98
  const [selectedKeys, setSelectedKeys] = createSignal<Selection>(
86
- initialSelectedKeys === 'all' ? 'all' : new Set(initialSelectedKeys || [])
99
+ initialSelectedKeys === "all" ? "all" : new Set(initialSelectedKeys || []),
87
100
  );
88
101
 
89
102
  function updateTree(
@@ -103,12 +116,17 @@ export function createTreeData<T>(options: TreeOptions<T>): TreeData<T> {
103
116
  // Delete node
104
117
  deleteNode(node, newMap);
105
118
  if (node.parentKey != null) {
106
- return updateTree(items, node.parentKey, parent => ({
107
- ...parent,
108
- children: parent.children!.filter(c => c.key !== key),
109
- }), newMap);
119
+ return updateTree(
120
+ items,
121
+ node.parentKey,
122
+ (parent) => ({
123
+ ...parent,
124
+ children: parent.children!.filter((c) => c.key !== key),
125
+ }),
126
+ newMap,
127
+ );
110
128
  }
111
- return { items: items.filter(i => i.key !== key), nodeMap: newMap };
129
+ return { items: items.filter((i) => i.key !== key), nodeMap: newMap };
112
130
  }
113
131
 
114
132
  newMap.set(key!, updated);
@@ -119,21 +137,30 @@ export function createTreeData<T>(options: TreeOptions<T>): TreeData<T> {
119
137
  }
120
138
 
121
139
  if (node.parentKey != null) {
122
- return updateTree(items, node.parentKey, parent => ({
123
- ...parent,
124
- children: parent.children!.map(c => c.key === key ? updated : c),
125
- }), newMap);
140
+ return updateTree(
141
+ items,
142
+ node.parentKey,
143
+ (parent) => ({
144
+ ...parent,
145
+ children: parent.children!.map((c) => (c.key === key ? updated : c)),
146
+ }),
147
+ newMap,
148
+ );
126
149
  }
127
150
 
128
- return { items: items.map(i => i.key === key ? updated : i), nodeMap: newMap };
151
+ return { items: items.map((i) => (i.key === key ? updated : i)), nodeMap: newMap };
129
152
  }
130
153
 
131
154
  return { items, nodeMap: newMap };
132
155
  }
133
156
 
134
157
  return {
135
- get items() { return treeState().items; },
136
- get selectedKeys() { return selectedKeys(); },
158
+ get items() {
159
+ return treeState().items;
160
+ },
161
+ get selectedKeys() {
162
+ return selectedKeys();
163
+ },
137
164
 
138
165
  setSelectedKeys(keys: Selection) {
139
166
  setSelectedKeys(keys);
@@ -144,10 +171,10 @@ export function createTreeData<T>(options: TreeOptions<T>): TreeData<T> {
144
171
  },
145
172
 
146
173
  insert(parentKey: Key | null, index: number, ...values: T[]) {
147
- setTreeState(state => {
174
+ setTreeState((state) => {
148
175
  const { items, nodeMap } = state;
149
176
  const newMap = new Map(nodeMap);
150
- const newNodes = values.map(v => {
177
+ const newNodes = values.map((v) => {
151
178
  const tree = buildTree([v], newMap, parentKey, getKey, getChildren);
152
179
  return tree.items[0];
153
180
  });
@@ -159,30 +186,35 @@ export function createTreeData<T>(options: TreeOptions<T>): TreeData<T> {
159
186
  };
160
187
  }
161
188
 
162
- return updateTree(items, parentKey, parent => ({
163
- ...parent,
164
- children: [
165
- ...(parent.children || []).slice(0, index),
166
- ...newNodes,
167
- ...(parent.children || []).slice(index),
168
- ],
169
- }), newMap);
189
+ return updateTree(
190
+ items,
191
+ parentKey,
192
+ (parent) => ({
193
+ ...parent,
194
+ children: [
195
+ ...(parent.children || []).slice(0, index),
196
+ ...newNodes,
197
+ ...(parent.children || []).slice(index),
198
+ ],
199
+ }),
200
+ newMap,
201
+ );
170
202
  });
171
203
  },
172
204
 
173
205
  insertBefore(key: Key, ...values: T[]) {
174
- setTreeState(state => {
206
+ setTreeState((state) => {
175
207
  const { items, nodeMap } = state;
176
208
  const node = nodeMap.get(key);
177
209
  if (!node) return state;
178
210
 
179
211
  const parent = node.parentKey != null ? nodeMap.get(node.parentKey) : null;
180
212
  const siblings = parent?.children ?? items;
181
- const index = siblings.findIndex(n => n.key === key);
213
+ const index = siblings.findIndex((n) => n.key === key);
182
214
  if (index === -1) return state;
183
215
 
184
216
  const newMap = new Map(nodeMap);
185
- const newNodes = values.map(v => {
217
+ const newNodes = values.map((v) => {
186
218
  const tree = buildTree([v], newMap, node.parentKey, getKey, getChildren);
187
219
  return tree.items[0];
188
220
  });
@@ -194,30 +226,31 @@ export function createTreeData<T>(options: TreeOptions<T>): TreeData<T> {
194
226
  };
195
227
  }
196
228
 
197
- return updateTree(items, node.parentKey, p => ({
198
- ...p,
199
- children: [
200
- ...p.children!.slice(0, index),
201
- ...newNodes,
202
- ...p.children!.slice(index),
203
- ],
204
- }), newMap);
229
+ return updateTree(
230
+ items,
231
+ node.parentKey,
232
+ (p) => ({
233
+ ...p,
234
+ children: [...p.children!.slice(0, index), ...newNodes, ...p.children!.slice(index)],
235
+ }),
236
+ newMap,
237
+ );
205
238
  });
206
239
  },
207
240
 
208
241
  insertAfter(key: Key, ...values: T[]) {
209
- setTreeState(state => {
242
+ setTreeState((state) => {
210
243
  const { items, nodeMap } = state;
211
244
  const node = nodeMap.get(key);
212
245
  if (!node) return state;
213
246
 
214
247
  const parent = node.parentKey != null ? nodeMap.get(node.parentKey) : null;
215
248
  const siblings = parent?.children ?? items;
216
- const index = siblings.findIndex(n => n.key === key);
249
+ const index = siblings.findIndex((n) => n.key === key);
217
250
  if (index === -1) return state;
218
251
 
219
252
  const newMap = new Map(nodeMap);
220
- const newNodes = values.map(v => {
253
+ const newNodes = values.map((v) => {
221
254
  const tree = buildTree([v], newMap, node.parentKey, getKey, getChildren);
222
255
  return tree.items[0];
223
256
  });
@@ -229,22 +262,27 @@ export function createTreeData<T>(options: TreeOptions<T>): TreeData<T> {
229
262
  };
230
263
  }
231
264
 
232
- return updateTree(items, node.parentKey, p => ({
233
- ...p,
234
- children: [
235
- ...p.children!.slice(0, index + 1),
236
- ...newNodes,
237
- ...p.children!.slice(index + 1),
238
- ],
239
- }), newMap);
265
+ return updateTree(
266
+ items,
267
+ node.parentKey,
268
+ (p) => ({
269
+ ...p,
270
+ children: [
271
+ ...p.children!.slice(0, index + 1),
272
+ ...newNodes,
273
+ ...p.children!.slice(index + 1),
274
+ ],
275
+ }),
276
+ newMap,
277
+ );
240
278
  });
241
279
  },
242
280
 
243
281
  append(parentKey: Key | null, ...values: T[]) {
244
- setTreeState(state => {
282
+ setTreeState((state) => {
245
283
  const { items, nodeMap } = state;
246
284
  const newMap = new Map(nodeMap);
247
- const newNodes = values.map(v => {
285
+ const newNodes = values.map((v) => {
248
286
  const tree = buildTree([v], newMap, parentKey, getKey, getChildren);
249
287
  return tree.items[0];
250
288
  });
@@ -253,18 +291,23 @@ export function createTreeData<T>(options: TreeOptions<T>): TreeData<T> {
253
291
  return { items: [...items, ...newNodes], nodeMap: newMap };
254
292
  }
255
293
 
256
- return updateTree(items, parentKey, parent => ({
257
- ...parent,
258
- children: [...(parent.children || []), ...newNodes],
259
- }), newMap);
294
+ return updateTree(
295
+ items,
296
+ parentKey,
297
+ (parent) => ({
298
+ ...parent,
299
+ children: [...(parent.children || []), ...newNodes],
300
+ }),
301
+ newMap,
302
+ );
260
303
  });
261
304
  },
262
305
 
263
306
  prepend(parentKey: Key | null, ...values: T[]) {
264
- setTreeState(state => {
307
+ setTreeState((state) => {
265
308
  const { items, nodeMap } = state;
266
309
  const newMap = new Map(nodeMap);
267
- const newNodes = values.map(v => {
310
+ const newNodes = values.map((v) => {
268
311
  const tree = buildTree([v], newMap, parentKey, getKey, getChildren);
269
312
  return tree.items[0];
270
313
  });
@@ -273,15 +316,20 @@ export function createTreeData<T>(options: TreeOptions<T>): TreeData<T> {
273
316
  return { items: [...newNodes, ...items], nodeMap: newMap };
274
317
  }
275
318
 
276
- return updateTree(items, parentKey, parent => ({
277
- ...parent,
278
- children: [...newNodes, ...(parent.children || [])],
279
- }), newMap);
319
+ return updateTree(
320
+ items,
321
+ parentKey,
322
+ (parent) => ({
323
+ ...parent,
324
+ children: [...newNodes, ...(parent.children || [])],
325
+ }),
326
+ newMap,
327
+ );
280
328
  });
281
329
  },
282
330
 
283
331
  remove(...keys: Key[]) {
284
- setTreeState(state => {
332
+ setTreeState((state) => {
285
333
  let { items, nodeMap } = state;
286
334
  let newMap = new Map(nodeMap);
287
335
  let newItems = items;
@@ -295,8 +343,8 @@ export function createTreeData<T>(options: TreeOptions<T>): TreeData<T> {
295
343
  return { items: newItems, nodeMap: newMap };
296
344
  });
297
345
 
298
- setSelectedKeys(sel => {
299
- if (sel === 'all') return sel;
346
+ setSelectedKeys((sel) => {
347
+ if (sel === "all") return sel;
300
348
  const newSel = new Set(sel);
301
349
  for (const key of keys) {
302
350
  newSel.delete(key);
@@ -307,14 +355,14 @@ export function createTreeData<T>(options: TreeOptions<T>): TreeData<T> {
307
355
 
308
356
  removeSelectedItems() {
309
357
  const sel = selectedKeys();
310
- if (sel === 'all') {
358
+ if (sel === "all") {
311
359
  setTreeState({ items: [], nodeMap: new Map() });
312
360
  setSelectedKeys(new Set<Key>());
313
361
  return;
314
362
  }
315
363
 
316
364
  const keysToRemove = [...sel];
317
- setTreeState(state => {
365
+ setTreeState((state) => {
318
366
  let { items, nodeMap } = state;
319
367
  let newMap = new Map(nodeMap);
320
368
  let newItems = items;
@@ -329,11 +377,20 @@ export function createTreeData<T>(options: TreeOptions<T>): TreeData<T> {
329
377
  },
330
378
 
331
379
  move(key: Key, toParentKey: Key | null, index: number) {
332
- setTreeState(state => {
380
+ setTreeState((state) => {
333
381
  const { items, nodeMap } = state;
334
382
  const node = nodeMap.get(key);
335
383
  if (!node) return state;
336
384
 
385
+ // Cyclical move validation: prevent moving a node into its own subtree
386
+ if (toParentKey != null) {
387
+ let parent: TreeNode<T> | undefined = nodeMap.get(toParentKey);
388
+ while (parent) {
389
+ if (parent.key === key) return state;
390
+ parent = parent.parentKey != null ? nodeMap.get(parent.parentKey) : undefined;
391
+ }
392
+ }
393
+
337
394
  // Remove the node
338
395
  let newMap = new Map(nodeMap);
339
396
  const removeResult = updateTree(items, key, () => null, newMap);
@@ -351,33 +408,76 @@ export function createTreeData<T>(options: TreeOptions<T>): TreeData<T> {
351
408
  };
352
409
  }
353
410
 
354
- return updateTree(newItems, toParentKey, parent => ({
355
- ...parent,
356
- children: [
357
- ...(parent.children || []).slice(0, index),
358
- movedNode,
359
- ...(parent.children || []).slice(index),
360
- ],
361
- }), newMap);
411
+ return updateTree(
412
+ newItems,
413
+ toParentKey,
414
+ (parent) => ({
415
+ ...parent,
416
+ children: [
417
+ ...(parent.children || []).slice(0, index),
418
+ movedNode,
419
+ ...(parent.children || []).slice(index),
420
+ ],
421
+ }),
422
+ newMap,
423
+ );
424
+ });
425
+ },
426
+
427
+ moveBefore(key: Key, keys: Iterable<Key>) {
428
+ setTreeState((state) => {
429
+ const { items, nodeMap } = state;
430
+ const node = nodeMap.get(key);
431
+ if (!node) return state;
432
+
433
+ const toParentKey = node.parentKey ?? null;
434
+ let parent: TreeNode<T> | null = null;
435
+ if (toParentKey != null) {
436
+ parent = nodeMap.get(toParentKey) ?? null;
437
+ }
438
+ const toIndex = parent?.children ? parent.children.indexOf(node) : items.indexOf(node);
439
+ return moveItems(state, keys, parent, toIndex, updateTree, addNode);
440
+ });
441
+ },
442
+
443
+ moveAfter(key: Key, keys: Iterable<Key>) {
444
+ setTreeState((state) => {
445
+ const { items, nodeMap } = state;
446
+ const node = nodeMap.get(key);
447
+ if (!node) return state;
448
+
449
+ const toParentKey = node.parentKey ?? null;
450
+ let parent: TreeNode<T> | null = null;
451
+ if (toParentKey != null) {
452
+ parent = nodeMap.get(toParentKey) ?? null;
453
+ }
454
+ let toIndex = parent?.children ? parent.children.indexOf(node) : items.indexOf(node);
455
+ toIndex++;
456
+ return moveItems(state, keys, parent, toIndex, updateTree, addNode);
362
457
  });
363
458
  },
364
459
 
365
460
  update(key: Key, newValue: T) {
366
- setTreeState(state => {
461
+ setTreeState((state) => {
367
462
  const { items, nodeMap } = state;
368
463
  const newMap = new Map(nodeMap);
369
464
 
370
- return updateTree(items, key, oldNode => {
371
- const node: TreeNode<T> = {
372
- key: oldNode.key,
373
- parentKey: oldNode.parentKey,
374
- value: newValue,
375
- children: null,
376
- };
377
- const tree = buildTree(getChildren(newValue), newMap, node.key, getKey, getChildren);
378
- node.children = tree.items;
379
- return node;
380
- }, newMap);
465
+ return updateTree(
466
+ items,
467
+ key,
468
+ (oldNode) => {
469
+ const node: TreeNode<T> = {
470
+ key: oldNode.key,
471
+ parentKey: oldNode.parentKey,
472
+ value: newValue,
473
+ children: null,
474
+ };
475
+ const tree = buildTree(getChildren(newValue), newMap, node.key, getKey, getChildren);
476
+ node.children = tree.items;
477
+ return node;
478
+ },
479
+ newMap,
480
+ );
381
481
  });
382
482
  },
383
483
  };
@@ -396,9 +496,10 @@ function buildTree<T>(
396
496
  const key = getKey(item);
397
497
  const children = getChildren(item);
398
498
 
399
- const childTree = children.length > 0
400
- ? buildTree(children, nodeMap, key, getKey, getChildren)
401
- : { items: [], nodeMap };
499
+ const childTree =
500
+ children.length > 0
501
+ ? buildTree(children, nodeMap, key, getKey, getChildren)
502
+ : { items: [], nodeMap };
402
503
 
403
504
  const node: TreeNode<T> = {
404
505
  key,
@@ -431,3 +532,115 @@ function deleteNode<T>(node: TreeNode<T>, map: Map<Key, TreeNode<T>>): void {
431
532
  }
432
533
  }
433
534
  }
535
+
536
+ function moveItems<T>(
537
+ state: TreeDataState<T>,
538
+ keys: Iterable<Key>,
539
+ toParent: TreeNode<T> | null,
540
+ toIndex: number,
541
+ updateTreeFn: (
542
+ items: TreeNode<T>[],
543
+ key: Key | null,
544
+ update: (node: TreeNode<T>) => TreeNode<T> | null,
545
+ originalMap: Map<Key, TreeNode<T>>,
546
+ ) => TreeDataState<T>,
547
+ addNodeFn: (node: TreeNode<T>, map: Map<Key, TreeNode<T>>) => void,
548
+ ): TreeDataState<T> {
549
+ const { items, nodeMap } = state;
550
+
551
+ // Cyclical move validation: prevent moving a node into its own subtree
552
+ const removeKeys = new Set(keys);
553
+ let ancestor: TreeNode<T> | null = toParent;
554
+ while (ancestor != null) {
555
+ if (removeKeys.has(ancestor.key)) {
556
+ throw new Error("Cannot move an item to be a child of itself.");
557
+ }
558
+ ancestor = ancestor.parentKey != null ? (nodeMap.get(ancestor.parentKey) ?? null) : null;
559
+ }
560
+
561
+ const originalToIndex = toIndex;
562
+ const keyArray = [...removeKeys];
563
+
564
+ // Depth-first traversal to determine in-order positions and remove items
565
+ const inOrderKeys = new Map<Key, number>();
566
+ const removedItems: TreeNode<T>[] = [];
567
+ let newItems = items;
568
+ let newMap = nodeMap;
569
+ let i = 0;
570
+
571
+ function traversal(
572
+ node: { children?: TreeNode<T>[] | null },
573
+ callbacks: {
574
+ inorder?: (child: TreeNode<T>) => void;
575
+ postorder?: (child: TreeNode<T>) => void;
576
+ },
577
+ ) {
578
+ callbacks.inorder?.(node as TreeNode<T>);
579
+ if (node.children) {
580
+ for (const child of node.children) {
581
+ traversal(child, callbacks);
582
+ callbacks.postorder?.(child);
583
+ }
584
+ }
585
+ }
586
+
587
+ traversal(
588
+ { children: items },
589
+ {
590
+ inorder(child) {
591
+ if (keyArray.includes(child.key)) {
592
+ inOrderKeys.set(child.key, i++);
593
+ }
594
+ },
595
+ postorder(child) {
596
+ if (keyArray.includes(child.key)) {
597
+ removedItems.push({ ...newMap.get(child.key)!, parentKey: toParent?.key ?? null });
598
+ const result = updateTreeFn(newItems, child.key, () => null, newMap);
599
+ newItems = result.items;
600
+ newMap = result.nodeMap;
601
+ }
602
+ // Decrement index if the removed child is in the target parent and before the target index
603
+ if (
604
+ (child.parentKey === toParent || child.parentKey === toParent?.key) &&
605
+ keyArray.includes(child.key) &&
606
+ (toParent?.children ? toParent.children.indexOf(child) : items.indexOf(child)) <
607
+ originalToIndex
608
+ ) {
609
+ toIndex--;
610
+ }
611
+ },
612
+ },
613
+ );
614
+
615
+ const inOrderItems = removedItems.sort((a, b) =>
616
+ inOrderKeys.get(a.key)! > inOrderKeys.get(b.key)! ? 1 : -1,
617
+ );
618
+
619
+ // If parentKey is null, insert into the root.
620
+ if (!toParent || toParent.key == null) {
621
+ inOrderItems.forEach((movedNode) => {
622
+ addNodeFn(movedNode, newMap);
623
+ });
624
+ return {
625
+ items: [...newItems.slice(0, toIndex), ...inOrderItems, ...newItems.slice(toIndex)],
626
+ nodeMap: newMap,
627
+ };
628
+ }
629
+
630
+ // Otherwise, update the parent node and its ancestors.
631
+ return updateTreeFn(
632
+ newItems,
633
+ toParent.key,
634
+ (parentNode) => ({
635
+ key: parentNode.key,
636
+ parentKey: parentNode.parentKey,
637
+ value: parentNode.value,
638
+ children: [
639
+ ...parentNode.children!.slice(0, toIndex),
640
+ ...inOrderItems,
641
+ ...parentNode.children!.slice(toIndex),
642
+ ],
643
+ }),
644
+ newMap,
645
+ );
646
+ }
package/src/data/index.ts CHANGED
@@ -4,14 +4,14 @@ export {
4
4
  type ListData,
5
5
  type Key as ListDataKey,
6
6
  type Selection as ListDataSelection,
7
- } from './createListData';
7
+ } from "./createListData";
8
8
 
9
9
  export {
10
10
  createTreeData,
11
11
  type TreeOptions,
12
12
  type TreeData,
13
13
  type TreeNode as TreeDataNode,
14
- } from './createTreeData';
14
+ } from "./createTreeData";
15
15
 
16
16
  export {
17
17
  createAsyncList,
@@ -22,4 +22,4 @@ export {
22
22
  type AsyncListStateUpdate,
23
23
  type SortDescriptor,
24
24
  type LoadingState,
25
- } from './createAsyncList';
25
+ } from "./createAsyncList";
@@ -9,6 +9,7 @@ export {
9
9
  createDateFieldState,
10
10
  createTimeFieldState,
11
11
  createRangeCalendarState,
12
+ createDatePickerState,
12
13
  type DateFieldStateProps as DateFieldStateOptions,
13
14
  type DateFieldState,
14
15
  type DateSegment,
@@ -19,18 +20,13 @@ export {
19
20
  type TimeSegmentType,
20
21
  type RangeCalendarStateProps as DateRangePickerStateOptions,
21
22
  type RangeCalendarState as DateRangePickerState,
22
- } from '../calendar';
23
-
24
- export {
25
- createOverlayTriggerState,
26
- type OverlayTriggerProps as DatePickerStateOptions,
27
- type OverlayTriggerState as DatePickerState,
28
- } from '../overlays';
23
+ type DatePickerState,
24
+ type DatePickerStateOptions,
25
+ } from "../calendar";
29
26
 
30
27
  export {
31
28
  createDateFieldState as useDateFieldState,
32
29
  createTimeFieldState as useTimeFieldState,
33
30
  createRangeCalendarState as useDateRangePickerState,
34
- } from '../calendar';
35
-
36
- export { createOverlayTriggerState as useDatePickerState } from '../overlays';
31
+ createDatePickerState as useDatePickerState,
32
+ } from "../calendar";