@proyecto-viviana/solidaria-components 0.2.5 → 0.2.9

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 (194) hide show
  1. package/LICENSE +21 -0
  2. package/dist/ActionBar.d.ts +71 -0
  3. package/dist/ActionBar.d.ts.map +1 -0
  4. package/dist/ActionGroup.d.ts +74 -0
  5. package/dist/ActionGroup.d.ts.map +1 -0
  6. package/dist/Alert.d.ts +70 -0
  7. package/dist/Alert.d.ts.map +1 -0
  8. package/dist/Breadcrumbs.d.ts +10 -2
  9. package/dist/Breadcrumbs.d.ts.map +1 -1
  10. package/dist/Button.d.ts +4 -0
  11. package/dist/Button.d.ts.map +1 -1
  12. package/dist/Calendar.d.ts +13 -0
  13. package/dist/Calendar.d.ts.map +1 -1
  14. package/dist/Checkbox.d.ts +2 -2
  15. package/dist/Checkbox.d.ts.map +1 -1
  16. package/dist/Collection.d.ts +125 -0
  17. package/dist/Collection.d.ts.map +1 -0
  18. package/dist/Color.d.ts +114 -2
  19. package/dist/Color.d.ts.map +1 -1
  20. package/dist/ColorEditor.d.ts +42 -0
  21. package/dist/ColorEditor.d.ts.map +1 -0
  22. package/dist/ComboBox.d.ts +64 -0
  23. package/dist/ComboBox.d.ts.map +1 -1
  24. package/dist/ContextualHelpTrigger.d.ts +40 -0
  25. package/dist/ContextualHelpTrigger.d.ts.map +1 -0
  26. package/dist/DateField.d.ts +27 -2
  27. package/dist/DateField.d.ts.map +1 -1
  28. package/dist/DatePicker.d.ts +67 -2
  29. package/dist/DatePicker.d.ts.map +1 -1
  30. package/dist/Dialog.d.ts.map +1 -1
  31. package/dist/Disclosure.d.ts +2 -0
  32. package/dist/Disclosure.d.ts.map +1 -1
  33. package/dist/DragAndDrop.d.ts +80 -0
  34. package/dist/DragAndDrop.d.ts.map +1 -0
  35. package/dist/DragPreview.d.ts +14 -0
  36. package/dist/DragPreview.d.ts.map +1 -0
  37. package/dist/DropZone.d.ts +27 -0
  38. package/dist/DropZone.d.ts.map +1 -0
  39. package/dist/FieldError.d.ts +23 -0
  40. package/dist/FieldError.d.ts.map +1 -0
  41. package/dist/FileTrigger.d.ts +26 -0
  42. package/dist/FileTrigger.d.ts.map +1 -0
  43. package/dist/Focusable.d.ts +27 -0
  44. package/dist/Focusable.d.ts.map +1 -0
  45. package/dist/Form.d.ts +27 -0
  46. package/dist/Form.d.ts.map +1 -0
  47. package/dist/GridList.d.ts +40 -1
  48. package/dist/GridList.d.ts.map +1 -1
  49. package/dist/Icon.d.ts +57 -0
  50. package/dist/Icon.d.ts.map +1 -0
  51. package/dist/Keyboard.d.ts +13 -0
  52. package/dist/Keyboard.d.ts.map +1 -0
  53. package/dist/Link.d.ts.map +1 -1
  54. package/dist/ListBox.d.ts +43 -1
  55. package/dist/ListBox.d.ts.map +1 -1
  56. package/dist/ListDropTargetDelegate.d.ts +38 -0
  57. package/dist/ListDropTargetDelegate.d.ts.map +1 -0
  58. package/dist/Menu.d.ts +20 -2
  59. package/dist/Menu.d.ts.map +1 -1
  60. package/dist/Meter.d.ts +2 -2
  61. package/dist/Meter.d.ts.map +1 -1
  62. package/dist/Modal.d.ts +2 -0
  63. package/dist/Modal.d.ts.map +1 -1
  64. package/dist/NumberField.d.ts +2 -0
  65. package/dist/NumberField.d.ts.map +1 -1
  66. package/dist/Popover.d.ts +4 -2
  67. package/dist/Popover.d.ts.map +1 -1
  68. package/dist/Pressable.d.ts +27 -0
  69. package/dist/Pressable.d.ts.map +1 -0
  70. package/dist/ProgressBar.d.ts +2 -2
  71. package/dist/ProgressBar.d.ts.map +1 -1
  72. package/dist/RadioGroup.d.ts.map +1 -1
  73. package/dist/RangeCalendar.d.ts +5 -0
  74. package/dist/RangeCalendar.d.ts.map +1 -1
  75. package/dist/RouterProvider.d.ts +75 -0
  76. package/dist/RouterProvider.d.ts.map +1 -0
  77. package/dist/SearchField.d.ts +2 -3
  78. package/dist/SearchField.d.ts.map +1 -1
  79. package/dist/Select.d.ts +11 -0
  80. package/dist/Select.d.ts.map +1 -1
  81. package/dist/SelectionIndicator.d.ts +30 -0
  82. package/dist/SelectionIndicator.d.ts.map +1 -0
  83. package/dist/SharedElementTransition.d.ts +39 -0
  84. package/dist/SharedElementTransition.d.ts.map +1 -0
  85. package/dist/Slider.d.ts +6 -3
  86. package/dist/Slider.d.ts.map +1 -1
  87. package/dist/Table.d.ts +39 -0
  88. package/dist/Table.d.ts.map +1 -1
  89. package/dist/Tabs.d.ts +4 -3
  90. package/dist/Tabs.d.ts.map +1 -1
  91. package/dist/TagGroup.d.ts +12 -2
  92. package/dist/TagGroup.d.ts.map +1 -1
  93. package/dist/Text.d.ts +10 -0
  94. package/dist/Text.d.ts.map +1 -0
  95. package/dist/TextField.d.ts +4 -0
  96. package/dist/TextField.d.ts.map +1 -1
  97. package/dist/TimeField.d.ts +26 -1
  98. package/dist/TimeField.d.ts.map +1 -1
  99. package/dist/Toast.d.ts.map +1 -1
  100. package/dist/ToggleButton.d.ts +30 -0
  101. package/dist/ToggleButton.d.ts.map +1 -0
  102. package/dist/ToggleButtonGroup.d.ts +33 -0
  103. package/dist/ToggleButtonGroup.d.ts.map +1 -0
  104. package/dist/Toolbar.d.ts.map +1 -1
  105. package/dist/Tooltip.d.ts +9 -0
  106. package/dist/Tooltip.d.ts.map +1 -1
  107. package/dist/Tree.d.ts +44 -2
  108. package/dist/Tree.d.ts.map +1 -1
  109. package/dist/Virtualizer.d.ts +61 -0
  110. package/dist/Virtualizer.d.ts.map +1 -0
  111. package/dist/VirtualizerLayouts.d.ts +82 -0
  112. package/dist/VirtualizerLayouts.d.ts.map +1 -0
  113. package/dist/VisuallyHidden.d.ts +3 -1
  114. package/dist/VisuallyHidden.d.ts.map +1 -1
  115. package/dist/contexts.d.ts +1 -0
  116. package/dist/contexts.d.ts.map +1 -1
  117. package/dist/index.d.ts +57 -25
  118. package/dist/index.d.ts.map +1 -1
  119. package/dist/index.js +13961 -5946
  120. package/dist/index.js.map +1 -7
  121. package/dist/index.ssr.js +9612 -2401
  122. package/dist/index.ssr.js.map +1 -7
  123. package/dist/useDragAndDrop.d.ts +93 -0
  124. package/dist/useDragAndDrop.d.ts.map +1 -0
  125. package/dist/utils.d.ts +7 -1
  126. package/dist/utils.d.ts.map +1 -1
  127. package/dist/virtualizer/Layout.d.ts +79 -0
  128. package/dist/virtualizer/Layout.d.ts.map +1 -0
  129. package/package.json +8 -6
  130. package/src/ActionBar.tsx +248 -0
  131. package/src/ActionGroup.tsx +285 -0
  132. package/src/Alert.tsx +177 -0
  133. package/src/Autocomplete.tsx +1 -1
  134. package/src/Breadcrumbs.tsx +103 -17
  135. package/src/Button.tsx +65 -21
  136. package/src/Calendar.tsx +179 -53
  137. package/src/Checkbox.tsx +1 -2
  138. package/src/Collection.tsx +341 -0
  139. package/src/Color.tsx +652 -34
  140. package/src/ColorEditor.tsx +231 -0
  141. package/src/ComboBox.tsx +315 -81
  142. package/src/ContextualHelpTrigger.tsx +183 -0
  143. package/src/DateField.tsx +93 -19
  144. package/src/DatePicker.tsx +495 -25
  145. package/src/Dialog.tsx +40 -9
  146. package/src/Disclosure.tsx +33 -27
  147. package/src/DragAndDrop.tsx +334 -0
  148. package/src/DragPreview.tsx +45 -0
  149. package/src/DropZone.tsx +213 -0
  150. package/src/FieldError.tsx +67 -0
  151. package/src/FileTrigger.tsx +83 -0
  152. package/src/Focusable.tsx +106 -0
  153. package/src/Form.tsx +85 -0
  154. package/src/GridList.tsx +379 -41
  155. package/src/Icon.tsx +154 -0
  156. package/src/Keyboard.tsx +26 -0
  157. package/src/Link.tsx +14 -1
  158. package/src/ListBox.tsx +484 -33
  159. package/src/ListDropTargetDelegate.ts +282 -0
  160. package/src/Menu.tsx +388 -35
  161. package/src/Meter.tsx +7 -3
  162. package/src/Modal.tsx +32 -4
  163. package/src/NumberField.tsx +163 -43
  164. package/src/Popover.tsx +136 -180
  165. package/src/Pressable.tsx +108 -0
  166. package/src/ProgressBar.tsx +7 -3
  167. package/src/RadioGroup.tsx +35 -25
  168. package/src/RangeCalendar.tsx +100 -68
  169. package/src/RouterProvider.tsx +240 -0
  170. package/src/SearchField.tsx +142 -34
  171. package/src/Select.tsx +221 -73
  172. package/src/SelectionIndicator.tsx +105 -0
  173. package/src/SharedElementTransition.tsx +258 -0
  174. package/src/Slider.tsx +16 -6
  175. package/src/Table.tsx +417 -57
  176. package/src/Tabs.tsx +68 -35
  177. package/src/TagGroup.tsx +121 -36
  178. package/src/Text.tsx +18 -0
  179. package/src/TextField.tsx +25 -8
  180. package/src/TimeField.tsx +101 -151
  181. package/src/Toast.tsx +108 -14
  182. package/src/ToggleButton.tsx +159 -0
  183. package/src/ToggleButtonGroup.tsx +136 -0
  184. package/src/Toolbar.tsx +14 -8
  185. package/src/Tooltip.tsx +108 -19
  186. package/src/Tree.tsx +1143 -87
  187. package/src/Virtualizer.tsx +702 -0
  188. package/src/VirtualizerLayouts.ts +265 -0
  189. package/src/VisuallyHidden.tsx +15 -21
  190. package/src/contexts.ts +1 -0
  191. package/src/index.ts +1057 -620
  192. package/src/useDragAndDrop.ts +351 -0
  193. package/src/utils.tsx +37 -3
  194. package/src/virtualizer/Layout.ts +200 -0
package/src/Button.tsx CHANGED
@@ -16,7 +16,9 @@ import {
16
16
  createButton,
17
17
  createFocusRing,
18
18
  createHover,
19
+ mergeProps,
19
20
  type AriaButtonProps,
21
+ type PressEvent,
20
22
  } from '@proyecto-viviana/solidaria';
21
23
  import {
22
24
  type RenderChildren,
@@ -43,6 +45,8 @@ export interface ButtonRenderProps {
43
45
  isFocusVisible: boolean;
44
46
  /** Whether the button is disabled. */
45
47
  isDisabled: boolean;
48
+ /** Whether the button is currently in a pending state. */
49
+ isPending: boolean;
46
50
  }
47
51
 
48
52
  export interface ButtonProps
@@ -54,6 +58,8 @@ export interface ButtonProps
54
58
  class?: ClassNameOrFunction<ButtonRenderProps>;
55
59
  /** The inline style for the element. */
56
60
  style?: StyleOrFunction<ButtonRenderProps>;
61
+ /** Whether the button is in a pending state. */
62
+ isPending?: boolean;
57
63
  }
58
64
 
59
65
  // ============================================
@@ -84,12 +90,16 @@ export const ButtonContext = createContext<ButtonProps | null>(null);
84
90
  * ```
85
91
  */
86
92
  export function Button(props: ButtonProps): JSX.Element {
93
+ const contextProps = useContext(ButtonContext);
94
+ const mergedProps = (contextProps ? mergeProps(contextProps, props) : props) as ButtonProps;
95
+
87
96
  // Split props
88
- const [local, ariaProps] = splitProps(props, [
97
+ const [local, ariaProps] = splitProps(mergedProps, [
89
98
  'children',
90
99
  'class',
91
100
  'style',
92
101
  'slot',
102
+ 'isPending',
93
103
  ]);
94
104
 
95
105
  // Check if inside a DialogTrigger or PopoverTrigger - if so, toggle on press
@@ -109,28 +119,30 @@ export function Button(props: ButtonProps): JSX.Element {
109
119
  return !!disabled;
110
120
  };
111
121
 
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
+ const resolvePending = (): boolean => !!local.isPending;
123
+
124
+ let buttonEl: HTMLButtonElement | undefined;
125
+
126
+ // Explicit trigger ownership: a button toggles overlays only when it is the
127
+ // registered trigger element for the surrounding trigger context.
128
+ const isDialogTrigger = () =>
129
+ !!dialogTriggerContext && !!buttonEl && dialogTriggerContext.triggerRef() === buttonEl;
130
+ const isPopoverTrigger = () =>
131
+ !!popoverTriggerContext && !!buttonEl && popoverTriggerContext.triggerRef() === buttonEl;
122
132
 
123
133
  // Wrap onPress to also toggle dialog/popover if this is a trigger button
124
- const handlePress = (e: any) => {
134
+ const handlePress = (e: PressEvent) => {
135
+ if (resolvePending()) {
136
+ return;
137
+ }
125
138
  // Call original onPress if provided
126
139
  if (typeof ariaProps.onPress === 'function') {
127
140
  ariaProps.onPress(e);
128
141
  }
129
- // Toggle dialog only if this is a trigger button (has no onPress handler)
142
+ // Toggle only when this exact button is the registered trigger element.
130
143
  if (isDialogTrigger()) {
131
144
  dialogTriggerContext!.state.toggle();
132
145
  }
133
- // Toggle popover only if this is a trigger button (has no onPress handler)
134
146
  if (isPopoverTrigger()) {
135
147
  popoverTriggerContext!.state.toggle();
136
148
  }
@@ -140,8 +152,23 @@ export function Button(props: ButtonProps): JSX.Element {
140
152
  const buttonAria = createButton({
141
153
  ...ariaProps,
142
154
  onPress: handlePress,
155
+ get onPressStart() {
156
+ return resolvePending() ? undefined : ariaProps.onPressStart;
157
+ },
158
+ get onPressEnd() {
159
+ return resolvePending() ? undefined : ariaProps.onPressEnd;
160
+ },
161
+ get onPressUp() {
162
+ return resolvePending() ? undefined : ariaProps.onPressUp;
163
+ },
164
+ get onPressChange() {
165
+ return resolvePending() ? undefined : ariaProps.onPressChange;
166
+ },
167
+ get onClick() {
168
+ return resolvePending() ? undefined : ariaProps.onClick;
169
+ },
143
170
  get isDisabled() {
144
- return resolveDisabled();
171
+ return resolveDisabled() || resolvePending();
145
172
  },
146
173
  });
147
174
 
@@ -151,23 +178,25 @@ export function Button(props: ButtonProps): JSX.Element {
151
178
  // Create hover
152
179
  const { isHovered, hoverProps } = createHover({
153
180
  get isDisabled() {
154
- return resolveDisabled();
181
+ return resolveDisabled() || resolvePending();
155
182
  },
156
183
  });
157
184
 
158
185
  // Render props values
159
186
  const renderValues = createMemo<ButtonRenderProps>(() => ({
160
187
  isHovered: isHovered(),
161
- isPressed: buttonAria.isPressed(),
188
+ isPressed: buttonAria.isPressed() && !resolvePending(),
162
189
  isFocused: isFocused(),
163
190
  isFocusVisible: isFocusVisible(),
164
191
  isDisabled: resolveDisabled(),
192
+ isPending: resolvePending(),
165
193
  }));
166
194
 
167
195
  // Resolve render props
168
196
  const renderProps = useRenderProps(
169
197
  {
170
- children: props.children,
198
+ // Use merged children so ButtonContext can supply slot/default content.
199
+ children: local.children,
171
200
  class: local.class,
172
201
  style: local.style,
173
202
  defaultClassName: 'solidaria-Button',
@@ -206,13 +235,18 @@ export function Button(props: ButtonProps): JSX.Element {
206
235
 
207
236
  // Ref callback that combines all refs
208
237
  const handleRef = (el: HTMLButtonElement) => {
238
+ buttonEl = el;
239
+
209
240
  // Call the focusable ref for autoFocus support
210
241
  buttonPropsRef?.(el);
211
242
  focusPropsRef?.(el);
212
243
  hoverPropsRef?.(el);
213
244
 
214
- // If this button is a popover trigger, register it
215
- if (isPopoverTrigger() && popoverTriggerContext?.setTriggerRef) {
245
+ // Register trigger ownership for surrounding trigger contexts.
246
+ if (dialogTriggerContext?.setTriggerRef) {
247
+ dialogTriggerContext.setTriggerRef(el);
248
+ }
249
+ if (popoverTriggerContext?.setTriggerRef) {
216
250
  popoverTriggerContext.setTriggerRef(el);
217
251
  }
218
252
  };
@@ -224,13 +258,23 @@ export function Button(props: ButtonProps): JSX.Element {
224
258
  {...cleanButtonProps()}
225
259
  {...cleanFocusProps()}
226
260
  {...cleanHoverProps()}
261
+ type={
262
+ (buttonAria.buttonProps as Record<string, unknown>).type === 'submit' && resolvePending()
263
+ ? 'button'
264
+ : (buttonAria.buttonProps as Record<string, unknown>).type as
265
+ | 'button'
266
+ | 'submit'
267
+ | 'reset'
268
+ | undefined
269
+ }
227
270
  class={renderProps.class()}
228
271
  style={renderProps.style()}
229
- data-pressed={buttonAria.isPressed() || undefined}
272
+ data-pressed={(buttonAria.isPressed() && !resolvePending()) || undefined}
230
273
  data-hovered={isHovered() || undefined}
231
274
  data-focused={isFocused() || undefined}
232
275
  data-focus-visible={isFocusVisible() || undefined}
233
276
  data-disabled={resolveDisabled() || undefined}
277
+ data-pending={resolvePending() || undefined}
234
278
  >
235
279
  {renderProps.renderChildren()}
236
280
  </button>
package/src/Calendar.tsx CHANGED
@@ -30,6 +30,8 @@ import {
30
30
  type CalendarStateProps,
31
31
  type CalendarDate,
32
32
  type DateValue,
33
+ endOfMonth,
34
+ isSameMonth,
33
35
  } from '@proyecto-viviana/solid-stately';
34
36
  import {
35
37
  type RenderChildren,
@@ -121,11 +123,24 @@ export interface CalendarHeaderCellProps extends SlotProps {
121
123
  style?: JSX.CSSProperties;
122
124
  }
123
125
 
126
+ export interface CalendarGridHeaderProps extends SlotProps {
127
+ children?: JSX.Element;
128
+ class?: string;
129
+ style?: JSX.CSSProperties;
130
+ }
131
+
132
+ export interface CalendarGridBodyProps extends SlotProps {
133
+ children?: JSX.Element;
134
+ class?: string;
135
+ style?: JSX.CSSProperties;
136
+ }
137
+
124
138
  // ============================================
125
139
  // CONTEXT
126
140
  // ============================================
127
141
 
128
142
  export const CalendarContext = createContext<CalendarState<DateValue> | null>(null);
143
+ const CalendarGridMonthContext = createContext<CalendarDate | null>(null);
129
144
 
130
145
  export function useCalendarContext(): CalendarState<DateValue> {
131
146
  const context = useContext(CalendarContext);
@@ -159,6 +174,8 @@ export function useCalendarContext(): CalendarState<DateValue> {
159
174
  export function Calendar<T extends DateValue = CalendarDate>(
160
175
  props: CalendarProps<T>
161
176
  ): JSX.Element {
177
+ const inheritedState = useContext(CalendarContext);
178
+
162
179
  // Use hydration-safe pattern for client-only rendering
163
180
  const isHydrated = useIsHydrated();
164
181
 
@@ -167,11 +184,77 @@ export function Calendar<T extends DateValue = CalendarDate>(
167
184
  when={isHydrated()}
168
185
  fallback={<div class="solidaria-Calendar solidaria-Calendar--placeholder" aria-hidden="true" />}
169
186
  >
170
- <CalendarInner {...props} />
187
+ <Show
188
+ when={inheritedState}
189
+ fallback={<CalendarInner {...props} />}
190
+ >
191
+ <CalendarWithState
192
+ state={inheritedState as CalendarState<DateValue>}
193
+ {...props}
194
+ />
195
+ </Show>
171
196
  </Show>
172
197
  );
173
198
  }
174
199
 
200
+ function CalendarWithState<T extends DateValue = CalendarDate>(
201
+ props: CalendarProps<T> & { state: CalendarState<DateValue> }
202
+ ): JSX.Element {
203
+ const [local, _stateProps, rest] = splitProps(
204
+ props,
205
+ ['children', 'class', 'style', 'slot', 'state'],
206
+ [
207
+ 'value',
208
+ 'defaultValue',
209
+ 'onChange',
210
+ 'minValue',
211
+ 'maxValue',
212
+ 'isDisabled',
213
+ 'isReadOnly',
214
+ 'autoFocus',
215
+ 'focusedValue',
216
+ 'defaultFocusedValue',
217
+ 'onFocusChange',
218
+ 'locale',
219
+ 'isDateUnavailable',
220
+ 'visibleMonths',
221
+ 'isDateDisabled',
222
+ 'validationState',
223
+ 'errorMessage',
224
+ 'firstDayOfWeek',
225
+ ]
226
+ );
227
+
228
+ const state = () => props.state;
229
+ const calendarAria = createCalendar(rest, state());
230
+
231
+ const renderValues = createMemo<CalendarRenderProps>(() => ({
232
+ isDisabled: state().isDisabled(),
233
+ isReadOnly: state().isReadOnly(),
234
+ }));
235
+
236
+ const renderProps = useRenderProps(
237
+ {
238
+ class: local.class,
239
+ style: local.style,
240
+ defaultClassName: 'solidaria-Calendar',
241
+ },
242
+ renderValues
243
+ );
244
+
245
+ return (
246
+ <div
247
+ {...calendarAria.calendarProps}
248
+ class={renderProps.class()}
249
+ style={renderProps.style()}
250
+ data-disabled={dataAttr(state().isDisabled())}
251
+ data-readonly={dataAttr(state().isReadOnly())}
252
+ >
253
+ {props.children}
254
+ </div>
255
+ );
256
+ }
257
+
175
258
  /**
176
259
  * Internal Calendar component that renders after client mount.
177
260
  */
@@ -321,10 +404,17 @@ export function CalendarButton(props: CalendarButtonProps): JSX.Element {
321
404
  export function CalendarGrid(props: CalendarGridProps): JSX.Element {
322
405
  const state = useCalendarContext();
323
406
  const [gridRef, setGridRef] = createSignal<HTMLTableElement | null>(null);
407
+ const startDate = createMemo(() => {
408
+ const offsetMonths = props.offset?.months ?? 0;
409
+ const baseStart = state.visibleRange().start;
410
+ return offsetMonths ? baseStart.add({ months: offsetMonths }) : baseStart;
411
+ });
324
412
 
325
413
  // Create grid ARIA props
326
414
  const gridAria = createCalendarGrid(
327
415
  {
416
+ startDate: startDate(),
417
+ endDate: endOfMonth(startDate()),
328
418
  weekdayStyle: props.weekdayStyle,
329
419
  },
330
420
  state,
@@ -350,52 +440,81 @@ export function CalendarGrid(props: CalendarGridProps): JSX.Element {
350
440
  // This breaks the cycle where accessing visibleRange() inside For loop
351
441
  // would cause infinite re-renders.
352
442
  const allDates = createMemo(() => {
353
- const numWeeks = state.getWeeksInMonth();
443
+ const monthStart = startDate();
444
+ const numWeeks = state.getWeeksInMonth(monthStart);
354
445
  const weekDates: (CalendarDate | null)[][] = [];
355
446
 
356
447
  for (let weekIndex = 0; weekIndex < numWeeks; weekIndex++) {
357
- weekDates.push(state.getDatesInWeek(weekIndex));
448
+ weekDates.push(state.getDatesInWeek(weekIndex, monthStart));
358
449
  }
359
450
 
360
451
  return weekDates;
361
452
  });
362
453
 
363
454
  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">
455
+ <CalendarGridMonthContext.Provider value={startDate()}>
456
+ <table
457
+ ref={setGridRef}
458
+ {...gridAria.gridProps}
459
+ class={renderProps.class()}
460
+ style={renderProps.style()}
461
+ >
462
+ <thead {...gridAria.headerProps}>
463
+ <tr>
464
+ <For each={gridAria.weekDays}>
465
+ {(day) => (
466
+ <th scope="col" class="solidaria-CalendarHeaderCell">
467
+ {day}
468
+ </th>
469
+ )}
470
+ </For>
471
+ </tr>
472
+ </thead>
473
+ <tbody>
474
+ <Index each={allDates()}>
475
+ {(weekDates) => (
476
+ <tr>
477
+ <Index each={weekDates()}>
478
+ {(date) => (
479
+ <Show when={date()} fallback={<td />}>
389
480
  {props.children?.(date()!)}
390
- </td>
391
- </Show>
392
- )}
393
- </Index>
394
- </tr>
395
- )}
396
- </Index>
397
- </tbody>
398
- </table>
481
+ </Show>
482
+ )}
483
+ </Index>
484
+ </tr>
485
+ )}
486
+ </Index>
487
+ </tbody>
488
+ </table>
489
+ </CalendarGridMonthContext.Provider>
490
+ );
491
+ }
492
+
493
+ export function CalendarGridHeader(props: CalendarGridHeaderProps): JSX.Element {
494
+ return (
495
+ <thead class={props.class ?? 'solidaria-CalendarGridHeader'} style={props.style}>
496
+ {props.children}
497
+ </thead>
498
+ );
499
+ }
500
+
501
+ export function CalendarGridBody(props: CalendarGridBodyProps): JSX.Element {
502
+ return (
503
+ <tbody class={props.class ?? 'solidaria-CalendarGridBody'} style={props.style}>
504
+ {props.children}
505
+ </tbody>
506
+ );
507
+ }
508
+
509
+ export function CalendarHeaderCell(props: CalendarHeaderCellProps): JSX.Element {
510
+ return (
511
+ <th
512
+ scope="col"
513
+ class={props.class ?? 'solidaria-CalendarHeaderCell'}
514
+ style={props.style}
515
+ >
516
+ {props.children}
517
+ </th>
399
518
  );
400
519
  }
401
520
 
@@ -408,11 +527,16 @@ export function CalendarGrid(props: CalendarGridProps): JSX.Element {
408
527
  */
409
528
  export function CalendarCell(props: CalendarCellProps): JSX.Element {
410
529
  const state = useCalendarContext();
530
+ const currentMonthStart = useContext(CalendarGridMonthContext);
411
531
  const [cellRef, setCellRef] = createSignal<HTMLDivElement | null>(null);
532
+ const isOutsideMonth = createMemo(() => currentMonthStart != null && !isSameMonth(currentMonthStart, props.date));
412
533
 
413
534
  // Create cell ARIA props
414
535
  const cellAria = createCalendarCell(
415
- { date: props.date },
536
+ () => ({
537
+ date: props.date,
538
+ isOutsideMonth: isOutsideMonth(),
539
+ }),
416
540
  state,
417
541
  cellRef
418
542
  );
@@ -449,21 +573,23 @@ export function CalendarCell(props: CalendarCellProps): JSX.Element {
449
573
  };
450
574
 
451
575
  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>
576
+ <td {...cellAria.cellProps}>
577
+ <div
578
+ ref={setCellRef}
579
+ {...cellAria.buttonProps}
580
+ class={renderProps.class()}
581
+ style={renderProps.style()}
582
+ data-selected={dataAttr(cellAria.isSelected)}
583
+ data-focused={dataAttr(cellAria.isFocused)}
584
+ data-disabled={dataAttr(cellAria.isDisabled)}
585
+ data-unavailable={dataAttr(cellAria.isUnavailable)}
586
+ data-outside-month={dataAttr(cellAria.isOutsideMonth)}
587
+ data-today={dataAttr(cellAria.isToday)}
588
+ data-pressed={dataAttr(cellAria.isPressed)}
589
+ >
590
+ {getChildren()}
591
+ </div>
592
+ </td>
467
593
  );
468
594
  }
469
595
 
package/src/Checkbox.tsx CHANGED
@@ -8,7 +8,6 @@
8
8
  import {
9
9
  type JSX,
10
10
  type Accessor,
11
- type ParentProps,
12
11
  createContext,
13
12
  useContext,
14
13
  createMemo,
@@ -125,7 +124,7 @@ export const CheckboxContext = createContext<CheckboxProps | null>(null);
125
124
  * </CheckboxGroup>
126
125
  * ```
127
126
  */
128
- export function CheckboxGroup(props: ParentProps<CheckboxGroupProps>): JSX.Element {
127
+ export function CheckboxGroup(props: CheckboxGroupProps): JSX.Element {
129
128
  const [local, ariaProps] = splitProps(props, [
130
129
  'class',
131
130
  'style',