@jxsuite/studio 6.1.0 → 6.1.2
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/dist/chunks/2020-f2gkpy8d.js +4 -0
- package/dist/chunks/{action-group-2mqby73c.js → action-group-4aan7g6g.js} +3 -3
- package/dist/chunks/adapter-4912g339.js +4 -0
- package/dist/chunks/cf-account-picker-wccaenh6.js +4 -0
- package/dist/chunks/cf-settings-br6105tr.js +4 -0
- package/dist/chunks/color-28ksk2qm.js +4 -0
- package/dist/chunks/color-area-0fj8a4ga.js +4 -0
- package/dist/chunks/color-field-xch8kx2g.js +4 -0
- package/dist/chunks/color-slider-jxd8v350.js +4 -0
- package/dist/chunks/combobox-p0efwjke.js +4 -0
- package/dist/chunks/components-db68vsn7.js +4 -0
- package/dist/chunks/content-source-1449qesq.js +4 -0
- package/dist/chunks/convert-to-repeater-5h457egj.js +4 -0
- package/dist/chunks/dialog-c4x05vyx.js +4 -0
- package/dist/chunks/editor-x9jn86a7.js +4 -0
- package/dist/chunks/entry-commands-may24cpt.js +4 -0
- package/dist/chunks/extension-sections-pvr14vxr.js +4 -0
- package/dist/chunks/file-ops-x9v54pcj.js +4 -0
- package/dist/chunks/files-j3knqf0s.js +4 -0
- package/dist/chunks/format-host-tyre2trb.js +4 -0
- package/dist/chunks/fs-events-64ma9htc.js +4 -0
- package/dist/chunks/git-panel-84ps5dex.js +4 -0
- package/dist/chunks/grid-view-d2wq9ezg.js +51 -0
- package/dist/chunks/icons-pnfz478q.js +4 -0
- package/dist/chunks/iframe-entry-fvbk89gm.js +5 -0
- package/dist/chunks/iframe-entry-jdcktez8.js +5 -0
- package/dist/chunks/iframe-entry-x0ygf2yr.js +5 -0
- package/dist/chunks/iframe-entry-zap785cw.js +5 -0
- package/dist/chunks/iframe-host-ck6vejt5.js +4 -0
- package/dist/chunks/index-b8xw3vy9.js +4 -0
- package/dist/chunks/{index-gybvv7a6.js → index-zpjmzqfk.js} +3 -3
- package/dist/chunks/{javascript-rnvdp3k4.js → javascript-m54mnwp6.js} +3 -3
- package/dist/chunks/jsonMode-w15cmrcm.js +13 -0
- package/dist/chunks/jx-validate-at3zn8wa.js +4 -0
- package/dist/chunks/layers-h4xp1pss.js +4 -0
- package/dist/chunks/layers-panel-m5hw1d7g.js +4 -0
- package/dist/chunks/listbox-e74qjyq6.js +4 -0
- package/dist/chunks/lit-html-8t8t3dnr.js +4 -0
- package/dist/chunks/media-picker-2cweexc5.js +4 -0
- package/dist/chunks/menu-n6yzswmy.js +4 -0
- package/dist/chunks/menu-ynw13y0s.js +4 -0
- package/dist/chunks/monaco-binding-7gx83x3r.js +4 -0
- package/dist/chunks/monaco-buffer-qzxn567r.js +4 -0
- package/dist/chunks/monaco-setup-gxf6656g.js +4 -0
- package/dist/chunks/notify-cj5zbrs2.js +4 -0
- package/dist/chunks/number-field-y62xq0ty.js +4 -0
- package/dist/chunks/parse-b7ddhr8m.js +4 -0
- package/dist/chunks/platform-3dfws9js.js +4 -0
- package/dist/chunks/popover-jt2gxmzs.js +4 -0
- package/dist/chunks/publish-panel-1gvxbj21.js +4 -0
- package/dist/chunks/quick-search-0dajrwqg.js +4 -0
- package/dist/chunks/references-49qgt404.js +4 -0
- package/dist/chunks/right-panel-jm1bwe53.js +4 -0
- package/dist/chunks/section-registry-6kwc4fky.js +4 -0
- package/dist/chunks/select-rzds841e.js +4 -0
- package/dist/chunks/split-n2gfpm5m.js +4 -0
- package/dist/chunks/{studio-5g0ag7c0.js → studio-0q988f9w.js} +3 -3
- package/dist/chunks/studio-0rt52vpq.js +5 -0
- package/dist/chunks/studio-18vgbhs5.js +5 -0
- package/dist/chunks/{studio-pxg4ap1e.js → studio-1fxkaaea.js} +4 -4
- package/dist/chunks/studio-24mccdrj.js +5 -0
- package/dist/chunks/studio-2eh507zk.js +9 -0
- package/dist/chunks/studio-2hcbccfv.js +5 -0
- package/dist/chunks/studio-2j1cb95x.js +5 -0
- package/dist/chunks/studio-2jbs3rxv.js +5 -0
- package/dist/chunks/{studio-qbj760tx.js → studio-485046te.js} +7 -7
- package/dist/chunks/studio-4h8k4dw9.js +5 -0
- package/dist/chunks/studio-5f6n18kx.js +5 -0
- package/dist/chunks/studio-5gthpky6.js +5 -0
- package/dist/chunks/studio-5ve6bbep.js +5 -0
- package/dist/chunks/studio-6ep3js6b.js +9 -0
- package/dist/chunks/studio-6wkmf3wz.js +9 -0
- package/dist/chunks/studio-841rf3cg.js +5 -0
- package/dist/chunks/studio-8gmwgheg.js +5 -0
- package/dist/chunks/studio-8qm0ep50.js +5 -0
- package/dist/chunks/{studio-anyrgzvb.js → studio-90pq9km1.js} +4 -4
- package/dist/chunks/studio-924p1tm1.js +6 -0
- package/dist/chunks/{studio-v2bvmbjj.js → studio-a3g98wjr.js} +4 -4
- package/dist/chunks/studio-a3shpz9y.js +5 -0
- package/dist/chunks/studio-amsbaaar.js +6 -0
- package/dist/chunks/studio-at5spjbc.js +7 -0
- package/dist/chunks/studio-b2xv945e.js +5 -0
- package/dist/chunks/studio-bn5nkafw.js +5 -0
- package/dist/chunks/studio-bw6q5xjf.js +9 -0
- package/dist/chunks/studio-c7q0t9x1.js +5 -0
- package/dist/chunks/studio-camnhc96.js +6 -0
- package/dist/chunks/studio-cffqvnzd.js +5 -0
- package/dist/chunks/studio-d81xfh1g.js +5 -0
- package/dist/chunks/studio-dgz8d0c1.js +5 -0
- package/dist/chunks/studio-efvfrsf8.js +5 -0
- package/dist/chunks/studio-er30bpcx.js +5 -0
- package/dist/chunks/studio-ezscgr64.js +5 -0
- package/dist/chunks/studio-ffrrncvz.js +5 -0
- package/dist/chunks/studio-fpphgn8y.js +10 -0
- package/dist/chunks/studio-j1kvhdjk.js +4 -0
- package/dist/chunks/{studio-txjjzrsm.js → studio-j430n16g.js} +5 -5
- package/dist/chunks/studio-jjkg84nj.js +5 -0
- package/dist/chunks/studio-m0q32ars.js +4 -0
- package/dist/chunks/studio-m6bdst11.js +5 -0
- package/dist/chunks/studio-nv2cptd4.js +64 -0
- package/dist/chunks/studio-nwfrc98n.js +5 -0
- package/dist/chunks/studio-p1wgvp7r.js +5 -0
- package/dist/chunks/studio-pag2wncm.js +5 -0
- package/dist/chunks/studio-qvanvzfd.js +5 -0
- package/dist/chunks/studio-qwa64kt7.js +5 -0
- package/dist/chunks/studio-rk1zc4x3.js +928 -0
- package/dist/chunks/studio-se2r3ptc.js +5 -0
- package/dist/chunks/studio-sg2a0dh0.js +5 -0
- package/dist/chunks/studio-tjzjhe68.js +5 -0
- package/dist/chunks/{studio-0x3jyb8r.js → studio-tq0rtfwj.js} +4 -4
- package/dist/chunks/{studio-cpxkgjrj.js → studio-v0jzqdjm.js} +4 -4
- package/dist/chunks/studio-v2w7q8r1.js +7 -0
- package/dist/chunks/studio-v5vjq1h0.js +4 -0
- package/dist/chunks/studio-v8aga3vp.js +14 -0
- package/dist/chunks/studio-vfcdrfmv.js +5 -0
- package/dist/chunks/studio-vmfkgdjf.js +5 -0
- package/dist/chunks/studio-wt1816jj.js +5 -0
- package/dist/chunks/studio-wz73q5kq.js +4 -0
- package/dist/chunks/studio-y04qtxvp.js +7 -0
- package/dist/chunks/studio-y21g8zzg.js +5 -0
- package/dist/chunks/studio-y64hrt8p.js +12 -0
- package/dist/chunks/studio-ynn90f58.js +16 -0
- package/dist/chunks/studio-yxz682sx.js +5 -0
- package/dist/chunks/studio-zp7snvkq.js +5 -0
- package/dist/chunks/studio-zq4z6tm6.js +5 -0
- package/dist/chunks/swatch-group-ewh24n1f.js +4 -0
- package/dist/chunks/tabs-f5cw3tgp.js +4 -0
- package/dist/chunks/textfield-wewc8rq2.js +4 -0
- package/dist/chunks/toast-c9fn075p.js +4 -0
- package/dist/chunks/toast-host-ke5z4ng7.js +4 -0
- package/dist/chunks/{toolbar-2nnzqhrj.js → toolbar-44cm5cta.js} +3 -3
- package/dist/chunks/tooltip-5v8ngwj2.js +4 -0
- package/dist/chunks/tree-mdq3v5cw.js +4 -0
- package/dist/chunks/tsMode-sf49ee9x.js +14 -0
- package/dist/chunks/workspace-jtfahpee.js +4 -0
- package/dist/chunks/ws-client-nze0k6mv.js +4 -0
- package/dist/iframe-entry.js +16 -16
- package/dist/manifest.json +63 -63
- package/dist/studio.js +98 -98
- package/dist/workers/ts.worker.js +3 -3
- package/package.json +11 -11
- package/src/about/about-modal.ts +4 -3
- package/src/account/action-flow.ts +45 -38
- package/src/account-status.ts +7 -2
- package/src/browse/library-layouts.ts +8 -5
- package/src/browse/library-model.ts +18 -6
- package/src/browse/library-pane.ts +37 -21
- package/src/browse/library-preview.ts +14 -9
- package/src/browse/library-source.ts +1 -1
- package/src/canvas/asset-refs.ts +24 -9
- package/src/canvas/asset-resolve.ts +19 -23
- package/src/canvas/canvas-helpers.ts +7 -6
- package/src/canvas/canvas-live-render.ts +44 -53
- package/src/canvas/canvas-patcher.ts +30 -30
- package/src/canvas/canvas-perf.ts +11 -5
- package/src/canvas/canvas-render.ts +66 -42
- package/src/canvas/canvas-surface.ts +5 -3
- package/src/canvas/canvas-utils.ts +163 -64
- package/src/canvas/dialog-path.ts +9 -4
- package/src/canvas/dialog-state.ts +1 -2
- package/src/canvas/diff-marks.ts +9 -16
- package/src/canvas/diff-toolbar.ts +8 -7
- package/src/canvas/edit-width-drag.ts +4 -1
- package/src/canvas/edit-width.ts +1 -3
- package/src/canvas/iframe-channel.ts +27 -13
- package/src/canvas/iframe-drop.ts +13 -12
- package/src/canvas/iframe-editable-root.ts +29 -16
- package/src/canvas/iframe-entry.ts +80 -63
- package/src/canvas/iframe-eval.ts +73 -49
- package/src/canvas/iframe-host.ts +203 -118
- package/src/canvas/iframe-inline-edit.ts +69 -32
- package/src/canvas/iframe-insert.ts +5 -4
- package/src/canvas/iframe-interaction.ts +37 -26
- package/src/canvas/iframe-overlay.ts +1 -1
- package/src/canvas/iframe-patch.ts +18 -15
- package/src/canvas/iframe-position.ts +12 -6
- package/src/canvas/iframe-protocol.ts +15 -16
- package/src/canvas/iframe-render.ts +41 -36
- package/src/canvas/iframe-slash.ts +24 -11
- package/src/canvas/iframe-subtree.ts +6 -2
- package/src/canvas/path-mapping.ts +19 -12
- package/src/canvas/popover-path.ts +7 -3
- package/src/canvas/popover-state.ts +1 -2
- package/src/canvas/serialize-scope.ts +13 -5
- package/src/canvas/stage-scrollbar.ts +2 -1
- package/src/canvas/surface-registry.ts +21 -3
- package/src/collab/collab-commands.ts +7 -2
- package/src/collab/collab-session.ts +84 -45
- package/src/collab/collab-state.ts +4 -3
- package/src/collab/monaco-binding.ts +16 -13
- package/src/collab/monaco-cursors.ts +5 -2
- package/src/commands/budget.ts +3 -3
- package/src/commands/command-args.ts +103 -71
- package/src/commands/context.ts +22 -20
- package/src/commands/defaults.ts +4 -1
- package/src/commands/keymap.ts +47 -43
- package/src/commands/levels.ts +3 -3
- package/src/commands/live-context.ts +10 -8
- package/src/commands/reference.ts +2 -1
- package/src/commands/registry.ts +12 -10
- package/src/commands/run-reported.ts +15 -10
- package/src/component-props.ts +46 -30
- package/src/content/collection-match.ts +5 -4
- package/src/content/draft-state.ts +4 -3
- package/src/content/entry-commands.ts +3 -2
- package/src/content/entry-editor.ts +29 -17
- package/src/content/entry-fields.ts +12 -7
- package/src/content/entry-model.ts +21 -12
- package/src/editor/canvas-context-menu.ts +1 -2
- package/src/editor/canvas-slash-bridge.ts +3 -6
- package/src/editor/content-slice.ts +16 -14
- package/src/editor/context-menu.ts +35 -22
- package/src/editor/convert-targets.ts +30 -35
- package/src/editor/convert-to-component.ts +11 -5
- package/src/editor/convert-to-repeater.ts +34 -22
- package/src/editor/editable-tags.ts +17 -2
- package/src/editor/file-drop-action.ts +21 -22
- package/src/editor/inline-edit-apply.ts +35 -17
- package/src/editor/inline-edit.ts +66 -50
- package/src/editor/inline-format.ts +59 -56
- package/src/editor/inline-link.ts +40 -15
- package/src/editor/insert-zone-action.ts +1 -1
- package/src/editor/merge-tags.ts +58 -19
- package/src/editor/repeater-scope.ts +39 -28
- package/src/editor/shortcuts.ts +87 -47
- package/src/editor/slash-menu.ts +1 -6
- package/src/files/asset-versions.ts +4 -4
- package/src/files/components.ts +15 -10
- package/src/files/elements.ts +5 -6
- package/src/files/file-ops.ts +77 -36
- package/src/files/files.ts +90 -95
- package/src/files/media-meta.ts +2 -1
- package/src/files/media-paths.ts +6 -1
- package/src/files/serialize-document.ts +2 -2
- package/src/format/constraints.ts +1 -1
- package/src/format/convert-file.ts +27 -13
- package/src/format/format-choices.ts +2 -1
- package/src/format/format-host.ts +76 -50
- package/src/github/github-auth-status.ts +27 -3
- package/src/github/github-auth.ts +19 -9
- package/src/github/github-publish.ts +24 -20
- package/src/grid/cell-editors.ts +46 -31
- package/src/grid/cell-popovers.ts +5 -3
- package/src/grid/edit-buffer.ts +10 -9
- package/src/grid/grid-controller.ts +20 -22
- package/src/grid/grid-layout.ts +21 -5
- package/src/grid/grid-open.ts +3 -6
- package/src/grid/grid-panel.ts +11 -4
- package/src/grid/grid-source.ts +8 -8
- package/src/grid/grid-view.ts +14 -17
- package/src/grid/redirects-grid.ts +14 -5
- package/src/grid/redirects.ts +16 -14
- package/src/grid/schema-columns.ts +25 -19
- package/src/grid/sources/connector-source.ts +47 -20
- package/src/grid/sources/content-source.ts +25 -24
- package/src/grid/sources/csv-file-source.ts +2 -2
- package/src/grid/tabulator-tables.d.ts +55 -34
- package/src/hosting/stage.ts +7 -7
- package/src/i18n/i18n-commands.ts +1 -2
- package/src/media/media-pane.ts +4 -1
- package/src/new-project/add-repo-modal.ts +20 -19
- package/src/new-project/import-tab.ts +10 -14
- package/src/new-project/location-fields.ts +2 -1
- package/src/new-project/new-project-modal.ts +12 -9
- package/src/packages/jxsuite-update.ts +4 -3
- package/src/packages/pull-package-sync.ts +26 -25
- package/src/page-params.ts +97 -68
- package/src/panels/activity-panel.ts +17 -9
- package/src/panels/ai-chat/attached-context.ts +13 -7
- package/src/panels/ai-chat/chat-view.ts +80 -73
- package/src/panels/ai-chat/composer.ts +30 -33
- package/src/panels/ai-chat/sessions-view.ts +1 -2
- package/src/panels/ai-panel.ts +23 -20
- package/src/panels/block-action-bar.ts +46 -35
- package/src/panels/bottom-dock.ts +5 -3
- package/src/panels/canvas-dnd-bridge.ts +31 -24
- package/src/panels/data-explorer.ts +62 -25
- package/src/panels/data-grid.ts +14 -11
- package/src/panels/dnd.ts +108 -118
- package/src/panels/editors.ts +55 -22
- package/src/panels/elements-panel.ts +10 -3
- package/src/panels/events-panel.ts +84 -69
- package/src/panels/formula-workspace.ts +76 -51
- package/src/panels/frontmatter-fields.ts +24 -19
- package/src/panels/frontmatter-panel.ts +44 -34
- package/src/panels/git-diff-open.ts +4 -4
- package/src/panels/git-panel.ts +49 -61
- package/src/panels/head-panel.ts +131 -111
- package/src/panels/i18n-panel.ts +10 -3
- package/src/panels/imports-panel.ts +23 -47
- package/src/panels/jump-bar.ts +48 -29
- package/src/panels/layers-panel.ts +97 -74
- package/src/panels/left-panel.ts +3 -3
- package/src/panels/pane-context.ts +31 -22
- package/src/panels/pane-grid.ts +49 -20
- package/src/panels/panel-registry.ts +22 -37
- package/src/panels/properties-panel.ts +175 -121
- package/src/panels/quick-search.ts +53 -31
- package/src/panels/right-panel.ts +3 -3
- package/src/panels/seo-modal.ts +13 -17
- package/src/panels/settings-menu.ts +15 -15
- package/src/panels/signals-panel.ts +153 -131
- package/src/panels/statement-editor.ts +230 -140
- package/src/panels/style-panel.ts +254 -216
- package/src/panels/style-utils.ts +114 -51
- package/src/panels/stylebook-doc.ts +57 -54
- package/src/panels/stylebook-layers-panel.ts +9 -9
- package/src/panels/stylebook-panel.ts +13 -17
- package/src/panels/tab-drop.ts +27 -11
- package/src/panels/tab-strip.ts +36 -26
- package/src/platform-errors.ts +57 -43
- package/src/platform.ts +58 -30
- package/src/platforms/cloud.ts +345 -175
- package/src/platforms/default-platform.ts +10 -4
- package/src/platforms/devserver.ts +174 -127
- package/src/platforms/read-batcher.ts +16 -8
- package/src/project-list.ts +2 -1
- package/src/publish/deploy-checklist.ts +8 -2
- package/src/publish/pages-service.ts +28 -13
- package/src/publish/publish-commands.ts +5 -4
- package/src/publish/publish-panel.ts +10 -6
- package/src/recent-projects.ts +15 -8
- package/src/resize-edges.ts +26 -36
- package/src/services/a11y-report.ts +26 -19
- package/src/services/agent-seed.ts +23 -11
- package/src/services/ai-ask.ts +9 -12
- package/src/services/ai-command-tools.ts +68 -62
- package/src/services/ai-import-tools.ts +80 -67
- package/src/services/ai-models.ts +17 -13
- package/src/services/ai-project-tools.ts +68 -32
- package/src/services/ai-session-store.ts +19 -10
- package/src/services/ai-system-prompt.ts +46 -20
- package/src/services/ai-tools.ts +71 -27
- package/src/services/ai-write-report.ts +20 -12
- package/src/services/ai-writes.ts +4 -4
- package/src/services/automation.ts +58 -31
- package/src/services/cem-export.ts +149 -58
- package/src/services/clock.ts +6 -1
- package/src/services/code-services.ts +37 -31
- package/src/services/context-manager.ts +14 -10
- package/src/services/context-resolver.ts +20 -8
- package/src/services/data-service.ts +19 -15
- package/src/services/directory-picker.ts +18 -12
- package/src/services/document-assistant.ts +39 -19
- package/src/services/gated-registry.ts +10 -6
- package/src/services/harness/chat-reducer.ts +23 -1
- package/src/services/import-client.ts +91 -38
- package/src/services/import-seed.ts +8 -2
- package/src/services/jx-validate.ts +28 -31
- package/src/services/live-preview.ts +0 -0
- package/src/services/live-surfaces.ts +6 -3
- package/src/services/model-uri.ts +10 -2
- package/src/services/module-preloads.ts +12 -8
- package/src/services/monaco-buffer.ts +43 -24
- package/src/services/monaco-lazy.ts +7 -8
- package/src/services/monaco-setup.ts +23 -16
- package/src/services/notify.ts +44 -17
- package/src/services/popover-report.ts +25 -10
- package/src/services/preview-eval.ts +20 -8
- package/src/services/profile.ts +13 -6
- package/src/services/project-path.ts +13 -10
- package/src/services/references.ts +0 -0
- package/src/services/render-critic.ts +8 -7
- package/src/services/settings/kernel.ts +13 -4
- package/src/services/settings/write-queue.ts +9 -9
- package/src/services/token-lint.ts +12 -10
- package/src/services/tool-executor.ts +17 -5
- package/src/services/tool-outcomes.ts +44 -24
- package/src/services/trusted-types.ts +24 -7
- package/src/settings/contexts-section.ts +11 -8
- package/src/settings/contributed-section.ts +79 -60
- package/src/settings/css-vars-editor.ts +37 -16
- package/src/settings/defs-editor.ts +38 -35
- package/src/settings/extension-rows.ts +16 -8
- package/src/settings/extension-sections.ts +23 -13
- package/src/settings/extensions-section.ts +4 -1
- package/src/settings/general-settings.ts +11 -8
- package/src/settings/locales-section.ts +20 -12
- package/src/settings/preferences-dialog.ts +9 -6
- package/src/settings/preferences-keymap.ts +7 -5
- package/src/settings/preferences-sections.ts +11 -5
- package/src/settings/project-sections.ts +1 -1
- package/src/settings/schema-field-ui.ts +9 -0
- package/src/settings/settings-document.ts +5 -5
- package/src/shell/tree.ts +6 -5
- package/src/shell.ts +104 -81
- package/src/site-context.ts +37 -22
- package/src/state.ts +41 -49
- package/src/store.ts +54 -34
- package/src/studio.ts +39 -77
- package/src/style/live-preview.ts +1 -1
- package/src/style/project-styles.ts +6 -7
- package/src/style/token-ref.ts +5 -4
- package/src/surfaces/about.ts +18 -19
- package/src/surfaces/add-repo.ts +17 -19
- package/src/surfaces/ai-chat.ts +31 -36
- package/src/surfaces/ai-credentials-form.ts +6 -16
- package/src/surfaces/ai-managed-connect.ts +3 -4
- package/src/surfaces/ai-model-picker.ts +3 -5
- package/src/surfaces/block-action-bar.ts +22 -11
- package/src/surfaces/boot-failure.ts +4 -5
- package/src/surfaces/bottom-dock.ts +9 -18
- package/src/surfaces/canvas-stage.ts +12 -11
- package/src/surfaces/cf-account-picker.ts +17 -18
- package/src/surfaces/commandbar.ts +14 -9
- package/src/surfaces/convert-repeater.ts +17 -19
- package/src/surfaces/data-actions.ts +9 -7
- package/src/surfaces/dialog.ts +26 -28
- package/src/surfaces/diff-toolbar.ts +9 -7
- package/src/surfaces/doc-header.ts +10 -19
- package/src/surfaces/empty-state.ts +7 -10
- package/src/surfaces/entry-editor.ts +14 -11
- package/src/surfaces/expression-editor.ts +11 -25
- package/src/surfaces/files-panel.ts +27 -14
- package/src/surfaces/formula-palette.ts +4 -5
- package/src/surfaces/git-panel.ts +7 -15
- package/src/surfaces/github-auth.ts +16 -20
- package/src/surfaces/github-publish.ts +17 -22
- package/src/surfaces/grid-cell.ts +30 -31
- package/src/surfaces/grid-open.ts +10 -14
- package/src/surfaces/grid-panel.ts +13 -9
- package/src/surfaces/grid-replace.ts +13 -13
- package/src/surfaces/grid-views.ts +15 -18
- package/src/surfaces/inspector-dock.ts +13 -12
- package/src/surfaces/jump-bar.ts +5 -6
- package/src/surfaces/jxsuite-update.ts +16 -22
- package/src/surfaces/library-pane.ts +25 -20
- package/src/surfaces/logic-panel.ts +17 -30
- package/src/surfaces/logic-workspace.ts +13 -15
- package/src/surfaces/media-browser.ts +11 -10
- package/src/surfaces/media-field.ts +4 -5
- package/src/surfaces/media-pane.ts +8 -7
- package/src/surfaces/menu.ts +29 -23
- package/src/surfaces/navigator-dock.ts +11 -12
- package/src/surfaces/new-project.ts +27 -26
- package/src/surfaces/pane-context.ts +20 -25
- package/src/surfaces/pane-grid.ts +15 -10
- package/src/surfaces/panel-activity.ts +5 -6
- package/src/surfaces/panel-data.ts +3 -4
- package/src/surfaces/panel-deploy-checklist.ts +5 -6
- package/src/surfaces/panel-elements.ts +5 -7
- package/src/surfaces/panel-i18n.ts +5 -7
- package/src/surfaces/panel-imports.ts +6 -13
- package/src/surfaces/panel-outline.ts +25 -19
- package/src/surfaces/panel-page.ts +11 -18
- package/src/surfaces/panel-problems.ts +5 -7
- package/src/surfaces/panel-signals.ts +20 -34
- package/src/surfaces/panel-stylebook-layers.ts +5 -8
- package/src/surfaces/preferences.ts +21 -11
- package/src/surfaces/progress-modal.ts +15 -9
- package/src/surfaces/properties-panel.json +1 -1
- package/src/surfaces/properties-panel.ts +20 -42
- package/src/surfaces/publish.ts +18 -18
- package/src/surfaces/push-plan.ts +7 -8
- package/src/surfaces/rail.json +126 -73
- package/src/surfaces/rail.ts +38 -12
- package/src/surfaces/reference-field.ts +11 -15
- package/src/surfaces/schema-builder.ts +16 -22
- package/src/surfaces/schema-form.ts +15 -25
- package/src/surfaces/secret-field.ts +9 -6
- package/src/surfaces/seo.ts +21 -15
- package/src/surfaces/settings-contexts.ts +9 -7
- package/src/surfaces/settings-contributed.ts +14 -10
- package/src/surfaces/settings-css-vars.ts +5 -12
- package/src/surfaces/settings-defs.json +2 -2
- package/src/surfaces/settings-defs.ts +17 -21
- package/src/surfaces/settings-deploy.ts +8 -15
- package/src/surfaces/settings-extensions.ts +5 -6
- package/src/surfaces/settings-head.ts +33 -39
- package/src/surfaces/settings-locales.ts +8 -20
- package/src/surfaces/settings-overview.ts +5 -6
- package/src/surfaces/settings-packages.ts +8 -7
- package/src/surfaces/settings-pane.ts +9 -18
- package/src/surfaces/settings-rawjson.ts +5 -6
- package/src/surfaces/shell.ts +1 -2
- package/src/surfaces/slash-menu.ts +19 -9
- package/src/surfaces/statements.ts +13 -18
- package/src/surfaces/statusbar.ts +17 -14
- package/src/surfaces/style-panel.ts +18 -31
- package/src/surfaces/stylebook-chrome.ts +3 -5
- package/src/surfaces/tab-strip.ts +14 -13
- package/src/surfaces/target-line.ts +6 -7
- package/src/surfaces/welcome.ts +5 -7
- package/src/tabs/patch-ops.ts +4 -3
- package/src/tabs/project-config.ts +32 -21
- package/src/tabs/selection.ts +36 -8
- package/src/tabs/tab.ts +52 -41
- package/src/tabs/transact.ts +98 -53
- package/src/tabs/typing.ts +31 -0
- package/src/types.ts +32 -17
- package/src/ui/ai-credentials-form.ts +10 -13
- package/src/ui/ai-model-picker.ts +3 -3
- package/src/ui/cf-account-picker.ts +7 -9
- package/src/ui/color-selector.ts +9 -5
- package/src/ui/dynamic-slot.ts +7 -8
- package/src/ui/expression-editor.ts +112 -105
- package/src/ui/form-controls.ts +57 -48
- package/src/ui/formula-catalog.ts +239 -230
- package/src/ui/formula-chips.ts +33 -18
- package/src/ui/layers.ts +44 -31
- package/src/ui/media-picker.ts +18 -9
- package/src/ui/popover-surface.ts +20 -12
- package/src/ui/progress-modal.ts +13 -8
- package/src/ui/regions.ts +7 -6
- package/src/ui/schema-form.ts +113 -70
- package/src/ui/surface.ts +71 -8
- package/src/ui/timing.ts +9 -0
- package/src/ui/value-source.ts +44 -31
- package/src/ui/virtual-window.ts +3 -2
- package/src/utils/base64.ts +3 -1
- package/src/utils/edit-display.ts +103 -74
- package/src/utils/element-selectors.ts +3 -2
- package/src/utils/google-fonts.ts +15 -14
- package/src/utils/inherited-style.ts +18 -20
- package/src/utils/link-target.ts +1 -1
- package/src/utils/preview-format.ts +25 -3
- package/src/utils/strip-events.ts +49 -22
- package/src/utils/studio-utils.ts +29 -14
- package/src/view.ts +2 -3
- package/src/workspace/pane-derive.ts +10 -12
- package/src/workspace/session.ts +53 -43
- package/src/workspace/workspace.ts +47 -36
- package/dist/chunks/2020-nkxms0ay.js +0 -4
- package/dist/chunks/adapter-m948ab5f.js +0 -4
- package/dist/chunks/cf-account-picker-n8hr38v7.js +0 -4
- package/dist/chunks/cf-settings-356xdtne.js +0 -4
- package/dist/chunks/color-area-jqhna8zy.js +0 -4
- package/dist/chunks/color-field-embq5ctg.js +0 -4
- package/dist/chunks/color-fpezvnkt.js +0 -4
- package/dist/chunks/color-slider-1qmw7wqy.js +0 -4
- package/dist/chunks/combobox-773hdzyj.js +0 -4
- package/dist/chunks/components-yk3t844e.js +0 -4
- package/dist/chunks/content-source-bawmyc09.js +0 -4
- package/dist/chunks/convert-to-repeater-7wns8kf1.js +0 -4
- package/dist/chunks/dialog-mtm9fq5t.js +0 -4
- package/dist/chunks/editor-6sc8nacq.js +0 -4
- package/dist/chunks/entry-commands-8ay9fh81.js +0 -4
- package/dist/chunks/extension-sections-na7rj3nr.js +0 -4
- package/dist/chunks/file-ops-gye0qw56.js +0 -4
- package/dist/chunks/files-dmc2xvcq.js +0 -4
- package/dist/chunks/format-host-t76b53f8.js +0 -4
- package/dist/chunks/fs-events-cg4tpz06.js +0 -4
- package/dist/chunks/git-panel-yef7bshy.js +0 -4
- package/dist/chunks/grid-view-7tt4bxw1.js +0 -51
- package/dist/chunks/icons-qbh8akb1.js +0 -4
- package/dist/chunks/iframe-entry-f7mqjwpm.js +0 -5
- package/dist/chunks/iframe-entry-haw7jkvz.js +0 -5
- package/dist/chunks/iframe-entry-z6qrytv3.js +0 -5
- package/dist/chunks/iframe-host-tmz30gfp.js +0 -4
- package/dist/chunks/index-nag78a9h.js +0 -4
- package/dist/chunks/jsonMode-zhwsprqk.js +0 -13
- package/dist/chunks/jx-validate-3gbp5nkn.js +0 -4
- package/dist/chunks/layers-fvz99859.js +0 -4
- package/dist/chunks/layers-panel-gchmbf9p.js +0 -4
- package/dist/chunks/listbox-s8fkmnq8.js +0 -4
- package/dist/chunks/lit-html-9agdspkt.js +0 -4
- package/dist/chunks/media-picker-rhjvyy00.js +0 -4
- package/dist/chunks/menu-2e4y9j7b.js +0 -4
- package/dist/chunks/menu-37d07z9m.js +0 -4
- package/dist/chunks/monaco-binding-2jnhjjvr.js +0 -4
- package/dist/chunks/monaco-buffer-rp21359g.js +0 -4
- package/dist/chunks/monaco-setup-vhh7gayr.js +0 -4
- package/dist/chunks/notify-h3www560.js +0 -4
- package/dist/chunks/number-field-gw7sq8rn.js +0 -4
- package/dist/chunks/parse-897fvqah.js +0 -4
- package/dist/chunks/platform-hz34wcd7.js +0 -4
- package/dist/chunks/popover-8htra4er.js +0 -4
- package/dist/chunks/publish-panel-exsmjzyj.js +0 -4
- package/dist/chunks/quick-search-pgaqeh0m.js +0 -4
- package/dist/chunks/references-2cgdxnb8.js +0 -4
- package/dist/chunks/right-panel-jf856w5w.js +0 -4
- package/dist/chunks/section-registry-jnf8r5gy.js +0 -4
- package/dist/chunks/select-n3v7gwas.js +0 -4
- package/dist/chunks/split-pff8f3ze.js +0 -4
- package/dist/chunks/studio-0f55h9ye.js +0 -5
- package/dist/chunks/studio-0sqdhnew.js +0 -12
- package/dist/chunks/studio-19x1c75w.js +0 -5
- package/dist/chunks/studio-2sqcndak.js +0 -5
- package/dist/chunks/studio-3aey7dd3.js +0 -5
- package/dist/chunks/studio-3bpdkq2s.js +0 -5
- package/dist/chunks/studio-47y6fbpf.js +0 -5
- package/dist/chunks/studio-4m3826v2.js +0 -5
- package/dist/chunks/studio-4nx2dj1g.js +0 -4
- package/dist/chunks/studio-4xv5s47r.js +0 -9
- package/dist/chunks/studio-5g4t8v6w.js +0 -5
- package/dist/chunks/studio-5py436sf.js +0 -5
- package/dist/chunks/studio-77kt594t.js +0 -5
- package/dist/chunks/studio-8f87n763.js +0 -10
- package/dist/chunks/studio-8mb00b84.js +0 -5
- package/dist/chunks/studio-8p51gq2h.js +0 -6
- package/dist/chunks/studio-954ds834.js +0 -5
- package/dist/chunks/studio-9ft45c83.js +0 -9
- package/dist/chunks/studio-a2138x5k.js +0 -7
- package/dist/chunks/studio-a9yzstqj.js +0 -5
- package/dist/chunks/studio-acdksxx6.js +0 -5
- package/dist/chunks/studio-ar8jcf2y.js +0 -5
- package/dist/chunks/studio-bmn4mn9j.js +0 -7
- package/dist/chunks/studio-e7xxa0sj.js +0 -5
- package/dist/chunks/studio-ecaz25vk.js +0 -5
- package/dist/chunks/studio-ery42sqr.js +0 -4
- package/dist/chunks/studio-fzdywr6p.js +0 -9
- package/dist/chunks/studio-g5fmf0c1.js +0 -5
- package/dist/chunks/studio-g7nse7zb.js +0 -5
- package/dist/chunks/studio-geq1ea6k.js +0 -14
- package/dist/chunks/studio-ghkb32r8.js +0 -5
- package/dist/chunks/studio-ghrhy2y7.js +0 -5
- package/dist/chunks/studio-grawhey1.js +0 -5
- package/dist/chunks/studio-h0xgswew.js +0 -5
- package/dist/chunks/studio-h9c4p2tx.js +0 -5
- package/dist/chunks/studio-jyzj5cxs.js +0 -5
- package/dist/chunks/studio-mgx8yhnz.js +0 -64
- package/dist/chunks/studio-mpb04y1d.js +0 -6
- package/dist/chunks/studio-n17mty64.js +0 -5
- package/dist/chunks/studio-nwh2eqsk.js +0 -6
- package/dist/chunks/studio-q1h883bt.js +0 -16
- package/dist/chunks/studio-q4tv82h7.js +0 -9
- package/dist/chunks/studio-qpqa7vk3.js +0 -5
- package/dist/chunks/studio-qqz8e5gk.js +0 -5
- package/dist/chunks/studio-qvasen3f.js +0 -5
- package/dist/chunks/studio-rggdb3hm.js +0 -5
- package/dist/chunks/studio-sghy936h.js +0 -4
- package/dist/chunks/studio-skprc6ef.js +0 -5
- package/dist/chunks/studio-tt2nactf.js +0 -5
- package/dist/chunks/studio-tyasmc39.js +0 -5
- package/dist/chunks/studio-vk9ezads.js +0 -5
- package/dist/chunks/studio-vzacdfsc.js +0 -4
- package/dist/chunks/studio-w4c0xmrw.js +0 -5
- package/dist/chunks/studio-wfjqhhbk.js +0 -5
- package/dist/chunks/studio-wgh5kxpj.js +0 -5
- package/dist/chunks/studio-xasj0796.js +0 -5
- package/dist/chunks/studio-y78s8r2n.js +0 -5
- package/dist/chunks/studio-z8w183sh.js +0 -5
- package/dist/chunks/studio-zscd9ty4.js +0 -928
- package/dist/chunks/studio-zxp13sss.js +0 -7
- package/dist/chunks/studio-zygnmm01.js +0 -5
- package/dist/chunks/swatch-group-8qh9a3bm.js +0 -4
- package/dist/chunks/tabs-jwthg40w.js +0 -4
- package/dist/chunks/textfield-spy3hc77.js +0 -4
- package/dist/chunks/toast-4d35zd64.js +0 -4
- package/dist/chunks/toast-host-8sjmfed3.js +0 -4
- package/dist/chunks/tooltip-fd6g9xy3.js +0 -4
- package/dist/chunks/tree-h19v1jfz.js +0 -4
- package/dist/chunks/tsMode-gr0m4dzr.js +0 -14
- package/dist/chunks/workspace-m15qtcqp.js +0 -4
- package/dist/chunks/ws-client-nf61frr1.js +0 -4
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* template creation, centering, transform application, zoom indicator, and fit-to-screen.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import type { CanvasPanel
|
|
7
|
+
import type { CanvasPanel } from "../types";
|
|
8
8
|
|
|
9
9
|
import { renderOnly } from "../store";
|
|
10
10
|
import {
|
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
import type { CanvasStageHandle, CanvasStagePanelItem } from "../surfaces/canvas-stage";
|
|
40
40
|
import type { AnyCommand, CommandRegistry } from "../commands/registry";
|
|
41
41
|
import type { CommandArgValues } from "../commands/command-args";
|
|
42
|
+
import { isNumber, isString } from "@jxsuite/schema/guards";
|
|
42
43
|
import type { Tab } from "../tabs/tab";
|
|
43
44
|
|
|
44
45
|
/*
|
|
@@ -106,6 +107,22 @@ function setZoomOf(surface: CanvasSurface, zoom: number): void {
|
|
|
106
107
|
}
|
|
107
108
|
}
|
|
108
109
|
|
|
110
|
+
/** The {@link CanvasPanel} fields that hold the board's drawn nodes. */
|
|
111
|
+
type CanvasPanelNodeKey = "canvas" | "element" | "scrollContainer" | "viewport";
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* A panel record as it may be before {@link bindCanvasPanels} has run: its DOM fields can still be
|
|
115
|
+
* null, because {@link canvasPanelEntry} builds them that way. A bound {@link CanvasPanel} is
|
|
116
|
+
* assignable to it, so a reader that must tolerate an unbound board takes this type.
|
|
117
|
+
*/
|
|
118
|
+
export type UnboundCanvasPanel = Omit<CanvasPanel, CanvasPanelNodeKey> &
|
|
119
|
+
Record<CanvasPanelNodeKey, HTMLElement | null>;
|
|
120
|
+
|
|
121
|
+
/** Whether the stage has wired a board's canvas and viewport nodes into its record yet. */
|
|
122
|
+
export function isPanelBound(panel: UnboundCanvasPanel): boolean {
|
|
123
|
+
return Boolean(panel.canvas && panel.viewport);
|
|
124
|
+
}
|
|
125
|
+
|
|
109
126
|
/**
|
|
110
127
|
* One artboard: the record the geometry reads, and the item the stage document draws.
|
|
111
128
|
*
|
|
@@ -139,7 +156,7 @@ export function canvasPanelEntry(
|
|
|
139
156
|
fullWidth: boolean,
|
|
140
157
|
width: number | null = null,
|
|
141
158
|
): CanvasPanelEntry {
|
|
142
|
-
const
|
|
159
|
+
const unbound: UnboundCanvasPanel = {
|
|
143
160
|
_width: width || null,
|
|
144
161
|
canvas: null,
|
|
145
162
|
element: null,
|
|
@@ -148,7 +165,11 @@ export function canvasPanelEntry(
|
|
|
148
165
|
renderScope: null,
|
|
149
166
|
scrollContainer: null,
|
|
150
167
|
viewport: null,
|
|
151
|
-
}
|
|
168
|
+
};
|
|
169
|
+
/* SAFETY: the record is handed out unbound and filled in place by `bindCanvasPanels` once the
|
|
170
|
+
stage has drawn it; every reader that can run before that (`tabOfMountedPanel`, `applyEditZoom`,
|
|
171
|
+
`updateActivePanelHeaders`) reads it as an UnboundCanvasPanel and checks the nodes first. */
|
|
172
|
+
const panel = unbound as CanvasPanel;
|
|
152
173
|
/* The viewport takes the declared width, the canvas takes it too — but a FULL-WIDTH board's
|
|
153
174
|
viewport does not, because "full width" means "as wide as the box you are in". Carried as two
|
|
154
175
|
custom properties rather than as `width:` so `applyEditZoom`'s inline write on the canvas still
|
|
@@ -186,9 +207,13 @@ export function canvasPanelEntry(
|
|
|
186
207
|
*/
|
|
187
208
|
export function bindCanvasPanels(entries: CanvasPanelEntry[], stage: CanvasStageHandle): void {
|
|
188
209
|
for (const { item, panel } of entries) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
210
|
+
/* SAFETY: callers bind only after `drawStage` has settled, and the stage document draws the
|
|
211
|
+
`panel`, `panel-viewport` and `panel-canvas` parts for every item it was given, keyed by
|
|
212
|
+
`item.key`, so each lookup finds its node. */
|
|
213
|
+
const node = (part: string) => stage.panelNode(item.key, part) as HTMLElement;
|
|
214
|
+
panel.element = node("panel");
|
|
215
|
+
panel.viewport = node("panel-viewport");
|
|
216
|
+
panel.canvas = node("panel-canvas");
|
|
192
217
|
}
|
|
193
218
|
}
|
|
194
219
|
|
|
@@ -289,6 +314,36 @@ export function clampEditZoom(zoom: number): number {
|
|
|
289
314
|
return Math.min(EDIT_ZOOM_MAX, Math.max(EDIT_ZOOM_MIN, zoom));
|
|
290
315
|
}
|
|
291
316
|
|
|
317
|
+
/**
|
|
318
|
+
* Where an Edit-mode zoom is anchored: the scroller, the zoom the canvas is DRAWN at now, and the
|
|
319
|
+
* layout-px offset into the canvas of the content line at viewport-y `anchorY` (the cursor for a
|
|
320
|
+
* wheel, the scroller's middle for a button or a chord).
|
|
321
|
+
*
|
|
322
|
+
* The drawn zoom is read from the panel's applied layout width rather than from `ui.editZoom`,
|
|
323
|
+
* which a wheel burst has already moved on: the reactive write lands per event and the DOM once a
|
|
324
|
+
* frame.
|
|
325
|
+
*/
|
|
326
|
+
function editZoomAnchor(
|
|
327
|
+
surface: CanvasSurface,
|
|
328
|
+
layoutWidth: number | null,
|
|
329
|
+
anchorY: number | null,
|
|
330
|
+
): { layoutY: number; scroller: HTMLElement; zoom: number } | null {
|
|
331
|
+
const scroller = surface.wrap.querySelector<HTMLElement>('[part="edit-canvas"]');
|
|
332
|
+
const canvasEl = surface.panels[0]?.canvas;
|
|
333
|
+
if (!scroller || !canvasEl) {
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
const column = surface.wrap.querySelector<HTMLElement>('[part="edit-column"]');
|
|
337
|
+
const renderWidth = column ? rectOf(column).width : 0;
|
|
338
|
+
const zoom = layoutWidth && renderWidth > 0 ? renderWidth / layoutWidth : 1;
|
|
339
|
+
let y = anchorY;
|
|
340
|
+
if (y === null) {
|
|
341
|
+
const box = rectOf(scroller);
|
|
342
|
+
y = box.top + box.height / 2;
|
|
343
|
+
}
|
|
344
|
+
return { layoutY: Math.max(0, (y - rectOf(canvasEl).top) / zoom), scroller, zoom };
|
|
345
|
+
}
|
|
346
|
+
|
|
292
347
|
/**
|
|
293
348
|
* Apply the active tab's edit-mode content zoom to the single edit panel.
|
|
294
349
|
*
|
|
@@ -309,19 +364,23 @@ export function clampEditZoom(zoom: number): number {
|
|
|
309
364
|
* bare style writes only; the iframe's own ResizeObserver re-posts `contentHeight` after the
|
|
310
365
|
* reflow, which also finalizes the viewport height.
|
|
311
366
|
*/
|
|
312
|
-
export function applyEditZoom(
|
|
367
|
+
export function applyEditZoom(
|
|
368
|
+
surface: CanvasSurface = activeCanvasSurface(),
|
|
369
|
+
anchorY: number | null = null,
|
|
370
|
+
) {
|
|
313
371
|
// THIS pane's effective mode. It was the focused pane's, so a side pane in Edit was refused its
|
|
314
372
|
// Own content zoom whenever the primary happened to be in Design.
|
|
315
373
|
if (canvasModeOfPane(surface.paneId) !== "edit") {
|
|
316
374
|
return;
|
|
317
375
|
}
|
|
318
376
|
const [panel] = surface.panels;
|
|
319
|
-
if (!panel
|
|
377
|
+
if (!panel || !isPanelBound(panel)) {
|
|
320
378
|
return;
|
|
321
379
|
}
|
|
322
380
|
const canvasEl = panel.canvas;
|
|
323
381
|
const iframe = canvasEl.querySelector("iframe");
|
|
324
382
|
const editZoom = tabOfSurface(surface)?.session.ui.editZoom ?? 1;
|
|
383
|
+
const anchor = editZoomAnchor(surface, panel._width ?? null, anchorY);
|
|
325
384
|
if (editZoom === 1) {
|
|
326
385
|
// Exactly today's fluid behavior — no inline width, no transform, auto viewport height.
|
|
327
386
|
panel._width = null;
|
|
@@ -357,6 +416,11 @@ export function applyEditZoom(surface: CanvasSurface = activeCanvasSurface()) {
|
|
|
357
416
|
panel.viewport.style.height = `${iframe.offsetHeight * editZoom}px`;
|
|
358
417
|
}
|
|
359
418
|
}
|
|
419
|
+
if (anchor) {
|
|
420
|
+
// The content line that was under the anchor goes back under it: it sat `layoutY` layout px
|
|
421
|
+
// Into the canvas, which now draws it `layoutY * (new - old)` px further down.
|
|
422
|
+
anchor.scroller.scrollTop += anchor.layoutY * (editZoom - anchor.zoom);
|
|
423
|
+
}
|
|
360
424
|
// Re-anchor the fixed block-action-bar over the rescaled canvas.
|
|
361
425
|
renderOnly("overlays");
|
|
362
426
|
}
|
|
@@ -386,17 +450,25 @@ export function setEditZoom(zoom: number, surface: CanvasSurface = activeCanvasS
|
|
|
386
450
|
*/
|
|
387
451
|
const _editZoomRafs = new Map<string, number>();
|
|
388
452
|
|
|
453
|
+
/** The viewport-y each stage's pending frame zooms around — the latest wheel event's cursor. */
|
|
454
|
+
const _editZoomAnchors = new Map<string, number | null>();
|
|
455
|
+
|
|
389
456
|
/**
|
|
390
457
|
* Wheel-rate edit-zoom setter: the reactive `editZoom` write lands immediately (the zoom pod's
|
|
391
458
|
* label tracks it), but the DOM work — an iframe width resize, i.e. a real reflow — is coalesced to
|
|
392
459
|
* one `applyEditZoom()` per animation frame so a fast ctrl+scroll burst doesn't thrash layout.
|
|
393
460
|
*/
|
|
394
|
-
export function requestEditZoom(
|
|
461
|
+
export function requestEditZoom(
|
|
462
|
+
zoom: number,
|
|
463
|
+
surface: CanvasSurface = activeCanvasSurface(),
|
|
464
|
+
anchorY: number | null = null,
|
|
465
|
+
) {
|
|
395
466
|
const tab = tabOfSurface(surface);
|
|
396
467
|
if (!tab) {
|
|
397
468
|
return;
|
|
398
469
|
}
|
|
399
470
|
tab.session.ui.editZoom = clampEditZoom(zoom);
|
|
471
|
+
_editZoomAnchors.set(surface.paneId, anchorY);
|
|
400
472
|
if (_editZoomRafs.has(surface.paneId)) {
|
|
401
473
|
return;
|
|
402
474
|
}
|
|
@@ -404,7 +476,9 @@ export function requestEditZoom(zoom: number, surface: CanvasSurface = activeCan
|
|
|
404
476
|
surface.paneId,
|
|
405
477
|
requestAnimationFrame(() => {
|
|
406
478
|
_editZoomRafs.delete(surface.paneId);
|
|
407
|
-
|
|
479
|
+
const at = _editZoomAnchors.get(surface.paneId) ?? null;
|
|
480
|
+
_editZoomAnchors.delete(surface.paneId);
|
|
481
|
+
applyEditZoom(surface, at);
|
|
408
482
|
}),
|
|
409
483
|
);
|
|
410
484
|
}
|
|
@@ -522,12 +596,12 @@ export const FIT_WORDS: readonly string[] = ["width", "page", "none"];
|
|
|
522
596
|
* assistant sees. It stays as the typed read the body needs (`args.fit` is `unknown`) and as the
|
|
523
597
|
* refusal for a caller that reaches the body directly.
|
|
524
598
|
*/
|
|
525
|
-
function fitArg(commandId: string, args:
|
|
599
|
+
function fitArg(commandId: string, args: CommandArgValues, key: string): FitMode {
|
|
526
600
|
const value = args[key];
|
|
527
|
-
if (
|
|
528
|
-
return value
|
|
601
|
+
if (isFitWord(value)) {
|
|
602
|
+
return value;
|
|
529
603
|
}
|
|
530
|
-
if (
|
|
604
|
+
if (isNumber(value) && value >= PAN_ZOOM_MIN && value <= PAN_ZOOM_MAX) {
|
|
531
605
|
return value;
|
|
532
606
|
}
|
|
533
607
|
throw new RangeError(
|
|
@@ -536,6 +610,11 @@ function fitArg(commandId: string, args: Record<string, unknown>, key: string):
|
|
|
536
610
|
);
|
|
537
611
|
}
|
|
538
612
|
|
|
613
|
+
/** Whether a value is one of {@link FIT_WORDS}, the named (non-scale) fits. */
|
|
614
|
+
function isFitWord(value: unknown): value is Exclude<FitMode, number> {
|
|
615
|
+
return isString(value) && FIT_WORDS.includes(value);
|
|
616
|
+
}
|
|
617
|
+
|
|
539
618
|
/** Declared fits, keyed per tab + document. */
|
|
540
619
|
const _fits = new Map<string, FitMode>();
|
|
541
620
|
|
|
@@ -592,7 +671,7 @@ export function applyFit(fit?: FitMode, surface: CanvasSurface = activeCanvasSur
|
|
|
592
671
|
applyTransform(surface);
|
|
593
672
|
return;
|
|
594
673
|
}
|
|
595
|
-
if (
|
|
674
|
+
if (isNumber(chosen)) {
|
|
596
675
|
setZoomOf(surface, clampPanZoom(chosen));
|
|
597
676
|
applyTransform(surface);
|
|
598
677
|
return;
|
|
@@ -607,22 +686,15 @@ export function setFit(fit: FitMode, surface: CanvasSurface = activeCanvasSurfac
|
|
|
607
686
|
applyFit(fit, surface);
|
|
608
687
|
}
|
|
609
688
|
|
|
610
|
-
/**
|
|
611
|
-
* Record the active document's CURRENT pan-zoom as its declared fit.
|
|
612
|
-
*
|
|
613
|
-
* For the gesture paths that move the zoom themselves and then have to say so — ctrl+scroll writes
|
|
614
|
-
* `ui.zoom` directly, pinch will too. An author-chosen zoom is a numeric fit, so re-entering the
|
|
615
|
-
* mode restores it instead of re-framing over the top of it.
|
|
616
|
-
*/
|
|
617
|
-
export function markExplicitZoom(surface: CanvasSurface = activeCanvasSurface()): void {
|
|
618
|
-
declareFit(clampPanZoom(zoomOf(surface)), surface);
|
|
619
|
-
}
|
|
620
|
-
|
|
621
689
|
/**
|
|
622
690
|
* Set the active tab's pan-zoom on the author's behalf: clamped, declared as this document's fit,
|
|
623
691
|
* and applied. Every author-facing pan-zoom control routes through here.
|
|
624
692
|
*/
|
|
625
|
-
export function setUserZoom(
|
|
693
|
+
export function setUserZoom(
|
|
694
|
+
zoom: number,
|
|
695
|
+
surface: CanvasSurface = activeCanvasSurface(),
|
|
696
|
+
at: { clientX: number; clientY: number } | null = null,
|
|
697
|
+
): void {
|
|
626
698
|
const tab = tabOfSurface(surface);
|
|
627
699
|
if (!tab) {
|
|
628
700
|
return;
|
|
@@ -631,7 +703,23 @@ export function setUserZoom(zoom: number, surface: CanvasSurface = activeCanvasS
|
|
|
631
703
|
// Synchronously on assignment, and the zoom pod reads `getFit()` while it renders — so declaring
|
|
632
704
|
// Second means the control repaints one interaction behind the state it is reporting.
|
|
633
705
|
const next = clampPanZoom(zoom);
|
|
706
|
+
const ratio = next / zoomOf(surface);
|
|
634
707
|
declareFit(next, surface);
|
|
708
|
+
if (surface.panzoomWrap && ratio !== 1) {
|
|
709
|
+
/* Zoom AROUND a point: the cursor for a wheel, the stage's middle for a button or a chord.
|
|
710
|
+
Measured from the wrap's own drawn box, not the stage's: the wrap's layout origin is not the
|
|
711
|
+
stage's (it centres itself with `margin-block: auto`, and Stylebook puts a lead slot before
|
|
712
|
+
it), and the cursor-minus-stage arithmetic this replaced drifted by exactly that offset. A
|
|
713
|
+
content point `d` px into the drawn box is `d * ratio` px in after the zoom, so the pan
|
|
714
|
+
moves by the difference. */
|
|
715
|
+
const box = rectOf(surface.panzoomWrap);
|
|
716
|
+
const stage = rectOf(surface.wrap);
|
|
717
|
+
const x = at?.clientX ?? stage.left + stage.width / 2;
|
|
718
|
+
const y = at?.clientY ?? stage.top + stage.height / 2;
|
|
719
|
+
surface.panX += (x - box.left) * (1 - ratio);
|
|
720
|
+
surface.panY += (y - box.top) * (1 - ratio);
|
|
721
|
+
surface.needsCenter = false;
|
|
722
|
+
}
|
|
635
723
|
setZoomOf(surface, next);
|
|
636
724
|
applyTransform(surface);
|
|
637
725
|
}
|
|
@@ -795,6 +883,11 @@ export type CanvasMode = (typeof CANVAS_MODES)[number];
|
|
|
795
883
|
/** The base modes the preview flag composes with — the two the Canvas view axis shows it beside. */
|
|
796
884
|
const PREVIEWABLE_BASE_MODES = new Set(["edit", "design"]);
|
|
797
885
|
|
|
886
|
+
/** Whether a base mode is one the preview flag composes with: a member of PREVIEWABLE_BASE_MODES. */
|
|
887
|
+
function isPreviewableBase(mode: string): mode is "edit" | "design" {
|
|
888
|
+
return PREVIEWABLE_BASE_MODES.has(mode);
|
|
889
|
+
}
|
|
890
|
+
|
|
798
891
|
// ─── The Canvas view (§4.2) ──────────────────────────────────────────────────
|
|
799
892
|
// `Edit │ Design` is a radio and `Preview` is a TOGGLE beside it, because that is what the storage
|
|
800
893
|
// Has always been: `preview` is not a base mode, it is a flag that composes with one.
|
|
@@ -855,7 +948,13 @@ export function canvasBaseViewsFor(tab: ViewableTab): CanvasView[] {
|
|
|
855
948
|
/** The base view the tab returns to — what the radio marks while preview is on. */
|
|
856
949
|
export function canvasBaseViewOf(tab: ViewableTab): CanvasView | null {
|
|
857
950
|
const base = tab.session.ui.canvasMode;
|
|
858
|
-
return
|
|
951
|
+
return isPreviewableBase(base) ? base : null;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
/** A tab's Preview toggle: whether it is offered, and whether it is pressed. */
|
|
955
|
+
export interface PreviewState {
|
|
956
|
+
available: boolean;
|
|
957
|
+
on: boolean;
|
|
859
958
|
}
|
|
860
959
|
|
|
861
960
|
/**
|
|
@@ -864,7 +963,7 @@ export function canvasBaseViewOf(tab: ViewableTab): CanvasView | null {
|
|
|
864
963
|
* `available` is a fact about the DOCUMENT (its declared modes) and about the base it is currently
|
|
865
964
|
* in — `source` composes with no preview, so the toggle is not offered there.
|
|
866
965
|
*/
|
|
867
|
-
export function previewStateOf(tab: ViewableTab):
|
|
966
|
+
export function previewStateOf(tab: ViewableTab): PreviewState {
|
|
868
967
|
return {
|
|
869
968
|
available:
|
|
870
969
|
tab.capabilities.modes.includes("preview") &&
|
|
@@ -983,7 +1082,7 @@ export function canvasViewCommands(deps: CanvasCommandDeps): AnyCommand[] {
|
|
|
983
1082
|
* than the control it replaced, which is the opposite of the point.
|
|
984
1083
|
*/
|
|
985
1084
|
function contextTab(commandId: string, args: CommandArgValues) {
|
|
986
|
-
const { pane } = args
|
|
1085
|
+
const { pane } = args;
|
|
987
1086
|
if (pane === undefined) {
|
|
988
1087
|
return requireTab(commandId);
|
|
989
1088
|
}
|
|
@@ -1015,8 +1114,8 @@ export function canvasViewCommands(deps: CanvasCommandDeps): AnyCommand[] {
|
|
|
1015
1114
|
|
|
1016
1115
|
/** The pane a rendering-context verb addresses, named or focused. {@link repaint}'s own rule. */
|
|
1017
1116
|
function paneOfArgs(args: CommandArgValues): string {
|
|
1018
|
-
const { pane } = args
|
|
1019
|
-
return
|
|
1117
|
+
const { pane } = args;
|
|
1118
|
+
return isString(pane) ? pane : workspace.activePaneId;
|
|
1020
1119
|
}
|
|
1021
1120
|
|
|
1022
1121
|
return [
|
|
@@ -1200,9 +1299,9 @@ export function canvasViewCommands(deps: CanvasCommandDeps): AnyCommand[] {
|
|
|
1200
1299
|
* so it simply renders at the pane's width — which is the same clamp the drag applies, arrived
|
|
1201
1300
|
* at by CSS instead of by arithmetic. Refusing would make the verb depend on the window size.
|
|
1202
1301
|
*/
|
|
1203
|
-
run: (_commandCtx, args) => {
|
|
1302
|
+
run: (_commandCtx, args: CommandArgValues) => {
|
|
1204
1303
|
const tab = contextTab("canvas.setEditWidth", args);
|
|
1205
|
-
const { width } = args
|
|
1304
|
+
const { width } = args;
|
|
1206
1305
|
if (width === null) {
|
|
1207
1306
|
clearEditWidth(paneOfArgs(args));
|
|
1208
1307
|
repaint(args);
|
|
@@ -1253,10 +1352,10 @@ export function canvasViewCommands(deps: CanvasCommandDeps): AnyCommand[] {
|
|
|
1253
1352
|
group: "3_canvas",
|
|
1254
1353
|
requires: "an open document",
|
|
1255
1354
|
when: documentOpen,
|
|
1256
|
-
run: (_commandCtx, args) => {
|
|
1355
|
+
run: (_commandCtx, args: CommandArgValues) => {
|
|
1257
1356
|
const tab = contextTab("canvas.setBreakpoint", args);
|
|
1258
|
-
const { media } = args
|
|
1259
|
-
if (media !== null &&
|
|
1357
|
+
const { media } = args;
|
|
1358
|
+
if (media !== null && !isString(media)) {
|
|
1260
1359
|
throw new RangeError(
|
|
1261
1360
|
`command "canvas.setBreakpoint" argument "media": expected a breakpoint key or null`,
|
|
1262
1361
|
);
|
|
@@ -1265,9 +1364,7 @@ export function canvasViewCommands(deps: CanvasCommandDeps): AnyCommand[] {
|
|
|
1265
1364
|
that does not exist — the rule `data.expandRow` applies to a state entry's name.
|
|
1266
1365
|
`getEffectiveMedia` and not `document.$media`: the popover offers the SITE's breakpoints
|
|
1267
1366
|
too, and a command that refused what the control offers would be worse than no command. */
|
|
1268
|
-
const declared = Object.keys(
|
|
1269
|
-
getEffectiveMedia(tab.doc.document?.$media as Record<string, string> | undefined),
|
|
1270
|
-
);
|
|
1367
|
+
const declared = Object.keys(getEffectiveMedia(tab.doc.document.$media));
|
|
1271
1368
|
if (media !== null && !declared.includes(media)) {
|
|
1272
1369
|
throw new RangeError(
|
|
1273
1370
|
`command "canvas.setBreakpoint" argument "media": "${media}" is not a breakpoint this ` +
|
|
@@ -1301,7 +1398,7 @@ export function canvasViewCommands(deps: CanvasCommandDeps): AnyCommand[] {
|
|
|
1301
1398
|
args,
|
|
1302
1399
|
"scheme",
|
|
1303
1400
|
COLOR_SCHEMES,
|
|
1304
|
-
)
|
|
1401
|
+
);
|
|
1305
1402
|
repaint(args);
|
|
1306
1403
|
},
|
|
1307
1404
|
title: "Set Color Scheme",
|
|
@@ -1417,16 +1514,18 @@ export function canvasViewCommands(deps: CanvasCommandDeps): AnyCommand[] {
|
|
|
1417
1514
|
level: "document",
|
|
1418
1515
|
menus: ["palette"],
|
|
1419
1516
|
requires: "a popover in the open document",
|
|
1420
|
-
run: (_commandCtx, args) => {
|
|
1517
|
+
run: (_commandCtx, args: CommandArgValues) => {
|
|
1421
1518
|
const tab = contextTab("canvas.setPopoverOpen", args);
|
|
1422
|
-
|
|
1519
|
+
/* SAFETY: `registry.run` coerces args against this record's schema before `run`, and the
|
|
1520
|
+
schema declares `path` an array of strings and numbers, which is what a JxPath is. */
|
|
1521
|
+
const explicitPath = args["path"] as JxPath | undefined;
|
|
1423
1522
|
const open =
|
|
1424
|
-
|
|
1425
|
-
if (!open &&
|
|
1523
|
+
args["open"] === undefined ? true : booleanArg("canvas.setPopoverOpen", args, "open");
|
|
1524
|
+
if (!open && explicitPath === undefined) {
|
|
1426
1525
|
deps.setOpenPopover(tab, null);
|
|
1427
1526
|
return;
|
|
1428
1527
|
}
|
|
1429
|
-
const path = popoverPathFor(tab,
|
|
1528
|
+
const path = popoverPathFor(tab, explicitPath);
|
|
1430
1529
|
/* REFUSES a path that is not a popover rather than opening nothing — the rule
|
|
1431
1530
|
`canvas.setBreakpoint` applies to a breakpoint key. A <dialog> is refused with it: its UA
|
|
1432
1531
|
rules key off `open`, not `popover`, so de-popovering one falls back to a different rule
|
|
@@ -1477,16 +1576,18 @@ export function canvasViewCommands(deps: CanvasCommandDeps): AnyCommand[] {
|
|
|
1477
1576
|
level: "document",
|
|
1478
1577
|
menus: ["palette"],
|
|
1479
1578
|
requires: "a dialog in the open document",
|
|
1480
|
-
run: (_commandCtx, args) => {
|
|
1579
|
+
run: (_commandCtx, args: CommandArgValues) => {
|
|
1481
1580
|
const tab = contextTab("canvas.setDialogOpen", args);
|
|
1482
|
-
|
|
1581
|
+
/* SAFETY: `registry.run` coerces args against this record's schema before `run`, and the
|
|
1582
|
+
schema declares `path` an array of strings and numbers, which is what a JxPath is. */
|
|
1583
|
+
const explicitPath = args["path"] as JxPath | undefined;
|
|
1483
1584
|
const open =
|
|
1484
|
-
|
|
1485
|
-
if (!open &&
|
|
1585
|
+
args["open"] === undefined ? true : booleanArg("canvas.setDialogOpen", args, "open");
|
|
1586
|
+
if (!open && explicitPath === undefined) {
|
|
1486
1587
|
deps.setOpenDialog(tab, null);
|
|
1487
1588
|
return;
|
|
1488
1589
|
}
|
|
1489
|
-
const path = dialogPathFor(tab,
|
|
1590
|
+
const path = dialogPathFor(tab, explicitPath);
|
|
1490
1591
|
/* REFUSES a path that is not a dialog, for the same reason its twin refuses a non-popover:
|
|
1491
1592
|
the canvas would draw it under the wrong rule and with the wrong name. */
|
|
1492
1593
|
if (path === null) {
|
|
@@ -1528,14 +1629,14 @@ export function canvasViewCommands(deps: CanvasCommandDeps): AnyCommand[] {
|
|
|
1528
1629
|
* (`scripts/screenshots/README.md`) forbids outright. The pointer and the camera use the same
|
|
1529
1630
|
* door.
|
|
1530
1631
|
*/
|
|
1531
|
-
run: (_commandCtx, args) => {
|
|
1632
|
+
run: (_commandCtx, args: CommandArgValues) => {
|
|
1532
1633
|
// Resolve the tab first, so a pane with no document refuses before anything opens.
|
|
1533
1634
|
contextTab("canvas.setResolvingOpen", args);
|
|
1534
|
-
const { open, pane } = args
|
|
1635
|
+
const { open, pane } = args;
|
|
1535
1636
|
// `open` defaults to true and is never COERCED: `{ open: "no" }` would otherwise read as a
|
|
1536
1637
|
// Close, the class of silent wrong answer this setter family exists to stop.
|
|
1537
1638
|
deps.setResolvingOpen(
|
|
1538
|
-
|
|
1639
|
+
isString(pane) ? pane : workspace.activePaneId,
|
|
1539
1640
|
open === undefined || booleanArg("canvas.setResolvingOpen", args, "open"),
|
|
1540
1641
|
);
|
|
1541
1642
|
},
|
|
@@ -1578,26 +1679,24 @@ export function canvasViewCommands(deps: CanvasCommandDeps): AnyCommand[] {
|
|
|
1578
1679
|
group: "3_canvas",
|
|
1579
1680
|
requires: "an open component document",
|
|
1580
1681
|
when: documentOpen,
|
|
1581
|
-
run: (_commandCtx, args) => {
|
|
1682
|
+
run: (_commandCtx, args: CommandArgValues) => {
|
|
1582
1683
|
const tab = contextTab("canvas.setTestProp", args);
|
|
1583
1684
|
const name = stringArg("canvas.setTestProp", args, "name");
|
|
1584
1685
|
// REFUSES a prop the component does not declare, rather than seeding a value nothing reads
|
|
1585
1686
|
// — the rule `data.expandRow` and `canvas.setBreakpoint` both apply to their own names.
|
|
1586
|
-
const declared = Object.keys(
|
|
1587
|
-
(tab.doc.document?.state as Record<string, unknown> | undefined) ?? {},
|
|
1588
|
-
);
|
|
1687
|
+
const declared = Object.keys(tab.doc.document.state ?? {});
|
|
1589
1688
|
if (!declared.includes(name)) {
|
|
1590
1689
|
throw new RangeError(
|
|
1591
1690
|
`command "canvas.setTestProp" argument "name": "${name}" is not a prop this component ` +
|
|
1592
1691
|
`declares — it declares: ${declared.length > 0 ? declared.join(", ") : "nothing"}`,
|
|
1593
1692
|
);
|
|
1594
1693
|
}
|
|
1595
|
-
const { value } = args
|
|
1694
|
+
const { value } = args;
|
|
1596
1695
|
const next = { ...tab.session.ui.previewProps };
|
|
1597
1696
|
if (value === null || value === undefined) {
|
|
1598
1697
|
delete next[name];
|
|
1599
1698
|
} else {
|
|
1600
|
-
next[name] = value
|
|
1699
|
+
next[name] = value;
|
|
1601
1700
|
}
|
|
1602
1701
|
tab.session.ui.previewProps = Object.keys(next).length > 0 ? next : null;
|
|
1603
1702
|
repaint(args);
|
|
@@ -1665,13 +1764,13 @@ export function registerCanvasViewCommands(
|
|
|
1665
1764
|
*/
|
|
1666
1765
|
export function updateActivePanelHeaders(surface: CanvasSurface = activeCanvasSurface()) {
|
|
1667
1766
|
const activeMedia = activeMediaOfPane(surface.paneId);
|
|
1668
|
-
|
|
1767
|
+
// A board the stage has not bound yet has no header to mark.
|
|
1768
|
+
const panels: readonly UnboundCanvasPanel[] = surface.panels;
|
|
1769
|
+
for (const p of panels) {
|
|
1669
1770
|
const header = p.element?.querySelector('[part="panel-header"]');
|
|
1670
1771
|
if (header) {
|
|
1671
1772
|
const isActive =
|
|
1672
|
-
(activeMedia === null && p.mediaName === "base") ||
|
|
1673
|
-
(activeMedia === null && p.mediaName === null) ||
|
|
1674
|
-
activeMedia === p.mediaName;
|
|
1773
|
+
(activeMedia === null && p.mediaName === "base") || activeMedia === p.mediaName;
|
|
1675
1774
|
/* An ATTRIBUTE the document does not bind, written from outside it. Which board is current is
|
|
1676
1775
|
a fact about the pane's session that changes without the stage being rebuilt — the same
|
|
1677
1776
|
reason the pan transform is written rather than bound — so a reconcile can never disagree
|
|
@@ -12,8 +12,9 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import { activeTab } from "../workspace/workspace";
|
|
15
|
-
import { getNodeAtPath } from "
|
|
15
|
+
import { getNodeAtPath } from "@jxsuite/schema/doc-ops";
|
|
16
16
|
import { documentHasDialog, isDialog } from "@jxsuite/schema/dialogs";
|
|
17
|
+
import { isNonNullObject } from "@jxsuite/schema/guards";
|
|
17
18
|
import { primarySelection } from "../tabs/selection";
|
|
18
19
|
import type { JxMutableNode } from "@jxsuite/schema/types";
|
|
19
20
|
import type { JxPath } from "../state";
|
|
@@ -39,7 +40,8 @@ export function ancestorDialogPath(
|
|
|
39
40
|
for (let end = path.length; end >= 0; end -= 1) {
|
|
40
41
|
const prefix = path.slice(0, end);
|
|
41
42
|
const node = getNodeAtPath(doc, prefix);
|
|
42
|
-
|
|
43
|
+
// A path can end on a text child or a value, so only an element is asked about its tag.
|
|
44
|
+
if (isNonNullObject(node) && isDialog(node)) {
|
|
43
45
|
return prefix;
|
|
44
46
|
}
|
|
45
47
|
}
|
|
@@ -58,19 +60,22 @@ export function ancestorDialogPath(
|
|
|
58
60
|
* @returns The dialog's path, or null.
|
|
59
61
|
*/
|
|
60
62
|
export function dialogPathFor(tab: Tab, explicit?: JxPath): JxPath | null {
|
|
63
|
+
/* SAFETY: a widening, so it cannot hide a mismatch: `Tab` declares the document always present,
|
|
64
|
+
but a tab record without one must answer null rather than throw (tests/dialog-path.test.ts,
|
|
65
|
+
"a tab with no document"), and the widened type keeps that guard checked. */
|
|
61
66
|
const doc = tab.doc.document as JxMutableNode | undefined;
|
|
62
67
|
if (!doc) {
|
|
63
68
|
return null;
|
|
64
69
|
}
|
|
65
70
|
if (explicit) {
|
|
66
71
|
const node = getNodeAtPath(doc, explicit);
|
|
67
|
-
return node &&
|
|
72
|
+
return isNonNullObject(node) && isDialog(node) ? explicit : null;
|
|
68
73
|
}
|
|
69
74
|
return ancestorDialogPath(doc, primarySelection(tab.session.selection));
|
|
70
75
|
}
|
|
71
76
|
|
|
72
77
|
/** Whether the active document holds a `<dialog>` at all — the command's `enablement`. */
|
|
73
78
|
export function activeDocumentHasDialog(): boolean {
|
|
74
|
-
const doc = activeTab.value?.doc.document
|
|
79
|
+
const doc = activeTab.value?.doc.document;
|
|
75
80
|
return doc ? documentHasDialog(doc) : false;
|
|
76
81
|
}
|
|
@@ -19,7 +19,6 @@ import { ancestorDialogPath } from "./dialog-path";
|
|
|
19
19
|
import { postDialogOpen } from "./iframe-host";
|
|
20
20
|
import { primarySelection } from "../tabs/selection";
|
|
21
21
|
import { updateSession } from "../store";
|
|
22
|
-
import type { JxMutableNode } from "@jxsuite/schema/types";
|
|
23
22
|
import type { JxPath } from "../state";
|
|
24
23
|
import type { Tab } from "../tabs/tab";
|
|
25
24
|
|
|
@@ -51,7 +50,7 @@ export function setOpenDialog(tab: Tab, path: JxPath | null): void {
|
|
|
51
50
|
* @returns Whether anything changed.
|
|
52
51
|
*/
|
|
53
52
|
export function openDialogFor(tab: Tab, path: JxPath | null): boolean {
|
|
54
|
-
const target = ancestorDialogPath(tab.doc.document
|
|
53
|
+
const target = ancestorDialogPath(tab.doc.document, path);
|
|
55
54
|
if (target === null || samePath(tab.session.ui.openDialog, target)) {
|
|
56
55
|
return false;
|
|
57
56
|
}
|
package/src/canvas/diff-marks.ts
CHANGED
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
*/
|
|
36
36
|
|
|
37
37
|
import { deepEqual, matchChildren } from "@jxsuite/collab/diff-core";
|
|
38
|
+
import { isJsonObject } from "@jxsuite/schema/guards";
|
|
38
39
|
import type { JxMutableNode, JxPath } from "@jxsuite/schema/types";
|
|
39
40
|
|
|
40
41
|
/** What happened to a node. `modified` means the node survived and its own content changed. */
|
|
@@ -84,10 +85,6 @@ export interface ChangeMapOptions {
|
|
|
84
85
|
|
|
85
86
|
const DEFAULT_MAX_CELLS = 250_000;
|
|
86
87
|
|
|
87
|
-
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
88
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
88
|
class ChangeWalker {
|
|
92
89
|
readonly original: ChangeMark[] = [];
|
|
93
90
|
readonly current: ChangeMark[] = [];
|
|
@@ -121,12 +118,7 @@ class ChangeWalker {
|
|
|
121
118
|
this.steps.push({ currentPath: bPath, kind, originalPath: aPath });
|
|
122
119
|
}
|
|
123
120
|
|
|
124
|
-
diffNode(
|
|
125
|
-
aPath: JxPath,
|
|
126
|
-
bPath: JxPath,
|
|
127
|
-
a: Record<string, unknown>,
|
|
128
|
-
b: Record<string, unknown>,
|
|
129
|
-
): void {
|
|
121
|
+
diffNode(aPath: JxPath, bPath: JxPath, a: JxMutableNode, b: JxMutableNode): void {
|
|
130
122
|
const isRoot = aPath.length === 0 && bPath.length === 0;
|
|
131
123
|
let ownChanged = false;
|
|
132
124
|
for (const key of new Set([...Object.keys(a), ...Object.keys(b)])) {
|
|
@@ -161,8 +153,8 @@ class ChangeWalker {
|
|
|
161
153
|
private diffChildren(
|
|
162
154
|
aPath: JxPath,
|
|
163
155
|
bPath: JxPath,
|
|
164
|
-
ca: readonly
|
|
165
|
-
cb: readonly
|
|
156
|
+
ca: readonly (JxMutableNode | string)[],
|
|
157
|
+
cb: readonly (JxMutableNode | string)[],
|
|
166
158
|
): void {
|
|
167
159
|
if (ca.length * cb.length > this.maxCells) {
|
|
168
160
|
this.degraded = true;
|
|
@@ -183,7 +175,7 @@ class ChangeWalker {
|
|
|
183
175
|
if (!match.identical) {
|
|
184
176
|
const aItem = ca[match.aIndex];
|
|
185
177
|
const bItem = cb[match.bIndex];
|
|
186
|
-
if (
|
|
178
|
+
if (isJsonObject(aItem) && isJsonObject(bItem)) {
|
|
187
179
|
this.diffNode(
|
|
188
180
|
[...aPath, "children", match.aIndex],
|
|
189
181
|
[...bPath, "children", match.bIndex],
|
|
@@ -211,11 +203,12 @@ class ChangeWalker {
|
|
|
211
203
|
kind: "added" | "removed",
|
|
212
204
|
aPath: JxPath,
|
|
213
205
|
bPath: JxPath,
|
|
214
|
-
|
|
206
|
+
// Every caller reads in bounds, but an indexed read is typed possibly undefined; it is no element.
|
|
207
|
+
item: JxMutableNode | string | undefined,
|
|
215
208
|
aIndex: number | null,
|
|
216
209
|
bIndex: number | null,
|
|
217
210
|
): void {
|
|
218
|
-
if (!
|
|
211
|
+
if (!isJsonObject(item)) {
|
|
219
212
|
this.emit("modified", aPath, bPath);
|
|
220
213
|
return;
|
|
221
214
|
}
|
|
@@ -241,7 +234,7 @@ export function buildChangeMap(
|
|
|
241
234
|
opts: ChangeMapOptions = {},
|
|
242
235
|
): ChangeMap {
|
|
243
236
|
const walker = new ChangeWalker(opts.maxCells ?? DEFAULT_MAX_CELLS);
|
|
244
|
-
walker.diffNode([], [], a
|
|
237
|
+
walker.diffNode([], [], a, b);
|
|
245
238
|
return {
|
|
246
239
|
current: walker.current,
|
|
247
240
|
degraded: walker.degraded,
|