@proyecto-viviana/solidaria-components 0.1.3 → 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 -10
  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/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 };