@jxsuite/studio 2.0.1 → 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-799jpvhm.js → components-2bpqp4mq.js} +5 -7
- package/dist/chunks/{components-799jpvhm.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-8jxwts2p.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-gs6kqdt1.js → studio-adn0z1k3.js} +14 -8
- package/dist/chunks/{studio-gs6kqdt1.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-esrewxap.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-v7jkjqng.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-jm0z592w.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 +21080 -32585
- 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 +7 -0
- package/src/new-project/location-fields.ts +9 -1
- package/src/new-project/new-project-modal.ts +221 -245
- 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 -53
- 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 +30 -1
- 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 +7 -1
- 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-qr3drkkw.js +0 -531
- package/dist/chunks/extension-sections-qr3drkkw.js.map +0 -12
- package/dist/chunks/files-j8a1t06k.js +0 -50
- package/dist/chunks/files-j8a1t06k.js.map +0 -9
- package/dist/chunks/git-panel-xtq5z81x.js +0 -28
- package/dist/chunks/git-panel-xtq5z81x.js.map +0 -9
- package/dist/chunks/layers-panel-ancn2wpq.js +0 -26
- package/dist/chunks/layers-panel-ancn2wpq.js.map +0 -9
- package/dist/chunks/settings-modal-17ttr96g.js +0 -29
- package/dist/chunks/settings-modal-17ttr96g.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-0xgs7xrs.js +0 -429
- package/dist/chunks/studio-0xgs7xrs.js.map +0 -13
- package/dist/chunks/studio-4d8hzcz5.js +0 -3427
- package/dist/chunks/studio-4d8hzcz5.js.map +0 -26
- package/dist/chunks/studio-4k0m4fmp.js.map +0 -13
- package/dist/chunks/studio-9smfzqhc.js +0 -19
- package/dist/chunks/studio-9smfzqhc.js.map +0 -10
- package/dist/chunks/studio-jm0z592w.js.map +0 -115
- package/dist/chunks/studio-m2t4mdg5.js +0 -1854
- package/dist/chunks/studio-m2t4mdg5.js.map +0 -18
- package/dist/chunks/studio-n4p11dfy.js +0 -853
- package/dist/chunks/studio-n4p11dfy.js.map +0 -12
- package/dist/chunks/studio-qkvt37c0.js.map +0 -9
- package/dist/chunks/studio-sjh1wt1a.js +0 -3744
- package/dist/chunks/studio-sjh1wt1a.js.map +0 -22
- package/dist/chunks/studio-v7jkjqng.js.map +0 -46
- 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-yfcstdzy.js +0 -399
- package/dist/chunks/studio-yfcstdzy.js.map +0 -12
- package/dist/chunks/studio-zp7jncs8.js +0 -469
- package/dist/chunks/studio-zp7jncs8.js.map +0 -14
- 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-8jxwts2p.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-esrewxap.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
|
@@ -1,12 +1,57 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
|
+
/**
|
|
3
|
+
* The Logic tab — everything about how this element BEHAVES.
|
|
4
|
+
*
|
|
5
|
+
* Plan §6.5 re-split the inspector by task rather than by data type, and this is the tab that
|
|
6
|
+
* gained by it. Wiring a `$switch`, wiring a repeater to a collection and wiring a click handler
|
|
7
|
+
* are one job; they were three, split across two tabs, because a `$switch` is stored as a property
|
|
8
|
+
* and a click handler is stored as a property-shaped function, and the old split followed the
|
|
9
|
+
* storage. So Logic is now:
|
|
10
|
+
*
|
|
11
|
+
* - **Repeating list** — the `$prototype: "Array"` node's items / filter / sort, and its template.
|
|
12
|
+
* - **Condition** — the `$switch` expression and its cases.
|
|
13
|
+
* - **Events** — declared events, bindings, inline bodies, expressions.
|
|
14
|
+
* - **Observed Attributes · CSS Properties · CSS Parts** — a custom element's outward contract.
|
|
15
|
+
*
|
|
16
|
+
* The last three arrived from the Content tab, where they were three near-identical hand-written
|
|
17
|
+
* flex rows; they are now three calls to {@link renderStaticKvRow}.
|
|
18
|
+
*
|
|
19
|
+
* Everything here reads `session.selection`, so the tab is selection-level in the same sense the
|
|
20
|
+
* rest of the inspector is: no selection is an empty state, not a blank panel.
|
|
21
|
+
*/
|
|
22
|
+
|
|
2
23
|
import { getNodeAtPath, renderOnly } from "../store";
|
|
3
24
|
import { html, nothing } from "lit-html";
|
|
4
25
|
import { live } from "lit-html/directives/live.js";
|
|
5
26
|
import { activeTab } from "../workspace/workspace";
|
|
6
|
-
import {
|
|
27
|
+
import { primarySelection, unifyValues } from "../tabs/selection";
|
|
28
|
+
import { renderProvenanceChip } from "./provenance";
|
|
29
|
+
import {
|
|
30
|
+
mutateAddDef,
|
|
31
|
+
mutateAddSwitchCase,
|
|
32
|
+
mutateRemoveSwitchCase,
|
|
33
|
+
mutateRenameSwitchCase,
|
|
34
|
+
mutateUpdateProperty,
|
|
35
|
+
transactDoc,
|
|
36
|
+
} from "../tabs/transact";
|
|
37
|
+
import { clickAnythingTo, renderEmptyState, staleSelectionMessage } from "./empty-state";
|
|
7
38
|
import { renderExpressionEditor } from "../ui/expression-editor";
|
|
8
39
|
import { renderStatementEditor } from "./statement-editor";
|
|
40
|
+
import { inspectorStatementsRegion } from "../ui/regions";
|
|
9
41
|
import { livePreviewExpression } from "../services/live-preview";
|
|
42
|
+
import { renderFieldRow, renderStaticKvRow } from "../ui/field-row";
|
|
43
|
+
import { renderDynamicSlot, slotMode, switchSlotMode } from "../ui/dynamic-slot";
|
|
44
|
+
import { VALUE_SOURCE_LABELS, capsForPosition } from "../ui/value-source";
|
|
45
|
+
import { spTextField } from "../ui/field-input";
|
|
46
|
+
import {
|
|
47
|
+
bindableSignalNames,
|
|
48
|
+
defaultAsString,
|
|
49
|
+
isInspectorSectionOpen,
|
|
50
|
+
mapSignalsFor,
|
|
51
|
+
setInspectorSection,
|
|
52
|
+
} from "./properties-panel";
|
|
53
|
+
import { collectCssParts } from "./signals-panel";
|
|
54
|
+
import { openLogicTarget } from "./formula-workspace";
|
|
10
55
|
import {
|
|
11
56
|
getEventBinding,
|
|
12
57
|
isExpressionDef,
|
|
@@ -16,8 +61,26 @@ import {
|
|
|
16
61
|
} from "@jxsuite/schema/guards";
|
|
17
62
|
|
|
18
63
|
import type { JsonValue } from "../types";
|
|
19
|
-
import type {
|
|
64
|
+
import type { TemplateResult } from "lit-html";
|
|
65
|
+
import type { SlotCapsSource, SlotMode, SignalOption } from "../ui/dynamic-slot";
|
|
66
|
+
import type { JxPath } from "../state";
|
|
67
|
+
import type {
|
|
68
|
+
CemEvent,
|
|
69
|
+
JxEventBinding,
|
|
70
|
+
JxFunctionDef,
|
|
71
|
+
JxMutableNode,
|
|
72
|
+
JxPrototypeDef,
|
|
73
|
+
} from "@jxsuite/schema/types";
|
|
20
74
|
|
|
75
|
+
/**
|
|
76
|
+
* The events worth SUGGESTING — not the events an element may have.
|
|
77
|
+
*
|
|
78
|
+
* These ten were a closed `sp-picker`, so `ondragover`, `onpointerdown`, `onwheel`, `onpaste` and
|
|
79
|
+
* every custom event a component emits were unbindable from the Inspector: the plan's §6.5 asks for
|
|
80
|
+
* "a free-form combobox instead of a hard-coded list of ten", and `ui/value-selector.ts`'s own
|
|
81
|
+
* docstring names this field as the reason it exists ("what lets a control like the event-name
|
|
82
|
+
* field stop being a list of ten"). The widget was written and never wired.
|
|
83
|
+
*/
|
|
21
84
|
export const EVENT_NAMES = [
|
|
22
85
|
"onclick",
|
|
23
86
|
"oninput",
|
|
@@ -31,21 +94,307 @@ export const EVENT_NAMES = [
|
|
|
31
94
|
"onmouseleave",
|
|
32
95
|
];
|
|
33
96
|
|
|
34
|
-
/** @
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
97
|
+
/** {@link EVENT_NAMES} as the combobox's option list, plus whatever this element already declares. */
|
|
98
|
+
function eventNameOptions(declared: readonly string[]): { label: string; value: string }[] {
|
|
99
|
+
const seen = new Set<string>();
|
|
100
|
+
const out: { label: string; value: string }[] = [];
|
|
101
|
+
for (const name of [...declared, ...EVENT_NAMES]) {
|
|
102
|
+
if (!seen.has(name)) {
|
|
103
|
+
seen.add(name);
|
|
104
|
+
out.push({ label: name, value: name });
|
|
105
|
+
}
|
|
42
106
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* The rungs an `on*` handler permits, derived from the schema (`RefObject | ExpressionEntry |
|
|
112
|
+
* FunctionDef`) rather than listed here.
|
|
113
|
+
*
|
|
114
|
+
* This picker used to read Inline code / Expression / Existing function — a fourth private dialect
|
|
115
|
+
* for the one ladder §6.6 collapses, so a user who learned "Formula" on a property row met
|
|
116
|
+
* "Expression" here and had no reason to think they were the same thing.
|
|
117
|
+
*/
|
|
118
|
+
const HANDLER_MODES: SlotMode[] = capsForPosition("eventHandler");
|
|
119
|
+
|
|
120
|
+
/** The value a handler starts at on each rung, when the user has never been on that rung before. */
|
|
121
|
+
function seedForHandlerMode(mode: SlotMode, functionDefs: [string, unknown][]): JsonValue {
|
|
122
|
+
if (mode === "function") {
|
|
123
|
+
return { $prototype: "Function", body: "", parameters: [] };
|
|
46
124
|
}
|
|
125
|
+
if (mode === "expression") {
|
|
126
|
+
return { $expression: { operator: "=", target: null } };
|
|
127
|
+
}
|
|
128
|
+
const [firstFn] = functionDefs;
|
|
129
|
+
return firstFn ? { $ref: `#/state/${firstFn[0]}` } : { $ref: "" };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ─── The bindable row ────────────────────────────────────────────────────────
|
|
133
|
+
|
|
134
|
+
/** Arguments for {@link bindableFieldRow}. */
|
|
135
|
+
interface BindableRowOpts {
|
|
136
|
+
/** The `data-prop` key — what `inspector/field:<prop>` addresses. */
|
|
137
|
+
prop: string;
|
|
138
|
+
label: string;
|
|
139
|
+
/** The raw document value: a JSON literal, `{ $ref }`, a `${}` template or an `$expression`. */
|
|
140
|
+
rawValue: unknown;
|
|
141
|
+
onChange: (v?: JsonValue) => void;
|
|
142
|
+
/** Removes the position outright. Absent means the position is mandatory and cannot be cleared. */
|
|
143
|
+
onClear?: (() => void) | undefined;
|
|
144
|
+
/** Extra signals this position may bind to — `$map/item` and friends inside a template. */
|
|
145
|
+
extraSignals?: SignalOption[] | null;
|
|
146
|
+
/** Stable identity for the dynamic slot's per-mode value memory; must include the node path. */
|
|
147
|
+
fieldKey: string;
|
|
148
|
+
/** The document position being edited — the rungs follow from its schema, never from here. */
|
|
149
|
+
caps: SlotCapsSource;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* A bindable value as a first-class field row.
|
|
154
|
+
*
|
|
155
|
+
* This used to render a bare `<div class="field-row">` with a label and a widget: no set-dot, no
|
|
156
|
+
* clear affordance, no error slot — the three things every other row in the inspector has had since
|
|
157
|
+
* `renderFieldRow` landed. Repeater and Switch fields were the last second-class rows in the
|
|
158
|
+
* inspector, which is exactly what §12 P5 item 6 names.
|
|
159
|
+
*
|
|
160
|
+
* Every position it serves is a single-line expression (a collection, a filter, a sort key, a
|
|
161
|
+
* `$switch`), so it draws one literal editor rather than dispatching over a widget type — the
|
|
162
|
+
* textarea and checkbox arms it used to carry had no caller in either tab.
|
|
163
|
+
*/
|
|
164
|
+
function bindableFieldRow({
|
|
165
|
+
prop,
|
|
166
|
+
label,
|
|
167
|
+
rawValue,
|
|
168
|
+
onChange,
|
|
169
|
+
onClear,
|
|
170
|
+
extraSignals = null,
|
|
171
|
+
fieldKey,
|
|
172
|
+
caps,
|
|
173
|
+
}: BindableRowOpts) {
|
|
174
|
+
const defs = activeTab.value!.doc.document.state || {};
|
|
175
|
+
const boundRef = isRef(rawValue) ? rawValue.$ref : null;
|
|
176
|
+
const staticVal = slotMode(rawValue) === "literal" ? (rawValue ?? "") : "";
|
|
47
177
|
|
|
48
|
-
|
|
178
|
+
// De-escalating to literal restores the bound signal's declared default (old unbind behavior).
|
|
179
|
+
const literalDefault = boundRef
|
|
180
|
+
? defaultAsString(defs[boundRef.startsWith("#/state/") ? boundRef.slice(8) : boundRef]) ||
|
|
181
|
+
undefined
|
|
182
|
+
: undefined;
|
|
183
|
+
|
|
184
|
+
const slot = renderDynamicSlot({
|
|
185
|
+
caps,
|
|
186
|
+
extraSignals,
|
|
187
|
+
fieldKey,
|
|
188
|
+
literalDefault,
|
|
189
|
+
onChange,
|
|
190
|
+
staticWidget: spTextField(`prop:${label}`, String(staticVal), (v: string) => onChange(v)),
|
|
191
|
+
stateDefs: bindableSignalNames(activeTab.value!.doc.document),
|
|
192
|
+
value: rawValue,
|
|
193
|
+
});
|
|
194
|
+
return renderFieldRow({
|
|
195
|
+
hasValue: rawValue !== undefined && rawValue !== "",
|
|
196
|
+
label,
|
|
197
|
+
labelExtra: slot.modeButton,
|
|
198
|
+
prop,
|
|
199
|
+
widget: slot.widget,
|
|
200
|
+
...(onClear ? { onClear } : {}),
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// ─── Repeating list ──────────────────────────────────────────────────────────
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* The repeater's items / filter / sort, and the way into its template.
|
|
208
|
+
*
|
|
209
|
+
* Filter and Sort are always drawn. They used to hide behind `+ Add filter`, which seeded `{ $ref:
|
|
210
|
+
* "#/state/" }` — a binding to the empty pointer, which is not a signal — so the row opened already
|
|
211
|
+
* bound to nothing and the only way to type a literal was to cycle the mode ring twice (§11.4).
|
|
212
|
+
* There is no seed to fix, because a repeater has exactly three inputs and an empty row states that
|
|
213
|
+
* better than a button does: type into it and it is set, clear it and it is gone.
|
|
214
|
+
*/
|
|
215
|
+
function renderRepeaterFieldsTemplate(node: JxMutableNode, path: JxPath) {
|
|
216
|
+
const key = path.join("/");
|
|
217
|
+
const clear = (name: string) => () =>
|
|
218
|
+
transactDoc(activeTab.value, (t) => mutateUpdateProperty(t, path, name));
|
|
219
|
+
const optional = (name: "filter" | "sort", label: string) =>
|
|
220
|
+
bindableFieldRow({
|
|
221
|
+
caps: name === "filter" ? "repeaterFilter" : "repeaterSort",
|
|
222
|
+
fieldKey: `prop|${key}|${name}`,
|
|
223
|
+
label,
|
|
224
|
+
onChange: (v?: JsonValue) =>
|
|
225
|
+
transactDoc(activeTab.value, (t) => mutateUpdateProperty(t, path, name, v || undefined)),
|
|
226
|
+
onClear: clear(name),
|
|
227
|
+
prop: name,
|
|
228
|
+
rawValue: node[name],
|
|
229
|
+
});
|
|
230
|
+
return html`
|
|
231
|
+
${bindableFieldRow({
|
|
232
|
+
caps: "repeaterItems",
|
|
233
|
+
fieldKey: `prop|${key}|items`,
|
|
234
|
+
label: "Items",
|
|
235
|
+
onChange: (v?: JsonValue) =>
|
|
236
|
+
transactDoc(activeTab.value, (t) => mutateUpdateProperty(t, path, "items", v)),
|
|
237
|
+
prop: "items",
|
|
238
|
+
rawValue: node.items,
|
|
239
|
+
})}
|
|
240
|
+
${optional("filter", "Filter")} ${optional("sort", "Sort")}
|
|
241
|
+
${
|
|
242
|
+
node.map
|
|
243
|
+
? html`
|
|
244
|
+
<sp-action-button
|
|
245
|
+
size="s"
|
|
246
|
+
class="logic-edit-template"
|
|
247
|
+
@click=${() => {
|
|
248
|
+
activeTab.value!.session.selection = [[...path, "map"]];
|
|
249
|
+
}}
|
|
250
|
+
>Edit template →</sp-action-button
|
|
251
|
+
>
|
|
252
|
+
`
|
|
253
|
+
: nothing
|
|
254
|
+
}
|
|
255
|
+
`;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// ─── Condition ───────────────────────────────────────────────────────────────
|
|
259
|
+
|
|
260
|
+
/** The `$switch` expression and its cases — each case a field row like every other. */
|
|
261
|
+
function renderSwitchFieldsTemplate(
|
|
262
|
+
node: JxMutableNode,
|
|
263
|
+
path: JxPath,
|
|
264
|
+
mapSignals: SignalOption[] | null,
|
|
265
|
+
) {
|
|
266
|
+
const caseNames = Object.keys(node.cases || {});
|
|
267
|
+
return html`
|
|
268
|
+
${bindableFieldRow({
|
|
269
|
+
// `SwitchDef` is a $ref and nothing else, so From data… is the only rung — a $switch is
|
|
270
|
+
// Inherently dynamic, and de-escalating it would delete the key and demote the node.
|
|
271
|
+
caps: "switchDiscriminant",
|
|
272
|
+
extraSignals: mapSignals,
|
|
273
|
+
fieldKey: `prop|${path.join("/")}|$switch`,
|
|
274
|
+
label: "Expression",
|
|
275
|
+
onChange: (v?: JsonValue) =>
|
|
276
|
+
transactDoc(activeTab.value, (t) => mutateUpdateProperty(t, path, "$switch", v)),
|
|
277
|
+
prop: "$switch",
|
|
278
|
+
rawValue: node.$switch,
|
|
279
|
+
})}
|
|
280
|
+
<div class="logic-subhead">Cases</div>
|
|
281
|
+
${caseNames.map((caseName) => {
|
|
282
|
+
let debounce: ReturnType<typeof setTimeout> | undefined;
|
|
283
|
+
return renderFieldRow({
|
|
284
|
+
hasValue: true,
|
|
285
|
+
label: "Case",
|
|
286
|
+
prop: `case:${caseName}`,
|
|
287
|
+
provenance: {
|
|
288
|
+
onClick: () =>
|
|
289
|
+
transactDoc(activeTab.value!, (t) => mutateRemoveSwitchCase(t, path, caseName)),
|
|
290
|
+
state: "set",
|
|
291
|
+
title: `Remove case "${caseName}"`,
|
|
292
|
+
},
|
|
293
|
+
widget: html`
|
|
294
|
+
<div class="logic-case-row">
|
|
295
|
+
<sp-textfield
|
|
296
|
+
size="s"
|
|
297
|
+
class="logic-case-name"
|
|
298
|
+
.value=${live(caseName)}
|
|
299
|
+
@input=${(e: Event) => {
|
|
300
|
+
clearTimeout(debounce);
|
|
301
|
+
const next = (e.target as HTMLInputElement).value;
|
|
302
|
+
debounce = setTimeout(() => {
|
|
303
|
+
if (next && next !== caseName) {
|
|
304
|
+
transactDoc(activeTab.value, (t) =>
|
|
305
|
+
mutateRenameSwitchCase(t, path, caseName, next),
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
}, 500);
|
|
309
|
+
}}
|
|
310
|
+
></sp-textfield>
|
|
311
|
+
<sp-action-button
|
|
312
|
+
size="xs"
|
|
313
|
+
quiet
|
|
314
|
+
class="logic-case-open"
|
|
315
|
+
title="Edit case"
|
|
316
|
+
@click=${(e: Event) => {
|
|
317
|
+
e.stopPropagation();
|
|
318
|
+
activeTab.value!.session.selection = [[...path, "cases", caseName]];
|
|
319
|
+
}}
|
|
320
|
+
>→</sp-action-button
|
|
321
|
+
>
|
|
322
|
+
</div>
|
|
323
|
+
`,
|
|
324
|
+
});
|
|
325
|
+
})}
|
|
326
|
+
<span
|
|
327
|
+
class="kv-add"
|
|
328
|
+
@click=${() => {
|
|
329
|
+
transactDoc(activeTab.value, (t) =>
|
|
330
|
+
mutateAddSwitchCase(t, path, `case${caseNames.length + 1}`),
|
|
331
|
+
);
|
|
332
|
+
}}
|
|
333
|
+
>+ Add case</span
|
|
334
|
+
>
|
|
335
|
+
`;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// ─── Events ──────────────────────────────────────────────────────────────────
|
|
339
|
+
|
|
340
|
+
/** The event bindings themselves — declared events, then one block per bound `on*` key. */
|
|
341
|
+
/**
|
|
342
|
+
* The Logic tab's Mixed contract (§6.5), stated once because it is a judgement, not a mechanism.
|
|
343
|
+
*
|
|
344
|
+
* Wiring splits in two, and a multi-selection treats the halves differently:
|
|
345
|
+
*
|
|
346
|
+
* - **Which events exist, and how each is produced** — the event key, its Value Source rung, and its
|
|
347
|
+
* removal — is a property of the BATCH. Binding one handler to six buttons, or clearing it off
|
|
348
|
+
* all six, is a single decision, so those three controls write to every selected element inside
|
|
349
|
+
* one transaction and one undo step.
|
|
350
|
+
* - **What a handler CONTAINS** — a function body, an expression's operands, a repeater's source and
|
|
351
|
+
* template — is the PRIMARY's. Six elements do not share one handler body; broadcasting a
|
|
352
|
+
* keystroke into six different bodies would destroy five of them, and showing one body while
|
|
353
|
+
* claiming to edit six is the lie the Mixed chip exists to prevent.
|
|
354
|
+
*
|
|
355
|
+
* So the row header states `mixed (n)` when the selected elements disagree about a key — including
|
|
356
|
+
* when some of them do not bind it at all — and the body below it stays what it always was: the
|
|
357
|
+
* primary's, edited alone.
|
|
358
|
+
*
|
|
359
|
+
* @param {readonly JxPath[]} targets
|
|
360
|
+
* @param {string} key
|
|
361
|
+
* @param {JsonValue} [value] — omitted deletes the key.
|
|
362
|
+
*/
|
|
363
|
+
function commitToTargets(targets: readonly JxPath[], key: string, value?: JsonValue): void {
|
|
364
|
+
transactDoc(activeTab.value, (t) => {
|
|
365
|
+
for (const target of targets) {
|
|
366
|
+
mutateUpdateProperty(t, target, key, value);
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* How many selected elements disagree about one event key — 0 when they agree or there is one.
|
|
373
|
+
*
|
|
374
|
+
* @param {JxMutableNode} doc
|
|
375
|
+
* @param {readonly JxPath[]} targets
|
|
376
|
+
* @param {string} evKey
|
|
377
|
+
* @returns {number}
|
|
378
|
+
*/
|
|
379
|
+
function mixedEventCount(doc: JxMutableNode, targets: readonly JxPath[], evKey: string): number {
|
|
380
|
+
if (targets.length < 2) {
|
|
381
|
+
return 0;
|
|
382
|
+
}
|
|
383
|
+
const values = targets.map((path) => {
|
|
384
|
+
const n = getNodeAtPath(doc, path) as JxMutableNode | undefined;
|
|
385
|
+
return n ? (getEventBinding(n, evKey) ?? null) : null;
|
|
386
|
+
});
|
|
387
|
+
return unifyValues(values).mixed ? targets.length : 0;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function renderEventsBody(
|
|
391
|
+
node: JxMutableNode,
|
|
392
|
+
selection: JxPath,
|
|
393
|
+
isCustomElement: boolean,
|
|
394
|
+
targets: readonly JxPath[] = [selection],
|
|
395
|
+
) {
|
|
396
|
+
const tab = activeTab.value!;
|
|
397
|
+
const defs = tab.doc.document.state || {};
|
|
49
398
|
const functionDefs = Object.entries(defs).filter(
|
|
50
399
|
([, d]) =>
|
|
51
400
|
(d as JxPrototypeDef)?.$prototype === "Function" || (d as Record<string, unknown>)?.$handler,
|
|
@@ -53,7 +402,7 @@ export function eventsSidebarTemplate(helpers: { isCustomElementDoc: () => boole
|
|
|
53
402
|
|
|
54
403
|
// Declared CEM events (custom element docs)
|
|
55
404
|
let declaredEventsT: unknown = nothing;
|
|
56
|
-
if (
|
|
405
|
+
if (isCustomElement) {
|
|
57
406
|
const allEmits: (CemEvent & { _fn: string })[] = [];
|
|
58
407
|
for (const [fnName, d] of Object.entries(defs)) {
|
|
59
408
|
if (isFunctionDef(d) && Array.isArray(d.emits)) {
|
|
@@ -85,93 +434,96 @@ export function eventsSidebarTemplate(helpers: { isCustomElementDoc: () => boole
|
|
|
85
434
|
}
|
|
86
435
|
}
|
|
87
436
|
|
|
88
|
-
// Find existing event bindings
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
437
|
+
// Find existing event bindings. Resolved once, as pairs: asking `getEventBinding` for the key and
|
|
438
|
+
// Then again for the value left a `if (!evVal) return nothing` arm nothing could ever reach.
|
|
439
|
+
const eventEntries = Object.keys(node)
|
|
440
|
+
.filter((k) => k.startsWith("on"))
|
|
441
|
+
.map((k) => [k, getEventBinding(node, k)] as const)
|
|
442
|
+
.filter((pair): pair is [string, JxEventBinding] => pair[1] !== undefined);
|
|
92
443
|
|
|
93
444
|
return html`
|
|
94
445
|
<div class="events-panel">
|
|
95
446
|
${declaredEventsT}
|
|
96
447
|
<div class="events-section">
|
|
97
448
|
${
|
|
98
|
-
|
|
449
|
+
eventEntries.length > 0
|
|
99
450
|
? html` <sp-field-label size="s">Event Bindings</sp-field-label> `
|
|
100
451
|
: nothing
|
|
101
452
|
}
|
|
102
|
-
${
|
|
103
|
-
const evVal = getEventBinding(node, evKey);
|
|
104
|
-
if (!evVal) {
|
|
105
|
-
return nothing;
|
|
106
|
-
}
|
|
453
|
+
${eventEntries.map(([evKey, evVal]) => {
|
|
107
454
|
const inlineFn: JxFunctionDef | null = isFunctionDef(evVal) ? evVal : null;
|
|
108
455
|
const expression = isExpressionDef(evVal) ? evVal.$expression : null;
|
|
109
456
|
const refValue = isRef(evVal) ? evVal.$ref : null;
|
|
110
|
-
const currentMode =
|
|
457
|
+
const currentMode = slotMode(evVal);
|
|
458
|
+
const modeFieldKey = `event|${selection.join("/")}|${evKey}`;
|
|
111
459
|
return html`
|
|
112
460
|
<div class="event-binding">
|
|
113
461
|
<div class="event-row">
|
|
114
|
-
<
|
|
462
|
+
<jx-value-selector
|
|
115
463
|
size="s"
|
|
116
464
|
class="event-name"
|
|
117
|
-
.value=${
|
|
465
|
+
.value=${evKey}
|
|
466
|
+
.options=${eventNameOptions(Object.keys(node).filter((k) => k.startsWith("on")))}
|
|
118
467
|
@change=${(e: Event) => {
|
|
119
|
-
const newKey = (e.target as HTMLInputElement).value;
|
|
120
|
-
|
|
468
|
+
const newKey = (e.target as HTMLInputElement).value.trim();
|
|
469
|
+
// A NAME, not a menu choice: the field is free-form now, so it has to refuse
|
|
470
|
+
// What it cannot bind rather than trusting a list it no longer constrains.
|
|
471
|
+
if (newKey && newKey !== evKey && /^on[a-z][\da-z-]*$/i.test(newKey)) {
|
|
472
|
+
// Renaming the key moves the binding on every selected element, in one step.
|
|
121
473
|
transactDoc(activeTab.value, (t) => {
|
|
122
|
-
|
|
123
|
-
|
|
474
|
+
for (const target of targets) {
|
|
475
|
+
const existing = getEventBinding(
|
|
476
|
+
getNodeAtPath(t.doc.document, target) as JxMutableNode,
|
|
477
|
+
evKey,
|
|
478
|
+
);
|
|
479
|
+
if (existing === undefined) {
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
482
|
+
mutateUpdateProperty(t, target, evKey);
|
|
483
|
+
mutateUpdateProperty(t, target, newKey, existing as JsonValue);
|
|
484
|
+
}
|
|
124
485
|
});
|
|
125
486
|
}
|
|
126
487
|
}}
|
|
127
488
|
>
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
)}
|
|
131
|
-
</sp-picker>
|
|
489
|
+
></jx-value-selector
|
|
490
|
+
>
|
|
132
491
|
<sp-picker
|
|
133
492
|
size="s"
|
|
134
493
|
class="event-mode"
|
|
135
494
|
.value=${live(currentMode)}
|
|
136
495
|
@change=${(e: Event) => {
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
);
|
|
152
|
-
} else {
|
|
153
|
-
const [firstFn] = functionDefs;
|
|
154
|
-
transactDoc(activeTab.value, (t) =>
|
|
155
|
-
mutateUpdateProperty(
|
|
156
|
-
t,
|
|
157
|
-
selection,
|
|
158
|
-
evKey,
|
|
159
|
-
firstFn ? { $ref: `#/state/${firstFn[0]}` } : { $ref: "" },
|
|
160
|
-
),
|
|
161
|
-
);
|
|
162
|
-
}
|
|
496
|
+
const next = (e.target as HTMLInputElement).value as SlotMode;
|
|
497
|
+
/* The same ladder the inspector's rows offer, remembering the representation
|
|
498
|
+
it left: switching to Formula and back used to throw the handler body away. */
|
|
499
|
+
commitToTargets(
|
|
500
|
+
targets,
|
|
501
|
+
evKey,
|
|
502
|
+
switchSlotMode(
|
|
503
|
+
modeFieldKey,
|
|
504
|
+
currentMode,
|
|
505
|
+
next,
|
|
506
|
+
evVal as JsonValue,
|
|
507
|
+
seedForHandlerMode(next, functionDefs),
|
|
508
|
+
) ?? seedForHandlerMode(next, functionDefs),
|
|
509
|
+
);
|
|
163
510
|
}}
|
|
164
511
|
>
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
512
|
+
${HANDLER_MODES.map(
|
|
513
|
+
(m) => html`<sp-menu-item value=${m}>${VALUE_SOURCE_LABELS[m]}</sp-menu-item>`,
|
|
514
|
+
)}
|
|
168
515
|
</sp-picker>
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
516
|
+
${renderProvenanceChip(evKey, {
|
|
517
|
+
state: mixedEventCount(tab.doc.document, targets, evKey) > 0 ? "mixed" : "set",
|
|
518
|
+
donor: String(targets.length),
|
|
519
|
+
onClick: () => commitToTargets(targets, evKey),
|
|
520
|
+
title:
|
|
521
|
+
mixedEventCount(tab.doc.document, targets, evKey) > 0
|
|
522
|
+
? `${targets.length} selected elements bind ${evKey} differently — ` +
|
|
523
|
+
`clearing removes it from all of them`
|
|
524
|
+
: `Clear ${evKey}`,
|
|
525
|
+
})}
|
|
526
|
+
<sp-action-button size="xs" quiet @click=${() => commitToTargets(targets, evKey)}>
|
|
175
527
|
<sp-icon-delete slot="icon"></sp-icon-delete>
|
|
176
528
|
</sp-action-button>
|
|
177
529
|
</div>
|
|
@@ -230,6 +582,12 @@ export function eventsSidebarTemplate(helpers: { isCustomElementDoc: () => boole
|
|
|
230
582
|
{
|
|
231
583
|
allowEventRef: true,
|
|
232
584
|
emits: inlineFn.emits ?? [],
|
|
585
|
+
// The Inspector's copy, named by the handler it edits. It answered
|
|
586
|
+
// To `navigator/statements` until the docks were split, and then
|
|
587
|
+
// To a bare `inspector/statements` — which this `.map` stamps once
|
|
588
|
+
// Per structured handler, so two handlers on a node made two
|
|
589
|
+
// Elements answer to it and `resolveRegion` took the second.
|
|
590
|
+
region: inspectorStatementsRegion(evKey),
|
|
233
591
|
stateDefs: Object.keys(defs),
|
|
234
592
|
stateEntries: defs,
|
|
235
593
|
},
|
|
@@ -258,11 +616,10 @@ export function eventsSidebarTemplate(helpers: { isCustomElementDoc: () => boole
|
|
|
258
616
|
quiet
|
|
259
617
|
title="Open in editor"
|
|
260
618
|
@click=${() => {
|
|
261
|
-
|
|
262
|
-
eventKey: evKey,
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
};
|
|
619
|
+
openLogicTarget({
|
|
620
|
+
editing: { eventKey: evKey, path: selection, type: "event" },
|
|
621
|
+
surface: "function",
|
|
622
|
+
});
|
|
266
623
|
}}
|
|
267
624
|
>
|
|
268
625
|
<sp-icon-code slot="icon"></sp-icon-code>
|
|
@@ -309,14 +666,13 @@ export function eventsSidebarTemplate(helpers: { isCustomElementDoc: () => boole
|
|
|
309
666
|
quiet
|
|
310
667
|
title="Open in formula workspace"
|
|
311
668
|
@click=${() => {
|
|
312
|
-
|
|
313
|
-
eventKey: evKey,
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
};
|
|
669
|
+
openLogicTarget({
|
|
670
|
+
editing: { eventKey: evKey, path: selection, type: "event" },
|
|
671
|
+
surface: "formula",
|
|
672
|
+
});
|
|
317
673
|
}}
|
|
318
674
|
>
|
|
319
|
-
<sp-icon-
|
|
675
|
+
<sp-icon-align-bottom slot="icon"></sp-icon-align-bottom>
|
|
320
676
|
</sp-action-button>
|
|
321
677
|
</div>
|
|
322
678
|
`
|
|
@@ -390,3 +746,161 @@ export function eventsSidebarTemplate(helpers: { isCustomElementDoc: () => boole
|
|
|
390
746
|
</div>
|
|
391
747
|
`;
|
|
392
748
|
}
|
|
749
|
+
|
|
750
|
+
// ─── The custom element's outward contract ───────────────────────────────────
|
|
751
|
+
|
|
752
|
+
/** Observed attributes: the `attribute` names a page may set from markup, and what they feed. */
|
|
753
|
+
function renderObservedAttrsSection(document: JxMutableNode) {
|
|
754
|
+
const state = document.state || {};
|
|
755
|
+
const entries = Object.entries(state).filter(([, d]) => (d as Record<string, unknown>).attribute);
|
|
756
|
+
return html`
|
|
757
|
+
<sp-accordion-item
|
|
758
|
+
label="Observed Attributes"
|
|
759
|
+
?open=${isInspectorSectionOpen("__observed", false)}
|
|
760
|
+
@sp-accordion-item-toggle=${() =>
|
|
761
|
+
setInspectorSection("__observed", !isInspectorSectionOpen("__observed", false))}
|
|
762
|
+
>
|
|
763
|
+
<div class="style-section-body">
|
|
764
|
+
${
|
|
765
|
+
entries.length === 0
|
|
766
|
+
? renderEmptyState({
|
|
767
|
+
compact: true,
|
|
768
|
+
message:
|
|
769
|
+
"Attributes let a page set this component from markup. " +
|
|
770
|
+
'Name an "attribute" on a data entry to expose it here.',
|
|
771
|
+
})
|
|
772
|
+
: entries.map(([key, d]) => {
|
|
773
|
+
const def = d as Record<string, unknown>;
|
|
774
|
+
return renderStaticKvRow({
|
|
775
|
+
detail: `→ ${key}`,
|
|
776
|
+
name: String(def.attribute),
|
|
777
|
+
...(def.type ? { value: String(def.type) } : {}),
|
|
778
|
+
...(def.reflects ? { tags: ["reflects"] } : {}),
|
|
779
|
+
});
|
|
780
|
+
})
|
|
781
|
+
}
|
|
782
|
+
</div>
|
|
783
|
+
</sp-accordion-item>
|
|
784
|
+
`;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
/** The `--custom-properties` a page may override on this component. */
|
|
788
|
+
function renderCssPropsSection(node: JxMutableNode) {
|
|
789
|
+
const style = node.style || {};
|
|
790
|
+
const cssProps = Object.entries(style).filter(([k]) => k.startsWith("--"));
|
|
791
|
+
if (cssProps.length === 0) {
|
|
792
|
+
return nothing;
|
|
793
|
+
}
|
|
794
|
+
return html`
|
|
795
|
+
<sp-accordion-item
|
|
796
|
+
label="CSS Properties"
|
|
797
|
+
?open=${isInspectorSectionOpen("__cssprops", false)}
|
|
798
|
+
@sp-accordion-item-toggle=${() =>
|
|
799
|
+
setInspectorSection("__cssprops", !isInspectorSectionOpen("__cssprops", false))}
|
|
800
|
+
>
|
|
801
|
+
<div class="style-section-body">
|
|
802
|
+
${cssProps.map(([prop, val]) => renderStaticKvRow({ name: prop, value: String(val) }))}
|
|
803
|
+
</div>
|
|
804
|
+
</sp-accordion-item>
|
|
805
|
+
`;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
/** The `part` names a page may style inside this component's shadow tree. */
|
|
809
|
+
function renderCssPartsSection(document: JxMutableNode) {
|
|
810
|
+
const parts = collectCssParts(document);
|
|
811
|
+
if (parts.length === 0) {
|
|
812
|
+
return nothing;
|
|
813
|
+
}
|
|
814
|
+
return html`
|
|
815
|
+
<sp-accordion-item
|
|
816
|
+
label="CSS Parts"
|
|
817
|
+
?open=${isInspectorSectionOpen("__cssparts", false)}
|
|
818
|
+
@sp-accordion-item-toggle=${() =>
|
|
819
|
+
setInspectorSection("__cssparts", !isInspectorSectionOpen("__cssparts", false))}
|
|
820
|
+
>
|
|
821
|
+
<div class="style-section-body">
|
|
822
|
+
${parts.map((p) => renderStaticKvRow({ detail: `<${p.tag}>`, name: p.name }))}
|
|
823
|
+
</div>
|
|
824
|
+
</sp-accordion-item>
|
|
825
|
+
`;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
// ─── The tab ─────────────────────────────────────────────────────────────────
|
|
829
|
+
|
|
830
|
+
/**
|
|
831
|
+
* The Logic tab.
|
|
832
|
+
*
|
|
833
|
+
* @param {{ isCustomElementDoc: () => boolean }} helpers — injected because the answer needs the
|
|
834
|
+
* tab's mode and ui, which the dock already has in hand.
|
|
835
|
+
*/
|
|
836
|
+
export function renderLogicPanelTemplate(helpers: {
|
|
837
|
+
isCustomElementDoc: () => boolean;
|
|
838
|
+
}): TemplateResult {
|
|
839
|
+
const { isCustomElementDoc } = helpers;
|
|
840
|
+
const tab = activeTab.value;
|
|
841
|
+
const selection = primarySelection(tab?.session.selection);
|
|
842
|
+
const doc = tab?.doc.document;
|
|
843
|
+
if (!selection) {
|
|
844
|
+
return renderEmptyState({ message: clickAnythingTo("wire it up") });
|
|
845
|
+
}
|
|
846
|
+
const node = getNodeAtPath(doc!, selection);
|
|
847
|
+
if (!node) {
|
|
848
|
+
return renderEmptyState({ message: staleSelectionMessage() });
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
// The whole selection the Logic tab wires. `[selection]` when one element is selected — which is
|
|
852
|
+
// Every existing call site's behaviour, unchanged.
|
|
853
|
+
const targets: JxPath[] =
|
|
854
|
+
tab!.session.selection.length > 0 ? tab!.session.selection : [selection];
|
|
855
|
+
const isMapNode = node.$prototype === "Array";
|
|
856
|
+
const isSwitchNode = Boolean(node.$switch);
|
|
857
|
+
const isRoot = selection.length === 0;
|
|
858
|
+
const isCustomElement = isCustomElementDoc();
|
|
859
|
+
const mapSignals = mapSignalsFor(selection);
|
|
860
|
+
|
|
861
|
+
const repeaterT = isMapNode
|
|
862
|
+
? html`
|
|
863
|
+
<sp-accordion-item label="Repeating list" open>
|
|
864
|
+
<div class="style-section-body">${renderRepeaterFieldsTemplate(node, selection)}</div>
|
|
865
|
+
</sp-accordion-item>
|
|
866
|
+
`
|
|
867
|
+
: nothing;
|
|
868
|
+
|
|
869
|
+
const switchT = isSwitchNode
|
|
870
|
+
? html`
|
|
871
|
+
<sp-accordion-item label="Condition" open>
|
|
872
|
+
<div class="style-section-body">
|
|
873
|
+
${renderSwitchFieldsTemplate(node, selection, mapSignals)}
|
|
874
|
+
</div>
|
|
875
|
+
</sp-accordion-item>
|
|
876
|
+
`
|
|
877
|
+
: nothing;
|
|
878
|
+
|
|
879
|
+
// A repeater is not an element: it has no `on*` position to bind, and offering "Add Event" on one
|
|
880
|
+
// Writes a handler onto a node the renderer never mounts.
|
|
881
|
+
const eventsT = isMapNode
|
|
882
|
+
? nothing
|
|
883
|
+
: html`
|
|
884
|
+
<sp-accordion-item label="Events" open>
|
|
885
|
+
<div class="style-section-body">
|
|
886
|
+
${renderEventsBody(node, selection, isCustomElement, targets)}
|
|
887
|
+
</div>
|
|
888
|
+
</sp-accordion-item>
|
|
889
|
+
`;
|
|
890
|
+
|
|
891
|
+
const contractT =
|
|
892
|
+
isCustomElement && isRoot
|
|
893
|
+
? html`
|
|
894
|
+
${renderObservedAttrsSection(doc!)} ${renderCssPropsSection(node)}
|
|
895
|
+
${renderCssPartsSection(doc!)}
|
|
896
|
+
`
|
|
897
|
+
: nothing;
|
|
898
|
+
|
|
899
|
+
return html`
|
|
900
|
+
<div class="style-sidebar">
|
|
901
|
+
<sp-accordion allow-multiple size="s">
|
|
902
|
+
${repeaterT} ${switchT} ${eventsT} ${contractT}
|
|
903
|
+
</sp-accordion>
|
|
904
|
+
</div>
|
|
905
|
+
`;
|
|
906
|
+
}
|