efficient-shell 4.127.0 → 4.132.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/README.md +938 -5
  2. package/dist/{Browser-F5TKMP4K.js → Browser-XPVJ2K7B.js} +13 -10
  3. package/dist/Browser-XPVJ2K7B.js.map +1 -0
  4. package/dist/{Calculator-T3XG7S73.js → Calculator-ZXJPXG7F.js} +12 -9
  5. package/dist/Calculator-ZXJPXG7F.js.map +1 -0
  6. package/dist/ConfirmDialog-MTC7QMUJ.js +4 -0
  7. package/dist/{ConfirmDialog-LJXMB45A.js.map → ConfirmDialog-MTC7QMUJ.js.map} +1 -1
  8. package/dist/{CurrencyConverter-CASQMKLO.js → CurrencyConverter-WSJ2BBSX.js} +12 -9
  9. package/dist/CurrencyConverter-WSJ2BBSX.js.map +1 -0
  10. package/dist/{Documents-YX67YTZS.js → Documents-ONGSXUJI.js} +14 -11
  11. package/dist/Documents-ONGSXUJI.js.map +1 -0
  12. package/dist/{Files-QB63GO6J.js → Files-GQZMFWXQ.js} +17 -14
  13. package/dist/Files-GQZMFWXQ.js.map +1 -0
  14. package/dist/{Notepad-3SUD5XUE.js → Notepad-HM73XAM4.js} +15 -12
  15. package/dist/Notepad-HM73XAM4.js.map +1 -0
  16. package/dist/PdfViewer-M2YGZIYX.js +5 -0
  17. package/dist/{PdfViewer-LSP3YNFC.js.map → PdfViewer-M2YGZIYX.js.map} +1 -1
  18. package/dist/{PomodoroTimer-4EHD2QC4.js → PomodoroTimer-DG3LI5CX.js} +14 -11
  19. package/dist/PomodoroTimer-DG3LI5CX.js.map +1 -0
  20. package/dist/{Preview-4ZHR4SKP.js → Preview-TUSV4UMO.js} +16 -13
  21. package/dist/Preview-TUSV4UMO.js.map +1 -0
  22. package/dist/{Sidebar-J76PV4QF.js → Sidebar-BPU7RCZP.js} +5 -4
  23. package/dist/Sidebar-BPU7RCZP.js.map +1 -0
  24. package/dist/{Spreadsheet-G3SC7XJ5.js → Spreadsheet-3WTXCHYQ.js} +14 -11
  25. package/dist/Spreadsheet-3WTXCHYQ.js.map +1 -0
  26. package/dist/{Stock-TLT4VN2R.js → Stock-YMPOMUAW.js} +12 -9
  27. package/dist/Stock-YMPOMUAW.js.map +1 -0
  28. package/dist/{Weather-FRKX3DAK.js → Weather-NZO3CWLH.js} +12 -9
  29. package/dist/Weather-NZO3CWLH.js.map +1 -0
  30. package/dist/{WorldClock-GKCITO3M.js → WorldClock-HUC6D3AD.js} +12 -9
  31. package/dist/WorldClock-HUC6D3AD.js.map +1 -0
  32. package/dist/apps/index.js +26 -22
  33. package/dist/apps/index.js.map +1 -1
  34. package/dist/brand.css +1 -1
  35. package/dist/chunk-7IN7YZAL.js +547 -0
  36. package/dist/chunk-7IN7YZAL.js.map +1 -0
  37. package/dist/{chunk-YNGPTOL6.js → chunk-7MA5XBWD.js} +3 -3
  38. package/dist/{chunk-YNGPTOL6.js.map → chunk-7MA5XBWD.js.map} +1 -1
  39. package/dist/{chunk-WK7FV7VV.js → chunk-BJ34QOR3.js} +827 -625
  40. package/dist/chunk-BJ34QOR3.js.map +1 -0
  41. package/dist/{chunk-HNH7FOYB.js → chunk-CGXMWHQW.js} +7 -6
  42. package/dist/chunk-CGXMWHQW.js.map +1 -0
  43. package/dist/{chunk-XUCIYMN7.js → chunk-CJYO4RVV.js} +4 -4
  44. package/dist/{chunk-XUCIYMN7.js.map → chunk-CJYO4RVV.js.map} +1 -1
  45. package/dist/{chunk-N3CG5HG5.js → chunk-CLGNTGC5.js} +12 -11
  46. package/dist/chunk-CLGNTGC5.js.map +1 -0
  47. package/dist/chunk-D276EMXS.js +57 -0
  48. package/dist/chunk-D276EMXS.js.map +1 -0
  49. package/dist/{chunk-7KIOEKHS.js → chunk-E3TWIN7Z.js} +21 -135
  50. package/dist/chunk-E3TWIN7Z.js.map +1 -0
  51. package/dist/{chunk-2VM2FRZJ.js → chunk-EENVXIVU.js} +47 -67
  52. package/dist/chunk-EENVXIVU.js.map +1 -0
  53. package/dist/{chunk-YG45DAUT.js → chunk-FONEQRBH.js} +17 -11
  54. package/dist/chunk-FONEQRBH.js.map +1 -0
  55. package/dist/chunk-IPXN646P.js +14 -0
  56. package/dist/chunk-IPXN646P.js.map +1 -0
  57. package/dist/chunk-IRWSRJ4K.js +48 -0
  58. package/dist/chunk-IRWSRJ4K.js.map +1 -0
  59. package/dist/chunk-JMKYYPOF.js +7 -0
  60. package/dist/{chunk-CJZXR7MG.js.map → chunk-JMKYYPOF.js.map} +1 -1
  61. package/dist/{chunk-JFQGPY7W.js → chunk-KWEX4ZAF.js} +20 -17
  62. package/dist/chunk-KWEX4ZAF.js.map +1 -0
  63. package/dist/{chunk-OKEFO6TI.js → chunk-LQTVTOSY.js} +10 -10
  64. package/dist/chunk-LQTVTOSY.js.map +1 -0
  65. package/dist/{chunk-G4KA3SAX.js → chunk-MQPX6ERJ.js} +4 -4
  66. package/dist/{chunk-G4KA3SAX.js.map → chunk-MQPX6ERJ.js.map} +1 -1
  67. package/dist/{chunk-FQB24B42.js → chunk-SEWF4O3H.js} +3 -3
  68. package/dist/{chunk-FQB24B42.js.map → chunk-SEWF4O3H.js.map} +1 -1
  69. package/dist/{chunk-AXWC3332.js → chunk-TFXJRHJV.js} +3 -3
  70. package/dist/{chunk-AXWC3332.js.map → chunk-TFXJRHJV.js.map} +1 -1
  71. package/dist/{chunk-G3HQLQYZ.js → chunk-TQURTLK2.js} +59 -34
  72. package/dist/chunk-TQURTLK2.js.map +1 -0
  73. package/dist/{chunk-6XQHH7D2.js → chunk-TRCWINHF.js} +5 -5
  74. package/dist/{chunk-6XQHH7D2.js.map → chunk-TRCWINHF.js.map} +1 -1
  75. package/dist/{chunk-NPJCMM6V.js → chunk-VWZIGZFF.js} +4 -4
  76. package/dist/{chunk-NPJCMM6V.js.map → chunk-VWZIGZFF.js.map} +1 -1
  77. package/dist/{chunk-HYZ5QMVO.js → chunk-XH3ELPQZ.js} +22 -19
  78. package/dist/chunk-XH3ELPQZ.js.map +1 -0
  79. package/dist/{chunk-PPUZJFCI.js → chunk-ZKHD4J73.js} +8 -7
  80. package/dist/chunk-ZKHD4J73.js.map +1 -0
  81. package/dist/file-intake/index.js +3 -1
  82. package/dist/file-intake/index.js.map +1 -1
  83. package/dist/{index-dQia6NpB.d.ts → index-COwksV6G.d.ts} +699 -199
  84. package/dist/index.d.ts +2 -2
  85. package/dist/index.js +37 -32
  86. package/dist/index.js.map +1 -1
  87. package/dist/map/index.js +5 -3
  88. package/dist/map/index.js.map +1 -1
  89. package/dist/markdown/index.js +4 -3
  90. package/dist/markdown/index.js.map +1 -1
  91. package/dist/page-tabs/index.js +12 -8
  92. package/dist/page-tabs/index.js.map +1 -1
  93. package/dist/shell.css +17 -17
  94. package/dist/themes.css +15 -0
  95. package/dist/ui/index.d.ts +1 -1
  96. package/dist/ui/index.js +17 -13
  97. package/dist/ui/index.js.map +1 -1
  98. package/dist/ui.css +691 -283
  99. package/package.json +1 -1
  100. package/dist/Browser-F5TKMP4K.js.map +0 -1
  101. package/dist/Calculator-T3XG7S73.js.map +0 -1
  102. package/dist/ConfirmDialog-LJXMB45A.js +0 -3
  103. package/dist/CurrencyConverter-CASQMKLO.js.map +0 -1
  104. package/dist/Documents-YX67YTZS.js.map +0 -1
  105. package/dist/Files-QB63GO6J.js.map +0 -1
  106. package/dist/Notepad-3SUD5XUE.js.map +0 -1
  107. package/dist/PdfViewer-LSP3YNFC.js +0 -4
  108. package/dist/PomodoroTimer-4EHD2QC4.js.map +0 -1
  109. package/dist/Preview-4ZHR4SKP.js.map +0 -1
  110. package/dist/Sidebar-J76PV4QF.js.map +0 -1
  111. package/dist/Spreadsheet-G3SC7XJ5.js.map +0 -1
  112. package/dist/Stock-TLT4VN2R.js.map +0 -1
  113. package/dist/Weather-FRKX3DAK.js.map +0 -1
  114. package/dist/WorldClock-GKCITO3M.js.map +0 -1
  115. package/dist/chunk-2VM2FRZJ.js.map +0 -1
  116. package/dist/chunk-3CUSBZWG.js +0 -59
  117. package/dist/chunk-3CUSBZWG.js.map +0 -1
  118. package/dist/chunk-7KIOEKHS.js.map +0 -1
  119. package/dist/chunk-CJZXR7MG.js +0 -7
  120. package/dist/chunk-G3HQLQYZ.js.map +0 -1
  121. package/dist/chunk-HNH7FOYB.js.map +0 -1
  122. package/dist/chunk-HYZ5QMVO.js.map +0 -1
  123. package/dist/chunk-JFQGPY7W.js.map +0 -1
  124. package/dist/chunk-N3CG5HG5.js.map +0 -1
  125. package/dist/chunk-OKEFO6TI.js.map +0 -1
  126. package/dist/chunk-PPUZJFCI.js.map +0 -1
  127. package/dist/chunk-WK7FV7VV.js.map +0 -1
  128. package/dist/chunk-YG45DAUT.js.map +0 -1
@@ -1,7 +1,7 @@
1
+ import { useShellStrings, splitAround } from './chunk-7IN7YZAL.js';
1
2
  import { createContext, useEffect, useRef, useId, useContext, useState, useCallback, useLayoutEffect } from 'react';
2
3
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
4
 
4
- // src/shell/ConfirmDialog.tsx
5
5
  var FOCUSABLE = [
6
6
  "a[href]",
7
7
  "button:not([disabled])",
@@ -160,6 +160,7 @@ function Dialog({
160
160
  const bodyId = useId();
161
161
  const showClose = !blocking && !footer;
162
162
  const titleId = useId();
163
+ const strings = useShellStrings().dialog;
163
164
  useDismissPopupsOnOpen(open);
164
165
  useFocusTrap(panelRef, open, initialFocus);
165
166
  useScrollLock(open);
@@ -200,8 +201,8 @@ function Dialog({
200
201
  {
201
202
  type: "button",
202
203
  onClick: onClose,
203
- "aria-label": "Close",
204
- className: "absolute right-3 top-3 rounded-md p-1 text-gray-400 hover:bg-gray-100 hover:text-gray-600 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-400",
204
+ "aria-label": strings.close,
205
+ className: "absolute right-3 top-3 rounded-md p-1 text-gray-400 hover:bg-gray-100 hover:text-gray-600 rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-solid)]",
205
206
  children: /* @__PURE__ */ jsx("svg", { className: "h-5 w-5", viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M6 6l8 8M14 6l-8 8" }) })
206
207
  }
207
208
  )
@@ -324,6 +325,8 @@ function ConfirmProvider({ children }) {
324
325
  const dTone = TONE[dOptions.variant === "warning" ? "warning" : "danger"];
325
326
  const dWord = dOptions.confirmWord;
326
327
  const dSatisfied = dWord == null || dInput === dWord;
328
+ const strings = useShellStrings().dialog;
329
+ const [typeBefore, typeAfter] = splitAround(strings.typeToConfirm);
327
330
  return /* @__PURE__ */ jsxs(ConfirmContext.Provider, { value: confirmFn, children: [
328
331
  children,
329
332
  /* @__PURE__ */ jsx(
@@ -333,21 +336,21 @@ function ConfirmProvider({ children }) {
333
336
  onClose: () => handleClose(confirmId, false),
334
337
  initialFocus: cancelRef,
335
338
  footer: /* @__PURE__ */ jsxs(Fragment, { children: [
336
- /* @__PURE__ */ jsx("button", { ref: cancelRef, type: "button", onClick: () => handleClose(confirmId, false), className: CANCEL_BTN, children: options.cancelLabel || "Cancel" }),
339
+ /* @__PURE__ */ jsx("button", { ref: cancelRef, type: "button", onClick: () => handleClose(confirmId, false), className: CANCEL_BTN, children: options.cancelLabel || strings.cancel }),
337
340
  /* @__PURE__ */ jsx(
338
341
  "button",
339
342
  {
340
343
  type: "button",
341
344
  onClick: () => handleClose(confirmId, true),
342
345
  className: `px-4 py-2 text-sm font-medium rounded-lg ${tone.button}`,
343
- children: options.confirmLabel || "OK"
346
+ children: options.confirmLabel || strings.ok
344
347
  }
345
348
  )
346
349
  ] }),
347
350
  children: /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
348
351
  /* @__PURE__ */ jsx("div", { className: `shrink-0 w-10 h-10 rounded-full flex items-center justify-center ${tone.icon}`, children: /* @__PURE__ */ jsx(WarningIcon, {}) }),
349
352
  /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
350
- /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold text-gray-900", children: options.title || "Confirm" }),
353
+ /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold text-gray-900", children: options.title || strings.confirmTitle }),
351
354
  /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-gray-600", children: options.message })
352
355
  ] })
353
356
  ] })
@@ -360,7 +363,7 @@ function ConfirmProvider({ children }) {
360
363
  onClose: () => handleDClose(false),
361
364
  initialFocus: dWord != null ? void 0 : dCancelRef,
362
365
  footer: /* @__PURE__ */ jsxs(Fragment, { children: [
363
- /* @__PURE__ */ jsx("button", { ref: dCancelRef, type: "button", onClick: () => handleDClose(false), className: CANCEL_BTN, children: dOptions.cancelLabel || "Dismiss" }),
366
+ /* @__PURE__ */ jsx("button", { ref: dCancelRef, type: "button", onClick: () => handleDClose(false), className: CANCEL_BTN, children: dOptions.cancelLabel || strings.destructiveCancel }),
364
367
  /* @__PURE__ */ jsx(
365
368
  "button",
366
369
  {
@@ -368,7 +371,7 @@ function ConfirmProvider({ children }) {
368
371
  onClick: () => handleDClose(true),
369
372
  disabled: !dSatisfied,
370
373
  className: `px-4 py-2 text-sm font-medium rounded-lg disabled:opacity-40 ${dTone.button}`,
371
- children: dWord ?? dOptions.confirmLabel ?? "Delete"
374
+ children: dWord ?? dOptions.confirmLabel ?? strings.destructiveConfirm
372
375
  }
373
376
  )
374
377
  ] }),
@@ -378,7 +381,7 @@ function ConfirmProvider({ children }) {
378
381
  {
379
382
  type: "button",
380
383
  onClick: () => handleDClose(false),
381
- "aria-label": "Close",
384
+ "aria-label": strings.close,
382
385
  className: "absolute right-4 top-4 rounded-md p-1 text-gray-400 hover:bg-gray-100 hover:text-gray-600",
383
386
  children: /* @__PURE__ */ jsx(CloseIcon, {})
384
387
  }
@@ -386,13 +389,13 @@ function ConfirmProvider({ children }) {
386
389
  /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
387
390
  /* @__PURE__ */ jsx("div", { className: `shrink-0 w-10 h-10 rounded-full flex items-center justify-center ${dTone.icon}`, children: /* @__PURE__ */ jsx(WarningIcon, {}) }),
388
391
  /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
389
- /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold text-gray-900 pr-6", children: dOptions.title || "Confirm Action" }),
392
+ /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold text-gray-900 pr-6", children: dOptions.title || strings.destructiveTitle }),
390
393
  /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-gray-600", children: dOptions.message }),
391
394
  dWord != null && /* @__PURE__ */ jsxs(Fragment, { children: [
392
395
  /* @__PURE__ */ jsxs("p", { className: "mt-3 text-sm text-gray-700", children: [
393
- "Type ",
396
+ typeBefore,
394
397
  /* @__PURE__ */ jsx("kbd", { className: "rounded border border-gray-300 bg-gray-50 px-1.5 py-0.5 text-xs font-bold text-red-600 font-mono", children: dWord }),
395
- " to confirm:"
398
+ typeAfter
396
399
  ] }),
397
400
  /* @__PURE__ */ jsx(
398
401
  "input",
@@ -405,7 +408,7 @@ function ConfirmProvider({ children }) {
405
408
  if (e.key === "Enter" && dInput === dWord) handleDClose(true);
406
409
  },
407
410
  placeholder: dWord,
408
- className: "mt-2 w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-red-500 focus:ring-red-500"
411
+ className: "mt-2 w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-red-500"
409
412
  }
410
413
  )
411
414
  ] })
@@ -419,9 +422,9 @@ function ConfirmProvider({ children }) {
419
422
  {
420
423
  open: pOpen,
421
424
  onClose: () => handlePClose(false),
422
- title: pOptions.title || "Enter a value",
425
+ title: pOptions.title || strings.promptTitle,
423
426
  footer: /* @__PURE__ */ jsxs(Fragment, { children: [
424
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => handlePClose(false), className: CANCEL_BTN, children: pOptions.cancelLabel || "Cancel" }),
427
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => handlePClose(false), className: CANCEL_BTN, children: pOptions.cancelLabel || strings.cancel }),
425
428
  /* @__PURE__ */ jsx(
426
429
  "button",
427
430
  {
@@ -429,7 +432,7 @@ function ConfirmProvider({ children }) {
429
432
  onClick: () => handlePClose(true),
430
433
  disabled: !pOptions.allowEmpty && !pInput.trim(),
431
434
  className: "bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 text-sm font-medium rounded-lg disabled:opacity-40",
432
- children: pOptions.confirmLabel || "OK"
435
+ children: pOptions.confirmLabel || strings.ok
433
436
  }
434
437
  )
435
438
  ] }),
@@ -448,7 +451,7 @@ function ConfirmProvider({ children }) {
448
451
  },
449
452
  onFocus: (e) => e.target.select(),
450
453
  placeholder: pOptions.placeholder,
451
- className: "mt-3 w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 focus:outline-none"
454
+ className: "mt-3 w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-blue-500 rosh-focus-ring focus-visible:ring-1 focus-visible:ring-[color:var(--rosh-focus-ring-accent)]"
452
455
  }
453
456
  )
454
457
  ]
@@ -458,5 +461,5 @@ function ConfirmProvider({ children }) {
458
461
  }
459
462
 
460
463
  export { ConfirmProvider, Dialog, OVERLAY_OPEN_EVENT, Z_LAYERS, confirm, confirmDestructive, dismissPopups, onOverlayOpen, prompt, registerModalEscapeInterceptor, runEscapeInterceptors, useConfirm, useDismissPopupsOnOpen, useFocusTrap, useScrollLock };
461
- //# sourceMappingURL=chunk-HYZ5QMVO.js.map
462
- //# sourceMappingURL=chunk-HYZ5QMVO.js.map
464
+ //# sourceMappingURL=chunk-XH3ELPQZ.js.map
465
+ //# sourceMappingURL=chunk-XH3ELPQZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shell/focusTrap.ts","../src/shell/escapeInterceptors.ts","../src/shell/overlayEvents.ts","../src/shell/useDismissPopupsOnOpen.ts","../src/shell/zLayers.ts","../src/shell/Dialog.tsx","../src/shell/ConfirmDialog.tsx"],"names":["useEffect","jsx","useRef","jsxs"],"mappings":"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","file":"chunk-XH3ELPQZ.js","sourcesContent":["/**\n * Focus containment and scroll locking for a modal surface — the two things\n * Headless UI was doing for `ConfirmDialog` before it was rewritten to import\n * nothing.\n *\n * Both are small, and both are the kind of small that is wrong in a way nobody\n * notices until someone navigates by keyboard: focus tabbing out of a dialog\n * onto the page behind it reads as the dialog having closed, and a page that\n * scrolls under a fixed overlay loses the user's place when it reopens.\n */\nimport { useEffect, type RefObject } from 'react';\n\n/**\n * Focusable candidates, in DOM order. Deliberately excludes anything with\n * `tabindex=\"-1\"` — that attribute means \"focusable by script, skipped by Tab\",\n * and treating it as a stop is the usual bug in a hand-rolled trap.\n */\nconst FOCUSABLE = [\n 'a[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(',');\n\nfunction focusable(root: HTMLElement): HTMLElement[] {\n return Array.from(root.querySelectorAll<HTMLElement>(FOCUSABLE))\n // A hidden element still matches the selector. offsetParent is null for\n // anything display:none or inside it — cheap, and right for our markup.\n .filter(el => el.offsetParent !== null || el === document.activeElement);\n}\n\n/**\n * While `active`, keep Tab inside `ref`, move focus in on open, and restore it\n * to wherever it came from on close.\n *\n * Restoring matters more than trapping: a dialog opened from a button in a\n * toolbar should hand focus back to that button, or a keyboard user is dumped\n * at the top of the document and has to find their place again.\n */\nexport function useFocusTrap(\n ref: RefObject<HTMLElement | null>,\n active: boolean,\n initialFocus?: RefObject<HTMLElement | null>,\n): void {\n useEffect(() => {\n if (!active) return;\n const root = ref.current;\n if (!root) return;\n\n const previous = document.activeElement as HTMLElement | null;\n\n // Focus the requested element, else the first natural stop, else the\n // container itself so the trap has somewhere to hold focus at all.\n const first = initialFocus?.current ?? focusable(root)[0] ?? root;\n if (first === root && !root.hasAttribute('tabindex')) root.setAttribute('tabindex', '-1');\n first.focus();\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key !== 'Tab') return;\n const stops = focusable(root);\n if (stops.length === 0) { e.preventDefault(); return; }\n const firstStop = stops[0];\n const lastStop = stops[stops.length - 1];\n const current = document.activeElement;\n\n // Wrap at both ends. Also catches focus having escaped the dialog\n // entirely (current is outside root), which happens if something inside\n // was removed while focused.\n if (e.shiftKey && (current === firstStop || !root.contains(current))) {\n e.preventDefault();\n lastStop.focus();\n } else if (!e.shiftKey && (current === lastStop || !root.contains(current))) {\n e.preventDefault();\n firstStop.focus();\n }\n };\n\n document.addEventListener('keydown', onKeyDown, true);\n return () => {\n document.removeEventListener('keydown', onKeyDown, true);\n // Only take focus back if it is still inside the dialog. If something\n // else claimed it in the meantime, stealing it back is the rude option.\n if (!root.contains(document.activeElement) && document.activeElement !== document.body) return;\n previous?.focus?.();\n };\n }, [ref, active, initialFocus]);\n}\n\n/**\n * While `active`, stop the document behind the overlay from scrolling.\n *\n * Compensates for the scrollbar's width so the page does not visibly jump\n * sideways as it locks — the artefact that makes a dialog feel cheap. Nested\n * locks are counted, so two stacked dialogs unlock exactly once.\n */\nlet lockCount = 0;\nlet restore: { overflow: string; paddingRight: string } | null = null;\n\nexport function useScrollLock(active: boolean): void {\n useEffect(() => {\n if (!active) return;\n const body = document.body;\n if (lockCount === 0) {\n restore = { overflow: body.style.overflow, paddingRight: body.style.paddingRight };\n const gap = window.innerWidth - document.documentElement.clientWidth;\n body.style.overflow = 'hidden';\n if (gap > 0) body.style.paddingRight = `${gap}px`;\n }\n lockCount += 1;\n return () => {\n lockCount -= 1;\n if (lockCount === 0 && restore) {\n body.style.overflow = restore.overflow;\n body.style.paddingRight = restore.paddingRight;\n restore = null;\n }\n };\n }, [active]);\n}\n","/**\n * The Escape-interceptor seam — deliberately a leaf that imports NOTHING.\n *\n * This lived inside `shell/Modal.tsx` until 4.16.0, and that one detail decided\n * what the whole package cost to import. `forms/Select.tsx` registers an\n * interceptor so Escape closes its portaled listbox instead of the window\n * around it — a two-line need — and reaching it through Modal pulled the entire\n * window manager into any bundle containing a dropdown: react-router-dom,\n * @tanstack/react-query, axios, @headlessui/react and @heroicons/react, plus\n * Modal's module-scope `localStorage` reads, which run at import time. An app\n * that wanted a text field and a select paid for a desktop it never rendered.\n *\n * Splitting the Set out is the whole fix: Modal and Select now both import this\n * file, and neither imports the other. `registerModalEscapeInterceptor` is\n * re-exported from Modal (and so from the package root) with the same binding\n * identity, so nothing downstream changes.\n *\n * NOTHING may be imported here — not React, not a type, not a sibling. The\n * moment it has an edge, every consumer of `react-os-shell/ui` inherits that\n * edge's transitive graph, which is exactly the failure this module exists to\n * prevent. `tests/uiEntryIsPeerFree.test.ts` enforces it.\n *\n * ── Escape interceptors ────────────────────────────────────────────────────\n * Window content can claim an Escape press before the topmost-modal handler\n * closes the window — e.g. the DXF Preview's measure tool exits AutoCAD-style\n * (clear the command input, then the tool, and only a further Esc closes the\n * window). Interceptors run in REVERSE registration order — most recently\n * registered first — and the first to return true consumes the event (the\n * modal neither closes nor sees it). An interceptor is global, so it must\n * check it belongs to the *active* modal itself (via `getActiveModalId()`)\n * before consuming.\n *\n * Reverse, because registration order tracks stacking order and Escape belongs\n * to whatever is on top. Two stacked `Dialog`s each register one; oldest-first\n * would hand Escape to the dialog UNDERNEATH and dismiss the wrong surface,\n * leaving the one the user is looking at on screen. This was invisible while\n * `ConfirmDialog` was the only multi-dialog registrant, because it registered\n * a single interceptor and hand-ordered its three dialogs inside it.\n *\n * Registrants that check `getActiveModalId()` are unaffected: at most one of\n * them can consume, so the order they are offered the event in cannot change\n * which one takes it.\n *\n * ── Draining the Set with no shell present ────────────────────────────────\n * This used to say that nothing draining the Set was fine, because a component\n * would handle Escape itself. That holds for `Select`, which has its own\n * `onKeyDown`. It did NOT hold for `Dialog`, which registers here and has no\n * other handler — so on a till or a routed portal, the two places `Dialog`\n * exists to serve, Escape did nothing at all.\n *\n * So the Set drains itself. The first registration attaches one document-level\n * capture listener; the last removal takes it away.\n *\n * It cannot double-fire when a shell IS present. `Modal` listens on `window`\n * in the capture phase, and capture runs window before document: Modal's\n * handler goes first, calls `runEscapeInterceptors`, and stops propagation when\n * one consumes — so this listener never sees the event. When Modal declines\n * (it is not the topmost window), this runs and the dialog floating above it\n * still gets its Escape, which is the right outcome anyway.\n *\n * Ordering across stacked dialogs is unchanged, because it is still the same\n * reverse walk deciding who consumes — not the listener that started it.\n */\nconst escapeInterceptors = new Set<(e: KeyboardEvent) => boolean>();\n\n/**\n * The self-drain listener, attached while at least one interceptor is\n * registered. Kept in module scope rather than per-registration so N dialogs\n * share one listener and the reverse walk stays the only thing deciding who\n * consumes.\n */\nlet detachDrain: (() => void) | null = null;\n\nfunction attachDrain(): void {\n // `document` is absent when this module is imported on a server; there is no\n // Escape to handle there, and registration still works for when it hydrates.\n if (detachDrain || typeof document === 'undefined') return;\n const onKeyDown = (e: KeyboardEvent): void => {\n if (e.key !== 'Escape') return;\n if (runEscapeInterceptors(e)) {\n e.preventDefault();\n e.stopPropagation();\n }\n };\n document.addEventListener('keydown', onKeyDown, true);\n detachDrain = () => document.removeEventListener('keydown', onKeyDown, true);\n}\n\n/** Register an Escape interceptor; returns an unregister function. */\nexport function registerModalEscapeInterceptor(fn: (e: KeyboardEvent) => boolean): () => void {\n escapeInterceptors.add(fn);\n attachDrain();\n return () => {\n escapeInterceptors.delete(fn);\n if (escapeInterceptors.size === 0 && detachDrain) {\n detachDrain();\n detachDrain = null;\n }\n };\n}\n\n/** Run the registered interceptors, most recent first; true if one consumed\n * the event. Internal to the shell — the window key handler calls this,\n * consumers never do. */\nexport function runEscapeInterceptors(e: KeyboardEvent): boolean {\n // A Set iterates in insertion order and has no reverse iterator, so snapshot\n // it. The copy also makes the walk safe against an interceptor that\n // unregisters itself while handling the event — which is exactly what a\n // dialog closing on Escape does.\n const ordered = Array.from(escapeInterceptors);\n for (let i = ordered.length - 1; i >= 0; i--) {\n try {\n if (ordered[i](e)) return true;\n } catch { /* a broken interceptor must not block closing */ }\n }\n return false;\n}\n","/**\n * The overlay-open seam — deliberately a leaf that imports NOTHING, for the same\n * reason as `escapeInterceptors.ts`: every popup in `react-os-shell/ui` reaches\n * it, so any edge added here lands in every consumer's bundle.\n *\n * ── Why popups need telling ──\n * A popup (a listbox, a calendar, a context menu) is portalled to `<body>` and\n * layered above the modal layer, so it can escape the window or dialog that\n * owns it. It closes on an outside pointer-down, on its own keys, and on a\n * pick. None of those happen when a keyboard shortcut opens a full-screen\n * overlay: ⌘K raised the search palette over an open `SearchableSelect`, and\n * the list stayed open, painted crisp ABOVE the palette's blurred backdrop.\n * Raising the palette cannot fix that — a popup opened INSIDE the palette or a\n * dialog must still paint above it, so the popup layer has to stay on top.\n *\n * So an overlay announces itself as it opens, and every open popup closes.\n * An overlay dispatches BEFORE its own content subscribes (a popup subscribes\n * only while open, in a passive effect), so a popup inside the overlay being\n * opened is never the one dismissed.\n *\n * Consumers with an overlay of their own call `dismissPopups()` when it opens;\n * consumers with a popup of their own listen for `OVERLAY_OPEN_EVENT` on\n * `window`.\n */\n\n/** Dispatched on `window` when a full-screen overlay (the search palette, a\n * `Dialog`, a `Drawer`, the shortcut sheet) opens. Open popups close on it. */\nexport const OVERLAY_OPEN_EVENT = 'react-os-shell:overlay-open';\n\n/** Close every open popup — call it as an overlay opens. A no-op on a server. */\nexport function dismissPopups(): void {\n if (typeof window === 'undefined') return;\n window.dispatchEvent(new Event(OVERLAY_OPEN_EVENT));\n}\n\n/** Subscribe to `OVERLAY_OPEN_EVENT`; returns the unsubscribe. Internal to the\n * kit's popups, which call it from the effect that runs while they are open. */\nexport function onOverlayOpen(handler: () => void): () => void {\n if (typeof window === 'undefined') return () => {};\n window.addEventListener(OVERLAY_OPEN_EVENT, handler);\n return () => window.removeEventListener(OVERLAY_OPEN_EVENT, handler);\n}\n","import { useEffect, useLayoutEffect } from 'react';\nimport { dismissPopups } from './overlayEvents';\n\n/**\n * A layout effect in the browser, a passive one on a server — where a layout\n * effect never runs anyway and React 18 warns for calling one.\n */\nconst useBrowserLayoutEffect = typeof document === 'undefined' ? useEffect : useLayoutEffect;\n\n/**\n * For an overlay: close every open popup as `open` turns true.\n *\n * A LAYOUT effect, not a passive one, so the popups close in the same frame the\n * overlay first paints. A state update made from a passive effect is scheduled\n * as a later task, and the browser lane caught the gap: the palette was on\n * screen with the list still open over it, for a frame or more, one run in\n * three.\n *\n * It runs before any popup inside the overlay can have subscribed — those\n * subscribe from a passive effect, and only once open — so the overlay never\n * dismisses its own content (see `overlayEvents.ts`).\n */\nexport function useDismissPopupsOnOpen(open: boolean): void {\n useBrowserLayoutEffect(() => {\n if (open) dismissPopups();\n }, [open]);\n}\n","/**\n * The shell's z-index scale — one map instead of literals scattered across the\n * components that stack against each other. A leaf that imports nothing, like\n * `escapeInterceptors.ts`, because the kit's popups read it.\n *\n * The numbers are the ones those components already used; collecting them\n * changed the order of exactly one thing, the ⌘K search palette. It sat at 200,\n * which is below the window stack once a dozen windows are open\n * (`window + index * windowStep`), below every pinned window, and below every\n * dialog — so it now sits on the overlay layer with `Dialog` and `Drawer`, and\n * is portalled to `<body>` so no window's stacking context can hold it down.\n *\n * Applied as inline `zIndex`, never as a Tailwind `z-[…]` class built from\n * these numbers: an interpolated class name is invisible to the consumer's\n * Tailwind scan and would generate no rule at all.\n *\n * Bottom to top:\n *\n * window 50 base of the window stack; each window above adds\n * windowStep 10 (`Modal`'s activation order)\n * menu 400 context menus and flyouts that stay in their layer\n * (`PopupMenu`)\n * pinnedWindow 999 an always-on-top window\n * overlay 9999 full-screen surfaces that interrupt: the search palette,\n * `Dialog`, `Drawer`, the shortcut sheet\n * popup 10000 portalled popups (listboxes, calendars, the server\n * status card) — above the overlay layer, so one opened\n * from inside a dialog or the palette is not drawn behind\n * it. Popups close when an overlay opens (`overlayEvents`),\n * which is what stops one from floating over an overlay\n * that was opened on top of it.\n */\nexport const Z_LAYERS = {\n window: 50,\n windowStep: 10,\n menu: 400,\n pinnedWindow: 999,\n overlay: 9999,\n popup: 10000,\n} as const;\n\nexport type ZLayer = keyof typeof Z_LAYERS;\n","/**\n * Dialog — a modal sheet that is NOT a shell window.\n *\n * The distinction matters. `Modal` is a window: it has a title bar, it can be\n * minimised, dragged, stacked and restored, and it lives in the window manager's\n * activation order. This is the other thing — an overlay that interrupts, is\n * answered, and goes away. A till has no desktop to put a window on, and a\n * routed portal page has no window manager either, so both need this one.\n *\n * It imports nothing but React, which is the point: it is what lets\n * `ConfirmDialog` — and every consumer of `react-os-shell/ui` — stop depending\n * on Headless UI and Heroicons. Focus containment and scroll locking come from\n * `./focusTrap` rather than a library.\n */\nimport { useEffect, useId, useRef, type ReactNode, type RefObject } from 'react';\nimport { useFocusTrap, useScrollLock } from './focusTrap';\nimport { registerModalEscapeInterceptor } from './escapeInterceptors';\nimport { useDismissPopupsOnOpen } from './useDismissPopupsOnOpen';\nimport { useShellStrings } from './strings';\nimport { Z_LAYERS } from './zLayers';\n\nexport type DialogSize = 'sm' | 'md' | 'lg';\n\nexport interface DialogProps {\n open: boolean;\n /** Called for Escape, a backdrop click, and the close control. */\n onClose: () => void;\n title?: ReactNode;\n children?: ReactNode;\n /** Action row, right-aligned below the body. */\n footer?: ReactNode;\n /**\n * Escape and backdrop clicks do nothing — the only way out is an action in\n * the footer. For a state the user must actually resolve rather than dismiss,\n * such as a sale whose outcome is unknown. Use it sparingly: a dialog that\n * cannot be dismissed is a dead end if its actions ever fail to render.\n */\n blocking?: boolean;\n size?: DialogSize;\n /**\n * Element to focus on open. Defaults to the first focusable thing in the\n * dialog — which for a destructive confirm should be Cancel, not the button\n * that does the irreversible thing.\n */\n initialFocus?: RefObject<HTMLElement | null>;\n /**\n * Names the dialog when it carries no visible `title`. Without a name it is\n * announced as just \"dialog\", which tells a screen reader user nothing about\n * what opened. Ignored when `title` is set — a visible label always wins over\n * a parallel invisible one, or the two drift.\n */\n 'aria-label'?: string;\n className?: string;\n}\n\nconst SIZES: Record<DialogSize, string> = {\n sm: 'max-w-sm',\n md: 'max-w-md',\n lg: 'max-w-lg',\n};\n\nexport default function Dialog({\n open, onClose, title, children, footer, blocking = false, size = 'md', initialFocus,\n 'aria-label': ariaLabel, className = '',\n}: DialogProps) {\n const panelRef = useRef<HTMLDivElement>(null);\n const bodyId = useId();\n // One source of truth for the close control: the button and the title's\n // gutter are the same decision, and computing it twice is how they drift.\n const showClose = !blocking && !footer;\n const titleId = useId();\n const strings = useShellStrings().dialog;\n\n // Opening closes every popup still open elsewhere: they sit on the popup\n // layer, above this one, and would float over the scrim. A popup inside this\n // dialog is unaffected — it cannot be open yet, and it only subscribes while\n // open (see `overlayEvents.ts`).\n useDismissPopupsOnOpen(open);\n\n useFocusTrap(panelRef, open, initialFocus);\n useScrollLock(open);\n\n // Escape goes through the shell's interceptor rather than a local listener.\n // A dialog floats above every shell window but is absent from the window\n // activation order, so an unclaimed Escape reaches the frontmost Modal and\n // closes the WINDOW BEHIND the dialog. Claiming it here means the dialog\n // closes and the window does not. With no shell present nothing else is\n // listening and this is simply where Escape is handled.\n useEffect(() => {\n if (!open) return;\n return registerModalEscapeInterceptor(() => {\n if (blocking) return true; // claimed, but deliberately does nothing\n onClose();\n return true;\n });\n }, [open, blocking, onClose]);\n\n if (!open) return null;\n\n return (\n <div className=\"fixed inset-0\" style={{ zIndex: Z_LAYERS.overlay }} role=\"presentation\">\n {/* No handler here. The dismissal layer below is also `fixed inset-0`\n and sits on top of this, so a click in this region never reaches the\n scrim — an onClick here would be unreachable in every case, and two\n dismissal paths where only one can fire is how the next reader loses\n an afternoon. */}\n <div className=\"fixed inset-0 bg-black/30\" aria-hidden=\"true\" />\n {/* The scrim above covers the viewport, and so does this — which sits on\n top of it. A click \"outside the dialog\" therefore landed HERE and\n never reached the scrim's handler, so clicking away never dismissed\n anything and a dialog with no buttons could only be left with Escape.\n The dismissal lives on this layer as well, gated on the target being\n the layer itself so a click inside the panel does not bubble into it. */}\n <div\n className=\"fixed inset-0 flex items-center justify-center p-4\"\n onClick={blocking ? undefined : (e => { if (e.target === e.currentTarget) onClose(); })}\n >\n <div\n ref={panelRef}\n role=\"dialog\"\n aria-modal=\"true\"\n // Points at the rendered heading rather than re-deriving the name\n // from the prop: `title` is a ReactNode, so an element title — an\n // icon beside a word, a count in a badge — used to fall through the\n // string check and leave the dialog with no name at all.\n aria-labelledby={title ? titleId : undefined}\n aria-label={title ? undefined : ariaLabel}\n // The body is the dialog's description, and saying so is what makes a\n // screen reader read the question along with the title when focus\n // lands here. Without it the user hears \"Cancel order, dialog\" and\n // has to go looking for what cancelling actually does.\n aria-describedby={children ? bodyId : undefined}\n className={`relative w-full ${SIZES[size]} rounded-lg bg-white p-6 shadow-xl ${className}`.trim()}\n >\n {/* `id` for the accessible name, and a right gutter ONLY when the\n close button is actually there to need it — a dialog with a\n footer draws no cross, and reserving 2rem beside its title just\n indents the heading away from the edge for nothing. */}\n {title && (\n <h2 id={titleId} className={`${showClose ? 'pr-8 ' : ''}text-base font-semibold text-gray-900`}>\n {title}\n </h2>\n )}\n {children && <div id={bodyId} className=\"mt-2 text-sm text-gray-600\">{children}</div>}\n {footer && <div className=\"mt-6 flex justify-end gap-3\">{footer}</div>}\n {/* A way out that is visible, for a dialog that offers none of its\n own. Escape and the backdrop both work, but neither is on screen,\n so a dialog whose body is just an image could be left only by a\n keyboard shortcut nothing announces.\n\n NOT when there is a footer. A confirm already offers two labelled\n choices, and an unlabelled cross beside \"Discard\" and \"Keep\n Editing\" is a third exit that says nothing about which one it\n means — worse on the decision where it matters most. It also put\n a stop in the middle of that dialog's Tab cycle, which is the\n thing the browser test guards.\n\n LAST in the DOM though drawn top-right: first, it became the\n dialog's first tab stop and the first button a focus trap finds. */}\n {showClose && (\n <button\n type=\"button\"\n onClick={onClose}\n aria-label={strings.close}\n className=\"absolute right-3 top-3 rounded-md p-1 text-gray-400 hover:bg-gray-100 hover:text-gray-600 rosh-focus-ring focus-visible:ring-2 focus-visible:ring-[color:var(--rosh-focus-ring-solid)]\"\n >\n <svg className=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden=\"true\">\n <path d=\"M6 6l8 8M14 6l-8 8\" />\n </svg>\n </button>\n )}\n </div>\n </div>\n </div>\n );\n}\n","/**\n * confirm / confirmDestructive / prompt — the imperative dialogs, callable from\n * any click handler without a hook.\n *\n * Rebuilt on `./Dialog` in 4.18.0. It previously rendered Headless UI, which\n * meant every consumer of `react-os-shell/ui` inherited `@headlessui/react` and\n * `@heroicons/react` to ask someone a yes/no question. Focus containment and\n * scroll locking now come from `./focusTrap`; the icons are inline SVG. The\n * three dialogs' behaviour is otherwise unchanged, with two deliberate\n * exceptions noted below.\n *\n * FAIL-CLOSED. Each global starts as a function resolving to false/null, so a\n * `confirm()` with no provider mounted answers \"no\" rather than hanging or\n * throwing. A dialog nobody can see must never resolve true — that is the\n * difference between a no-op and a deletion.\n *\n * CONFIRMS QUEUE, they do not drop. A second `confirm()` while one is open\n * waits its turn and shows afterwards. Dropping it would silently resolve a\n * question the user was never asked, and the caller cannot tell that from a\n * genuine \"no\".\n */\nimport { createContext, useContext, useState, useCallback, useRef, useEffect } from 'react';\nimport Dialog from './Dialog';\nimport { splitAround, useShellStrings } from './strings';\n\ninterface ConfirmOptions {\n title?: string;\n message: string;\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: 'danger' | 'warning' | 'info';\n}\n\ntype ConfirmFn = (options: ConfirmOptions | string) => Promise<boolean>;\ninterface PendingConfirm {\n id: number;\n options: ConfirmOptions;\n resolve: (value: boolean) => void;\n}\n\nconst ConfirmContext = createContext<ConfirmFn>(() => Promise.resolve(false));\n\nexport const useConfirm = () => useContext(ConfirmContext);\n\n// Global callable — works without a hook, usable from any click handler\nlet globalConfirmFn: ConfirmFn = () => Promise.resolve(false);\nexport const confirm = (opts: ConfirmOptions | string) => globalConfirmFn(opts);\n\ninterface DestructiveConfirmOptions {\n title?: string;\n message: string;\n /**\n * Require typing this word (case-sensitive) before the action is enabled —\n * for something genuinely irreversible at scale, like dropping a tenant.\n *\n * OPTIONAL since 4.18.0. Omit it for a plain two-button destructive confirm.\n * Type-to-confirm assumes a keyboard, and a touch device that has none (a\n * till, a warehouse scanner) cannot satisfy it at all — the dialog becomes an\n * unanswerable question. Ask for a word when the cost of a mis-tap is high\n * enough to justify making the user work; not by default.\n */\n confirmWord?: string;\n /** Label for the action button when there is no `confirmWord`. */\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: 'danger' | 'warning';\n}\ntype DestructiveConfirmFn = (options: DestructiveConfirmOptions) => Promise<boolean>;\nlet globalDestructiveConfirmFn: DestructiveConfirmFn = () => Promise.resolve(false);\nexport const confirmDestructive = (opts: DestructiveConfirmOptions) => globalDestructiveConfirmFn(opts);\n\n// Prompt — windowed replacement for native window.prompt(). Resolves to the\n// trimmed string, or null if the user cancelled. Empty input counts as\n// cancel by default; pass `allowEmpty: true` to opt in.\ninterface PromptOptions {\n title?: string;\n message?: string;\n defaultValue?: string;\n placeholder?: string;\n confirmLabel?: string;\n cancelLabel?: string;\n allowEmpty?: boolean;\n}\ntype PromptFn = (options: PromptOptions | string) => Promise<string | null>;\nlet globalPromptFn: PromptFn = () => Promise.resolve(null);\nexport const prompt = (opts: PromptOptions | string) => globalPromptFn(opts);\n\nconst TONE: Record<'danger' | 'warning' | 'info', { icon: string; button: string }> = {\n danger: { icon: 'text-red-600 bg-red-100', button: 'bg-red-600 hover:bg-red-700 text-white' },\n warning: { icon: 'text-yellow-600 bg-yellow-100', button: 'bg-yellow-600 hover:bg-yellow-700 text-white' },\n info: { icon: 'text-blue-600 bg-blue-100', button: 'bg-blue-600 hover:bg-blue-700 text-white' },\n};\n\nconst CANCEL_BTN =\n 'bg-white text-gray-700 border border-gray-300 px-4 py-2 text-sm font-medium rounded-lg hover:bg-gray-50';\n\n/** Inline replacements for the two Heroicons this file used to import. */\nfunction WarningIcon() {\n return (\n <svg className=\"h-5 w-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"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 </svg>\n );\n}\n\nfunction CloseIcon() {\n return (\n <svg className=\"h-5 w-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n );\n}\n\nexport function ConfirmProvider({ children }: { children: React.ReactNode }) {\n const [open, setOpen] = useState(false);\n const [options, setOptions] = useState<ConfirmOptions>({ message: '' });\n const [confirmId, setConfirmId] = useState(0);\n const resolveRef = useRef<(value: boolean) => void>();\n const activeConfirmIdRef = useRef<number | null>(null);\n const nextConfirmIdRef = useRef(0);\n const confirmQueueRef = useRef<PendingConfirm[]>([]);\n\n // Cancel is the default focus target in every dialog here. The destructive\n // action sits on the RIGHT and is never what Enter or a stray keypress hits.\n const cancelRef = useRef<HTMLButtonElement>(null);\n const dCancelRef = useRef<HTMLButtonElement>(null);\n\n const showConfirm = useCallback((request: PendingConfirm) => {\n activeConfirmIdRef.current = request.id;\n resolveRef.current = request.resolve;\n setConfirmId(request.id);\n setOptions(request.options);\n setOpen(true);\n }, []);\n\n const confirmFn: ConfirmFn = useCallback((opts) => {\n const normalized = typeof opts === 'string' ? { message: opts } : opts;\n return new Promise<boolean>((resolve) => {\n const request = { id: ++nextConfirmIdRef.current, options: normalized, resolve };\n if (activeConfirmIdRef.current === null) showConfirm(request);\n else confirmQueueRef.current.push(request);\n });\n }, [showConfirm]);\n\n // Destructive confirm state\n const [dOpen, setDOpen] = useState(false);\n const [dOptions, setDOptions] = useState<DestructiveConfirmOptions>({ message: '' });\n const [dInput, setDInput] = useState('');\n const dResolveRef = useRef<(value: boolean) => void>();\n\n const destructiveConfirmFn: DestructiveConfirmFn = useCallback((opts) => {\n setDOptions(opts);\n setDInput('');\n setDOpen(true);\n return new Promise<boolean>((resolve) => {\n dResolveRef.current = resolve;\n });\n }, []);\n\n // Prompt state\n const [pOpen, setPOpen] = useState(false);\n const [pOptions, setPOptions] = useState<PromptOptions>({});\n const [pInput, setPInput] = useState('');\n const pResolveRef = useRef<(value: string | null) => void>();\n\n const promptFn: PromptFn = useCallback((opts) => {\n const normalized = typeof opts === 'string' ? { message: opts } : opts;\n setPOptions(normalized);\n setPInput(normalized.defaultValue ?? '');\n setPOpen(true);\n return new Promise<string | null>((resolve) => {\n pResolveRef.current = resolve;\n });\n }, []);\n\n useEffect(() => {\n globalConfirmFn = confirmFn;\n globalDestructiveConfirmFn = destructiveConfirmFn;\n globalPromptFn = promptFn;\n }, [confirmFn, destructiveConfirmFn, promptFn]);\n\n const handleClose = (id: number, result: boolean) => {\n // A callback captured by the previous dialog must never settle the next\n // queued request after the active request advances.\n if (activeConfirmIdRef.current !== id) return;\n const resolve = resolveRef.current;\n const next = confirmQueueRef.current.shift();\n if (next) showConfirm(next);\n else {\n activeConfirmIdRef.current = null;\n resolveRef.current = undefined;\n setOpen(false);\n }\n resolve?.(result);\n };\n\n const handleDClose = (result: boolean) => {\n setDOpen(false);\n setDInput('');\n dResolveRef.current?.(result);\n };\n\n const handlePClose = (commit: boolean) => {\n if (commit) {\n const trimmed = pInput.trim();\n if (!trimmed && !pOptions.allowEmpty) {\n // Empty + not opted-in to allow empty: treat Save as Cancel.\n setPOpen(false);\n pResolveRef.current?.(null);\n return;\n }\n setPOpen(false);\n pResolveRef.current?.(trimmed);\n } else {\n setPOpen(false);\n pResolveRef.current?.(null);\n }\n };\n\n // Escape is claimed by each Dialog itself now, and interceptors run most\n // recent first, so a stack of these dismisses top-down without the provider\n // hand-ordering them the way it used to.\n\n const variant = options.variant || (options.confirmLabel?.toLowerCase().includes('delete') || options.message.toLowerCase().includes('delete') ? 'danger' : 'info');\n const tone = TONE[variant];\n const dTone = TONE[dOptions.variant === 'warning' ? 'warning' : 'danger'];\n const dWord = dOptions.confirmWord;\n const dSatisfied = dWord == null || dInput === dWord;\n // Every default below is the catalog's; every option a caller passed still\n // wins, exactly as it did over the hardcoded English.\n const strings = useShellStrings().dialog;\n const [typeBefore, typeAfter] = splitAround(strings.typeToConfirm);\n\n return (\n <ConfirmContext.Provider value={confirmFn}>\n {children}\n\n <Dialog\n open={open}\n onClose={() => handleClose(confirmId, false)}\n initialFocus={cancelRef}\n footer={\n <>\n <button ref={cancelRef} type=\"button\" onClick={() => handleClose(confirmId, false)} className={CANCEL_BTN}>\n {options.cancelLabel || strings.cancel}\n </button>\n <button type=\"button\" onClick={() => handleClose(confirmId, true)}\n className={`px-4 py-2 text-sm font-medium rounded-lg ${tone.button}`}>\n {options.confirmLabel || strings.ok}\n </button>\n </>\n }\n >\n <div className=\"flex gap-4\">\n <div className={`shrink-0 w-10 h-10 rounded-full flex items-center justify-center ${tone.icon}`}>\n <WarningIcon />\n </div>\n <div className=\"flex-1\">\n <h2 className=\"text-base font-semibold text-gray-900\">{options.title || strings.confirmTitle}</h2>\n <p className=\"mt-2 text-sm text-gray-600\">{options.message}</p>\n </div>\n </div>\n </Dialog>\n\n {/* Destructive confirm — optionally gated on typing a word */}\n <Dialog\n open={dOpen}\n onClose={() => handleDClose(false)}\n // With a word to type, focus the input: that is the task. Without one,\n // focus Cancel, so the irreversible button is never one Enter away.\n initialFocus={dWord != null ? undefined : dCancelRef}\n footer={\n <>\n <button ref={dCancelRef} type=\"button\" onClick={() => handleDClose(false)} className={CANCEL_BTN}>\n {dOptions.cancelLabel || strings.destructiveCancel}\n </button>\n <button type=\"button\" onClick={() => handleDClose(true)} disabled={!dSatisfied}\n className={`px-4 py-2 text-sm font-medium rounded-lg disabled:opacity-40 ${dTone.button}`}>\n {dWord ?? dOptions.confirmLabel ?? strings.destructiveConfirm}\n </button>\n </>\n }\n >\n <button\n type=\"button\"\n onClick={() => handleDClose(false)}\n aria-label={strings.close}\n className=\"absolute right-4 top-4 rounded-md p-1 text-gray-400 hover:bg-gray-100 hover:text-gray-600\"\n >\n <CloseIcon />\n </button>\n <div className=\"flex gap-4\">\n <div className={`shrink-0 w-10 h-10 rounded-full flex items-center justify-center ${dTone.icon}`}>\n <WarningIcon />\n </div>\n <div className=\"flex-1\">\n <h2 className=\"text-base font-semibold text-gray-900 pr-6\">{dOptions.title || strings.destructiveTitle}</h2>\n <p className=\"mt-2 text-sm text-gray-600\">{dOptions.message}</p>\n {dWord != null && (\n <>\n <p className=\"mt-3 text-sm text-gray-700\">\n {typeBefore}<kbd className=\"rounded border border-gray-300 bg-gray-50 px-1.5 py-0.5 text-xs font-bold text-red-600 font-mono\">{dWord}</kbd>{typeAfter}\n </p>\n <input\n autoFocus\n type=\"text\"\n value={dInput}\n onChange={e => setDInput(e.target.value)}\n onKeyDown={e => { if (e.key === 'Enter' && dInput === dWord) handleDClose(true); }}\n placeholder={dWord}\n className=\"mt-2 w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-red-500\"\n />\n </>\n )}\n </div>\n </div>\n </Dialog>\n\n {/* Prompt — windowed replacement for window.prompt() */}\n <Dialog\n open={pOpen}\n onClose={() => handlePClose(false)}\n title={pOptions.title || strings.promptTitle}\n footer={\n <>\n <button type=\"button\" onClick={() => handlePClose(false)} className={CANCEL_BTN}>\n {pOptions.cancelLabel || strings.cancel}\n </button>\n <button type=\"button\" onClick={() => handlePClose(true)}\n disabled={!pOptions.allowEmpty && !pInput.trim()}\n className=\"bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 text-sm font-medium rounded-lg disabled:opacity-40\">\n {pOptions.confirmLabel || strings.ok}\n </button>\n </>\n }\n >\n {pOptions.message && <p className=\"text-sm text-gray-600\">{pOptions.message}</p>}\n <input\n autoFocus\n type=\"text\"\n value={pInput}\n onChange={(e) => setPInput(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') handlePClose(true);\n else if (e.key === 'Escape') handlePClose(false);\n }}\n onFocus={(e) => e.target.select()}\n placeholder={pOptions.placeholder}\n className=\"mt-3 w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-blue-500 rosh-focus-ring focus-visible:ring-1 focus-visible:ring-[color:var(--rosh-focus-ring-accent)]\"\n />\n </Dialog>\n </ConfirmContext.Provider>\n );\n}\n"]}
@@ -1,8 +1,9 @@
1
1
  import { useShellAuth, navIcons } from './chunk-GA35NEND.js';
2
- import { isStaleChunkError, CMD_Z, CMD_SHIFT_Z, LoadingSpinner, Result, useIsMobile, useShellPrefs } from './chunk-G3HQLQYZ.js';
3
- import { Button_default } from './chunk-OKEFO6TI.js';
4
- import { useShellStrings, PopupMenu, PopupMenuItem, PopupMenuDivider, PopupMenuLabel } from './chunk-7KIOEKHS.js';
5
- import { Z_LAYERS, confirm, runEscapeInterceptors } from './chunk-HYZ5QMVO.js';
2
+ import { isStaleChunkError, CMD_Z, CMD_SHIFT_Z, LoadingSpinner, Result, useIsMobile, useShellPrefs } from './chunk-TQURTLK2.js';
3
+ import { Button_default } from './chunk-LQTVTOSY.js';
4
+ import { PopupMenu, PopupMenuItem, PopupMenuDivider, PopupMenuLabel } from './chunk-E3TWIN7Z.js';
5
+ import { Z_LAYERS, confirm, runEscapeInterceptors } from './chunk-XH3ELPQZ.js';
6
+ import { useShellStrings } from './chunk-7IN7YZAL.js';
6
7
  import { createContext, Component, useContext, useLayoutEffect, useRef, useEffect, useState, useCallback, useSyncExternalStore, useMemo, isValidElement, cloneElement, useReducer, useId, Suspense } from 'react';
7
8
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
8
9
  import { createPortal } from 'react-dom';
@@ -1262,7 +1263,7 @@ function CancelButton({ onClick, children, className }) {
1262
1263
  const ctx = useContext(ModalActionsContext);
1263
1264
  const handleClick = async () => {
1264
1265
  if (ctx?.isDirty) {
1265
- const { confirm: confirm2 } = await import('./ConfirmDialog-LJXMB45A.js');
1266
+ const { confirm: confirm2 } = await import('./ConfirmDialog-MTC7QMUJ.js');
1266
1267
  const ok = await confirm2({
1267
1268
  title: "Discard changes?",
1268
1269
  message: "You have unsaved changes. Are you sure you want to cancel? All changes will be lost.",
@@ -3705,5 +3706,5 @@ function useUndoableState(initial, opts) {
3705
3706
  }
3706
3707
 
3707
3708
  export { CancelButton, CopyButton, DocFavStar, EntityWindowFallback, EntityWindowLoading, EntityWindowState, LoadingSpinner2 as LoadingSpinner, MODAL_SUBMIT_SELECTOR, Modal, ModalActions, SIDEBAR_STRIP_W, UndoControls, UndoProvider, WINDOW_REGISTRY, WindowCrashedFallback, WindowErrorBoundary, WindowManagerProvider, WindowTitle, beginWindowGesture, cancelWindowFront, client_default, commitExposeHighlight, drainPerfEvents, exitExposeMode, forgetMaximizedWindowBoxes, getActiveModalId, getActiveWindowRoute, getExposeHighlight, getWindowPosition, isDraftEntityId, isDraftEntityWindow, isEntityEntry, isPageEntry, isShellApiClientConfigured, markMenuOpen, requestWindowFront, setExposeHighlight, setPerfCollecting, setShellApiClient, setShellWindowRegistry, setWindowDefaultPosition, setWindowPosition, subscribeExposeHighlight, toggleExposeMode, useEnclosingModalId, useIsActiveWindow, useModalActive, useUndo, useUndoCanEdit, useUndoable, useUndoableState, useWidgetSettings, useWindowDirty, useWindowManager, useWindowMenuItem, useWindowTitle };
3708
- //# sourceMappingURL=chunk-PPUZJFCI.js.map
3709
- //# sourceMappingURL=chunk-PPUZJFCI.js.map
3709
+ //# sourceMappingURL=chunk-ZKHD4J73.js.map
3710
+ //# sourceMappingURL=chunk-ZKHD4J73.js.map