react-os-shell 4.63.0 → 4.74.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 +3 -0
- package/dist/{Browser-SPTNLEMR.js → Browser-ZF5X2FON.js} +7 -7
- package/dist/{Browser-SPTNLEMR.js.map → Browser-ZF5X2FON.js.map} +1 -1
- package/dist/{Calculator-XMOPPCK3.js → Calculator-SA62H5S3.js} +6 -6
- package/dist/{Calculator-XMOPPCK3.js.map → Calculator-SA62H5S3.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-24HNX6C6.js → CurrencyConverter-BMCRLZLY.js} +6 -6
- package/dist/{CurrencyConverter-24HNX6C6.js.map → CurrencyConverter-BMCRLZLY.js.map} +1 -1
- package/dist/{Documents-GMRVVCH7.js → Documents-2TGJPV2Y.js} +8 -8
- package/dist/{Documents-GMRVVCH7.js.map → Documents-2TGJPV2Y.js.map} +1 -1
- package/dist/{Files-ITH4SVML.js → Files-Z3ONKUA6.js} +9 -9
- package/dist/{Files-ITH4SVML.js.map → Files-Z3ONKUA6.js.map} +1 -1
- package/dist/{Notepad-GE5P55TL.js → Notepad-JWZS5YKJ.js} +8 -8
- package/dist/{Notepad-GE5P55TL.js.map → Notepad-JWZS5YKJ.js.map} +1 -1
- package/dist/{PomodoroTimer-ER5STVKM.js → PomodoroTimer-DRM5W25H.js} +8 -8
- package/dist/{PomodoroTimer-ER5STVKM.js.map → PomodoroTimer-DRM5W25H.js.map} +1 -1
- package/dist/{Preview-UXVDXCDJ.js → Preview-7O7W7OMQ.js} +9 -9
- package/dist/{Preview-UXVDXCDJ.js.map → Preview-7O7W7OMQ.js.map} +1 -1
- package/dist/{Spreadsheet-B32JQVX4.js → Spreadsheet-CLTZSW3T.js} +7 -7
- package/dist/{Spreadsheet-B32JQVX4.js.map → Spreadsheet-CLTZSW3T.js.map} +1 -1
- package/dist/{Stock-FSFPFDQT.js → Stock-CO5N3N2M.js} +6 -6
- package/dist/{Stock-FSFPFDQT.js.map → Stock-CO5N3N2M.js.map} +1 -1
- package/dist/{Weather-HXOERJJV.js → Weather-IEGJX7RI.js} +6 -6
- package/dist/{Weather-HXOERJJV.js.map → Weather-IEGJX7RI.js.map} +1 -1
- package/dist/{WorldClock-2FUGLIUZ.js → WorldClock-FLW3QZYG.js} +6 -6
- package/dist/{WorldClock-2FUGLIUZ.js.map → WorldClock-FLW3QZYG.js.map} +1 -1
- package/dist/apps/index.js +17 -17
- package/dist/{chunk-TK6HI2U4.js → chunk-2VM2FRZJ.js} +42 -11
- package/dist/chunk-2VM2FRZJ.js.map +1 -0
- package/dist/{chunk-ECE3B3FZ.js → chunk-AXWC3332.js} +3 -3
- package/dist/{chunk-ECE3B3FZ.js.map → chunk-AXWC3332.js.map} +1 -1
- package/dist/{chunk-ZCDFNZQS.js → chunk-BLLINYDD.js} +97 -5
- package/dist/chunk-BLLINYDD.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-TO6ZZHJK.js → chunk-EG3WEQBH.js} +4 -4
- package/dist/{chunk-TO6ZZHJK.js.map → chunk-EG3WEQBH.js.map} +1 -1
- package/dist/{chunk-JMESET3G.js → chunk-G7IHPEJE.js} +138 -39
- package/dist/chunk-G7IHPEJE.js.map +1 -0
- package/dist/chunk-NJDH5PHA.js +7 -0
- package/dist/{chunk-WCGHIJZR.js.map → chunk-NJDH5PHA.js.map} +1 -1
- package/dist/{chunk-LYQVLRWQ.js → chunk-RUAZJ54W.js} +3 -3
- package/dist/{chunk-LYQVLRWQ.js.map → chunk-RUAZJ54W.js.map} +1 -1
- package/dist/{chunk-CWA27IGB.js → chunk-S6K37RLY.js} +781 -344
- package/dist/chunk-S6K37RLY.js.map +1 -0
- package/dist/{chunk-IOCOH2QQ.js → chunk-TT2WNTDS.js} +4 -4
- package/dist/{chunk-IOCOH2QQ.js.map → chunk-TT2WNTDS.js.map} +1 -1
- package/dist/{chunk-3OCL3DB4.js → chunk-TT56U4GY.js} +3 -3
- package/dist/{chunk-3OCL3DB4.js.map → chunk-TT56U4GY.js.map} +1 -1
- package/dist/{index-Ka32s3Ij.d.ts → index-DVekeidu.d.ts} +258 -27
- package/dist/index.d.ts +2 -2
- package/dist/index.js +121 -35
- package/dist/index.js.map +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +5 -5
- package/package.json +2 -2
- package/dist/ConfirmDialog-EEH4CWSW.js +0 -3
- package/dist/chunk-CWA27IGB.js.map +0 -1
- package/dist/chunk-JMESET3G.js.map +0 -1
- package/dist/chunk-OXLLRKBC.js.map +0 -1
- package/dist/chunk-TK6HI2U4.js.map +0 -1
- package/dist/chunk-WCGHIJZR.js +0 -7
- package/dist/chunk-ZCDFNZQS.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
|
-
import { useIsMobile, PopupMenu, PopupMenuItem, useShellPrefs } from './chunk-
|
|
4
|
-
import { registerModalEscapeInterceptor, useFocusTrap, useScrollLock } from './chunk-
|
|
3
|
+
import { useIsMobile, useShellStrings, PopupMenu, PopupMenuItem, useShellPrefs } from './chunk-BLLINYDD.js';
|
|
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()
|
|
@@ -638,6 +639,47 @@ function FormField({
|
|
|
638
639
|
) : hint ? /* @__PURE__ */ jsx("p", { id: htmlFor ? `${htmlFor}-hint` : void 0, className: "mt-1 text-[11px] text-gray-400", children: hint }) : null
|
|
639
640
|
] });
|
|
640
641
|
}
|
|
642
|
+
function FormErrorSummary({ errors, title, autoFocus = true, className = "" }) {
|
|
643
|
+
const strings = useShellStrings();
|
|
644
|
+
const boxRef = useRef(null);
|
|
645
|
+
const hadErrors = useRef(false);
|
|
646
|
+
useEffect(() => {
|
|
647
|
+
const has = errors.length > 0;
|
|
648
|
+
if (has && !hadErrors.current && autoFocus) boxRef.current?.focus();
|
|
649
|
+
hadErrors.current = has;
|
|
650
|
+
}, [errors.length > 0, autoFocus]);
|
|
651
|
+
if (errors.length === 0) return null;
|
|
652
|
+
const focusField = (fieldId) => {
|
|
653
|
+
const el = document.getElementById(fieldId);
|
|
654
|
+
if (!el) return;
|
|
655
|
+
el.scrollIntoView({ block: "center" });
|
|
656
|
+
el.focus();
|
|
657
|
+
};
|
|
658
|
+
return /* @__PURE__ */ jsxs(
|
|
659
|
+
"div",
|
|
660
|
+
{
|
|
661
|
+
ref: boxRef,
|
|
662
|
+
role: "alert",
|
|
663
|
+
tabIndex: -1,
|
|
664
|
+
className: `rounded-md border border-red-300 bg-red-50 px-4 py-3 focus:outline-none focus-visible:ring-2 focus-visible:ring-red-400 ${className}`.trim(),
|
|
665
|
+
children: [
|
|
666
|
+
/* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold text-red-800", children: title ?? strings.form.errorSummaryTitle }),
|
|
667
|
+
/* @__PURE__ */ jsx("ul", { className: "mt-1.5 space-y-1", children: errors.map((e, i) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
|
|
668
|
+
"a",
|
|
669
|
+
{
|
|
670
|
+
href: `#${e.fieldId}`,
|
|
671
|
+
onClick: (event) => {
|
|
672
|
+
event.preventDefault();
|
|
673
|
+
focusField(e.fieldId);
|
|
674
|
+
},
|
|
675
|
+
className: "text-sm text-red-700 underline hover:text-red-900",
|
|
676
|
+
children: e.message
|
|
677
|
+
}
|
|
678
|
+
) }, `${e.fieldId}-${i}`)) })
|
|
679
|
+
]
|
|
680
|
+
}
|
|
681
|
+
);
|
|
682
|
+
}
|
|
641
683
|
function Label({ required, children, className = "", ...rest }) {
|
|
642
684
|
return /* @__PURE__ */ jsxs("label", { className: `mb-1 block text-xs font-medium text-gray-600 ${className}`.trim(), ...rest, children: [
|
|
643
685
|
children,
|
|
@@ -1098,6 +1140,273 @@ function MediaUploadGrid({
|
|
|
1098
1140
|
}
|
|
1099
1141
|
) });
|
|
1100
1142
|
}
|
|
1143
|
+
var MONTH_NAMES = [
|
|
1144
|
+
"January",
|
|
1145
|
+
"February",
|
|
1146
|
+
"March",
|
|
1147
|
+
"April",
|
|
1148
|
+
"May",
|
|
1149
|
+
"June",
|
|
1150
|
+
"July",
|
|
1151
|
+
"August",
|
|
1152
|
+
"September",
|
|
1153
|
+
"October",
|
|
1154
|
+
"November",
|
|
1155
|
+
"December"
|
|
1156
|
+
];
|
|
1157
|
+
var DAY_NAMES = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
1158
|
+
var DAY_SHORT = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
1159
|
+
var pad = (n) => String(n).padStart(2, "0");
|
|
1160
|
+
function toKey(d) {
|
|
1161
|
+
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
1162
|
+
}
|
|
1163
|
+
function fromKey(key) {
|
|
1164
|
+
if (!key) return null;
|
|
1165
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(key);
|
|
1166
|
+
if (!m) return null;
|
|
1167
|
+
const d = new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));
|
|
1168
|
+
return Number.isNaN(d.getTime()) ? null : d;
|
|
1169
|
+
}
|
|
1170
|
+
var monthKey = (d) => `${d.getFullYear()}-${pad(d.getMonth() + 1)}`;
|
|
1171
|
+
var YEARS_PER_PAGE = 12;
|
|
1172
|
+
var yearPageStart = (y) => Math.floor(y / YEARS_PER_PAGE) * YEARS_PER_PAGE;
|
|
1173
|
+
function monthStart(key) {
|
|
1174
|
+
const m = /^(\d{4})-(\d{2})$/.exec(key);
|
|
1175
|
+
return m ? new Date(Number(m[1]), Number(m[2]) - 1, 1) : /* @__PURE__ */ new Date();
|
|
1176
|
+
}
|
|
1177
|
+
function buildCells(view, weekStartsOn) {
|
|
1178
|
+
const first = new Date(view.getFullYear(), view.getMonth(), 1);
|
|
1179
|
+
const lead = (first.getDay() - weekStartsOn + 7) % 7;
|
|
1180
|
+
const start = new Date(first.getFullYear(), first.getMonth(), 1 - lead);
|
|
1181
|
+
return Array.from({ length: 42 }, (_, i) => new Date(start.getFullYear(), start.getMonth(), start.getDate() + i));
|
|
1182
|
+
}
|
|
1183
|
+
var addDays = (d, n) => new Date(d.getFullYear(), d.getMonth(), d.getDate() + n);
|
|
1184
|
+
var addMonths = (d, n) => {
|
|
1185
|
+
const target = new Date(d.getFullYear(), d.getMonth() + n, 1);
|
|
1186
|
+
const lastDay = new Date(target.getFullYear(), target.getMonth() + 1, 0).getDate();
|
|
1187
|
+
return new Date(target.getFullYear(), target.getMonth(), Math.min(d.getDate(), lastDay));
|
|
1188
|
+
};
|
|
1189
|
+
function Calendar({
|
|
1190
|
+
value,
|
|
1191
|
+
endValue,
|
|
1192
|
+
mode = "single",
|
|
1193
|
+
onSelect,
|
|
1194
|
+
min,
|
|
1195
|
+
max,
|
|
1196
|
+
month,
|
|
1197
|
+
defaultMonth,
|
|
1198
|
+
onMonthChange,
|
|
1199
|
+
weekStartsOn = 0,
|
|
1200
|
+
quickJump = true,
|
|
1201
|
+
"aria-label": ariaLabel,
|
|
1202
|
+
className = ""
|
|
1203
|
+
}) {
|
|
1204
|
+
const selected = fromKey(value);
|
|
1205
|
+
const today = /* @__PURE__ */ new Date();
|
|
1206
|
+
const todayKey = toKey(today);
|
|
1207
|
+
const [innerMonth, setInnerMonth] = useState(() => {
|
|
1208
|
+
if (defaultMonth) return defaultMonth;
|
|
1209
|
+
if (selected) return monthKey(selected);
|
|
1210
|
+
const here = monthKey(today);
|
|
1211
|
+
if (min && here < min.slice(0, 7)) return min.slice(0, 7);
|
|
1212
|
+
if (max && here > max.slice(0, 7)) return max.slice(0, 7);
|
|
1213
|
+
return here;
|
|
1214
|
+
});
|
|
1215
|
+
const viewMonth = month ?? innerMonth;
|
|
1216
|
+
const view = monthStart(viewMonth);
|
|
1217
|
+
const [active, setActive] = useState(() => value ?? todayKey);
|
|
1218
|
+
const gridRef = useRef(null);
|
|
1219
|
+
const shouldFocus = useRef(false);
|
|
1220
|
+
const [panel, setPanel] = useState("days");
|
|
1221
|
+
const cells = useMemo(() => buildCells(view, weekStartsOn), [viewMonth, weekStartsOn]);
|
|
1222
|
+
const outOfRange = (key) => !!min && key < min || !!max && key > max;
|
|
1223
|
+
const activeInView = cells.some((c) => toKey(c) === active);
|
|
1224
|
+
const fallbackActive = toKey(cells.find((c) => c.getMonth() === view.getMonth()) ?? cells[0]);
|
|
1225
|
+
const activeKey = activeInView ? active : fallbackActive;
|
|
1226
|
+
useEffect(() => {
|
|
1227
|
+
if (!shouldFocus.current) return;
|
|
1228
|
+
shouldFocus.current = false;
|
|
1229
|
+
gridRef.current?.querySelector('[data-active="true"]')?.focus();
|
|
1230
|
+
}, [activeKey, viewMonth]);
|
|
1231
|
+
const pageBy = (n) => {
|
|
1232
|
+
if (panel === "years") return new Date(view.getFullYear() + n * YEARS_PER_PAGE, view.getMonth(), 1);
|
|
1233
|
+
if (panel === "months") return new Date(view.getFullYear() + n, view.getMonth(), 1);
|
|
1234
|
+
return addMonths(view, n);
|
|
1235
|
+
};
|
|
1236
|
+
const pageBack = () => pageBy(-1);
|
|
1237
|
+
const pageForward = () => pageBy(1);
|
|
1238
|
+
const goToMonth = (next) => {
|
|
1239
|
+
const key = monthKey(next);
|
|
1240
|
+
if (month === void 0) setInnerMonth(key);
|
|
1241
|
+
onMonthChange?.(key);
|
|
1242
|
+
};
|
|
1243
|
+
const moveTo = (next) => {
|
|
1244
|
+
shouldFocus.current = true;
|
|
1245
|
+
setActive(toKey(next));
|
|
1246
|
+
if (monthKey(next) !== viewMonth) goToMonth(next);
|
|
1247
|
+
};
|
|
1248
|
+
const onKeyDown = (e) => {
|
|
1249
|
+
const current = fromKey(activeKey) ?? today;
|
|
1250
|
+
const step = {
|
|
1251
|
+
ArrowLeft: () => addDays(current, -1),
|
|
1252
|
+
ArrowRight: () => addDays(current, 1),
|
|
1253
|
+
ArrowUp: () => addDays(current, -7),
|
|
1254
|
+
ArrowDown: () => addDays(current, 7),
|
|
1255
|
+
// Home and End are the week, not the month: the grid's rows are weeks, and
|
|
1256
|
+
// this is what the ARIA date-grid pattern asks for.
|
|
1257
|
+
Home: () => addDays(current, -((current.getDay() - weekStartsOn + 7) % 7)),
|
|
1258
|
+
End: () => addDays(current, 6 - (current.getDay() - weekStartsOn + 7) % 7),
|
|
1259
|
+
PageUp: () => addMonths(current, e.shiftKey ? -12 : -1),
|
|
1260
|
+
PageDown: () => addMonths(current, e.shiftKey ? 12 : 1)
|
|
1261
|
+
};
|
|
1262
|
+
if (step[e.key]) {
|
|
1263
|
+
e.preventDefault();
|
|
1264
|
+
moveTo(step[e.key]());
|
|
1265
|
+
return;
|
|
1266
|
+
}
|
|
1267
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1268
|
+
e.preventDefault();
|
|
1269
|
+
if (!outOfRange(activeKey)) onSelect(activeKey);
|
|
1270
|
+
}
|
|
1271
|
+
};
|
|
1272
|
+
const inRange = (key) => {
|
|
1273
|
+
if (mode !== "range" || !value || !endValue) return false;
|
|
1274
|
+
return key > value && key < endValue;
|
|
1275
|
+
};
|
|
1276
|
+
const label = ariaLabel ?? `${MONTH_NAMES[view.getMonth()]} ${view.getFullYear()}`;
|
|
1277
|
+
return /* @__PURE__ */ jsxs("div", { className, children: [
|
|
1278
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between px-1", children: [
|
|
1279
|
+
/* @__PURE__ */ jsx(
|
|
1280
|
+
"button",
|
|
1281
|
+
{
|
|
1282
|
+
type: "button",
|
|
1283
|
+
"aria-label": panel === "years" ? "Previous years" : panel === "months" ? "Previous year" : "Previous month",
|
|
1284
|
+
onClick: () => goToMonth(pageBack()),
|
|
1285
|
+
className: "rounded-full p-1 text-gray-600 hover:bg-gray-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-400",
|
|
1286
|
+
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" }) })
|
|
1287
|
+
}
|
|
1288
|
+
),
|
|
1289
|
+
/* @__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: [
|
|
1290
|
+
panel !== "years" && /* @__PURE__ */ jsx(
|
|
1291
|
+
"button",
|
|
1292
|
+
{
|
|
1293
|
+
type: "button",
|
|
1294
|
+
"aria-label": `Choose a month, currently ${MONTH_NAMES[view.getMonth()]}`,
|
|
1295
|
+
onClick: () => setPanel((p) => p === "months" ? "days" : "months"),
|
|
1296
|
+
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",
|
|
1297
|
+
children: MONTH_NAMES[view.getMonth()]
|
|
1298
|
+
}
|
|
1299
|
+
),
|
|
1300
|
+
/* @__PURE__ */ jsx(
|
|
1301
|
+
"button",
|
|
1302
|
+
{
|
|
1303
|
+
type: "button",
|
|
1304
|
+
"aria-label": `Choose a year, currently ${view.getFullYear()}`,
|
|
1305
|
+
onClick: () => setPanel((p) => p === "years" ? "days" : "years"),
|
|
1306
|
+
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",
|
|
1307
|
+
children: view.getFullYear()
|
|
1308
|
+
}
|
|
1309
|
+
)
|
|
1310
|
+
] }) : /* @__PURE__ */ jsxs("span", { children: [
|
|
1311
|
+
MONTH_NAMES[view.getMonth()],
|
|
1312
|
+
" ",
|
|
1313
|
+
view.getFullYear()
|
|
1314
|
+
] }) }),
|
|
1315
|
+
/* @__PURE__ */ jsx(
|
|
1316
|
+
"button",
|
|
1317
|
+
{
|
|
1318
|
+
type: "button",
|
|
1319
|
+
"aria-label": panel === "years" ? "Next years" : panel === "months" ? "Next year" : "Next month",
|
|
1320
|
+
onClick: () => goToMonth(pageForward()),
|
|
1321
|
+
className: "rounded-full p-1 text-gray-600 hover:bg-gray-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-400",
|
|
1322
|
+
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" }) })
|
|
1323
|
+
}
|
|
1324
|
+
)
|
|
1325
|
+
] }),
|
|
1326
|
+
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(
|
|
1327
|
+
"button",
|
|
1328
|
+
{
|
|
1329
|
+
type: "button",
|
|
1330
|
+
"aria-pressed": m === view.getMonth(),
|
|
1331
|
+
onClick: () => {
|
|
1332
|
+
goToMonth(new Date(view.getFullYear(), m, 1));
|
|
1333
|
+
setPanel("days");
|
|
1334
|
+
},
|
|
1335
|
+
className: [
|
|
1336
|
+
"rounded-md py-4 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-400",
|
|
1337
|
+
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"
|
|
1338
|
+
].join(" "),
|
|
1339
|
+
children: name.slice(0, 3)
|
|
1340
|
+
},
|
|
1341
|
+
name
|
|
1342
|
+
)) }),
|
|
1343
|
+
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(
|
|
1344
|
+
"button",
|
|
1345
|
+
{
|
|
1346
|
+
type: "button",
|
|
1347
|
+
"aria-pressed": y === view.getFullYear(),
|
|
1348
|
+
onClick: () => {
|
|
1349
|
+
goToMonth(new Date(y, view.getMonth(), 1));
|
|
1350
|
+
setPanel("months");
|
|
1351
|
+
},
|
|
1352
|
+
className: [
|
|
1353
|
+
"rounded-md py-4 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-400",
|
|
1354
|
+
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"
|
|
1355
|
+
].join(" "),
|
|
1356
|
+
children: y
|
|
1357
|
+
},
|
|
1358
|
+
y
|
|
1359
|
+
)) }),
|
|
1360
|
+
/* @__PURE__ */ jsxs(
|
|
1361
|
+
"div",
|
|
1362
|
+
{
|
|
1363
|
+
ref: gridRef,
|
|
1364
|
+
role: "grid",
|
|
1365
|
+
"aria-label": label,
|
|
1366
|
+
onKeyDown,
|
|
1367
|
+
hidden: panel !== "days",
|
|
1368
|
+
children: [
|
|
1369
|
+
/* @__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) => (
|
|
1370
|
+
// abbr carries the full name: "Su" is read as a word otherwise.
|
|
1371
|
+
/* @__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)
|
|
1372
|
+
)) }),
|
|
1373
|
+
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) => {
|
|
1374
|
+
const key = toKey(cell);
|
|
1375
|
+
const outside = cell.getMonth() !== view.getMonth();
|
|
1376
|
+
const isSelected = key === value || mode === "range" && key === endValue;
|
|
1377
|
+
const between = inRange(key);
|
|
1378
|
+
const disabled = outOfRange(key);
|
|
1379
|
+
return /* @__PURE__ */ jsx("div", { role: "gridcell", "aria-selected": isSelected, children: /* @__PURE__ */ jsx(
|
|
1380
|
+
"button",
|
|
1381
|
+
{
|
|
1382
|
+
type: "button",
|
|
1383
|
+
"data-active": key === activeKey,
|
|
1384
|
+
tabIndex: key === activeKey ? 0 : -1,
|
|
1385
|
+
disabled,
|
|
1386
|
+
"aria-label": `${cell.getDate()} ${MONTH_NAMES[cell.getMonth()]} ${cell.getFullYear()}`,
|
|
1387
|
+
"aria-current": key === todayKey ? "date" : void 0,
|
|
1388
|
+
onClick: () => {
|
|
1389
|
+
setActive(key);
|
|
1390
|
+
onSelect(key);
|
|
1391
|
+
},
|
|
1392
|
+
className: [
|
|
1393
|
+
// 44px below `sm`, compact above it. A 32px cell is under
|
|
1394
|
+
// every touch-target guideline there is, and a date grid
|
|
1395
|
+
// is seven of them side by side — the case where missing
|
|
1396
|
+
// by four pixels picks the wrong day rather than nothing.
|
|
1397
|
+
"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",
|
|
1398
|
+
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",
|
|
1399
|
+
key === todayKey && !isSelected ? "font-semibold text-blue-600" : ""
|
|
1400
|
+
].filter(Boolean).join(" "),
|
|
1401
|
+
children: cell.getDate()
|
|
1402
|
+
}
|
|
1403
|
+
) }, key);
|
|
1404
|
+
}) }, row))
|
|
1405
|
+
]
|
|
1406
|
+
}
|
|
1407
|
+
)
|
|
1408
|
+
] });
|
|
1409
|
+
}
|
|
1101
1410
|
function useClickOutside(ref, onClose) {
|
|
1102
1411
|
useEffect(() => {
|
|
1103
1412
|
const handler = (e) => {
|
|
@@ -1108,10 +1417,8 @@ function useClickOutside(ref, onClose) {
|
|
|
1108
1417
|
}, [ref, onClose]);
|
|
1109
1418
|
}
|
|
1110
1419
|
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");
|
|
1420
|
+
var monthKeyOf = (d) => `${d.getFullYear()}-${pad2(d.getMonth() + 1)}`;
|
|
1421
|
+
var pad2 = (n) => String(n).padStart(2, "0");
|
|
1115
1422
|
var EDGE_MARGIN = 8;
|
|
1116
1423
|
function clipBounds(el) {
|
|
1117
1424
|
for (let node = el.parentElement; node; node = node.parentElement) {
|
|
@@ -1125,7 +1432,7 @@ function clipBounds(el) {
|
|
|
1125
1432
|
return { left: 0, right: window.innerWidth };
|
|
1126
1433
|
}
|
|
1127
1434
|
function toISODate(d) {
|
|
1128
|
-
return `${d.getFullYear()}-${
|
|
1435
|
+
return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
|
|
1129
1436
|
}
|
|
1130
1437
|
function parseDate(s) {
|
|
1131
1438
|
const [y, m, d] = s.split("-").map(Number);
|
|
@@ -1151,10 +1458,7 @@ function DateRangePicker({
|
|
|
1151
1458
|
const panelRef = useRef(null);
|
|
1152
1459
|
const [align, setAlign] = useState("left");
|
|
1153
1460
|
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));
|
|
1461
|
+
const [viewMonth, setViewMonth] = useState(() => monthKeyOf(from ? parseDate(from) : now));
|
|
1158
1462
|
const displayDate = (s) => s ? formatDisplay(s) : "";
|
|
1159
1463
|
useClickOutside(ref, useCallback(() => {
|
|
1160
1464
|
if (open) setOpen(false);
|
|
@@ -1179,11 +1483,7 @@ function DateRangePicker({
|
|
|
1179
1483
|
setTempFrom(from);
|
|
1180
1484
|
setTempTo(to);
|
|
1181
1485
|
setActivePreset(null);
|
|
1182
|
-
|
|
1183
|
-
setMonth(anchor.getMonth());
|
|
1184
|
-
setYear(anchor.getFullYear());
|
|
1185
|
-
setYearPage(yearPageStart(anchor.getFullYear()));
|
|
1186
|
-
setView("days");
|
|
1486
|
+
setViewMonth(monthKeyOf(from ? parseDate(from) : now));
|
|
1187
1487
|
setOpen(true);
|
|
1188
1488
|
};
|
|
1189
1489
|
const handlePreset = (label) => {
|
|
@@ -1216,10 +1516,7 @@ function DateRangePicker({
|
|
|
1216
1516
|
setTempFrom(toISODate(start));
|
|
1217
1517
|
setTempTo(toISODate(end));
|
|
1218
1518
|
setActivePreset(label);
|
|
1219
|
-
|
|
1220
|
-
setYear(start.getFullYear());
|
|
1221
|
-
setYearPage(yearPageStart(start.getFullYear()));
|
|
1222
|
-
setView("days");
|
|
1519
|
+
setViewMonth(monthKeyOf(start));
|
|
1223
1520
|
};
|
|
1224
1521
|
const handleCalendarSelect = (date) => {
|
|
1225
1522
|
setActivePreset("Custom");
|
|
@@ -1243,57 +1540,6 @@ function DateRangePicker({
|
|
|
1243
1540
|
onChange("", "");
|
|
1244
1541
|
setOpen(false);
|
|
1245
1542
|
};
|
|
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
1543
|
const displayText = from && to ? `${displayDate(from)} \u2014 ${displayDate(to)}` : from ? `From ${displayDate(from)}` : to ? `To ${displayDate(to)}` : "";
|
|
1298
1544
|
return /* @__PURE__ */ jsxs("div", { className: "relative", ref, children: [
|
|
1299
1545
|
/* @__PURE__ */ jsxs(
|
|
@@ -1349,85 +1595,18 @@ function DateRangePicker({
|
|
|
1349
1595
|
] })
|
|
1350
1596
|
] }),
|
|
1351
1597
|
/* @__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
|
-
] }),
|
|
1598
|
+
/* @__PURE__ */ jsx("div", { className: "w-64", children: /* @__PURE__ */ jsx(
|
|
1599
|
+
Calendar,
|
|
1600
|
+
{
|
|
1601
|
+
mode: "range",
|
|
1602
|
+
value: tempFrom || null,
|
|
1603
|
+
endValue: tempTo || null,
|
|
1604
|
+
month: viewMonth,
|
|
1605
|
+
onMonthChange: setViewMonth,
|
|
1606
|
+
onSelect: handleCalendarSelect,
|
|
1607
|
+
"aria-label": "Date range"
|
|
1608
|
+
}
|
|
1609
|
+
) }),
|
|
1431
1610
|
/* @__PURE__ */ jsxs("div", { className: "border-l border-gray-200 pl-4 flex flex-col gap-1 min-w-[130px]", children: [
|
|
1432
1611
|
PRESET_LABELS.map((label) => /* @__PURE__ */ jsx(
|
|
1433
1612
|
"button",
|
|
@@ -1469,45 +1648,14 @@ function DateRangePicker({
|
|
|
1469
1648
|
)
|
|
1470
1649
|
] });
|
|
1471
1650
|
}
|
|
1472
|
-
var ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
1473
|
-
function toInputValue(value) {
|
|
1474
|
-
if (value === null || value === void 0 || value === "") return "";
|
|
1475
|
-
if (value instanceof Date) return Number.isNaN(value.getTime()) ? "" : toISODate(value);
|
|
1476
|
-
if (ISO_DATE.test(value)) return value;
|
|
1477
|
-
const parsed = new Date(value);
|
|
1478
|
-
return Number.isNaN(parsed.getTime()) ? "" : toISODate(parsed);
|
|
1479
|
-
}
|
|
1480
|
-
function fromInputValue(raw) {
|
|
1481
|
-
if (!ISO_DATE.test(raw)) return null;
|
|
1482
|
-
const [year, month, day] = raw.split("-").map(Number);
|
|
1483
|
-
const date = new Date(year, month - 1, day);
|
|
1484
|
-
return date.getMonth() === month - 1 && date.getDate() === day ? date : null;
|
|
1485
|
-
}
|
|
1486
|
-
var DatePicker = forwardRef(function DatePicker2({ value, onChange, min, max, invalid, size, className = "", ...rest }, ref) {
|
|
1487
|
-
return /* @__PURE__ */ jsx(
|
|
1488
|
-
"input",
|
|
1489
|
-
{
|
|
1490
|
-
ref,
|
|
1491
|
-
type: "date",
|
|
1492
|
-
"aria-invalid": invalid || void 0,
|
|
1493
|
-
value: toInputValue(value),
|
|
1494
|
-
min: toInputValue(min) || void 0,
|
|
1495
|
-
max: toInputValue(max) || void 0,
|
|
1496
|
-
onChange: (event) => onChange?.(fromInputValue(event.target.value)),
|
|
1497
|
-
className: inputClasses({ invalid, size, className }),
|
|
1498
|
-
...rest
|
|
1499
|
-
}
|
|
1500
|
-
);
|
|
1501
|
-
});
|
|
1502
|
-
var DatePicker_default = DatePicker;
|
|
1503
1651
|
var TIME = /^\d{2}:\d{2}(:\d{2})?$/;
|
|
1504
|
-
var
|
|
1505
|
-
function
|
|
1652
|
+
var pad3 = (n) => String(n).padStart(2, "0");
|
|
1653
|
+
function toInputValue(value, withSeconds) {
|
|
1506
1654
|
if (value === null || value === void 0 || value === "") return "";
|
|
1507
1655
|
if (value instanceof Date) {
|
|
1508
1656
|
if (Number.isNaN(value.getTime())) return "";
|
|
1509
|
-
const base = `${
|
|
1510
|
-
return withSeconds ? `${base}:${
|
|
1657
|
+
const base = `${pad3(value.getHours())}:${pad3(value.getMinutes())}`;
|
|
1658
|
+
return withSeconds ? `${base}:${pad3(value.getSeconds())}` : base;
|
|
1511
1659
|
}
|
|
1512
1660
|
return TIME.test(value) ? value : "";
|
|
1513
1661
|
}
|
|
@@ -1520,9 +1668,9 @@ var TimePicker = forwardRef(function TimePicker2({ value, onChange, min, max, in
|
|
|
1520
1668
|
type: "time",
|
|
1521
1669
|
step,
|
|
1522
1670
|
"aria-invalid": invalid || void 0,
|
|
1523
|
-
value:
|
|
1524
|
-
min:
|
|
1525
|
-
max:
|
|
1671
|
+
value: toInputValue(value, withSeconds),
|
|
1672
|
+
min: toInputValue(min, withSeconds) || void 0,
|
|
1673
|
+
max: toInputValue(max, withSeconds) || void 0,
|
|
1526
1674
|
onChange: (event) => onChange?.(TIME.test(event.target.value) ? event.target.value : null),
|
|
1527
1675
|
className: inputClasses({ invalid, size, className }),
|
|
1528
1676
|
...rest
|
|
@@ -1530,10 +1678,252 @@ var TimePicker = forwardRef(function TimePicker2({ value, onChange, min, max, in
|
|
|
1530
1678
|
);
|
|
1531
1679
|
});
|
|
1532
1680
|
var TimePicker_default = TimePicker;
|
|
1681
|
+
var POPUP_MAX_WIDTH = 448;
|
|
1682
|
+
var MENU_MAX_HEIGHT2 = 240;
|
|
1683
|
+
var MENU_GAP2 = 4;
|
|
1684
|
+
var VIEWPORT_MARGIN2 = 8;
|
|
1685
|
+
function useDropdownPosition(triggerRef, open) {
|
|
1686
|
+
const [pos, setPos] = useState(null);
|
|
1687
|
+
useLayoutEffect(() => {
|
|
1688
|
+
if (!open) {
|
|
1689
|
+
setPos(null);
|
|
1690
|
+
return;
|
|
1691
|
+
}
|
|
1692
|
+
let lastLeft = NaN, lastTop = NaN, lastRight = NaN, lastBottom = NaN;
|
|
1693
|
+
const compute = () => {
|
|
1694
|
+
const rect = triggerRef.current?.getBoundingClientRect();
|
|
1695
|
+
if (!rect) return;
|
|
1696
|
+
lastLeft = rect.left;
|
|
1697
|
+
lastTop = rect.top;
|
|
1698
|
+
lastRight = rect.right;
|
|
1699
|
+
lastBottom = rect.bottom;
|
|
1700
|
+
const spaceBelow = window.innerHeight - rect.bottom - MENU_GAP2 - VIEWPORT_MARGIN2;
|
|
1701
|
+
const spaceAbove = rect.top - MENU_GAP2 - VIEWPORT_MARGIN2;
|
|
1702
|
+
const placeAbove = spaceBelow < Math.min(MENU_MAX_HEIGHT2, 160) && spaceAbove > spaceBelow;
|
|
1703
|
+
const maxHeight = Math.max(96, Math.min(MENU_MAX_HEIGHT2, placeAbove ? spaceAbove : spaceBelow));
|
|
1704
|
+
const next = { minWidth: rect.width, maxHeight };
|
|
1705
|
+
if (window.innerWidth - rect.left < POPUP_MAX_WIDTH) {
|
|
1706
|
+
next.right = Math.max(VIEWPORT_MARGIN2, window.innerWidth - rect.right);
|
|
1707
|
+
} else {
|
|
1708
|
+
next.left = Math.max(VIEWPORT_MARGIN2, rect.left);
|
|
1709
|
+
}
|
|
1710
|
+
if (placeAbove) next.bottom = window.innerHeight - rect.top + MENU_GAP2;
|
|
1711
|
+
else next.top = rect.bottom + MENU_GAP2;
|
|
1712
|
+
setPos(next);
|
|
1713
|
+
};
|
|
1714
|
+
compute();
|
|
1715
|
+
let raf = requestAnimationFrame(function tick() {
|
|
1716
|
+
const rect = triggerRef.current?.getBoundingClientRect();
|
|
1717
|
+
if (rect && (rect.left !== lastLeft || rect.top !== lastTop || rect.right !== lastRight || rect.bottom !== lastBottom)) {
|
|
1718
|
+
compute();
|
|
1719
|
+
}
|
|
1720
|
+
raf = requestAnimationFrame(tick);
|
|
1721
|
+
});
|
|
1722
|
+
window.addEventListener("scroll", compute, true);
|
|
1723
|
+
window.addEventListener("resize", compute);
|
|
1724
|
+
return () => {
|
|
1725
|
+
cancelAnimationFrame(raf);
|
|
1726
|
+
window.removeEventListener("scroll", compute, true);
|
|
1727
|
+
window.removeEventListener("resize", compute);
|
|
1728
|
+
};
|
|
1729
|
+
}, [open, triggerRef]);
|
|
1730
|
+
return pos;
|
|
1731
|
+
}
|
|
1732
|
+
var ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
1733
|
+
var MONTH_NAMES2 = [
|
|
1734
|
+
"January",
|
|
1735
|
+
"February",
|
|
1736
|
+
"March",
|
|
1737
|
+
"April",
|
|
1738
|
+
"May",
|
|
1739
|
+
"June",
|
|
1740
|
+
"July",
|
|
1741
|
+
"August",
|
|
1742
|
+
"September",
|
|
1743
|
+
"October",
|
|
1744
|
+
"November",
|
|
1745
|
+
"December"
|
|
1746
|
+
];
|
|
1747
|
+
function toInputValue2(value) {
|
|
1748
|
+
if (value === null || value === void 0 || value === "") return "";
|
|
1749
|
+
if (value instanceof Date) return Number.isNaN(value.getTime()) ? "" : toISODate(value);
|
|
1750
|
+
if (ISO_DATE.test(value)) return value;
|
|
1751
|
+
const parsed = new Date(value);
|
|
1752
|
+
return Number.isNaN(parsed.getTime()) ? "" : toISODate(parsed);
|
|
1753
|
+
}
|
|
1754
|
+
function fromInputValue(raw) {
|
|
1755
|
+
if (!ISO_DATE.test(raw)) return null;
|
|
1756
|
+
const [year, month, day] = raw.split("-").map(Number);
|
|
1757
|
+
const date = new Date(year, month - 1, day);
|
|
1758
|
+
return date.getMonth() === month - 1 && date.getDate() === day ? date : null;
|
|
1759
|
+
}
|
|
1760
|
+
function display(key) {
|
|
1761
|
+
const d = fromInputValue(key);
|
|
1762
|
+
return d ? `${d.getDate()} ${MONTH_NAMES2[d.getMonth()]} ${d.getFullYear()}` : "";
|
|
1763
|
+
}
|
|
1764
|
+
var DatePicker = forwardRef(function DatePicker2({
|
|
1765
|
+
value,
|
|
1766
|
+
onChange,
|
|
1767
|
+
min,
|
|
1768
|
+
max,
|
|
1769
|
+
invalid,
|
|
1770
|
+
size,
|
|
1771
|
+
native,
|
|
1772
|
+
weekStartsOn,
|
|
1773
|
+
className = "",
|
|
1774
|
+
"aria-label": ariaLabel,
|
|
1775
|
+
"aria-describedby": describedBy,
|
|
1776
|
+
id,
|
|
1777
|
+
name,
|
|
1778
|
+
disabled,
|
|
1779
|
+
placeholder,
|
|
1780
|
+
...rest
|
|
1781
|
+
}, ref) {
|
|
1782
|
+
const current = toInputValue2(value);
|
|
1783
|
+
const lo = toInputValue2(min);
|
|
1784
|
+
const hi = toInputValue2(max);
|
|
1785
|
+
const [open, setOpen] = useState(false);
|
|
1786
|
+
const wrapRef = useRef(null);
|
|
1787
|
+
const triggerRef = useRef(null);
|
|
1788
|
+
const panelRef = useRef(null);
|
|
1789
|
+
const panelId = useId();
|
|
1790
|
+
const pos = useDropdownPosition(triggerRef, open);
|
|
1791
|
+
useEffect(() => {
|
|
1792
|
+
if (!open) return;
|
|
1793
|
+
const onPointerDown = (e) => {
|
|
1794
|
+
const target = e.target;
|
|
1795
|
+
if (wrapRef.current?.contains(target) || panelRef.current?.contains(target)) return;
|
|
1796
|
+
setOpen(false);
|
|
1797
|
+
};
|
|
1798
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
1799
|
+
return () => document.removeEventListener("pointerdown", onPointerDown, true);
|
|
1800
|
+
}, [open]);
|
|
1801
|
+
useEffect(() => {
|
|
1802
|
+
if (!open) return;
|
|
1803
|
+
return registerModalEscapeInterceptor((event) => {
|
|
1804
|
+
if (event.key !== "Escape") return false;
|
|
1805
|
+
setOpen(false);
|
|
1806
|
+
triggerRef.current?.focus();
|
|
1807
|
+
return true;
|
|
1808
|
+
});
|
|
1809
|
+
}, [open]);
|
|
1810
|
+
if (native) {
|
|
1811
|
+
return /* @__PURE__ */ jsx(
|
|
1812
|
+
"input",
|
|
1813
|
+
{
|
|
1814
|
+
ref,
|
|
1815
|
+
type: "date",
|
|
1816
|
+
id,
|
|
1817
|
+
name,
|
|
1818
|
+
disabled,
|
|
1819
|
+
"aria-label": ariaLabel,
|
|
1820
|
+
"aria-describedby": describedBy,
|
|
1821
|
+
"aria-invalid": invalid || void 0,
|
|
1822
|
+
value: current,
|
|
1823
|
+
min: lo || void 0,
|
|
1824
|
+
max: hi || void 0,
|
|
1825
|
+
onChange: (event) => onChange?.(fromInputValue(event.target.value)),
|
|
1826
|
+
className: inputClasses({ invalid, size, className }),
|
|
1827
|
+
...rest
|
|
1828
|
+
}
|
|
1829
|
+
);
|
|
1830
|
+
}
|
|
1831
|
+
return /* @__PURE__ */ jsxs("div", { ref: wrapRef, className: "relative", children: [
|
|
1832
|
+
/* @__PURE__ */ jsx("input", { ref, type: "hidden", name, value: current }),
|
|
1833
|
+
/* @__PURE__ */ jsxs(
|
|
1834
|
+
"button",
|
|
1835
|
+
{
|
|
1836
|
+
ref: triggerRef,
|
|
1837
|
+
type: "button",
|
|
1838
|
+
id,
|
|
1839
|
+
disabled,
|
|
1840
|
+
"aria-haspopup": "dialog",
|
|
1841
|
+
"aria-expanded": open,
|
|
1842
|
+
"aria-controls": open ? panelId : void 0,
|
|
1843
|
+
"aria-describedby": describedBy,
|
|
1844
|
+
"aria-invalid": invalid || void 0,
|
|
1845
|
+
"aria-label": ariaLabel ? `${ariaLabel}${current ? `, ${display(current)}` : ""}` : void 0,
|
|
1846
|
+
onClick: () => setOpen((o) => !o),
|
|
1847
|
+
className: `${inputClasses({ invalid, size, className })} flex items-center justify-between text-left`,
|
|
1848
|
+
children: [
|
|
1849
|
+
/* @__PURE__ */ jsx("span", { className: current ? "text-gray-900" : "text-gray-400", children: current ? display(current) : placeholder ?? "Select a date" }),
|
|
1850
|
+
/* @__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" }) })
|
|
1851
|
+
]
|
|
1852
|
+
}
|
|
1853
|
+
),
|
|
1854
|
+
open && createPortal(
|
|
1855
|
+
/* @__PURE__ */ jsxs(
|
|
1856
|
+
"div",
|
|
1857
|
+
{
|
|
1858
|
+
ref: panelRef,
|
|
1859
|
+
id: panelId,
|
|
1860
|
+
role: "dialog",
|
|
1861
|
+
"aria-label": ariaLabel ?? "Choose a date",
|
|
1862
|
+
className: "fixed z-[400] w-72 rounded-xl border border-gray-200 bg-white p-3 shadow-lg",
|
|
1863
|
+
style: {
|
|
1864
|
+
left: pos?.left,
|
|
1865
|
+
right: pos?.right,
|
|
1866
|
+
top: pos?.top,
|
|
1867
|
+
bottom: pos?.bottom,
|
|
1868
|
+
// Hidden for the first paint until the layout effect measures the
|
|
1869
|
+
// trigger, so the panel never flashes at (0,0).
|
|
1870
|
+
visibility: pos ? void 0 : "hidden"
|
|
1871
|
+
},
|
|
1872
|
+
children: [
|
|
1873
|
+
/* @__PURE__ */ jsx(
|
|
1874
|
+
Calendar,
|
|
1875
|
+
{
|
|
1876
|
+
value: current || null,
|
|
1877
|
+
min: lo || null,
|
|
1878
|
+
max: hi || null,
|
|
1879
|
+
weekStartsOn,
|
|
1880
|
+
onSelect: (key) => {
|
|
1881
|
+
setOpen(false);
|
|
1882
|
+
triggerRef.current?.focus();
|
|
1883
|
+
onChange?.(fromInputValue(key));
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
),
|
|
1887
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-2 flex justify-between border-t border-gray-100 pt-2", children: [
|
|
1888
|
+
/* @__PURE__ */ jsx(
|
|
1889
|
+
"button",
|
|
1890
|
+
{
|
|
1891
|
+
type: "button",
|
|
1892
|
+
onClick: () => {
|
|
1893
|
+
setOpen(false);
|
|
1894
|
+
triggerRef.current?.focus();
|
|
1895
|
+
onChange?.(null);
|
|
1896
|
+
},
|
|
1897
|
+
className: "rounded-md px-2 py-1 text-sm text-gray-500 hover:bg-gray-100 hover:text-gray-700",
|
|
1898
|
+
children: "Clear"
|
|
1899
|
+
}
|
|
1900
|
+
),
|
|
1901
|
+
/* @__PURE__ */ jsx(
|
|
1902
|
+
"button",
|
|
1903
|
+
{
|
|
1904
|
+
type: "button",
|
|
1905
|
+
onClick: () => {
|
|
1906
|
+
setOpen(false);
|
|
1907
|
+
triggerRef.current?.focus();
|
|
1908
|
+
onChange?.(/* @__PURE__ */ new Date());
|
|
1909
|
+
},
|
|
1910
|
+
className: "rounded-md px-2 py-1 text-sm font-medium text-blue-600 hover:bg-blue-50",
|
|
1911
|
+
children: "Today"
|
|
1912
|
+
}
|
|
1913
|
+
)
|
|
1914
|
+
] })
|
|
1915
|
+
]
|
|
1916
|
+
}
|
|
1917
|
+
),
|
|
1918
|
+
document.body
|
|
1919
|
+
)
|
|
1920
|
+
] });
|
|
1921
|
+
});
|
|
1922
|
+
var DatePicker_default = DatePicker;
|
|
1533
1923
|
var ISO_LOCAL = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2})?$/;
|
|
1534
|
-
var
|
|
1924
|
+
var pad4 = (n) => String(n).padStart(2, "0");
|
|
1535
1925
|
function serialise(date) {
|
|
1536
|
-
return `${date.getFullYear()}-${
|
|
1926
|
+
return `${date.getFullYear()}-${pad4(date.getMonth() + 1)}-${pad4(date.getDate())}T${pad4(date.getHours())}:${pad4(date.getMinutes())}`;
|
|
1537
1927
|
}
|
|
1538
1928
|
function toInputValue3(value) {
|
|
1539
1929
|
if (value === null || value === void 0 || value === "") return "";
|
|
@@ -1677,8 +2067,8 @@ function Segmented({
|
|
|
1677
2067
|
className = ""
|
|
1678
2068
|
}) {
|
|
1679
2069
|
const groupId = useId();
|
|
1680
|
-
const track = `inline-flex items-center gap-1 rounded-lg bg-gray-100 p-1 ${block ? "w-full" : ""} ${className}`.trim();
|
|
1681
|
-
const itemBase = `inline-flex items-center justify-center gap-1.5 rounded-md font-medium transition-colors ${block ? "flex-1" : ""}`;
|
|
2070
|
+
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();
|
|
2071
|
+
const itemBase = `inline-flex shrink-0 items-center justify-center gap-1.5 whitespace-nowrap rounded-md font-medium transition-colors ${block ? "flex-1" : ""}`;
|
|
1682
2072
|
if (name) {
|
|
1683
2073
|
return /* @__PURE__ */ jsx("div", { role: "radiogroup", "aria-label": label, className: track, children: options.map((opt) => {
|
|
1684
2074
|
const id = `${groupId}-${opt.value}`;
|
|
@@ -2029,58 +2419,7 @@ function FilePicker({
|
|
|
2029
2419
|
error && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-red-600", children: error })
|
|
2030
2420
|
] });
|
|
2031
2421
|
}
|
|
2032
|
-
|
|
2033
|
-
var MENU_MAX_HEIGHT2 = 240;
|
|
2034
|
-
var MENU_GAP2 = 4;
|
|
2035
|
-
var VIEWPORT_MARGIN2 = 8;
|
|
2036
|
-
function useDropdownPosition(triggerRef, open) {
|
|
2037
|
-
const [pos, setPos] = useState(null);
|
|
2038
|
-
useLayoutEffect(() => {
|
|
2039
|
-
if (!open) {
|
|
2040
|
-
setPos(null);
|
|
2041
|
-
return;
|
|
2042
|
-
}
|
|
2043
|
-
let lastLeft = NaN, lastTop = NaN, lastRight = NaN, lastBottom = NaN;
|
|
2044
|
-
const compute = () => {
|
|
2045
|
-
const rect = triggerRef.current?.getBoundingClientRect();
|
|
2046
|
-
if (!rect) return;
|
|
2047
|
-
lastLeft = rect.left;
|
|
2048
|
-
lastTop = rect.top;
|
|
2049
|
-
lastRight = rect.right;
|
|
2050
|
-
lastBottom = rect.bottom;
|
|
2051
|
-
const spaceBelow = window.innerHeight - rect.bottom - MENU_GAP2 - VIEWPORT_MARGIN2;
|
|
2052
|
-
const spaceAbove = rect.top - MENU_GAP2 - VIEWPORT_MARGIN2;
|
|
2053
|
-
const placeAbove = spaceBelow < Math.min(MENU_MAX_HEIGHT2, 160) && spaceAbove > spaceBelow;
|
|
2054
|
-
const maxHeight = Math.max(96, Math.min(MENU_MAX_HEIGHT2, placeAbove ? spaceAbove : spaceBelow));
|
|
2055
|
-
const next = { minWidth: rect.width, maxHeight };
|
|
2056
|
-
if (window.innerWidth - rect.left < POPUP_MAX_WIDTH) {
|
|
2057
|
-
next.right = Math.max(VIEWPORT_MARGIN2, window.innerWidth - rect.right);
|
|
2058
|
-
} else {
|
|
2059
|
-
next.left = Math.max(VIEWPORT_MARGIN2, rect.left);
|
|
2060
|
-
}
|
|
2061
|
-
if (placeAbove) next.bottom = window.innerHeight - rect.top + MENU_GAP2;
|
|
2062
|
-
else next.top = rect.bottom + MENU_GAP2;
|
|
2063
|
-
setPos(next);
|
|
2064
|
-
};
|
|
2065
|
-
compute();
|
|
2066
|
-
let raf = requestAnimationFrame(function tick() {
|
|
2067
|
-
const rect = triggerRef.current?.getBoundingClientRect();
|
|
2068
|
-
if (rect && (rect.left !== lastLeft || rect.top !== lastTop || rect.right !== lastRight || rect.bottom !== lastBottom)) {
|
|
2069
|
-
compute();
|
|
2070
|
-
}
|
|
2071
|
-
raf = requestAnimationFrame(tick);
|
|
2072
|
-
});
|
|
2073
|
-
window.addEventListener("scroll", compute, true);
|
|
2074
|
-
window.addEventListener("resize", compute);
|
|
2075
|
-
return () => {
|
|
2076
|
-
cancelAnimationFrame(raf);
|
|
2077
|
-
window.removeEventListener("scroll", compute, true);
|
|
2078
|
-
window.removeEventListener("resize", compute);
|
|
2079
|
-
};
|
|
2080
|
-
}, [open, triggerRef]);
|
|
2081
|
-
return pos;
|
|
2082
|
-
}
|
|
2083
|
-
function ClearButton({ onClear, ariaLabel = "Clear selection" }) {
|
|
2422
|
+
function ClearButton({ onClear, ariaLabel }) {
|
|
2084
2423
|
return /* @__PURE__ */ jsx(
|
|
2085
2424
|
"button",
|
|
2086
2425
|
{
|
|
@@ -2101,7 +2440,7 @@ function SearchableSelect({
|
|
|
2101
2440
|
onChange,
|
|
2102
2441
|
options,
|
|
2103
2442
|
placeholder,
|
|
2104
|
-
emptyOptionLabel
|
|
2443
|
+
emptyOptionLabel,
|
|
2105
2444
|
className = "",
|
|
2106
2445
|
disabled,
|
|
2107
2446
|
id,
|
|
@@ -2111,6 +2450,8 @@ function SearchableSelect({
|
|
|
2111
2450
|
}) {
|
|
2112
2451
|
const [open, setOpen] = useState(false);
|
|
2113
2452
|
const [search, setSearchState] = useState("");
|
|
2453
|
+
const strings = useShellStrings();
|
|
2454
|
+
const noneLabel = emptyOptionLabel ?? strings.select.none;
|
|
2114
2455
|
const setSearch = (next) => {
|
|
2115
2456
|
setSearchState(next);
|
|
2116
2457
|
onSearchChange?.(next);
|
|
@@ -2212,13 +2553,13 @@ function SearchableSelect({
|
|
|
2212
2553
|
setSearch("");
|
|
2213
2554
|
}
|
|
2214
2555
|
},
|
|
2215
|
-
placeholder: placeholder ||
|
|
2556
|
+
placeholder: placeholder || noneLabel,
|
|
2216
2557
|
className: `${INPUT_BASE} ${className} ${value ? "pr-8" : ""} ${disabled ? "bg-gray-50 text-gray-400 cursor-not-allowed" : ""} truncate`,
|
|
2217
2558
|
style: adornPad ? { paddingRight: adornPad } : void 0,
|
|
2218
2559
|
disabled
|
|
2219
2560
|
}
|
|
2220
2561
|
),
|
|
2221
|
-
value && !disabled && /* @__PURE__ */ jsx(ClearButton, { onClear: () => {
|
|
2562
|
+
value && !disabled && /* @__PURE__ */ jsx(ClearButton, { ariaLabel: strings.select.clear, onClear: () => {
|
|
2222
2563
|
onChange("");
|
|
2223
2564
|
setOpen(false);
|
|
2224
2565
|
setSearch("");
|
|
@@ -2229,7 +2570,7 @@ function SearchableSelect({
|
|
|
2229
2570
|
"div",
|
|
2230
2571
|
{
|
|
2231
2572
|
ref: menuRef,
|
|
2232
|
-
className: "fixed z-[
|
|
2573
|
+
className: "fixed z-[10000] rounded-2xl overflow-hidden",
|
|
2233
2574
|
style: {
|
|
2234
2575
|
left: menuPos?.left,
|
|
2235
2576
|
right: menuPos?.right,
|
|
@@ -2243,7 +2584,7 @@ function SearchableSelect({
|
|
|
2243
2584
|
visibility: menuPos ? void 0 : "hidden",
|
|
2244
2585
|
...glassStyle()
|
|
2245
2586
|
},
|
|
2246
|
-
children: /* @__PURE__ */ jsx("div", { className: "overflow-y-auto", style: { maxHeight: menuPos?.maxHeight ?? MENU_MAX_HEIGHT2 }, children: filtered.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-3 py-3 text-sm text-gray-400 text-center", children:
|
|
2587
|
+
children: /* @__PURE__ */ jsx("div", { className: "overflow-y-auto", style: { maxHeight: menuPos?.maxHeight ?? MENU_MAX_HEIGHT2 }, children: filtered.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-3 py-3 text-sm text-gray-400 text-center", children: strings.select.noMatches }) : filtered.map((o) => /* @__PURE__ */ jsxs(
|
|
2247
2588
|
"button",
|
|
2248
2589
|
{
|
|
2249
2590
|
type: "button",
|
|
@@ -2279,6 +2620,7 @@ function TagInput({
|
|
|
2279
2620
|
}) {
|
|
2280
2621
|
const [open, setOpen] = useState(false);
|
|
2281
2622
|
const [search, setSearch] = useState("");
|
|
2623
|
+
const strings = useShellStrings();
|
|
2282
2624
|
const wrapRef = useRef(null);
|
|
2283
2625
|
const inputRef = useRef(null);
|
|
2284
2626
|
const menuRef = useRef(null);
|
|
@@ -2342,7 +2684,7 @@ function TagInput({
|
|
|
2342
2684
|
"button",
|
|
2343
2685
|
{
|
|
2344
2686
|
type: "button",
|
|
2345
|
-
"aria-label":
|
|
2687
|
+
"aria-label": `${strings.select.remove} ${labelFor(v)}`,
|
|
2346
2688
|
onClick: () => remove(v),
|
|
2347
2689
|
className: "text-blue-400 hover:text-red-500 focus:outline-none focus-visible:ring-1 focus-visible:ring-blue-500 rounded leading-none",
|
|
2348
2690
|
children: "\xD7"
|
|
@@ -2398,7 +2740,7 @@ function TagInput({
|
|
|
2398
2740
|
"div",
|
|
2399
2741
|
{
|
|
2400
2742
|
ref: menuRef,
|
|
2401
|
-
className: "fixed z-[
|
|
2743
|
+
className: "fixed z-[10000] rounded-2xl overflow-hidden",
|
|
2402
2744
|
style: {
|
|
2403
2745
|
left: menuPos?.left,
|
|
2404
2746
|
right: menuPos?.right,
|
|
@@ -2412,7 +2754,7 @@ function TagInput({
|
|
|
2412
2754
|
visibility: menuPos ? void 0 : "hidden",
|
|
2413
2755
|
...glassStyle()
|
|
2414
2756
|
},
|
|
2415
|
-
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 ?
|
|
2757
|
+
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 ? strings.select.allSelected : strings.select.noMatches }) : available.map((o) => /* @__PURE__ */ jsx(
|
|
2416
2758
|
"button",
|
|
2417
2759
|
{
|
|
2418
2760
|
type: "button",
|
|
@@ -2714,23 +3056,23 @@ function DescriptionList({
|
|
|
2714
3056
|
const resolved = typeof columns === "number" ? { base: columns } : columns;
|
|
2715
3057
|
const base = resolved.base ?? 1;
|
|
2716
3058
|
const widest = Math.max(base, resolved.sm ?? 0, resolved.lg ?? 0);
|
|
2717
|
-
const
|
|
3059
|
+
const pad5 = size === "sm" ? "px-3 py-2" : "px-4 py-3";
|
|
2718
3060
|
const text = size === "sm" ? "text-xs" : "text-sm";
|
|
2719
3061
|
return /* @__PURE__ */ jsxs("div", { className: [bordered ? "rounded-lg border border-gray-200 bg-white" : "", className].filter(Boolean).join(" "), children: [
|
|
2720
|
-
title && /* @__PURE__ */ jsx("div", { className: `${
|
|
3062
|
+
title && /* @__PURE__ */ jsx("div", { className: `${pad5} ${bordered ? "border-b border-gray-100" : ""} text-sm font-semibold text-gray-900`.trim(), children: title }),
|
|
2721
3063
|
/* @__PURE__ */ jsx("dl", { className: [
|
|
2722
3064
|
"grid",
|
|
2723
3065
|
COLS2[base],
|
|
2724
3066
|
resolved.sm ? SM[resolved.sm] : "",
|
|
2725
3067
|
resolved.lg ? LG[resolved.lg] : "",
|
|
2726
3068
|
bordered ? "" : "gap-x-6 gap-y-3",
|
|
2727
|
-
bordered ? "" :
|
|
3069
|
+
bordered ? "" : pad5 === "px-4 py-3" ? "py-1" : ""
|
|
2728
3070
|
].filter(Boolean).join(" "), children: items.map((item, i) => /* @__PURE__ */ jsxs(
|
|
2729
3071
|
"div",
|
|
2730
3072
|
{
|
|
2731
3073
|
className: [
|
|
2732
3074
|
item.span ? SPAN[widest] : "",
|
|
2733
|
-
bordered ? `${
|
|
3075
|
+
bordered ? `${pad5} border-b border-gray-100 last:border-b-0` : ""
|
|
2734
3076
|
].filter(Boolean).join(" "),
|
|
2735
3077
|
children: [
|
|
2736
3078
|
/* @__PURE__ */ jsx("dt", { className: `${text} text-gray-500`, children: item.label }),
|
|
@@ -4143,8 +4485,9 @@ function HelpCenter({
|
|
|
4143
4485
|
onNew,
|
|
4144
4486
|
onEdit,
|
|
4145
4487
|
renderBody,
|
|
4146
|
-
emptyMessage
|
|
4488
|
+
emptyMessage
|
|
4147
4489
|
}) {
|
|
4490
|
+
const strings = useShellStrings();
|
|
4148
4491
|
const [query, setQuery] = useState("");
|
|
4149
4492
|
const [selectedSlug, setSelectedSlug] = useState(null);
|
|
4150
4493
|
const [expanded, setExpanded] = useState({});
|
|
@@ -4177,8 +4520,8 @@ function HelpCenter({
|
|
|
4177
4520
|
return /* @__PURE__ */ jsxs("div", { className: "flex h-full gap-4 px-4 py-3 min-h-0", children: [
|
|
4178
4521
|
/* @__PURE__ */ jsxs("aside", { className: "w-64 shrink-0 flex flex-col bg-white rounded-lg shadow overflow-hidden", children: [
|
|
4179
4522
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 px-3 py-2 border-b border-gray-200 bg-gray-50 shrink-0", children: [
|
|
4180
|
-
/* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold text-gray-900", children:
|
|
4181
|
-
canEdit && onNew && /* @__PURE__ */ jsx("button", { type: "button", onClick: onNew, className: "text-xs text-blue-600 hover:underline", children:
|
|
4523
|
+
/* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold text-gray-900", children: strings.help.title }),
|
|
4524
|
+
canEdit && onNew && /* @__PURE__ */ jsx("button", { type: "button", onClick: onNew, className: "text-xs text-blue-600 hover:underline", children: strings.help.newArticle })
|
|
4182
4525
|
] }),
|
|
4183
4526
|
/* @__PURE__ */ jsx("div", { className: "px-2.5 py-2 border-b border-gray-100 shrink-0", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
4184
4527
|
/* @__PURE__ */ jsx(
|
|
@@ -4204,12 +4547,12 @@ function HelpCenter({
|
|
|
4204
4547
|
type: "text",
|
|
4205
4548
|
value: query,
|
|
4206
4549
|
onChange: (e) => setQuery(e.target.value),
|
|
4207
|
-
placeholder:
|
|
4550
|
+
placeholder: strings.help.searchPlaceholder,
|
|
4208
4551
|
className: "w-full rounded-md border border-gray-300 bg-white py-1.5 pl-8 pr-2 text-sm shadow-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500"
|
|
4209
4552
|
}
|
|
4210
4553
|
)
|
|
4211
4554
|
] }) }),
|
|
4212
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto py-1", children: loading ? /* @__PURE__ */ jsx("p", { className: "px-3 py-6 text-center text-xs text-gray-400", children:
|
|
4555
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto py-1", children: loading ? /* @__PURE__ */ jsx("p", { className: "px-3 py-6 text-center text-xs text-gray-400", children: strings.help.loading }) : visibleGroups.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-3 py-6 text-center text-xs text-gray-500", children: q ? strings.help.noResults : emptyMessage ?? strings.help.empty }) : visibleGroups.map((group) => {
|
|
4213
4556
|
const open = isGroupOpen(group.key);
|
|
4214
4557
|
return /* @__PURE__ */ jsxs("div", { className: "py-0.5", children: [
|
|
4215
4558
|
/* @__PURE__ */ jsxs(
|
|
@@ -4234,7 +4577,7 @@ function HelpCenter({
|
|
|
4234
4577
|
className: `w-full text-left pl-8 pr-3 py-1.5 text-sm flex items-center gap-1.5 transition-colors ${active ? "bg-blue-50 text-blue-700 font-medium" : "text-gray-700 hover:bg-gray-50"}`,
|
|
4235
4578
|
children: [
|
|
4236
4579
|
/* @__PURE__ */ jsx("span", { className: "truncate", children: doc.title }),
|
|
4237
|
-
doc.is_published === false && /* @__PURE__ */ jsx("span", { className: "ml-auto shrink-0 text-[10px] text-amber-600", children:
|
|
4580
|
+
doc.is_published === false && /* @__PURE__ */ jsx("span", { className: "ml-auto shrink-0 text-[10px] text-amber-600", children: strings.help.draft })
|
|
4238
4581
|
]
|
|
4239
4582
|
},
|
|
4240
4583
|
doc.slug
|
|
@@ -4249,7 +4592,10 @@ function HelpCenter({
|
|
|
4249
4592
|
/* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold text-gray-900 truncate", children: selected.title }),
|
|
4250
4593
|
/* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500 mt-0.5", children: [
|
|
4251
4594
|
selected.category_label,
|
|
4252
|
-
selected.is_published === false && /* @__PURE__ */
|
|
4595
|
+
selected.is_published === false && /* @__PURE__ */ jsxs("span", { className: "ml-2 text-amber-600", children: [
|
|
4596
|
+
"\xB7 ",
|
|
4597
|
+
strings.help.draft
|
|
4598
|
+
] })
|
|
4253
4599
|
] })
|
|
4254
4600
|
] }),
|
|
4255
4601
|
canEdit && onEdit && /* @__PURE__ */ jsx(
|
|
@@ -4258,12 +4604,12 @@ function HelpCenter({
|
|
|
4258
4604
|
type: "button",
|
|
4259
4605
|
onClick: () => onEdit(selected),
|
|
4260
4606
|
className: "shrink-0 text-sm text-blue-600 hover:underline",
|
|
4261
|
-
children:
|
|
4607
|
+
children: strings.help.edit
|
|
4262
4608
|
}
|
|
4263
4609
|
)
|
|
4264
4610
|
] }),
|
|
4265
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-auto px-5 py-4", children: renderBody ? renderBody(selected) : selected.body ? /* @__PURE__ */ jsx(Markdown, { children: selected.body }) : /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 italic", children:
|
|
4266
|
-
] }) : /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-center px-6 text-center", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500", children: loading ?
|
|
4611
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-auto px-5 py-4", children: renderBody ? renderBody(selected) : selected.body ? /* @__PURE__ */ jsx(Markdown, { children: selected.body }) : /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 italic", children: strings.help.noBody }) })
|
|
4612
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-center px-6 text-center", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500", children: loading ? strings.help.loading : strings.help.pickArticle }) }) })
|
|
4267
4613
|
] });
|
|
4268
4614
|
}
|
|
4269
4615
|
var VARIANTS = {
|
|
@@ -4484,12 +4830,28 @@ function DropdownMenu({
|
|
|
4484
4830
|
)
|
|
4485
4831
|
] });
|
|
4486
4832
|
}
|
|
4487
|
-
var
|
|
4833
|
+
var SIZE_CLASS = {
|
|
4834
|
+
sm: "sm:w-[320px]",
|
|
4835
|
+
md: "sm:w-[448px]",
|
|
4836
|
+
lg: "sm:w-[640px]"
|
|
4837
|
+
};
|
|
4488
4838
|
var SIDE_POSITION = {
|
|
4489
4839
|
right: "inset-y-0 right-0",
|
|
4490
4840
|
left: "inset-y-0 left-0",
|
|
4491
4841
|
bottom: "inset-x-0 bottom-0"
|
|
4492
4842
|
};
|
|
4843
|
+
function CloseButton({ onClose }) {
|
|
4844
|
+
return /* @__PURE__ */ jsx(
|
|
4845
|
+
"button",
|
|
4846
|
+
{
|
|
4847
|
+
type: "button",
|
|
4848
|
+
onClick: onClose,
|
|
4849
|
+
"aria-label": "Close",
|
|
4850
|
+
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",
|
|
4851
|
+
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" }) })
|
|
4852
|
+
}
|
|
4853
|
+
);
|
|
4854
|
+
}
|
|
4493
4855
|
function Drawer({
|
|
4494
4856
|
open,
|
|
4495
4857
|
onClose,
|
|
@@ -4500,10 +4862,12 @@ function Drawer({
|
|
|
4500
4862
|
children,
|
|
4501
4863
|
blocking = false,
|
|
4502
4864
|
initialFocus,
|
|
4865
|
+
"aria-label": ariaLabel,
|
|
4503
4866
|
className = ""
|
|
4504
4867
|
}) {
|
|
4505
4868
|
const panelRef = useRef(null);
|
|
4506
4869
|
const bodyId = useId();
|
|
4870
|
+
const titleId = useId();
|
|
4507
4871
|
useFocusTrap(panelRef, open, initialFocus);
|
|
4508
4872
|
useScrollLock(open);
|
|
4509
4873
|
useEffect(() => {
|
|
@@ -4516,7 +4880,7 @@ function Drawer({
|
|
|
4516
4880
|
}, [open, blocking, onClose]);
|
|
4517
4881
|
if (!open) return null;
|
|
4518
4882
|
const isBottom = side === "bottom";
|
|
4519
|
-
const panelStyle = isBottom ? { maxHeight: "85vh" } :
|
|
4883
|
+
const panelStyle = isBottom ? { maxHeight: "85vh" } : void 0;
|
|
4520
4884
|
return /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-[9999]", role: "presentation", children: [
|
|
4521
4885
|
/* @__PURE__ */ jsx("div", { className: "fixed inset-0 bg-black/30", onClick: blocking ? void 0 : onClose, "aria-hidden": "true" }),
|
|
4522
4886
|
/* @__PURE__ */ jsxs(
|
|
@@ -4525,29 +4889,27 @@ function Drawer({
|
|
|
4525
4889
|
ref: panelRef,
|
|
4526
4890
|
role: "dialog",
|
|
4527
4891
|
"aria-modal": "true",
|
|
4528
|
-
"aria-
|
|
4892
|
+
"aria-labelledby": title ? titleId : void 0,
|
|
4893
|
+
"aria-label": title ? void 0 : ariaLabel,
|
|
4529
4894
|
"aria-describedby": children ? bodyId : void 0,
|
|
4530
4895
|
style: panelStyle,
|
|
4531
4896
|
className: [
|
|
4532
4897
|
"fixed flex flex-col bg-white shadow-xl",
|
|
4898
|
+
// Full width on a phone, the asked-for width from `sm` up. A 320px
|
|
4899
|
+
// drawer on a 375px screen leaves a 55px strip of scrim: too narrow
|
|
4900
|
+
// to aim at, too wide to read as an edge, and it makes the panel look
|
|
4901
|
+
// like a desktop rail that was squeezed rather than a sheet built for
|
|
4902
|
+
// the screen it is on.
|
|
4903
|
+
isBottom ? "" : `w-full max-w-full ${SIZE_CLASS[size]}`,
|
|
4533
4904
|
SIDE_POSITION[side],
|
|
4534
4905
|
isBottom ? "rounded-t-xl" : "",
|
|
4535
4906
|
className
|
|
4536
4907
|
].filter(Boolean).join(" "),
|
|
4537
4908
|
children: [
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
!blocking && /* @__PURE__ */ jsx(
|
|
4541
|
-
|
|
4542
|
-
{
|
|
4543
|
-
type: "button",
|
|
4544
|
-
onClick: onClose,
|
|
4545
|
-
"aria-label": "Close",
|
|
4546
|
-
className: "rounded-md p-1 text-gray-400 hover:bg-gray-100 hover:text-gray-600",
|
|
4547
|
-
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" }) })
|
|
4548
|
-
}
|
|
4549
|
-
)
|
|
4550
|
-
] }),
|
|
4909
|
+
title ? /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center justify-between gap-4 border-b border-gray-100 px-4 py-3", children: [
|
|
4910
|
+
/* @__PURE__ */ jsx("h2", { id: titleId, className: "text-base font-semibold text-gray-900", children: title }),
|
|
4911
|
+
!blocking && /* @__PURE__ */ jsx(CloseButton, { onClose })
|
|
4912
|
+
] }) : !blocking && /* @__PURE__ */ jsx("div", { className: "absolute right-2 top-2 z-10", children: /* @__PURE__ */ jsx(CloseButton, { onClose }) }),
|
|
4551
4913
|
/* @__PURE__ */ jsx("div", { id: bodyId, className: "min-h-0 flex-1 overflow-y-auto px-4 py-4", children }),
|
|
4552
4914
|
footer && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 justify-end gap-3 border-t border-gray-100 px-4 py-3", children: footer })
|
|
4553
4915
|
]
|
|
@@ -4957,11 +5319,14 @@ function DataTable({
|
|
|
4957
5319
|
minWidth,
|
|
4958
5320
|
rowClassName,
|
|
4959
5321
|
onRow,
|
|
4960
|
-
emptyText
|
|
5322
|
+
emptyText,
|
|
5323
|
+
selection,
|
|
4961
5324
|
footer,
|
|
4962
5325
|
virtualized,
|
|
4963
5326
|
className = ""
|
|
4964
5327
|
}) {
|
|
5328
|
+
const strings = useShellStrings();
|
|
5329
|
+
const emptyContent = emptyText ?? strings.table.empty;
|
|
4965
5330
|
const keyOf = (row, i) => typeof rowKey === "function" ? rowKey(row, i) : String(row[rowKey]);
|
|
4966
5331
|
const [startRow, setStartRow] = useState(0);
|
|
4967
5332
|
const overscan = virtualized?.overscan ?? 6;
|
|
@@ -4995,6 +5360,27 @@ function DataTable({
|
|
|
4995
5360
|
};
|
|
4996
5361
|
const leaves = columns.flatMap((h) => isGroup(h) ? h.columns : [h]);
|
|
4997
5362
|
const grouped = columns.some(isGroup);
|
|
5363
|
+
const selectedSet = new Set(selection?.selected ?? []);
|
|
5364
|
+
const pageKeys = selection ? data.map((row, i) => keyOf(row, i)) : [];
|
|
5365
|
+
const allSelected = pageKeys.length > 0 && pageKeys.every((k) => selectedSet.has(k));
|
|
5366
|
+
const someSelected = pageKeys.some((k) => selectedSet.has(k));
|
|
5367
|
+
const toggleRow = (key) => {
|
|
5368
|
+
if (!selection) return;
|
|
5369
|
+
selection.onChange(
|
|
5370
|
+
selectedSet.has(key) ? selection.selected.filter((k) => k !== key) : [...selection.selected, key]
|
|
5371
|
+
);
|
|
5372
|
+
};
|
|
5373
|
+
const toggleAll = () => {
|
|
5374
|
+
if (!selection) return;
|
|
5375
|
+
const page = new Set(pageKeys);
|
|
5376
|
+
selection.onChange(
|
|
5377
|
+
allSelected ? selection.selected.filter((k) => !page.has(k)) : [...selection.selected, ...pageKeys.filter((k) => !selectedSet.has(k))]
|
|
5378
|
+
);
|
|
5379
|
+
};
|
|
5380
|
+
const SELECT_W = 36;
|
|
5381
|
+
const selOffset = selection ? SELECT_W : 0;
|
|
5382
|
+
const colCount = leaves.length + (selection ? 1 : 0);
|
|
5383
|
+
const hasPinned = leaves.some((c) => c.fixed === "left");
|
|
4998
5384
|
const cellBase = `${PAD[size]} ${size === "sm" ? "text-xs" : "text-sm"}`;
|
|
4999
5385
|
const headerCell = (col, ci, rowSpan, topOffset = 0) => {
|
|
5000
5386
|
const dir = directionFor(col);
|
|
@@ -5008,7 +5394,7 @@ function DataTable({
|
|
|
5008
5394
|
"aria-sort": dir === "asc" ? "ascending" : dir === "desc" ? "descending" : col.sortable && onSortChange ? "none" : void 0,
|
|
5009
5395
|
style: {
|
|
5010
5396
|
width: col.width,
|
|
5011
|
-
...pinned ? { left: offsets[ci] ?? 0 } : {},
|
|
5397
|
+
...pinned ? { left: (offsets[ci] ?? 0) + selOffset } : {},
|
|
5012
5398
|
// A virtualized header pins to the top of the vertical scroll; one
|
|
5013
5399
|
// sticky box can hold both axes, so a pinned column's header corner
|
|
5014
5400
|
// stays put in both directions.
|
|
@@ -5058,45 +5444,73 @@ function DataTable({
|
|
|
5058
5444
|
// page around under the user.
|
|
5059
5445
|
/* @__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: [
|
|
5060
5446
|
/* @__PURE__ */ jsx("span", { className: "h-6 w-6 animate-spin rounded-full border-2 border-gray-200 border-t-blue-600" }),
|
|
5061
|
-
/* @__PURE__ */ jsx("span", { className: "sr-only", children:
|
|
5447
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: strings.table.loading })
|
|
5062
5448
|
] }),
|
|
5063
5449
|
/* @__PURE__ */ jsxs("table", { className: "w-full border-collapse tabular-nums", style: minWidth ? { minWidth } : void 0, children: [
|
|
5064
5450
|
caption && /* @__PURE__ */ jsx("caption", { className: "sr-only", children: caption }),
|
|
5065
5451
|
/* @__PURE__ */ jsxs("thead", { children: [
|
|
5066
|
-
/* @__PURE__ */
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5452
|
+
/* @__PURE__ */ jsxs("tr", { ref: headRowRef, className: "border-b border-gray-200 bg-gray-50", children: [
|
|
5453
|
+
selection && /* @__PURE__ */ jsx(
|
|
5454
|
+
"th",
|
|
5455
|
+
{
|
|
5456
|
+
scope: "col",
|
|
5457
|
+
rowSpan: grouped ? 2 : void 0,
|
|
5458
|
+
style: { width: SELECT_W, ...virtualized ? { top: 0 } : {} },
|
|
5459
|
+
className: [
|
|
5460
|
+
cellBase,
|
|
5461
|
+
hasPinned || virtualized ? "sticky z-20 bg-gray-50" : "",
|
|
5462
|
+
hasPinned ? "left-0" : ""
|
|
5463
|
+
].filter(Boolean).join(" "),
|
|
5464
|
+
children: /* @__PURE__ */ jsx(
|
|
5465
|
+
"input",
|
|
5466
|
+
{
|
|
5467
|
+
type: "checkbox",
|
|
5468
|
+
"aria-label": strings.table.selectAll,
|
|
5469
|
+
checked: allSelected,
|
|
5470
|
+
ref: (el) => {
|
|
5471
|
+
if (el) el.indeterminate = someSelected && !allSelected;
|
|
5472
|
+
},
|
|
5473
|
+
onChange: toggleAll,
|
|
5474
|
+
className: "h-4 w-4 rounded border-gray-300 text-blue-600"
|
|
5475
|
+
}
|
|
5476
|
+
)
|
|
5477
|
+
}
|
|
5478
|
+
),
|
|
5479
|
+
columns.map((h, hi) => {
|
|
5480
|
+
if (isGroup(h)) {
|
|
5481
|
+
return /* @__PURE__ */ jsx(
|
|
5482
|
+
"th",
|
|
5483
|
+
{
|
|
5484
|
+
scope: "colgroup",
|
|
5485
|
+
colSpan: h.columns.length,
|
|
5486
|
+
style: virtualized ? { top: 0 } : void 0,
|
|
5487
|
+
className: [
|
|
5488
|
+
cellBase,
|
|
5489
|
+
"text-center",
|
|
5490
|
+
"font-semibold uppercase tracking-wide text-gray-500",
|
|
5491
|
+
size === "sm" ? "text-[10px]" : "text-xs",
|
|
5492
|
+
"border-b border-gray-200",
|
|
5493
|
+
virtualized ? "sticky z-10 bg-gray-50" : "",
|
|
5494
|
+
h.headerClassName ?? ""
|
|
5495
|
+
].filter(Boolean).join(" "),
|
|
5496
|
+
children: h.title
|
|
5497
|
+
},
|
|
5498
|
+
h.key ?? `group-${hi}`
|
|
5499
|
+
);
|
|
5500
|
+
}
|
|
5501
|
+
return headerCell(h, leaves.indexOf(h), grouped ? 2 : 1);
|
|
5502
|
+
})
|
|
5503
|
+
] }),
|
|
5090
5504
|
grouped && /* @__PURE__ */ jsx("tr", { className: "border-b border-gray-200 bg-gray-50", children: columns.flatMap((h) => isGroup(h) ? h.columns : []).map(
|
|
5091
5505
|
(col) => headerCell(col, leaves.indexOf(col), 1, headRowH)
|
|
5092
5506
|
) })
|
|
5093
5507
|
] }),
|
|
5094
|
-
/* @__PURE__ */ jsx("tbody", { children: data.length === 0 && !loading ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan:
|
|
5095
|
-
topPad > 0 && /* @__PURE__ */ jsx("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx("td", { colSpan:
|
|
5508
|
+
/* @__PURE__ */ jsx("tbody", { children: data.length === 0 && !loading ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: colCount, className: `${cellBase} py-10 text-center text-gray-500`, children: emptyContent }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5509
|
+
topPad > 0 && /* @__PURE__ */ jsx("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx("td", { colSpan: colCount, style: { height: topPad, padding: 0, border: 0 } }) }),
|
|
5096
5510
|
data.slice(start, end).map((row, si) => {
|
|
5097
5511
|
const i = start + si;
|
|
5098
5512
|
const rowProps = onRow?.(row, i);
|
|
5099
|
-
return /* @__PURE__ */
|
|
5513
|
+
return /* @__PURE__ */ jsxs(
|
|
5100
5514
|
"tr",
|
|
5101
5515
|
{
|
|
5102
5516
|
style: virtualized ? { height: virtualized.rowHeight } : void 0,
|
|
@@ -5116,32 +5530,55 @@ function DataTable({
|
|
|
5116
5530
|
rowClassName?.(row, i) ?? "",
|
|
5117
5531
|
rowProps?.className ?? ""
|
|
5118
5532
|
].filter(Boolean).join(" "),
|
|
5119
|
-
children:
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5533
|
+
children: [
|
|
5534
|
+
selection && (() => {
|
|
5535
|
+
const key = keyOf(row, i);
|
|
5536
|
+
return /* @__PURE__ */ jsx(
|
|
5537
|
+
"td",
|
|
5538
|
+
{
|
|
5539
|
+
style: { width: SELECT_W },
|
|
5540
|
+
onClick: (e) => e.stopPropagation(),
|
|
5541
|
+
className: [cellBase, hasPinned ? "sticky left-0 z-10 bg-white" : ""].filter(Boolean).join(" "),
|
|
5542
|
+
children: /* @__PURE__ */ jsx(
|
|
5543
|
+
"input",
|
|
5544
|
+
{
|
|
5545
|
+
type: "checkbox",
|
|
5546
|
+
"aria-label": strings.table.selectRow,
|
|
5547
|
+
checked: selectedSet.has(key),
|
|
5548
|
+
onChange: () => toggleRow(key),
|
|
5549
|
+
className: "h-4 w-4 rounded border-gray-300 text-blue-600"
|
|
5550
|
+
}
|
|
5551
|
+
)
|
|
5552
|
+
}
|
|
5553
|
+
);
|
|
5554
|
+
})(),
|
|
5555
|
+
leaves.map((col, ci) => {
|
|
5556
|
+
const pinned = col.fixed === "left";
|
|
5557
|
+
return /* @__PURE__ */ jsx(
|
|
5558
|
+
"td",
|
|
5559
|
+
{
|
|
5560
|
+
style: pinned ? { left: (offsets[ci] ?? 0) + selOffset } : void 0,
|
|
5561
|
+
className: [
|
|
5562
|
+
cellBase,
|
|
5563
|
+
ALIGN2[col.align ?? (col.numeric ? "right" : "left")],
|
|
5564
|
+
col.numeric ? "font-mono" : "",
|
|
5565
|
+
"text-gray-900",
|
|
5566
|
+
col.ellipsis ? "max-w-0 truncate" : "",
|
|
5567
|
+
// A pinned cell needs its own background or the
|
|
5568
|
+
// scrolling columns show through it.
|
|
5569
|
+
pinned ? "sticky z-10 bg-white" : ""
|
|
5570
|
+
].filter(Boolean).join(" "),
|
|
5571
|
+
children: col.render ? col.render(row, i) : col.dataIndex ? row[col.dataIndex] : null
|
|
5572
|
+
},
|
|
5573
|
+
col.key
|
|
5574
|
+
);
|
|
5575
|
+
})
|
|
5576
|
+
]
|
|
5140
5577
|
},
|
|
5141
5578
|
keyOf(row, i)
|
|
5142
5579
|
);
|
|
5143
5580
|
}),
|
|
5144
|
-
bottomPad > 0 && /* @__PURE__ */ jsx("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx("td", { colSpan:
|
|
5581
|
+
bottomPad > 0 && /* @__PURE__ */ jsx("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx("td", { colSpan: colCount, style: { height: bottomPad, padding: 0, border: 0 } }) })
|
|
5145
5582
|
] }) })
|
|
5146
5583
|
] }),
|
|
5147
5584
|
footer
|
|
@@ -5204,8 +5641,8 @@ function Sparkline({
|
|
|
5204
5641
|
const max = Math.max(...data);
|
|
5205
5642
|
const min = Math.min(...data);
|
|
5206
5643
|
const span = max - min || 1;
|
|
5207
|
-
const
|
|
5208
|
-
const y = (v) => height -
|
|
5644
|
+
const pad5 = strokeWidth + (showDots ? 2 : 0);
|
|
5645
|
+
const y = (v) => height - pad5 - (v - min) / span * (height - pad5 * 2);
|
|
5209
5646
|
const pts = data.length === 1 ? [[0, height / 2], [width, height / 2]] : data.map((v, i) => [i * width / (data.length - 1), y(v)]);
|
|
5210
5647
|
const line = pts.map(([x, yy], i) => `${i === 0 ? "M" : "L"}${x.toFixed(2)},${yy.toFixed(2)}`).join(" ");
|
|
5211
5648
|
const area = `${line} L${width.toFixed(2)},${height} L0,${height} Z`;
|
|
@@ -6107,6 +6544,6 @@ var ALT_SHIFT_D = isMac ? "\u2325\u21E7D" : "Alt+Shift+D";
|
|
|
6107
6544
|
var ALT_SHIFT_E = isMac ? "\u2325\u21E7E" : "Alt+Shift+E";
|
|
6108
6545
|
var ALT_SHIFT_N = isMac ? "\u2325\u21E7N" : "Alt+Shift+N";
|
|
6109
6546
|
|
|
6110
|
-
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, 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, inputClasses, isMac, isSeverityTone, lastEnabledIndex, matchTypeahead, mediaFileName, nextEnabledIndex, resolveTheme, severityOf, tabButtonId, tabPanelId, toISODate, useClickOutside, useTheme };
|
|
6111
|
-
//# sourceMappingURL=chunk-
|
|
6112
|
-
//# sourceMappingURL=chunk-
|
|
6547
|
+
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, FormErrorSummary, 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 };
|
|
6548
|
+
//# sourceMappingURL=chunk-S6K37RLY.js.map
|
|
6549
|
+
//# sourceMappingURL=chunk-S6K37RLY.js.map
|