bits-ui 2.4.1 → 2.6.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 (48) hide show
  1. package/dist/bits/calendar/calendar.svelte.d.ts +77 -1
  2. package/dist/bits/calendar/calendar.svelte.js +169 -9
  3. package/dist/bits/calendar/components/calendar-month-select.svelte +54 -0
  4. package/dist/bits/calendar/components/calendar-month-select.svelte.d.ts +4 -0
  5. package/dist/bits/calendar/components/calendar-year-select.svelte +51 -0
  6. package/dist/bits/calendar/components/calendar-year-select.svelte.d.ts +4 -0
  7. package/dist/bits/calendar/components/calendar.svelte +6 -0
  8. package/dist/bits/calendar/exports.d.ts +3 -1
  9. package/dist/bits/calendar/exports.js +2 -0
  10. package/dist/bits/calendar/types.d.ts +94 -12
  11. package/dist/bits/combobox/types.d.ts +1 -1
  12. package/dist/bits/command/command.svelte.d.ts +26 -2
  13. package/dist/bits/command/command.svelte.js +378 -27
  14. package/dist/bits/command/components/command.svelte +4 -0
  15. package/dist/bits/command/components/command.svelte.d.ts +1 -1
  16. package/dist/bits/command/types.d.ts +16 -2
  17. package/dist/bits/date-field/date-field.svelte.js +5 -1
  18. package/dist/bits/date-picker/components/date-picker-calendar.svelte +3 -0
  19. package/dist/bits/date-picker/components/date-picker.svelte +4 -0
  20. package/dist/bits/date-picker/date-picker.svelte.d.ts +2 -0
  21. package/dist/bits/date-picker/exports.d.ts +3 -1
  22. package/dist/bits/date-picker/exports.js +2 -0
  23. package/dist/bits/date-picker/types.d.ts +13 -1
  24. package/dist/bits/date-range-field/date-range-field.svelte.js +5 -1
  25. package/dist/bits/date-range-picker/components/date-range-picker-calendar.svelte +5 -0
  26. package/dist/bits/date-range-picker/components/date-range-picker.svelte +10 -0
  27. package/dist/bits/date-range-picker/date-range-picker.svelte.d.ts +5 -0
  28. package/dist/bits/date-range-picker/exports.d.ts +3 -1
  29. package/dist/bits/date-range-picker/exports.js +2 -0
  30. package/dist/bits/date-range-picker/types.d.ts +33 -1
  31. package/dist/bits/range-calendar/components/range-calendar.svelte +10 -0
  32. package/dist/bits/range-calendar/exports.d.ts +3 -1
  33. package/dist/bits/range-calendar/exports.js +2 -0
  34. package/dist/bits/range-calendar/range-calendar.svelte.d.ts +20 -0
  35. package/dist/bits/range-calendar/range-calendar.svelte.js +120 -6
  36. package/dist/bits/range-calendar/types.d.ts +44 -12
  37. package/dist/bits/select/components/select-hidden-input.svelte +6 -2
  38. package/dist/bits/select/components/select-hidden-input.svelte.d.ts +2 -1
  39. package/dist/bits/select/components/select.svelte +3 -2
  40. package/dist/bits/select/types.d.ts +5 -0
  41. package/dist/internal/date-time/calendar-helpers.svelte.d.ts +8 -2
  42. package/dist/internal/date-time/calendar-helpers.svelte.js +47 -15
  43. package/dist/internal/date-time/formatter.d.ts +8 -1
  44. package/dist/internal/date-time/formatter.js +16 -3
  45. package/dist/internal/kbd-constants.d.ts +2 -0
  46. package/dist/internal/kbd-constants.js +2 -0
  47. package/dist/shared/attributes.d.ts +3 -1
  48. package/package.json +1 -1
@@ -226,6 +226,18 @@ export type DatePickerRootPropsWithoutHTML = WithChildren<{
226
226
  * date is invalid.
227
227
  */
228
228
  errorMessageId?: string;
229
+ /**
230
+ * The format of the month names in the calendar.
231
+ *
232
+ * @default "long"
233
+ */
234
+ monthFormat?: Intl.DateTimeFormatOptions["month"] | ((month: number) => string);
235
+ /**
236
+ * The format of the year names in the calendar.
237
+ *
238
+ * @default "numeric"
239
+ */
240
+ yearFormat?: Intl.DateTimeFormatOptions["year"] | ((year: number) => string);
229
241
  }>;
230
242
  export type DatePickerRootProps = DatePickerRootPropsWithoutHTML;
231
243
  export type { PopoverTriggerPropsWithoutHTML as DatePickerTriggerPropsWithoutHTML, PopoverTriggerProps as DatePickerTriggerProps, PopoverContentPropsWithoutHTML as DatePickerContentPropsWithoutHTML, PopoverContentProps as DatePickerContentProps, PopoverContentStaticPropsWithoutHTML as DatePickerContentStaticPropsWithoutHTML, PopoverContentStaticProps as DatePickerContentStaticProps, PopoverArrowPropsWithoutHTML as DatePickerArrowPropsWithoutHTML, PopoverArrowProps as DatePickerArrowProps, PopoverClosePropsWithoutHTML as DatePickerClosePropsWithoutHTML, PopoverCloseProps as DatePickerCloseProps, } from "../popover/types.js";
@@ -234,4 +246,4 @@ export type DatePickerCalendarPropsWithoutHTML = WithChild<{}, CalendarRootSnipp
234
246
  export type DatePickerCalendarProps = DatePickerCalendarPropsWithoutHTML & Without<BitsPrimitiveDivAttributes, DatePickerCalendarPropsWithoutHTML>;
235
247
  export type DatePickerPortalPropsWithoutHTML = PortalProps;
236
248
  export type DatePickerPortalProps = DatePickerPortalPropsWithoutHTML;
237
- export type { CalendarCellPropsWithoutHTML as DatePickerCellPropsWithoutHTML, CalendarCellProps as DatePickerCellProps, CalendarDayPropsWithoutHTML as DatePickerDayPropsWithoutHTML, CalendarDayProps as DatePickerDayProps, CalendarGridPropsWithoutHTML as DatePickerGridPropsWithoutHTML, CalendarGridProps as DatePickerGridProps, CalendarGridBodyPropsWithoutHTML as DatePickerGridBodyPropsWithoutHTML, CalendarGridBodyProps as DatePickerGridBodyProps, CalendarGridHeadPropsWithoutHTML as DatePickerGridHeadPropsWithoutHTML, CalendarGridHeadProps as DatePickerGridHeadProps, CalendarGridRowPropsWithoutHTML as DatePickerGridRowPropsWithoutHTML, CalendarGridRowProps as DatePickerGridRowProps, CalendarHeadCellPropsWithoutHTML as DatePickerHeadCellPropsWithoutHTML, CalendarHeadCellProps as DatePickerHeadCellProps, CalendarHeaderPropsWithoutHTML as DatePickerHeaderPropsWithoutHTML, CalendarHeaderProps as DatePickerHeaderProps, CalendarHeadingPropsWithoutHTML as DatePickerHeadingPropsWithoutHTML, CalendarHeadingProps as DatePickerHeadingProps, CalendarNextButtonPropsWithoutHTML as DatePickerNextButtonPropsWithoutHTML, CalendarNextButtonProps as DatePickerNextButtonProps, CalendarPrevButtonPropsWithoutHTML as DatePickerPrevButtonPropsWithoutHTML, CalendarPrevButtonProps as DatePickerPrevButtonProps, } from "../calendar/types.js";
249
+ export type { CalendarCellPropsWithoutHTML as DatePickerCellPropsWithoutHTML, CalendarCellProps as DatePickerCellProps, CalendarDayPropsWithoutHTML as DatePickerDayPropsWithoutHTML, CalendarDayProps as DatePickerDayProps, CalendarGridPropsWithoutHTML as DatePickerGridPropsWithoutHTML, CalendarGridProps as DatePickerGridProps, CalendarGridBodyPropsWithoutHTML as DatePickerGridBodyPropsWithoutHTML, CalendarGridBodyProps as DatePickerGridBodyProps, CalendarGridHeadPropsWithoutHTML as DatePickerGridHeadPropsWithoutHTML, CalendarGridHeadProps as DatePickerGridHeadProps, CalendarGridRowPropsWithoutHTML as DatePickerGridRowPropsWithoutHTML, CalendarGridRowProps as DatePickerGridRowProps, CalendarHeadCellPropsWithoutHTML as DatePickerHeadCellPropsWithoutHTML, CalendarHeadCellProps as DatePickerHeadCellProps, CalendarHeaderPropsWithoutHTML as DatePickerHeaderPropsWithoutHTML, CalendarHeaderProps as DatePickerHeaderProps, CalendarHeadingPropsWithoutHTML as DatePickerHeadingPropsWithoutHTML, CalendarHeadingProps as DatePickerHeadingProps, CalendarNextButtonPropsWithoutHTML as DatePickerNextButtonPropsWithoutHTML, CalendarNextButtonProps as DatePickerNextButtonProps, CalendarPrevButtonPropsWithoutHTML as DatePickerPrevButtonPropsWithoutHTML, CalendarPrevButtonProps as DatePickerPrevButtonProps, CalendarMonthSelectProps as DatePickerMonthSelectProps, CalendarMonthSelectPropsWithoutHTML as DatePickerMonthSelectPropsWithoutHTML, CalendarYearSelectProps as DatePickerYearSelectProps, CalendarYearSelectPropsWithoutHTML as DatePickerYearSelectPropsWithoutHTML, } from "../calendar/types.js";
@@ -26,7 +26,11 @@ export class DateRangeFieldRootState {
26
26
  domContext;
27
27
  constructor(opts) {
28
28
  this.opts = opts;
29
- this.formatter = createFormatter(this.opts.locale.current);
29
+ this.formatter = createFormatter({
30
+ initialLocale: this.opts.locale.current,
31
+ monthFormat: box.with(() => "long"),
32
+ yearFormat: box.with(() => "numeric"),
33
+ });
30
34
  this.domContext = new DOMContext(this.opts.ref);
31
35
  onDestroyEffect(() => {
32
36
  removeDescriptionElement(this.descriptionId, this.domContext.getDocument());
@@ -40,10 +40,15 @@
40
40
  minValue: dateRangePickerRootState.opts.minValue,
41
41
  placeholder: dateRangePickerRootState.opts.placeholder,
42
42
  value: dateRangePickerRootState.opts.value,
43
+ excludeDisabled: dateRangePickerRootState.opts.excludeDisabled,
43
44
  onRangeSelect: dateRangePickerRootState.opts.onRangeSelect,
44
45
  startValue: dateRangePickerRootState.opts.startValue,
45
46
  endValue: dateRangePickerRootState.opts.endValue,
46
47
  defaultPlaceholder: dateRangePickerRootState.opts.defaultPlaceholder,
48
+ minDays: dateRangePickerRootState.opts.minDays,
49
+ maxDays: dateRangePickerRootState.opts.maxDays,
50
+ monthFormat: dateRangePickerRootState.opts.monthFormat,
51
+ yearFormat: dateRangePickerRootState.opts.yearFormat,
47
52
  });
48
53
 
49
54
  const mergedProps = $derived(mergeProps(restProps, rangeCalendarState.props));
@@ -48,8 +48,13 @@
48
48
  onEndValueChange = noop,
49
49
  validate = noop,
50
50
  errorMessageId,
51
+ minDays,
52
+ maxDays,
53
+ excludeDisabled = false,
51
54
  child,
52
55
  children,
56
+ monthFormat = "long",
57
+ yearFormat = "numeric",
53
58
  ...restProps
54
59
  }: DateRangePickerRootProps = $props();
55
60
 
@@ -132,6 +137,8 @@
132
137
  isDateUnavailable: box.with(() => isDateUnavailable),
133
138
  minValue: box.with(() => minValue),
134
139
  maxValue: box.with(() => maxValue),
140
+ minDays: box.with(() => minDays),
141
+ maxDays: box.with(() => maxDays),
135
142
  disabled: box.with(() => disabled),
136
143
  readonly: box.with(() => readonly),
137
144
  granularity: box.with(() => granularity),
@@ -149,6 +156,7 @@
149
156
  isDateDisabled: box.with(() => isDateDisabled),
150
157
  fixedWeeks: box.with(() => fixedWeeks),
151
158
  numberOfMonths: box.with(() => numberOfMonths),
159
+ excludeDisabled: box.with(() => excludeDisabled),
152
160
  onRangeSelect: box.with(() => onRangeSelect),
153
161
  startValue: box.with(
154
162
  () => startValue,
@@ -164,6 +172,8 @@
164
172
  onEndValueChange(v);
165
173
  }
166
174
  ),
175
+ monthFormat: box.with(() => monthFormat),
176
+ yearFormat: box.with(() => yearFormat),
167
177
  defaultPlaceholder,
168
178
  });
169
179
 
@@ -15,6 +15,8 @@ type DateRangePickerRootStateProps = WritableBoxedValues<{
15
15
  isDateDisabled: DateMatcher;
16
16
  minValue: DateValue | undefined;
17
17
  maxValue: DateValue | undefined;
18
+ minDays: number | undefined;
19
+ maxDays: number | undefined;
18
20
  disabled: boolean;
19
21
  readonly: boolean;
20
22
  granularity: Granularity | undefined;
@@ -30,7 +32,10 @@ type DateRangePickerRootStateProps = WritableBoxedValues<{
30
32
  numberOfMonths: number;
31
33
  calendarLabel: string;
32
34
  disableDaysOutsideMonth: boolean;
35
+ excludeDisabled: boolean;
33
36
  onRangeSelect?: () => void;
37
+ monthFormat: Intl.DateTimeFormatOptions["month"] | ((month: number) => string);
38
+ yearFormat: Intl.DateTimeFormatOptions["year"] | ((year: number) => string);
34
39
  }> & {
35
40
  defaultPlaceholder: DateValue;
36
41
  };
@@ -16,6 +16,8 @@ export { default as Header } from "../calendar/components/calendar-header.svelte
16
16
  export { default as Heading } from "../calendar/components/calendar-heading.svelte";
17
17
  export { default as NextButton } from "../calendar/components/calendar-next-button.svelte";
18
18
  export { default as PrevButton } from "../calendar/components/calendar-prev-button.svelte";
19
+ export { default as MonthSelect } from "../calendar/components/calendar-month-select.svelte";
20
+ export { default as YearSelect } from "../calendar/components/calendar-year-select.svelte";
19
21
  export { default as Cell } from "../range-calendar/components/range-calendar-cell.svelte";
20
22
  export { default as Day } from "../range-calendar/components/range-calendar-day.svelte";
21
- export type { DateRangePickerRootProps as RootProps, DateRangePickerLabelProps as LabelProps, DateRangePickerInputProps as InputProps, DateRangePickerSegmentProps as SegmentProps, DateRangePickerArrowProps as ArrowProps, DateRangePickerCloseProps as CloseProps, DateRangePickerContentProps as ContentProps, DateRangePickerTriggerProps as TriggerProps, DateRangePickerCalendarProps as CalendarProps, DateRangePickerCellProps as CellProps, DateRangePickerDayProps as DayProps, DateRangePickerGridBodyProps as GridBodyProps, DateRangePickerGridHeadProps as GridHeadProps, DateRangePickerGridProps as GridProps, DateRangePickerGridRowProps as GridRowProps, DateRangePickerHeadCellProps as HeadCellProps, DateRangePickerHeaderProps as HeaderProps, DateRangePickerHeadingProps as HeadingProps, DateRangePickerNextButtonProps as NextButtonProps, DateRangePickerPrevButtonProps as PrevButtonProps, } from "./types.js";
23
+ export type { DateRangePickerRootProps as RootProps, DateRangePickerLabelProps as LabelProps, DateRangePickerInputProps as InputProps, DateRangePickerSegmentProps as SegmentProps, DateRangePickerArrowProps as ArrowProps, DateRangePickerCloseProps as CloseProps, DateRangePickerContentProps as ContentProps, DateRangePickerTriggerProps as TriggerProps, DateRangePickerCalendarProps as CalendarProps, DateRangePickerCellProps as CellProps, DateRangePickerDayProps as DayProps, DateRangePickerGridBodyProps as GridBodyProps, DateRangePickerGridHeadProps as GridHeadProps, DateRangePickerGridProps as GridProps, DateRangePickerGridRowProps as GridRowProps, DateRangePickerHeadCellProps as HeadCellProps, DateRangePickerHeaderProps as HeaderProps, DateRangePickerHeadingProps as HeadingProps, DateRangePickerNextButtonProps as NextButtonProps, DateRangePickerPrevButtonProps as PrevButtonProps, DateRangePickerMonthSelectProps as MonthSelectProps, DateRangePickerYearSelectProps as YearSelectProps, } from "./types.js";
@@ -16,5 +16,7 @@ export { default as Header } from "../calendar/components/calendar-header.svelte
16
16
  export { default as Heading } from "../calendar/components/calendar-heading.svelte";
17
17
  export { default as NextButton } from "../calendar/components/calendar-next-button.svelte";
18
18
  export { default as PrevButton } from "../calendar/components/calendar-prev-button.svelte";
19
+ export { default as MonthSelect } from "../calendar/components/calendar-month-select.svelte";
20
+ export { default as YearSelect } from "../calendar/components/calendar-year-select.svelte";
19
21
  export { default as Cell } from "../range-calendar/components/range-calendar-cell.svelte";
20
22
  export { default as Day } from "../range-calendar/components/range-calendar-day.svelte";
@@ -233,10 +233,42 @@ export type DateRangePickerRootPropsWithoutHTML = WithChild<{
233
233
  * date is invalid.
234
234
  */
235
235
  errorMessageId?: string;
236
+ /**
237
+ * The minimum number of days that can be selected in a range.
238
+ *
239
+ * @default undefined
240
+ */
241
+ minDays?: number;
242
+ /**
243
+ * The maximum number of days that can be selected in a range.
244
+ *
245
+ * @default undefined
246
+ */
247
+ maxDays?: number;
248
+ /**
249
+ * Whether to automatically reset the range if any date within the selected range
250
+ * becomes disabled. When true, the entire range will be cleared if a disabled
251
+ * date is found between the start and end dates.
252
+ *
253
+ * @default false
254
+ */
255
+ excludeDisabled?: boolean;
256
+ /**
257
+ * The format of the month names in the calendar.
258
+ *
259
+ * @default "long"
260
+ */
261
+ monthFormat?: Intl.DateTimeFormatOptions["month"] | ((month: number) => string);
262
+ /**
263
+ * The format of the year names in the calendar.
264
+ *
265
+ * @default "numeric"
266
+ */
267
+ yearFormat?: Intl.DateTimeFormatOptions["year"] | ((year: number) => string);
236
268
  }>;
237
269
  export type DateRangePickerRootProps = DateRangePickerRootPropsWithoutHTML & Without<BitsPrimitiveDivAttributes, DateRangePickerRootPropsWithoutHTML>;
238
270
  export type { PopoverTriggerPropsWithoutHTML as DateRangePickerTriggerPropsWithoutHTML, PopoverTriggerProps as DateRangePickerTriggerProps, PopoverContentPropsWithoutHTML as DateRangePickerContentPropsWithoutHTML, PopoverContentProps as DateRangePickerContentProps, PopoverArrowPropsWithoutHTML as DateRangePickerArrowPropsWithoutHTML, PopoverArrowProps as DateRangePickerArrowProps, PopoverClosePropsWithoutHTML as DateRangePickerClosePropsWithoutHTML, PopoverCloseProps as DateRangePickerCloseProps, } from "../popover/types.js";
239
271
  export type { DateRangeFieldInputPropsWithoutHTML as DateRangePickerInputPropsWithoutHTML, DateRangeFieldInputProps as DateRangePickerInputProps, DateRangeFieldLabelPropsWithoutHTML as DateRangePickerLabelPropsWithoutHTML, DateRangeFieldLabelProps as DateRangePickerLabelProps, DateRangeFieldSegmentPropsWithoutHTML as DateRangePickerSegmentPropsWithoutHTML, DateRangeFieldSegmentProps as DateRangePickerSegmentProps, } from "../date-range-field/types.js";
240
272
  export type DateRangePickerCalendarPropsWithoutHTML = WithChild<{}, CalendarRootSnippetProps>;
241
273
  export type DateRangePickerCalendarProps = DateRangePickerCalendarPropsWithoutHTML & Without<BitsPrimitiveDivAttributes, DateRangePickerCalendarPropsWithoutHTML>;
242
- export type { RangeCalendarCellPropsWithoutHTML as DateRangePickerCellPropsWithoutHTML, RangeCalendarCellProps as DateRangePickerCellProps, RangeCalendarDayPropsWithoutHTML as DateRangePickerDayPropsWithoutHTML, RangeCalendarDayProps as DateRangePickerDayProps, RangeCalendarGridPropsWithoutHTML as DateRangePickerGridPropsWithoutHTML, RangeCalendarGridProps as DateRangePickerGridProps, RangeCalendarGridBodyPropsWithoutHTML as DateRangePickerGridBodyPropsWithoutHTML, RangeCalendarGridBodyProps as DateRangePickerGridBodyProps, RangeCalendarGridHeadPropsWithoutHTML as DateRangePickerGridHeadPropsWithoutHTML, RangeCalendarGridHeadProps as DateRangePickerGridHeadProps, RangeCalendarGridRowPropsWithoutHTML as DateRangePickerGridRowPropsWithoutHTML, RangeCalendarGridRowProps as DateRangePickerGridRowProps, RangeCalendarHeadCellPropsWithoutHTML as DateRangePickerHeadCellPropsWithoutHTML, RangeCalendarHeadCellProps as DateRangePickerHeadCellProps, RangeCalendarHeaderPropsWithoutHTML as DateRangePickerHeaderPropsWithoutHTML, RangeCalendarHeaderProps as DateRangePickerHeaderProps, RangeCalendarHeadingPropsWithoutHTML as DateRangePickerHeadingPropsWithoutHTML, RangeCalendarHeadingProps as DateRangePickerHeadingProps, RangeCalendarNextButtonPropsWithoutHTML as DateRangePickerNextButtonPropsWithoutHTML, RangeCalendarNextButtonProps as DateRangePickerNextButtonProps, RangeCalendarPrevButtonPropsWithoutHTML as DateRangePickerPrevButtonPropsWithoutHTML, RangeCalendarPrevButtonProps as DateRangePickerPrevButtonProps, } from "../range-calendar/types.js";
274
+ export type { RangeCalendarCellPropsWithoutHTML as DateRangePickerCellPropsWithoutHTML, RangeCalendarCellProps as DateRangePickerCellProps, RangeCalendarDayPropsWithoutHTML as DateRangePickerDayPropsWithoutHTML, RangeCalendarDayProps as DateRangePickerDayProps, RangeCalendarGridPropsWithoutHTML as DateRangePickerGridPropsWithoutHTML, RangeCalendarGridProps as DateRangePickerGridProps, RangeCalendarGridBodyPropsWithoutHTML as DateRangePickerGridBodyPropsWithoutHTML, RangeCalendarGridBodyProps as DateRangePickerGridBodyProps, RangeCalendarGridHeadPropsWithoutHTML as DateRangePickerGridHeadPropsWithoutHTML, RangeCalendarGridHeadProps as DateRangePickerGridHeadProps, RangeCalendarGridRowPropsWithoutHTML as DateRangePickerGridRowPropsWithoutHTML, RangeCalendarGridRowProps as DateRangePickerGridRowProps, RangeCalendarHeadCellPropsWithoutHTML as DateRangePickerHeadCellPropsWithoutHTML, RangeCalendarHeadCellProps as DateRangePickerHeadCellProps, RangeCalendarHeaderPropsWithoutHTML as DateRangePickerHeaderPropsWithoutHTML, RangeCalendarHeaderProps as DateRangePickerHeaderProps, RangeCalendarHeadingPropsWithoutHTML as DateRangePickerHeadingPropsWithoutHTML, RangeCalendarHeadingProps as DateRangePickerHeadingProps, RangeCalendarNextButtonPropsWithoutHTML as DateRangePickerNextButtonPropsWithoutHTML, RangeCalendarNextButtonProps as DateRangePickerNextButtonProps, RangeCalendarPrevButtonPropsWithoutHTML as DateRangePickerPrevButtonPropsWithoutHTML, RangeCalendarPrevButtonProps as DateRangePickerPrevButtonProps, RangeCalendarMonthSelectProps as DateRangePickerMonthSelectProps, RangeCalendarMonthSelectPropsWithoutHTML as DateRangePickerMonthSelectPropsWithoutHTML, RangeCalendarYearSelectProps as DateRangePickerYearSelectProps, RangeCalendarYearSelectPropsWithoutHTML as DateRangePickerYearSelectPropsWithoutHTML, } from "../range-calendar/types.js";
@@ -35,8 +35,13 @@
35
35
  maxValue = undefined,
36
36
  preventDeselect = false,
37
37
  disableDaysOutsideMonth = true,
38
+ minDays,
39
+ maxDays,
38
40
  onStartValueChange = noop,
39
41
  onEndValueChange = noop,
42
+ excludeDisabled = false,
43
+ monthFormat = "long",
44
+ yearFormat = "numeric",
40
45
  ...restProps
41
46
  }: RangeCalendarRootProps = $props();
42
47
 
@@ -112,6 +117,9 @@
112
117
  calendarLabel: box.with(() => calendarLabel),
113
118
  fixedWeeks: box.with(() => fixedWeeks),
114
119
  disableDaysOutsideMonth: box.with(() => disableDaysOutsideMonth),
120
+ minDays: box.with(() => minDays),
121
+ maxDays: box.with(() => maxDays),
122
+ excludeDisabled: box.with(() => excludeDisabled),
115
123
  startValue: box.with(
116
124
  () => startValue,
117
125
  (v) => {
@@ -126,6 +134,8 @@
126
134
  onEndValueChange(v);
127
135
  }
128
136
  ),
137
+ monthFormat: box.with(() => monthFormat),
138
+ yearFormat: box.with(() => yearFormat),
129
139
  defaultPlaceholder,
130
140
  });
131
141
 
@@ -10,4 +10,6 @@ export { default as Header } from "../calendar/components/calendar-header.svelte
10
10
  export { default as Heading } from "../calendar/components/calendar-heading.svelte";
11
11
  export { default as NextButton } from "../calendar/components/calendar-next-button.svelte";
12
12
  export { default as PrevButton } from "../calendar/components/calendar-prev-button.svelte";
13
- export type { RangeCalendarRootProps as RootProps, RangeCalendarPrevButtonProps as PrevButtonProps, RangeCalendarNextButtonProps as NextButtonProps, RangeCalendarHeadingProps as HeadingProps, RangeCalendarHeaderProps as HeaderProps, RangeCalendarGridProps as GridProps, RangeCalendarGridHeadProps as GridHeadProps, RangeCalendarHeadCellProps as HeadCellProps, RangeCalendarGridBodyProps as GridBodyProps, RangeCalendarCellProps as CellProps, RangeCalendarGridRowProps as GridRowProps, RangeCalendarDayProps as DayProps, } from "./types.js";
13
+ export { default as MonthSelect } from "../calendar/components/calendar-month-select.svelte";
14
+ export { default as YearSelect } from "../calendar/components/calendar-year-select.svelte";
15
+ export type { RangeCalendarRootProps as RootProps, RangeCalendarPrevButtonProps as PrevButtonProps, RangeCalendarNextButtonProps as NextButtonProps, RangeCalendarHeadingProps as HeadingProps, RangeCalendarHeaderProps as HeaderProps, RangeCalendarGridProps as GridProps, RangeCalendarGridHeadProps as GridHeadProps, RangeCalendarHeadCellProps as HeadCellProps, RangeCalendarGridBodyProps as GridBodyProps, RangeCalendarCellProps as CellProps, RangeCalendarGridRowProps as GridRowProps, RangeCalendarDayProps as DayProps, RangeCalendarMonthSelectProps as MonthSelectProps, RangeCalendarYearSelectProps as YearSelectProps, } from "./types.js";
@@ -10,3 +10,5 @@ export { default as Header } from "../calendar/components/calendar-header.svelte
10
10
  export { default as Heading } from "../calendar/components/calendar-heading.svelte";
11
11
  export { default as NextButton } from "../calendar/components/calendar-next-button.svelte";
12
12
  export { default as PrevButton } from "../calendar/components/calendar-prev-button.svelte";
13
+ export { default as MonthSelect } from "../calendar/components/calendar-month-select.svelte";
14
+ export { default as YearSelect } from "../calendar/components/calendar-year-select.svelte";
@@ -28,11 +28,16 @@ type RangeCalendarRootStateProps = WithRefProps<WritableBoxedValues<{
28
28
  calendarLabel: string;
29
29
  readonly: boolean;
30
30
  disableDaysOutsideMonth: boolean;
31
+ excludeDisabled: boolean;
32
+ minDays: number | undefined;
33
+ maxDays: number | undefined;
31
34
  /**
32
35
  * This is strictly used by the `DateRangePicker` component to close the popover when a date range
33
36
  * is selected. It is not intended to be used by the user.
34
37
  */
35
38
  onRangeSelect?: () => void;
39
+ monthFormat: Intl.DateTimeFormatOptions["month"] | ((month: number) => string);
40
+ yearFormat: Intl.DateTimeFormatOptions["year"] | ((year: number) => string);
36
41
  }> & {
37
42
  defaultPlaceholder: DateValue;
38
43
  }>;
@@ -66,6 +71,8 @@ export declare class RangeCalendarRootState {
66
71
  start: DateValue;
67
72
  end: DateValue;
68
73
  } | null;
74
+ readonly initialPlaceholderYear: number;
75
+ readonly defaultYears: number[];
69
76
  constructor(opts: RangeCalendarRootStateProps);
70
77
  setMonths: (months: Month<DateValue>[]) => void;
71
78
  isOutsideVisibleMonths(date: DateValue): boolean;
@@ -120,6 +127,10 @@ export declare class RangeCalendarCellState {
120
127
  readonly isFocusedDate: boolean;
121
128
  readonly isSelectedDate: boolean;
122
129
  readonly isSelectionStart: boolean;
130
+ readonly isRangeStart: boolean;
131
+ readonly isRangeEnd: boolean;
132
+ readonly isRangeMiddle: boolean;
133
+ readonly isSelectionMiddle: boolean;
123
134
  readonly isSelectionEnd: boolean;
124
135
  readonly isHighlighted: boolean;
125
136
  readonly labelText: string;
@@ -138,6 +149,9 @@ export declare class RangeCalendarCellState {
138
149
  readonly "data-focused": "" | undefined;
139
150
  readonly "data-selection-start": "" | undefined;
140
151
  readonly "data-selection-end": "" | undefined;
152
+ readonly "data-range-start": "" | undefined;
153
+ readonly "data-range-end": "" | undefined;
154
+ readonly "data-range-middle": "" | undefined;
141
155
  readonly "data-highlighted": "" | undefined;
142
156
  readonly "data-selected": "" | undefined;
143
157
  readonly "data-value": string;
@@ -152,6 +166,9 @@ export declare class RangeCalendarCellState {
152
166
  readonly "data-focused": "" | undefined;
153
167
  readonly "data-selection-start": "" | undefined;
154
168
  readonly "data-selection-end": "" | undefined;
169
+ readonly "data-range-start": "" | undefined;
170
+ readonly "data-range-end": "" | undefined;
171
+ readonly "data-range-middle": "" | undefined;
155
172
  readonly "data-highlighted": "" | undefined;
156
173
  readonly "data-selected": "" | undefined;
157
174
  readonly "data-value": string;
@@ -191,6 +208,9 @@ declare class RangeCalendarDayState {
191
208
  readonly "data-focused": "" | undefined;
192
209
  readonly "data-selection-start": "" | undefined;
193
210
  readonly "data-selection-end": "" | undefined;
211
+ readonly "data-range-start": "" | undefined;
212
+ readonly "data-range-end": "" | undefined;
213
+ readonly "data-range-middle": "" | undefined;
194
214
  readonly "data-highlighted": "" | undefined;
195
215
  readonly "data-selected": "" | undefined;
196
216
  readonly "data-value": string;
@@ -6,9 +6,9 @@ import { useId } from "../../internal/use-id.js";
6
6
  import { getAriaDisabled, getAriaSelected, getDataDisabled, getDataSelected, getDataUnavailable, } from "../../internal/attrs.js";
7
7
  import { getAnnouncer } from "../../internal/date-time/announcer.js";
8
8
  import { createFormatter } from "../../internal/date-time/formatter.js";
9
- import { calendarAttrs, createMonths, getCalendarElementProps, getCalendarHeadingValue, getIsNextButtonDisabled, getIsPrevButtonDisabled, getWeekdays, handleCalendarKeydown, handleCalendarNextPage, handleCalendarPrevPage, shiftCalendarFocus, useEnsureNonDisabledPlaceholder, useMonthViewOptionsSync, useMonthViewPlaceholderSync, } from "../../internal/date-time/calendar-helpers.svelte.js";
9
+ import { calendarAttrs, createMonths, getCalendarElementProps, getCalendarHeadingValue, getDefaultYears, getIsNextButtonDisabled, getIsPrevButtonDisabled, getWeekdays, handleCalendarKeydown, handleCalendarNextPage, handleCalendarPrevPage, shiftCalendarFocus, useEnsureNonDisabledPlaceholder, useMonthViewOptionsSync, useMonthViewPlaceholderSync, } from "../../internal/date-time/calendar-helpers.svelte.js";
10
10
  import { areAllDaysBetweenValid, getDateValueType, isAfter, isBefore, isBetweenInclusive, toDate, } from "../../internal/date-time/utils.js";
11
- import { onMount } from "svelte";
11
+ import { onMount, untrack } from "svelte";
12
12
  export class RangeCalendarRootState {
13
13
  opts;
14
14
  visibleMonths = $derived.by(() => this.months.map((month) => month.value));
@@ -69,6 +69,8 @@ export class RangeCalendarRootState {
69
69
  });
70
70
  });
71
71
  headingValue = $derived.by(() => {
72
+ this.opts.monthFormat.current;
73
+ this.opts.yearFormat.current;
72
74
  return getCalendarHeadingValue({
73
75
  months: this.months,
74
76
  formatter: this.formatter,
@@ -93,11 +95,23 @@ export class RangeCalendarRootState {
93
95
  return range;
94
96
  return null;
95
97
  });
98
+ initialPlaceholderYear = $derived.by(() => untrack(() => this.opts.placeholder.current.year));
99
+ defaultYears = $derived.by(() => {
100
+ return getDefaultYears({
101
+ minValue: this.opts.minValue.current,
102
+ maxValue: this.opts.maxValue.current,
103
+ placeholderYear: this.initialPlaceholderYear,
104
+ });
105
+ });
96
106
  constructor(opts) {
97
107
  this.opts = opts;
98
108
  this.domContext = new DOMContext(opts.ref);
99
109
  this.announcer = getAnnouncer(null);
100
- this.formatter = createFormatter(this.opts.locale.current);
110
+ this.formatter = createFormatter({
111
+ initialLocale: this.opts.locale.current,
112
+ monthFormat: this.opts.monthFormat,
113
+ yearFormat: this.opts.yearFormat,
114
+ });
101
115
  this.months = createMonths({
102
116
  dateObj: this.opts.placeholder.current,
103
117
  weekStartsOn: this.opts.weekStartsOn.current,
@@ -105,7 +119,7 @@ export class RangeCalendarRootState {
105
119
  fixedWeeks: this.opts.fixedWeeks.current,
106
120
  numberOfMonths: this.opts.numberOfMonths.current,
107
121
  });
108
- $effect(() => {
122
+ $effect.pre(() => {
109
123
  if (this.formatter.getLocale() === this.opts.locale.current)
110
124
  return;
111
125
  this.formatter.setLocale(this.opts.locale.current);
@@ -175,6 +189,22 @@ export class RangeCalendarRootState {
175
189
  this.opts.placeholder.current = startValue;
176
190
  }
177
191
  });
192
+ /**
193
+ * Check for disabled dates in the selected range when excludeDisabled is enabled
194
+ */
195
+ watch([
196
+ () => this.opts.startValue.current,
197
+ () => this.opts.endValue.current,
198
+ () => this.opts.excludeDisabled.current,
199
+ ], ([startValue, endValue, excludeDisabled]) => {
200
+ if (!excludeDisabled || !startValue || !endValue)
201
+ return;
202
+ if (this.#hasDisabledDatesInRange(startValue, endValue)) {
203
+ this.#setStartValue(undefined);
204
+ this.#setEndValue(undefined);
205
+ this.#announceEmpty();
206
+ }
207
+ });
178
208
  watch([() => this.opts.startValue.current, () => this.opts.endValue.current], ([startValue, endValue]) => {
179
209
  if (this.opts.value.current &&
180
210
  this.opts.value.current.start === startValue &&
@@ -191,9 +221,19 @@ export class RangeCalendarRootState {
191
221
  const end = endValue;
192
222
  this.#setStartValue(end);
193
223
  this.#setEndValue(start);
224
+ if (!this.#isRangeValid(endValue, startValue)) {
225
+ this.#setStartValue(startValue);
226
+ this.#setEndValue(undefined);
227
+ return { start: startValue, end: undefined };
228
+ }
194
229
  return { start: endValue, end: startValue };
195
230
  }
196
231
  else {
232
+ if (!this.#isRangeValid(startValue, endValue)) {
233
+ this.#setStartValue(endValue);
234
+ this.#setEndValue(undefined);
235
+ return { start: endValue, end: undefined };
236
+ }
197
237
  return {
198
238
  start: startValue,
199
239
  end: endValue,
@@ -240,9 +280,19 @@ export class RangeCalendarRootState {
240
280
  }
241
281
  #setStartValue(value) {
242
282
  this.opts.startValue.current = value;
283
+ // update the main value prop immediately for external consumers
284
+ this.#updateValue((prev) => ({
285
+ ...prev,
286
+ start: value,
287
+ }));
243
288
  }
244
289
  #setEndValue(value) {
245
290
  this.opts.endValue.current = value;
291
+ // update the main value prop immediately for external consumers
292
+ this.#updateValue((prev) => ({
293
+ ...prev,
294
+ end: value,
295
+ }));
246
296
  }
247
297
  setMonths = (months) => {
248
298
  this.months = months;
@@ -286,6 +336,26 @@ export class RangeCalendarRootState {
286
336
  }
287
337
  return false;
288
338
  }
339
+ #isRangeValid(start, end) {
340
+ // ensure we always use the correct order for calculation
341
+ const orderedStart = isBefore(end, start) ? end : start;
342
+ const orderedEnd = isBefore(end, start) ? start : end;
343
+ const startDate = orderedStart.toDate(getLocalTimeZone());
344
+ const endDate = orderedEnd.toDate(getLocalTimeZone());
345
+ const timeDifference = endDate.getTime() - startDate.getTime();
346
+ const daysDifference = Math.floor(timeDifference / (1000 * 60 * 60 * 24));
347
+ const daysInRange = daysDifference + 1; // +1 to include both start and end days
348
+ if (this.opts.minDays.current && daysInRange < this.opts.minDays.current)
349
+ return false;
350
+ if (this.opts.maxDays.current && daysInRange > this.opts.maxDays.current)
351
+ return false;
352
+ // check for disabled dates in range if excludeDisabled is enabled
353
+ if (this.opts.excludeDisabled.current &&
354
+ this.#hasDisabledDatesInRange(orderedStart, orderedEnd)) {
355
+ return false;
356
+ }
357
+ return true;
358
+ }
289
359
  shiftFocus(node, add) {
290
360
  return shiftCalendarFocus({
291
361
  node,
@@ -344,8 +414,32 @@ export class RangeCalendarRootState {
344
414
  this.#setStartValue(date);
345
415
  }
346
416
  else if (!this.opts.endValue.current) {
347
- this.#announceSelectedRange(this.opts.startValue.current, date);
348
- this.#setEndValue(date);
417
+ // determine the start and end dates for validation
418
+ const startDate = this.opts.startValue.current;
419
+ const endDate = date;
420
+ const orderedStart = isBefore(endDate, startDate) ? endDate : startDate;
421
+ const orderedEnd = isBefore(endDate, startDate) ? startDate : endDate;
422
+ // check if the range violates constraints
423
+ if (!this.#isRangeValid(orderedStart, orderedEnd)) {
424
+ // reset to just the clicked date
425
+ this.#setStartValue(date);
426
+ this.#setEndValue(undefined);
427
+ this.#announceSelectedDate(date);
428
+ }
429
+ else {
430
+ // ensure start and end are properly ordered
431
+ if (isBefore(endDate, startDate)) {
432
+ // backward selection - reorder the values
433
+ this.#setStartValue(endDate);
434
+ this.#setEndValue(startDate);
435
+ this.#announceSelectedRange(endDate, startDate);
436
+ }
437
+ else {
438
+ // forward selection - keep original order
439
+ this.#setEndValue(date);
440
+ this.#announceSelectedRange(this.opts.startValue.current, date);
441
+ }
442
+ }
349
443
  }
350
444
  else if (this.opts.endValue.current && this.opts.startValue.current) {
351
445
  this.#setEndValue(undefined);
@@ -423,6 +517,13 @@ export class RangeCalendarRootState {
423
517
  onkeydown: this.onkeydown,
424
518
  ...attachRef(this.opts.ref),
425
519
  }));
520
+ #hasDisabledDatesInRange(start, end) {
521
+ for (let date = start; isBefore(date, end) || isSameDay(date, end); date = date.add({ days: 1 })) {
522
+ if (this.isDateDisabled(date))
523
+ return true;
524
+ }
525
+ return false;
526
+ }
426
527
  }
427
528
  export class RangeCalendarCellState {
428
529
  opts;
@@ -436,6 +537,16 @@ export class RangeCalendarCellState {
436
537
  isFocusedDate = $derived.by(() => isSameDay(this.opts.date.current, this.root.opts.placeholder.current));
437
538
  isSelectedDate = $derived.by(() => this.root.isSelected(this.opts.date.current));
438
539
  isSelectionStart = $derived.by(() => this.root.isSelectionStart(this.opts.date.current));
540
+ isRangeStart = $derived.by(() => this.root.isSelectionStart(this.opts.date.current));
541
+ isRangeEnd = $derived.by(() => {
542
+ if (!this.root.opts.endValue.current)
543
+ return this.root.isSelectionStart(this.opts.date.current);
544
+ return this.root.isSelectionEnd(this.opts.date.current);
545
+ });
546
+ isRangeMiddle = $derived.by(() => this.isSelectionMiddle);
547
+ isSelectionMiddle = $derived.by(() => {
548
+ return this.isSelectedDate && !this.isSelectionStart && !this.isSelectionEnd;
549
+ });
439
550
  isSelectionEnd = $derived.by(() => this.root.isSelectionEnd(this.opts.date.current));
440
551
  isHighlighted = $derived.by(() => this.root.highlightedRange
441
552
  ? isBetweenInclusive(this.opts.date.current, this.root.highlightedRange.start, this.root.highlightedRange.end)
@@ -468,6 +579,9 @@ export class RangeCalendarCellState {
468
579
  "data-focused": this.isFocusedDate ? "" : undefined,
469
580
  "data-selection-start": this.isSelectionStart ? "" : undefined,
470
581
  "data-selection-end": this.isSelectionEnd ? "" : undefined,
582
+ "data-range-start": this.isRangeStart ? "" : undefined,
583
+ "data-range-end": this.isRangeEnd ? "" : undefined,
584
+ "data-range-middle": this.isRangeMiddle ? "" : undefined,
471
585
  "data-highlighted": this.isHighlighted ? "" : undefined,
472
586
  "data-selected": getDataSelected(this.isSelectedDate),
473
587
  "data-value": this.opts.date.current.toString(),