@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/SearchField.tsx
CHANGED
|
@@ -9,21 +9,28 @@ import {
|
|
|
9
9
|
type JSX,
|
|
10
10
|
createContext,
|
|
11
11
|
createMemo,
|
|
12
|
+
onCleanup,
|
|
13
|
+
onMount,
|
|
12
14
|
splitProps,
|
|
13
15
|
useContext,
|
|
14
16
|
Show,
|
|
15
|
-
} from
|
|
17
|
+
} from "solid-js";
|
|
16
18
|
import {
|
|
17
19
|
createSearchField,
|
|
18
20
|
createFocusRing,
|
|
19
21
|
createHover,
|
|
20
22
|
createPress,
|
|
23
|
+
mergeProps,
|
|
21
24
|
type AriaSearchFieldProps,
|
|
22
|
-
} from
|
|
25
|
+
} from "@proyecto-viviana/solidaria";
|
|
23
26
|
import {
|
|
24
27
|
createSearchFieldState,
|
|
28
|
+
VALID_VALIDITY_STATE,
|
|
25
29
|
type SearchFieldState,
|
|
26
|
-
|
|
30
|
+
type ValidationResult,
|
|
31
|
+
} from "@proyecto-viviana/solid-stately";
|
|
32
|
+
import { FormContext, type FormProps } from "./Form";
|
|
33
|
+
import { FieldErrorContext, type FieldErrorContextValue } from "./FieldError";
|
|
27
34
|
import {
|
|
28
35
|
type RenderChildren,
|
|
29
36
|
type ClassNameOrFunction,
|
|
@@ -31,11 +38,7 @@ import {
|
|
|
31
38
|
type SlotProps,
|
|
32
39
|
useRenderProps,
|
|
33
40
|
filterDOMProps,
|
|
34
|
-
} from
|
|
35
|
-
|
|
36
|
-
// ============================================
|
|
37
|
-
// TYPES
|
|
38
|
-
// ============================================
|
|
41
|
+
} from "./utils";
|
|
39
42
|
|
|
40
43
|
export interface SearchFieldRenderProps {
|
|
41
44
|
/** Whether the search field is empty. */
|
|
@@ -52,7 +55,7 @@ export interface SearchFieldRenderProps {
|
|
|
52
55
|
value: string;
|
|
53
56
|
}
|
|
54
57
|
|
|
55
|
-
export interface SearchFieldProps extends Omit<AriaSearchFieldProps,
|
|
58
|
+
export interface SearchFieldProps extends Omit<AriaSearchFieldProps, "label">, SlotProps {
|
|
56
59
|
/** The current value (controlled). */
|
|
57
60
|
value?: string;
|
|
58
61
|
/** The default value (uncontrolled). */
|
|
@@ -71,6 +74,8 @@ export interface SearchFieldProps extends Omit<AriaSearchFieldProps, 'label'>, S
|
|
|
71
74
|
class?: ClassNameOrFunction<SearchFieldRenderProps>;
|
|
72
75
|
/** The inline style for the element. */
|
|
73
76
|
style?: StyleOrFunction<SearchFieldRenderProps>;
|
|
77
|
+
/** Ref for the outer search field element. */
|
|
78
|
+
ref?: (el: HTMLDivElement) => void;
|
|
74
79
|
}
|
|
75
80
|
|
|
76
81
|
export interface SearchFieldInputRenderProps {
|
|
@@ -86,7 +91,8 @@ export interface SearchFieldInputRenderProps {
|
|
|
86
91
|
isInvalid: boolean;
|
|
87
92
|
}
|
|
88
93
|
|
|
89
|
-
export interface SearchFieldInputProps
|
|
94
|
+
export interface SearchFieldInputProps
|
|
95
|
+
extends SlotProps, Omit<JSX.InputHTMLAttributes<HTMLInputElement>, "class" | "style"> {
|
|
90
96
|
/** The CSS className for the element. */
|
|
91
97
|
class?: ClassNameOrFunction<SearchFieldInputRenderProps>;
|
|
92
98
|
/** The inline style for the element. */
|
|
@@ -102,7 +108,10 @@ export interface SearchFieldClearButtonRenderProps {
|
|
|
102
108
|
isDisabled: boolean;
|
|
103
109
|
}
|
|
104
110
|
|
|
105
|
-
export interface SearchFieldClearButtonProps
|
|
111
|
+
export interface SearchFieldClearButtonProps
|
|
112
|
+
extends
|
|
113
|
+
SlotProps,
|
|
114
|
+
Omit<JSX.ButtonHTMLAttributes<HTMLButtonElement>, "class" | "style" | "children"> {
|
|
106
115
|
/** The children of the button. */
|
|
107
116
|
children?: RenderChildren<SearchFieldClearButtonRenderProps>;
|
|
108
117
|
/** The CSS className for the element. */
|
|
@@ -111,85 +120,181 @@ export interface SearchFieldClearButtonProps extends SlotProps, Omit<JSX.ButtonH
|
|
|
111
120
|
style?: StyleOrFunction<SearchFieldClearButtonRenderProps>;
|
|
112
121
|
}
|
|
113
122
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
state: SearchFieldState;
|
|
120
|
-
inputProps: JSX.InputHTMLAttributes<HTMLInputElement>;
|
|
121
|
-
clearButtonProps: {
|
|
122
|
-
'aria-label': string;
|
|
123
|
+
interface SearchFieldContextValue extends Partial<SearchFieldProps> {
|
|
124
|
+
state?: SearchFieldState;
|
|
125
|
+
inputProps?: JSX.InputHTMLAttributes<HTMLInputElement>;
|
|
126
|
+
clearButtonProps?: {
|
|
127
|
+
"aria-label": string;
|
|
123
128
|
tabIndex: number;
|
|
124
129
|
disabled?: boolean;
|
|
125
130
|
onMouseDown: (e: MouseEvent) => void;
|
|
126
131
|
onClick: () => void;
|
|
127
132
|
};
|
|
128
|
-
labelProps
|
|
129
|
-
descriptionProps
|
|
130
|
-
errorMessageProps
|
|
131
|
-
isDisabled
|
|
132
|
-
isInvalid
|
|
133
|
-
isRequired
|
|
134
|
-
isReadOnly
|
|
135
|
-
setInputRef
|
|
133
|
+
labelProps?: JSX.HTMLAttributes<HTMLElement>;
|
|
134
|
+
descriptionProps?: JSX.HTMLAttributes<HTMLElement>;
|
|
135
|
+
errorMessageProps?: JSX.HTMLAttributes<HTMLElement>;
|
|
136
|
+
isDisabled?: boolean;
|
|
137
|
+
isInvalid?: boolean;
|
|
138
|
+
isRequired?: boolean;
|
|
139
|
+
isReadOnly?: boolean;
|
|
140
|
+
setInputRef?: (el: HTMLInputElement) => void;
|
|
141
|
+
slots?: Record<string, SearchFieldProps>;
|
|
136
142
|
}
|
|
137
143
|
|
|
138
144
|
export const SearchFieldContext = createContext<SearchFieldContextValue | null>(null);
|
|
139
145
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
146
|
+
function withFormValidationBehavior(
|
|
147
|
+
props: SearchFieldProps,
|
|
148
|
+
formContext: FormProps | null,
|
|
149
|
+
): SearchFieldProps {
|
|
150
|
+
if (!formContext?.validationBehavior) {
|
|
151
|
+
return props;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return new Proxy(props, {
|
|
155
|
+
get(target, property, receiver) {
|
|
156
|
+
const localValue = Reflect.get(target, property, receiver);
|
|
157
|
+
if (property === "validationBehavior" && localValue === undefined) {
|
|
158
|
+
return formContext.validationBehavior;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return localValue;
|
|
162
|
+
},
|
|
163
|
+
has(target, property) {
|
|
164
|
+
return (
|
|
165
|
+
Reflect.has(target, property) ||
|
|
166
|
+
(property === "validationBehavior" && formContext.validationBehavior !== undefined)
|
|
167
|
+
);
|
|
168
|
+
},
|
|
169
|
+
ownKeys(target) {
|
|
170
|
+
const keys = new Set(Reflect.ownKeys(target));
|
|
171
|
+
if (formContext.validationBehavior !== undefined) {
|
|
172
|
+
keys.add("validationBehavior");
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return Array.from(keys);
|
|
176
|
+
},
|
|
177
|
+
getOwnPropertyDescriptor(target, property) {
|
|
178
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(target, property);
|
|
179
|
+
if (descriptor) {
|
|
180
|
+
return descriptor;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (property === "validationBehavior" && formContext.validationBehavior !== undefined) {
|
|
184
|
+
return {
|
|
185
|
+
enumerable: true,
|
|
186
|
+
configurable: true,
|
|
187
|
+
get: () => formContext.validationBehavior,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return undefined;
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function eventWithCurrentTarget<T extends HTMLElement>(event: Event, element: T): Event {
|
|
197
|
+
return new Proxy(event, {
|
|
198
|
+
get(target, property, receiver) {
|
|
199
|
+
if (property === "target" || property === "currentTarget") {
|
|
200
|
+
return element;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const value = Reflect.get(target, property, receiver);
|
|
204
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function clearDelegatedTextEntryHandlers(element: HTMLElement) {
|
|
210
|
+
const delegatedElement = element as HTMLElement & {
|
|
211
|
+
$$input?: unknown;
|
|
212
|
+
$$change?: unknown;
|
|
213
|
+
};
|
|
214
|
+
delete delegatedElement.$$input;
|
|
215
|
+
delete delegatedElement.$$change;
|
|
216
|
+
}
|
|
143
217
|
|
|
144
218
|
/**
|
|
145
219
|
* A search field allows a user to enter and clear a search query.
|
|
146
220
|
*/
|
|
147
221
|
export function SearchField(props: SearchFieldProps): JSX.Element {
|
|
222
|
+
const formContext = useContext(FormContext);
|
|
223
|
+
const contextProps = useContext(SearchFieldContext);
|
|
224
|
+
const contextSlotProps = contextProps?.slots?.[props.slot ?? "default"];
|
|
225
|
+
const contextBaseProps = createMemo<SearchFieldProps>(() => {
|
|
226
|
+
if (!contextProps) return {};
|
|
227
|
+
const {
|
|
228
|
+
state: _state,
|
|
229
|
+
inputProps: _inputProps,
|
|
230
|
+
clearButtonProps: _clearButtonProps,
|
|
231
|
+
labelProps: _labelProps,
|
|
232
|
+
descriptionProps: _descriptionProps,
|
|
233
|
+
errorMessageProps: _errorMessageProps,
|
|
234
|
+
isDisabled: _isDisabled,
|
|
235
|
+
isInvalid: _isInvalid,
|
|
236
|
+
isRequired: _isRequired,
|
|
237
|
+
isReadOnly: _isReadOnly,
|
|
238
|
+
setInputRef: _setInputRef,
|
|
239
|
+
slots: _slots,
|
|
240
|
+
...restContextProps
|
|
241
|
+
} = contextProps;
|
|
242
|
+
return restContextProps as SearchFieldProps;
|
|
243
|
+
});
|
|
244
|
+
const baseProps = (
|
|
245
|
+
contextProps ? mergeProps(contextBaseProps(), contextSlotProps ?? {}, props) : props
|
|
246
|
+
) as SearchFieldProps;
|
|
247
|
+
const mergedProps = withFormValidationBehavior(baseProps, formContext);
|
|
248
|
+
|
|
148
249
|
const [local, stateProps, ariaProps, rest] = splitProps(
|
|
149
|
-
|
|
150
|
-
[
|
|
151
|
-
[
|
|
250
|
+
mergedProps,
|
|
251
|
+
["children", "class", "style", "slot", "ref"],
|
|
252
|
+
["value", "defaultValue", "onChange", "onSubmit", "onClear"],
|
|
152
253
|
[
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
254
|
+
"label",
|
|
255
|
+
"aria-label",
|
|
256
|
+
"aria-labelledby",
|
|
257
|
+
"aria-describedby",
|
|
258
|
+
"isDisabled",
|
|
259
|
+
"isReadOnly",
|
|
260
|
+
"isRequired",
|
|
261
|
+
"isInvalid",
|
|
262
|
+
"description",
|
|
263
|
+
"errorMessage",
|
|
264
|
+
"id",
|
|
265
|
+
"autoFocus",
|
|
266
|
+
"excludeFromTabOrder",
|
|
267
|
+
"name",
|
|
268
|
+
"form",
|
|
269
|
+
"validationBehavior",
|
|
270
|
+
"type",
|
|
271
|
+
"placeholder",
|
|
272
|
+
"autoComplete",
|
|
273
|
+
"inputMode",
|
|
274
|
+
"enterKeyHint",
|
|
275
|
+
"autoCorrect",
|
|
276
|
+
"autoCapitalize",
|
|
277
|
+
"spellCheck",
|
|
278
|
+
"maxLength",
|
|
279
|
+
"minLength",
|
|
280
|
+
"pattern",
|
|
281
|
+
"onFocus",
|
|
282
|
+
"onBlur",
|
|
283
|
+
"onFocusChange",
|
|
284
|
+
"onKeyDown",
|
|
285
|
+
"onKeyUp",
|
|
286
|
+
"onCopy",
|
|
287
|
+
"onCut",
|
|
288
|
+
"onPaste",
|
|
289
|
+
"onCompositionStart",
|
|
290
|
+
"onCompositionEnd",
|
|
291
|
+
"onCompositionUpdate",
|
|
292
|
+
"onSelect",
|
|
293
|
+
"onBeforeInput",
|
|
294
|
+
"onInput",
|
|
295
|
+
],
|
|
190
296
|
);
|
|
191
297
|
|
|
192
|
-
// Create search field state
|
|
193
298
|
const state = createSearchFieldState({
|
|
194
299
|
get value() {
|
|
195
300
|
return stateProps.value;
|
|
@@ -202,13 +307,11 @@ export function SearchField(props: SearchFieldProps): JSX.Element {
|
|
|
202
307
|
},
|
|
203
308
|
});
|
|
204
309
|
|
|
205
|
-
// Ref for the input
|
|
206
310
|
let inputRef: HTMLInputElement | undefined;
|
|
207
311
|
const setInputRef = (el: HTMLInputElement) => {
|
|
208
312
|
inputRef = el;
|
|
209
313
|
};
|
|
210
314
|
|
|
211
|
-
// Create search field aria props
|
|
212
315
|
const searchFieldAria = createSearchField(
|
|
213
316
|
{
|
|
214
317
|
get isDisabled() {
|
|
@@ -226,14 +329,14 @@ export function SearchField(props: SearchFieldProps): JSX.Element {
|
|
|
226
329
|
get label() {
|
|
227
330
|
return ariaProps.label;
|
|
228
331
|
},
|
|
229
|
-
get
|
|
230
|
-
return ariaProps[
|
|
332
|
+
get "aria-label"() {
|
|
333
|
+
return ariaProps["aria-label"];
|
|
231
334
|
},
|
|
232
|
-
get
|
|
233
|
-
return ariaProps[
|
|
335
|
+
get "aria-labelledby"() {
|
|
336
|
+
return ariaProps["aria-labelledby"];
|
|
234
337
|
},
|
|
235
|
-
get
|
|
236
|
-
return ariaProps[
|
|
338
|
+
get "aria-describedby"() {
|
|
339
|
+
return ariaProps["aria-describedby"];
|
|
237
340
|
},
|
|
238
341
|
get description() {
|
|
239
342
|
return ariaProps.description;
|
|
@@ -247,15 +350,30 @@ export function SearchField(props: SearchFieldProps): JSX.Element {
|
|
|
247
350
|
get name() {
|
|
248
351
|
return ariaProps.name;
|
|
249
352
|
},
|
|
353
|
+
get form() {
|
|
354
|
+
return ariaProps.form;
|
|
355
|
+
},
|
|
356
|
+
get validationBehavior() {
|
|
357
|
+
return ariaProps.validationBehavior;
|
|
358
|
+
},
|
|
359
|
+
get type() {
|
|
360
|
+
return ariaProps.type;
|
|
361
|
+
},
|
|
250
362
|
get autoFocus() {
|
|
251
363
|
return ariaProps.autoFocus;
|
|
252
364
|
},
|
|
365
|
+
get excludeFromTabOrder() {
|
|
366
|
+
return ariaProps.excludeFromTabOrder;
|
|
367
|
+
},
|
|
253
368
|
get autoComplete() {
|
|
254
369
|
return ariaProps.autoComplete;
|
|
255
370
|
},
|
|
256
371
|
get inputMode() {
|
|
257
372
|
return ariaProps.inputMode;
|
|
258
373
|
},
|
|
374
|
+
get enterKeyHint() {
|
|
375
|
+
return ariaProps.enterKeyHint;
|
|
376
|
+
},
|
|
259
377
|
get autoCorrect() {
|
|
260
378
|
return ariaProps.autoCorrect;
|
|
261
379
|
},
|
|
@@ -324,12 +442,11 @@ export function SearchField(props: SearchFieldProps): JSX.Element {
|
|
|
324
442
|
},
|
|
325
443
|
},
|
|
326
444
|
state,
|
|
327
|
-
() => inputRef ?? null
|
|
445
|
+
() => inputRef ?? null,
|
|
328
446
|
);
|
|
329
447
|
|
|
330
|
-
// Render props values
|
|
331
448
|
const renderValues = createMemo<SearchFieldRenderProps>(() => ({
|
|
332
|
-
isEmpty: state.value() ===
|
|
449
|
+
isEmpty: state.value() === "",
|
|
333
450
|
isDisabled: ariaProps.isDisabled ?? false,
|
|
334
451
|
isInvalid: searchFieldAria.isInvalid ?? false,
|
|
335
452
|
isRequired: ariaProps.isRequired ?? false,
|
|
@@ -337,20 +454,61 @@ export function SearchField(props: SearchFieldProps): JSX.Element {
|
|
|
337
454
|
value: state.value(),
|
|
338
455
|
}));
|
|
339
456
|
|
|
340
|
-
// Resolve render props
|
|
341
457
|
const renderProps = useRenderProps(
|
|
342
458
|
{
|
|
343
|
-
children:
|
|
459
|
+
children: local.children,
|
|
344
460
|
class: local.class,
|
|
345
461
|
style: local.style,
|
|
346
|
-
defaultClassName:
|
|
462
|
+
defaultClassName: "solidaria-SearchField",
|
|
347
463
|
},
|
|
348
|
-
renderValues
|
|
464
|
+
renderValues,
|
|
349
465
|
);
|
|
466
|
+
const childRenderValues: SearchFieldRenderProps = {
|
|
467
|
+
get isEmpty() {
|
|
468
|
+
return state.value() === "";
|
|
469
|
+
},
|
|
470
|
+
get isDisabled() {
|
|
471
|
+
return ariaProps.isDisabled ?? false;
|
|
472
|
+
},
|
|
473
|
+
get isInvalid() {
|
|
474
|
+
return searchFieldAria.isInvalid ?? false;
|
|
475
|
+
},
|
|
476
|
+
get isRequired() {
|
|
477
|
+
return ariaProps.isRequired ?? false;
|
|
478
|
+
},
|
|
479
|
+
get isReadOnly() {
|
|
480
|
+
return ariaProps.isReadOnly ?? false;
|
|
481
|
+
},
|
|
482
|
+
get value() {
|
|
483
|
+
return state.value();
|
|
484
|
+
},
|
|
485
|
+
};
|
|
350
486
|
|
|
351
|
-
|
|
352
|
-
|
|
487
|
+
const domProps = createMemo(() =>
|
|
488
|
+
filterDOMProps(rest as Record<string, unknown>, { global: true }),
|
|
489
|
+
);
|
|
353
490
|
|
|
491
|
+
const fieldValidation = createMemo<ValidationResult>(() => {
|
|
492
|
+
const isInvalid = searchFieldAria.isInvalid;
|
|
493
|
+
const errorMessage = ariaProps.errorMessage;
|
|
494
|
+
const validationErrors = isInvalid && typeof errorMessage === "string" ? [errorMessage] : [];
|
|
495
|
+
|
|
496
|
+
return {
|
|
497
|
+
isInvalid,
|
|
498
|
+
validationErrors,
|
|
499
|
+
validationDetails: isInvalid
|
|
500
|
+
? { ...VALID_VALIDITY_STATE, customError: true, valid: false }
|
|
501
|
+
: VALID_VALIDITY_STATE,
|
|
502
|
+
};
|
|
503
|
+
});
|
|
504
|
+
const fieldErrorContext: FieldErrorContextValue = {
|
|
505
|
+
get validation() {
|
|
506
|
+
return fieldValidation();
|
|
507
|
+
},
|
|
508
|
+
get errorMessageProps() {
|
|
509
|
+
return searchFieldAria.errorMessageProps;
|
|
510
|
+
},
|
|
511
|
+
};
|
|
354
512
|
const contextValue: SearchFieldContextValue = {
|
|
355
513
|
state,
|
|
356
514
|
get inputProps() {
|
|
@@ -382,32 +540,43 @@ export function SearchField(props: SearchFieldProps): JSX.Element {
|
|
|
382
540
|
},
|
|
383
541
|
setInputRef,
|
|
384
542
|
};
|
|
543
|
+
const fieldChildren = () => {
|
|
544
|
+
const children = local.children;
|
|
545
|
+
return typeof children === "function" ? children(childRenderValues) : children;
|
|
546
|
+
};
|
|
385
547
|
|
|
386
548
|
return (
|
|
387
|
-
<
|
|
388
|
-
<
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
549
|
+
<FieldErrorContext.Provider value={fieldErrorContext}>
|
|
550
|
+
<SearchFieldContext.Provider value={contextValue}>
|
|
551
|
+
<div
|
|
552
|
+
{...domProps()}
|
|
553
|
+
ref={local.ref}
|
|
554
|
+
class={renderProps.class()}
|
|
555
|
+
style={renderProps.style()}
|
|
556
|
+
data-empty={state.value() === "" || undefined}
|
|
557
|
+
data-disabled={ariaProps.isDisabled || undefined}
|
|
558
|
+
data-invalid={searchFieldAria.isInvalid || undefined}
|
|
559
|
+
data-required={ariaProps.isRequired || undefined}
|
|
560
|
+
data-readonly={ariaProps.isReadOnly || undefined}
|
|
561
|
+
>
|
|
562
|
+
{fieldChildren()}
|
|
563
|
+
</div>
|
|
564
|
+
</SearchFieldContext.Provider>
|
|
565
|
+
</FieldErrorContext.Provider>
|
|
401
566
|
);
|
|
402
567
|
}
|
|
403
568
|
|
|
404
569
|
/**
|
|
405
570
|
* The label for a search field.
|
|
406
571
|
*/
|
|
407
|
-
export function SearchFieldLabel(props: {
|
|
572
|
+
export function SearchFieldLabel(props: {
|
|
573
|
+
children?: JSX.Element;
|
|
574
|
+
class?: string;
|
|
575
|
+
style?: JSX.CSSProperties;
|
|
576
|
+
}): JSX.Element {
|
|
408
577
|
const context = useContext(SearchFieldContext);
|
|
409
578
|
if (!context) {
|
|
410
|
-
throw new Error(
|
|
579
|
+
throw new Error("SearchFieldLabel must be used within a SearchField");
|
|
411
580
|
}
|
|
412
581
|
|
|
413
582
|
const cleanLabelProps = () => {
|
|
@@ -418,7 +587,7 @@ export function SearchFieldLabel(props: { children?: JSX.Element; class?: string
|
|
|
418
587
|
return (
|
|
419
588
|
<label
|
|
420
589
|
{...cleanLabelProps()}
|
|
421
|
-
class={props.class ??
|
|
590
|
+
class={props.class ?? "solidaria-SearchField-label"}
|
|
422
591
|
style={props.style}
|
|
423
592
|
>
|
|
424
593
|
{props.children}
|
|
@@ -430,43 +599,39 @@ export function SearchFieldLabel(props: { children?: JSX.Element; class?: string
|
|
|
430
599
|
* The input element for a search field.
|
|
431
600
|
*/
|
|
432
601
|
export function SearchFieldInput(props: SearchFieldInputProps): JSX.Element {
|
|
433
|
-
const [local, domProps] = splitProps(props, [
|
|
602
|
+
const [local, domProps] = splitProps(props, ["class", "style", "slot"]);
|
|
603
|
+
let inputElement: HTMLInputElement | undefined;
|
|
434
604
|
|
|
435
605
|
const context = useContext(SearchFieldContext);
|
|
436
606
|
if (!context) {
|
|
437
|
-
throw new Error(
|
|
607
|
+
throw new Error("SearchFieldInput must be used within a SearchField");
|
|
438
608
|
}
|
|
439
609
|
|
|
440
|
-
// Create focus ring
|
|
441
610
|
const { isFocused, isFocusVisible, focusProps } = createFocusRing();
|
|
442
611
|
|
|
443
|
-
// Create hover
|
|
444
612
|
const { isHovered, hoverProps } = createHover({
|
|
445
613
|
get isDisabled() {
|
|
446
614
|
return context.isDisabled;
|
|
447
615
|
},
|
|
448
616
|
});
|
|
449
617
|
|
|
450
|
-
// Render props values
|
|
451
618
|
const renderValues = createMemo<SearchFieldInputRenderProps>(() => ({
|
|
452
619
|
isFocused: isFocused(),
|
|
453
620
|
isFocusVisible: isFocusVisible(),
|
|
454
621
|
isHovered: isHovered(),
|
|
455
|
-
isDisabled: context.isDisabled,
|
|
456
|
-
isInvalid: context.isInvalid,
|
|
622
|
+
isDisabled: !!context.isDisabled,
|
|
623
|
+
isInvalid: !!context.isInvalid,
|
|
457
624
|
}));
|
|
458
625
|
|
|
459
|
-
// Resolve render props
|
|
460
626
|
const renderProps = useRenderProps(
|
|
461
627
|
{
|
|
462
628
|
class: local.class,
|
|
463
629
|
style: local.style,
|
|
464
|
-
defaultClassName:
|
|
630
|
+
defaultClassName: "solidaria-SearchField-input",
|
|
465
631
|
},
|
|
466
|
-
renderValues
|
|
632
|
+
renderValues,
|
|
467
633
|
);
|
|
468
634
|
|
|
469
|
-
// Remove ref from spread props
|
|
470
635
|
const cleanInputProps = () => {
|
|
471
636
|
const { ref: _ref, ...rest } = context.inputProps as Record<string, unknown>;
|
|
472
637
|
return rest;
|
|
@@ -480,13 +645,67 @@ export function SearchFieldInput(props: SearchFieldInputProps): JSX.Element {
|
|
|
480
645
|
return rest;
|
|
481
646
|
};
|
|
482
647
|
|
|
648
|
+
const mergedInputProps = () =>
|
|
649
|
+
({
|
|
650
|
+
...domProps,
|
|
651
|
+
...cleanInputProps(),
|
|
652
|
+
...cleanFocusProps(),
|
|
653
|
+
...cleanHoverProps(),
|
|
654
|
+
}) as Record<string, unknown>;
|
|
655
|
+
|
|
656
|
+
onMount(() => {
|
|
657
|
+
const element = inputElement;
|
|
658
|
+
if (!element) {
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
const inputHandler = (event: Event) => {
|
|
663
|
+
const handler = mergedInputProps().onInput as
|
|
664
|
+
| JSX.EventHandler<HTMLInputElement, InputEvent>
|
|
665
|
+
| undefined;
|
|
666
|
+
handler?.(
|
|
667
|
+
eventWithCurrentTarget(event, element) as InputEvent & {
|
|
668
|
+
currentTarget: HTMLInputElement;
|
|
669
|
+
target: Element;
|
|
670
|
+
},
|
|
671
|
+
);
|
|
672
|
+
clearDelegatedTextEntryHandlers(element);
|
|
673
|
+
event.stopPropagation();
|
|
674
|
+
};
|
|
675
|
+
const changeHandler = (event: Event) => {
|
|
676
|
+
const handler = mergedInputProps().onChange as
|
|
677
|
+
| JSX.EventHandler<HTMLInputElement, Event>
|
|
678
|
+
| undefined;
|
|
679
|
+
handler?.(
|
|
680
|
+
eventWithCurrentTarget(event, element) as Event & {
|
|
681
|
+
currentTarget: HTMLInputElement;
|
|
682
|
+
target: Element;
|
|
683
|
+
},
|
|
684
|
+
);
|
|
685
|
+
clearDelegatedTextEntryHandlers(element);
|
|
686
|
+
event.stopPropagation();
|
|
687
|
+
};
|
|
688
|
+
|
|
689
|
+
element.addEventListener("input", inputHandler);
|
|
690
|
+
element.addEventListener("change", changeHandler);
|
|
691
|
+
clearDelegatedTextEntryHandlers(element);
|
|
692
|
+
onCleanup(() => {
|
|
693
|
+
element.removeEventListener("input", inputHandler);
|
|
694
|
+
element.removeEventListener("change", changeHandler);
|
|
695
|
+
});
|
|
696
|
+
});
|
|
697
|
+
|
|
483
698
|
return (
|
|
484
699
|
<input
|
|
485
|
-
{...
|
|
486
|
-
ref={
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
700
|
+
{...mergedInputProps()}
|
|
701
|
+
ref={(element) => {
|
|
702
|
+
inputElement = element;
|
|
703
|
+
context.setInputRef?.(element);
|
|
704
|
+
const ref = (domProps as { ref?: unknown }).ref;
|
|
705
|
+
if (typeof ref === "function") {
|
|
706
|
+
ref(element);
|
|
707
|
+
}
|
|
708
|
+
}}
|
|
490
709
|
class={renderProps.class()}
|
|
491
710
|
style={renderProps.style()}
|
|
492
711
|
data-focused={isFocused() || undefined}
|
|
@@ -502,52 +721,51 @@ export function SearchFieldInput(props: SearchFieldInputProps): JSX.Element {
|
|
|
502
721
|
* The clear button for a search field.
|
|
503
722
|
*/
|
|
504
723
|
export function SearchFieldClearButton(props: SearchFieldClearButtonProps): JSX.Element {
|
|
505
|
-
const [local, domProps] = splitProps(props, [
|
|
724
|
+
const [local, domProps] = splitProps(props, ["class", "style", "slot", "children"]);
|
|
506
725
|
|
|
507
726
|
const context = useContext(SearchFieldContext);
|
|
508
727
|
if (!context) {
|
|
509
|
-
throw new Error(
|
|
728
|
+
throw new Error("SearchFieldClearButton must be used within a SearchField");
|
|
510
729
|
}
|
|
511
730
|
|
|
512
|
-
|
|
731
|
+
const isDisabled = () => !!(context.isDisabled || context.isReadOnly);
|
|
732
|
+
const isEmpty = () => (context.state?.value() ?? "") === "";
|
|
733
|
+
const clear = () => {
|
|
734
|
+
if (!isDisabled() && !isEmpty()) {
|
|
735
|
+
context.clearButtonProps?.onClick();
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
|
|
513
739
|
const { isPressed, pressProps } = createPress({
|
|
514
740
|
get isDisabled() {
|
|
515
741
|
return context.isDisabled || context.isReadOnly;
|
|
516
742
|
},
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
},
|
|
743
|
+
onClick: clear,
|
|
744
|
+
onPress: clear,
|
|
520
745
|
});
|
|
521
746
|
|
|
522
|
-
// Create hover
|
|
523
747
|
const { isHovered, hoverProps } = createHover({
|
|
524
748
|
get isDisabled() {
|
|
525
749
|
return context.isDisabled || context.isReadOnly;
|
|
526
750
|
},
|
|
527
751
|
});
|
|
528
752
|
|
|
529
|
-
const isDisabled = () => context.isDisabled || context.isReadOnly;
|
|
530
|
-
const isEmpty = () => context.state.value() === '';
|
|
531
|
-
|
|
532
|
-
// Render props values
|
|
533
753
|
const renderValues = createMemo<SearchFieldClearButtonRenderProps>(() => ({
|
|
534
754
|
isPressed: isPressed(),
|
|
535
755
|
isHovered: isHovered(),
|
|
536
756
|
isDisabled: isDisabled(),
|
|
537
757
|
}));
|
|
538
758
|
|
|
539
|
-
// Resolve render props
|
|
540
759
|
const renderProps = useRenderProps(
|
|
541
760
|
{
|
|
542
761
|
children: props.children,
|
|
543
762
|
class: local.class,
|
|
544
763
|
style: local.style,
|
|
545
|
-
defaultClassName:
|
|
764
|
+
defaultClassName: "solidaria-SearchField-clear",
|
|
546
765
|
},
|
|
547
|
-
renderValues
|
|
766
|
+
renderValues,
|
|
548
767
|
);
|
|
549
768
|
|
|
550
|
-
// Remove ref from spread props
|
|
551
769
|
const cleanPressProps = () => {
|
|
552
770
|
const { ref: _ref, ...rest } = pressProps as Record<string, unknown>;
|
|
553
771
|
return rest;
|
|
@@ -557,17 +775,19 @@ export function SearchFieldClearButton(props: SearchFieldClearButtonProps): JSX.
|
|
|
557
775
|
return rest;
|
|
558
776
|
};
|
|
559
777
|
|
|
560
|
-
// Only show clear button when there's a value
|
|
561
778
|
return (
|
|
562
779
|
<Show when={!isEmpty()}>
|
|
563
780
|
<button
|
|
564
781
|
{...domProps}
|
|
565
782
|
type="button"
|
|
566
|
-
aria-label={context.clearButtonProps[
|
|
567
|
-
tabIndex={context.clearButtonProps
|
|
568
|
-
disabled={context.clearButtonProps
|
|
569
|
-
onMouseDown={context.clearButtonProps
|
|
783
|
+
aria-label={context.clearButtonProps?.["aria-label"] ?? "Clear search"}
|
|
784
|
+
tabIndex={context.clearButtonProps?.tabIndex ?? -1}
|
|
785
|
+
disabled={context.clearButtonProps?.disabled}
|
|
786
|
+
onMouseDown={context.clearButtonProps?.onMouseDown}
|
|
570
787
|
{...cleanPressProps()}
|
|
788
|
+
onPointerUp={clear}
|
|
789
|
+
onMouseUp={clear}
|
|
790
|
+
onClick={clear}
|
|
571
791
|
{...cleanHoverProps()}
|
|
572
792
|
class={renderProps.class()}
|
|
573
793
|
style={renderProps.style()}
|
|
@@ -581,7 +801,6 @@ export function SearchFieldClearButton(props: SearchFieldClearButtonProps): JSX.
|
|
|
581
801
|
);
|
|
582
802
|
}
|
|
583
803
|
|
|
584
|
-
// Attach sub-components
|
|
585
804
|
SearchField.Label = SearchFieldLabel;
|
|
586
805
|
SearchField.Input = SearchFieldInput;
|
|
587
806
|
SearchField.ClearButton = SearchFieldClearButton;
|