@jxsuite/studio 5.2.0 → 5.4.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 +28 -27
- package/dist/chunks/{cf-account-picker-h4dab9bq.js → cf-account-picker-3f08rry6.js} +21 -18
- package/dist/chunks/{cf-settings-adg74qsk.js → cf-settings-m79r7p5y.js} +4 -4
- package/dist/chunks/{components-5y78e05d.js → components-xm826zjw.js} +3 -3
- package/dist/chunks/{content-source-sgg1sv6n.js → content-source-jt7rbcbc.js} +22 -22
- package/dist/chunks/{convert-to-repeater-mf1cxgfn.js → convert-to-repeater-vg38bq99.js} +22 -22
- package/dist/chunks/{editor-3qhbg51x.js → editor-ddy019sn.js} +2 -2
- package/dist/chunks/entry-commands-64nb2a9a.js +42 -0
- package/dist/chunks/{extension-sections-c6zwzbre.js → extension-sections-r73an5s6.js} +31 -30
- package/dist/chunks/{file-ops-vrpq1jjk.js → file-ops-3xan8mnj.js} +21 -21
- package/dist/chunks/{files-msaf95y6.js → files-egsb0ry8.js} +30 -29
- package/dist/chunks/{format-host-f64fnesp.js → format-host-mym8qnd0.js} +3 -3
- package/dist/chunks/{fs-events-3y6y0nrm.js → fs-events-z2gg8qjt.js} +4 -4
- package/dist/chunks/{git-panel-bv5e22j0.js → git-panel-a05atk6q.js} +20 -20
- package/dist/chunks/{grid-view-1p6hsyjx.css → grid-view-3g1h2re8.css} +956 -139
- package/dist/chunks/{grid-view-paj67nr5.js → grid-view-qaqer9kr.js} +24 -24
- package/dist/chunks/{icons-yy10wk9r.js → icons-drxq9q10.js} +8 -2
- package/dist/chunks/{iframe-host-dh5np8vk.js → iframe-host-psetcv20.js} +11 -11
- package/dist/chunks/{index-n4j7qxyr.js → index-9yjae3hz.js} +4 -4
- package/dist/chunks/{javascript-4abzjcy9.css → javascript-bc9z461d.css} +688 -54
- package/dist/chunks/{javascript-xvrfrpkb.js → javascript-hr5sg57n.js} +2 -2
- package/dist/chunks/{jsonMode-vvmpmk34.css → jsonMode-qqd9nm1t.css} +1120 -303
- package/dist/chunks/{jsonMode-tyx2kj6p.js → jsonMode-zs88v0wr.js} +4 -4
- package/dist/chunks/{jx-validate-j0wxk72w.js → jx-validate-epp2z3s3.js} +2 -2
- package/dist/chunks/layers-panel-83a16ytx.js +41 -0
- package/dist/chunks/{layers-1vcfdbet.js → layers-s6mc01ry.js} +3 -3
- package/dist/chunks/{listbox-6v2ac08j.js → listbox-b7jxnhq1.js} +19 -3
- package/dist/chunks/{media-picker-p49nhqhs.js → media-picker-nhn6rv4w.js} +11 -11
- package/dist/chunks/{menu-qht48vnc.js → menu-8j4qxjrp.js} +4 -4
- package/dist/chunks/{monaco-binding-sw6en4dw.js → monaco-binding-e8d9wzyk.js} +3 -3
- package/dist/chunks/{monaco-buffer-pykwbm92.js → monaco-buffer-jaq1t9zj.js} +2 -2
- package/dist/chunks/{monaco-setup-8vbyqnhr.css → monaco-setup-ey9cjcm3.css} +954 -137
- package/dist/chunks/{monaco-setup-8r62fj6y.js → monaco-setup-gsjdysze.js} +7 -7
- package/dist/chunks/{platform-ts9cg1a4.js → platform-fnchmhy7.js} +5 -3
- package/dist/chunks/publish-panel-ak6hxfma.js +27 -0
- package/dist/chunks/quick-search-c63mkt3b.js +47 -0
- package/dist/chunks/{references-h69xp9zz.js → references-f7bdv3z5.js} +3 -3
- package/dist/chunks/right-panel-t5n8wttg.js +45 -0
- package/dist/chunks/{split-g7nm1rgb.js → split-4cz4b6ef.js} +14 -3
- package/dist/chunks/{studio-sar8g54p.js → studio-01269reb.js} +8 -8
- package/dist/chunks/{studio-rnyf3f8e.js → studio-0a4gncx0.js} +3 -3
- package/dist/chunks/{studio-e1f24eff.js → studio-0d4p4wxj.js} +6778 -2993
- package/dist/chunks/{studio-4wbb9ct0.js → studio-1tejxvba.js} +3006 -1855
- package/dist/chunks/{studio-p6pmwkvh.js → studio-3nprwbd9.js} +147 -28
- package/dist/chunks/{studio-4c041r8y.js → studio-40z39dme.js} +3 -3
- package/dist/chunks/{studio-68fydsrj.js → studio-482eeazk.js} +20 -20
- package/dist/chunks/{studio-y4f9fdge.js → studio-4998spet.js} +10 -9
- package/dist/chunks/{studio-nq5yf5mp.js → studio-557bmn0x.js} +2 -2
- package/dist/chunks/{studio-hdc2jt3z.js → studio-5w26wza5.js} +3 -3
- package/dist/chunks/{studio-6nzaktvy.js → studio-6pwn9j8c.js} +6 -3
- package/dist/chunks/{studio-wnsyffg1.js → studio-6vg0x5fz.js} +3 -2
- package/dist/chunks/{studio-vn5hske5.js → studio-7d3c1m59.js} +12 -5
- package/dist/chunks/{studio-28vs5k2y.js → studio-9vsvz7w7.js} +7 -7
- package/dist/chunks/{studio-t3adrr56.js → studio-9wm0xzpf.js} +19 -19
- package/dist/chunks/{studio-38emantv.js → studio-a5h5j33a.js} +19 -5
- package/dist/chunks/{studio-ympe0n7a.js → studio-ag3z6shb.js} +10 -4
- package/dist/chunks/studio-aj9drheq.js +177 -0
- package/dist/chunks/{studio-vt0tj32j.js → studio-apv9x70c.js} +189 -130
- package/dist/chunks/{studio-c04nzbby.js → studio-b9q3znz8.js} +2 -2
- package/dist/chunks/{studio-2mdbbc76.js → studio-bh47w0cy.js} +9 -10
- package/dist/chunks/{studio-ez11dmdh.js → studio-dgdm6vvt.js} +264 -52
- package/dist/chunks/{studio-5nz00bhh.js → studio-dwdcr2e8.js} +4 -4
- package/dist/chunks/{studio-nqgawfks.js → studio-fbcyz234.js} +146 -139
- package/dist/chunks/{studio-kcgff4r0.js → studio-fgmfksz8.js} +2 -2
- package/dist/chunks/{studio-x72j58vw.js → studio-fqpkpq1t.js} +7 -4
- package/dist/chunks/{studio-15f3kxqe.js → studio-fy320dfc.js} +62 -68
- package/dist/chunks/{studio-zjjde71a.js → studio-gjj4bbfx.js} +2 -2
- package/dist/chunks/{studio-66arbpc2.js → studio-jfhxy8h3.js} +16 -15
- package/dist/chunks/{studio-d0300636.js → studio-ks2zzth2.js} +17 -2
- package/dist/chunks/{studio-c07s5ckd.js → studio-kwewmhhq.js} +4 -4
- package/dist/chunks/{studio-01jeck2y.js → studio-m58xn8at.js} +26 -25
- package/dist/chunks/{studio-mpzwze9x.js → studio-mfkh1q8d.js} +17 -17
- package/dist/chunks/{studio-etvx9s2g.js → studio-mrh0a92f.js} +17 -17
- package/dist/chunks/{studio-qa7fzxan.js → studio-mt79tn56.js} +3 -3
- package/dist/chunks/{studio-hhskq2mr.js → studio-ne593z1j.js} +39 -32
- package/dist/chunks/{studio-h4nvnjvz.js → studio-ptfcxkz5.js} +418 -232
- package/dist/chunks/{studio-4xmjcrg3.js → studio-qxye31h7.js} +7 -7
- package/dist/chunks/{studio-a1pswps3.js → studio-rav5bpmp.js} +81 -59
- package/dist/chunks/{studio-ncn9e189.js → studio-rwmmbrth.js} +6 -6
- package/dist/chunks/{studio-en82c639.js → studio-sceg8ws0.js} +8 -8
- package/dist/chunks/{studio-wjpgxywa.js → studio-sjas5b3a.js} +19 -13
- package/dist/chunks/{studio-4r14yzyy.js → studio-vd67b66d.js} +3 -3
- package/dist/chunks/{studio-14d9tq4d.js → studio-w475cbf9.js} +10 -10
- package/dist/chunks/{studio-ctm7bhx5.js → studio-w7gpcvfj.js} +9 -9
- package/dist/chunks/{studio-9j6sfeba.js → studio-xrbfdxgk.js} +7 -7
- package/dist/chunks/{studio-x10fp4tp.js → studio-y49b6mjv.js} +35 -35
- package/dist/chunks/{studio-5t7ena5z.js → studio-ygvr9e4q.js} +10 -10
- package/dist/chunks/{studio-z2smx5ce.js → studio-yxmmjy2a.js} +9 -6
- package/dist/chunks/{tsMode-jy4m86rv.js → tsMode-ay4c78ne.js} +4 -4
- package/dist/chunks/{tsMode-hnxxb73h.css → tsMode-c72wyz27.css} +954 -137
- package/dist/chunks/{workspace-bnw54cha.js → workspace-b9k2frks.js} +5 -5
- package/dist/chunks/{ws-client-ny4zc51r.js → ws-client-erze4czt.js} +356 -20
- package/dist/codicon.ttf +0 -0
- package/dist/iframe-entry.js +20 -18
- package/dist/studio.css +956 -139
- package/dist/studio.js +1511 -851
- package/dist/workers/editor.worker.js +196 -107
- package/dist/workers/json.worker.js +196 -107
- package/dist/workers/ts.worker.js +196 -107
- package/package.json +18 -17
- package/src/about/about-modal.ts +4 -3
- package/src/browse/library-commands.ts +15 -13
- package/src/browse/library-pane.ts +2 -2
- package/src/canvas/canvas-render.ts +97 -83
- package/src/canvas/canvas-surface.ts +2 -2
- package/src/canvas/canvas-utils.ts +42 -32
- package/src/canvas/diff-toolbar.ts +21 -2
- package/src/canvas/diff-view.ts +30 -6
- package/src/canvas/iframe-entry.ts +2 -2
- package/src/canvas/iframe-host.ts +5 -5
- package/src/canvas/iframe-interaction.ts +7 -6
- package/src/canvas/iframe-overlay.ts +1 -1
- package/src/canvas/iframe-protocol.ts +6 -5
- package/src/canvas/iframe-render.ts +3 -3
- package/src/canvas/popover-state.ts +1 -1
- package/src/canvas/stage-scrollbar.ts +112 -0
- package/src/canvas/surface-registry.ts +9 -2
- package/src/collab/collab-commands.ts +8 -6
- package/src/collab/collab-session.ts +4 -4
- package/src/collab/collab-state.ts +4 -4
- package/src/collab/presence-chips.ts +3 -3
- package/src/commands/app-commands.ts +7 -7
- package/src/commands/budget.ts +17 -16
- package/src/commands/command-args.ts +10 -9
- package/src/commands/context.ts +20 -10
- package/src/commands/defaults.ts +30 -29
- package/src/commands/levels.ts +8 -6
- package/src/commands/live-context.ts +12 -10
- package/src/commands/reference.ts +5 -5
- package/src/commands/registry.ts +2 -2
- package/src/content/draft-state.ts +9 -8
- package/src/content/entry-commands.ts +16 -14
- package/src/content/entry-editor.ts +2 -2
- package/src/content/entry-fields.ts +1 -1
- package/src/editor/context-menu.ts +4 -4
- package/src/editor/convert-to-component.ts +6 -5
- package/src/editor/inline-edit.ts +3 -3
- package/src/editor/shortcuts.ts +88 -20
- package/src/editor/slash-menu.ts +11 -10
- package/src/files/elements.ts +4 -5
- package/src/files/file-ops.ts +1 -1
- package/src/files/files.ts +21 -17
- package/src/files/serialize-document.ts +1 -1
- package/src/format/convert-file.ts +5 -5
- package/src/github/github-auth-status.ts +107 -0
- package/src/github/github-auth.ts +18 -82
- package/src/github/github-publish.ts +7 -6
- package/src/grid/cell-editors.ts +8 -7
- package/src/grid/grid-layout.ts +1 -1
- package/src/grid/grid-open.ts +6 -5
- package/src/grid/grid-panel.ts +13 -12
- package/src/grid/redirects-grid.ts +14 -11
- package/src/grid/redirects.ts +10 -5
- package/src/grid/sources/content-source.ts +10 -9
- package/src/hosting/document.ts +28 -1
- package/src/hosting/stage.ts +15 -4
- package/src/i18n/i18n-commands.ts +9 -7
- package/src/new-project/location-fields.ts +16 -3
- package/src/new-project/new-project-modal.ts +23 -7
- package/src/page-params.ts +6 -6
- package/src/panels/activity-panel.ts +11 -10
- package/src/panels/ai-chat/chat-view.ts +27 -14
- package/src/panels/ai-chat/composer.ts +10 -3
- package/src/panels/ai-panel.ts +87 -29
- package/src/panels/block-action-bar.ts +59 -33
- package/src/panels/bottom-dock.ts +22 -22
- package/src/panels/chat-panel.ts +40 -5
- package/src/panels/data-explorer.ts +9 -9
- package/src/panels/data-grid.ts +1 -1
- package/src/panels/editors.ts +8 -8
- package/src/panels/elements-panel.ts +7 -8
- package/src/panels/empty-state.ts +1 -1
- package/src/panels/events-panel.ts +13 -12
- package/src/panels/formula-workspace.ts +8 -5
- package/src/panels/frontmatter-fields.ts +4 -1
- package/src/panels/frontmatter-panel.ts +18 -18
- package/src/panels/git-panel.ts +19 -13
- package/src/panels/head-panel.ts +9 -10
- package/src/panels/i18n-panel.ts +6 -4
- package/src/panels/imports-panel.ts +1 -1
- package/src/panels/jump-bar.ts +20 -18
- package/src/panels/layers-panel.ts +19 -17
- package/src/panels/left-panel.ts +3 -3
- package/src/panels/navigator-panels.ts +8 -8
- package/src/panels/overlays.ts +1 -1
- package/src/panels/pane-context.ts +56 -28
- package/src/panels/pane-grid.ts +9 -8
- package/src/panels/panel-registry.ts +47 -19
- package/src/panels/problems-panel.ts +11 -12
- package/src/panels/properties-panel.ts +21 -20
- package/src/panels/provenance.ts +3 -3
- package/src/panels/quick-search.ts +15 -11
- package/src/panels/right-panel.ts +4 -3
- package/src/panels/seo-modal.ts +5 -4
- package/src/panels/settings-menu.ts +9 -9
- package/src/panels/settings-pane.ts +3 -3
- package/src/panels/signals-panel.ts +16 -9
- package/src/panels/statement-editor.ts +12 -9
- package/src/panels/style-panel.ts +45 -41
- package/src/panels/stylebook-panel.ts +0 -1
- package/src/panels/tab-strip.ts +26 -23
- package/src/platform-errors.ts +2 -2
- package/src/platform.ts +44 -4
- package/src/platforms/cloud.ts +11 -1
- package/src/platforms/default-platform.ts +141 -4
- package/src/platforms/devserver.ts +23 -3
- package/src/publish/deploy-checklist.ts +11 -10
- package/src/publish/publish-commands.ts +9 -8
- package/src/services/a11y-report.ts +1 -1
- package/src/services/ai-ask.ts +39 -16
- package/src/services/ai-command-tools.ts +28 -14
- package/src/services/ai-import-tools.ts +43 -29
- package/src/services/ai-project-tools.ts +20 -38
- package/src/services/ai-settings.ts +55 -2
- package/src/services/ai-tools.ts +69 -58
- package/src/services/ai-write-report.ts +4 -4
- package/src/services/ai-writes.ts +74 -55
- package/src/services/automation.ts +12 -12
- package/src/services/clock.ts +2 -1
- package/src/services/connection.ts +2 -2
- package/src/services/context-manager.ts +69 -6
- package/src/services/directory-picker.ts +93 -27
- package/src/services/document-assistant.ts +86 -17
- package/src/services/gated-registry.ts +4 -3
- package/src/services/idle.ts +5 -4
- package/src/services/live-surfaces.ts +2 -1
- package/src/services/module-preloads.ts +67 -0
- package/src/services/notify.ts +9 -7
- package/src/services/popover-report.ts +3 -3
- package/src/services/preview-eval.ts +1 -1
- package/src/services/project-adoption.ts +34 -1
- package/src/services/project-path.ts +53 -0
- package/src/services/settings/kernel.ts +13 -2
- package/src/services/tool-executor.ts +135 -30
- package/src/services/tool-outcomes.ts +143 -0
- package/src/settings/contexts-section.ts +8 -8
- package/src/settings/contributed-section.ts +6 -6
- package/src/settings/css-vars-editor.ts +6 -5
- package/src/settings/extension-commands.ts +19 -18
- package/src/settings/extension-sections.ts +7 -7
- package/src/settings/extensions-section.ts +3 -3
- package/src/settings/general-settings.ts +21 -18
- package/src/settings/preferences-accounts.ts +3 -3
- package/src/settings/preferences-dialog.ts +9 -8
- package/src/settings/preferences-sections.ts +1 -1
- package/src/settings/project-sections.ts +2 -2
- package/src/settings/section-registry.ts +7 -6
- package/src/settings/settings-document.ts +41 -43
- package/src/shell/tree.ts +29 -0
- package/src/shell.ts +63 -55
- package/src/site-context.ts +1 -1
- package/src/store.ts +2 -2
- package/src/studio.ts +52 -28
- package/src/style/live-preview.ts +8 -8
- package/src/style/project-styles.ts +8 -9
- package/src/style/token-ref.ts +2 -2
- package/src/surfaces/about.json +6 -2
- package/src/surfaces/add-repo.json +2 -2
- package/src/surfaces/add-repo.ts +2 -2
- package/src/surfaces/ai-chat.json +14 -6
- package/src/surfaces/ai-chat.ts +4 -2
- package/src/surfaces/ai-credentials-form.json +53 -49
- package/src/surfaces/ai-credentials-form.ts +18 -4
- package/src/surfaces/ai-managed-connect.json +4 -4
- package/src/surfaces/block-action-bar.json +4 -4
- package/src/surfaces/block-action-bar.ts +3 -3
- package/src/surfaces/boot-failure.json +228 -0
- package/src/surfaces/boot-failure.ts +156 -0
- package/src/surfaces/bottom-dock.json +1 -1
- package/src/surfaces/canvas-stage.json +9 -40
- package/src/surfaces/canvas-stage.ts +9 -9
- package/src/surfaces/cf-account-picker.json +11 -8
- package/src/surfaces/commandbar.ts +11 -10
- package/src/surfaces/convert-repeater.ts +3 -2
- package/src/surfaces/dialog.json +7 -1
- package/src/surfaces/dialog.ts +2 -2
- package/src/surfaces/doc-header.json +6 -13
- package/src/surfaces/doc-header.ts +4 -5
- package/src/surfaces/entry-editor.json +1 -1
- package/src/surfaces/entry-editor.ts +2 -1
- package/src/surfaces/expression-editor.json +5 -5
- package/src/surfaces/files-panel.json +4 -3
- package/src/surfaces/files-panel.ts +1 -1
- package/src/surfaces/formula-palette.json +10 -9
- package/src/surfaces/formula-palette.ts +11 -7
- package/src/surfaces/git-panel.json +167 -109
- package/src/surfaces/git-panel.ts +2 -2
- package/src/surfaces/github-auth.json +2 -1
- package/src/surfaces/github-publish.ts +3 -3
- package/src/surfaces/grid-open.json +1 -1
- package/src/surfaces/grid-panel.json +2 -2
- package/src/surfaces/grid-views.json +1 -1
- package/src/surfaces/inspector-dock.json +2 -2
- package/src/surfaces/jump-bar.json +1 -1
- package/src/surfaces/jump-bar.ts +1 -1
- package/src/surfaces/library-pane.ts +2 -1
- package/src/surfaces/logic-panel.json +7 -7
- package/src/surfaces/logic-panel.ts +6 -4
- package/src/surfaces/logic-workspace.json +2 -2
- package/src/surfaces/logic-workspace.ts +2 -2
- package/src/surfaces/media-browser.ts +3 -3
- package/src/surfaces/media-pane.ts +2 -1
- package/src/surfaces/menu.ts +5 -5
- package/src/surfaces/new-project.json +1 -1
- package/src/surfaces/palette.json +8 -7
- package/src/surfaces/pane-context.json +86 -57
- package/src/surfaces/pane-context.ts +2 -1
- package/src/surfaces/pane-grid.json +3 -3
- package/src/surfaces/panel-activity.json +2 -1
- package/src/surfaces/panel-deploy-checklist.json +1 -1
- package/src/surfaces/panel-elements.ts +2 -1
- package/src/surfaces/panel-i18n.ts +2 -1
- package/src/surfaces/panel-outline.json +1 -1
- package/src/surfaces/panel-outline.ts +4 -3
- package/src/surfaces/panel-page.json +2 -2
- package/src/surfaces/panel-page.ts +4 -1
- package/src/surfaces/panel-problems.json +4 -3
- package/src/surfaces/panel-problems.ts +2 -2
- package/src/surfaces/panel-signals.json +23 -8
- package/src/surfaces/panel-signals.ts +5 -1
- package/src/surfaces/panel-stylebook-layers.json +1 -1
- package/src/surfaces/panel-stylebook-layers.ts +2 -2
- package/src/surfaces/preferences.json +21 -8
- package/src/surfaces/preferences.ts +9 -1
- package/src/surfaces/properties-panel.json +4 -4
- package/src/surfaces/properties-panel.ts +2 -2
- package/src/surfaces/publish.json +1 -1
- package/src/surfaces/publish.ts +2 -1
- package/src/surfaces/push-plan.json +4 -3
- package/src/surfaces/rail.json +2 -2
- package/src/surfaces/rail.ts +10 -4
- package/src/surfaces/reference-field.json +1 -1
- package/src/surfaces/schema-form.json +2 -2
- package/src/surfaces/schema-form.ts +1 -1
- package/src/surfaces/seo.json +1 -1
- package/src/surfaces/seo.ts +2 -2
- package/src/surfaces/settings-contributed.ts +2 -1
- package/src/surfaces/settings-css-vars.json +4 -4
- package/src/surfaces/settings-deploy.json +4 -4
- package/src/surfaces/settings-deploy.ts +2 -1
- package/src/surfaces/settings-extensions.json +6 -6
- package/src/surfaces/settings-extensions.ts +6 -2
- package/src/surfaces/settings-locales.json +4 -4
- package/src/surfaces/settings-overview.ts +2 -1
- package/src/surfaces/settings-pane.ts +3 -2
- package/src/surfaces/settings-rawjson.ts +1 -1
- package/src/surfaces/slash-menu.ts +4 -4
- package/src/surfaces/statements.json +3 -3
- package/src/surfaces/statusbar.ts +23 -23
- package/src/surfaces/style-panel.json +9 -5
- package/src/surfaces/style-panel.ts +3 -3
- package/src/surfaces/tab-strip.json +2 -2
- package/src/surfaces/target-line.json +1 -1
- package/src/surfaces/target-line.ts +12 -10
- package/src/surfaces/welcome.json +7 -2
- package/src/tabs/doc-op-apply.ts +5 -5
- package/src/tabs/patch-ops.ts +3 -3
- package/src/tabs/project-config.ts +10 -10
- package/src/tabs/selection.ts +1 -1
- package/src/tabs/tab.ts +13 -14
- package/src/tabs/transact.ts +18 -24
- package/src/types.ts +27 -3
- package/src/ui/ai-credentials-form.ts +74 -16
- package/src/ui/ai-managed-connect.ts +68 -19
- package/src/ui/color-selector.ts +1 -1
- package/src/ui/expression-editor.ts +3 -3
- package/src/ui/form-controls.ts +6 -5
- package/src/ui/formula-catalog.ts +4 -4
- package/src/ui/formula-chips.ts +2 -2
- package/src/ui/layers.ts +20 -18
- package/src/ui/panel-resize.ts +8 -28
- package/src/ui/popover-surface.ts +2 -2
- package/src/ui/progress-modal.ts +3 -3
- package/src/ui/regions.ts +14 -9
- package/src/ui/schema-form.ts +10 -9
- package/src/ui/timing.ts +9 -7
- package/src/ui/value-source.ts +4 -4
- package/src/ui/virtual-window.ts +58 -5
- package/src/utils/base64.ts +20 -1
- package/src/utils/canvas-media.ts +1 -1
- package/src/utils/studio-utils.ts +0 -31
- package/src/view.ts +4 -3
- package/src/workspace/pane-derive.ts +14 -13
- package/src/workspace/session.ts +7 -6
- package/src/workspace/workspace.ts +49 -39
- package/styles/canvas.css +1 -27
- package/styles/inspector.css +4 -3
- package/styles/overlays.css +1 -1
- package/styles/tokens.css +17 -1
- package/styles/tokens.json +6 -1
- package/dist/chunks/entry-commands-w9qsxa6q.js +0 -42
- package/dist/chunks/layers-panel-fksbdg4q.js +0 -40
- package/dist/chunks/publish-panel-vz23wwmg.js +0 -27
- package/dist/chunks/quick-search-e9rp74m8.js +0 -46
- package/dist/chunks/right-panel-j97t2yvy.js +0 -45
- package/dist/chunks/studio-727xh0e3.js +0 -76
- package/src/files/json-layout.ts +0 -474
- package/src/services/ai-turn-signal.ts +0 -70
package/src/ui/panel-resize.ts
CHANGED
|
@@ -43,8 +43,7 @@ import {
|
|
|
43
43
|
} from "../shell";
|
|
44
44
|
import type { DockId } from "../shell";
|
|
45
45
|
import { effect } from "../reactivity";
|
|
46
|
-
import {
|
|
47
|
-
import { splitModifiersOf } from "@jxsuite/ui/behaviors/split";
|
|
46
|
+
import { splitModifiersOf, trackOf } from "@jxsuite/ui/behaviors/split";
|
|
48
47
|
import type { SplitModifiers } from "@jxsuite/ui/behaviors/split";
|
|
49
48
|
|
|
50
49
|
/**
|
|
@@ -59,11 +58,11 @@ import type { SplitModifiers } from "@jxsuite/ui/behaviors/split";
|
|
|
59
58
|
*
|
|
60
59
|
* **There is no pointer path left in this module**, and it is worth recording why rather than
|
|
61
60
|
* quietly dropping it: a handle driven by pointer events alone is unreachable from a keyboard,
|
|
62
|
-
* which is an SC 2.1.1 failure however it is drawn. The pane split moved to `jx-split` first
|
|
63
|
-
* §5.5), the three docks followed, and the Edit column was last because its handle SNAPS —
|
|
64
|
-
* element had no way to tell a host which modifiers a step carried. It has now: every
|
|
65
|
-
* carries them, so a snap lives in {@link bindSplit} rather than in a pointer handler of
|
|
66
|
-
* module's own.
|
|
61
|
+
* which is an SC 2.1.1 failure however it is drawn. The pane split moved to `jx-split` first
|
|
62
|
+
* (`ui.md` §5.5), the three docks followed, and the Edit column was last because its handle SNAPS —
|
|
63
|
+
* and the element had no way to tell a host which modifiers a step carried. It has now: every
|
|
64
|
+
* `input` carries them, so a snap lives in {@link bindSplit} rather than in a pointer handler of
|
|
65
|
+
* this module's own.
|
|
67
66
|
*/
|
|
68
67
|
export interface ResizeTarget {
|
|
69
68
|
/** Which coordinate the drag reads. */
|
|
@@ -160,25 +159,6 @@ export interface SplitElement extends HTMLElement {
|
|
|
160
159
|
collapse: number;
|
|
161
160
|
}
|
|
162
161
|
|
|
163
|
-
/**
|
|
164
|
-
* The length of the box a handle divides, along its axis — the same box `jx-split` measures at
|
|
165
|
-
* pointerdown, read here so the share this adapter writes and the one the element drags against are
|
|
166
|
-
* two readings of one number.
|
|
167
|
-
*/
|
|
168
|
-
function trackOf(handle: HTMLElement, axis: "x" | "y"): number {
|
|
169
|
-
for (let node = handle.parentElement; node; node = node.parentElement) {
|
|
170
|
-
if (globalThis.getComputedStyle(node).display === "contents") {
|
|
171
|
-
continue;
|
|
172
|
-
}
|
|
173
|
-
const box = rectOf(node);
|
|
174
|
-
const length = axis === "x" ? box.width : box.height;
|
|
175
|
-
if (length > 0) {
|
|
176
|
-
return length;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
return 0;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
162
|
/**
|
|
183
163
|
* A target's pixel size as the leading side's share of the track, and back.
|
|
184
164
|
*
|
|
@@ -231,7 +211,7 @@ function sizeOf(target: ResizeTarget, share: number, track: number): number {
|
|
|
231
211
|
*/
|
|
232
212
|
export function bindSplit(handle: SplitElement, target: ResizeTarget): () => void {
|
|
233
213
|
const sync = (): void => {
|
|
234
|
-
const track = trackOf(handle, target.axis);
|
|
214
|
+
const track = trackOf(handle, target.axis === "x");
|
|
235
215
|
if (track <= 0) {
|
|
236
216
|
return;
|
|
237
217
|
}
|
|
@@ -243,7 +223,7 @@ export function bindSplit(handle: SplitElement, target: ResizeTarget): () => voi
|
|
|
243
223
|
handle.value = shareOf(target, target.read(), track);
|
|
244
224
|
};
|
|
245
225
|
const onInput = (event: Event): void => {
|
|
246
|
-
const track = trackOf(handle, target.axis);
|
|
226
|
+
const track = trackOf(handle, target.axis === "x");
|
|
247
227
|
if (track <= 0) {
|
|
248
228
|
return;
|
|
249
229
|
}
|
|
@@ -66,8 +66,8 @@ export interface OpenPopoverSurfaceOptions {
|
|
|
66
66
|
/** The platform closed it — clicked outside, Escape, or a second press on the invoker. */
|
|
67
67
|
onDismissed?: () => void;
|
|
68
68
|
/**
|
|
69
|
-
* A node the document made exists. The one seam an island reaches its host through
|
|
70
|
-
* straight to the runtime.
|
|
69
|
+
* A node the document made exists. The one seam an island reaches its host through
|
|
70
|
+
* (studio-ui-guidelines.md §9.4), passed straight to the runtime.
|
|
71
71
|
*/
|
|
72
72
|
onNodeCreated?: JxMountOptions["onNodeCreated"];
|
|
73
73
|
}
|
package/src/ui/progress-modal.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
2
|
/**
|
|
3
|
-
* The one surface in Studio that still BLOCKS while it works — and now the only one (
|
|
3
|
+
* The one surface in Studio that still BLOCKS while it works — and now the only one (§16.4).
|
|
4
4
|
*
|
|
5
5
|
* What changed. This modal used to be four things at once: the running state, the error view, the
|
|
6
6
|
* log and the operation's entire memory. It blocked the whole app, offered no way out, and took all
|
|
7
7
|
* four with it when it closed — so a failed `bun install` could be read exactly once, and a hung
|
|
8
|
-
* one could not be escaped at all. §
|
|
8
|
+
* one could not be escaped at all. §16.4 splits those apart:
|
|
9
9
|
*
|
|
10
10
|
* - The **record** moves to `panels/activity-panel.ts`, which keeps the entry, its steps and its log
|
|
11
11
|
* after the modal is gone;
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* - And the **exit** arrives twice: `Run in the background` hands the app back while the operation
|
|
16
16
|
* keeps going in Activity, and an operation that passed a `cancel` gets a real Cancel button.
|
|
17
17
|
*
|
|
18
|
-
* What did NOT change is which operations block. §
|
|
18
|
+
* What did NOT change is which operations block. §16.4 keeps blocking for dependency install and
|
|
19
19
|
* nothing else, and this module's four call sites are exactly that — `packages/ensure-deps.ts`,
|
|
20
20
|
* `packages/pull-package-sync.ts`, `packages/jxsuite-update.ts` and
|
|
21
21
|
* `settings/dependencies-editor.ts`. Every other long operation calls `beginActivity` directly and
|
package/src/ui/regions.ts
CHANGED
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
* restoration after a toast or a Problems jump, and the screenshot pipeline, which today addresses
|
|
10
10
|
* the shell through sixteen CSS selectors, seven of which name nodes the shell redesign deletes.
|
|
11
11
|
*
|
|
12
|
-
* **The grammar** (
|
|
12
|
+
* **The grammar** (scripts/screenshots/README.md, "The region grammar") is
|
|
13
|
+
* `<surface>[.<instance>][/<part>]`:
|
|
13
14
|
*
|
|
14
15
|
* ```text
|
|
15
16
|
* navigator the Navigator dock
|
|
@@ -38,7 +39,10 @@ import type { FocusRegion } from "../shell";
|
|
|
38
39
|
/** The attribute every region carries. One attribute, one grammar, one resolver. */
|
|
39
40
|
export const REGION_ATTR = "data-jx-region";
|
|
40
41
|
|
|
41
|
-
/**
|
|
42
|
+
/**
|
|
43
|
+
* The eight surfaces the region grammar declares (`scripts/screenshots/README.md`). A region id
|
|
44
|
+
* always begins with one of these.
|
|
45
|
+
*/
|
|
42
46
|
export const REGION_SURFACES = [
|
|
43
47
|
"rail",
|
|
44
48
|
"navigator",
|
|
@@ -377,12 +381,12 @@ export function inspectorStatementsRegion(eventKey: string): string {
|
|
|
377
381
|
* Region id for a Bottom dock tab, derived from the panel's own id.
|
|
378
382
|
*
|
|
379
383
|
* The third member of the derived-region family, and the one that shows the grammar was worth
|
|
380
|
-
* specifying before the surface existed: `dock.bottom`
|
|
381
|
-
* whose NAME contains the instance separator, which is why {@link DOTTED_SURFACES}
|
|
382
|
-
* resolved to nothing, because nothing hosted it. `panels/bottom-dock.ts` stamps this
|
|
383
|
-
* the same id `view.setBottomTab` accepts, so the dock
|
|
384
|
-
* authoring an id — and the host itself carries the bare `dock.bottom` only while it
|
|
385
|
-
* closed dock resolves to nothing rather than to an invisible box.
|
|
384
|
+
* specifying before the surface existed: `dock.bottom` parsed before the dock was built (it is the
|
|
385
|
+
* only surface whose NAME contains the instance separator, which is why {@link DOTTED_SURFACES}
|
|
386
|
+
* exists) and resolved to nothing, because nothing hosted it. `panels/bottom-dock.ts` stamps this
|
|
387
|
+
* once, from the same id `view.setBottomTab` accepts, so every tab the dock hosts is addressable
|
|
388
|
+
* without anyone authoring an id — and the host itself carries the bare `dock.bottom` only while it
|
|
389
|
+
* is open, so a closed dock resolves to nothing rather than to an invisible box.
|
|
386
390
|
*/
|
|
387
391
|
export function bottomPanelRegion(panelId: string): string {
|
|
388
392
|
return `dock.bottom/panel:${panelId}`;
|
|
@@ -419,7 +423,8 @@ export function overlayRegion(
|
|
|
419
423
|
}
|
|
420
424
|
|
|
421
425
|
/**
|
|
422
|
-
* `regions` — the
|
|
426
|
+
* `regions` — the resolver behind the region grammar (`scripts/screenshots/README.md`), gathered so
|
|
427
|
+
* a consumer imports one thing.
|
|
423
428
|
*
|
|
424
429
|
* `probe.regions` is a projection of this; nothing here knows the camera exists.
|
|
425
430
|
*/
|
package/src/ui/schema-form.ts
CHANGED
|
@@ -162,7 +162,7 @@ export interface RenderFormOptions {
|
|
|
162
162
|
ui?: Record<string, { control?: string; enum?: unknown }> | undefined;
|
|
163
163
|
rerender?: (() => void) | undefined;
|
|
164
164
|
/**
|
|
165
|
-
* Externally-produced diagnostics, keyed by property name — §
|
|
165
|
+
* Externally-produced diagnostics, keyed by property name — §16.1's inline tier, sourced.
|
|
166
166
|
*
|
|
167
167
|
* This is how a validator that runs over the WHOLE document reaches the one field it is about:
|
|
168
168
|
* `jx-validate`'s `project.json` errors, Monaco's markers for the same file open in the code
|
|
@@ -177,7 +177,7 @@ export interface RenderFormOptions {
|
|
|
177
177
|
/** How many times each field has been refused in a row; drives the row's repeat counter. */
|
|
178
178
|
errorCounts?: Record<string, number> | undefined;
|
|
179
179
|
/**
|
|
180
|
-
* Report required-but-empty fields inline. Off by default, and that default is §
|
|
180
|
+
* Report required-but-empty fields inline. Off by default, and that default is §16.5's rule
|
|
181
181
|
* literally applied: a form the user has not touched yet has not committed anything, so painting
|
|
182
182
|
* every required field red the moment it renders is telling them they got something wrong before
|
|
183
183
|
* they did anything. Required-ness is already shown — the row carries the required mark. A host
|
|
@@ -313,7 +313,7 @@ function asText(value: unknown): string {
|
|
|
313
313
|
return typeof value === "object" ? JSON.stringify(value, null, 2) : String(value);
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
-
// ─── Field validation (§
|
|
316
|
+
// ─── Field validation (§16.1, inline tier) ───────────────────────────────────
|
|
317
317
|
|
|
318
318
|
/**
|
|
319
319
|
* Why this value is not acceptable for this property schema, or `""` when it is.
|
|
@@ -670,7 +670,7 @@ function createController(): FormController {
|
|
|
670
670
|
return raw;
|
|
671
671
|
}
|
|
672
672
|
|
|
673
|
-
/** The rung picker: every source this position permits, one action away (§6.
|
|
673
|
+
/** The rung picker: every source this position permits, one action away (§6.6). */
|
|
674
674
|
function openSourceMenu(key: string, anchor: HTMLElement): void {
|
|
675
675
|
const plan = plans.get(key);
|
|
676
676
|
if (!plan?.ladder) {
|
|
@@ -985,11 +985,12 @@ function deriveField(prop: string, ps: JsonSchema, args: DeriveArgs): SchemaForm
|
|
|
985
985
|
}
|
|
986
986
|
|
|
987
987
|
/* A relationship to another collection (`$ref: "#/content/<type>"`) is the registered `reference`
|
|
988
|
-
control, wherever the form is drawn — §
|
|
989
|
-
`registerFormControl("reference", …)` in `ui/form-controls.ts`. It is
|
|
990
|
-
the choices are entry files on disk, so they are read asynchronously
|
|
991
|
-
schema `enum` is a closed set the document itself declares. When the
|
|
992
|
-
(a bare-Bun import of this engine), the field falls through to the
|
|
988
|
+
control, wherever the form is drawn — site-architecture.md §7.4's one entry picker is this
|
|
989
|
+
dispatch plus the single `registerFormControl("reference", …)` in `ui/form-controls.ts`. It is
|
|
990
|
+
deliberately NOT an enum: the choices are entry files on disk, so they are read asynchronously
|
|
991
|
+
and can be stale, and a schema `enum` is a closed set the document itself declares. When the
|
|
992
|
+
control is not registered (a bare-Bun import of this engine), the field falls through to the
|
|
993
|
+
plain text control below. */
|
|
993
994
|
if (referenceTarget(ps) !== null) {
|
|
994
995
|
const reference = controlRegistry.get("reference");
|
|
995
996
|
if (reference) {
|
package/src/ui/timing.ts
CHANGED
|
@@ -13,16 +13,17 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
* Text/style input debounce — the §4.4 standard. Long enough that a normal
|
|
17
|
-
* one commit per pause rather than one per keystroke, short enough that the
|
|
18
|
-
* live.
|
|
16
|
+
* Text/style input debounce — the studio-ui-guidelines.md §4.4 standard. Long enough that a normal
|
|
17
|
+
* typing cadence produces one commit per pause rather than one per keystroke, short enough that the
|
|
18
|
+
* canvas still feels live.
|
|
19
19
|
*/
|
|
20
20
|
export const INPUT_DEBOUNCE = 400;
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
* Code and expression textareas — the §4.4 standard. Longer than
|
|
24
|
-
* each commit re-parses source (or re-lints), and because half-typed
|
|
25
|
-
* committing eagerly just burns work on states the user is about to
|
|
23
|
+
* Code and expression textareas — the studio-ui-guidelines.md §4.4 standard. Longer than
|
|
24
|
+
* {@link INPUT_DEBOUNCE} because each commit re-parses source (or re-lints), and because half-typed
|
|
25
|
+
* code is usually invalid, so committing eagerly just burns work on states the user is about to
|
|
26
|
+
* leave.
|
|
26
27
|
*/
|
|
27
28
|
export const CODE_DEBOUNCE = 500;
|
|
28
29
|
|
|
@@ -38,7 +39,8 @@ export const LIVE_PREVIEW = 350;
|
|
|
38
39
|
* `STATUS_MESSAGE = 3000` used to live here: how long a transient message stayed in the status bar
|
|
39
40
|
* before it erased itself. It had one reader, `statusMessage`, which is deleted — the bar carries
|
|
40
41
|
* ambient state now and outcomes go to `services/notify.ts`, whose `TOAST_LIFETIME_MS` is per
|
|
41
|
-
* SEVERITY (
|
|
42
|
+
* SEVERITY (4s, or 8s for a warning or an error: studio-ui-guidelines.md §13.2) rather than one
|
|
43
|
+
* number for a failure and a save alike.
|
|
42
44
|
*/
|
|
43
45
|
|
|
44
46
|
/**
|
package/src/ui/value-source.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Value Source — the one vocabulary for "how is this value produced", and the derivation that says
|
|
3
|
-
* which productions a given document position actually permits (
|
|
3
|
+
* which productions a given document position actually permits (§6.6).
|
|
4
4
|
*
|
|
5
5
|
* Six controls used to answer that question in six dialects: `abc / $ref / ${} / fx` on the dynamic
|
|
6
6
|
* slot, `inline / $expression / ref` on the Events tab, `lit / $ref / expr` on every expression
|
|
7
7
|
* operand, and `Static value / route param / Custom…` in the schema-driven forms. They are the same
|
|
8
|
-
* four rungs of the Rule of Least Power ladder (spec §2.2) wearing four costumes, and a user who
|
|
8
|
+
* four rungs of the Rule of Least Power ladder (spec.md §2.2) wearing four costumes, and a user who
|
|
9
9
|
* learned one learned none of the others. {@link VALUE_SOURCE_LABELS} is the single vocabulary;
|
|
10
10
|
* every surface that offers the choice spells it the same way.
|
|
11
11
|
*
|
|
@@ -48,11 +48,11 @@ import { isFunctionDef, isRef, isTemplateString } from "@jxsuite/schema/guards";
|
|
|
48
48
|
/** A rung of the value ladder — one way a document position can produce its value. */
|
|
49
49
|
export type SlotMode = "literal" | "ref" | "template" | "expression" | "function";
|
|
50
50
|
|
|
51
|
-
/** Ladder order, least powerful first (spec §2.2). Every rung list is sorted by this. */
|
|
51
|
+
/** Ladder order, least powerful first (spec.md §2.2). Every rung list is sorted by this. */
|
|
52
52
|
export const SLOT_MODE_ORDER: SlotMode[] = ["literal", "ref", "template", "expression", "function"];
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
|
-
* The user-facing name of each rung — the whole point of §6.
|
|
55
|
+
* The user-facing name of each rung — the whole point of §6.6. `ref` keeps its ellipsis because
|
|
56
56
|
* choosing it opens a picker rather than committing a value.
|
|
57
57
|
*/
|
|
58
58
|
export const VALUE_SOURCE_LABELS: Record<SlotMode, string> = {
|
package/src/ui/virtual-window.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* project. The two trees pay a smaller version of the same bill — a 5 000-node page drew 5 000
|
|
10
10
|
* rows, each an `sp-icon` custom element — and they now pay it through this file.
|
|
11
11
|
*
|
|
12
|
-
* **It lives in `ui/`, not in `browse/`.**
|
|
12
|
+
* **It lives in `ui/`, not in `browse/`.** The shell redesign promised "one virtual-list primitive
|
|
13
13
|
* behind the Files tree and the Outline tree, reused by the Library grid", and what shipped sat
|
|
14
14
|
* inside the Library and was imported by the Library alone. A primitive two surfaces share cannot
|
|
15
15
|
* live inside one of them: the next surface that needs it either reaches across a feature boundary
|
|
@@ -300,6 +300,44 @@ export function nearestScroller(el: HTMLElement | null): HTMLElement | null {
|
|
|
300
300
|
return null;
|
|
301
301
|
}
|
|
302
302
|
|
|
303
|
+
/**
|
|
304
|
+
* The scroller that resolved for `list` last time, memoized while the tree still holds it.
|
|
305
|
+
*
|
|
306
|
+
* Every render pass asks {@link nearestScroller} the same question about the same list, and each
|
|
307
|
+
* ask is a walk whose reads (scrollHeight, clientHeight, computed overflow) land on a tree that is
|
|
308
|
+
* mid-paint — they force the flush the DevTools timeline charges to whatever function happened to
|
|
309
|
+
* read first. Profiling the program boot put 400 ms of style recalculation behind a handful of
|
|
310
|
+
* these walks (`trackOf` and this one together), and the answer did not change between any two
|
|
311
|
+
* repaints.
|
|
312
|
+
*
|
|
313
|
+
* Only a POSITIVE resolution is cached, and negative answers are never: a list that has not grown
|
|
314
|
+
* its rows yet has nothing to scroll (the first paint of every session), and a null answer memoized
|
|
315
|
+
* at that instant would never be revisited. Once a scroller is found it is kept while
|
|
316
|
+
* `cached.contains(list)` and both are connected — containment and connectivity are plain node
|
|
317
|
+
* walks that never read layout, so the cache invalidates itself on reparenting or teardown without
|
|
318
|
+
* paying for it.
|
|
319
|
+
*
|
|
320
|
+
* **The one semantic residue is deliberate**: the original walk additionally required the scroller
|
|
321
|
+
* to HAVE something to scroll right then (the "declares overflow but never scrolls" guard above). A
|
|
322
|
+
* memoized scroller that has since stopped scrolling stays answered — which is harmless for the
|
|
323
|
+
* window: `computeWindow` then yields the whole list (a list that fits has no window to cut), and
|
|
324
|
+
* the watch's own ResizeObserver drives a measure when the box moves so the empty answer of the
|
|
325
|
+
* next moment arrives without a walk.
|
|
326
|
+
*/
|
|
327
|
+
export function scrollerFor(list: HTMLElement): HTMLElement | null {
|
|
328
|
+
const cached = scrollerCache.get(list);
|
|
329
|
+
if (cached && cached.isConnected && list.isConnected && cached.contains(list)) {
|
|
330
|
+
return cached;
|
|
331
|
+
}
|
|
332
|
+
const found = nearestScroller(list);
|
|
333
|
+
if (found) {
|
|
334
|
+
scrollerCache.set(list, found);
|
|
335
|
+
} else {
|
|
336
|
+
scrollerCache.delete(list);
|
|
337
|
+
}
|
|
338
|
+
return found;
|
|
339
|
+
}
|
|
340
|
+
|
|
303
341
|
/**
|
|
304
342
|
* How far `list`'s first row has scrolled above the top of `scroller`'s viewport.
|
|
305
343
|
*
|
|
@@ -327,7 +365,7 @@ export function listWindow(
|
|
|
327
365
|
list: HTMLElement | null,
|
|
328
366
|
spec: { count: number; rowHeight: number; columns?: number; overscanRows?: number },
|
|
329
367
|
): WindowRange {
|
|
330
|
-
const scroller = list?.isConnected === true ?
|
|
368
|
+
const scroller = list?.isConnected === true ? scrollerFor(list) : null;
|
|
331
369
|
if (!scroller || !list) {
|
|
332
370
|
const count = Math.max(0, Math.trunc(spec.count));
|
|
333
371
|
return { end: count, padBottom: 0, padTop: 0, start: 0, totalRows: count };
|
|
@@ -377,7 +415,7 @@ export function scrollTopToReveal(spec: {
|
|
|
377
415
|
* would paint twice for one keystroke.
|
|
378
416
|
*/
|
|
379
417
|
export function revealListRow(list: HTMLElement | null, index: number, rowHeight: number): boolean {
|
|
380
|
-
const scroller = list?.isConnected === true ?
|
|
418
|
+
const scroller = list?.isConnected === true ? scrollerFor(list) : null;
|
|
381
419
|
if (!scroller || !list || index < 0 || !(rowHeight > 0)) {
|
|
382
420
|
return false;
|
|
383
421
|
}
|
|
@@ -437,9 +475,24 @@ export interface ListWindowWatch {
|
|
|
437
475
|
window: VirtualWindow;
|
|
438
476
|
}
|
|
439
477
|
|
|
478
|
+
const scrollerCache = new WeakMap<HTMLElement, HTMLElement>();
|
|
479
|
+
|
|
440
480
|
/**
|
|
441
481
|
* Bind — or keep — the scroll watch that repaints a windowed list.
|
|
442
482
|
*
|
|
483
|
+
* Runs synchronously, on purpose. Deferring the resolve-and-bind to the next animation frame was
|
|
484
|
+
* tried and measured (`scripts/perf/REPORT.md`, "deferring the first measure a frame"): it moved
|
|
485
|
+
* the boot trace's forced-flush cost rather than removing it, since the layout work still runs on
|
|
486
|
+
* the frame's own pass either way, and it cost eight test-semantics changes in this file's test
|
|
487
|
+
* suite for the same totals — so it was reverted. What actually removed the repeated flush is
|
|
488
|
+
* `scrollerFor`'s identity memoization (alongside `trackOf`'s, in `split.ts`): once a scroller is
|
|
489
|
+
* resolved for a list, later calls skip the ancestor walk entirely instead of re-reading
|
|
490
|
+
* `scrollHeight`/`clientHeight` on a dirty tree every render.
|
|
491
|
+
*
|
|
492
|
+
* A steady state where the SAME list and scroller are bound hands back `previous` unchanged — no
|
|
493
|
+
* work happens when nothing changed. Only a rebind (new list, changed scroller, first bind) creates
|
|
494
|
+
* a new watch.
|
|
495
|
+
*
|
|
443
496
|
* Called from the surface's `afterRender`, where the rows exist and the scroller can be resolved,
|
|
444
497
|
* and handed back its own previous handle so re-binding is the exception rather than the rule: the
|
|
445
498
|
* tree element survives every re-render (lit reuses it), so the steady state is "same list, same
|
|
@@ -450,14 +503,14 @@ export interface ListWindowWatch {
|
|
|
450
503
|
* the element whose box moves when the ROWS change height, so it is what the window observes to
|
|
451
504
|
* learn that `rowHeight()` now answers differently ({@link createVirtualWindow}).
|
|
452
505
|
*
|
|
453
|
-
*
|
|
506
|
+
* @returns The handle to keep, or null when nothing scrolls this list.
|
|
454
507
|
*/
|
|
455
508
|
export function watchListWindow(
|
|
456
509
|
previous: ListWindowWatch | null,
|
|
457
510
|
list: HTMLElement,
|
|
458
511
|
spec: { count: () => number; rowHeight: () => number; onChange: () => void },
|
|
459
512
|
): ListWindowWatch | null {
|
|
460
|
-
const scroller =
|
|
513
|
+
const scroller = scrollerFor(list);
|
|
461
514
|
if (previous && previous.list === list && previous.scroller === scroller) {
|
|
462
515
|
return previous;
|
|
463
516
|
}
|
package/src/utils/base64.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
2
|
/**
|
|
3
|
-
* Base64 encoding for binary
|
|
3
|
+
* Base64 encoding for binary payloads that cross an RPC boundary.
|
|
4
4
|
*
|
|
5
5
|
* `StudioPlatform.uploadFile` accepts `string | File | Blob | ArrayBuffer`, but the RPC platforms
|
|
6
6
|
* (electrobun, chromium) JSON-serialize their params — a `File`/`Blob` becomes `{}` on the wire.
|
|
7
7
|
* Those platforms encode here before the call; the HTTP platforms (dev server, cloud) post the
|
|
8
8
|
* binary body directly and must NOT use this.
|
|
9
|
+
*
|
|
10
|
+
* {@link base64ToBytes} is the same boundary in the other direction, for `readFileBytes`: the RPC
|
|
11
|
+
* backends answer a base64 string for the same reason they accept one, and the caller wants bytes.
|
|
9
12
|
*/
|
|
10
13
|
|
|
11
14
|
/** Bytes per `String.fromCodePoint` call — spreading a whole large file blows the call stack. */
|
|
@@ -31,3 +34,19 @@ export async function toBase64(data: string | File | Blob | ArrayBuffer): Promis
|
|
|
31
34
|
const buffer = data instanceof ArrayBuffer ? data : await data.arrayBuffer();
|
|
32
35
|
return bytesToBase64(new Uint8Array(buffer));
|
|
33
36
|
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Decode a base64 string to raw bytes — the inverse of {@link bytesToBase64}.
|
|
40
|
+
*
|
|
41
|
+
* The RPC platforms' `readFileBytes` answers base64 because their params and results are JSON, so
|
|
42
|
+
* this is where a JPEG becomes a JPEG again. `atob` yields one character per byte, and reading the
|
|
43
|
+
* code point back out is what keeps a byte above 0x7F from being re-encoded as UTF-8 — the exact
|
|
44
|
+
* corruption that makes `readFile` useless for an image.
|
|
45
|
+
*
|
|
46
|
+
* `Uint8Array.from` with a mapper rather than an index loop, because `atob`'s output is latin1: one
|
|
47
|
+
* code unit per byte, none of them a surrogate, so iterating characters and iterating bytes are the
|
|
48
|
+
* same walk and the index never has to be reasoned about.
|
|
49
|
+
*/
|
|
50
|
+
export function base64ToBytes(base64: string): Uint8Array {
|
|
51
|
+
return Uint8Array.from(atob(base64), (char) => char.codePointAt(0) ?? 0);
|
|
52
|
+
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { pureSchemeOf } from "@jxsuite/runtime";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* True when a feature query participates in the forced-scheme contract (spec §9.5) — a pure
|
|
8
|
+
* True when a feature query participates in the forced-scheme contract (spec.md §9.5) — a pure
|
|
9
9
|
* prefers-color-scheme query. These surface as the Auto/Light/Dark control, not generic toggles.
|
|
10
10
|
*
|
|
11
11
|
* @param {string} query
|
|
@@ -76,37 +76,6 @@ export function attrLabel(
|
|
|
76
76
|
return camelToLabel(attr);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
/**
|
|
80
|
-
* Abbreviate a CSS value for button-group display
|
|
81
|
-
*
|
|
82
|
-
* @param {string} val
|
|
83
|
-
* @returns {string}
|
|
84
|
-
*/
|
|
85
|
-
export function abbreviateValue(val: string) {
|
|
86
|
-
const map: Record<string, string> = {
|
|
87
|
-
baseline: "base",
|
|
88
|
-
column: "col",
|
|
89
|
-
"column-reverse": "col-r",
|
|
90
|
-
contents: "cnt",
|
|
91
|
-
"flex-end": "end",
|
|
92
|
-
"flex-start": "start",
|
|
93
|
-
"flow-root": "flow",
|
|
94
|
-
inline: "inl",
|
|
95
|
-
"inline-block": "i-blk",
|
|
96
|
-
"inline-flex": "i-flx",
|
|
97
|
-
"inline-grid": "i-grd",
|
|
98
|
-
normal: "norm",
|
|
99
|
-
nowrap: "no-wr",
|
|
100
|
-
"row-reverse": "row-r",
|
|
101
|
-
"space-around": "arnd",
|
|
102
|
-
"space-between": "betw",
|
|
103
|
-
"space-evenly": "even",
|
|
104
|
-
stretch: "str",
|
|
105
|
-
"wrap-reverse": "wr-rev",
|
|
106
|
-
};
|
|
107
|
-
return map[val] || val;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
79
|
/**
|
|
111
80
|
* True when a schema `format` names a MEDIA reference.
|
|
112
81
|
*
|
package/src/view.ts
CHANGED
|
@@ -23,9 +23,10 @@ import type { Tab } from "./tabs/tab";
|
|
|
23
23
|
* different modules, torn down by different events and written into by different continuations —
|
|
24
24
|
* and each of those differences used to justify its own spelling of the same two ideas ("ignore the
|
|
25
25
|
* change my own `setValue` is about to fire" and "cancel the work armed over this buffer"). The
|
|
26
|
-
* function editor got a canceller in
|
|
27
|
-
* timer survived three disposal sites and stayed able to replace a
|
|
28
|
-
* `services/monaco-buffer.ts` owns the rule; this is the storage it
|
|
26
|
+
* function editor got a canceller in the shell redesign's panes phase and the source view did not,
|
|
27
|
+
* which is exactly how a 600ms timer survived three disposal sites and stayed able to replace a
|
|
28
|
+
* page with an empty parse. `services/monaco-buffer.ts` owns the rule; this is the storage it
|
|
29
|
+
* needs.
|
|
29
30
|
*/
|
|
30
31
|
/**
|
|
31
32
|
* A comparison's Monaco diff editor.
|
|
@@ -171,10 +171,10 @@ export const PRESET_LABELS: Readonly<Record<DerivePreset, string>> = {
|
|
|
171
171
|
diff: "Diff vs HEAD",
|
|
172
172
|
layout: "Layout",
|
|
173
173
|
/* An UNFINISHED sentence, like `breakpoint`'s, because the row and the chip both finish it with
|
|
174
|
-
the locale's own autonym — "Same page in français". Jx has no message catalogue
|
|
175
|
-
translation is a different file in a different directory, so
|
|
176
|
-
rather than re-rendering this one, and the label says "the same
|
|
177
|
-
rather than about the text on screen. */
|
|
174
|
+
the locale's own autonym — "Same page in français". Jx has no message catalogue
|
|
175
|
+
(site-architecture.md §13.3): a translation is a different file in a different directory, so
|
|
176
|
+
this preset opens that file rather than re-rendering this one, and the label says "the same
|
|
177
|
+
page" about the document rather than about the text on screen. */
|
|
178
178
|
locale: "Same page in",
|
|
179
179
|
};
|
|
180
180
|
|
|
@@ -1029,9 +1029,9 @@ export function presetRefusal(
|
|
|
1029
1029
|
if (i18n === null || i18n.locales.length < 2) {
|
|
1030
1030
|
return "a project that declares more than one locale — see Project Settings › Locales";
|
|
1031
1031
|
}
|
|
1032
|
-
/* A PATH, because a translation is a FILE (§13.3) rather than a rendering:
|
|
1033
|
-
has nowhere for its sibling to be, and `translationPathFor` would answer
|
|
1034
|
-
frame later with a sentence about locales instead of about saving. */
|
|
1032
|
+
/* A PATH, because a translation is a FILE (site-architecture.md §13.3) rather than a rendering:
|
|
1033
|
+
an unsaved document has nowhere for its sibling to be, and `translationPathFor` would answer
|
|
1034
|
+
null for it one frame later with a sentence about locales instead of about saving. */
|
|
1035
1035
|
if (source.documentPath === null) {
|
|
1036
1036
|
return "a document that has been saved";
|
|
1037
1037
|
}
|
|
@@ -1082,10 +1082,11 @@ function derivationFor(
|
|
|
1082
1082
|
media: string | null,
|
|
1083
1083
|
locale: string | null = null,
|
|
1084
1084
|
): PaneDerivation {
|
|
1085
|
-
/* A COMPANION, because the French copy of this page is a different FILE —
|
|
1086
|
-
catalogue, so there is no rendering of this document that is the
|
|
1087
|
-
be a second copy of the same page under a chip naming another
|
|
1088
|
-
this module's own header warns about: a projection that changes
|
|
1085
|
+
/* A COMPANION, because the French copy of this page is a different FILE — Jx has no message
|
|
1086
|
+
catalogue (site-architecture.md §13.3), so there is no rendering of this document that is the
|
|
1087
|
+
French one. A lens here would be a second copy of the same page under a chip naming another
|
|
1088
|
+
language, which is the defect this module's own header warns about: a projection that changes
|
|
1089
|
+
only the chip. */
|
|
1089
1090
|
if (preset === "locale") {
|
|
1090
1091
|
return {
|
|
1091
1092
|
kind: "companion",
|
|
@@ -1213,8 +1214,8 @@ export function derivationCommands(deps: DerivationDeps): AnyCommand[] {
|
|
|
1213
1214
|
enablement: () => deriveRefusal(activePane().id) === null,
|
|
1214
1215
|
requires: DERIVE_REQUIRES,
|
|
1215
1216
|
undo: "none",
|
|
1216
|
-
/* No `aiTool`, by §12.4's first deletion rule: chrome — it arranges
|
|
1217
|
-
looking at. */
|
|
1217
|
+
/* No `aiTool`, by studio-ui-guidelines.md §12.4's first deletion rule: chrome — it arranges
|
|
1218
|
+
what the person is looking at. */
|
|
1218
1219
|
run: (_ctx, args) => {
|
|
1219
1220
|
const preset = enumArg("pane.derive", args, "preset", DERIVE_PRESETS);
|
|
1220
1221
|
/* `??`, not `||`. `optionalStringArg` answers `undefined` or a non-empty string — it is
|
package/src/workspace/session.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Session.ts — what a project looked like when you left it, and how it looks that way again.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* tab, per-tab editor kind / view / zoom / rendering context
|
|
6
|
-
* consequence plainly: **the session survives a relaunch
|
|
7
|
-
* held `layouts` and `activeLayout` and nothing else, its interface said
|
|
8
|
-
*
|
|
9
|
-
* nine open documents, a split, and the breakpoint you were checking were lost every
|
|
4
|
+
* The shell redesign promised that session state persists **per project root** — open tabs and
|
|
5
|
+
* order per pane, active tab, per-tab editor kind / view / zoom / rendering context — and stated
|
|
6
|
+
* the consequence plainly: **the session survives a relaunch** (§14.8). Neither shipped. The
|
|
7
|
+
* per-project record held `layouts` and `activeLayout` and nothing else, its interface said session
|
|
8
|
+
* state would "grow into this shape", and reopening a project landed on the home page with an empty
|
|
9
|
+
* strip — so nine open documents, a split, and the breakpoint you were checking were lost every
|
|
10
|
+
* time.
|
|
10
11
|
*
|
|
11
12
|
* **Paths, not tab ids.** A tab id is minted per open and means nothing across a reload; the
|
|
12
13
|
* document's path is the identity the workspace already dedupes on (`openFileInTab` scans
|