@proyecto-viviana/solidaria-components 0.0.1 → 0.0.2
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/package.json +4 -3
- package/src/Button.tsx +177 -0
- package/src/Checkbox.tsx +378 -0
- package/src/Link.tsx +201 -0
- package/src/ProgressBar.tsx +162 -0
- package/src/RadioGroup.tsx +354 -0
- package/src/Separator.tsx +130 -0
- package/src/Switch.tsx +214 -0
- package/src/TextField.tsx +271 -0
- package/src/VisuallyHidden.tsx +60 -0
- package/src/index.ts +111 -0
- package/src/utils.tsx +202 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@proyecto-viviana/solidaria-components",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "Pre-wired headless components for SolidJS - port of react-aria-components",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -8,13 +8,14 @@
|
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
-
"solid": "./
|
|
11
|
+
"solid": "./src/index.ts",
|
|
12
12
|
"import": "./dist/index.js",
|
|
13
13
|
"types": "./dist/index.d.ts"
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
|
-
"dist"
|
|
17
|
+
"dist",
|
|
18
|
+
"src"
|
|
18
19
|
],
|
|
19
20
|
"sideEffects": false,
|
|
20
21
|
"scripts": {
|
package/src/Button.tsx
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Button component for solidaria-components
|
|
3
|
+
*
|
|
4
|
+
* A pre-wired headless button that combines state + aria hooks.
|
|
5
|
+
* Port of react-aria-components/src/Button.tsx
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
type JSX,
|
|
10
|
+
createContext,
|
|
11
|
+
createMemo,
|
|
12
|
+
splitProps,
|
|
13
|
+
} from 'solid-js';
|
|
14
|
+
import {
|
|
15
|
+
createButton,
|
|
16
|
+
createFocusRing,
|
|
17
|
+
createHover,
|
|
18
|
+
type AriaButtonProps,
|
|
19
|
+
} from '@proyecto-viviana/solidaria';
|
|
20
|
+
import {
|
|
21
|
+
type RenderChildren,
|
|
22
|
+
type ClassNameOrFunction,
|
|
23
|
+
type StyleOrFunction,
|
|
24
|
+
type SlotProps,
|
|
25
|
+
useRenderProps,
|
|
26
|
+
filterDOMProps,
|
|
27
|
+
} from './utils';
|
|
28
|
+
|
|
29
|
+
// ============================================
|
|
30
|
+
// TYPES
|
|
31
|
+
// ============================================
|
|
32
|
+
|
|
33
|
+
export interface ButtonRenderProps {
|
|
34
|
+
/** Whether the button is currently hovered with a mouse. */
|
|
35
|
+
isHovered: boolean;
|
|
36
|
+
/** Whether the button is currently in a pressed state. */
|
|
37
|
+
isPressed: boolean;
|
|
38
|
+
/** Whether the button is focused, either via a mouse or keyboard. */
|
|
39
|
+
isFocused: boolean;
|
|
40
|
+
/** Whether the button is keyboard focused. */
|
|
41
|
+
isFocusVisible: boolean;
|
|
42
|
+
/** Whether the button is disabled. */
|
|
43
|
+
isDisabled: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface ButtonProps
|
|
47
|
+
extends Omit<AriaButtonProps, 'children'>,
|
|
48
|
+
SlotProps {
|
|
49
|
+
/** The children of the component. A function may be provided to receive render props. */
|
|
50
|
+
children?: RenderChildren<ButtonRenderProps>;
|
|
51
|
+
/** The CSS className for the element. */
|
|
52
|
+
class?: ClassNameOrFunction<ButtonRenderProps>;
|
|
53
|
+
/** The inline style for the element. */
|
|
54
|
+
style?: StyleOrFunction<ButtonRenderProps>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ============================================
|
|
58
|
+
// CONTEXT
|
|
59
|
+
// ============================================
|
|
60
|
+
|
|
61
|
+
export const ButtonContext = createContext<ButtonProps | null>(null);
|
|
62
|
+
|
|
63
|
+
// ============================================
|
|
64
|
+
// COMPONENT
|
|
65
|
+
// ============================================
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* A button allows a user to perform an action.
|
|
69
|
+
*
|
|
70
|
+
* This is a headless component that provides accessibility and state management.
|
|
71
|
+
* Style it using the render props pattern or data attributes.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```tsx
|
|
75
|
+
* <Button onPress={() => alert('Pressed!')}>
|
|
76
|
+
* {({ isPressed, isHovered }) => (
|
|
77
|
+
* <span class={isPressed ? 'bg-blue-700' : isHovered ? 'bg-blue-600' : 'bg-blue-500'}>
|
|
78
|
+
* Click me
|
|
79
|
+
* </span>
|
|
80
|
+
* )}
|
|
81
|
+
* </Button>
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export function Button(props: ButtonProps): JSX.Element {
|
|
85
|
+
// Split props
|
|
86
|
+
const [local, ariaProps] = splitProps(props, [
|
|
87
|
+
'children',
|
|
88
|
+
'class',
|
|
89
|
+
'style',
|
|
90
|
+
'slot',
|
|
91
|
+
]);
|
|
92
|
+
|
|
93
|
+
// Helper to resolve isDisabled (handles both boolean and Accessor<boolean>)
|
|
94
|
+
const resolveDisabled = (): boolean => {
|
|
95
|
+
const disabled = ariaProps.isDisabled;
|
|
96
|
+
if (typeof disabled === 'function') {
|
|
97
|
+
return disabled();
|
|
98
|
+
}
|
|
99
|
+
return !!disabled;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// Create button aria props
|
|
103
|
+
const buttonAria = createButton({
|
|
104
|
+
...ariaProps,
|
|
105
|
+
get isDisabled() {
|
|
106
|
+
return resolveDisabled();
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Create focus ring
|
|
111
|
+
const { isFocused, isFocusVisible, focusProps } = createFocusRing();
|
|
112
|
+
|
|
113
|
+
// Create hover
|
|
114
|
+
const { isHovered, hoverProps } = createHover({
|
|
115
|
+
get isDisabled() {
|
|
116
|
+
return resolveDisabled();
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Render props values
|
|
121
|
+
const renderValues = createMemo<ButtonRenderProps>(() => ({
|
|
122
|
+
isHovered: isHovered(),
|
|
123
|
+
isPressed: buttonAria.isPressed(),
|
|
124
|
+
isFocused: isFocused(),
|
|
125
|
+
isFocusVisible: isFocusVisible(),
|
|
126
|
+
isDisabled: resolveDisabled(),
|
|
127
|
+
}));
|
|
128
|
+
|
|
129
|
+
// Resolve render props
|
|
130
|
+
const renderProps = useRenderProps(
|
|
131
|
+
{
|
|
132
|
+
children: local.children,
|
|
133
|
+
class: local.class,
|
|
134
|
+
style: local.style,
|
|
135
|
+
defaultClassName: 'solidaria-Button',
|
|
136
|
+
},
|
|
137
|
+
renderValues
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
// Filter DOM props
|
|
141
|
+
const domProps = createMemo(() => {
|
|
142
|
+
const filtered = filterDOMProps(ariaProps, { global: true });
|
|
143
|
+
return filtered;
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Remove ref from spread props to avoid type conflicts
|
|
147
|
+
const cleanButtonProps = () => {
|
|
148
|
+
const { ref: _ref1, ...rest } = buttonAria.buttonProps as Record<string, unknown>;
|
|
149
|
+
return rest;
|
|
150
|
+
};
|
|
151
|
+
const cleanFocusProps = () => {
|
|
152
|
+
const { ref: _ref2, ...rest } = focusProps as Record<string, unknown>;
|
|
153
|
+
return rest;
|
|
154
|
+
};
|
|
155
|
+
const cleanHoverProps = () => {
|
|
156
|
+
const { ref: _ref3, ...rest } = hoverProps as Record<string, unknown>;
|
|
157
|
+
return rest;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<button
|
|
162
|
+
{...domProps()}
|
|
163
|
+
{...cleanButtonProps()}
|
|
164
|
+
{...cleanFocusProps()}
|
|
165
|
+
{...cleanHoverProps()}
|
|
166
|
+
class={renderProps().class}
|
|
167
|
+
style={renderProps().style}
|
|
168
|
+
data-pressed={buttonAria.isPressed() || undefined}
|
|
169
|
+
data-hovered={isHovered() || undefined}
|
|
170
|
+
data-focused={isFocused() || undefined}
|
|
171
|
+
data-focus-visible={isFocusVisible() || undefined}
|
|
172
|
+
data-disabled={resolveDisabled() || undefined}
|
|
173
|
+
>
|
|
174
|
+
{renderProps().children}
|
|
175
|
+
</button>
|
|
176
|
+
);
|
|
177
|
+
}
|
package/src/Checkbox.tsx
ADDED
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkbox and CheckboxGroup components for solidaria-components
|
|
3
|
+
*
|
|
4
|
+
* Pre-wired headless checkbox components that combine state + aria hooks.
|
|
5
|
+
* Port of react-aria-components/src/Checkbox.tsx
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
type JSX,
|
|
10
|
+
type Accessor,
|
|
11
|
+
type ParentProps,
|
|
12
|
+
createContext,
|
|
13
|
+
useContext,
|
|
14
|
+
createMemo,
|
|
15
|
+
splitProps,
|
|
16
|
+
} from 'solid-js';
|
|
17
|
+
import {
|
|
18
|
+
createCheckbox,
|
|
19
|
+
createCheckboxGroup,
|
|
20
|
+
createCheckboxGroupItem,
|
|
21
|
+
createFocusRing,
|
|
22
|
+
createHover,
|
|
23
|
+
type AriaCheckboxProps,
|
|
24
|
+
type AriaCheckboxGroupProps,
|
|
25
|
+
} from '@proyecto-viviana/solidaria';
|
|
26
|
+
import {
|
|
27
|
+
createToggleState,
|
|
28
|
+
createCheckboxGroupState,
|
|
29
|
+
type CheckboxGroupState,
|
|
30
|
+
} from '@proyecto-viviana/solid-stately';
|
|
31
|
+
import { VisuallyHidden } from './VisuallyHidden';
|
|
32
|
+
import {
|
|
33
|
+
type RenderChildren,
|
|
34
|
+
type ClassNameOrFunction,
|
|
35
|
+
type StyleOrFunction,
|
|
36
|
+
type SlotProps,
|
|
37
|
+
useRenderProps,
|
|
38
|
+
filterDOMProps,
|
|
39
|
+
} from './utils';
|
|
40
|
+
|
|
41
|
+
// ============================================
|
|
42
|
+
// TYPES
|
|
43
|
+
// ============================================
|
|
44
|
+
|
|
45
|
+
export interface CheckboxGroupRenderProps {
|
|
46
|
+
/** Whether the checkbox group is disabled. */
|
|
47
|
+
isDisabled: boolean;
|
|
48
|
+
/** Whether the checkbox group is read only. */
|
|
49
|
+
isReadOnly: boolean;
|
|
50
|
+
/** Whether the checkbox group is required. */
|
|
51
|
+
isRequired: boolean;
|
|
52
|
+
/** Whether the checkbox group is invalid. */
|
|
53
|
+
isInvalid: boolean;
|
|
54
|
+
/** State of the checkbox group. */
|
|
55
|
+
state: CheckboxGroupState;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface CheckboxRenderProps {
|
|
59
|
+
/** Whether the checkbox is selected. */
|
|
60
|
+
isSelected: boolean;
|
|
61
|
+
/** Whether the checkbox is indeterminate. */
|
|
62
|
+
isIndeterminate: boolean;
|
|
63
|
+
/** Whether the checkbox is currently hovered with a mouse. */
|
|
64
|
+
isHovered: boolean;
|
|
65
|
+
/** Whether the checkbox is currently in a pressed state. */
|
|
66
|
+
isPressed: boolean;
|
|
67
|
+
/** Whether the checkbox is focused, either via a mouse or keyboard. */
|
|
68
|
+
isFocused: boolean;
|
|
69
|
+
/** Whether the checkbox is keyboard focused. */
|
|
70
|
+
isFocusVisible: boolean;
|
|
71
|
+
/** Whether the checkbox is disabled. */
|
|
72
|
+
isDisabled: boolean;
|
|
73
|
+
/** Whether the checkbox is read only. */
|
|
74
|
+
isReadOnly: boolean;
|
|
75
|
+
/** Whether the checkbox is invalid. */
|
|
76
|
+
isInvalid: boolean;
|
|
77
|
+
/** Whether the checkbox is required. */
|
|
78
|
+
isRequired: boolean;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface CheckboxGroupProps
|
|
82
|
+
extends Omit<AriaCheckboxGroupProps, 'children' | 'label' | 'description' | 'errorMessage'>,
|
|
83
|
+
SlotProps {
|
|
84
|
+
/** The children of the component. A function may be provided to receive render props. */
|
|
85
|
+
children?: RenderChildren<CheckboxGroupRenderProps>;
|
|
86
|
+
/** The CSS className for the element. */
|
|
87
|
+
class?: ClassNameOrFunction<CheckboxGroupRenderProps>;
|
|
88
|
+
/** The inline style for the element. */
|
|
89
|
+
style?: StyleOrFunction<CheckboxGroupRenderProps>;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface CheckboxProps
|
|
93
|
+
extends Omit<AriaCheckboxProps, 'children'>,
|
|
94
|
+
SlotProps {
|
|
95
|
+
/** The children of the component. A function may be provided to receive render props. */
|
|
96
|
+
children?: RenderChildren<CheckboxRenderProps>;
|
|
97
|
+
/** The CSS className for the element. */
|
|
98
|
+
class?: ClassNameOrFunction<CheckboxRenderProps>;
|
|
99
|
+
/** The inline style for the element. */
|
|
100
|
+
style?: StyleOrFunction<CheckboxRenderProps>;
|
|
101
|
+
/** Whether the checkbox is indeterminate. */
|
|
102
|
+
isIndeterminate?: boolean;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ============================================
|
|
106
|
+
// CONTEXT
|
|
107
|
+
// ============================================
|
|
108
|
+
|
|
109
|
+
export const CheckboxGroupContext = createContext<CheckboxGroupProps | null>(null);
|
|
110
|
+
export const CheckboxGroupStateContext = createContext<CheckboxGroupState | null>(null);
|
|
111
|
+
export const CheckboxContext = createContext<CheckboxProps | null>(null);
|
|
112
|
+
|
|
113
|
+
// ============================================
|
|
114
|
+
// CHECKBOX GROUP COMPONENT
|
|
115
|
+
// ============================================
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* A checkbox group allows a user to select multiple items from a list of options.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```tsx
|
|
122
|
+
* <CheckboxGroup>
|
|
123
|
+
* <Checkbox value="one">Option 1</Checkbox>
|
|
124
|
+
* <Checkbox value="two">Option 2</Checkbox>
|
|
125
|
+
* </CheckboxGroup>
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
export function CheckboxGroup(props: ParentProps<CheckboxGroupProps>): JSX.Element {
|
|
129
|
+
const [local, ariaProps] = splitProps(props, [
|
|
130
|
+
'children',
|
|
131
|
+
'class',
|
|
132
|
+
'style',
|
|
133
|
+
'slot',
|
|
134
|
+
]);
|
|
135
|
+
|
|
136
|
+
// Create checkbox group state
|
|
137
|
+
// Use getters to ensure props are read lazily inside reactive contexts
|
|
138
|
+
const state = createCheckboxGroupState({
|
|
139
|
+
get value() { return ariaProps.value; },
|
|
140
|
+
get defaultValue() { return ariaProps.defaultValue; },
|
|
141
|
+
get onChange() { return ariaProps.onChange; },
|
|
142
|
+
get isDisabled() { return ariaProps.isDisabled; },
|
|
143
|
+
get isReadOnly() { return ariaProps.isReadOnly; },
|
|
144
|
+
get isRequired() { return ariaProps.isRequired; },
|
|
145
|
+
get isInvalid() { return ariaProps.isInvalid; },
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Create checkbox group aria props
|
|
149
|
+
const groupAria = createCheckboxGroup(() => ariaProps, state);
|
|
150
|
+
|
|
151
|
+
// Render props values
|
|
152
|
+
const renderValues = createMemo<CheckboxGroupRenderProps>(() => ({
|
|
153
|
+
isDisabled: state.isDisabled,
|
|
154
|
+
isReadOnly: state.isReadOnly,
|
|
155
|
+
isRequired: ariaProps.isRequired ?? false,
|
|
156
|
+
isInvalid: groupAria.isInvalid,
|
|
157
|
+
state,
|
|
158
|
+
}));
|
|
159
|
+
|
|
160
|
+
// Resolve render props
|
|
161
|
+
const renderProps = useRenderProps(
|
|
162
|
+
{
|
|
163
|
+
children: local.children,
|
|
164
|
+
class: local.class,
|
|
165
|
+
style: local.style,
|
|
166
|
+
defaultClassName: 'solidaria-CheckboxGroup',
|
|
167
|
+
},
|
|
168
|
+
renderValues
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
// Filter DOM props
|
|
172
|
+
const domProps = createMemo(() => filterDOMProps(ariaProps, { global: true }));
|
|
173
|
+
|
|
174
|
+
// Remove ref from spread props to avoid type conflicts
|
|
175
|
+
const cleanGroupProps = () => {
|
|
176
|
+
const { ref: _ref, ...rest } = groupAria.groupProps as Record<string, unknown>;
|
|
177
|
+
return rest;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
return (
|
|
181
|
+
<CheckboxGroupStateContext.Provider value={state}>
|
|
182
|
+
<div
|
|
183
|
+
{...domProps()}
|
|
184
|
+
{...cleanGroupProps()}
|
|
185
|
+
class={renderProps().class}
|
|
186
|
+
style={renderProps().style}
|
|
187
|
+
data-disabled={state.isDisabled || undefined}
|
|
188
|
+
data-readonly={state.isReadOnly || undefined}
|
|
189
|
+
data-required={ariaProps.isRequired || undefined}
|
|
190
|
+
data-invalid={groupAria.isInvalid || undefined}
|
|
191
|
+
>
|
|
192
|
+
{renderProps().children}
|
|
193
|
+
</div>
|
|
194
|
+
</CheckboxGroupStateContext.Provider>
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// ============================================
|
|
199
|
+
// CHECKBOX COMPONENT
|
|
200
|
+
// ============================================
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* A checkbox allows a user to select multiple items from a list of individual items,
|
|
204
|
+
* or to mark one individual item as selected.
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```tsx
|
|
208
|
+
* <Checkbox>
|
|
209
|
+
* {({ isSelected }) => (
|
|
210
|
+
* <>
|
|
211
|
+
* <span class={`checkbox ${isSelected ? 'checked' : ''}`}>
|
|
212
|
+
* {isSelected && '✓'}
|
|
213
|
+
* </span>
|
|
214
|
+
* <span>Accept terms</span>
|
|
215
|
+
* </>
|
|
216
|
+
* )}
|
|
217
|
+
* </Checkbox>
|
|
218
|
+
* ```
|
|
219
|
+
*/
|
|
220
|
+
export function Checkbox(props: CheckboxProps): JSX.Element {
|
|
221
|
+
let inputRef: HTMLInputElement | null = null;
|
|
222
|
+
|
|
223
|
+
const [local, ariaProps] = splitProps(props, [
|
|
224
|
+
'children',
|
|
225
|
+
'class',
|
|
226
|
+
'style',
|
|
227
|
+
'slot',
|
|
228
|
+
'isIndeterminate',
|
|
229
|
+
]);
|
|
230
|
+
|
|
231
|
+
// Check if we're inside a CheckboxGroup
|
|
232
|
+
const groupState = useContext(CheckboxGroupStateContext);
|
|
233
|
+
|
|
234
|
+
// Create appropriate state/aria hooks based on context
|
|
235
|
+
let isSelected: Accessor<boolean>;
|
|
236
|
+
let isPressed: Accessor<boolean>;
|
|
237
|
+
let isDisabled: boolean;
|
|
238
|
+
let isReadOnly: boolean;
|
|
239
|
+
let isInvalid: boolean;
|
|
240
|
+
let labelProps: JSX.LabelHTMLAttributes<HTMLLabelElement>;
|
|
241
|
+
let inputProps: JSX.InputHTMLAttributes<HTMLInputElement>;
|
|
242
|
+
|
|
243
|
+
if (groupState) {
|
|
244
|
+
// Inside a CheckboxGroup - use group item
|
|
245
|
+
const itemAria = createCheckboxGroupItem(
|
|
246
|
+
() => ({
|
|
247
|
+
...ariaProps,
|
|
248
|
+
value: ariaProps.value ?? '',
|
|
249
|
+
children: typeof local.children === 'function' ? true : local.children,
|
|
250
|
+
}),
|
|
251
|
+
groupState,
|
|
252
|
+
() => inputRef
|
|
253
|
+
);
|
|
254
|
+
isSelected = itemAria.isSelected;
|
|
255
|
+
isPressed = itemAria.isPressed;
|
|
256
|
+
isDisabled = itemAria.isDisabled;
|
|
257
|
+
isReadOnly = itemAria.isReadOnly;
|
|
258
|
+
isInvalid = itemAria.isInvalid;
|
|
259
|
+
labelProps = itemAria.labelProps;
|
|
260
|
+
inputProps = itemAria.inputProps;
|
|
261
|
+
} else {
|
|
262
|
+
// Standalone checkbox
|
|
263
|
+
// Use getters to ensure props are read lazily inside reactive contexts
|
|
264
|
+
const state = createToggleState({
|
|
265
|
+
get isSelected() { return ariaProps.isSelected; },
|
|
266
|
+
get defaultSelected() { return ariaProps.defaultSelected; },
|
|
267
|
+
get onChange() { return ariaProps.onChange; },
|
|
268
|
+
get isReadOnly() { return ariaProps.isReadOnly; },
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
const checkboxAria = createCheckbox(
|
|
272
|
+
() => ({
|
|
273
|
+
...ariaProps,
|
|
274
|
+
isIndeterminate: local.isIndeterminate,
|
|
275
|
+
children: typeof local.children === 'function' ? true : local.children,
|
|
276
|
+
}),
|
|
277
|
+
state,
|
|
278
|
+
() => inputRef
|
|
279
|
+
);
|
|
280
|
+
isSelected = checkboxAria.isSelected;
|
|
281
|
+
isPressed = checkboxAria.isPressed;
|
|
282
|
+
isDisabled = checkboxAria.isDisabled;
|
|
283
|
+
isReadOnly = checkboxAria.isReadOnly;
|
|
284
|
+
isInvalid = checkboxAria.isInvalid;
|
|
285
|
+
labelProps = checkboxAria.labelProps;
|
|
286
|
+
inputProps = checkboxAria.inputProps;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Create focus ring
|
|
290
|
+
const { isFocused, isFocusVisible, focusProps } = createFocusRing();
|
|
291
|
+
|
|
292
|
+
// Create hover
|
|
293
|
+
const { isHovered, hoverProps } = createHover({
|
|
294
|
+
get isDisabled() {
|
|
295
|
+
return isDisabled || isReadOnly;
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
// Render props values
|
|
300
|
+
const renderValues = createMemo<CheckboxRenderProps>(() => ({
|
|
301
|
+
isSelected: isSelected(),
|
|
302
|
+
isIndeterminate: local.isIndeterminate ?? false,
|
|
303
|
+
isHovered: isHovered(),
|
|
304
|
+
isPressed: isPressed(),
|
|
305
|
+
isFocused: isFocused(),
|
|
306
|
+
isFocusVisible: isFocusVisible(),
|
|
307
|
+
isDisabled,
|
|
308
|
+
isReadOnly,
|
|
309
|
+
isInvalid,
|
|
310
|
+
isRequired: ariaProps.isRequired ?? false,
|
|
311
|
+
}));
|
|
312
|
+
|
|
313
|
+
// Resolve render props
|
|
314
|
+
const renderProps = useRenderProps(
|
|
315
|
+
{
|
|
316
|
+
children: local.children,
|
|
317
|
+
class: local.class,
|
|
318
|
+
style: local.style,
|
|
319
|
+
defaultClassName: 'solidaria-Checkbox',
|
|
320
|
+
},
|
|
321
|
+
renderValues
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
// Filter DOM props
|
|
325
|
+
const domProps = createMemo(() => {
|
|
326
|
+
const filtered = filterDOMProps(ariaProps, { global: true });
|
|
327
|
+
delete (filtered as Record<string, unknown>).id;
|
|
328
|
+
delete (filtered as Record<string, unknown>).onClick;
|
|
329
|
+
return filtered;
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
// Remove ref from spread props to avoid type conflicts
|
|
333
|
+
const cleanLabelProps = () => {
|
|
334
|
+
const { ref: _ref1, ...rest } = labelProps as Record<string, unknown>;
|
|
335
|
+
return rest;
|
|
336
|
+
};
|
|
337
|
+
const cleanHoverProps = () => {
|
|
338
|
+
const { ref: _ref2, ...rest } = hoverProps as Record<string, unknown>;
|
|
339
|
+
return rest;
|
|
340
|
+
};
|
|
341
|
+
const cleanInputProps = () => {
|
|
342
|
+
const { ref: _ref3, ...rest } = inputProps as Record<string, unknown>;
|
|
343
|
+
return rest;
|
|
344
|
+
};
|
|
345
|
+
const cleanFocusProps = () => {
|
|
346
|
+
const { ref: _ref4, ...rest } = focusProps as Record<string, unknown>;
|
|
347
|
+
return rest;
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
return (
|
|
351
|
+
<label
|
|
352
|
+
{...domProps()}
|
|
353
|
+
{...cleanLabelProps()}
|
|
354
|
+
{...cleanHoverProps()}
|
|
355
|
+
class={renderProps().class}
|
|
356
|
+
style={renderProps().style}
|
|
357
|
+
data-selected={isSelected() || undefined}
|
|
358
|
+
data-indeterminate={local.isIndeterminate || undefined}
|
|
359
|
+
data-pressed={isPressed() || undefined}
|
|
360
|
+
data-hovered={isHovered() || undefined}
|
|
361
|
+
data-focused={isFocused() || undefined}
|
|
362
|
+
data-focus-visible={isFocusVisible() || undefined}
|
|
363
|
+
data-disabled={isDisabled || undefined}
|
|
364
|
+
data-readonly={isReadOnly || undefined}
|
|
365
|
+
data-invalid={isInvalid || undefined}
|
|
366
|
+
data-required={ariaProps.isRequired || undefined}
|
|
367
|
+
>
|
|
368
|
+
<VisuallyHidden>
|
|
369
|
+
<input
|
|
370
|
+
ref={(el) => (inputRef = el)}
|
|
371
|
+
{...cleanInputProps()}
|
|
372
|
+
{...cleanFocusProps()}
|
|
373
|
+
/>
|
|
374
|
+
</VisuallyHidden>
|
|
375
|
+
{renderProps().children}
|
|
376
|
+
</label>
|
|
377
|
+
);
|
|
378
|
+
}
|