@proyecto-viviana/solidaria-components 0.1.2 → 0.2.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.
Files changed (62) 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.ssr.js +15 -15
  20. package/dist/index.ssr.js.map +2 -2
  21. package/package.json +8 -9
  22. package/src/Autocomplete.tsx +0 -174
  23. package/src/Breadcrumbs.tsx +0 -264
  24. package/src/Button.tsx +0 -238
  25. package/src/Calendar.tsx +0 -471
  26. package/src/Checkbox.tsx +0 -387
  27. package/src/Color.tsx +0 -1370
  28. package/src/ComboBox.tsx +0 -824
  29. package/src/DateField.tsx +0 -337
  30. package/src/DatePicker.tsx +0 -367
  31. package/src/Dialog.tsx +0 -262
  32. package/src/Disclosure.tsx +0 -439
  33. package/src/GridList.tsx +0 -511
  34. package/src/Landmark.tsx +0 -203
  35. package/src/Link.tsx +0 -201
  36. package/src/ListBox.tsx +0 -346
  37. package/src/Menu.tsx +0 -544
  38. package/src/Meter.tsx +0 -157
  39. package/src/Modal.tsx +0 -433
  40. package/src/NumberField.tsx +0 -542
  41. package/src/Popover.tsx +0 -540
  42. package/src/ProgressBar.tsx +0 -162
  43. package/src/RadioGroup.tsx +0 -356
  44. package/src/RangeCalendar.tsx +0 -462
  45. package/src/SearchField.tsx +0 -479
  46. package/src/Select.tsx +0 -734
  47. package/src/Separator.tsx +0 -130
  48. package/src/Slider.tsx +0 -500
  49. package/src/Switch.tsx +0 -213
  50. package/src/Table.tsx +0 -857
  51. package/src/Tabs.tsx +0 -552
  52. package/src/TagGroup.tsx +0 -421
  53. package/src/TextField.tsx +0 -271
  54. package/src/TimeField.tsx +0 -455
  55. package/src/Toast.tsx +0 -503
  56. package/src/Toolbar.tsx +0 -160
  57. package/src/Tooltip.tsx +0 -423
  58. package/src/Tree.tsx +0 -551
  59. package/src/VisuallyHidden.tsx +0 -60
  60. package/src/contexts.ts +0 -74
  61. package/src/index.ts +0 -620
  62. 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
- }