efficient-shell 4.134.0 → 4.137.1
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/LICENSE +6 -17
- package/README.md +84 -8
- package/dist/Browser-ZX5OTOKK.js +43 -0
- package/dist/Calculator-4SQGOQFQ.js +29 -0
- package/dist/ConfirmDialog-NPKW2XHM.js +1 -0
- package/dist/CurrencyConverter-2KOM7L6V.js +21 -0
- package/dist/Documents-IZTIQYPG.js +52 -0
- package/dist/Files-B63KKXGZ.js +89 -0
- package/dist/Notepad-WA77V45J.js +25 -0
- package/dist/PdfViewer-RBRGEKWF.js +1 -0
- package/dist/PomodoroTimer-SDUBKXUS.js +99 -0
- package/dist/Preview-D4KOA4OI.js +187 -0
- package/dist/Sidebar-Y57LYXXI.js +23 -0
- package/dist/Spreadsheet-JX5E6WH6.js +37 -0
- package/dist/Stock-XAQ5WMUZ.js +16 -0
- package/dist/Weather-HLAGJ5LV.js +60 -0
- package/dist/WorldClock-IRI4VCTA.js +32 -0
- package/dist/apps/index.js +1 -151
- package/dist/brand.css +1 -1
- package/dist/chunk-3A46NCXK.js +29 -0
- package/dist/chunk-44UO7FYU.js +11 -0
- package/dist/chunk-466CM2TJ.js +1 -0
- package/dist/chunk-57MIENLJ.js +1 -0
- package/dist/chunk-5CRAF2AD.js +2 -0
- package/dist/chunk-A2OQLLYK.js +6 -0
- package/dist/chunk-B43AGQET.js +4 -0
- package/dist/chunk-BR22X7E5.js +1 -0
- package/dist/chunk-BUTSU7FO.js +1 -0
- package/dist/chunk-D65T4H6J.js +1 -0
- package/dist/chunk-ESL5TDNA.js +1 -0
- package/dist/chunk-FBDZGO3V.js +1 -0
- package/dist/chunk-FHTLC7HH.js +1 -0
- package/dist/chunk-FQLMX3IE.js +948 -0
- package/dist/chunk-H562R4GX.js +34 -0
- package/dist/chunk-JN4WXTWJ.js +106 -0
- package/dist/chunk-LVDRBRYU.js +1 -0
- package/dist/chunk-LWLCNQY7.js +1 -0
- package/dist/chunk-MAIHBBWT.js +1 -0
- package/dist/chunk-NPJH5MD7.js +13 -0
- package/dist/chunk-OCSOMMY2.js +1 -0
- package/dist/chunk-OQDWLHZI.js +1 -0
- package/dist/chunk-OWSAMA3I.js +23 -0
- package/dist/chunk-PH3PRIFP.js +5 -0
- package/dist/chunk-TAWKWSPN.js +9 -0
- package/dist/chunk-U4GTZPXP.js +1 -0
- package/dist/chunk-UB4JIOLD.js +2 -0
- package/dist/chunk-UZAJ5BF6.js +9 -0
- package/dist/chunk-VEGMDXT4.js +1 -0
- package/dist/chunk-VTVSMRFX.js +1 -0
- package/dist/chunk-VVAGSKW7.js +1 -0
- package/dist/chunk-XO43FJRM.js +19 -0
- package/dist/chunk-Y7BOLDRM.js +69 -0
- package/dist/file-intake/index.js +1 -4
- package/dist/{index-DZ7E7bCl.d.ts → index-DVI9DMSu.d.ts} +189 -18
- package/dist/index.d.ts +2 -2
- package/dist/index.js +639 -7473
- package/dist/map/index.js +20 -540
- package/dist/markdown/index.js +6 -184
- package/dist/markup/index.js +1 -135
- package/dist/page-tabs/index.js +21 -709
- package/dist/sounds-OMHXVVQ4.js +1 -0
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +1 -19
- package/dist/ui.css +78 -10
- package/package.json +4 -3
- package/dist/Browser-O3QZGUF2.js +0 -482
- package/dist/Browser-O3QZGUF2.js.map +0 -1
- package/dist/Calculator-L6N5X3KU.js +0 -192
- package/dist/Calculator-L6N5X3KU.js.map +0 -1
- package/dist/ConfirmDialog-LYSSZSUD.js +0 -4
- package/dist/ConfirmDialog-LYSSZSUD.js.map +0 -1
- package/dist/CurrencyConverter-64MKXB3D.js +0 -236
- package/dist/CurrencyConverter-64MKXB3D.js.map +0 -1
- package/dist/Documents-5WXXYCLI.js +0 -441
- package/dist/Documents-5WXXYCLI.js.map +0 -1
- package/dist/Files-AUURUUDN.js +0 -805
- package/dist/Files-AUURUUDN.js.map +0 -1
- package/dist/Notepad-GPXJVPB7.js +0 -410
- package/dist/Notepad-GPXJVPB7.js.map +0 -1
- package/dist/PdfViewer-HKO6P4SR.js +0 -5
- package/dist/PdfViewer-HKO6P4SR.js.map +0 -1
- package/dist/PomodoroTimer-4TQBWLP2.js +0 -633
- package/dist/PomodoroTimer-4TQBWLP2.js.map +0 -1
- package/dist/Preview-FOZYPKM2.js +0 -2959
- package/dist/Preview-FOZYPKM2.js.map +0 -1
- package/dist/Sidebar-BPU7RCZP.js +0 -291
- package/dist/Sidebar-BPU7RCZP.js.map +0 -1
- package/dist/Spreadsheet-3C66BBBF.js +0 -519
- package/dist/Spreadsheet-3C66BBBF.js.map +0 -1
- package/dist/Stock-IF4IHYLU.js +0 -158
- package/dist/Stock-IF4IHYLU.js.map +0 -1
- package/dist/Weather-725PFR7T.js +0 -431
- package/dist/Weather-725PFR7T.js.map +0 -1
- package/dist/WorldClock-UU4NZIQ7.js +0 -202
- package/dist/WorldClock-UU4NZIQ7.js.map +0 -1
- package/dist/apps/index.js.map +0 -1
- package/dist/chunk-2TPTHAKI.js +0 -316
- package/dist/chunk-2TPTHAKI.js.map +0 -1
- package/dist/chunk-4P44JXDS.js +0 -195
- package/dist/chunk-4P44JXDS.js.map +0 -1
- package/dist/chunk-5O42JXQE.js +0 -26
- package/dist/chunk-5O42JXQE.js.map +0 -1
- package/dist/chunk-72CQWN7O.js +0 -547
- package/dist/chunk-72CQWN7O.js.map +0 -1
- package/dist/chunk-7CCHEEYC.js +0 -94
- package/dist/chunk-7CCHEEYC.js.map +0 -1
- package/dist/chunk-BE7FZOFU.js +0 -17
- package/dist/chunk-BE7FZOFU.js.map +0 -1
- package/dist/chunk-D276EMXS.js +0 -57
- package/dist/chunk-D276EMXS.js.map +0 -1
- package/dist/chunk-D7PYW2QS.js +0 -265
- package/dist/chunk-D7PYW2QS.js.map +0 -1
- package/dist/chunk-DVZWYWSD.js +0 -26
- package/dist/chunk-DVZWYWSD.js.map +0 -1
- package/dist/chunk-ET6ID4LP.js +0 -102
- package/dist/chunk-ET6ID4LP.js.map +0 -1
- package/dist/chunk-GA35NEND.js +0 -56
- package/dist/chunk-GA35NEND.js.map +0 -1
- package/dist/chunk-GIGV2ZRW.js +0 -70
- package/dist/chunk-GIGV2ZRW.js.map +0 -1
- package/dist/chunk-IPXN646P.js +0 -14
- package/dist/chunk-IPXN646P.js.map +0 -1
- package/dist/chunk-IRWSRJ4K.js +0 -48
- package/dist/chunk-IRWSRJ4K.js.map +0 -1
- package/dist/chunk-IULP5BCD.js +0 -79
- package/dist/chunk-IULP5BCD.js.map +0 -1
- package/dist/chunk-MGGY74RY.js +0 -14
- package/dist/chunk-MGGY74RY.js.map +0 -1
- package/dist/chunk-OLJDJYSU.js +0 -13678
- package/dist/chunk-OLJDJYSU.js.map +0 -1
- package/dist/chunk-PIGDNN5F.js +0 -46
- package/dist/chunk-PIGDNN5F.js.map +0 -1
- package/dist/chunk-Q2MJVSJT.js +0 -7
- package/dist/chunk-Q2MJVSJT.js.map +0 -1
- package/dist/chunk-Q3LT745N.js +0 -3710
- package/dist/chunk-Q3LT745N.js.map +0 -1
- package/dist/chunk-QAGQRNKI.js +0 -145
- package/dist/chunk-QAGQRNKI.js.map +0 -1
- package/dist/chunk-QRL64J5F.js +0 -503
- package/dist/chunk-QRL64J5F.js.map +0 -1
- package/dist/chunk-QSKCQUZE.js +0 -1103
- package/dist/chunk-QSKCQUZE.js.map +0 -1
- package/dist/chunk-R4OQIQYX.js +0 -153
- package/dist/chunk-R4OQIQYX.js.map +0 -1
- package/dist/chunk-RT6DSB5Y.js +0 -143
- package/dist/chunk-RT6DSB5Y.js.map +0 -1
- package/dist/chunk-SHQM5CK3.js +0 -549
- package/dist/chunk-SHQM5CK3.js.map +0 -1
- package/dist/chunk-T4VQHMG4.js +0 -822
- package/dist/chunk-T4VQHMG4.js.map +0 -1
- package/dist/chunk-TRCWINHF.js +0 -105
- package/dist/chunk-TRCWINHF.js.map +0 -1
- package/dist/chunk-TW7LPMVR.js +0 -16
- package/dist/chunk-TW7LPMVR.js.map +0 -1
- package/dist/chunk-W622KQTD.js +0 -465
- package/dist/chunk-W622KQTD.js.map +0 -1
- package/dist/chunk-X4Q6G253.js +0 -416
- package/dist/chunk-X4Q6G253.js.map +0 -1
- package/dist/chunk-YNKK7NE3.js +0 -171
- package/dist/chunk-YNKK7NE3.js.map +0 -1
- package/dist/chunk-YPO6RDMX.js +0 -20
- package/dist/chunk-YPO6RDMX.js.map +0 -1
- package/dist/file-intake/index.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/map/index.js.map +0 -1
- package/dist/markdown/index.js.map +0 -1
- package/dist/markup/index.js.map +0 -1
- package/dist/page-tabs/index.js.map +0 -1
- package/dist/sounds-NT4DEZGD.js +0 -3
- package/dist/sounds-NT4DEZGD.js.map +0 -1
- package/dist/ui/index.js.map +0 -1
package/dist/chunk-2TPTHAKI.js
DELETED
|
@@ -1,316 +0,0 @@
|
|
|
1
|
-
import { useShellStrings } from './chunk-72CQWN7O.js';
|
|
2
|
-
import { useHydrated, useBrowserState } from './chunk-IRWSRJ4K.js';
|
|
3
|
-
import { createContext, useSyncExternalStore, useCallback, useContext, useMemo } from 'react';
|
|
4
|
-
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
|
-
|
|
6
|
-
var QUERY = "(max-width: 767px), (pointer: coarse)";
|
|
7
|
-
function getSnapshot() {
|
|
8
|
-
if (typeof window === "undefined" || !window.matchMedia) return false;
|
|
9
|
-
return window.matchMedia(QUERY).matches;
|
|
10
|
-
}
|
|
11
|
-
function getServerSnapshot() {
|
|
12
|
-
return false;
|
|
13
|
-
}
|
|
14
|
-
function subscribe(cb) {
|
|
15
|
-
if (typeof window === "undefined" || !window.matchMedia) return () => {
|
|
16
|
-
};
|
|
17
|
-
const mql = window.matchMedia(QUERY);
|
|
18
|
-
if (mql.addEventListener) {
|
|
19
|
-
mql.addEventListener("change", cb);
|
|
20
|
-
return () => mql.removeEventListener("change", cb);
|
|
21
|
-
}
|
|
22
|
-
mql.addListener(cb);
|
|
23
|
-
return () => mql.removeListener(cb);
|
|
24
|
-
}
|
|
25
|
-
function useIsMobile() {
|
|
26
|
-
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
27
|
-
}
|
|
28
|
-
var STATUS_TONE = {
|
|
29
|
-
success: "success",
|
|
30
|
-
error: "error",
|
|
31
|
-
warning: "warning",
|
|
32
|
-
info: "info",
|
|
33
|
-
// A missing page is not an error the user made, and colouring it red says it
|
|
34
|
-
// was. Refused and broken are genuinely different from not-found.
|
|
35
|
-
404: "info",
|
|
36
|
-
403: "warning",
|
|
37
|
-
500: "error"
|
|
38
|
-
};
|
|
39
|
-
var TONE_CLASS = {
|
|
40
|
-
success: "text-green-600 bg-green-100",
|
|
41
|
-
error: "text-red-600 bg-red-100",
|
|
42
|
-
warning: "text-amber-600 bg-amber-100",
|
|
43
|
-
info: "text-blue-600 bg-blue-100"
|
|
44
|
-
};
|
|
45
|
-
var DEFAULT_TITLE = {
|
|
46
|
-
404: (errors) => errors.notFound,
|
|
47
|
-
403: (errors) => errors.noAccess,
|
|
48
|
-
500: (errors) => errors.serverError
|
|
49
|
-
};
|
|
50
|
-
function StatusIcon({ tone }) {
|
|
51
|
-
const common = { className: "h-6 w-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, "aria-hidden": true };
|
|
52
|
-
switch (tone) {
|
|
53
|
-
case "success":
|
|
54
|
-
return /* @__PURE__ */ jsx("svg", { ...common, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.5 12.75l6 6 9-13.5" }) });
|
|
55
|
-
case "error":
|
|
56
|
-
return /* @__PURE__ */ jsx("svg", { ...common, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) });
|
|
57
|
-
case "warning":
|
|
58
|
-
return /* @__PURE__ */ jsx("svg", { ...common, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z" }) });
|
|
59
|
-
default:
|
|
60
|
-
return /* @__PURE__ */ jsx("svg", { ...common, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" }) });
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
function Result({
|
|
64
|
-
status = "info",
|
|
65
|
-
title,
|
|
66
|
-
subTitle,
|
|
67
|
-
extra,
|
|
68
|
-
icon,
|
|
69
|
-
children,
|
|
70
|
-
className = ""
|
|
71
|
-
}) {
|
|
72
|
-
const tone = STATUS_TONE[status];
|
|
73
|
-
const errors = useShellStrings().errors;
|
|
74
|
-
const announces = tone === "error";
|
|
75
|
-
return /* @__PURE__ */ jsxs(
|
|
76
|
-
"div",
|
|
77
|
-
{
|
|
78
|
-
role: announces ? "alert" : void 0,
|
|
79
|
-
className: `flex flex-col items-center justify-center px-6 py-12 text-center ${className}`.trim(),
|
|
80
|
-
children: [
|
|
81
|
-
/* @__PURE__ */ jsx("div", { className: `flex h-14 w-14 items-center justify-center rounded-full ${TONE_CLASS[tone]}`, children: icon ?? /* @__PURE__ */ jsx(StatusIcon, { tone }) }),
|
|
82
|
-
/* @__PURE__ */ jsx("h2", { className: "mt-4 text-lg font-semibold text-gray-900", children: title ?? DEFAULT_TITLE[status]?.(errors) ?? "" }),
|
|
83
|
-
subTitle && /* @__PURE__ */ jsx("p", { className: "mt-1 max-w-md text-sm text-gray-500", children: subTitle }),
|
|
84
|
-
children && /* @__PURE__ */ jsx("div", { className: "mt-4 w-full max-w-md text-left", children }),
|
|
85
|
-
extra && /* @__PURE__ */ jsx("div", { className: "mt-6 flex flex-wrap items-center justify-center gap-3", children: extra })
|
|
86
|
-
]
|
|
87
|
-
}
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
function LoadingSpinner({ size = "md", padding = "py-12", label, className = "" }) {
|
|
91
|
-
const dim = size === "sm" ? "h-5 w-5" : size === "lg" ? "h-12 w-12" : "h-8 w-8";
|
|
92
|
-
const ring = /* @__PURE__ */ jsx("div", { className: `${dim} animate-spin rounded-full border-2 border-gray-200 border-t-blue-600` });
|
|
93
|
-
if (label == null) {
|
|
94
|
-
return /* @__PURE__ */ jsx("div", { className: `flex items-center justify-center ${padding} ${className}`, children: ring });
|
|
95
|
-
}
|
|
96
|
-
return /* @__PURE__ */ jsxs("div", { role: "status", className: `flex flex-col items-center justify-center gap-3 ${padding} ${className}`, children: [
|
|
97
|
-
ring,
|
|
98
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500", children: label })
|
|
99
|
-
] });
|
|
100
|
-
}
|
|
101
|
-
var isMac = typeof window !== "undefined" && typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent);
|
|
102
|
-
var FORMS = {
|
|
103
|
-
MOD: ["\u2318", "Ctrl"],
|
|
104
|
-
ALT: ["\u2325", "Alt"],
|
|
105
|
-
CMD_ENTER: ["\u2318\u23CE", "Ctrl\u23CE"],
|
|
106
|
-
CMD_S: ["\u2318S", "Ctrl+S"],
|
|
107
|
-
CMD_K: ["\u2318K", "Ctrl+K"],
|
|
108
|
-
CMD_DOT: ["\u2318.", "Ctrl+."],
|
|
109
|
-
CMD_A: ["\u2318A", "Ctrl+A"],
|
|
110
|
-
CMD_Z: ["\u2318Z", "Ctrl+Z"],
|
|
111
|
-
CMD_SHIFT_Z: ["\u2318\u21E7Z", "Ctrl+Shift+Z"],
|
|
112
|
-
ALT_SHIFT_D: ["\u2325\u21E7D", "Alt+Shift+D"],
|
|
113
|
-
ALT_SHIFT_E: ["\u2325\u21E7E", "Alt+Shift+E"],
|
|
114
|
-
ALT_SHIFT_N: ["\u2325\u21E7N", "Alt+Shift+N"]
|
|
115
|
-
};
|
|
116
|
-
var HERE = isMac ? 0 : 1;
|
|
117
|
-
var MOD = FORMS.MOD[HERE];
|
|
118
|
-
var ALT = FORMS.ALT[HERE];
|
|
119
|
-
var SHIFT = "\u21E7";
|
|
120
|
-
var ENTER = "\u23CE";
|
|
121
|
-
var CMD_ENTER = FORMS.CMD_ENTER[HERE];
|
|
122
|
-
var CMD_S = FORMS.CMD_S[HERE];
|
|
123
|
-
var CMD_K = FORMS.CMD_K[HERE];
|
|
124
|
-
var CMD_DOT = FORMS.CMD_DOT[HERE];
|
|
125
|
-
var CMD_A = FORMS.CMD_A[HERE];
|
|
126
|
-
var CMD_Z = FORMS.CMD_Z[HERE];
|
|
127
|
-
var CMD_SHIFT_Z = FORMS.CMD_SHIFT_Z[HERE];
|
|
128
|
-
var ALT_SHIFT_D = FORMS.ALT_SHIFT_D[HERE];
|
|
129
|
-
var ALT_SHIFT_E = FORMS.ALT_SHIFT_E[HERE];
|
|
130
|
-
var ALT_SHIFT_N = FORMS.ALT_SHIFT_N[HERE];
|
|
131
|
-
var AS_ON_SERVER = new Map(
|
|
132
|
-
isMac ? Object.values(FORMS).map(([mac, other]) => [mac, other]) : []
|
|
133
|
-
);
|
|
134
|
-
function useShortcutLabel(keys) {
|
|
135
|
-
const hydrated = useHydrated();
|
|
136
|
-
return hydrated ? keys : AS_ON_SERVER.get(keys) ?? keys;
|
|
137
|
-
}
|
|
138
|
-
var KBD_BASE = "inline-flex items-center justify-center rounded border border-gray-200 bg-gray-50 font-medium text-gray-500";
|
|
139
|
-
var KBD_SIZES = {
|
|
140
|
-
sm: "px-1 py-0.5 text-[10px]",
|
|
141
|
-
md: "px-1.5 py-0.5 text-[11px]"
|
|
142
|
-
};
|
|
143
|
-
function Kbd({ keys, size = "md", className = "" }) {
|
|
144
|
-
const label = useShortcutLabel(keys);
|
|
145
|
-
return /* @__PURE__ */ jsx("kbd", { className: [KBD_BASE, KBD_SIZES[size], className].filter(Boolean).join(" "), children: label });
|
|
146
|
-
}
|
|
147
|
-
var ShellPrefsContext = createContext(null);
|
|
148
|
-
function ShellPrefsProvider({
|
|
149
|
-
value,
|
|
150
|
-
children
|
|
151
|
-
}) {
|
|
152
|
-
return /* @__PURE__ */ jsx(ShellPrefsContext.Provider, { value, children });
|
|
153
|
-
}
|
|
154
|
-
function useLocalStoragePrefs(storageKey = "react-os-shell:prefs", defaults) {
|
|
155
|
-
const [prefs, setPrefs] = useBrowserState(() => {
|
|
156
|
-
try {
|
|
157
|
-
const stored = JSON.parse(localStorage.getItem(storageKey) || "{}");
|
|
158
|
-
return { ...defaults ?? {}, ...stored };
|
|
159
|
-
} catch {
|
|
160
|
-
return { ...defaults ?? {} };
|
|
161
|
-
}
|
|
162
|
-
}, { ...defaults ?? {} });
|
|
163
|
-
const save = useCallback((patch) => {
|
|
164
|
-
setPrefs((prev) => {
|
|
165
|
-
const next = { ...prev, ...patch };
|
|
166
|
-
try {
|
|
167
|
-
localStorage.setItem(storageKey, JSON.stringify(next));
|
|
168
|
-
} catch {
|
|
169
|
-
}
|
|
170
|
-
return next;
|
|
171
|
-
});
|
|
172
|
-
}, [storageKey]);
|
|
173
|
-
return { prefs, save };
|
|
174
|
-
}
|
|
175
|
-
var NO_PROVIDER = { prefs: {}, save: () => {
|
|
176
|
-
} };
|
|
177
|
-
function useShellPrefsAdapter() {
|
|
178
|
-
return useContext(ShellPrefsContext) ?? NO_PROVIDER;
|
|
179
|
-
}
|
|
180
|
-
function useShellPrefs() {
|
|
181
|
-
const { prefs, save: rawSave } = useShellPrefsAdapter();
|
|
182
|
-
const save = useCallback((patch) => {
|
|
183
|
-
const result = rawSave(patch);
|
|
184
|
-
return result && typeof result.then === "function" ? result.catch(() => {
|
|
185
|
-
}) : result;
|
|
186
|
-
}, [rawSave]);
|
|
187
|
-
return useMemo(() => ({ prefs, save }), [prefs, save]);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// src/shell/staleChunk.ts
|
|
191
|
-
var STALE_CHUNK_RELOAD_KEY = "react-os-shell:stale-chunk-reload-at";
|
|
192
|
-
var STALE_CHUNK_RELOAD_COOLDOWN_MS = 3e4;
|
|
193
|
-
var VITE_PRELOAD_ERROR_EVENT = "vite:preloadError";
|
|
194
|
-
var NEXT_CHUNK_PATH_PREFIX = "/_next/static/";
|
|
195
|
-
var STALE_CHUNK_MESSAGE = /Failed to fetch dynamically imported module|error loading dynamically imported module|Importing a module script failed|Unable to preload CSS/i;
|
|
196
|
-
var CHUNK_LOAD_ERROR_NAME = "ChunkLoadError";
|
|
197
|
-
function isStaleChunkError(error) {
|
|
198
|
-
if (error instanceof Error && error.name === CHUNK_LOAD_ERROR_NAME) return true;
|
|
199
|
-
const message = error instanceof Error ? error.message : typeof error === "string" ? error : "";
|
|
200
|
-
return STALE_CHUNK_MESSAGE.test(message);
|
|
201
|
-
}
|
|
202
|
-
function linkLoadsChunk(link) {
|
|
203
|
-
const rels = link.rel.toLowerCase().split(/\s+/);
|
|
204
|
-
if (rels.includes("stylesheet") || rels.includes("modulepreload")) return true;
|
|
205
|
-
const as = (link.getAttribute("as") ?? "").toLowerCase();
|
|
206
|
-
return rels.includes("preload") && (as === "script" || as === "style");
|
|
207
|
-
}
|
|
208
|
-
function failedChunkUrl(event, prefix) {
|
|
209
|
-
const target = event.target;
|
|
210
|
-
let src = "";
|
|
211
|
-
if (target instanceof window.HTMLScriptElement) src = target.src;
|
|
212
|
-
else if (target instanceof window.HTMLLinkElement && linkLoadsChunk(target)) src = target.href;
|
|
213
|
-
else if (event instanceof window.ErrorEvent && event.error?.name === "SyntaxError") {
|
|
214
|
-
src = event.filename;
|
|
215
|
-
}
|
|
216
|
-
if (!src) return null;
|
|
217
|
-
try {
|
|
218
|
-
const base = new URL(prefix, window.location.origin).href;
|
|
219
|
-
const url = new URL(src, window.location.href).href;
|
|
220
|
-
return url.startsWith(base) ? url : null;
|
|
221
|
-
} catch {
|
|
222
|
-
return null;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
async function isGoneFromServer(url) {
|
|
226
|
-
try {
|
|
227
|
-
const response = await fetch(url, { method: "HEAD", cache: "no-store" });
|
|
228
|
-
if (response.status === 404 || response.status === 410) return true;
|
|
229
|
-
return response.ok && /\btext\/html\b/i.test(response.headers.get("content-type") ?? "");
|
|
230
|
-
} catch {
|
|
231
|
-
return false;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
function defaultStorage() {
|
|
235
|
-
try {
|
|
236
|
-
const s = window.sessionStorage;
|
|
237
|
-
s.getItem(STALE_CHUNK_RELOAD_KEY);
|
|
238
|
-
return s;
|
|
239
|
-
} catch {
|
|
240
|
-
return null;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
function readLastReload(storage) {
|
|
244
|
-
if (!storage) return null;
|
|
245
|
-
try {
|
|
246
|
-
const raw = storage.getItem(STALE_CHUNK_RELOAD_KEY);
|
|
247
|
-
const at = raw === null ? NaN : Number(raw);
|
|
248
|
-
return Number.isFinite(at) ? at : null;
|
|
249
|
-
} catch {
|
|
250
|
-
return null;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
function writeLastReload(storage, at) {
|
|
254
|
-
if (!storage) return;
|
|
255
|
-
try {
|
|
256
|
-
storage.setItem(STALE_CHUNK_RELOAD_KEY, String(at));
|
|
257
|
-
} catch {
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
function installStaleChunkReload(options = {}) {
|
|
261
|
-
if (typeof window === "undefined") return () => {
|
|
262
|
-
};
|
|
263
|
-
const cooldownMs = options.cooldownMs ?? STALE_CHUNK_RELOAD_COOLDOWN_MS;
|
|
264
|
-
const reload = options.reload ?? (() => window.location.reload());
|
|
265
|
-
const now = options.now ?? Date.now;
|
|
266
|
-
const storage = options.storage === void 0 ? defaultStorage() : options.storage;
|
|
267
|
-
const chunkPathPrefix = options.chunkPathPrefix === void 0 ? NEXT_CHUNK_PATH_PREFIX : options.chunkPathPrefix;
|
|
268
|
-
const claimReload = (chunk) => {
|
|
269
|
-
const at = now();
|
|
270
|
-
const last = readLastReload(storage);
|
|
271
|
-
if (last !== null && at - last < cooldownMs) {
|
|
272
|
-
console.error(
|
|
273
|
-
"[efficient-shell] a lazy chunk is still missing after a reload; letting the failure through:",
|
|
274
|
-
chunk
|
|
275
|
-
);
|
|
276
|
-
return false;
|
|
277
|
-
}
|
|
278
|
-
writeLastReload(storage, at);
|
|
279
|
-
console.warn(
|
|
280
|
-
"[efficient-shell] a lazy chunk is no longer on the server (new deploy?); reloading onto the current build:",
|
|
281
|
-
chunk
|
|
282
|
-
);
|
|
283
|
-
return true;
|
|
284
|
-
};
|
|
285
|
-
const onPreloadError = (event) => {
|
|
286
|
-
const payload = event.payload;
|
|
287
|
-
if (!isStaleChunkError(payload) || !claimReload(payload)) return;
|
|
288
|
-
event.preventDefault();
|
|
289
|
-
reload();
|
|
290
|
-
};
|
|
291
|
-
let active = true;
|
|
292
|
-
let reloading = false;
|
|
293
|
-
const asking = /* @__PURE__ */ new Set();
|
|
294
|
-
const onChunkError = chunkPathPrefix === null ? null : (event) => {
|
|
295
|
-
const chunk = failedChunkUrl(event, chunkPathPrefix);
|
|
296
|
-
if (!chunk || reloading || asking.has(chunk)) return;
|
|
297
|
-
asking.add(chunk);
|
|
298
|
-
void isGoneFromServer(chunk).then((gone) => {
|
|
299
|
-
asking.delete(chunk);
|
|
300
|
-
if (!gone || !active || reloading || !claimReload(chunk)) return;
|
|
301
|
-
reloading = true;
|
|
302
|
-
reload();
|
|
303
|
-
});
|
|
304
|
-
};
|
|
305
|
-
window.addEventListener(VITE_PRELOAD_ERROR_EVENT, onPreloadError);
|
|
306
|
-
if (onChunkError) window.addEventListener("error", onChunkError, true);
|
|
307
|
-
return () => {
|
|
308
|
-
active = false;
|
|
309
|
-
window.removeEventListener(VITE_PRELOAD_ERROR_EVENT, onPreloadError);
|
|
310
|
-
if (onChunkError) window.removeEventListener("error", onChunkError, true);
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
export { ALT, ALT_SHIFT_D, ALT_SHIFT_E, ALT_SHIFT_N, CMD_A, CMD_DOT, CMD_ENTER, CMD_K, CMD_S, CMD_SHIFT_Z, CMD_Z, ENTER, Kbd, LoadingSpinner, MOD, NEXT_CHUNK_PATH_PREFIX, Result, SHIFT, STALE_CHUNK_RELOAD_COOLDOWN_MS, STALE_CHUNK_RELOAD_KEY, ShellPrefsProvider, VITE_PRELOAD_ERROR_EVENT, installStaleChunkReload, isMac, isStaleChunkError, useIsMobile, useLocalStoragePrefs, useShellPrefs, useShellPrefsAdapter, useShortcutLabel };
|
|
315
|
-
//# sourceMappingURL=chunk-2TPTHAKI.js.map
|
|
316
|
-
//# sourceMappingURL=chunk-2TPTHAKI.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/shell/useIsMobile.ts","../src/shell/Result.tsx","../src/shell/Spinner.tsx","../src/shell/Kbd.tsx","../src/shell/ShellPrefs.tsx","../src/shell/staleChunk.ts"],"names":["jsx","jsxs"],"mappings":"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","file":"chunk-2TPTHAKI.js","sourcesContent":["/**\n * Mobile breakpoint hook — single source of truth for \"is this a phone/tablet\n * portrait viewport?\" Drives whether <Layout> renders the desktop chrome\n * (windows / taskbar / start menu sidebar) or the <MobileAppLanding> screen\n * that points the user at the consumer-wired mobile app. A handful of\n * primitives (Modal, ResizableTable) also read it to adapt touch behaviour.\n *\n * Locked at 768 px so iPad portrait counts as mobile. Also OR's with\n * `pointer: coarse` so touch-only devices that happen to be wider (e.g. an\n * Android tablet in landscape) still get touch-appropriate UI.\n */\nimport { useSyncExternalStore } from 'react';\n\nconst QUERY = '(max-width: 767px), (pointer: coarse)';\n\nfunction getSnapshot(): boolean {\n if (typeof window === 'undefined' || !window.matchMedia) return false;\n return window.matchMedia(QUERY).matches;\n}\n\nfunction getServerSnapshot(): boolean {\n return false;\n}\n\nfunction subscribe(cb: () => void): () => void {\n if (typeof window === 'undefined' || !window.matchMedia) return () => {};\n const mql = window.matchMedia(QUERY);\n // Older Safari uses addListener; modern browsers use addEventListener.\n if (mql.addEventListener) {\n mql.addEventListener('change', cb);\n return () => mql.removeEventListener('change', cb);\n }\n mql.addListener(cb);\n return () => mql.removeListener(cb);\n}\n\nexport function useIsMobile(): boolean {\n return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n","/**\n * Result — the full-page outcome state: a 404, a 403, a crashed boundary, a\n * completed checkout.\n *\n * `EmptyState` is the neighbour to know about. That one means \"this list has\n * nothing in it yet\", which is normal and usually actionable. This one means\n * something ENDED — succeeded, failed, or was refused — and it is the whole\n * page rather than a region of one. `ErrorPage` is this component wrapped in a\n * full-screen frame.\n */\nimport { type ReactNode } from 'react';\nimport { useShellStrings, type ShellStrings } from './strings';\n\nexport type ResultStatus = 'success' | 'error' | 'warning' | 'info' | '404' | '403' | '500';\n\nexport interface ResultProps {\n status?: ResultStatus;\n title?: ReactNode;\n subTitle?: ReactNode;\n /** Actions — usually one primary route out. Always give the user one. */\n extra?: ReactNode;\n /** Replace the status glyph entirely. */\n icon?: ReactNode;\n children?: ReactNode;\n className?: string;\n}\n\ntype Tone = 'success' | 'error' | 'warning' | 'info';\n\nconst STATUS_TONE: Record<ResultStatus, Tone> = {\n success: 'success', error: 'error', warning: 'warning', info: 'info',\n // A missing page is not an error the user made, and colouring it red says it\n // was. Refused and broken are genuinely different from not-found.\n 404: 'info', 403: 'warning', 500: 'error',\n};\n\nconst TONE_CLASS: Record<Tone, string> = {\n success: 'text-green-600 bg-green-100',\n error: 'text-red-600 bg-red-100',\n warning: 'text-amber-600 bg-amber-100',\n info: 'text-blue-600 bg-blue-100',\n};\n\n/** Default copy, so the common cases need only `status` — the catalog's\n * `errors` words, picked at render so a translation reaches them. */\nconst DEFAULT_TITLE: Partial<Record<ResultStatus, (errors: ShellStrings['errors']) => string>> = {\n 404: errors => errors.notFound,\n 403: errors => errors.noAccess,\n 500: errors => errors.serverError,\n};\n\nfunction StatusIcon({ tone }: { tone: Tone }) {\n const common = { className: 'h-6 w-6', fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor', strokeWidth: 1.5, 'aria-hidden': true } as const;\n switch (tone) {\n case 'success':\n return <svg {...common}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\" /></svg>;\n case 'error':\n return <svg {...common}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" /></svg>;\n case 'warning':\n return <svg {...common}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z\" /></svg>;\n default:\n return <svg {...common}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z\" /></svg>;\n }\n}\n\nexport default function Result({\n status = 'info', title, subTitle, extra, icon, children, className = '',\n}: ResultProps) {\n const tone = STATUS_TONE[status];\n const errors = useShellStrings().errors;\n // WCAG 4.1.3. A Result that reports a failure is a status message: it appears\n // without the user moving focus, so a screen-reader user is told nothing\n // unless it announces itself. `alert` is assertive, which is right for a\n // failure and wrong for everything else — an outcome someone asked for\n // (a completed checkout) or a neutral one (an empty cart) would interrupt\n // whatever they were reading to say something they already expected.\n const announces = tone === 'error';\n return (\n <div\n role={announces ? 'alert' : undefined}\n className={`flex flex-col items-center justify-center px-6 py-12 text-center ${className}`.trim()}\n >\n <div className={`flex h-14 w-14 items-center justify-center rounded-full ${TONE_CLASS[tone]}`}>\n {icon ?? <StatusIcon tone={tone} />}\n </div>\n <h2 className=\"mt-4 text-lg font-semibold text-gray-900\">\n {title ?? DEFAULT_TITLE[status]?.(errors) ?? ''}\n </h2>\n {subTitle && <p className=\"mt-1 max-w-md text-sm text-gray-500\">{subTitle}</p>}\n {children && <div className=\"mt-4 w-full max-w-md text-left\">{children}</div>}\n {extra && <div className=\"mt-6 flex flex-wrap items-center justify-center gap-3\">{extra}</div>}\n </div>\n );\n}\n","import { type ReactNode } from 'react';\n\nexport interface LoadingSpinnerProps {\n /** Ring diameter: `sm` = 20px, `md` = 32px (default), `lg` = 48px. */\n size?: 'sm' | 'md' | 'lg';\n /** Wrapper padding utility (default `py-12`). Pass `''` to remove. */\n padding?: string;\n /**\n * Caption under the ring, e.g. \"Signing in…\". Naming what is happening beats\n * a bare ring on a full-screen wait, where there is nothing else on the page\n * to infer it from. Adds `role=\"status\"` so it is announced.\n */\n label?: ReactNode;\n /** Extra classes on the centering wrapper. */\n className?: string;\n}\n\n/**\n * LoadingSpinner — a centered animated ring for pending/loading regions.\n * (Distinct from the shell's internal \"Loading…\" text used inside data grids.)\n */\nexport default function LoadingSpinner({ size = 'md', padding = 'py-12', label, className = '' }: LoadingSpinnerProps) {\n const dim = size === 'sm' ? 'h-5 w-5' : size === 'lg' ? 'h-12 w-12' : 'h-8 w-8';\n const ring = <div className={`${dim} animate-spin rounded-full border-2 border-gray-200 border-t-blue-600`} />;\n // Without a label the markup is exactly what it has always been — including\n // no `role`, which would otherwise have changed the a11y tree for every\n // existing caller. A labelled spinner is a status; a bare ring is decoration.\n if (label == null) {\n return <div className={`flex items-center justify-center ${padding} ${className}`}>{ring}</div>;\n }\n return (\n <div role=\"status\" className={`flex flex-col items-center justify-center gap-3 ${padding} ${className}`}>\n {ring}\n <p className=\"text-sm text-gray-500\">{label}</p>\n </div>\n );\n}\n","/**\n * Keyboard shortcuts: the platform-aware STRINGS a shortcut is written with,\n * and the badge that renders one.\n *\n * Both live here because they are one concept — a shortcut nobody can see is\n * not a shortcut — and because the strings came first: the constants have\n * shipped for years and the badge around them was left to each consumer, which\n * is how the admin portal ended up with 109 hand-written `<kbd>` elements\n * across 80 files in two different sizes.\n */\nimport { useHydrated } from './hydration';\n\n/**\n * Whether the READER is on a Mac. Fixed when the module loads, and `false` on a\n * server whatever the server runs on: Node has had a global `navigator` since\n * 21, and its `platform` is the machine's own — a guard on `navigator` alone\n * let a Mac server write \\u2318 into HTML for every reader it served.\n */\nexport const isMac = typeof window !== 'undefined' && typeof navigator !== 'undefined'\n && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent);\n\n/**\n * Every platform-aware label, as [Mac, everywhere else]. One table, so the\n * badge can tell what a constant was written as on the server from what it is\n * written as here.\n */\nconst FORMS = {\n MOD: ['\\u2318', 'Ctrl'],\n ALT: ['\\u2325', 'Alt'],\n CMD_ENTER: ['\\u2318\\u23CE', 'Ctrl\\u23CE'],\n CMD_S: ['\\u2318S', 'Ctrl+S'],\n CMD_K: ['\\u2318K', 'Ctrl+K'],\n CMD_DOT: ['\\u2318.', 'Ctrl+.'],\n CMD_A: ['\\u2318A', 'Ctrl+A'],\n CMD_Z: ['\\u2318Z', 'Ctrl+Z'],\n CMD_SHIFT_Z: ['\\u2318\\u21e7Z', 'Ctrl+Shift+Z'],\n ALT_SHIFT_D: ['\\u2325\\u21E7D', 'Alt+Shift+D'],\n ALT_SHIFT_E: ['\\u2325\\u21E7E', 'Alt+Shift+E'],\n ALT_SHIFT_N: ['\\u2325\\u21E7N', 'Alt+Shift+N'],\n} as const;\nconst HERE = isMac ? 0 : 1;\n\n/** Platform-aware modifier symbols */\nexport const MOD = FORMS.MOD[HERE];\nexport const ALT = FORMS.ALT[HERE];\nexport const SHIFT = '\\u21E7';\nexport const ENTER = '\\u23CE';\n\n/** Common shortcut labels */\nexport const CMD_ENTER = FORMS.CMD_ENTER[HERE];\nexport const CMD_S = FORMS.CMD_S[HERE];\nexport const CMD_K = FORMS.CMD_K[HERE];\nexport const CMD_DOT = FORMS.CMD_DOT[HERE];\nexport const CMD_A = FORMS.CMD_A[HERE];\nexport const CMD_Z = FORMS.CMD_Z[HERE];\n/** Redo. Mac has no \\u2318Y convention, so it is the shifted undo there. */\nexport const CMD_SHIFT_Z = FORMS.CMD_SHIFT_Z[HERE];\nexport const ALT_SHIFT_D = FORMS.ALT_SHIFT_D[HERE];\nexport const ALT_SHIFT_E = FORMS.ALT_SHIFT_E[HERE];\nexport const ALT_SHIFT_N = FORMS.ALT_SHIFT_N[HERE];\n\n/**\n * What each constant said on the server, keyed by what it says on this Mac.\n * Empty everywhere else, because a server and a non-Mac reader write every\n * constant the same way and there is nothing to translate.\n */\nconst AS_ON_SERVER: ReadonlyMap<string, string> = new Map(\n isMac ? Object.values(FORMS).map(([mac, other]) => [mac, other] as [string, string]) : [],\n);\n\n/**\n * A shortcut label as it can be shown NOW.\n *\n * The constants are fixed when the module loads, so on a server they are the\n * non-Mac forms and in a Mac reader's browser the \\u2318 forms — and a page\n * hydrating `Ctrl+S` into `\\u2318S` is a mismatch. While hydrating, this hands\n * back the form the server wrote; one render later, the reader's own. A root\n * that was never server-rendered gets the reader's form on its first render,\n * as it always did.\n *\n * Only the constants are recognised. A string written out by hand — `'\\u2318K'`\n * rather than `CMD_K` — cannot be told apart from the Mac constant, so on a\n * server-rendered page write shortcuts with the constants.\n */\nexport function useShortcutLabel(keys: string): string {\n const hydrated = useHydrated();\n return hydrated ? keys : (AS_ON_SERVER.get(keys) ?? keys);\n}\n\nexport type KbdSize = 'sm' | 'md';\n\nexport interface KbdProps {\n /**\n * The shortcut, already written \\u2014 one of the constants above, or any string\n * (`'Esc'`, `'\\u2190'`). This component does NOT assemble a shortcut from\n * modifier flags: which symbol a platform uses is what the constants are\n * for, and two answers to that question is one too many.\n */\n keys: string;\n /**\n * `sm` is the quiet badge that rides inside another control's label \\u2014 the\n * `\\u2325\\u21E7E` on an Edit button. `md` (the default) is the one beside a\n * primary action, where it has to be readable at a glance.\n */\n size?: KbdSize;\n /**\n * Layered on, not replacing: a consumer that themes the badge (the admin\n * portal tints the submit one with its accent) adds its own class here and\n * keeps the shape.\n */\n className?: string;\n}\n\nconst KBD_BASE =\n 'inline-flex items-center justify-center rounded border border-gray-200 bg-gray-50 font-medium text-gray-500';\n\n// A Record keyed by the union, so a new rung without an entry is a compile\n// error rather than an undefined class string.\nconst KBD_SIZES: Record<KbdSize, string> = {\n sm: 'px-1 py-0.5 text-[10px]',\n md: 'px-1.5 py-0.5 text-[11px]',\n};\n\n/**\n * The shortcut badge: a real `<kbd>`, which is what tells a screen reader that\n * `\\u2318\\u23CE` is a key combination and not two pieces of punctuation.\n *\n * It renders the shortcut and nothing else \\u2014 no `aria-label` naming it \"Command\n * Enter\", because the badge is almost always INSIDE the control it belongs to\n * (\"Save \\u2318\\u23CE\") and a second name there would be read as part of the\n * button's own.\n */\nexport function Kbd({ keys, size = 'md', className = '' }: KbdProps) {\n const label = useShortcutLabel(keys);\n return <kbd className={[KBD_BASE, KBD_SIZES[size], className].filter(Boolean).join(' ')}>{label}</kbd>;\n}\n","/**\n * Shell-side user-preferences surface — the package never owns where prefs\n * live. The consumer supplies a hook returning the current prefs object plus\n * a save callback; the shell reads keys it knows about (theme,\n * taskbar_position, taskbar_size, world_clocks, favorite_documents,\n * desktop_folders, desktop_snap, notepad_notes, …) and patches them.\n *\n * When no provider is mounted, the shell falls back to localStorage scoped\n * by `storageKey` — so the package works out of the box for a backend-less\n * consumer.\n */\nimport { createContext, useContext, useCallback, useMemo, type ReactNode } from 'react';\nimport { useBrowserState } from './hydration';\n\nexport interface ShellPrefsAdapter {\n /** The current prefs object. The shell reads its known keys directly off\n * this; consumer-private keys are ignored. */\n prefs: Record<string, any>;\n /** Patch a subset of prefs. The shell calls this with shallow diffs. */\n save: (patch: Record<string, any>) => Promise<void> | void;\n}\n\nconst ShellPrefsContext = createContext<ShellPrefsAdapter | null>(null);\n\nexport function ShellPrefsProvider({\n value,\n children,\n}: { value: ShellPrefsAdapter; children: ReactNode }) {\n return <ShellPrefsContext.Provider value={value}>{children}</ShellPrefsContext.Provider>;\n}\n\n/** Default localStorage-backed adapter — useful when the consumer doesn't\n * ship a backend. Pass the result into <ShellPrefsProvider value={…}>.\n *\n * `defaults` are merged behind whatever's already stored, so they only\n * apply for keys the user hasn't set yet. Useful for opting out of bundled\n * features (e.g. `{ restore_windows: false }`). Note this is the only way to\n * turn a default-ON feature off up front; a default-OFF one like\n * `show_desktop_version` is already off until someone ticks its box. */\nexport function useLocalStoragePrefs(\n storageKey = 'react-os-shell:prefs',\n defaults?: Record<string, any>,\n): ShellPrefsAdapter {\n // Stored prefs are the reader's, so a server renders the defaults and\n // hydration agrees with it; the stored ones land the moment hydration ends.\n // A save that arrives before that — a child's mount effect — is merged into\n // what is STORED, never into the defaults (see `useBrowserState`).\n const [prefs, setPrefs] = useBrowserState<Record<string, any>>(() => {\n try {\n const stored = JSON.parse(localStorage.getItem(storageKey) || '{}');\n return { ...(defaults ?? {}), ...stored };\n } catch { return { ...(defaults ?? {}) }; }\n }, { ...(defaults ?? {}) });\n const save = useCallback((patch: Record<string, any>) => {\n setPrefs(prev => {\n const next = { ...prev, ...patch };\n try { localStorage.setItem(storageKey, JSON.stringify(next)); } catch {}\n return next;\n });\n }, [storageKey]);\n return { prefs, save };\n}\n\n/** Stable no-provider adapter: reads as empty, drops saves. One instance, so\n * a component with no provider above it is not handed a new `save` (and a new\n * effect dependency) on every render. */\nconst NO_PROVIDER: ShellPrefsAdapter = { prefs: {}, save: () => {} };\n\n/** The adapter exactly as the consumer supplied it — its `save` MAY reject.\n *\n * A consumer whose adapter reports a failed write is how the shell knows a\n * write did not land, which is what lets `SessionWindowRestore` retry one\n * rather than record a lost write as saved. That component is the only caller\n * that wants this; everything else wants `useShellPrefs`. Exported from the\n * module for it and for the spec, not from the package index. */\nexport function useShellPrefsAdapter(): ShellPrefsAdapter {\n return useContext(ShellPrefsContext) ?? NO_PROVIDER;\n}\n\n/** Returns the active prefs adapter. When no provider is mounted, reads as\n * empty and silently drops saves — components still render, but persistence\n * is a no-op.\n *\n * `save` here NEVER REJECTS. Nearly every caller fires and forgets —\n * `save({ desktop_bg: bg })` inside an onChange, with the result discarded —\n * and an adapter that reports a failed write turns each of those into an\n * unhandled rejection, one per failed PATCH, across the shell and every\n * consumer. So the rejection is swallowed once here rather than at a dozen\n * call sites that would each have to remember. `await save(…)` still works;\n * it just resolves whether or not the write landed.\n *\n * A caller that must know reads `useShellPrefsAdapter` instead. */\nexport function useShellPrefs(): ShellPrefsAdapter {\n const { prefs, save: rawSave } = useShellPrefsAdapter();\n const save = useCallback((patch: Record<string, any>) => {\n const result = rawSave(patch);\n // Stay thenable for `await save(…)`, but settled either way. Duck-typed:\n // an adapter may hand back any thenable, not a native Promise.\n return result && typeof (result as Promise<void>).then === 'function'\n ? (result as Promise<void>).catch(() => {})\n : result;\n }, [rawSave]);\n return useMemo(() => ({ prefs, save }), [prefs, save]);\n}\n","/**\n * Stale-chunk recovery — reload once when a lazy chunk the running page asks\n * for is no longer on the server.\n *\n * A build names every lazy chunk by its content hash, and a deploy replaces\n * the whole set. A tab opened before the deploy still runs the old entry, and\n * the first lazy window it opens asks for a chunk the server no longer has.\n * The SPA fallback answers with `index.html`, which is not the script the\n * page asked for, and the import fails. Nothing inside the page can satisfy\n * that import — only a fresh document, which names the new chunks, can — so\n * an error boundary's \"try again\" remounts into the same failure, and the\n * only recovery that works is a reload.\n *\n * Two bundlers, two ways to hear it:\n *\n * - **Vite** dispatches `vite:preloadError` on `window` (cancelable;\n * `preventDefault()` swallows the throw), and the import rejects with\n * \"Failed to fetch dynamically imported module\".\n * - **Next.js (Turbopack) and webpack** load a chunk by appending a `<script>`\n * or a stylesheet `<link>`, and a failed one rejects the import with an\n * Error named `ChunkLoadError`. There is no bundler event, but one capture\n * listener on `window`, matching the build's chunk path (`/_next/static/`\n * by default), hears every chunk — the app's lazy pages, the shell's lazy\n * apps, CSS — in one of two ways:\n * - the element's own `error`: a 404, or `index.html` refused under\n * `X-Content-Type-Options: nosniff`. A resource error does not bubble,\n * but it does pass `window` in the capture phase.\n * - without `nosniff` the browser RUNS `index.html` as the script, and a\n * `SyntaxError` whose `filename` is the chunk reaches `window`. Nothing\n * else ever would: Turbopack's loader waits for the chunk to register\n * itself, so the import neither resolves nor rejects.\n *\n * Neither proves a deploy. A dropped connection fails the element too, and\n * Turbopack retries a failed chunk once before it gives up. So before\n * reloading, a `HEAD` request (`no-store`) asks the server whether the file\n * is gone: a 404 or 410, or HTML where a chunk should be (the SPA\n * fallback). A chunk that is still there, a 5xx, or no answer at all\n * (offline) is left to the loader's retry and the crash fallback — a reload\n * would throw the page away for nothing, or land on the browser's offline\n * page.\n *\n * `installStaleChunkReload` listens for both and reloads the page — once per\n * cooldown, remembered in `sessionStorage` under one key whichever signal\n * fired, so a chunk that is STILL missing after the reload (a broken deploy)\n * surfaces as the crash it is rather than as a reload loop that eats the\n * user's open windows.\n *\n * Kit-safe: imports nothing. Call it once, before the app mounts.\n */\n\n/** sessionStorage key holding the epoch-ms of the last reload this made. */\nexport const STALE_CHUNK_RELOAD_KEY = 'react-os-shell:stale-chunk-reload-at';\n\n/**\n * How soon after a reload a second missing chunk is allowed to crash instead\n * of reloading again. A reload plus the shell restoring its windows takes a\n * few seconds; anything under this is the same failure, not a new deploy.\n */\nexport const STALE_CHUNK_RELOAD_COOLDOWN_MS = 30_000;\n\n/** The event name Vite's preload helper dispatches. */\nexport const VITE_PRELOAD_ERROR_EVENT = 'vite:preloadError';\n\n/** Where Next.js serves a build's hashed chunks, under Turbopack or webpack. */\nexport const NEXT_CHUNK_PATH_PREFIX = '/_next/static/';\n\nexport interface StaleChunkReloadOptions {\n /** Defaults to {@link STALE_CHUNK_RELOAD_COOLDOWN_MS}. */\n cooldownMs?: number;\n /** Replaced in tests; the default is `window.location.reload()`. */\n reload?: () => void;\n /**\n * Where the last-reload timestamp is kept. Defaults to `sessionStorage`\n * (guarded — a browser that throws on access, such as a private window\n * with storage disabled, degrades to \"always reload\"). `null` disables the\n * cooldown outright.\n */\n storage?: Pick<Storage, 'getItem' | 'setItem'> | null;\n /** Clock, for tests. */\n now?: () => number;\n /**\n * Where the build serves its chunks: a `<script>` or stylesheet `<link>`\n * under it that fails to load — and that the server confirms is gone —\n * reloads the page. A path, resolved from this page's origin, or a full URL\n * for chunks on another host (Next's `assetPrefix` on a CDN, which must then\n * allow the cross-origin `HEAD` that confirms it). End it with `/`: it is a\n * plain prefix match. Defaults to {@link NEXT_CHUNK_PATH_PREFIX}; a\n * `basePath` app passes `'/<basePath>/_next/static/'`, a webpack app its\n * `output.publicPath`. `null` listens for Vite's event only.\n *\n * Never point it at Vite's `/assets/`: Vite's own event already covers\n * those chunks, and hearing the same failure twice would spend the\n * cooldown on the first and let Vite throw on the second.\n */\n chunkPathPrefix?: string | null;\n}\n\n/**\n * The messages the three engines produce for a dynamic `import()` whose\n * module the server did not return, plus Vite's own line for a CSS chunk it\n * could not preload. Used by the shell's crash fallback to offer \"Reload\n * page\" instead of a remount that cannot succeed.\n */\nconst STALE_CHUNK_MESSAGE =\n /Failed to fetch dynamically imported module|error loading dynamically imported module|Importing a module script failed|Unable to preload CSS/i;\n\n/**\n * The name Turbopack and webpack give the Error a failed chunk rejects with\n * (\"Failed to load chunk /_next/static/chunks/… from module …\", \"Loading\n * chunk 42 failed.\").\n */\nconst CHUNK_LOAD_ERROR_NAME = 'ChunkLoadError';\n\n/** True when `error` is a lazy chunk the server no longer serves. */\nexport function isStaleChunkError(error: unknown): boolean {\n if (error instanceof Error && error.name === CHUNK_LOAD_ERROR_NAME) return true;\n const message =\n error instanceof Error ? error.message : typeof error === 'string' ? error : '';\n return STALE_CHUNK_MESSAGE.test(message);\n}\n\n/**\n * Whether a failed `<link>` was loading code or styles the page needs now: a\n * stylesheet, a module preload, or a preload of a script or a style. A\n * prefetch is speculative — for a page the user may never open — and a font,\n * an image or an icon is not a chunk; reloading for any of those would throw\n * away what the user is doing for nothing. `rel` is matched without regard\n * to case, as the browser matches it.\n */\nfunction linkLoadsChunk(link: HTMLLinkElement): boolean {\n const rels = link.rel.toLowerCase().split(/\\s+/);\n if (rels.includes('stylesheet') || rels.includes('modulepreload')) return true;\n const as = (link.getAttribute('as') ?? '').toLowerCase();\n return rels.includes('preload') && (as === 'script' || as === 'style');\n}\n\n/**\n * The address of the chunk an `error` on `window` is about, when it is one of\n * the build's chunks under `prefix`: a failed `<script>` or chunk `<link>`,\n * or a `SyntaxError` thrown by running a chunk that came back as HTML. Null\n * for anything else — an image, a third party, a runtime error in the app.\n * The constructors are read off `window`, so a document without them as bare\n * globals (a test DOM) or an element from another frame cannot throw here.\n */\nfunction failedChunkUrl(event: Event, prefix: string): string | null {\n const target = event.target;\n let src = '';\n if (target instanceof window.HTMLScriptElement) src = target.src;\n else if (target instanceof window.HTMLLinkElement && linkLoadsChunk(target)) src = target.href;\n else if (event instanceof window.ErrorEvent && (event.error as { name?: unknown } | null)?.name === 'SyntaxError') {\n src = event.filename;\n }\n if (!src) return null;\n try {\n // A path prefix lands on this origin, from its root; a full-URL prefix\n // stays where it points. Then one comparison serves both.\n const base = new URL(prefix, window.location.origin).href;\n const url = new URL(src, window.location.href).href;\n return url.startsWith(base) ? url : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Whether the server no longer has `url`: a 404 or 410, or the SPA fallback's\n * HTML where a chunk should be. Anything else — the file is there, a 5xx, no\n * answer at all — means the load failed for a reason a reload would not fix.\n * `no-store`, so a cached copy cannot answer for the server.\n */\nasync function isGoneFromServer(url: string): Promise<boolean> {\n try {\n const response = await fetch(url, { method: 'HEAD', cache: 'no-store' });\n if (response.status === 404 || response.status === 410) return true;\n return response.ok && /\\btext\\/html\\b/i.test(response.headers.get('content-type') ?? '');\n } catch {\n return false;\n }\n}\n\nfunction defaultStorage(): Pick<Storage, 'getItem' | 'setItem'> | null {\n try {\n const s = window.sessionStorage;\n // Touch it: some browsers expose the object and throw on first use.\n s.getItem(STALE_CHUNK_RELOAD_KEY);\n return s;\n } catch {\n return null;\n }\n}\n\nfunction readLastReload(storage: Pick<Storage, 'getItem' | 'setItem'> | null): number | null {\n if (!storage) return null;\n try {\n const raw = storage.getItem(STALE_CHUNK_RELOAD_KEY);\n const at = raw === null ? NaN : Number(raw);\n return Number.isFinite(at) ? at : null;\n } catch {\n return null;\n }\n}\n\nfunction writeLastReload(storage: Pick<Storage, 'getItem' | 'setItem'> | null, at: number): void {\n if (!storage) return;\n try {\n storage.setItem(STALE_CHUNK_RELOAD_KEY, String(at));\n } catch {\n /* storage full or disabled — the reload still happens, just without the cooldown */\n }\n}\n\n/**\n * Reload the page the first time a lazy chunk fails to load, and let the\n * failure through on a repeat within the cooldown.\n *\n * Returns the uninstaller. Server-side (no `window`) it installs nothing.\n */\nexport function installStaleChunkReload(options: StaleChunkReloadOptions = {}): () => void {\n if (typeof window === 'undefined') return () => {};\n\n const cooldownMs = options.cooldownMs ?? STALE_CHUNK_RELOAD_COOLDOWN_MS;\n const reload = options.reload ?? (() => window.location.reload());\n const now = options.now ?? Date.now;\n const storage = options.storage === undefined ? defaultStorage() : options.storage;\n const chunkPathPrefix =\n options.chunkPathPrefix === undefined ? NEXT_CHUNK_PATH_PREFIX : options.chunkPathPrefix;\n\n /**\n * Whether to reload for this missing chunk — false inside the cooldown.\n * Claims the cooldown when it says yes. Both listeners ask here, so they\n * share one record.\n */\n const claimReload = (chunk: unknown): boolean => {\n const at = now();\n const last = readLastReload(storage);\n if (last !== null && at - last < cooldownMs) {\n // Reloaded moments ago and the chunk is still gone: this is not a\n // deploy the page missed, it is a server that cannot serve the build.\n // Let the import fail, so the boundary shows what is wrong.\n console.error(\n '[efficient-shell] a lazy chunk is still missing after a reload; letting the failure through:',\n chunk,\n );\n return false;\n }\n writeLastReload(storage, at);\n console.warn(\n '[efficient-shell] a lazy chunk is no longer on the server (new deploy?); reloading onto the current build:',\n chunk,\n );\n return true;\n };\n\n const onPreloadError = (event: Event) => {\n const payload = (event as Event & { payload?: unknown }).payload;\n // Vite dispatches this for ANY rejected dynamic import it wraps, not only\n // a missing chunk — an optional peer probed by its bare package name\n // rejects the same way, and its caller already catches that.\n // Reloading on that threw the whole portal away on every DXF preview.\n if (!isStaleChunkError(payload) || !claimReload(payload)) return;\n event.preventDefault();\n reload();\n };\n\n // The chunk listener asks the server before it reloads, so its decision is\n // async. One question per chunk at a time (Turbopack's retry fails the same\n // file again while the first is out), none once a reload has started (the\n // page is going), and none acted on after uninstall.\n let active = true;\n let reloading = false;\n const asking = new Set<string>();\n\n // Capture phase: a resource error does not bubble.\n const onChunkError = chunkPathPrefix === null ? null : (event: Event) => {\n const chunk = failedChunkUrl(event, chunkPathPrefix);\n if (!chunk || reloading || asking.has(chunk)) return;\n asking.add(chunk);\n void isGoneFromServer(chunk).then((gone) => {\n asking.delete(chunk);\n if (!gone || !active || reloading || !claimReload(chunk)) return;\n reloading = true;\n reload();\n });\n };\n\n window.addEventListener(VITE_PRELOAD_ERROR_EVENT, onPreloadError);\n if (onChunkError) window.addEventListener('error', onChunkError, true);\n return () => {\n active = false;\n window.removeEventListener(VITE_PRELOAD_ERROR_EVENT, onPreloadError);\n if (onChunkError) window.removeEventListener('error', onChunkError, true);\n };\n}\n"]}
|
package/dist/chunk-4P44JXDS.js
DELETED
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
import { currentShellStrings } from './chunk-72CQWN7O.js';
|
|
2
|
-
|
|
3
|
-
// src/shell/toast.ts
|
|
4
|
-
var TOAST_CONTAINER_ID = "toast-container";
|
|
5
|
-
var TOAST_BOTTOM_CONTAINER_ID = "toast-container-bottom";
|
|
6
|
-
var NOTIF_CONTAINER_ID = "notif-container";
|
|
7
|
-
var FADE_MS = 300;
|
|
8
|
-
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
9
|
-
var defaults = {};
|
|
10
|
-
var live = /* @__PURE__ */ new Map();
|
|
11
|
-
function getOrCreate(id, className) {
|
|
12
|
-
let el = document.getElementById(id);
|
|
13
|
-
if (!el) {
|
|
14
|
-
el = document.createElement("div");
|
|
15
|
-
el.id = id;
|
|
16
|
-
el.className = className;
|
|
17
|
-
document.body.appendChild(el);
|
|
18
|
-
}
|
|
19
|
-
return el;
|
|
20
|
-
}
|
|
21
|
-
var GLYPHS = {
|
|
22
|
-
success: "M5 13l4 4L19 7",
|
|
23
|
-
error: "M6 18L18 6M6 6l12 12",
|
|
24
|
-
warning: "M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z",
|
|
25
|
-
info: "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z",
|
|
26
|
-
loading: "M12 3a9 9 0 019 9",
|
|
27
|
-
bell: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0"
|
|
28
|
-
};
|
|
29
|
-
function glyph(name, className) {
|
|
30
|
-
const svg = document.createElementNS(SVG_NS, "svg");
|
|
31
|
-
svg.setAttribute("class", className);
|
|
32
|
-
svg.setAttribute("fill", "none");
|
|
33
|
-
svg.setAttribute("viewBox", "0 0 24 24");
|
|
34
|
-
svg.setAttribute("stroke", "currentColor");
|
|
35
|
-
svg.setAttribute("stroke-width", "2");
|
|
36
|
-
const path = document.createElementNS(SVG_NS, "path");
|
|
37
|
-
path.setAttribute("stroke-linecap", "round");
|
|
38
|
-
if (name !== "loading") path.setAttribute("stroke-linejoin", "round");
|
|
39
|
-
path.setAttribute("d", GLYPHS[name]);
|
|
40
|
-
svg.appendChild(path);
|
|
41
|
-
return svg;
|
|
42
|
-
}
|
|
43
|
-
function div(className, text) {
|
|
44
|
-
const el = document.createElement("div");
|
|
45
|
-
el.className = className;
|
|
46
|
-
if (text !== void 0) el.textContent = text;
|
|
47
|
-
return el;
|
|
48
|
-
}
|
|
49
|
-
function showToast(variant, message, opts) {
|
|
50
|
-
const opts_ = { ...defaults, ...opts };
|
|
51
|
-
const placement = opts_.placement ?? "top";
|
|
52
|
-
const sticky = opts_.sticky ?? false;
|
|
53
|
-
const key = `${placement}|${variant}|${message}`;
|
|
54
|
-
if (opts_.dedupe) {
|
|
55
|
-
const existing = live.get(key);
|
|
56
|
-
if (existing) {
|
|
57
|
-
existing.restart();
|
|
58
|
-
return { dismiss: existing.dismiss };
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (variant !== "loading") {
|
|
62
|
-
import('./sounds-NT4DEZGD.js').then((s) => {
|
|
63
|
-
if (variant === "success") s.playSuccess();
|
|
64
|
-
else if (variant === "error") s.playError();
|
|
65
|
-
else s.playNotification();
|
|
66
|
-
}).catch(() => {
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
const container = placement === "bottom" ? getOrCreate(TOAST_BOTTOM_CONTAINER_ID, "fixed bottom-4 left-1/2 -translate-x-1/2 z-[9999] flex flex-col-reverse gap-2 items-center pointer-events-none") : getOrCreate(TOAST_CONTAINER_ID, "fixed top-4 left-1/2 -translate-x-1/2 z-[9999] flex flex-col gap-2 items-center pointer-events-none");
|
|
70
|
-
const offscreen = placement === "bottom" ? "translateY(10px)" : "translateY(-10px)";
|
|
71
|
-
const el = div("pointer-events-auto cursor-pointer rosh-toast");
|
|
72
|
-
el.style.opacity = "0";
|
|
73
|
-
el.style.transform = `${offscreen} scale(0.95)`;
|
|
74
|
-
el.setAttribute("role", variant === "error" ? "alert" : "status");
|
|
75
|
-
el.setAttribute("aria-atomic", "true");
|
|
76
|
-
el.appendChild(glyph(variant, `h-4 w-4 rosh-tone-${variant}${variant === "loading" ? " animate-spin" : ""}`));
|
|
77
|
-
const span = document.createElement("span");
|
|
78
|
-
span.textContent = message;
|
|
79
|
-
el.appendChild(span);
|
|
80
|
-
container.appendChild(el);
|
|
81
|
-
requestAnimationFrame(() => {
|
|
82
|
-
el.style.opacity = "1";
|
|
83
|
-
el.style.transform = "translateY(0) scale(1)";
|
|
84
|
-
});
|
|
85
|
-
let timer;
|
|
86
|
-
let gone = false;
|
|
87
|
-
const dismiss = () => {
|
|
88
|
-
if (gone) return;
|
|
89
|
-
gone = true;
|
|
90
|
-
if (timer) clearTimeout(timer);
|
|
91
|
-
live.delete(key);
|
|
92
|
-
el.style.opacity = "0";
|
|
93
|
-
el.style.transform = `${offscreen} scale(0.95)`;
|
|
94
|
-
setTimeout(() => el.remove(), FADE_MS);
|
|
95
|
-
};
|
|
96
|
-
const duration = opts_.duration ?? (variant === "info" ? 4500 : 3e3);
|
|
97
|
-
const restart = () => {
|
|
98
|
-
if (timer) clearTimeout(timer);
|
|
99
|
-
if (!sticky) timer = setTimeout(dismiss, duration);
|
|
100
|
-
};
|
|
101
|
-
restart();
|
|
102
|
-
el.addEventListener("mouseenter", () => {
|
|
103
|
-
if (timer) clearTimeout(timer);
|
|
104
|
-
});
|
|
105
|
-
el.addEventListener("mouseleave", () => {
|
|
106
|
-
if (!gone) restart();
|
|
107
|
-
});
|
|
108
|
-
el.addEventListener("click", dismiss);
|
|
109
|
-
live.set(key, { el, restart, dismiss });
|
|
110
|
-
return { dismiss };
|
|
111
|
-
}
|
|
112
|
-
function showNotification(message, opts) {
|
|
113
|
-
import('./sounds-NT4DEZGD.js').then((s) => s.playNotification()).catch(() => {
|
|
114
|
-
});
|
|
115
|
-
const container = getOrCreate(NOTIF_CONTAINER_ID, "fixed top-4 right-4 z-[9999] flex flex-col gap-3 items-end pointer-events-none");
|
|
116
|
-
const el = div("pointer-events-auto cursor-pointer rosh-notif");
|
|
117
|
-
el.style.opacity = "0";
|
|
118
|
-
el.style.transform = "translateX(30px) scale(0.95)";
|
|
119
|
-
const badge = div("rosh-notif-badge");
|
|
120
|
-
badge.appendChild(glyph("bell", "h-5 w-5"));
|
|
121
|
-
const body = div("rosh-notif-body");
|
|
122
|
-
body.append(div("rosh-notif-title", currentShellStrings().toast.notification), div("notif-msg rosh-notif-msg", message));
|
|
123
|
-
const close = document.createElement("button");
|
|
124
|
-
close.className = "rosh-notif-close";
|
|
125
|
-
close.textContent = "\xD7";
|
|
126
|
-
el.append(badge, body, close);
|
|
127
|
-
const dismiss = () => {
|
|
128
|
-
el.style.opacity = "0";
|
|
129
|
-
el.style.transform = "translateX(30px) scale(0.95)";
|
|
130
|
-
setTimeout(() => el.remove(), FADE_MS);
|
|
131
|
-
};
|
|
132
|
-
close.addEventListener("click", (e) => {
|
|
133
|
-
e.stopPropagation();
|
|
134
|
-
dismiss();
|
|
135
|
-
});
|
|
136
|
-
el.addEventListener("click", dismiss);
|
|
137
|
-
container.appendChild(el);
|
|
138
|
-
requestAnimationFrame(() => {
|
|
139
|
-
el.style.opacity = "1";
|
|
140
|
-
el.style.transform = "translateX(0) scale(1)";
|
|
141
|
-
});
|
|
142
|
-
setTimeout(dismiss, opts?.duration ?? 1e4);
|
|
143
|
-
}
|
|
144
|
-
var toast = {
|
|
145
|
-
success: (message, opts) => showToast("success", message, opts),
|
|
146
|
-
error: (message, opts) => showToast("error", message, opts),
|
|
147
|
-
/**
|
|
148
|
-
* Something the user should read before continuing — a partial success, a
|
|
149
|
-
* setting that will not apply until they do something else. Distinct from
|
|
150
|
-
* `error`, which is "this did not happen".
|
|
151
|
-
*/
|
|
152
|
-
warning: (message, opts) => showToast("warning", message, opts),
|
|
153
|
-
info: (message, opts) => showToast("info", message, opts),
|
|
154
|
-
// Persistent top-right notification card (the old toast.info presentation).
|
|
155
|
-
notify: (message, opts) => showNotification(message, opts),
|
|
156
|
-
/**
|
|
157
|
-
* One toast for one async operation: a spinning "loading" toast while `p`
|
|
158
|
-
* is pending, swapped for a success or error toast when it settles. The
|
|
159
|
-
* promise is returned untouched, so `await toast.promise(save(), …)` still
|
|
160
|
-
* throws to the caller — this narrates the operation, it does not handle it.
|
|
161
|
-
*
|
|
162
|
-
* `error` is REQUIRED, and there is deliberately no fallback that prints
|
|
163
|
-
* the exception: a raw `e.message` in a toast is how internals leak to the
|
|
164
|
-
* screen (the same reasoning that keeps ErrorBoundary's stack behind
|
|
165
|
-
* `showDetails`). The success/error messages may be functions of the
|
|
166
|
-
* resolved value / the rejection, for the "Saved 3 rows" case.
|
|
167
|
-
*/
|
|
168
|
-
promise: (p, msgs, opts) => {
|
|
169
|
-
const pending = showToast("loading", msgs.loading, { ...opts, sticky: true });
|
|
170
|
-
p.then(
|
|
171
|
-
(value) => {
|
|
172
|
-
pending.dismiss();
|
|
173
|
-
showToast("success", typeof msgs.success === "function" ? msgs.success(value) : msgs.success, opts);
|
|
174
|
-
},
|
|
175
|
-
(error) => {
|
|
176
|
-
pending.dismiss();
|
|
177
|
-
showToast("error", typeof msgs.error === "function" ? msgs.error(error) : msgs.error, opts);
|
|
178
|
-
}
|
|
179
|
-
);
|
|
180
|
-
return p;
|
|
181
|
-
},
|
|
182
|
-
/**
|
|
183
|
-
* Set defaults for every subsequent toast. Call once at app startup; later
|
|
184
|
-
* calls replace the whole object rather than merging, so a consumer sets its
|
|
185
|
-
* policy in one place. Per-call options still take precedence.
|
|
186
|
-
*/
|
|
187
|
-
configure: (next) => {
|
|
188
|
-
defaults = { ...next };
|
|
189
|
-
}
|
|
190
|
-
};
|
|
191
|
-
var toast_default = toast;
|
|
192
|
-
|
|
193
|
-
export { toast_default };
|
|
194
|
-
//# sourceMappingURL=chunk-4P44JXDS.js.map
|
|
195
|
-
//# sourceMappingURL=chunk-4P44JXDS.js.map
|