@sit-onyx/headless 0.1.1-dev-20250922084911 → 0.2.0-dev-20251014161744

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.
@@ -0,0 +1,71 @@
1
+ import { MaybeRefOrGetter, Ref } from 'vue';
2
+ import { DateRange, DateValue, Weekday } from '../../utils/dates.js';
3
+ import { Nullable } from '../../utils/types.js';
4
+ export type SelectionMode = "single" | "multiple" | "range";
5
+ export type CalendarSize = "small" | "big";
6
+ export type CreateCalendarOptions = {
7
+ locale: MaybeRefOrGetter<string>;
8
+ calendarSize: MaybeRefOrGetter<CalendarSize>;
9
+ weekStartDay: MaybeRefOrGetter<Weekday>;
10
+ viewMonth: Ref<DateValue>;
11
+ modelValue?: Ref<Nullable<DateValue | DateValue[] | DateRange>>;
12
+ disabled?: MaybeRefOrGetter<boolean>;
13
+ min?: MaybeRefOrGetter<Nullable<DateValue>>;
14
+ max?: MaybeRefOrGetter<Nullable<DateValue>>;
15
+ showCalendarWeeks?: MaybeRefOrGetter<boolean>;
16
+ selectionMode?: MaybeRefOrGetter<SelectionMode>;
17
+ onUpdateViewMonth?: (date: Date) => unknown;
18
+ onUpdateModelValue?: (newValue: Date | Date[] | DateRange) => unknown;
19
+ };
20
+ export type RenderWeek = {
21
+ weekNumber: number;
22
+ days: RenderDay[];
23
+ };
24
+ export type RenderDay = {
25
+ date: Date;
26
+ isCurrentMonth: boolean;
27
+ };
28
+ /**
29
+ * @experimental
30
+ * @deprecated This component is still under active development and its API might change in patch releases.
31
+ */
32
+ export declare const _unstableCreateCalendar: (options: CreateCalendarOptions) => import('../../utils/builder.js').HeadlessComposable<{
33
+ table: {
34
+ role: string;
35
+ onKeydown: (event: KeyboardEvent) => Promise<void>;
36
+ ref: import('../../utils/builder.js').HeadlessElRef<HTMLElement>;
37
+ };
38
+ cell: import('vue').ComputedRef<(cell: {
39
+ date: Date;
40
+ }) => {
41
+ role: string;
42
+ "aria-selected": boolean;
43
+ "aria-disabled": boolean;
44
+ }>;
45
+ button: import('vue').ComputedRef<(button: {
46
+ date: Date;
47
+ }) => {
48
+ "aria-label": string;
49
+ "data-date": string;
50
+ } | {
51
+ tabindex: string;
52
+ disabled: boolean;
53
+ onClick: (() => void) | undefined;
54
+ "aria-label": string;
55
+ "data-date": string;
56
+ }>;
57
+ }, {
58
+ weekdayNames: import('vue').ComputedRef<string[]>;
59
+ weeksToRender: import('vue').ComputedRef<RenderWeek[]>;
60
+ focusedDate: Ref<Date, Date>;
61
+ viewMonth: import('vue').WritableComputedRef<Date, Date>;
62
+ }, {
63
+ goToMonthByOffset: (offset: number) => void;
64
+ goToToday: () => void;
65
+ isSelected: import('vue').ComputedRef<(date: Date) => boolean>;
66
+ isToday: (date: Date) => boolean;
67
+ getRangeType: import('vue').ComputedRef<(date: Date, range?: DateRange) => "start" | "middle" | "end" | undefined>;
68
+ isDisabled: import('vue').ComputedRef<(date: Date) => boolean>;
69
+ goToDate: (date: Date, preventSelectionUpdate?: boolean) => void;
70
+ isFocused: import('vue').ComputedRef<(date: Date) => boolean>;
71
+ }>;
@@ -0,0 +1 @@
1
+ export {};
@@ -132,18 +132,18 @@ declare const _default: import('vue').DefineComponent<{}, {
132
132
  onBlur?: ((payload: FocusEvent) => void) | undefined;
133
133
  onChange?: ((payload: Event) => void) | undefined;
134
134
  onBeforeinput?: ((payload: InputEvent) => void) | undefined;
135
- onInput?: ((payload: Event) => void) | undefined;
135
+ onFormdata?: ((payload: FormDataEvent) => void) | undefined;
136
+ onInput?: ((payload: InputEvent) => void) | undefined;
136
137
  onReset?: ((payload: Event) => void) | undefined;
137
138
  onSubmit?: ((payload: SubmitEvent) => void) | undefined;
138
139
  onInvalid?: ((payload: Event) => void) | undefined;
140
+ onFullscreenchange?: ((payload: Event) => void) | undefined;
141
+ onFullscreenerror?: ((payload: Event) => void) | undefined;
139
142
  onLoad?: ((payload: Event) => void) | undefined;
140
143
  onError?: ((payload: Event) => void) | undefined;
141
144
  onKeydown?: ((payload: KeyboardEvent) => void) | undefined;
142
145
  onKeypress?: ((payload: KeyboardEvent) => void) | undefined;
143
146
  onKeyup?: ((payload: KeyboardEvent) => void) | undefined;
144
- onAuxclick?: ((payload: PointerEvent) => void) | undefined;
145
- onClick?: ((payload: PointerEvent) => void) | undefined;
146
- onContextmenu?: ((payload: PointerEvent) => void) | undefined;
147
147
  onDblclick?: ((payload: MouseEvent) => void) | undefined;
148
148
  onMouseenter?: ((payload: MouseEvent) => void) | undefined;
149
149
  onMouseleave?: ((payload: MouseEvent) => void) | undefined;
@@ -180,6 +180,11 @@ declare const _default: import('vue').DefineComponent<{}, {
180
180
  onTouchend?: ((payload: TouchEvent) => void) | undefined;
181
181
  onTouchmove?: ((payload: TouchEvent) => void) | undefined;
182
182
  onTouchstart?: ((payload: TouchEvent) => void) | undefined;
183
+ onAuxclick?: ((payload: PointerEvent) => void) | undefined;
184
+ onClick?: ((payload: PointerEvent) => void) | undefined;
185
+ onContextmenu?: ((payload: PointerEvent) => void) | undefined;
186
+ onGotpointercapture?: ((payload: PointerEvent) => void) | undefined;
187
+ onLostpointercapture?: ((payload: PointerEvent) => void) | undefined;
183
188
  onPointerdown?: ((payload: PointerEvent) => void) | undefined;
184
189
  onPointermove?: ((payload: PointerEvent) => void) | undefined;
185
190
  onPointerup?: ((payload: PointerEvent) => void) | undefined;
@@ -188,11 +193,17 @@ declare const _default: import('vue').DefineComponent<{}, {
188
193
  onPointerleave?: ((payload: PointerEvent) => void) | undefined;
189
194
  onPointerover?: ((payload: PointerEvent) => void) | undefined;
190
195
  onPointerout?: ((payload: PointerEvent) => void) | undefined;
196
+ onBeforetoggle?: ((payload: ToggleEvent) => void) | undefined;
197
+ onToggle?: ((payload: ToggleEvent) => void) | undefined;
191
198
  onWheel?: ((payload: WheelEvent) => void) | undefined;
199
+ onAnimationcancel?: ((payload: AnimationEvent) => void) | undefined;
192
200
  onAnimationstart?: ((payload: AnimationEvent) => void) | undefined;
193
201
  onAnimationend?: ((payload: AnimationEvent) => void) | undefined;
194
202
  onAnimationiteration?: ((payload: AnimationEvent) => void) | undefined;
203
+ onSecuritypolicyviolation?: ((payload: SecurityPolicyViolationEvent) => void) | undefined;
204
+ onTransitioncancel?: ((payload: TransitionEvent) => void) | undefined;
195
205
  onTransitionend?: ((payload: TransitionEvent) => void) | undefined;
206
+ onTransitionrun?: ((payload: TransitionEvent) => void) | undefined;
196
207
  onTransitionstart?: ((payload: TransitionEvent) => void) | undefined;
197
208
  ref?: import('vue').Ref<Element | ({
198
209
  $: import('vue').ComponentInternalInstance;
@@ -132,18 +132,18 @@ declare const _default: import('vue').DefineComponent<{}, {
132
132
  onBlur?: ((payload: FocusEvent) => void) | undefined;
133
133
  onChange?: ((payload: Event) => void) | undefined;
134
134
  onBeforeinput?: ((payload: InputEvent) => void) | undefined;
135
- onInput?: ((payload: Event) => void) | undefined;
135
+ onFormdata?: ((payload: FormDataEvent) => void) | undefined;
136
+ onInput?: ((payload: InputEvent) => void) | undefined;
136
137
  onReset?: ((payload: Event) => void) | undefined;
137
138
  onSubmit?: ((payload: SubmitEvent) => void) | undefined;
138
139
  onInvalid?: ((payload: Event) => void) | undefined;
140
+ onFullscreenchange?: ((payload: Event) => void) | undefined;
141
+ onFullscreenerror?: ((payload: Event) => void) | undefined;
139
142
  onLoad?: ((payload: Event) => void) | undefined;
140
143
  onError?: ((payload: Event) => void) | undefined;
141
144
  onKeydown?: ((payload: KeyboardEvent) => void) | undefined;
142
145
  onKeypress?: ((payload: KeyboardEvent) => void) | undefined;
143
146
  onKeyup?: ((payload: KeyboardEvent) => void) | undefined;
144
- onAuxclick?: ((payload: PointerEvent) => void) | undefined;
145
- onClick?: ((payload: PointerEvent) => void) | undefined;
146
- onContextmenu?: ((payload: PointerEvent) => void) | undefined;
147
147
  onDblclick?: ((payload: MouseEvent) => void) | undefined;
148
148
  onMouseenter?: ((payload: MouseEvent) => void) | undefined;
149
149
  onMouseleave?: ((payload: MouseEvent) => void) | undefined;
@@ -180,6 +180,11 @@ declare const _default: import('vue').DefineComponent<{}, {
180
180
  onTouchend?: ((payload: TouchEvent) => void) | undefined;
181
181
  onTouchmove?: ((payload: TouchEvent) => void) | undefined;
182
182
  onTouchstart?: ((payload: TouchEvent) => void) | undefined;
183
+ onAuxclick?: ((payload: PointerEvent) => void) | undefined;
184
+ onClick?: ((payload: PointerEvent) => void) | undefined;
185
+ onContextmenu?: ((payload: PointerEvent) => void) | undefined;
186
+ onGotpointercapture?: ((payload: PointerEvent) => void) | undefined;
187
+ onLostpointercapture?: ((payload: PointerEvent) => void) | undefined;
183
188
  onPointerdown?: ((payload: PointerEvent) => void) | undefined;
184
189
  onPointermove?: ((payload: PointerEvent) => void) | undefined;
185
190
  onPointerup?: ((payload: PointerEvent) => void) | undefined;
@@ -188,11 +193,17 @@ declare const _default: import('vue').DefineComponent<{}, {
188
193
  onPointerleave?: ((payload: PointerEvent) => void) | undefined;
189
194
  onPointerover?: ((payload: PointerEvent) => void) | undefined;
190
195
  onPointerout?: ((payload: PointerEvent) => void) | undefined;
196
+ onBeforetoggle?: ((payload: ToggleEvent) => void) | undefined;
197
+ onToggle?: ((payload: ToggleEvent) => void) | undefined;
191
198
  onWheel?: ((payload: WheelEvent) => void) | undefined;
199
+ onAnimationcancel?: ((payload: AnimationEvent) => void) | undefined;
192
200
  onAnimationstart?: ((payload: AnimationEvent) => void) | undefined;
193
201
  onAnimationend?: ((payload: AnimationEvent) => void) | undefined;
194
202
  onAnimationiteration?: ((payload: AnimationEvent) => void) | undefined;
203
+ onSecuritypolicyviolation?: ((payload: SecurityPolicyViolationEvent) => void) | undefined;
204
+ onTransitioncancel?: ((payload: TransitionEvent) => void) | undefined;
195
205
  onTransitionend?: ((payload: TransitionEvent) => void) | undefined;
206
+ onTransitionrun?: ((payload: TransitionEvent) => void) | undefined;
196
207
  onTransitionstart?: ((payload: TransitionEvent) => void) | undefined;
197
208
  ref?: import('vue').Ref<Element | ({
198
209
  $: import('vue').ComponentInternalInstance;
@@ -200,18 +200,18 @@ export declare const createComboBox: <TValue extends ListboxValue, TAutoComplete
200
200
  onBlur?: ((payload: FocusEvent) => void) | undefined;
201
201
  onChange?: ((payload: Event) => void) | undefined;
202
202
  onBeforeinput?: ((payload: InputEvent) => void) | undefined;
203
- onInput?: ((payload: Event) => void) | undefined;
203
+ onFormdata?: ((payload: FormDataEvent) => void) | undefined;
204
+ onInput?: ((payload: InputEvent) => void) | undefined;
204
205
  onReset?: ((payload: Event) => void) | undefined;
205
206
  onSubmit?: ((payload: SubmitEvent) => void) | undefined;
206
207
  onInvalid?: ((payload: Event) => void) | undefined;
208
+ onFullscreenchange?: ((payload: Event) => void) | undefined;
209
+ onFullscreenerror?: ((payload: Event) => void) | undefined;
207
210
  onLoad?: ((payload: Event) => void) | undefined;
208
211
  onError?: ((payload: Event) => void) | undefined;
209
212
  onKeydown?: ((payload: KeyboardEvent) => void) | undefined;
210
213
  onKeypress?: ((payload: KeyboardEvent) => void) | undefined;
211
214
  onKeyup?: ((payload: KeyboardEvent) => void) | undefined;
212
- onAuxclick?: ((payload: PointerEvent) => void) | undefined;
213
- onClick?: ((payload: PointerEvent) => void) | undefined;
214
- onContextmenu?: ((payload: PointerEvent) => void) | undefined;
215
215
  onDblclick?: ((payload: MouseEvent) => void) | undefined;
216
216
  onMouseenter?: ((payload: MouseEvent) => void) | undefined;
217
217
  onMouseleave?: ((payload: MouseEvent) => void) | undefined;
@@ -248,6 +248,11 @@ export declare const createComboBox: <TValue extends ListboxValue, TAutoComplete
248
248
  onTouchend?: ((payload: TouchEvent) => void) | undefined;
249
249
  onTouchmove?: ((payload: TouchEvent) => void) | undefined;
250
250
  onTouchstart?: ((payload: TouchEvent) => void) | undefined;
251
+ onAuxclick?: ((payload: PointerEvent) => void) | undefined;
252
+ onClick?: ((payload: PointerEvent) => void) | undefined;
253
+ onContextmenu?: ((payload: PointerEvent) => void) | undefined;
254
+ onGotpointercapture?: ((payload: PointerEvent) => void) | undefined;
255
+ onLostpointercapture?: ((payload: PointerEvent) => void) | undefined;
251
256
  onPointerdown?: ((payload: PointerEvent) => void) | undefined;
252
257
  onPointermove?: ((payload: PointerEvent) => void) | undefined;
253
258
  onPointerup?: ((payload: PointerEvent) => void) | undefined;
@@ -256,11 +261,17 @@ export declare const createComboBox: <TValue extends ListboxValue, TAutoComplete
256
261
  onPointerleave?: ((payload: PointerEvent) => void) | undefined;
257
262
  onPointerover?: ((payload: PointerEvent) => void) | undefined;
258
263
  onPointerout?: ((payload: PointerEvent) => void) | undefined;
264
+ onBeforetoggle?: ((payload: ToggleEvent) => void) | undefined;
265
+ onToggle?: ((payload: ToggleEvent) => void) | undefined;
259
266
  onWheel?: ((payload: WheelEvent) => void) | undefined;
267
+ onAnimationcancel?: ((payload: AnimationEvent) => void) | undefined;
260
268
  onAnimationstart?: ((payload: AnimationEvent) => void) | undefined;
261
269
  onAnimationend?: ((payload: AnimationEvent) => void) | undefined;
262
270
  onAnimationiteration?: ((payload: AnimationEvent) => void) | undefined;
271
+ onSecuritypolicyviolation?: ((payload: SecurityPolicyViolationEvent) => void) | undefined;
272
+ onTransitioncancel?: ((payload: TransitionEvent) => void) | undefined;
263
273
  onTransitionend?: ((payload: TransitionEvent) => void) | undefined;
274
+ onTransitionrun?: ((payload: TransitionEvent) => void) | undefined;
264
275
  onTransitionstart?: ((payload: TransitionEvent) => void) | undefined;
265
276
  ref?: Ref<Element | ({
266
277
  $: import('vue').ComponentInternalInstance;
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from './composables/calendar/createCalendar.js';
1
2
  export * from './composables/comboBox/createComboBox.js';
2
3
  export * from './composables/helpers/useGlobalListener.js';
3
4
  export * from './composables/helpers/useOutsideClick.js';
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { shallowRef, computed, reactive, onBeforeMount, watchEffect, onBeforeUnmount, toValue, unref, ref, nextTick, useId, watch, toRef } from "vue";
1
+ import { shallowRef, computed, toValue, ref, watch, nextTick, reactive, onBeforeMount, watchEffect, onBeforeUnmount, unref, useId, toRef } from "vue";
2
2
  const createBuilder = (builder) => builder;
3
3
  function createElRef() {
4
4
  const elementRef = shallowRef();
@@ -9,6 +9,303 @@ function createElRef() {
9
9
  get: () => elementRef.value
10
10
  });
11
11
  }
12
+ function getISOWeekNumber(date) {
13
+ const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
14
+ const dayNum = d.getUTCDay() || 7;
15
+ d.setUTCDate(d.getUTCDate() + 4 - dayNum);
16
+ const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
17
+ const weekNo = Math.ceil(((d.getTime() - yearStart.getTime()) / 864e5 + 1) / 7);
18
+ return weekNo;
19
+ }
20
+ function isInDateRange(date, start, end) {
21
+ start = new Date(start);
22
+ start.setHours(0, 0, 0, 0);
23
+ end = new Date(end);
24
+ end.setHours(23, 59, 59, 999);
25
+ const time = date.getTime();
26
+ return time >= start.getTime() && time <= end.getTime();
27
+ }
28
+ function getNormalizedDayIndex(date, weekStartDay) {
29
+ const day = date.getDay();
30
+ const start = WEEKDAYS.indexOf(weekStartDay);
31
+ const normalizedDay = day === 0 ? 6 : day - 1;
32
+ return (normalizedDay - start + 7) % 7;
33
+ }
34
+ const WEEKDAYS = [
35
+ "Monday",
36
+ "Tuesday",
37
+ "Wednesday",
38
+ "Thursday",
39
+ "Friday",
40
+ "Saturday",
41
+ "Sunday"
42
+ ];
43
+ function sortDateRange(range) {
44
+ const start = new Date(range.start);
45
+ const end = range.end ? new Date(range.end) : void 0;
46
+ if (end && end.getTime() < start.getTime()) {
47
+ return { start: end, end: start };
48
+ }
49
+ return { start, end };
50
+ }
51
+ const _unstableCreateCalendar = createBuilder((options) => {
52
+ const viewMonth = computed({
53
+ get: () => {
54
+ const date = toValue(options.viewMonth);
55
+ return date ? new Date(date) : /* @__PURE__ */ new Date();
56
+ },
57
+ set: (newValue) => options.onUpdateViewMonth?.(new Date(newValue))
58
+ });
59
+ const weekdayNames = computed(() => {
60
+ const formatter = new Intl.DateTimeFormat(toValue(options.locale), {
61
+ weekday: toValue(options.calendarSize) === "big" ? "long" : "short"
62
+ });
63
+ const names = Array.from({ length: 7 }, (_, i) => new Date(2024, 0, 1 + i)).map(
64
+ (day) => formatter.format(day)
65
+ );
66
+ const weekStartDay = toValue(options.weekStartDay);
67
+ const index = WEEKDAYS.indexOf(weekStartDay);
68
+ return names.slice(index).concat(names.slice(0, index));
69
+ });
70
+ const focusedDate = ref(/* @__PURE__ */ new Date());
71
+ watch(
72
+ () => toValue(options.modelValue),
73
+ (newValue) => {
74
+ if (!newValue) return;
75
+ let newFocusDate;
76
+ if (Array.isArray(newValue)) {
77
+ newFocusDate = newValue.length ? new Date(newValue[0]) : void 0;
78
+ } else if (typeof newValue === "object" && !(newValue instanceof Date)) {
79
+ newFocusDate = new Date(newValue.start);
80
+ } else {
81
+ newFocusDate = new Date(newValue);
82
+ }
83
+ if (newFocusDate) focusedDate.value = newFocusDate;
84
+ }
85
+ );
86
+ const isToday = (date) => {
87
+ return date.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
88
+ };
89
+ const isSelected = computed(() => {
90
+ return (date) => {
91
+ const value = toValue(options.modelValue);
92
+ if (!value) return false;
93
+ if (Array.isArray(value)) {
94
+ const values = value.map((i) => new Date(i));
95
+ return values.some((d) => d.toDateString() === date.toDateString());
96
+ }
97
+ if (typeof value === "object" && !(value instanceof Date)) {
98
+ const start = new Date(value.start);
99
+ const end = value.end ? new Date(value.end) : void 0;
100
+ return start.toDateString() === date.toDateString() || end?.toDateString() === date.toDateString();
101
+ }
102
+ return new Date(value).toDateString() === date.toDateString();
103
+ };
104
+ });
105
+ const isFocused = computed(() => {
106
+ return (date) => {
107
+ return focusedDate.value?.toDateString() === date.toDateString();
108
+ };
109
+ });
110
+ const isDisabled = computed(() => {
111
+ return (date) => {
112
+ if (toValue(options.disabled)) return true;
113
+ const min = toValue(options.min);
114
+ const minDate = min ? new Date(min) : void 0;
115
+ minDate?.setHours(0, 0, 0, 0);
116
+ const max = toValue(options.max);
117
+ const maxDate = max ? new Date(max) : void 0;
118
+ maxDate?.setHours(23, 59, 59, 999);
119
+ if (minDate && maxDate) return !isInDateRange(date, minDate, maxDate);
120
+ if (minDate) return date.getTime() < minDate.getTime();
121
+ if (maxDate) return date.getTime() > maxDate.getTime();
122
+ return false;
123
+ };
124
+ });
125
+ const weeksToRender = computed(() => {
126
+ const weekStartDay = toValue(options.weekStartDay);
127
+ const firstDayInViewMonth = new Date(
128
+ viewMonth.value.getFullYear(),
129
+ viewMonth.value.getMonth(),
130
+ 1
131
+ );
132
+ const startOffset = (firstDayInViewMonth.getDay() + 6) % 7;
133
+ const daysBeforeStart = (startOffset - WEEKDAYS.indexOf(weekStartDay) + 7) % 7;
134
+ const weeksToRender2 = 6;
135
+ const weeks = [];
136
+ for (let weekIndex = 0; weekIndex < weeksToRender2; weekIndex++) {
137
+ const weekStartDate = new Date(firstDayInViewMonth);
138
+ weekStartDate.setDate(weekStartDate.getDate() - daysBeforeStart + weekIndex * 7);
139
+ const days = Array.from({ length: 7 }, (_, dayIndex) => {
140
+ const date = new Date(weekStartDate);
141
+ date.setDate(date.getDate() + dayIndex);
142
+ return {
143
+ date,
144
+ isCurrentMonth: date.getMonth() === viewMonth.value.getMonth()
145
+ };
146
+ });
147
+ weeks.push({
148
+ weekNumber: getISOWeekNumber(weekStartDate),
149
+ days
150
+ });
151
+ }
152
+ return weeks;
153
+ });
154
+ const goToDate = (date, preventSelectionUpdate) => {
155
+ focusedDate.value = new Date(date);
156
+ if (focusedDate.value.getFullYear() !== viewMonth.value.getFullYear() || focusedDate.value.getMonth() !== viewMonth.value.getMonth()) {
157
+ viewMonth.value = new Date(focusedDate.value);
158
+ }
159
+ const selectionMode = toValue(options.selectionMode);
160
+ if (!selectionMode || preventSelectionUpdate) return;
161
+ const selection = toValue(options.modelValue);
162
+ switch (selectionMode) {
163
+ case "single":
164
+ options.onUpdateModelValue?.(new Date(date));
165
+ break;
166
+ case "multiple": {
167
+ let values = Array.isArray(selection) ? selection.map((d) => new Date(d)) : [];
168
+ if (isSelected.value(date)) {
169
+ values = values.filter((d) => d.toDateString() !== date.toDateString());
170
+ } else {
171
+ values.push(new Date(date));
172
+ }
173
+ options.onUpdateModelValue?.(values);
174
+ break;
175
+ }
176
+ case "range": {
177
+ const currentRange = typeof selection === "object" && !(selection instanceof Date) && !Array.isArray(selection) ? selection : void 0;
178
+ let newRange;
179
+ if (currentRange?.start && currentRange.end) {
180
+ newRange = { start: new Date(date) };
181
+ } else {
182
+ newRange = {
183
+ start: currentRange?.start ? new Date(currentRange.start) : new Date(date),
184
+ end: currentRange?.start ? new Date(date) : void 0
185
+ };
186
+ }
187
+ newRange = sortDateRange(newRange);
188
+ options.onUpdateModelValue?.(newRange);
189
+ break;
190
+ }
191
+ }
192
+ };
193
+ const handleKeyNavigation = async (event) => {
194
+ let newDate;
195
+ const getNewFocusDateByDiff = (diff, type = "days") => {
196
+ const date = new Date(focusedDate.value);
197
+ if (type === "month") date.setMonth(date.getMonth() + diff);
198
+ else date.setDate(date.getDate() + diff);
199
+ return date;
200
+ };
201
+ switch (event.key) {
202
+ case "ArrowUp":
203
+ newDate = getNewFocusDateByDiff(-7);
204
+ break;
205
+ case "ArrowDown":
206
+ newDate = getNewFocusDateByDiff(7);
207
+ break;
208
+ case "ArrowLeft":
209
+ newDate = getNewFocusDateByDiff(-1);
210
+ break;
211
+ case "ArrowRight":
212
+ newDate = getNewFocusDateByDiff(1);
213
+ break;
214
+ case "Home": {
215
+ const idx = getNormalizedDayIndex(focusedDate.value, toValue(options.weekStartDay));
216
+ newDate = getNewFocusDateByDiff(-idx);
217
+ break;
218
+ }
219
+ case "End": {
220
+ const idx = getNormalizedDayIndex(focusedDate.value, toValue(options.weekStartDay));
221
+ newDate = getNewFocusDateByDiff(6 - idx);
222
+ break;
223
+ }
224
+ case "PageUp":
225
+ newDate = getNewFocusDateByDiff(-(event.shiftKey ? 12 : 1), "month");
226
+ break;
227
+ case "PageDown":
228
+ newDate = getNewFocusDateByDiff(event.shiftKey ? 12 : 1, "month");
229
+ break;
230
+ }
231
+ if (!newDate || isDisabled.value(newDate)) return;
232
+ event.preventDefault();
233
+ goToDate(newDate, true);
234
+ await nextTick();
235
+ tableRef.value?.querySelector(`[data-date="${focusedDate.value.toDateString()}"]`)?.focus();
236
+ };
237
+ const getRangeType = computed(() => {
238
+ return (date, range) => {
239
+ const selection = range ?? toValue(options.modelValue);
240
+ if (!selection || typeof selection !== "object" || Array.isArray(selection) || selection instanceof Date) {
241
+ return;
242
+ }
243
+ const sortedRange = sortDateRange(selection);
244
+ const start = new Date(sortedRange.start);
245
+ start.setHours(0, 0, 0, 0);
246
+ const end = sortedRange.end ? new Date(sortedRange.end) : void 0;
247
+ end?.setHours(23, 59, 59, 999);
248
+ if (date.toDateString() === start.toDateString()) return "start";
249
+ if (date.toDateString() === end?.toDateString()) return "end";
250
+ if (end && isInDateRange(date, start, end)) return "middle";
251
+ };
252
+ });
253
+ const goToMonthByOffset = (offset) => {
254
+ const date = new Date(viewMonth.value);
255
+ date.setMonth(date.getMonth() + offset, 1);
256
+ viewMonth.value = date;
257
+ };
258
+ const goToToday = () => {
259
+ viewMonth.value = /* @__PURE__ */ new Date();
260
+ };
261
+ const tableRef = createElRef();
262
+ return {
263
+ state: {
264
+ weekdayNames,
265
+ weeksToRender,
266
+ focusedDate,
267
+ viewMonth
268
+ },
269
+ elements: {
270
+ table: {
271
+ role: "grid",
272
+ onKeydown: handleKeyNavigation,
273
+ ref: tableRef
274
+ },
275
+ cell: computed(() => (cell) => ({
276
+ role: "gridcell",
277
+ "aria-selected": isSelected.value(cell.date),
278
+ "aria-disabled": isDisabled.value(cell.date)
279
+ })),
280
+ button: computed(() => (button) => {
281
+ const formatter = new Intl.DateTimeFormat(toValue(options.locale), { dateStyle: "full" });
282
+ const attributes = {
283
+ "aria-label": formatter.format(button.date),
284
+ "data-date": button.date.toDateString()
285
+ };
286
+ const selection = toValue(options.selectionMode);
287
+ if (!selection) return attributes;
288
+ const disabled = isDisabled.value(button.date);
289
+ return {
290
+ ...attributes,
291
+ tabindex: isFocused.value(button.date) && !disabled ? "0" : "-1",
292
+ disabled,
293
+ onClick: disabled ? void 0 : () => goToDate(button.date)
294
+ };
295
+ })
296
+ },
297
+ internals: {
298
+ goToMonthByOffset,
299
+ goToToday,
300
+ isSelected,
301
+ isToday,
302
+ getRangeType,
303
+ isDisabled,
304
+ goToDate,
305
+ isFocused
306
+ }
307
+ };
308
+ });
12
309
  const isSubsetMatching = (subset, target) => Object.entries(subset).every(
13
310
  ([key, value]) => target[key] === value
14
311
  );
@@ -762,6 +1059,7 @@ const createTooltip = createBuilder(({ debounce: debounce2, isVisible }) => {
762
1059
  export {
763
1060
  CLOSING_KEYS,
764
1061
  OPENING_KEYS,
1062
+ _unstableCreateCalendar,
765
1063
  createBuilder,
766
1064
  createComboBox,
767
1065
  createElRef,
@@ -0,0 +1,15 @@
1
+ import { Nullable } from './types.js';
2
+ export declare function getISOWeekNumber(date: Date): number;
3
+ /**
4
+ * Checks whether the given date is in between the given start and end date.
5
+ */
6
+ export declare function isInDateRange(date: Date, start: Date, end: Date): boolean;
7
+ export declare function getNormalizedDayIndex(date: Date, weekStartDay: Weekday): number;
8
+ export declare const WEEKDAYS: readonly ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
9
+ export type Weekday = (typeof WEEKDAYS)[number];
10
+ export type DateValue = Date | string | number;
11
+ export type DateRange<T extends DateValue = DateValue> = {
12
+ start: T;
13
+ end?: Nullable<T>;
14
+ };
15
+ export declare function sortDateRange(range: DateRange): DateRange<Date>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sit-onyx/headless",
3
3
  "description": "Headless composables for Vue",
4
- "version": "0.1.1-dev-20250922084911",
4
+ "version": "0.2.0-dev-20251014161744",
5
5
  "type": "module",
6
6
  "author": "Schwarz IT KG",
7
7
  "license": "Apache-2.0",
@@ -32,14 +32,14 @@
32
32
  "url": "https://github.com/SchwarzIT/onyx/issues"
33
33
  },
34
34
  "peerDependencies": {
35
- "@playwright/experimental-ct-vue": "1.55.0",
36
- "@playwright/test": "1.55.0",
35
+ "@playwright/experimental-ct-vue": "1.56.0",
36
+ "@playwright/test": "1.56.0",
37
37
  "typescript": ">= 5",
38
38
  "vue": ">= 3.5.0"
39
39
  },
40
40
  "devDependencies": {
41
- "@vue/compiler-dom": "3.5.21",
42
- "vue": "3.5.21",
41
+ "@vue/compiler-dom": "3.5.22",
42
+ "vue": "3.5.22",
43
43
  "@sit-onyx/shared": "^0.1.0"
44
44
  },
45
45
  "scripts": {