@proyecto-viviana/solidaria-components 0.2.5 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +39 -272
- package/dist/ActionBar.d.ts +79 -0
- package/dist/ActionBar.d.ts.map +1 -0
- package/dist/ActionGroup.d.ts +74 -0
- package/dist/ActionGroup.d.ts.map +1 -0
- package/dist/Alert.d.ts +70 -0
- package/dist/Alert.d.ts.map +1 -0
- package/dist/Autocomplete.d.ts +5 -5
- package/dist/Autocomplete.d.ts.map +1 -1
- package/dist/Breadcrumbs.d.ts +27 -8
- package/dist/Breadcrumbs.d.ts.map +1 -1
- package/dist/Button.d.ts +28 -5
- package/dist/Button.d.ts.map +1 -1
- package/dist/Calendar.d.ts +51 -7
- package/dist/Calendar.d.ts.map +1 -1
- package/dist/Checkbox.d.ts +33 -8
- package/dist/Checkbox.d.ts.map +1 -1
- package/dist/Collection.d.ts +130 -0
- package/dist/Collection.d.ts.map +1 -0
- package/dist/Color.d.ts +210 -9
- package/dist/Color.d.ts.map +1 -1
- package/dist/ColorEditor.d.ts +42 -0
- package/dist/ColorEditor.d.ts.map +1 -0
- package/dist/ComboBox.d.ts +146 -16
- package/dist/ComboBox.d.ts.map +1 -1
- package/dist/ContextualHelpTrigger.d.ts +40 -0
- package/dist/ContextualHelpTrigger.d.ts.map +1 -0
- package/dist/DateField.d.ts +35 -8
- package/dist/DateField.d.ts.map +1 -1
- package/dist/DatePicker.d.ts +101 -5
- 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 +25 -5
- package/dist/Disclosure.d.ts.map +1 -1
- package/dist/DragAndDrop.d.ts +80 -0
- package/dist/DragAndDrop.d.ts.map +1 -0
- package/dist/DragPreview.d.ts +14 -0
- package/dist/DragPreview.d.ts.map +1 -0
- package/dist/DropZone.d.ts +27 -0
- package/dist/DropZone.d.ts.map +1 -0
- package/dist/FieldError.d.ts +27 -0
- package/dist/FieldError.d.ts.map +1 -0
- package/dist/FileTrigger.d.ts +26 -0
- package/dist/FileTrigger.d.ts.map +1 -0
- package/dist/Focusable.d.ts +27 -0
- package/dist/Focusable.d.ts.map +1 -0
- package/dist/Form.d.ts +41 -0
- package/dist/Form.d.ts.map +1 -0
- package/dist/GridList.d.ts +69 -10
- 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 +57 -0
- package/dist/Icon.d.ts.map +1 -0
- package/dist/Keyboard.d.ts +13 -0
- package/dist/Keyboard.d.ts.map +1 -0
- 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 +73 -11
- package/dist/ListBox.d.ts.map +1 -1
- package/dist/ListDropTargetDelegate.d.ts +38 -0
- package/dist/ListDropTargetDelegate.d.ts.map +1 -0
- package/dist/Menu.d.ts +79 -10
- package/dist/Menu.d.ts.map +1 -1
- package/dist/Meter.d.ts +4 -4
- package/dist/Meter.d.ts.map +1 -1
- package/dist/Modal.d.ts +6 -4
- package/dist/Modal.d.ts.map +1 -1
- package/dist/NumberField.d.ts +10 -12
- package/dist/NumberField.d.ts.map +1 -1
- package/dist/Popover.d.ts +32 -7
- package/dist/Popover.d.ts.map +1 -1
- package/dist/Pressable.d.ts +27 -0
- package/dist/Pressable.d.ts.map +1 -0
- package/dist/ProgressBar.d.ts +6 -4
- 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 +39 -7
- package/dist/RangeCalendar.d.ts.map +1 -1
- package/dist/RouterProvider.d.ts +75 -0
- package/dist/RouterProvider.d.ts.map +1 -0
- package/dist/SearchField.d.ts +23 -21
- package/dist/SearchField.d.ts.map +1 -1
- package/dist/Select.d.ts +48 -7
- package/dist/Select.d.ts.map +1 -1
- package/dist/SelectionIndicator.d.ts +30 -0
- package/dist/SelectionIndicator.d.ts.map +1 -0
- package/dist/Separator.d.ts +9 -3
- package/dist/Separator.d.ts.map +1 -1
- package/dist/SharedElementTransition.d.ts +41 -0
- package/dist/SharedElementTransition.d.ts.map +1 -0
- package/dist/Slider.d.ts +15 -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 +222 -19
- package/dist/Table.d.ts.map +1 -1
- package/dist/Tabs.d.ts +47 -10
- package/dist/Tabs.d.ts.map +1 -1
- package/dist/TagGroup.d.ts +22 -10
- package/dist/TagGroup.d.ts.map +1 -1
- package/dist/Text.d.ts +10 -0
- package/dist/Text.d.ts.map +1 -0
- package/dist/TextField.d.ts +19 -11
- package/dist/TextField.d.ts.map +1 -1
- package/dist/TimeField.d.ts +32 -7
- 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 +36 -0
- package/dist/ToggleButton.d.ts.map +1 -0
- package/dist/ToggleButtonGroup.d.ts +33 -0
- package/dist/ToggleButtonGroup.d.ts.map +1 -0
- package/dist/Toolbar.d.ts +7 -3
- package/dist/Toolbar.d.ts.map +1 -1
- package/dist/Tooltip.d.ts +58 -7
- package/dist/Tooltip.d.ts.map +1 -1
- package/dist/Tree.d.ts +102 -11
- package/dist/Tree.d.ts.map +1 -1
- package/dist/Virtualizer.d.ts +61 -0
- package/dist/Virtualizer.d.ts.map +1 -0
- package/dist/VirtualizerLayouts.d.ts +82 -0
- package/dist/VirtualizerLayouts.d.ts.map +1 -0
- package/dist/VisuallyHidden.d.ts +4 -2
- package/dist/VisuallyHidden.d.ts.map +1 -1
- package/dist/contexts.d.ts +6 -1
- package/dist/contexts.d.ts.map +1 -1
- package/dist/index.d.ts +73 -39
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23342 -10644
- package/dist/index.js.map +1 -7
- package/dist/index.jsx +18110 -0
- package/dist/index.jsx.map +1 -0
- package/dist/useDragAndDrop.d.ts +93 -0
- package/dist/useDragAndDrop.d.ts.map +1 -0
- package/dist/utils.d.ts +8 -2
- package/dist/utils.d.ts.map +1 -1
- package/dist/virtualizer/Layout.d.ts +79 -0
- package/dist/virtualizer/Layout.d.ts.map +1 -0
- package/package.json +33 -32
- package/src/ActionBar.tsx +251 -0
- package/src/ActionGroup.tsx +277 -0
- package/src/Alert.tsx +152 -0
- package/src/Autocomplete.tsx +39 -44
- package/src/Breadcrumbs.tsx +227 -72
- package/src/Button.tsx +315 -74
- package/src/Calendar.tsx +347 -141
- package/src/Checkbox.tsx +414 -123
- package/src/Collection.tsx +350 -0
- package/src/Color.tsx +1325 -284
- package/src/ColorEditor.tsx +213 -0
- package/src/ComboBox.tsx +644 -245
- package/src/ContextualHelpTrigger.tsx +195 -0
- package/src/DateField.tsx +274 -106
- package/src/DatePicker.tsx +892 -111
- package/src/DateRangePickerContext.tsx +44 -0
- package/src/Dialog.tsx +173 -104
- package/src/Disclosure.tsx +158 -105
- package/src/DragAndDrop.tsx +340 -0
- package/src/DragPreview.tsx +47 -0
- package/src/DropZone.tsx +233 -0
- package/src/FieldError.tsx +89 -0
- package/src/FileTrigger.tsx +83 -0
- package/src/Focusable.tsx +103 -0
- package/src/Form.tsx +140 -0
- package/src/GridList.tsx +542 -128
- package/src/HiddenDateInput.tsx +153 -0
- package/src/HiddenTimeInput.tsx +133 -0
- package/src/Icon.tsx +133 -0
- package/src/Keyboard.tsx +26 -0
- package/src/Landmark.tsx +37 -63
- package/src/Link.tsx +132 -69
- package/src/ListBox.tsx +656 -106
- package/src/ListDropTargetDelegate.ts +283 -0
- package/src/Menu.tsx +1234 -132
- package/src/Meter.tsx +44 -58
- package/src/Modal.tsx +262 -166
- package/src/NumberField.tsx +267 -151
- package/src/Popover.tsx +452 -343
- package/src/Pressable.tsx +108 -0
- package/src/ProgressBar.tsx +54 -59
- package/src/RadioGroup.tsx +533 -121
- package/src/RangeCalendar.tsx +249 -150
- package/src/RouterProvider.tsx +223 -0
- package/src/SearchField.tsx +460 -133
- package/src/Select.tsx +804 -233
- package/src/SelectionIndicator.tsx +108 -0
- package/src/Separator.tsx +47 -49
- package/src/SharedElementTransition.tsx +264 -0
- package/src/Slider.tsx +148 -98
- package/src/StepList.tsx +272 -0
- package/src/Switch.tsx +93 -46
- package/src/Table.tsx +1551 -225
- package/src/Tabs.tsx +377 -123
- package/src/TagGroup.tsx +233 -135
- package/src/Text.tsx +18 -0
- package/src/TextField.tsx +413 -86
- package/src/TimeField.tsx +232 -222
- package/src/Toast.tsx +306 -160
- package/src/ToggleButton.tsx +169 -0
- package/src/ToggleButtonGroup.tsx +141 -0
- package/src/Toolbar.tsx +61 -70
- package/src/Tooltip.tsx +473 -116
- package/src/Tree.tsx +1514 -175
- package/src/Virtualizer.tsx +730 -0
- package/src/VirtualizerLayouts.ts +280 -0
- package/src/VisuallyHidden.tsx +32 -38
- package/src/contexts.ts +29 -36
- package/src/index.ts +972 -620
- package/src/useDragAndDrop.ts +367 -0
- package/src/utils.tsx +69 -50
- package/src/virtualizer/Layout.ts +192 -0
- package/dist/index.ssr.js +0 -9785
- package/dist/index.ssr.js.map +0 -7
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ActionGroup component for solidaria-components
|
|
3
|
+
*
|
|
4
|
+
* Pre-wired headless action group component that combines
|
|
5
|
+
* createListState + createActionGroup/createActionGroupItem.
|
|
6
|
+
* Provides proper dynamic roles (toolbar/radiogroup), keyboard
|
|
7
|
+
* navigation, and ARIA attributes.
|
|
8
|
+
*
|
|
9
|
+
* No RAC equivalent exists — this bridges solidaria ARIA hooks
|
|
10
|
+
* directly to a headless component.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
type JSX,
|
|
15
|
+
type ParentProps,
|
|
16
|
+
createContext,
|
|
17
|
+
createMemo,
|
|
18
|
+
splitProps,
|
|
19
|
+
useContext,
|
|
20
|
+
For,
|
|
21
|
+
} from "solid-js";
|
|
22
|
+
import {
|
|
23
|
+
createActionGroup,
|
|
24
|
+
createActionGroupItem,
|
|
25
|
+
type AriaActionGroupProps,
|
|
26
|
+
} from "@proyecto-viviana/solidaria";
|
|
27
|
+
import {
|
|
28
|
+
createListState,
|
|
29
|
+
type ListState,
|
|
30
|
+
type Key,
|
|
31
|
+
type SelectionMode,
|
|
32
|
+
} from "@proyecto-viviana/solid-stately";
|
|
33
|
+
import {
|
|
34
|
+
type ClassNameOrFunction,
|
|
35
|
+
type StyleOrFunction,
|
|
36
|
+
type SlotProps,
|
|
37
|
+
useRenderProps,
|
|
38
|
+
filterDOMProps,
|
|
39
|
+
} from "./utils";
|
|
40
|
+
|
|
41
|
+
export interface ActionGroupRenderProps {
|
|
42
|
+
/** The orientation of the action group. */
|
|
43
|
+
orientation: "horizontal" | "vertical";
|
|
44
|
+
/** Whether the entire group is disabled. */
|
|
45
|
+
isDisabled: boolean;
|
|
46
|
+
/** The selection mode. */
|
|
47
|
+
selectionMode: SelectionMode;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface ActionGroupItemRenderProps {
|
|
51
|
+
/** Whether the item is selected. */
|
|
52
|
+
isSelected: boolean;
|
|
53
|
+
/** Whether the item is disabled. */
|
|
54
|
+
isDisabled: boolean;
|
|
55
|
+
/** Whether the item is focused. */
|
|
56
|
+
isFocused: boolean;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface ActionGroupItem {
|
|
60
|
+
id: string;
|
|
61
|
+
label: string;
|
|
62
|
+
isDisabled?: boolean;
|
|
63
|
+
[key: string]: unknown;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface ActionGroupProps<T extends ActionGroupItem = ActionGroupItem> extends SlotProps {
|
|
67
|
+
/** The items in the action group. */
|
|
68
|
+
items: T[];
|
|
69
|
+
/** The selection mode. @default 'none' */
|
|
70
|
+
selectionMode?: SelectionMode;
|
|
71
|
+
/** Orientation of the group. @default 'horizontal' */
|
|
72
|
+
orientation?: "horizontal" | "vertical";
|
|
73
|
+
/** Whether the entire group is disabled. */
|
|
74
|
+
isDisabled?: boolean;
|
|
75
|
+
/** Accessible label. */
|
|
76
|
+
"aria-label"?: string;
|
|
77
|
+
/** Labelled-by id. */
|
|
78
|
+
"aria-labelledby"?: string;
|
|
79
|
+
/** Currently selected keys (controlled). */
|
|
80
|
+
selectedKeys?: Iterable<Key>;
|
|
81
|
+
/** Default selected keys (uncontrolled). */
|
|
82
|
+
defaultSelectedKeys?: Iterable<Key>;
|
|
83
|
+
/** Handler called when selection changes. */
|
|
84
|
+
onSelectionChange?: (keys: "all" | Set<Key>) => void;
|
|
85
|
+
/** Handler called when an item action is triggered. */
|
|
86
|
+
onAction?: (key: Key) => void;
|
|
87
|
+
/** Keys of disabled items. */
|
|
88
|
+
disabledKeys?: Iterable<Key>;
|
|
89
|
+
/** Render function for each item. */
|
|
90
|
+
children: (item: T, renderProps: ActionGroupItemRenderProps) => JSX.Element;
|
|
91
|
+
/** CSS class for the container. */
|
|
92
|
+
class?: ClassNameOrFunction<ActionGroupRenderProps>;
|
|
93
|
+
/** Inline style for the container. */
|
|
94
|
+
style?: StyleOrFunction<ActionGroupRenderProps>;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface ActionGroupContextValue<T extends ActionGroupItem = ActionGroupItem> {
|
|
98
|
+
state: ListState<T>;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export const ActionGroupContext = createContext<ActionGroupContextValue | null>(null);
|
|
102
|
+
export const ActionGroupStateContext = createContext<ListState<ActionGroupItem> | null>(null);
|
|
103
|
+
|
|
104
|
+
export function ActionGroup<T extends ActionGroupItem = ActionGroupItem>(
|
|
105
|
+
props: ActionGroupProps<T>,
|
|
106
|
+
): JSX.Element {
|
|
107
|
+
const [local, ariaGroupProps, domProps] = splitProps(
|
|
108
|
+
props,
|
|
109
|
+
[
|
|
110
|
+
"items",
|
|
111
|
+
"selectionMode",
|
|
112
|
+
"orientation",
|
|
113
|
+
"isDisabled",
|
|
114
|
+
"selectedKeys",
|
|
115
|
+
"defaultSelectedKeys",
|
|
116
|
+
"onSelectionChange",
|
|
117
|
+
"onAction",
|
|
118
|
+
"disabledKeys",
|
|
119
|
+
"children",
|
|
120
|
+
"class",
|
|
121
|
+
"style",
|
|
122
|
+
"slot",
|
|
123
|
+
],
|
|
124
|
+
["aria-label", "aria-labelledby"],
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
const state = createListState<T>({
|
|
128
|
+
get items() {
|
|
129
|
+
return local.items;
|
|
130
|
+
},
|
|
131
|
+
get selectionMode() {
|
|
132
|
+
return local.selectionMode ?? "none";
|
|
133
|
+
},
|
|
134
|
+
get selectedKeys() {
|
|
135
|
+
return local.selectedKeys;
|
|
136
|
+
},
|
|
137
|
+
get defaultSelectedKeys() {
|
|
138
|
+
return local.defaultSelectedKeys;
|
|
139
|
+
},
|
|
140
|
+
get onSelectionChange() {
|
|
141
|
+
return local.onSelectionChange;
|
|
142
|
+
},
|
|
143
|
+
get disabledKeys() {
|
|
144
|
+
return local.disabledKeys;
|
|
145
|
+
},
|
|
146
|
+
getKey: (item) => item.id,
|
|
147
|
+
getTextValue: (item) => item.label,
|
|
148
|
+
getDisabled: (item) => !!item.isDisabled,
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const groupAriaProps: AriaActionGroupProps<T> = {
|
|
152
|
+
get items() {
|
|
153
|
+
return local.items;
|
|
154
|
+
},
|
|
155
|
+
get isDisabled() {
|
|
156
|
+
return local.isDisabled;
|
|
157
|
+
},
|
|
158
|
+
get orientation() {
|
|
159
|
+
return local.orientation;
|
|
160
|
+
},
|
|
161
|
+
get "aria-label"() {
|
|
162
|
+
return ariaGroupProps["aria-label"];
|
|
163
|
+
},
|
|
164
|
+
get "aria-labelledby"() {
|
|
165
|
+
return ariaGroupProps["aria-labelledby"];
|
|
166
|
+
},
|
|
167
|
+
get onAction() {
|
|
168
|
+
return local.onAction;
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const { actionGroupProps } = createActionGroup(groupAriaProps, state as ListState<T>);
|
|
173
|
+
|
|
174
|
+
const orientation = () => local.orientation ?? "horizontal";
|
|
175
|
+
|
|
176
|
+
const renderProps = useRenderProps(
|
|
177
|
+
{
|
|
178
|
+
children: undefined,
|
|
179
|
+
class: local.class,
|
|
180
|
+
style: local.style,
|
|
181
|
+
defaultClassName: "solidaria-ActionGroup",
|
|
182
|
+
},
|
|
183
|
+
() => ({
|
|
184
|
+
orientation: orientation(),
|
|
185
|
+
isDisabled: !!local.isDisabled,
|
|
186
|
+
selectionMode: (local.selectionMode ?? "none") as SelectionMode,
|
|
187
|
+
}),
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
const filteredDOMProps = createMemo(() =>
|
|
191
|
+
filterDOMProps(domProps as Record<string, unknown>, { global: true }),
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
return (
|
|
195
|
+
<ActionGroupContext.Provider value={{ state: state as ListState<ActionGroupItem> }}>
|
|
196
|
+
<ActionGroupStateContext.Provider value={state as ListState<ActionGroupItem>}>
|
|
197
|
+
<div
|
|
198
|
+
{...filteredDOMProps()}
|
|
199
|
+
{...actionGroupProps}
|
|
200
|
+
ref={(el: HTMLDivElement) => {
|
|
201
|
+
const refFn = (actionGroupProps as { ref?: (el: HTMLElement) => void }).ref;
|
|
202
|
+
refFn?.(el);
|
|
203
|
+
}}
|
|
204
|
+
class={renderProps.class()}
|
|
205
|
+
style={renderProps.style()}
|
|
206
|
+
slot={local.slot}
|
|
207
|
+
data-orientation={orientation()}
|
|
208
|
+
data-disabled={local.isDisabled || undefined}
|
|
209
|
+
>
|
|
210
|
+
<For each={local.items}>
|
|
211
|
+
{(item) => (
|
|
212
|
+
<ActionGroupItemWrapper
|
|
213
|
+
item={item}
|
|
214
|
+
state={state as ListState<ActionGroupItem>}
|
|
215
|
+
renderChild={
|
|
216
|
+
local.children as (
|
|
217
|
+
item: ActionGroupItem,
|
|
218
|
+
rp: ActionGroupItemRenderProps,
|
|
219
|
+
) => JSX.Element
|
|
220
|
+
}
|
|
221
|
+
/>
|
|
222
|
+
)}
|
|
223
|
+
</For>
|
|
224
|
+
</div>
|
|
225
|
+
</ActionGroupStateContext.Provider>
|
|
226
|
+
</ActionGroupContext.Provider>
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
interface ActionGroupItemWrapperProps {
|
|
231
|
+
item: ActionGroupItem;
|
|
232
|
+
state: ListState<ActionGroupItem>;
|
|
233
|
+
renderChild: (item: ActionGroupItem, renderProps: ActionGroupItemRenderProps) => JSX.Element;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function ActionGroupItemWrapper(props: ActionGroupItemWrapperProps): JSX.Element {
|
|
237
|
+
const { buttonProps } = createActionGroupItem(
|
|
238
|
+
{
|
|
239
|
+
get key() {
|
|
240
|
+
return props.item.id;
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
props.state,
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
const isFocused = () => props.state.focusedKey() === props.item.id;
|
|
247
|
+
const isSelected = () => {
|
|
248
|
+
const keys = props.state.selectedKeys();
|
|
249
|
+
return keys === "all" || (keys instanceof Set && keys.has(props.item.id));
|
|
250
|
+
};
|
|
251
|
+
const isDisabled = () => props.state.isDisabled(props.item.id);
|
|
252
|
+
|
|
253
|
+
const renderProps = createMemo<ActionGroupItemRenderProps>(() => ({
|
|
254
|
+
isSelected: isSelected(),
|
|
255
|
+
isDisabled: isDisabled(),
|
|
256
|
+
isFocused: isFocused(),
|
|
257
|
+
}));
|
|
258
|
+
|
|
259
|
+
const { ref: _ref, ...restButtonProps } = buttonProps as Record<string, unknown> & {
|
|
260
|
+
ref?: unknown;
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
return (
|
|
264
|
+
<button
|
|
265
|
+
{...restButtonProps}
|
|
266
|
+
data-selected={isSelected() || undefined}
|
|
267
|
+
data-disabled={isDisabled() || undefined}
|
|
268
|
+
data-focused={isFocused() || undefined}
|
|
269
|
+
>
|
|
270
|
+
{props.renderChild(props.item, renderProps())}
|
|
271
|
+
</button>
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export function useActionGroupContext(): ActionGroupContextValue | null {
|
|
276
|
+
return useContext(ActionGroupContext);
|
|
277
|
+
}
|
package/src/Alert.tsx
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alert component for solidaria-components
|
|
3
|
+
*
|
|
4
|
+
* Minimal headless Alert that owns ARIA semantics (role="alert")
|
|
5
|
+
* and provides render props for styling. The UI layer consumes this
|
|
6
|
+
* for styling/composition only.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { type JSX, createContext, createMemo, splitProps, useContext } from "solid-js";
|
|
10
|
+
import {
|
|
11
|
+
type RenderChildren,
|
|
12
|
+
type ClassNameOrFunction,
|
|
13
|
+
type StyleOrFunction,
|
|
14
|
+
type SlotProps,
|
|
15
|
+
filterDOMProps,
|
|
16
|
+
} from "./utils";
|
|
17
|
+
import { Button, type ButtonProps } from "./Button";
|
|
18
|
+
|
|
19
|
+
export type AlertVariant = "info" | "success" | "warning" | "error";
|
|
20
|
+
|
|
21
|
+
export interface AlertRenderProps {
|
|
22
|
+
/** The variant of the alert. */
|
|
23
|
+
variant: AlertVariant;
|
|
24
|
+
/** Whether the alert can be dismissed. */
|
|
25
|
+
isDismissible: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface AlertProps extends SlotProps {
|
|
29
|
+
/** The variant of the alert. */
|
|
30
|
+
variant?: AlertVariant;
|
|
31
|
+
/** Whether the alert can be dismissed. */
|
|
32
|
+
isDismissible?: boolean;
|
|
33
|
+
/** Handler called when the alert is dismissed. */
|
|
34
|
+
onDismiss?: () => void;
|
|
35
|
+
/** The children of the component. A function may be provided to receive render props. */
|
|
36
|
+
children?: RenderChildren<AlertRenderProps>;
|
|
37
|
+
/** The CSS className for the element. */
|
|
38
|
+
class?: ClassNameOrFunction<AlertRenderProps>;
|
|
39
|
+
/** The inline style for the element. */
|
|
40
|
+
style?: StyleOrFunction<AlertRenderProps>;
|
|
41
|
+
/** The id of the element. */
|
|
42
|
+
id?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface AlertContextValue {
|
|
46
|
+
variant: () => AlertVariant;
|
|
47
|
+
isDismissible: () => boolean;
|
|
48
|
+
onDismiss?: () => void;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const AlertContext = createContext<AlertContextValue | null>(null);
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* An alert displays a brief, important message in a way that
|
|
55
|
+
* attracts the user's attention without interrupting their task.
|
|
56
|
+
*
|
|
57
|
+
* This is a headless component that provides the ARIA `role="alert"`
|
|
58
|
+
* semantics and render props for styling.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```tsx
|
|
62
|
+
* <Alert variant="error" isDismissible onDismiss={() => setVisible(false)}>
|
|
63
|
+
* {({ variant }) => <span>Something went wrong ({variant})</span>}
|
|
64
|
+
* </Alert>
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export function Alert(props: AlertProps): JSX.Element {
|
|
68
|
+
const [local, rest] = splitProps(props, [
|
|
69
|
+
"children",
|
|
70
|
+
"class",
|
|
71
|
+
"style",
|
|
72
|
+
"slot",
|
|
73
|
+
"variant",
|
|
74
|
+
"isDismissible",
|
|
75
|
+
"onDismiss",
|
|
76
|
+
]);
|
|
77
|
+
|
|
78
|
+
const variant = () => local.variant ?? "info";
|
|
79
|
+
const isDismissible = () => !!local.isDismissible;
|
|
80
|
+
|
|
81
|
+
const renderValues = createMemo<AlertRenderProps>(() => ({
|
|
82
|
+
variant: variant(),
|
|
83
|
+
isDismissible: isDismissible(),
|
|
84
|
+
}));
|
|
85
|
+
|
|
86
|
+
// Resolve class and style manually. We intentionally avoid useRenderProps()
|
|
87
|
+
// because it destructures children eagerly, which would create child
|
|
88
|
+
// components (e.g. AlertDismissButton) BEFORE the AlertContext.Provider
|
|
89
|
+
// is in scope, breaking context for sub-components.
|
|
90
|
+
const computedClass = createMemo(() => {
|
|
91
|
+
const cls = local.class;
|
|
92
|
+
return typeof cls === "function" ? cls(renderValues()) : (cls ?? "solidaria-Alert");
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const computedStyle = createMemo(() => {
|
|
96
|
+
const s = local.style;
|
|
97
|
+
return typeof s === "function" ? s(renderValues()) : s;
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const domProps = createMemo(() => filterDOMProps(rest, { global: true }));
|
|
101
|
+
|
|
102
|
+
const contextValue: AlertContextValue = {
|
|
103
|
+
variant,
|
|
104
|
+
isDismissible,
|
|
105
|
+
onDismiss: local.onDismiss,
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// Children are accessed lazily inside the Provider scope (via local.children
|
|
109
|
+
// in JSX) so sub-components like AlertDismissButton can read AlertContext.
|
|
110
|
+
return (
|
|
111
|
+
<AlertContext.Provider value={contextValue}>
|
|
112
|
+
<div
|
|
113
|
+
{...domProps()}
|
|
114
|
+
role="alert"
|
|
115
|
+
class={computedClass()}
|
|
116
|
+
style={computedStyle()}
|
|
117
|
+
data-variant={variant()}
|
|
118
|
+
data-dismissible={isDismissible() || undefined}
|
|
119
|
+
>
|
|
120
|
+
{typeof local.children === "function"
|
|
121
|
+
? (local.children as (props: AlertRenderProps) => JSX.Element)(renderValues())
|
|
122
|
+
: local.children}
|
|
123
|
+
</div>
|
|
124
|
+
</AlertContext.Provider>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface AlertDismissButtonProps extends Omit<ButtonProps, "onPress"> {}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* A dismiss button for use inside an Alert.
|
|
132
|
+
* Uses the headless Button for full keyboard/a11y support.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```tsx
|
|
136
|
+
* <Alert isDismissible onDismiss={handleDismiss}>
|
|
137
|
+
* <span>Alert content</span>
|
|
138
|
+
* <AlertDismissButton aria-label="Dismiss">X</AlertDismissButton>
|
|
139
|
+
* </Alert>
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
export function AlertDismissButton(props: AlertDismissButtonProps): JSX.Element {
|
|
143
|
+
const context = useContext(AlertContext);
|
|
144
|
+
|
|
145
|
+
return (
|
|
146
|
+
<Button
|
|
147
|
+
{...props}
|
|
148
|
+
aria-label={props["aria-label"] ?? "Dismiss"}
|
|
149
|
+
onPress={() => context?.onDismiss?.()}
|
|
150
|
+
/>
|
|
151
|
+
);
|
|
152
|
+
}
|
package/src/Autocomplete.tsx
CHANGED
|
@@ -15,62 +15,56 @@ import {
|
|
|
15
15
|
createMemo,
|
|
16
16
|
splitProps,
|
|
17
17
|
createSignal,
|
|
18
|
-
} from
|
|
18
|
+
} from "solid-js";
|
|
19
19
|
import {
|
|
20
20
|
createAutocomplete,
|
|
21
21
|
type AriaAutocompleteOptions,
|
|
22
22
|
type AutocompleteInputProps,
|
|
23
23
|
type CollectionOptions,
|
|
24
|
-
} from
|
|
24
|
+
} from "@proyecto-viviana/solidaria";
|
|
25
25
|
import {
|
|
26
26
|
createAutocompleteState,
|
|
27
27
|
type AutocompleteState,
|
|
28
28
|
type AutocompleteStateOptions,
|
|
29
|
-
} from
|
|
30
|
-
import { type SlotProps } from
|
|
31
|
-
|
|
32
|
-
// ============================================
|
|
33
|
-
// TYPES
|
|
34
|
-
// ============================================
|
|
29
|
+
} from "@proyecto-viviana/solid-stately";
|
|
30
|
+
import { type SlotProps } from "./utils";
|
|
35
31
|
|
|
36
32
|
export interface AutocompleteProps<T = unknown>
|
|
37
|
-
extends
|
|
38
|
-
Omit<
|
|
33
|
+
extends
|
|
34
|
+
Omit<AutocompleteStateOptions, "children">,
|
|
35
|
+
Omit<AriaAutocompleteOptions<T>, "inputRef" | "collectionRef">,
|
|
39
36
|
ParentProps,
|
|
40
37
|
SlotProps {}
|
|
41
38
|
|
|
42
|
-
// ============================================
|
|
43
|
-
// CONTEXTS
|
|
44
|
-
// ============================================
|
|
45
|
-
|
|
46
39
|
export interface AutocompleteContextValue {
|
|
47
|
-
inputProps: AutocompleteInputProps
|
|
48
|
-
inputRef: (el: HTMLInputElement) => void
|
|
40
|
+
inputProps: AutocompleteInputProps;
|
|
41
|
+
inputRef: (el: HTMLInputElement) => void;
|
|
49
42
|
}
|
|
50
43
|
|
|
51
44
|
export interface AutocompleteCollectionContextValue {
|
|
52
|
-
collectionProps: CollectionOptions
|
|
53
|
-
collectionRef: (el: HTMLElement) => void
|
|
54
|
-
filter?: (textValue: string) => boolean
|
|
45
|
+
collectionProps: CollectionOptions;
|
|
46
|
+
collectionRef: (el: HTMLElement) => void;
|
|
47
|
+
filter?: (textValue: string) => boolean;
|
|
55
48
|
}
|
|
56
49
|
|
|
57
|
-
export const AutocompleteContext = createContext<AutocompleteContextValue | null>(null)
|
|
58
|
-
export const AutocompleteStateContext = createContext<AutocompleteState | null>(null)
|
|
59
|
-
export const AutocompleteCollectionContext =
|
|
50
|
+
export const AutocompleteContext = createContext<AutocompleteContextValue | null>(null);
|
|
51
|
+
export const AutocompleteStateContext = createContext<AutocompleteState | null>(null);
|
|
52
|
+
export const AutocompleteCollectionContext =
|
|
53
|
+
createContext<AutocompleteCollectionContextValue | null>(null);
|
|
60
54
|
|
|
61
55
|
/**
|
|
62
56
|
* Hook to consume autocomplete input context.
|
|
63
57
|
* Use this in your input component (TextField/SearchField) to get the autocomplete props.
|
|
64
58
|
*/
|
|
65
59
|
export function useAutocompleteInput() {
|
|
66
|
-
return useContext(AutocompleteContext)
|
|
60
|
+
return useContext(AutocompleteContext);
|
|
67
61
|
}
|
|
68
62
|
|
|
69
63
|
/**
|
|
70
64
|
* Hook to consume autocomplete state context.
|
|
71
65
|
*/
|
|
72
66
|
export function useAutocompleteState() {
|
|
73
|
-
return useContext(AutocompleteStateContext)
|
|
67
|
+
return useContext(AutocompleteStateContext);
|
|
74
68
|
}
|
|
75
69
|
|
|
76
70
|
/**
|
|
@@ -78,13 +72,9 @@ export function useAutocompleteState() {
|
|
|
78
72
|
* Use this in your collection component (ListBox/Menu) to get the autocomplete props.
|
|
79
73
|
*/
|
|
80
74
|
export function useAutocompleteCollection() {
|
|
81
|
-
return useContext(AutocompleteCollectionContext)
|
|
75
|
+
return useContext(AutocompleteCollectionContext);
|
|
82
76
|
}
|
|
83
77
|
|
|
84
|
-
// ============================================
|
|
85
|
-
// AUTOCOMPLETE COMPONENT
|
|
86
|
-
// ============================================
|
|
87
|
-
|
|
88
78
|
/**
|
|
89
79
|
* An autocomplete allows users to search or filter a list of suggestions.
|
|
90
80
|
* It wraps a text input and a collection component (ListBox or Menu),
|
|
@@ -124,16 +114,21 @@ export function useAutocompleteCollection() {
|
|
|
124
114
|
export function Autocomplete<T = unknown>(props: AutocompleteProps<T>): JSX.Element {
|
|
125
115
|
const [stateProps, ariaProps, local] = splitProps(
|
|
126
116
|
props,
|
|
127
|
-
[
|
|
128
|
-
[
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
117
|
+
["inputValue", "defaultInputValue", "onInputChange"],
|
|
118
|
+
[
|
|
119
|
+
"filter",
|
|
120
|
+
"disableAutoFocusFirst",
|
|
121
|
+
"disableVirtualFocus",
|
|
122
|
+
"collectionId",
|
|
123
|
+
"collectionAriaLabel",
|
|
124
|
+
],
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
const state = createAutocompleteState(stateProps);
|
|
133
128
|
|
|
134
129
|
// Create refs
|
|
135
|
-
let inputRef: HTMLInputElement | undefined
|
|
136
|
-
let collectionRef: HTMLElement | undefined
|
|
130
|
+
let inputRef: HTMLInputElement | undefined;
|
|
131
|
+
let collectionRef: HTMLElement | undefined;
|
|
137
132
|
|
|
138
133
|
// Create autocomplete aria
|
|
139
134
|
const autocomplete = createAutocomplete<T>(
|
|
@@ -142,25 +137,25 @@ export function Autocomplete<T = unknown>(props: AutocompleteProps<T>): JSX.Elem
|
|
|
142
137
|
inputRef: () => inputRef,
|
|
143
138
|
collectionRef: () => collectionRef,
|
|
144
139
|
},
|
|
145
|
-
state
|
|
146
|
-
)
|
|
140
|
+
state,
|
|
141
|
+
);
|
|
147
142
|
|
|
148
143
|
// Input context value
|
|
149
144
|
const inputContextValue = createMemo<AutocompleteContextValue>(() => ({
|
|
150
145
|
inputProps: autocomplete.inputProps,
|
|
151
146
|
inputRef: (el: HTMLInputElement) => {
|
|
152
|
-
inputRef = el
|
|
147
|
+
inputRef = el;
|
|
153
148
|
},
|
|
154
|
-
}))
|
|
149
|
+
}));
|
|
155
150
|
|
|
156
151
|
// Collection context value
|
|
157
152
|
const collectionContextValue = createMemo<AutocompleteCollectionContextValue>(() => ({
|
|
158
153
|
collectionProps: autocomplete.collectionProps,
|
|
159
154
|
collectionRef: (el: HTMLElement) => {
|
|
160
|
-
collectionRef = el
|
|
155
|
+
collectionRef = el;
|
|
161
156
|
},
|
|
162
157
|
filter: autocomplete.filter,
|
|
163
|
-
}))
|
|
158
|
+
}));
|
|
164
159
|
|
|
165
160
|
return (
|
|
166
161
|
<AutocompleteStateContext.Provider value={state}>
|
|
@@ -170,5 +165,5 @@ export function Autocomplete<T = unknown>(props: AutocompleteProps<T>): JSX.Elem
|
|
|
170
165
|
</AutocompleteCollectionContext.Provider>
|
|
171
166
|
</AutocompleteContext.Provider>
|
|
172
167
|
</AutocompleteStateContext.Provider>
|
|
173
|
-
)
|
|
168
|
+
);
|
|
174
169
|
}
|