@jxsuite/studio 4.1.0 → 5.0.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/README.md +1 -1
- package/data/elements-meta.json +5 -15
- package/data/html-meta.json +51 -6
- package/dist/chunks/{2020-n6tfwnda.js → 2020-g79n01v9.js} +14 -14
- package/dist/chunks/action-group-sp6tna8v.js +118 -0
- package/dist/chunks/adapter-nj7tnjfn.js +13 -0
- package/dist/chunks/cf-account-picker-fyf63pmy.js +495 -0
- package/dist/chunks/cf-settings-71bv5zn9.js +20 -0
- package/dist/chunks/color-area-v17df7b8.js +154 -0
- package/dist/chunks/color-field-anwybnkn.js +208 -0
- package/dist/chunks/color-slider-44ez96fc.js +79 -0
- package/dist/chunks/color-xgg3kfw7.js +35 -0
- package/dist/chunks/combobox-5e7jev23.js +236 -0
- package/dist/chunks/components-2w1f35qs.js +18 -0
- package/dist/chunks/content-source-3wqeas45.js +46 -0
- package/dist/chunks/convert-to-repeater-d0cgnb6d.js +639 -0
- package/dist/chunks/dialog-s890b918.js +85 -0
- package/dist/chunks/editor-3qhbg51x.js +35 -0
- package/dist/chunks/entry-commands-d6g50j7s.js +42 -0
- package/dist/chunks/extension-sections-fy7q4fe9.js +651 -0
- package/dist/chunks/file-ops-3btj6st0.js +47 -0
- package/dist/chunks/files-ef8fgs3w.js +72 -0
- package/dist/chunks/format-host-3c33nwr8.js +40 -0
- package/dist/chunks/fs-events-13tj6sex.js +18 -0
- package/dist/chunks/git-panel-4wp2rn9b.js +49 -0
- package/dist/chunks/icons-yy10wk9r.js +402 -0
- package/dist/chunks/iframe-entry-15g3n6xv.js +114 -0
- package/dist/chunks/iframe-entry-b27vq81n.js +203 -0
- package/dist/chunks/iframe-entry-nbyxee1y.js +154 -0
- package/dist/chunks/iframe-host-jgesd924.js +115 -0
- package/dist/chunks/{index-wcnt3r9g.js → index-mdmyx6s2.js} +11 -11
- package/dist/chunks/index-n4j7qxyr.js +109 -0
- package/dist/chunks/{javascript-q8kpmfah.js → javascript-xvrfrpkb.js} +8 -9
- package/dist/chunks/{jsonMode-dkr040ga.js → jsonMode-tyx2kj6p.js} +526 -527
- package/dist/chunks/jx-validate-j0wxk72w.js +15 -0
- package/dist/chunks/layers-1nq5evsh.js +29 -0
- package/dist/chunks/layers-panel-ar2gh90g.js +40 -0
- package/dist/chunks/listbox-6v2ac08j.js +44 -0
- package/dist/chunks/lit-html-m244w9nh.js +17 -0
- package/dist/chunks/media-picker-2qbetq73.js +33 -0
- package/dist/chunks/menu-q99sy9rf.js +285 -0
- package/dist/chunks/menu-rf7n72mf.js +14 -0
- package/dist/chunks/{monaco-binding-rj6xpx9y.js → monaco-binding-sw6en4dw.js} +12 -15
- package/dist/chunks/monaco-buffer-bhy3hb6m.js +24 -0
- package/dist/chunks/{monaco-setup-vx9bhp1d.js → monaco-setup-8r62fj6y.js} +27 -37
- package/dist/chunks/notify-628t0anh.js +21 -0
- package/dist/chunks/number-field-5cndyft8.js +72 -0
- package/dist/chunks/parse-0zx14y15.js +10 -0
- package/dist/chunks/platform-ts9cg1a4.js +15 -0
- package/dist/chunks/popover-47z3ytva.js +25 -0
- package/dist/chunks/publish-panel-98f7sr3g.js +27 -0
- package/dist/chunks/quick-search-srzz83k2.js +45 -0
- package/dist/chunks/references-n553f0e1.js +26 -0
- package/dist/chunks/right-panel-rrgx2dn3.js +45 -0
- package/dist/chunks/section-registry-5pq32t0q.js +25 -0
- package/dist/chunks/select-2r16ez41.js +49 -0
- package/dist/chunks/split-g7nm1rgb.js +191 -0
- package/dist/chunks/studio-0hqbpbd0.js +62 -0
- package/dist/chunks/studio-18avnhjp.js +2430 -0
- package/dist/chunks/{studio-kryvsw6j.js → studio-1k325pwf.js} +48 -48
- package/dist/chunks/{studio-msd847zn.js → studio-25hkdrkw.js} +357 -86
- package/dist/chunks/studio-26d7myd1.js +258 -0
- package/dist/chunks/{studio-4r1pv6zf.js → studio-38emantv.js} +22 -5
- package/dist/chunks/studio-3gxv60tn.js +422 -0
- package/dist/chunks/{studio-fbf92ckf.js → studio-3hxkd92t.js} +275 -163
- package/dist/chunks/studio-4m0haseg.js +185 -0
- package/dist/chunks/{studio-ynxwkrzd.js → studio-4wbb9ct0.js} +1953 -1785
- package/dist/chunks/{studio-1wagb550.js → studio-5523bpzt.js} +11 -11
- package/dist/chunks/{studio-x4qkdat5.js → studio-57mf66w2.js} +1749 -2481
- package/dist/chunks/studio-5jy81t3s.js +17463 -0
- package/dist/chunks/studio-5rt7sqa0.js +1168 -0
- package/dist/chunks/studio-5te5tqng.js +81 -0
- package/dist/chunks/{studio-p4ngc046.js → studio-6ewqv390.js} +9 -9
- package/dist/chunks/{studio-9ab8gqsm.js → studio-6nzaktvy.js} +7 -7
- package/dist/chunks/studio-6xa21ej9.js +28 -0
- package/dist/chunks/{studio-5ehhackm.js → studio-727xh0e3.js} +19 -19
- package/dist/chunks/{studio-ahn3pdgx.js → studio-79y5sz51.js} +52 -38
- package/dist/chunks/{studio-gcye7qka.js → studio-7e11jpa9.js} +21 -21
- package/dist/chunks/{studio-q7v10cg2.js → studio-7r42c6ca.js} +17 -7
- package/dist/chunks/studio-7xptrg0j.js +954 -0
- package/dist/chunks/{studio-cft9r4r7.js → studio-81390n6f.js} +22 -22
- package/dist/chunks/{studio-q43a5y9h.js → studio-8jn5yhyn.js} +16 -16
- package/dist/chunks/studio-8qtrpzr3.js +839 -0
- package/dist/chunks/{studio-dg7zyt5x.js → studio-98b3z07n.js} +1 -1
- package/dist/chunks/studio-9xxz1q69.js +1356 -0
- package/dist/chunks/studio-akbww0j5.js +13615 -0
- package/dist/chunks/{studio-x813zp48.js → studio-arfpe389.js} +30 -30
- package/dist/chunks/{studio-trxrabqf.js → studio-az3zd49t.js} +475 -283
- package/dist/chunks/studio-cpvb2ed1.js +1171 -0
- package/dist/chunks/{studio-f3wqjtk5.js → studio-d0300636.js} +5076 -18
- package/dist/chunks/{studio-bgxt93ga.js → studio-d055c37e.js} +13 -13
- package/dist/chunks/studio-d1ja2x9r.js +362 -0
- package/dist/chunks/{studio-b9b6t1dg.js → studio-e1f24eff.js} +5664 -5666
- package/dist/chunks/{studio-3bqpr0zh.js → studio-em9nw8eh.js} +299 -110
- package/dist/chunks/studio-erdatzvp.js +1190 -0
- package/dist/chunks/{studio-g1wdche0.js → studio-esrxgwh6.js} +80 -80
- package/dist/chunks/studio-fabxk6r9.js +2811 -0
- package/dist/chunks/{studio-3n4ndrzh.js → studio-h4nvnjvz.js} +303 -303
- package/dist/chunks/{studio-dm19q43r.js → studio-hhvs4sdg.js} +10 -10
- package/dist/chunks/{studio-q9jd1a60.js → studio-kcgff4r0.js} +15 -18
- package/dist/chunks/{studio-685s0ytq.js → studio-nqgawfks.js} +572 -572
- package/dist/chunks/{studio-xrapxwwc.js → studio-p1dw8wfw.js} +55 -29
- package/dist/chunks/studio-pm6hgy7r.js +4763 -0
- package/dist/chunks/studio-q0a3yk4n.js +33 -0
- package/dist/chunks/{studio-wcy8trfx.js → studio-q3x06vmj.js} +23 -22
- package/dist/chunks/studio-qahxvnan.js +111 -0
- package/dist/chunks/{studio-53n8bp04.js → studio-r6xmmtfh.js} +1 -1
- package/dist/chunks/{studio-2b946z26.js → studio-rkstz940.js} +3658 -6134
- package/dist/chunks/{studio-tvgyw9xw.js → studio-rnyf3f8e.js} +83 -250
- package/dist/chunks/studio-rpyah2ew.js +2805 -0
- package/dist/chunks/studio-rs76k67r.js +12 -0
- package/dist/chunks/{studio-jkftxyvz.js → studio-s6z853aq.js} +5858 -2152
- package/dist/chunks/{studio-6yw4y3my.js → studio-sgdc5pfc.js} +8 -8
- package/dist/chunks/studio-tb3ev01j.js +763 -0
- package/dist/chunks/{studio-t5wqwzdh.js → studio-tjjk7jvk.js} +1 -1
- package/dist/chunks/studio-vhv5tgxm.js +51 -0
- package/dist/chunks/{studio-qjy2z9bv.js → studio-vz68yn9e.js} +32 -137
- package/dist/chunks/studio-wqpngpsk.js +174 -0
- package/dist/chunks/{studio-b55y6ewx.js → studio-x3rty6tr.js} +58 -58
- package/dist/chunks/studio-xsykpvsh.js +8448 -0
- package/dist/chunks/{studio-92ab2jqe.js → studio-y9zedyjn.js} +14 -14
- package/dist/chunks/studio-yxa81f45.js +12 -0
- package/dist/chunks/swatch-group-t0n6h2rn.js +139 -0
- package/dist/chunks/tabs-wbp1cdws.js +156 -0
- package/dist/chunks/textfield-abk6qyee.js +73 -0
- package/dist/chunks/toast-780pvfbv.js +27 -0
- package/dist/chunks/toast-host-3sqv46sn.js +116 -0
- package/dist/chunks/toolbar-xbh5bhtr.js +194 -0
- package/dist/chunks/tooltip-eptb614w.js +369 -0
- package/dist/chunks/tree-a73p0pqm.js +367 -0
- package/dist/chunks/{tsMode-76kr53q0.js → tsMode-jy4m86rv.js} +83 -85
- package/dist/chunks/workspace-wrew8zk4.js +69 -0
- package/dist/chunks/{ws-client-6shc5rze.js → ws-client-ny4zc51r.js} +20 -22
- package/dist/iframe-entry.js +1780 -667
- package/dist/studio.js +52819 -36480
- package/dist/workers/editor.worker.js +1040 -1085
- package/dist/workers/json.worker.js +1946 -1991
- package/dist/workers/ts.worker.js +4960 -5005
- package/index.html +1 -0
- package/package.json +18 -52
- package/src/about/about-modal.ts +72 -123
- package/src/browse/library-commands.ts +20 -49
- package/src/browse/library-layouts.ts +87 -218
- package/src/browse/library-pane.ts +406 -438
- package/src/canvas/canvas-helpers.ts +0 -49
- package/src/canvas/canvas-live-render.ts +25 -2
- package/src/canvas/canvas-render.ts +666 -231
- package/src/canvas/canvas-surface.ts +0 -1
- package/src/canvas/canvas-utils.ts +310 -117
- package/src/canvas/dialog-path.ts +76 -0
- package/src/canvas/dialog-state.ts +67 -0
- package/src/canvas/diff-marks.ts +252 -0
- package/src/canvas/diff-toolbar.ts +349 -0
- package/src/canvas/diff-view.ts +123 -0
- package/src/canvas/edit-width-drag.ts +187 -0
- package/src/canvas/edit-width.ts +150 -0
- package/src/canvas/iframe-entry.ts +125 -8
- package/src/canvas/iframe-host.ts +271 -15
- package/src/canvas/iframe-interaction.ts +133 -13
- package/src/canvas/iframe-patch.ts +7 -1
- package/src/canvas/iframe-position.ts +5 -6
- package/src/canvas/iframe-protocol.ts +106 -5
- package/src/canvas/iframe-render.ts +373 -5
- package/src/canvas/iframe-slash.ts +2 -2
- package/src/canvas/iframe-subtree.ts +5 -8
- package/src/canvas/path-mapping.ts +25 -3
- package/src/canvas/popover-path.ts +106 -0
- package/src/canvas/popover-state.ts +155 -0
- package/src/canvas/surface-registry.ts +21 -10
- package/src/collab/presence-chips.ts +51 -73
- package/src/commands/app-commands.ts +10 -0
- package/src/commands/budget.ts +12 -0
- package/src/commands/command-args.ts +369 -6
- package/src/commands/defaults.ts +44 -14
- package/src/commands/live-context.ts +11 -5
- package/src/commands/reference.ts +12 -2
- package/src/commands/registry.ts +165 -8
- package/src/content/entry-commands.ts +16 -23
- package/src/content/entry-editor.ts +144 -101
- package/src/editor/canvas-slash-bridge.ts +2 -2
- package/src/editor/context-menu.ts +49 -200
- package/src/editor/convert-to-component.ts +42 -82
- package/src/editor/convert-to-repeater.ts +132 -173
- package/src/editor/inline-edit.ts +11 -0
- package/src/editor/shortcuts.ts +65 -26
- package/src/editor/slash-menu.ts +150 -157
- package/src/files/file-ops.ts +117 -11
- package/src/files/files.ts +943 -660
- package/src/files/json-layout.ts +474 -0
- package/src/files/serialize-document.ts +8 -1
- package/src/format/convert-file.ts +16 -10
- package/src/format/format-host.ts +50 -1
- package/src/github/github-auth.ts +71 -29
- package/src/github/github-publish.ts +57 -65
- package/src/grid/cell-editors.ts +46 -4
- package/src/grid/cell-popovers.ts +65 -62
- package/src/grid/grid-open.ts +86 -64
- package/src/grid/grid-panel.ts +390 -469
- package/src/grid/redirects-grid.ts +40 -44
- package/src/hosting/layout.ts +2 -0
- package/src/i18n/i18n-commands.ts +127 -62
- package/src/media/media-pane.ts +83 -133
- package/src/new-project/add-repo-modal.ts +125 -176
- package/src/new-project/import-tab.ts +181 -252
- package/src/new-project/location-fields.ts +93 -160
- package/src/new-project/new-project-modal.ts +376 -367
- package/src/packages/jxsuite-update.ts +76 -18
- package/src/panels/activity-panel.ts +137 -104
- package/src/panels/ai-chat/chat-markdown.ts +15 -13
- package/src/panels/ai-chat/chat-view.ts +307 -472
- package/src/panels/ai-chat/composer.ts +175 -163
- package/src/panels/ai-chat/sessions-view.ts +31 -62
- package/src/panels/ai-panel.ts +210 -185
- package/src/panels/block-action-bar.ts +437 -643
- package/src/panels/bottom-dock.ts +112 -47
- package/src/panels/chat-panel.ts +19 -14
- package/src/panels/data-explorer.ts +141 -102
- package/src/panels/data-grid.ts +183 -150
- package/src/panels/dnd.ts +75 -20
- package/src/panels/editors.ts +26 -19
- package/src/panels/elements-panel.ts +243 -186
- package/src/panels/empty-state.ts +26 -42
- package/src/panels/events-panel.ts +950 -729
- package/src/panels/formula-workspace.ts +434 -207
- package/src/panels/frontmatter-fields.ts +185 -153
- package/src/panels/frontmatter-panel.ts +411 -187
- package/src/panels/git-diff-open.ts +148 -0
- package/src/panels/git-panel.ts +679 -605
- package/src/panels/head-panel.ts +617 -435
- package/src/panels/i18n-panel.ts +153 -133
- package/src/panels/imports-panel.ts +388 -414
- package/src/panels/jump-bar.ts +174 -147
- package/src/panels/layers-panel.ts +785 -671
- package/src/panels/left-panel.ts +166 -94
- package/src/panels/navigator-panels.ts +1 -1
- package/src/panels/pane-context.ts +529 -677
- package/src/panels/pane-grid.ts +265 -241
- package/src/panels/panel-registry.ts +15 -4
- package/src/panels/problems-panel.ts +177 -99
- package/src/panels/properties-panel.ts +1525 -966
- package/src/panels/provenance.ts +31 -113
- package/src/panels/quick-search.ts +217 -172
- package/src/panels/right-panel.ts +135 -169
- package/src/panels/seo-modal.ts +346 -167
- package/src/panels/settings-menu.ts +109 -646
- package/src/panels/settings-pane.ts +102 -86
- package/src/panels/signals-panel.ts +1318 -1172
- package/src/panels/statement-editor.ts +556 -428
- package/src/panels/style-panel.ts +1367 -630
- package/src/panels/style-utils.ts +36 -32
- package/src/panels/stylebook-doc.ts +30 -73
- package/src/panels/stylebook-layers-panel.ts +202 -109
- package/src/panels/stylebook-panel.ts +124 -88
- package/src/panels/tab-strip.ts +385 -287
- package/src/platforms/cloud.ts +106 -16
- package/src/platforms/devserver.ts +13 -0
- package/src/publish/deploy-checklist.ts +124 -78
- package/src/publish/publish-commands.ts +4 -12
- package/src/publish/publish-panel.ts +134 -328
- package/src/services/a11y-report.ts +100 -43
- package/src/services/ai-command-tools.ts +468 -0
- package/src/services/ai-session-store.ts +6 -0
- package/src/services/ai-system-prompt.ts +110 -18
- package/src/services/ai-tools.ts +28 -143
- package/src/services/ai-write-report.ts +174 -0
- package/src/services/document-assistant.ts +50 -2
- package/src/services/idle.ts +16 -14
- package/src/services/live-surfaces.ts +237 -0
- package/src/services/model-uri.ts +75 -0
- package/src/services/notify.ts +63 -6
- package/src/services/popover-report.ts +325 -0
- package/src/services/surface-registry.ts +56 -0
- package/src/services/tool-executor.ts +6 -0
- package/src/settings/contexts-section.ts +301 -299
- package/src/settings/contributed-section.ts +361 -222
- package/src/settings/css-vars-editor.ts +320 -325
- package/src/settings/defs-editor.ts +572 -535
- package/src/settings/dependencies-editor.ts +79 -107
- package/src/settings/extension-commands.ts +379 -0
- package/src/settings/extension-rows.ts +113 -0
- package/src/settings/extensions-section.ts +287 -0
- package/src/settings/general-settings.ts +130 -181
- package/src/settings/head-editor.ts +10 -305
- package/src/settings/locales-section.ts +146 -196
- package/src/settings/preferences-accounts.ts +1 -1
- package/src/settings/preferences-dialog.ts +350 -330
- package/src/settings/project-sections.ts +108 -181
- package/src/settings/schema-field-ui.ts +11 -399
- package/src/settings/section-registry.ts +8 -1
- package/src/settings/settings-document.ts +31 -29
- package/src/shell/tree.ts +42 -87
- package/src/shell.ts +48 -36
- package/src/studio.ts +90 -67
- package/src/style/token-ref.ts +0 -39
- package/src/surfaces/about.json +263 -0
- package/src/surfaces/about.ts +163 -0
- package/src/surfaces/add-repo.json +486 -0
- package/src/surfaces/add-repo.ts +236 -0
- package/src/surfaces/ai-chat.json +2185 -0
- package/src/surfaces/ai-chat.ts +549 -0
- package/src/surfaces/ai-credentials-form.json +332 -0
- package/src/surfaces/ai-credentials-form.ts +151 -0
- package/src/surfaces/ai-managed-connect.json +108 -0
- package/src/surfaces/ai-managed-connect.ts +123 -0
- package/src/surfaces/ai-model-picker.json +114 -0
- package/src/surfaces/ai-model-picker.ts +139 -0
- package/src/surfaces/block-action-bar.json +640 -0
- package/src/surfaces/block-action-bar.ts +368 -0
- package/src/surfaces/bottom-dock.json +154 -0
- package/src/surfaces/bottom-dock.ts +125 -0
- package/src/surfaces/canvas-stage.json +444 -0
- package/src/surfaces/canvas-stage.ts +253 -0
- package/src/surfaces/cf-account-picker.json +300 -0
- package/src/surfaces/cf-account-picker.ts +214 -0
- package/src/surfaces/commandbar.json +984 -0
- package/src/{panels/toolbar.ts → surfaces/commandbar.ts} +414 -389
- package/src/surfaces/convert-repeater.json +309 -0
- package/src/surfaces/convert-repeater.ts +276 -0
- package/src/surfaces/data-actions.json +157 -0
- package/src/surfaces/data-actions.ts +115 -0
- package/src/surfaces/dialog.json +289 -0
- package/src/surfaces/dialog.ts +343 -0
- package/src/surfaces/diff-toolbar.json +266 -0
- package/src/surfaces/diff-toolbar.ts +139 -0
- package/src/surfaces/doc-header.json +739 -0
- package/src/surfaces/doc-header.ts +223 -0
- package/src/surfaces/empty-state.json +152 -0
- package/src/surfaces/empty-state.ts +173 -0
- package/src/surfaces/entry-editor.json +281 -0
- package/src/surfaces/entry-editor.ts +191 -0
- package/src/surfaces/expression-editor.json +977 -0
- package/src/surfaces/expression-editor.ts +266 -0
- package/src/surfaces/files-panel.json +592 -0
- package/src/surfaces/files-panel.ts +301 -0
- package/src/surfaces/formula-palette.json +364 -0
- package/src/surfaces/formula-palette.ts +340 -0
- package/src/surfaces/git-panel.json +1822 -0
- package/src/surfaces/git-panel.ts +272 -0
- package/src/surfaces/github-auth.json +112 -0
- package/src/surfaces/github-auth.ts +139 -0
- package/src/surfaces/github-publish.json +206 -0
- package/src/surfaces/github-publish.ts +169 -0
- package/src/surfaces/grid-cell.json +218 -0
- package/src/surfaces/grid-cell.ts +120 -0
- package/src/surfaces/grid-open.json +147 -0
- package/src/surfaces/grid-open.ts +87 -0
- package/src/surfaces/grid-panel.json +706 -0
- package/src/surfaces/grid-panel.ts +206 -0
- package/src/surfaces/grid-replace.json +179 -0
- package/src/surfaces/grid-replace.ts +89 -0
- package/src/surfaces/grid-views.json +446 -0
- package/src/surfaces/grid-views.ts +172 -0
- package/src/surfaces/inspector-dock.json +187 -0
- package/src/surfaces/inspector-dock.ts +161 -0
- package/src/surfaces/jump-bar.json +243 -0
- package/src/surfaces/jump-bar.ts +129 -0
- package/src/surfaces/jxsuite-update.json +146 -0
- package/src/surfaces/jxsuite-update.ts +149 -0
- package/src/surfaces/library-pane.json +1509 -0
- package/src/surfaces/library-pane.ts +363 -0
- package/src/surfaces/logic-panel.json +1949 -0
- package/src/surfaces/logic-panel.ts +369 -0
- package/src/surfaces/logic-workspace.json +685 -0
- package/src/surfaces/logic-workspace.ts +238 -0
- package/src/surfaces/media-browser.json +303 -0
- package/src/surfaces/media-browser.ts +145 -0
- package/src/surfaces/media-field.json +163 -0
- package/src/surfaces/media-field.ts +116 -0
- package/src/surfaces/media-pane.json +513 -0
- package/src/surfaces/media-pane.ts +197 -0
- package/src/surfaces/menu.json +232 -0
- package/src/surfaces/menu.ts +375 -0
- package/src/surfaces/navigator-dock.json +113 -0
- package/src/surfaces/navigator-dock.ts +130 -0
- package/src/surfaces/new-project.json +1654 -0
- package/src/surfaces/new-project.ts +411 -0
- package/src/surfaces/palette.json +535 -0
- package/src/surfaces/pane-context.json +1497 -0
- package/src/surfaces/pane-context.ts +513 -0
- package/src/surfaces/pane-grid.json +188 -0
- package/src/surfaces/pane-grid.ts +250 -0
- package/src/surfaces/panel-activity.json +563 -0
- package/src/surfaces/panel-activity.ts +187 -0
- package/src/surfaces/panel-data.json +141 -0
- package/src/surfaces/panel-data.ts +156 -0
- package/src/surfaces/panel-deploy-checklist.json +283 -0
- package/src/surfaces/panel-deploy-checklist.ts +175 -0
- package/src/surfaces/panel-elements.json +367 -0
- package/src/surfaces/panel-elements.ts +175 -0
- package/src/surfaces/panel-i18n.json +569 -0
- package/src/surfaces/panel-i18n.ts +212 -0
- package/src/surfaces/panel-imports.json +780 -0
- package/src/surfaces/panel-imports.ts +209 -0
- package/src/surfaces/panel-outline.json +734 -0
- package/src/surfaces/panel-outline.ts +326 -0
- package/src/surfaces/panel-page.json +1017 -0
- package/src/surfaces/panel-page.ts +240 -0
- package/src/surfaces/panel-problems.json +497 -0
- package/src/surfaces/panel-problems.ts +157 -0
- package/src/surfaces/panel-signals.json +1973 -0
- package/src/surfaces/panel-signals.ts +436 -0
- package/src/surfaces/panel-stylebook-layers.json +317 -0
- package/src/surfaces/panel-stylebook-layers.ts +155 -0
- package/src/surfaces/preferences.json +850 -0
- package/src/surfaces/preferences.ts +332 -0
- package/src/surfaces/progress-modal.json +110 -0
- package/src/surfaces/progress-modal.ts +150 -0
- package/src/surfaces/properties-panel.json +1578 -0
- package/src/surfaces/properties-panel.ts +337 -0
- package/src/surfaces/publish.json +945 -0
- package/src/surfaces/publish.ts +392 -0
- package/src/surfaces/push-plan.json +110 -0
- package/src/surfaces/push-plan.ts +87 -0
- package/src/surfaces/rail.json +255 -0
- package/src/surfaces/rail.ts +206 -0
- package/src/surfaces/reference-field.json +191 -0
- package/src/surfaces/reference-field.ts +168 -0
- package/src/surfaces/schema-builder.json +1011 -0
- package/src/surfaces/schema-builder.ts +181 -0
- package/src/surfaces/schema-form.json +1013 -0
- package/src/surfaces/schema-form.ts +287 -0
- package/src/surfaces/secret-field.json +60 -0
- package/src/surfaces/secret-field.ts +146 -0
- package/src/surfaces/seo.json +932 -0
- package/src/surfaces/seo.ts +334 -0
- package/src/surfaces/settings-contexts.json +538 -0
- package/src/surfaces/settings-contexts.ts +196 -0
- package/src/surfaces/settings-contributed.json +489 -0
- package/src/surfaces/settings-contributed.ts +199 -0
- package/src/surfaces/settings-css-vars.json +820 -0
- package/src/surfaces/settings-css-vars.ts +199 -0
- package/src/surfaces/settings-defs.json +1363 -0
- package/src/surfaces/settings-defs.ts +232 -0
- package/src/surfaces/settings-deploy.json +108 -0
- package/src/surfaces/settings-deploy.ts +135 -0
- package/src/surfaces/settings-extensions.json +486 -0
- package/src/surfaces/settings-extensions.ts +201 -0
- package/src/surfaces/settings-head.json +779 -0
- package/src/surfaces/settings-head.ts +397 -0
- package/src/surfaces/settings-locales.json +420 -0
- package/src/surfaces/settings-locales.ts +137 -0
- package/src/surfaces/settings-overview.json +423 -0
- package/src/surfaces/settings-overview.ts +218 -0
- package/src/surfaces/settings-packages.json +549 -0
- package/src/surfaces/settings-packages.ts +158 -0
- package/src/surfaces/settings-pane.json +147 -0
- package/src/surfaces/settings-pane.ts +150 -0
- package/src/surfaces/settings-rawjson.json +104 -0
- package/src/surfaces/settings-rawjson.ts +107 -0
- package/src/surfaces/shell.json +99 -0
- package/src/surfaces/shell.ts +30 -0
- package/src/surfaces/slash-menu.json +180 -0
- package/src/surfaces/slash-menu.ts +272 -0
- package/src/surfaces/statements.json +607 -0
- package/src/surfaces/statements.ts +238 -0
- package/src/surfaces/statusbar.json +94 -0
- package/src/{panels → surfaces}/statusbar.ts +163 -90
- package/src/surfaces/style-panel.json +1643 -0
- package/src/surfaces/style-panel.ts +338 -0
- package/src/surfaces/stylebook-chrome.json +122 -0
- package/src/surfaces/stylebook-chrome.ts +122 -0
- package/src/surfaces/tab-strip.json +448 -0
- package/src/surfaces/tab-strip.ts +200 -0
- package/src/surfaces/target-line.json +419 -0
- package/src/surfaces/target-line.ts +349 -0
- package/src/surfaces/toasts.json +189 -0
- package/src/surfaces/welcome.json +571 -0
- package/src/surfaces/welcome.ts +338 -0
- package/src/tabs/project-config.ts +71 -15
- package/src/tabs/tab.ts +52 -1
- package/src/types.ts +22 -0
- package/src/ui/ai-credentials-form.ts +104 -100
- package/src/ui/ai-managed-connect.ts +54 -36
- package/src/ui/ai-model-picker.ts +75 -47
- package/src/ui/cf-account-picker.ts +76 -141
- package/src/ui/color-selector.ts +80 -301
- package/src/ui/dynamic-slot.ts +43 -283
- package/src/ui/expression-editor.ts +797 -576
- package/src/ui/field-input.ts +8 -181
- package/src/ui/form-controls.ts +838 -366
- package/src/ui/formula-chips.ts +80 -85
- package/src/ui/kit.ts +33 -0
- package/src/ui/layers.ts +293 -593
- package/src/ui/media-picker.ts +203 -284
- package/src/ui/panel-resize.ts +251 -64
- package/src/ui/popover-surface.ts +153 -0
- package/src/ui/progress-modal.ts +22 -60
- package/src/ui/regions.ts +13 -7
- package/src/ui/schema-form.ts +906 -440
- package/src/ui/surface.ts +122 -0
- package/src/ui/unit-selector.ts +15 -131
- package/src/ui/value-source.ts +14 -0
- package/src/ui/virtual-window.ts +88 -9
- package/src/utils/canvas-media.ts +72 -0
- package/src/utils/edit-display.ts +7 -2
- package/src/utils/element-selectors.ts +69 -0
- package/src/utils/link-target.ts +2 -2
- package/src/utils/studio-utils.ts +0 -10
- package/src/view.ts +15 -0
- package/src/workspace/pane-derive.ts +36 -14
- package/src/workspace/workspace.ts +15 -6
- package/styles/canvas.css +72 -467
- package/styles/forced-colors.css +48 -82
- package/styles/forced-colors.json +41 -0
- package/styles/inspector.css +2 -1301
- package/styles/overlays.css +96 -2823
- package/styles/panels.css +6 -1423
- package/styles/shell-frame.css +272 -0
- package/styles/shell-frame.json +227 -0
- package/styles/shell.css +0 -1568
- package/styles/tokens.css +65 -136
- package/styles/tokens.json +84 -0
- package/dist/chunks/Overlay.dev-etqjwyf9.js +0 -23
- package/dist/chunks/adapter-jkcyhgtr.js +0 -14
- package/dist/chunks/cf-account-picker-en86v7x7.js +0 -163
- package/dist/chunks/cf-settings-45fgyx8y.js +0 -21
- package/dist/chunks/components-zmx10t62.js +0 -21
- package/dist/chunks/content-source-48xg86wj.js +0 -49
- package/dist/chunks/convert-to-repeater-43tfn7cs.js +0 -268
- package/dist/chunks/editor-cptq5jp1.js +0 -37
- package/dist/chunks/entry-commands-e63f1xc0.js +0 -46
- package/dist/chunks/extension-sections-txv08xxg.js +0 -311
- package/dist/chunks/file-ops-wbh4hhsx.js +0 -48
- package/dist/chunks/files-3kfkwhk4.js +0 -93
- package/dist/chunks/flow-qbfgrpeh.js +0 -634
- package/dist/chunks/focus-trap.esm-9t2drp0g.js +0 -1025
- package/dist/chunks/focus-visible-6eg70z18.js +0 -167
- package/dist/chunks/format-host-w16q81tf.js +0 -43
- package/dist/chunks/fs-events-hrrg328g.js +0 -21
- package/dist/chunks/git-panel-532whr1y.js +0 -59
- package/dist/chunks/index-zqxmqxmh.js +0 -109
- package/dist/chunks/jx-validate-8er6gbxy.js +0 -19
- package/dist/chunks/layers-panel-07hm7g5j.js +0 -67
- package/dist/chunks/layers-q75tj2mf.js +0 -45
- package/dist/chunks/lit-html-j055mkh8.js +0 -22
- package/dist/chunks/monaco-buffer-dqw0xxpx.js +0 -25
- package/dist/chunks/notify-yjm79n4s.js +0 -30
- package/dist/chunks/parse-24d0gay3.js +0 -19
- package/dist/chunks/platform-ba1j1gbh.js +0 -16
- package/dist/chunks/publish-panel-v9st96ja.js +0 -29
- package/dist/chunks/quick-search-zccjp6gv.js +0 -66
- package/dist/chunks/references-3qx8fkyp.js +0 -29
- package/dist/chunks/right-panel-vm3b6kwy.js +0 -46
- package/dist/chunks/section-registry-sx1ykvkw.js +0 -30
- package/dist/chunks/sp-overlay.dev-qgvhnxf4.js +0 -18
- package/dist/chunks/sp-popover.dev-n2etmqdp.js +0 -9
- package/dist/chunks/sp-progress-circle.dev-hryhj0es.js +0 -15
- package/dist/chunks/sp-tooltip.dev-4sastdnw.js +0 -15
- package/dist/chunks/sp-tray.dev-tkbscm06.js +0 -199
- package/dist/chunks/studio-0a5qrh01.js +0 -3
- package/dist/chunks/studio-0bq6eh7v.js +0 -12
- package/dist/chunks/studio-18j3bmcz.js +0 -14
- package/dist/chunks/studio-1ngbejft.js +0 -181
- package/dist/chunks/studio-4b5z1x43.js +0 -424
- package/dist/chunks/studio-4n2b5gzb.js +0 -357
- package/dist/chunks/studio-4rzyrtjz.js +0 -426
- package/dist/chunks/studio-5fx3g9jg.js +0 -4325
- package/dist/chunks/studio-5myknm0a.js +0 -1903
- package/dist/chunks/studio-7afd21nw.js +0 -67
- package/dist/chunks/studio-7nte2hj4.js +0 -613
- package/dist/chunks/studio-8jpzqk5s.js +0 -128
- package/dist/chunks/studio-8q517dfr.js +0 -24
- package/dist/chunks/studio-950k0dx6.js +0 -6939
- package/dist/chunks/studio-9n4mrmnb.js +0 -184
- package/dist/chunks/studio-a0tswy0w.js +0 -58
- package/dist/chunks/studio-ahnzd9rg.js +0 -23
- package/dist/chunks/studio-cmb03bg5.js +0 -13890
- package/dist/chunks/studio-d1ks410h.js +0 -175
- package/dist/chunks/studio-ef49pnzx.js +0 -387
- package/dist/chunks/studio-eqq1w638.js +0 -113
- package/dist/chunks/studio-ew0djmhg.js +0 -341
- package/dist/chunks/studio-gfgb8pe6.js +0 -1652
- package/dist/chunks/studio-h4rxscfc.js +0 -10
- package/dist/chunks/studio-jc994dnr.js +0 -1066
- package/dist/chunks/studio-kyh9avvv.js +0 -28
- package/dist/chunks/studio-m3hwn7y1.js +0 -120
- package/dist/chunks/studio-mtfnaqs9.js +0 -659
- package/dist/chunks/studio-n6j9t10q.js +0 -318
- package/dist/chunks/studio-n8b9wqwy.js +0 -291
- package/dist/chunks/studio-qcy05dp8.js +0 -1743
- package/dist/chunks/studio-qq6jym04.js +0 -53
- package/dist/chunks/studio-rdx8jcxy.js +0 -83
- package/dist/chunks/studio-rn9ta2mz.js +0 -111
- package/dist/chunks/studio-t7qb9db8.js +0 -665
- package/dist/chunks/studio-tmc5emrw.js +0 -8
- package/dist/chunks/studio-z6nw2ek2.js +0 -18
- package/dist/chunks/studio-zczps70q.js +0 -378
- package/dist/chunks/studio-zqazsct2.js +0 -1823
- package/dist/chunks/workspace-fjx52ryv.js +0 -89
- package/src/panels/activity-bar.ts +0 -251
- package/src/panels/panel-scheduler.ts +0 -219
- package/src/panels/style-inputs.ts +0 -237
- package/src/panels/target-line.ts +0 -274
- package/src/panels/welcome-screen.ts +0 -346
- package/src/ui/button-group.ts +0 -102
- package/src/ui/choice-field.ts +0 -72
- package/src/ui/field-row.ts +0 -249
- package/src/ui/formula-palette.ts +0 -213
- package/src/ui/icons.ts +0 -52
- package/src/ui/jx-theme.ts +0 -130
- package/src/ui/spectrum.ts +0 -340
- package/src/ui/value-selector.ts +0 -174
- package/src/ui/widgets.ts +0 -172
- /package/dist/chunks/{javascript-s56a8dpk.css → javascript-4abzjcy9.css} +0 -0
- /package/dist/chunks/{jsonMode-zr9sw0c7.css → jsonMode-vvmpmk34.css} +0 -0
- /package/dist/chunks/{monaco-setup-pav68602.css → monaco-setup-8vbyqnhr.css} +0 -0
- /package/dist/chunks/{tsMode-ef187txx.css → tsMode-hnxxb73h.css} +0 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one way a Studio surface document is mounted.
|
|
3
|
+
*
|
|
4
|
+
* A surface is a Jx document under `src/surfaces/`, bundled as JSON and registered here by name.
|
|
5
|
+
* The adapter that owns a surface builds a scope of host records and functions and calls
|
|
6
|
+
* `mountSurface`; this module waits for the kit, mounts through the runtime's `mount()` with the
|
|
7
|
+
* surfaces' own base and resolver so a document's `$ref`s resolve with no network, stamps the
|
|
8
|
+
* host's region id, and records the mount so a redefinition or a saved edit can find it
|
|
9
|
+
* (specs/studio-ui-guidelines.md §9.3, specs/embedding.md §2).
|
|
10
|
+
*
|
|
11
|
+
* @docs extending/ui-kit
|
|
12
|
+
*/
|
|
13
|
+
import { mount, preloadDocument } from "@jxsuite/runtime";
|
|
14
|
+
import type { JxMountOptions, JxScope } from "@jxsuite/runtime/types";
|
|
15
|
+
import type { JxDocument } from "@jxsuite/schema/types";
|
|
16
|
+
import { registerMount, unregisterMount } from "../services/surface-registry";
|
|
17
|
+
import { kitReady } from "./kit";
|
|
18
|
+
import { REGION_ATTR } from "./regions";
|
|
19
|
+
|
|
20
|
+
/** The URL every surface document is known by: `jx-studio:/surfaces/<name>.json`. */
|
|
21
|
+
export const SURFACES_BASE = "jx-studio:/surfaces/";
|
|
22
|
+
|
|
23
|
+
const surfaces = new Map<string, JxDocument>();
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Register a surface document under a name. Bundled JSON, so it is also preloaded under its URL for
|
|
27
|
+
* the runtime's own resolution paths.
|
|
28
|
+
*/
|
|
29
|
+
export function registerSurface(name: string, doc: JxDocument): void {
|
|
30
|
+
surfaces.set(name, doc);
|
|
31
|
+
preloadDocument(surfaceUrl(name), doc);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** The URL a surface name resolves to. */
|
|
35
|
+
export function surfaceUrl(name: string): string {
|
|
36
|
+
return `${SURFACES_BASE}${name}.json`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** The registered document for a name, if any. */
|
|
40
|
+
export function surfaceDocument(name: string): JxDocument | undefined {
|
|
41
|
+
return surfaces.get(name);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** The mount resolver: answers surface URLs from the registry and nothing else. */
|
|
45
|
+
export function surfaceResolver(url: string): JxDocument | undefined {
|
|
46
|
+
if (!url.startsWith(SURFACES_BASE) || !url.endsWith(".json")) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
return surfaces.get(url.slice(SURFACES_BASE.length, -".json".length));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface SurfaceHandle {
|
|
53
|
+
readonly scope: JxScope;
|
|
54
|
+
readonly root: HTMLElement | Text;
|
|
55
|
+
readonly elements: ReadonlySet<string>;
|
|
56
|
+
readonly dispose: () => void;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface MountSurfaceOptions {
|
|
60
|
+
/** A `data-jx-region` id stamped on the host, so the screenshot pipeline can address it. */
|
|
61
|
+
region?: string;
|
|
62
|
+
onNodeCreated?: JxMountOptions["onNodeCreated"];
|
|
63
|
+
onNodeMoved?: JxMountOptions["onNodeMoved"];
|
|
64
|
+
signal?: AbortSignal;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Mount a registered surface into a host node with the given host scope.
|
|
69
|
+
*
|
|
70
|
+
* @throws {Error} When no document is registered under `name`
|
|
71
|
+
*/
|
|
72
|
+
export async function mountSurface(
|
|
73
|
+
name: string,
|
|
74
|
+
hostScope: Record<string, unknown>,
|
|
75
|
+
host: HTMLElement,
|
|
76
|
+
options: MountSurfaceOptions = {},
|
|
77
|
+
): Promise<SurfaceHandle> {
|
|
78
|
+
const doc = surfaces.get(name);
|
|
79
|
+
if (!doc) {
|
|
80
|
+
throw new Error(`Studio surface "${name}" is not registered`);
|
|
81
|
+
}
|
|
82
|
+
await kitReady();
|
|
83
|
+
if (options.region) {
|
|
84
|
+
host.setAttribute(REGION_ATTR, options.region);
|
|
85
|
+
}
|
|
86
|
+
const handle = await mount(doc, host, {
|
|
87
|
+
scope: hostScope,
|
|
88
|
+
base: SURFACES_BASE,
|
|
89
|
+
resolver: surfaceResolver,
|
|
90
|
+
...(options.onNodeCreated ? { onNodeCreated: options.onNodeCreated } : {}),
|
|
91
|
+
...(options.onNodeMoved ? { onNodeMoved: options.onNodeMoved } : {}),
|
|
92
|
+
...(options.signal ? { signal: options.signal } : {}),
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const surfaceHandle = (dispose: () => void): SurfaceHandle => ({
|
|
96
|
+
dispose,
|
|
97
|
+
elements: handle.elements,
|
|
98
|
+
root: handle.root,
|
|
99
|
+
scope: handle.scope,
|
|
100
|
+
});
|
|
101
|
+
if (options.signal?.aborted) {
|
|
102
|
+
// The runtime already disposed it without attaching; there is no mount to record.
|
|
103
|
+
return surfaceHandle(handle.dispose);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
let id = 0;
|
|
107
|
+
const dispose = (): void => {
|
|
108
|
+
handle.dispose();
|
|
109
|
+
unregisterMount(id);
|
|
110
|
+
};
|
|
111
|
+
id = registerMount({
|
|
112
|
+
elements: handle.elements,
|
|
113
|
+
host,
|
|
114
|
+
name,
|
|
115
|
+
remount: async () => {
|
|
116
|
+
dispose();
|
|
117
|
+
await mountSurface(name, hostScope, host, options);
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
options.signal?.addEventListener("abort", () => unregisterMount(id), { once: true });
|
|
121
|
+
return surfaceHandle(dispose);
|
|
122
|
+
}
|
package/src/ui/unit-selector.ts
CHANGED
|
@@ -1,138 +1,22 @@
|
|
|
1
|
-
/// <reference lib="dom" />
|
|
2
1
|
/**
|
|
3
|
-
*
|
|
2
|
+
* The CSS length grammar the Style tab parses a typed value with.
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* This module used to draw the control as well — an `sp-textfield` beside an `sp-picker-button` and
|
|
5
|
+
* an `sp-overlay` of units — and that control is now the Style tab's own composite over the kit
|
|
6
|
+
* (`surfaces/style-panel.json`'s `group` widget: a field the reader may type anything into, beside
|
|
7
|
+
* a button that opens the KIT MENU of units and keywords). What could not move into the document is
|
|
8
|
+
* this: deciding whether `12px`, `auto` and `10px 20px` are a number with a unit, a keyword, or a
|
|
9
|
+
* value that only partially parses. That is a decision, so it stays in TypeScript, and it stays in
|
|
10
|
+
* ONE place because the panel reads it three times over — for the number the field shows, for the
|
|
11
|
+
* placeholder an inherited value contributes, and for the unit a menu choice re-attaches.
|
|
7
12
|
*/
|
|
8
13
|
|
|
9
|
-
import { html, nothing } from "lit-html";
|
|
10
|
-
import { live } from "lit-html/directives/live.js";
|
|
11
|
-
import { classMap } from "lit-html/directives/class-map.js";
|
|
12
|
-
import { cancelStyleDebounce, debouncedStyleCommit } from "../store";
|
|
13
|
-
|
|
14
|
-
export const UNIT_RE = /^(-?[\d.]+)(px|rem|em|%|vw|vh|svw|svh|dvh|ms|s|fr|ch|ex|deg)?$/;
|
|
15
|
-
|
|
16
14
|
/**
|
|
17
|
-
*
|
|
15
|
+
* A number and, optionally, one of the units the panel offers.
|
|
18
16
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* @param {string} [placeholder]
|
|
24
|
-
* @returns {import("lit-html").TemplateResult}
|
|
17
|
+
* Anchored at both ends on purpose: a value that is a length AND something else — `10px 20px`, a
|
|
18
|
+
* `calc()`, a `${}` template — must NOT match, because matching would let the unit menu rewrite a
|
|
19
|
+
* value it does not understand. Those fall through to the partial-parse path instead, which shows
|
|
20
|
+
* the leading number and leaves the value alone.
|
|
25
21
|
*/
|
|
26
|
-
export
|
|
27
|
-
/** @type {Record<string, unknown>} */ entry: Record<string, unknown>,
|
|
28
|
-
/** @type {string} */ prop: string,
|
|
29
|
-
/** @type {string | number | undefined} */ value: string | number | undefined,
|
|
30
|
-
/** @type {(val: string) => void} */ onChange: (val: string) => void,
|
|
31
|
-
/** @type {string} */ placeholder = "",
|
|
32
|
-
) {
|
|
33
|
-
const units = (entry.$units || []) as string[];
|
|
34
|
-
const keywords = (entry.$keywords || []) as string[];
|
|
35
|
-
const strVal = String(value ?? "");
|
|
36
|
-
const match = strVal.match(UNIT_RE);
|
|
37
|
-
const isKeyword = !match && strVal !== "" && keywords.includes(strVal);
|
|
38
|
-
const isNumericVal = (v: string) => /^-?\d*\.?\d*$/.test(v);
|
|
39
|
-
|
|
40
|
-
const currentUnit = isKeyword ? units[0] || "" : match ? match[2] || "" : units[0] || "";
|
|
41
|
-
let displayValue;
|
|
42
|
-
if (isKeyword) {
|
|
43
|
-
displayValue = strVal;
|
|
44
|
-
} else if (match) {
|
|
45
|
-
displayValue = match[1]!;
|
|
46
|
-
} else if (strVal !== "") {
|
|
47
|
-
// Intentional partial parse: shorthand like "10px 20px" displays its leading number.
|
|
48
|
-
// Number() yields NaN for those, so Number.parseFloat stays (see unit-selector tests).
|
|
49
|
-
// oxlint-disable-next-line unicorn/prefer-number-coercion
|
|
50
|
-
const num = Number.parseFloat(strVal);
|
|
51
|
-
displayValue = Number.isNaN(num) ? strVal : String(num);
|
|
52
|
-
} else {
|
|
53
|
-
displayValue = "";
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Parse placeholder so inherited values display as "500" not "500px"
|
|
57
|
-
const placeholderMatch = placeholder.match(UNIT_RE);
|
|
58
|
-
const numericPlaceholder = placeholderMatch ? placeholderMatch[1]! : placeholder || "0";
|
|
59
|
-
|
|
60
|
-
const isExpression = isKeyword || (displayValue !== "" && !isNumericVal(displayValue));
|
|
61
|
-
const hasUnits = units.length > 0 || keywords.length > 0;
|
|
62
|
-
const btnId = `style-unit-${prop}`;
|
|
63
|
-
|
|
64
|
-
const commitValue = (rawVal: string) => {
|
|
65
|
-
const val = rawVal.trim();
|
|
66
|
-
if (val === "") {
|
|
67
|
-
onChange("");
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
if (isNumericVal(val)) {
|
|
71
|
-
onChange(units.length > 0 ? val + currentUnit : val);
|
|
72
|
-
} else {
|
|
73
|
-
onChange(val);
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
return html`
|
|
78
|
-
<div class="style-input-number-unit">
|
|
79
|
-
<div
|
|
80
|
-
class=${classMap({
|
|
81
|
-
"input-group": true,
|
|
82
|
-
"is-expression": isExpression,
|
|
83
|
-
})}
|
|
84
|
-
>
|
|
85
|
-
<sp-textfield
|
|
86
|
-
size="s"
|
|
87
|
-
placeholder=${numericPlaceholder}
|
|
88
|
-
.value=${live(displayValue)}
|
|
89
|
-
@input=${debouncedStyleCommit(`nui:${prop}`, 400, (e: Event) => {
|
|
90
|
-
commitValue((e.target as HTMLInputElement).value);
|
|
91
|
-
})}
|
|
92
|
-
@change=${(e: Event) => {
|
|
93
|
-
cancelStyleDebounce(`nui:${prop}`);
|
|
94
|
-
commitValue((e.target as HTMLInputElement).value);
|
|
95
|
-
}}
|
|
96
|
-
></sp-textfield>
|
|
97
|
-
${
|
|
98
|
-
hasUnits
|
|
99
|
-
? html`
|
|
100
|
-
<sp-picker-button id=${btnId} size="s">
|
|
101
|
-
<span slot="label">${currentUnit || units[0] || ""}</span>
|
|
102
|
-
</sp-picker-button>
|
|
103
|
-
<sp-overlay trigger="${btnId}@click" placement="bottom-end" offset="4">
|
|
104
|
-
<sp-popover style="min-width: var(--spectrum-component-width-900, 64px)">
|
|
105
|
-
<sp-menu
|
|
106
|
-
label="CSS unit"
|
|
107
|
-
@change=${(e: Event) => {
|
|
108
|
-
const chosen = (e.target as HTMLInputElement).value;
|
|
109
|
-
if (keywords.includes(chosen)) {
|
|
110
|
-
onChange(chosen);
|
|
111
|
-
} else if (units.includes(chosen)) {
|
|
112
|
-
const curMatch = String(value ?? "").match(UNIT_RE);
|
|
113
|
-
const numPart = curMatch ? curMatch[1] : "";
|
|
114
|
-
if (numPart) {
|
|
115
|
-
onChange(numPart + chosen);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}}
|
|
119
|
-
>
|
|
120
|
-
${units.map((u: string) => html`<sp-menu-item value=${u}>${u}</sp-menu-item>`)}
|
|
121
|
-
${
|
|
122
|
-
keywords.length > 0 && units.length > 0
|
|
123
|
-
? html`<sp-menu-divider></sp-menu-divider>`
|
|
124
|
-
: nothing
|
|
125
|
-
}
|
|
126
|
-
${keywords.map(
|
|
127
|
-
(kw: string) => html`<sp-menu-item value=${kw}>${kw}</sp-menu-item>`,
|
|
128
|
-
)}
|
|
129
|
-
</sp-menu>
|
|
130
|
-
</sp-popover>
|
|
131
|
-
</sp-overlay>
|
|
132
|
-
`
|
|
133
|
-
: nothing
|
|
134
|
-
}
|
|
135
|
-
</div>
|
|
136
|
-
</div>
|
|
137
|
-
`;
|
|
138
|
-
}
|
|
22
|
+
export const UNIT_RE = /^(-?[\d.]+)(px|rem|em|%|vw|vh|svw|svh|dvh|ms|s|fr|ch|ex|deg)?$/;
|
package/src/ui/value-source.ts
CHANGED
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
stringOrRefSchema,
|
|
41
41
|
styleObjectSchema,
|
|
42
42
|
switchDefSchema,
|
|
43
|
+
tagExpressionSchema,
|
|
43
44
|
tagNameSchema,
|
|
44
45
|
} from "@jxsuite/schema/defs";
|
|
45
46
|
import { isFunctionDef, isRef, isTemplateString } from "@jxsuite/schema/guards";
|
|
@@ -261,6 +262,19 @@ const ELEMENT_TAG_SCHEMA = {
|
|
|
261
262
|
anyOf: [tagNameSchema, ...elementTagNameSchema.anyOf.slice(1)],
|
|
262
263
|
} as const;
|
|
263
264
|
|
|
265
|
+
/**
|
|
266
|
+
* The operators a `TagExpression` admits, READ OFF THE DEF rather than restated beside it.
|
|
267
|
+
*
|
|
268
|
+
* The Formula rung at a tag position is not the whole operator table: `TagExpression` is two
|
|
269
|
+
* branches, `?:` and `switch`, and every other operator produces a document `jx validate` rejects
|
|
270
|
+
* and `tagNameCandidates` cannot enumerate. The rung is derived from the schema and so is the
|
|
271
|
+
* grammar inside it, for the same reason — a third branch upstream reaches the Inspector by itself,
|
|
272
|
+
* and a hand-kept pair would not have noticed.
|
|
273
|
+
*/
|
|
274
|
+
export const TAG_EXPRESSION_OPERATORS: readonly string[] = tagExpressionSchema.anyOf.map(
|
|
275
|
+
(branch) => branch.properties.operator.const,
|
|
276
|
+
);
|
|
277
|
+
|
|
264
278
|
/**
|
|
265
279
|
* The document positions a bindable slot can occupy. A panel names the position it is editing; the
|
|
266
280
|
* rungs follow from the schema, so a panel can no longer offer a rung the compiler would reject —
|
package/src/ui/virtual-window.ts
CHANGED
|
@@ -114,9 +114,24 @@ export function computeWindow(spec: WindowSpec): WindowRange {
|
|
|
114
114
|
};
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
/**
|
|
117
|
+
/**
|
|
118
|
+
* Two ranges are the same window — the guard that keeps scrolling from repainting every frame.
|
|
119
|
+
*
|
|
120
|
+
* The SPACERS count, not only the slice. Both are pure functions of the same four inputs, so while
|
|
121
|
+
* the row height holds still a range with the same slice has the same spacers and the guard is
|
|
122
|
+
* exactly as quiet as it was. It is when the row height MOVES that the two come apart: the same
|
|
123
|
+
* eleven rows at a new height reserve a different number of pixels either side, and a guard that
|
|
124
|
+
* looked at the slice alone called that "nothing changed" and left the tree's declared height
|
|
125
|
+
* disagreeing with its own rows.
|
|
126
|
+
*/
|
|
118
127
|
export function sameWindow(a: WindowRange, b: WindowRange): boolean {
|
|
119
|
-
return
|
|
128
|
+
return (
|
|
129
|
+
a.start === b.start &&
|
|
130
|
+
a.end === b.end &&
|
|
131
|
+
a.totalRows === b.totalRows &&
|
|
132
|
+
a.padTop === b.padTop &&
|
|
133
|
+
a.padBottom === b.padBottom
|
|
134
|
+
);
|
|
120
135
|
}
|
|
121
136
|
|
|
122
137
|
// ─── The observer ────────────────────────────────────────────────────────────
|
|
@@ -160,6 +175,22 @@ export interface VirtualWindowOptions {
|
|
|
160
175
|
* rAF hop would paint the spacer before the content one frame in three. `ResizeObserver` covers the
|
|
161
176
|
* pane being resized; where the environment has none (happy-dom), `measure()` is the whole contract
|
|
162
177
|
* and the caller drives it — which is also how the perf test drives it.
|
|
178
|
+
*
|
|
179
|
+
* **The list is observed as well as the scroller, and that is the whole of how a row-height change
|
|
180
|
+
* reaches the window.** The window has two inputs nothing else reports: the scroller's box, which
|
|
181
|
+
* its own observer covers, and the height of one row, which the host measures live off a drawn row
|
|
182
|
+
* — but only when something asks for a measurement. A density switch asks for nothing: the rows
|
|
183
|
+
* change height in place, the scroller's box is exactly what it was, and no scroll arrives, so the
|
|
184
|
+
* spacers stood at the old height until the reader happened to scroll — sighted when compact still
|
|
185
|
+
* drew rows at 20px, as a tree declaring 1320px over a 62-row model whose rows now totalled 1240.
|
|
186
|
+
* Compact is 24px today and the switch that moves a row is comfortable, 24px to 28px (ui.md §4.3);
|
|
187
|
+
* the drift is the same in either direction. The list's height, though, is `padTop + drawn ×
|
|
188
|
+
* rowHeight + padBottom` with the two spacers fixed in pixels, so ANY change to the row height
|
|
189
|
+
* changes the list's box by `drawn × Δ`, and observing the list is what turns that into the ask. It
|
|
190
|
+
* is deliberately not an observer on `data-density`: Studio writes no such attribute (the kit
|
|
191
|
+
* declares the rule and a consumer sets it), and the same drift follows a late web font, a zoom, or
|
|
192
|
+
* a stylesheet that overrides `--jx-control-h` — none of which touch an attribute, all of which
|
|
193
|
+
* move the list's box.
|
|
163
194
|
*/
|
|
164
195
|
export function createVirtualWindow(options: VirtualWindowOptions): VirtualWindow {
|
|
165
196
|
const { scroller, list, count, rowHeight, columns, onChange, overscanRows } = options;
|
|
@@ -187,10 +218,38 @@ export function createVirtualWindow(options: VirtualWindowOptions): VirtualWindo
|
|
|
187
218
|
|
|
188
219
|
scroller.addEventListener("scroll", measure, { passive: true });
|
|
189
220
|
|
|
221
|
+
/*
|
|
222
|
+
* A resize is measured ONE FRAME LATER, and the reason is the list observer above.
|
|
223
|
+
*
|
|
224
|
+
* Measuring inside the observer's own callback is how a scroll is answered, and for a scroll it
|
|
225
|
+
* is right. For a resize it is a loop: the measure repaints the spacers, the spacers are part of
|
|
226
|
+
* the list's box, the box the observer is watching changes during delivery, and the browser —
|
|
227
|
+
* which will not deliver a second observation in the same frame — reports "ResizeObserver loop
|
|
228
|
+
* completed with undelivered notifications" as a window `error` instead. One per density toggle,
|
|
229
|
+
* measured; zero before the list was observed. A frame hop is the documented remedy: the write
|
|
230
|
+
* lands in the next frame, the observer sees it as a fresh observation, and the second measure
|
|
231
|
+
* finds the window unchanged and writes nothing. Two observations in one frame collapse into
|
|
232
|
+
* one measure, which is also what a pane resize wants. Measured again with the hop in place:
|
|
233
|
+
* zero errors across seven density toggles over a 386-row windowed model, first visits included.
|
|
234
|
+
*/
|
|
235
|
+
let pending = 0;
|
|
236
|
+
const measureNextFrame = (): void => {
|
|
237
|
+
if (pending !== 0) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
pending = requestAnimationFrame(() => {
|
|
241
|
+
pending = 0;
|
|
242
|
+
measure();
|
|
243
|
+
});
|
|
244
|
+
};
|
|
245
|
+
|
|
190
246
|
let resizeObserver: ResizeObserver | null = null;
|
|
191
247
|
if (typeof ResizeObserver === "function") {
|
|
192
|
-
resizeObserver = new ResizeObserver(
|
|
248
|
+
resizeObserver = new ResizeObserver(measureNextFrame);
|
|
193
249
|
resizeObserver.observe(scroller);
|
|
250
|
+
if (list) {
|
|
251
|
+
resizeObserver.observe(list);
|
|
252
|
+
}
|
|
194
253
|
}
|
|
195
254
|
|
|
196
255
|
measure();
|
|
@@ -201,6 +260,10 @@ export function createVirtualWindow(options: VirtualWindowOptions): VirtualWindo
|
|
|
201
260
|
scroller.removeEventListener("scroll", measure);
|
|
202
261
|
resizeObserver?.disconnect();
|
|
203
262
|
resizeObserver = null;
|
|
263
|
+
if (pending !== 0) {
|
|
264
|
+
cancelAnimationFrame(pending);
|
|
265
|
+
pending = 0;
|
|
266
|
+
}
|
|
204
267
|
},
|
|
205
268
|
measure,
|
|
206
269
|
range: () => current,
|
|
@@ -337,12 +400,24 @@ export function revealListRow(list: HTMLElement | null, index: number, rowHeight
|
|
|
337
400
|
* The height one row actually has, measured, with the stylesheet's declared height as the answer
|
|
338
401
|
* until a row exists to measure.
|
|
339
402
|
*
|
|
340
|
-
* Both are needed. The DECLARED height
|
|
341
|
-
*
|
|
342
|
-
*
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
*
|
|
403
|
+
* Both are needed. The DECLARED height is what lets the FIRST render window anything at all, before
|
|
404
|
+
* any row has been laid out. It used to be `styles/panels.css`'s `.layer-row` and `.file-tree-item`
|
|
405
|
+
* rules; both trees are `jx-tree-item` now and the declaration travelled with them — `blockSize:
|
|
406
|
+
* var(--jx-control-h)`, which is 24px and matches the constants the two hosts pass. At
|
|
407
|
+
* `[data-density=comfortable]` that token is 28px while the constants stay 24, and the constant is
|
|
408
|
+
* only the answer until a row exists, so a session that STARTS comfortable is right from its second
|
|
409
|
+
* paint. (Compact used to be the other direction, 20px; it is 24px now, because WCAG 2.2 SC 2.5.8
|
|
410
|
+
* asks 24 CSS px of a target and the kit holds every density to it — ui.md §4.3.) The MEASUREMENT
|
|
411
|
+
* is what stops that constant becoming a lie the day someone changes the row's padding, a user
|
|
412
|
+
* zooms, or a locale's font raises the line box: a window computed from a stale height does not
|
|
413
|
+
* fail loudly, it drifts, and the list quietly ends a few rows short of its own scrollbar.
|
|
414
|
+
*
|
|
415
|
+
* A measurement is only as fresh as the last time something ASKED for one, and this used to be
|
|
416
|
+
* where the density switch got through: the rows shrank in place, nothing scrolled, nothing resized
|
|
417
|
+
* the scroller, and the spacers stood at the old height until the next scroll — measured in a
|
|
418
|
+
* browser as a `padbottom` of 408 (17 × 24) over rows that had shrunk to 20px, when compact still
|
|
419
|
+
* drew them at that height. The ask is now the list's own resize ({@link createVirtualWindow}
|
|
420
|
+
* observes it), which is the one event every cause of a row-height change has in common.
|
|
346
421
|
*/
|
|
347
422
|
export function measuredRowHeight(
|
|
348
423
|
list: HTMLElement | null,
|
|
@@ -371,6 +446,10 @@ export interface ListWindowWatch {
|
|
|
371
446
|
* scroller, nothing to do". A new element — the panel remounted, or moved dock — moves the
|
|
372
447
|
* listener, and a list that no longer scrolls drops it.
|
|
373
448
|
*
|
|
449
|
+
* The list goes to the window as well as the scroller, and not only for the scroll offset: it is
|
|
450
|
+
* the element whose box moves when the ROWS change height, so it is what the window observes to
|
|
451
|
+
* learn that `rowHeight()` now answers differently ({@link createVirtualWindow}).
|
|
452
|
+
*
|
|
374
453
|
* Returns the handle to keep, or null when nothing scrolls this list.
|
|
375
454
|
*/
|
|
376
455
|
export function watchListWindow(
|
|
@@ -84,3 +84,75 @@ export function activeBreakpointsForWidth(
|
|
|
84
84
|
}
|
|
85
85
|
return active;
|
|
86
86
|
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The ONE breakpoint a canvas of this width is rendering under, or `null` for Base.
|
|
90
|
+
*
|
|
91
|
+
* {@link activeBreakpointsForWidth} answers a set, because several queries genuinely match at once:
|
|
92
|
+
* a desktop-first project at 700px satisfies both `(max-width: 1024px)` and `(max-width: 768px)`.
|
|
93
|
+
* The rendering context is one value, though — `session.ui.activeMedia` is a single key — so this
|
|
94
|
+
* picks the most specific member of that set: the one whose declared width is CLOSEST to the canvas
|
|
95
|
+
* width, ties going to the narrower.
|
|
96
|
+
*
|
|
97
|
+
* Closest, rather than last-in-array, on purpose. Every matching `max` entry is at least as wide as
|
|
98
|
+
* the canvas and every matching `min` entry at most, so "closest" reads as "narrowest" for a
|
|
99
|
+
* desktop-first project and "widest" for a mobile-first one — the correct band in both. Array
|
|
100
|
+
* position would agree for those two, but {@link parseMediaEntries}'s comparator decides the whole
|
|
101
|
+
* sort from `a.type` alone, so it orders a project mixing `min-` and `max-width` arbitrarily.
|
|
102
|
+
* Distance does not depend on the sort at all.
|
|
103
|
+
*
|
|
104
|
+
* @param {{ name: string; width: number; type: string }[]} sizeBreakpoints
|
|
105
|
+
* @param {number} canvasWidth
|
|
106
|
+
* @returns {string | null}
|
|
107
|
+
*/
|
|
108
|
+
export function mediaForWidth(
|
|
109
|
+
sizeBreakpoints: { name: string; width: number; type: string }[],
|
|
110
|
+
canvasWidth: number,
|
|
111
|
+
): string | null {
|
|
112
|
+
const active = activeBreakpointsForWidth(sizeBreakpoints, canvasWidth);
|
|
113
|
+
let best: { name: string; width: number } | null = null;
|
|
114
|
+
for (const bp of sizeBreakpoints) {
|
|
115
|
+
if (!active.has(bp.name)) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const distance = Math.abs(bp.width - canvasWidth);
|
|
119
|
+
if (best === null) {
|
|
120
|
+
best = bp;
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
const bestDistance = Math.abs(best.width - canvasWidth);
|
|
124
|
+
// Ties to the NARROWER entry: at a width equidistant from a `max` and a `min` neighbour, the
|
|
125
|
+
// Tighter constraint is the one an author is checking.
|
|
126
|
+
if (distance < bestDistance || (distance === bestDistance && bp.width < best.width)) {
|
|
127
|
+
best = bp;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return best?.name ?? null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Pull a dragged width onto a declared one when it comes close enough — magnetic snapping.
|
|
135
|
+
*
|
|
136
|
+
* The Edit canvas is dragged continuously, which is the point of it; landing EXACTLY on a declared
|
|
137
|
+
* breakpoint is nevertheless the single most common intent, and a pixel-perfect drag cannot deliver
|
|
138
|
+
* it. So a target within `tolerance` wins, and the caller offers Alt as the bypass — free motion
|
|
139
|
+
* stays reachable rather than being traded away for the convenience.
|
|
140
|
+
*
|
|
141
|
+
* @param {number} width
|
|
142
|
+
* @param {number[]} targets — declared breakpoint widths, plus the base width
|
|
143
|
+
* @param {number} tolerance — in px, either side
|
|
144
|
+
* @returns {number}
|
|
145
|
+
*/
|
|
146
|
+
export function snapEditWidth(width: number, targets: number[], tolerance = 8): number {
|
|
147
|
+
let best: number | null = null;
|
|
148
|
+
for (const target of targets) {
|
|
149
|
+
const distance = Math.abs(target - width);
|
|
150
|
+
if (distance > tolerance) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
if (best === null || distance < Math.abs(best - width)) {
|
|
154
|
+
best = target;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return best ?? width;
|
|
158
|
+
}
|
|
@@ -294,11 +294,16 @@ export function prepareForEditMode(node: JxMutableNode): JxMutableNode {
|
|
|
294
294
|
}
|
|
295
295
|
out.attributes = processed;
|
|
296
296
|
} else if (k === "style") {
|
|
297
|
-
|
|
297
|
+
/* Drop template-valued style declarations. State is not live in edit mode, so the value
|
|
298
|
+
cannot be resolved; omitting the property lets the cascade answer, which is exactly what
|
|
299
|
+
the `""` this used to write meant while declarations went inline. As a RULE, `color: ` is
|
|
300
|
+
a malformed declaration instead of a no-op. Mirrored by iframe-patch's editModeStyle. */
|
|
298
301
|
if (v && typeof v === "object") {
|
|
299
302
|
const s: Record<string, unknown> = {};
|
|
300
303
|
for (const [sk, sv] of Object.entries(v)) {
|
|
301
|
-
|
|
304
|
+
if (typeof sv !== "string" || !sv.includes("${")) {
|
|
305
|
+
s[sk] = sv;
|
|
306
|
+
}
|
|
302
307
|
}
|
|
303
308
|
out.style = s;
|
|
304
309
|
} else {
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The nested selectors the Style tab offers for a given element.
|
|
3
|
+
*
|
|
4
|
+
* `COMMON_SELECTORS` is the global base and stays exactly that: eleven states every element can be
|
|
5
|
+
* in. What it could not express is a state that only exists for SOME elements — `:popover-open` on
|
|
6
|
+
* a `<p>` is a rule that can never match, and offering it there teaches the menu to be ignored.
|
|
7
|
+
*
|
|
8
|
+
* A separate module from `store.ts` because `store.ts` imports the world and this has to be
|
|
9
|
+
* testable without a DOM. The additions are deliberately few: each one is a state the platform
|
|
10
|
+
* gives that element and nothing else, so the menu stays a map of where to look rather than a
|
|
11
|
+
* catalogue of CSS.
|
|
12
|
+
*
|
|
13
|
+
* @docs studio/design/states-and-selectors
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { COMMON_SELECTORS } from "../store";
|
|
17
|
+
import { displayTagName } from "@jxsuite/schema/guards";
|
|
18
|
+
import { isPopover } from "@jxsuite/schema/overlays";
|
|
19
|
+
import type { JxMutableNode } from "@jxsuite/schema/types";
|
|
20
|
+
|
|
21
|
+
/** Form controls that carry the validity and checked states. */
|
|
22
|
+
const FIELD_TAGS = new Set(["input", "select", "textarea"]);
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The states an element can be in beyond the common set.
|
|
26
|
+
*
|
|
27
|
+
* `::backdrop` is offered on a popover even though the canvas does not RENDER it (there is no
|
|
28
|
+
* backdrop pseudo-element outside the top layer, and Preview is where it appears). Offering it is
|
|
29
|
+
* still right: it is a real part of the shipped page, and the alternative — no way to author it
|
|
30
|
+
* except by typing it into the custom-selector dialog — is worse than a state you check in
|
|
31
|
+
* Preview.
|
|
32
|
+
*/
|
|
33
|
+
function extraSelectorsFor(node: JxMutableNode): string[] {
|
|
34
|
+
const tag = displayTagName(node.tagName).toLowerCase();
|
|
35
|
+
const out: string[] = [];
|
|
36
|
+
if (isPopover(node)) {
|
|
37
|
+
out.push(":popover-open", "::backdrop", ":popover-open::backdrop");
|
|
38
|
+
}
|
|
39
|
+
if (tag === "dialog") {
|
|
40
|
+
out.push("[open]", ":modal", "::backdrop");
|
|
41
|
+
}
|
|
42
|
+
if (tag === "details") {
|
|
43
|
+
out.push("[open]");
|
|
44
|
+
}
|
|
45
|
+
if (FIELD_TAGS.has(tag)) {
|
|
46
|
+
out.push(":checked", ":invalid", ":required", ":user-invalid");
|
|
47
|
+
}
|
|
48
|
+
if (tag === "a") {
|
|
49
|
+
out.push(":visited", ":target");
|
|
50
|
+
}
|
|
51
|
+
return out;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Every selector the menu should offer for `node`, in a stable order and without duplicates.
|
|
56
|
+
*
|
|
57
|
+
* The common set first, so the menu does not reorder itself as the selection moves; the
|
|
58
|
+
* element-specific ones after. Callers union this with what the element already DECLARES and with
|
|
59
|
+
* the active selector, so nothing an author has written can drop out of the menu.
|
|
60
|
+
*
|
|
61
|
+
* @param node The selected node, or undefined when there is no selection.
|
|
62
|
+
* @returns The offerable selectors.
|
|
63
|
+
*/
|
|
64
|
+
export function selectorsForNode(node: JxMutableNode | null | undefined): string[] {
|
|
65
|
+
if (!node || typeof node !== "object") {
|
|
66
|
+
return [...COMMON_SELECTORS];
|
|
67
|
+
}
|
|
68
|
+
return [...new Set([...COMMON_SELECTORS, ...extraSelectorsFor(node)])];
|
|
69
|
+
}
|
package/src/utils/link-target.ts
CHANGED
|
@@ -33,8 +33,8 @@ const ABSOLUTE_SCHEME = /^([a-z][a-z\d+.-]*:)?\/\//i;
|
|
|
33
33
|
* Classify a raw `href` string into a {@link LinkTarget}.
|
|
34
34
|
*
|
|
35
35
|
* Rules (checked in order): 1. `mailto:…` → `{ kind: "mailto", value: address }` 2. `tel:…` → `{
|
|
36
|
-
* kind: "tel", value: number }` 3. `#…` → `{ kind: "anchor", value: rest }` (leading `#` stripped)
|
|
37
|
-
*
|
|
36
|
+
* kind: "tel", value: number }` 3. `#…` → `{ kind: "anchor", value: rest }` (leading `#` stripped) 4.
|
|
37
|
+
* absolute (`http(s)://…`) or protocol-relative (`//…`) → `{ kind: "external", value: href }` 5.
|
|
38
38
|
* `/…` → `{ kind: "internal", value: path }` 6. anything else → `{ kind: "external", value: href
|
|
39
39
|
* }`
|
|
40
40
|
*
|
|
@@ -8,16 +8,6 @@ import { collectionForFile } from "../content/collection-match";
|
|
|
8
8
|
import { defaultContentFormat } from "../format/format-host";
|
|
9
9
|
import type { ProjectConfig } from "@jxsuite/schema/types";
|
|
10
10
|
|
|
11
|
-
/**
|
|
12
|
-
* CamelCase → kebab-case for inline style attributes
|
|
13
|
-
*
|
|
14
|
-
* @param {string} str
|
|
15
|
-
* @returns {string}
|
|
16
|
-
*/
|
|
17
|
-
export function camelToKebab(str: string) {
|
|
18
|
-
return str.replaceAll(/[A-Z]/g, (c: string) => `-${c.toLowerCase()}`);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
11
|
/**
|
|
22
12
|
* Convert camelCase property name to "Title Case" label (e.g. "backgroundColor" → "Background
|
|
23
13
|
* Color")
|
package/src/view.ts
CHANGED
|
@@ -27,6 +27,21 @@ import type { Tab } from "./tabs/tab";
|
|
|
27
27
|
* timer survived three disposal sites and stayed able to replace a page with an empty parse.
|
|
28
28
|
* `services/monaco-buffer.ts` owns the rule; this is the storage it needs.
|
|
29
29
|
*/
|
|
30
|
+
/**
|
|
31
|
+
* A comparison's Monaco diff editor.
|
|
32
|
+
*
|
|
33
|
+
* Deliberately NOT a {@link MonacoSurface}: an `IStandaloneDiffEditor` is a different type, and
|
|
34
|
+
* widening the code-editor slot to a union would put a non-code editor into `buffersForTab`'s
|
|
35
|
+
* array, where `bufferIsLive`, `getValue` and `_writes` are all code-editor APIs. It carries none
|
|
36
|
+
* of that state because it has nothing to commit: both its models are read-only, and one of them is
|
|
37
|
+
* a git object that does not exist on disk.
|
|
38
|
+
*
|
|
39
|
+
* `_diffKey` is the comparison it was mounted for, so a retarget to a different file disposes it
|
|
40
|
+
* before claiming the next pair of URIs rather than throwing on a URI the previous mount still
|
|
41
|
+
* holds.
|
|
42
|
+
*/
|
|
43
|
+
export type DiffSurface = editor.IStandaloneDiffEditor & { _diffKey?: string };
|
|
44
|
+
|
|
30
45
|
export type MonacoSurface = editor.IStandaloneCodeEditor & {
|
|
31
46
|
_ignoreNextChange?: boolean;
|
|
32
47
|
/** The debounced work armed over this buffer, with this editor's exact lifetime. */
|