bits-ui 2.4.0 → 2.5.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.
- package/dist/bits/alert-dialog/components/alert-dialog-content.svelte +1 -0
- package/dist/bits/calendar/calendar.svelte.d.ts +77 -1
- package/dist/bits/calendar/calendar.svelte.js +169 -9
- package/dist/bits/calendar/components/calendar-month-select.svelte +54 -0
- package/dist/bits/calendar/components/calendar-month-select.svelte.d.ts +4 -0
- package/dist/bits/calendar/components/calendar-year-select.svelte +51 -0
- package/dist/bits/calendar/components/calendar-year-select.svelte.d.ts +4 -0
- package/dist/bits/calendar/components/calendar.svelte +6 -0
- package/dist/bits/calendar/exports.d.ts +3 -1
- package/dist/bits/calendar/exports.js +2 -0
- package/dist/bits/calendar/types.d.ts +94 -12
- package/dist/bits/combobox/types.d.ts +1 -1
- package/dist/bits/date-field/date-field.svelte.js +5 -1
- package/dist/bits/date-picker/components/date-picker-calendar.svelte +3 -0
- package/dist/bits/date-picker/components/date-picker.svelte +4 -0
- package/dist/bits/date-picker/date-picker.svelte.d.ts +2 -0
- package/dist/bits/date-picker/exports.d.ts +3 -1
- package/dist/bits/date-picker/exports.js +2 -0
- package/dist/bits/date-picker/types.d.ts +13 -1
- package/dist/bits/date-range-field/date-range-field.svelte.js +5 -1
- package/dist/bits/date-range-picker/components/date-range-picker-calendar.svelte +5 -0
- package/dist/bits/date-range-picker/components/date-range-picker.svelte +10 -0
- package/dist/bits/date-range-picker/date-range-picker.svelte.d.ts +5 -0
- package/dist/bits/date-range-picker/exports.d.ts +3 -1
- package/dist/bits/date-range-picker/exports.js +2 -0
- package/dist/bits/date-range-picker/types.d.ts +33 -1
- package/dist/bits/dialog/components/dialog-content.svelte +1 -0
- package/dist/bits/navigation-menu/components/navigation-menu-content-impl.svelte +1 -0
- package/dist/bits/range-calendar/components/range-calendar.svelte +10 -0
- package/dist/bits/range-calendar/exports.d.ts +3 -1
- package/dist/bits/range-calendar/exports.js +2 -0
- package/dist/bits/range-calendar/range-calendar.svelte.d.ts +20 -0
- package/dist/bits/range-calendar/range-calendar.svelte.js +120 -6
- package/dist/bits/range-calendar/types.d.ts +44 -12
- package/dist/bits/scroll-area/scroll-area.svelte.js +1 -1
- package/dist/bits/select/components/select-hidden-input.svelte +6 -2
- package/dist/bits/select/components/select-hidden-input.svelte.d.ts +2 -1
- package/dist/bits/select/components/select.svelte +3 -2
- package/dist/bits/select/types.d.ts +5 -0
- package/dist/bits/slider/slider.svelte.d.ts +2 -1
- package/dist/bits/slider/slider.svelte.js +7 -5
- package/dist/bits/utilities/escape-layer/escape-layer.svelte +2 -0
- package/dist/bits/utilities/escape-layer/types.d.ts +2 -0
- package/dist/bits/utilities/escape-layer/use-escape-layer.svelte.d.ts +5 -1
- package/dist/bits/utilities/escape-layer/use-escape-layer.svelte.js +4 -1
- package/dist/bits/utilities/floating-layer/use-floating-layer.svelte.js +2 -0
- package/dist/bits/utilities/popper-layer/popper-layer-inner.svelte +1 -1
- package/dist/internal/date-time/calendar-helpers.svelte.d.ts +8 -2
- package/dist/internal/date-time/calendar-helpers.svelte.js +47 -15
- package/dist/internal/date-time/formatter.d.ts +8 -1
- package/dist/internal/date-time/formatter.js +16 -3
- package/dist/internal/floating-svelte/types.d.ts +12 -0
- package/dist/internal/floating-svelte/use-floating.svelte.js +18 -12
- package/dist/internal/use-grace-area.svelte.js +5 -2
- package/dist/shared/attributes.d.ts +3 -1
- package/package.json +1 -1
|
@@ -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(
|
|
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
|
-
|
|
348
|
-
this
|
|
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(),
|
|
@@ -20,7 +20,7 @@ export type RangeCalendarRootPropsWithoutHTML = WithChild<{
|
|
|
20
20
|
* The placeholder date, used to control the view of the
|
|
21
21
|
* calendar when no value is present.
|
|
22
22
|
*
|
|
23
|
-
* @
|
|
23
|
+
* @default the current date
|
|
24
24
|
*/
|
|
25
25
|
placeholder?: DateValue;
|
|
26
26
|
/**
|
|
@@ -28,11 +28,23 @@ export type RangeCalendarRootPropsWithoutHTML = WithChild<{
|
|
|
28
28
|
* changes.
|
|
29
29
|
*/
|
|
30
30
|
onPlaceholderChange?: OnChangeFn<DateValue>;
|
|
31
|
+
/**
|
|
32
|
+
* The minimum number of days that can be selected in a range.
|
|
33
|
+
*
|
|
34
|
+
* @default undefined
|
|
35
|
+
*/
|
|
36
|
+
minDays?: number;
|
|
37
|
+
/**
|
|
38
|
+
* The maximum number of days that can be selected in a range.
|
|
39
|
+
*
|
|
40
|
+
* @default undefined
|
|
41
|
+
*/
|
|
42
|
+
maxDays?: number;
|
|
31
43
|
/**
|
|
32
44
|
* Whether or not users can deselect a date once selected
|
|
33
45
|
* without selecting another date.
|
|
34
46
|
*
|
|
35
|
-
* @
|
|
47
|
+
* @default false
|
|
36
48
|
*/
|
|
37
49
|
preventDeselect?: boolean;
|
|
38
50
|
/**
|
|
@@ -46,7 +58,7 @@ export type RangeCalendarRootPropsWithoutHTML = WithChild<{
|
|
|
46
58
|
/**
|
|
47
59
|
* Whether or not the calendar is disabled.
|
|
48
60
|
*
|
|
49
|
-
* @
|
|
61
|
+
* @default false
|
|
50
62
|
*/
|
|
51
63
|
disabled?: boolean;
|
|
52
64
|
/**
|
|
@@ -60,7 +72,7 @@ export type RangeCalendarRootPropsWithoutHTML = WithChild<{
|
|
|
60
72
|
* February), clicking the next button changes the view to March and April. If `pagedNavigation`
|
|
61
73
|
* is `false`, the view shifts to February and March.
|
|
62
74
|
*
|
|
63
|
-
* @
|
|
75
|
+
* @default false
|
|
64
76
|
*/
|
|
65
77
|
pagedNavigation?: boolean;
|
|
66
78
|
/**
|
|
@@ -68,7 +80,7 @@ export type RangeCalendarRootPropsWithoutHTML = WithChild<{
|
|
|
68
80
|
* be a number between 0 and 6, where 0 is Sunday and 6 is
|
|
69
81
|
* Saturday.
|
|
70
82
|
*
|
|
71
|
-
* @
|
|
83
|
+
* @default 0 (Sunday)
|
|
72
84
|
*/
|
|
73
85
|
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
74
86
|
/**
|
|
@@ -81,7 +93,7 @@ export type RangeCalendarRootPropsWithoutHTML = WithChild<{
|
|
|
81
93
|
* - "narrow": "S", "M", "T", etc.
|
|
82
94
|
*```
|
|
83
95
|
*
|
|
84
|
-
* @
|
|
96
|
+
* @default "narrow"
|
|
85
97
|
*
|
|
86
98
|
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#weekday
|
|
87
99
|
*/
|
|
@@ -119,14 +131,14 @@ export type RangeCalendarRootPropsWithoutHTML = WithChild<{
|
|
|
119
131
|
* To display 6 weeks per month, you will need to render out the previous
|
|
120
132
|
* and next month's dates in the calendar as well.
|
|
121
133
|
*
|
|
122
|
-
* @
|
|
134
|
+
* @default false
|
|
123
135
|
*/
|
|
124
136
|
fixedWeeks?: boolean;
|
|
125
137
|
/**
|
|
126
138
|
* Determines the number of months to display on the calendar simultaneously.
|
|
127
139
|
* For navigation between months, refer to the `pagedNavigation` prop.
|
|
128
140
|
*
|
|
129
|
-
* @
|
|
141
|
+
* @default 1
|
|
130
142
|
*/
|
|
131
143
|
numberOfMonths?: number;
|
|
132
144
|
/**
|
|
@@ -143,7 +155,7 @@ export type RangeCalendarRootPropsWithoutHTML = WithChild<{
|
|
|
143
155
|
/**
|
|
144
156
|
* The default locale setting.
|
|
145
157
|
*
|
|
146
|
-
* @
|
|
158
|
+
* @default 'en'
|
|
147
159
|
*/
|
|
148
160
|
locale?: string;
|
|
149
161
|
/**
|
|
@@ -152,7 +164,7 @@ export type RangeCalendarRootPropsWithoutHTML = WithChild<{
|
|
|
152
164
|
* dates. @see disabled for a similar prop that prevents focusing
|
|
153
165
|
* and selecting dates.
|
|
154
166
|
*
|
|
155
|
-
* @
|
|
167
|
+
* @default false
|
|
156
168
|
*/
|
|
157
169
|
readonly?: boolean;
|
|
158
170
|
/**
|
|
@@ -160,9 +172,17 @@ export type RangeCalendarRootPropsWithoutHTML = WithChild<{
|
|
|
160
172
|
* days outside the current month are rendered to fill the calendar grid, but they
|
|
161
173
|
* are not selectable. Setting this prop to `true` will disable this behavior.
|
|
162
174
|
*
|
|
163
|
-
* @
|
|
175
|
+
* @default false
|
|
164
176
|
*/
|
|
165
177
|
disableDaysOutsideMonth?: boolean;
|
|
178
|
+
/**
|
|
179
|
+
* Whether to automatically reset the range if any date within the selected range
|
|
180
|
+
* becomes disabled. When true, the entire range will be cleared if a disabled
|
|
181
|
+
* date is found between the start and end dates.
|
|
182
|
+
*
|
|
183
|
+
* @default false
|
|
184
|
+
*/
|
|
185
|
+
excludeDisabled?: boolean;
|
|
166
186
|
/**
|
|
167
187
|
* A callback function called when the start value changes. This doesn't necessarily mean
|
|
168
188
|
* the `value` has updated and should be used to apply cosmetic changes to the calendar when
|
|
@@ -175,6 +195,18 @@ export type RangeCalendarRootPropsWithoutHTML = WithChild<{
|
|
|
175
195
|
* only part of the value is changed/completed.
|
|
176
196
|
*/
|
|
177
197
|
onEndValueChange?: OnChangeFn<DateValue | undefined>;
|
|
198
|
+
/**
|
|
199
|
+
* The format of the month names in the calendar.
|
|
200
|
+
*
|
|
201
|
+
* @default "long"
|
|
202
|
+
*/
|
|
203
|
+
monthFormat?: Intl.DateTimeFormatOptions["month"] | ((month: number) => string);
|
|
204
|
+
/**
|
|
205
|
+
* The format of the year names in the calendar.
|
|
206
|
+
*
|
|
207
|
+
* @default "numeric"
|
|
208
|
+
*/
|
|
209
|
+
yearFormat?: Intl.DateTimeFormatOptions["year"] | ((year: number) => string);
|
|
178
210
|
}, RangeCalendarRootSnippetProps>;
|
|
179
211
|
export type RangeCalendarRootProps = RangeCalendarRootPropsWithoutHTML & Without<BitsPrimitiveDivAttributes, RangeCalendarRootPropsWithoutHTML>;
|
|
180
|
-
export type { CalendarPrevButtonProps as RangeCalendarPrevButtonProps, CalendarPrevButtonPropsWithoutHTML as RangeCalendarPrevButtonPropsWithoutHTML, CalendarNextButtonProps as RangeCalendarNextButtonProps, CalendarNextButtonPropsWithoutHTML as RangeCalendarNextButtonPropsWithoutHTML, CalendarHeadingProps as RangeCalendarHeadingProps, CalendarHeadingPropsWithoutHTML as RangeCalendarHeadingPropsWithoutHTML, CalendarGridProps as RangeCalendarGridProps, CalendarGridPropsWithoutHTML as RangeCalendarGridPropsWithoutHTML, CalendarCellProps as RangeCalendarCellProps, CalendarCellPropsWithoutHTML as RangeCalendarCellPropsWithoutHTML, CalendarDayProps as RangeCalendarDayProps, CalendarDayPropsWithoutHTML as RangeCalendarDayPropsWithoutHTML, CalendarGridBodyProps as RangeCalendarGridBodyProps, CalendarGridBodyPropsWithoutHTML as RangeCalendarGridBodyPropsWithoutHTML, CalendarGridHeadProps as RangeCalendarGridHeadProps, CalendarGridHeadPropsWithoutHTML as RangeCalendarGridHeadPropsWithoutHTML, CalendarGridRowProps as RangeCalendarGridRowProps, CalendarGridRowPropsWithoutHTML as RangeCalendarGridRowPropsWithoutHTML, CalendarHeadCellProps as RangeCalendarHeadCellProps, CalendarHeadCellPropsWithoutHTML as RangeCalendarHeadCellPropsWithoutHTML, CalendarHeaderProps as RangeCalendarHeaderProps, CalendarHeaderPropsWithoutHTML as RangeCalendarHeaderPropsWithoutHTML, } from "../calendar/types.js";
|
|
212
|
+
export type { CalendarPrevButtonProps as RangeCalendarPrevButtonProps, CalendarPrevButtonPropsWithoutHTML as RangeCalendarPrevButtonPropsWithoutHTML, CalendarNextButtonProps as RangeCalendarNextButtonProps, CalendarNextButtonPropsWithoutHTML as RangeCalendarNextButtonPropsWithoutHTML, CalendarHeadingProps as RangeCalendarHeadingProps, CalendarHeadingPropsWithoutHTML as RangeCalendarHeadingPropsWithoutHTML, CalendarGridProps as RangeCalendarGridProps, CalendarGridPropsWithoutHTML as RangeCalendarGridPropsWithoutHTML, CalendarCellProps as RangeCalendarCellProps, CalendarCellPropsWithoutHTML as RangeCalendarCellPropsWithoutHTML, CalendarDayProps as RangeCalendarDayProps, CalendarDayPropsWithoutHTML as RangeCalendarDayPropsWithoutHTML, CalendarGridBodyProps as RangeCalendarGridBodyProps, CalendarGridBodyPropsWithoutHTML as RangeCalendarGridBodyPropsWithoutHTML, CalendarGridHeadProps as RangeCalendarGridHeadProps, CalendarGridHeadPropsWithoutHTML as RangeCalendarGridHeadPropsWithoutHTML, CalendarGridRowProps as RangeCalendarGridRowProps, CalendarGridRowPropsWithoutHTML as RangeCalendarGridRowPropsWithoutHTML, CalendarHeadCellProps as RangeCalendarHeadCellProps, CalendarHeadCellPropsWithoutHTML as RangeCalendarHeadCellPropsWithoutHTML, CalendarHeaderProps as RangeCalendarHeaderProps, CalendarHeaderPropsWithoutHTML as RangeCalendarHeaderPropsWithoutHTML, CalendarMonthSelectProps as RangeCalendarMonthSelectProps, CalendarMonthSelectPropsWithoutHTML as RangeCalendarMonthSelectPropsWithoutHTML, CalendarYearSelectProps as RangeCalendarYearSelectProps, CalendarYearSelectPropsWithoutHTML as RangeCalendarYearSelectPropsWithoutHTML, } from "../calendar/types.js";
|
|
@@ -506,7 +506,7 @@ class ScrollAreaScrollbarSharedState {
|
|
|
506
506
|
if (isScrollbarWheel)
|
|
507
507
|
this.handleWheelScroll(e, maxScrollPos);
|
|
508
508
|
};
|
|
509
|
-
const unsubListener = addEventListener(
|
|
509
|
+
const unsubListener = addEventListener(this.root.domContext.getDocument(), "wheel", handleWheel, {
|
|
510
510
|
passive: false,
|
|
511
511
|
});
|
|
512
512
|
return unsubListener;
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { box } from "svelte-toolbelt";
|
|
3
3
|
import { useSelectHiddenInput } from "../select.svelte.js";
|
|
4
|
+
import type { HTMLInputAttributes } from "svelte/elements";
|
|
4
5
|
import HiddenInput from "../../utilities/hidden-input.svelte";
|
|
5
6
|
|
|
6
|
-
let {
|
|
7
|
+
let {
|
|
8
|
+
value = $bindable(""),
|
|
9
|
+
autocomplete,
|
|
10
|
+
}: { value?: string } & Omit<HTMLInputAttributes, "value"> = $props();
|
|
7
11
|
|
|
8
12
|
const hiddenInputState = useSelectHiddenInput({
|
|
9
13
|
value: box.with(() => value),
|
|
@@ -11,5 +15,5 @@
|
|
|
11
15
|
</script>
|
|
12
16
|
|
|
13
17
|
{#if hiddenInputState.shouldRender}
|
|
14
|
-
<HiddenInput {...hiddenInputState.props} bind:value />
|
|
18
|
+
<HiddenInput {...hiddenInputState.props} bind:value {autocomplete} />
|
|
15
19
|
{/if}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import type { HTMLInputAttributes } from "svelte/elements";
|
|
1
2
|
type $$ComponentProps = {
|
|
2
3
|
value?: string;
|
|
3
|
-
}
|
|
4
|
+
} & Omit<HTMLInputAttributes, "value">;
|
|
4
5
|
declare const SelectHiddenInput: import("svelte").Component<$$ComponentProps, {}, "value">;
|
|
5
6
|
type SelectHiddenInput = ReturnType<typeof SelectHiddenInput>;
|
|
6
7
|
export default SelectHiddenInput;
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
required = false,
|
|
21
21
|
items = [],
|
|
22
22
|
allowDeselect = false,
|
|
23
|
+
autocomplete,
|
|
23
24
|
children,
|
|
24
25
|
}: SelectRootProps = $props();
|
|
25
26
|
|
|
@@ -79,9 +80,9 @@
|
|
|
79
80
|
{#if Array.isArray(rootState.opts.value.current)}
|
|
80
81
|
{#if rootState.opts.value.current.length}
|
|
81
82
|
{#each rootState.opts.value.current as item (item)}
|
|
82
|
-
<SelectHiddenInput value={item} />
|
|
83
|
+
<SelectHiddenInput value={item} {autocomplete} />
|
|
83
84
|
{/each}
|
|
84
85
|
{/if}
|
|
85
86
|
{:else}
|
|
86
|
-
<SelectHiddenInput bind:value={rootState.opts.value.current as string} />
|
|
87
|
+
<SelectHiddenInput bind:value={rootState.opts.value.current as string} {autocomplete} />
|
|
87
88
|
{/if}
|
|
@@ -5,6 +5,7 @@ import type { ArrowProps, ArrowPropsWithoutHTML } from "../utilities/arrow/types
|
|
|
5
5
|
import type { BitsPrimitiveButtonAttributes, BitsPrimitiveDivAttributes } from "../../shared/attributes.js";
|
|
6
6
|
import type { OnChangeFn, WithChild, WithChildNoChildrenSnippetProps, WithChildren, Without } from "../../internal/types.js";
|
|
7
7
|
import type { FloatingContentSnippetProps, StaticContentSnippetProps } from "../../shared/types.js";
|
|
8
|
+
import type { HTMLInputAttributes } from "svelte/elements";
|
|
8
9
|
export type SelectBaseRootPropsWithoutHTML = WithChildren<{
|
|
9
10
|
/**
|
|
10
11
|
* Whether the combobox is disabled.
|
|
@@ -74,6 +75,10 @@ export type SelectBaseRootPropsWithoutHTML = WithChildren<{
|
|
|
74
75
|
* This is only applicable to `type="single"` selects/comboboxes.
|
|
75
76
|
*/
|
|
76
77
|
allowDeselect?: boolean;
|
|
78
|
+
/**
|
|
79
|
+
* The autocomplete attribute to forward to the hidden input element.
|
|
80
|
+
*/
|
|
81
|
+
autocomplete?: HTMLInputAttributes["autocomplete"];
|
|
77
82
|
}>;
|
|
78
83
|
export type SelectSingleRootPropsWithoutHTML = {
|
|
79
84
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Box, type ReadableBox } from "svelte-toolbelt";
|
|
1
|
+
import { type Box, type ReadableBox, DOMContext } from "svelte-toolbelt";
|
|
2
2
|
import { Context } from "runed";
|
|
3
3
|
import type { ReadableBoxedValues, WritableBoxedValues } from "../../internal/box.svelte.js";
|
|
4
4
|
import type { BitsKeyboardEvent, OnChangeFn, WithRefProps } from "../../internal/types.js";
|
|
@@ -22,6 +22,7 @@ declare class SliderBaseRootState {
|
|
|
22
22
|
isActive: boolean;
|
|
23
23
|
direction: "rl" | "lr" | "tb" | "bt";
|
|
24
24
|
normalizedSteps: number[];
|
|
25
|
+
domContext: DOMContext;
|
|
25
26
|
constructor(opts: SliderBaseRootStateProps);
|
|
26
27
|
isThumbActive(_index: number): boolean;
|
|
27
28
|
getAllThumbs: () => HTMLElement[];
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Abdelrahman (https://github.com/abdel-17)
|
|
4
4
|
*/
|
|
5
5
|
import { untrack } from "svelte";
|
|
6
|
-
import { executeCallbacks, onMountEffect, attachRef, } from "svelte-toolbelt";
|
|
6
|
+
import { executeCallbacks, onMountEffect, attachRef, DOMContext, } from "svelte-toolbelt";
|
|
7
7
|
import { on } from "svelte/events";
|
|
8
8
|
import { Context, watch } from "runed";
|
|
9
9
|
import { getRangeStyles, getThumbStyles, getTickStyles, normalizeSteps, snapValueToCustomSteps, getAdjacentStepValue, getTickLabelStyles, getThumbLabelStyles, } from "./helpers.js";
|
|
@@ -31,8 +31,10 @@ class SliderBaseRootState {
|
|
|
31
31
|
normalizedSteps = $derived.by(() => {
|
|
32
32
|
return normalizeSteps(this.opts.step.current, this.opts.min.current, this.opts.max.current);
|
|
33
33
|
});
|
|
34
|
+
domContext;
|
|
34
35
|
constructor(opts) {
|
|
35
36
|
this.opts = opts;
|
|
37
|
+
this.domContext = new DOMContext(this.opts.ref);
|
|
36
38
|
}
|
|
37
39
|
isThumbActive(_index) {
|
|
38
40
|
return this.isActive;
|
|
@@ -101,7 +103,7 @@ class SliderSingleRootState extends SliderBaseRootState {
|
|
|
101
103
|
super(opts);
|
|
102
104
|
this.opts = opts;
|
|
103
105
|
onMountEffect(() => {
|
|
104
|
-
return executeCallbacks(on(
|
|
106
|
+
return executeCallbacks(on(this.domContext.getDocument(), "pointerdown", this.handlePointerDown), on(this.domContext.getDocument(), "pointerup", this.handlePointerUp), on(this.domContext.getDocument(), "pointermove", this.handlePointerMove), on(this.domContext.getDocument(), "pointerleave", this.handlePointerUp));
|
|
105
107
|
});
|
|
106
108
|
watch([
|
|
107
109
|
() => this.opts.step.current,
|
|
@@ -191,7 +193,7 @@ class SliderSingleRootState extends SliderBaseRootState {
|
|
|
191
193
|
const closestThumb = this.getAllThumbs()[0];
|
|
192
194
|
if (!closestThumb || !sliderNode)
|
|
193
195
|
return;
|
|
194
|
-
const target = e.target;
|
|
196
|
+
const target = e.composedPath()[0] ?? e.target;
|
|
195
197
|
if (!isElementOrSVGElement(target) || !sliderNode.contains(target))
|
|
196
198
|
return;
|
|
197
199
|
e.preventDefault();
|
|
@@ -286,7 +288,7 @@ class SliderMultiRootState extends SliderBaseRootState {
|
|
|
286
288
|
super(opts);
|
|
287
289
|
this.opts = opts;
|
|
288
290
|
onMountEffect(() => {
|
|
289
|
-
return executeCallbacks(on(
|
|
291
|
+
return executeCallbacks(on(this.domContext.getDocument(), "pointerdown", this.handlePointerDown), on(this.domContext.getDocument(), "pointerup", this.handlePointerUp), on(this.domContext.getDocument(), "pointermove", this.handlePointerMove), on(this.domContext.getDocument(), "pointerleave", this.handlePointerUp));
|
|
290
292
|
});
|
|
291
293
|
watch([
|
|
292
294
|
() => this.opts.step.current,
|
|
@@ -405,7 +407,7 @@ class SliderMultiRootState extends SliderBaseRootState {
|
|
|
405
407
|
const closestThumb = this.#getClosestThumb(e);
|
|
406
408
|
if (!closestThumb || !sliderNode)
|
|
407
409
|
return;
|
|
408
|
-
const target = e.target;
|
|
410
|
+
const target = e.composedPath()[0] ?? e.target;
|
|
409
411
|
if (!isElementOrSVGElement(target) || !sliderNode.contains(target))
|
|
410
412
|
return;
|
|
411
413
|
e.preventDefault();
|
|
@@ -9,12 +9,14 @@
|
|
|
9
9
|
onEscapeKeydown = noop,
|
|
10
10
|
children,
|
|
11
11
|
enabled,
|
|
12
|
+
ref,
|
|
12
13
|
}: EscapeLayerImplProps = $props();
|
|
13
14
|
|
|
14
15
|
useEscapeLayer({
|
|
15
16
|
escapeKeydownBehavior: box.with(() => escapeKeydownBehavior),
|
|
16
17
|
onEscapeKeydown: box.with(() => onEscapeKeydown),
|
|
17
18
|
enabled: box.with(() => enabled),
|
|
19
|
+
ref,
|
|
18
20
|
});
|
|
19
21
|
</script>
|
|
20
22
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Snippet } from "svelte";
|
|
2
|
+
import type { Box } from "svelte-toolbelt";
|
|
2
3
|
export type EscapeBehaviorType = "close" | "defer-otherwise-close" | "defer-otherwise-ignore" | "ignore";
|
|
3
4
|
export type EscapeLayerProps = {
|
|
4
5
|
/**
|
|
@@ -24,4 +25,5 @@ export type EscapeLayerImplProps = {
|
|
|
24
25
|
*/
|
|
25
26
|
enabled: boolean;
|
|
26
27
|
children?: Snippet;
|
|
28
|
+
ref: Box<HTMLElement | null>;
|
|
27
29
|
} & EscapeLayerProps;
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import { DOMContext, type Box } from "svelte-toolbelt";
|
|
1
2
|
import type { EscapeLayerImplProps } from "./types.js";
|
|
2
3
|
import type { ReadableBoxedValues } from "../../../internal/box.svelte.js";
|
|
3
|
-
type EscapeLayerStateProps = ReadableBoxedValues<Required<Omit<EscapeLayerImplProps, "children"
|
|
4
|
+
type EscapeLayerStateProps = ReadableBoxedValues<Required<Omit<EscapeLayerImplProps, "children" | "ref">>> & {
|
|
5
|
+
ref: Box<HTMLElement | null>;
|
|
6
|
+
};
|
|
4
7
|
export declare class EscapeLayerState {
|
|
5
8
|
#private;
|
|
6
9
|
readonly opts: EscapeLayerStateProps;
|
|
10
|
+
readonly domContext: DOMContext;
|
|
7
11
|
constructor(opts: EscapeLayerStateProps);
|
|
8
12
|
}
|
|
9
13
|
export declare function useEscapeLayer(props: EscapeLayerStateProps): EscapeLayerState;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DOMContext } from "svelte-toolbelt";
|
|
1
2
|
import { watch } from "runed";
|
|
2
3
|
import { on } from "svelte/events";
|
|
3
4
|
import { kbd } from "../../../internal/kbd.js";
|
|
@@ -5,8 +6,10 @@ import { noop } from "../../../internal/noop.js";
|
|
|
5
6
|
globalThis.bitsEscapeLayers ??= new Map();
|
|
6
7
|
export class EscapeLayerState {
|
|
7
8
|
opts;
|
|
9
|
+
domContext;
|
|
8
10
|
constructor(opts) {
|
|
9
11
|
this.opts = opts;
|
|
12
|
+
this.domContext = new DOMContext(this.opts.ref);
|
|
10
13
|
let unsubEvents = noop;
|
|
11
14
|
watch(() => opts.enabled.current, (enabled) => {
|
|
12
15
|
if (enabled) {
|
|
@@ -20,7 +23,7 @@ export class EscapeLayerState {
|
|
|
20
23
|
});
|
|
21
24
|
}
|
|
22
25
|
#addEventListener = () => {
|
|
23
|
-
return on(
|
|
26
|
+
return on(this.domContext.getDocument(), "keydown", this.#onkeydown, { passive: false });
|
|
24
27
|
};
|
|
25
28
|
#onkeydown = (e) => {
|
|
26
29
|
if (e.key !== kbd.ESCAPE || !isResponsibleEscapeLayer(this))
|
|
@@ -183,6 +183,8 @@ class FloatingContentState {
|
|
|
183
183
|
return cleanup;
|
|
184
184
|
},
|
|
185
185
|
open: () => this.opts.enabled.current,
|
|
186
|
+
sideOffset: () => this.opts.sideOffset.current,
|
|
187
|
+
alignOffset: () => this.opts.alignOffset.current,
|
|
186
188
|
});
|
|
187
189
|
$effect(() => {
|
|
188
190
|
if (!this.floating.isPositioned)
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
{ref}
|
|
92
92
|
>
|
|
93
93
|
{#snippet focusScope({ props: focusScopeProps })}
|
|
94
|
-
<EscapeLayer {onEscapeKeydown} {escapeKeydownBehavior} {enabled}>
|
|
94
|
+
<EscapeLayer {onEscapeKeydown} {escapeKeydownBehavior} {enabled} {ref}>
|
|
95
95
|
<DismissibleLayer
|
|
96
96
|
{id}
|
|
97
97
|
{onInteractOutside}
|
|
@@ -181,7 +181,7 @@ export declare function getCalendarElementProps({ fullCalendarLabel, id, isInval
|
|
|
181
181
|
readonly "data-disabled": "" | undefined;
|
|
182
182
|
readonly "data-readonly": "" | undefined;
|
|
183
183
|
};
|
|
184
|
-
export type CalendarParts = "root" | "grid" | "cell" | "next-button" | "prev-button" | "day" | "grid-body" | "grid-head" | "grid-row" | "head-cell" | "header" | "heading";
|
|
184
|
+
export type CalendarParts = "root" | "grid" | "cell" | "next-button" | "prev-button" | "day" | "grid-body" | "grid-head" | "grid-row" | "head-cell" | "header" | "heading" | "month-select" | "year-select";
|
|
185
185
|
export declare function pickerOpenFocus(e: Event): void;
|
|
186
186
|
export declare function getFirstNonDisabledDateInView(calendarRef: HTMLElement): DateValue | undefined;
|
|
187
187
|
/**
|
|
@@ -198,5 +198,11 @@ export declare function useEnsureNonDisabledPlaceholder({ ref, placeholder, defa
|
|
|
198
198
|
defaultPlaceholder: DateValue;
|
|
199
199
|
}): void;
|
|
200
200
|
export declare function getDateWithPreviousTime(date: DateValue | undefined, prev: DateValue | undefined): DateValue | undefined;
|
|
201
|
-
export declare const calendarAttrs: import("../attrs.js").BitsAttrs<readonly ["root", "grid", "cell", "next-button", "prev-button", "day", "grid-body", "grid-head", "grid-row", "head-cell", "header", "heading"]>;
|
|
201
|
+
export declare const calendarAttrs: import("../attrs.js").BitsAttrs<readonly ["root", "grid", "cell", "next-button", "prev-button", "day", "grid-body", "grid-head", "grid-row", "head-cell", "header", "heading", "month-select", "year-select"]>;
|
|
202
|
+
type GetDefaultYearsProps = {
|
|
203
|
+
placeholderYear: number;
|
|
204
|
+
minValue: DateValue | undefined;
|
|
205
|
+
maxValue: DateValue | undefined;
|
|
206
|
+
};
|
|
207
|
+
export declare function getDefaultYears(opts: GetDefaultYearsProps): number[];
|
|
202
208
|
export {};
|