@xeonr/platform-ui 1.3.1 → 1.4.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/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -1
- package/dist/kit/Anchored.d.ts +13 -2
- package/dist/kit/Anchored.d.ts.map +1 -1
- package/dist/kit/Anchored.js +47 -18
- package/dist/kit/Anchored.js.map +1 -1
- package/dist/kit/Badge.d.ts +1 -0
- package/dist/kit/Badge.d.ts.map +1 -1
- package/dist/kit/Badge.js +14 -0
- package/dist/kit/Badge.js.map +1 -1
- package/dist/kit/Button.d.ts +8 -2
- package/dist/kit/Button.d.ts.map +1 -1
- package/dist/kit/Button.js +17 -3
- package/dist/kit/Button.js.map +1 -1
- package/dist/kit/Chip.d.ts +6 -0
- package/dist/kit/Chip.d.ts.map +1 -1
- package/dist/kit/Chip.js +2 -1
- package/dist/kit/Chip.js.map +1 -1
- package/dist/kit/Color.d.ts +69 -0
- package/dist/kit/Color.d.ts.map +1 -0
- package/dist/kit/Color.js +150 -0
- package/dist/kit/Color.js.map +1 -0
- package/dist/kit/Combobox.d.ts +5 -1
- package/dist/kit/Combobox.d.ts.map +1 -1
- package/dist/kit/Combobox.js +39 -28
- package/dist/kit/Combobox.js.map +1 -1
- package/dist/kit/Controls.d.ts +184 -0
- package/dist/kit/Controls.d.ts.map +1 -0
- package/dist/kit/Controls.js +344 -0
- package/dist/kit/Controls.js.map +1 -0
- package/dist/kit/DatePicker.d.ts +125 -0
- package/dist/kit/DatePicker.d.ts.map +1 -0
- package/dist/kit/DatePicker.js +438 -0
- package/dist/kit/DatePicker.js.map +1 -0
- package/dist/kit/Dropzone.d.ts +41 -0
- package/dist/kit/Dropzone.d.ts.map +1 -0
- package/dist/kit/Dropzone.js +118 -0
- package/dist/kit/Dropzone.js.map +1 -0
- package/dist/kit/Form.d.ts +86 -13
- package/dist/kit/Form.d.ts.map +1 -1
- package/dist/kit/Form.js +124 -13
- package/dist/kit/Form.js.map +1 -1
- package/dist/kit/Icon.d.ts +4 -0
- package/dist/kit/Icon.d.ts.map +1 -1
- package/dist/kit/Icon.js +5 -1
- package/dist/kit/Icon.js.map +1 -1
- package/dist/kit/List.d.ts +55 -8
- package/dist/kit/List.d.ts.map +1 -1
- package/dist/kit/List.js +43 -6
- package/dist/kit/List.js.map +1 -1
- package/dist/kit/Menu.d.ts +71 -9
- package/dist/kit/Menu.d.ts.map +1 -1
- package/dist/kit/Menu.js +119 -21
- package/dist/kit/Menu.js.map +1 -1
- package/dist/kit/Modal.d.ts +37 -4
- package/dist/kit/Modal.d.ts.map +1 -1
- package/dist/kit/Modal.js +42 -14
- package/dist/kit/Modal.js.map +1 -1
- package/dist/kit/MultiCombobox.d.ts +48 -1
- package/dist/kit/MultiCombobox.d.ts.map +1 -1
- package/dist/kit/MultiCombobox.js +100 -27
- package/dist/kit/MultiCombobox.js.map +1 -1
- package/dist/kit/Picker.d.ts +6 -1
- package/dist/kit/Picker.d.ts.map +1 -1
- package/dist/kit/Picker.js +10 -5
- package/dist/kit/Picker.js.map +1 -1
- package/dist/kit/Popover.d.ts +13 -1
- package/dist/kit/Popover.d.ts.map +1 -1
- package/dist/kit/Popover.js +31 -9
- package/dist/kit/Popover.js.map +1 -1
- package/dist/kit/Skeleton.d.ts +44 -3
- package/dist/kit/Skeleton.d.ts.map +1 -1
- package/dist/kit/Skeleton.js +39 -1
- package/dist/kit/Skeleton.js.map +1 -1
- package/dist/kit/Stepper.d.ts +33 -0
- package/dist/kit/Stepper.d.ts.map +1 -0
- package/dist/kit/Stepper.js +97 -0
- package/dist/kit/Stepper.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useId, useRef, useState } from "react";
|
|
3
|
+
import styled, { css } from "styled-components";
|
|
4
|
+
import { v } from "../theme/tokens.js";
|
|
5
|
+
import { Icon } from "./Icon.js";
|
|
6
|
+
import { IconButton } from "./Button.js";
|
|
7
|
+
import { Anchored } from "./Anchored.js";
|
|
8
|
+
import { useEscapeLayer } from "./layers.js";
|
|
9
|
+
import { useField } from "./Form.js";
|
|
10
|
+
import { chipCss } from "./Chip.js";
|
|
11
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
12
|
+
/** The local calendar day a Date falls on, as `YYYY-MM-DD`. */
|
|
13
|
+
export function toDayKey(d) {
|
|
14
|
+
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
15
|
+
}
|
|
16
|
+
/** `YYYY-MM-DD` as local midnight, or null if it is not one. Any other Date-parsable string is read and truncated to its local day. */
|
|
17
|
+
export function fromDayKey(s) {
|
|
18
|
+
if (!s)
|
|
19
|
+
return null;
|
|
20
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(s);
|
|
21
|
+
if (m)
|
|
22
|
+
return new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));
|
|
23
|
+
const d = new Date(s);
|
|
24
|
+
return Number.isNaN(+d) ? null : new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
25
|
+
}
|
|
26
|
+
const asKey = (d) => d === undefined ? null : typeof d === "string" ? (fromDayKey(d) ? toDayKey(fromDayKey(d)) : null) : toDayKey(d);
|
|
27
|
+
const addDays = (k, n) => {
|
|
28
|
+
const d = fromDayKey(k);
|
|
29
|
+
return toDayKey(new Date(d.getFullYear(), d.getMonth(), d.getDate() + n));
|
|
30
|
+
};
|
|
31
|
+
const addMonths = (k, n) => {
|
|
32
|
+
const d = fromDayKey(k);
|
|
33
|
+
const target = new Date(d.getFullYear(), d.getMonth() + n, 1);
|
|
34
|
+
const last = new Date(target.getFullYear(), target.getMonth() + 1, 0).getDate();
|
|
35
|
+
return toDayKey(new Date(target.getFullYear(), target.getMonth(), Math.min(d.getDate(), last)));
|
|
36
|
+
};
|
|
37
|
+
const monthOf = (k) => k.slice(0, 7);
|
|
38
|
+
/* ------------------------------------------------------------------ Calendar */
|
|
39
|
+
const CalWrap = styled.div `
|
|
40
|
+
width: 252px;
|
|
41
|
+
user-select: none;
|
|
42
|
+
`;
|
|
43
|
+
const CalHead = styled.div `
|
|
44
|
+
display: flex;
|
|
45
|
+
align-items: center;
|
|
46
|
+
justify-content: space-between;
|
|
47
|
+
margin-bottom: 6px;
|
|
48
|
+
font-size: 12.5px;
|
|
49
|
+
font-weight: 600;
|
|
50
|
+
color: ${v.text};
|
|
51
|
+
button:disabled { opacity: 0.35; cursor: not-allowed; background: transparent; }
|
|
52
|
+
`;
|
|
53
|
+
const Week = styled.div `
|
|
54
|
+
display: grid;
|
|
55
|
+
grid-template-columns: repeat(7, 36px);
|
|
56
|
+
`;
|
|
57
|
+
const Weekday = styled.span `
|
|
58
|
+
height: 26px;
|
|
59
|
+
display: grid;
|
|
60
|
+
place-items: center;
|
|
61
|
+
font-size: 10.5px;
|
|
62
|
+
font-weight: 600;
|
|
63
|
+
color: ${v.faint};
|
|
64
|
+
`;
|
|
65
|
+
const Cell = styled.div `
|
|
66
|
+
padding: 1px 0;
|
|
67
|
+
${(p) => p.$band === "mid" && css `background: ${v.brand12};`}
|
|
68
|
+
${(p) => p.$band === "start" && css `background: linear-gradient(to right, transparent 50%, ${v.brand12} 50%);`}
|
|
69
|
+
${(p) => p.$band === "end" && css `background: linear-gradient(to left, transparent 50%, ${v.brand12} 50%);`}
|
|
70
|
+
`;
|
|
71
|
+
const Day = styled.button `
|
|
72
|
+
width: 36px;
|
|
73
|
+
height: 32px;
|
|
74
|
+
display: grid;
|
|
75
|
+
place-items: center;
|
|
76
|
+
border-radius: ${v.rCtl};
|
|
77
|
+
font-size: 12px;
|
|
78
|
+
font-variant-numeric: tabular-nums;
|
|
79
|
+
color: ${(p) => (p.$outside ? v.faint : v.text)};
|
|
80
|
+
border: 1px solid ${(p) => (p.$today ? v.line2 : "transparent")};
|
|
81
|
+
transition: background 0.12s ease;
|
|
82
|
+
&:hover:not(:disabled) { background: ${v.hover}; }
|
|
83
|
+
&:disabled { opacity: 0.35; cursor: not-allowed; text-decoration: line-through; }
|
|
84
|
+
&:focus-visible { box-shadow: ${v.ring}; border-radius: ${v.rCtl}; }
|
|
85
|
+
${(p) => p.$edge &&
|
|
86
|
+
css `
|
|
87
|
+
background: ${v.grad};
|
|
88
|
+
color: ${v.onBrand};
|
|
89
|
+
border-color: transparent;
|
|
90
|
+
&:hover:not(:disabled) { background: ${v.grad}; filter: brightness(1.08); }
|
|
91
|
+
`}
|
|
92
|
+
`;
|
|
93
|
+
/**
|
|
94
|
+
* Calendar: one month of days to pick from — one day, or a range. A range
|
|
95
|
+
* takes two clicks in either order (the second may be the same day, for a
|
|
96
|
+
* one-day range) and previews itself under the pointer in between. Keyboard
|
|
97
|
+
* as a date grid: arrows move a day or a week, Page Up/Down a month (with
|
|
98
|
+
* Shift, a year), Home/End the week's ends, Enter or Space picks.
|
|
99
|
+
*/
|
|
100
|
+
export function Calendar(props) {
|
|
101
|
+
const { min, max, isDisabled, weekStartsOn = 1, locale, autoFocus } = props;
|
|
102
|
+
const range = props.mode === "range";
|
|
103
|
+
const from = range ? props.value[0] : props.value;
|
|
104
|
+
const to = range ? props.value[1] : props.value;
|
|
105
|
+
const lo = asKey(min);
|
|
106
|
+
const hi = asKey(max);
|
|
107
|
+
const today = toDayKey(new Date());
|
|
108
|
+
const off = (k) => (!!lo && k < lo) || (!!hi && k > hi) || !!isDisabled?.(k);
|
|
109
|
+
const initial = to ?? from ?? (hi && today > hi ? hi : lo && today < lo ? lo : today);
|
|
110
|
+
const [focus, setFocus] = useState(initial);
|
|
111
|
+
const [hover, setHover] = useState(null);
|
|
112
|
+
const month = monthOf(focus);
|
|
113
|
+
const grid = useRef(null);
|
|
114
|
+
const keyed = useRef(!!autoFocus);
|
|
115
|
+
// the focused day follows the keyboard; the DOM focus follows it once the keyboard has been used
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
if (!keyed.current)
|
|
118
|
+
return;
|
|
119
|
+
grid.current?.querySelector(`[data-day="${focus}"]`)?.focus();
|
|
120
|
+
}, [focus]);
|
|
121
|
+
const first = fromDayKey(`${month}-01`);
|
|
122
|
+
const lead = (first.getDay() - weekStartsOn + 7) % 7;
|
|
123
|
+
const start = toDayKey(new Date(first.getFullYear(), first.getMonth(), 1 - lead));
|
|
124
|
+
const weeks = Array.from({ length: 6 }, (_, w) => Array.from({ length: 7 }, (_, d) => addDays(start, w * 7 + d)));
|
|
125
|
+
const weekdays = weeks[0].map((k) => fromDayKey(k).toLocaleDateString(locale, { weekday: "short" }).slice(0, 2));
|
|
126
|
+
const title = first.toLocaleDateString(locale, { month: "long", year: "numeric" });
|
|
127
|
+
const prevMonthLast = toDayKey(new Date(first.getFullYear(), first.getMonth(), 0));
|
|
128
|
+
const nextMonthFirst = toDayKey(new Date(first.getFullYear(), first.getMonth() + 1, 1));
|
|
129
|
+
const canPrev = !lo || prevMonthLast >= lo;
|
|
130
|
+
const canNext = !hi || nextMonthFirst <= hi;
|
|
131
|
+
const pick = (k) => {
|
|
132
|
+
if (off(k))
|
|
133
|
+
return;
|
|
134
|
+
setFocus(k);
|
|
135
|
+
if (props.mode !== "range") {
|
|
136
|
+
props.onChange(k);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const [a, b] = props.value;
|
|
140
|
+
if (!a || b)
|
|
141
|
+
props.onChange([k, null]);
|
|
142
|
+
else
|
|
143
|
+
props.onChange(k < a ? [k, a] : [a, k]);
|
|
144
|
+
};
|
|
145
|
+
// the band a range draws, previewed under the pointer while half-picked
|
|
146
|
+
const bandTo = range && from && !to && hover ? hover : to;
|
|
147
|
+
const [bLo, bHi] = from && bandTo ? (bandTo < from ? [bandTo, from] : [from, bandTo]) : [null, null];
|
|
148
|
+
const onKey = (e) => {
|
|
149
|
+
const step = {
|
|
150
|
+
ArrowLeft: () => addDays(focus, -1),
|
|
151
|
+
ArrowRight: () => addDays(focus, 1),
|
|
152
|
+
ArrowUp: () => addDays(focus, -7),
|
|
153
|
+
ArrowDown: () => addDays(focus, 7),
|
|
154
|
+
PageUp: () => addMonths(focus, e.shiftKey ? -12 : -1),
|
|
155
|
+
PageDown: () => addMonths(focus, e.shiftKey ? 12 : 1),
|
|
156
|
+
Home: () => addDays(focus, -((fromDayKey(focus).getDay() - weekStartsOn + 7) % 7)),
|
|
157
|
+
End: () => addDays(focus, 6 - ((fromDayKey(focus).getDay() - weekStartsOn + 7) % 7)),
|
|
158
|
+
};
|
|
159
|
+
const go = step[e.key];
|
|
160
|
+
if (go) {
|
|
161
|
+
e.preventDefault();
|
|
162
|
+
keyed.current = true;
|
|
163
|
+
let next = go();
|
|
164
|
+
if (lo && next < lo)
|
|
165
|
+
next = lo;
|
|
166
|
+
if (hi && next > hi)
|
|
167
|
+
next = hi;
|
|
168
|
+
setFocus(next);
|
|
169
|
+
if (range && from && !to)
|
|
170
|
+
setHover(next);
|
|
171
|
+
}
|
|
172
|
+
else if (e.key === "Enter" || e.key === " ") {
|
|
173
|
+
e.preventDefault();
|
|
174
|
+
pick(focus);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
return (_jsxs(CalWrap, { children: [_jsxs(CalHead, { children: [_jsx(IconButton, { "$size": 26, "aria-label": "Previous month", disabled: !canPrev, onClick: () => setFocus(addMonths(focus, -1) < (lo ?? "") ? lo : addMonths(focus, -1)), children: _jsx(Icon, { name: "chevron-left" }) }), _jsx("span", { "aria-live": "polite", children: title }), _jsx(IconButton, { "$size": 26, "aria-label": "Next month", disabled: !canNext, onClick: () => setFocus(hi && addMonths(focus, 1) > hi ? hi : addMonths(focus, 1)), children: _jsx(Icon, { name: "chevron-right" }) })] }), _jsxs("div", { ref: grid, role: "grid", "aria-label": title, "aria-multiselectable": range || undefined, onKeyDown: onKey, onMouseLeave: () => setHover(null), children: [_jsx(Week, { role: "row", children: weekdays.map((w, i) => _jsx(Weekday, { role: "columnheader", children: w }, i)) }), weeks.map((week) => (_jsx(Week, { role: "row", children: week.map((k) => {
|
|
178
|
+
const edge = k === from || k === to;
|
|
179
|
+
const inBand = !!bLo && !!bHi && k >= bLo && k <= bHi && bLo !== bHi;
|
|
180
|
+
const band = !inBand ? "none" : k === bLo ? "start" : k === bHi ? "end" : "mid";
|
|
181
|
+
const selected = edge || (!!from && !!to && k > from && k < to);
|
|
182
|
+
const date = fromDayKey(k);
|
|
183
|
+
return (_jsx(Cell, { role: "gridcell", "aria-selected": selected, "$band": band, children: _jsx(Day, { type: "button", "data-day": k, tabIndex: k === focus ? 0 : -1, disabled: off(k), "aria-label": date.toLocaleDateString(locale, { weekday: "long", day: "numeric", month: "long", year: "numeric" }), "aria-current": k === today ? "date" : undefined, "$edge": edge, "$outside": monthOf(k) !== month, "$today": k === today, onMouseEnter: () => setHover(k), onFocus: () => setFocus(k), onClick: () => pick(k), children: date.getDate() }) }, k));
|
|
184
|
+
}) }, week[0])))] })] }));
|
|
185
|
+
}
|
|
186
|
+
/* ------------------------------------------------------------------ DatePicker */
|
|
187
|
+
const FieldBox = styled.div `
|
|
188
|
+
display: flex;
|
|
189
|
+
align-items: center;
|
|
190
|
+
width: 100%;
|
|
191
|
+
min-width: 0;
|
|
192
|
+
height: 32px;
|
|
193
|
+
border-radius: ${v.rCtl};
|
|
194
|
+
background: ${v.field};
|
|
195
|
+
border: 1px solid ${(p) => (p.$invalid ? v.danger : p.$open ? v.brand55 : v.fieldLine)};
|
|
196
|
+
${(p) => p.$open && css `box-shadow: 0 0 0 3px ${p.$invalid ? v.dangerBg : v.brand08};`}
|
|
197
|
+
${(p) => p.$disabled && css `opacity: 0.55;`}
|
|
198
|
+
&:focus-within { border-color: ${(p) => (p.$invalid ? v.danger : v.brand55)}; }
|
|
199
|
+
`;
|
|
200
|
+
const FieldBtn = styled.button `
|
|
201
|
+
flex: 1 1 auto;
|
|
202
|
+
min-width: 0;
|
|
203
|
+
height: 100%;
|
|
204
|
+
display: flex;
|
|
205
|
+
align-items: center;
|
|
206
|
+
gap: 8px;
|
|
207
|
+
padding: 0 10px;
|
|
208
|
+
text-align: left;
|
|
209
|
+
font-size: 12.5px;
|
|
210
|
+
color: ${(p) => (p.$placeholder ? v.faint : v.text)};
|
|
211
|
+
&:focus-visible { box-shadow: none; }
|
|
212
|
+
&:disabled { cursor: not-allowed; }
|
|
213
|
+
> .val { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
214
|
+
> svg { flex: none; color: ${v.faint}; font-size: 12px; }
|
|
215
|
+
`;
|
|
216
|
+
const ChipBox = styled.span `
|
|
217
|
+
${chipCss}
|
|
218
|
+
padding: 0;
|
|
219
|
+
gap: 0;
|
|
220
|
+
cursor: default;
|
|
221
|
+
&:has(button:focus-visible) { box-shadow: ${v.ring}; }
|
|
222
|
+
`;
|
|
223
|
+
const ChipBtn = styled.button `
|
|
224
|
+
display: inline-flex;
|
|
225
|
+
align-items: center;
|
|
226
|
+
gap: 6px;
|
|
227
|
+
height: 100%;
|
|
228
|
+
padding: 0 10px;
|
|
229
|
+
border-radius: 999px;
|
|
230
|
+
font: inherit;
|
|
231
|
+
color: inherit;
|
|
232
|
+
&:focus-visible { box-shadow: none; }
|
|
233
|
+
&:disabled { cursor: not-allowed; }
|
|
234
|
+
svg { font-size: 11px; }
|
|
235
|
+
`;
|
|
236
|
+
const ClearBtn = styled.button `
|
|
237
|
+
flex: none;
|
|
238
|
+
display: inline-grid;
|
|
239
|
+
place-items: center;
|
|
240
|
+
width: 22px;
|
|
241
|
+
height: 22px;
|
|
242
|
+
margin: ${(p) => (p.$chip ? "0 3px 0 -6px" : "0 5px 0 0")};
|
|
243
|
+
border-radius: ${(p) => (p.$chip ? "50%" : "6px")};
|
|
244
|
+
color: ${v.faint};
|
|
245
|
+
font-size: 10px;
|
|
246
|
+
&:hover { color: ${v.text}; background: ${v.hover}; }
|
|
247
|
+
`;
|
|
248
|
+
const Panel = styled.div `
|
|
249
|
+
display: flex;
|
|
250
|
+
align-items: flex-start;
|
|
251
|
+
gap: 12px;
|
|
252
|
+
padding: 10px 12px 12px;
|
|
253
|
+
background: ${v.surface};
|
|
254
|
+
border: 1px solid ${v.line2};
|
|
255
|
+
border-radius: ${v.rCard};
|
|
256
|
+
box-shadow: ${v.elev};
|
|
257
|
+
max-width: calc(100vw - 16px);
|
|
258
|
+
overflow-x: auto;
|
|
259
|
+
> .side {
|
|
260
|
+
align-self: stretch;
|
|
261
|
+
border-left: 1px solid ${v.line};
|
|
262
|
+
padding-left: 12px;
|
|
263
|
+
min-width: 160px;
|
|
264
|
+
}
|
|
265
|
+
`;
|
|
266
|
+
const Presets = styled.div `
|
|
267
|
+
display: flex;
|
|
268
|
+
flex-direction: column;
|
|
269
|
+
gap: 2px;
|
|
270
|
+
min-width: 112px;
|
|
271
|
+
padding-right: 10px;
|
|
272
|
+
border-right: 1px solid ${v.line};
|
|
273
|
+
align-self: stretch;
|
|
274
|
+
> button {
|
|
275
|
+
height: 26px;
|
|
276
|
+
padding: 0 8px;
|
|
277
|
+
border-radius: ${v.rCtl};
|
|
278
|
+
font-size: 11.5px;
|
|
279
|
+
font-weight: 600;
|
|
280
|
+
text-align: left;
|
|
281
|
+
color: ${v.muted};
|
|
282
|
+
white-space: nowrap;
|
|
283
|
+
&:hover { background: ${v.hover}; color: ${v.text}; }
|
|
284
|
+
&[aria-pressed="true"] { background: ${v.brand12}; color: ${v.brand}; }
|
|
285
|
+
}
|
|
286
|
+
`;
|
|
287
|
+
const Foot = styled.div `
|
|
288
|
+
display: flex;
|
|
289
|
+
justify-content: space-between;
|
|
290
|
+
align-items: center;
|
|
291
|
+
margin-top: 8px;
|
|
292
|
+
font-size: 11px;
|
|
293
|
+
color: ${v.faint};
|
|
294
|
+
> button { font-size: 11.5px; font-weight: 600; color: ${v.muted}; padding: 3px 6px; border-radius: 6px; }
|
|
295
|
+
> button:hover { color: ${v.text}; background: ${v.hover}; }
|
|
296
|
+
`;
|
|
297
|
+
const dayLabel = (k, locale) => fromDayKey(k).toLocaleDateString(locale, { day: "numeric", month: "short", year: "numeric" });
|
|
298
|
+
const monthLabel = (d, locale, year = true) => d.toLocaleDateString(locale, year ? { month: "long", year: "numeric" } : { month: "long" });
|
|
299
|
+
/** "March 2026" / "March – May 2026" for a range of whole calendar months, else null. */
|
|
300
|
+
function describeMonths(a, b, locale) {
|
|
301
|
+
const from = fromDayKey(a);
|
|
302
|
+
const to = fromDayKey(b);
|
|
303
|
+
if (!from || !to || from > to || from.getDate() !== 1)
|
|
304
|
+
return null;
|
|
305
|
+
// the day after `to` is the 1st: `to` is the last day of its month
|
|
306
|
+
if (new Date(to.getFullYear(), to.getMonth(), to.getDate() + 1).getDate() !== 1)
|
|
307
|
+
return null;
|
|
308
|
+
const sameYear = from.getFullYear() === to.getFullYear();
|
|
309
|
+
if (sameYear && from.getMonth() === to.getMonth())
|
|
310
|
+
return monthLabel(from, locale);
|
|
311
|
+
return `${monthLabel(from, locale, !sameYear)} – ${monthLabel(to, locale)}`;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* The default caption for a range: "3 Mar 2026 – 9 Mar 2026", "From 3 Mar 2026",
|
|
315
|
+
* "Until 9 Mar 2026". The second argument is a locale or options; with
|
|
316
|
+
* `{ months: true }` a whole calendar month reads "March 2026".
|
|
317
|
+
*/
|
|
318
|
+
export function describeDateRange([a, b], opts) {
|
|
319
|
+
const { locale, months } = typeof opts === "string" ? { locale: opts, months: false } : (opts ?? {});
|
|
320
|
+
if (a && b && months) {
|
|
321
|
+
const m = describeMonths(a, b, locale);
|
|
322
|
+
if (m)
|
|
323
|
+
return m;
|
|
324
|
+
}
|
|
325
|
+
if (a && b)
|
|
326
|
+
return a === b ? dayLabel(a, locale) : `${dayLabel(a, locale)} – ${dayLabel(b, locale)}`;
|
|
327
|
+
if (a)
|
|
328
|
+
return `From ${dayLabel(a, locale)}`;
|
|
329
|
+
if (b)
|
|
330
|
+
return `Until ${dayLabel(b, locale)}`;
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
const presetValue = (p) => (typeof p.value === "function" ? p.value() : p.value);
|
|
334
|
+
/**
|
|
335
|
+
* DatePicker: a day, or a range of days, picked from a Calendar that opens
|
|
336
|
+
* from a trigger. The `field` variant is a form control (it goes red inside a
|
|
337
|
+
* Field with an `error`); the `chip` variant sits in a filter bar and lights
|
|
338
|
+
* while a value is set. `presets` are the shortcuts a range picker wants
|
|
339
|
+
* ("Last 7 days"). The calendar portals to document.body, flips near a viewport
|
|
340
|
+
* edge, and Escape closes it before any modal it sits in.
|
|
341
|
+
*
|
|
342
|
+
* A range is held inside the picker while it is half-picked and handed up
|
|
343
|
+
* only once both ends are chosen, so a list filtered on it does not refetch
|
|
344
|
+
* for a range that is still being drawn.
|
|
345
|
+
*/
|
|
346
|
+
export function DatePicker(props) {
|
|
347
|
+
const { clearable = true, disabled, label, id, variant = "field", icon = "calendar", side, align, aside, name, locale } = props;
|
|
348
|
+
const range = props.mode === "range";
|
|
349
|
+
const field = useField();
|
|
350
|
+
const [open, setOpen] = useState(false);
|
|
351
|
+
const [draft, setDraft] = useState([null, null]);
|
|
352
|
+
const wrap = useRef(null);
|
|
353
|
+
const layer = useRef(null);
|
|
354
|
+
const trigger = useRef(null);
|
|
355
|
+
const panelId = useId();
|
|
356
|
+
const empty = range ? !props.value[0] && !props.value[1] : !props.value;
|
|
357
|
+
const caption = empty
|
|
358
|
+
? (props.placeholder ?? (range ? "Any time" : "Pick a date"))
|
|
359
|
+
: props.mode === "range"
|
|
360
|
+
? (props.format ? props.format(props.value) : describeDateRange(props.value, { locale, months: props.months }))
|
|
361
|
+
: (props.format ? props.format(props.value) : dayLabel(props.value, locale));
|
|
362
|
+
// focus goes back to the trigger after the panel has gone (asked for here, done in an effect)
|
|
363
|
+
const [refocus, setRefocus] = useState(0);
|
|
364
|
+
useEffect(() => { if (refocus)
|
|
365
|
+
trigger.current?.focus(); }, [refocus]);
|
|
366
|
+
const close = (back) => {
|
|
367
|
+
setOpen(false);
|
|
368
|
+
if (back)
|
|
369
|
+
setRefocus((n) => n + 1);
|
|
370
|
+
};
|
|
371
|
+
const show = () => {
|
|
372
|
+
if (disabled)
|
|
373
|
+
return;
|
|
374
|
+
if (props.mode === "range")
|
|
375
|
+
setDraft(props.value);
|
|
376
|
+
setOpen(true);
|
|
377
|
+
};
|
|
378
|
+
useEscapeLayer(open, () => close(true));
|
|
379
|
+
useEffect(() => {
|
|
380
|
+
if (!open)
|
|
381
|
+
return;
|
|
382
|
+
const onDown = (e) => {
|
|
383
|
+
const t = e.target;
|
|
384
|
+
if (!wrap.current?.contains(t) && !layer.current?.contains(t))
|
|
385
|
+
setOpen(false);
|
|
386
|
+
};
|
|
387
|
+
document.addEventListener("mousedown", onDown, true);
|
|
388
|
+
return () => document.removeEventListener("mousedown", onDown, true);
|
|
389
|
+
}, [open]);
|
|
390
|
+
const clear = () => {
|
|
391
|
+
if (props.mode === "range")
|
|
392
|
+
props.onChange([null, null]);
|
|
393
|
+
else
|
|
394
|
+
props.onChange(null);
|
|
395
|
+
setDraft([null, null]);
|
|
396
|
+
};
|
|
397
|
+
const common = { min: props.min, max: props.max, isDisabled: props.isDisabled, weekStartsOn: props.weekStartsOn, locale };
|
|
398
|
+
const calendar = props.mode === "range" ? (_jsx(Calendar, { ...common, mode: "range", autoFocus: true, value: draft, onChange: (r) => {
|
|
399
|
+
setDraft(r);
|
|
400
|
+
if (r[0] && r[1]) {
|
|
401
|
+
props.onChange(r);
|
|
402
|
+
close(true);
|
|
403
|
+
}
|
|
404
|
+
} })) : (_jsx(Calendar, { ...common, autoFocus: true, value: props.value, onChange: (d) => { props.onChange(d); close(true); } }));
|
|
405
|
+
const presets = props.presets?.length ? (_jsx(Presets, { role: "group", "aria-label": "Shortcuts", children: props.mode === "range"
|
|
406
|
+
? props.presets.map((p) => {
|
|
407
|
+
const val = presetValue(p);
|
|
408
|
+
return (_jsx("button", { type: "button", "aria-pressed": val[0] === props.value[0] && val[1] === props.value[1], onClick: () => { props.onChange(val); close(true); }, children: p.label }, p.label));
|
|
409
|
+
})
|
|
410
|
+
: props.presets.map((p) => {
|
|
411
|
+
const val = presetValue(p);
|
|
412
|
+
return (_jsx("button", { type: "button", "aria-pressed": val === props.value, onClick: () => { props.onChange(val); close(true); }, children: p.label }, p.label));
|
|
413
|
+
}) })) : null;
|
|
414
|
+
const half = range && open && draft[0] && !draft[1];
|
|
415
|
+
const triggerProps = {
|
|
416
|
+
ref: trigger,
|
|
417
|
+
type: "button",
|
|
418
|
+
id: id,
|
|
419
|
+
disabled,
|
|
420
|
+
"aria-label": label,
|
|
421
|
+
"aria-haspopup": "dialog",
|
|
422
|
+
"aria-expanded": open,
|
|
423
|
+
"aria-controls": open ? panelId : undefined,
|
|
424
|
+
"aria-invalid": field?.invalid || undefined,
|
|
425
|
+
"aria-describedby": field?.describedBy,
|
|
426
|
+
onClick: () => (open ? close(false) : show()),
|
|
427
|
+
onKeyDown: (e) => { if (e.key === "ArrowDown" && !open) {
|
|
428
|
+
e.preventDefault();
|
|
429
|
+
show();
|
|
430
|
+
} },
|
|
431
|
+
};
|
|
432
|
+
const clearBtn = clearable && !empty && !disabled ? (_jsx(ClearBtn, { type: "button", "$chip": variant === "chip", "aria-label": range ? "Clear dates" : "Clear date", onClick: (e) => { e.stopPropagation(); clear(); }, children: _jsx(Icon, { name: "close" }) })) : null;
|
|
433
|
+
const hidden = name !== undefined
|
|
434
|
+
? _jsx("input", { type: "hidden", name: name, value: range ? `${props.value[0] ?? ""}/${props.value[1] ?? ""}` : (props.value ?? "") })
|
|
435
|
+
: null;
|
|
436
|
+
return (_jsxs("div", { ref: wrap, style: { display: variant === "chip" ? "inline-flex" : "block", minWidth: 0 }, children: [variant === "chip" ? (_jsxs(ChipBox, { "$on": !empty || open, children: [_jsxs(ChipBtn, { ...triggerProps, children: [_jsx(Icon, { name: icon }), _jsx("span", { children: caption })] }), clearBtn] })) : (_jsxs(FieldBox, { "$open": open, "$invalid": !!field?.invalid, "$disabled": !!disabled, children: [_jsxs(FieldBtn, { ...triggerProps, "$placeholder": empty, children: [_jsx(Icon, { name: icon }), _jsx("span", { className: "val", children: caption })] }), clearBtn] })), hidden, open ? (_jsx(Anchored, { anchor: wrap, align: align ?? "left", side: side, gap: 5, layerRef: layer, children: _jsxs(Panel, { id: panelId, role: "dialog", "aria-label": label ?? (range ? "Choose dates" : "Choose a date"), children: [presets, _jsxs("div", { children: [calendar, range ? (_jsxs(Foot, { children: [_jsx("span", { "aria-live": "polite", children: half ? "Pick the last day" : draft[0] ? "" : "Pick the first day" }), !empty || draft[0] ? _jsx("button", { type: "button", onClick: () => { clear(); }, children: "Clear" }) : null] })) : null] }), aside ? _jsx("div", { className: "side", children: aside(() => close(true)) }) : null] }) })) : null] }));
|
|
437
|
+
}
|
|
438
|
+
//# sourceMappingURL=DatePicker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DatePicker.js","sourceRoot":"","sources":["../../src/kit/DatePicker.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAsC,MAAM,OAAO,CAAC;AAC/F,OAAO,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,CAAC,EAAE,MAAM,oBAAoB,CAAC;AACvC,OAAO,EAAE,IAAI,EAAiB,MAAM,WAAY,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAc,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAyC,MAAM,eAAgB,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAY,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAY,CAAC;AAgBrC,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAEtD,+DAA+D;AAC/D,MAAM,UAAU,QAAQ,CAAC,CAAO;IAC9B,OAAO,GAAG,CAAC,CAAC,WAAW,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;AAC3E,CAAC;AAED,uIAAuI;AACvI,MAAM,UAAU,UAAU,CAAC,CAA4B;IACrD,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,MAAM,CAAC,GAAG,2BAA2B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9C,IAAI,CAAC;QAAE,OAAO,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AACxF,CAAC;AAED,MAAM,KAAK,GAAG,CAAC,CAA4B,EAAiB,EAAE,CAC5D,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACnH,MAAM,OAAO,GAAG,CAAC,CAAS,EAAE,CAAS,EAAE,EAAE;IACvC,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAE,CAAC;IACzB,OAAO,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;AAC5E,CAAC,CAAC;AACF,MAAM,SAAS,GAAG,CAAC,CAAS,EAAE,CAAS,EAAE,EAAE;IACzC,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAE,CAAC;IACzB,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9D,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;IAChF,OAAO,QAAQ,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,MAAM,CAAC,QAAQ,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AAClG,CAAC,CAAC;AACF,MAAM,OAAO,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAE7C,iFAAiF;AAEjF,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAA;;;CAGzB,CAAC;AAEF,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;WAOf,CAAC,CAAC,IAAI;;CAEhB,CAAC;AAEF,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAA;;;CAGtB,CAAC;AAEF,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAA;;;;;;WAMhB,CAAC,CAAC,KAAK;CACjB,CAAC;AAEF,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAA6C;;IAEhE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,IAAI,GAAG,CAAA,eAAe,CAAC,CAAC,OAAO,GAAG;IAC1D,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,IAAI,GAAG,CAAA,0DAA0D,CAAC,CAAC,OAAO,QAAQ;IAC5G,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,IAAI,GAAG,CAAA,yDAAyD,CAAC,CAAC,OAAO,QAAQ;CAC5G,CAAC;AAEF,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAwD;;;;;mBAK9D,CAAC,CAAC,IAAI;;;WAGd,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;sBAC3B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC;;yCAExB,CAAC,CAAC,KAAK;;kCAEd,CAAC,CAAC,IAAI,oBAAoB,CAAC,CAAC,IAAI;IAC9D,CAAC,CAAC,EAAE,EAAE,CACN,CAAC,CAAC,KAAK;IACP,GAAG,CAAA;oBACa,CAAC,CAAC,IAAI;eACX,CAAC,CAAC,OAAO;;6CAEqB,CAAC,CAAC,IAAI;KAC9C;CACJ,CAAC;AA2BF;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAoB;IAC3C,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,YAAY,GAAG,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IAC5E,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC;IACrC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;IAClD,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;IAChD,MAAM,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;IACtB,MAAM,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;IACtB,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IACnC,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;IAErF,MAAM,OAAO,GAAG,EAAE,IAAI,IAAI,IAAI,CAAC,EAAE,IAAI,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACtF,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAS,OAAO,CAAC,CAAC;IACpD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IACxD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAElC,iGAAiG;IACjG,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,KAAK,CAAC,OAAO;YAAE,OAAO;QAC3B,IAAI,CAAC,OAAO,EAAE,aAAa,CAAoB,cAAc,KAAK,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC;IACnF,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEZ,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,KAAK,KAAK,CAAE,CAAC;IACzC,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,YAAY,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IAClF,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAClH,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAE,CAAC,kBAAkB,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACnH,MAAM,KAAK,GAAG,KAAK,CAAC,kBAAkB,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IACnF,MAAM,aAAa,GAAG,QAAQ,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IACnF,MAAM,cAAc,GAAG,QAAQ,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACxF,MAAM,OAAO,GAAG,CAAC,EAAE,IAAI,aAAa,IAAI,EAAE,CAAC;IAC3C,MAAM,OAAO,GAAG,CAAC,EAAE,IAAI,cAAc,IAAI,EAAE,CAAC;IAE5C,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,EAAE;QACzB,IAAI,GAAG,CAAC,CAAC,CAAC;YAAE,OAAO;QACnB,QAAQ,CAAC,CAAC,CAAC,CAAC;QACZ,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAAC,OAAO;QAAC,CAAC;QAC1D,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC;QAC3B,IAAI,CAAC,CAAC,IAAI,CAAC;YAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;;YAClC,KAAK,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC,CAAC;IAEF,wEAAwE;IACxE,MAAM,MAAM,GAAG,KAAK,IAAI,IAAI,IAAI,CAAC,EAAE,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1D,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAErG,MAAM,KAAK,GAAG,CAAC,CAAgB,EAAE,EAAE;QACjC,MAAM,IAAI,GAAiC;YACzC,SAAS,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YACnC,UAAU,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;YACnC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YACjC,SAAS,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;YAClC,MAAM,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACrD,QAAQ,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YACrD,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAE,CAAC,MAAM,EAAE,GAAG,YAAY,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACnF,GAAG,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,KAAK,CAAE,CAAC,MAAM,EAAE,GAAG,YAAY,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;SACtF,CAAC;QACF,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACvB,IAAI,EAAE,EAAE,CAAC;YACP,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC;YACrB,IAAI,IAAI,GAAG,EAAE,EAAE,CAAC;YAChB,IAAI,EAAE,IAAI,IAAI,GAAG,EAAE;gBAAE,IAAI,GAAG,EAAE,CAAC;YAC/B,IAAI,EAAE,IAAI,IAAI,GAAG,EAAE;gBAAE,IAAI,GAAG,EAAE,CAAC;YAC/B,QAAQ,CAAC,IAAI,CAAC,CAAC;YACf,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,EAAE;gBAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC3C,CAAC;aAAM,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;YAC9C,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,IAAI,CAAC,KAAK,CAAC,CAAC;QACd,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CACL,MAAC,OAAO,eACN,MAAC,OAAO,eACN,KAAC,UAAU,aAAQ,EAAE,gBAAa,gBAAgB,EAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAG,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,YAC5J,KAAC,IAAI,IAAC,IAAI,EAAC,cAAc,GAAG,GACjB,EACb,4BAAgB,QAAQ,YAAE,KAAK,GAAQ,EACvC,KAAC,UAAU,aAAQ,EAAE,gBAAa,YAAY,EAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,YACnJ,KAAC,IAAI,IAAC,IAAI,EAAC,eAAe,GAAG,GAClB,IACL,EACV,eAAK,GAAG,EAAE,IAAI,EAAE,IAAI,EAAC,MAAM,gBAAa,KAAK,0BAAwB,KAAK,IAAI,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,aAC3I,KAAC,IAAI,IAAC,IAAI,EAAC,KAAK,YACb,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAC,OAAO,IAAS,IAAI,EAAC,cAAc,YAAE,CAAC,IAAzB,CAAC,CAAmC,CAAC,GACtE,EACN,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACnB,KAAC,IAAI,IAAe,IAAI,EAAC,KAAK,YAC3B,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;4BACd,MAAM,IAAI,GAAG,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;4BACpC,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG,CAAC;4BACrE,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;4BAChF,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;4BAChE,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,CAAE,CAAC;4BAC5B,OAAO,CACL,KAAC,IAAI,IAAS,IAAI,EAAC,UAAU,mBAAgB,QAAQ,WAAS,IAAI,YAChE,KAAC,GAAG,IACF,IAAI,EAAC,QAAQ,cACH,CAAC,EACX,QAAQ,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAC9B,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,gBACJ,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,kBAClG,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,WACvC,IAAI,cACD,OAAO,CAAC,CAAC,CAAC,KAAK,KAAK,YACtB,CAAC,KAAK,KAAK,EACnB,YAAY,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAC/B,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAC1B,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,YAErB,IAAI,CAAC,OAAO,EAAE,GACX,IAhBG,CAAC,CAiBL,CACR,CAAC;wBACJ,CAAC,CAAC,IA3BO,IAAI,CAAC,CAAC,CAAC,CA4BX,CACR,CAAC,IACE,IACE,CACX,CAAC;AACJ,CAAC;AAED,mFAAmF;AAEnF,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAA2D;;;;;;mBAMnE,CAAC,CAAC,IAAI;gBACT,CAAC,CAAC,KAAK;sBACD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACpF,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAA,yBAAyB,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG;IACpF,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,CAAA,gBAAgB;mCACV,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;CAC5E,CAAC;AAEF,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAA2B;;;;;;;;;;WAU9C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;;;;+BAItB,CAAC,CAAC,KAAK;CACrC,CAAC;AAEF,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAA+B;IACtD,OAAO;;;;8CAImC,CAAC,CAAC,IAAI;CACnD,CAAC;AAEF,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAA;;;;;;;;;;;;CAY5B,CAAC;AAEF,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAiC;;;;;;YAMnD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,WAAW,CAAC;mBACxC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;WACxC,CAAC,CAAC,KAAK;;qBAEG,CAAC,CAAC,IAAI,iBAAiB,CAAC,CAAC,KAAK;CAClD,CAAC;AAEF,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;gBAKR,CAAC,CAAC,OAAO;sBACH,CAAC,CAAC,KAAK;mBACV,CAAC,CAAC,KAAK;gBACV,CAAC,CAAC,IAAI;;;;;6BAKO,CAAC,CAAC,IAAI;;;;CAIlC,CAAC;AAEF,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;4BAME,CAAC,CAAC,IAAI;;;;;qBAKb,CAAC,CAAC,IAAI;;;;aAId,CAAC,CAAC,KAAK;;4BAEQ,CAAC,CAAC,KAAK,YAAY,CAAC,CAAC,IAAI;2CACV,CAAC,CAAC,OAAO,YAAY,CAAC,CAAC,KAAK;;CAEtE,CAAC;AAEF,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;WAMZ,CAAC,CAAC,KAAK;2DACyC,CAAC,CAAC,KAAK;4BACtC,CAAC,CAAC,IAAI,iBAAiB,CAAC,CAAC,KAAK;CACzD,CAAC;AA2DF,MAAM,QAAQ,GAAG,CAAC,CAAS,EAAE,MAAe,EAAE,EAAE,CAC9C,UAAU,CAAC,CAAC,CAAE,CAAC,kBAAkB,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;AAajG,MAAM,UAAU,GAAG,CAAC,CAAO,EAAE,MAAe,EAAE,IAAI,GAAG,IAAI,EAAE,EAAE,CAC3D,CAAC,CAAC,kBAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;AAE9F,yFAAyF;AACzF,SAAS,cAAc,CAAC,CAAS,EAAE,CAAS,EAAE,MAAe;IAC3D,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IAC3B,MAAM,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IACzB,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,IAAI,IAAI,GAAG,EAAE,IAAI,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACnE,mEAAmE;IACnE,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE,EAAE,EAAE,CAAC,QAAQ,EAAE,EAAE,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7F,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,CAAC,WAAW,EAAE,CAAC;IACzD,IAAI,QAAQ,IAAI,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE;QAAE,OAAO,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnF,OAAO,GAAG,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,UAAU,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC;AAC9E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAiB,EAAE,IAAwC;IAChG,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IACrG,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,EAAE,CAAC;QACrB,MAAM,CAAC,GAAG,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC;YAAE,OAAO,CAAC,CAAC;IAClB,CAAC;IACD,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC;IACrG,IAAI,CAAC;QAAE,OAAO,QAAQ,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC;IAC5C,IAAI,CAAC;QAAE,OAAO,SAAS,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC;IAC7C,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,WAAW,GAAG,CAAK,CAAgB,EAAK,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,CAAE,CAAC,CAAC,KAAiB,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AAEpH;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC/C,MAAM,EAAE,SAAS,GAAG,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,GAAG,OAAO,EAAE,IAAI,GAAG,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IAChI,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC;IACrC,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IACjE,MAAM,IAAI,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,KAAK,EAAE,CAAC;IAExB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;IACxE,MAAM,OAAO,GAAc,KAAK;QAC9B,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;QAC7D,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO;YACtB,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;YAC/G,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAEnF,8FAA8F;IAC9F,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC1C,SAAS,CAAC,GAAG,EAAE,GAAG,IAAI,OAAO;QAAE,OAAO,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACvE,MAAM,KAAK,GAAG,CAAC,IAAa,EAAE,EAAE;QAC9B,OAAO,CAAC,KAAK,CAAC,CAAC;QACf,IAAI,IAAI;YAAE,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACrC,CAAC,CAAC;IACF,MAAM,IAAI,GAAG,GAAG,EAAE;QAChB,IAAI,QAAQ;YAAE,OAAO;QACrB,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO;YAAE,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC,CAAC;IAEF,cAAc,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAExC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,MAAM,MAAM,GAAG,CAAC,CAAa,EAAE,EAAE;YAC/B,MAAM,CAAC,GAAG,CAAC,CAAC,MAAc,CAAC;YAC3B,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;gBAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QAChF,CAAC,CAAC;QACF,QAAQ,CAAC,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;QACrD,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IACvE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAEX,MAAM,KAAK,GAAG,GAAG,EAAE;QACjB,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO;YAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;;YACpD,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC1B,QAAQ,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IACzB,CAAC,CAAC;IAEF,MAAM,MAAM,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC;IAC1H,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,CACxC,KAAC,QAAQ,OACH,MAAM,EACV,IAAI,EAAC,OAAO,EACZ,SAAS,QACT,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE;YACd,QAAQ,CAAC,CAAC,CAAC,CAAC;YACZ,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAAC,CAAC;QACvD,CAAC,GACD,CACH,CAAC,CAAC,CAAC,CACF,KAAC,QAAQ,OAAK,MAAM,EAAE,SAAS,QAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAI,CAC7G,CAAC;IAEF,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CACtC,KAAC,OAAO,IAAC,IAAI,EAAC,OAAO,gBAAY,WAAW,YACzC,KAAK,CAAC,IAAI,KAAK,OAAO;YACrB,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gBACxB,MAAM,GAAG,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;gBAC3B,OAAO,CACL,iBAAsB,IAAI,EAAC,QAAQ,kBAAe,GAAG,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,YAC3J,CAAC,CAAC,KAAK,IADG,CAAC,CAAC,KAAK,CAEX,CACV,CAAC;YACJ,CAAC,CAAC;YACF,CAAC,CAAC,KAAK,CAAC,OAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gBACzB,MAAM,GAAG,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;gBAC3B,OAAO,CACL,iBAAsB,IAAI,EAAC,QAAQ,kBAAe,GAAG,KAAK,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,YACxH,CAAC,CAAC,KAAK,IADG,CAAC,CAAC,KAAK,CAEX,CACV,CAAC;YACJ,CAAC,CAAC,GACI,CACX,CAAC,CAAC,CAAC,IAAI,CAAC;IAET,MAAM,IAAI,GAAG,KAAK,IAAI,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACpD,MAAM,YAAY,GAAG;QACnB,GAAG,EAAE,OAAO;QACZ,IAAI,EAAE,QAAiB;QACvB,EAAE,EAAE,EAAE;QACN,QAAQ;QACR,YAAY,EAAE,KAAK;QACnB,eAAe,EAAE,QAAiB;QAClC,eAAe,EAAE,IAAI;QACrB,eAAe,EAAE,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;QAC3C,cAAc,EAAE,KAAK,EAAE,OAAO,IAAI,SAAS;QAC3C,kBAAkB,EAAE,KAAK,EAAE,WAAW;QACtC,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7C,SAAS,EAAE,CAAC,CAAgB,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,KAAK,WAAW,IAAI,CAAC,IAAI,EAAE,CAAC;YAAC,CAAC,CAAC,cAAc,EAAE,CAAC;YAAC,IAAI,EAAE,CAAC;QAAC,CAAC,CAAC,CAAC;KACzG,CAAC;IACF,MAAM,QAAQ,GAAG,SAAS,IAAI,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAClD,KAAC,QAAQ,IAAC,IAAI,EAAC,QAAQ,WAAQ,OAAO,KAAK,MAAM,gBAAc,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,YAAY,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,YACpJ,KAAC,IAAI,IAAC,IAAI,EAAC,OAAO,GAAG,GACZ,CACZ,CAAC,CAAC,CAAC,IAAI,CAAC;IAET,MAAM,MAAM,GAAG,IAAI,KAAK,SAAS;QAC/B,CAAC,CAAC,gBAAO,IAAI,EAAC,QAAQ,EAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,GAAI;QAC7H,CAAC,CAAC,IAAI,CAAC;IAET,OAAO,CACL,eAAK,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,aAC1F,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,CACpB,MAAC,OAAO,WAAM,CAAC,KAAK,IAAI,IAAI,aAC1B,MAAC,OAAO,OAAK,YAAY,aACvB,KAAC,IAAI,IAAC,IAAI,EAAE,IAAI,GAAI,EACpB,yBAAO,OAAO,GAAQ,IACd,EACT,QAAQ,IACD,CACX,CAAC,CAAC,CAAC,CACF,MAAC,QAAQ,aAAQ,IAAI,cAAY,CAAC,CAAC,KAAK,EAAE,OAAO,eAAa,CAAC,CAAC,QAAQ,aACtE,MAAC,QAAQ,OAAK,YAAY,kBAAgB,KAAK,aAC7C,KAAC,IAAI,IAAC,IAAI,EAAE,IAAI,GAAI,EACpB,eAAM,SAAS,EAAC,KAAK,YAAE,OAAO,GAAQ,IAC7B,EACV,QAAQ,IACA,CACZ,EACA,MAAM,EACN,IAAI,CAAC,CAAC,CAAC,CACN,KAAC,QAAQ,IAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,IAAI,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,YACjF,MAAC,KAAK,IAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAC,QAAQ,gBAAa,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,eAAe,CAAC,aAC9F,OAAO,EACR,0BACG,QAAQ,EACR,KAAK,CAAC,CAAC,CAAC,CACP,MAAC,IAAI,eACH,4BAAgB,QAAQ,YAAE,IAAI,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,oBAAoB,GAAQ,EAClG,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,iBAAQ,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,sBAAgB,CAAC,CAAC,CAAC,IAAI,IACzF,CACR,CAAC,CAAC,CAAC,IAAI,IACJ,EACL,KAAK,CAAC,CAAC,CAAC,cAAK,SAAS,EAAC,MAAM,YAAE,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAO,CAAC,CAAC,CAAC,IAAI,IAChE,GACC,CACZ,CAAC,CAAC,CAAC,IAAI,IACJ,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { type IconName } from "./Icon.tsx";
|
|
3
|
+
/** Whether a file matches an `accept` list of extensions (`.png`) and MIME types (`image/*`, `application/pdf`). */
|
|
4
|
+
export declare function fileAccepted(file: File, accept: string[] | undefined): boolean;
|
|
5
|
+
export interface DropzoneProps {
|
|
6
|
+
/** the accepted files, from a drop or the file dialog */
|
|
7
|
+
onFiles: (files: File[]) => void;
|
|
8
|
+
/** files that `accept` or `multiple` turned away, so the caller can say why */
|
|
9
|
+
onReject?: ((files: File[]) => void) | undefined;
|
|
10
|
+
/** extensions (`.png`) and MIME types (`image/*`) it takes; anything, by default */
|
|
11
|
+
accept?: string[] | undefined;
|
|
12
|
+
/** take several at once (default true) */
|
|
13
|
+
multiple?: boolean | undefined;
|
|
14
|
+
disabled?: boolean | undefined;
|
|
15
|
+
/** files are being taken in: a spinner, and no drops until it is done */
|
|
16
|
+
busy?: boolean | undefined;
|
|
17
|
+
/** the caption while `busy` (default "Uploading…") */
|
|
18
|
+
busyLabel?: ReactNode | undefined;
|
|
19
|
+
/** the caption (default "**Drop files here** or click to browse") */
|
|
20
|
+
children?: ReactNode | undefined;
|
|
21
|
+
/** a second line — the limits ("Up to 5 GB each") */
|
|
22
|
+
hint?: ReactNode | undefined;
|
|
23
|
+
/** the caption while files are over it (default "Drop to add") */
|
|
24
|
+
overLabel?: ReactNode | undefined;
|
|
25
|
+
icon?: IconName | (string & {}) | undefined;
|
|
26
|
+
/** one row rather than a block — under a list that already has files */
|
|
27
|
+
compact?: boolean | undefined;
|
|
28
|
+
/** accessible name (default "Choose files") */
|
|
29
|
+
label?: string | undefined;
|
|
30
|
+
/** take a whole folder from the file dialog (Chromium, Safari and Firefox all honour `webkitdirectory`) */
|
|
31
|
+
directory?: boolean | undefined;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Dropzone: drag files onto it, or click it (or Enter/Space) to browse.
|
|
35
|
+
* Three states — idle, files over it, busy — and it says which. Filters on
|
|
36
|
+
* `accept` itself, because a drop ignores the file dialog's filter; what it
|
|
37
|
+
* turns away goes to `onReject`. Generic: no upload, no queue, no progress —
|
|
38
|
+
* pair it with `TransferList` for that.
|
|
39
|
+
*/
|
|
40
|
+
export declare function Dropzone({ onFiles, onReject, accept, multiple, disabled, busy, busyLabel, children, hint, overLabel, icon, compact, label, directory, }: DropzoneProps): import("react").JSX.Element;
|
|
41
|
+
//# sourceMappingURL=Dropzone.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Dropzone.d.ts","sourceRoot":"","sources":["../../src/kit/Dropzone.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGzE,OAAO,EAAQ,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAmCjD,oHAAoH;AACpH,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,GAAG,OAAO,CAW9E;AAED,MAAM,WAAW,aAAa;IAC5B,yDAAyD;IACzD,OAAO,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;IACjC,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACjD,oFAAoF;IACpF,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC9B,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/B,yEAAyE;IACzE,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,sDAAsD;IACtD,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAClC,qEAAqE;IACrE,QAAQ,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IACjC,qDAAqD;IACrD,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC7B,kEAAkE;IAClE,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAClC,IAAI,CAAC,EAAE,QAAQ,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,GAAG,SAAS,CAAC;IAC5C,wEAAwE;IACxE,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,2GAA2G;IAC3G,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACjC;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,EACvB,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAe,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAwB,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAyB,EAC/H,IAAe,EAAE,OAAO,EAAE,KAAsB,EAAE,SAAS,GAC5D,EAAE,aAAa,+BAiFf"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useRef, useState } from "react";
|
|
3
|
+
import styled, { css } from "styled-components";
|
|
4
|
+
import { v } from "../theme/tokens.js";
|
|
5
|
+
import { Icon } from "./Icon.js";
|
|
6
|
+
import { Spinner } from "./Skeleton.js";
|
|
7
|
+
// The drop target a console's upload screen needs: files dragged onto it or
|
|
8
|
+
// chosen by clicking it, handed back as File[]. Added for the upl.im
|
|
9
|
+
// dashboard (1.4), whose uploader had wrapped a third-party uploader's
|
|
10
|
+
// headless dropzone; this one knows nothing about where the files go.
|
|
11
|
+
// FilePicker stays the one-line click target inside a form.
|
|
12
|
+
const Zone = styled.div `
|
|
13
|
+
position: relative;
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: ${(p) => (p.$compact ? "row" : "column")};
|
|
16
|
+
align-items: center;
|
|
17
|
+
justify-content: center;
|
|
18
|
+
gap: ${(p) => (p.$compact ? "10px" : "8px")};
|
|
19
|
+
padding: ${(p) => (p.$compact ? "14px 16px" : "40px 20px")};
|
|
20
|
+
border: 1px dashed ${(p) => (p.$state === "over" ? v.brand : v.line2)};
|
|
21
|
+
border-radius: ${v.rPanel};
|
|
22
|
+
background: ${(p) => (p.$state === "over" ? v.brand08 : v.surface2)};
|
|
23
|
+
color: ${v.muted};
|
|
24
|
+
font-size: 12.5px;
|
|
25
|
+
text-align: center;
|
|
26
|
+
cursor: pointer;
|
|
27
|
+
transition: border-color 0.14s ease, background 0.14s ease, color 0.14s ease;
|
|
28
|
+
&:hover { border-color: ${v.brand55}; color: ${v.text}; }
|
|
29
|
+
&:focus-visible { box-shadow: ${v.ring}; border-color: ${v.brand55}; border-radius: ${v.rPanel}; }
|
|
30
|
+
> .glyph { font-size: ${(p) => (p.$compact ? 16 : 22)}px; color: ${(p) => (p.$state === "over" ? v.brand : v.faint)}; display: inline-flex; }
|
|
31
|
+
> .sub { font-size: 11px; color: ${v.faint}; }
|
|
32
|
+
strong { color: ${v.text}; font-weight: 600; }
|
|
33
|
+
input { display: none; }
|
|
34
|
+
${(p) => p.$state === "busy" && css `cursor: progress; &:hover { border-color: ${v.line2}; color: ${v.muted}; }`}
|
|
35
|
+
${(p) => p.$disabled && css `opacity: 0.55; cursor: not-allowed; &:hover { border-color: ${v.line2}; color: ${v.muted}; }`}
|
|
36
|
+
`;
|
|
37
|
+
/** Whether a file matches an `accept` list of extensions (`.png`) and MIME types (`image/*`, `application/pdf`). */
|
|
38
|
+
export function fileAccepted(file, accept) {
|
|
39
|
+
if (!accept || accept.length === 0)
|
|
40
|
+
return true;
|
|
41
|
+
const name = file.name.toLowerCase();
|
|
42
|
+
const type = (file.type || "").toLowerCase();
|
|
43
|
+
return accept.some((raw) => {
|
|
44
|
+
const a = raw.trim().toLowerCase();
|
|
45
|
+
if (!a)
|
|
46
|
+
return false;
|
|
47
|
+
if (a.startsWith("."))
|
|
48
|
+
return name.endsWith(a);
|
|
49
|
+
if (a.endsWith("/*"))
|
|
50
|
+
return type.startsWith(a.slice(0, -1));
|
|
51
|
+
return type === a;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Dropzone: drag files onto it, or click it (or Enter/Space) to browse.
|
|
56
|
+
* Three states — idle, files over it, busy — and it says which. Filters on
|
|
57
|
+
* `accept` itself, because a drop ignores the file dialog's filter; what it
|
|
58
|
+
* turns away goes to `onReject`. Generic: no upload, no queue, no progress —
|
|
59
|
+
* pair it with `TransferList` for that.
|
|
60
|
+
*/
|
|
61
|
+
export function Dropzone({ onFiles, onReject, accept, multiple = true, disabled, busy, busyLabel = "Uploading…", children, hint, overLabel = "Drop to add", icon = "upload", compact, label = "Choose files", directory, }) {
|
|
62
|
+
const [over, setOver] = useState(false);
|
|
63
|
+
const input = useRef(null);
|
|
64
|
+
// dragenter/leave fire for every child the pointer crosses; count them so the
|
|
65
|
+
// highlight only drops when the pointer really leaves the zone
|
|
66
|
+
const depth = useRef(0);
|
|
67
|
+
const off = !!disabled || !!busy;
|
|
68
|
+
const take = (list) => {
|
|
69
|
+
const files = Array.from(list ?? []);
|
|
70
|
+
if (!files.length)
|
|
71
|
+
return;
|
|
72
|
+
const ok = files.filter((f) => fileAccepted(f, accept));
|
|
73
|
+
const kept = multiple ? ok : ok.slice(0, 1);
|
|
74
|
+
const turned = files.filter((f) => !kept.includes(f));
|
|
75
|
+
if (turned.length)
|
|
76
|
+
onReject?.(turned);
|
|
77
|
+
if (kept.length)
|
|
78
|
+
onFiles(kept);
|
|
79
|
+
};
|
|
80
|
+
const hasFiles = (e) => Array.from(e.dataTransfer?.types ?? []).includes("Files");
|
|
81
|
+
const state = busy ? "busy" : over ? "over" : "idle";
|
|
82
|
+
return (_jsxs(Zone, { role: "button", tabIndex: off ? -1 : 0, "aria-label": label, "aria-disabled": off || undefined, "aria-busy": busy || undefined, "$state": state, "$disabled": !!disabled, "$compact": !!compact, onClick: () => { if (!off)
|
|
83
|
+
input.current?.click(); }, onKeyDown: (e) => {
|
|
84
|
+
if (off)
|
|
85
|
+
return;
|
|
86
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
87
|
+
e.preventDefault();
|
|
88
|
+
input.current?.click();
|
|
89
|
+
}
|
|
90
|
+
}, onDragEnter: (e) => {
|
|
91
|
+
if (off || !hasFiles(e))
|
|
92
|
+
return;
|
|
93
|
+
e.preventDefault();
|
|
94
|
+
depth.current += 1;
|
|
95
|
+
setOver(true);
|
|
96
|
+
}, onDragOver: (e) => {
|
|
97
|
+
if (off || !hasFiles(e))
|
|
98
|
+
return;
|
|
99
|
+
e.preventDefault();
|
|
100
|
+
e.dataTransfer.dropEffect = "copy";
|
|
101
|
+
}, onDragLeave: () => {
|
|
102
|
+
depth.current = Math.max(0, depth.current - 1);
|
|
103
|
+
if (depth.current === 0)
|
|
104
|
+
setOver(false);
|
|
105
|
+
}, onDrop: (e) => {
|
|
106
|
+
depth.current = 0;
|
|
107
|
+
setOver(false);
|
|
108
|
+
if (off)
|
|
109
|
+
return;
|
|
110
|
+
e.preventDefault();
|
|
111
|
+
take(e.dataTransfer.files);
|
|
112
|
+
}, children: [_jsx("input", { ref: input, type: "file", tabIndex: -1, multiple: multiple, accept: accept?.join(","), disabled: off, ...(directory ? { webkitdirectory: "", directory: "" } : {}), onClick: (e) => e.stopPropagation(), onChange: (e) => {
|
|
113
|
+
take(e.target.files);
|
|
114
|
+
// the same file chosen twice in a row is still a choice
|
|
115
|
+
e.target.value = "";
|
|
116
|
+
} }), _jsx("span", { className: "glyph", "aria-hidden": true, children: busy ? _jsx(Spinner, { "$size": compact ? 16 : 22 }) : _jsx(Icon, { name: icon }) }), _jsx("span", { "aria-live": "polite", children: busy ? busyLabel : over ? overLabel : (children ?? _jsxs(_Fragment, { children: [_jsx("strong", { children: "Drop files here" }), " or click to browse"] })) }), hint && !busy ? _jsx("span", { className: "sub", children: hint }) : null] }));
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=Dropzone.js.map
|