@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.
- package/dist/ActionBar.d.ts.map +1 -1
- package/dist/ActionBar.js +175 -0
- package/dist/ActionBar.js.map +1 -0
- package/dist/ActionBar.jsx +119 -0
- package/dist/ActionBar.jsx.map +1 -0
- package/dist/ActionGroup.d.ts.map +1 -1
- package/dist/ActionGroup.js +179 -0
- package/dist/ActionGroup.js.map +1 -0
- package/dist/ActionGroup.jsx +129 -0
- package/dist/ActionGroup.jsx.map +1 -0
- package/dist/Alert.js +111 -0
- package/dist/Alert.js.map +1 -0
- package/dist/Alert.jsx +82 -0
- package/dist/Alert.jsx.map +1 -0
- package/dist/Autocomplete.d.ts +2 -2
- package/dist/Autocomplete.d.ts.map +1 -1
- package/dist/Autocomplete.js +130 -0
- package/dist/Autocomplete.js.map +1 -0
- package/dist/Autocomplete.jsx +116 -0
- package/dist/Autocomplete.jsx.map +1 -0
- package/dist/Breadcrumbs.d.ts.map +1 -1
- package/dist/Breadcrumbs.js +333 -0
- package/dist/Breadcrumbs.js.map +1 -0
- package/dist/Breadcrumbs.jsx +261 -0
- package/dist/Breadcrumbs.jsx.map +1 -0
- package/dist/Button.d.ts.map +1 -1
- package/dist/Button.js +348 -0
- package/dist/Button.js.map +1 -0
- package/dist/Button.jsx +314 -0
- package/dist/Button.jsx.map +1 -0
- package/dist/Calendar.d.ts +4 -4
- package/dist/Calendar.d.ts.map +1 -1
- package/dist/Calendar.js +573 -0
- package/dist/Calendar.js.map +1 -0
- package/dist/Calendar.jsx +342 -0
- package/dist/Calendar.jsx.map +1 -0
- package/dist/CalendarPicker.d.ts +33 -0
- package/dist/CalendarPicker.d.ts.map +1 -0
- package/dist/CalendarPicker.js +44 -0
- package/dist/CalendarPicker.js.map +1 -0
- package/dist/CalendarPicker.jsx +44 -0
- package/dist/CalendarPicker.jsx.map +1 -0
- package/dist/Checkbox.d.ts +83 -4
- package/dist/Checkbox.d.ts.map +1 -1
- package/dist/Checkbox.js +923 -0
- package/dist/Checkbox.js.map +1 -0
- package/dist/Checkbox.jsx +707 -0
- package/dist/Checkbox.jsx.map +1 -0
- package/dist/Collection.d.ts.map +1 -1
- package/dist/Collection.js +202 -0
- package/dist/Collection.js.map +1 -0
- package/dist/Collection.jsx +152 -0
- package/dist/Collection.jsx.map +1 -0
- package/dist/Color.d.ts.map +1 -1
- package/dist/Color.js +1717 -0
- package/dist/Color.js.map +1 -0
- package/dist/Color.jsx +1340 -0
- package/dist/Color.jsx.map +1 -0
- package/dist/ColorEditor.js +208 -0
- package/dist/ColorEditor.js.map +1 -0
- package/dist/ColorEditor.jsx +120 -0
- package/dist/ColorEditor.jsx.map +1 -0
- package/dist/ComboBox.d.ts +8 -4
- package/dist/ComboBox.d.ts.map +1 -1
- package/dist/ComboBox.js +1000 -0
- package/dist/ComboBox.js.map +1 -0
- package/dist/ComboBox.jsx +724 -0
- package/dist/ComboBox.jsx.map +1 -0
- package/dist/ContextualHelpTrigger.js +146 -0
- package/dist/ContextualHelpTrigger.js.map +1 -0
- package/dist/ContextualHelpTrigger.jsx +109 -0
- package/dist/ContextualHelpTrigger.jsx.map +1 -0
- package/dist/DateField.d.ts +14 -5
- package/dist/DateField.d.ts.map +1 -1
- package/dist/DateField.js +4 -0
- package/dist/DateField.jsx +4 -0
- package/dist/DateField2.js +502 -0
- package/dist/DateField2.js.map +1 -0
- package/dist/DateField2.jsx +354 -0
- package/dist/DateField2.jsx.map +1 -0
- package/dist/DatePicker.d.ts +46 -7
- package/dist/DatePicker.d.ts.map +1 -1
- package/dist/DatePicker.js +7 -0
- package/dist/DatePicker.jsx +7 -0
- 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/Dialog.d.ts.map +1 -1
- package/dist/Dialog.js +337 -0
- package/dist/Dialog.js.map +1 -0
- package/dist/Dialog.jsx +192 -0
- package/dist/Dialog.jsx.map +1 -0
- package/dist/Disclosure.d.ts.map +1 -1
- package/dist/Disclosure.js +331 -0
- package/dist/Disclosure.js.map +1 -0
- package/dist/Disclosure.jsx +230 -0
- package/dist/Disclosure.jsx.map +1 -0
- package/dist/DragAndDrop.d.ts.map +1 -1
- package/dist/DragAndDrop.js +176 -0
- package/dist/DragAndDrop.js.map +1 -0
- package/dist/DragAndDrop.jsx +160 -0
- package/dist/DragAndDrop.jsx.map +1 -0
- package/dist/DropZone.d.ts.map +1 -1
- package/dist/DropZone.js +189 -0
- package/dist/DropZone.js.map +1 -0
- package/dist/DropZone.jsx +144 -0
- package/dist/DropZone.jsx.map +1 -0
- package/dist/FieldError.js +66 -0
- package/dist/FieldError.js.map +1 -0
- package/dist/FieldError.jsx +47 -0
- package/dist/FieldError.jsx.map +1 -0
- package/dist/FileTrigger.js +79 -0
- package/dist/FileTrigger.js.map +1 -0
- package/dist/FileTrigger.jsx +49 -0
- package/dist/FileTrigger.jsx.map +1 -0
- package/dist/Focusable.js +70 -0
- package/dist/Focusable.js.map +1 -0
- package/dist/Focusable.jsx +69 -0
- package/dist/Focusable.jsx.map +1 -0
- package/dist/Form.js +99 -0
- package/dist/Form.js.map +1 -0
- package/dist/Form.jsx +73 -0
- package/dist/Form.jsx.map +1 -0
- package/dist/GridList.d.ts +34 -2
- package/dist/GridList.d.ts.map +1 -1
- package/dist/GridList.js +723 -0
- package/dist/GridList.js.map +1 -0
- package/dist/GridList.jsx +552 -0
- package/dist/GridList.jsx.map +1 -0
- package/dist/Icon.d.ts.map +1 -1
- package/dist/Icon.js +127 -0
- package/dist/Icon.js.map +1 -0
- package/dist/Icon.jsx +72 -0
- package/dist/Icon.jsx.map +1 -0
- package/dist/Keyboard.js +30 -0
- package/dist/Keyboard.js.map +1 -0
- package/dist/Keyboard.jsx +24 -0
- package/dist/Keyboard.jsx.map +1 -0
- package/dist/Landmark.js +134 -0
- package/dist/Landmark.js.map +1 -0
- package/dist/Landmark.jsx +118 -0
- package/dist/Landmark.jsx.map +1 -0
- package/dist/Link.d.ts.map +1 -1
- package/dist/Link.js +219 -0
- package/dist/Link.js.map +1 -0
- package/dist/Link.jsx +189 -0
- package/dist/Link.jsx.map +1 -0
- package/dist/ListBox.d.ts +2 -2
- package/dist/ListBox.d.ts.map +1 -1
- package/dist/ListBox.js +831 -0
- package/dist/ListBox.js.map +1 -0
- package/dist/ListBox.jsx +644 -0
- package/dist/ListBox.jsx.map +1 -0
- package/dist/Menu.d.ts +27 -9
- package/dist/Menu.d.ts.map +1 -1
- package/dist/Menu.js +1254 -0
- package/dist/Menu.js.map +1 -0
- package/dist/Menu.jsx +1042 -0
- package/dist/Menu.jsx.map +1 -0
- package/dist/Meter.d.ts.map +1 -1
- package/dist/Meter.js +123 -0
- package/dist/Meter.js.map +1 -0
- package/dist/Meter.jsx +107 -0
- package/dist/Meter.jsx.map +1 -0
- package/dist/Modal.d.ts.map +1 -1
- package/dist/Modal.js +382 -0
- package/dist/Modal.js.map +1 -0
- package/dist/Modal.jsx +314 -0
- package/dist/Modal.jsx.map +1 -0
- package/dist/NumberField.d.ts +3 -3
- package/dist/NumberField.d.ts.map +1 -1
- package/dist/NumberField.js +573 -0
- package/dist/NumberField.js.map +1 -0
- package/dist/NumberField.jsx +443 -0
- package/dist/NumberField.jsx.map +1 -0
- package/dist/Popover.d.ts +10 -2
- package/dist/Popover.d.ts.map +1 -1
- package/dist/Popover.js +471 -0
- package/dist/Popover.js.map +1 -0
- package/dist/Popover.jsx +354 -0
- package/dist/Popover.jsx.map +1 -0
- package/dist/Pressable.js +69 -0
- package/dist/Pressable.js.map +1 -0
- package/dist/Pressable.jsx +68 -0
- package/dist/Pressable.jsx.map +1 -0
- package/dist/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar.js +130 -0
- package/dist/ProgressBar.js.map +1 -0
- package/dist/ProgressBar.jsx +114 -0
- package/dist/ProgressBar.jsx.map +1 -0
- package/dist/RadioGroup.d.ts +82 -4
- package/dist/RadioGroup.d.ts.map +1 -1
- package/dist/RadioGroup.js +931 -0
- package/dist/RadioGroup.js.map +1 -0
- package/dist/RadioGroup.jsx +681 -0
- package/dist/RadioGroup.jsx.map +1 -0
- package/dist/RangeCalendar.d.ts.map +1 -1
- package/dist/RangeCalendar.js +546 -0
- package/dist/RangeCalendar.js.map +1 -0
- package/dist/RangeCalendar.jsx +323 -0
- package/dist/RangeCalendar.jsx.map +1 -0
- package/dist/RouterProvider.js +118 -0
- package/dist/RouterProvider.js.map +1 -0
- package/dist/RouterProvider.jsx +112 -0
- package/dist/RouterProvider.jsx.map +1 -0
- package/dist/SearchField.d.ts +2 -2
- package/dist/SearchField.d.ts.map +1 -1
- package/dist/SearchField.js +667 -0
- package/dist/SearchField.js.map +1 -0
- package/dist/SearchField.jsx +550 -0
- package/dist/SearchField.jsx.map +1 -0
- package/dist/Select.d.ts +7 -0
- package/dist/Select.d.ts.map +1 -1
- package/dist/Select.js +1044 -0
- package/dist/Select.js.map +1 -0
- package/dist/Select.jsx +759 -0
- package/dist/Select.jsx.map +1 -0
- package/dist/SelectionIndicator.d.ts.map +1 -1
- package/dist/SelectionIndicator.js +86 -0
- package/dist/SelectionIndicator.js.map +1 -0
- package/dist/SelectionIndicator.jsx +50 -0
- package/dist/SelectionIndicator.jsx.map +1 -0
- package/dist/Separator.js +97 -0
- package/dist/Separator.js.map +1 -0
- package/dist/Separator.jsx +85 -0
- package/dist/Separator.jsx.map +1 -0
- package/dist/SharedElementTransition.d.ts.map +1 -1
- package/dist/SharedElementTransition.js +167 -0
- package/dist/SharedElementTransition.js.map +1 -0
- package/dist/SharedElementTransition.jsx +140 -0
- package/dist/SharedElementTransition.jsx.map +1 -0
- package/dist/Slider.d.ts +33 -1
- package/dist/Slider.d.ts.map +1 -1
- package/dist/Slider.js +515 -0
- package/dist/Slider.js.map +1 -0
- package/dist/Slider.jsx +403 -0
- package/dist/Slider.jsx.map +1 -0
- package/dist/StepList.d.ts.map +1 -1
- package/dist/StepList.js +191 -0
- package/dist/StepList.js.map +1 -0
- package/dist/StepList.jsx +136 -0
- package/dist/StepList.jsx.map +1 -0
- package/dist/Switch.d.ts +65 -2
- package/dist/Switch.d.ts.map +1 -1
- package/dist/Switch.js +534 -0
- package/dist/Switch.js.map +1 -0
- package/dist/Switch.jsx +393 -0
- package/dist/Switch.jsx.map +1 -0
- package/dist/Table.d.ts +50 -0
- package/dist/Table.d.ts.map +1 -1
- package/dist/Table.js +1766 -0
- package/dist/Table.js.map +1 -0
- package/dist/Table.jsx +1355 -0
- package/dist/Table.jsx.map +1 -0
- package/dist/Tabs.d.ts +0 -4
- package/dist/Tabs.d.ts.map +1 -1
- package/dist/Tabs.js +598 -0
- package/dist/Tabs.js.map +1 -0
- package/dist/Tabs.jsx +367 -0
- package/dist/Tabs.jsx.map +1 -0
- package/dist/TagGroup.d.ts +3 -1
- package/dist/TagGroup.d.ts.map +1 -1
- package/dist/TagGroup.js +382 -0
- package/dist/TagGroup.js.map +1 -0
- package/dist/TagGroup.jsx +273 -0
- package/dist/TagGroup.jsx.map +1 -0
- package/dist/Text.d.ts +18 -6
- package/dist/Text.d.ts.map +1 -1
- package/dist/Text.js +42 -0
- package/dist/Text.js.map +1 -0
- package/dist/Text.jsx +35 -0
- package/dist/Text.jsx.map +1 -0
- package/dist/TextField.d.ts +6 -6
- package/dist/TextField.d.ts.map +1 -1
- package/dist/TextField.js +439 -0
- package/dist/TextField.js.map +1 -0
- package/dist/TextField.jsx +406 -0
- package/dist/TextField.jsx.map +1 -0
- package/dist/TimeField.d.ts +17 -53
- package/dist/TimeField.d.ts.map +1 -1
- package/dist/TimeField.js +278 -0
- package/dist/TimeField.js.map +1 -0
- package/dist/TimeField.jsx +218 -0
- package/dist/TimeField.jsx.map +1 -0
- package/dist/Toast.d.ts +14 -0
- package/dist/Toast.d.ts.map +1 -1
- package/dist/Toast.js +551 -0
- package/dist/Toast.js.map +1 -0
- package/dist/Toast.jsx +361 -0
- package/dist/Toast.jsx.map +1 -0
- package/dist/ToggleButton.d.ts.map +1 -1
- package/dist/ToggleButton.js +123 -0
- package/dist/ToggleButton.js.map +1 -0
- package/dist/ToggleButton.jsx +88 -0
- package/dist/ToggleButton.jsx.map +1 -0
- package/dist/ToggleButtonGroup.d.ts.map +1 -1
- package/dist/ToggleButtonGroup.js +114 -0
- package/dist/ToggleButtonGroup.js.map +1 -0
- package/dist/ToggleButtonGroup.jsx +85 -0
- package/dist/ToggleButtonGroup.jsx.map +1 -0
- package/dist/Toolbar.js +112 -0
- package/dist/Toolbar.js.map +1 -0
- package/dist/Toolbar.jsx +92 -0
- package/dist/Toolbar.jsx.map +1 -0
- package/dist/Tooltip.d.ts.map +1 -1
- package/dist/Tooltip.js +539 -0
- package/dist/Tooltip.js.map +1 -0
- package/dist/Tooltip.jsx +465 -0
- package/dist/Tooltip.jsx.map +1 -0
- package/dist/Tree.d.ts +14 -2
- package/dist/Tree.d.ts.map +1 -1
- package/dist/Tree.js +1424 -0
- package/dist/Tree.js.map +1 -0
- package/dist/Tree.jsx +1172 -0
- package/dist/Tree.jsx.map +1 -0
- package/dist/Virtualizer.d.ts +16 -2
- package/dist/Virtualizer.d.ts.map +1 -1
- package/dist/Virtualizer.js +2 -0
- package/dist/Virtualizer.jsx +2 -0
- package/dist/Virtualizer2.js +751 -0
- package/dist/Virtualizer2.js.map +1 -0
- package/dist/Virtualizer2.jsx +730 -0
- package/dist/Virtualizer2.jsx.map +1 -0
- package/dist/VirtualizerLayouts.d.ts +18 -0
- package/dist/VirtualizerLayouts.d.ts.map +1 -1
- package/dist/VisuallyHidden.js +42 -0
- package/dist/VisuallyHidden.js.map +1 -0
- package/dist/VisuallyHidden.jsx +35 -0
- package/dist/VisuallyHidden.jsx.map +1 -0
- package/dist/contexts.js +33 -0
- package/dist/contexts.js.map +1 -0
- package/dist/contexts.jsx +33 -0
- package/dist/contexts.jsx.map +1 -0
- package/dist/index.d.ts +9 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +69 -23932
- package/dist/index.jsx +69 -18337
- package/dist/useDragAndDrop.d.ts +0 -8
- package/dist/useDragAndDrop.d.ts.map +1 -1
- package/dist/useDragAndDrop.js +2 -0
- package/dist/useDragAndDrop.jsx +2 -0
- package/dist/useDragAndDrop2.js +399 -0
- package/dist/useDragAndDrop2.js.map +1 -0
- package/dist/useDragAndDrop2.jsx +399 -0
- package/dist/useDragAndDrop2.jsx.map +1 -0
- package/dist/utils.d.ts +84 -11
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +285 -0
- package/dist/utils.js.map +1 -0
- package/dist/utils.jsx +277 -0
- package/dist/utils.jsx.map +1 -0
- package/dist/virtualizer/Layout.js +144 -0
- package/dist/virtualizer/Layout.js.map +1 -0
- package/dist/virtualizer/Layout.jsx +144 -0
- package/dist/virtualizer/Layout.jsx.map +1 -0
- package/package.json +395 -4
- package/src/ActionBar.tsx +10 -12
- package/src/ActionGroup.tsx +5 -3
- package/src/Autocomplete.tsx +14 -9
- package/src/Breadcrumbs.tsx +58 -39
- package/src/Button.tsx +22 -2
- package/src/Calendar.tsx +57 -11
- package/src/CalendarPicker.tsx +73 -0
- package/src/Checkbox.tsx +539 -3
- package/src/Collection.tsx +9 -3
- package/src/Color.tsx +84 -41
- package/src/ComboBox.tsx +97 -21
- package/src/DateField.tsx +304 -53
- package/src/DatePicker.tsx +402 -62
- package/src/DateRangePickerContext.tsx +2 -0
- package/src/Dialog.tsx +13 -5
- package/src/Disclosure.tsx +7 -1
- package/src/DragAndDrop.tsx +3 -1
- package/src/DropZone.tsx +3 -1
- package/src/GridList.tsx +133 -26
- package/src/Icon.tsx +3 -1
- package/src/Link.tsx +3 -1
- package/src/ListBox.tsx +354 -25
- package/src/Menu.tsx +252 -128
- package/src/Meter.tsx +3 -1
- package/src/Modal.tsx +120 -56
- package/src/NumberField.tsx +51 -8
- package/src/Popover.tsx +68 -17
- package/src/ProgressBar.tsx +3 -1
- package/src/RadioGroup.tsx +468 -4
- package/src/RangeCalendar.tsx +123 -2
- package/src/SearchField.tsx +80 -4
- package/src/Select.tsx +122 -26
- package/src/SelectionIndicator.tsx +3 -1
- package/src/SharedElementTransition.tsx +95 -37
- package/src/Slider.tsx +159 -13
- package/src/StepList.tsx +0 -7
- package/src/Switch.tsx +395 -2
- package/src/Table.tsx +428 -99
- package/src/Tabs.tsx +17 -45
- package/src/TagGroup.tsx +29 -7
- package/src/Text.tsx +31 -10
- package/src/TextField.tsx +44 -6
- package/src/TimeField.tsx +127 -192
- package/src/Toast.tsx +79 -14
- package/src/ToggleButton.tsx +3 -1
- package/src/ToggleButtonGroup.tsx +3 -1
- package/src/Tooltip.tsx +3 -1
- package/src/Tree.tsx +91 -13
- package/src/Virtualizer.tsx +180 -31
- package/src/VirtualizerLayouts.ts +45 -10
- package/src/index.ts +51 -8
- package/src/useDragAndDrop.ts +8 -10
- package/src/utils.tsx +246 -30
- package/dist/HiddenTimeInput.d.ts +0 -25
- package/dist/HiddenTimeInput.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/index.jsx.map +0 -1
- package/src/HiddenTimeInput.tsx +0 -133
package/src/RadioGroup.tsx
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import {
|
|
9
9
|
type JSX,
|
|
10
10
|
type ParentProps,
|
|
11
|
+
type Context,
|
|
11
12
|
createContext,
|
|
12
13
|
createMemo,
|
|
13
14
|
createSignal,
|
|
@@ -43,9 +44,11 @@ import {
|
|
|
43
44
|
type ClassNameOrFunction,
|
|
44
45
|
type StyleOrFunction,
|
|
45
46
|
type SlotProps,
|
|
47
|
+
Provider,
|
|
46
48
|
useRenderProps,
|
|
47
49
|
filterDOMProps,
|
|
48
50
|
} from "./utils";
|
|
51
|
+
import { TextContext } from "./Text";
|
|
49
52
|
|
|
50
53
|
type RefLike<T> = ((el: T) => void) | { current?: T | null } | undefined;
|
|
51
54
|
|
|
@@ -147,6 +150,15 @@ export interface RadioGroupProps
|
|
|
147
150
|
description?: JSX.Element;
|
|
148
151
|
/** An error message for the radio group. */
|
|
149
152
|
errorMessage?: JSX.Element;
|
|
153
|
+
/**
|
|
154
|
+
* Whether this component renders the visible description/error help-text nodes.
|
|
155
|
+
* Defaults to `true`. A styled layer (e.g. solid-spectrum) passes `false` to keep
|
|
156
|
+
* the id-minting and `aria-describedby` wiring here (so child radios inherit the
|
|
157
|
+
* group's shared description via `radioGroupData`) while owning the visible node
|
|
158
|
+
* itself — mirroring RAC, where the group exposes a `TextContext`/`FieldError`
|
|
159
|
+
* slot rather than rendering its own help text.
|
|
160
|
+
*/
|
|
161
|
+
renderHelpText?: boolean;
|
|
150
162
|
}
|
|
151
163
|
|
|
152
164
|
export interface RadioProps extends Omit<AriaRadioProps, "children">, SlotProps {
|
|
@@ -213,7 +225,14 @@ export function RadioGroup(props: ParentProps<RadioGroupProps>): JSX.Element {
|
|
|
213
225
|
props,
|
|
214
226
|
) as ParentProps<RadioGroupProps>)
|
|
215
227
|
: props;
|
|
216
|
-
const [local, ariaProps] = splitProps(mergedProps, [
|
|
228
|
+
const [local, ariaProps] = splitProps(mergedProps, [
|
|
229
|
+
"class",
|
|
230
|
+
"style",
|
|
231
|
+
"render",
|
|
232
|
+
"ref",
|
|
233
|
+
"slot",
|
|
234
|
+
"renderHelpText",
|
|
235
|
+
]);
|
|
217
236
|
|
|
218
237
|
const state = createRadioGroupState(() => ({
|
|
219
238
|
value: mergedProps.value,
|
|
@@ -255,7 +274,9 @@ export function RadioGroup(props: ParentProps<RadioGroupProps>): JSX.Element {
|
|
|
255
274
|
|
|
256
275
|
const renderProps = useRenderProps(
|
|
257
276
|
{
|
|
258
|
-
children
|
|
277
|
+
get children() {
|
|
278
|
+
return props.children;
|
|
279
|
+
},
|
|
259
280
|
class: local.class,
|
|
260
281
|
style: local.style,
|
|
261
282
|
defaultClassName: "solidaria-RadioGroup",
|
|
@@ -366,12 +387,12 @@ export function RadioGroup(props: ParentProps<RadioGroupProps>): JSX.Element {
|
|
|
366
387
|
return (
|
|
367
388
|
<>
|
|
368
389
|
{renderedChildren()}
|
|
369
|
-
<Show when={mergedProps.description}>
|
|
390
|
+
<Show when={(local.renderHelpText ?? true) && mergedProps.description}>
|
|
370
391
|
<div {...(groupAria.descriptionProps as unknown as JSX.HTMLAttributes<HTMLDivElement>)}>
|
|
371
392
|
{mergedProps.description}
|
|
372
393
|
</div>
|
|
373
394
|
</Show>
|
|
374
|
-
<Show when={isInvalid() && mergedProps.errorMessage}>
|
|
395
|
+
<Show when={(local.renderHelpText ?? true) && isInvalid() && mergedProps.errorMessage}>
|
|
375
396
|
<div {...(groupAria.errorMessageProps as unknown as JSX.HTMLAttributes<HTMLDivElement>)}>
|
|
376
397
|
{mergedProps.errorMessage}
|
|
377
398
|
</div>
|
|
@@ -766,3 +787,446 @@ export function Radio(props: RadioProps): JSX.Element {
|
|
|
766
787
|
</Show>
|
|
767
788
|
);
|
|
768
789
|
}
|
|
790
|
+
|
|
791
|
+
// ============================================================================
|
|
792
|
+
// RadioField + RadioButton — the RAC form-field split (RAC 1.19)
|
|
793
|
+
// ----------------------------------------------------------------------------
|
|
794
|
+
// Upstream split the monolithic Radio into a RadioField wrapper (owns the radio
|
|
795
|
+
// aria + optional description) containing a RadioButton control (the clickable
|
|
796
|
+
// indicator + label). Mirrors react-aria-components/src/RadioGroup.tsx. The
|
|
797
|
+
// legacy `Radio` above stays as the deprecated monolith for back-compat.
|
|
798
|
+
//
|
|
799
|
+
// Spine note: upstream wires the two halves with InternalRadioContext +
|
|
800
|
+
// SelectionIndicatorContext + TextContext slots through `<Provider>`. Our
|
|
801
|
+
// `<Provider>` is inert and TextContext carries no slots yet
|
|
802
|
+
// (`port-context-slots`), so — exactly like RadioImpl already does — we use a
|
|
803
|
+
// native Solid context and bridge `description`/`errorMessage` with explicit
|
|
804
|
+
// ids. Like the legacy `Radio`, both halves require a surrounding RadioGroup.
|
|
805
|
+
// ============================================================================
|
|
806
|
+
|
|
807
|
+
export interface RadioFieldRenderProps {
|
|
808
|
+
/** Whether the radio is selected. */
|
|
809
|
+
isSelected: boolean;
|
|
810
|
+
/** Whether the radio is disabled. */
|
|
811
|
+
isDisabled: boolean;
|
|
812
|
+
/** Whether the radio is read only. */
|
|
813
|
+
isReadOnly: boolean;
|
|
814
|
+
/** Whether the radio is invalid. */
|
|
815
|
+
isInvalid: boolean;
|
|
816
|
+
/** Whether the radio is required. */
|
|
817
|
+
isRequired: boolean;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
export interface RadioButtonRenderProps extends RadioRenderProps {}
|
|
821
|
+
|
|
822
|
+
export interface RadioFieldProps extends Omit<AriaRadioProps, "children">, SlotProps {
|
|
823
|
+
/** The children of the component (typically a `RadioButton`). A function may receive render props. */
|
|
824
|
+
children?: RenderChildren<RadioFieldRenderProps>;
|
|
825
|
+
/** The CSS className for the element. */
|
|
826
|
+
class?: ClassNameOrFunction<RadioFieldRenderProps>;
|
|
827
|
+
/** The inline style for the element. */
|
|
828
|
+
style?: StyleOrFunction<RadioFieldRenderProps>;
|
|
829
|
+
/** Ref for the radio field root element. */
|
|
830
|
+
ref?: RefLike<HTMLDivElement>;
|
|
831
|
+
/** Ref for the underlying input element. */
|
|
832
|
+
inputRef?: RefLike<HTMLInputElement>;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
export interface RadioButtonProps extends SlotProps {
|
|
836
|
+
/** The children of the component. A function may receive render props. */
|
|
837
|
+
children?: RenderChildren<RadioButtonRenderProps>;
|
|
838
|
+
/** The CSS className for the element. */
|
|
839
|
+
class?: ClassNameOrFunction<RadioButtonRenderProps>;
|
|
840
|
+
/** The inline style for the element. */
|
|
841
|
+
style?: StyleOrFunction<RadioButtonRenderProps>;
|
|
842
|
+
/** Ref for the outer label element. */
|
|
843
|
+
ref?: RefLike<HTMLLabelElement>;
|
|
844
|
+
/** Handler called when hover starts. */
|
|
845
|
+
onHoverStart?: () => void;
|
|
846
|
+
/** Handler called when hover ends. */
|
|
847
|
+
onHoverEnd?: () => void;
|
|
848
|
+
/** Handler called when hover state changes. */
|
|
849
|
+
onHoverChange?: (isHovered: boolean) => void;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
export interface RadioFieldContextValue extends Partial<RadioFieldProps> {
|
|
853
|
+
slots?: Record<string, Partial<RadioFieldProps>>;
|
|
854
|
+
}
|
|
855
|
+
export const RadioFieldContext = createContext<RadioFieldContextValue | null>(null);
|
|
856
|
+
|
|
857
|
+
/** Carries the radio aria + state from a RadioField/Radio wrapper to its RadioButton. */
|
|
858
|
+
interface InternalRadioContextValue {
|
|
859
|
+
isSelected: () => boolean;
|
|
860
|
+
isPressed: () => boolean;
|
|
861
|
+
isDisabled: () => boolean;
|
|
862
|
+
labelProps: () => JSX.LabelHTMLAttributes<HTMLLabelElement>;
|
|
863
|
+
inputProps: () => JSX.InputHTMLAttributes<HTMLInputElement>;
|
|
864
|
+
setInputRef: (el: HTMLInputElement) => void;
|
|
865
|
+
defaultClassName: string;
|
|
866
|
+
}
|
|
867
|
+
const InternalRadioContext = createContext<InternalRadioContextValue | null>(null);
|
|
868
|
+
|
|
869
|
+
/**
|
|
870
|
+
* A RadioField represents an individual option within a radio group, containing a
|
|
871
|
+
* `RadioButton` and optional description. Must be rendered inside a `RadioGroup`.
|
|
872
|
+
* Per-option help text is wired through a TextContext description slot — render it
|
|
873
|
+
* with `<Text slot="description">`. (Radios have no per-option error slot; errors
|
|
874
|
+
* are reported at the group level.)
|
|
875
|
+
*
|
|
876
|
+
* @example
|
|
877
|
+
* ```tsx
|
|
878
|
+
* <RadioGroup>
|
|
879
|
+
* <RadioField value="a">
|
|
880
|
+
* <RadioButton>Option A</RadioButton>
|
|
881
|
+
* <Text slot="description">The first option</Text>
|
|
882
|
+
* </RadioField>
|
|
883
|
+
* </RadioGroup>
|
|
884
|
+
* ```
|
|
885
|
+
*/
|
|
886
|
+
export function RadioField(props: RadioFieldProps): JSX.Element {
|
|
887
|
+
const getState = createMemo(() => useContext(RadioGroupStateContext));
|
|
888
|
+
return (
|
|
889
|
+
<Show when={getState()} fallback={null} keyed>
|
|
890
|
+
{(state) => <RadioFieldImpl fieldProps={props} state={state} />}
|
|
891
|
+
</Show>
|
|
892
|
+
);
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
function RadioFieldImpl(props: {
|
|
896
|
+
fieldProps: RadioFieldProps;
|
|
897
|
+
state: RadioGroupState;
|
|
898
|
+
}): JSX.Element {
|
|
899
|
+
const [inputElement, setInputElement] = createSignal<HTMLInputElement | null>(null);
|
|
900
|
+
const { state } = props;
|
|
901
|
+
const contextProps = useContext(RadioFieldContext);
|
|
902
|
+
const contextSlotProps = contextProps?.slots?.[props.fieldProps.slot ?? "default"];
|
|
903
|
+
const contextBaseProps = createMemo<Partial<RadioFieldProps>>(() => {
|
|
904
|
+
if (!contextProps) return {};
|
|
905
|
+
const { slots: _slots, ...rest } = contextProps;
|
|
906
|
+
return rest;
|
|
907
|
+
});
|
|
908
|
+
const fieldProps = contextProps
|
|
909
|
+
? (mergeProps(contextBaseProps(), contextSlotProps ?? {}, props.fieldProps) as RadioFieldProps)
|
|
910
|
+
: props.fieldProps;
|
|
911
|
+
const inputRefs = createMemo(
|
|
912
|
+
() =>
|
|
913
|
+
[contextBaseProps().inputRef, contextSlotProps?.inputRef, props.fieldProps.inputRef].filter(
|
|
914
|
+
Boolean,
|
|
915
|
+
) as RefLike<HTMLInputElement>[],
|
|
916
|
+
);
|
|
917
|
+
|
|
918
|
+
// `children` is split out of ariaProps so neither the inputAriaProps key-copy
|
|
919
|
+
// loop nor the hook accessor spread eagerly reads it — reading a Solid
|
|
920
|
+
// `children` getter instantiates the nested RadioButton, and doing so OUTSIDE
|
|
921
|
+
// InternalRadioContext both breaks its binding and recurses.
|
|
922
|
+
const [local, ariaProps] = splitProps(fieldProps, [
|
|
923
|
+
"class",
|
|
924
|
+
"style",
|
|
925
|
+
"ref",
|
|
926
|
+
"inputRef",
|
|
927
|
+
"slot",
|
|
928
|
+
"children",
|
|
929
|
+
]);
|
|
930
|
+
const inputAriaProps = createMemo(() => {
|
|
931
|
+
const clean: Record<string, unknown> = {};
|
|
932
|
+
for (const key in ariaProps as Record<string, unknown>) {
|
|
933
|
+
if (!key.startsWith("data-")) {
|
|
934
|
+
clean[key] = (ariaProps as Record<string, unknown>)[key];
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
return clean as typeof ariaProps;
|
|
938
|
+
});
|
|
939
|
+
|
|
940
|
+
const radioAria = createRadio(
|
|
941
|
+
() => ({
|
|
942
|
+
...inputAriaProps(),
|
|
943
|
+
// The hook reads `children` only to decide if an aria-label is needed; the
|
|
944
|
+
// visible label lives in the RadioButton, so report presence as a literal.
|
|
945
|
+
children: true,
|
|
946
|
+
}),
|
|
947
|
+
state,
|
|
948
|
+
inputElement,
|
|
949
|
+
);
|
|
950
|
+
|
|
951
|
+
// The hook mints the description slot id and bakes the combined aria-describedby
|
|
952
|
+
// (own description + the group's shared description/error) into the input; the
|
|
953
|
+
// field exposes that id through TextContext so a `<Text slot="description">`
|
|
954
|
+
// child resolves it. Mirrors react-aria-components' RadioField Provider value
|
|
955
|
+
// list (description slot only — radios have no per-option error slot).
|
|
956
|
+
const textSlots = {
|
|
957
|
+
slots: {
|
|
958
|
+
get description() {
|
|
959
|
+
return radioAria.descriptionProps;
|
|
960
|
+
},
|
|
961
|
+
},
|
|
962
|
+
};
|
|
963
|
+
|
|
964
|
+
const setInputRef = (el: HTMLInputElement) => {
|
|
965
|
+
setInputElement(el);
|
|
966
|
+
el.addEventListener("invalid", (event) => {
|
|
967
|
+
state.updateValidation(getNativeValidation(el));
|
|
968
|
+
state.commitValidation();
|
|
969
|
+
el.focus();
|
|
970
|
+
event.preventDefault();
|
|
971
|
+
});
|
|
972
|
+
el.addEventListener("change", () => {
|
|
973
|
+
state.updateValidation(el.validity.valid ? validValidation : getNativeValidation(el));
|
|
974
|
+
state.commitValidation();
|
|
975
|
+
});
|
|
976
|
+
for (const ref of inputRefs()) {
|
|
977
|
+
assignRef(ref, el);
|
|
978
|
+
}
|
|
979
|
+
};
|
|
980
|
+
const setFieldRef = (el: HTMLDivElement) => {
|
|
981
|
+
assignRef(local.ref, el);
|
|
982
|
+
};
|
|
983
|
+
|
|
984
|
+
const internalContext: InternalRadioContextValue = {
|
|
985
|
+
isSelected: () => radioAria.isSelected(),
|
|
986
|
+
isPressed: () => radioAria.isPressed(),
|
|
987
|
+
isDisabled: () => radioAria.isDisabled,
|
|
988
|
+
labelProps: () => radioAria.labelProps,
|
|
989
|
+
inputProps: () => radioAria.inputProps,
|
|
990
|
+
setInputRef,
|
|
991
|
+
defaultClassName: "solidaria-RadioButton",
|
|
992
|
+
};
|
|
993
|
+
|
|
994
|
+
const selectionIndicatorContext = createMemo<SelectionIndicatorContextValue>(() => ({
|
|
995
|
+
isSelected: radioAria.isSelected,
|
|
996
|
+
}));
|
|
997
|
+
|
|
998
|
+
const renderValues = createMemo<RadioFieldRenderProps>(() => ({
|
|
999
|
+
isSelected: radioAria.isSelected(),
|
|
1000
|
+
isDisabled: radioAria.isDisabled,
|
|
1001
|
+
isReadOnly: state.isReadOnly,
|
|
1002
|
+
isInvalid: state.isInvalid,
|
|
1003
|
+
isRequired: state.isRequired,
|
|
1004
|
+
}));
|
|
1005
|
+
|
|
1006
|
+
const renderProps = useRenderProps(
|
|
1007
|
+
{
|
|
1008
|
+
children: fieldProps.children,
|
|
1009
|
+
class: local.class,
|
|
1010
|
+
style: local.style,
|
|
1011
|
+
defaultClassName: "solidaria-RadioField",
|
|
1012
|
+
},
|
|
1013
|
+
renderValues,
|
|
1014
|
+
);
|
|
1015
|
+
|
|
1016
|
+
const domProps = createMemo(() => {
|
|
1017
|
+
const filtered = filterDOMProps(ariaProps, { global: true });
|
|
1018
|
+
delete (filtered as Record<string, unknown>).id;
|
|
1019
|
+
delete (filtered as Record<string, unknown>).onClick;
|
|
1020
|
+
return filtered;
|
|
1021
|
+
});
|
|
1022
|
+
|
|
1023
|
+
// Children are accessed inside the providers (component-execution owner) so a
|
|
1024
|
+
// nested RadioButton's useContext binds to InternalRadioContext.
|
|
1025
|
+
const FieldChildren = () => {
|
|
1026
|
+
const childRenderValues: RadioFieldRenderProps = {
|
|
1027
|
+
get isSelected() {
|
|
1028
|
+
return radioAria.isSelected();
|
|
1029
|
+
},
|
|
1030
|
+
get isDisabled() {
|
|
1031
|
+
return radioAria.isDisabled;
|
|
1032
|
+
},
|
|
1033
|
+
get isReadOnly() {
|
|
1034
|
+
return state.isReadOnly;
|
|
1035
|
+
},
|
|
1036
|
+
get isInvalid() {
|
|
1037
|
+
return state.isInvalid;
|
|
1038
|
+
},
|
|
1039
|
+
get isRequired() {
|
|
1040
|
+
return state.isRequired;
|
|
1041
|
+
},
|
|
1042
|
+
};
|
|
1043
|
+
const renderedChildren = createMemo(() => {
|
|
1044
|
+
const children = fieldProps.children;
|
|
1045
|
+
return typeof children === "function" ? children(childRenderValues) : children;
|
|
1046
|
+
});
|
|
1047
|
+
return <>{renderedChildren()}</>;
|
|
1048
|
+
};
|
|
1049
|
+
|
|
1050
|
+
return (
|
|
1051
|
+
<div
|
|
1052
|
+
{...domProps()}
|
|
1053
|
+
ref={setFieldRef}
|
|
1054
|
+
class={renderProps.class()}
|
|
1055
|
+
style={renderProps.style()}
|
|
1056
|
+
slot={local.slot}
|
|
1057
|
+
data-selected={radioAria.isSelected() || undefined}
|
|
1058
|
+
data-disabled={radioAria.isDisabled || undefined}
|
|
1059
|
+
data-readonly={state.isReadOnly || undefined}
|
|
1060
|
+
data-invalid={state.isInvalid || undefined}
|
|
1061
|
+
data-required={state.isRequired || undefined}
|
|
1062
|
+
>
|
|
1063
|
+
<SelectionIndicatorContext.Provider value={selectionIndicatorContext()}>
|
|
1064
|
+
<InternalRadioContext.Provider value={internalContext}>
|
|
1065
|
+
<Provider values={[[TextContext, textSlots]] as Array<[Context<unknown>, unknown]>}>
|
|
1066
|
+
<FieldChildren />
|
|
1067
|
+
</Provider>
|
|
1068
|
+
</InternalRadioContext.Provider>
|
|
1069
|
+
</SelectionIndicatorContext.Provider>
|
|
1070
|
+
</div>
|
|
1071
|
+
);
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
/**
|
|
1075
|
+
* A RadioButton is the clickable area of a radio, including the indicator and label.
|
|
1076
|
+
* Must be rendered inside a `RadioField` (or the legacy `Radio`).
|
|
1077
|
+
*/
|
|
1078
|
+
export function RadioButton(props: RadioButtonProps): JSX.Element {
|
|
1079
|
+
const getCtx = createMemo(() => useContext(InternalRadioContext));
|
|
1080
|
+
const getState = createMemo(() => useContext(RadioGroupStateContext));
|
|
1081
|
+
return (
|
|
1082
|
+
<Show when={getCtx()} fallback={null} keyed>
|
|
1083
|
+
{(ctx) => (
|
|
1084
|
+
<Show when={getState()} fallback={null} keyed>
|
|
1085
|
+
{(state) => <RadioButtonImpl buttonProps={props} ctx={ctx} state={state} />}
|
|
1086
|
+
</Show>
|
|
1087
|
+
)}
|
|
1088
|
+
</Show>
|
|
1089
|
+
);
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
function RadioButtonImpl(props: {
|
|
1093
|
+
buttonProps: RadioButtonProps;
|
|
1094
|
+
ctx: InternalRadioContextValue;
|
|
1095
|
+
state: RadioGroupState;
|
|
1096
|
+
}): JSX.Element {
|
|
1097
|
+
const { ctx, state } = props;
|
|
1098
|
+
|
|
1099
|
+
const { isFocused, isFocusVisible, focusProps } = createFocusRing();
|
|
1100
|
+
const { isHovered, hoverProps } = createHover({
|
|
1101
|
+
get isDisabled() {
|
|
1102
|
+
return ctx.isDisabled() || state.isReadOnly;
|
|
1103
|
+
},
|
|
1104
|
+
onHoverStart: props.buttonProps.onHoverStart,
|
|
1105
|
+
onHoverEnd: props.buttonProps.onHoverEnd,
|
|
1106
|
+
onHoverChange: props.buttonProps.onHoverChange,
|
|
1107
|
+
});
|
|
1108
|
+
|
|
1109
|
+
const renderValues = createMemo<RadioButtonRenderProps>(() => ({
|
|
1110
|
+
isSelected: ctx.isSelected(),
|
|
1111
|
+
isHovered: isHovered(),
|
|
1112
|
+
isPressed: ctx.isPressed(),
|
|
1113
|
+
isFocused: isFocused(),
|
|
1114
|
+
isFocusVisible: isFocusVisible(),
|
|
1115
|
+
isDisabled: ctx.isDisabled(),
|
|
1116
|
+
isReadOnly: state.isReadOnly,
|
|
1117
|
+
isInvalid: state.isInvalid,
|
|
1118
|
+
isRequired: state.isRequired,
|
|
1119
|
+
}));
|
|
1120
|
+
|
|
1121
|
+
const renderProps = useRenderProps(
|
|
1122
|
+
{
|
|
1123
|
+
children: props.buttonProps.children,
|
|
1124
|
+
class: props.buttonProps.class,
|
|
1125
|
+
style: props.buttonProps.style,
|
|
1126
|
+
defaultClassName: ctx.defaultClassName,
|
|
1127
|
+
},
|
|
1128
|
+
renderValues,
|
|
1129
|
+
);
|
|
1130
|
+
|
|
1131
|
+
const cleanLabelProps = () => {
|
|
1132
|
+
const { ref: _ref1, ...rest } = ctx.labelProps() as Record<string, unknown>;
|
|
1133
|
+
return rest;
|
|
1134
|
+
};
|
|
1135
|
+
const cleanHoverProps = () => {
|
|
1136
|
+
const { ref: _ref2, ...rest } = hoverProps as Record<string, unknown>;
|
|
1137
|
+
return rest;
|
|
1138
|
+
};
|
|
1139
|
+
const cleanInputProps = () => {
|
|
1140
|
+
const {
|
|
1141
|
+
ref: _ref3,
|
|
1142
|
+
onFocus: _onFocus,
|
|
1143
|
+
onBlur: _onBlur,
|
|
1144
|
+
...rest
|
|
1145
|
+
} = ctx.inputProps() as Record<string, unknown>;
|
|
1146
|
+
return rest;
|
|
1147
|
+
};
|
|
1148
|
+
const cleanFocusProps = () => {
|
|
1149
|
+
const {
|
|
1150
|
+
ref: _ref4,
|
|
1151
|
+
onFocus: _onFocus,
|
|
1152
|
+
onBlur: _onBlur,
|
|
1153
|
+
...rest
|
|
1154
|
+
} = focusProps as Record<string, unknown>;
|
|
1155
|
+
return rest;
|
|
1156
|
+
};
|
|
1157
|
+
const handleInputFocus: JSX.EventHandler<HTMLInputElement, FocusEvent> = (event) => {
|
|
1158
|
+
(
|
|
1159
|
+
ctx.inputProps() as unknown as { onFocus?: JSX.EventHandler<HTMLInputElement, FocusEvent> }
|
|
1160
|
+
).onFocus?.(event);
|
|
1161
|
+
(
|
|
1162
|
+
focusProps as unknown as { onFocus?: JSX.EventHandler<HTMLInputElement, FocusEvent> }
|
|
1163
|
+
).onFocus?.(event);
|
|
1164
|
+
};
|
|
1165
|
+
const handleInputBlur: JSX.EventHandler<HTMLInputElement, FocusEvent> = (event) => {
|
|
1166
|
+
(
|
|
1167
|
+
ctx.inputProps() as unknown as { onBlur?: JSX.EventHandler<HTMLInputElement, FocusEvent> }
|
|
1168
|
+
).onBlur?.(event);
|
|
1169
|
+
(focusProps as unknown as { onBlur?: JSX.EventHandler<HTMLInputElement, FocusEvent> }).onBlur?.(
|
|
1170
|
+
event,
|
|
1171
|
+
);
|
|
1172
|
+
};
|
|
1173
|
+
const handleInputClick: JSX.EventHandler<HTMLInputElement, MouseEvent> = (event) => {
|
|
1174
|
+
(
|
|
1175
|
+
ctx.inputProps() as unknown as { onClick?: JSX.EventHandler<HTMLInputElement, MouseEvent> }
|
|
1176
|
+
).onClick?.(event);
|
|
1177
|
+
};
|
|
1178
|
+
const handleInputInvalid: JSX.EventHandler<HTMLInputElement, Event> = (event) => {
|
|
1179
|
+
state.updateValidation(getNativeValidation(event.currentTarget));
|
|
1180
|
+
state.commitValidation();
|
|
1181
|
+
event.currentTarget.focus();
|
|
1182
|
+
event.preventDefault();
|
|
1183
|
+
};
|
|
1184
|
+
const handleInputChange: JSX.EventHandler<HTMLInputElement, Event> = (event) => {
|
|
1185
|
+
(
|
|
1186
|
+
ctx.inputProps() as unknown as { onChange?: JSX.EventHandler<HTMLInputElement, Event> }
|
|
1187
|
+
).onChange?.(event);
|
|
1188
|
+
state.updateValidation(
|
|
1189
|
+
event.currentTarget.validity.valid
|
|
1190
|
+
? validValidation
|
|
1191
|
+
: getNativeValidation(event.currentTarget),
|
|
1192
|
+
);
|
|
1193
|
+
state.commitValidation();
|
|
1194
|
+
};
|
|
1195
|
+
const setButtonRef = (el: HTMLLabelElement) => {
|
|
1196
|
+
assignRef(props.buttonProps.ref, el);
|
|
1197
|
+
};
|
|
1198
|
+
|
|
1199
|
+
return (
|
|
1200
|
+
<label
|
|
1201
|
+
{...cleanLabelProps()}
|
|
1202
|
+
{...cleanHoverProps()}
|
|
1203
|
+
ref={setButtonRef}
|
|
1204
|
+
class={renderProps.class()}
|
|
1205
|
+
style={renderProps.style()}
|
|
1206
|
+
slot={props.buttonProps.slot}
|
|
1207
|
+
data-selected={ctx.isSelected() || undefined}
|
|
1208
|
+
data-pressed={ctx.isPressed() || undefined}
|
|
1209
|
+
data-hovered={isHovered() || undefined}
|
|
1210
|
+
data-focused={isFocused() || undefined}
|
|
1211
|
+
data-focus-visible={isFocusVisible() || undefined}
|
|
1212
|
+
data-disabled={ctx.isDisabled() || undefined}
|
|
1213
|
+
data-readonly={state.isReadOnly || undefined}
|
|
1214
|
+
data-invalid={state.isInvalid || undefined}
|
|
1215
|
+
data-required={state.isRequired || undefined}
|
|
1216
|
+
>
|
|
1217
|
+
<VisuallyHidden>
|
|
1218
|
+
<input
|
|
1219
|
+
ref={ctx.setInputRef}
|
|
1220
|
+
{...cleanInputProps()}
|
|
1221
|
+
{...cleanFocusProps()}
|
|
1222
|
+
onFocus={handleInputFocus}
|
|
1223
|
+
onBlur={handleInputBlur}
|
|
1224
|
+
onInvalid={handleInputInvalid}
|
|
1225
|
+
onChange={handleInputChange}
|
|
1226
|
+
onClick={handleInputClick}
|
|
1227
|
+
/>
|
|
1228
|
+
</VisuallyHidden>
|
|
1229
|
+
{renderProps.renderChildren()}
|
|
1230
|
+
</label>
|
|
1231
|
+
);
|
|
1232
|
+
}
|
package/src/RangeCalendar.tsx
CHANGED
|
@@ -196,6 +196,13 @@ export function useRangeCalendarContext(): RangeCalendarState<DateValue> {
|
|
|
196
196
|
export function RangeCalendar<T extends DateValue = CalendarDate>(
|
|
197
197
|
props: RangeCalendarProps<T>,
|
|
198
198
|
): JSX.Element {
|
|
199
|
+
// When rendered inside a composite that owns the range state (e.g.
|
|
200
|
+
// DateRangePicker provides `RangeCalendarContext`), reuse that shared state
|
|
201
|
+
// instead of minting a fresh one — otherwise the composite's focus/anchor
|
|
202
|
+
// flags (e.g. the popover-open `setFocused(true)`) drive a different state
|
|
203
|
+
// instance than the one this grid renders. Mirrors the single `Calendar`.
|
|
204
|
+
const inheritedState = useContext(RangeCalendarContext);
|
|
205
|
+
|
|
199
206
|
// Use hydration-safe pattern for client-only rendering
|
|
200
207
|
const isHydrated = useIsHydrated();
|
|
201
208
|
|
|
@@ -209,11 +216,106 @@ export function RangeCalendar<T extends DateValue = CalendarDate>(
|
|
|
209
216
|
/>
|
|
210
217
|
}
|
|
211
218
|
>
|
|
212
|
-
<RangeCalendarInner {...props} />
|
|
219
|
+
<Show when={inheritedState} fallback={<RangeCalendarInner {...props} />}>
|
|
220
|
+
<RangeCalendarWithState
|
|
221
|
+
state={inheritedState as RangeCalendarState<DateValue>}
|
|
222
|
+
{...props}
|
|
223
|
+
/>
|
|
224
|
+
</Show>
|
|
213
225
|
</Show>
|
|
214
226
|
);
|
|
215
227
|
}
|
|
216
228
|
|
|
229
|
+
/**
|
|
230
|
+
* RangeCalendar variant that renders against an externally-owned state (from
|
|
231
|
+
* `RangeCalendarContext`) rather than creating its own. Mirrors the single
|
|
232
|
+
* `CalendarWithState`.
|
|
233
|
+
*/
|
|
234
|
+
function RangeCalendarWithState<T extends DateValue = CalendarDate>(
|
|
235
|
+
props: RangeCalendarProps<T> & { state: RangeCalendarState<DateValue> },
|
|
236
|
+
): JSX.Element {
|
|
237
|
+
const [local, , rest] = splitProps(
|
|
238
|
+
props,
|
|
239
|
+
["children", "class", "style", "slot", "state", "ref"],
|
|
240
|
+
[
|
|
241
|
+
"value",
|
|
242
|
+
"defaultValue",
|
|
243
|
+
"onChange",
|
|
244
|
+
"minValue",
|
|
245
|
+
"maxValue",
|
|
246
|
+
"isDisabled",
|
|
247
|
+
"isReadOnly",
|
|
248
|
+
"focusedValue",
|
|
249
|
+
"defaultFocusedValue",
|
|
250
|
+
"onFocusChange",
|
|
251
|
+
"locale",
|
|
252
|
+
"createCalendar",
|
|
253
|
+
"isDateUnavailable",
|
|
254
|
+
"visibleMonths",
|
|
255
|
+
"pageBehavior",
|
|
256
|
+
"selectionAlignment",
|
|
257
|
+
"isDateDisabled",
|
|
258
|
+
"validationState",
|
|
259
|
+
"allowsNonContiguousRanges",
|
|
260
|
+
"firstDayOfWeek",
|
|
261
|
+
],
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
const state = () => props.state;
|
|
265
|
+
|
|
266
|
+
const calendarAria = createRangeCalendar(rest, state());
|
|
267
|
+
|
|
268
|
+
const renderValues = createMemo<RangeCalendarRenderProps>(() => ({
|
|
269
|
+
isDisabled: state().isDisabled(),
|
|
270
|
+
isReadOnly: state().isReadOnly(),
|
|
271
|
+
isInvalid: state().isValueInvalid(),
|
|
272
|
+
isDragging: state().isDragging(),
|
|
273
|
+
}));
|
|
274
|
+
|
|
275
|
+
const renderProps = useRenderProps(
|
|
276
|
+
{
|
|
277
|
+
class: local.class,
|
|
278
|
+
style: local.style,
|
|
279
|
+
defaultClassName: "solidaria-RangeCalendar",
|
|
280
|
+
},
|
|
281
|
+
renderValues,
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
return (
|
|
285
|
+
<RangeCalendarStateContext.Provider value={state()}>
|
|
286
|
+
<RangeCalendarContext.Provider value={state()}>
|
|
287
|
+
<div
|
|
288
|
+
{...calendarAria.calendarProps}
|
|
289
|
+
ref={(el) => assignRef(local.ref, el)}
|
|
290
|
+
class={renderProps.class()}
|
|
291
|
+
style={renderProps.style()}
|
|
292
|
+
data-disabled={dataAttr(state().isDisabled())}
|
|
293
|
+
data-readonly={dataAttr(state().isReadOnly())}
|
|
294
|
+
data-invalid={dataAttr(state().isValueInvalid())}
|
|
295
|
+
data-dragging={dataAttr(state().isDragging())}
|
|
296
|
+
>
|
|
297
|
+
<VisuallyHidden>
|
|
298
|
+
<h2>{String(calendarAria.calendarProps["aria-label"] ?? "")}</h2>
|
|
299
|
+
</VisuallyHidden>
|
|
300
|
+
{props.children}
|
|
301
|
+
{/* For touch screen readers, a visually hidden next button after the
|
|
302
|
+
* month grid so it's easy to navigate after reaching the end without
|
|
303
|
+
* going all the way back to the start. Mirrors react-aria-components
|
|
304
|
+
* Calendar (and the headless Calendar). */}
|
|
305
|
+
<VisuallyHidden>
|
|
306
|
+
<button
|
|
307
|
+
aria-label={String(calendarAria.nextButtonProps["aria-label"] ?? "")}
|
|
308
|
+
disabled={Boolean(calendarAria.nextButtonProps.disabled)}
|
|
309
|
+
onClick={() => state().focusNextPage()}
|
|
310
|
+
tabIndex={-1}
|
|
311
|
+
/>
|
|
312
|
+
</VisuallyHidden>
|
|
313
|
+
</div>
|
|
314
|
+
</RangeCalendarContext.Provider>
|
|
315
|
+
</RangeCalendarStateContext.Provider>
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
217
319
|
/**
|
|
218
320
|
* Internal RangeCalendar component that renders after client mount.
|
|
219
321
|
*/
|
|
@@ -284,6 +386,18 @@ function RangeCalendarInner<T extends DateValue = CalendarDate>(
|
|
|
284
386
|
<h2>{String(calendarAria.calendarProps["aria-label"] ?? "")}</h2>
|
|
285
387
|
</VisuallyHidden>
|
|
286
388
|
{props.children}
|
|
389
|
+
{/* For touch screen readers, a visually hidden next button after the
|
|
390
|
+
* month grid so it's easy to navigate after reaching the end without
|
|
391
|
+
* going all the way back to the start. Mirrors react-aria-components
|
|
392
|
+
* Calendar (and the headless Calendar). */}
|
|
393
|
+
<VisuallyHidden>
|
|
394
|
+
<button
|
|
395
|
+
aria-label={String(calendarAria.nextButtonProps["aria-label"] ?? "")}
|
|
396
|
+
disabled={Boolean(calendarAria.nextButtonProps.disabled)}
|
|
397
|
+
onClick={() => state.focusNextPage()}
|
|
398
|
+
tabIndex={-1}
|
|
399
|
+
/>
|
|
400
|
+
</VisuallyHidden>
|
|
287
401
|
</div>
|
|
288
402
|
</RangeCalendarContext.Provider>
|
|
289
403
|
</RangeCalendarStateContext.Provider>
|
|
@@ -350,6 +464,11 @@ export function RangeCalendarButton(props: RangeCalendarButtonProps): JSX.Elemen
|
|
|
350
464
|
class={props.class ?? "solidaria-RangeCalendarButton"}
|
|
351
465
|
style={props.style}
|
|
352
466
|
disabled={isDisabled()}
|
|
467
|
+
// Mirror useFocusable (same as CalendarButton): always set an explicit
|
|
468
|
+
// tabIndex on an enabled focusable nav button (0), and drop it entirely
|
|
469
|
+
// when disabled — so the prev/next buttons appear in the roving tab order
|
|
470
|
+
// exactly as the S2 oracle does.
|
|
471
|
+
tabindex={isDisabled() ? undefined : 0}
|
|
353
472
|
>
|
|
354
473
|
{props.children}
|
|
355
474
|
</button>
|
|
@@ -508,7 +627,9 @@ export function RangeCalendarCell(props: RangeCalendarCellProps): JSX.Element {
|
|
|
508
627
|
|
|
509
628
|
const renderProps = useRenderProps(
|
|
510
629
|
{
|
|
511
|
-
children
|
|
630
|
+
get children() {
|
|
631
|
+
return props.children;
|
|
632
|
+
},
|
|
512
633
|
class: props.class,
|
|
513
634
|
style: props.style,
|
|
514
635
|
defaultClassName: "solidaria-RangeCalendarCell",
|