react-os-shell 0.2.2 → 0.2.20

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 (43) hide show
  1. package/dist/{Browser-IAQ5N3LL.js → Browser-RJZLTAJQ.js} +3 -3
  2. package/dist/{Browser-IAQ5N3LL.js.map → Browser-RJZLTAJQ.js.map} +1 -1
  3. package/dist/{Calculator-7MIONNJK.js → Calculator-DMROKOY2.js} +4 -4
  4. package/dist/{Calculator-7MIONNJK.js.map → Calculator-DMROKOY2.js.map} +1 -1
  5. package/dist/{Calendar-2R2DWXTG.js → Calendar-24TAKCAJ.js} +3 -3
  6. package/dist/{Calendar-2R2DWXTG.js.map → Calendar-24TAKCAJ.js.map} +1 -1
  7. package/dist/{CurrencyConverter-BMTB7FLA.js → CurrencyConverter-KMBBKLHZ.js} +4 -4
  8. package/dist/{CurrencyConverter-BMTB7FLA.js.map → CurrencyConverter-KMBBKLHZ.js.map} +1 -1
  9. package/dist/{Documents-CBNJAM3Q.js → Documents-QMP6QN3C.js} +3 -3
  10. package/dist/{Documents-CBNJAM3Q.js.map → Documents-QMP6QN3C.js.map} +1 -1
  11. package/dist/{Email-BS6MESSZ.js → Email-XTFUEIE5.js} +3 -3
  12. package/dist/{Email-BS6MESSZ.js.map → Email-XTFUEIE5.js.map} +1 -1
  13. package/dist/Files-GMIYQPAA.js +7 -0
  14. package/dist/{Files-U3BSTCC3.js.map → Files-GMIYQPAA.js.map} +1 -1
  15. package/dist/{Minesweeper-XOSH6BW2.js → Minesweeper-YPAR6SPJ.js} +3 -3
  16. package/dist/{Minesweeper-XOSH6BW2.js.map → Minesweeper-YPAR6SPJ.js.map} +1 -1
  17. package/dist/{Notepad-DMSBGGMS.js → Notepad-VEEUZROP.js} +3 -3
  18. package/dist/{Notepad-DMSBGGMS.js.map → Notepad-VEEUZROP.js.map} +1 -1
  19. package/dist/{PomodoroTimer-3XLLIDV3.js → PomodoroTimer-HWHMQZO6.js} +4 -4
  20. package/dist/{PomodoroTimer-3XLLIDV3.js.map → PomodoroTimer-HWHMQZO6.js.map} +1 -1
  21. package/dist/Preview-Z447TOCE.js +6 -0
  22. package/dist/{Preview-Y2LMO2DL.js.map → Preview-Z447TOCE.js.map} +1 -1
  23. package/dist/{Spreadsheet-IRPGCABR.js → Spreadsheet-W76QOD42.js} +3 -3
  24. package/dist/{Spreadsheet-IRPGCABR.js.map → Spreadsheet-W76QOD42.js.map} +1 -1
  25. package/dist/{Weather-5IW43PAQ.js → Weather-DIKN7BOT.js} +4 -4
  26. package/dist/{Weather-5IW43PAQ.js.map → Weather-DIKN7BOT.js.map} +1 -1
  27. package/dist/apps/index.js +16 -16
  28. package/dist/{chunk-IQV6QQBQ.js → chunk-4J466VCS.js} +3 -3
  29. package/dist/{chunk-IQV6QQBQ.js.map → chunk-4J466VCS.js.map} +1 -1
  30. package/dist/{chunk-JEJHECSO.js → chunk-7ZUE7PEH.js} +4 -4
  31. package/dist/{chunk-JEJHECSO.js.map → chunk-7ZUE7PEH.js.map} +1 -1
  32. package/dist/{chunk-DIJ46HNS.js → chunk-HVZUPS3P.js} +3 -3
  33. package/dist/{chunk-DIJ46HNS.js.map → chunk-HVZUPS3P.js.map} +1 -1
  34. package/dist/{chunk-7P6DO3NC.js → chunk-QXY6ZHRX.js} +73 -35
  35. package/dist/chunk-QXY6ZHRX.js.map +1 -0
  36. package/dist/index.d.ts +19 -3
  37. package/dist/index.js +124 -113
  38. package/dist/index.js.map +1 -1
  39. package/dist/styles.css +11 -0
  40. package/package.json +1 -1
  41. package/dist/Files-U3BSTCC3.js +0 -7
  42. package/dist/Preview-Y2LMO2DL.js +0 -6
  43. package/dist/chunk-7P6DO3NC.js.map +0 -1
@@ -69,14 +69,26 @@ var _apiClient = null;
69
69
  function setShellApiClient(instance) {
70
70
  _apiClient = instance;
71
71
  }
72
+ function isShellApiClientConfigured() {
73
+ return _apiClient !== null;
74
+ }
75
+ var NOOP_METHODS = /* @__PURE__ */ new Set([
76
+ "get",
77
+ "post",
78
+ "put",
79
+ "patch",
80
+ "delete",
81
+ "head",
82
+ "options",
83
+ "request"
84
+ ]);
72
85
  var apiClient = new Proxy({}, {
73
86
  get(_t, prop) {
74
- if (!_apiClient) {
75
- throw new Error(
76
- `react-os-shell: apiClient.${String(prop)}() called before setShellApiClient(). Wire your axios instance once at app startup.`
77
- );
87
+ if (_apiClient) return _apiClient[prop];
88
+ if (typeof prop === "string" && NOOP_METHODS.has(prop)) {
89
+ return () => Promise.resolve({ data: null, status: 0, statusText: "", headers: {}, config: {} });
78
90
  }
79
- return _apiClient[prop];
91
+ return void 0;
80
92
  }
81
93
  });
82
94
  var client_default = apiClient;
@@ -117,7 +129,7 @@ function glassStyle(opacity) {
117
129
  };
118
130
  }
119
131
  var GLASS_DIVIDER = "border-white/20";
120
- var GLASS_INPUT_BG = "bg-white/15";
132
+ var GLASS_INPUT_BG = "glass-input-bg";
121
133
  function getDensity() {
122
134
  return getComputedStyle(document.documentElement).getPropertyValue("--menu-density")?.trim() || "normal";
123
135
  }
@@ -261,21 +273,21 @@ function useIsMobile() {
261
273
  return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
262
274
  }
263
275
 
264
- // src/shell/mobileShellStore.ts
265
- var _mode = "home";
266
- var listeners = /* @__PURE__ */ new Set();
267
- function getMobileMode() {
268
- return _mode;
276
+ // src/shell/mobileSwipeStore.ts
277
+ var _parentKey = null;
278
+ var subs = /* @__PURE__ */ new Set();
279
+ function getSwipingParentKey() {
280
+ return _parentKey;
269
281
  }
270
- function setMobileMode(mode) {
271
- if (_mode === mode) return;
272
- _mode = mode;
273
- listeners.forEach((fn) => fn());
282
+ function setSwipingParentKey(key) {
283
+ if (_parentKey === key) return;
284
+ _parentKey = key;
285
+ for (const cb of subs) cb();
274
286
  }
275
- function subscribeMobileMode(cb) {
276
- listeners.add(cb);
287
+ function subscribeSwipingParentKey(cb) {
288
+ subs.add(cb);
277
289
  return () => {
278
- listeners.delete(cb);
290
+ subs.delete(cb);
279
291
  };
280
292
  }
281
293
  var ModalIdContext = createContext("");
@@ -547,7 +559,7 @@ function useIsActiveModal(modalId) {
547
559
  function triggerSplitView() {
548
560
  window.dispatchEvent(new CustomEvent("modal-split-view"));
549
561
  }
550
- function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = false, onNext, onPrev, footer, bodyScroll, onMinimize, initialBox, actions, actionsLeft, allowPinOnTop, initialPosition, widget, compact, appStyle, autoHeight, autoMinHeight, widgetMenu, dimensions, windowKey, children }) {
562
+ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = false, onNext, onPrev, footer, bodyScroll, onMinimize, initialBox, actions, actionsLeft, allowPinOnTop, initialPosition, widget, compact, appStyle, autoHeight, autoMinHeight, widgetMenu, dimensions, windowKey, openedFromKey, children }) {
551
563
  const isMobile = useIsMobile();
552
564
  const [swipeX, setSwipeX] = useState(0);
553
565
  const [swipeDragging, setSwipeDragging] = useState(false);
@@ -560,7 +572,9 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
560
572
  if (!isMobile) return;
561
573
  swipeStartRef.current = { startX: e.clientX, startY: e.clientY, pointerId: e.pointerId };
562
574
  setSwipeDragging(true);
563
- }, [isMobile]);
575
+ setSwipingParentKey(openedFromKey ?? null);
576
+ }, [isMobile, openedFromKey]);
577
+ const swipingParentKey = useSyncExternalStore(subscribeSwipingParentKey, getSwipingParentKey);
564
578
  useEffect(() => {
565
579
  if (!swipeDragging) return;
566
580
  const onMove = (ev) => {
@@ -571,6 +585,7 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
571
585
  swipeStartRef.current = null;
572
586
  setSwipeDragging(false);
573
587
  setSwipeX(0);
588
+ setSwipingParentKey(null);
574
589
  return;
575
590
  }
576
591
  setSwipeX(Math.max(0, dx));
@@ -584,11 +599,13 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
584
599
  if (past) {
585
600
  setSwipeX(window.innerWidth);
586
601
  setTimeout(() => {
587
- setMobileMode("home");
602
+ onClose();
588
603
  setSwipeX(0);
604
+ setSwipingParentKey(null);
589
605
  }, 180);
590
606
  } else {
591
607
  setSwipeX(0);
608
+ setSwipingParentKey(null);
592
609
  }
593
610
  };
594
611
  window.addEventListener("pointermove", onMove);
@@ -1132,7 +1149,12 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
1132
1149
  },
1133
1150
  style: isMobile ? {
1134
1151
  // Mobile fullscreen: ignore stored box, fill viewport down to bottom
1135
- // nav. Widgets stay hidden on mobile.
1152
+ // nav. Widgets stay hidden on mobile. Only the active window is
1153
+ // visible — all others hidden so swipe-right reveals the home
1154
+ // wallpaper backdrop. Exception: when a sibling Modal is being
1155
+ // swiped to-back and we're its `openedFrom` parent, un-hide so the
1156
+ // user sees their parent list during the slide instead of just the
1157
+ // wallpaper.
1136
1158
  zIndex: zIndex + 1,
1137
1159
  top: 0,
1138
1160
  left: 0,
@@ -1143,14 +1165,18 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
1143
1165
  transform: `translateX(${swipeX}px)`,
1144
1166
  transition: swipeDragging ? "none" : "transform 180ms ease-out",
1145
1167
  ...widget ? { display: "none" } : {},
1146
- ...zIndex < 0 ? { display: "none" } : {}
1168
+ ...zIndex < 0 ? { display: "none" } : {},
1169
+ ...!isActive && !pinnedOnTop && !(swipingParentKey && windowKey === swipingParentKey) ? { display: "none" } : {}
1147
1170
  } : {
1148
1171
  zIndex: pinnedOnTop ? 999 : zIndex + 1,
1149
1172
  width: box.w,
1150
1173
  height: autoHeight ? "auto" : box.h,
1151
1174
  top: box.y,
1152
1175
  ...autoHeight ? {
1153
- minHeight: `${autoMinHeight ?? 240}px`,
1176
+ // Widgets must fit content exactly (Weather, Currency, etc.) —
1177
+ // the 240 px floor only applies to non-widget app windows where
1178
+ // a near-empty body would look broken.
1179
+ minHeight: `${autoMinHeight ?? (widget ? 0 : 240)}px`,
1154
1180
  maxHeight: `calc(100vh - var(--taskbar-height, 0px) - 24px)`
1155
1181
  } : {},
1156
1182
  ...widget && widgetAnchor === "right" ? { right: window.innerWidth - box.x - box.w } : { left: box.x },
@@ -1434,7 +1460,7 @@ function useWindowManager() {
1434
1460
  }
1435
1461
  function DesktopShortcutMenuItem({ item }) {
1436
1462
  const queryClient = useQueryClient();
1437
- const { data: profile } = useQuery({ queryKey: ["my-profile-sidebar"], queryFn: () => client_default.get("/auth/me/").then((r) => r.data) });
1463
+ const { data: profile } = useQuery({ queryKey: ["my-profile-sidebar"], enabled: isShellApiClientConfigured(), queryFn: () => client_default.get("/auth/me/").then((r) => r.data) });
1438
1464
  const favDocs = (profile?.preferences || {}).favorite_documents || [];
1439
1465
  const favType = item.type === "page" ? "page" : item.entityType || "";
1440
1466
  const favId = item.type === "page" ? item.route || "" : item.entityId || "";
@@ -1454,14 +1480,14 @@ function PageWindow({ item, onClose }) {
1454
1480
  if (!raw || !isPageEntry(raw)) return null;
1455
1481
  const entry = raw;
1456
1482
  const Component = entry.component;
1457
- return /* @__PURE__ */ jsxs(Modal, { open: true, onClose, icon: navIcons[item.route], title: entry.label, size: entry.size || "2xl", allowPinOnTop: entry.allowPinOnTop, initialPosition: entry.initialPosition, widget: entry.widget, compact: entry.compact, appStyle: entry.appStyle, autoHeight: entry.autoHeight, autoMinHeight: entry.autoMinHeight, dimensions: entry.dimensions, windowKey: item.id, children: [
1483
+ return /* @__PURE__ */ jsxs(Modal, { open: true, onClose, icon: navIcons[item.route], title: entry.label, size: entry.size || "2xl", allowPinOnTop: entry.allowPinOnTop, initialPosition: entry.initialPosition, widget: entry.widget, compact: entry.compact, appStyle: entry.appStyle, autoHeight: entry.autoHeight, autoMinHeight: entry.autoMinHeight, dimensions: entry.dimensions, windowKey: item.id, openedFromKey: item.openedFrom, children: [
1458
1484
  /* @__PURE__ */ jsx(DesktopShortcutMenuItem, { item }),
1459
1485
  /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsx(LoadingSpinner, {}) }), children: /* @__PURE__ */ jsx(Component, {}) })
1460
1486
  ] });
1461
1487
  }
1462
1488
  function DocFavStar({ entityType, entityId, label }) {
1463
1489
  const queryClient = useQueryClient();
1464
- const { data: profile } = useQuery({ queryKey: ["my-profile-sidebar"], queryFn: () => client_default.get("/auth/me/").then((r) => r.data) });
1490
+ const { data: profile } = useQuery({ queryKey: ["my-profile-sidebar"], enabled: isShellApiClientConfigured(), queryFn: () => client_default.get("/auth/me/").then((r) => r.data) });
1465
1491
  const favDocs = (profile?.preferences || {}).favorite_documents || [];
1466
1492
  const isFav = favDocs.some((d) => d.entityType === entityType && d.entityId === entityId);
1467
1493
  const toggle = () => {
@@ -1493,7 +1519,7 @@ function RestoredRegistryModal({ item, onClose, onMinimize }) {
1493
1519
  initialData: item.entitySnapshot,
1494
1520
  initialDataUpdatedAt: 0,
1495
1521
  // Treat snapshot as stale so query refetches immediately
1496
- enabled: !entry.selfFetching && !isDuplicate,
1522
+ enabled: !entry.selfFetching && !isDuplicate && isShellApiClientConfigured(),
1497
1523
  staleTime: 0,
1498
1524
  refetchOnWindowFocus: true,
1499
1525
  refetchOnMount: "always",
@@ -1539,6 +1565,7 @@ function RestoredRegistryModal({ item, onClose, onMinimize }) {
1539
1565
  footer: footerContent,
1540
1566
  copyText: item.id,
1541
1567
  windowKey: item.id,
1568
+ openedFromKey: item.openedFrom,
1542
1569
  size: entry.size || "2xl",
1543
1570
  autoHeight: entry.autoHeight,
1544
1571
  autoMinHeight: entry.autoMinHeight,
@@ -1553,6 +1580,12 @@ function RestoredRegistryModal({ item, onClose, onMinimize }) {
1553
1580
  function findPanelByWindowKey(key) {
1554
1581
  return document.querySelector(`[data-modal-panel][data-window-key="${key}"]`);
1555
1582
  }
1583
+ function currentlyActiveWindowKey() {
1584
+ const activeId = getActiveModalId();
1585
+ if (!activeId) return void 0;
1586
+ const panel = document.querySelector(`[data-modal-panel][data-modal-id="${activeId}"]`);
1587
+ return panel?.getAttribute("data-window-key") ?? void 0;
1588
+ }
1556
1589
  function findPanelByLabel(label) {
1557
1590
  const panels = document.querySelectorAll("[data-modal-panel]");
1558
1591
  for (const p of Array.from(panels)) {
@@ -1684,7 +1717,7 @@ function TaskbarTabPreview({ items, anchorEl, onActivate, onClose, onMouseEnter,
1684
1717
  maxWidth: "calc(100vw - 16px)",
1685
1718
  opacity: pos.ready ? 1 : 0
1686
1719
  },
1687
- className: isGroup ? "flex gap-2 p-2 rounded-lg bg-white/40 backdrop-blur-sm border border-white/30 shadow-2xl flex-wrap" : "",
1720
+ className: isGroup ? "flex gap-2 flex-wrap" : "",
1688
1721
  onMouseEnter,
1689
1722
  onMouseLeave,
1690
1723
  children: items.map((it) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center", children: [
@@ -1898,6 +1931,7 @@ function WindowManagerProvider({ children }) {
1898
1931
  const openEntity = useCallback((entityType, entityId, snapshot, label, route) => {
1899
1932
  if (!WINDOW_REGISTRY[entityType] || !isEntityEntry(WINDOW_REGISTRY[entityType])) return;
1900
1933
  const id = label || entityId;
1934
+ const openedFrom = currentlyActiveWindowKey();
1901
1935
  setOpenWindows((prev) => {
1902
1936
  const existing = prev.find((m) => m.entityId === entityId && m.entityType === entityType);
1903
1937
  if (existing) {
@@ -1920,13 +1954,15 @@ function WindowManagerProvider({ children }) {
1920
1954
  route: route || window.location.pathname,
1921
1955
  entityType,
1922
1956
  entityId,
1923
- entitySnapshot: snapshot
1957
+ entitySnapshot: snapshot,
1958
+ openedFrom
1924
1959
  }];
1925
1960
  });
1926
1961
  }, []);
1927
1962
  const openPage = useCallback((path) => {
1928
1963
  if (!WINDOW_REGISTRY[path] || !isPageEntry(WINDOW_REGISTRY[path])) return;
1929
1964
  const entry = WINDOW_REGISTRY[path];
1965
+ const openedFrom = currentlyActiveWindowKey();
1930
1966
  setOpenWindows((prev) => {
1931
1967
  if (entry.multiInstance) {
1932
1968
  const instanceCount = prev.filter((m) => m.type === "page" && m.route === path).length;
@@ -1936,7 +1972,8 @@ function WindowManagerProvider({ children }) {
1936
1972
  id,
1937
1973
  type: "page",
1938
1974
  label: instanceCount === 0 ? entry.label : `${entry.label} ${nextNum}`,
1939
- route: path
1975
+ route: path,
1976
+ openedFrom
1940
1977
  }];
1941
1978
  }
1942
1979
  const existing = prev.find((m) => m.type === "page" && m.route === path);
@@ -1960,7 +1997,8 @@ function WindowManagerProvider({ children }) {
1960
1997
  id: `page:${path}`,
1961
1998
  type: "page",
1962
1999
  label: entry.label,
1963
- route: path
2000
+ route: path,
2001
+ openedFrom
1964
2002
  }];
1965
2003
  });
1966
2004
  }, []);
@@ -2009,6 +2047,6 @@ function WindowManagerProvider({ children }) {
2009
2047
  ] });
2010
2048
  }
2011
2049
 
2012
- export { CancelButton, CopyButton, DocFavStar, GLASS_DIVIDER, GLASS_INPUT_BG, LoadingSpinner, Modal, ModalActions, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, ThumbCard, WINDOW_REGISTRY, WindowManagerProvider, WindowTitle, activateModal, client_default, getActiveModalId, getMobileMode, glassStyle, isEntityEntry, isPageEntry, isSection, navIcons, navSections, sectionIcons, setMobileMode, setShellApiClient, setShellNavIcons, setShellWindowRegistry, startMenuCategories, subscribeMobileMode, useIsMobile, useModalActive, useWidgetSettings, useWindowManager, useWindowMenuItem, useWindowTitle };
2013
- //# sourceMappingURL=chunk-7P6DO3NC.js.map
2014
- //# sourceMappingURL=chunk-7P6DO3NC.js.map
2050
+ export { CancelButton, CopyButton, DocFavStar, GLASS_DIVIDER, GLASS_INPUT_BG, LoadingSpinner, Modal, ModalActions, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, ThumbCard, WINDOW_REGISTRY, WindowManagerProvider, WindowTitle, activateModal, client_default, getActiveModalId, glassStyle, isEntityEntry, isPageEntry, isSection, navIcons, navSections, sectionIcons, setShellApiClient, setShellNavIcons, setShellWindowRegistry, startMenuCategories, useIsMobile, useModalActive, useWidgetSettings, useWindowManager, useWindowMenuItem, useWindowTitle };
2051
+ //# sourceMappingURL=chunk-QXY6ZHRX.js.map
2052
+ //# sourceMappingURL=chunk-QXY6ZHRX.js.map