@proyecto-viviana/solidaria-components 0.3.2 → 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 (398) hide show
  1. package/dist/ActionBar.js +184 -0
  2. package/dist/ActionBar.js.map +1 -0
  3. package/dist/ActionBar.jsx +128 -0
  4. package/dist/ActionBar.jsx.map +1 -0
  5. package/dist/ActionGroup.js +179 -0
  6. package/dist/ActionGroup.js.map +1 -0
  7. package/dist/ActionGroup.jsx +129 -0
  8. package/dist/ActionGroup.jsx.map +1 -0
  9. package/dist/Alert.js +111 -0
  10. package/dist/Alert.js.map +1 -0
  11. package/dist/Alert.jsx +82 -0
  12. package/dist/Alert.jsx.map +1 -0
  13. package/dist/Autocomplete.js +130 -0
  14. package/dist/Autocomplete.js.map +1 -0
  15. package/dist/Autocomplete.jsx +116 -0
  16. package/dist/Autocomplete.jsx.map +1 -0
  17. package/dist/Breadcrumbs.d.ts.map +1 -1
  18. package/dist/Breadcrumbs.js +334 -0
  19. package/dist/Breadcrumbs.js.map +1 -0
  20. package/dist/Breadcrumbs.jsx +266 -0
  21. package/dist/Breadcrumbs.jsx.map +1 -0
  22. package/dist/Button.d.ts.map +1 -1
  23. package/dist/Button.js +348 -0
  24. package/dist/Button.js.map +1 -0
  25. package/dist/Button.jsx +314 -0
  26. package/dist/Button.jsx.map +1 -0
  27. package/dist/Calendar.d.ts +4 -4
  28. package/dist/Calendar.d.ts.map +1 -1
  29. package/dist/Calendar.js +538 -0
  30. package/dist/Calendar.js.map +1 -0
  31. package/dist/Calendar.jsx +333 -0
  32. package/dist/Calendar.jsx.map +1 -0
  33. package/dist/CalendarPicker.d.ts +33 -0
  34. package/dist/CalendarPicker.d.ts.map +1 -0
  35. package/dist/CalendarPicker.js +44 -0
  36. package/dist/CalendarPicker.js.map +1 -0
  37. package/dist/CalendarPicker.jsx +44 -0
  38. package/dist/CalendarPicker.jsx.map +1 -0
  39. package/dist/Checkbox.d.ts +83 -4
  40. package/dist/Checkbox.d.ts.map +1 -1
  41. package/dist/Checkbox.js +923 -0
  42. package/dist/Checkbox.js.map +1 -0
  43. package/dist/Checkbox.jsx +707 -0
  44. package/dist/Checkbox.jsx.map +1 -0
  45. package/dist/Collection.d.ts.map +1 -1
  46. package/dist/Collection.js +202 -0
  47. package/dist/Collection.js.map +1 -0
  48. package/dist/Collection.jsx +152 -0
  49. package/dist/Collection.jsx.map +1 -0
  50. package/dist/Color.d.ts.map +1 -1
  51. package/dist/Color.js +1720 -0
  52. package/dist/Color.js.map +1 -0
  53. package/dist/Color.jsx +1344 -0
  54. package/dist/Color.jsx.map +1 -0
  55. package/dist/ColorEditor.js +208 -0
  56. package/dist/ColorEditor.js.map +1 -0
  57. package/dist/ColorEditor.jsx +120 -0
  58. package/dist/ColorEditor.jsx.map +1 -0
  59. package/dist/ComboBox.d.ts +4 -4
  60. package/dist/ComboBox.d.ts.map +1 -1
  61. package/dist/ComboBox.js +992 -0
  62. package/dist/ComboBox.js.map +1 -0
  63. package/dist/ComboBox.jsx +714 -0
  64. package/dist/ComboBox.jsx.map +1 -0
  65. package/dist/ContextualHelpTrigger.js +146 -0
  66. package/dist/ContextualHelpTrigger.js.map +1 -0
  67. package/dist/ContextualHelpTrigger.jsx +109 -0
  68. package/dist/ContextualHelpTrigger.jsx.map +1 -0
  69. package/dist/DateField.d.ts +3 -3
  70. package/dist/DateField.d.ts.map +1 -1
  71. package/dist/DateField.js +4 -0
  72. package/dist/DateField.jsx +4 -0
  73. package/dist/DateField2.js +499 -0
  74. package/dist/DateField2.js.map +1 -0
  75. package/dist/DateField2.jsx +317 -0
  76. package/dist/DateField2.jsx.map +1 -0
  77. package/dist/DatePicker.d.ts +4 -4
  78. package/dist/DatePicker.d.ts.map +1 -1
  79. package/dist/DatePicker.js +991 -0
  80. package/dist/DatePicker.js.map +1 -0
  81. package/dist/DatePicker.jsx +682 -0
  82. package/dist/DatePicker.jsx.map +1 -0
  83. package/dist/Dialog.d.ts.map +1 -1
  84. package/dist/Dialog.js +337 -0
  85. package/dist/Dialog.js.map +1 -0
  86. package/dist/Dialog.jsx +192 -0
  87. package/dist/Dialog.jsx.map +1 -0
  88. package/dist/Disclosure.d.ts.map +1 -1
  89. package/dist/Disclosure.js +328 -0
  90. package/dist/Disclosure.js.map +1 -0
  91. package/dist/Disclosure.jsx +230 -0
  92. package/dist/Disclosure.jsx.map +1 -0
  93. package/dist/DragAndDrop.d.ts.map +1 -1
  94. package/dist/DragAndDrop.js +176 -0
  95. package/dist/DragAndDrop.js.map +1 -0
  96. package/dist/DragAndDrop.jsx +160 -0
  97. package/dist/DragAndDrop.jsx.map +1 -0
  98. package/dist/DropZone.d.ts.map +1 -1
  99. package/dist/DropZone.js +189 -0
  100. package/dist/DropZone.js.map +1 -0
  101. package/dist/DropZone.jsx +144 -0
  102. package/dist/DropZone.jsx.map +1 -0
  103. package/dist/FieldError.js +66 -0
  104. package/dist/FieldError.js.map +1 -0
  105. package/dist/FieldError.jsx +47 -0
  106. package/dist/FieldError.jsx.map +1 -0
  107. package/dist/FileTrigger.js +79 -0
  108. package/dist/FileTrigger.js.map +1 -0
  109. package/dist/FileTrigger.jsx +49 -0
  110. package/dist/FileTrigger.jsx.map +1 -0
  111. package/dist/Focusable.js +70 -0
  112. package/dist/Focusable.js.map +1 -0
  113. package/dist/Focusable.jsx +69 -0
  114. package/dist/Focusable.jsx.map +1 -0
  115. package/dist/Form.js +99 -0
  116. package/dist/Form.js.map +1 -0
  117. package/dist/Form.jsx +73 -0
  118. package/dist/Form.jsx.map +1 -0
  119. package/dist/GridList.d.ts +34 -2
  120. package/dist/GridList.d.ts.map +1 -1
  121. package/dist/GridList.js +723 -0
  122. package/dist/GridList.js.map +1 -0
  123. package/dist/GridList.jsx +552 -0
  124. package/dist/GridList.jsx.map +1 -0
  125. package/dist/HiddenTimeInput.js +104 -0
  126. package/dist/HiddenTimeInput.js.map +1 -0
  127. package/dist/HiddenTimeInput.jsx +69 -0
  128. package/dist/HiddenTimeInput.jsx.map +1 -0
  129. package/dist/Icon.d.ts.map +1 -1
  130. package/dist/Icon.js +127 -0
  131. package/dist/Icon.js.map +1 -0
  132. package/dist/Icon.jsx +72 -0
  133. package/dist/Icon.jsx.map +1 -0
  134. package/dist/Keyboard.js +30 -0
  135. package/dist/Keyboard.js.map +1 -0
  136. package/dist/Keyboard.jsx +24 -0
  137. package/dist/Keyboard.jsx.map +1 -0
  138. package/dist/Landmark.js +134 -0
  139. package/dist/Landmark.js.map +1 -0
  140. package/dist/Landmark.jsx +118 -0
  141. package/dist/Landmark.jsx.map +1 -0
  142. package/dist/Link.d.ts.map +1 -1
  143. package/dist/Link.js +219 -0
  144. package/dist/Link.js.map +1 -0
  145. package/dist/Link.jsx +189 -0
  146. package/dist/Link.jsx.map +1 -0
  147. package/dist/ListBox.d.ts.map +1 -1
  148. package/dist/ListBox.js +670 -0
  149. package/dist/ListBox.js.map +1 -0
  150. package/dist/ListBox.jsx +508 -0
  151. package/dist/ListBox.jsx.map +1 -0
  152. package/dist/Menu.d.ts +27 -9
  153. package/dist/Menu.d.ts.map +1 -1
  154. package/dist/Menu.js +1254 -0
  155. package/dist/Menu.js.map +1 -0
  156. package/dist/Menu.jsx +1042 -0
  157. package/dist/Menu.jsx.map +1 -0
  158. package/dist/Meter.d.ts.map +1 -1
  159. package/dist/Meter.js +123 -0
  160. package/dist/Meter.js.map +1 -0
  161. package/dist/Meter.jsx +107 -0
  162. package/dist/Meter.jsx.map +1 -0
  163. package/dist/Modal.d.ts.map +1 -1
  164. package/dist/Modal.js +380 -0
  165. package/dist/Modal.js.map +1 -0
  166. package/dist/Modal.jsx +314 -0
  167. package/dist/Modal.jsx.map +1 -0
  168. package/dist/NumberField.d.ts +3 -3
  169. package/dist/NumberField.d.ts.map +1 -1
  170. package/dist/NumberField.js +573 -0
  171. package/dist/NumberField.js.map +1 -0
  172. package/dist/NumberField.jsx +443 -0
  173. package/dist/NumberField.jsx.map +1 -0
  174. package/dist/Popover.d.ts +10 -2
  175. package/dist/Popover.d.ts.map +1 -1
  176. package/dist/Popover.js +464 -0
  177. package/dist/Popover.js.map +1 -0
  178. package/dist/Popover.jsx +333 -0
  179. package/dist/Popover.jsx.map +1 -0
  180. package/dist/Pressable.js +69 -0
  181. package/dist/Pressable.js.map +1 -0
  182. package/dist/Pressable.jsx +68 -0
  183. package/dist/Pressable.jsx.map +1 -0
  184. package/dist/ProgressBar.d.ts.map +1 -1
  185. package/dist/ProgressBar.js +130 -0
  186. package/dist/ProgressBar.js.map +1 -0
  187. package/dist/ProgressBar.jsx +114 -0
  188. package/dist/ProgressBar.jsx.map +1 -0
  189. package/dist/RadioGroup.d.ts +82 -4
  190. package/dist/RadioGroup.d.ts.map +1 -1
  191. package/dist/RadioGroup.js +931 -0
  192. package/dist/RadioGroup.js.map +1 -0
  193. package/dist/RadioGroup.jsx +681 -0
  194. package/dist/RadioGroup.jsx.map +1 -0
  195. package/dist/RangeCalendar.d.ts.map +1 -1
  196. package/dist/RangeCalendar.js +410 -0
  197. package/dist/RangeCalendar.js.map +1 -0
  198. package/dist/RangeCalendar.jsx +253 -0
  199. package/dist/RangeCalendar.jsx.map +1 -0
  200. package/dist/RouterProvider.js +118 -0
  201. package/dist/RouterProvider.js.map +1 -0
  202. package/dist/RouterProvider.jsx +112 -0
  203. package/dist/RouterProvider.jsx.map +1 -0
  204. package/dist/SearchField.d.ts +2 -2
  205. package/dist/SearchField.d.ts.map +1 -1
  206. package/dist/SearchField.js +643 -0
  207. package/dist/SearchField.js.map +1 -0
  208. package/dist/SearchField.jsx +526 -0
  209. package/dist/SearchField.jsx.map +1 -0
  210. package/dist/Select.d.ts.map +1 -1
  211. package/dist/Select.js +1031 -0
  212. package/dist/Select.js.map +1 -0
  213. package/dist/Select.jsx +744 -0
  214. package/dist/Select.jsx.map +1 -0
  215. package/dist/SelectionIndicator.d.ts.map +1 -1
  216. package/dist/SelectionIndicator.js +86 -0
  217. package/dist/SelectionIndicator.js.map +1 -0
  218. package/dist/SelectionIndicator.jsx +50 -0
  219. package/dist/SelectionIndicator.jsx.map +1 -0
  220. package/dist/Separator.js +97 -0
  221. package/dist/Separator.js.map +1 -0
  222. package/dist/Separator.jsx +85 -0
  223. package/dist/Separator.jsx.map +1 -0
  224. package/dist/SharedElementTransition.d.ts.map +1 -1
  225. package/dist/SharedElementTransition.js +165 -0
  226. package/dist/SharedElementTransition.js.map +1 -0
  227. package/dist/SharedElementTransition.jsx +138 -0
  228. package/dist/SharedElementTransition.jsx.map +1 -0
  229. package/dist/Slider.d.ts +33 -1
  230. package/dist/Slider.d.ts.map +1 -1
  231. package/dist/Slider.js +515 -0
  232. package/dist/Slider.js.map +1 -0
  233. package/dist/Slider.jsx +403 -0
  234. package/dist/Slider.jsx.map +1 -0
  235. package/dist/StepList.js +198 -0
  236. package/dist/StepList.js.map +1 -0
  237. package/dist/StepList.jsx +141 -0
  238. package/dist/StepList.jsx.map +1 -0
  239. package/dist/Switch.d.ts +65 -2
  240. package/dist/Switch.d.ts.map +1 -1
  241. package/dist/Switch.js +534 -0
  242. package/dist/Switch.js.map +1 -0
  243. package/dist/Switch.jsx +393 -0
  244. package/dist/Switch.jsx.map +1 -0
  245. package/dist/Table.d.ts +48 -0
  246. package/dist/Table.d.ts.map +1 -1
  247. package/dist/Table.js +1759 -0
  248. package/dist/Table.js.map +1 -0
  249. package/dist/Table.jsx +1348 -0
  250. package/dist/Table.jsx.map +1 -0
  251. package/dist/Tabs.d.ts +0 -4
  252. package/dist/Tabs.d.ts.map +1 -1
  253. package/dist/Tabs.js +595 -0
  254. package/dist/Tabs.js.map +1 -0
  255. package/dist/Tabs.jsx +367 -0
  256. package/dist/Tabs.jsx.map +1 -0
  257. package/dist/TagGroup.d.ts.map +1 -1
  258. package/dist/TagGroup.js +378 -0
  259. package/dist/TagGroup.js.map +1 -0
  260. package/dist/TagGroup.jsx +270 -0
  261. package/dist/TagGroup.jsx.map +1 -0
  262. package/dist/Text.d.ts +18 -6
  263. package/dist/Text.d.ts.map +1 -1
  264. package/dist/Text.js +42 -0
  265. package/dist/Text.js.map +1 -0
  266. package/dist/Text.jsx +35 -0
  267. package/dist/Text.jsx.map +1 -0
  268. package/dist/TextField.d.ts +6 -6
  269. package/dist/TextField.d.ts.map +1 -1
  270. package/dist/TextField.js +436 -0
  271. package/dist/TextField.js.map +1 -0
  272. package/dist/TextField.jsx +403 -0
  273. package/dist/TextField.jsx.map +1 -0
  274. package/dist/TimeField.d.ts +3 -3
  275. package/dist/TimeField.d.ts.map +1 -1
  276. package/dist/TimeField.js +372 -0
  277. package/dist/TimeField.js.map +1 -0
  278. package/dist/TimeField.jsx +224 -0
  279. package/dist/TimeField.jsx.map +1 -0
  280. package/dist/Toast.d.ts +14 -0
  281. package/dist/Toast.d.ts.map +1 -1
  282. package/dist/Toast.js +551 -0
  283. package/dist/Toast.js.map +1 -0
  284. package/dist/Toast.jsx +361 -0
  285. package/dist/Toast.jsx.map +1 -0
  286. package/dist/ToggleButton.d.ts.map +1 -1
  287. package/dist/ToggleButton.js +123 -0
  288. package/dist/ToggleButton.js.map +1 -0
  289. package/dist/ToggleButton.jsx +88 -0
  290. package/dist/ToggleButton.jsx.map +1 -0
  291. package/dist/ToggleButtonGroup.d.ts.map +1 -1
  292. package/dist/ToggleButtonGroup.js +114 -0
  293. package/dist/ToggleButtonGroup.js.map +1 -0
  294. package/dist/ToggleButtonGroup.jsx +85 -0
  295. package/dist/ToggleButtonGroup.jsx.map +1 -0
  296. package/dist/Toolbar.js +112 -0
  297. package/dist/Toolbar.js.map +1 -0
  298. package/dist/Toolbar.jsx +92 -0
  299. package/dist/Toolbar.jsx.map +1 -0
  300. package/dist/Tooltip.d.ts.map +1 -1
  301. package/dist/Tooltip.js +539 -0
  302. package/dist/Tooltip.js.map +1 -0
  303. package/dist/Tooltip.jsx +465 -0
  304. package/dist/Tooltip.jsx.map +1 -0
  305. package/dist/Tree.d.ts +14 -2
  306. package/dist/Tree.d.ts.map +1 -1
  307. package/dist/Tree.js +1424 -0
  308. package/dist/Tree.js.map +1 -0
  309. package/dist/Tree.jsx +1172 -0
  310. package/dist/Tree.jsx.map +1 -0
  311. package/dist/Virtualizer.d.ts +16 -2
  312. package/dist/Virtualizer.d.ts.map +1 -1
  313. package/dist/Virtualizer.js +2 -0
  314. package/dist/Virtualizer.jsx +2 -0
  315. package/dist/Virtualizer2.js +751 -0
  316. package/dist/Virtualizer2.js.map +1 -0
  317. package/dist/Virtualizer2.jsx +730 -0
  318. package/dist/Virtualizer2.jsx.map +1 -0
  319. package/dist/VirtualizerLayouts.d.ts +18 -0
  320. package/dist/VirtualizerLayouts.d.ts.map +1 -1
  321. package/dist/VisuallyHidden.js +42 -0
  322. package/dist/VisuallyHidden.js.map +1 -0
  323. package/dist/VisuallyHidden.jsx +35 -0
  324. package/dist/VisuallyHidden.jsx.map +1 -0
  325. package/dist/contexts.js +33 -0
  326. package/dist/contexts.js.map +1 -0
  327. package/dist/contexts.jsx +33 -0
  328. package/dist/contexts.jsx.map +1 -0
  329. package/dist/index.d.ts +7 -6
  330. package/dist/index.d.ts.map +1 -1
  331. package/dist/index.js +70 -23932
  332. package/dist/index.jsx +70 -18337
  333. package/dist/useDragAndDrop.js +2 -0
  334. package/dist/useDragAndDrop.jsx +2 -0
  335. package/dist/useDragAndDrop2.js +395 -0
  336. package/dist/useDragAndDrop2.js.map +1 -0
  337. package/dist/useDragAndDrop2.jsx +395 -0
  338. package/dist/useDragAndDrop2.jsx.map +1 -0
  339. package/dist/utils.d.ts +83 -11
  340. package/dist/utils.d.ts.map +1 -1
  341. package/dist/utils.js +285 -0
  342. package/dist/utils.js.map +1 -0
  343. package/dist/utils.jsx +277 -0
  344. package/dist/utils.jsx.map +1 -0
  345. package/dist/virtualizer/Layout.js +144 -0
  346. package/dist/virtualizer/Layout.js.map +1 -0
  347. package/dist/virtualizer/Layout.jsx +144 -0
  348. package/dist/virtualizer/Layout.jsx.map +1 -0
  349. package/package.json +401 -4
  350. package/src/Breadcrumbs.tsx +3 -1
  351. package/src/Button.tsx +22 -2
  352. package/src/Calendar.tsx +27 -10
  353. package/src/CalendarPicker.tsx +73 -0
  354. package/src/Checkbox.tsx +539 -3
  355. package/src/Collection.tsx +9 -3
  356. package/src/Color.tsx +42 -14
  357. package/src/ComboBox.tsx +50 -6
  358. package/src/DateField.tsx +20 -2
  359. package/src/DatePicker.tsx +57 -5
  360. package/src/Dialog.tsx +13 -5
  361. package/src/Disclosure.tsx +3 -1
  362. package/src/DragAndDrop.tsx +3 -1
  363. package/src/DropZone.tsx +3 -1
  364. package/src/GridList.tsx +125 -24
  365. package/src/Icon.tsx +3 -1
  366. package/src/Link.tsx +3 -1
  367. package/src/ListBox.tsx +31 -4
  368. package/src/Menu.tsx +252 -128
  369. package/src/Meter.tsx +3 -1
  370. package/src/Modal.tsx +100 -52
  371. package/src/NumberField.tsx +51 -8
  372. package/src/Popover.tsx +40 -10
  373. package/src/ProgressBar.tsx +3 -1
  374. package/src/RadioGroup.tsx +468 -4
  375. package/src/RangeCalendar.tsx +3 -1
  376. package/src/SearchField.tsx +27 -3
  377. package/src/Select.tsx +22 -7
  378. package/src/SelectionIndicator.tsx +3 -1
  379. package/src/SharedElementTransition.tsx +3 -1
  380. package/src/Slider.tsx +159 -13
  381. package/src/Switch.tsx +395 -2
  382. package/src/Table.tsx +409 -95
  383. package/src/Tabs.tsx +16 -45
  384. package/src/TagGroup.tsx +3 -1
  385. package/src/Text.tsx +31 -10
  386. package/src/TextField.tsx +43 -5
  387. package/src/TimeField.tsx +20 -2
  388. package/src/Toast.tsx +79 -14
  389. package/src/ToggleButton.tsx +3 -1
  390. package/src/ToggleButtonGroup.tsx +3 -1
  391. package/src/Tooltip.tsx +3 -1
  392. package/src/Tree.tsx +77 -9
  393. package/src/Virtualizer.tsx +180 -31
  394. package/src/VirtualizerLayouts.ts +45 -10
  395. package/src/index.ts +50 -0
  396. package/src/utils.tsx +243 -27
  397. package/dist/index.js.map +0 -1
  398. package/dist/index.jsx.map +0 -1
package/src/utils.tsx CHANGED
@@ -6,16 +6,20 @@
6
6
  import {
7
7
  type JSX,
8
8
  type Accessor,
9
+ type Context,
9
10
  type FlowComponent,
10
- type ParentComponent,
11
+ createComponent,
11
12
  createContext,
12
13
  useContext,
13
14
  createMemo,
14
15
  createSignal,
15
16
  onMount,
17
+ sharedConfig,
18
+ untrack,
16
19
  Show,
17
20
  } from "solid-js";
18
21
  import { isServer } from "solid-js/web";
22
+ import { mergeProps } from "@proyecto-viviana/solidaria";
19
23
 
20
24
  /**
21
25
  * Render props pattern - children can be a function that receives state
@@ -73,6 +77,19 @@ export interface RenderPropsResult<T> {
73
77
  * {renderProps.renderChildren()}
74
78
  */
75
79
  renderChildren: () => JSX.Element;
80
+ /**
81
+ * Render a render-prop child ONCE over a reactive view of the values,
82
+ * mirroring how React reconciles a render prop's returned tree in place.
83
+ *
84
+ * Prefer this over `renderChildren()` for interactive leaf components (a
85
+ * Tab, a toggle segment) whose child wraps the pressable element: re-invoking
86
+ * the render function on every values() change recreates that DOM subtree,
87
+ * which detaches the pointer/press target mid-gesture and makes the browser
88
+ * suppress the native `click` (createPress then has to synthesize an
89
+ * untrusted fallback click — a visible parity break vs React). Static (non
90
+ * function) children are returned untouched, exactly like `renderChildren`.
91
+ */
92
+ renderChildrenStable: () => JSX.Element;
76
93
  /** The raw children prop (function or JSX) - use renderChildren() in most cases */
77
94
  children: RenderChildren<T> | undefined;
78
95
  /** The render props values accessor */
@@ -115,9 +132,55 @@ export function useRenderProps<T extends object>(
115
132
  class: computedClass,
116
133
  style: computedStyle,
117
134
  renderChildren: () => {
118
- const currentValues = values();
119
135
  const children = props.children;
120
- return typeof children === "function" ? children(currentValues) : children;
136
+ // Only read values() for render-prop children. Static JSX children must
137
+ // not track the render-state memo: re-running the insertion effect
138
+ // recreates real DOM nodes on every hover/press/focus flip (React keeps
139
+ // them stable via vdom diffing), which detaches the pressed node
140
+ // mid-press and suppresses the browser's native click.
141
+ //
142
+ // A render prop takes the values argument, so classify by arity — the
143
+ // same convention `solid-js/h` uses for dynamic props. A zero-arg
144
+ // function child is an accessor (a compiled `{expression}` child, a
145
+ // solid-refresh dev wrapper, a one-shot `solid-js/h` element thunk):
146
+ // return it untouched so the insert machinery unwraps it in its own
147
+ // nested effect. Calling it here would track its reads in the shared
148
+ // insertion effect, and every re-run disposes the child computations
149
+ // that effect owns — a one-shot h thunk then hands back the same
150
+ // disposed node, leaving connected DOM whose reactivity is dead.
151
+ return typeof children === "function" && children.length > 0
152
+ ? children(values())
153
+ : (children as JSX.Element);
154
+ },
155
+ renderChildrenStable: () => {
156
+ const children = props.children;
157
+ if (typeof children !== "function" || children.length === 0) {
158
+ return children as JSX.Element;
159
+ }
160
+ // Invoke the render function exactly once, over a getter view of the
161
+ // values, so the returned DOM is created a single time and only the
162
+ // reactive reads inside it (JSX bindings, component props) re-run on a
163
+ // values() change — React's reconciliation, not Solid's recreation.
164
+ //
165
+ // `untrack` keeps the enclosing insert from tracking values() (so it
166
+ // never re-runs and never recreates), but does NOT change the owner:
167
+ // this still executes inside the caller's insert scope, so any slotted
168
+ // context the render prop reads binds against the surrounding provider.
169
+ //
170
+ // The value keys are read once here (untracked). Render-state memos in
171
+ // this codebase return a fixed-shape object, so the key set is stable.
172
+ return untrack(() => {
173
+ const snapshot = values();
174
+ const view = {} as T;
175
+ for (const key of Object.keys(snapshot) as Array<keyof T & string>) {
176
+ Object.defineProperty(view, key, {
177
+ enumerable: true,
178
+ configurable: true,
179
+ get: () => values()[key],
180
+ });
181
+ }
182
+ return (children as (renderProps: T) => JSX.Element)(view);
183
+ });
121
184
  },
122
185
  get children() {
123
186
  return props.children;
@@ -139,41 +202,177 @@ export function composeRenderProps<T extends object>(
139
202
  };
140
203
  }
141
204
 
205
+ /** A Solid ref target: a callback, a mutable `{ current }` object, or undefined. */
206
+ export type RefLike<T> = T | ((el: T) => void) | { current?: T | null } | undefined;
207
+
208
+ /** A value paired with an optional ref to merge onto the consuming element. */
209
+ export type WithRef<T, E> = T & { ref?: RefLike<E> };
210
+
142
211
  /**
143
- * Context value that can be null or the actual value
212
+ * A context value carrying named slots (mirrors react-aria-components'
213
+ * `SlottedValue`). Each entry under `slots` is the props object delivered to the
214
+ * component rendered with the matching `slot` name.
144
215
  */
145
- export type ContextValue<T> = T | null;
216
+ export interface SlottedValue<T> {
217
+ slots?: Record<string, T>;
218
+ }
219
+
220
+ /** A slotted context value: a slots record, a bare value, or null/undefined. */
221
+ export type SlottedContextValue<T> = SlottedValue<T> | T | null | undefined;
222
+
223
+ /**
224
+ * The value type for a context consumed via {@link useContextProps}. Mirrors
225
+ * upstream `ContextValue<T, E>`: it may carry `slots` and an optional `ref` to
226
+ * merge onto the consuming element.
227
+ */
228
+ export type ContextValue<T, E = HTMLElement> = SlottedContextValue<WithRef<T, E>>;
146
229
 
147
230
  /**
148
- * Creates a context with props and ref merging support
231
+ * Creates a context that can carry either a bare value or a `slots` record.
149
232
  */
150
233
  export function createSlottedContext<T>() {
151
- return createContext<T | null>(null);
234
+ return createContext<SlottedContextValue<T>>(null);
235
+ }
236
+
237
+ /** Assigns an element to a Solid ref (callback or mutable `{ current }` object). */
238
+ export function assignRef<T>(ref: RefLike<T>, el: T): void {
239
+ if (!ref) {
240
+ return;
241
+ }
242
+
243
+ if (typeof ref === "function") {
244
+ (ref as (el: T) => void)(el);
245
+ } else if (typeof ref === "object" && "current" in ref) {
246
+ (ref as { current?: T | null }).current = el;
247
+ }
248
+ }
249
+
250
+ /** Merges multiple Solid refs into one callback that forwards to each, once. */
251
+ export function mergeRefs<T>(...refs: Array<RefLike<T>>): (el: T) => void {
252
+ return (el: T) => {
253
+ const seen = new Set<RefLike<T>>();
254
+ for (const ref of refs) {
255
+ if (!ref || seen.has(ref)) {
256
+ continue;
257
+ }
258
+
259
+ seen.add(ref);
260
+ assignRef(ref, el);
261
+ }
262
+ };
152
263
  }
153
264
 
154
265
  /**
155
- * Use context with null check
266
+ * Resolves a (possibly slotted) context value for the given slot name. Port of
267
+ * react-aria-components' `useSlottedContext`:
268
+ * - `slot === null` opts out of the context entirely (returns `null`);
269
+ * - if the context carries a `slots` record, the entry for `slot` (or
270
+ * {@link DEFAULT_SLOT}) is returned, throwing on an unknown slot name;
271
+ * - otherwise the bare context value is returned.
156
272
  */
157
273
  export function useSlottedContext<T>(
158
- context: ReturnType<typeof createContext<T | null>>,
159
- ): T | null {
160
- return useContext(context);
274
+ context: Context<SlottedContextValue<T>>,
275
+ slot?: string | null,
276
+ ): T | null | undefined {
277
+ const ctx = useContext(context);
278
+ if (slot === null) {
279
+ // An explicit `null` slot means: ignore this context.
280
+ return null;
281
+ }
282
+
283
+ if (ctx && typeof ctx === "object" && "slots" in ctx && ctx.slots) {
284
+ const slots = ctx.slots as Record<string, T>;
285
+ const slotName = slot || DEFAULT_SLOT;
286
+ const slotValue = slots[slotName];
287
+ if (!slotValue) {
288
+ const validSlots = Object.keys(slots)
289
+ .map((name) => `"${name}"`)
290
+ .join(", ");
291
+ throw new Error(
292
+ slot
293
+ ? `Invalid slot "${slot}". Valid slot names are ${validSlots}.`
294
+ : `A slot prop is required. Valid slot names are ${validSlots}.`,
295
+ );
296
+ }
297
+ return slotValue;
298
+ }
299
+
300
+ return ctx as T | null | undefined;
161
301
  }
162
302
 
163
- export function useContextProps<TProps extends object, TRef>(
303
+ /**
304
+ * Merges context-provided props and a context ref into a component's own props
305
+ * and ref. Port of react-aria-components' `useContextProps`:
306
+ * - the context is resolved for `props.slot` via {@link useSlottedContext};
307
+ * - props win over context props (handler props are chained by `mergeProps`);
308
+ * - the component's own ref and the context's ref merge into one callback.
309
+ *
310
+ * The prop merge stays reactive (Solid `mergeProps` preserves getters), so prop
311
+ * changes keep flowing; the context value is read once at setup, matching a single
312
+ * upstream render.
313
+ */
314
+ export function useContextProps<TProps extends SlotProps, TRef>(
164
315
  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];
316
+ ref: RefLike<TRef>,
317
+ context: Context<ContextValue<TProps, TRef>>,
318
+ ): [TProps, (el: TRef) => void] {
319
+ const ctx = (useSlottedContext(context, props.slot) ?? {}) as WithRef<Partial<TProps>, TRef>;
320
+ const { ref: contextRef, ...contextProps } = ctx;
321
+ const mergedRef = mergeRefs(ref, contextRef);
322
+ const mergedProps = mergeProps(contextProps as object, props as object) as unknown as TProps;
323
+ return [mergedProps, mergedRef];
170
324
  }
171
325
 
172
- export const Provider: ParentComponent<{
173
- values: Array<[ReturnType<typeof createContext<unknown>>, unknown]>;
174
- }> = (props) => {
175
- return props.children;
176
- };
326
+ /**
327
+ * Detects whether slotted content was rendered into a placeholder, for the
328
+ * aria-label fallback pattern. Port of react-aria-components' `useSlot`: returns a
329
+ * ref callback to attach to the placeholder and an accessor that is `true` while
330
+ * an element is mounted there. The accessor flips to `false` after mount if the
331
+ * ref never ran (no slotted content was provided).
332
+ */
333
+ export function useSlot(initialState = true): [(el: Element | null) => void, Accessor<boolean>] {
334
+ const [hasSlot, setHasSlot] = createSignal(initialState);
335
+ let hasRun = false;
336
+ const ref = (el: Element | null) => {
337
+ hasRun = true;
338
+ setHasSlot(!!el);
339
+ };
340
+ onMount(() => {
341
+ if (!hasRun) {
342
+ setHasSlot(false);
343
+ }
344
+ });
345
+ return [ref, hasSlot];
346
+ }
347
+
348
+ /**
349
+ * Nests a set of context providers around `children`. Port of
350
+ * react-aria-components' `Provider`: each `[Context, value]` pair wraps the
351
+ * previous result, so the LAST pair is the outermost provider — matching upstream's
352
+ * wrap-in-iteration-order.
353
+ *
354
+ * `children` is read through a lazy getter inside the innermost provider so child
355
+ * components are *created* within every provider's owner; Solid binds `useContext`
356
+ * at component-execution time, so eager children would miss these providers.
357
+ */
358
+ export function Provider(props: {
359
+ values: Array<[Context<unknown>, unknown]>;
360
+ children: JSX.Element;
361
+ }): JSX.Element {
362
+ const build = (index: number): JSX.Element => {
363
+ if (index < 0) {
364
+ return props.children;
365
+ }
366
+ const [context, value] = props.values[index];
367
+ return createComponent(context.Provider, {
368
+ value,
369
+ get children() {
370
+ return build(index - 1);
371
+ },
372
+ });
373
+ };
374
+ return build(props.values.length - 1);
375
+ }
177
376
 
178
377
  /**
179
378
  * Converts boolean state values to data attributes
@@ -299,7 +498,12 @@ export const ClientOnly: FlowComponent<ClientOnlyProps> = (props) => {
299
498
  return <>{props.fallback}</>;
300
499
  }
301
500
 
302
- // On client, track if we've hydrated
501
+ // Outside a hydration walk there is nothing to defer (see useIsHydrated).
502
+ if (!sharedConfig.context) {
503
+ return <>{props.children}</>;
504
+ }
505
+
506
+ // Hydrating: render the fallback until the walk completes.
303
507
  const [isHydrated, setIsHydrated] = createSignal(false);
304
508
 
305
509
  // onMount runs after hydration is complete
@@ -334,16 +538,28 @@ export function useIsHydrated(): Accessor<boolean> {
334
538
  return () => false;
335
539
  }
336
540
 
337
- // On client, start false (so the first render matches the server, which
541
+ // Outside a hydration walk (pure CSR, or a remount created after hydration
542
+ // finished) the caller is already "hydrated" — report true immediately.
543
+ // Solid sets `sharedConfig.context` only while synchronously walking
544
+ // server-rendered DOM, so this is exactly the window the false→true flip
545
+ // exists for. A fresh per-instance false→true flip on every remount is not
546
+ // just wasted work: ancestor `children()`/`Context.Provider` resolution
547
+ // unwraps and tracks the <Show> accessor this hook gates, so the post-mount
548
+ // flip re-resolves those children, recreates the subtree (with another fresh
549
+ // signal), and loops forever — a stack overflow with no overlay rendered.
550
+ if (!sharedConfig.context) {
551
+ return () => true;
552
+ }
553
+
554
+ // Hydrating: start false (so the first render matches the server, which
338
555
  // emitted nothing for hydrated-gated content) and flip to true after mount.
339
556
  const [isHydrated, setIsHydrated] = createSignal(false);
340
557
 
341
558
  // onMount runs in the effect phase — *after* the synchronous hydration pass
342
559
  // has finished walking the server DOM — so flipping here renders the gated
343
560
  // content as a fresh client-side update (Portal: no getNextElement walk, no
344
- // mismatch), yet fires synchronously under `render()` (unit tests / pure CSR)
345
- // where requestAnimationFrame would never run. This mirrors the component
346
- // gate above and is strictly earlier than a rAF tick.
561
+ // mismatch). This mirrors the component gate above and is strictly earlier
562
+ // than a rAF tick.
347
563
  onMount(() => {
348
564
  setIsHydrated(true);
349
565
  });