react-os-shell 3.16.2 → 3.16.3

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 (56) hide show
  1. package/dist/{chunk-RNXBHVCZ.js → Browser-PTRUZ73Y.js} +10 -12
  2. package/dist/Browser-PTRUZ73Y.js.map +1 -0
  3. package/dist/{Documents-KQ2YMWX5.js → Documents-U4JJQFWL.js} +4 -3
  4. package/dist/Documents-U4JJQFWL.js.map +1 -0
  5. package/dist/{chunk-EFTDLYWR.js → Files-VQHPKNSN.js} +13 -13
  6. package/dist/Files-VQHPKNSN.js.map +1 -0
  7. package/dist/{Notepad-NOMFXBKY.js → Notepad-4QHMNSLQ.js} +4 -3
  8. package/dist/Notepad-4QHMNSLQ.js.map +1 -0
  9. package/dist/{PomodoroTimer-BQVEKF45.js → PomodoroTimer-WVA3ZB4J.js} +3 -3
  10. package/dist/{PomodoroTimer-BQVEKF45.js.map → PomodoroTimer-WVA3ZB4J.js.map} +1 -1
  11. package/dist/{chunk-4BSHCQM6.js → Preview-YIHTIPXD.js} +16 -1119
  12. package/dist/Preview-YIHTIPXD.js.map +1 -0
  13. package/dist/Spreadsheet-CU6UCLDP.js +506 -0
  14. package/dist/Spreadsheet-CU6UCLDP.js.map +1 -0
  15. package/dist/apps/index.d.ts +97 -75
  16. package/dist/apps/index.js +14 -15
  17. package/dist/apps/index.js.map +1 -1
  18. package/dist/{chunk-QCGWXJX3.js → chunk-2Q4LCCVB.js} +5 -7
  19. package/dist/chunk-2Q4LCCVB.js.map +1 -0
  20. package/dist/chunk-4SQU5YV6.js +24 -0
  21. package/dist/chunk-4SQU5YV6.js.map +1 -0
  22. package/dist/chunk-BFBWLCO6.js +16 -0
  23. package/dist/chunk-BFBWLCO6.js.map +1 -0
  24. package/dist/chunk-BV6SQ46N.js +24 -0
  25. package/dist/chunk-BV6SQ46N.js.map +1 -0
  26. package/dist/chunk-DINNWYVB.js +98 -0
  27. package/dist/chunk-DINNWYVB.js.map +1 -0
  28. package/dist/{chunk-ZMDLIYIK.js → chunk-GP4Y3VCB.js} +4 -510
  29. package/dist/chunk-GP4Y3VCB.js.map +1 -0
  30. package/dist/chunk-QU5L5ZYM.js +1103 -0
  31. package/dist/chunk-QU5L5ZYM.js.map +1 -0
  32. package/dist/{chunk-SJNGOGS5.js → chunk-UFR3CXIF.js} +4 -95
  33. package/dist/chunk-UFR3CXIF.js.map +1 -0
  34. package/dist/chunk-UPO23MX4.js +17 -0
  35. package/dist/chunk-UPO23MX4.js.map +1 -0
  36. package/dist/chunk-WTJY2AEO.js +7 -0
  37. package/dist/chunk-WTJY2AEO.js.map +1 -0
  38. package/dist/index.js +11 -9
  39. package/dist/index.js.map +1 -1
  40. package/package.json +1 -1
  41. package/dist/Browser-NM54NOXT.js +0 -7
  42. package/dist/Browser-NM54NOXT.js.map +0 -1
  43. package/dist/Documents-KQ2YMWX5.js.map +0 -1
  44. package/dist/Files-GOQMZWQU.js +0 -12
  45. package/dist/Files-GOQMZWQU.js.map +0 -1
  46. package/dist/Notepad-NOMFXBKY.js.map +0 -1
  47. package/dist/Preview-GGC5263S.js +0 -8
  48. package/dist/Preview-GGC5263S.js.map +0 -1
  49. package/dist/Spreadsheet-S6BVMBSM.js +0 -7
  50. package/dist/Spreadsheet-S6BVMBSM.js.map +0 -1
  51. package/dist/chunk-4BSHCQM6.js.map +0 -1
  52. package/dist/chunk-EFTDLYWR.js.map +0 -1
  53. package/dist/chunk-QCGWXJX3.js.map +0 -1
  54. package/dist/chunk-RNXBHVCZ.js.map +0 -1
  55. package/dist/chunk-SJNGOGS5.js.map +0 -1
  56. package/dist/chunk-ZMDLIYIK.js.map +0 -1
@@ -2,66 +2,12 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
3
  import { W as WindowRegistry } from '../types-BHVq95fp.js';
4
4
 
5
- /** Stage a URL for the next Browser window mount — pair with
6
- * `openPage('/browser')`. Used by "open this link in the Browser" flows
7
- * (e.g. links inside an email body). */
8
- declare function setBrowserStartUrl(url: string): void;
9
5
  declare function Browser$1(): react_jsx_runtime.JSX.Element;
10
6
 
11
- /**
12
- * Demo filesystem. When a consumer (e.g. the demo app) injects a static tree
13
- * via `setFilesDemoTree`, Files browses it in-memory — no file server needed.
14
- * Browse-only: upload / new-folder / rename / delete / trash are hidden while a
15
- * demo tree is set. Consumers with a real file server never call it, so their
16
- * behaviour is unchanged.
17
- */
18
- interface FilesDemoNode {
19
- name: string;
20
- kind: 'file' | 'folder';
21
- size?: number;
22
- modifiedAt?: string;
23
- children?: FilesDemoNode[];
24
- }
25
- declare function setFilesDemoTree(tree: FilesDemoNode[] | null): void;
26
- declare function openFilesInTrashMode(): void;
27
7
  declare function Files$1(): react_jsx_runtime.JSX.Element;
28
8
 
29
9
  declare function Documents$1(): react_jsx_runtime.JSX.Element;
30
10
 
31
- interface PdfPreviewData {
32
- /** Object URL or remote URL of the PDF. Blob URLs are revoked when the window unmounts.
33
- * Leave blank when staging a `converting: true` placeholder; call `handle.update({...})`
34
- * on the handle returned by `setPdfPreview` once conversion finishes. */
35
- url?: string;
36
- /** Display name (and download filename). */
37
- filename: string;
38
- /** Renderer to use. Defaults to `'pdf'`. `'dxf'` requires the consumer to
39
- * have `dxf-viewer` installed (it's an optional peer dep). `'image'`
40
- * renders an `<img>` for raster screenshots / photos. `'3d'` covers
41
- * STEP / STL / OBJ / GLTF / 3MF / IGES via the optional
42
- * `online-3d-viewer` peer dep. */
43
- kind?: 'pdf' | 'dxf' | 'image' | '3d';
44
- /** Optional download handler — replaces the built-in "save URL as filename" if supplied. */
45
- onDownload?: () => void;
46
- /** Optional email handler — only shown when supplied. */
47
- onEmail?: () => void;
48
- /** Show a progress placeholder while the consumer fetches/converts the file. */
49
- converting?: boolean;
50
- /** Headline shown on the converting placeholder (e.g. "CONVERTING DWG FILE"). */
51
- convertingMessage?: string;
52
- }
53
- /** Handle returned by `setPdfPreview`. Holds the identity of the staged
54
- * payload so a later `.update()` only targets the window that picked it up
55
- * (not every open Preview, which would clobber unrelated windows). */
56
- interface PdfPreviewHandle {
57
- /** Replace the data shown in the window that consumed this staging.
58
- * No-op if no window ever consumed it, or if that window has been closed. */
59
- update(next: PdfPreviewData): void;
60
- }
61
- /** Stage a PDF for the next Preview window mount. The returned handle's
62
- * `update()` method swaps content in *that* specific window only — use it
63
- * to replace a `converting: true` placeholder with the resolved file. */
64
- declare function setPdfPreview(data: PdfPreviewData): PdfPreviewHandle;
65
11
  declare function Preview$1(): react_jsx_runtime.JSX.Element;
66
12
 
67
13
  declare function Stock$1(): react_jsx_runtime.JSX.Element;
@@ -84,27 +30,6 @@ declare function CurrencyConverter$1(): react_jsx_runtime.JSX.Element;
84
30
 
85
31
  declare function Weather$1(): react_jsx_runtime.JSX.Element;
86
32
 
87
- interface SpreadsheetPreviewData {
88
- /** CSV text (comma- or tab-separated). */
89
- csv: string;
90
- /** Display name; the title strips a trailing `.csv`/`.tsv`/`.txt`. */
91
- filename: string;
92
- /** When provided, the toolbar shows an Email button that calls back with the
93
- * sheet serialized as CSV at click time (edits included) and a filename
94
- * derived from the current title. */
95
- onEmail?: (csv: string, filename: string) => void;
96
- }
97
- /** Handle returned by `setSpreadsheetPreview`. Holds the identity of the
98
- * staged payload so a later `.update()` only targets the window that picked
99
- * it up — opening a second Spreadsheet never clobbers the first. */
100
- interface SpreadsheetPreviewHandle {
101
- /** Replace the data shown in the window that consumed this staging.
102
- * No-op if no window ever consumed it, or if that window has been closed. */
103
- update(next: SpreadsheetPreviewData): void;
104
- }
105
- /** Stage CSV content for the next Spreadsheet window mount. The returned
106
- * handle's `update()` method swaps content in *that* specific window only. */
107
- declare function setSpreadsheetPreview(data: SpreadsheetPreviewData): SpreadsheetPreviewHandle;
108
33
  declare function Spreadsheet$1(): react_jsx_runtime.JSX.Element;
109
34
 
110
35
  declare function Calculator$1(): react_jsx_runtime.JSX.Element;
@@ -159,6 +84,103 @@ declare const BUILTIN_APP_INFO: {
159
84
  };
160
85
  type BuiltinAppId = keyof typeof BUILTIN_APP_INFO;
161
86
 
87
+ /**
88
+ * PDF Preview staging — the tiny consumer-facing surface of the Preview app.
89
+ *
90
+ * Lives apart from Preview.tsx so importing `setPdfPreview` (from
91
+ * `react-os-shell/apps` or shell internals like PdfActionButton /
92
+ * openPreviewFile) never drags the viewer implementation — and its static
93
+ * pdfjs-dist import — into a host's startup bundle. The Preview window
94
+ * component stays behind its React.lazy dynamic import and drains the stage
95
+ * on mount via the @internal peek/claim helpers below.
96
+ */
97
+ interface PdfPreviewData {
98
+ /** Object URL or remote URL of the PDF. Blob URLs are revoked when the window unmounts.
99
+ * Leave blank when staging a `converting: true` placeholder; call `handle.update({...})`
100
+ * on the handle returned by `setPdfPreview` once conversion finishes. */
101
+ url?: string;
102
+ /** Display name (and download filename). */
103
+ filename: string;
104
+ /** Renderer to use. Defaults to `'pdf'`. `'dxf'` requires the consumer to
105
+ * have `dxf-viewer` installed (it's an optional peer dep). `'image'`
106
+ * renders an `<img>` for raster screenshots / photos. `'3d'` covers
107
+ * STEP / STL / OBJ / GLTF / 3MF / IGES via the optional
108
+ * `online-3d-viewer` peer dep. */
109
+ kind?: 'pdf' | 'dxf' | 'image' | '3d';
110
+ /** Optional download handler — replaces the built-in "save URL as filename" if supplied. */
111
+ onDownload?: () => void;
112
+ /** Optional email handler — only shown when supplied. */
113
+ onEmail?: () => void;
114
+ /** Show a progress placeholder while the consumer fetches/converts the file. */
115
+ converting?: boolean;
116
+ /** Headline shown on the converting placeholder (e.g. "CONVERTING DWG FILE"). */
117
+ convertingMessage?: string;
118
+ }
119
+ /** Handle returned by `setPdfPreview`. Holds the identity of the staged
120
+ * payload so a later `.update()` only targets the window that picked it up
121
+ * (not every open Preview, which would clobber unrelated windows). */
122
+ interface PdfPreviewHandle {
123
+ /** Replace the data shown in the window that consumed this staging.
124
+ * No-op if no window ever consumed it, or if that window has been closed. */
125
+ update(next: PdfPreviewData): void;
126
+ }
127
+ /** Stage a PDF for the next Preview window mount. The returned handle's
128
+ * `update()` method swaps content in *that* specific window only — use it
129
+ * to replace a `converting: true` placeholder with the resolved file. */
130
+ declare function setPdfPreview(data: PdfPreviewData): PdfPreviewHandle;
131
+
132
+ /**
133
+ * Spreadsheet staging — the tiny consumer-facing surface of the Spreadsheets
134
+ * app. Lives apart from Spreadsheet.tsx so importing `setSpreadsheetPreview`
135
+ * (from `react-os-shell/apps` or shell internals like openPreviewFile) never
136
+ * drags the grid implementation into a host's startup bundle. The Spreadsheet
137
+ * window component stays behind its React.lazy dynamic import and drains the
138
+ * stage on mount via the @internal peek/claim helpers below.
139
+ */
140
+ interface SpreadsheetPreviewData {
141
+ /** CSV text (comma- or tab-separated). */
142
+ csv: string;
143
+ /** Display name; the title strips a trailing `.csv`/`.tsv`/`.txt`. */
144
+ filename: string;
145
+ /** When provided, the toolbar shows an Email button that calls back with the
146
+ * sheet serialized as CSV at click time (edits included) and a filename
147
+ * derived from the current title. */
148
+ onEmail?: (csv: string, filename: string) => void;
149
+ }
150
+ /** Handle returned by `setSpreadsheetPreview`. Holds the identity of the
151
+ * staged payload so a later `.update()` only targets the window that picked
152
+ * it up — opening a second Spreadsheet never clobbers the first. */
153
+ interface SpreadsheetPreviewHandle {
154
+ /** Replace the data shown in the window that consumed this staging.
155
+ * No-op if no window ever consumed it, or if that window has been closed. */
156
+ update(next: SpreadsheetPreviewData): void;
157
+ }
158
+ /** Stage CSV content for the next Spreadsheet window mount. The returned
159
+ * handle's `update()` method swaps content in *that* specific window only. */
160
+ declare function setSpreadsheetPreview(data: SpreadsheetPreviewData): SpreadsheetPreviewHandle;
161
+
162
+ /** Stage a URL for the next Browser window mount — pair with
163
+ * `openPage('/browser')`. Used by "open this link in the Browser" flows
164
+ * (e.g. links inside an email body). */
165
+ declare function setBrowserStartUrl(url: string): void;
166
+
167
+ /**
168
+ * Demo filesystem. When a consumer (e.g. the demo app) injects a static tree
169
+ * via `setFilesDemoTree`, Files browses it in-memory — no file server needed.
170
+ * Browse-only: upload / new-folder / rename / delete / trash are hidden while a
171
+ * demo tree is set. Consumers with a real file server never call it, so their
172
+ * behaviour is unchanged.
173
+ */
174
+ interface FilesDemoNode {
175
+ name: string;
176
+ kind: 'file' | 'folder';
177
+ size?: number;
178
+ modifiedAt?: string;
179
+ children?: FilesDemoNode[];
180
+ }
181
+ declare function setFilesDemoTree(tree: FilesDemoNode[] | null): void;
182
+ declare function openFilesInTrashMode(): void;
183
+
162
184
  declare const Calculator: react.LazyExoticComponent<typeof Calculator$1>;
163
185
  declare const Spreadsheet: react.LazyExoticComponent<typeof Spreadsheet$1>;
164
186
  declare const Weather: react.LazyExoticComponent<typeof Weather$1>;
@@ -1,28 +1,27 @@
1
- export { openFilesInTrashMode, setFilesDemoTree } from '../chunk-EFTDLYWR.js';
2
- import '../chunk-SJNGOGS5.js';
3
- import '../chunk-YG45DAUT.js';
4
- export { setPdfPreview } from '../chunk-4BSHCQM6.js';
5
- import '../chunk-VENYVK3L.js';
6
- export { setSpreadsheetPreview } from '../chunk-ZMDLIYIK.js';
7
- export { setBrowserStartUrl } from '../chunk-RNXBHVCZ.js';
8
- export { BUILTIN_APP_INFO } from '../chunk-QCGWXJX3.js';
1
+ export { setBrowserStartUrl } from '../chunk-BFBWLCO6.js';
2
+ export { openFilesInTrashMode, setFilesDemoTree } from '../chunk-UPO23MX4.js';
3
+ import '../chunk-UFR3CXIF.js';
4
+ export { setPdfPreview } from '../chunk-BV6SQ46N.js';
5
+ export { BUILTIN_APP_INFO } from '../chunk-2Q4LCCVB.js';
6
+ export { setSpreadsheetPreview } from '../chunk-4SQU5YV6.js';
7
+ import '../chunk-WTJY2AEO.js';
9
8
  import '../chunk-ZCL4X6PU.js';
10
9
  import '../chunk-UBN4IUDE.js';
11
10
  import '../chunk-ZF6AYO4G.js';
12
11
  import { lazy } from 'react';
13
12
 
14
13
  var Calculator = lazy(() => import('../Calculator-TADU6MLU.js'));
15
- var Spreadsheet = lazy(() => import('../Spreadsheet-S6BVMBSM.js'));
14
+ var Spreadsheet = lazy(() => import('../Spreadsheet-CU6UCLDP.js'));
16
15
  var Weather = lazy(() => import('../Weather-MHLLLOB5.js'));
17
16
  var CurrencyConverter = lazy(() => import('../CurrencyConverter-VOYRUDXD.js'));
18
- var PomodoroTimer = lazy(() => import('../PomodoroTimer-BQVEKF45.js'));
19
- var Notepad = lazy(() => import('../Notepad-NOMFXBKY.js'));
17
+ var PomodoroTimer = lazy(() => import('../PomodoroTimer-WVA3ZB4J.js'));
18
+ var Notepad = lazy(() => import('../Notepad-4QHMNSLQ.js'));
20
19
  var WorldClock = lazy(() => import('../WorldClock-MPI4DPOT.js'));
21
20
  var Stock = lazy(() => import('../Stock-MOZKPNGI.js'));
22
- var Preview = lazy(() => import('../Preview-GGC5263S.js'));
23
- var Documents = lazy(() => import('../Documents-KQ2YMWX5.js'));
24
- var Files = lazy(() => import('../Files-GOQMZWQU.js'));
25
- var Browser = lazy(() => import('../Browser-NM54NOXT.js'));
21
+ var Preview = lazy(() => import('../Preview-YIHTIPXD.js'));
22
+ var Documents = lazy(() => import('../Documents-U4JJQFWL.js'));
23
+ var Files = lazy(() => import('../Files-VQHPKNSN.js'));
24
+ var Browser = lazy(() => import('../Browser-PTRUZ73Y.js'));
26
25
  var utilityApps = {
27
26
  "/calculator": { component: Calculator, label: "Calculator", size: "sm", allowPinOnTop: true, utility: true, widget: true, dimensions: [280, 420] },
28
27
  "/spreadsheet": { component: Spreadsheet, label: "Spreadsheets", size: "2xl", appStyle: true, multiInstance: true },
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/apps/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Bundled apps — pre-built window registry entries for the 12 apps that ship\n * with `react-os-shell`. Consumers compose them into their own registry via\n * `createWindowRegistry`:\n *\n * import { createWindowRegistry } from 'react-os-shell';\n * import { bundledApps } from 'react-os-shell/apps';\n * import { erpEntities } from './shell-config';\n *\n * const windows = createWindowRegistry(bundledApps, erpEntities);\n *\n * Subsets are also exported (`utilityApps`, `documentApps`, `webApps`) so a\n * consumer can pick-and-choose without importing every component.\n *\n * NOTE: Notepad requires consumer-supplied persistence for stored content.\n * WorldClock uses `useShellPrefs()` so it lives in `bundledApps`; without a\n * consumer-supplied prefs adapter the city list won't survive a reload.\n */\nimport { lazy } from 'react';\nimport type { WindowRegistry } from '../windowRegistry/types';\n\n// ── Utility apps ──\nconst Calculator = lazy(() => import('./Calculator'));\nconst Spreadsheet = lazy(() => import('./Spreadsheet'));\nconst Weather = lazy(() => import('./Weather'));\nconst CurrencyConverter = lazy(() => import('./CurrencyConverter'));\nconst PomodoroTimer = lazy(() => import('./PomodoroTimer'));\nconst Notepad = lazy(() => import('./Notepad'));\nconst WorldClock = lazy(() => import('./WorldClock'));\nconst Stock = lazy(() => import('./Stock'));\n\n// ── Document apps ──\nconst Preview = lazy(() => import('./Preview'));\nconst Documents = lazy(() => import('./Documents'));\nconst Files = lazy(() => import('./Files'));\n\n// ── Web ──\nconst Browser = lazy(() => import('./Browser'));\n\nexport const utilityApps: WindowRegistry = {\n '/calculator': { component: Calculator, label: 'Calculator', size: 'sm', allowPinOnTop: true, utility: true, widget: true, dimensions: [280, 420] },\n '/spreadsheet': { component: Spreadsheet, label: 'Spreadsheets', size: '2xl', appStyle: true, multiInstance: true },\n '/notepad': { component: Notepad, label: 'Notepad', size: 'lg', allowPinOnTop: true, flushBody: true },\n '/weather': { component: Weather, label: 'Weather', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 400] },\n '/currency': { component: CurrencyConverter, label: 'Currency Converter', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 480] },\n '/pomodoro': { component: PomodoroTimer, label: 'Pomodoro Timer', size: 'sm', utility: true, widget: true, dimensions: [320, 600] },\n '/world-clock': { component: WorldClock, label: 'World Clock', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 480] },\n '/stock': { component: Stock, label: 'Stocks', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 360] },\n};\n\nexport const documentApps: WindowRegistry = {\n '/preview': { component: Preview, label: 'Preview', size: '2xl', appStyle: true, multiInstance: true },\n '/documents': { component: Documents, label: 'Documents', size: 'xl', appStyle: true, multiInstance: true },\n '/files': { component: Files, label: 'Files', size: 'xl', appStyle: true },\n};\n\nexport const webApps: WindowRegistry = {\n '/browser': { component: Browser, label: 'Browser', size: '2xl', appStyle: true, multiInstance: true },\n};\n\nexport const bundledApps: WindowRegistry = {\n ...utilityApps,\n ...documentApps,\n ...webApps,\n};\n\nexport {\n Calculator,\n Spreadsheet,\n Notepad,\n Weather,\n CurrencyConverter,\n PomodoroTimer,\n WorldClock,\n Stock,\n Preview,\n Documents,\n Files,\n Browser,\n};\n\nexport { BUILTIN_APP_INFO } from './_about';\nexport type { BuiltinAppId, BuiltinAppInfo } from './_about';\nexport { setPdfPreview } from './Preview';\nexport { setSpreadsheetPreview } from './Spreadsheet';\nexport { setBrowserStartUrl } from './Browser';\nexport { openFilesInTrashMode, setFilesDemoTree } from './Files';\nexport type { FilesDemoNode } from './Files';\nexport type { PdfPreviewData, PdfPreviewHandle } from './Preview';\nexport type { SpreadsheetPreviewData, SpreadsheetPreviewHandle } from './Spreadsheet';\n"]}
1
+ {"version":3,"sources":["../../src/apps/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Bundled apps — pre-built window registry entries for the 12 apps that ship\n * with `react-os-shell`. Consumers compose them into their own registry via\n * `createWindowRegistry`:\n *\n * import { createWindowRegistry } from 'react-os-shell';\n * import { bundledApps } from 'react-os-shell/apps';\n * import { erpEntities } from './shell-config';\n *\n * const windows = createWindowRegistry(bundledApps, erpEntities);\n *\n * Subsets are also exported (`utilityApps`, `documentApps`, `webApps`) so a\n * consumer can pick-and-choose without importing every component.\n *\n * NOTE: Notepad requires consumer-supplied persistence for stored content.\n * WorldClock uses `useShellPrefs()` so it lives in `bundledApps`; without a\n * consumer-supplied prefs adapter the city list won't survive a reload.\n */\nimport { lazy } from 'react';\nimport type { WindowRegistry } from '../windowRegistry/types';\n\n// ── Utility apps ──\nconst Calculator = lazy(() => import('./Calculator'));\nconst Spreadsheet = lazy(() => import('./Spreadsheet'));\nconst Weather = lazy(() => import('./Weather'));\nconst CurrencyConverter = lazy(() => import('./CurrencyConverter'));\nconst PomodoroTimer = lazy(() => import('./PomodoroTimer'));\nconst Notepad = lazy(() => import('./Notepad'));\nconst WorldClock = lazy(() => import('./WorldClock'));\nconst Stock = lazy(() => import('./Stock'));\n\n// ── Document apps ──\nconst Preview = lazy(() => import('./Preview'));\nconst Documents = lazy(() => import('./Documents'));\nconst Files = lazy(() => import('./Files'));\n\n// ── Web ──\nconst Browser = lazy(() => import('./Browser'));\n\nexport const utilityApps: WindowRegistry = {\n '/calculator': { component: Calculator, label: 'Calculator', size: 'sm', allowPinOnTop: true, utility: true, widget: true, dimensions: [280, 420] },\n '/spreadsheet': { component: Spreadsheet, label: 'Spreadsheets', size: '2xl', appStyle: true, multiInstance: true },\n '/notepad': { component: Notepad, label: 'Notepad', size: 'lg', allowPinOnTop: true, flushBody: true },\n '/weather': { component: Weather, label: 'Weather', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 400] },\n '/currency': { component: CurrencyConverter, label: 'Currency Converter', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 480] },\n '/pomodoro': { component: PomodoroTimer, label: 'Pomodoro Timer', size: 'sm', utility: true, widget: true, dimensions: [320, 600] },\n '/world-clock': { component: WorldClock, label: 'World Clock', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 480] },\n '/stock': { component: Stock, label: 'Stocks', size: 'sm', utility: true, widget: true, autoHeight: true, dimensions: [320, 360] },\n};\n\nexport const documentApps: WindowRegistry = {\n '/preview': { component: Preview, label: 'Preview', size: '2xl', appStyle: true, multiInstance: true },\n '/documents': { component: Documents, label: 'Documents', size: 'xl', appStyle: true, multiInstance: true },\n '/files': { component: Files, label: 'Files', size: 'xl', appStyle: true },\n};\n\nexport const webApps: WindowRegistry = {\n '/browser': { component: Browser, label: 'Browser', size: '2xl', appStyle: true, multiInstance: true },\n};\n\nexport const bundledApps: WindowRegistry = {\n ...utilityApps,\n ...documentApps,\n ...webApps,\n};\n\nexport {\n Calculator,\n Spreadsheet,\n Notepad,\n Weather,\n CurrencyConverter,\n PomodoroTimer,\n WorldClock,\n Stock,\n Preview,\n Documents,\n Files,\n Browser,\n};\n\nexport { BUILTIN_APP_INFO } from './_about';\nexport type { BuiltinAppId, BuiltinAppInfo } from './_about';\n// Setters/config live in small standalone modules (not the app-implementation\n// files) so importing them here never drags an app chunk — most notably\n// Preview's static pdfjs-dist import — into a host's startup bundle.\nexport { setPdfPreview } from './_previewStage';\nexport { setSpreadsheetPreview } from './_spreadsheetStage';\nexport { setBrowserStartUrl } from './_browserStage';\nexport { openFilesInTrashMode, setFilesDemoTree } from './_filesShared';\nexport type { FilesDemoNode } from './_filesShared';\nexport type { PdfPreviewData, PdfPreviewHandle } from './_previewStage';\nexport type { SpreadsheetPreviewData, SpreadsheetPreviewHandle } from './_spreadsheetStage';\n"]}
@@ -1,11 +1,9 @@
1
+ import { VERSION } from './chunk-WTJY2AEO.js';
1
2
  import { useWindowMenuItem, Modal } from './chunk-ZCL4X6PU.js';
2
3
  import { navIcons } from './chunk-ZF6AYO4G.js';
3
4
  import { useState, useCallback, isValidElement, cloneElement } from 'react';
4
5
  import { jsx, jsxs } from 'react/jsx-runtime';
5
6
 
6
- // src/version.ts
7
- var VERSION = "3.16.2" ;
8
- var APP_VERSION = VERSION;
9
7
  var BUILTIN_APP_INFO = {
10
8
  spreadsheet: {
11
9
  name: "Spreadsheets",
@@ -68,7 +66,7 @@ function AboutApp({ app }) {
68
66
  /* @__PURE__ */ jsx("span", { className: "font-medium text-gray-700", children: "react-os-shell" }),
69
67
  " desktop environment"
70
68
  ] }),
71
- /* @__PURE__ */ jsxs("p", { className: "mt-0.5 text-[10px] font-mono text-gray-400", children: [
69
+ VERSION && /* @__PURE__ */ jsxs("p", { className: "mt-0.5 text-[10px] font-mono text-gray-400", children: [
72
70
  "shell v",
73
71
  VERSION
74
72
  ] })
@@ -76,6 +74,6 @@ function AboutApp({ app }) {
76
74
  ] }) });
77
75
  }
78
76
 
79
- export { APP_VERSION, AboutApp, BUILTIN_APP_INFO, VERSION };
80
- //# sourceMappingURL=chunk-QCGWXJX3.js.map
81
- //# sourceMappingURL=chunk-QCGWXJX3.js.map
77
+ export { AboutApp, BUILTIN_APP_INFO };
78
+ //# sourceMappingURL=chunk-2Q4LCCVB.js.map
79
+ //# sourceMappingURL=chunk-2Q4LCCVB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/apps/_about.tsx"],"names":[],"mappings":";;;;;;AA4BO,IAAM,gBAAA,GAAmB;AAAA,EAC9B,WAAA,EAAa;AAAA,IACX,IAAA,EAAM,cAAA;AAAA,IACN,OAAA,EAAS,OAAA;AAAA,IACT,KAAA,EAAO,cAAA;AAAA,IACP,WAAA,EAAa;AAAA,GACf;AAAA,EACA,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,SAAA;AAAA,IACN,OAAA,EAAS,OAAA;AAAA,IACT,KAAA,EAAO,UAAA;AAAA,IACP,WAAA,EAAa;AAAA,GACf;AAAA,EACA,SAAA,EAAW;AAAA,IACT,IAAA,EAAM,WAAA;AAAA,IACN,OAAA,EAAS,OAAA;AAAA,IACT,KAAA,EAAO,YAAA;AAAA,IACP,WAAA,EAAa;AAAA,GACf;AAAA,EACA,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,SAAA;AAAA,IACN,OAAA,EAAS,OAAA;AAAA,IACT,KAAA,EAAO,UAAA;AAAA,IACP,WAAA,EAAa;AAAA,GACf;AAAA,EACA,KAAA,EAAO;AAAA,IACL,IAAA,EAAM,OAAA;AAAA,IACN,OAAA,EAAS,OAAA;AAAA,IACT,KAAA,EAAO,QAAA;AAAA,IACP,WAAA,EAAa;AAAA,GACf;AAAA,EACA,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,SAAA;AAAA,IACN,OAAA,EAAS,OAAA;AAAA,IACT,KAAA,EAAO,UAAA;AAAA,IACP,WAAA,EAAa;AAAA;AAEjB;AAIA,IAAM,eAAA,uBACH,KAAA,EAAA,EAAI,SAAA,EAAU,yBAAwB,IAAA,EAAK,MAAA,EAAO,SAAQ,WAAA,EAAY,MAAA,EAAO,gBAAe,WAAA,EAAa,GAAA,EACxG,8BAAC,MAAA,EAAA,EAAK,aAAA,EAAc,SAAQ,cAAA,EAAe,OAAA,EAAQ,CAAA,EAAE,oJAAA,EAAqJ,CAAA,EAC5M,CAAA;AAKF,IAAM,iBAAA,uBACH,KAAA,EAAA,EAAI,SAAA,EAAU,WAAU,IAAA,EAAK,MAAA,EAAO,SAAQ,WAAA,EAAY,MAAA,EAAO,gBAAe,WAAA,EAAa,GAAA,EAC1F,8BAAC,MAAA,EAAA,EAAK,aAAA,EAAc,SAAQ,cAAA,EAAe,OAAA,EAAQ,CAAA,EAAE,oIAAA,EAAqI,CAAA,EAC5L,CAAA;AAKa,SAAR,QAAA,CAA0B,EAAE,GAAA,EAAI,EAA0B;AAC/D,EAAA,MAAM,IAAA,GAAO,iBAAiB,GAAG,CAAA;AACjC,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,KAAK,CAAA;AACtC,EAAA,MAAM,aAAa,WAAA,CAAY,MAAM,QAAQ,IAAI,CAAA,EAAG,EAAE,CAAA;AACtD,EAAA,iBAAA,CAAkB,CAAA,MAAA,EAAS,IAAA,CAAK,IAAI,CAAA,CAAA,EAAI,YAAY,eAAe,CAAA;AAEnE,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAElB,EAAA,MAAM,UAAA,GAAa,QAAA,CAAS,IAAA,CAAK,KAAK,CAAA;AACtC,EAAA,MAAM,OAAA,GAAU,cAAA,CAAe,UAAU,CAAA,GACrC,YAAA,CAAa,YAA4B,EAAE,SAAA,EAAW,SAAA,EAAkB,CAAA,GACxE,iBAAA;AAEJ,EAAA,uBACE,GAAA,CAAC,KAAA,EAAA,EAAM,IAAA,EAAI,IAAA,EAAC,OAAA,EAAS,MAAM,OAAA,CAAQ,KAAK,CAAA,EAAG,KAAA,EAAO,CAAA,MAAA,EAAS,IAAA,CAAK,IAAI,CAAA,CAAA,EAAI,IAAA,EAAK,IAAA,EAAK,OAAA,EAAO,IAAA,EAAC,UAAA,EAAY,KAAA,EAAO,UAAA,EAAU,IAAA,EAAC,UAAA,EAAY,CAAC,GAAA,EAAK,GAAG,CAAA,EAC3I,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,uDAAA,EACb,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,2FAAA,EACZ,QAAA,EAAA,OAAA,EACH,CAAA;AAAA,oBACA,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,sCAAA,EAAwC,eAAK,IAAA,EAAK,CAAA;AAAA,oBAChE,IAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,qCAAA,EAAsC,QAAA,EAAA;AAAA,MAAA,UAAA;AAAA,MAAS,IAAA,CAAK;AAAA,KAAA,EAAQ,CAAA;AAAA,oBACzE,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,4CAAA,EAA8C,eAAK,WAAA,EAAY,CAAA;AAAA,oBAC5E,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,2CAAA,EACb,QAAA,EAAA;AAAA,sBAAA,IAAA,CAAC,GAAA,EAAA,EAAE,WAAU,2BAAA,EAA4B,QAAA,EAAA;AAAA,QAAA,cAAA;AAAA,wBAC3B,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,2BAAA,EAA4B,QAAA,EAAA,gBAAA,EAAc,CAAA;AAAA,QAAO;AAAA,OAAA,EAC/E,CAAA;AAAA,MACC,OAAA,oBAAW,IAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,4CAAA,EAA6C,QAAA,EAAA;AAAA,QAAA,SAAA;AAAA,QAAQ;AAAA,OAAA,EAAQ;AAAA,KAAA,EACxF;AAAA,GAAA,EACF,CAAA,EACF,CAAA;AAEJ","file":"chunk-2Q4LCCVB.js","sourcesContent":["/**\n * Shared \"About\" dialog for the bundled apps.\n *\n * Each bundled app carries its own version (independent of the package\n * version) so app-level changes can be tracked without bumping every app at\n * once. `<AboutApp app=\"…\" />` registers an \"About <Name>\" item in the\n * window title menu and renders the dialog: app icon, name, app version and\n * the react-os-shell attribution + shell version.\n *\n * Bump an app's version in `BUILTIN_APP_INFO` whenever that app's behaviour\n * changes, alongside the package-level CHANGELOG entry.\n */\nimport { useCallback, useState, isValidElement, cloneElement, type ReactElement } from 'react';\nimport Modal, { useWindowMenuItem } from '../shell/Modal';\nimport { navIcons } from '../shell-config/nav';\nimport { VERSION } from '../version';\n\nexport interface BuiltinAppInfo {\n /** Display name — matches the window-registry label. */\n name: string;\n /** App version, independent of the package version. */\n version: string;\n /** One-line summary shown in the About dialog. */\n description: string;\n /** Registry route — used to look up the consumer-registered nav icon. */\n route: string;\n}\n\nexport const BUILTIN_APP_INFO = {\n spreadsheet: {\n name: 'Spreadsheets',\n version: '1.1.0',\n route: '/spreadsheet',\n description: 'Multi-sheet spreadsheet editor with CSV / TSV import and export.',\n },\n notepad: {\n name: 'Notepad',\n version: '1.0.0',\n route: '/notepad',\n description: 'Color-coded notes with checklists, desktop stickies and entity autolinking.',\n },\n documents: {\n name: 'Documents',\n version: '1.1.0',\n route: '/documents',\n description: 'Letter-page editor for Word documents and plain-text files — images, lists, alignment.',\n },\n preview: {\n name: 'Preview',\n version: '1.2.1',\n route: '/preview',\n description: 'Viewer for PDF documents, images, DXF drawings and 3D models — CAD-style measuring with object snap and an AutoCAD-like command bar.',\n },\n files: {\n name: 'Files',\n version: '1.1.0',\n route: '/files',\n description: 'Personal file manager with folders, uploads, quota, trash and desktop shortcut folders.',\n },\n browser: {\n name: 'Browser',\n version: '1.0.0',\n route: '/browser',\n description: 'Minimal web browser with bookmarks, history and navigation bar.',\n },\n} satisfies Record<string, BuiltinAppInfo>;\n\nexport type BuiltinAppId = keyof typeof BUILTIN_APP_INFO;\n\nconst ABOUT_MENU_ICON = (\n <svg className=\"h-4 w-4 text-gray-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z\" />\n </svg>\n);\n\n// Generic window glyph shown when the consumer hasn't registered a nav icon\n// for the app's route (same fallback shape as the Modal title bar).\nconst FALLBACK_APP_ICON = (\n <svg className=\"h-9 w-9\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M3.75 6.75A2.25 2.25 0 016 4.5h12a2.25 2.25 0 012.25 2.25v10.5A2.25 2.25 0 0118 19.5H6a2.25 2.25 0 01-2.25-2.25V6.75z M3.75 9h16.5\" />\n </svg>\n);\n\n/** Registers \"About <Name>\" in the window title menu and renders the dialog.\n * Render anywhere inside the app's window. */\nexport default function AboutApp({ app }: { app: BuiltinAppId }) {\n const info = BUILTIN_APP_INFO[app];\n const [open, setOpen] = useState(false);\n const openDialog = useCallback(() => setOpen(true), []);\n useWindowMenuItem(`About ${info.name}`, openDialog, ABOUT_MENU_ICON);\n\n if (!open) return null;\n\n const registered = navIcons[info.route];\n const appIcon = isValidElement(registered)\n ? cloneElement(registered as ReactElement, { className: 'h-9 w-9' } as any)\n : FALLBACK_APP_ICON;\n\n return (\n <Modal open onClose={() => setOpen(false)} title={`About ${info.name}`} size=\"sm\" compact bodyScroll={false} autoHeight dimensions={[320, 320]}>\n <div className=\"flex flex-col items-center text-center px-5 pt-5 pb-4\">\n <div className=\"flex h-16 w-16 items-center justify-center rounded-2xl bg-gray-100 text-gray-600 shrink-0\">\n {appIcon}\n </div>\n <h2 className=\"mt-3 text-lg font-bold text-gray-900\">{info.name}</h2>\n <p className=\"text-[11px] font-mono text-gray-400\">Version {info.version}</p>\n <p className=\"mt-2 text-xs text-gray-500 leading-relaxed\">{info.description}</p>\n <div className=\"mt-4 pt-3 border-t border-gray-200 w-full\">\n <p className=\"text-[11px] text-gray-500\">\n Part of the <span className=\"font-medium text-gray-700\">react-os-shell</span> desktop environment\n </p>\n {VERSION && <p className=\"mt-0.5 text-[10px] font-mono text-gray-400\">shell v{VERSION}</p>}\n </div>\n </div>\n </Modal>\n );\n}\n"]}
@@ -0,0 +1,24 @@
1
+ // src/apps/_spreadsheetStage.ts
2
+ var SPREADSHEET_PREVIEW_UPDATE_EVENT = "react-os-shell:spreadsheet-preview-update";
3
+ var pendingSpreadsheet = null;
4
+ var nextSpreadsheetToken = 0;
5
+ function setSpreadsheetPreview(data) {
6
+ const token = ++nextSpreadsheetToken;
7
+ pendingSpreadsheet = { token, data };
8
+ return {
9
+ update(next) {
10
+ if (typeof window === "undefined") return;
11
+ window.dispatchEvent(new CustomEvent(SPREADSHEET_PREVIEW_UPDATE_EVENT, { detail: { token, data: next } }));
12
+ }
13
+ };
14
+ }
15
+ function peekSpreadsheetPreviewStage() {
16
+ return pendingSpreadsheet;
17
+ }
18
+ function claimSpreadsheetPreviewStage(stage) {
19
+ if (pendingSpreadsheet === stage) pendingSpreadsheet = null;
20
+ }
21
+
22
+ export { SPREADSHEET_PREVIEW_UPDATE_EVENT, claimSpreadsheetPreviewStage, peekSpreadsheetPreviewStage, setSpreadsheetPreview };
23
+ //# sourceMappingURL=chunk-4SQU5YV6.js.map
24
+ //# sourceMappingURL=chunk-4SQU5YV6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/apps/_spreadsheetStage.ts"],"names":[],"mappings":";AA8BO,IAAM,gCAAA,GAAmC;AAQhD,IAAI,kBAAA,GAAqD,IAAA;AACzD,IAAI,oBAAA,GAAuB,CAAA;AAIpB,SAAS,sBAAsB,IAAA,EAAwD;AAC5F,EAAA,MAAM,QAAQ,EAAE,oBAAA;AAChB,EAAA,kBAAA,GAAqB,EAAE,OAAO,IAAA,EAAK;AACnC,EAAA,OAAO;AAAA,IACL,OAAO,IAAA,EAA8B;AACnC,MAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACnC,MAAA,MAAA,CAAO,aAAA,CAAc,IAAI,WAAA,CAAY,gCAAA,EAAkC,EAAE,MAAA,EAAQ,EAAE,KAAA,EAAO,IAAA,EAAM,IAAA,EAAK,EAAG,CAAC,CAAA;AAAA,IAC3G;AAAA,GACF;AACF;AAGO,SAAS,2BAAA,GAA8D;AAC5E,EAAA,OAAO,kBAAA;AACT;AAKO,SAAS,6BAA6B,KAAA,EAAsC;AACjF,EAAA,IAAI,kBAAA,KAAuB,OAAO,kBAAA,GAAqB,IAAA;AACzD","file":"chunk-4SQU5YV6.js","sourcesContent":["/**\n * Spreadsheet staging — the tiny consumer-facing surface of the Spreadsheets\n * app. Lives apart from Spreadsheet.tsx so importing `setSpreadsheetPreview`\n * (from `react-os-shell/apps` or shell internals like openPreviewFile) never\n * drags the grid implementation into a host's startup bundle. The Spreadsheet\n * window component stays behind its React.lazy dynamic import and drains the\n * stage on mount via the @internal peek/claim helpers below.\n */\n\nexport interface SpreadsheetPreviewData {\n /** CSV text (comma- or tab-separated). */\n csv: string;\n /** Display name; the title strips a trailing `.csv`/`.tsv`/`.txt`. */\n filename: string;\n /** When provided, the toolbar shows an Email button that calls back with the\n * sheet serialized as CSV at click time (edits included) and a filename\n * derived from the current title. */\n onEmail?: (csv: string, filename: string) => void;\n}\n\n/** Handle returned by `setSpreadsheetPreview`. Holds the identity of the\n * staged payload so a later `.update()` only targets the window that picked\n * it up — opening a second Spreadsheet never clobbers the first. */\nexport interface SpreadsheetPreviewHandle {\n /** Replace the data shown in the window that consumed this staging.\n * No-op if no window ever consumed it, or if that window has been closed. */\n update(next: SpreadsheetPreviewData): void;\n}\n\n/** @internal Event carrying `.update()` payloads to the claiming window. */\nexport const SPREADSHEET_PREVIEW_UPDATE_EVENT = 'react-os-shell:spreadsheet-preview-update';\n\n/** @internal Staged payload awaiting the next Spreadsheet window mount. */\nexport interface PendingSpreadsheetStage {\n token: number;\n data: SpreadsheetPreviewData;\n}\n\nlet pendingSpreadsheet: PendingSpreadsheetStage | null = null;\nlet nextSpreadsheetToken = 0;\n\n/** Stage CSV content for the next Spreadsheet window mount. The returned\n * handle's `update()` method swaps content in *that* specific window only. */\nexport function setSpreadsheetPreview(data: SpreadsheetPreviewData): SpreadsheetPreviewHandle {\n const token = ++nextSpreadsheetToken;\n pendingSpreadsheet = { token, data };\n return {\n update(next: SpreadsheetPreviewData) {\n if (typeof window === 'undefined') return;\n window.dispatchEvent(new CustomEvent(SPREADSHEET_PREVIEW_UPDATE_EVENT, { detail: { token, data: next } }));\n },\n };\n}\n\n/** @internal Render-phase peek — see Spreadsheet.tsx for the drain protocol. */\nexport function peekSpreadsheetPreviewStage(): PendingSpreadsheetStage | null {\n return pendingSpreadsheet;\n}\n\n/** @internal Commit-phase claim. The identity check keeps a payload staged\n * *after* the claimant's render-phase peek available for the window it\n * belongs to. */\nexport function claimSpreadsheetPreviewStage(stage: PendingSpreadsheetStage): void {\n if (pendingSpreadsheet === stage) pendingSpreadsheet = null;\n}\n"]}
@@ -0,0 +1,16 @@
1
+ // src/apps/_browserStage.ts
2
+ var pendingStartUrl = null;
3
+ var nextStartToken = 0;
4
+ function setBrowserStartUrl(url) {
5
+ pendingStartUrl = { token: ++nextStartToken, url };
6
+ }
7
+ function peekBrowserStartUrl() {
8
+ return pendingStartUrl;
9
+ }
10
+ function claimBrowserStartUrl(stage) {
11
+ if (pendingStartUrl === stage) pendingStartUrl = null;
12
+ }
13
+
14
+ export { claimBrowserStartUrl, peekBrowserStartUrl, setBrowserStartUrl };
15
+ //# sourceMappingURL=chunk-BFBWLCO6.js.map
16
+ //# sourceMappingURL=chunk-BFBWLCO6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/apps/_browserStage.ts"],"names":[],"mappings":";AAeA,IAAI,eAAA,GAA0C,IAAA;AAC9C,IAAI,cAAA,GAAiB,CAAA;AAKd,SAAS,mBAAmB,GAAA,EAAmB;AACpD,EAAA,eAAA,GAAkB,EAAE,KAAA,EAAO,EAAE,cAAA,EAAgB,GAAA,EAAI;AACnD;AAGO,SAAS,mBAAA,GAA8C;AAC5D,EAAA,OAAO,eAAA;AACT;AAKO,SAAS,qBAAqB,KAAA,EAA8B;AACjE,EAAA,IAAI,eAAA,KAAoB,OAAO,eAAA,GAAkB,IAAA;AACnD","file":"chunk-BFBWLCO6.js","sourcesContent":["/**\n * Browser start-URL staging — the tiny consumer-facing surface of the Browser\n * app. Lives apart from Browser.tsx so importing `setBrowserStartUrl` (from\n * `react-os-shell/apps`) never drags the Browser implementation into a host's\n * startup bundle. The Browser window component stays behind its React.lazy\n * dynamic import and drains the stage on mount via the @internal peek/claim\n * helpers below.\n */\n\n/** @internal Staged URL awaiting the next Browser window mount. */\nexport interface PendingStartUrl {\n token: number;\n url: string;\n}\n\nlet pendingStartUrl: PendingStartUrl | null = null;\nlet nextStartToken = 0;\n\n/** Stage a URL for the next Browser window mount — pair with\n * `openPage('/browser')`. Used by \"open this link in the Browser\" flows\n * (e.g. links inside an email body). */\nexport function setBrowserStartUrl(url: string): void {\n pendingStartUrl = { token: ++nextStartToken, url };\n}\n\n/** @internal Render-phase peek — see Browser.tsx for the drain protocol. */\nexport function peekBrowserStartUrl(): PendingStartUrl | null {\n return pendingStartUrl;\n}\n\n/** @internal Commit-phase claim. The identity check keeps a URL staged\n * *after* the claimant's render-phase peek available for the window it\n * belongs to. */\nexport function claimBrowserStartUrl(stage: PendingStartUrl): void {\n if (pendingStartUrl === stage) pendingStartUrl = null;\n}\n"]}
@@ -0,0 +1,24 @@
1
+ // src/apps/_previewStage.ts
2
+ var PDF_PREVIEW_UPDATE_EVENT = "react-os-shell:pdf-preview-update";
3
+ var pending = null;
4
+ var nextToken = 0;
5
+ function setPdfPreview(data) {
6
+ const token = ++nextToken;
7
+ pending = { token, data };
8
+ return {
9
+ update(next) {
10
+ if (typeof window === "undefined") return;
11
+ window.dispatchEvent(new CustomEvent(PDF_PREVIEW_UPDATE_EVENT, { detail: { token, data: next } }));
12
+ }
13
+ };
14
+ }
15
+ function peekPdfPreviewStage() {
16
+ return pending;
17
+ }
18
+ function claimPdfPreviewStage(stage) {
19
+ if (pending === stage) pending = null;
20
+ }
21
+
22
+ export { PDF_PREVIEW_UPDATE_EVENT, claimPdfPreviewStage, peekPdfPreviewStage, setPdfPreview };
23
+ //# sourceMappingURL=chunk-BV6SQ46N.js.map
24
+ //# sourceMappingURL=chunk-BV6SQ46N.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/apps/_previewStage.ts"],"names":[],"mappings":";AA4CO,IAAM,wBAAA,GAA2B;AAQxC,IAAI,OAAA,GAAkC,IAAA;AACtC,IAAI,SAAA,GAAY,CAAA;AAKT,SAAS,cAAc,IAAA,EAAwC;AACpE,EAAA,MAAM,QAAQ,EAAE,SAAA;AAChB,EAAA,OAAA,GAAU,EAAE,OAAO,IAAA,EAAK;AACxB,EAAA,OAAO;AAAA,IACL,OAAO,IAAA,EAAsB;AAC3B,MAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACnC,MAAA,MAAA,CAAO,aAAA,CAAc,IAAI,WAAA,CAAY,wBAAA,EAA0B,EAAE,MAAA,EAAQ,EAAE,KAAA,EAAO,IAAA,EAAM,IAAA,EAAK,EAAG,CAAC,CAAA;AAAA,IACnG;AAAA,GACF;AACF;AAGO,SAAS,mBAAA,GAA8C;AAC5D,EAAA,OAAO,OAAA;AACT;AAKO,SAAS,qBAAqB,KAAA,EAA8B;AACjE,EAAA,IAAI,OAAA,KAAY,OAAO,OAAA,GAAU,IAAA;AACnC","file":"chunk-BV6SQ46N.js","sourcesContent":["/**\n * PDF Preview staging — the tiny consumer-facing surface of the Preview app.\n *\n * Lives apart from Preview.tsx so importing `setPdfPreview` (from\n * `react-os-shell/apps` or shell internals like PdfActionButton /\n * openPreviewFile) never drags the viewer implementation — and its static\n * pdfjs-dist import — into a host's startup bundle. The Preview window\n * component stays behind its React.lazy dynamic import and drains the stage\n * on mount via the @internal peek/claim helpers below.\n */\n\nexport interface PdfPreviewData {\n /** Object URL or remote URL of the PDF. Blob URLs are revoked when the window unmounts.\n * Leave blank when staging a `converting: true` placeholder; call `handle.update({...})`\n * on the handle returned by `setPdfPreview` once conversion finishes. */\n url?: string;\n /** Display name (and download filename). */\n filename: string;\n /** Renderer to use. Defaults to `'pdf'`. `'dxf'` requires the consumer to\n * have `dxf-viewer` installed (it's an optional peer dep). `'image'`\n * renders an `<img>` for raster screenshots / photos. `'3d'` covers\n * STEP / STL / OBJ / GLTF / 3MF / IGES via the optional\n * `online-3d-viewer` peer dep. */\n kind?: 'pdf' | 'dxf' | 'image' | '3d';\n /** Optional download handler — replaces the built-in \"save URL as filename\" if supplied. */\n onDownload?: () => void;\n /** Optional email handler — only shown when supplied. */\n onEmail?: () => void;\n /** Show a progress placeholder while the consumer fetches/converts the file. */\n converting?: boolean;\n /** Headline shown on the converting placeholder (e.g. \"CONVERTING DWG FILE\"). */\n convertingMessage?: string;\n}\n\n/** Handle returned by `setPdfPreview`. Holds the identity of the staged\n * payload so a later `.update()` only targets the window that picked it up\n * (not every open Preview, which would clobber unrelated windows). */\nexport interface PdfPreviewHandle {\n /** Replace the data shown in the window that consumed this staging.\n * No-op if no window ever consumed it, or if that window has been closed. */\n update(next: PdfPreviewData): void;\n}\n\n/** @internal Event carrying `.update()` payloads to the claiming window. */\nexport const PDF_PREVIEW_UPDATE_EVENT = 'react-os-shell:pdf-preview-update';\n\n/** @internal Staged payload awaiting the next Preview window mount. */\nexport interface PendingPdfStage {\n token: number;\n data: PdfPreviewData;\n}\n\nlet pending: PendingPdfStage | null = null;\nlet nextToken = 0;\n\n/** Stage a PDF for the next Preview window mount. The returned handle's\n * `update()` method swaps content in *that* specific window only — use it\n * to replace a `converting: true` placeholder with the resolved file. */\nexport function setPdfPreview(data: PdfPreviewData): PdfPreviewHandle {\n const token = ++nextToken;\n pending = { token, data };\n return {\n update(next: PdfPreviewData) {\n if (typeof window === 'undefined') return;\n window.dispatchEvent(new CustomEvent(PDF_PREVIEW_UPDATE_EVENT, { detail: { token, data: next } }));\n },\n };\n}\n\n/** @internal Render-phase peek — see Preview.tsx for the drain protocol. */\nexport function peekPdfPreviewStage(): PendingPdfStage | null {\n return pending;\n}\n\n/** @internal Commit-phase claim. The identity check keeps a payload staged\n * *after* the claimant's render-phase peek available for the window it\n * belongs to. */\nexport function claimPdfPreviewStage(stage: PendingPdfStage): void {\n if (pending === stage) pending = null;\n}\n"]}
@@ -0,0 +1,98 @@
1
+ import { toast_default } from './chunk-VENYVK3L.js';
2
+ import { setPdfPreview } from './chunk-BV6SQ46N.js';
3
+ import { setSpreadsheetPreview } from './chunk-4SQU5YV6.js';
4
+ import { Fragment } from 'react';
5
+ import { jsx, jsxs } from 'react/jsx-runtime';
6
+
7
+ var DEFAULT_SEPARATOR = /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5 shrink-0 text-gray-300", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": true, children: /* @__PURE__ */ jsx(
8
+ "path",
9
+ {
10
+ fillRule: "evenodd",
11
+ d: "M7.21 14.77a.75.75 0 0 1 .02-1.06L11.168 10 7.23 6.29a.75.75 0 1 1 1.04-1.08l4.5 4.25a.75.75 0 0 1 0 1.08l-4.5 4.25a.75.75 0 0 1-1.06-.02Z",
12
+ clipRule: "evenodd"
13
+ }
14
+ ) });
15
+ function Breadcrumbs({ items, separator, maxItems = 0, className }) {
16
+ if (items.length === 0) return null;
17
+ const sep = separator ?? DEFAULT_SEPARATOR;
18
+ const crumbs = [];
19
+ const lastIndex = items.length - 1;
20
+ if (maxItems > 0 && items.length > maxItems && maxItems >= 2) {
21
+ const tailCount = Math.max(1, maxItems - 1);
22
+ crumbs.push({ kind: "item", item: items[0], isLast: false });
23
+ crumbs.push({ kind: "ellipsis" });
24
+ for (let i = items.length - tailCount; i <= lastIndex; i++) {
25
+ crumbs.push({ kind: "item", item: items[i], isLast: i === lastIndex });
26
+ }
27
+ } else {
28
+ items.forEach((item, i) => crumbs.push({ kind: "item", item, isLast: i === lastIndex }));
29
+ }
30
+ return /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", className: `min-w-0 ${className ?? ""}`, children: /* @__PURE__ */ jsx("ol", { className: "flex items-center gap-1.5 text-sm", children: crumbs.map((crumb, i) => /* @__PURE__ */ jsxs(Fragment, { children: [
31
+ i > 0 && /* @__PURE__ */ jsx("li", { "aria-hidden": true, className: "flex items-center", children: sep }),
32
+ /* @__PURE__ */ jsx("li", { className: "flex min-w-0 items-center", children: crumb.kind === "ellipsis" ? /* @__PURE__ */ jsx("span", { className: "px-0.5 text-gray-400 select-none", "aria-label": "Hidden crumbs", children: "\u2026" }) : crumb.isLast || !crumb.item.onClick ? /* @__PURE__ */ jsxs(
33
+ "span",
34
+ {
35
+ "aria-current": crumb.isLast ? "page" : void 0,
36
+ className: `inline-flex min-w-0 items-center gap-1 truncate ${crumb.isLast ? "font-medium text-gray-900" : "text-gray-500"}`,
37
+ children: [
38
+ crumb.item.icon,
39
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: crumb.item.label })
40
+ ]
41
+ }
42
+ ) : /* @__PURE__ */ jsxs(
43
+ "button",
44
+ {
45
+ type: "button",
46
+ onClick: crumb.item.onClick,
47
+ className: "inline-flex min-w-0 items-center gap-1 truncate rounded px-1 -mx-1 text-gray-500 transition-colors hover:text-gray-900 hover:underline focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-400",
48
+ children: [
49
+ crumb.item.icon,
50
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: crumb.item.label })
51
+ ]
52
+ }
53
+ ) })
54
+ ] }, i)) }) });
55
+ }
56
+
57
+ // src/utils/openPreviewFile.ts
58
+ var PREVIEW_OPENED_EVENT = "react-os-shell:preview-opened";
59
+ function getServer() {
60
+ const override = typeof window !== "undefined" && window.__REACT_OS_SHELL_FILE_SERVER__;
61
+ return (override || "http://localhost:4000").replace(/\/$/, "");
62
+ }
63
+ async function openPreviewFile(opts) {
64
+ const { filePath, filename, kind, onStaged } = opts;
65
+ try {
66
+ const res = await fetch(
67
+ `${getServer()}/api/file?path=${encodeURIComponent(filePath)}`,
68
+ { credentials: "include" }
69
+ );
70
+ if (!res.ok) {
71
+ toast_default.error(`Download failed (${res.status})`);
72
+ return false;
73
+ }
74
+ const blob = await res.blob();
75
+ if (kind === "csv") {
76
+ const text = await blob.text();
77
+ setSpreadsheetPreview({ csv: text, filename });
78
+ onStaged?.("/spreadsheet");
79
+ } else {
80
+ const url = URL.createObjectURL(blob);
81
+ setPdfPreview({ url, filename, kind });
82
+ onStaged?.("/preview");
83
+ }
84
+ if (typeof window !== "undefined") {
85
+ window.dispatchEvent(new CustomEvent(PREVIEW_OPENED_EVENT, {
86
+ detail: { filePath, filename, kind }
87
+ }));
88
+ }
89
+ return true;
90
+ } catch (e) {
91
+ toast_default.error(e?.message || "Open failed");
92
+ return false;
93
+ }
94
+ }
95
+
96
+ export { Breadcrumbs, PREVIEW_OPENED_EVENT, openPreviewFile };
97
+ //# sourceMappingURL=chunk-DINNWYVB.js.map
98
+ //# sourceMappingURL=chunk-DINNWYVB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shell/Breadcrumbs.tsx","../src/utils/openPreviewFile.ts"],"names":[],"mappings":";;;;;;AAgCA,IAAM,iBAAA,mBACJ,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,oCAAA,EAAqC,SAAQ,WAAA,EAAY,IAAA,EAAK,cAAA,EAAe,aAAA,EAAW,IAAA,EACrG,QAAA,kBAAA,GAAA;AAAA,EAAC,MAAA;AAAA,EAAA;AAAA,IACC,QAAA,EAAS,SAAA;AAAA,IACT,CAAA,EAAE,4IAAA;AAAA,IACF,QAAA,EAAS;AAAA;AACX,CAAA,EACF,CAAA;AAKa,SAAR,YAA6B,EAAE,KAAA,EAAO,WAAW,QAAA,GAAW,CAAA,EAAG,WAAU,EAAqB;AACnG,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AAC/B,EAAA,MAAM,MAAM,SAAA,IAAa,iBAAA;AAGzB,EAAA,MAAM,SAAkB,EAAC;AACzB,EAAA,MAAM,SAAA,GAAY,MAAM,MAAA,GAAS,CAAA;AACjC,EAAA,IAAI,WAAW,CAAA,IAAK,KAAA,CAAM,MAAA,GAAS,QAAA,IAAY,YAAY,CAAA,EAAG;AAC5D,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,WAAW,CAAC,CAAA;AAC1C,IAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,MAAM,CAAC,CAAA,EAAG,MAAA,EAAQ,KAAA,EAAO,CAAA;AAC3D,IAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,UAAA,EAAY,CAAA;AAChC,IAAA,KAAA,IAAS,IAAI,KAAA,CAAM,MAAA,GAAS,SAAA,EAAW,CAAA,IAAK,WAAW,CAAA,EAAA,EAAK;AAC1D,MAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,KAAA,CAAM,CAAC,CAAA,EAAG,MAAA,EAAQ,CAAA,KAAM,SAAA,EAAW,CAAA;AAAA,IACvE;AAAA,EACF,CAAA,MAAO;AACL,IAAA,KAAA,CAAM,OAAA,CAAQ,CAAC,IAAA,EAAM,CAAA,KAAM,OAAO,IAAA,CAAK,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,MAAA,EAAQ,CAAA,KAAM,SAAA,EAAW,CAAC,CAAA;AAAA,EACzF;AAEA,EAAA,2BACG,KAAA,EAAA,EAAI,YAAA,EAAW,cAAa,SAAA,EAAW,CAAA,QAAA,EAAW,aAAa,EAAE,CAAA,CAAA,EAChE,8BAAC,IAAA,EAAA,EAAG,SAAA,EAAU,qCACX,QAAA,EAAA,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,EAAO,CAAA,0BACjB,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,IAAA,CAAA,GAAI,qBAAK,GAAA,CAAC,IAAA,EAAA,EAAG,eAAW,IAAA,EAAC,SAAA,EAAU,qBAAqB,QAAA,EAAA,GAAA,EAAI,CAAA;AAAA,oBAC7D,GAAA,CAAC,QAAG,SAAA,EAAU,2BAAA,EACX,gBAAM,IAAA,KAAS,UAAA,uBACb,MAAA,EAAA,EAAK,SAAA,EAAU,oCAAmC,YAAA,EAAW,eAAA,EAAgB,oBAAC,CAAA,GAC7E,KAAA,CAAM,UAAU,CAAC,KAAA,CAAM,KAAK,OAAA,mBAC9B,IAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,cAAA,EAAc,KAAA,CAAM,MAAA,GAAS,MAAA,GAAS,MAAA;AAAA,QACtC,SAAA,EAAW,CAAA,gDAAA,EACT,KAAA,CAAM,MAAA,GAAS,8BAA8B,eAC/C,CAAA,CAAA;AAAA,QAEC,QAAA,EAAA;AAAA,UAAA,KAAA,CAAM,IAAA,CAAK,IAAA;AAAA,8BACX,MAAA,EAAA,EAAK,SAAA,EAAU,UAAA,EAAY,QAAA,EAAA,KAAA,CAAM,KAAK,KAAA,EAAM;AAAA;AAAA;AAAA,KAC/C,mBAEA,IAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAK,QAAA;AAAA,QACL,OAAA,EAAS,MAAM,IAAA,CAAK,OAAA;AAAA,QACpB,SAAA,EAAU,4MAAA;AAAA,QAET,QAAA,EAAA;AAAA,UAAA,KAAA,CAAM,IAAA,CAAK,IAAA;AAAA,8BACX,MAAA,EAAA,EAAK,SAAA,EAAU,UAAA,EAAY,QAAA,EAAA,KAAA,CAAM,KAAK,KAAA,EAAM;AAAA;AAAA;AAAA,KAC/C,EAEJ;AAAA,GAAA,EAAA,EAzBa,CA0Bf,CACD,CAAA,EACH,CAAA,EACF,CAAA;AAEJ;;;ACpEO,IAAM,oBAAA,GAAuB;AAQpC,SAAS,SAAA,GAAY;AACnB,EAAA,MAAM,QAAA,GAAY,OAAO,MAAA,KAAW,WAAA,IAAgB,MAAA,CAAe,8BAAA;AACnE,EAAA,OAAA,CAAQ,QAAA,IAAY,uBAAA,EAAyB,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AAChE;AAEA,eAAsB,gBAAgB,IAAA,EAA6C;AACjF,EAAA,MAAM,EAAE,QAAA,EAAU,QAAA,EAAU,IAAA,EAAM,UAAS,GAAI,IAAA;AAC/C,EAAA,IAAI;AACF,IAAA,MAAM,MAAM,MAAM,KAAA;AAAA,MAChB,GAAG,SAAA,EAAW,CAAA,eAAA,EAAkB,kBAAA,CAAmB,QAAQ,CAAC,CAAA,CAAA;AAAA,MAC5D,EAAE,aAAa,SAAA;AAAU,KAC3B;AACA,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,aAAA,CAAM,KAAA,CAAM,CAAA,iBAAA,EAAoB,GAAA,CAAI,MAAM,CAAA,CAAA,CAAG,CAAA;AAC7C,MAAA,OAAO,KAAA;AAAA,IACT;AACA,IAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,IAAA,EAAK;AAC5B,IAAA,IAAI,SAAS,KAAA,EAAO;AAClB,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,IAAA,EAAK;AAC7B,MAAA,qBAAA,CAAsB,EAAE,GAAA,EAAK,IAAA,EAAM,QAAA,EAAU,CAAA;AAC7C,MAAA,QAAA,GAAW,cAAc,CAAA;AAAA,IAC3B,CAAA,MAAO;AACL,MAAA,MAAM,GAAA,GAAM,GAAA,CAAI,eAAA,CAAgB,IAAI,CAAA;AACpC,MAAA,aAAA,CAAc,EAAE,GAAA,EAAK,QAAA,EAAU,IAAA,EAAM,CAAA;AACrC,MAAA,QAAA,GAAW,UAAU,CAAA;AAAA,IACvB;AACA,IAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,MAAA,MAAA,CAAO,aAAA,CAAc,IAAI,WAAA,CAAiC,oBAAA,EAAsB;AAAA,QAC9E,MAAA,EAAQ,EAAE,QAAA,EAAU,QAAA,EAAU,IAAA;AAAK,OACpC,CAAC,CAAA;AAAA,IACJ;AACA,IAAA,OAAO,IAAA;AAAA,EACT,SAAS,CAAA,EAAQ;AACf,IAAA,aAAA,CAAM,KAAA,CAAM,CAAA,EAAG,OAAA,IAAW,aAAa,CAAA;AACvC,IAAA,OAAO,KAAA;AAAA,EACT;AACF","file":"chunk-DINNWYVB.js","sourcesContent":["import { Fragment } from 'react';\nimport type { ReactNode } from 'react';\n\n/**\n * Generic breadcrumb trail. Self-contained and styled with the same Tailwind\n * utilities the shell already ships, so consumers get it for free.\n *\n * Pass an ordered list of `items` from root → current. Every crumb except the\n * last renders as a button when it has an `onClick`; the last crumb is treated\n * as the current location — rendered inert with `aria-current=\"page\"`. When the\n * trail is long, set `maxItems` to collapse the middle into an ellipsis\n * (`first … last-n` ), keeping the first and the tail visible.\n */\nexport interface BreadcrumbItem {\n /** Visible label. */\n label: ReactNode;\n /** Optional leading icon (typically a 3.5×3.5 svg). */\n icon?: ReactNode;\n /** Navigate to this crumb. Omitted on the current (last) crumb. */\n onClick?: () => void;\n}\n\nexport interface BreadcrumbsProps {\n items: BreadcrumbItem[];\n /** Node rendered between crumbs. Defaults to a chevron. */\n separator?: ReactNode;\n /** Collapse the middle to an ellipsis when there are more than this many\n * crumbs. `0` (default) never collapses. */\n maxItems?: number;\n className?: string;\n}\n\nconst DEFAULT_SEPARATOR = (\n <svg className=\"h-3.5 w-3.5 shrink-0 text-gray-300\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden>\n <path\n fillRule=\"evenodd\"\n d=\"M7.21 14.77a.75.75 0 0 1 .02-1.06L11.168 10 7.23 6.29a.75.75 0 1 1 1.04-1.08l4.5 4.25a.75.75 0 0 1 0 1.08l-4.5 4.25a.75.75 0 0 1-1.06-.02Z\"\n clipRule=\"evenodd\"\n />\n </svg>\n);\n\ntype Crumb = { kind: 'item'; item: BreadcrumbItem; isLast: boolean } | { kind: 'ellipsis' };\n\nexport default function Breadcrumbs({ items, separator, maxItems = 0, className }: BreadcrumbsProps) {\n if (items.length === 0) return null;\n const sep = separator ?? DEFAULT_SEPARATOR;\n\n // Build the display list, collapsing the middle if `maxItems` is exceeded.\n const crumbs: Crumb[] = [];\n const lastIndex = items.length - 1;\n if (maxItems > 0 && items.length > maxItems && maxItems >= 2) {\n const tailCount = Math.max(1, maxItems - 1); // keep the first + this many from the end\n crumbs.push({ kind: 'item', item: items[0], isLast: false });\n crumbs.push({ kind: 'ellipsis' });\n for (let i = items.length - tailCount; i <= lastIndex; i++) {\n crumbs.push({ kind: 'item', item: items[i], isLast: i === lastIndex });\n }\n } else {\n items.forEach((item, i) => crumbs.push({ kind: 'item', item, isLast: i === lastIndex }));\n }\n\n return (\n <nav aria-label=\"Breadcrumb\" className={`min-w-0 ${className ?? ''}`}>\n <ol className=\"flex items-center gap-1.5 text-sm\">\n {crumbs.map((crumb, i) => (\n <Fragment key={i}>\n {i > 0 && <li aria-hidden className=\"flex items-center\">{sep}</li>}\n <li className=\"flex min-w-0 items-center\">\n {crumb.kind === 'ellipsis' ? (\n <span className=\"px-0.5 text-gray-400 select-none\" aria-label=\"Hidden crumbs\">…</span>\n ) : crumb.isLast || !crumb.item.onClick ? (\n <span\n aria-current={crumb.isLast ? 'page' : undefined}\n className={`inline-flex min-w-0 items-center gap-1 truncate ${\n crumb.isLast ? 'font-medium text-gray-900' : 'text-gray-500'\n }`}\n >\n {crumb.item.icon}\n <span className=\"truncate\">{crumb.item.label}</span>\n </span>\n ) : (\n <button\n type=\"button\"\n onClick={crumb.item.onClick}\n className=\"inline-flex min-w-0 items-center gap-1 truncate rounded px-1 -mx-1 text-gray-500 transition-colors hover:text-gray-900 hover:underline focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-400\"\n >\n {crumb.item.icon}\n <span className=\"truncate\">{crumb.item.label}</span>\n </button>\n )}\n </li>\n </Fragment>\n ))}\n </ol>\n </nav>\n );\n}\n","/**\n * Fetch a file from the user's file-server and route it into the right\n * preview window. Shared by the Files app and the desktop Documents\n * folder's shortcut click-through.\n *\n * On success, dispatches `react-os-shell:preview-opened` so Desktop can\n * record the file as a shortcut without this util needing access to the\n * prefs adapter.\n */\nimport toast from '../shell/toast';\nimport { setPdfPreview } from '../apps/_previewStage';\nimport { setSpreadsheetPreview } from '../apps/_spreadsheetStage';\n\nexport type PreviewFileKind = 'pdf' | 'dxf' | '3d' | 'image' | 'csv';\n\nexport interface OpenPreviewFileOpts {\n /** Server-relative path, e.g. \"/reports/Q1.pdf\". */\n filePath: string;\n /** Display name (also used as the download filename). */\n filename: string;\n /** Which viewer to route into. CSV opens in Spreadsheet; the rest open in Preview. */\n kind: PreviewFileKind;\n /** Optional callback invoked after staging the preview, with the route to\n * open (e.g. '/preview' or '/spreadsheet'). The caller is responsible\n * for actually opening the page since the window manager hook is\n * React-scoped. */\n onStaged?: (route: '/preview' | '/spreadsheet') => void;\n}\n\nexport const PREVIEW_OPENED_EVENT = 'react-os-shell:preview-opened';\n\nexport interface PreviewOpenedDetail {\n filePath: string;\n filename: string;\n kind: PreviewFileKind;\n}\n\nfunction getServer() {\n const override = (typeof window !== 'undefined' && (window as any).__REACT_OS_SHELL_FILE_SERVER__) as string | undefined;\n return (override || 'http://localhost:4000').replace(/\\/$/, '');\n}\n\nexport async function openPreviewFile(opts: OpenPreviewFileOpts): Promise<boolean> {\n const { filePath, filename, kind, onStaged } = opts;\n try {\n const res = await fetch(\n `${getServer()}/api/file?path=${encodeURIComponent(filePath)}`,\n { credentials: 'include' },\n );\n if (!res.ok) {\n toast.error(`Download failed (${res.status})`);\n return false;\n }\n const blob = await res.blob();\n if (kind === 'csv') {\n const text = await blob.text();\n setSpreadsheetPreview({ csv: text, filename });\n onStaged?.('/spreadsheet');\n } else {\n const url = URL.createObjectURL(blob);\n setPdfPreview({ url, filename, kind });\n onStaged?.('/preview');\n }\n if (typeof window !== 'undefined') {\n window.dispatchEvent(new CustomEvent<PreviewOpenedDetail>(PREVIEW_OPENED_EVENT, {\n detail: { filePath, filename, kind },\n }));\n }\n return true;\n } catch (e: any) {\n toast.error(e?.message || 'Open failed');\n return false;\n }\n}\n"]}