@corvu-next/calendar 0.1.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/LICENSE +21 -0
- package/dist/index.d.ts +434 -0
- package/dist/index.js +739 -0
- package/dist/index.jsx +825 -0
- package/package.json +49 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,739 @@
|
|
|
1
|
+
import { createContext, merge, createMemo, createUniqueId, createSignal, untrack, useContext, omit, createEffect } from 'solid-js';
|
|
2
|
+
import { useKeyedContext, createKeyedContext } from '@corvu-next/utils/create/keyedContext';
|
|
3
|
+
import { createComponent, mergeProps, memo } from 'solid-js/web';
|
|
4
|
+
import { Dynamic, DynamicButton } from '@corvu-next/utils/dynamic';
|
|
5
|
+
import { callEventHandler } from '@corvu-next/utils/dom';
|
|
6
|
+
import { dataIf, isFunction } from '@corvu-next/utils';
|
|
7
|
+
import { mergeRefs } from '@corvu-next/utils/reactivity';
|
|
8
|
+
import createControllableSignal from '@corvu-next/utils/create/controllableSignal';
|
|
9
|
+
import createOnce from '@corvu-next/utils/create/once';
|
|
10
|
+
import createRegister from '@corvu-next/utils/create/register';
|
|
11
|
+
|
|
12
|
+
// src/context.ts
|
|
13
|
+
var CalendarContext = createContext(null);
|
|
14
|
+
var createCalendarContext = (contextId) => {
|
|
15
|
+
if (contextId === void 0) return CalendarContext;
|
|
16
|
+
const context = createKeyedContext(
|
|
17
|
+
`calendar-${contextId}`
|
|
18
|
+
);
|
|
19
|
+
return context;
|
|
20
|
+
};
|
|
21
|
+
var useCalendarContext = (contextId) => {
|
|
22
|
+
if (contextId === void 0) {
|
|
23
|
+
const context2 = useContext(CalendarContext);
|
|
24
|
+
if (!context2) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
"[corvu]: Calendar context not found. Make sure to wrap Calendar components in <Calendar.Root>"
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
return context2;
|
|
30
|
+
}
|
|
31
|
+
const context = useKeyedContext(
|
|
32
|
+
`calendar-${contextId}`
|
|
33
|
+
);
|
|
34
|
+
if (!context) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`[corvu]: Calendar context with id "${contextId}" not found. Make sure to wrap Calendar components in <Calendar.Root contextId="${contextId}">`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
return context;
|
|
40
|
+
};
|
|
41
|
+
var InternalCalendarContext = createContext(null);
|
|
42
|
+
var createInternalCalendarContext = (contextId) => {
|
|
43
|
+
if (contextId === void 0) return InternalCalendarContext;
|
|
44
|
+
const context = createKeyedContext(
|
|
45
|
+
`calendar-internal-${contextId}`
|
|
46
|
+
);
|
|
47
|
+
return context;
|
|
48
|
+
};
|
|
49
|
+
var useInternalCalendarContext = (contextId) => {
|
|
50
|
+
if (contextId === void 0) {
|
|
51
|
+
const context2 = useContext(InternalCalendarContext);
|
|
52
|
+
if (!context2) {
|
|
53
|
+
throw new Error(
|
|
54
|
+
"[corvu]: Calendar context not found. Make sure to wrap Calendar components in <Calendar.Root>"
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
return context2;
|
|
58
|
+
}
|
|
59
|
+
const context = useKeyedContext(
|
|
60
|
+
`calendar-internal-${contextId}`
|
|
61
|
+
);
|
|
62
|
+
if (!context) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
`[corvu]: Calendar context with id "${contextId}" not found. Make sure to wrap Calendar components in <Calendar.Root contextId="${contextId}">`
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
return context;
|
|
68
|
+
};
|
|
69
|
+
var CalendarCell = (props) => {
|
|
70
|
+
return createComponent(Dynamic, mergeProps({
|
|
71
|
+
as: "td",
|
|
72
|
+
role: "presentation",
|
|
73
|
+
"data-corvu-calendar-cell": ""
|
|
74
|
+
}, props));
|
|
75
|
+
};
|
|
76
|
+
var Cell_default = CalendarCell;
|
|
77
|
+
|
|
78
|
+
// src/utils.ts
|
|
79
|
+
var isSameDay = (a, b) => {
|
|
80
|
+
if (!a || !b) return false;
|
|
81
|
+
if (a.getDate() !== b.getDate()) return false;
|
|
82
|
+
if (a.getMonth() !== b.getMonth()) return false;
|
|
83
|
+
if (a.getFullYear() !== b.getFullYear()) return false;
|
|
84
|
+
return true;
|
|
85
|
+
};
|
|
86
|
+
var isSameDayOrBefore = (a, b) => {
|
|
87
|
+
if (!a || !b) return false;
|
|
88
|
+
if (isSameDay(a, b)) return true;
|
|
89
|
+
if (a.getTime() < b.getTime()) return true;
|
|
90
|
+
return false;
|
|
91
|
+
};
|
|
92
|
+
var isSameDayOrAfter = (a, b) => {
|
|
93
|
+
if (!a || !b) return false;
|
|
94
|
+
if (isSameDay(a, b)) return true;
|
|
95
|
+
if (a.getTime() > b.getTime()) return true;
|
|
96
|
+
return false;
|
|
97
|
+
};
|
|
98
|
+
var modifyDate = (date, modify) => {
|
|
99
|
+
const newYear = date.getFullYear() + (modify.year ?? 0);
|
|
100
|
+
const newMonth = date.getMonth() + (modify.month ?? 0);
|
|
101
|
+
let newDay = date.getDate() + (modify.day ?? 0);
|
|
102
|
+
if (modify.month !== void 0 && modify.month !== 0) {
|
|
103
|
+
newDay = Math.min(new Date(newYear, newMonth + 1, 0).getDate(), newDay);
|
|
104
|
+
}
|
|
105
|
+
return new Date(newYear, newMonth, newDay);
|
|
106
|
+
};
|
|
107
|
+
var modifyFocusedDay = (date, modify, disabled, retry = true, iteration = 0) => {
|
|
108
|
+
if (iteration > 365) return null;
|
|
109
|
+
const newDate = modifyDate(date, modify);
|
|
110
|
+
if (!disabled(newDate)) return newDate;
|
|
111
|
+
if (!retry) return null;
|
|
112
|
+
return modifyFocusedDay(newDate, modify, disabled, retry, iteration + 1);
|
|
113
|
+
};
|
|
114
|
+
var dayIsInMonth = (focusedDay, month, numberOfMonths) => {
|
|
115
|
+
const firstDay = new Date(month.getFullYear(), month.getMonth(), 1);
|
|
116
|
+
const lastDay = new Date(
|
|
117
|
+
month.getFullYear(),
|
|
118
|
+
month.getMonth() + numberOfMonths,
|
|
119
|
+
0
|
|
120
|
+
);
|
|
121
|
+
return focusedDay.getTime() >= firstDay.getTime() && focusedDay.getTime() <= lastDay.getTime();
|
|
122
|
+
};
|
|
123
|
+
var findAvailableDayInMonth = (start, disabled) => {
|
|
124
|
+
const lastDayOfMonth = new Date(start.getFullYear(), start.getMonth() + 1, 0);
|
|
125
|
+
const month = start.getMonth();
|
|
126
|
+
let shift = 0;
|
|
127
|
+
const maxShift = Math.max(
|
|
128
|
+
start.getDate() - 1,
|
|
129
|
+
lastDayOfMonth.getDate() - start.getDate()
|
|
130
|
+
);
|
|
131
|
+
while (shift <= maxShift) {
|
|
132
|
+
start.setDate(start.getDate() + shift);
|
|
133
|
+
if (start.getMonth() === month && !disabled(start)) return start;
|
|
134
|
+
start.setDate(start.getDate() - shift);
|
|
135
|
+
if (start.getMonth() === month && !disabled(start)) return start;
|
|
136
|
+
shift++;
|
|
137
|
+
}
|
|
138
|
+
return start;
|
|
139
|
+
};
|
|
140
|
+
var CalendarCellTrigger = (props) => {
|
|
141
|
+
const p = props;
|
|
142
|
+
const otherProps = omit(p, "day", "month", "contextId", "ref", "onClick", "onKeyDown", "disabled");
|
|
143
|
+
const [ref, setRef] = createSignal(null);
|
|
144
|
+
const [isToday, setIsToday] = createSignal(false);
|
|
145
|
+
createEffect(() => {
|
|
146
|
+
setIsToday(isSameDay(p.day, /* @__PURE__ */ new Date()));
|
|
147
|
+
});
|
|
148
|
+
const context = createMemo(() => useInternalCalendarContext(p.contextId));
|
|
149
|
+
createEffect(() => {
|
|
150
|
+
const focusedDay = context().focusedDay();
|
|
151
|
+
const day = p.day;
|
|
152
|
+
const month = p.month;
|
|
153
|
+
if (!untrack(() => context().isFocusing())) return;
|
|
154
|
+
if (context().isDisabled(day, month)) return;
|
|
155
|
+
if (isSameDay(focusedDay, day)) {
|
|
156
|
+
untrack(() => {
|
|
157
|
+
ref()?.focus();
|
|
158
|
+
context().setIsFocusing(false);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
createEffect(() => {
|
|
163
|
+
if (context().isDisabled(p.day, p.month)) return;
|
|
164
|
+
if (isSameDay(p.day, context().focusedDay())) {
|
|
165
|
+
context().setFocusedDayRef(ref());
|
|
166
|
+
return () => {
|
|
167
|
+
context().setFocusedDayRef(null);
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
const onClick = (e) => {
|
|
172
|
+
!callEventHandler(p.onClick, e) && context().onDaySelect(p.day);
|
|
173
|
+
};
|
|
174
|
+
const onKeyDown = (event) => {
|
|
175
|
+
if (callEventHandler(p.onKeyDown, event)) return;
|
|
176
|
+
let focusedDay = null;
|
|
177
|
+
if (event.key === "ArrowLeft" && context().textDirection() === "ltr" || event.key === "ArrowRight" && context().textDirection() === "rtl") {
|
|
178
|
+
event.preventDefault();
|
|
179
|
+
focusedDay = modifyFocusedDay(p.day, {
|
|
180
|
+
day: -1
|
|
181
|
+
}, context().disabled);
|
|
182
|
+
} else if (event.key === "ArrowRight" && context().textDirection() === "ltr" || event.key === "ArrowLeft" && context().textDirection() === "rtl") {
|
|
183
|
+
event.preventDefault();
|
|
184
|
+
focusedDay = modifyFocusedDay(p.day, {
|
|
185
|
+
day: 1
|
|
186
|
+
}, context().disabled);
|
|
187
|
+
} else if (event.key === "ArrowUp") {
|
|
188
|
+
event.preventDefault();
|
|
189
|
+
focusedDay = modifyFocusedDay(p.day, {
|
|
190
|
+
day: -7
|
|
191
|
+
}, context().disabled);
|
|
192
|
+
} else if (event.key === "ArrowDown") {
|
|
193
|
+
event.preventDefault();
|
|
194
|
+
focusedDay = modifyFocusedDay(p.day, {
|
|
195
|
+
day: 7
|
|
196
|
+
}, context().disabled);
|
|
197
|
+
} else if (event.key === "Home" && context().textDirection() === "ltr" || event.key === "End" && context().textDirection() === "rtl") {
|
|
198
|
+
event.preventDefault();
|
|
199
|
+
focusedDay = modifyFocusedDay(p.day, {
|
|
200
|
+
day: -((p.day.getDay() - context().startOfWeek() + 7) % 7)
|
|
201
|
+
}, context().disabled, false);
|
|
202
|
+
} else if (event.key === "End" && context().textDirection() === "ltr" || event.key === "Home" && context().textDirection() === "rtl") {
|
|
203
|
+
event.preventDefault();
|
|
204
|
+
focusedDay = modifyFocusedDay(p.day, {
|
|
205
|
+
day: (context().startOfWeek() + 6 - p.day.getDay() + 7) % 7
|
|
206
|
+
}, context().disabled, false);
|
|
207
|
+
} else if (event.key === "PageUp") {
|
|
208
|
+
event.preventDefault();
|
|
209
|
+
if (event.shiftKey) {
|
|
210
|
+
focusedDay = modifyFocusedDay(p.day, {
|
|
211
|
+
year: -1
|
|
212
|
+
}, context().disabled);
|
|
213
|
+
} else {
|
|
214
|
+
focusedDay = modifyFocusedDay(p.day, {
|
|
215
|
+
month: -1
|
|
216
|
+
}, context().disabled);
|
|
217
|
+
}
|
|
218
|
+
} else if (event.key === "PageDown") {
|
|
219
|
+
event.preventDefault();
|
|
220
|
+
if (event.shiftKey) {
|
|
221
|
+
focusedDay = modifyFocusedDay(p.day, {
|
|
222
|
+
year: 1
|
|
223
|
+
}, context().disabled);
|
|
224
|
+
} else {
|
|
225
|
+
focusedDay = modifyFocusedDay(p.day, {
|
|
226
|
+
month: 1
|
|
227
|
+
}, context().disabled);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (focusedDay === null) return;
|
|
231
|
+
context().setIsFocusing(true);
|
|
232
|
+
context().setFocusedDay(focusedDay);
|
|
233
|
+
};
|
|
234
|
+
return createComponent(Dynamic, mergeProps({
|
|
235
|
+
as: "button",
|
|
236
|
+
ref(r$) {
|
|
237
|
+
var _ref$ = mergeRefs(setRef, p.ref);
|
|
238
|
+
typeof _ref$ === "function" && _ref$(r$);
|
|
239
|
+
},
|
|
240
|
+
onClick,
|
|
241
|
+
onKeyDown,
|
|
242
|
+
get disabled() {
|
|
243
|
+
return p.disabled === true || context().isDisabled(p.day, p.month) || void 0;
|
|
244
|
+
},
|
|
245
|
+
role: "gridcell",
|
|
246
|
+
get tabIndex() {
|
|
247
|
+
return isSameDay(context().focusedDay(), p.day) ? 0 : -1;
|
|
248
|
+
},
|
|
249
|
+
get ["aria-selected"]() {
|
|
250
|
+
return memo(() => !!context().isSelected(p.day))() ? "true" : !context().isDisabled(p.day, p.month) ? "false" : void 0;
|
|
251
|
+
},
|
|
252
|
+
get ["aria-disabled"]() {
|
|
253
|
+
return context().isDisabled(p.day, p.month) ? "true" : void 0;
|
|
254
|
+
},
|
|
255
|
+
get ["data-selected"]() {
|
|
256
|
+
return dataIf(context().isSelected(p.day));
|
|
257
|
+
},
|
|
258
|
+
get ["data-disabled"]() {
|
|
259
|
+
return dataIf(context().isDisabled(p.day, p.month));
|
|
260
|
+
},
|
|
261
|
+
get ["data-today"]() {
|
|
262
|
+
return dataIf(isToday());
|
|
263
|
+
},
|
|
264
|
+
get ["data-range-start"]() {
|
|
265
|
+
return dataIf(context().mode() === "range" && isSameDay(p.day, context().value().from));
|
|
266
|
+
},
|
|
267
|
+
get ["data-range-end"]() {
|
|
268
|
+
return dataIf(context().mode() === "range" && isSameDay(p.day, context().value().to));
|
|
269
|
+
},
|
|
270
|
+
get ["data-in-range"]() {
|
|
271
|
+
return dataIf(context().mode() === "range" && isSameDayOrAfter(p.day, context().value().from) && isSameDayOrBefore(p.day, context().value().to));
|
|
272
|
+
},
|
|
273
|
+
"data-corvu-calendar-celltrigger": ""
|
|
274
|
+
}, otherProps));
|
|
275
|
+
};
|
|
276
|
+
var CellTrigger_default = CalendarCellTrigger;
|
|
277
|
+
var CalendarHeadCell = (props) => {
|
|
278
|
+
return createComponent(Dynamic, mergeProps({
|
|
279
|
+
as: "th",
|
|
280
|
+
scope: "col",
|
|
281
|
+
"data-corvu-calendar-headcell": ""
|
|
282
|
+
}, props));
|
|
283
|
+
};
|
|
284
|
+
var HeadCell_default = CalendarHeadCell;
|
|
285
|
+
var CalendarLabel = (props) => {
|
|
286
|
+
const p = props;
|
|
287
|
+
const otherProps = omit(p, "index", "contextId");
|
|
288
|
+
const context = createMemo(() => useInternalCalendarContext(p.contextId));
|
|
289
|
+
createEffect(() => {
|
|
290
|
+
const _context = context();
|
|
291
|
+
_context.registerLabelId(p.index ?? 0);
|
|
292
|
+
return () => _context.unregisterLabelId(p.index ?? 0);
|
|
293
|
+
});
|
|
294
|
+
return createComponent(Dynamic, mergeProps({
|
|
295
|
+
as: "h2",
|
|
296
|
+
get id() {
|
|
297
|
+
return context().labelIds()[p.index ?? 0]?.();
|
|
298
|
+
},
|
|
299
|
+
"aria-live": "polite",
|
|
300
|
+
"data-corvu-calendar-label": ""
|
|
301
|
+
}, otherProps));
|
|
302
|
+
};
|
|
303
|
+
var Label_default = CalendarLabel;
|
|
304
|
+
var CalendarNav = (props) => {
|
|
305
|
+
const otherProps = omit(props, "action", "contextId", "onClick");
|
|
306
|
+
const context = createMemo(() => useInternalCalendarContext(props.contextId));
|
|
307
|
+
const onClick = (e) => {
|
|
308
|
+
!callEventHandler(props.onClick, e) && context().navigate(props.action);
|
|
309
|
+
};
|
|
310
|
+
return createComponent(DynamicButton, mergeProps({
|
|
311
|
+
as: "button",
|
|
312
|
+
onClick,
|
|
313
|
+
"data-corvu-calendar-nav": ""
|
|
314
|
+
}, otherProps));
|
|
315
|
+
};
|
|
316
|
+
var Nav_default = CalendarNav;
|
|
317
|
+
var CalendarRoot = (props) => {
|
|
318
|
+
const defaultedProps = merge({
|
|
319
|
+
initialValue: props.mode === "single" ? null : props.mode === "multiple" ? [] : {
|
|
320
|
+
from: null,
|
|
321
|
+
to: null
|
|
322
|
+
},
|
|
323
|
+
initialMonth: props.initialFocusedDay ?? /* @__PURE__ */ new Date(),
|
|
324
|
+
initialFocusedDay: findAvailableDayInMonth(props.initialMonth ?? /* @__PURE__ */ new Date(), props.disabled ?? (() => true)),
|
|
325
|
+
startOfWeek: 1,
|
|
326
|
+
required: false,
|
|
327
|
+
disabled: () => false,
|
|
328
|
+
numberOfMonths: 1,
|
|
329
|
+
disableOutsideDays: true,
|
|
330
|
+
fixedWeeks: false,
|
|
331
|
+
textDirection: "ltr",
|
|
332
|
+
labelIds: [],
|
|
333
|
+
min: null,
|
|
334
|
+
max: null,
|
|
335
|
+
excludeDisabled: false
|
|
336
|
+
}, props);
|
|
337
|
+
const [value, setValue] = createControllableSignal({
|
|
338
|
+
value: () => defaultedProps.value,
|
|
339
|
+
initialValue: defaultedProps.initialValue,
|
|
340
|
+
onChange: props.onValueChange
|
|
341
|
+
});
|
|
342
|
+
const [month, setMonthInternal] = createControllableSignal({
|
|
343
|
+
value: () => defaultedProps.month,
|
|
344
|
+
initialValue: defaultedProps.initialMonth,
|
|
345
|
+
onChange: defaultedProps.onMonthChange
|
|
346
|
+
});
|
|
347
|
+
const [focusedDay, setFocusedDayInternal] = createControllableSignal({
|
|
348
|
+
value: () => defaultedProps.focusedDay,
|
|
349
|
+
initialValue: defaultedProps.initialFocusedDay,
|
|
350
|
+
onChange: defaultedProps.onFocusedDayChange
|
|
351
|
+
});
|
|
352
|
+
const registerMemo = createMemo(() => {
|
|
353
|
+
const registers = Array.from({
|
|
354
|
+
length: defaultedProps.numberOfMonths
|
|
355
|
+
}, (_, index) => createRegister({
|
|
356
|
+
value: () => defaultedProps.labelIds[index] ?? createUniqueId()
|
|
357
|
+
}));
|
|
358
|
+
const labelIds = registers.map((register) => register[0]);
|
|
359
|
+
const registerLabelId = (index) => {
|
|
360
|
+
registers[index]?.[1]();
|
|
361
|
+
};
|
|
362
|
+
const unregisterLabelId = (index) => {
|
|
363
|
+
registers[index]?.[2]();
|
|
364
|
+
};
|
|
365
|
+
return [labelIds, registerLabelId, unregisterLabelId];
|
|
366
|
+
});
|
|
367
|
+
const [focusedDayRef, setFocusedDayRef] = createSignal(null);
|
|
368
|
+
const [isFocusing, setIsFocusing] = createSignal(false);
|
|
369
|
+
const setMonth = (next) => {
|
|
370
|
+
return untrack(() => {
|
|
371
|
+
let nextValue;
|
|
372
|
+
if (typeof next === "function") {
|
|
373
|
+
nextValue = next(month());
|
|
374
|
+
} else {
|
|
375
|
+
nextValue = next;
|
|
376
|
+
}
|
|
377
|
+
setMonthInternal(nextValue);
|
|
378
|
+
if (!dayIsInMonth(focusedDay(), nextValue, defaultedProps.numberOfMonths)) {
|
|
379
|
+
setFocusedDayInternal((focusedDay2) => findAvailableDayInMonth(new Date(nextValue.getFullYear(), nextValue.getMonth(), focusedDay2.getDate()), defaultedProps.disabled));
|
|
380
|
+
}
|
|
381
|
+
return nextValue;
|
|
382
|
+
});
|
|
383
|
+
};
|
|
384
|
+
const setFocusedDay = (next) => {
|
|
385
|
+
return untrack(() => {
|
|
386
|
+
let nextValue;
|
|
387
|
+
if (typeof next === "function") {
|
|
388
|
+
nextValue = next(focusedDay());
|
|
389
|
+
} else {
|
|
390
|
+
nextValue = next;
|
|
391
|
+
}
|
|
392
|
+
if (defaultedProps.disabled(nextValue)) return;
|
|
393
|
+
setFocusedDayInternal(nextValue);
|
|
394
|
+
if (!dayIsInMonth(nextValue, month(), defaultedProps.numberOfMonths)) {
|
|
395
|
+
const delta = (nextValue.getFullYear() - month().getFullYear()) * 12 + (nextValue.getMonth() - month().getMonth());
|
|
396
|
+
const newMonth = new Date(month().getFullYear(), month().getMonth() + Math.sign(delta) * Math.max(defaultedProps.numberOfMonths, Math.abs(delta)));
|
|
397
|
+
setMonthInternal(newMonth);
|
|
398
|
+
}
|
|
399
|
+
return nextValue;
|
|
400
|
+
});
|
|
401
|
+
};
|
|
402
|
+
const weekdays = () => {
|
|
403
|
+
const startOfWeek = defaultedProps.startOfWeek;
|
|
404
|
+
return Array.from({
|
|
405
|
+
length: 7
|
|
406
|
+
}, (_, i) => {
|
|
407
|
+
const day = (i + startOfWeek) % 7 + 4;
|
|
408
|
+
return new Date(1970, 0, day);
|
|
409
|
+
});
|
|
410
|
+
};
|
|
411
|
+
const months = () => {
|
|
412
|
+
const months2 = [];
|
|
413
|
+
for (let i = 0; i < defaultedProps.numberOfMonths; i++) {
|
|
414
|
+
months2.push({
|
|
415
|
+
month: modifyDate(month(), {
|
|
416
|
+
month: i
|
|
417
|
+
}),
|
|
418
|
+
weeks: weeks(i)
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
return months2;
|
|
422
|
+
};
|
|
423
|
+
const weeks = (monthOffset = 0) => {
|
|
424
|
+
const adjustedMonth = new Date(month().getFullYear(), month().getMonth() + monthOffset);
|
|
425
|
+
const calendar = [];
|
|
426
|
+
const firstDayOfMonth = new Date(adjustedMonth.getFullYear(), adjustedMonth.getMonth(), 1);
|
|
427
|
+
const lastDayOfMonth = new Date(adjustedMonth.getFullYear(), adjustedMonth.getMonth() + 1, 0);
|
|
428
|
+
const prefixedDays = (firstDayOfMonth.getDay() - defaultedProps.startOfWeek + 7) % 7;
|
|
429
|
+
const weekCount = defaultedProps.fixedWeeks ? 6 : Math.ceil((lastDayOfMonth.getDate() + prefixedDays) / 7);
|
|
430
|
+
const currentDay = new Date(adjustedMonth.getFullYear(), adjustedMonth.getMonth(), 1 - prefixedDays);
|
|
431
|
+
for (let i = 0; i < weekCount; i++) {
|
|
432
|
+
const week = [];
|
|
433
|
+
for (let i2 = 0; i2 < 7; i2++) {
|
|
434
|
+
week.push(new Date(currentDay));
|
|
435
|
+
currentDay.setDate(currentDay.getDate() + 1);
|
|
436
|
+
}
|
|
437
|
+
calendar.push(week);
|
|
438
|
+
}
|
|
439
|
+
return calendar;
|
|
440
|
+
};
|
|
441
|
+
const navigate = (action) => {
|
|
442
|
+
if (typeof action === "function") {
|
|
443
|
+
const newDate = action(month());
|
|
444
|
+
setMonth(newDate);
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
switch (action) {
|
|
448
|
+
case "prev-month":
|
|
449
|
+
setMonth((month2) => modifyDate(month2, {
|
|
450
|
+
month: -1
|
|
451
|
+
}));
|
|
452
|
+
break;
|
|
453
|
+
case "next-month":
|
|
454
|
+
setMonth((month2) => modifyDate(month2, {
|
|
455
|
+
month: 1
|
|
456
|
+
}));
|
|
457
|
+
break;
|
|
458
|
+
case "prev-year":
|
|
459
|
+
setMonth((month2) => modifyDate(month2, {
|
|
460
|
+
year: -1
|
|
461
|
+
}));
|
|
462
|
+
break;
|
|
463
|
+
case "next-year":
|
|
464
|
+
setMonth((month2) => modifyDate(month2, {
|
|
465
|
+
year: 1
|
|
466
|
+
}));
|
|
467
|
+
break;
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
const onDaySelect = (day) => {
|
|
471
|
+
setFocusedDay(day);
|
|
472
|
+
switch (defaultedProps.mode) {
|
|
473
|
+
case "single":
|
|
474
|
+
setValue((value2) => {
|
|
475
|
+
if (isSameDay(day, value2) && !defaultedProps.required) {
|
|
476
|
+
return null;
|
|
477
|
+
} else {
|
|
478
|
+
return day;
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
break;
|
|
482
|
+
case "multiple":
|
|
483
|
+
setValue((value2) => {
|
|
484
|
+
value2 = value2;
|
|
485
|
+
const isSelected2 = value2.some((d) => isSameDay(day, d));
|
|
486
|
+
if (isSelected2 && value2.length !== defaultedProps.min && !(value2.length === 1 && defaultedProps.required)) {
|
|
487
|
+
return value2.filter((d) => !isSameDay(day, d));
|
|
488
|
+
}
|
|
489
|
+
if (!isSelected2 && value2.length !== defaultedProps.max) {
|
|
490
|
+
return [...value2, day];
|
|
491
|
+
}
|
|
492
|
+
return value2;
|
|
493
|
+
});
|
|
494
|
+
break;
|
|
495
|
+
case "range":
|
|
496
|
+
setValue((value2) => {
|
|
497
|
+
value2 = value2;
|
|
498
|
+
if (value2.from === null) {
|
|
499
|
+
return {
|
|
500
|
+
from: day,
|
|
501
|
+
to: null
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
if (value2.to === null) {
|
|
505
|
+
let from = value2.from;
|
|
506
|
+
let to = day;
|
|
507
|
+
if (day < from) {
|
|
508
|
+
to = from;
|
|
509
|
+
from = day;
|
|
510
|
+
}
|
|
511
|
+
if (defaultedProps.excludeDisabled) {
|
|
512
|
+
for (let day2 = new Date(from); day2 < to; day2.setDate(day2.getDate() + 1)) {
|
|
513
|
+
if (defaultedProps.disabled(day2)) {
|
|
514
|
+
return {
|
|
515
|
+
from: day2,
|
|
516
|
+
to: null
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
return {
|
|
522
|
+
from,
|
|
523
|
+
to
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
if (isSameDay(day, value2.from) && !defaultedProps.required) {
|
|
527
|
+
return {
|
|
528
|
+
from: null,
|
|
529
|
+
to: null
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
return {
|
|
533
|
+
from: day,
|
|
534
|
+
to: null
|
|
535
|
+
};
|
|
536
|
+
});
|
|
537
|
+
break;
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
const isSelected = (day) => {
|
|
541
|
+
let _value = value();
|
|
542
|
+
switch (defaultedProps.mode) {
|
|
543
|
+
case "single":
|
|
544
|
+
return isSameDay(day, _value);
|
|
545
|
+
case "multiple":
|
|
546
|
+
return _value.some((value2) => isSameDay(day, value2));
|
|
547
|
+
case "range":
|
|
548
|
+
_value = _value;
|
|
549
|
+
return isSameDay(day, _value.from) || isSameDayOrAfter(day, _value.from) && isSameDayOrBefore(day, _value.to);
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
const isDisabled = (day, _month) => {
|
|
553
|
+
_month = _month ?? month();
|
|
554
|
+
if (defaultedProps.disableOutsideDays && day.getMonth() !== _month.getMonth()) {
|
|
555
|
+
return true;
|
|
556
|
+
}
|
|
557
|
+
return defaultedProps.disabled(day);
|
|
558
|
+
};
|
|
559
|
+
const childrenProps = {
|
|
560
|
+
get mode() {
|
|
561
|
+
return defaultedProps.mode;
|
|
562
|
+
},
|
|
563
|
+
get value() {
|
|
564
|
+
return value();
|
|
565
|
+
},
|
|
566
|
+
// @ts-expect-error: Union type shenanigans
|
|
567
|
+
setValue,
|
|
568
|
+
get month() {
|
|
569
|
+
return month();
|
|
570
|
+
},
|
|
571
|
+
setMonth,
|
|
572
|
+
get focusedDay() {
|
|
573
|
+
return focusedDay();
|
|
574
|
+
},
|
|
575
|
+
setFocusedDay,
|
|
576
|
+
get startOfWeek() {
|
|
577
|
+
return defaultedProps.startOfWeek;
|
|
578
|
+
},
|
|
579
|
+
get required() {
|
|
580
|
+
return defaultedProps.required;
|
|
581
|
+
},
|
|
582
|
+
get numberOfMonths() {
|
|
583
|
+
return defaultedProps.numberOfMonths;
|
|
584
|
+
},
|
|
585
|
+
get disableOutsideDays() {
|
|
586
|
+
return defaultedProps.disableOutsideDays;
|
|
587
|
+
},
|
|
588
|
+
get fixedWeeks() {
|
|
589
|
+
return defaultedProps.fixedWeeks;
|
|
590
|
+
},
|
|
591
|
+
get textDirection() {
|
|
592
|
+
return defaultedProps.textDirection;
|
|
593
|
+
},
|
|
594
|
+
get weekdays() {
|
|
595
|
+
return weekdays();
|
|
596
|
+
},
|
|
597
|
+
get months() {
|
|
598
|
+
return months();
|
|
599
|
+
},
|
|
600
|
+
get weeks() {
|
|
601
|
+
return weeks();
|
|
602
|
+
},
|
|
603
|
+
navigate,
|
|
604
|
+
get focusedDayRef() {
|
|
605
|
+
return focusedDayRef();
|
|
606
|
+
},
|
|
607
|
+
get min() {
|
|
608
|
+
return defaultedProps.min;
|
|
609
|
+
},
|
|
610
|
+
get max() {
|
|
611
|
+
return defaultedProps.max;
|
|
612
|
+
},
|
|
613
|
+
get excludeDisabled() {
|
|
614
|
+
return defaultedProps.excludeDisabled;
|
|
615
|
+
},
|
|
616
|
+
get labelIds() {
|
|
617
|
+
return registerMemo()[0].map((labelId) => labelId());
|
|
618
|
+
}
|
|
619
|
+
};
|
|
620
|
+
const memoizedChildren = createOnce(() => defaultedProps.children);
|
|
621
|
+
const resolveChildren = () => {
|
|
622
|
+
const children = memoizedChildren()();
|
|
623
|
+
if (isFunction(children)) {
|
|
624
|
+
return children(childrenProps);
|
|
625
|
+
}
|
|
626
|
+
return children;
|
|
627
|
+
};
|
|
628
|
+
const memoizedCalendarRoot = createMemo(() => {
|
|
629
|
+
const CalendarContext2 = createCalendarContext(defaultedProps.contextId);
|
|
630
|
+
const InternalCalendarContext2 = createInternalCalendarContext(defaultedProps.contextId);
|
|
631
|
+
return createComponent(CalendarContext2, {
|
|
632
|
+
value: {
|
|
633
|
+
// @ts-expect-error: Union type shenanigans
|
|
634
|
+
mode: () => defaultedProps.mode,
|
|
635
|
+
// @ts-expect-error: Union type shenanigans
|
|
636
|
+
value,
|
|
637
|
+
// @ts-expect-error: Union type shenanigans
|
|
638
|
+
setValue,
|
|
639
|
+
month,
|
|
640
|
+
setMonth,
|
|
641
|
+
focusedDay,
|
|
642
|
+
setFocusedDay,
|
|
643
|
+
startOfWeek: () => defaultedProps.startOfWeek,
|
|
644
|
+
required: () => defaultedProps.required,
|
|
645
|
+
numberOfMonths: () => defaultedProps.numberOfMonths,
|
|
646
|
+
disableOutsideDays: () => defaultedProps.disableOutsideDays,
|
|
647
|
+
fixedWeeks: () => defaultedProps.fixedWeeks,
|
|
648
|
+
textDirection: () => defaultedProps.textDirection,
|
|
649
|
+
weekdays,
|
|
650
|
+
months,
|
|
651
|
+
weeks,
|
|
652
|
+
navigate,
|
|
653
|
+
focusedDayRef,
|
|
654
|
+
min: () => defaultedProps.min,
|
|
655
|
+
max: () => defaultedProps.max,
|
|
656
|
+
excludeDisabled: () => defaultedProps.excludeDisabled,
|
|
657
|
+
labelIds: () => registerMemo()[0]
|
|
658
|
+
},
|
|
659
|
+
get children() {
|
|
660
|
+
return createComponent(InternalCalendarContext2, {
|
|
661
|
+
get value() {
|
|
662
|
+
return {
|
|
663
|
+
// @ts-expect-error: Union type shenanigans
|
|
664
|
+
mode: () => defaultedProps.mode,
|
|
665
|
+
// @ts-expect-error: Union type shenanigans
|
|
666
|
+
value,
|
|
667
|
+
// @ts-expect-error: Union type shenanigans
|
|
668
|
+
setValue,
|
|
669
|
+
month,
|
|
670
|
+
setMonth,
|
|
671
|
+
focusedDay,
|
|
672
|
+
setFocusedDay,
|
|
673
|
+
startOfWeek: () => defaultedProps.startOfWeek,
|
|
674
|
+
required: () => defaultedProps.required,
|
|
675
|
+
numberOfMonths: () => defaultedProps.numberOfMonths,
|
|
676
|
+
disableOutsideDays: () => defaultedProps.disableOutsideDays,
|
|
677
|
+
fixedWeeks: () => defaultedProps.fixedWeeks,
|
|
678
|
+
textDirection: () => defaultedProps.textDirection,
|
|
679
|
+
weekdays,
|
|
680
|
+
months,
|
|
681
|
+
weeks,
|
|
682
|
+
navigate,
|
|
683
|
+
focusedDayRef,
|
|
684
|
+
min: () => defaultedProps.min,
|
|
685
|
+
max: () => defaultedProps.max,
|
|
686
|
+
excludeDisabled: () => defaultedProps.excludeDisabled,
|
|
687
|
+
labelIds: () => registerMemo()[0],
|
|
688
|
+
registerLabelId: (index) => registerMemo()[1](index),
|
|
689
|
+
unregisterLabelId: (index) => registerMemo()[2](index),
|
|
690
|
+
onDaySelect,
|
|
691
|
+
isSelected,
|
|
692
|
+
isDisabled,
|
|
693
|
+
isFocusing,
|
|
694
|
+
setIsFocusing,
|
|
695
|
+
disabled: defaultedProps.disabled,
|
|
696
|
+
setFocusedDayRef
|
|
697
|
+
};
|
|
698
|
+
},
|
|
699
|
+
get children() {
|
|
700
|
+
return untrack(() => resolveChildren());
|
|
701
|
+
}
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
});
|
|
705
|
+
});
|
|
706
|
+
return memoizedCalendarRoot;
|
|
707
|
+
};
|
|
708
|
+
var Root_default = CalendarRoot;
|
|
709
|
+
var CalendarTable = (props) => {
|
|
710
|
+
const p = props;
|
|
711
|
+
const otherProps = omit(p, "index", "contextId");
|
|
712
|
+
const context = createMemo(() => useInternalCalendarContext(p.contextId));
|
|
713
|
+
return createComponent(Dynamic, mergeProps({
|
|
714
|
+
as: "table",
|
|
715
|
+
role: "grid",
|
|
716
|
+
get ["aria-labelledby"]() {
|
|
717
|
+
return context().labelIds()[p.index ?? 0]?.();
|
|
718
|
+
},
|
|
719
|
+
get ["aria-multiselectable"]() {
|
|
720
|
+
return context().mode() === "multiple" || context().mode() === "range" ? "true" : void 0;
|
|
721
|
+
},
|
|
722
|
+
"data-corvu-calendar-table": ""
|
|
723
|
+
}, otherProps));
|
|
724
|
+
};
|
|
725
|
+
var Table_default = CalendarTable;
|
|
726
|
+
|
|
727
|
+
// src/index.ts
|
|
728
|
+
var Calendar = Object.assign(Root_default, {
|
|
729
|
+
Label: Label_default,
|
|
730
|
+
Nav: Nav_default,
|
|
731
|
+
Table: Table_default,
|
|
732
|
+
HeadCell: HeadCell_default,
|
|
733
|
+
Cell: Cell_default,
|
|
734
|
+
CellTrigger: CellTrigger_default,
|
|
735
|
+
useContext: useCalendarContext
|
|
736
|
+
});
|
|
737
|
+
var index_default = Calendar;
|
|
738
|
+
|
|
739
|
+
export { index_default as default };
|