@jxsuite/studio 6.1.1 → 8.0.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/README.md +5 -5
- package/dist/chunks/2020-5wtzce5g.js +4 -0
- package/dist/chunks/{action-group-2mqby73c.js → action-group-4aan7g6g.js} +3 -3
- package/dist/chunks/adapter-5tphg7xe.js +4 -0
- package/dist/chunks/add-new-flow-psym14sn.js +4 -0
- package/dist/chunks/cf-account-picker-haqazq5r.js +4 -0
- package/dist/chunks/cf-settings-h2wrh6hq.js +4 -0
- package/dist/chunks/color-area-6rbra5dy.js +4 -0
- package/dist/chunks/color-field-gy56c94g.js +4 -0
- package/dist/chunks/color-m7r1vk54.js +4 -0
- package/dist/chunks/color-slider-sqqdyf6c.js +4 -0
- package/dist/chunks/combobox-72h32ejk.js +4 -0
- package/dist/chunks/components-r22xca09.js +4 -0
- package/dist/chunks/content-source-mmppmcyg.js +4 -0
- package/dist/chunks/convert-to-repeater-he70fc2b.js +4 -0
- package/dist/chunks/dialog-c4x05vyx.js +4 -0
- package/dist/chunks/editor-ccd9jwsa.js +4 -0
- package/dist/chunks/entry-commands-6qxz9e8p.js +4 -0
- package/dist/chunks/extension-sections-0egb88dm.js +4 -0
- package/dist/chunks/file-ops-qnab36ek.js +4 -0
- package/dist/chunks/files-rcn56qvm.js +4 -0
- package/dist/chunks/format-host-yxz0kjjs.js +4 -0
- package/dist/chunks/fs-events-d1qxq4z4.js +4 -0
- package/dist/chunks/grid-open-4z1g062t.js +4 -0
- package/dist/chunks/grid-view-qg1b5eqx.js +51 -0
- package/dist/chunks/icons-63bjtbs7.js +4 -0
- package/dist/chunks/iframe-entry-2zggzajv.js +5 -0
- package/dist/chunks/iframe-entry-76j8vwwx.js +5 -0
- package/dist/chunks/iframe-entry-99nr5zfb.js +5 -0
- package/dist/chunks/iframe-entry-pkgmcgp0.js +5 -0
- package/dist/chunks/iframe-host-ssv7kyj0.js +4 -0
- package/dist/chunks/{index-2veqmnhr.js → index-32eqzv1k.js} +3 -3
- package/dist/chunks/index-f0jn7nnp.js +4 -0
- package/dist/chunks/{javascript-8nbvs12s.js → javascript-pjp734q4.js} +3 -3
- package/dist/chunks/jsonMode-njkvsa02.js +13 -0
- package/dist/chunks/jx-validate-ttasrbh7.js +4 -0
- package/dist/chunks/layers-bgyr11tr.js +4 -0
- package/dist/chunks/layers-panel-7ez66zeq.js +4 -0
- package/dist/chunks/listbox-c421cf8c.js +4 -0
- package/dist/chunks/lit-html-v9gh687x.js +4 -0
- package/dist/chunks/media-library-sq468wts.js +4 -0
- package/dist/chunks/media-picker-shfe59pt.js +4 -0
- package/dist/chunks/menu-bdpzbfvs.js +4 -0
- package/dist/chunks/monaco-binding-vq1hgnn0.js +4 -0
- package/dist/chunks/monaco-buffer-3afgwvbp.js +4 -0
- package/dist/chunks/monaco-setup-xrd2cbkp.js +4 -0
- package/dist/chunks/notify-kzrjr3fv.js +4 -0
- package/dist/chunks/number-field-y62xq0ty.js +4 -0
- package/dist/chunks/parse-v77xtwv7.js +4 -0
- package/dist/chunks/platform-7v4rtd7m.js +4 -0
- package/dist/chunks/popover-b89sfej7.js +4 -0
- package/dist/chunks/publish-panel-2z9gw8ee.js +4 -0
- package/dist/chunks/publish-quick-qx2455cj.js +4 -0
- package/dist/chunks/publish-workspace-wrc1dgwx.js +4 -0
- package/dist/chunks/quick-search-n0t0eqxb.js +4 -0
- package/dist/chunks/references-9547rg5s.js +4 -0
- package/dist/chunks/right-panel-wsgnr9pn.js +4 -0
- package/dist/chunks/select-rzds841e.js +4 -0
- package/dist/chunks/source-control-kwktr9y6.js +4 -0
- package/dist/chunks/split-c9zfdgxf.js +4 -0
- package/dist/chunks/studio-03ct6yfv.js +9 -0
- package/dist/chunks/studio-07rcfje3.js +5 -0
- package/dist/chunks/studio-3e54qh39.js +7 -0
- package/dist/chunks/studio-3exxhz5g.js +5 -0
- package/dist/chunks/studio-3q40e3rj.js +5 -0
- package/dist/chunks/studio-3qeh9t0h.js +6 -0
- package/dist/chunks/studio-3qqjeep5.js +6 -0
- package/dist/chunks/studio-43sd2mam.js +4 -0
- package/dist/chunks/studio-4hp8pkyt.js +5 -0
- package/dist/chunks/studio-58xg6j2q.js +9 -0
- package/dist/chunks/studio-5g0rprdt.js +7 -0
- package/dist/chunks/studio-6m380wp7.js +5 -0
- package/dist/chunks/studio-80jyh1xh.js +4 -0
- package/dist/chunks/studio-83mk4bgg.js +9 -0
- package/dist/chunks/{studio-kggey1jt.js → studio-881z1xrx.js} +4 -4
- package/dist/chunks/studio-8m0y2qe7.js +5 -0
- package/dist/chunks/studio-8tr6cfrc.js +5 -0
- package/dist/chunks/studio-8vcvfs7r.js +6 -0
- package/dist/chunks/studio-9tmebf0s.js +5 -0
- package/dist/chunks/studio-a2bvaptz.js +5 -0
- package/dist/chunks/studio-b7y5mr30.js +5 -0
- package/dist/chunks/studio-bavb31r0.js +5 -0
- package/dist/chunks/studio-bbe4c90a.js +5 -0
- package/dist/chunks/studio-c05wdnt3.js +5 -0
- package/dist/chunks/studio-ccv2svc6.js +5 -0
- package/dist/chunks/studio-d5grtb9e.js +16 -0
- package/dist/chunks/studio-df0baea9.js +5 -0
- package/dist/chunks/studio-dgk4dqtx.js +7 -0
- package/dist/chunks/studio-e1g64q43.js +5 -0
- package/dist/chunks/studio-ed1hp6zf.js +6 -0
- package/dist/chunks/studio-ed3xx40h.js +7 -0
- package/dist/chunks/studio-f14e1zdj.js +5 -0
- package/dist/chunks/studio-fbhxxc5f.js +5 -0
- package/dist/chunks/studio-fyh0jc96.js +5 -0
- package/dist/chunks/studio-gcxk20n7.js +5 -0
- package/dist/chunks/studio-jaaz8ce9.js +5 -0
- package/dist/chunks/{studio-8grwxtqk.js → studio-jcnsdaep.js} +4 -4
- package/dist/chunks/studio-jsgf2q5k.js +7 -0
- package/dist/chunks/{studio-1q1sh2ax.js → studio-k3xxbagr.js} +3 -3
- package/dist/chunks/studio-k7evxqh4.js +5 -0
- package/dist/chunks/studio-kt3pjkwd.js +5 -0
- package/dist/chunks/studio-m8g16bgz.js +5 -0
- package/dist/chunks/studio-mn0476ag.js +5 -0
- package/dist/chunks/studio-mx1smyq0.js +5 -0
- package/dist/chunks/studio-n0c5h6mf.js +5 -0
- package/dist/chunks/{studio-rv11kfwa.js → studio-nh6d342n.js} +7 -7
- package/dist/chunks/studio-nqxqf8p2.js +4 -0
- package/dist/chunks/studio-p4nrkvqr.js +5 -0
- package/dist/chunks/{studio-h46vtzk8.js → studio-pbxa5fpc.js} +4 -4
- package/dist/chunks/studio-pgmvdv7z.js +7 -0
- package/dist/chunks/studio-ph84avkf.js +5 -0
- package/dist/chunks/{studio-wszjyh0j.js → studio-q0mvbaq6.js} +4 -4
- package/dist/chunks/studio-q0tccd43.js +5 -0
- package/dist/chunks/studio-q7rtx6zq.js +14 -0
- package/dist/chunks/{studio-pre0skq6.js → studio-qgh13jtz.js} +4 -4
- package/dist/chunks/studio-qmn1xc24.js +5 -0
- package/dist/chunks/studio-qwdqwkj0.js +5 -0
- package/dist/chunks/{studio-t6b6qe31.js → studio-r5qy30vx.js} +4 -4
- package/dist/chunks/studio-rj9eamf8.js +5 -0
- package/dist/chunks/studio-rptgsk96.js +5 -0
- package/dist/chunks/studio-rthyg42z.js +928 -0
- package/dist/chunks/studio-s19tp1xr.js +5 -0
- package/dist/chunks/studio-s32578pn.js +5 -0
- package/dist/chunks/studio-svb7yyve.js +5 -0
- package/dist/chunks/studio-syreb644.js +5 -0
- package/dist/chunks/studio-tf9jryb1.js +10 -0
- package/dist/chunks/studio-tfkznv39.js +5 -0
- package/dist/chunks/studio-tft6r105.js +5 -0
- package/dist/chunks/studio-txf2kysx.js +5 -0
- package/dist/chunks/studio-v8867ddv.js +12 -0
- package/dist/chunks/studio-vxq7fcvv.js +5 -0
- package/dist/chunks/studio-w4rz9hdk.js +5 -0
- package/dist/chunks/studio-wbcjbhy1.js +9 -0
- package/dist/chunks/studio-wc649wss.js +5 -0
- package/dist/chunks/studio-wys23mxz.js +5 -0
- package/dist/chunks/studio-x1x167jh.js +5 -0
- package/dist/chunks/studio-x9hsze61.js +5 -0
- package/dist/chunks/studio-y0n7yxea.js +9 -0
- package/dist/chunks/studio-y3ahhdpx.js +5 -0
- package/dist/chunks/studio-z97c48fk.js +5 -0
- package/dist/chunks/studio-zat62m0c.js +5 -0
- package/dist/chunks/studio-zcd2e7yz.js +5 -0
- package/dist/chunks/studio-zz9qe3rw.js +64 -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-1gv0h53h.js +4 -0
- package/dist/chunks/toast-host-1yg5ar8d.js +4 -0
- package/dist/chunks/{toolbar-2nnzqhrj.js → toolbar-44cm5cta.js} +3 -3
- package/dist/chunks/tooltip-yypz28gq.js +4 -0
- package/dist/chunks/tree-9xa4hm7n.js +4 -0
- package/dist/chunks/tsMode-epyfz1hv.js +14 -0
- package/dist/chunks/workspace-dz7nxfhv.js +4 -0
- package/dist/chunks/workspace-home-xsd7hkjw.js +4 -0
- package/dist/chunks/ws-client-bv552sfx.js +4 -0
- package/dist/iframe-entry.js +20 -16
- package/dist/manifest.json +77 -63
- package/dist/studio.js +106 -107
- package/dist/workers/ts.worker.js +3 -3
- package/package.json +17 -16
- 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/component-examples.ts +272 -0
- package/src/browse/library-commands.ts +64 -104
- package/src/browse/library-layouts.ts +270 -53
- package/src/browse/library-model.ts +194 -134
- package/src/browse/library-pane.ts +748 -440
- package/src/browse/library-preview.ts +161 -26
- package/src/browse/library-source.ts +308 -41
- package/src/browse/preview-root.ts +78 -0
- package/src/browse/preview-style.ts +155 -0
- package/src/canvas/asset-refs.ts +40 -10
- package/src/canvas/asset-resolve.ts +19 -23
- package/src/canvas/canvas-helpers.ts +7 -6
- package/src/canvas/canvas-live-render.ts +260 -77
- package/src/canvas/canvas-origin.ts +37 -12
- package/src/canvas/canvas-page-context.ts +112 -0
- package/src/canvas/canvas-patcher.ts +30 -30
- package/src/canvas/canvas-perf.ts +11 -5
- package/src/canvas/canvas-render.ts +175 -148
- package/src/canvas/canvas-surface.ts +5 -3
- package/src/canvas/canvas-utils.ts +147 -61
- 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 +120 -12
- package/src/canvas/iframe-editable-root.ts +29 -16
- package/src/canvas/iframe-entry.ts +104 -75
- package/src/canvas/iframe-eval.ts +73 -49
- package/src/canvas/iframe-host.ts +269 -158
- package/src/canvas/iframe-inline-edit.ts +49 -30
- package/src/canvas/iframe-insert.ts +5 -4
- package/src/canvas/iframe-interaction.ts +30 -25
- package/src/canvas/iframe-keys.ts +11 -0
- package/src/canvas/iframe-overlay.ts +1 -1
- package/src/canvas/iframe-patch.ts +25 -21
- package/src/canvas/iframe-position.ts +12 -6
- package/src/canvas/iframe-protocol.ts +36 -21
- package/src/canvas/iframe-render.ts +84 -35
- package/src/canvas/iframe-slash.ts +24 -11
- package/src/canvas/iframe-subtree.ts +10 -3
- package/src/canvas/npm-modules.ts +22 -0
- 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/preview-navigate.ts +16 -0
- package/src/canvas/repeater-sources.ts +200 -0
- package/src/canvas/serialize-scope.ts +13 -5
- package/src/canvas/stage-scrollbar.ts +7 -2
- package/src/canvas/surface-registry.ts +27 -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/app-commands.ts +16 -6
- package/src/commands/budget.ts +13 -11
- package/src/commands/command-args.ts +103 -71
- package/src/commands/context.ts +55 -28
- package/src/commands/defaults.ts +69 -45
- package/src/commands/keymap.ts +56 -43
- package/src/commands/levels.ts +14 -8
- package/src/commands/live-context.ts +9 -7
- package/src/commands/reference.ts +2 -1
- package/src/commands/registry.ts +22 -11
- package/src/commands/run-reported.ts +15 -10
- package/src/component-props.ts +46 -30
- package/src/content/collection-match.ts +11 -9
- package/src/content/collection-pages.ts +412 -0
- package/src/content/content-collections.ts +270 -0
- package/src/content/draft-state.ts +4 -3
- package/src/content/entry-commands.ts +54 -62
- package/src/content/entry-editor.ts +137 -32
- package/src/content/entry-fields.ts +25 -8
- package/src/content/entry-inspector.ts +225 -0
- package/src/content/entry-model.ts +38 -15
- package/src/content/entry-open.ts +80 -0
- package/src/content/entry-summaries.ts +440 -0
- package/src/content/file-record-ids.ts +80 -0
- package/src/content/file-records.ts +125 -0
- package/src/content/page-summaries.ts +129 -0
- package/src/content/record-entry.ts +201 -0
- package/src/content/writing-banner.ts +177 -0
- package/src/create/add-new-commands.ts +185 -0
- package/src/create/add-new-flow.ts +1116 -0
- package/src/create/add-new.ts +1014 -0
- package/src/create/element-name.ts +121 -0
- 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 +78 -48
- package/src/editor/convert-to-repeater.ts +34 -22
- package/src/editor/editable-tags.ts +17 -2
- package/src/editor/file-drop-action.ts +29 -22
- package/src/editor/inline-edit-apply.ts +79 -17
- package/src/editor/inline-edit.ts +76 -50
- package/src/editor/inline-format.ts +59 -56
- package/src/editor/inline-link.ts +40 -15
- package/src/editor/insert-component.ts +91 -0
- package/src/editor/insert-zone-action.ts +14 -5
- package/src/editor/merge-tags.ts +58 -19
- package/src/editor/repeater-scope.ts +39 -28
- package/src/editor/shortcuts.ts +76 -42
- package/src/editor/slash-menu.ts +52 -14
- package/src/files/asset-versions.ts +4 -4
- package/src/files/components.ts +89 -20
- package/src/files/elements.ts +5 -6
- package/src/files/file-ops.ts +92 -41
- package/src/files/files.ts +248 -239
- package/src/files/fs-events.ts +18 -7
- package/src/files/media-meta.ts +97 -2
- package/src/files/media-paths.ts +3 -0
- package/src/files/media-types.ts +55 -0
- package/src/files/media-upload.ts +209 -52
- package/src/files/new-file-name.ts +156 -0
- package/src/files/serialize-document.ts +15 -5
- 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 +91 -50
- package/src/github/github-auth-status.ts +27 -3
- package/src/github/github-auth.ts +21 -11
- package/src/github/github-publish.ts +28 -23
- 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 +25 -23
- package/src/grid/grid-layout.ts +21 -5
- package/src/grid/grid-open.ts +3 -33
- package/src/grid/grid-panel.ts +65 -6
- package/src/grid/grid-reveal.ts +34 -0
- package/src/grid/grid-source.ts +9 -31
- package/src/grid/grid-view.ts +45 -23
- 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 +100 -31
- package/src/grid/sources/csv-file-source.ts +2 -2
- package/src/grid/tabulator-tables.d.ts +61 -34
- package/src/hosting/document.ts +2 -2
- package/src/hosting/stage.ts +7 -7
- package/src/i18n/i18n-commands.ts +3 -3
- package/src/media/media-commands.ts +181 -0
- package/src/media/media-library-model.ts +232 -0
- package/src/media/media-library.ts +1283 -0
- package/src/media/media-pane.ts +51 -20
- 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 +38 -14
- package/src/panels/ai-chat/attached-context.ts +13 -7
- package/src/panels/ai-chat/chat-markdown.ts +8 -8
- 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 +57 -46
- package/src/panels/bottom-dock.ts +5 -3
- package/src/panels/canvas-dnd-bridge.ts +36 -26
- package/src/panels/chat-panel.ts +6 -6
- package/src/panels/collections-panel.ts +306 -0
- package/src/panels/component-preview.ts +35 -13
- package/src/panels/data-explorer.ts +63 -26
- package/src/panels/data-grid.ts +18 -11
- package/src/panels/dnd.ts +115 -138
- package/src/panels/editors.ts +52 -21
- package/src/panels/elements-panel.ts +19 -5
- package/src/panels/empty-state.ts +2 -2
- package/src/panels/events-panel.ts +84 -69
- package/src/panels/formula-workspace.ts +78 -54
- package/src/panels/frontmatter-fields.ts +33 -28
- package/src/panels/git-diff-open.ts +10 -6
- package/src/panels/head-panel.ts +488 -202
- package/src/panels/i18n-panel.ts +20 -12
- package/src/panels/imports-panel.ts +25 -47
- package/src/panels/jump-bar.ts +75 -31
- package/src/panels/layers-panel.ts +130 -101
- package/src/panels/left-panel.ts +25 -11
- package/src/panels/navigator-panels.ts +23 -11
- package/src/panels/pane-context.ts +140 -49
- package/src/panels/pane-grid.ts +55 -26
- package/src/panels/panel-registry.ts +36 -46
- package/src/panels/properties-panel.ts +182 -124
- package/src/panels/quick-search.ts +53 -31
- package/src/panels/right-panel.ts +201 -45
- package/src/panels/seo-modal.ts +54 -125
- package/src/panels/settings-menu.ts +63 -61
- package/src/panels/settings-pane.ts +268 -162
- package/src/panels/signals-panel.ts +156 -135
- package/src/panels/site-model.ts +367 -0
- package/src/panels/site-panel.ts +638 -0
- package/src/panels/statement-editor.ts +230 -140
- package/src/panels/style-panel.ts +253 -206
- package/src/panels/style-utils.ts +114 -51
- package/src/panels/stylebook-doc.ts +195 -60
- package/src/panels/stylebook-layers-panel.ts +48 -89
- package/src/panels/stylebook-panel.ts +60 -27
- package/src/panels/styles-panel.ts +327 -0
- package/src/panels/tab-drop.ts +27 -11
- package/src/panels/tab-strip.ts +143 -49
- package/src/platform-errors.ts +57 -43
- package/src/platform.ts +59 -31
- package/src/platforms/cloud.ts +373 -176
- package/src/platforms/default-platform.ts +14 -8
- package/src/platforms/devserver.ts +180 -142
- package/src/platforms/read-batcher.ts +16 -8
- package/src/project-list.ts +2 -1
- package/src/publish/deploy-checklist.ts +20 -9
- package/src/publish/pages-service.ts +66 -27
- package/src/publish/publish-changes.ts +491 -0
- package/src/publish/publish-commands.ts +88 -22
- package/src/publish/publish-ids.ts +49 -0
- package/src/publish/publish-panel.ts +10 -6
- package/src/publish/publish-quick.ts +148 -0
- package/src/publish/publish-workspace.ts +926 -0
- package/src/publish/source-control.ts +907 -0
- 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 +74 -51
- package/src/services/cem-export.ts +149 -58
- package/src/services/cf-settings.ts +4 -4
- package/src/services/clock.ts +6 -1
- package/src/services/code-services.ts +37 -31
- package/src/services/connection.ts +2 -2
- 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 +20 -14
- 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 +29 -9
- package/src/services/settings/definitions.ts +25 -14
- 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 +128 -70
- package/src/settings/css-vars-editor.ts +119 -32
- package/src/settings/defs-editor.ts +38 -35
- package/src/settings/developer-panels.ts +43 -0
- package/src/settings/extension-rows.ts +16 -8
- package/src/settings/extension-sections.ts +42 -14
- package/src/settings/extensions-section.ts +4 -1
- package/src/settings/general-settings.ts +101 -28
- package/src/settings/locales-section.ts +20 -12
- package/src/settings/preferences-dialog.ts +17 -7
- package/src/settings/preferences-keymap.ts +7 -5
- package/src/settings/preferences-sections.ts +11 -5
- package/src/settings/project-sections.ts +28 -11
- package/src/settings/schema-field-ui.ts +12 -1
- package/src/settings/section-registry.ts +116 -11
- package/src/settings/settings-dialog.ts +192 -0
- package/src/settings/settings-document.ts +186 -166
- package/src/shell/tree.ts +6 -5
- package/src/shell.ts +536 -477
- package/src/site-context.ts +101 -32
- package/src/state.ts +68 -57
- package/src/store.ts +54 -34
- package/src/studio.ts +219 -116
- package/src/style/live-preview.ts +1 -1
- package/src/style/project-styles.ts +40 -7
- package/src/style/stylebook-specimens.ts +89 -0
- package/src/style/stylebook-target.ts +26 -0
- package/src/style/tag-inheritance.ts +105 -0
- package/src/style/token-ref.ts +5 -4
- package/src/style/variables-focus.ts +61 -0
- package/src/style/variables-view.ts +235 -0
- package/src/surfaces/about.ts +18 -19
- package/src/surfaces/add-new.json +1482 -0
- package/src/surfaces/add-new.ts +325 -0
- package/src/surfaces/add-repo.ts +17 -19
- package/src/surfaces/ai-chat.ts +33 -38
- 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.json +4 -3
- package/src/surfaces/boot-failure.ts +4 -5
- package/src/surfaces/bottom-dock.json +1 -1
- package/src/surfaces/bottom-dock.ts +9 -18
- package/src/surfaces/canvas-stage.json +30 -19
- package/src/surfaces/canvas-stage.ts +17 -16
- package/src/surfaces/cf-account-picker.ts +17 -18
- package/src/surfaces/collections-panel.json +615 -0
- package/src/surfaces/collections-panel.ts +168 -0
- package/src/surfaces/commandbar.json +241 -96
- package/src/surfaces/commandbar.ts +145 -105
- 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/empty-state.json +1 -1
- package/src/surfaces/empty-state.ts +7 -10
- package/src/surfaces/entry-editor.json +136 -0
- package/src/surfaces/entry-editor.ts +35 -11
- package/src/surfaces/entry-inspector.json +371 -0
- package/src/surfaces/entry-inspector.ts +143 -0
- 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/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.json +162 -14
- package/src/surfaces/inspector-dock.ts +59 -31
- package/src/surfaces/jump-bar.ts +5 -6
- package/src/surfaces/jxsuite-update.ts +16 -22
- package/src/surfaces/library-pane.json +670 -437
- package/src/surfaces/library-pane.ts +111 -77
- package/src/surfaces/logic-panel.ts +17 -30
- package/src/surfaces/logic-workspace.ts +13 -15
- package/src/surfaces/media-browser.json +62 -6
- package/src/surfaces/media-browser.ts +26 -11
- package/src/surfaces/media-field.json +1 -1
- package/src/surfaces/media-field.ts +4 -5
- package/src/surfaces/media-library.json +1586 -0
- package/src/surfaces/media-library.ts +282 -0
- package/src/surfaces/media-pane.ts +8 -7
- package/src/surfaces/media-pick-dialog.json +71 -0
- package/src/surfaces/media-pick-dialog.ts +132 -0
- package/src/surfaces/menu.ts +47 -23
- package/src/surfaces/navigator-dock.ts +11 -12
- package/src/surfaces/new-project.ts +27 -26
- package/src/surfaces/pane-context.json +144 -77
- package/src/surfaces/pane-context.ts +44 -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.json +12 -6
- package/src/surfaces/panel-deploy-checklist.ts +8 -7
- 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.json +72 -2
- package/src/surfaces/panel-page.ts +49 -25
- package/src/surfaces/panel-problems.ts +5 -7
- package/src/surfaces/panel-signals.json +1 -1
- package/src/surfaces/panel-signals.ts +25 -39
- package/src/surfaces/panel-stylebook-layers.json +71 -204
- package/src/surfaces/panel-stylebook-layers.ts +5 -29
- package/src/surfaces/preferences.json +120 -48
- package/src/surfaces/preferences.ts +29 -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-quick.json +428 -0
- package/src/surfaces/publish-quick.ts +165 -0
- package/src/surfaces/publish-workspace.json +2892 -0
- package/src/surfaces/publish-workspace.ts +391 -0
- package/src/surfaces/publish.ts +18 -18
- package/src/surfaces/push-plan.ts +7 -8
- package/src/surfaces/rail.json +1 -159
- package/src/surfaces/rail.ts +22 -79
- package/src/surfaces/reference-field.ts +11 -15
- package/src/surfaces/schema-builder.ts +16 -22
- package/src/surfaces/schema-form.json +10 -2
- package/src/surfaces/schema-form.ts +17 -25
- package/src/surfaces/secret-field.ts +9 -6
- package/src/surfaces/seo.json +1 -1
- package/src/surfaces/seo.ts +21 -15
- package/src/surfaces/settings-contexts.ts +9 -7
- package/src/surfaces/settings-contributed.json +5 -5
- package/src/surfaces/settings-contributed.ts +32 -12
- package/src/surfaces/settings-css-vars.json +44 -36
- package/src/surfaces/settings-css-vars.ts +82 -16
- package/src/surfaces/settings-defs.json +2 -2
- package/src/surfaces/settings-defs.ts +17 -21
- package/src/surfaces/settings-deploy.json +2 -15
- package/src/surfaces/settings-deploy.ts +9 -16
- package/src/surfaces/settings-dialog.json +51 -0
- package/src/surfaces/settings-dialog.ts +169 -0
- 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.json +3 -3
- package/src/surfaces/settings-overview.ts +14 -8
- package/src/surfaces/settings-packages.ts +8 -7
- package/src/surfaces/settings-pane.json +269 -46
- package/src/surfaces/settings-pane.ts +88 -36
- package/src/surfaces/settings-rawjson.ts +5 -6
- package/src/surfaces/shell.json +2 -1
- package/src/surfaces/shell.ts +1 -2
- package/src/surfaces/site-panel.json +1029 -0
- package/src/surfaces/site-panel.ts +233 -0
- package/src/surfaces/slash-menu.json +63 -21
- package/src/surfaces/slash-menu.ts +42 -9
- package/src/surfaces/statements.ts +13 -18
- package/src/surfaces/statusbar.ts +56 -29
- package/src/surfaces/style-panel.ts +18 -31
- package/src/surfaces/stylebook-chrome.ts +3 -5
- package/src/surfaces/styles-panel.json +735 -0
- package/src/surfaces/styles-panel.ts +195 -0
- package/src/surfaces/styles-variables.json +149 -0
- package/src/surfaces/styles-variables.ts +145 -0
- package/src/surfaces/tab-strip.json +4 -4
- package/src/surfaces/tab-strip.ts +14 -13
- package/src/surfaces/target-line.ts +6 -7
- package/src/surfaces/welcome.ts +6 -8
- package/src/surfaces/writing-banner.json +94 -0
- package/src/surfaces/writing-banner.ts +80 -0
- package/src/tabs/bare-repeaters.ts +101 -0
- 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 +99 -48
- package/src/tabs/transact.ts +98 -53
- package/src/types.ts +53 -43
- 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 +104 -56
- package/src/ui/formula-catalog.ts +239 -230
- package/src/ui/formula-chips.ts +33 -18
- package/src/ui/layers.ts +57 -31
- package/src/ui/media-picker.ts +300 -47
- package/src/ui/popover-surface.ts +20 -12
- package/src/ui/progress-modal.ts +13 -8
- package/src/ui/regions.ts +14 -12
- package/src/ui/schema-form.ts +372 -97
- 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 +29 -3
- package/src/utils/base64.ts +6 -4
- package/src/utils/edit-display.ts +366 -111
- 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/local-day.ts +18 -0
- 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 +14 -16
- package/src/workspace/session.ts +81 -50
- package/src/workspace/tab-workspace.ts +137 -0
- package/src/workspace/workspace-back.ts +189 -0
- package/src/workspace/workspace-home.ts +133 -0
- package/src/workspace/workspace-ids.ts +129 -0
- package/src/workspace/workspace-switch.ts +372 -0
- package/src/workspace/workspace.ts +165 -47
- package/styles/shell-frame.css +30 -7
- package/styles/shell-frame.json +15 -3
- package/dist/chunks/2020-va2wwra4.js +0 -4
- package/dist/chunks/adapter-f93pafd7.js +0 -4
- package/dist/chunks/cf-account-picker-af1h381v.js +0 -4
- package/dist/chunks/cf-settings-125tdm0w.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-ax2f1fnn.js +0 -4
- package/dist/chunks/content-source-108aqtk1.js +0 -4
- package/dist/chunks/convert-to-repeater-ry5rmppr.js +0 -4
- package/dist/chunks/dialog-mtm9fq5t.js +0 -4
- package/dist/chunks/editor-pfgdmkb0.js +0 -4
- package/dist/chunks/entry-commands-t0k1q0kx.js +0 -4
- package/dist/chunks/extension-sections-6mwh2hf8.js +0 -4
- package/dist/chunks/file-ops-meej5mqf.js +0 -4
- package/dist/chunks/files-44vp8a2s.js +0 -4
- package/dist/chunks/format-host-7q1petb9.js +0 -4
- package/dist/chunks/fs-events-h2mwnxaz.js +0 -4
- package/dist/chunks/git-panel-zngbymvd.js +0 -4
- package/dist/chunks/grid-view-sx9vynsp.js +0 -51
- package/dist/chunks/icons-p44xhjf0.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-qk3ycq87.js +0 -4
- package/dist/chunks/index-wkyfjeqz.js +0 -4
- package/dist/chunks/jsonMode-s8kt9dsj.js +0 -13
- package/dist/chunks/jx-validate-psgd7vsx.js +0 -4
- package/dist/chunks/layers-panel-1kq2jyfk.js +0 -4
- package/dist/chunks/layers-xd92fg8d.js +0 -4
- package/dist/chunks/listbox-s8fkmnq8.js +0 -4
- package/dist/chunks/lit-html-ac4cwwr4.js +0 -4
- package/dist/chunks/media-picker-0svzkdyb.js +0 -4
- package/dist/chunks/menu-37d07z9m.js +0 -4
- package/dist/chunks/menu-5c55ea3d.js +0 -4
- package/dist/chunks/monaco-binding-z6r70pdt.js +0 -4
- package/dist/chunks/monaco-buffer-fz6gq5y7.js +0 -4
- package/dist/chunks/monaco-setup-q4axkgj7.js +0 -4
- package/dist/chunks/notify-0xgtn8q1.js +0 -4
- package/dist/chunks/number-field-gw7sq8rn.js +0 -4
- package/dist/chunks/parse-897fvqah.js +0 -4
- package/dist/chunks/platform-v1qctbe6.js +0 -4
- package/dist/chunks/popover-8htra4er.js +0 -4
- package/dist/chunks/publish-panel-ym1fmgq5.js +0 -4
- package/dist/chunks/quick-search-a54e6t5n.js +0 -4
- package/dist/chunks/references-gmqp82fs.js +0 -4
- package/dist/chunks/right-panel-v7t9awbk.js +0 -4
- package/dist/chunks/section-registry-vhyf3zsr.js +0 -4
- package/dist/chunks/select-n3v7gwas.js +0 -4
- package/dist/chunks/split-pff8f3ze.js +0 -4
- package/dist/chunks/studio-0bhx5hz6.js +0 -5
- package/dist/chunks/studio-0k1ddnyy.js +0 -6
- package/dist/chunks/studio-1b04pd0j.js +0 -64
- package/dist/chunks/studio-4dwbj6gb.js +0 -5
- package/dist/chunks/studio-4tanh828.js +0 -5
- package/dist/chunks/studio-55h4mstj.js +0 -4
- package/dist/chunks/studio-5tnvjkz4.js +0 -5
- package/dist/chunks/studio-60dqgb0c.js +0 -5
- package/dist/chunks/studio-61dp09qg.js +0 -9
- package/dist/chunks/studio-63epcrj2.js +0 -5
- package/dist/chunks/studio-74k29dy9.js +0 -5
- package/dist/chunks/studio-7vg6jcd3.js +0 -5
- package/dist/chunks/studio-7zx31knw.js +0 -9
- package/dist/chunks/studio-8bxk97km.js +0 -5
- package/dist/chunks/studio-933e30n4.js +0 -5
- package/dist/chunks/studio-98wnwhbg.js +0 -5
- package/dist/chunks/studio-9mccjwjh.js +0 -14
- package/dist/chunks/studio-a2ke1e4t.js +0 -5
- package/dist/chunks/studio-e3a2a6v3.js +0 -4
- package/dist/chunks/studio-e81q1vb9.js +0 -5
- package/dist/chunks/studio-epgrmqqm.js +0 -5
- package/dist/chunks/studio-ery42sqr.js +0 -4
- package/dist/chunks/studio-g1shz58g.js +0 -5
- package/dist/chunks/studio-gf0fz03c.js +0 -5
- package/dist/chunks/studio-gjtpe62q.js +0 -6
- package/dist/chunks/studio-gkskhg7m.js +0 -5
- package/dist/chunks/studio-gx4dnjzd.js +0 -5
- package/dist/chunks/studio-j03zga3y.js +0 -9
- package/dist/chunks/studio-jhpxeckz.js +0 -5
- package/dist/chunks/studio-k01r7ykp.js +0 -5
- package/dist/chunks/studio-kk7h30ne.js +0 -7
- package/dist/chunks/studio-kt1zqney.js +0 -5
- package/dist/chunks/studio-m3cwhvye.js +0 -5
- package/dist/chunks/studio-mcayt6hz.js +0 -5
- package/dist/chunks/studio-myjcghv3.js +0 -5
- package/dist/chunks/studio-n8bxwc3y.js +0 -4
- package/dist/chunks/studio-ngm8gvpb.js +0 -5
- package/dist/chunks/studio-nj5a01jy.js +0 -928
- package/dist/chunks/studio-pcgz8heb.js +0 -5
- package/dist/chunks/studio-qcsq0t15.js +0 -5
- package/dist/chunks/studio-qkstvve9.js +0 -5
- package/dist/chunks/studio-qv1pwd3c.js +0 -5
- package/dist/chunks/studio-rc6dvxjb.js +0 -7
- package/dist/chunks/studio-s8dmmz66.js +0 -5
- package/dist/chunks/studio-sp5xzbj4.js +0 -6
- package/dist/chunks/studio-szsjbj0g.js +0 -5
- package/dist/chunks/studio-t1xzawhr.js +0 -16
- package/dist/chunks/studio-tdcprbqb.js +0 -5
- package/dist/chunks/studio-vrmcjf9g.js +0 -7
- package/dist/chunks/studio-vyc0b4he.js +0 -10
- package/dist/chunks/studio-w0cgf6jg.js +0 -5
- package/dist/chunks/studio-w3hskzqk.js +0 -5
- package/dist/chunks/studio-xgrgcdyh.js +0 -9
- package/dist/chunks/studio-xz2yxfcb.js +0 -5
- package/dist/chunks/studio-y6n42tgs.js +0 -5
- package/dist/chunks/studio-yb560vxr.js +0 -5
- package/dist/chunks/studio-yn9f8vtx.js +0 -5
- package/dist/chunks/studio-yw05w8f0.js +0 -7
- package/dist/chunks/studio-z16sgavc.js +0 -5
- package/dist/chunks/studio-zey7zsdw.js +0 -12
- package/dist/chunks/studio-zyqn40w4.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-2frah6h1.js +0 -14
- package/dist/chunks/workspace-zt81g1ms.js +0 -4
- package/dist/chunks/ws-client-n2bh4hkf.js +0 -4
- package/src/panels/frontmatter-panel.ts +0 -701
- package/src/panels/git-panel.ts +0 -1120
- package/src/surfaces/doc-header.json +0 -776
- package/src/surfaces/doc-header.ts +0 -231
- package/src/surfaces/git-panel.json +0 -1880
- package/src/surfaces/git-panel.ts +0 -272
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
|
+
/// <reference lib="dom.iterable" />
|
|
2
3
|
/**
|
|
3
4
|
* Inline-format.js — Inline formatting engine for contenteditable editing
|
|
4
5
|
*
|
|
@@ -22,6 +23,25 @@ const FORMAT_TAGS = new Set([
|
|
|
22
23
|
"span",
|
|
23
24
|
]);
|
|
24
25
|
|
|
26
|
+
/** Whether `node` is an element. Decided by node type, so it holds for a node of any realm. */
|
|
27
|
+
function isElementNode(node: Node): node is Element {
|
|
28
|
+
return node.nodeType === Node.ELEMENT_NODE;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Whether `node` is a text node (`CDATASection` has its own node type and is excluded). */
|
|
32
|
+
function isTextNode(node: Node): node is Text {
|
|
33
|
+
return node.nodeType === Node.TEXT_NODE;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** One edge-whitespace move {@link liftEdgeWhitespace} applies after its scan. */
|
|
37
|
+
interface EdgeWhitespaceLift {
|
|
38
|
+
type: "lift-leading" | "lift-trailing";
|
|
39
|
+
el: Element;
|
|
40
|
+
/** The wrapper's first (leading) or last (trailing) child, whose edge whitespace moves out. */
|
|
41
|
+
text: Text;
|
|
42
|
+
ws: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
25
45
|
/**
|
|
26
46
|
* Check whether `tag` is currently active on both ends of the selection. Walks from anchor and
|
|
27
47
|
* focus nodes up to editableRoot looking for the tag. Returns false if selection is outside
|
|
@@ -59,10 +79,7 @@ export function isTagActiveInSelection(tag: string, editableRoot: HTMLElement |
|
|
|
59
79
|
const hasTag = (node: Node | null) => {
|
|
60
80
|
let current = node;
|
|
61
81
|
while (current && current !== editableRoot) {
|
|
62
|
-
if (
|
|
63
|
-
current.nodeType === Node.ELEMENT_NODE &&
|
|
64
|
-
(current as Element).tagName.toLowerCase() === tag
|
|
65
|
-
) {
|
|
82
|
+
if (isElementNode(current) && current.tagName.toLowerCase() === tag) {
|
|
66
83
|
return true;
|
|
67
84
|
}
|
|
68
85
|
current = current.parentNode;
|
|
@@ -121,20 +138,11 @@ export function toggleInlineFormat(tag: string, editableRoot: HTMLElement | null
|
|
|
121
138
|
*/
|
|
122
139
|
function findIntersectingElements(tag: string, range: Range, root: HTMLElement) {
|
|
123
140
|
const matches: Element[] = [];
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
acceptNode(node: Node) {
|
|
130
|
-
if ((node as Element).tagName.toLowerCase() === tag && range.intersectsNode(node)) {
|
|
131
|
-
return NodeFilter.FILTER_ACCEPT;
|
|
132
|
-
}
|
|
133
|
-
return NodeFilter.FILTER_SKIP;
|
|
134
|
-
},
|
|
135
|
-
});
|
|
136
|
-
while (walker.nextNode()) {
|
|
137
|
-
matches.push(walker.currentNode as Element);
|
|
141
|
+
// Every descendant element, in document order: the same set a SHOW_ELEMENT tree walk visits.
|
|
142
|
+
for (const el of root.querySelectorAll("*")) {
|
|
143
|
+
if (el.tagName.toLowerCase() === tag && range.intersectsNode(el)) {
|
|
144
|
+
matches.push(el);
|
|
145
|
+
}
|
|
138
146
|
}
|
|
139
147
|
return matches;
|
|
140
148
|
}
|
|
@@ -343,21 +351,19 @@ export function normalizeInlineContent(root: HTMLElement | null) {
|
|
|
343
351
|
*/
|
|
344
352
|
function mergeAdjacentSiblings(root: HTMLElement) {
|
|
345
353
|
let changed = false;
|
|
346
|
-
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
|
347
354
|
const toMerge: [Element, Element][] = [];
|
|
348
355
|
|
|
349
356
|
// Collect pairs first to avoid mutation during walk
|
|
350
|
-
|
|
351
|
-
const el = walker.currentNode as Element;
|
|
357
|
+
for (const el of root.querySelectorAll("*")) {
|
|
352
358
|
const next = el.nextSibling;
|
|
353
359
|
if (
|
|
354
360
|
next &&
|
|
355
|
-
next
|
|
356
|
-
|
|
361
|
+
isElementNode(next) &&
|
|
362
|
+
next.tagName === el.tagName &&
|
|
357
363
|
FORMAT_TAGS.has(el.tagName.toLowerCase()) &&
|
|
358
|
-
attributesMatch(el, next
|
|
364
|
+
attributesMatch(el, next)
|
|
359
365
|
) {
|
|
360
|
-
toMerge.push([el, next
|
|
366
|
+
toMerge.push([el, next]);
|
|
361
367
|
}
|
|
362
368
|
}
|
|
363
369
|
|
|
@@ -383,27 +389,31 @@ function mergeAdjacentSiblings(root: HTMLElement) {
|
|
|
383
389
|
*/
|
|
384
390
|
function collapseRedundantNesting(root: HTMLElement) {
|
|
385
391
|
let changed = false;
|
|
386
|
-
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
|
387
392
|
const toCollapse: Element[] = [];
|
|
388
393
|
|
|
389
|
-
|
|
390
|
-
const el = walker.currentNode as Element;
|
|
394
|
+
for (const el of root.querySelectorAll("*")) {
|
|
391
395
|
if (!FORMAT_TAGS.has(el.tagName.toLowerCase())) {
|
|
392
396
|
continue;
|
|
393
397
|
}
|
|
394
398
|
// Check if only child is an element with the same tag
|
|
399
|
+
const only = el.firstChild;
|
|
395
400
|
if (
|
|
396
401
|
el.childNodes.length === 1 &&
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
402
|
+
only !== null &&
|
|
403
|
+
isElementNode(only) &&
|
|
404
|
+
only.tagName === el.tagName
|
|
400
405
|
) {
|
|
401
406
|
toCollapse.push(el);
|
|
402
407
|
}
|
|
403
408
|
}
|
|
404
409
|
|
|
405
410
|
for (const el of toCollapse) {
|
|
406
|
-
const inner = el.firstChild
|
|
411
|
+
const inner = el.firstChild;
|
|
412
|
+
if (inner === null) {
|
|
413
|
+
/* Three or more nested identical wrappers: collapsing the outer pair moved this wrapper's only
|
|
414
|
+
child out, leaving it empty. That has always failed here, and is kept rather than changed. */
|
|
415
|
+
throw new TypeError("collapseRedundantNesting: an earlier collapse emptied this wrapper");
|
|
416
|
+
}
|
|
407
417
|
// Replace outer with inner's children
|
|
408
418
|
while (inner.firstChild) {
|
|
409
419
|
inner.before(inner.firstChild);
|
|
@@ -422,11 +432,9 @@ function collapseRedundantNesting(root: HTMLElement) {
|
|
|
422
432
|
*/
|
|
423
433
|
function removeEmptyInlines(root: HTMLElement) {
|
|
424
434
|
let changed = false;
|
|
425
|
-
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
|
426
435
|
const toRemove: Element[] = [];
|
|
427
436
|
|
|
428
|
-
|
|
429
|
-
const el = walker.currentNode as Element;
|
|
437
|
+
for (const el of root.querySelectorAll("*")) {
|
|
430
438
|
if (!FORMAT_TAGS.has(el.tagName.toLowerCase())) {
|
|
431
439
|
continue;
|
|
432
440
|
}
|
|
@@ -451,12 +459,9 @@ function removeEmptyInlines(root: HTMLElement) {
|
|
|
451
459
|
*/
|
|
452
460
|
function liftEdgeWhitespace(root: HTMLElement) {
|
|
453
461
|
let changed = false;
|
|
454
|
-
const
|
|
455
|
-
/** @type {{ type: string; el: Element; ws: string }[]} */
|
|
456
|
-
const ops = [];
|
|
462
|
+
const ops: EdgeWhitespaceLift[] = [];
|
|
457
463
|
|
|
458
|
-
|
|
459
|
-
const el = walker.currentNode as Element;
|
|
464
|
+
for (const el of root.querySelectorAll("*")) {
|
|
460
465
|
if (!FORMAT_TAGS.has(el.tagName.toLowerCase())) {
|
|
461
466
|
continue;
|
|
462
467
|
}
|
|
@@ -465,36 +470,36 @@ function liftEdgeWhitespace(root: HTMLElement) {
|
|
|
465
470
|
}
|
|
466
471
|
|
|
467
472
|
const first = el.firstChild;
|
|
468
|
-
if (first && first
|
|
469
|
-
const text = first.textContent
|
|
473
|
+
if (first && isTextNode(first)) {
|
|
474
|
+
const text = first.textContent;
|
|
470
475
|
const m = text.match(/^(\s+)/);
|
|
471
476
|
if (m && text.length > m[1]!.length) {
|
|
472
|
-
ops.push({ el, type: "lift-leading", ws: m[1]! });
|
|
477
|
+
ops.push({ el, text: first, type: "lift-leading", ws: m[1]! });
|
|
473
478
|
}
|
|
474
479
|
}
|
|
475
480
|
|
|
476
481
|
const last = el.lastChild;
|
|
477
|
-
if (last && last
|
|
478
|
-
const text = last.textContent
|
|
482
|
+
if (last && isTextNode(last) && last !== first) {
|
|
483
|
+
const text = last.textContent;
|
|
479
484
|
const m = text.match(/(\s+)$/);
|
|
480
485
|
if (m && text.length > m[1]!.length) {
|
|
481
|
-
ops.push({ el, type: "lift-trailing", ws: m[1]! });
|
|
486
|
+
ops.push({ el, text: last, type: "lift-trailing", ws: m[1]! });
|
|
482
487
|
}
|
|
483
488
|
}
|
|
484
489
|
}
|
|
485
490
|
|
|
491
|
+
/* Each recorded text node is still its wrapper's edge child when its move runs: a move only edits
|
|
492
|
+
a text node's data and inserts a sibling OUTSIDE its own wrapper, and a wrapper whose edge child
|
|
493
|
+
is an element (the only place a nested move could insert) never recorded a move on that edge. */
|
|
486
494
|
for (const op of ops) {
|
|
487
495
|
if (op.type === "lift-leading") {
|
|
488
|
-
|
|
489
|
-
firstChild.textContent = (firstChild.textContent ?? "").slice(op.ws.length);
|
|
496
|
+
op.text.textContent = op.text.textContent.slice(op.ws.length);
|
|
490
497
|
op.el.parentNode?.insertBefore(document.createTextNode(op.ws), op.el);
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
const lastChild = op.el.lastChild as Text;
|
|
494
|
-
lastChild.textContent = (lastChild.textContent ?? "").slice(0, -op.ws.length);
|
|
498
|
+
} else {
|
|
499
|
+
op.text.textContent = op.text.textContent.slice(0, -op.ws.length);
|
|
495
500
|
op.el.parentNode?.insertBefore(document.createTextNode(op.ws), op.el.nextSibling);
|
|
496
|
-
changed = true;
|
|
497
501
|
}
|
|
502
|
+
changed = true;
|
|
498
503
|
}
|
|
499
504
|
return changed;
|
|
500
505
|
}
|
|
@@ -508,11 +513,9 @@ function liftEdgeWhitespace(root: HTMLElement) {
|
|
|
508
513
|
*/
|
|
509
514
|
function unwrapBareSpans(root: HTMLElement) {
|
|
510
515
|
let changed = false;
|
|
511
|
-
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
|
512
516
|
const toUnwrap: Element[] = [];
|
|
513
517
|
|
|
514
|
-
|
|
515
|
-
const el = walker.currentNode as Element;
|
|
518
|
+
for (const el of root.querySelectorAll("*")) {
|
|
516
519
|
if (el.tagName.toLowerCase() !== "span") {
|
|
517
520
|
continue;
|
|
518
521
|
}
|
|
@@ -8,32 +8,57 @@
|
|
|
8
8
|
* it here (Phase 4b-2).
|
|
9
9
|
*
|
|
10
10
|
* `document.execCommand` is uncoverable under happy-dom (no implementation), so it is wrapped in a
|
|
11
|
-
* one-line shim {@link
|
|
12
|
-
* assert at the stub level (documented as stub-level, not behavioral).
|
|
11
|
+
* one-line shim {@link execEditingCommand} that the branch logic calls; tests stub
|
|
12
|
+
* `document.execCommand` and assert at the stub level (documented as stub-level, not behavioral).
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { normalizeInlineContent } from "./inline-format";
|
|
16
16
|
|
|
17
|
-
/**
|
|
18
|
-
|
|
17
|
+
/**
|
|
18
|
+
* The one uncoverable call, isolated so the surrounding branch logic stays unit-testable, and the
|
|
19
|
+
* one place Studio reaches `document.execCommand`. It is deprecated, and NOT kept for the native
|
|
20
|
+
* undo stack: Studio owns history (`edit.undo` is forwarded out of the frame and a `historyUndo`
|
|
21
|
+
* `beforeinput` is rejected, studio.md §8.2.1). It is kept because it is the only script entry into
|
|
22
|
+
* the browser's editing engine, which a Range rewrite would not reproduce: `insertText` rebalances
|
|
23
|
+
* whitespace into ` ` runs (and back) around the caret, and `createLink` splits the anchor at
|
|
24
|
+
* inline-formatting boundaries it only partly covers.
|
|
25
|
+
*/
|
|
26
|
+
export const execEditingCommand = (cmd: string, val?: string): boolean =>
|
|
27
|
+
// oxlint-disable-next-line typescript/no-deprecated -- no successor API exists: execCommand is the only script entry into the browser's editing engine (whitespace rebalancing, anchor splitting), see the doc comment above
|
|
28
|
+
document.execCommand(cmd, false, val);
|
|
29
|
+
|
|
30
|
+
/** The link the selection sits in, as the format toolbar's Link field shows it. */
|
|
31
|
+
export interface LinkState {
|
|
32
|
+
/** Whether the selection anchor is inside an `<a>`. */
|
|
33
|
+
active: boolean;
|
|
34
|
+
/** The author-entered URL of that `<a>`, or null when there is none. */
|
|
35
|
+
href: string | null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Whether `node` is an `<a>` element. Decided by node type and name rather than `instanceof`, so it
|
|
40
|
+
* holds for nodes of another realm; for an element, `nodeName` is its tag name.
|
|
41
|
+
*/
|
|
42
|
+
function isAnchorNode(node: Node): node is HTMLAnchorElement | SVGAElement {
|
|
43
|
+
return node.nodeType === Node.ELEMENT_NODE && node.nodeName.toLowerCase() === "a";
|
|
44
|
+
}
|
|
19
45
|
|
|
20
46
|
/**
|
|
21
47
|
* Read the link state of the current selection relative to `root`: walk the selection's anchor node
|
|
22
48
|
* up to `root` looking for an `<a>`. Returns the author-entered `href` attribute (NOT the resolved
|
|
23
49
|
* `.href` property), so relative/templated URLs round-trip unchanged.
|
|
24
50
|
*/
|
|
25
|
-
export function linkStateForSelection(root: HTMLElement):
|
|
51
|
+
export function linkStateForSelection(root: HTMLElement): LinkState {
|
|
26
52
|
const sel = window.getSelection();
|
|
27
53
|
if (!sel || !sel.rangeCount) {
|
|
28
54
|
return { active: false, href: null };
|
|
29
55
|
}
|
|
30
56
|
let node: Node | null = sel.anchorNode;
|
|
31
57
|
while (node && node !== root) {
|
|
32
|
-
if (
|
|
58
|
+
if (isAnchorNode(node)) {
|
|
33
59
|
// Design/edit renders anchors de-linked, with the URL on `data-jx-href` — so the toolbar's
|
|
34
60
|
// Link field must read that first or it shows an empty URL for every existing link.
|
|
35
|
-
|
|
36
|
-
return { active: true, href: el.dataset.jxHref ?? el.getAttribute("href") };
|
|
61
|
+
return { active: true, href: node.dataset.jxHref ?? node.getAttribute("href") };
|
|
37
62
|
}
|
|
38
63
|
node = node.parentNode;
|
|
39
64
|
}
|
|
@@ -44,17 +69,17 @@ export function linkStateForSelection(root: HTMLElement): { active: boolean; hre
|
|
|
44
69
|
* Find the `<a>` that contains the selection anchor (up to `root`), if any.
|
|
45
70
|
*
|
|
46
71
|
* @param {HTMLElement} root
|
|
47
|
-
* @returns {HTMLAnchorElement | null}
|
|
72
|
+
* @returns {HTMLAnchorElement | SVGAElement | null}
|
|
48
73
|
*/
|
|
49
|
-
function anchorInSelection(root: HTMLElement): HTMLAnchorElement | null {
|
|
74
|
+
function anchorInSelection(root: HTMLElement): HTMLAnchorElement | SVGAElement | null {
|
|
50
75
|
const sel = window.getSelection();
|
|
51
76
|
if (!sel || !sel.rangeCount) {
|
|
52
77
|
return null;
|
|
53
78
|
}
|
|
54
79
|
let node: Node | null = sel.anchorNode;
|
|
55
80
|
while (node && node !== root) {
|
|
56
|
-
if (
|
|
57
|
-
return node
|
|
81
|
+
if (isAnchorNode(node)) {
|
|
82
|
+
return node;
|
|
58
83
|
}
|
|
59
84
|
node = node.parentNode;
|
|
60
85
|
}
|
|
@@ -80,13 +105,13 @@ export function applyLink(root: HTMLElement, href: string | null): void {
|
|
|
80
105
|
existing.replaceWith(frag);
|
|
81
106
|
}
|
|
82
107
|
} else if (href) {
|
|
83
|
-
|
|
108
|
+
execEditingCommand("createLink", href);
|
|
84
109
|
}
|
|
85
110
|
normalizeInlineContent(root);
|
|
86
111
|
}
|
|
87
112
|
|
|
88
|
-
/** Insert a `${token}` template expression at the caret inside `root
|
|
113
|
+
/** Insert a `${token}` template expression at the caret inside `root`, through the editing engine. */
|
|
89
114
|
export function insertTemplateToken(root: HTMLElement, token: string): void {
|
|
90
115
|
root.focus();
|
|
91
|
-
|
|
116
|
+
execEditingCommand("insertText", `\${${token}}`);
|
|
92
117
|
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inserting a component has one meaning everywhere (`specs/studio.md` §5.7, §9.1.3).
|
|
3
|
+
*
|
|
4
|
+
* A component instance is only a usable element in a document that imports it: the canvas drop did
|
|
5
|
+
* that, and the Insert panel's click, the slash menu and the canvas `+` did not, so a component
|
|
6
|
+
* clicked in rendered as an element the page could not resolve. This module is the one rule the
|
|
7
|
+
* four doors share — the instance comes from `buildComponentInstance`, and the import from the one
|
|
8
|
+
* `$elements` service, `files/elements.ts`'s `enableElement`.
|
|
9
|
+
*
|
|
10
|
+
* @docs studio/design/components
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { isString } from "@jxsuite/schema/guards";
|
|
14
|
+
import { buildComponentInstance, componentRegistry } from "../files/components";
|
|
15
|
+
import { enableElement } from "../files/elements";
|
|
16
|
+
import { mutateUpdateProperty } from "../tabs/transact";
|
|
17
|
+
import type { JxNodeValue } from "../tabs/transact";
|
|
18
|
+
import type { ElementsEntry } from "../files/elements";
|
|
19
|
+
import type { JxMutableNode } from "@jxsuite/schema/types";
|
|
20
|
+
import type { Tab } from "../tabs/tab";
|
|
21
|
+
import type { SlashCommand } from "./inline-edit";
|
|
22
|
+
|
|
23
|
+
/** The slash menu's group heading for the project's components. */
|
|
24
|
+
export const COMPONENTS_GROUP = "Components";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Import the component a node is an instance of into `tab`'s document, when it is one and is not
|
|
28
|
+
* imported yet. A node whose tag has no hyphen is an HTML element and is left alone, and a
|
|
29
|
+
* component the registry cannot name (an npm entry with no package, a local one with no path)
|
|
30
|
+
* changes nothing, so a document that had no `$elements` is not handed an empty one.
|
|
31
|
+
*
|
|
32
|
+
* A computed tag (`{ $expression }`) names no registered component, so it is left alone too.
|
|
33
|
+
*
|
|
34
|
+
* This is a MUTATION: call it inside the transaction that inserts the instance, so the instance and
|
|
35
|
+
* its import are one undo step. As a transaction of its own after the insert, the first ⌘Z took
|
|
36
|
+
* back only the import and left a document using a component it no longer imported, which saves as
|
|
37
|
+
* an instance the page cannot resolve.
|
|
38
|
+
*
|
|
39
|
+
* @param tab The document the node was inserted into, inside a `transactDoc`.
|
|
40
|
+
* @param tagName The inserted node's tag.
|
|
41
|
+
*/
|
|
42
|
+
export function mutateImportComponent(tab: Tab, tagName: JxMutableNode["tagName"]): void {
|
|
43
|
+
const after = elementsImporting(tab, tagName);
|
|
44
|
+
if (after) {
|
|
45
|
+
/* Through the recorded mutator, not a bare assignment: a transaction that records ops is
|
|
46
|
+
undone by replaying their inverses, so an unrecorded write beside the insert would survive
|
|
47
|
+
the ⌘Z that took the instance back, and never reach a co-editor.
|
|
48
|
+
SAFETY: `$elements` entries are JSON — module specifiers, `{ $ref }` imports and inline
|
|
49
|
+
element definitions — which is what a node key holds. */
|
|
50
|
+
mutateUpdateProperty(tab, [], "$elements", after as JxNodeValue);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** The document's `$elements` with the component imported, or null when nothing would change. */
|
|
55
|
+
function elementsImporting(tab: Tab, tagName: JxMutableNode["tagName"]): ElementsEntry[] | null {
|
|
56
|
+
if (!isString(tagName) || !tagName.includes("-")) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
const comp = componentRegistry.find((entry) => entry.tagName === tagName);
|
|
60
|
+
if (!comp) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
/* SAFETY: `$elements` holds module specifiers and `{ $ref }` imports; the document type and
|
|
64
|
+
files/elements.ts spell an inline entry as JxMutableNode and JxElement respectively, two editor
|
|
65
|
+
views of the same JSON object that enableElement only compares by `$ref`. */
|
|
66
|
+
const before = (tab.doc.document.$elements ?? []) as ElementsEntry[];
|
|
67
|
+
const after = enableElement(before, comp, tab.documentPath ?? null);
|
|
68
|
+
return after.length === before.length ? null : after;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** A fresh instance of a registered component, or null for a tag the registry does not know. */
|
|
72
|
+
export function componentInstance(tagName: string): JxMutableNode | null {
|
|
73
|
+
const comp = componentRegistry.find((entry) => entry.tagName === tagName);
|
|
74
|
+
return comp ? buildComponentInstance(comp) : null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Every registered component as a slash-menu offer, under the Components heading: the project's
|
|
79
|
+
* own, described by their definition file, and the ones installed packages provide, described by
|
|
80
|
+
* their package. A package component needs no prior enabling, because inserting one imports its
|
|
81
|
+
* package ({@link mutateImportComponent}), exactly as the canvas drop does.
|
|
82
|
+
*/
|
|
83
|
+
export function componentSlashCommands(): SlashCommand[] {
|
|
84
|
+
return componentRegistry.map((comp) => ({
|
|
85
|
+
component: true,
|
|
86
|
+
description: (comp.source === "npm" ? comp.package : comp.path) ?? "",
|
|
87
|
+
group: COMPONENTS_GROUP,
|
|
88
|
+
label: `<${comp.tagName}>`,
|
|
89
|
+
tag: comp.tagName,
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
@@ -7,11 +7,13 @@
|
|
|
7
7
|
* name via `setInsertZoneClickHandler(runInsertZoneAction)` in studio.ts.
|
|
8
8
|
*
|
|
9
9
|
* The cross-origin insertion "+" (drawn by the host from posted zones) runs the parent-realm
|
|
10
|
-
* slash-menu → mutateInsertNode flow on click. The
|
|
11
|
-
*
|
|
10
|
+
* slash-menu → mutateInsertNode flow on click. The menu offers the HTML elements and, under a
|
|
11
|
+
* Components heading, the project's components. The host captured the zone (parentPath + index);
|
|
12
|
+
* the new node is selected at its inserted path. Salvaged from the orphaned insertion-helper.ts.
|
|
12
13
|
*/
|
|
13
14
|
|
|
14
15
|
import { showSlashMenu } from "./slash-menu";
|
|
16
|
+
import { componentInstance, mutateImportComponent } from "./insert-component";
|
|
15
17
|
import { defaultDef } from "../panels/shared";
|
|
16
18
|
import { mutateInsertNode, transactDoc } from "../tabs/transact";
|
|
17
19
|
import { activeTab } from "../workspace/workspace";
|
|
@@ -21,12 +23,19 @@ import type { JxPath } from "../state";
|
|
|
21
23
|
export function runInsertZoneAction(btn: HTMLElement, zone: InsertZone): void {
|
|
22
24
|
showSlashMenu(btn, "", {
|
|
23
25
|
onSelect: (cmd) => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
/* A pick from the Components group inserts an instance and imports the component, as a drop
|
|
27
|
+
of the same component does (§5.7); every other pick inserts the element's default. */
|
|
28
|
+
const instance = cmd.component === true ? componentInstance(cmd.tag) : null;
|
|
29
|
+
const def = instance ?? defaultDef(cmd.tag);
|
|
30
|
+
const insertPath: JxPath = zone.insertParentPath;
|
|
26
31
|
const idx = zone.index;
|
|
27
32
|
const newPath = [...insertPath, "children", idx];
|
|
28
|
-
|
|
33
|
+
const tab = activeTab.value;
|
|
34
|
+
transactDoc(tab, (t) => {
|
|
29
35
|
mutateInsertNode(t, insertPath, idx, def);
|
|
36
|
+
if (instance) {
|
|
37
|
+
mutateImportComponent(t, instance.tagName);
|
|
38
|
+
}
|
|
30
39
|
t.session.selection = [newPath];
|
|
31
40
|
});
|
|
32
41
|
},
|
package/src/editor/merge-tags.ts
CHANGED
|
@@ -9,8 +9,10 @@
|
|
|
9
9
|
* Pure and DOM-free: callers pass the data in, this returns plain descriptors.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import { isNonNullObject, isString } from "@jxsuite/schema/guards";
|
|
12
13
|
import { defCategory } from "../panels/signals-panel";
|
|
13
14
|
import { dataTypeLabel, unwrapSignal } from "../panels/data-explorer";
|
|
15
|
+
import type { JsonPrimitive, JxStateDefinition } from "@jxsuite/schema/types";
|
|
14
16
|
|
|
15
17
|
export interface MergeTag {
|
|
16
18
|
/** Insertion token placed between `${` and `}`, e.g. `state.user.name`, `item.title`, `index`. */
|
|
@@ -23,20 +25,50 @@ export interface MergeTag {
|
|
|
23
25
|
category: string;
|
|
24
26
|
}
|
|
25
27
|
|
|
28
|
+
/**
|
|
29
|
+
* A value in a live render scope, as far as the merge-tag walk reads it: document data, a handler,
|
|
30
|
+
* a pending (`undefined`) entry, or an object — a plain record, a fetched payload, a Vue ref —
|
|
31
|
+
* whose own keys hold further scope values.
|
|
32
|
+
*/
|
|
33
|
+
export type ScopeValue =
|
|
34
|
+
| JsonPrimitive
|
|
35
|
+
| undefined
|
|
36
|
+
| bigint
|
|
37
|
+
| symbol
|
|
38
|
+
| ((...args: never[]) => void)
|
|
39
|
+
| ScopeValue[]
|
|
40
|
+
| ScopeRecord;
|
|
41
|
+
|
|
42
|
+
/** A render scope, or any object inside one, read key by key. */
|
|
43
|
+
export interface ScopeRecord {
|
|
44
|
+
readonly [key: string]: ScopeValue;
|
|
45
|
+
}
|
|
46
|
+
|
|
26
47
|
/** Levels of nesting walked beneath each root name. */
|
|
27
48
|
const DEPTH_CAP = 3;
|
|
28
49
|
/** Maximum object keys enumerated per level (mirrors the data-explorer tree cap). */
|
|
29
50
|
const BREADTH_CAP = 30;
|
|
30
51
|
|
|
52
|
+
/** Whether a scope value is an object read by key: non-null, not an array, not a function. */
|
|
53
|
+
function isScopeRecord(value: ScopeValue): value is ScopeRecord {
|
|
54
|
+
return isNonNullObject(value) && !Array.isArray(value);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** The value behind a Vue ref, or the value itself. */
|
|
58
|
+
function unwrapScopeValue(value: ScopeValue): ScopeValue {
|
|
59
|
+
/* SAFETY: unwrapSignal returns its argument unchanged, or a ref's `.value`; a ref is a scope record,
|
|
60
|
+
so its `.value` member is itself a scope value. */
|
|
61
|
+
return unwrapSignal(value) as ScopeValue;
|
|
62
|
+
}
|
|
63
|
+
|
|
31
64
|
/** Type label plus a short value preview for primitives. */
|
|
32
|
-
function previewHint(value:
|
|
33
|
-
const v =
|
|
65
|
+
function previewHint(value: ScopeValue): string {
|
|
66
|
+
const v = unwrapScopeValue(value);
|
|
34
67
|
const typeLabel = dataTypeLabel(v);
|
|
35
|
-
if (v === null || v === undefined ||
|
|
68
|
+
if (v === null || v === undefined || isNonNullObject(v)) {
|
|
36
69
|
return typeLabel; // Null / pending / Array(n) / {n}
|
|
37
70
|
}
|
|
38
|
-
const text =
|
|
39
|
-
typeof v === "string" ? (v.length > 24 ? `"${v.slice(0, 24)}…"` : `"${v}"`) : String(v);
|
|
71
|
+
const text = isString(v) ? (v.length > 24 ? `"${v.slice(0, 24)}…"` : `"${v}"`) : String(v);
|
|
40
72
|
return `${typeLabel} · ${text}`;
|
|
41
73
|
}
|
|
42
74
|
|
|
@@ -44,25 +76,25 @@ function previewHint(value: unknown): string {
|
|
|
44
76
|
* Walk a resolved value, appending nested-path tags to `out`. Arrays contribute a `.length` tag and
|
|
45
77
|
* stop (index access is context-dependent); plain objects recurse up to the depth/breadth caps.
|
|
46
78
|
*/
|
|
47
|
-
function walk(value:
|
|
79
|
+
function walk(value: ScopeValue, prefix: string, category: string, depth: number, out: MergeTag[]) {
|
|
48
80
|
if (depth >= DEPTH_CAP) {
|
|
49
81
|
return;
|
|
50
82
|
}
|
|
51
|
-
const v =
|
|
52
|
-
if (v === null || v === undefined || typeof v !== "object") {
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
83
|
+
const v = unwrapScopeValue(value);
|
|
55
84
|
if (Array.isArray(v)) {
|
|
56
85
|
const token = `${prefix}.length`;
|
|
57
86
|
out.push({ category, hint: `number · ${v.length}`, label: token, token });
|
|
58
87
|
return;
|
|
59
88
|
}
|
|
89
|
+
if (!isScopeRecord(v)) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
60
92
|
const keys = Object.keys(v).slice(0, BREADTH_CAP);
|
|
61
93
|
for (const key of keys) {
|
|
62
94
|
if (key.startsWith("$")) {
|
|
63
95
|
continue; // Internal keys ($children, $ref, reactive plumbing) are not author-facing
|
|
64
96
|
}
|
|
65
|
-
const childVal =
|
|
97
|
+
const childVal = v[key];
|
|
66
98
|
const childPrefix = `${prefix}.${key}`;
|
|
67
99
|
out.push({ category, hint: previewHint(childVal), label: childPrefix, token: childPrefix });
|
|
68
100
|
walk(childVal, childPrefix, category, depth + 1, out);
|
|
@@ -80,9 +112,9 @@ function walk(value: unknown, prefix: string, category: string, depth: number, o
|
|
|
80
112
|
* carries a `$map` (repeater) context, `item` / `item.*` / `index` tags are appended.
|
|
81
113
|
*/
|
|
82
114
|
export function buildMergeTags(
|
|
83
|
-
state: Record<string,
|
|
84
|
-
scope:
|
|
85
|
-
localScope:
|
|
115
|
+
state: Readonly<Record<string, JxStateDefinition>> | null | undefined,
|
|
116
|
+
scope: ScopeRecord | null | undefined,
|
|
117
|
+
localScope: ScopeRecord | null = null,
|
|
86
118
|
): MergeTag[] {
|
|
87
119
|
const out: MergeTag[] = [];
|
|
88
120
|
const defs = state ?? {};
|
|
@@ -103,13 +135,20 @@ export function buildMergeTags(
|
|
|
103
135
|
}
|
|
104
136
|
|
|
105
137
|
if (localScope) {
|
|
106
|
-
const map =
|
|
107
|
-
if (map
|
|
108
|
-
|
|
109
|
-
|
|
138
|
+
const map = unwrapScopeValue(localScope.$map);
|
|
139
|
+
if (isNonNullObject(map)) {
|
|
140
|
+
// An array `$map` has no `item` / `index` members, so it reads as an empty row.
|
|
141
|
+
const row = isScopeRecord(map) ? map : undefined;
|
|
142
|
+
out.push({
|
|
143
|
+
category: "repeater",
|
|
144
|
+
hint: previewHint(row?.item),
|
|
145
|
+
label: "item",
|
|
146
|
+
token: "item",
|
|
147
|
+
});
|
|
148
|
+
walk(row?.item, "item", "repeater", 0, out);
|
|
110
149
|
out.push({
|
|
111
150
|
category: "repeater",
|
|
112
|
-
hint: previewHint(
|
|
151
|
+
hint: previewHint(row?.index),
|
|
113
152
|
label: "index",
|
|
114
153
|
token: "index",
|
|
115
154
|
});
|