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