@jxsuite/studio 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/canvas.html +21 -0
- package/dist/chunks/Overlay.dev-qfjzkms8.js +23 -0
- package/dist/chunks/{Overlay.dev-cszx7yn5.js.map → Overlay.dev-qfjzkms8.js.map} +1 -1
- package/dist/chunks/{adapter-z8fkmbmv.js → adapter-qfnesn5v.js} +2 -2
- package/dist/chunks/{cf-settings-mmyv436d.js → cf-settings-73sh5z4p.js} +3 -3
- package/dist/chunks/{components-0hzentwq.js → components-2bpqp4mq.js} +5 -7
- package/dist/chunks/{components-0hzentwq.js.map → components-2bpqp4mq.js.map} +1 -1
- package/dist/chunks/content-source-34gnkbnn.js +38 -0
- package/dist/chunks/content-source-34gnkbnn.js.map +9 -0
- package/dist/chunks/convert-to-repeater-t8kxre5s.js +258 -0
- package/dist/chunks/convert-to-repeater-t8kxre5s.js.map +10 -0
- package/dist/chunks/extension-sections-6mqydz35.js +301 -0
- package/dist/chunks/extension-sections-6mqydz35.js.map +11 -0
- package/dist/chunks/files-8kn321h1.js +70 -0
- package/dist/chunks/files-8kn321h1.js.map +9 -0
- package/dist/chunks/{format-host-2c188n41.js → format-host-mkwsmt8d.js} +3 -3
- package/dist/chunks/git-panel-tjbr191d.js +51 -0
- package/dist/chunks/git-panel-tjbr191d.js.map +9 -0
- package/dist/chunks/{index-baeg2x3y.js → index-7pxchcce.js} +4 -3
- package/dist/chunks/{index-baeg2x3y.js.map → index-7pxchcce.js.map} +3 -3
- package/dist/chunks/{jx-validate-qx8degj7.js → jx-validate-v6qgknrs.js} +3 -3
- package/dist/chunks/layers-panel-87pb25km.js +58 -0
- package/dist/chunks/layers-panel-87pb25km.js.map +9 -0
- package/dist/chunks/{monaco-setup-zjdp9zdw.js → monaco-setup-e0yh25j4.js} +4 -75
- package/dist/chunks/{monaco-setup-zjdp9zdw.js.map → monaco-setup-e0yh25j4.js.map} +3 -4
- package/dist/chunks/publish-panel-m0fcgdrt.js +21 -0
- package/dist/chunks/publish-panel-m0fcgdrt.js.map +9 -0
- package/dist/chunks/quick-search-rhs6cbsb.js +53 -0
- package/dist/chunks/quick-search-rhs6cbsb.js.map +9 -0
- package/dist/chunks/right-panel-zpdxd98t.js +37 -0
- package/dist/chunks/right-panel-zpdxd98t.js.map +9 -0
- package/dist/chunks/section-registry-zmckaxf4.js +30 -0
- package/dist/chunks/section-registry-zmckaxf4.js.map +9 -0
- package/dist/chunks/sp-overlay.dev-9ran0sfq.js +18 -0
- package/dist/chunks/sp-overlay.dev-9ran0sfq.js.map +9 -0
- package/dist/chunks/sp-popover.dev-rebmdncr.js +9 -0
- package/dist/chunks/sp-popover.dev-rebmdncr.js.map +9 -0
- package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js +15 -0
- package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js.map +9 -0
- package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js +15 -0
- package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js.map +9 -0
- package/dist/chunks/{sp-tray.dev-pb2fsd65.js → sp-tray.dev-ey59vfh7.js} +10 -8
- package/dist/chunks/{sp-tray.dev-pb2fsd65.js.map → sp-tray.dev-ey59vfh7.js.map} +2 -2
- package/dist/chunks/{studio-9qr6fq7p.js → studio-0rqqhrdy.js} +10 -378
- package/dist/chunks/{studio-9qr6fq7p.js.map → studio-0rqqhrdy.js.map} +4 -14
- package/dist/chunks/{studio-5x6tqqec.js → studio-2sj1jj3v.js} +10 -8
- package/dist/chunks/{studio-5x6tqqec.js.map → studio-2sj1jj3v.js.map} +2 -2
- package/dist/chunks/{studio-h3fw0wn8.js → studio-3fk1ac9z.js} +6 -4
- package/dist/chunks/{studio-h3fw0wn8.js.map → studio-3fk1ac9z.js.map} +2 -2
- package/dist/chunks/studio-41exgzhq.js +6690 -0
- package/dist/chunks/studio-41exgzhq.js.map +38 -0
- package/dist/chunks/{studio-7v2bpweq.js → studio-4mqb9a0j.js} +6 -4
- package/dist/chunks/{studio-7v2bpweq.js.map → studio-4mqb9a0j.js.map} +2 -2
- package/dist/chunks/studio-50k77cca.js +1787 -0
- package/dist/chunks/studio-50k77cca.js.map +18 -0
- package/dist/chunks/{studio-56v3zwk6.js → studio-6a0h7sne.js} +10 -8
- package/dist/chunks/{studio-56v3zwk6.js.map → studio-6a0h7sne.js.map} +2 -2
- package/dist/chunks/studio-6f0am8f2.js +53 -0
- package/dist/chunks/studio-6f0am8f2.js.map +10 -0
- package/dist/chunks/studio-6nmjc5qk.js +7002 -0
- package/dist/chunks/studio-6nmjc5qk.js.map +32 -0
- package/dist/chunks/studio-7afd21nw.js +67 -0
- package/dist/chunks/studio-7afd21nw.js.map +10 -0
- package/dist/chunks/{studio-xze4zrs1.js → studio-7bmdvzne.js} +2 -2
- package/dist/chunks/studio-7bmdvzne.js.map +10 -0
- package/dist/chunks/studio-8jpzqk5s.js +128 -0
- package/dist/chunks/studio-8jpzqk5s.js.map +10 -0
- package/dist/chunks/studio-94m77tgk.js +1482 -0
- package/dist/chunks/studio-94m77tgk.js.map +13 -0
- package/dist/chunks/studio-9je6w5sq.js +1000 -0
- package/dist/chunks/studio-9je6w5sq.js.map +16 -0
- package/dist/chunks/{studio-w7c6kvk7.js → studio-a7pzveq1.js} +2 -2
- package/dist/chunks/{studio-97qcgvdn.js → studio-adn0z1k3.js} +14 -8
- package/dist/chunks/{studio-97qcgvdn.js.map → studio-adn0z1k3.js.map} +3 -3
- package/dist/chunks/{studio-kr88ryr7.js → studio-bsxxx3x2.js} +17 -15
- package/dist/chunks/{studio-kr88ryr7.js.map → studio-bsxxx3x2.js.map} +7 -6
- package/dist/chunks/studio-bw5dz6km.js +608 -0
- package/dist/chunks/studio-bw5dz6km.js.map +21 -0
- package/dist/chunks/studio-c6s5getc.js +4232 -0
- package/dist/chunks/studio-c6s5getc.js.map +39 -0
- package/dist/chunks/studio-cjm7fdjf.js +451 -0
- package/dist/chunks/studio-cjm7fdjf.js.map +14 -0
- package/dist/chunks/{studio-cx91mnh8.js → studio-ckwz4d3x.js} +53 -53
- package/dist/chunks/{studio-cx91mnh8.js.map → studio-ckwz4d3x.js.map} +5 -5
- package/dist/chunks/studio-dg7zyt5x.js +28 -0
- package/dist/chunks/studio-dg7zyt5x.js.map +10 -0
- package/dist/chunks/studio-dzcyvvvz.js +166 -0
- package/dist/chunks/studio-dzcyvvvz.js.map +10 -0
- package/dist/chunks/{studio-7kqe41sa.js → studio-evkr5d3b.js} +15 -7
- package/dist/chunks/{studio-7kqe41sa.js.map → studio-evkr5d3b.js.map} +5 -4
- package/dist/chunks/studio-f12h6177.js +411 -0
- package/dist/chunks/studio-f12h6177.js.map +13 -0
- package/dist/chunks/studio-hbp1s8m9.js +1817 -0
- package/dist/chunks/studio-hbp1s8m9.js.map +14 -0
- package/dist/chunks/studio-k2sxjph5.js +15295 -0
- package/dist/chunks/studio-k2sxjph5.js.map +235 -0
- package/dist/chunks/studio-myje51t3.js +385 -0
- package/dist/chunks/studio-myje51t3.js.map +12 -0
- package/dist/chunks/studio-na6rwzhw.js +353 -0
- package/dist/chunks/studio-na6rwzhw.js.map +11 -0
- package/dist/chunks/{studio-4k0m4fmp.js → studio-p471gg5n.js} +126 -3
- package/dist/chunks/studio-p471gg5n.js.map +14 -0
- package/dist/chunks/{studio-9bjwf0d4.js → studio-rgwcpast.js} +5 -46
- package/dist/chunks/{studio-9bjwf0d4.js.map → studio-rgwcpast.js.map} +4 -5
- package/dist/chunks/{studio-hhj92gcr.js → studio-s519zc99.js} +3 -3
- package/dist/chunks/studio-sas7mt3k.js +75 -0
- package/dist/chunks/studio-sas7mt3k.js.map +10 -0
- package/dist/chunks/studio-t5wqwzdh.js +74 -0
- package/dist/chunks/studio-t5wqwzdh.js.map +10 -0
- package/dist/chunks/{studio-9qpspwfn.js → studio-temv5bw4.js} +5 -5
- package/dist/chunks/{studio-9qpspwfn.js.map → studio-temv5bw4.js.map} +1 -1
- package/dist/chunks/{studio-qkvt37c0.js → studio-tr20m8g8.js} +669 -18
- package/dist/chunks/studio-tr20m8g8.js.map +9 -0
- package/dist/chunks/{studio-ygzav7z5.js → studio-v96qfnww.js} +5514 -4291
- package/dist/chunks/studio-v96qfnww.js.map +54 -0
- package/dist/chunks/studio-vcetc91k.js +659 -0
- package/dist/chunks/studio-vcetc91k.js.map +10 -0
- package/dist/chunks/{studio-n9zmpxjg.js → studio-vmymjefp.js} +2972 -4937
- package/dist/chunks/studio-vmymjefp.js.map +98 -0
- package/dist/chunks/{studio-bghqfmea.js → studio-wwseqyw0.js} +2 -2
- package/dist/chunks/studio-x9hmy5kr.js +390 -0
- package/dist/chunks/studio-x9hmy5kr.js.map +10 -0
- package/dist/chunks/studio-xa0ce0n7.js +335 -0
- package/dist/chunks/studio-xa0ce0n7.js.map +10 -0
- package/dist/chunks/studio-xm3dbxvn.js +378 -0
- package/dist/chunks/studio-xm3dbxvn.js.map +19 -0
- package/dist/chunks/{studio-nqw433kv.js → studio-xmvbhg31.js} +2 -2
- package/dist/chunks/studio-zv37yrfa.js +1054 -0
- package/dist/chunks/studio-zv37yrfa.js.map +13 -0
- package/dist/chunks/{ws-client-q7hkz3j9.js → ws-client-654ts66j.js} +6 -4
- package/dist/chunks/ws-client-654ts66j.js.map +11 -0
- package/dist/iframe-entry.js +668 -230
- package/dist/studio.js +23711 -35185
- package/index.html +35 -4685
- package/package.json +17 -15
- package/src/about/about-modal.ts +42 -11
- package/src/browse/library-commands.ts +240 -0
- package/src/browse/library-layouts.ts +369 -0
- package/src/browse/library-model.ts +396 -0
- package/src/browse/library-pane.ts +1049 -0
- package/src/browse/library-preview.ts +252 -0
- package/src/browse/library-source.ts +150 -0
- package/src/canvas/canvas-helpers.ts +33 -9
- package/src/canvas/canvas-live-render.ts +45 -29
- package/src/canvas/canvas-patcher.ts +151 -31
- package/src/canvas/canvas-perf.ts +46 -7
- package/src/canvas/canvas-render.ts +1092 -220
- package/src/canvas/canvas-surface.ts +240 -0
- package/src/canvas/canvas-utils.ts +1166 -124
- package/src/canvas/iframe-drop.ts +2 -1
- package/src/canvas/iframe-entry.ts +241 -4
- package/src/canvas/iframe-host.ts +1226 -143
- package/src/canvas/iframe-inline-edit.ts +31 -0
- package/src/canvas/iframe-interaction.ts +76 -16
- package/src/canvas/iframe-keys.ts +107 -45
- package/src/canvas/iframe-overlay.ts +38 -1
- package/src/canvas/iframe-protocol.ts +137 -2
- package/src/canvas/iframe-render.ts +70 -2
- package/src/canvas/iframe-slash.ts +6 -0
- package/src/canvas/path-mapping.ts +56 -6
- package/src/canvas/surface-registry.ts +292 -0
- package/src/collab/collab-commands.ts +244 -0
- package/src/collab/collab-session.ts +198 -32
- package/src/collab/collab-state.ts +28 -2
- package/src/collab/presence-chips.ts +100 -9
- package/src/commands/active-registry.ts +42 -0
- package/src/commands/app-commands.ts +176 -0
- package/src/commands/budget.ts +158 -0
- package/src/commands/command-args.ts +253 -0
- package/src/commands/context.ts +387 -0
- package/src/commands/defaults.ts +580 -0
- package/src/commands/keymap.ts +571 -0
- package/src/commands/levels.ts +345 -0
- package/src/commands/live-context.ts +193 -0
- package/src/commands/reference.ts +227 -0
- package/src/commands/registry.ts +293 -0
- package/src/component-props.ts +3 -2
- package/src/content/draft-state.ts +106 -0
- package/src/content/entry-commands.ts +282 -0
- package/src/content/entry-editor.ts +327 -0
- package/src/content/entry-fields.ts +116 -0
- package/src/content/entry-model.ts +175 -0
- package/src/editor/canvas-context-menu.ts +17 -11
- package/src/editor/canvas-slash-bridge.ts +11 -4
- package/src/editor/context-menu.ts +804 -204
- package/src/editor/convert-to-component.ts +31 -10
- package/src/editor/convert-to-repeater.ts +3 -2
- package/src/editor/inline-edit-apply.ts +5 -5
- package/src/editor/inline-edit.ts +86 -50
- package/src/editor/insert-zone-action.ts +1 -1
- package/src/editor/shortcuts.ts +1043 -329
- package/src/editor/slash-menu.ts +1 -0
- package/src/files/elements.ts +166 -0
- package/src/files/file-ops.ts +178 -31
- package/src/files/files.ts +898 -268
- package/src/files/fs-events.ts +21 -0
- package/src/files/media-meta.ts +203 -0
- package/src/files/media-paths.ts +141 -0
- package/src/files/media-upload.ts +7 -3
- package/src/files/media-usage.ts +189 -0
- package/src/github/github-auth.ts +235 -33
- package/src/github/github-publish.ts +80 -21
- package/src/grid/grid-controller.ts +152 -12
- package/src/grid/grid-layout.ts +225 -20
- package/src/grid/grid-open.ts +120 -0
- package/src/grid/grid-panel.ts +554 -39
- package/src/grid/grid-source.ts +27 -1
- package/src/grid/redirects-grid.ts +599 -0
- package/src/grid/redirects.ts +398 -0
- package/src/grid/sources/content-source.ts +108 -2
- package/src/i18n/i18n-commands.ts +322 -0
- package/src/new-project/add-repo-modal.ts +8 -10
- package/src/new-project/import-tab.ts +34 -9
- package/src/new-project/location-fields.ts +9 -1
- package/src/new-project/new-project-modal.ts +270 -262
- package/src/packages/jxsuite-update.ts +97 -48
- package/src/packages/pull-package-sync.ts +18 -9
- package/src/page-params.ts +2 -1
- package/src/panels/activity-bar.ts +152 -91
- package/src/panels/activity-panel.ts +481 -0
- package/src/panels/ai-chat/chat-markdown.ts +8 -3
- package/src/panels/ai-chat/chat-view.ts +245 -18
- package/src/panels/ai-chat/composer.ts +31 -5
- package/src/panels/ai-chat/sessions-view.ts +17 -10
- package/src/panels/ai-panel.ts +279 -120
- package/src/panels/block-action-bar.ts +1115 -224
- package/src/panels/bottom-dock.ts +337 -0
- package/src/panels/canvas-dnd-bridge.ts +37 -8
- package/src/panels/chat-panel.ts +29 -12
- package/src/panels/data-explorer.ts +254 -112
- package/src/panels/data-grid.ts +10 -4
- package/src/panels/dnd.ts +28 -51
- package/src/panels/editors.ts +434 -107
- package/src/panels/elements-panel.ts +66 -2
- package/src/panels/empty-state.ts +112 -0
- package/src/panels/events-panel.ts +596 -82
- package/src/panels/formula-workspace.ts +408 -218
- package/src/panels/frontmatter-fields.ts +51 -10
- package/src/panels/frontmatter-panel.ts +357 -79
- package/src/panels/git-panel.ts +375 -164
- package/src/panels/head-panel.ts +791 -85
- package/src/panels/i18n-panel.ts +592 -0
- package/src/panels/imports-panel.ts +95 -85
- package/src/panels/jump-bar.ts +584 -0
- package/src/panels/layers-panel.ts +1106 -328
- package/src/panels/left-panel.ts +109 -204
- package/src/panels/navigator-panels.ts +131 -0
- package/src/panels/overlays.ts +7 -2
- package/src/panels/pane-context.ts +1477 -0
- package/src/panels/pane-grid.ts +406 -0
- package/src/panels/panel-registry.ts +340 -0
- package/src/panels/panel-scheduler.ts +75 -0
- package/src/panels/problems-panel.ts +234 -0
- package/src/panels/properties-panel.ts +946 -1139
- package/src/panels/provenance.ts +258 -0
- package/src/panels/quick-search.ts +791 -122
- package/src/panels/right-panel.ts +228 -102
- package/src/panels/seo-modal.ts +395 -0
- package/src/panels/settings-pane.ts +203 -0
- package/src/panels/signals-panel.ts +354 -137
- package/src/panels/statement-editor.ts +41 -25
- package/src/panels/statusbar.ts +342 -106
- package/src/panels/style-panel.ts +974 -463
- package/src/panels/style-utils.ts +3 -3
- package/src/panels/stylebook-doc.ts +4 -2
- package/src/panels/stylebook-layers-panel.ts +3 -2
- package/src/panels/stylebook-panel.ts +51 -26
- package/src/panels/tab-strip.ts +1058 -78
- package/src/panels/target-line.ts +274 -0
- package/src/panels/toolbar.ts +631 -484
- package/src/panels/welcome-screen.ts +301 -198
- package/src/platform-errors.ts +26 -3
- package/src/platform.ts +96 -2
- package/src/platforms/cloud.ts +71 -8
- package/src/platforms/devserver.ts +92 -29
- package/src/publish/deploy-checklist.ts +383 -0
- package/src/publish/pages-service.ts +10 -1
- package/src/publish/publish-commands.ts +218 -0
- package/src/publish/publish-panel.ts +110 -16
- package/src/recent-projects.ts +3 -2
- package/src/services/a11y-report.ts +505 -0
- package/src/services/ai-models.ts +75 -2
- package/src/services/ai-project-tools.ts +29 -10
- package/src/services/ai-system-prompt.ts +53 -14
- package/src/services/ai-tools.ts +39 -3
- package/src/services/ai-writes.ts +154 -0
- package/src/services/announce.ts +97 -0
- package/src/services/automation.ts +424 -175
- package/src/services/cem-export.ts +9 -4
- package/src/services/clock.ts +61 -0
- package/src/services/document-assistant.ts +36 -8
- package/src/services/idle.ts +179 -0
- package/src/services/import-client.ts +26 -0
- package/src/services/monaco-buffer.ts +627 -0
- package/src/services/monaco-lazy.ts +36 -0
- package/src/services/notify.ts +271 -0
- package/src/services/profile.ts +155 -0
- package/src/services/references.ts +0 -0
- package/src/services/token-lint.ts +3 -2
- package/src/services/tool-executor.ts +53 -7
- package/src/services/trusted-types.ts +123 -0
- package/src/settings/contexts-section.ts +427 -0
- package/src/settings/contributed-section.ts +149 -11
- package/src/settings/css-vars-editor.ts +306 -349
- package/src/settings/defs-editor.ts +93 -34
- package/src/settings/dependencies-editor.ts +7 -7
- package/src/settings/extension-sections.ts +37 -5
- package/src/settings/general-settings.ts +204 -121
- package/src/settings/locales-section.ts +347 -0
- package/src/settings/preferences-accounts.ts +140 -0
- package/src/settings/preferences-dialog.ts +620 -0
- package/src/settings/preferences-keymap.ts +270 -0
- package/src/settings/project-sections.ts +260 -0
- package/src/settings/section-registry.ts +169 -0
- package/src/settings/settings-document.ts +385 -0
- package/src/shell.ts +1549 -0
- package/src/site-context.ts +45 -20
- package/src/state.ts +14 -275
- package/src/store.ts +88 -43
- package/src/studio.ts +790 -346
- package/src/style/live-preview.ts +36 -0
- package/src/style/project-styles.ts +349 -0
- package/src/style/token-ref.ts +123 -0
- package/src/tabs/patch-ops.ts +16 -4
- package/src/tabs/project-config.ts +416 -0
- package/src/tabs/selection.ts +323 -0
- package/src/tabs/tab.ts +182 -47
- package/src/tabs/transact.ts +209 -28
- package/src/types.ts +68 -13
- package/src/ui/ai-credentials-form.ts +39 -35
- package/src/ui/ai-managed-connect.ts +113 -0
- package/src/ui/dynamic-slot.ts +224 -81
- package/src/ui/expression-editor.ts +71 -63
- package/src/ui/field-input.ts +4 -6
- package/src/ui/field-row.ts +215 -38
- package/src/ui/form-controls.ts +194 -7
- package/src/ui/layers.ts +492 -69
- package/src/ui/media-picker.ts +115 -25
- package/src/ui/panel-resize.ts +109 -91
- package/src/ui/progress-modal.ts +131 -50
- package/src/ui/regions.ts +462 -0
- package/src/ui/schema-form.ts +229 -45
- package/src/ui/spectrum.ts +24 -8
- package/src/ui/timing.ts +49 -0
- package/src/ui/value-selector.ts +20 -0
- package/src/ui/value-source.ts +348 -0
- package/src/ui/virtual-window.ts +400 -0
- package/src/utils/edit-display.ts +3 -2
- package/src/utils/inherited-style.ts +67 -37
- package/src/view.ts +64 -78
- package/src/workspace/pane-derive.ts +1258 -0
- package/src/workspace/session.ts +317 -0
- package/src/workspace/workspace.ts +1345 -23
- package/styles/canvas.css +653 -0
- package/styles/forced-colors.css +106 -0
- package/styles/inspector.css +1454 -0
- package/styles/overlays.css +2704 -0
- package/styles/panels.css +1701 -0
- package/styles/shell.css +1423 -0
- package/styles/tokens.css +151 -0
- package/dist/chunks/Overlay.dev-cszx7yn5.js +0 -22
- package/dist/chunks/extension-sections-qct0gt8f.js +0 -531
- package/dist/chunks/extension-sections-qct0gt8f.js.map +0 -12
- package/dist/chunks/files-02zn5y24.js +0 -50
- package/dist/chunks/files-02zn5y24.js.map +0 -9
- package/dist/chunks/git-panel-mbb0y0hz.js +0 -28
- package/dist/chunks/git-panel-mbb0y0hz.js.map +0 -9
- package/dist/chunks/layers-panel-9qekmqk1.js +0 -26
- package/dist/chunks/layers-panel-9qekmqk1.js.map +0 -9
- package/dist/chunks/settings-modal-gj0hrah4.js +0 -29
- package/dist/chunks/settings-modal-gj0hrah4.js.map +0 -9
- package/dist/chunks/sp-overlay.dev-earn5as8.js +0 -17
- package/dist/chunks/sp-overlay.dev-earn5as8.js.map +0 -9
- package/dist/chunks/sp-popover.dev-frxtfejn.js +0 -8
- package/dist/chunks/sp-popover.dev-frxtfejn.js.map +0 -9
- package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js +0 -14
- package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js.map +0 -9
- package/dist/chunks/sp-tooltip.dev-a9fywesm.js +0 -21
- package/dist/chunks/sp-tooltip.dev-a9fywesm.js.map +0 -10
- package/dist/chunks/studio-4k0m4fmp.js.map +0 -13
- package/dist/chunks/studio-568nx4t5.js +0 -469
- package/dist/chunks/studio-568nx4t5.js.map +0 -14
- package/dist/chunks/studio-9smfzqhc.js +0 -19
- package/dist/chunks/studio-9smfzqhc.js.map +0 -10
- package/dist/chunks/studio-asvf0j9e.js +0 -429
- package/dist/chunks/studio-asvf0j9e.js.map +0 -13
- package/dist/chunks/studio-d77qm3pk.js +0 -3427
- package/dist/chunks/studio-d77qm3pk.js.map +0 -26
- package/dist/chunks/studio-j6gqyjf4.js +0 -1854
- package/dist/chunks/studio-j6gqyjf4.js.map +0 -18
- package/dist/chunks/studio-n9zmpxjg.js.map +0 -115
- package/dist/chunks/studio-qkvt37c0.js.map +0 -9
- package/dist/chunks/studio-rq0vxb19.js +0 -3744
- package/dist/chunks/studio-rq0vxb19.js.map +0 -22
- package/dist/chunks/studio-wd6ewdvd.js +0 -853
- package/dist/chunks/studio-wd6ewdvd.js.map +0 -12
- package/dist/chunks/studio-xq0t7n5t.js +0 -140
- package/dist/chunks/studio-xq0t7n5t.js.map +0 -10
- package/dist/chunks/studio-xze4zrs1.js.map +0 -10
- package/dist/chunks/studio-ygzav7z5.js.map +0 -46
- package/dist/chunks/studio-zmy7241e.js +0 -399
- package/dist/chunks/studio-zmy7241e.js.map +0 -12
- package/dist/chunks/ws-client-q7hkz3j9.js.map +0 -11
- package/src/browse/browse-modal.ts +0 -69
- package/src/browse/browse.ts +0 -904
- package/src/canvas/canvas-diff.ts +0 -216
- package/src/canvas/nested-site-style.ts +0 -58
- package/src/new-project/design-fields.ts +0 -264
- package/src/new-project/templates.ts +0 -61
- package/src/panels/tab-bar.ts +0 -548
- package/src/settings/settings-modal.ts +0 -203
- /package/dist/chunks/{adapter-z8fkmbmv.js.map → adapter-qfnesn5v.js.map} +0 -0
- /package/dist/chunks/{cf-settings-mmyv436d.js.map → cf-settings-73sh5z4p.js.map} +0 -0
- /package/dist/chunks/{format-host-2c188n41.js.map → format-host-mkwsmt8d.js.map} +0 -0
- /package/dist/chunks/{jx-validate-qx8degj7.js.map → jx-validate-v6qgknrs.js.map} +0 -0
- /package/dist/chunks/{studio-w7c6kvk7.js.map → studio-a7pzveq1.js.map} +0 -0
- /package/dist/chunks/{studio-hhj92gcr.js.map → studio-s519zc99.js.map} +0 -0
- /package/dist/chunks/{studio-bghqfmea.js.map → studio-wwseqyw0.js.map} +0 -0
- /package/dist/chunks/{studio-nqw433kv.js.map → studio-xmvbhg31.js.map} +0 -0
|
@@ -2,9 +2,18 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Ai-credentials-form.ts — reusable AI provider credentials form (key / model / endpoint).
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* share state. Persists via src/services/ai-settings.ts on Save.
|
|
5
|
+
* Embedded by every host that needs a provider configured — **Preferences › Assistant** (⌘,) and the
|
|
6
|
+
* New Project modal's Import/Agent gates. All draft/model-list state lives inside the closure, so
|
|
7
|
+
* multiple instances never share state. Persists via src/services/ai-settings.ts on Save.
|
|
8
|
+
*
|
|
9
|
+
* The interim `Assistant: Settings…` dialog that used to host it is deleted: a provider key is an
|
|
10
|
+
* application setting, and the surface that owns application settings is also the one that can list
|
|
11
|
+
* it and revoke it (plan §9.3). Nothing about this form changed for the move, which is the argument
|
|
12
|
+
* for it having been a reusable form rather than a section of a dialog.
|
|
13
|
+
*
|
|
14
|
+
* Built from Spectrum controls with its layout in `styles/shell.css`: a roaming credential the user
|
|
15
|
+
* configures once does not get its own bespoke inputs, and it certainly does not get 200-character
|
|
16
|
+
* inline `style=` strings that stop responding the moment the theme changes.
|
|
8
17
|
*
|
|
9
18
|
* @license MIT
|
|
10
19
|
*/
|
|
@@ -118,35 +127,34 @@ export function createAiCredentialsForm(opts: AiCredentialsFormOptions): AiCrede
|
|
|
118
127
|
function render(): TemplateResult {
|
|
119
128
|
const haveKey = hasOpenAiKey();
|
|
120
129
|
return html`
|
|
121
|
-
<div
|
|
122
|
-
class="ai-creds-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
opts.intro === undefined
|
|
128
|
-
? html`
|
|
129
|
-
<div style="font-size:11px;color:var(--fg-dim)">
|
|
130
|
+
<div class="ai-creds-form">
|
|
131
|
+
<div class="ai-creds-title">AI provider key</div>
|
|
132
|
+
<div class="ai-creds-note">
|
|
133
|
+
${
|
|
134
|
+
opts.intro === undefined
|
|
135
|
+
? html`
|
|
130
136
|
Any OpenAI-compatible key works. Stored locally in this browser; sent only to the
|
|
131
137
|
Studio proxy (never to a third party except your chosen endpoint).
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
<
|
|
138
|
+
`
|
|
139
|
+
: opts.intro
|
|
140
|
+
}
|
|
141
|
+
</div>
|
|
142
|
+
<sp-textfield
|
|
143
|
+
class="ai-creds-field"
|
|
137
144
|
type="password"
|
|
138
|
-
|
|
145
|
+
size="s"
|
|
139
146
|
placeholder="sk-… or any compatible key"
|
|
140
147
|
.value=${keyDraft}
|
|
141
148
|
@input=${(e: Event) => {
|
|
142
149
|
keyDraft = (e.target as HTMLInputElement).value;
|
|
143
150
|
}}
|
|
144
|
-
|
|
145
|
-
<div
|
|
151
|
+
></sp-textfield>
|
|
152
|
+
<div class="ai-creds-label">Model</div>
|
|
146
153
|
${
|
|
147
154
|
availableModels.length > 0
|
|
148
155
|
? html`
|
|
149
156
|
<sp-combobox
|
|
157
|
+
class="ai-creds-field"
|
|
150
158
|
size="s"
|
|
151
159
|
allows-custom-value
|
|
152
160
|
.value=${modelDraft}
|
|
@@ -163,18 +171,18 @@ export function createAiCredentialsForm(opts: AiCredentialsFormOptions): AiCrede
|
|
|
163
171
|
</sp-combobox>
|
|
164
172
|
`
|
|
165
173
|
: html`
|
|
166
|
-
<
|
|
167
|
-
|
|
168
|
-
|
|
174
|
+
<sp-textfield
|
|
175
|
+
class="ai-creds-field"
|
|
176
|
+
size="s"
|
|
169
177
|
placeholder="Model ID (e.g. gpt-4o, claude-sonnet-4-20250514, etc.)"
|
|
170
178
|
.value=${modelDraft}
|
|
171
179
|
@input=${(e: Event) => {
|
|
172
180
|
modelDraft = (e.target as HTMLInputElement).value;
|
|
173
181
|
}}
|
|
174
|
-
|
|
182
|
+
></sp-textfield>
|
|
175
183
|
`
|
|
176
184
|
}
|
|
177
|
-
<div
|
|
185
|
+
<div class="ai-creds-models">
|
|
178
186
|
<sp-button size="s" variant="secondary" ?disabled=${modelsLoading} @click=${fetchModels}>
|
|
179
187
|
${
|
|
180
188
|
modelsLoading
|
|
@@ -184,22 +192,18 @@ export function createAiCredentialsForm(opts: AiCredentialsFormOptions): AiCrede
|
|
|
184
192
|
: "Fetch models"
|
|
185
193
|
}
|
|
186
194
|
</sp-button>
|
|
187
|
-
${
|
|
188
|
-
modelsError
|
|
189
|
-
? html`<span style="font-size:10px;color:var(--danger)">${modelsError}</span>`
|
|
190
|
-
: nothing
|
|
191
|
-
}
|
|
195
|
+
${modelsError ? html`<span class="ai-creds-error">${modelsError}</span>` : nothing}
|
|
192
196
|
</div>
|
|
193
|
-
<
|
|
194
|
-
|
|
195
|
-
|
|
197
|
+
<sp-textfield
|
|
198
|
+
class="ai-creds-field"
|
|
199
|
+
size="s"
|
|
196
200
|
placeholder="Endpoint (optional, e.g. http://localhost:11434/v1)"
|
|
197
201
|
.value=${baseUrlDraft}
|
|
198
202
|
@input=${(e: Event) => {
|
|
199
203
|
baseUrlDraft = (e.target as HTMLInputElement).value;
|
|
200
204
|
}}
|
|
201
|
-
|
|
202
|
-
<div
|
|
205
|
+
></sp-textfield>
|
|
206
|
+
<div class="ai-creds-actions">
|
|
203
207
|
${
|
|
204
208
|
haveKey
|
|
205
209
|
? html`<sp-button size="s" variant="secondary" @click=${cancel}>Cancel</sp-button>`
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
/**
|
|
3
|
+
* Ai-managed-connect.ts — the keyless "Connect Cloudflare" (Workers AI) option for credentials
|
|
4
|
+
* gates.
|
|
5
|
+
*
|
|
6
|
+
* Companion to ai-credentials-form.ts: managed platforms broker Workers AI on the user's OWN
|
|
7
|
+
* Cloudflare account, so a gate that renders only the key form strands them — they have no key, and
|
|
8
|
+
* nothing on screen offers the hosted OAuth flow that would give them working AI. Both hosts that
|
|
9
|
+
* gate on credentials (the assistant sidebar and the New Project modal's Import/Agent tabs) embed
|
|
10
|
+
* this alongside the form so both real paths are always on offer.
|
|
11
|
+
*
|
|
12
|
+
* State is per-instance (closure-scoped) like the credentials form; the capability probe behind
|
|
13
|
+
* `ensureProbe` is shared module-wide by services/ai-models.ts.
|
|
14
|
+
*
|
|
15
|
+
* @docs studio/ai
|
|
16
|
+
* @license MIT
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { html, nothing } from "lit-html";
|
|
20
|
+
import type { TemplateResult } from "lit-html";
|
|
21
|
+
import { getPlatform, hasPlatform } from "../platform";
|
|
22
|
+
import {
|
|
23
|
+
ensureProxyProbe,
|
|
24
|
+
fetchAvailableModels,
|
|
25
|
+
isManagedProxy,
|
|
26
|
+
isProxyConfigured,
|
|
27
|
+
} from "../services/ai-models";
|
|
28
|
+
|
|
29
|
+
export interface ManagedConnectOptions {
|
|
30
|
+
/** Host re-render scheduler — called on connect start/finish and when the probe settles. */
|
|
31
|
+
requestRender: () => void;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface ManagedConnect {
|
|
35
|
+
/** Whether the keyless path is available and worth offering right now. */
|
|
36
|
+
canOffer: () => boolean;
|
|
37
|
+
/** Fire the shared capability probe, repainting the host when it settles. */
|
|
38
|
+
ensureProbe: () => void;
|
|
39
|
+
/** The CTA block, or `nothing` when the platform cannot broker AI. */
|
|
40
|
+
render: () => TemplateResult | typeof nothing;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Create a managed-connect controller bound to a host's render scheduler.
|
|
45
|
+
*
|
|
46
|
+
* @param {ManagedConnectOptions} opts
|
|
47
|
+
* @returns {ManagedConnect}
|
|
48
|
+
*/
|
|
49
|
+
export function createManagedConnect(opts: ManagedConnectOptions): ManagedConnect {
|
|
50
|
+
let busy = false;
|
|
51
|
+
let connectError = "";
|
|
52
|
+
|
|
53
|
+
/*
|
|
54
|
+
* Offer the keyless path when the proxy says managed-but-unconfigured and the platform can run
|
|
55
|
+
* the hosted OAuth flow (the PAL seam — desktop shells can implement cfConnect later). Guarded on
|
|
56
|
+
* hasPlatform() because gates can render from modules that load before registration.
|
|
57
|
+
*/
|
|
58
|
+
function canOffer(): boolean {
|
|
59
|
+
return (
|
|
60
|
+
isManagedProxy() && !isProxyConfigured() && hasPlatform() && Boolean(getPlatform().cfConnect)
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function ensureProbe() {
|
|
65
|
+
ensureProxyProbe(opts.requestRender);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function connect() {
|
|
69
|
+
if (busy) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
busy = true;
|
|
73
|
+
connectError = "";
|
|
74
|
+
opts.requestRender();
|
|
75
|
+
try {
|
|
76
|
+
const connection = await getPlatform().cfConnect?.();
|
|
77
|
+
if (connection) {
|
|
78
|
+
// Re-probe: /models flips to configured once the connection lands, opening the gate.
|
|
79
|
+
await fetchAvailableModels({ force: true });
|
|
80
|
+
} else {
|
|
81
|
+
connectError = "Cloudflare connection was not completed.";
|
|
82
|
+
}
|
|
83
|
+
} catch (error) {
|
|
84
|
+
connectError = error instanceof Error ? error.message : String(error);
|
|
85
|
+
}
|
|
86
|
+
busy = false;
|
|
87
|
+
opts.requestRender();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function render(): TemplateResult | typeof nothing {
|
|
91
|
+
if (!canOffer()) {
|
|
92
|
+
return nothing;
|
|
93
|
+
}
|
|
94
|
+
return html`
|
|
95
|
+
<div class="ai-managed-connect">
|
|
96
|
+
<div>Use Workers AI on your own Cloudflare account — no API key needed.</div>
|
|
97
|
+
<sp-button
|
|
98
|
+
size="s"
|
|
99
|
+
?disabled=${busy}
|
|
100
|
+
@click=${() => {
|
|
101
|
+
void connect();
|
|
102
|
+
}}
|
|
103
|
+
>
|
|
104
|
+
${busy ? "Connecting…" : "Connect Cloudflare"}
|
|
105
|
+
</sp-button>
|
|
106
|
+
${connectError ? html`<div class="ai-managed-connect-error">${connectError}</div>` : nothing}
|
|
107
|
+
<div class="ai-managed-connect-divider">— or bring your own key —</div>
|
|
108
|
+
</div>
|
|
109
|
+
`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return { canOffer, ensureProbe, render };
|
|
113
|
+
}
|
package/src/ui/dynamic-slot.ts
CHANGED
|
@@ -1,59 +1,120 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
2
|
/**
|
|
3
|
-
* Dynamic-slot — the shared
|
|
3
|
+
* Dynamic-slot — the shared Value Source control for any bindable document position.
|
|
4
4
|
*
|
|
5
|
-
* Renders the panel-provided static widget plus a label-side
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* Renders the panel-provided static widget plus a label-side chip that names, in plain language,
|
|
6
|
+
* how this value is produced — Fixed value / From data… / Mixed text / Formula
|
|
7
|
+
* (`ui/value-source.ts` owns the vocabulary). Clicking the chip opens a picker listing every rung
|
|
8
|
+
* the position permits, so **any rung is one action away**. It used to be a cycle ring: `$ref →
|
|
9
|
+
* literal` meant passing through `${}`, committing a template to the document on the way past, and
|
|
10
|
+
* the only way to know where the next click would land was the tooltip.
|
|
11
|
+
*
|
|
12
|
+
* The rungs are not declared by the caller but **derived from the schema** at the named position
|
|
13
|
+
* (plan §6.3): `caps` is a {@link SlotPosition}, or a schema handed in for the one case a position
|
|
14
|
+
* name cannot cover — a field in an extension's config form, whose schema arrives at runtime. There
|
|
15
|
+
* is no way for a caller to state a rung list of its own.
|
|
16
|
+
*
|
|
17
|
+
* Each mode's last value is remembered per field for the session, so switching back to an earlier
|
|
18
|
+
* mode restores what the user had there. The same memory is exported for the Events tab, which
|
|
19
|
+
* offers the same ladder in its own layout.
|
|
10
20
|
*/
|
|
11
21
|
|
|
12
22
|
import { html, nothing } from "lit-html";
|
|
13
23
|
import { live } from "lit-html/directives/live.js";
|
|
14
|
-
import { isRef
|
|
24
|
+
import { isRef } from "@jxsuite/schema/guards";
|
|
15
25
|
import { cloneValue } from "../tabs/doc-op-apply";
|
|
16
26
|
import { activeTab } from "../workspace/workspace";
|
|
17
27
|
import { renderExpressionEditor } from "./expression-editor";
|
|
28
|
+
import { VALUE_SOURCE_HINTS, VALUE_SOURCE_LABELS, slotCaps, slotMode } from "./value-source";
|
|
18
29
|
|
|
19
30
|
import type { TemplateResult } from "lit-html";
|
|
20
31
|
import type { EditorPreview } from "./expression-editor";
|
|
21
32
|
import type { JxStateDefinition } from "@jxsuite/schema/types";
|
|
22
33
|
import type { JsonValue } from "../types";
|
|
34
|
+
import type { SlotCapsSource, SlotMode } from "./value-source";
|
|
23
35
|
|
|
24
|
-
export type
|
|
25
|
-
|
|
26
|
-
const MODE_LABELS: Record<SlotMode, string> = {
|
|
27
|
-
expression: "fx",
|
|
28
|
-
literal: "abc",
|
|
29
|
-
ref: "$ref",
|
|
30
|
-
template: "${}",
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const MODE_NOUNS: Record<SlotMode, string> = {
|
|
34
|
-
expression: "expression",
|
|
35
|
-
literal: "static",
|
|
36
|
-
ref: "signal binding",
|
|
37
|
-
template: "template literal",
|
|
38
|
-
};
|
|
36
|
+
export type { SlotCapsSource, SlotMode, SlotPosition } from "./value-source";
|
|
37
|
+
export { slotCaps, slotMode } from "./value-source";
|
|
39
38
|
|
|
40
39
|
/*
|
|
41
|
-
* Session memory of each field's last value per mode, so
|
|
40
|
+
* Session memory of each field's last value per mode, so switching modes round-trips user input.
|
|
42
41
|
* Keyed `${tabId}|${fieldKey}|${mode}`; the mode key is derived from the value at stash time, so a
|
|
43
42
|
* restore always lands a value whose slotMode() matches the target mode. `undefined` is a
|
|
44
43
|
* legitimate stash (cleared literal), hence Map.has() discrimination on recall.
|
|
45
44
|
*/
|
|
46
45
|
const slotModeMemory = new Map<string, JsonValue | undefined>();
|
|
47
46
|
|
|
48
|
-
|
|
47
|
+
/*
|
|
48
|
+
* The rung each field is CURRENTLY being edited at, keyed `${tabId}|${fieldKey}`.
|
|
49
|
+
*
|
|
50
|
+
* Without this the rendered rung was re-sniffed from the document value on every render, so typing
|
|
51
|
+
* `${` into a Fixed value field swapped the widget out from under the cursor mid-keystroke — and
|
|
52
|
+
* typing the closing brace away swapped it back. A keystroke can only ever move a value between
|
|
53
|
+
* the literal and mixed-text rungs (both are plain strings); every other transition needs a
|
|
54
|
+
* structural change to the value, which a text edit cannot make. So those two rungs hold once
|
|
55
|
+
* entered, and everything else still follows the document.
|
|
56
|
+
*/
|
|
57
|
+
const slotModeRendered = new Map<string, SlotMode>();
|
|
58
|
+
|
|
59
|
+
/** Test hook: drop all remembered per-mode field values and per-field rungs. */
|
|
49
60
|
export function resetSlotModeMemory(): void {
|
|
50
61
|
slotModeMemory.clear();
|
|
62
|
+
slotModeRendered.clear();
|
|
51
63
|
}
|
|
52
64
|
|
|
53
65
|
function memoryKey(fieldKey: string, mode: SlotMode): string {
|
|
54
66
|
return `${activeTab.value?.id ?? "-"}|${fieldKey}|${mode}`;
|
|
55
67
|
}
|
|
56
68
|
|
|
69
|
+
function fieldScopeKey(fieldKey: string): string {
|
|
70
|
+
return `${activeTab.value?.id ?? "-"}|${fieldKey}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Remember `value` as this field's representation at `mode`, for a later switch back. */
|
|
74
|
+
export function stashSlotValue(
|
|
75
|
+
fieldKey: string,
|
|
76
|
+
mode: SlotMode,
|
|
77
|
+
value: JsonValue | undefined,
|
|
78
|
+
): void {
|
|
79
|
+
slotModeMemory.set(memoryKey(fieldKey, mode), cloneValue(value));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Whether this field has a remembered representation at `mode`. */
|
|
83
|
+
export function hasStashedSlotValue(fieldKey: string, mode: SlotMode): boolean {
|
|
84
|
+
return slotModeMemory.has(memoryKey(fieldKey, mode));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** This field's remembered representation at `mode` (a fresh clone). */
|
|
88
|
+
export function recallSlotValue(fieldKey: string, mode: SlotMode): JsonValue | undefined {
|
|
89
|
+
return cloneValue(slotModeMemory.get(memoryKey(fieldKey, mode)));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Record the rung the user just chose for this field, so the next render honours it. */
|
|
93
|
+
export function setSlotMode(fieldKey: string, mode: SlotMode): void {
|
|
94
|
+
slotModeRendered.set(fieldScopeKey(fieldKey), mode);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Whether a keystroke alone could have produced this rung transition. */
|
|
98
|
+
function isTextEditRung(mode: SlotMode): boolean {
|
|
99
|
+
return mode === "literal" || mode === "template";
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* The rung to render this field at: the one it is already being edited at when a text edit could
|
|
104
|
+
* explain the difference, otherwise whatever the document value says. Records its answer.
|
|
105
|
+
*/
|
|
106
|
+
export function effectiveSlotMode(fieldKey: string, value: unknown): SlotMode {
|
|
107
|
+
const key = fieldScopeKey(fieldKey);
|
|
108
|
+
const sniffed = slotMode(value);
|
|
109
|
+
const previous = slotModeRendered.get(key);
|
|
110
|
+
const mode =
|
|
111
|
+
previous !== undefined && isTextEditRung(previous) && isTextEditRung(sniffed)
|
|
112
|
+
? previous
|
|
113
|
+
: sniffed;
|
|
114
|
+
slotModeRendered.set(key, mode);
|
|
115
|
+
return mode;
|
|
116
|
+
}
|
|
117
|
+
|
|
57
118
|
function hasRefOptions(opts: DynamicSlotOpts): boolean {
|
|
58
119
|
return opts.stateDefs.length > 0 || Boolean(opts.extraSignals?.length);
|
|
59
120
|
}
|
|
@@ -72,10 +133,19 @@ export interface DynamicSlotOpts {
|
|
|
72
133
|
onChange: (v?: JsonValue) => void;
|
|
73
134
|
/** Panel-provided literal editor for this slot's type. */
|
|
74
135
|
staticWidget: unknown;
|
|
75
|
-
/**
|
|
76
|
-
caps:
|
|
136
|
+
/** Where this slot's rungs are derived from — a named document position, or a schema. */
|
|
137
|
+
caps: SlotCapsSource;
|
|
77
138
|
/** State keys offered by the ref picker and expression editor. */
|
|
78
139
|
stateDefs: string[];
|
|
140
|
+
/**
|
|
141
|
+
* Let the From data… rung take a pointer that is not in its list.
|
|
142
|
+
*
|
|
143
|
+
* The list is complete wherever it is a component's own signals. It is not complete in an
|
|
144
|
+
* extension's config form, where a value may point at a route param, a signal, or a pointer
|
|
145
|
+
* neither the form nor the panel enumerates — so there the same rung is a combobox whose options
|
|
146
|
+
* are suggestions, which is what `jx-value-selector` is for.
|
|
147
|
+
*/
|
|
148
|
+
allowCustomRef?: boolean;
|
|
79
149
|
/** Full state defs map — lets expression mode resolve named-formula catalog entries. */
|
|
80
150
|
stateEntries?: Record<string, JxStateDefinition> | null;
|
|
81
151
|
/** Extra pointer options beyond #/state/* (e.g. $map/item within repeater templates). */
|
|
@@ -86,20 +156,16 @@ export interface DynamicSlotOpts {
|
|
|
86
156
|
preview?: EditorPreview | null;
|
|
87
157
|
/** Static value restored when de-escalating to literal mode. */
|
|
88
158
|
literalDefault?: JsonValue;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if (value && typeof value === "object" && "$expression" in value) {
|
|
100
|
-
return "expression";
|
|
101
|
-
}
|
|
102
|
-
return "literal";
|
|
159
|
+
/**
|
|
160
|
+
* A position-specific seed for a rung, overriding the generic one.
|
|
161
|
+
*
|
|
162
|
+
* The generic expression seed is `{ operator: "??" }`, which is a sensible starting point almost
|
|
163
|
+
* everywhere and an INVALID document in a position whose schema narrows which operators it takes.
|
|
164
|
+
* An element's `tagName` is the first such position — a `TagExpression` is `?:` or `switch` and
|
|
165
|
+
* nothing else — so a generic seed would drop a document that fails its own validator the moment
|
|
166
|
+
* the chip is clicked. Return `undefined` to accept the generic seed.
|
|
167
|
+
*/
|
|
168
|
+
seedFor?: (mode: SlotMode) => JsonValue | undefined;
|
|
103
169
|
}
|
|
104
170
|
|
|
105
171
|
function defaultForSlotMode(mode: SlotMode, opts: DynamicSlotOpts): JsonValue | undefined {
|
|
@@ -115,13 +181,47 @@ function defaultForSlotMode(mode: SlotMode, opts: DynamicSlotOpts): JsonValue |
|
|
|
115
181
|
case "expression": {
|
|
116
182
|
return { $expression: { operator: "??", target: null, value: null } };
|
|
117
183
|
}
|
|
184
|
+
case "function": {
|
|
185
|
+
return { $prototype: "Function", body: "", parameters: [] };
|
|
186
|
+
}
|
|
118
187
|
default: {
|
|
119
188
|
return opts.literalDefault;
|
|
120
189
|
}
|
|
121
190
|
}
|
|
122
191
|
}
|
|
123
192
|
|
|
193
|
+
/** Every pointer the From data… rung offers, as `{ value, label }` options. */
|
|
194
|
+
function refOptions(opts: DynamicSlotOpts): SignalOption[] {
|
|
195
|
+
return [
|
|
196
|
+
...opts.stateDefs.map((name) => ({ label: name, value: `#/state/${name}` })),
|
|
197
|
+
...(opts.extraSignals ?? []),
|
|
198
|
+
];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function renderCustomRefWidget(refVal: string, opts: DynamicSlotOpts) {
|
|
202
|
+
return html`
|
|
203
|
+
<jx-value-selector
|
|
204
|
+
size="s"
|
|
205
|
+
style="flex:1"
|
|
206
|
+
placeholder="#/state/…"
|
|
207
|
+
.value=${refVal}
|
|
208
|
+
.options=${refOptions(opts)}
|
|
209
|
+
@change=${(e: Event & { detail?: { value?: string } }) => {
|
|
210
|
+
const v = (e.detail?.value ?? (e.target as HTMLInputElement).value ?? "").trim();
|
|
211
|
+
if (v) {
|
|
212
|
+
opts.onChange({ $ref: v });
|
|
213
|
+
} else {
|
|
214
|
+
opts.onChange();
|
|
215
|
+
}
|
|
216
|
+
}}
|
|
217
|
+
></jx-value-selector>
|
|
218
|
+
`;
|
|
219
|
+
}
|
|
220
|
+
|
|
124
221
|
function renderRefWidget(refVal: string, opts: DynamicSlotOpts) {
|
|
222
|
+
if (opts.allowCustomRef) {
|
|
223
|
+
return renderCustomRefWidget(refVal, opts);
|
|
224
|
+
}
|
|
125
225
|
return html`
|
|
126
226
|
<sp-picker
|
|
127
227
|
size="s"
|
|
@@ -168,26 +268,52 @@ function renderTemplateWidget(value: unknown, opts: DynamicSlotOpts) {
|
|
|
168
268
|
}
|
|
169
269
|
|
|
170
270
|
export interface DynamicSlotParts {
|
|
171
|
-
/** Label-side
|
|
271
|
+
/** Label-side Value Source chip and its picker. */
|
|
172
272
|
modeButton: TemplateResult;
|
|
173
273
|
/** Active-mode widget, sized to fill the row's widget column. */
|
|
174
274
|
widget: TemplateResult;
|
|
175
275
|
}
|
|
176
276
|
|
|
177
277
|
/**
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
* the outgoing
|
|
278
|
+
* Switch a field to `next`: stash the outgoing representation, restore the incoming one if this
|
|
279
|
+
* field has been there before, and record the new rung. Shared with the Events tab, which used to
|
|
280
|
+
* throw the outgoing representation away on every mode change.
|
|
281
|
+
*/
|
|
282
|
+
export function switchSlotMode(
|
|
283
|
+
fieldKey: string,
|
|
284
|
+
from: SlotMode,
|
|
285
|
+
to: SlotMode,
|
|
286
|
+
current: JsonValue | undefined,
|
|
287
|
+
seed: JsonValue | undefined,
|
|
288
|
+
): JsonValue | undefined {
|
|
289
|
+
stashSlotValue(fieldKey, from, current);
|
|
290
|
+
setSlotMode(fieldKey, to);
|
|
291
|
+
return hasStashedSlotValue(fieldKey, to) ? recallSlotValue(fieldKey, to) : seed;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/** A DOM id for the chip, so `sp-overlay` can name it as its trigger. */
|
|
295
|
+
function chipId(fieldKey: string): string {
|
|
296
|
+
return `value-source-${fieldKey.replaceAll(/[^\dA-Za-z]+/g, "-")}`;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* The label-side Value Source chip: the current rung in plain language — quiet while the value is
|
|
301
|
+
* fixed, accent-tinted once it is produced from something else — opening a picker of every rung
|
|
302
|
+
* this position permits.
|
|
181
303
|
*/
|
|
182
|
-
function
|
|
304
|
+
function renderModeChip(mode: SlotMode, caps: SlotMode[], opts: DynamicSlotOpts): TemplateResult {
|
|
183
305
|
const color =
|
|
184
|
-
mode
|
|
185
|
-
? "color:var(--spectrum-
|
|
186
|
-
: "color:var(--spectrum-
|
|
187
|
-
// A ref rung with nothing to point at is a dead end — drop it rather than
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
306
|
+
mode === "literal"
|
|
307
|
+
? "color:var(--spectrum-gray-600, #808080)"
|
|
308
|
+
: "color:var(--spectrum-accent-content-color-default, #5c9dff)";
|
|
309
|
+
// A ref rung with nothing to point at is a dead end — drop it rather than offer an empty picker.
|
|
310
|
+
const offered = caps.filter((m) => m !== "ref" || hasRefOptions(opts));
|
|
311
|
+
const label = VALUE_SOURCE_LABELS[mode];
|
|
312
|
+
/* Disabled only when the rung this value already sits on is the only one there is. A value on a
|
|
313
|
+
rung the position does NOT permit — a fixed string left in a `$switch`, say — is exactly the
|
|
314
|
+
case that needs the chip most, and counting rungs alone used to grey it out. */
|
|
315
|
+
if (!offered.some((m) => m !== mode)) {
|
|
316
|
+
const hint = `Value source: ${label} (no other source available here)`;
|
|
191
317
|
return html`
|
|
192
318
|
<sp-action-button
|
|
193
319
|
size="xs"
|
|
@@ -197,53 +323,70 @@ function renderModeButton(mode: SlotMode, caps: SlotMode[], opts: DynamicSlotOpt
|
|
|
197
323
|
style=${color}
|
|
198
324
|
title=${hint}
|
|
199
325
|
aria-label=${hint}
|
|
200
|
-
>${
|
|
326
|
+
>${label}</sp-action-button
|
|
201
327
|
>
|
|
202
328
|
`;
|
|
203
329
|
}
|
|
204
|
-
|
|
205
|
-
const
|
|
206
|
-
const
|
|
330
|
+
const id = chipId(opts.fieldKey);
|
|
331
|
+
const hint = `Value source: ${label} — click to change`;
|
|
332
|
+
const choose = (next: SlotMode) => {
|
|
333
|
+
if (next === mode) {
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
/* Leaving ref seeds an empty literal stash with the signal's declared default, so
|
|
337
|
+
unbind-restores-default survives a detour (ref → mixed text → fixed value). */
|
|
338
|
+
if (
|
|
339
|
+
mode === "ref" &&
|
|
340
|
+
opts.literalDefault !== undefined &&
|
|
341
|
+
!hasStashedSlotValue(opts.fieldKey, "literal")
|
|
342
|
+
) {
|
|
343
|
+
stashSlotValue(opts.fieldKey, "literal", opts.literalDefault);
|
|
344
|
+
}
|
|
345
|
+
opts.onChange(
|
|
346
|
+
switchSlotMode(
|
|
347
|
+
opts.fieldKey,
|
|
348
|
+
mode,
|
|
349
|
+
next,
|
|
350
|
+
cloneValue(opts.value as JsonValue | undefined),
|
|
351
|
+
opts.seedFor?.(next) ?? defaultForSlotMode(next, opts),
|
|
352
|
+
),
|
|
353
|
+
);
|
|
354
|
+
};
|
|
207
355
|
return html`
|
|
208
356
|
<sp-action-button
|
|
357
|
+
id=${id}
|
|
209
358
|
size="xs"
|
|
210
359
|
quiet
|
|
211
360
|
class="dynamic-slot-mode"
|
|
212
361
|
style=${color}
|
|
213
362
|
title=${hint}
|
|
214
363
|
aria-label=${hint}
|
|
215
|
-
|
|
216
|
-
slotModeMemory.set(
|
|
217
|
-
memoryKey(opts.fieldKey, mode),
|
|
218
|
-
cloneValue(opts.value as JsonValue | undefined),
|
|
219
|
-
);
|
|
220
|
-
// Leaving ref seeds an empty literal stash with the signal's declared default.
|
|
221
|
-
// Unbind-restores-default thus survives multi-hop cycles (ref → template → literal).
|
|
222
|
-
if (mode === "ref" && opts.literalDefault !== undefined) {
|
|
223
|
-
const litKey = memoryKey(opts.fieldKey, "literal");
|
|
224
|
-
if (!slotModeMemory.has(litKey)) {
|
|
225
|
-
slotModeMemory.set(litKey, cloneValue(opts.literalDefault));
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
const key = memoryKey(opts.fieldKey, next);
|
|
229
|
-
opts.onChange(
|
|
230
|
-
slotModeMemory.has(key)
|
|
231
|
-
? cloneValue(slotModeMemory.get(key))
|
|
232
|
-
: defaultForSlotMode(next, opts),
|
|
233
|
-
);
|
|
234
|
-
}}
|
|
235
|
-
>${MODE_LABELS[mode]}</sp-action-button
|
|
364
|
+
>${label}</sp-action-button
|
|
236
365
|
>
|
|
366
|
+
<sp-overlay trigger="${id}@click" placement="bottom-start" type="auto">
|
|
367
|
+
<sp-popover>
|
|
368
|
+
<sp-menu size="s" label="Value source">
|
|
369
|
+
${offered.map(
|
|
370
|
+
(m) => html`
|
|
371
|
+
<sp-menu-item data-mode=${m} ?selected=${m === mode} @click=${() => choose(m)}
|
|
372
|
+
>${VALUE_SOURCE_LABELS[m]}
|
|
373
|
+
<span slot="description">${VALUE_SOURCE_HINTS[m]}</span></sp-menu-item
|
|
374
|
+
>
|
|
375
|
+
`,
|
|
376
|
+
)}
|
|
377
|
+
</sp-menu>
|
|
378
|
+
</sp-popover>
|
|
379
|
+
</sp-overlay>
|
|
237
380
|
`;
|
|
238
381
|
}
|
|
239
382
|
|
|
240
383
|
/**
|
|
241
384
|
* Render a bindable slot as two parts the panel places independently: the active mode's widget for
|
|
242
|
-
* the row's value column, and the
|
|
385
|
+
* the row's value column, and the Value Source chip for the label side.
|
|
243
386
|
*/
|
|
244
387
|
export function renderDynamicSlot(opts: DynamicSlotOpts): DynamicSlotParts {
|
|
245
|
-
const caps
|
|
246
|
-
const mode =
|
|
388
|
+
const caps = slotCaps(opts.caps);
|
|
389
|
+
const mode = effectiveSlotMode(opts.fieldKey, opts.value);
|
|
247
390
|
|
|
248
391
|
const widget =
|
|
249
392
|
mode === "ref"
|
|
@@ -264,7 +407,7 @@ export function renderDynamicSlot(opts: DynamicSlotOpts): DynamicSlotParts {
|
|
|
264
407
|
: opts.staticWidget;
|
|
265
408
|
|
|
266
409
|
return {
|
|
267
|
-
modeButton:
|
|
410
|
+
modeButton: renderModeChip(mode, caps, opts),
|
|
268
411
|
widget: html`
|
|
269
412
|
<div class="dynamic-slot" style="display:flex;flex:1;min-width:0">
|
|
270
413
|
<div style="flex:1;min-width:0">${widget}</div>
|