@jxsuite/studio 2.2.2 → 2.3.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.
- package/data/css-meta.json +1487 -0
- package/data/elements-meta.json +370 -0
- package/data/html-meta.json +366 -0
- package/data/stylebook-meta.json +200 -0
- package/data/webdata.json +1621 -0
- package/dist/chunks/{Overlay.dev-ymy3et3y.js → Overlay.dev-d2ajy6sj.js} +7 -7
- package/dist/chunks/{content-source-r2n7v682.js → content-source-56xpvx83.js} +13 -12
- package/dist/chunks/{convert-to-repeater-cnpyvj74.js → convert-to-repeater-0xh9wwek.js} +12 -11
- package/dist/chunks/{extension-sections-vpcm4jvx.js → extension-sections-g34239vm.js} +17 -16
- package/dist/chunks/{files-zeg88k2d.js → files-gkz202dp.js} +18 -19
- package/dist/chunks/{format-host-taymsw55.js → format-host-pej3srnw.js} +2 -2
- package/dist/chunks/{git-panel-qp4rrwr9.js → git-panel-4j6xbh8g.js} +12 -11
- package/dist/chunks/{layers-panel-kj93w2zg.js → layers-panel-8mvn8sgd.js} +15 -14
- package/dist/chunks/{monaco-setup-xy3bs05d.js → monaco-setup-a5wkmbgh.js} +6 -3
- package/dist/chunks/{publish-panel-6qz6kp41.js → publish-panel-ptddc3kg.js} +6 -6
- package/dist/chunks/{quick-search-9wwa09hh.js → quick-search-j88azfs2.js} +19 -18
- package/dist/chunks/right-panel-egkaxy89.js +38 -0
- package/dist/chunks/{sp-overlay.dev-h6kdx076.js → sp-overlay.dev-s18hymn9.js} +8 -8
- package/dist/chunks/sp-progress-circle.dev-0zxcyz3r.js +15 -0
- package/dist/chunks/sp-tooltip.dev-5c6d1kjz.js +15 -0
- package/dist/chunks/{studio-753znj4c.js → studio-0e4h32g6.js} +5 -5
- package/dist/chunks/{studio-yz9s88s0.js → studio-10s469da.js} +25 -9
- package/dist/chunks/{studio-6f0am8f2.js → studio-2w11grav.js} +2 -2
- package/dist/chunks/{studio-zqv3w24n.js → studio-3q65xvzv.js} +5 -5
- package/dist/chunks/{studio-qhh8r5fz.js → studio-4058pg09.js} +4 -4
- package/dist/chunks/{studio-hekaagev.js → studio-4enps87v.js} +17 -17
- package/dist/chunks/{studio-tqemhphj.js → studio-50eed4c9.js} +4 -4
- package/dist/chunks/studio-53n8bp04.js +16 -0
- package/dist/chunks/{studio-nqq8jk8f.js → studio-5amdrjm4.js} +14 -14
- package/dist/chunks/{studio-6zzbyx17.js → studio-5ne8mdx9.js} +2 -2
- package/dist/chunks/{studio-3z8jjm2p.js → studio-7ejemhej.js} +3 -3
- package/dist/chunks/{studio-1kgfcv7s.js → studio-a11d3a1b.js} +12 -11
- package/dist/chunks/{studio-rgwcpast.js → studio-ay8wcr2b.js} +2 -2
- package/dist/chunks/{studio-fys6z73y.js → studio-bak2cyjr.js} +7 -7
- package/dist/chunks/{studio-xmvbhg31.js → studio-c31yb4t6.js} +2 -2
- package/dist/chunks/{studio-8sdyjfd6.js → studio-cf4rk7kv.js} +2 -2
- package/dist/chunks/{studio-yphy4z9m.js → studio-cv606rs1.js} +5 -5
- package/dist/chunks/{studio-5kt960pk.js → studio-hk523hby.js} +133 -147
- package/dist/chunks/{studio-x0et2z9g.js → studio-hs8x23fv.js} +15 -15
- package/dist/chunks/{studio-p471gg5n.js → studio-kvfx9z2c.js} +7 -3
- package/dist/chunks/{studio-22xr4q8q.js → studio-ncnet0ba.js} +18 -29
- package/dist/chunks/{studio-ckwz4d3x.js → studio-twsafr1e.js} +2 -2
- package/dist/chunks/{studio-qrsfh1w7.js → studio-tzx3xmvx.js} +5 -5
- package/dist/chunks/{studio-g8t7g0gp.js → studio-vdpcpada.js} +3 -3
- package/dist/chunks/{studio-6a0h7sne.js → studio-vhk5fmfv.js} +2 -2
- package/dist/chunks/{studio-hrajjyt2.js → studio-wdt9y92a.js} +2 -2
- package/dist/chunks/{studio-r8vx7bkz.js → studio-x3etxs0s.js} +14 -13
- package/dist/chunks/{studio-pv8m0h4a.js → studio-yxzgjq8q.js} +28 -23
- package/dist/chunks/{studio-300zsz1k.js → studio-zdkgwhkv.js} +6 -6
- package/dist/codicon.ttf +0 -0
- package/dist/iframe-entry.js +8 -1
- package/dist/manifest.json +82 -0
- package/dist/studio.js +232 -103
- package/index.html +0 -50
- package/package.json +11 -4
- package/src/canvas/iframe-entry.ts +5 -0
- package/src/canvas/iframe-host.ts +45 -4
- package/src/content/entry-editor.ts +2 -1
- package/src/editor/context-menu.ts +13 -2
- package/src/editor/slash-menu.ts +26 -11
- package/src/files/files.ts +11 -23
- package/src/grid/grid-panel.ts +27 -6
- package/src/hosting/document.ts +109 -0
- package/src/hosting/layout.ts +211 -0
- package/src/hosting/stage.ts +166 -0
- package/src/hosting/tsconfig.json +18 -0
- package/src/panels/ai-chat/chat-view.ts +25 -14
- package/src/panels/git-panel.ts +17 -14
- package/src/panels/head-panel.ts +32 -14
- package/src/panels/imports-panel.ts +32 -13
- package/src/panels/layers-panel.ts +9 -1
- package/src/panels/panel-registry.ts +0 -1
- package/src/panels/properties-panel.ts +3 -3
- package/src/panels/settings-pane.ts +1 -1
- package/src/panels/style-panel.ts +3 -3
- package/src/panels/stylebook-panel.ts +10 -1
- package/src/panels/toolbar.ts +1 -1
- package/src/services/bundle-base.ts +69 -0
- package/src/services/monaco-setup.ts +19 -13
- package/src/shell/tree.ts +155 -0
- package/src/shell.ts +0 -2
- package/src/studio.ts +22 -2
- package/src/types.ts +15 -0
- package/src/ui/regions.ts +10 -45
- package/styles/overlays.css +35 -0
- package/dist/chunks/2020-xp8vnwma.js.map +0 -24
- package/dist/chunks/Overlay.dev-ymy3et3y.js.map +0 -9
- package/dist/chunks/adapter-jkcyhgtr.js.map +0 -9
- package/dist/chunks/cf-settings-g5fbf2zp.js.map +0 -9
- package/dist/chunks/components-z6cnkyy1.js.map +0 -9
- package/dist/chunks/content-source-r2n7v682.js.map +0 -9
- package/dist/chunks/convert-to-repeater-cnpyvj74.js.map +0 -10
- package/dist/chunks/editor-cptq5jp1.js.map +0 -9
- package/dist/chunks/extension-sections-vpcm4jvx.js.map +0 -11
- package/dist/chunks/files-zeg88k2d.js.map +0 -9
- package/dist/chunks/flow-qbfgrpeh.js.map +0 -12
- package/dist/chunks/focus-trap.esm-ggawf1hy.js.map +0 -11
- package/dist/chunks/focus-visible-6eg70z18.js.map +0 -10
- package/dist/chunks/format-host-taymsw55.js.map +0 -9
- package/dist/chunks/git-panel-qp4rrwr9.js.map +0 -9
- package/dist/chunks/index-nj44jpzj.js.map +0 -14
- package/dist/chunks/index-zqxmqxmh.js.map +0 -9
- package/dist/chunks/javascript-q8kpmfah.js.map +0 -11
- package/dist/chunks/jsonMode-dkr040ga.js.map +0 -18
- package/dist/chunks/jx-validate-jj9rnt4n.js.map +0 -9
- package/dist/chunks/layers-panel-kj93w2zg.js.map +0 -9
- package/dist/chunks/monaco-binding-rj6xpx9y.js.map +0 -10
- package/dist/chunks/monaco-setup-xy3bs05d.js.map +0 -15
- package/dist/chunks/publish-panel-6qz6kp41.js.map +0 -9
- package/dist/chunks/quick-search-9wwa09hh.js.map +0 -9
- package/dist/chunks/right-panel-faf816ch.js +0 -37
- package/dist/chunks/right-panel-faf816ch.js.map +0 -9
- package/dist/chunks/section-registry-sx1ykvkw.js.map +0 -9
- package/dist/chunks/sp-overlay.dev-h6kdx076.js.map +0 -9
- package/dist/chunks/sp-popover.dev-dj9x7e7a.js.map +0 -9
- package/dist/chunks/sp-progress-circle.dev-0fpvhm52.js +0 -15
- package/dist/chunks/sp-progress-circle.dev-0fpvhm52.js.map +0 -9
- package/dist/chunks/sp-tooltip.dev-rvepkw4r.js +0 -15
- package/dist/chunks/sp-tooltip.dev-rvepkw4r.js.map +0 -9
- package/dist/chunks/sp-tray.dev-64v4pxw8.js.map +0 -12
- package/dist/chunks/studio-0a5qrh01.js.map +0 -9
- package/dist/chunks/studio-0rqqhrdy.js.map +0 -12
- package/dist/chunks/studio-18j3bmcz.js.map +0 -10
- package/dist/chunks/studio-1kgfcv7s.js.map +0 -13
- package/dist/chunks/studio-22xr4q8q.js.map +0 -13
- package/dist/chunks/studio-300zsz1k.js.map +0 -39
- package/dist/chunks/studio-3fk1ac9z.js.map +0 -12
- package/dist/chunks/studio-3n4ndrzh.js.map +0 -41
- package/dist/chunks/studio-3z8jjm2p.js.map +0 -13
- package/dist/chunks/studio-4mqb9a0j.js.map +0 -14
- package/dist/chunks/studio-4q0wznzf.js.map +0 -73
- package/dist/chunks/studio-5ehhackm.js.map +0 -10
- package/dist/chunks/studio-5kt960pk.js.map +0 -38
- package/dist/chunks/studio-5x5774ak.js.map +0 -10
- package/dist/chunks/studio-685s0ytq.js.map +0 -76
- package/dist/chunks/studio-6a0h7sne.js.map +0 -15
- package/dist/chunks/studio-6f0am8f2.js.map +0 -10
- package/dist/chunks/studio-6kv3apa9.js.map +0 -10
- package/dist/chunks/studio-6zzbyx17.js.map +0 -12
- package/dist/chunks/studio-753znj4c.js.map +0 -16
- package/dist/chunks/studio-7afd21nw.js.map +0 -10
- package/dist/chunks/studio-8jpzqk5s.js.map +0 -10
- package/dist/chunks/studio-8q517dfr.js.map +0 -10
- package/dist/chunks/studio-8sdyjfd6.js.map +0 -10
- package/dist/chunks/studio-a0tswy0w.js.map +0 -9
- package/dist/chunks/studio-a7pzveq1.js.map +0 -11
- package/dist/chunks/studio-ahnzd9rg.js.map +0 -10
- package/dist/chunks/studio-b9b6t1dg.js.map +0 -651
- package/dist/chunks/studio-bw5dz6km.js.map +0 -21
- package/dist/chunks/studio-cjm7fdjf.js.map +0 -14
- package/dist/chunks/studio-ckwz4d3x.js.map +0 -12
- package/dist/chunks/studio-d1ks410h.js.map +0 -10
- package/dist/chunks/studio-dg7zyt5x.js.map +0 -10
- package/dist/chunks/studio-fys6z73y.js.map +0 -10
- package/dist/chunks/studio-g1wdche0.js.map +0 -56
- package/dist/chunks/studio-g8t7g0gp.js.map +0 -10
- package/dist/chunks/studio-h4rxscfc.js.map +0 -10
- package/dist/chunks/studio-hekaagev.js.map +0 -18
- package/dist/chunks/studio-hrajjyt2.js.map +0 -10
- package/dist/chunks/studio-nqq8jk8f.js.map +0 -14
- package/dist/chunks/studio-p471gg5n.js.map +0 -14
- package/dist/chunks/studio-pv8m0h4a.js.map +0 -98
- package/dist/chunks/studio-qhh8r5fz.js.map +0 -13
- package/dist/chunks/studio-qrsfh1w7.js.map +0 -41
- package/dist/chunks/studio-r8vx7bkz.js.map +0 -235
- package/dist/chunks/studio-rgwcpast.js.map +0 -12
- package/dist/chunks/studio-s519zc99.js.map +0 -10
- package/dist/chunks/studio-sas7mt3k.js.map +0 -10
- package/dist/chunks/studio-t5wqwzdh.js.map +0 -10
- package/dist/chunks/studio-tqemhphj.js.map +0 -11
- package/dist/chunks/studio-tr20m8g8.js.map +0 -9
- package/dist/chunks/studio-tvgyw9xw.js.map +0 -14
- package/dist/chunks/studio-x0et2z9g.js.map +0 -32
- package/dist/chunks/studio-xm3dbxvn.js.map +0 -19
- package/dist/chunks/studio-xmvbhg31.js.map +0 -10
- package/dist/chunks/studio-ynxwkrzd.js.map +0 -246
- package/dist/chunks/studio-yphy4z9m.js.map +0 -10
- package/dist/chunks/studio-yz9s88s0.js.map +0 -54
- package/dist/chunks/studio-z6nw2ek2.js.map +0 -10
- package/dist/chunks/studio-zqv3w24n.js.map +0 -11
- package/dist/chunks/tsMode-76kr53q0.js.map +0 -13
- package/dist/chunks/ws-client-6shc5rze.js.map +0 -12
|
@@ -742,7 +742,15 @@ export function onTreeKeydown(
|
|
|
742
742
|
*/
|
|
743
743
|
export function startLayerTitleEdit(path: JxPath, rerender: () => void) {
|
|
744
744
|
const key = pathKey(path);
|
|
745
|
-
|
|
745
|
+
/* Scoped to THIS panel's tree, and escaped, through the same helper every other row lookup in
|
|
746
|
+
this file uses. The predecessor was a bare `document.querySelector` with the key interpolated
|
|
747
|
+
raw, which is wrong twice over: a second pane — or the stylebook, which draws a layer tree of
|
|
748
|
+
its own — puts more than one `.layer-row[data-path=…]` in the document, and the first match
|
|
749
|
+
wins rather than the right one; and an unescaped key containing a quote or a bracket is not a
|
|
750
|
+
selector the parser accepts, so a legitimately-named node throws instead of renaming.
|
|
751
|
+
`_outlineList` is null before the first render, which is the same "row the window does not
|
|
752
|
+
hold" case the reveal-and-repaint path below already handles. */
|
|
753
|
+
const row = _outlineList ? rowElementFor(_outlineList, key) : null;
|
|
746
754
|
if (!row) {
|
|
747
755
|
// Renaming through a command (⌘↵, the palette, the block bar) can name a row the window does
|
|
748
756
|
// Not hold. Scroll to it and repaint; the row exists on the next pass, and the caller's own
|
|
@@ -83,7 +83,6 @@ export interface NavigatorPanelDeps {
|
|
|
83
83
|
registerLayersDnD: () => void;
|
|
84
84
|
registerElementsDnD: () => void;
|
|
85
85
|
registerComponentsDnD: () => void;
|
|
86
|
-
setupTreeKeyboard: (tree: HTMLElement) => void;
|
|
87
86
|
registerFileTreeDnD: (ctx: { renderLeftPanel: () => void }) => void;
|
|
88
87
|
setGitDiffState: (state: GitDiffState | null) => void;
|
|
89
88
|
cloneRepository?: () => void;
|
|
@@ -544,7 +544,7 @@ function renderLinkTargetField(node: JxMutableNode, path: JxPath) {
|
|
|
544
544
|
<sp-picker
|
|
545
545
|
class="link-target-kind"
|
|
546
546
|
size="s"
|
|
547
|
-
value=${kind}
|
|
547
|
+
.value=${live(kind)}
|
|
548
548
|
@change=${(e: Event) => {
|
|
549
549
|
const nextKind = (e.target as HTMLInputElement).value as LinkKind;
|
|
550
550
|
// Switching kind reinterprets the current value under the new kind.
|
|
@@ -566,7 +566,7 @@ function renderLinkTargetField(node: JxMutableNode, path: JxPath) {
|
|
|
566
566
|
<sp-picker
|
|
567
567
|
class="link-target-value"
|
|
568
568
|
size="s"
|
|
569
|
-
value=${value}
|
|
569
|
+
.value=${live(value)}
|
|
570
570
|
@change=${(e: Event) => commit("internal", (e.target as HTMLInputElement).value)}
|
|
571
571
|
>
|
|
572
572
|
${knownValue ? html`<sp-menu-item value=${value}>${value}</sp-menu-item>` : nothing}
|
|
@@ -624,7 +624,7 @@ function renderTargetField(node: JxMutableNode, path: JxPath, entry: HtmlMetaEnt
|
|
|
624
624
|
<sp-picker
|
|
625
625
|
class="link-target-window"
|
|
626
626
|
size="s"
|
|
627
|
-
value=${current}
|
|
627
|
+
.value=${live(current)}
|
|
628
628
|
@change=${(e: Event) =>
|
|
629
629
|
transactDoc(activeTab.value!, (t) =>
|
|
630
630
|
mutateUpdateAttribute(
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* `settings/settings-document.ts`, which the app loads when it registers its commands.
|
|
19
19
|
*
|
|
20
20
|
* Nothing here is stamped with a region of its own. `#canvas-wrap` already carries `pane.primary`
|
|
21
|
-
* (`
|
|
21
|
+
* (the frame, `shell/tree.ts`), the entry rows and the entry editor are stamped by
|
|
22
22
|
* `settings/contributed-section.ts` as `pane.primary/entry:<key>` and `pane.primary/editor`, and a
|
|
23
23
|
* third id for "the settings body" would be a hand-stamped region with nothing to say.
|
|
24
24
|
*
|
|
@@ -1215,7 +1215,7 @@ function styleSidebarTemplate(
|
|
|
1215
1215
|
return html`
|
|
1216
1216
|
<sp-accordion-item
|
|
1217
1217
|
label=${sec.label}
|
|
1218
|
-
.open=${isOpen}
|
|
1218
|
+
.open=${live(isOpen)}
|
|
1219
1219
|
@sp-accordion-item-toggle=${(e: Event) => {
|
|
1220
1220
|
activeTab.value!.session.ui.styleSections = {
|
|
1221
1221
|
...activeTab.value!.session.ui.styleSections,
|
|
@@ -1235,7 +1235,7 @@ function styleSidebarTemplate(
|
|
|
1235
1235
|
const customSectionT = html`
|
|
1236
1236
|
<sp-accordion-item
|
|
1237
1237
|
label="Custom"
|
|
1238
|
-
.open=${customIsOpen}
|
|
1238
|
+
.open=${live(customIsOpen)}
|
|
1239
1239
|
@sp-accordion-item-toggle=${(e: Event) => {
|
|
1240
1240
|
activeTab.value!.session.ui.styleSections = {
|
|
1241
1241
|
...activeTab.value!.session.ui.styleSections,
|
|
@@ -1319,7 +1319,7 @@ function styleSidebarTemplate(
|
|
|
1319
1319
|
? html`
|
|
1320
1320
|
<sp-accordion-item
|
|
1321
1321
|
label="Relative Styling"
|
|
1322
|
-
.open=${nestedIsOpen}
|
|
1322
|
+
.open=${live(nestedIsOpen)}
|
|
1323
1323
|
@sp-accordion-item-toggle=${(e: Event) => {
|
|
1324
1324
|
activeTab.value!.session.ui.styleSections = {
|
|
1325
1325
|
...activeTab.value!.session.ui.styleSections,
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { html, render as litRender } from "lit-html";
|
|
17
|
+
import { repeat } from "lit-html/directives/repeat.js";
|
|
17
18
|
import { ref } from "lit-html/directives/ref.js";
|
|
18
19
|
import { classMap } from "lit-html/directives/class-map.js";
|
|
19
20
|
import { live } from "lit-html/directives/live.js";
|
|
@@ -169,7 +170,15 @@ export function renderStylebookMode(surface: CanvasSurface, ctx: StylebookCtx) {
|
|
|
169
170
|
}
|
|
170
171
|
})}
|
|
171
172
|
>
|
|
172
|
-
${
|
|
173
|
+
${repeat(
|
|
174
|
+
panelEntries,
|
|
175
|
+
/* Keyed on mediaName. Each entry owns a canvas IFRAME, and the breakpoint set changes
|
|
176
|
+
with the project's media definitions — so position-based reuse hands one breakpoint's
|
|
177
|
+
iframe to another's width. That is a live document rendered at the wrong viewport,
|
|
178
|
+
not a cosmetic diff. */
|
|
179
|
+
(e) => e.panel.mediaName,
|
|
180
|
+
(e) => e.tpl,
|
|
181
|
+
)}
|
|
173
182
|
</div>
|
|
174
183
|
`,
|
|
175
184
|
/** @type {HTMLElement} */ canvasWrap,
|
package/src/panels/toolbar.ts
CHANGED
|
@@ -644,7 +644,7 @@ function dockTogglesTpl(registry: CommandRegistry) {
|
|
|
644
644
|
/**
|
|
645
645
|
* Mount the Command Bar.
|
|
646
646
|
*
|
|
647
|
-
* @param rootEl The `#toolbar` host, stamped `commandbar` by `
|
|
647
|
+
* @param rootEl The `#toolbar` host, stamped `commandbar` by the frame (`shell/tree.ts`).
|
|
648
648
|
* @param _ctx Ignored — see {@link ToolbarCtx}.
|
|
649
649
|
*/
|
|
650
650
|
export function mount(rootEl: HTMLElement, _ctx: ToolbarCtx = {}) {
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the studio bundle was loaded from — the one fact a shipped asset can be located against.
|
|
3
|
+
*
|
|
4
|
+
* `import.meta.url` is NOT that fact, and the difference has been shipping a silent bug. Only the
|
|
5
|
+
* two ENTRIES are guaranteed to be emitted at `dist/<name>.js` (studio.md §11.1 — four consumers
|
|
6
|
+
* address those paths literally, so they are never hashed). Every other module is subject to
|
|
7
|
+
* `splitting: true` and may be hoisted into a content-hashed chunk under `dist/chunks/` — and
|
|
8
|
+
* `services/monaco-setup` was, by the code-split in 78d85ba2. Its `new URL("workers/…",
|
|
9
|
+
* import.meta.url)` therefore resolved against `dist/chunks/`, while all three distribution paths
|
|
10
|
+
* stage the workers beside the ENTRY. Verified in the built output: the string `workers/` appears
|
|
11
|
+
* in `dist/chunks/monaco-setup-<hash>.js` and in neither `dist/studio.js` nor
|
|
12
|
+
* `dist/iframe-entry.js`, and `dist/chunks/workers/` does not exist.
|
|
13
|
+
*
|
|
14
|
+
* The failure mode is why this is worth a module rather than a comment: a Monaco worker that 404s
|
|
15
|
+
* takes the whole JSON language service with it — no schema validation, no completion, no hover —
|
|
16
|
+
* and reports nothing. Nobody sees a red anything.
|
|
17
|
+
*
|
|
18
|
+
* So the entries publish their own location and everything else reads it. The base is the entry's
|
|
19
|
+
* DIRECTORY, so `bundleUrl("workers/json.worker.js")` lands beside the entry on every host without
|
|
20
|
+
* the host being asked for anything: `/packages/studio/dist/` on the repo dev server,
|
|
21
|
+
* `views://studio/dist/` in the packaged app, `/__studio__/dist/` on the desktop loopback server,
|
|
22
|
+
* and whatever prefix a cloud host staged the tree under.
|
|
23
|
+
*
|
|
24
|
+
* **Only an entry may call {@link setBundleBase}.** `tests/entry-anchors.test.ts` enforces both
|
|
25
|
+
* halves — that both entries call it, and that no other module under `src/` so much as mentions
|
|
26
|
+
* `import.meta.url` — because the next refactor that moves a module into a chunk must not be able
|
|
27
|
+
* to reintroduce this quietly.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/** The entry's directory, with a trailing slash. `undefined` until an entry sets it. */
|
|
31
|
+
let base: string | undefined;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Record the calling ENTRY's own URL. Call as `setBundleBase(import.meta.url)`, first statement
|
|
35
|
+
* after the imports, from `src/studio.ts` or `src/canvas/iframe-entry.ts` only.
|
|
36
|
+
*
|
|
37
|
+
* @param entryUrl The entry module's `import.meta.url`.
|
|
38
|
+
*/
|
|
39
|
+
export function setBundleBase(entryUrl: string): void {
|
|
40
|
+
// Directory, not file: `new URL("./", <file url>)` strips the last segment.
|
|
41
|
+
base = new URL("./", entryUrl).href;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Resolve a path relative to the bundle's own directory.
|
|
46
|
+
*
|
|
47
|
+
* Throws rather than guessing, because its predecessor's whole problem was failing silently: an
|
|
48
|
+
* unset base means an entry did not run, and a URL invented here would 404 somewhere the user
|
|
49
|
+
* cannot see.
|
|
50
|
+
*
|
|
51
|
+
* @param path Bundle-relative path, e.g. `workers/json.worker.js` or `../canvas.html`.
|
|
52
|
+
* @returns Absolute URL.
|
|
53
|
+
* @throws {Error} When no entry has called {@link setBundleBase}.
|
|
54
|
+
*/
|
|
55
|
+
export function bundleUrl(path: string): string {
|
|
56
|
+
if (base === undefined) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`bundleUrl(${JSON.stringify(path)}) before setBundleBase(). An entry module ` +
|
|
59
|
+
`(src/studio.ts or src/canvas/iframe-entry.ts) must call setBundleBase(import.meta.url) ` +
|
|
60
|
+
`first; a test needs tests/with-dom.ts, which sets one.`,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
return new URL(path, base).href;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Test seam: forget the recorded base. Not called by application code. */
|
|
67
|
+
export function resetBundleBase(): void {
|
|
68
|
+
base = undefined;
|
|
69
|
+
}
|
|
@@ -80,6 +80,7 @@ import "monaco-editor/languages/definitions/javascript/register";
|
|
|
80
80
|
import { flattenSchema } from "@jxsuite/schema/project-schemas";
|
|
81
81
|
import jxSchema from "@jxsuite/schema/schema.json";
|
|
82
82
|
import projectSchema from "@jxsuite/schema/project-schema.json";
|
|
83
|
+
import { bundleUrl } from "./bundle-base";
|
|
83
84
|
|
|
84
85
|
/* Re-exported for the modules that already imported it from here. New callers should reach for
|
|
85
86
|
`./model-uri` directly — it is Monaco-free, and importing this module loads the editor. */
|
|
@@ -93,28 +94,33 @@ const WORKER_FILES: Record<string, string> = {
|
|
|
93
94
|
};
|
|
94
95
|
|
|
95
96
|
/**
|
|
96
|
-
* Resolve a Monaco worker to the PRE-BUNDLED copy that ships NEXT TO
|
|
97
|
+
* Resolve a Monaco worker to the PRE-BUNDLED copy that ships NEXT TO THE ENTRY — `dist/workers/`
|
|
97
98
|
* beside `dist/studio.js`, written by scripts/build-workers.ts.
|
|
98
99
|
*
|
|
99
|
-
* Self-location
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
* document-relative URL would resolve into the wrong directory there. The only invariant is the
|
|
105
|
-
* bundle's own location.
|
|
100
|
+
* Self-location is what makes one expression correct on every host, because none of them agree on a
|
|
101
|
+
* prefix and two of them cannot be served by one: the repo dev server mounts the shell at
|
|
102
|
+
* `/packages/studio/index.html`, the packaged desktop app at `views://studio/index.html`, the
|
|
103
|
+
* desktop loopback server under `/__studio__/`, and a cloud host under whatever prefix it staged
|
|
104
|
+
* the tree at. The only invariant is the bundle's own location.
|
|
106
105
|
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
106
|
+
* **But `import.meta.url` is not that location, and this function used to think it was.** It is
|
|
107
|
+
* THIS MODULE's url, and since the code-split (78d85ba2) this module is emitted into
|
|
108
|
+
* `dist/chunks/monaco-setup-<hash>.js` — so the expression resolved to `chunks/workers/<name>`, a
|
|
109
|
+
* directory that has never existed in any distribution. Only the two entries have a contractual
|
|
110
|
+
* emitted path (studio.md §11.1), which is exactly what `services/bundle-base` records.
|
|
111
|
+
*
|
|
112
|
+
* The bug this closes is invisible by construction, which is why it survived: a Monaco worker that
|
|
113
|
+
* 404s takes the whole JSON language service with it — no schema validation, no completion, no
|
|
114
|
+
* hover — and surfaces no error at all. The same silence covered the predecessor of the
|
|
115
|
+
* `import.meta.url` form, a root-absolute `/monaco-editor/esm/vs/...` that resolved on the repo dev
|
|
116
|
+
* server alone.
|
|
111
117
|
*
|
|
112
118
|
* @param {string} label - Monaco worker label ("json", "typescript", …)
|
|
113
119
|
* @returns {string} Absolute URL of the worker bundle
|
|
114
120
|
*/
|
|
115
121
|
export function workerUrl(label: string): string {
|
|
116
122
|
const file = WORKER_FILES[label] || WORKER_FILES.editorWorkerService!;
|
|
117
|
-
return
|
|
123
|
+
return bundleUrl(`workers/${file}`);
|
|
118
124
|
}
|
|
119
125
|
|
|
120
126
|
self.MonacoEnvironment = {
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shell's mount tree — the one definition of what the application frame IS.
|
|
3
|
+
*
|
|
4
|
+
* It was `index.html`'s body, and, in drifted copies, the body of twenty-three test files. The copy
|
|
5
|
+
* in `tests/studio-shell-fixture.ts` had lost `#resize-bottom`, `#bottom-dock` and `#layer-toast`,
|
|
6
|
+
* so every shell-boot test ran against a shell with no bottom dock and no toast host — a difference
|
|
7
|
+
* no test could report, because the fixture WAS the thing under test.
|
|
8
|
+
*
|
|
9
|
+
* Nothing here is dynamic: `mountShellTree()` renders once at boot, before `initShellRefs()` adopts
|
|
10
|
+
* the hosts, and each region then renders into its own host through its own effect (see
|
|
11
|
+
* studio-ui-guidelines.md §9.3). It is a lit template rather than a string because that makes the
|
|
12
|
+
* region attributes bindings the tree owns, and because the twenty-three test files can now ask for
|
|
13
|
+
* the real shell instead of describing one.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { html, render as litRender } from "lit-html";
|
|
17
|
+
import type { TemplateResult } from "lit-html";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Render a frame template into `host`, surviving a host that was emptied since the last mount.
|
|
21
|
+
*
|
|
22
|
+
* `textContent = ""` (or `innerHTML = ""`) removes the comment nodes lit uses as a ChildPart's
|
|
23
|
+
* markers but leaves lit's private `_$litPart$` reference behind, so the next render reuses a part
|
|
24
|
+
* whose markers are detached from the DOM and throws — or, worse, quietly renders nothing. Test
|
|
25
|
+
* fixtures clear the body between cases constantly, and the app does the same thing to a stage on
|
|
26
|
+
* every mode transition; `canvas/canvas-render.ts`'s hardClearCanvasWrap carries the same ejection
|
|
27
|
+
* for the same reason.
|
|
28
|
+
*
|
|
29
|
+
* Mounting is a one-shot, so ejecting unconditionally costs nothing and makes it idempotent.
|
|
30
|
+
*/
|
|
31
|
+
function mountInto(host: ParentNode, tpl: TemplateResult): void {
|
|
32
|
+
/* Both halves, in this order. Clearing alone leaves lit's private part reference pointing at
|
|
33
|
+
comment markers that are no longer in the document, so the next render throws or paints
|
|
34
|
+
nothing. Ejecting alone leaves the OLD nodes in place and lit starts a fresh part beside them,
|
|
35
|
+
so a second mount produces two frames rather than one. */
|
|
36
|
+
(host as HTMLElement).textContent = "";
|
|
37
|
+
// @ts-expect-error -- _$litPart$ is lit's private render-part marker, not in the DOM types
|
|
38
|
+
delete (host as HTMLElement)["_$litPart$"];
|
|
39
|
+
litRender(tpl, host as HTMLElement);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The four overlay layers that `ui/layers.ts` renders into, in stacking order.
|
|
44
|
+
*
|
|
45
|
+
* Exported apart from {@link shellTree} because it is the piece a unit test usually wants alone
|
|
46
|
+
* (through `mountOverlayLayers` in the test harness) — twenty fixtures were describing this set by
|
|
47
|
+
* hand, and they had already stopped agreeing: most carried three layers and one carried four, so
|
|
48
|
+
* whether a toast host existed at all depended on which test file you happened to be in.
|
|
49
|
+
*/
|
|
50
|
+
export function overlayLayers(): TemplateResult {
|
|
51
|
+
return html`
|
|
52
|
+
<!-- The four overlay layers, in stacking order. Their z-indices were inline style
|
|
53
|
+
attributes, which put the one piece of ordering the whole overlay system depends on
|
|
54
|
+
outside the reach of check-styles.ts's stacking rule — the check that exists because a
|
|
55
|
+
blocking progress modal once shipped above its own scrim with no reachable exit. They are
|
|
56
|
+
classes in styles/overlays.css now, and the toast host is ABOVE the dialog host because
|
|
57
|
+
an operation started from a dialog reports its outcome to the person still looking at
|
|
58
|
+
it. -->
|
|
59
|
+
<div id="layer-popover" class="jx-layer jx-layer--popover"></div>
|
|
60
|
+
<div id="layer-modal" class="jx-layer jx-layer--modal"></div>
|
|
61
|
+
<div id="layer-dialog" class="jx-layer jx-layer--dialog"></div>
|
|
62
|
+
<!-- role="status" sits on the HOST, so a stack of toasts is announced as one live region
|
|
63
|
+
rather than one region per notification. It carries its region id whether or not a toast
|
|
64
|
+
has ever been raised: a region that only exists once something has gone wrong is one a
|
|
65
|
+
screenshot cannot address and focus cannot be moved into. -->
|
|
66
|
+
<div
|
|
67
|
+
id="layer-toast"
|
|
68
|
+
class="jx-layer jx-layer--toast"
|
|
69
|
+
role="status"
|
|
70
|
+
aria-live="polite"
|
|
71
|
+
data-jx-region="overlay.toasts"
|
|
72
|
+
></div>
|
|
73
|
+
`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The application frame: the Spectrum theme wrapper, the app grid, and the four overlay layers.
|
|
78
|
+
*
|
|
79
|
+
* The theme's three attributes are BINDINGS rather than literals, and that is not decoration. A
|
|
80
|
+
* literal lives in the template lit clones with `importNode`, and cloning a registered custom
|
|
81
|
+
* element makes the DOM fire `attributeChangedCallback` before its constructor has run — Spectrum's
|
|
82
|
+
* Theme then reaches for `_provideSystemContext` and finds nothing. A binding is applied after the
|
|
83
|
+
* element exists. `shell.ts` overwrites `color` on the first theme effect anyway, so the literal
|
|
84
|
+
* was never the source of truth.
|
|
85
|
+
*
|
|
86
|
+
* Region ids are stamped HERE. They used to live in a selector-to-id map in `ui/regions.ts`, whose
|
|
87
|
+
* comment gave the reason plainly — these were "bare `<div id>` in index.html, so it cannot stamp
|
|
88
|
+
* itself". A template can, so the map is gone and the id sits on the element it names.
|
|
89
|
+
*/
|
|
90
|
+
export function shellTree(): TemplateResult {
|
|
91
|
+
return html`
|
|
92
|
+
<div id="app">
|
|
93
|
+
<div id="toolbar" data-jx-region="commandbar"></div>
|
|
94
|
+
<!-- The PANE GRID (studio.md §18.1). One cell per pane, each holding that pane's own strip,
|
|
95
|
+
jump bar, chrome layer and stage — the four surfaces that used to be flat siblings of
|
|
96
|
+
THIS grid, which is to say application rows that only ever described one pane. There is
|
|
97
|
+
nothing to see here in markup: panels/pane-grid.ts reconciles the cells against
|
|
98
|
+
workspace.panes, because how many there are is a fact about the workspace and a
|
|
99
|
+
single div can only ever be one of them. -->
|
|
100
|
+
<div id="pane-grid"></div>
|
|
101
|
+
<div id="activity-bar" data-jx-region="rail"></div>
|
|
102
|
+
<div id="left-panel" data-jx-region="navigator"></div>
|
|
103
|
+
<div id="resize-left" class="resize-handle"></div>
|
|
104
|
+
<!-- The Bottom dock (⌘J). It sits in the PANE's column, under the stage and above the
|
|
105
|
+
status bar, so opening it never narrows the Navigator or the Inspector (studio.md §12
|
|
106
|
+
region ⑪). Its handle resizes on the other axis; panels/bottom-dock.ts stamps
|
|
107
|
+
dock.bottom on this host while it is open, and nothing while it is closed. -->
|
|
108
|
+
<div id="resize-bottom" class="resize-handle resize-handle-row"></div>
|
|
109
|
+
<div id="bottom-dock"></div>
|
|
110
|
+
<div id="resize-right" class="resize-handle"></div>
|
|
111
|
+
<!-- The Inspector dock. Four tabs — Content · Style · Logic · Assistant (studio.md §12
|
|
112
|
+
region ⑨) — all inside this one host. -->
|
|
113
|
+
<div id="right-panel" data-jx-region="inspector"></div>
|
|
114
|
+
<!-- The app's only status channel: announce what lands in it (studio.md §12 region ⑫). -->
|
|
115
|
+
<div id="statusbar" role="status" aria-live="polite" data-jx-region="statusbar"></div>
|
|
116
|
+
</div>
|
|
117
|
+
${overlayLayers()}
|
|
118
|
+
`;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Render {@link shellTree} into `host`.
|
|
123
|
+
*
|
|
124
|
+
* The entry calls this once, before `initShellRefs()`. Tests call it instead of pasting an
|
|
125
|
+
* approximation of the frame — which is the whole reason it is a function.
|
|
126
|
+
*
|
|
127
|
+
* @param host Where the frame goes. Defaults to the document body.
|
|
128
|
+
*/
|
|
129
|
+
export function mountShellTree(host: ParentNode = document.body): void {
|
|
130
|
+
mountInto(themeHost(host), shellTree());
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* The Spectrum theme wrapper, created once and reused.
|
|
135
|
+
*
|
|
136
|
+
* It is NOT part of {@link shellTree}, and the reason is a real constraint rather than taste. lit
|
|
137
|
+
* instantiates a template by cloning it with `importNode`, and cloning a registered custom element
|
|
138
|
+
* enqueues its `attributeChangedCallback` before the constructor body has run — Spectrum's Theme
|
|
139
|
+
* then reaches for a field it assigns in that body and throws. `createElement` runs the constructor
|
|
140
|
+
* first, so the attributes are safe to set afterwards.
|
|
141
|
+
*
|
|
142
|
+
* `shell.ts` rewrites `color` on the first theme effect, so the value here is only the first frame.
|
|
143
|
+
*/
|
|
144
|
+
function themeHost(host: ParentNode): HTMLElement {
|
|
145
|
+
const existing = host.querySelector?.("sp-theme");
|
|
146
|
+
if (existing) {
|
|
147
|
+
return existing as HTMLElement;
|
|
148
|
+
}
|
|
149
|
+
const theme = document.createElement("sp-theme");
|
|
150
|
+
theme.setAttribute("color", "dark");
|
|
151
|
+
theme.setAttribute("scale", "medium");
|
|
152
|
+
theme.setAttribute("system", "spectrum");
|
|
153
|
+
(host as HTMLElement).append(theme);
|
|
154
|
+
return theme;
|
|
155
|
+
}
|
package/src/shell.ts
CHANGED
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
import { effect, effectScope, reactive } from "./reactivity";
|
|
25
25
|
import { loadedMonaco } from "./services/monaco-lazy";
|
|
26
26
|
import { applyStartupProfile } from "./services/profile";
|
|
27
|
-
import { stampShellRegions } from "./ui/regions";
|
|
28
27
|
import { workspace } from "./workspace/workspace";
|
|
29
28
|
import { captureSession, readSession } from "./workspace/session";
|
|
30
29
|
import type { PersistedSession } from "./workspace/session";
|
|
@@ -1044,7 +1043,6 @@ export function mountShell(): void {
|
|
|
1044
1043
|
}
|
|
1045
1044
|
// The six shell hosts are bare `<div id>`s in index.html, so they cannot stamp their own region
|
|
1046
1045
|
// The way a panel or an overlay slot does. One table, applied once the tree exists.
|
|
1047
|
-
stampShellRegions();
|
|
1048
1046
|
// The Bottom dock mounts from here rather than from the bootstrap because it is a DOCK: it is
|
|
1049
1047
|
// Projected onto the grid by the same record and the same effect as the other two, and a second
|
|
1050
1048
|
// Mounting site would be a second place the shell's own layout is decided. Every surface's own
|
package/src/studio.ts
CHANGED
|
@@ -112,7 +112,6 @@ import {
|
|
|
112
112
|
openLastSessionOrHome,
|
|
113
113
|
registerFileTreeDnD,
|
|
114
114
|
reloadCleanTab,
|
|
115
|
-
setupTreeKeyboard,
|
|
116
115
|
} from "./files/files";
|
|
117
116
|
import { startFsSync } from "./files/fs-events";
|
|
118
117
|
import { invalidateParamValues } from "./page-params";
|
|
@@ -233,6 +232,24 @@ import { convertToComponent } from "./editor/convert-to-component";
|
|
|
233
232
|
import type { GitDiffState } from "./types";
|
|
234
233
|
import type { Tab } from "./tabs/tab";
|
|
235
234
|
import type { JxMutableNode, ProjectConfig } from "@jxsuite/schema/types";
|
|
235
|
+
import { setBundleBase } from "./services/bundle-base";
|
|
236
|
+
import { mountShellTree } from "./shell/tree";
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Anchor every shipped-asset URL to THIS module's directory.
|
|
240
|
+
*
|
|
241
|
+
* Only an ENTRY may do this, and it must be an entry: `splitting: true` may hoist any other module
|
|
242
|
+
* into a content-hashed chunk under `dist/chunks/`, where `import.meta.url` means something else
|
|
243
|
+
* entirely. That is not hypothetical — it is the bug this call fixes, in `services/monaco-setup`.
|
|
244
|
+
* `tests/entry-anchors.test.ts` holds the line in both directions.
|
|
245
|
+
*
|
|
246
|
+
* Placed before any other statement so nothing can read the base before it exists. In ESM the
|
|
247
|
+
* entry's body runs AFTER its whole static import graph, so a module that called `bundleUrl()`
|
|
248
|
+
* during evaluation would still throw — deliberately, and loudly. Nothing does today: Monaco is
|
|
249
|
+
* reached only through the dynamic `services/monaco-lazy`, and `workerUrl` runs inside
|
|
250
|
+
* `MonacoEnvironment.getWorker`.
|
|
251
|
+
*/
|
|
252
|
+
setBundleBase(import.meta.url);
|
|
236
253
|
|
|
237
254
|
void _swc;
|
|
238
255
|
|
|
@@ -419,6 +436,10 @@ mountResizeEdges();
|
|
|
419
436
|
|
|
420
437
|
// ─── Render loop ──────────────────────────────────────────────────────────────
|
|
421
438
|
|
|
439
|
+
/* The application frame, before anything adopts a host out of it. index.html carries an empty body
|
|
440
|
+
and this is the only definition — see src/shell/tree.ts for what that fixed. */
|
|
441
|
+
mountShellTree();
|
|
442
|
+
|
|
422
443
|
initShellRefs();
|
|
423
444
|
// One effect projects the dock record onto the shell grid — collapse classes and column widths.
|
|
424
445
|
mountShell();
|
|
@@ -815,7 +836,6 @@ leftPanelMod.mount({
|
|
|
815
836
|
setGitDiffState: (state: GitDiffState | null) => {
|
|
816
837
|
shell.git.diffState = state;
|
|
817
838
|
},
|
|
818
|
-
setupTreeKeyboard,
|
|
819
839
|
webdata,
|
|
820
840
|
});
|
|
821
841
|
|
package/src/types.ts
CHANGED
|
@@ -166,6 +166,21 @@ export interface StudioPlatform {
|
|
|
166
166
|
* "desktop"`, but only chromium sets this.
|
|
167
167
|
*/
|
|
168
168
|
canvasUrl?: string;
|
|
169
|
+
/**
|
|
170
|
+
* True when this platform resolves {@link canvasUrl} ASYNCHRONOUSLY.
|
|
171
|
+
*
|
|
172
|
+
* Electrobun does: the url is this window's loopback port, fetched over RPC inside `activate()`.
|
|
173
|
+
* Until the canvas fallback was anchored to the bundle it did not matter — the old literal
|
|
174
|
+
* `/packages/studio/canvas.html` resolved to nothing servable under `views://`, so an early frame
|
|
175
|
+
* simply failed and the host rebuilt when the real url landed. Now the fallback RESOLVES:
|
|
176
|
+
* `views://studio/canvas.html` is a document electrobun really stages. An early frame would boot
|
|
177
|
+
* the whole canvas bundle inside the SHELL's app-privileged origin, in a CEF instance running
|
|
178
|
+
* `disable-site-isolation-trials` — and the cross-origin loopback canvas exists precisely so that
|
|
179
|
+
* cannot happen. Declaring it makes the host wait instead.
|
|
180
|
+
*
|
|
181
|
+
* Not keyed on `id`: chromium and electrobun both report `"desktop"`, and only electrobun defers.
|
|
182
|
+
*/
|
|
183
|
+
canvasUrlDeferred?: boolean;
|
|
169
184
|
activate: (root?: string) => Promise<void>;
|
|
170
185
|
openProject: () => Promise<{
|
|
171
186
|
config: ProjectConfig;
|
package/src/ui/regions.ts
CHANGED
|
@@ -285,54 +285,19 @@ export function focusRegionOf(el: Element | null): FocusRegion | null {
|
|
|
285
285
|
|
|
286
286
|
// ─── Stamping ─────────────────────────────────────────────────────────────────
|
|
287
287
|
|
|
288
|
-
|
|
289
|
-
*
|
|
290
|
-
*
|
|
291
|
-
* These live in `index.html` as bare `<div id>`s, so they cannot stamp themselves the way a panel
|
|
292
|
-
* or an overlay slot does. The table is the shell's own layout stated in region terms, and it is
|
|
293
|
-
* the only place a surface id is written down by hand.
|
|
294
|
-
*
|
|
295
|
-
* `#tab-strip` is addressed as `pane.primary/tabs` deliberately: the region names the PANE's strip,
|
|
296
|
-
* so the id survives the node. The assistant is the case that has now happened twice over:
|
|
297
|
-
* `inspector.assistant` was minted while the chat was a fifth grid column, survived the column
|
|
298
|
-
* being deleted, and survives the `#chat-panel` DIV being deleted too — it is stamped by
|
|
299
|
-
* `panels/chat-panel.ts` on whatever container hosts the assistant, which is now the Inspector's
|
|
300
|
-
* fourth tab body. That is the whole argument for naming the role rather than the div, and the
|
|
301
|
-
* reason this table lost a row without any shot losing its subject.
|
|
288
|
+
/*
|
|
289
|
+
* There is no SHELL_REGION_HOSTS map here any more, and no stampShellRegions().
|
|
302
290
|
*
|
|
303
|
-
*
|
|
304
|
-
*
|
|
305
|
-
* `
|
|
306
|
-
* it
|
|
291
|
+
* It existed because the shell's hosts were bare `<div id>` elements in index.html — the map's
|
|
292
|
+
* own comment said so: it "cannot stamp itself". The frame is a lit template now
|
|
293
|
+
* (`src/shell/tree.ts`), so each id sits on the element it names, and a selector-to-id map beside
|
|
294
|
+
* it would be a second definition of the same fact — which is the thing moving the frame into code
|
|
295
|
+
* was for. `tests/shell-tree.test.ts` asserts the frame's ids parse and resolve uniquely, which is
|
|
296
|
+
* what the map used to guarantee by construction.
|
|
307
297
|
*
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
* were only ever the primary pane's stage and strip. `panels/pane-grid.ts` builds a cell per pane
|
|
311
|
-
* and stamps {@link paneRegion} on each, so the id is derived from the pane rather than from a div
|
|
312
|
-
* that could only ever be one of them. Four rows gone, not one shot re-pointed.
|
|
298
|
+
* A surface that is NOT part of the frame stamps its own id from its own template, which is what
|
|
299
|
+
* the derived helpers below are for.
|
|
313
300
|
*/
|
|
314
|
-
export const SHELL_REGION_HOSTS: Readonly<Record<string, string>> = {
|
|
315
|
-
"#activity-bar": "rail",
|
|
316
|
-
// The fourth overlay layer. It is here rather than stamped by `ui/layers.ts` for the same reason
|
|
317
|
-
// Every other row is: it is a bare `<div id>` in index.html, so it cannot stamp itself, and the
|
|
318
|
-
// Id has to resolve whether or not a toast has ever been raised — a region that only exists once
|
|
319
|
-
// Something has gone wrong is a region a shot cannot address and focus cannot be moved into.
|
|
320
|
-
"#layer-toast": "overlay.toasts",
|
|
321
|
-
"#left-panel": "navigator",
|
|
322
|
-
"#right-panel": "inspector",
|
|
323
|
-
"#statusbar": "statusbar",
|
|
324
|
-
"#toolbar": "commandbar",
|
|
325
|
-
};
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* Stamp the shell hosts. Idempotent, and safe to call before the DOM exists (an absent host is
|
|
329
|
-
* simply not stamped — the desktop shell and the tests both boot partial trees).
|
|
330
|
-
*/
|
|
331
|
-
export function stampShellRegions(root: ParentNode = document): void {
|
|
332
|
-
for (const [selector, id] of Object.entries(SHELL_REGION_HOSTS)) {
|
|
333
|
-
root.querySelector(selector)?.setAttribute(REGION_ATTR, id);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
301
|
|
|
337
302
|
/**
|
|
338
303
|
* Region id for a pane, or for a part inside one — derived from the pane's own id.
|
package/styles/overlays.css
CHANGED
|
@@ -2702,3 +2702,38 @@
|
|
|
2702
2702
|
.settings-locale-routing {
|
|
2703
2703
|
max-width: 320px;
|
|
2704
2704
|
}
|
|
2705
|
+
|
|
2706
|
+
/* ─── Overlay layers ───────────────────────────────────────────────────────
|
|
2707
|
+
The four full-viewport hosts `ui/layers.ts` renders into, in stacking order.
|
|
2708
|
+
Their z-indices were inline `style` attributes on four divs in index.html,
|
|
2709
|
+
which put the one piece of ordering the whole overlay system depends on
|
|
2710
|
+
outside `check-styles.ts`'s stacking rule — the rule that exists because a
|
|
2711
|
+
blocking progress modal shipped above its own scrim with no reachable exit.
|
|
2712
|
+
`src/shell/tree.ts` emits these classes; the ordering is reviewable here.
|
|
2713
|
+
|
|
2714
|
+
Each layer is inert until something is rendered into it: `pointer-events`
|
|
2715
|
+
is none on the host, and each slot `ui/layers.ts` appends turns it back on
|
|
2716
|
+
for itself. */
|
|
2717
|
+
.jx-layer {
|
|
2718
|
+
position: fixed;
|
|
2719
|
+
inset: 0;
|
|
2720
|
+
pointer-events: none;
|
|
2721
|
+
}
|
|
2722
|
+
|
|
2723
|
+
.jx-layer--popover {
|
|
2724
|
+
z-index: 1000;
|
|
2725
|
+
}
|
|
2726
|
+
|
|
2727
|
+
.jx-layer--modal {
|
|
2728
|
+
z-index: 2000;
|
|
2729
|
+
}
|
|
2730
|
+
|
|
2731
|
+
.jx-layer--dialog {
|
|
2732
|
+
z-index: 3000;
|
|
2733
|
+
}
|
|
2734
|
+
|
|
2735
|
+
/* Above the dialog layer, deliberately: an operation started from a dialog
|
|
2736
|
+
reports its outcome to the person who is still looking at the dialog. */
|
|
2737
|
+
.jx-layer--toast {
|
|
2738
|
+
z-index: 4000;
|
|
2739
|
+
}
|