efficient-shell 4.126.4 → 4.131.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 +972 -4
- package/dist/{Browser-IIVSJJIO.js → Browser-PSEMJFZE.js} +13 -9
- package/dist/Browser-PSEMJFZE.js.map +1 -0
- package/dist/{Calculator-HCKFTSJR.js → Calculator-ZXJPXG7F.js} +12 -8
- package/dist/Calculator-ZXJPXG7F.js.map +1 -0
- package/dist/ConfirmDialog-MTC7QMUJ.js +4 -0
- package/dist/{ConfirmDialog-LJXMB45A.js.map → ConfirmDialog-MTC7QMUJ.js.map} +1 -1
- package/dist/{CurrencyConverter-BKKORN6K.js → CurrencyConverter-WSJ2BBSX.js} +12 -8
- package/dist/CurrencyConverter-WSJ2BBSX.js.map +1 -0
- package/dist/{Documents-MIU3AWGL.js → Documents-PGMZR2MA.js} +14 -10
- package/dist/Documents-PGMZR2MA.js.map +1 -0
- package/dist/{Files-N2P2LJ5R.js → Files-2LKCJGYW.js} +17 -13
- package/dist/Files-2LKCJGYW.js.map +1 -0
- package/dist/{Notepad-L775LQBJ.js → Notepad-KW6WVABH.js} +15 -11
- package/dist/Notepad-KW6WVABH.js.map +1 -0
- package/dist/PdfViewer-M2YGZIYX.js +5 -0
- package/dist/{PdfViewer-LSP3YNFC.js.map → PdfViewer-M2YGZIYX.js.map} +1 -1
- package/dist/{PomodoroTimer-SVJ62RXM.js → PomodoroTimer-DG3LI5CX.js} +14 -10
- package/dist/PomodoroTimer-DG3LI5CX.js.map +1 -0
- package/dist/{Preview-G56SXZU4.js → Preview-E7EJJNXN.js} +16 -12
- package/dist/Preview-E7EJJNXN.js.map +1 -0
- package/dist/{Sidebar-J76PV4QF.js → Sidebar-BPU7RCZP.js} +5 -4
- package/dist/Sidebar-BPU7RCZP.js.map +1 -0
- package/dist/{Spreadsheet-ZP5KSNLJ.js → Spreadsheet-IDUODRZU.js} +14 -10
- package/dist/Spreadsheet-IDUODRZU.js.map +1 -0
- package/dist/{Stock-CDUS4VCZ.js → Stock-YMPOMUAW.js} +12 -8
- package/dist/Stock-YMPOMUAW.js.map +1 -0
- package/dist/{Weather-EEDBWBPQ.js → Weather-NZO3CWLH.js} +12 -8
- package/dist/Weather-NZO3CWLH.js.map +1 -0
- package/dist/{WorldClock-FFFULVTJ.js → WorldClock-HUC6D3AD.js} +12 -8
- package/dist/WorldClock-HUC6D3AD.js.map +1 -0
- package/dist/apps/index.js +26 -21
- package/dist/apps/index.js.map +1 -1
- package/dist/brand.css +1 -1
- package/dist/{chunk-N2CMEDSH.js → chunk-2GZQ352J.js} +4 -4
- package/dist/{chunk-N2CMEDSH.js.map → chunk-2GZQ352J.js.map} +1 -1
- package/dist/chunk-7IN7YZAL.js +547 -0
- package/dist/chunk-7IN7YZAL.js.map +1 -0
- package/dist/{chunk-YNGPTOL6.js → chunk-7MA5XBWD.js} +3 -3
- package/dist/{chunk-YNGPTOL6.js.map → chunk-7MA5XBWD.js.map} +1 -1
- package/dist/{chunk-4TVV2BIU.js → chunk-BJ34QOR3.js} +827 -624
- package/dist/chunk-BJ34QOR3.js.map +1 -0
- package/dist/{chunk-HNH7FOYB.js → chunk-CGXMWHQW.js} +7 -6
- package/dist/chunk-CGXMWHQW.js.map +1 -0
- package/dist/{chunk-N3CG5HG5.js → chunk-CLGNTGC5.js} +12 -11
- package/dist/chunk-CLGNTGC5.js.map +1 -0
- package/dist/chunk-D276EMXS.js +57 -0
- package/dist/chunk-D276EMXS.js.map +1 -0
- package/dist/{chunk-7KIOEKHS.js → chunk-E3TWIN7Z.js} +21 -135
- package/dist/chunk-E3TWIN7Z.js.map +1 -0
- package/dist/{chunk-2VM2FRZJ.js → chunk-EENVXIVU.js} +47 -67
- package/dist/chunk-EENVXIVU.js.map +1 -0
- package/dist/{chunk-YG45DAUT.js → chunk-FONEQRBH.js} +17 -11
- package/dist/chunk-FONEQRBH.js.map +1 -0
- package/dist/chunk-IPXN646P.js +14 -0
- package/dist/chunk-IPXN646P.js.map +1 -0
- package/dist/chunk-IRWSRJ4K.js +48 -0
- package/dist/chunk-IRWSRJ4K.js.map +1 -0
- package/dist/{chunk-JFQGPY7W.js → chunk-KWEX4ZAF.js} +20 -17
- package/dist/chunk-KWEX4ZAF.js.map +1 -0
- package/dist/chunk-LQTVTOSY.js +117 -0
- package/dist/chunk-LQTVTOSY.js.map +1 -0
- package/dist/{chunk-DMCFOWOJ.js → chunk-MQPX6ERJ.js} +4 -4
- package/dist/{chunk-DMCFOWOJ.js.map → chunk-MQPX6ERJ.js.map} +1 -1
- package/dist/{chunk-FQB24B42.js → chunk-SEWF4O3H.js} +3 -3
- package/dist/{chunk-FQB24B42.js.map → chunk-SEWF4O3H.js.map} +1 -1
- package/dist/{chunk-AXWC3332.js → chunk-TFXJRHJV.js} +3 -3
- package/dist/{chunk-AXWC3332.js.map → chunk-TFXJRHJV.js.map} +1 -1
- package/dist/{chunk-YNHLQ24V.js → chunk-TQURTLK2.js} +59 -143
- package/dist/chunk-TQURTLK2.js.map +1 -0
- package/dist/{chunk-6XQHH7D2.js → chunk-TRCWINHF.js} +5 -5
- package/dist/{chunk-6XQHH7D2.js.map → chunk-TRCWINHF.js.map} +1 -1
- package/dist/chunk-UHPWZ2F4.js +7 -0
- package/dist/{chunk-K6ZT6MWE.js.map → chunk-UHPWZ2F4.js.map} +1 -1
- package/dist/{chunk-32W6VY2J.js → chunk-VWZIGZFF.js} +4 -4
- package/dist/{chunk-32W6VY2J.js.map → chunk-VWZIGZFF.js.map} +1 -1
- package/dist/{chunk-HYZ5QMVO.js → chunk-XH3ELPQZ.js} +22 -19
- package/dist/chunk-XH3ELPQZ.js.map +1 -0
- package/dist/{chunk-W6XTG23K.js → chunk-ZKHD4J73.js} +8 -6
- package/dist/chunk-ZKHD4J73.js.map +1 -0
- package/dist/file-intake/index.js +3 -1
- package/dist/file-intake/index.js.map +1 -1
- package/dist/{index-dQia6NpB.d.ts → index-COwksV6G.d.ts} +699 -199
- package/dist/index.d.ts +2 -2
- package/dist/index.js +38 -31
- package/dist/index.js.map +1 -1
- package/dist/map/index.d.ts +329 -0
- package/dist/map/index.js +541 -0
- package/dist/map/index.js.map +1 -0
- package/dist/markdown/index.js +4 -3
- package/dist/markdown/index.js.map +1 -1
- package/dist/page-tabs/index.js +12 -8
- package/dist/page-tabs/index.js.map +1 -1
- package/dist/shell.css +17 -17
- package/dist/themes.css +15 -0
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +17 -12
- package/dist/ui/index.js.map +1 -1
- package/dist/ui.css +673 -283
- package/package.json +11 -1
- package/dist/Browser-IIVSJJIO.js.map +0 -1
- package/dist/Calculator-HCKFTSJR.js.map +0 -1
- package/dist/ConfirmDialog-LJXMB45A.js +0 -3
- package/dist/CurrencyConverter-BKKORN6K.js.map +0 -1
- package/dist/Documents-MIU3AWGL.js.map +0 -1
- package/dist/Files-N2P2LJ5R.js.map +0 -1
- package/dist/Notepad-L775LQBJ.js.map +0 -1
- package/dist/PdfViewer-LSP3YNFC.js +0 -4
- package/dist/PomodoroTimer-SVJ62RXM.js.map +0 -1
- package/dist/Preview-G56SXZU4.js.map +0 -1
- package/dist/Sidebar-J76PV4QF.js.map +0 -1
- package/dist/Spreadsheet-ZP5KSNLJ.js.map +0 -1
- package/dist/Stock-CDUS4VCZ.js.map +0 -1
- package/dist/Weather-EEDBWBPQ.js.map +0 -1
- package/dist/WorldClock-FFFULVTJ.js.map +0 -1
- package/dist/chunk-2VM2FRZJ.js.map +0 -1
- package/dist/chunk-3CUSBZWG.js +0 -59
- package/dist/chunk-3CUSBZWG.js.map +0 -1
- package/dist/chunk-4TVV2BIU.js.map +0 -1
- package/dist/chunk-7KIOEKHS.js.map +0 -1
- package/dist/chunk-HNH7FOYB.js.map +0 -1
- package/dist/chunk-HYZ5QMVO.js.map +0 -1
- package/dist/chunk-JFQGPY7W.js.map +0 -1
- package/dist/chunk-K6ZT6MWE.js +0 -7
- package/dist/chunk-N3CG5HG5.js.map +0 -1
- package/dist/chunk-W6XTG23K.js.map +0 -1
- package/dist/chunk-YG45DAUT.js.map +0 -1
- package/dist/chunk-YNHLQ24V.js.map +0 -1
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import { Breadcrumbs } from './chunk-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { toast_default } from './chunk-
|
|
5
|
-
import {
|
|
6
|
-
import { useFileIntake, humanSize, FileIntakeAlert } from './chunk-
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
1
|
+
import { Breadcrumbs } from './chunk-CGXMWHQW.js';
|
|
2
|
+
import { SidebarLayout } from './chunk-FONEQRBH.js';
|
|
3
|
+
import { BrandMark } from './chunk-TRCWINHF.js';
|
|
4
|
+
import { toast_default } from './chunk-EENVXIVU.js';
|
|
5
|
+
import { useIsMobile, useShortcutLabel, useShellPrefs } from './chunk-TQURTLK2.js';
|
|
6
|
+
import { useFileIntake, humanSize, FileIntakeAlert } from './chunk-CLGNTGC5.js';
|
|
7
|
+
import { BUTTON_BASE, BUTTON_VARIANTS, Button_default } from './chunk-LQTVTOSY.js';
|
|
8
|
+
import { PopupMenu, PopupMenuItem } from './chunk-E3TWIN7Z.js';
|
|
9
|
+
import { registerModalEscapeInterceptor, onOverlayOpen, Z_LAYERS, useDismissPopupsOnOpen, useFocusTrap, useScrollLock } from './chunk-XH3ELPQZ.js';
|
|
10
|
+
import { glassStyle } from './chunk-D276EMXS.js';
|
|
11
|
+
import { useShellLocale, useShellStrings, DEFAULT_SHELL_STRINGS, currentShellStrings, formatPlain, formatFixed, formatPercent, splitAround } from './chunk-7IN7YZAL.js';
|
|
12
|
+
import { useBrowserLayoutEffect, useBrowserValue, useBrowserValueOnce } from './chunk-IRWSRJ4K.js';
|
|
13
|
+
import { forwardRef, useCallback, useState, useRef, useId, useEffect, createContext, useMemo, Children, isValidElement, cloneElement, useContext, Fragment as Fragment$1, Component, useSyncExternalStore, useLayoutEffect } from 'react';
|
|
11
14
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
12
15
|
import { createPortal } from 'react-dom';
|
|
13
16
|
|
|
@@ -36,7 +39,7 @@ var IconButton_default = IconButton;
|
|
|
36
39
|
|
|
37
40
|
// src/forms/styles.ts
|
|
38
41
|
var INPUT_SHAPE_PRE = "block w-full rounded-md border border-gray-300 bg-white";
|
|
39
|
-
var INPUT_SHAPE_POST = "text-gray-800 placeholder:text-gray-400 shadow-sm focus:border-blue-400 focus
|
|
42
|
+
var INPUT_SHAPE_POST = "text-gray-800 placeholder:text-gray-400 shadow-sm focus:border-blue-400 rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring)]";
|
|
40
43
|
var INPUT_SIZES = {
|
|
41
44
|
// The desktop rungs carry no explicit height: a text control's height should
|
|
42
45
|
// follow its own font, or a long label wraps out of a box that was pinned.
|
|
@@ -52,7 +55,7 @@ var INPUT_SIZES = {
|
|
|
52
55
|
touch: "h-14 px-4 text-base"
|
|
53
56
|
};
|
|
54
57
|
var INPUT_BASE = `${INPUT_SHAPE_PRE} ${INPUT_SIZES.md} ${INPUT_SHAPE_POST}`;
|
|
55
|
-
var INPUT_INVALID = "border-red-300 focus:border-red-400 focus:ring-
|
|
58
|
+
var INPUT_INVALID = "border-red-300 focus:border-red-400 focus-visible:ring-[color:var(--rosh-focus-ring-invalid)]";
|
|
56
59
|
var INPUT_DISABLED = "disabled:cursor-not-allowed disabled:opacity-60";
|
|
57
60
|
function inputClasses(opts) {
|
|
58
61
|
const shape = opts?.size && opts.size !== "md" ? `${INPUT_SHAPE_PRE} ${INPUT_SIZES[opts.size]} ${INPUT_SHAPE_POST}` : INPUT_BASE;
|
|
@@ -134,7 +137,7 @@ function useDropdownPosition(triggerRef, open, options = {}) {
|
|
|
134
137
|
preferredMaxHeight = MENU_MAX_HEIGHT
|
|
135
138
|
} = options;
|
|
136
139
|
const [pos, setPos] = useState(null);
|
|
137
|
-
|
|
140
|
+
useBrowserLayoutEffect(() => {
|
|
138
141
|
if (!open) {
|
|
139
142
|
setPos(null);
|
|
140
143
|
return;
|
|
@@ -493,7 +496,7 @@ var Select = forwardRef(function Select2({ touchSize = "touch", ...props }, ref)
|
|
|
493
496
|
return isMobile ? /* @__PURE__ */ jsx(NativeSelect, { ref, ...props, size: touchSize }) : /* @__PURE__ */ jsx(ListboxSelect, { ref, ...props });
|
|
494
497
|
});
|
|
495
498
|
var Select_default = Select;
|
|
496
|
-
var BOX = "h-4 w-4 shrink-0 rounded border-gray-300 accent-blue-600 focus
|
|
499
|
+
var BOX = "h-4 w-4 shrink-0 rounded border-gray-300 accent-blue-600 rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring)] disabled:cursor-not-allowed disabled:opacity-60";
|
|
497
500
|
var Checkbox = forwardRef(function Checkbox2({ checked, onChange, indeterminate = false, label, description, disabled, className = "", ...rest }, ref) {
|
|
498
501
|
const inner = useRef(null);
|
|
499
502
|
useEffect(() => {
|
|
@@ -528,7 +531,7 @@ var Checkbox = forwardRef(function Checkbox2({ checked, onChange, indeterminate
|
|
|
528
531
|
] });
|
|
529
532
|
});
|
|
530
533
|
var Checkbox_default = Checkbox;
|
|
531
|
-
var DOT = "h-4 w-4 shrink-0 border-gray-300 accent-blue-600 focus
|
|
534
|
+
var DOT = "h-4 w-4 shrink-0 border-gray-300 accent-blue-600 rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring)] disabled:cursor-not-allowed disabled:opacity-60";
|
|
532
535
|
var Radio = forwardRef(function Radio2({ checked, onChange, label, description, disabled, className = "", ...rest }, ref) {
|
|
533
536
|
if (!label && !description) {
|
|
534
537
|
return /* @__PURE__ */ jsx(
|
|
@@ -686,7 +689,7 @@ function FormErrorSummary({ errors, title, autoFocus = true, className = "" }) {
|
|
|
686
689
|
ref: boxRef,
|
|
687
690
|
role: "alert",
|
|
688
691
|
tabIndex: -1,
|
|
689
|
-
className: `rounded-md border border-red-300 bg-red-50 px-4 py-3 focus
|
|
692
|
+
className: `rounded-md border border-red-300 bg-red-50 px-4 py-3 rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-invalid-solid)] ${className}`.trim(),
|
|
690
693
|
children: [
|
|
691
694
|
/* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold text-red-800", children: title ?? strings.form.errorSummaryTitle }),
|
|
692
695
|
/* @__PURE__ */ jsx("ul", { className: "mt-1.5 space-y-1", children: errors.map((e, i) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
|
|
@@ -737,9 +740,9 @@ function mediaKindWord(accept) {
|
|
|
737
740
|
if (acceptsImage && !acceptsVideo) return "image";
|
|
738
741
|
return "file";
|
|
739
742
|
}
|
|
740
|
-
function mediaPromptLine(accept) {
|
|
743
|
+
function mediaPromptLine(accept, strings = DEFAULT_SHELL_STRINGS.media) {
|
|
741
744
|
const kind = mediaKindWord(accept);
|
|
742
|
-
return
|
|
745
|
+
return kind === "image" ? strings.uploadImage : kind === "video" ? strings.uploadVideo : strings.uploadFile;
|
|
743
746
|
}
|
|
744
747
|
function dropzoneClass(dragOver, locked, extra = "") {
|
|
745
748
|
return [
|
|
@@ -749,7 +752,9 @@ function dropzoneClass(dragOver, locked, extra = "") {
|
|
|
749
752
|
extra
|
|
750
753
|
].filter(Boolean).join(" ");
|
|
751
754
|
}
|
|
752
|
-
|
|
755
|
+
function zoneFocusClass(locked) {
|
|
756
|
+
return locked ? "rosh-focus-ring" : "rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-zone)]";
|
|
757
|
+
}
|
|
753
758
|
function BusyOverlay({ label, rounded = "rounded-lg" }) {
|
|
754
759
|
return /* @__PURE__ */ jsxs(
|
|
755
760
|
"div",
|
|
@@ -768,7 +773,7 @@ function FilenameBadge({ children }) {
|
|
|
768
773
|
"span",
|
|
769
774
|
{
|
|
770
775
|
className: "absolute inset-x-1 bottom-1 truncate rounded px-1.5 py-0.5 text-xs text-white",
|
|
771
|
-
style: { background: "
|
|
776
|
+
style: { background: "var(--rosh-media-scrim)" },
|
|
772
777
|
children
|
|
773
778
|
}
|
|
774
779
|
);
|
|
@@ -825,18 +830,22 @@ function MediaUploadField({
|
|
|
825
830
|
fit = "cover",
|
|
826
831
|
height = 112,
|
|
827
832
|
placeholder,
|
|
828
|
-
cta
|
|
833
|
+
cta: ctaProp,
|
|
829
834
|
acceptHint,
|
|
830
835
|
showFilename = true,
|
|
831
836
|
allowReplace = true,
|
|
832
837
|
allowRemove = true,
|
|
833
|
-
replaceLabel
|
|
834
|
-
removeLabel
|
|
838
|
+
replaceLabel: replaceLabelProp,
|
|
839
|
+
removeLabel: removeLabelProp,
|
|
835
840
|
busy = false,
|
|
836
|
-
busyLabel
|
|
841
|
+
busyLabel: busyLabelProp,
|
|
837
842
|
disabled = false
|
|
838
843
|
}) {
|
|
839
|
-
const
|
|
844
|
+
const strings = useShellStrings().media;
|
|
845
|
+
const cta = ctaProp ?? strings.cta;
|
|
846
|
+
const replaceLabel = replaceLabelProp ?? strings.replace;
|
|
847
|
+
const removeLabel = removeLabelProp ?? strings.remove;
|
|
848
|
+
const busyLabel = busyLabelProp ?? strings.uploading;
|
|
840
849
|
const fieldId = useId();
|
|
841
850
|
const objectUrlRef = useRef(null);
|
|
842
851
|
const [videoBlobUrl, setVideoBlobUrl] = useState(null);
|
|
@@ -845,7 +854,7 @@ function MediaUploadField({
|
|
|
845
854
|
}, []);
|
|
846
855
|
const locked = disabled || busy;
|
|
847
856
|
const isVideo = !!value && (isVideoUrl(value, accept) || value === videoBlobUrl);
|
|
848
|
-
const dimLine = placeholder ?? mediaPromptLine(accept);
|
|
857
|
+
const dimLine = placeholder ?? mediaPromptLine(accept, strings);
|
|
849
858
|
const emitObjectUrl = (file) => {
|
|
850
859
|
if (objectUrlRef.current) URL.revokeObjectURL(objectUrlRef.current);
|
|
851
860
|
const url = URL.createObjectURL(file);
|
|
@@ -921,20 +930,14 @@ function MediaUploadField({
|
|
|
921
930
|
id: fieldId,
|
|
922
931
|
onClick: () => pick(),
|
|
923
932
|
disabled: locked,
|
|
924
|
-
"aria-label": typeof dimLine === "string" ? dimLine :
|
|
933
|
+
"aria-label": typeof dimLine === "string" ? dimLine : strings.upload,
|
|
925
934
|
"aria-busy": busy || void 0,
|
|
926
935
|
"aria-invalid": error ? true : void 0,
|
|
927
936
|
"aria-required": required || void 0,
|
|
928
937
|
"aria-describedby": error ? `${fieldId}-error` : hint ? `${fieldId}-hint` : void 0,
|
|
929
|
-
onFocus: () => setFocused(true),
|
|
930
|
-
onBlur: () => setFocused(false),
|
|
931
938
|
...intake.zoneProps,
|
|
932
|
-
className: dropzoneClass(dragOver, locked),
|
|
933
|
-
style: {
|
|
934
|
-
minHeight: height,
|
|
935
|
-
outline: "none",
|
|
936
|
-
boxShadow: focused && !locked ? FOCUS_RING : void 0
|
|
937
|
-
},
|
|
939
|
+
className: dropzoneClass(dragOver, locked, zoneFocusClass(locked)),
|
|
940
|
+
style: { minHeight: height },
|
|
938
941
|
children: busy ? /* @__PURE__ */ jsxs("span", { role: "status", className: "flex flex-col items-center gap-1.5", children: [
|
|
939
942
|
/* @__PURE__ */ jsx(Spinner, {}),
|
|
940
943
|
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-500", children: busyLabel })
|
|
@@ -983,6 +986,7 @@ function BrandAssetEditor({
|
|
|
983
986
|
const [saving, setSaving] = useState(false);
|
|
984
987
|
const [removing, setRemoving] = useState(false);
|
|
985
988
|
const noun = actionNoun(assetName);
|
|
989
|
+
const strings = useShellStrings().brandAsset;
|
|
986
990
|
const visibleUrl = stagedUrl || committedUrl || fallbackUrl || "";
|
|
987
991
|
const visibleHasAlpha = stagedFile ? null : committedUrl ? committedHasAlpha : fallbackHasAlpha;
|
|
988
992
|
const visibleIsLight = stagedFile ? null : committedUrl ? committedIsLight : fallbackIsLight;
|
|
@@ -1013,7 +1017,7 @@ function BrandAssetEditor({
|
|
|
1013
1017
|
setStagedFile(null);
|
|
1014
1018
|
setStagedUrl("");
|
|
1015
1019
|
} catch (cause) {
|
|
1016
|
-
setError(cause instanceof Error ? cause.message :
|
|
1020
|
+
setError(cause instanceof Error ? cause.message : strings.saveFailed(noun, assetName));
|
|
1017
1021
|
} finally {
|
|
1018
1022
|
setSaving(false);
|
|
1019
1023
|
}
|
|
@@ -1033,12 +1037,12 @@ function BrandAssetEditor({
|
|
|
1033
1037
|
try {
|
|
1034
1038
|
await onRemove();
|
|
1035
1039
|
} catch (cause) {
|
|
1036
|
-
setError(cause instanceof Error ? cause.message :
|
|
1040
|
+
setError(cause instanceof Error ? cause.message : strings.removeFailed(noun, assetName));
|
|
1037
1041
|
} finally {
|
|
1038
1042
|
setRemoving(false);
|
|
1039
1043
|
}
|
|
1040
1044
|
};
|
|
1041
|
-
return /* @__PURE__ */ jsxs("section", { "aria-label":
|
|
1045
|
+
return /* @__PURE__ */ jsxs("section", { "aria-label": strings.region(assetName, subjectName), className: "grid gap-4 lg:grid-cols-2", children: [
|
|
1042
1046
|
/* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [
|
|
1043
1047
|
/* @__PURE__ */ jsx(
|
|
1044
1048
|
MediaUploadField,
|
|
@@ -1048,7 +1052,7 @@ function BrandAssetEditor({
|
|
|
1048
1052
|
},
|
|
1049
1053
|
onFile: stage,
|
|
1050
1054
|
label: assetName,
|
|
1051
|
-
hint: error ||
|
|
1055
|
+
hint: error || strings.usedFor(subjectName),
|
|
1052
1056
|
error: error || void 0,
|
|
1053
1057
|
accept,
|
|
1054
1058
|
acceptHint,
|
|
@@ -1061,21 +1065,18 @@ function BrandAssetEditor({
|
|
|
1061
1065
|
}
|
|
1062
1066
|
),
|
|
1063
1067
|
/* @__PURE__ */ jsxs("div", { className: "mt-3 flex flex-wrap gap-2", children: [
|
|
1064
|
-
/* @__PURE__ */
|
|
1065
|
-
|
|
1066
|
-
noun
|
|
1067
|
-
] }),
|
|
1068
|
-
(stagedFile || committedUrl) && /* @__PURE__ */ jsx(Button_default, { variant: "ghost-danger", onClick: remove, disabled, loading: removing, children: stagedFile ? "Discard change" : `Remove ${noun}` })
|
|
1068
|
+
/* @__PURE__ */ jsx(Button_default, { onClick: save, disabled: !stagedFile || disabled, loading: saving, children: strings.save(noun, assetName) }),
|
|
1069
|
+
(stagedFile || committedUrl) && /* @__PURE__ */ jsx(Button_default, { variant: "ghost-danger", onClick: remove, disabled, loading: removing, children: stagedFile ? strings.discard : strings.remove(noun, assetName) })
|
|
1069
1070
|
] })
|
|
1070
1071
|
] }),
|
|
1071
|
-
previews.length > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", "aria-label":
|
|
1072
|
-
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-900", children:
|
|
1072
|
+
previews.length > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", "aria-label": strings.previews(assetName), children: [
|
|
1073
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-900", children: strings.preview }),
|
|
1073
1074
|
/* @__PURE__ */ jsx("div", { className: "mt-3 grid gap-3", children: previews.map((preview) => {
|
|
1074
1075
|
const mark = /* @__PURE__ */ jsx(
|
|
1075
1076
|
BrandMark,
|
|
1076
1077
|
{
|
|
1077
1078
|
src: visibleUrl,
|
|
1078
|
-
alt:
|
|
1079
|
+
alt: strings.alt(subjectName, assetName),
|
|
1079
1080
|
slot: preview.slot,
|
|
1080
1081
|
surface: preview.surface,
|
|
1081
1082
|
adaptive: true,
|
|
@@ -1230,28 +1231,27 @@ function MediaUploadGrid({
|
|
|
1230
1231
|
fit = "cover",
|
|
1231
1232
|
thumbSize = 96,
|
|
1232
1233
|
placeholder,
|
|
1233
|
-
cta
|
|
1234
|
+
cta: ctaProp,
|
|
1234
1235
|
acceptHint,
|
|
1235
1236
|
showCover = false,
|
|
1236
|
-
coverLabel
|
|
1237
|
+
coverLabel: coverLabelProp,
|
|
1237
1238
|
busy = false,
|
|
1238
|
-
busyLabel
|
|
1239
|
+
busyLabel: busyLabelProp,
|
|
1239
1240
|
disabled = false,
|
|
1240
1241
|
readOnly = false
|
|
1241
1242
|
}) {
|
|
1243
|
+
const strings = useShellStrings().media;
|
|
1244
|
+
const cta = ctaProp ?? strings.cta;
|
|
1245
|
+
const coverLabel = coverLabelProp ?? strings.cover;
|
|
1246
|
+
const busyLabel = busyLabelProp ?? strings.uploading;
|
|
1242
1247
|
const gridId = useId();
|
|
1243
1248
|
const [draggingIndex, setDraggingIndex] = useState(null);
|
|
1244
|
-
const [focusedKey, setFocusedKey] = useState(null);
|
|
1245
|
-
const ringStyle = (key) => ({
|
|
1246
|
-
outline: "none",
|
|
1247
|
-
...focusedKey === key && !locked ? { boxShadow: FOCUS_RING } : {}
|
|
1248
|
-
});
|
|
1249
|
-
const blurKey = (key) => setFocusedKey((k) => k === key ? null : k);
|
|
1250
1249
|
const locked = disabled || busy;
|
|
1251
1250
|
const canAdd = (!!onPick || !!onFiles) && !locked && !readOnly;
|
|
1252
1251
|
const canRemove = !!onRemove && !locked && !readOnly;
|
|
1253
1252
|
const reorderEnabled = !!onReorder && !locked && !readOnly;
|
|
1254
|
-
const
|
|
1253
|
+
const focusRing = zoneFocusClass(locked);
|
|
1254
|
+
const dimLine = placeholder ?? mediaPromptLine(accept, strings);
|
|
1255
1255
|
const intake = useFileIntake({
|
|
1256
1256
|
accept,
|
|
1257
1257
|
maxSizeBytes,
|
|
@@ -1299,7 +1299,7 @@ function MediaUploadGrid({
|
|
|
1299
1299
|
setDraggingIndex(null);
|
|
1300
1300
|
} : void 0,
|
|
1301
1301
|
tabIndex: reorderEnabled ? 0 : void 0,
|
|
1302
|
-
"aria-label": reorderEnabled ?
|
|
1302
|
+
"aria-label": reorderEnabled ? strings.reorder(name, index + 1, items.length) : void 0,
|
|
1303
1303
|
onKeyDown: reorderEnabled ? (e) => {
|
|
1304
1304
|
if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
|
|
1305
1305
|
if (index > 0) {
|
|
@@ -1313,17 +1313,12 @@ function MediaUploadGrid({
|
|
|
1313
1313
|
}
|
|
1314
1314
|
}
|
|
1315
1315
|
} : void 0,
|
|
1316
|
-
onFocus: reorderEnabled ? (e) => {
|
|
1317
|
-
if (e.target === e.currentTarget) setFocusedKey(`thumb:${item.id}`);
|
|
1318
|
-
} : void 0,
|
|
1319
|
-
onBlur: reorderEnabled ? (e) => {
|
|
1320
|
-
if (e.target === e.currentTarget) blurKey(`thumb:${item.id}`);
|
|
1321
|
-
} : void 0,
|
|
1322
1316
|
className: [
|
|
1323
1317
|
"relative shrink-0 overflow-hidden rounded-md border border-gray-200 bg-gray-100",
|
|
1318
|
+
focusRing,
|
|
1324
1319
|
draggingIndex === index ? "opacity-50" : ""
|
|
1325
1320
|
].join(" "),
|
|
1326
|
-
style: { ...square, cursor: reorderEnabled ? "move" : void 0
|
|
1321
|
+
style: { ...square, cursor: reorderEnabled ? "move" : void 0 },
|
|
1327
1322
|
children: [
|
|
1328
1323
|
video ? /* @__PURE__ */ jsx("video", { src: item.url, muted: true, playsInline: true, preload: "metadata", "aria-label": name, className: "h-full w-full", style: { objectFit: fit } }) : /* @__PURE__ */ jsx("img", { src: item.url, alt: name, className: "h-full w-full", style: { objectFit: fit } }),
|
|
1329
1324
|
isCover && /* @__PURE__ */ jsx("span", { className: "absolute left-1 top-1 rounded bg-blue-600 px-1.5 py-0.5 text-xs font-medium text-white", children: coverLabel }),
|
|
@@ -1333,11 +1328,9 @@ function MediaUploadGrid({
|
|
|
1333
1328
|
{
|
|
1334
1329
|
type: "button",
|
|
1335
1330
|
onClick: () => onRemove(item.id),
|
|
1336
|
-
"aria-label":
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
className: "absolute right-1 top-1 flex h-5 w-5 items-center justify-center rounded-full text-white",
|
|
1340
|
-
style: { background: "rgba(0,0,0,0.55)", ...ringStyle(`rm:${item.id}`) },
|
|
1331
|
+
"aria-label": strings.removeItem(name),
|
|
1332
|
+
className: `absolute right-1 top-1 flex h-5 w-5 items-center justify-center rounded-full text-white ${focusRing}`,
|
|
1333
|
+
style: { background: "var(--rosh-media-scrim-button)" },
|
|
1341
1334
|
children: REMOVE_ICON
|
|
1342
1335
|
}
|
|
1343
1336
|
)
|
|
@@ -1351,14 +1344,12 @@ function MediaUploadGrid({
|
|
|
1351
1344
|
{
|
|
1352
1345
|
type: "button",
|
|
1353
1346
|
onClick: () => pick(),
|
|
1354
|
-
"aria-label":
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
className: "flex shrink-0 flex-col items-center justify-center gap-1 rounded-md border-2 border-dashed border-gray-300 bg-gray-50 text-gray-400 transition-colors hover:bg-gray-100 hover:text-gray-500",
|
|
1358
|
-
style: { ...square, ...ringStyle("add") },
|
|
1347
|
+
"aria-label": strings.addMedia,
|
|
1348
|
+
className: `flex shrink-0 flex-col items-center justify-center gap-1 rounded-md border-2 border-dashed border-gray-300 bg-gray-50 text-gray-400 transition-colors hover:bg-gray-100 hover:text-gray-500 ${focusRing}`,
|
|
1349
|
+
style: square,
|
|
1359
1350
|
children: [
|
|
1360
1351
|
/* @__PURE__ */ jsx(UploadGlyph, { className: "h-5 w-5" }),
|
|
1361
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-500", children:
|
|
1352
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-500", children: strings.add })
|
|
1362
1353
|
]
|
|
1363
1354
|
}
|
|
1364
1355
|
);
|
|
@@ -1367,11 +1358,9 @@ function MediaUploadGrid({
|
|
|
1367
1358
|
{
|
|
1368
1359
|
type: "button",
|
|
1369
1360
|
onClick: () => pick(),
|
|
1370
|
-
"aria-label": typeof dimLine === "string" ? dimLine :
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
className: dropzoneClass(zoneDragOver, false),
|
|
1374
|
-
style: { minHeight: thumbSize + 32, ...ringStyle("zone") },
|
|
1361
|
+
"aria-label": typeof dimLine === "string" ? dimLine : strings.upload,
|
|
1362
|
+
className: dropzoneClass(zoneDragOver, false, focusRing),
|
|
1363
|
+
style: { minHeight: thumbSize + 32 },
|
|
1375
1364
|
children: [
|
|
1376
1365
|
/* @__PURE__ */ jsx("span", { className: "text-gray-400", children: /* @__PURE__ */ jsx(UploadGlyph, {}) }),
|
|
1377
1366
|
/* @__PURE__ */ jsx("span", { className: "px-3 text-xs text-gray-500", children: dimLine }),
|
|
@@ -1384,7 +1373,7 @@ function MediaUploadGrid({
|
|
|
1384
1373
|
{
|
|
1385
1374
|
className: "flex w-full items-center justify-center rounded-lg border border-gray-200 bg-gray-50 px-3 text-xs text-gray-400",
|
|
1386
1375
|
style: { minHeight: thumbSize + 32 },
|
|
1387
|
-
children:
|
|
1376
|
+
children: strings.empty
|
|
1388
1377
|
}
|
|
1389
1378
|
);
|
|
1390
1379
|
return /* @__PURE__ */ jsxs(FormField, { label, labelId: label ? `${gridId}-label` : void 0, htmlFor: gridId, hint, error, required, className, children: [
|
|
@@ -1400,9 +1389,9 @@ function MediaUploadGrid({
|
|
|
1400
1389
|
className: "relative rounded-lg transition-colors",
|
|
1401
1390
|
style: {
|
|
1402
1391
|
...locked ? { opacity: 0.6 } : {},
|
|
1403
|
-
//
|
|
1404
|
-
//
|
|
1405
|
-
...zoneDragOver ? { boxShadow: "0 0 0 2px
|
|
1392
|
+
// The drop halo, beside the lock's opacity in one style object. Its
|
|
1393
|
+
// colour is `--rosh-drop-ring`, the value it always was.
|
|
1394
|
+
...zoneDragOver ? { boxShadow: "0 0 0 2px var(--rosh-drop-ring)" } : {}
|
|
1406
1395
|
},
|
|
1407
1396
|
children: [
|
|
1408
1397
|
items.length === 0 ? emptyDropzone : /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
|
|
@@ -1417,7 +1406,10 @@ function MediaUploadGrid({
|
|
|
1417
1406
|
/* @__PURE__ */ jsx(FileIntakeAlert, { rejections: intake.rejections })
|
|
1418
1407
|
] });
|
|
1419
1408
|
}
|
|
1420
|
-
|
|
1409
|
+
|
|
1410
|
+
// src/utils/date.ts
|
|
1411
|
+
var MONTH_ABBR = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
1412
|
+
var MONTH_FULL = [
|
|
1421
1413
|
"January",
|
|
1422
1414
|
"February",
|
|
1423
1415
|
"March",
|
|
@@ -1431,8 +1423,118 @@ var MONTH_NAMES = [
|
|
|
1431
1423
|
"November",
|
|
1432
1424
|
"December"
|
|
1433
1425
|
];
|
|
1434
|
-
|
|
1435
|
-
|
|
1426
|
+
function monthAbbr(mm) {
|
|
1427
|
+
return MONTH_ABBR[parseInt(mm, 10) - 1] ?? mm;
|
|
1428
|
+
}
|
|
1429
|
+
function monthFull(mm) {
|
|
1430
|
+
return MONTH_FULL[parseInt(mm, 10) - 1] ?? mm;
|
|
1431
|
+
}
|
|
1432
|
+
function getUserDateFormat() {
|
|
1433
|
+
if (typeof window === "undefined") return "DD/MM/YYYY";
|
|
1434
|
+
try {
|
|
1435
|
+
return localStorage.getItem("user_date_format") || "DD/MM/YYYY";
|
|
1436
|
+
} catch {
|
|
1437
|
+
return "DD/MM/YYYY";
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
var DEFAULT_DATE_STYLE = { dateStyle: "medium" };
|
|
1441
|
+
var dateFormats = /* @__PURE__ */ new Map();
|
|
1442
|
+
function dateFormat(locale, options) {
|
|
1443
|
+
const key = `${locale}|${JSON.stringify(options)}`;
|
|
1444
|
+
let format2 = dateFormats.get(key);
|
|
1445
|
+
if (!format2) {
|
|
1446
|
+
format2 = new Intl.DateTimeFormat(locale, { ...options, timeZone: "UTC", calendar: "gregory" });
|
|
1447
|
+
dateFormats.set(key, format2);
|
|
1448
|
+
}
|
|
1449
|
+
return format2;
|
|
1450
|
+
}
|
|
1451
|
+
function formatDate(value, options) {
|
|
1452
|
+
if (!value) return "\u2014";
|
|
1453
|
+
const dateStr = value.includes("T") ? value.split("T")[0] : value;
|
|
1454
|
+
const [y, m, d] = dateStr.split("-").map(Number);
|
|
1455
|
+
if (!y || !m || !d) return value;
|
|
1456
|
+
if (options?.locale) {
|
|
1457
|
+
return dateFormat(options.locale, options.style ?? DEFAULT_DATE_STYLE).format(new Date(Date.UTC(y, m - 1, d)));
|
|
1458
|
+
}
|
|
1459
|
+
const dd = String(d).padStart(2, "0");
|
|
1460
|
+
const mm = String(m).padStart(2, "0");
|
|
1461
|
+
const yyyy = String(y);
|
|
1462
|
+
const fmt2 = getUserDateFormat();
|
|
1463
|
+
switch (fmt2) {
|
|
1464
|
+
case "MM/DD/YYYY":
|
|
1465
|
+
return `${mm}/${dd}/${yyyy}`;
|
|
1466
|
+
case "YYYY-MM-DD":
|
|
1467
|
+
return `${yyyy}-${mm}-${dd}`;
|
|
1468
|
+
case "DD-MM-YYYY":
|
|
1469
|
+
return `${dd}-${mm}-${yyyy}`;
|
|
1470
|
+
case "MM-DD-YYYY":
|
|
1471
|
+
return `${mm}-${dd}-${yyyy}`;
|
|
1472
|
+
case "DD.MM.YYYY":
|
|
1473
|
+
return `${dd}.${mm}.${yyyy}`;
|
|
1474
|
+
case "YYYY.MM.DD":
|
|
1475
|
+
return `${yyyy}.${mm}.${dd}`;
|
|
1476
|
+
case "YYYY/MM/DD":
|
|
1477
|
+
return `${yyyy}/${mm}/${dd}`;
|
|
1478
|
+
case "DD/MM/YY":
|
|
1479
|
+
return `${dd}/${mm}/${yyyy.slice(-2)}`;
|
|
1480
|
+
case "MM/DD/YY":
|
|
1481
|
+
return `${mm}/${dd}/${yyyy.slice(-2)}`;
|
|
1482
|
+
case "DD/MMM/YYYY":
|
|
1483
|
+
return `${dd}/${monthAbbr(mm)}/${yyyy}`;
|
|
1484
|
+
case "DD/MMM/YY":
|
|
1485
|
+
return `${dd}/${monthAbbr(mm)}/${yyyy.slice(-2)}`;
|
|
1486
|
+
case "DD MMM YYYY":
|
|
1487
|
+
return `${dd} ${monthAbbr(mm)} ${yyyy}`;
|
|
1488
|
+
case "MMM DD, YYYY":
|
|
1489
|
+
return `${monthAbbr(mm)} ${dd}, ${yyyy}`;
|
|
1490
|
+
case "DD MMMM YYYY":
|
|
1491
|
+
return `${dd} ${monthFull(mm)} ${yyyy}`;
|
|
1492
|
+
case "MMMM DD, YYYY":
|
|
1493
|
+
return `${monthFull(mm)} ${dd}, ${yyyy}`;
|
|
1494
|
+
case "DD/MM/YYYY":
|
|
1495
|
+
default:
|
|
1496
|
+
return `${dd}/${mm}/${yyyy}`;
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
var WEEKDAY_FULL = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
1500
|
+
var WEEKDAY_TWO = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
1501
|
+
var ENGLISH_NAMES = {
|
|
1502
|
+
months: MONTH_FULL,
|
|
1503
|
+
monthsShort: MONTH_ABBR,
|
|
1504
|
+
weekdays: WEEKDAY_FULL,
|
|
1505
|
+
weekdaysShort: WEEKDAY_TWO,
|
|
1506
|
+
monthYear: (year, month) => `${MONTH_FULL[month]} ${year}`,
|
|
1507
|
+
shortMonthYear: (year, month) => `${MONTH_ABBR[month]} ${year}`,
|
|
1508
|
+
longDate: (year, month, day) => `${day} ${MONTH_FULL[month]} ${year}`
|
|
1509
|
+
};
|
|
1510
|
+
var localeNames = /* @__PURE__ */ new Map();
|
|
1511
|
+
function calendarNames(locale) {
|
|
1512
|
+
if (!locale) return ENGLISH_NAMES;
|
|
1513
|
+
const cached = localeNames.get(locale);
|
|
1514
|
+
if (cached) return cached;
|
|
1515
|
+
const fmt2 = (options) => dateFormat(locale, options);
|
|
1516
|
+
const at = (year, month, day = 1) => new Date(Date.UTC(year, month, day));
|
|
1517
|
+
const monthLong = fmt2({ month: "long" });
|
|
1518
|
+
const monthShort = fmt2({ month: "short" });
|
|
1519
|
+
const weekdayLong = fmt2({ weekday: "long" });
|
|
1520
|
+
const weekdayShort = fmt2({ weekday: "short" });
|
|
1521
|
+
const monthYearFmt = fmt2({ month: "long", year: "numeric" });
|
|
1522
|
+
const shortMonthYearFmt = fmt2({ month: "short", year: "numeric" });
|
|
1523
|
+
const longDateFmt = fmt2({ day: "numeric", month: "long", year: "numeric" });
|
|
1524
|
+
const twelve = Array.from({ length: 12 }, (_, m) => m);
|
|
1525
|
+
const seven = Array.from({ length: 7 }, (_, i) => i);
|
|
1526
|
+
const names = {
|
|
1527
|
+
months: twelve.map((m) => monthLong.format(at(2e3, m))),
|
|
1528
|
+
monthsShort: twelve.map((m) => monthShort.format(at(2e3, m))),
|
|
1529
|
+
weekdays: seven.map((i) => weekdayLong.format(at(2e3, 0, 2 + i))),
|
|
1530
|
+
weekdaysShort: seven.map((i) => weekdayShort.format(at(2e3, 0, 2 + i))),
|
|
1531
|
+
monthYear: (year, month) => monthYearFmt.format(at(year, month)),
|
|
1532
|
+
shortMonthYear: (year, month) => shortMonthYearFmt.format(at(year, month)),
|
|
1533
|
+
longDate: (year, month, day) => longDateFmt.format(at(year, month, day))
|
|
1534
|
+
};
|
|
1535
|
+
localeNames.set(locale, names);
|
|
1536
|
+
return names;
|
|
1537
|
+
}
|
|
1436
1538
|
var pad = (n) => String(n).padStart(2, "0");
|
|
1437
1539
|
function toKey(d) {
|
|
1438
1540
|
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
@@ -1447,10 +1549,11 @@ function fromKey(key) {
|
|
|
1447
1549
|
var monthKey = (d) => `${d.getFullYear()}-${pad(d.getMonth() + 1)}`;
|
|
1448
1550
|
var YEARS_PER_PAGE = 12;
|
|
1449
1551
|
var yearPageStart = (y) => Math.floor(y / YEARS_PER_PAGE) * YEARS_PER_PAGE;
|
|
1450
|
-
function monthStart(key) {
|
|
1552
|
+
function monthStart(key, today) {
|
|
1451
1553
|
const m = /^(\d{4})-(\d{2})$/.exec(key);
|
|
1452
|
-
return m ? new Date(Number(m[1]), Number(m[2]) - 1, 1) :
|
|
1554
|
+
return m ? new Date(Number(m[1]), Number(m[2]) - 1, 1) : today;
|
|
1453
1555
|
}
|
|
1556
|
+
var readTodayKey = () => toKey(/* @__PURE__ */ new Date());
|
|
1454
1557
|
function buildCells(view, weekStartsOn) {
|
|
1455
1558
|
const first = new Date(view.getFullYear(), view.getMonth(), 1);
|
|
1456
1559
|
const lead = (first.getDay() - weekStartsOn + 7) % 7;
|
|
@@ -1479,32 +1582,45 @@ function Calendar({
|
|
|
1479
1582
|
className = ""
|
|
1480
1583
|
}) {
|
|
1481
1584
|
const selected = fromKey(value);
|
|
1482
|
-
const
|
|
1483
|
-
const
|
|
1484
|
-
const
|
|
1485
|
-
|
|
1486
|
-
|
|
1585
|
+
const todayKey = useBrowserValue(readTodayKey, null);
|
|
1586
|
+
const today = fromKey(todayKey);
|
|
1587
|
+
const strings = useShellStrings().calendar;
|
|
1588
|
+
const names = calendarNames(useShellLocale());
|
|
1589
|
+
const openingMonth = () => {
|
|
1590
|
+
if (!today) return null;
|
|
1487
1591
|
const here = monthKey(today);
|
|
1488
1592
|
if (min && here < min.slice(0, 7)) return min.slice(0, 7);
|
|
1489
1593
|
if (max && here > max.slice(0, 7)) return max.slice(0, 7);
|
|
1490
1594
|
return here;
|
|
1595
|
+
};
|
|
1596
|
+
const [innerMonth, setInnerMonth] = useState(() => {
|
|
1597
|
+
if (defaultMonth) return defaultMonth;
|
|
1598
|
+
if (selected) return monthKey(selected);
|
|
1599
|
+
return openingMonth();
|
|
1491
1600
|
});
|
|
1492
|
-
const viewMonth = month ?? innerMonth;
|
|
1493
|
-
const view = monthStart(viewMonth);
|
|
1601
|
+
const viewMonth = month ?? innerMonth ?? openingMonth();
|
|
1602
|
+
const view = viewMonth === null ? null : monthStart(viewMonth, today);
|
|
1494
1603
|
const [active, setActive] = useState(() => value ?? todayKey);
|
|
1495
1604
|
const gridRef = useRef(null);
|
|
1496
1605
|
const shouldFocus = useRef(false);
|
|
1497
1606
|
const [panel, setPanel] = useState("days");
|
|
1498
|
-
const cells = useMemo(() => buildCells(view, weekStartsOn), [viewMonth, weekStartsOn]);
|
|
1607
|
+
const cells = useMemo(() => view ? buildCells(view, weekStartsOn) : [], [viewMonth, weekStartsOn]);
|
|
1499
1608
|
const outOfRange = (key) => !!min && key < min || !!max && key > max;
|
|
1500
|
-
const
|
|
1501
|
-
const
|
|
1502
|
-
const
|
|
1609
|
+
const cursor = active ?? todayKey;
|
|
1610
|
+
const activeInView = cells.some((c) => toKey(c) === cursor);
|
|
1611
|
+
const fallbackCell = view ? cells.find((c) => c.getMonth() === view.getMonth()) ?? cells[0] : null;
|
|
1612
|
+
const activeKey = activeInView && cursor ? cursor : fallbackCell ? toKey(fallbackCell) : "";
|
|
1503
1613
|
useEffect(() => {
|
|
1504
1614
|
if (!shouldFocus.current) return;
|
|
1505
1615
|
shouldFocus.current = false;
|
|
1506
1616
|
gridRef.current?.querySelector('[data-active="true"]')?.focus();
|
|
1507
1617
|
}, [activeKey, viewMonth]);
|
|
1618
|
+
if (!view) {
|
|
1619
|
+
return /* @__PURE__ */ jsxs("div", { className, "aria-hidden": "true", "data-calendar-pending": "", children: [
|
|
1620
|
+
/* @__PURE__ */ jsx("div", { className: "mb-2 h-6" }),
|
|
1621
|
+
Array.from({ length: 7 }, (_, row) => /* @__PURE__ */ jsx("div", { className: row === 0 ? "py-1 text-xs" : "py-1.5 min-h-11 sm:min-h-0 text-sm", children: "\xA0" }, row))
|
|
1622
|
+
] });
|
|
1623
|
+
}
|
|
1508
1624
|
const pageBy = (n) => {
|
|
1509
1625
|
if (panel === "years") return new Date(view.getFullYear() + n * YEARS_PER_PAGE, view.getMonth(), 1);
|
|
1510
1626
|
if (panel === "months") return new Date(view.getFullYear() + n, view.getMonth(), 1);
|
|
@@ -1523,7 +1639,7 @@ function Calendar({
|
|
|
1523
1639
|
if (monthKey(next) !== viewMonth) goToMonth(next);
|
|
1524
1640
|
};
|
|
1525
1641
|
const onKeyDown = (e) => {
|
|
1526
|
-
const current = fromKey(activeKey) ?? today;
|
|
1642
|
+
const current = fromKey(activeKey) ?? today ?? view;
|
|
1527
1643
|
const step = {
|
|
1528
1644
|
ArrowLeft: () => addDays(current, -1),
|
|
1529
1645
|
ArrowRight: () => addDays(current, 1),
|
|
@@ -1550,16 +1666,16 @@ function Calendar({
|
|
|
1550
1666
|
if (mode !== "range" || !value || !endValue) return false;
|
|
1551
1667
|
return key > value && key < endValue;
|
|
1552
1668
|
};
|
|
1553
|
-
const label = ariaLabel ??
|
|
1669
|
+
const label = ariaLabel ?? names.monthYear(view.getFullYear(), view.getMonth());
|
|
1554
1670
|
return /* @__PURE__ */ jsxs("div", { className, children: [
|
|
1555
1671
|
/* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between px-1", children: [
|
|
1556
1672
|
/* @__PURE__ */ jsx(
|
|
1557
1673
|
"button",
|
|
1558
1674
|
{
|
|
1559
1675
|
type: "button",
|
|
1560
|
-
"aria-label": panel === "years" ?
|
|
1676
|
+
"aria-label": panel === "years" ? strings.previousYears : panel === "months" ? strings.previousYear : strings.previousMonth,
|
|
1561
1677
|
onClick: () => goToMonth(pageBack()),
|
|
1562
|
-
className: "rounded-full p-1 text-gray-600 hover:bg-gray-100 focus
|
|
1678
|
+
className: "rounded-full p-1 text-gray-600 hover:bg-gray-100 rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-solid)]",
|
|
1563
1679
|
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" }) })
|
|
1564
1680
|
}
|
|
1565
1681
|
),
|
|
@@ -1568,39 +1684,35 @@ function Calendar({
|
|
|
1568
1684
|
"button",
|
|
1569
1685
|
{
|
|
1570
1686
|
type: "button",
|
|
1571
|
-
"aria-label":
|
|
1687
|
+
"aria-label": strings.chooseMonth(names.months[view.getMonth()]),
|
|
1572
1688
|
onClick: () => setPanel((p) => p === "months" ? "days" : "months"),
|
|
1573
|
-
className: "rounded-md px-1.5 py-0.5 transition-colors hover:bg-gray-100 focus
|
|
1574
|
-
children:
|
|
1689
|
+
className: "rounded-md px-1.5 py-0.5 transition-colors hover:bg-gray-100 rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-solid)]",
|
|
1690
|
+
children: names.months[view.getMonth()]
|
|
1575
1691
|
}
|
|
1576
1692
|
),
|
|
1577
1693
|
/* @__PURE__ */ jsx(
|
|
1578
1694
|
"button",
|
|
1579
1695
|
{
|
|
1580
1696
|
type: "button",
|
|
1581
|
-
"aria-label":
|
|
1697
|
+
"aria-label": strings.chooseYear(view.getFullYear()),
|
|
1582
1698
|
onClick: () => setPanel((p) => p === "years" ? "days" : "years"),
|
|
1583
|
-
className: "rounded-md px-1.5 py-0.5 transition-colors hover:bg-gray-100 focus
|
|
1699
|
+
className: "rounded-md px-1.5 py-0.5 transition-colors hover:bg-gray-100 rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-solid)]",
|
|
1584
1700
|
children: view.getFullYear()
|
|
1585
1701
|
}
|
|
1586
1702
|
)
|
|
1587
|
-
] }) : /* @__PURE__ */
|
|
1588
|
-
MONTH_NAMES[view.getMonth()],
|
|
1589
|
-
" ",
|
|
1590
|
-
view.getFullYear()
|
|
1591
|
-
] }) }),
|
|
1703
|
+
] }) : /* @__PURE__ */ jsx("span", { children: names.monthYear(view.getFullYear(), view.getMonth()) }) }),
|
|
1592
1704
|
/* @__PURE__ */ jsx(
|
|
1593
1705
|
"button",
|
|
1594
1706
|
{
|
|
1595
1707
|
type: "button",
|
|
1596
|
-
"aria-label": panel === "years" ?
|
|
1708
|
+
"aria-label": panel === "years" ? strings.nextYears : panel === "months" ? strings.nextYear : strings.nextMonth,
|
|
1597
1709
|
onClick: () => goToMonth(pageForward()),
|
|
1598
|
-
className: "rounded-full p-1 text-gray-600 hover:bg-gray-100 focus
|
|
1710
|
+
className: "rounded-full p-1 text-gray-600 hover:bg-gray-100 rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-solid)]",
|
|
1599
1711
|
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" }) })
|
|
1600
1712
|
}
|
|
1601
1713
|
)
|
|
1602
1714
|
] }),
|
|
1603
|
-
panel === "months" && /* @__PURE__ */ jsx("div", { role: "group", "aria-label":
|
|
1715
|
+
panel === "months" && /* @__PURE__ */ jsx("div", { role: "group", "aria-label": strings.monthPanel, className: "grid grid-cols-3 gap-1 text-center text-sm", children: names.monthsShort.map((name, m) => /* @__PURE__ */ jsx(
|
|
1604
1716
|
"button",
|
|
1605
1717
|
{
|
|
1606
1718
|
type: "button",
|
|
@@ -1610,14 +1722,14 @@ function Calendar({
|
|
|
1610
1722
|
setPanel("days");
|
|
1611
1723
|
},
|
|
1612
1724
|
className: [
|
|
1613
|
-
"rounded-md py-4 transition-colors focus
|
|
1614
|
-
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"
|
|
1725
|
+
"rounded-md py-4 transition-colors rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-solid)]",
|
|
1726
|
+
m === view.getMonth() ? "bg-blue-600 font-semibold text-white" : today && m === today.getMonth() && view.getFullYear() === today.getFullYear() ? "font-medium text-blue-600 hover:bg-gray-100" : "text-gray-700 hover:bg-gray-100"
|
|
1615
1727
|
].join(" "),
|
|
1616
|
-
children: name
|
|
1728
|
+
children: name
|
|
1617
1729
|
},
|
|
1618
1730
|
name
|
|
1619
1731
|
)) }),
|
|
1620
|
-
panel === "years" && /* @__PURE__ */ jsx("div", { role: "group", "aria-label":
|
|
1732
|
+
panel === "years" && /* @__PURE__ */ jsx("div", { role: "group", "aria-label": strings.yearPanel, 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(
|
|
1621
1733
|
"button",
|
|
1622
1734
|
{
|
|
1623
1735
|
type: "button",
|
|
@@ -1627,8 +1739,8 @@ function Calendar({
|
|
|
1627
1739
|
setPanel("months");
|
|
1628
1740
|
},
|
|
1629
1741
|
className: [
|
|
1630
|
-
"rounded-md py-4 transition-colors focus
|
|
1631
|
-
y === view.getFullYear() ? "bg-blue-600 font-semibold text-white" : y === today
|
|
1742
|
+
"rounded-md py-4 transition-colors rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-solid)]",
|
|
1743
|
+
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"
|
|
1632
1744
|
].join(" "),
|
|
1633
1745
|
children: y
|
|
1634
1746
|
},
|
|
@@ -1645,7 +1757,7 @@ function Calendar({
|
|
|
1645
1757
|
children: [
|
|
1646
1758
|
/* @__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) => (
|
|
1647
1759
|
// abbr carries the full name: "Su" is read as a word otherwise.
|
|
1648
|
-
/* @__PURE__ */ jsx("div", { role: "columnheader", "aria-label":
|
|
1760
|
+
/* @__PURE__ */ jsx("div", { role: "columnheader", "aria-label": names.weekdays[d], className: "py-1", children: /* @__PURE__ */ jsx("abbr", { title: names.weekdays[d], className: "no-underline", children: names.weekdaysShort[d] }) }, d)
|
|
1649
1761
|
)) }),
|
|
1650
1762
|
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) => {
|
|
1651
1763
|
const key = toKey(cell);
|
|
@@ -1660,7 +1772,7 @@ function Calendar({
|
|
|
1660
1772
|
"data-active": key === activeKey,
|
|
1661
1773
|
tabIndex: key === activeKey ? 0 : -1,
|
|
1662
1774
|
disabled,
|
|
1663
|
-
"aria-label":
|
|
1775
|
+
"aria-label": names.longDate(cell.getFullYear(), cell.getMonth(), cell.getDate()),
|
|
1664
1776
|
"aria-current": key === todayKey ? "date" : void 0,
|
|
1665
1777
|
onClick: () => {
|
|
1666
1778
|
setActive(key);
|
|
@@ -1671,7 +1783,7 @@ function Calendar({
|
|
|
1671
1783
|
// every touch-target guideline there is, and a date grid
|
|
1672
1784
|
// is seven of them side by side — the case where missing
|
|
1673
1785
|
// by four pixels picks the wrong day rather than nothing.
|
|
1674
|
-
"w-full rounded-md py-1.5 min-h-11 sm:min-h-0 transition-colors focus
|
|
1786
|
+
"w-full rounded-md py-1.5 min-h-11 sm:min-h-0 transition-colors rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-solid)]",
|
|
1675
1787
|
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",
|
|
1676
1788
|
key === todayKey && !isSelected ? "font-semibold text-blue-600" : ""
|
|
1677
1789
|
].filter(Boolean).join(" "),
|
|
@@ -1684,7 +1796,7 @@ function Calendar({
|
|
|
1684
1796
|
)
|
|
1685
1797
|
] });
|
|
1686
1798
|
}
|
|
1687
|
-
var
|
|
1799
|
+
var PRESETS = ["last2Weeks", "lastMonth", "last3Months", "last6Months", "last12Months"];
|
|
1688
1800
|
var monthKeyOf = (d) => `${d.getFullYear()}-${pad2(d.getMonth() + 1)}`;
|
|
1689
1801
|
var pad2 = (n) => String(n).padStart(2, "0");
|
|
1690
1802
|
function toISODate(d) {
|
|
@@ -1698,15 +1810,38 @@ function defaultFormatDisplay(s) {
|
|
|
1698
1810
|
const [y, m, d] = s.split("-");
|
|
1699
1811
|
return y && m && d ? `${d}/${m}/${y}` : s;
|
|
1700
1812
|
}
|
|
1813
|
+
var numericDates = /* @__PURE__ */ new Map();
|
|
1814
|
+
function localeFormatDisplay(locale) {
|
|
1815
|
+
let format2 = numericDates.get(locale);
|
|
1816
|
+
if (!format2) {
|
|
1817
|
+
format2 = new Intl.DateTimeFormat(locale, {
|
|
1818
|
+
year: "numeric",
|
|
1819
|
+
month: "2-digit",
|
|
1820
|
+
day: "2-digit",
|
|
1821
|
+
timeZone: "UTC",
|
|
1822
|
+
calendar: "gregory"
|
|
1823
|
+
});
|
|
1824
|
+
numericDates.set(locale, format2);
|
|
1825
|
+
}
|
|
1826
|
+
const intl = format2;
|
|
1827
|
+
return (s) => {
|
|
1828
|
+
const [y, m, d] = s.split("-").map(Number);
|
|
1829
|
+
return y && m && d ? intl.format(new Date(Date.UTC(y, m - 1, d))) : s;
|
|
1830
|
+
};
|
|
1831
|
+
}
|
|
1701
1832
|
function DateRangePicker({
|
|
1702
1833
|
from,
|
|
1703
1834
|
to,
|
|
1704
1835
|
onChange,
|
|
1705
|
-
formatDisplay
|
|
1836
|
+
formatDisplay: formatDisplayProp,
|
|
1706
1837
|
clearable = true,
|
|
1707
|
-
placeholder
|
|
1838
|
+
placeholder: placeholderProp,
|
|
1708
1839
|
fullWidth = false
|
|
1709
1840
|
}) {
|
|
1841
|
+
const strings = useShellStrings().dateRange;
|
|
1842
|
+
const locale = useShellLocale();
|
|
1843
|
+
const formatDisplay = formatDisplayProp ?? (locale ? localeFormatDisplay(locale) : defaultFormatDisplay);
|
|
1844
|
+
const placeholder = placeholderProp ?? strings.placeholder;
|
|
1710
1845
|
const [open, setOpen] = useState(false);
|
|
1711
1846
|
const [tempFrom, setTempFrom] = useState(from);
|
|
1712
1847
|
const [tempTo, setTempTo] = useState(to);
|
|
@@ -1741,27 +1876,27 @@ function DateRangePicker({
|
|
|
1741
1876
|
setViewMonth(monthKeyOf(from ? parseDate(from) : now));
|
|
1742
1877
|
setOpen(true);
|
|
1743
1878
|
};
|
|
1744
|
-
const handlePreset = (
|
|
1879
|
+
const handlePreset = (preset) => {
|
|
1745
1880
|
let start, end;
|
|
1746
|
-
switch (
|
|
1747
|
-
case "
|
|
1881
|
+
switch (preset) {
|
|
1882
|
+
case "last2Weeks":
|
|
1748
1883
|
end = /* @__PURE__ */ new Date();
|
|
1749
1884
|
start = /* @__PURE__ */ new Date();
|
|
1750
1885
|
start.setDate(start.getDate() - 14);
|
|
1751
1886
|
break;
|
|
1752
|
-
case "
|
|
1887
|
+
case "lastMonth":
|
|
1753
1888
|
start = new Date(now.getFullYear(), now.getMonth() - 1, 1);
|
|
1754
1889
|
end = new Date(now.getFullYear(), now.getMonth(), 0);
|
|
1755
1890
|
break;
|
|
1756
|
-
case "
|
|
1891
|
+
case "last3Months":
|
|
1757
1892
|
start = new Date(now.getFullYear(), now.getMonth() - 3, 1);
|
|
1758
1893
|
end = new Date(now.getFullYear(), now.getMonth(), 0);
|
|
1759
1894
|
break;
|
|
1760
|
-
case "
|
|
1895
|
+
case "last6Months":
|
|
1761
1896
|
start = new Date(now.getFullYear(), now.getMonth() - 6, 1);
|
|
1762
1897
|
end = new Date(now.getFullYear(), now.getMonth(), 0);
|
|
1763
1898
|
break;
|
|
1764
|
-
case "
|
|
1899
|
+
case "last12Months":
|
|
1765
1900
|
start = new Date(now.getFullYear(), now.getMonth() - 12, 1);
|
|
1766
1901
|
end = new Date(now.getFullYear(), now.getMonth(), 0);
|
|
1767
1902
|
break;
|
|
@@ -1770,7 +1905,7 @@ function DateRangePicker({
|
|
|
1770
1905
|
}
|
|
1771
1906
|
setTempFrom(toISODate(start));
|
|
1772
1907
|
setTempTo(toISODate(end));
|
|
1773
|
-
setActivePreset(
|
|
1908
|
+
setActivePreset(preset);
|
|
1774
1909
|
setViewMonth(monthKeyOf(start));
|
|
1775
1910
|
};
|
|
1776
1911
|
const handleCalendarSelect = (date) => {
|
|
@@ -1795,12 +1930,12 @@ function DateRangePicker({
|
|
|
1795
1930
|
onChange("", "");
|
|
1796
1931
|
setOpen(false);
|
|
1797
1932
|
};
|
|
1798
|
-
const displayText = from && to ? `${displayDate(from)} \u2014 ${displayDate(to)}` : from ?
|
|
1933
|
+
const displayText = from && to ? `${displayDate(from)} \u2014 ${displayDate(to)}` : from ? strings.fromOnly(displayDate(from)) : to ? strings.toOnly(displayDate(to)) : "";
|
|
1799
1934
|
return /* @__PURE__ */ jsxs("div", { className: `relative${fullWidth ? " w-full" : ""}`, ref, children: [
|
|
1800
1935
|
/* @__PURE__ */ jsxs(
|
|
1801
1936
|
"div",
|
|
1802
1937
|
{
|
|
1803
|
-
className: `${fullWidth ? "flex w-full" : "inline-flex"} items-center gap-2 border rounded-lg px-2.5 py-1.5 text-sm focus-within:border-blue-500 focus-
|
|
1938
|
+
className: `${fullWidth ? "flex w-full" : "inline-flex"} items-center gap-2 border rounded-lg px-2.5 py-1.5 text-sm focus-within:border-blue-500 has-focus-visible:ring-1 has-focus-visible:ring-[color:var(--rosh-focus-ring-deep)] ${from || to ? "border-blue-400 bg-blue-50 text-blue-700" : "border-gray-300 text-gray-500"}`,
|
|
1804
1939
|
children: [
|
|
1805
1940
|
/* @__PURE__ */ jsxs(
|
|
1806
1941
|
"button",
|
|
@@ -1809,7 +1944,7 @@ function DateRangePicker({
|
|
|
1809
1944
|
onClick: handleOpen,
|
|
1810
1945
|
"aria-haspopup": "dialog",
|
|
1811
1946
|
"aria-expanded": open,
|
|
1812
|
-
className: `inline-flex items-center gap-2 focus
|
|
1947
|
+
className: `inline-flex items-center gap-2 rosh-focus-ring${fullWidth ? " min-w-0 flex-1 justify-start" : ""}`,
|
|
1813
1948
|
children: [
|
|
1814
1949
|
/* @__PURE__ */ jsx("svg", { className: "w-4 h-4 shrink-0", fill: "none", stroke: "currentColor", strokeWidth: "2", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
|
|
1815
1950
|
/* @__PURE__ */ jsx("span", { className: "truncate", children: displayText || placeholder })
|
|
@@ -1821,8 +1956,8 @@ function DateRangePicker({
|
|
|
1821
1956
|
{
|
|
1822
1957
|
type: "button",
|
|
1823
1958
|
onClick: handleClear,
|
|
1824
|
-
"aria-label":
|
|
1825
|
-
className: "text-blue-400 hover:text-red-500 focus
|
|
1959
|
+
"aria-label": strings.clearRange,
|
|
1960
|
+
className: "text-blue-400 hover:text-red-500 rosh-focus-ring focus-visible:ring-1 focus-visible:ring-[color:var(--rosh-focus-ring-deep)] rounded",
|
|
1826
1961
|
children: "\xD7"
|
|
1827
1962
|
}
|
|
1828
1963
|
)
|
|
@@ -1835,7 +1970,7 @@ function DateRangePicker({
|
|
|
1835
1970
|
{
|
|
1836
1971
|
ref: panelRef,
|
|
1837
1972
|
role: "dialog",
|
|
1838
|
-
"aria-label":
|
|
1973
|
+
"aria-label": strings.dialog,
|
|
1839
1974
|
className: "fixed rounded-2xl p-4",
|
|
1840
1975
|
style: {
|
|
1841
1976
|
zIndex: Z_LAYERS.popup,
|
|
@@ -1858,13 +1993,13 @@ function DateRangePicker({
|
|
|
1858
1993
|
children: [
|
|
1859
1994
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 mb-3", children: [
|
|
1860
1995
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1861
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-500", children:
|
|
1862
|
-
/* @__PURE__ */ jsx("span", { className: `text-sm px-2 py-1 rounded border min-w-[90px] ${tempFrom ? "border-blue-300 bg-blue-50 text-blue-700" : "border-gray-200 bg-gray-50 text-gray-400"}`, children: tempFrom ? displayDate(tempFrom) :
|
|
1996
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-500", children: strings.from }),
|
|
1997
|
+
/* @__PURE__ */ jsx("span", { className: `text-sm px-2 py-1 rounded border min-w-[90px] ${tempFrom ? "border-blue-300 bg-blue-50 text-blue-700" : "border-gray-200 bg-gray-50 text-gray-400"}`, children: tempFrom ? displayDate(tempFrom) : strings.start })
|
|
1863
1998
|
] }),
|
|
1864
1999
|
/* @__PURE__ */ jsx("span", { className: "text-gray-300", children: "\u2014" }),
|
|
1865
2000
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1866
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-500", children:
|
|
1867
|
-
/* @__PURE__ */ jsx("span", { className: `text-sm px-2 py-1 rounded border min-w-[90px] ${tempTo ? "border-blue-300 bg-blue-50 text-blue-700" : "border-gray-200 bg-gray-50 text-gray-400"}`, children: tempTo ? displayDate(tempTo) :
|
|
2001
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-500", children: strings.to }),
|
|
2002
|
+
/* @__PURE__ */ jsx("span", { className: `text-sm px-2 py-1 rounded border min-w-[90px] ${tempTo ? "border-blue-300 bg-blue-50 text-blue-700" : "border-gray-200 bg-gray-50 text-gray-400"}`, children: tempTo ? displayDate(tempTo) : strings.end })
|
|
1868
2003
|
] })
|
|
1869
2004
|
] }),
|
|
1870
2005
|
/* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
|
|
@@ -1877,17 +2012,17 @@ function DateRangePicker({
|
|
|
1877
2012
|
month: viewMonth,
|
|
1878
2013
|
onMonthChange: setViewMonth,
|
|
1879
2014
|
onSelect: handleCalendarSelect,
|
|
1880
|
-
"aria-label":
|
|
2015
|
+
"aria-label": strings.dialog
|
|
1881
2016
|
}
|
|
1882
2017
|
) }),
|
|
1883
2018
|
/* @__PURE__ */ jsxs("div", { className: "border-l border-gray-200 pl-4 flex flex-col gap-1 min-w-[130px]", children: [
|
|
1884
|
-
|
|
2019
|
+
PRESETS.map((label) => /* @__PURE__ */ jsx(
|
|
1885
2020
|
"button",
|
|
1886
2021
|
{
|
|
1887
2022
|
type: "button",
|
|
1888
2023
|
onClick: () => handlePreset(label),
|
|
1889
2024
|
className: `text-left px-3 py-1.5 text-sm rounded-md transition-colors ${activePreset === label ? "bg-blue-50 text-blue-700 font-medium" : "text-gray-700 hover:bg-gray-50"}`,
|
|
1890
|
-
children: label
|
|
2025
|
+
children: strings[label]
|
|
1891
2026
|
},
|
|
1892
2027
|
label
|
|
1893
2028
|
)),
|
|
@@ -1897,14 +2032,14 @@ function DateRangePicker({
|
|
|
1897
2032
|
type: "button",
|
|
1898
2033
|
onClick: () => setActivePreset("Custom"),
|
|
1899
2034
|
className: `text-left px-3 py-1.5 text-sm rounded-md transition-colors ${activePreset === "Custom" ? "bg-blue-50 text-blue-700 font-medium" : "text-gray-700 hover:bg-gray-50"}`,
|
|
1900
|
-
children:
|
|
2035
|
+
children: strings.custom
|
|
1901
2036
|
}
|
|
1902
2037
|
)
|
|
1903
2038
|
] })
|
|
1904
2039
|
] }),
|
|
1905
2040
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 mt-4 pt-3 border-t border-gray-200", children: [
|
|
1906
|
-
clearable && /* @__PURE__ */ jsx("button", { type: "button", onClick: handleClear, className: "px-3 py-1.5 text-sm text-gray-500 hover:text-gray-700", children:
|
|
1907
|
-
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => setOpen(false), className: "px-3 py-1.5 text-sm text-gray-600 border border-gray-300 rounded-md hover:bg-gray-50", children:
|
|
2041
|
+
clearable && /* @__PURE__ */ jsx("button", { type: "button", onClick: handleClear, className: "px-3 py-1.5 text-sm text-gray-500 hover:text-gray-700", children: strings.clear }),
|
|
2042
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => setOpen(false), className: "px-3 py-1.5 text-sm text-gray-600 border border-gray-300 rounded-md hover:bg-gray-50", children: strings.cancel }),
|
|
1908
2043
|
/* @__PURE__ */ jsx(
|
|
1909
2044
|
"button",
|
|
1910
2045
|
{
|
|
@@ -1912,7 +2047,7 @@ function DateRangePicker({
|
|
|
1912
2047
|
onClick: handleApply,
|
|
1913
2048
|
disabled: !tempFrom || !tempTo,
|
|
1914
2049
|
className: "px-4 py-1.5 text-sm font-medium text-white bg-blue-600 rounded-md hover:bg-blue-700 disabled:opacity-50",
|
|
1915
|
-
children:
|
|
2050
|
+
children: strings.apply
|
|
1916
2051
|
}
|
|
1917
2052
|
)
|
|
1918
2053
|
] })
|
|
@@ -1936,11 +2071,13 @@ function toInputValue(value, withSeconds) {
|
|
|
1936
2071
|
}
|
|
1937
2072
|
var TimePicker = forwardRef(function TimePicker2({ value, onChange, min, max, invalid, size, className = "", step, ...rest }, ref) {
|
|
1938
2073
|
const withSeconds = step != null && Number(step) < 60;
|
|
2074
|
+
const locale = useShellLocale();
|
|
1939
2075
|
return /* @__PURE__ */ jsx(
|
|
1940
2076
|
"input",
|
|
1941
2077
|
{
|
|
1942
2078
|
ref,
|
|
1943
2079
|
type: "time",
|
|
2080
|
+
lang: locale,
|
|
1944
2081
|
step,
|
|
1945
2082
|
"aria-invalid": invalid || void 0,
|
|
1946
2083
|
value: toInputValue(value, withSeconds),
|
|
@@ -1954,20 +2091,6 @@ var TimePicker = forwardRef(function TimePicker2({ value, onChange, min, max, in
|
|
|
1954
2091
|
});
|
|
1955
2092
|
var TimePicker_default = TimePicker;
|
|
1956
2093
|
var ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
1957
|
-
var MONTH_NAMES2 = [
|
|
1958
|
-
"January",
|
|
1959
|
-
"February",
|
|
1960
|
-
"March",
|
|
1961
|
-
"April",
|
|
1962
|
-
"May",
|
|
1963
|
-
"June",
|
|
1964
|
-
"July",
|
|
1965
|
-
"August",
|
|
1966
|
-
"September",
|
|
1967
|
-
"October",
|
|
1968
|
-
"November",
|
|
1969
|
-
"December"
|
|
1970
|
-
];
|
|
1971
2094
|
function toInputValue2(value) {
|
|
1972
2095
|
if (value === null || value === void 0 || value === "") return "";
|
|
1973
2096
|
if (value instanceof Date) return Number.isNaN(value.getTime()) ? "" : toISODate(value);
|
|
@@ -1981,9 +2104,9 @@ function fromInputValue(raw) {
|
|
|
1981
2104
|
const date = new Date(year, month - 1, day);
|
|
1982
2105
|
return date.getMonth() === month - 1 && date.getDate() === day ? date : null;
|
|
1983
2106
|
}
|
|
1984
|
-
function display(key) {
|
|
2107
|
+
function display(key, names) {
|
|
1985
2108
|
const d = fromInputValue(key);
|
|
1986
|
-
return d ?
|
|
2109
|
+
return d ? names.longDate(d.getFullYear(), d.getMonth(), d.getDate()) : "";
|
|
1987
2110
|
}
|
|
1988
2111
|
var DatePicker = forwardRef(function DatePicker2({
|
|
1989
2112
|
value,
|
|
@@ -2006,6 +2129,9 @@ var DatePicker = forwardRef(function DatePicker2({
|
|
|
2006
2129
|
const current = toInputValue2(value);
|
|
2007
2130
|
const lo = toInputValue2(min);
|
|
2008
2131
|
const hi = toInputValue2(max);
|
|
2132
|
+
const strings = useShellStrings().datePicker;
|
|
2133
|
+
const locale = useShellLocale();
|
|
2134
|
+
const names = calendarNames(locale);
|
|
2009
2135
|
const [open, setOpen] = useState(false);
|
|
2010
2136
|
const wrapRef = useRef(null);
|
|
2011
2137
|
const triggerRef = useRef(null);
|
|
@@ -2041,6 +2167,7 @@ var DatePicker = forwardRef(function DatePicker2({
|
|
|
2041
2167
|
{
|
|
2042
2168
|
ref,
|
|
2043
2169
|
type: "date",
|
|
2170
|
+
lang: locale,
|
|
2044
2171
|
id,
|
|
2045
2172
|
name,
|
|
2046
2173
|
disabled,
|
|
@@ -2070,11 +2197,11 @@ var DatePicker = forwardRef(function DatePicker2({
|
|
|
2070
2197
|
"aria-controls": open ? panelId : void 0,
|
|
2071
2198
|
"aria-describedby": describedBy,
|
|
2072
2199
|
"aria-invalid": invalid || void 0,
|
|
2073
|
-
"aria-label": ariaLabel ? `${ariaLabel}${current ? `, ${display(current)}` : ""}` : void 0,
|
|
2200
|
+
"aria-label": ariaLabel ? `${ariaLabel}${current ? `, ${display(current, names)}` : ""}` : void 0,
|
|
2074
2201
|
onClick: () => setOpen((o) => !o),
|
|
2075
2202
|
className: `${inputClasses({ invalid, size, className })} flex items-center justify-between text-left`,
|
|
2076
2203
|
children: [
|
|
2077
|
-
/* @__PURE__ */ jsx("span", { className: current ? "text-gray-900" : "text-gray-400", children: current ? display(current) : placeholder ??
|
|
2204
|
+
/* @__PURE__ */ jsx("span", { className: current ? "text-gray-900" : "text-gray-400", children: current ? display(current, names) : placeholder ?? strings.placeholder }),
|
|
2078
2205
|
/* @__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" }) })
|
|
2079
2206
|
]
|
|
2080
2207
|
}
|
|
@@ -2086,7 +2213,7 @@ var DatePicker = forwardRef(function DatePicker2({
|
|
|
2086
2213
|
ref: panelRef,
|
|
2087
2214
|
id: panelId,
|
|
2088
2215
|
role: "dialog",
|
|
2089
|
-
"aria-label": ariaLabel ??
|
|
2216
|
+
"aria-label": ariaLabel ?? strings.dialog,
|
|
2090
2217
|
className: "fixed w-72 rounded-xl border border-gray-200 bg-white p-3 shadow-lg",
|
|
2091
2218
|
style: {
|
|
2092
2219
|
zIndex: Z_LAYERS.popup,
|
|
@@ -2124,7 +2251,7 @@ var DatePicker = forwardRef(function DatePicker2({
|
|
|
2124
2251
|
onChange?.(null);
|
|
2125
2252
|
},
|
|
2126
2253
|
className: "rounded-md px-2 py-1 text-sm text-gray-500 hover:bg-gray-100 hover:text-gray-700",
|
|
2127
|
-
children:
|
|
2254
|
+
children: strings.clear
|
|
2128
2255
|
}
|
|
2129
2256
|
),
|
|
2130
2257
|
/* @__PURE__ */ jsx(
|
|
@@ -2137,7 +2264,7 @@ var DatePicker = forwardRef(function DatePicker2({
|
|
|
2137
2264
|
onChange?.(/* @__PURE__ */ new Date());
|
|
2138
2265
|
},
|
|
2139
2266
|
className: "rounded-md px-2 py-1 text-sm font-medium text-blue-600 hover:bg-blue-50",
|
|
2140
|
-
children:
|
|
2267
|
+
children: strings.today
|
|
2141
2268
|
}
|
|
2142
2269
|
)
|
|
2143
2270
|
] })
|
|
@@ -2170,11 +2297,13 @@ function fromInputValue2(raw) {
|
|
|
2170
2297
|
return date.getMonth() === month - 1 && date.getDate() === day ? date : null;
|
|
2171
2298
|
}
|
|
2172
2299
|
var DateTimePicker = forwardRef(function DateTimePicker2({ value, onChange, min, max, invalid, size, className = "", ...rest }, ref) {
|
|
2300
|
+
const locale = useShellLocale();
|
|
2173
2301
|
return /* @__PURE__ */ jsx(
|
|
2174
2302
|
"input",
|
|
2175
2303
|
{
|
|
2176
2304
|
ref,
|
|
2177
2305
|
type: "datetime-local",
|
|
2306
|
+
lang: locale,
|
|
2178
2307
|
"aria-invalid": invalid || void 0,
|
|
2179
2308
|
value: toInputValue3(value),
|
|
2180
2309
|
min: toInputValue3(min) || void 0,
|
|
@@ -2248,8 +2377,9 @@ async function writeClipboard(text, html) {
|
|
|
2248
2377
|
}
|
|
2249
2378
|
async function copyToClipboard(label, text, html) {
|
|
2250
2379
|
const ok = await writeClipboard(text, html);
|
|
2251
|
-
|
|
2252
|
-
|
|
2380
|
+
const strings = currentShellStrings().copy;
|
|
2381
|
+
if (ok) toast_default.success(strings.copiedLabel(label));
|
|
2382
|
+
else toast_default.error(strings.failed);
|
|
2253
2383
|
return ok;
|
|
2254
2384
|
}
|
|
2255
2385
|
var COPIED_MS = 2e3;
|
|
@@ -2283,13 +2413,14 @@ function Snippet({
|
|
|
2283
2413
|
}) {
|
|
2284
2414
|
const [copied, setCopied] = useState(false);
|
|
2285
2415
|
const timer = useRef(null);
|
|
2416
|
+
const strings = useShellStrings().copy;
|
|
2286
2417
|
useEffect(() => () => {
|
|
2287
2418
|
if (timer.current) clearTimeout(timer.current);
|
|
2288
2419
|
}, []);
|
|
2289
2420
|
const copy = useCallback(async () => {
|
|
2290
2421
|
const ok = await writeClipboard(value);
|
|
2291
2422
|
if (!ok) {
|
|
2292
|
-
toast_default.error(
|
|
2423
|
+
toast_default.error(strings.failed);
|
|
2293
2424
|
return;
|
|
2294
2425
|
}
|
|
2295
2426
|
setCopied(true);
|
|
@@ -2299,7 +2430,7 @@ function Snippet({
|
|
|
2299
2430
|
timer.current = null;
|
|
2300
2431
|
}, COPIED_MS);
|
|
2301
2432
|
onCopy?.(value);
|
|
2302
|
-
}, [value, onCopy]);
|
|
2433
|
+
}, [value, onCopy, strings]);
|
|
2303
2434
|
const { box, button } = SIZES[size];
|
|
2304
2435
|
const onButton = !hideCopyButton;
|
|
2305
2436
|
return /* @__PURE__ */ jsxs(
|
|
@@ -2323,14 +2454,14 @@ function Snippet({
|
|
|
2323
2454
|
IconButton_default,
|
|
2324
2455
|
{
|
|
2325
2456
|
id,
|
|
2326
|
-
"aria-label": label ?
|
|
2457
|
+
"aria-label": label ? strings.copyLabel(label) : strings.copy,
|
|
2327
2458
|
"aria-describedby": describedBy,
|
|
2328
2459
|
onClick: copy,
|
|
2329
2460
|
className: `${button} text-gray-400`,
|
|
2330
2461
|
children: copied ? /* @__PURE__ */ jsx(CheckGlyph, {}) : /* @__PURE__ */ jsx(CopyGlyph, {})
|
|
2331
2462
|
}
|
|
2332
2463
|
),
|
|
2333
|
-
/* @__PURE__ */ jsx("span", { "aria-live": "polite", className: "sr-only", children: copied ?
|
|
2464
|
+
/* @__PURE__ */ jsx("span", { "aria-live": "polite", className: "sr-only", children: copied ? strings.copied : "" })
|
|
2334
2465
|
] })
|
|
2335
2466
|
]
|
|
2336
2467
|
}
|
|
@@ -2358,10 +2489,11 @@ function NumericKeypad({
|
|
|
2358
2489
|
value,
|
|
2359
2490
|
onChange,
|
|
2360
2491
|
onEnter,
|
|
2361
|
-
enterLabel
|
|
2492
|
+
enterLabel,
|
|
2362
2493
|
enterDisabled,
|
|
2363
2494
|
className = ""
|
|
2364
2495
|
}) {
|
|
2496
|
+
const strings = useShellStrings().keypad;
|
|
2365
2497
|
const press = (next) => {
|
|
2366
2498
|
if (next !== value) onChange(next);
|
|
2367
2499
|
};
|
|
@@ -2381,7 +2513,7 @@ function NumericKeypad({
|
|
|
2381
2513
|
{
|
|
2382
2514
|
size: "touch-xl",
|
|
2383
2515
|
variant: "secondary",
|
|
2384
|
-
"aria-label":
|
|
2516
|
+
"aria-label": strings.backspace,
|
|
2385
2517
|
onClick: () => press(backspace(value)),
|
|
2386
2518
|
children: "\u232B"
|
|
2387
2519
|
}
|
|
@@ -2394,7 +2526,7 @@ function NumericKeypad({
|
|
|
2394
2526
|
className: "col-span-3",
|
|
2395
2527
|
disabled: enterDisabled,
|
|
2396
2528
|
onClick: onEnter,
|
|
2397
|
-
children: enterLabel
|
|
2529
|
+
children: enterLabel ?? strings.enter
|
|
2398
2530
|
}
|
|
2399
2531
|
)
|
|
2400
2532
|
] });
|
|
@@ -2412,10 +2544,13 @@ var TileButton = forwardRef(function TileButton2({ title, subtitle, size = "lg",
|
|
|
2412
2544
|
disabled,
|
|
2413
2545
|
"aria-pressed": selected || void 0,
|
|
2414
2546
|
className: [
|
|
2415
|
-
"flex w-full flex-col justify-between rounded-xl border text-left transition-colors",
|
|
2416
|
-
"focus:outline-none focus:ring-2 focus:ring-blue-400/40",
|
|
2547
|
+
"flex w-full flex-col justify-between rounded-xl border text-left transition-colors rosh-focus-ring",
|
|
2417
2548
|
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
2418
|
-
|
|
2549
|
+
// The focus ring only on a tile that is NOT chosen. A chosen tile already
|
|
2550
|
+
// wears the same ring, so in the kit's own focus nothing changes; under
|
|
2551
|
+
// `rosh-host-focus` the focus token goes transparent, and a focus ring
|
|
2552
|
+
// declared here as well would paint over the chosen one with nothing.
|
|
2553
|
+
selected ? "border-blue-600 bg-blue-50 ring-2 ring-blue-400/40" : "border-gray-200 bg-white hover:bg-gray-50 focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-strong)]",
|
|
2419
2554
|
SIZES2[size],
|
|
2420
2555
|
className
|
|
2421
2556
|
].filter(Boolean).join(" "),
|
|
@@ -2557,7 +2692,7 @@ var Switch = forwardRef(function Switch2({
|
|
|
2557
2692
|
...rest,
|
|
2558
2693
|
className: [
|
|
2559
2694
|
"relative inline-flex shrink-0 items-center rounded-full p-0.5 transition-colors",
|
|
2560
|
-
"focus
|
|
2695
|
+
"rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-strong)]",
|
|
2561
2696
|
"disabled:cursor-not-allowed disabled:opacity-40",
|
|
2562
2697
|
TRACK[size],
|
|
2563
2698
|
checked ? "bg-blue-600" : "bg-gray-300"
|
|
@@ -2705,7 +2840,7 @@ var FilePicker = forwardRef(function FilePicker2({
|
|
|
2705
2840
|
className = ""
|
|
2706
2841
|
}, ref) {
|
|
2707
2842
|
const zoneId = useId();
|
|
2708
|
-
const
|
|
2843
|
+
const strings = useShellStrings().files;
|
|
2709
2844
|
const intake = useFileIntake({
|
|
2710
2845
|
accept,
|
|
2711
2846
|
acceptHint,
|
|
@@ -2726,25 +2861,15 @@ var FilePicker = forwardRef(function FilePicker2({
|
|
|
2726
2861
|
id: zoneId,
|
|
2727
2862
|
disabled,
|
|
2728
2863
|
onClick: intake.open,
|
|
2729
|
-
onFocus: () => setFocused(true),
|
|
2730
|
-
onBlur: () => setFocused(false),
|
|
2731
2864
|
"aria-invalid": error ? true : void 0,
|
|
2732
2865
|
"aria-required": required || void 0,
|
|
2733
2866
|
"aria-describedby": describedBy,
|
|
2734
2867
|
...intake.zoneProps,
|
|
2735
|
-
className: dropzoneClass(intake.dragOver, disabled,
|
|
2736
|
-
style: { outline: "none", boxShadow: focused && !disabled ? FOCUS_RING : void 0 },
|
|
2868
|
+
className: dropzoneClass(intake.dragOver, disabled, `px-4 py-6 ${zoneFocusClass(disabled)}`),
|
|
2737
2869
|
children: [
|
|
2738
2870
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
2739
|
-
/* @__PURE__ */
|
|
2740
|
-
|
|
2741
|
-
multiple ? "files" : "a file"
|
|
2742
|
-
] }),
|
|
2743
|
-
/* @__PURE__ */ jsxs("span", { className: "text-sm text-gray-500", children: [
|
|
2744
|
-
" or drag ",
|
|
2745
|
-
multiple ? "them" : "it",
|
|
2746
|
-
" here"
|
|
2747
|
-
] })
|
|
2871
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-blue-600", children: multiple ? strings.chooseMany : strings.chooseOne }),
|
|
2872
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-gray-500", children: ` ${multiple ? strings.dragMany : strings.dragOne}` })
|
|
2748
2873
|
] }),
|
|
2749
2874
|
acceptHint && /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-400", children: acceptHint })
|
|
2750
2875
|
]
|
|
@@ -2753,7 +2878,7 @@ var FilePicker = forwardRef(function FilePicker2({
|
|
|
2753
2878
|
/* @__PURE__ */ jsx("input", { ...intake.inputProps }),
|
|
2754
2879
|
files.length > 0 && /* @__PURE__ */ jsx("ul", { className: "mt-2 flex flex-col gap-1", children: files.map((file, i) => /* @__PURE__ */ jsxs("li", { className: "flex items-center justify-between gap-3 rounded-md bg-gray-50 px-3 py-2", children: [
|
|
2755
2880
|
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-sm text-gray-800", title: file.name, children: file.name }),
|
|
2756
|
-
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs tabular-nums text-gray-500", children: humanSize(file.size) }),
|
|
2881
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs tabular-nums text-gray-500", children: humanSize(file.size, strings) }),
|
|
2757
2882
|
/* @__PURE__ */ jsx(
|
|
2758
2883
|
"button",
|
|
2759
2884
|
{
|
|
@@ -2763,7 +2888,7 @@ var FilePicker = forwardRef(function FilePicker2({
|
|
|
2763
2888
|
intake.clearRejections();
|
|
2764
2889
|
onChange(files.filter((_, j) => j !== i));
|
|
2765
2890
|
},
|
|
2766
|
-
"aria-label":
|
|
2891
|
+
"aria-label": strings.remove(file.name),
|
|
2767
2892
|
className: "shrink-0 text-gray-400 hover:text-gray-600",
|
|
2768
2893
|
children: /* @__PURE__ */ jsx(CloseGlyph, {})
|
|
2769
2894
|
}
|
|
@@ -2808,7 +2933,8 @@ function FileGlyph({ className = "h-4 w-4" }) {
|
|
|
2808
2933
|
}
|
|
2809
2934
|
);
|
|
2810
2935
|
}
|
|
2811
|
-
function AttachmentDropZone({ intake, dropLabel
|
|
2936
|
+
function AttachmentDropZone({ intake, dropLabel, className = "", children }) {
|
|
2937
|
+
const strings = useShellStrings().files;
|
|
2812
2938
|
return /* @__PURE__ */ jsxs("div", { ...intake.zoneProps, ...intake.pasteProps, className: `relative ${className}`, children: [
|
|
2813
2939
|
children,
|
|
2814
2940
|
/* @__PURE__ */ jsx("input", { ...intake.inputProps }),
|
|
@@ -2817,13 +2943,14 @@ function AttachmentDropZone({ intake, dropLabel = "Drop files to attach", classN
|
|
|
2817
2943
|
{
|
|
2818
2944
|
"aria-hidden": "true",
|
|
2819
2945
|
className: "pointer-events-none absolute inset-0 z-10 flex items-center justify-center rounded-lg border-2 border-dashed border-blue-500 bg-blue-50/80 text-sm font-medium text-blue-600",
|
|
2820
|
-
children: dropLabel
|
|
2946
|
+
children: dropLabel ?? strings.drop
|
|
2821
2947
|
}
|
|
2822
2948
|
)
|
|
2823
2949
|
] });
|
|
2824
2950
|
}
|
|
2825
2951
|
var canPreview = () => typeof URL !== "undefined" && typeof URL.createObjectURL === "function";
|
|
2826
2952
|
function AttachmentList({ files, onRemove, disabled = false, className = "" }) {
|
|
2953
|
+
const strings = useShellStrings().files;
|
|
2827
2954
|
const urls = useRef(/* @__PURE__ */ new Map());
|
|
2828
2955
|
useEffect(() => {
|
|
2829
2956
|
const live = new Set(files);
|
|
@@ -2857,14 +2984,14 @@ function AttachmentList({ files, onRemove, disabled = false, className = "" }) {
|
|
|
2857
2984
|
children: [
|
|
2858
2985
|
thumb ? /* @__PURE__ */ jsx("img", { src: thumb, alt: "", className: "h-6 w-6 shrink-0 rounded object-cover" }) : /* @__PURE__ */ jsx("span", { className: "text-gray-400", children: /* @__PURE__ */ jsx(FileGlyph, {}) }),
|
|
2859
2986
|
/* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", title: file.name, children: file.name }),
|
|
2860
|
-
/* @__PURE__ */ jsx("span", { className: "shrink-0 tabular-nums text-gray-400", children: humanSize(file.size) }),
|
|
2987
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 tabular-nums text-gray-400", children: humanSize(file.size, strings) }),
|
|
2861
2988
|
onRemove && /* @__PURE__ */ jsx(
|
|
2862
2989
|
"button",
|
|
2863
2990
|
{
|
|
2864
2991
|
type: "button",
|
|
2865
2992
|
disabled,
|
|
2866
2993
|
onClick: () => onRemove(i),
|
|
2867
|
-
"aria-label":
|
|
2994
|
+
"aria-label": strings.remove(file.name),
|
|
2868
2995
|
className: "shrink-0 rounded p-0.5 text-gray-400 hover:bg-gray-200 hover:text-gray-600 disabled:cursor-not-allowed",
|
|
2869
2996
|
children: /* @__PURE__ */ jsx(CloseGlyph, { className: "h-3.5 w-3.5" })
|
|
2870
2997
|
}
|
|
@@ -2875,7 +3002,9 @@ function AttachmentList({ files, onRemove, disabled = false, className = "" }) {
|
|
|
2875
3002
|
);
|
|
2876
3003
|
}) });
|
|
2877
3004
|
}
|
|
2878
|
-
function AttachButton({ onClick, count = 0, variant = "button", label
|
|
3005
|
+
function AttachButton({ onClick, count = 0, variant = "button", label: labelProp, disabled = false }) {
|
|
3006
|
+
const strings = useShellStrings().files;
|
|
3007
|
+
const label = labelProp ?? strings.attach;
|
|
2879
3008
|
const counted = count > 0 ? `${label} (${count})` : label;
|
|
2880
3009
|
if (variant === "icon") {
|
|
2881
3010
|
return /* @__PURE__ */ jsxs("span", { className: "relative inline-flex", children: [
|
|
@@ -2999,7 +3128,7 @@ function SearchableSelect({
|
|
|
2999
3128
|
setSearch("");
|
|
3000
3129
|
};
|
|
3001
3130
|
const [adornPad, setAdornPad] = useState(null);
|
|
3002
|
-
|
|
3131
|
+
useBrowserLayoutEffect(() => {
|
|
3003
3132
|
if (!rightAdornment || open) {
|
|
3004
3133
|
setAdornPad(null);
|
|
3005
3134
|
return;
|
|
@@ -3243,7 +3372,7 @@ function TagInput({
|
|
|
3243
3372
|
},
|
|
3244
3373
|
className: inputClasses({
|
|
3245
3374
|
invalid,
|
|
3246
|
-
className: `flex flex-wrap items-center gap-1 cursor-text focus-within:border-blue-400 focus-
|
|
3375
|
+
className: `flex flex-wrap items-center gap-1 cursor-text focus-within:border-blue-400 has-focus-visible:ring-2 has-focus-visible:ring-[color:var(--rosh-focus-ring)] ${disabled ? "bg-gray-50 cursor-not-allowed" : ""} ${className}`
|
|
3247
3376
|
}),
|
|
3248
3377
|
children: [
|
|
3249
3378
|
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: [
|
|
@@ -3252,9 +3381,9 @@ function TagInput({
|
|
|
3252
3381
|
"button",
|
|
3253
3382
|
{
|
|
3254
3383
|
type: "button",
|
|
3255
|
-
"aria-label": `${strings.select.remove} ${labelFor(v)}`,
|
|
3384
|
+
"aria-label": strings.select.removeItem?.(labelFor(v)) ?? `${strings.select.remove} ${labelFor(v)}`,
|
|
3256
3385
|
onClick: () => remove(v),
|
|
3257
|
-
className: "text-blue-400 hover:text-red-500 focus
|
|
3386
|
+
className: "text-blue-400 hover:text-red-500 rosh-focus-ring focus-visible:ring-1 focus-visible:ring-[color:var(--rosh-focus-ring-deep)] rounded leading-none",
|
|
3258
3387
|
children: "\xD7"
|
|
3259
3388
|
}
|
|
3260
3389
|
)
|
|
@@ -3297,7 +3426,7 @@ function TagInput({
|
|
|
3297
3426
|
setOpen(false);
|
|
3298
3427
|
}
|
|
3299
3428
|
},
|
|
3300
|
-
className: "min-w-[8ch] flex-1 border-none bg-transparent p-0 text-sm text-gray-800 placeholder:text-gray-400 focus
|
|
3429
|
+
className: "min-w-[8ch] flex-1 border-none bg-transparent p-0 text-sm text-gray-800 placeholder:text-gray-400 rosh-focus-ring focus-visible:ring-0 disabled:cursor-not-allowed"
|
|
3301
3430
|
}
|
|
3302
3431
|
)
|
|
3303
3432
|
]
|
|
@@ -3396,6 +3525,8 @@ function Card({
|
|
|
3396
3525
|
);
|
|
3397
3526
|
}
|
|
3398
3527
|
function StatCard({ label, value, icon, delta, className = "" }) {
|
|
3528
|
+
const locale = useShellLocale();
|
|
3529
|
+
const shown = typeof value === "number" && locale ? formatPlain(value, locale) : value;
|
|
3399
3530
|
const deltaColor = delta?.direction === "up" ? "text-green-600" : delta?.direction === "down" ? "text-red-600" : "text-gray-500";
|
|
3400
3531
|
const arrow = delta?.direction === "up" ? "\u25B2" : delta?.direction === "down" ? "\u25BC" : "\u2192";
|
|
3401
3532
|
return /* @__PURE__ */ jsxs("div", { className: `rounded-lg border border-gray-200 bg-white p-4 shadow-sm ${className}`.trim(), children: [
|
|
@@ -3404,7 +3535,7 @@ function StatCard({ label, value, icon, delta, className = "" }) {
|
|
|
3404
3535
|
icon && /* @__PURE__ */ jsx("span", { className: "text-gray-400", children: icon })
|
|
3405
3536
|
] }),
|
|
3406
3537
|
/* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-baseline gap-2", children: [
|
|
3407
|
-
/* @__PURE__ */ jsx("span", { className: "text-2xl font-semibold text-gray-900", children:
|
|
3538
|
+
/* @__PURE__ */ jsx("span", { className: "text-2xl font-semibold text-gray-900", children: shown }),
|
|
3408
3539
|
delta && /* @__PURE__ */ jsxs("span", { className: `text-xs font-medium ${deltaColor}`, children: [
|
|
3409
3540
|
arrow,
|
|
3410
3541
|
" ",
|
|
@@ -3687,7 +3818,8 @@ function CountBadge({
|
|
|
3687
3818
|
className = ""
|
|
3688
3819
|
}) {
|
|
3689
3820
|
const visible = dot || count > 0 || count === 0 && showZero;
|
|
3690
|
-
const
|
|
3821
|
+
const locale = useShellLocale();
|
|
3822
|
+
const label = count > max ? `${formatPlain(max, locale)}+` : formatPlain(count, locale);
|
|
3691
3823
|
const badge = visible ? dot ? /* @__PURE__ */ jsx(
|
|
3692
3824
|
"span",
|
|
3693
3825
|
{
|
|
@@ -3728,7 +3860,8 @@ function Statistic({
|
|
|
3728
3860
|
size = "md",
|
|
3729
3861
|
className = ""
|
|
3730
3862
|
}) {
|
|
3731
|
-
const
|
|
3863
|
+
const locale = useShellLocale();
|
|
3864
|
+
const shown = typeof value !== "number" ? value : precision != null ? formatFixed(value, precision, locale) : locale ? formatPlain(value, locale) : value;
|
|
3732
3865
|
return /* @__PURE__ */ jsxs("div", { className, children: [
|
|
3733
3866
|
title && /* @__PURE__ */ jsx("div", { className: "text-xs font-medium uppercase tracking-wide text-gray-500", children: title }),
|
|
3734
3867
|
/* @__PURE__ */ jsxs("div", { className: `mt-1 flex items-baseline gap-1 ${TONE3[tone]}`, children: [
|
|
@@ -3806,6 +3939,7 @@ function AvatarGroup({ children, max, size = "md", className = "" }) {
|
|
|
3806
3939
|
const overflow = max ? items.length - shown.length : 0;
|
|
3807
3940
|
const px = SIZE_PX[size];
|
|
3808
3941
|
const overlap = Math.round(px * 0.3);
|
|
3942
|
+
const locale = useShellLocale();
|
|
3809
3943
|
return /* @__PURE__ */ jsxs("div", { className: `flex items-center ${className}`.trim(), children: [
|
|
3810
3944
|
shown.map((child, i) => /* @__PURE__ */ jsx("span", { className: "rounded-full ring-2 ring-white", style: { marginLeft: i === 0 ? 0 : -overlap }, children: child }, i)),
|
|
3811
3945
|
overflow > 0 && /* @__PURE__ */ jsxs(
|
|
@@ -3815,7 +3949,7 @@ function AvatarGroup({ children, max, size = "md", className = "" }) {
|
|
|
3815
3949
|
style: { width: px, height: px, marginLeft: -overlap, fontSize: Math.round(px * 0.36) },
|
|
3816
3950
|
children: [
|
|
3817
3951
|
"+",
|
|
3818
|
-
overflow
|
|
3952
|
+
formatPlain(overflow, locale)
|
|
3819
3953
|
]
|
|
3820
3954
|
}
|
|
3821
3955
|
)
|
|
@@ -3859,6 +3993,7 @@ function Banner({
|
|
|
3859
3993
|
}) {
|
|
3860
3994
|
const t = TONE4[tone];
|
|
3861
3995
|
const solid = emphasis === "solid";
|
|
3996
|
+
const strings = useShellStrings().banner;
|
|
3862
3997
|
const box = solid ? TONE_SOLID[tone] : t.box;
|
|
3863
3998
|
const stick = sticky ? "sticky top-0 z-30" : "";
|
|
3864
3999
|
return /* @__PURE__ */ jsxs(
|
|
@@ -3878,7 +4013,7 @@ function Banner({
|
|
|
3878
4013
|
{
|
|
3879
4014
|
type: "button",
|
|
3880
4015
|
onClick: onDismiss,
|
|
3881
|
-
"aria-label":
|
|
4016
|
+
"aria-label": strings.dismiss,
|
|
3882
4017
|
className: `shrink-0 ${solid ? "opacity-80 hover:opacity-100" : "text-gray-400 hover:text-gray-600"}`,
|
|
3883
4018
|
children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", 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" }) })
|
|
3884
4019
|
}
|
|
@@ -4025,7 +4160,7 @@ function Stepper({
|
|
|
4025
4160
|
{
|
|
4026
4161
|
type: "button",
|
|
4027
4162
|
onClick: () => onChange?.(step.id),
|
|
4028
|
-
className: "relative z-10 flex min-w-0 flex-col items-center gap-1.5 rounded px-2 text-center focus
|
|
4163
|
+
className: "relative z-10 flex min-w-0 flex-col items-center gap-1.5 rounded px-2 text-center rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-solid)]",
|
|
4029
4164
|
children: [
|
|
4030
4165
|
circle,
|
|
4031
4166
|
text
|
|
@@ -4199,7 +4334,8 @@ function ColoredBadge({
|
|
|
4199
4334
|
const colour = colorClass ?? GROUP_COLORS[tone ?? "neutral"];
|
|
4200
4335
|
const sizeCls = size === "xs" ? "px-2 py-0.5 text-[10px]" : size === "md" ? "px-2.5 py-0.5 text-xs" : "px-2 py-0.5 text-xs";
|
|
4201
4336
|
const capCls = capitalize ? "capitalize" : "";
|
|
4202
|
-
const
|
|
4337
|
+
const strings = useShellStrings().badge;
|
|
4338
|
+
const closeName = closeLabel ?? (typeof children === "string" ? strings.removeItem(children) : strings.remove);
|
|
4203
4339
|
const closeSize = size === "xs" ? "h-2.5 w-2.5" : "h-3 w-3";
|
|
4204
4340
|
return /* @__PURE__ */ jsxs("span", { className: ["inline-flex items-center rounded-full font-medium", sizeCls, capCls, colour, className].filter(Boolean).join(" "), children: [
|
|
4205
4341
|
children,
|
|
@@ -4209,7 +4345,7 @@ function ColoredBadge({
|
|
|
4209
4345
|
type: "button",
|
|
4210
4346
|
onClick: onClose,
|
|
4211
4347
|
"aria-label": closeName,
|
|
4212
|
-
className: "-mr-0.5 ml-1 inline-flex shrink-0 items-center justify-center rounded-full opacity-70 transition-opacity hover:opacity-100 focus
|
|
4348
|
+
className: "-mr-0.5 ml-1 inline-flex shrink-0 items-center justify-center rounded-full opacity-70 transition-opacity hover:opacity-100 rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-strong)]",
|
|
4213
4349
|
children: /* @__PURE__ */ jsx("svg", { className: closeSize, viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" }) })
|
|
4214
4350
|
}
|
|
4215
4351
|
)
|
|
@@ -4228,7 +4364,8 @@ function EmptyState({
|
|
|
4228
4364
|
const v = frameless ? "none" : variant ?? "dashed";
|
|
4229
4365
|
const custom = typeof icon !== "boolean" && icon != null ? icon : null;
|
|
4230
4366
|
const showIcon = custom ? false : icon ?? v !== "card";
|
|
4231
|
-
const
|
|
4367
|
+
const strings = useShellStrings().emptyState;
|
|
4368
|
+
const primary = message ?? (title ? void 0 : strings.message);
|
|
4232
4369
|
const secondary = description ?? hint;
|
|
4233
4370
|
const frame = v === "card" ? "rounded-md border border-gray-200 bg-white px-6 py-12" : v === "none" ? "px-6 py-12" : "rounded-lg border-2 border-dashed border-gray-300 px-6 py-12";
|
|
4234
4371
|
return /* @__PURE__ */ jsxs("div", { className: `flex flex-col items-center justify-center text-center ${frame}`, children: [
|
|
@@ -4330,9 +4467,13 @@ function resolveSeverity(severity, component) {
|
|
|
4330
4467
|
tone: null,
|
|
4331
4468
|
fill: SEVERITY_UNKNOWN_FILL,
|
|
4332
4469
|
ink: SEVERITY_UNKNOWN_INK,
|
|
4333
|
-
word: `unrecognised severity ${described}
|
|
4470
|
+
word: `unrecognised severity ${described}`,
|
|
4471
|
+
token: described
|
|
4334
4472
|
};
|
|
4335
4473
|
}
|
|
4474
|
+
function severityWord(style, words) {
|
|
4475
|
+
return style.tone ? words[style.tone] : words.unrecognised(style.token ?? "");
|
|
4476
|
+
}
|
|
4336
4477
|
function warnOnce(key, message) {
|
|
4337
4478
|
if (reported.has(key)) return;
|
|
4338
4479
|
reported.add(key);
|
|
@@ -4358,11 +4499,14 @@ function MetricBar({
|
|
|
4358
4499
|
severity,
|
|
4359
4500
|
detail,
|
|
4360
4501
|
formatValue,
|
|
4361
|
-
emptyLabel
|
|
4502
|
+
emptyLabel: emptyLabelProp,
|
|
4362
4503
|
size = "sm",
|
|
4363
4504
|
ariaLabel,
|
|
4364
4505
|
className = ""
|
|
4365
4506
|
}) {
|
|
4507
|
+
const strings = useShellStrings().meter;
|
|
4508
|
+
const locale = useShellLocale();
|
|
4509
|
+
const emptyLabel = emptyLabelProp ?? strings.noData;
|
|
4366
4510
|
const reading2 = value != null && Number.isFinite(value) ? value : null;
|
|
4367
4511
|
const scale = Number.isFinite(max) && max > 0 ? max : null;
|
|
4368
4512
|
if (scale == null) {
|
|
@@ -4376,7 +4520,7 @@ function MetricBar({
|
|
|
4376
4520
|
const warnAt = boundOf(warn);
|
|
4377
4521
|
const critAt = boundOf(crit);
|
|
4378
4522
|
const width = reading2 != null && scale != null ? clampPct(reading2 / scale * 100) : 0;
|
|
4379
|
-
const format2 = formatValue ?? ((v) => scale === 100 ?
|
|
4523
|
+
const format2 = formatValue ?? ((v) => scale === 100 ? formatPercent(v, 1, locale) : formatPlain(v, locale));
|
|
4380
4524
|
const printed = reading2 != null ? format2(reading2) : "\u2014";
|
|
4381
4525
|
const showTicks = reading2 != null && scale != null && (warnAt != null || critAt != null);
|
|
4382
4526
|
const meterLabel = ariaLabel ?? (typeof label === "string" ? label : void 0);
|
|
@@ -4407,8 +4551,8 @@ function MetricBar({
|
|
|
4407
4551
|
style: { width: `${width}%` }
|
|
4408
4552
|
}
|
|
4409
4553
|
),
|
|
4410
|
-
showTicks && scale != null && warnAt != null && /* @__PURE__ */ jsx(Tick, { at: clampPct(warnAt / scale * 100), title:
|
|
4411
|
-
showTicks && scale != null && critAt != null && /* @__PURE__ */ jsx(Tick, { at: clampPct(critAt / scale * 100), title:
|
|
4554
|
+
showTicks && scale != null && warnAt != null && /* @__PURE__ */ jsx(Tick, { at: clampPct(warnAt / scale * 100), title: strings.warningAt(warnAt), className: "bg-gray-400 opacity-75" }),
|
|
4555
|
+
showTicks && scale != null && critAt != null && /* @__PURE__ */ jsx(Tick, { at: clampPct(critAt / scale * 100), title: strings.criticalAt(critAt), className: "bg-gray-500" })
|
|
4412
4556
|
]
|
|
4413
4557
|
}
|
|
4414
4558
|
);
|
|
@@ -4442,14 +4586,14 @@ function budgetState(elapsed, budget) {
|
|
|
4442
4586
|
if (allowed == null || allowed === 0) return "no-budget";
|
|
4443
4587
|
return spent > allowed ? "over" : "within";
|
|
4444
4588
|
}
|
|
4445
|
-
function defaultDuration(seconds) {
|
|
4589
|
+
function defaultDuration(seconds, words = DEFAULT_SHELL_STRINGS.meter) {
|
|
4446
4590
|
const total = Math.round(seconds);
|
|
4447
4591
|
const h = Math.floor(total / 3600);
|
|
4448
4592
|
const m = Math.floor(total % 3600 / 60);
|
|
4449
4593
|
const s = total % 60;
|
|
4450
|
-
if (h > 0) return
|
|
4451
|
-
if (m > 0) return
|
|
4452
|
-
return
|
|
4594
|
+
if (h > 0) return words.hoursMinutes(h, m);
|
|
4595
|
+
if (m > 0) return words.minutesSeconds(m, s);
|
|
4596
|
+
return words.seconds(s);
|
|
4453
4597
|
}
|
|
4454
4598
|
var clampPct2 = (n) => Math.min(100, Math.max(0, n));
|
|
4455
4599
|
function BudgetBar({
|
|
@@ -4458,13 +4602,18 @@ function BudgetBar({
|
|
|
4458
4602
|
budget,
|
|
4459
4603
|
grace,
|
|
4460
4604
|
detail,
|
|
4461
|
-
formatDuration
|
|
4462
|
-
emptyLabel
|
|
4463
|
-
noBudgetLabel
|
|
4605
|
+
formatDuration: formatDurationProp,
|
|
4606
|
+
emptyLabel: emptyLabelProp,
|
|
4607
|
+
noBudgetLabel: noBudgetLabelProp,
|
|
4464
4608
|
size = "sm",
|
|
4465
4609
|
ariaLabel,
|
|
4466
4610
|
className = ""
|
|
4467
4611
|
}) {
|
|
4612
|
+
const strings = useShellStrings().meter;
|
|
4613
|
+
const locale = useShellLocale();
|
|
4614
|
+
const formatDuration = formatDurationProp ?? ((seconds) => defaultDuration(seconds, strings));
|
|
4615
|
+
const emptyLabel = emptyLabelProp ?? strings.noReading;
|
|
4616
|
+
const noBudgetLabel = noBudgetLabelProp ?? strings.noBudget;
|
|
4468
4617
|
const spent = reading(elapsed);
|
|
4469
4618
|
const allowed = reading(budget);
|
|
4470
4619
|
const budgetAt = allowed != null && allowed > 0 ? allowed : null;
|
|
@@ -4479,7 +4628,7 @@ function BudgetBar({
|
|
|
4479
4628
|
const hatchEnd = !over ? 0 : scaledOverrun && span != null && spent != null ? clampPct2(spent / span * 100) : 100;
|
|
4480
4629
|
const hatchWidth = Math.max(0, hatchEnd - hatchStart);
|
|
4481
4630
|
const percent = spent != null && budgetAt != null ? spent / budgetAt * 100 : null;
|
|
4482
|
-
const printed = percent != null ?
|
|
4631
|
+
const printed = percent != null ? formatPercent(Math.round(percent), 0, locale) : spent != null ? formatDuration(spent) : "\u2014";
|
|
4483
4632
|
const trailing = detail ?? (spent == null ? emptyLabel : budgetAt == null ? noBudgetLabel : `${formatDuration(spent)} / ${formatDuration(budgetAt)}`);
|
|
4484
4633
|
const meterLabel = ariaLabel ?? (typeof label === "string" ? label : void 0);
|
|
4485
4634
|
const barHeight = size === "md" ? "h-2" : "h-1.5";
|
|
@@ -4493,7 +4642,7 @@ function BudgetBar({
|
|
|
4493
4642
|
"aria-valuemin": 0,
|
|
4494
4643
|
"aria-valuemax": span,
|
|
4495
4644
|
"aria-valuenow": Math.min(span, spent),
|
|
4496
|
-
"aria-valuetext":
|
|
4645
|
+
"aria-valuetext": strings.ofBudget(printed),
|
|
4497
4646
|
className: `relative mt-2 ${barHeight} overflow-hidden rounded-full bg-gray-200`,
|
|
4498
4647
|
children: [
|
|
4499
4648
|
(!over || scaledOverrun) && /* @__PURE__ */ jsx(
|
|
@@ -4513,7 +4662,7 @@ function BudgetBar({
|
|
|
4513
4662
|
graceAt > 0 && deadlineAt != null && /* @__PURE__ */ jsx(
|
|
4514
4663
|
"div",
|
|
4515
4664
|
{
|
|
4516
|
-
title:
|
|
4665
|
+
title: strings.budget,
|
|
4517
4666
|
className: "absolute inset-y-0 w-0.5 bg-gray-700",
|
|
4518
4667
|
style: { left: `${deadlineAt}%` }
|
|
4519
4668
|
}
|
|
@@ -4541,77 +4690,6 @@ function BudgetBar({
|
|
|
4541
4690
|
] });
|
|
4542
4691
|
}
|
|
4543
4692
|
|
|
4544
|
-
// src/utils/date.ts
|
|
4545
|
-
var MONTH_ABBR = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
4546
|
-
var MONTH_FULL = [
|
|
4547
|
-
"January",
|
|
4548
|
-
"February",
|
|
4549
|
-
"March",
|
|
4550
|
-
"April",
|
|
4551
|
-
"May",
|
|
4552
|
-
"June",
|
|
4553
|
-
"July",
|
|
4554
|
-
"August",
|
|
4555
|
-
"September",
|
|
4556
|
-
"October",
|
|
4557
|
-
"November",
|
|
4558
|
-
"December"
|
|
4559
|
-
];
|
|
4560
|
-
function monthAbbr(mm) {
|
|
4561
|
-
return MONTH_ABBR[parseInt(mm, 10) - 1] ?? mm;
|
|
4562
|
-
}
|
|
4563
|
-
function monthFull(mm) {
|
|
4564
|
-
return MONTH_FULL[parseInt(mm, 10) - 1] ?? mm;
|
|
4565
|
-
}
|
|
4566
|
-
function getUserDateFormat() {
|
|
4567
|
-
return localStorage.getItem("user_date_format") || "DD/MM/YYYY";
|
|
4568
|
-
}
|
|
4569
|
-
function formatDate(value) {
|
|
4570
|
-
if (!value) return "\u2014";
|
|
4571
|
-
const dateStr = value.includes("T") ? value.split("T")[0] : value;
|
|
4572
|
-
const [y, m, d] = dateStr.split("-").map(Number);
|
|
4573
|
-
if (!y || !m || !d) return value;
|
|
4574
|
-
const dd = String(d).padStart(2, "0");
|
|
4575
|
-
const mm = String(m).padStart(2, "0");
|
|
4576
|
-
const yyyy = String(y);
|
|
4577
|
-
const fmt2 = getUserDateFormat();
|
|
4578
|
-
switch (fmt2) {
|
|
4579
|
-
case "MM/DD/YYYY":
|
|
4580
|
-
return `${mm}/${dd}/${yyyy}`;
|
|
4581
|
-
case "YYYY-MM-DD":
|
|
4582
|
-
return `${yyyy}-${mm}-${dd}`;
|
|
4583
|
-
case "DD-MM-YYYY":
|
|
4584
|
-
return `${dd}-${mm}-${yyyy}`;
|
|
4585
|
-
case "MM-DD-YYYY":
|
|
4586
|
-
return `${mm}-${dd}-${yyyy}`;
|
|
4587
|
-
case "DD.MM.YYYY":
|
|
4588
|
-
return `${dd}.${mm}.${yyyy}`;
|
|
4589
|
-
case "YYYY.MM.DD":
|
|
4590
|
-
return `${yyyy}.${mm}.${dd}`;
|
|
4591
|
-
case "YYYY/MM/DD":
|
|
4592
|
-
return `${yyyy}/${mm}/${dd}`;
|
|
4593
|
-
case "DD/MM/YY":
|
|
4594
|
-
return `${dd}/${mm}/${yyyy.slice(-2)}`;
|
|
4595
|
-
case "MM/DD/YY":
|
|
4596
|
-
return `${mm}/${dd}/${yyyy.slice(-2)}`;
|
|
4597
|
-
case "DD/MMM/YYYY":
|
|
4598
|
-
return `${dd}/${monthAbbr(mm)}/${yyyy}`;
|
|
4599
|
-
case "DD/MMM/YY":
|
|
4600
|
-
return `${dd}/${monthAbbr(mm)}/${yyyy.slice(-2)}`;
|
|
4601
|
-
case "DD MMM YYYY":
|
|
4602
|
-
return `${dd} ${monthAbbr(mm)} ${yyyy}`;
|
|
4603
|
-
case "MMM DD, YYYY":
|
|
4604
|
-
return `${monthAbbr(mm)} ${dd}, ${yyyy}`;
|
|
4605
|
-
case "DD MMMM YYYY":
|
|
4606
|
-
return `${dd} ${monthFull(mm)} ${yyyy}`;
|
|
4607
|
-
case "MMMM DD, YYYY":
|
|
4608
|
-
return `${monthFull(mm)} ${dd}, ${yyyy}`;
|
|
4609
|
-
case "DD/MM/YYYY":
|
|
4610
|
-
default:
|
|
4611
|
-
return `${dd}/${mm}/${yyyy}`;
|
|
4612
|
-
}
|
|
4613
|
-
}
|
|
4614
|
-
|
|
4615
4693
|
// src/shell/timelineDates.ts
|
|
4616
4694
|
var DAY_MS = 864e5;
|
|
4617
4695
|
function toDayMs(dateStr) {
|
|
@@ -4622,8 +4700,8 @@ function toDayMs(dateStr) {
|
|
|
4622
4700
|
if (year < 2e3 || year > 2100) return null;
|
|
4623
4701
|
return t;
|
|
4624
4702
|
}
|
|
4625
|
-
function fmtSliderDate(ms) {
|
|
4626
|
-
return formatDate(new Date(ms).toISOString().slice(0, 10));
|
|
4703
|
+
function fmtSliderDate(ms, locale) {
|
|
4704
|
+
return formatDate(new Date(ms).toISOString().slice(0, 10), { locale });
|
|
4627
4705
|
}
|
|
4628
4706
|
var fillId = (id, index) => `${id}-fill-${index}`;
|
|
4629
4707
|
var glowId = (id) => `${id}-glow`;
|
|
@@ -5211,7 +5289,6 @@ function prefersReducedMotion() {
|
|
|
5211
5289
|
return false;
|
|
5212
5290
|
}
|
|
5213
5291
|
}
|
|
5214
|
-
var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
5215
5292
|
var monoWidth = (text) => text.length * MONO_CHAR_PX;
|
|
5216
5293
|
var KIND_STYLES = {
|
|
5217
5294
|
// No glyph by default: a flag belongs on the milestone that OPENED the
|
|
@@ -5263,8 +5340,8 @@ function accessibleName(mark) {
|
|
|
5263
5340
|
const detail = detailText(mark.detail);
|
|
5264
5341
|
return `${mark.label} \xB7 ${mark.dateText}${detail ? ` \xB7 ${detail}` : ""}`;
|
|
5265
5342
|
}
|
|
5266
|
-
function foldName(members) {
|
|
5267
|
-
return
|
|
5343
|
+
function foldName(members, words) {
|
|
5344
|
+
return words.events(members.length, members.map(accessibleName));
|
|
5268
5345
|
}
|
|
5269
5346
|
function foldDates(members) {
|
|
5270
5347
|
const first = members[0].dateText;
|
|
@@ -5380,6 +5457,8 @@ function MeasuringRow({ marks, innerRef }) {
|
|
|
5380
5457
|
] }, mark.key)) });
|
|
5381
5458
|
}
|
|
5382
5459
|
function Ruler({ startMs, endMs, axis, geo, reveal }) {
|
|
5460
|
+
const strings = useShellStrings().timeline;
|
|
5461
|
+
const names = calendarNames(useShellLocale());
|
|
5383
5462
|
const y = geo.ruler;
|
|
5384
5463
|
const ticks = [];
|
|
5385
5464
|
const labels = [];
|
|
@@ -5403,7 +5482,7 @@ function Ruler({ startMs, endMs, axis, geo, reveal }) {
|
|
|
5403
5482
|
}
|
|
5404
5483
|
const bands = cuts.map((gap) => {
|
|
5405
5484
|
const centre = (gap.fromPx + gap.toPx) / 2;
|
|
5406
|
-
const half = monoWidth(
|
|
5485
|
+
const half = monoWidth(strings.days(Math.round(gap.gapMs / DAY_MS))) / 2 + 6;
|
|
5407
5486
|
return [centre - half, centre + half];
|
|
5408
5487
|
});
|
|
5409
5488
|
const blocked = (from, to) => bands.some(([low, high]) => from < high && to > low);
|
|
@@ -5432,7 +5511,7 @@ function Ruler({ startMs, endMs, axis, geo, reveal }) {
|
|
|
5432
5511
|
);
|
|
5433
5512
|
if (x - lastLabelX >= MONTH_LABEL_PITCH_PX || firstLabel) {
|
|
5434
5513
|
const withYear = firstLabel || cursor.getUTCMonth() === 0;
|
|
5435
|
-
const text =
|
|
5514
|
+
const text = withYear ? names.shortMonthYear(cursor.getUTCFullYear(), cursor.getUTCMonth()) : names.monthsShort[cursor.getUTCMonth()];
|
|
5436
5515
|
if (!blocked(x, x + monoWidth(text))) {
|
|
5437
5516
|
labels.push(
|
|
5438
5517
|
/* @__PURE__ */ jsx(
|
|
@@ -5472,10 +5551,7 @@ function Ruler({ startMs, endMs, axis, geo, reveal }) {
|
|
|
5472
5551
|
/* @__PURE__ */ jsx("i", {}),
|
|
5473
5552
|
/* @__PURE__ */ jsx("i", {})
|
|
5474
5553
|
] }),
|
|
5475
|
-
/* @__PURE__ */
|
|
5476
|
-
days.toLocaleString(),
|
|
5477
|
-
" days"
|
|
5478
|
-
] })
|
|
5554
|
+
/* @__PURE__ */ jsx("span", { children: strings.days(days) })
|
|
5479
5555
|
]
|
|
5480
5556
|
},
|
|
5481
5557
|
`cut-${gap.fromMs}`
|
|
@@ -5484,12 +5560,13 @@ function Ruler({ startMs, endMs, axis, geo, reveal }) {
|
|
|
5484
5560
|
] });
|
|
5485
5561
|
}
|
|
5486
5562
|
function PendingColumn({ pending, reveal }) {
|
|
5563
|
+
const strings = useShellStrings().timeline;
|
|
5487
5564
|
const [expanded, setExpanded] = useState(false);
|
|
5488
5565
|
const shown = expanded ? pending : pending.slice(0, PENDING_ROW_LIMIT);
|
|
5489
5566
|
const folded = pending.length - shown.length;
|
|
5490
5567
|
return /* @__PURE__ */ jsxs("div", { className: "rosh-tl-pending", "data-timeline-part": "pending", children: [
|
|
5491
|
-
/* @__PURE__ */ jsx("p", { className: "rosh-tl-pending-head", children:
|
|
5492
|
-
/* @__PURE__ */ jsx("ol", { className: "rosh-tl-ghosts", "aria-label":
|
|
5568
|
+
/* @__PURE__ */ jsx("p", { className: "rosh-tl-pending-head", children: strings.notReached }),
|
|
5569
|
+
/* @__PURE__ */ jsx("ol", { className: "rosh-tl-ghosts", "aria-label": strings.notReached, children: shown.map((entry, index) => /* @__PURE__ */ jsxs(
|
|
5493
5570
|
"li",
|
|
5494
5571
|
{
|
|
5495
5572
|
className: reveal ? "rosh-tl-fade" : void 0,
|
|
@@ -5503,23 +5580,20 @@ function PendingColumn({ pending, reveal }) {
|
|
|
5503
5580
|
}
|
|
5504
5581
|
),
|
|
5505
5582
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
5506
|
-
index === 0 && /* @__PURE__ */ jsx("b", { children:
|
|
5583
|
+
index === 0 && /* @__PURE__ */ jsx("b", { children: `${strings.next} \xB7 ` }),
|
|
5507
5584
|
entry.label
|
|
5508
5585
|
] })
|
|
5509
5586
|
]
|
|
5510
5587
|
},
|
|
5511
5588
|
entry.key
|
|
5512
5589
|
)) }),
|
|
5513
|
-
folded > 0 && /* @__PURE__ */
|
|
5514
|
-
"+",
|
|
5515
|
-
folded,
|
|
5516
|
-
" more"
|
|
5517
|
-
] })
|
|
5590
|
+
folded > 0 && /* @__PURE__ */ jsx("button", { type: "button", className: "rosh-tl-more text-gray-500", onClick: () => setExpanded(true), children: strings.more(folded) })
|
|
5518
5591
|
] });
|
|
5519
5592
|
}
|
|
5520
5593
|
function VerticalTrack({ marks, pending, currentKey, todayMs, reveal, ariaLabel, step, nodeProps, onKeyDown }) {
|
|
5594
|
+
const strings = useShellStrings().timeline;
|
|
5521
5595
|
const currentIndex = marks.findIndex((mark) => mark.key === currentKey);
|
|
5522
|
-
const gapDays = marks.length > 0 ? Math.round((todayMs - marks[marks.length - 1].ms) / DAY_MS) : 0;
|
|
5596
|
+
const gapDays = marks.length > 0 && todayMs !== null ? Math.round((todayMs - marks[marks.length - 1].ms) / DAY_MS) : 0;
|
|
5523
5597
|
return /* @__PURE__ */ jsxs("div", { "data-timeline-part": "vertical", children: [
|
|
5524
5598
|
/* @__PURE__ */ jsx("ol", { className: "rosh-tl-v", "aria-label": ariaLabel, onKeyDown, children: marks.map((mark, index) => {
|
|
5525
5599
|
const dressing = nodeDressing(mark.kind, mark.role);
|
|
@@ -5562,10 +5636,7 @@ function VerticalTrack({ marks, pending, currentKey, todayMs, reveal, ariaLabel,
|
|
|
5562
5636
|
}) }),
|
|
5563
5637
|
gapDays > 0 && /* @__PURE__ */ jsxs("p", { className: "rosh-tl-vgap", "aria-hidden": "true", children: [
|
|
5564
5638
|
/* @__PURE__ */ jsx("i", { className: "rosh-tl-vline is-dash" }),
|
|
5565
|
-
/* @__PURE__ */
|
|
5566
|
-
gapDays.toLocaleString(),
|
|
5567
|
-
" days to today"
|
|
5568
|
-
] })
|
|
5639
|
+
/* @__PURE__ */ jsx("span", { children: strings.daysToToday(gapDays) })
|
|
5569
5640
|
] }),
|
|
5570
5641
|
pending.length > 0 && /* @__PURE__ */ jsx(PendingColumn, { pending, reveal })
|
|
5571
5642
|
] });
|
|
@@ -5639,6 +5710,7 @@ function StartMark({ geo, caption, endCaption, around, reveal, trackPx }) {
|
|
|
5639
5710
|
}
|
|
5640
5711
|
function TodayMark({ x, geo, trackPx, label, reveal }) {
|
|
5641
5712
|
const tagWidth = 48;
|
|
5713
|
+
const strings = useShellStrings().timeline;
|
|
5642
5714
|
return /* @__PURE__ */ jsxs("div", { "aria-hidden": "true", "data-timeline-part": "today", children: [
|
|
5643
5715
|
/* @__PURE__ */ jsx(
|
|
5644
5716
|
"div",
|
|
@@ -5656,13 +5728,13 @@ function TodayMark({ x, geo, trackPx, label, reveal }) {
|
|
|
5656
5728
|
"span",
|
|
5657
5729
|
{
|
|
5658
5730
|
className: `rosh-tl-todaytag${reveal ? " rosh-tl-fade" : ""}`,
|
|
5659
|
-
title:
|
|
5731
|
+
title: strings.todayTitle(label),
|
|
5660
5732
|
style: {
|
|
5661
5733
|
left: `${clampLabelLeft(x, tagWidth, trackPx)}px`,
|
|
5662
5734
|
top: `${geo.tag}px`,
|
|
5663
5735
|
...reveal ? { animationDelay: "420ms" } : {}
|
|
5664
5736
|
},
|
|
5665
|
-
children:
|
|
5737
|
+
children: strings.today
|
|
5666
5738
|
}
|
|
5667
5739
|
)
|
|
5668
5740
|
] });
|
|
@@ -5731,6 +5803,7 @@ function PhaseBracket({ phase, geo, xOf }) {
|
|
|
5731
5803
|
] });
|
|
5732
5804
|
}
|
|
5733
5805
|
function ActiveLabel({ nodes, trackPx, geo, activeKey, hoveredKey, currentKey }) {
|
|
5806
|
+
const strings = useShellStrings().timeline;
|
|
5734
5807
|
const holds = (node2, key) => key !== null && (node2.key === key || node2.members.some((member) => member.key === key));
|
|
5735
5808
|
const node = nodes.find((n) => n.key === hoveredKey) ?? nodes.find((n) => holds(n, activeKey)) ?? null;
|
|
5736
5809
|
if (!node) return null;
|
|
@@ -5757,7 +5830,7 @@ function ActiveLabel({ nodes, trackPx, geo, activeKey, hoveredKey, currentKey })
|
|
|
5757
5830
|
type: "button",
|
|
5758
5831
|
className: "rosh-tl-name rosh-tl-open",
|
|
5759
5832
|
"data-timeline-part": "open",
|
|
5760
|
-
"aria-label":
|
|
5833
|
+
"aria-label": strings.open(name),
|
|
5761
5834
|
onClick: onOpen,
|
|
5762
5835
|
children: name
|
|
5763
5836
|
}
|
|
@@ -6021,6 +6094,8 @@ function ThumbLayer({
|
|
|
6021
6094
|
nodes,
|
|
6022
6095
|
onProgress
|
|
6023
6096
|
}) {
|
|
6097
|
+
const strings = useShellStrings().timeline;
|
|
6098
|
+
const locale = useShellLocale();
|
|
6024
6099
|
const draggingRef = useRef(false);
|
|
6025
6100
|
const x = glide ? glide.px : axis.xByMs(value);
|
|
6026
6101
|
const at = glide ? glide.ms : value;
|
|
@@ -6072,7 +6147,7 @@ function ThumbLayer({
|
|
|
6072
6147
|
if (key === "End") return endMs;
|
|
6073
6148
|
return null;
|
|
6074
6149
|
};
|
|
6075
|
-
const valueText = thumb.valueText ? thumb.valueText(at) : fmtSliderDate(at);
|
|
6150
|
+
const valueText = thumb.valueText ? thumb.valueText(at) : fmtSliderDate(at, locale);
|
|
6076
6151
|
const days = Math.max(1, Math.round((endMs - startMs) / DAY_MS));
|
|
6077
6152
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6078
6153
|
/* @__PURE__ */ jsx(
|
|
@@ -6097,7 +6172,7 @@ function ThumbLayer({
|
|
|
6097
6172
|
className: "rosh-tl-chip",
|
|
6098
6173
|
"data-timeline-part": "chip",
|
|
6099
6174
|
style: { left: `${clampLabelLeft(x, chipWidth, trackPx) + chipWidth / 2}px`, top: `${geo.tag}px` },
|
|
6100
|
-
children: thumb.chip ? thumb.chip(at) : fmtSliderDate(at)
|
|
6175
|
+
children: thumb.chip ? thumb.chip(at) : fmtSliderDate(at, locale)
|
|
6101
6176
|
}
|
|
6102
6177
|
),
|
|
6103
6178
|
/* @__PURE__ */ jsx(
|
|
@@ -6107,7 +6182,7 @@ function ThumbLayer({
|
|
|
6107
6182
|
tabIndex: 0,
|
|
6108
6183
|
className: "rosh-tl-thumb text-blue-600",
|
|
6109
6184
|
"data-timeline-part": "thumb",
|
|
6110
|
-
"aria-label": thumb.ariaLabel ??
|
|
6185
|
+
"aria-label": thumb.ariaLabel ?? strings.scrub,
|
|
6111
6186
|
"aria-valuemin": 0,
|
|
6112
6187
|
"aria-valuemax": stops && stops.length > 0 ? stops.length - 1 : days,
|
|
6113
6188
|
"aria-valuenow": stops && stops.length > 0 ? Math.max(0, index) : Math.round((value - startMs) / DAY_MS),
|
|
@@ -6162,10 +6237,13 @@ function TimelineTrack({
|
|
|
6162
6237
|
endMark = null
|
|
6163
6238
|
}) {
|
|
6164
6239
|
const bare = labels === "none";
|
|
6165
|
-
const
|
|
6166
|
-
const
|
|
6240
|
+
const mountedToday = useBrowserValueOnce(Date.now, null);
|
|
6241
|
+
const stillness = useBrowserValueOnce(prefersReducedMotion, false);
|
|
6167
6242
|
const now = todayMs ?? mountedToday;
|
|
6168
6243
|
const rootRef = useRef(null);
|
|
6244
|
+
const strings = useShellStrings().timeline;
|
|
6245
|
+
const locale = useShellLocale();
|
|
6246
|
+
const fmtDate = (ms) => fmtSliderDate(ms, locale);
|
|
6169
6247
|
const layerRef = useRef(null);
|
|
6170
6248
|
const measureRef = useRef(null);
|
|
6171
6249
|
const tipRef = useRef(null);
|
|
@@ -6206,7 +6284,7 @@ function TimelineTrack({
|
|
|
6206
6284
|
const happened = dated.filter((item) => !item.provisional);
|
|
6207
6285
|
const resolvedCurrent = currentKey ?? (happened.length > 0 ? happened[happened.length - 1].key : null);
|
|
6208
6286
|
const itemMarks = dated.map((item, index) => {
|
|
6209
|
-
const dateText = item.date ??
|
|
6287
|
+
const dateText = item.date ?? fmtDate(item.ms);
|
|
6210
6288
|
const ordinary = (item.priority ?? 0) > 0 || item.kind === "report";
|
|
6211
6289
|
const kind = resolveKind(item);
|
|
6212
6290
|
return {
|
|
@@ -6235,7 +6313,7 @@ function TimelineTrack({
|
|
|
6235
6313
|
});
|
|
6236
6314
|
const markerMarks = markers.map((marker) => ({ marker, ms: new Date(marker.date).getTime() })).filter(({ ms }) => Number.isFinite(ms) && inWindow(ms)).map(({ marker, ms }) => {
|
|
6237
6315
|
const key = `marker-${marker.id}`;
|
|
6238
|
-
const dateText =
|
|
6316
|
+
const dateText = fmtDate(ms);
|
|
6239
6317
|
return {
|
|
6240
6318
|
key,
|
|
6241
6319
|
ms,
|
|
@@ -6270,8 +6348,8 @@ function TimelineTrack({
|
|
|
6270
6348
|
baseX: trackPx,
|
|
6271
6349
|
kind: cap.kind ?? "default",
|
|
6272
6350
|
label: cap.label,
|
|
6273
|
-
dateText:
|
|
6274
|
-
detail: others.length > 0 ?
|
|
6351
|
+
dateText: strings.notReached,
|
|
6352
|
+
detail: others.length > 0 ? strings.alsoToCome(others) : void 0,
|
|
6275
6353
|
glyph: void 0,
|
|
6276
6354
|
role: "key",
|
|
6277
6355
|
widthPx: MARK_OVERLAP_PX,
|
|
@@ -6288,7 +6366,7 @@ function TimelineTrack({
|
|
|
6288
6366
|
baseX: axisPx,
|
|
6289
6367
|
kind: "default",
|
|
6290
6368
|
label: endMark.label,
|
|
6291
|
-
dateText: endMark.dateText ??
|
|
6369
|
+
dateText: endMark.dateText ?? fmtDate(endMs),
|
|
6292
6370
|
detail: endMark.detail,
|
|
6293
6371
|
glyph: void 0,
|
|
6294
6372
|
role: "key",
|
|
@@ -6299,7 +6377,7 @@ function TimelineTrack({
|
|
|
6299
6377
|
isCap: true
|
|
6300
6378
|
}] : [];
|
|
6301
6379
|
const marks = [...itemMarks, ...markerMarks, ...capMarks, ...endMarks].sort((a, b) => a.x - b.x || a.ms - b.ms);
|
|
6302
|
-
const startCaption = edgeCaptions?.start ??
|
|
6380
|
+
const startCaption = edgeCaptions?.start ?? strings.start(fmtDate(startMs));
|
|
6303
6381
|
const startCaptionPx = startCaption == null || startCaption === false ? 0 : typeof startCaption === "string" ? Math.ceil(monoWidth(startCaption)) : START_CAPTION_FALLBACK_PX;
|
|
6304
6382
|
const groups = labels === "lanes" ? clusterMarks(marks) : [];
|
|
6305
6383
|
const groupKey = (group) => group.type === "cluster" ? `cluster-${group.members[0].key}` : group.mark.key;
|
|
@@ -6482,7 +6560,7 @@ function TimelineTrack({
|
|
|
6482
6560
|
};
|
|
6483
6561
|
}, [playing, endPlayback, reportProgress]);
|
|
6484
6562
|
const reached = itemMarks.filter((mark) => !mark.provisional);
|
|
6485
|
-
const fillTo = thumb ? glide ? glide.ms : thumbAt : fillToMs !== void 0 ? fillToMs : reached.length > 0 ? Math.min(reached[reached.length - 1].ms, now) : null;
|
|
6563
|
+
const fillTo = thumb ? glide ? glide.ms : thumbAt : fillToMs !== void 0 ? fillToMs : reached.length > 0 ? now === null ? reached[reached.length - 1].ms : Math.min(reached[reached.length - 1].ms, now) : null;
|
|
6486
6564
|
const litKeys = new Set(highlightKeys ?? []);
|
|
6487
6565
|
const litXs = marks.filter((mark) => litKeys.has(mark.key)).map((mark) => mark.x);
|
|
6488
6566
|
const band = litXs.length > 0 ? { from: Math.min(...litXs), to: Math.max(...litXs) } : null;
|
|
@@ -6646,7 +6724,7 @@ function TimelineTrack({
|
|
|
6646
6724
|
"data-timeline-node": "fold",
|
|
6647
6725
|
"data-timeline-key": node.key,
|
|
6648
6726
|
"data-timeline-count": String(node.members.length),
|
|
6649
|
-
"aria-label": foldName(node.members),
|
|
6727
|
+
"aria-label": foldName(node.members, strings),
|
|
6650
6728
|
"aria-describedby": bubbleKey === node.key ? tipId : void 0,
|
|
6651
6729
|
tabIndex: node.key === tabKey ? 0 : -1,
|
|
6652
6730
|
ref: (el) => {
|
|
@@ -6778,13 +6856,13 @@ function TimelineTrack({
|
|
|
6778
6856
|
}
|
|
6779
6857
|
),
|
|
6780
6858
|
bare && /* @__PURE__ */ jsx(Captions, { nodes: railNodes, geo, reveal }),
|
|
6781
|
-
now > startMs && now <= endMs + DAY_MS && /* @__PURE__ */ jsx(
|
|
6859
|
+
now !== null && now > startMs && now <= endMs + DAY_MS && /* @__PURE__ */ jsx(
|
|
6782
6860
|
TodayMark,
|
|
6783
6861
|
{
|
|
6784
6862
|
x: view.xByMs(Math.min(now, endMs)),
|
|
6785
6863
|
geo,
|
|
6786
6864
|
trackPx,
|
|
6787
|
-
label:
|
|
6865
|
+
label: fmtDate(now),
|
|
6788
6866
|
reveal
|
|
6789
6867
|
}
|
|
6790
6868
|
),
|
|
@@ -6928,7 +7006,7 @@ function TimelineTrack({
|
|
|
6928
7006
|
className: "rosh-tl-bubble-open text-blue-600",
|
|
6929
7007
|
"data-timeline-part": "bubble-open",
|
|
6930
7008
|
onClick: () => (bubbleNode.mark?.onOpen ?? bubbleNode.mark?.onClick)?.(),
|
|
6931
|
-
children:
|
|
7009
|
+
children: strings.openButton
|
|
6932
7010
|
}
|
|
6933
7011
|
)
|
|
6934
7012
|
] }) : (
|
|
@@ -7031,9 +7109,11 @@ function MilestoneTimeline({
|
|
|
7031
7109
|
highlightKeys = null,
|
|
7032
7110
|
onHoverChange
|
|
7033
7111
|
}) {
|
|
7034
|
-
const
|
|
7112
|
+
const today = useBrowserValueOnce(Date.now, null);
|
|
7035
7113
|
const dated = [];
|
|
7036
7114
|
const pending = [];
|
|
7115
|
+
const strings = useShellStrings().timeline;
|
|
7116
|
+
const locale = useShellLocale();
|
|
7037
7117
|
for (const m of milestones) {
|
|
7038
7118
|
const ms = toDayMs(m.date ?? null);
|
|
7039
7119
|
if (ms === null) pending.push({ key: m.key, label: m.label, kind: m.kind });
|
|
@@ -7043,22 +7123,24 @@ function MilestoneTimeline({
|
|
|
7043
7123
|
const explicitEnd = toDayMs(endDate ?? null);
|
|
7044
7124
|
let startMs;
|
|
7045
7125
|
let endMs;
|
|
7126
|
+
let anchored = true;
|
|
7046
7127
|
if (dated.length === 0) {
|
|
7047
|
-
endMs = explicitEnd ?? today;
|
|
7128
|
+
endMs = explicitEnd ?? today ?? 0;
|
|
7048
7129
|
startMs = endMs - 30 * DAY_MS;
|
|
7130
|
+
anchored = explicitEnd !== null || today !== null;
|
|
7049
7131
|
} else {
|
|
7050
7132
|
startMs = dated[0].ms;
|
|
7051
7133
|
endMs = explicitEnd ?? dated[dated.length - 1].ms;
|
|
7052
7134
|
if (endMs - startMs < DAY_MS) endMs = startMs + DAY_MS;
|
|
7053
7135
|
}
|
|
7054
7136
|
const totalLeadDays = dated.length > 0 ? Math.max(0, Math.round((endMs - startMs) / DAY_MS)) : 0;
|
|
7055
|
-
const duration = summary ?? (totalLeadDays > 0 ?
|
|
7137
|
+
const duration = summary ?? (totalLeadDays > 0 ? strings.duration(totalLeadDays) : void 0);
|
|
7056
7138
|
const meta = [
|
|
7057
|
-
dated.length > 0 ?
|
|
7139
|
+
dated.length > 0 ? strings.started(fmtSliderDate(dated[0].ms, locale)) : void 0,
|
|
7058
7140
|
duration,
|
|
7059
7141
|
// Only where something HAS not happened: "7 of 7 milestones" is a count of
|
|
7060
7142
|
// nothing, and the reader can see the dots.
|
|
7061
|
-
pending.length > 0 ?
|
|
7143
|
+
pending.length > 0 ? strings.reached(dated.length, milestones.length) : void 0
|
|
7062
7144
|
];
|
|
7063
7145
|
const items = dated.map((m) => ({
|
|
7064
7146
|
key: m.key,
|
|
@@ -7086,7 +7168,7 @@ function MilestoneTimeline({
|
|
|
7086
7168
|
maxMs: Math.max(...ms)
|
|
7087
7169
|
}));
|
|
7088
7170
|
const rail = variant === "rail";
|
|
7089
|
-
const track = /* @__PURE__ */ jsx("div", { className: "select-none", children: /* @__PURE__ */ jsx(
|
|
7171
|
+
const track = anchored && /* @__PURE__ */ jsx("div", { className: "select-none", children: /* @__PURE__ */ jsx(
|
|
7090
7172
|
TimelineTrack,
|
|
7091
7173
|
{
|
|
7092
7174
|
axis: rail ? "spread" : "compressed",
|
|
@@ -7096,11 +7178,11 @@ function MilestoneTimeline({
|
|
|
7096
7178
|
phases,
|
|
7097
7179
|
startMs,
|
|
7098
7180
|
endMs,
|
|
7099
|
-
todayMs: today,
|
|
7181
|
+
todayMs: today ?? void 0,
|
|
7100
7182
|
edgeCaptions,
|
|
7101
7183
|
highlightKeys,
|
|
7102
7184
|
onHoverChange,
|
|
7103
|
-
ariaLabel:
|
|
7185
|
+
ariaLabel: strings.milestones(title)
|
|
7104
7186
|
}
|
|
7105
7187
|
) });
|
|
7106
7188
|
if (rail) {
|
|
@@ -7161,6 +7243,7 @@ function useProductionTimeline(opts) {
|
|
|
7161
7243
|
markers = []
|
|
7162
7244
|
} = opts;
|
|
7163
7245
|
const [scrubMs, setScrubMs] = useState(null);
|
|
7246
|
+
const strings = useShellStrings().production;
|
|
7164
7247
|
useEffect(() => {
|
|
7165
7248
|
if (currentReportDate) {
|
|
7166
7249
|
setScrubMs(new Date(currentReportDate).getTime());
|
|
@@ -7182,8 +7265,16 @@ function useProductionTimeline(opts) {
|
|
|
7182
7265
|
stopPlay();
|
|
7183
7266
|
}, [currentReportId]);
|
|
7184
7267
|
const reportTimes = reports.map((r) => toDayMs(r.date)).filter((t) => t != null);
|
|
7185
|
-
const
|
|
7186
|
-
const
|
|
7268
|
+
const today = useBrowserValueOnce(Date.now, null);
|
|
7269
|
+
const now = today ?? Math.max(
|
|
7270
|
+
0,
|
|
7271
|
+
...reportTimes,
|
|
7272
|
+
...markers.map((m) => toDayMs(m.date) ?? 0),
|
|
7273
|
+
toDayMs(poProductionStartDate ?? null) ?? 0,
|
|
7274
|
+
toDayMs(poEstCompletionDate ?? null) ?? 0
|
|
7275
|
+
);
|
|
7276
|
+
const earliestReport = reportTimes.length ? Math.min(...reportTimes) : now;
|
|
7277
|
+
const latestReport = reportTimes.length ? Math.max(...reportTimes) : now;
|
|
7187
7278
|
const startMs = toDayMs(poProductionStartDate ?? null) ?? earliestReport;
|
|
7188
7279
|
const estComplete = toDayMs(poEstCompletionDate ?? null) ?? 0;
|
|
7189
7280
|
const isPostProd = POST_PRODUCTION_STATUSES.has((poStatus || "").toLowerCase());
|
|
@@ -7193,7 +7284,7 @@ function useProductionTimeline(opts) {
|
|
|
7193
7284
|
}, 0);
|
|
7194
7285
|
const endMs = (() => {
|
|
7195
7286
|
const candidates = [estComplete, latestReport, latestMarker, startMs + DAY_MS];
|
|
7196
|
-
if (!isPostProd) candidates.push(
|
|
7287
|
+
if (!isPostProd) candidates.push(now);
|
|
7197
7288
|
return Math.max(...candidates);
|
|
7198
7289
|
})();
|
|
7199
7290
|
const totalLeadDays = Math.max(1, Math.round((endMs - startMs) / DAY_MS));
|
|
@@ -7228,7 +7319,7 @@ function useProductionTimeline(opts) {
|
|
|
7228
7319
|
}));
|
|
7229
7320
|
return {
|
|
7230
7321
|
id: `zero-${poNumber}`,
|
|
7231
|
-
progress_number:
|
|
7322
|
+
progress_number: strings.start,
|
|
7232
7323
|
date: poProductionStartDate || new Date(startMs).toISOString().slice(0, 10),
|
|
7233
7324
|
items: zeroItems,
|
|
7234
7325
|
est_completion_date: poEstCompletionDate ?? null,
|
|
@@ -7281,7 +7372,7 @@ function useProductionTimeline(opts) {
|
|
|
7281
7372
|
}
|
|
7282
7373
|
displayed = {
|
|
7283
7374
|
id: `interp-${effectiveScrub}`,
|
|
7284
|
-
progress_number:
|
|
7375
|
+
progress_number: strings.estimated,
|
|
7285
7376
|
date: new Date(effectiveScrub).toISOString().slice(0, 10),
|
|
7286
7377
|
created_by_name: "",
|
|
7287
7378
|
est_completion_date: estCompletion,
|
|
@@ -7317,9 +7408,9 @@ function useProductionTimeline(opts) {
|
|
|
7317
7408
|
setScrubMs(startMs);
|
|
7318
7409
|
let lastTime = performance.now();
|
|
7319
7410
|
let cur = startMs;
|
|
7320
|
-
const step = (
|
|
7321
|
-
const dt =
|
|
7322
|
-
lastTime =
|
|
7411
|
+
const step = (now2) => {
|
|
7412
|
+
const dt = now2 - lastTime;
|
|
7413
|
+
lastTime = now2;
|
|
7323
7414
|
cur = cur + dt / msPerDayOfPlayback * DAY_MS;
|
|
7324
7415
|
if (cur >= playStopMs) {
|
|
7325
7416
|
setScrubMs(playStopMs);
|
|
@@ -7384,6 +7475,8 @@ function TimelineScrubber({
|
|
|
7384
7475
|
bare = false,
|
|
7385
7476
|
endMark = null
|
|
7386
7477
|
}) {
|
|
7478
|
+
const strings = useShellStrings().production;
|
|
7479
|
+
const locale = useShellLocale();
|
|
7387
7480
|
const dated = reports.map((r) => ({ report: r, ms: new Date(r.date).getTime() })).filter(({ ms }) => Number.isFinite(ms)).sort((a, b) => a.ms - b.ms);
|
|
7388
7481
|
const items = dated.map(({ report, ms }) => ({
|
|
7389
7482
|
key: report.id,
|
|
@@ -7423,13 +7516,13 @@ function TimelineScrubber({
|
|
|
7423
7516
|
onChange,
|
|
7424
7517
|
onDragStart,
|
|
7425
7518
|
stops,
|
|
7426
|
-
ariaLabel:
|
|
7519
|
+
ariaLabel: strings.scrub,
|
|
7427
7520
|
valueText: (ms) => {
|
|
7428
7521
|
const report = reportAt(ms);
|
|
7429
|
-
return report ? `${reportLabel(report)} \xB7 ${fmtSliderDate(ms)}` : fmtSliderDate(ms);
|
|
7522
|
+
return report ? `${reportLabel(report)} \xB7 ${fmtSliderDate(ms, locale)}` : fmtSliderDate(ms, locale);
|
|
7430
7523
|
}
|
|
7431
7524
|
},
|
|
7432
|
-
ariaLabel:
|
|
7525
|
+
ariaLabel: strings.label(fmtSliderDate(startMs, locale), fmtSliderDate(endMs, locale))
|
|
7433
7526
|
}
|
|
7434
7527
|
) });
|
|
7435
7528
|
}
|
|
@@ -7462,7 +7555,7 @@ function ProductionTimeline({
|
|
|
7462
7555
|
onOpenMarker,
|
|
7463
7556
|
renderReportPreview,
|
|
7464
7557
|
onScrubProgress,
|
|
7465
|
-
heading
|
|
7558
|
+
heading: headingProp,
|
|
7466
7559
|
edgeCaptions,
|
|
7467
7560
|
reportLabel = (report) => report.progress_number,
|
|
7468
7561
|
resetLabel,
|
|
@@ -7487,6 +7580,10 @@ function ProductionTimeline({
|
|
|
7487
7580
|
} = snapshot;
|
|
7488
7581
|
const stops = reports.map((report) => toDayMs(report.date)).filter((ms) => ms != null).sort((a, b) => a - b);
|
|
7489
7582
|
const play = useReportPlayback(stops, setScrubMs, onPlayStart);
|
|
7583
|
+
const strings = useShellStrings().production;
|
|
7584
|
+
const locale = useShellLocale();
|
|
7585
|
+
const heading = headingProp ?? strings.heading;
|
|
7586
|
+
const fmtDate = (ms) => fmtSliderDate(ms, locale);
|
|
7490
7587
|
if (reports.length === 0 && markers.length === 0) return null;
|
|
7491
7588
|
const shipmentMarkers = markers.filter((m) => m.kind === "shipment");
|
|
7492
7589
|
const inspectionMarkers = markers.filter((m) => m.kind === "inspection");
|
|
@@ -7505,11 +7602,11 @@ function ProductionTimeline({
|
|
|
7505
7602
|
type: "button",
|
|
7506
7603
|
onClick: play.toggle,
|
|
7507
7604
|
"aria-pressed": play.playing,
|
|
7508
|
-
title: play.playing ?
|
|
7605
|
+
title: play.playing ? strings.pause : strings.playTitle,
|
|
7509
7606
|
className: "rosh-tl-play text-gray-700 border-gray-300 hover:text-blue-600 hover:border-blue-600",
|
|
7510
7607
|
children: [
|
|
7511
7608
|
play.playing ? /* @__PURE__ */ jsx("svg", { viewBox: "0 0 10 10", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M2 1.5h2.3v7H2zM5.7 1.5H8v7H5.7z" }) }) : /* @__PURE__ */ jsx("svg", { viewBox: "0 0 10 10", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M2 1.2 8.4 5 2 8.8z" }) }),
|
|
7512
|
-
/* @__PURE__ */ jsx("span", { children: play.playing ?
|
|
7609
|
+
/* @__PURE__ */ jsx("span", { children: play.playing ? strings.pause : strings.play })
|
|
7513
7610
|
]
|
|
7514
7611
|
}
|
|
7515
7612
|
)
|
|
@@ -7523,26 +7620,26 @@ function ProductionTimeline({
|
|
|
7523
7620
|
resetToCurrent();
|
|
7524
7621
|
},
|
|
7525
7622
|
className: "text-xs text-blue-600 underline-offset-4 hover:underline font-medium",
|
|
7526
|
-
children: resetLabel ??
|
|
7623
|
+
children: resetLabel ?? strings.backTo(String(currentLabel))
|
|
7527
7624
|
}
|
|
7528
7625
|
) : null;
|
|
7626
|
+
const [showingBefore, showingAfter] = splitAround(strings.showing);
|
|
7529
7627
|
const statusLine = (showing) => /* @__PURE__ */ jsx("p", { className: "rosh-tl-status text-gray-800", children: displayed ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7530
|
-
showing &&
|
|
7628
|
+
showing && showingBefore,
|
|
7531
7629
|
/* @__PURE__ */ jsx("b", { className: "font-medium", children: reportLabel(displayed) }),
|
|
7630
|
+
showing && showingAfter,
|
|
7532
7631
|
/* @__PURE__ */ jsxs("span", { className: "text-gray-500", children: [
|
|
7533
7632
|
" \xB7 ",
|
|
7534
|
-
|
|
7633
|
+
fmtDate(new Date(displayed.date).getTime()),
|
|
7535
7634
|
" \xB7 ",
|
|
7536
|
-
Math.round(overall),
|
|
7537
|
-
"% overall",
|
|
7635
|
+
strings.overall(Math.round(overall)),
|
|
7538
7636
|
" \xB7 ",
|
|
7539
|
-
|
|
7540
|
-
" pc in stock"
|
|
7637
|
+
strings.inStock(totalStock)
|
|
7541
7638
|
] })
|
|
7542
|
-
] }) : /* @__PURE__ */ jsx("span", { className: "text-gray-500", children:
|
|
7639
|
+
] }) : /* @__PURE__ */ jsx("span", { className: "text-gray-500", children: strings.noReport }) });
|
|
7543
7640
|
if (variant === "rail") {
|
|
7544
7641
|
const estimateAhead = estCompletionMs != null && estCompletionMs >= endMs && endMs > startMs;
|
|
7545
|
-
const endMark = estimateAhead ? { key: "__estimate__", label:
|
|
7642
|
+
const endMark = estimateAhead ? { key: "__estimate__", label: strings.estimatedCompletion, dateText: fmtDate(estCompletionMs) } : null;
|
|
7546
7643
|
return /* @__PURE__ */ jsxs("div", { className: "shrink-0", "data-timeline-variant": "rail", children: [
|
|
7547
7644
|
/* @__PURE__ */ jsx(
|
|
7548
7645
|
TimelineScrubber,
|
|
@@ -7562,8 +7659,8 @@ function ProductionTimeline({
|
|
|
7562
7659
|
renderReportPreview,
|
|
7563
7660
|
reportLabel,
|
|
7564
7661
|
edgeCaptions: {
|
|
7565
|
-
start: edgeCaptions?.start ??
|
|
7566
|
-
end: edgeCaptions?.end ?? (estimateAhead ?
|
|
7662
|
+
start: edgeCaptions?.start ?? strings.start,
|
|
7663
|
+
end: edgeCaptions?.end ?? (estimateAhead ? strings.estDone : void 0)
|
|
7567
7664
|
},
|
|
7568
7665
|
onDragStart: play.stop,
|
|
7569
7666
|
playback: {
|
|
@@ -7588,8 +7685,8 @@ function ProductionTimeline({
|
|
|
7588
7685
|
heading,
|
|
7589
7686
|
subject: poNumber,
|
|
7590
7687
|
meta: [
|
|
7591
|
-
`${
|
|
7592
|
-
|
|
7688
|
+
`${fmtDate(startMs)} \u2192 ${fmtDate(endMs)}`,
|
|
7689
|
+
strings.leadTime(totalLeadDays)
|
|
7593
7690
|
],
|
|
7594
7691
|
actions: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7595
7692
|
resetButton,
|
|
@@ -7600,7 +7697,7 @@ function ProductionTimeline({
|
|
|
7600
7697
|
/* @__PURE__ */ jsxs("div", { className: "rosh-tl-legend", children: [
|
|
7601
7698
|
reports.length > 0 && /* @__PURE__ */ jsxs("span", { className: "border-gray-200 text-gray-500", children: [
|
|
7602
7699
|
/* @__PURE__ */ jsx("i", { "aria-hidden": "true", className: "rosh-tl-glyph is-ring border-blue-600" }),
|
|
7603
|
-
|
|
7700
|
+
strings.report
|
|
7604
7701
|
] }),
|
|
7605
7702
|
shipmentMarkers.length > 0 && /* @__PURE__ */ jsxs("span", { className: "border-gray-200 text-gray-500", children: [
|
|
7606
7703
|
/* @__PURE__ */ jsx(
|
|
@@ -7612,7 +7709,7 @@ function ProductionTimeline({
|
|
|
7612
7709
|
children: /* @__PURE__ */ jsx(TimelineGlyph, { name: "truck" })
|
|
7613
7710
|
}
|
|
7614
7711
|
),
|
|
7615
|
-
|
|
7712
|
+
strings.shipment
|
|
7616
7713
|
] }),
|
|
7617
7714
|
inspectionMarkers.length > 0 && /* @__PURE__ */ jsxs("span", { className: "border-gray-200 text-gray-500", children: [
|
|
7618
7715
|
/* @__PURE__ */ jsx(
|
|
@@ -7624,7 +7721,7 @@ function ProductionTimeline({
|
|
|
7624
7721
|
children: /* @__PURE__ */ jsx(TimelineGlyph, { name: "flask" })
|
|
7625
7722
|
}
|
|
7626
7723
|
),
|
|
7627
|
-
|
|
7724
|
+
strings.inspection
|
|
7628
7725
|
] }),
|
|
7629
7726
|
invoiceMarkers.length > 0 && /* @__PURE__ */ jsxs("span", { className: "border-gray-200 text-gray-500", children: [
|
|
7630
7727
|
/* @__PURE__ */ jsx(
|
|
@@ -7636,7 +7733,7 @@ function ProductionTimeline({
|
|
|
7636
7733
|
children: /* @__PURE__ */ jsx(TimelineGlyph, { name: "receipt" })
|
|
7637
7734
|
}
|
|
7638
7735
|
),
|
|
7639
|
-
|
|
7736
|
+
strings.invoice
|
|
7640
7737
|
] })
|
|
7641
7738
|
] })
|
|
7642
7739
|
] }),
|
|
@@ -7685,6 +7782,7 @@ function ContainerFillChart({
|
|
|
7685
7782
|
className,
|
|
7686
7783
|
style
|
|
7687
7784
|
}) {
|
|
7785
|
+
const strings = useShellStrings().containers;
|
|
7688
7786
|
const filledLines = isFilled ? items.filter(isFilled) : items;
|
|
7689
7787
|
const qtyInstr = (l) => toInt(getInstructionQty(l));
|
|
7690
7788
|
const qtyActual = (l) => toInt(getActualQty(l));
|
|
@@ -7714,24 +7812,12 @@ function ContainerFillChart({
|
|
|
7714
7812
|
return /* @__PURE__ */ jsxs("div", { className: `mt-2 px-1 space-y-2 ${className ?? ""}`.trim(), style, children: [
|
|
7715
7813
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs text-gray-500", children: [
|
|
7716
7814
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
7717
|
-
filledLines.length
|
|
7718
|
-
"
|
|
7719
|
-
totalQty,
|
|
7720
|
-
" pcs",
|
|
7721
|
-
hasActual && totalQtyInstr !== totalQtyActual && /* @__PURE__ */ jsxs("span", { className: "ml-1 text-gray-400", children: [
|
|
7722
|
-
"(",
|
|
7723
|
-
totalQtyInstr,
|
|
7724
|
-
" instr / ",
|
|
7725
|
-
totalQtyActual,
|
|
7726
|
-
" loaded)"
|
|
7727
|
-
] })
|
|
7815
|
+
`${strings.items(filledLines.length)} \xB7 ${strings.pieces(totalQty)}`,
|
|
7816
|
+
hasActual && totalQtyInstr !== totalQtyActual && /* @__PURE__ */ jsx("span", { className: "ml-1 text-gray-400", children: strings.split(totalQtyInstr, totalQtyActual) })
|
|
7728
7817
|
] }),
|
|
7729
7818
|
showNewIndicator && newCount > 0 && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-green-600", children: [
|
|
7730
7819
|
/* @__PURE__ */ jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-green-500" }),
|
|
7731
|
-
newCount,
|
|
7732
|
-
" new (",
|
|
7733
|
-
newQty,
|
|
7734
|
-
" pcs)"
|
|
7820
|
+
strings.added(newCount, newQty)
|
|
7735
7821
|
] })
|
|
7736
7822
|
] }),
|
|
7737
7823
|
totalVolume > 0 ? /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
@@ -7750,28 +7836,23 @@ function ContainerFillChart({
|
|
|
7750
7836
|
/* @__PURE__ */ jsx("div", { className: `absolute inset-y-0 left-0 ${longerColor} transition-all`, style: { width: `${longerPct}%` } }),
|
|
7751
7837
|
dual && shorterPct > 0 && /* @__PURE__ */ jsx("div", { className: `absolute inset-y-0 left-0 ${shorterColor} transition-all`, style: { width: `${shorterPct}%` } })
|
|
7752
7838
|
] }),
|
|
7753
|
-
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-gray-500 w-16 text-right", children: dual ?
|
|
7839
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-gray-500 w-16 text-right", children: dual ? strings.fill(Math.min(totalVolumeActual - i * containerCap, containerCap), containerCap) : strings.fill(Math.min(totalVolumeInstr - i * containerCap, containerCap), containerCap) })
|
|
7754
7840
|
] }, `bar-${i}`);
|
|
7755
7841
|
}),
|
|
7756
7842
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs pt-0.5", children: [
|
|
7757
7843
|
/* @__PURE__ */ jsxs("span", { className: "text-gray-500 inline-flex items-center gap-1", children: [
|
|
7758
|
-
|
|
7844
|
+
strings.total,
|
|
7759
7845
|
hasActual ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7760
7846
|
/* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 text-blue-700", children: [
|
|
7761
7847
|
/* @__PURE__ */ jsx("span", { className: "inline-block w-2 h-2 rounded-full bg-blue-500" }),
|
|
7762
|
-
|
|
7763
|
-
" m\xB3 instruction"
|
|
7848
|
+
strings.instructed(totalVolumeInstr)
|
|
7764
7849
|
] }),
|
|
7765
7850
|
/* @__PURE__ */ jsx("span", { className: "text-gray-400", children: "/" }),
|
|
7766
7851
|
/* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 text-green-700", children: [
|
|
7767
7852
|
/* @__PURE__ */ jsx("span", { className: "inline-block w-2 h-2 rounded-full bg-green-500" }),
|
|
7768
|
-
|
|
7769
|
-
" m\xB3 loaded"
|
|
7853
|
+
strings.loaded(totalVolumeActual)
|
|
7770
7854
|
] })
|
|
7771
|
-
] }) : /* @__PURE__ */
|
|
7772
|
-
totalVolume.toFixed(2),
|
|
7773
|
-
" m\xB3"
|
|
7774
|
-
] })
|
|
7855
|
+
] }) : /* @__PURE__ */ jsx("b", { className: "text-gray-700", children: strings.volume(totalVolume) })
|
|
7775
7856
|
] }),
|
|
7776
7857
|
/* @__PURE__ */ jsxs("span", { className: `font-medium ${isOptimal ? "text-green-600" : "text-gray-500"}`, children: [
|
|
7777
7858
|
isOptimal && "\u2713 ",
|
|
@@ -7780,7 +7861,7 @@ function ContainerFillChart({
|
|
|
7780
7861
|
useType
|
|
7781
7862
|
] })
|
|
7782
7863
|
] })
|
|
7783
|
-
] }) : /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-400", children:
|
|
7864
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-400", children: strings.noVolume })
|
|
7784
7865
|
] });
|
|
7785
7866
|
}
|
|
7786
7867
|
var INLINE_RE = /!\[([^\]]*)\]\(([^)]+)\)|\[([^\]]+)\]\(([^)]+)\)|\*\*([^*]+)\*\*|`([^`]+)`|\*([^*]+)\*/g;
|
|
@@ -7850,6 +7931,7 @@ function renderInline(text) {
|
|
|
7850
7931
|
}
|
|
7851
7932
|
function ScreenshotPlaceholder({ alt }) {
|
|
7852
7933
|
const label = alt.replace(/^screenshot:\s*/i, "");
|
|
7934
|
+
const strings = useShellStrings().markdown;
|
|
7853
7935
|
return /* @__PURE__ */ jsxs("div", { className: "my-1 flex items-start gap-2 rounded-lg border border-dashed border-gray-300 bg-gray-50 px-3 py-2.5", children: [
|
|
7854
7936
|
/* @__PURE__ */ jsx(
|
|
7855
7937
|
"svg",
|
|
@@ -7862,7 +7944,7 @@ function ScreenshotPlaceholder({ alt }) {
|
|
|
7862
7944
|
}
|
|
7863
7945
|
),
|
|
7864
7946
|
/* @__PURE__ */ jsxs("span", { className: "text-xs text-gray-500", children: [
|
|
7865
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium text-gray-600", children:
|
|
7947
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-gray-600", children: `${strings.screenshot} \u2014 ` }),
|
|
7866
7948
|
label
|
|
7867
7949
|
] })
|
|
7868
7950
|
] });
|
|
@@ -8085,7 +8167,7 @@ function HelpCenter({
|
|
|
8085
8167
|
value: query,
|
|
8086
8168
|
onChange: (e) => setQuery(e.target.value),
|
|
8087
8169
|
placeholder: strings.help.searchPlaceholder,
|
|
8088
|
-
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
|
|
8170
|
+
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 rosh-focus-ring focus-visible:ring-1 focus-visible:ring-[color:var(--rosh-focus-ring-accent)]"
|
|
8089
8171
|
}
|
|
8090
8172
|
)
|
|
8091
8173
|
] }) }),
|
|
@@ -8163,6 +8245,7 @@ function SidebarActionButton({
|
|
|
8163
8245
|
title,
|
|
8164
8246
|
className = ""
|
|
8165
8247
|
}) {
|
|
8248
|
+
const hotkeyLabel = useShortcutLabel(hotkey ?? "");
|
|
8166
8249
|
return /* @__PURE__ */ jsxs(
|
|
8167
8250
|
"button",
|
|
8168
8251
|
{
|
|
@@ -8173,7 +8256,7 @@ function SidebarActionButton({
|
|
|
8173
8256
|
className: `w-full inline-flex items-center justify-center gap-2 rounded-lg px-4 py-2 text-sm font-medium transition-colors disabled:opacity-50 ${VARIANTS2[variant]} ${className}`,
|
|
8174
8257
|
children: [
|
|
8175
8258
|
children,
|
|
8176
|
-
hotkey && /* @__PURE__ */ jsx("kbd", { className: "rounded border border-blue-400/50 bg-blue-500/30 px-1.5 py-0.5 text-[10px] font-medium", children:
|
|
8259
|
+
hotkey && /* @__PURE__ */ jsx("kbd", { className: "rounded border border-blue-400/50 bg-blue-500/30 px-1.5 py-0.5 text-[10px] font-medium", children: hotkeyLabel })
|
|
8177
8260
|
]
|
|
8178
8261
|
}
|
|
8179
8262
|
);
|
|
@@ -8183,6 +8266,8 @@ function SidebarGroupLabel({ children }) {
|
|
|
8183
8266
|
}
|
|
8184
8267
|
function SidebarNavItem({ label, count, active, onClick, icon, trailing, severity }) {
|
|
8185
8268
|
const marker = resolveSeverity(severity, "SidebarNavItem");
|
|
8269
|
+
const severityWords = useShellStrings().severity;
|
|
8270
|
+
const word = marker ? severityWord(marker, severityWords) : void 0;
|
|
8186
8271
|
return /* @__PURE__ */ jsxs(
|
|
8187
8272
|
"button",
|
|
8188
8273
|
{
|
|
@@ -8198,7 +8283,7 @@ function SidebarNavItem({ label, count, active, onClick, icon, trailing, severit
|
|
|
8198
8283
|
"span",
|
|
8199
8284
|
{
|
|
8200
8285
|
"aria-hidden": "true",
|
|
8201
|
-
title:
|
|
8286
|
+
title: word,
|
|
8202
8287
|
className: `shrink-0 h-1.5 w-1.5 rounded-full ${marker.fill}`
|
|
8203
8288
|
}
|
|
8204
8289
|
),
|
|
@@ -8210,7 +8295,7 @@ function SidebarNavItem({ label, count, active, onClick, icon, trailing, severit
|
|
|
8210
8295
|
children: label
|
|
8211
8296
|
}
|
|
8212
8297
|
),
|
|
8213
|
-
marker && /* @__PURE__ */ jsx("span", { className: "sr-only", children:
|
|
8298
|
+
marker && /* @__PURE__ */ jsx("span", { className: "sr-only", children: word }),
|
|
8214
8299
|
count != null && count > 0 && /* @__PURE__ */ jsx("span", { className: `shrink-0 inline-flex items-center justify-center min-w-[1.25rem] px-1.5 h-5 rounded-full text-[11px] font-medium ${active ? "bg-blue-100 text-blue-700" : "bg-gray-100 text-gray-600"}`, children: count }),
|
|
8215
8300
|
trailing != null && /* @__PURE__ */ jsx("span", { className: "shrink-0", children: trailing })
|
|
8216
8301
|
]
|
|
@@ -8343,7 +8428,7 @@ function DropdownMenu({
|
|
|
8343
8428
|
disabled,
|
|
8344
8429
|
onClick: () => open ? close(false) : openAt(enabledFrom(0, 1)),
|
|
8345
8430
|
onKeyDown: onTriggerKeyDown,
|
|
8346
|
-
className: "inline-flex items-center justify-center rounded-md text-gray-600 transition-colors hover:bg-gray-100 hover:text-gray-900 focus
|
|
8431
|
+
className: "inline-flex items-center justify-center rounded-md text-gray-600 transition-colors hover:bg-gray-100 hover:text-gray-900 rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-solid)] disabled:cursor-not-allowed disabled:opacity-60",
|
|
8347
8432
|
children: trigger
|
|
8348
8433
|
}
|
|
8349
8434
|
),
|
|
@@ -8462,13 +8547,14 @@ var SIDE_POSITION = {
|
|
|
8462
8547
|
bottom: "inset-x-0 bottom-0"
|
|
8463
8548
|
};
|
|
8464
8549
|
function CloseButton({ onClose }) {
|
|
8550
|
+
const strings = useShellStrings().dialog;
|
|
8465
8551
|
return /* @__PURE__ */ jsx(
|
|
8466
8552
|
"button",
|
|
8467
8553
|
{
|
|
8468
8554
|
type: "button",
|
|
8469
8555
|
onClick: onClose,
|
|
8470
|
-
"aria-label":
|
|
8471
|
-
className: "rounded-md p-1 text-gray-400 hover:bg-gray-100 hover:text-gray-600 focus
|
|
8556
|
+
"aria-label": strings.close,
|
|
8557
|
+
className: "rounded-md p-1 text-gray-400 hover:bg-gray-100 hover:text-gray-600 rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-solid)]",
|
|
8472
8558
|
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" }) })
|
|
8473
8559
|
}
|
|
8474
8560
|
);
|
|
@@ -8540,7 +8626,10 @@ function Drawer({
|
|
|
8540
8626
|
] });
|
|
8541
8627
|
}
|
|
8542
8628
|
var DEFAULT_MAGNIFIER = "M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z";
|
|
8543
|
-
|
|
8629
|
+
var MIN_QUERY = 2;
|
|
8630
|
+
function GlobalSearch({ providers, typeIcons, placeholder: placeholderProp, onSelect } = {}) {
|
|
8631
|
+
const strings = useShellStrings().search;
|
|
8632
|
+
const placeholder = placeholderProp ?? strings.placeholder;
|
|
8544
8633
|
const [open, setOpen] = useState(false);
|
|
8545
8634
|
const [query, setQuery] = useState("");
|
|
8546
8635
|
const [results, setResults] = useState([]);
|
|
@@ -8572,7 +8661,7 @@ function GlobalSearch({ providers, typeIcons, placeholder = "Search...", onSelec
|
|
|
8572
8661
|
}, [open]);
|
|
8573
8662
|
useEffect(() => {
|
|
8574
8663
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
8575
|
-
if (query.length <
|
|
8664
|
+
if (query.length < MIN_QUERY) {
|
|
8576
8665
|
setResults([]);
|
|
8577
8666
|
return;
|
|
8578
8667
|
}
|
|
@@ -8626,14 +8715,14 @@ function GlobalSearch({ providers, typeIcons, placeholder = "Search...", onSelec
|
|
|
8626
8715
|
onChange: (e) => setQuery(e.target.value),
|
|
8627
8716
|
onKeyDown: handleKeyDown,
|
|
8628
8717
|
placeholder,
|
|
8629
|
-
className: "flex-1 text-sm bg-transparent border-0
|
|
8718
|
+
className: "flex-1 text-sm bg-transparent border-0 rosh-focus-ring placeholder-gray-400"
|
|
8630
8719
|
}
|
|
8631
8720
|
),
|
|
8632
|
-
/* @__PURE__ */ jsx("kbd", { className: "hidden sm:inline-flex items-center rounded border border-gray-300 px-1.5 py-0.5 text-[10px] font-medium text-gray-400", children:
|
|
8721
|
+
/* @__PURE__ */ jsx("kbd", { className: "hidden sm:inline-flex items-center rounded border border-gray-300 px-1.5 py-0.5 text-[10px] font-medium text-gray-400", children: strings.escBadge })
|
|
8633
8722
|
] }),
|
|
8634
8723
|
/* @__PURE__ */ jsxs("div", { className: "max-h-[50vh] overflow-y-auto", children: [
|
|
8635
|
-
loading && /* @__PURE__ */ jsx("div", { className: "px-4 py-6 text-center text-sm text-gray-400", children:
|
|
8636
|
-
!loading && query.length >=
|
|
8724
|
+
loading && /* @__PURE__ */ jsx("div", { className: "px-4 py-6 text-center text-sm text-gray-400", children: strings.searching }),
|
|
8725
|
+
!loading && query.length >= MIN_QUERY && results.length === 0 && /* @__PURE__ */ jsx("div", { className: "px-4 py-6 text-center text-sm text-gray-400", children: strings.noResults }),
|
|
8637
8726
|
!loading && results.length > 0 && /* @__PURE__ */ jsx("ul", { className: "py-2", children: results.map((r, i) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
|
|
8638
8727
|
"button",
|
|
8639
8728
|
{
|
|
@@ -8650,23 +8739,23 @@ function GlobalSearch({ providers, typeIcons, placeholder = "Search...", onSelec
|
|
|
8650
8739
|
]
|
|
8651
8740
|
}
|
|
8652
8741
|
) }, `${r.type}-${r.label}-${i}`)) }),
|
|
8653
|
-
!loading && query.length <
|
|
8742
|
+
!loading && query.length < MIN_QUERY && /* @__PURE__ */ jsx("div", { className: "px-4 py-6 text-center text-sm text-gray-400", children: strings.minChars(MIN_QUERY) })
|
|
8654
8743
|
] }),
|
|
8655
8744
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-2 border-t border-gray-100 bg-gray-50 text-[11px] text-gray-400", children: [
|
|
8656
8745
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
8657
8746
|
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
|
|
8658
8747
|
/* @__PURE__ */ jsx("kbd", { className: "rounded border border-gray-300 px-1 py-0.5 font-medium", children: "\u2191" }),
|
|
8659
8748
|
/* @__PURE__ */ jsx("kbd", { className: "rounded border border-gray-300 px-1 py-0.5 font-medium", children: "\u2193" }),
|
|
8660
|
-
|
|
8749
|
+
` ${strings.navigate}`
|
|
8661
8750
|
] }),
|
|
8662
8751
|
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
|
|
8663
|
-
/* @__PURE__ */ jsx("kbd", { className: "rounded border border-gray-300 px-1 py-0.5 font-medium", children:
|
|
8664
|
-
|
|
8752
|
+
/* @__PURE__ */ jsx("kbd", { className: "rounded border border-gray-300 px-1 py-0.5 font-medium", children: strings.enterKey }),
|
|
8753
|
+
` ${strings.open}`
|
|
8665
8754
|
] })
|
|
8666
8755
|
] }),
|
|
8667
8756
|
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
|
|
8668
|
-
/* @__PURE__ */ jsx("kbd", { className: "rounded border border-gray-300 px-1 py-0.5 font-medium", children:
|
|
8669
|
-
|
|
8757
|
+
/* @__PURE__ */ jsx("kbd", { className: "rounded border border-gray-300 px-1 py-0.5 font-medium", children: strings.escKey }),
|
|
8758
|
+
` ${strings.close}`
|
|
8670
8759
|
] })
|
|
8671
8760
|
] })
|
|
8672
8761
|
] })
|
|
@@ -8684,13 +8773,18 @@ function Kanban({
|
|
|
8684
8773
|
onCardClick,
|
|
8685
8774
|
sortInColumn,
|
|
8686
8775
|
isLoading = false,
|
|
8687
|
-
loadingText
|
|
8776
|
+
loadingText: loadingTextProp,
|
|
8688
8777
|
emptyState,
|
|
8689
8778
|
showColumnsWhenEmpty = false,
|
|
8690
|
-
columnEmptyText
|
|
8779
|
+
columnEmptyText: columnEmptyTextProp,
|
|
8691
8780
|
onAddItem,
|
|
8692
|
-
addItemText
|
|
8781
|
+
addItemText: addItemTextProp
|
|
8693
8782
|
}) {
|
|
8783
|
+
const strings = useShellStrings().kanban;
|
|
8784
|
+
const locale = useShellLocale();
|
|
8785
|
+
const loadingText = loadingTextProp ?? strings.loading;
|
|
8786
|
+
const columnEmptyText = columnEmptyTextProp ?? strings.dropHere;
|
|
8787
|
+
const addItemText = addItemTextProp ?? strings.addItem;
|
|
8694
8788
|
const [dragId, setDragId] = useState(null);
|
|
8695
8789
|
const [over, setOver] = useState(null);
|
|
8696
8790
|
const grouped = useMemo(() => {
|
|
@@ -8706,7 +8800,7 @@ function Kanban({
|
|
|
8706
8800
|
};
|
|
8707
8801
|
const boardRef = useRef(null);
|
|
8708
8802
|
const prevRects = useRef(/* @__PURE__ */ new Map());
|
|
8709
|
-
|
|
8803
|
+
useBrowserLayoutEffect(() => {
|
|
8710
8804
|
if (dragId !== null) return;
|
|
8711
8805
|
const board = boardRef.current;
|
|
8712
8806
|
if (!board) return;
|
|
@@ -8759,7 +8853,7 @@ function Kanban({
|
|
|
8759
8853
|
};
|
|
8760
8854
|
if (isLoading) return /* @__PURE__ */ jsx("div", { className: "text-sm text-gray-500 p-4", children: loadingText });
|
|
8761
8855
|
if (items.length === 0 && !showColumnsWhenEmpty) {
|
|
8762
|
-
return /* @__PURE__ */ jsx(Fragment, { children: emptyState ?? /* @__PURE__ */ jsx("div", { className: "text-sm text-gray-500 p-4", children:
|
|
8856
|
+
return /* @__PURE__ */ jsx(Fragment, { children: emptyState ?? /* @__PURE__ */ jsx("div", { className: "text-sm text-gray-500 p-4", children: strings.empty }) });
|
|
8763
8857
|
}
|
|
8764
8858
|
return /* @__PURE__ */ jsx("div", { ref: boardRef, className: "flex-1 overflow-x-auto grid-scroll", children: /* @__PURE__ */ jsx("div", { className: "flex gap-3 h-full min-w-max pb-2", children: columns.map((col) => {
|
|
8765
8859
|
const colItems = grouped[col.value] ?? [];
|
|
@@ -8791,7 +8885,7 @@ function Kanban({
|
|
|
8791
8885
|
/* @__PURE__ */ jsx("span", { className: `h-2 w-2 rounded-full ${col.dot ?? "bg-gray-400"}` }),
|
|
8792
8886
|
col.label
|
|
8793
8887
|
] }),
|
|
8794
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs opacity-70", children: colItems.length })
|
|
8888
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs opacity-70", children: formatPlain(colItems.length, locale) })
|
|
8795
8889
|
]
|
|
8796
8890
|
}
|
|
8797
8891
|
),
|
|
@@ -8890,14 +8984,16 @@ function Pagination({
|
|
|
8890
8984
|
showEdges = false,
|
|
8891
8985
|
className = ""
|
|
8892
8986
|
}) {
|
|
8987
|
+
const strings = useShellStrings().pagination;
|
|
8988
|
+
const locale = useShellLocale();
|
|
8893
8989
|
if (pageCount <= 1) return null;
|
|
8894
8990
|
const pages = buildPages(page, pageCount, siblingCount);
|
|
8895
8991
|
const go = (p) => {
|
|
8896
8992
|
if (p >= 1 && p <= pageCount && p !== page) onPageChange(p);
|
|
8897
8993
|
};
|
|
8898
|
-
return /* @__PURE__ */ jsxs("nav", { "aria-label":
|
|
8899
|
-
showEdges && /* @__PURE__ */ jsx("button", { type: "button", "aria-label":
|
|
8900
|
-
/* @__PURE__ */ jsx("button", { type: "button", "aria-label":
|
|
8994
|
+
return /* @__PURE__ */ jsxs("nav", { "aria-label": strings.label, className: `flex items-center gap-1 ${className}`.trim(), children: [
|
|
8995
|
+
showEdges && /* @__PURE__ */ jsx("button", { type: "button", "aria-label": strings.first, disabled: page === 1, onClick: () => go(1), className: `${BTN} text-gray-600 hover:bg-gray-100`, children: "\xAB" }),
|
|
8996
|
+
/* @__PURE__ */ jsx("button", { type: "button", "aria-label": strings.previous, disabled: page === 1, onClick: () => go(page - 1), className: `${BTN} text-gray-600 hover:bg-gray-100`, children: "\u2039" }),
|
|
8901
8997
|
pages.map(
|
|
8902
8998
|
(p, i) => p === "\u2026" ? /* @__PURE__ */ jsx("span", { className: "px-1 text-gray-400", children: "\u2026" }, `gap-${i}`) : /* @__PURE__ */ jsx(
|
|
8903
8999
|
"button",
|
|
@@ -8906,13 +9002,13 @@ function Pagination({
|
|
|
8906
9002
|
"aria-current": p === page ? "page" : void 0,
|
|
8907
9003
|
onClick: () => go(p),
|
|
8908
9004
|
className: `${BTN} ${p === page ? "bg-blue-600 font-medium text-white" : "text-gray-700 hover:bg-gray-100"}`,
|
|
8909
|
-
children: p
|
|
9005
|
+
children: formatPlain(p, locale)
|
|
8910
9006
|
},
|
|
8911
9007
|
p
|
|
8912
9008
|
)
|
|
8913
9009
|
),
|
|
8914
|
-
/* @__PURE__ */ jsx("button", { type: "button", "aria-label":
|
|
8915
|
-
showEdges && /* @__PURE__ */ jsx("button", { type: "button", "aria-label":
|
|
9010
|
+
/* @__PURE__ */ jsx("button", { type: "button", "aria-label": strings.next, disabled: page === pageCount, onClick: () => go(page + 1), className: `${BTN} text-gray-600 hover:bg-gray-100`, children: "\u203A" }),
|
|
9011
|
+
showEdges && /* @__PURE__ */ jsx("button", { type: "button", "aria-label": strings.last, disabled: page === pageCount, onClick: () => go(pageCount), className: `${BTN} text-gray-600 hover:bg-gray-100`, children: "\xBB" })
|
|
8916
9012
|
] });
|
|
8917
9013
|
}
|
|
8918
9014
|
var isGroup = (h) => Array.isArray(h.columns);
|
|
@@ -8967,7 +9063,7 @@ function DataTable({
|
|
|
8967
9063
|
const bottomPad = virtualized ? (data.length - end) * virtualized.rowHeight : 0;
|
|
8968
9064
|
const headRowRef = useRef(null);
|
|
8969
9065
|
const [headRowH, setHeadRowH] = useState(0);
|
|
8970
|
-
|
|
9066
|
+
useBrowserLayoutEffect(() => {
|
|
8971
9067
|
if (!virtualized) return;
|
|
8972
9068
|
const h = headRowRef.current?.offsetHeight ?? 0;
|
|
8973
9069
|
setHeadRowH((prev) => prev === h ? prev : h);
|
|
@@ -9148,7 +9244,7 @@ function DataTable({
|
|
|
9148
9244
|
} : {},
|
|
9149
9245
|
className: [
|
|
9150
9246
|
"border-b border-gray-100 last:border-b-0",
|
|
9151
|
-
rowProps?.onClick ? "cursor-pointer hover:bg-gray-50 focus
|
|
9247
|
+
rowProps?.onClick ? "cursor-pointer hover:bg-gray-50 rosh-focus-ring focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[color:var(--rosh-focus-ring-solid)]" : "",
|
|
9152
9248
|
rowClassName?.(row, i) ?? "",
|
|
9153
9249
|
rowProps?.className ?? ""
|
|
9154
9250
|
].filter(Boolean).join(" "),
|
|
@@ -9223,27 +9319,29 @@ function ListFooter({
|
|
|
9223
9319
|
isFetchingMore,
|
|
9224
9320
|
extra
|
|
9225
9321
|
}) {
|
|
9322
|
+
const strings = useShellStrings().list;
|
|
9226
9323
|
const total = totalCount ?? loadedCount;
|
|
9227
9324
|
const allLoaded = loadedCount >= total;
|
|
9228
9325
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
9229
9326
|
extra,
|
|
9230
|
-
selectedCount > 0 ? `${selectedCount}
|
|
9231
|
-
allLoaded ? totalCount != null ?
|
|
9232
|
-
isFetchingMore ?
|
|
9327
|
+
selectedCount > 0 ? `${strings.selected(selectedCount)} \u2014 ` : "",
|
|
9328
|
+
allLoaded ? totalCount != null ? strings.allLoaded(total, label) : strings.count(total, label) : strings.loadedOf(loadedCount, total, label),
|
|
9329
|
+
isFetchingMore ? ` \xB7 ${strings.loadingMore}` : ""
|
|
9233
9330
|
] });
|
|
9234
9331
|
}
|
|
9235
9332
|
function ListLoadError({
|
|
9236
|
-
title
|
|
9237
|
-
message
|
|
9333
|
+
title,
|
|
9334
|
+
message,
|
|
9238
9335
|
onRetry,
|
|
9239
9336
|
variant = "dashed"
|
|
9240
9337
|
}) {
|
|
9338
|
+
const strings = useShellStrings().list;
|
|
9241
9339
|
const frame = variant === "card" ? "rounded-md border border-gray-200 bg-white px-6 py-12" : variant === "none" ? "px-6 py-12" : "rounded-lg border-2 border-dashed border-red-200 px-6 py-12";
|
|
9242
9340
|
return /* @__PURE__ */ jsxs("div", { className: `flex flex-col items-center justify-center text-center ${frame}`, role: "alert", children: [
|
|
9243
9341
|
/* @__PURE__ */ jsx("svg", { className: "h-10 w-10 text-red-300 mb-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1, "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v3.75m0 3.75h.008M10.34 3.94l-8.4 14.55A1.5 1.5 0 003.24 21h17.52a1.5 1.5 0 001.3-2.51l-8.4-14.55a1.5 1.5 0 00-2.6 0z" }) }),
|
|
9244
|
-
/* @__PURE__ */ jsx("h3", { className: "text-sm font-medium text-gray-900", children: title }),
|
|
9245
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 mt-2", children: message }),
|
|
9246
|
-
onRetry && /* @__PURE__ */ jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsx(Button_default, { variant: "secondary", size: "sm", onClick: onRetry, children:
|
|
9342
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-medium text-gray-900", children: title ?? strings.loadError }),
|
|
9343
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 mt-2", children: message ?? strings.loadErrorMessage }),
|
|
9344
|
+
onRetry && /* @__PURE__ */ jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsx(Button_default, { variant: "secondary", size: "sm", onClick: onRetry, children: strings.retry }) })
|
|
9247
9345
|
] });
|
|
9248
9346
|
}
|
|
9249
9347
|
function Sparkline({
|
|
@@ -9296,6 +9394,7 @@ function BarChart({
|
|
|
9296
9394
|
className,
|
|
9297
9395
|
style
|
|
9298
9396
|
}) {
|
|
9397
|
+
const locale = useShellLocale();
|
|
9299
9398
|
if (data.length === 0) return null;
|
|
9300
9399
|
const peak = max ?? (Math.max(...data, 0) || 1);
|
|
9301
9400
|
return /* @__PURE__ */ jsxs("div", { className, style, children: [
|
|
@@ -9308,13 +9407,22 @@ function BarChart({
|
|
|
9308
9407
|
minHeight: v > 0 ? 2 : 0,
|
|
9309
9408
|
backgroundColor: colors?.[i] ?? color
|
|
9310
9409
|
},
|
|
9311
|
-
title: labels?.[i] != null ? `${labels[i]}: ${v}` :
|
|
9410
|
+
title: labels?.[i] != null ? `${labels[i]}: ${formatPlain(v, locale)}` : formatPlain(v, locale)
|
|
9312
9411
|
}
|
|
9313
9412
|
) }, i)) }),
|
|
9314
9413
|
labels && /* @__PURE__ */ jsx("div", { className: "mt-1 flex", style: { gap }, children: labels.map((l, i) => /* @__PURE__ */ jsx("div", { className: "flex-1 truncate text-center text-[10px] text-gray-400", children: l }, i)) })
|
|
9315
9414
|
] });
|
|
9316
9415
|
}
|
|
9317
|
-
var
|
|
9416
|
+
var DONUT_PALETTE = [
|
|
9417
|
+
"var(--rosh-donut-1)",
|
|
9418
|
+
"var(--rosh-donut-2)",
|
|
9419
|
+
"var(--rosh-donut-3)",
|
|
9420
|
+
"var(--rosh-donut-4)",
|
|
9421
|
+
"var(--rosh-donut-5)",
|
|
9422
|
+
"var(--rosh-donut-6)",
|
|
9423
|
+
"var(--rosh-donut-7)",
|
|
9424
|
+
"var(--rosh-donut-8)"
|
|
9425
|
+
];
|
|
9318
9426
|
function DonutChart({ segments, size = 120, thickness = 16, centerLabel, className, style }) {
|
|
9319
9427
|
const total = segments.reduce((s, x) => s + Math.max(0, x.value), 0) || 1;
|
|
9320
9428
|
const r = (size - thickness) / 2;
|
|
@@ -9328,7 +9436,7 @@ function DonutChart({ segments, size = 120, thickness = 16, centerLabel, classNa
|
|
|
9328
9436
|
style: { width: size, height: size, ...style },
|
|
9329
9437
|
children: [
|
|
9330
9438
|
/* @__PURE__ */ jsxs("svg", { width: size, height: size, viewBox: `0 0 ${size} ${size}`, role: "img", "aria-hidden": "true", style: { transform: "rotate(-90deg)" }, children: [
|
|
9331
|
-
/* @__PURE__ */ jsx("circle", { cx: c, cy: c, r, fill: "none", stroke: "
|
|
9439
|
+
/* @__PURE__ */ jsx("circle", { cx: c, cy: c, r, fill: "none", stroke: "var(--rosh-donut-track)", strokeWidth: thickness }),
|
|
9332
9440
|
segments.map((s, i) => {
|
|
9333
9441
|
const len2 = Math.max(0, s.value) / total * circ;
|
|
9334
9442
|
const el = /* @__PURE__ */ jsx(
|
|
@@ -9338,7 +9446,7 @@ function DonutChart({ segments, size = 120, thickness = 16, centerLabel, classNa
|
|
|
9338
9446
|
cy: c,
|
|
9339
9447
|
r,
|
|
9340
9448
|
fill: "none",
|
|
9341
|
-
stroke: s.color ??
|
|
9449
|
+
stroke: s.color ?? DONUT_PALETTE[i % DONUT_PALETTE.length],
|
|
9342
9450
|
strokeWidth: thickness,
|
|
9343
9451
|
strokeDasharray: `${len2} ${circ - len2}`,
|
|
9344
9452
|
strokeDashoffset: -offset
|
|
@@ -9361,7 +9469,7 @@ function toPoints(data, min, span) {
|
|
|
9361
9469
|
function pathFor(pts) {
|
|
9362
9470
|
return pts.map(([x, y], i) => `${i === 0 ? "M" : "L"}${x.toFixed(2)},${y.toFixed(2)}`).join(" ");
|
|
9363
9471
|
}
|
|
9364
|
-
var fmt = (v) => Number.isInteger(v) ?
|
|
9472
|
+
var fmt = (v, locale) => Number.isInteger(v) ? formatPlain(v, locale) : formatFixed(v, 1, locale);
|
|
9365
9473
|
function LineChart({
|
|
9366
9474
|
series,
|
|
9367
9475
|
labels,
|
|
@@ -9375,6 +9483,7 @@ function LineChart({
|
|
|
9375
9483
|
className,
|
|
9376
9484
|
style
|
|
9377
9485
|
}) {
|
|
9486
|
+
const locale = useShellLocale();
|
|
9378
9487
|
const drawn = series.filter((s) => s.data.length > 0);
|
|
9379
9488
|
if (drawn.length === 0) return null;
|
|
9380
9489
|
const all = drawn.flatMap((s) => s.data);
|
|
@@ -9389,9 +9498,9 @@ function LineChart({
|
|
|
9389
9498
|
] }, i)) }),
|
|
9390
9499
|
/* @__PURE__ */ jsxs("div", { className: "flex", children: [
|
|
9391
9500
|
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: [
|
|
9392
|
-
/* @__PURE__ */ jsx("span", { children: fmt(top) }),
|
|
9393
|
-
/* @__PURE__ */ jsx("span", { children: fmt(bottom + span / 2) }),
|
|
9394
|
-
/* @__PURE__ */ jsx("span", { children: fmt(bottom) })
|
|
9501
|
+
/* @__PURE__ */ jsx("span", { children: fmt(top, locale) }),
|
|
9502
|
+
/* @__PURE__ */ jsx("span", { children: fmt(bottom + span / 2, locale) }),
|
|
9503
|
+
/* @__PURE__ */ jsx("span", { children: fmt(bottom, locale) })
|
|
9395
9504
|
] }),
|
|
9396
9505
|
/* @__PURE__ */ jsxs(
|
|
9397
9506
|
"svg",
|
|
@@ -9411,7 +9520,7 @@ function LineChart({
|
|
|
9411
9520
|
return /* @__PURE__ */ jsxs("g", { children: [
|
|
9412
9521
|
s.fill && /* @__PURE__ */ jsx("path", { d: `${line} L100,100 L0,100 Z`, fill: s.fill, stroke: "none" }),
|
|
9413
9522
|
/* @__PURE__ */ jsx("path", { d: line, fill: "none", stroke: color(s), strokeWidth, strokeLinejoin: "round", strokeLinecap: "round", vectorEffect: "non-scaling-stroke" }),
|
|
9414
|
-
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))
|
|
9523
|
+
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} ` : ""}${formatPlain(s.data[i], locale)}` }) }, i))
|
|
9415
9524
|
] }, si);
|
|
9416
9525
|
})
|
|
9417
9526
|
]
|
|
@@ -9429,7 +9538,7 @@ var STATUS_GROUPS = {
|
|
|
9429
9538
|
overdue: "danger"
|
|
9430
9539
|
};
|
|
9431
9540
|
var REVENUE = [12, 18, 14, 22, 19, 27, 24, 31, 28, 35, 30, 38];
|
|
9432
|
-
var
|
|
9541
|
+
var MONTHS = ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"];
|
|
9433
9542
|
var ORDERS = [
|
|
9434
9543
|
{ id: "#3201", customer: "Alice Nguyen", total: "$1,204", status: "paid" },
|
|
9435
9544
|
{ id: "#3202", customer: "Marco Reyes", total: "$642", status: "shipped" },
|
|
@@ -9456,7 +9565,7 @@ function DashboardTemplate() {
|
|
|
9456
9565
|
/* @__PURE__ */ jsx(StatCard, { label: "Refunds", value: "$1.1k", delta: { value: "0%", direction: "flat" } })
|
|
9457
9566
|
] }),
|
|
9458
9567
|
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-4 lg:grid-cols-3", children: [
|
|
9459
|
-
/* @__PURE__ */ jsx(Card, { header: "Revenue", className: "lg:col-span-2", children: /* @__PURE__ */ jsx("div", { className: "text-blue-600", children: /* @__PURE__ */ jsx(BarChart, { data: REVENUE, labels:
|
|
9568
|
+
/* @__PURE__ */ jsx(Card, { header: "Revenue", className: "lg:col-span-2", children: /* @__PURE__ */ jsx("div", { className: "text-blue-600", children: /* @__PURE__ */ jsx(BarChart, { data: REVENUE, labels: MONTHS, height: 160 }) }) }),
|
|
9460
9569
|
/* @__PURE__ */ jsx(Card, { header: "Traffic sources", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
|
|
9461
9570
|
/* @__PURE__ */ jsx(
|
|
9462
9571
|
DonutChart,
|
|
@@ -9473,19 +9582,19 @@ function DashboardTemplate() {
|
|
|
9473
9582
|
),
|
|
9474
9583
|
/* @__PURE__ */ jsxs("ul", { className: "space-y-1.5 text-sm text-gray-600", children: [
|
|
9475
9584
|
/* @__PURE__ */ jsxs("li", { className: "flex items-center gap-2", children: [
|
|
9476
|
-
/* @__PURE__ */ jsx(Dot, { c:
|
|
9585
|
+
/* @__PURE__ */ jsx(Dot, { c: DONUT_PALETTE[0] }),
|
|
9477
9586
|
"Direct \xB7 45%"
|
|
9478
9587
|
] }),
|
|
9479
9588
|
/* @__PURE__ */ jsxs("li", { className: "flex items-center gap-2", children: [
|
|
9480
|
-
/* @__PURE__ */ jsx(Dot, { c:
|
|
9589
|
+
/* @__PURE__ */ jsx(Dot, { c: DONUT_PALETTE[1] }),
|
|
9481
9590
|
"Search \xB7 30%"
|
|
9482
9591
|
] }),
|
|
9483
9592
|
/* @__PURE__ */ jsxs("li", { className: "flex items-center gap-2", children: [
|
|
9484
|
-
/* @__PURE__ */ jsx(Dot, { c:
|
|
9593
|
+
/* @__PURE__ */ jsx(Dot, { c: DONUT_PALETTE[2] }),
|
|
9485
9594
|
"Social \xB7 15%"
|
|
9486
9595
|
] }),
|
|
9487
9596
|
/* @__PURE__ */ jsxs("li", { className: "flex items-center gap-2", children: [
|
|
9488
|
-
/* @__PURE__ */ jsx(Dot, { c:
|
|
9597
|
+
/* @__PURE__ */ jsx(Dot, { c: DONUT_PALETTE[3] }),
|
|
9489
9598
|
"Email \xB7 10%"
|
|
9490
9599
|
] })
|
|
9491
9600
|
] })
|
|
@@ -9971,12 +10080,12 @@ function AuthScreen({ mode = "login" }) {
|
|
|
9971
10080
|
] }) });
|
|
9972
10081
|
}
|
|
9973
10082
|
var COPY2 = {
|
|
9974
|
-
403: { title:
|
|
9975
|
-
404: { title:
|
|
9976
|
-
500: { title:
|
|
10083
|
+
403: (errors) => ({ title: errors.forbidden, body: errors.forbiddenBody }),
|
|
10084
|
+
404: (errors) => ({ title: errors.notFound, body: errors.notFoundBody }),
|
|
10085
|
+
500: (errors) => ({ title: errors.serverError, body: errors.serverErrorBody })
|
|
9977
10086
|
};
|
|
9978
10087
|
function ErrorPage({ code = 404, actions }) {
|
|
9979
|
-
const c = COPY2[code];
|
|
10088
|
+
const c = COPY2[code](useShellStrings().errors);
|
|
9980
10089
|
return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center bg-gray-50 p-6 text-center", children: [
|
|
9981
10090
|
/* @__PURE__ */ jsx("div", { className: "text-7xl font-bold tracking-tight text-gray-400", children: code }),
|
|
9982
10091
|
/* @__PURE__ */ jsx("h1", { className: "mt-2 text-xl font-semibold text-gray-900", children: c.title }),
|
|
@@ -9984,6 +10093,9 @@ function ErrorPage({ code = 404, actions }) {
|
|
|
9984
10093
|
actions && /* @__PURE__ */ jsx("div", { className: "mt-6 flex items-center gap-2", children: actions })
|
|
9985
10094
|
] });
|
|
9986
10095
|
}
|
|
10096
|
+
function ErrorWord({ pick }) {
|
|
10097
|
+
return /* @__PURE__ */ jsx(Fragment, { children: pick(useShellStrings().errors) });
|
|
10098
|
+
}
|
|
9987
10099
|
var ErrorBoundary = class extends Component {
|
|
9988
10100
|
state = { error: null };
|
|
9989
10101
|
static getDerivedStateFromError(error) {
|
|
@@ -10018,26 +10130,34 @@ var ErrorBoundary = class extends Component {
|
|
|
10018
10130
|
{
|
|
10019
10131
|
code: 500,
|
|
10020
10132
|
actions: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
10021
|
-
/* @__PURE__ */ jsx(Button_default, { onClick: this.reset, children:
|
|
10133
|
+
/* @__PURE__ */ jsx(Button_default, { onClick: this.reset, children: /* @__PURE__ */ jsx(ErrorWord, { pick: (errors) => errors.retry }) }),
|
|
10022
10134
|
this.props.actions
|
|
10023
10135
|
] })
|
|
10024
10136
|
}
|
|
10025
10137
|
) }),
|
|
10026
10138
|
this.props.showDetails && /* @__PURE__ */ jsxs("details", { className: "mx-auto w-full max-w-2xl shrink-0 px-6 pb-6", children: [
|
|
10027
|
-
/* @__PURE__ */ jsx("summary", { className: "cursor-pointer text-sm font-medium text-gray-600", children:
|
|
10139
|
+
/* @__PURE__ */ jsx("summary", { className: "cursor-pointer text-sm font-medium text-gray-600", children: /* @__PURE__ */ jsx(ErrorWord, { pick: (errors) => errors.details }) }),
|
|
10028
10140
|
/* @__PURE__ */ jsx("pre", { className: "mt-2 overflow-auto rounded-md bg-gray-100 p-3 text-xs text-gray-700", children: error.stack ?? error.message })
|
|
10029
10141
|
] })
|
|
10030
10142
|
] })
|
|
10031
10143
|
);
|
|
10032
10144
|
}
|
|
10033
10145
|
};
|
|
10146
|
+
function darkQuery() {
|
|
10147
|
+
return typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(prefers-color-scheme: dark)") : null;
|
|
10148
|
+
}
|
|
10034
10149
|
function subscribeMediaQuery(cb) {
|
|
10035
|
-
const mq =
|
|
10150
|
+
const mq = darkQuery();
|
|
10151
|
+
if (!mq) return () => {
|
|
10152
|
+
};
|
|
10036
10153
|
mq.addEventListener("change", cb);
|
|
10037
10154
|
return () => mq.removeEventListener("change", cb);
|
|
10038
10155
|
}
|
|
10039
10156
|
function getSystemIsDark() {
|
|
10040
|
-
return
|
|
10157
|
+
return darkQuery()?.matches ?? false;
|
|
10158
|
+
}
|
|
10159
|
+
function getServerIsDark() {
|
|
10160
|
+
return false;
|
|
10041
10161
|
}
|
|
10042
10162
|
function hexToHsl(hex) {
|
|
10043
10163
|
const r = parseInt(hex.slice(1, 3), 16) / 255;
|
|
@@ -10068,7 +10188,7 @@ function hslToHex(h, s, l) {
|
|
|
10068
10188
|
}
|
|
10069
10189
|
function resolveTheme(theme) {
|
|
10070
10190
|
const t = theme || "system";
|
|
10071
|
-
if (t === "system") return
|
|
10191
|
+
if (t === "system") return getSystemIsDark() ? "dark" : "light";
|
|
10072
10192
|
return t;
|
|
10073
10193
|
}
|
|
10074
10194
|
function applyAccent(accentColor) {
|
|
@@ -10126,7 +10246,7 @@ function applyThemePrefs(p) {
|
|
|
10126
10246
|
}
|
|
10127
10247
|
function useTheme() {
|
|
10128
10248
|
const { prefs } = useShellPrefs();
|
|
10129
|
-
const systemDark = useSyncExternalStore(subscribeMediaQuery, getSystemIsDark);
|
|
10249
|
+
const systemDark = useSyncExternalStore(subscribeMediaQuery, getSystemIsDark, getServerIsDark);
|
|
10130
10250
|
const saved = prefs.theme || "system";
|
|
10131
10251
|
const accentColor = prefs.accent_color || null;
|
|
10132
10252
|
const customBgColor = prefs.custom_bg_color || null;
|
|
@@ -10558,7 +10678,7 @@ function usePlotWidth(ref, fallback = DEFAULT_PLOT_WIDTH) {
|
|
|
10558
10678
|
function RankedBars({
|
|
10559
10679
|
rows,
|
|
10560
10680
|
max,
|
|
10561
|
-
formatValue
|
|
10681
|
+
formatValue: formatValueProp,
|
|
10562
10682
|
emphasisKey,
|
|
10563
10683
|
highlight = "none",
|
|
10564
10684
|
emphasisTone,
|
|
@@ -10566,8 +10686,12 @@ function RankedBars({
|
|
|
10566
10686
|
rowGap = 30,
|
|
10567
10687
|
animate = true,
|
|
10568
10688
|
className,
|
|
10569
|
-
emptyLabel
|
|
10689
|
+
emptyLabel: emptyLabelProp
|
|
10570
10690
|
}) {
|
|
10691
|
+
const strings = useShellStrings().charts;
|
|
10692
|
+
const locale = useShellLocale();
|
|
10693
|
+
const formatValue = formatValueProp ?? ((v) => formatPlain(v, locale));
|
|
10694
|
+
const emptyLabel = emptyLabelProp ?? strings.nothingToRank;
|
|
10571
10695
|
if (rows.length === 0) {
|
|
10572
10696
|
return /* @__PURE__ */ jsx("p", { className: `text-sm text-gray-500 ${className ?? ""}`, children: emptyLabel });
|
|
10573
10697
|
}
|
|
@@ -10584,7 +10708,7 @@ function RankedBars({
|
|
|
10584
10708
|
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between gap-3", children: [
|
|
10585
10709
|
/* @__PURE__ */ jsxs("span", { className: `truncate font-mono text-xs text-gray-600 ${emphasised ? "font-semibold" : ""}`, title: row.label, children: [
|
|
10586
10710
|
row.label,
|
|
10587
|
-
emphasised && /* @__PURE__ */ jsx("span", { className: "sr-only", children:
|
|
10711
|
+
emphasised && /* @__PURE__ */ jsx("span", { className: "sr-only", children: ` ${strings.emphasised}` })
|
|
10588
10712
|
] }),
|
|
10589
10713
|
/* @__PURE__ */ jsx(
|
|
10590
10714
|
"span",
|
|
@@ -10618,11 +10742,15 @@ function Meter({
|
|
|
10618
10742
|
objective,
|
|
10619
10743
|
label,
|
|
10620
10744
|
detail,
|
|
10621
|
-
formatValue
|
|
10745
|
+
formatValue: formatValueProp,
|
|
10622
10746
|
tone,
|
|
10623
10747
|
className,
|
|
10624
|
-
unavailableLabel
|
|
10748
|
+
unavailableLabel: unavailableLabelProp
|
|
10625
10749
|
}) {
|
|
10750
|
+
const strings = useShellStrings().charts;
|
|
10751
|
+
const locale = useShellLocale();
|
|
10752
|
+
const formatValue = formatValueProp ?? ((v) => formatPercent(v * 100, 1, locale));
|
|
10753
|
+
const unavailableLabel = unavailableLabelProp ?? strings.notEnough;
|
|
10626
10754
|
if (value == null || !Number.isFinite(value)) {
|
|
10627
10755
|
return /* @__PURE__ */ jsxs("div", { className, children: [
|
|
10628
10756
|
label && /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-gray-700", children: label }),
|
|
@@ -10636,7 +10764,7 @@ function Meter({
|
|
|
10636
10764
|
const caption = [
|
|
10637
10765
|
segments?.length ? segments.map((seg) => `${seg.label} ${formatValue(seg.value)}`).join(" \xB7 ") : "",
|
|
10638
10766
|
detail ?? "",
|
|
10639
|
-
objective != null ?
|
|
10767
|
+
objective != null ? (met ? strings.objectiveMet : strings.objectiveMissed)(formatValue(objective)) : ""
|
|
10640
10768
|
].filter(Boolean).join(" \xB7 ");
|
|
10641
10769
|
return /* @__PURE__ */ jsxs("div", { className, children: [
|
|
10642
10770
|
/* @__PURE__ */ jsxs("div", { className: "mb-1.5 flex items-baseline justify-between gap-3", children: [
|
|
@@ -10704,9 +10832,9 @@ function Meter({
|
|
|
10704
10832
|
] });
|
|
10705
10833
|
}
|
|
10706
10834
|
var DIRECTION = {
|
|
10707
|
-
up: { glyph: "\u25B2", word: "
|
|
10708
|
-
down: { glyph: "\u25BC", word: "
|
|
10709
|
-
flat: { glyph: "\u25A0", word: "
|
|
10835
|
+
up: { glyph: "\u25B2", word: "trendUp" },
|
|
10836
|
+
down: { glyph: "\u25BC", word: "trendDown" },
|
|
10837
|
+
flat: { glyph: "\u25A0", word: "trendFlat" }
|
|
10710
10838
|
};
|
|
10711
10839
|
function StatTile({
|
|
10712
10840
|
label,
|
|
@@ -10719,6 +10847,8 @@ function StatTile({
|
|
|
10719
10847
|
footnote,
|
|
10720
10848
|
className
|
|
10721
10849
|
}) {
|
|
10850
|
+
const strings = useShellStrings().charts;
|
|
10851
|
+
const locale = useShellLocale();
|
|
10722
10852
|
const direction = delta == null ? null : delta > 0 ? "up" : delta < 0 ? "down" : "flat";
|
|
10723
10853
|
const deltaColour = deltaTone ? STATUS_VARS[deltaTone] : void 0;
|
|
10724
10854
|
const trendColour = trendTone ? STATUS_VARS[trendTone] : resolveSeriesColor(0);
|
|
@@ -10731,10 +10861,10 @@ function StatTile({
|
|
|
10731
10861
|
direction && /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium", style: deltaColour ? { color: deltaColour } : void 0, children: [
|
|
10732
10862
|
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: DIRECTION[direction].glyph }),
|
|
10733
10863
|
" ",
|
|
10734
|
-
Math.abs(delta),
|
|
10864
|
+
formatPlain(Math.abs(delta), locale),
|
|
10735
10865
|
/* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
|
|
10736
10866
|
" ",
|
|
10737
|
-
DIRECTION[direction].word
|
|
10867
|
+
strings[DIRECTION[direction].word]
|
|
10738
10868
|
] })
|
|
10739
10869
|
] }),
|
|
10740
10870
|
trend && trend.length > 1 && /* @__PURE__ */ jsx(
|
|
@@ -10755,9 +10885,11 @@ function ChartSkeleton({
|
|
|
10755
10885
|
width = 720,
|
|
10756
10886
|
variant = "area",
|
|
10757
10887
|
bars = 9,
|
|
10758
|
-
label
|
|
10888
|
+
label: labelProp,
|
|
10759
10889
|
className
|
|
10760
10890
|
}) {
|
|
10891
|
+
const strings = useShellStrings().charts;
|
|
10892
|
+
const label = labelProp ?? strings.loading;
|
|
10761
10893
|
const id = useId();
|
|
10762
10894
|
const shimmerId = `${id}-shimmer`;
|
|
10763
10895
|
const left = 48;
|
|
@@ -10892,7 +11024,7 @@ function ChartLegend({
|
|
|
10892
11024
|
onMouseLeave: () => setHighlighted(null),
|
|
10893
11025
|
onFocus: () => setHighlighted(entry.key),
|
|
10894
11026
|
onBlur: () => setHighlighted(null),
|
|
10895
|
-
className: `flex items-center gap-2 rounded text-xs text-gray-600 transition-opacity
|
|
11027
|
+
className: `flex items-center gap-2 rounded text-xs text-gray-600 transition-opacity rosh-focus-outline ${dimmed ? "opacity-40" : ""}`,
|
|
10896
11028
|
children: swatch
|
|
10897
11029
|
}
|
|
10898
11030
|
) : /* @__PURE__ */ jsx("span", { className: "flex items-center gap-2 text-xs text-gray-600", children: swatch }) }, entry.key);
|
|
@@ -10903,7 +11035,7 @@ function ChartFrame({
|
|
|
10903
11035
|
subtitle,
|
|
10904
11036
|
legend,
|
|
10905
11037
|
table,
|
|
10906
|
-
tableLabel
|
|
11038
|
+
tableLabel,
|
|
10907
11039
|
busy = false,
|
|
10908
11040
|
loading = false,
|
|
10909
11041
|
skeletonVariant = "area",
|
|
@@ -10914,6 +11046,7 @@ function ChartFrame({
|
|
|
10914
11046
|
children,
|
|
10915
11047
|
className
|
|
10916
11048
|
}) {
|
|
11049
|
+
const strings = useShellStrings().charts;
|
|
10917
11050
|
return /* @__PURE__ */ jsx(ChartHighlightProvider, { children: /* @__PURE__ */ jsxs(
|
|
10918
11051
|
"section",
|
|
10919
11052
|
{
|
|
@@ -10930,7 +11063,7 @@ function ChartFrame({
|
|
|
10930
11063
|
loading ? /* @__PURE__ */ jsx(ChartSkeleton, { variant: skeletonVariant, height: skeletonHeight }) : /* @__PURE__ */ jsx("div", { className: busy ? "opacity-60 transition-opacity" : "transition-opacity", children }),
|
|
10931
11064
|
!loading && legend && legend.length > 1 && /* @__PURE__ */ jsx(ChartLegend, { entries: legend, interactive: interactiveLegend, fallbackSwatch: legendSwatch }),
|
|
10932
11065
|
!loading && table && /* @__PURE__ */ jsxs("details", { className: "border-t border-gray-100 pt-3", children: [
|
|
10933
|
-
/* @__PURE__ */ jsx("summary", { className: "cursor-pointer text-sm font-medium text-gray-600
|
|
11066
|
+
/* @__PURE__ */ jsx("summary", { className: "cursor-pointer text-sm font-medium text-gray-600 rosh-focus-outline", children: tableLabel ?? strings.showTable }),
|
|
10934
11067
|
/* @__PURE__ */ jsx("div", { className: "mt-3 overflow-x-auto", style: { color: CHART_INK.label }, children: table })
|
|
10935
11068
|
] })
|
|
10936
11069
|
]
|
|
@@ -11026,6 +11159,7 @@ function ChartBrush({
|
|
|
11026
11159
|
color,
|
|
11027
11160
|
className
|
|
11028
11161
|
}) {
|
|
11162
|
+
const strings = useShellStrings().charts;
|
|
11029
11163
|
const track = useRef(null);
|
|
11030
11164
|
const last = labels.length - 1;
|
|
11031
11165
|
const [from, to] = range;
|
|
@@ -11103,10 +11237,10 @@ function ChartBrush({
|
|
|
11103
11237
|
height,
|
|
11104
11238
|
rx: 3,
|
|
11105
11239
|
fill: hue,
|
|
11106
|
-
className: "cursor-ew-resize focus
|
|
11240
|
+
className: "cursor-ew-resize rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-deep)]",
|
|
11107
11241
|
tabIndex: 0,
|
|
11108
11242
|
role: "slider",
|
|
11109
|
-
"aria-label": edge === "from" ?
|
|
11243
|
+
"aria-label": edge === "from" ? strings.windowStart : strings.windowEnd,
|
|
11110
11244
|
"aria-valuemin": 0,
|
|
11111
11245
|
"aria-valuemax": last,
|
|
11112
11246
|
"aria-valuenow": index,
|
|
@@ -11129,7 +11263,7 @@ function ChartBrush({
|
|
|
11129
11263
|
height,
|
|
11130
11264
|
viewBox: `0 0 ${width} ${height}`,
|
|
11131
11265
|
role: "group",
|
|
11132
|
-
"aria-label":
|
|
11266
|
+
"aria-label": strings.window(labels[from], labels[to], labels.length),
|
|
11133
11267
|
children: [
|
|
11134
11268
|
/* @__PURE__ */ jsx("path", { d: outline, fill: CHART_INK.grid }),
|
|
11135
11269
|
/* @__PURE__ */ jsx("rect", { x: 0, y: 0, width: xAt(from), height, fill: CHART_INK.surface, fillOpacity: 0.72 }),
|
|
@@ -11161,15 +11295,19 @@ function CartesianPlot({
|
|
|
11161
11295
|
min,
|
|
11162
11296
|
max,
|
|
11163
11297
|
yTickCount = 4,
|
|
11164
|
-
formatValue
|
|
11298
|
+
formatValue: formatValueProp,
|
|
11165
11299
|
yAxisLabel,
|
|
11166
11300
|
xTickAnchor = "center",
|
|
11167
11301
|
children,
|
|
11168
11302
|
tooltip,
|
|
11169
11303
|
ariaLabel,
|
|
11170
11304
|
className,
|
|
11171
|
-
emptyLabel
|
|
11305
|
+
emptyLabel: emptyLabelProp
|
|
11172
11306
|
}) {
|
|
11307
|
+
const strings = useShellStrings().charts;
|
|
11308
|
+
const locale = useShellLocale();
|
|
11309
|
+
const formatValue = formatValueProp ?? ((v) => formatPlain(v, locale));
|
|
11310
|
+
const emptyLabel = emptyLabelProp ?? strings.noData;
|
|
11173
11311
|
const host = useRef(null);
|
|
11174
11312
|
const measured = usePlotWidth(host);
|
|
11175
11313
|
const width = widthProp ?? measured;
|
|
@@ -11214,7 +11352,7 @@ function CartesianPlot({
|
|
|
11214
11352
|
role: "img",
|
|
11215
11353
|
"aria-label": ariaLabel,
|
|
11216
11354
|
tabIndex: 0,
|
|
11217
|
-
className: "focus
|
|
11355
|
+
className: "rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-deep)]",
|
|
11218
11356
|
onMouseLeave: () => setActive(null),
|
|
11219
11357
|
onBlur: () => setActive(null),
|
|
11220
11358
|
onKeyDown: onKey,
|
|
@@ -11268,7 +11406,7 @@ function TimeSeriesChart({
|
|
|
11268
11406
|
tension = 0,
|
|
11269
11407
|
max,
|
|
11270
11408
|
yTickCount = 4,
|
|
11271
|
-
formatValue
|
|
11409
|
+
formatValue: formatValueProp,
|
|
11272
11410
|
yAxisLabel,
|
|
11273
11411
|
referenceLines,
|
|
11274
11412
|
labelEndpoints = false,
|
|
@@ -11285,8 +11423,12 @@ function TimeSeriesChart({
|
|
|
11285
11423
|
gridStyle = "solid",
|
|
11286
11424
|
width: widthProp,
|
|
11287
11425
|
className,
|
|
11288
|
-
emptyLabel
|
|
11426
|
+
emptyLabel: emptyLabelProp
|
|
11289
11427
|
}) {
|
|
11428
|
+
const strings = useShellStrings().charts;
|
|
11429
|
+
const locale = useShellLocale();
|
|
11430
|
+
const formatValue = formatValueProp ?? ((v) => formatPlain(v, locale));
|
|
11431
|
+
const emptyLabel = emptyLabelProp ?? strings.noData;
|
|
11290
11432
|
const host = useRef(null);
|
|
11291
11433
|
const measured = usePlotWidth(host);
|
|
11292
11434
|
const width = widthProp ?? measured;
|
|
@@ -11341,7 +11483,7 @@ function TimeSeriesChart({
|
|
|
11341
11483
|
const y = linearScale([0, top], { from: plot.bottom, to: plot.top });
|
|
11342
11484
|
const scaleY = (value) => ladder ? ladder(value) : y(value);
|
|
11343
11485
|
const isPercent = stacked && stackMode === "percent";
|
|
11344
|
-
const formatTick = isPercent ? (v) =>
|
|
11486
|
+
const formatTick = isPercent ? (v) => formatPercent(Math.round(v * 100), 0, locale) : formatValue;
|
|
11345
11487
|
const yTicks = ladder ? ladder.levels.map((level) => ({ value: level, y: ladder(level) })) : y.ticks(yTickCount + 1).map((value) => ({ value, y: y(value) }));
|
|
11346
11488
|
const move = (delta) => (event) => {
|
|
11347
11489
|
event.preventDefault();
|
|
@@ -11359,9 +11501,9 @@ function TimeSeriesChart({
|
|
|
11359
11501
|
height,
|
|
11360
11502
|
viewBox: `0 0 ${width} ${height}`,
|
|
11361
11503
|
role: "img",
|
|
11362
|
-
"aria-label":
|
|
11504
|
+
"aria-label": strings.overIntervals(drawn.map((s) => s.label), labels.length),
|
|
11363
11505
|
tabIndex: 0,
|
|
11364
|
-
className: "focus
|
|
11506
|
+
className: "rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-deep)]",
|
|
11365
11507
|
onMouseLeave: () => setActive(null),
|
|
11366
11508
|
onBlur: () => setActive(null),
|
|
11367
11509
|
onKeyDown: (event) => {
|
|
@@ -11631,9 +11773,9 @@ function TimeSeriesChart({
|
|
|
11631
11773
|
// carries it back: the share the chart drew AND the count it was
|
|
11632
11774
|
// taken over. A share without its denominator is the thing this
|
|
11633
11775
|
// whole family keeps refusing to ship.
|
|
11634
|
-
value: !isValue(s.data[active]) ? void 0 : stacked && stackMode === "percent" ? `${((share(s.data[active], active) ?? 0) * 100
|
|
11776
|
+
value: !isValue(s.data[active]) ? void 0 : stacked && stackMode === "percent" ? `${formatPercent((share(s.data[active], active) ?? 0) * 100, 1, locale)} \xB7 ${formatValue(s.data[active])}` : formatValue(s.data[active])
|
|
11635
11777
|
})),
|
|
11636
|
-
footnote: stacked && stackMode === "percent" ?
|
|
11778
|
+
footnote: stacked && stackMode === "percent" ? strings.inBucket(formatValue(bucketTotals[active])) : void 0
|
|
11637
11779
|
}
|
|
11638
11780
|
)
|
|
11639
11781
|
}
|
|
@@ -11649,7 +11791,7 @@ function ColumnChart({
|
|
|
11649
11791
|
height = 220,
|
|
11650
11792
|
width,
|
|
11651
11793
|
max,
|
|
11652
|
-
formatValue
|
|
11794
|
+
formatValue: formatValueProp,
|
|
11653
11795
|
yAxisLabel,
|
|
11654
11796
|
className,
|
|
11655
11797
|
emptyLabel,
|
|
@@ -11663,6 +11805,9 @@ function ColumnChart({
|
|
|
11663
11805
|
}) {
|
|
11664
11806
|
const defsId = useId();
|
|
11665
11807
|
const { highlighted } = useHighlight();
|
|
11808
|
+
const strings = useShellStrings().charts;
|
|
11809
|
+
const locale = useShellLocale();
|
|
11810
|
+
const formatValue = formatValueProp ?? ((v) => formatPlain(v, locale));
|
|
11666
11811
|
if (loading) return /* @__PURE__ */ jsx(ChartSkeleton, { height, width, variant: "bars", className });
|
|
11667
11812
|
const drawn = series.map((s, slot) => ({ ...s, slot })).filter((s) => s.data.some((v) => Number.isFinite(v)));
|
|
11668
11813
|
const finiteAt = (s, i) => {
|
|
@@ -11683,11 +11828,11 @@ function ColumnChart({
|
|
|
11683
11828
|
height,
|
|
11684
11829
|
width,
|
|
11685
11830
|
max: percent ? 1 : max,
|
|
11686
|
-
formatValue: percent ? (v) =>
|
|
11831
|
+
formatValue: percent ? (v) => formatPercent(Math.round(v * 100), 0, locale) : formatValue,
|
|
11687
11832
|
yAxisLabel,
|
|
11688
11833
|
className,
|
|
11689
11834
|
emptyLabel,
|
|
11690
|
-
ariaLabel:
|
|
11835
|
+
ariaLabel: strings.acrossCategories(drawn.map((s) => s.label), labels.length),
|
|
11691
11836
|
tooltip: (index) => /* @__PURE__ */ jsx(
|
|
11692
11837
|
ChartTooltip,
|
|
11693
11838
|
{
|
|
@@ -11698,9 +11843,9 @@ function ColumnChart({
|
|
|
11698
11843
|
color: resolveSeriesColor(s.slot, s.color, s.tone),
|
|
11699
11844
|
// Percent mode drops volume from the plot, so the tooltip carries
|
|
11700
11845
|
// it back — the share AND the count it was taken over.
|
|
11701
|
-
value: !Number.isFinite(s.data[index]) ? void 0 : percent ? `${((share(s.data[index], index) ?? 0) * 100
|
|
11846
|
+
value: !Number.isFinite(s.data[index]) ? void 0 : percent ? `${formatPercent((share(s.data[index], index) ?? 0) * 100, 1, locale)} \xB7 ${formatValue(s.data[index])}` : formatValue(s.data[index])
|
|
11702
11847
|
})),
|
|
11703
|
-
footnote: percent ?
|
|
11848
|
+
footnote: percent ? strings.inCategory(formatValue(totals[index])) : void 0
|
|
11704
11849
|
}
|
|
11705
11850
|
),
|
|
11706
11851
|
children: ({ x, y, bottom, active }) => {
|
|
@@ -11776,16 +11921,21 @@ function ScatterChart({
|
|
|
11776
11921
|
width: widthProp,
|
|
11777
11922
|
xLabel,
|
|
11778
11923
|
yLabel,
|
|
11779
|
-
formatX
|
|
11780
|
-
formatY
|
|
11924
|
+
formatX: formatXProp,
|
|
11925
|
+
formatY: formatYProp,
|
|
11781
11926
|
xDomain,
|
|
11782
11927
|
yDomain,
|
|
11783
11928
|
xScale = "linear",
|
|
11784
11929
|
yScale = "linear",
|
|
11785
11930
|
radiusRange = [4, 22],
|
|
11786
11931
|
className,
|
|
11787
|
-
emptyLabel
|
|
11932
|
+
emptyLabel: emptyLabelProp
|
|
11788
11933
|
}) {
|
|
11934
|
+
const strings = useShellStrings().charts;
|
|
11935
|
+
const locale = useShellLocale();
|
|
11936
|
+
const formatX = formatXProp ?? ((v) => formatPlain(v, locale));
|
|
11937
|
+
const formatY = formatYProp ?? ((v) => formatPlain(v, locale));
|
|
11938
|
+
const emptyLabel = emptyLabelProp ?? strings.noObservations;
|
|
11789
11939
|
const host = useRef(null);
|
|
11790
11940
|
const measured = usePlotWidth(host);
|
|
11791
11941
|
const width = widthProp ?? measured;
|
|
@@ -11838,9 +11988,9 @@ function ScatterChart({
|
|
|
11838
11988
|
height,
|
|
11839
11989
|
viewBox: `0 0 ${width} ${height}`,
|
|
11840
11990
|
role: "img",
|
|
11841
|
-
"aria-label":
|
|
11991
|
+
"aria-label": strings.scatter(drawn.map((s) => s.label), yLabel ?? strings.yAxis, xLabel ?? strings.xAxis) + (omitted > 0 ? `. ${strings.outsideRange(omitted)}` : ""),
|
|
11842
11992
|
tabIndex: 0,
|
|
11843
|
-
className: "focus
|
|
11993
|
+
className: "rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-deep)]",
|
|
11844
11994
|
onMouseLeave: () => setHover(null),
|
|
11845
11995
|
onBlur: () => setHover(null),
|
|
11846
11996
|
onKeyDown: onKey,
|
|
@@ -11878,9 +12028,9 @@ function ScatterChart({
|
|
|
11878
12028
|
{
|
|
11879
12029
|
title: hoveredPoint.label ?? hoveredSeries.label,
|
|
11880
12030
|
rows: [
|
|
11881
|
-
{ key: "x", label: xLabel ??
|
|
11882
|
-
{ key: "y", label: yLabel ??
|
|
11883
|
-
...hoveredPoint.size != null ? [{ key: "size", label:
|
|
12031
|
+
{ key: "x", label: xLabel ?? strings.xAxis, color: resolveSeriesColor(hover.s, hoveredSeries.color, hoveredSeries.tone), value: formatX(hoveredPoint.x) },
|
|
12032
|
+
{ key: "y", label: yLabel ?? strings.yAxis, color: resolveSeriesColor(hover.s, hoveredSeries.color, hoveredSeries.tone), value: formatY(hoveredPoint.y) },
|
|
12033
|
+
...hoveredPoint.size != null ? [{ key: "size", label: strings.size, color: CHART_INK.muted, value: formatPlain(hoveredPoint.size, locale) }] : []
|
|
11884
12034
|
],
|
|
11885
12035
|
footnote: hoveredPoint.label ? hoveredSeries.label : void 0
|
|
11886
12036
|
}
|
|
@@ -11896,15 +12046,19 @@ function RangeChart({
|
|
|
11896
12046
|
width,
|
|
11897
12047
|
max,
|
|
11898
12048
|
min,
|
|
11899
|
-
formatValue
|
|
12049
|
+
formatValue: formatValueProp,
|
|
11900
12050
|
yAxisLabel,
|
|
11901
12051
|
color,
|
|
11902
12052
|
tone,
|
|
11903
|
-
label
|
|
12053
|
+
label: labelProp,
|
|
11904
12054
|
className,
|
|
11905
12055
|
emptyLabel,
|
|
11906
12056
|
radius = 3
|
|
11907
12057
|
}) {
|
|
12058
|
+
const strings = useShellStrings().charts;
|
|
12059
|
+
const locale = useShellLocale();
|
|
12060
|
+
const formatValue = formatValueProp ?? ((v) => formatPlain(v, locale));
|
|
12061
|
+
const label = labelProp ?? strings.range;
|
|
11908
12062
|
const values = rows.flatMap((r) => [r.low, r.high]).filter(Number.isFinite);
|
|
11909
12063
|
const colour = resolveSeriesColor(0, color, tone);
|
|
11910
12064
|
return /* @__PURE__ */ jsx(
|
|
@@ -11921,15 +12075,15 @@ function RangeChart({
|
|
|
11921
12075
|
className,
|
|
11922
12076
|
emptyLabel,
|
|
11923
12077
|
bandPadding: variant === "bar" ? 0.34 : 0,
|
|
11924
|
-
ariaLabel:
|
|
12078
|
+
ariaLabel: strings.rangeLabel(label, labels.length),
|
|
11925
12079
|
tooltip: (index) => /* @__PURE__ */ jsx(
|
|
11926
12080
|
ChartTooltip,
|
|
11927
12081
|
{
|
|
11928
12082
|
title: labels[index],
|
|
11929
12083
|
rows: [
|
|
11930
12084
|
// undefined renders the em dash: "no row here" is not "zero".
|
|
11931
|
-
{ key: "high", label:
|
|
11932
|
-
{ key: "low", label:
|
|
12085
|
+
{ key: "high", label: strings.high, color: colour, value: rows[index] == null ? void 0 : formatValue(rows[index].high) },
|
|
12086
|
+
{ key: "low", label: strings.low, color: colour, value: rows[index] == null ? void 0 : formatValue(rows[index].low) }
|
|
11933
12087
|
]
|
|
11934
12088
|
}
|
|
11935
12089
|
),
|
|
@@ -11964,13 +12118,16 @@ function WaterfallChart({
|
|
|
11964
12118
|
steps,
|
|
11965
12119
|
height = 240,
|
|
11966
12120
|
width,
|
|
11967
|
-
formatValue
|
|
12121
|
+
formatValue: formatValueProp,
|
|
11968
12122
|
yAxisLabel,
|
|
11969
12123
|
className,
|
|
11970
12124
|
emptyLabel,
|
|
11971
12125
|
radius = 3,
|
|
11972
12126
|
connectors = true
|
|
11973
12127
|
}) {
|
|
12128
|
+
const strings = useShellStrings().charts;
|
|
12129
|
+
const locale = useShellLocale();
|
|
12130
|
+
const formatValue = formatValueProp ?? ((v) => formatPlain(v, locale));
|
|
11974
12131
|
let running = 0;
|
|
11975
12132
|
const bars = steps.map((step) => {
|
|
11976
12133
|
if (step.total) {
|
|
@@ -11994,7 +12151,7 @@ function WaterfallChart({
|
|
|
11994
12151
|
className,
|
|
11995
12152
|
emptyLabel,
|
|
11996
12153
|
bandPadding: 0.36,
|
|
11997
|
-
ariaLabel:
|
|
12154
|
+
ariaLabel: strings.waterfall(steps.length, formatValue(bars[0]?.from ?? 0), formatValue(running)),
|
|
11998
12155
|
tooltip: (index) => {
|
|
11999
12156
|
const bar = bars[index];
|
|
12000
12157
|
const tone = bar?.total ? STATUS_VARS.neutral : bar.value >= 0 ? STATUS_VARS.good : STATUS_VARS.critical;
|
|
@@ -12006,12 +12163,12 @@ function WaterfallChart({
|
|
|
12006
12163
|
{
|
|
12007
12164
|
key: "step",
|
|
12008
12165
|
color: tone,
|
|
12009
|
-
label: bar?.total ?
|
|
12166
|
+
label: bar?.total ? strings.balance : bar.value >= 0 ? strings.increase : strings.decrease,
|
|
12010
12167
|
// The sign is written out: colour alone does not survive
|
|
12011
12168
|
// greyscale, and polarity is the whole point of this chart.
|
|
12012
12169
|
value: bar?.total ? formatValue(bar.to) : `${bar.value >= 0 ? "+" : "\u2212"}${formatValue(Math.abs(bar.value))}`
|
|
12013
12170
|
},
|
|
12014
|
-
...bar?.total ? [] : [{ key: "running", label:
|
|
12171
|
+
...bar?.total ? [] : [{ key: "running", label: strings.runningTotal, color: STATUS_VARS.neutral, value: formatValue(bar.to) }]
|
|
12015
12172
|
]
|
|
12016
12173
|
}
|
|
12017
12174
|
);
|
|
@@ -12065,13 +12222,19 @@ function HistogramChart({
|
|
|
12065
12222
|
width,
|
|
12066
12223
|
color,
|
|
12067
12224
|
tone,
|
|
12068
|
-
formatBound
|
|
12069
|
-
formatCount
|
|
12070
|
-
yAxisLabel
|
|
12071
|
-
label
|
|
12225
|
+
formatBound: formatBoundProp,
|
|
12226
|
+
formatCount: formatCountProp,
|
|
12227
|
+
yAxisLabel: yAxisLabelProp,
|
|
12228
|
+
label: labelProp,
|
|
12072
12229
|
className,
|
|
12073
12230
|
emptyLabel
|
|
12074
12231
|
}) {
|
|
12232
|
+
const strings = useShellStrings().charts;
|
|
12233
|
+
const locale = useShellLocale();
|
|
12234
|
+
const formatBound = formatBoundProp ?? ((v) => Number.isInteger(v) ? formatPlain(v, locale) : formatFixed(v, 1, locale));
|
|
12235
|
+
const formatCount = formatCountProp ?? ((v) => formatPlain(v, locale));
|
|
12236
|
+
const yAxisLabel = yAxisLabelProp ?? strings.countAxis;
|
|
12237
|
+
const label = labelProp ?? strings.distribution;
|
|
12075
12238
|
const computed = precomputed ?? binValues(values ?? [], bins);
|
|
12076
12239
|
const colour = resolveSeriesColor(0, color, tone);
|
|
12077
12240
|
const labels = computed.map((b) => formatBound(b.from));
|
|
@@ -12089,12 +12252,12 @@ function HistogramChart({
|
|
|
12089
12252
|
yAxisLabel,
|
|
12090
12253
|
className,
|
|
12091
12254
|
emptyLabel,
|
|
12092
|
-
ariaLabel:
|
|
12255
|
+
ariaLabel: strings.histogram(label, computed.length, (values ?? []).length),
|
|
12093
12256
|
tooltip: (index) => /* @__PURE__ */ jsx(
|
|
12094
12257
|
ChartTooltip,
|
|
12095
12258
|
{
|
|
12096
12259
|
title: `${formatBound(computed[index].from)} \u2013 ${formatBound(computed[index].to)}`,
|
|
12097
|
-
rows: [{ key: "count", label:
|
|
12260
|
+
rows: [{ key: "count", label: strings.observations, color: colour, value: formatCount(computed[index].count) }]
|
|
12098
12261
|
}
|
|
12099
12262
|
),
|
|
12100
12263
|
children: ({ x, y, bottom, active }) => /* @__PURE__ */ jsx("g", { children: computed.map((bin, i) => /* @__PURE__ */ jsx(
|
|
@@ -12118,12 +12281,16 @@ function BoxPlotChart({
|
|
|
12118
12281
|
width,
|
|
12119
12282
|
color,
|
|
12120
12283
|
tone,
|
|
12121
|
-
formatValue
|
|
12284
|
+
formatValue: formatValueProp,
|
|
12122
12285
|
yAxisLabel,
|
|
12123
|
-
label
|
|
12286
|
+
label: labelProp,
|
|
12124
12287
|
className,
|
|
12125
12288
|
emptyLabel
|
|
12126
12289
|
}) {
|
|
12290
|
+
const strings = useShellStrings().charts;
|
|
12291
|
+
const locale = useShellLocale();
|
|
12292
|
+
const formatValue = formatValueProp ?? ((v) => formatPlain(v, locale));
|
|
12293
|
+
const label = labelProp ?? strings.distribution;
|
|
12127
12294
|
const colour = resolveSeriesColor(0, color, tone);
|
|
12128
12295
|
const values = boxes.flatMap((b) => [b.min, b.max, ...b.outliers ?? []]).filter(Number.isFinite);
|
|
12129
12296
|
return /* @__PURE__ */ jsx(
|
|
@@ -12138,7 +12305,7 @@ function BoxPlotChart({
|
|
|
12138
12305
|
yAxisLabel,
|
|
12139
12306
|
className,
|
|
12140
12307
|
emptyLabel,
|
|
12141
|
-
ariaLabel:
|
|
12308
|
+
ariaLabel: strings.fiveNumber(label, boxes.length),
|
|
12142
12309
|
tooltip: (index) => {
|
|
12143
12310
|
const b = boxes[index];
|
|
12144
12311
|
return /* @__PURE__ */ jsx(
|
|
@@ -12146,14 +12313,14 @@ function BoxPlotChart({
|
|
|
12146
12313
|
{
|
|
12147
12314
|
title: b.label,
|
|
12148
12315
|
rows: [
|
|
12149
|
-
{ key: "max", label:
|
|
12150
|
-
{ key: "q3", label:
|
|
12151
|
-
{ key: "median", label:
|
|
12152
|
-
{ key: "q1", label:
|
|
12153
|
-
{ key: "min", label:
|
|
12316
|
+
{ key: "max", label: strings.maximum, color: colour, value: formatValue(b.max) },
|
|
12317
|
+
{ key: "q3", label: strings.q3, color: colour, value: formatValue(b.q3) },
|
|
12318
|
+
{ key: "median", label: strings.median, color: colour, value: formatValue(b.median) },
|
|
12319
|
+
{ key: "q1", label: strings.q1, color: colour, value: formatValue(b.q1) },
|
|
12320
|
+
{ key: "min", label: strings.minimum, color: colour, value: formatValue(b.min) }
|
|
12154
12321
|
],
|
|
12155
12322
|
emphasisKey: "median",
|
|
12156
|
-
footnote: b.outliers?.length ?
|
|
12323
|
+
footnote: b.outliers?.length ? strings.outliers(b.outliers.length) : void 0
|
|
12157
12324
|
}
|
|
12158
12325
|
);
|
|
12159
12326
|
},
|
|
@@ -12194,12 +12361,16 @@ function CandlestickChart({
|
|
|
12194
12361
|
width,
|
|
12195
12362
|
// Not `String(v)`: the axis domain is padded off the data, so its ticks are
|
|
12196
12363
|
// almost never integers, and a raw float prints as 102.72999999999999.
|
|
12197
|
-
formatValue
|
|
12364
|
+
formatValue: formatValueProp,
|
|
12198
12365
|
yAxisLabel,
|
|
12199
|
-
label
|
|
12366
|
+
label: labelProp,
|
|
12200
12367
|
className,
|
|
12201
12368
|
emptyLabel
|
|
12202
12369
|
}) {
|
|
12370
|
+
const strings = useShellStrings().charts;
|
|
12371
|
+
const locale = useShellLocale();
|
|
12372
|
+
const formatValue = formatValueProp ?? ((v) => Number.isInteger(v) ? formatPlain(v, locale) : formatFixed(v, 2, locale));
|
|
12373
|
+
const label = labelProp ?? strings.price;
|
|
12203
12374
|
const values = candles.flatMap((c) => [c.low, c.high]).filter(Number.isFinite);
|
|
12204
12375
|
const lo = Math.min(...values);
|
|
12205
12376
|
const hi = Math.max(...values);
|
|
@@ -12218,7 +12389,7 @@ function CandlestickChart({
|
|
|
12218
12389
|
yAxisLabel,
|
|
12219
12390
|
className,
|
|
12220
12391
|
emptyLabel,
|
|
12221
|
-
ariaLabel:
|
|
12392
|
+
ariaLabel: strings.ohlc(label, candles.length),
|
|
12222
12393
|
tooltip: (index) => {
|
|
12223
12394
|
const c = candles[index];
|
|
12224
12395
|
const rose = c.close >= c.open;
|
|
@@ -12228,13 +12399,13 @@ function CandlestickChart({
|
|
|
12228
12399
|
{
|
|
12229
12400
|
title: c.label,
|
|
12230
12401
|
rows: [
|
|
12231
|
-
{ key: "open", label:
|
|
12232
|
-
{ key: "high", label:
|
|
12233
|
-
{ key: "low", label:
|
|
12234
|
-
{ key: "close", label:
|
|
12402
|
+
{ key: "open", label: strings.open, color: tone, value: formatValue(c.open) },
|
|
12403
|
+
{ key: "high", label: strings.high, color: tone, value: formatValue(c.high) },
|
|
12404
|
+
{ key: "low", label: strings.low, color: tone, value: formatValue(c.low) },
|
|
12405
|
+
{ key: "close", label: strings.close, color: tone, value: formatValue(c.close) }
|
|
12235
12406
|
],
|
|
12236
12407
|
emphasisKey: "close",
|
|
12237
|
-
footnote: rose ?
|
|
12408
|
+
footnote: rose ? strings.closedAbove : strings.closedBelow
|
|
12238
12409
|
}
|
|
12239
12410
|
);
|
|
12240
12411
|
},
|
|
@@ -12278,13 +12449,18 @@ function HeatmapChart({
|
|
|
12278
12449
|
width: widthProp,
|
|
12279
12450
|
color,
|
|
12280
12451
|
max,
|
|
12281
|
-
formatValue
|
|
12282
|
-
label
|
|
12452
|
+
formatValue: formatValueProp,
|
|
12453
|
+
label: labelProp,
|
|
12283
12454
|
className,
|
|
12284
|
-
emptyLabel
|
|
12455
|
+
emptyLabel: emptyLabelProp,
|
|
12285
12456
|
cellGap = 2,
|
|
12286
12457
|
cellRadius = 2
|
|
12287
12458
|
}) {
|
|
12459
|
+
const strings = useShellStrings().charts;
|
|
12460
|
+
const locale = useShellLocale();
|
|
12461
|
+
const formatValue = formatValueProp ?? ((v) => formatPlain(v, locale));
|
|
12462
|
+
const label = labelProp ?? strings.intensity;
|
|
12463
|
+
const emptyLabel = emptyLabelProp ?? strings.noActivity;
|
|
12288
12464
|
const host = useRef(null);
|
|
12289
12465
|
const measured = usePlotWidth(host);
|
|
12290
12466
|
const width = widthProp ?? measured;
|
|
@@ -12331,9 +12507,9 @@ function HeatmapChart({
|
|
|
12331
12507
|
height: totalHeight,
|
|
12332
12508
|
viewBox: `0 0 ${width} ${totalHeight}`,
|
|
12333
12509
|
role: "img",
|
|
12334
|
-
"aria-label":
|
|
12510
|
+
"aria-label": strings.heatmap(label, rows.length, columns.length),
|
|
12335
12511
|
tabIndex: 0,
|
|
12336
|
-
className: "focus
|
|
12512
|
+
className: "rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-deep)]",
|
|
12337
12513
|
onMouseLeave: () => setHover(null),
|
|
12338
12514
|
onBlur: () => setHover(null),
|
|
12339
12515
|
onKeyDown: onKey,
|
|
@@ -12398,11 +12574,15 @@ function RadarChart({
|
|
|
12398
12574
|
mode = "area",
|
|
12399
12575
|
grid = "polygon",
|
|
12400
12576
|
rings = 4,
|
|
12401
|
-
formatValue
|
|
12577
|
+
formatValue: formatValueProp,
|
|
12402
12578
|
animate = true,
|
|
12403
12579
|
className,
|
|
12404
|
-
emptyLabel
|
|
12580
|
+
emptyLabel: emptyLabelProp
|
|
12405
12581
|
}) {
|
|
12582
|
+
const strings = useShellStrings().charts;
|
|
12583
|
+
const locale = useShellLocale();
|
|
12584
|
+
const formatValue = formatValueProp ?? ((v) => formatPlain(v, locale));
|
|
12585
|
+
const emptyLabel = emptyLabelProp ?? strings.nothingToCompare;
|
|
12406
12586
|
const titleId = useId();
|
|
12407
12587
|
const [hover, setHover] = useState(null);
|
|
12408
12588
|
const { highlighted } = useHighlight();
|
|
@@ -12437,7 +12617,7 @@ function RadarChart({
|
|
|
12437
12617
|
"aria-labelledby": titleId,
|
|
12438
12618
|
onMouseLeave: () => setHover(null),
|
|
12439
12619
|
children: [
|
|
12440
|
-
/* @__PURE__ */ jsx("title", { id: titleId, children:
|
|
12620
|
+
/* @__PURE__ */ jsx("title", { id: titleId, children: strings.acrossMeasures(drawn.map((s) => s.label), axes.length) }),
|
|
12441
12621
|
Array.from({ length: rings }, (_, r) => {
|
|
12442
12622
|
const rr = radius * (r + 1) / rings;
|
|
12443
12623
|
return grid === "circle" ? /* @__PURE__ */ jsx("circle", { cx, cy, r: rr, fill: "none", stroke: CHART_INK.grid, strokeWidth: 1 }, r) : /* @__PURE__ */ jsx("path", { d: ring(polygonPoints(cx, cy, rr, axes.length)), fill: "none", stroke: CHART_INK.grid, strokeWidth: 1 }, r);
|
|
@@ -12500,8 +12680,8 @@ function RadarChart({
|
|
|
12500
12680
|
/* @__PURE__ */ jsx(
|
|
12501
12681
|
AccessibleTable,
|
|
12502
12682
|
{
|
|
12503
|
-
caption:
|
|
12504
|
-
head: [
|
|
12683
|
+
caption: strings.acrossMeasures(drawn.map((s) => s.label), axes.length),
|
|
12684
|
+
head: [strings.tableSeries, ...axes.map((axis) => axis.label)],
|
|
12505
12685
|
rows: drawn.map((s) => [s.label, ...axes.map((_, i) => formatValue(s.values[i] ?? 0))])
|
|
12506
12686
|
}
|
|
12507
12687
|
)
|
|
@@ -12514,15 +12694,20 @@ function PieChart({
|
|
|
12514
12694
|
innerRadius,
|
|
12515
12695
|
padAngle = 0.012,
|
|
12516
12696
|
maxSegments = 6,
|
|
12517
|
-
otherLabel
|
|
12518
|
-
formatValue
|
|
12697
|
+
otherLabel: otherLabelProp,
|
|
12698
|
+
formatValue: formatValueProp,
|
|
12519
12699
|
centerLabel,
|
|
12520
12700
|
animate = true,
|
|
12521
12701
|
labels = "none",
|
|
12522
12702
|
labelMinShare = 0.04,
|
|
12523
12703
|
className,
|
|
12524
|
-
emptyLabel
|
|
12704
|
+
emptyLabel: emptyLabelProp
|
|
12525
12705
|
}) {
|
|
12706
|
+
const strings = useShellStrings().charts;
|
|
12707
|
+
const locale = useShellLocale();
|
|
12708
|
+
const formatValue = formatValueProp ?? ((v) => formatPlain(v, locale));
|
|
12709
|
+
const otherLabel = otherLabelProp ?? strings.other;
|
|
12710
|
+
const emptyLabel = emptyLabelProp ?? strings.nothingToBreakDown;
|
|
12526
12711
|
const titleId = useId();
|
|
12527
12712
|
const [hover, setHover] = useState(null);
|
|
12528
12713
|
const { highlighted } = useHighlight();
|
|
@@ -12586,7 +12771,7 @@ function PieChart({
|
|
|
12586
12771
|
"aria-labelledby": titleId,
|
|
12587
12772
|
onMouseLeave: () => setHover(null),
|
|
12588
12773
|
children: [
|
|
12589
|
-
/* @__PURE__ */ jsx("title", { id: titleId, children:
|
|
12774
|
+
/* @__PURE__ */ jsx("title", { id: titleId, children: strings.breakdown(formatValue(total), shown.length) }),
|
|
12590
12775
|
shown.map((segment, i) => {
|
|
12591
12776
|
const colour = resolveSeriesColor(i, segment.color, segment.tone);
|
|
12592
12777
|
const start = variant === "rose" ? angle(i) : cursor;
|
|
@@ -12643,7 +12828,7 @@ function PieChart({
|
|
|
12643
12828
|
fill: CHART_INK.label,
|
|
12644
12829
|
textAnchor: entry.right ? "end" : "start",
|
|
12645
12830
|
style: { fontVariantNumeric: "tabular-nums" },
|
|
12646
|
-
children:
|
|
12831
|
+
children: formatPercent(entry.share * 100, 1, locale)
|
|
12647
12832
|
}
|
|
12648
12833
|
)
|
|
12649
12834
|
] }, `lbl-${entry.key}`);
|
|
@@ -12657,18 +12842,15 @@ function PieChart({
|
|
|
12657
12842
|
{
|
|
12658
12843
|
title: hoveredSegment.label,
|
|
12659
12844
|
rows: [
|
|
12660
|
-
{ key: "value", label:
|
|
12661
|
-
{ key: "share", label:
|
|
12845
|
+
{ key: "value", label: strings.value, color: resolveSeriesColor(hover, hoveredSegment.color, hoveredSegment.tone), value: formatValue(hoveredSegment.value) },
|
|
12846
|
+
{ key: "share", label: strings.share, color: CHART_INK.muted, value: formatPercent(hoveredSegment.value / total * 100, 1, locale) }
|
|
12662
12847
|
]
|
|
12663
12848
|
}
|
|
12664
12849
|
) }),
|
|
12665
12850
|
/* @__PURE__ */ jsx("ul", { className: "m-0 mt-3 grid gap-1 p-0", style: { gridTemplateColumns: "repeat(auto-fit,minmax(140px,1fr))" }, children: shown.map((segment, i) => /* @__PURE__ */ jsxs("li", { className: "flex list-none items-center gap-2 text-xs text-gray-600", children: [
|
|
12666
12851
|
/* @__PURE__ */ jsx("span", { className: "h-2.5 w-2.5 shrink-0 rounded-sm", style: { backgroundColor: resolveSeriesColor(i, segment.color, segment.tone) } }),
|
|
12667
12852
|
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: segment.label }),
|
|
12668
|
-
/* @__PURE__ */
|
|
12669
|
-
(segment.value / total * 100).toFixed(1),
|
|
12670
|
-
"%"
|
|
12671
|
-
] })
|
|
12853
|
+
/* @__PURE__ */ jsx("span", { className: "tabular-nums text-gray-800", children: formatPercent(segment.value / total * 100, 1, locale) })
|
|
12672
12854
|
] }, segment.key)) })
|
|
12673
12855
|
] });
|
|
12674
12856
|
}
|
|
@@ -12678,12 +12860,16 @@ function RadialBarChart({
|
|
|
12678
12860
|
variant = "track",
|
|
12679
12861
|
size = 300,
|
|
12680
12862
|
max,
|
|
12681
|
-
formatValue
|
|
12863
|
+
formatValue: formatValueProp,
|
|
12682
12864
|
animate = true,
|
|
12683
12865
|
className,
|
|
12684
|
-
emptyLabel
|
|
12866
|
+
emptyLabel: emptyLabelProp,
|
|
12685
12867
|
trackGap = 6
|
|
12686
12868
|
}) {
|
|
12869
|
+
const strings = useShellStrings().charts;
|
|
12870
|
+
const locale = useShellLocale();
|
|
12871
|
+
const formatValue = formatValueProp ?? ((v) => formatPlain(v, locale));
|
|
12872
|
+
const emptyLabel = emptyLabelProp ?? strings.nothingToPlot;
|
|
12687
12873
|
const titleId = useId();
|
|
12688
12874
|
const [hover, setHover] = useState(null);
|
|
12689
12875
|
const { highlighted } = useHighlight();
|
|
@@ -12714,7 +12900,7 @@ function RadialBarChart({
|
|
|
12714
12900
|
"aria-labelledby": titleId,
|
|
12715
12901
|
onMouseLeave: () => setHover(null),
|
|
12716
12902
|
children: [
|
|
12717
|
-
/* @__PURE__ */ jsx("title", { id: titleId, children:
|
|
12903
|
+
/* @__PURE__ */ jsx("title", { id: titleId, children: variant === "track" ? strings.radialTrack(drawnRows.length) : strings.radialCycle(drawnRows.length) }),
|
|
12718
12904
|
drawnRows.map((row, i) => {
|
|
12719
12905
|
const colour = resolveSeriesColor(i, row.color, row.tone);
|
|
12720
12906
|
const share = Math.max(0, Math.min(1, row.value / top));
|
|
@@ -12754,7 +12940,7 @@ function RadialBarChart({
|
|
|
12754
12940
|
ChartTooltip,
|
|
12755
12941
|
{
|
|
12756
12942
|
title: hoveredRow.label,
|
|
12757
|
-
rows: [{ key: "value", label:
|
|
12943
|
+
rows: [{ key: "value", label: strings.value, color: resolveSeriesColor(hover, hoveredRow.color, hoveredRow.tone), value: formatValue(hoveredRow.value) }]
|
|
12758
12944
|
}
|
|
12759
12945
|
) }),
|
|
12760
12946
|
/* @__PURE__ */ jsx("ul", { className: "m-0 mt-3 grid gap-1 p-0", style: { gridTemplateColumns: "repeat(auto-fit,minmax(150px,1fr))" }, children: rows.map((row, i) => /* @__PURE__ */ jsxs("li", { className: "flex list-none items-center gap-2 text-xs text-gray-600", children: [
|
|
@@ -12770,11 +12956,15 @@ function FunnelChart({
|
|
|
12770
12956
|
height,
|
|
12771
12957
|
width = 560,
|
|
12772
12958
|
gap = 4,
|
|
12773
|
-
formatValue
|
|
12959
|
+
formatValue: formatValueProp,
|
|
12774
12960
|
color,
|
|
12775
12961
|
className,
|
|
12776
|
-
emptyLabel
|
|
12962
|
+
emptyLabel: emptyLabelProp
|
|
12777
12963
|
}) {
|
|
12964
|
+
const strings = useShellStrings().charts;
|
|
12965
|
+
const locale = useShellLocale();
|
|
12966
|
+
const formatValue = formatValueProp ?? ((v) => formatPlain(v, locale));
|
|
12967
|
+
const emptyLabel = emptyLabelProp ?? strings.noStages;
|
|
12778
12968
|
const titleId = useId();
|
|
12779
12969
|
const [hover, setHover] = useState(null);
|
|
12780
12970
|
const { highlighted } = useHighlight();
|
|
@@ -12807,7 +12997,7 @@ function FunnelChart({
|
|
|
12807
12997
|
"aria-labelledby": titleId,
|
|
12808
12998
|
onMouseLeave: () => setHover(null),
|
|
12809
12999
|
children: [
|
|
12810
|
-
/* @__PURE__ */ jsx("title", { id: titleId, children:
|
|
13000
|
+
/* @__PURE__ */ jsx("title", { id: titleId, children: strings.funnel(stages.length, formatValue(stages[0].value), formatValue(stages[stages.length - 1].value)) }),
|
|
12811
13001
|
stages.map((stage, i) => {
|
|
12812
13002
|
const y0 = i * total / stages.length + gap / 2;
|
|
12813
13003
|
const y1 = (i + 1) * total / stages.length - gap / 2;
|
|
@@ -12826,12 +13016,9 @@ function FunnelChart({
|
|
|
12826
13016
|
/* @__PURE__ */ jsx("text", { x: labelWidth - 14, y: (y0 + y1) / 2 - 2, textAnchor: "end", fontSize: 12, fill: CHART_INK.label, children: stage.label }),
|
|
12827
13017
|
/* @__PURE__ */ jsxs("text", { x: labelWidth - 14, y: (y0 + y1) / 2 + 14, textAnchor: "end", fontSize: 11, fill: CHART_INK.muted, style: { fontVariantNumeric: "tabular-nums" }, children: [
|
|
12828
13018
|
formatValue(stage.value),
|
|
12829
|
-
dropped != null ? ` \xB7 \u2212${dropped
|
|
13019
|
+
dropped != null ? ` \xB7 \u2212${formatPercent(dropped, 1, locale)}` : ""
|
|
12830
13020
|
] }),
|
|
12831
|
-
/* @__PURE__ */
|
|
12832
|
-
(stage.value / (stages[0].value || 1) * 100).toFixed(0),
|
|
12833
|
-
"%"
|
|
12834
|
-
] })
|
|
13021
|
+
/* @__PURE__ */ jsx("text", { x: cx, y: (y0 + y1) / 2 + 4, textAnchor: "middle", fontSize: 11.5, fontWeight: 600, fill: bandInk(i), style: { fontVariantNumeric: "tabular-nums" }, children: formatPercent(stage.value / (stages[0].value || 1) * 100, 0, locale) })
|
|
12835
13022
|
] }, stage.key);
|
|
12836
13023
|
})
|
|
12837
13024
|
]
|
|
@@ -12842,9 +13029,9 @@ function FunnelChart({
|
|
|
12842
13029
|
{
|
|
12843
13030
|
title: hoveredStage.label,
|
|
12844
13031
|
rows: [
|
|
12845
|
-
{ key: "value", label:
|
|
12846
|
-
{ key: "share", label:
|
|
12847
|
-
...hover > 0 && stages[hover - 1].value > 0 ? [{ key: "drop", label:
|
|
13032
|
+
{ key: "value", label: strings.count, color: shade(hover), value: formatValue(hoveredStage.value) },
|
|
13033
|
+
{ key: "share", label: strings.ofFirstStage, color: CHART_INK.muted, value: formatPercent(hoveredStage.value / (stages[0].value || 1) * 100, 0, locale) },
|
|
13034
|
+
...hover > 0 && stages[hover - 1].value > 0 ? [{ key: "drop", label: strings.droppedHere, color: STATUS_VARS.critical, value: `\u2212${formatPercent((1 - hoveredStage.value / stages[hover - 1].value) * 100, 1, locale)}` }] : []
|
|
12848
13035
|
]
|
|
12849
13036
|
}
|
|
12850
13037
|
) })
|
|
@@ -12857,11 +13044,15 @@ function TreemapChart({
|
|
|
12857
13044
|
width: widthProp,
|
|
12858
13045
|
gap = 2,
|
|
12859
13046
|
radius = 3,
|
|
12860
|
-
formatValue
|
|
13047
|
+
formatValue: formatValueProp,
|
|
12861
13048
|
color,
|
|
12862
13049
|
className,
|
|
12863
|
-
emptyLabel
|
|
13050
|
+
emptyLabel: emptyLabelProp
|
|
12864
13051
|
}) {
|
|
13052
|
+
const strings = useShellStrings().charts;
|
|
13053
|
+
const locale = useShellLocale();
|
|
13054
|
+
const formatValue = formatValueProp ?? ((v) => formatPlain(v, locale));
|
|
13055
|
+
const emptyLabel = emptyLabelProp ?? strings.nothingToBreakDown;
|
|
12865
13056
|
const host = useRef(null);
|
|
12866
13057
|
const measured = usePlotWidth(host);
|
|
12867
13058
|
const width = widthProp ?? measured;
|
|
@@ -12886,7 +13077,7 @@ function TreemapChart({
|
|
|
12886
13077
|
height,
|
|
12887
13078
|
viewBox: `0 0 ${width} ${height}`,
|
|
12888
13079
|
role: "img",
|
|
12889
|
-
"aria-label":
|
|
13080
|
+
"aria-label": strings.treemap(items.length),
|
|
12890
13081
|
onMouseLeave: () => setHover(null),
|
|
12891
13082
|
children: tiles.map((tile) => {
|
|
12892
13083
|
const w = Math.max(0, tile.width - gap);
|
|
@@ -12915,14 +13106,14 @@ function TreemapChart({
|
|
|
12915
13106
|
ChartTooltip,
|
|
12916
13107
|
{
|
|
12917
13108
|
title: hoveredTile.label,
|
|
12918
|
-
rows: [{ key: "value", label:
|
|
13109
|
+
rows: [{ key: "value", label: strings.value, color: shade(hoveredTile.value), value: formatValue(hoveredTile.value) }]
|
|
12919
13110
|
}
|
|
12920
13111
|
) }),
|
|
12921
13112
|
/* @__PURE__ */ jsx(
|
|
12922
13113
|
AccessibleTable,
|
|
12923
13114
|
{
|
|
12924
|
-
caption:
|
|
12925
|
-
head: [
|
|
13115
|
+
caption: strings.treemap(items.length),
|
|
13116
|
+
head: [strings.tableItem, strings.value],
|
|
12926
13117
|
rows: tiles.map((tile) => [tile.label, formatValue(tile.value)])
|
|
12927
13118
|
}
|
|
12928
13119
|
)
|
|
@@ -12963,11 +13154,15 @@ function SunburstChart({
|
|
|
12963
13154
|
size = 320,
|
|
12964
13155
|
innerRadius = 44,
|
|
12965
13156
|
ringGap = 2,
|
|
12966
|
-
formatValue
|
|
13157
|
+
formatValue: formatValueProp,
|
|
12967
13158
|
centerLabel,
|
|
12968
13159
|
className,
|
|
12969
|
-
emptyLabel
|
|
13160
|
+
emptyLabel: emptyLabelProp
|
|
12970
13161
|
}) {
|
|
13162
|
+
const strings = useShellStrings().charts;
|
|
13163
|
+
const locale = useShellLocale();
|
|
13164
|
+
const formatValue = formatValueProp ?? ((v) => formatPlain(v, locale));
|
|
13165
|
+
const emptyLabel = emptyLabelProp ?? strings.nothingToBreakDown;
|
|
12971
13166
|
const [hover, setHover] = useState(null);
|
|
12972
13167
|
const { highlighted } = useHighlight();
|
|
12973
13168
|
const wedges = [];
|
|
@@ -12986,7 +13181,7 @@ function SunburstChart({
|
|
|
12986
13181
|
return true;
|
|
12987
13182
|
};
|
|
12988
13183
|
const hovered = hover ? wedges.find((w) => w.id === hover) : void 0;
|
|
12989
|
-
const share = (w) =>
|
|
13184
|
+
const share = (w) => formatPercent(w.value / total * 100, 1, locale);
|
|
12990
13185
|
return /* @__PURE__ */ jsxs("div", { className: `relative ${className ?? ""}`, children: [
|
|
12991
13186
|
/* @__PURE__ */ jsxs(
|
|
12992
13187
|
"svg",
|
|
@@ -12995,7 +13190,7 @@ function SunburstChart({
|
|
|
12995
13190
|
height: size,
|
|
12996
13191
|
viewBox: `0 0 ${size} ${size}`,
|
|
12997
13192
|
role: "img",
|
|
12998
|
-
"aria-label":
|
|
13193
|
+
"aria-label": strings.sunburst(formatValue(total), depth),
|
|
12999
13194
|
onMouseLeave: () => setHover(null),
|
|
13000
13195
|
children: [
|
|
13001
13196
|
wedges.map((w) => /* @__PURE__ */ jsx(
|
|
@@ -13019,16 +13214,16 @@ function SunburstChart({
|
|
|
13019
13214
|
{
|
|
13020
13215
|
title: hovered.label,
|
|
13021
13216
|
rows: [
|
|
13022
|
-
{ key: "value", label:
|
|
13023
|
-
{ key: "share", label:
|
|
13217
|
+
{ key: "value", label: strings.value, color: shade(hovered), value: formatValue(hovered.value) },
|
|
13218
|
+
{ key: "share", label: strings.share, color: CHART_INK.muted, value: share(hovered) }
|
|
13024
13219
|
]
|
|
13025
13220
|
}
|
|
13026
13221
|
) }),
|
|
13027
13222
|
/* @__PURE__ */ jsx(
|
|
13028
13223
|
AccessibleTable,
|
|
13029
13224
|
{
|
|
13030
|
-
caption:
|
|
13031
|
-
head: [
|
|
13225
|
+
caption: strings.sunburst(formatValue(total), depth),
|
|
13226
|
+
head: [strings.tableLevel, strings.tableItem, strings.value, strings.share],
|
|
13032
13227
|
rows: wedges.map((w) => [w.depth + 1, w.label, formatValue(w.value), share(w)])
|
|
13033
13228
|
}
|
|
13034
13229
|
)
|
|
@@ -13041,10 +13236,14 @@ function SankeyChart({
|
|
|
13041
13236
|
width: widthProp,
|
|
13042
13237
|
nodeWidth = 14,
|
|
13043
13238
|
nodePadding = 12,
|
|
13044
|
-
formatValue
|
|
13239
|
+
formatValue: formatValueProp,
|
|
13045
13240
|
className,
|
|
13046
|
-
emptyLabel
|
|
13241
|
+
emptyLabel: emptyLabelProp
|
|
13047
13242
|
}) {
|
|
13243
|
+
const strings = useShellStrings().charts;
|
|
13244
|
+
const locale = useShellLocale();
|
|
13245
|
+
const formatValue = formatValueProp ?? ((v) => formatPlain(v, locale));
|
|
13246
|
+
const emptyLabel = emptyLabelProp ?? strings.noFlows;
|
|
13048
13247
|
const host = useRef(null);
|
|
13049
13248
|
const measured = usePlotWidth(host);
|
|
13050
13249
|
const width = widthProp ?? measured;
|
|
@@ -13102,7 +13301,7 @@ function SankeyChart({
|
|
|
13102
13301
|
height,
|
|
13103
13302
|
viewBox: `0 0 ${width} ${height}`,
|
|
13104
13303
|
role: "img",
|
|
13105
|
-
"aria-label":
|
|
13304
|
+
"aria-label": strings.sankey(nodes.length, links.length),
|
|
13106
13305
|
onMouseLeave: () => setHover(null),
|
|
13107
13306
|
children: [
|
|
13108
13307
|
links.map((link, i) => {
|
|
@@ -13161,21 +13360,21 @@ function SankeyChart({
|
|
|
13161
13360
|
ChartTooltip,
|
|
13162
13361
|
{
|
|
13163
13362
|
title: `${hoveredLink.from} \u2192 ${hoveredLink.to}`,
|
|
13164
|
-
rows: [{ key: "value", label:
|
|
13363
|
+
rows: [{ key: "value", label: strings.flow, color: resolveSeriesColor(placed.get(hoveredLink.from)?.index ?? 0, hoveredLink.color), value: formatValue(hoveredLink.value) }]
|
|
13165
13364
|
}
|
|
13166
13365
|
) }),
|
|
13167
13366
|
hoveredNode && /* @__PURE__ */ jsx("div", { className: "absolute top-2 left-2 z-10", children: /* @__PURE__ */ jsx(
|
|
13168
13367
|
ChartTooltip,
|
|
13169
13368
|
{
|
|
13170
13369
|
title: hoveredNode.label,
|
|
13171
|
-
rows: [{ key: "value", label:
|
|
13370
|
+
rows: [{ key: "value", label: strings.throughput, color: resolveSeriesColor(placed.get(hoveredNode.key)?.index ?? 0, hoveredNode.color, hoveredNode.tone), value: formatValue(throughput.get(hoveredNode.key) ?? 0) }]
|
|
13172
13371
|
}
|
|
13173
13372
|
) }),
|
|
13174
13373
|
/* @__PURE__ */ jsx(
|
|
13175
13374
|
AccessibleTable,
|
|
13176
13375
|
{
|
|
13177
|
-
caption:
|
|
13178
|
-
head: [
|
|
13376
|
+
caption: strings.sankey(nodes.length, links.length),
|
|
13377
|
+
head: [strings.tableFrom, strings.tableTo, strings.value],
|
|
13179
13378
|
rows: links.map((link) => [link.from, link.to, formatValue(link.value)])
|
|
13180
13379
|
}
|
|
13181
13380
|
)
|
|
@@ -13188,10 +13387,14 @@ function ChordChart({
|
|
|
13188
13387
|
maxNodes = 8,
|
|
13189
13388
|
padAngle = 0.04,
|
|
13190
13389
|
arcWidth = 12,
|
|
13191
|
-
formatValue
|
|
13390
|
+
formatValue: formatValueProp,
|
|
13192
13391
|
className,
|
|
13193
|
-
emptyLabel
|
|
13392
|
+
emptyLabel: emptyLabelProp
|
|
13194
13393
|
}) {
|
|
13394
|
+
const strings = useShellStrings().charts;
|
|
13395
|
+
const locale = useShellLocale();
|
|
13396
|
+
const formatValue = formatValueProp ?? ((v) => formatPlain(v, locale));
|
|
13397
|
+
const emptyLabel = emptyLabelProp ?? strings.noFlows;
|
|
13195
13398
|
const [hover, setHover] = useState(null);
|
|
13196
13399
|
const { highlighted } = useHighlight();
|
|
13197
13400
|
const cell = (row, col) => {
|
|
@@ -13252,7 +13455,7 @@ function ChordChart({
|
|
|
13252
13455
|
height: size,
|
|
13253
13456
|
viewBox: `0 0 ${size} ${size}`,
|
|
13254
13457
|
role: "img",
|
|
13255
|
-
"aria-label":
|
|
13458
|
+
"aria-label": strings.chord(order.length),
|
|
13256
13459
|
onMouseLeave: () => setHover(null),
|
|
13257
13460
|
children: [
|
|
13258
13461
|
ribbons.map((ribbon, i) => {
|
|
@@ -13308,21 +13511,21 @@ function ChordChart({
|
|
|
13308
13511
|
ChartTooltip,
|
|
13309
13512
|
{
|
|
13310
13513
|
title: labels[hoveredArc],
|
|
13311
|
-
rows: [{ key: "total", label:
|
|
13514
|
+
rows: [{ key: "total", label: strings.totalFlow, color: resolveSeriesColor(spans.get(hoveredArc).slot), value: formatValue(totals[hoveredArc]) }]
|
|
13312
13515
|
}
|
|
13313
13516
|
) }),
|
|
13314
13517
|
hoveredRibbon && /* @__PURE__ */ jsx("div", { className: "absolute top-2 left-2 z-10", children: /* @__PURE__ */ jsx(
|
|
13315
13518
|
ChartTooltip,
|
|
13316
13519
|
{
|
|
13317
13520
|
title: `${labels[hoveredRibbon.from]} \u2192 ${labels[hoveredRibbon.to]}`,
|
|
13318
|
-
rows: [{ key: "value", label:
|
|
13521
|
+
rows: [{ key: "value", label: strings.flow, color: resolveSeriesColor(spans.get(hoveredRibbon.from).slot), value: formatValue(hoveredRibbon.value) }]
|
|
13319
13522
|
}
|
|
13320
13523
|
) }),
|
|
13321
13524
|
/* @__PURE__ */ jsx(
|
|
13322
13525
|
AccessibleTable,
|
|
13323
13526
|
{
|
|
13324
|
-
caption:
|
|
13325
|
-
head: [
|
|
13527
|
+
caption: strings.chord(order.length),
|
|
13528
|
+
head: [strings.tableFrom, strings.tableTo, strings.value],
|
|
13326
13529
|
rows: ribbons.map((ribbon) => [labels[ribbon.from], labels[ribbon.to], formatValue(ribbon.value)])
|
|
13327
13530
|
}
|
|
13328
13531
|
)
|
|
@@ -13330,5 +13533,5 @@ function ChordChart({
|
|
|
13330
13533
|
}
|
|
13331
13534
|
|
|
13332
13535
|
export { APP_UPDATE_POLL_MS, Accordion, AppUpdateBanner, AttachButton, AttachmentDropZone, AttachmentList, AuthScreen, Avatar, AvatarGroup, Banner, BarChart, BoxPlotChart, BrandAssetEditor, BudgetBar, CHART_INK, Calendar, CandlestickChart, Card, CartesianPlot, ChartBrush, ChartDefs, ChartDot, ChartFrame, ChartHighlightProvider, ChartSkeleton, ChartTooltip, ChatTemplate, Checkbox_default, CheckoutTemplate, ChordChart, ColoredBadge, ColumnChart, ComposerAttachments, ContainerFillChart, CountBadge, DAY_MS, DashboardTemplate, DataTable, DataTablePage, DatePicker_default, DateRangePicker, DateTimePicker_default, DescriptionList, Divider, DonutChart, Drawer, DropdownMenu, EmailTemplate, EmptyState, ErrorBoundary, ErrorPage, FilePicker_default, FormErrorSummary, FormField, FormLayoutPage, FunnelChart, GROUP_COLORS, GROUP_COLORS_SOLID, GalleryTemplate, GlobalSearch, Grid, HeatmapChart, HelpCenter, HistogramChart, INPUT_BASE, INPUT_SIZES, IconButton_default, Inline, InputNumber_default, Input_default, Kanban, Label, LineChart, ListFooter, ListLoadError, MAX_FRACTION_DIGITS, MENU_MAX_HEIGHT, MOTION, Markdown, MediaUploadField, MediaUploadGrid, Meter, MetricBar, MilestoneTimeline, NativeSelect, NumericKeypad, POPUP_MAX_WIDTH, POST_PRODUCTION_STATUSES, PageHeader, Pagination, PaperclipGlyph, Paragraph, PieChart, PortalBrandingProvider, ProductionTimeline, RADAR_SERIES_CAP, RadarChart, RadialBarChart, RadioGroup, Radio_default, RangeChart, RankedBars, SCATTER_SERIES_CAP, SERIES_SLOT_COUNT, SERIES_VARS, STAGES, STATUS_VARS, SankeyChart, ScatterChart, SearchableSelect, Segmented, Select_default, SettingRow, SidebarActionButton, SidebarGroupLabel, SidebarNavItem, Skeleton, Snippet, Sparkline, Stack, StatCard, StatTile, Statistic, StatusBadge, StatusBadgeProvider, Stepper, SunburstChart, Switch_default, Tabs, TagInput, Text, Textarea_default, TileButton_default, TimePicker_default, TimeSeriesChart, TimelineTrack, Title, Tooltip, TopNav, TreemapChart, WaterfallChart, angleScale, appendKey, applyThemePrefs, arcPath, areaBetween, areaFrom, autoHighlightIndex, backspace, bandScale, binValues, budgetState, bumpPath, calcOverall, calcReportOverall, copyToClipboard, curvePath, dashFor, fillFor, fillId, firstEnabledIndex, fmtSliderDate, formatDate, fromKey, glowId, groundId, groupColors, highlightOpacity, inputClasses, isSeverityTone, ladderScale, lastEnabledIndex, linearPath, linearScale, logScale, maskId, matchTypeahead, mediaFileName, monotonePath, nextEnabledIndex, niceMax, polygonPoints, popupBounds, radiusScale, resolvePortalBrandAsset, resolveSeriesColor, resolveTheme, selectionAt, seriesColor, severityOf, splinePath, squarify, stagger, stepPath, tabButtonId, tabPanelId, toDayMs, toISODate, toKey, useAppUpdate, useClickOutside, useDropdownPosition, useHighlight, usePlotWidth, usePortalBranding, useProductionTimeline, useTheme };
|
|
13333
|
-
//# sourceMappingURL=chunk-
|
|
13334
|
-
//# sourceMappingURL=chunk-
|
|
13536
|
+
//# sourceMappingURL=chunk-BJ34QOR3.js.map
|
|
13537
|
+
//# sourceMappingURL=chunk-BJ34QOR3.js.map
|