react-os-shell 4.55.0 → 4.67.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 +7 -3
- package/dist/{Browser-WHBSYGLC.js → Browser-NBYPPENQ.js} +6 -6
- package/dist/{Browser-WHBSYGLC.js.map → Browser-NBYPPENQ.js.map} +1 -1
- package/dist/{Calculator-PHKNMRLX.js → Calculator-UNAVT7IE.js} +5 -5
- package/dist/{Calculator-PHKNMRLX.js.map → Calculator-UNAVT7IE.js.map} +1 -1
- package/dist/ConfirmDialog-SREDNTIB.js +3 -0
- package/dist/{ConfirmDialog-EEH4CWSW.js.map → ConfirmDialog-SREDNTIB.js.map} +1 -1
- package/dist/{CurrencyConverter-MEG7RHEK.js → CurrencyConverter-KURXJHLK.js} +5 -5
- package/dist/{CurrencyConverter-MEG7RHEK.js.map → CurrencyConverter-KURXJHLK.js.map} +1 -1
- package/dist/{Documents-Y32RNCTU.js → Documents-7CUBCETC.js} +6 -6
- package/dist/{Documents-Y32RNCTU.js.map → Documents-7CUBCETC.js.map} +1 -1
- package/dist/{Files-LTG2S2KU.js → Files-UXEDRQF4.js} +6 -6
- package/dist/{Files-LTG2S2KU.js.map → Files-UXEDRQF4.js.map} +1 -1
- package/dist/{Notepad-P7J2OAXD.js → Notepad-ON4T45UP.js} +6 -6
- package/dist/{Notepad-P7J2OAXD.js.map → Notepad-ON4T45UP.js.map} +1 -1
- package/dist/{PomodoroTimer-5B5AFXQH.js → PomodoroTimer-J7V5VXR4.js} +5 -5
- package/dist/{PomodoroTimer-5B5AFXQH.js.map → PomodoroTimer-J7V5VXR4.js.map} +1 -1
- package/dist/{Preview-XZQ55YGY.js → Preview-QINOPDT2.js} +6 -6
- package/dist/{Preview-XZQ55YGY.js.map → Preview-QINOPDT2.js.map} +1 -1
- package/dist/{Spreadsheet-KKSLCSIK.js → Spreadsheet-OFF3J4HN.js} +6 -6
- package/dist/{Spreadsheet-KKSLCSIK.js.map → Spreadsheet-OFF3J4HN.js.map} +1 -1
- package/dist/{Stock-KTWRNBI6.js → Stock-BSU7S7MW.js} +5 -5
- package/dist/{Stock-KTWRNBI6.js.map → Stock-BSU7S7MW.js.map} +1 -1
- package/dist/{Weather-B7MO7N4N.js → Weather-BKNRVMG6.js} +5 -5
- package/dist/{Weather-B7MO7N4N.js.map → Weather-BKNRVMG6.js.map} +1 -1
- package/dist/{WorldClock-M5MEV74F.js → WorldClock-VMTD2QWD.js} +5 -5
- package/dist/{WorldClock-M5MEV74F.js.map → WorldClock-VMTD2QWD.js.map} +1 -1
- package/dist/apps/index.js +16 -16
- package/dist/{chunk-CTTHBTOX.js → chunk-B3IYV7JN.js} +1052 -334
- package/dist/chunk-B3IYV7JN.js.map +1 -0
- package/dist/{chunk-OXLLRKBC.js → chunk-CDR2Q64Q.js} +38 -22
- package/dist/chunk-CDR2Q64Q.js.map +1 -0
- package/dist/{chunk-FHPPPDHL.js → chunk-E2N5WEHI.js} +3 -3
- package/dist/{chunk-FHPPPDHL.js.map → chunk-E2N5WEHI.js.map} +1 -1
- package/dist/{chunk-5S65ZC5W.js → chunk-GRSVL6WX.js} +83 -9
- package/dist/chunk-GRSVL6WX.js.map +1 -0
- package/dist/{chunk-S3ZIBWRY.js → chunk-HAFM6ZQD.js} +4 -4
- package/dist/{chunk-S3ZIBWRY.js.map → chunk-HAFM6ZQD.js.map} +1 -1
- package/dist/chunk-K35QFOJF.js +7 -0
- package/dist/{chunk-LCLB7YBY.js.map → chunk-K35QFOJF.js.map} +1 -1
- package/dist/{index-BE0z2D6y.d.ts → index-DM-d12A7.d.ts} +206 -7
- package/dist/index.d.ts +29 -8
- package/dist/index.js +58 -20
- package/dist/index.js.map +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +3 -3
- package/package.json +1 -1
- package/dist/ConfirmDialog-EEH4CWSW.js +0 -3
- package/dist/chunk-5S65ZC5W.js.map +0 -1
- package/dist/chunk-CTTHBTOX.js.map +0 -1
- package/dist/chunk-LCLB7YBY.js +0 -7
- package/dist/chunk-OXLLRKBC.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Breadcrumbs } from './chunk-HNH7FOYB.js';
|
|
2
2
|
import { SidebarLayout } from './chunk-YG45DAUT.js';
|
|
3
3
|
import { useIsMobile, PopupMenu, PopupMenuItem, useShellPrefs } from './chunk-ZCDFNZQS.js';
|
|
4
|
-
import { registerModalEscapeInterceptor, useFocusTrap, useScrollLock } from './chunk-
|
|
4
|
+
import { registerModalEscapeInterceptor, useFocusTrap, useScrollLock } from './chunk-CDR2Q64Q.js';
|
|
5
5
|
import { glassStyle } from './chunk-3CUSBZWG.js';
|
|
6
6
|
import { forwardRef, useId, useCallback, useState, useRef, useEffect, createContext, useLayoutEffect, useMemo, Children, isValidElement, cloneElement, useContext, Fragment as Fragment$1, Component, useSyncExternalStore } from 'react';
|
|
7
7
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
@@ -164,7 +164,7 @@ function inputClasses(opts) {
|
|
|
164
164
|
return [shape, opts?.invalid ? INPUT_INVALID : "", INPUT_DISABLED, opts?.className ?? ""].filter(Boolean).join(" ");
|
|
165
165
|
}
|
|
166
166
|
var Input = forwardRef(function Input2({ invalid, leftIcon, rightAdornment, size, className = "", ...rest }, ref) {
|
|
167
|
-
const
|
|
167
|
+
const pad5 = `${leftIcon ? "pl-9" : ""} ${rightAdornment ? "pr-9" : ""}`.trim();
|
|
168
168
|
const field = (
|
|
169
169
|
// `inputMode` needs no plumbing — it rides the native spread onto the
|
|
170
170
|
// <input>, which is how a till sets inputMode="none" to keep the OS
|
|
@@ -174,7 +174,7 @@ var Input = forwardRef(function Input2({ invalid, leftIcon, rightAdornment, size
|
|
|
174
174
|
{
|
|
175
175
|
ref,
|
|
176
176
|
"aria-invalid": invalid || void 0,
|
|
177
|
-
className: inputClasses({ invalid, size, className: [
|
|
177
|
+
className: inputClasses({ invalid, size, className: [pad5, className].filter(Boolean).join(" ") }),
|
|
178
178
|
...rest
|
|
179
179
|
}
|
|
180
180
|
)
|
|
@@ -282,7 +282,8 @@ function useAnchoredPosition(triggerRef, open) {
|
|
|
282
282
|
const placeAbove = spaceBelow < Math.min(MENU_MAX_HEIGHT, 160) && spaceAbove > spaceBelow;
|
|
283
283
|
const maxHeight = Math.max(96, Math.min(MENU_MAX_HEIGHT, placeAbove ? spaceAbove : spaceBelow));
|
|
284
284
|
const left = Math.max(VIEWPORT_MARGIN, Math.min(rect.left, window.innerWidth - rect.width - VIEWPORT_MARGIN));
|
|
285
|
-
const
|
|
285
|
+
const width = Math.min(rect.width, window.innerWidth - 2 * VIEWPORT_MARGIN);
|
|
286
|
+
const next = { left, width, maxHeight };
|
|
286
287
|
if (placeAbove) next.bottom = window.innerHeight - rect.top + MENU_GAP;
|
|
287
288
|
else next.top = rect.bottom + MENU_GAP;
|
|
288
289
|
setPos(next);
|
|
@@ -497,12 +498,12 @@ var ListboxSelect = forwardRef(function ListboxSelect2({
|
|
|
497
498
|
ref: listRef,
|
|
498
499
|
id: listboxId,
|
|
499
500
|
role: "listbox",
|
|
500
|
-
className: "fixed z-[
|
|
501
|
+
className: "fixed z-[10000] overflow-y-auto rounded-2xl py-1",
|
|
501
502
|
style: {
|
|
502
503
|
left: menuPos?.left,
|
|
503
504
|
top: menuPos?.top,
|
|
504
505
|
bottom: menuPos?.bottom,
|
|
505
|
-
|
|
506
|
+
width: menuPos?.width,
|
|
506
507
|
maxHeight: menuPos?.maxHeight ?? MENU_MAX_HEIGHT,
|
|
507
508
|
visibility: menuPos ? void 0 : "hidden",
|
|
508
509
|
...glassStyle()
|
|
@@ -1098,6 +1099,273 @@ function MediaUploadGrid({
|
|
|
1098
1099
|
}
|
|
1099
1100
|
) });
|
|
1100
1101
|
}
|
|
1102
|
+
var MONTH_NAMES = [
|
|
1103
|
+
"January",
|
|
1104
|
+
"February",
|
|
1105
|
+
"March",
|
|
1106
|
+
"April",
|
|
1107
|
+
"May",
|
|
1108
|
+
"June",
|
|
1109
|
+
"July",
|
|
1110
|
+
"August",
|
|
1111
|
+
"September",
|
|
1112
|
+
"October",
|
|
1113
|
+
"November",
|
|
1114
|
+
"December"
|
|
1115
|
+
];
|
|
1116
|
+
var DAY_NAMES = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
1117
|
+
var DAY_SHORT = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
1118
|
+
var pad = (n) => String(n).padStart(2, "0");
|
|
1119
|
+
function toKey(d) {
|
|
1120
|
+
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
1121
|
+
}
|
|
1122
|
+
function fromKey(key) {
|
|
1123
|
+
if (!key) return null;
|
|
1124
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(key);
|
|
1125
|
+
if (!m) return null;
|
|
1126
|
+
const d = new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));
|
|
1127
|
+
return Number.isNaN(d.getTime()) ? null : d;
|
|
1128
|
+
}
|
|
1129
|
+
var monthKey = (d) => `${d.getFullYear()}-${pad(d.getMonth() + 1)}`;
|
|
1130
|
+
var YEARS_PER_PAGE = 12;
|
|
1131
|
+
var yearPageStart = (y) => Math.floor(y / YEARS_PER_PAGE) * YEARS_PER_PAGE;
|
|
1132
|
+
function monthStart(key) {
|
|
1133
|
+
const m = /^(\d{4})-(\d{2})$/.exec(key);
|
|
1134
|
+
return m ? new Date(Number(m[1]), Number(m[2]) - 1, 1) : /* @__PURE__ */ new Date();
|
|
1135
|
+
}
|
|
1136
|
+
function buildCells(view, weekStartsOn) {
|
|
1137
|
+
const first = new Date(view.getFullYear(), view.getMonth(), 1);
|
|
1138
|
+
const lead = (first.getDay() - weekStartsOn + 7) % 7;
|
|
1139
|
+
const start = new Date(first.getFullYear(), first.getMonth(), 1 - lead);
|
|
1140
|
+
return Array.from({ length: 42 }, (_, i) => new Date(start.getFullYear(), start.getMonth(), start.getDate() + i));
|
|
1141
|
+
}
|
|
1142
|
+
var addDays = (d, n) => new Date(d.getFullYear(), d.getMonth(), d.getDate() + n);
|
|
1143
|
+
var addMonths = (d, n) => {
|
|
1144
|
+
const target = new Date(d.getFullYear(), d.getMonth() + n, 1);
|
|
1145
|
+
const lastDay = new Date(target.getFullYear(), target.getMonth() + 1, 0).getDate();
|
|
1146
|
+
return new Date(target.getFullYear(), target.getMonth(), Math.min(d.getDate(), lastDay));
|
|
1147
|
+
};
|
|
1148
|
+
function Calendar({
|
|
1149
|
+
value,
|
|
1150
|
+
endValue,
|
|
1151
|
+
mode = "single",
|
|
1152
|
+
onSelect,
|
|
1153
|
+
min,
|
|
1154
|
+
max,
|
|
1155
|
+
month,
|
|
1156
|
+
defaultMonth,
|
|
1157
|
+
onMonthChange,
|
|
1158
|
+
weekStartsOn = 0,
|
|
1159
|
+
quickJump = true,
|
|
1160
|
+
"aria-label": ariaLabel,
|
|
1161
|
+
className = ""
|
|
1162
|
+
}) {
|
|
1163
|
+
const selected = fromKey(value);
|
|
1164
|
+
const today = /* @__PURE__ */ new Date();
|
|
1165
|
+
const todayKey = toKey(today);
|
|
1166
|
+
const [innerMonth, setInnerMonth] = useState(() => {
|
|
1167
|
+
if (defaultMonth) return defaultMonth;
|
|
1168
|
+
if (selected) return monthKey(selected);
|
|
1169
|
+
const here = monthKey(today);
|
|
1170
|
+
if (min && here < min.slice(0, 7)) return min.slice(0, 7);
|
|
1171
|
+
if (max && here > max.slice(0, 7)) return max.slice(0, 7);
|
|
1172
|
+
return here;
|
|
1173
|
+
});
|
|
1174
|
+
const viewMonth = month ?? innerMonth;
|
|
1175
|
+
const view = monthStart(viewMonth);
|
|
1176
|
+
const [active, setActive] = useState(() => value ?? todayKey);
|
|
1177
|
+
const gridRef = useRef(null);
|
|
1178
|
+
const shouldFocus = useRef(false);
|
|
1179
|
+
const [panel, setPanel] = useState("days");
|
|
1180
|
+
const cells = useMemo(() => buildCells(view, weekStartsOn), [viewMonth, weekStartsOn]);
|
|
1181
|
+
const outOfRange = (key) => !!min && key < min || !!max && key > max;
|
|
1182
|
+
const activeInView = cells.some((c) => toKey(c) === active);
|
|
1183
|
+
const fallbackActive = toKey(cells.find((c) => c.getMonth() === view.getMonth()) ?? cells[0]);
|
|
1184
|
+
const activeKey = activeInView ? active : fallbackActive;
|
|
1185
|
+
useEffect(() => {
|
|
1186
|
+
if (!shouldFocus.current) return;
|
|
1187
|
+
shouldFocus.current = false;
|
|
1188
|
+
gridRef.current?.querySelector('[data-active="true"]')?.focus();
|
|
1189
|
+
}, [activeKey, viewMonth]);
|
|
1190
|
+
const pageBy = (n) => {
|
|
1191
|
+
if (panel === "years") return new Date(view.getFullYear() + n * YEARS_PER_PAGE, view.getMonth(), 1);
|
|
1192
|
+
if (panel === "months") return new Date(view.getFullYear() + n, view.getMonth(), 1);
|
|
1193
|
+
return addMonths(view, n);
|
|
1194
|
+
};
|
|
1195
|
+
const pageBack = () => pageBy(-1);
|
|
1196
|
+
const pageForward = () => pageBy(1);
|
|
1197
|
+
const goToMonth = (next) => {
|
|
1198
|
+
const key = monthKey(next);
|
|
1199
|
+
if (month === void 0) setInnerMonth(key);
|
|
1200
|
+
onMonthChange?.(key);
|
|
1201
|
+
};
|
|
1202
|
+
const moveTo = (next) => {
|
|
1203
|
+
shouldFocus.current = true;
|
|
1204
|
+
setActive(toKey(next));
|
|
1205
|
+
if (monthKey(next) !== viewMonth) goToMonth(next);
|
|
1206
|
+
};
|
|
1207
|
+
const onKeyDown = (e) => {
|
|
1208
|
+
const current = fromKey(activeKey) ?? today;
|
|
1209
|
+
const step = {
|
|
1210
|
+
ArrowLeft: () => addDays(current, -1),
|
|
1211
|
+
ArrowRight: () => addDays(current, 1),
|
|
1212
|
+
ArrowUp: () => addDays(current, -7),
|
|
1213
|
+
ArrowDown: () => addDays(current, 7),
|
|
1214
|
+
// Home and End are the week, not the month: the grid's rows are weeks, and
|
|
1215
|
+
// this is what the ARIA date-grid pattern asks for.
|
|
1216
|
+
Home: () => addDays(current, -((current.getDay() - weekStartsOn + 7) % 7)),
|
|
1217
|
+
End: () => addDays(current, 6 - (current.getDay() - weekStartsOn + 7) % 7),
|
|
1218
|
+
PageUp: () => addMonths(current, e.shiftKey ? -12 : -1),
|
|
1219
|
+
PageDown: () => addMonths(current, e.shiftKey ? 12 : 1)
|
|
1220
|
+
};
|
|
1221
|
+
if (step[e.key]) {
|
|
1222
|
+
e.preventDefault();
|
|
1223
|
+
moveTo(step[e.key]());
|
|
1224
|
+
return;
|
|
1225
|
+
}
|
|
1226
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1227
|
+
e.preventDefault();
|
|
1228
|
+
if (!outOfRange(activeKey)) onSelect(activeKey);
|
|
1229
|
+
}
|
|
1230
|
+
};
|
|
1231
|
+
const inRange = (key) => {
|
|
1232
|
+
if (mode !== "range" || !value || !endValue) return false;
|
|
1233
|
+
return key > value && key < endValue;
|
|
1234
|
+
};
|
|
1235
|
+
const label = ariaLabel ?? `${MONTH_NAMES[view.getMonth()]} ${view.getFullYear()}`;
|
|
1236
|
+
return /* @__PURE__ */ jsxs("div", { className, children: [
|
|
1237
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between px-1", children: [
|
|
1238
|
+
/* @__PURE__ */ jsx(
|
|
1239
|
+
"button",
|
|
1240
|
+
{
|
|
1241
|
+
type: "button",
|
|
1242
|
+
"aria-label": panel === "years" ? "Previous years" : panel === "months" ? "Previous year" : "Previous month",
|
|
1243
|
+
onClick: () => goToMonth(pageBack()),
|
|
1244
|
+
className: "rounded-full p-1 text-gray-600 hover:bg-gray-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-400",
|
|
1245
|
+
children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", fill: "none", stroke: "currentColor", strokeWidth: "2", viewBox: "0 0 24 24", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 19l-7-7 7-7" }) })
|
|
1246
|
+
}
|
|
1247
|
+
),
|
|
1248
|
+
/* @__PURE__ */ jsx("div", { "aria-live": "polite", className: "flex items-center gap-1 text-sm font-semibold text-gray-800", children: quickJump ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1249
|
+
panel !== "years" && /* @__PURE__ */ jsx(
|
|
1250
|
+
"button",
|
|
1251
|
+
{
|
|
1252
|
+
type: "button",
|
|
1253
|
+
"aria-label": `Choose a month, currently ${MONTH_NAMES[view.getMonth()]}`,
|
|
1254
|
+
onClick: () => setPanel((p) => p === "months" ? "days" : "months"),
|
|
1255
|
+
className: "rounded-md px-1.5 py-0.5 transition-colors hover:bg-gray-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-400",
|
|
1256
|
+
children: MONTH_NAMES[view.getMonth()]
|
|
1257
|
+
}
|
|
1258
|
+
),
|
|
1259
|
+
/* @__PURE__ */ jsx(
|
|
1260
|
+
"button",
|
|
1261
|
+
{
|
|
1262
|
+
type: "button",
|
|
1263
|
+
"aria-label": `Choose a year, currently ${view.getFullYear()}`,
|
|
1264
|
+
onClick: () => setPanel((p) => p === "years" ? "days" : "years"),
|
|
1265
|
+
className: "rounded-md px-1.5 py-0.5 transition-colors hover:bg-gray-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-400",
|
|
1266
|
+
children: view.getFullYear()
|
|
1267
|
+
}
|
|
1268
|
+
)
|
|
1269
|
+
] }) : /* @__PURE__ */ jsxs("span", { children: [
|
|
1270
|
+
MONTH_NAMES[view.getMonth()],
|
|
1271
|
+
" ",
|
|
1272
|
+
view.getFullYear()
|
|
1273
|
+
] }) }),
|
|
1274
|
+
/* @__PURE__ */ jsx(
|
|
1275
|
+
"button",
|
|
1276
|
+
{
|
|
1277
|
+
type: "button",
|
|
1278
|
+
"aria-label": panel === "years" ? "Next years" : panel === "months" ? "Next year" : "Next month",
|
|
1279
|
+
onClick: () => goToMonth(pageForward()),
|
|
1280
|
+
className: "rounded-full p-1 text-gray-600 hover:bg-gray-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-400",
|
|
1281
|
+
children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", fill: "none", stroke: "currentColor", strokeWidth: "2", viewBox: "0 0 24 24", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) })
|
|
1282
|
+
}
|
|
1283
|
+
)
|
|
1284
|
+
] }),
|
|
1285
|
+
panel === "months" && /* @__PURE__ */ jsx("div", { role: "group", "aria-label": "Choose a month", className: "grid grid-cols-3 gap-1 text-center text-sm", children: MONTH_NAMES.map((name, m) => /* @__PURE__ */ jsx(
|
|
1286
|
+
"button",
|
|
1287
|
+
{
|
|
1288
|
+
type: "button",
|
|
1289
|
+
"aria-pressed": m === view.getMonth(),
|
|
1290
|
+
onClick: () => {
|
|
1291
|
+
goToMonth(new Date(view.getFullYear(), m, 1));
|
|
1292
|
+
setPanel("days");
|
|
1293
|
+
},
|
|
1294
|
+
className: [
|
|
1295
|
+
"rounded-md py-4 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-400",
|
|
1296
|
+
m === view.getMonth() ? "bg-blue-600 font-semibold text-white" : m === today.getMonth() && view.getFullYear() === today.getFullYear() ? "font-medium text-blue-600 hover:bg-gray-100" : "text-gray-700 hover:bg-gray-100"
|
|
1297
|
+
].join(" "),
|
|
1298
|
+
children: name.slice(0, 3)
|
|
1299
|
+
},
|
|
1300
|
+
name
|
|
1301
|
+
)) }),
|
|
1302
|
+
panel === "years" && /* @__PURE__ */ jsx("div", { role: "group", "aria-label": "Choose a year", className: "grid grid-cols-3 gap-1 text-center text-sm", children: Array.from({ length: YEARS_PER_PAGE }, (_, i) => yearPageStart(view.getFullYear()) + i).map((y) => /* @__PURE__ */ jsx(
|
|
1303
|
+
"button",
|
|
1304
|
+
{
|
|
1305
|
+
type: "button",
|
|
1306
|
+
"aria-pressed": y === view.getFullYear(),
|
|
1307
|
+
onClick: () => {
|
|
1308
|
+
goToMonth(new Date(y, view.getMonth(), 1));
|
|
1309
|
+
setPanel("months");
|
|
1310
|
+
},
|
|
1311
|
+
className: [
|
|
1312
|
+
"rounded-md py-4 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-400",
|
|
1313
|
+
y === view.getFullYear() ? "bg-blue-600 font-semibold text-white" : y === today.getFullYear() ? "font-medium text-blue-600 hover:bg-gray-100" : "text-gray-700 hover:bg-gray-100"
|
|
1314
|
+
].join(" "),
|
|
1315
|
+
children: y
|
|
1316
|
+
},
|
|
1317
|
+
y
|
|
1318
|
+
)) }),
|
|
1319
|
+
/* @__PURE__ */ jsxs(
|
|
1320
|
+
"div",
|
|
1321
|
+
{
|
|
1322
|
+
ref: gridRef,
|
|
1323
|
+
role: "grid",
|
|
1324
|
+
"aria-label": label,
|
|
1325
|
+
onKeyDown,
|
|
1326
|
+
hidden: panel !== "days",
|
|
1327
|
+
children: [
|
|
1328
|
+
/* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 text-center text-xs font-medium text-gray-500", children: Array.from({ length: 7 }, (_, i) => (i + weekStartsOn) % 7).map((d) => (
|
|
1329
|
+
// abbr carries the full name: "Su" is read as a word otherwise.
|
|
1330
|
+
/* @__PURE__ */ jsx("div", { role: "columnheader", "aria-label": DAY_NAMES[d], className: "py-1", children: /* @__PURE__ */ jsx("abbr", { title: DAY_NAMES[d], className: "no-underline", children: DAY_SHORT[d] }) }, d)
|
|
1331
|
+
)) }),
|
|
1332
|
+
Array.from({ length: 6 }, (_, row) => /* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 text-center text-sm", children: cells.slice(row * 7, row * 7 + 7).map((cell) => {
|
|
1333
|
+
const key = toKey(cell);
|
|
1334
|
+
const outside = cell.getMonth() !== view.getMonth();
|
|
1335
|
+
const isSelected = key === value || mode === "range" && key === endValue;
|
|
1336
|
+
const between = inRange(key);
|
|
1337
|
+
const disabled = outOfRange(key);
|
|
1338
|
+
return /* @__PURE__ */ jsx("div", { role: "gridcell", "aria-selected": isSelected, children: /* @__PURE__ */ jsx(
|
|
1339
|
+
"button",
|
|
1340
|
+
{
|
|
1341
|
+
type: "button",
|
|
1342
|
+
"data-active": key === activeKey,
|
|
1343
|
+
tabIndex: key === activeKey ? 0 : -1,
|
|
1344
|
+
disabled,
|
|
1345
|
+
"aria-label": `${cell.getDate()} ${MONTH_NAMES[cell.getMonth()]} ${cell.getFullYear()}`,
|
|
1346
|
+
"aria-current": key === todayKey ? "date" : void 0,
|
|
1347
|
+
onClick: () => {
|
|
1348
|
+
setActive(key);
|
|
1349
|
+
onSelect(key);
|
|
1350
|
+
},
|
|
1351
|
+
className: [
|
|
1352
|
+
// 44px below `sm`, compact above it. A 32px cell is under
|
|
1353
|
+
// every touch-target guideline there is, and a date grid
|
|
1354
|
+
// is seven of them side by side — the case where missing
|
|
1355
|
+
// by four pixels picks the wrong day rather than nothing.
|
|
1356
|
+
"w-full rounded-md py-1.5 min-h-11 sm:min-h-0 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-400",
|
|
1357
|
+
disabled ? "cursor-not-allowed text-gray-300" : isSelected ? "bg-blue-600 font-semibold text-white" : between ? "bg-blue-100 text-blue-800" : outside ? "text-gray-300 hover:bg-gray-100" : "text-gray-700 hover:bg-gray-100",
|
|
1358
|
+
key === todayKey && !isSelected ? "font-semibold text-blue-600" : ""
|
|
1359
|
+
].filter(Boolean).join(" "),
|
|
1360
|
+
children: cell.getDate()
|
|
1361
|
+
}
|
|
1362
|
+
) }, key);
|
|
1363
|
+
}) }, row))
|
|
1364
|
+
]
|
|
1365
|
+
}
|
|
1366
|
+
)
|
|
1367
|
+
] });
|
|
1368
|
+
}
|
|
1101
1369
|
function useClickOutside(ref, onClose) {
|
|
1102
1370
|
useEffect(() => {
|
|
1103
1371
|
const handler = (e) => {
|
|
@@ -1108,10 +1376,8 @@ function useClickOutside(ref, onClose) {
|
|
|
1108
1376
|
}, [ref, onClose]);
|
|
1109
1377
|
}
|
|
1110
1378
|
var PRESET_LABELS = ["Last 2 Weeks", "Last Month", "Last 3 Months", "Last 6 Months", "Last 12 Months"];
|
|
1111
|
-
var
|
|
1112
|
-
var
|
|
1113
|
-
var yearPageStart = (y) => Math.floor(y / YEARS_PER_PAGE) * YEARS_PER_PAGE;
|
|
1114
|
-
var pad = (n) => String(n).padStart(2, "0");
|
|
1379
|
+
var monthKeyOf = (d) => `${d.getFullYear()}-${pad2(d.getMonth() + 1)}`;
|
|
1380
|
+
var pad2 = (n) => String(n).padStart(2, "0");
|
|
1115
1381
|
var EDGE_MARGIN = 8;
|
|
1116
1382
|
function clipBounds(el) {
|
|
1117
1383
|
for (let node = el.parentElement; node; node = node.parentElement) {
|
|
@@ -1125,7 +1391,7 @@ function clipBounds(el) {
|
|
|
1125
1391
|
return { left: 0, right: window.innerWidth };
|
|
1126
1392
|
}
|
|
1127
1393
|
function toISODate(d) {
|
|
1128
|
-
return `${d.getFullYear()}-${
|
|
1394
|
+
return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
|
|
1129
1395
|
}
|
|
1130
1396
|
function parseDate(s) {
|
|
1131
1397
|
const [y, m, d] = s.split("-").map(Number);
|
|
@@ -1151,10 +1417,7 @@ function DateRangePicker({
|
|
|
1151
1417
|
const panelRef = useRef(null);
|
|
1152
1418
|
const [align, setAlign] = useState("left");
|
|
1153
1419
|
const now = /* @__PURE__ */ new Date();
|
|
1154
|
-
const [
|
|
1155
|
-
const [year, setYear] = useState(from ? parseDate(from).getFullYear() : now.getFullYear());
|
|
1156
|
-
const [view, setView] = useState("days");
|
|
1157
|
-
const [yearPage, setYearPage] = useState(() => yearPageStart(year));
|
|
1420
|
+
const [viewMonth, setViewMonth] = useState(() => monthKeyOf(from ? parseDate(from) : now));
|
|
1158
1421
|
const displayDate = (s) => s ? formatDisplay(s) : "";
|
|
1159
1422
|
useClickOutside(ref, useCallback(() => {
|
|
1160
1423
|
if (open) setOpen(false);
|
|
@@ -1179,11 +1442,7 @@ function DateRangePicker({
|
|
|
1179
1442
|
setTempFrom(from);
|
|
1180
1443
|
setTempTo(to);
|
|
1181
1444
|
setActivePreset(null);
|
|
1182
|
-
|
|
1183
|
-
setMonth(anchor.getMonth());
|
|
1184
|
-
setYear(anchor.getFullYear());
|
|
1185
|
-
setYearPage(yearPageStart(anchor.getFullYear()));
|
|
1186
|
-
setView("days");
|
|
1445
|
+
setViewMonth(monthKeyOf(from ? parseDate(from) : now));
|
|
1187
1446
|
setOpen(true);
|
|
1188
1447
|
};
|
|
1189
1448
|
const handlePreset = (label) => {
|
|
@@ -1216,10 +1475,7 @@ function DateRangePicker({
|
|
|
1216
1475
|
setTempFrom(toISODate(start));
|
|
1217
1476
|
setTempTo(toISODate(end));
|
|
1218
1477
|
setActivePreset(label);
|
|
1219
|
-
|
|
1220
|
-
setYear(start.getFullYear());
|
|
1221
|
-
setYearPage(yearPageStart(start.getFullYear()));
|
|
1222
|
-
setView("days");
|
|
1478
|
+
setViewMonth(monthKeyOf(start));
|
|
1223
1479
|
};
|
|
1224
1480
|
const handleCalendarSelect = (date) => {
|
|
1225
1481
|
setActivePreset("Custom");
|
|
@@ -1243,57 +1499,6 @@ function DateRangePicker({
|
|
|
1243
1499
|
onChange("", "");
|
|
1244
1500
|
setOpen(false);
|
|
1245
1501
|
};
|
|
1246
|
-
const changeMonth = (delta) => {
|
|
1247
|
-
let m = month + delta, y = year;
|
|
1248
|
-
if (m < 0) {
|
|
1249
|
-
m = 11;
|
|
1250
|
-
y--;
|
|
1251
|
-
} else if (m > 11) {
|
|
1252
|
-
m = 0;
|
|
1253
|
-
y++;
|
|
1254
|
-
}
|
|
1255
|
-
setMonth(m);
|
|
1256
|
-
setYear(y);
|
|
1257
|
-
};
|
|
1258
|
-
const handleStep = (delta) => {
|
|
1259
|
-
if (view === "days") changeMonth(delta);
|
|
1260
|
-
else if (view === "months") setYear(year + delta);
|
|
1261
|
-
else setYearPage(yearPage + delta * YEARS_PER_PAGE);
|
|
1262
|
-
};
|
|
1263
|
-
const selectMonth = (m) => {
|
|
1264
|
-
setMonth(m);
|
|
1265
|
-
setView("days");
|
|
1266
|
-
};
|
|
1267
|
-
const selectYear = (y) => {
|
|
1268
|
-
setYear(y);
|
|
1269
|
-
setView("months");
|
|
1270
|
-
};
|
|
1271
|
-
const openYears = () => {
|
|
1272
|
-
setYearPage(yearPageStart(year));
|
|
1273
|
-
setView("years");
|
|
1274
|
-
};
|
|
1275
|
-
const firstDay = new Date(year, month, 1).getDay();
|
|
1276
|
-
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
|
1277
|
-
const prevDays = new Date(year, month, 0).getDate();
|
|
1278
|
-
const monthName = new Date(year, month).toLocaleString("default", { month: "long" });
|
|
1279
|
-
const cells = [];
|
|
1280
|
-
for (let i = firstDay - 1; i >= 0; i--) {
|
|
1281
|
-
const d = new Date(year, month - 1, prevDays - i);
|
|
1282
|
-
cells.push({ day: prevDays - i, current: false, date: toISODate(d) });
|
|
1283
|
-
}
|
|
1284
|
-
for (let d = 1; d <= daysInMonth; d++) {
|
|
1285
|
-
cells.push({ day: d, current: true, date: toISODate(new Date(year, month, d)) });
|
|
1286
|
-
}
|
|
1287
|
-
const remaining = 42 - cells.length;
|
|
1288
|
-
for (let d = 1; d <= remaining; d++) {
|
|
1289
|
-
cells.push({ day: d, current: false, date: toISODate(new Date(year, month + 1, d)) });
|
|
1290
|
-
}
|
|
1291
|
-
const isInRange = (date) => {
|
|
1292
|
-
if (!tempFrom || !tempTo) return false;
|
|
1293
|
-
const s = tempFrom < tempTo ? tempFrom : tempTo;
|
|
1294
|
-
const e = tempFrom < tempTo ? tempTo : tempFrom;
|
|
1295
|
-
return date > s && date < e;
|
|
1296
|
-
};
|
|
1297
1502
|
const displayText = from && to ? `${displayDate(from)} \u2014 ${displayDate(to)}` : from ? `From ${displayDate(from)}` : to ? `To ${displayDate(to)}` : "";
|
|
1298
1503
|
return /* @__PURE__ */ jsxs("div", { className: "relative", ref, children: [
|
|
1299
1504
|
/* @__PURE__ */ jsxs(
|
|
@@ -1349,85 +1554,18 @@ function DateRangePicker({
|
|
|
1349
1554
|
] })
|
|
1350
1555
|
] }),
|
|
1351
1556
|
/* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
|
|
1352
|
-
/* @__PURE__ */
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
),
|
|
1365
|
-
view === "years" ? /* @__PURE__ */ jsxs("span", { className: "px-1.5 py-0.5", children: [
|
|
1366
|
-
yearPage,
|
|
1367
|
-
" \u2013 ",
|
|
1368
|
-
yearPage + YEARS_PER_PAGE - 1
|
|
1369
|
-
] }) : /* @__PURE__ */ jsx(
|
|
1370
|
-
"button",
|
|
1371
|
-
{
|
|
1372
|
-
type: "button",
|
|
1373
|
-
onClick: openYears,
|
|
1374
|
-
className: "px-1.5 py-0.5 rounded-md hover:bg-gray-100 transition-colors",
|
|
1375
|
-
children: year
|
|
1376
|
-
}
|
|
1377
|
-
)
|
|
1378
|
-
] }),
|
|
1379
|
-
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => handleStep(1), "aria-label": "Next", className: "p-1 rounded-full hover:bg-gray-100 text-gray-600", children: /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", strokeWidth: "2", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) }) })
|
|
1380
|
-
] }),
|
|
1381
|
-
/* @__PURE__ */ jsxs("div", { className: "min-h-[13.75rem]", children: [
|
|
1382
|
-
view === "days" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1383
|
-
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 text-center text-xs font-medium text-gray-500 mb-1", children: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((d) => /* @__PURE__ */ jsx("div", { className: "py-1", children: d }, d)) }),
|
|
1384
|
-
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 text-center text-sm", children: cells.map((c, i) => {
|
|
1385
|
-
const isStart = c.date === tempFrom;
|
|
1386
|
-
const isEnd = c.date === tempTo;
|
|
1387
|
-
const isSelected = isStart || isEnd;
|
|
1388
|
-
const inRange = isInRange(c.date);
|
|
1389
|
-
return /* @__PURE__ */ jsx(
|
|
1390
|
-
"button",
|
|
1391
|
-
{
|
|
1392
|
-
type: "button",
|
|
1393
|
-
onClick: () => handleCalendarSelect(c.date),
|
|
1394
|
-
className: `py-1.5 rounded-md transition-colors ${!c.current ? "text-gray-300" : isSelected ? "bg-blue-600 text-white font-semibold" : inRange ? "bg-blue-100 text-blue-800" : "text-gray-700 hover:bg-gray-100"}`,
|
|
1395
|
-
children: c.day
|
|
1396
|
-
},
|
|
1397
|
-
i
|
|
1398
|
-
);
|
|
1399
|
-
}) })
|
|
1400
|
-
] }),
|
|
1401
|
-
view === "months" && /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-1 text-center text-sm", children: MONTH_NAMES.map((name, m) => {
|
|
1402
|
-
const isCurrent = m === month;
|
|
1403
|
-
const isThisMonth = m === now.getMonth() && year === now.getFullYear();
|
|
1404
|
-
return /* @__PURE__ */ jsx(
|
|
1405
|
-
"button",
|
|
1406
|
-
{
|
|
1407
|
-
type: "button",
|
|
1408
|
-
onClick: () => selectMonth(m),
|
|
1409
|
-
className: `py-4 rounded-md transition-colors ${isCurrent ? "bg-blue-600 text-white font-semibold" : isThisMonth ? "text-blue-600 font-medium hover:bg-gray-100" : "text-gray-700 hover:bg-gray-100"}`,
|
|
1410
|
-
children: name
|
|
1411
|
-
},
|
|
1412
|
-
name
|
|
1413
|
-
);
|
|
1414
|
-
}) }),
|
|
1415
|
-
view === "years" && /* @__PURE__ */ jsx("div", { className: "grid grid-cols-3 gap-1 text-center text-sm", children: Array.from({ length: YEARS_PER_PAGE }, (_, i) => yearPage + i).map((y) => {
|
|
1416
|
-
const isCurrent = y === year;
|
|
1417
|
-
const isThisYear = y === now.getFullYear();
|
|
1418
|
-
return /* @__PURE__ */ jsx(
|
|
1419
|
-
"button",
|
|
1420
|
-
{
|
|
1421
|
-
type: "button",
|
|
1422
|
-
onClick: () => selectYear(y),
|
|
1423
|
-
className: `py-4 rounded-md transition-colors ${isCurrent ? "bg-blue-600 text-white font-semibold" : isThisYear ? "text-blue-600 font-medium hover:bg-gray-100" : "text-gray-700 hover:bg-gray-100"}`,
|
|
1424
|
-
children: y
|
|
1425
|
-
},
|
|
1426
|
-
y
|
|
1427
|
-
);
|
|
1428
|
-
}) })
|
|
1429
|
-
] })
|
|
1430
|
-
] }),
|
|
1557
|
+
/* @__PURE__ */ jsx("div", { className: "w-64", children: /* @__PURE__ */ jsx(
|
|
1558
|
+
Calendar,
|
|
1559
|
+
{
|
|
1560
|
+
mode: "range",
|
|
1561
|
+
value: tempFrom || null,
|
|
1562
|
+
endValue: tempTo || null,
|
|
1563
|
+
month: viewMonth,
|
|
1564
|
+
onMonthChange: setViewMonth,
|
|
1565
|
+
onSelect: handleCalendarSelect,
|
|
1566
|
+
"aria-label": "Date range"
|
|
1567
|
+
}
|
|
1568
|
+
) }),
|
|
1431
1569
|
/* @__PURE__ */ jsxs("div", { className: "border-l border-gray-200 pl-4 flex flex-col gap-1 min-w-[130px]", children: [
|
|
1432
1570
|
PRESET_LABELS.map((label) => /* @__PURE__ */ jsx(
|
|
1433
1571
|
"button",
|
|
@@ -1469,37 +1607,315 @@ function DateRangePicker({
|
|
|
1469
1607
|
)
|
|
1470
1608
|
] });
|
|
1471
1609
|
}
|
|
1472
|
-
var
|
|
1473
|
-
|
|
1610
|
+
var TIME = /^\d{2}:\d{2}(:\d{2})?$/;
|
|
1611
|
+
var pad3 = (n) => String(n).padStart(2, "0");
|
|
1612
|
+
function toInputValue(value, withSeconds) {
|
|
1613
|
+
if (value === null || value === void 0 || value === "") return "";
|
|
1614
|
+
if (value instanceof Date) {
|
|
1615
|
+
if (Number.isNaN(value.getTime())) return "";
|
|
1616
|
+
const base = `${pad3(value.getHours())}:${pad3(value.getMinutes())}`;
|
|
1617
|
+
return withSeconds ? `${base}:${pad3(value.getSeconds())}` : base;
|
|
1618
|
+
}
|
|
1619
|
+
return TIME.test(value) ? value : "";
|
|
1620
|
+
}
|
|
1621
|
+
var TimePicker = forwardRef(function TimePicker2({ value, onChange, min, max, invalid, size, className = "", step, ...rest }, ref) {
|
|
1622
|
+
const withSeconds = step != null && Number(step) < 60;
|
|
1623
|
+
return /* @__PURE__ */ jsx(
|
|
1624
|
+
"input",
|
|
1625
|
+
{
|
|
1626
|
+
ref,
|
|
1627
|
+
type: "time",
|
|
1628
|
+
step,
|
|
1629
|
+
"aria-invalid": invalid || void 0,
|
|
1630
|
+
value: toInputValue(value, withSeconds),
|
|
1631
|
+
min: toInputValue(min, withSeconds) || void 0,
|
|
1632
|
+
max: toInputValue(max, withSeconds) || void 0,
|
|
1633
|
+
onChange: (event) => onChange?.(TIME.test(event.target.value) ? event.target.value : null),
|
|
1634
|
+
className: inputClasses({ invalid, size, className }),
|
|
1635
|
+
...rest
|
|
1636
|
+
}
|
|
1637
|
+
);
|
|
1638
|
+
});
|
|
1639
|
+
var TimePicker_default = TimePicker;
|
|
1640
|
+
var POPUP_MAX_WIDTH = 448;
|
|
1641
|
+
var MENU_MAX_HEIGHT2 = 240;
|
|
1642
|
+
var MENU_GAP2 = 4;
|
|
1643
|
+
var VIEWPORT_MARGIN2 = 8;
|
|
1644
|
+
function useDropdownPosition(triggerRef, open) {
|
|
1645
|
+
const [pos, setPos] = useState(null);
|
|
1646
|
+
useLayoutEffect(() => {
|
|
1647
|
+
if (!open) {
|
|
1648
|
+
setPos(null);
|
|
1649
|
+
return;
|
|
1650
|
+
}
|
|
1651
|
+
let lastLeft = NaN, lastTop = NaN, lastRight = NaN, lastBottom = NaN;
|
|
1652
|
+
const compute = () => {
|
|
1653
|
+
const rect = triggerRef.current?.getBoundingClientRect();
|
|
1654
|
+
if (!rect) return;
|
|
1655
|
+
lastLeft = rect.left;
|
|
1656
|
+
lastTop = rect.top;
|
|
1657
|
+
lastRight = rect.right;
|
|
1658
|
+
lastBottom = rect.bottom;
|
|
1659
|
+
const spaceBelow = window.innerHeight - rect.bottom - MENU_GAP2 - VIEWPORT_MARGIN2;
|
|
1660
|
+
const spaceAbove = rect.top - MENU_GAP2 - VIEWPORT_MARGIN2;
|
|
1661
|
+
const placeAbove = spaceBelow < Math.min(MENU_MAX_HEIGHT2, 160) && spaceAbove > spaceBelow;
|
|
1662
|
+
const maxHeight = Math.max(96, Math.min(MENU_MAX_HEIGHT2, placeAbove ? spaceAbove : spaceBelow));
|
|
1663
|
+
const next = { minWidth: rect.width, maxHeight };
|
|
1664
|
+
if (window.innerWidth - rect.left < POPUP_MAX_WIDTH) {
|
|
1665
|
+
next.right = Math.max(VIEWPORT_MARGIN2, window.innerWidth - rect.right);
|
|
1666
|
+
} else {
|
|
1667
|
+
next.left = Math.max(VIEWPORT_MARGIN2, rect.left);
|
|
1668
|
+
}
|
|
1669
|
+
if (placeAbove) next.bottom = window.innerHeight - rect.top + MENU_GAP2;
|
|
1670
|
+
else next.top = rect.bottom + MENU_GAP2;
|
|
1671
|
+
setPos(next);
|
|
1672
|
+
};
|
|
1673
|
+
compute();
|
|
1674
|
+
let raf = requestAnimationFrame(function tick() {
|
|
1675
|
+
const rect = triggerRef.current?.getBoundingClientRect();
|
|
1676
|
+
if (rect && (rect.left !== lastLeft || rect.top !== lastTop || rect.right !== lastRight || rect.bottom !== lastBottom)) {
|
|
1677
|
+
compute();
|
|
1678
|
+
}
|
|
1679
|
+
raf = requestAnimationFrame(tick);
|
|
1680
|
+
});
|
|
1681
|
+
window.addEventListener("scroll", compute, true);
|
|
1682
|
+
window.addEventListener("resize", compute);
|
|
1683
|
+
return () => {
|
|
1684
|
+
cancelAnimationFrame(raf);
|
|
1685
|
+
window.removeEventListener("scroll", compute, true);
|
|
1686
|
+
window.removeEventListener("resize", compute);
|
|
1687
|
+
};
|
|
1688
|
+
}, [open, triggerRef]);
|
|
1689
|
+
return pos;
|
|
1690
|
+
}
|
|
1691
|
+
var ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
1692
|
+
var MONTH_NAMES2 = [
|
|
1693
|
+
"January",
|
|
1694
|
+
"February",
|
|
1695
|
+
"March",
|
|
1696
|
+
"April",
|
|
1697
|
+
"May",
|
|
1698
|
+
"June",
|
|
1699
|
+
"July",
|
|
1700
|
+
"August",
|
|
1701
|
+
"September",
|
|
1702
|
+
"October",
|
|
1703
|
+
"November",
|
|
1704
|
+
"December"
|
|
1705
|
+
];
|
|
1706
|
+
function toInputValue2(value) {
|
|
1707
|
+
if (value === null || value === void 0 || value === "") return "";
|
|
1708
|
+
if (value instanceof Date) return Number.isNaN(value.getTime()) ? "" : toISODate(value);
|
|
1709
|
+
if (ISO_DATE.test(value)) return value;
|
|
1710
|
+
const parsed = new Date(value);
|
|
1711
|
+
return Number.isNaN(parsed.getTime()) ? "" : toISODate(parsed);
|
|
1712
|
+
}
|
|
1713
|
+
function fromInputValue(raw) {
|
|
1714
|
+
if (!ISO_DATE.test(raw)) return null;
|
|
1715
|
+
const [year, month, day] = raw.split("-").map(Number);
|
|
1716
|
+
const date = new Date(year, month - 1, day);
|
|
1717
|
+
return date.getMonth() === month - 1 && date.getDate() === day ? date : null;
|
|
1718
|
+
}
|
|
1719
|
+
function display(key) {
|
|
1720
|
+
const d = fromInputValue(key);
|
|
1721
|
+
return d ? `${d.getDate()} ${MONTH_NAMES2[d.getMonth()]} ${d.getFullYear()}` : "";
|
|
1722
|
+
}
|
|
1723
|
+
var DatePicker = forwardRef(function DatePicker2({
|
|
1724
|
+
value,
|
|
1725
|
+
onChange,
|
|
1726
|
+
min,
|
|
1727
|
+
max,
|
|
1728
|
+
invalid,
|
|
1729
|
+
size,
|
|
1730
|
+
native,
|
|
1731
|
+
weekStartsOn,
|
|
1732
|
+
className = "",
|
|
1733
|
+
"aria-label": ariaLabel,
|
|
1734
|
+
"aria-describedby": describedBy,
|
|
1735
|
+
id,
|
|
1736
|
+
name,
|
|
1737
|
+
disabled,
|
|
1738
|
+
placeholder,
|
|
1739
|
+
...rest
|
|
1740
|
+
}, ref) {
|
|
1741
|
+
const current = toInputValue2(value);
|
|
1742
|
+
const lo = toInputValue2(min);
|
|
1743
|
+
const hi = toInputValue2(max);
|
|
1744
|
+
const [open, setOpen] = useState(false);
|
|
1745
|
+
const wrapRef = useRef(null);
|
|
1746
|
+
const triggerRef = useRef(null);
|
|
1747
|
+
const panelRef = useRef(null);
|
|
1748
|
+
const panelId = useId();
|
|
1749
|
+
const pos = useDropdownPosition(triggerRef, open);
|
|
1750
|
+
useEffect(() => {
|
|
1751
|
+
if (!open) return;
|
|
1752
|
+
const onPointerDown = (e) => {
|
|
1753
|
+
const target = e.target;
|
|
1754
|
+
if (wrapRef.current?.contains(target) || panelRef.current?.contains(target)) return;
|
|
1755
|
+
setOpen(false);
|
|
1756
|
+
};
|
|
1757
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
1758
|
+
return () => document.removeEventListener("pointerdown", onPointerDown, true);
|
|
1759
|
+
}, [open]);
|
|
1760
|
+
useEffect(() => {
|
|
1761
|
+
if (!open) return;
|
|
1762
|
+
return registerModalEscapeInterceptor((event) => {
|
|
1763
|
+
if (event.key !== "Escape") return false;
|
|
1764
|
+
setOpen(false);
|
|
1765
|
+
triggerRef.current?.focus();
|
|
1766
|
+
return true;
|
|
1767
|
+
});
|
|
1768
|
+
}, [open]);
|
|
1769
|
+
if (native) {
|
|
1770
|
+
return /* @__PURE__ */ jsx(
|
|
1771
|
+
"input",
|
|
1772
|
+
{
|
|
1773
|
+
ref,
|
|
1774
|
+
type: "date",
|
|
1775
|
+
id,
|
|
1776
|
+
name,
|
|
1777
|
+
disabled,
|
|
1778
|
+
"aria-label": ariaLabel,
|
|
1779
|
+
"aria-describedby": describedBy,
|
|
1780
|
+
"aria-invalid": invalid || void 0,
|
|
1781
|
+
value: current,
|
|
1782
|
+
min: lo || void 0,
|
|
1783
|
+
max: hi || void 0,
|
|
1784
|
+
onChange: (event) => onChange?.(fromInputValue(event.target.value)),
|
|
1785
|
+
className: inputClasses({ invalid, size, className }),
|
|
1786
|
+
...rest
|
|
1787
|
+
}
|
|
1788
|
+
);
|
|
1789
|
+
}
|
|
1790
|
+
return /* @__PURE__ */ jsxs("div", { ref: wrapRef, className: "relative", children: [
|
|
1791
|
+
/* @__PURE__ */ jsx("input", { ref, type: "hidden", name, value: current }),
|
|
1792
|
+
/* @__PURE__ */ jsxs(
|
|
1793
|
+
"button",
|
|
1794
|
+
{
|
|
1795
|
+
ref: triggerRef,
|
|
1796
|
+
type: "button",
|
|
1797
|
+
id,
|
|
1798
|
+
disabled,
|
|
1799
|
+
"aria-haspopup": "dialog",
|
|
1800
|
+
"aria-expanded": open,
|
|
1801
|
+
"aria-controls": open ? panelId : void 0,
|
|
1802
|
+
"aria-describedby": describedBy,
|
|
1803
|
+
"aria-invalid": invalid || void 0,
|
|
1804
|
+
"aria-label": ariaLabel ? `${ariaLabel}${current ? `, ${display(current)}` : ""}` : void 0,
|
|
1805
|
+
onClick: () => setOpen((o) => !o),
|
|
1806
|
+
className: `${inputClasses({ invalid, size, className })} flex items-center justify-between text-left`,
|
|
1807
|
+
children: [
|
|
1808
|
+
/* @__PURE__ */ jsx("span", { className: current ? "text-gray-900" : "text-gray-400", children: current ? display(current) : placeholder ?? "Select a date" }),
|
|
1809
|
+
/* @__PURE__ */ jsx("svg", { className: "h-4 w-4 shrink-0 text-gray-400", fill: "none", stroke: "currentColor", strokeWidth: "1.75", viewBox: "0 0 24 24", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3M4 11h16M5 7h14a1 1 0 011 1v11a1 1 0 01-1 1H5a1 1 0 01-1-1V8a1 1 0 011-1z" }) })
|
|
1810
|
+
]
|
|
1811
|
+
}
|
|
1812
|
+
),
|
|
1813
|
+
open && createPortal(
|
|
1814
|
+
/* @__PURE__ */ jsxs(
|
|
1815
|
+
"div",
|
|
1816
|
+
{
|
|
1817
|
+
ref: panelRef,
|
|
1818
|
+
id: panelId,
|
|
1819
|
+
role: "dialog",
|
|
1820
|
+
"aria-label": ariaLabel ?? "Choose a date",
|
|
1821
|
+
className: "fixed z-[400] w-72 rounded-xl border border-gray-200 bg-white p-3 shadow-lg",
|
|
1822
|
+
style: {
|
|
1823
|
+
left: pos?.left,
|
|
1824
|
+
right: pos?.right,
|
|
1825
|
+
top: pos?.top,
|
|
1826
|
+
bottom: pos?.bottom,
|
|
1827
|
+
// Hidden for the first paint until the layout effect measures the
|
|
1828
|
+
// trigger, so the panel never flashes at (0,0).
|
|
1829
|
+
visibility: pos ? void 0 : "hidden"
|
|
1830
|
+
},
|
|
1831
|
+
children: [
|
|
1832
|
+
/* @__PURE__ */ jsx(
|
|
1833
|
+
Calendar,
|
|
1834
|
+
{
|
|
1835
|
+
value: current || null,
|
|
1836
|
+
min: lo || null,
|
|
1837
|
+
max: hi || null,
|
|
1838
|
+
weekStartsOn,
|
|
1839
|
+
onSelect: (key) => {
|
|
1840
|
+
setOpen(false);
|
|
1841
|
+
triggerRef.current?.focus();
|
|
1842
|
+
onChange?.(fromInputValue(key));
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
),
|
|
1846
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-2 flex justify-between border-t border-gray-100 pt-2", children: [
|
|
1847
|
+
/* @__PURE__ */ jsx(
|
|
1848
|
+
"button",
|
|
1849
|
+
{
|
|
1850
|
+
type: "button",
|
|
1851
|
+
onClick: () => {
|
|
1852
|
+
setOpen(false);
|
|
1853
|
+
triggerRef.current?.focus();
|
|
1854
|
+
onChange?.(null);
|
|
1855
|
+
},
|
|
1856
|
+
className: "rounded-md px-2 py-1 text-sm text-gray-500 hover:bg-gray-100 hover:text-gray-700",
|
|
1857
|
+
children: "Clear"
|
|
1858
|
+
}
|
|
1859
|
+
),
|
|
1860
|
+
/* @__PURE__ */ jsx(
|
|
1861
|
+
"button",
|
|
1862
|
+
{
|
|
1863
|
+
type: "button",
|
|
1864
|
+
onClick: () => {
|
|
1865
|
+
setOpen(false);
|
|
1866
|
+
triggerRef.current?.focus();
|
|
1867
|
+
onChange?.(/* @__PURE__ */ new Date());
|
|
1868
|
+
},
|
|
1869
|
+
className: "rounded-md px-2 py-1 text-sm font-medium text-blue-600 hover:bg-blue-50",
|
|
1870
|
+
children: "Today"
|
|
1871
|
+
}
|
|
1872
|
+
)
|
|
1873
|
+
] })
|
|
1874
|
+
]
|
|
1875
|
+
}
|
|
1876
|
+
),
|
|
1877
|
+
document.body
|
|
1878
|
+
)
|
|
1879
|
+
] });
|
|
1880
|
+
});
|
|
1881
|
+
var DatePicker_default = DatePicker;
|
|
1882
|
+
var ISO_LOCAL = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2})?$/;
|
|
1883
|
+
var pad4 = (n) => String(n).padStart(2, "0");
|
|
1884
|
+
function serialise(date) {
|
|
1885
|
+
return `${date.getFullYear()}-${pad4(date.getMonth() + 1)}-${pad4(date.getDate())}T${pad4(date.getHours())}:${pad4(date.getMinutes())}`;
|
|
1886
|
+
}
|
|
1887
|
+
function toInputValue3(value) {
|
|
1474
1888
|
if (value === null || value === void 0 || value === "") return "";
|
|
1475
|
-
if (value instanceof Date) return Number.isNaN(value.getTime()) ? "" :
|
|
1476
|
-
if (
|
|
1477
|
-
|
|
1478
|
-
return Number.isNaN(parsed.getTime()) ? "" : toISODate(parsed);
|
|
1889
|
+
if (value instanceof Date) return Number.isNaN(value.getTime()) ? "" : serialise(value);
|
|
1890
|
+
if (ISO_LOCAL.test(value)) return value;
|
|
1891
|
+
return "";
|
|
1479
1892
|
}
|
|
1480
|
-
function
|
|
1481
|
-
if (!
|
|
1482
|
-
const [
|
|
1483
|
-
const
|
|
1893
|
+
function fromInputValue2(raw) {
|
|
1894
|
+
if (!ISO_LOCAL.test(raw)) return null;
|
|
1895
|
+
const [datePart, timePart] = raw.split("T");
|
|
1896
|
+
const [year, month, day] = datePart.split("-").map(Number);
|
|
1897
|
+
const [hours, minutes, seconds = 0] = timePart.split(":").map(Number);
|
|
1898
|
+
if (hours > 23 || minutes > 59 || seconds > 59) return null;
|
|
1899
|
+
const date = new Date(year, month - 1, day, hours, minutes, seconds);
|
|
1484
1900
|
return date.getMonth() === month - 1 && date.getDate() === day ? date : null;
|
|
1485
1901
|
}
|
|
1486
|
-
var
|
|
1902
|
+
var DateTimePicker = forwardRef(function DateTimePicker2({ value, onChange, min, max, invalid, size, className = "", ...rest }, ref) {
|
|
1487
1903
|
return /* @__PURE__ */ jsx(
|
|
1488
1904
|
"input",
|
|
1489
1905
|
{
|
|
1490
1906
|
ref,
|
|
1491
|
-
type: "
|
|
1907
|
+
type: "datetime-local",
|
|
1492
1908
|
"aria-invalid": invalid || void 0,
|
|
1493
|
-
value:
|
|
1494
|
-
min:
|
|
1495
|
-
max:
|
|
1496
|
-
onChange: (event) => onChange?.(
|
|
1909
|
+
value: toInputValue3(value),
|
|
1910
|
+
min: toInputValue3(min) || void 0,
|
|
1911
|
+
max: toInputValue3(max) || void 0,
|
|
1912
|
+
onChange: (event) => onChange?.(fromInputValue2(event.target.value)),
|
|
1497
1913
|
className: inputClasses({ invalid, size, className }),
|
|
1498
1914
|
...rest
|
|
1499
1915
|
}
|
|
1500
1916
|
);
|
|
1501
1917
|
});
|
|
1502
|
-
var
|
|
1918
|
+
var DateTimePicker_default = DateTimePicker;
|
|
1503
1919
|
|
|
1504
1920
|
// src/forms/keypadInput.ts
|
|
1505
1921
|
var MAX_FRACTION_DIGITS = 2;
|
|
@@ -1610,8 +2026,8 @@ function Segmented({
|
|
|
1610
2026
|
className = ""
|
|
1611
2027
|
}) {
|
|
1612
2028
|
const groupId = useId();
|
|
1613
|
-
const track = `inline-flex items-center gap-1 rounded-lg bg-gray-100 p-1 ${block ? "w-full" : ""} ${className}`.trim();
|
|
1614
|
-
const itemBase = `inline-flex items-center justify-center gap-1.5 rounded-md font-medium transition-colors ${block ? "flex-1" : ""}`;
|
|
2029
|
+
const track = `inline-flex max-w-full items-center gap-1 overflow-x-auto rounded-lg bg-gray-100 p-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden ${block ? "w-full" : ""} ${className}`.trim();
|
|
2030
|
+
const itemBase = `inline-flex shrink-0 items-center justify-center gap-1.5 whitespace-nowrap rounded-md font-medium transition-colors ${block ? "flex-1" : ""}`;
|
|
1615
2031
|
if (name) {
|
|
1616
2032
|
return /* @__PURE__ */ jsx("div", { role: "radiogroup", "aria-label": label, className: track, children: options.map((opt) => {
|
|
1617
2033
|
const id = `${groupId}-${opt.value}`;
|
|
@@ -1962,57 +2378,6 @@ function FilePicker({
|
|
|
1962
2378
|
error && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-red-600", children: error })
|
|
1963
2379
|
] });
|
|
1964
2380
|
}
|
|
1965
|
-
var POPUP_MAX_WIDTH = 448;
|
|
1966
|
-
var MENU_MAX_HEIGHT2 = 240;
|
|
1967
|
-
var MENU_GAP2 = 4;
|
|
1968
|
-
var VIEWPORT_MARGIN2 = 8;
|
|
1969
|
-
function useDropdownPosition(triggerRef, open) {
|
|
1970
|
-
const [pos, setPos] = useState(null);
|
|
1971
|
-
useLayoutEffect(() => {
|
|
1972
|
-
if (!open) {
|
|
1973
|
-
setPos(null);
|
|
1974
|
-
return;
|
|
1975
|
-
}
|
|
1976
|
-
let lastLeft = NaN, lastTop = NaN, lastRight = NaN, lastBottom = NaN;
|
|
1977
|
-
const compute = () => {
|
|
1978
|
-
const rect = triggerRef.current?.getBoundingClientRect();
|
|
1979
|
-
if (!rect) return;
|
|
1980
|
-
lastLeft = rect.left;
|
|
1981
|
-
lastTop = rect.top;
|
|
1982
|
-
lastRight = rect.right;
|
|
1983
|
-
lastBottom = rect.bottom;
|
|
1984
|
-
const spaceBelow = window.innerHeight - rect.bottom - MENU_GAP2 - VIEWPORT_MARGIN2;
|
|
1985
|
-
const spaceAbove = rect.top - MENU_GAP2 - VIEWPORT_MARGIN2;
|
|
1986
|
-
const placeAbove = spaceBelow < Math.min(MENU_MAX_HEIGHT2, 160) && spaceAbove > spaceBelow;
|
|
1987
|
-
const maxHeight = Math.max(96, Math.min(MENU_MAX_HEIGHT2, placeAbove ? spaceAbove : spaceBelow));
|
|
1988
|
-
const next = { minWidth: rect.width, maxHeight };
|
|
1989
|
-
if (window.innerWidth - rect.left < POPUP_MAX_WIDTH) {
|
|
1990
|
-
next.right = Math.max(VIEWPORT_MARGIN2, window.innerWidth - rect.right);
|
|
1991
|
-
} else {
|
|
1992
|
-
next.left = Math.max(VIEWPORT_MARGIN2, rect.left);
|
|
1993
|
-
}
|
|
1994
|
-
if (placeAbove) next.bottom = window.innerHeight - rect.top + MENU_GAP2;
|
|
1995
|
-
else next.top = rect.bottom + MENU_GAP2;
|
|
1996
|
-
setPos(next);
|
|
1997
|
-
};
|
|
1998
|
-
compute();
|
|
1999
|
-
let raf = requestAnimationFrame(function tick() {
|
|
2000
|
-
const rect = triggerRef.current?.getBoundingClientRect();
|
|
2001
|
-
if (rect && (rect.left !== lastLeft || rect.top !== lastTop || rect.right !== lastRight || rect.bottom !== lastBottom)) {
|
|
2002
|
-
compute();
|
|
2003
|
-
}
|
|
2004
|
-
raf = requestAnimationFrame(tick);
|
|
2005
|
-
});
|
|
2006
|
-
window.addEventListener("scroll", compute, true);
|
|
2007
|
-
window.addEventListener("resize", compute);
|
|
2008
|
-
return () => {
|
|
2009
|
-
cancelAnimationFrame(raf);
|
|
2010
|
-
window.removeEventListener("scroll", compute, true);
|
|
2011
|
-
window.removeEventListener("resize", compute);
|
|
2012
|
-
};
|
|
2013
|
-
}, [open, triggerRef]);
|
|
2014
|
-
return pos;
|
|
2015
|
-
}
|
|
2016
2381
|
function ClearButton({ onClear, ariaLabel = "Clear selection" }) {
|
|
2017
2382
|
return /* @__PURE__ */ jsx(
|
|
2018
2383
|
"button",
|
|
@@ -2162,7 +2527,7 @@ function SearchableSelect({
|
|
|
2162
2527
|
"div",
|
|
2163
2528
|
{
|
|
2164
2529
|
ref: menuRef,
|
|
2165
|
-
className: "fixed z-[
|
|
2530
|
+
className: "fixed z-[10000] rounded-2xl overflow-hidden",
|
|
2166
2531
|
style: {
|
|
2167
2532
|
left: menuPos?.left,
|
|
2168
2533
|
right: menuPos?.right,
|
|
@@ -2199,6 +2564,171 @@ function SearchableSelect({
|
|
|
2199
2564
|
)
|
|
2200
2565
|
] });
|
|
2201
2566
|
}
|
|
2567
|
+
function TagInput({
|
|
2568
|
+
value,
|
|
2569
|
+
onChange,
|
|
2570
|
+
options = [],
|
|
2571
|
+
placeholder,
|
|
2572
|
+
allowFreeText = false,
|
|
2573
|
+
invalid,
|
|
2574
|
+
disabled,
|
|
2575
|
+
id,
|
|
2576
|
+
className = ""
|
|
2577
|
+
}) {
|
|
2578
|
+
const [open, setOpen] = useState(false);
|
|
2579
|
+
const [search, setSearch] = useState("");
|
|
2580
|
+
const wrapRef = useRef(null);
|
|
2581
|
+
const inputRef = useRef(null);
|
|
2582
|
+
const menuRef = useRef(null);
|
|
2583
|
+
const menuPos = useDropdownPosition(wrapRef, open);
|
|
2584
|
+
const labelFor = (v) => options.find((o) => o.value === v)?.label ?? v;
|
|
2585
|
+
const available = useMemo(() => {
|
|
2586
|
+
const seen = new Set(value);
|
|
2587
|
+
const out = [];
|
|
2588
|
+
const q = search.trim().toLowerCase();
|
|
2589
|
+
for (const o of options) {
|
|
2590
|
+
if (seen.has(o.value)) continue;
|
|
2591
|
+
seen.add(o.value);
|
|
2592
|
+
if (!q || o.label.toLowerCase().includes(q)) out.push(o);
|
|
2593
|
+
}
|
|
2594
|
+
return out;
|
|
2595
|
+
}, [options, value, search]);
|
|
2596
|
+
const add = (v) => {
|
|
2597
|
+
if (!v || value.includes(v)) {
|
|
2598
|
+
setSearch("");
|
|
2599
|
+
return;
|
|
2600
|
+
}
|
|
2601
|
+
onChange([...value, v]);
|
|
2602
|
+
setSearch("");
|
|
2603
|
+
};
|
|
2604
|
+
const remove = (v) => onChange(value.filter((x) => x !== v));
|
|
2605
|
+
const commitFreeText = () => {
|
|
2606
|
+
const t = search.trim();
|
|
2607
|
+
if (allowFreeText && t) add(t);
|
|
2608
|
+
else setSearch("");
|
|
2609
|
+
};
|
|
2610
|
+
useEffect(() => {
|
|
2611
|
+
if (!open) return;
|
|
2612
|
+
const handler = (e) => {
|
|
2613
|
+
const t = e.target;
|
|
2614
|
+
if (wrapRef.current?.contains(t) || menuRef.current?.contains(t)) return;
|
|
2615
|
+
commitFreeText();
|
|
2616
|
+
setOpen(false);
|
|
2617
|
+
};
|
|
2618
|
+
document.addEventListener("mousedown", handler);
|
|
2619
|
+
return () => document.removeEventListener("mousedown", handler);
|
|
2620
|
+
});
|
|
2621
|
+
const hasMenu = options.length > 0;
|
|
2622
|
+
return /* @__PURE__ */ jsxs("div", { ref: wrapRef, className: "relative", children: [
|
|
2623
|
+
/* @__PURE__ */ jsxs(
|
|
2624
|
+
"div",
|
|
2625
|
+
{
|
|
2626
|
+
onMouseDown: (e) => {
|
|
2627
|
+
if (disabled) return;
|
|
2628
|
+
if (e.target.closest("button")) return;
|
|
2629
|
+
e.preventDefault();
|
|
2630
|
+
inputRef.current?.focus();
|
|
2631
|
+
},
|
|
2632
|
+
className: inputClasses({
|
|
2633
|
+
invalid,
|
|
2634
|
+
className: `flex flex-wrap items-center gap-1 cursor-text focus-within:border-blue-400 focus-within:ring-2 focus-within:ring-blue-400/30 ${disabled ? "bg-gray-50 cursor-not-allowed" : ""} ${className}`
|
|
2635
|
+
}),
|
|
2636
|
+
children: [
|
|
2637
|
+
value.map((v) => /* @__PURE__ */ jsxs("span", { className: "inline-flex max-w-full items-center gap-1 rounded bg-blue-50 px-1.5 py-0.5 text-xs font-medium text-blue-700", children: [
|
|
2638
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: labelFor(v) }),
|
|
2639
|
+
!disabled && /* @__PURE__ */ jsx(
|
|
2640
|
+
"button",
|
|
2641
|
+
{
|
|
2642
|
+
type: "button",
|
|
2643
|
+
"aria-label": `Remove ${labelFor(v)}`,
|
|
2644
|
+
onClick: () => remove(v),
|
|
2645
|
+
className: "text-blue-400 hover:text-red-500 focus:outline-none focus-visible:ring-1 focus-visible:ring-blue-500 rounded leading-none",
|
|
2646
|
+
children: "\xD7"
|
|
2647
|
+
}
|
|
2648
|
+
)
|
|
2649
|
+
] }, v)),
|
|
2650
|
+
/* @__PURE__ */ jsx(
|
|
2651
|
+
"input",
|
|
2652
|
+
{
|
|
2653
|
+
id,
|
|
2654
|
+
ref: inputRef,
|
|
2655
|
+
type: "text",
|
|
2656
|
+
autoComplete: "off",
|
|
2657
|
+
role: "combobox",
|
|
2658
|
+
"aria-expanded": open && hasMenu,
|
|
2659
|
+
"aria-invalid": invalid || void 0,
|
|
2660
|
+
disabled,
|
|
2661
|
+
value: search,
|
|
2662
|
+
placeholder: value.length === 0 ? placeholder : void 0,
|
|
2663
|
+
onChange: (e) => {
|
|
2664
|
+
setSearch(e.target.value);
|
|
2665
|
+
setOpen(true);
|
|
2666
|
+
},
|
|
2667
|
+
onFocus: () => {
|
|
2668
|
+
if (!disabled && hasMenu) setOpen(true);
|
|
2669
|
+
},
|
|
2670
|
+
onKeyDown: (e) => {
|
|
2671
|
+
if (e.key === "Enter" || e.key === "," && allowFreeText) {
|
|
2672
|
+
e.preventDefault();
|
|
2673
|
+
const q = search.trim();
|
|
2674
|
+
const matches = q ? available.filter((o) => o.label.toLowerCase().includes(q.toLowerCase())) : [];
|
|
2675
|
+
if (matches.length === 1) add(matches[0].value);
|
|
2676
|
+
else commitFreeText();
|
|
2677
|
+
} else if (e.key === "Backspace" && search === "" && value.length > 0) {
|
|
2678
|
+
remove(value[value.length - 1]);
|
|
2679
|
+
} else if (e.key === "Escape") {
|
|
2680
|
+
setOpen(false);
|
|
2681
|
+
setSearch("");
|
|
2682
|
+
inputRef.current?.blur();
|
|
2683
|
+
} else if (e.key === "Tab") {
|
|
2684
|
+
commitFreeText();
|
|
2685
|
+
setOpen(false);
|
|
2686
|
+
}
|
|
2687
|
+
},
|
|
2688
|
+
className: "min-w-[8ch] flex-1 border-none bg-transparent p-0 text-sm text-gray-800 placeholder:text-gray-400 focus:outline-none focus:ring-0 disabled:cursor-not-allowed"
|
|
2689
|
+
}
|
|
2690
|
+
)
|
|
2691
|
+
]
|
|
2692
|
+
}
|
|
2693
|
+
),
|
|
2694
|
+
open && hasMenu && createPortal(
|
|
2695
|
+
/* @__PURE__ */ jsx(
|
|
2696
|
+
"div",
|
|
2697
|
+
{
|
|
2698
|
+
ref: menuRef,
|
|
2699
|
+
className: "fixed z-[10000] rounded-2xl overflow-hidden",
|
|
2700
|
+
style: {
|
|
2701
|
+
left: menuPos?.left,
|
|
2702
|
+
right: menuPos?.right,
|
|
2703
|
+
top: menuPos?.top,
|
|
2704
|
+
bottom: menuPos?.bottom,
|
|
2705
|
+
minWidth: menuPos?.minWidth,
|
|
2706
|
+
maxWidth: POPUP_MAX_WIDTH,
|
|
2707
|
+
width: "max-content",
|
|
2708
|
+
// Hidden for the first paint until the layout effect measures the
|
|
2709
|
+
// trigger, so the menu never flashes at (0,0).
|
|
2710
|
+
visibility: menuPos ? void 0 : "hidden",
|
|
2711
|
+
...glassStyle()
|
|
2712
|
+
},
|
|
2713
|
+
children: /* @__PURE__ */ jsx("div", { className: "overflow-y-auto", style: { maxHeight: menuPos?.maxHeight ?? MENU_MAX_HEIGHT2 }, children: available.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-3 py-3 text-sm text-gray-400 text-center", children: options.length > 0 && value.length >= options.length ? "All options selected" : "No matches" }) : available.map((o) => /* @__PURE__ */ jsx(
|
|
2714
|
+
"button",
|
|
2715
|
+
{
|
|
2716
|
+
type: "button",
|
|
2717
|
+
onMouseDown: (e) => {
|
|
2718
|
+
e.preventDefault();
|
|
2719
|
+
add(o.value);
|
|
2720
|
+
},
|
|
2721
|
+
className: "w-full text-left px-3 py-1.5 text-sm hover:bg-gray-50 text-gray-700 whitespace-nowrap",
|
|
2722
|
+
children: o.label
|
|
2723
|
+
},
|
|
2724
|
+
o.value
|
|
2725
|
+
)) })
|
|
2726
|
+
}
|
|
2727
|
+
),
|
|
2728
|
+
document.body
|
|
2729
|
+
)
|
|
2730
|
+
] });
|
|
2731
|
+
}
|
|
2202
2732
|
var PADDING = {
|
|
2203
2733
|
none: { body: "", edge: "px-4 py-3" },
|
|
2204
2734
|
sm: { body: "p-3", edge: "px-3 py-2" },
|
|
@@ -2482,23 +3012,23 @@ function DescriptionList({
|
|
|
2482
3012
|
const resolved = typeof columns === "number" ? { base: columns } : columns;
|
|
2483
3013
|
const base = resolved.base ?? 1;
|
|
2484
3014
|
const widest = Math.max(base, resolved.sm ?? 0, resolved.lg ?? 0);
|
|
2485
|
-
const
|
|
3015
|
+
const pad5 = size === "sm" ? "px-3 py-2" : "px-4 py-3";
|
|
2486
3016
|
const text = size === "sm" ? "text-xs" : "text-sm";
|
|
2487
3017
|
return /* @__PURE__ */ jsxs("div", { className: [bordered ? "rounded-lg border border-gray-200 bg-white" : "", className].filter(Boolean).join(" "), children: [
|
|
2488
|
-
title && /* @__PURE__ */ jsx("div", { className: `${
|
|
3018
|
+
title && /* @__PURE__ */ jsx("div", { className: `${pad5} ${bordered ? "border-b border-gray-100" : ""} text-sm font-semibold text-gray-900`.trim(), children: title }),
|
|
2489
3019
|
/* @__PURE__ */ jsx("dl", { className: [
|
|
2490
3020
|
"grid",
|
|
2491
3021
|
COLS2[base],
|
|
2492
3022
|
resolved.sm ? SM[resolved.sm] : "",
|
|
2493
3023
|
resolved.lg ? LG[resolved.lg] : "",
|
|
2494
3024
|
bordered ? "" : "gap-x-6 gap-y-3",
|
|
2495
|
-
bordered ? "" :
|
|
3025
|
+
bordered ? "" : pad5 === "px-4 py-3" ? "py-1" : ""
|
|
2496
3026
|
].filter(Boolean).join(" "), children: items.map((item, i) => /* @__PURE__ */ jsxs(
|
|
2497
3027
|
"div",
|
|
2498
3028
|
{
|
|
2499
3029
|
className: [
|
|
2500
3030
|
item.span ? SPAN[widest] : "",
|
|
2501
|
-
bordered ? `${
|
|
3031
|
+
bordered ? `${pad5} border-b border-gray-100 last:border-b-0` : ""
|
|
2502
3032
|
].filter(Boolean).join(" "),
|
|
2503
3033
|
children: [
|
|
2504
3034
|
/* @__PURE__ */ jsx("dt", { className: `${text} text-gray-500`, children: item.label }),
|
|
@@ -2867,6 +3397,69 @@ function Tabs({
|
|
|
2867
3397
|
}
|
|
2868
3398
|
);
|
|
2869
3399
|
}
|
|
3400
|
+
var Check = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 12 12", fill: "none", className: "h-3.5 w-3.5", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M2.5 6.5L5 9l4.5-5", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
3401
|
+
function Stepper({
|
|
3402
|
+
items,
|
|
3403
|
+
value,
|
|
3404
|
+
onChange,
|
|
3405
|
+
"aria-label": ariaLabel,
|
|
3406
|
+
className = ""
|
|
3407
|
+
}) {
|
|
3408
|
+
const currentIndex = Math.max(0, items.findIndex((s) => s.id === value));
|
|
3409
|
+
return /* @__PURE__ */ jsx("ol", { "aria-label": ariaLabel, className: `flex items-start ${className}`.trim(), children: items.map((step, i) => {
|
|
3410
|
+
const state = i < currentIndex ? "complete" : i === currentIndex ? "current" : "upcoming";
|
|
3411
|
+
const clickable = state === "complete" && !!onChange;
|
|
3412
|
+
const circle = /* @__PURE__ */ jsx(
|
|
3413
|
+
"span",
|
|
3414
|
+
{
|
|
3415
|
+
"aria-hidden": "true",
|
|
3416
|
+
className: [
|
|
3417
|
+
"flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-xs font-semibold transition-colors",
|
|
3418
|
+
state === "complete" ? "bg-blue-600 text-white" : "",
|
|
3419
|
+
state === "current" ? "border-2 border-blue-600 bg-white text-blue-600" : "",
|
|
3420
|
+
state === "upcoming" ? "border-2 border-gray-300 bg-white text-gray-400" : ""
|
|
3421
|
+
].filter(Boolean).join(" "),
|
|
3422
|
+
children: state === "complete" ? /* @__PURE__ */ jsx(Check, {}) : i + 1
|
|
3423
|
+
}
|
|
3424
|
+
);
|
|
3425
|
+
const text = /* @__PURE__ */ jsxs("span", { className: "min-w-0", children: [
|
|
3426
|
+
/* @__PURE__ */ jsx("span", { className: `block text-sm font-medium ${state === "upcoming" ? "text-gray-400" : "text-gray-900"}`, children: step.label }),
|
|
3427
|
+
step.description && /* @__PURE__ */ jsx("span", { className: "block text-xs text-gray-500", children: step.description })
|
|
3428
|
+
] });
|
|
3429
|
+
return /* @__PURE__ */ jsxs(
|
|
3430
|
+
"li",
|
|
3431
|
+
{
|
|
3432
|
+
"aria-current": state === "current" ? "step" : void 0,
|
|
3433
|
+
className: `flex items-start gap-2 ${i > 0 ? "flex-1" : ""}`,
|
|
3434
|
+
children: [
|
|
3435
|
+
i > 0 && /* @__PURE__ */ jsx(
|
|
3436
|
+
"span",
|
|
3437
|
+
{
|
|
3438
|
+
"aria-hidden": "true",
|
|
3439
|
+
className: `mt-3.5 h-0.5 flex-1 rounded ${i <= currentIndex ? "bg-blue-600" : "bg-gray-200"}`
|
|
3440
|
+
}
|
|
3441
|
+
),
|
|
3442
|
+
clickable ? /* @__PURE__ */ jsxs(
|
|
3443
|
+
"button",
|
|
3444
|
+
{
|
|
3445
|
+
type: "button",
|
|
3446
|
+
onClick: () => onChange?.(step.id),
|
|
3447
|
+
className: "flex items-start gap-2 text-left rounded focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-400",
|
|
3448
|
+
children: [
|
|
3449
|
+
circle,
|
|
3450
|
+
text
|
|
3451
|
+
]
|
|
3452
|
+
}
|
|
3453
|
+
) : /* @__PURE__ */ jsxs("span", { className: "flex items-start gap-2", children: [
|
|
3454
|
+
circle,
|
|
3455
|
+
text
|
|
3456
|
+
] })
|
|
3457
|
+
]
|
|
3458
|
+
},
|
|
3459
|
+
step.id
|
|
3460
|
+
);
|
|
3461
|
+
}) });
|
|
3462
|
+
}
|
|
2870
3463
|
function Accordion({
|
|
2871
3464
|
items,
|
|
2872
3465
|
defaultOpenIds = [],
|
|
@@ -3287,8 +3880,8 @@ function formatDate(value) {
|
|
|
3287
3880
|
const dd = String(d).padStart(2, "0");
|
|
3288
3881
|
const mm = String(m).padStart(2, "0");
|
|
3289
3882
|
const yyyy = String(y);
|
|
3290
|
-
const
|
|
3291
|
-
switch (
|
|
3883
|
+
const fmt2 = getUserDateFormat();
|
|
3884
|
+
switch (fmt2) {
|
|
3292
3885
|
case "MM/DD/YYYY":
|
|
3293
3886
|
return `${mm}/${dd}/${yyyy}`;
|
|
3294
3887
|
case "YYYY-MM-DD":
|
|
@@ -4189,12 +4782,28 @@ function DropdownMenu({
|
|
|
4189
4782
|
)
|
|
4190
4783
|
] });
|
|
4191
4784
|
}
|
|
4192
|
-
var
|
|
4785
|
+
var SIZE_CLASS = {
|
|
4786
|
+
sm: "sm:w-[320px]",
|
|
4787
|
+
md: "sm:w-[448px]",
|
|
4788
|
+
lg: "sm:w-[640px]"
|
|
4789
|
+
};
|
|
4193
4790
|
var SIDE_POSITION = {
|
|
4194
4791
|
right: "inset-y-0 right-0",
|
|
4195
4792
|
left: "inset-y-0 left-0",
|
|
4196
4793
|
bottom: "inset-x-0 bottom-0"
|
|
4197
4794
|
};
|
|
4795
|
+
function CloseButton({ onClose }) {
|
|
4796
|
+
return /* @__PURE__ */ jsx(
|
|
4797
|
+
"button",
|
|
4798
|
+
{
|
|
4799
|
+
type: "button",
|
|
4800
|
+
onClick: onClose,
|
|
4801
|
+
"aria-label": "Close",
|
|
4802
|
+
className: "rounded-md p-1 text-gray-400 hover:bg-gray-100 hover:text-gray-600 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-400",
|
|
4803
|
+
children: /* @__PURE__ */ jsx("svg", { className: "h-5 w-5", viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M6 6l8 8M14 6l-8 8" }) })
|
|
4804
|
+
}
|
|
4805
|
+
);
|
|
4806
|
+
}
|
|
4198
4807
|
function Drawer({
|
|
4199
4808
|
open,
|
|
4200
4809
|
onClose,
|
|
@@ -4205,10 +4814,12 @@ function Drawer({
|
|
|
4205
4814
|
children,
|
|
4206
4815
|
blocking = false,
|
|
4207
4816
|
initialFocus,
|
|
4817
|
+
"aria-label": ariaLabel,
|
|
4208
4818
|
className = ""
|
|
4209
4819
|
}) {
|
|
4210
4820
|
const panelRef = useRef(null);
|
|
4211
4821
|
const bodyId = useId();
|
|
4822
|
+
const titleId = useId();
|
|
4212
4823
|
useFocusTrap(panelRef, open, initialFocus);
|
|
4213
4824
|
useScrollLock(open);
|
|
4214
4825
|
useEffect(() => {
|
|
@@ -4221,7 +4832,7 @@ function Drawer({
|
|
|
4221
4832
|
}, [open, blocking, onClose]);
|
|
4222
4833
|
if (!open) return null;
|
|
4223
4834
|
const isBottom = side === "bottom";
|
|
4224
|
-
const panelStyle = isBottom ? { maxHeight: "85vh" } :
|
|
4835
|
+
const panelStyle = isBottom ? { maxHeight: "85vh" } : void 0;
|
|
4225
4836
|
return /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-[9999]", role: "presentation", children: [
|
|
4226
4837
|
/* @__PURE__ */ jsx("div", { className: "fixed inset-0 bg-black/30", onClick: blocking ? void 0 : onClose, "aria-hidden": "true" }),
|
|
4227
4838
|
/* @__PURE__ */ jsxs(
|
|
@@ -4230,29 +4841,27 @@ function Drawer({
|
|
|
4230
4841
|
ref: panelRef,
|
|
4231
4842
|
role: "dialog",
|
|
4232
4843
|
"aria-modal": "true",
|
|
4233
|
-
"aria-
|
|
4844
|
+
"aria-labelledby": title ? titleId : void 0,
|
|
4845
|
+
"aria-label": title ? void 0 : ariaLabel,
|
|
4234
4846
|
"aria-describedby": children ? bodyId : void 0,
|
|
4235
4847
|
style: panelStyle,
|
|
4236
4848
|
className: [
|
|
4237
4849
|
"fixed flex flex-col bg-white shadow-xl",
|
|
4850
|
+
// Full width on a phone, the asked-for width from `sm` up. A 320px
|
|
4851
|
+
// drawer on a 375px screen leaves a 55px strip of scrim: too narrow
|
|
4852
|
+
// to aim at, too wide to read as an edge, and it makes the panel look
|
|
4853
|
+
// like a desktop rail that was squeezed rather than a sheet built for
|
|
4854
|
+
// the screen it is on.
|
|
4855
|
+
isBottom ? "" : `w-full max-w-full ${SIZE_CLASS[size]}`,
|
|
4238
4856
|
SIDE_POSITION[side],
|
|
4239
4857
|
isBottom ? "rounded-t-xl" : "",
|
|
4240
4858
|
className
|
|
4241
4859
|
].filter(Boolean).join(" "),
|
|
4242
4860
|
children: [
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
!blocking && /* @__PURE__ */ jsx(
|
|
4246
|
-
|
|
4247
|
-
{
|
|
4248
|
-
type: "button",
|
|
4249
|
-
onClick: onClose,
|
|
4250
|
-
"aria-label": "Close",
|
|
4251
|
-
className: "rounded-md p-1 text-gray-400 hover:bg-gray-100 hover:text-gray-600",
|
|
4252
|
-
children: /* @__PURE__ */ jsx("svg", { className: "h-5 w-5", viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M6 6l8 8M14 6l-8 8" }) })
|
|
4253
|
-
}
|
|
4254
|
-
)
|
|
4255
|
-
] }),
|
|
4861
|
+
title ? /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center justify-between gap-4 border-b border-gray-100 px-4 py-3", children: [
|
|
4862
|
+
/* @__PURE__ */ jsx("h2", { id: titleId, className: "text-base font-semibold text-gray-900", children: title }),
|
|
4863
|
+
!blocking && /* @__PURE__ */ jsx(CloseButton, { onClose })
|
|
4864
|
+
] }) : !blocking && /* @__PURE__ */ jsx("div", { className: "absolute right-2 top-2 z-10", children: /* @__PURE__ */ jsx(CloseButton, { onClose }) }),
|
|
4256
4865
|
/* @__PURE__ */ jsx("div", { id: bodyId, className: "min-h-0 flex-1 overflow-y-auto px-4 py-4", children }),
|
|
4257
4866
|
footer && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 justify-end gap-3 border-t border-gray-100 px-4 py-3", children: footer })
|
|
4258
4867
|
]
|
|
@@ -4664,9 +5273,28 @@ function DataTable({
|
|
|
4664
5273
|
onRow,
|
|
4665
5274
|
emptyText = "Nothing to show",
|
|
4666
5275
|
footer,
|
|
5276
|
+
virtualized,
|
|
4667
5277
|
className = ""
|
|
4668
5278
|
}) {
|
|
4669
5279
|
const keyOf = (row, i) => typeof rowKey === "function" ? rowKey(row, i) : String(row[rowKey]);
|
|
5280
|
+
const [startRow, setStartRow] = useState(0);
|
|
5281
|
+
const overscan = virtualized?.overscan ?? 6;
|
|
5282
|
+
const onBodyScroll = virtualized ? (e) => {
|
|
5283
|
+
const next = Math.max(0, Math.floor(e.currentTarget.scrollTop / virtualized.rowHeight) - overscan);
|
|
5284
|
+
setStartRow((prev) => prev === next ? prev : next);
|
|
5285
|
+
} : void 0;
|
|
5286
|
+
const windowSize = virtualized ? Math.ceil(virtualized.height / virtualized.rowHeight) + overscan * 2 : data.length;
|
|
5287
|
+
const start = virtualized ? Math.min(startRow, Math.max(0, data.length - windowSize)) : 0;
|
|
5288
|
+
const end = Math.min(data.length, start + windowSize);
|
|
5289
|
+
const topPad = virtualized ? start * virtualized.rowHeight : 0;
|
|
5290
|
+
const bottomPad = virtualized ? (data.length - end) * virtualized.rowHeight : 0;
|
|
5291
|
+
const headRowRef = useRef(null);
|
|
5292
|
+
const [headRowH, setHeadRowH] = useState(0);
|
|
5293
|
+
useLayoutEffect(() => {
|
|
5294
|
+
if (!virtualized) return;
|
|
5295
|
+
const h = headRowRef.current?.offsetHeight ?? 0;
|
|
5296
|
+
setHeadRowH((prev) => prev === h ? prev : h);
|
|
5297
|
+
});
|
|
4670
5298
|
const fieldOf = (col) => col.sortField ?? col.key;
|
|
4671
5299
|
const directionFor = (col) => sort && sort.field === fieldOf(col) ? sort.direction : null;
|
|
4672
5300
|
const toggleSort = (col) => {
|
|
@@ -4682,7 +5310,7 @@ function DataTable({
|
|
|
4682
5310
|
const leaves = columns.flatMap((h) => isGroup(h) ? h.columns : [h]);
|
|
4683
5311
|
const grouped = columns.some(isGroup);
|
|
4684
5312
|
const cellBase = `${PAD[size]} ${size === "sm" ? "text-xs" : "text-sm"}`;
|
|
4685
|
-
const headerCell = (col, ci, rowSpan) => {
|
|
5313
|
+
const headerCell = (col, ci, rowSpan, topOffset = 0) => {
|
|
4686
5314
|
const dir = directionFor(col);
|
|
4687
5315
|
const align = ALIGN2[col.align ?? (col.numeric ? "right" : "left")];
|
|
4688
5316
|
const pinned = col.fixed === "left";
|
|
@@ -4692,13 +5320,20 @@ function DataTable({
|
|
|
4692
5320
|
scope: "col",
|
|
4693
5321
|
rowSpan: rowSpan > 1 ? rowSpan : void 0,
|
|
4694
5322
|
"aria-sort": dir === "asc" ? "ascending" : dir === "desc" ? "descending" : col.sortable && onSortChange ? "none" : void 0,
|
|
4695
|
-
style: {
|
|
5323
|
+
style: {
|
|
5324
|
+
width: col.width,
|
|
5325
|
+
...pinned ? { left: offsets[ci] ?? 0 } : {},
|
|
5326
|
+
// A virtualized header pins to the top of the vertical scroll; one
|
|
5327
|
+
// sticky box can hold both axes, so a pinned column's header corner
|
|
5328
|
+
// stays put in both directions.
|
|
5329
|
+
...virtualized ? { top: topOffset } : {}
|
|
5330
|
+
},
|
|
4696
5331
|
className: [
|
|
4697
5332
|
cellBase,
|
|
4698
5333
|
align,
|
|
4699
5334
|
"font-semibold uppercase tracking-wide text-gray-500",
|
|
4700
5335
|
size === "sm" ? "text-[10px]" : "text-xs",
|
|
4701
|
-
pinned ? "sticky z-10 bg-gray-50" : "",
|
|
5336
|
+
pinned ? virtualized ? "sticky z-20 bg-gray-50" : "sticky z-10 bg-gray-50" : virtualized ? "sticky z-10 bg-gray-50" : "",
|
|
4702
5337
|
col.headerClassName ?? ""
|
|
4703
5338
|
].filter(Boolean).join(" "),
|
|
4704
5339
|
children: col.sortable && onSortChange ? /* @__PURE__ */ jsxs(
|
|
@@ -4725,92 +5360,108 @@ function DataTable({
|
|
|
4725
5360
|
return at;
|
|
4726
5361
|
});
|
|
4727
5362
|
return /* @__PURE__ */ jsxs("div", { className, children: [
|
|
4728
|
-
/* @__PURE__ */ jsxs(
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
"
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
const rowProps = onRow?.(row, i);
|
|
4767
|
-
return /* @__PURE__ */ jsx(
|
|
4768
|
-
"tr",
|
|
4769
|
-
{
|
|
4770
|
-
onClick: rowProps?.onClick,
|
|
4771
|
-
...rowProps?.onClick ? {
|
|
4772
|
-
tabIndex: 0,
|
|
4773
|
-
onKeyDown: (e) => {
|
|
4774
|
-
if (e.target !== e.currentTarget) return;
|
|
4775
|
-
if (e.key !== "Enter" && e.key !== " ") return;
|
|
4776
|
-
e.preventDefault();
|
|
4777
|
-
rowProps.onClick?.();
|
|
5363
|
+
/* @__PURE__ */ jsxs(
|
|
5364
|
+
"div",
|
|
5365
|
+
{
|
|
5366
|
+
onScroll: onBodyScroll,
|
|
5367
|
+
style: virtualized ? { maxHeight: virtualized.height } : void 0,
|
|
5368
|
+
className: `relative overflow-x-auto ${virtualized ? "overflow-y-auto" : ""} ${bordered ? "rounded-lg border border-gray-200" : ""}`.trim(),
|
|
5369
|
+
children: [
|
|
5370
|
+
loading && // An overlay rather than replacing the rows: the table keeps its
|
|
5371
|
+
// height and its scroll position, so re-sorting does not throw the
|
|
5372
|
+
// page around under the user.
|
|
5373
|
+
/* @__PURE__ */ jsxs("div", { className: "absolute inset-0 z-20 flex items-start justify-center bg-white/60 pt-8", role: "status", "aria-live": "polite", children: [
|
|
5374
|
+
/* @__PURE__ */ jsx("span", { className: "h-6 w-6 animate-spin rounded-full border-2 border-gray-200 border-t-blue-600" }),
|
|
5375
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Loading" })
|
|
5376
|
+
] }),
|
|
5377
|
+
/* @__PURE__ */ jsxs("table", { className: "w-full border-collapse tabular-nums", style: minWidth ? { minWidth } : void 0, children: [
|
|
5378
|
+
caption && /* @__PURE__ */ jsx("caption", { className: "sr-only", children: caption }),
|
|
5379
|
+
/* @__PURE__ */ jsxs("thead", { children: [
|
|
5380
|
+
/* @__PURE__ */ jsx("tr", { ref: headRowRef, className: "border-b border-gray-200 bg-gray-50", children: columns.map((h, hi) => {
|
|
5381
|
+
if (isGroup(h)) {
|
|
5382
|
+
return /* @__PURE__ */ jsx(
|
|
5383
|
+
"th",
|
|
5384
|
+
{
|
|
5385
|
+
scope: "colgroup",
|
|
5386
|
+
colSpan: h.columns.length,
|
|
5387
|
+
style: virtualized ? { top: 0 } : void 0,
|
|
5388
|
+
className: [
|
|
5389
|
+
cellBase,
|
|
5390
|
+
"text-center",
|
|
5391
|
+
"font-semibold uppercase tracking-wide text-gray-500",
|
|
5392
|
+
size === "sm" ? "text-[10px]" : "text-xs",
|
|
5393
|
+
"border-b border-gray-200",
|
|
5394
|
+
virtualized ? "sticky z-10 bg-gray-50" : "",
|
|
5395
|
+
h.headerClassName ?? ""
|
|
5396
|
+
].filter(Boolean).join(" "),
|
|
5397
|
+
children: h.title
|
|
5398
|
+
},
|
|
5399
|
+
h.key ?? `group-${hi}`
|
|
5400
|
+
);
|
|
4778
5401
|
}
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
children: leaves.
|
|
4787
|
-
|
|
5402
|
+
return headerCell(h, leaves.indexOf(h), grouped ? 2 : 1);
|
|
5403
|
+
}) }),
|
|
5404
|
+
grouped && /* @__PURE__ */ jsx("tr", { className: "border-b border-gray-200 bg-gray-50", children: columns.flatMap((h) => isGroup(h) ? h.columns : []).map(
|
|
5405
|
+
(col) => headerCell(col, leaves.indexOf(col), 1, headRowH)
|
|
5406
|
+
) })
|
|
5407
|
+
] }),
|
|
5408
|
+
/* @__PURE__ */ jsx("tbody", { children: data.length === 0 && !loading ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: leaves.length, className: `${cellBase} py-10 text-center text-gray-500`, children: emptyText }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5409
|
+
topPad > 0 && /* @__PURE__ */ jsx("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx("td", { colSpan: leaves.length, style: { height: topPad, padding: 0, border: 0 } }) }),
|
|
5410
|
+
data.slice(start, end).map((row, si) => {
|
|
5411
|
+
const i = start + si;
|
|
5412
|
+
const rowProps = onRow?.(row, i);
|
|
4788
5413
|
return /* @__PURE__ */ jsx(
|
|
4789
|
-
"
|
|
5414
|
+
"tr",
|
|
4790
5415
|
{
|
|
4791
|
-
style:
|
|
5416
|
+
style: virtualized ? { height: virtualized.rowHeight } : void 0,
|
|
5417
|
+
onClick: rowProps?.onClick,
|
|
5418
|
+
...rowProps?.onClick ? {
|
|
5419
|
+
tabIndex: 0,
|
|
5420
|
+
onKeyDown: (e) => {
|
|
5421
|
+
if (e.target !== e.currentTarget) return;
|
|
5422
|
+
if (e.key !== "Enter" && e.key !== " ") return;
|
|
5423
|
+
e.preventDefault();
|
|
5424
|
+
rowProps.onClick?.();
|
|
5425
|
+
}
|
|
5426
|
+
} : {},
|
|
4792
5427
|
className: [
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
"
|
|
4797
|
-
col.ellipsis ? "max-w-0 truncate" : "",
|
|
4798
|
-
// A pinned cell needs its own background or the
|
|
4799
|
-
// scrolling columns show through it.
|
|
4800
|
-
pinned ? "sticky z-10 bg-white" : ""
|
|
5428
|
+
"border-b border-gray-100 last:border-b-0",
|
|
5429
|
+
rowProps?.onClick ? "cursor-pointer hover:bg-gray-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-blue-400" : "",
|
|
5430
|
+
rowClassName?.(row, i) ?? "",
|
|
5431
|
+
rowProps?.className ?? ""
|
|
4801
5432
|
].filter(Boolean).join(" "),
|
|
4802
|
-
children:
|
|
5433
|
+
children: leaves.map((col, ci) => {
|
|
5434
|
+
const pinned = col.fixed === "left";
|
|
5435
|
+
return /* @__PURE__ */ jsx(
|
|
5436
|
+
"td",
|
|
5437
|
+
{
|
|
5438
|
+
style: pinned ? { left: offsets[ci] ?? 0 } : void 0,
|
|
5439
|
+
className: [
|
|
5440
|
+
cellBase,
|
|
5441
|
+
ALIGN2[col.align ?? (col.numeric ? "right" : "left")],
|
|
5442
|
+
col.numeric ? "font-mono" : "",
|
|
5443
|
+
"text-gray-900",
|
|
5444
|
+
col.ellipsis ? "max-w-0 truncate" : "",
|
|
5445
|
+
// A pinned cell needs its own background or the
|
|
5446
|
+
// scrolling columns show through it.
|
|
5447
|
+
pinned ? "sticky z-10 bg-white" : ""
|
|
5448
|
+
].filter(Boolean).join(" "),
|
|
5449
|
+
children: col.render ? col.render(row, i) : col.dataIndex ? row[col.dataIndex] : null
|
|
5450
|
+
},
|
|
5451
|
+
col.key
|
|
5452
|
+
);
|
|
5453
|
+
})
|
|
4803
5454
|
},
|
|
4804
|
-
|
|
5455
|
+
keyOf(row, i)
|
|
4805
5456
|
);
|
|
4806
|
-
})
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
)
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
5457
|
+
}),
|
|
5458
|
+
bottomPad > 0 && /* @__PURE__ */ jsx("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx("td", { colSpan: leaves.length, style: { height: bottomPad, padding: 0, border: 0 } }) })
|
|
5459
|
+
] }) })
|
|
5460
|
+
] }),
|
|
5461
|
+
footer
|
|
5462
|
+
]
|
|
5463
|
+
}
|
|
5464
|
+
),
|
|
4814
5465
|
pagination && pagination.pageCount > 1 && /* @__PURE__ */ jsx("div", { className: "mt-3 flex justify-end", children: /* @__PURE__ */ jsx(
|
|
4815
5466
|
Pagination,
|
|
4816
5467
|
{
|
|
@@ -4867,8 +5518,8 @@ function Sparkline({
|
|
|
4867
5518
|
const max = Math.max(...data);
|
|
4868
5519
|
const min = Math.min(...data);
|
|
4869
5520
|
const span = max - min || 1;
|
|
4870
|
-
const
|
|
4871
|
-
const y = (v) => height -
|
|
5521
|
+
const pad5 = strokeWidth + (showDots ? 2 : 0);
|
|
5522
|
+
const y = (v) => height - pad5 - (v - min) / span * (height - pad5 * 2);
|
|
4872
5523
|
const pts = data.length === 1 ? [[0, height / 2], [width, height / 2]] : data.map((v, i) => [i * width / (data.length - 1), y(v)]);
|
|
4873
5524
|
const line = pts.map(([x, yy], i) => `${i === 0 ? "M" : "L"}${x.toFixed(2)},${yy.toFixed(2)}`).join(" ");
|
|
4874
5525
|
const area = `${line} L${width.toFixed(2)},${height} L0,${height} Z`;
|
|
@@ -4960,6 +5611,73 @@ function DonutChart({ segments, size = 120, thickness = 16, centerLabel, classNa
|
|
|
4960
5611
|
}
|
|
4961
5612
|
);
|
|
4962
5613
|
}
|
|
5614
|
+
function toPoints(data, min, span) {
|
|
5615
|
+
if (data.length === 1) return [[0, 100 - (data[0] - min) / span * 100], [100, 100 - (data[0] - min) / span * 100]];
|
|
5616
|
+
return data.map((v, i) => [i * 100 / (data.length - 1), 100 - (v - min) / span * 100]);
|
|
5617
|
+
}
|
|
5618
|
+
function pathFor(pts) {
|
|
5619
|
+
return pts.map(([x, y], i) => `${i === 0 ? "M" : "L"}${x.toFixed(2)},${y.toFixed(2)}`).join(" ");
|
|
5620
|
+
}
|
|
5621
|
+
var fmt = (v) => Number.isInteger(v) ? String(v) : v.toFixed(1);
|
|
5622
|
+
function LineChart({
|
|
5623
|
+
series,
|
|
5624
|
+
labels,
|
|
5625
|
+
height = 160,
|
|
5626
|
+
strokeWidth = 2,
|
|
5627
|
+
showDots = false,
|
|
5628
|
+
max,
|
|
5629
|
+
min,
|
|
5630
|
+
showScale = false,
|
|
5631
|
+
showLegend = false,
|
|
5632
|
+
className,
|
|
5633
|
+
style
|
|
5634
|
+
}) {
|
|
5635
|
+
const drawn = series.filter((s) => s.data.length > 0);
|
|
5636
|
+
if (drawn.length === 0) return null;
|
|
5637
|
+
const all = drawn.flatMap((s) => s.data);
|
|
5638
|
+
const top = max ?? Math.max(...all);
|
|
5639
|
+
const bottom = min ?? Math.min(...all);
|
|
5640
|
+
const span = top - bottom || 1;
|
|
5641
|
+
const color = (s) => s.color ?? "currentColor";
|
|
5642
|
+
return /* @__PURE__ */ jsxs("div", { className, style, children: [
|
|
5643
|
+
showLegend && drawn.some((s) => s.label) && /* @__PURE__ */ jsx("div", { className: "mb-1.5 flex flex-wrap items-center gap-x-3 gap-y-0.5", children: drawn.map((s, i) => s.label && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-xs text-gray-500", children: [
|
|
5644
|
+
/* @__PURE__ */ jsx("span", { className: "h-2 w-2 rounded-full", style: { backgroundColor: color(s) } }),
|
|
5645
|
+
s.label
|
|
5646
|
+
] }, i)) }),
|
|
5647
|
+
/* @__PURE__ */ jsxs("div", { className: "flex", children: [
|
|
5648
|
+
showScale && /* @__PURE__ */ jsxs("div", { className: "flex flex-col justify-between pr-1.5 text-right text-[10px] leading-none text-gray-400", style: { height }, children: [
|
|
5649
|
+
/* @__PURE__ */ jsx("span", { children: fmt(top) }),
|
|
5650
|
+
/* @__PURE__ */ jsx("span", { children: fmt(bottom + span / 2) }),
|
|
5651
|
+
/* @__PURE__ */ jsx("span", { children: fmt(bottom) })
|
|
5652
|
+
] }),
|
|
5653
|
+
/* @__PURE__ */ jsxs(
|
|
5654
|
+
"svg",
|
|
5655
|
+
{
|
|
5656
|
+
className: "min-w-0 flex-1",
|
|
5657
|
+
width: "100%",
|
|
5658
|
+
height,
|
|
5659
|
+
viewBox: "0 0 100 100",
|
|
5660
|
+
preserveAspectRatio: "none",
|
|
5661
|
+
role: "img",
|
|
5662
|
+
"aria-hidden": "true",
|
|
5663
|
+
children: [
|
|
5664
|
+
showScale && [0, 50, 100].map((y) => /* @__PURE__ */ jsx("line", { x1: 0, y1: y, x2: 100, y2: y, stroke: "currentColor", strokeOpacity: 0.12, strokeWidth: 1, vectorEffect: "non-scaling-stroke" }, y)),
|
|
5665
|
+
drawn.map((s, si) => {
|
|
5666
|
+
const pts = toPoints(s.data, bottom, span);
|
|
5667
|
+
const line = pathFor(pts);
|
|
5668
|
+
return /* @__PURE__ */ jsxs("g", { children: [
|
|
5669
|
+
s.fill && /* @__PURE__ */ jsx("path", { d: `${line} L100,100 L0,100 Z`, fill: s.fill, stroke: "none" }),
|
|
5670
|
+
/* @__PURE__ */ jsx("path", { d: line, fill: "none", stroke: color(s), strokeWidth, strokeLinejoin: "round", strokeLinecap: "round", vectorEffect: "non-scaling-stroke" }),
|
|
5671
|
+
showDots && s.data.length > 1 && pts.map(([x, y], i) => /* @__PURE__ */ jsx("path", { d: `M${x.toFixed(2)},${y.toFixed(2)} h0.01`, stroke: color(s), strokeWidth: strokeWidth * 2.5, strokeLinecap: "round", vectorEffect: "non-scaling-stroke", children: /* @__PURE__ */ jsx("title", { children: `${labels?.[i] != null ? `${labels[i]}: ` : ""}${s.label ? `${s.label} ` : ""}${s.data[i]}` }) }, i))
|
|
5672
|
+
] }, si);
|
|
5673
|
+
})
|
|
5674
|
+
]
|
|
5675
|
+
}
|
|
5676
|
+
)
|
|
5677
|
+
] }),
|
|
5678
|
+
labels && /* @__PURE__ */ jsx("div", { className: `mt-1 flex justify-between ${showScale ? "pl-6" : ""}`, children: labels.map((l, i) => /* @__PURE__ */ jsx("div", { className: "truncate text-[10px] text-gray-400", children: l }, i)) })
|
|
5679
|
+
] });
|
|
5680
|
+
}
|
|
4963
5681
|
var STATUS_GROUPS = {
|
|
4964
5682
|
paid: "success",
|
|
4965
5683
|
shipped: "active",
|
|
@@ -5703,6 +6421,6 @@ var ALT_SHIFT_D = isMac ? "\u2325\u21E7D" : "Alt+Shift+D";
|
|
|
5703
6421
|
var ALT_SHIFT_E = isMac ? "\u2325\u21E7E" : "Alt+Shift+E";
|
|
5704
6422
|
var ALT_SHIFT_N = isMac ? "\u2325\u21E7N" : "Alt+Shift+N";
|
|
5705
6423
|
|
|
5706
|
-
export { ALT, ALT_SHIFT_D, ALT_SHIFT_E, ALT_SHIFT_N, Accordion, AuthScreen, Avatar, AvatarGroup, Banner, BarChart, Button_default, CMD_A, CMD_DOT, CMD_ENTER, CMD_K, CMD_S, CMD_SHIFT_Z, CMD_Z, Card, ChatTemplate, Checkbox_default, CheckoutTemplate, ColoredBadge, ContainerFillChart, CountBadge, DashboardTemplate, DataTable, DataTablePage, DatePicker_default, DateRangePicker, DescriptionList, Divider, DonutChart, Drawer, DropdownMenu, ENTER, EmailTemplate, EmptyState, ErrorBoundary, ErrorPage, FilePicker, FormField, FormLayoutPage, GROUP_COLORS, GalleryTemplate, GlobalSearch, Grid, HelpCenter, INPUT_BASE, INPUT_SIZES, IconButton_default, Inline, InputNumber_default, Input_default, Kanban, Label, ListFooter, ListLoadError, LoadingSpinner, MAX_FRACTION_DIGITS, MOD, Markdown, MediaUploadField, MediaUploadGrid, MetricBar, MilestoneTimeline, NativeSelect, NumericKeypad, PageHeader, Pagination, Paragraph, Radio_default, Result, SHIFT, SearchableSelect, Segmented, Select_default, SidebarActionButton, SidebarGroupLabel, SidebarNavItem, Skeleton, Sparkline, Stack, StatCard, Statistic, StatusBadge, StatusBadgeProvider, Switch_default, Tabs, Text, Textarea_default, TileButton_default, Title, Tooltip, TopNav, appendKey, applyThemePrefs, backspace, firstEnabledIndex, formatDate, inputClasses, isMac, isSeverityTone, lastEnabledIndex, matchTypeahead, mediaFileName, nextEnabledIndex, resolveTheme, severityOf, tabButtonId, tabPanelId, toISODate, useClickOutside, useTheme };
|
|
5707
|
-
//# sourceMappingURL=chunk-
|
|
5708
|
-
//# sourceMappingURL=chunk-
|
|
6424
|
+
export { ALT, ALT_SHIFT_D, ALT_SHIFT_E, ALT_SHIFT_N, Accordion, AuthScreen, Avatar, AvatarGroup, Banner, BarChart, Button_default, CMD_A, CMD_DOT, CMD_ENTER, CMD_K, CMD_S, CMD_SHIFT_Z, CMD_Z, Calendar, Card, ChatTemplate, Checkbox_default, CheckoutTemplate, ColoredBadge, ContainerFillChart, CountBadge, DashboardTemplate, DataTable, DataTablePage, DatePicker_default, DateRangePicker, DateTimePicker_default, DescriptionList, Divider, DonutChart, Drawer, DropdownMenu, ENTER, EmailTemplate, EmptyState, ErrorBoundary, ErrorPage, FilePicker, FormField, FormLayoutPage, GROUP_COLORS, GalleryTemplate, GlobalSearch, Grid, HelpCenter, INPUT_BASE, INPUT_SIZES, IconButton_default, Inline, InputNumber_default, Input_default, Kanban, Label, LineChart, ListFooter, ListLoadError, LoadingSpinner, MAX_FRACTION_DIGITS, MOD, Markdown, MediaUploadField, MediaUploadGrid, MetricBar, MilestoneTimeline, NativeSelect, NumericKeypad, PageHeader, Pagination, Paragraph, Radio_default, Result, SHIFT, SearchableSelect, Segmented, Select_default, SidebarActionButton, SidebarGroupLabel, SidebarNavItem, Skeleton, Sparkline, Stack, StatCard, Statistic, StatusBadge, StatusBadgeProvider, Stepper, Switch_default, Tabs, TagInput, Text, Textarea_default, TileButton_default, TimePicker_default, Title, Tooltip, TopNav, appendKey, applyThemePrefs, backspace, firstEnabledIndex, formatDate, fromKey, inputClasses, isMac, isSeverityTone, lastEnabledIndex, matchTypeahead, mediaFileName, nextEnabledIndex, resolveTheme, severityOf, tabButtonId, tabPanelId, toISODate, toKey, useClickOutside, useTheme };
|
|
6425
|
+
//# sourceMappingURL=chunk-B3IYV7JN.js.map
|
|
6426
|
+
//# sourceMappingURL=chunk-B3IYV7JN.js.map
|