@proyecto-viviana/solidaria-components 0.4.0 → 0.5.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 (226) hide show
  1. package/dist/ActionBar.d.ts.map +1 -1
  2. package/dist/ActionBar.js +2 -11
  3. package/dist/ActionBar.js.map +1 -1
  4. package/dist/ActionBar.jsx +2 -11
  5. package/dist/ActionBar.jsx.map +1 -1
  6. package/dist/ActionGroup.d.ts.map +1 -1
  7. package/dist/ActionGroup.js +1 -1
  8. package/dist/ActionGroup.js.map +1 -1
  9. package/dist/ActionGroup.jsx +1 -1
  10. package/dist/ActionGroup.jsx.map +1 -1
  11. package/dist/Autocomplete.d.ts +2 -2
  12. package/dist/Autocomplete.d.ts.map +1 -1
  13. package/dist/Autocomplete.js +7 -7
  14. package/dist/Autocomplete.js.map +1 -1
  15. package/dist/Autocomplete.jsx +7 -7
  16. package/dist/Autocomplete.jsx.map +1 -1
  17. package/dist/Breadcrumbs.d.ts.map +1 -1
  18. package/dist/Breadcrumbs.js +18 -18
  19. package/dist/Breadcrumbs.js.map +1 -1
  20. package/dist/Breadcrumbs.jsx +21 -26
  21. package/dist/Breadcrumbs.jsx.map +1 -1
  22. package/dist/Calendar.d.ts.map +1 -1
  23. package/dist/Calendar.js +100 -65
  24. package/dist/Calendar.js.map +1 -1
  25. package/dist/Calendar.jsx +10 -1
  26. package/dist/Calendar.jsx.map +1 -1
  27. package/dist/Color.d.ts.map +1 -1
  28. package/dist/Color.js +15 -18
  29. package/dist/Color.js.map +1 -1
  30. package/dist/Color.jsx +15 -19
  31. package/dist/Color.jsx.map +1 -1
  32. package/dist/ComboBox.d.ts +4 -0
  33. package/dist/ComboBox.d.ts.map +1 -1
  34. package/dist/ComboBox.js +21 -13
  35. package/dist/ComboBox.js.map +1 -1
  36. package/dist/ComboBox.jsx +23 -13
  37. package/dist/ComboBox.jsx.map +1 -1
  38. package/dist/DateField.d.ts +11 -2
  39. package/dist/DateField.d.ts.map +1 -1
  40. package/dist/DateField2.js +237 -234
  41. package/dist/DateField2.js.map +1 -1
  42. package/dist/DateField2.jsx +134 -97
  43. package/dist/DateField2.jsx.map +1 -1
  44. package/dist/DatePicker.d.ts +42 -3
  45. package/dist/DatePicker.d.ts.map +1 -1
  46. package/dist/DatePicker.js +6 -990
  47. package/dist/DatePicker.jsx +6 -681
  48. package/dist/DatePicker2.js +1171 -0
  49. package/dist/DatePicker2.js.map +1 -0
  50. package/dist/DatePicker2.jsx +820 -0
  51. package/dist/DatePicker2.jsx.map +1 -0
  52. package/dist/DateRangePickerContext.d.ts +2 -0
  53. package/dist/DateRangePickerContext.d.ts.map +1 -1
  54. package/dist/Disclosure.d.ts.map +1 -1
  55. package/dist/Disclosure.js +3 -0
  56. package/dist/Disclosure.js.map +1 -1
  57. package/dist/Disclosure.jsx +1 -1
  58. package/dist/Disclosure.jsx.map +1 -1
  59. package/dist/ElementTag.d.ts +29 -0
  60. package/dist/ElementTag.d.ts.map +1 -0
  61. package/dist/ElementTag.js +220 -0
  62. package/dist/ElementTag.js.map +1 -0
  63. package/dist/ElementTag.jsx +67 -0
  64. package/dist/ElementTag.jsx.map +1 -0
  65. package/dist/GridList.d.ts.map +1 -1
  66. package/dist/GridList.js +2 -2
  67. package/dist/GridList.js.map +1 -1
  68. package/dist/GridList.jsx +2 -2
  69. package/dist/GridList.jsx.map +1 -1
  70. package/dist/Landmark.js +4 -3
  71. package/dist/Landmark.js.map +1 -1
  72. package/dist/Landmark.jsx +3 -3
  73. package/dist/Landmark.jsx.map +1 -1
  74. package/dist/Link.js +3 -2
  75. package/dist/Link.js.map +1 -1
  76. package/dist/Link.jsx +3 -3
  77. package/dist/Link.jsx.map +1 -1
  78. package/dist/ListBox.d.ts +2 -2
  79. package/dist/ListBox.d.ts.map +1 -1
  80. package/dist/ListBox.js +327 -166
  81. package/dist/ListBox.js.map +1 -1
  82. package/dist/ListBox.jsx +161 -25
  83. package/dist/ListBox.jsx.map +1 -1
  84. package/dist/Modal.d.ts.map +1 -1
  85. package/dist/Modal.js +7 -5
  86. package/dist/Modal.js.map +1 -1
  87. package/dist/Modal.jsx +5 -5
  88. package/dist/Modal.jsx.map +1 -1
  89. package/dist/Popover.d.ts.map +1 -1
  90. package/dist/Popover.js +16 -9
  91. package/dist/Popover.js.map +1 -1
  92. package/dist/Popover.jsx +25 -4
  93. package/dist/Popover.jsx.map +1 -1
  94. package/dist/RangeCalendar.d.ts.map +1 -1
  95. package/dist/RangeCalendar.js +182 -46
  96. package/dist/RangeCalendar.js.map +1 -1
  97. package/dist/RangeCalendar.jsx +72 -2
  98. package/dist/RangeCalendar.jsx.map +1 -1
  99. package/dist/SearchField.d.ts.map +1 -1
  100. package/dist/SearchField.js +26 -2
  101. package/dist/SearchField.js.map +1 -1
  102. package/dist/SearchField.jsx +26 -2
  103. package/dist/SearchField.jsx.map +1 -1
  104. package/dist/Select.d.ts +7 -0
  105. package/dist/Select.d.ts.map +1 -1
  106. package/dist/Select.js +64 -51
  107. package/dist/Select.js.map +1 -1
  108. package/dist/Select.jsx +35 -20
  109. package/dist/Select.jsx.map +1 -1
  110. package/dist/Separator.js +3 -2
  111. package/dist/Separator.js.map +1 -1
  112. package/dist/Separator.jsx +2 -2
  113. package/dist/Separator.jsx.map +1 -1
  114. package/dist/SharedElementTransition.d.ts.map +1 -1
  115. package/dist/SharedElementTransition.js +35 -33
  116. package/dist/SharedElementTransition.js.map +1 -1
  117. package/dist/SharedElementTransition.jsx +35 -33
  118. package/dist/SharedElementTransition.jsx.map +1 -1
  119. package/dist/StepList.d.ts.map +1 -1
  120. package/dist/StepList.js +2 -9
  121. package/dist/StepList.js.map +1 -1
  122. package/dist/StepList.jsx +1 -6
  123. package/dist/StepList.jsx.map +1 -1
  124. package/dist/Table.d.ts +2 -0
  125. package/dist/Table.d.ts.map +1 -1
  126. package/dist/Table.js +10 -3
  127. package/dist/Table.js.map +1 -1
  128. package/dist/Table.jsx +10 -3
  129. package/dist/Table.jsx.map +1 -1
  130. package/dist/Tabs.d.ts.map +1 -1
  131. package/dist/Tabs.js +3 -0
  132. package/dist/Tabs.js.map +1 -1
  133. package/dist/Tabs.jsx +1 -1
  134. package/dist/Tabs.jsx.map +1 -1
  135. package/dist/TagGroup.d.ts +3 -1
  136. package/dist/TagGroup.d.ts.map +1 -1
  137. package/dist/TagGroup.js +12 -8
  138. package/dist/TagGroup.js.map +1 -1
  139. package/dist/TagGroup.jsx +11 -8
  140. package/dist/TagGroup.jsx.map +1 -1
  141. package/dist/Text.d.ts.map +1 -1
  142. package/dist/Text.js +9 -8
  143. package/dist/Text.js.map +1 -1
  144. package/dist/Text.jsx +3 -3
  145. package/dist/Text.jsx.map +1 -1
  146. package/dist/TextField.js +4 -1
  147. package/dist/TextField.js.map +1 -1
  148. package/dist/TextField.jsx +4 -1
  149. package/dist/TextField.jsx.map +1 -1
  150. package/dist/TimeField.d.ts +14 -50
  151. package/dist/TimeField.d.ts.map +1 -1
  152. package/dist/TimeField.js +111 -205
  153. package/dist/TimeField.js.map +1 -1
  154. package/dist/TimeField.jsx +76 -82
  155. package/dist/TimeField.jsx.map +1 -1
  156. package/dist/Tree.d.ts.map +1 -1
  157. package/dist/Tree.js +3 -3
  158. package/dist/Tree.js.map +1 -1
  159. package/dist/Tree.jsx +3 -3
  160. package/dist/Tree.jsx.map +1 -1
  161. package/dist/VisuallyHidden.d.ts.map +1 -1
  162. package/dist/VisuallyHidden.js +3 -11
  163. package/dist/VisuallyHidden.js.map +1 -1
  164. package/dist/VisuallyHidden.jsx +3 -4
  165. package/dist/VisuallyHidden.jsx.map +1 -1
  166. package/dist/index.d.ts +3 -3
  167. package/dist/index.d.ts.map +1 -1
  168. package/dist/index.js +6 -6
  169. package/dist/index.jsx +6 -6
  170. package/dist/useDragAndDrop.d.ts +0 -8
  171. package/dist/useDragAndDrop.d.ts.map +1 -1
  172. package/dist/useDragAndDrop2.js +6 -2
  173. package/dist/useDragAndDrop2.js.map +1 -1
  174. package/dist/useDragAndDrop2.jsx +6 -2
  175. package/dist/useDragAndDrop2.jsx.map +1 -1
  176. package/dist/utils.d.ts +1 -0
  177. package/dist/utils.d.ts.map +1 -1
  178. package/dist/utils.js +2 -2
  179. package/dist/utils.js.map +1 -1
  180. package/dist/utils.jsx +2 -2
  181. package/dist/utils.jsx.map +1 -1
  182. package/package.json +3 -9
  183. package/src/ActionBar.tsx +10 -12
  184. package/src/ActionGroup.tsx +5 -3
  185. package/src/Autocomplete.tsx +14 -9
  186. package/src/Breadcrumbs.tsx +57 -42
  187. package/src/Calendar.tsx +30 -1
  188. package/src/Color.tsx +42 -27
  189. package/src/ComboBox.tsx +49 -17
  190. package/src/DateField.tsx +285 -52
  191. package/src/DatePicker.tsx +345 -57
  192. package/src/DateRangePickerContext.tsx +2 -0
  193. package/src/Disclosure.tsx +4 -0
  194. package/src/ElementTag.tsx +116 -0
  195. package/src/GridList.tsx +8 -2
  196. package/src/Landmark.tsx +4 -4
  197. package/src/Link.tsx +4 -4
  198. package/src/ListBox.tsx +323 -21
  199. package/src/Modal.tsx +21 -5
  200. package/src/Popover.tsx +28 -7
  201. package/src/RangeCalendar.tsx +120 -1
  202. package/src/SearchField.tsx +53 -1
  203. package/src/Select.tsx +114 -22
  204. package/src/Separator.tsx +3 -3
  205. package/src/SharedElementTransition.tsx +92 -36
  206. package/src/StepList.tsx +0 -7
  207. package/src/Table.tsx +19 -4
  208. package/src/Tabs.tsx +1 -0
  209. package/src/TagGroup.tsx +26 -6
  210. package/src/Text.tsx +5 -4
  211. package/src/TextField.tsx +1 -1
  212. package/src/TimeField.tsx +113 -196
  213. package/src/Tree.tsx +14 -4
  214. package/src/VisuallyHidden.tsx +8 -12
  215. package/src/index.ts +3 -8
  216. package/src/useDragAndDrop.ts +8 -10
  217. package/src/utils.tsx +3 -3
  218. package/dist/DatePicker.js.map +0 -1
  219. package/dist/DatePicker.jsx.map +0 -1
  220. package/dist/HiddenTimeInput.d.ts +0 -25
  221. package/dist/HiddenTimeInput.d.ts.map +0 -1
  222. package/dist/HiddenTimeInput.js +0 -104
  223. package/dist/HiddenTimeInput.js.map +0 -1
  224. package/dist/HiddenTimeInput.jsx +0 -69
  225. package/dist/HiddenTimeInput.jsx.map +0 -1
  226. package/src/HiddenTimeInput.tsx +0 -133
@@ -13,9 +13,11 @@ import {
13
13
  createContext,
14
14
  createEffect,
15
15
  createMemo,
16
+ createRenderEffect,
16
17
  createSignal,
17
18
  onCleanup,
18
19
  splitProps,
20
+ untrack,
19
21
  useContext,
20
22
  Show,
21
23
  on,
@@ -110,11 +112,16 @@ export function SharedElement(props: SharedElementProps): JSX.Element | null {
110
112
  local.isVisible === false ? "hidden" : "visible",
111
113
  );
112
114
 
113
- let elementRef: HTMLDivElement | undefined;
115
+ // The mounted div, tracked as a signal so the FLIP-read effect below REACTS to
116
+ // it appearing. React guarantees `ref.current` is committed before the layout
117
+ // effect body runs; Solid gives no such ordering between the `<Show>`'s
118
+ // insertion render-effect and a plain createEffect, so we make the read depend
119
+ // on the element instead of racing its mount (see READ PHASE).
120
+ const [element, setElement] = createSignal<HTMLDivElement | undefined>();
114
121
  let frame: number | undefined;
115
122
 
116
123
  const setRef = (el: HTMLDivElement) => {
117
- elementRef = el;
124
+ setElement(el);
118
125
  // Forward ref to consumer
119
126
  const userRef = local.ref;
120
127
  if (typeof userRef === "function") {
@@ -124,44 +131,112 @@ export function SharedElement(props: SharedElementProps): JSX.Element | null {
124
131
  }
125
132
  };
126
133
 
127
- // Handle visibility transitions with FLIP animation
128
- createEffect(
134
+ // Store a geometry + transition-style snapshot of the currently-mounted
135
+ // element, so a sibling SharedElement with the same `name` can FLIP from it.
136
+ // Mirrors upstream's layout-effect *cleanup*
137
+ // (react-aria-components/src/SharedElementTransition.tsx), which runs for
138
+ // every `isVisible` flip — not only on unmount.
139
+ const storeSnapshot = () => {
140
+ const el = untrack(element);
141
+ if (el && el.isConnected && !el.hasAttribute("data-exiting")) {
142
+ // Store a snapshot of the rectangle and computed style for transitioning properties.
143
+ const style = window.getComputedStyle(el);
144
+ if (style.transitionProperty !== "none") {
145
+ const transitionProperty = style.transitionProperty.split(/\s*,\s*/);
146
+ scope.snapshots[local.name] = {
147
+ rect: el.getBoundingClientRect(),
148
+ style: transitionProperty.map((property) => [property, style.getPropertyValue(property)]),
149
+ };
150
+ }
151
+ }
152
+ };
153
+
154
+ // MOUNT-IN-RENDER — mirrors upstream's render-phase
155
+ // `if (isVisible && state === 'hidden') setState('visible')`. Promoting a
156
+ // hidden element to visible in the render phase mounts its div (via the
157
+ // `<Show>` below) BEFORE the FLIP-read createEffect runs, so the incoming
158
+ // element is in the DOM to be measured and translated. Without this the
159
+ // incoming element's ref is still null when the read effect fires and it can
160
+ // only enter fresh — never FLIP. Keyed on `isVisible` (untracked lifecycle
161
+ // read) so it cannot loop.
162
+ createRenderEffect(
163
+ on(
164
+ () => local.isVisible !== false,
165
+ (isVisible) => {
166
+ if (isVisible && untrack(lifecycle) === "hidden") {
167
+ setLifecycle("visible");
168
+ }
169
+ },
170
+ ),
171
+ );
172
+
173
+ // STORE PHASE — a render effect runs before user effects within a Solid
174
+ // batch, exactly as React runs all layout-effect destroys before any create.
175
+ // The cleanup registered here fires on the *next* `isVisible` change (and on
176
+ // disposal), capturing the outgoing snapshot BEFORE any sibling's FLIP-read
177
+ // createEffect below runs — React's two-phase commit. Only the cleanup
178
+ // registered while VISIBLE stores (an outgoing element); an incoming
179
+ // element's prior cleanup was registered while hidden and must not clobber
180
+ // the outgoing snapshot. This mirrors React closing over `element =
181
+ // ref.current`, which is null while hidden.
182
+ createRenderEffect(
129
183
  on(
130
184
  () => local.isVisible !== false,
131
185
  (isVisible) => {
186
+ onCleanup(() => {
187
+ if (isVisible) {
188
+ storeSnapshot();
189
+ }
190
+ });
191
+ },
192
+ ),
193
+ );
194
+
195
+ // READ PHASE — mirrors upstream's layout-effect body, which reads the freshly
196
+ // committed `ref.current`. Keying on the `element` signal (not just isVisible)
197
+ // makes this run only once the incoming div is actually mounted: when isVisible
198
+ // flips true the mount-in-render effect above mounts the div, `setRef` sets the
199
+ // signal, and this effect runs with `el` present — never against a null ref.
200
+ // (Solid batches, so an isVisible flip + the resulting mount coalesce into one
201
+ // run with the mounted element.) There is therefore no "element not yet in DOM"
202
+ // fresh-enter branch: with no committed div there is nothing to measure, so we
203
+ // wait — exactly as React never runs the body before commit.
204
+ createEffect(
205
+ on(
206
+ [() => local.isVisible !== false, element] as const,
207
+ ([isVisible, el]) => {
132
208
  const name = local.name;
133
- const element = elementRef;
134
209
 
135
210
  if (frame != null) {
136
211
  cancelAnimationFrame(frame);
137
212
  frame = undefined;
138
213
  }
139
214
 
140
- if (isVisible && element) {
215
+ if (isVisible && el) {
141
216
  const prevSnapshot = scope.snapshots[name];
142
217
 
143
218
  if (prevSnapshot) {
144
219
  // FLIP: Element is transitioning from a previous instance.
145
220
  setLifecycle("visible");
146
- const animations = getAnimations(element);
221
+ const animations = getAnimations(el);
147
222
 
148
223
  // Set properties to animate from.
149
224
  const values = prevSnapshot.style.map(([property, prevValue]) => {
150
- const value = element.style.getPropertyValue(property);
225
+ const value = el.style.getPropertyValue(property);
151
226
  if (property === "translate") {
152
227
  const prevRect = prevSnapshot.rect;
153
- const currentRect = element.getBoundingClientRect();
228
+ const currentRect = el.getBoundingClientRect();
154
229
  const deltaX = prevRect.left - currentRect.left;
155
230
  const deltaY = prevRect.top - currentRect.top;
156
- element.style.setProperty("translate", `${deltaX}px ${deltaY}px`);
231
+ el.style.setProperty("translate", `${deltaX}px ${deltaY}px`);
157
232
  } else {
158
- element.style.setProperty(property, prevValue);
233
+ el.style.setProperty(property, prevValue);
159
234
  }
160
235
  return [property, value] as [string, string];
161
236
  });
162
237
 
163
238
  // Cancel any new animations triggered by these properties.
164
- for (const a of getAnimations(element)) {
239
+ for (const a of getAnimations(el)) {
165
240
  if (!animations.includes(a)) {
166
241
  a.cancel();
167
242
  }
@@ -171,7 +246,7 @@ export function SharedElement(props: SharedElementProps): JSX.Element | null {
171
246
  frame = requestAnimationFrame(() => {
172
247
  frame = undefined;
173
248
  for (const [property, value] of values) {
174
- element.style.setProperty(property, value);
249
+ el.style.setProperty(property, value);
175
250
  }
176
251
  });
177
252
 
@@ -184,7 +259,7 @@ export function SharedElement(props: SharedElementProps): JSX.Element | null {
184
259
  setLifecycle("visible");
185
260
  });
186
261
  }
187
- } else if (!isVisible && element) {
262
+ } else if (!isVisible && el) {
188
263
  // Wait a microtask to check if a snapshot still exists (meaning no new
189
264
  // SharedElement consumed it), then enter exiting state.
190
265
  queueMicrotask(() => {
@@ -192,7 +267,7 @@ export function SharedElement(props: SharedElementProps): JSX.Element | null {
192
267
  delete scope.snapshots[name];
193
268
  setLifecycle("exiting");
194
269
  // Wait for animations to finish before hiding.
195
- Promise.all(getAnimations(element).map((a) => a.finished))
270
+ Promise.all(getAnimations(el).map((a) => a.finished))
196
271
  .then(() => setLifecycle("hidden"))
197
272
  .catch(() => {});
198
273
  } else {
@@ -200,36 +275,17 @@ export function SharedElement(props: SharedElementProps): JSX.Element | null {
200
275
  setLifecycle("hidden");
201
276
  }
202
277
  });
203
- } else if (isVisible) {
204
- // Element not yet in DOM, entering fresh
205
- setLifecycle("entering");
206
- frame = requestAnimationFrame(() => {
207
- frame = undefined;
208
- setLifecycle("visible");
209
- });
210
278
  }
211
279
  },
212
280
  ),
213
281
  );
214
282
 
215
- // Capture snapshot on cleanup (unmount)
283
+ // Cancel any pending FLIP frame on disposal. The snapshot store lives in the
284
+ // render-effect cleanup above, which also fires on disposal.
216
285
  onCleanup(() => {
217
286
  if (frame != null) {
218
287
  cancelAnimationFrame(frame);
219
288
  }
220
-
221
- const element = elementRef;
222
- if (element && element.isConnected && !element.hasAttribute("data-exiting")) {
223
- // Store a snapshot of the rectangle and computed style for transitioning properties.
224
- const style = window.getComputedStyle(element);
225
- if (style.transitionProperty !== "none") {
226
- const transitionProperty = style.transitionProperty.split(/\s*,\s*/);
227
- scope.snapshots[local.name] = {
228
- rect: element.getBoundingClientRect(),
229
- style: transitionProperty.map((property) => [property, style.getPropertyValue(property)]),
230
- };
231
- }
232
- }
233
289
  });
234
290
 
235
291
  const renderProps = useRenderProps(
package/src/StepList.tsx CHANGED
@@ -240,12 +240,6 @@ export function Step(props: StepProps): JSX.Element {
240
240
  }
241
241
  };
242
242
 
243
- const stepStateText = () => {
244
- if (isSelected()) return "Current";
245
- if (isCompleted()) return "Completed";
246
- return "Not completed";
247
- };
248
-
249
243
  return (
250
244
  <li
251
245
  {...domProps}
@@ -263,7 +257,6 @@ export function Step(props: StepProps): JSX.Element {
263
257
  tabIndex={selectable() ? 0 : undefined}
264
258
  onClick={handleClick}
265
259
  on:keydown={handleKeyDown}
266
- aria-label={`Step ${local.stepNumber}: ${local.item.label}, ${stepStateText()}`}
267
260
  >
268
261
  {local.children}
269
262
  </a>
package/src/Table.tsx CHANGED
@@ -50,6 +50,7 @@ import {
50
50
  type ColumnSize,
51
51
  type GridNode,
52
52
  type DropTarget,
53
+ type Collection,
53
54
  } from "@proyecto-viviana/solid-stately";
54
55
  import {
55
56
  type RenderChildren,
@@ -523,6 +524,8 @@ export const TableColumnResizeStateContext = createContext<{
523
524
  interface TableRowContextValue {
524
525
  rowKey: Key;
525
526
  rowNode: GridNode<unknown>;
527
+ /** The row's resolved disabled state, so a child selection checkbox can gate on it. */
528
+ isRowDisabled: boolean;
526
529
  getCellColumnKey(cellId: string, explicitId?: Key): Key | undefined;
527
530
  }
528
531
 
@@ -622,7 +625,12 @@ export function Table<T extends object>(props: TableProps<T>): JSX.Element {
622
625
  const collection = () => state.collection;
623
626
  const parentCollectionRenderer = useCollectionRenderer<T>();
624
627
 
625
- 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>(
626
634
  () => ({
627
635
  id: ariaProps.id,
628
636
  "aria-label": ariaProps["aria-label"],
@@ -665,7 +673,7 @@ export function Table<T extends object>(props: TableProps<T>): JSX.Element {
665
673
  });
666
674
 
667
675
  const cleanGridProps = () => {
668
- const { ref: _ref1, ...rest } = gridProps as Record<string, unknown>;
676
+ const { ref: _ref1, ...rest } = tableAria.gridProps as Record<string, unknown>;
669
677
  return rest;
670
678
  };
671
679
  const cleanFocusProps = () => {
@@ -757,8 +765,11 @@ export function Table<T extends object>(props: TableProps<T>): JSX.Element {
757
765
  getKeyPageBelow: (key) => state.collection.getKeyAfter?.(key) ?? null,
758
766
  getKeyPageAbove: (key) => state.collection.getKeyBefore?.(key) ?? null,
759
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.
760
771
  get collection() {
761
- return state.collection;
772
+ return state.collection as unknown as Collection;
762
773
  },
763
774
  get selectedKeys() {
764
775
  return state.selectedKeys;
@@ -1735,6 +1746,9 @@ export function TableRow<T extends object>(props: TableRowProps<T>): JSX.Element
1735
1746
  const rowContextValue: TableRowContextValue = {
1736
1747
  rowKey: rowKey(),
1737
1748
  rowNode: rowNode(),
1749
+ get isRowDisabled() {
1750
+ return isDisabled();
1751
+ },
1738
1752
  getCellColumnKey(cellId, explicitId) {
1739
1753
  if (explicitId === "__selection__") {
1740
1754
  return explicitId;
@@ -2152,9 +2166,10 @@ export function TableSelectionCheckbox(props: TableSelectionCheckboxProps): JSX.
2152
2166
  }
2153
2167
 
2154
2168
  const { state } = context;
2169
+ const rowContext = useContext(TableRowContext);
2155
2170
 
2156
2171
  const selectionCheckboxAria = createTableSelectionCheckbox<object>(
2157
- () => ({ key: props.rowKey }),
2172
+ () => ({ key: props.rowKey, isRowDisabled: rowContext?.isRowDisabled }),
2158
2173
  () => state as TableState<object, TableCollection<object>>,
2159
2174
  );
2160
2175
 
package/src/Tabs.tsx CHANGED
@@ -610,6 +610,7 @@ function TabInner(props: {
610
610
  onPointerDown={tabAria.tabProps.onPointerDown}
611
611
  onClick={tabAria.tabProps.onClick}
612
612
  onFocus={tabAria.tabProps.onFocus}
613
+ onFocusIn={tabAria.tabProps.onFocusIn}
613
614
  onBlur={tabAria.tabProps.onBlur}
614
615
  {...hoverProps}
615
616
  data-selected={tabAria.isSelected() || undefined}
package/src/TagGroup.tsx CHANGED
@@ -18,7 +18,12 @@ import {
18
18
  For,
19
19
  Show,
20
20
  } from "solid-js";
21
- import { createTagGroup, createTag, type AriaTagGroupProps } from "@proyecto-viviana/solidaria";
21
+ import {
22
+ createTagGroup,
23
+ createTag,
24
+ useLocale,
25
+ type AriaTagGroupProps,
26
+ } from "@proyecto-viviana/solidaria";
22
27
  import {
23
28
  createListState,
24
29
  type ListState,
@@ -31,9 +36,11 @@ import {
31
36
  type ClassNameOrFunction,
32
37
  type StyleOrFunction,
33
38
  type SlotProps,
39
+ type RefLike,
34
40
  useRenderProps,
35
41
  filterDOMProps,
36
42
  dataAttr,
43
+ mergeRefs,
37
44
  } from "./utils";
38
45
  import { SharedElementTransition } from "./SharedElementTransition";
39
46
  import {
@@ -140,6 +147,8 @@ export interface TagProps extends SlotProps {
140
147
  class?: ClassNameOrFunction<TagRenderProps>;
141
148
  /** The inline style for the element. */
142
149
  style?: StyleOrFunction<TagRenderProps>;
150
+ /** A ref to the tag's DOM element (merged with the internal collection ref). */
151
+ ref?: RefLike<HTMLDivElement>;
143
152
  /** Handler called when the tag is activated. */
144
153
  onAction?: (key: Key) => void;
145
154
  }
@@ -254,6 +263,11 @@ export function TagList<T extends { id?: Key; key?: Key }>(props: TagListProps<T
254
263
  },
255
264
  });
256
265
 
266
+ // The tag group navigates on the inline axis, so ArrowLeft/ArrowRight flip
267
+ // under RTL. Thread the resolved layout direction into the hook (mirrors
268
+ // ListBox, and useTagGroup passing `direction` to the ListKeyboardDelegate).
269
+ const locale = useLocale();
270
+
257
271
  // Create tag group accessibility props
258
272
  const tagGroupAria = createTagGroup(
259
273
  {
@@ -272,6 +286,9 @@ export function TagList<T extends { id?: Key; key?: Key }>(props: TagListProps<T
272
286
  get onRemove() {
273
287
  return local.onRemove;
274
288
  },
289
+ get direction() {
290
+ return locale().direction;
291
+ },
275
292
  },
276
293
  state,
277
294
  gridRef,
@@ -312,18 +329,20 @@ export function TagList<T extends { id?: Key; key?: Key }>(props: TagListProps<T
312
329
  {...tagGroupAria.gridProps}
313
330
  class={renderProps.class()}
314
331
  style={renderProps.style()}
315
- onFocus={() => {
332
+ // Track focus-within via the BUBBLING focusin/focusout pair (not the
333
+ // non-bubbling focus/blur the hook's trampoline uses) so this render-prop
334
+ // signal never clobbers `gridProps.onFocus` — the container focus
335
+ // trampoline that marshals entry onto the first/last row.
336
+ onFocusIn={() => {
316
337
  setIsFocused(true);
317
- state.setFocused(true);
318
338
  }}
319
- onBlur={(e) => {
339
+ onFocusOut={(e) => {
320
340
  const nextTarget = e.relatedTarget as Node | null;
321
341
  if (nextTarget && e.currentTarget.contains(nextTarget)) {
322
342
  return;
323
343
  }
324
344
 
325
345
  setIsFocused(false);
326
- state.setFocused(false);
327
346
  }}
328
347
  data-empty={dataAttr(local.items.length === 0)}
329
348
  data-focused={dataAttr(isFocused())}
@@ -351,6 +370,7 @@ export function Tag(props: TagProps): JSX.Element {
351
370
  "isDisabled",
352
371
  "textValue",
353
372
  "onAction",
373
+ "ref",
354
374
  ]);
355
375
 
356
376
  const state = useContext(TagListStateContext);
@@ -433,7 +453,7 @@ export function Tag(props: TagProps): JSX.Element {
433
453
  }}
434
454
  >
435
455
  <div
436
- ref={setTagRef}
456
+ ref={mergeRefs(setTagRef, local.ref)}
437
457
  {...domProps()}
438
458
  {...tagAria.rowProps}
439
459
  class={renderProps.class()}
package/src/Text.tsx CHANGED
@@ -1,5 +1,5 @@
1
1
  import { type JSX, createContext, splitProps } from "solid-js";
2
- import { Dynamic } from "solid-js/web";
2
+ import { ElementTag } from "./ElementTag";
3
3
  import { type ContextValue, type SlotProps, useContextProps, filterDOMProps } from "./utils";
4
4
 
5
5
  export interface TextProps extends JSX.HTMLAttributes<HTMLElement>, SlotProps {
@@ -28,12 +28,13 @@ export function Text(props: TextProps): JSX.Element {
28
28
  // are rendered explicitly; everything else (notably the slotted `id`) is spread.
29
29
  const [local, domProps] = splitProps(merged, ["elementType", "class", "children", "slot", "ref"]);
30
30
  return (
31
- <Dynamic
32
- component={local.elementType ?? "span"}
31
+ <ElementTag
33
32
  class={local.class ?? "solidaria-Text"}
34
33
  {...filterDOMProps(domProps, { global: true })}
34
+ // last, so a stray `tag` in the spread can never redirect the element
35
+ tag={local.elementType ?? "span"}
35
36
  >
36
37
  {local.children}
37
- </Dynamic>
38
+ </ElementTag>
38
39
  );
39
40
  }
package/src/TextField.tsx CHANGED
@@ -531,7 +531,7 @@ export function TextField(props: TextFieldProps): JSX.Element {
531
531
  };
532
532
 
533
533
  const domProps = createMemo(() => {
534
- const filtered = filterDOMProps(ariaProps, { global: true });
534
+ const filtered = filterDOMProps(ariaProps, { global: true, events: false });
535
535
  delete (filtered as Record<string, unknown>).id;
536
536
  return filtered;
537
537
  });