@proyecto-viviana/solidaria-components 0.1.3 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/Color.d.ts +6 -2
  2. package/dist/Color.d.ts.map +1 -1
  3. package/dist/ComboBox.d.ts +3 -3
  4. package/dist/ComboBox.d.ts.map +1 -1
  5. package/dist/GridList.d.ts +2 -2
  6. package/dist/GridList.d.ts.map +1 -1
  7. package/dist/ListBox.d.ts +5 -5
  8. package/dist/ListBox.d.ts.map +1 -1
  9. package/dist/Menu.d.ts +3 -3
  10. package/dist/Menu.d.ts.map +1 -1
  11. package/dist/Select.d.ts +3 -3
  12. package/dist/Select.d.ts.map +1 -1
  13. package/dist/Table.d.ts +2 -2
  14. package/dist/Table.d.ts.map +1 -1
  15. package/dist/Tabs.d.ts +1 -1
  16. package/dist/Tabs.d.ts.map +1 -1
  17. package/dist/index.js +15 -15
  18. package/dist/index.js.map +2 -2
  19. package/dist/index.jsx +9056 -0
  20. package/dist/index.jsx.map +7 -0
  21. package/dist/index.ssr.js +15 -15
  22. package/dist/index.ssr.js.map +2 -2
  23. package/package.json +8 -10
  24. package/src/Autocomplete.tsx +0 -174
  25. package/src/Breadcrumbs.tsx +0 -264
  26. package/src/Button.tsx +0 -238
  27. package/src/Calendar.tsx +0 -471
  28. package/src/Checkbox.tsx +0 -387
  29. package/src/Color.tsx +0 -1370
  30. package/src/ComboBox.tsx +0 -824
  31. package/src/DateField.tsx +0 -337
  32. package/src/DatePicker.tsx +0 -367
  33. package/src/Dialog.tsx +0 -262
  34. package/src/Disclosure.tsx +0 -439
  35. package/src/GridList.tsx +0 -511
  36. package/src/Landmark.tsx +0 -203
  37. package/src/Link.tsx +0 -201
  38. package/src/ListBox.tsx +0 -346
  39. package/src/Menu.tsx +0 -544
  40. package/src/Meter.tsx +0 -157
  41. package/src/Modal.tsx +0 -433
  42. package/src/NumberField.tsx +0 -542
  43. package/src/Popover.tsx +0 -540
  44. package/src/ProgressBar.tsx +0 -162
  45. package/src/RadioGroup.tsx +0 -356
  46. package/src/RangeCalendar.tsx +0 -462
  47. package/src/SearchField.tsx +0 -479
  48. package/src/Select.tsx +0 -734
  49. package/src/Separator.tsx +0 -130
  50. package/src/Slider.tsx +0 -500
  51. package/src/Switch.tsx +0 -213
  52. package/src/Table.tsx +0 -857
  53. package/src/Tabs.tsx +0 -552
  54. package/src/TagGroup.tsx +0 -421
  55. package/src/TextField.tsx +0 -271
  56. package/src/TimeField.tsx +0 -455
  57. package/src/Toast.tsx +0 -503
  58. package/src/Toolbar.tsx +0 -160
  59. package/src/Tooltip.tsx +0 -423
  60. package/src/Tree.tsx +0 -551
  61. package/src/VisuallyHidden.tsx +0 -60
  62. package/src/contexts.ts +0 -74
  63. package/src/index.ts +0 -620
  64. package/src/utils.tsx +0 -329
package/src/TagGroup.tsx DELETED
@@ -1,421 +0,0 @@
1
- /**
2
- * TagGroup component for solidaria-components
3
- *
4
- * Pre-wired headless tag group component that combines aria hooks.
5
- * Port of react-aria-components/src/TagGroup.tsx
6
- *
7
- * A tag group is a focusable list of labels, categories, keywords, filters, or other items,
8
- * with support for keyboard navigation, selection, and removal.
9
- */
10
-
11
- import {
12
- type JSX,
13
- createContext,
14
- createMemo,
15
- createSignal,
16
- splitProps,
17
- useContext,
18
- For,
19
- Show,
20
- } from 'solid-js';
21
- import {
22
- createTagGroup,
23
- createTag,
24
- type AriaTagGroupProps,
25
- } from '@proyecto-viviana/solidaria';
26
- import {
27
- createListState,
28
- type ListState,
29
- type Key,
30
- type SelectionMode,
31
- type SelectionBehavior,
32
- } from '@proyecto-viviana/solid-stately';
33
- import {
34
- type RenderChildren,
35
- type ClassNameOrFunction,
36
- type StyleOrFunction,
37
- type SlotProps,
38
- useRenderProps,
39
- filterDOMProps,
40
- dataAttr,
41
- } from './utils';
42
-
43
- // ============================================
44
- // TYPES
45
- // ============================================
46
-
47
- export interface TagGroupRenderProps {
48
- /** Whether the tag group is disabled. */
49
- isDisabled: boolean;
50
- /** Whether the tag list is empty. */
51
- isEmpty: boolean;
52
- }
53
-
54
- export interface TagGroupProps
55
- extends Omit<AriaTagGroupProps, 'id'>,
56
- SlotProps {
57
- /** The children of the component. */
58
- children?: JSX.Element;
59
- /** The CSS className for the element. */
60
- class?: ClassNameOrFunction<TagGroupRenderProps>;
61
- /** The inline style for the element. */
62
- style?: StyleOrFunction<TagGroupRenderProps>;
63
- }
64
-
65
- export interface TagListRenderProps {
66
- /** Whether the tag list is empty. */
67
- isEmpty: boolean;
68
- /** Whether the tag list is focused. */
69
- isFocused: boolean;
70
- }
71
-
72
- export interface TagListProps<T> extends SlotProps {
73
- /** The items to display in the tag list. */
74
- items: T[];
75
- /** Function to render each item. */
76
- children: (item: T) => JSX.Element;
77
- /** The CSS className for the element. */
78
- class?: ClassNameOrFunction<TagListRenderProps>;
79
- /** The inline style for the element. */
80
- style?: StyleOrFunction<TagListRenderProps>;
81
- /** Content to render when the list is empty. */
82
- renderEmptyState?: () => JSX.Element;
83
- /** The selection mode for the tag list. */
84
- selectionMode?: SelectionMode;
85
- /** How selection behaves in the collection. */
86
- selectionBehavior?: SelectionBehavior;
87
- /** The currently selected keys (controlled). */
88
- selectedKeys?: Iterable<Key>;
89
- /** The default selected keys (uncontrolled). */
90
- defaultSelectedKeys?: Iterable<Key>;
91
- /** Handler called when selection changes. */
92
- onSelectionChange?: (keys: 'all' | Set<Key>) => void;
93
- /** Keys that are disabled. */
94
- disabledKeys?: Iterable<Key>;
95
- /** Function to get a unique key from an item. */
96
- getKey?: (item: T) => Key;
97
- /** Accessibility label. */
98
- label?: string;
99
- /** Custom aria-label. */
100
- 'aria-label'?: string;
101
- /** Reference to external label element. */
102
- 'aria-labelledby'?: string;
103
- /** Reference to description element. */
104
- 'aria-describedby'?: string;
105
- /** Whether the tag list is disabled. */
106
- isDisabled?: boolean;
107
- /** Handler called when tags are removed. */
108
- onRemove?: (keys: Set<Key>) => void;
109
- }
110
-
111
- export interface TagRenderProps {
112
- /** Whether the tag is selected. */
113
- isSelected: boolean;
114
- /** Whether the tag is disabled. */
115
- isDisabled: boolean;
116
- /** Whether the tag is focused. */
117
- isFocused: boolean;
118
- /** Whether the tag is pressed. */
119
- isPressed: boolean;
120
- /** Whether the tag allows removal. */
121
- allowsRemoving: boolean;
122
- /** The selection mode. */
123
- selectionMode: SelectionMode;
124
- }
125
-
126
- export interface TagProps extends SlotProps {
127
- /** A unique key for this tag. */
128
- id: Key;
129
- /** Whether the tag is disabled. */
130
- isDisabled?: boolean;
131
- /** A text value for accessibility. */
132
- textValue?: string;
133
- /** The children of the component. A function may be provided to receive render props. */
134
- children?: RenderChildren<TagRenderProps>;
135
- /** The CSS className for the element. */
136
- class?: ClassNameOrFunction<TagRenderProps>;
137
- /** The inline style for the element. */
138
- style?: StyleOrFunction<TagRenderProps>;
139
- }
140
-
141
- // ============================================
142
- // CONTEXT
143
- // ============================================
144
-
145
- interface TagGroupContextValue {
146
- state: ListState;
147
- onRemove?: (keys: Set<Key>) => void;
148
- }
149
-
150
- export const TagGroupContext = createContext<TagGroupContextValue | null>(null);
151
- export const TagListStateContext = createContext<ListState | null>(null);
152
-
153
- export function useTagGroupContext(): TagGroupContextValue | null {
154
- return useContext(TagGroupContext);
155
- }
156
-
157
- // ============================================
158
- // TAG GROUP COMPONENT
159
- // ============================================
160
-
161
- /**
162
- * A tag group is a focusable list of labels, categories, keywords, filters, or other items,
163
- * with support for keyboard navigation, selection, and removal.
164
- *
165
- * @example
166
- * ```tsx
167
- * <TagGroup label="Categories" onRemove={(keys) => removeItems(keys)}>
168
- * <TagList items={items}>
169
- * {(item) => <Tag id={item.id}>{item.name}</Tag>}
170
- * </TagList>
171
- * </TagGroup>
172
- * ```
173
- */
174
- export function TagGroup(props: TagGroupProps): JSX.Element {
175
- const [local] = splitProps(props, [
176
- 'class',
177
- 'style',
178
- 'slot',
179
- ]);
180
-
181
- // We need TagList to provide the state, so TagGroup just provides context
182
- return (
183
- <div
184
- class={typeof local.class === 'string' ? local.class : 'solidaria-TagGroup'}
185
- style={typeof local.style === 'object' ? local.style : undefined}
186
- slot={local.slot}
187
- >
188
- {props.children}
189
- </div>
190
- );
191
- }
192
-
193
- // ============================================
194
- // TAG LIST COMPONENT
195
- // ============================================
196
-
197
- /**
198
- * TagList contains the list of tags within a TagGroup.
199
- */
200
- export function TagList<T extends { id?: Key; key?: Key }>(props: TagListProps<T>): JSX.Element {
201
- const [local] = splitProps(props, [
202
- 'items',
203
- 'class',
204
- 'style',
205
- 'slot',
206
- 'renderEmptyState',
207
- 'selectionMode',
208
- 'selectionBehavior',
209
- 'selectedKeys',
210
- 'defaultSelectedKeys',
211
- 'onSelectionChange',
212
- 'disabledKeys',
213
- 'getKey',
214
- 'label',
215
- 'aria-label',
216
- 'aria-labelledby',
217
- 'aria-describedby',
218
- 'isDisabled',
219
- 'onRemove',
220
- ]);
221
-
222
- // Create a ref for the grid
223
- const [gridRef, setGridRef] = createSignal<HTMLDivElement | null>(null);
224
-
225
- // Default getKey function
226
- const getKey = (item: T): Key => {
227
- if (local.getKey) return local.getKey(item);
228
- if (item.id !== undefined) return item.id;
229
- if (item.key !== undefined) return item.key;
230
- return String(item);
231
- };
232
-
233
- // Create list state
234
- const state = createListState({
235
- get items() { return local.items; },
236
- getKey,
237
- get selectionMode() { return local.selectionMode ?? 'none'; },
238
- get selectionBehavior() { return local.selectionBehavior ?? 'toggle'; },
239
- get selectedKeys() { return local.selectedKeys; },
240
- get defaultSelectedKeys() { return local.defaultSelectedKeys; },
241
- get onSelectionChange() { return local.onSelectionChange; },
242
- get disabledKeys() { return local.disabledKeys; },
243
- });
244
-
245
- // Create tag group accessibility props
246
- const tagGroupAria = createTagGroup(
247
- {
248
- get label() { return local.label; },
249
- get 'aria-label'() { return local['aria-label']; },
250
- get 'aria-labelledby'() { return local['aria-labelledby']; },
251
- get 'aria-describedby'() { return local['aria-describedby']; },
252
- get isDisabled() { return local.isDisabled; },
253
- get onRemove() { return local.onRemove; },
254
- },
255
- state,
256
- gridRef
257
- );
258
-
259
- // Track focus
260
- const [isFocused, setIsFocused] = createSignal(false);
261
-
262
- // Render props values
263
- const renderValues = createMemo<TagListRenderProps>(() => ({
264
- isEmpty: local.items.length === 0,
265
- isFocused: isFocused(),
266
- }));
267
-
268
- // Resolve render props
269
- const renderProps = useRenderProps(
270
- {
271
- class: local.class,
272
- style: local.style,
273
- defaultClassName: 'solidaria-TagList',
274
- },
275
- renderValues
276
- );
277
-
278
- // Context value
279
- const contextValue: TagGroupContextValue = {
280
- state,
281
- get onRemove() { return local.onRemove; },
282
- };
283
-
284
- return (
285
- <TagGroupContext.Provider value={contextValue}>
286
- <TagListStateContext.Provider value={state}>
287
- <div
288
- ref={setGridRef}
289
- {...tagGroupAria.gridProps}
290
- class={renderProps.class()}
291
- style={renderProps.style()}
292
- onFocus={() => setIsFocused(true)}
293
- onBlur={() => setIsFocused(false)}
294
- data-empty={dataAttr(local.items.length === 0)}
295
- data-focused={dataAttr(isFocused())}
296
- >
297
- <Show
298
- when={local.items.length > 0}
299
- fallback={local.renderEmptyState?.()}
300
- >
301
- <For each={local.items}>
302
- {(item) => props.children(item)}
303
- </For>
304
- </Show>
305
- </div>
306
- </TagListStateContext.Provider>
307
- </TagGroupContext.Provider>
308
- );
309
- }
310
-
311
- // ============================================
312
- // TAG COMPONENT
313
- // ============================================
314
-
315
- /**
316
- * A Tag is an individual item within a TagList.
317
- */
318
- export function Tag(props: TagProps): JSX.Element {
319
- const [local, rest] = splitProps(props, [
320
- 'id',
321
- 'class',
322
- 'style',
323
- 'slot',
324
- 'isDisabled',
325
- 'textValue',
326
- ]);
327
-
328
- const state = useContext(TagListStateContext);
329
-
330
- // Create a ref for the tag
331
- const [tagRef, setTagRef] = createSignal<HTMLDivElement | null>(null);
332
-
333
- // Create tag accessibility props
334
- const tagAria = createTag(
335
- {
336
- get key() { return local.id; },
337
- get isDisabled() { return local.isDisabled; },
338
- get textValue() { return local.textValue; },
339
- },
340
- state!,
341
- tagRef
342
- );
343
-
344
- // Render props values
345
- const renderValues = createMemo<TagRenderProps>(() => ({
346
- isSelected: tagAria.isSelected,
347
- isDisabled: tagAria.isDisabled,
348
- isFocused: tagAria.isFocused,
349
- isPressed: tagAria.isPressed,
350
- allowsRemoving: tagAria.allowsRemoving,
351
- selectionMode: state?.selectionMode() ?? 'none',
352
- }));
353
-
354
- // Resolve render props
355
- const renderProps = useRenderProps(
356
- {
357
- children: props.children,
358
- class: local.class,
359
- style: local.style,
360
- defaultClassName: 'solidaria-Tag',
361
- },
362
- renderValues
363
- );
364
-
365
- // Filter DOM props
366
- const domProps = createMemo(() => filterDOMProps(rest, { global: true }));
367
-
368
- return (
369
- <div
370
- ref={setTagRef}
371
- {...domProps()}
372
- {...tagAria.rowProps}
373
- class={renderProps.class()}
374
- style={renderProps.style()}
375
- data-selected={dataAttr(tagAria.isSelected)}
376
- data-disabled={dataAttr(tagAria.isDisabled)}
377
- data-focused={dataAttr(tagAria.isFocused)}
378
- data-pressed={dataAttr(tagAria.isPressed)}
379
- data-allows-removing={dataAttr(tagAria.allowsRemoving)}
380
- >
381
- <div {...tagAria.gridCellProps} style={{ display: 'contents' }}>
382
- {renderProps.renderChildren()}
383
- </div>
384
- </div>
385
- );
386
- }
387
-
388
- // ============================================
389
- // TAG REMOVE BUTTON COMPONENT
390
- // ============================================
391
-
392
- export interface TagRemoveButtonProps {
393
- /** The children of the button (usually an X icon). */
394
- children?: JSX.Element;
395
- /** The CSS className for the element. */
396
- class?: string;
397
- /** The inline style for the element. */
398
- style?: JSX.CSSProperties;
399
- }
400
-
401
- /**
402
- * TagRemoveButton is the button used to remove a tag.
403
- * It should be placed inside a Tag component.
404
- */
405
- export function TagRemoveButton(props: TagRemoveButtonProps): JSX.Element {
406
- // This is a simplified version - in a full implementation,
407
- // we'd get the remove button props from the Tag context
408
- return (
409
- <button
410
- type="button"
411
- class={props.class ?? 'solidaria-TagRemoveButton'}
412
- style={props.style}
413
- aria-label="Remove"
414
- >
415
- {props.children ?? '×'}
416
- </button>
417
- );
418
- }
419
-
420
- // Re-export types
421
- export type { Key, SelectionMode, SelectionBehavior };
package/src/TextField.tsx DELETED
@@ -1,271 +0,0 @@
1
- /**
2
- * TextField component for solidaria-components
3
- *
4
- * A pre-wired headless text field that combines state + aria hooks.
5
- * Port of react-aria-components/src/TextField.tsx
6
- */
7
-
8
- import {
9
- type JSX,
10
- createContext,
11
- useContext,
12
- createMemo,
13
- splitProps,
14
- } from 'solid-js';
15
- import {
16
- createTextField,
17
- createFocusRing,
18
- createHover,
19
- type AriaTextFieldProps,
20
- } from '@proyecto-viviana/solidaria';
21
- import { createTextFieldState } from '@proyecto-viviana/solid-stately';
22
- import {
23
- type RenderChildren,
24
- type ClassNameOrFunction,
25
- type StyleOrFunction,
26
- type SlotProps,
27
- useRenderProps,
28
- filterDOMProps,
29
- } from './utils';
30
-
31
- // ============================================
32
- // TYPES
33
- // ============================================
34
-
35
- export interface TextFieldRenderProps {
36
- /** Whether the text field is disabled. */
37
- isDisabled: boolean;
38
- /** Whether the value is invalid. */
39
- isInvalid: boolean;
40
- /** Whether the text field is read only. */
41
- isReadOnly: boolean;
42
- /** Whether the text field is required. */
43
- isRequired: boolean;
44
- /** Whether the text field is currently hovered with a mouse. */
45
- isHovered: boolean;
46
- /** Whether the text field is focused, either via a mouse or keyboard. */
47
- isFocused: boolean;
48
- /** Whether the text field is keyboard focused. */
49
- isFocusVisible: boolean;
50
- }
51
-
52
- export interface TextFieldProps
53
- extends Omit<AriaTextFieldProps, 'children'>,
54
- SlotProps {
55
- /** The children of the component. A function may be provided to receive render props. */
56
- children?: RenderChildren<TextFieldRenderProps>;
57
- /** The CSS className for the element. */
58
- class?: ClassNameOrFunction<TextFieldRenderProps>;
59
- /** The inline style for the element. */
60
- style?: StyleOrFunction<TextFieldRenderProps>;
61
- }
62
-
63
- // ============================================
64
- // CONTEXT
65
- // ============================================
66
-
67
- export interface TextFieldContextValue {
68
- labelProps: JSX.LabelHTMLAttributes<HTMLLabelElement>;
69
- inputProps: JSX.InputHTMLAttributes<HTMLInputElement>;
70
- descriptionProps: JSX.HTMLAttributes<HTMLElement>;
71
- errorMessageProps: JSX.HTMLAttributes<HTMLElement>;
72
- isInvalid: boolean;
73
- }
74
-
75
- export const TextFieldContext = createContext<TextFieldContextValue | null>(null);
76
-
77
- // ============================================
78
- // SUB-COMPONENTS
79
- // ============================================
80
-
81
- export interface LabelProps extends JSX.LabelHTMLAttributes<HTMLLabelElement> {
82
- children?: JSX.Element;
83
- }
84
-
85
- /**
86
- * A label element that automatically wires up to the parent TextField context.
87
- * This enables the proper htmlFor/id relationship between label and input.
88
- */
89
- export function Label(props: LabelProps): JSX.Element {
90
- const context = useContext(TextFieldContext);
91
-
92
- // Merge context labelProps with local props (local props take precedence)
93
- const mergedProps = () => {
94
- if (context) {
95
- const { ref: _ref, ...contextLabelProps } = context.labelProps as Record<string, unknown>;
96
- return { ...contextLabelProps, ...props };
97
- }
98
- return props;
99
- };
100
-
101
- return <label {...mergedProps()}>{props.children}</label>;
102
- }
103
-
104
- export interface InputProps extends Omit<JSX.InputHTMLAttributes<HTMLInputElement>, 'children'> {}
105
-
106
- /**
107
- * An input element that automatically wires up to the parent TextField context.
108
- * This enables focus tracking, validation, and accessibility props to flow from
109
- * the TextField to the actual input element.
110
- */
111
- export function Input(props: InputProps): JSX.Element {
112
- const context = useContext(TextFieldContext);
113
-
114
- // Merge context inputProps with local props (local props take precedence)
115
- const mergedProps = () => {
116
- if (context) {
117
- // Remove ref from context props to avoid conflicts
118
- const { ref: _ref, ...contextInputProps } = context.inputProps as Record<string, unknown>;
119
- return { ...contextInputProps, ...props };
120
- }
121
- return props;
122
- };
123
-
124
- return <input {...mergedProps()} />;
125
- }
126
-
127
- export interface TextAreaProps extends Omit<JSX.TextareaHTMLAttributes<HTMLTextAreaElement>, 'children'> {}
128
-
129
- /**
130
- * A textarea element that automatically wires up to the parent TextField context.
131
- * This enables focus tracking, validation, and accessibility props to flow from
132
- * the TextField to the actual textarea element.
133
- */
134
- export function TextArea(props: TextAreaProps): JSX.Element {
135
- const context = useContext(TextFieldContext);
136
-
137
- // Merge context inputProps with local props (local props take precedence)
138
- // Note: TextArea uses inputProps from context since it's an input variant
139
- const mergedProps = () => {
140
- if (context) {
141
- const { ref: _ref, type: _type, ...contextInputProps } = context.inputProps as Record<string, unknown>;
142
- return { ...contextInputProps, ...props };
143
- }
144
- return props;
145
- };
146
-
147
- return <textarea {...mergedProps()} />;
148
- }
149
-
150
- // ============================================
151
- // COMPONENT
152
- // ============================================
153
-
154
- /**
155
- * A text field allows a user to enter a plain text value with a keyboard.
156
- *
157
- * This is a headless component that provides accessibility and state management.
158
- * Style it using the render props pattern or data attributes.
159
- *
160
- * @example
161
- * ```tsx
162
- * <TextField>
163
- * {({ isInvalid }) => (
164
- * <>
165
- * <Label>Email</Label>
166
- * <Input class={isInvalid ? 'border-red-500' : 'border-gray-300'} />
167
- * </>
168
- * )}
169
- * </TextField>
170
- * ```
171
- */
172
- export function TextField(props: TextFieldProps): JSX.Element {
173
- // Split props
174
- const [local, ariaProps] = splitProps(props, [
175
- 'children',
176
- 'class',
177
- 'style',
178
- 'slot',
179
- ]);
180
-
181
- // Create text field state
182
- // Use getters to ensure props are read lazily inside reactive contexts
183
- const state = createTextFieldState({
184
- get value() { return ariaProps.value; },
185
- get defaultValue() { return ariaProps.defaultValue; },
186
- get onChange() { return ariaProps.onChange; },
187
- });
188
-
189
- // Create text field aria props
190
- const textFieldAria = createTextField(() => ({
191
- ...ariaProps,
192
- value: state.value(),
193
- onChange: state.setValue,
194
- }));
195
-
196
- // Create focus ring
197
- const { isFocused, isFocusVisible, focusProps } = createFocusRing();
198
-
199
- // Create hover
200
- const { isHovered, hoverProps } = createHover({
201
- get isDisabled() {
202
- return ariaProps.isDisabled;
203
- },
204
- });
205
-
206
- // Render props values
207
- const renderValues = createMemo<TextFieldRenderProps>(() => ({
208
- isDisabled: ariaProps.isDisabled || false,
209
- isInvalid: textFieldAria.isInvalid,
210
- isReadOnly: ariaProps.isReadOnly || false,
211
- isRequired: ariaProps.isRequired || false,
212
- isHovered: isHovered(),
213
- isFocused: isFocused(),
214
- isFocusVisible: isFocusVisible(),
215
- }));
216
-
217
- // Resolve render props
218
- const renderProps = useRenderProps(
219
- {
220
- children: props.children,
221
- class: local.class,
222
- style: local.style,
223
- defaultClassName: 'solidaria-TextField',
224
- },
225
- renderValues
226
- );
227
-
228
- // Filter DOM props
229
- const domProps = createMemo(() => {
230
- const filtered = filterDOMProps(ariaProps, { global: true });
231
- delete (filtered as Record<string, unknown>).id;
232
- return filtered;
233
- });
234
-
235
- // Remove ref from spread props to avoid type conflicts
236
- const cleanHoverProps = () => {
237
- const { ref: _ref, ...rest } = hoverProps as Record<string, unknown>;
238
- return rest;
239
- };
240
-
241
- // Context value for sub-components
242
- // Note: We create the value object directly (not in a memo) so it's available
243
- // immediately when children access the context
244
- const contextValue: TextFieldContextValue = {
245
- labelProps: textFieldAria.labelProps as JSX.LabelHTMLAttributes<HTMLLabelElement>,
246
- inputProps: { ...textFieldAria.inputProps, ...focusProps } as JSX.InputHTMLAttributes<HTMLInputElement>,
247
- descriptionProps: textFieldAria.descriptionProps as JSX.HTMLAttributes<HTMLElement>,
248
- errorMessageProps: textFieldAria.errorMessageProps as JSX.HTMLAttributes<HTMLElement>,
249
- isInvalid: textFieldAria.isInvalid,
250
- };
251
-
252
- return (
253
- <TextFieldContext.Provider value={contextValue}>
254
- <div
255
- {...domProps()}
256
- {...cleanHoverProps()}
257
- class={renderProps.class()}
258
- style={renderProps.style()}
259
- data-disabled={ariaProps.isDisabled || undefined}
260
- data-invalid={textFieldAria.isInvalid || undefined}
261
- data-readonly={ariaProps.isReadOnly || undefined}
262
- data-required={ariaProps.isRequired || undefined}
263
- data-hovered={isHovered() || undefined}
264
- data-focused={isFocused() || undefined}
265
- data-focus-visible={isFocusVisible() || undefined}
266
- >
267
- {renderProps.renderChildren()}
268
- </div>
269
- </TextFieldContext.Provider>
270
- );
271
- }