@proyecto-viviana/solidaria-components 0.2.5 → 0.3.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 (225) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +39 -272
  3. package/dist/ActionBar.d.ts +79 -0
  4. package/dist/ActionBar.d.ts.map +1 -0
  5. package/dist/ActionGroup.d.ts +74 -0
  6. package/dist/ActionGroup.d.ts.map +1 -0
  7. package/dist/Alert.d.ts +70 -0
  8. package/dist/Alert.d.ts.map +1 -0
  9. package/dist/Autocomplete.d.ts +5 -5
  10. package/dist/Autocomplete.d.ts.map +1 -1
  11. package/dist/Breadcrumbs.d.ts +27 -8
  12. package/dist/Breadcrumbs.d.ts.map +1 -1
  13. package/dist/Button.d.ts +28 -5
  14. package/dist/Button.d.ts.map +1 -1
  15. package/dist/Calendar.d.ts +51 -7
  16. package/dist/Calendar.d.ts.map +1 -1
  17. package/dist/Checkbox.d.ts +33 -8
  18. package/dist/Checkbox.d.ts.map +1 -1
  19. package/dist/Collection.d.ts +130 -0
  20. package/dist/Collection.d.ts.map +1 -0
  21. package/dist/Color.d.ts +210 -9
  22. package/dist/Color.d.ts.map +1 -1
  23. package/dist/ColorEditor.d.ts +42 -0
  24. package/dist/ColorEditor.d.ts.map +1 -0
  25. package/dist/ComboBox.d.ts +146 -16
  26. package/dist/ComboBox.d.ts.map +1 -1
  27. package/dist/ContextualHelpTrigger.d.ts +40 -0
  28. package/dist/ContextualHelpTrigger.d.ts.map +1 -0
  29. package/dist/DateField.d.ts +35 -8
  30. package/dist/DateField.d.ts.map +1 -1
  31. package/dist/DatePicker.d.ts +101 -5
  32. package/dist/DatePicker.d.ts.map +1 -1
  33. package/dist/DateRangePickerContext.d.ts +30 -0
  34. package/dist/DateRangePickerContext.d.ts.map +1 -0
  35. package/dist/Dialog.d.ts +5 -5
  36. package/dist/Dialog.d.ts.map +1 -1
  37. package/dist/Disclosure.d.ts +25 -5
  38. package/dist/Disclosure.d.ts.map +1 -1
  39. package/dist/DragAndDrop.d.ts +80 -0
  40. package/dist/DragAndDrop.d.ts.map +1 -0
  41. package/dist/DragPreview.d.ts +14 -0
  42. package/dist/DragPreview.d.ts.map +1 -0
  43. package/dist/DropZone.d.ts +27 -0
  44. package/dist/DropZone.d.ts.map +1 -0
  45. package/dist/FieldError.d.ts +27 -0
  46. package/dist/FieldError.d.ts.map +1 -0
  47. package/dist/FileTrigger.d.ts +26 -0
  48. package/dist/FileTrigger.d.ts.map +1 -0
  49. package/dist/Focusable.d.ts +27 -0
  50. package/dist/Focusable.d.ts.map +1 -0
  51. package/dist/Form.d.ts +41 -0
  52. package/dist/Form.d.ts.map +1 -0
  53. package/dist/GridList.d.ts +69 -10
  54. package/dist/GridList.d.ts.map +1 -1
  55. package/dist/HiddenDateInput.d.ts +26 -0
  56. package/dist/HiddenDateInput.d.ts.map +1 -0
  57. package/dist/HiddenTimeInput.d.ts +25 -0
  58. package/dist/HiddenTimeInput.d.ts.map +1 -0
  59. package/dist/Icon.d.ts +57 -0
  60. package/dist/Icon.d.ts.map +1 -0
  61. package/dist/Keyboard.d.ts +13 -0
  62. package/dist/Keyboard.d.ts.map +1 -0
  63. package/dist/Landmark.d.ts +3 -3
  64. package/dist/Landmark.d.ts.map +1 -1
  65. package/dist/Link.d.ts +10 -4
  66. package/dist/Link.d.ts.map +1 -1
  67. package/dist/ListBox.d.ts +73 -11
  68. package/dist/ListBox.d.ts.map +1 -1
  69. package/dist/ListDropTargetDelegate.d.ts +38 -0
  70. package/dist/ListDropTargetDelegate.d.ts.map +1 -0
  71. package/dist/Menu.d.ts +79 -10
  72. package/dist/Menu.d.ts.map +1 -1
  73. package/dist/Meter.d.ts +4 -4
  74. package/dist/Meter.d.ts.map +1 -1
  75. package/dist/Modal.d.ts +6 -4
  76. package/dist/Modal.d.ts.map +1 -1
  77. package/dist/NumberField.d.ts +10 -12
  78. package/dist/NumberField.d.ts.map +1 -1
  79. package/dist/Popover.d.ts +32 -7
  80. package/dist/Popover.d.ts.map +1 -1
  81. package/dist/Pressable.d.ts +27 -0
  82. package/dist/Pressable.d.ts.map +1 -0
  83. package/dist/ProgressBar.d.ts +6 -4
  84. package/dist/ProgressBar.d.ts.map +1 -1
  85. package/dist/RadioGroup.d.ts +43 -9
  86. package/dist/RadioGroup.d.ts.map +1 -1
  87. package/dist/RangeCalendar.d.ts +39 -7
  88. package/dist/RangeCalendar.d.ts.map +1 -1
  89. package/dist/RouterProvider.d.ts +75 -0
  90. package/dist/RouterProvider.d.ts.map +1 -0
  91. package/dist/SearchField.d.ts +23 -21
  92. package/dist/SearchField.d.ts.map +1 -1
  93. package/dist/Select.d.ts +48 -7
  94. package/dist/Select.d.ts.map +1 -1
  95. package/dist/SelectionIndicator.d.ts +30 -0
  96. package/dist/SelectionIndicator.d.ts.map +1 -0
  97. package/dist/Separator.d.ts +9 -3
  98. package/dist/Separator.d.ts.map +1 -1
  99. package/dist/SharedElementTransition.d.ts +41 -0
  100. package/dist/SharedElementTransition.d.ts.map +1 -0
  101. package/dist/Slider.d.ts +15 -8
  102. package/dist/Slider.d.ts.map +1 -1
  103. package/dist/StepList.d.ts +90 -0
  104. package/dist/StepList.d.ts.map +1 -0
  105. package/dist/Switch.d.ts +11 -5
  106. package/dist/Switch.d.ts.map +1 -1
  107. package/dist/Table.d.ts +222 -19
  108. package/dist/Table.d.ts.map +1 -1
  109. package/dist/Tabs.d.ts +47 -10
  110. package/dist/Tabs.d.ts.map +1 -1
  111. package/dist/TagGroup.d.ts +22 -10
  112. package/dist/TagGroup.d.ts.map +1 -1
  113. package/dist/Text.d.ts +10 -0
  114. package/dist/Text.d.ts.map +1 -0
  115. package/dist/TextField.d.ts +19 -11
  116. package/dist/TextField.d.ts.map +1 -1
  117. package/dist/TimeField.d.ts +32 -7
  118. package/dist/TimeField.d.ts.map +1 -1
  119. package/dist/Toast.d.ts +29 -14
  120. package/dist/Toast.d.ts.map +1 -1
  121. package/dist/ToggleButton.d.ts +36 -0
  122. package/dist/ToggleButton.d.ts.map +1 -0
  123. package/dist/ToggleButtonGroup.d.ts +33 -0
  124. package/dist/ToggleButtonGroup.d.ts.map +1 -0
  125. package/dist/Toolbar.d.ts +7 -3
  126. package/dist/Toolbar.d.ts.map +1 -1
  127. package/dist/Tooltip.d.ts +58 -7
  128. package/dist/Tooltip.d.ts.map +1 -1
  129. package/dist/Tree.d.ts +102 -11
  130. package/dist/Tree.d.ts.map +1 -1
  131. package/dist/Virtualizer.d.ts +61 -0
  132. package/dist/Virtualizer.d.ts.map +1 -0
  133. package/dist/VirtualizerLayouts.d.ts +82 -0
  134. package/dist/VirtualizerLayouts.d.ts.map +1 -0
  135. package/dist/VisuallyHidden.d.ts +4 -2
  136. package/dist/VisuallyHidden.d.ts.map +1 -1
  137. package/dist/contexts.d.ts +6 -1
  138. package/dist/contexts.d.ts.map +1 -1
  139. package/dist/index.d.ts +73 -39
  140. package/dist/index.d.ts.map +1 -1
  141. package/dist/index.js +23342 -10644
  142. package/dist/index.js.map +1 -7
  143. package/dist/index.jsx +18110 -0
  144. package/dist/index.jsx.map +1 -0
  145. package/dist/useDragAndDrop.d.ts +93 -0
  146. package/dist/useDragAndDrop.d.ts.map +1 -0
  147. package/dist/utils.d.ts +8 -2
  148. package/dist/utils.d.ts.map +1 -1
  149. package/dist/virtualizer/Layout.d.ts +79 -0
  150. package/dist/virtualizer/Layout.d.ts.map +1 -0
  151. package/package.json +33 -32
  152. package/src/ActionBar.tsx +251 -0
  153. package/src/ActionGroup.tsx +277 -0
  154. package/src/Alert.tsx +152 -0
  155. package/src/Autocomplete.tsx +39 -44
  156. package/src/Breadcrumbs.tsx +227 -72
  157. package/src/Button.tsx +315 -74
  158. package/src/Calendar.tsx +347 -141
  159. package/src/Checkbox.tsx +414 -123
  160. package/src/Collection.tsx +350 -0
  161. package/src/Color.tsx +1325 -284
  162. package/src/ColorEditor.tsx +213 -0
  163. package/src/ComboBox.tsx +644 -245
  164. package/src/ContextualHelpTrigger.tsx +195 -0
  165. package/src/DateField.tsx +274 -106
  166. package/src/DatePicker.tsx +892 -111
  167. package/src/DateRangePickerContext.tsx +44 -0
  168. package/src/Dialog.tsx +173 -104
  169. package/src/Disclosure.tsx +158 -105
  170. package/src/DragAndDrop.tsx +340 -0
  171. package/src/DragPreview.tsx +47 -0
  172. package/src/DropZone.tsx +233 -0
  173. package/src/FieldError.tsx +89 -0
  174. package/src/FileTrigger.tsx +83 -0
  175. package/src/Focusable.tsx +103 -0
  176. package/src/Form.tsx +140 -0
  177. package/src/GridList.tsx +542 -128
  178. package/src/HiddenDateInput.tsx +153 -0
  179. package/src/HiddenTimeInput.tsx +133 -0
  180. package/src/Icon.tsx +133 -0
  181. package/src/Keyboard.tsx +26 -0
  182. package/src/Landmark.tsx +37 -63
  183. package/src/Link.tsx +132 -69
  184. package/src/ListBox.tsx +656 -106
  185. package/src/ListDropTargetDelegate.ts +283 -0
  186. package/src/Menu.tsx +1234 -132
  187. package/src/Meter.tsx +44 -58
  188. package/src/Modal.tsx +262 -166
  189. package/src/NumberField.tsx +267 -151
  190. package/src/Popover.tsx +452 -343
  191. package/src/Pressable.tsx +108 -0
  192. package/src/ProgressBar.tsx +54 -59
  193. package/src/RadioGroup.tsx +533 -121
  194. package/src/RangeCalendar.tsx +249 -150
  195. package/src/RouterProvider.tsx +223 -0
  196. package/src/SearchField.tsx +460 -133
  197. package/src/Select.tsx +804 -233
  198. package/src/SelectionIndicator.tsx +108 -0
  199. package/src/Separator.tsx +47 -49
  200. package/src/SharedElementTransition.tsx +264 -0
  201. package/src/Slider.tsx +148 -98
  202. package/src/StepList.tsx +272 -0
  203. package/src/Switch.tsx +93 -46
  204. package/src/Table.tsx +1551 -225
  205. package/src/Tabs.tsx +377 -123
  206. package/src/TagGroup.tsx +233 -135
  207. package/src/Text.tsx +18 -0
  208. package/src/TextField.tsx +413 -86
  209. package/src/TimeField.tsx +232 -222
  210. package/src/Toast.tsx +306 -160
  211. package/src/ToggleButton.tsx +169 -0
  212. package/src/ToggleButtonGroup.tsx +141 -0
  213. package/src/Toolbar.tsx +61 -70
  214. package/src/Tooltip.tsx +473 -116
  215. package/src/Tree.tsx +1514 -175
  216. package/src/Virtualizer.tsx +730 -0
  217. package/src/VirtualizerLayouts.ts +280 -0
  218. package/src/VisuallyHidden.tsx +32 -38
  219. package/src/contexts.ts +29 -36
  220. package/src/index.ts +972 -620
  221. package/src/useDragAndDrop.ts +367 -0
  222. package/src/utils.tsx +69 -50
  223. package/src/virtualizer/Layout.ts +192 -0
  224. package/dist/index.ssr.js +0 -9785
  225. package/dist/index.ssr.js.map +0 -7
@@ -0,0 +1,367 @@
1
+ /**
2
+ * Drag and drop compatibility hook for collection components.
3
+ *
4
+ * Mirrors RAC's `useDragAndDrop` shape while delegating to Solid
5
+ * state and aria primitives.
6
+ */
7
+
8
+ import type { Accessor, JSX } from "solid-js";
9
+ import { DragPreview } from "./DragPreview";
10
+ import { ListDropTargetDelegate } from "./ListDropTargetDelegate";
11
+ import {
12
+ createDraggableCollection,
13
+ createDraggableItem,
14
+ createDroppableCollection,
15
+ createDroppableItem,
16
+ getGlobalDraggingCollectionRef,
17
+ getGlobalDraggingKeys,
18
+ type DraggableCollectionOptions,
19
+ type DraggableCollectionAria,
20
+ type DraggableItemOptions,
21
+ type DraggableItemAria,
22
+ type DroppableCollectionOptions,
23
+ type DroppableCollectionAria,
24
+ type DroppableItemOptions,
25
+ type DroppableItemAria,
26
+ type DropTargetDelegate as AriaDropTargetDelegate,
27
+ } from "@proyecto-viviana/solidaria";
28
+ import {
29
+ createDraggableCollectionState,
30
+ createDroppableCollectionState,
31
+ type DragItem,
32
+ type DragPreviewRenderer,
33
+ type DraggableCollectionProps,
34
+ type DraggableCollectionState,
35
+ type DraggableCollectionStateOptions,
36
+ type DropTarget,
37
+ type DroppableCollectionProps,
38
+ type DroppableCollectionState,
39
+ type DroppableCollectionStateOptions,
40
+ } from "@proyecto-viviana/solid-stately";
41
+
42
+ interface DraggableCollectionStateOpts<T = object> extends Omit<
43
+ DraggableCollectionStateOptions<T>,
44
+ "getItems"
45
+ > {
46
+ items?: T[];
47
+ }
48
+
49
+ interface DragHooks<T = object> {
50
+ useDraggableCollectionState?: (
51
+ props: DraggableCollectionStateOpts<T>,
52
+ ) => DraggableCollectionState;
53
+ useDraggableCollection?: (
54
+ props: Omit<DraggableCollectionOptions, "ref">,
55
+ state: DraggableCollectionState,
56
+ ref: Accessor<HTMLElement | null>,
57
+ ) => DraggableCollectionAria;
58
+ useDraggableItem?: (
59
+ props: DraggableItemOptions,
60
+ state: DraggableCollectionState,
61
+ ) => DraggableItemAria;
62
+ DragPreview?: typeof DragPreview;
63
+ renderDragPreview?: DragAndDropOptions<T>["renderDragPreview"];
64
+ isVirtualDragging?: () => boolean;
65
+ }
66
+
67
+ interface DropHooks {
68
+ useDroppableCollectionState?: (
69
+ props: DroppableCollectionStateOptions,
70
+ ) => DroppableCollectionState;
71
+ useDroppableCollection?: (
72
+ props: Omit<DroppableCollectionOptions, "ref">,
73
+ state: DroppableCollectionState,
74
+ ref: Accessor<HTMLElement | null>,
75
+ ) => DroppableCollectionAria;
76
+ useDroppableItem?: (
77
+ options: Omit<DroppableItemOptions, "ref">,
78
+ state: DroppableCollectionState,
79
+ ref: Accessor<HTMLElement | null>,
80
+ ) => DroppableItemAria;
81
+ useDropIndicator?: (
82
+ props: { target: DropTarget },
83
+ state: DroppableCollectionState,
84
+ ref: Accessor<HTMLElement | null>,
85
+ ) => {
86
+ dropIndicatorProps: JSX.HTMLAttributes<HTMLElement>;
87
+ isDropTarget: boolean;
88
+ isHidden: boolean;
89
+ };
90
+ renderDropIndicator?: (target: DropTarget) => JSX.Element;
91
+ dropTargetDelegate?: AriaDropTargetDelegate;
92
+ ListDropTargetDelegate?: typeof ListDropTargetDelegate;
93
+ }
94
+
95
+ export type DragAndDropHooks<T = object> = DragHooks<T> & DropHooks;
96
+
97
+ export interface DragAndDrop<T = object> {
98
+ /** Drag and drop hooks for the collection element. */
99
+ dragAndDropHooks: DragAndDropHooks<T>;
100
+ }
101
+
102
+ export interface DragAndDropOptions<T = object>
103
+ extends Partial<Omit<DraggableCollectionProps<T>, "preview">>, Partial<DroppableCollectionProps> {
104
+ /**
105
+ * Optional keyboard delegate forwarded to the collection droppable hook.
106
+ */
107
+ keyboardDelegate?: DroppableCollectionOptions["keyboardDelegate"];
108
+ /**
109
+ * Optional keydown handler composed with collection droppable keyboard behavior.
110
+ */
111
+ onKeyDown?: DroppableCollectionOptions["onKeyDown"];
112
+ /**
113
+ * A function that returns the items being dragged.
114
+ * If omitted, draggable hooks are not added.
115
+ */
116
+ getItems?: (keys: Set<string | number>, items: T[]) => DragItem[];
117
+ /**
118
+ * Optional custom drag preview renderer.
119
+ */
120
+ renderDragPreview?: (
121
+ items: DragItem[],
122
+ ) => JSX.Element | { element: JSX.Element; x: number; y: number };
123
+ /**
124
+ * Optional drop indicator renderer for collection components.
125
+ */
126
+ renderDropIndicator?: (target: DropTarget) => JSX.Element;
127
+ /**
128
+ * Optional custom drop target delegate.
129
+ */
130
+ dropTargetDelegate?: AriaDropTargetDelegate;
131
+ /**
132
+ * Optional drag preview ref.
133
+ */
134
+ preview?: { current: DragPreviewRenderer | null };
135
+ /**
136
+ * Optional item snapshot used by draggable state `getItems`.
137
+ */
138
+ items?: T[];
139
+ /**
140
+ * Disable both drag and drop behavior.
141
+ */
142
+ isDisabled?: boolean;
143
+ }
144
+
145
+ /**
146
+ * Provides hooks to enable drag-and-drop behavior for collection components.
147
+ */
148
+ export function useDragAndDrop<T = object>(options: DragAndDropOptions<T> = {}): DragAndDrop<T> {
149
+ const {
150
+ getItems,
151
+ onDrop,
152
+ onInsert,
153
+ onItemDrop,
154
+ onReorder,
155
+ onMove,
156
+ onRootDrop,
157
+ renderDragPreview,
158
+ renderDropIndicator,
159
+ dropTargetDelegate,
160
+ } = options;
161
+
162
+ const isDraggable = typeof getItems === "function";
163
+ const isDroppable = Boolean(
164
+ onDrop || onInsert || onItemDrop || onReorder || onMove || onRootDrop,
165
+ );
166
+
167
+ const hooks: DragAndDropHooks<T> = {};
168
+ const hasDom = typeof HTMLElement !== "undefined";
169
+ const isElementNode = (value: unknown): value is HTMLElement => {
170
+ if (!value) return false;
171
+ if (hasDom && value instanceof HTMLElement) return true;
172
+ return typeof value === "object" && (value as { nodeType?: number }).nodeType === 1;
173
+ };
174
+ const resolvedPreview =
175
+ options.preview ??
176
+ (renderDragPreview
177
+ ? {
178
+ current: (
179
+ items: DragItem[],
180
+ callback: (node: HTMLElement | null, x?: number, y?: number) => void,
181
+ ) => {
182
+ const rendered = renderDragPreview(items);
183
+ if (!rendered) {
184
+ callback(null);
185
+ return;
186
+ }
187
+ if (typeof rendered === "object" && rendered !== null && "element" in rendered) {
188
+ const previewValue = rendered as { element: unknown; x?: number; y?: number };
189
+ callback(
190
+ isElementNode(previewValue.element) ? previewValue.element : null,
191
+ previewValue.x,
192
+ previewValue.y,
193
+ );
194
+ return;
195
+ }
196
+ callback(isElementNode(rendered) ? rendered : null);
197
+ },
198
+ }
199
+ : undefined);
200
+
201
+ if (isDraggable && getItems) {
202
+ hooks.useDraggableCollectionState = (props: DraggableCollectionStateOpts<T>) => {
203
+ return createDraggableCollectionState<T>(() => ({
204
+ onDragStart: options.onDragStart ?? props.onDragStart,
205
+ onDragMove: options.onDragMove ?? props.onDragMove,
206
+ onDragEnd: options.onDragEnd ?? props.onDragEnd,
207
+ getAllowedDropOperations:
208
+ options.getAllowedDropOperations ?? props.getAllowedDropOperations,
209
+ isDisabled: options.isDisabled ?? props.isDisabled,
210
+ preview: resolvedPreview ?? props.preview,
211
+ getItems: (keys) => {
212
+ const sourceItems = props.items ?? options.items ?? [];
213
+ return getItems(keys, sourceItems);
214
+ },
215
+ }));
216
+ };
217
+ hooks.useDraggableCollection = (
218
+ props: Omit<DraggableCollectionOptions, "ref">,
219
+ state: DraggableCollectionState,
220
+ ref: Accessor<HTMLElement | null>,
221
+ ) => createDraggableCollection({ ...props, ref }, state);
222
+ hooks.useDraggableItem = (props, state) => createDraggableItem(() => props, state);
223
+ hooks.DragPreview = DragPreview;
224
+ hooks.renderDragPreview = renderDragPreview;
225
+ hooks.isVirtualDragging = () =>
226
+ getGlobalDraggingCollectionRef() != null || getGlobalDraggingKeys().size > 0;
227
+ }
228
+
229
+ if (isDroppable) {
230
+ hooks.useDroppableCollectionState = (props: DroppableCollectionStateOptions) => {
231
+ return createDroppableCollectionState(() => ({
232
+ acceptedDragTypes: options.acceptedDragTypes ?? props.acceptedDragTypes,
233
+ getDropOperation: options.getDropOperation ?? props.getDropOperation,
234
+ onDropEnter: options.onDropEnter ?? props.onDropEnter,
235
+ onDropActivate: options.onDropActivate ?? props.onDropActivate,
236
+ onDropExit: options.onDropExit ?? props.onDropExit,
237
+ onDrop: options.onDrop ?? props.onDrop,
238
+ onInsert: options.onInsert ?? props.onInsert,
239
+ onRootDrop: options.onRootDrop ?? props.onRootDrop,
240
+ onItemDrop: options.onItemDrop ?? props.onItemDrop,
241
+ onReorder: options.onReorder ?? props.onReorder,
242
+ onMove: options.onMove ?? props.onMove,
243
+ shouldAcceptItemDrop: options.shouldAcceptItemDrop ?? props.shouldAcceptItemDrop,
244
+ isDisabled: options.isDisabled ?? props.isDisabled,
245
+ }));
246
+ };
247
+ hooks.useDroppableCollection = (
248
+ props: Omit<DroppableCollectionOptions, "ref">,
249
+ state: DroppableCollectionState,
250
+ ref: Accessor<HTMLElement | null>,
251
+ ) => {
252
+ const acceptedDragTypes = options.acceptedDragTypes ?? props.acceptedDragTypes;
253
+ const normalizedAcceptedDragTypes =
254
+ acceptedDragTypes === "all"
255
+ ? "all"
256
+ : acceptedDragTypes?.filter(
257
+ (type): type is string | symbol =>
258
+ typeof type === "string" || typeof type === "symbol",
259
+ );
260
+ return createDroppableCollection(
261
+ () => ({
262
+ ref,
263
+ dropTargetDelegate: options.dropTargetDelegate ?? props.dropTargetDelegate,
264
+ keyboardDelegate: options.keyboardDelegate ?? props.keyboardDelegate,
265
+ onKeyDown: options.onKeyDown ?? props.onKeyDown,
266
+ acceptedDragTypes: normalizedAcceptedDragTypes,
267
+ isDisabled: options.isDisabled ?? props.isDisabled,
268
+ onDropActivate: (e) => {
269
+ (options.onDropActivate ?? props.onDropActivate)?.({
270
+ type: "dropactivate",
271
+ target: e.target,
272
+ x: e.x,
273
+ y: e.y,
274
+ });
275
+ },
276
+ onDrop: (e) => {
277
+ (options.onDrop ?? props.onDrop)?.({
278
+ type: "drop",
279
+ target: e.target,
280
+ x: e.x,
281
+ y: e.y,
282
+ items: e.items,
283
+ dropOperation: e.dropOperation,
284
+ });
285
+ },
286
+ onRootDrop: options.onRootDrop ?? props.onRootDrop,
287
+ onItemDrop: (e) => {
288
+ if (e.target.type === "item") {
289
+ (options.onItemDrop ?? props.onItemDrop)?.({
290
+ items: e.items,
291
+ target: e.target,
292
+ dropOperation: e.dropOperation,
293
+ isInternal: e.isInternal,
294
+ });
295
+ }
296
+ },
297
+ onInsert: (e) => {
298
+ if (e.target.type === "item") {
299
+ (options.onInsert ?? props.onInsert)?.({
300
+ items: e.items,
301
+ target: e.target,
302
+ dropOperation: e.dropOperation,
303
+ });
304
+ }
305
+ },
306
+ onReorder: (e) => {
307
+ if (e.target.type === "item") {
308
+ (options.onReorder ?? props.onReorder)?.({
309
+ keys: e.keys,
310
+ target: e.target,
311
+ dropOperation: e.dropOperation,
312
+ });
313
+ }
314
+ },
315
+ onMove: (e) => {
316
+ if (e.target.type === "item") {
317
+ (options.onMove ?? props.onMove)?.({
318
+ keys: e.keys,
319
+ target: e.target,
320
+ dropOperation: e.dropOperation,
321
+ });
322
+ }
323
+ },
324
+ }),
325
+ state,
326
+ );
327
+ };
328
+ hooks.useDroppableItem = (
329
+ props: Omit<DroppableItemOptions, "ref">,
330
+ state: DroppableCollectionState,
331
+ ref: Accessor<HTMLElement | null>,
332
+ ) => createDroppableItem(() => ({ ...props, ref }), state);
333
+ hooks.useDropIndicator = (
334
+ props: { target: DropTarget },
335
+ state: DroppableCollectionState,
336
+ _ref: Accessor<HTMLElement | null>,
337
+ ) => {
338
+ const target = props.target;
339
+ const activeTarget = state.target;
340
+ const isDropTarget =
341
+ activeTarget?.type === target.type &&
342
+ (target.type === "root" ||
343
+ (activeTarget.type === "item" &&
344
+ target.type === "item" &&
345
+ activeTarget.key === target.key &&
346
+ activeTarget.dropPosition === target.dropPosition));
347
+ return {
348
+ dropIndicatorProps: {
349
+ role: "option",
350
+ "aria-disabled": true,
351
+ "aria-hidden": isDropTarget ? undefined : "true",
352
+ tabIndex: -1,
353
+ "data-drop-target": isDropTarget ? "" : undefined,
354
+ },
355
+ isDropTarget,
356
+ isHidden: !isDropTarget,
357
+ };
358
+ };
359
+ hooks.renderDropIndicator = renderDropIndicator;
360
+ hooks.dropTargetDelegate = dropTargetDelegate;
361
+ hooks.ListDropTargetDelegate = ListDropTargetDelegate;
362
+ }
363
+
364
+ return {
365
+ dragAndDropHooks: hooks,
366
+ };
367
+ }
package/src/utils.tsx CHANGED
@@ -7,18 +7,15 @@ import {
7
7
  type JSX,
8
8
  type Accessor,
9
9
  type FlowComponent,
10
+ type ParentComponent,
10
11
  createContext,
11
12
  useContext,
12
13
  createMemo,
13
14
  createSignal,
14
15
  onMount,
15
16
  Show,
16
- } from 'solid-js';
17
- import { isServer } from 'solid-js/web';
18
-
19
- // ============================================
20
- // TYPES
21
- // ============================================
17
+ } from "solid-js";
18
+ import { isServer } from "solid-js/web";
22
19
 
23
20
  /**
24
21
  * Render props pattern - children can be a function that receives state
@@ -55,9 +52,7 @@ export interface SlotProps {
55
52
  slot?: string;
56
53
  }
57
54
 
58
- // ============================================
59
- // RENDER PROPS
60
- // ============================================
55
+ export const DEFAULT_SLOT = "default";
61
56
 
62
57
  /**
63
58
  * Return type for useRenderProps
@@ -95,44 +90,54 @@ export interface RenderPropsResult<T> {
95
90
  */
96
91
  export function useRenderProps<T extends object>(
97
92
  props: RenderPropsBase<T> & { defaultClassName?: string },
98
- values: Accessor<T>
93
+ values: Accessor<T>,
99
94
  ): RenderPropsResult<T> {
100
- const { children, class: className, style, defaultClassName = '' } = props;
95
+ // Don't destructure children access lazily to avoid eager evaluation
96
+ // that would trigger child component creation before context providers mount.
97
+ const { class: className, style, defaultClassName = "" } = props;
101
98
 
102
99
  // Compute class and style eagerly (they don't depend on context)
103
100
  const computedClass = createMemo(() => {
104
101
  const currentValues = values();
105
- return typeof className === 'function'
102
+ return typeof className === "function"
106
103
  ? className(currentValues)
107
- : className ?? defaultClassName;
104
+ : (className ?? defaultClassName);
108
105
  });
109
106
 
110
107
  const computedStyle = createMemo(() => {
111
108
  const currentValues = values();
112
- return typeof style === 'function'
113
- ? style(currentValues)
114
- : style;
109
+ return typeof style === "function" ? style(currentValues) : style;
115
110
  });
116
111
 
117
112
  // Return object with explicit function for rendering children
118
- // This avoids the getter pattern that causes SSR issues
113
+ // Children are accessed lazily during render (inside context providers)
119
114
  return {
120
115
  class: computedClass,
121
116
  style: computedStyle,
122
117
  renderChildren: () => {
123
118
  const currentValues = values();
124
- return typeof children === 'function'
125
- ? children(currentValues)
126
- : children;
119
+ const children = props.children;
120
+ return typeof children === "function" ? children(currentValues) : children;
121
+ },
122
+ get children() {
123
+ return props.children;
127
124
  },
128
- children,
129
125
  values,
130
126
  };
131
127
  }
132
128
 
133
- // ============================================
134
- // CONTEXT UTILITIES
135
- // ============================================
129
+ export function composeRenderProps<T extends object>(
130
+ base: RenderPropsBase<T> | undefined,
131
+ override: RenderPropsBase<T> | undefined,
132
+ ): RenderPropsBase<T> {
133
+ if (!base) return override ?? {};
134
+ if (!override) return base;
135
+ return {
136
+ children: override.children ?? base.children,
137
+ class: override.class ?? base.class,
138
+ style: override.style ?? base.style,
139
+ };
140
+ }
136
141
 
137
142
  /**
138
143
  * Context value that can be null or the actual value
@@ -149,32 +154,45 @@ export function createSlottedContext<T>() {
149
154
  /**
150
155
  * Use context with null check
151
156
  */
152
- export function useSlottedContext<T>(context: ReturnType<typeof createContext<T | null>>): T | null {
157
+ export function useSlottedContext<T>(
158
+ context: ReturnType<typeof createContext<T | null>>,
159
+ ): T | null {
153
160
  return useContext(context);
154
161
  }
155
162
 
156
- // ============================================
157
- // DATA ATTRIBUTES
158
- // ============================================
163
+ export function useContextProps<TProps extends object, TRef>(
164
+ props: TProps,
165
+ ref: TRef,
166
+ context?: ContextValue<Partial<TProps>>,
167
+ ): [TProps, TRef] {
168
+ if (!context) return [props, ref];
169
+ return [{ ...(context as TProps), ...props }, ref];
170
+ }
171
+
172
+ export const Provider: ParentComponent<{
173
+ values: Array<[ReturnType<typeof createContext<unknown>>, unknown]>;
174
+ }> = (props) => {
175
+ return props.children;
176
+ };
159
177
 
160
178
  /**
161
179
  * Converts boolean state values to data attributes
162
180
  */
163
- export function dataAttr(value: boolean | undefined): '' | undefined {
164
- return value ? '' : undefined;
181
+ export function dataAttr(value: boolean | undefined): "" | undefined {
182
+ return value ? "" : undefined;
165
183
  }
166
184
 
167
185
  /**
168
186
  * Creates data attributes from render props
169
187
  */
170
188
  export function createDataAttributes<T extends Record<string, boolean | string | undefined>>(
171
- values: T
189
+ values: T,
172
190
  ): Record<string, string | undefined> {
173
191
  const result: Record<string, string | undefined> = {};
174
192
 
175
193
  for (const [key, value] of Object.entries(values)) {
176
- if (typeof value === 'boolean') {
177
- result[`data-${camelToKebab(key)}`] = value ? '' : undefined;
194
+ if (typeof value === "boolean") {
195
+ result[`data-${camelToKebab(key)}`] = value ? "" : undefined;
178
196
  } else if (value !== undefined) {
179
197
  result[`data-${camelToKebab(key)}`] = value;
180
198
  }
@@ -184,13 +202,9 @@ export function createDataAttributes<T extends Record<string, boolean | string |
184
202
  }
185
203
 
186
204
  function camelToKebab(str: string): string {
187
- return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
205
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
188
206
  }
189
207
 
190
- // ============================================
191
- // PROPS UTILITIES
192
- // ============================================
193
-
194
208
  /**
195
209
  * Remove data attributes from props (for internal use)
196
210
  */
@@ -198,7 +212,7 @@ export function removeDataAttributes<T extends Record<string, unknown>>(props: T
198
212
  const result: Record<string, unknown> = {};
199
213
 
200
214
  for (const [key, value] of Object.entries(props)) {
201
- if (!key.startsWith('data-')) {
215
+ if (!key.startsWith("data-")) {
202
216
  result[key] = value;
203
217
  }
204
218
  }
@@ -215,14 +229,25 @@ export function removeDataAttributes<T extends Record<string, unknown>>(props: T
215
229
  */
216
230
  export function filterDOMProps<R extends object = Record<string, unknown>>(
217
231
  props: object,
218
- options: { global?: boolean } = {}
232
+ options: { global?: boolean } = {},
219
233
  ): R {
220
234
  const { global = false } = options;
221
235
  const result: Record<string, unknown> = {};
222
236
 
223
237
  const globalAttrs = new Set([
224
- 'id', 'class', 'style', 'tabIndex', 'role', 'title', 'lang', 'dir',
225
- 'hidden', 'draggable', 'accessKey', 'contentEditable', 'spellcheck',
238
+ "id",
239
+ "class",
240
+ "style",
241
+ "tabIndex",
242
+ "role",
243
+ "title",
244
+ "lang",
245
+ "dir",
246
+ "hidden",
247
+ "draggable",
248
+ "accessKey",
249
+ "contentEditable",
250
+ "spellcheck",
226
251
  ]);
227
252
 
228
253
  const ariaAttrs = /^aria-/;
@@ -232,12 +257,10 @@ export function filterDOMProps<R extends object = Record<string, unknown>>(
232
257
  for (const key in props) {
233
258
  if (
234
259
  Object.prototype.hasOwnProperty.call(props, key) &&
235
- (
236
- (global && globalAttrs.has(key)) ||
260
+ ((global && globalAttrs.has(key)) ||
237
261
  ariaAttrs.test(key) ||
238
262
  dataAttrs.test(key) ||
239
- eventHandlers.test(key)
240
- )
263
+ eventHandlers.test(key))
241
264
  ) {
242
265
  result[key] = (props as Record<string, unknown>)[key];
243
266
  }
@@ -246,10 +269,6 @@ export function filterDOMProps<R extends object = Record<string, unknown>>(
246
269
  return result as R;
247
270
  }
248
271
 
249
- // ============================================
250
- // CLIENT-ONLY UTILITIES
251
- // ============================================
252
-
253
272
  export interface ClientOnlyProps {
254
273
  /** The children to render only on the client */
255
274
  children: JSX.Element;