@jxsuite/studio 6.1.1 → 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-va2wwra4.js → 2020-f2gkpy8d.js} +3 -3
- 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-2veqmnhr.js → index-zpjmzqfk.js} +3 -3
- package/dist/chunks/{javascript-8nbvs12s.js → javascript-m54mnwp6.js} +3 -3
- package/dist/chunks/{jsonMode-s8kt9dsj.js → jsonMode-w15cmrcm.js} +8 -8
- 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-1q1sh2ax.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-h46vtzk8.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-rv11kfwa.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-8grwxtqk.js → studio-90pq9km1.js} +4 -4
- package/dist/chunks/studio-924p1tm1.js +6 -0
- package/dist/chunks/{studio-pre0skq6.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-vrmcjf9g.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-wszjyh0j.js → studio-tq0rtfwj.js} +4 -4
- package/dist/chunks/{studio-kggey1jt.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-zey7zsdw.js → studio-y64hrt8p.js} +7 -7
- 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-2frah6h1.js → tsMode-sf49ee9x.js} +7 -7
- 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 +97 -97
- package/package.json +6 -6
- 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 +62 -41
- package/src/canvas/canvas-surface.ts +5 -3
- package/src/canvas/canvas-utils.ts +90 -49
- 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 +135 -96
- 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-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 +12 -16
- package/src/canvas/iframe-render.ts +36 -34
- 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/keymap.ts +47 -43
- package/src/commands/levels.ts +3 -3
- package/src/commands/live-context.ts +7 -7
- 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 +32 -20
- 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 +3 -0
- 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 +52 -21
- 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 +218 -205
- 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 +129 -117
- 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 +25 -75
- 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 +19 -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.ts +13 -13
- 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/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 +73 -73
- 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 +40 -36
- 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/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-t6b6qe31.js +0 -5
- package/dist/chunks/studio-tdcprbqb.js +0 -5
- 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-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/workspace-zt81g1ms.js +0 -4
- package/dist/chunks/ws-client-n2bh4hkf.js +0 -4
|
@@ -27,7 +27,15 @@ import { collectionInfo } from "../grid/sources/content-source";
|
|
|
27
27
|
import { projectState } from "../store";
|
|
28
28
|
import { findContentTypeSchema } from "../utils/studio-utils";
|
|
29
29
|
import type { ContentSectionEntry } from "../types";
|
|
30
|
-
import
|
|
30
|
+
import { isNonNullObject, isString } from "@jxsuite/schema/guards";
|
|
31
|
+
import type {
|
|
32
|
+
ContentTypeSchema,
|
|
33
|
+
ContentTypeSchemaField,
|
|
34
|
+
ContentTypeSchemaValue,
|
|
35
|
+
JsonObject,
|
|
36
|
+
JsonValue,
|
|
37
|
+
} from "@jxsuite/schema/types";
|
|
38
|
+
import type { EntryFields } from "./entry-fields";
|
|
31
39
|
|
|
32
40
|
// ─── Collections ─────────────────────────────────────────────────────────────
|
|
33
41
|
|
|
@@ -44,7 +52,7 @@ export interface EntryCollection {
|
|
|
44
52
|
|
|
45
53
|
/** Every content type the project declares, in declaration order. */
|
|
46
54
|
export function collectionNames(): string[] {
|
|
47
|
-
return Object.keys(
|
|
55
|
+
return Object.keys(projectState?.projectConfig?.content ?? {});
|
|
48
56
|
}
|
|
49
57
|
|
|
50
58
|
/**
|
|
@@ -94,12 +102,13 @@ export function collectionOfPath(path: string | null): EntryCollection | null {
|
|
|
94
102
|
// ─── Seeding a new entry ─────────────────────────────────────────────────────
|
|
95
103
|
|
|
96
104
|
/** Deep copy of a schema `default`, so two entries seeded from one schema never share an object. */
|
|
97
|
-
function cloneDefault(value:
|
|
98
|
-
if (value === null ||
|
|
105
|
+
function cloneDefault(value: ContentTypeSchemaValue): JsonValue {
|
|
106
|
+
if (value === null || !isNonNullObject(value)) {
|
|
99
107
|
return value;
|
|
100
108
|
}
|
|
109
|
+
// SAFETY: `JSON.parse` of what `JSON.stringify` just wrote is JSON by construction.
|
|
101
110
|
// oxlint-disable-next-line unicorn/prefer-structured-clone
|
|
102
|
-
return JSON.parse(JSON.stringify(value)) as
|
|
111
|
+
return JSON.parse(JSON.stringify(value)) as JsonValue;
|
|
103
112
|
}
|
|
104
113
|
|
|
105
114
|
/**
|
|
@@ -109,8 +118,8 @@ function cloneDefault(value: unknown): unknown {
|
|
|
109
118
|
* and picking an arbitrary entry of the target collection on the author's behalf would be inventing
|
|
110
119
|
* a relationship they never stated.
|
|
111
120
|
*/
|
|
112
|
-
function emptyForField(field: ContentTypeSchemaField):
|
|
113
|
-
if (
|
|
121
|
+
function emptyForField(field: ContentTypeSchemaField): JsonValue {
|
|
122
|
+
if (isString(field.$ref)) {
|
|
114
123
|
return "";
|
|
115
124
|
}
|
|
116
125
|
switch (field.type) {
|
|
@@ -125,7 +134,7 @@ function emptyForField(field: ContentTypeSchemaField): unknown {
|
|
|
125
134
|
return [];
|
|
126
135
|
}
|
|
127
136
|
case "object": {
|
|
128
|
-
return seedEntry(field
|
|
137
|
+
return seedEntry(field);
|
|
129
138
|
}
|
|
130
139
|
default: {
|
|
131
140
|
return "";
|
|
@@ -145,13 +154,13 @@ function emptyForField(field: ContentTypeSchemaField): unknown {
|
|
|
145
154
|
* author's file full of keys they never asked for, and "the schema mentions it" is not a reason for
|
|
146
155
|
* it to exist on disk — the form still draws a row for it, because the form draws the SCHEMA.
|
|
147
156
|
*/
|
|
148
|
-
export function seedEntry(schema: ContentTypeSchema | null | undefined):
|
|
157
|
+
export function seedEntry(schema: ContentTypeSchema | null | undefined): JsonObject {
|
|
149
158
|
const properties = schema?.properties;
|
|
150
159
|
if (!properties) {
|
|
151
160
|
return {};
|
|
152
161
|
}
|
|
153
|
-
const required = new Set(Array.isArray(schema
|
|
154
|
-
const seed:
|
|
162
|
+
const required = new Set(Array.isArray(schema.required) ? schema.required : []);
|
|
163
|
+
const seed: JsonObject = {};
|
|
155
164
|
for (const [name, field] of Object.entries(properties)) {
|
|
156
165
|
if (field.default !== undefined) {
|
|
157
166
|
seed[name] = cloneDefault(field.default);
|
|
@@ -168,7 +177,7 @@ export function seedEntry(schema: ContentTypeSchema | null | undefined): Record<
|
|
|
168
177
|
*/
|
|
169
178
|
export function missingRequired(
|
|
170
179
|
schema: ContentTypeSchema | null | undefined,
|
|
171
|
-
value:
|
|
180
|
+
value: EntryFields,
|
|
172
181
|
): string[] {
|
|
173
182
|
const required = Array.isArray(schema?.required) ? schema.required : [];
|
|
174
183
|
return required.filter((name) => value[name] === undefined);
|
|
@@ -15,7 +15,6 @@ import { dismissContextMenu, showContextMenu } from "./context-menu";
|
|
|
15
15
|
import { bubbleInlinePath } from "../canvas/canvas-helpers";
|
|
16
16
|
import { activeTab } from "../workspace/workspace";
|
|
17
17
|
import type { CanvasContextMenuHandler } from "../canvas/iframe-host";
|
|
18
|
-
import type { JxPath } from "../state";
|
|
19
18
|
|
|
20
19
|
/**
|
|
21
20
|
* Build the handler.
|
|
@@ -34,7 +33,7 @@ export function makeCanvasContextMenuHandler(): CanvasContextMenuHandler {
|
|
|
34
33
|
}
|
|
35
34
|
// Lift inline-element paths (a <strong> inside a <p>) to their block parent — right-clicking
|
|
36
35
|
// Formatted text should act on the block, matching the legacy handler.
|
|
37
|
-
const bubbled = bubbleInlinePath(activeTab.value?.doc.document, path
|
|
36
|
+
const bubbled = bubbleInlinePath(activeTab.value?.doc.document, path);
|
|
38
37
|
// ShowContextMenu reads only preventDefault/clientX/clientY from the event, so a synthetic
|
|
39
38
|
// MouseEvent carries the converted coords safely.
|
|
40
39
|
const evt = new MouseEvent("contextmenu", { clientX, clientY });
|
|
@@ -18,11 +18,8 @@ export const canvasSlashHandler: CanvasSlashHandler = {
|
|
|
18
18
|
opened. Typing "/" needs none — the author keeps typing into the iframe's contenteditable and
|
|
19
19
|
the engine re-posts `slashShow` with the updated filter. A menu opened BY NAME
|
|
20
20
|
(`insert.openSlashMenu`) has no "/…" run to type into, so without the field the only way past
|
|
21
|
-
fifteen blocks is scrolling.
|
|
21
|
+
fifteen blocks is scrolling. The menu reads `showFilter` for truthiness alone, so `false` and an
|
|
22
|
+
absent key are one state to it. */
|
|
22
23
|
show: ({ rect, filter, showFilter, onSelect, onDismiss }) =>
|
|
23
|
-
showSlashMenuAtRect(rect, filter, {
|
|
24
|
-
onDismiss,
|
|
25
|
-
onSelect,
|
|
26
|
-
...(showFilter === true ? { showFilter: true } : {}),
|
|
27
|
-
}),
|
|
24
|
+
showSlashMenuAtRect(rect, filter, { onDismiss, onSelect, showFilter: showFilter === true }),
|
|
28
25
|
};
|
|
@@ -14,11 +14,18 @@
|
|
|
14
14
|
* @docs studio/editing/writing
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import { isString } from "@jxsuite/schema/guards";
|
|
17
18
|
import type { JxMutableNode } from "@jxsuite/schema/types";
|
|
18
19
|
|
|
19
20
|
/** A block's content as a children array — the form both storage shapes normalize to. */
|
|
20
21
|
export type Content = (JxMutableNode | string)[];
|
|
21
22
|
|
|
23
|
+
/** A block's content in the form it is stored: `children` for markup, folded `textContent` else. */
|
|
24
|
+
export interface StoredContent {
|
|
25
|
+
children?: Content;
|
|
26
|
+
textContent?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
22
29
|
/**
|
|
23
30
|
* The content of `node` as a children array, whichever way it is stored.
|
|
24
31
|
*
|
|
@@ -30,18 +37,16 @@ export function contentOf(node: JxMutableNode | undefined | null): Content {
|
|
|
30
37
|
return [];
|
|
31
38
|
}
|
|
32
39
|
if (Array.isArray(node.children)) {
|
|
33
|
-
return node.children
|
|
40
|
+
return node.children;
|
|
34
41
|
}
|
|
35
|
-
return
|
|
36
|
-
? [node.textContent]
|
|
37
|
-
: [];
|
|
42
|
+
return isString(node.textContent) && node.textContent.length > 0 ? [node.textContent] : [];
|
|
38
43
|
}
|
|
39
44
|
|
|
40
45
|
/** The rendered text length of a content array. */
|
|
41
46
|
export function contentLength(children: Content): number {
|
|
42
47
|
let n = 0;
|
|
43
48
|
for (const child of children) {
|
|
44
|
-
n +=
|
|
49
|
+
n += isString(child) ? child.length : contentLength(contentOf(child));
|
|
45
50
|
}
|
|
46
51
|
return n;
|
|
47
52
|
}
|
|
@@ -60,7 +65,7 @@ export function sliceContent(children: Content, start: number, end: number): Con
|
|
|
60
65
|
if (pos >= end) {
|
|
61
66
|
break;
|
|
62
67
|
}
|
|
63
|
-
if (
|
|
68
|
+
if (isString(child)) {
|
|
64
69
|
const childEnd = pos + child.length;
|
|
65
70
|
if (childEnd > start) {
|
|
66
71
|
const text = child.slice(
|
|
@@ -102,7 +107,7 @@ function withContent(node: JxMutableNode, children: Content): JxMutableNode {
|
|
|
102
107
|
if (children.length === 0) {
|
|
103
108
|
return { ...rest, textContent: "" };
|
|
104
109
|
}
|
|
105
|
-
if (children.length === 1 &&
|
|
110
|
+
if (children.length === 1 && isString(children[0])) {
|
|
106
111
|
return { ...rest, textContent: children[0] };
|
|
107
112
|
}
|
|
108
113
|
return { ...rest, children };
|
|
@@ -115,12 +120,12 @@ function withContent(node: JxMutableNode, children: Content): JxMutableNode {
|
|
|
115
120
|
export function normalizeContent(children: Content): Content {
|
|
116
121
|
const out: Content = [];
|
|
117
122
|
for (const child of children) {
|
|
118
|
-
if (
|
|
123
|
+
if (isString(child)) {
|
|
119
124
|
if (child.length === 0) {
|
|
120
125
|
continue;
|
|
121
126
|
}
|
|
122
127
|
const prev = out.at(-1);
|
|
123
|
-
if (
|
|
128
|
+
if (isString(prev)) {
|
|
124
129
|
out[out.length - 1] = prev + child;
|
|
125
130
|
continue;
|
|
126
131
|
}
|
|
@@ -152,15 +157,12 @@ export function spliceAcross(
|
|
|
152
157
|
}
|
|
153
158
|
|
|
154
159
|
/** `{ children }` when the content carries markup, else the folded `{ textContent }` form. */
|
|
155
|
-
export function toStored(children: Content): {
|
|
156
|
-
children?: Content;
|
|
157
|
-
textContent?: string;
|
|
158
|
-
} {
|
|
160
|
+
export function toStored(children: Content): StoredContent {
|
|
159
161
|
const normalized = normalizeContent(children);
|
|
160
162
|
if (normalized.length === 0) {
|
|
161
163
|
return { textContent: "" };
|
|
162
164
|
}
|
|
163
|
-
if (normalized.length === 1 &&
|
|
165
|
+
if (normalized.length === 1 && isString(normalized[0])) {
|
|
164
166
|
return { textContent: normalized[0] };
|
|
165
167
|
}
|
|
166
168
|
return { children: normalized };
|
|
@@ -21,10 +21,11 @@
|
|
|
21
21
|
* is left here is the projection: the menu itself is the `menu` surface (`surfaces/menu.json`), a
|
|
22
22
|
* `jx-menu` the kit gives its keyboard contract, its popover and its dismissal.
|
|
23
23
|
*/
|
|
24
|
-
import {
|
|
24
|
+
import { getNodeAtPath } from "@jxsuite/schema/doc-ops";
|
|
25
|
+
import { displayTagName, isNodeObject, isNonNullObject, isString } from "@jxsuite/schema/guards";
|
|
25
26
|
import { jsonClone } from "../utils/studio-utils";
|
|
26
27
|
import { htmlToJx } from "@jxsuite/markup/html-to-jx";
|
|
27
|
-
import { childIndex,
|
|
28
|
+
import { childIndex, parentElementPath } from "../store";
|
|
28
29
|
import { activeTab, workspace } from "../workspace/workspace";
|
|
29
30
|
import { isSelected, isSpliceablePath, primarySelection } from "../tabs/selection";
|
|
30
31
|
import {
|
|
@@ -58,17 +59,15 @@ import type { AnyCommand, CommandRegistry } from "../commands/registry";
|
|
|
58
59
|
import type { CommandContext } from "../commands/context";
|
|
59
60
|
import type { Placement } from "../commands/levels";
|
|
60
61
|
import type { JxPath } from "../state";
|
|
61
|
-
import type { JxMutableNode, JxStyle } from "@jxsuite/schema/types";
|
|
62
|
-
|
|
63
|
-
type JxNode = JxMutableNode;
|
|
62
|
+
import type { JxAttributeValue, JxMutableNode, JxStyle } from "@jxsuite/schema/types";
|
|
64
63
|
|
|
65
64
|
// ─── Clipboard helpers ───────────────────────────────────────────────────────
|
|
66
65
|
|
|
67
|
-
const JX_MIME = "web application/jx+json";
|
|
66
|
+
export const JX_MIME = "web application/jx+json";
|
|
68
67
|
|
|
69
|
-
/** @param {
|
|
70
|
-
function nodeToHtml(node:
|
|
71
|
-
if (
|
|
68
|
+
/** @param {JxMutableNode | string} node */
|
|
69
|
+
function nodeToHtml(node: JxMutableNode | string): string {
|
|
70
|
+
if (isString(node)) {
|
|
72
71
|
return node;
|
|
73
72
|
}
|
|
74
73
|
/* A chosen tag cannot be serialised to one HTML string, so the copy takes the branch the
|
|
@@ -77,9 +76,10 @@ function nodeToHtml(node: JxNode | string): string {
|
|
|
77
76
|
const tag = displayTagName(node.tagName).split("|")[0] || "div";
|
|
78
77
|
let attrs = "";
|
|
79
78
|
if (node.attributes) {
|
|
80
|
-
|
|
79
|
+
// A document's attribute value is read as possibly JSON `null`, which is skipped with the refs.
|
|
80
|
+
for (const [k, v] of Object.entries<JxAttributeValue | null>(node.attributes)) {
|
|
81
81
|
// Bound ($ref) attribute values have no static HTML representation — skip.
|
|
82
|
-
if (
|
|
82
|
+
if (v === null || isNonNullObject(v)) {
|
|
83
83
|
continue;
|
|
84
84
|
}
|
|
85
85
|
attrs += v === "" ? ` ${k}` : ` ${k}="${String(v).replaceAll('"', """)}"`;
|
|
@@ -94,7 +94,7 @@ function nodeToHtml(node: JxNode | string): string {
|
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
let inner = "";
|
|
97
|
-
if (
|
|
97
|
+
if (isString(node.textContent)) {
|
|
98
98
|
inner = node.textContent;
|
|
99
99
|
} else if (Array.isArray(node.children)) {
|
|
100
100
|
inner = node.children.map((c) => nodeToHtml(c)).join("");
|
|
@@ -105,9 +105,9 @@ function nodeToHtml(node: JxNode | string): string {
|
|
|
105
105
|
/**
|
|
106
106
|
* Write a Jx node to the system clipboard with both jx+json and text/html types.
|
|
107
107
|
*
|
|
108
|
-
* @param {
|
|
108
|
+
* @param {JxMutableNode} json
|
|
109
109
|
*/
|
|
110
|
-
async function writeToClipboard(json:
|
|
110
|
+
async function writeToClipboard(json: JxMutableNode) {
|
|
111
111
|
workspace.clipboard = json;
|
|
112
112
|
try {
|
|
113
113
|
const jxBlob = new Blob([JSON.stringify(json)], { type: JX_MIME });
|
|
@@ -131,7 +131,7 @@ async function writeToClipboard(json: Record<string, unknown>) {
|
|
|
131
131
|
/**
|
|
132
132
|
* Read from the system clipboard. Returns Jx node(s) or null.
|
|
133
133
|
*
|
|
134
|
-
* @returns {Promise<
|
|
134
|
+
* @returns {Promise<JxMutableNode[] | null>}
|
|
135
135
|
*/
|
|
136
136
|
async function readFromClipboard() {
|
|
137
137
|
try {
|
|
@@ -139,16 +139,18 @@ async function readFromClipboard() {
|
|
|
139
139
|
for (const item of items) {
|
|
140
140
|
if (item.types.includes(JX_MIME)) {
|
|
141
141
|
const blob = await item.getType(JX_MIME);
|
|
142
|
-
|
|
142
|
+
/* SAFETY: `web application/jx+json` is Jx's own clipboard type, and `writeToClipboard` puts a
|
|
143
|
+
node there serialized with JSON.stringify; malformed text throws into the fallback below. */
|
|
144
|
+
const json = JSON.parse(await blob.text()) as JxMutableNode;
|
|
143
145
|
return [json];
|
|
144
146
|
}
|
|
145
147
|
if (item.types.includes("text/html")) {
|
|
146
148
|
const blob = await item.getType("text/html");
|
|
147
149
|
const htmlStr = await blob.text();
|
|
148
150
|
const nodes = htmlToJx(htmlStr);
|
|
149
|
-
const jxNodes = nodes.map((n) =>
|
|
150
|
-
|
|
151
|
-
)
|
|
151
|
+
const jxNodes: JxMutableNode[] = nodes.map((n) =>
|
|
152
|
+
isString(n) ? { tagName: "p", textContent: n } : n,
|
|
153
|
+
);
|
|
152
154
|
if (jxNodes.length > 0) {
|
|
153
155
|
return jxNodes;
|
|
154
156
|
}
|
|
@@ -158,8 +160,8 @@ async function readFromClipboard() {
|
|
|
158
160
|
const text = await blob.text();
|
|
159
161
|
// Try parsing as Jx JSON
|
|
160
162
|
try {
|
|
161
|
-
const parsed = JSON.parse(text)
|
|
162
|
-
if (parsed && parsed.tagName) {
|
|
163
|
+
const parsed: unknown = JSON.parse(text);
|
|
164
|
+
if (isNodeObject(parsed) && parsed.tagName) {
|
|
163
165
|
return [parsed];
|
|
164
166
|
}
|
|
165
167
|
} catch {
|
|
@@ -241,7 +243,12 @@ export async function pasteNode() {
|
|
|
241
243
|
}
|
|
242
244
|
|
|
243
245
|
if (selected && selected.length >= 2) {
|
|
246
|
+
// SAFETY: parentElementPath returns a path for any path of two or more segments, checked above.
|
|
244
247
|
const pp = parentElementPath(selected) as JxPath;
|
|
248
|
+
/* SAFETY: a selection with a sibling position ends in `"children", <index>`, so this is the
|
|
249
|
+
numeric child index. A selected repeater template (`…, "map"`) or `$switch` case also has two
|
|
250
|
+
or more segments; callers do not exclude that case yet, so it reaches here with a string
|
|
251
|
+
segment exactly as before this cast. */
|
|
245
252
|
const idx = childIndex(selected) as number;
|
|
246
253
|
transactDoc(tab, (t) => {
|
|
247
254
|
for (let i = 0; i < nodes.length; i++) {
|
|
@@ -408,7 +415,10 @@ export function elementCommands(deps: ElementCommandDeps): AnyCommand[] {
|
|
|
408
415
|
if (!target || !nodes || nodes.length === 0) {
|
|
409
416
|
return;
|
|
410
417
|
}
|
|
418
|
+
/* SAFETY: this record runs only when enabled, and `spliceable` admits a target whose path
|
|
419
|
+
ends in `"children", <index>` — so it has a parent element path. */
|
|
411
420
|
const parent = parentElementPath(target.path) as JxPath;
|
|
421
|
+
// SAFETY: the same `spliceable` check proved the last segment is a numeric child index.
|
|
412
422
|
const idx = childIndex(target.path) as number;
|
|
413
423
|
transactDoc(activeTab.value, (t) => {
|
|
414
424
|
for (const [offset, node] of nodes.entries()) {
|
|
@@ -576,7 +586,10 @@ function insertSiblingParagraph(target: ElementMenuTarget | null, offset: number
|
|
|
576
586
|
if (!target) {
|
|
577
587
|
return;
|
|
578
588
|
}
|
|
589
|
+
/* SAFETY: both callers are records enabled only by `spliceable`, which admits a target whose path
|
|
590
|
+
ends in `"children", <index>` — so it has a parent element path. */
|
|
579
591
|
const parent = parentElementPath(target.path) as JxPath;
|
|
592
|
+
// SAFETY: the same `spliceable` check proved the last segment is a numeric child index.
|
|
580
593
|
const idx = childIndex(target.path) as number;
|
|
581
594
|
transactDoc(activeTab.value, (t) =>
|
|
582
595
|
mutateInsertNode(t, parent, idx + offset, { children: [], tagName: "p" }),
|
|
@@ -681,7 +694,7 @@ function commandTarget(): ElementMenuTarget | null {
|
|
|
681
694
|
if (!tab || !path) {
|
|
682
695
|
return null;
|
|
683
696
|
}
|
|
684
|
-
const node = getNodeAtPath(tab.doc.document, path)
|
|
697
|
+
const node = getNodeAtPath(tab.doc.document, path);
|
|
685
698
|
return node ? { node, path } : null;
|
|
686
699
|
}
|
|
687
700
|
|
|
@@ -1,34 +1,33 @@
|
|
|
1
1
|
import elementsMeta from "../../data/elements-meta.json";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
3
|
+
import { ELEMENT_DEFS } from "./editable-tags";
|
|
4
|
+
import type { SlashCommand } from "./inline-edit";
|
|
5
|
+
|
|
6
|
+
export type { SlashCommand } from "./inline-edit";
|
|
8
7
|
|
|
9
|
-
const TAG_LABELS =
|
|
10
|
-
article
|
|
11
|
-
aside
|
|
12
|
-
blockquote
|
|
13
|
-
div
|
|
14
|
-
footer
|
|
15
|
-
h1
|
|
16
|
-
h2
|
|
17
|
-
h3
|
|
18
|
-
h4
|
|
19
|
-
h5
|
|
20
|
-
h6
|
|
21
|
-
header
|
|
22
|
-
main
|
|
23
|
-
nav
|
|
24
|
-
ol
|
|
25
|
-
p
|
|
26
|
-
search
|
|
27
|
-
section
|
|
28
|
-
ul
|
|
29
|
-
|
|
8
|
+
const TAG_LABELS = new Map<string, string>([
|
|
9
|
+
["article", "Article"],
|
|
10
|
+
["aside", "Aside"],
|
|
11
|
+
["blockquote", "Blockquote"],
|
|
12
|
+
["div", "Div"],
|
|
13
|
+
["footer", "Footer"],
|
|
14
|
+
["h1", "Heading 1"],
|
|
15
|
+
["h2", "Heading 2"],
|
|
16
|
+
["h3", "Heading 3"],
|
|
17
|
+
["h4", "Heading 4"],
|
|
18
|
+
["h5", "Heading 5"],
|
|
19
|
+
["h6", "Heading 6"],
|
|
20
|
+
["header", "Header"],
|
|
21
|
+
["main", "Main"],
|
|
22
|
+
["nav", "Nav"],
|
|
23
|
+
["ol", "Numbered List"],
|
|
24
|
+
["p", "Paragraph"],
|
|
25
|
+
["search", "Search"],
|
|
26
|
+
["section", "Section"],
|
|
27
|
+
["ul", "Bulleted List"],
|
|
28
|
+
]);
|
|
30
29
|
|
|
31
|
-
const groups
|
|
30
|
+
const groups: Readonly<Record<string, string[]>> = elementsMeta.$convertGroups;
|
|
32
31
|
|
|
33
32
|
/**
|
|
34
33
|
* Get the list of tags the current element can be converted to.
|
|
@@ -37,18 +36,14 @@ const groups = (elementsMeta.$convertGroups || {}) as Record<string, string[]>;
|
|
|
37
36
|
* @param {boolean} isEmpty
|
|
38
37
|
* @returns {SlashCommand[]}
|
|
39
38
|
*/
|
|
40
|
-
export function getConvertTargets(currentTag: string, isEmpty: boolean) {
|
|
41
|
-
const def =
|
|
42
|
-
| Record<string, unknown>
|
|
43
|
-
| undefined;
|
|
39
|
+
export function getConvertTargets(currentTag: string, isEmpty: boolean): SlashCommand[] {
|
|
40
|
+
const def = ELEMENT_DEFS[currentTag];
|
|
44
41
|
if (!def?.$convertTo) {
|
|
45
42
|
return [];
|
|
46
43
|
}
|
|
47
44
|
|
|
48
45
|
const groupNames =
|
|
49
|
-
isEmpty && def.$convertToWhenEmpty
|
|
50
|
-
? (def.$convertToWhenEmpty as string[])
|
|
51
|
-
: [def.$convertTo as string];
|
|
46
|
+
isEmpty && def.$convertToWhenEmpty ? def.$convertToWhenEmpty : [def.$convertTo];
|
|
52
47
|
|
|
53
48
|
const tags = new Set<string>();
|
|
54
49
|
for (const name of groupNames) {
|
|
@@ -61,7 +56,7 @@ export function getConvertTargets(currentTag: string, isEmpty: boolean) {
|
|
|
61
56
|
|
|
62
57
|
return [...tags].map((tag) => ({
|
|
63
58
|
description: "",
|
|
64
|
-
label: TAG_LABELS
|
|
59
|
+
label: TAG_LABELS.get(tag) || tag.charAt(0).toUpperCase() + tag.slice(1),
|
|
65
60
|
tag,
|
|
66
61
|
}));
|
|
67
62
|
}
|
|
@@ -17,9 +17,10 @@
|
|
|
17
17
|
*
|
|
18
18
|
* @docs studio/design/components
|
|
19
19
|
*/
|
|
20
|
-
import { displayTagName } from "@jxsuite/schema/guards";
|
|
20
|
+
import { displayTagName, isNonNullObject } from "@jxsuite/schema/guards";
|
|
21
21
|
import { errorMessage } from "@jxsuite/schema/parse";
|
|
22
|
-
import {
|
|
22
|
+
import { getNodeAtPath } from "@jxsuite/schema/doc-ops";
|
|
23
|
+
import { childIndex, parentElementPath } from "../store";
|
|
23
24
|
import { primarySelection } from "../tabs/selection";
|
|
24
25
|
import { activeTab } from "../workspace/workspace";
|
|
25
26
|
import { transact } from "../tabs/transact";
|
|
@@ -71,10 +72,16 @@ export async function convertToComponent() {
|
|
|
71
72
|
const converted = transact(tab, (doc) => {
|
|
72
73
|
// Navigate to parent's children array and replace the node
|
|
73
74
|
const pp = parentElementPath(selectionPath) ?? [];
|
|
75
|
+
/* SAFETY: an element with a sibling position ends in `"children", <index>`, so this is the
|
|
76
|
+
numeric child index. A selected repeater template (`…, "map"`) or `$switch` case also passes
|
|
77
|
+
the two-segment check above; callers do not exclude that case yet, so it reaches here with a
|
|
78
|
+
string segment exactly as before this cast. */
|
|
74
79
|
const idx = childIndex(selectionPath) as number;
|
|
75
80
|
let parent = doc;
|
|
76
|
-
// Paths address nodes by construction (same contract as getNodeAtPath).
|
|
77
81
|
for (const seg of pp) {
|
|
82
|
+
/* SAFETY: `pp` is the parent element's path, and a `JxPath` alternates node keys with
|
|
83
|
+
`"children"` and an index, so walking it from the root lands on a node (the same contract as
|
|
84
|
+
getNodeAtPath). */
|
|
78
85
|
parent = parent[seg] as JxMutableNode;
|
|
79
86
|
}
|
|
80
87
|
if (!Array.isArray(parent.children)) {
|
|
@@ -87,8 +94,7 @@ export async function convertToComponent() {
|
|
|
87
94
|
doc.$elements = [];
|
|
88
95
|
}
|
|
89
96
|
const alreadyReferenced = doc.$elements.some(
|
|
90
|
-
(
|
|
91
|
-
el && typeof el === "object" && "$ref" in el && el.$ref === refPath,
|
|
97
|
+
(el) => isNonNullObject(el) && "$ref" in el && el.$ref === refPath,
|
|
92
98
|
);
|
|
93
99
|
if (!alreadyReferenced) {
|
|
94
100
|
doc.$elements.push({ $ref: refPath });
|
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
*
|
|
13
13
|
* @docs studio/design/repeaters
|
|
14
14
|
*/
|
|
15
|
-
import {
|
|
15
|
+
import { getNodeAtPath } from "@jxsuite/schema/doc-ops";
|
|
16
|
+
import { isJsonObject, isPrototypeDef } from "@jxsuite/schema/guards";
|
|
17
|
+
import { childIndex, childList, parentElementPath } from "../store";
|
|
16
18
|
import { primarySelection } from "../tabs/selection";
|
|
17
19
|
import { activeTab } from "../workspace/workspace";
|
|
18
20
|
import { transactDoc } from "../tabs/transact";
|
|
@@ -22,15 +24,18 @@ import { fetchPluginSchema } from "../services/code-services";
|
|
|
22
24
|
import { CREATE_NEW_SOURCE, openConvertRepeaterSurface } from "../surfaces/convert-repeater";
|
|
23
25
|
|
|
24
26
|
import type { ConvertRepeaterView } from "../surfaces/convert-repeater";
|
|
25
|
-
import type { JxMutableNode } from "@jxsuite/schema/types";
|
|
27
|
+
import type { JxMutableNode, JxRef, JxStateDefinition } from "@jxsuite/schema/types";
|
|
26
28
|
|
|
27
29
|
/** What a name has to look like to become a state definition. */
|
|
28
30
|
const IDENTIFIER = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
29
31
|
|
|
32
|
+
/** A document's state definitions, by name. */
|
|
33
|
+
type StateDefs = Readonly<Record<string, JxStateDefinition>>;
|
|
34
|
+
|
|
30
35
|
interface RepeaterConfig {
|
|
31
|
-
items:
|
|
32
|
-
filter?:
|
|
33
|
-
sort?:
|
|
36
|
+
items: JxRef;
|
|
37
|
+
filter?: JxRef;
|
|
38
|
+
sort?: JxRef;
|
|
34
39
|
newDef?: { name: string };
|
|
35
40
|
}
|
|
36
41
|
|
|
@@ -65,14 +70,18 @@ export async function convertToRepeater() {
|
|
|
65
70
|
if (!pp) {
|
|
66
71
|
return;
|
|
67
72
|
}
|
|
73
|
+
/* SAFETY: the command is enabled only when every selected path is spliceable
|
|
74
|
+
(`structurallyEditable` in commands/defaults.ts), so `path` ends in `"children", <index>`. */
|
|
68
75
|
const idx = childIndex(path) as number;
|
|
69
76
|
const parent = getNodeAtPath(doc, pp);
|
|
70
77
|
if (!parent?.children) {
|
|
71
78
|
return;
|
|
72
79
|
}
|
|
73
|
-
|
|
80
|
+
/* SAFETY: a selection addresses an element node (the canvas selects elements, and an outline
|
|
81
|
+
text row is not a selectable item), and this reads the selected slot of its parent. */
|
|
82
|
+
const element = childList(parent)[idx] as JxMutableNode;
|
|
74
83
|
|
|
75
|
-
const repeater:
|
|
84
|
+
const repeater: JxMutableNode = {
|
|
76
85
|
$prototype: "Array",
|
|
77
86
|
items: config.items,
|
|
78
87
|
map: element,
|
|
@@ -84,9 +93,11 @@ export async function convertToRepeater() {
|
|
|
84
93
|
repeater.sort = config.sort;
|
|
85
94
|
}
|
|
86
95
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
96
|
+
/* Replace the selected element in place with the array pseudo-element — no wrapper div. The
|
|
97
|
+
repeated items render directly among the original parent's children.
|
|
98
|
+
SAFETY: a document is normalized to the member form when it loads into a tab
|
|
99
|
+
(`normalizeArrayChildren`), so a present `children` is an array, never a bare repeater. */
|
|
100
|
+
(parent.children as (string | JxMutableNode)[])[idx] = repeater;
|
|
90
101
|
});
|
|
91
102
|
}
|
|
92
103
|
|
|
@@ -98,18 +109,19 @@ export async function convertToRepeater() {
|
|
|
98
109
|
* returns in its schema — so it is asked for once per definition, and only for the ones the first
|
|
99
110
|
* three did not already claim.
|
|
100
111
|
*/
|
|
101
|
-
async function arraySourceNames(defs:
|
|
112
|
+
async function arraySourceNames(defs: StateDefs): Promise<string[]> {
|
|
102
113
|
const named = Object.entries(defs)
|
|
103
|
-
.filter(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
114
|
+
.filter(
|
|
115
|
+
([, def]) =>
|
|
116
|
+
isJsonObject(def) &&
|
|
117
|
+
(def.type === "array" || Array.isArray(def.default) || def.$prototype === "Array"),
|
|
118
|
+
)
|
|
107
119
|
.map(([name]) => name);
|
|
108
120
|
|
|
109
121
|
const docPath = activeTab.value?.documentPath;
|
|
110
|
-
for (const [name,
|
|
111
|
-
|
|
112
|
-
if (!def
|
|
122
|
+
for (const [name, def] of Object.entries(defs)) {
|
|
123
|
+
// Only a named, non-Function, non-Array prototype can be a plugin whose schema says it returns one.
|
|
124
|
+
if (!isPrototypeDef(def) || !def.$prototype || def.$prototype === "Array") {
|
|
113
125
|
continue;
|
|
114
126
|
}
|
|
115
127
|
if (named.includes(name)) {
|
|
@@ -117,8 +129,8 @@ async function arraySourceNames(defs: Record<string, unknown>): Promise<string[]
|
|
|
117
129
|
}
|
|
118
130
|
const schema = await fetchPluginSchema(
|
|
119
131
|
{
|
|
120
|
-
...(def.$src != null && { $src: def.$src
|
|
121
|
-
$prototype: def.$prototype
|
|
132
|
+
...(def.$src != null && { $src: def.$src }),
|
|
133
|
+
$prototype: def.$prototype,
|
|
122
134
|
},
|
|
123
135
|
{ ...(docPath != null && { documentPath: docPath }) },
|
|
124
136
|
);
|
|
@@ -136,10 +148,10 @@ async function arraySourceNames(defs: Record<string, unknown>): Promise<string[]
|
|
|
136
148
|
* name keeps the dialog open with the reason under the field — the flow's state machine, which is
|
|
137
149
|
* the half the surface deliberately does not have.
|
|
138
150
|
*
|
|
139
|
-
* @param {
|
|
151
|
+
* @param {StateDefs} defs
|
|
140
152
|
* @returns {Promise<RepeaterConfig | null>}
|
|
141
153
|
*/
|
|
142
|
-
async function promptRepeaterConfig(defs:
|
|
154
|
+
async function promptRepeaterConfig(defs: StateDefs): Promise<RepeaterConfig | null> {
|
|
143
155
|
const sources = await arraySourceNames(defs);
|
|
144
156
|
const functions = Object.entries(defs)
|
|
145
157
|
.filter(([, d]) => defCategory(d) === "function")
|
|
@@ -21,11 +21,26 @@
|
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
import elementsMeta from "../../data/elements-meta.json";
|
|
24
|
+
import type { InlineAction } from "./inline-edit";
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
/** The fields of one `elements-meta.json` `$defs` entry the editor reads. */
|
|
27
|
+
export interface ElementMeta {
|
|
28
|
+
/** Tags this element accepts as inline children; containers declare `[]`. */
|
|
26
29
|
$inlineChildren?: string[];
|
|
30
|
+
/** The formatting verbs the block action bar offers, or the tag whose list this one shares. */
|
|
31
|
+
$inlineActions?: InlineAction[] | string;
|
|
32
|
+
/** The `$convertGroups` group this element converts within. */
|
|
33
|
+
$convertTo?: string;
|
|
34
|
+
/** The groups offered instead of `$convertTo` while the element is empty. */
|
|
35
|
+
$convertToWhenEmpty?: string[];
|
|
27
36
|
}
|
|
28
37
|
|
|
38
|
+
/**
|
|
39
|
+
* The studio's element metadata by tag. The JSON is bundled with the studio, so the compiler checks
|
|
40
|
+
* every entry against {@link ElementMeta} here, once, instead of each reader asserting it.
|
|
41
|
+
*/
|
|
42
|
+
export const ELEMENT_DEFS: Readonly<Record<string, ElementMeta>> = elementsMeta.$defs;
|
|
43
|
+
|
|
29
44
|
/**
|
|
30
45
|
* Tags the studio's own metadata says accept inline children.
|
|
31
46
|
*
|
|
@@ -36,7 +51,7 @@ interface ElementDef {
|
|
|
36
51
|
const EXCLUDED = new Set(["pre"]);
|
|
37
52
|
|
|
38
53
|
export const BUILTIN_EDITABLE_TAGS: ReadonlySet<string> = new Set(
|
|
39
|
-
Object.entries(
|
|
54
|
+
Object.entries(ELEMENT_DEFS)
|
|
40
55
|
.filter(([tag, def]) => !EXCLUDED.has(tag) && (def.$inlineChildren?.length ?? 0) > 0)
|
|
41
56
|
.map(([tag]) => tag),
|
|
42
57
|
);
|