efficient-shell 4.132.0 → 4.134.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 (111) hide show
  1. package/README.md +62 -12
  2. package/dist/{Browser-XPVJ2K7B.js → Browser-O3QZGUF2.js} +11 -11
  3. package/dist/{Browser-XPVJ2K7B.js.map → Browser-O3QZGUF2.js.map} +1 -1
  4. package/dist/{Calculator-ZXJPXG7F.js → Calculator-L6N5X3KU.js} +9 -9
  5. package/dist/{Calculator-ZXJPXG7F.js.map → Calculator-L6N5X3KU.js.map} +1 -1
  6. package/dist/ConfirmDialog-LYSSZSUD.js +4 -0
  7. package/dist/{ConfirmDialog-MTC7QMUJ.js.map → ConfirmDialog-LYSSZSUD.js.map} +1 -1
  8. package/dist/{CurrencyConverter-WSJ2BBSX.js → CurrencyConverter-64MKXB3D.js} +9 -9
  9. package/dist/{CurrencyConverter-WSJ2BBSX.js.map → CurrencyConverter-64MKXB3D.js.map} +1 -1
  10. package/dist/{Documents-ONGSXUJI.js → Documents-5WXXYCLI.js} +11 -11
  11. package/dist/{Documents-ONGSXUJI.js.map → Documents-5WXXYCLI.js.map} +1 -1
  12. package/dist/{Files-GQZMFWXQ.js → Files-AUURUUDN.js} +17 -17
  13. package/dist/{Files-GQZMFWXQ.js.map → Files-AUURUUDN.js.map} +1 -1
  14. package/dist/{Notepad-HM73XAM4.js → Notepad-GPXJVPB7.js} +12 -12
  15. package/dist/{Notepad-HM73XAM4.js.map → Notepad-GPXJVPB7.js.map} +1 -1
  16. package/dist/PdfViewer-HKO6P4SR.js +5 -0
  17. package/dist/{PdfViewer-M2YGZIYX.js.map → PdfViewer-HKO6P4SR.js.map} +1 -1
  18. package/dist/{PomodoroTimer-DG3LI5CX.js → PomodoroTimer-4TQBWLP2.js} +11 -11
  19. package/dist/{PomodoroTimer-DG3LI5CX.js.map → PomodoroTimer-4TQBWLP2.js.map} +1 -1
  20. package/dist/{Preview-TUSV4UMO.js → Preview-FOZYPKM2.js} +14 -14
  21. package/dist/{Preview-TUSV4UMO.js.map → Preview-FOZYPKM2.js.map} +1 -1
  22. package/dist/{Spreadsheet-3WTXCHYQ.js → Spreadsheet-3C66BBBF.js} +12 -12
  23. package/dist/{Spreadsheet-3WTXCHYQ.js.map → Spreadsheet-3C66BBBF.js.map} +1 -1
  24. package/dist/{Stock-YMPOMUAW.js → Stock-IF4IHYLU.js} +9 -9
  25. package/dist/{Stock-YMPOMUAW.js.map → Stock-IF4IHYLU.js.map} +1 -1
  26. package/dist/{Weather-NZO3CWLH.js → Weather-725PFR7T.js} +9 -9
  27. package/dist/{Weather-NZO3CWLH.js.map → Weather-725PFR7T.js.map} +1 -1
  28. package/dist/{WorldClock-HUC6D3AD.js → WorldClock-UU4NZIQ7.js} +9 -9
  29. package/dist/{WorldClock-HUC6D3AD.js.map → WorldClock-UU4NZIQ7.js.map} +1 -1
  30. package/dist/apps/index.d.ts +2 -2
  31. package/dist/apps/index.js +28 -28
  32. package/dist/apps/index.js.map +1 -1
  33. package/dist/brand.css +1 -1
  34. package/dist/{chunk-TQURTLK2.js → chunk-2TPTHAKI.js} +5 -5
  35. package/dist/{chunk-TQURTLK2.js.map → chunk-2TPTHAKI.js.map} +1 -1
  36. package/dist/{chunk-EENVXIVU.js → chunk-4P44JXDS.js} +3 -3
  37. package/dist/{chunk-EENVXIVU.js.map → chunk-4P44JXDS.js.map} +1 -1
  38. package/dist/{chunk-CT3HVZRZ.js → chunk-5O42JXQE.js} +2 -2
  39. package/dist/chunk-5O42JXQE.js.map +1 -0
  40. package/dist/{chunk-7IN7YZAL.js → chunk-72CQWN7O.js} +3 -3
  41. package/dist/chunk-72CQWN7O.js.map +1 -0
  42. package/dist/{chunk-I464GYJJ.js → chunk-BE7FZOFU.js} +2 -2
  43. package/dist/chunk-BE7FZOFU.js.map +1 -0
  44. package/dist/{chunk-3L463T5H.js → chunk-DVZWYWSD.js} +2 -2
  45. package/dist/chunk-DVZWYWSD.js.map +1 -0
  46. package/dist/{chunk-FONEQRBH.js → chunk-ET6ID4LP.js} +3 -3
  47. package/dist/{chunk-FONEQRBH.js.map → chunk-ET6ID4LP.js.map} +1 -1
  48. package/dist/{chunk-CGXMWHQW.js → chunk-GIGV2ZRW.js} +3 -3
  49. package/dist/{chunk-CGXMWHQW.js.map → chunk-GIGV2ZRW.js.map} +1 -1
  50. package/dist/{chunk-CJYO4RVV.js → chunk-IULP5BCD.js} +5 -5
  51. package/dist/chunk-IULP5BCD.js.map +1 -0
  52. package/dist/{chunk-BJ34QOR3.js → chunk-OLJDJYSU.js} +287 -146
  53. package/dist/chunk-OLJDJYSU.js.map +1 -0
  54. package/dist/{chunk-7MA5XBWD.js → chunk-PIGDNN5F.js} +5 -5
  55. package/dist/{chunk-7MA5XBWD.js.map → chunk-PIGDNN5F.js.map} +1 -1
  56. package/dist/chunk-Q2MJVSJT.js +7 -0
  57. package/dist/{chunk-JMKYYPOF.js.map → chunk-Q2MJVSJT.js.map} +1 -1
  58. package/dist/{chunk-ZKHD4J73.js → chunk-Q3LT745N.js} +10 -10
  59. package/dist/chunk-Q3LT745N.js.map +1 -0
  60. package/dist/{chunk-CLGNTGC5.js → chunk-QAGQRNKI.js} +3 -3
  61. package/dist/{chunk-CLGNTGC5.js.map → chunk-QAGQRNKI.js.map} +1 -1
  62. package/dist/{chunk-E3TWIN7Z.js → chunk-QRL64J5F.js} +3 -3
  63. package/dist/{chunk-E3TWIN7Z.js.map → chunk-QRL64J5F.js.map} +1 -1
  64. package/dist/{chunk-TFXJRHJV.js → chunk-QSKCQUZE.js} +3 -3
  65. package/dist/{chunk-TFXJRHJV.js.map → chunk-QSKCQUZE.js.map} +1 -1
  66. package/dist/{chunk-MQPX6ERJ.js → chunk-R4OQIQYX.js} +4 -4
  67. package/dist/{chunk-MQPX6ERJ.js.map → chunk-R4OQIQYX.js.map} +1 -1
  68. package/dist/{chunk-LQTVTOSY.js → chunk-RT6DSB5Y.js} +45 -19
  69. package/dist/chunk-RT6DSB5Y.js.map +1 -0
  70. package/dist/{chunk-VWZIGZFF.js → chunk-SHQM5CK3.js} +4 -4
  71. package/dist/{chunk-VWZIGZFF.js.map → chunk-SHQM5CK3.js.map} +1 -1
  72. package/dist/{chunk-KWEX4ZAF.js → chunk-T4VQHMG4.js} +3 -3
  73. package/dist/{chunk-KWEX4ZAF.js.map → chunk-T4VQHMG4.js.map} +1 -1
  74. package/dist/{chunk-BFBWLCO6.js → chunk-TW7LPMVR.js} +2 -2
  75. package/dist/chunk-TW7LPMVR.js.map +1 -0
  76. package/dist/{chunk-XH3ELPQZ.js → chunk-W622KQTD.js} +3 -3
  77. package/dist/chunk-W622KQTD.js.map +1 -0
  78. package/dist/{chunk-SEWF4O3H.js → chunk-X4Q6G253.js} +3 -3
  79. package/dist/chunk-X4Q6G253.js.map +1 -0
  80. package/dist/file-intake/index.js +2 -2
  81. package/dist/{index-COwksV6G.d.ts → index-DZ7E7bCl.d.ts} +196 -4
  82. package/dist/index.d.ts +3 -3
  83. package/dist/index.js +35 -35
  84. package/dist/index.js.map +1 -1
  85. package/dist/map/index.js +1 -1
  86. package/dist/markdown/index.d.ts +4 -4
  87. package/dist/markdown/index.js.map +1 -1
  88. package/dist/markup/index.d.ts +2 -2
  89. package/dist/markup/index.js.map +1 -1
  90. package/dist/page-tabs/index.js +3 -3
  91. package/dist/shell.css +1 -1
  92. package/dist/styles.css +4 -4
  93. package/dist/themes.css +3 -3
  94. package/dist/ui/index.d.ts +1 -1
  95. package/dist/ui/index.js +12 -12
  96. package/dist/ui.css +233 -8
  97. package/package.json +1 -1
  98. package/dist/ConfirmDialog-MTC7QMUJ.js +0 -4
  99. package/dist/PdfViewer-M2YGZIYX.js +0 -5
  100. package/dist/chunk-3L463T5H.js.map +0 -1
  101. package/dist/chunk-7IN7YZAL.js.map +0 -1
  102. package/dist/chunk-BFBWLCO6.js.map +0 -1
  103. package/dist/chunk-BJ34QOR3.js.map +0 -1
  104. package/dist/chunk-CJYO4RVV.js.map +0 -1
  105. package/dist/chunk-CT3HVZRZ.js.map +0 -1
  106. package/dist/chunk-I464GYJJ.js.map +0 -1
  107. package/dist/chunk-JMKYYPOF.js +0 -7
  108. package/dist/chunk-LQTVTOSY.js.map +0 -1
  109. package/dist/chunk-SEWF4O3H.js.map +0 -1
  110. package/dist/chunk-XH3ELPQZ.js.map +0 -1
  111. package/dist/chunk-ZKHD4J73.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { useShellStrings } from './chunk-7IN7YZAL.js';
1
+ import { useShellStrings } from './chunk-72CQWN7O.js';
2
2
  import { useHydrated, useBrowserState } from './chunk-IRWSRJ4K.js';
3
3
  import { createContext, useSyncExternalStore, useCallback, useContext, useMemo } from 'react';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -270,14 +270,14 @@ function installStaleChunkReload(options = {}) {
270
270
  const last = readLastReload(storage);
271
271
  if (last !== null && at - last < cooldownMs) {
272
272
  console.error(
273
- "[react-os-shell] a lazy chunk is still missing after a reload; letting the failure through:",
273
+ "[efficient-shell] a lazy chunk is still missing after a reload; letting the failure through:",
274
274
  chunk
275
275
  );
276
276
  return false;
277
277
  }
278
278
  writeLastReload(storage, at);
279
279
  console.warn(
280
- "[react-os-shell] a lazy chunk is no longer on the server (new deploy?); reloading onto the current build:",
280
+ "[efficient-shell] a lazy chunk is no longer on the server (new deploy?); reloading onto the current build:",
281
281
  chunk
282
282
  );
283
283
  return true;
@@ -312,5 +312,5 @@ function installStaleChunkReload(options = {}) {
312
312
  }
313
313
 
314
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
315
+ //# sourceMappingURL=chunk-2TPTHAKI.js.map
316
+ //# sourceMappingURL=chunk-2TPTHAKI.js.map
@@ -1 +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":";;;;;AAaA,IAAM,KAAA,GAAQ,uCAAA;AAEd,SAAS,WAAA,GAAuB;AAC9B,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,CAAC,MAAA,CAAO,YAAY,OAAO,KAAA;AAChE,EAAA,OAAO,MAAA,CAAO,UAAA,CAAW,KAAK,CAAA,CAAE,OAAA;AAClC;AAEA,SAAS,iBAAA,GAA6B;AACpC,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,UAAU,EAAA,EAA4B;AAC7C,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,CAAC,MAAA,CAAO,UAAA,SAAmB,MAAM;AAAA,EAAC,CAAA;AACvE,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,UAAA,CAAW,KAAK,CAAA;AAEnC,EAAA,IAAI,IAAI,gBAAA,EAAkB;AACxB,IAAA,GAAA,CAAI,gBAAA,CAAiB,UAAU,EAAE,CAAA;AACjC,IAAA,OAAO,MAAM,GAAA,CAAI,mBAAA,CAAoB,QAAA,EAAU,EAAE,CAAA;AAAA,EACnD;AACA,EAAA,GAAA,CAAI,YAAY,EAAE,CAAA;AAClB,EAAA,OAAO,MAAM,GAAA,CAAI,cAAA,CAAe,EAAE,CAAA;AACpC;AAEO,SAAS,WAAA,GAAuB;AACrC,EAAA,OAAO,oBAAA,CAAqB,SAAA,EAAW,WAAA,EAAa,iBAAiB,CAAA;AACvE;ACTA,IAAM,WAAA,GAA0C;AAAA,EAC9C,OAAA,EAAS,SAAA;AAAA,EAAW,KAAA,EAAO,OAAA;AAAA,EAAS,OAAA,EAAS,SAAA;AAAA,EAAW,IAAA,EAAM,MAAA;AAAA;AAAA;AAAA,EAG9D,GAAA,EAAK,MAAA;AAAA,EAAQ,GAAA,EAAK,SAAA;AAAA,EAAW,GAAA,EAAK;AACpC,CAAA;AAEA,IAAM,UAAA,GAAmC;AAAA,EACvC,OAAA,EAAS,6BAAA;AAAA,EACT,KAAA,EAAO,yBAAA;AAAA,EACP,OAAA,EAAS,6BAAA;AAAA,EACT,IAAA,EAAM;AACR,CAAA;AAIA,IAAM,aAAA,GAA2F;AAAA,EAC/F,GAAA,EAAK,YAAU,MAAA,CAAO,QAAA;AAAA,EACtB,GAAA,EAAK,YAAU,MAAA,CAAO,QAAA;AAAA,EACtB,GAAA,EAAK,YAAU,MAAA,CAAO;AACxB,CAAA;AAEA,SAAS,UAAA,CAAW,EAAE,IAAA,EAAK,EAAmB;AAC5C,EAAA,MAAM,MAAA,GAAS,EAAE,SAAA,EAAW,SAAA,EAAW,IAAA,EAAM,MAAA,EAAQ,OAAA,EAAS,WAAA,EAAa,MAAA,EAAQ,cAAA,EAAgB,WAAA,EAAa,GAAA,EAAK,eAAe,IAAA,EAAK;AACzI,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,SAAA;AACH,MAAA,uBAAO,GAAA,CAAC,KAAA,EAAA,EAAK,GAAG,MAAA,EAAQ,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,aAAA,EAAc,OAAA,EAAQ,cAAA,EAAe,OAAA,EAAQ,CAAA,EAAE,uBAAA,EAAwB,CAAA,EAAE,CAAA;AAAA,IACzG,KAAK,OAAA;AACH,MAAA,uBAAO,GAAA,CAAC,KAAA,EAAA,EAAK,GAAG,MAAA,EAAQ,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,aAAA,EAAc,OAAA,EAAQ,cAAA,EAAe,OAAA,EAAQ,CAAA,EAAE,sBAAA,EAAuB,CAAA,EAAE,CAAA;AAAA,IACxG,KAAK,SAAA;AACH,MAAA,uBAAO,GAAA,CAAC,KAAA,EAAA,EAAK,GAAG,MAAA,EAAQ,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,aAAA,EAAc,OAAA,EAAQ,cAAA,EAAe,OAAA,EAAQ,CAAA,EAAE,0EAAA,EAA2E,CAAA,EAAE,CAAA;AAAA,IAC5J;AACE,MAAA,uBAAO,GAAA,CAAC,KAAA,EAAA,EAAK,GAAG,MAAA,EAAQ,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,aAAA,EAAc,OAAA,EAAQ,cAAA,EAAe,OAAA,EAAQ,CAAA,EAAE,oJAAA,EAAqJ,CAAA,EAAE,CAAA;AAAA;AAE1O;AAEe,SAAR,MAAA,CAAwB;AAAA,EAC7B,MAAA,GAAS,MAAA;AAAA,EAAQ,KAAA;AAAA,EAAO,QAAA;AAAA,EAAU,KAAA;AAAA,EAAO,IAAA;AAAA,EAAM,QAAA;AAAA,EAAU,SAAA,GAAY;AACvE,CAAA,EAAgB;AACd,EAAA,MAAM,IAAA,GAAO,YAAY,MAAM,CAAA;AAC/B,EAAA,MAAM,MAAA,GAAS,iBAAgB,CAAE,MAAA;AAOjC,EAAA,MAAM,YAAY,IAAA,KAAS,OAAA;AAC3B,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAM,YAAY,OAAA,GAAU,MAAA;AAAA,MAC5B,SAAA,EAAW,CAAA,iEAAA,EAAoE,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK;AAAA,MAEhG,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,CAAA,wDAAA,EAA2D,UAAA,CAAW,IAAI,CAAC,CAAA,CAAA,EACxF,QAAA,EAAA,IAAA,oBAAQ,GAAA,CAAC,UAAA,EAAA,EAAW,IAAA,EAAY,CAAA,EACnC,CAAA;AAAA,wBACA,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,0CAAA,EACX,QAAA,EAAA,KAAA,IAAS,cAAc,MAAM,CAAA,GAAI,MAAM,CAAA,IAAK,EAAA,EAC/C,CAAA;AAAA,QACC,QAAA,oBAAY,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,uCAAuC,QAAA,EAAA,QAAA,EAAS,CAAA;AAAA,QACzE,QAAA,oBAAY,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,kCAAkC,QAAA,EAAS,CAAA;AAAA,QACtE,KAAA,oBAAS,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,yDAAyD,QAAA,EAAA,KAAA,EAAM;AAAA;AAAA;AAAA,GAC1F;AAEJ;ACxEe,SAAR,cAAA,CAAgC,EAAE,IAAA,GAAO,IAAA,EAAM,UAAU,OAAA,EAAS,KAAA,EAAO,SAAA,GAAY,EAAA,EAAG,EAAwB;AACrH,EAAA,MAAM,MAAM,IAAA,KAAS,IAAA,GAAO,SAAA,GAAY,IAAA,KAAS,OAAO,WAAA,GAAc,SAAA;AACtE,EAAA,MAAM,uBAAOA,GAAAA,CAAC,SAAI,SAAA,EAAW,CAAA,EAAG,GAAG,CAAA,qEAAA,CAAA,EAAyE,CAAA;AAI5G,EAAA,IAAI,SAAS,IAAA,EAAM;AACjB,IAAA,uBAAOA,IAAC,KAAA,EAAA,EAAI,SAAA,EAAW,oCAAoC,OAAO,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,EAAK,QAAA,EAAA,IAAA,EAAK,CAAA;AAAA,EAC3F;AACA,EAAA,uBACEC,IAAAA,CAAC,KAAA,EAAA,EAAI,IAAA,EAAK,QAAA,EAAS,WAAW,CAAA,gDAAA,EAAmD,OAAO,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,EAClG,QAAA,EAAA;AAAA,IAAA,IAAA;AAAA,oBACDD,GAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,yBAAyB,QAAA,EAAA,KAAA,EAAM;AAAA,GAAA,EAC9C,CAAA;AAEJ;AClBO,IAAM,KAAA,GAAQ,OAAO,MAAA,KAAW,WAAA,IAAe,OAAO,SAAA,KAAc,WAAA,IACtE,iBAAA,CAAkB,IAAA,CAAK,SAAA,CAAU,QAAA,IAAY,SAAA,CAAU,SAAS;AAOrE,IAAM,KAAA,GAAQ;AAAA,EACZ,GAAA,EAAK,CAAC,QAAA,EAAU,MAAM,CAAA;AAAA,EACtB,GAAA,EAAK,CAAC,QAAA,EAAU,KAAK,CAAA;AAAA,EACrB,SAAA,EAAW,CAAC,cAAA,EAAgB,YAAY,CAAA;AAAA,EACxC,KAAA,EAAO,CAAC,SAAA,EAAW,QAAQ,CAAA;AAAA,EAC3B,KAAA,EAAO,CAAC,SAAA,EAAW,QAAQ,CAAA;AAAA,EAC3B,OAAA,EAAS,CAAC,SAAA,EAAW,QAAQ,CAAA;AAAA,EAC7B,KAAA,EAAO,CAAC,SAAA,EAAW,QAAQ,CAAA;AAAA,EAC3B,KAAA,EAAO,CAAC,SAAA,EAAW,QAAQ,CAAA;AAAA,EAC3B,WAAA,EAAa,CAAC,eAAA,EAAiB,cAAc,CAAA;AAAA,EAC7C,WAAA,EAAa,CAAC,eAAA,EAAiB,aAAa,CAAA;AAAA,EAC5C,WAAA,EAAa,CAAC,eAAA,EAAiB,aAAa,CAAA;AAAA,EAC5C,WAAA,EAAa,CAAC,eAAA,EAAiB,aAAa;AAC9C,CAAA;AACA,IAAM,IAAA,GAAO,QAAQ,CAAA,GAAI,CAAA;AAGlB,IAAM,GAAA,GAAM,KAAA,CAAM,GAAA,CAAI,IAAI;AAC1B,IAAM,GAAA,GAAM,KAAA,CAAM,GAAA,CAAI,IAAI;AAC1B,IAAM,KAAA,GAAQ;AACd,IAAM,KAAA,GAAQ;AAGd,IAAM,SAAA,GAAY,KAAA,CAAM,SAAA,CAAU,IAAI;AACtC,IAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,IAAI;AAC9B,IAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,IAAI;AAC9B,IAAM,OAAA,GAAU,KAAA,CAAM,OAAA,CAAQ,IAAI;AAClC,IAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,IAAI;AAC9B,IAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,IAAI;AAE9B,IAAM,WAAA,GAAc,KAAA,CAAM,WAAA,CAAY,IAAI;AAC1C,IAAM,WAAA,GAAc,KAAA,CAAM,WAAA,CAAY,IAAI;AAC1C,IAAM,WAAA,GAAc,KAAA,CAAM,WAAA,CAAY,IAAI;AAC1C,IAAM,WAAA,GAAc,KAAA,CAAM,WAAA,CAAY,IAAI;AAOjD,IAAM,eAA4C,IAAI,GAAA;AAAA,EACpD,QAAQ,MAAA,CAAO,MAAA,CAAO,KAAK,CAAA,CAAE,IAAI,CAAC,CAAC,GAAA,EAAK,KAAK,MAAM,CAAC,GAAA,EAAK,KAAK,CAAqB,IAAI;AACzF,CAAA;AAgBO,SAAS,iBAAiB,IAAA,EAAsB;AACrD,EAAA,MAAM,WAAW,WAAA,EAAY;AAC7B,EAAA,OAAO,QAAA,GAAW,IAAA,GAAQ,YAAA,CAAa,GAAA,CAAI,IAAI,CAAA,IAAK,IAAA;AACtD;AA0BA,IAAM,QAAA,GACJ,6GAAA;AAIF,IAAM,SAAA,GAAqC;AAAA,EACzC,EAAA,EAAI,yBAAA;AAAA,EACJ,EAAA,EAAI;AACN,CAAA;AAWO,SAAS,IAAI,EAAE,IAAA,EAAM,OAAO,IAAA,EAAM,SAAA,GAAY,IAAG,EAAa;AACnE,EAAA,MAAM,KAAA,GAAQ,iBAAiB,IAAI,CAAA;AACnC,EAAA,uBAAOA,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,CAAC,UAAU,SAAA,CAAU,IAAI,CAAA,EAAG,SAAS,EAAE,MAAA,CAAO,OAAO,EAAE,IAAA,CAAK,GAAG,GAAI,QAAA,EAAA,KAAA,EAAM,CAAA;AAClG;ACjHA,IAAM,iBAAA,GAAoB,cAAwC,IAAI,CAAA;AAE/D,SAAS,kBAAA,CAAmB;AAAA,EACjC,KAAA;AAAA,EACA;AACF,CAAA,EAAsD;AACpD,EAAA,uBAAOA,GAAAA,CAAC,iBAAA,CAAkB,QAAA,EAAlB,EAA2B,OAAe,QAAA,EAAS,CAAA;AAC7D;AAUO,SAAS,oBAAA,CACd,UAAA,GAAa,sBAAA,EACb,QAAA,EACmB;AAKnB,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,gBAAqC,MAAM;AACnE,IAAA,IAAI;AACF,MAAA,MAAM,SAAS,IAAA,CAAK,KAAA,CAAM,aAAa,OAAA,CAAQ,UAAU,KAAK,IAAI,CAAA;AAClE,MAAA,OAAO,EAAE,GAAI,QAAA,IAAY,EAAC,EAAI,GAAG,MAAA,EAAO;AAAA,IAC1C,CAAA,CAAA,MAAQ;AAAE,MAAA,OAAO,EAAE,GAAI,QAAA,IAAY,EAAC,EAAG;AAAA,IAAG;AAAA,EAC5C,GAAG,EAAE,GAAI,QAAA,IAAY,IAAK,CAAA;AAC1B,EAAA,MAAM,IAAA,GAAO,WAAA,CAAY,CAAC,KAAA,KAA+B;AACvD,IAAA,QAAA,CAAS,CAAA,IAAA,KAAQ;AACf,MAAA,MAAM,IAAA,GAAO,EAAE,GAAG,IAAA,EAAM,GAAG,KAAA,EAAM;AACjC,MAAA,IAAI;AAAE,QAAA,YAAA,CAAa,OAAA,CAAQ,UAAA,EAAY,IAAA,CAAK,SAAA,CAAU,IAAI,CAAC,CAAA;AAAA,MAAG,CAAA,CAAA,MAAQ;AAAA,MAAC;AACvE,MAAA,OAAO,IAAA;AAAA,IACT,CAAC,CAAA;AAAA,EACH,CAAA,EAAG,CAAC,UAAU,CAAC,CAAA;AACf,EAAA,OAAO,EAAE,OAAO,IAAA,EAAK;AACvB;AAKA,IAAM,cAAiC,EAAE,KAAA,EAAO,EAAC,EAAG,MAAM,MAAM;AAAC,CAAA,EAAE;AAS5D,SAAS,oBAAA,GAA0C;AACxD,EAAA,OAAO,UAAA,CAAW,iBAAiB,CAAA,IAAK,WAAA;AAC1C;AAeO,SAAS,aAAA,GAAmC;AACjD,EAAA,MAAM,EAAE,KAAA,EAAO,IAAA,EAAM,OAAA,KAAY,oBAAA,EAAqB;AACtD,EAAA,MAAM,IAAA,GAAO,WAAA,CAAY,CAAC,KAAA,KAA+B;AACvD,IAAA,MAAM,MAAA,GAAS,QAAQ,KAAK,CAAA;AAG5B,IAAA,OAAO,UAAU,OAAQ,MAAA,CAAyB,SAAS,UAAA,GACtD,MAAA,CAAyB,MAAM,MAAM;AAAA,IAAC,CAAC,CAAA,GACxC,MAAA;AAAA,EACN,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AACZ,EAAA,OAAO,OAAA,CAAQ,OAAO,EAAE,KAAA,EAAO,MAAK,CAAA,EAAI,CAAC,KAAA,EAAO,IAAI,CAAC,CAAA;AACvD;;;ACpDO,IAAM,sBAAA,GAAyB;AAO/B,IAAM,8BAAA,GAAiC;AAGvC,IAAM,wBAAA,GAA2B;AAGjC,IAAM,sBAAA,GAAyB;AAuCtC,IAAM,mBAAA,GACJ,+IAAA;AAOF,IAAM,qBAAA,GAAwB,gBAAA;AAGvB,SAAS,kBAAkB,KAAA,EAAyB;AACzD,EAAA,IAAI,KAAA,YAAiB,KAAA,IAAS,KAAA,CAAM,IAAA,KAAS,uBAAuB,OAAO,IAAA;AAC3E,EAAA,MAAM,OAAA,GACJ,iBAAiB,KAAA,GAAQ,KAAA,CAAM,UAAU,OAAO,KAAA,KAAU,WAAW,KAAA,GAAQ,EAAA;AAC/E,EAAA,OAAO,mBAAA,CAAoB,KAAK,OAAO,CAAA;AACzC;AAUA,SAAS,eAAe,IAAA,EAAgC;AACtD,EAAA,MAAM,OAAO,IAAA,CAAK,GAAA,CAAI,WAAA,EAAY,CAAE,MAAM,KAAK,CAAA;AAC/C,EAAA,IAAI,IAAA,CAAK,SAAS,YAAY,CAAA,IAAK,KAAK,QAAA,CAAS,eAAe,GAAG,OAAO,IAAA;AAC1E,EAAA,MAAM,MAAM,IAAA,CAAK,YAAA,CAAa,IAAI,CAAA,IAAK,IAAI,WAAA,EAAY;AACvD,EAAA,OAAO,KAAK,QAAA,CAAS,SAAS,CAAA,KAAM,EAAA,KAAO,YAAY,EAAA,KAAO,OAAA,CAAA;AAChE;AAUA,SAAS,cAAA,CAAe,OAAc,MAAA,EAA+B;AACnE,EAAA,MAAM,SAAS,KAAA,CAAM,MAAA;AACrB,EAAA,IAAI,GAAA,GAAM,EAAA;AACV,EAAA,IAAI,MAAA,YAAkB,MAAA,CAAO,iBAAA,EAAmB,GAAA,GAAM,MAAA,CAAO,GAAA;AAAA,OAAA,IACpD,kBAAkB,MAAA,CAAO,eAAA,IAAmB,eAAe,MAAM,CAAA,QAAS,MAAA,CAAO,IAAA;AAAA,OAAA,IACjF,iBAAiB,MAAA,CAAO,UAAA,IAAe,KAAA,CAAM,KAAA,EAAqC,SAAS,aAAA,EAAe;AACjH,IAAA,GAAA,GAAM,KAAA,CAAM,QAAA;AAAA,EACd;AACA,EAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AACjB,EAAA,IAAI;AAGF,IAAA,MAAM,OAAO,IAAI,GAAA,CAAI,QAAQ,MAAA,CAAO,QAAA,CAAS,MAAM,CAAA,CAAE,IAAA;AACrD,IAAA,MAAM,MAAM,IAAI,GAAA,CAAI,KAAK,MAAA,CAAO,QAAA,CAAS,IAAI,CAAA,CAAE,IAAA;AAC/C,IAAA,OAAO,GAAA,CAAI,UAAA,CAAW,IAAI,CAAA,GAAI,GAAA,GAAM,IAAA;AAAA,EACtC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAQA,eAAe,iBAAiB,GAAA,EAA+B;AAC7D,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAA,EAAK,EAAE,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAO,UAAA,EAAY,CAAA;AACvE,IAAA,IAAI,SAAS,MAAA,KAAW,GAAA,IAAO,QAAA,CAAS,MAAA,KAAW,KAAK,OAAO,IAAA;AAC/D,IAAA,OAAO,QAAA,CAAS,MAAM,iBAAA,CAAkB,IAAA,CAAK,SAAS,OAAA,CAAQ,GAAA,CAAI,cAAc,CAAA,IAAK,EAAE,CAAA;AAAA,EACzF,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEA,SAAS,cAAA,GAA8D;AACrE,EAAA,IAAI;AACF,IAAA,MAAM,IAAI,MAAA,CAAO,cAAA;AAEjB,IAAA,CAAA,CAAE,QAAQ,sBAAsB,CAAA;AAChC,IAAA,OAAO,CAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEA,SAAS,eAAe,OAAA,EAAqE;AAC3F,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AACrB,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,OAAA,CAAQ,sBAAsB,CAAA;AAClD,IAAA,MAAM,EAAA,GAAK,GAAA,KAAQ,IAAA,GAAO,GAAA,GAAM,OAAO,GAAG,CAAA;AAC1C,IAAA,OAAO,MAAA,CAAO,QAAA,CAAS,EAAE,CAAA,GAAI,EAAA,GAAK,IAAA;AAAA,EACpC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEA,SAAS,eAAA,CAAgB,SAAsD,EAAA,EAAkB;AAC/F,EAAA,IAAI,CAAC,OAAA,EAAS;AACd,EAAA,IAAI;AACF,IAAA,OAAA,CAAQ,OAAA,CAAQ,sBAAA,EAAwB,MAAA,CAAO,EAAE,CAAC,CAAA;AAAA,EACpD,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;AAQO,SAAS,uBAAA,CAAwB,OAAA,GAAmC,EAAC,EAAe;AACzF,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,OAAO,MAAM;AAAA,EAAC,CAAA;AAEjD,EAAA,MAAM,UAAA,GAAa,QAAQ,UAAA,IAAc,8BAAA;AACzC,EAAA,MAAM,SAAS,OAAA,CAAQ,MAAA,KAAW,MAAM,MAAA,CAAO,SAAS,MAAA,EAAO,CAAA;AAC/D,EAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,GAAA,IAAO,IAAA,CAAK,GAAA;AAChC,EAAA,MAAM,UAAU,OAAA,CAAQ,OAAA,KAAY,MAAA,GAAY,cAAA,KAAmB,OAAA,CAAQ,OAAA;AAC3E,EAAA,MAAM,eAAA,GACJ,OAAA,CAAQ,eAAA,KAAoB,MAAA,GAAY,yBAAyB,OAAA,CAAQ,eAAA;AAO3E,EAAA,MAAM,WAAA,GAAc,CAAC,KAAA,KAA4B;AAC/C,IAAA,MAAM,KAAK,GAAA,EAAI;AACf,IAAA,MAAM,IAAA,GAAO,eAAe,OAAO,CAAA;AACnC,IAAA,IAAI,IAAA,KAAS,IAAA,IAAQ,EAAA,GAAK,IAAA,GAAO,UAAA,EAAY;AAI3C,MAAA,OAAA,CAAQ,KAAA;AAAA,QACN,6FAAA;AAAA,QACA;AAAA,OACF;AACA,MAAA,OAAO,KAAA;AAAA,IACT;AACA,IAAA,eAAA,CAAgB,SAAS,EAAE,CAAA;AAC3B,IAAA,OAAA,CAAQ,IAAA;AAAA,MACN,2GAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,OAAO,IAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,cAAA,GAAiB,CAAC,KAAA,KAAiB;AACvC,IAAA,MAAM,UAAW,KAAA,CAAwC,OAAA;AAKzD,IAAA,IAAI,CAAC,iBAAA,CAAkB,OAAO,KAAK,CAAC,WAAA,CAAY,OAAO,CAAA,EAAG;AAC1D,IAAA,KAAA,CAAM,cAAA,EAAe;AACrB,IAAA,MAAA,EAAO;AAAA,EACT,CAAA;AAMA,EAAA,IAAI,MAAA,GAAS,IAAA;AACb,EAAA,IAAI,SAAA,GAAY,KAAA;AAChB,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAY;AAG/B,EAAA,MAAM,YAAA,GAAe,eAAA,KAAoB,IAAA,GAAO,IAAA,GAAO,CAAC,KAAA,KAAiB;AACvE,IAAA,MAAM,KAAA,GAAQ,cAAA,CAAe,KAAA,EAAO,eAAe,CAAA;AACnD,IAAA,IAAI,CAAC,KAAA,IAAS,SAAA,IAAa,MAAA,CAAO,GAAA,CAAI,KAAK,CAAA,EAAG;AAC9C,IAAA,MAAA,CAAO,IAAI,KAAK,CAAA;AAChB,IAAA,KAAK,gBAAA,CAAiB,KAAK,CAAA,CAAE,IAAA,CAAK,CAAC,IAAA,KAAS;AAC1C,MAAA,MAAA,CAAO,OAAO,KAAK,CAAA;AACnB,MAAA,IAAI,CAAC,QAAQ,CAAC,MAAA,IAAU,aAAa,CAAC,WAAA,CAAY,KAAK,CAAA,EAAG;AAC1D,MAAA,SAAA,GAAY,IAAA;AACZ,MAAA,MAAA,EAAO;AAAA,IACT,CAAC,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,MAAA,CAAO,gBAAA,CAAiB,0BAA0B,cAAc,CAAA;AAChE,EAAA,IAAI,YAAA,EAAc,MAAA,CAAO,gBAAA,CAAiB,OAAA,EAAS,cAAc,IAAI,CAAA;AACrE,EAAA,OAAO,MAAM;AACX,IAAA,MAAA,GAAS,KAAA;AACT,IAAA,MAAA,CAAO,mBAAA,CAAoB,0BAA0B,cAAc,CAAA;AACnE,IAAA,IAAI,YAAA,EAAc,MAAA,CAAO,mBAAA,CAAoB,OAAA,EAAS,cAAc,IAAI,CAAA;AAAA,EAC1E,CAAA;AACF","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"]}
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"]}
@@ -1,4 +1,4 @@
1
- import { currentShellStrings } from './chunk-7IN7YZAL.js';
1
+ import { currentShellStrings } from './chunk-72CQWN7O.js';
2
2
 
3
3
  // src/shell/toast.ts
4
4
  var TOAST_CONTAINER_ID = "toast-container";
@@ -191,5 +191,5 @@ var toast = {
191
191
  var toast_default = toast;
192
192
 
193
193
  export { toast_default };
194
- //# sourceMappingURL=chunk-EENVXIVU.js.map
195
- //# sourceMappingURL=chunk-EENVXIVU.js.map
194
+ //# sourceMappingURL=chunk-4P44JXDS.js.map
195
+ //# sourceMappingURL=chunk-4P44JXDS.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shell/toast.ts"],"names":[],"mappings":";;;AAwCA,IAAM,kBAAA,GAAqB,iBAAA;AAC3B,IAAM,yBAAA,GAA4B,wBAAA;AAClC,IAAM,kBAAA,GAAqB,iBAAA;AAC3B,IAAM,OAAA,GAAU,GAAA;AAChB,IAAM,MAAA,GAAS,4BAAA;AAkCf,IAAI,WAAyB,EAAC;AAG9B,IAAM,IAAA,uBAAW,GAAA,EAA2E;AAE5F,SAAS,WAAA,CAAY,IAAY,SAAA,EAAgC;AAC/D,EAAA,IAAI,EAAA,GAAK,QAAA,CAAS,cAAA,CAAe,EAAE,CAAA;AACnC,EAAA,IAAI,CAAC,EAAA,EAAI;AACP,IAAA,EAAA,GAAK,QAAA,CAAS,cAAc,KAAK,CAAA;AACjC,IAAA,EAAA,CAAG,EAAA,GAAK,EAAA;AACR,IAAA,EAAA,CAAG,SAAA,GAAY,SAAA;AACf,IAAA,QAAA,CAAS,IAAA,CAAK,YAAY,EAAE,CAAA;AAAA,EAC9B;AACA,EAAA,OAAO,EAAA;AACT;AASA,IAAM,MAAA,GAAwC;AAAA,EAC5C,OAAA,EAAS,gBAAA;AAAA,EACT,KAAA,EAAO,sBAAA;AAAA,EACP,OAAA,EAAS,kLAAA;AAAA,EACT,IAAA,EAAM,2DAAA;AAAA,EACN,OAAA,EAAS,mBAAA;AAAA,EACT,IAAA,EAAM;AACR,CAAA;AAEA,SAAS,KAAA,CAAM,MAAqB,SAAA,EAAkC;AACpE,EAAA,MAAM,GAAA,GAAM,QAAA,CAAS,eAAA,CAAgB,MAAA,EAAQ,KAAK,CAAA;AAClD,EAAA,GAAA,CAAI,YAAA,CAAa,SAAS,SAAS,CAAA;AACnC,EAAA,GAAA,CAAI,YAAA,CAAa,QAAQ,MAAM,CAAA;AAC/B,EAAA,GAAA,CAAI,YAAA,CAAa,WAAW,WAAW,CAAA;AACvC,EAAA,GAAA,CAAI,YAAA,CAAa,UAAU,cAAc,CAAA;AACzC,EAAA,GAAA,CAAI,YAAA,CAAa,gBAAgB,GAAG,CAAA;AACpC,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,eAAA,CAAgB,MAAA,EAAQ,MAAM,CAAA;AACpD,EAAA,IAAA,CAAK,YAAA,CAAa,kBAAkB,OAAO,CAAA;AAC3C,EAAA,IAAI,IAAA,KAAS,SAAA,EAAW,IAAA,CAAK,YAAA,CAAa,mBAAmB,OAAO,CAAA;AACpE,EAAA,IAAA,CAAK,YAAA,CAAa,GAAA,EAAK,MAAA,CAAO,IAAI,CAAC,CAAA;AACnC,EAAA,GAAA,CAAI,YAAY,IAAI,CAAA;AACpB,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,GAAA,CAAI,WAAmB,IAAA,EAA+B;AAC7D,EAAA,MAAM,EAAA,GAAK,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AACvC,EAAA,EAAA,CAAG,SAAA,GAAY,SAAA;AACf,EAAA,IAAI,IAAA,KAAS,MAAA,EAAW,EAAA,CAAG,WAAA,GAAc,IAAA;AACzC,EAAA,OAAO,EAAA;AACT;AAIA,SAAS,SAAA,CAAU,OAAA,EAAe,OAAA,EACf,IAAA,EAA8C;AAC/D,EAAA,MAAM,KAAA,GAAQ,EAAE,GAAG,QAAA,EAAU,GAAG,IAAA,EAAK;AACrC,EAAA,MAAM,SAAA,GAA4B,MAAM,SAAA,IAAa,KAAA;AACrD,EAAA,MAAM,MAAA,GAAS,MAAM,MAAA,IAAU,KAAA;AAG/B,EAAA,MAAM,MAAM,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,OAAO,IAAI,OAAO,CAAA,CAAA;AAC9C,EAAA,IAAI,MAAM,MAAA,EAAQ;AAChB,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA;AAC7B,IAAA,IAAI,QAAA,EAAU;AAAE,MAAA,QAAA,CAAS,OAAA,EAAQ;AAAG,MAAA,OAAO,EAAE,OAAA,EAAS,QAAA,CAAS,OAAA,EAAQ;AAAA,IAAG;AAAA,EAC5E;AAIA,EAAA,IAAI,YAAY,SAAA,EAAW;AACzB,IAAA,OAAO,sBAAiB,CAAA,CAAE,IAAA,CAAK,CAAA,CAAA,KAAK;AAClC,MAAA,IAAI,OAAA,KAAY,SAAA,EAAW,CAAA,CAAE,WAAA,EAAY;AAAA,WAAA,IAChC,OAAA,KAAY,OAAA,EAAS,CAAA,CAAE,SAAA,EAAU;AAAA,aACnC,gBAAA,EAAiB;AAAA,IAC1B,CAAC,CAAA,CAAE,KAAA,CAAM,MAAM;AAAA,IAAC,CAAC,CAAA;AAAA,EACnB;AAEA,EAAA,MAAM,SAAA,GAAY,cAAc,QAAA,GAC5B,WAAA,CAAY,2BAA2B,gHAAgH,CAAA,GACvJ,WAAA,CAAY,kBAAA,EAAoB,qGAAqG,CAAA;AAIzI,EAAA,MAAM,SAAA,GAAY,SAAA,KAAc,QAAA,GAAW,kBAAA,GAAqB,mBAAA;AAMhE,EAAA,MAAM,EAAA,GAAK,IAAI,+CAA+C,CAAA;AAC9D,EAAA,EAAA,CAAG,MAAM,OAAA,GAAU,GAAA;AACnB,EAAA,EAAA,CAAG,KAAA,CAAM,SAAA,GAAY,CAAA,EAAG,SAAS,CAAA,YAAA,CAAA;AAKjC,EAAA,EAAA,CAAG,YAAA,CAAa,MAAA,EAAQ,OAAA,KAAY,OAAA,GAAU,UAAU,QAAQ,CAAA;AAGhE,EAAA,EAAA,CAAG,YAAA,CAAa,eAAe,MAAM,CAAA;AAErC,EAAA,EAAA,CAAG,WAAA,CAAY,KAAA,CAAM,OAAA,EAAS,CAAA,kBAAA,EAAqB,OAAO,CAAA,EAAG,OAAA,KAAY,SAAA,GAAY,eAAA,GAAkB,EAAE,CAAA,CAAE,CAAC,CAAA;AAC5G,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,aAAA,CAAc,MAAM,CAAA;AAC1C,EAAA,IAAA,CAAK,WAAA,GAAc,OAAA;AACnB,EAAA,EAAA,CAAG,YAAY,IAAI,CAAA;AAEnB,EAAA,SAAA,CAAU,YAAY,EAAE,CAAA;AACxB,EAAA,qBAAA,CAAsB,MAAM;AAAE,IAAA,EAAA,CAAG,MAAM,OAAA,GAAU,GAAA;AAAK,IAAA,EAAA,CAAG,MAAM,SAAA,GAAY,wBAAA;AAAA,EAA0B,CAAC,CAAA;AAEtG,EAAA,IAAI,KAAA;AACJ,EAAA,IAAI,IAAA,GAAO,KAAA;AACX,EAAA,MAAM,UAAU,MAAM;AACpB,IAAA,IAAI,IAAA,EAAM;AACV,IAAA,IAAA,GAAO,IAAA;AACP,IAAA,IAAI,KAAA,eAAoB,KAAK,CAAA;AAC7B,IAAA,IAAA,CAAK,OAAO,GAAG,CAAA;AACf,IAAA,EAAA,CAAG,MAAM,OAAA,GAAU,GAAA;AACnB,IAAA,EAAA,CAAG,KAAA,CAAM,SAAA,GAAY,CAAA,EAAG,SAAS,CAAA,YAAA,CAAA;AACjC,IAAA,UAAA,CAAW,MAAM,EAAA,CAAG,MAAA,EAAO,EAAG,OAAO,CAAA;AAAA,EACvC,CAAA;AAIA,EAAA,MAAM,QAAA,GAAW,KAAA,CAAM,QAAA,KAAa,OAAA,KAAY,SAAS,IAAA,GAAO,GAAA,CAAA;AAChE,EAAA,MAAM,UAAU,MAAM;AACpB,IAAA,IAAI,KAAA,eAAoB,KAAK,CAAA;AAC7B,IAAA,IAAI,CAAC,MAAA,EAAQ,KAAA,GAAQ,UAAA,CAAW,SAAS,QAAQ,CAAA;AAAA,EACnD,CAAA;AACA,EAAA,OAAA,EAAQ;AAMR,EAAA,EAAA,CAAG,gBAAA,CAAiB,cAAc,MAAM;AAAE,IAAA,IAAI,KAAA,eAAoB,KAAK,CAAA;AAAA,EAAG,CAAC,CAAA;AAC3E,EAAA,EAAA,CAAG,gBAAA,CAAiB,cAAc,MAAM;AAAE,IAAA,IAAI,CAAC,MAAM,OAAA,EAAQ;AAAA,EAAG,CAAC,CAAA;AAKjE,EAAA,EAAA,CAAG,gBAAA,CAAiB,SAAS,OAAO,CAAA;AAEpC,EAAA,IAAA,CAAK,IAAI,GAAA,EAAK,EAAE,EAAA,EAAI,OAAA,EAAS,SAAS,CAAA;AAEtC,EAAA,OAAO,EAAE,OAAA,EAAQ;AACnB;AAIA,SAAS,gBAAA,CAAiB,SAAiB,IAAA,EAA8B;AACvE,EAAA,OAAO,sBAAiB,EAAE,IAAA,CAAK,CAAA,CAAA,KAAK,EAAE,gBAAA,EAAkB,CAAA,CAAE,KAAA,CAAM,MAAM;AAAA,EAAC,CAAC,CAAA;AAExE,EAAA,MAAM,SAAA,GAAY,WAAA,CAAY,kBAAA,EAAoB,gFAAgF,CAAA;AAElI,EAAA,MAAM,EAAA,GAAK,IAAI,+CAA+C,CAAA;AAC9D,EAAA,EAAA,CAAG,MAAM,OAAA,GAAU,GAAA;AACnB,EAAA,EAAA,CAAG,MAAM,SAAA,GAAY,8BAAA;AAErB,EAAA,MAAM,KAAA,GAAQ,IAAI,kBAAkB,CAAA;AACpC,EAAA,KAAA,CAAM,WAAA,CAAY,KAAA,CAAM,MAAA,EAAQ,SAAS,CAAC,CAAA;AAC1C,EAAA,MAAM,IAAA,GAAO,IAAI,iBAAiB,CAAA;AAElC,EAAA,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,kBAAA,EAAoB,mBAAA,EAAoB,CAAE,KAAA,CAAM,YAAY,CAAA,EAAG,GAAA,CAAI,0BAAA,EAA4B,OAAO,CAAC,CAAA;AAGvH,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,aAAA,CAAc,QAAQ,CAAA;AAC7C,EAAA,KAAA,CAAM,SAAA,GAAY,kBAAA;AAClB,EAAA,KAAA,CAAM,WAAA,GAAc,MAAA;AACpB,EAAA,EAAA,CAAG,MAAA,CAAO,KAAA,EAAO,IAAA,EAAM,KAAK,CAAA;AAE5B,EAAA,MAAM,UAAU,MAAM;AACpB,IAAA,EAAA,CAAG,MAAM,OAAA,GAAU,GAAA;AACnB,IAAA,EAAA,CAAG,MAAM,SAAA,GAAY,8BAAA;AACrB,IAAA,UAAA,CAAW,MAAM,EAAA,CAAG,MAAA,EAAO,EAAG,OAAO,CAAA;AAAA,EACvC,CAAA;AAEA,EAAA,KAAA,CAAM,gBAAA,CAAiB,OAAA,EAAS,CAAC,CAAA,KAAM;AAAE,IAAA,CAAA,CAAE,eAAA,EAAgB;AAAG,IAAA,OAAA,EAAQ;AAAA,EAAG,CAAC,CAAA;AAC1E,EAAA,EAAA,CAAG,gBAAA,CAAiB,SAAS,OAAO,CAAA;AAEpC,EAAA,SAAA,CAAU,YAAY,EAAE,CAAA;AACxB,EAAA,qBAAA,CAAsB,MAAM;AAAE,IAAA,EAAA,CAAG,MAAM,OAAA,GAAU,GAAA;AAAK,IAAA,EAAA,CAAG,MAAM,SAAA,GAAY,wBAAA;AAAA,EAA0B,CAAC,CAAA;AAEtG,EAAA,UAAA,CAAW,OAAA,EAAS,IAAA,EAAM,QAAA,IAAY,GAAK,CAAA;AAC7C;AAEA,IAAM,KAAA,GAAQ;AAAA,EACZ,SAAS,CAAC,OAAA,EAAiB,SAAwB,SAAA,CAAU,SAAA,EAAW,SAAS,IAAI,CAAA;AAAA,EACrF,OAAO,CAAC,OAAA,EAAiB,SAAwB,SAAA,CAAU,OAAA,EAAS,SAAS,IAAI,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMjF,SAAS,CAAC,OAAA,EAAiB,SAAwB,SAAA,CAAU,SAAA,EAAW,SAAS,IAAI,CAAA;AAAA,EACrF,MAAM,CAAC,OAAA,EAAiB,SAAwB,SAAA,CAAU,MAAA,EAAQ,SAAS,IAAI,CAAA;AAAA;AAAA,EAE/E,QAAQ,CAAC,OAAA,EAAiB,IAAA,KAAiC,gBAAA,CAAiB,SAAS,IAAI,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAazF,OAAA,EAAS,CACP,CAAA,EACA,IAAA,EAKA,IAAA,KACe;AACf,IAAA,MAAM,OAAA,GAAU,SAAA,CAAU,SAAA,EAAW,IAAA,CAAK,OAAA,EAAS,EAAE,GAAG,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,CAAA;AAC5E,IAAA,CAAA,CAAE,IAAA;AAAA,MACA,CAAA,KAAA,KAAS;AACP,QAAA,OAAA,CAAQ,OAAA,EAAQ;AAChB,QAAA,SAAA,CAAU,SAAA,EAAW,OAAO,IAAA,CAAK,OAAA,KAAY,UAAA,GAAa,IAAA,CAAK,OAAA,CAAQ,KAAK,CAAA,GAAI,IAAA,CAAK,OAAA,EAAS,IAAI,CAAA;AAAA,MACpG,CAAA;AAAA,MACA,CAAA,KAAA,KAAS;AACP,QAAA,OAAA,CAAQ,OAAA,EAAQ;AAChB,QAAA,SAAA,CAAU,OAAA,EAAS,OAAO,IAAA,CAAK,KAAA,KAAU,UAAA,GAAa,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA,GAAI,IAAA,CAAK,KAAA,EAAO,IAAI,CAAA;AAAA,MAC5F;AAAA,KACF;AACA,IAAA,OAAO,CAAA;AAAA,EACT,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAA,EAAW,CAAC,IAAA,KAAuB;AAAE,IAAA,QAAA,GAAW,EAAE,GAAG,IAAA,EAAK;AAAA,EAAG;AAC/D,CAAA;AAEA,IAAO,aAAA,GAAQ","file":"chunk-EENVXIVU.js","sourcesContent":["/**\n * Two presentations:\n *\n * 1. toast.success / error / info — brief operation feedback, top-center,\n * auto-dismiss (success/error ~3s, info ~4.5s). The everyday \"what just\n * happened\" feedback — most messages want this.\n * 2. toast.notify — system notification, top-right card, stays 10s, dismissible.\n * For an alert worth lingering on; reach for it deliberately, not by default.\n *\n * (Historically `toast.info` rendered the top-right notification card; it now\n * renders a brief toast — that persistent card moved to `toast.notify`.)\n *\n * ── Built for a strict Content-Security-Policy ──\n *\n * Every node here is made with `createElement`/`createElementNS` and dressed\n * with CLASSES from ui.css (`.rosh-toast`, `.rosh-notif`…). There is no HTML\n * string, no `style=\"…\"` attribute and no `on…=` handler anywhere in the\n * markup, and that is load-bearing rather than tidy:\n *\n * - An inline handler attribute is inline SCRIPT. Under any `script-src`\n * without `'unsafe-inline'` (a nonce-based policy, which is what Next.js\n * apps run) the browser refuses it and files a violation report. The\n * notification card's close button used to carry one for its hover colour,\n * so every `toast.notify` on such a site was a CSP report.\n * - A `style` attribute that arrives through markup is governed by\n * `style-src`; a policy with a nonce or a hash there ignores\n * `'unsafe-inline'` and drops it. Styles set through the CSSOM\n * (`el.style.opacity = …`) are not, which is why the enter/leave motion\n * below still writes `el.style` directly — that is the one dynamic part.\n * - No `innerHTML` also means nothing here needs a Trusted Types policy.\n *\n * The cost is that the toast's look now lives in ui.css, which every consumer\n * already imports (alone, or inside styles.css). Its colours are custom\n * properties there (`--rosh-toast-*`) with the values it always had, so a host\n * can restyle a toast without forking it.\n * `tests/strictCsp.test.ts` holds the DOM to all of this.\n */\n\nimport { currentShellStrings } from './strings';\n\nconst TOAST_CONTAINER_ID = 'toast-container';\nconst TOAST_BOTTOM_CONTAINER_ID = 'toast-container-bottom';\nconst NOTIF_CONTAINER_ID = 'notif-container';\nconst FADE_MS = 300;\nconst SVG_NS = 'http://www.w3.org/2000/svg';\n\nexport type ToastPlacement = 'top' | 'bottom';\n\nexport interface ToastOptions {\n /** Milliseconds before auto-dismiss. Ignored when `sticky`. */\n duration?: number;\n /**\n * Stay until dismissed. For a message the user must actually act on — the\n * kind that must not scroll past while they are looking at a customer.\n * Implies tap-to-dismiss is the only way out, which it already is.\n */\n sticky?: boolean;\n /**\n * `bottom` centres toasts along the bottom edge. On a till the top of the\n * screen is the cart total and the bottom is nearest the hand.\n */\n placement?: ToastPlacement;\n /**\n * Drop a message identical to one already showing, and RESTART its timer\n * rather than stacking a second copy. A failing poll otherwise writes the\n * same sentence a dozen times. The restart matters: the user asked twice, so\n * the message should persist, not expire on the first one's schedule.\n */\n dedupe?: boolean;\n}\n\n/**\n * Defaults for every subsequent toast, set once at app startup — the same\n * \"consumer wires this once\" shape as `setShellApiClient`/`setShellNavIcons`.\n * A till calls `toast.configure({ placement: 'bottom', duration: 6000,\n * dedupe: true })` instead of repeating those options at 40 call sites.\n * Per-call options still win.\n */\nlet defaults: ToastOptions = {};\n\n/** Live toasts by dedupe key, so a repeat can find and refresh its own. */\nconst live = new Map<string, { el: HTMLElement; restart: () => void; dismiss: () => void }>();\n\nfunction getOrCreate(id: string, className: string): HTMLElement {\n let el = document.getElementById(id);\n if (!el) {\n el = document.createElement('div');\n el.id = id;\n el.className = className;\n document.body.appendChild(el);\n }\n return el;\n}\n\ntype Tone = 'success' | 'error' | 'warning' | 'info' | 'loading';\n\n/**\n * Outline glyphs (Heroicons' paths), stroked in `currentColor` so the colour\n * comes from the tone class in ui.css rather than from an attribute here.\n * `loading` is an open arc that spins — the same vocabulary as LoadingSpinner.\n */\nconst GLYPHS: Record<Tone | 'bell', string> = {\n success: 'M5 13l4 4L19 7',\n error: 'M6 18L18 6M6 6l12 12',\n 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',\n info: 'M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z',\n loading: 'M12 3a9 9 0 019 9',\n 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',\n};\n\nfunction glyph(name: Tone | 'bell', className: string): SVGSVGElement {\n const svg = document.createElementNS(SVG_NS, 'svg');\n svg.setAttribute('class', className);\n svg.setAttribute('fill', 'none');\n svg.setAttribute('viewBox', '0 0 24 24');\n svg.setAttribute('stroke', 'currentColor');\n svg.setAttribute('stroke-width', '2');\n const path = document.createElementNS(SVG_NS, 'path');\n path.setAttribute('stroke-linecap', 'round');\n if (name !== 'loading') path.setAttribute('stroke-linejoin', 'round');\n path.setAttribute('d', GLYPHS[name]);\n svg.appendChild(path);\n return svg;\n}\n\nfunction div(className: string, text?: string): HTMLDivElement {\n const el = document.createElement('div');\n el.className = className;\n if (text !== undefined) el.textContent = text;\n return el;\n}\n\n// ── Toast (operation feedback) — top-center, brief ──\n\nfunction showToast(variant: Tone, message: string,\n opts?: ToastOptions): { dismiss: () => void } {\n const opts_ = { ...defaults, ...opts };\n const placement: ToastPlacement = opts_.placement ?? 'top';\n const sticky = opts_.sticky ?? false;\n\n // A repeat of a message already on screen refreshes it instead of stacking.\n const key = `${placement}|${variant}|${message}`;\n if (opts_.dedupe) {\n const existing = live.get(key);\n if (existing) { existing.restart(); return { dismiss: existing.dismiss }; }\n }\n\n // A loading toast is the START of an operation — the sound belongs to the\n // outcome, which follows in a moment.\n if (variant !== 'loading') {\n import('../utils/sounds').then(s => {\n if (variant === 'success') s.playSuccess();\n else if (variant === 'error') s.playError();\n else s.playNotification();\n }).catch(() => {});\n }\n\n const container = placement === 'bottom'\n ? 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')\n : 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');\n\n // Enter from the edge the toast is anchored to, so it reads as arriving from\n // off-screen rather than drifting in from the wrong direction.\n const offscreen = placement === 'bottom' ? 'translateY(10px)' : 'translateY(-10px)';\n\n // The tone is a CLASS: `.rosh-tone-warning` and friends in ui.css colour the\n // glyph through `--rosh-toast-*`. Warning is amber and deliberately not the\n // error red: a warning is something to read before continuing, not something\n // that failed, and painting both red teaches people to ignore the colour.\n const el = div('pointer-events-auto cursor-pointer rosh-toast');\n el.style.opacity = '0';\n el.style.transform = `${offscreen} scale(0.95)`;\n // A toast IS a status message, and it appears without the user moving focus\n // — so without a live region it is announced to nobody. `alert` is\n // assertive and interrupts whatever is being read, which is right for a\n // failure and wrong for a confirmation the user already expected.\n el.setAttribute('role', variant === 'error' ? 'alert' : 'status');\n // Read the whole toast, not the word that changed. Without it a repeat that\n // only alters a number announces the number alone.\n el.setAttribute('aria-atomic', 'true');\n\n el.appendChild(glyph(variant, `h-4 w-4 rosh-tone-${variant}${variant === 'loading' ? ' animate-spin' : ''}`));\n const span = document.createElement('span');\n span.textContent = message;\n el.appendChild(span);\n\n container.appendChild(el);\n requestAnimationFrame(() => { el.style.opacity = '1'; el.style.transform = 'translateY(0) scale(1)'; });\n\n let timer: ReturnType<typeof setTimeout> | undefined;\n let gone = false;\n const dismiss = () => {\n if (gone) return;\n gone = true;\n if (timer) clearTimeout(timer);\n live.delete(key);\n el.style.opacity = '0';\n el.style.transform = `${offscreen} scale(0.95)`;\n setTimeout(() => el.remove(), FADE_MS);\n };\n\n // Info messages are usually a sentence (\"no matches — check X\"); give them a\n // beat longer to read than the terse success/error confirmations.\n const duration = opts_.duration ?? (variant === 'info' ? 4500 : 3000);\n const restart = () => {\n if (timer) clearTimeout(timer);\n if (!sticky) timer = setTimeout(dismiss, duration);\n };\n restart();\n\n // Hold the timer while the pointer rests on it. Three seconds is enough to\n // read a confirmation and not enough to read an address someone leaned in\n // for — and a toast that vanishes as you reach for it cannot be re-read at\n // all, since there is no history to open.\n el.addEventListener('mouseenter', () => { if (timer) clearTimeout(timer); });\n el.addEventListener('mouseleave', () => { if (!gone) restart(); });\n\n // Tap anywhere on the toast to dismiss it. A toast has no other click\n // affordance, and a sticky one has no other exit at all — `notify` has\n // behaved this way since it existed.\n el.addEventListener('click', dismiss);\n\n live.set(key, { el, restart, dismiss });\n // Internal handle — `toast.promise` swaps its loading toast for the outcome.\n return { dismiss };\n}\n\n// ── Notification (system alert) — top-right, stays longer ──\n\nfunction showNotification(message: string, opts?: { duration?: number }) {\n import('../utils/sounds').then(s => s.playNotification()).catch(() => {});\n\n const container = getOrCreate(NOTIF_CONTAINER_ID, 'fixed top-4 right-4 z-[9999] flex flex-col gap-3 items-end pointer-events-none');\n\n const el = div('pointer-events-auto cursor-pointer rosh-notif');\n el.style.opacity = '0';\n el.style.transform = 'translateX(30px) scale(0.95)';\n\n const badge = div('rosh-notif-badge');\n badge.appendChild(glyph('bell', 'h-5 w-5'));\n const body = div('rosh-notif-body');\n // The heading is the app's catalog word — read here, outside React.\n body.append(div('rosh-notif-title', currentShellStrings().toast.notification), div('notif-msg rosh-notif-msg', message));\n // The close button's hover colour is a `:hover` rule in ui.css. It was an\n // `onmouseenter` attribute — inline script, refused by a strict CSP.\n const close = document.createElement('button');\n close.className = 'rosh-notif-close';\n close.textContent = '×';\n el.append(badge, body, close);\n\n const dismiss = () => {\n el.style.opacity = '0';\n el.style.transform = 'translateX(30px) scale(0.95)';\n setTimeout(() => el.remove(), FADE_MS);\n };\n\n close.addEventListener('click', (e) => { e.stopPropagation(); dismiss(); });\n el.addEventListener('click', dismiss);\n\n container.appendChild(el);\n requestAnimationFrame(() => { el.style.opacity = '1'; el.style.transform = 'translateX(0) scale(1)'; });\n\n setTimeout(dismiss, opts?.duration ?? 10000);\n}\n\nconst toast = {\n success: (message: string, opts?: ToastOptions) => showToast('success', message, opts),\n error: (message: string, opts?: ToastOptions) => showToast('error', message, opts),\n /**\n * Something the user should read before continuing — a partial success, a\n * setting that will not apply until they do something else. Distinct from\n * `error`, which is \"this did not happen\".\n */\n warning: (message: string, opts?: ToastOptions) => showToast('warning', message, opts),\n info: (message: string, opts?: ToastOptions) => showToast('info', message, opts),\n // Persistent top-right notification card (the old toast.info presentation).\n notify: (message: string, opts?: { duration?: number }) => showNotification(message, opts),\n /**\n * One toast for one async operation: a spinning \"loading\" toast while `p`\n * is pending, swapped for a success or error toast when it settles. The\n * promise is returned untouched, so `await toast.promise(save(), …)` still\n * throws to the caller — this narrates the operation, it does not handle it.\n *\n * `error` is REQUIRED, and there is deliberately no fallback that prints\n * the exception: a raw `e.message` in a toast is how internals leak to the\n * screen (the same reasoning that keeps ErrorBoundary's stack behind\n * `showDetails`). The success/error messages may be functions of the\n * resolved value / the rejection, for the \"Saved 3 rows\" case.\n */\n promise: <T,>(\n p: Promise<T>,\n msgs: {\n loading: string;\n success: string | ((value: T) => string);\n error: string | ((error: unknown) => string);\n },\n opts?: ToastOptions,\n ): Promise<T> => {\n const pending = showToast('loading', msgs.loading, { ...opts, sticky: true });\n p.then(\n value => {\n pending.dismiss();\n showToast('success', typeof msgs.success === 'function' ? msgs.success(value) : msgs.success, opts);\n },\n error => {\n pending.dismiss();\n showToast('error', typeof msgs.error === 'function' ? msgs.error(error) : msgs.error, opts);\n },\n );\n return p;\n },\n /**\n * Set defaults for every subsequent toast. Call once at app startup; later\n * calls replace the whole object rather than merging, so a consumer sets its\n * policy in one place. Per-call options still take precedence.\n */\n configure: (next: ToastOptions) => { defaults = { ...next }; },\n};\n\nexport default toast;\n"]}
1
+ {"version":3,"sources":["../src/shell/toast.ts"],"names":[],"mappings":"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","file":"chunk-4P44JXDS.js","sourcesContent":["/**\n * Two presentations:\n *\n * 1. toast.success / error / info — brief operation feedback, top-center,\n * auto-dismiss (success/error ~3s, info ~4.5s). The everyday \"what just\n * happened\" feedback — most messages want this.\n * 2. toast.notify — system notification, top-right card, stays 10s, dismissible.\n * For an alert worth lingering on; reach for it deliberately, not by default.\n *\n * (Historically `toast.info` rendered the top-right notification card; it now\n * renders a brief toast — that persistent card moved to `toast.notify`.)\n *\n * ── Built for a strict Content-Security-Policy ──\n *\n * Every node here is made with `createElement`/`createElementNS` and dressed\n * with CLASSES from ui.css (`.rosh-toast`, `.rosh-notif`…). There is no HTML\n * string, no `style=\"…\"` attribute and no `on…=` handler anywhere in the\n * markup, and that is load-bearing rather than tidy:\n *\n * - An inline handler attribute is inline SCRIPT. Under any `script-src`\n * without `'unsafe-inline'` (a nonce-based policy, which is what Next.js\n * apps run) the browser refuses it and files a violation report. The\n * notification card's close button used to carry one for its hover colour,\n * so every `toast.notify` on such a site was a CSP report.\n * - A `style` attribute that arrives through markup is governed by\n * `style-src`; a policy with a nonce or a hash there ignores\n * `'unsafe-inline'` and drops it. Styles set through the CSSOM\n * (`el.style.opacity = …`) are not, which is why the enter/leave motion\n * below still writes `el.style` directly — that is the one dynamic part.\n * - No `innerHTML` also means nothing here needs a Trusted Types policy.\n *\n * The cost is that the toast's look now lives in ui.css, which every consumer\n * already imports (alone, or inside styles.css). Its colours are custom\n * properties there (`--rosh-toast-*`) with the values it always had, so a host\n * can restyle a toast without forking it.\n * `tests/strictCsp.test.ts` holds the DOM to all of this.\n */\n\nimport { currentShellStrings } from './strings';\n\nconst TOAST_CONTAINER_ID = 'toast-container';\nconst TOAST_BOTTOM_CONTAINER_ID = 'toast-container-bottom';\nconst NOTIF_CONTAINER_ID = 'notif-container';\nconst FADE_MS = 300;\nconst SVG_NS = 'http://www.w3.org/2000/svg';\n\nexport type ToastPlacement = 'top' | 'bottom';\n\nexport interface ToastOptions {\n /** Milliseconds before auto-dismiss. Ignored when `sticky`. */\n duration?: number;\n /**\n * Stay until dismissed. For a message the user must actually act on — the\n * kind that must not scroll past while they are looking at a customer.\n * Implies tap-to-dismiss is the only way out, which it already is.\n */\n sticky?: boolean;\n /**\n * `bottom` centres toasts along the bottom edge. On a till the top of the\n * screen is the cart total and the bottom is nearest the hand.\n */\n placement?: ToastPlacement;\n /**\n * Drop a message identical to one already showing, and RESTART its timer\n * rather than stacking a second copy. A failing poll otherwise writes the\n * same sentence a dozen times. The restart matters: the user asked twice, so\n * the message should persist, not expire on the first one's schedule.\n */\n dedupe?: boolean;\n}\n\n/**\n * Defaults for every subsequent toast, set once at app startup — the same\n * \"consumer wires this once\" shape as `setShellApiClient`/`setShellNavIcons`.\n * A till calls `toast.configure({ placement: 'bottom', duration: 6000,\n * dedupe: true })` instead of repeating those options at 40 call sites.\n * Per-call options still win.\n */\nlet defaults: ToastOptions = {};\n\n/** Live toasts by dedupe key, so a repeat can find and refresh its own. */\nconst live = new Map<string, { el: HTMLElement; restart: () => void; dismiss: () => void }>();\n\nfunction getOrCreate(id: string, className: string): HTMLElement {\n let el = document.getElementById(id);\n if (!el) {\n el = document.createElement('div');\n el.id = id;\n el.className = className;\n document.body.appendChild(el);\n }\n return el;\n}\n\ntype Tone = 'success' | 'error' | 'warning' | 'info' | 'loading';\n\n/**\n * Outline glyphs (Heroicons' paths), stroked in `currentColor` so the colour\n * comes from the tone class in ui.css rather than from an attribute here.\n * `loading` is an open arc that spins — the same vocabulary as LoadingSpinner.\n */\nconst GLYPHS: Record<Tone | 'bell', string> = {\n success: 'M5 13l4 4L19 7',\n error: 'M6 18L18 6M6 6l12 12',\n 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',\n info: 'M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z',\n loading: 'M12 3a9 9 0 019 9',\n 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',\n};\n\nfunction glyph(name: Tone | 'bell', className: string): SVGSVGElement {\n const svg = document.createElementNS(SVG_NS, 'svg');\n svg.setAttribute('class', className);\n svg.setAttribute('fill', 'none');\n svg.setAttribute('viewBox', '0 0 24 24');\n svg.setAttribute('stroke', 'currentColor');\n svg.setAttribute('stroke-width', '2');\n const path = document.createElementNS(SVG_NS, 'path');\n path.setAttribute('stroke-linecap', 'round');\n if (name !== 'loading') path.setAttribute('stroke-linejoin', 'round');\n path.setAttribute('d', GLYPHS[name]);\n svg.appendChild(path);\n return svg;\n}\n\nfunction div(className: string, text?: string): HTMLDivElement {\n const el = document.createElement('div');\n el.className = className;\n if (text !== undefined) el.textContent = text;\n return el;\n}\n\n// ── Toast (operation feedback) — top-center, brief ──\n\nfunction showToast(variant: Tone, message: string,\n opts?: ToastOptions): { dismiss: () => void } {\n const opts_ = { ...defaults, ...opts };\n const placement: ToastPlacement = opts_.placement ?? 'top';\n const sticky = opts_.sticky ?? false;\n\n // A repeat of a message already on screen refreshes it instead of stacking.\n const key = `${placement}|${variant}|${message}`;\n if (opts_.dedupe) {\n const existing = live.get(key);\n if (existing) { existing.restart(); return { dismiss: existing.dismiss }; }\n }\n\n // A loading toast is the START of an operation — the sound belongs to the\n // outcome, which follows in a moment.\n if (variant !== 'loading') {\n import('../utils/sounds').then(s => {\n if (variant === 'success') s.playSuccess();\n else if (variant === 'error') s.playError();\n else s.playNotification();\n }).catch(() => {});\n }\n\n const container = placement === 'bottom'\n ? 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')\n : 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');\n\n // Enter from the edge the toast is anchored to, so it reads as arriving from\n // off-screen rather than drifting in from the wrong direction.\n const offscreen = placement === 'bottom' ? 'translateY(10px)' : 'translateY(-10px)';\n\n // The tone is a CLASS: `.rosh-tone-warning` and friends in ui.css colour the\n // glyph through `--rosh-toast-*`. Warning is amber and deliberately not the\n // error red: a warning is something to read before continuing, not something\n // that failed, and painting both red teaches people to ignore the colour.\n const el = div('pointer-events-auto cursor-pointer rosh-toast');\n el.style.opacity = '0';\n el.style.transform = `${offscreen} scale(0.95)`;\n // A toast IS a status message, and it appears without the user moving focus\n // — so without a live region it is announced to nobody. `alert` is\n // assertive and interrupts whatever is being read, which is right for a\n // failure and wrong for a confirmation the user already expected.\n el.setAttribute('role', variant === 'error' ? 'alert' : 'status');\n // Read the whole toast, not the word that changed. Without it a repeat that\n // only alters a number announces the number alone.\n el.setAttribute('aria-atomic', 'true');\n\n el.appendChild(glyph(variant, `h-4 w-4 rosh-tone-${variant}${variant === 'loading' ? ' animate-spin' : ''}`));\n const span = document.createElement('span');\n span.textContent = message;\n el.appendChild(span);\n\n container.appendChild(el);\n requestAnimationFrame(() => { el.style.opacity = '1'; el.style.transform = 'translateY(0) scale(1)'; });\n\n let timer: ReturnType<typeof setTimeout> | undefined;\n let gone = false;\n const dismiss = () => {\n if (gone) return;\n gone = true;\n if (timer) clearTimeout(timer);\n live.delete(key);\n el.style.opacity = '0';\n el.style.transform = `${offscreen} scale(0.95)`;\n setTimeout(() => el.remove(), FADE_MS);\n };\n\n // Info messages are usually a sentence (\"no matches — check X\"); give them a\n // beat longer to read than the terse success/error confirmations.\n const duration = opts_.duration ?? (variant === 'info' ? 4500 : 3000);\n const restart = () => {\n if (timer) clearTimeout(timer);\n if (!sticky) timer = setTimeout(dismiss, duration);\n };\n restart();\n\n // Hold the timer while the pointer rests on it. Three seconds is enough to\n // read a confirmation and not enough to read an address someone leaned in\n // for — and a toast that vanishes as you reach for it cannot be re-read at\n // all, since there is no history to open.\n el.addEventListener('mouseenter', () => { if (timer) clearTimeout(timer); });\n el.addEventListener('mouseleave', () => { if (!gone) restart(); });\n\n // Tap anywhere on the toast to dismiss it. A toast has no other click\n // affordance, and a sticky one has no other exit at all — `notify` has\n // behaved this way since it existed.\n el.addEventListener('click', dismiss);\n\n live.set(key, { el, restart, dismiss });\n // Internal handle — `toast.promise` swaps its loading toast for the outcome.\n return { dismiss };\n}\n\n// ── Notification (system alert) — top-right, stays longer ──\n\nfunction showNotification(message: string, opts?: { duration?: number }) {\n import('../utils/sounds').then(s => s.playNotification()).catch(() => {});\n\n const container = getOrCreate(NOTIF_CONTAINER_ID, 'fixed top-4 right-4 z-[9999] flex flex-col gap-3 items-end pointer-events-none');\n\n const el = div('pointer-events-auto cursor-pointer rosh-notif');\n el.style.opacity = '0';\n el.style.transform = 'translateX(30px) scale(0.95)';\n\n const badge = div('rosh-notif-badge');\n badge.appendChild(glyph('bell', 'h-5 w-5'));\n const body = div('rosh-notif-body');\n // The heading is the app's catalog word — read here, outside React.\n body.append(div('rosh-notif-title', currentShellStrings().toast.notification), div('notif-msg rosh-notif-msg', message));\n // The close button's hover colour is a `:hover` rule in ui.css. It was an\n // `onmouseenter` attribute — inline script, refused by a strict CSP.\n const close = document.createElement('button');\n close.className = 'rosh-notif-close';\n close.textContent = '×';\n el.append(badge, body, close);\n\n const dismiss = () => {\n el.style.opacity = '0';\n el.style.transform = 'translateX(30px) scale(0.95)';\n setTimeout(() => el.remove(), FADE_MS);\n };\n\n close.addEventListener('click', (e) => { e.stopPropagation(); dismiss(); });\n el.addEventListener('click', dismiss);\n\n container.appendChild(el);\n requestAnimationFrame(() => { el.style.opacity = '1'; el.style.transform = 'translateX(0) scale(1)'; });\n\n setTimeout(dismiss, opts?.duration ?? 10000);\n}\n\nconst toast = {\n success: (message: string, opts?: ToastOptions) => showToast('success', message, opts),\n error: (message: string, opts?: ToastOptions) => showToast('error', message, opts),\n /**\n * Something the user should read before continuing — a partial success, a\n * setting that will not apply until they do something else. Distinct from\n * `error`, which is \"this did not happen\".\n */\n warning: (message: string, opts?: ToastOptions) => showToast('warning', message, opts),\n info: (message: string, opts?: ToastOptions) => showToast('info', message, opts),\n // Persistent top-right notification card (the old toast.info presentation).\n notify: (message: string, opts?: { duration?: number }) => showNotification(message, opts),\n /**\n * One toast for one async operation: a spinning \"loading\" toast while `p`\n * is pending, swapped for a success or error toast when it settles. The\n * promise is returned untouched, so `await toast.promise(save(), …)` still\n * throws to the caller — this narrates the operation, it does not handle it.\n *\n * `error` is REQUIRED, and there is deliberately no fallback that prints\n * the exception: a raw `e.message` in a toast is how internals leak to the\n * screen (the same reasoning that keeps ErrorBoundary's stack behind\n * `showDetails`). The success/error messages may be functions of the\n * resolved value / the rejection, for the \"Saved 3 rows\" case.\n */\n promise: <T,>(\n p: Promise<T>,\n msgs: {\n loading: string;\n success: string | ((value: T) => string);\n error: string | ((error: unknown) => string);\n },\n opts?: ToastOptions,\n ): Promise<T> => {\n const pending = showToast('loading', msgs.loading, { ...opts, sticky: true });\n p.then(\n value => {\n pending.dismiss();\n showToast('success', typeof msgs.success === 'function' ? msgs.success(value) : msgs.success, opts);\n },\n error => {\n pending.dismiss();\n showToast('error', typeof msgs.error === 'function' ? msgs.error(error) : msgs.error, opts);\n },\n );\n return p;\n },\n /**\n * Set defaults for every subsequent toast. Call once at app startup; later\n * calls replace the whole object rather than merging, so a consumer sets its\n * policy in one place. Per-call options still take precedence.\n */\n configure: (next: ToastOptions) => { defaults = { ...next }; },\n};\n\nexport default toast;\n"]}
@@ -22,5 +22,5 @@ function claimSpreadsheetPreviewStage(stage) {
22
22
  }
23
23
 
24
24
  export { SPREADSHEET_PREVIEW_UPDATE_EVENT, claimSpreadsheetPreviewStage, peekSpreadsheetPreviewStage, setSpreadsheetPreview };
25
- //# sourceMappingURL=chunk-CT3HVZRZ.js.map
26
- //# sourceMappingURL=chunk-CT3HVZRZ.js.map
25
+ //# sourceMappingURL=chunk-5O42JXQE.js.map
26
+ //# sourceMappingURL=chunk-5O42JXQE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/apps/_spreadsheetStage.ts"],"names":[],"mappings":";AAiCO,IAAM,gCAAA,GAAmC;AAahD,IAAI,kBAAA,GAAqD,IAAA;AACzD,IAAI,oBAAA,GAAuB,CAAA;AAIpB,SAAS,sBAAsB,IAAA,EAAwD;AAC5F,EAAA,MAAM,QAAQ,EAAE,oBAAA;AAChB,EAAA,MAAM,KAAA,GAAiC,EAAE,KAAA,EAAO,IAAA,EAAK;AACrD,EAAA,kBAAA,GAAqB,KAAA;AACrB,EAAA,OAAO;AAAA,IACL,OAAO,IAAA,EAA8B;AAMnC,MAAA,IAAI,kBAAA,KAAuB,KAAA,EAAO,KAAA,CAAM,IAAA,GAAO,IAAA;AAC/C,MAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACnC,MAAA,MAAA,CAAO,aAAA,CAAc,IAAI,WAAA,CAAY,gCAAA,EAAkC,EAAE,MAAA,EAAQ,EAAE,KAAA,EAAO,IAAA,EAAM,IAAA,EAAK,EAAG,CAAC,CAAA;AAAA,IAC3G;AAAA,GACF;AACF;AAGO,SAAS,2BAAA,GAA8D;AAC5E,EAAA,OAAO,kBAAA;AACT;AAKO,SAAS,6BAA6B,KAAA,EAAsC;AACjF,EAAA,IAAI,kBAAA,KAAuB,OAAO,kBAAA,GAAqB,IAAA;AACzD","file":"chunk-5O42JXQE.js","sourcesContent":["/**\n * Spreadsheet staging — the tiny consumer-facing surface of the Spreadsheets\n * app. Lives apart from Spreadsheet.tsx so importing `setSpreadsheetPreview`\n * (from `efficient-shell/apps` or shell internals like openPreviewFile) never\n * drags the grid implementation into a host's startup bundle. The Spreadsheet\n * window component stays behind its React.lazy dynamic import and drains the\n * stage on mount via the @internal peek/claim helpers below.\n */\n\nexport interface SpreadsheetPreviewData {\n /** CSV text (comma- or tab-separated). */\n csv: string;\n /** Display name; the title strips a trailing `.csv`/`.tsv`/`.txt`. */\n filename: string;\n /** When provided, the toolbar shows an Email button that calls back with the\n * sheet serialized as CSV at click time (edits included) and a filename\n * derived from the current title. */\n onEmail?: (csv: string, filename: string) => void;\n}\n\n/** Handle returned by `setSpreadsheetPreview`. Holds the identity of the\n * staged payload so a later `.update()` only targets the window that picked\n * it up — opening a second Spreadsheet never clobbers the first. */\nexport interface SpreadsheetPreviewHandle {\n /** Replace the data shown in the window that consumed this staging. Safe to\n * call before that window exists — an update that lands while the payload\n * is still staged replaces the staged payload, so the window opens on the\n * resolved sheet instead of whatever it was staged with.\n * No-op only once the window that consumed the staging has been closed. */\n update(next: SpreadsheetPreviewData): void;\n}\n\n/** @internal Event carrying `.update()` payloads to the claiming window. */\nexport const SPREADSHEET_PREVIEW_UPDATE_EVENT = 'react-os-shell:spreadsheet-preview-update';\n\n/** @internal Staged payload awaiting the next Spreadsheet window mount.\n *\n * `data` is MUTABLE and deliberately so: `update()` rewrites it in place\n * while the stage is still unclaimed. Restaging a fresh object instead would\n * break the identity that `claimSpreadsheetPreviewStage` and the claimant's\n * own `consumedRef` are holding. */\nexport interface PendingSpreadsheetStage {\n token: number;\n data: SpreadsheetPreviewData;\n}\n\nlet pendingSpreadsheet: PendingSpreadsheetStage | null = null;\nlet nextSpreadsheetToken = 0;\n\n/** Stage CSV content for the next Spreadsheet window mount. The returned\n * handle's `update()` method swaps content in *that* specific window only. */\nexport function setSpreadsheetPreview(data: SpreadsheetPreviewData): SpreadsheetPreviewHandle {\n const token = ++nextSpreadsheetToken;\n const stage: PendingSpreadsheetStage = { token, data };\n pendingSpreadsheet = stage;\n return {\n update(next: SpreadsheetPreviewData) {\n // Same delivery gap the Preview stage has (see _previewStage.ts): the\n // window is a lazy chunk, so a consumer that resolves quickly can call\n // this before any window has mounted to hear the event, and the payload\n // would be dropped. Rewrite the stage as well while it is still ours —\n // `pendingSpreadsheet === stage` is exactly \"nobody has claimed it yet\".\n if (pendingSpreadsheet === stage) stage.data = next;\n if (typeof window === 'undefined') return;\n window.dispatchEvent(new CustomEvent(SPREADSHEET_PREVIEW_UPDATE_EVENT, { detail: { token, data: next } }));\n },\n };\n}\n\n/** @internal Render-phase peek — see Spreadsheet.tsx for the drain protocol. */\nexport function peekSpreadsheetPreviewStage(): PendingSpreadsheetStage | null {\n return pendingSpreadsheet;\n}\n\n/** @internal Commit-phase claim. The identity check keeps a payload staged\n * *after* the claimant's render-phase peek available for the window it\n * belongs to. */\nexport function claimSpreadsheetPreviewStage(stage: PendingSpreadsheetStage): void {\n if (pendingSpreadsheet === stage) pendingSpreadsheet = null;\n}\n"]}
@@ -496,7 +496,7 @@ function canonicalLocale(tag) {
496
496
  if (!reportedLocales.has(tag)) {
497
497
  reportedLocales.add(tag);
498
498
  console.error(
499
- `[react-os-shell] ShellStringsProvider: locale="${tag}" is not a BCP 47 language tag, so it is ignored and numbers and dates keep their default formatting. Pass a tag such as "de-DE" or "ja".`
499
+ `[efficient-shell] ShellStringsProvider: locale="${tag}" is not a BCP 47 language tag, so it is ignored and numbers and dates keep their default formatting. Pass a tag such as "de-DE" or "ja".`
500
500
  );
501
501
  }
502
502
  return void 0;
@@ -543,5 +543,5 @@ function splitAround(sentence) {
543
543
  }
544
544
 
545
545
  export { DEFAULT_SHELL_STRINGS, ShellStringsProvider, currentShellStrings, formatFixed, formatPercent, formatPlain, splitAround, useShellLocale, useShellStrings };
546
- //# sourceMappingURL=chunk-7IN7YZAL.js.map
547
- //# sourceMappingURL=chunk-7IN7YZAL.js.map
546
+ //# sourceMappingURL=chunk-72CQWN7O.js.map
547
+ //# sourceMappingURL=chunk-72CQWN7O.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/number.ts","../src/shell/strings.tsx"],"names":[],"mappings":"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","file":"chunk-72CQWN7O.js","sourcesContent":["/**\n * Numbers in the host's locale — or exactly as the kit printed them before it\n * had a locale to print them in.\n *\n * Every helper takes the BCP 47 tag `ShellStringsProvider` was given (read with\n * `useShellLocale`), and every one has two halves. With a tag, `Intl` writes the\n * number the way that locale does: `1.234,5` in German, a narrow space before\n * the percent sign in French. Without one, the helper returns what its call\n * sites used to compute inline — `String(v)`, `v.toFixed(d)`,\n * `v.toLocaleString()` — character for character.\n *\n * The second half is the contract, and the reason the fallbacks are spelled out\n * rather than left to an `Intl` default: `new Intl.NumberFormat()` with no tag\n * is the RUNTIME's locale, and a hard-coded `'en-US'` is somebody else's. An app\n * that never mounts a provider, or mounts one without a locale, must not see a\n * digit move — a table whose totals regrouped themselves on upgrade is a bug\n * report, not a feature.\n *\n * Kit-safe: no React, no DOM.\n */\n\n/** Building an `Intl.NumberFormat` is the expensive part of using one, and a\n * chart formats every tick of every axis on every render. One per locale and\n * option set, for the life of the page. */\nconst formats = new Map<string, Intl.NumberFormat>();\n\nfunction numberFormat(locale: string, options: Intl.NumberFormatOptions): Intl.NumberFormat {\n const key = `${locale}|${JSON.stringify(options)}`;\n let format = formats.get(key);\n if (!format) {\n format = new Intl.NumberFormat(locale, options);\n formats.set(key, format);\n }\n return format;\n}\n\n/**\n * A number as written — `String(v)` without a locale. With one, every digit the\n * value has is kept (up to `Intl`'s ceiling of 20), because the call sites this\n * replaces never rounded: a chart whose caller passed 0.125 printed `0.125`, and\n * `Intl`'s default of three fraction digits would quietly print `0.125` but\n * `0.1235` for 0.12345.\n */\nexport function formatPlain(value: number, locale?: string): string {\n return locale ? numberFormat(locale, { maximumFractionDigits: 20 }).format(value) : String(value);\n}\n\n/** A count with thousands separators — `v.toLocaleString()` without a locale,\n * which is the runtime's own grouping, exactly as before. */\nexport function formatGrouped(value: number, locale?: string): string {\n return locale ? numberFormat(locale, {}).format(value) : value.toLocaleString();\n}\n\n/** Exactly `digits` decimals — `v.toFixed(digits)` without a locale. */\nexport function formatFixed(value: number, digits: number, locale?: string): string {\n return locale\n ? numberFormat(locale, { minimumFractionDigits: digits, maximumFractionDigits: digits }).format(value)\n : value.toFixed(digits);\n}\n\n/**\n * A PERCENTAGE — `37.5`, not the fraction `0.375` — with `digits` decimals:\n * `${p.toFixed(digits)}%` without a locale, the locale's own percent with one\n * (`37,5 %`, `%37,5`).\n *\n * It takes the percentage rather than the fraction because that is what every\n * call site already had in hand: they computed `(share * 100).toFixed(1)`, and\n * passing that same product through keeps the no-locale output identical down to\n * the last floating-point digit.\n */\nexport function formatPercent(percent: number, digits: number, locale?: string): string {\n return locale\n ? numberFormat(locale, {\n style: 'percent', minimumFractionDigits: digits, maximumFractionDigits: digits,\n }).format(percent / 100)\n : `${percent.toFixed(digits)}%`;\n}\n","/**\n * ShellStrings — the shell's user-facing strings, in one typed catalog.\n *\n * Every string here was hardcoded English at its call site, which made the\n * shell untranslatable no matter what the consuming portal did. The catalog\n * is the fix's whole shape: components read strings through `useShellStrings`\n * (which works with NO provider — the English defaults are the context\n * default), and a consumer that wants another language mounts\n * `ShellStringsProvider` once with a partial override. Overrides merge per\n * SECTION, so translating the window controls does not oblige anyone to\n * translate the help viewer.\n *\n * This is deliberately not an i18n library: no message IDs, no interpolation\n * DSL, no plural rules. The shell's strings are labels and short sentences;\n * a typed object keeps them discoverable and lets TypeScript flag a\n * translation that goes stale when a string is added.\n *\n * ── Sentences that carry a value are functions ──\n * \"3 of 40 records\", \"Remove invoice.pdf\", \"Choose a year, currently 2026\".\n * A string with a hole in it would need a template syntax, and a template\n * syntax would need plural rules the moment a count went into the hole —\n * which is the i18n library this file refuses to be. So those entries are\n * plain functions, and the host writes them with whatever it already has:\n * `Intl.PluralRules`, its own message catalog, a ternary.\n *\n * Two rules keep the functions predictable:\n * - A COUNT arrives as a `number`, unformatted, because the words depend on\n * it (\"1 file\", \"2 files\", \"5 файлов\") and a plural rule needs the number.\n * The host formats it; the English defaults do, in the provider's `locale`.\n * - A VALUE the kit already formatted — a date, a caller's `formatValue`\n * output, a file size — arrives as the `string` that would be printed.\n *\n * A few older entries are halves the caller concatenates (`select.remove` +\n * a label, `pageTabs.discardMany` after a count). They stay, so no existing\n * catalog breaks, and each has an optional function beside it that wins when\n * supplied — word order differs between languages, and a concatenation cannot.\n *\n * ── Locale ──\n * `ShellStringsProvider` also takes a `locale` (a BCP 47 tag). It is not a\n * string section, it is how numbers and dates are WRITTEN: month and weekday\n * names in the pickers, `formatDate`, the digits in a list footer or a chart\n * axis. With no locale the kit writes exactly what it always wrote — the same\n * English month names, `toLocaleString()` with no argument, `String(v)` — so\n * mounting the provider for its strings alone changes no number on screen.\n * `useShellLocale` reads it; `src/utils/number.ts` and `calendarNames` in\n * `src/utils/date.ts` are the two halves that honour it.\n *\n * Prop-level text (a `emptyText` prop, a `placeholder`) always wins over the\n * catalog — the catalog replaces hardcoded DEFAULTS, never a caller's words.\n *\n * Kit-safe: no window-manager import, so `efficient-shell/ui` consumers get it\n * too.\n */\nimport { createContext, useContext, useEffect, useMemo, type ReactNode } from 'react';\nimport { formatFixed, formatGrouped, formatPercent, formatPlain } from '../utils/number';\n\nexport interface ShellStrings {\n /** Window chrome: control tooltips and the title bar's accessible name. */\n window: {\n minimize: string;\n /** Bring a hand-minimized window back — the tab's own control. */\n restore: string;\n maximize: string;\n windowed: string;\n pinOnTop: string;\n unpin: string;\n close: string;\n /** Suffix of the title bar's aria-label: `\"{title} — {windowSuffix}\"`. */\n windowSuffix: string;\n prev: string;\n next: string;\n snapLayouts: string;\n snapLeft: string;\n snapRight: string;\n snapTopLeft: string;\n snapTopRight: string;\n snapBottomLeft: string;\n snapBottomRight: string;\n };\n /** Taskbar and exposé. */\n taskbar: {\n closeWindow: string;\n offscreenHint: string;\n offscreenDot: string;\n expose: string;\n addToDesktop: string;\n removeFromDesktop: string;\n /** Group menu — a taskbar tab standing for more than one window. The\n * count is appended by the caller, e.g. \"Close all (3)\". */\n minimizeAllWindows: string;\n restoreAllWindows: string;\n closeAllWindows: string;\n };\n /** The logout cover. */\n logout: {\n goodbye: string;\n seeYou: string;\n };\n /** About + What's New dialogs. */\n about: {\n aboutPrefix: string;\n thisApp: string;\n openSourceLicenses: string;\n whatsNew: string;\n noChangelog: string;\n };\n /** Data-display defaults (DataTable, lists). */\n table: {\n empty: string;\n loading: string;\n selectAll: string;\n selectRow: string;\n };\n /** Picker defaults (SearchableSelect, TagInput). */\n select: {\n none: string;\n noMatches: string;\n allSelected: string;\n clear: string;\n /** aria-label of a TagInput chip's remove button: `\"{remove} {label}\"`. */\n remove: string;\n /** The whole chip label, when the word order is not \"{remove} {label}\".\n * Wins over `remove` when supplied. */\n removeItem?: (label: string) => string;\n };\n /** Notification bell + popup. */\n notifications: {\n title: string;\n markAllRead: string;\n dnd: string;\n dndOn: string;\n caughtUp: string;\n empty: string;\n viewAll: string;\n cardLabel: string;\n dismiss: string;\n };\n /** Form-level messages. */\n form: {\n errorSummaryTitle: string;\n };\n /** HelpCenter chrome. */\n help: {\n title: string;\n searchPlaceholder: string;\n empty: string;\n noResults: string;\n loading: string;\n pickArticle: string;\n noBody: string;\n draft: string;\n newArticle: string;\n edit: string;\n };\n /** The app-update banner (a deploy happened under a long-lived tab). */\n update: {\n available: string;\n refreshNow: string;\n };\n /** The page-tab strip (`efficient-shell/page-tabs`). */\n pageTabs: {\n /** The strip's accessible name. */\n label: string;\n /** A tab's close button, and the menu item: `\"{close} {title}\"` for the button. */\n close: string;\n /** The close button's whole label, when the word order is not\n * \"{close} {title}\". Wins over `close` for the button when supplied. */\n closeTab?: (title: string) => string;\n closeOthers: string;\n closeRight: string;\n closeAll: string;\n /** Marks a tab with unsaved changes (the dot's accessible text). */\n unsaved: string;\n /** Asked before a tab with unsaved changes closes. */\n discardTitle: string;\n discardOne: string;\n /** Several at once — the count is prefixed by the caller: \"3 pages have…\". */\n discardMany: string;\n /** The whole several-at-once sentence, for a language whose noun follows\n * the count's plural form. Wins over `discardMany` when supplied. */\n discardCount?: (count: number) => string;\n discardConfirm: string;\n keepEditing: string;\n };\n /** `Dialog` and `Drawer`'s close control, and the dialogs behind `confirm`,\n * `confirmDestructive` and `prompt` (each option a caller passes wins). */\n dialog: {\n close: string;\n cancel: string;\n ok: string;\n /** `confirm`'s heading when the caller gives no `title`. */\n confirmTitle: string;\n /** `confirmDestructive`'s heading, cancel and confirm defaults. */\n destructiveTitle: string;\n destructiveCancel: string;\n destructiveConfirm: string;\n /** The line over the type-to-confirm box; the word is drawn in a `<kbd>`\n * wherever the sentence puts it. */\n typeToConfirm: (word: string) => string;\n /** `prompt`'s heading when the caller gives no `title`. */\n promptTitle: string;\n };\n /** The month grid (`Calendar`, and the pickers that open it). Month and\n * weekday NAMES are not here — they come from `locale`. */\n calendar: {\n previousMonth: string;\n nextMonth: string;\n previousYear: string;\n nextYear: string;\n previousYears: string;\n nextYears: string;\n /** The month and year panels' accessible names. */\n monthPanel: string;\n yearPanel: string;\n /** The heading's month button. */\n chooseMonth: (month: string) => string;\n /** The heading's year button. */\n chooseYear: (year: number) => string;\n };\n /** `DatePicker`'s trigger and popover. */\n datePicker: {\n placeholder: string;\n /** The popover's accessible name when the field has no `aria-label`. */\n dialog: string;\n clear: string;\n today: string;\n };\n /** `DateRangePicker`. */\n dateRange: {\n placeholder: string;\n /** The trigger's × button. */\n clearRange: string;\n /** The popover's and the grid's accessible name. */\n dialog: string;\n from: string;\n to: string;\n /** The From/To boxes before a day is chosen. */\n start: string;\n end: string;\n /** The trigger with only one end of the range set. */\n fromOnly: (date: string) => string;\n toOnly: (date: string) => string;\n last2Weeks: string;\n lastMonth: string;\n last3Months: string;\n last6Months: string;\n last12Months: string;\n custom: string;\n clear: string;\n cancel: string;\n apply: string;\n };\n /** `Pagination` (and `DataTable`'s pager). */\n pagination: {\n label: string;\n first: string;\n previous: string;\n next: string;\n last: string;\n };\n /** `ListFooter` and `ListLoadError`. `label` is the caller's own noun\n * (\"records\"); the counts are numbers, for the plural. */\n list: {\n /** Before the em dash: \"3 selected — 40 records\". */\n selected: (count: number) => string;\n allLoaded: (total: number, label: string) => string;\n count: (total: number, label: string) => string;\n loadedOf: (loaded: number, total: number, label: string) => string;\n /** After a middle dot: \"40 of 900 records · Loading more...\". */\n loadingMore: string;\n loadError: string;\n loadErrorMessage: string;\n retry: string;\n };\n /** `Kanban`'s defaults (its own props win). */\n kanban: {\n loading: string;\n empty: string;\n dropHere: string;\n addItem: string;\n };\n /** File intake: `FilePicker`, `ComposerAttachments`, and the rejection\n * messages every upload control shares. */\n files: {\n attach: string;\n drop: string;\n remove: (name: string) => string;\n chooseMany: string;\n chooseOne: string;\n /** After the choose link, in the same line. */\n dragMany: string;\n dragOne: string;\n /** `hint` is the caller's `acceptHint` when it is a string, else ''. */\n notAccepted: (name: string, hint: string) => string;\n /** `size` and `limit` arrive written out — \"6.2 MB\". */\n tooLarge: (name: string, size: string, limit: string) => string;\n tooMany: (name: string, max: number) => string;\n bytes: (value: number) => string;\n kilobytes: (value: number) => string;\n megabytes: (value: number) => string;\n };\n /** `MediaUploadField` and `MediaUploadGrid`. */\n media: {\n uploadImage: string;\n uploadVideo: string;\n uploadFile: string;\n /** The drop zone's accessible name when its prompt is not a string. */\n upload: string;\n cta: string;\n replace: string;\n remove: string;\n uploading: string;\n cover: string;\n add: string;\n addMedia: string;\n empty: string;\n removeItem: (name: string) => string;\n /** A reorderable thumbnail's accessible name. */\n reorder: (name: string, position: number, total: number) => string;\n };\n /** `BrandAssetEditor`. `noun` is the last word of `assetName`, lower-cased\n * (\"Portal logo\" → \"logo\"); a translation that cannot use it has\n * `assetName` itself. */\n brandAsset: {\n save: (noun: string, assetName: string) => string;\n remove: (noun: string, assetName: string) => string;\n discard: string;\n saveFailed: (noun: string, assetName: string) => string;\n removeFailed: (noun: string, assetName: string) => string;\n region: (assetName: string, subjectName: string) => string;\n usedFor: (subjectName: string) => string;\n previews: (assetName: string) => string;\n preview: string;\n alt: (subjectName: string, assetName: string) => string;\n };\n /** `Snippet`'s copy button, and the clipboard's toasts. */\n copy: {\n copy: string;\n copyLabel: (label: string) => string;\n /** Snippet's spoken confirmation. */\n copied: string;\n /** `copyToClipboard`'s success toast; `label` names what was copied. */\n copiedLabel: (label: string) => string;\n failed: string;\n };\n /** `NumericKeypad`. */\n keypad: {\n backspace: string;\n enter: string;\n };\n /** `Banner`. */\n banner: {\n dismiss: string;\n };\n /** A closable `ColoredBadge`'s × (its `closeLabel` wins). */\n badge: {\n /** When the badge's content is not plain text. */\n remove: string;\n removeItem: (label: string) => string;\n };\n /** `Breadcrumbs`. */\n breadcrumbs: {\n label: string;\n /** The ellipsis standing for the crumbs `maxItems` folded away. */\n hidden: string;\n };\n /** `EmptyState`'s line when the caller gives neither a title nor a message. */\n emptyState: {\n message: string;\n };\n /** `ErrorPage`, `ErrorBoundary` and `Result`'s status defaults. */\n errors: {\n notFound: string;\n notFoundBody: string;\n forbidden: string;\n forbiddenBody: string;\n /** `Result status=\"403\"`'s title — gentler than `ErrorPage`'s. */\n noAccess: string;\n serverError: string;\n serverErrorBody: string;\n retry: string;\n details: string;\n };\n /** `GlobalSearch`. */\n search: {\n placeholder: string;\n /** The key cap beside the input. */\n escBadge: string;\n searching: string;\n noResults: string;\n minChars: (min: number) => string;\n navigate: string;\n open: string;\n close: string;\n enterKey: string;\n escKey: string;\n };\n /** `EditableGrid`. */\n grid: {\n selectAll: string;\n insertRowAbove: string;\n insertRowBelow: string;\n deleteRow: (row: number) => string;\n insertColumnLeft: string;\n insertColumnRight: string;\n deleteColumn: (column: string) => string;\n resize: string;\n fill: string;\n };\n /** `SidebarLayout`'s resize handle. */\n sidebar: {\n resize: string;\n };\n /** `MarkdownLite`. */\n markdown: {\n /** Before an image placeholder's caption, with an em dash between. */\n screenshot: string;\n };\n /** The word a severity marker is spoken and tooltipped with. */\n severity: {\n success: string;\n warning: string;\n danger: string;\n /** A token that is not one of the three, as received. */\n unrecognised: (token: string) => string;\n };\n /** `MetricBar` and `BudgetBar`. */\n meter: {\n noData: string;\n warningAt: (bound: number) => string;\n criticalAt: (bound: number) => string;\n noReading: string;\n noBudget: string;\n /** The meter's spoken value: \"84% of budget\". */\n ofBudget: (value: string) => string;\n /** The deadline marker's tooltip. */\n budget: string;\n hoursMinutes: (hours: number, minutes: number) => string;\n minutesSeconds: (minutes: number, seconds: number) => string;\n seconds: (seconds: number) => string;\n };\n /** The chart family. Series, axis and category names are the caller's. */\n charts: {\n showTable: string;\n loading: string;\n noData: string;\n windowStart: string;\n windowEnd: string;\n window: (from: string, to: string, count: number) => string;\n overIntervals: (series: string[], count: number) => string;\n acrossCategories: (series: string[], count: number) => string;\n acrossMeasures: (series: string[], count: number) => string;\n /** The pie's accessible name; `total` is written by the caller's `formatValue`. */\n breakdown: (total: string, segments: number) => string;\n funnel: (stages: number, first: string, last: string) => string;\n radialTrack: (count: number) => string;\n radialCycle: (count: number) => string;\n /** Column heads of the screen-reader tables some charts carry. */\n tableFrom: string;\n tableTo: string;\n tableItem: string;\n tableLevel: string;\n tableSeries: string;\n inBucket: (total: string) => string;\n inCategory: (total: string) => string;\n value: string;\n share: string;\n count: string;\n flow: string;\n totalFlow: string;\n throughput: string;\n open: string;\n high: string;\n low: string;\n close: string;\n maximum: string;\n q3: string;\n median: string;\n q1: string;\n minimum: string;\n distribution: string;\n fiveNumber: (label: string, count: number) => string;\n outliers: (count: number) => string;\n price: string;\n ohlc: (label: string, count: number) => string;\n closedAbove: string;\n closedBelow: string;\n noFlows: string;\n chord: (count: number) => string;\n noStages: string;\n ofFirstStage: string;\n droppedHere: string;\n intensity: string;\n noActivity: string;\n heatmap: (label: string, rows: number, columns: number) => string;\n /** A histogram's y-axis title. */\n countAxis: string;\n histogram: (label: string, bins: number, observations: number) => string;\n observations: string;\n /** `Meter` with no value to judge. */\n notEnough: string;\n objectiveMet: (objective: string) => string;\n objectiveMissed: (objective: string) => string;\n nothingToPlot: string;\n nothingToCompare: string;\n /** The pie slice the small segments are folded into. */\n other: string;\n nothingToBreakDown: string;\n range: string;\n rangeLabel: (label: string, count: number) => string;\n nothingToRank: string;\n /** Spoken after the emphasised row of `RankedBars`. */\n emphasised: string;\n sankey: (nodes: number, links: number) => string;\n noObservations: string;\n xAxis: string;\n yAxis: string;\n size: string;\n scatter: (series: string[], yLabel: string, xLabel: string) => string;\n outsideRange: (count: number) => string;\n waterfall: (steps: number, from: string, to: string) => string;\n balance: string;\n increase: string;\n decrease: string;\n runningTotal: string;\n sunburst: (total: string, depth: number) => string;\n treemap: (count: number) => string;\n /** `StatTile`'s delta direction, spoken after the arrow glyph. */\n trendUp: string;\n trendDown: string;\n trendFlat: string;\n };\n /** `TimelineTrack` and `MilestoneTimeline`. */\n timeline: {\n /** A cut in the axis: \"412 days\". */\n days: (count: number) => string;\n daysToToday: (count: number) => string;\n notReached: string;\n /** Before the first pending entry, with a middle dot after it. */\n next: string;\n more: (count: number) => string;\n today: string;\n todayTitle: (date: string) => string;\n open: (name: string) => string;\n openButton: string;\n scrub: string;\n alsoToCome: (names: string[]) => string;\n start: (date: string) => string;\n /** A folded run of marks: its count, then each member's own name. */\n events: (count: number, names: string[]) => string;\n started: (date: string) => string;\n duration: (days: number) => string;\n reached: (dated: number, total: number) => string;\n milestones: (title: string) => string;\n };\n /** `ProductionTimeline`. */\n production: {\n heading: string;\n /** The synthetic report standing for the production start. */\n start: string;\n /** The synthetic report between two real ones. */\n estimated: string;\n estimatedCompletion: string;\n estDone: string;\n play: string;\n pause: string;\n playTitle: string;\n backTo: (report: string) => string;\n /** The report is drawn bold wherever the sentence puts it. */\n showing: (report: string) => string;\n overall: (percent: number) => string;\n inStock: (pieces: number) => string;\n noReport: string;\n leadTime: (days: number) => string;\n report: string;\n shipment: string;\n inspection: string;\n invoice: string;\n scrub: string;\n label: (from: string, to: string) => string;\n };\n /** `ContainerFillChart`. Volumes are cubic metres. */\n containers: {\n items: (count: number) => string;\n pieces: (count: number) => string;\n split: (instructed: number, loaded: number) => string;\n added: (count: number, pieces: number) => string;\n fill: (volume: number, capacity: number) => string;\n total: string;\n instructed: (volume: number) => string;\n loaded: (volume: number) => string;\n volume: (volume: number) => string;\n noVolume: string;\n };\n /** `toast.notify`'s card. */\n toast: {\n notification: string;\n };\n}\n\n/**\n * The English catalog, with its numbers written for `locale`.\n *\n * A function, not a literal, because the defaults that carry a count have to\n * write it the way the provider's locale does — `1.234 records` is still the\n * English default, in a German-formatted app — and the locale is not known\n * until a provider says so. With no locale every number is written exactly as\n * the component wrote it inline before (`toLocaleString()` where it grouped,\n * a bare interpolation where it did not), which is what makes\n * `DEFAULT_SHELL_STRINGS` byte-identical to the strings it replaced.\n */\nfunction englishStrings(locale?: string): ShellStrings {\n const plain = (v: number) => formatPlain(v, locale);\n const grouped = (v: number) => formatGrouped(v, locale);\n const fixed = (v: number, digits: number) => formatFixed(v, digits, locale);\n const percent = (p: number, digits: number) => formatPercent(p, digits, locale);\n return {\n window: {\n minimize: 'Minimize',\n restore: 'Restore',\n maximize: 'Maximize',\n windowed: 'Windowed',\n pinOnTop: 'Pin on top',\n unpin: 'Unpin from top',\n close: 'Close',\n windowSuffix: 'window',\n prev: 'Prev',\n next: 'Next',\n snapLayouts: 'Snap layouts',\n snapLeft: 'Snap left half',\n snapRight: 'Snap right half',\n snapTopLeft: 'Snap top-left quarter',\n snapTopRight: 'Snap top-right quarter',\n snapBottomLeft: 'Snap bottom-left quarter',\n snapBottomRight: 'Snap bottom-right quarter',\n },\n taskbar: {\n closeWindow: 'Close window',\n offscreenHint: 'This window is off screen — click to bring it back',\n offscreenDot: 'Off screen — click to bring this window back',\n expose: 'Exposé — show all open windows as thumbnails',\n addToDesktop: 'Add to desktop',\n removeFromDesktop: 'Remove from desktop',\n minimizeAllWindows: 'Minimize all',\n restoreAllWindows: 'Restore all',\n closeAllWindows: 'Close all',\n },\n logout: {\n goodbye: 'Goodbye',\n seeYou: 'See you next time',\n },\n about: {\n aboutPrefix: 'About',\n thisApp: 'this app',\n openSourceLicenses: 'Open Source Licenses',\n whatsNew: \"What's New\",\n noChangelog: 'No changelog available.',\n },\n table: {\n empty: 'Nothing to show',\n loading: 'Loading',\n selectAll: 'Select all rows',\n selectRow: 'Select row',\n },\n select: {\n none: '— None —',\n noMatches: 'No matches',\n allSelected: 'All options selected',\n clear: 'Clear selection',\n remove: 'Remove',\n },\n notifications: {\n title: 'Notifications',\n markAllRead: 'Mark all read',\n dnd: 'Do not disturb',\n dndOn: 'Do not disturb is on',\n caughtUp: 'All caught up',\n empty: 'No notifications yet',\n viewAll: 'View all notifications',\n cardLabel: 'Notification',\n dismiss: 'Dismiss notification',\n },\n form: {\n errorSummaryTitle: 'There is a problem',\n },\n help: {\n title: 'Help',\n searchPlaceholder: 'Search help…',\n empty: 'No help articles yet.',\n noResults: 'No articles match your search.',\n loading: 'Loading…',\n pickArticle: 'Pick a help article from the left.',\n noBody: 'This article has no body yet.',\n draft: 'Draft',\n newArticle: '+ New',\n edit: 'Edit',\n },\n update: {\n available: 'A new version is available.',\n refreshNow: 'Refresh now',\n },\n pageTabs: {\n label: 'Open pages',\n close: 'Close',\n closeOthers: 'Close other tabs',\n closeRight: 'Close tabs to the right',\n closeAll: 'Close all tabs',\n unsaved: 'Unsaved changes',\n discardTitle: 'Discard unsaved changes?',\n discardOne: 'This page has changes that have not been saved. Close it anyway?',\n discardMany: 'pages have changes that have not been saved. Close them anyway?',\n discardConfirm: 'Discard and close',\n keepEditing: 'Keep editing',\n },\n dialog: {\n close: 'Close',\n cancel: 'Cancel',\n ok: 'OK',\n confirmTitle: 'Confirm',\n destructiveTitle: 'Confirm Action',\n destructiveCancel: 'Dismiss',\n destructiveConfirm: 'Delete',\n typeToConfirm: word => `Type ${word} to confirm:`,\n promptTitle: 'Enter a value',\n },\n calendar: {\n previousMonth: 'Previous month',\n nextMonth: 'Next month',\n previousYear: 'Previous year',\n nextYear: 'Next year',\n previousYears: 'Previous years',\n nextYears: 'Next years',\n monthPanel: 'Choose a month',\n yearPanel: 'Choose a year',\n chooseMonth: month => `Choose a month, currently ${month}`,\n // A year is never grouped: \"2,026\" is a quantity, not a year.\n chooseYear: year => `Choose a year, currently ${year}`,\n },\n datePicker: {\n placeholder: 'Select a date',\n dialog: 'Choose a date',\n clear: 'Clear',\n today: 'Today',\n },\n dateRange: {\n placeholder: 'Date Range',\n clearRange: 'Clear date range',\n dialog: 'Date range',\n from: 'From',\n to: 'To',\n start: 'Start',\n end: 'End',\n fromOnly: date => `From ${date}`,\n toOnly: date => `To ${date}`,\n last2Weeks: 'Last 2 Weeks',\n lastMonth: 'Last Month',\n last3Months: 'Last 3 Months',\n last6Months: 'Last 6 Months',\n last12Months: 'Last 12 Months',\n custom: 'Custom',\n clear: 'Clear',\n cancel: 'Cancel',\n apply: 'Apply',\n },\n pagination: {\n label: 'Pagination',\n first: 'First page',\n previous: 'Previous page',\n next: 'Next page',\n last: 'Last page',\n },\n list: {\n selected: count => `${plain(count)} selected`,\n allLoaded: (total, label) => `All ${grouped(total)} ${label} loaded`,\n count: (total, label) => `${grouped(total)} ${label}`,\n loadedOf: (loaded, total, label) => `${grouped(loaded)} of ${grouped(total)} ${label}`,\n loadingMore: 'Loading more...',\n loadError: \"Couldn't load this list\",\n loadErrorMessage: 'Something went wrong fetching these records. Check your connection and try again.',\n retry: 'Try again',\n },\n kanban: {\n loading: 'Loading…',\n empty: 'No items.',\n dropHere: 'Drop here',\n addItem: 'Add item',\n },\n files: {\n attach: 'Attach files',\n drop: 'Drop files to attach',\n remove: name => `Remove ${name}`,\n chooseMany: 'Choose files',\n chooseOne: 'Choose a file',\n dragMany: 'or drag them here',\n dragOne: 'or drag it here',\n notAccepted: (name, hint) => `${name} is not an accepted file type${hint ? ` (${hint})` : ''}`,\n tooLarge: (name, size, limit) => `${name} is ${size} — the limit is ${limit}`,\n tooMany: (name, max) => `${name} was not added — ${plain(max)} ${max === 1 ? 'file' : 'files'} is the limit`,\n bytes: value => `${plain(value)} B`,\n kilobytes: value => `${plain(value)} KB`,\n megabytes: value => `${fixed(value, 1)} MB`,\n },\n media: {\n uploadImage: 'Upload an image',\n uploadVideo: 'Upload a video',\n uploadFile: 'Upload a file',\n upload: 'Upload media',\n cta: 'Choose from library or upload',\n replace: 'Replace',\n remove: 'Remove',\n uploading: 'Uploading…',\n cover: 'Cover',\n add: 'Add',\n addMedia: 'Add media',\n empty: 'No media.',\n removeItem: name => `Remove ${name}`,\n reorder: (name, position, total) =>\n `${name}, item ${plain(position)} of ${plain(total)}. Use arrow keys to reorder.`,\n },\n brandAsset: {\n save: noun => `Save ${noun}`,\n remove: noun => `Remove ${noun}`,\n discard: 'Discard change',\n saveFailed: noun => `Could not save ${noun}.`,\n removeFailed: noun => `Could not remove ${noun}.`,\n region: (assetName, subjectName) => `${assetName} for ${subjectName}`,\n usedFor: subjectName => `Used for ${subjectName}.`,\n previews: assetName => `${assetName} previews`,\n preview: 'Preview',\n alt: (subjectName, assetName) => `${subjectName} ${assetName}`,\n },\n copy: {\n copy: 'Copy',\n copyLabel: label => `Copy ${label}`,\n copied: 'Copied',\n copiedLabel: label => `${label} copied`,\n failed: 'Could not copy to the clipboard',\n },\n keypad: {\n backspace: 'Backspace',\n enter: 'Enter',\n },\n banner: {\n dismiss: 'Dismiss',\n },\n badge: {\n remove: 'Remove',\n removeItem: label => `Remove ${label}`,\n },\n breadcrumbs: {\n label: 'Breadcrumb',\n hidden: 'Hidden crumbs',\n },\n emptyState: {\n message: 'Nothing here yet.',\n },\n errors: {\n notFound: 'Page not found',\n notFoundBody: \"The page you're looking for doesn't exist or was moved.\",\n forbidden: 'Access denied',\n forbiddenBody: \"You don't have permission to view this page.\",\n noAccess: \"You don't have access to this\",\n serverError: 'Something went wrong',\n serverErrorBody: 'An unexpected error occurred. Please try again.',\n retry: 'Try again',\n details: 'Error details',\n },\n search: {\n placeholder: 'Search...',\n escBadge: 'ESC',\n searching: 'Searching...',\n noResults: 'No results found.',\n minChars: min => `Type at least ${plain(min)} characters to search...`,\n navigate: 'navigate',\n open: 'open',\n close: 'close',\n enterKey: 'Enter',\n escKey: 'Esc',\n },\n grid: {\n selectAll: 'Select all',\n insertRowAbove: 'Insert row above',\n insertRowBelow: 'Insert row below',\n // A row NUMBER, as the grid's own row header prints it — never grouped.\n deleteRow: row => `Delete row ${row}`,\n insertColumnLeft: 'Insert column left',\n insertColumnRight: 'Insert column right',\n deleteColumn: column => `Delete column ${column}`,\n resize: 'Drag to resize · double-click to auto-fit',\n fill: 'Drag to fill',\n },\n sidebar: {\n resize: 'Drag to resize · double-click to reset',\n },\n markdown: {\n screenshot: 'Screenshot',\n },\n severity: {\n success: 'ok',\n warning: 'warning',\n danger: 'critical',\n unrecognised: token => `unrecognised severity ${token}`,\n },\n meter: {\n noData: 'no data',\n warningAt: bound => `warning ≥ ${plain(bound)}`,\n criticalAt: bound => `critical ≥ ${plain(bound)}`,\n noReading: 'no reading',\n noBudget: 'no budget',\n ofBudget: value => `${value} of budget`,\n budget: 'budget',\n hoursMinutes: (hours, minutes) => `${plain(hours)}h ${plain(minutes)}m`,\n minutesSeconds: (minutes, seconds) => `${plain(minutes)}m ${plain(seconds)}s`,\n seconds: seconds => `${plain(seconds)}s`,\n },\n charts: {\n showTable: 'Show the data as a table',\n loading: 'Loading chart data',\n noData: 'No data in this window.',\n windowStart: 'Window start',\n windowEnd: 'Window end',\n window: (from, to, count) => `Time window — showing ${from} to ${to} of ${plain(count)} intervals`,\n overIntervals: (series, count) => `${series.join(', ')} over ${plain(count)} intervals`,\n acrossCategories: (series, count) => `${series.join(', ')} across ${plain(count)} categories`,\n acrossMeasures: (series, count) => `${series.join(', ')} across ${plain(count)} measures`,\n breakdown: (total, segments) => `Breakdown of ${total} across ${plain(segments)} segments`,\n funnel: (stages, first, last) => `Funnel of ${plain(stages)} stages, ${first} down to ${last}`,\n radialTrack: count => `${plain(count)} categories, as concentric proportions`,\n radialCycle: count => `${plain(count)} categories, around a cycle`,\n tableFrom: 'From',\n tableTo: 'To',\n tableItem: 'Item',\n tableLevel: 'Level',\n tableSeries: 'Series',\n inBucket: total => `${total} in this bucket`,\n inCategory: total => `${total} in this category`,\n value: 'Value',\n share: 'Share',\n count: 'Count',\n flow: 'Flow',\n totalFlow: 'Total flow',\n throughput: 'Throughput',\n open: 'Open',\n high: 'High',\n low: 'Low',\n close: 'Close',\n maximum: 'Maximum',\n q3: 'Q3',\n median: 'Median',\n q1: 'Q1',\n minimum: 'Minimum',\n distribution: 'Distribution',\n fiveNumber: (label, count) => `${label}: five-number summary for ${plain(count)} categories`,\n outliers: count => `${plain(count)} outlier${count > 1 ? 's' : ''} beyond the whiskers`,\n price: 'Price',\n ohlc: (label, count) => `${label}: open, high, low and close across ${plain(count)} periods`,\n closedAbove: 'Closed above its open',\n closedBelow: 'Closed below its open',\n noFlows: 'No flows to chart.',\n chord: count => `Flows between ${plain(count)} participants`,\n noStages: 'No stages to chart.',\n ofFirstStage: 'Of first stage',\n droppedHere: 'Dropped here',\n intensity: 'Intensity',\n noActivity: 'No activity in this window.',\n heatmap: (label, rows, columns) => `${label} across ${plain(rows)} rows and ${plain(columns)} columns`,\n countAxis: 'count',\n histogram: (label, bins, observations) =>\n `${label}: ${plain(bins)} bins over ${plain(observations)} observations`,\n observations: 'Observations',\n notEnough: 'Not enough eligible requests to judge.',\n objectiveMet: objective => `objective ${objective} met`,\n objectiveMissed: objective => `objective ${objective} missed`,\n nothingToPlot: 'Nothing to plot.',\n nothingToCompare: 'Nothing to compare.',\n other: 'Other',\n nothingToBreakDown: 'Nothing to break down.',\n range: 'Range',\n rangeLabel: (label, count) => `${label}: low and high across ${plain(count)} categories`,\n nothingToRank: 'Nothing to rank in this window.',\n emphasised: '(emphasised)',\n sankey: (nodes, links) => `Flow between ${plain(nodes)} nodes over ${plain(links)} links`,\n noObservations: 'No observations in this window.',\n xAxis: 'x',\n yAxis: 'y',\n size: 'Size',\n scatter: (series, yLabel, xLabel) => `${series.join(', ')}: ${yLabel} against ${xLabel}`,\n outsideRange: count => `${plain(count)} ${count === 1 ? 'point' : 'points'} outside the shown range`,\n waterfall: (steps, from, to) => `Waterfall of ${plain(steps)} steps from ${from} to ${to}`,\n balance: 'Balance',\n increase: 'Increase',\n decrease: 'Decrease',\n runningTotal: 'Running total',\n sunburst: (total, depth) => `Hierarchy of ${total} across ${plain(depth)} levels`,\n treemap: count => `Treemap of ${plain(count)} items`,\n trendUp: 'up',\n trendDown: 'down',\n trendFlat: 'flat',\n },\n timeline: {\n days: count => `${grouped(count)} days`,\n daysToToday: count => `${grouped(count)} days to today`,\n notReached: 'Not yet reached',\n next: 'Next',\n more: count => `+${plain(count)} more`,\n today: 'Today',\n todayTitle: date => `Today — ${date}`,\n open: name => `Open ${name}`,\n openButton: 'Open',\n scrub: 'Scrub the timeline',\n alsoToCome: names => `Also to come: ${names.join(', ')}`,\n start: date => `Start · ${date}`,\n events: (count, names) => `${plain(count)} events · ${names.join(', ')}`,\n started: date => `started ${date}`,\n duration: days => `${grouped(days)} day${days === 1 ? '' : 's'}`,\n reached: (dated, total) => `${plain(dated)} of ${plain(total)} milestones`,\n milestones: title => `${title} milestones`,\n },\n production: {\n heading: 'Production progress',\n start: 'Start',\n estimated: 'Estimated',\n estimatedCompletion: 'Estimated completion',\n estDone: 'Est. done',\n play: 'Play',\n pause: 'Pause',\n playTitle: 'Play the timeline, report by report',\n backTo: report => `Back to ${report}`,\n showing: report => `Showing ${report}`,\n overall: p => `${percent(p, 0)} overall`,\n inStock: pieces => `${grouped(pieces)} pc in stock`,\n noReport: 'No production report filed yet',\n leadTime: days => `${grouped(days)} day${days === 1 ? '' : 's'} lead time`,\n report: 'Production report',\n shipment: 'Shipment',\n inspection: 'Inspection',\n invoice: 'Invoice',\n scrub: 'Scrub the production timeline',\n label: (from, to) => `Production reports and events, ${from} to ${to}`,\n },\n containers: {\n items: count => `${plain(count)} items`,\n pieces: count => `${plain(count)} pcs`,\n split: (instructed, loaded) => `(${plain(instructed)} instr / ${plain(loaded)} loaded)`,\n added: (count, pieces) => `${plain(count)} new (${plain(pieces)} pcs)`,\n fill: (volume, capacity) => `${fixed(volume, 1)} / ${plain(capacity)} m³`,\n total: 'Total:',\n instructed: volume => `${fixed(volume, 2)} m³ instruction`,\n loaded: volume => `${fixed(volume, 2)} m³ loaded`,\n volume: volume => `${fixed(volume, 2)} m³`,\n noVolume: 'Volume: N/A (no volume data for these part numbers)',\n },\n toast: {\n notification: 'Notification',\n },\n };\n}\n\nexport const DEFAULT_SHELL_STRINGS: ShellStrings = englishStrings();\n\n/** The English defaults per locale — a provider re-rendering with the same\n * locale gets the same object, so its merge memo holds. */\nconst localisedDefaults = new Map<string, ShellStrings>();\n\nfunction defaultsFor(locale: string | undefined): ShellStrings {\n if (!locale) return DEFAULT_SHELL_STRINGS;\n let defaults = localisedDefaults.get(locale);\n if (!defaults) {\n defaults = englishStrings(locale);\n localisedDefaults.set(locale, defaults);\n }\n return defaults;\n}\n\n/** A per-section partial: override any subset of a section's strings. */\nexport type ShellStringsOverride = {\n [S in keyof ShellStrings]?: Partial<ShellStrings[S]>;\n};\n\nconst ShellStringsContext = createContext<ShellStrings>(DEFAULT_SHELL_STRINGS);\n\n/** `null` outside any provider — which is how a provider tells it is nested. */\nconst ShellLocaleContext = createContext<{ locale: string | undefined } | null>(null);\n\nconst reportedLocales = new Set<string>();\n\n/**\n * The tag in canonical form, or `undefined` for one `Intl` refuses.\n *\n * Refused here, once, rather than at every formatter: `new Intl.DateTimeFormat\n * ('en_US')` throws, and a malformed tag would otherwise take down whichever\n * component formatted a number first — in render, where the error boundary is\n * the only thing left to catch it. A tag that is well formed but names nothing\n * the runtime has (`xx-YY`) is not an error: `Intl` falls back on its own.\n */\nfunction canonicalLocale(tag: string | undefined): string | undefined {\n if (!tag) return undefined;\n try {\n return Intl.getCanonicalLocales(tag)[0];\n } catch {\n if (!reportedLocales.has(tag)) {\n reportedLocales.add(tag);\n console.error(\n `[efficient-shell] ShellStringsProvider: locale=\"${tag}\" is not a BCP 47 language tag, so it is ` +\n 'ignored and numbers and dates keep their default formatting. Pass a tag such as \"de-DE\" or \"ja\".',\n );\n }\n return undefined;\n }\n}\n\n/**\n * The catalog for code that runs outside React — `toast` builds its DOM by\n * hand, long after any render. It follows the OUTERMOST mounted provider (the\n * app's own, not a subtree's), and is the English defaults when none is\n * mounted. Not part of the public surface: components read `useShellStrings`.\n */\nlet outermost: ShellStrings = DEFAULT_SHELL_STRINGS;\n\n/** One empty override for every provider given none — a fresh `{}` per render\n * would re-merge, and re-render every reader, each time the provider did. */\nconst NO_OVERRIDE: ShellStringsOverride = {};\n\nexport function currentShellStrings(): ShellStrings {\n return outermost;\n}\n\n/**\n * Mount once, near the top of the app. `value` is a partial — sections and\n * keys you do not translate keep their English defaults, so a catalog never\n * breaks by falling behind a release.\n *\n * `locale` is a BCP 47 tag (`'de-DE'`, `'ja'`, `'zh-Hant'`) for how numbers and\n * dates are written; omit it and they are written exactly as without a\n * provider. A nested provider without a `locale` keeps its parent's — a subtree\n * that overrides one string should not lose the app's number format. Strings\n * do not cascade that way: a nested provider's `value` merges onto the English\n * defaults, as it always has.\n */\nexport function ShellStringsProvider({ value = NO_OVERRIDE, locale, children }: {\n value?: ShellStringsOverride;\n locale?: string;\n children: ReactNode;\n}) {\n const parent = useContext(ShellLocaleContext);\n const own = useMemo(() => canonicalLocale(locale), [locale]);\n const active = locale === undefined ? parent?.locale : own;\n const merged = useMemo<ShellStrings>(() => {\n const base = defaultsFor(active);\n const out = {} as ShellStrings;\n for (const key of Object.keys(base) as (keyof ShellStrings)[]) {\n out[key] = { ...base[key], ...(value[key] ?? {}) } as never;\n }\n return out;\n }, [value, active]);\n const localeValue = useMemo(() => ({ locale: active }), [active]);\n\n const nested = parent !== null;\n useEffect(() => {\n if (nested) return;\n outermost = merged;\n return () => {\n if (outermost === merged) outermost = DEFAULT_SHELL_STRINGS;\n };\n }, [merged, nested]);\n\n return (\n <ShellLocaleContext.Provider value={localeValue}>\n <ShellStringsContext.Provider value={merged}>{children}</ShellStringsContext.Provider>\n </ShellLocaleContext.Provider>\n );\n}\n\n/** The active catalog — English defaults when no provider is mounted. */\nexport function useShellStrings(): ShellStrings {\n return useContext(ShellStringsContext);\n}\n\n/**\n * The provider's `locale`, canonicalised — `undefined` when there is no\n * provider or it was given none. Hand it to `formatDate(value, { locale })`,\n * `fmtSliderDate(ms, locale)`, or `Intl` directly, so a host's own cells write\n * numbers and dates the way the kit's do.\n */\nexport function useShellLocale(): string | undefined {\n return useContext(ShellLocaleContext)?.locale;\n}\n\n/**\n * The text either side of the value in a catalog sentence, for the few\n * sentences that wrap their value in markup of its own — \"Type <kbd>DELETE</kbd>\n * to confirm:\", \"Showing <b>PR-7</b>\".\n *\n * The entry stays a plain `(word) => string`, so a translator writes a sentence\n * and puts the word wherever their language does; the kit calls it with a\n * marker no sentence contains and splits there. A sentence that leaves the word\n * out entirely comes back whole, as the text before it.\n */\nexport function splitAround(sentence: (slot: string) => string): [string, string] {\n const MARK = '\\u0000';\n const [before = '', ...after] = sentence(MARK).split(MARK);\n return [before, after.join('')];\n}\n"]}