@jxsuite/studio 3.0.0 → 4.0.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 (173) hide show
  1. package/README.md +5 -5
  2. package/dist/chunks/Overlay.dev-723bv0df.js +23 -0
  3. package/dist/chunks/{cf-settings-zj2cj1ar.js → cf-settings-45fgyx8y.js} +6 -5
  4. package/dist/chunks/{components-z6cnkyy1.js → components-zmx10t62.js} +6 -5
  5. package/dist/chunks/content-source-t88vb2dr.js +49 -0
  6. package/dist/chunks/{convert-to-repeater-6vvx96n2.js → convert-to-repeater-dhw1nrz9.js} +27 -19
  7. package/dist/chunks/entry-commands-6z6bhxg0.js +46 -0
  8. package/dist/chunks/{extension-sections-kwzvpemr.js → extension-sections-3ydgjbdy.js} +32 -24
  9. package/dist/chunks/file-ops-rskmhxyq.js +48 -0
  10. package/dist/chunks/files-0cratsr0.js +92 -0
  11. package/dist/chunks/{format-host-8fr3545e.js → format-host-tgcmfs4p.js} +3 -3
  12. package/dist/chunks/fs-events-hrrg328g.js +21 -0
  13. package/dist/chunks/{git-panel-g01d93vc.js → git-panel-0yywyk76.js} +21 -16
  14. package/dist/chunks/{jx-validate-jj9rnt4n.js → jx-validate-8q2g05x1.js} +6 -4
  15. package/dist/chunks/layers-panel-z3tqe5cd.js +67 -0
  16. package/dist/chunks/layers-q75tj2mf.js +45 -0
  17. package/dist/chunks/lit-html-j055mkh8.js +22 -0
  18. package/dist/chunks/monaco-buffer-dqw0xxpx.js +25 -0
  19. package/dist/chunks/{monaco-setup-a5wkmbgh.js → monaco-setup-rws7k4br.js} +4 -4
  20. package/dist/chunks/notify-yjm79n4s.js +30 -0
  21. package/dist/chunks/parse-24d0gay3.js +19 -0
  22. package/dist/chunks/platform-ba1j1gbh.js +16 -0
  23. package/dist/chunks/publish-panel-54jvhskq.js +28 -0
  24. package/dist/chunks/quick-search-cgfmjwq5.js +65 -0
  25. package/dist/chunks/references-3qx8fkyp.js +29 -0
  26. package/dist/chunks/right-panel-cqp8bc4v.js +46 -0
  27. package/dist/chunks/sp-overlay.dev-yztmtrs1.js +18 -0
  28. package/dist/chunks/sp-popover.dev-n2etmqdp.js +9 -0
  29. package/dist/chunks/sp-progress-circle.dev-hryhj0es.js +15 -0
  30. package/dist/chunks/sp-tooltip.dev-xcvpnqr0.js +15 -0
  31. package/dist/chunks/{sp-tray.dev-64v4pxw8.js → sp-tray.dev-tkbscm06.js} +5 -5
  32. package/dist/chunks/{studio-8ezdegcx.js → studio-1hbqnt19.js} +36 -32
  33. package/dist/chunks/{studio-r5xbtctf.js → studio-2zkz8evn.js} +446 -2451
  34. package/dist/chunks/{studio-pkp61mh8.js → studio-4pqqxbrt.js} +23 -15
  35. package/dist/chunks/{studio-kvfx9z2c.js → studio-4rzyrtjz.js} +70 -31
  36. package/dist/chunks/{studio-3dkcd4c5.js → studio-5q69gfag.js} +60 -56
  37. package/dist/chunks/{studio-rh1cnamv.js → studio-5rywrkxz.js} +563 -133
  38. package/dist/chunks/{studio-6kv3apa9.js → studio-68n67094.js} +25 -9
  39. package/dist/chunks/{studio-0rqqhrdy.js → studio-7nte2hj4.js} +2 -2
  40. package/dist/chunks/{studio-xntfdy1x.js → studio-8swrjbny.js} +31 -18
  41. package/dist/chunks/studio-92ab2jqe.js +282 -0
  42. package/dist/chunks/{studio-sas7mt3k.js → studio-9ab8gqsm.js} +2 -2
  43. package/dist/chunks/{studio-ry1vz5sv.js → studio-9c4k4vhv.js} +15 -13
  44. package/dist/chunks/studio-9n4mrmnb.js +184 -0
  45. package/dist/chunks/{studio-tr20m8g8.js → studio-9r6j5ev1.js} +37 -2
  46. package/dist/chunks/{studio-2x9zbxmx.js → studio-ahjfdy6e.js} +9 -7
  47. package/dist/chunks/{studio-s519zc99.js → studio-bgxt93ga.js} +3 -3
  48. package/dist/chunks/{studio-dc8s8heb.js → studio-cb12yz9w.js} +8528 -8780
  49. package/dist/chunks/studio-cft9r4r7.js +119 -0
  50. package/dist/chunks/{studio-hcxzyk3x.js → studio-eenfkt4e.js} +6 -6
  51. package/dist/chunks/studio-eesa1myv.js +498 -0
  52. package/dist/chunks/{studio-ay8wcr2b.js → studio-eqq1w638.js} +7 -9
  53. package/dist/chunks/{studio-7p35254k.js → studio-ex8zyp98.js} +30 -26
  54. package/dist/chunks/studio-gv8vvshc.js +118 -0
  55. package/dist/chunks/studio-hbtp0eh1.js +1315 -0
  56. package/dist/chunks/{studio-a0yp7syn.js → studio-htsf0w6m.js} +29 -114
  57. package/dist/chunks/{studio-j595e748.js → studio-kjjsjak4.js} +139 -63
  58. package/dist/chunks/{studio-5x5774ak.js → studio-kryvsw6j.js} +3 -3
  59. package/dist/chunks/{studio-kfpek536.js → studio-kyh9avvv.js} +2 -2
  60. package/dist/chunks/{studio-g5gdqnyd.js → studio-kyk2v92a.js} +14 -14
  61. package/dist/chunks/{studio-twsafr1e.js → studio-m3hwn7y1.js} +3 -3
  62. package/dist/chunks/{studio-tzx3xmvx.js → studio-mmv72a27.js} +8 -8
  63. package/dist/chunks/{studio-vhk5fmfv.js → studio-n8b9wqwy.js} +5 -5
  64. package/dist/chunks/{studio-cjm7fdjf.js → studio-p4ngc046.js} +8 -104
  65. package/dist/chunks/{studio-p5dja96s.js → studio-p8j86wag.js} +2 -2
  66. package/dist/chunks/{studio-6z5eyjwn.js → studio-pdfjntbk.js} +66 -129
  67. package/dist/chunks/studio-q43a5y9h.js +394 -0
  68. package/dist/chunks/studio-q7v10cg2.js +106 -0
  69. package/dist/chunks/{studio-2w11grav.js → studio-qq6jym04.js} +3 -3
  70. package/dist/chunks/studio-r1r7afxx.js +1066 -0
  71. package/dist/chunks/{studio-3fk1ac9z.js → studio-rdx8jcxy.js} +4 -4
  72. package/dist/chunks/{studio-4mqb9a0j.js → studio-rn9ta2mz.js} +4 -4
  73. package/dist/chunks/studio-sf7zjgv1.js +91 -0
  74. package/dist/chunks/studio-t7qb9db8.js +665 -0
  75. package/dist/chunks/studio-tmc5emrw.js +8 -0
  76. package/dist/chunks/{studio-wdt9y92a.js → studio-txwkm6p9.js} +2 -2
  77. package/dist/chunks/{studio-k4jvjcfx.js → studio-v38hmvx1.js} +7 -7
  78. package/dist/chunks/{studio-7ejemhej.js → studio-vadzgkrz.js} +6 -6
  79. package/dist/chunks/studio-wcy8trfx.js +263 -0
  80. package/dist/chunks/{studio-5efrtn1m.js → studio-wx5609xd.js} +21 -17
  81. package/dist/chunks/{studio-qpfq7xhm.js → studio-xrapxwwc.js} +22 -285
  82. package/dist/chunks/{studio-hj2se583.js → studio-yxrkyv8a.js} +41 -31
  83. package/dist/chunks/{studio-xm3dbxvn.js → studio-zczps70q.js} +2 -2
  84. package/dist/chunks/workspace-xpres40v.js +89 -0
  85. package/dist/iframe-entry.js +108 -24
  86. package/dist/studio.js +2362 -1695
  87. package/package.json +16 -15
  88. package/src/browse/library-pane.ts +57 -3
  89. package/src/canvas/canvas-render.ts +23 -1
  90. package/src/canvas/iframe-patch.ts +47 -21
  91. package/src/canvas/iframe-render.ts +22 -6
  92. package/src/commands/app-commands.ts +4 -0
  93. package/src/commands/command-args.ts +29 -0
  94. package/src/commands/context.ts +15 -1
  95. package/src/commands/defaults.ts +29 -1
  96. package/src/commands/levels.ts +16 -0
  97. package/src/commands/live-context.ts +3 -0
  98. package/src/content/collection-match.ts +267 -0
  99. package/src/content/entry-commands.ts +38 -29
  100. package/src/content/entry-fields.ts +6 -0
  101. package/src/editor/shortcuts.ts +5 -0
  102. package/src/files/file-ops.ts +10 -42
  103. package/src/files/files.ts +485 -59
  104. package/src/files/fs-events.ts +9 -0
  105. package/src/files/gitignore.ts +432 -0
  106. package/src/files/serialize-document.ts +60 -0
  107. package/src/format/convert-file.ts +511 -0
  108. package/src/format/format-choices.ts +199 -0
  109. package/src/grid/grid-view.ts +16 -2
  110. package/src/media/media-open.ts +58 -0
  111. package/src/media/media-pane.ts +310 -0
  112. package/src/new-project/import-tab.ts +332 -160
  113. package/src/new-project/new-project-modal.ts +27 -34
  114. package/src/packages/ensure-deps.ts +14 -7
  115. package/src/packages/jxsuite-update.ts +11 -11
  116. package/src/page-params.ts +10 -46
  117. package/src/panels/activity-bar.ts +45 -16
  118. package/src/panels/ai-chat/attached-context.ts +6 -1
  119. package/src/panels/ai-chat/chat-view.ts +255 -13
  120. package/src/panels/ai-chat/composer.ts +21 -97
  121. package/src/panels/ai-panel.ts +116 -2
  122. package/src/panels/navigator-panels.ts +7 -6
  123. package/src/panels/settings-menu.ts +799 -0
  124. package/src/panels/toolbar.ts +135 -15
  125. package/src/platforms/cloud.ts +20 -0
  126. package/src/platforms/devserver.ts +67 -33
  127. package/src/preview/preview-overlay.ts +226 -0
  128. package/src/services/ai-ask.ts +247 -0
  129. package/src/services/ai-import-tools.ts +494 -0
  130. package/src/services/ai-project-tools.ts +20 -26
  131. package/src/services/ai-system-prompt.ts +88 -2
  132. package/src/services/ai-turn-signal.ts +70 -0
  133. package/src/services/connection.ts +74 -0
  134. package/src/services/context-manager.ts +89 -0
  135. package/src/services/document-assistant.ts +45 -4
  136. package/src/services/import-client.ts +33 -6
  137. package/src/services/import-run.ts +158 -0
  138. package/src/services/import-seed.ts +120 -0
  139. package/src/services/jx-validate.ts +58 -6
  140. package/src/services/project-adoption.ts +71 -0
  141. package/src/services/references.ts +0 -0
  142. package/src/services/settings/definitions.ts +17 -0
  143. package/src/services/tool-executor.ts +34 -2
  144. package/src/settings/contexts-section.ts +45 -3
  145. package/src/settings/dependencies-editor.ts +43 -23
  146. package/src/settings/general-settings.ts +30 -12
  147. package/src/settings/preferences-dialog.ts +18 -41
  148. package/src/settings/preferences-sections.ts +57 -0
  149. package/src/settings/settings-document.ts +65 -9
  150. package/src/studio.ts +33 -6
  151. package/src/tabs/transact.ts +42 -19
  152. package/src/types.ts +103 -5
  153. package/src/ui/ai-model-picker.ts +162 -0
  154. package/src/ui/choice-field.ts +72 -0
  155. package/src/ui/layers.ts +83 -5
  156. package/src/utils/studio-utils.ts +22 -52
  157. package/styles/forced-colors.css +7 -0
  158. package/styles/overlays.css +256 -0
  159. package/styles/panels.css +13 -1
  160. package/styles/shell.css +111 -0
  161. package/dist/chunks/Overlay.dev-d2ajy6sj.js +0 -23
  162. package/dist/chunks/content-source-7fy9qrm0.js +0 -40
  163. package/dist/chunks/files-xcybanxe.js +0 -70
  164. package/dist/chunks/layers-panel-27essgkc.js +0 -60
  165. package/dist/chunks/publish-panel-09sy2bab.js +0 -22
  166. package/dist/chunks/quick-search-sefb61v8.js +0 -55
  167. package/dist/chunks/right-panel-9r32jd5j.js +0 -39
  168. package/dist/chunks/sp-overlay.dev-s18hymn9.js +0 -18
  169. package/dist/chunks/sp-popover.dev-dj9x7e7a.js +0 -9
  170. package/dist/chunks/sp-progress-circle.dev-0zxcyz3r.js +0 -15
  171. package/dist/chunks/sp-tooltip.dev-5c6d1kjz.js +0 -15
  172. package/dist/chunks/studio-c31yb4t6.js +0 -55
  173. package/src/canvas/site-style-css.ts +0 -117
@@ -0,0 +1,1315 @@
1
+ import {
2
+ errorMessage
3
+ } from "./studio-9n4mrmnb.js";
4
+ import {
5
+ PRIMARY_PANE,
6
+ PROJECT_CONFIG_PATH,
7
+ SECONDARY_PANE,
8
+ argsSchema,
9
+ booleanArg,
10
+ booleanProperty,
11
+ createTab,
12
+ disposeTab,
13
+ enumArg,
14
+ enumProperty,
15
+ focusPane,
16
+ isWellFormedLocale,
17
+ resolveI18n,
18
+ setWorkspaceProject,
19
+ stringArg,
20
+ stringProperty,
21
+ transactDoc,
22
+ workspace
23
+ } from "./studio-2zkz8evn.js";
24
+ import {
25
+ SETTINGS,
26
+ readStoredSetting,
27
+ setSetting
28
+ } from "./studio-92ab2jqe.js";
29
+ import {
30
+ effect,
31
+ effectScope,
32
+ notify,
33
+ pinClock,
34
+ reactive,
35
+ toRaw
36
+ } from "./studio-xrapxwwc.js";
37
+ import {
38
+ projectState,
39
+ requireProjectState,
40
+ setProjectState
41
+ } from "./studio-p4ngc046.js";
42
+ import {
43
+ loadedMonaco
44
+ } from "./studio-eenfkt4e.js";
45
+ import {
46
+ getPlatform
47
+ } from "./studio-9ab8gqsm.js";
48
+ import {
49
+ __require
50
+ } from "./studio-a0tswy0w.js";
51
+
52
+ // src/workspace/session.ts
53
+ var PANE_IDS = new Set([PRIMARY_PANE, SECONDARY_PANE]);
54
+ var SCHEMES = new Set(["auto", "light", "dark"]);
55
+ function uiOf(tab) {
56
+ const { ui } = tab.session;
57
+ return {
58
+ activeMedia: ui.activeMedia,
59
+ canvasMode: ui.canvasMode,
60
+ editZoom: ui.editZoom,
61
+ preview: ui.preview,
62
+ previewColorScheme: ui.previewColorScheme,
63
+ previewLocale: ui.previewLocale,
64
+ showLayout: ui.showLayout,
65
+ zoom: ui.zoom
66
+ };
67
+ }
68
+ function captureSession() {
69
+ const ui = {};
70
+ const panes = [];
71
+ for (const pane of workspace.panes) {
72
+ if (pane.derived) {
73
+ continue;
74
+ }
75
+ const files = [];
76
+ for (const tabId of pane.tabOrder) {
77
+ const tab = workspace.tabs.get(tabId);
78
+ if (!tab?.documentPath) {
79
+ continue;
80
+ }
81
+ files.push(tab.documentPath);
82
+ ui[tab.documentPath] = uiOf(tab);
83
+ }
84
+ if (files.length === 0) {
85
+ continue;
86
+ }
87
+ const activeTab = pane.activeTabId ? workspace.tabs.get(pane.activeTabId) : null;
88
+ panes.push({
89
+ activeFile: activeTab?.documentPath ?? null,
90
+ files,
91
+ id: pane.id
92
+ });
93
+ }
94
+ return { focusedPane: workspace.activePaneId, panes, ui };
95
+ }
96
+ function readTabUi(value) {
97
+ if (typeof value !== "object" || value === null) {
98
+ return {};
99
+ }
100
+ const raw = value;
101
+ const out = {};
102
+ if (typeof raw.canvasMode === "string") {
103
+ out.canvasMode = raw.canvasMode;
104
+ }
105
+ if (typeof raw.preview === "boolean") {
106
+ out.preview = raw.preview;
107
+ }
108
+ if (typeof raw.zoom === "number" && Number.isFinite(raw.zoom)) {
109
+ out.zoom = raw.zoom;
110
+ }
111
+ if (typeof raw.editZoom === "number" && Number.isFinite(raw.editZoom)) {
112
+ out.editZoom = raw.editZoom;
113
+ }
114
+ if (raw.activeMedia === null || typeof raw.activeMedia === "string") {
115
+ out.activeMedia = raw.activeMedia;
116
+ }
117
+ if (typeof raw.previewColorScheme === "string" && SCHEMES.has(raw.previewColorScheme)) {
118
+ out.previewColorScheme = raw.previewColorScheme;
119
+ }
120
+ if (raw.previewLocale === null || isWellFormedLocale(raw.previewLocale)) {
121
+ out.previewLocale = raw.previewLocale;
122
+ }
123
+ if (typeof raw.showLayout === "boolean") {
124
+ out.showLayout = raw.showLayout;
125
+ }
126
+ return out;
127
+ }
128
+ function readSession(value) {
129
+ if (typeof value !== "object" || value === null) {
130
+ return null;
131
+ }
132
+ const raw = value;
133
+ if (!Array.isArray(raw.panes)) {
134
+ return null;
135
+ }
136
+ const panes = [];
137
+ for (const entry of raw.panes) {
138
+ if (typeof entry !== "object" || entry === null) {
139
+ continue;
140
+ }
141
+ const pane = entry;
142
+ if (typeof pane.id !== "string" || !PANE_IDS.has(pane.id)) {
143
+ continue;
144
+ }
145
+ const files = Array.isArray(pane.files) ? pane.files.filter((file) => typeof file === "string" && file !== "") : [];
146
+ if (files.length === 0) {
147
+ continue;
148
+ }
149
+ panes.push({
150
+ activeFile: typeof pane.activeFile === "string" && files.includes(pane.activeFile) ? pane.activeFile : null,
151
+ files,
152
+ id: pane.id
153
+ });
154
+ }
155
+ if (panes.length === 0) {
156
+ return null;
157
+ }
158
+ const ui = {};
159
+ if (typeof raw.ui === "object" && raw.ui !== null) {
160
+ for (const [path, entry] of Object.entries(raw.ui)) {
161
+ ui[path] = readTabUi(entry);
162
+ }
163
+ }
164
+ return {
165
+ focusedPane: typeof raw.focusedPane === "string" && PANE_IDS.has(raw.focusedPane) ? raw.focusedPane : PRIMARY_PANE,
166
+ panes,
167
+ ui
168
+ };
169
+ }
170
+ async function restoreSession(session, deps) {
171
+ let opened = 0;
172
+ if (session.panes.some((pane) => pane.id === SECONDARY_PANE)) {
173
+ deps.ensureSecondPane();
174
+ }
175
+ for (const pane of session.panes) {
176
+ for (const file of pane.files) {
177
+ try {
178
+ await deps.openFile(file, pane.id);
179
+ } catch {}
180
+ if ([...workspace.tabs.values()].some((tab) => tab.documentPath === file)) {
181
+ opened += 1;
182
+ }
183
+ }
184
+ }
185
+ if (opened === 0) {
186
+ return 0;
187
+ }
188
+ for (const tab of workspace.tabs.values()) {
189
+ const stored = tab.documentPath ? session.ui[tab.documentPath] : undefined;
190
+ if (!stored) {
191
+ continue;
192
+ }
193
+ const { ui } = tab.session;
194
+ if (stored.canvasMode && tab.capabilities.modes.includes(stored.canvasMode)) {
195
+ ui.canvasMode = stored.canvasMode;
196
+ }
197
+ if (stored.preview !== undefined) {
198
+ ui.preview = stored.preview;
199
+ }
200
+ if (stored.zoom !== undefined) {
201
+ ui.zoom = stored.zoom;
202
+ }
203
+ if (stored.editZoom !== undefined) {
204
+ ui.editZoom = stored.editZoom;
205
+ }
206
+ if (stored.activeMedia !== undefined) {
207
+ ui.activeMedia = stored.activeMedia;
208
+ }
209
+ if (stored.previewColorScheme !== undefined) {
210
+ ui.previewColorScheme = stored.previewColorScheme;
211
+ }
212
+ if (stored.previewLocale !== undefined) {
213
+ ui.previewLocale = stored.previewLocale;
214
+ }
215
+ if (stored.showLayout !== undefined) {
216
+ ui.showLayout = stored.showLayout;
217
+ }
218
+ }
219
+ for (const stored of session.panes) {
220
+ const pane = workspace.panes.find((p) => p.id === stored.id);
221
+ if (!pane || !stored.activeFile) {
222
+ continue;
223
+ }
224
+ const match = pane.tabOrder.find((tabId) => workspace.tabs.get(tabId)?.documentPath === stored.activeFile);
225
+ if (match) {
226
+ pane.activeTabId = match;
227
+ }
228
+ }
229
+ if (workspace.panes.some((pane) => pane.id === session.focusedPane)) {
230
+ focusPane(session.focusedPane);
231
+ }
232
+ return opened;
233
+ }
234
+
235
+ // src/services/profile.ts
236
+ var STARTUP_PROFILES = {
237
+ default: {
238
+ description: "Resume whatever was persisted — layout, recents, settings, chat history.",
239
+ id: "default",
240
+ reset: "none"
241
+ },
242
+ fresh: {
243
+ description: "A first-run app: no layout, no recents, no settings, no history.",
244
+ id: "fresh",
245
+ reset: "app-state"
246
+ }
247
+ };
248
+ var DEFAULT_PROFILE_ID = "default";
249
+ var OWNED_KEY_PATTERN = /^jx[-._:]/;
250
+ function isStudioStorageKey(key) {
251
+ return OWNED_KEY_PATTERN.test(key);
252
+ }
253
+ function clearStudioStorage() {
254
+ const store = globalThis.localStorage;
255
+ if (!store) {
256
+ return [];
257
+ }
258
+ const doomed = [];
259
+ try {
260
+ for (let i = 0;i < store.length; i++) {
261
+ const key = store.key(i);
262
+ if (key && isStudioStorageKey(key)) {
263
+ doomed.push(key);
264
+ }
265
+ }
266
+ for (const key of doomed) {
267
+ store.removeItem(key);
268
+ }
269
+ } catch {}
270
+ return doomed;
271
+ }
272
+ function applyProfile(id) {
273
+ const profile = STARTUP_PROFILES[id];
274
+ if (!profile) {
275
+ throw new RangeError(`unknown startup profile "${id}"; declared: ${Object.keys(STARTUP_PROFILES).join(", ")}`);
276
+ }
277
+ if (profile.reset === "app-state") {
278
+ clearStudioStorage();
279
+ }
280
+ return profile;
281
+ }
282
+ var _startup = null;
283
+ function applyStartupProfile(search) {
284
+ if (_startup) {
285
+ return _startup;
286
+ }
287
+ const query = new URLSearchParams(search ?? globalThis.location?.search ?? "");
288
+ const profile = applyProfile(query.get("profile") ?? DEFAULT_PROFILE_ID);
289
+ const clockParam = query.get("clock");
290
+ _startup = { clock: clockParam === null ? null : pinClock(clockParam), profile };
291
+ return _startup;
292
+ }
293
+
294
+ // src/shell.ts
295
+ var NAVIGATOR_PANEL_IDS = [
296
+ "files",
297
+ "search",
298
+ "git",
299
+ "i18n",
300
+ "layers",
301
+ "page",
302
+ "data",
303
+ "packages",
304
+ "insert"
305
+ ];
306
+ var RENAMED_PANEL_IDS = {
307
+ blocks: "insert",
308
+ head: "page",
309
+ imports: "packages",
310
+ state: "data"
311
+ };
312
+ var DEFAULT_PANEL_ID = "layers";
313
+ function isNavigatorPanelId(value) {
314
+ return typeof value === "string" && NAVIGATOR_PANEL_IDS.includes(value);
315
+ }
316
+ function requireNavigatorPanelId(value, source) {
317
+ if (!isNavigatorPanelId(value)) {
318
+ throw new Error(`${source}: "${value}" is not a declared Navigator panel id.`);
319
+ }
320
+ return value;
321
+ }
322
+ function migratePanelId(stored) {
323
+ if (typeof stored !== "string") {
324
+ return null;
325
+ }
326
+ const renamed = RENAMED_PANEL_IDS[stored];
327
+ if (renamed) {
328
+ return renamed;
329
+ }
330
+ return isNavigatorPanelId(stored) ? stored : null;
331
+ }
332
+ var INSPECTOR_TAB_IDS = ["properties", "style", "events", "assistant"];
333
+ var DEFAULT_INSPECTOR_TAB = "properties";
334
+ function isInspectorTabId(value) {
335
+ return typeof value === "string" && INSPECTOR_TAB_IDS.includes(value);
336
+ }
337
+ var BOTTOM_TAB_IDS = ["problems", "logic", "activity"];
338
+ var DEFAULT_BOTTOM_TAB = "problems";
339
+ function isBottomTabId(value) {
340
+ return typeof value === "string" && BOTTOM_TAB_IDS.includes(value);
341
+ }
342
+ var CHROME_THEMES = ["light", "dark"];
343
+ var DOCK_STORAGE_KEY = "jx-studio-panel-widths";
344
+ var PROJECT_STORAGE_PREFIX = "jx-studio-project::";
345
+ var DEFAULT_THEME = "dark";
346
+ function isChromeTheme(value) {
347
+ return typeof value === "string" && CHROME_THEMES.includes(value);
348
+ }
349
+ function readPersistedTheme() {
350
+ const stored = readStoredSetting(SETTINGS.theme);
351
+ return isChromeTheme(stored) ? stored : DEFAULT_THEME;
352
+ }
353
+ var DOCK_IDS = ["left", "right", "bottom"];
354
+ var DOCK_DEFAULTS = {
355
+ bottom: { collapsed: true, size: 220 },
356
+ left: { collapsed: false, size: 240 },
357
+ right: { collapsed: false, size: 280 }
358
+ };
359
+ var DOCK_DEFAULT_SIZES = {
360
+ bottom: DOCK_DEFAULTS.bottom.size,
361
+ left: DOCK_DEFAULTS.left.size,
362
+ right: DOCK_DEFAULTS.right.size
363
+ };
364
+ var DOCK_CSS_VAR = {
365
+ bottom: "--dock-h-bottom",
366
+ left: "--panel-w-left",
367
+ right: "--panel-w-right"
368
+ };
369
+ var DOCK_CLASS = {
370
+ bottom: "bottom-collapsed",
371
+ left: "left-collapsed",
372
+ right: "right-collapsed"
373
+ };
374
+ var DEFAULT_PANE_SPLIT = 0.5;
375
+ function clampPaneSplit(value) {
376
+ return typeof value === "number" && value >= 0.2 && value <= 0.8 ? value : DEFAULT_PANE_SPLIT;
377
+ }
378
+ function setPaneSplit(value) {
379
+ shell.paneSplit = Math.min(0.8, Math.max(0.2, value));
380
+ }
381
+ function readPersistedDocks() {
382
+ try {
383
+ return JSON.parse(localStorage.getItem(DOCK_STORAGE_KEY) || "{}");
384
+ } catch {
385
+ return {};
386
+ }
387
+ }
388
+ function freshGit() {
389
+ return {
390
+ branches: null,
391
+ commitMessage: "",
392
+ diffState: null,
393
+ error: null,
394
+ lastUpdated: null,
395
+ loading: false,
396
+ logEntries: null,
397
+ status: null,
398
+ subTab: "changes"
399
+ };
400
+ }
401
+ function freshStylebook() {
402
+ return { customizedOnly: false, filter: "", selection: null, tab: "elements" };
403
+ }
404
+ function builtInLayouts() {
405
+ return [
406
+ {
407
+ bottomTab: "problems",
408
+ docks: {
409
+ bottom: { collapsed: true, size: 220 },
410
+ left: { collapsed: false, size: 240 },
411
+ right: { collapsed: true, size: 280 }
412
+ },
413
+ id: "write",
414
+ inspectorTab: "properties",
415
+ name: "Write",
416
+ navigatorPanel: "files"
417
+ },
418
+ {
419
+ bottomTab: "problems",
420
+ docks: {
421
+ bottom: { collapsed: true, size: 220 },
422
+ left: { collapsed: false, size: 240 },
423
+ right: { collapsed: false, size: 320 }
424
+ },
425
+ id: "design",
426
+ inspectorTab: "style",
427
+ name: "Design",
428
+ navigatorPanel: "layers"
429
+ },
430
+ {
431
+ bottomTab: "logic",
432
+ docks: {
433
+ bottom: { collapsed: true, size: 260 },
434
+ left: { collapsed: false, size: 280 },
435
+ right: { collapsed: false, size: 300 }
436
+ },
437
+ id: "build",
438
+ inspectorTab: "events",
439
+ name: "Build",
440
+ navigatorPanel: "data"
441
+ },
442
+ {
443
+ bottomTab: "activity",
444
+ docks: {
445
+ bottom: { collapsed: false, size: 240 },
446
+ left: { collapsed: false, size: 300 },
447
+ right: { collapsed: true, size: 280 }
448
+ },
449
+ id: "ship",
450
+ inspectorTab: "properties",
451
+ name: "Ship",
452
+ navigatorPanel: "git"
453
+ }
454
+ ];
455
+ }
456
+ var DEFAULT_LAYOUT_ID = "design";
457
+ function createShellState() {
458
+ const saved = readPersistedDocks();
459
+ const docks = {};
460
+ for (const id of DOCK_IDS) {
461
+ const width = saved[id];
462
+ const collapsed = saved[`${id}Collapsed`];
463
+ docks[id] = {
464
+ collapsed: typeof collapsed === "boolean" ? collapsed : DOCK_DEFAULTS[id].collapsed,
465
+ size: typeof width === "number" && width > 0 ? width : DOCK_DEFAULTS[id].size
466
+ };
467
+ }
468
+ return {
469
+ bottomTab: isBottomTabId(saved.bottomTab) ? saved.bottomTab : DEFAULT_BOTTOM_TAB,
470
+ docks,
471
+ focusRegion: "pane",
472
+ paneSplit: clampPaneSplit(saved.paneSplit),
473
+ git: freshGit(),
474
+ layout: DEFAULT_LAYOUT_ID,
475
+ layoutSelection: null,
476
+ layouts: builtInLayouts(),
477
+ leftTab: migratePanelId(saved.leftTab) ?? DEFAULT_PANEL_ID,
478
+ settingsTab: "stylebook",
479
+ stylebook: freshStylebook(),
480
+ theme: readPersistedTheme()
481
+ };
482
+ }
483
+ applyStartupProfile();
484
+ var shell = reactive(createShellState());
485
+ function persistDocks() {
486
+ try {
487
+ localStorage.setItem(DOCK_STORAGE_KEY, JSON.stringify({
488
+ bottom: shell.docks.bottom.size,
489
+ bottomCollapsed: shell.docks.bottom.collapsed,
490
+ bottomTab: shell.bottomTab,
491
+ left: shell.docks.left.size,
492
+ leftCollapsed: shell.docks.left.collapsed,
493
+ leftTab: shell.leftTab,
494
+ paneSplit: shell.paneSplit,
495
+ right: shell.docks.right.size,
496
+ rightCollapsed: shell.docks.right.collapsed
497
+ }));
498
+ } catch {}
499
+ }
500
+ var _layoutRoot;
501
+ function isLayoutPreset(value) {
502
+ if (typeof value !== "object" || value === null) {
503
+ return false;
504
+ }
505
+ const preset = value;
506
+ return typeof preset.id === "string" && preset.id !== "" && typeof preset.name === "string" && isNavigatorPanelId(preset.navigatorPanel) && isInspectorTabId(preset.inspectorTab) && isBottomTabId(preset.bottomTab) && DOCK_IDS.every((dock) => typeof preset.docks?.[dock]?.size === "number");
507
+ }
508
+ function rawPersistedProject(root) {
509
+ if (!root) {
510
+ return {};
511
+ }
512
+ try {
513
+ return JSON.parse(localStorage.getItem(`${PROJECT_STORAGE_PREFIX}${root}`) || "{}");
514
+ } catch {
515
+ return {};
516
+ }
517
+ }
518
+ function readPersistedProject(root) {
519
+ const fresh = { activeLayout: null, layouts: builtInLayouts() };
520
+ if (!root) {
521
+ return fresh;
522
+ }
523
+ const parsed = rawPersistedProject(root);
524
+ const layouts = Array.isArray(parsed.layouts) ? parsed.layouts.filter(isLayoutPreset) : [];
525
+ if (layouts.length === 0) {
526
+ return fresh;
527
+ }
528
+ return {
529
+ activeLayout: typeof parsed.activeLayout === "string" ? parsed.activeLayout : null,
530
+ layouts
531
+ };
532
+ }
533
+ function persistedSession(root) {
534
+ return readSession(rawPersistedProject(root).session);
535
+ }
536
+ var _sessionRoot = null;
537
+ function markSessionRestored(root) {
538
+ _sessionRoot = root;
539
+ }
540
+ function flushSession() {
541
+ persistProjectShell();
542
+ }
543
+ function persistProjectShell() {
544
+ const root = workspace.projectRoot;
545
+ if (!root) {
546
+ return;
547
+ }
548
+ try {
549
+ localStorage.setItem(`${PROJECT_STORAGE_PREFIX}${root}`, JSON.stringify({
550
+ activeLayout: shell.layout,
551
+ layouts: shell.layouts,
552
+ session: root === _sessionRoot ? captureSession() : rawPersistedProject(root).session
553
+ }));
554
+ } catch {}
555
+ }
556
+ function syncProjectLayouts(root) {
557
+ if (root === _layoutRoot) {
558
+ return;
559
+ }
560
+ _layoutRoot = root;
561
+ const { activeLayout, layouts } = readPersistedProject(root);
562
+ shell.layouts = layouts;
563
+ const has = (id) => id !== null && layouts.some((preset) => preset.id === id);
564
+ shell.layout = has(activeLayout) ? activeLayout : has(shell.layout) ? shell.layout : has(DEFAULT_LAYOUT_ID) ? DEFAULT_LAYOUT_ID : layouts[0]?.id ?? DEFAULT_LAYOUT_ID;
565
+ }
566
+ function layoutById(id) {
567
+ return shell.layouts.find((preset) => preset.id === id);
568
+ }
569
+ function layoutIdFor(name) {
570
+ const slug = name.trim().toLowerCase().replaceAll(/[^a-z0-9]+/g, "-").replaceAll(/^-|-$/g, "");
571
+ return slug || "layout";
572
+ }
573
+ function applyLayout(id, deps) {
574
+ const preset = layoutById(id);
575
+ if (!preset) {
576
+ throw new RangeError(`no layout named "${id}" — this project has: ${shell.layouts.map((p) => p.id).join(", ")}`);
577
+ }
578
+ shell.layout = preset.id;
579
+ shell.leftTab = preset.navigatorPanel;
580
+ shell.bottomTab = preset.bottomTab;
581
+ for (const dock of DOCK_IDS) {
582
+ shell.docks[dock].collapsed = preset.docks[dock].collapsed;
583
+ shell.docks[dock].size = preset.docks[dock].size;
584
+ }
585
+ deps.setInspectorTab(preset.inspectorTab);
586
+ persistDocks();
587
+ persistProjectShell();
588
+ }
589
+ function saveLayout(name, deps) {
590
+ const trimmed = name.trim();
591
+ const id = layoutIdFor(trimmed);
592
+ const docks = {};
593
+ for (const dock of DOCK_IDS) {
594
+ docks[dock] = { collapsed: shell.docks[dock].collapsed, size: shell.docks[dock].size };
595
+ }
596
+ const preset = {
597
+ bottomTab: isBottomTabId(shell.bottomTab) ? shell.bottomTab : DEFAULT_BOTTOM_TAB,
598
+ docks,
599
+ id,
600
+ inspectorTab: deps.inspectorTab(),
601
+ name: trimmed || id,
602
+ navigatorPanel: migratePanelId(shell.leftTab) ?? DEFAULT_PANEL_ID
603
+ };
604
+ const existing = shell.layouts.findIndex((entry) => entry.id === id);
605
+ if (existing === -1) {
606
+ shell.layouts.push(preset);
607
+ } else {
608
+ shell.layouts.splice(existing, 1, preset);
609
+ }
610
+ shell.layout = id;
611
+ persistProjectShell();
612
+ return preset;
613
+ }
614
+ function renameLayout(id, name) {
615
+ const preset = layoutById(id);
616
+ const trimmed = name.trim();
617
+ if (!preset || !trimmed) {
618
+ return;
619
+ }
620
+ preset.name = trimmed;
621
+ persistProjectShell();
622
+ }
623
+ function deleteLayout(id) {
624
+ if (shell.layouts.length < 2) {
625
+ return;
626
+ }
627
+ const index = shell.layouts.findIndex((preset) => preset.id === id);
628
+ if (index === -1) {
629
+ return;
630
+ }
631
+ shell.layouts.splice(index, 1);
632
+ if (shell.layout === id) {
633
+ shell.layout = shell.layouts[0].id;
634
+ }
635
+ persistProjectShell();
636
+ }
637
+ function resetLayout(deps) {
638
+ applyLayout(shell.layout, deps);
639
+ }
640
+ function monacoTheme(theme = shell.theme) {
641
+ return theme === "light" ? "vs" : "vs-dark";
642
+ }
643
+ function applyChromeTheme() {
644
+ document.querySelector("sp-theme")?.setAttribute("color", shell.theme);
645
+ document.documentElement.dataset.theme = shell.theme;
646
+ loadedMonaco()?.editor.setTheme(monacoTheme());
647
+ }
648
+ function applyDockLayout() {
649
+ const root = document.documentElement;
650
+ for (const id of DOCK_IDS) {
651
+ root.style.setProperty(DOCK_CSS_VAR[id], `${shell.docks[id].size}px`);
652
+ }
653
+ const app = document.querySelector("#app");
654
+ if (!app) {
655
+ return;
656
+ }
657
+ for (const id of DOCK_IDS) {
658
+ app.classList.toggle(DOCK_CLASS[id], shell.docks[id].collapsed);
659
+ }
660
+ }
661
+ var _scope = null;
662
+ var _surfaces = [];
663
+ function registerShellSurface(surface) {
664
+ if (!_surfaces.includes(surface)) {
665
+ _surfaces.push(surface);
666
+ }
667
+ }
668
+ function mountShell() {
669
+ if (_scope) {
670
+ return;
671
+ }
672
+ for (const surface of _surfaces) {
673
+ surface.mount();
674
+ }
675
+ _scope = effectScope();
676
+ _scope.run(() => {
677
+ effect(() => {
678
+ applyDockLayout();
679
+ });
680
+ effect(() => {
681
+ applyChromeTheme();
682
+ });
683
+ effect(() => {
684
+ syncProjectLayouts(workspace.projectRoot);
685
+ });
686
+ effect(() => {
687
+ const root = workspace.projectRoot;
688
+ workspace.activePaneId;
689
+ for (const pane of workspace.panes) {
690
+ pane.id;
691
+ pane.activeTabId;
692
+ pane.tabOrder.join("\x00");
693
+ }
694
+ if (root) {
695
+ persistProjectShell();
696
+ }
697
+ });
698
+ });
699
+ }
700
+ function setDockCollapsed(dock, collapsed) {
701
+ if (shell.docks[dock].collapsed === collapsed) {
702
+ persistDocks();
703
+ return;
704
+ }
705
+ shell.docks[dock].collapsed = collapsed;
706
+ persistDocks();
707
+ }
708
+ function toggleDock(dock) {
709
+ setDockCollapsed(dock, !shell.docks[dock].collapsed);
710
+ }
711
+ function setDockSize(dock, size) {
712
+ shell.docks[dock].size = size;
713
+ }
714
+ function setActivityTab(tab) {
715
+ shell.leftTab = tab;
716
+ setDockCollapsed("left", false);
717
+ persistDocks();
718
+ }
719
+ function setBottomTab(tab) {
720
+ shell.bottomTab = tab;
721
+ setDockCollapsed("bottom", false);
722
+ persistDocks();
723
+ }
724
+ function setChromeTheme(theme) {
725
+ if (shell.theme === theme) {
726
+ return;
727
+ }
728
+ shell.theme = theme;
729
+ setSetting(SETTINGS.theme, theme);
730
+ }
731
+ function toggleActivityTab(tab) {
732
+ if (tab === shell.leftTab && !shell.docks.left.collapsed) {
733
+ setDockCollapsed("left", true);
734
+ return;
735
+ }
736
+ setActivityTab(tab);
737
+ }
738
+ function setLayoutSelection(selection) {
739
+ shell.layoutSelection = selection;
740
+ }
741
+ function resetProjectShell() {
742
+ Object.assign(shell.git, freshGit());
743
+ Object.assign(shell.stylebook, freshStylebook());
744
+ shell.settingsTab = "stylebook";
745
+ shell.layoutSelection = null;
746
+ _sessionRoot = null;
747
+ _layoutRoot = undefined;
748
+ }
749
+ var projectOpen = (ctx) => ctx.project.open;
750
+ function shellViewCommands(deps) {
751
+ return [
752
+ {
753
+ args: argsSchema({
754
+ tab: enumProperty(NAVIGATOR_PANEL_IDS, "Which Navigator panel to show.")
755
+ }),
756
+ category: "View",
757
+ id: "view.setActivity",
758
+ level: "application",
759
+ menus: ["commandbar/overflow", "palette"],
760
+ group: "4_docks",
761
+ requires: "an open project",
762
+ when: projectOpen,
763
+ aiTool: {
764
+ description: "Show one of the Navigator panels (Files, Search, Source Control, Languages, Outline, " + "Page, Data, Packages, Insert) and open the Navigator dock if it is closed. Languages is " + "the translation-parity grid, and it exists only in a project that declares two or more " + "locales. Problems is a Bottom dock tab — use show_bottom_tab for it.",
765
+ name: "show_navigator_panel"
766
+ },
767
+ run: (_ctx, args) => {
768
+ const tab = enumArg("view.setActivity", args, "tab", NAVIGATOR_PANEL_IDS);
769
+ if (deps.panelAvailable && !deps.panelAvailable(tab)) {
770
+ throw new RangeError(`command "view.setActivity" argument "tab": "${tab}" names a panel that is registered but not ` + `available right now, so showing it would persist a Navigator tab nothing can draw`);
771
+ }
772
+ setActivityTab(tab);
773
+ },
774
+ title: "Show Navigator Panel"
775
+ },
776
+ {
777
+ args: argsSchema({
778
+ tab: enumProperty(INSPECTOR_TAB_IDS, "Which Inspector tab to show.")
779
+ }),
780
+ category: "View",
781
+ id: "view.setRightTab",
782
+ level: "document",
783
+ menus: ["palette"],
784
+ group: "4_docks",
785
+ requires: "an open document",
786
+ when: (ctx) => ctx.document.open,
787
+ run: (_ctx, args) => {
788
+ deps.setInspectorTab(enumArg("view.setRightTab", args, "tab", INSPECTOR_TAB_IDS));
789
+ },
790
+ title: "Show Inspector Tab"
791
+ },
792
+ {
793
+ args: argsSchema({
794
+ open: booleanProperty("True to show the Navigator dock, false to collapse it.")
795
+ }),
796
+ category: "View",
797
+ id: "view.setNavigator",
798
+ level: "application",
799
+ menus: ["palette"],
800
+ group: "4_docks",
801
+ run: (_ctx, args) => {
802
+ setDockCollapsed("left", !booleanArg("view.setNavigator", args, "open"));
803
+ },
804
+ title: "Show Navigator Dock"
805
+ },
806
+ {
807
+ args: argsSchema({
808
+ open: booleanProperty("True to show the Inspector dock, false to collapse it.")
809
+ }),
810
+ category: "View",
811
+ id: "view.setRightPanel",
812
+ level: "application",
813
+ menus: ["palette"],
814
+ group: "4_docks",
815
+ run: (_ctx, args) => {
816
+ setDockCollapsed("right", !booleanArg("view.setRightPanel", args, "open"));
817
+ },
818
+ title: "Show Inspector Dock"
819
+ },
820
+ {
821
+ args: argsSchema({
822
+ open: booleanProperty("True to show the Bottom dock, false to collapse it.")
823
+ }),
824
+ category: "View",
825
+ id: "view.setBottomDock",
826
+ level: "application",
827
+ menus: ["palette"],
828
+ group: "4_docks",
829
+ run: (_ctx, args) => {
830
+ setDockCollapsed("bottom", !booleanArg("view.setBottomDock", args, "open"));
831
+ },
832
+ title: "Show Bottom Dock"
833
+ },
834
+ {
835
+ category: "View",
836
+ id: "view.toggleBottomDock",
837
+ keybinding: "mod+j",
838
+ level: "application",
839
+ menus: ["commandbar/overflow", "palette"],
840
+ group: "4_docks",
841
+ run: () => {
842
+ toggleDock("bottom");
843
+ },
844
+ title: "Toggle Bottom Dock"
845
+ },
846
+ {
847
+ args: argsSchema({
848
+ tab: enumProperty(BOTTOM_TAB_IDS, "Which Bottom dock tab to show.")
849
+ }),
850
+ category: "View",
851
+ id: "view.setBottomTab",
852
+ level: "application",
853
+ menus: ["palette"],
854
+ group: "4_docks",
855
+ aiTool: {
856
+ description: "Show one of the Bottom dock's tabs (Problems, Diff, Logic, Activity) and open the " + "Bottom dock if it is closed.",
857
+ name: "show_bottom_tab"
858
+ },
859
+ run: (_ctx, args) => {
860
+ const tab = enumArg("view.setBottomTab", args, "tab", BOTTOM_TAB_IDS);
861
+ if (deps.panelAvailable && !deps.panelAvailable(tab)) {
862
+ throw new RangeError(`command "view.setBottomTab" argument "tab": "${tab}" names a panel that is registered but not ` + `available right now, so showing it would persist a Bottom dock tab nothing can draw`);
863
+ }
864
+ setBottomTab(tab);
865
+ },
866
+ title: "Show Bottom Dock Tab"
867
+ },
868
+ {
869
+ args: argsSchema({
870
+ open: booleanProperty("True to show the Assistant tab, false to step off it.")
871
+ }),
872
+ category: "View",
873
+ id: "view.setAssistant",
874
+ level: "application",
875
+ menus: ["never"],
876
+ group: "4_docks",
877
+ run: (_ctx, args) => {
878
+ if (booleanArg("view.setAssistant", args, "open")) {
879
+ setDockCollapsed("right", false);
880
+ deps.setInspectorTab("assistant");
881
+ return;
882
+ }
883
+ if (deps.inspectorTab() === "assistant") {
884
+ deps.setInspectorTab(DEFAULT_INSPECTOR_TAB);
885
+ }
886
+ },
887
+ title: "Show Assistant"
888
+ },
889
+ {
890
+ args: argsSchema({
891
+ layout: stringProperty("The layout's id — one of this project's saved layouts.")
892
+ }),
893
+ category: "View",
894
+ id: "view.setLayout",
895
+ level: "application",
896
+ menus: ["palette"],
897
+ group: "4_layouts",
898
+ requires: "an open project",
899
+ when: projectOpen,
900
+ aiTool: {
901
+ description: "Adopt one of the project's named layouts (Write, Design, Build, Ship, or one the user " + "saved): its Navigator panel, its dock widths and visibility, and its Inspector tab.",
902
+ name: "set_layout"
903
+ },
904
+ run: (_ctx, args) => {
905
+ applyLayout(stringArg("view.setLayout", args, "layout"), deps);
906
+ },
907
+ title: "Switch Layout"
908
+ },
909
+ {
910
+ args: argsSchema({
911
+ name: stringProperty("What to call this arrangement. An existing name is overwritten.")
912
+ }),
913
+ category: "View",
914
+ id: "view.saveLayout",
915
+ level: "application",
916
+ menus: ["palette"],
917
+ group: "4_layouts",
918
+ requires: "an open project",
919
+ when: projectOpen,
920
+ run: (_ctx, args) => {
921
+ saveLayout(stringArg("view.saveLayout", args, "name"), deps);
922
+ },
923
+ title: "Save Layout"
924
+ },
925
+ {
926
+ args: argsSchema({
927
+ layout: stringProperty("The layout's id."),
928
+ name: stringProperty("Its new name. The id, and every reference to it, is unchanged.")
929
+ }),
930
+ category: "View",
931
+ id: "view.renameLayout",
932
+ level: "application",
933
+ menus: ["palette"],
934
+ group: "4_layouts",
935
+ requires: "an open project",
936
+ when: projectOpen,
937
+ run: (_ctx, args) => {
938
+ renameLayout(stringArg("view.renameLayout", args, "layout"), stringArg("view.renameLayout", args, "name"));
939
+ },
940
+ title: "Rename Layout"
941
+ },
942
+ {
943
+ args: argsSchema({
944
+ layout: stringProperty("The layout's id. The last remaining layout is kept.")
945
+ }),
946
+ category: "View",
947
+ id: "view.deleteLayout",
948
+ level: "application",
949
+ menus: ["palette"],
950
+ group: "4_layouts",
951
+ requires: "an open project",
952
+ when: projectOpen,
953
+ run: (_ctx, args) => {
954
+ deleteLayout(stringArg("view.deleteLayout", args, "layout"));
955
+ },
956
+ title: "Delete Layout"
957
+ },
958
+ {
959
+ category: "View",
960
+ id: "view.resetLayout",
961
+ level: "application",
962
+ menus: ["palette"],
963
+ group: "4_layouts",
964
+ requires: "an open project",
965
+ when: projectOpen,
966
+ run: () => {
967
+ resetLayout(deps);
968
+ },
969
+ title: "Reset Layout"
970
+ },
971
+ {
972
+ args: argsSchema({
973
+ color: enumProperty(CHROME_THEMES, "The Studio chrome's theme.")
974
+ }),
975
+ category: "View",
976
+ id: "view.setTheme",
977
+ level: "application",
978
+ menus: ["palette"],
979
+ group: "6_appearance",
980
+ run: (_ctx, args) => {
981
+ setChromeTheme(enumArg("view.setTheme", args, "color", CHROME_THEMES));
982
+ },
983
+ title: "Set Theme"
984
+ }
985
+ ];
986
+ }
987
+ function registerShellViewCommands(registry, deps) {
988
+ registry.registerAll(shellViewCommands(deps));
989
+ }
990
+
991
+ // src/tabs/project-config.ts
992
+ function serializeProjectConfig(config) {
993
+ return JSON.stringify(config, null, 2);
994
+ }
995
+ var _bound = null;
996
+ var _detached = null;
997
+ var _committed = null;
998
+ var _seeding = null;
999
+ function openConfigTab() {
1000
+ const tab = workspace.tabs.get(PROJECT_CONFIG_PATH);
1001
+ return tab ? toRaw(tab) : null;
1002
+ }
1003
+ function unbind() {
1004
+ if (_detached) {
1005
+ disposeTab(_detached);
1006
+ _detached = null;
1007
+ }
1008
+ _bound = null;
1009
+ _committed = null;
1010
+ _seeding = null;
1011
+ }
1012
+ function seedCommitted() {
1013
+ _seeding ??= (async () => {
1014
+ try {
1015
+ const text = await getPlatform().readFile(PROJECT_CONFIG_PATH);
1016
+ _committed = serializeProjectConfig(JSON.parse(text));
1017
+ } catch {
1018
+ _committed = null;
1019
+ }
1020
+ })();
1021
+ return _seeding;
1022
+ }
1023
+ function syncProjectState(config) {
1024
+ const state = requireProjectState();
1025
+ if (state.projectConfig === config) {
1026
+ return;
1027
+ }
1028
+ setProjectState({ ...state, projectConfig: config });
1029
+ setWorkspaceProject(workspace.projectRoot, config);
1030
+ }
1031
+ function liveConfig() {
1032
+ const config = requireProjectState()?.projectConfig;
1033
+ return config ? toRaw(config) : null;
1034
+ }
1035
+ function replaceContents(target, source) {
1036
+ for (const key of Object.keys(target)) {
1037
+ if (!Object.hasOwn(source, key)) {
1038
+ delete target[key];
1039
+ }
1040
+ }
1041
+ Object.assign(target, source);
1042
+ }
1043
+ function bind(tab) {
1044
+ _bound = tab;
1045
+ tab.scope.run(() => {
1046
+ effect(() => {
1047
+ const doc = tab.doc.document;
1048
+ if (_bound !== tab || !requireProjectState()) {
1049
+ return;
1050
+ }
1051
+ syncProjectState(toRaw(doc));
1052
+ });
1053
+ });
1054
+ return tab;
1055
+ }
1056
+ function projectConfigDocument() {
1057
+ const state = requireProjectState();
1058
+ const open = openConfigTab();
1059
+ if (_bound && (_bound !== (open ?? _detached) || toRaw(_bound.doc.document) !== state.projectConfig)) {
1060
+ unbind();
1061
+ }
1062
+ if (_bound) {
1063
+ return _bound;
1064
+ }
1065
+ if (open) {
1066
+ return bind(open);
1067
+ }
1068
+ _detached = createTab({
1069
+ document: state.projectConfig ?? {},
1070
+ documentPath: PROJECT_CONFIG_PATH,
1071
+ id: PROJECT_CONFIG_PATH
1072
+ });
1073
+ return bind(_detached);
1074
+ }
1075
+ function extensionsKey(config) {
1076
+ return JSON.stringify(config.extensions ?? null);
1077
+ }
1078
+ async function refreshExtensionSurfaces() {
1079
+ const { loadFormats, refreshExtensionUi, refreshFormats } = await import("./format-host-tgcmfs4p.js");
1080
+ refreshFormats();
1081
+ loadFormats();
1082
+ refreshExtensionUi(getPlatform());
1083
+ }
1084
+ async function commitProjectConfig(patch) {
1085
+ const live = liveConfig();
1086
+ const tab = projectConfigDocument();
1087
+ await seedCommitted();
1088
+ const current = toRaw(tab.doc.document);
1089
+ const currentText = serializeProjectConfig(current);
1090
+ const rival = live && live !== current && serializeProjectConfig(live) !== currentText ? live : null;
1091
+ if (rival && tab.doc.dirty) {
1092
+ const error = new Error(`${PROJECT_CONFIG_PATH} has unsaved changes in its editor tab`);
1093
+ notify.error(`Could not save ${PROJECT_CONFIG_PATH} — the file is open with unsaved changes. Save or ` + `revert that tab, then make the settings change again.`, { key: `save:${PROJECT_CONFIG_PATH}`, path: PROJECT_CONFIG_PATH, source: "Settings" });
1094
+ return { error, ok: false };
1095
+ }
1096
+ const base = rival ?? current;
1097
+ const next = patch ? { ...base, ...patch } : base;
1098
+ const text = serializeProjectConfig(next);
1099
+ if (!rival && !tab.doc.dirty && text === _committed) {
1100
+ return { ok: true };
1101
+ }
1102
+ const before = extensionsKey(current);
1103
+ transactDoc(tab, (t) => {
1104
+ const doc = t.doc.document;
1105
+ if (rival) {
1106
+ replaceContents(doc, rival);
1107
+ }
1108
+ for (const [key, value] of Object.entries(patch ?? {})) {
1109
+ doc[key] = value;
1110
+ }
1111
+ });
1112
+ const config = toRaw(tab.doc.document);
1113
+ const output = serializeProjectConfig(config);
1114
+ try {
1115
+ await getPlatform().writeFile(PROJECT_CONFIG_PATH, output);
1116
+ } catch (error) {
1117
+ notify.error(`Could not save ${PROJECT_CONFIG_PATH} — ${errorMessage(error)}`, {
1118
+ key: `save:${PROJECT_CONFIG_PATH}`,
1119
+ path: PROJECT_CONFIG_PATH,
1120
+ source: "Settings"
1121
+ });
1122
+ return { error, ok: false };
1123
+ }
1124
+ _committed = output;
1125
+ tab.doc.dirty = false;
1126
+ if (extensionsKey(config) !== before) {
1127
+ await refreshExtensionSurfaces();
1128
+ }
1129
+ return { ok: true };
1130
+ }
1131
+ async function adoptProjectConfig(config) {
1132
+ if (!requireProjectState()) {
1133
+ setWorkspaceProject(workspace.projectRoot, config);
1134
+ return;
1135
+ }
1136
+ const tab = projectConfigDocument();
1137
+ transactDoc(tab, (t) => replaceContents(t.doc.document, config), { skipHistory: true });
1138
+ tab.doc.dirty = false;
1139
+ await seedCommitted();
1140
+ _committed = serializeProjectConfig(config);
1141
+ }
1142
+
1143
+ // src/site-context.ts
1144
+ function getEffectiveMedia(docMedia) {
1145
+ const siteMedia = projectState?.projectConfig?.$media;
1146
+ if (!siteMedia) {
1147
+ return docMedia || {};
1148
+ }
1149
+ if (!docMedia) {
1150
+ return { ...siteMedia };
1151
+ }
1152
+ return { ...siteMedia, ...docMedia };
1153
+ }
1154
+ function getEffectiveStyle(docStyle) {
1155
+ const siteStyle = projectState?.projectConfig?.style;
1156
+ if (!siteStyle) {
1157
+ return docStyle || {};
1158
+ }
1159
+ if (!docStyle) {
1160
+ return { ...siteStyle };
1161
+ }
1162
+ const merged = { ...siteStyle };
1163
+ for (const [k, v] of Object.entries(docStyle)) {
1164
+ merged[k] = typeof v === "object" && v !== null && typeof merged[k] === "object" && merged[k] !== null ? { ...merged[k], ...v } : v;
1165
+ }
1166
+ return merged;
1167
+ }
1168
+ function getEffectiveImports(docImports) {
1169
+ const siteImports = projectState?.projectConfig?.imports;
1170
+ if (!siteImports) {
1171
+ return docImports || {};
1172
+ }
1173
+ if (!docImports) {
1174
+ return { ...siteImports };
1175
+ }
1176
+ return { ...siteImports, ...docImports };
1177
+ }
1178
+ function getEffectiveElements(docElements) {
1179
+ const siteElements = projectState?.projectConfig?.$elements;
1180
+ if (!siteElements?.length) {
1181
+ return docElements || [];
1182
+ }
1183
+ if (!docElements?.length) {
1184
+ return [...siteElements];
1185
+ }
1186
+ const seen = new Set;
1187
+ const merged = [];
1188
+ for (const entry of [...siteElements, ...docElements]) {
1189
+ const key = typeof entry === "string" ? entry : entry?.$ref;
1190
+ if (key && !seen.has(key)) {
1191
+ seen.add(key);
1192
+ merged.push(entry);
1193
+ }
1194
+ }
1195
+ return merged;
1196
+ }
1197
+ function getEffectiveHead(docHead) {
1198
+ const siteHead = projectState?.projectConfig?.$head;
1199
+ if (!siteHead?.length) {
1200
+ return docHead || [];
1201
+ }
1202
+ if (!docHead?.length) {
1203
+ return [...siteHead];
1204
+ }
1205
+ const seen = new Set;
1206
+ const merged = [];
1207
+ for (const entry of [...siteHead, ...docHead]) {
1208
+ const key = String(entry?.attributes?.href || entry?.attributes?.src || "") || JSON.stringify(entry);
1209
+ if (!seen.has(key)) {
1210
+ seen.add(key);
1211
+ merged.push(entry);
1212
+ }
1213
+ }
1214
+ return merged;
1215
+ }
1216
+ function getEffectiveLocales() {
1217
+ const config = projectState?.projectConfig;
1218
+ return config ? resolveI18n(config).i18n : null;
1219
+ }
1220
+ var layoutCache = new Map;
1221
+ function invalidateLayoutCache() {
1222
+ layoutCache.clear();
1223
+ }
1224
+ function getEffectiveLayoutPath(docLayout) {
1225
+ if (docLayout === false) {
1226
+ return null;
1227
+ }
1228
+ const defaultLayout = projectState?.projectConfig?.defaults?.layout;
1229
+ return docLayout || defaultLayout || null;
1230
+ }
1231
+ async function resolveLayoutDoc(layoutPath) {
1232
+ const normalized = layoutPath.replace(/^\.\//, "");
1233
+ if (layoutCache.has(normalized)) {
1234
+ return structuredClone(layoutCache.get(normalized));
1235
+ }
1236
+ try {
1237
+ const platform = getPlatform();
1238
+ const content = await platform.readFile(normalized);
1239
+ const doc = JSON.parse(content);
1240
+ layoutCache.set(normalized, doc);
1241
+ return structuredClone(doc);
1242
+ } catch {
1243
+ return null;
1244
+ }
1245
+ }
1246
+ function distributePageIntoLayout(layoutDoc, pageDoc) {
1247
+ const pageChildren = pageDoc.children ?? [];
1248
+ const children = Array.isArray(pageChildren) ? pageChildren : [];
1249
+ const named = new Map;
1250
+ const defaults = [];
1251
+ for (const child of children) {
1252
+ const slotName = typeof child === "object" ? child.attributes?.slot : undefined;
1253
+ if (typeof child === "object" && typeof slotName === "string" && slotName) {
1254
+ if (!named.has(slotName)) {
1255
+ named.set(slotName, []);
1256
+ }
1257
+ named.get(slotName).push(child);
1258
+ } else {
1259
+ defaults.push(child);
1260
+ }
1261
+ }
1262
+ fillSlots(layoutDoc, named, defaults);
1263
+ if (pageDoc.state) {
1264
+ layoutDoc.state = { ...layoutDoc.state, ...pageDoc.state };
1265
+ }
1266
+ if (pageDoc.$media) {
1267
+ layoutDoc.$media = { ...layoutDoc.$media, ...pageDoc.$media };
1268
+ }
1269
+ if (pageDoc.style) {
1270
+ layoutDoc.style = { ...layoutDoc.style, ...pageDoc.style };
1271
+ }
1272
+ if (pageDoc.attributes) {
1273
+ layoutDoc.attributes = { ...layoutDoc.attributes, ...pageDoc.attributes };
1274
+ }
1275
+ return layoutDoc;
1276
+ }
1277
+ function fillSlots(node, named, defaults) {
1278
+ if (!node || typeof node !== "object") {
1279
+ return;
1280
+ }
1281
+ if (!Array.isArray(node.children)) {
1282
+ return;
1283
+ }
1284
+ const newChildren = [];
1285
+ for (const child of node.children) {
1286
+ if (child && typeof child === "object" && child.tagName === "slot") {
1287
+ const slotName = child.attributes?.name;
1288
+ if (typeof slotName === "string" && slotName && named.has(slotName)) {
1289
+ newChildren.push(...named.get(slotName));
1290
+ named.delete(slotName);
1291
+ } else if (!slotName && defaults.length > 0) {
1292
+ newChildren.push(...defaults);
1293
+ } else if (Array.isArray(child.children)) {
1294
+ newChildren.push(...child.children);
1295
+ }
1296
+ } else {
1297
+ if (typeof child !== "string") {
1298
+ fillSlots(child, named, defaults);
1299
+ }
1300
+ newChildren.push(child);
1301
+ }
1302
+ }
1303
+ node.children = newChildren;
1304
+ }
1305
+ async function updateSiteConfig(patch) {
1306
+ const result = await commitProjectConfig(patch);
1307
+ if (!result.ok) {
1308
+ throw result.error;
1309
+ }
1310
+ }
1311
+
1312
+ export { serializeProjectConfig, commitProjectConfig, adoptProjectConfig, getEffectiveMedia, getEffectiveStyle, getEffectiveImports, getEffectiveElements, getEffectiveHead, getEffectiveLocales, invalidateLayoutCache, getEffectiveLayoutPath, resolveLayoutDoc, distributePageIntoLayout, updateSiteConfig, restoreSession, requireNavigatorPanelId, DEFAULT_INSPECTOR_TAB, isInspectorTabId, BOTTOM_TAB_IDS, DEFAULT_BOTTOM_TAB, isBottomTabId, CHROME_THEMES, DOCK_IDS, DOCK_DEFAULT_SIZES, setPaneSplit, shell, persistDocks, persistedSession, markSessionRestored, flushSession, monacoTheme, registerShellSurface, mountShell, setDockCollapsed, setDockSize, setActivityTab, setBottomTab, setChromeTheme, toggleActivityTab, setLayoutSelection, resetProjectShell, registerShellViewCommands };
1313
+
1314
+ //# debugId=A24625062C5DB75E64756E2164756E21
1315
+ //# sourceMappingURL=studio-hbtp0eh1.js.map