@jxsuite/studio 5.5.0 → 5.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/dist/chunks/{2020-g8mwpbkq.js → 2020-cs2sb9t1.js} +3 -3
- package/dist/chunks/adapter-y5gdq19c.js +4 -0
- package/dist/chunks/cf-account-picker-882a7ecm.js +4 -0
- package/dist/chunks/cf-settings-20dznc3j.js +4 -0
- package/dist/chunks/components-q037dya7.js +4 -0
- package/dist/chunks/content-source-37x3vsap.js +4 -0
- package/dist/chunks/convert-to-repeater-grfep2w8.js +4 -0
- package/dist/chunks/editor-j5sq149q.js +4 -0
- package/dist/chunks/entry-commands-c5h3nqck.js +4 -0
- package/dist/chunks/extension-sections-dp8endhx.js +4 -0
- package/dist/chunks/file-ops-937cvqk6.js +4 -0
- package/dist/chunks/files-tznwe1p1.js +4 -0
- package/dist/chunks/format-host-e2pjvd25.js +4 -0
- package/dist/chunks/fs-events-fv64ak3s.js +4 -0
- package/dist/chunks/git-panel-gb713ttc.js +4 -0
- package/dist/chunks/grid-view-5amhg604.js +51 -0
- package/dist/chunks/grid-view-5mqv1cbd.css +1 -0
- package/dist/chunks/iframe-host-t819mcg5.js +4 -0
- package/dist/chunks/{index-arg188jq.js → index-9ydfe04y.js} +3 -3
- package/dist/chunks/index-m0x5ztax.js +4 -0
- package/dist/chunks/{javascript-zcdmye2k.js → javascript-d9pqgc2p.js} +2 -2
- package/dist/chunks/{jsonMode-6x5e1nbf.js → jsonMode-800yvbem.js} +5 -5
- package/dist/chunks/jx-validate-zc9zp77s.js +4 -0
- package/dist/chunks/layers-4bsr82wz.js +4 -0
- package/dist/chunks/layers-panel-b6shnaax.js +4 -0
- package/dist/chunks/lit-html-cfn61dn7.js +4 -0
- package/dist/chunks/media-picker-ej0kdh1j.js +4 -0
- package/dist/chunks/menu-rtxf9chb.js +4 -0
- package/dist/chunks/{monaco-binding-4az2kh5p.js → monaco-binding-62dtmgbf.js} +3 -3
- package/dist/chunks/monaco-buffer-nn4dtx27.js +4 -0
- package/dist/chunks/{monaco-setup-d7mwkcx3.js → monaco-setup-tj13ndtm.js} +3 -3
- package/dist/chunks/notify-ahs57a2z.js +4 -0
- package/dist/chunks/platform-v9xyfkbx.js +4 -0
- package/dist/chunks/publish-panel-bq36xcmj.js +4 -0
- package/dist/chunks/quick-search-zm00h9dh.js +4 -0
- package/dist/chunks/references-99ws0b0m.js +4 -0
- package/dist/chunks/right-panel-pq2f71q3.js +4 -0
- package/dist/chunks/section-registry-b2yzp9sw.js +4 -0
- package/dist/chunks/studio-01kbbqg3.js +928 -0
- package/dist/chunks/{studio-hf4qdjc8.js → studio-01qza1n3.js} +4 -4
- package/dist/chunks/{studio-pkkw32j0.js → studio-03wwfvyt.js} +4 -4
- package/dist/chunks/{studio-7gqyhjns.js → studio-0bbxhhce.js} +4 -4
- package/dist/chunks/studio-0k9mvpgj.js +14 -0
- package/dist/chunks/studio-0scebvb9.js +6 -0
- package/dist/chunks/studio-1a99w39s.js +5 -0
- package/dist/chunks/studio-1wvfxkyy.js +5 -0
- package/dist/chunks/studio-1x8x26k3.js +5 -0
- package/dist/chunks/studio-222rqyyc.js +5 -0
- package/dist/chunks/studio-4xppwncr.js +4 -0
- package/dist/chunks/{studio-xcng8nx7.js → studio-54g077x3.js} +5 -5
- package/dist/chunks/studio-56z7evx4.js +10 -0
- package/dist/chunks/studio-5e9zsamh.js +9 -0
- package/dist/chunks/studio-65fhspdd.js +5 -0
- package/dist/chunks/studio-693nhyky.js +5 -0
- package/dist/chunks/{studio-7jazdy6y.js → studio-7pgy3xaf.js} +4 -4
- package/dist/chunks/studio-888knnkc.js +5 -0
- package/dist/chunks/studio-9mqfamps.js +5 -0
- package/dist/chunks/studio-a7xqhc3n.js +5 -0
- package/dist/chunks/studio-aje966s9.js +5 -0
- package/dist/chunks/studio-aqmph6k4.js +5 -0
- package/dist/chunks/studio-c6w3tq7t.js +5 -0
- package/dist/chunks/{studio-6j2jn55a.js → studio-c6zdm25z.js} +8 -8
- package/dist/chunks/{studio-f8jyp45j.js → studio-c9d3pxf7.js} +4 -4
- package/dist/chunks/studio-ceb34dxj.js +5 -0
- package/dist/chunks/studio-cvbkkfqb.js +5 -0
- package/dist/chunks/studio-cxt150pj.js +7 -0
- package/dist/chunks/studio-dkn3x3hz.js +5 -0
- package/dist/chunks/studio-e6re3rk1.js +5 -0
- package/dist/chunks/{studio-5n1km79v.js → studio-edbtvcd1.js} +4 -4
- package/dist/chunks/{studio-xc8ebsts.js → studio-eh0rac07.js} +4 -4
- package/dist/chunks/{studio-625ezz59.js → studio-evwgp1ym.js} +4 -4
- package/dist/chunks/{studio-he2fhrgp.js → studio-f195h2hq.js} +4 -4
- package/dist/chunks/studio-fqq890ap.js +4 -0
- package/dist/chunks/studio-frb0qbf7.js +6 -0
- package/dist/chunks/studio-gfn1kpxj.js +6 -0
- package/dist/chunks/studio-gh97gngt.js +5 -0
- package/dist/chunks/{studio-awqghqxv.js → studio-gp02nqnw.js} +4 -4
- package/dist/chunks/{studio-x9sagq2d.js → studio-hjbg8d5y.js} +7 -7
- package/dist/chunks/studio-j6gnhvaa.js +5 -0
- package/dist/chunks/studio-mwxgyn9h.js +7 -0
- package/dist/chunks/{studio-x5esgzct.js → studio-n78gjfy8.js} +4 -4
- package/dist/chunks/studio-nbxqcgvf.js +5 -0
- package/dist/chunks/{studio-p1eggxcf.js → studio-nt06yybj.js} +4 -4
- package/dist/chunks/{studio-hc9q4j24.js → studio-p7c1agz0.js} +5 -5
- package/dist/chunks/{studio-8r4y2x0z.js → studio-pwqfmt4p.js} +4 -4
- package/dist/chunks/{studio-5wfrgee9.js → studio-r3kaka4d.js} +4 -4
- package/dist/chunks/studio-semd1s8s.js +5 -0
- package/dist/chunks/studio-skzanb0k.js +5 -0
- package/dist/chunks/studio-spf2skgc.js +5 -0
- package/dist/chunks/{studio-b4epb26c.js → studio-st75kn99.js} +7 -7
- package/dist/chunks/{studio-eq27rrr0.js → studio-sxc0zvpt.js} +3 -3
- package/dist/chunks/studio-t1eedsyx.js +4 -0
- package/dist/chunks/{studio-73czgk6a.js → studio-tp642n5g.js} +4 -4
- package/dist/chunks/studio-tw7rre6s.js +5 -0
- package/dist/chunks/{studio-7by9a93k.js → studio-tzegmy4w.js} +4 -4
- package/dist/chunks/studio-vavmwshr.js +5 -0
- package/dist/chunks/studio-wma2c6g8.js +5 -0
- package/dist/chunks/studio-x92tgnee.js +64 -0
- package/dist/chunks/studio-xk0z6msk.js +5 -0
- package/dist/chunks/{studio-c4pnt1c6.js → studio-xry7tk3z.js} +5 -5
- package/dist/chunks/studio-xta2vxp6.js +9 -0
- package/dist/chunks/{studio-21enxdr8.js → studio-xy3tv3az.js} +4 -4
- package/dist/chunks/studio-y7jehjrp.js +5 -0
- package/dist/chunks/{studio-k1eaqyzm.js → studio-yr04mv2j.js} +4 -4
- package/dist/chunks/{studio-mhhc9btt.js → studio-zd4kayn2.js} +4 -4
- package/dist/chunks/studio-zpnk016a.js +16 -0
- package/dist/chunks/{tsMode-rtwt7w1a.js → tsMode-k9s9fcag.js} +5 -5
- package/dist/chunks/workspace-b69mgm0e.js +4 -0
- package/dist/chunks/ws-client-0ja08haa.js +4 -0
- package/dist/iframe-entry.js +14 -14
- package/dist/manifest.json +62 -59
- package/dist/studio.css +1 -1
- package/dist/studio.js +121 -123
- package/package.json +5 -5
- package/src/account/action-flow.ts +294 -0
- package/src/account/action-required.ts +68 -0
- package/src/account-status.ts +29 -1
- package/src/browse/library-model.ts +3 -1
- package/src/browse/library-preview.ts +6 -2
- package/src/canvas/asset-refs.ts +3 -1
- package/src/canvas/asset-resolve.ts +79 -1
- package/src/canvas/iframe-entry.ts +38 -1
- package/src/canvas/iframe-host.ts +85 -0
- package/src/canvas/iframe-protocol.ts +13 -0
- package/src/canvas/stage-scrollbar.ts +7 -7
- package/src/files/asset-versions.ts +294 -0
- package/src/files/file-ops.ts +5 -8
- package/src/files/files.ts +61 -9
- package/src/files/fs-events.ts +279 -28
- package/src/files/media-meta.ts +2 -1
- package/src/files/media-paths.ts +5 -2
- package/src/files/media-upload.ts +5 -1
- package/src/new-project/add-repo-modal.ts +12 -1
- package/src/new-project/new-project-modal.ts +12 -1
- package/src/panels/git-panel.ts +25 -2
- package/src/panels/jump-bar.ts +132 -158
- package/src/panels/pane-context.ts +8 -8
- package/src/panels/pane-grid.ts +18 -26
- package/src/panels/style-panel.ts +2 -2
- package/src/platform-errors.ts +61 -1
- package/src/platforms/cloud.ts +389 -50
- package/src/platforms/devserver.ts +17 -1
- package/src/publish/pages-service.ts +17 -7
- package/src/services/ai-models.ts +30 -6
- package/src/services/ai-system-prompt.ts +81 -51
- package/src/services/context-manager.ts +41 -70
- package/src/services/document-assistant.ts +12 -3
- package/src/services/harness/chat-reducer.ts +115 -0
- package/src/services/harness/turn-hooks.ts +50 -0
- package/src/services/tool-executor.ts +69 -288
- package/src/services/tool-outcomes.ts +12 -10
- package/src/settings/preferences-accounts.ts +42 -3
- package/src/settings/preferences-dialog.ts +8 -1
- package/src/studio.ts +20 -6
- package/src/surfaces/block-action-bar.json +6 -1
- package/src/surfaces/dialog.ts +5 -0
- package/src/surfaces/jump-bar.json +9 -12
- package/src/surfaces/jump-bar.ts +15 -16
- package/src/surfaces/pane-context.json +2 -2
- package/src/surfaces/pane-grid.json +8 -25
- package/src/surfaces/pane-grid.ts +7 -8
- package/src/surfaces/statusbar.json +71 -3
- package/src/surfaces/statusbar.ts +66 -139
- package/src/surfaces/style-panel.json +3 -3
- package/src/surfaces/style-panel.ts +11 -1
- package/src/surfaces/welcome.json +86 -1
- package/src/surfaces/welcome.ts +61 -2
- package/src/types.ts +84 -2
- package/src/ui/ai-managed-connect.ts +41 -4
- package/src/ui/media-picker.ts +2 -1
- package/dist/chunks/adapter-bsbs78x9.js +0 -4
- package/dist/chunks/cf-account-picker-gnm7xeqb.js +0 -4
- package/dist/chunks/cf-settings-9y6jyscp.js +0 -4
- package/dist/chunks/components-s51h3b7c.js +0 -4
- package/dist/chunks/content-source-ty3be0qg.js +0 -4
- package/dist/chunks/convert-to-repeater-c3e7q61z.js +0 -4
- package/dist/chunks/editor-t002b41m.js +0 -4
- package/dist/chunks/entry-commands-sb72e9gy.js +0 -4
- package/dist/chunks/extension-sections-ktn2ntnj.js +0 -4
- package/dist/chunks/file-ops-78zeytkm.js +0 -4
- package/dist/chunks/files-gatzrz8v.js +0 -4
- package/dist/chunks/format-host-r59b1651.js +0 -4
- package/dist/chunks/fs-events-f8h91ndt.js +0 -4
- package/dist/chunks/git-panel-y12zf7nj.js +0 -4
- package/dist/chunks/grid-view-rfd8b2pg.js +0 -51
- package/dist/chunks/grid-view-tafenfm2.css +0 -1
- package/dist/chunks/iframe-host-vsrsj20g.js +0 -4
- package/dist/chunks/index-5aghyrfh.js +0 -4
- package/dist/chunks/jx-validate-653krkrf.js +0 -4
- package/dist/chunks/layers-32p8gtae.js +0 -4
- package/dist/chunks/layers-panel-rs58m105.js +0 -4
- package/dist/chunks/lit-html-54bmkwz3.js +0 -4
- package/dist/chunks/media-picker-5bb04wct.js +0 -4
- package/dist/chunks/menu-cbha7w2e.js +0 -4
- package/dist/chunks/monaco-buffer-9vbbyfr1.js +0 -4
- package/dist/chunks/notify-dc1nz5ar.js +0 -4
- package/dist/chunks/platform-2m49s1zf.js +0 -4
- package/dist/chunks/publish-panel-nx3ycmma.js +0 -4
- package/dist/chunks/quick-search-yzrzh9x3.js +0 -4
- package/dist/chunks/references-vx7mbj9f.js +0 -4
- package/dist/chunks/right-panel-7jzpbxja.js +0 -4
- package/dist/chunks/section-registry-gjryse41.js +0 -4
- package/dist/chunks/studio-3znfhcxg.js +0 -5
- package/dist/chunks/studio-58qam27v.js +0 -4
- package/dist/chunks/studio-6j59fwaw.js +0 -5
- package/dist/chunks/studio-7z69g1gx.js +0 -5
- package/dist/chunks/studio-93j3v6zx.js +0 -5
- package/dist/chunks/studio-9gf6v8zy.js +0 -5
- package/dist/chunks/studio-9rhmettf.js +0 -4
- package/dist/chunks/studio-ac5aq677.js +0 -10
- package/dist/chunks/studio-as65vbns.js +0 -5
- package/dist/chunks/studio-bkv0sga4.js +0 -6
- package/dist/chunks/studio-bttmqef4.js +0 -5
- package/dist/chunks/studio-c3y9d41k.js +0 -5
- package/dist/chunks/studio-ccegp7gz.js +0 -9
- package/dist/chunks/studio-chxabn98.js +0 -6
- package/dist/chunks/studio-cktcdsxz.js +0 -16
- package/dist/chunks/studio-cnspfke5.js +0 -5
- package/dist/chunks/studio-de3p1ktm.js +0 -5
- package/dist/chunks/studio-fsbcn530.js +0 -928
- package/dist/chunks/studio-gftga7a3.js +0 -64
- package/dist/chunks/studio-hf1rpcq0.js +0 -4
- package/dist/chunks/studio-hz02hq70.js +0 -5
- package/dist/chunks/studio-jnb285we.js +0 -5
- package/dist/chunks/studio-jsv3s3s1.js +0 -5
- package/dist/chunks/studio-ks7cksh0.js +0 -5
- package/dist/chunks/studio-nptx0dbs.js +0 -5
- package/dist/chunks/studio-pg0z7k98.js +0 -5
- package/dist/chunks/studio-pve0b2f2.js +0 -5
- package/dist/chunks/studio-q7zmjv3b.js +0 -6
- package/dist/chunks/studio-rpmvw7kj.js +0 -5
- package/dist/chunks/studio-rwhss52s.js +0 -5
- package/dist/chunks/studio-sbg3g3h0.js +0 -5
- package/dist/chunks/studio-sq1bn60g.js +0 -14
- package/dist/chunks/studio-vwz7rma2.js +0 -5
- package/dist/chunks/studio-wa55e8gf.js +0 -5
- package/dist/chunks/studio-x0mzdha2.js +0 -5
- package/dist/chunks/studio-xrgpakvc.js +0 -9
- package/dist/chunks/studio-xt3djk1w.js +0 -7
- package/dist/chunks/studio-yh3nggx1.js +0 -7
- package/dist/chunks/studio-zmecp6hq.js +0 -5
- package/dist/chunks/workspace-g6dvaete.js +0 -4
- package/dist/chunks/ws-client-shf41j5p.js +0 -4
package/src/panels/jump-bar.ts
CHANGED
|
@@ -1,67 +1,79 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
2
|
/**
|
|
3
|
-
* The jump bar — the pane's address,
|
|
3
|
+
* The jump bar — the focused pane's address, as a breadcrumb trail along the foot of the window.
|
|
4
4
|
*
|
|
5
|
-
* **
|
|
5
|
+
* **Where it lives, and why it moved.** The trail is the status bar's DOCUMENT field: the file,
|
|
6
|
+
* then every ancestor of the selected element, leaf last, each one a button that selects it. That
|
|
7
|
+
* is the pattern the Gutenberg block editor taught a generation of authors, and it is where they
|
|
8
|
+
* look for it. It used to be a 10px row across the top of every pane, between the tab strip and the
|
|
9
|
+
* context bar, and in that position it read as part of the tab strip rather than as a control: the
|
|
10
|
+
* address was on screen and authors reported it missing. It also cost every pane 24px of stage
|
|
11
|
+
* height. At the foot it costs nothing, because the status bar's row is already there, and the
|
|
12
|
+
* field it replaced (the file path, a view name the context bar already prints, and a save word the
|
|
13
|
+
* tab strip's dirty marker and the Command Bar's Save button already state) was the bar's least
|
|
14
|
+
* useful content.
|
|
15
|
+
*
|
|
16
|
+
* **One bar, for the focused pane.** The status bar is one row for the whole window, so the trail
|
|
17
|
+
* addresses the pane that has focus, which is the pane the Inspector, the Outline and the keyboard
|
|
18
|
+
* already address. Clicking into the other pane re-points it.
|
|
19
|
+
*
|
|
20
|
+
* **The two half-breadcrumbs this replaced.** Studio grew two trails, neither of which could say
|
|
6
21
|
* where you were:
|
|
7
22
|
*
|
|
8
23
|
* 1. `panels/pane-context.ts`'s `navTpl()` (the old `#tab-bar` breadcrumb, `tab-bar.ts:129-185`) — a
|
|
9
24
|
* `Back` button plus one span per `session.documentStack` frame. It appeared ONLY while you were
|
|
10
|
-
* inside a sub-document
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* crumb. It appeared ONLY while something was selected, and knew nothing about the document it
|
|
16
|
-
* was inside.
|
|
25
|
+
* inside a sub-document and knew nothing about the selection below it. It is deleted, and so is
|
|
26
|
+
* the stack it walked: nothing ever pushed a frame, so it could only ever draw its empty
|
|
27
|
+
* branch.
|
|
28
|
+
* 2. `surfaces/statusbar.ts`'s selection field — a clickable ancestor trail that appeared ONLY while
|
|
29
|
+
* something was selected and knew nothing about the document it was inside.
|
|
17
30
|
*
|
|
18
|
-
*
|
|
19
|
-
* address, so neither one was a place to look. **This bar is the whole chain**, always:
|
|
31
|
+
* This bar is the whole chain, always:
|
|
20
32
|
*
|
|
21
33
|
* ```text
|
|
22
|
-
*
|
|
23
|
-
*
|
|
34
|
+
* Jx Suite ⑂ main ‖ pages/blog/[slug].json › article › header › h1 ⌃ ‖ 3 selected
|
|
35
|
+
* PROJECT field ‖ this bar: file, then the selection's ancestors ‖ SELECTION field
|
|
24
36
|
* ```
|
|
25
37
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* (a selector is not a node).
|
|
38
|
+
* The project is not a step of the trail: the PROJECT field directly to its left already names it,
|
|
39
|
+
* with the same `project.openRecent` command, and two adjacent buttons saying one thing is the
|
|
40
|
+
* duplication studio-ui-guidelines.md §12.2's chrome budget forbids. `statusbar/selection` keeps
|
|
41
|
+
* the two facts a trail cannot state: HOW MANY things are selected (a count is not a path) and
|
|
42
|
+
* which Stylebook rule the Style panel is editing (a selector is not a node).
|
|
32
43
|
*
|
|
33
44
|
* **Every interactive item is a command, resolved from the registry.** There is no click handler in
|
|
34
45
|
* this file that names behaviour: a segment names a command id and its args, and the registry
|
|
35
|
-
* supplies the title, the chord, the enablement and the run.
|
|
36
|
-
* `
|
|
37
|
-
*
|
|
38
|
-
* had no way in and both are gone.
|
|
46
|
+
* supplies the title, the chord, the enablement and the run. Two ids carry the whole bar —
|
|
47
|
+
* `palette.openFiles` (or `pane.pin` in a derived pane) and `selection.set` — and this file
|
|
48
|
+
* declares none of them.
|
|
39
49
|
*
|
|
40
50
|
* **A segment whose command the registry does not have becomes a readout, it does not disappear.**
|
|
41
|
-
* That is the one place this bar deliberately differs from the status bar, where an
|
|
42
|
-
* item vanishes. An address with a hole in it is a lie about containment; a readout is
|
|
43
|
-
* step you cannot take.
|
|
51
|
+
* That is the one place this bar deliberately differs from the status bar's own items, where an
|
|
52
|
+
* unavailable item vanishes. An address with a hole in it is a lie about containment; a readout is
|
|
53
|
+
* merely a step you cannot take.
|
|
44
54
|
*
|
|
45
55
|
* **This file is the FLOW; the markup is a document.** `surfaces/jump-bar.json` owns the bar's
|
|
46
|
-
* structure, its ARIA and every value in its style, and `surfaces/jump-bar.ts` mounts
|
|
47
|
-
* (studio-ui-guidelines.md §6, §9.3). What stays here
|
|
48
|
-
* this bar is about, what its address is, which of its
|
|
49
|
-
* chevron opens — and the chevron opens the KIT MENU,
|
|
50
|
-
* commands is what that surface already is
|
|
56
|
+
* structure, its ARIA and every value in its style, and `surfaces/jump-bar.ts` mounts it into the
|
|
57
|
+
* host the status bar's document leaves for it (studio-ui-guidelines.md §6, §9.3). What stays here
|
|
58
|
+
* is the part that is a decision: which pane this bar is about, what its address is, which of its
|
|
59
|
+
* steps the registry can run, and what a chevron opens — and the chevron opens the KIT MENU,
|
|
60
|
+
* `surfaces/menu.ts`, because a list of commands is what that surface already is
|
|
61
|
+
* (studio-ui-guidelines.md §12.5).
|
|
62
|
+
*
|
|
63
|
+
* @docs studio/interface
|
|
51
64
|
*/
|
|
52
65
|
|
|
53
66
|
import { displayTagName } from "@jxsuite/schema/guards";
|
|
54
67
|
import { childList, getNodeAtPath, nodeLabel, pathsEqual, projectState } from "../store";
|
|
55
68
|
import { effect, effectScope } from "../reactivity";
|
|
56
|
-
import {
|
|
69
|
+
import { activePane, workspace } from "../workspace/workspace";
|
|
57
70
|
import { derivationOfPane, tabOfPane } from "../canvas/canvas-surface";
|
|
58
|
-
import { paneRegion } from "../ui/regions";
|
|
59
71
|
import { primarySelection } from "../tabs/selection";
|
|
60
72
|
import { activeRegistry } from "../commands/active-registry";
|
|
61
73
|
import { runReported } from "../commands/run-reported";
|
|
62
74
|
import { openMenu } from "../surfaces/menu";
|
|
75
|
+
import { rectOf } from "../utils/geometry";
|
|
63
76
|
import { mountJumpBarSurface } from "../surfaces/jump-bar";
|
|
64
|
-
import { PANE_SELECTOR } from "../surfaces/pane-grid";
|
|
65
77
|
import type { CommandArgs, CommandRegistry } from "../commands/registry";
|
|
66
78
|
import type { FormulaEditDef, FunctionEditDef } from "../types";
|
|
67
79
|
import type { JxPath } from "../state";
|
|
@@ -71,11 +83,17 @@ import type { Tab } from "../tabs/tab";
|
|
|
71
83
|
import type { PaneDerivation } from "../workspace/workspace";
|
|
72
84
|
import type { EffectScope } from "@vue/reactivity";
|
|
73
85
|
|
|
74
|
-
/**
|
|
75
|
-
|
|
86
|
+
/**
|
|
87
|
+
* The region the trail stamps on itself. It is the status bar's DOCUMENT field: the document, and
|
|
88
|
+
* where in it you are.
|
|
89
|
+
*/
|
|
90
|
+
export const JUMP_BAR_REGION = "statusbar/document";
|
|
76
91
|
|
|
77
|
-
/**
|
|
78
|
-
|
|
92
|
+
/**
|
|
93
|
+
* How a segment's alternatives hang from its chevron: ABOVE it, leading edges aligned. The bar sits
|
|
94
|
+
* on the window's floor, so the kit menu's default (below the opener) would open off screen.
|
|
95
|
+
*/
|
|
96
|
+
const ABOVE_OPENER = "block-start span-inline-end";
|
|
79
97
|
|
|
80
98
|
// ─── The model ───────────────────────────────────────────────────────────────
|
|
81
99
|
|
|
@@ -84,7 +102,7 @@ const JUMP_BAR_HEIGHT = 24;
|
|
|
84
102
|
* step of the address without matching its rendered text, which is derived (the shot contract's R1,
|
|
85
103
|
* `scripts/screenshots/README.md`).
|
|
86
104
|
*/
|
|
87
|
-
export type JumpSegmentKind = "
|
|
105
|
+
export type JumpSegmentKind = "file" | "editor" | "node";
|
|
88
106
|
|
|
89
107
|
/** One alternative in a segment's dropdown. Each is a command, exactly like the segment itself. */
|
|
90
108
|
export interface JumpChoice {
|
|
@@ -111,12 +129,12 @@ export interface JumpSegment {
|
|
|
111
129
|
// ─── Labels ──────────────────────────────────────────────────────────────────
|
|
112
130
|
|
|
113
131
|
/**
|
|
114
|
-
* The document's path with the project root taken off — the root is the
|
|
132
|
+
* The document's path with the project root taken off — the root is the PROJECT field to its left.
|
|
115
133
|
*
|
|
116
134
|
* Lives here rather than in `statusbar.ts`, where it started: the jump bar is the surface whose
|
|
117
|
-
* whole job is naming the containment chain
|
|
118
|
-
*
|
|
119
|
-
*
|
|
135
|
+
* whole job is naming the containment chain. Having the reader own it also keeps
|
|
136
|
+
* `mock.module("surfaces/statusbar")` — which six bootstrap tests do — from deciding whether the
|
|
137
|
+
* jump bar can name a file.
|
|
120
138
|
*/
|
|
121
139
|
export function documentLabel(path: string | null): string {
|
|
122
140
|
if (!path) {
|
|
@@ -235,22 +253,12 @@ export function jumpSegments(
|
|
|
235
253
|
if (!tab) {
|
|
236
254
|
return [];
|
|
237
255
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
kind: "project",
|
|
245
|
-
label: project.name,
|
|
246
|
-
title: project.projectRoot,
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// ONE document per tab. This used to walk `session.documentStack` and emit a `subdocument`
|
|
251
|
-
// Segment per frame, each one a `document.setStackLevel` you could click back to — but nothing
|
|
252
|
-
// In `src/` ever pushed a frame, so the loop had exactly one iteration in the shipped app and the
|
|
253
|
-
// Address it drew was always this line. A tab holds a document; drilling in opens another tab.
|
|
256
|
+
// ONE document per tab, and no project segment before it: the status bar's PROJECT field sits
|
|
257
|
+
// Directly to the left of this trail and already names the project, with the same
|
|
258
|
+
// `project.openRecent` command. The document segment used to follow a `subdocument` segment per
|
|
259
|
+
// `session.documentStack` frame, each one a `document.setStackLevel` you could click back to —
|
|
260
|
+
// But nothing in `src/` ever pushed a frame. A tab holds a document; drilling in opens another
|
|
261
|
+
// Tab.
|
|
254
262
|
/* In a DERIVED pane the leading verb is Keep, not Open.
|
|
255
263
|
The address is still the document — a lens draws the source pane's, a companion its own — but
|
|
256
264
|
the question an author has about a pane that is following something is "can I stop it
|
|
@@ -258,13 +266,15 @@ export function jumpSegments(
|
|
|
258
266
|
lens: `projectStep` already renders a step whose command is disabled as a disabled button with
|
|
259
267
|
`disabledReason` in the tooltip, so the sentence explaining why Code, Diff and breakpoint views
|
|
260
268
|
cannot be pinned arrives for free. */
|
|
261
|
-
segments
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
269
|
+
const segments: JumpSegment[] = [
|
|
270
|
+
{
|
|
271
|
+
choices: [],
|
|
272
|
+
command: derived ? "pane.pin" : "palette.openFiles",
|
|
273
|
+
kind: "file",
|
|
274
|
+
label: documentLabel(tab.documentPath),
|
|
275
|
+
title: tab.documentPath ?? "Not saved to disk yet",
|
|
276
|
+
},
|
|
277
|
+
];
|
|
268
278
|
|
|
269
279
|
// A logic editor is the leaf of the address, and it has no selection under it: the Monaco buffer
|
|
270
280
|
// And the formula workspace are editing a definition, not a node of the document tree.
|
|
@@ -377,8 +387,8 @@ function projectStep(
|
|
|
377
387
|
|
|
378
388
|
// ─── Rendering ───────────────────────────────────────────────────────────────
|
|
379
389
|
|
|
380
|
-
/**
|
|
381
|
-
interface
|
|
390
|
+
/** The bar: the document mounted in the status bar's slot, and the address it last drew. */
|
|
391
|
+
interface Bar {
|
|
382
392
|
host: HTMLElement;
|
|
383
393
|
surface: JumpBarSurface;
|
|
384
394
|
/** The segments behind the projection, by key — what `run` and `choose` resolve against. */
|
|
@@ -386,14 +396,13 @@ interface PaneBar {
|
|
|
386
396
|
}
|
|
387
397
|
|
|
388
398
|
/**
|
|
389
|
-
* Where
|
|
399
|
+
* Where the bar is mounted, once the status bar has a slot for it.
|
|
390
400
|
*
|
|
391
|
-
*
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
* hand-over `panels/frontmatter-panel.ts` takes from the stage.
|
|
401
|
+
* ONE bar, not one per pane: the status bar is one row for the window, so the trail addresses the
|
|
402
|
+
* focused pane. `surfaces/statusbar.ts` attaches its `trail` slot when its document mounts and
|
|
403
|
+
* detaches it when it is disposed.
|
|
395
404
|
*/
|
|
396
|
-
|
|
405
|
+
let _bar: Bar | null = null;
|
|
397
406
|
|
|
398
407
|
let _scope: EffectScope | null = null;
|
|
399
408
|
|
|
@@ -414,6 +423,9 @@ export function dismissJumpMenu(): void {
|
|
|
414
423
|
* nothing here draws a panel: `surfaces/menu.ts` owns the roving caret, typeahead, Escape and light
|
|
415
424
|
* dismissal, because a list of commands is what that surface already is: a second one is the defect
|
|
416
425
|
* studio-ui-guidelines.md §12.5 names.
|
|
426
|
+
*
|
|
427
|
+
* The menu hangs ABOVE the chevron. The bar is the window's floor, so there is nothing below it;
|
|
428
|
+
* `place` is the same answer in coordinates, for an engine that cannot anchor a popover.
|
|
417
429
|
*/
|
|
418
430
|
function openChoices(segment: JumpSegment, anchor: HTMLElement | null): void {
|
|
419
431
|
const registry = activeRegistry();
|
|
@@ -442,6 +454,8 @@ function openChoices(segment: JumpSegment, anchor: HTMLElement | null): void {
|
|
|
442
454
|
}
|
|
443
455
|
},
|
|
444
456
|
opener: anchor,
|
|
457
|
+
placement: ABOVE_OPENER,
|
|
458
|
+
...(anchor ? { place: (box: DOMRect) => aboveOpener(anchor, box) } : {}),
|
|
445
459
|
region: "jump-bar",
|
|
446
460
|
rows,
|
|
447
461
|
});
|
|
@@ -449,33 +463,17 @@ function openChoices(segment: JumpSegment, anchor: HTMLElement | null): void {
|
|
|
449
463
|
}
|
|
450
464
|
|
|
451
465
|
/**
|
|
452
|
-
*
|
|
453
|
-
*
|
|
454
|
-
* The same one-projection-one-variable shape `pane-context.ts` uses for its own band, and for the
|
|
455
|
-
* same reason: the stage's offset is the SUM of the two, so a pane with no tab open (no bar) costs
|
|
456
|
-
* the welcome screen no dead band.
|
|
457
|
-
*
|
|
458
|
-
* **The variable is written on the PANE, not on `:root`** — when there is a pane to write it on.
|
|
459
|
-
* Two cells have two bars and two stages, and one document-level number would offset both by
|
|
460
|
-
* whichever pane painted last: a side pane showing a document would push the primary's welcome
|
|
461
|
-
* screen down by 24px, and closing the last tab in one pane would lift the other's document under
|
|
462
|
-
* its own bar. `.pane-stage` reads it from its cell by cascade. A host outside a cell (the tests,
|
|
463
|
-
* and the bare offset callers) still writes the root, which is exactly what it meant before.
|
|
464
|
-
*
|
|
465
|
-
* @param {number} height Bar height in px. `0` when the pane has no address to print.
|
|
466
|
-
* @param {HTMLElement | null} [host] The bar's host. Its cell takes the variable when it has one.
|
|
466
|
+
* The menu's corner when it hangs above `anchor`: its bottom on the anchor's top, leading edges
|
|
467
|
+
* aligned.
|
|
467
468
|
*/
|
|
468
|
-
export function
|
|
469
|
-
const
|
|
470
|
-
|
|
469
|
+
export function aboveOpener(anchor: HTMLElement, box: DOMRect): { x: number; y: number } {
|
|
470
|
+
const rect = rectOf(anchor);
|
|
471
|
+
return { x: Math.round(rect.left), y: Math.max(0, Math.round(rect.top - box.height)) };
|
|
471
472
|
}
|
|
472
473
|
|
|
473
|
-
/**
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
* @param {string} paneId
|
|
477
|
-
*/
|
|
478
|
-
function projectPane(paneId: string): { steps: ProjectedStep[]; segments: JumpSegment[] } {
|
|
474
|
+
/** The address of the focused pane, and the segments behind it. */
|
|
475
|
+
function projectFocused(): { steps: ProjectedStep[]; segments: JumpSegment[] } {
|
|
476
|
+
const paneId = activePane().id;
|
|
479
477
|
const segments = jumpSegments(tabOfPane(paneId), derivationOfPane(paneId));
|
|
480
478
|
const registry = activeRegistry();
|
|
481
479
|
return {
|
|
@@ -486,65 +484,52 @@ function projectPane(paneId: string): { steps: ProjectedStep[]; segments: JumpSe
|
|
|
486
484
|
};
|
|
487
485
|
}
|
|
488
486
|
|
|
489
|
-
/**
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
* @param {string} [paneId] Defaults to every attached pane — what "render the jump bar" means when
|
|
493
|
-
* the caller is a lifecycle rather than a pane.
|
|
494
|
-
*/
|
|
495
|
-
export function renderJumpBar(paneId?: string): void {
|
|
496
|
-
if (_bars.size === 0) {
|
|
487
|
+
/** Paint the bar. Exported because the bootstrap paints once before mounting the effect. */
|
|
488
|
+
export function renderJumpBar(): void {
|
|
489
|
+
if (!_bar) {
|
|
497
490
|
return;
|
|
498
491
|
}
|
|
499
492
|
// The address changed, so an open menu is describing a place that may no longer be on the bar.
|
|
500
493
|
// Repaints happen only when tracked state moves, so this cannot close a menu you are reading.
|
|
501
494
|
dismissJumpMenu();
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
}
|
|
506
|
-
const { segments, steps } = projectPane(id);
|
|
507
|
-
bar.segments = new Map(steps.map((step, i) => [step.key, segments[i]!]));
|
|
508
|
-
bar.surface.update(steps);
|
|
509
|
-
applyJumpBarOffset(steps.length === 0 ? 0 : JUMP_BAR_HEIGHT, bar.host);
|
|
510
|
-
}
|
|
495
|
+
const { segments, steps } = projectFocused();
|
|
496
|
+
_bar.segments = new Map(steps.map((step, i) => [step.key, segments[i]!]));
|
|
497
|
+
_bar.surface.update(steps);
|
|
511
498
|
}
|
|
512
499
|
|
|
513
500
|
/**
|
|
514
|
-
* Give
|
|
501
|
+
* Give the bar somewhere to paint, or take it away.
|
|
515
502
|
*
|
|
516
|
-
* Called by `
|
|
517
|
-
* mount first:
|
|
518
|
-
* that DOM is about to be unreachable.
|
|
503
|
+
* Called by `surfaces/statusbar.ts` as its document mounts and as it is disposed. Detaching
|
|
504
|
+
* disposes the mount first: the slot being removed still has this bar's document in it, and the
|
|
505
|
+
* runtime that owns that DOM is about to be unreachable.
|
|
519
506
|
*
|
|
520
|
-
* @param {string} paneId
|
|
521
507
|
* @param {HTMLElement | null} host
|
|
522
508
|
*/
|
|
523
|
-
export function attachJumpBarHost(
|
|
524
|
-
|
|
525
|
-
if (previous?.host === host) {
|
|
509
|
+
export function attachJumpBarHost(host: HTMLElement | null): void {
|
|
510
|
+
if (_bar?.host === host) {
|
|
526
511
|
return;
|
|
527
512
|
}
|
|
528
|
-
if (
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
513
|
+
if (_bar) {
|
|
514
|
+
dismissJumpMenu();
|
|
515
|
+
_bar.surface.dispose();
|
|
516
|
+
_bar = null;
|
|
532
517
|
}
|
|
533
518
|
if (!host) {
|
|
534
519
|
return;
|
|
535
520
|
}
|
|
536
|
-
|
|
521
|
+
_bar = {
|
|
537
522
|
host,
|
|
538
523
|
segments: new Map(),
|
|
539
|
-
surface: mountJumpBarSurface(host,
|
|
524
|
+
surface: mountJumpBarSurface(host, JUMP_BAR_REGION, {
|
|
540
525
|
choose: (key, anchor) => {
|
|
541
|
-
const segment =
|
|
526
|
+
const segment = _bar?.segments.get(key);
|
|
542
527
|
if (segment) {
|
|
543
528
|
openChoices(segment, anchor);
|
|
544
529
|
}
|
|
545
530
|
},
|
|
546
531
|
run: (key) => {
|
|
547
|
-
const segment =
|
|
532
|
+
const segment = _bar?.segments.get(key);
|
|
548
533
|
const registry = activeRegistry();
|
|
549
534
|
if (segment?.command && registry) {
|
|
550
535
|
void runReported(registry, segment.command, segment.args, "Jump Bar");
|
|
@@ -552,22 +537,18 @@ export function attachJumpBarHost(paneId: string, host: HTMLElement | null): voi
|
|
|
552
537
|
},
|
|
553
538
|
}),
|
|
554
539
|
};
|
|
555
|
-
|
|
556
|
-
renderJumpBar(paneId);
|
|
540
|
+
renderJumpBar();
|
|
557
541
|
}
|
|
558
542
|
|
|
559
543
|
/**
|
|
560
|
-
* Subscribe the bar to the state it renders. Idempotent.
|
|
544
|
+
* Subscribe the bar to the state it renders. Idempotent: a second call replaces the effect.
|
|
561
545
|
*
|
|
562
|
-
*
|
|
563
|
-
*
|
|
564
|
-
* the
|
|
565
|
-
*
|
|
566
|
-
* @param {HTMLElement} host
|
|
546
|
+
* Called by `surfaces/statusbar.ts`'s `mountStatusbar`, which owns the bar's lifecycle because the
|
|
547
|
+
* trail is its DOCUMENT field. The host arrives separately ({@link attachJumpBarHost}), and either
|
|
548
|
+
* may come first: the effect paints whatever host is attached, and attaching paints at once.
|
|
567
549
|
*/
|
|
568
|
-
export function mountJumpBar(
|
|
569
|
-
|
|
570
|
-
attachJumpBarHost(PRIMARY_PANE, host);
|
|
550
|
+
export function mountJumpBar(): void {
|
|
551
|
+
_scope?.stop();
|
|
571
552
|
_scope = effectScope();
|
|
572
553
|
_scope.run(() => {
|
|
573
554
|
effect(() => {
|
|
@@ -575,14 +556,11 @@ export function mountJumpBar(host: HTMLElement): void {
|
|
|
575
556
|
// Reading it here is what repaints the bar from a skeleton into the real thing.
|
|
576
557
|
void activeRegistry();
|
|
577
558
|
void projectState?.name;
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
if (!tab) {
|
|
584
|
-
continue;
|
|
585
|
-
}
|
|
559
|
+
// The FOCUSED pane's tab: clicking into the other pane re-points the trail.
|
|
560
|
+
void workspace.activePaneId;
|
|
561
|
+
void workspace.panes.length;
|
|
562
|
+
const tab = tabOfPane(activePane().id);
|
|
563
|
+
if (tab) {
|
|
586
564
|
void tab.doc.document;
|
|
587
565
|
void tab.documentPath;
|
|
588
566
|
void tab.session.selection.map((path) => path.join("/")).join("|");
|
|
@@ -594,21 +572,17 @@ export function mountJumpBar(host: HTMLElement): void {
|
|
|
594
572
|
});
|
|
595
573
|
}
|
|
596
574
|
|
|
575
|
+
/** Stop the effect and take the bar down. */
|
|
597
576
|
export function unmountJumpBar(): void {
|
|
598
577
|
dismissJumpMenu();
|
|
599
578
|
_scope?.stop();
|
|
600
579
|
_scope = null;
|
|
601
|
-
|
|
602
|
-
bar.surface.dispose();
|
|
603
|
-
applyJumpBarOffset(0, bar.host);
|
|
604
|
-
}
|
|
605
|
-
_bars.clear();
|
|
606
|
-
applyJumpBarOffset(0);
|
|
580
|
+
attachJumpBarHost(null);
|
|
607
581
|
}
|
|
608
582
|
|
|
609
583
|
// ─── This bar contributes no commands ────────────────────────────────────────
|
|
610
584
|
// It declared one, `document.setStackLevel` — "leave a sub-document by naming the level you want to
|
|
611
585
|
// Be at". Its `enablement` read `session.documentStack.length > 0`, a stack nothing could ever push
|
|
612
586
|
// To, so the command was permanently disabled and its palette entry permanently unreachable. Every
|
|
613
|
-
// Id the bar renders now belongs to the surface that owns the behaviour: `
|
|
614
|
-
// `
|
|
587
|
+
// Id the bar renders now belongs to the surface that owns the behaviour: `palette.openFiles`,
|
|
588
|
+
// `pane.pin`, `selection.set`.
|
|
@@ -303,10 +303,9 @@ export function unmount() {
|
|
|
303
303
|
* welcome screen (no tab, no bar) does not open under a 28px gap nothing explains, and a read-only
|
|
304
304
|
* banner does not sit on top of the document it is warning you about.
|
|
305
305
|
*
|
|
306
|
-
* **On the PANE, not on `:root
|
|
307
|
-
*
|
|
308
|
-
*
|
|
309
|
-
* when the shell had one bar.
|
|
306
|
+
* **On the PANE, not on `:root`**: two cells have two bands of different heights, and a single
|
|
307
|
+
* document-level number offsets both stages by whichever pane painted last. A host outside a cell
|
|
308
|
+
* writes the root, which is what it meant when the shell had one bar.
|
|
310
309
|
*
|
|
311
310
|
* @param {number} height Band height in px. `0` when the pane has no chrome.
|
|
312
311
|
* @param {HTMLElement | null} [host] The bar's host. Its cell takes the variable when it has one.
|
|
@@ -409,7 +408,8 @@ export function dismissPresetMenu(): void {
|
|
|
409
408
|
*
|
|
410
409
|
* The leading slot existed to push the three axes right. It is where §18.4's preset menu goes
|
|
411
410
|
* because the menu is about THIS PANE and the bar is the pane's own chrome; the alternative homes
|
|
412
|
-
* (the tab strip, the
|
|
411
|
+
* (the tab strip, the status bar's breadcrumb trail) are about a document and an address
|
|
412
|
+
* respectively.
|
|
413
413
|
*
|
|
414
414
|
* **There is no `pane.showDerivePresets`.** §13.5, quoted verbatim in `canvas/canvas-render.ts`:
|
|
415
415
|
* opening a menu to press an item names a CONTROL; the item is the command. Every row here runs
|
|
@@ -625,9 +625,9 @@ export function presetRows(paneId: string): PresetRow[] {
|
|
|
625
625
|
* the stage and the zoom pod still has something to zoom. Suppressing them while the dock was open
|
|
626
626
|
* removed the controls for the very document the reader could still see.
|
|
627
627
|
*
|
|
628
|
-
* **There is no breadcrumb either.** The address is the jump bar's job — `panels/jump-bar.ts`,
|
|
629
|
-
*
|
|
630
|
-
* second trail beside both of them.
|
|
628
|
+
* **There is no breadcrumb either.** The address is the jump bar's job — `panels/jump-bar.ts`, the
|
|
629
|
+
* status bar's trail — and the Logic tab's own header carries the Close. This bar drew a second
|
|
630
|
+
* Back and a second trail beside both of them.
|
|
631
631
|
*/
|
|
632
632
|
function viewFor(tab: Tab, paneId: string, ctx: PaneContextCtx): PaneContextView {
|
|
633
633
|
/* A LENS suppresses the two axes that WRITE. Editor kind and Canvas view both land in
|
package/src/panels/pane-grid.ts
CHANGED
|
@@ -5,27 +5,28 @@
|
|
|
5
5
|
* `workspace.panes` has been a real data model since the shell redesign's chrome phase: an ordered
|
|
6
6
|
* list, a focused id, a split, an unsplit. Nothing drew it. `index.html` declared ONE each of
|
|
7
7
|
* `#tab-strip`, `#jump-bar`, `#pane-chrome` and `#canvas-wrap` as flat siblings in `#app`'s grid —
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* surfaces that belong to a PANE, laid out as rows and columns of the APPLICATION — so the shell
|
|
9
|
+
* could model two panes and had somewhere to put exactly one. §18.3's stage handover was the
|
|
10
10
|
* workaround: one stage, taken by whichever pane had focus, releasing the loser's artboards on the
|
|
11
11
|
* way past. This module is what that scaffolding was standing in for, and the handover is deleted
|
|
12
12
|
* with it.
|
|
13
13
|
*
|
|
14
14
|
* **The document owns the frame; this module owns the decisions.** `surfaces/pane-grid.json` is the
|
|
15
|
-
* cells, the
|
|
15
|
+
* cells, the four boxes inside each one, the splitter between two of them and every rule that lays
|
|
16
16
|
* them out; `surfaces/pane-grid.ts` is the mount. What is left here is the flow: which panes there
|
|
17
17
|
* are, what a cell's stage is furnished with, in what ORDER a departing cell is taken apart, and
|
|
18
18
|
* what the grid's own tracks are. Everything a cell CONTAINS still arrives through the module that
|
|
19
19
|
* owns it — `canvas/canvas-render.ts` is the render root of the stage and this document puts
|
|
20
|
-
* nothing inside it, `panels/
|
|
21
|
-
*
|
|
22
|
-
*
|
|
20
|
+
* nothing inside it, `panels/pane-context.ts` is handed the chrome box, `panels/tab-strip.ts` is
|
|
21
|
+
* handed the strip, and this module makes the fourth — the right-edge drop zone — a pragmatic
|
|
22
|
+
* target itself. (The jump bar had a box here too, until it moved to the status bar: a pane's
|
|
23
|
+
* address is now the focused pane's breadcrumb trail along the foot of the window.)
|
|
23
24
|
*
|
|
24
25
|
* **Three properties survived the conversion, and each is structural rather than remembered:**
|
|
25
26
|
*
|
|
26
27
|
* 1. _A pane is complete before it is published._ The runtime builds a `$map` row inside its own
|
|
27
|
-
* effect scope and inserts it afterwards, so the
|
|
28
|
-
*
|
|
28
|
+
* effect scope and inserts it afterwards, so the `cellPart` calls below — the surface record,
|
|
29
|
+
* the gestures, the context bar's mount, the pane-focus listener, the drop zone's own
|
|
29
30
|
* registration — all happen while the cell is still detached. There is no frame in which a cell
|
|
30
31
|
* exists with no stage inside it.
|
|
31
32
|
* 2. _A pane's node is never re-parented._ The repeater is keyed on the pane id and the runtime's
|
|
@@ -81,7 +82,6 @@ import { releaseCanvasHosts } from "../canvas/iframe-host";
|
|
|
81
82
|
import { installStageGestures } from "../editor/shortcuts";
|
|
82
83
|
import { scheduleCanvasRender } from "../canvas/canvas-render";
|
|
83
84
|
import { paneRegion, paneStripRegion } from "../ui/regions";
|
|
84
|
-
import { attachJumpBarHost } from "./jump-bar";
|
|
85
85
|
import { attachPaneChromeHost } from "./pane-context";
|
|
86
86
|
import { MAX_PANES, focusPane, workspace } from "../workspace/workspace";
|
|
87
87
|
import { mountPaneGridSurface } from "../surfaces/pane-grid";
|
|
@@ -89,12 +89,11 @@ import type { EffectScope } from "@vue/reactivity";
|
|
|
89
89
|
import type { CanvasSurface } from "../canvas/canvas-surface";
|
|
90
90
|
import type { PaneCellPart, PaneGridRow, PaneGridSurface } from "../surfaces/pane-grid";
|
|
91
91
|
|
|
92
|
-
/** One drawn pane: its root and the
|
|
92
|
+
/** One drawn pane: its root and the four surfaces inside it. */
|
|
93
93
|
export interface PaneCell {
|
|
94
94
|
paneId: string;
|
|
95
95
|
root: HTMLElement;
|
|
96
96
|
strip: HTMLElement;
|
|
97
|
-
jump: HTMLElement;
|
|
98
97
|
chrome: HTMLElement;
|
|
99
98
|
stage: HTMLElement;
|
|
100
99
|
dropZone: HTMLElement;
|
|
@@ -162,7 +161,6 @@ function cellState(paneId: string): CellState {
|
|
|
162
161
|
const cell: CellState = {
|
|
163
162
|
chrome: null as unknown as HTMLElement,
|
|
164
163
|
dropZone: null as unknown as HTMLElement,
|
|
165
|
-
jump: null as unknown as HTMLElement,
|
|
166
164
|
paneId,
|
|
167
165
|
releaseDropZone: null,
|
|
168
166
|
releaseGestures: null,
|
|
@@ -283,15 +281,15 @@ function attachDropZone(paneId: string, element: HTMLElement): () => void {
|
|
|
283
281
|
}
|
|
284
282
|
|
|
285
283
|
/**
|
|
286
|
-
* One of a cell's
|
|
284
|
+
* One of a cell's five boxes has been created. Fill the record in, and wire what belongs to it.
|
|
287
285
|
*
|
|
288
|
-
* The
|
|
289
|
-
* `panels/frontmatter-panel.ts` is handed the stage.
|
|
286
|
+
* The context bar is HANDED its host rather than resolving a region, the same way
|
|
287
|
+
* `panels/frontmatter-panel.ts` is handed the stage. It cannot resolve one the way the tab strip
|
|
290
288
|
* does: the strip's host carries `pane.<id>/tabs` and nothing inside it re-stamps that id, while
|
|
291
|
-
* the
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
*
|
|
289
|
+
* the context bar stamps `pane.<id>/context` on markup it renders INSIDE its box — so a region on
|
|
290
|
+
* the wrapper as well would put the same id on two nested elements, and `resolveRegion` takes the
|
|
291
|
+
* LAST match. Sixty shots crop `pane.primary/context`; a second, larger element carrying it is a
|
|
292
|
+
* silently widened crop.
|
|
295
293
|
*/
|
|
296
294
|
function cellPart(paneId: string, part: PaneCellPart, element: HTMLElement): void {
|
|
297
295
|
const cell = cellState(paneId);
|
|
@@ -304,11 +302,6 @@ function cellPart(paneId: string, part: PaneCellPart, element: HTMLElement): voi
|
|
|
304
302
|
cell.strip = element;
|
|
305
303
|
return;
|
|
306
304
|
}
|
|
307
|
-
if (part === "jump") {
|
|
308
|
-
cell.jump = element;
|
|
309
|
-
attachJumpBarHost(paneId, element);
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
305
|
if (part === "chrome") {
|
|
313
306
|
cell.chrome = element;
|
|
314
307
|
attachPaneChromeHost(paneId, element);
|
|
@@ -333,7 +326,7 @@ function cellPart(paneId: string, part: PaneCellPart, element: HTMLElement): voi
|
|
|
333
326
|
*
|
|
334
327
|
* The order is the document's own, and each step needs the one before it:
|
|
335
328
|
*
|
|
336
|
-
* - The
|
|
329
|
+
* - The context bar goes first, disposing a mount whose DOM is inside this cell — the runtime that
|
|
337
330
|
* owns it is about to be unreachable.
|
|
338
331
|
* - `releaseCanvasHosts` goes before `disposePaneSurface` and while `stage` still CONTAINS its
|
|
339
332
|
* frames, which is the whole reason it can find them. A frame released later is noticed only by
|
|
@@ -345,7 +338,6 @@ function cellPart(paneId: string, part: PaneCellPart, element: HTMLElement): voi
|
|
|
345
338
|
function disposeCell(cell: CellState): void {
|
|
346
339
|
cell.releaseDropZone?.();
|
|
347
340
|
cell.releaseDropZone = null;
|
|
348
|
-
attachJumpBarHost(cell.paneId, null);
|
|
349
341
|
attachPaneChromeHost(cell.paneId, null);
|
|
350
342
|
cell.releaseGestures?.();
|
|
351
343
|
cell.releaseGestures = null;
|