@proyecto-viviana/solid-stately 0.0.6 → 0.1.1

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 (208) hide show
  1. package/README.md +312 -0
  2. package/dist/index.d.ts +3363 -6
  3. package/dist/index.js +6194 -19
  4. package/dist/index.js.map +1 -1
  5. package/package.json +52 -48
  6. package/src/autocomplete/createAutocompleteState.d.ts +46 -0
  7. package/src/autocomplete/createAutocompleteState.d.ts.map +1 -0
  8. package/src/autocomplete/createAutocompleteState.ts +90 -0
  9. package/src/autocomplete/index.d.ts +2 -0
  10. package/src/autocomplete/index.d.ts.map +1 -0
  11. package/src/autocomplete/index.ts +5 -0
  12. package/src/calendar/createCalendarState.d.ts +130 -0
  13. package/src/calendar/createCalendarState.d.ts.map +1 -0
  14. package/src/calendar/createCalendarState.ts +461 -0
  15. package/src/calendar/createDateFieldState.d.ts +110 -0
  16. package/src/calendar/createDateFieldState.d.ts.map +1 -0
  17. package/src/calendar/createDateFieldState.ts +562 -0
  18. package/src/calendar/createRangeCalendarState.d.ts +146 -0
  19. package/src/calendar/createRangeCalendarState.d.ts.map +1 -0
  20. package/src/calendar/createRangeCalendarState.ts +535 -0
  21. package/src/calendar/createTimeFieldState.d.ts +95 -0
  22. package/src/calendar/createTimeFieldState.d.ts.map +1 -0
  23. package/src/calendar/createTimeFieldState.ts +483 -0
  24. package/src/calendar/index.d.ts +7 -0
  25. package/src/calendar/index.d.ts.map +1 -0
  26. package/src/calendar/index.ts +81 -0
  27. package/{dist → src}/checkbox/createCheckboxGroupState.d.ts +1 -0
  28. package/src/checkbox/createCheckboxGroupState.d.ts.map +1 -0
  29. package/{dist → src}/checkbox/index.d.ts +1 -0
  30. package/src/checkbox/index.d.ts.map +1 -0
  31. package/src/collections/ListCollection.d.ts +37 -0
  32. package/src/collections/ListCollection.d.ts.map +1 -0
  33. package/src/collections/ListCollection.ts +146 -0
  34. package/src/collections/createListState.d.ts +79 -0
  35. package/src/collections/createListState.d.ts.map +1 -0
  36. package/src/collections/createListState.ts +264 -0
  37. package/src/collections/createMenuState.d.ts +50 -0
  38. package/src/collections/createMenuState.d.ts.map +1 -0
  39. package/src/collections/createMenuState.ts +106 -0
  40. package/src/collections/createSelectionState.d.ts +76 -0
  41. package/src/collections/createSelectionState.d.ts.map +1 -0
  42. package/src/collections/createSelectionState.ts +336 -0
  43. package/src/collections/index.d.ts +6 -0
  44. package/src/collections/index.d.ts.map +1 -0
  45. package/src/collections/index.ts +46 -0
  46. package/src/collections/types.d.ts +147 -0
  47. package/src/collections/types.d.ts.map +1 -0
  48. package/src/collections/types.ts +169 -0
  49. package/src/color/Color.d.ts +28 -0
  50. package/src/color/Color.d.ts.map +1 -0
  51. package/src/color/Color.ts +951 -0
  52. package/src/color/createColorAreaState.d.ts +76 -0
  53. package/src/color/createColorAreaState.d.ts.map +1 -0
  54. package/src/color/createColorAreaState.ts +293 -0
  55. package/src/color/createColorFieldState.d.ts +55 -0
  56. package/src/color/createColorFieldState.d.ts.map +1 -0
  57. package/src/color/createColorFieldState.ts +292 -0
  58. package/src/color/createColorSliderState.d.ts +67 -0
  59. package/src/color/createColorSliderState.d.ts.map +1 -0
  60. package/src/color/createColorSliderState.ts +241 -0
  61. package/src/color/createColorWheelState.d.ts +51 -0
  62. package/src/color/createColorWheelState.d.ts.map +1 -0
  63. package/src/color/createColorWheelState.ts +211 -0
  64. package/src/color/index.d.ts +10 -0
  65. package/src/color/index.d.ts.map +1 -0
  66. package/src/color/index.ts +47 -0
  67. package/src/color/types.d.ts +106 -0
  68. package/src/color/types.d.ts.map +1 -0
  69. package/src/color/types.ts +127 -0
  70. package/src/combobox/createComboBoxState.d.ts +125 -0
  71. package/src/combobox/createComboBoxState.d.ts.map +1 -0
  72. package/src/combobox/createComboBoxState.ts +703 -0
  73. package/src/combobox/index.d.ts +5 -0
  74. package/src/combobox/index.d.ts.map +1 -0
  75. package/src/combobox/index.ts +13 -0
  76. package/src/disclosure/createDisclosureState.d.ts +64 -0
  77. package/src/disclosure/createDisclosureState.d.ts.map +1 -0
  78. package/src/disclosure/createDisclosureState.ts +193 -0
  79. package/src/disclosure/index.d.ts +2 -0
  80. package/src/disclosure/index.d.ts.map +1 -0
  81. package/src/disclosure/index.ts +9 -0
  82. package/src/dnd/createDragState.d.ts +59 -0
  83. package/src/dnd/createDragState.d.ts.map +1 -0
  84. package/src/dnd/createDragState.ts +153 -0
  85. package/src/dnd/createDraggableCollectionState.d.ts +57 -0
  86. package/src/dnd/createDraggableCollectionState.d.ts.map +1 -0
  87. package/src/dnd/createDraggableCollectionState.ts +165 -0
  88. package/src/dnd/createDropState.d.ts +61 -0
  89. package/src/dnd/createDropState.d.ts.map +1 -0
  90. package/src/dnd/createDropState.ts +212 -0
  91. package/src/dnd/createDroppableCollectionState.d.ts +78 -0
  92. package/src/dnd/createDroppableCollectionState.d.ts.map +1 -0
  93. package/src/dnd/createDroppableCollectionState.ts +357 -0
  94. package/src/dnd/index.d.ts +11 -0
  95. package/src/dnd/index.d.ts.map +1 -0
  96. package/src/dnd/index.ts +76 -0
  97. package/src/dnd/types.d.ts +264 -0
  98. package/src/dnd/types.d.ts.map +1 -0
  99. package/src/dnd/types.ts +317 -0
  100. package/src/form/createFormValidationState.d.ts +100 -0
  101. package/src/form/createFormValidationState.d.ts.map +1 -0
  102. package/src/form/createFormValidationState.ts +389 -0
  103. package/src/form/index.d.ts +2 -0
  104. package/src/form/index.d.ts.map +1 -0
  105. package/src/form/index.ts +15 -0
  106. package/src/grid/createGridState.d.ts +12 -0
  107. package/src/grid/createGridState.d.ts.map +1 -0
  108. package/src/grid/createGridState.ts +327 -0
  109. package/src/grid/index.d.ts +7 -0
  110. package/src/grid/index.d.ts.map +1 -0
  111. package/src/grid/index.ts +13 -0
  112. package/src/grid/types.d.ts +156 -0
  113. package/src/grid/types.d.ts.map +1 -0
  114. package/src/grid/types.ts +179 -0
  115. package/src/index.d.ts +26 -0
  116. package/src/index.d.ts.map +1 -0
  117. package/src/index.ts +350 -1
  118. package/src/numberfield/createNumberFieldState.d.ts +65 -0
  119. package/src/numberfield/createNumberFieldState.d.ts.map +1 -0
  120. package/src/numberfield/createNumberFieldState.ts +383 -0
  121. package/src/numberfield/index.d.ts +2 -0
  122. package/src/numberfield/index.d.ts.map +1 -0
  123. package/src/numberfield/index.ts +5 -0
  124. package/src/overlays/createOverlayTriggerState.d.ts +32 -0
  125. package/src/overlays/createOverlayTriggerState.d.ts.map +1 -0
  126. package/src/overlays/createOverlayTriggerState.ts +67 -0
  127. package/src/overlays/index.d.ts +2 -0
  128. package/src/overlays/index.d.ts.map +1 -0
  129. package/src/overlays/index.ts +5 -0
  130. package/{dist → src}/radio/createRadioGroupState.d.ts +1 -0
  131. package/src/radio/createRadioGroupState.d.ts.map +1 -0
  132. package/{dist → src}/radio/index.d.ts +1 -0
  133. package/src/radio/index.d.ts.map +1 -0
  134. package/src/searchfield/createSearchFieldState.d.ts +25 -0
  135. package/src/searchfield/createSearchFieldState.d.ts.map +1 -0
  136. package/src/searchfield/createSearchFieldState.ts +62 -0
  137. package/src/searchfield/index.d.ts +3 -0
  138. package/src/searchfield/index.d.ts.map +1 -0
  139. package/src/searchfield/index.ts +5 -0
  140. package/src/select/createSelectState.d.ts +73 -0
  141. package/src/select/createSelectState.d.ts.map +1 -0
  142. package/src/select/createSelectState.ts +181 -0
  143. package/src/select/index.d.ts +2 -0
  144. package/src/select/index.d.ts.map +1 -0
  145. package/src/select/index.ts +5 -0
  146. package/src/slider/createSliderState.d.ts +72 -0
  147. package/src/slider/createSliderState.d.ts.map +1 -0
  148. package/src/slider/createSliderState.ts +211 -0
  149. package/src/slider/index.d.ts +3 -0
  150. package/src/slider/index.d.ts.map +1 -0
  151. package/src/slider/index.ts +6 -0
  152. package/{dist → src}/ssr/index.d.ts +5 -0
  153. package/src/ssr/index.d.ts.map +1 -0
  154. package/src/ssr/index.ts +6 -1
  155. package/src/table/TableCollection.d.ts +52 -0
  156. package/src/table/TableCollection.d.ts.map +1 -0
  157. package/src/table/TableCollection.ts +388 -0
  158. package/src/table/createTableState.d.ts +12 -0
  159. package/src/table/createTableState.d.ts.map +1 -0
  160. package/src/table/createTableState.ts +127 -0
  161. package/src/table/index.d.ts +8 -0
  162. package/src/table/index.d.ts.map +1 -0
  163. package/src/table/index.ts +18 -0
  164. package/src/table/types.d.ts +139 -0
  165. package/src/table/types.d.ts.map +1 -0
  166. package/src/table/types.ts +150 -0
  167. package/src/tabs/createTabListState.d.ts +68 -0
  168. package/src/tabs/createTabListState.d.ts.map +1 -0
  169. package/src/tabs/createTabListState.ts +240 -0
  170. package/src/tabs/index.d.ts +2 -0
  171. package/src/tabs/index.d.ts.map +1 -0
  172. package/src/tabs/index.ts +7 -0
  173. package/{dist → src}/textfield/createTextFieldState.d.ts +1 -0
  174. package/src/textfield/createTextFieldState.d.ts.map +1 -0
  175. package/{dist → src}/textfield/index.d.ts +1 -0
  176. package/src/textfield/index.d.ts.map +1 -0
  177. package/src/toast/createToastState.d.ts +118 -0
  178. package/src/toast/createToastState.d.ts.map +1 -0
  179. package/src/toast/createToastState.ts +316 -0
  180. package/src/toast/index.d.ts +2 -0
  181. package/src/toast/index.d.ts.map +1 -0
  182. package/src/toast/index.ts +11 -0
  183. package/{dist → src}/toggle/createToggleState.d.ts +1 -0
  184. package/src/toggle/createToggleState.d.ts.map +1 -0
  185. package/{dist → src}/toggle/index.d.ts +1 -0
  186. package/src/toggle/index.d.ts.map +1 -0
  187. package/src/tooltip/createTooltipTriggerState.d.ts +39 -0
  188. package/src/tooltip/createTooltipTriggerState.d.ts.map +1 -0
  189. package/src/tooltip/createTooltipTriggerState.ts +183 -0
  190. package/src/tooltip/index.d.ts +2 -0
  191. package/src/tooltip/index.d.ts.map +1 -0
  192. package/src/tooltip/index.ts +6 -0
  193. package/src/tree/TreeCollection.d.ts +40 -0
  194. package/src/tree/TreeCollection.d.ts.map +1 -0
  195. package/src/tree/TreeCollection.ts +175 -0
  196. package/src/tree/createTreeState.d.ts +14 -0
  197. package/src/tree/createTreeState.d.ts.map +1 -0
  198. package/src/tree/createTreeState.ts +392 -0
  199. package/src/tree/index.d.ts +7 -0
  200. package/src/tree/index.d.ts.map +1 -0
  201. package/src/tree/index.ts +13 -0
  202. package/src/tree/types.d.ts +157 -0
  203. package/src/tree/types.d.ts.map +1 -0
  204. package/src/tree/types.ts +174 -0
  205. package/{dist → src}/utils/index.d.ts +1 -0
  206. package/src/utils/index.d.ts.map +1 -0
  207. package/{dist → src}/utils/reactivity.d.ts +1 -0
  208. package/src/utils/reactivity.d.ts.map +1 -0
@@ -0,0 +1,175 @@
1
+ /**
2
+ * TreeCollection implementation.
3
+ * Based on @react-stately/tree/TreeCollection.
4
+ *
5
+ * A flattened view of tree nodes that respects expanded state.
6
+ * Only visible nodes (root + expanded children) are included in iteration.
7
+ */
8
+
9
+ import type { Key } from '../collections/types';
10
+ import type { TreeCollection as ITreeCollection, TreeNode, TreeItemData } from './types';
11
+
12
+ /**
13
+ * Creates a TreeCollection from hierarchical data.
14
+ * The collection is flattened based on expanded keys.
15
+ */
16
+ export class TreeCollection<T> implements ITreeCollection<T> {
17
+ private keyMap: Map<Key, TreeNode<T>> = new Map();
18
+ private visibleKeys: Key[] = [];
19
+ private _rows: TreeNode<T>[] = [];
20
+
21
+ constructor(
22
+ items: TreeItemData<T>[],
23
+ expandedKeys: Set<Key>
24
+ ) {
25
+ this.buildCollection(items, expandedKeys);
26
+ }
27
+
28
+ private buildCollection(items: TreeItemData<T>[], expandedKeys: Set<Key>): void {
29
+ let globalIndex = 0;
30
+
31
+ const visit = (
32
+ item: TreeItemData<T>,
33
+ level: number,
34
+ parentKey: Key | null,
35
+ indexInParent: number
36
+ ): TreeNode<T> => {
37
+ const hasChildren = item.children && item.children.length > 0;
38
+ const isExpanded = hasChildren && expandedKeys.has(item.key);
39
+
40
+ // Build child nodes first (even if not visible, for the map)
41
+ const childNodes: TreeNode<T>[] = [];
42
+ if (hasChildren && item.children) {
43
+ for (let i = 0; i < item.children.length; i++) {
44
+ const childNode = visit(item.children[i], level + 1, item.key, i);
45
+ childNodes.push(childNode);
46
+ }
47
+ }
48
+
49
+ const node: TreeNode<T> = {
50
+ type: 'item',
51
+ key: item.key,
52
+ value: item.value,
53
+ textValue: item.textValue || String(item.key),
54
+ level,
55
+ index: indexInParent,
56
+ parentKey,
57
+ hasChildNodes: hasChildren || false,
58
+ childNodes,
59
+ isDisabled: item.isDisabled,
60
+ isExpandable: hasChildren,
61
+ isExpanded,
62
+ };
63
+
64
+ // Always add to keyMap (for getItem lookups)
65
+ this.keyMap.set(item.key, node);
66
+
67
+ return node;
68
+ };
69
+
70
+ // First pass: build all nodes
71
+ const rootNodes: TreeNode<T>[] = [];
72
+ for (let i = 0; i < items.length; i++) {
73
+ const node = visit(items[i], 0, null, i);
74
+ rootNodes.push(node);
75
+ }
76
+
77
+ // Second pass: build visible rows list
78
+ const addVisibleNodes = (nodes: TreeNode<T>[]): void => {
79
+ for (const node of nodes) {
80
+ // Update the row index for visible nodes
81
+ node.rowIndex = globalIndex++;
82
+ this._rows.push(node);
83
+ this.visibleKeys.push(node.key);
84
+
85
+ // Add children if expanded
86
+ if (node.isExpanded && node.childNodes.length > 0) {
87
+ addVisibleNodes(node.childNodes);
88
+ }
89
+ }
90
+ };
91
+
92
+ addVisibleNodes(rootNodes);
93
+ }
94
+
95
+ // Collection properties
96
+
97
+ get size(): number {
98
+ return this.visibleKeys.length;
99
+ }
100
+
101
+ get rows(): TreeNode<T>[] {
102
+ return this._rows;
103
+ }
104
+
105
+ get rowCount(): number {
106
+ return this._rows.length;
107
+ }
108
+
109
+ // Collection methods
110
+
111
+ getKeys(): Iterable<Key> {
112
+ return this.visibleKeys;
113
+ }
114
+
115
+ getItem(key: Key): TreeNode<T> | null {
116
+ return this.keyMap.get(key) ?? null;
117
+ }
118
+
119
+ at(index: number): TreeNode<T> | null {
120
+ if (index < 0 || index >= this._rows.length) {
121
+ return null;
122
+ }
123
+ return this._rows[index];
124
+ }
125
+
126
+ getKeyBefore(key: Key): Key | null {
127
+ const index = this.visibleKeys.indexOf(key);
128
+ if (index <= 0) return null;
129
+ return this.visibleKeys[index - 1];
130
+ }
131
+
132
+ getKeyAfter(key: Key): Key | null {
133
+ const index = this.visibleKeys.indexOf(key);
134
+ if (index < 0 || index >= this.visibleKeys.length - 1) return null;
135
+ return this.visibleKeys[index + 1];
136
+ }
137
+
138
+ getFirstKey(): Key | null {
139
+ return this.visibleKeys[0] ?? null;
140
+ }
141
+
142
+ getLastKey(): Key | null {
143
+ return this.visibleKeys[this.visibleKeys.length - 1] ?? null;
144
+ }
145
+
146
+ getChildren(key: Key): Iterable<TreeNode<T>> {
147
+ const node = this.keyMap.get(key);
148
+ return node?.childNodes ?? [];
149
+ }
150
+
151
+ getTextValue(key: Key): string {
152
+ const node = this.keyMap.get(key);
153
+ return node?.textValue ?? '';
154
+ }
155
+
156
+ getParentKey(key: Key): Key | null {
157
+ const node = this.keyMap.get(key);
158
+ return node?.parentKey ?? null;
159
+ }
160
+
161
+ [Symbol.iterator](): Iterator<TreeNode<T>> {
162
+ return this._rows[Symbol.iterator]();
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Factory function to create a TreeCollection.
168
+ * Useful for the collectionFactory pattern in TreeStateOptions.
169
+ */
170
+ export function createTreeCollection<T>(
171
+ items: TreeItemData<T>[],
172
+ expandedKeys: Set<Key>
173
+ ): TreeCollection<T> {
174
+ return new TreeCollection(items, expandedKeys);
175
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Tree state management for Tree components.
3
+ * Based on @react-stately/tree/useTreeState.
4
+ *
5
+ * Manages expansion state, selection, and focus for hierarchical tree data.
6
+ */
7
+ import { type Accessor } from 'solid-js';
8
+ import type { TreeState, TreeStateOptions, TreeCollection } from './types';
9
+ /**
10
+ * Creates state management for a tree component.
11
+ * Handles expansion, selection, focus management, and keyboard navigation state.
12
+ */
13
+ export declare function createTreeState<T extends object, C extends TreeCollection<T> = TreeCollection<T>>(options: Accessor<TreeStateOptions<T, C>>): TreeState<T, C>;
14
+ //# sourceMappingURL=createTreeState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createTreeState.d.ts","sourceRoot":"","sources":["createTreeState.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAA8C,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AACrF,OAAO,KAAK,EACV,SAAS,EACT,gBAAgB,EAChB,cAAc,EAEf,MAAM,SAAS,CAAC;AAGjB;;;GAGG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,cAAc,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,EAC/F,OAAO,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GACxC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAiWjB"}
@@ -0,0 +1,392 @@
1
+ /**
2
+ * Tree state management for Tree components.
3
+ * Based on @react-stately/tree/useTreeState.
4
+ *
5
+ * Manages expansion state, selection, and focus for hierarchical tree data.
6
+ */
7
+
8
+ import { createSignal, createEffect, createMemo, on, type Accessor } from 'solid-js';
9
+ import type {
10
+ TreeState,
11
+ TreeStateOptions,
12
+ TreeCollection,
13
+ TreeNode,
14
+ } from './types';
15
+ import type { Key, FocusStrategy } from '../collections/types';
16
+
17
+ /**
18
+ * Creates state management for a tree component.
19
+ * Handles expansion, selection, focus management, and keyboard navigation state.
20
+ */
21
+ export function createTreeState<T extends object, C extends TreeCollection<T> = TreeCollection<T>>(
22
+ options: Accessor<TreeStateOptions<T, C>>
23
+ ): TreeState<T, C> {
24
+ const getOptions = () => options();
25
+
26
+ // Disabled keys as a Set
27
+ const disabledKeys = createMemo(() => {
28
+ const keys = getOptions().disabledKeys;
29
+ return keys ? new Set(keys) : new Set<Key>();
30
+ });
31
+
32
+ // Expansion state (uncontrolled)
33
+ const [internalExpandedKeys, setInternalExpandedKeys] = createSignal<Set<Key>>(
34
+ getInitialExpandedKeys(getOptions().defaultExpandedKeys)
35
+ );
36
+
37
+ // Computed expanded keys (controlled or uncontrolled)
38
+ const expandedKeys = createMemo(() => {
39
+ const opts = getOptions();
40
+ if (opts.expandedKeys !== undefined) {
41
+ return new Set(opts.expandedKeys);
42
+ }
43
+ return internalExpandedKeys();
44
+ });
45
+
46
+ // Collection - rebuilt when expanded keys change
47
+ const collection = createMemo(() => {
48
+ const opts = getOptions();
49
+ return opts.collectionFactory(expandedKeys());
50
+ });
51
+
52
+ // Focus state
53
+ const [isFocused, setIsFocused] = createSignal(false);
54
+ const [focusedKey, setFocusedKeyInternal] = createSignal<Key | null>(null);
55
+ const [childFocusStrategy, setChildFocusStrategy] = createSignal<FocusStrategy | null>(null);
56
+ const [isKeyboardNavigationDisabled, setKeyboardNavigationDisabled] = createSignal(false);
57
+
58
+ // Selection state
59
+ const [internalSelectedKeys, setInternalSelectedKeys] = createSignal<'all' | Set<Key>>(
60
+ getInitialSelection(getOptions().defaultSelectedKeys)
61
+ );
62
+ const [anchorKey, setAnchorKey] = createSignal<Key | null>(null);
63
+
64
+ // Computed selection
65
+ const selectedKeys = createMemo(() => {
66
+ const opts = getOptions();
67
+ if (opts.selectedKeys !== undefined) {
68
+ return normalizeSelection(opts.selectedKeys);
69
+ }
70
+ return internalSelectedKeys();
71
+ });
72
+
73
+ const selectionMode = createMemo(() => getOptions().selectionMode ?? 'none');
74
+ const selectionBehavior = createMemo(() => getOptions().selectionBehavior ?? 'toggle');
75
+ const disallowEmptySelection = createMemo(() => getOptions().disallowEmptySelection ?? false);
76
+ const disabledBehavior = createMemo(() => getOptions().disabledBehavior ?? 'all');
77
+
78
+ // Set focused key
79
+ const setFocusedKey = (key: Key | null, strategy: FocusStrategy = 'first') => {
80
+ setFocusedKeyInternal(key);
81
+ setChildFocusStrategy(strategy);
82
+ };
83
+
84
+ // Reset focused key if the item is removed from visible collection
85
+ let cachedCollection: C | null = null;
86
+
87
+ createEffect(
88
+ on(collection, (coll) => {
89
+ const currentFocusedKey = focusedKey();
90
+
91
+ if (currentFocusedKey != null && cachedCollection) {
92
+ // Check if the focused item is still visible
93
+ const visibleKeys = [...coll.getKeys()];
94
+ if (!visibleKeys.includes(currentFocusedKey)) {
95
+ // The focused item was collapsed or removed, find a new one to focus
96
+ // Try to find the parent and focus it
97
+ const node = cachedCollection.getItem(currentFocusedKey);
98
+ if (node?.parentKey != null) {
99
+ const parent = coll.getItem(node.parentKey);
100
+ if (parent && visibleKeys.includes(parent.key)) {
101
+ setFocusedKeyInternal(parent.key);
102
+ cachedCollection = coll;
103
+ return;
104
+ }
105
+ }
106
+
107
+ // Otherwise, find the nearest visible sibling or previous item
108
+ const rows = coll.rows;
109
+ if (rows.length > 0) {
110
+ // Find the closest item to where the focused item was
111
+ const cachedNode = cachedCollection.getItem(currentFocusedKey);
112
+ if (cachedNode?.rowIndex !== undefined) {
113
+ const newIndex = Math.min(cachedNode.rowIndex, rows.length - 1);
114
+ const newNode = rows[newIndex];
115
+ if (newNode && !disabledKeys().has(newNode.key)) {
116
+ setFocusedKeyInternal(newNode.key);
117
+ cachedCollection = coll;
118
+ return;
119
+ }
120
+ }
121
+ // Fall back to first non-disabled item
122
+ for (const row of rows) {
123
+ if (!disabledKeys().has(row.key)) {
124
+ setFocusedKeyInternal(row.key);
125
+ break;
126
+ }
127
+ }
128
+ } else {
129
+ setFocusedKeyInternal(null);
130
+ }
131
+ }
132
+ }
133
+
134
+ cachedCollection = coll;
135
+ })
136
+ );
137
+
138
+ // Selection methods
139
+ const isSelected = (key: Key): boolean => {
140
+ const keys = selectedKeys();
141
+ if (keys === 'all') return true;
142
+ return keys.has(key);
143
+ };
144
+
145
+ const isDisabled = (key: Key): boolean => {
146
+ return disabledKeys().has(key);
147
+ };
148
+
149
+ const isExpanded = (key: Key): boolean => {
150
+ return expandedKeys().has(key);
151
+ };
152
+
153
+ const updateSelection = (newSelection: 'all' | Set<Key>) => {
154
+ const opts = getOptions();
155
+
156
+ // Controlled mode
157
+ if (opts.selectedKeys !== undefined) {
158
+ opts.onSelectionChange?.(newSelection);
159
+ return;
160
+ }
161
+
162
+ // Uncontrolled mode
163
+ const current = internalSelectedKeys();
164
+ const isDifferent =
165
+ current === 'all' ||
166
+ newSelection === 'all' ||
167
+ current.size !== (newSelection as Set<Key>).size ||
168
+ ![...current].every((k) => (newSelection as Set<Key>).has(k));
169
+
170
+ if (isDifferent) {
171
+ setInternalSelectedKeys(newSelection);
172
+ opts.onSelectionChange?.(newSelection);
173
+ }
174
+ };
175
+
176
+ const toggleSelection = (key: Key) => {
177
+ if (isDisabled(key) && disabledBehavior() === 'all') return;
178
+ if (selectionMode() === 'none') return;
179
+
180
+ const current = selectedKeys();
181
+
182
+ if (selectionMode() === 'single') {
183
+ if (isSelected(key) && !disallowEmptySelection()) {
184
+ updateSelection(new Set());
185
+ } else {
186
+ updateSelection(new Set([key]));
187
+ }
188
+ return;
189
+ }
190
+
191
+ // Multiple selection
192
+ if (current === 'all') {
193
+ // Can't toggle when all selected without knowing all keys
194
+ return;
195
+ }
196
+
197
+ const newSelection = new Set(current);
198
+ if (newSelection.has(key)) {
199
+ if (newSelection.size > 1 || !disallowEmptySelection()) {
200
+ newSelection.delete(key);
201
+ }
202
+ } else {
203
+ newSelection.add(key);
204
+ }
205
+
206
+ updateSelection(newSelection);
207
+ setAnchorKey(key);
208
+ };
209
+
210
+ const replaceSelection = (key: Key) => {
211
+ if (isDisabled(key) && disabledBehavior() === 'all') return;
212
+ if (selectionMode() === 'none') return;
213
+
214
+ updateSelection(new Set([key]));
215
+ setAnchorKey(key);
216
+ };
217
+
218
+ const extendSelection = (toKey: Key) => {
219
+ if (isDisabled(toKey) && disabledBehavior() === 'all') return;
220
+ if (selectionMode() !== 'multiple') {
221
+ replaceSelection(toKey);
222
+ return;
223
+ }
224
+
225
+ const anchor = anchorKey();
226
+ if (!anchor) {
227
+ replaceSelection(toKey);
228
+ return;
229
+ }
230
+
231
+ const coll = collection();
232
+ const rows = coll.rows.filter((r) => r.type === 'item');
233
+ const keys = rows.map((r) => r.key);
234
+ const anchorIndex = keys.indexOf(anchor);
235
+ const toIndex = keys.indexOf(toKey);
236
+
237
+ if (anchorIndex === -1 || toIndex === -1) {
238
+ replaceSelection(toKey);
239
+ return;
240
+ }
241
+
242
+ const start = Math.min(anchorIndex, toIndex);
243
+ const end = Math.max(anchorIndex, toIndex);
244
+ const rangeKeys = keys.slice(start, end + 1).filter((k) => !isDisabled(k));
245
+
246
+ updateSelection(new Set(rangeKeys));
247
+ };
248
+
249
+ const selectAll = () => {
250
+ if (selectionMode() !== 'multiple') return;
251
+ updateSelection('all');
252
+ };
253
+
254
+ const clearSelection = () => {
255
+ if (disallowEmptySelection()) return;
256
+ updateSelection(new Set());
257
+ };
258
+
259
+ const toggleSelectAll = () => {
260
+ if (selectionMode() !== 'multiple') return;
261
+
262
+ if (selectedKeys() === 'all') {
263
+ clearSelection();
264
+ } else {
265
+ selectAll();
266
+ }
267
+ };
268
+
269
+ // Expansion methods
270
+ const updateExpandedKeys = (newKeys: Set<Key>) => {
271
+ const opts = getOptions();
272
+
273
+ // Controlled mode
274
+ if (opts.expandedKeys !== undefined) {
275
+ opts.onExpandedChange?.(newKeys);
276
+ return;
277
+ }
278
+
279
+ // Uncontrolled mode
280
+ setInternalExpandedKeys(newKeys);
281
+ opts.onExpandedChange?.(newKeys);
282
+ };
283
+
284
+ const toggleKey = (key: Key) => {
285
+ const node = collection().getItem(key);
286
+ if (!node || !node.isExpandable) return;
287
+ if (isDisabled(key) && disabledBehavior() === 'all') return;
288
+
289
+ const current = expandedKeys();
290
+ const newKeys = new Set(current);
291
+
292
+ if (newKeys.has(key)) {
293
+ newKeys.delete(key);
294
+ } else {
295
+ newKeys.add(key);
296
+ }
297
+
298
+ updateExpandedKeys(newKeys);
299
+ };
300
+
301
+ const expandKey = (key: Key) => {
302
+ const node = collection().getItem(key);
303
+ if (!node || !node.isExpandable) return;
304
+ if (isDisabled(key) && disabledBehavior() === 'all') return;
305
+
306
+ const current = expandedKeys();
307
+ if (current.has(key)) return;
308
+
309
+ const newKeys = new Set(current);
310
+ newKeys.add(key);
311
+ updateExpandedKeys(newKeys);
312
+ };
313
+
314
+ const collapseKey = (key: Key) => {
315
+ const node = collection().getItem(key);
316
+ if (!node || !node.isExpandable) return;
317
+ if (isDisabled(key) && disabledBehavior() === 'all') return;
318
+
319
+ const current = expandedKeys();
320
+ if (!current.has(key)) return;
321
+
322
+ const newKeys = new Set(current);
323
+ newKeys.delete(key);
324
+ updateExpandedKeys(newKeys);
325
+ };
326
+
327
+ const setExpandedKeys = (keys: Set<Key>) => {
328
+ updateExpandedKeys(keys);
329
+ };
330
+
331
+ return {
332
+ get collection() {
333
+ return collection();
334
+ },
335
+ get disabledKeys() {
336
+ return disabledKeys();
337
+ },
338
+ get expandedKeys() {
339
+ return expandedKeys();
340
+ },
341
+ get isKeyboardNavigationDisabled() {
342
+ return isKeyboardNavigationDisabled();
343
+ },
344
+ get focusedKey() {
345
+ return focusedKey();
346
+ },
347
+ get childFocusStrategy() {
348
+ return childFocusStrategy();
349
+ },
350
+ get isFocused() {
351
+ return isFocused();
352
+ },
353
+ get selectionMode() {
354
+ return selectionMode();
355
+ },
356
+ get selectedKeys() {
357
+ return selectedKeys();
358
+ },
359
+ isSelected,
360
+ isDisabled,
361
+ isExpanded,
362
+ setFocusedKey,
363
+ setFocused: setIsFocused,
364
+ toggleSelection,
365
+ replaceSelection,
366
+ extendSelection,
367
+ selectAll,
368
+ clearSelection,
369
+ toggleSelectAll,
370
+ toggleKey,
371
+ expandKey,
372
+ collapseKey,
373
+ setExpandedKeys,
374
+ setKeyboardNavigationDisabled,
375
+ };
376
+ }
377
+
378
+ // Helper functions
379
+ function getInitialSelection(defaultKeys?: 'all' | Iterable<Key>): 'all' | Set<Key> {
380
+ if (defaultKeys === undefined) return new Set();
381
+ return normalizeSelection(defaultKeys);
382
+ }
383
+
384
+ function normalizeSelection(keys: 'all' | Iterable<Key>): 'all' | Set<Key> {
385
+ if (keys === 'all') return 'all';
386
+ return new Set(keys);
387
+ }
388
+
389
+ function getInitialExpandedKeys(defaultKeys?: Iterable<Key>): Set<Key> {
390
+ if (defaultKeys === undefined) return new Set();
391
+ return new Set(defaultKeys);
392
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Tree state management exports.
3
+ */
4
+ export { createTreeState } from './createTreeState';
5
+ export { TreeCollection, createTreeCollection } from './TreeCollection';
6
+ export type { TreeState, TreeStateOptions, TreeCollection as TreeCollectionInterface, TreeNode, TreeItemData, } from './types';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxE,YAAY,EACV,SAAS,EACT,gBAAgB,EAChB,cAAc,IAAI,uBAAuB,EACzC,QAAQ,EACR,YAAY,GACb,MAAM,SAAS,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Tree state management exports.
3
+ */
4
+
5
+ export { createTreeState } from './createTreeState';
6
+ export { TreeCollection, createTreeCollection } from './TreeCollection';
7
+ export type {
8
+ TreeState,
9
+ TreeStateOptions,
10
+ TreeCollection as TreeCollectionInterface,
11
+ TreeNode,
12
+ TreeItemData,
13
+ } from './types';