@jxsuite/studio 5.3.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-nwnwdm6p.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-4rzvmp0m.js → content-source-jt7rbcbc.js} +22 -22
- package/dist/chunks/{convert-to-repeater-jxsv62v7.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-2mrptyek.js → extension-sections-r73an5s6.js} +30 -29
- package/dist/chunks/{file-ops-knfqshrm.js → file-ops-3xan8mnj.js} +21 -21
- package/dist/chunks/{files-y6fr4he9.js → files-egsb0ry8.js} +28 -28
- package/dist/chunks/{format-host-1k4qrcqd.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-2rkrsjva.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-a7b87n2c.js → grid-view-qaqer9kr.js} +24 -24
- package/dist/chunks/{icons-yy10wk9r.js → icons-drxq9q10.js} +8 -2
- package/dist/chunks/{iframe-host-scpw01h8.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/layers-panel-83a16ytx.js +41 -0
- package/dist/chunks/{layers-jnvdbqva.js → layers-s6mc01ry.js} +3 -3
- package/dist/chunks/{media-picker-f66nav16.js → media-picker-nhn6rv4w.js} +11 -11
- package/dist/chunks/{menu-1dfhry4s.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-km6abc6q.js → monaco-setup-gsjdysze.js} +6 -6
- 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/{studio-ze46gzjh.js → studio-01269reb.js} +7 -7
- 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-d1n2bykn.js → studio-3nprwbd9.js} +117 -25
- package/dist/chunks/{studio-4c041r8y.js → studio-40z39dme.js} +3 -3
- package/dist/chunks/{studio-151w0xnh.js → studio-482eeazk.js} +20 -20
- package/dist/chunks/{studio-cgprcdxn.js → studio-4998spet.js} +10 -9
- package/dist/chunks/{studio-nq5yf5mp.js → studio-557bmn0x.js} +2 -2
- package/dist/chunks/{studio-rtskkm43.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-6gryj0sg.js → studio-9vsvz7w7.js} +6 -6
- package/dist/chunks/{studio-50wfwy44.js → studio-9wm0xzpf.js} +19 -19
- package/dist/chunks/{studio-0j7r7s9g.js → studio-ag3z6shb.js} +10 -4
- package/dist/chunks/studio-aj9drheq.js +177 -0
- package/dist/chunks/{studio-xajk70w0.js → studio-apv9x70c.js} +189 -130
- package/dist/chunks/{studio-c04nzbby.js → studio-b9q3znz8.js} +2 -2
- package/dist/chunks/{studio-nfx354t1.js → studio-bh47w0cy.js} +9 -10
- package/dist/chunks/{studio-gk2twyh4.js → studio-dgdm6vvt.js} +264 -52
- package/dist/chunks/{studio-gtfq1dkz.js → studio-dwdcr2e8.js} +4 -4
- package/dist/chunks/{studio-nqgawfks.js → studio-fbcyz234.js} +146 -139
- package/dist/chunks/{studio-27q131j3.js → studio-fqpkpq1t.js} +7 -4
- package/dist/chunks/{studio-c0qgc3tn.js → studio-fy320dfc.js} +62 -68
- package/dist/chunks/{studio-zjjde71a.js → studio-gjj4bbfx.js} +2 -2
- package/dist/chunks/{studio-g33v4fe9.js → studio-jfhxy8h3.js} +7 -7
- package/dist/chunks/{studio-ab87phj1.js → studio-kwewmhhq.js} +4 -4
- package/dist/chunks/{studio-7rrb1esn.js → studio-m58xn8at.js} +25 -24
- package/dist/chunks/{studio-fzjx96t2.js → studio-mfkh1q8d.js} +17 -17
- package/dist/chunks/{studio-drg8qj9k.js → studio-mrh0a92f.js} +17 -17
- package/dist/chunks/{studio-jt27ta6x.js → studio-mt79tn56.js} +3 -3
- package/dist/chunks/{studio-b66rsh78.js → studio-ne593z1j.js} +38 -31
- package/dist/chunks/{studio-h4nvnjvz.js → studio-ptfcxkz5.js} +418 -232
- package/dist/chunks/{studio-dd1qqkry.js → studio-qxye31h7.js} +7 -7
- package/dist/chunks/{studio-ye9drbk8.js → studio-rav5bpmp.js} +73 -52
- package/dist/chunks/{studio-6kvgrkrp.js → studio-rwmmbrth.js} +6 -6
- package/dist/chunks/{studio-b7xacrwe.js → studio-sceg8ws0.js} +8 -8
- package/dist/chunks/{studio-msc1ee1m.js → studio-sjas5b3a.js} +19 -13
- package/dist/chunks/{studio-a65w20ex.js → studio-vd67b66d.js} +3 -3
- package/dist/chunks/{studio-7144epdr.js → studio-w475cbf9.js} +10 -10
- package/dist/chunks/{studio-4f3psrk1.js → studio-w7gpcvfj.js} +9 -9
- package/dist/chunks/{studio-nsgw7dbk.js → studio-xrbfdxgk.js} +7 -7
- package/dist/chunks/{studio-ke09tn9k.js → studio-y49b6mjv.js} +35 -35
- package/dist/chunks/{studio-j0w60gft.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-np10mayv.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 +18 -16
- package/dist/studio.css +956 -139
- package/dist/studio.js +1453 -830
- 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 +15 -14
- 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/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/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 +46 -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 +2 -2
- package/src/surfaces/formula-palette.ts +1 -1
- 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/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 +5 -5
- 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 +1 -1
- 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-1wnsqn5d.js +0 -42
- package/dist/chunks/layers-panel-73gfkcga.js +0 -41
- package/dist/chunks/publish-panel-z1zd2da1.js +0 -27
- package/dist/chunks/quick-search-zdv7h8ht.js +0 -47
- package/dist/chunks/right-panel-889vbnm5.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
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
} from "../format/format-host";
|
|
29
29
|
import { notify } from "../services/notify";
|
|
30
30
|
import { activeTab } from "../workspace/workspace";
|
|
31
|
-
import { serializeJson } from "
|
|
31
|
+
import { serializeJson } from "@jxsuite/schema/json-layout";
|
|
32
32
|
import { invalidateReferenceEntries } from "../ui/form-controls";
|
|
33
33
|
import { reloadDraftAwareGrids } from "../grid/sources/content-source";
|
|
34
34
|
import { setIncludeDrafts } from "./draft-state";
|
|
@@ -64,7 +64,7 @@ async function seedText(collection: EntryCollection): Promise<string> {
|
|
|
64
64
|
formatForPath(`untitled${collection.ext}`)?.name ??
|
|
65
65
|
defaultContentFormat()?.name;
|
|
66
66
|
if (collection.ext === ".json" || formatName === undefined) {
|
|
67
|
-
// The save serializer with no layout (
|
|
67
|
+
// The save serializer with no layout (`@jxsuite/schema/json-layout`): a seed has no source text, and
|
|
68
68
|
// This is what the formatter makes of one, newline included.
|
|
69
69
|
return serializeJson(seed, null);
|
|
70
70
|
}
|
|
@@ -190,9 +190,10 @@ export function contentCommands(): AnyCommand[] {
|
|
|
190
190
|
when: (ctx) => ctx.project.open,
|
|
191
191
|
enablement: () => creatableCollections().length > 0,
|
|
192
192
|
undo: "project",
|
|
193
|
-
/* No `aiTool`, by §12.4's second deletion rule: `createEntry` awaits
|
|
194
|
-
awaits the New File prompt for the name; a cancel resolves with
|
|
195
|
-
`name` argument that skips the prompt is the way back in, and
|
|
193
|
+
/* No `aiTool`, by studio-ui-guidelines.md §12.4's second deletion rule: `createEntry` awaits
|
|
194
|
+
`createFileIn`, which awaits the New File prompt for the name; a cancel resolves with
|
|
195
|
+
nothing thrown. An optional `name` argument that skips the prompt is the way back in, and
|
|
196
|
+
is a UX call (issue 273). */
|
|
196
197
|
run: async (_ctx, args) => {
|
|
197
198
|
const names = creatableCollections();
|
|
198
199
|
await createEntry(enumArg("content.newEntry", args, "collection", names));
|
|
@@ -210,8 +211,8 @@ export function contentCommands(): AnyCommand[] {
|
|
|
210
211
|
group: "1_file",
|
|
211
212
|
requires: "an open project",
|
|
212
213
|
when: (ctx) => ctx.project.open,
|
|
213
|
-
/* No `aiTool`, by §12.4's first deletion rule: this opens a surface;
|
|
214
|
-
`open_document`. */
|
|
214
|
+
/* No `aiTool`, by studio-ui-guidelines.md §12.4's first deletion rule: this opens a surface;
|
|
215
|
+
the model has `open_document`. */
|
|
215
216
|
run: async (_ctx, args) => {
|
|
216
217
|
await openEntryEditor(stringArg("content.openEntry", args, "path"));
|
|
217
218
|
},
|
|
@@ -233,12 +234,12 @@ export function contentCommands(): AnyCommand[] {
|
|
|
233
234
|
when: (ctx) => ctx.document.open,
|
|
234
235
|
enablement: () => activeEntryTab() !== null,
|
|
235
236
|
undo: "document",
|
|
236
|
-
/* No `aiTool`, by §12.4's fourth deletion rule: the draft flag is ONE
|
|
237
|
-
and the model already writes fields — `set_property` at the root path
|
|
238
|
-
(`mutateDocumentField` is the same `set-key` at `[]`), `write_file` for a
|
|
239
|
-
The state is reachable — `open_document` opens a collection file as
|
|
240
|
-
`content.openEntry` does — so the reason is redundancy, not reach. Six lines to
|
|
241
|
-
should a task want the flag by name rather than by key. */
|
|
237
|
+
/* No `aiTool`, by studio-ui-guidelines.md §12.4's fourth deletion rule: the draft flag is ONE
|
|
238
|
+
FIELD on the entry, and the model already writes fields — `set_property` at the root path
|
|
239
|
+
for a JSON entry (`mutateDocumentField` is the same `set-key` at `[]`), `write_file` for a
|
|
240
|
+
frontmatter one. The state is reachable — `open_document` opens a collection file as
|
|
241
|
+
readily as `content.openEntry` does — so the reason is redundancy, not reach. Six lines to
|
|
242
|
+
re-enter should a task want the flag by name rather than by key. */
|
|
242
243
|
run: (_ctx, args) => {
|
|
243
244
|
const tab = activeEntryTab();
|
|
244
245
|
if (!tab) {
|
|
@@ -259,7 +260,8 @@ export function contentCommands(): AnyCommand[] {
|
|
|
259
260
|
group: "2_view",
|
|
260
261
|
requires: "an open project",
|
|
261
262
|
when: (ctx) => ctx.project.open,
|
|
262
|
-
/* No `aiTool`, by §12.4's first deletion rule: a listing filter for a
|
|
263
|
+
/* No `aiTool`, by studio-ui-guidelines.md §12.4's first deletion rule: a listing filter for a
|
|
264
|
+
person. */
|
|
263
265
|
/*
|
|
264
266
|
* Set the flag, then repaint what reads it.
|
|
265
267
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
2
|
/**
|
|
3
|
-
* The **Entry editor**
|
|
3
|
+
* The **Entry editor** (site-architecture.md §7.4): a content entry's fields, as a form, in a pane.
|
|
4
4
|
*
|
|
5
5
|
* Until now a markdown entry could be edited two ways and neither was its schema: the canvas edited
|
|
6
6
|
* its BODY, and the Document Header card drew a field list from `panels/frontmatter-fields.ts`'s
|
|
@@ -179,7 +179,7 @@ function formContext(tab: Tab): SchemaFormContext {
|
|
|
179
179
|
* Required fields this entry does not have.
|
|
180
180
|
*
|
|
181
181
|
* Deliberately keyed on ABSENCE, not emptiness. A seeded entry's `title: ""` is present and the
|
|
182
|
-
* author has not done anything wrong yet, so §
|
|
182
|
+
* author has not done anything wrong yet, so §16.5 says not to paint it red; a required key that is
|
|
183
183
|
* missing from the file is a fact about the document, and saying so is the whole reason the form
|
|
184
184
|
* knows the schema.
|
|
185
185
|
*/
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
* editing. That is the point.
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
-
import { cloneValue } from "@jxsuite/
|
|
31
|
+
import { cloneValue } from "@jxsuite/schema/doc-ops";
|
|
32
32
|
import { notePreviewOverlayEdit } from "../preview/preview-overlay";
|
|
33
33
|
import { recordDocOp } from "../tabs/patch-ops";
|
|
34
34
|
import { mutateUpdateFrontmatter, transactDoc } from "../tabs/transact";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
2
|
// ─── Clipboard & Context Menu ─────────────────────────────────────────────────
|
|
3
3
|
/**
|
|
4
|
-
* The element context menu is a RENDERING of the command registry (
|
|
4
|
+
* The element context menu is a RENDERING of the command registry (studio-ui-guidelines.md §12).
|
|
5
5
|
*
|
|
6
6
|
* This file used to hold an 18-item literal of `{ label, action, danger }` records — a fourth
|
|
7
7
|
* hand-maintained copy of verbs that also exist in the toolbar, the block action bar and the
|
|
@@ -283,7 +283,7 @@ export function pasteStyles() {
|
|
|
283
283
|
return;
|
|
284
284
|
}
|
|
285
285
|
const style = jsonClone(workspace.styleClipboard);
|
|
286
|
-
// Pasting one style onto six cards is
|
|
286
|
+
// Pasting one style onto six cards is one decision and one undo step (§6.7): `transactDoc`
|
|
287
287
|
// Records everything its callback mutates as a single history entry.
|
|
288
288
|
transactDoc(tab, (t) => {
|
|
289
289
|
for (const sel of targets) {
|
|
@@ -754,8 +754,8 @@ let _registry: CommandRegistry | null = null;
|
|
|
754
754
|
*/
|
|
755
755
|
export function contextMenuRegistry(): CommandRegistry {
|
|
756
756
|
/*
|
|
757
|
-
* THE APP'S REGISTRY, when there is one —
|
|
758
|
-
* rendering only
|
|
757
|
+
* THE APP'S REGISTRY, when there is one — a menu is a rendering of the records (§13), so this
|
|
758
|
+
* file keeps positioning and popover rendering only.
|
|
759
759
|
*
|
|
760
760
|
* The private registry below existed because the menu's context had to describe the RIGHT-CLICKED
|
|
761
761
|
* node while the app's described the ambient selection. Those are the same node now:
|
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
* The naming question is `showPromptDialog` — one headline, one sentence, one field, one refusal —
|
|
7
7
|
* which is exactly the shape this used to hand-render as an `sp-dialog-wrapper` of its own, down to
|
|
8
8
|
* the Enter binding, the focus move and the select-all. That helper is already a document over the
|
|
9
|
-
* kit (`src/surfaces/dialog.json`, studio-ui-guidelines §8.7), so the conversion here is a
|
|
10
|
-
* rather than a second surface: a prompt authored beside the prompt would be a second
|
|
11
|
-
* question Studio has settled once, and the two would drift the first time one of them
|
|
9
|
+
* kit (`src/surfaces/dialog.json`, studio-ui-guidelines.md §8.7), so the conversion here is a
|
|
10
|
+
* DELETION rather than a second surface: a prompt authored beside the prompt would be a second
|
|
11
|
+
* answer to a question Studio has settled once, and the two would drift the first time one of them
|
|
12
|
+
* was fixed.
|
|
12
13
|
*
|
|
13
14
|
* What is left is the flow, which is all this module ever owned that mattered: what the default
|
|
14
15
|
* name is, what makes a name usable, whether the document actually took the reference, and what is
|
|
@@ -25,7 +26,7 @@ import { transact } from "../tabs/transact";
|
|
|
25
26
|
import { componentRegistry, computeRelativePath, loadComponentRegistry } from "../files/components";
|
|
26
27
|
import { getPlatform } from "../platform";
|
|
27
28
|
import { jsonClone } from "../utils/studio-utils";
|
|
28
|
-
import { serializeJson } from "
|
|
29
|
+
import { serializeJson } from "@jxsuite/schema/json-layout";
|
|
29
30
|
import { notify } from "../services/notify";
|
|
30
31
|
import { showPromptDialog } from "../ui/layers";
|
|
31
32
|
import { validateComponentSlots } from "../services/cem-export";
|
|
@@ -106,7 +107,7 @@ export async function convertToComponent() {
|
|
|
106
107
|
// Write component file and refresh registry
|
|
107
108
|
try {
|
|
108
109
|
const platform = getPlatform();
|
|
109
|
-
/* Through the save serializer (
|
|
110
|
+
/* Through the save serializer (`@jxsuite/schema/json-layout`) rather than `JSON.stringify`, so the new
|
|
110
111
|
file lands in the formatter's layout with its trailing newline and the first save from its
|
|
111
112
|
tab is a clean diff. No layout to carry: the subtree was lifted out of another document, and
|
|
112
113
|
its record there is keyed by that document's pointers. */
|
|
@@ -67,9 +67,9 @@ export interface InlineAction {
|
|
|
67
67
|
* REMOVED from the data, and the field stays only so an older `elements-meta.json` still parses.
|
|
68
68
|
*
|
|
69
69
|
* It held `"Cmd+B"` — a mac spelling, printed verbatim into every tooltip on every platform,
|
|
70
|
-
* which is the hardcoded-chord defect
|
|
71
|
-
*
|
|
72
|
-
*
|
|
70
|
+
* which is the hardcoded-chord defect §13.3 exists to kill. The chord now lives on the `format.*`
|
|
71
|
+
* record (`panels/block-action-bar.ts`) and is formatted by the keymap's one formatter. Nothing
|
|
72
|
+
* reads this.
|
|
73
73
|
*/
|
|
74
74
|
shortcut?: string;
|
|
75
75
|
}
|
package/src/editor/shortcuts.ts
CHANGED
|
@@ -218,11 +218,11 @@ function selectFirstChild(): void {
|
|
|
218
218
|
/**
|
|
219
219
|
* Walk out of the selection by one rung.
|
|
220
220
|
*
|
|
221
|
-
* This is the Escape ladder (
|
|
222
|
-
* is not on the registry yet, so "Escape returns to
|
|
223
|
-
* from. What ships is the rest of it — a nested
|
|
224
|
-
* clears — which replaces an Escape that always
|
|
225
|
-
* whole path to get out of one node.
|
|
221
|
+
* This is the Escape ladder (leave the block action bar, select the parent, clear), and it is one
|
|
222
|
+
* rung short of complete: the block action bar is not on the registry yet, so "Escape returns to
|
|
223
|
+
* the bar's selection" has nowhere to read focus from. What ships is the rest of it — a nested
|
|
224
|
+
* selection selects its parent, the document element clears — which replaces an Escape that always
|
|
225
|
+
* cleared regardless of depth and so threw away the whole path to get out of one node.
|
|
226
226
|
*/
|
|
227
227
|
function selectParent(): void {
|
|
228
228
|
const tab = activeTab.value;
|
|
@@ -255,7 +255,7 @@ function insertSiblingParagraph(): void {
|
|
|
255
255
|
}
|
|
256
256
|
|
|
257
257
|
/**
|
|
258
|
-
* Duplicate the whole selection in ONE transaction, so a batch is one undo step (§6.
|
|
258
|
+
* Duplicate the whole selection in ONE transaction, so a batch is one undo step (§6.7).
|
|
259
259
|
*
|
|
260
260
|
* With one path selected this is `mutateDuplicateNode` on that path and nothing else — the batch
|
|
261
261
|
* form calls the single form, it does not reimplement it.
|
|
@@ -354,12 +354,12 @@ function zoomBy(ctx: CommandContext, factor: number, redraw: () => void): void {
|
|
|
354
354
|
// ─── Shell verbs ──────────────────────────────────────────────────────────────
|
|
355
355
|
|
|
356
356
|
/**
|
|
357
|
-
* The Command Bar's dock toggles, mapped onto the two docks
|
|
357
|
+
* The Command Bar's dock toggles, mapped onto the two side docks.
|
|
358
358
|
*
|
|
359
|
-
* `"bottom"` is the
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
359
|
+
* `"bottom"` is absent: the Bottom dock (§16.3) is toggled by `shell.ts`'s own
|
|
360
|
+
* `view.toggleBottomDock` (⌘J), and no default record passes `"bottom"` to `toggleDock`. The
|
|
361
|
+
* `bottom` branch of {@link toggleShellDock}, which selects the Assistant (the Inspector's fourth
|
|
362
|
+
* tab), predates that dock.
|
|
363
363
|
*/
|
|
364
364
|
const DOCK_FOR_COMMAND: Readonly<Record<Exclude<CommandDockId, "bottom">, DockId>> = {
|
|
365
365
|
inspector: "right",
|
|
@@ -403,9 +403,9 @@ let zenRestore: Partial<Record<DockId, boolean>> | null = null;
|
|
|
403
403
|
/**
|
|
404
404
|
* Collapse every dock; the same chord puts them back exactly as they were.
|
|
405
405
|
*
|
|
406
|
-
*
|
|
407
|
-
*
|
|
408
|
-
*
|
|
406
|
+
* Being reversible by the same key is the whole requirement, and it is why the previous state is
|
|
407
|
+
* snapshotted rather than assumed: an author who had the assistant closed does not want leaving Zen
|
|
408
|
+
* to open it.
|
|
409
409
|
*/
|
|
410
410
|
function toggleZen(): void {
|
|
411
411
|
if (zenRestore) {
|
|
@@ -427,7 +427,7 @@ function toggleZen(): void {
|
|
|
427
427
|
// ─── Region focus (F6) ────────────────────────────────────────────────────────
|
|
428
428
|
|
|
429
429
|
/**
|
|
430
|
-
* The F6 ring, in reading order: rail → navigator → pane → inspector → dock → status
|
|
430
|
+
* The F6 ring, in reading order: rail → navigator → pane → inspector → dock → status.
|
|
431
431
|
*
|
|
432
432
|
* `shell.focusRegion` has enumerated these six values since the shell record landed and nothing
|
|
433
433
|
* could act on it, because there was no map from the enum to the DOM. `ui/regions.ts` is that map;
|
|
@@ -445,9 +445,9 @@ export const REGION_CYCLE: readonly FocusRegion[] = [
|
|
|
445
445
|
/**
|
|
446
446
|
* The next region in the ring that is actually on screen, or `null` when none is.
|
|
447
447
|
*
|
|
448
|
-
* Absent regions are SKIPPED rather than focused-and-lost:
|
|
449
|
-
* and a collapsed Navigator has no host, so a ring that did not skip would strand the caret
|
|
450
|
-
* second press. Pure, and injectable, so the walk is testable without a shell.
|
|
448
|
+
* Absent regions are SKIPPED rather than focused-and-lost: a closed Bottom dock has no region
|
|
449
|
+
* (§16.3) and a collapsed Navigator has no host, so a ring that did not skip would strand the caret
|
|
450
|
+
* every second press. Pure, and injectable, so the walk is testable without a shell.
|
|
451
451
|
*/
|
|
452
452
|
export function nextRegion(
|
|
453
453
|
current: FocusRegion,
|
|
@@ -518,7 +518,7 @@ function cycleRegion(direction: 1 | -1): void {
|
|
|
518
518
|
// ─── Panel and inspector focus (⌘1–8, ⌘⇧1–4) ─────────────────────────────────
|
|
519
519
|
|
|
520
520
|
/**
|
|
521
|
-
* Toggle-FOCUS, not toggle-visible
|
|
521
|
+
* Toggle-FOCUS, not toggle-visible.
|
|
522
522
|
*
|
|
523
523
|
* ⌘1 from the canvas reveals Files and puts the caret in it; ⌘1 again — with Files already focused
|
|
524
524
|
* — collapses the dock and hands the caret back to the pane. The distinction matters because the
|
|
@@ -992,6 +992,72 @@ const SELF_SCROLLING_MODES: ReadonlySet<string> = new Set([
|
|
|
992
992
|
"settings",
|
|
993
993
|
]);
|
|
994
994
|
|
|
995
|
+
/**
|
|
996
|
+
* Can a box between `target` and the stage still answer this wheel itself?
|
|
997
|
+
*
|
|
998
|
+
* Edit forwards every wheel to the page's scroller (see the branch below), which was the whole
|
|
999
|
+
* story while the stage cell held nothing but the page. It also holds the Document Header band now,
|
|
1000
|
+
* a capped scroll container standing beside the scroller — and a `preventDefault` from an ANCESTOR
|
|
1001
|
+
* listener cancels the native scroll of whatever the pointer is over, so a form taller than the cap
|
|
1002
|
+
* could not be wheeled at all while the page scrolled underneath it instead. So the stage takes the
|
|
1003
|
+
* wheel only when nothing inside it wants one: the walk stops at the stage cell, and it steps over
|
|
1004
|
+
* the page's scroller because that box is what the forwarding is FOR — a wheel forwarded out of the
|
|
1005
|
+
* cross-origin frame is dispatched on the cell itself and reaches no scrollable element on the way,
|
|
1006
|
+
* and letting the browser scroll the page natively would chain out of it into the shell.
|
|
1007
|
+
*
|
|
1008
|
+
* @param {WheelEvent} e
|
|
1009
|
+
* @param {HTMLElement} stage The cell the listener is on — the walk's upper bound, exclusive.
|
|
1010
|
+
* @param {HTMLElement | null} pageScroller The box the Edit branch scrolls itself.
|
|
1011
|
+
*/
|
|
1012
|
+
function wheelBelongsInside(
|
|
1013
|
+
e: WheelEvent,
|
|
1014
|
+
stage: HTMLElement,
|
|
1015
|
+
pageScroller: HTMLElement | null,
|
|
1016
|
+
): boolean {
|
|
1017
|
+
const { target } = e;
|
|
1018
|
+
let el: Element | null =
|
|
1019
|
+
target instanceof Element ? target : ((target as Node | null)?.parentElement ?? null);
|
|
1020
|
+
while (el && el !== stage) {
|
|
1021
|
+
if (el instanceof HTMLElement && el !== pageScroller && canScrollBy(el, e.deltaX, e.deltaY)) {
|
|
1022
|
+
return true;
|
|
1023
|
+
}
|
|
1024
|
+
el = el.parentElement;
|
|
1025
|
+
}
|
|
1026
|
+
return false;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
/**
|
|
1030
|
+
* Is `el` a scroll container with room left in the direction this wheel asks for?
|
|
1031
|
+
*
|
|
1032
|
+
* Both halves are load-bearing: a box already at the end of its range answers nothing, and left the
|
|
1033
|
+
* wheel it would chain the scroll out to its ancestors — which is the shell, and exactly what the
|
|
1034
|
+
* Edit branch's `preventDefault` is there to stop. The 1px slack is the subpixel one a fractional
|
|
1035
|
+
* layout leaves at the end of a range. Overflow is read the way `ui/virtual-window.ts`'s scroller
|
|
1036
|
+
* walk reads it, cheap test first: happy-dom performs no layout, so the sizes are 0 for every
|
|
1037
|
+
* element and no test pays for a `getComputedStyle` it could not answer anyway.
|
|
1038
|
+
*
|
|
1039
|
+
* @param {HTMLElement} el
|
|
1040
|
+
* @param {number} dx
|
|
1041
|
+
* @param {number} dy
|
|
1042
|
+
*/
|
|
1043
|
+
function canScrollBy(el: HTMLElement, dx: number, dy: number): boolean {
|
|
1044
|
+
const downRoom = dy > 0 && el.scrollTop < el.scrollHeight - el.clientHeight - 1;
|
|
1045
|
+
const upRoom = dy < 0 && el.scrollTop > 0;
|
|
1046
|
+
const acrossRoom =
|
|
1047
|
+
(dx > 0 && el.scrollLeft < el.scrollWidth - el.clientWidth - 1) ||
|
|
1048
|
+
(dx < 0 && el.scrollLeft > 0);
|
|
1049
|
+
if (!downRoom && !upRoom && !acrossRoom) {
|
|
1050
|
+
return false;
|
|
1051
|
+
}
|
|
1052
|
+
const style = getComputedStyle(el);
|
|
1053
|
+
const scrolls = (overflow: string) =>
|
|
1054
|
+
overflow === "auto" || overflow === "scroll" || overflow === "overlay";
|
|
1055
|
+
return (
|
|
1056
|
+
(downRoom || upRoom ? scrolls(style.overflowY) : false) ||
|
|
1057
|
+
(acrossRoom ? scrolls(style.overflowX) : false)
|
|
1058
|
+
);
|
|
1059
|
+
}
|
|
1060
|
+
|
|
995
1061
|
/** The stage-context reader, published by {@link initShortcuts} for {@link installStageGestures}. */
|
|
996
1062
|
let _stageContext: StageContext | null = null;
|
|
997
1063
|
|
|
@@ -1033,7 +1099,9 @@ export function installStageGestures(surface: CanvasSurface): () => void {
|
|
|
1033
1099
|
/* The stage's own scroller, by the `part` the stage document draws it with — the same
|
|
1034
1100
|
attribute every other consumer of the canvas's chrome now addresses it by. */
|
|
1035
1101
|
const sc = canvasWrap.querySelector<HTMLElement>('[part="edit-canvas"]');
|
|
1036
|
-
|
|
1102
|
+
/* …unless the pointer is over a box in this cell that scrolls itself — the Document Header
|
|
1103
|
+
band, which Edit docks beside the scroller. See {@link wheelBelongsInside}. */
|
|
1104
|
+
if (sc && !wheelBelongsInside(e, canvasWrap, sc)) {
|
|
1037
1105
|
e.preventDefault();
|
|
1038
1106
|
sc.scrollTop += e.deltaY;
|
|
1039
1107
|
sc.scrollLeft += e.deltaX;
|
package/src/editor/slash-menu.ts
CHANGED
|
@@ -7,16 +7,17 @@
|
|
|
7
7
|
* its markup, its ARIA and every value in its style — and this module is the decisions: what is on
|
|
8
8
|
* offer, what the filter matches, which row is active, and what a pick does.
|
|
9
9
|
*
|
|
10
|
-
* **Why this is not `surfaces/menu.json`.** Every other Studio menu is that surface, and
|
|
11
|
-
* a second list of actions is a defect — but a `jx-menu` owns
|
|
12
|
-
* moves the caret onto its first row. This panel exists to
|
|
13
|
-
* inside the canvas's `contenteditable` and usually inside
|
|
14
|
-
* typed after the `/` has to keep landing there. A panel
|
|
15
|
-
* interaction it exists to serve. So the panel is a listbox that
|
|
16
|
-
* takes focus, and the keys are taken where they actually land — a
|
|
17
|
-
* listener for this realm, and {@link handleSlashMenuKey} called straight
|
|
18
|
-
* other one. That listener is not a focus trap and cannot become one: it
|
|
19
|
-
* same driver the bridge uses, and everything else keeps going to the
|
|
10
|
+
* **Why this is not `surfaces/menu.json`.** Every other Studio menu is that surface, and
|
|
11
|
+
* studio-ui-guidelines.md §12.5 says a second list of actions is a defect — but a `jx-menu` owns
|
|
12
|
+
* DOM focus by contract: showing one moves the caret onto its first row. This panel exists to
|
|
13
|
+
* filter a caret that is somewhere else, inside the canvas's `contenteditable` and usually inside
|
|
14
|
+
* the canvas IFRAME, and every character typed after the `/` has to keep landing there. A panel
|
|
15
|
+
* that takes the keyboard ends the interaction it exists to serve. So the panel is a listbox that
|
|
16
|
+
* marks its active row and never takes focus, and the keys are taken where they actually land — a
|
|
17
|
+
* document-level capturing listener for this realm, and {@link handleSlashMenuKey} called straight
|
|
18
|
+
* across the bridge for the other one. That listener is not a focus trap and cannot become one: it
|
|
19
|
+
* forwards four keys to the same driver the bridge uses, and everything else keeps going to the
|
|
20
|
+
* caret.
|
|
20
21
|
*
|
|
21
22
|
* Light dismissal, the top layer and Escape-on-the-topmost-popover are the platform's, through the
|
|
22
23
|
* `jx-popover` the document is rooted in; the `mousedown` capture listener that used to hand-roll
|
package/src/files/elements.ts
CHANGED
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
* Elements.ts — what belongs in a document's (or a project's) `$elements`, decided once.
|
|
3
3
|
*
|
|
4
4
|
* `$elements` is the list of component modules a document may use. Three surfaces wrote it, each
|
|
5
|
-
* with its own idea of what "already imported" means
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* validation."
|
|
5
|
+
* with its own idea of what "already imported" means: the Packages panel's cherry-pick checkboxes,
|
|
6
|
+
* its "Add component…" picker, and the automatic push when a component is dropped on the canvas.
|
|
7
|
+
* §9.1.3 puts one `enableElement()` / `disableElement()` service behind all three, because the same
|
|
8
|
+
* array was written three ways with no shared UI and no shared validation.
|
|
10
9
|
*
|
|
11
10
|
* They really did disagree. The canvas drop matched a local component by `ref.endsWith(basename)`,
|
|
12
11
|
* so `./components/card.json` counted `./vendor/card.json` as already imported and the drop
|
package/src/files/file-ops.ts
CHANGED
|
@@ -39,7 +39,7 @@ import type { CollabParser } from "../collab/collab-session";
|
|
|
39
39
|
import { flushCanvasEdits } from "../canvas/iframe-host";
|
|
40
40
|
import { flushPreviewOverlay } from "../preview/preview-overlay";
|
|
41
41
|
import { serializeDocument } from "./serialize-document";
|
|
42
|
-
import { parseJsonDocument } from "
|
|
42
|
+
import { parseJsonDocument } from "@jxsuite/schema/json-layout";
|
|
43
43
|
import {
|
|
44
44
|
defaultContentFormat,
|
|
45
45
|
formatByName,
|
package/src/files/files.ts
CHANGED
|
@@ -77,8 +77,8 @@ import { activeRegistry } from "../commands/active-registry";
|
|
|
77
77
|
import { runActiveReported, runReported } from "../commands/run-reported";
|
|
78
78
|
import { collectionOfPath } from "../content/entry-model";
|
|
79
79
|
import { confirmFileDelete, parseSourceForPath, renamePromptMessage } from "./file-ops";
|
|
80
|
-
import { parseJsonDocument } from "
|
|
81
|
-
import type { JsonLayout } from "
|
|
80
|
+
import { parseJsonDocument } from "@jxsuite/schema/json-layout";
|
|
81
|
+
import type { JsonLayout } from "@jxsuite/schema/json-layout";
|
|
82
82
|
import { invalidateUsages } from "../services/references";
|
|
83
83
|
import {
|
|
84
84
|
documentExtensions,
|
|
@@ -379,10 +379,10 @@ export async function openHomePage() {
|
|
|
379
379
|
/**
|
|
380
380
|
* Reopen the documents this project was last left with, or its home page if there are none.
|
|
381
381
|
*
|
|
382
|
-
*
|
|
383
|
-
*
|
|
384
|
-
*
|
|
385
|
-
*
|
|
382
|
+
* §14.8: **the session survives a relaunch.** Every one of the three ways into a project — the
|
|
383
|
+
* `?project=` bootstrap, the PAL picker and a recent-project open — ended at `openHomePage()`, so
|
|
384
|
+
* nine open documents, a split and the mode you were in were lost each time. The per-project
|
|
385
|
+
* record's own interface said "session state grows into this shape".
|
|
386
386
|
*
|
|
387
387
|
* ONE function for all three, because the three used to be three calls to `openHomePage` and this
|
|
388
388
|
* is exactly the kind of behaviour that lands on two of them.
|
|
@@ -538,10 +538,10 @@ let _fileList: HTMLElement | null = null;
|
|
|
538
538
|
/**
|
|
539
539
|
* Every DRAWN row's element, by path.
|
|
540
540
|
*
|
|
541
|
-
* Held rather than queried, which is the §9.4 rule and, for a windowed
|
|
542
|
-
* answer: the nodes are re-used for different files as the window slides, so
|
|
543
|
-
* later resolves to whichever file is standing there now. Entries whose
|
|
544
|
-
* document are swept on the next projection.
|
|
541
|
+
* Held rather than queried, which is the studio-ui-guidelines.md §9.4 rule and, for a windowed
|
|
542
|
+
* list, the only correct answer: the nodes are re-used for different files as the window slides, so
|
|
543
|
+
* a selector run a frame later resolves to whichever file is standing there now. Entries whose
|
|
544
|
+
* element has left the document are swept on the next projection.
|
|
545
545
|
*/
|
|
546
546
|
const _fileRowEls = new Map<string, HTMLElement>();
|
|
547
547
|
/** The scroll watch that repaints the tree as its scroller moves. */
|
|
@@ -1668,9 +1668,9 @@ function fileMenuRows(entry: { name: string; path: string; type: string }): Menu
|
|
|
1668
1668
|
*
|
|
1669
1669
|
* The KIT menu, not a popover of this module's own: `openMenu()` owns the panel, the roving focus,
|
|
1670
1670
|
* the typeahead, the light dismissal and Escape, and it is the answer this shell already settled on
|
|
1671
|
-
* (§8.4). What went with the `sp-popover` it replaces is the hand-written
|
|
1672
|
-
* measured the panel a frame after it opened and moved it back inside the
|
|
1673
|
-
* kit does that for every menu instead of this one doing it for itself.
|
|
1671
|
+
* (studio-ui-guidelines.md §8.4). What went with the `sp-popover` it replaces is the hand-written
|
|
1672
|
+
* clamp — a `ref` that measured the panel a frame after it opened and moved it back inside the
|
|
1673
|
+
* viewport — because the kit does that for every menu instead of this one doing it for itself.
|
|
1674
1674
|
*/
|
|
1675
1675
|
function showFileContextMenu(path: string, x: number, y: number): void {
|
|
1676
1676
|
const row = fileRowAt(path);
|
|
@@ -2235,7 +2235,10 @@ async function deleteFile(
|
|
|
2235
2235
|
export interface OpenFileOpts {
|
|
2236
2236
|
/** Which pane. Defaults to the focused one. */
|
|
2237
2237
|
paneId?: string;
|
|
2238
|
-
/**
|
|
2238
|
+
/**
|
|
2239
|
+
* Open as a disposable preview tab — browsing rather than committing
|
|
2240
|
+
* (`docs/studio/interface/tabs.md#preview-and-pinned-documents`).
|
|
2241
|
+
*/
|
|
2239
2242
|
preview?: boolean;
|
|
2240
2243
|
/** False leaves the keyboard where it is. Defaults to true. */
|
|
2241
2244
|
focus?: boolean;
|
|
@@ -2489,7 +2492,7 @@ export async function reloadFileInTab(path: string) {
|
|
|
2489
2492
|
* Contribute the Files panel.
|
|
2490
2493
|
*
|
|
2491
2494
|
* `level: "project"` because it WRITES project files — create, rename, delete, move. It reads the
|
|
2492
|
-
* focused document only to highlight a row, and
|
|
2495
|
+
* focused document only to highlight a row, and §13.2 files a surface by what it writes.
|
|
2493
2496
|
*/
|
|
2494
2497
|
export function registerFilesPanel(): void {
|
|
2495
2498
|
registerPanel({
|
|
@@ -2520,8 +2523,9 @@ const FILE_ACTIONS: FilesPanelActions = {
|
|
|
2520
2523
|
},
|
|
2521
2524
|
openProject: () => {
|
|
2522
2525
|
/* The DECLARED command, run through the registry — never a second opener of this surface's own
|
|
2523
|
-
(§12.5). It is the one the ⌘O chord, the palette and the status
|
|
2524
|
-
run, and it is the only one that knows about the picker modal
|
|
2526
|
+
(studio-ui-guidelines.md §12.5). It is the one the ⌘O chord, the palette and the status
|
|
2527
|
+
bar's PROJECT field already run, and it is the only one that knows about the picker modal
|
|
2528
|
+
and the "new window" target. */
|
|
2525
2529
|
void runActiveReported("project.open", undefined, "Files");
|
|
2526
2530
|
},
|
|
2527
2531
|
refresh: () => {
|
|
@@ -27,8 +27,8 @@ import {
|
|
|
27
27
|
stringProperty,
|
|
28
28
|
} from "../commands/command-args";
|
|
29
29
|
import { convertTargetExtensions, convertTargets } from "./format-choices";
|
|
30
|
-
import { parseJsonDocument, serializeJson } from "
|
|
31
|
-
import type { JsonLayout } from "
|
|
30
|
+
import { parseJsonDocument, serializeJson } from "@jxsuite/schema/json-layout";
|
|
31
|
+
import type { JsonLayout } from "@jxsuite/schema/json-layout";
|
|
32
32
|
import type { AnyCommand, CommandRegistry } from "../commands/registry";
|
|
33
33
|
|
|
34
34
|
/** What a conversion will do, resolved in full before the reader is asked to confirm it. */
|
|
@@ -99,7 +99,7 @@ async function writeDocument(
|
|
|
99
99
|
): Promise<string> {
|
|
100
100
|
const merged = { ...frontmatter, ...document };
|
|
101
101
|
if (targetExt === ".json") {
|
|
102
|
-
/* The same serializer a save uses (
|
|
102
|
+
/* The same serializer a save uses (`@jxsuite/schema/json-layout`), with NO layout: the source was
|
|
103
103
|
markdown or CSV, so there is no JSON text whose line breaks could be kept. Every object
|
|
104
104
|
expands and every short array stays on one line — which is exactly what the repository's
|
|
105
105
|
formatter would make of `JSON.stringify` output, so the converted file needs no reformat and
|
|
@@ -497,8 +497,8 @@ export function fileFormatCommands(): AnyCommand[] {
|
|
|
497
497
|
// Nothing restores it: the file has moved and its references have been rewritten with it.
|
|
498
498
|
// The confirmation carrying the count is what stands in for an undo.
|
|
499
499
|
undo: "none",
|
|
500
|
-
/* No `aiTool`, by §12.4's second deletion rule: `run` awaits a
|
|
501
|
-
answers. */
|
|
500
|
+
/* No `aiTool`, by studio-ui-guidelines.md §12.4's second deletion rule: `run` awaits a
|
|
501
|
+
confirm dialog the person answers. */
|
|
502
502
|
run: async (_ctx, args: Record<string, unknown>) => {
|
|
503
503
|
const target = typeof args.format === "string" ? args.format : undefined;
|
|
504
504
|
await convertFile(
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The GitHub credential's state — whether one exists, where it lives, and how to forget it.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `github-auth.ts` because a launcher's PAL-init bundle needs exactly one thing from
|
|
5
|
+
* that module before Studio itself has loaded: {@link hydrateGithubToken}, so the accounts pane can
|
|
6
|
+
* say "signed in" on the first frame (`desktop/src/boot.ts`). `github-auth.ts` also pulls in
|
|
7
|
+
* `notify`, `../ui/layers` and the device-flow dialog surface for the actual sign-in UI — none of
|
|
8
|
+
* which a bundler drops just because only this module's exports are imported, so a launcher that
|
|
9
|
+
* imported the combined file got a second, independent copy of Lit's runtime alongside the one the
|
|
10
|
+
* studio bundle it shares a window with already loads (`packages/desktop/src/init.ts`, the
|
|
11
|
+
* "Multiple versions of Lit loaded" warning). This file has no UI dependency at all, so a launcher
|
|
12
|
+
* that imports only this gets none of that.
|
|
13
|
+
*
|
|
14
|
+
* `github-auth.ts` re-exports everything here, so every other caller in Studio is unaffected.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/// <reference lib="dom" />
|
|
18
|
+
|
|
19
|
+
const STORAGE_KEY = "jx_github_token";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The desktop launcher's RFC 8252 sign-in, when this build is running inside one.
|
|
23
|
+
*
|
|
24
|
+
* Launcher-only, like `updater` and `windowControls`, and reached the same way — a loopback
|
|
25
|
+
* redirect needs a loopback server, which a page in a browser does not have.
|
|
26
|
+
*/
|
|
27
|
+
export interface NativeGithubAuth {
|
|
28
|
+
signIn: (force?: boolean) => Promise<{ token: string }>;
|
|
29
|
+
signOut: () => Promise<{ ok: boolean }>;
|
|
30
|
+
status: () => Promise<{ stored: boolean }>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function nativeAuth(): NativeGithubAuth | null {
|
|
34
|
+
return (
|
|
35
|
+
(globalThis as unknown as { __jxPlatform?: { githubAuth?: NativeGithubAuth } }).__jxPlatform
|
|
36
|
+
?.githubAuth ?? null
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The token the desktop store handed us this session.
|
|
42
|
+
*
|
|
43
|
+
* On the desktop the token at rest is a `0600` file in the user's config directory, **not**
|
|
44
|
+
* `localStorage` — so it is not readable by script in the webview between sessions, and it does not
|
|
45
|
+
* survive in a place a stray extension or a copied profile can reach. Holding it in a module
|
|
46
|
+
* variable is what keeps {@link getGithubToken} synchronous for its callers.
|
|
47
|
+
*/
|
|
48
|
+
let nativeToken: string | null = null;
|
|
49
|
+
|
|
50
|
+
/** Whether the desktop store holds a token, as of the last time it was asked. */
|
|
51
|
+
let nativeStored = false;
|
|
52
|
+
|
|
53
|
+
/** Record the token a native sign-in just returned — {@link authenticateGithub}'s own setter. */
|
|
54
|
+
export function setNativeToken(token: string | null): void {
|
|
55
|
+
nativeToken = token;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Record that the desktop's credential store does (or does not) hold a token.
|
|
60
|
+
*
|
|
61
|
+
* The launcher calls this once at startup. It carries a **boolean, not the token**: the accounts
|
|
62
|
+
* pane only needs to know whether one exists, and handing the webview a credential it has not been
|
|
63
|
+
* asked to use is the exposure the 0600 store exists to remove. When a sign-in does happen the
|
|
64
|
+
* token arrives through {@link setNativeToken} and lives in memory for that session.
|
|
65
|
+
*
|
|
66
|
+
* @param {boolean} stored
|
|
67
|
+
*/
|
|
68
|
+
export function hydrateGithubToken(stored: boolean): void {
|
|
69
|
+
nativeStored = stored;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Whether a GitHub credential exists, wherever it lives.
|
|
74
|
+
*
|
|
75
|
+
* Separate from {@link getGithubToken} because the two questions genuinely differ on the desktop: a
|
|
76
|
+
* token can be stored on disk and not yet in this session's memory, and the accounts pane asks
|
|
77
|
+
* "signed in?" while rendering — synchronously — where an API caller asks for the credential itself
|
|
78
|
+
* and can await it.
|
|
79
|
+
*
|
|
80
|
+
* @returns {boolean}
|
|
81
|
+
*/
|
|
82
|
+
export function githubTokenStored(): boolean {
|
|
83
|
+
return nativeToken !== null || nativeStored || localStorage.getItem(STORAGE_KEY) !== null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Where the credential this build would use actually lives, for text that says so. */
|
|
87
|
+
export function githubTokenLocation(): "desktop" | "browser" {
|
|
88
|
+
return nativeAuth() ? "desktop" : "browser";
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function getGithubToken(): string | null {
|
|
92
|
+
return nativeToken ?? localStorage.getItem(STORAGE_KEY);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function clearGithubToken(): void {
|
|
96
|
+
nativeToken = null;
|
|
97
|
+
nativeStored = false;
|
|
98
|
+
localStorage.removeItem(STORAGE_KEY);
|
|
99
|
+
// Fire-and-forget: the accounts pane's revoke is synchronous, and a store that failed to forget
|
|
100
|
+
// The token is not something the user can act on from there.
|
|
101
|
+
void nativeAuth()
|
|
102
|
+
?.signOut()
|
|
103
|
+
.catch(() => {});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** The key {@link authenticateGithub}'s device flow writes the browser-stored token under. */
|
|
107
|
+
export { STORAGE_KEY };
|