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