@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.
Files changed (225) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +39 -272
  3. package/dist/ActionBar.d.ts +79 -0
  4. package/dist/ActionBar.d.ts.map +1 -0
  5. package/dist/ActionGroup.d.ts +74 -0
  6. package/dist/ActionGroup.d.ts.map +1 -0
  7. package/dist/Alert.d.ts +70 -0
  8. package/dist/Alert.d.ts.map +1 -0
  9. package/dist/Autocomplete.d.ts +5 -5
  10. package/dist/Autocomplete.d.ts.map +1 -1
  11. package/dist/Breadcrumbs.d.ts +27 -8
  12. package/dist/Breadcrumbs.d.ts.map +1 -1
  13. package/dist/Button.d.ts +28 -5
  14. package/dist/Button.d.ts.map +1 -1
  15. package/dist/Calendar.d.ts +51 -7
  16. package/dist/Calendar.d.ts.map +1 -1
  17. package/dist/Checkbox.d.ts +33 -8
  18. package/dist/Checkbox.d.ts.map +1 -1
  19. package/dist/Collection.d.ts +130 -0
  20. package/dist/Collection.d.ts.map +1 -0
  21. package/dist/Color.d.ts +210 -9
  22. package/dist/Color.d.ts.map +1 -1
  23. package/dist/ColorEditor.d.ts +42 -0
  24. package/dist/ColorEditor.d.ts.map +1 -0
  25. package/dist/ComboBox.d.ts +146 -16
  26. package/dist/ComboBox.d.ts.map +1 -1
  27. package/dist/ContextualHelpTrigger.d.ts +40 -0
  28. package/dist/ContextualHelpTrigger.d.ts.map +1 -0
  29. package/dist/DateField.d.ts +35 -8
  30. package/dist/DateField.d.ts.map +1 -1
  31. package/dist/DatePicker.d.ts +101 -5
  32. package/dist/DatePicker.d.ts.map +1 -1
  33. package/dist/DateRangePickerContext.d.ts +30 -0
  34. package/dist/DateRangePickerContext.d.ts.map +1 -0
  35. package/dist/Dialog.d.ts +5 -5
  36. package/dist/Dialog.d.ts.map +1 -1
  37. package/dist/Disclosure.d.ts +25 -5
  38. package/dist/Disclosure.d.ts.map +1 -1
  39. package/dist/DragAndDrop.d.ts +80 -0
  40. package/dist/DragAndDrop.d.ts.map +1 -0
  41. package/dist/DragPreview.d.ts +14 -0
  42. package/dist/DragPreview.d.ts.map +1 -0
  43. package/dist/DropZone.d.ts +27 -0
  44. package/dist/DropZone.d.ts.map +1 -0
  45. package/dist/FieldError.d.ts +27 -0
  46. package/dist/FieldError.d.ts.map +1 -0
  47. package/dist/FileTrigger.d.ts +26 -0
  48. package/dist/FileTrigger.d.ts.map +1 -0
  49. package/dist/Focusable.d.ts +27 -0
  50. package/dist/Focusable.d.ts.map +1 -0
  51. package/dist/Form.d.ts +41 -0
  52. package/dist/Form.d.ts.map +1 -0
  53. package/dist/GridList.d.ts +69 -10
  54. package/dist/GridList.d.ts.map +1 -1
  55. package/dist/HiddenDateInput.d.ts +26 -0
  56. package/dist/HiddenDateInput.d.ts.map +1 -0
  57. package/dist/HiddenTimeInput.d.ts +25 -0
  58. package/dist/HiddenTimeInput.d.ts.map +1 -0
  59. package/dist/Icon.d.ts +57 -0
  60. package/dist/Icon.d.ts.map +1 -0
  61. package/dist/Keyboard.d.ts +13 -0
  62. package/dist/Keyboard.d.ts.map +1 -0
  63. package/dist/Landmark.d.ts +3 -3
  64. package/dist/Landmark.d.ts.map +1 -1
  65. package/dist/Link.d.ts +10 -4
  66. package/dist/Link.d.ts.map +1 -1
  67. package/dist/ListBox.d.ts +73 -11
  68. package/dist/ListBox.d.ts.map +1 -1
  69. package/dist/ListDropTargetDelegate.d.ts +38 -0
  70. package/dist/ListDropTargetDelegate.d.ts.map +1 -0
  71. package/dist/Menu.d.ts +79 -10
  72. package/dist/Menu.d.ts.map +1 -1
  73. package/dist/Meter.d.ts +4 -4
  74. package/dist/Meter.d.ts.map +1 -1
  75. package/dist/Modal.d.ts +6 -4
  76. package/dist/Modal.d.ts.map +1 -1
  77. package/dist/NumberField.d.ts +10 -12
  78. package/dist/NumberField.d.ts.map +1 -1
  79. package/dist/Popover.d.ts +32 -7
  80. package/dist/Popover.d.ts.map +1 -1
  81. package/dist/Pressable.d.ts +27 -0
  82. package/dist/Pressable.d.ts.map +1 -0
  83. package/dist/ProgressBar.d.ts +6 -4
  84. package/dist/ProgressBar.d.ts.map +1 -1
  85. package/dist/RadioGroup.d.ts +43 -9
  86. package/dist/RadioGroup.d.ts.map +1 -1
  87. package/dist/RangeCalendar.d.ts +39 -7
  88. package/dist/RangeCalendar.d.ts.map +1 -1
  89. package/dist/RouterProvider.d.ts +75 -0
  90. package/dist/RouterProvider.d.ts.map +1 -0
  91. package/dist/SearchField.d.ts +23 -21
  92. package/dist/SearchField.d.ts.map +1 -1
  93. package/dist/Select.d.ts +48 -7
  94. package/dist/Select.d.ts.map +1 -1
  95. package/dist/SelectionIndicator.d.ts +30 -0
  96. package/dist/SelectionIndicator.d.ts.map +1 -0
  97. package/dist/Separator.d.ts +9 -3
  98. package/dist/Separator.d.ts.map +1 -1
  99. package/dist/SharedElementTransition.d.ts +41 -0
  100. package/dist/SharedElementTransition.d.ts.map +1 -0
  101. package/dist/Slider.d.ts +15 -8
  102. package/dist/Slider.d.ts.map +1 -1
  103. package/dist/StepList.d.ts +90 -0
  104. package/dist/StepList.d.ts.map +1 -0
  105. package/dist/Switch.d.ts +11 -5
  106. package/dist/Switch.d.ts.map +1 -1
  107. package/dist/Table.d.ts +222 -19
  108. package/dist/Table.d.ts.map +1 -1
  109. package/dist/Tabs.d.ts +47 -10
  110. package/dist/Tabs.d.ts.map +1 -1
  111. package/dist/TagGroup.d.ts +22 -10
  112. package/dist/TagGroup.d.ts.map +1 -1
  113. package/dist/Text.d.ts +10 -0
  114. package/dist/Text.d.ts.map +1 -0
  115. package/dist/TextField.d.ts +19 -11
  116. package/dist/TextField.d.ts.map +1 -1
  117. package/dist/TimeField.d.ts +32 -7
  118. package/dist/TimeField.d.ts.map +1 -1
  119. package/dist/Toast.d.ts +29 -14
  120. package/dist/Toast.d.ts.map +1 -1
  121. package/dist/ToggleButton.d.ts +36 -0
  122. package/dist/ToggleButton.d.ts.map +1 -0
  123. package/dist/ToggleButtonGroup.d.ts +33 -0
  124. package/dist/ToggleButtonGroup.d.ts.map +1 -0
  125. package/dist/Toolbar.d.ts +7 -3
  126. package/dist/Toolbar.d.ts.map +1 -1
  127. package/dist/Tooltip.d.ts +58 -7
  128. package/dist/Tooltip.d.ts.map +1 -1
  129. package/dist/Tree.d.ts +102 -11
  130. package/dist/Tree.d.ts.map +1 -1
  131. package/dist/Virtualizer.d.ts +61 -0
  132. package/dist/Virtualizer.d.ts.map +1 -0
  133. package/dist/VirtualizerLayouts.d.ts +82 -0
  134. package/dist/VirtualizerLayouts.d.ts.map +1 -0
  135. package/dist/VisuallyHidden.d.ts +4 -2
  136. package/dist/VisuallyHidden.d.ts.map +1 -1
  137. package/dist/contexts.d.ts +6 -1
  138. package/dist/contexts.d.ts.map +1 -1
  139. package/dist/index.d.ts +73 -39
  140. package/dist/index.d.ts.map +1 -1
  141. package/dist/index.js +23342 -10644
  142. package/dist/index.js.map +1 -7
  143. package/dist/index.jsx +18110 -0
  144. package/dist/index.jsx.map +1 -0
  145. package/dist/useDragAndDrop.d.ts +93 -0
  146. package/dist/useDragAndDrop.d.ts.map +1 -0
  147. package/dist/utils.d.ts +8 -2
  148. package/dist/utils.d.ts.map +1 -1
  149. package/dist/virtualizer/Layout.d.ts +79 -0
  150. package/dist/virtualizer/Layout.d.ts.map +1 -0
  151. package/package.json +33 -32
  152. package/src/ActionBar.tsx +251 -0
  153. package/src/ActionGroup.tsx +277 -0
  154. package/src/Alert.tsx +152 -0
  155. package/src/Autocomplete.tsx +39 -44
  156. package/src/Breadcrumbs.tsx +227 -72
  157. package/src/Button.tsx +315 -74
  158. package/src/Calendar.tsx +347 -141
  159. package/src/Checkbox.tsx +414 -123
  160. package/src/Collection.tsx +350 -0
  161. package/src/Color.tsx +1325 -284
  162. package/src/ColorEditor.tsx +213 -0
  163. package/src/ComboBox.tsx +644 -245
  164. package/src/ContextualHelpTrigger.tsx +195 -0
  165. package/src/DateField.tsx +274 -106
  166. package/src/DatePicker.tsx +892 -111
  167. package/src/DateRangePickerContext.tsx +44 -0
  168. package/src/Dialog.tsx +173 -104
  169. package/src/Disclosure.tsx +158 -105
  170. package/src/DragAndDrop.tsx +340 -0
  171. package/src/DragPreview.tsx +47 -0
  172. package/src/DropZone.tsx +233 -0
  173. package/src/FieldError.tsx +89 -0
  174. package/src/FileTrigger.tsx +83 -0
  175. package/src/Focusable.tsx +103 -0
  176. package/src/Form.tsx +140 -0
  177. package/src/GridList.tsx +542 -128
  178. package/src/HiddenDateInput.tsx +153 -0
  179. package/src/HiddenTimeInput.tsx +133 -0
  180. package/src/Icon.tsx +133 -0
  181. package/src/Keyboard.tsx +26 -0
  182. package/src/Landmark.tsx +37 -63
  183. package/src/Link.tsx +132 -69
  184. package/src/ListBox.tsx +656 -106
  185. package/src/ListDropTargetDelegate.ts +283 -0
  186. package/src/Menu.tsx +1234 -132
  187. package/src/Meter.tsx +44 -58
  188. package/src/Modal.tsx +262 -166
  189. package/src/NumberField.tsx +267 -151
  190. package/src/Popover.tsx +452 -343
  191. package/src/Pressable.tsx +108 -0
  192. package/src/ProgressBar.tsx +54 -59
  193. package/src/RadioGroup.tsx +533 -121
  194. package/src/RangeCalendar.tsx +249 -150
  195. package/src/RouterProvider.tsx +223 -0
  196. package/src/SearchField.tsx +460 -133
  197. package/src/Select.tsx +804 -233
  198. package/src/SelectionIndicator.tsx +108 -0
  199. package/src/Separator.tsx +47 -49
  200. package/src/SharedElementTransition.tsx +264 -0
  201. package/src/Slider.tsx +148 -98
  202. package/src/StepList.tsx +272 -0
  203. package/src/Switch.tsx +93 -46
  204. package/src/Table.tsx +1551 -225
  205. package/src/Tabs.tsx +377 -123
  206. package/src/TagGroup.tsx +233 -135
  207. package/src/Text.tsx +18 -0
  208. package/src/TextField.tsx +413 -86
  209. package/src/TimeField.tsx +232 -222
  210. package/src/Toast.tsx +306 -160
  211. package/src/ToggleButton.tsx +169 -0
  212. package/src/ToggleButtonGroup.tsx +141 -0
  213. package/src/Toolbar.tsx +61 -70
  214. package/src/Tooltip.tsx +473 -116
  215. package/src/Tree.tsx +1514 -175
  216. package/src/Virtualizer.tsx +730 -0
  217. package/src/VirtualizerLayouts.ts +280 -0
  218. package/src/VisuallyHidden.tsx +32 -38
  219. package/src/contexts.ts +29 -36
  220. package/src/index.ts +972 -620
  221. package/src/useDragAndDrop.ts +367 -0
  222. package/src/utils.tsx +69 -50
  223. package/src/virtualizer/Layout.ts +192 -0
  224. package/dist/index.ssr.js +0 -9785
  225. 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
+ }
@@ -15,62 +15,56 @@ import {
15
15
  createMemo,
16
16
  splitProps,
17
17
  createSignal,
18
- } from 'solid-js'
18
+ } from "solid-js";
19
19
  import {
20
20
  createAutocomplete,
21
21
  type AriaAutocompleteOptions,
22
22
  type AutocompleteInputProps,
23
23
  type CollectionOptions,
24
- } from '@proyecto-viviana/solidaria'
24
+ } from "@proyecto-viviana/solidaria";
25
25
  import {
26
26
  createAutocompleteState,
27
27
  type AutocompleteState,
28
28
  type AutocompleteStateOptions,
29
- } from '@proyecto-viviana/solid-stately'
30
- import { type SlotProps } from './utils'
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 Omit<AutocompleteStateOptions, 'children'>,
38
- Omit<AriaAutocompleteOptions<T>, 'inputRef' | 'collectionRef'>,
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 = createContext<AutocompleteCollectionContextValue | null>(null)
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
- ['inputValue', 'defaultInputValue', 'onInputChange'],
128
- ['filter', 'disableAutoFocusFirst', 'disableVirtualFocus']
129
- )
130
-
131
- // Create state
132
- const state = createAutocompleteState(stateProps)
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
  }