react-os-shell 4.63.0 → 4.74.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 (64) hide show
  1. package/README.md +3 -0
  2. package/dist/{Browser-SPTNLEMR.js → Browser-ZF5X2FON.js} +7 -7
  3. package/dist/{Browser-SPTNLEMR.js.map → Browser-ZF5X2FON.js.map} +1 -1
  4. package/dist/{Calculator-XMOPPCK3.js → Calculator-SA62H5S3.js} +6 -6
  5. package/dist/{Calculator-XMOPPCK3.js.map → Calculator-SA62H5S3.js.map} +1 -1
  6. package/dist/ConfirmDialog-SREDNTIB.js +3 -0
  7. package/dist/{ConfirmDialog-EEH4CWSW.js.map → ConfirmDialog-SREDNTIB.js.map} +1 -1
  8. package/dist/{CurrencyConverter-24HNX6C6.js → CurrencyConverter-BMCRLZLY.js} +6 -6
  9. package/dist/{CurrencyConverter-24HNX6C6.js.map → CurrencyConverter-BMCRLZLY.js.map} +1 -1
  10. package/dist/{Documents-GMRVVCH7.js → Documents-2TGJPV2Y.js} +8 -8
  11. package/dist/{Documents-GMRVVCH7.js.map → Documents-2TGJPV2Y.js.map} +1 -1
  12. package/dist/{Files-ITH4SVML.js → Files-Z3ONKUA6.js} +9 -9
  13. package/dist/{Files-ITH4SVML.js.map → Files-Z3ONKUA6.js.map} +1 -1
  14. package/dist/{Notepad-GE5P55TL.js → Notepad-JWZS5YKJ.js} +8 -8
  15. package/dist/{Notepad-GE5P55TL.js.map → Notepad-JWZS5YKJ.js.map} +1 -1
  16. package/dist/{PomodoroTimer-ER5STVKM.js → PomodoroTimer-DRM5W25H.js} +8 -8
  17. package/dist/{PomodoroTimer-ER5STVKM.js.map → PomodoroTimer-DRM5W25H.js.map} +1 -1
  18. package/dist/{Preview-UXVDXCDJ.js → Preview-7O7W7OMQ.js} +9 -9
  19. package/dist/{Preview-UXVDXCDJ.js.map → Preview-7O7W7OMQ.js.map} +1 -1
  20. package/dist/{Spreadsheet-B32JQVX4.js → Spreadsheet-CLTZSW3T.js} +7 -7
  21. package/dist/{Spreadsheet-B32JQVX4.js.map → Spreadsheet-CLTZSW3T.js.map} +1 -1
  22. package/dist/{Stock-FSFPFDQT.js → Stock-CO5N3N2M.js} +6 -6
  23. package/dist/{Stock-FSFPFDQT.js.map → Stock-CO5N3N2M.js.map} +1 -1
  24. package/dist/{Weather-HXOERJJV.js → Weather-IEGJX7RI.js} +6 -6
  25. package/dist/{Weather-HXOERJJV.js.map → Weather-IEGJX7RI.js.map} +1 -1
  26. package/dist/{WorldClock-2FUGLIUZ.js → WorldClock-FLW3QZYG.js} +6 -6
  27. package/dist/{WorldClock-2FUGLIUZ.js.map → WorldClock-FLW3QZYG.js.map} +1 -1
  28. package/dist/apps/index.js +17 -17
  29. package/dist/{chunk-TK6HI2U4.js → chunk-2VM2FRZJ.js} +42 -11
  30. package/dist/chunk-2VM2FRZJ.js.map +1 -0
  31. package/dist/{chunk-ECE3B3FZ.js → chunk-AXWC3332.js} +3 -3
  32. package/dist/{chunk-ECE3B3FZ.js.map → chunk-AXWC3332.js.map} +1 -1
  33. package/dist/{chunk-ZCDFNZQS.js → chunk-BLLINYDD.js} +97 -5
  34. package/dist/chunk-BLLINYDD.js.map +1 -0
  35. package/dist/{chunk-OXLLRKBC.js → chunk-CDR2Q64Q.js} +38 -22
  36. package/dist/chunk-CDR2Q64Q.js.map +1 -0
  37. package/dist/{chunk-TO6ZZHJK.js → chunk-EG3WEQBH.js} +4 -4
  38. package/dist/{chunk-TO6ZZHJK.js.map → chunk-EG3WEQBH.js.map} +1 -1
  39. package/dist/{chunk-JMESET3G.js → chunk-G7IHPEJE.js} +138 -39
  40. package/dist/chunk-G7IHPEJE.js.map +1 -0
  41. package/dist/chunk-NJDH5PHA.js +7 -0
  42. package/dist/{chunk-WCGHIJZR.js.map → chunk-NJDH5PHA.js.map} +1 -1
  43. package/dist/{chunk-LYQVLRWQ.js → chunk-RUAZJ54W.js} +3 -3
  44. package/dist/{chunk-LYQVLRWQ.js.map → chunk-RUAZJ54W.js.map} +1 -1
  45. package/dist/{chunk-CWA27IGB.js → chunk-S6K37RLY.js} +781 -344
  46. package/dist/chunk-S6K37RLY.js.map +1 -0
  47. package/dist/{chunk-IOCOH2QQ.js → chunk-TT2WNTDS.js} +4 -4
  48. package/dist/{chunk-IOCOH2QQ.js.map → chunk-TT2WNTDS.js.map} +1 -1
  49. package/dist/{chunk-3OCL3DB4.js → chunk-TT56U4GY.js} +3 -3
  50. package/dist/{chunk-3OCL3DB4.js.map → chunk-TT56U4GY.js.map} +1 -1
  51. package/dist/{index-Ka32s3Ij.d.ts → index-DVekeidu.d.ts} +258 -27
  52. package/dist/index.d.ts +2 -2
  53. package/dist/index.js +121 -35
  54. package/dist/index.js.map +1 -1
  55. package/dist/ui/index.d.ts +1 -1
  56. package/dist/ui/index.js +5 -5
  57. package/package.json +2 -2
  58. package/dist/ConfirmDialog-EEH4CWSW.js +0 -3
  59. package/dist/chunk-CWA27IGB.js.map +0 -1
  60. package/dist/chunk-JMESET3G.js.map +0 -1
  61. package/dist/chunk-OXLLRKBC.js.map +0 -1
  62. package/dist/chunk-TK6HI2U4.js.map +0 -1
  63. package/dist/chunk-WCGHIJZR.js +0 -7
  64. package/dist/chunk-ZCDFNZQS.js.map +0 -1
@@ -1,5 +1,5 @@
1
- import { useIsMobile, useShellPrefs, PopupMenu, PopupMenuItem, PopupMenuDivider } from './chunk-ZCDFNZQS.js';
2
- import { confirm, runEscapeInterceptors } from './chunk-OXLLRKBC.js';
1
+ import { useShellStrings, useIsMobile, useShellPrefs, PopupMenu, PopupMenuItem, PopupMenuDivider } from './chunk-BLLINYDD.js';
2
+ import { confirm, runEscapeInterceptors } from './chunk-CDR2Q64Q.js';
3
3
  import { useShellAuth, navIcons } from './chunk-WNLPTLT6.js';
4
4
  import { createContext, Component, useContext, useRef, useLayoutEffect, useState, useEffect, useCallback, useSyncExternalStore, useMemo, isValidElement, cloneElement, useReducer, useId, Suspense } from 'react';
5
5
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
@@ -190,6 +190,7 @@ function PageWindow({ item, onClose, accentRgb }) {
190
190
  return /* @__PURE__ */ jsx(Modal, { open: true, onClose, icon: navIcons[item.route], title: entry.label, size: entry.size || "2xl", dirty, allowPinOnTop: entry.allowPinOnTop, initialPosition: entry.initialPosition, widget: entry.widget, compact: entry.compact, appStyle: entry.appStyle, flushBody: entry.flushBody, autoHeight: entry.autoHeight, autoMinHeight: entry.autoMinHeight, dimensions: entry.dimensions, windowKey: item.id, openedFromKey: item.openedFrom, accentRgb, children: /* @__PURE__ */ jsx(WindowDirtyContext.Provider, { value: registerDirty, children: /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsx(LoadingSpinner, {}) }), children: /* @__PURE__ */ jsx(Component2, {}) }) }) });
191
191
  }
192
192
  function DocFavStar({ entityType, entityId, label }) {
193
+ const shellStrings = useShellStrings();
193
194
  const queryClient = useQueryClient();
194
195
  const { data: profile } = useQuery({ queryKey: ["my-profile-sidebar"], enabled: isShellApiClientConfigured(), queryFn: () => client_default.get("/auth/me/").then((r) => r.data) });
195
196
  const favDocs = (profile?.preferences || {}).favorite_documents || [];
@@ -204,7 +205,7 @@ function DocFavStar({ entityType, entityId, label }) {
204
205
  "button",
205
206
  {
206
207
  onClick: toggle,
207
- title: isFav ? "Remove from desktop" : "Add to desktop",
208
+ title: isFav ? shellStrings.taskbar.removeFromDesktop : shellStrings.taskbar.addToDesktop,
208
209
  className: `shrink-0 transition-colors ${isFav ? "text-yellow-500 hover:text-yellow-600" : "text-gray-300 hover:text-yellow-400"}`,
209
210
  children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", fill: isFav ? "currentColor" : "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.563.563 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.563.563 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z" }) })
210
211
  }
@@ -331,6 +332,7 @@ function clearPeekFocus() {
331
332
  document.querySelectorAll("[data-modal-panel][data-peek-focus]").forEach((el) => el.removeAttribute("data-peek-focus"));
332
333
  }
333
334
  function ThumbCard({ id, label, maxW, maxH, titleAbove = false, onClick, onClose }) {
335
+ const shellStrings = useShellStrings();
334
336
  const previewRef = useRef(null);
335
337
  const [size, setSize] = useState({ w: maxW, h: Math.round(maxH * 0.75) });
336
338
  const [hasSnapshot, setHasSnapshot] = useState(false);
@@ -398,7 +400,7 @@ function ThumbCard({ id, label, maxW, maxH, titleAbove = false, onClick, onClose
398
400
  onClose();
399
401
  },
400
402
  className: "absolute top-1 right-1 z-20 h-5 w-5 rounded-full bg-gray-900/90 ring-1 ring-white/80 shadow-sm hover:bg-red-500 text-white flex items-center justify-center",
401
- title: "Close window",
403
+ title: shellStrings.taskbar.closeWindow,
402
404
  children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 3, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) })
403
405
  }
404
406
  )
@@ -407,6 +409,7 @@ function ThumbCard({ id, label, maxW, maxH, titleAbove = false, onClick, onClose
407
409
  );
408
410
  }
409
411
  function TaskbarTabPreview({ items, anchorEl, onActivate, onClose, onMouseEnter, onMouseLeave }) {
412
+ const shellStrings = useShellStrings();
410
413
  const MAX_W = 240;
411
414
  const MAX_H = 160;
412
415
  const isGroup = items.length > 1;
@@ -493,7 +496,7 @@ function TaskbarTabPreview({ items, anchorEl, onActivate, onClose, onMouseEnter,
493
496
  bearing !== null && /* @__PURE__ */ jsxs(
494
497
  "span",
495
498
  {
496
- title: "This window is off screen \u2014 click to bring it back",
499
+ title: shellStrings.taskbar.offscreenHint,
497
500
  className: "mt-1 inline-flex items-center gap-1 rounded bg-amber-500 px-1.5 py-0.5 text-[10px] font-semibold text-white shadow-sm",
498
501
  children: [
499
502
  /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", style: { transform: `rotate(${bearing}deg)` }, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 3, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 12h14m0 0l-5-5m5 5l-5 5" }) }),
@@ -512,6 +515,7 @@ function TaskbarTabPreview({ items, anchorEl, onActivate, onClose, onMouseEnter,
512
515
  );
513
516
  }
514
517
  function TaskbarWindows({ openWindows, onRemove, onSplitView, onActivate, onActivateById }) {
518
+ const shellStrings = useShellStrings();
515
519
  const [target, setTarget] = useState(null);
516
520
  useEffect(() => {
517
521
  const el = document.getElementById("taskbar-windows");
@@ -635,7 +639,7 @@ function TaskbarWindows({ openWindows, onRemove, onSplitView, onActivate, onActi
635
639
  children: [
636
640
  icon && isValidElement(icon) ? cloneElement(icon, { className: `h-3.5 w-3.5 shrink-0 ${isActive ? "text-blue-600" : "text-gray-400"}` }) : /* @__PURE__ */ jsx("svg", { className: `h-3.5 w-3.5 shrink-0 ${isActive ? "text-blue-600" : "text-gray-400"}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4" }) }),
637
641
  /* @__PURE__ */ jsx("span", { className: "truncate flex-1", children: isGrouped ? group.label : liveTitle(primary.label) }),
638
- offscreen && /* @__PURE__ */ jsx("span", { title: "Off screen \u2014 click to bring this window back", className: "shrink-0 h-1.5 w-1.5 rounded-full bg-amber-500" }),
642
+ offscreen && /* @__PURE__ */ jsx("span", { title: shellStrings.taskbar.offscreenDot, className: "shrink-0 h-1.5 w-1.5 rounded-full bg-amber-500" }),
639
643
  isGrouped && /* @__PURE__ */ jsx("span", { className: "shrink-0 px-1.5 py-0.5 rounded-full bg-blue-500/80 text-white text-[10px] font-bold leading-none", children: group.items.length }),
640
644
  !isGrouped && /* @__PURE__ */ jsx("span", { role: "button", onClick: (e) => {
641
645
  e.stopPropagation();
@@ -651,7 +655,7 @@ function TaskbarWindows({ openWindows, onRemove, onSplitView, onActivate, onActi
651
655
  "button",
652
656
  {
653
657
  onClick: onSplitView,
654
- title: "Expos\xE9 \u2014 show all open windows as thumbnails",
658
+ title: shellStrings.taskbar.expose,
655
659
  className: "flex items-center gap-1 rounded px-2 py-1 text-[11px] font-medium text-blue-600 border border-blue-300 hover:bg-blue-50 transition-colors shrink-0",
656
660
  children: [
657
661
  /* @__PURE__ */ jsxs("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: [
@@ -1111,7 +1115,7 @@ function CancelButton({ onClick, children, className }) {
1111
1115
  const ctx = useContext(ModalActionsContext);
1112
1116
  const handleClick = async () => {
1113
1117
  if (ctx?.isDirty) {
1114
- const { confirm: confirm2 } = await import('./ConfirmDialog-EEH4CWSW.js');
1118
+ const { confirm: confirm2 } = await import('./ConfirmDialog-SREDNTIB.js');
1115
1119
  const ok = await confirm2({
1116
1120
  title: "Discard changes?",
1117
1121
  message: "You have unsaved changes. Are you sure you want to cancel? All changes will be lost.",
@@ -1450,6 +1454,73 @@ function hideSnapPreview() {
1450
1454
  snapPreviewEl.style.opacity = "0";
1451
1455
  snapPreviewEl.style.display = "none";
1452
1456
  }
1457
+ var SNAP_PICKER_ZONES = [
1458
+ { zone: "left", labelKey: "snapLeft", region: "inset-y-0 left-0 w-1/2" },
1459
+ { zone: "right", labelKey: "snapRight", region: "inset-y-0 right-0 w-1/2" },
1460
+ { zone: "tl", labelKey: "snapTopLeft", region: "top-0 left-0 h-1/2 w-1/2" },
1461
+ { zone: "tr", labelKey: "snapTopRight", region: "top-0 right-0 h-1/2 w-1/2" },
1462
+ { zone: "bl", labelKey: "snapBottomLeft", region: "bottom-0 left-0 h-1/2 w-1/2" },
1463
+ { zone: "br", labelKey: "snapBottomRight", region: "bottom-0 right-0 h-1/2 w-1/2" }
1464
+ ];
1465
+ var SNAP_PICKER_OPEN_MS = 350;
1466
+ var SNAP_PICKER_CLOSE_MS = 200;
1467
+ function SnapLayoutsButton({ maximized, onToggleMax, onSnap, buttonClassName, strings }) {
1468
+ const [open, setOpen] = useState(false);
1469
+ const openTimer = useRef(void 0);
1470
+ const closeTimer = useRef(void 0);
1471
+ useEffect(() => () => {
1472
+ clearTimeout(openTimer.current);
1473
+ clearTimeout(closeTimer.current);
1474
+ }, []);
1475
+ const armOpen = () => {
1476
+ clearTimeout(closeTimer.current);
1477
+ openTimer.current = setTimeout(() => setOpen(true), SNAP_PICKER_OPEN_MS);
1478
+ };
1479
+ const armClose = () => {
1480
+ clearTimeout(openTimer.current);
1481
+ closeTimer.current = setTimeout(() => setOpen(false), SNAP_PICKER_CLOSE_MS);
1482
+ };
1483
+ return /* @__PURE__ */ jsxs("span", { className: "relative inline-flex", onMouseEnter: armOpen, onMouseLeave: armClose, children: [
1484
+ /* @__PURE__ */ jsx(
1485
+ "button",
1486
+ {
1487
+ onClick: onToggleMax,
1488
+ onFocus: armOpen,
1489
+ onBlur: armClose,
1490
+ title: maximized ? strings.windowed : strings.maximize,
1491
+ className: buttonClassName,
1492
+ children: maximized ? "\u2750" : "\u2922"
1493
+ }
1494
+ ),
1495
+ open && /* @__PURE__ */ jsx(
1496
+ "div",
1497
+ {
1498
+ role: "group",
1499
+ "aria-label": strings.snapLayouts,
1500
+ onMouseEnter: () => clearTimeout(closeTimer.current),
1501
+ onMouseLeave: armClose,
1502
+ className: "absolute right-0 top-full z-30 mt-1 grid w-max grid-cols-2 gap-1 rounded-lg border border-gray-200 bg-white p-1.5 shadow-lg",
1503
+ children: SNAP_PICKER_ZONES.map(({ zone, labelKey, region }) => /* @__PURE__ */ jsx(
1504
+ "button",
1505
+ {
1506
+ type: "button",
1507
+ "aria-label": strings[labelKey],
1508
+ title: strings[labelKey],
1509
+ onClick: () => {
1510
+ setOpen(false);
1511
+ onSnap(zone);
1512
+ },
1513
+ onFocus: () => clearTimeout(closeTimer.current),
1514
+ onBlur: armClose,
1515
+ className: "relative h-7 w-11 rounded border border-gray-300 bg-gray-50 hover:border-blue-400 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-400",
1516
+ children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: `absolute rounded-sm bg-blue-500/70 ${region}`, style: { margin: 2 } })
1517
+ },
1518
+ zone
1519
+ ))
1520
+ }
1521
+ )
1522
+ ] });
1523
+ }
1453
1524
  var GESTURE_STYLE_ID = "rosh-gesture-style";
1454
1525
  function ensureGestureStyle() {
1455
1526
  if (typeof document === "undefined" || document.getElementById(GESTURE_STYLE_ID)) return;
@@ -1747,6 +1818,8 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
1747
1818
  };
1748
1819
  }, [swipeDragging]);
1749
1820
  const [displayTitle, setDisplayTitle] = useState(title);
1821
+ const shellStrings = useShellStrings();
1822
+ const winStr = shellStrings.window;
1750
1823
  useEffect(() => {
1751
1824
  setDisplayTitle(title);
1752
1825
  }, [title]);
@@ -2423,10 +2496,18 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
2423
2496
  boxRef.current = next;
2424
2497
  setBox(next);
2425
2498
  }, [modalId, maximized, calcWindowed, calcMaximized]);
2499
+ const applySnapZone = useCallback((zone) => {
2500
+ if (!preSnapBoxRef.current) preSnapBoxRef.current = { ...boxRef.current };
2501
+ setMaximized(false);
2502
+ const snapped = calcSnapBox(zone);
2503
+ boxRef.current = snapped;
2504
+ setBox(snapped);
2505
+ activateModal(modalId);
2506
+ }, [modalId]);
2426
2507
  const titleBarKeyProps = alwaysMaximized || exposeActive ? {} : {
2427
2508
  tabIndex: 0,
2428
2509
  role: "group",
2429
- "aria-label": titleTooltip ? `${titleTooltip} \u2014 window` : "Window",
2510
+ "aria-label": titleTooltip ? `${titleTooltip} \u2014 ${winStr.windowSuffix}` : winStr.windowSuffix,
2430
2511
  "aria-keyshortcuts": "ArrowUp ArrowDown ArrowLeft ArrowRight Shift+ArrowUp Shift+ArrowDown Shift+ArrowLeft Shift+ArrowRight Control+ArrowUp Control+ArrowDown Control+ArrowLeft Control+ArrowRight Enter",
2431
2512
  onKeyDown: onTitleBarKeyDown
2432
2513
  };
@@ -2689,7 +2770,7 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
2689
2770
  "button",
2690
2771
  {
2691
2772
  onClick: () => setPinnedOnTop((p) => !p),
2692
- title: pinnedOnTop ? "Unpin from top" : "Pin on top",
2773
+ title: pinnedOnTop ? winStr.unpin : winStr.pinOnTop,
2693
2774
  className: `p-0.5 rounded hover:bg-gray-200 ${pinnedOnTop ? "text-blue-600" : "text-gray-400 hover:text-gray-600"}`,
2694
2775
  children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: pinnedOnTop ? "currentColor" : "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16.5 3.75V16.5L12 14.25 7.5 16.5V3.75m9 0H18A2.25 2.25 0 0120.25 6v12A2.25 2.25 0 0118 20.25H6A2.25 2.25 0 013.75 18V6A2.25 2.25 0 016 3.75h1.5m9 0h-9" }) })
2695
2776
  }
@@ -2719,20 +2800,29 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
2719
2800
  "button",
2720
2801
  {
2721
2802
  onClick: () => setPinnedOnTop((p) => !p),
2722
- title: pinnedOnTop ? "Unpin from top" : "Pin on top",
2803
+ title: pinnedOnTop ? winStr.unpin : winStr.pinOnTop,
2723
2804
  className: `p-0.5 rounded hover:bg-gray-200 ${pinnedOnTop ? "text-blue-600" : "text-gray-400 hover:text-gray-600"}`,
2724
2805
  children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: pinnedOnTop ? "currentColor" : "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16.5 3.75V16.5L12 14.25 7.5 16.5V3.75m9 0H18A2.25 2.25 0 0120.25 6v12A2.25 2.25 0 0118 20.25H6A2.25 2.25 0 013.75 18V6A2.25 2.25 0 016 3.75h1.5m9 0h-9" }) })
2725
2806
  }
2726
2807
  ),
2727
- /* @__PURE__ */ jsx("button", { onClick: () => _minimizeModal(modalId), title: "Minimize", className: "text-gray-400 hover:text-gray-600 px-1 py-0.5 rounded hover:bg-gray-200 text-xs leading-none", children: "\u2500" }),
2728
- !alwaysMaximized && /* @__PURE__ */ jsx("button", { onClick: () => {
2729
- if (maximized) {
2730
- setMaximized(false);
2731
- setBox(calcWindowed());
2732
- } else {
2733
- reset();
2808
+ /* @__PURE__ */ jsx("button", { onClick: () => _minimizeModal(modalId), title: winStr.minimize, className: "text-gray-400 hover:text-gray-600 px-1 py-0.5 rounded hover:bg-gray-200 text-xs leading-none", children: "\u2500" }),
2809
+ !alwaysMaximized && /* @__PURE__ */ jsx(
2810
+ SnapLayoutsButton,
2811
+ {
2812
+ maximized,
2813
+ onToggleMax: () => {
2814
+ if (maximized) {
2815
+ setMaximized(false);
2816
+ setBox(calcWindowed());
2817
+ } else {
2818
+ reset();
2819
+ }
2820
+ },
2821
+ onSnap: applySnapZone,
2822
+ buttonClassName: "text-gray-400 hover:text-gray-600 px-1 py-0.5 rounded hover:bg-gray-200 text-xs leading-none",
2823
+ strings: winStr
2734
2824
  }
2735
- }, title: maximized ? "Windowed" : "Maximize", className: "text-gray-400 hover:text-gray-600 px-1 py-0.5 rounded hover:bg-gray-200 text-xs leading-none", children: maximized ? "\u2750" : "\u2922" }),
2825
+ ),
2736
2826
  /* @__PURE__ */ jsx("button", { type: "button", onClick: guardedClose, className: "rounded p-0.5 text-gray-400 hover:text-gray-600 hover:bg-gray-200", children: /* @__PURE__ */ jsx(XMarkIcon, { className: "h-4 w-4" }) })
2737
2827
  ] })
2738
2828
  ]
@@ -2754,28 +2844,37 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
2754
2844
  !exposeActive && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 shrink-0 ml-4", children: [
2755
2845
  hasNav && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 mr-1 text-[10px] text-gray-400", children: [
2756
2846
  /* @__PURE__ */ jsx("kbd", { className: "rounded border border-gray-300 bg-gray-200 px-1.5 py-0.5 font-medium text-gray-500", children: "K" }),
2757
- /* @__PURE__ */ jsx("span", { children: "Prev" }),
2847
+ /* @__PURE__ */ jsx("span", { children: winStr.prev }),
2758
2848
  /* @__PURE__ */ jsx("kbd", { className: "rounded border border-gray-300 bg-gray-200 px-1.5 py-0.5 font-medium ml-1 text-gray-500", children: "J" }),
2759
- /* @__PURE__ */ jsx("span", { children: "Next" })
2849
+ /* @__PURE__ */ jsx("span", { children: winStr.next })
2760
2850
  ] }),
2761
2851
  allowPinOnTop && /* @__PURE__ */ jsx(
2762
2852
  "button",
2763
2853
  {
2764
2854
  onClick: () => setPinnedOnTop((p) => !p),
2765
- title: pinnedOnTop ? "Unpin from top" : "Pin on top",
2855
+ title: pinnedOnTop ? winStr.unpin : winStr.pinOnTop,
2766
2856
  className: `text-xs px-2 py-1 rounded hover:bg-gray-200 ${pinnedOnTop ? "text-blue-600" : "text-gray-400 hover:text-gray-600"}`,
2767
2857
  children: /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: pinnedOnTop ? "currentColor" : "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16.5 3.75V16.5L12 14.25 7.5 16.5V3.75m9 0H18A2.25 2.25 0 0120.25 6v12A2.25 2.25 0 0118 20.25H6A2.25 2.25 0 013.75 18V6A2.25 2.25 0 016 3.75h1.5m9 0h-9" }) })
2768
2858
  }
2769
2859
  ),
2770
- /* @__PURE__ */ jsx("button", { onClick: () => _minimizeModal(modalId), title: "Minimize", className: "text-gray-400 hover:text-gray-600 text-xs px-2 py-1 rounded hover:bg-gray-200", children: "\u2500" }),
2771
- !alwaysMaximized && /* @__PURE__ */ jsx("button", { onClick: () => {
2772
- if (maximized) {
2773
- setMaximized(false);
2774
- setBox(calcWindowed());
2775
- } else {
2776
- reset();
2860
+ /* @__PURE__ */ jsx("button", { onClick: () => _minimizeModal(modalId), title: winStr.minimize, className: "text-gray-400 hover:text-gray-600 text-xs px-2 py-1 rounded hover:bg-gray-200", children: "\u2500" }),
2861
+ !alwaysMaximized && /* @__PURE__ */ jsx(
2862
+ SnapLayoutsButton,
2863
+ {
2864
+ maximized,
2865
+ onToggleMax: () => {
2866
+ if (maximized) {
2867
+ setMaximized(false);
2868
+ setBox(calcWindowed());
2869
+ } else {
2870
+ reset();
2871
+ }
2872
+ },
2873
+ onSnap: applySnapZone,
2874
+ buttonClassName: "text-gray-400 hover:text-gray-600 text-xs px-2 py-1 rounded hover:bg-gray-200",
2875
+ strings: winStr
2777
2876
  }
2778
- }, title: maximized ? "Windowed" : "Maximize", className: "text-gray-400 hover:text-gray-600 text-xs px-2 py-1 rounded hover:bg-gray-200", children: maximized ? "\u2750" : "\u2922" }),
2877
+ ),
2779
2878
  /* @__PURE__ */ jsx("kbd", { className: "rounded border border-gray-300 bg-gray-200 px-1.5 py-0.5 text-[10px] font-medium text-gray-400", children: "ESC" }),
2780
2879
  /* @__PURE__ */ jsx("button", { type: "button", onClick: guardedClose, className: "rounded-md text-gray-400 hover:text-gray-600", children: /* @__PURE__ */ jsx(XMarkIcon, { className: "h-5 w-5" }) })
2781
2880
  ] })
@@ -2878,7 +2977,7 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
2878
2977
  {
2879
2978
  type: "button",
2880
2979
  "data-expose-close": true,
2881
- "aria-label": "Close window",
2980
+ "aria-label": shellStrings.taskbar.closeWindow,
2882
2981
  title: "Close",
2883
2982
  className: "absolute flex items-center justify-center rounded-full bg-black/55 text-white shadow-lg ring-1 ring-white/40 transition-colors hover:bg-red-500",
2884
2983
  style: {
@@ -2932,7 +3031,7 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
2932
3031
  setWindowMenu(null);
2933
3032
  }, children: [
2934
3033
  /* @__PURE__ */ jsx("svg", { className: "h-4 w-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19.5 12h-15" }) }),
2935
- "Minimize"
3034
+ winStr.minimize
2936
3035
  ] }),
2937
3036
  !alwaysMaximized && (maximized ? /* @__PURE__ */ jsxs(PopupMenuItem, { onClick: () => {
2938
3037
  setMaximized(false);
@@ -2940,13 +3039,13 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
2940
3039
  setWindowMenu(null);
2941
3040
  }, children: [
2942
3041
  /* @__PURE__ */ jsx("svg", { className: "h-4 w-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 4.5v15m6-15v15M4.5 9h15M4.5 15h15" }) }),
2943
- "Windowed"
3042
+ winStr.windowed
2944
3043
  ] }) : /* @__PURE__ */ jsxs(PopupMenuItem, { onClick: () => {
2945
3044
  reset();
2946
3045
  setWindowMenu(null);
2947
3046
  }, children: [
2948
3047
  /* @__PURE__ */ jsx("svg", { className: "h-4 w-4 text-gray-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15" }) }),
2949
- "Maximize"
3048
+ winStr.maximize
2950
3049
  ] }))
2951
3050
  ] }),
2952
3051
  allowPinOnTop && /* @__PURE__ */ jsxs(PopupMenuItem, { onClick: () => {
@@ -2954,14 +3053,14 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
2954
3053
  setWindowMenu(null);
2955
3054
  }, children: [
2956
3055
  /* @__PURE__ */ jsx("svg", { className: `h-4 w-4 ${pinnedOnTop ? "text-blue-600" : "text-gray-400"}`, fill: pinnedOnTop ? "currentColor" : "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16.5 3.75V16.5L12 14.25 7.5 16.5V3.75m9 0H18A2.25 2.25 0 0120.25 6v12A2.25 2.25 0 0118 20.25H6A2.25 2.25 0 013.75 18V6A2.25 2.25 0 016 3.75h1.5m9 0h-9" }) }),
2957
- pinnedOnTop ? "Unpin from Top" : "Pin on Top"
3056
+ pinnedOnTop ? winStr.unpin : winStr.pinOnTop
2958
3057
  ] }),
2959
3058
  shortcutSpec && /* @__PURE__ */ jsxs(PopupMenuItem, { onClick: () => {
2960
3059
  setWindowMenu(null);
2961
3060
  toggleDesktopShortcut();
2962
3061
  }, children: [
2963
3062
  /* @__PURE__ */ jsx("svg", { className: `h-4 w-4 ${isOnDesktop ? "text-yellow-500" : "text-gray-400"}`, fill: isOnDesktop ? "currentColor" : "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.563.563 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.563.563 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z" }) }),
2964
- isOnDesktop ? "Remove from Desktop" : "Add to Desktop"
3063
+ isOnDesktop ? shellStrings.taskbar.removeFromDesktop : shellStrings.taskbar.addToDesktop
2965
3064
  ] }),
2966
3065
  (_extraMenuItems[modalId] || []).length > 0 && /* @__PURE__ */ jsx(Fragment, { children: (_extraMenuItems[modalId] || []).map((item, i) => /* @__PURE__ */ jsxs(PopupMenuItem, { onClick: () => {
2967
3066
  setWindowMenu(null);
@@ -2976,7 +3075,7 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
2976
3075
  guardedClose();
2977
3076
  }, children: [
2978
3077
  /* @__PURE__ */ jsx(XMarkIcon, { className: "h-4 w-4" }),
2979
- "Close"
3078
+ winStr.close
2980
3079
  ] })
2981
3080
  ] });
2982
3081
  return createPortal(
@@ -3200,5 +3299,5 @@ function useUndoableState(initial, opts) {
3200
3299
  }
3201
3300
 
3202
3301
  export { CancelButton, CopyButton, DocFavStar, LoadingSpinner, Modal, ModalActions, SIDEBAR_STRIP_W, UndoProvider, WINDOW_REGISTRY, WindowCrashedFallback, WindowErrorBoundary, WindowManagerProvider, WindowTitle, beginWindowGesture, cancelWindowFront, client_default, commitExposeHighlight, drainPerfEvents, exitExposeMode, forgetMaximizedWindowBoxes, getActiveModalId, getActiveWindowRoute, getExposeHighlight, getWindowPosition, isEntityEntry, isPageEntry, isShellApiClientConfigured, markMenuOpen, requestWindowFront, setExposeHighlight, setPerfCollecting, setShellApiClient, setShellWindowRegistry, setWindowDefaultPosition, setWindowPosition, subscribeExposeHighlight, toggleExposeMode, useEnclosingModalId, useIsActiveWindow, useModalActive, useUndo, useUndoable, useUndoableState, useWidgetSettings, useWindowDirty, useWindowManager, useWindowMenuItem, useWindowTitle };
3203
- //# sourceMappingURL=chunk-JMESET3G.js.map
3204
- //# sourceMappingURL=chunk-JMESET3G.js.map
3302
+ //# sourceMappingURL=chunk-G7IHPEJE.js.map
3303
+ //# sourceMappingURL=chunk-G7IHPEJE.js.map