efficient-shell 4.126.4 → 4.131.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/README.md +972 -4
  2. package/dist/{Browser-IIVSJJIO.js → Browser-PSEMJFZE.js} +13 -9
  3. package/dist/Browser-PSEMJFZE.js.map +1 -0
  4. package/dist/{Calculator-HCKFTSJR.js → Calculator-ZXJPXG7F.js} +12 -8
  5. package/dist/Calculator-ZXJPXG7F.js.map +1 -0
  6. package/dist/ConfirmDialog-MTC7QMUJ.js +4 -0
  7. package/dist/{ConfirmDialog-LJXMB45A.js.map → ConfirmDialog-MTC7QMUJ.js.map} +1 -1
  8. package/dist/{CurrencyConverter-BKKORN6K.js → CurrencyConverter-WSJ2BBSX.js} +12 -8
  9. package/dist/CurrencyConverter-WSJ2BBSX.js.map +1 -0
  10. package/dist/{Documents-MIU3AWGL.js → Documents-PGMZR2MA.js} +14 -10
  11. package/dist/Documents-PGMZR2MA.js.map +1 -0
  12. package/dist/{Files-N2P2LJ5R.js → Files-2LKCJGYW.js} +17 -13
  13. package/dist/Files-2LKCJGYW.js.map +1 -0
  14. package/dist/{Notepad-L775LQBJ.js → Notepad-KW6WVABH.js} +15 -11
  15. package/dist/Notepad-KW6WVABH.js.map +1 -0
  16. package/dist/PdfViewer-M2YGZIYX.js +5 -0
  17. package/dist/{PdfViewer-LSP3YNFC.js.map → PdfViewer-M2YGZIYX.js.map} +1 -1
  18. package/dist/{PomodoroTimer-SVJ62RXM.js → PomodoroTimer-DG3LI5CX.js} +14 -10
  19. package/dist/PomodoroTimer-DG3LI5CX.js.map +1 -0
  20. package/dist/{Preview-G56SXZU4.js → Preview-E7EJJNXN.js} +16 -12
  21. package/dist/Preview-E7EJJNXN.js.map +1 -0
  22. package/dist/{Sidebar-J76PV4QF.js → Sidebar-BPU7RCZP.js} +5 -4
  23. package/dist/Sidebar-BPU7RCZP.js.map +1 -0
  24. package/dist/{Spreadsheet-ZP5KSNLJ.js → Spreadsheet-IDUODRZU.js} +14 -10
  25. package/dist/Spreadsheet-IDUODRZU.js.map +1 -0
  26. package/dist/{Stock-CDUS4VCZ.js → Stock-YMPOMUAW.js} +12 -8
  27. package/dist/Stock-YMPOMUAW.js.map +1 -0
  28. package/dist/{Weather-EEDBWBPQ.js → Weather-NZO3CWLH.js} +12 -8
  29. package/dist/Weather-NZO3CWLH.js.map +1 -0
  30. package/dist/{WorldClock-FFFULVTJ.js → WorldClock-HUC6D3AD.js} +12 -8
  31. package/dist/WorldClock-HUC6D3AD.js.map +1 -0
  32. package/dist/apps/index.js +26 -21
  33. package/dist/apps/index.js.map +1 -1
  34. package/dist/brand.css +1 -1
  35. package/dist/{chunk-N2CMEDSH.js → chunk-2GZQ352J.js} +4 -4
  36. package/dist/{chunk-N2CMEDSH.js.map → chunk-2GZQ352J.js.map} +1 -1
  37. package/dist/chunk-7IN7YZAL.js +547 -0
  38. package/dist/chunk-7IN7YZAL.js.map +1 -0
  39. package/dist/{chunk-YNGPTOL6.js → chunk-7MA5XBWD.js} +3 -3
  40. package/dist/{chunk-YNGPTOL6.js.map → chunk-7MA5XBWD.js.map} +1 -1
  41. package/dist/{chunk-4TVV2BIU.js → chunk-BJ34QOR3.js} +827 -624
  42. package/dist/chunk-BJ34QOR3.js.map +1 -0
  43. package/dist/{chunk-HNH7FOYB.js → chunk-CGXMWHQW.js} +7 -6
  44. package/dist/chunk-CGXMWHQW.js.map +1 -0
  45. package/dist/{chunk-N3CG5HG5.js → chunk-CLGNTGC5.js} +12 -11
  46. package/dist/chunk-CLGNTGC5.js.map +1 -0
  47. package/dist/chunk-D276EMXS.js +57 -0
  48. package/dist/chunk-D276EMXS.js.map +1 -0
  49. package/dist/{chunk-7KIOEKHS.js → chunk-E3TWIN7Z.js} +21 -135
  50. package/dist/chunk-E3TWIN7Z.js.map +1 -0
  51. package/dist/{chunk-2VM2FRZJ.js → chunk-EENVXIVU.js} +47 -67
  52. package/dist/chunk-EENVXIVU.js.map +1 -0
  53. package/dist/{chunk-YG45DAUT.js → chunk-FONEQRBH.js} +17 -11
  54. package/dist/chunk-FONEQRBH.js.map +1 -0
  55. package/dist/chunk-IPXN646P.js +14 -0
  56. package/dist/chunk-IPXN646P.js.map +1 -0
  57. package/dist/chunk-IRWSRJ4K.js +48 -0
  58. package/dist/chunk-IRWSRJ4K.js.map +1 -0
  59. package/dist/{chunk-JFQGPY7W.js → chunk-KWEX4ZAF.js} +20 -17
  60. package/dist/chunk-KWEX4ZAF.js.map +1 -0
  61. package/dist/chunk-LQTVTOSY.js +117 -0
  62. package/dist/chunk-LQTVTOSY.js.map +1 -0
  63. package/dist/{chunk-DMCFOWOJ.js → chunk-MQPX6ERJ.js} +4 -4
  64. package/dist/{chunk-DMCFOWOJ.js.map → chunk-MQPX6ERJ.js.map} +1 -1
  65. package/dist/{chunk-FQB24B42.js → chunk-SEWF4O3H.js} +3 -3
  66. package/dist/{chunk-FQB24B42.js.map → chunk-SEWF4O3H.js.map} +1 -1
  67. package/dist/{chunk-AXWC3332.js → chunk-TFXJRHJV.js} +3 -3
  68. package/dist/{chunk-AXWC3332.js.map → chunk-TFXJRHJV.js.map} +1 -1
  69. package/dist/{chunk-YNHLQ24V.js → chunk-TQURTLK2.js} +59 -143
  70. package/dist/chunk-TQURTLK2.js.map +1 -0
  71. package/dist/{chunk-6XQHH7D2.js → chunk-TRCWINHF.js} +5 -5
  72. package/dist/{chunk-6XQHH7D2.js.map → chunk-TRCWINHF.js.map} +1 -1
  73. package/dist/chunk-UHPWZ2F4.js +7 -0
  74. package/dist/{chunk-K6ZT6MWE.js.map → chunk-UHPWZ2F4.js.map} +1 -1
  75. package/dist/{chunk-32W6VY2J.js → chunk-VWZIGZFF.js} +4 -4
  76. package/dist/{chunk-32W6VY2J.js.map → chunk-VWZIGZFF.js.map} +1 -1
  77. package/dist/{chunk-HYZ5QMVO.js → chunk-XH3ELPQZ.js} +22 -19
  78. package/dist/chunk-XH3ELPQZ.js.map +1 -0
  79. package/dist/{chunk-W6XTG23K.js → chunk-ZKHD4J73.js} +8 -6
  80. package/dist/chunk-ZKHD4J73.js.map +1 -0
  81. package/dist/file-intake/index.js +3 -1
  82. package/dist/file-intake/index.js.map +1 -1
  83. package/dist/{index-dQia6NpB.d.ts → index-COwksV6G.d.ts} +699 -199
  84. package/dist/index.d.ts +2 -2
  85. package/dist/index.js +38 -31
  86. package/dist/index.js.map +1 -1
  87. package/dist/map/index.d.ts +329 -0
  88. package/dist/map/index.js +541 -0
  89. package/dist/map/index.js.map +1 -0
  90. package/dist/markdown/index.js +4 -3
  91. package/dist/markdown/index.js.map +1 -1
  92. package/dist/page-tabs/index.js +12 -8
  93. package/dist/page-tabs/index.js.map +1 -1
  94. package/dist/shell.css +17 -17
  95. package/dist/themes.css +15 -0
  96. package/dist/ui/index.d.ts +1 -1
  97. package/dist/ui/index.js +17 -12
  98. package/dist/ui/index.js.map +1 -1
  99. package/dist/ui.css +673 -283
  100. package/package.json +11 -1
  101. package/dist/Browser-IIVSJJIO.js.map +0 -1
  102. package/dist/Calculator-HCKFTSJR.js.map +0 -1
  103. package/dist/ConfirmDialog-LJXMB45A.js +0 -3
  104. package/dist/CurrencyConverter-BKKORN6K.js.map +0 -1
  105. package/dist/Documents-MIU3AWGL.js.map +0 -1
  106. package/dist/Files-N2P2LJ5R.js.map +0 -1
  107. package/dist/Notepad-L775LQBJ.js.map +0 -1
  108. package/dist/PdfViewer-LSP3YNFC.js +0 -4
  109. package/dist/PomodoroTimer-SVJ62RXM.js.map +0 -1
  110. package/dist/Preview-G56SXZU4.js.map +0 -1
  111. package/dist/Sidebar-J76PV4QF.js.map +0 -1
  112. package/dist/Spreadsheet-ZP5KSNLJ.js.map +0 -1
  113. package/dist/Stock-CDUS4VCZ.js.map +0 -1
  114. package/dist/Weather-EEDBWBPQ.js.map +0 -1
  115. package/dist/WorldClock-FFFULVTJ.js.map +0 -1
  116. package/dist/chunk-2VM2FRZJ.js.map +0 -1
  117. package/dist/chunk-3CUSBZWG.js +0 -59
  118. package/dist/chunk-3CUSBZWG.js.map +0 -1
  119. package/dist/chunk-4TVV2BIU.js.map +0 -1
  120. package/dist/chunk-7KIOEKHS.js.map +0 -1
  121. package/dist/chunk-HNH7FOYB.js.map +0 -1
  122. package/dist/chunk-HYZ5QMVO.js.map +0 -1
  123. package/dist/chunk-JFQGPY7W.js.map +0 -1
  124. package/dist/chunk-K6ZT6MWE.js +0 -7
  125. package/dist/chunk-N3CG5HG5.js.map +0 -1
  126. package/dist/chunk-W6XTG23K.js.map +0 -1
  127. package/dist/chunk-YG45DAUT.js.map +0 -1
  128. package/dist/chunk-YNHLQ24V.js.map +0 -1
@@ -1,116 +1,8 @@
1
- import { forwardRef, useId, createContext, useSyncExternalStore, useState, useCallback, useContext, useMemo } from 'react';
1
+ import { useShellStrings } from './chunk-7IN7YZAL.js';
2
+ import { useHydrated, useBrowserState } from './chunk-IRWSRJ4K.js';
3
+ import { createContext, useSyncExternalStore, useCallback, useContext, useMemo } from 'react';
2
4
  import { jsxs, jsx } from 'react/jsx-runtime';
3
5
 
4
- // src/forms/Button.tsx
5
- var BUTTON_BASE = "inline-flex items-center justify-center rounded-md font-medium transition-colors focus:outline-none focus:ring-2 disabled:cursor-not-allowed disabled:opacity-60";
6
- var BUTTON_VARIANTS = {
7
- primary: "bg-blue-600 text-white shadow-sm hover:bg-blue-700 focus:ring-blue-400/40",
8
- secondary: "border border-gray-300 bg-white text-gray-700 shadow-sm hover:bg-gray-50 focus:ring-blue-400/30",
9
- ghost: "text-gray-700 hover:bg-gray-100 focus:ring-blue-400/30",
10
- "ghost-danger": "text-red-600 hover:bg-red-50 focus:ring-red-400/30",
11
- danger: "bg-red-600 text-white shadow-sm hover:bg-red-700 focus:ring-red-400/40",
12
- /**
13
- * A button that reads as a link: no box, no padding, underlined on hover.
14
- * For an action that belongs in running text or beside a field — "Forgot
15
- * your password?", "Use a different address" — where a boxed button would
16
- * claim more of the page than the action deserves.
17
- *
18
- * It is still a <button>. Anything that NAVIGATES should be an anchor, so it
19
- * can be middle-clicked and read off the status bar; this is for actions
20
- * that merely look quiet.
21
- */
22
- link: "text-blue-600 underline-offset-4 hover:underline focus:ring-blue-400/30"
23
- };
24
- var SIZES = {
25
- sm: "gap-1 px-2.5 py-1 text-xs",
26
- md: "gap-1.5 px-3 py-1.5 text-sm",
27
- // `py-2.5`, not `py-2`: this rung has to come out 40px to match IconButton's
28
- // `h-10`, which is the promise IconButton's docblock makes for every rung.
29
- // `py-2` gives 36px (20px line box + 8px twice) and puts a 4px step between a
30
- // Button and an IconButton sitting in the same row.
31
- lg: "gap-2 px-4 py-2.5 text-sm",
32
- // 44px is the WCAG 2.5.5 floor, and a floor is not a comfortable size. Use it
33
- // ONLY for chrome that sits outside the task — switching screens, ending a
34
- // shift — and never on the path someone is actually working through. It
35
- // exists so a dense toolbar has something legitimate to reach for instead of
36
- // borrowing the desktop `sm`, which is half this height.
37
- "touch-sm": "gap-1.5 h-11 px-4 text-base",
38
- "touch": "gap-2 h-14 px-5 text-base",
39
- // 56px — the comfortable default
40
- "touch-lg": "gap-2 h-16 px-6 text-lg",
41
- // 64px — primary action on a page
42
- "touch-xl": "gap-3 h-20 px-8 text-2xl"
43
- // 80px — keypad keys, tender
44
- };
45
- var LINK_BASE = "inline-flex items-center font-medium transition-colors focus:outline-none focus:ring-2 disabled:cursor-not-allowed disabled:opacity-60";
46
- var LINK_SIZES = {
47
- sm: "gap-1 text-xs",
48
- md: "gap-1.5 text-sm",
49
- lg: "gap-2 text-sm",
50
- "touch-sm": "gap-1.5 text-base",
51
- "touch": "gap-2 text-base",
52
- "touch-lg": "gap-2 text-lg",
53
- "touch-xl": "gap-3 text-2xl"
54
- };
55
- function Spinner() {
56
- return /* @__PURE__ */ jsxs("svg", { className: "h-3.5 w-3.5 animate-spin", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
57
- /* @__PURE__ */ jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
58
- /* @__PURE__ */ jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" })
59
- ] });
60
- }
61
- var Button = forwardRef(function Button2({
62
- variant = "primary",
63
- size = "md",
64
- loading = false,
65
- leftIcon,
66
- rightIcon,
67
- block = false,
68
- disabled,
69
- type = "button",
70
- children,
71
- className = "",
72
- disabledReason,
73
- ...rest
74
- }, ref) {
75
- const generatedId = useId();
76
- const isDisabled = disabled || loading;
77
- const showReason = isDisabled && disabledReason != null && disabledReason !== "";
78
- const reasonId = showReason ? generatedId : void 0;
79
- const button = /* @__PURE__ */ jsxs(
80
- "button",
81
- {
82
- ref,
83
- type,
84
- disabled: isDisabled,
85
- "aria-busy": loading || void 0,
86
- "aria-describedby": reasonId,
87
- className: [
88
- // `link` takes the base WITHOUT the box: no rounding, no padding from
89
- // the size table. It cannot cancel those by overriding — two padding
90
- // utilities in one class attribute resolve by compiled-stylesheet
91
- // order, not by the order they were written — so it never receives
92
- // them, and keeps only the size's gap and text size.
93
- variant === "link" ? LINK_BASE : BUTTON_BASE,
94
- BUTTON_VARIANTS[variant],
95
- variant === "link" ? LINK_SIZES[size] : SIZES[size],
96
- block ? "w-full" : "",
97
- className
98
- ].filter(Boolean).join(" "),
99
- ...rest,
100
- children: [
101
- loading ? /* @__PURE__ */ jsx(Spinner, {}) : leftIcon,
102
- children,
103
- !loading && rightIcon
104
- ]
105
- }
106
- );
107
- if (!showReason) return button;
108
- return /* @__PURE__ */ jsxs("span", { className: block ? "flex w-full flex-col gap-1" : "inline-flex flex-col items-start gap-1", children: [
109
- button,
110
- /* @__PURE__ */ jsx("span", { id: reasonId, className: "text-xs text-red-600", children: disabledReason })
111
- ] });
112
- });
113
- var Button_default = Button;
114
6
  var QUERY = "(max-width: 767px), (pointer: coarse)";
115
7
  function getSnapshot() {
116
8
  if (typeof window === "undefined" || !window.matchMedia) return false;
@@ -151,9 +43,9 @@ var TONE_CLASS = {
151
43
  info: "text-blue-600 bg-blue-100"
152
44
  };
153
45
  var DEFAULT_TITLE = {
154
- 404: "Page not found",
155
- 403: "You don't have access to this",
156
- 500: "Something went wrong"
46
+ 404: (errors) => errors.notFound,
47
+ 403: (errors) => errors.noAccess,
48
+ 500: (errors) => errors.serverError
157
49
  };
158
50
  function StatusIcon({ tone }) {
159
51
  const common = { className: "h-6 w-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, "aria-hidden": true };
@@ -178,6 +70,7 @@ function Result({
178
70
  className = ""
179
71
  }) {
180
72
  const tone = STATUS_TONE[status];
73
+ const errors = useShellStrings().errors;
181
74
  const announces = tone === "error";
182
75
  return /* @__PURE__ */ jsxs(
183
76
  "div",
@@ -186,7 +79,7 @@ function Result({
186
79
  className: `flex flex-col items-center justify-center px-6 py-12 text-center ${className}`.trim(),
187
80
  children: [
188
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 }) }),
189
- /* @__PURE__ */ jsx("h2", { className: "mt-4 text-lg font-semibold text-gray-900", children: title ?? DEFAULT_TITLE[status] ?? "" }),
82
+ /* @__PURE__ */ jsx("h2", { className: "mt-4 text-lg font-semibold text-gray-900", children: title ?? DEFAULT_TITLE[status]?.(errors) ?? "" }),
190
83
  subTitle && /* @__PURE__ */ jsx("p", { className: "mt-1 max-w-md text-sm text-gray-500", children: subTitle }),
191
84
  children && /* @__PURE__ */ jsx("div", { className: "mt-4 w-full max-w-md text-left", children }),
192
85
  extra && /* @__PURE__ */ jsx("div", { className: "mt-6 flex flex-wrap items-center justify-center gap-3", children: extra })
@@ -205,6 +98,52 @@ function LoadingSpinner({ size = "md", padding = "py-12", label, className = ""
205
98
  /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500", children: label })
206
99
  ] });
207
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
+ }
208
147
  var ShellPrefsContext = createContext(null);
209
148
  function ShellPrefsProvider({
210
149
  value,
@@ -213,14 +152,14 @@ function ShellPrefsProvider({
213
152
  return /* @__PURE__ */ jsx(ShellPrefsContext.Provider, { value, children });
214
153
  }
215
154
  function useLocalStoragePrefs(storageKey = "react-os-shell:prefs", defaults) {
216
- const [prefs, setPrefs] = useState(() => {
155
+ const [prefs, setPrefs] = useBrowserState(() => {
217
156
  try {
218
157
  const stored = JSON.parse(localStorage.getItem(storageKey) || "{}");
219
158
  return { ...defaults ?? {}, ...stored };
220
159
  } catch {
221
160
  return { ...defaults ?? {} };
222
161
  }
223
- });
162
+ }, { ...defaults ?? {} });
224
163
  const save = useCallback((patch) => {
225
164
  setPrefs((prev) => {
226
165
  const next = { ...prev, ...patch };
@@ -371,30 +310,7 @@ function installStaleChunkReload(options = {}) {
371
310
  if (onChunkError) window.removeEventListener("error", onChunkError, true);
372
311
  };
373
312
  }
374
- var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent);
375
- var MOD = isMac ? "\u2318" : "Ctrl";
376
- var ALT = isMac ? "\u2325" : "Alt";
377
- var SHIFT = "\u21E7";
378
- var ENTER = "\u23CE";
379
- var CMD_ENTER = isMac ? "\u2318\u23CE" : "Ctrl\u23CE";
380
- var CMD_S = isMac ? "\u2318S" : "Ctrl+S";
381
- var CMD_K = isMac ? "\u2318K" : "Ctrl+K";
382
- var CMD_DOT = isMac ? "\u2318." : "Ctrl+.";
383
- var CMD_A = isMac ? "\u2318A" : "Ctrl+A";
384
- var CMD_Z = isMac ? "\u2318Z" : "Ctrl+Z";
385
- var CMD_SHIFT_Z = isMac ? "\u2318\u21E7Z" : "Ctrl+Shift+Z";
386
- var ALT_SHIFT_D = isMac ? "\u2325\u21E7D" : "Alt+Shift+D";
387
- var ALT_SHIFT_E = isMac ? "\u2325\u21E7E" : "Alt+Shift+E";
388
- var ALT_SHIFT_N = isMac ? "\u2325\u21E7N" : "Alt+Shift+N";
389
- var KBD_BASE = "inline-flex items-center justify-center rounded border border-gray-200 bg-gray-50 font-medium text-gray-500";
390
- var KBD_SIZES = {
391
- sm: "px-1 py-0.5 text-[10px]",
392
- md: "px-1.5 py-0.5 text-[11px]"
393
- };
394
- function Kbd({ keys, size = "md", className = "" }) {
395
- return /* @__PURE__ */ jsx("kbd", { className: [KBD_BASE, KBD_SIZES[size], className].filter(Boolean).join(" "), children: keys });
396
- }
397
313
 
398
- export { ALT, ALT_SHIFT_D, ALT_SHIFT_E, ALT_SHIFT_N, BUTTON_BASE, BUTTON_VARIANTS, Button_default, 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 };
399
- //# sourceMappingURL=chunk-YNHLQ24V.js.map
400
- //# sourceMappingURL=chunk-YNHLQ24V.js.map
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-TQURTLK2.js.map
316
+ //# sourceMappingURL=chunk-TQURTLK2.js.map
@@ -0,0 +1 @@
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-TQURTLK2.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 '[react-os-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 '[react-os-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"]}
@@ -17,9 +17,9 @@ function resolveBrandMarkTreatment(hasAlpha, isLight, surface) {
17
17
  return surface === "dark" ? "plate-light" : "bare";
18
18
  }
19
19
  var TREATMENT_CLASS = {
20
- "plate-light": "bg-white shadow-[0_2px_12px_rgba(0,0,0,0.18)]",
21
- "plate-dark": "bg-neutral-900 shadow-[0_2px_12px_rgba(0,0,0,0.25)]",
22
- framed: "border border-black/10 shadow-[0_2px_12px_rgba(0,0,0,0.18)]",
20
+ "plate-light": "bg-white shadow-[0_2px_12px_var(--rosh-mark-plate-shadow)]",
21
+ "plate-dark": "bg-neutral-900 shadow-[0_2px_12px_var(--rosh-mark-plate-shadow-strong)]",
22
+ framed: "border border-black/10 shadow-[0_2px_12px_var(--rosh-mark-plate-shadow)]",
23
23
  bare: ""
24
24
  };
25
25
  function treatmentStyle(treatment, radius, padding) {
@@ -101,5 +101,5 @@ function BrandMark({
101
101
  }
102
102
 
103
103
  export { BrandMark, resolveBrandMarkTreatment };
104
- //# sourceMappingURL=chunk-6XQHH7D2.js.map
105
- //# sourceMappingURL=chunk-6XQHH7D2.js.map
104
+ //# sourceMappingURL=chunk-TRCWINHF.js.map
105
+ //# sourceMappingURL=chunk-TRCWINHF.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/forms/BrandMark.tsx"],"names":[],"mappings":"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","file":"chunk-6XQHH7D2.js","sourcesContent":["import { useEffect, useState, type CSSProperties } from 'react';\n\nexport type BrandMarkSlot = 'favicon' | 'compact' | 'wordmark';\nexport type BrandMarkSurface = 'light' | 'dark';\nexport type BrandMarkTreatment = 'plate-light' | 'plate-dark' | 'framed' | 'bare';\n\nexport interface BrandMarkProps {\n src?: string | null;\n fallbackSrc?: string | null;\n fallbackHasAlpha?: boolean | null;\n fallbackIsLight?: boolean | null;\n fallbackAdaptive?: boolean;\n alt: string;\n slot?: BrandMarkSlot;\n surface?: BrandMarkSurface;\n /** Override the square slot size in pixels for compact shell chrome. */\n size?: number;\n /** Override a natural-aspect slot width without forcing square dimensions. */\n width?: number | string;\n /** Override a natural-aspect slot height without forcing square dimensions. */\n height?: number | string;\n /** Mark the image decorative when the adjacent text already names it. */\n decorative?: boolean;\n /** Hide the slot after load failure when surrounding UI owns the fallback. */\n fallbackMode?: 'monogram' | 'none';\n /** Keep an arbitrary tenant mark readable without recolouring the artwork. */\n adaptive?: boolean;\n /** Server-detected transparency hint for the selected asset. */\n hasAlpha?: boolean | null;\n /** Server-detected tone hint for the selected asset. */\n isLight?: boolean | null;\n treatmentPadding?: number | string;\n treatmentRadius?: number;\n className?: string;\n style?: CSSProperties;\n}\n\nconst SLOT_CLASS: Record<BrandMarkSlot, string> = {\n favicon: 'h-8 w-8',\n compact: 'h-10 w-10',\n wordmark: 'h-10 w-40',\n};\n\nfunction monogram(alt: string) {\n return alt.trim().charAt(0).toLocaleUpperCase() || '·';\n}\n\n/**\n * Chooses the smallest backing needed to preserve contrast. Opaque artwork\n * carries its own background; transparent artwork only needs a plate when its\n * tone would disappear into the current surface. Unknown artwork gets the\n * conservative light plate used by every portal.\n */\nexport function resolveBrandMarkTreatment(\n hasAlpha: boolean | null,\n isLight: boolean | null,\n surface: BrandMarkSurface,\n): BrandMarkTreatment {\n if (hasAlpha === false) return 'framed';\n if (hasAlpha == null || isLight == null) return 'plate-light';\n if (isLight) return surface === 'light' ? 'plate-dark' : 'bare';\n return surface === 'dark' ? 'plate-light' : 'bare';\n}\n\n/** The plate's colour and border are classes, so they follow the theme like\n * the rest of the file; only the caller-tunable radius and padding are\n * inline, because those arrive as numbers. */\nconst TREATMENT_CLASS: Record<BrandMarkTreatment, string> = {\n 'plate-light': 'bg-white shadow-[0_2px_12px_rgba(0,0,0,0.18)]',\n 'plate-dark': 'bg-neutral-900 shadow-[0_2px_12px_rgba(0,0,0,0.25)]',\n framed: 'border border-black/10 shadow-[0_2px_12px_rgba(0,0,0,0.18)]',\n bare: '',\n};\n\nfunction treatmentStyle(\n treatment: BrandMarkTreatment,\n radius: number,\n padding: number | string,\n): CSSProperties {\n if (treatment === 'bare') return {};\n return treatment === 'framed'\n ? { borderRadius: radius }\n : { borderRadius: radius, padding };\n}\n\n/**\n * Renders a brand asset inside a stable portal slot without ever cropping or\n * stretching the source. Raster normalisation belongs to the server; this\n * component owns only the presentation contract shared by portal surfaces.\n */\nexport default function BrandMark({\n src,\n fallbackSrc,\n fallbackHasAlpha = null,\n fallbackIsLight = null,\n fallbackAdaptive,\n alt,\n slot = 'compact',\n surface = 'light',\n size,\n width,\n height,\n decorative = false,\n fallbackMode = 'monogram',\n adaptive = false,\n hasAlpha = null,\n isLight = null,\n treatmentPadding = 4,\n treatmentRadius = 8,\n className = '',\n style,\n}: BrandMarkProps) {\n const [activeSrc, setActiveSrc] = useState(src || fallbackSrc || '');\n\n useEffect(() => {\n setActiveSrc(src || fallbackSrc || '');\n }, [src, fallbackSrc]);\n\n const usingFallback = Boolean(\n fallbackSrc && activeSrc === fallbackSrc && activeSrc !== src,\n );\n const activeAdaptive = usingFallback ? fallbackAdaptive ?? adaptive : adaptive;\n const activeHasAlpha = usingFallback ? fallbackHasAlpha : hasAlpha;\n const activeIsLight = usingFallback ? fallbackIsLight : isLight;\n const treatment = activeAdaptive\n ? resolveBrandMarkTreatment(activeHasAlpha, activeIsLight, surface)\n : 'bare';\n const frameClass = [\n 'inline-flex shrink-0 items-center justify-center overflow-hidden',\n size == null && width == null && height == null ? SLOT_CLASS[slot] : '',\n surface === 'dark' ? 'text-white' : 'text-gray-700',\n TREATMENT_CLASS[treatment],\n className,\n ].filter(Boolean).join(' ');\n const frameStyle: CSSProperties = {\n ...treatmentStyle(treatment, treatmentRadius, treatmentPadding),\n ...(size == null ? { width, height } : { width: size, height: size }),\n ...style,\n };\n\n if (!activeSrc) {\n if (fallbackMode === 'none') return null;\n return (\n <span\n data-brand-fallback\n data-brand-slot={slot}\n aria-label={decorative ? undefined : alt}\n aria-hidden={decorative || undefined}\n role={decorative ? undefined : 'img'}\n className={`${frameClass} rounded-md bg-gray-100 font-semibold`}\n style={frameStyle}\n >\n {decorative ? null : monogram(alt)}\n </span>\n );\n }\n\n return (\n <span className={frameClass} data-brand-treatment={treatment} style={frameStyle}>\n <img\n src={activeSrc}\n alt={decorative ? '' : alt}\n data-brand-slot={slot}\n className=\"block max-h-full max-w-full\"\n style={{ objectFit: 'contain' }}\n onError={() => setActiveSrc(current => (\n fallbackSrc && current !== fallbackSrc ? fallbackSrc : ''\n ))}\n />\n </span>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/forms/BrandMark.tsx"],"names":[],"mappings":"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","file":"chunk-TRCWINHF.js","sourcesContent":["import { useEffect, useState, type CSSProperties } from 'react';\n\nexport type BrandMarkSlot = 'favicon' | 'compact' | 'wordmark';\nexport type BrandMarkSurface = 'light' | 'dark';\nexport type BrandMarkTreatment = 'plate-light' | 'plate-dark' | 'framed' | 'bare';\n\nexport interface BrandMarkProps {\n src?: string | null;\n fallbackSrc?: string | null;\n fallbackHasAlpha?: boolean | null;\n fallbackIsLight?: boolean | null;\n fallbackAdaptive?: boolean;\n alt: string;\n slot?: BrandMarkSlot;\n surface?: BrandMarkSurface;\n /** Override the square slot size in pixels for compact shell chrome. */\n size?: number;\n /** Override a natural-aspect slot width without forcing square dimensions. */\n width?: number | string;\n /** Override a natural-aspect slot height without forcing square dimensions. */\n height?: number | string;\n /** Mark the image decorative when the adjacent text already names it. */\n decorative?: boolean;\n /** Hide the slot after load failure when surrounding UI owns the fallback. */\n fallbackMode?: 'monogram' | 'none';\n /** Keep an arbitrary tenant mark readable without recolouring the artwork. */\n adaptive?: boolean;\n /** Server-detected transparency hint for the selected asset. */\n hasAlpha?: boolean | null;\n /** Server-detected tone hint for the selected asset. */\n isLight?: boolean | null;\n treatmentPadding?: number | string;\n treatmentRadius?: number;\n className?: string;\n style?: CSSProperties;\n}\n\nconst SLOT_CLASS: Record<BrandMarkSlot, string> = {\n favicon: 'h-8 w-8',\n compact: 'h-10 w-10',\n wordmark: 'h-10 w-40',\n};\n\nfunction monogram(alt: string) {\n return alt.trim().charAt(0).toLocaleUpperCase() || '·';\n}\n\n/**\n * Chooses the smallest backing needed to preserve contrast. Opaque artwork\n * carries its own background; transparent artwork only needs a plate when its\n * tone would disappear into the current surface. Unknown artwork gets the\n * conservative light plate used by every portal.\n */\nexport function resolveBrandMarkTreatment(\n hasAlpha: boolean | null,\n isLight: boolean | null,\n surface: BrandMarkSurface,\n): BrandMarkTreatment {\n if (hasAlpha === false) return 'framed';\n if (hasAlpha == null || isLight == null) return 'plate-light';\n if (isLight) return surface === 'light' ? 'plate-dark' : 'bare';\n return surface === 'dark' ? 'plate-light' : 'bare';\n}\n\n/** The plate's colour and border are classes, so they follow the theme like\n * the rest of the file; only the caller-tunable radius and padding are\n * inline, because those arrive as numbers. The shadow's geometry is in the\n * class and its colour is a token (`--rosh-mark-plate-shadow`, and the\n * `-strong` one under the dark plate), so a host restyling depth reaches it. */\nconst TREATMENT_CLASS: Record<BrandMarkTreatment, string> = {\n 'plate-light': 'bg-white shadow-[0_2px_12px_var(--rosh-mark-plate-shadow)]',\n 'plate-dark': 'bg-neutral-900 shadow-[0_2px_12px_var(--rosh-mark-plate-shadow-strong)]',\n framed: 'border border-black/10 shadow-[0_2px_12px_var(--rosh-mark-plate-shadow)]',\n bare: '',\n};\n\nfunction treatmentStyle(\n treatment: BrandMarkTreatment,\n radius: number,\n padding: number | string,\n): CSSProperties {\n if (treatment === 'bare') return {};\n return treatment === 'framed'\n ? { borderRadius: radius }\n : { borderRadius: radius, padding };\n}\n\n/**\n * Renders a brand asset inside a stable portal slot without ever cropping or\n * stretching the source. Raster normalisation belongs to the server; this\n * component owns only the presentation contract shared by portal surfaces.\n */\nexport default function BrandMark({\n src,\n fallbackSrc,\n fallbackHasAlpha = null,\n fallbackIsLight = null,\n fallbackAdaptive,\n alt,\n slot = 'compact',\n surface = 'light',\n size,\n width,\n height,\n decorative = false,\n fallbackMode = 'monogram',\n adaptive = false,\n hasAlpha = null,\n isLight = null,\n treatmentPadding = 4,\n treatmentRadius = 8,\n className = '',\n style,\n}: BrandMarkProps) {\n const [activeSrc, setActiveSrc] = useState(src || fallbackSrc || '');\n\n useEffect(() => {\n setActiveSrc(src || fallbackSrc || '');\n }, [src, fallbackSrc]);\n\n const usingFallback = Boolean(\n fallbackSrc && activeSrc === fallbackSrc && activeSrc !== src,\n );\n const activeAdaptive = usingFallback ? fallbackAdaptive ?? adaptive : adaptive;\n const activeHasAlpha = usingFallback ? fallbackHasAlpha : hasAlpha;\n const activeIsLight = usingFallback ? fallbackIsLight : isLight;\n const treatment = activeAdaptive\n ? resolveBrandMarkTreatment(activeHasAlpha, activeIsLight, surface)\n : 'bare';\n const frameClass = [\n 'inline-flex shrink-0 items-center justify-center overflow-hidden',\n size == null && width == null && height == null ? SLOT_CLASS[slot] : '',\n surface === 'dark' ? 'text-white' : 'text-gray-700',\n TREATMENT_CLASS[treatment],\n className,\n ].filter(Boolean).join(' ');\n const frameStyle: CSSProperties = {\n ...treatmentStyle(treatment, treatmentRadius, treatmentPadding),\n ...(size == null ? { width, height } : { width: size, height: size }),\n ...style,\n };\n\n if (!activeSrc) {\n if (fallbackMode === 'none') return null;\n return (\n <span\n data-brand-fallback\n data-brand-slot={slot}\n aria-label={decorative ? undefined : alt}\n aria-hidden={decorative || undefined}\n role={decorative ? undefined : 'img'}\n className={`${frameClass} rounded-md bg-gray-100 font-semibold`}\n style={frameStyle}\n >\n {decorative ? null : monogram(alt)}\n </span>\n );\n }\n\n return (\n <span className={frameClass} data-brand-treatment={treatment} style={frameStyle}>\n <img\n src={activeSrc}\n alt={decorative ? '' : alt}\n data-brand-slot={slot}\n className=\"block max-h-full max-w-full\"\n style={{ objectFit: 'contain' }}\n onError={() => setActiveSrc(current => (\n fallbackSrc && current !== fallbackSrc ? fallbackSrc : ''\n ))}\n />\n </span>\n );\n}\n"]}
@@ -0,0 +1,7 @@
1
+ // src/version.ts
2
+ var VERSION = "4.131.0" ;
3
+ var APP_VERSION = VERSION;
4
+
5
+ export { APP_VERSION, VERSION };
6
+ //# sourceMappingURL=chunk-UHPWZ2F4.js.map
7
+ //# sourceMappingURL=chunk-UHPWZ2F4.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/version.ts"],"names":[],"mappings":";AAIO,IAAM,OAAA,GAAwD,SAAA;AAG9D,IAAM,WAAA,GAAc","file":"chunk-K6ZT6MWE.js","sourcesContent":["declare const __PKG_VERSION__: string | undefined;\n\n/** Package version, injected by tsup at build time. Stays as an empty\n * string when the source is consumed without a build (e.g. tests). */\nexport const VERSION: string = typeof __PKG_VERSION__ === 'string' ? __PKG_VERSION__ : '';\n\n/** Legacy alias kept so existing consumers do not break. */\nexport const APP_VERSION = VERSION;\n"]}
1
+ {"version":3,"sources":["../src/version.ts"],"names":[],"mappings":";AAIO,IAAM,OAAA,GAAwD,SAAA;AAG9D,IAAM,WAAA,GAAc","file":"chunk-UHPWZ2F4.js","sourcesContent":["declare const __PKG_VERSION__: string | undefined;\n\n/** Package version, injected by tsup at build time. Stays as an empty\n * string when the source is consumed without a build (e.g. tests). */\nexport const VERSION: string = typeof __PKG_VERSION__ === 'string' ? __PKG_VERSION__ : '';\n\n/** Legacy alias kept so existing consumers do not break. */\nexport const APP_VERSION = VERSION;\n"]}
@@ -1,5 +1,5 @@
1
- import { toast_default } from './chunk-2VM2FRZJ.js';
2
- import { useShellPrefs } from './chunk-YNHLQ24V.js';
1
+ import { toast_default } from './chunk-EENVXIVU.js';
2
+ import { useShellPrefs } from './chunk-TQURTLK2.js';
3
3
  import { useSyncExternalStore, useCallback, useMemo } from 'react';
4
4
 
5
5
  // src/shell/pomodoroStore.ts
@@ -545,5 +545,5 @@ function migratePomodoroTasksOnce(currentTasks, setAllTasks) {
545
545
  }
546
546
 
547
547
  export { ALARM_OPTIONS, FOCUS_SOUND_OPTIONS, getPomoSnapshot, migratePomodoroTasksOnce, playAlarm, pomoPause, pomoStart, pomoSwitchMode, previewFocusSound, setPomoAlarm, setPomoAlarmConfig, setPomoBehaviour, setPomoDurations, setPomoFocusSound, setShellTodoProvider, subscribePomo, useTodoTasks };
548
- //# sourceMappingURL=chunk-32W6VY2J.js.map
549
- //# sourceMappingURL=chunk-32W6VY2J.js.map
548
+ //# sourceMappingURL=chunk-VWZIGZFF.js.map
549
+ //# sourceMappingURL=chunk-VWZIGZFF.js.map