@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
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,11 +5,14 @@
|
|
|
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
|
|
@@ -161,6 +164,7 @@ export function templateToEditDisplay(str: string) {
|
|
|
161
164
|
export function restoreTemplateExpressions(el: HTMLElement) {
|
|
162
165
|
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
|
|
163
166
|
while (walker.nextNode()) {
|
|
167
|
+
// SAFETY: the walker was created with NodeFilter.SHOW_TEXT, so every node it stops on is Text.
|
|
164
168
|
const node = walker.currentNode as Text;
|
|
165
169
|
if (node.data.includes("\u276A")) {
|
|
166
170
|
node.data = node.data.replaceAll(/\u276A\s*(.*?)\s*\u276B/g, "${$1}");
|
|
@@ -175,52 +179,64 @@ export function restoreTemplateExpressions(el: HTMLElement) {
|
|
|
175
179
|
* edit-only device — it is never compiled or rendered in preview.
|
|
176
180
|
*
|
|
177
181
|
* @param {JxMutableNode} arrayObj
|
|
178
|
-
* @returns {
|
|
182
|
+
* @returns {JxMutableNode}
|
|
179
183
|
*/
|
|
180
|
-
function arrayToPerimeter(arrayObj: JxMutableNode):
|
|
184
|
+
function arrayToPerimeter(arrayObj: JxMutableNode): JxMutableNode {
|
|
181
185
|
const template = arrayObj.map;
|
|
182
186
|
return {
|
|
183
|
-
children:
|
|
184
|
-
template && typeof template === "object"
|
|
185
|
-
? [prepareForEditMode(template as JxMutableNode)]
|
|
186
|
-
: [],
|
|
187
|
+
children: isNonNullObject(template) ? [prepareForEditMode(template)] : [],
|
|
187
188
|
className: "repeater-perimeter",
|
|
188
189
|
tagName: "div",
|
|
189
190
|
};
|
|
190
191
|
}
|
|
191
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
|
+
|
|
192
203
|
/**
|
|
193
204
|
* Prepare a document for edit-mode rendering. Replaces template strings with readable literal text,
|
|
194
205
|
* $prototype:Array with placeholders, and $ref bindings with display labels. Preserves state so the
|
|
195
|
-
* 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.
|
|
196
209
|
*
|
|
197
210
|
* @param {JxMutableNode} node
|
|
198
211
|
* @returns {JxMutableNode}
|
|
199
212
|
*/
|
|
200
|
-
export function prepareForEditMode(node: JxMutableNode): JxMutableNode
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
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 {
|
|
204
217
|
if (Array.isArray(node)) {
|
|
205
218
|
// Arrays of nodes round-trip element-wise; the array itself is not a node.
|
|
206
|
-
return
|
|
219
|
+
return node.map((n) => prepareForEditMode(n));
|
|
220
|
+
}
|
|
221
|
+
if (!isNodeObject(node)) {
|
|
222
|
+
return node;
|
|
207
223
|
}
|
|
208
224
|
|
|
209
225
|
// A mapped-array node itself → its edit-mode perimeter (e.g. when the patcher re-renders an
|
|
210
226
|
// Array node directly). Members inside a children array funnel here via the children branch.
|
|
211
|
-
if (
|
|
212
|
-
return arrayToPerimeter(node)
|
|
227
|
+
if (node.$prototype === "Array") {
|
|
228
|
+
return arrayToPerimeter(node);
|
|
213
229
|
}
|
|
214
230
|
|
|
215
|
-
const
|
|
231
|
+
const obj = node;
|
|
216
232
|
|
|
217
|
-
const out:
|
|
233
|
+
const out: RebuiltNode = {};
|
|
218
234
|
let needsMediaPlaceholder = false;
|
|
219
|
-
const isMediaElement = mediaTags.has(
|
|
235
|
+
const isMediaElement = isString(obj.tagName) && mediaTags.has(obj.tagName);
|
|
220
236
|
|
|
221
237
|
// Check if this media element lacks a resolvable src (top-level or in attributes)
|
|
222
238
|
if (isMediaElement) {
|
|
223
|
-
const attrs = obj.attributes
|
|
239
|
+
const attrs = obj.attributes;
|
|
224
240
|
const topSrc = obj.src;
|
|
225
241
|
const attrSrc = attrs?.src;
|
|
226
242
|
const topPoster = obj.poster;
|
|
@@ -235,11 +251,11 @@ export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
|
|
|
235
251
|
for (const [k, v] of Object.entries(obj)) {
|
|
236
252
|
if (k === "state" || k === "$media" || k === "$elements") {
|
|
237
253
|
out[k] = v; // Preserve as-is for runtime resolution
|
|
238
|
-
} else if (k === "$props" && v
|
|
254
|
+
} else if (k === "$props" && isDocumentContainer(v)) {
|
|
239
255
|
// Process $props values: convert template strings to display format
|
|
240
|
-
const propsOut:
|
|
256
|
+
const propsOut: RebuiltNode = {};
|
|
241
257
|
for (const [pk, pv] of Object.entries(v)) {
|
|
242
|
-
if (
|
|
258
|
+
if (isString(pv) && pv.includes("${")) {
|
|
243
259
|
// Image-like prop → neutral placeholder (the component renders it as an <img src>); link
|
|
244
260
|
// Targets → inert ""; everything else → the readable ❪ expr ❫ binding text.
|
|
245
261
|
if (isImageUrlKey(pk)) {
|
|
@@ -249,10 +265,8 @@ export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
|
|
|
249
265
|
} else {
|
|
250
266
|
propsOut[pk] = templateToEditDisplay(pv);
|
|
251
267
|
}
|
|
252
|
-
} else if (pv &&
|
|
253
|
-
|
|
254
|
-
const label = ref.startsWith("#/state/") ? ref.slice(8) : ref;
|
|
255
|
-
propsOut[pk] = `{${label}}`;
|
|
268
|
+
} else if (isNodeObject(pv) && pv.$ref) {
|
|
269
|
+
propsOut[pk] = refDisplayLabel(pv.$ref);
|
|
256
270
|
} else {
|
|
257
271
|
propsOut[pk] = pv;
|
|
258
272
|
}
|
|
@@ -262,25 +276,21 @@ export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
|
|
|
262
276
|
if (Array.isArray(v)) {
|
|
263
277
|
// Each member recurses; array pseudo-elements become a single repeater-perimeter element
|
|
264
278
|
// (via the top-level array case) so they stay a 1:1 DOM node among their siblings.
|
|
265
|
-
out.children = v.map((c) => prepareForEditMode(c
|
|
266
|
-
} else if (
|
|
267
|
-
v &&
|
|
268
|
-
typeof v === "object" &&
|
|
269
|
-
(v as Record<string, unknown>).$prototype === "Array"
|
|
270
|
-
) {
|
|
279
|
+
out.children = v.map((c) => prepareForEditMode(c));
|
|
280
|
+
} else if (isNodeObject(v) && v.$prototype === "Array") {
|
|
271
281
|
// Legacy whole-children repeater → a single perimeter as the sole child.
|
|
272
|
-
out.children = [prepareForEditMode(v
|
|
282
|
+
out.children = [prepareForEditMode(v)];
|
|
273
283
|
} else {
|
|
274
|
-
out.children = prepareForEditMode(v
|
|
284
|
+
out.children = prepareForEditMode(v);
|
|
275
285
|
}
|
|
276
|
-
} else if (k === "cases" && obj.$switch && v
|
|
286
|
+
} else if (k === "cases" && obj.$switch && isDocumentContainer(v)) {
|
|
277
287
|
// Replace $switch cases with a placeholder showing the first case or a label
|
|
278
|
-
const
|
|
279
|
-
if (
|
|
280
|
-
const firstCase =
|
|
288
|
+
const [firstEntry] = Object.entries(v);
|
|
289
|
+
if (firstEntry) {
|
|
290
|
+
const [, firstCase] = firstEntry;
|
|
281
291
|
out.children =
|
|
282
|
-
firstCase &&
|
|
283
|
-
? [prepareForEditMode(firstCase
|
|
292
|
+
isDocumentContainer(firstCase) && !(isNodeObject(firstCase) && firstCase.$ref)
|
|
293
|
+
? [prepareForEditMode(firstCase)]
|
|
284
294
|
: [
|
|
285
295
|
{
|
|
286
296
|
style: {
|
|
@@ -294,29 +304,26 @@ export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
|
|
|
294
304
|
padding: "6px 10px",
|
|
295
305
|
},
|
|
296
306
|
tagName: "div",
|
|
297
|
-
textContent: `[$switch: ${
|
|
307
|
+
textContent: `[$switch: ${Object.keys(v).join(" | ")}]`,
|
|
298
308
|
},
|
|
299
309
|
];
|
|
300
310
|
}
|
|
301
|
-
} else if (k === "attributes" && isMediaElement && v
|
|
311
|
+
} else if (k === "attributes" && isMediaElement && isDocumentContainer(v)) {
|
|
302
312
|
// Process attributes for media elements: replace src/poster with transparent pixel
|
|
303
|
-
const
|
|
304
|
-
const
|
|
305
|
-
for (const [ak, av] of Object.entries(attrs)) {
|
|
313
|
+
const processed: RebuiltNode = {};
|
|
314
|
+
for (const [ak, av] of Object.entries(v)) {
|
|
306
315
|
if (ak === "src" || ak === "poster") {
|
|
307
|
-
if (
|
|
316
|
+
if (isString(av) && av !== "" && !av.includes("${")) {
|
|
308
317
|
processed[ak] = av;
|
|
309
318
|
} else {
|
|
310
319
|
needsMediaPlaceholder = true;
|
|
311
320
|
processed[ak] = TRANSPARENT_PX;
|
|
312
321
|
}
|
|
313
|
-
} else if (
|
|
322
|
+
} else if (isString(av) && av.includes("${")) {
|
|
314
323
|
const isUrlAttr = ak === "href" || ak === "action";
|
|
315
324
|
processed[ak] = isUrlAttr ? "" : templateToEditDisplay(av);
|
|
316
|
-
} else if (av &&
|
|
317
|
-
|
|
318
|
-
const label = ref.startsWith("#/state/") ? ref.slice(8) : ref;
|
|
319
|
-
processed[ak] = `{${label}}`;
|
|
325
|
+
} else if (isNodeObject(av) && av.$ref) {
|
|
326
|
+
processed[ak] = refDisplayLabel(av.$ref);
|
|
320
327
|
} else {
|
|
321
328
|
processed[ak] = av;
|
|
322
329
|
}
|
|
@@ -327,10 +334,10 @@ export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
|
|
|
327
334
|
cannot be resolved; omitting the property lets the cascade answer, which is exactly what
|
|
328
335
|
the `""` this used to write meant while declarations went inline. As a RULE, `color: ` is
|
|
329
336
|
a malformed declaration instead of a no-op. Mirrored by iframe-patch's editModeStyle. */
|
|
330
|
-
if (v
|
|
331
|
-
const s:
|
|
337
|
+
if (isDocumentContainer(v)) {
|
|
338
|
+
const s: RebuiltNode = {};
|
|
332
339
|
for (const [sk, sv] of Object.entries(v)) {
|
|
333
|
-
if (
|
|
340
|
+
if (!isString(sv) || !sv.includes("${")) {
|
|
334
341
|
s[sk] = sv;
|
|
335
342
|
}
|
|
336
343
|
}
|
|
@@ -338,10 +345,9 @@ export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
|
|
|
338
345
|
} else {
|
|
339
346
|
out.style = v;
|
|
340
347
|
}
|
|
341
|
-
} else if (
|
|
348
|
+
} else if (isString(v) && v.includes("${")) {
|
|
342
349
|
// Template string in a display property → show raw expression
|
|
343
|
-
const isMediaSrc =
|
|
344
|
-
(k === "src" || k === "poster") && mediaTags.has((obj.tagName as string) || "");
|
|
350
|
+
const isMediaSrc = (k === "src" || k === "poster") && isMediaElement;
|
|
345
351
|
if (isMediaSrc) {
|
|
346
352
|
needsMediaPlaceholder = true;
|
|
347
353
|
out[k] = TRANSPARENT_PX;
|
|
@@ -349,42 +355,36 @@ export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
|
|
|
349
355
|
const isUrlAttr = k === "src" || k === "href" || k === "poster" || k === "action";
|
|
350
356
|
out[k] = isUrlAttr ? "" : templateToEditDisplay(v);
|
|
351
357
|
}
|
|
352
|
-
} else if (v &&
|
|
358
|
+
} else if (isNodeObject(v) && v.$ref) {
|
|
353
359
|
// $ref binding → show ref path as literal text
|
|
354
|
-
const
|
|
355
|
-
const
|
|
356
|
-
const isMediaSrc =
|
|
357
|
-
(k === "src" || k === "poster") && mediaTags.has((obj.tagName as string) || "");
|
|
360
|
+
const label = refDisplayLabel(v.$ref);
|
|
361
|
+
const isMediaSrc = (k === "src" || k === "poster") && isMediaElement;
|
|
358
362
|
if (isMediaSrc) {
|
|
359
363
|
needsMediaPlaceholder = true;
|
|
360
364
|
out[k] = TRANSPARENT_PX;
|
|
361
365
|
} else {
|
|
362
|
-
out[k] =
|
|
366
|
+
out[k] = label;
|
|
363
367
|
}
|
|
364
368
|
} else {
|
|
365
369
|
// Empty src/poster on media elements → use transparent pixel placeholder
|
|
366
|
-
if (
|
|
367
|
-
(k === "src" || k === "poster") &&
|
|
368
|
-
v === "" &&
|
|
369
|
-
mediaTags.has((obj.tagName as string) || "")
|
|
370
|
-
) {
|
|
370
|
+
if ((k === "src" || k === "poster") && v === "" && isMediaElement) {
|
|
371
371
|
needsMediaPlaceholder = true;
|
|
372
372
|
out[k] = TRANSPARENT_PX;
|
|
373
373
|
} else {
|
|
374
|
-
out[k] = prepareForEditMode(v
|
|
374
|
+
out[k] = prepareForEditMode(v);
|
|
375
375
|
}
|
|
376
376
|
}
|
|
377
377
|
}
|
|
378
378
|
|
|
379
379
|
// Mark empty elements with placeholder classes for design-mode visibility
|
|
380
|
-
const placeholderClass = computeEmptyPlaceholderClass(out
|
|
380
|
+
const placeholderClass = computeEmptyPlaceholderClass(out);
|
|
381
381
|
if (placeholderClass) {
|
|
382
382
|
out.className = out.className ? `${out.className} ${placeholderClass}` : placeholderClass;
|
|
383
383
|
}
|
|
384
384
|
|
|
385
385
|
// Media elements with missing/dynamic src get a placeholder class
|
|
386
386
|
if (needsMediaPlaceholder) {
|
|
387
|
-
const cls = (out.className
|
|
387
|
+
const cls = isString(out.className) ? out.className : "";
|
|
388
388
|
if (!cls.includes("empty-media-placeholder")) {
|
|
389
389
|
out.className = cls ? `${cls} empty-media-placeholder` : "empty-media-placeholder";
|
|
390
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
|
};
|