@proyecto-viviana/solidaria-components 0.2.9 → 0.3.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/README.md +39 -272
- package/dist/ActionBar.d.ts +21 -13
- package/dist/ActionBar.d.ts.map +1 -1
- package/dist/ActionGroup.d.ts +8 -8
- package/dist/ActionGroup.d.ts.map +1 -1
- package/dist/Alert.d.ts +5 -5
- package/dist/Alert.d.ts.map +1 -1
- package/dist/Autocomplete.d.ts +5 -5
- package/dist/Autocomplete.d.ts.map +1 -1
- package/dist/Breadcrumbs.d.ts +18 -7
- package/dist/Breadcrumbs.d.ts.map +1 -1
- package/dist/Button.d.ts +24 -5
- package/dist/Button.d.ts.map +1 -1
- package/dist/Calendar.d.ts +38 -7
- package/dist/Calendar.d.ts.map +1 -1
- package/dist/Checkbox.d.ts +32 -7
- package/dist/Checkbox.d.ts.map +1 -1
- package/dist/Collection.d.ts +19 -14
- package/dist/Collection.d.ts.map +1 -1
- package/dist/Color.d.ts +103 -14
- package/dist/Color.d.ts.map +1 -1
- package/dist/ColorEditor.d.ts +6 -6
- package/dist/ColorEditor.d.ts.map +1 -1
- package/dist/ComboBox.d.ts +85 -19
- package/dist/ComboBox.d.ts.map +1 -1
- package/dist/ContextualHelpTrigger.d.ts +2 -2
- package/dist/ContextualHelpTrigger.d.ts.map +1 -1
- package/dist/DateField.d.ts +8 -6
- package/dist/DateField.d.ts.map +1 -1
- package/dist/DatePicker.d.ts +53 -22
- package/dist/DatePicker.d.ts.map +1 -1
- package/dist/DateRangePickerContext.d.ts +30 -0
- package/dist/DateRangePickerContext.d.ts.map +1 -0
- package/dist/Dialog.d.ts +5 -5
- package/dist/Dialog.d.ts.map +1 -1
- package/dist/Disclosure.d.ts +23 -5
- package/dist/Disclosure.d.ts.map +1 -1
- package/dist/DragAndDrop.d.ts +6 -6
- package/dist/DragAndDrop.d.ts.map +1 -1
- package/dist/DragPreview.d.ts +2 -2
- package/dist/DragPreview.d.ts.map +1 -1
- package/dist/DropZone.d.ts +4 -4
- package/dist/DropZone.d.ts.map +1 -1
- package/dist/FieldError.d.ts +9 -5
- package/dist/FieldError.d.ts.map +1 -1
- package/dist/FileTrigger.d.ts +3 -3
- package/dist/FileTrigger.d.ts.map +1 -1
- package/dist/Focusable.d.ts +2 -2
- package/dist/Focusable.d.ts.map +1 -1
- package/dist/Form.d.ts +18 -4
- package/dist/Form.d.ts.map +1 -1
- package/dist/GridList.d.ts +32 -12
- package/dist/GridList.d.ts.map +1 -1
- package/dist/HiddenDateInput.d.ts +26 -0
- package/dist/HiddenDateInput.d.ts.map +1 -0
- package/dist/HiddenTimeInput.d.ts +25 -0
- package/dist/HiddenTimeInput.d.ts.map +1 -0
- package/dist/Icon.d.ts +5 -5
- package/dist/Icon.d.ts.map +1 -1
- package/dist/Keyboard.d.ts +1 -1
- package/dist/Landmark.d.ts +3 -3
- package/dist/Landmark.d.ts.map +1 -1
- package/dist/Link.d.ts +10 -4
- package/dist/Link.d.ts.map +1 -1
- package/dist/ListBox.d.ts +32 -12
- package/dist/ListBox.d.ts.map +1 -1
- package/dist/ListDropTargetDelegate.d.ts +6 -6
- package/dist/ListDropTargetDelegate.d.ts.map +1 -1
- package/dist/Menu.d.ts +65 -14
- package/dist/Menu.d.ts.map +1 -1
- package/dist/Meter.d.ts +3 -3
- package/dist/Meter.d.ts.map +1 -1
- package/dist/Modal.d.ts +5 -5
- package/dist/Modal.d.ts.map +1 -1
- package/dist/NumberField.d.ts +8 -12
- package/dist/NumberField.d.ts.map +1 -1
- package/dist/Popover.d.ts +28 -5
- package/dist/Popover.d.ts.map +1 -1
- package/dist/Pressable.d.ts +2 -2
- package/dist/Pressable.d.ts.map +1 -1
- package/dist/ProgressBar.d.ts +5 -3
- package/dist/ProgressBar.d.ts.map +1 -1
- package/dist/RadioGroup.d.ts +43 -9
- package/dist/RadioGroup.d.ts.map +1 -1
- package/dist/RangeCalendar.d.ts +34 -7
- package/dist/RangeCalendar.d.ts.map +1 -1
- package/dist/RouterProvider.d.ts +2 -2
- package/dist/RouterProvider.d.ts.map +1 -1
- package/dist/SearchField.d.ts +23 -20
- package/dist/SearchField.d.ts.map +1 -1
- package/dist/Select.d.ts +41 -11
- package/dist/Select.d.ts.map +1 -1
- package/dist/SelectionIndicator.d.ts +3 -3
- package/dist/SelectionIndicator.d.ts.map +1 -1
- package/dist/Separator.d.ts +9 -3
- package/dist/Separator.d.ts.map +1 -1
- package/dist/SharedElementTransition.d.ts +6 -4
- package/dist/SharedElementTransition.d.ts.map +1 -1
- package/dist/Slider.d.ts +12 -8
- package/dist/Slider.d.ts.map +1 -1
- package/dist/StepList.d.ts +90 -0
- package/dist/StepList.d.ts.map +1 -0
- package/dist/Switch.d.ts +11 -5
- package/dist/Switch.d.ts.map +1 -1
- package/dist/Table.d.ts +187 -23
- package/dist/Table.d.ts.map +1 -1
- package/dist/Tabs.d.ts +45 -9
- package/dist/Tabs.d.ts.map +1 -1
- package/dist/TagGroup.d.ts +12 -10
- package/dist/TagGroup.d.ts.map +1 -1
- package/dist/Text.d.ts +2 -2
- package/dist/TextField.d.ts +15 -11
- package/dist/TextField.d.ts.map +1 -1
- package/dist/TimeField.d.ts +6 -6
- package/dist/TimeField.d.ts.map +1 -1
- package/dist/Toast.d.ts +29 -14
- package/dist/Toast.d.ts.map +1 -1
- package/dist/ToggleButton.d.ts +11 -5
- package/dist/ToggleButton.d.ts.map +1 -1
- package/dist/ToggleButtonGroup.d.ts +7 -7
- package/dist/ToggleButtonGroup.d.ts.map +1 -1
- package/dist/Toolbar.d.ts +7 -3
- package/dist/Toolbar.d.ts.map +1 -1
- package/dist/Tooltip.d.ts +50 -8
- package/dist/Tooltip.d.ts.map +1 -1
- package/dist/Tree.d.ts +66 -17
- package/dist/Tree.d.ts.map +1 -1
- package/dist/Virtualizer.d.ts +12 -12
- package/dist/Virtualizer.d.ts.map +1 -1
- package/dist/VirtualizerLayouts.d.ts +2 -2
- package/dist/VirtualizerLayouts.d.ts.map +1 -1
- package/dist/VisuallyHidden.d.ts +1 -1
- package/dist/VisuallyHidden.d.ts.map +1 -1
- package/dist/contexts.d.ts +5 -1
- package/dist/contexts.d.ts.map +1 -1
- package/dist/index.d.ts +73 -71
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23253 -18564
- package/dist/index.js.map +1 -1
- package/dist/index.jsx +18116 -0
- package/dist/index.jsx.map +1 -0
- package/dist/useDragAndDrop.d.ts +13 -13
- package/dist/useDragAndDrop.d.ts.map +1 -1
- package/dist/utils.d.ts +2 -2
- package/dist/utils.d.ts.map +1 -1
- package/dist/virtualizer/Layout.d.ts +1 -1
- package/dist/virtualizer/Layout.d.ts.map +1 -1
- package/package.json +31 -32
- package/src/ActionBar.tsx +75 -72
- package/src/ActionGroup.tsx +53 -61
- package/src/Alert.tsx +17 -42
- package/src/Autocomplete.tsx +39 -44
- package/src/Breadcrumbs.tsx +149 -80
- package/src/Button.tsx +267 -70
- package/src/Calendar.tsx +218 -138
- package/src/Checkbox.tsx +413 -121
- package/src/Collection.tsx +67 -58
- package/src/Color.tsx +803 -380
- package/src/ColorEditor.tsx +131 -149
- package/src/ComboBox.tsx +414 -249
- package/src/ContextualHelpTrigger.tsx +86 -74
- package/src/DateField.tsx +185 -91
- package/src/DatePicker.tsx +524 -213
- package/src/DateRangePickerContext.tsx +44 -0
- package/src/Dialog.tsx +156 -118
- package/src/Disclosure.tsx +127 -80
- package/src/DragAndDrop.tsx +60 -54
- package/src/DragPreview.tsx +13 -11
- package/src/DropZone.tsx +42 -22
- package/src/FieldError.tsx +45 -23
- package/src/FileTrigger.tsx +19 -19
- package/src/Focusable.tsx +21 -24
- package/src/Form.tsx +71 -16
- package/src/GridList.tsx +273 -197
- package/src/HiddenDateInput.tsx +153 -0
- package/src/HiddenTimeInput.tsx +133 -0
- package/src/Icon.tsx +22 -43
- package/src/Keyboard.tsx +3 -3
- package/src/Landmark.tsx +37 -63
- package/src/Link.tsx +125 -75
- package/src/ListBox.tsx +332 -233
- package/src/ListDropTargetDelegate.ts +81 -80
- package/src/Menu.tsx +1023 -274
- package/src/Meter.tsx +38 -56
- package/src/Modal.tsx +251 -176
- package/src/NumberField.tsx +139 -143
- package/src/Popover.tsx +396 -234
- package/src/Pressable.tsx +21 -21
- package/src/ProgressBar.tsx +48 -57
- package/src/RadioGroup.tsx +524 -122
- package/src/RangeCalendar.tsx +157 -90
- package/src/RouterProvider.tsx +30 -47
- package/src/SearchField.tsx +362 -143
- package/src/Select.tsx +656 -233
- package/src/SelectionIndicator.tsx +18 -15
- package/src/Separator.tsx +47 -49
- package/src/SharedElementTransition.tsx +103 -97
- package/src/Slider.tsx +138 -98
- package/src/StepList.tsx +272 -0
- package/src/Switch.tsx +93 -46
- package/src/Table.tsx +1308 -342
- package/src/Tabs.tsx +324 -103
- package/src/TagGroup.tsx +139 -126
- package/src/Text.tsx +3 -3
- package/src/TextField.tsx +389 -79
- package/src/TimeField.tsx +136 -76
- package/src/Toast.tsx +216 -158
- package/src/ToggleButton.tsx +47 -37
- package/src/ToggleButtonGroup.tsx +39 -34
- package/src/Toolbar.tsx +54 -69
- package/src/Tooltip.tsx +387 -119
- package/src/Tree.tsx +651 -368
- package/src/Virtualizer.tsx +208 -180
- package/src/VirtualizerLayouts.ts +45 -30
- package/src/VisuallyHidden.tsx +19 -19
- package/src/contexts.ts +29 -37
- package/src/index.ts +110 -195
- package/src/useDragAndDrop.ts +87 -71
- package/src/utils.tsx +49 -60
- package/src/virtualizer/Layout.ts +14 -22
- package/dist/index.ssr.js +0 -16996
- package/dist/index.ssr.js.map +0 -1
package/src/Button.tsx
CHANGED
|
@@ -8,18 +8,23 @@
|
|
|
8
8
|
import {
|
|
9
9
|
type JSX,
|
|
10
10
|
createContext,
|
|
11
|
+
createEffect,
|
|
11
12
|
createMemo,
|
|
13
|
+
createSignal,
|
|
12
14
|
splitProps,
|
|
13
15
|
useContext,
|
|
14
|
-
} from
|
|
16
|
+
} from "solid-js";
|
|
15
17
|
import {
|
|
18
|
+
announce,
|
|
16
19
|
createButton,
|
|
17
20
|
createFocusRing,
|
|
18
21
|
createHover,
|
|
22
|
+
createId,
|
|
19
23
|
mergeProps,
|
|
20
24
|
type AriaButtonProps,
|
|
25
|
+
type HoverEvent,
|
|
21
26
|
type PressEvent,
|
|
22
|
-
} from
|
|
27
|
+
} from "@proyecto-viviana/solidaria";
|
|
23
28
|
import {
|
|
24
29
|
type RenderChildren,
|
|
25
30
|
type ClassNameOrFunction,
|
|
@@ -27,12 +32,70 @@ import {
|
|
|
27
32
|
type SlotProps,
|
|
28
33
|
useRenderProps,
|
|
29
34
|
filterDOMProps,
|
|
30
|
-
} from
|
|
31
|
-
import { DialogTriggerContext, PopoverTriggerContext } from
|
|
35
|
+
} from "./utils";
|
|
36
|
+
import { DialogTriggerContext, PopoverTriggerContext } from "./contexts";
|
|
37
|
+
import { ProgressBarContext } from "./ProgressBar";
|
|
32
38
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
39
|
+
type RefLike<T> = ((el: T) => void) | { current?: T | null } | undefined;
|
|
40
|
+
|
|
41
|
+
function assignRef<T>(ref: RefLike<T>, el: T): void {
|
|
42
|
+
if (!ref) return;
|
|
43
|
+
if (typeof ref === "function") {
|
|
44
|
+
ref(el);
|
|
45
|
+
} else {
|
|
46
|
+
ref.current = el;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function createLiveButtonRenderProps(values: () => ButtonRenderProps): ButtonRenderProps {
|
|
51
|
+
return {
|
|
52
|
+
get isHovered() {
|
|
53
|
+
return values().isHovered;
|
|
54
|
+
},
|
|
55
|
+
get isPressed() {
|
|
56
|
+
return values().isPressed;
|
|
57
|
+
},
|
|
58
|
+
get isFocused() {
|
|
59
|
+
return values().isFocused;
|
|
60
|
+
},
|
|
61
|
+
get isFocusVisible() {
|
|
62
|
+
return values().isFocusVisible;
|
|
63
|
+
},
|
|
64
|
+
get isDisabled() {
|
|
65
|
+
return values().isDisabled;
|
|
66
|
+
},
|
|
67
|
+
get isPending() {
|
|
68
|
+
return values().isPending;
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function createLiveCustomRootProps(
|
|
74
|
+
getProps: () => JSX.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
75
|
+
getChildren: () => JSX.Element,
|
|
76
|
+
ref: (el: HTMLButtonElement) => void,
|
|
77
|
+
): JSX.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
78
|
+
const props = {} as JSX.ButtonHTMLAttributes<HTMLButtonElement>;
|
|
79
|
+
const keys = new Set([...Object.keys(getProps()), "children", "ref"]);
|
|
80
|
+
|
|
81
|
+
for (const key of keys) {
|
|
82
|
+
Object.defineProperty(props, key, {
|
|
83
|
+
enumerable: true,
|
|
84
|
+
configurable: true,
|
|
85
|
+
get() {
|
|
86
|
+
if (key === "children") {
|
|
87
|
+
return getChildren();
|
|
88
|
+
}
|
|
89
|
+
if (key === "ref") {
|
|
90
|
+
return ref;
|
|
91
|
+
}
|
|
92
|
+
return (getProps() as Record<string, unknown>)[key];
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return props;
|
|
98
|
+
}
|
|
36
99
|
|
|
37
100
|
export interface ButtonRenderProps {
|
|
38
101
|
/** Whether the button is currently hovered with a mouse. */
|
|
@@ -49,28 +112,37 @@ export interface ButtonRenderProps {
|
|
|
49
112
|
isPending: boolean;
|
|
50
113
|
}
|
|
51
114
|
|
|
52
|
-
export interface ButtonProps
|
|
53
|
-
extends Omit<AriaButtonProps, 'children'>,
|
|
54
|
-
SlotProps {
|
|
115
|
+
export interface ButtonProps extends Omit<AriaButtonProps, "children">, SlotProps {
|
|
55
116
|
/** The children of the component. A function may be provided to receive render props. */
|
|
56
117
|
children?: RenderChildren<ButtonRenderProps>;
|
|
57
118
|
/** The CSS className for the element. */
|
|
58
119
|
class?: ClassNameOrFunction<ButtonRenderProps>;
|
|
59
120
|
/** The inline style for the element. */
|
|
60
121
|
style?: StyleOrFunction<ButtonRenderProps>;
|
|
122
|
+
/** Custom renderer for the outer button element. */
|
|
123
|
+
render?: (
|
|
124
|
+
props: JSX.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
125
|
+
renderProps: ButtonRenderProps,
|
|
126
|
+
) => JSX.Element;
|
|
127
|
+
/** Ref for the underlying button element. */
|
|
128
|
+
ref?: RefLike<HTMLButtonElement>;
|
|
61
129
|
/** Whether the button is in a pending state. */
|
|
62
130
|
isPending?: boolean;
|
|
131
|
+
/** Keeps pending buttons focusable by using aria-disabled without a native disabled attribute. */
|
|
132
|
+
isPendingFocusable?: boolean;
|
|
133
|
+
/** Handler called when hover starts. */
|
|
134
|
+
onHoverStart?: (e: HoverEvent) => void;
|
|
135
|
+
/** Handler called when hover ends. */
|
|
136
|
+
onHoverEnd?: (e: HoverEvent) => void;
|
|
137
|
+
/** Handler called when hover state changes. */
|
|
138
|
+
onHoverChange?: (isHovered: boolean) => void;
|
|
63
139
|
}
|
|
64
140
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
export const ButtonContext = createContext<ButtonProps | null>(null);
|
|
141
|
+
export interface ButtonContextValue extends ButtonProps {
|
|
142
|
+
slots?: Record<string, ButtonProps>;
|
|
143
|
+
}
|
|
70
144
|
|
|
71
|
-
|
|
72
|
-
// COMPONENT
|
|
73
|
-
// ============================================
|
|
145
|
+
export const ButtonContext = createContext<ButtonContextValue | null>(null);
|
|
74
146
|
|
|
75
147
|
/**
|
|
76
148
|
* A button allows a user to perform an action.
|
|
@@ -91,15 +163,28 @@ export const ButtonContext = createContext<ButtonProps | null>(null);
|
|
|
91
163
|
*/
|
|
92
164
|
export function Button(props: ButtonProps): JSX.Element {
|
|
93
165
|
const contextProps = useContext(ButtonContext);
|
|
94
|
-
const
|
|
166
|
+
const contextSlotProps = contextProps?.slots?.[props.slot ?? "default"];
|
|
167
|
+
const contextBaseProps = createMemo<ButtonProps>(() => {
|
|
168
|
+
if (!contextProps) return {};
|
|
169
|
+
const { slots: _slots, ...rest } = contextProps;
|
|
170
|
+
return rest;
|
|
171
|
+
});
|
|
172
|
+
const mergedProps = (
|
|
173
|
+
contextProps ? mergeProps(contextBaseProps(), contextSlotProps ?? {}, props) : props
|
|
174
|
+
) as ButtonProps;
|
|
95
175
|
|
|
96
|
-
// Split props
|
|
97
176
|
const [local, ariaProps] = splitProps(mergedProps, [
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
177
|
+
"children",
|
|
178
|
+
"class",
|
|
179
|
+
"style",
|
|
180
|
+
"render",
|
|
181
|
+
"ref",
|
|
182
|
+
"slot",
|
|
183
|
+
"isPending",
|
|
184
|
+
"isPendingFocusable",
|
|
185
|
+
"onHoverStart",
|
|
186
|
+
"onHoverEnd",
|
|
187
|
+
"onHoverChange",
|
|
103
188
|
]);
|
|
104
189
|
|
|
105
190
|
// Check if inside a DialogTrigger or PopoverTrigger - if so, toggle on press
|
|
@@ -113,30 +198,35 @@ export function Button(props: ButtonProps): JSX.Element {
|
|
|
113
198
|
// Helper to resolve isDisabled (handles both boolean and Accessor<boolean>)
|
|
114
199
|
const resolveDisabled = (): boolean => {
|
|
115
200
|
const disabled = ariaProps.isDisabled;
|
|
116
|
-
if (typeof disabled ===
|
|
201
|
+
if (typeof disabled === "function") {
|
|
117
202
|
return disabled();
|
|
118
203
|
}
|
|
119
204
|
return !!disabled;
|
|
120
205
|
};
|
|
121
206
|
|
|
122
207
|
const resolvePending = (): boolean => !!local.isPending;
|
|
208
|
+
const isPendingFocusable = () => local.isPendingFocusable !== false;
|
|
123
209
|
|
|
124
|
-
|
|
210
|
+
const [resolvedButtonEl, setResolvedButtonEl] = createSignal<HTMLButtonElement | null>(null);
|
|
211
|
+
const buttonId = createId((ariaProps as Record<string, unknown>).id as string | undefined);
|
|
212
|
+
const progressId = createId();
|
|
125
213
|
|
|
126
214
|
// Explicit trigger ownership: a button toggles overlays only when it is the
|
|
127
215
|
// registered trigger element for the surrounding trigger context.
|
|
128
216
|
const isDialogTrigger = () =>
|
|
129
|
-
!!dialogTriggerContext &&
|
|
217
|
+
!!dialogTriggerContext &&
|
|
218
|
+
!!resolvedButtonEl() &&
|
|
219
|
+
dialogTriggerContext.triggerRef() === resolvedButtonEl();
|
|
130
220
|
const isPopoverTrigger = () =>
|
|
131
|
-
!!popoverTriggerContext &&
|
|
221
|
+
!!popoverTriggerContext &&
|
|
222
|
+
!!resolvedButtonEl() &&
|
|
223
|
+
popoverTriggerContext.triggerRef() === resolvedButtonEl();
|
|
132
224
|
|
|
133
|
-
// Wrap onPress to also toggle dialog/popover if this is a trigger button
|
|
134
225
|
const handlePress = (e: PressEvent) => {
|
|
135
226
|
if (resolvePending()) {
|
|
136
227
|
return;
|
|
137
228
|
}
|
|
138
|
-
|
|
139
|
-
if (typeof ariaProps.onPress === 'function') {
|
|
229
|
+
if (typeof ariaProps.onPress === "function") {
|
|
140
230
|
ariaProps.onPress(e);
|
|
141
231
|
}
|
|
142
232
|
// Toggle only when this exact button is the registered trigger element.
|
|
@@ -148,7 +238,6 @@ export function Button(props: ButtonProps): JSX.Element {
|
|
|
148
238
|
}
|
|
149
239
|
};
|
|
150
240
|
|
|
151
|
-
// Create button aria props
|
|
152
241
|
const buttonAria = createButton({
|
|
153
242
|
...ariaProps,
|
|
154
243
|
onPress: handlePress,
|
|
@@ -172,17 +261,17 @@ export function Button(props: ButtonProps): JSX.Element {
|
|
|
172
261
|
},
|
|
173
262
|
});
|
|
174
263
|
|
|
175
|
-
// Create focus ring
|
|
176
264
|
const { isFocused, isFocusVisible, focusProps } = createFocusRing();
|
|
177
265
|
|
|
178
|
-
// Create hover
|
|
179
266
|
const { isHovered, hoverProps } = createHover({
|
|
180
267
|
get isDisabled() {
|
|
181
268
|
return resolveDisabled() || resolvePending();
|
|
182
269
|
},
|
|
270
|
+
onHoverStart: local.onHoverStart,
|
|
271
|
+
onHoverEnd: local.onHoverEnd,
|
|
272
|
+
onHoverChange: local.onHoverChange,
|
|
183
273
|
});
|
|
184
274
|
|
|
185
|
-
// Render props values
|
|
186
275
|
const renderValues = createMemo<ButtonRenderProps>(() => ({
|
|
187
276
|
isHovered: isHovered(),
|
|
188
277
|
isPressed: buttonAria.isPressed() && !resolvePending(),
|
|
@@ -192,19 +281,19 @@ export function Button(props: ButtonProps): JSX.Element {
|
|
|
192
281
|
isPending: resolvePending(),
|
|
193
282
|
}));
|
|
194
283
|
|
|
195
|
-
// Resolve render props
|
|
196
284
|
const renderProps = useRenderProps(
|
|
197
285
|
{
|
|
198
286
|
// Use merged children so ButtonContext can supply slot/default content.
|
|
199
|
-
children
|
|
287
|
+
get children() {
|
|
288
|
+
return local.children;
|
|
289
|
+
},
|
|
200
290
|
class: local.class,
|
|
201
291
|
style: local.style,
|
|
202
|
-
defaultClassName:
|
|
292
|
+
defaultClassName: "solidaria-Button",
|
|
203
293
|
},
|
|
204
|
-
renderValues
|
|
294
|
+
renderValues,
|
|
205
295
|
);
|
|
206
296
|
|
|
207
|
-
// Filter DOM props
|
|
208
297
|
// Remove onClick from DOM props - it's already handled by createPress
|
|
209
298
|
// This matches React Aria Components behavior (Button.tsx line 144: delete DOMProps.onClick)
|
|
210
299
|
const domProps = createMemo(() => {
|
|
@@ -214,12 +303,16 @@ export function Button(props: ButtonProps): JSX.Element {
|
|
|
214
303
|
return filtered;
|
|
215
304
|
});
|
|
216
305
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
const
|
|
306
|
+
const buttonPropsRef = (buttonAria.buttonProps as Record<string, unknown>).ref as
|
|
307
|
+
| ((el: HTMLElement) => void)
|
|
308
|
+
| undefined;
|
|
309
|
+
const focusPropsRef = (focusProps as Record<string, unknown>).ref as
|
|
310
|
+
| ((el: HTMLElement) => void)
|
|
311
|
+
| undefined;
|
|
312
|
+
const hoverPropsRef = (hoverProps as Record<string, unknown>).ref as
|
|
313
|
+
| ((el: HTMLElement) => void)
|
|
314
|
+
| undefined;
|
|
221
315
|
|
|
222
|
-
// Remove ref from spread props to avoid type conflicts
|
|
223
316
|
const cleanButtonProps = () => {
|
|
224
317
|
const { ref: _ref1, ...rest } = buttonAria.buttonProps as Record<string, unknown>;
|
|
225
318
|
return rest;
|
|
@@ -232,51 +325,155 @@ export function Button(props: ButtonProps): JSX.Element {
|
|
|
232
325
|
const { ref: _ref3, ...rest } = hoverProps as Record<string, unknown>;
|
|
233
326
|
return rest;
|
|
234
327
|
};
|
|
328
|
+
const ariaLabelledBy = createMemo(() => {
|
|
329
|
+
const labelledBy = cleanButtonProps()["aria-labelledby"] as string | undefined;
|
|
330
|
+
if (!resolvePending()) {
|
|
331
|
+
return labelledBy;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (labelledBy) {
|
|
335
|
+
return `${labelledBy} ${progressId}`;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (cleanButtonProps()["aria-label"]) {
|
|
339
|
+
return `${buttonId} ${progressId}`;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return labelledBy;
|
|
343
|
+
});
|
|
235
344
|
|
|
236
|
-
// Ref callback that combines all refs
|
|
237
345
|
const handleRef = (el: HTMLButtonElement) => {
|
|
238
|
-
|
|
346
|
+
setResolvedButtonEl(el);
|
|
347
|
+
assignRef(local.ref, el);
|
|
239
348
|
|
|
240
|
-
// Call the focusable ref for autoFocus support
|
|
241
349
|
buttonPropsRef?.(el);
|
|
242
350
|
focusPropsRef?.(el);
|
|
243
351
|
hoverPropsRef?.(el);
|
|
244
352
|
|
|
245
353
|
// Register trigger ownership for surrounding trigger contexts.
|
|
246
354
|
if (dialogTriggerContext?.setTriggerRef) {
|
|
355
|
+
if (!el.id) {
|
|
356
|
+
el.id = dialogTriggerContext.triggerId;
|
|
357
|
+
}
|
|
247
358
|
dialogTriggerContext.setTriggerRef(el);
|
|
248
359
|
}
|
|
249
360
|
if (popoverTriggerContext?.setTriggerRef) {
|
|
250
361
|
popoverTriggerContext.setTriggerRef(el);
|
|
251
362
|
}
|
|
252
363
|
};
|
|
364
|
+
const buttonType = () =>
|
|
365
|
+
(buttonAria.buttonProps as Record<string, unknown>).type === "submit" && resolvePending()
|
|
366
|
+
? "button"
|
|
367
|
+
: ((buttonAria.buttonProps as Record<string, unknown>).type as
|
|
368
|
+
| "button"
|
|
369
|
+
| "submit"
|
|
370
|
+
| "reset"
|
|
371
|
+
| undefined);
|
|
372
|
+
const triggerAriaProps = () => {
|
|
373
|
+
const dialogTriggerProps = dialogTriggerContext?.triggerProps;
|
|
374
|
+
if (dialogTriggerProps && isDialogTrigger()) {
|
|
375
|
+
const next: Record<string, unknown> = {};
|
|
376
|
+
for (const name of ["aria-haspopup", "aria-expanded", "aria-controls"]) {
|
|
377
|
+
if (dialogTriggerProps[name] != null) {
|
|
378
|
+
next[name] = dialogTriggerProps[name];
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return next;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
const triggerProps = popoverTriggerContext?.triggerProps;
|
|
385
|
+
if (!triggerProps || !isPopoverTrigger()) {
|
|
386
|
+
return {};
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const next: Record<string, unknown> = {};
|
|
390
|
+
for (const name of ["aria-haspopup", "aria-expanded", "aria-controls"]) {
|
|
391
|
+
if (triggerProps[name] != null) {
|
|
392
|
+
next[name] = triggerProps[name];
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return next;
|
|
396
|
+
};
|
|
397
|
+
const disablePendingInteractions = (props: Record<string, unknown>) => {
|
|
398
|
+
if (!resolvePending()) {
|
|
399
|
+
return props;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const next = { ...props };
|
|
403
|
+
for (const key of Object.keys(next)) {
|
|
404
|
+
if (key.startsWith("on") && !key.includes("Focus") && !key.includes("Blur")) {
|
|
405
|
+
next[key] = undefined;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
next.href = undefined;
|
|
409
|
+
next.target = undefined;
|
|
410
|
+
return next;
|
|
411
|
+
};
|
|
412
|
+
const dataState = (value: boolean) => (value ? "true" : undefined);
|
|
413
|
+
const buttonChildren = () => renderProps.renderChildren();
|
|
414
|
+
const buttonContent = () => (
|
|
415
|
+
<ProgressBarContext.Provider value={{ id: progressId }}>
|
|
416
|
+
{buttonChildren()}
|
|
417
|
+
</ProgressBarContext.Provider>
|
|
418
|
+
);
|
|
419
|
+
let wasPending = resolvePending();
|
|
420
|
+
createEffect(() => {
|
|
421
|
+
const pending = resolvePending();
|
|
422
|
+
const message = { "aria-labelledby": ariaLabelledBy() || buttonId };
|
|
253
423
|
|
|
254
|
-
|
|
424
|
+
if (!wasPending && isFocused() && pending) {
|
|
425
|
+
announce(message, "assertive");
|
|
426
|
+
} else if (wasPending && isFocused() && !pending) {
|
|
427
|
+
announce(message, "assertive");
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
wasPending = pending;
|
|
431
|
+
});
|
|
432
|
+
const rootProps = () =>
|
|
433
|
+
({
|
|
434
|
+
...domProps(),
|
|
435
|
+
...disablePendingInteractions(cleanButtonProps()),
|
|
436
|
+
...triggerAriaProps(),
|
|
437
|
+
...cleanFocusProps(),
|
|
438
|
+
...cleanHoverProps(),
|
|
439
|
+
type: buttonType(),
|
|
440
|
+
id: buttonId,
|
|
441
|
+
class: renderProps.class(),
|
|
442
|
+
style: renderProps.style(),
|
|
443
|
+
slot: local.slot,
|
|
444
|
+
disabled: resolvePending() && isPendingFocusable() ? undefined : cleanButtonProps().disabled,
|
|
445
|
+
"aria-labelledby": ariaLabelledBy(),
|
|
446
|
+
"aria-disabled": resolvePending()
|
|
447
|
+
? "true"
|
|
448
|
+
: (cleanButtonProps()["aria-disabled"] ?? ariaProps["aria-disabled"]),
|
|
449
|
+
"data-pressed": dataState(buttonAria.isPressed() && !resolvePending()),
|
|
450
|
+
"data-hovered": dataState(isHovered()),
|
|
451
|
+
"data-focused": dataState(isFocused()),
|
|
452
|
+
"data-focus-visible": dataState(isFocusVisible()),
|
|
453
|
+
"data-disabled": dataState(resolveDisabled()),
|
|
454
|
+
"data-pending": dataState(resolvePending()),
|
|
455
|
+
}) as JSX.ButtonHTMLAttributes<HTMLButtonElement>;
|
|
456
|
+
const customRootProps = createLiveCustomRootProps(rootProps, buttonContent, handleRef);
|
|
457
|
+
const customRenderValues = createLiveButtonRenderProps(renderValues);
|
|
458
|
+
|
|
459
|
+
return local.render ? (
|
|
460
|
+
local.render(customRootProps, customRenderValues)
|
|
461
|
+
) : (
|
|
255
462
|
<button
|
|
256
463
|
ref={handleRef}
|
|
257
|
-
{...
|
|
258
|
-
{...cleanButtonProps()}
|
|
259
|
-
{...cleanFocusProps()}
|
|
260
|
-
{...cleanHoverProps()}
|
|
261
|
-
type={
|
|
262
|
-
(buttonAria.buttonProps as Record<string, unknown>).type === 'submit' && resolvePending()
|
|
263
|
-
? 'button'
|
|
264
|
-
: (buttonAria.buttonProps as Record<string, unknown>).type as
|
|
265
|
-
| 'button'
|
|
266
|
-
| 'submit'
|
|
267
|
-
| 'reset'
|
|
268
|
-
| undefined
|
|
269
|
-
}
|
|
464
|
+
{...rootProps()}
|
|
270
465
|
class={renderProps.class()}
|
|
271
466
|
style={renderProps.style()}
|
|
272
|
-
data-pressed={(
|
|
273
|
-
data-hovered={
|
|
274
|
-
data-focused={
|
|
275
|
-
data-focus-visible={
|
|
276
|
-
|
|
277
|
-
|
|
467
|
+
attr:data-pressed={(rootProps() as Record<string, unknown>)["data-pressed"] as string}
|
|
468
|
+
attr:data-hovered={(rootProps() as Record<string, unknown>)["data-hovered"] as string}
|
|
469
|
+
attr:data-focused={(rootProps() as Record<string, unknown>)["data-focused"] as string}
|
|
470
|
+
attr:data-focus-visible={
|
|
471
|
+
(rootProps() as Record<string, unknown>)["data-focus-visible"] as string
|
|
472
|
+
}
|
|
473
|
+
attr:data-disabled={(rootProps() as Record<string, unknown>)["data-disabled"] as string}
|
|
474
|
+
attr:data-pending={(rootProps() as Record<string, unknown>)["data-pending"] as string}
|
|
278
475
|
>
|
|
279
|
-
{
|
|
476
|
+
{buttonContent()}
|
|
280
477
|
</button>
|
|
281
478
|
);
|
|
282
479
|
}
|