@proyecto-viviana/solidaria-components 0.2.5 → 0.3.0

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 (225) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +39 -272
  3. package/dist/ActionBar.d.ts +79 -0
  4. package/dist/ActionBar.d.ts.map +1 -0
  5. package/dist/ActionGroup.d.ts +74 -0
  6. package/dist/ActionGroup.d.ts.map +1 -0
  7. package/dist/Alert.d.ts +70 -0
  8. package/dist/Alert.d.ts.map +1 -0
  9. package/dist/Autocomplete.d.ts +5 -5
  10. package/dist/Autocomplete.d.ts.map +1 -1
  11. package/dist/Breadcrumbs.d.ts +27 -8
  12. package/dist/Breadcrumbs.d.ts.map +1 -1
  13. package/dist/Button.d.ts +28 -5
  14. package/dist/Button.d.ts.map +1 -1
  15. package/dist/Calendar.d.ts +51 -7
  16. package/dist/Calendar.d.ts.map +1 -1
  17. package/dist/Checkbox.d.ts +33 -8
  18. package/dist/Checkbox.d.ts.map +1 -1
  19. package/dist/Collection.d.ts +130 -0
  20. package/dist/Collection.d.ts.map +1 -0
  21. package/dist/Color.d.ts +210 -9
  22. package/dist/Color.d.ts.map +1 -1
  23. package/dist/ColorEditor.d.ts +42 -0
  24. package/dist/ColorEditor.d.ts.map +1 -0
  25. package/dist/ComboBox.d.ts +146 -16
  26. package/dist/ComboBox.d.ts.map +1 -1
  27. package/dist/ContextualHelpTrigger.d.ts +40 -0
  28. package/dist/ContextualHelpTrigger.d.ts.map +1 -0
  29. package/dist/DateField.d.ts +35 -8
  30. package/dist/DateField.d.ts.map +1 -1
  31. package/dist/DatePicker.d.ts +101 -5
  32. package/dist/DatePicker.d.ts.map +1 -1
  33. package/dist/DateRangePickerContext.d.ts +30 -0
  34. package/dist/DateRangePickerContext.d.ts.map +1 -0
  35. package/dist/Dialog.d.ts +5 -5
  36. package/dist/Dialog.d.ts.map +1 -1
  37. package/dist/Disclosure.d.ts +25 -5
  38. package/dist/Disclosure.d.ts.map +1 -1
  39. package/dist/DragAndDrop.d.ts +80 -0
  40. package/dist/DragAndDrop.d.ts.map +1 -0
  41. package/dist/DragPreview.d.ts +14 -0
  42. package/dist/DragPreview.d.ts.map +1 -0
  43. package/dist/DropZone.d.ts +27 -0
  44. package/dist/DropZone.d.ts.map +1 -0
  45. package/dist/FieldError.d.ts +27 -0
  46. package/dist/FieldError.d.ts.map +1 -0
  47. package/dist/FileTrigger.d.ts +26 -0
  48. package/dist/FileTrigger.d.ts.map +1 -0
  49. package/dist/Focusable.d.ts +27 -0
  50. package/dist/Focusable.d.ts.map +1 -0
  51. package/dist/Form.d.ts +41 -0
  52. package/dist/Form.d.ts.map +1 -0
  53. package/dist/GridList.d.ts +69 -10
  54. package/dist/GridList.d.ts.map +1 -1
  55. package/dist/HiddenDateInput.d.ts +26 -0
  56. package/dist/HiddenDateInput.d.ts.map +1 -0
  57. package/dist/HiddenTimeInput.d.ts +25 -0
  58. package/dist/HiddenTimeInput.d.ts.map +1 -0
  59. package/dist/Icon.d.ts +57 -0
  60. package/dist/Icon.d.ts.map +1 -0
  61. package/dist/Keyboard.d.ts +13 -0
  62. package/dist/Keyboard.d.ts.map +1 -0
  63. package/dist/Landmark.d.ts +3 -3
  64. package/dist/Landmark.d.ts.map +1 -1
  65. package/dist/Link.d.ts +10 -4
  66. package/dist/Link.d.ts.map +1 -1
  67. package/dist/ListBox.d.ts +73 -11
  68. package/dist/ListBox.d.ts.map +1 -1
  69. package/dist/ListDropTargetDelegate.d.ts +38 -0
  70. package/dist/ListDropTargetDelegate.d.ts.map +1 -0
  71. package/dist/Menu.d.ts +79 -10
  72. package/dist/Menu.d.ts.map +1 -1
  73. package/dist/Meter.d.ts +4 -4
  74. package/dist/Meter.d.ts.map +1 -1
  75. package/dist/Modal.d.ts +6 -4
  76. package/dist/Modal.d.ts.map +1 -1
  77. package/dist/NumberField.d.ts +10 -12
  78. package/dist/NumberField.d.ts.map +1 -1
  79. package/dist/Popover.d.ts +32 -7
  80. package/dist/Popover.d.ts.map +1 -1
  81. package/dist/Pressable.d.ts +27 -0
  82. package/dist/Pressable.d.ts.map +1 -0
  83. package/dist/ProgressBar.d.ts +6 -4
  84. package/dist/ProgressBar.d.ts.map +1 -1
  85. package/dist/RadioGroup.d.ts +43 -9
  86. package/dist/RadioGroup.d.ts.map +1 -1
  87. package/dist/RangeCalendar.d.ts +39 -7
  88. package/dist/RangeCalendar.d.ts.map +1 -1
  89. package/dist/RouterProvider.d.ts +75 -0
  90. package/dist/RouterProvider.d.ts.map +1 -0
  91. package/dist/SearchField.d.ts +23 -21
  92. package/dist/SearchField.d.ts.map +1 -1
  93. package/dist/Select.d.ts +48 -7
  94. package/dist/Select.d.ts.map +1 -1
  95. package/dist/SelectionIndicator.d.ts +30 -0
  96. package/dist/SelectionIndicator.d.ts.map +1 -0
  97. package/dist/Separator.d.ts +9 -3
  98. package/dist/Separator.d.ts.map +1 -1
  99. package/dist/SharedElementTransition.d.ts +41 -0
  100. package/dist/SharedElementTransition.d.ts.map +1 -0
  101. package/dist/Slider.d.ts +15 -8
  102. package/dist/Slider.d.ts.map +1 -1
  103. package/dist/StepList.d.ts +90 -0
  104. package/dist/StepList.d.ts.map +1 -0
  105. package/dist/Switch.d.ts +11 -5
  106. package/dist/Switch.d.ts.map +1 -1
  107. package/dist/Table.d.ts +222 -19
  108. package/dist/Table.d.ts.map +1 -1
  109. package/dist/Tabs.d.ts +47 -10
  110. package/dist/Tabs.d.ts.map +1 -1
  111. package/dist/TagGroup.d.ts +22 -10
  112. package/dist/TagGroup.d.ts.map +1 -1
  113. package/dist/Text.d.ts +10 -0
  114. package/dist/Text.d.ts.map +1 -0
  115. package/dist/TextField.d.ts +19 -11
  116. package/dist/TextField.d.ts.map +1 -1
  117. package/dist/TimeField.d.ts +32 -7
  118. package/dist/TimeField.d.ts.map +1 -1
  119. package/dist/Toast.d.ts +29 -14
  120. package/dist/Toast.d.ts.map +1 -1
  121. package/dist/ToggleButton.d.ts +36 -0
  122. package/dist/ToggleButton.d.ts.map +1 -0
  123. package/dist/ToggleButtonGroup.d.ts +33 -0
  124. package/dist/ToggleButtonGroup.d.ts.map +1 -0
  125. package/dist/Toolbar.d.ts +7 -3
  126. package/dist/Toolbar.d.ts.map +1 -1
  127. package/dist/Tooltip.d.ts +58 -7
  128. package/dist/Tooltip.d.ts.map +1 -1
  129. package/dist/Tree.d.ts +102 -11
  130. package/dist/Tree.d.ts.map +1 -1
  131. package/dist/Virtualizer.d.ts +61 -0
  132. package/dist/Virtualizer.d.ts.map +1 -0
  133. package/dist/VirtualizerLayouts.d.ts +82 -0
  134. package/dist/VirtualizerLayouts.d.ts.map +1 -0
  135. package/dist/VisuallyHidden.d.ts +4 -2
  136. package/dist/VisuallyHidden.d.ts.map +1 -1
  137. package/dist/contexts.d.ts +6 -1
  138. package/dist/contexts.d.ts.map +1 -1
  139. package/dist/index.d.ts +73 -39
  140. package/dist/index.d.ts.map +1 -1
  141. package/dist/index.js +23342 -10644
  142. package/dist/index.js.map +1 -7
  143. package/dist/index.jsx +18110 -0
  144. package/dist/index.jsx.map +1 -0
  145. package/dist/useDragAndDrop.d.ts +93 -0
  146. package/dist/useDragAndDrop.d.ts.map +1 -0
  147. package/dist/utils.d.ts +8 -2
  148. package/dist/utils.d.ts.map +1 -1
  149. package/dist/virtualizer/Layout.d.ts +79 -0
  150. package/dist/virtualizer/Layout.d.ts.map +1 -0
  151. package/package.json +33 -32
  152. package/src/ActionBar.tsx +251 -0
  153. package/src/ActionGroup.tsx +277 -0
  154. package/src/Alert.tsx +152 -0
  155. package/src/Autocomplete.tsx +39 -44
  156. package/src/Breadcrumbs.tsx +227 -72
  157. package/src/Button.tsx +315 -74
  158. package/src/Calendar.tsx +347 -141
  159. package/src/Checkbox.tsx +414 -123
  160. package/src/Collection.tsx +350 -0
  161. package/src/Color.tsx +1325 -284
  162. package/src/ColorEditor.tsx +213 -0
  163. package/src/ComboBox.tsx +644 -245
  164. package/src/ContextualHelpTrigger.tsx +195 -0
  165. package/src/DateField.tsx +274 -106
  166. package/src/DatePicker.tsx +892 -111
  167. package/src/DateRangePickerContext.tsx +44 -0
  168. package/src/Dialog.tsx +173 -104
  169. package/src/Disclosure.tsx +158 -105
  170. package/src/DragAndDrop.tsx +340 -0
  171. package/src/DragPreview.tsx +47 -0
  172. package/src/DropZone.tsx +233 -0
  173. package/src/FieldError.tsx +89 -0
  174. package/src/FileTrigger.tsx +83 -0
  175. package/src/Focusable.tsx +103 -0
  176. package/src/Form.tsx +140 -0
  177. package/src/GridList.tsx +542 -128
  178. package/src/HiddenDateInput.tsx +153 -0
  179. package/src/HiddenTimeInput.tsx +133 -0
  180. package/src/Icon.tsx +133 -0
  181. package/src/Keyboard.tsx +26 -0
  182. package/src/Landmark.tsx +37 -63
  183. package/src/Link.tsx +132 -69
  184. package/src/ListBox.tsx +656 -106
  185. package/src/ListDropTargetDelegate.ts +283 -0
  186. package/src/Menu.tsx +1234 -132
  187. package/src/Meter.tsx +44 -58
  188. package/src/Modal.tsx +262 -166
  189. package/src/NumberField.tsx +267 -151
  190. package/src/Popover.tsx +452 -343
  191. package/src/Pressable.tsx +108 -0
  192. package/src/ProgressBar.tsx +54 -59
  193. package/src/RadioGroup.tsx +533 -121
  194. package/src/RangeCalendar.tsx +249 -150
  195. package/src/RouterProvider.tsx +223 -0
  196. package/src/SearchField.tsx +460 -133
  197. package/src/Select.tsx +804 -233
  198. package/src/SelectionIndicator.tsx +108 -0
  199. package/src/Separator.tsx +47 -49
  200. package/src/SharedElementTransition.tsx +264 -0
  201. package/src/Slider.tsx +148 -98
  202. package/src/StepList.tsx +272 -0
  203. package/src/Switch.tsx +93 -46
  204. package/src/Table.tsx +1551 -225
  205. package/src/Tabs.tsx +377 -123
  206. package/src/TagGroup.tsx +233 -135
  207. package/src/Text.tsx +18 -0
  208. package/src/TextField.tsx +413 -86
  209. package/src/TimeField.tsx +232 -222
  210. package/src/Toast.tsx +306 -160
  211. package/src/ToggleButton.tsx +169 -0
  212. package/src/ToggleButtonGroup.tsx +141 -0
  213. package/src/Toolbar.tsx +61 -70
  214. package/src/Tooltip.tsx +473 -116
  215. package/src/Tree.tsx +1514 -175
  216. package/src/Virtualizer.tsx +730 -0
  217. package/src/VirtualizerLayouts.ts +280 -0
  218. package/src/VisuallyHidden.tsx +32 -38
  219. package/src/contexts.ts +29 -36
  220. package/src/index.ts +972 -620
  221. package/src/useDragAndDrop.ts +367 -0
  222. package/src/utils.tsx +69 -50
  223. package/src/virtualizer/Layout.ts +192 -0
  224. package/dist/index.ssr.js +0 -9785
  225. package/dist/index.ssr.js.map +0 -7
@@ -7,21 +7,24 @@
7
7
 
8
8
  import {
9
9
  type JSX,
10
+ type Accessor,
10
11
  createContext,
11
12
  createMemo,
12
13
  createSignal,
13
14
  splitProps,
14
15
  useContext,
15
16
  For,
17
+ Index,
16
18
  Show,
17
- } from 'solid-js';
19
+ } from "solid-js";
18
20
  import {
19
21
  createRangeCalendar,
20
22
  createCalendarGrid,
21
23
  createRangeCalendarCell,
24
+ createHover,
22
25
  type AriaRangeCalendarProps,
23
26
  type AriaCalendarGridProps,
24
- } from '@proyecto-viviana/solidaria';
27
+ } from "@proyecto-viviana/solidaria";
25
28
  import {
26
29
  createRangeCalendarState,
27
30
  type RangeCalendarState,
@@ -29,7 +32,9 @@ import {
29
32
  type CalendarDate,
30
33
  type DateValue,
31
34
  type RangeValue,
32
- } from '@proyecto-viviana/solid-stately';
35
+ endOfMonth,
36
+ isSameMonth,
37
+ } from "@proyecto-viviana/solid-stately";
33
38
  import {
34
39
  type RenderChildren,
35
40
  type ClassNameOrFunction,
@@ -38,24 +43,38 @@ import {
38
43
  useRenderProps,
39
44
  dataAttr,
40
45
  useIsHydrated,
41
- } from './utils';
46
+ } from "./utils";
47
+ import { VisuallyHidden } from "./VisuallyHidden";
42
48
 
43
- // ============================================
44
- // TYPES
45
- // ============================================
49
+ type RefLike<T> = ((el: T) => void) | { current?: T | null } | undefined;
50
+
51
+ function assignRef<T>(ref: RefLike<T>, el: T): void {
52
+ if (!ref) {
53
+ return;
54
+ }
55
+
56
+ if (typeof ref === "function") {
57
+ ref(el);
58
+ } else {
59
+ ref.current = el;
60
+ }
61
+ }
46
62
 
47
63
  export interface RangeCalendarRenderProps {
48
64
  /** Whether the calendar is disabled. */
49
65
  isDisabled: boolean;
50
66
  /** Whether the calendar is read-only. */
51
67
  isReadOnly: boolean;
68
+ /** Whether the current selection is invalid. */
69
+ isInvalid: boolean;
52
70
  /** Whether the user is currently selecting a range. */
53
71
  isDragging: boolean;
54
72
  }
55
73
 
56
74
  export interface RangeCalendarProps<T extends DateValue = DateValue>
57
- extends Omit<AriaRangeCalendarProps, 'id' | 'isDisabled' | 'isReadOnly'>,
58
- Omit<RangeCalendarStateProps<T>, 'locale'>,
75
+ extends
76
+ Omit<AriaRangeCalendarProps, "id" | "isDisabled" | "isReadOnly">,
77
+ Omit<RangeCalendarStateProps<T>, "locale">,
59
78
  SlotProps {
60
79
  /** The children of the component. */
61
80
  children?: JSX.Element;
@@ -65,6 +84,8 @@ export interface RangeCalendarProps<T extends DateValue = DateValue>
65
84
  style?: StyleOrFunction<RangeCalendarRenderProps>;
66
85
  /** The locale to use for formatting. */
67
86
  locale?: string;
87
+ /** Ref for the range calendar root element. */
88
+ ref?: RefLike<HTMLDivElement>;
68
89
  }
69
90
 
70
91
  export interface RangeCalendarGridRenderProps {
@@ -72,13 +93,20 @@ export interface RangeCalendarGridRenderProps {
72
93
  isDisabled: boolean;
73
94
  }
74
95
 
75
- export interface RangeCalendarGridProps extends Omit<AriaCalendarGridProps, 'startDate' | 'endDate'>, SlotProps {
96
+ export interface RangeCalendarGridProps
97
+ extends Omit<AriaCalendarGridProps, "startDate" | "endDate">, SlotProps {
76
98
  /** The children of the component (render function receiving dates). */
77
99
  children?: (date: CalendarDate) => JSX.Element;
78
100
  /** The CSS className for the element. */
79
101
  class?: ClassNameOrFunction<RangeCalendarGridRenderProps>;
80
102
  /** The inline style for the element. */
81
103
  style?: StyleOrFunction<RangeCalendarGridRenderProps>;
104
+ /** Class name for weekday header cells. */
105
+ headerCellClass?: string;
106
+ /** Inline style for weekday header cells. */
107
+ headerCellStyle?: JSX.CSSProperties;
108
+ /** Number of months to offset from the start. */
109
+ offset?: { months?: number };
82
110
  }
83
111
 
84
112
  export interface RangeCalendarCellRenderProps {
@@ -94,12 +122,24 @@ export interface RangeCalendarCellRenderProps {
94
122
  isDisabled: boolean;
95
123
  /** Whether the cell is unavailable. */
96
124
  isUnavailable: boolean;
125
+ /** Whether the cell is part of an invalid selection. */
126
+ isInvalid: boolean;
97
127
  /** Whether the cell is outside the visible month. */
98
128
  isOutsideMonth: boolean;
99
129
  /** Whether the cell represents today. */
100
130
  isToday: boolean;
101
131
  /** Whether the cell is pressed. */
102
132
  isPressed: boolean;
133
+ /** Whether the cell is hovered. */
134
+ isHovered: boolean;
135
+ /** Whether the cell is the first day slot in its row. */
136
+ isFirstChild: boolean;
137
+ /** Whether the cell is the last day slot in its row. */
138
+ isLastChild: boolean;
139
+ /** Whether the cell is in the first rendered week row. */
140
+ isFirstWeek: boolean;
141
+ /** Whether the cell is in the last rendered week row. */
142
+ isLastWeek: boolean;
103
143
  /** The formatted date string. */
104
144
  formattedDate: string;
105
145
  }
@@ -113,26 +153,29 @@ export interface RangeCalendarCellProps extends SlotProps {
113
153
  class?: ClassNameOrFunction<RangeCalendarCellRenderProps>;
114
154
  /** The inline style for the element. */
115
155
  style?: StyleOrFunction<RangeCalendarCellRenderProps>;
156
+ /** Class name for the table cell wrapper. */
157
+ cellClass?: ClassNameOrFunction<RangeCalendarCellRenderProps>;
158
+ /** Inline style for the table cell wrapper. */
159
+ cellStyle?: StyleOrFunction<RangeCalendarCellRenderProps>;
116
160
  }
117
161
 
118
- // ============================================
119
- // CONTEXT
120
- // ============================================
121
-
122
162
  export const RangeCalendarContext = createContext<RangeCalendarState<DateValue> | null>(null);
163
+ export const RangeCalendarStateContext = createContext<RangeCalendarState<DateValue> | null>(null);
164
+ const RangeCalendarGridMonthContext = createContext<Accessor<CalendarDate> | null>(null);
165
+ const RangeCalendarGridCellPositionContext = createContext<Accessor<{
166
+ weekIndex: number;
167
+ dayIndex: number;
168
+ lastWeekIndex: number;
169
+ }> | null>(null);
123
170
 
124
171
  export function useRangeCalendarContext(): RangeCalendarState<DateValue> {
125
172
  const context = useContext(RangeCalendarContext);
126
173
  if (!context) {
127
- throw new Error('RangeCalendar components must be used within a RangeCalendar');
174
+ throw new Error("RangeCalendar components must be used within a RangeCalendar");
128
175
  }
129
176
  return context;
130
177
  }
131
178
 
132
- // ============================================
133
- // RANGE CALENDAR COMPONENT
134
- // ============================================
135
-
136
179
  /**
137
180
  * A range calendar displays a grid of days and allows users to select a contiguous range of dates.
138
181
  *
@@ -151,7 +194,7 @@ export function useRangeCalendarContext(): RangeCalendarState<DateValue> {
151
194
  * ```
152
195
  */
153
196
  export function RangeCalendar<T extends DateValue = CalendarDate>(
154
- props: RangeCalendarProps<T>
197
+ props: RangeCalendarProps<T>,
155
198
  ): JSX.Element {
156
199
  // Use hydration-safe pattern for client-only rendering
157
200
  const isHydrated = useIsHydrated();
@@ -159,7 +202,12 @@ export function RangeCalendar<T extends DateValue = CalendarDate>(
159
202
  return (
160
203
  <Show
161
204
  when={isHydrated()}
162
- fallback={<div class="solidaria-RangeCalendar solidaria-RangeCalendar--placeholder" aria-hidden="true" />}
205
+ fallback={
206
+ <div
207
+ class="solidaria-RangeCalendar solidaria-RangeCalendar--placeholder"
208
+ aria-hidden="true"
209
+ />
210
+ }
163
211
  >
164
212
  <RangeCalendarInner {...props} />
165
213
  </Show>
@@ -170,75 +218,78 @@ export function RangeCalendar<T extends DateValue = CalendarDate>(
170
218
  * Internal RangeCalendar component that renders after client mount.
171
219
  */
172
220
  function RangeCalendarInner<T extends DateValue = CalendarDate>(
173
- props: RangeCalendarProps<T>
221
+ props: RangeCalendarProps<T>,
174
222
  ): JSX.Element {
175
223
  const [local, stateProps, rest] = splitProps(
176
224
  props,
177
- ['children', 'class', 'style', 'slot'],
225
+ ["children", "class", "style", "slot", "ref"],
178
226
  [
179
- 'value',
180
- 'defaultValue',
181
- 'onChange',
182
- 'minValue',
183
- 'maxValue',
184
- 'isDisabled',
185
- 'isReadOnly',
186
- 'focusedValue',
187
- 'defaultFocusedValue',
188
- 'onFocusChange',
189
- 'locale',
190
- 'isDateUnavailable',
191
- 'visibleMonths',
192
- 'isDateDisabled',
193
- 'validationState',
194
- 'allowsNonContiguousRanges',
195
- 'firstDayOfWeek',
196
- ]
227
+ "value",
228
+ "defaultValue",
229
+ "onChange",
230
+ "minValue",
231
+ "maxValue",
232
+ "isDisabled",
233
+ "isReadOnly",
234
+ "focusedValue",
235
+ "defaultFocusedValue",
236
+ "onFocusChange",
237
+ "locale",
238
+ "createCalendar",
239
+ "isDateUnavailable",
240
+ "visibleMonths",
241
+ "pageBehavior",
242
+ "selectionAlignment",
243
+ "isDateDisabled",
244
+ "validationState",
245
+ "allowsNonContiguousRanges",
246
+ "firstDayOfWeek",
247
+ ],
197
248
  );
198
249
 
199
- // Create range calendar state
200
250
  const state = createRangeCalendarState(stateProps);
201
251
 
202
- // Create range calendar ARIA props
203
252
  const calendarAria = createRangeCalendar(rest, state as unknown as RangeCalendarState<DateValue>);
204
253
 
205
- // Render props values
206
254
  const renderValues = createMemo<RangeCalendarRenderProps>(() => ({
207
255
  isDisabled: state.isDisabled(),
208
256
  isReadOnly: state.isReadOnly(),
257
+ isInvalid: state.isValueInvalid(),
209
258
  isDragging: state.isDragging(),
210
259
  }));
211
260
 
212
- // Resolve render props
213
261
  const renderProps = useRenderProps(
214
262
  {
215
263
  class: local.class,
216
264
  style: local.style,
217
- defaultClassName: 'solidaria-RangeCalendar',
265
+ defaultClassName: "solidaria-RangeCalendar",
218
266
  },
219
- renderValues
267
+ renderValues,
220
268
  );
221
269
 
222
270
  return (
223
- <RangeCalendarContext.Provider value={state as unknown as RangeCalendarState<DateValue>}>
224
- <div
225
- {...calendarAria.calendarProps}
226
- class={renderProps.class()}
227
- style={renderProps.style()}
228
- data-disabled={dataAttr(state.isDisabled())}
229
- data-readonly={dataAttr(state.isReadOnly())}
230
- data-dragging={dataAttr(state.isDragging())}
231
- >
232
- {props.children}
233
- </div>
234
- </RangeCalendarContext.Provider>
271
+ <RangeCalendarStateContext.Provider value={state as unknown as RangeCalendarState<DateValue>}>
272
+ <RangeCalendarContext.Provider value={state as unknown as RangeCalendarState<DateValue>}>
273
+ <div
274
+ {...calendarAria.calendarProps}
275
+ ref={(el) => assignRef(local.ref, el)}
276
+ class={renderProps.class()}
277
+ style={renderProps.style()}
278
+ data-disabled={dataAttr(state.isDisabled())}
279
+ data-readonly={dataAttr(state.isReadOnly())}
280
+ data-invalid={dataAttr(state.isValueInvalid())}
281
+ data-dragging={dataAttr(state.isDragging())}
282
+ >
283
+ <VisuallyHidden>
284
+ <h2>{String(calendarAria.calendarProps["aria-label"] ?? "")}</h2>
285
+ </VisuallyHidden>
286
+ {props.children}
287
+ </div>
288
+ </RangeCalendarContext.Provider>
289
+ </RangeCalendarStateContext.Provider>
235
290
  );
236
291
  }
237
292
 
238
- // ============================================
239
- // RANGE CALENDAR HEADING COMPONENT
240
- // ============================================
241
-
242
293
  export interface RangeCalendarHeadingProps extends SlotProps {
243
294
  /** The CSS className for the element. */
244
295
  class?: string;
@@ -254,7 +305,7 @@ export function RangeCalendarHeading(props: RangeCalendarHeadingProps): JSX.Elem
254
305
 
255
306
  return (
256
307
  <h2
257
- class={props.class ?? 'solidaria-RangeCalendarHeading'}
308
+ class={props.class ?? "solidaria-RangeCalendarHeading"}
258
309
  style={props.style}
259
310
  aria-live="polite"
260
311
  >
@@ -263,13 +314,9 @@ export function RangeCalendarHeading(props: RangeCalendarHeadingProps): JSX.Elem
263
314
  );
264
315
  }
265
316
 
266
- // ============================================
267
- // RANGE CALENDAR BUTTON COMPONENT
268
- // ============================================
269
-
270
317
  export interface RangeCalendarButtonProps extends SlotProps {
271
318
  /** The slot for this button (previous or next). */
272
- slot?: 'previous' | 'next';
319
+ slot?: "previous" | "next";
273
320
  /** The children of the component. */
274
321
  children?: JSX.Element;
275
322
  /** The CSS className for the element. */
@@ -288,123 +335,158 @@ export function RangeCalendarButton(props: RangeCalendarButtonProps): JSX.Elemen
288
335
  const calendarAria = createRangeCalendar({}, state);
289
336
 
290
337
  const buttonProps = createMemo(() => {
291
- if (props.slot === 'previous') {
338
+ if (props.slot === "previous") {
292
339
  return calendarAria.prevButtonProps;
293
340
  }
294
341
  return calendarAria.nextButtonProps;
295
342
  });
343
+ const isDisabled = createMemo(
344
+ () => props.isDisabled || Boolean(buttonProps().disabled) || state.isDisabled(),
345
+ );
296
346
 
297
347
  return (
298
348
  <button
299
349
  {...buttonProps()}
300
- class={props.class ?? 'solidaria-RangeCalendarButton'}
350
+ class={props.class ?? "solidaria-RangeCalendarButton"}
301
351
  style={props.style}
302
- disabled={props.isDisabled || state.isDisabled()}
352
+ disabled={isDisabled()}
303
353
  >
304
354
  {props.children}
305
355
  </button>
306
356
  );
307
357
  }
308
358
 
309
- // ============================================
310
- // RANGE CALENDAR GRID COMPONENT
311
- // ============================================
312
-
313
359
  /**
314
360
  * Displays a grid of range calendar cells.
315
361
  */
316
362
  export function RangeCalendarGrid(props: RangeCalendarGridProps): JSX.Element {
317
363
  const state = useRangeCalendarContext();
318
364
  const [gridRef, setGridRef] = createSignal<HTMLTableElement | null>(null);
365
+ const startDate = createMemo(() => {
366
+ const offsetMonths = props.offset?.months ?? 0;
367
+ const baseStart = state.visibleRange().start;
368
+ return offsetMonths ? baseStart.add({ months: offsetMonths }) : baseStart;
369
+ });
319
370
 
320
- // Create grid ARIA props
321
371
  const gridAria = createCalendarGrid(
322
372
  {
373
+ startDate: startDate(),
374
+ endDate: endOfMonth(startDate()),
323
375
  weekdayStyle: props.weekdayStyle,
324
376
  },
325
377
  state as unknown as Parameters<typeof createCalendarGrid>[1],
326
- gridRef
378
+ gridRef,
327
379
  );
328
380
 
329
- // Render props values
330
381
  const renderValues = createMemo<RangeCalendarGridRenderProps>(() => ({
331
382
  isDisabled: state.isDisabled(),
332
383
  }));
333
384
 
334
- // Resolve render props
335
385
  const renderProps = useRenderProps(
336
386
  {
337
387
  class: props.class,
338
388
  style: props.style,
339
- defaultClassName: 'solidaria-RangeCalendarGrid',
389
+ defaultClassName: "solidaria-RangeCalendarGrid",
340
390
  },
341
- renderValues
391
+ renderValues,
342
392
  );
343
393
 
344
- // Get weeks to render
345
- const weeks = createMemo(() => {
346
- const numWeeks = state.getWeeksInMonth();
347
- return Array.from({ length: numWeeks }, (_, i) => i);
394
+ // Memoize all dates for the grid to avoid reactive loops in render paths.
395
+ const allDates = createMemo(() => {
396
+ const monthStart = startDate();
397
+ const numWeeks = state.getWeeksInMonth(monthStart);
398
+ const weekDates: (CalendarDate | null)[][] = [];
399
+
400
+ for (let weekIndex = 0; weekIndex < numWeeks; weekIndex++) {
401
+ weekDates.push(state.getDatesInWeek(weekIndex, monthStart));
402
+ }
403
+
404
+ return weekDates;
348
405
  });
349
406
 
350
407
  return (
351
- <table
352
- ref={setGridRef}
353
- {...gridAria.gridProps}
354
- class={renderProps.class()}
355
- style={renderProps.style()}
356
- >
357
- <thead {...gridAria.headerProps}>
358
- <tr>
359
- <For each={gridAria.weekDays}>
360
- {(day) => (
361
- <th scope="col" class="solidaria-RangeCalendarHeaderCell">
362
- {day}
363
- </th>
408
+ <RangeCalendarGridMonthContext.Provider value={startDate}>
409
+ <table
410
+ ref={setGridRef}
411
+ {...gridAria.gridProps}
412
+ class={renderProps.class()}
413
+ style={renderProps.style()}
414
+ >
415
+ <thead {...gridAria.headerProps}>
416
+ <tr>
417
+ <For each={gridAria.weekDays}>
418
+ {(day) => (
419
+ <th
420
+ scope="col"
421
+ class={props.headerCellClass ?? "solidaria-RangeCalendarHeaderCell"}
422
+ style={props.headerCellStyle}
423
+ >
424
+ {day}
425
+ </th>
426
+ )}
427
+ </For>
428
+ </tr>
429
+ </thead>
430
+ <tbody>
431
+ <Index each={allDates()}>
432
+ {(weekDates, weekIndex) => (
433
+ <tr>
434
+ <Index each={weekDates()}>
435
+ {(date, dayIndex) => (
436
+ <Show when={date()} fallback={<td />}>
437
+ <RangeCalendarGridCellPositionContext.Provider
438
+ value={() => ({
439
+ weekIndex,
440
+ dayIndex,
441
+ lastWeekIndex: allDates().length - 1,
442
+ })}
443
+ >
444
+ {props.children?.(date()!)}
445
+ </RangeCalendarGridCellPositionContext.Provider>
446
+ </Show>
447
+ )}
448
+ </Index>
449
+ </tr>
364
450
  )}
365
- </For>
366
- </tr>
367
- </thead>
368
- <tbody>
369
- <For each={weeks()}>
370
- {(weekIndex) => (
371
- <tr>
372
- <For each={state.getDatesInWeek(weekIndex)}>
373
- {(date) => (
374
- <Show when={date}>
375
- <td>
376
- {props.children?.(date!)}
377
- </td>
378
- </Show>
379
- )}
380
- </For>
381
- </tr>
382
- )}
383
- </For>
384
- </tbody>
385
- </table>
451
+ </Index>
452
+ </tbody>
453
+ </table>
454
+ </RangeCalendarGridMonthContext.Provider>
386
455
  );
387
456
  }
388
457
 
389
- // ============================================
390
- // RANGE CALENDAR CELL COMPONENT
391
- // ============================================
392
-
393
458
  /**
394
459
  * A cell in the range calendar grid representing a single day.
395
460
  */
396
461
  export function RangeCalendarCell(props: RangeCalendarCellProps): JSX.Element {
397
462
  const state = useRangeCalendarContext();
463
+ const currentMonthStart = useContext(RangeCalendarGridMonthContext);
464
+ const cellPosition = useContext(RangeCalendarGridCellPositionContext);
398
465
  const [cellRef, setCellRef] = createSignal<HTMLDivElement | null>(null);
466
+ const isOutsideMonth = createMemo(
467
+ () => currentMonthStart != null && !isSameMonth(currentMonthStart(), props.date),
468
+ );
469
+ const position = createMemo(
470
+ () =>
471
+ cellPosition?.() ?? {
472
+ weekIndex: 0,
473
+ dayIndex: 0,
474
+ lastWeekIndex: 0,
475
+ },
476
+ );
399
477
 
400
- // Create cell ARIA props
401
478
  const cellAria = createRangeCalendarCell(
402
- { date: props.date },
479
+ () => ({
480
+ date: props.date,
481
+ isOutsideMonth: isOutsideMonth(),
482
+ }),
403
483
  state,
404
- cellRef
484
+ cellRef,
405
485
  );
486
+ const { hoverProps, isHovered } = createHover(() => ({
487
+ isDisabled: cellAria.isDisabled || cellAria.isUnavailable,
488
+ }));
406
489
 
407
- // Render props values
408
490
  const renderValues = createMemo<RangeCalendarCellRenderProps>(() => ({
409
491
  isSelected: cellAria.isSelected,
410
492
  isSelectionStart: cellAria.isSelectionStart,
@@ -412,51 +494,68 @@ export function RangeCalendarCell(props: RangeCalendarCellProps): JSX.Element {
412
494
  isFocused: cellAria.isFocused,
413
495
  isDisabled: cellAria.isDisabled,
414
496
  isUnavailable: cellAria.isUnavailable,
497
+ isInvalid: cellAria.isInvalid,
415
498
  isOutsideMonth: cellAria.isOutsideMonth,
416
499
  isToday: cellAria.isToday,
417
500
  isPressed: cellAria.isPressed,
501
+ isHovered: isHovered(),
502
+ isFirstChild: position().dayIndex === 0,
503
+ isLastChild: position().dayIndex === 6,
504
+ isFirstWeek: position().weekIndex === 0,
505
+ isLastWeek: position().weekIndex === position().lastWeekIndex,
418
506
  formattedDate: cellAria.formattedDate,
419
507
  }));
420
508
 
421
- // Resolve render props
422
509
  const renderProps = useRenderProps(
423
510
  {
424
511
  children: props.children,
425
512
  class: props.class,
426
513
  style: props.style,
427
- defaultClassName: 'solidaria-RangeCalendarCell',
514
+ defaultClassName: "solidaria-RangeCalendarCell",
428
515
  },
429
- renderValues
516
+ renderValues,
517
+ );
518
+ const cellRenderProps = useRenderProps(
519
+ {
520
+ class: props.cellClass,
521
+ style: props.cellStyle,
522
+ defaultClassName: "solidaria-RangeCalendarCellWrapper",
523
+ },
524
+ renderValues,
430
525
  );
431
526
 
432
527
  // Determine children content - avoid Show for SSR hydration compatibility
433
528
  const getChildren = () => {
434
- if (typeof props.children === 'function') {
529
+ if (typeof props.children === "function") {
435
530
  return renderProps.renderChildren();
436
531
  }
437
532
  return cellAria.formattedDate;
438
533
  };
439
534
 
440
535
  return (
441
- <div
442
- ref={setCellRef}
443
- {...cellAria.buttonProps}
444
- class={renderProps.class()}
445
- style={renderProps.style()}
446
- data-selected={dataAttr(cellAria.isSelected)}
447
- data-selection-start={dataAttr(cellAria.isSelectionStart)}
448
- data-selection-end={dataAttr(cellAria.isSelectionEnd)}
449
- data-focused={dataAttr(cellAria.isFocused)}
450
- data-disabled={dataAttr(cellAria.isDisabled)}
451
- data-unavailable={dataAttr(cellAria.isUnavailable)}
452
- data-outside-month={dataAttr(cellAria.isOutsideMonth)}
453
- data-today={dataAttr(cellAria.isToday)}
454
- data-pressed={dataAttr(cellAria.isPressed)}
455
- >
456
- {getChildren()}
457
- </div>
536
+ <td {...cellAria.cellProps} class={cellRenderProps.class()} style={cellRenderProps.style()}>
537
+ <div
538
+ ref={setCellRef}
539
+ {...cellAria.buttonProps}
540
+ {...hoverProps}
541
+ class={renderProps.class()}
542
+ style={renderProps.style()}
543
+ data-selected={dataAttr(cellAria.isSelected)}
544
+ data-selection-start={dataAttr(cellAria.isSelectionStart)}
545
+ data-selection-end={dataAttr(cellAria.isSelectionEnd)}
546
+ data-focused={dataAttr(cellAria.isFocused)}
547
+ data-disabled={dataAttr(cellAria.isDisabled)}
548
+ data-unavailable={dataAttr(cellAria.isUnavailable)}
549
+ data-invalid={dataAttr(cellAria.isInvalid)}
550
+ data-outside-month={dataAttr(cellAria.isOutsideMonth)}
551
+ data-today={dataAttr(cellAria.isToday)}
552
+ data-pressed={dataAttr(cellAria.isPressed)}
553
+ data-hovered={dataAttr(isHovered())}
554
+ >
555
+ {getChildren()}
556
+ </div>
557
+ </td>
458
558
  );
459
559
  }
460
560
 
461
- // Re-export types
462
561
  export type { RangeCalendarState, RangeValue };