panelui-native 0.28.1 → 0.32.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/README.md +22 -3
- package/lib/module/components/calendar/index.js +450 -132
- package/lib/module/components/calendar/index.js.map +1 -1
- package/lib/module/components/code-block/highlight.js +363 -0
- package/lib/module/components/code-block/highlight.js.map +1 -0
- package/lib/module/components/code-block/index.js +313 -0
- package/lib/module/components/code-block/index.js.map +1 -0
- package/lib/module/components/date-picker/index.js +8 -1
- package/lib/module/components/date-picker/index.js.map +1 -1
- package/lib/module/components/heatmap-chart/index.js +9 -8
- package/lib/module/components/heatmap-chart/index.js.map +1 -1
- package/lib/module/components/map/index.js +50 -4
- package/lib/module/components/map/index.js.map +1 -1
- package/lib/module/components/menu/index.js +714 -0
- package/lib/module/components/menu/index.js.map +1 -0
- package/lib/module/components/plan/index.js +582 -0
- package/lib/module/components/plan/index.js.map +1 -0
- package/lib/module/components/popover/index.js +35 -4
- package/lib/module/components/popover/index.js.map +1 -1
- package/lib/module/components/post/index.js +992 -0
- package/lib/module/components/post/index.js.map +1 -0
- package/lib/module/components/radio-group/index.js +13 -8
- package/lib/module/components/radio-group/index.js.map +1 -1
- package/lib/module/components/reasoning/index.js +244 -0
- package/lib/module/components/reasoning/index.js.map +1 -0
- package/lib/module/components/response/index.js +296 -0
- package/lib/module/components/response/index.js.map +1 -0
- package/lib/module/components/response/markdown.js +463 -0
- package/lib/module/components/response/markdown.js.map +1 -0
- package/lib/module/components/select/index.js +97 -15
- package/lib/module/components/select/index.js.map +1 -1
- package/lib/module/components/sources/index.js +221 -0
- package/lib/module/components/sources/index.js.map +1 -0
- package/lib/module/components/table/index.js +632 -0
- package/lib/module/components/table/index.js.map +1 -0
- package/lib/module/components/task/index.js +300 -0
- package/lib/module/components/task/index.js.map +1 -0
- package/lib/module/components/textarea/index.js +295 -0
- package/lib/module/components/textarea/index.js.map +1 -0
- package/lib/module/components/tooltip/index.js +179 -23
- package/lib/module/components/tooltip/index.js.map +1 -1
- package/lib/module/icons/index.js +339 -0
- package/lib/module/icons/index.js.map +1 -1
- package/lib/module/index.js +12 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/primitives/collapse.js +112 -0
- package/lib/module/primitives/collapse.js.map +1 -0
- package/lib/module/utils/date.js +129 -22
- package/lib/module/utils/date.js.map +1 -1
- package/lib/typescript/src/components/calendar/index.d.ts +79 -5
- package/lib/typescript/src/components/calendar/index.d.ts.map +1 -1
- package/lib/typescript/src/components/code-block/highlight.d.ts +39 -0
- package/lib/typescript/src/components/code-block/highlight.d.ts.map +1 -0
- package/lib/typescript/src/components/code-block/index.d.ts +113 -0
- package/lib/typescript/src/components/code-block/index.d.ts.map +1 -0
- package/lib/typescript/src/components/date-picker/index.d.ts +7 -1
- package/lib/typescript/src/components/date-picker/index.d.ts.map +1 -1
- package/lib/typescript/src/components/heatmap-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/map/index.d.ts +8 -1
- package/lib/typescript/src/components/map/index.d.ts.map +1 -1
- package/lib/typescript/src/components/menu/index.d.ts +261 -0
- package/lib/typescript/src/components/menu/index.d.ts.map +1 -0
- package/lib/typescript/src/components/plan/index.d.ts +238 -0
- package/lib/typescript/src/components/plan/index.d.ts.map +1 -0
- package/lib/typescript/src/components/popover/index.d.ts +35 -1
- package/lib/typescript/src/components/popover/index.d.ts.map +1 -1
- package/lib/typescript/src/components/post/index.d.ts +358 -0
- package/lib/typescript/src/components/post/index.d.ts.map +1 -0
- package/lib/typescript/src/components/radio-group/index.d.ts.map +1 -1
- package/lib/typescript/src/components/reasoning/index.d.ts +97 -0
- package/lib/typescript/src/components/reasoning/index.d.ts.map +1 -0
- package/lib/typescript/src/components/response/index.d.ts +91 -0
- package/lib/typescript/src/components/response/index.d.ts.map +1 -0
- package/lib/typescript/src/components/response/markdown.d.ts +88 -0
- package/lib/typescript/src/components/response/markdown.d.ts.map +1 -0
- package/lib/typescript/src/components/select/index.d.ts +27 -2
- package/lib/typescript/src/components/select/index.d.ts.map +1 -1
- package/lib/typescript/src/components/sources/index.d.ts +85 -0
- package/lib/typescript/src/components/sources/index.d.ts.map +1 -0
- package/lib/typescript/src/components/table/index.d.ts +274 -0
- package/lib/typescript/src/components/table/index.d.ts.map +1 -0
- package/lib/typescript/src/components/task/index.d.ts +103 -0
- package/lib/typescript/src/components/task/index.d.ts.map +1 -0
- package/lib/typescript/src/components/textarea/index.d.ts +175 -0
- package/lib/typescript/src/components/textarea/index.d.ts.map +1 -0
- package/lib/typescript/src/components/tooltip/index.d.ts +63 -8
- package/lib/typescript/src/components/tooltip/index.d.ts.map +1 -1
- package/lib/typescript/src/icons/index.d.ts +54 -1
- package/lib/typescript/src/icons/index.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +14 -3
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/primitives/collapse.d.ts +42 -0
- package/lib/typescript/src/primitives/collapse.d.ts.map +1 -0
- package/lib/typescript/src/utils/date.d.ts +49 -5
- package/lib/typescript/src/utils/date.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/calendar/index.tsx +519 -139
- package/src/components/code-block/highlight.ts +278 -0
- package/src/components/code-block/index.tsx +341 -0
- package/src/components/date-picker/index.tsx +19 -1
- package/src/components/heatmap-chart/index.tsx +9 -9
- package/src/components/map/index.tsx +53 -4
- package/src/components/menu/index.tsx +812 -0
- package/src/components/plan/index.tsx +648 -0
- package/src/components/popover/index.tsx +69 -2
- package/src/components/post/index.tsx +1116 -0
- package/src/components/radio-group/index.tsx +11 -2
- package/src/components/reasoning/index.tsx +297 -0
- package/src/components/response/index.tsx +390 -0
- package/src/components/response/markdown.ts +489 -0
- package/src/components/select/index.tsx +132 -12
- package/src/components/sources/index.tsx +278 -0
- package/src/components/table/index.tsx +747 -0
- package/src/components/task/index.tsx +329 -0
- package/src/components/textarea/index.tsx +381 -0
- package/src/components/tooltip/index.tsx +203 -20
- package/src/icons/index.tsx +264 -1
- package/src/index.ts +131 -0
- package/src/primitives/collapse.tsx +128 -0
- package/src/utils/date.ts +146 -22
- package/theme.css +112 -0
|
@@ -17,25 +17,35 @@
|
|
|
17
17
|
* between months. So the grid is six rows always, and the spare cells hold the
|
|
18
18
|
* neighbouring months' days.
|
|
19
19
|
*
|
|
20
|
-
* ##
|
|
20
|
+
* ## How a range is drawn
|
|
21
21
|
*
|
|
22
22
|
* On the web the band under a selected range is one background with the ends
|
|
23
23
|
* rounded by `:first-child` and `:last-child`. There are no pseudo-classes
|
|
24
|
-
* here, so each
|
|
25
|
-
*
|
|
26
|
-
* range that runs over a weekend has to close off on Saturday and open again
|
|
27
|
-
* on Sunday rather than trailing into the gap.
|
|
24
|
+
* here, so each cell draws its own piece of the band as a view *behind* the
|
|
25
|
+
* number, and works out for itself where that piece has to stop.
|
|
28
26
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
27
|
+
* Two questions, and they are not the same one:
|
|
28
|
+
*
|
|
29
|
+
* - **How wide.** A day between the two ends fills its cell, so the pieces meet
|
|
30
|
+
* and the band reads as continuous. An end fills half its cell, from the
|
|
31
|
+
* centre outwards towards the middle of the range — the half that is not
|
|
32
|
+
* covered by the disc, so the disc appears to sit *on* the band rather than
|
|
33
|
+
* beside it. That is the join the old three-piece version never made, which
|
|
34
|
+
* is why a range used to read as two discs with a gap and a stripe.
|
|
35
|
+
* - **Where it is rounded.** Only where it genuinely stops: at an end of the
|
|
36
|
+
* range, or at the edge of a row, because a range running over a weekend has
|
|
37
|
+
* to close off on Saturday and open again on Sunday rather than trailing into
|
|
38
|
+
* the gap between the two.
|
|
31
39
|
*/
|
|
32
|
-
import { createContext, useCallback, useContext, useMemo, useState } from 'react';
|
|
33
|
-
import { Pressable, View } from 'react-native';
|
|
40
|
+
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
|
41
|
+
import { AppState, Pressable, ScrollView, View } from 'react-native';
|
|
34
42
|
import { tv } from 'tailwind-variants';
|
|
35
|
-
import {
|
|
43
|
+
import { useCSSVariable } from 'uniwind';
|
|
44
|
+
import { CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from "../../icons/index.js";
|
|
36
45
|
import { Text } from "../../primitives/text.js";
|
|
37
46
|
import { cn } from "../../utils/cn.js";
|
|
38
|
-
import {
|
|
47
|
+
import { Popover } from "../popover/index.js";
|
|
48
|
+
import { addCalendarMonths, calendarDayNumber, calendarLongDate, calendarMonthLabel, calendarMonthNames, calendarParts, clampDate, isAfter, isBefore, isSameCalendarMonth, isSameDay, isWithin, localeWeekStart, monthGrid, normalizeWeekStart, resolveCalendar, startOfCalendarMonth, startOfDay, weekdayNames } from "../../utils/date.js";
|
|
39
49
|
|
|
40
50
|
/** A range under construction: `to` is undefined between the two taps. */
|
|
41
51
|
|
|
@@ -49,15 +59,46 @@ import { addCalendarMonths, addDays, calendarDayNumber, calendarLongDate, calend
|
|
|
49
59
|
* "no weekends" and "not in the past" are the two most common cases and
|
|
50
60
|
* neither can be written as a list that stays right tomorrow.
|
|
51
61
|
*/
|
|
52
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
62
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
63
|
+
/**
|
|
64
|
+
* The corner radius of a day, and so of the band that runs between days.
|
|
65
|
+
*
|
|
66
|
+
* A number rather than a class because the band's four corners are set
|
|
67
|
+
* independently from the flags below, which no single `rounded-*` can express.
|
|
68
|
+
*/
|
|
69
|
+
const DAY_RADIUS = 8;
|
|
70
|
+
const calendarVariants = tv({
|
|
71
|
+
slots: {
|
|
72
|
+
root: 'gap-3',
|
|
73
|
+
header: 'h-10 flex-row items-center justify-between gap-2',
|
|
74
|
+
nav: 'h-8 w-8 items-center justify-center rounded-full',
|
|
75
|
+
caption: 'flex-1 flex-row items-center justify-center gap-1'
|
|
76
|
+
},
|
|
77
|
+
variants: {
|
|
78
|
+
/** Draw the calendar's own panel, for one standing on the page. */
|
|
79
|
+
bordered: {
|
|
80
|
+
true: {
|
|
81
|
+
root: 'rounded-3xl border border-border bg-card p-3'
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
defaultVariants: {
|
|
86
|
+
bordered: true
|
|
87
|
+
}
|
|
88
|
+
});
|
|
53
89
|
const dayVariants = tv({
|
|
54
90
|
slots: {
|
|
55
|
-
cell: 'flex-1 items-center justify-center',
|
|
91
|
+
cell: 'h-10 flex-1 items-center justify-center',
|
|
56
92
|
/** The range band, drawn behind the number so it can run cell to cell. */
|
|
57
|
-
band: 'absolute inset-y-
|
|
58
|
-
/**
|
|
59
|
-
|
|
60
|
-
|
|
93
|
+
band: 'absolute inset-y-0.5 bg-accent',
|
|
94
|
+
/**
|
|
95
|
+
* The fill on a selected day, or the ring on today. Square-ish rather than
|
|
96
|
+
* round: a circle has one point of contact with the band beside it, so a
|
|
97
|
+
* range reads as beads on a string. A rounded rectangle meets the band
|
|
98
|
+
* along its whole edge and the two become one shape.
|
|
99
|
+
*/
|
|
100
|
+
disc: 'h-9 w-9 items-center justify-center rounded-lg',
|
|
101
|
+
label: 'text-sm'
|
|
61
102
|
},
|
|
62
103
|
variants: {
|
|
63
104
|
selected: {
|
|
@@ -82,14 +123,15 @@ const dayVariants = tv({
|
|
|
82
123
|
label: 'text-muted-foreground/30'
|
|
83
124
|
}
|
|
84
125
|
},
|
|
85
|
-
|
|
126
|
+
/** A ruled-out day inside a range still sits on it, but faintly. */
|
|
127
|
+
fadedBand: {
|
|
86
128
|
true: {
|
|
87
|
-
band: '
|
|
129
|
+
band: 'opacity-40'
|
|
88
130
|
}
|
|
89
131
|
}
|
|
90
132
|
},
|
|
91
133
|
compoundVariants: [
|
|
92
|
-
// A selected day inside a range keeps the solid
|
|
134
|
+
// A selected day inside a range keeps the solid fill; the band passes
|
|
93
135
|
// under it rather than the disc losing to it.
|
|
94
136
|
{
|
|
95
137
|
selected: true,
|
|
@@ -108,10 +150,42 @@ function useCalendar(component) {
|
|
|
108
150
|
return context;
|
|
109
151
|
}
|
|
110
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Today, kept current.
|
|
155
|
+
*
|
|
156
|
+
* "Today" is not a constant, and a calendar is exactly the kind of thing left
|
|
157
|
+
* on screen across the boundary that changes it — a picker open in a sheet, an
|
|
158
|
+
* app resumed the next morning. Recomputed when the app comes back to the
|
|
159
|
+
* foreground, which is when a stale answer would otherwise become visible, and
|
|
160
|
+
* held as state so the marker actually moves when it does.
|
|
161
|
+
*/
|
|
162
|
+
function useToday() {
|
|
163
|
+
const [today, setToday] = useState(() => startOfDay(new Date()));
|
|
164
|
+
useEffect(() => {
|
|
165
|
+
const refresh = () => {
|
|
166
|
+
const now = startOfDay(new Date());
|
|
167
|
+
// A new object every resume would invalidate every memo below it for a
|
|
168
|
+
// date that has not changed.
|
|
169
|
+
setToday(current => current.getTime() === now.getTime() ? current : now);
|
|
170
|
+
};
|
|
171
|
+
const subscription = AppState.addEventListener('change', state => {
|
|
172
|
+
if (state === 'active') refresh();
|
|
173
|
+
});
|
|
174
|
+
return () => subscription.remove();
|
|
175
|
+
}, []);
|
|
176
|
+
return today;
|
|
177
|
+
}
|
|
178
|
+
|
|
111
179
|
/** Whether a rule, a list or a span rules this day out. */
|
|
112
180
|
function isDisabled(date, disabled, minDate, maxDate) {
|
|
113
|
-
|
|
114
|
-
|
|
181
|
+
/*
|
|
182
|
+
* Both bounds are compared at local midnight, because they are about days
|
|
183
|
+
* and the caller almost always hands over a moment. `minDate={new Date()}`
|
|
184
|
+
* means "from today", and against a raw timestamp that would rule out every
|
|
185
|
+
* hour of today that has already passed — which is to say, today.
|
|
186
|
+
*/
|
|
187
|
+
if (minDate && isBefore(date, startOfDay(minDate))) return true;
|
|
188
|
+
if (maxDate && isAfter(date, startOfDay(maxDate))) return true;
|
|
115
189
|
if (!disabled) return false;
|
|
116
190
|
if (typeof disabled === 'function') return disabled(date);
|
|
117
191
|
if (Array.isArray(disabled)) return disabled.some(day => isSameDay(day, date));
|
|
@@ -131,8 +205,12 @@ function CalendarRoot({
|
|
|
131
205
|
disabled,
|
|
132
206
|
minDate,
|
|
133
207
|
maxDate,
|
|
134
|
-
|
|
208
|
+
startMonth,
|
|
209
|
+
endMonth,
|
|
210
|
+
weekStartsOn: weekStartsOnProp = 0,
|
|
135
211
|
showOutsideDays = true,
|
|
212
|
+
selectOutsideDays = false,
|
|
213
|
+
bordered = true,
|
|
136
214
|
locale,
|
|
137
215
|
calendar = 'gregory',
|
|
138
216
|
...props
|
|
@@ -140,6 +218,10 @@ function CalendarRoot({
|
|
|
140
218
|
// Settled once here rather than at each call site, so every part of the
|
|
141
219
|
// grid is certainly reading the same calendar.
|
|
142
220
|
const system = useMemo(() => resolveCalendar(calendar, locale), [calendar, locale]);
|
|
221
|
+
// Settled once too, and normalised: everything below indexes an array of
|
|
222
|
+
// seven with it, where a negative or out-of-range value is a blank column
|
|
223
|
+
// rather than an error anyone would trace back to here.
|
|
224
|
+
const weekStartsOn = useMemo(() => weekStartsOnProp === 'auto' ? localeWeekStart(locale) : normalizeWeekStart(weekStartsOnProp), [weekStartsOnProp, locale]);
|
|
143
225
|
const [internalSelected, setInternalSelected] = useState(defaultSelected);
|
|
144
226
|
const isControlled = selected !== undefined;
|
|
145
227
|
const value = isControlled ? selected : internalSelected;
|
|
@@ -156,18 +238,57 @@ function CalendarRoot({
|
|
|
156
238
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
157
239
|
}, []);
|
|
158
240
|
const [internalMonth, setInternalMonth] = useState(initialMonth);
|
|
159
|
-
|
|
241
|
+
/*
|
|
242
|
+
* Memoised on the *instant*, not on the prop. A controlled caller almost
|
|
243
|
+
* always passes a fresh `new Date(…)`, and deriving a new month object from
|
|
244
|
+
* it on every render invalidates the grid memo and the context memo below —
|
|
245
|
+
* so a calendar that has not moved rebuilds forty-two cells per keystroke
|
|
246
|
+
* somewhere else on the screen.
|
|
247
|
+
*/
|
|
248
|
+
const controlledMonth = useMemo(() => monthProp ? startOfCalendarMonth(monthProp, system, locale) : undefined,
|
|
249
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
250
|
+
[monthProp?.getTime(), system, locale]);
|
|
251
|
+
const month = controlledMonth ?? internalMonth;
|
|
252
|
+
|
|
253
|
+
/*
|
|
254
|
+
* How far the calendar may be paged, as the first day of the outermost month
|
|
255
|
+
* either way. `startMonth`/`endMonth` win where they are given, because they
|
|
256
|
+
* are the props about *navigation*; `minDate`/`maxDate` are about which days
|
|
257
|
+
* can be picked, and stand in when the navigation bounds are not stated.
|
|
258
|
+
*/
|
|
259
|
+
const monthBounds = useMemo(() => {
|
|
260
|
+
const lower = startMonth ?? minDate;
|
|
261
|
+
const upper = endMonth ?? maxDate;
|
|
262
|
+
return {
|
|
263
|
+
from: lower ? startOfCalendarMonth(lower, system, locale) : undefined,
|
|
264
|
+
to: upper ? startOfCalendarMonth(upper, system, locale) : undefined
|
|
265
|
+
};
|
|
266
|
+
}, [startMonth, minDate, endMonth, maxDate, system, locale]);
|
|
160
267
|
const setMonth = useCallback(next => {
|
|
161
|
-
|
|
268
|
+
/*
|
|
269
|
+
* Clamped here rather than only at the arrows. The arrows guard
|
|
270
|
+
* themselves, but the caption's dropdowns and a controlled caller both
|
|
271
|
+
* reach this by other routes — and a month list that offers a year is a
|
|
272
|
+
* poor place to discover that the year was out of bounds.
|
|
273
|
+
*/
|
|
274
|
+
const settled = clampDate(startOfCalendarMonth(next, system, locale), monthBounds.from, monthBounds.to);
|
|
162
275
|
if (!monthProp) setInternalMonth(settled);
|
|
163
276
|
onMonthChange?.(settled);
|
|
164
|
-
}, [monthProp, onMonthChange, system, locale]);
|
|
277
|
+
}, [monthProp, onMonthChange, system, locale, monthBounds]);
|
|
165
278
|
const commit = useCallback(next => {
|
|
166
279
|
if (!isControlled) setInternalSelected(next);
|
|
167
280
|
onSelect?.(next);
|
|
168
281
|
}, [isControlled, onSelect]);
|
|
169
282
|
const select = useCallback(date => {
|
|
170
283
|
const day = startOfDay(date);
|
|
284
|
+
|
|
285
|
+
/*
|
|
286
|
+
* A tap on a neighbouring month's cell — which only happens with
|
|
287
|
+
* `selectOutsideDays` — commits a date the grid is not showing. Page to
|
|
288
|
+
* it, or the selection lands in a greyed-out cell of the month you are
|
|
289
|
+
* still looking at and reads as having missed.
|
|
290
|
+
*/
|
|
291
|
+
if (!isSameCalendarMonth(day, month, system, locale)) setMonth(day);
|
|
171
292
|
if (mode === 'multiple') {
|
|
172
293
|
const current = value ?? [];
|
|
173
294
|
const without = current.filter(picked => !isSameDay(picked, day));
|
|
@@ -199,7 +320,7 @@ function CalendarRoot({
|
|
|
199
320
|
// Single. Tapping the selected day again clears it.
|
|
200
321
|
const current = value;
|
|
201
322
|
commit(isSameDay(current, day) ? undefined : day);
|
|
202
|
-
}, [mode, value, commit]);
|
|
323
|
+
}, [mode, value, commit, month, system, locale, setMonth]);
|
|
203
324
|
const context = useMemo(() => ({
|
|
204
325
|
month,
|
|
205
326
|
setMonth,
|
|
@@ -207,20 +328,28 @@ function CalendarRoot({
|
|
|
207
328
|
system,
|
|
208
329
|
minDate,
|
|
209
330
|
maxDate,
|
|
331
|
+
startMonth,
|
|
332
|
+
endMonth,
|
|
210
333
|
captionLayout
|
|
211
|
-
}), [month, setMonth, locale, system, minDate, maxDate, captionLayout]);
|
|
334
|
+
}), [month, setMonth, locale, system, minDate, maxDate, startMonth, endMonth, captionLayout]);
|
|
335
|
+
const {
|
|
336
|
+
root
|
|
337
|
+
} = calendarVariants({
|
|
338
|
+
bordered
|
|
339
|
+
});
|
|
340
|
+
const months = Math.max(1, numberOfMonths);
|
|
212
341
|
return /*#__PURE__*/_jsx(CalendarContext.Provider, {
|
|
213
342
|
value: context,
|
|
214
343
|
children: /*#__PURE__*/_jsx(View, {
|
|
215
344
|
...props,
|
|
216
|
-
className: cn(
|
|
345
|
+
className: cn(root(), className),
|
|
217
346
|
children: Array.from({
|
|
218
|
-
length:
|
|
347
|
+
length: months
|
|
219
348
|
}, (_unused, offset) => /*#__PURE__*/_jsxs(View, {
|
|
220
349
|
className: "gap-2",
|
|
221
|
-
children: [/*#__PURE__*/_jsx(
|
|
350
|
+
children: [/*#__PURE__*/_jsx(CalendarHeader, {
|
|
222
351
|
offset: offset,
|
|
223
|
-
lastOffset:
|
|
352
|
+
lastOffset: months - 1
|
|
224
353
|
}), /*#__PURE__*/_jsx(CalendarGrid, {
|
|
225
354
|
month: addCalendarMonths(month, offset, system, locale),
|
|
226
355
|
mode: mode,
|
|
@@ -231,6 +360,7 @@ function CalendarRoot({
|
|
|
231
360
|
maxDate: maxDate,
|
|
232
361
|
weekStartsOn: weekStartsOn,
|
|
233
362
|
showOutsideDays: showOutsideDays,
|
|
363
|
+
selectOutsideDays: selectOutsideDays,
|
|
234
364
|
locale: locale,
|
|
235
365
|
system: system
|
|
236
366
|
})]
|
|
@@ -245,15 +375,20 @@ CalendarRoot.displayName = 'Calendar';
|
|
|
245
375
|
/* -------------------------------------------------------------------------- */
|
|
246
376
|
|
|
247
377
|
/**
|
|
248
|
-
* The month
|
|
378
|
+
* The row over a month: an arrow at each edge and the month's name between
|
|
379
|
+
* them.
|
|
249
380
|
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
252
|
-
*
|
|
381
|
+
* The arrows are pinned to the edges of the calendar rather than packed around
|
|
382
|
+
* the label, so the two targets are as far apart as the panel allows and the
|
|
383
|
+
* name sits centred over its own grid. With several months shown they are split
|
|
384
|
+
* across the run — back on the first, forward on the last — because both sets
|
|
385
|
+
* on both headers would page the whole run and give two ways to do one thing.
|
|
386
|
+
* The month that owns neither still lays out a spacer, or its name would slide
|
|
387
|
+
* off centre.
|
|
253
388
|
*/
|
|
254
|
-
function
|
|
255
|
-
offset,
|
|
256
|
-
lastOffset
|
|
389
|
+
function CalendarHeader({
|
|
390
|
+
offset = 0,
|
|
391
|
+
lastOffset = 0
|
|
257
392
|
}) {
|
|
258
393
|
const {
|
|
259
394
|
month,
|
|
@@ -263,38 +398,56 @@ function CalendarCaption({
|
|
|
263
398
|
minDate,
|
|
264
399
|
maxDate,
|
|
265
400
|
captionLayout
|
|
266
|
-
} = useCalendar('Calendar.
|
|
401
|
+
} = useCalendar('Calendar.Header');
|
|
402
|
+
const {
|
|
403
|
+
header,
|
|
404
|
+
caption
|
|
405
|
+
} = calendarVariants();
|
|
267
406
|
const shown = addCalendarMonths(month, offset, system, locale);
|
|
268
407
|
const canGoBack = !minDate || isBefore(startOfCalendarMonth(minDate, system, locale), month);
|
|
269
408
|
const canGoForward = !maxDate || isAfter(startOfCalendarMonth(maxDate, system, locale), shown);
|
|
270
409
|
return /*#__PURE__*/_jsxs(View, {
|
|
271
|
-
className:
|
|
410
|
+
className: header(),
|
|
272
411
|
children: [offset === 0 ? /*#__PURE__*/_jsx(CalendarNav, {
|
|
273
412
|
direction: "previous",
|
|
274
413
|
disabled: !canGoBack,
|
|
275
414
|
onPress: () => setMonth(addCalendarMonths(month, -1, system, locale))
|
|
276
415
|
}) : /*#__PURE__*/_jsx(View, {
|
|
277
|
-
className: "h-
|
|
278
|
-
}),
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
416
|
+
className: "h-8 w-8"
|
|
417
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
418
|
+
className: caption(),
|
|
419
|
+
children: captionLayout === 'dropdown' ? /*#__PURE__*/_jsx(CalendarDropdowns, {
|
|
420
|
+
month: shown,
|
|
421
|
+
offset: offset
|
|
422
|
+
}) : /*#__PURE__*/_jsx(Text, {
|
|
423
|
+
weight: "semibold",
|
|
424
|
+
className: "text-base",
|
|
425
|
+
children: calendarMonthLabel(shown, system, locale)
|
|
426
|
+
})
|
|
284
427
|
}), offset === lastOffset ? /*#__PURE__*/_jsx(CalendarNav, {
|
|
285
428
|
direction: "next",
|
|
286
429
|
disabled: !canGoForward,
|
|
287
430
|
onPress: () => setMonth(addCalendarMonths(month, 1, system, locale))
|
|
288
431
|
}) : /*#__PURE__*/_jsx(View, {
|
|
289
|
-
className: "h-
|
|
432
|
+
className: "h-8 w-8"
|
|
290
433
|
})]
|
|
291
434
|
});
|
|
292
435
|
}
|
|
436
|
+
/**
|
|
437
|
+
* One paging arrow.
|
|
438
|
+
*
|
|
439
|
+
* Borderless: two bordered squares at the ends of a bordered panel read as a
|
|
440
|
+
* row of boxes rather than as controls, and the chevron is legible enough on
|
|
441
|
+
* its own. The target is still 32px with another 8 of slop around it.
|
|
442
|
+
*/
|
|
293
443
|
function CalendarNav({
|
|
294
444
|
direction,
|
|
295
|
-
disabled,
|
|
445
|
+
disabled = false,
|
|
296
446
|
onPress
|
|
297
447
|
}) {
|
|
448
|
+
const {
|
|
449
|
+
nav
|
|
450
|
+
} = calendarVariants();
|
|
298
451
|
return /*#__PURE__*/_jsx(Pressable, {
|
|
299
452
|
disabled: disabled,
|
|
300
453
|
onPress: onPress,
|
|
@@ -304,21 +457,26 @@ function CalendarNav({
|
|
|
304
457
|
accessibilityState: {
|
|
305
458
|
disabled
|
|
306
459
|
},
|
|
307
|
-
className: cn(
|
|
460
|
+
className: cn(nav(), disabled ? 'opacity-30' : 'active:bg-accent'),
|
|
308
461
|
children: direction === 'next' ? /*#__PURE__*/_jsx(ChevronRightIcon, {
|
|
309
|
-
size:
|
|
462
|
+
size: 18
|
|
310
463
|
}) : /*#__PURE__*/_jsx(ChevronLeftIcon, {
|
|
311
|
-
size:
|
|
464
|
+
size: 18
|
|
312
465
|
})
|
|
313
466
|
});
|
|
314
467
|
}
|
|
315
468
|
|
|
316
469
|
/**
|
|
317
|
-
* Month and year as
|
|
470
|
+
* Month and year as chips that open a panel of options.
|
|
471
|
+
*
|
|
472
|
+
* The panel floats rather than opening in place, and the caption is the reason:
|
|
473
|
+
* it is a fixed-height row, so a list opened inside it has nowhere to go and
|
|
474
|
+
* spills over the grid below. A popover is laid out against the chip and
|
|
475
|
+
* clamped to the screen, which is the behaviour this needs and already has.
|
|
318
476
|
*
|
|
319
|
-
*
|
|
320
|
-
* itself already
|
|
321
|
-
*
|
|
477
|
+
* Native pickers are still the wrong tool — a platform overlay on top of a
|
|
478
|
+
* calendar that is itself already in a popover is two floating layers deep for
|
|
479
|
+
* choosing a number, and it cannot show a Hijri year at all.
|
|
322
480
|
*/
|
|
323
481
|
function CalendarDropdowns({
|
|
324
482
|
month,
|
|
@@ -329,9 +487,10 @@ function CalendarDropdowns({
|
|
|
329
487
|
locale,
|
|
330
488
|
system,
|
|
331
489
|
minDate,
|
|
332
|
-
maxDate
|
|
490
|
+
maxDate,
|
|
491
|
+
startMonth,
|
|
492
|
+
endMonth
|
|
333
493
|
} = useCalendar('Calendar.Caption');
|
|
334
|
-
const [open, setOpen] = useState(null);
|
|
335
494
|
|
|
336
495
|
/*
|
|
337
496
|
* Everything here counts in the calendar on screen, not in the platform's.
|
|
@@ -341,10 +500,49 @@ function CalendarDropdowns({
|
|
|
341
500
|
*/
|
|
342
501
|
const months = useMemo(() => calendarMonthNames(month, system, locale, 'short'), [month, system, locale]);
|
|
343
502
|
const current = calendarParts(month, system, locale);
|
|
503
|
+
/*
|
|
504
|
+
* `startMonth`/`endMonth` bound the lists, falling back to the selectable
|
|
505
|
+
* bounds and then to a century back and a decade on. They are separate props
|
|
506
|
+
* because the two questions are different: a birthday picker wants a hundred
|
|
507
|
+
* years on offer and no bound at all on the days inside them.
|
|
508
|
+
*/
|
|
509
|
+
const first = startMonth ?? minDate;
|
|
510
|
+
const last = endMonth ?? maxDate;
|
|
511
|
+
const firstParts = first ? calendarParts(first, system, locale) : null;
|
|
512
|
+
const lastParts = last ? calendarParts(last, system, locale) : null;
|
|
344
513
|
const bounds = {
|
|
345
|
-
from:
|
|
346
|
-
to:
|
|
514
|
+
from: firstParts ? firstParts.year : current.year - 100,
|
|
515
|
+
to: lastParts ? lastParts.year : current.year + 10
|
|
347
516
|
};
|
|
517
|
+
/*
|
|
518
|
+
* The month list is bounded too, and only the year list used to be — so a
|
|
519
|
+
* calendar starting in March 1925 still offered January and February of 1925,
|
|
520
|
+
* and picking one navigated somewhere the calendar had said it would not go.
|
|
521
|
+
* Only the outermost year of each bound loses months; every year between them
|
|
522
|
+
* has all twelve.
|
|
523
|
+
*/
|
|
524
|
+
const monthOptions = months.map((label, index) => ({
|
|
525
|
+
label,
|
|
526
|
+
month: index + 1
|
|
527
|
+
})).filter(({
|
|
528
|
+
month
|
|
529
|
+
}) => {
|
|
530
|
+
if (firstParts && current.year === firstParts.year && month < firstParts.month) {
|
|
531
|
+
return false;
|
|
532
|
+
}
|
|
533
|
+
if (lastParts && current.year === lastParts.year && month > lastParts.month) {
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
return true;
|
|
537
|
+
});
|
|
538
|
+
/*
|
|
539
|
+
* Oldest first, the way a year runs. The list is long — a century by default
|
|
540
|
+
* — so it is opened scrolled to the year already in the caption rather than
|
|
541
|
+
* to either end, which is what makes the natural order affordable. Counting
|
|
542
|
+
* backwards was a way of putting the likely years at the top of a list that
|
|
543
|
+
* always opened at the top; it is not needed once the list opens in the right
|
|
544
|
+
* place, and it made every other use of the picker read upside down.
|
|
545
|
+
*/
|
|
348
546
|
const years = Array.from({
|
|
349
547
|
length: Math.max(1, bounds.to - bounds.from + 1)
|
|
350
548
|
}, (_unused, index) => bounds.from + index);
|
|
@@ -356,58 +554,154 @@ function CalendarDropdowns({
|
|
|
356
554
|
*/
|
|
357
555
|
const choose = months_ => {
|
|
358
556
|
setMonth(addCalendarMonths(month, months_ - offset, system, locale));
|
|
359
|
-
setOpen(null);
|
|
360
557
|
};
|
|
361
|
-
return /*#__PURE__*/_jsxs(
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
558
|
+
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
559
|
+
children: [/*#__PURE__*/_jsx(CaptionDropdown, {
|
|
560
|
+
label: months[current.month - 1] ?? String(current.month),
|
|
561
|
+
accessibilityLabel: "Month",
|
|
562
|
+
options: monthOptions.map(option => option.label),
|
|
563
|
+
active: monthOptions.findIndex(option => option.month === current.month),
|
|
564
|
+
width: MONTH_LIST_WIDTH,
|
|
565
|
+
onSelect: index => choose((monthOptions[index]?.month ?? current.month) - current.month)
|
|
566
|
+
}), /*#__PURE__*/_jsx(CaptionDropdown, {
|
|
567
|
+
label: String(current.year),
|
|
568
|
+
accessibilityLabel: "Year",
|
|
569
|
+
options: years.map(String),
|
|
570
|
+
active: years.indexOf(current.year),
|
|
571
|
+
width: YEAR_LIST_WIDTH,
|
|
572
|
+
onSelect: index => choose((years[index] - current.year) * 12)
|
|
573
|
+
})]
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/** Panel widths. A month name needs the room; a four-digit year does not. */
|
|
578
|
+
const MONTH_LIST_WIDTH = 176;
|
|
579
|
+
const YEAR_LIST_WIDTH = 132;
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Height of one option row, and the tallest the list is allowed to be.
|
|
583
|
+
*
|
|
584
|
+
* The row height is a constant rather than a measurement because it is what
|
|
585
|
+
* turns "the twenty-ninth option" into a scroll offset, and that has to be
|
|
586
|
+
* known before the list has laid out — the whole point is that it opens in the
|
|
587
|
+
* right place rather than scrolling there afterwards.
|
|
588
|
+
*/
|
|
589
|
+
const OPTION_HEIGHT = 40;
|
|
590
|
+
const LIST_MAX_HEIGHT = OPTION_HEIGHT * 6.5;
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* One chip and the list of options it opens.
|
|
594
|
+
*
|
|
595
|
+
* A list, not a grid of chips. Twelve months tile into a panel well enough, but
|
|
596
|
+
* the same treatment applied to a century of years is a wall of four-digit
|
|
597
|
+
* numbers with no order the eye can follow — and it opened at whichever end
|
|
598
|
+
* happened to be first. Rows in a column read as a list, take a checkmark, and
|
|
599
|
+
* can be scrolled to a particular one.
|
|
600
|
+
*/
|
|
601
|
+
function CaptionDropdown({
|
|
602
|
+
label,
|
|
603
|
+
accessibilityLabel,
|
|
604
|
+
options,
|
|
605
|
+
active,
|
|
606
|
+
width,
|
|
607
|
+
onSelect
|
|
608
|
+
}) {
|
|
609
|
+
const [open, setOpen] = useState(false);
|
|
610
|
+
const list = useRef(null);
|
|
611
|
+
/*
|
|
612
|
+
* The check is given a colour rather than left to its own fallback, which is
|
|
613
|
+
* white — right inside a filled control, invisible on this panel.
|
|
614
|
+
*/
|
|
615
|
+
const rawTick = useCSSVariable('--color-foreground');
|
|
616
|
+
const tick = typeof rawTick === 'string' ? rawTick : undefined;
|
|
617
|
+
|
|
618
|
+
/*
|
|
619
|
+
* Opened on the option already in the caption, centred in the panel rather
|
|
620
|
+
* than pinned to an edge so the years either side of it are in view too. A
|
|
621
|
+
* hundred-item list that opens at the top is showing the one year nobody came
|
|
622
|
+
* to pick, and asks for a flick through a century to reach the one they did.
|
|
623
|
+
*/
|
|
624
|
+
const scrollToActive = useCallback(() => {
|
|
625
|
+
if (active < 0) return;
|
|
626
|
+
const centred = active * OPTION_HEIGHT - LIST_MAX_HEIGHT / 2 + OPTION_HEIGHT / 2;
|
|
627
|
+
list.current?.scrollTo({
|
|
628
|
+
y: Math.max(0, centred),
|
|
629
|
+
animated: false
|
|
630
|
+
});
|
|
631
|
+
}, [active]);
|
|
632
|
+
return /*#__PURE__*/_jsxs(Popover, {
|
|
633
|
+
open: open,
|
|
634
|
+
onOpenChange: setOpen,
|
|
635
|
+
children: [/*#__PURE__*/_jsx(Popover.Trigger, {
|
|
636
|
+
children: /*#__PURE__*/_jsx(CaptionChip, {
|
|
637
|
+
label: label,
|
|
638
|
+
expanded: open,
|
|
639
|
+
accessibilityLabel: accessibilityLabel
|
|
391
640
|
})
|
|
392
|
-
})
|
|
641
|
+
}), /*#__PURE__*/_jsx(Popover.Content, {
|
|
642
|
+
align: "center",
|
|
643
|
+
width: width,
|
|
644
|
+
className: "p-1.5",
|
|
645
|
+
children: /*#__PURE__*/_jsx(ScrollView, {
|
|
646
|
+
ref: list,
|
|
647
|
+
bounces: false,
|
|
648
|
+
showsVerticalScrollIndicator: false,
|
|
649
|
+
style: {
|
|
650
|
+
maxHeight: LIST_MAX_HEIGHT
|
|
651
|
+
}
|
|
652
|
+
// Fires once the rows exist, which is the first moment there is
|
|
653
|
+
// anything to scroll. Doing it on mount would scroll an empty list.
|
|
654
|
+
,
|
|
655
|
+
onContentSizeChange: scrollToActive,
|
|
656
|
+
children: options.map((option, index) => {
|
|
657
|
+
const selected = index === active;
|
|
658
|
+
return /*#__PURE__*/_jsxs(Pressable, {
|
|
659
|
+
onPress: () => {
|
|
660
|
+
onSelect(index);
|
|
661
|
+
setOpen(false);
|
|
662
|
+
},
|
|
663
|
+
accessibilityRole: "button",
|
|
664
|
+
accessibilityState: {
|
|
665
|
+
selected
|
|
666
|
+
},
|
|
667
|
+
style: {
|
|
668
|
+
height: OPTION_HEIGHT
|
|
669
|
+
},
|
|
670
|
+
className: cn('flex-row items-center justify-between gap-2 rounded-xl px-3', selected ? 'bg-accent' : 'active:bg-accent'),
|
|
671
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
672
|
+
size: "sm",
|
|
673
|
+
weight: selected ? 'semibold' : 'normal',
|
|
674
|
+
children: option
|
|
675
|
+
}), selected ? /*#__PURE__*/_jsx(CheckIcon, {
|
|
676
|
+
size: 16,
|
|
677
|
+
color: tick
|
|
678
|
+
}) : null]
|
|
679
|
+
}, option);
|
|
680
|
+
})
|
|
681
|
+
})
|
|
682
|
+
})]
|
|
393
683
|
});
|
|
394
684
|
}
|
|
395
685
|
function CaptionChip({
|
|
396
686
|
label,
|
|
397
687
|
expanded,
|
|
688
|
+
accessibilityLabel,
|
|
398
689
|
onPress
|
|
399
690
|
}) {
|
|
400
|
-
return /*#__PURE__*/
|
|
691
|
+
return /*#__PURE__*/_jsxs(Pressable, {
|
|
401
692
|
onPress: onPress,
|
|
402
693
|
accessibilityRole: "button",
|
|
694
|
+
accessibilityLabel: accessibilityLabel,
|
|
403
695
|
accessibilityState: {
|
|
404
696
|
expanded
|
|
405
697
|
},
|
|
406
|
-
className: "flex-row items-center gap-1 rounded-
|
|
407
|
-
children: /*#__PURE__*/_jsx(Text, {
|
|
698
|
+
className: "flex-row items-center gap-1 rounded-lg px-2 py-1.5 active:bg-accent",
|
|
699
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
408
700
|
weight: "semibold",
|
|
409
701
|
children: label
|
|
410
|
-
})
|
|
702
|
+
}), /*#__PURE__*/_jsx(ChevronDownIcon, {
|
|
703
|
+
size: 14
|
|
704
|
+
})]
|
|
411
705
|
});
|
|
412
706
|
}
|
|
413
707
|
|
|
@@ -425,6 +719,7 @@ function CalendarGrid({
|
|
|
425
719
|
maxDate,
|
|
426
720
|
weekStartsOn,
|
|
427
721
|
showOutsideDays,
|
|
722
|
+
selectOutsideDays = false,
|
|
428
723
|
locale,
|
|
429
724
|
system
|
|
430
725
|
}) {
|
|
@@ -434,18 +729,9 @@ function CalendarGrid({
|
|
|
434
729
|
* boundaries and the day numbers differ — so the walk itself is the same
|
|
435
730
|
* either way and only where it starts moves.
|
|
436
731
|
*/
|
|
437
|
-
const weeks = useMemo(() =>
|
|
438
|
-
const first = startOfCalendarMonth(month, system, locale);
|
|
439
|
-
const lead = (first.getDay() - weekStartsOn + 7) % 7;
|
|
440
|
-
const start = addDays(first, -lead);
|
|
441
|
-
return Array.from({
|
|
442
|
-
length: 6
|
|
443
|
-
}, (_unusedWeek, week) => Array.from({
|
|
444
|
-
length: 7
|
|
445
|
-
}, (_unusedDay, day) => addDays(start, week * 7 + day)));
|
|
446
|
-
}, [month, weekStartsOn, system, locale]);
|
|
732
|
+
const weeks = useMemo(() => monthGrid(month, weekStartsOn, system, locale), [month, weekStartsOn, system, locale]);
|
|
447
733
|
const headings = useMemo(() => weekdayNames(locale, weekStartsOn), [locale, weekStartsOn]);
|
|
448
|
-
const today =
|
|
734
|
+
const today = useToday();
|
|
449
735
|
const range = mode === 'range' ? value : undefined;
|
|
450
736
|
const multiple = mode === 'multiple' ? value ?? [] : [];
|
|
451
737
|
const single = mode === 'single' ? value : undefined;
|
|
@@ -475,22 +761,41 @@ function CalendarGrid({
|
|
|
475
761
|
className: "h-10 flex-1"
|
|
476
762
|
}, dayIndex);
|
|
477
763
|
}
|
|
478
|
-
const
|
|
764
|
+
const isStart = mode === 'range' && isSameDay(date, range?.from);
|
|
765
|
+
const isEnd = mode === 'range' && isSameDay(date, range?.to);
|
|
766
|
+
const selected = mode === 'range' ? isStart || isEnd : mode === 'multiple' ? multiple.some(picked => isSameDay(picked, date)) : isSameDay(date, single);
|
|
767
|
+
|
|
768
|
+
/*
|
|
769
|
+
* Inclusive of both ends, unlike the old middles-only rule. An end
|
|
770
|
+
* has to carry its half of the band or there is a gap between the
|
|
771
|
+
* disc and the run beside it — which is precisely what made a range
|
|
772
|
+
* read as two discs with a stripe floating between them.
|
|
773
|
+
*/
|
|
774
|
+
const inRange = !!range?.to && isWithin(date, range.from, range.to);
|
|
479
775
|
|
|
480
|
-
|
|
481
|
-
|
|
776
|
+
/*
|
|
777
|
+
* Whether the band carries on past this cell's edge into the one
|
|
778
|
+
* beside it. It stops at an end of the range, and at the edge of a
|
|
779
|
+
* row — a range over a weekend closes on Saturday and opens again
|
|
780
|
+
* on Sunday rather than trailing into the gap between the rows.
|
|
781
|
+
*/
|
|
782
|
+
const openStart = inRange && !isStart && dayIndex > 0;
|
|
783
|
+
const openEnd = inRange && !isEnd && dayIndex < 6;
|
|
784
|
+
|
|
785
|
+
// A neighbouring month's day is drawn, not offered. Reaching into
|
|
786
|
+
// July from June is what the arrows are for.
|
|
787
|
+
const ruledOut = isDisabled(date, disabled, minDate, maxDate) || outside && !selectOutsideDays;
|
|
482
788
|
return /*#__PURE__*/_jsx(CalendarDay, {
|
|
483
789
|
date: date,
|
|
484
790
|
outside: outside,
|
|
485
791
|
selected: selected,
|
|
486
792
|
inRange: inRange,
|
|
793
|
+
rangeStart: isStart,
|
|
794
|
+
rangeEnd: isEnd,
|
|
487
795
|
today: isSameDay(date, today),
|
|
488
|
-
disabled:
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
,
|
|
492
|
-
openStart: inRange && dayIndex > 0,
|
|
493
|
-
openEnd: inRange && dayIndex < 6,
|
|
796
|
+
disabled: ruledOut,
|
|
797
|
+
openStart: openStart,
|
|
798
|
+
openEnd: openEnd,
|
|
494
799
|
locale: locale,
|
|
495
800
|
system: system,
|
|
496
801
|
onPress: () => onSelect(date)
|
|
@@ -505,6 +810,8 @@ function CalendarDay({
|
|
|
505
810
|
outside,
|
|
506
811
|
selected,
|
|
507
812
|
inRange,
|
|
813
|
+
rangeStart = false,
|
|
814
|
+
rangeEnd = false,
|
|
508
815
|
today,
|
|
509
816
|
disabled,
|
|
510
817
|
openStart,
|
|
@@ -518,8 +825,25 @@ function CalendarDay({
|
|
|
518
825
|
today: today && !selected,
|
|
519
826
|
outside,
|
|
520
827
|
disabled,
|
|
521
|
-
inRange
|
|
828
|
+
fadedBand: disabled && inRange
|
|
522
829
|
});
|
|
830
|
+
|
|
831
|
+
/*
|
|
832
|
+
* An end of the range fills half its cell, from the centre outwards towards
|
|
833
|
+
* the rest of the range; every other day in it fills the whole cell. Half a
|
|
834
|
+
* cell is what puts the band underneath the disc rather than beside it — the
|
|
835
|
+
* disc is centred, so a band starting at the centre emerges from behind it
|
|
836
|
+
* and the two read as one shape. A range of one day gets both halves and so
|
|
837
|
+
* no band at all, which is right: there is nothing to span.
|
|
838
|
+
*/
|
|
839
|
+
const bandStyle = inRange ? {
|
|
840
|
+
left: rangeStart ? '50%' : 0,
|
|
841
|
+
right: rangeEnd ? '50%' : 0,
|
|
842
|
+
borderTopLeftRadius: openStart ? 0 : DAY_RADIUS,
|
|
843
|
+
borderBottomLeftRadius: openStart ? 0 : DAY_RADIUS,
|
|
844
|
+
borderTopRightRadius: openEnd ? 0 : DAY_RADIUS,
|
|
845
|
+
borderBottomRightRadius: openEnd ? 0 : DAY_RADIUS
|
|
846
|
+
} : null;
|
|
523
847
|
return /*#__PURE__*/_jsxs(Pressable, {
|
|
524
848
|
disabled: disabled,
|
|
525
849
|
onPress: onPress,
|
|
@@ -529,28 +853,22 @@ function CalendarDay({
|
|
|
529
853
|
selected,
|
|
530
854
|
disabled
|
|
531
855
|
},
|
|
532
|
-
className:
|
|
533
|
-
children: [
|
|
534
|
-
className:
|
|
535
|
-
style:
|
|
536
|
-
left: openStart ? 0 : '10%',
|
|
537
|
-
right: openEnd ? 0 : '10%',
|
|
538
|
-
borderTopLeftRadius: openStart ? 0 : 999,
|
|
539
|
-
borderBottomLeftRadius: openStart ? 0 : 999,
|
|
540
|
-
borderTopRightRadius: openEnd ? 0 : 999,
|
|
541
|
-
borderBottomRightRadius: openEnd ? 0 : 999
|
|
542
|
-
}
|
|
856
|
+
className: styles.cell(),
|
|
857
|
+
children: [bandStyle ? /*#__PURE__*/_jsx(View, {
|
|
858
|
+
className: styles.band(),
|
|
859
|
+
style: bandStyle
|
|
543
860
|
}) : null, /*#__PURE__*/_jsx(View, {
|
|
544
|
-
className:
|
|
861
|
+
className: styles.disc(),
|
|
545
862
|
children: /*#__PURE__*/_jsx(Text, {
|
|
546
|
-
|
|
547
|
-
className: cn(styles.label()),
|
|
863
|
+
className: styles.label(),
|
|
548
864
|
children: calendarDayNumber(date, system, locale)
|
|
549
865
|
})
|
|
550
866
|
})]
|
|
551
867
|
});
|
|
552
868
|
}
|
|
553
869
|
export const Calendar = Object.assign(CalendarRoot, {
|
|
870
|
+
Header: CalendarHeader,
|
|
871
|
+
Nav: CalendarNav,
|
|
554
872
|
Grid: CalendarGrid,
|
|
555
873
|
Day: CalendarDay
|
|
556
874
|
});
|