@proyecto-viviana/solid-stately 0.2.3 → 0.2.7

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 (82) hide show
  1. package/LICENSE +21 -0
  2. package/dist/autocomplete/createAutocompleteState.d.ts +2 -1
  3. package/dist/checkbox/createCheckboxGroupState.d.ts +10 -1
  4. package/dist/collections/types.d.ts +11 -0
  5. package/dist/color/getColorChannels.d.ts +20 -0
  6. package/dist/data/createAsyncList.d.ts +111 -0
  7. package/dist/data/createListData.d.ts +65 -0
  8. package/dist/data/createTreeData.d.ts +61 -0
  9. package/dist/data/index.d.ts +3 -0
  10. package/dist/datepicker/index.d.ts +10 -0
  11. package/dist/grid/types.d.ts +5 -1
  12. package/dist/index.d.ts +6 -1
  13. package/dist/index.js +3737 -2697
  14. package/dist/index.js.map +1 -7
  15. package/dist/menu/index.d.ts +8 -0
  16. package/dist/radio/createRadioGroupState.d.ts +10 -1
  17. package/dist/select/createSelectState.d.ts +17 -0
  18. package/dist/selection/index.d.ts +11 -0
  19. package/dist/toast/createToastState.d.ts +7 -1
  20. package/dist/toggle/createToggleGroupState.d.ts +45 -0
  21. package/dist/toggle/index.d.ts +1 -0
  22. package/dist/tree/TreeCollection.d.ts +3 -2
  23. package/package.json +6 -5
  24. package/src/autocomplete/createAutocompleteState.ts +10 -11
  25. package/src/calendar/createDateFieldState.ts +24 -1
  26. package/src/checkbox/createCheckboxGroupState.ts +42 -6
  27. package/src/collections/ListCollection.ts +152 -146
  28. package/src/collections/createListState.ts +266 -264
  29. package/src/collections/createMenuState.ts +106 -106
  30. package/src/collections/createSelectionState.ts +336 -336
  31. package/src/collections/index.ts +46 -46
  32. package/src/collections/types.ts +181 -169
  33. package/src/color/Color.ts +951 -951
  34. package/src/color/createColorAreaState.ts +293 -293
  35. package/src/color/createColorFieldState.ts +292 -292
  36. package/src/color/createColorSliderState.ts +241 -241
  37. package/src/color/createColorWheelState.ts +211 -211
  38. package/src/color/getColorChannels.ts +34 -0
  39. package/src/color/index.ts +47 -47
  40. package/src/color/types.ts +127 -127
  41. package/src/combobox/createComboBoxState.ts +703 -703
  42. package/src/combobox/index.ts +13 -13
  43. package/src/data/createAsyncList.ts +377 -0
  44. package/src/data/createListData.ts +298 -0
  45. package/src/data/createTreeData.ts +433 -0
  46. package/src/data/index.ts +25 -0
  47. package/src/datepicker/index.ts +36 -0
  48. package/src/disclosure/createDisclosureState.ts +4 -4
  49. package/src/dnd/createDragState.ts +153 -153
  50. package/src/dnd/createDraggableCollectionState.ts +165 -165
  51. package/src/dnd/createDropState.ts +212 -212
  52. package/src/dnd/createDroppableCollectionState.ts +357 -357
  53. package/src/dnd/index.ts +76 -76
  54. package/src/dnd/types.ts +317 -317
  55. package/src/form/createFormValidationState.ts +389 -389
  56. package/src/form/index.ts +15 -15
  57. package/src/grid/types.ts +5 -0
  58. package/src/index.ts +49 -0
  59. package/src/menu/index.ts +19 -0
  60. package/src/numberfield/createNumberFieldState.ts +427 -383
  61. package/src/numberfield/index.ts +5 -5
  62. package/src/overlays/createOverlayTriggerState.ts +67 -67
  63. package/src/overlays/index.ts +5 -5
  64. package/src/radio/createRadioGroupState.ts +44 -6
  65. package/src/searchfield/createSearchFieldState.ts +62 -62
  66. package/src/searchfield/index.ts +5 -5
  67. package/src/select/createSelectState.ts +290 -181
  68. package/src/select/index.ts +5 -5
  69. package/src/selection/index.ts +28 -0
  70. package/src/slider/createSliderState.ts +211 -211
  71. package/src/slider/index.ts +6 -6
  72. package/src/tabs/createTabListState.ts +37 -11
  73. package/src/toast/createToastState.d.ts +6 -1
  74. package/src/toast/createToastState.ts +8 -1
  75. package/src/toggle/createToggleGroupState.ts +127 -0
  76. package/src/toggle/index.ts +6 -0
  77. package/src/tooltip/createTooltipTriggerState.ts +183 -183
  78. package/src/tooltip/index.ts +6 -6
  79. package/src/tree/TreeCollection.ts +208 -175
  80. package/src/tree/createTreeState.ts +392 -392
  81. package/src/tree/index.ts +13 -13
  82. package/src/tree/types.ts +174 -174
@@ -0,0 +1,433 @@
1
+ /**
2
+ * createTreeData - SolidJS port of React Spectrum's useTreeData
3
+ *
4
+ * Manages state for an immutable tree data structure, and provides
5
+ * convenience methods to update the data over time.
6
+ */
7
+
8
+ import { createSignal } from 'solid-js';
9
+
10
+ export type Key = string | number;
11
+ export type Selection = 'all' | Set<Key>;
12
+
13
+ export interface TreeNode<T> {
14
+ /** A unique key for the tree node. */
15
+ key: Key;
16
+ /** The key of the parent node. */
17
+ parentKey: Key | null;
18
+ /** The value object for the tree node. */
19
+ value: T;
20
+ /** The children of this node. */
21
+ children: TreeNode<T>[] | null;
22
+ }
23
+
24
+ export interface TreeOptions<T> {
25
+ /** Initial items in the tree. */
26
+ initialItems?: T[];
27
+ /** The keys for the initially selected items. */
28
+ initialSelectedKeys?: 'all' | Iterable<Key>;
29
+ /** A function that returns a unique key for an item object. */
30
+ getKey?: (item: T) => Key;
31
+ /** A function that returns the children of an item object. */
32
+ getChildren?: (item: T) => T[];
33
+ }
34
+
35
+ export interface TreeData<T> {
36
+ /** The root items in the tree. */
37
+ readonly items: TreeNode<T>[];
38
+ /** The keys of the currently selected items in the tree. */
39
+ readonly selectedKeys: Selection;
40
+ /** Sets the selected keys. */
41
+ setSelectedKeys(keys: Selection): void;
42
+ /** Gets an item from the tree by key. */
43
+ getItem(key: Key): TreeNode<T> | undefined;
44
+ /** Inserts items into the tree. */
45
+ insert(parentKey: Key | null, index: number, ...values: T[]): void;
46
+ /** Inserts items before a given key. */
47
+ insertBefore(key: Key, ...values: T[]): void;
48
+ /** Inserts items after a given key. */
49
+ insertAfter(key: Key, ...values: T[]): void;
50
+ /** Appends items to a parent node. */
51
+ append(parentKey: Key | null, ...values: T[]): void;
52
+ /** Prepends items to a parent node. */
53
+ prepend(parentKey: Key | null, ...values: T[]): void;
54
+ /** Removes items from the tree by their keys. */
55
+ remove(...keys: Key[]): void;
56
+ /** Removes all items from the tree that are currently in the set of selected items. */
57
+ removeSelectedItems(): void;
58
+ /** Moves an item to a new parent. */
59
+ move(key: Key, toParentKey: Key | null, index: number): void;
60
+ /** Updates an item in the tree. */
61
+ update(key: Key, newValue: T): void;
62
+ }
63
+
64
+ interface TreeDataState<T> {
65
+ items: TreeNode<T>[];
66
+ nodeMap: Map<Key, TreeNode<T>>;
67
+ }
68
+
69
+ /**
70
+ * Manages state for an immutable tree data structure, and provides
71
+ * convenience methods to update the data over time.
72
+ */
73
+ export function createTreeData<T>(options: TreeOptions<T>): TreeData<T> {
74
+ const {
75
+ initialItems = [],
76
+ initialSelectedKeys,
77
+ getKey = (item: any) => item.id ?? item.key,
78
+ getChildren = (item: any) => item.children ?? [],
79
+ } = options;
80
+
81
+ // Build initial tree
82
+ const initialTree = buildTree(initialItems, new Map(), null, getKey, getChildren);
83
+
84
+ const [treeState, setTreeState] = createSignal<TreeDataState<T>>(initialTree);
85
+ const [selectedKeys, setSelectedKeys] = createSignal<Selection>(
86
+ initialSelectedKeys === 'all' ? 'all' : new Set(initialSelectedKeys || [])
87
+ );
88
+
89
+ function updateTree(
90
+ items: TreeNode<T>[],
91
+ key: Key | null,
92
+ update: (node: TreeNode<T>) => TreeNode<T> | null,
93
+ originalMap: Map<Key, TreeNode<T>>,
94
+ ): TreeDataState<T> {
95
+ let node = key != null ? originalMap.get(key) : null;
96
+ if (key != null && !node) return { items, nodeMap: originalMap };
97
+
98
+ const newMap = new Map(originalMap);
99
+
100
+ if (node) {
101
+ const updated = update(node);
102
+ if (!updated) {
103
+ // Delete node
104
+ deleteNode(node, newMap);
105
+ if (node.parentKey != null) {
106
+ return updateTree(items, node.parentKey, parent => ({
107
+ ...parent,
108
+ children: parent.children!.filter(c => c.key !== key),
109
+ }), newMap);
110
+ }
111
+ return { items: items.filter(i => i.key !== key), nodeMap: newMap };
112
+ }
113
+
114
+ newMap.set(key!, updated);
115
+ if (updated.children) {
116
+ for (const child of updated.children) {
117
+ addNode(child, newMap);
118
+ }
119
+ }
120
+
121
+ 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);
126
+ }
127
+
128
+ return { items: items.map(i => i.key === key ? updated : i), nodeMap: newMap };
129
+ }
130
+
131
+ return { items, nodeMap: newMap };
132
+ }
133
+
134
+ return {
135
+ get items() { return treeState().items; },
136
+ get selectedKeys() { return selectedKeys(); },
137
+
138
+ setSelectedKeys(keys: Selection) {
139
+ setSelectedKeys(keys);
140
+ },
141
+
142
+ getItem(key: Key) {
143
+ return treeState().nodeMap.get(key);
144
+ },
145
+
146
+ insert(parentKey: Key | null, index: number, ...values: T[]) {
147
+ setTreeState(state => {
148
+ const { items, nodeMap } = state;
149
+ const newMap = new Map(nodeMap);
150
+ const newNodes = values.map(v => {
151
+ const tree = buildTree([v], newMap, parentKey, getKey, getChildren);
152
+ return tree.items[0];
153
+ });
154
+
155
+ if (parentKey == null) {
156
+ return {
157
+ items: [...items.slice(0, index), ...newNodes, ...items.slice(index)],
158
+ nodeMap: newMap,
159
+ };
160
+ }
161
+
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);
170
+ });
171
+ },
172
+
173
+ insertBefore(key: Key, ...values: T[]) {
174
+ setTreeState(state => {
175
+ const { items, nodeMap } = state;
176
+ const node = nodeMap.get(key);
177
+ if (!node) return state;
178
+
179
+ const parent = node.parentKey != null ? nodeMap.get(node.parentKey) : null;
180
+ const siblings = parent?.children ?? items;
181
+ const index = siblings.findIndex(n => n.key === key);
182
+ if (index === -1) return state;
183
+
184
+ const newMap = new Map(nodeMap);
185
+ const newNodes = values.map(v => {
186
+ const tree = buildTree([v], newMap, node.parentKey, getKey, getChildren);
187
+ return tree.items[0];
188
+ });
189
+
190
+ if (node.parentKey == null) {
191
+ return {
192
+ items: [...items.slice(0, index), ...newNodes, ...items.slice(index)],
193
+ nodeMap: newMap,
194
+ };
195
+ }
196
+
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);
205
+ });
206
+ },
207
+
208
+ insertAfter(key: Key, ...values: T[]) {
209
+ setTreeState(state => {
210
+ const { items, nodeMap } = state;
211
+ const node = nodeMap.get(key);
212
+ if (!node) return state;
213
+
214
+ const parent = node.parentKey != null ? nodeMap.get(node.parentKey) : null;
215
+ const siblings = parent?.children ?? items;
216
+ const index = siblings.findIndex(n => n.key === key);
217
+ if (index === -1) return state;
218
+
219
+ const newMap = new Map(nodeMap);
220
+ const newNodes = values.map(v => {
221
+ const tree = buildTree([v], newMap, node.parentKey, getKey, getChildren);
222
+ return tree.items[0];
223
+ });
224
+
225
+ if (node.parentKey == null) {
226
+ return {
227
+ items: [...items.slice(0, index + 1), ...newNodes, ...items.slice(index + 1)],
228
+ nodeMap: newMap,
229
+ };
230
+ }
231
+
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);
240
+ });
241
+ },
242
+
243
+ append(parentKey: Key | null, ...values: T[]) {
244
+ setTreeState(state => {
245
+ const { items, nodeMap } = state;
246
+ const newMap = new Map(nodeMap);
247
+ const newNodes = values.map(v => {
248
+ const tree = buildTree([v], newMap, parentKey, getKey, getChildren);
249
+ return tree.items[0];
250
+ });
251
+
252
+ if (parentKey == null) {
253
+ return { items: [...items, ...newNodes], nodeMap: newMap };
254
+ }
255
+
256
+ return updateTree(items, parentKey, parent => ({
257
+ ...parent,
258
+ children: [...(parent.children || []), ...newNodes],
259
+ }), newMap);
260
+ });
261
+ },
262
+
263
+ prepend(parentKey: Key | null, ...values: T[]) {
264
+ setTreeState(state => {
265
+ const { items, nodeMap } = state;
266
+ const newMap = new Map(nodeMap);
267
+ const newNodes = values.map(v => {
268
+ const tree = buildTree([v], newMap, parentKey, getKey, getChildren);
269
+ return tree.items[0];
270
+ });
271
+
272
+ if (parentKey == null) {
273
+ return { items: [...newNodes, ...items], nodeMap: newMap };
274
+ }
275
+
276
+ return updateTree(items, parentKey, parent => ({
277
+ ...parent,
278
+ children: [...newNodes, ...(parent.children || [])],
279
+ }), newMap);
280
+ });
281
+ },
282
+
283
+ remove(...keys: Key[]) {
284
+ setTreeState(state => {
285
+ let { items, nodeMap } = state;
286
+ let newMap = new Map(nodeMap);
287
+ let newItems = items;
288
+
289
+ for (const key of keys) {
290
+ const result = updateTree(newItems, key, () => null, newMap);
291
+ newItems = result.items;
292
+ newMap = result.nodeMap;
293
+ }
294
+
295
+ return { items: newItems, nodeMap: newMap };
296
+ });
297
+
298
+ setSelectedKeys(sel => {
299
+ if (sel === 'all') return sel;
300
+ const newSel = new Set(sel);
301
+ for (const key of keys) {
302
+ newSel.delete(key);
303
+ }
304
+ return newSel;
305
+ });
306
+ },
307
+
308
+ removeSelectedItems() {
309
+ const sel = selectedKeys();
310
+ if (sel === 'all') {
311
+ setTreeState({ items: [], nodeMap: new Map() });
312
+ setSelectedKeys(new Set<Key>());
313
+ return;
314
+ }
315
+
316
+ const keysToRemove = [...sel];
317
+ setTreeState(state => {
318
+ let { items, nodeMap } = state;
319
+ let newMap = new Map(nodeMap);
320
+ let newItems = items;
321
+ for (const key of keysToRemove) {
322
+ const result = updateTree(newItems, key, () => null, newMap);
323
+ newItems = result.items;
324
+ newMap = result.nodeMap;
325
+ }
326
+ return { items: newItems, nodeMap: newMap };
327
+ });
328
+ setSelectedKeys(new Set<Key>());
329
+ },
330
+
331
+ move(key: Key, toParentKey: Key | null, index: number) {
332
+ setTreeState(state => {
333
+ const { items, nodeMap } = state;
334
+ const node = nodeMap.get(key);
335
+ if (!node) return state;
336
+
337
+ // Remove the node
338
+ let newMap = new Map(nodeMap);
339
+ const removeResult = updateTree(items, key, () => null, newMap);
340
+ let newItems = removeResult.items;
341
+ newMap = removeResult.nodeMap;
342
+
343
+ // Re-add it at the target
344
+ const movedNode: TreeNode<T> = { ...node, parentKey: toParentKey };
345
+ addNode(movedNode, newMap);
346
+
347
+ if (toParentKey == null) {
348
+ return {
349
+ items: [...newItems.slice(0, index), movedNode, ...newItems.slice(index)],
350
+ nodeMap: newMap,
351
+ };
352
+ }
353
+
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);
362
+ });
363
+ },
364
+
365
+ update(key: Key, newValue: T) {
366
+ setTreeState(state => {
367
+ const { items, nodeMap } = state;
368
+ const newMap = new Map(nodeMap);
369
+
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);
381
+ });
382
+ },
383
+ };
384
+ }
385
+
386
+ function buildTree<T>(
387
+ items: T[],
388
+ nodeMap: Map<Key, TreeNode<T>>,
389
+ parentKey: Key | null,
390
+ getKey: (item: T) => Key,
391
+ getChildren: (item: T) => T[],
392
+ ): TreeDataState<T> {
393
+ const nodes: TreeNode<T>[] = [];
394
+
395
+ for (const item of items) {
396
+ const key = getKey(item);
397
+ const children = getChildren(item);
398
+
399
+ const childTree = children.length > 0
400
+ ? buildTree(children, nodeMap, key, getKey, getChildren)
401
+ : { items: [], nodeMap };
402
+
403
+ const node: TreeNode<T> = {
404
+ key,
405
+ parentKey,
406
+ value: item,
407
+ children: childTree.items.length > 0 ? childTree.items : null,
408
+ };
409
+
410
+ nodeMap.set(key, node);
411
+ nodes.push(node);
412
+ }
413
+
414
+ return { items: nodes, nodeMap };
415
+ }
416
+
417
+ function addNode<T>(node: TreeNode<T>, map: Map<Key, TreeNode<T>>): void {
418
+ map.set(node.key, node);
419
+ if (node.children) {
420
+ for (const child of node.children) {
421
+ addNode(child, map);
422
+ }
423
+ }
424
+ }
425
+
426
+ function deleteNode<T>(node: TreeNode<T>, map: Map<Key, TreeNode<T>>): void {
427
+ map.delete(node.key);
428
+ if (node.children) {
429
+ for (const child of node.children) {
430
+ deleteNode(child, map);
431
+ }
432
+ }
433
+ }
@@ -0,0 +1,25 @@
1
+ export {
2
+ createListData,
3
+ type ListOptions,
4
+ type ListData,
5
+ type Key as ListDataKey,
6
+ type Selection as ListDataSelection,
7
+ } from './createListData';
8
+
9
+ export {
10
+ createTreeData,
11
+ type TreeOptions,
12
+ type TreeData,
13
+ type TreeNode as TreeDataNode,
14
+ } from './createTreeData';
15
+
16
+ export {
17
+ createAsyncList,
18
+ type AsyncListOptions,
19
+ type AsyncListData,
20
+ type AsyncListLoadFunction,
21
+ type AsyncListLoadOptions,
22
+ type AsyncListStateUpdate,
23
+ type SortDescriptor,
24
+ type LoadingState,
25
+ } from './createAsyncList';
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Datepicker compatibility surface.
3
+ *
4
+ * This is a module-compat shim that maps React Stately datepicker hook names
5
+ * to existing Solid stately primitives.
6
+ */
7
+
8
+ export {
9
+ createDateFieldState,
10
+ createTimeFieldState,
11
+ createRangeCalendarState,
12
+ type DateFieldStateProps as DateFieldStateOptions,
13
+ type DateFieldState,
14
+ type DateSegment,
15
+ type DateSegmentType as SegmentType,
16
+ type TimeFieldStateProps as TimeFieldStateOptions,
17
+ type TimeFieldState,
18
+ type TimeSegment,
19
+ type TimeSegmentType,
20
+ type RangeCalendarStateProps as DateRangePickerStateOptions,
21
+ 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';
29
+
30
+ export {
31
+ createDateFieldState as useDateFieldState,
32
+ createTimeFieldState as useTimeFieldState,
33
+ createRangeCalendarState as useDateRangePickerState,
34
+ } from '../calendar';
35
+
36
+ export { createOverlayTriggerState as useDatePickerState } from '../overlays';
@@ -3,7 +3,7 @@
3
3
  * Based on @react-stately/disclosure useDisclosureState and useDisclosureGroupState
4
4
  */
5
5
 
6
- import { createSignal, createEffect, type Accessor } from 'solid-js';
6
+ import { createSignal, createEffect, createMemo, type Accessor } from 'solid-js';
7
7
  import { access, type MaybeAccessor } from '../utils';
8
8
 
9
9
  // ============================================
@@ -121,11 +121,11 @@ export function createDisclosureGroupState(
121
121
  new Set(propsAccessor().defaultExpandedKeys ?? [])
122
122
  );
123
123
 
124
- // Determine expanded keys (controlled vs uncontrolled)
125
- const expandedKeys: Accessor<Set<Key>> = () => {
124
+ // Determine expanded keys (controlled vs uncontrolled, memoized)
125
+ const expandedKeys: Accessor<Set<Key>> = createMemo(() => {
126
126
  const p = propsAccessor();
127
127
  return p.expandedKeys !== undefined ? new Set(p.expandedKeys) : internalKeys();
128
- };
128
+ });
129
129
 
130
130
  const setExpandedKeys = (keys: Set<Key>) => {
131
131
  const p = propsAccessor();