@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/Button.tsx DELETED
@@ -1,238 +0,0 @@
1
- /**
2
- * Button component for solidaria-components
3
- *
4
- * A pre-wired headless button that combines state + aria hooks.
5
- * Port of react-aria-components/src/Button.tsx
6
- */
7
-
8
- import {
9
- type JSX,
10
- createContext,
11
- createMemo,
12
- splitProps,
13
- useContext,
14
- } from 'solid-js';
15
- import {
16
- createButton,
17
- createFocusRing,
18
- createHover,
19
- type AriaButtonProps,
20
- } from '@proyecto-viviana/solidaria';
21
- import {
22
- type RenderChildren,
23
- type ClassNameOrFunction,
24
- type StyleOrFunction,
25
- type SlotProps,
26
- useRenderProps,
27
- filterDOMProps,
28
- } from './utils';
29
- import { DialogTriggerContext, PopoverTriggerContext } from './contexts';
30
-
31
- // ============================================
32
- // TYPES
33
- // ============================================
34
-
35
- export interface ButtonRenderProps {
36
- /** Whether the button is currently hovered with a mouse. */
37
- isHovered: boolean;
38
- /** Whether the button is currently in a pressed state. */
39
- isPressed: boolean;
40
- /** Whether the button is focused, either via a mouse or keyboard. */
41
- isFocused: boolean;
42
- /** Whether the button is keyboard focused. */
43
- isFocusVisible: boolean;
44
- /** Whether the button is disabled. */
45
- isDisabled: boolean;
46
- }
47
-
48
- export interface ButtonProps
49
- extends Omit<AriaButtonProps, 'children'>,
50
- SlotProps {
51
- /** The children of the component. A function may be provided to receive render props. */
52
- children?: RenderChildren<ButtonRenderProps>;
53
- /** The CSS className for the element. */
54
- class?: ClassNameOrFunction<ButtonRenderProps>;
55
- /** The inline style for the element. */
56
- style?: StyleOrFunction<ButtonRenderProps>;
57
- }
58
-
59
- // ============================================
60
- // CONTEXT
61
- // ============================================
62
-
63
- export const ButtonContext = createContext<ButtonProps | null>(null);
64
-
65
- // ============================================
66
- // COMPONENT
67
- // ============================================
68
-
69
- /**
70
- * A button allows a user to perform an action.
71
- *
72
- * This is a headless component that provides accessibility and state management.
73
- * Style it using the render props pattern or data attributes.
74
- *
75
- * @example
76
- * ```tsx
77
- * <Button onPress={() => alert('Pressed!')}>
78
- * {({ isPressed, isHovered }) => (
79
- * <span class={isPressed ? 'bg-blue-700' : isHovered ? 'bg-blue-600' : 'bg-blue-500'}>
80
- * Click me
81
- * </span>
82
- * )}
83
- * </Button>
84
- * ```
85
- */
86
- export function Button(props: ButtonProps): JSX.Element {
87
- // Split props
88
- const [local, ariaProps] = splitProps(props, [
89
- 'children',
90
- 'class',
91
- 'style',
92
- 'slot',
93
- ]);
94
-
95
- // Check if inside a DialogTrigger or PopoverTrigger - if so, toggle on press
96
- // NOTE: Context is captured at component creation time. For Buttons inside a Modal,
97
- // the Modal provides OverlayTriggerStateContext, but due to SolidJS's eager JSX evaluation,
98
- // components inside Modal children are created before the Modal's Show renders.
99
- // So we can't reliably use context here to determine if we're inside a Modal.
100
- const dialogTriggerContext = useContext(DialogTriggerContext);
101
- const popoverTriggerContext = useContext(PopoverTriggerContext);
102
-
103
- // Helper to resolve isDisabled (handles both boolean and Accessor<boolean>)
104
- const resolveDisabled = (): boolean => {
105
- const disabled = ariaProps.isDisabled;
106
- if (typeof disabled === 'function') {
107
- return disabled();
108
- }
109
- return !!disabled;
110
- };
111
-
112
- // Determine if this button should act as a dialog/popover trigger
113
- // We only toggle if:
114
- // 1. We have DialogTriggerContext or PopoverTriggerContext (we're inside a trigger)
115
- // 2. AND there is NO onPress handler (the trigger button typically has no onPress,
116
- // while close buttons inside dialogs have onPress={close})
117
- // This heuristic works because:
118
- // - Trigger buttons: don't have onPress, should toggle
119
- // - Close buttons: have onPress={close}, should NOT toggle (just call onPress)
120
- const isDialogTrigger = () => dialogTriggerContext && !ariaProps.onPress;
121
- const isPopoverTrigger = () => popoverTriggerContext && !ariaProps.onPress;
122
-
123
- // Wrap onPress to also toggle dialog/popover if this is a trigger button
124
- const handlePress = (e: any) => {
125
- // Call original onPress if provided
126
- if (typeof ariaProps.onPress === 'function') {
127
- ariaProps.onPress(e);
128
- }
129
- // Toggle dialog only if this is a trigger button (has no onPress handler)
130
- if (isDialogTrigger()) {
131
- dialogTriggerContext!.state.toggle();
132
- }
133
- // Toggle popover only if this is a trigger button (has no onPress handler)
134
- if (isPopoverTrigger()) {
135
- popoverTriggerContext!.state.toggle();
136
- }
137
- };
138
-
139
- // Create button aria props
140
- const buttonAria = createButton({
141
- ...ariaProps,
142
- onPress: handlePress,
143
- get isDisabled() {
144
- return resolveDisabled();
145
- },
146
- });
147
-
148
- // Create focus ring
149
- const { isFocused, isFocusVisible, focusProps } = createFocusRing();
150
-
151
- // Create hover
152
- const { isHovered, hoverProps } = createHover({
153
- get isDisabled() {
154
- return resolveDisabled();
155
- },
156
- });
157
-
158
- // Render props values
159
- const renderValues = createMemo<ButtonRenderProps>(() => ({
160
- isHovered: isHovered(),
161
- isPressed: buttonAria.isPressed(),
162
- isFocused: isFocused(),
163
- isFocusVisible: isFocusVisible(),
164
- isDisabled: resolveDisabled(),
165
- }));
166
-
167
- // Resolve render props
168
- const renderProps = useRenderProps(
169
- {
170
- children: props.children,
171
- class: local.class,
172
- style: local.style,
173
- defaultClassName: 'solidaria-Button',
174
- },
175
- renderValues
176
- );
177
-
178
- // Filter DOM props
179
- // Remove onClick from DOM props - it's already handled by createPress
180
- // This matches React Aria Components behavior (Button.tsx line 144: delete DOMProps.onClick)
181
- const domProps = createMemo(() => {
182
- const filtered = filterDOMProps(ariaProps, { global: true });
183
- // onClick is handled by createPress, not passed directly to DOM
184
- delete (filtered as Record<string, unknown>).onClick;
185
- return filtered;
186
- });
187
-
188
- // Extract refs from props to combine them manually
189
- const buttonPropsRef = (buttonAria.buttonProps as Record<string, unknown>).ref as ((el: HTMLElement) => void) | undefined;
190
- const focusPropsRef = (focusProps as Record<string, unknown>).ref as ((el: HTMLElement) => void) | undefined;
191
- const hoverPropsRef = (hoverProps as Record<string, unknown>).ref as ((el: HTMLElement) => void) | undefined;
192
-
193
- // Remove ref from spread props to avoid type conflicts
194
- const cleanButtonProps = () => {
195
- const { ref: _ref1, ...rest } = buttonAria.buttonProps as Record<string, unknown>;
196
- return rest;
197
- };
198
- const cleanFocusProps = () => {
199
- const { ref: _ref2, ...rest } = focusProps as Record<string, unknown>;
200
- return rest;
201
- };
202
- const cleanHoverProps = () => {
203
- const { ref: _ref3, ...rest } = hoverProps as Record<string, unknown>;
204
- return rest;
205
- };
206
-
207
- // Ref callback that combines all refs
208
- const handleRef = (el: HTMLButtonElement) => {
209
- // Call the focusable ref for autoFocus support
210
- buttonPropsRef?.(el);
211
- focusPropsRef?.(el);
212
- hoverPropsRef?.(el);
213
-
214
- // If this button is a popover trigger, register it
215
- if (isPopoverTrigger() && popoverTriggerContext?.setTriggerRef) {
216
- popoverTriggerContext.setTriggerRef(el);
217
- }
218
- };
219
-
220
- return (
221
- <button
222
- ref={handleRef}
223
- {...domProps()}
224
- {...cleanButtonProps()}
225
- {...cleanFocusProps()}
226
- {...cleanHoverProps()}
227
- class={renderProps.class()}
228
- style={renderProps.style()}
229
- data-pressed={buttonAria.isPressed() || undefined}
230
- data-hovered={isHovered() || undefined}
231
- data-focused={isFocused() || undefined}
232
- data-focus-visible={isFocusVisible() || undefined}
233
- data-disabled={resolveDisabled() || undefined}
234
- >
235
- {renderProps.renderChildren()}
236
- </button>
237
- );
238
- }
package/src/Calendar.tsx DELETED
@@ -1,471 +0,0 @@
1
- /**
2
- * Calendar component for solidaria-components
3
- *
4
- * Pre-wired headless calendar component that combines aria hooks.
5
- * Port of react-aria-components/src/Calendar.tsx
6
- */
7
-
8
- import {
9
- type JSX,
10
- createContext,
11
- createMemo,
12
- createSignal,
13
- splitProps,
14
- useContext,
15
- For,
16
- Index,
17
- Show,
18
- } from 'solid-js';
19
-
20
- import {
21
- createCalendar,
22
- createCalendarGrid,
23
- createCalendarCell,
24
- type AriaCalendarProps,
25
- type AriaCalendarGridProps,
26
- } from '@proyecto-viviana/solidaria';
27
- import {
28
- createCalendarState,
29
- type CalendarState,
30
- type CalendarStateProps,
31
- type CalendarDate,
32
- type DateValue,
33
- } from '@proyecto-viviana/solid-stately';
34
- import {
35
- type RenderChildren,
36
- type ClassNameOrFunction,
37
- type StyleOrFunction,
38
- type SlotProps,
39
- useRenderProps,
40
- dataAttr,
41
- useIsHydrated,
42
- } from './utils';
43
-
44
- // ============================================
45
- // TYPES
46
- // ============================================
47
-
48
- export interface CalendarRenderProps {
49
- /** Whether the calendar is disabled. */
50
- isDisabled: boolean;
51
- /** Whether the calendar is read-only. */
52
- isReadOnly: boolean;
53
- }
54
-
55
- export interface CalendarProps<T extends DateValue = DateValue>
56
- extends Omit<AriaCalendarProps, 'id' | 'isDisabled' | 'isReadOnly'>,
57
- Omit<CalendarStateProps<T>, 'locale'>,
58
- SlotProps {
59
- /** The children of the component. */
60
- children?: JSX.Element;
61
- /** The CSS className for the element. */
62
- class?: ClassNameOrFunction<CalendarRenderProps>;
63
- /** The inline style for the element. */
64
- style?: StyleOrFunction<CalendarRenderProps>;
65
- /** The locale to use for formatting. */
66
- locale?: string;
67
- }
68
-
69
- export interface CalendarGridRenderProps {
70
- /** Whether the grid is disabled. */
71
- isDisabled: boolean;
72
- }
73
-
74
- export interface CalendarGridProps extends Omit<AriaCalendarGridProps, 'startDate' | 'endDate'>, SlotProps {
75
- /** The children of the component (render function receiving weeks). */
76
- children?: (date: CalendarDate) => JSX.Element;
77
- /** The CSS className for the element. */
78
- class?: ClassNameOrFunction<CalendarGridRenderProps>;
79
- /** The inline style for the element. */
80
- style?: StyleOrFunction<CalendarGridRenderProps>;
81
- /** Number of weeks to offset from the start. */
82
- offset?: { months?: number };
83
- }
84
-
85
- export interface CalendarCellRenderProps {
86
- /** Whether the cell is selected. */
87
- isSelected: boolean;
88
- /** Whether the cell is focused. */
89
- isFocused: boolean;
90
- /** Whether the cell is disabled. */
91
- isDisabled: boolean;
92
- /** Whether the cell is unavailable. */
93
- isUnavailable: boolean;
94
- /** Whether the cell is outside the visible month. */
95
- isOutsideMonth: boolean;
96
- /** Whether the cell represents today. */
97
- isToday: boolean;
98
- /** Whether the cell is pressed. */
99
- isPressed: boolean;
100
- /** The formatted date string. */
101
- formattedDate: string;
102
- }
103
-
104
- export interface CalendarCellProps extends SlotProps {
105
- /** The date for this cell. */
106
- date: CalendarDate;
107
- /** The children of the component. A function may be provided to receive render props. */
108
- children?: RenderChildren<CalendarCellRenderProps>;
109
- /** The CSS className for the element. */
110
- class?: ClassNameOrFunction<CalendarCellRenderProps>;
111
- /** The inline style for the element. */
112
- style?: StyleOrFunction<CalendarCellRenderProps>;
113
- }
114
-
115
- export interface CalendarHeaderCellProps extends SlotProps {
116
- /** The children of the component. */
117
- children?: JSX.Element;
118
- /** The CSS className for the element. */
119
- class?: string;
120
- /** The inline style for the element. */
121
- style?: JSX.CSSProperties;
122
- }
123
-
124
- // ============================================
125
- // CONTEXT
126
- // ============================================
127
-
128
- export const CalendarContext = createContext<CalendarState<DateValue> | null>(null);
129
-
130
- export function useCalendarContext(): CalendarState<DateValue> {
131
- const context = useContext(CalendarContext);
132
- if (!context) {
133
- throw new Error('Calendar components must be used within a Calendar');
134
- }
135
- return context;
136
- }
137
-
138
- // ============================================
139
- // CALENDAR COMPONENT
140
- // ============================================
141
-
142
- /**
143
- * A calendar displays a grid of days in a month and allows users to select a single date.
144
- *
145
- * @example
146
- * ```tsx
147
- * <Calendar aria-label="Event date">
148
- * <header>
149
- * <CalendarButton slot="previous">◀</CalendarButton>
150
- * <CalendarHeading />
151
- * <CalendarButton slot="next">▶</CalendarButton>
152
- * </header>
153
- * <CalendarGrid>
154
- * {(date) => <CalendarCell date={date} />}
155
- * </CalendarGrid>
156
- * </Calendar>
157
- * ```
158
- */
159
- export function Calendar<T extends DateValue = CalendarDate>(
160
- props: CalendarProps<T>
161
- ): JSX.Element {
162
- // Use hydration-safe pattern for client-only rendering
163
- const isHydrated = useIsHydrated();
164
-
165
- return (
166
- <Show
167
- when={isHydrated()}
168
- fallback={<div class="solidaria-Calendar solidaria-Calendar--placeholder" aria-hidden="true" />}
169
- >
170
- <CalendarInner {...props} />
171
- </Show>
172
- );
173
- }
174
-
175
- /**
176
- * Internal Calendar component that renders after client mount.
177
- */
178
- function CalendarInner<T extends DateValue = CalendarDate>(
179
- props: CalendarProps<T>
180
- ): JSX.Element {
181
- const [local, stateProps, rest] = splitProps(
182
- props,
183
- ['children', 'class', 'style', 'slot'],
184
- [
185
- 'value',
186
- 'defaultValue',
187
- 'onChange',
188
- 'minValue',
189
- 'maxValue',
190
- 'isDisabled',
191
- 'isReadOnly',
192
- 'autoFocus',
193
- 'focusedValue',
194
- 'defaultFocusedValue',
195
- 'onFocusChange',
196
- 'locale',
197
- 'isDateUnavailable',
198
- 'visibleMonths',
199
- 'isDateDisabled',
200
- 'validationState',
201
- 'errorMessage',
202
- 'firstDayOfWeek',
203
- ]
204
- );
205
-
206
- // Create calendar state
207
- const state = createCalendarState(stateProps);
208
-
209
- // Create calendar ARIA props
210
- const calendarAria = createCalendar(rest, state as unknown as CalendarState<DateValue>);
211
-
212
- // Render props values
213
- const renderValues = createMemo<CalendarRenderProps>(() => ({
214
- isDisabled: state.isDisabled(),
215
- isReadOnly: state.isReadOnly(),
216
- }));
217
-
218
- // Resolve render props
219
- const renderProps = useRenderProps(
220
- {
221
- class: local.class,
222
- style: local.style,
223
- defaultClassName: 'solidaria-Calendar',
224
- },
225
- renderValues
226
- );
227
-
228
- return (
229
- <CalendarContext.Provider value={state as unknown as CalendarState<DateValue>}>
230
- <div
231
- {...calendarAria.calendarProps}
232
- class={renderProps.class()}
233
- style={renderProps.style()}
234
- data-disabled={dataAttr(state.isDisabled())}
235
- data-readonly={dataAttr(state.isReadOnly())}
236
- >
237
- {props.children}
238
- </div>
239
- </CalendarContext.Provider>
240
- );
241
- }
242
-
243
- // ============================================
244
- // CALENDAR HEADING COMPONENT
245
- // ============================================
246
-
247
- export interface CalendarHeadingProps extends SlotProps {
248
- /** The CSS className for the element. */
249
- class?: string;
250
- /** The inline style for the element. */
251
- style?: JSX.CSSProperties;
252
- }
253
-
254
- /**
255
- * Displays the current month and year in the calendar.
256
- */
257
- export function CalendarHeading(props: CalendarHeadingProps): JSX.Element {
258
- const state = useCalendarContext();
259
-
260
- return (
261
- <h2
262
- class={props.class ?? 'solidaria-CalendarHeading'}
263
- style={props.style}
264
- aria-live="polite"
265
- >
266
- {state.title()}
267
- </h2>
268
- );
269
- }
270
-
271
- // ============================================
272
- // CALENDAR BUTTON COMPONENT
273
- // ============================================
274
-
275
- export interface CalendarButtonProps extends SlotProps {
276
- /** The slot for this button (previous or next). */
277
- slot?: 'previous' | 'next';
278
- /** The children of the component. */
279
- children?: JSX.Element;
280
- /** The CSS className for the element. */
281
- class?: string;
282
- /** The inline style for the element. */
283
- style?: JSX.CSSProperties;
284
- /** Whether the button is disabled. */
285
- isDisabled?: boolean;
286
- }
287
-
288
- /**
289
- * A button for navigating the calendar.
290
- */
291
- export function CalendarButton(props: CalendarButtonProps): JSX.Element {
292
- const state = useCalendarContext();
293
- const calendarAria = createCalendar({}, state);
294
-
295
- const buttonProps = createMemo(() => {
296
- if (props.slot === 'previous') {
297
- return calendarAria.prevButtonProps;
298
- }
299
- return calendarAria.nextButtonProps;
300
- });
301
-
302
- return (
303
- <button
304
- {...buttonProps()}
305
- class={props.class ?? 'solidaria-CalendarButton'}
306
- style={props.style}
307
- disabled={props.isDisabled || state.isDisabled()}
308
- >
309
- {props.children}
310
- </button>
311
- );
312
- }
313
-
314
- // ============================================
315
- // CALENDAR GRID COMPONENT
316
- // ============================================
317
-
318
- /**
319
- * Displays a grid of calendar cells.
320
- */
321
- export function CalendarGrid(props: CalendarGridProps): JSX.Element {
322
- const state = useCalendarContext();
323
- const [gridRef, setGridRef] = createSignal<HTMLTableElement | null>(null);
324
-
325
- // Create grid ARIA props
326
- const gridAria = createCalendarGrid(
327
- {
328
- weekdayStyle: props.weekdayStyle,
329
- },
330
- state,
331
- gridRef
332
- );
333
-
334
- // Render props values
335
- const renderValues = createMemo<CalendarGridRenderProps>(() => ({
336
- isDisabled: state.isDisabled(),
337
- }));
338
-
339
- // Resolve render props
340
- const renderProps = useRenderProps(
341
- {
342
- class: props.class,
343
- style: props.style,
344
- defaultClassName: 'solidaria-CalendarGrid',
345
- },
346
- renderValues
347
- );
348
-
349
- // Memoize ALL dates for the grid at once to avoid reactive loops.
350
- // This breaks the cycle where accessing visibleRange() inside For loop
351
- // would cause infinite re-renders.
352
- const allDates = createMemo(() => {
353
- const numWeeks = state.getWeeksInMonth();
354
- const weekDates: (CalendarDate | null)[][] = [];
355
-
356
- for (let weekIndex = 0; weekIndex < numWeeks; weekIndex++) {
357
- weekDates.push(state.getDatesInWeek(weekIndex));
358
- }
359
-
360
- return weekDates;
361
- });
362
-
363
- return (
364
- <table
365
- ref={setGridRef}
366
- {...gridAria.gridProps}
367
- class={renderProps.class()}
368
- style={renderProps.style()}
369
- >
370
- <thead {...gridAria.headerProps}>
371
- <tr>
372
- <For each={gridAria.weekDays}>
373
- {(day) => (
374
- <th scope="col" class="solidaria-CalendarHeaderCell">
375
- {day}
376
- </th>
377
- )}
378
- </For>
379
- </tr>
380
- </thead>
381
- <tbody>
382
- <Index each={allDates()}>
383
- {(weekDates) => (
384
- <tr>
385
- <Index each={weekDates()}>
386
- {(date) => (
387
- <Show when={date()}>
388
- <td role="gridcell">
389
- {props.children?.(date()!)}
390
- </td>
391
- </Show>
392
- )}
393
- </Index>
394
- </tr>
395
- )}
396
- </Index>
397
- </tbody>
398
- </table>
399
- );
400
- }
401
-
402
- // ============================================
403
- // CALENDAR CELL COMPONENT
404
- // ============================================
405
-
406
- /**
407
- * A cell in the calendar grid representing a single day.
408
- */
409
- export function CalendarCell(props: CalendarCellProps): JSX.Element {
410
- const state = useCalendarContext();
411
- const [cellRef, setCellRef] = createSignal<HTMLDivElement | null>(null);
412
-
413
- // Create cell ARIA props
414
- const cellAria = createCalendarCell(
415
- { date: props.date },
416
- state,
417
- cellRef
418
- );
419
-
420
- // Render props values
421
- const renderValues = createMemo<CalendarCellRenderProps>(() => ({
422
- isSelected: cellAria.isSelected,
423
- isFocused: cellAria.isFocused,
424
- isDisabled: cellAria.isDisabled,
425
- isUnavailable: cellAria.isUnavailable,
426
- isOutsideMonth: cellAria.isOutsideMonth,
427
- isToday: cellAria.isToday,
428
- isPressed: cellAria.isPressed,
429
- formattedDate: cellAria.formattedDate,
430
- }));
431
-
432
- // Resolve render props
433
- const renderProps = useRenderProps(
434
- {
435
- children: props.children,
436
- class: props.class,
437
- style: props.style,
438
- defaultClassName: 'solidaria-CalendarCell',
439
- },
440
- renderValues
441
- );
442
-
443
- // Determine children content - avoid Show for SSR hydration compatibility
444
- const getChildren = () => {
445
- if (typeof props.children === 'function') {
446
- return renderProps.renderChildren();
447
- }
448
- return cellAria.formattedDate;
449
- };
450
-
451
- return (
452
- <div
453
- ref={setCellRef}
454
- {...cellAria.buttonProps}
455
- class={renderProps.class()}
456
- style={renderProps.style()}
457
- data-selected={dataAttr(cellAria.isSelected)}
458
- data-focused={dataAttr(cellAria.isFocused)}
459
- data-disabled={dataAttr(cellAria.isDisabled)}
460
- data-unavailable={dataAttr(cellAria.isUnavailable)}
461
- data-outside-month={dataAttr(cellAria.isOutsideMonth)}
462
- data-today={dataAttr(cellAria.isToday)}
463
- data-pressed={dataAttr(cellAria.isPressed)}
464
- >
465
- {getChildren()}
466
- </div>
467
- );
468
- }
469
-
470
- // Re-export types
471
- export type { CalendarState, CalendarDate, DateValue };