@jxsuite/studio 6.1.0 → 6.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/2020-f2gkpy8d.js +4 -0
- package/dist/chunks/{action-group-2mqby73c.js → action-group-4aan7g6g.js} +3 -3
- package/dist/chunks/adapter-4912g339.js +4 -0
- package/dist/chunks/cf-account-picker-wccaenh6.js +4 -0
- package/dist/chunks/cf-settings-br6105tr.js +4 -0
- package/dist/chunks/color-28ksk2qm.js +4 -0
- package/dist/chunks/color-area-0fj8a4ga.js +4 -0
- package/dist/chunks/color-field-xch8kx2g.js +4 -0
- package/dist/chunks/color-slider-jxd8v350.js +4 -0
- package/dist/chunks/combobox-p0efwjke.js +4 -0
- package/dist/chunks/components-db68vsn7.js +4 -0
- package/dist/chunks/content-source-1449qesq.js +4 -0
- package/dist/chunks/convert-to-repeater-5h457egj.js +4 -0
- package/dist/chunks/dialog-c4x05vyx.js +4 -0
- package/dist/chunks/editor-x9jn86a7.js +4 -0
- package/dist/chunks/entry-commands-may24cpt.js +4 -0
- package/dist/chunks/extension-sections-pvr14vxr.js +4 -0
- package/dist/chunks/file-ops-x9v54pcj.js +4 -0
- package/dist/chunks/files-j3knqf0s.js +4 -0
- package/dist/chunks/format-host-tyre2trb.js +4 -0
- package/dist/chunks/fs-events-64ma9htc.js +4 -0
- package/dist/chunks/git-panel-84ps5dex.js +4 -0
- package/dist/chunks/grid-view-d2wq9ezg.js +51 -0
- package/dist/chunks/icons-pnfz478q.js +4 -0
- package/dist/chunks/iframe-entry-fvbk89gm.js +5 -0
- package/dist/chunks/iframe-entry-jdcktez8.js +5 -0
- package/dist/chunks/iframe-entry-x0ygf2yr.js +5 -0
- package/dist/chunks/iframe-entry-zap785cw.js +5 -0
- package/dist/chunks/iframe-host-ck6vejt5.js +4 -0
- package/dist/chunks/index-b8xw3vy9.js +4 -0
- package/dist/chunks/{index-gybvv7a6.js → index-zpjmzqfk.js} +3 -3
- package/dist/chunks/{javascript-rnvdp3k4.js → javascript-m54mnwp6.js} +3 -3
- package/dist/chunks/jsonMode-w15cmrcm.js +13 -0
- package/dist/chunks/jx-validate-at3zn8wa.js +4 -0
- package/dist/chunks/layers-h4xp1pss.js +4 -0
- package/dist/chunks/layers-panel-m5hw1d7g.js +4 -0
- package/dist/chunks/listbox-e74qjyq6.js +4 -0
- package/dist/chunks/lit-html-8t8t3dnr.js +4 -0
- package/dist/chunks/media-picker-2cweexc5.js +4 -0
- package/dist/chunks/menu-n6yzswmy.js +4 -0
- package/dist/chunks/menu-ynw13y0s.js +4 -0
- package/dist/chunks/monaco-binding-7gx83x3r.js +4 -0
- package/dist/chunks/monaco-buffer-qzxn567r.js +4 -0
- package/dist/chunks/monaco-setup-gxf6656g.js +4 -0
- package/dist/chunks/notify-cj5zbrs2.js +4 -0
- package/dist/chunks/number-field-y62xq0ty.js +4 -0
- package/dist/chunks/parse-b7ddhr8m.js +4 -0
- package/dist/chunks/platform-3dfws9js.js +4 -0
- package/dist/chunks/popover-jt2gxmzs.js +4 -0
- package/dist/chunks/publish-panel-1gvxbj21.js +4 -0
- package/dist/chunks/quick-search-0dajrwqg.js +4 -0
- package/dist/chunks/references-49qgt404.js +4 -0
- package/dist/chunks/right-panel-jm1bwe53.js +4 -0
- package/dist/chunks/section-registry-6kwc4fky.js +4 -0
- package/dist/chunks/select-rzds841e.js +4 -0
- package/dist/chunks/split-n2gfpm5m.js +4 -0
- package/dist/chunks/{studio-5g0ag7c0.js → studio-0q988f9w.js} +3 -3
- package/dist/chunks/studio-0rt52vpq.js +5 -0
- package/dist/chunks/studio-18vgbhs5.js +5 -0
- package/dist/chunks/{studio-pxg4ap1e.js → studio-1fxkaaea.js} +4 -4
- package/dist/chunks/studio-24mccdrj.js +5 -0
- package/dist/chunks/studio-2eh507zk.js +9 -0
- package/dist/chunks/studio-2hcbccfv.js +5 -0
- package/dist/chunks/studio-2j1cb95x.js +5 -0
- package/dist/chunks/studio-2jbs3rxv.js +5 -0
- package/dist/chunks/{studio-qbj760tx.js → studio-485046te.js} +7 -7
- package/dist/chunks/studio-4h8k4dw9.js +5 -0
- package/dist/chunks/studio-5f6n18kx.js +5 -0
- package/dist/chunks/studio-5gthpky6.js +5 -0
- package/dist/chunks/studio-5ve6bbep.js +5 -0
- package/dist/chunks/studio-6ep3js6b.js +9 -0
- package/dist/chunks/studio-6wkmf3wz.js +9 -0
- package/dist/chunks/studio-841rf3cg.js +5 -0
- package/dist/chunks/studio-8gmwgheg.js +5 -0
- package/dist/chunks/studio-8qm0ep50.js +5 -0
- package/dist/chunks/{studio-anyrgzvb.js → studio-90pq9km1.js} +4 -4
- package/dist/chunks/studio-924p1tm1.js +6 -0
- package/dist/chunks/{studio-v2bvmbjj.js → studio-a3g98wjr.js} +4 -4
- package/dist/chunks/studio-a3shpz9y.js +5 -0
- package/dist/chunks/studio-amsbaaar.js +6 -0
- package/dist/chunks/studio-at5spjbc.js +7 -0
- package/dist/chunks/studio-b2xv945e.js +5 -0
- package/dist/chunks/studio-bn5nkafw.js +5 -0
- package/dist/chunks/studio-bw6q5xjf.js +9 -0
- package/dist/chunks/studio-c7q0t9x1.js +5 -0
- package/dist/chunks/studio-camnhc96.js +6 -0
- package/dist/chunks/studio-cffqvnzd.js +5 -0
- package/dist/chunks/studio-d81xfh1g.js +5 -0
- package/dist/chunks/studio-dgz8d0c1.js +5 -0
- package/dist/chunks/studio-efvfrsf8.js +5 -0
- package/dist/chunks/studio-er30bpcx.js +5 -0
- package/dist/chunks/studio-ezscgr64.js +5 -0
- package/dist/chunks/studio-ffrrncvz.js +5 -0
- package/dist/chunks/studio-fpphgn8y.js +10 -0
- package/dist/chunks/studio-j1kvhdjk.js +4 -0
- package/dist/chunks/{studio-txjjzrsm.js → studio-j430n16g.js} +5 -5
- package/dist/chunks/studio-jjkg84nj.js +5 -0
- package/dist/chunks/studio-m0q32ars.js +4 -0
- package/dist/chunks/studio-m6bdst11.js +5 -0
- package/dist/chunks/studio-nv2cptd4.js +64 -0
- package/dist/chunks/studio-nwfrc98n.js +5 -0
- package/dist/chunks/studio-p1wgvp7r.js +5 -0
- package/dist/chunks/studio-pag2wncm.js +5 -0
- package/dist/chunks/studio-qvanvzfd.js +5 -0
- package/dist/chunks/studio-qwa64kt7.js +5 -0
- package/dist/chunks/studio-rk1zc4x3.js +928 -0
- package/dist/chunks/studio-se2r3ptc.js +5 -0
- package/dist/chunks/studio-sg2a0dh0.js +5 -0
- package/dist/chunks/studio-tjzjhe68.js +5 -0
- package/dist/chunks/{studio-0x3jyb8r.js → studio-tq0rtfwj.js} +4 -4
- package/dist/chunks/{studio-cpxkgjrj.js → studio-v0jzqdjm.js} +4 -4
- package/dist/chunks/studio-v2w7q8r1.js +7 -0
- package/dist/chunks/studio-v5vjq1h0.js +4 -0
- package/dist/chunks/studio-v8aga3vp.js +14 -0
- package/dist/chunks/studio-vfcdrfmv.js +5 -0
- package/dist/chunks/studio-vmfkgdjf.js +5 -0
- package/dist/chunks/studio-wt1816jj.js +5 -0
- package/dist/chunks/studio-wz73q5kq.js +4 -0
- package/dist/chunks/studio-y04qtxvp.js +7 -0
- package/dist/chunks/studio-y21g8zzg.js +5 -0
- package/dist/chunks/studio-y64hrt8p.js +12 -0
- package/dist/chunks/studio-ynn90f58.js +16 -0
- package/dist/chunks/studio-yxz682sx.js +5 -0
- package/dist/chunks/studio-zp7snvkq.js +5 -0
- package/dist/chunks/studio-zq4z6tm6.js +5 -0
- package/dist/chunks/swatch-group-ewh24n1f.js +4 -0
- package/dist/chunks/tabs-f5cw3tgp.js +4 -0
- package/dist/chunks/textfield-wewc8rq2.js +4 -0
- package/dist/chunks/toast-c9fn075p.js +4 -0
- package/dist/chunks/toast-host-ke5z4ng7.js +4 -0
- package/dist/chunks/{toolbar-2nnzqhrj.js → toolbar-44cm5cta.js} +3 -3
- package/dist/chunks/tooltip-5v8ngwj2.js +4 -0
- package/dist/chunks/tree-mdq3v5cw.js +4 -0
- package/dist/chunks/tsMode-sf49ee9x.js +14 -0
- package/dist/chunks/workspace-jtfahpee.js +4 -0
- package/dist/chunks/ws-client-nze0k6mv.js +4 -0
- package/dist/iframe-entry.js +16 -16
- package/dist/manifest.json +63 -63
- package/dist/studio.js +98 -98
- package/dist/workers/ts.worker.js +3 -3
- package/package.json +11 -11
- package/src/about/about-modal.ts +4 -3
- package/src/account/action-flow.ts +45 -38
- package/src/account-status.ts +7 -2
- package/src/browse/library-layouts.ts +8 -5
- package/src/browse/library-model.ts +18 -6
- package/src/browse/library-pane.ts +37 -21
- package/src/browse/library-preview.ts +14 -9
- package/src/browse/library-source.ts +1 -1
- package/src/canvas/asset-refs.ts +24 -9
- package/src/canvas/asset-resolve.ts +19 -23
- package/src/canvas/canvas-helpers.ts +7 -6
- package/src/canvas/canvas-live-render.ts +44 -53
- package/src/canvas/canvas-patcher.ts +30 -30
- package/src/canvas/canvas-perf.ts +11 -5
- package/src/canvas/canvas-render.ts +66 -42
- package/src/canvas/canvas-surface.ts +5 -3
- package/src/canvas/canvas-utils.ts +163 -64
- package/src/canvas/dialog-path.ts +9 -4
- package/src/canvas/dialog-state.ts +1 -2
- package/src/canvas/diff-marks.ts +9 -16
- package/src/canvas/diff-toolbar.ts +8 -7
- package/src/canvas/edit-width-drag.ts +4 -1
- package/src/canvas/edit-width.ts +1 -3
- package/src/canvas/iframe-channel.ts +27 -13
- package/src/canvas/iframe-drop.ts +13 -12
- package/src/canvas/iframe-editable-root.ts +29 -16
- package/src/canvas/iframe-entry.ts +80 -63
- package/src/canvas/iframe-eval.ts +73 -49
- package/src/canvas/iframe-host.ts +203 -118
- package/src/canvas/iframe-inline-edit.ts +69 -32
- package/src/canvas/iframe-insert.ts +5 -4
- package/src/canvas/iframe-interaction.ts +37 -26
- package/src/canvas/iframe-overlay.ts +1 -1
- package/src/canvas/iframe-patch.ts +18 -15
- package/src/canvas/iframe-position.ts +12 -6
- package/src/canvas/iframe-protocol.ts +15 -16
- package/src/canvas/iframe-render.ts +41 -36
- package/src/canvas/iframe-slash.ts +24 -11
- package/src/canvas/iframe-subtree.ts +6 -2
- package/src/canvas/path-mapping.ts +19 -12
- package/src/canvas/popover-path.ts +7 -3
- package/src/canvas/popover-state.ts +1 -2
- package/src/canvas/serialize-scope.ts +13 -5
- package/src/canvas/stage-scrollbar.ts +2 -1
- package/src/canvas/surface-registry.ts +21 -3
- package/src/collab/collab-commands.ts +7 -2
- package/src/collab/collab-session.ts +84 -45
- package/src/collab/collab-state.ts +4 -3
- package/src/collab/monaco-binding.ts +16 -13
- package/src/collab/monaco-cursors.ts +5 -2
- package/src/commands/budget.ts +3 -3
- package/src/commands/command-args.ts +103 -71
- package/src/commands/context.ts +22 -20
- package/src/commands/defaults.ts +4 -1
- package/src/commands/keymap.ts +47 -43
- package/src/commands/levels.ts +3 -3
- package/src/commands/live-context.ts +10 -8
- package/src/commands/reference.ts +2 -1
- package/src/commands/registry.ts +12 -10
- package/src/commands/run-reported.ts +15 -10
- package/src/component-props.ts +46 -30
- package/src/content/collection-match.ts +5 -4
- package/src/content/draft-state.ts +4 -3
- package/src/content/entry-commands.ts +3 -2
- package/src/content/entry-editor.ts +29 -17
- package/src/content/entry-fields.ts +12 -7
- package/src/content/entry-model.ts +21 -12
- package/src/editor/canvas-context-menu.ts +1 -2
- package/src/editor/canvas-slash-bridge.ts +3 -6
- package/src/editor/content-slice.ts +16 -14
- package/src/editor/context-menu.ts +35 -22
- package/src/editor/convert-targets.ts +30 -35
- package/src/editor/convert-to-component.ts +11 -5
- package/src/editor/convert-to-repeater.ts +34 -22
- package/src/editor/editable-tags.ts +17 -2
- package/src/editor/file-drop-action.ts +21 -22
- package/src/editor/inline-edit-apply.ts +35 -17
- package/src/editor/inline-edit.ts +66 -50
- package/src/editor/inline-format.ts +59 -56
- package/src/editor/inline-link.ts +40 -15
- package/src/editor/insert-zone-action.ts +1 -1
- package/src/editor/merge-tags.ts +58 -19
- package/src/editor/repeater-scope.ts +39 -28
- package/src/editor/shortcuts.ts +87 -47
- package/src/editor/slash-menu.ts +1 -6
- package/src/files/asset-versions.ts +4 -4
- package/src/files/components.ts +15 -10
- package/src/files/elements.ts +5 -6
- package/src/files/file-ops.ts +77 -36
- package/src/files/files.ts +90 -95
- package/src/files/media-meta.ts +2 -1
- package/src/files/media-paths.ts +6 -1
- package/src/files/serialize-document.ts +2 -2
- package/src/format/constraints.ts +1 -1
- package/src/format/convert-file.ts +27 -13
- package/src/format/format-choices.ts +2 -1
- package/src/format/format-host.ts +76 -50
- package/src/github/github-auth-status.ts +27 -3
- package/src/github/github-auth.ts +19 -9
- package/src/github/github-publish.ts +24 -20
- package/src/grid/cell-editors.ts +46 -31
- package/src/grid/cell-popovers.ts +5 -3
- package/src/grid/edit-buffer.ts +10 -9
- package/src/grid/grid-controller.ts +20 -22
- package/src/grid/grid-layout.ts +21 -5
- package/src/grid/grid-open.ts +3 -6
- package/src/grid/grid-panel.ts +11 -4
- package/src/grid/grid-source.ts +8 -8
- package/src/grid/grid-view.ts +14 -17
- package/src/grid/redirects-grid.ts +14 -5
- package/src/grid/redirects.ts +16 -14
- package/src/grid/schema-columns.ts +25 -19
- package/src/grid/sources/connector-source.ts +47 -20
- package/src/grid/sources/content-source.ts +25 -24
- package/src/grid/sources/csv-file-source.ts +2 -2
- package/src/grid/tabulator-tables.d.ts +55 -34
- package/src/hosting/stage.ts +7 -7
- package/src/i18n/i18n-commands.ts +1 -2
- package/src/media/media-pane.ts +4 -1
- package/src/new-project/add-repo-modal.ts +20 -19
- package/src/new-project/import-tab.ts +10 -14
- package/src/new-project/location-fields.ts +2 -1
- package/src/new-project/new-project-modal.ts +12 -9
- package/src/packages/jxsuite-update.ts +4 -3
- package/src/packages/pull-package-sync.ts +26 -25
- package/src/page-params.ts +97 -68
- package/src/panels/activity-panel.ts +17 -9
- package/src/panels/ai-chat/attached-context.ts +13 -7
- package/src/panels/ai-chat/chat-view.ts +80 -73
- package/src/panels/ai-chat/composer.ts +30 -33
- package/src/panels/ai-chat/sessions-view.ts +1 -2
- package/src/panels/ai-panel.ts +23 -20
- package/src/panels/block-action-bar.ts +46 -35
- package/src/panels/bottom-dock.ts +5 -3
- package/src/panels/canvas-dnd-bridge.ts +31 -24
- package/src/panels/data-explorer.ts +62 -25
- package/src/panels/data-grid.ts +14 -11
- package/src/panels/dnd.ts +108 -118
- package/src/panels/editors.ts +55 -22
- package/src/panels/elements-panel.ts +10 -3
- package/src/panels/events-panel.ts +84 -69
- package/src/panels/formula-workspace.ts +76 -51
- package/src/panels/frontmatter-fields.ts +24 -19
- package/src/panels/frontmatter-panel.ts +44 -34
- package/src/panels/git-diff-open.ts +4 -4
- package/src/panels/git-panel.ts +49 -61
- package/src/panels/head-panel.ts +131 -111
- package/src/panels/i18n-panel.ts +10 -3
- package/src/panels/imports-panel.ts +23 -47
- package/src/panels/jump-bar.ts +48 -29
- package/src/panels/layers-panel.ts +97 -74
- package/src/panels/left-panel.ts +3 -3
- package/src/panels/pane-context.ts +31 -22
- package/src/panels/pane-grid.ts +49 -20
- package/src/panels/panel-registry.ts +22 -37
- package/src/panels/properties-panel.ts +175 -121
- package/src/panels/quick-search.ts +53 -31
- package/src/panels/right-panel.ts +3 -3
- package/src/panels/seo-modal.ts +13 -17
- package/src/panels/settings-menu.ts +15 -15
- package/src/panels/signals-panel.ts +153 -131
- package/src/panels/statement-editor.ts +230 -140
- package/src/panels/style-panel.ts +254 -216
- package/src/panels/style-utils.ts +114 -51
- package/src/panels/stylebook-doc.ts +57 -54
- package/src/panels/stylebook-layers-panel.ts +9 -9
- package/src/panels/stylebook-panel.ts +13 -17
- package/src/panels/tab-drop.ts +27 -11
- package/src/panels/tab-strip.ts +36 -26
- package/src/platform-errors.ts +57 -43
- package/src/platform.ts +58 -30
- package/src/platforms/cloud.ts +345 -175
- package/src/platforms/default-platform.ts +10 -4
- package/src/platforms/devserver.ts +174 -127
- package/src/platforms/read-batcher.ts +16 -8
- package/src/project-list.ts +2 -1
- package/src/publish/deploy-checklist.ts +8 -2
- package/src/publish/pages-service.ts +28 -13
- package/src/publish/publish-commands.ts +5 -4
- package/src/publish/publish-panel.ts +10 -6
- package/src/recent-projects.ts +15 -8
- package/src/resize-edges.ts +26 -36
- package/src/services/a11y-report.ts +26 -19
- package/src/services/agent-seed.ts +23 -11
- package/src/services/ai-ask.ts +9 -12
- package/src/services/ai-command-tools.ts +68 -62
- package/src/services/ai-import-tools.ts +80 -67
- package/src/services/ai-models.ts +17 -13
- package/src/services/ai-project-tools.ts +68 -32
- package/src/services/ai-session-store.ts +19 -10
- package/src/services/ai-system-prompt.ts +46 -20
- package/src/services/ai-tools.ts +71 -27
- package/src/services/ai-write-report.ts +20 -12
- package/src/services/ai-writes.ts +4 -4
- package/src/services/automation.ts +58 -31
- package/src/services/cem-export.ts +149 -58
- package/src/services/clock.ts +6 -1
- package/src/services/code-services.ts +37 -31
- package/src/services/context-manager.ts +14 -10
- package/src/services/context-resolver.ts +20 -8
- package/src/services/data-service.ts +19 -15
- package/src/services/directory-picker.ts +18 -12
- package/src/services/document-assistant.ts +39 -19
- package/src/services/gated-registry.ts +10 -6
- package/src/services/harness/chat-reducer.ts +23 -1
- package/src/services/import-client.ts +91 -38
- package/src/services/import-seed.ts +8 -2
- package/src/services/jx-validate.ts +28 -31
- package/src/services/live-preview.ts +0 -0
- package/src/services/live-surfaces.ts +6 -3
- package/src/services/model-uri.ts +10 -2
- package/src/services/module-preloads.ts +12 -8
- package/src/services/monaco-buffer.ts +43 -24
- package/src/services/monaco-lazy.ts +7 -8
- package/src/services/monaco-setup.ts +23 -16
- package/src/services/notify.ts +44 -17
- package/src/services/popover-report.ts +25 -10
- package/src/services/preview-eval.ts +20 -8
- package/src/services/profile.ts +13 -6
- package/src/services/project-path.ts +13 -10
- package/src/services/references.ts +0 -0
- package/src/services/render-critic.ts +8 -7
- package/src/services/settings/kernel.ts +13 -4
- package/src/services/settings/write-queue.ts +9 -9
- package/src/services/token-lint.ts +12 -10
- package/src/services/tool-executor.ts +17 -5
- package/src/services/tool-outcomes.ts +44 -24
- package/src/services/trusted-types.ts +24 -7
- package/src/settings/contexts-section.ts +11 -8
- package/src/settings/contributed-section.ts +79 -60
- package/src/settings/css-vars-editor.ts +37 -16
- package/src/settings/defs-editor.ts +38 -35
- package/src/settings/extension-rows.ts +16 -8
- package/src/settings/extension-sections.ts +23 -13
- package/src/settings/extensions-section.ts +4 -1
- package/src/settings/general-settings.ts +11 -8
- package/src/settings/locales-section.ts +20 -12
- package/src/settings/preferences-dialog.ts +9 -6
- package/src/settings/preferences-keymap.ts +7 -5
- package/src/settings/preferences-sections.ts +11 -5
- package/src/settings/project-sections.ts +1 -1
- package/src/settings/schema-field-ui.ts +9 -0
- package/src/settings/settings-document.ts +5 -5
- package/src/shell/tree.ts +6 -5
- package/src/shell.ts +104 -81
- package/src/site-context.ts +37 -22
- package/src/state.ts +41 -49
- package/src/store.ts +54 -34
- package/src/studio.ts +39 -77
- package/src/style/live-preview.ts +1 -1
- package/src/style/project-styles.ts +6 -7
- package/src/style/token-ref.ts +5 -4
- package/src/surfaces/about.ts +18 -19
- package/src/surfaces/add-repo.ts +17 -19
- package/src/surfaces/ai-chat.ts +31 -36
- package/src/surfaces/ai-credentials-form.ts +6 -16
- package/src/surfaces/ai-managed-connect.ts +3 -4
- package/src/surfaces/ai-model-picker.ts +3 -5
- package/src/surfaces/block-action-bar.ts +22 -11
- package/src/surfaces/boot-failure.ts +4 -5
- package/src/surfaces/bottom-dock.ts +9 -18
- package/src/surfaces/canvas-stage.ts +12 -11
- package/src/surfaces/cf-account-picker.ts +17 -18
- package/src/surfaces/commandbar.ts +14 -9
- package/src/surfaces/convert-repeater.ts +17 -19
- package/src/surfaces/data-actions.ts +9 -7
- package/src/surfaces/dialog.ts +26 -28
- package/src/surfaces/diff-toolbar.ts +9 -7
- package/src/surfaces/doc-header.ts +10 -19
- package/src/surfaces/empty-state.ts +7 -10
- package/src/surfaces/entry-editor.ts +14 -11
- package/src/surfaces/expression-editor.ts +11 -25
- package/src/surfaces/files-panel.ts +27 -14
- package/src/surfaces/formula-palette.ts +4 -5
- package/src/surfaces/git-panel.ts +7 -15
- package/src/surfaces/github-auth.ts +16 -20
- package/src/surfaces/github-publish.ts +17 -22
- package/src/surfaces/grid-cell.ts +30 -31
- package/src/surfaces/grid-open.ts +10 -14
- package/src/surfaces/grid-panel.ts +13 -9
- package/src/surfaces/grid-replace.ts +13 -13
- package/src/surfaces/grid-views.ts +15 -18
- package/src/surfaces/inspector-dock.ts +13 -12
- package/src/surfaces/jump-bar.ts +5 -6
- package/src/surfaces/jxsuite-update.ts +16 -22
- package/src/surfaces/library-pane.ts +25 -20
- package/src/surfaces/logic-panel.ts +17 -30
- package/src/surfaces/logic-workspace.ts +13 -15
- package/src/surfaces/media-browser.ts +11 -10
- package/src/surfaces/media-field.ts +4 -5
- package/src/surfaces/media-pane.ts +8 -7
- package/src/surfaces/menu.ts +29 -23
- package/src/surfaces/navigator-dock.ts +11 -12
- package/src/surfaces/new-project.ts +27 -26
- package/src/surfaces/pane-context.ts +20 -25
- package/src/surfaces/pane-grid.ts +15 -10
- package/src/surfaces/panel-activity.ts +5 -6
- package/src/surfaces/panel-data.ts +3 -4
- package/src/surfaces/panel-deploy-checklist.ts +5 -6
- package/src/surfaces/panel-elements.ts +5 -7
- package/src/surfaces/panel-i18n.ts +5 -7
- package/src/surfaces/panel-imports.ts +6 -13
- package/src/surfaces/panel-outline.ts +25 -19
- package/src/surfaces/panel-page.ts +11 -18
- package/src/surfaces/panel-problems.ts +5 -7
- package/src/surfaces/panel-signals.ts +20 -34
- package/src/surfaces/panel-stylebook-layers.ts +5 -8
- package/src/surfaces/preferences.ts +21 -11
- package/src/surfaces/progress-modal.ts +15 -9
- package/src/surfaces/properties-panel.json +1 -1
- package/src/surfaces/properties-panel.ts +20 -42
- package/src/surfaces/publish.ts +18 -18
- package/src/surfaces/push-plan.ts +7 -8
- package/src/surfaces/rail.json +126 -73
- package/src/surfaces/rail.ts +38 -12
- package/src/surfaces/reference-field.ts +11 -15
- package/src/surfaces/schema-builder.ts +16 -22
- package/src/surfaces/schema-form.ts +15 -25
- package/src/surfaces/secret-field.ts +9 -6
- package/src/surfaces/seo.ts +21 -15
- package/src/surfaces/settings-contexts.ts +9 -7
- package/src/surfaces/settings-contributed.ts +14 -10
- package/src/surfaces/settings-css-vars.ts +5 -12
- package/src/surfaces/settings-defs.json +2 -2
- package/src/surfaces/settings-defs.ts +17 -21
- package/src/surfaces/settings-deploy.ts +8 -15
- package/src/surfaces/settings-extensions.ts +5 -6
- package/src/surfaces/settings-head.ts +33 -39
- package/src/surfaces/settings-locales.ts +8 -20
- package/src/surfaces/settings-overview.ts +5 -6
- package/src/surfaces/settings-packages.ts +8 -7
- package/src/surfaces/settings-pane.ts +9 -18
- package/src/surfaces/settings-rawjson.ts +5 -6
- package/src/surfaces/shell.ts +1 -2
- package/src/surfaces/slash-menu.ts +19 -9
- package/src/surfaces/statements.ts +13 -18
- package/src/surfaces/statusbar.ts +17 -14
- package/src/surfaces/style-panel.ts +18 -31
- package/src/surfaces/stylebook-chrome.ts +3 -5
- package/src/surfaces/tab-strip.ts +14 -13
- package/src/surfaces/target-line.ts +6 -7
- package/src/surfaces/welcome.ts +5 -7
- package/src/tabs/patch-ops.ts +4 -3
- package/src/tabs/project-config.ts +32 -21
- package/src/tabs/selection.ts +36 -8
- package/src/tabs/tab.ts +52 -41
- package/src/tabs/transact.ts +98 -53
- package/src/tabs/typing.ts +31 -0
- package/src/types.ts +32 -17
- package/src/ui/ai-credentials-form.ts +10 -13
- package/src/ui/ai-model-picker.ts +3 -3
- package/src/ui/cf-account-picker.ts +7 -9
- package/src/ui/color-selector.ts +9 -5
- package/src/ui/dynamic-slot.ts +7 -8
- package/src/ui/expression-editor.ts +112 -105
- package/src/ui/form-controls.ts +57 -48
- package/src/ui/formula-catalog.ts +239 -230
- package/src/ui/formula-chips.ts +33 -18
- package/src/ui/layers.ts +44 -31
- package/src/ui/media-picker.ts +18 -9
- package/src/ui/popover-surface.ts +20 -12
- package/src/ui/progress-modal.ts +13 -8
- package/src/ui/regions.ts +7 -6
- package/src/ui/schema-form.ts +113 -70
- package/src/ui/surface.ts +71 -8
- package/src/ui/timing.ts +9 -0
- package/src/ui/value-source.ts +44 -31
- package/src/ui/virtual-window.ts +3 -2
- package/src/utils/base64.ts +3 -1
- package/src/utils/edit-display.ts +103 -74
- package/src/utils/element-selectors.ts +3 -2
- package/src/utils/google-fonts.ts +15 -14
- package/src/utils/inherited-style.ts +18 -20
- package/src/utils/link-target.ts +1 -1
- package/src/utils/preview-format.ts +25 -3
- package/src/utils/strip-events.ts +49 -22
- package/src/utils/studio-utils.ts +29 -14
- package/src/view.ts +2 -3
- package/src/workspace/pane-derive.ts +10 -12
- package/src/workspace/session.ts +53 -43
- package/src/workspace/workspace.ts +47 -36
- package/dist/chunks/2020-nkxms0ay.js +0 -4
- package/dist/chunks/adapter-m948ab5f.js +0 -4
- package/dist/chunks/cf-account-picker-n8hr38v7.js +0 -4
- package/dist/chunks/cf-settings-356xdtne.js +0 -4
- package/dist/chunks/color-area-jqhna8zy.js +0 -4
- package/dist/chunks/color-field-embq5ctg.js +0 -4
- package/dist/chunks/color-fpezvnkt.js +0 -4
- package/dist/chunks/color-slider-1qmw7wqy.js +0 -4
- package/dist/chunks/combobox-773hdzyj.js +0 -4
- package/dist/chunks/components-yk3t844e.js +0 -4
- package/dist/chunks/content-source-bawmyc09.js +0 -4
- package/dist/chunks/convert-to-repeater-7wns8kf1.js +0 -4
- package/dist/chunks/dialog-mtm9fq5t.js +0 -4
- package/dist/chunks/editor-6sc8nacq.js +0 -4
- package/dist/chunks/entry-commands-8ay9fh81.js +0 -4
- package/dist/chunks/extension-sections-na7rj3nr.js +0 -4
- package/dist/chunks/file-ops-gye0qw56.js +0 -4
- package/dist/chunks/files-dmc2xvcq.js +0 -4
- package/dist/chunks/format-host-t76b53f8.js +0 -4
- package/dist/chunks/fs-events-cg4tpz06.js +0 -4
- package/dist/chunks/git-panel-yef7bshy.js +0 -4
- package/dist/chunks/grid-view-7tt4bxw1.js +0 -51
- package/dist/chunks/icons-qbh8akb1.js +0 -4
- package/dist/chunks/iframe-entry-f7mqjwpm.js +0 -5
- package/dist/chunks/iframe-entry-haw7jkvz.js +0 -5
- package/dist/chunks/iframe-entry-z6qrytv3.js +0 -5
- package/dist/chunks/iframe-host-tmz30gfp.js +0 -4
- package/dist/chunks/index-nag78a9h.js +0 -4
- package/dist/chunks/jsonMode-zhwsprqk.js +0 -13
- package/dist/chunks/jx-validate-3gbp5nkn.js +0 -4
- package/dist/chunks/layers-fvz99859.js +0 -4
- package/dist/chunks/layers-panel-gchmbf9p.js +0 -4
- package/dist/chunks/listbox-s8fkmnq8.js +0 -4
- package/dist/chunks/lit-html-9agdspkt.js +0 -4
- package/dist/chunks/media-picker-rhjvyy00.js +0 -4
- package/dist/chunks/menu-2e4y9j7b.js +0 -4
- package/dist/chunks/menu-37d07z9m.js +0 -4
- package/dist/chunks/monaco-binding-2jnhjjvr.js +0 -4
- package/dist/chunks/monaco-buffer-rp21359g.js +0 -4
- package/dist/chunks/monaco-setup-vhh7gayr.js +0 -4
- package/dist/chunks/notify-h3www560.js +0 -4
- package/dist/chunks/number-field-gw7sq8rn.js +0 -4
- package/dist/chunks/parse-897fvqah.js +0 -4
- package/dist/chunks/platform-hz34wcd7.js +0 -4
- package/dist/chunks/popover-8htra4er.js +0 -4
- package/dist/chunks/publish-panel-exsmjzyj.js +0 -4
- package/dist/chunks/quick-search-pgaqeh0m.js +0 -4
- package/dist/chunks/references-2cgdxnb8.js +0 -4
- package/dist/chunks/right-panel-jf856w5w.js +0 -4
- package/dist/chunks/section-registry-jnf8r5gy.js +0 -4
- package/dist/chunks/select-n3v7gwas.js +0 -4
- package/dist/chunks/split-pff8f3ze.js +0 -4
- package/dist/chunks/studio-0f55h9ye.js +0 -5
- package/dist/chunks/studio-0sqdhnew.js +0 -12
- package/dist/chunks/studio-19x1c75w.js +0 -5
- package/dist/chunks/studio-2sqcndak.js +0 -5
- package/dist/chunks/studio-3aey7dd3.js +0 -5
- package/dist/chunks/studio-3bpdkq2s.js +0 -5
- package/dist/chunks/studio-47y6fbpf.js +0 -5
- package/dist/chunks/studio-4m3826v2.js +0 -5
- package/dist/chunks/studio-4nx2dj1g.js +0 -4
- package/dist/chunks/studio-4xv5s47r.js +0 -9
- package/dist/chunks/studio-5g4t8v6w.js +0 -5
- package/dist/chunks/studio-5py436sf.js +0 -5
- package/dist/chunks/studio-77kt594t.js +0 -5
- package/dist/chunks/studio-8f87n763.js +0 -10
- package/dist/chunks/studio-8mb00b84.js +0 -5
- package/dist/chunks/studio-8p51gq2h.js +0 -6
- package/dist/chunks/studio-954ds834.js +0 -5
- package/dist/chunks/studio-9ft45c83.js +0 -9
- package/dist/chunks/studio-a2138x5k.js +0 -7
- package/dist/chunks/studio-a9yzstqj.js +0 -5
- package/dist/chunks/studio-acdksxx6.js +0 -5
- package/dist/chunks/studio-ar8jcf2y.js +0 -5
- package/dist/chunks/studio-bmn4mn9j.js +0 -7
- package/dist/chunks/studio-e7xxa0sj.js +0 -5
- package/dist/chunks/studio-ecaz25vk.js +0 -5
- package/dist/chunks/studio-ery42sqr.js +0 -4
- package/dist/chunks/studio-fzdywr6p.js +0 -9
- package/dist/chunks/studio-g5fmf0c1.js +0 -5
- package/dist/chunks/studio-g7nse7zb.js +0 -5
- package/dist/chunks/studio-geq1ea6k.js +0 -14
- package/dist/chunks/studio-ghkb32r8.js +0 -5
- package/dist/chunks/studio-ghrhy2y7.js +0 -5
- package/dist/chunks/studio-grawhey1.js +0 -5
- package/dist/chunks/studio-h0xgswew.js +0 -5
- package/dist/chunks/studio-h9c4p2tx.js +0 -5
- package/dist/chunks/studio-jyzj5cxs.js +0 -5
- package/dist/chunks/studio-mgx8yhnz.js +0 -64
- package/dist/chunks/studio-mpb04y1d.js +0 -6
- package/dist/chunks/studio-n17mty64.js +0 -5
- package/dist/chunks/studio-nwh2eqsk.js +0 -6
- package/dist/chunks/studio-q1h883bt.js +0 -16
- package/dist/chunks/studio-q4tv82h7.js +0 -9
- package/dist/chunks/studio-qpqa7vk3.js +0 -5
- package/dist/chunks/studio-qqz8e5gk.js +0 -5
- package/dist/chunks/studio-qvasen3f.js +0 -5
- package/dist/chunks/studio-rggdb3hm.js +0 -5
- package/dist/chunks/studio-sghy936h.js +0 -4
- package/dist/chunks/studio-skprc6ef.js +0 -5
- package/dist/chunks/studio-tt2nactf.js +0 -5
- package/dist/chunks/studio-tyasmc39.js +0 -5
- package/dist/chunks/studio-vk9ezads.js +0 -5
- package/dist/chunks/studio-vzacdfsc.js +0 -4
- package/dist/chunks/studio-w4c0xmrw.js +0 -5
- package/dist/chunks/studio-wfjqhhbk.js +0 -5
- package/dist/chunks/studio-wgh5kxpj.js +0 -5
- package/dist/chunks/studio-xasj0796.js +0 -5
- package/dist/chunks/studio-y78s8r2n.js +0 -5
- package/dist/chunks/studio-z8w183sh.js +0 -5
- package/dist/chunks/studio-zscd9ty4.js +0 -928
- package/dist/chunks/studio-zxp13sss.js +0 -7
- package/dist/chunks/studio-zygnmm01.js +0 -5
- package/dist/chunks/swatch-group-8qh9a3bm.js +0 -4
- package/dist/chunks/tabs-jwthg40w.js +0 -4
- package/dist/chunks/textfield-spy3hc77.js +0 -4
- package/dist/chunks/toast-4d35zd64.js +0 -4
- package/dist/chunks/toast-host-8sjmfed3.js +0 -4
- package/dist/chunks/tooltip-fd6g9xy3.js +0 -4
- package/dist/chunks/tree-h19v1jfz.js +0 -4
- package/dist/chunks/tsMode-gr0m4dzr.js +0 -14
- package/dist/chunks/workspace-m15qtcqp.js +0 -4
- package/dist/chunks/ws-client-nf61frr1.js +0 -4
package/src/ui/value-source.ts
CHANGED
|
@@ -43,7 +43,16 @@ import {
|
|
|
43
43
|
tagExpressionSchema,
|
|
44
44
|
tagNameSchema,
|
|
45
45
|
} from "@jxsuite/schema/defs";
|
|
46
|
-
import {
|
|
46
|
+
import {
|
|
47
|
+
isFunctionDef,
|
|
48
|
+
isJsonObject,
|
|
49
|
+
isNonNullObject,
|
|
50
|
+
isRef,
|
|
51
|
+
isString,
|
|
52
|
+
isTemplateString,
|
|
53
|
+
} from "@jxsuite/schema/guards";
|
|
54
|
+
import type { ReadonlyJsonObject, ReadonlyJsonValue } from "@jxsuite/schema/project-schemas";
|
|
55
|
+
import type { JsonValue, JxDocumentValue } from "@jxsuite/schema/types";
|
|
47
56
|
|
|
48
57
|
/** A rung of the value ladder — one way a document position can produce its value. */
|
|
49
58
|
export type SlotMode = "literal" | "ref" | "template" | "expression" | "function";
|
|
@@ -73,7 +82,7 @@ export const VALUE_SOURCE_HINTS: Record<SlotMode, string> = {
|
|
|
73
82
|
};
|
|
74
83
|
|
|
75
84
|
/** Detect which rung of the ladder a raw document value occupies. */
|
|
76
|
-
export function slotMode(value:
|
|
85
|
+
export function slotMode(value: JxDocumentValue | JsonValue | undefined): SlotMode {
|
|
77
86
|
if (isRef(value)) {
|
|
78
87
|
return "ref";
|
|
79
88
|
}
|
|
@@ -83,7 +92,7 @@ export function slotMode(value: unknown): SlotMode {
|
|
|
83
92
|
if (isTemplateString(value)) {
|
|
84
93
|
return "template";
|
|
85
94
|
}
|
|
86
|
-
if (value &&
|
|
95
|
+
if (isNonNullObject(value) && "$expression" in value) {
|
|
87
96
|
return "expression";
|
|
88
97
|
}
|
|
89
98
|
return "literal";
|
|
@@ -91,8 +100,6 @@ export function slotMode(value: unknown): SlotMode {
|
|
|
91
100
|
|
|
92
101
|
// ─── Schema walk ────────────────────────────────────────────────────────────
|
|
93
102
|
|
|
94
|
-
type SchemaNode = Record<string, unknown>;
|
|
95
|
-
|
|
96
103
|
/**
|
|
97
104
|
* The `on*` property shape that `@jxsuite/schema`'s generator synthesises for every EventHandler
|
|
98
105
|
* IDL attribute (`buildEventHandlerProperties`). It is the only slot position with no declared
|
|
@@ -107,40 +114,45 @@ export const EVENT_HANDLER_SCHEMA = {
|
|
|
107
114
|
} as const;
|
|
108
115
|
|
|
109
116
|
/** The `$defs` a slot position can actually reach. Anything else is a bug, not a silent no-rung. */
|
|
110
|
-
const REACHABLE_DEFS
|
|
111
|
-
ExpressionEntry
|
|
112
|
-
FunctionDef
|
|
113
|
-
RefObject
|
|
114
|
-
StyleObject
|
|
115
|
-
|
|
117
|
+
const REACHABLE_DEFS = new Map<string, ReadonlyJsonObject>([
|
|
118
|
+
["ExpressionEntry", expressionEntrySchema],
|
|
119
|
+
["FunctionDef", functionDefSchema],
|
|
120
|
+
["RefObject", refObjectSchema],
|
|
121
|
+
["StyleObject", styleObjectSchema],
|
|
122
|
+
]);
|
|
116
123
|
|
|
117
124
|
/** A `{ $ref: … }` binding object: `required: ["$ref"]` with a `$ref` property. */
|
|
118
|
-
function isRefObjectSchema(node:
|
|
119
|
-
const { required } = node;
|
|
125
|
+
function isRefObjectSchema(node: ReadonlyJsonObject): boolean {
|
|
126
|
+
const { properties, required } = node;
|
|
120
127
|
return (
|
|
121
128
|
Array.isArray(required) &&
|
|
122
129
|
required.includes("$ref") &&
|
|
123
|
-
|
|
130
|
+
isJsonObject(properties) &&
|
|
131
|
+
Boolean(properties.$ref)
|
|
124
132
|
);
|
|
125
133
|
}
|
|
126
134
|
|
|
127
135
|
/** A `{ $expression: … }` entry. */
|
|
128
|
-
function isExpressionEntrySchema(node:
|
|
136
|
+
function isExpressionEntrySchema(node: ReadonlyJsonObject): boolean {
|
|
129
137
|
const { required } = node;
|
|
130
138
|
return Array.isArray(required) && required.includes("$expression");
|
|
131
139
|
}
|
|
132
140
|
|
|
133
141
|
/** A `$prototype: "Function"` declaration. */
|
|
134
|
-
function isFunctionDefSchema(node:
|
|
135
|
-
const
|
|
136
|
-
return
|
|
142
|
+
function isFunctionDefSchema(node: ReadonlyJsonObject): boolean {
|
|
143
|
+
const { properties } = node;
|
|
144
|
+
return (
|
|
145
|
+
isJsonObject(properties) &&
|
|
146
|
+
isJsonObject(properties.$prototype) &&
|
|
147
|
+
properties.$prototype.const === "Function"
|
|
148
|
+
);
|
|
137
149
|
}
|
|
138
150
|
|
|
139
151
|
/**
|
|
140
152
|
* A string branch that will accept `${…}`. A pattern/enum/const-constrained string will not — a
|
|
141
153
|
* `TagName` or a `#/state/…` pointer is a string, but not a place a template may be typed.
|
|
142
154
|
*/
|
|
143
|
-
function isFreeStringSchema(node:
|
|
155
|
+
function isFreeStringSchema(node: ReadonlyJsonObject): boolean {
|
|
144
156
|
return (
|
|
145
157
|
node.type === "string" &&
|
|
146
158
|
node.pattern === undefined &&
|
|
@@ -155,23 +167,24 @@ interface WalkState {
|
|
|
155
167
|
found: Set<SlotMode>;
|
|
156
168
|
/** Pointers the walk could not resolve — surfaced so a schema move fails loudly. */
|
|
157
169
|
unresolved: Set<string>;
|
|
158
|
-
seen: Set<
|
|
170
|
+
seen: Set<ReadonlyJsonObject>;
|
|
159
171
|
}
|
|
160
172
|
|
|
161
|
-
function walk(
|
|
162
|
-
|
|
173
|
+
function walk(schema: ReadonlyJsonValue | undefined, state: WalkState): void {
|
|
174
|
+
/* An array is an object too, but it names no keyword: the walk below found nothing in one, so
|
|
175
|
+
refusing it here is the same answer reached sooner. */
|
|
176
|
+
if (!isJsonObject(schema)) {
|
|
163
177
|
return;
|
|
164
178
|
}
|
|
165
|
-
const schema = node as SchemaNode;
|
|
166
179
|
if (state.seen.has(schema)) {
|
|
167
180
|
return;
|
|
168
181
|
}
|
|
169
182
|
state.seen.add(schema);
|
|
170
183
|
|
|
171
|
-
const pointer =
|
|
184
|
+
const pointer = isString(schema.$ref) ? schema.$ref : undefined;
|
|
172
185
|
if (pointer !== undefined && Object.keys(schema).length === 1) {
|
|
173
186
|
const name = pointer.startsWith("#/$defs/") ? pointer.slice("#/$defs/".length) : pointer;
|
|
174
|
-
const target = REACHABLE_DEFS
|
|
187
|
+
const target = REACHABLE_DEFS.get(name);
|
|
175
188
|
if (target) {
|
|
176
189
|
walk(target, state);
|
|
177
190
|
} else {
|
|
@@ -218,7 +231,7 @@ function walk(node: unknown, state: WalkState): void {
|
|
|
218
231
|
state.found.add("literal");
|
|
219
232
|
return;
|
|
220
233
|
}
|
|
221
|
-
if (
|
|
234
|
+
if (isString(schema.type) && SCALAR_TYPES.has(schema.type)) {
|
|
222
235
|
state.found.add("literal");
|
|
223
236
|
}
|
|
224
237
|
}
|
|
@@ -230,7 +243,7 @@ export interface DerivedCaps {
|
|
|
230
243
|
}
|
|
231
244
|
|
|
232
245
|
/** Derive the rungs a subschema permits, and report any pointer the walk could not follow. */
|
|
233
|
-
export function deriveSlotCapsDetailed(schema:
|
|
246
|
+
export function deriveSlotCapsDetailed(schema: ReadonlyJsonValue | undefined): DerivedCaps {
|
|
234
247
|
const state: WalkState = { found: new Set(), seen: new Set(), unresolved: new Set() };
|
|
235
248
|
walk(schema, state);
|
|
236
249
|
return {
|
|
@@ -240,7 +253,7 @@ export function deriveSlotCapsDetailed(schema: unknown): DerivedCaps {
|
|
|
240
253
|
}
|
|
241
254
|
|
|
242
255
|
/** Derive the rungs a subschema permits, in ladder order. */
|
|
243
|
-
export function deriveSlotCaps(schema:
|
|
256
|
+
export function deriveSlotCaps(schema: ReadonlyJsonValue | undefined): SlotMode[] {
|
|
244
257
|
return deriveSlotCapsDetailed(schema).caps;
|
|
245
258
|
}
|
|
246
259
|
|
|
@@ -322,7 +335,7 @@ export type SlotPosition = keyof typeof SLOT_POSITION_SCHEMAS;
|
|
|
322
335
|
* There is deliberately no third form. A caller may not state which rungs it wants: the rungs are
|
|
323
336
|
* derived from a schema or they are not derived at all.
|
|
324
337
|
*/
|
|
325
|
-
export type SlotCapsSource = SlotPosition | { schema:
|
|
338
|
+
export type SlotCapsSource = SlotPosition | { schema: ReadonlyJsonValue };
|
|
326
339
|
|
|
327
340
|
const capsCache = new Map<SlotPosition, SlotMode[]>();
|
|
328
341
|
|
|
@@ -339,7 +352,7 @@ export function capsForPosition(position: SlotPosition): SlotMode[] {
|
|
|
339
352
|
|
|
340
353
|
/** The rungs on offer for a {@link SlotCapsSource} — a named position, or a schema handed in. */
|
|
341
354
|
export function slotCaps(source: SlotCapsSource): SlotMode[] {
|
|
342
|
-
return
|
|
355
|
+
return isString(source) ? capsForPosition(source) : deriveSlotCaps(source.schema);
|
|
343
356
|
}
|
|
344
357
|
|
|
345
358
|
/**
|
|
@@ -351,7 +364,7 @@ export function slotCaps(source: SlotCapsSource): SlotMode[] {
|
|
|
351
364
|
* own config at runtime — which no plugin schema declares because it is not the plugin's to
|
|
352
365
|
* declare. Both are stated here, once, rather than assumed at each form.
|
|
353
366
|
*/
|
|
354
|
-
export function configFieldSchema(field:
|
|
367
|
+
export function configFieldSchema(field: ReadonlyJsonValue): ReadonlyJsonObject {
|
|
355
368
|
const declared = deriveSlotCaps(field).length > 0 ? field : { type: "string" };
|
|
356
369
|
return { anyOf: [declared, { $ref: "#/$defs/RefObject" }] };
|
|
357
370
|
}
|
package/src/ui/virtual-window.ts
CHANGED
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
|
|
29
29
|
/// <reference lib="dom" />
|
|
30
30
|
|
|
31
|
+
import { isFunction } from "@jxsuite/schema/guards";
|
|
31
32
|
import { rectOf } from "../utils/geometry";
|
|
32
33
|
|
|
33
34
|
/** The measurement a window is computed from. Everything is in CSS pixels. */
|
|
@@ -244,7 +245,7 @@ export function createVirtualWindow(options: VirtualWindowOptions): VirtualWindo
|
|
|
244
245
|
};
|
|
245
246
|
|
|
246
247
|
let resizeObserver: ResizeObserver | null = null;
|
|
247
|
-
if (
|
|
248
|
+
if (isFunction(globalThis.ResizeObserver)) {
|
|
248
249
|
resizeObserver = new ResizeObserver(measureNextFrame);
|
|
249
250
|
resizeObserver.observe(scroller);
|
|
250
251
|
if (list) {
|
|
@@ -373,7 +374,7 @@ export function listWindow(
|
|
|
373
374
|
return computeWindow({
|
|
374
375
|
columns: spec.columns ?? 1,
|
|
375
376
|
count: spec.count,
|
|
376
|
-
|
|
377
|
+
overscanRows: spec.overscanRows ?? DEFAULT_OVERSCAN_ROWS,
|
|
377
378
|
rowHeight: spec.rowHeight,
|
|
378
379
|
scrollTop: listScrollTop(scroller, list),
|
|
379
380
|
viewportHeight: scroller.clientHeight,
|
package/src/utils/base64.ts
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
* backends answer a base64 string for the same reason they accept one, and the caller wants bytes.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
+
import { isString } from "@jxsuite/schema/guards";
|
|
15
|
+
|
|
14
16
|
/** Bytes per `String.fromCodePoint` call — spreading a whole large file blows the call stack. */
|
|
15
17
|
const CHUNK = 32_768;
|
|
16
18
|
|
|
@@ -28,7 +30,7 @@ export function bytesToBase64(bytes: Uint8Array): string {
|
|
|
28
30
|
* have always received base64 strings, so existing callers keep working.
|
|
29
31
|
*/
|
|
30
32
|
export async function toBase64(data: string | File | Blob | ArrayBuffer): Promise<string> {
|
|
31
|
-
if (
|
|
33
|
+
if (isString(data)) {
|
|
32
34
|
return data;
|
|
33
35
|
}
|
|
34
36
|
const buffer = data instanceof ArrayBuffer ? data : await data.arrayBuffer();
|
|
@@ -5,18 +5,50 @@
|
|
|
5
5
|
* placeholders).
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { JxMutableNode } from "@jxsuite/schema/types";
|
|
9
|
-
import { displayTagName } from "@jxsuite/schema/guards";
|
|
8
|
+
import type { JxDocumentValue, JxMutableNode } from "@jxsuite/schema/types";
|
|
9
|
+
import { displayTagName, isNodeObject, isNonNullObject, isString } from "@jxsuite/schema/guards";
|
|
10
|
+
import { isDocumentContainer } from "./strip-events";
|
|
11
|
+
import type { RebuiltNode } from "./strip-events";
|
|
10
12
|
|
|
11
13
|
const mediaTags = new Set(["img", "video", "source", "iframe", "audio"]);
|
|
12
|
-
|
|
14
|
+
/** A 1×1 transparent GIF: what an unresolvable `src` binding shows in edit mode. */
|
|
15
|
+
export const TRANSPARENT_PX =
|
|
13
16
|
"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
|
14
17
|
// A neutral, visible gray placeholder for image-like bindings in edit mode (e.g. a component `image`
|
|
15
18
|
// Prop bound to ${...}). The component renders <img src={prop}> internally, so a transparent pixel
|
|
16
19
|
// Would collapse to nothing — a gray SVG box reads as an intentional placeholder instead.
|
|
17
|
-
const PLACEHOLDER_IMG =
|
|
20
|
+
export const PLACEHOLDER_IMG =
|
|
18
21
|
"data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='32'%20height='32'%3E%3Crect%20width='32'%20height='32'%20fill='%23d0d0d0'/%3E%3C/svg%3E";
|
|
19
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Swap every image under `host` that fails to load for {@link PLACEHOLDER_IMG}, until `signal`
|
|
25
|
+
* aborts.
|
|
26
|
+
*
|
|
27
|
+
* For previews drawn in the PARENT realm, where nothing ran {@link prepareForEditMode}: a library
|
|
28
|
+
* card's file, a component whose image prop is a `${}` binding with nothing to bind it, a document
|
|
29
|
+
* whose `src` is empty. The browser drew each as its broken-image glyph. `error` does not bubble,
|
|
30
|
+
* so the listener captures — which also covers images a preview renders after it is mounted. An
|
|
31
|
+
* empty `src` fires `error` too, so it needs no separate test; an image already showing the
|
|
32
|
+
* placeholder is left alone, so a placeholder that cannot load (it always can) does not loop.
|
|
33
|
+
*
|
|
34
|
+
* @param {Element} host
|
|
35
|
+
* @param {AbortSignal} signal
|
|
36
|
+
*/
|
|
37
|
+
export function placeholderBrokenImages(host: Element, signal: AbortSignal): void {
|
|
38
|
+
host.addEventListener(
|
|
39
|
+
"error",
|
|
40
|
+
(event) => {
|
|
41
|
+
const { target } = event;
|
|
42
|
+
if (target instanceof HTMLImageElement && target.getAttribute("src") !== PLACEHOLDER_IMG) {
|
|
43
|
+
target.setAttribute("src", PLACEHOLDER_IMG);
|
|
44
|
+
target.removeAttribute("srcset");
|
|
45
|
+
target.dataset.placeholder = "";
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
{ capture: true, signal },
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
20
52
|
// Prop/attribute names that feed an <img>/background, so a ${...} binding would otherwise render a
|
|
21
53
|
// Broken image in edit mode. Matched by exact name or common camelCase suffix (featuredImage, heroBg).
|
|
22
54
|
const IMAGE_KEY_RE =
|
|
@@ -132,6 +164,7 @@ export function templateToEditDisplay(str: string) {
|
|
|
132
164
|
export function restoreTemplateExpressions(el: HTMLElement) {
|
|
133
165
|
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
|
|
134
166
|
while (walker.nextNode()) {
|
|
167
|
+
// SAFETY: the walker was created with NodeFilter.SHOW_TEXT, so every node it stops on is Text.
|
|
135
168
|
const node = walker.currentNode as Text;
|
|
136
169
|
if (node.data.includes("\u276A")) {
|
|
137
170
|
node.data = node.data.replaceAll(/\u276A\s*(.*?)\s*\u276B/g, "${$1}");
|
|
@@ -146,52 +179,64 @@ export function restoreTemplateExpressions(el: HTMLElement) {
|
|
|
146
179
|
* edit-only device — it is never compiled or rendered in preview.
|
|
147
180
|
*
|
|
148
181
|
* @param {JxMutableNode} arrayObj
|
|
149
|
-
* @returns {
|
|
182
|
+
* @returns {JxMutableNode}
|
|
150
183
|
*/
|
|
151
|
-
function arrayToPerimeter(arrayObj: JxMutableNode):
|
|
184
|
+
function arrayToPerimeter(arrayObj: JxMutableNode): JxMutableNode {
|
|
152
185
|
const template = arrayObj.map;
|
|
153
186
|
return {
|
|
154
|
-
children:
|
|
155
|
-
template && typeof template === "object"
|
|
156
|
-
? [prepareForEditMode(template as JxMutableNode)]
|
|
157
|
-
: [],
|
|
187
|
+
children: isNonNullObject(template) ? [prepareForEditMode(template)] : [],
|
|
158
188
|
className: "repeater-perimeter",
|
|
159
189
|
tagName: "div",
|
|
160
190
|
};
|
|
161
191
|
}
|
|
162
192
|
|
|
193
|
+
/**
|
|
194
|
+
* The text a `$ref` binding shows in edit mode: its pointer, with the `#/state/` prefix dropped.
|
|
195
|
+
*
|
|
196
|
+
* @param {string} ref
|
|
197
|
+
*/
|
|
198
|
+
function refDisplayLabel(ref: string): string {
|
|
199
|
+
const label = ref.startsWith("#/state/") ? ref.slice(8) : ref;
|
|
200
|
+
return `{${label}}`;
|
|
201
|
+
}
|
|
202
|
+
|
|
163
203
|
/**
|
|
164
204
|
* Prepare a document for edit-mode rendering. Replaces template strings with readable literal text,
|
|
165
205
|
* $prototype:Array with placeholders, and $ref bindings with display labels. Preserves state so the
|
|
166
|
-
* runtime can still initialise scope.
|
|
206
|
+
* runtime can still initialise scope. Arrays are prepared member by member, and primitives and a
|
|
207
|
+
* cleared (`undefined`) key return unchanged, so the walker can recurse through any document
|
|
208
|
+
* value.
|
|
167
209
|
*
|
|
168
210
|
* @param {JxMutableNode} node
|
|
169
211
|
* @returns {JxMutableNode}
|
|
170
212
|
*/
|
|
171
|
-
export function prepareForEditMode(node: JxMutableNode): JxMutableNode
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
213
|
+
export function prepareForEditMode(node: JxMutableNode): JxMutableNode;
|
|
214
|
+
export function prepareForEditMode(node: JxDocumentValue): JxDocumentValue;
|
|
215
|
+
export function prepareForEditMode(node: JxDocumentValue | undefined): JxDocumentValue | undefined;
|
|
216
|
+
export function prepareForEditMode(node: JxDocumentValue | undefined): JxDocumentValue | undefined {
|
|
175
217
|
if (Array.isArray(node)) {
|
|
176
218
|
// Arrays of nodes round-trip element-wise; the array itself is not a node.
|
|
177
|
-
return
|
|
219
|
+
return node.map((n) => prepareForEditMode(n));
|
|
220
|
+
}
|
|
221
|
+
if (!isNodeObject(node)) {
|
|
222
|
+
return node;
|
|
178
223
|
}
|
|
179
224
|
|
|
180
225
|
// A mapped-array node itself → its edit-mode perimeter (e.g. when the patcher re-renders an
|
|
181
226
|
// Array node directly). Members inside a children array funnel here via the children branch.
|
|
182
|
-
if (
|
|
183
|
-
return arrayToPerimeter(node)
|
|
227
|
+
if (node.$prototype === "Array") {
|
|
228
|
+
return arrayToPerimeter(node);
|
|
184
229
|
}
|
|
185
230
|
|
|
186
|
-
const
|
|
231
|
+
const obj = node;
|
|
187
232
|
|
|
188
|
-
const out:
|
|
233
|
+
const out: RebuiltNode = {};
|
|
189
234
|
let needsMediaPlaceholder = false;
|
|
190
|
-
const isMediaElement = mediaTags.has(
|
|
235
|
+
const isMediaElement = isString(obj.tagName) && mediaTags.has(obj.tagName);
|
|
191
236
|
|
|
192
237
|
// Check if this media element lacks a resolvable src (top-level or in attributes)
|
|
193
238
|
if (isMediaElement) {
|
|
194
|
-
const attrs = obj.attributes
|
|
239
|
+
const attrs = obj.attributes;
|
|
195
240
|
const topSrc = obj.src;
|
|
196
241
|
const attrSrc = attrs?.src;
|
|
197
242
|
const topPoster = obj.poster;
|
|
@@ -206,11 +251,11 @@ export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
|
|
|
206
251
|
for (const [k, v] of Object.entries(obj)) {
|
|
207
252
|
if (k === "state" || k === "$media" || k === "$elements") {
|
|
208
253
|
out[k] = v; // Preserve as-is for runtime resolution
|
|
209
|
-
} else if (k === "$props" && v
|
|
254
|
+
} else if (k === "$props" && isDocumentContainer(v)) {
|
|
210
255
|
// Process $props values: convert template strings to display format
|
|
211
|
-
const propsOut:
|
|
256
|
+
const propsOut: RebuiltNode = {};
|
|
212
257
|
for (const [pk, pv] of Object.entries(v)) {
|
|
213
|
-
if (
|
|
258
|
+
if (isString(pv) && pv.includes("${")) {
|
|
214
259
|
// Image-like prop → neutral placeholder (the component renders it as an <img src>); link
|
|
215
260
|
// Targets → inert ""; everything else → the readable ❪ expr ❫ binding text.
|
|
216
261
|
if (isImageUrlKey(pk)) {
|
|
@@ -220,10 +265,8 @@ export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
|
|
|
220
265
|
} else {
|
|
221
266
|
propsOut[pk] = templateToEditDisplay(pv);
|
|
222
267
|
}
|
|
223
|
-
} else if (pv &&
|
|
224
|
-
|
|
225
|
-
const label = ref.startsWith("#/state/") ? ref.slice(8) : ref;
|
|
226
|
-
propsOut[pk] = `{${label}}`;
|
|
268
|
+
} else if (isNodeObject(pv) && pv.$ref) {
|
|
269
|
+
propsOut[pk] = refDisplayLabel(pv.$ref);
|
|
227
270
|
} else {
|
|
228
271
|
propsOut[pk] = pv;
|
|
229
272
|
}
|
|
@@ -233,25 +276,21 @@ export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
|
|
|
233
276
|
if (Array.isArray(v)) {
|
|
234
277
|
// Each member recurses; array pseudo-elements become a single repeater-perimeter element
|
|
235
278
|
// (via the top-level array case) so they stay a 1:1 DOM node among their siblings.
|
|
236
|
-
out.children = v.map((c) => prepareForEditMode(c
|
|
237
|
-
} else if (
|
|
238
|
-
v &&
|
|
239
|
-
typeof v === "object" &&
|
|
240
|
-
(v as Record<string, unknown>).$prototype === "Array"
|
|
241
|
-
) {
|
|
279
|
+
out.children = v.map((c) => prepareForEditMode(c));
|
|
280
|
+
} else if (isNodeObject(v) && v.$prototype === "Array") {
|
|
242
281
|
// Legacy whole-children repeater → a single perimeter as the sole child.
|
|
243
|
-
out.children = [prepareForEditMode(v
|
|
282
|
+
out.children = [prepareForEditMode(v)];
|
|
244
283
|
} else {
|
|
245
|
-
out.children = prepareForEditMode(v
|
|
284
|
+
out.children = prepareForEditMode(v);
|
|
246
285
|
}
|
|
247
|
-
} else if (k === "cases" && obj.$switch && v
|
|
286
|
+
} else if (k === "cases" && obj.$switch && isDocumentContainer(v)) {
|
|
248
287
|
// Replace $switch cases with a placeholder showing the first case or a label
|
|
249
|
-
const
|
|
250
|
-
if (
|
|
251
|
-
const firstCase =
|
|
288
|
+
const [firstEntry] = Object.entries(v);
|
|
289
|
+
if (firstEntry) {
|
|
290
|
+
const [, firstCase] = firstEntry;
|
|
252
291
|
out.children =
|
|
253
|
-
firstCase &&
|
|
254
|
-
? [prepareForEditMode(firstCase
|
|
292
|
+
isDocumentContainer(firstCase) && !(isNodeObject(firstCase) && firstCase.$ref)
|
|
293
|
+
? [prepareForEditMode(firstCase)]
|
|
255
294
|
: [
|
|
256
295
|
{
|
|
257
296
|
style: {
|
|
@@ -265,29 +304,26 @@ export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
|
|
|
265
304
|
padding: "6px 10px",
|
|
266
305
|
},
|
|
267
306
|
tagName: "div",
|
|
268
|
-
textContent: `[$switch: ${
|
|
307
|
+
textContent: `[$switch: ${Object.keys(v).join(" | ")}]`,
|
|
269
308
|
},
|
|
270
309
|
];
|
|
271
310
|
}
|
|
272
|
-
} else if (k === "attributes" && isMediaElement && v
|
|
311
|
+
} else if (k === "attributes" && isMediaElement && isDocumentContainer(v)) {
|
|
273
312
|
// Process attributes for media elements: replace src/poster with transparent pixel
|
|
274
|
-
const
|
|
275
|
-
const
|
|
276
|
-
for (const [ak, av] of Object.entries(attrs)) {
|
|
313
|
+
const processed: RebuiltNode = {};
|
|
314
|
+
for (const [ak, av] of Object.entries(v)) {
|
|
277
315
|
if (ak === "src" || ak === "poster") {
|
|
278
|
-
if (
|
|
316
|
+
if (isString(av) && av !== "" && !av.includes("${")) {
|
|
279
317
|
processed[ak] = av;
|
|
280
318
|
} else {
|
|
281
319
|
needsMediaPlaceholder = true;
|
|
282
320
|
processed[ak] = TRANSPARENT_PX;
|
|
283
321
|
}
|
|
284
|
-
} else if (
|
|
322
|
+
} else if (isString(av) && av.includes("${")) {
|
|
285
323
|
const isUrlAttr = ak === "href" || ak === "action";
|
|
286
324
|
processed[ak] = isUrlAttr ? "" : templateToEditDisplay(av);
|
|
287
|
-
} else if (av &&
|
|
288
|
-
|
|
289
|
-
const label = ref.startsWith("#/state/") ? ref.slice(8) : ref;
|
|
290
|
-
processed[ak] = `{${label}}`;
|
|
325
|
+
} else if (isNodeObject(av) && av.$ref) {
|
|
326
|
+
processed[ak] = refDisplayLabel(av.$ref);
|
|
291
327
|
} else {
|
|
292
328
|
processed[ak] = av;
|
|
293
329
|
}
|
|
@@ -298,10 +334,10 @@ export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
|
|
|
298
334
|
cannot be resolved; omitting the property lets the cascade answer, which is exactly what
|
|
299
335
|
the `""` this used to write meant while declarations went inline. As a RULE, `color: ` is
|
|
300
336
|
a malformed declaration instead of a no-op. Mirrored by iframe-patch's editModeStyle. */
|
|
301
|
-
if (v
|
|
302
|
-
const s:
|
|
337
|
+
if (isDocumentContainer(v)) {
|
|
338
|
+
const s: RebuiltNode = {};
|
|
303
339
|
for (const [sk, sv] of Object.entries(v)) {
|
|
304
|
-
if (
|
|
340
|
+
if (!isString(sv) || !sv.includes("${")) {
|
|
305
341
|
s[sk] = sv;
|
|
306
342
|
}
|
|
307
343
|
}
|
|
@@ -309,10 +345,9 @@ export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
|
|
|
309
345
|
} else {
|
|
310
346
|
out.style = v;
|
|
311
347
|
}
|
|
312
|
-
} else if (
|
|
348
|
+
} else if (isString(v) && v.includes("${")) {
|
|
313
349
|
// Template string in a display property → show raw expression
|
|
314
|
-
const isMediaSrc =
|
|
315
|
-
(k === "src" || k === "poster") && mediaTags.has((obj.tagName as string) || "");
|
|
350
|
+
const isMediaSrc = (k === "src" || k === "poster") && isMediaElement;
|
|
316
351
|
if (isMediaSrc) {
|
|
317
352
|
needsMediaPlaceholder = true;
|
|
318
353
|
out[k] = TRANSPARENT_PX;
|
|
@@ -320,42 +355,36 @@ export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
|
|
|
320
355
|
const isUrlAttr = k === "src" || k === "href" || k === "poster" || k === "action";
|
|
321
356
|
out[k] = isUrlAttr ? "" : templateToEditDisplay(v);
|
|
322
357
|
}
|
|
323
|
-
} else if (v &&
|
|
358
|
+
} else if (isNodeObject(v) && v.$ref) {
|
|
324
359
|
// $ref binding → show ref path as literal text
|
|
325
|
-
const
|
|
326
|
-
const
|
|
327
|
-
const isMediaSrc =
|
|
328
|
-
(k === "src" || k === "poster") && mediaTags.has((obj.tagName as string) || "");
|
|
360
|
+
const label = refDisplayLabel(v.$ref);
|
|
361
|
+
const isMediaSrc = (k === "src" || k === "poster") && isMediaElement;
|
|
329
362
|
if (isMediaSrc) {
|
|
330
363
|
needsMediaPlaceholder = true;
|
|
331
364
|
out[k] = TRANSPARENT_PX;
|
|
332
365
|
} else {
|
|
333
|
-
out[k] =
|
|
366
|
+
out[k] = label;
|
|
334
367
|
}
|
|
335
368
|
} else {
|
|
336
369
|
// Empty src/poster on media elements → use transparent pixel placeholder
|
|
337
|
-
if (
|
|
338
|
-
(k === "src" || k === "poster") &&
|
|
339
|
-
v === "" &&
|
|
340
|
-
mediaTags.has((obj.tagName as string) || "")
|
|
341
|
-
) {
|
|
370
|
+
if ((k === "src" || k === "poster") && v === "" && isMediaElement) {
|
|
342
371
|
needsMediaPlaceholder = true;
|
|
343
372
|
out[k] = TRANSPARENT_PX;
|
|
344
373
|
} else {
|
|
345
|
-
out[k] = prepareForEditMode(v
|
|
374
|
+
out[k] = prepareForEditMode(v);
|
|
346
375
|
}
|
|
347
376
|
}
|
|
348
377
|
}
|
|
349
378
|
|
|
350
379
|
// Mark empty elements with placeholder classes for design-mode visibility
|
|
351
|
-
const placeholderClass = computeEmptyPlaceholderClass(out
|
|
380
|
+
const placeholderClass = computeEmptyPlaceholderClass(out);
|
|
352
381
|
if (placeholderClass) {
|
|
353
382
|
out.className = out.className ? `${out.className} ${placeholderClass}` : placeholderClass;
|
|
354
383
|
}
|
|
355
384
|
|
|
356
385
|
// Media elements with missing/dynamic src get a placeholder class
|
|
357
386
|
if (needsMediaPlaceholder) {
|
|
358
|
-
const cls = (out.className
|
|
387
|
+
const cls = isString(out.className) ? out.className : "";
|
|
359
388
|
if (!cls.includes("empty-media-placeholder")) {
|
|
360
389
|
out.className = cls ? `${cls} empty-media-placeholder` : "empty-media-placeholder";
|
|
361
390
|
}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { COMMON_SELECTORS } from "../store";
|
|
17
|
-
import { displayTagName } from "@jxsuite/schema/guards";
|
|
17
|
+
import { displayTagName, isNonNullObject } from "@jxsuite/schema/guards";
|
|
18
18
|
import { isPopover } from "@jxsuite/schema/overlays";
|
|
19
19
|
import type { JxMutableNode } from "@jxsuite/schema/types";
|
|
20
20
|
|
|
@@ -62,7 +62,8 @@ function extraSelectorsFor(node: JxMutableNode): string[] {
|
|
|
62
62
|
* @returns The offerable selectors.
|
|
63
63
|
*/
|
|
64
64
|
export function selectorsForNode(node: JxMutableNode | null | undefined): string[] {
|
|
65
|
-
|
|
65
|
+
// The style panel reads the node with getNodeAtPath, which can answer a bare string text child.
|
|
66
|
+
if (!isNonNullObject(node)) {
|
|
66
67
|
return [...COMMON_SELECTORS];
|
|
67
68
|
}
|
|
68
69
|
return [...new Set([...COMMON_SELECTORS, ...extraSelectorsFor(node)])];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** Google Fonts helpers — shared between head-panel (per-page) and head-editor (project-level). */
|
|
2
2
|
|
|
3
|
+
import { isString } from "@jxsuite/schema/guards";
|
|
3
4
|
import type { JxHeadEntry } from "@jxsuite/schema/types";
|
|
4
5
|
|
|
5
6
|
export const GFONTS_CSS_PREFIX = "https://fonts.googleapis.com/css2?";
|
|
@@ -11,29 +12,30 @@ export const GFONTS_PRECONNECT_ORIGINS = [
|
|
|
11
12
|
/**
|
|
12
13
|
* Check if a `$head` entry is a Google Fonts stylesheet link.
|
|
13
14
|
*
|
|
14
|
-
* @param {JxHeadEntry} entry
|
|
15
|
+
* @param {JxHeadEntry | null | undefined} entry A `$head` slot; a JSON array can hold `null`.
|
|
15
16
|
* @returns {boolean}
|
|
16
17
|
*/
|
|
17
|
-
export function isGoogleFontEntry(entry: JxHeadEntry) {
|
|
18
|
+
export function isGoogleFontEntry(entry: JxHeadEntry | null | undefined) {
|
|
18
19
|
return (
|
|
19
20
|
entry?.tagName === "link" &&
|
|
20
|
-
entry
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
entry.attributes?.rel === "stylesheet" &&
|
|
22
|
+
isString(entry.attributes.href) &&
|
|
23
|
+
entry.attributes.href.startsWith(GFONTS_CSS_PREFIX)
|
|
23
24
|
);
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
28
|
* Check if a `$head` entry is a Google Fonts preconnect link.
|
|
28
29
|
*
|
|
29
|
-
* @param {JxHeadEntry} entry
|
|
30
|
+
* @param {JxHeadEntry | null | undefined} entry A `$head` slot; a JSON array can hold `null`.
|
|
30
31
|
* @returns {boolean}
|
|
31
32
|
*/
|
|
32
|
-
export function isGoogleFontPreconnect(entry: JxHeadEntry) {
|
|
33
|
+
export function isGoogleFontPreconnect(entry: JxHeadEntry | null | undefined) {
|
|
33
34
|
return (
|
|
34
35
|
entry?.tagName === "link" &&
|
|
35
|
-
entry
|
|
36
|
-
|
|
36
|
+
entry.attributes?.rel === "preconnect" &&
|
|
37
|
+
isString(entry.attributes.href) &&
|
|
38
|
+
GFONTS_PRECONNECT_ORIGINS.includes(entry.attributes.href)
|
|
37
39
|
);
|
|
38
40
|
}
|
|
39
41
|
|
|
@@ -68,14 +70,13 @@ export function buildGoogleFontUrl(family: string) {
|
|
|
68
70
|
*/
|
|
69
71
|
export function ensureGoogleFontPreconnects(head: JxHeadEntry[]) {
|
|
70
72
|
for (const origin of GFONTS_PRECONNECT_ORIGINS) {
|
|
73
|
+
// A `$head` array is JSON, so a slot can hold `null` whatever the element type says.
|
|
71
74
|
const exists = head.some(
|
|
72
|
-
(e: JxHeadEntry) =>
|
|
73
|
-
e?.tagName === "link" &&
|
|
74
|
-
e?.attributes?.rel === "preconnect" &&
|
|
75
|
-
e?.attributes?.href === origin,
|
|
75
|
+
(e: JxHeadEntry | null | undefined) =>
|
|
76
|
+
e?.tagName === "link" && e.attributes?.rel === "preconnect" && e.attributes.href === origin,
|
|
76
77
|
);
|
|
77
78
|
if (!exists) {
|
|
78
|
-
const attrs:
|
|
79
|
+
const attrs: NonNullable<JxHeadEntry["attributes"]> = {
|
|
79
80
|
href: origin,
|
|
80
81
|
rel: "preconnect",
|
|
81
82
|
};
|