@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/TimeField.tsx DELETED
@@ -1,455 +0,0 @@
1
- /**
2
- * TimeField component for solidaria-components
3
- *
4
- * Pre-wired headless time field component with segment-based editing.
5
- * Port of react-aria-components/src/TimeField.tsx
6
- */
7
-
8
- import {
9
- type JSX,
10
- createContext,
11
- createMemo,
12
- createSignal,
13
- splitProps,
14
- useContext,
15
- For,
16
- Show,
17
- } from 'solid-js';
18
- import {
19
- createTimeField,
20
- type AriaTimeFieldProps,
21
- } from '@proyecto-viviana/solidaria';
22
- import {
23
- createTimeFieldState,
24
- type TimeFieldState,
25
- type TimeFieldStateProps,
26
- type TimeSegment as TimeSegmentType,
27
- type TimeValue,
28
- } from '@proyecto-viviana/solid-stately';
29
- import {
30
- type RenderChildren,
31
- type ClassNameOrFunction,
32
- type StyleOrFunction,
33
- type SlotProps,
34
- useRenderProps,
35
- dataAttr,
36
- useIsHydrated,
37
- } from './utils';
38
-
39
- // ============================================
40
- // TYPES
41
- // ============================================
42
-
43
- export interface TimeFieldRenderProps {
44
- /** Whether the field is disabled. */
45
- isDisabled: boolean;
46
- /** Whether the field is read-only. */
47
- isReadOnly: boolean;
48
- /** Whether the field is required. */
49
- isRequired: boolean;
50
- /** Whether the field is invalid. */
51
- isInvalid: boolean;
52
- }
53
-
54
- export interface TimeFieldProps<T extends TimeValue = TimeValue>
55
- extends Omit<AriaTimeFieldProps, 'id' | 'isDisabled' | 'isReadOnly' | 'isRequired'>,
56
- Omit<TimeFieldStateProps<T>, 'locale'>,
57
- SlotProps {
58
- /** The children of the component. */
59
- children?: JSX.Element | ((segment: TimeSegmentType) => JSX.Element);
60
- /** The CSS className for the element. */
61
- class?: ClassNameOrFunction<TimeFieldRenderProps>;
62
- /** The inline style for the element. */
63
- style?: StyleOrFunction<TimeFieldRenderProps>;
64
- /** The locale to use for formatting. */
65
- locale?: string;
66
- }
67
-
68
- export interface TimeInputRenderProps {
69
- /** Whether the input is disabled. */
70
- isDisabled: boolean;
71
- /** Whether the input is focused. */
72
- isFocused: boolean;
73
- }
74
-
75
- export interface TimeInputProps extends SlotProps {
76
- /** The children of the component (render function receiving segments). */
77
- children?: (segment: TimeSegmentType) => JSX.Element;
78
- /** The CSS className for the element. */
79
- class?: ClassNameOrFunction<TimeInputRenderProps>;
80
- /** The inline style for the element. */
81
- style?: StyleOrFunction<TimeInputRenderProps>;
82
- }
83
-
84
- export interface TimeSegmentRenderProps {
85
- /** Whether the segment is focused. */
86
- isFocused: boolean;
87
- /** Whether the segment is editable. */
88
- isEditable: boolean;
89
- /** Whether the segment is a placeholder. */
90
- isPlaceholder: boolean;
91
- /** The segment type. */
92
- type: TimeSegmentType['type'];
93
- /** The text to display. */
94
- text: string;
95
- }
96
-
97
- export interface TimeSegmentProps extends SlotProps {
98
- /** The segment data. */
99
- segment: TimeSegmentType;
100
- /** The children of the component. A function may be provided to receive render props. */
101
- children?: RenderChildren<TimeSegmentRenderProps>;
102
- /** The CSS className for the element. */
103
- class?: ClassNameOrFunction<TimeSegmentRenderProps>;
104
- /** The inline style for the element. */
105
- style?: StyleOrFunction<TimeSegmentRenderProps>;
106
- }
107
-
108
- // ============================================
109
- // CONTEXT
110
- // ============================================
111
-
112
- export const TimeFieldContext = createContext<TimeFieldState<TimeValue> | null>(null);
113
-
114
- export function useTimeFieldContext(): TimeFieldState<TimeValue> {
115
- const context = useContext(TimeFieldContext);
116
- if (!context) {
117
- throw new Error('TimeField components must be used within a TimeField');
118
- }
119
- return context;
120
- }
121
-
122
- // ============================================
123
- // TIME FIELD COMPONENT
124
- // ============================================
125
-
126
- /**
127
- * A time field allows users to enter and edit time values using a keyboard.
128
- *
129
- * @example
130
- * ```tsx
131
- * <TimeField label="Time">
132
- * <Label>Time</Label>
133
- * <TimeInput>
134
- * {(segment) => <TimeSegment segment={segment} />}
135
- * </TimeInput>
136
- * </TimeField>
137
- * ```
138
- */
139
- export function TimeField<T extends TimeValue = TimeValue>(
140
- props: TimeFieldProps<T>
141
- ): JSX.Element {
142
- // Use hydration-safe pattern for client-only rendering
143
- const isHydrated = useIsHydrated();
144
-
145
- return (
146
- <Show
147
- when={isHydrated()}
148
- fallback={<div class="solidaria-TimeField solidaria-TimeField--placeholder" aria-hidden="true" />}
149
- >
150
- <TimeFieldInner {...props} />
151
- </Show>
152
- );
153
- }
154
-
155
- /**
156
- * Internal TimeField component that renders after client mount.
157
- */
158
- function TimeFieldInner<T extends TimeValue = TimeValue>(
159
- props: TimeFieldProps<T>
160
- ): JSX.Element {
161
- const [local, stateProps, rest] = splitProps(
162
- props,
163
- ['children', 'class', 'style', 'slot'],
164
- [
165
- 'value',
166
- 'defaultValue',
167
- 'onChange',
168
- 'minValue',
169
- 'maxValue',
170
- 'isDisabled',
171
- 'isReadOnly',
172
- 'isRequired',
173
- 'locale',
174
- 'granularity',
175
- 'hourCycle',
176
- 'validationState',
177
- 'placeholderValue',
178
- ]
179
- );
180
-
181
- const [fieldRef, setFieldRef] = createSignal<HTMLDivElement | null>(null);
182
-
183
- // Create time field state
184
- const state = createTimeFieldState(stateProps);
185
-
186
- // Create time field ARIA props
187
- const fieldAria = createTimeField(rest, state as unknown as TimeFieldState<TimeValue>, fieldRef);
188
-
189
- // Render props values
190
- const renderValues = createMemo<TimeFieldRenderProps>(() => ({
191
- isDisabled: state.isDisabled(),
192
- isReadOnly: state.isReadOnly(),
193
- isRequired: state.isRequired(),
194
- isInvalid: state.isInvalid(),
195
- }));
196
-
197
- // Resolve render props
198
- const renderProps = useRenderProps(
199
- {
200
- class: local.class,
201
- style: local.style,
202
- defaultClassName: 'solidaria-TimeField',
203
- },
204
- renderValues
205
- );
206
-
207
- return (
208
- <TimeFieldContext.Provider value={state as unknown as TimeFieldState<TimeValue>}>
209
- <div
210
- ref={setFieldRef}
211
- {...fieldAria.fieldProps}
212
- class={renderProps.class()}
213
- style={renderProps.style()}
214
- data-disabled={dataAttr(state.isDisabled())}
215
- data-readonly={dataAttr(state.isReadOnly())}
216
- data-required={dataAttr(state.isRequired())}
217
- data-invalid={dataAttr(state.isInvalid())}
218
- >
219
- {props.children as JSX.Element}
220
- </div>
221
- </TimeFieldContext.Provider>
222
- );
223
- }
224
-
225
- // ============================================
226
- // TIME INPUT COMPONENT
227
- // ============================================
228
-
229
- /**
230
- * The input area containing time segments.
231
- */
232
- export function TimeInput(props: TimeInputProps): JSX.Element {
233
- const state = useTimeFieldContext();
234
- const [isFocused, setIsFocused] = createSignal(false);
235
-
236
- // Render props values
237
- const renderValues = createMemo<TimeInputRenderProps>(() => ({
238
- isDisabled: state.isDisabled(),
239
- isFocused: isFocused(),
240
- }));
241
-
242
- // Resolve render props
243
- const renderProps = useRenderProps(
244
- {
245
- class: props.class,
246
- style: props.style,
247
- defaultClassName: 'solidaria-TimeInput',
248
- },
249
- renderValues
250
- );
251
-
252
- return (
253
- <div
254
- role="presentation"
255
- class={renderProps.class()}
256
- style={renderProps.style()}
257
- data-disabled={dataAttr(state.isDisabled())}
258
- data-focused={dataAttr(isFocused())}
259
- onFocusIn={() => setIsFocused(true)}
260
- onFocusOut={() => setIsFocused(false)}
261
- >
262
- <For each={state.segments()}>
263
- {(segment) => props.children?.(segment)}
264
- </For>
265
- </div>
266
- );
267
- }
268
-
269
- // ============================================
270
- // TIME SEGMENT COMPONENT
271
- // ============================================
272
-
273
- /**
274
- * A segment of a time field (hour, minute, second, AM/PM).
275
- */
276
- export function TimeSegment(props: TimeSegmentProps): JSX.Element {
277
- const state = useTimeFieldContext();
278
- const [_segmentRef, setSegmentRef] = createSignal<HTMLDivElement | null>(null);
279
-
280
- // Create segment ARIA props
281
- // We use a simplified version for time segments
282
- const [isFocused, setIsFocused] = createSignal(false);
283
- const [enteredKeys, setEnteredKeys] = createSignal('');
284
-
285
- const isEditable = createMemo(() => {
286
- const seg = props.segment;
287
- return seg.isEditable && !state.isDisabled() && !state.isReadOnly();
288
- });
289
-
290
- const handleKeyDown = (e: KeyboardEvent) => {
291
- if (!isEditable()) return;
292
-
293
- const seg = props.segment;
294
- const type = seg.type;
295
-
296
- if (type === 'literal') return;
297
-
298
- switch (e.key) {
299
- case 'ArrowUp':
300
- e.preventDefault();
301
- state.incrementSegment(type);
302
- break;
303
- case 'ArrowDown':
304
- e.preventDefault();
305
- state.decrementSegment(type);
306
- break;
307
- case 'Backspace':
308
- case 'Delete':
309
- e.preventDefault();
310
- state.clearSegment(type);
311
- setEnteredKeys('');
312
- break;
313
- default:
314
- if (/^\d$/.test(e.key)) {
315
- e.preventDefault();
316
- const newKeys = enteredKeys() + e.key;
317
- const numValue = parseInt(newKeys, 10);
318
- const maxValue = seg.maxValue ?? 59;
319
- const minValue = seg.minValue ?? 0;
320
-
321
- if (numValue <= maxValue) {
322
- state.setSegment(type, numValue);
323
- if (numValue * 10 > maxValue || newKeys.length >= 2) {
324
- setEnteredKeys('');
325
- } else {
326
- setEnteredKeys(newKeys);
327
- }
328
- } else {
329
- const singleValue = parseInt(e.key, 10);
330
- if (singleValue >= minValue && singleValue <= maxValue) {
331
- state.setSegment(type, singleValue);
332
- }
333
- setEnteredKeys(e.key);
334
- }
335
- }
336
- break;
337
- }
338
- };
339
-
340
- const handleFocus = () => {
341
- setIsFocused(true);
342
- setEnteredKeys('');
343
- };
344
-
345
- const handleBlur = () => {
346
- setIsFocused(false);
347
- setEnteredKeys('');
348
- };
349
-
350
- // Segment props
351
- const segmentProps = createMemo(() => {
352
- const seg = props.segment;
353
- const type = seg.type;
354
-
355
- if (type === 'literal') {
356
- return {
357
- 'aria-hidden': true,
358
- };
359
- }
360
-
361
- return {
362
- role: 'spinbutton' as const,
363
- tabIndex: isEditable() ? 0 : -1,
364
- 'aria-label': getTimeSegmentLabel(type),
365
- 'aria-valuenow': seg.value,
366
- 'aria-valuemin': seg.minValue,
367
- 'aria-valuemax': seg.maxValue,
368
- 'aria-valuetext': seg.isPlaceholder ? seg.placeholder : seg.text,
369
- 'aria-readonly': state.isReadOnly() || undefined,
370
- 'aria-disabled': state.isDisabled() || undefined,
371
- 'aria-invalid': state.isInvalid() || undefined,
372
- contentEditable: isEditable(),
373
- inputMode: 'numeric' as const,
374
- autoCorrect: 'off',
375
- enterKeyHint: 'next' as const,
376
- spellCheck: false,
377
- onKeyDown: handleKeyDown,
378
- onFocus: handleFocus,
379
- onBlur: handleBlur,
380
- onMouseDown: (e: MouseEvent) => {
381
- e.preventDefault();
382
- },
383
- };
384
- });
385
-
386
- const text = createMemo(() => {
387
- const seg = props.segment;
388
- return seg.isPlaceholder ? seg.placeholder : seg.text;
389
- });
390
-
391
- // Render props values
392
- const renderValues = createMemo<TimeSegmentRenderProps>(() => ({
393
- isFocused: isFocused(),
394
- isEditable: isEditable(),
395
- isPlaceholder: props.segment.isPlaceholder,
396
- type: props.segment.type,
397
- text: text(),
398
- }));
399
-
400
- // Resolve render props
401
- const renderProps = useRenderProps(
402
- {
403
- children: props.children,
404
- class: props.class,
405
- style: props.style,
406
- defaultClassName: 'solidaria-TimeSegment',
407
- },
408
- renderValues
409
- );
410
-
411
- // Determine children content - avoid Show for SSR hydration compatibility
412
- const getChildren = () => {
413
- if (typeof props.children === 'function') {
414
- return renderProps.renderChildren();
415
- }
416
- return text();
417
- };
418
-
419
- return (
420
- <div
421
- ref={setSegmentRef}
422
- {...segmentProps()}
423
- class={renderProps.class()}
424
- style={renderProps.style()}
425
- data-focused={dataAttr(isFocused())}
426
- data-editable={dataAttr(isEditable())}
427
- data-placeholder={dataAttr(props.segment.isPlaceholder)}
428
- data-type={props.segment.type}
429
- >
430
- {getChildren()}
431
- </div>
432
- );
433
- }
434
-
435
- // ============================================
436
- // HELPER FUNCTIONS
437
- // ============================================
438
-
439
- function getTimeSegmentLabel(type: TimeSegmentType['type']): string {
440
- switch (type) {
441
- case 'hour':
442
- return 'Hour';
443
- case 'minute':
444
- return 'Minute';
445
- case 'second':
446
- return 'Second';
447
- case 'dayPeriod':
448
- return 'AM/PM';
449
- default:
450
- return '';
451
- }
452
- }
453
-
454
- // Re-export types
455
- export type { TimeFieldState, TimeSegmentType, TimeValue };