@human-kit/svelte-components 1.0.0-alpha.2 → 1.0.0-alpha.4
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/FOCUS_STATE_CONTRACT.md +63 -0
- package/dist/FOCUS_STATE_REVIEW_TEMPLATE.md +70 -0
- package/dist/calendar/README.md +2 -1
- package/dist/calendar/TODO.md +21 -107
- package/dist/calendar/body-cell/README.md +15 -0
- package/dist/calendar/body-cell/calendar-body-cell.svelte +116 -41
- package/dist/calendar/grid/README.md +13 -0
- package/dist/calendar/grid-body/README.md +13 -0
- package/dist/calendar/grid-header/README.md +13 -0
- package/dist/calendar/header-cell/README.md +14 -0
- package/dist/calendar/heading/README.md +13 -0
- package/dist/calendar/root/README.md +24 -0
- package/dist/calendar/root/calendar-root-test.svelte +4 -0
- package/dist/calendar/root/calendar-root-test.svelte.d.ts +1 -0
- package/dist/calendar/root/calendar-root.svelte +3 -0
- package/dist/calendar/root/calendar-root.svelte.d.ts +1 -0
- package/dist/calendar/root/context.d.ts +4 -0
- package/dist/calendar/root/context.js +28 -25
- package/dist/calendar/root/date-utils.d.ts +1 -1
- package/dist/calendar/root/date-utils.js +16 -26
- package/dist/calendar/trigger-next/README.md +14 -0
- package/dist/calendar/trigger-previous/README.md +14 -0
- package/dist/clock/README.md +75 -0
- package/dist/clock/axis/README.md +24 -0
- package/dist/clock/axis/clock-axis.svelte +37 -0
- package/dist/clock/axis/clock-axis.svelte.d.ts +8 -0
- package/dist/clock/hooks/use-wheel-scroll.svelte.d.ts +16 -0
- package/dist/clock/hooks/use-wheel-scroll.svelte.js +336 -0
- package/dist/clock/index.d.ts +10 -0
- package/dist/clock/index.js +10 -0
- package/dist/clock/index.parts.d.ts +4 -0
- package/dist/clock/index.parts.js +4 -0
- package/dist/clock/root/README.md +38 -0
- package/dist/clock/root/clock-root-test.svelte +62 -0
- package/dist/clock/root/clock-root-test.svelte.d.ts +14 -0
- package/dist/clock/root/clock-root.svelte +329 -0
- package/dist/clock/root/clock-root.svelte.d.ts +25 -0
- package/dist/clock/root/context.d.ts +22 -0
- package/dist/clock/root/context.js +15 -0
- package/dist/clock/root/resolve-visible-columns.d.ts +7 -0
- package/dist/clock/root/resolve-visible-columns.js +16 -0
- package/dist/clock/root/time-utils.d.ts +48 -0
- package/dist/clock/root/time-utils.js +314 -0
- package/dist/clock/root/wheel-options.d.ts +17 -0
- package/dist/clock/root/wheel-options.js +63 -0
- package/dist/clock/wheel-column/README.md +25 -0
- package/dist/clock/wheel-column/clock-wheel-column-bindable-test.svelte +16 -0
- package/dist/clock/wheel-column/clock-wheel-column-bindable-test.svelte.d.ts +3 -0
- package/dist/clock/wheel-column/clock-wheel-column-custom-snippet-test.svelte +29 -0
- package/dist/clock/wheel-column/clock-wheel-column-custom-snippet-test.svelte.d.ts +6 -0
- package/dist/clock/wheel-column/clock-wheel-column-default-height-test.svelte +11 -0
- package/dist/clock/wheel-column/clock-wheel-column-default-height-test.svelte.d.ts +3 -0
- package/dist/clock/wheel-column/clock-wheel-column-test.svelte +38 -0
- package/dist/clock/wheel-column/clock-wheel-column-test.svelte.d.ts +12 -0
- package/dist/clock/wheel-column/clock-wheel-column-tp-test.svelte +38 -0
- package/dist/clock/wheel-column/clock-wheel-column-tp-test.svelte.d.ts +12 -0
- package/dist/clock/wheel-column/clock-wheel-column-untagged-snippet-test.svelte +29 -0
- package/dist/clock/wheel-column/clock-wheel-column-untagged-snippet-test.svelte.d.ts +6 -0
- package/dist/clock/wheel-column/clock-wheel-column.svelte +499 -0
- package/dist/clock/wheel-column/clock-wheel-column.svelte.d.ts +17 -0
- package/dist/clock/wheel-item/README.md +17 -0
- package/dist/clock/wheel-item/clock-wheel-item.svelte +49 -0
- package/dist/clock/wheel-item/clock-wheel-item.svelte.d.ts +17 -0
- package/dist/combobox/TODO.md +28 -175
- package/dist/combobox/button/combobox-button.svelte +2 -0
- package/dist/combobox/root/combobox.svelte +30 -0
- package/dist/datepicker/README.md +100 -0
- package/dist/datepicker/TODO.md +28 -0
- package/dist/datepicker/calendar/README.md +19 -0
- package/dist/datepicker/calendar/date-picker-calendar-unsafe-props-test.svelte +60 -0
- package/dist/datepicker/calendar/date-picker-calendar-unsafe-props-test.svelte.d.ts +3 -0
- package/dist/datepicker/calendar/date-picker-calendar.svelte +65 -0
- package/dist/datepicker/calendar/date-picker-calendar.svelte.d.ts +10 -0
- package/dist/datepicker/index.d.ts +18 -0
- package/dist/datepicker/index.js +18 -0
- package/dist/datepicker/index.parts.d.ts +14 -0
- package/dist/datepicker/index.parts.js +14 -0
- package/dist/datepicker/input/README.md +15 -0
- package/dist/datepicker/input/date-picker-input.svelte +108 -0
- package/dist/datepicker/input/date-picker-input.svelte.d.ts +11 -0
- package/dist/datepicker/internal/strict-props.d.ts +2 -0
- package/dist/datepicker/internal/strict-props.js +28 -0
- package/dist/datepicker/popover/README.md +20 -0
- package/dist/datepicker/popover/date-picker-popover-handler-test.svelte +57 -0
- package/dist/datepicker/popover/date-picker-popover-handler-test.svelte.d.ts +3 -0
- package/dist/datepicker/popover/date-picker-popover-unsafe-props-test.svelte +45 -0
- package/dist/datepicker/popover/date-picker-popover-unsafe-props-test.svelte.d.ts +18 -0
- package/dist/datepicker/popover/date-picker-popover.svelte +87 -0
- package/dist/datepicker/popover/date-picker-popover.svelte.d.ts +7 -0
- package/dist/datepicker/root/README.md +38 -0
- package/dist/datepicker/root/context.d.ts +43 -0
- package/dist/datepicker/root/context.js +15 -0
- package/dist/datepicker/root/date-picker-bindable-empty-test.svelte +24 -0
- package/dist/datepicker/root/date-picker-bindable-empty-test.svelte.d.ts +3 -0
- package/dist/datepicker/root/date-picker-bindable-test.svelte +41 -0
- package/dist/datepicker/root/date-picker-bindable-test.svelte.d.ts +3 -0
- package/dist/datepicker/root/date-picker-empty-test.svelte +47 -0
- package/dist/datepicker/root/date-picker-empty-test.svelte.d.ts +3 -0
- package/dist/datepicker/root/date-picker-locale-typing-test.svelte +47 -0
- package/dist/datepicker/root/date-picker-locale-typing-test.svelte.d.ts +3 -0
- package/dist/datepicker/root/date-picker-open-cancel-test.svelte +54 -0
- package/dist/datepicker/root/date-picker-open-cancel-test.svelte.d.ts +8 -0
- package/dist/datepicker/root/date-picker-root.svelte +495 -0
- package/dist/datepicker/root/date-picker-root.svelte.d.ts +24 -0
- package/dist/datepicker/root/date-picker-test.svelte +86 -0
- package/dist/datepicker/root/date-picker-test.svelte.d.ts +13 -0
- package/dist/datepicker/root/date-utils.d.ts +17 -0
- package/dist/datepicker/root/date-utils.js +138 -0
- package/dist/datepicker/root/draft-evaluation.d.ts +13 -0
- package/dist/datepicker/root/draft-evaluation.js +56 -0
- package/dist/datepicker/root/focus-controller.d.ts +3 -0
- package/dist/datepicker/root/focus-controller.js +15 -0
- package/dist/datepicker/root/open-change.d.ts +5 -0
- package/dist/datepicker/root/open-change.js +13 -0
- package/dist/datepicker/root/open-controller.d.ts +7 -0
- package/dist/datepicker/root/open-controller.js +15 -0
- package/dist/datepicker/root/segment-controller.d.ts +8 -0
- package/dist/datepicker/root/segment-controller.js +53 -0
- package/dist/datepicker/root/segment-state.d.ts +18 -0
- package/dist/datepicker/root/segment-state.js +134 -0
- package/dist/datepicker/root/value-commit.d.ts +4 -0
- package/dist/datepicker/root/value-commit.js +8 -0
- package/dist/datepicker/segment/README.md +14 -0
- package/dist/datepicker/segment/date-picker-segment.svelte +319 -0
- package/dist/datepicker/segment/date-picker-segment.svelte.d.ts +9 -0
- package/dist/datepicker/trigger/README.md +14 -0
- package/dist/datepicker/trigger/date-picker-trigger.svelte +110 -0
- package/dist/datepicker/trigger/date-picker-trigger.svelte.d.ts +9 -0
- package/dist/dialog/content/dialog-content.svelte +6 -6
- package/dist/dialog/root/context.d.ts +2 -1
- package/dist/dialog/root/dialog-root.svelte +9 -2
- package/dist/index.d.ts +8 -0
- package/dist/index.js +8 -0
- package/dist/listbox/root/listbox.svelte +44 -0
- package/dist/popover/README.md +10 -0
- package/dist/popover/content/popover-content-standalone-test.svelte +28 -0
- package/dist/popover/content/popover-content-standalone-test.svelte.d.ts +6 -0
- package/dist/popover/content/popover-content-test.svelte +2 -1
- package/dist/popover/content/popover-content-test.svelte.d.ts +2 -1
- package/dist/popover/content/popover-content.svelte +91 -18
- package/dist/popover/content/popover-content.svelte.d.ts +5 -1
- package/dist/popover/index.d.ts +1 -1
- package/dist/popover/index.js +1 -3
- package/dist/popover/root/README.md +10 -15
- package/dist/popover/root/context.d.ts +16 -7
- package/dist/popover/root/context.js +0 -2
- package/dist/popover/root/focus-state.d.ts +4 -0
- package/dist/popover/root/focus-state.js +33 -0
- package/dist/popover/root/popover-root.svelte +90 -17
- package/dist/popover/root/popover-root.svelte.d.ts +2 -1
- package/dist/popover/root/popover-test.svelte +2 -1
- package/dist/popover/root/popover-test.svelte.d.ts +2 -1
- package/dist/popover/trigger/popover-trigger-button.svelte +4 -4
- package/dist/popover/trigger/popover-trigger.svelte +1 -1
- package/dist/portal/portal.svelte +3 -1
- package/dist/primitives/click-outside.d.ts +1 -1
- package/dist/primitives/click-outside.js +1 -1
- package/dist/primitives/focus-trap.d.ts +7 -2
- package/dist/primitives/focus-trap.js +50 -17
- package/dist/primitives/index.d.ts +1 -0
- package/dist/primitives/index.js +1 -0
- package/dist/primitives/input-modality.d.ts +7 -0
- package/dist/primitives/input-modality.js +125 -0
- package/dist/test-utils/focus-contract.d.ts +3 -0
- package/dist/test-utils/focus-contract.js +26 -0
- package/dist/timepicker/IMPLEMENTATION_PLAN.md +254 -0
- package/dist/timepicker/README.md +97 -0
- package/dist/timepicker/TODO.md +86 -0
- package/dist/timepicker/clock/README.md +14 -0
- package/dist/timepicker/clock/time-picker-clock-test.svelte +45 -0
- package/dist/timepicker/clock/time-picker-clock-test.svelte.d.ts +11 -0
- package/dist/timepicker/clock/time-picker-clock.svelte +65 -0
- package/dist/timepicker/clock/time-picker-clock.svelte.d.ts +10 -0
- package/dist/timepicker/index.d.ts +14 -0
- package/dist/timepicker/index.js +14 -0
- package/dist/timepicker/index.parts.d.ts +8 -0
- package/dist/timepicker/index.parts.js +8 -0
- package/dist/timepicker/input/README.md +15 -0
- package/dist/timepicker/input/time-picker-input-forwarding-test.svelte +40 -0
- package/dist/timepicker/input/time-picker-input-forwarding-test.svelte.d.ts +3 -0
- package/dist/timepicker/input/time-picker-input.svelte +109 -0
- package/dist/timepicker/input/time-picker-input.svelte.d.ts +11 -0
- package/dist/timepicker/internal/strict-props.d.ts +4 -0
- package/dist/timepicker/internal/strict-props.js +51 -0
- package/dist/timepicker/popover/README.md +20 -0
- package/dist/timepicker/popover/time-picker-popover-unsafe-props-test.svelte +22 -0
- package/dist/timepicker/popover/time-picker-popover-unsafe-props-test.svelte.d.ts +3 -0
- package/dist/timepicker/popover/time-picker-popover.svelte +89 -0
- package/dist/timepicker/popover/time-picker-popover.svelte.d.ts +7 -0
- package/dist/timepicker/root/README.md +42 -0
- package/dist/timepicker/root/context.d.ts +51 -0
- package/dist/timepicker/root/context.js +15 -0
- package/dist/timepicker/root/time-picker-12h-test.svelte +22 -0
- package/dist/timepicker/root/time-picker-12h-test.svelte.d.ts +3 -0
- package/dist/timepicker/root/time-picker-bindable-test.svelte +25 -0
- package/dist/timepicker/root/time-picker-bindable-test.svelte.d.ts +3 -0
- package/dist/timepicker/root/time-picker-empty-test.svelte +20 -0
- package/dist/timepicker/root/time-picker-empty-test.svelte.d.ts +3 -0
- package/dist/timepicker/root/time-picker-root.svelte +625 -0
- package/dist/timepicker/root/time-picker-root.svelte.d.ts +28 -0
- package/dist/timepicker/root/time-picker-test.svelte +72 -0
- package/dist/timepicker/root/time-picker-test.svelte.d.ts +15 -0
- package/dist/timepicker/root/time-utils.d.ts +1 -0
- package/dist/timepicker/root/time-utils.js +3 -0
- package/dist/timepicker/segment/README.md +14 -0
- package/dist/timepicker/segment/time-picker-segment.svelte +365 -0
- package/dist/timepicker/segment/time-picker-segment.svelte.d.ts +9 -0
- package/dist/timepicker/trigger/README.md +14 -0
- package/dist/timepicker/trigger/time-picker-trigger-forwarding-test.svelte +35 -0
- package/dist/timepicker/trigger/time-picker-trigger-forwarding-test.svelte.d.ts +3 -0
- package/dist/timepicker/trigger/time-picker-trigger.svelte +122 -0
- package/dist/timepicker/trigger/time-picker-trigger.svelte.d.ts +9 -0
- package/dist/utils/date-only.d.ts +11 -0
- package/dist/utils/date-only.js +53 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/package.json +16 -1
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
type CalendarRootProps = {
|
|
35
35
|
selectionMode?: CalendarSelectionMode;
|
|
36
36
|
visibleMonths?: number;
|
|
37
|
+
showOutsideDays?: boolean;
|
|
37
38
|
isDateUnavailable?: (date: string) => boolean;
|
|
38
39
|
isDisabled?: boolean;
|
|
39
40
|
isReadOnly?: boolean;
|
|
@@ -62,6 +63,7 @@
|
|
|
62
63
|
let {
|
|
63
64
|
selectionMode = 'single',
|
|
64
65
|
visibleMonths = 1,
|
|
66
|
+
showOutsideDays = false,
|
|
65
67
|
isDateUnavailable,
|
|
66
68
|
isDisabled = false,
|
|
67
69
|
isReadOnly = false,
|
|
@@ -100,6 +102,7 @@
|
|
|
100
102
|
return {
|
|
101
103
|
selectionMode,
|
|
102
104
|
visibleMonths,
|
|
105
|
+
showOutsideDays,
|
|
103
106
|
locale: resolvedLocale,
|
|
104
107
|
isDateUnavailable,
|
|
105
108
|
isDisabled,
|
|
@@ -4,6 +4,7 @@ import { type CalendarDateValue } from './date-utils';
|
|
|
4
4
|
type CalendarRootProps = {
|
|
5
5
|
selectionMode?: CalendarSelectionMode;
|
|
6
6
|
visibleMonths?: number;
|
|
7
|
+
showOutsideDays?: boolean;
|
|
7
8
|
isDateUnavailable?: (date: string) => boolean;
|
|
8
9
|
isDisabled?: boolean;
|
|
9
10
|
isReadOnly?: boolean;
|
|
@@ -16,6 +16,7 @@ export type CalendarMonth = {
|
|
|
16
16
|
export type CreateCalendarContextOptions<TSelectionMode extends CalendarSelectionMode = CalendarSelectionMode> = {
|
|
17
17
|
selectionMode?: TSelectionMode;
|
|
18
18
|
visibleMonths?: number;
|
|
19
|
+
showOutsideDays?: boolean;
|
|
19
20
|
locale?: string;
|
|
20
21
|
isDisabled?: boolean;
|
|
21
22
|
isReadOnly?: boolean;
|
|
@@ -31,12 +32,14 @@ export type CalendarContext = {
|
|
|
31
32
|
selectionMode: CalendarSelectionMode;
|
|
32
33
|
firstDayOfWeek: number;
|
|
33
34
|
visibleMonths: number;
|
|
35
|
+
showOutsideDays: boolean;
|
|
34
36
|
isDisabled: boolean;
|
|
35
37
|
isReadOnly: boolean;
|
|
36
38
|
months: CalendarMonth[];
|
|
37
39
|
selectedValue: CalendarDateValue | undefined;
|
|
38
40
|
rangeValue: CalendarRangeValue | undefined;
|
|
39
41
|
focusedValue: CalendarDateValue;
|
|
42
|
+
focusVisible: boolean;
|
|
40
43
|
weekdayLabels: string[];
|
|
41
44
|
headingLabel: string;
|
|
42
45
|
isSelected: (date: CalendarDateValue) => boolean;
|
|
@@ -47,6 +50,7 @@ export type CalendarContext = {
|
|
|
47
50
|
isDateDisabled: (date: CalendarDateValue) => boolean;
|
|
48
51
|
isOutsideVisibleRange: (date: CalendarDateValue, monthIndex: number) => boolean;
|
|
49
52
|
setFocusedValue: (date: CalendarDateValue) => void;
|
|
53
|
+
setFocusVisible: (visible: boolean) => void;
|
|
50
54
|
setHoveredValue: (date: CalendarDateValue | undefined) => void;
|
|
51
55
|
selectDate: (date: CalendarDateValue) => void;
|
|
52
56
|
goToNextPage: () => void;
|
|
@@ -2,9 +2,8 @@ import { getContext, setContext } from 'svelte';
|
|
|
2
2
|
import { writable } from 'svelte/store';
|
|
3
3
|
import { addDays, addMonths, buildMonthGrid, compareDates, formatCalendarDate, formatMonthHeading, getFirstDayOfWeek, getTodayUtcDate, getWeekdayLabels, isValidCalendarDateValue, parseCalendarDate, startOfMonth } from './date-utils';
|
|
4
4
|
const KEY = Symbol('calendar');
|
|
5
|
-
const MAX_FOCUS_SEARCH_DAYS = 370;
|
|
6
5
|
export function createCalendarContext(options) {
|
|
7
|
-
let { selectionMode = 'single', visibleMonths = 1, locale = Intl.DateTimeFormat().resolvedOptions().locale, isDisabled = false, isReadOnly = false, isDateUnavailable, onChange } = options;
|
|
6
|
+
let { selectionMode = 'single', visibleMonths = 1, showOutsideDays = false, locale = Intl.DateTimeFormat().resolvedOptions().locale, isDisabled = false, isReadOnly = false, isDateUnavailable, onChange } = options;
|
|
8
7
|
const { value, defaultValue } = options;
|
|
9
8
|
function isRangeValue(valueToCheck) {
|
|
10
9
|
if (!valueToCheck || typeof valueToCheck === 'string')
|
|
@@ -85,6 +84,7 @@ export function createCalendarContext(options) {
|
|
|
85
84
|
initialRangeSelected?.end ??
|
|
86
85
|
initialRangeSelected?.start ??
|
|
87
86
|
fallbackToday;
|
|
87
|
+
let currentFocusVisible = false;
|
|
88
88
|
let currentVisibleMonth = startOfMonth(parseCalendarDate(currentFocused) ?? getTodayUtcDate());
|
|
89
89
|
let cachedMonths = [];
|
|
90
90
|
let hasCachedMonths = false;
|
|
@@ -93,6 +93,7 @@ export function createCalendarContext(options) {
|
|
|
93
93
|
let pendingRangePathCacheStart;
|
|
94
94
|
let previousUnavailableFn = isDateUnavailable;
|
|
95
95
|
let previousVisibleMonths = visibleMonths;
|
|
96
|
+
let previousShowOutsideDays = showOutsideDays;
|
|
96
97
|
let previousLocale = locale;
|
|
97
98
|
let cachedFirstDayOfWeek = getFirstDayOfWeek(locale);
|
|
98
99
|
const layoutVersion = writable(0);
|
|
@@ -133,16 +134,19 @@ export function createCalendarContext(options) {
|
|
|
133
134
|
let shouldNotifySelection = false;
|
|
134
135
|
const nextSelectionMode = next.selectionMode ?? 'single';
|
|
135
136
|
const nextVisibleMonths = Math.max(1, next.visibleMonths ?? 1);
|
|
137
|
+
const nextShowOutsideDays = next.showOutsideDays ?? false;
|
|
136
138
|
const nextLocale = next.locale ?? Intl.DateTimeFormat().resolvedOptions().locale;
|
|
137
139
|
const nextUnavailableFn = next.isDateUnavailable;
|
|
138
140
|
if (nextUnavailableFn !== previousUnavailableFn ||
|
|
139
141
|
nextVisibleMonths !== previousVisibleMonths ||
|
|
142
|
+
nextShowOutsideDays !== previousShowOutsideDays ||
|
|
140
143
|
nextLocale !== previousLocale) {
|
|
141
144
|
clearUnavailableCache();
|
|
142
145
|
shouldNotifyLayout = true;
|
|
143
146
|
}
|
|
144
147
|
previousUnavailableFn = nextUnavailableFn;
|
|
145
148
|
previousVisibleMonths = nextVisibleMonths;
|
|
149
|
+
previousShowOutsideDays = nextShowOutsideDays;
|
|
146
150
|
previousLocale = nextLocale;
|
|
147
151
|
if (selectionMode !== nextSelectionMode) {
|
|
148
152
|
selectionMode = nextSelectionMode;
|
|
@@ -157,6 +161,7 @@ export function createCalendarContext(options) {
|
|
|
157
161
|
shouldNotifyLayout = true;
|
|
158
162
|
}
|
|
159
163
|
visibleMonths = nextVisibleMonths;
|
|
164
|
+
showOutsideDays = nextShowOutsideDays;
|
|
160
165
|
locale = nextLocale;
|
|
161
166
|
cachedFirstDayOfWeek = getFirstDayOfWeek(locale);
|
|
162
167
|
if (isDisabled !== (next.isDisabled ?? false) || isReadOnly !== (next.isReadOnly ?? false)) {
|
|
@@ -312,7 +317,7 @@ export function createCalendarContext(options) {
|
|
|
312
317
|
monthIndex,
|
|
313
318
|
monthStart,
|
|
314
319
|
heading: formatMonthHeading(monthStart, locale),
|
|
315
|
-
weeks: buildMonthGrid(monthStart, firstDayOfWeek)
|
|
320
|
+
weeks: buildMonthGrid(monthStart, firstDayOfWeek, showOutsideDays)
|
|
316
321
|
};
|
|
317
322
|
});
|
|
318
323
|
hasCachedMonths = true;
|
|
@@ -359,7 +364,7 @@ export function createCalendarContext(options) {
|
|
|
359
364
|
return result;
|
|
360
365
|
}
|
|
361
366
|
function isDateDisabled(date) {
|
|
362
|
-
if (isDisabled
|
|
367
|
+
if (isDisabled)
|
|
363
368
|
return true;
|
|
364
369
|
if (selectionMode === 'range' && currentRangeStart && !currentRangeEnd) {
|
|
365
370
|
return !isPendingRangePathSelectable(date);
|
|
@@ -386,6 +391,12 @@ export function createCalendarContext(options) {
|
|
|
386
391
|
}
|
|
387
392
|
notifySelection();
|
|
388
393
|
}
|
|
394
|
+
function setFocusVisible(visible) {
|
|
395
|
+
if (currentFocusVisible === visible)
|
|
396
|
+
return;
|
|
397
|
+
currentFocusVisible = visible;
|
|
398
|
+
notifySelection();
|
|
399
|
+
}
|
|
389
400
|
function setHoveredValue(date) {
|
|
390
401
|
if (selectionMode !== 'range')
|
|
391
402
|
return;
|
|
@@ -514,7 +525,7 @@ export function createCalendarContext(options) {
|
|
|
514
525
|
return undefined;
|
|
515
526
|
const next = addDays(parsed, amount);
|
|
516
527
|
const nextValue = formatCalendarDate(next);
|
|
517
|
-
const focusableValue = findFocusableDate(nextValue
|
|
528
|
+
const focusableValue = findFocusableDate(nextValue);
|
|
518
529
|
if (!focusableValue)
|
|
519
530
|
return undefined;
|
|
520
531
|
setFocusedValue(focusableValue);
|
|
@@ -526,8 +537,7 @@ export function createCalendarContext(options) {
|
|
|
526
537
|
return undefined;
|
|
527
538
|
const next = addMonths(parsed, amount);
|
|
528
539
|
const nextValue = formatCalendarDate(next);
|
|
529
|
-
const
|
|
530
|
-
const focusableValue = findFocusableDate(nextValue, dayStep);
|
|
540
|
+
const focusableValue = findFocusableDate(nextValue);
|
|
531
541
|
if (!focusableValue) {
|
|
532
542
|
if (selectionMode === 'range' && currentRangeStart && !currentRangeEnd) {
|
|
533
543
|
return moveToMonthEdge(baseDate, amount >= 0 ? 'end' : 'start');
|
|
@@ -545,33 +555,19 @@ export function createCalendarContext(options) {
|
|
|
545
555
|
const monthEnd = addDays(addMonths(monthStart, 1), -1);
|
|
546
556
|
const targetDate = edge === 'start' ? monthStart : monthEnd;
|
|
547
557
|
const nextValue = formatCalendarDate(targetDate);
|
|
548
|
-
const
|
|
549
|
-
const focusableValue = findFocusableDate(nextValue, dayStep);
|
|
558
|
+
const focusableValue = findFocusableDate(nextValue);
|
|
550
559
|
if (!focusableValue)
|
|
551
560
|
return undefined;
|
|
552
561
|
setFocusedValue(focusableValue);
|
|
553
562
|
return focusableValue;
|
|
554
563
|
}
|
|
555
|
-
function findFocusableDate(targetDate
|
|
564
|
+
function findFocusableDate(targetDate) {
|
|
556
565
|
if (isDisabled)
|
|
557
566
|
return undefined;
|
|
558
|
-
|
|
559
|
-
return targetDate;
|
|
560
|
-
if (dayStep === 0)
|
|
561
|
-
return undefined;
|
|
562
|
-
let current = parseCalendarDate(targetDate);
|
|
563
|
-
if (!current)
|
|
564
|
-
return undefined;
|
|
565
|
-
for (let index = 0; index < MAX_FOCUS_SEARCH_DAYS; index++) {
|
|
566
|
-
current = addDays(current, dayStep > 0 ? 1 : -1);
|
|
567
|
-
const candidate = formatCalendarDate(current);
|
|
568
|
-
if (!isDateDisabled(candidate)) {
|
|
569
|
-
return candidate;
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
return undefined;
|
|
567
|
+
return targetDate;
|
|
573
568
|
}
|
|
574
569
|
function handleCellKeydown(event, date) {
|
|
570
|
+
setFocusVisible(true);
|
|
575
571
|
const keyDate = isValidCalendarDateValue(currentFocused) ? currentFocused : date;
|
|
576
572
|
let movedDate;
|
|
577
573
|
function extendRangeWithKeyboard(nextDate) {
|
|
@@ -668,6 +664,9 @@ export function createCalendarContext(options) {
|
|
|
668
664
|
get visibleMonths() {
|
|
669
665
|
return visibleMonths;
|
|
670
666
|
},
|
|
667
|
+
get showOutsideDays() {
|
|
668
|
+
return showOutsideDays;
|
|
669
|
+
},
|
|
671
670
|
get isDisabled() {
|
|
672
671
|
return isDisabled;
|
|
673
672
|
},
|
|
@@ -686,6 +685,9 @@ export function createCalendarContext(options) {
|
|
|
686
685
|
get focusedValue() {
|
|
687
686
|
return currentFocused;
|
|
688
687
|
},
|
|
688
|
+
get focusVisible() {
|
|
689
|
+
return currentFocusVisible;
|
|
690
|
+
},
|
|
689
691
|
get weekdayLabels() {
|
|
690
692
|
return getWeekdayLabels(locale, cachedFirstDayOfWeek);
|
|
691
693
|
},
|
|
@@ -700,6 +702,7 @@ export function createCalendarContext(options) {
|
|
|
700
702
|
isDateDisabled,
|
|
701
703
|
isOutsideVisibleRange,
|
|
702
704
|
setFocusedValue,
|
|
705
|
+
setFocusVisible,
|
|
703
706
|
setHoveredValue,
|
|
704
707
|
selectDate,
|
|
705
708
|
goToNextPage,
|
|
@@ -13,5 +13,5 @@ export type CalendarDayCell = {
|
|
|
13
13
|
date: CalendarDateValue;
|
|
14
14
|
isOutsideMonth: boolean;
|
|
15
15
|
};
|
|
16
|
-
export declare function buildMonthGrid(monthStart: Date, firstDayOfWeek: number): CalendarDayCell[][];
|
|
16
|
+
export declare function buildMonthGrid(monthStart: Date, firstDayOfWeek: number, showOutsideDays?: boolean): CalendarDayCell[][];
|
|
17
17
|
export declare function formatMonthHeading(date: Date, locale: string): string;
|
|
@@ -1,43 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
import { createUtcDate, formatDateOnlyValue, isValidDateOnlyValue, parseDateOnlyValue } from '../../utils/date-only';
|
|
2
2
|
export function isValidCalendarDateValue(value) {
|
|
3
|
-
|
|
4
|
-
if (!match)
|
|
5
|
-
return false;
|
|
6
|
-
const year = Number(match[1]);
|
|
7
|
-
const month = Number(match[2]);
|
|
8
|
-
const day = Number(match[3]);
|
|
9
|
-
if (month < 1 || month > 12 || day < 1 || day > 31)
|
|
10
|
-
return false;
|
|
11
|
-
const date = new Date(Date.UTC(year, month - 1, day));
|
|
12
|
-
return (date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day);
|
|
3
|
+
return isValidDateOnlyValue(value);
|
|
13
4
|
}
|
|
14
5
|
export function parseCalendarDate(value) {
|
|
15
|
-
|
|
16
|
-
return null;
|
|
17
|
-
const [year, month, day] = value.split('-').map(Number);
|
|
18
|
-
return new Date(Date.UTC(year, month - 1, day));
|
|
6
|
+
return parseDateOnlyValue(value);
|
|
19
7
|
}
|
|
20
8
|
export function formatCalendarDate(date) {
|
|
21
|
-
|
|
22
|
-
const month = String(date.getUTCMonth() + 1).padStart(2, '0');
|
|
23
|
-
const day = String(date.getUTCDate()).padStart(2, '0');
|
|
24
|
-
return `${year}-${month}-${day}`;
|
|
9
|
+
return formatDateOnlyValue(date);
|
|
25
10
|
}
|
|
26
11
|
export function startOfMonth(date) {
|
|
27
|
-
return
|
|
12
|
+
return createUtcDate(date.getUTCFullYear(), date.getUTCMonth(), 1);
|
|
28
13
|
}
|
|
29
14
|
function getDaysInMonthUtc(year, monthIndex) {
|
|
30
|
-
return
|
|
15
|
+
return createUtcDate(year, monthIndex + 1, 0).getUTCDate();
|
|
31
16
|
}
|
|
32
17
|
export function addMonths(date, amount) {
|
|
33
18
|
const targetMonth = date.getUTCMonth() + amount;
|
|
34
19
|
const targetYear = date.getUTCFullYear() + Math.floor(targetMonth / 12);
|
|
35
20
|
const normalizedMonth = ((targetMonth % 12) + 12) % 12;
|
|
36
21
|
const targetDay = Math.min(date.getUTCDate(), getDaysInMonthUtc(targetYear, normalizedMonth));
|
|
37
|
-
return
|
|
22
|
+
return createUtcDate(targetYear, normalizedMonth, targetDay);
|
|
38
23
|
}
|
|
39
24
|
export function addDays(date, amount) {
|
|
40
|
-
return
|
|
25
|
+
return createUtcDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() + amount);
|
|
41
26
|
}
|
|
42
27
|
export function compareDates(a, b) {
|
|
43
28
|
const at = a.getTime();
|
|
@@ -50,7 +35,7 @@ export function compareDates(a, b) {
|
|
|
50
35
|
}
|
|
51
36
|
export function getTodayUtcDate() {
|
|
52
37
|
const now = new Date();
|
|
53
|
-
return
|
|
38
|
+
return createUtcDate(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate());
|
|
54
39
|
}
|
|
55
40
|
export function getFirstDayOfWeek(locale) {
|
|
56
41
|
try {
|
|
@@ -76,13 +61,18 @@ export function getWeekdayLabels(locale, firstDayOfWeek) {
|
|
|
76
61
|
return formatter.format(addDays(sunday, dayOffset));
|
|
77
62
|
});
|
|
78
63
|
}
|
|
79
|
-
export function buildMonthGrid(monthStart, firstDayOfWeek) {
|
|
64
|
+
export function buildMonthGrid(monthStart, firstDayOfWeek, showOutsideDays = true) {
|
|
80
65
|
const firstOfMonth = startOfMonth(monthStart);
|
|
81
66
|
const firstWeekday = firstOfMonth.getUTCDay();
|
|
82
67
|
const startOffset = (firstWeekday - firstDayOfWeek + 7) % 7;
|
|
83
68
|
const gridStart = addDays(firstOfMonth, -startOffset);
|
|
69
|
+
const lastOfMonth = addDays(addMonths(firstOfMonth, 1), -1);
|
|
70
|
+
const lastWeekday = lastOfMonth.getUTCDay();
|
|
71
|
+
const endOffset = (firstDayOfWeek + 6 - lastWeekday + 7) % 7;
|
|
72
|
+
const visibleDays = startOffset + lastOfMonth.getUTCDate() + endOffset;
|
|
73
|
+
const weekCount = showOutsideDays ? 6 : Math.max(1, Math.ceil(visibleDays / 7));
|
|
84
74
|
const weeks = [];
|
|
85
|
-
for (let weekIndex = 0; weekIndex <
|
|
75
|
+
for (let weekIndex = 0; weekIndex < weekCount; weekIndex++) {
|
|
86
76
|
const week = [];
|
|
87
77
|
for (let dayIndex = 0; dayIndex < 7; dayIndex++) {
|
|
88
78
|
const date = addDays(gridStart, weekIndex * 7 + dayIndex);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Calendar TriggerNext
|
|
2
|
+
|
|
3
|
+
## API reference
|
|
4
|
+
|
|
5
|
+
### Calendar.TriggerNext
|
|
6
|
+
|
|
7
|
+
Name: `Calendar.TriggerNext`
|
|
8
|
+
Description: Button part that advances the visible calendar period.
|
|
9
|
+
|
|
10
|
+
| Prop | Type | Default | Description |
|
|
11
|
+
| -------------- | ---------------------- | ----------- | ------------------------------------------------------ |
|
|
12
|
+
| `children` | `Snippet` | `undefined` | Optional trigger content. |
|
|
13
|
+
| `class` | `string` | `''` | CSS class names for the trigger button. |
|
|
14
|
+
| `...restProps` | `HTMLButtonAttributes` | `-` | Additional button attributes forwarded to the trigger. |
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Calendar TriggerPrevious
|
|
2
|
+
|
|
3
|
+
## API reference
|
|
4
|
+
|
|
5
|
+
### Calendar.TriggerPrevious
|
|
6
|
+
|
|
7
|
+
Name: `Calendar.TriggerPrevious`
|
|
8
|
+
Description: Button part that moves the visible calendar period backward.
|
|
9
|
+
|
|
10
|
+
| Prop | Type | Default | Description |
|
|
11
|
+
| -------------- | ---------------------- | ----------- | ------------------------------------------------------ |
|
|
12
|
+
| `children` | `Snippet` | `undefined` | Optional trigger content. |
|
|
13
|
+
| `class` | `string` | `''` | CSS class names for the trigger button. |
|
|
14
|
+
| `...restProps` | `HTMLButtonAttributes` | `-` | Additional button attributes forwarded to the trigger. |
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Clock
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
`Clock` provides a standalone wheel-based time picker with spinbutton columns for hour, minute, second, and day-period selection. It can be used independently or composed inside `TimePicker` via `TimePicker.Clock`.
|
|
6
|
+
|
|
7
|
+
## Anatomy
|
|
8
|
+
|
|
9
|
+
- `Clock.Root`
|
|
10
|
+
- `Clock.Axis`
|
|
11
|
+
- `Clock.WheelColumn`
|
|
12
|
+
- `Clock.WheelItem`
|
|
13
|
+
|
|
14
|
+
```svelte
|
|
15
|
+
<Clock.Root value="14:30" granularity="minute" hourCycle={24} class="flex gap-2">
|
|
16
|
+
{#snippet column(col)}
|
|
17
|
+
<Clock.WheelColumn type={col.type} class="h-44 w-16">
|
|
18
|
+
{#snippet children(option)}
|
|
19
|
+
<Clock.WheelItem type={col.type} {option} class="..." />
|
|
20
|
+
{/snippet}
|
|
21
|
+
</Clock.WheelColumn>
|
|
22
|
+
{/snippet}
|
|
23
|
+
<Clock.Axis class="rounded-md ring-1 ring-inset" />
|
|
24
|
+
</Clock.Root>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Default columns are rendered automatically when no `column` snippet is provided:
|
|
28
|
+
|
|
29
|
+
```svelte
|
|
30
|
+
<Clock.Root value="09:00" granularity="minute" hourCycle={24} />
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Root API
|
|
34
|
+
|
|
35
|
+
- `value?: string | null` (`HH:mm` or `HH:mm:ss`)
|
|
36
|
+
- `defaultValue?: string | null` (`HH:mm` or `HH:mm:ss`)
|
|
37
|
+
- `onChange?: (value: string | null) => void`
|
|
38
|
+
- `minValue?: string`
|
|
39
|
+
- `maxValue?: string`
|
|
40
|
+
- `hourCycle?: 12 | 24` (defaults to locale)
|
|
41
|
+
- `granularity?: 'hour' | 'minute' | 'second'` (defaults to `'minute'`)
|
|
42
|
+
- `hourStep?: number`
|
|
43
|
+
- `minuteStep?: number`
|
|
44
|
+
- `secondStep?: number`
|
|
45
|
+
- `isDisabled?: boolean`
|
|
46
|
+
- `column?: Snippet<[ClockColumnInfo]>` — custom per-column rendering
|
|
47
|
+
- `children?: Snippet` — arbitrary children. When `column` is used, children render after columns (useful for overlays like `Clock.Axis`).
|
|
48
|
+
- `class?: string`
|
|
49
|
+
- `aria-label?: string`
|
|
50
|
+
|
|
51
|
+
Visible columns are resolved automatically in stable order: `hour → minute? → second? → dayPeriod?`.
|
|
52
|
+
|
|
53
|
+
## Wheel API
|
|
54
|
+
|
|
55
|
+
- `Clock.Axis` renders a root-level visual overlay (for example, a central selection band) across all columns.
|
|
56
|
+
- `Clock.WheelColumn` renders one wheel (`role="spinbutton"`) for one editable segment (`hour`, `minute`, `second`, or `dayPeriod`).
|
|
57
|
+
- `Clock.WheelItem` is headless: it renders one item (`data-wheel-item`) with state attributes (`data-selected`, `data-disabled`, `data-centered`) and leaves all visual styling to consumers.
|
|
58
|
+
- `ClockColumnInfo` shape:
|
|
59
|
+
- `type: 'hour' | 'minute' | 'second' | 'dayPeriod'`
|
|
60
|
+
- `label?: string`
|
|
61
|
+
|
|
62
|
+
## Accessibility
|
|
63
|
+
|
|
64
|
+
- Each wheel column exposes `role="spinbutton"` with `aria-valuenow`, `aria-valuetext`, `aria-valuemin`, and `aria-valuemax`.
|
|
65
|
+
- `ArrowUp/ArrowDown`: change value by one step.
|
|
66
|
+
- `ArrowLeft/ArrowRight`: move focus between columns.
|
|
67
|
+
- `Home/End`: jump to first/last value in the column.
|
|
68
|
+
|
|
69
|
+
## Notes
|
|
70
|
+
|
|
71
|
+
- Locale is read from `LocaleProvider` when available.
|
|
72
|
+
- Internally, values are normalized to 24-hour representation; 12-hour rendering only affects UI segments.
|
|
73
|
+
- `granularity='hour'` emits `HH:00` values.
|
|
74
|
+
- Min/max comparisons do not support midnight-wrapping ranges.
|
|
75
|
+
- Wheel selection commits immediately on snap.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Clock Axis
|
|
2
|
+
|
|
3
|
+
## API reference
|
|
4
|
+
|
|
5
|
+
### Clock.Axis
|
|
6
|
+
|
|
7
|
+
Name: `Clock.Axis`
|
|
8
|
+
Description: Visual overlay band for `Clock.Root`; it is presentational (`aria-hidden`) and does not manage selection.
|
|
9
|
+
|
|
10
|
+
| Prop | Type | Default | Description |
|
|
11
|
+
| -------------- | -------------------------------- | ----------- | ---------------------------------------------------- |
|
|
12
|
+
| `height` | `number` | `undefined` | Optional overlay height in pixels. |
|
|
13
|
+
| `class` | `string` | `''` | CSS class names for the overlay element. |
|
|
14
|
+
| `style` | `string` | `''` | Inline styles merged with the optional height style. |
|
|
15
|
+
| `...restProps` | `HTMLAttributes<HTMLDivElement>` | `-` | Additional attributes forwarded to the overlay div. |
|
|
16
|
+
|
|
17
|
+
### Context utilities
|
|
18
|
+
|
|
19
|
+
Name: `useClockContext`
|
|
20
|
+
Description: Ensures `Clock.Axis` is used within `Clock.Root`.
|
|
21
|
+
|
|
22
|
+
| Prop | Type | Default | Description |
|
|
23
|
+
| ----------------- | -------------------- | ------- | ------------------------------------------------ |
|
|
24
|
+
| `useClockContext` | `() => ClockContext` | `-` | Returns context and throws outside `Clock.Root`. |
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
import { useClockContext } from '../root/context';
|
|
4
|
+
|
|
5
|
+
type ClockAxisProps = Omit<HTMLAttributes<HTMLDivElement>, 'class' | 'children'> & {
|
|
6
|
+
class?: string;
|
|
7
|
+
height?: number;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
let {
|
|
11
|
+
class: className = '',
|
|
12
|
+
height,
|
|
13
|
+
style: styleProp = '',
|
|
14
|
+
...restProps
|
|
15
|
+
}: ClockAxisProps = $props();
|
|
16
|
+
|
|
17
|
+
const resolvedStyle = $derived.by(() => {
|
|
18
|
+
const base = styleProp?.trim() ?? '';
|
|
19
|
+
if (height === undefined || !Number.isFinite(height) || height <= 0) {
|
|
20
|
+
return base.length > 0 ? base : undefined;
|
|
21
|
+
}
|
|
22
|
+
const axisHeight = `height:${height}px`;
|
|
23
|
+
if (base.length === 0) return axisHeight;
|
|
24
|
+
const withSemicolon = /;\s*$/.test(base) ? base : `${base};`;
|
|
25
|
+
return `${withSemicolon}${axisHeight}`;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
useClockContext();
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<div
|
|
32
|
+
aria-hidden="true"
|
|
33
|
+
data-clock-axis
|
|
34
|
+
class={`pointer-events-none absolute top-1/2 left-0 w-full -translate-y-1/2 ${className}`}
|
|
35
|
+
style={resolvedStyle}
|
|
36
|
+
{...restProps}
|
|
37
|
+
></div>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
|
+
type ClockAxisProps = Omit<HTMLAttributes<HTMLDivElement>, 'class' | 'children'> & {
|
|
3
|
+
class?: string;
|
|
4
|
+
height?: number;
|
|
5
|
+
};
|
|
6
|
+
declare const ClockAxis: import("svelte").Component<ClockAxisProps, {}, "">;
|
|
7
|
+
type ClockAxis = ReturnType<typeof ClockAxis>;
|
|
8
|
+
export default ClockAxis;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type WheelScrollBehavior = 'smooth' | 'instant';
|
|
2
|
+
export type WheelScrollApi = {
|
|
3
|
+
scrollToIndex: (index: number, behavior?: WheelScrollBehavior, options?: {
|
|
4
|
+
silent?: boolean;
|
|
5
|
+
}) => void;
|
|
6
|
+
destroy: () => void;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Manages scroll-based item selection for a wheel column.
|
|
10
|
+
*
|
|
11
|
+
* All snapping is handled in JavaScript (no CSS `scroll-snap-type`).
|
|
12
|
+
* After scrolling settles (either short inactivity in `scroll` events
|
|
13
|
+
* or browser `scrollend`), we find the nearest centered item and run
|
|
14
|
+
* a fast 120 ms ease-out animation to align it.
|
|
15
|
+
*/
|
|
16
|
+
export declare function useWheelScroll(container: HTMLElement, onSnap: (centeredIndex: number) => number | null | void): WheelScrollApi;
|