react-os-shell 2.6.0 → 2.7.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 (57) hide show
  1. package/dist/Browser-YEOBTPST.js +7 -0
  2. package/dist/{Browser-H55YZJT5.js.map → Browser-YEOBTPST.js.map} +1 -1
  3. package/dist/{Calculator-H7HMALL3.js → Calculator-LF2IH7NZ.js} +4 -4
  4. package/dist/{Calculator-H7HMALL3.js.map → Calculator-LF2IH7NZ.js.map} +1 -1
  5. package/dist/{CurrencyConverter-576WXG7B.js → CurrencyConverter-AZ5RBU7E.js} +4 -4
  6. package/dist/{CurrencyConverter-576WXG7B.js.map → CurrencyConverter-AZ5RBU7E.js.map} +1 -1
  7. package/dist/{Documents-XBOFBIIZ.js → Documents-D7UN7W6P.js} +4 -4
  8. package/dist/{Documents-XBOFBIIZ.js.map → Documents-D7UN7W6P.js.map} +1 -1
  9. package/dist/Files-VXHZY7NY.js +13 -0
  10. package/dist/{Files-KX3OMH6V.js.map → Files-VXHZY7NY.js.map} +1 -1
  11. package/dist/{Notepad-PWLIOQR5.js → Notepad-THWCG35G.js} +4 -5
  12. package/dist/Notepad-THWCG35G.js.map +1 -0
  13. package/dist/{PomodoroTimer-PQ7FXSKY.js → PomodoroTimer-M7MDQTVN.js} +5 -6
  14. package/dist/PomodoroTimer-M7MDQTVN.js.map +1 -0
  15. package/dist/Preview-5SOLJFFK.js +9 -0
  16. package/dist/{Preview-YOTSKJNV.js.map → Preview-5SOLJFFK.js.map} +1 -1
  17. package/dist/Spreadsheet-UVBEPLQB.js +7 -0
  18. package/dist/{Spreadsheet-LQOJPR4G.js.map → Spreadsheet-UVBEPLQB.js.map} +1 -1
  19. package/dist/{Stock-NQFKY52J.js → Stock-7JFY7KUK.js} +4 -4
  20. package/dist/{Stock-NQFKY52J.js.map → Stock-7JFY7KUK.js.map} +1 -1
  21. package/dist/{Weather-KH5A7AZ3.js → Weather-B55N3VEX.js} +4 -5
  22. package/dist/Weather-B55N3VEX.js.map +1 -0
  23. package/dist/{WorldClock-VUMFYV5V.js → WorldClock-SARH4X3Y.js} +4 -5
  24. package/dist/WorldClock-SARH4X3Y.js.map +1 -0
  25. package/dist/apps/index.js +19 -19
  26. package/dist/{chunk-QOH6MNLW.js → chunk-AAKIF7SW.js} +4 -4
  27. package/dist/{chunk-QOH6MNLW.js.map → chunk-AAKIF7SW.js.map} +1 -1
  28. package/dist/{chunk-2NHG2V2R.js → chunk-FX77XLQZ.js} +5 -5
  29. package/dist/{chunk-2NHG2V2R.js.map → chunk-FX77XLQZ.js.map} +1 -1
  30. package/dist/{chunk-YVIW5GPB.js → chunk-IQTT4ZBV.js} +3 -3
  31. package/dist/{chunk-YVIW5GPB.js.map → chunk-IQTT4ZBV.js.map} +1 -1
  32. package/dist/{chunk-TJ6N7SI5.js → chunk-JNF5VRPB.js} +75 -35
  33. package/dist/chunk-JNF5VRPB.js.map +1 -0
  34. package/dist/{chunk-R3CZB3O2.js → chunk-LD2JBHD3.js} +4 -4
  35. package/dist/{chunk-R3CZB3O2.js.map → chunk-LD2JBHD3.js.map} +1 -1
  36. package/dist/{chunk-FIOHSNGM.js → chunk-MJIMKMSJ.js} +4 -4
  37. package/dist/{chunk-FIOHSNGM.js.map → chunk-MJIMKMSJ.js.map} +1 -1
  38. package/dist/{chunk-5X5LQNOX.js → chunk-P75EON66.js} +3 -3
  39. package/dist/{chunk-5X5LQNOX.js.map → chunk-P75EON66.js.map} +1 -1
  40. package/dist/{chunk-7CT2Y2MB.js → chunk-UATWDGLV.js} +4 -4
  41. package/dist/{chunk-7CT2Y2MB.js.map → chunk-UATWDGLV.js.map} +1 -1
  42. package/dist/{chunk-BE53IFLK.js → chunk-YZEQWMO5.js} +4 -4
  43. package/dist/{chunk-BE53IFLK.js.map → chunk-YZEQWMO5.js.map} +1 -1
  44. package/dist/index.js +89 -13
  45. package/dist/index.js.map +1 -1
  46. package/package.json +1 -1
  47. package/dist/Browser-H55YZJT5.js +0 -7
  48. package/dist/Files-KX3OMH6V.js +0 -13
  49. package/dist/Notepad-PWLIOQR5.js.map +0 -1
  50. package/dist/PomodoroTimer-PQ7FXSKY.js.map +0 -1
  51. package/dist/Preview-YOTSKJNV.js +0 -9
  52. package/dist/Spreadsheet-LQOJPR4G.js +0 -7
  53. package/dist/Weather-KH5A7AZ3.js.map +0 -1
  54. package/dist/WorldClock-VUMFYV5V.js.map +0 -1
  55. package/dist/chunk-36VM54SC.js +0 -42
  56. package/dist/chunk-36VM54SC.js.map +0 -1
  57. package/dist/chunk-TJ6N7SI5.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  import { confirm } from './chunk-UBN4IUDE.js';
2
2
  import { glassStyle, GLASS_DIVIDER, navIcons } from './chunk-ZF6AYO4G.js';
3
- import { createContext, Component, useRef, useEffect, useSyncExternalStore, useContext, useState, useCallback, isValidElement, cloneElement, useLayoutEffect, Suspense, useMemo } from 'react';
3
+ import { createContext, Component, useRef, useEffect, useSyncExternalStore, useState, useCallback, useContext, isValidElement, cloneElement, useLayoutEffect, Suspense } from 'react';
4
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
5
  import { useLocation } from 'react-router-dom';
6
6
  import { createPortal } from 'react-dom';
@@ -260,7 +260,45 @@ function subscribeSwipingParentKey(cb) {
260
260
  subs.delete(cb);
261
261
  };
262
262
  }
263
+ var ShellPrefsContext = createContext(null);
264
+ function ShellPrefsProvider({
265
+ value,
266
+ children
267
+ }) {
268
+ return /* @__PURE__ */ jsx(ShellPrefsContext.Provider, { value, children });
269
+ }
270
+ function useLocalStoragePrefs(storageKey = "react-os-shell:prefs", defaults) {
271
+ const [prefs, setPrefs] = useState(() => {
272
+ try {
273
+ const stored = JSON.parse(localStorage.getItem(storageKey) || "{}");
274
+ return { ...defaults ?? {}, ...stored };
275
+ } catch {
276
+ return { ...defaults ?? {} };
277
+ }
278
+ });
279
+ const save = useCallback((patch) => {
280
+ setPrefs((prev) => {
281
+ const next = { ...prev, ...patch };
282
+ try {
283
+ localStorage.setItem(storageKey, JSON.stringify(next));
284
+ } catch {
285
+ }
286
+ return next;
287
+ });
288
+ }, [storageKey]);
289
+ return { prefs, save };
290
+ }
291
+ function useShellPrefs() {
292
+ const ctx = useContext(ShellPrefsContext);
293
+ if (ctx) return ctx;
294
+ return { prefs: {}, save: () => {
295
+ } };
296
+ }
263
297
  var ModalIdContext = createContext("");
298
+ var WindowShortcutContext = createContext(null);
299
+ function WindowShortcutProvider({ spec, children }) {
300
+ return /* @__PURE__ */ jsx(WindowShortcutContext.Provider, { value: spec, children });
301
+ }
264
302
  var TITLE_STRIP_TYPES = /* @__PURE__ */ new Set(["button", "input", "textarea", "select", "kbd", "svg"]);
265
303
  function extractTitleText(node) {
266
304
  if (node == null || typeof node === "boolean") return "";
@@ -877,6 +915,15 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
877
915
  const [touched, setTouched] = useState(false);
878
916
  const [pinnedOnTop, setPinnedOnTop] = useState(false);
879
917
  const [windowMenu, setWindowMenu] = useState(null);
918
+ const shortcutSpec = useContext(WindowShortcutContext);
919
+ const { prefs: shellPrefs, save: saveShellPrefs } = useShellPrefs();
920
+ const favDocs = shellPrefs.favorite_documents || [];
921
+ const isOnDesktop = !!shortcutSpec && favDocs.some((d) => d.entityType === shortcutSpec.entityType && d.entityId === shortcutSpec.entityId);
922
+ const toggleDesktopShortcut = useCallback(() => {
923
+ if (!shortcutSpec) return;
924
+ const next = isOnDesktop ? favDocs.filter((d) => !(d.entityType === shortcutSpec.entityType && d.entityId === shortcutSpec.entityId)) : [...favDocs, { entityType: shortcutSpec.entityType, entityId: shortcutSpec.entityId, label: shortcutSpec.label }];
925
+ saveShellPrefs({ favorite_documents: next });
926
+ }, [shortcutSpec, isOnDesktop, favDocs, saveShellPrefs]);
880
927
  const [ctxMenu, setCtxMenu] = useState(null);
881
928
  const [widgetAnchor, setWidgetAnchor] = useState(initialPosition === "top-right" ? "right" : "left");
882
929
  const closingRef = useRef(false);
@@ -1804,6 +1851,13 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
1804
1851
  /* @__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" }) }),
1805
1852
  pinnedOnTop ? "Unpin from Top" : "Pin on Top"
1806
1853
  ] }),
1854
+ shortcutSpec && /* @__PURE__ */ jsxs(PopupMenuItem, { onClick: () => {
1855
+ setWindowMenu(null);
1856
+ toggleDesktopShortcut();
1857
+ }, children: [
1858
+ /* @__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" }) }),
1859
+ isOnDesktop ? "Remove from Desktop" : "Add to Desktop"
1860
+ ] }),
1807
1861
  (_extraMenuItems[modalId] || []).length > 0 && /* @__PURE__ */ jsx(Fragment, { children: (_extraMenuItems[modalId] || []).map((item, i) => /* @__PURE__ */ jsxs(PopupMenuItem, { onClick: () => {
1808
1862
  setWindowMenu(null);
1809
1863
  item.onClick();
@@ -1820,10 +1874,13 @@ function Modal({ open, onClose, title, icon, copyText, size = "lg", dirty = fals
1820
1874
  "Close"
1821
1875
  ] })
1822
1876
  ] });
1823
- return createPortal(/* @__PURE__ */ jsxs(Fragment, { children: [
1824
- content,
1825
- windowMenuEl
1826
- ] }), document.body);
1877
+ return createPortal(
1878
+ /* @__PURE__ */ jsxs(WindowShortcutContext.Provider, { value: null, children: [
1879
+ content,
1880
+ windowMenuEl
1881
+ ] }),
1882
+ document.body
1883
+ );
1827
1884
  }
1828
1885
  function LoadingSpinner() {
1829
1886
  return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center p-8 text-sm text-gray-400", children: "Loading..." });
@@ -1849,32 +1906,18 @@ var MinimizedContext = createContext({
1849
1906
  function useWindowManager() {
1850
1907
  return useContext(MinimizedContext);
1851
1908
  }
1852
- function DesktopShortcutMenuItem({ item }) {
1853
- const queryClient = useQueryClient();
1854
- const { data: profile } = useQuery({ queryKey: ["my-profile-sidebar"], enabled: isShellApiClientConfigured(), queryFn: () => client_default.get("/auth/me/").then((r) => r.data) });
1855
- const favDocs = (profile?.preferences || {}).favorite_documents || [];
1856
- const favType = item.type === "page" ? "page" : item.entityType || "";
1857
- const favId = item.type === "page" ? item.route || "" : item.entityId || "";
1858
- const isFav = favDocs.some((d) => d.entityType === favType && d.entityId === favId);
1859
- const toggle = useCallback(() => {
1860
- const next = isFav ? favDocs.filter((d) => !(d.entityType === favType && d.entityId === favId)) : [...favDocs, { entityType: favType, entityId: favId, label: item.label }];
1861
- client_default.patch("/auth/me/", { preferences: { favorite_documents: next } }).then(() => {
1862
- queryClient.invalidateQueries({ queryKey: ["my-profile-sidebar"] });
1863
- });
1864
- }, [isFav, favDocs, favType, favId, item.label, queryClient]);
1865
- const icon = useMemo(() => /* @__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" }) }), [isFav]);
1866
- useWindowMenuItem(isFav ? "Remove from Desktop" : "Add to Desktop", toggle, icon);
1867
- return null;
1909
+ function shortcutSpecFor(item) {
1910
+ const entityType = item.type === "page" ? "page" : item.entityType || "";
1911
+ const entityId = item.type === "page" ? item.route || "" : item.entityId || "";
1912
+ if (!entityType || !entityId) return null;
1913
+ return { entityType, entityId, label: item.label };
1868
1914
  }
1869
1915
  function PageWindow({ item, onClose }) {
1870
1916
  const raw = WINDOW_REGISTRY[item.route];
1871
1917
  if (!raw || !isPageEntry(raw)) return null;
1872
1918
  const entry = raw;
1873
1919
  const Component2 = entry.component;
1874
- 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, flushBody: entry.flushBody, autoHeight: entry.autoHeight, autoMinHeight: entry.autoMinHeight, dimensions: entry.dimensions, windowKey: item.id, openedFromKey: item.openedFrom, children: [
1875
- /* @__PURE__ */ jsx(DesktopShortcutMenuItem, { item }),
1876
- /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsx(LoadingSpinner, {}) }), children: /* @__PURE__ */ jsx(Component2, {}) })
1877
- ] });
1920
+ return /* @__PURE__ */ jsx(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, flushBody: entry.flushBody, autoHeight: entry.autoHeight, autoMinHeight: entry.autoMinHeight, dimensions: entry.dimensions, windowKey: item.id, openedFromKey: item.openedFrom, children: /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsx(LoadingSpinner, {}) }), children: /* @__PURE__ */ jsx(Component2, {}) }) });
1878
1921
  }
1879
1922
  function DocFavStar({ entityType, entityId, label }) {
1880
1923
  const queryClient = useQueryClient();
@@ -1944,7 +1987,7 @@ function RestoredRegistryModal({ item, onClose, onMinimize }) {
1944
1987
  }
1945
1988
  return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(LoadingSpinner, {}), children: isLoading && !entity ? /* @__PURE__ */ jsx(LoadingSpinner, {}) : entity ? entry.render(entity, handleClose, item.entityId, editing, setEditing) : /* @__PURE__ */ jsx(Modal, { open: true, onClose, title: item.label, size: entry.size || "2xl", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 py-8 text-center", children: "Not found." }) }) });
1946
1989
  }
1947
- return /* @__PURE__ */ jsxs(
1990
+ return /* @__PURE__ */ jsx(
1948
1991
  Modal,
1949
1992
  {
1950
1993
  open: true,
@@ -1961,10 +2004,7 @@ function RestoredRegistryModal({ item, onClose, onMinimize }) {
1961
2004
  autoHeight: entry.autoHeight,
1962
2005
  autoMinHeight: entry.autoMinHeight,
1963
2006
  appStyle: entry.appStyle,
1964
- children: [
1965
- /* @__PURE__ */ jsx(DesktopShortcutMenuItem, { item }),
1966
- /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(LoadingSpinner, {}), children: entry.selfFetching ? entry.render(null, handleClose, item.entityId, editing, setEditing) : isLoading && !entity ? /* @__PURE__ */ jsx(LoadingSpinner, {}) : entity ? entry.render(entity, handleClose, item.entityId, editing, setEditing) : /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 py-8 text-center", children: "Not found." }) })
1967
- ]
2007
+ children: /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(LoadingSpinner, {}), children: entry.selfFetching ? entry.render(null, handleClose, item.entityId, editing, setEditing) : isLoading && !entity ? /* @__PURE__ */ jsx(LoadingSpinner, {}) : entity ? entry.render(entity, handleClose, item.entityId, editing, setEditing) : /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 py-8 text-center", children: "Not found." }) })
1968
2008
  }
1969
2009
  );
1970
2010
  }
@@ -2447,7 +2487,7 @@ function WindowManagerProvider({ children }) {
2447
2487
  WindowErrorBoundary,
2448
2488
  {
2449
2489
  fallback: (error, reset) => /* @__PURE__ */ jsx(Modal, { open: true, onClose: () => closeEntity(item.id), title: item.label, size: "md", autoHeight: true, windowKey: item.id, children: /* @__PURE__ */ jsx(WindowCrashedFallback, { error, onReload: reset }) }),
2450
- children: item.type === "page" ? /* @__PURE__ */ jsx(PageWindow, { item, onClose: () => closeEntity(item.id) }) : /* @__PURE__ */ jsx(
2490
+ children: /* @__PURE__ */ jsx(WindowShortcutProvider, { spec: shortcutSpecFor(item), children: item.type === "page" ? /* @__PURE__ */ jsx(PageWindow, { item, onClose: () => closeEntity(item.id) }) : /* @__PURE__ */ jsx(
2451
2491
  RestoredRegistryModal,
2452
2492
  {
2453
2493
  item,
@@ -2455,13 +2495,13 @@ function WindowManagerProvider({ children }) {
2455
2495
  onMinimize: () => {
2456
2496
  }
2457
2497
  }
2458
- )
2498
+ ) })
2459
2499
  },
2460
2500
  item.id
2461
2501
  ))
2462
2502
  ] });
2463
2503
  }
2464
2504
 
2465
- export { CancelButton, CopyButton, DocFavStar, LoadingSpinner, Modal, ModalActions, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, ThumbCard, WINDOW_REGISTRY, WindowCrashedFallback, WindowErrorBoundary, WindowManagerProvider, WindowTitle, activateModal, client_default, commitExposeHighlight, exitExposeMode, getActiveModalId, getActiveWindowRoute, getExposeHighlight, getWindowPosition, isEntityEntry, isPageEntry, registerModalEscapeInterceptor, setExposeHighlight, setShellApiClient, setShellWindowRegistry, setWindowDefaultPosition, setWindowPosition, subscribeExposeHighlight, toggleExposeMode, useIsMobile, useModalActive, useWidgetSettings, useWindowManager, useWindowMenuItem, useWindowTitle };
2466
- //# sourceMappingURL=chunk-TJ6N7SI5.js.map
2467
- //# sourceMappingURL=chunk-TJ6N7SI5.js.map
2505
+ export { CancelButton, CopyButton, DocFavStar, LoadingSpinner, Modal, ModalActions, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, ShellPrefsProvider, ThumbCard, WINDOW_REGISTRY, WindowCrashedFallback, WindowErrorBoundary, WindowManagerProvider, WindowTitle, activateModal, client_default, commitExposeHighlight, exitExposeMode, getActiveModalId, getActiveWindowRoute, getExposeHighlight, getWindowPosition, isEntityEntry, isPageEntry, registerModalEscapeInterceptor, setExposeHighlight, setShellApiClient, setShellWindowRegistry, setWindowDefaultPosition, setWindowPosition, subscribeExposeHighlight, toggleExposeMode, useIsMobile, useLocalStoragePrefs, useModalActive, useShellPrefs, useWidgetSettings, useWindowManager, useWindowMenuItem, useWindowTitle };
2506
+ //# sourceMappingURL=chunk-JNF5VRPB.js.map
2507
+ //# sourceMappingURL=chunk-JNF5VRPB.js.map