@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.
- package/dist/ActionBar.d.ts.map +1 -1
- package/dist/ActionBar.js +2 -11
- package/dist/ActionBar.js.map +1 -1
- package/dist/ActionBar.jsx +2 -11
- package/dist/ActionBar.jsx.map +1 -1
- package/dist/ActionGroup.d.ts.map +1 -1
- package/dist/ActionGroup.js +1 -1
- package/dist/ActionGroup.js.map +1 -1
- package/dist/ActionGroup.jsx +1 -1
- package/dist/ActionGroup.jsx.map +1 -1
- package/dist/Autocomplete.d.ts +2 -2
- package/dist/Autocomplete.d.ts.map +1 -1
- package/dist/Autocomplete.js +7 -7
- package/dist/Autocomplete.js.map +1 -1
- package/dist/Autocomplete.jsx +7 -7
- package/dist/Autocomplete.jsx.map +1 -1
- package/dist/Breadcrumbs.d.ts.map +1 -1
- package/dist/Breadcrumbs.js +18 -18
- package/dist/Breadcrumbs.js.map +1 -1
- package/dist/Breadcrumbs.jsx +21 -26
- package/dist/Breadcrumbs.jsx.map +1 -1
- package/dist/Calendar.d.ts.map +1 -1
- package/dist/Calendar.js +100 -65
- package/dist/Calendar.js.map +1 -1
- package/dist/Calendar.jsx +10 -1
- package/dist/Calendar.jsx.map +1 -1
- package/dist/Color.d.ts.map +1 -1
- package/dist/Color.js +15 -18
- package/dist/Color.js.map +1 -1
- package/dist/Color.jsx +15 -19
- package/dist/Color.jsx.map +1 -1
- package/dist/ComboBox.d.ts +4 -0
- package/dist/ComboBox.d.ts.map +1 -1
- package/dist/ComboBox.js +21 -13
- package/dist/ComboBox.js.map +1 -1
- package/dist/ComboBox.jsx +23 -13
- package/dist/ComboBox.jsx.map +1 -1
- package/dist/DateField.d.ts +11 -2
- package/dist/DateField.d.ts.map +1 -1
- package/dist/DateField2.js +237 -234
- package/dist/DateField2.js.map +1 -1
- package/dist/DateField2.jsx +134 -97
- package/dist/DateField2.jsx.map +1 -1
- package/dist/DatePicker.d.ts +42 -3
- package/dist/DatePicker.d.ts.map +1 -1
- package/dist/DatePicker.js +6 -990
- package/dist/DatePicker.jsx +6 -681
- package/dist/DatePicker2.js +1171 -0
- package/dist/DatePicker2.js.map +1 -0
- package/dist/DatePicker2.jsx +820 -0
- package/dist/DatePicker2.jsx.map +1 -0
- package/dist/DateRangePickerContext.d.ts +2 -0
- package/dist/DateRangePickerContext.d.ts.map +1 -1
- package/dist/Disclosure.d.ts.map +1 -1
- package/dist/Disclosure.js +3 -0
- package/dist/Disclosure.js.map +1 -1
- package/dist/Disclosure.jsx +1 -1
- package/dist/Disclosure.jsx.map +1 -1
- package/dist/ElementTag.d.ts +29 -0
- package/dist/ElementTag.d.ts.map +1 -0
- package/dist/ElementTag.js +220 -0
- package/dist/ElementTag.js.map +1 -0
- package/dist/ElementTag.jsx +67 -0
- package/dist/ElementTag.jsx.map +1 -0
- package/dist/GridList.d.ts.map +1 -1
- package/dist/GridList.js +2 -2
- package/dist/GridList.js.map +1 -1
- package/dist/GridList.jsx +2 -2
- package/dist/GridList.jsx.map +1 -1
- package/dist/Landmark.js +4 -3
- package/dist/Landmark.js.map +1 -1
- package/dist/Landmark.jsx +3 -3
- package/dist/Landmark.jsx.map +1 -1
- package/dist/Link.js +3 -2
- package/dist/Link.js.map +1 -1
- package/dist/Link.jsx +3 -3
- package/dist/Link.jsx.map +1 -1
- package/dist/ListBox.d.ts +2 -2
- package/dist/ListBox.d.ts.map +1 -1
- package/dist/ListBox.js +327 -166
- package/dist/ListBox.js.map +1 -1
- package/dist/ListBox.jsx +161 -25
- package/dist/ListBox.jsx.map +1 -1
- package/dist/Modal.d.ts.map +1 -1
- package/dist/Modal.js +7 -5
- package/dist/Modal.js.map +1 -1
- package/dist/Modal.jsx +5 -5
- package/dist/Modal.jsx.map +1 -1
- package/dist/Popover.d.ts.map +1 -1
- package/dist/Popover.js +16 -9
- package/dist/Popover.js.map +1 -1
- package/dist/Popover.jsx +25 -4
- package/dist/Popover.jsx.map +1 -1
- package/dist/RangeCalendar.d.ts.map +1 -1
- package/dist/RangeCalendar.js +182 -46
- package/dist/RangeCalendar.js.map +1 -1
- package/dist/RangeCalendar.jsx +72 -2
- package/dist/RangeCalendar.jsx.map +1 -1
- package/dist/SearchField.d.ts.map +1 -1
- package/dist/SearchField.js +26 -2
- package/dist/SearchField.js.map +1 -1
- package/dist/SearchField.jsx +26 -2
- package/dist/SearchField.jsx.map +1 -1
- package/dist/Select.d.ts +7 -0
- package/dist/Select.d.ts.map +1 -1
- package/dist/Select.js +64 -51
- package/dist/Select.js.map +1 -1
- package/dist/Select.jsx +35 -20
- package/dist/Select.jsx.map +1 -1
- package/dist/Separator.js +3 -2
- package/dist/Separator.js.map +1 -1
- package/dist/Separator.jsx +2 -2
- package/dist/Separator.jsx.map +1 -1
- package/dist/SharedElementTransition.d.ts.map +1 -1
- package/dist/SharedElementTransition.js +35 -33
- package/dist/SharedElementTransition.js.map +1 -1
- package/dist/SharedElementTransition.jsx +35 -33
- package/dist/SharedElementTransition.jsx.map +1 -1
- package/dist/StepList.d.ts.map +1 -1
- package/dist/StepList.js +2 -9
- package/dist/StepList.js.map +1 -1
- package/dist/StepList.jsx +1 -6
- package/dist/StepList.jsx.map +1 -1
- package/dist/Table.d.ts +2 -0
- package/dist/Table.d.ts.map +1 -1
- package/dist/Table.js +10 -3
- package/dist/Table.js.map +1 -1
- package/dist/Table.jsx +10 -3
- package/dist/Table.jsx.map +1 -1
- package/dist/Tabs.d.ts.map +1 -1
- package/dist/Tabs.js +3 -0
- package/dist/Tabs.js.map +1 -1
- package/dist/Tabs.jsx +1 -1
- package/dist/Tabs.jsx.map +1 -1
- package/dist/TagGroup.d.ts +3 -1
- package/dist/TagGroup.d.ts.map +1 -1
- package/dist/TagGroup.js +12 -8
- package/dist/TagGroup.js.map +1 -1
- package/dist/TagGroup.jsx +11 -8
- package/dist/TagGroup.jsx.map +1 -1
- package/dist/Text.d.ts.map +1 -1
- package/dist/Text.js +9 -8
- package/dist/Text.js.map +1 -1
- package/dist/Text.jsx +3 -3
- package/dist/Text.jsx.map +1 -1
- package/dist/TextField.js +4 -1
- package/dist/TextField.js.map +1 -1
- package/dist/TextField.jsx +4 -1
- package/dist/TextField.jsx.map +1 -1
- package/dist/TimeField.d.ts +14 -50
- package/dist/TimeField.d.ts.map +1 -1
- package/dist/TimeField.js +111 -205
- package/dist/TimeField.js.map +1 -1
- package/dist/TimeField.jsx +76 -82
- package/dist/TimeField.jsx.map +1 -1
- package/dist/Tree.d.ts.map +1 -1
- package/dist/Tree.js +3 -3
- package/dist/Tree.js.map +1 -1
- package/dist/Tree.jsx +3 -3
- package/dist/Tree.jsx.map +1 -1
- package/dist/VisuallyHidden.d.ts.map +1 -1
- package/dist/VisuallyHidden.js +3 -11
- package/dist/VisuallyHidden.js.map +1 -1
- package/dist/VisuallyHidden.jsx +3 -4
- package/dist/VisuallyHidden.jsx.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -6
- package/dist/index.jsx +6 -6
- package/dist/useDragAndDrop.d.ts +0 -8
- package/dist/useDragAndDrop.d.ts.map +1 -1
- package/dist/useDragAndDrop2.js +6 -2
- package/dist/useDragAndDrop2.js.map +1 -1
- package/dist/useDragAndDrop2.jsx +6 -2
- package/dist/useDragAndDrop2.jsx.map +1 -1
- package/dist/utils.d.ts +1 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +2 -2
- package/dist/utils.js.map +1 -1
- package/dist/utils.jsx +2 -2
- package/dist/utils.jsx.map +1 -1
- package/package.json +3 -9
- package/src/ActionBar.tsx +10 -12
- package/src/ActionGroup.tsx +5 -3
- package/src/Autocomplete.tsx +14 -9
- package/src/Breadcrumbs.tsx +57 -42
- package/src/Calendar.tsx +30 -1
- package/src/Color.tsx +42 -27
- package/src/ComboBox.tsx +49 -17
- package/src/DateField.tsx +285 -52
- package/src/DatePicker.tsx +345 -57
- package/src/DateRangePickerContext.tsx +2 -0
- package/src/Disclosure.tsx +4 -0
- package/src/ElementTag.tsx +116 -0
- package/src/GridList.tsx +8 -2
- package/src/Landmark.tsx +4 -4
- package/src/Link.tsx +4 -4
- package/src/ListBox.tsx +323 -21
- package/src/Modal.tsx +21 -5
- package/src/Popover.tsx +28 -7
- package/src/RangeCalendar.tsx +120 -1
- package/src/SearchField.tsx +53 -1
- package/src/Select.tsx +114 -22
- package/src/Separator.tsx +3 -3
- package/src/SharedElementTransition.tsx +92 -36
- package/src/StepList.tsx +0 -7
- package/src/Table.tsx +19 -4
- package/src/Tabs.tsx +1 -0
- package/src/TagGroup.tsx +26 -6
- package/src/Text.tsx +5 -4
- package/src/TextField.tsx +1 -1
- package/src/TimeField.tsx +113 -196
- package/src/Tree.tsx +14 -4
- package/src/VisuallyHidden.tsx +8 -12
- package/src/index.ts +3 -8
- package/src/useDragAndDrop.ts +8 -10
- package/src/utils.tsx +3 -3
- package/dist/DatePicker.js.map +0 -1
- package/dist/DatePicker.jsx.map +0 -1
- package/dist/HiddenTimeInput.d.ts +0 -25
- package/dist/HiddenTimeInput.d.ts.map +0 -1
- package/dist/HiddenTimeInput.js +0 -104
- package/dist/HiddenTimeInput.js.map +0 -1
- package/dist/HiddenTimeInput.jsx +0 -69
- package/dist/HiddenTimeInput.jsx.map +0 -1
- package/src/HiddenTimeInput.tsx +0 -133
package/src/Autocomplete.tsx
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
createAutocompleteState,
|
|
27
27
|
type AutocompleteState,
|
|
28
28
|
type AutocompleteStateOptions,
|
|
29
|
+
type CollectionNode,
|
|
29
30
|
} from "@proyecto-viviana/solid-stately";
|
|
30
31
|
import { type SlotProps } from "./utils";
|
|
31
32
|
|
|
@@ -44,7 +45,7 @@ export interface AutocompleteContextValue {
|
|
|
44
45
|
export interface AutocompleteCollectionContextValue {
|
|
45
46
|
collectionProps: CollectionOptions;
|
|
46
47
|
collectionRef: (el: HTMLElement) => void;
|
|
47
|
-
filter?: (
|
|
48
|
+
filter?: (nodeTextValue: string, node: CollectionNode<unknown>) => boolean;
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
export const AutocompleteContext = createContext<AutocompleteContextValue | null>(null);
|
|
@@ -126,16 +127,18 @@ export function Autocomplete<T = unknown>(props: AutocompleteProps<T>): JSX.Elem
|
|
|
126
127
|
|
|
127
128
|
const state = createAutocompleteState(stateProps);
|
|
128
129
|
|
|
129
|
-
//
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
// Refs are signals so createAutocomplete's effects (the beforeinput listener
|
|
131
|
+
// and the reverse-path focusin listener that mirrors aria-activedescendant)
|
|
132
|
+
// bind reactively once the input/collection elements actually mount.
|
|
133
|
+
const [inputRef, setInputRef] = createSignal<HTMLInputElement>();
|
|
134
|
+
const [collectionRef, setCollectionRef] = createSignal<HTMLElement>();
|
|
132
135
|
|
|
133
136
|
// Create autocomplete aria
|
|
134
137
|
const autocomplete = createAutocomplete<T>(
|
|
135
138
|
{
|
|
136
139
|
...ariaProps,
|
|
137
|
-
inputRef
|
|
138
|
-
collectionRef
|
|
140
|
+
inputRef,
|
|
141
|
+
collectionRef,
|
|
139
142
|
},
|
|
140
143
|
state,
|
|
141
144
|
);
|
|
@@ -144,7 +147,7 @@ export function Autocomplete<T = unknown>(props: AutocompleteProps<T>): JSX.Elem
|
|
|
144
147
|
const inputContextValue = createMemo<AutocompleteContextValue>(() => ({
|
|
145
148
|
inputProps: autocomplete.inputProps,
|
|
146
149
|
inputRef: (el: HTMLInputElement) => {
|
|
147
|
-
|
|
150
|
+
setInputRef(el);
|
|
148
151
|
},
|
|
149
152
|
}));
|
|
150
153
|
|
|
@@ -152,9 +155,11 @@ export function Autocomplete<T = unknown>(props: AutocompleteProps<T>): JSX.Elem
|
|
|
152
155
|
const collectionContextValue = createMemo<AutocompleteCollectionContextValue>(() => ({
|
|
153
156
|
collectionProps: autocomplete.collectionProps,
|
|
154
157
|
collectionRef: (el: HTMLElement) => {
|
|
155
|
-
|
|
158
|
+
setCollectionRef(el);
|
|
156
159
|
},
|
|
157
|
-
filter: autocomplete.filter
|
|
160
|
+
filter: autocomplete.filter as
|
|
161
|
+
| ((nodeTextValue: string, node: CollectionNode<unknown>) => boolean)
|
|
162
|
+
| undefined,
|
|
158
163
|
}));
|
|
159
164
|
|
|
160
165
|
return (
|
package/src/Breadcrumbs.tsx
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
For,
|
|
18
18
|
Show,
|
|
19
19
|
} from "solid-js";
|
|
20
|
-
import {
|
|
20
|
+
import { ElementTag } from "./ElementTag";
|
|
21
21
|
import {
|
|
22
22
|
createBreadcrumbs,
|
|
23
23
|
createBreadcrumbItem,
|
|
@@ -196,7 +196,20 @@ export function Breadcrumbs<T>(props: BreadcrumbsProps<T>): JSX.Element {
|
|
|
196
196
|
setStaticItemCount,
|
|
197
197
|
}}
|
|
198
198
|
>
|
|
199
|
-
|
|
199
|
+
{/*
|
|
200
|
+
Faithful to react-aria-components Breadcrumbs: the accessible name (navProps'
|
|
201
|
+
aria-label) sits directly on the <ol> (role="list"), with NO wrapping <nav>
|
|
202
|
+
landmark (react-spectrum/packages/react-aria-components/src/Breadcrumbs.tsx
|
|
203
|
+
renders `<dom.ol {...mergeProps(DOMProps, navProps)} style={props.style}>`).
|
|
204
|
+
The <ol> carries ONLY the consumer's class/style — no hard-coded inline
|
|
205
|
+
layout reset. An inline reset would beat the styled layer's class (inline
|
|
206
|
+
wins over class), which is exactly what broke S2 parity: the solid-spectrum
|
|
207
|
+
`wrapperStyles` class supplies display:flex / list-style:none / padding:0 /
|
|
208
|
+
marginStart and deliberately leaves align-items at its `normal` default, so
|
|
209
|
+
a hard-coded inline `align-items:center` + `margin:0` clobbered the
|
|
210
|
+
wrapper's margin and diverged from S2 (whose <ol> has neither).
|
|
211
|
+
*/}
|
|
212
|
+
<ol
|
|
200
213
|
{...navProps}
|
|
201
214
|
{...domProps()}
|
|
202
215
|
ref={(element) => assignRef(local.ref, element)}
|
|
@@ -204,39 +217,27 @@ export function Breadcrumbs<T>(props: BreadcrumbsProps<T>): JSX.Element {
|
|
|
204
217
|
style={renderProps.style()}
|
|
205
218
|
data-disabled={isDisabled() || undefined}
|
|
206
219
|
>
|
|
207
|
-
<
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
"align-items": "center",
|
|
211
|
-
"list-style": "none",
|
|
212
|
-
margin: 0,
|
|
213
|
-
padding: 0,
|
|
214
|
-
}}
|
|
220
|
+
<Show
|
|
221
|
+
when={hasCollectionItems()}
|
|
222
|
+
fallback={<StaticBreadcrumbItems>{local.children as JSX.Element}</StaticBreadcrumbItems>}
|
|
215
223
|
>
|
|
216
|
-
<
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
</li>
|
|
234
|
-
);
|
|
235
|
-
}}
|
|
236
|
-
</For>
|
|
237
|
-
</Show>
|
|
238
|
-
</ol>
|
|
239
|
-
</nav>
|
|
224
|
+
<For each={items()}>
|
|
225
|
+
{(item, index) => {
|
|
226
|
+
const itemKey = getItemKey(item, index());
|
|
227
|
+
const isLast = () => index() === items().length - 1;
|
|
228
|
+
const renderItem = local.children as ((item: T) => JSX.Element) | undefined;
|
|
229
|
+
|
|
230
|
+
return (
|
|
231
|
+
<li style={{ display: "flex", "align-items": "center" }}>
|
|
232
|
+
<BreadcrumbItemContext.Provider value={{ itemKey, isLast }}>
|
|
233
|
+
{renderItem?.(item)}
|
|
234
|
+
</BreadcrumbItemContext.Provider>
|
|
235
|
+
</li>
|
|
236
|
+
);
|
|
237
|
+
}}
|
|
238
|
+
</For>
|
|
239
|
+
</Show>
|
|
240
|
+
</ol>
|
|
240
241
|
</BreadcrumbsContext.Provider>
|
|
241
242
|
);
|
|
242
243
|
}
|
|
@@ -277,6 +278,18 @@ export function BreadcrumbItem(props: BreadcrumbItemProps): JSX.Element {
|
|
|
277
278
|
staticIndex === context.staticItemCount() - 1);
|
|
278
279
|
const itemKey = () => itemContext?.itemKey ?? ariaProps.id ?? null;
|
|
279
280
|
|
|
281
|
+
// Mirror react-aria-components' Link: render an <a> only when there is an
|
|
282
|
+
// href on an enabled, non-current item; otherwise fall back to a <span
|
|
283
|
+
// role="link"> (via createLink). A styled layer may force the element type
|
|
284
|
+
// (S2 renders the current item as a plain <div>), which takes precedence.
|
|
285
|
+
const elementType = () =>
|
|
286
|
+
ariaProps.elementType ?? (ariaProps.href && !isDisabled() && !isCurrent() ? "a" : "span");
|
|
287
|
+
// The current breadcrumb is the current page and is non-interactive: S2
|
|
288
|
+
// renders it as a plain element with no link role. createLink only omits
|
|
289
|
+
// role="link" for an <a>, so treat the current item as an "a" purely for the
|
|
290
|
+
// role decision while still rendering the resolved element type above.
|
|
291
|
+
const linkElementType = () => (isCurrent() ? "a" : elementType());
|
|
292
|
+
|
|
280
293
|
const handlePress = (e: PressEvent) => {
|
|
281
294
|
ariaProps.onPress?.(e);
|
|
282
295
|
const key = itemKey();
|
|
@@ -285,7 +298,7 @@ export function BreadcrumbItem(props: BreadcrumbItemProps): JSX.Element {
|
|
|
285
298
|
}
|
|
286
299
|
};
|
|
287
300
|
|
|
288
|
-
const
|
|
301
|
+
const itemAria = createBreadcrumbItem({
|
|
289
302
|
get id() {
|
|
290
303
|
return ariaProps.id;
|
|
291
304
|
},
|
|
@@ -305,7 +318,7 @@ export function BreadcrumbItem(props: BreadcrumbItemProps): JSX.Element {
|
|
|
305
318
|
return ariaProps.rel;
|
|
306
319
|
},
|
|
307
320
|
get elementType() {
|
|
308
|
-
return
|
|
321
|
+
return linkElementType();
|
|
309
322
|
},
|
|
310
323
|
get onPress() {
|
|
311
324
|
return handlePress;
|
|
@@ -354,20 +367,23 @@ export function BreadcrumbItem(props: BreadcrumbItemProps): JSX.Element {
|
|
|
354
367
|
},
|
|
355
368
|
});
|
|
356
369
|
|
|
370
|
+
const isPressed = itemAria.isPressed;
|
|
357
371
|
const { isFocused, isFocusVisible, focusProps } = createFocusRing();
|
|
358
372
|
const { isHovered, hoverProps } = createHover({
|
|
359
373
|
get isDisabled() {
|
|
360
374
|
return isDisabled();
|
|
361
375
|
},
|
|
362
376
|
});
|
|
377
|
+
// Read itemAria.itemProps fresh inside the memo (do NOT destructure it above):
|
|
378
|
+
// the reactive getter re-runs createBreadcrumbItem → createLink each time this
|
|
379
|
+
// memo re-evaluates, so role/tabIndex track elementType once isCurrent settles.
|
|
363
380
|
const mergedItemProps = createMemo(() =>
|
|
364
381
|
mergeProps(
|
|
365
|
-
itemProps as Record<string, unknown>,
|
|
382
|
+
itemAria.itemProps as Record<string, unknown>,
|
|
366
383
|
focusProps as Record<string, unknown>,
|
|
367
384
|
hoverProps as Record<string, unknown>,
|
|
368
385
|
),
|
|
369
386
|
);
|
|
370
|
-
const elementType = () => ariaProps.elementType ?? "a";
|
|
371
387
|
|
|
372
388
|
const renderValues = createMemo<BreadcrumbItemRenderProps>(() => ({
|
|
373
389
|
isCurrent: isCurrent(),
|
|
@@ -397,11 +413,10 @@ export function BreadcrumbItem(props: BreadcrumbItemProps): JSX.Element {
|
|
|
397
413
|
};
|
|
398
414
|
|
|
399
415
|
return (
|
|
400
|
-
<
|
|
401
|
-
|
|
416
|
+
<ElementTag
|
|
417
|
+
tag={elementType()}
|
|
402
418
|
{...mergedItemProps()}
|
|
403
419
|
ref={(element: HTMLElement) => assignRef(local.ref, element)}
|
|
404
|
-
href={isCurrent() ? undefined : (mergedItemProps() as { href?: string }).href}
|
|
405
420
|
aria-current={isCurrent() ? (ariaProps["aria-current"] ?? "page") : undefined}
|
|
406
421
|
aria-disabled={isDisabled() || isCurrent() || undefined}
|
|
407
422
|
class={renderProps.class()}
|
|
@@ -414,7 +429,7 @@ export function BreadcrumbItem(props: BreadcrumbItemProps): JSX.Element {
|
|
|
414
429
|
data-hovered={isHovered() || undefined}
|
|
415
430
|
>
|
|
416
431
|
{renderProps.renderChildren()}
|
|
417
|
-
</
|
|
432
|
+
</ElementTag>
|
|
418
433
|
);
|
|
419
434
|
}
|
|
420
435
|
|
package/src/Calendar.tsx
CHANGED
|
@@ -305,6 +305,17 @@ function CalendarWithState<
|
|
|
305
305
|
<h2>{String(calendarAria.calendarProps["aria-label"] ?? "")}</h2>
|
|
306
306
|
</VisuallyHidden>
|
|
307
307
|
{props.children}
|
|
308
|
+
{/* For touch screen readers, a visually hidden next button after the month
|
|
309
|
+
* grid so it's easy to navigate after reaching the end without going all
|
|
310
|
+
* the way back to the start. Mirrors react-aria-components Calendar. */}
|
|
311
|
+
<VisuallyHidden>
|
|
312
|
+
<button
|
|
313
|
+
aria-label={String(calendarAria.nextButtonProps["aria-label"] ?? "")}
|
|
314
|
+
disabled={Boolean(calendarAria.nextButtonProps.disabled)}
|
|
315
|
+
onClick={() => state().focusNextPage()}
|
|
316
|
+
tabIndex={-1}
|
|
317
|
+
/>
|
|
318
|
+
</VisuallyHidden>
|
|
308
319
|
</div>
|
|
309
320
|
);
|
|
310
321
|
}
|
|
@@ -387,6 +398,18 @@ function CalendarInner<
|
|
|
387
398
|
<h2>{String(calendarAria.calendarProps["aria-label"] ?? "")}</h2>
|
|
388
399
|
</VisuallyHidden>
|
|
389
400
|
{props.children}
|
|
401
|
+
{/* For touch screen readers, a visually hidden next button after the
|
|
402
|
+
* month grid so it's easy to navigate after reaching the end without
|
|
403
|
+
* going all the way back to the start. Mirrors react-aria-components
|
|
404
|
+
* Calendar. */}
|
|
405
|
+
<VisuallyHidden>
|
|
406
|
+
<button
|
|
407
|
+
aria-label={String(calendarAria.nextButtonProps["aria-label"] ?? "")}
|
|
408
|
+
disabled={Boolean(calendarAria.nextButtonProps.disabled)}
|
|
409
|
+
onClick={() => state.focusNextPage()}
|
|
410
|
+
tabIndex={-1}
|
|
411
|
+
/>
|
|
412
|
+
</VisuallyHidden>
|
|
390
413
|
</div>
|
|
391
414
|
</CalendarContext.Provider>
|
|
392
415
|
);
|
|
@@ -455,12 +478,18 @@ export function CalendarButton(props: CalendarButtonProps): JSX.Element {
|
|
|
455
478
|
return calendarAria.nextButtonProps;
|
|
456
479
|
});
|
|
457
480
|
|
|
481
|
+
const isDisabled = () => props.isDisabled || state.isDisabled();
|
|
482
|
+
|
|
458
483
|
return (
|
|
459
484
|
<button
|
|
460
485
|
{...buttonProps()}
|
|
461
486
|
class={props.class ?? "solidaria-CalendarButton"}
|
|
462
487
|
style={props.style}
|
|
463
|
-
disabled={
|
|
488
|
+
disabled={isDisabled()}
|
|
489
|
+
// Mirror useFocusable: always set an explicit tabIndex on an enabled
|
|
490
|
+
// focusable button (0), and drop it entirely when disabled — so the
|
|
491
|
+
// nav buttons appear in the roving tab order exactly as upstream does.
|
|
492
|
+
tabindex={isDisabled() ? undefined : 0}
|
|
464
493
|
>
|
|
465
494
|
{props.children}
|
|
466
495
|
</button>
|
package/src/Color.tsx
CHANGED
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
createFocusRing,
|
|
29
29
|
createHover,
|
|
30
30
|
mergeProps,
|
|
31
|
+
useLocale,
|
|
31
32
|
type AriaColorSliderOptions,
|
|
32
33
|
type AriaColorAreaOptions,
|
|
33
34
|
type AriaColorWheelOptions,
|
|
@@ -233,7 +234,11 @@ export function ColorSlider(props: ColorSliderProps): JSX.Element {
|
|
|
233
234
|
],
|
|
234
235
|
);
|
|
235
236
|
|
|
236
|
-
|
|
237
|
+
const locale = useLocale();
|
|
238
|
+
|
|
239
|
+
// Create color slider state. The locale drives the thumb value label's
|
|
240
|
+
// channel-value formatting (e.g. hue "50°" vs ar-AE "50 درجة"), mirroring
|
|
241
|
+
// RAC ColorSlider passing `useLocale().locale` into useColorSliderState.
|
|
237
242
|
const state = createColorSliderState(() => ({
|
|
238
243
|
value: stateProps.value ?? pickerContext?.value,
|
|
239
244
|
defaultValue: stateProps.defaultValue,
|
|
@@ -243,6 +248,7 @@ export function ColorSlider(props: ColorSliderProps): JSX.Element {
|
|
|
243
248
|
colorSpace: stateProps.colorSpace,
|
|
244
249
|
orientation: ariaProps.orientation,
|
|
245
250
|
isDisabled: ariaProps.isDisabled,
|
|
251
|
+
locale: locale().locale,
|
|
246
252
|
}));
|
|
247
253
|
|
|
248
254
|
let trackRef: HTMLDivElement | undefined;
|
|
@@ -2115,11 +2121,10 @@ export function ColorSwatchPicker(props: ColorSwatchPickerProps): JSX.Element {
|
|
|
2115
2121
|
() => ({
|
|
2116
2122
|
id: local.id,
|
|
2117
2123
|
"aria-label":
|
|
2118
|
-
local["aria-label"] ?? (!local["aria-labelledby"] ? "Color
|
|
2124
|
+
local["aria-label"] ?? (!local["aria-labelledby"] ? "Color swatches" : undefined),
|
|
2119
2125
|
"aria-labelledby": local["aria-labelledby"],
|
|
2120
2126
|
"aria-describedby": local["aria-describedby"],
|
|
2121
2127
|
"aria-details": local["aria-details"],
|
|
2122
|
-
shouldFocusWrap: true,
|
|
2123
2128
|
}),
|
|
2124
2129
|
state,
|
|
2125
2130
|
);
|
|
@@ -2247,32 +2252,28 @@ export function ColorSwatchPicker(props: ColorSwatchPickerProps): JSX.Element {
|
|
|
2247
2252
|
let nextKey: Key | null = null;
|
|
2248
2253
|
switch (e.key) {
|
|
2249
2254
|
case "ArrowDown":
|
|
2250
|
-
nextKey = getGridKeyBelow(listbox, initialKey)
|
|
2255
|
+
nextKey = getGridKeyBelow(listbox, initialKey);
|
|
2251
2256
|
break;
|
|
2252
2257
|
case "ArrowUp":
|
|
2253
|
-
nextKey = getGridKeyAbove(listbox, initialKey)
|
|
2258
|
+
nextKey = getGridKeyAbove(listbox, initialKey);
|
|
2254
2259
|
break;
|
|
2255
2260
|
case "ArrowRight":
|
|
2256
|
-
nextKey =
|
|
2257
|
-
getGridKeyRightOf(initialKey) ??
|
|
2258
|
-
(resolveDirection() === "rtl"
|
|
2259
|
-
? getBoundaryEnabledKey("prev")
|
|
2260
|
-
: getBoundaryEnabledKey("next"));
|
|
2261
|
+
nextKey = getGridKeyRightOf(initialKey);
|
|
2261
2262
|
break;
|
|
2262
2263
|
case "ArrowLeft":
|
|
2263
|
-
nextKey =
|
|
2264
|
-
getGridKeyLeftOf(initialKey) ??
|
|
2265
|
-
(resolveDirection() === "rtl"
|
|
2266
|
-
? getBoundaryEnabledKey("next")
|
|
2267
|
-
: getBoundaryEnabledKey("prev"));
|
|
2264
|
+
nextKey = getGridKeyLeftOf(initialKey);
|
|
2268
2265
|
break;
|
|
2269
2266
|
}
|
|
2270
2267
|
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2268
|
+
// Mirror react-aria's grid keyboard delegate: an arrow in grid layout is
|
|
2269
|
+
// always consumed (blocking the linear ListBox handler and page scroll),
|
|
2270
|
+
// but focus only moves when the delegate yields a next key. With
|
|
2271
|
+
// shouldFocusWrap unset (upstream default false) there is no wrap, so arrows
|
|
2272
|
+
// stop dead at the grid's edges. Selection is not mutated on arrow — under
|
|
2273
|
+
// the default 'toggle' selection behavior focus moves without selecting, and
|
|
2274
|
+
// Enter/Space commits (handled by createSelectableItem).
|
|
2275
|
+
if (nextKey != null) {
|
|
2276
|
+
state.setFocusedKey(nextKey);
|
|
2276
2277
|
}
|
|
2277
2278
|
|
|
2278
2279
|
e.preventDefault();
|
|
@@ -2292,12 +2293,18 @@ export function ColorSwatchPicker(props: ColorSwatchPickerProps): JSX.Element {
|
|
|
2292
2293
|
getListBoxKeyDown()?.(e);
|
|
2293
2294
|
};
|
|
2294
2295
|
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2296
|
+
// NB: we deliberately do NOT seed `state.setFocusedKey(selectedKey())` at rest.
|
|
2297
|
+
// Upstream's RAC `<ListBox>` (which `AriaColorSwatchPicker` is) keeps
|
|
2298
|
+
// `focusedKey == null` until the collection is focused — the listbox CONTAINER
|
|
2299
|
+
// is the roving tabstop (`tabIndex 0`), and `useSelectableCollection`'s onFocus
|
|
2300
|
+
// navigates to `firstSelectedKey` on entry (mirrored by `createListBox`'s
|
|
2301
|
+
// `onListBoxFocus`). Pre-seeding focusedKey to the selected swatch made the
|
|
2302
|
+
// selected option the rest tabstop instead (container `tabIndex -1`) — a
|
|
2303
|
+
// self-inflicted divergence — and, because our `createFocusWithin` only flips
|
|
2304
|
+
// `manager.setFocused(true)` on CONTAINER focus (Solid's `onFocus` is
|
|
2305
|
+
// non-bubbling), it also routed entry through a direct option focus that never
|
|
2306
|
+
// set `isFocused`, so arrow keys could not pull real DOM focus. Letting the
|
|
2307
|
+
// container be the tabstop restores both.
|
|
2301
2308
|
|
|
2302
2309
|
const { isFocused, isFocusVisible, focusProps } = createFocusRing({ within: true });
|
|
2303
2310
|
const domProps = createMemo(() =>
|
|
@@ -2387,13 +2394,20 @@ export function ColorSwatchPickerItem(props: ColorSwatchPickerItemProps): JSX.El
|
|
|
2387
2394
|
onCleanup(() => context.unregisterItem(itemKey));
|
|
2388
2395
|
});
|
|
2389
2396
|
|
|
2397
|
+
const [optionRef, setOptionRef] = createSignal<HTMLElement | null>(null);
|
|
2398
|
+
|
|
2390
2399
|
const optionAria = createOption(
|
|
2391
2400
|
() => ({
|
|
2392
2401
|
key: key(),
|
|
2393
2402
|
isDisabled: ariaProps.isDisabled,
|
|
2394
|
-
|
|
2403
|
+
// No aria-label: the option is named by its content (the child swatch's
|
|
2404
|
+
// role="img" aria-label), mirroring upstream ColorSwatchPickerItem which
|
|
2405
|
+
// sets only textValue (typeahead, threaded via registerItem above) and
|
|
2406
|
+
// never an aria-label.
|
|
2407
|
+
"aria-label": ariaProps["aria-label"],
|
|
2395
2408
|
}),
|
|
2396
2409
|
context.state,
|
|
2410
|
+
optionRef,
|
|
2397
2411
|
);
|
|
2398
2412
|
|
|
2399
2413
|
const renderValues = createMemo<ColorSwatchPickerItemRenderProps>(() => ({
|
|
@@ -2427,6 +2441,7 @@ export function ColorSwatchPickerItem(props: ColorSwatchPickerItemProps): JSX.El
|
|
|
2427
2441
|
|
|
2428
2442
|
return (
|
|
2429
2443
|
<div
|
|
2444
|
+
ref={setOptionRef}
|
|
2430
2445
|
{...mergeProps(domProps(), cleanOptionProps())}
|
|
2431
2446
|
class={renderProps.class()}
|
|
2432
2447
|
style={renderProps.style()}
|
package/src/ComboBox.tsx
CHANGED
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
createInteractOutside,
|
|
29
29
|
createScrollIntoViewOnFocus,
|
|
30
30
|
mergeProps,
|
|
31
|
+
isFocusVisible as isGlobalFocusVisible,
|
|
31
32
|
type AriaComboBoxProps,
|
|
32
33
|
type AriaListBoxProps,
|
|
33
34
|
type AriaOptionProps,
|
|
@@ -239,6 +240,8 @@ export interface ComboBoxValueProps extends SlotProps {
|
|
|
239
240
|
}
|
|
240
241
|
|
|
241
242
|
export interface ComboBoxButtonProps extends SlotProps {
|
|
243
|
+
/** A ref to the underlying button element. */
|
|
244
|
+
ref?: RefLike<HTMLButtonElement>;
|
|
242
245
|
/** The children of the button. */
|
|
243
246
|
children?: RenderChildren<ComboBoxButtonRenderProps>;
|
|
244
247
|
/** The CSS className for the element. */
|
|
@@ -278,6 +281,8 @@ export interface ComboBoxOptionRenderProps {
|
|
|
278
281
|
|
|
279
282
|
export interface ComboBoxOptionProps<T>
|
|
280
283
|
extends Omit<AriaOptionProps, "children" | "key">, SlotProps {
|
|
284
|
+
/** A ref to the underlying option element. */
|
|
285
|
+
ref?: RefLike<HTMLElement>;
|
|
281
286
|
/** The unique key for the option. */
|
|
282
287
|
id: Key;
|
|
283
288
|
/** The item value. */
|
|
@@ -706,10 +711,13 @@ export function ComboBoxDescription(props: ComboBoxDescriptionProps): JSX.Elemen
|
|
|
706
711
|
return rest;
|
|
707
712
|
};
|
|
708
713
|
|
|
714
|
+
// Upstream renders the description via `<Text slot="description">`, and RAC's
|
|
715
|
+
// `Text` defaults to `elementType="span"` (Text.tsx:24) — so the help text is a
|
|
716
|
+
// `<span>`, not a `<div>`. Match it (mirrors the TextField port's same revert).
|
|
709
717
|
return (
|
|
710
|
-
<
|
|
718
|
+
<span {...domProps} {...cleanDescriptionProps()} class={local.class} style={local.style}>
|
|
711
719
|
{local.children}
|
|
712
|
-
</
|
|
720
|
+
</span>
|
|
713
721
|
);
|
|
714
722
|
}
|
|
715
723
|
|
|
@@ -729,10 +737,12 @@ export function ComboBoxErrorMessage(props: ComboBoxErrorMessageProps): JSX.Elem
|
|
|
729
737
|
return rest;
|
|
730
738
|
};
|
|
731
739
|
|
|
740
|
+
// Same as the description: upstream's error is `<Text slot="errorMessage">`,
|
|
741
|
+
// a `<span>` (RAC Text default elementType). Match it.
|
|
732
742
|
return (
|
|
733
|
-
<
|
|
743
|
+
<span {...domProps} {...cleanErrorMessageProps()} class={local.class} style={local.style}>
|
|
734
744
|
{local.children}
|
|
735
|
-
</
|
|
745
|
+
</span>
|
|
736
746
|
);
|
|
737
747
|
}
|
|
738
748
|
|
|
@@ -865,7 +875,7 @@ export function ComboBoxValue(props: ComboBoxValueProps): JSX.Element {
|
|
|
865
875
|
* The trigger button for a combobox.
|
|
866
876
|
*/
|
|
867
877
|
export function ComboBoxButton(props: ComboBoxButtonProps): JSX.Element {
|
|
868
|
-
const [local, domProps] = splitProps(props, ["class", "style", "slot", "children"]);
|
|
878
|
+
const [local, domProps] = splitProps(props, ["class", "style", "slot", "children", "ref"]);
|
|
869
879
|
|
|
870
880
|
const context = useContext(ComboBoxContext);
|
|
871
881
|
if (!context) {
|
|
@@ -911,7 +921,10 @@ export function ComboBoxButton(props: ComboBoxButtonProps): JSX.Element {
|
|
|
911
921
|
return (
|
|
912
922
|
<button
|
|
913
923
|
{...domProps}
|
|
914
|
-
ref={(el) =>
|
|
924
|
+
ref={(el) => {
|
|
925
|
+
setButtonRef(el);
|
|
926
|
+
assignRef(local.ref, el);
|
|
927
|
+
}}
|
|
915
928
|
{...cleanButtonProps()}
|
|
916
929
|
{...cleanHoverProps()}
|
|
917
930
|
class={renderProps.class()}
|
|
@@ -941,7 +954,7 @@ export function ComboBoxListBox<T>(props: ComboBoxListBoxProps<T>): JSX.Element
|
|
|
941
954
|
const { state: comboBoxState, listState, isOpen, inputRef, buttonRef, setListBoxRef } = context;
|
|
942
955
|
const state = comboBoxState;
|
|
943
956
|
|
|
944
|
-
let listBoxRef:
|
|
957
|
+
let listBoxRef: HTMLElement | undefined;
|
|
945
958
|
|
|
946
959
|
// Reveal the activedescendant-focused option on keyboard navigation while the
|
|
947
960
|
// listbox is open. Real DOM focus stays on the input, so the browser won't
|
|
@@ -1017,7 +1030,7 @@ export function ComboBoxListBox<T>(props: ComboBoxListBoxProps<T>): JSX.Element
|
|
|
1017
1030
|
);
|
|
1018
1031
|
};
|
|
1019
1032
|
|
|
1020
|
-
const setListBoxElement = (el:
|
|
1033
|
+
const setListBoxElement = (el: HTMLElement) => {
|
|
1021
1034
|
listBoxRef = el;
|
|
1022
1035
|
setListBoxRef(el);
|
|
1023
1036
|
};
|
|
@@ -1028,7 +1041,10 @@ export function ComboBoxListBox<T>(props: ComboBoxListBoxProps<T>): JSX.Element
|
|
|
1028
1041
|
|
|
1029
1042
|
return (
|
|
1030
1043
|
<Show when={isOpen()}>
|
|
1031
|
-
|
|
1044
|
+
{/* `<div role="listbox">`, not `<ul>` — upstream RAC ListBox (and our own
|
|
1045
|
+
Select/ListBox) render div-over-div rows; the `role` comes from the
|
|
1046
|
+
spread listbox aria props (createListBox), not the element tag. */}
|
|
1047
|
+
<div
|
|
1032
1048
|
{...domProps}
|
|
1033
1049
|
ref={setListBoxElement}
|
|
1034
1050
|
{...cleanContextProps()}
|
|
@@ -1052,7 +1068,7 @@ export function ComboBoxListBox<T>(props: ComboBoxListBoxProps<T>): JSX.Element
|
|
|
1052
1068
|
}}
|
|
1053
1069
|
</For>
|
|
1054
1070
|
</Show>
|
|
1055
|
-
</
|
|
1071
|
+
</div>
|
|
1056
1072
|
</Show>
|
|
1057
1073
|
);
|
|
1058
1074
|
}
|
|
@@ -1069,6 +1085,7 @@ export function ComboBoxOption<T>(props: ComboBoxOptionProps<T>): JSX.Element {
|
|
|
1069
1085
|
"item",
|
|
1070
1086
|
"textValue",
|
|
1071
1087
|
"onAction",
|
|
1088
|
+
"ref",
|
|
1072
1089
|
]);
|
|
1073
1090
|
|
|
1074
1091
|
const stateContext = useContext(ComboBoxStateContext);
|
|
@@ -1078,7 +1095,7 @@ export function ComboBoxOption<T>(props: ComboBoxOptionProps<T>): JSX.Element {
|
|
|
1078
1095
|
}
|
|
1079
1096
|
const state = stateContext as ComboBoxState<T>;
|
|
1080
1097
|
const listState = (comboBoxContext as ComboBoxContextValue<T>).listState;
|
|
1081
|
-
const [ref, setRef] = createSignal<
|
|
1098
|
+
const [ref, setRef] = createSignal<HTMLElement | null>(null);
|
|
1082
1099
|
const optionId = () => {
|
|
1083
1100
|
const listBoxId = getComboBoxData(state as ComboBoxState<unknown>)?.listBoxId;
|
|
1084
1101
|
return listBoxId ? `${listBoxId}-option-${local.id}` : String(local.id);
|
|
@@ -1126,9 +1143,19 @@ export function ComboBoxOption<T>(props: ComboBoxOptionProps<T>): JSX.Element {
|
|
|
1126
1143
|
() => ref(),
|
|
1127
1144
|
);
|
|
1128
1145
|
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1146
|
+
// Mirror upstream `useOption` exactly (useOption.ts:172):
|
|
1147
|
+
// isFocusVisible = isFocused && selectionManager.isFocused && isFocusVisible()
|
|
1148
|
+
// where `isFocusVisible()` is the GLOBAL interaction-modality singleton read as
|
|
1149
|
+
// a render-time snapshot (NOT the input's focus ring, and NOT the option's own
|
|
1150
|
+
// createFocusRing — the option div never receives real DOM focus under virtual
|
|
1151
|
+
// focus, so its ring never lights). `optionAria.isFocused()` already folds in
|
|
1152
|
+
// `selectionManager.isFocused()` (createSelectableItem.ts:239), so the upstream
|
|
1153
|
+
// three-term product collapses to these two. Reading the global singleton off
|
|
1154
|
+
// the `isFocused` dependency gives the same non-reactive snapshot semantics as
|
|
1155
|
+
// React (mouse/hover focus → pointer modality → no ring; keyboard nav → keyboard
|
|
1156
|
+
// modality → ring), which the earlier input-ring OR-branch got wrong (it lit the
|
|
1157
|
+
// option ring whenever the input ring was on).
|
|
1158
|
+
const isOptionFocusVisible = () => optionAria.isFocused() && isGlobalFocusVisible();
|
|
1132
1159
|
|
|
1133
1160
|
const renderValues = createMemo<ComboBoxOptionRenderProps>(() => ({
|
|
1134
1161
|
isSelected: optionAria.isSelected(),
|
|
@@ -1162,8 +1189,13 @@ export function ComboBoxOption<T>(props: ComboBoxOptionProps<T>): JSX.Element {
|
|
|
1162
1189
|
|
|
1163
1190
|
return (
|
|
1164
1191
|
<SelectionIndicatorContext.Provider value={selectionIndicatorContext()}>
|
|
1165
|
-
|
|
1166
|
-
|
|
1192
|
+
{/* `<div role="option">`, not `<li>` — see the ComboBoxListBox note; the
|
|
1193
|
+
`role` comes from the spread option aria props (createOption). */}
|
|
1194
|
+
<div
|
|
1195
|
+
ref={(el) => {
|
|
1196
|
+
setRef(el);
|
|
1197
|
+
assignRef(local.ref, el);
|
|
1198
|
+
}}
|
|
1167
1199
|
{...cleanOptionProps()}
|
|
1168
1200
|
class={renderProps.class()}
|
|
1169
1201
|
style={renderProps.style()}
|
|
@@ -1175,7 +1207,7 @@ export function ComboBoxOption<T>(props: ComboBoxOptionProps<T>): JSX.Element {
|
|
|
1175
1207
|
data-disabled={optionAria.isDisabled() || undefined}
|
|
1176
1208
|
>
|
|
1177
1209
|
{renderProps.renderChildren()}
|
|
1178
|
-
</
|
|
1210
|
+
</div>
|
|
1179
1211
|
</SelectionIndicatorContext.Provider>
|
|
1180
1212
|
);
|
|
1181
1213
|
}
|