@proyecto-viviana/solidaria-components 0.3.2 → 0.4.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 (417) hide show
  1. package/dist/ActionBar.d.ts.map +1 -1
  2. package/dist/ActionBar.js +175 -0
  3. package/dist/ActionBar.js.map +1 -0
  4. package/dist/ActionBar.jsx +119 -0
  5. package/dist/ActionBar.jsx.map +1 -0
  6. package/dist/ActionGroup.d.ts.map +1 -1
  7. package/dist/ActionGroup.js +179 -0
  8. package/dist/ActionGroup.js.map +1 -0
  9. package/dist/ActionGroup.jsx +129 -0
  10. package/dist/ActionGroup.jsx.map +1 -0
  11. package/dist/Alert.js +111 -0
  12. package/dist/Alert.js.map +1 -0
  13. package/dist/Alert.jsx +82 -0
  14. package/dist/Alert.jsx.map +1 -0
  15. package/dist/Autocomplete.d.ts +2 -2
  16. package/dist/Autocomplete.d.ts.map +1 -1
  17. package/dist/Autocomplete.js +130 -0
  18. package/dist/Autocomplete.js.map +1 -0
  19. package/dist/Autocomplete.jsx +116 -0
  20. package/dist/Autocomplete.jsx.map +1 -0
  21. package/dist/Breadcrumbs.d.ts.map +1 -1
  22. package/dist/Breadcrumbs.js +333 -0
  23. package/dist/Breadcrumbs.js.map +1 -0
  24. package/dist/Breadcrumbs.jsx +261 -0
  25. package/dist/Breadcrumbs.jsx.map +1 -0
  26. package/dist/Button.d.ts.map +1 -1
  27. package/dist/Button.js +348 -0
  28. package/dist/Button.js.map +1 -0
  29. package/dist/Button.jsx +314 -0
  30. package/dist/Button.jsx.map +1 -0
  31. package/dist/Calendar.d.ts +4 -4
  32. package/dist/Calendar.d.ts.map +1 -1
  33. package/dist/Calendar.js +573 -0
  34. package/dist/Calendar.js.map +1 -0
  35. package/dist/Calendar.jsx +342 -0
  36. package/dist/Calendar.jsx.map +1 -0
  37. package/dist/CalendarPicker.d.ts +33 -0
  38. package/dist/CalendarPicker.d.ts.map +1 -0
  39. package/dist/CalendarPicker.js +44 -0
  40. package/dist/CalendarPicker.js.map +1 -0
  41. package/dist/CalendarPicker.jsx +44 -0
  42. package/dist/CalendarPicker.jsx.map +1 -0
  43. package/dist/Checkbox.d.ts +83 -4
  44. package/dist/Checkbox.d.ts.map +1 -1
  45. package/dist/Checkbox.js +923 -0
  46. package/dist/Checkbox.js.map +1 -0
  47. package/dist/Checkbox.jsx +707 -0
  48. package/dist/Checkbox.jsx.map +1 -0
  49. package/dist/Collection.d.ts.map +1 -1
  50. package/dist/Collection.js +202 -0
  51. package/dist/Collection.js.map +1 -0
  52. package/dist/Collection.jsx +152 -0
  53. package/dist/Collection.jsx.map +1 -0
  54. package/dist/Color.d.ts.map +1 -1
  55. package/dist/Color.js +1717 -0
  56. package/dist/Color.js.map +1 -0
  57. package/dist/Color.jsx +1340 -0
  58. package/dist/Color.jsx.map +1 -0
  59. package/dist/ColorEditor.js +208 -0
  60. package/dist/ColorEditor.js.map +1 -0
  61. package/dist/ColorEditor.jsx +120 -0
  62. package/dist/ColorEditor.jsx.map +1 -0
  63. package/dist/ComboBox.d.ts +8 -4
  64. package/dist/ComboBox.d.ts.map +1 -1
  65. package/dist/ComboBox.js +1000 -0
  66. package/dist/ComboBox.js.map +1 -0
  67. package/dist/ComboBox.jsx +724 -0
  68. package/dist/ComboBox.jsx.map +1 -0
  69. package/dist/ContextualHelpTrigger.js +146 -0
  70. package/dist/ContextualHelpTrigger.js.map +1 -0
  71. package/dist/ContextualHelpTrigger.jsx +109 -0
  72. package/dist/ContextualHelpTrigger.jsx.map +1 -0
  73. package/dist/DateField.d.ts +14 -5
  74. package/dist/DateField.d.ts.map +1 -1
  75. package/dist/DateField.js +4 -0
  76. package/dist/DateField.jsx +4 -0
  77. package/dist/DateField2.js +502 -0
  78. package/dist/DateField2.js.map +1 -0
  79. package/dist/DateField2.jsx +354 -0
  80. package/dist/DateField2.jsx.map +1 -0
  81. package/dist/DatePicker.d.ts +46 -7
  82. package/dist/DatePicker.d.ts.map +1 -1
  83. package/dist/DatePicker.js +7 -0
  84. package/dist/DatePicker.jsx +7 -0
  85. package/dist/DatePicker2.js +1171 -0
  86. package/dist/DatePicker2.js.map +1 -0
  87. package/dist/DatePicker2.jsx +820 -0
  88. package/dist/DatePicker2.jsx.map +1 -0
  89. package/dist/DateRangePickerContext.d.ts +2 -0
  90. package/dist/DateRangePickerContext.d.ts.map +1 -1
  91. package/dist/Dialog.d.ts.map +1 -1
  92. package/dist/Dialog.js +337 -0
  93. package/dist/Dialog.js.map +1 -0
  94. package/dist/Dialog.jsx +192 -0
  95. package/dist/Dialog.jsx.map +1 -0
  96. package/dist/Disclosure.d.ts.map +1 -1
  97. package/dist/Disclosure.js +331 -0
  98. package/dist/Disclosure.js.map +1 -0
  99. package/dist/Disclosure.jsx +230 -0
  100. package/dist/Disclosure.jsx.map +1 -0
  101. package/dist/DragAndDrop.d.ts.map +1 -1
  102. package/dist/DragAndDrop.js +176 -0
  103. package/dist/DragAndDrop.js.map +1 -0
  104. package/dist/DragAndDrop.jsx +160 -0
  105. package/dist/DragAndDrop.jsx.map +1 -0
  106. package/dist/DropZone.d.ts.map +1 -1
  107. package/dist/DropZone.js +189 -0
  108. package/dist/DropZone.js.map +1 -0
  109. package/dist/DropZone.jsx +144 -0
  110. package/dist/DropZone.jsx.map +1 -0
  111. package/dist/FieldError.js +66 -0
  112. package/dist/FieldError.js.map +1 -0
  113. package/dist/FieldError.jsx +47 -0
  114. package/dist/FieldError.jsx.map +1 -0
  115. package/dist/FileTrigger.js +79 -0
  116. package/dist/FileTrigger.js.map +1 -0
  117. package/dist/FileTrigger.jsx +49 -0
  118. package/dist/FileTrigger.jsx.map +1 -0
  119. package/dist/Focusable.js +70 -0
  120. package/dist/Focusable.js.map +1 -0
  121. package/dist/Focusable.jsx +69 -0
  122. package/dist/Focusable.jsx.map +1 -0
  123. package/dist/Form.js +99 -0
  124. package/dist/Form.js.map +1 -0
  125. package/dist/Form.jsx +73 -0
  126. package/dist/Form.jsx.map +1 -0
  127. package/dist/GridList.d.ts +34 -2
  128. package/dist/GridList.d.ts.map +1 -1
  129. package/dist/GridList.js +723 -0
  130. package/dist/GridList.js.map +1 -0
  131. package/dist/GridList.jsx +552 -0
  132. package/dist/GridList.jsx.map +1 -0
  133. package/dist/Icon.d.ts.map +1 -1
  134. package/dist/Icon.js +127 -0
  135. package/dist/Icon.js.map +1 -0
  136. package/dist/Icon.jsx +72 -0
  137. package/dist/Icon.jsx.map +1 -0
  138. package/dist/Keyboard.js +30 -0
  139. package/dist/Keyboard.js.map +1 -0
  140. package/dist/Keyboard.jsx +24 -0
  141. package/dist/Keyboard.jsx.map +1 -0
  142. package/dist/Landmark.js +134 -0
  143. package/dist/Landmark.js.map +1 -0
  144. package/dist/Landmark.jsx +118 -0
  145. package/dist/Landmark.jsx.map +1 -0
  146. package/dist/Link.d.ts.map +1 -1
  147. package/dist/Link.js +219 -0
  148. package/dist/Link.js.map +1 -0
  149. package/dist/Link.jsx +189 -0
  150. package/dist/Link.jsx.map +1 -0
  151. package/dist/ListBox.d.ts +2 -2
  152. package/dist/ListBox.d.ts.map +1 -1
  153. package/dist/ListBox.js +831 -0
  154. package/dist/ListBox.js.map +1 -0
  155. package/dist/ListBox.jsx +644 -0
  156. package/dist/ListBox.jsx.map +1 -0
  157. package/dist/Menu.d.ts +27 -9
  158. package/dist/Menu.d.ts.map +1 -1
  159. package/dist/Menu.js +1254 -0
  160. package/dist/Menu.js.map +1 -0
  161. package/dist/Menu.jsx +1042 -0
  162. package/dist/Menu.jsx.map +1 -0
  163. package/dist/Meter.d.ts.map +1 -1
  164. package/dist/Meter.js +123 -0
  165. package/dist/Meter.js.map +1 -0
  166. package/dist/Meter.jsx +107 -0
  167. package/dist/Meter.jsx.map +1 -0
  168. package/dist/Modal.d.ts.map +1 -1
  169. package/dist/Modal.js +382 -0
  170. package/dist/Modal.js.map +1 -0
  171. package/dist/Modal.jsx +314 -0
  172. package/dist/Modal.jsx.map +1 -0
  173. package/dist/NumberField.d.ts +3 -3
  174. package/dist/NumberField.d.ts.map +1 -1
  175. package/dist/NumberField.js +573 -0
  176. package/dist/NumberField.js.map +1 -0
  177. package/dist/NumberField.jsx +443 -0
  178. package/dist/NumberField.jsx.map +1 -0
  179. package/dist/Popover.d.ts +10 -2
  180. package/dist/Popover.d.ts.map +1 -1
  181. package/dist/Popover.js +471 -0
  182. package/dist/Popover.js.map +1 -0
  183. package/dist/Popover.jsx +354 -0
  184. package/dist/Popover.jsx.map +1 -0
  185. package/dist/Pressable.js +69 -0
  186. package/dist/Pressable.js.map +1 -0
  187. package/dist/Pressable.jsx +68 -0
  188. package/dist/Pressable.jsx.map +1 -0
  189. package/dist/ProgressBar.d.ts.map +1 -1
  190. package/dist/ProgressBar.js +130 -0
  191. package/dist/ProgressBar.js.map +1 -0
  192. package/dist/ProgressBar.jsx +114 -0
  193. package/dist/ProgressBar.jsx.map +1 -0
  194. package/dist/RadioGroup.d.ts +82 -4
  195. package/dist/RadioGroup.d.ts.map +1 -1
  196. package/dist/RadioGroup.js +931 -0
  197. package/dist/RadioGroup.js.map +1 -0
  198. package/dist/RadioGroup.jsx +681 -0
  199. package/dist/RadioGroup.jsx.map +1 -0
  200. package/dist/RangeCalendar.d.ts.map +1 -1
  201. package/dist/RangeCalendar.js +546 -0
  202. package/dist/RangeCalendar.js.map +1 -0
  203. package/dist/RangeCalendar.jsx +323 -0
  204. package/dist/RangeCalendar.jsx.map +1 -0
  205. package/dist/RouterProvider.js +118 -0
  206. package/dist/RouterProvider.js.map +1 -0
  207. package/dist/RouterProvider.jsx +112 -0
  208. package/dist/RouterProvider.jsx.map +1 -0
  209. package/dist/SearchField.d.ts +2 -2
  210. package/dist/SearchField.d.ts.map +1 -1
  211. package/dist/SearchField.js +667 -0
  212. package/dist/SearchField.js.map +1 -0
  213. package/dist/SearchField.jsx +550 -0
  214. package/dist/SearchField.jsx.map +1 -0
  215. package/dist/Select.d.ts +7 -0
  216. package/dist/Select.d.ts.map +1 -1
  217. package/dist/Select.js +1044 -0
  218. package/dist/Select.js.map +1 -0
  219. package/dist/Select.jsx +759 -0
  220. package/dist/Select.jsx.map +1 -0
  221. package/dist/SelectionIndicator.d.ts.map +1 -1
  222. package/dist/SelectionIndicator.js +86 -0
  223. package/dist/SelectionIndicator.js.map +1 -0
  224. package/dist/SelectionIndicator.jsx +50 -0
  225. package/dist/SelectionIndicator.jsx.map +1 -0
  226. package/dist/Separator.js +97 -0
  227. package/dist/Separator.js.map +1 -0
  228. package/dist/Separator.jsx +85 -0
  229. package/dist/Separator.jsx.map +1 -0
  230. package/dist/SharedElementTransition.d.ts.map +1 -1
  231. package/dist/SharedElementTransition.js +167 -0
  232. package/dist/SharedElementTransition.js.map +1 -0
  233. package/dist/SharedElementTransition.jsx +140 -0
  234. package/dist/SharedElementTransition.jsx.map +1 -0
  235. package/dist/Slider.d.ts +33 -1
  236. package/dist/Slider.d.ts.map +1 -1
  237. package/dist/Slider.js +515 -0
  238. package/dist/Slider.js.map +1 -0
  239. package/dist/Slider.jsx +403 -0
  240. package/dist/Slider.jsx.map +1 -0
  241. package/dist/StepList.d.ts.map +1 -1
  242. package/dist/StepList.js +191 -0
  243. package/dist/StepList.js.map +1 -0
  244. package/dist/StepList.jsx +136 -0
  245. package/dist/StepList.jsx.map +1 -0
  246. package/dist/Switch.d.ts +65 -2
  247. package/dist/Switch.d.ts.map +1 -1
  248. package/dist/Switch.js +534 -0
  249. package/dist/Switch.js.map +1 -0
  250. package/dist/Switch.jsx +393 -0
  251. package/dist/Switch.jsx.map +1 -0
  252. package/dist/Table.d.ts +50 -0
  253. package/dist/Table.d.ts.map +1 -1
  254. package/dist/Table.js +1766 -0
  255. package/dist/Table.js.map +1 -0
  256. package/dist/Table.jsx +1355 -0
  257. package/dist/Table.jsx.map +1 -0
  258. package/dist/Tabs.d.ts +0 -4
  259. package/dist/Tabs.d.ts.map +1 -1
  260. package/dist/Tabs.js +598 -0
  261. package/dist/Tabs.js.map +1 -0
  262. package/dist/Tabs.jsx +367 -0
  263. package/dist/Tabs.jsx.map +1 -0
  264. package/dist/TagGroup.d.ts +3 -1
  265. package/dist/TagGroup.d.ts.map +1 -1
  266. package/dist/TagGroup.js +382 -0
  267. package/dist/TagGroup.js.map +1 -0
  268. package/dist/TagGroup.jsx +273 -0
  269. package/dist/TagGroup.jsx.map +1 -0
  270. package/dist/Text.d.ts +18 -6
  271. package/dist/Text.d.ts.map +1 -1
  272. package/dist/Text.js +42 -0
  273. package/dist/Text.js.map +1 -0
  274. package/dist/Text.jsx +35 -0
  275. package/dist/Text.jsx.map +1 -0
  276. package/dist/TextField.d.ts +6 -6
  277. package/dist/TextField.d.ts.map +1 -1
  278. package/dist/TextField.js +439 -0
  279. package/dist/TextField.js.map +1 -0
  280. package/dist/TextField.jsx +406 -0
  281. package/dist/TextField.jsx.map +1 -0
  282. package/dist/TimeField.d.ts +17 -53
  283. package/dist/TimeField.d.ts.map +1 -1
  284. package/dist/TimeField.js +278 -0
  285. package/dist/TimeField.js.map +1 -0
  286. package/dist/TimeField.jsx +218 -0
  287. package/dist/TimeField.jsx.map +1 -0
  288. package/dist/Toast.d.ts +14 -0
  289. package/dist/Toast.d.ts.map +1 -1
  290. package/dist/Toast.js +551 -0
  291. package/dist/Toast.js.map +1 -0
  292. package/dist/Toast.jsx +361 -0
  293. package/dist/Toast.jsx.map +1 -0
  294. package/dist/ToggleButton.d.ts.map +1 -1
  295. package/dist/ToggleButton.js +123 -0
  296. package/dist/ToggleButton.js.map +1 -0
  297. package/dist/ToggleButton.jsx +88 -0
  298. package/dist/ToggleButton.jsx.map +1 -0
  299. package/dist/ToggleButtonGroup.d.ts.map +1 -1
  300. package/dist/ToggleButtonGroup.js +114 -0
  301. package/dist/ToggleButtonGroup.js.map +1 -0
  302. package/dist/ToggleButtonGroup.jsx +85 -0
  303. package/dist/ToggleButtonGroup.jsx.map +1 -0
  304. package/dist/Toolbar.js +112 -0
  305. package/dist/Toolbar.js.map +1 -0
  306. package/dist/Toolbar.jsx +92 -0
  307. package/dist/Toolbar.jsx.map +1 -0
  308. package/dist/Tooltip.d.ts.map +1 -1
  309. package/dist/Tooltip.js +539 -0
  310. package/dist/Tooltip.js.map +1 -0
  311. package/dist/Tooltip.jsx +465 -0
  312. package/dist/Tooltip.jsx.map +1 -0
  313. package/dist/Tree.d.ts +14 -2
  314. package/dist/Tree.d.ts.map +1 -1
  315. package/dist/Tree.js +1424 -0
  316. package/dist/Tree.js.map +1 -0
  317. package/dist/Tree.jsx +1172 -0
  318. package/dist/Tree.jsx.map +1 -0
  319. package/dist/Virtualizer.d.ts +16 -2
  320. package/dist/Virtualizer.d.ts.map +1 -1
  321. package/dist/Virtualizer.js +2 -0
  322. package/dist/Virtualizer.jsx +2 -0
  323. package/dist/Virtualizer2.js +751 -0
  324. package/dist/Virtualizer2.js.map +1 -0
  325. package/dist/Virtualizer2.jsx +730 -0
  326. package/dist/Virtualizer2.jsx.map +1 -0
  327. package/dist/VirtualizerLayouts.d.ts +18 -0
  328. package/dist/VirtualizerLayouts.d.ts.map +1 -1
  329. package/dist/VisuallyHidden.js +42 -0
  330. package/dist/VisuallyHidden.js.map +1 -0
  331. package/dist/VisuallyHidden.jsx +35 -0
  332. package/dist/VisuallyHidden.jsx.map +1 -0
  333. package/dist/contexts.js +33 -0
  334. package/dist/contexts.js.map +1 -0
  335. package/dist/contexts.jsx +33 -0
  336. package/dist/contexts.jsx.map +1 -0
  337. package/dist/index.d.ts +9 -9
  338. package/dist/index.d.ts.map +1 -1
  339. package/dist/index.js +69 -23932
  340. package/dist/index.jsx +69 -18337
  341. package/dist/useDragAndDrop.d.ts +0 -8
  342. package/dist/useDragAndDrop.d.ts.map +1 -1
  343. package/dist/useDragAndDrop.js +2 -0
  344. package/dist/useDragAndDrop.jsx +2 -0
  345. package/dist/useDragAndDrop2.js +399 -0
  346. package/dist/useDragAndDrop2.js.map +1 -0
  347. package/dist/useDragAndDrop2.jsx +399 -0
  348. package/dist/useDragAndDrop2.jsx.map +1 -0
  349. package/dist/utils.d.ts +84 -11
  350. package/dist/utils.d.ts.map +1 -1
  351. package/dist/utils.js +285 -0
  352. package/dist/utils.js.map +1 -0
  353. package/dist/utils.jsx +277 -0
  354. package/dist/utils.jsx.map +1 -0
  355. package/dist/virtualizer/Layout.js +144 -0
  356. package/dist/virtualizer/Layout.js.map +1 -0
  357. package/dist/virtualizer/Layout.jsx +144 -0
  358. package/dist/virtualizer/Layout.jsx.map +1 -0
  359. package/package.json +395 -4
  360. package/src/ActionBar.tsx +10 -12
  361. package/src/ActionGroup.tsx +5 -3
  362. package/src/Autocomplete.tsx +14 -9
  363. package/src/Breadcrumbs.tsx +58 -39
  364. package/src/Button.tsx +22 -2
  365. package/src/Calendar.tsx +57 -11
  366. package/src/CalendarPicker.tsx +73 -0
  367. package/src/Checkbox.tsx +539 -3
  368. package/src/Collection.tsx +9 -3
  369. package/src/Color.tsx +84 -41
  370. package/src/ComboBox.tsx +97 -21
  371. package/src/DateField.tsx +304 -53
  372. package/src/DatePicker.tsx +402 -62
  373. package/src/DateRangePickerContext.tsx +2 -0
  374. package/src/Dialog.tsx +13 -5
  375. package/src/Disclosure.tsx +7 -1
  376. package/src/DragAndDrop.tsx +3 -1
  377. package/src/DropZone.tsx +3 -1
  378. package/src/GridList.tsx +133 -26
  379. package/src/Icon.tsx +3 -1
  380. package/src/Link.tsx +3 -1
  381. package/src/ListBox.tsx +354 -25
  382. package/src/Menu.tsx +252 -128
  383. package/src/Meter.tsx +3 -1
  384. package/src/Modal.tsx +120 -56
  385. package/src/NumberField.tsx +51 -8
  386. package/src/Popover.tsx +68 -17
  387. package/src/ProgressBar.tsx +3 -1
  388. package/src/RadioGroup.tsx +468 -4
  389. package/src/RangeCalendar.tsx +123 -2
  390. package/src/SearchField.tsx +80 -4
  391. package/src/Select.tsx +122 -26
  392. package/src/SelectionIndicator.tsx +3 -1
  393. package/src/SharedElementTransition.tsx +95 -37
  394. package/src/Slider.tsx +159 -13
  395. package/src/StepList.tsx +0 -7
  396. package/src/Switch.tsx +395 -2
  397. package/src/Table.tsx +428 -99
  398. package/src/Tabs.tsx +17 -45
  399. package/src/TagGroup.tsx +29 -7
  400. package/src/Text.tsx +31 -10
  401. package/src/TextField.tsx +44 -6
  402. package/src/TimeField.tsx +127 -192
  403. package/src/Toast.tsx +79 -14
  404. package/src/ToggleButton.tsx +3 -1
  405. package/src/ToggleButtonGroup.tsx +3 -1
  406. package/src/Tooltip.tsx +3 -1
  407. package/src/Tree.tsx +91 -13
  408. package/src/Virtualizer.tsx +180 -31
  409. package/src/VirtualizerLayouts.ts +45 -10
  410. package/src/index.ts +51 -8
  411. package/src/useDragAndDrop.ts +8 -10
  412. package/src/utils.tsx +246 -30
  413. package/dist/HiddenTimeInput.d.ts +0 -25
  414. package/dist/HiddenTimeInput.d.ts.map +0 -1
  415. package/dist/index.js.map +0 -1
  416. package/dist/index.jsx.map +0 -1
  417. package/src/HiddenTimeInput.tsx +0 -133
package/src/Table.tsx CHANGED
@@ -14,6 +14,7 @@ import {
14
14
  createSignal,
15
15
  onCleanup,
16
16
  splitProps,
17
+ untrack,
17
18
  useContext,
18
19
  For,
19
20
  Show,
@@ -36,6 +37,7 @@ import {
36
37
  } from "@proyecto-viviana/solidaria";
37
38
  import {
38
39
  createTableState,
40
+ createTreeGridState,
39
41
  createTableCollection,
40
42
  createTableColumnResizeState,
41
43
  type TableState,
@@ -44,9 +46,11 @@ import {
44
46
  type Key,
45
47
  type SortDescriptor,
46
48
  type ColumnDefinition,
49
+ type RowDefinition,
47
50
  type ColumnSize,
48
51
  type GridNode,
49
52
  type DropTarget,
53
+ type Collection,
50
54
  } from "@proyecto-viviana/solid-stately";
51
55
  import {
52
56
  type RenderChildren,
@@ -59,7 +63,7 @@ import {
59
63
  } from "./utils";
60
64
  import { SharedElementTransition } from "./SharedElementTransition";
61
65
  import { type DragAndDropHooks } from "./useDragAndDrop";
62
- import { ButtonContext, type ButtonProps } from "./Button";
66
+ import { ButtonContext, type ButtonContextValue, type ButtonProps } from "./Button";
63
67
  import {
64
68
  CollectionRendererContext,
65
69
  type CollectionRendererContextValue,
@@ -122,6 +126,35 @@ function normalizeColumnDefinitions<T>(
122
126
  });
123
127
  }
124
128
 
129
+ /** Resolves a stable, unique key for a tree-grid item (keys must be unique across levels). */
130
+ function resolveItemKey<T>(item: T, getKey: ((item: T) => Key) | undefined, index: number): Key {
131
+ if (getKey) return getKey(item);
132
+ const record = item as { id?: Key; key?: Key };
133
+ return record.id ?? record.key ?? index;
134
+ }
135
+
136
+ /**
137
+ * Turns the flat `items` into nested {@link RowDefinition}s by recursively expanding each
138
+ * item's children via `getChildItems`. The result feeds the tree-grid collection.
139
+ */
140
+ function toTreeRowDefinitions<T>(
141
+ items: Iterable<T>,
142
+ getKey: ((item: T) => Key) | undefined,
143
+ getChildItems: ((item: T) => Iterable<T> | undefined) | undefined,
144
+ ): RowDefinition<T>[] {
145
+ return Array.from(items).map((item, index) => {
146
+ const childItems = getChildItems?.(item);
147
+ const childRows = childItems
148
+ ? toTreeRowDefinitions(childItems, getKey, getChildItems)
149
+ : undefined;
150
+ return {
151
+ key: resolveItemKey(item, getKey, index),
152
+ value: item,
153
+ childRows: childRows && childRows.length > 0 ? childRows : undefined,
154
+ };
155
+ });
156
+ }
157
+
125
158
  function getRowHeaderColumnKeys<T>(columns: (ColumnDefinition<T> & { id?: Key })[]): Set<Key> {
126
159
  const keys = new Set<Key>();
127
160
 
@@ -192,6 +225,18 @@ export interface TableProps<T extends object> extends Omit<AriaTableProps, "chil
192
225
  ) => JSX.Element;
193
226
  /** Drag and drop hooks from `useDragAndDrop`. */
194
227
  dragAndDropHooks?: DragAndDropHooks<T>;
228
+ /**
229
+ * Derives the child rows of an item, turning the flat `items` into a tree grid
230
+ * (expandable rows). Providing this — or any `UNSTABLE_*expandedKeys` prop — switches the
231
+ * table into tree-grid mode. Mirrors `@react-aria/table`'s `UNSTABLE_` tree-grid feature.
232
+ */
233
+ UNSTABLE_childItems?: (item: T) => Iterable<T> | undefined;
234
+ /** The currently expanded row keys (controlled). Tree grid only. */
235
+ UNSTABLE_expandedKeys?: "all" | Iterable<Key>;
236
+ /** The initial expanded row keys (uncontrolled). Tree grid only. */
237
+ UNSTABLE_defaultExpandedKeys?: "all" | Iterable<Key>;
238
+ /** Handler called when rows are expanded or collapsed. Tree grid only. */
239
+ UNSTABLE_onExpandedChange?: (keys: Set<Key>) => void;
195
240
  }
196
241
 
197
242
  export interface TableHeaderRenderProps {
@@ -324,6 +369,21 @@ export interface TableRowRenderProps {
324
369
  isHovered: boolean;
325
370
  /** Whether the row is disabled. */
326
371
  isDisabled: boolean;
372
+ /**
373
+ * Whether the row is expanded (tree grid only; `false` for a flat table).
374
+ * @selector [data-expanded]
375
+ */
376
+ isExpanded: boolean;
377
+ /**
378
+ * Whether the row has child rows (tree grid only; `false` for a flat table).
379
+ * @selector [data-has-child-items]
380
+ */
381
+ hasChildItems: boolean;
382
+ /**
383
+ * The 1-based nesting depth of the row within the table (1 for a flat table).
384
+ * @selector [data-level]
385
+ */
386
+ level: number;
327
387
  }
328
388
 
329
389
  export interface TableRowProps<T> extends SlotProps {
@@ -380,6 +440,27 @@ export interface TableCellRenderProps {
380
440
  isPressed: boolean;
381
441
  /** Whether the cell is hovered. */
382
442
  isHovered: boolean;
443
+ /**
444
+ * Whether the cell is in the tree column — the one that renders the expand/collapse
445
+ * chevron and nesting indentation (tree grid only; `false` for a flat table).
446
+ * @selector [data-tree-column]
447
+ */
448
+ isTreeColumn: boolean;
449
+ /**
450
+ * Whether the cell's row is expanded (tree grid only; `false` for a flat table).
451
+ * @selector [data-expanded]
452
+ */
453
+ isExpanded: boolean;
454
+ /**
455
+ * Whether the cell's row has child rows (tree grid only; `false` for a flat table).
456
+ * @selector [data-has-child-items]
457
+ */
458
+ hasChildItems: boolean;
459
+ /**
460
+ * The 1-based nesting depth of the cell's row within the table (1 for a flat table).
461
+ * @selector [data-level]
462
+ */
463
+ level: number;
383
464
  }
384
465
 
385
466
  export interface TableCellProps extends SlotProps {
@@ -443,6 +524,8 @@ export const TableColumnResizeStateContext = createContext<{
443
524
  interface TableRowContextValue {
444
525
  rowKey: Key;
445
526
  rowNode: GridNode<unknown>;
527
+ /** The row's resolved disabled state, so a child selection checkbox can gate on it. */
528
+ isRowDisabled: boolean;
446
529
  getCellColumnKey(cellId: string, explicitId?: Key): Key | undefined;
447
530
  }
448
531
 
@@ -472,6 +555,10 @@ export function Table<T extends object>(props: TableProps<T>): JSX.Element {
472
555
  "sortDescriptor",
473
556
  "onSortChange",
474
557
  "showSelectionCheckboxes",
558
+ "UNSTABLE_childItems",
559
+ "UNSTABLE_expandedKeys",
560
+ "UNSTABLE_defaultExpandedKeys",
561
+ "UNSTABLE_onExpandedChange",
475
562
  ],
476
563
  );
477
564
 
@@ -479,34 +566,71 @@ export function Table<T extends object>(props: TableProps<T>): JSX.Element {
479
566
  const normalizedColumns = createMemo(() => normalizeColumnDefinitions(stateProps.columns));
480
567
  const rowHeaderColumnKeys = createMemo(() => getRowHeaderColumnKeys(normalizedColumns()));
481
568
 
482
- const collection = createMemo(() =>
483
- createTableCollection<T>({
484
- columns: normalizedColumns(),
485
- rows: stateProps.items,
486
- getKey: stateProps.getKey,
487
- getTextValue: stateProps.getTextValue as
488
- | ((item: T, column: ColumnDefinition<T>) => string)
489
- | undefined,
490
- showSelectionCheckboxes: stateProps.showSelectionCheckboxes ?? false,
491
- rowHeaderColumnKeys: rowHeaderColumnKeys().size > 0 ? rowHeaderColumnKeys() : undefined,
492
- }),
493
- );
494
-
495
- const state = createTableState<T, TableCollection<T>>(() => ({
496
- collection: collection(),
497
- disabledKeys: stateProps.disabledKeys,
498
- selectionMode: stateProps.selectionMode,
499
- selectionBehavior: stateProps.selectionBehavior,
500
- selectedKeys: stateProps.selectedKeys,
501
- defaultSelectedKeys: stateProps.defaultSelectedKeys,
502
- onSelectionChange: stateProps.onSelectionChange,
503
- sortDescriptor: stateProps.sortDescriptor,
504
- onSortChange: stateProps.onSortChange,
505
- showSelectionCheckboxes: stateProps.showSelectionCheckboxes,
506
- }));
569
+ // Tree-grid mode is selected structurally by the presence of any expansion prop. Like
570
+ // controlled-vs-uncontrolled, this is a one-time decision, not a reactive toggle.
571
+ const isTreeGrid =
572
+ stateProps.UNSTABLE_childItems !== undefined ||
573
+ stateProps.UNSTABLE_expandedKeys !== undefined ||
574
+ stateProps.UNSTABLE_defaultExpandedKeys !== undefined ||
575
+ stateProps.UNSTABLE_onExpandedChange !== undefined;
576
+
577
+ const getTextValue = () =>
578
+ stateProps.getTextValue as ((item: T, column: ColumnDefinition<T>) => string) | undefined;
579
+
580
+ const state: TableState<T, TableCollection<T>> = isTreeGrid
581
+ ? createTreeGridState<T, TableCollection<T>>(() => ({
582
+ columns: normalizedColumns(),
583
+ rows: toTreeRowDefinitions(
584
+ stateProps.items,
585
+ stateProps.getKey,
586
+ stateProps.UNSTABLE_childItems,
587
+ ),
588
+ getKey: stateProps.getKey,
589
+ getTextValue: getTextValue(),
590
+ showSelectionCheckboxes: stateProps.showSelectionCheckboxes ?? false,
591
+ rowHeaderColumnKeys: rowHeaderColumnKeys().size > 0 ? rowHeaderColumnKeys() : undefined,
592
+ disabledKeys: stateProps.disabledKeys,
593
+ disabledBehavior: stateProps.disabledBehavior,
594
+ selectionMode: stateProps.selectionMode,
595
+ selectionBehavior: stateProps.selectionBehavior,
596
+ selectedKeys: stateProps.selectedKeys,
597
+ defaultSelectedKeys: stateProps.defaultSelectedKeys,
598
+ onSelectionChange: stateProps.onSelectionChange,
599
+ sortDescriptor: stateProps.sortDescriptor,
600
+ onSortChange: stateProps.onSortChange,
601
+ UNSTABLE_expandedKeys: stateProps.UNSTABLE_expandedKeys,
602
+ UNSTABLE_defaultExpandedKeys: stateProps.UNSTABLE_defaultExpandedKeys,
603
+ UNSTABLE_onExpandedChange: stateProps.UNSTABLE_onExpandedChange,
604
+ }))
605
+ : createTableState<T, TableCollection<T>>(() => ({
606
+ collection: createTableCollection<T>({
607
+ columns: normalizedColumns(),
608
+ rows: stateProps.items,
609
+ getKey: stateProps.getKey,
610
+ getTextValue: getTextValue(),
611
+ showSelectionCheckboxes: stateProps.showSelectionCheckboxes ?? false,
612
+ rowHeaderColumnKeys: rowHeaderColumnKeys().size > 0 ? rowHeaderColumnKeys() : undefined,
613
+ }),
614
+ disabledKeys: stateProps.disabledKeys,
615
+ disabledBehavior: stateProps.disabledBehavior,
616
+ selectionMode: stateProps.selectionMode,
617
+ selectionBehavior: stateProps.selectionBehavior,
618
+ selectedKeys: stateProps.selectedKeys,
619
+ defaultSelectedKeys: stateProps.defaultSelectedKeys,
620
+ onSelectionChange: stateProps.onSelectionChange,
621
+ sortDescriptor: stateProps.sortDescriptor,
622
+ onSortChange: stateProps.onSortChange,
623
+ showSelectionCheckboxes: stateProps.showSelectionCheckboxes,
624
+ }));
625
+ const collection = () => state.collection;
507
626
  const parentCollectionRenderer = useCollectionRenderer<T>();
508
627
 
509
- const { gridProps } = createTable<T>(
628
+ // Keep the hook's return object (do NOT destructure `gridProps`): the grid's
629
+ // sort-description `aria-describedby` is emitted via a `createDescription`
630
+ // effect that resolves its id AFTER the first render, so `gridProps` must be
631
+ // read reactively through the getter. Destructuring would freeze the initial
632
+ // (describedby-less) snapshot. Mirrors how columnHeader/row aria is consumed.
633
+ const tableAria = createTable<T>(
510
634
  () => ({
511
635
  id: ariaProps.id,
512
636
  "aria-label": ariaProps["aria-label"],
@@ -549,7 +673,7 @@ export function Table<T extends object>(props: TableProps<T>): JSX.Element {
549
673
  });
550
674
 
551
675
  const cleanGridProps = () => {
552
- const { ref: _ref1, ...rest } = gridProps as Record<string, unknown>;
676
+ const { ref: _ref1, ...rest } = tableAria.gridProps as Record<string, unknown>;
553
677
  return rest;
554
678
  };
555
679
  const cleanFocusProps = () => {
@@ -641,8 +765,11 @@ export function Table<T extends object>(props: TableProps<T>): JSX.Element {
641
765
  getKeyPageBelow: (key) => state.collection.getKeyAfter?.(key) ?? null,
642
766
  getKeyPageAbove: (key) => state.collection.getKeyBefore?.(key) ?? null,
643
767
  },
768
+ // TableCollection carries a wider node.type union (GridNode's 'cell'/
769
+ // 'column') than the narrow Collection option, but is structurally a
770
+ // valid Collection for navigate()/focus restoration — cast at the seam.
644
771
  get collection() {
645
- return state.collection;
772
+ return state.collection as unknown as Collection;
646
773
  },
647
774
  get selectedKeys() {
648
775
  return state.selectedKeys;
@@ -707,8 +834,16 @@ export function Table<T extends object>(props: TableProps<T>): JSX.Element {
707
834
  dndDropIndicator(index, position) ??
708
835
  parentCollectionRenderer?.renderDropIndicator?.(index, position),
709
836
  }));
837
+ // The root children function builds the structural `<TableHeader>`/`<TableBody>`
838
+ // subtree once. React re-invokes it on every render and reconciles the result, so
839
+ // reading focus-dependent render values (isFocused/isFocusVisible) there is cheap.
840
+ // Solid has no reconciliation: re-invoking recreates the entire thead/tbody subtree,
841
+ // which detaches the DOM-focused row and drops keyboard focus (Space/Enter never reach
842
+ // the row). So invoke it with an untracked snapshot of the render values — the insert
843
+ // below stays stable across focus changes while children still see current values at
844
+ // creation. Render values for collection structure are not reactive in practice.
710
845
  const tableChildren = () =>
711
- typeof props.children === "function" ? props.children(renderValues()) : props.children;
846
+ typeof props.children === "function" ? props.children(untrack(renderValues)) : props.children;
712
847
  const tableProps = () =>
713
848
  ({
714
849
  ref: (el: HTMLTableElement) => {
@@ -728,7 +863,6 @@ export function Table<T extends object>(props: TableProps<T>): JSX.Element {
728
863
  "data-empty": stateProps.items.length === 0 || undefined,
729
864
  "data-drop-target": isRootDropTarget() || undefined,
730
865
  slot: local.slot,
731
- children: tableChildren(),
732
866
  }) as JSX.HTMLAttributes<HTMLTableElement>;
733
867
 
734
868
  return (
@@ -737,7 +871,11 @@ export function Table<T extends object>(props: TableProps<T>): JSX.Element {
737
871
  value={state as unknown as TableState<object, TableCollection<object>>}
738
872
  >
739
873
  <CollectionRendererContext.Provider value={collectionRenderer()}>
740
- {local.render ? local.render(tableProps(), renderValues()) : <table {...tableProps()} />}
874
+ {local.render ? (
875
+ local.render({ ...tableProps(), children: tableChildren() }, renderValues())
876
+ ) : (
877
+ <table {...tableProps()}>{tableChildren()}</table>
878
+ )}
741
879
  </CollectionRendererContext.Provider>
742
880
  </TableStateContext.Provider>
743
881
  </TableContext.Provider>
@@ -1071,6 +1209,8 @@ export function TableBody<T extends object>(props: TableBodyProps<T>): JSX.Eleme
1071
1209
  context.collection,
1072
1210
  );
1073
1211
  const virtualRange = createMemo(() => {
1212
+ // Tree grids render every visible (flattened) row; virtual windowing is a follow-up.
1213
+ if (context.state.treeColumn != null) return null;
1074
1214
  if (!virtualizer || !parentCollectionRenderer?.isVirtualized) return null;
1075
1215
  const rowCount = items().length;
1076
1216
  const baseRange = virtualizer.getVisibleRange(rowCount);
@@ -1125,6 +1265,11 @@ export function TableBody<T extends object>(props: TableBodyProps<T>): JSX.Eleme
1125
1265
  });
1126
1266
  });
1127
1267
  const visibleItems = createMemo(() => {
1268
+ // Tree grid: render the flattened set of visible rows (top-level + expanded descendants)
1269
+ // the collection materialises in document order, so the render fn runs once per visible row.
1270
+ if (context.state.treeColumn != null) {
1271
+ return rowNodes().map((node) => node.value as T);
1272
+ }
1128
1273
  const range = virtualRange();
1129
1274
  if (!range) return items();
1130
1275
  return items().slice(range.start, range.end);
@@ -1435,7 +1580,7 @@ export function TableRow<T extends object>(props: TableRowProps<T>): JSX.Element
1435
1580
  if (!context) {
1436
1581
  throw new Error("TableRow must be used within a Table");
1437
1582
  }
1438
- const { state, collection } = context;
1583
+ const { state } = context;
1439
1584
  const tableContext = context as unknown as TableContextValue<T>;
1440
1585
  const registeredCellIds: string[] = [];
1441
1586
  const generatedId = createUniqueId();
@@ -1454,8 +1599,10 @@ export function TableRow<T extends object>(props: TableRowProps<T>): JSX.Element
1454
1599
 
1455
1600
  const [ref, setRef] = createSignal<HTMLTableRowElement | null>(null);
1456
1601
 
1602
+ // Read through `state.collection` (not the destructured snapshot) so the node tracks
1603
+ // collection rebuilds — e.g. a tree-grid row staying mounted across an expand/collapse.
1457
1604
  const rowNode = createMemo(() => {
1458
- const node = collection.getItem(rowKey());
1605
+ const node = state.collection.getItem(rowKey());
1459
1606
  if (!node) {
1460
1607
  return {
1461
1608
  type: "item" as const,
@@ -1492,7 +1639,12 @@ export function TableRow<T extends object>(props: TableRowProps<T>): JSX.Element
1492
1639
  const isPressed = () => rowAria.isPressed;
1493
1640
  const isInteractive = () => {
1494
1641
  const tableData = getTableData(state as TableState<object, TableCollection<object>>);
1495
- return state.selectionMode !== "none" || !!tableData?.actions.onRowAction || !!local.onAction;
1642
+ return (
1643
+ state.selectionMode !== "none" ||
1644
+ !!tableData?.actions.onRowAction ||
1645
+ !!local.onAction ||
1646
+ !!local.href
1647
+ );
1496
1648
  };
1497
1649
 
1498
1650
  const { isHovered, hoverProps } = createHover({
@@ -1549,6 +1701,13 @@ export function TableRow<T extends object>(props: TableRowProps<T>): JSX.Element
1549
1701
  );
1550
1702
  });
1551
1703
 
1704
+ // Tree-grid (expandable rows): nesting depth, child presence and expansion. These are
1705
+ // inert for a flat table (level 1, no children, not expanded).
1706
+ const isTreeRow = () => state.treeColumn != null;
1707
+ const rowLevel = () => rowNode().level + 1;
1708
+ const hasChildItems = () => rowAria.hasChildRows;
1709
+ const isExpanded = () => rowAria.isExpanded;
1710
+
1552
1711
  const renderValues = createMemo<TableRowRenderProps>(() => ({
1553
1712
  isSelected: isSelected(),
1554
1713
  isFocused: isFocused(),
@@ -1556,6 +1715,9 @@ export function TableRow<T extends object>(props: TableRowProps<T>): JSX.Element
1556
1715
  isPressed: isPressed(),
1557
1716
  isHovered: isHovered(),
1558
1717
  isDisabled: isDisabled(),
1718
+ isExpanded: isExpanded(),
1719
+ hasChildItems: hasChildItems(),
1720
+ level: rowLevel(),
1559
1721
  }));
1560
1722
 
1561
1723
  // Resolve render props (children rendered directly in JSX to avoid eager evaluation)
@@ -1584,6 +1746,9 @@ export function TableRow<T extends object>(props: TableRowProps<T>): JSX.Element
1584
1746
  const rowContextValue: TableRowContextValue = {
1585
1747
  rowKey: rowKey(),
1586
1748
  rowNode: rowNode(),
1749
+ get isRowDisabled() {
1750
+ return isDisabled();
1751
+ },
1587
1752
  getCellColumnKey(cellId, explicitId) {
1588
1753
  if (explicitId === "__selection__") {
1589
1754
  return explicitId;
@@ -1610,73 +1775,197 @@ export function TableRow<T extends object>(props: TableRowProps<T>): JSX.Element
1610
1775
  },
1611
1776
  };
1612
1777
  });
1613
- const buttonContextValue = createMemo(() => ({
1778
+ // A STABLE context object: its identity never changes, so the surrounding ButtonContext.Provider
1779
+ // never tears down and recreates the row's children. The slots are getters, so a slotted
1780
+ // <Button slot="drag"|"chevron"> reads the current drag/expand props each time it is (re)created —
1781
+ // e.g. when the tree column recreates the chevron on expand/collapse.
1782
+ const buttonContextValue: ButtonContextValue = {
1614
1783
  slots: {
1615
1784
  default: {},
1616
- drag: dragButtonProps(),
1785
+ get drag() {
1786
+ return dragButtonProps();
1787
+ },
1788
+ // Tree-grid expand/collapse chevron; the slotted <Button slot="chevron"> picks these up.
1789
+ // The aria hook yields DOM button attributes, merged onto the Button as passthrough props.
1790
+ get chevron() {
1791
+ return rowAria.expandButtonProps as unknown as ButtonProps;
1792
+ },
1617
1793
  },
1618
- }));
1794
+ };
1619
1795
 
1620
- const rowChildren = () => (
1621
- <ButtonContext.Provider value={buttonContextValue()}>
1622
- {typeof local.children === "function" ? (
1623
- local.columns ? (
1624
- <For each={local.columns}>
1625
- {(column) =>
1626
- (local.children as (column: TableColumnDefinition<T>) => JSX.Element)(column)
1627
- }
1628
- </For>
1629
- ) : (
1630
- (local.children as (renderProps: TableRowRenderProps) => JSX.Element)(renderValues())
1631
- )
1632
- ) : (
1633
- local.children
1634
- )}
1635
- </ButtonContext.Provider>
1636
- );
1637
- const tableRowProps = () =>
1638
- ({
1639
- ref: (el: HTMLTableRowElement) => {
1640
- setRef(el);
1641
- assignRef(local.ref, el);
1642
- },
1643
- ...domProps,
1644
- ...mergeProps(
1645
- cleanRowProps(),
1646
- cleanHoverProps(),
1647
- cleanFocusProps(),
1648
- focusWithinProps as Record<string, unknown>,
1649
- (draggableItem()?.dragProps as Record<string, unknown> | undefined) ?? {},
1650
- (droppableItem()?.dropProps as Record<string, unknown> | undefined) ?? {},
1651
- ),
1652
- class: renderProps.class(),
1653
- style: renderProps.style(),
1654
- "data-selected": isSelected() || undefined,
1655
- "data-focused": isFocused() || undefined,
1656
- "data-focus-visible": (isFocusVisible() && isFocused()) || undefined,
1657
- "data-focus-visible-within": dataAttr(isFocusWithin() && isGlobalFocusVisible()),
1658
- "data-pressed": isPressed() || undefined,
1659
- "data-hovered": isHovered() || undefined,
1660
- "data-disabled": isDisabled() || undefined,
1661
- "data-href": linkProps().href,
1662
- "data-target": linkProps().target,
1663
- "data-rel": linkProps().rel,
1664
- "data-download":
1665
- typeof linkProps().download === "string"
1666
- ? linkProps().download
1667
- : linkProps().download
1668
- ? ""
1669
- : undefined,
1670
- "data-ping": linkProps().ping,
1671
- "data-referrer-policy": linkProps().referrerPolicy,
1672
- "data-dragging": draggableItem()?.isDragging || undefined,
1673
- "data-drop-target": droppableItem()?.isDropTarget || undefined,
1674
- children: rowChildren(),
1675
- }) as JSX.HTMLAttributes<HTMLTableRowElement>;
1796
+ // Render props handed to the row's children as a STABLE getter proxy: reading a getter stays
1797
+ // fine-grained reactive at the point of use, without forcing the children to be re-derived (and
1798
+ // therefore disposed + recreated) whenever an unrelated render prop flips.
1799
+ const childRenderProps: TableRowRenderProps = {
1800
+ get isSelected() {
1801
+ return isSelected();
1802
+ },
1803
+ get isFocused() {
1804
+ return isFocused();
1805
+ },
1806
+ get isFocusVisible() {
1807
+ return isFocusVisible() && isFocused();
1808
+ },
1809
+ get isPressed() {
1810
+ return isPressed();
1811
+ },
1812
+ get isHovered() {
1813
+ return isHovered();
1814
+ },
1815
+ get isDisabled() {
1816
+ return isDisabled();
1817
+ },
1818
+ get isExpanded() {
1819
+ return isExpanded();
1820
+ },
1821
+ get hasChildItems() {
1822
+ return hasChildItems();
1823
+ },
1824
+ get level() {
1825
+ return rowLevel();
1826
+ },
1827
+ };
1828
+
1829
+ // Tree-grid rows carry their nesting depth as a CSS var so the tree column can indent.
1830
+ const rowStyle = () => {
1831
+ const base = renderProps.style();
1832
+ if (!isTreeRow()) return base;
1833
+ return { ...(base ?? {}), "--table-row-level": rowLevel() } as JSX.CSSProperties;
1834
+ };
1676
1835
 
1677
1836
  return (
1678
1837
  <TableRowContext.Provider value={rowContextValue}>
1679
- {local.render ? local.render(tableRowProps(), renderValues()) : <tr {...tableRowProps()} />}
1838
+ <ButtonContext.Provider value={buttonContextValue}>
1839
+ {(() => {
1840
+ // Build the row's children HERE — inside BOTH providers — so each cell instantiates under
1841
+ // this owner. TableCell/EditableCell read TableRowContext, and a slotted
1842
+ // <Button slot="drag"|"chevron"> reads ButtonContext; in Solid useContext binds at the
1843
+ // owner active when the component executes, so the children must be created inside the
1844
+ // providers, not merely wrapped by them afterwards. They are built EXACTLY ONCE: a press
1845
+ // or focus bubbling up from interactive cell content (e.g. an EditableCell's edit button)
1846
+ // flips the row's render-props signals, and re-deriving the children on every such change
1847
+ // would dispose and recreate the subtree, destroying the in-flight press. Cells claim
1848
+ // their column by render order (see getCellColumnKey), so reset the registry once before
1849
+ // this single pass.
1850
+ registeredCellIds.length = 0;
1851
+ const rowChildrenContent =
1852
+ typeof local.children === "function" ? (
1853
+ local.columns ? (
1854
+ <For each={local.columns}>
1855
+ {(column) =>
1856
+ (local.children as (column: TableColumnDefinition<T>) => JSX.Element)(column)
1857
+ }
1858
+ </For>
1859
+ ) : (
1860
+ (local.children as (renderProps: TableRowRenderProps) => JSX.Element)(
1861
+ childRenderProps,
1862
+ )
1863
+ )
1864
+ ) : (
1865
+ local.children
1866
+ );
1867
+ const tableRowProps = () =>
1868
+ ({
1869
+ ref: (el: HTMLTableRowElement) => {
1870
+ setRef(el);
1871
+ assignRef(local.ref, el);
1872
+ },
1873
+ ...domProps,
1874
+ ...mergeProps(
1875
+ cleanRowProps(),
1876
+ cleanHoverProps(),
1877
+ cleanFocusProps(),
1878
+ focusWithinProps as Record<string, unknown>,
1879
+ (draggableItem()?.dragProps as Record<string, unknown> | undefined) ?? {},
1880
+ (droppableItem()?.dropProps as Record<string, unknown> | undefined) ?? {},
1881
+ ),
1882
+ class: renderProps.class(),
1883
+ style: rowStyle(),
1884
+ "data-key": rowKey(),
1885
+ "data-selected": isSelected() || undefined,
1886
+ "data-focused": isFocused() || undefined,
1887
+ "data-focus-visible": (isFocusVisible() && isFocused()) || undefined,
1888
+ "data-focus-visible-within": dataAttr(isFocusWithin() && isGlobalFocusVisible()),
1889
+ "data-pressed": isPressed() || undefined,
1890
+ "data-hovered": isHovered() || undefined,
1891
+ "data-disabled": isDisabled() || undefined,
1892
+ "data-href": linkProps().href,
1893
+ "data-target": linkProps().target,
1894
+ "data-rel": linkProps().rel,
1895
+ "data-download":
1896
+ typeof linkProps().download === "string"
1897
+ ? linkProps().download
1898
+ : linkProps().download
1899
+ ? ""
1900
+ : undefined,
1901
+ "data-ping": linkProps().ping,
1902
+ "data-referrer-policy": linkProps().referrerPolicy,
1903
+ "data-dragging": draggableItem()?.isDragging || undefined,
1904
+ "data-drop-target": droppableItem()?.isDropTarget || undefined,
1905
+ "data-expanded": (isTreeRow() && isExpanded()) || undefined,
1906
+ "data-has-child-items": (isTreeRow() && hasChildItems()) || undefined,
1907
+ "data-level": isTreeRow() ? rowLevel() : undefined,
1908
+ children: rowChildrenContent,
1909
+ }) as JSX.HTMLAttributes<HTMLTableRowElement>;
1910
+
1911
+ return (
1912
+ <Show
1913
+ when={local.render}
1914
+ fallback={
1915
+ // Bind attributes individually on a STABLE <tr> (mirroring TableCell) so a
1916
+ // render-props change updates attributes in place instead of recreating the element
1917
+ // and its subtree.
1918
+ <tr
1919
+ ref={(el: HTMLTableRowElement) => {
1920
+ setRef(el);
1921
+ assignRef(local.ref, el);
1922
+ }}
1923
+ {...domProps}
1924
+ {...mergeProps(
1925
+ cleanRowProps(),
1926
+ cleanHoverProps(),
1927
+ cleanFocusProps(),
1928
+ focusWithinProps as Record<string, unknown>,
1929
+ (draggableItem()?.dragProps as Record<string, unknown> | undefined) ?? {},
1930
+ (droppableItem()?.dropProps as Record<string, unknown> | undefined) ?? {},
1931
+ )}
1932
+ class={renderProps.class()}
1933
+ style={rowStyle()}
1934
+ data-key={rowKey()}
1935
+ data-selected={isSelected() || undefined}
1936
+ data-focused={isFocused() || undefined}
1937
+ data-focus-visible={(isFocusVisible() && isFocused()) || undefined}
1938
+ data-focus-visible-within={dataAttr(isFocusWithin() && isGlobalFocusVisible())}
1939
+ data-pressed={isPressed() || undefined}
1940
+ data-hovered={isHovered() || undefined}
1941
+ data-disabled={isDisabled() || undefined}
1942
+ data-href={linkProps().href}
1943
+ data-target={linkProps().target}
1944
+ data-rel={linkProps().rel}
1945
+ data-download={
1946
+ typeof linkProps().download === "string"
1947
+ ? linkProps().download
1948
+ : linkProps().download
1949
+ ? ""
1950
+ : undefined
1951
+ }
1952
+ data-ping={linkProps().ping}
1953
+ data-referrer-policy={linkProps().referrerPolicy}
1954
+ data-dragging={draggableItem()?.isDragging || undefined}
1955
+ data-drop-target={droppableItem()?.isDropTarget || undefined}
1956
+ data-expanded={(isTreeRow() && isExpanded()) || undefined}
1957
+ data-has-child-items={(isTreeRow() && hasChildItems()) || undefined}
1958
+ data-level={isTreeRow() ? rowLevel() : undefined}
1959
+ >
1960
+ {rowChildrenContent}
1961
+ </tr>
1962
+ }
1963
+ >
1964
+ {local.render!(tableRowProps(), renderValues())}
1965
+ </Show>
1966
+ );
1967
+ })()}
1968
+ </ButtonContext.Provider>
1680
1969
  </TableRowContext.Provider>
1681
1970
  );
1682
1971
  }
@@ -1706,7 +1995,7 @@ export function TableCell(props: TableCellProps): JSX.Element {
1706
1995
  throw new Error("TableCell must be used within a Table");
1707
1996
  }
1708
1997
 
1709
- const { state, collection } = tableContext;
1998
+ const { state } = tableContext;
1710
1999
  const { rowKey, rowNode } = rowContext;
1711
2000
 
1712
2001
  const [ref, setRef] = createSignal<HTMLTableCellElement | null>(null);
@@ -1717,7 +2006,7 @@ export function TableCell(props: TableCellProps): JSX.Element {
1717
2006
  const key = columnKey();
1718
2007
  if (key != null) {
1719
2008
  const cellKey = `${rowKey}-${key}`;
1720
- const node = collection.getItem(cellKey);
2009
+ const node = state.collection.getItem(cellKey);
1721
2010
  if (node) return node;
1722
2011
  }
1723
2012
 
@@ -1737,9 +2026,21 @@ export function TableCell(props: TableCellProps): JSX.Element {
1737
2026
  const key = columnKey();
1738
2027
  if (key == null) return undefined;
1739
2028
  const cellKey = `${rowKey}-${key}`;
1740
- return collection.getItem(cellKey) ? (cellNode().index ?? 0) : undefined;
2029
+ return state.collection.getItem(cellKey) ? (cellNode().index ?? 0) : undefined;
1741
2030
  });
1742
2031
 
2032
+ // Tree-grid (expandable rows): the cell mirrors its row's nesting/expansion and flags the
2033
+ // tree column (the one that renders the chevron + indentation). Inert for a flat table.
2034
+ const isTreeGridCell = () => state.treeColumn != null;
2035
+ const parentRowNode = createMemo(() => state.collection.getItem(rowKey));
2036
+ const cellLevel = () => (parentRowNode()?.level ?? rowNode.level ?? 0) + 1;
2037
+ const cellHasChildItems = () => parentRowNode()?.isExpandable ?? false;
2038
+ const cellIsExpanded = () => {
2039
+ if (!isTreeGridCell() || !cellHasChildItems()) return false;
2040
+ return state.expandedKeys === "all" || state.expandedKeys.has(rowKey);
2041
+ };
2042
+ const isTreeColumn = () => isTreeGridCell() && columnKey() === state.treeColumn;
2043
+
1743
2044
  const cellAria = createTableCell<object>(
1744
2045
  () => ({
1745
2046
  node: cellNode(),
@@ -1763,6 +2064,10 @@ export function TableCell(props: TableCellProps): JSX.Element {
1763
2064
  columnIndex: cellColumnIndex() ?? 0,
1764
2065
  isPressed: isPressed(),
1765
2066
  isHovered: isHovered(),
2067
+ isTreeColumn: isTreeColumn(),
2068
+ isExpanded: cellIsExpanded(),
2069
+ hasChildItems: cellHasChildItems(),
2070
+ level: cellLevel(),
1766
2071
  }));
1767
2072
 
1768
2073
  // Resolve render props (children rendered directly in JSX to avoid eager evaluation)
@@ -1801,11 +2106,16 @@ export function TableCell(props: TableCellProps): JSX.Element {
1801
2106
  colSpan: local.colSpan,
1802
2107
  class: renderProps.class(),
1803
2108
  style: renderProps.style(),
2109
+ "data-key": cellNode().key,
1804
2110
  "data-focused": isFocused() || undefined,
1805
2111
  "data-focus-visible": (isFocusVisible() && isFocused()) || undefined,
1806
2112
  "data-column-index": cellColumnIndex(),
1807
2113
  "data-pressed": isPressed() || undefined,
1808
2114
  "data-hovered": isHovered() || undefined,
2115
+ "data-tree-column": isTreeColumn() || undefined,
2116
+ "data-expanded": (isTreeGridCell() && cellIsExpanded()) || undefined,
2117
+ "data-has-child-items": (isTreeGridCell() && cellHasChildItems()) || undefined,
2118
+ "data-level": isTreeGridCell() ? cellLevel() : undefined,
1809
2119
  children: cellChildren(),
1810
2120
  }) as JSX.TdHTMLAttributes<HTMLTableCellElement>;
1811
2121
 
@@ -1822,11 +2132,16 @@ export function TableCell(props: TableCellProps): JSX.Element {
1822
2132
  colSpan={local.colSpan}
1823
2133
  class={renderProps.class()}
1824
2134
  style={renderProps.style()}
2135
+ data-key={cellNode().key}
1825
2136
  data-focused={isFocused() || undefined}
1826
2137
  data-focus-visible={(isFocusVisible() && isFocused()) || undefined}
1827
2138
  data-column-index={cellColumnIndex()}
1828
2139
  data-pressed={isPressed() || undefined}
1829
2140
  data-hovered={isHovered() || undefined}
2141
+ data-tree-column={isTreeColumn() || undefined}
2142
+ data-expanded={(isTreeGridCell() && cellIsExpanded()) || undefined}
2143
+ data-has-child-items={(isTreeGridCell() && cellHasChildItems()) || undefined}
2144
+ data-level={isTreeGridCell() ? cellLevel() : undefined}
1830
2145
  >
1831
2146
  {cellChildren()}
1832
2147
  </td>
@@ -1851,9 +2166,10 @@ export function TableSelectionCheckbox(props: TableSelectionCheckboxProps): JSX.
1851
2166
  }
1852
2167
 
1853
2168
  const { state } = context;
2169
+ const rowContext = useContext(TableRowContext);
1854
2170
 
1855
2171
  const selectionCheckboxAria = createTableSelectionCheckbox<object>(
1856
- () => ({ key: props.rowKey }),
2172
+ () => ({ key: props.rowKey, isRowDisabled: rowContext?.isRowDisabled }),
1857
2173
  () => state as TableState<object, TableCollection<object>>,
1858
2174
  );
1859
2175
 
@@ -1864,6 +2180,11 @@ export function TableSelectionCheckbox(props: TableSelectionCheckboxProps): JSX.
1864
2180
  style={props.style}
1865
2181
  tabIndex={props.excludeFromTabOrder ? -1 : selectionCheckboxAria.checkboxProps.tabIndex}
1866
2182
  aria-label={props["aria-label"] ?? selectionCheckboxAria.checkboxProps["aria-label"]}
2183
+ onClick={(event) => event.stopPropagation()}
2184
+ onKeyDown={(event) => event.stopPropagation()}
2185
+ onKeyUp={(event) => event.stopPropagation()}
2186
+ onPointerDown={(event) => event.stopPropagation()}
2187
+ onPointerUp={(event) => event.stopPropagation()}
1867
2188
  />
1868
2189
  );
1869
2190
  }
@@ -1889,8 +2210,16 @@ export function TableSelectAllCheckbox(props: TableSelectAllCheckboxProps = {}):
1889
2210
  () => state as TableState<object, TableCollection<object>>,
1890
2211
  );
1891
2212
 
2213
+ let inputRef: HTMLInputElement | undefined;
2214
+ createEffect(() => {
2215
+ if (inputRef) {
2216
+ inputRef.indeterminate = selectAllCheckboxAria.isIndeterminate;
2217
+ }
2218
+ });
2219
+
1892
2220
  return (
1893
2221
  <input
2222
+ ref={inputRef}
1894
2223
  {...selectAllCheckboxAria.checkboxProps}
1895
2224
  class={props.class}
1896
2225
  style={props.style}