@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.
Files changed (607) hide show
  1. package/README.md +1 -1
  2. package/data/elements-meta.json +5 -15
  3. package/data/html-meta.json +51 -6
  4. package/dist/chunks/{2020-n6tfwnda.js → 2020-g79n01v9.js} +14 -14
  5. package/dist/chunks/action-group-sp6tna8v.js +118 -0
  6. package/dist/chunks/adapter-nj7tnjfn.js +13 -0
  7. package/dist/chunks/cf-account-picker-fyf63pmy.js +495 -0
  8. package/dist/chunks/cf-settings-71bv5zn9.js +20 -0
  9. package/dist/chunks/color-area-v17df7b8.js +154 -0
  10. package/dist/chunks/color-field-anwybnkn.js +208 -0
  11. package/dist/chunks/color-slider-44ez96fc.js +79 -0
  12. package/dist/chunks/color-xgg3kfw7.js +35 -0
  13. package/dist/chunks/combobox-5e7jev23.js +236 -0
  14. package/dist/chunks/components-2w1f35qs.js +18 -0
  15. package/dist/chunks/content-source-3wqeas45.js +46 -0
  16. package/dist/chunks/convert-to-repeater-d0cgnb6d.js +639 -0
  17. package/dist/chunks/dialog-s890b918.js +85 -0
  18. package/dist/chunks/editor-3qhbg51x.js +35 -0
  19. package/dist/chunks/entry-commands-d6g50j7s.js +42 -0
  20. package/dist/chunks/extension-sections-fy7q4fe9.js +651 -0
  21. package/dist/chunks/file-ops-3btj6st0.js +47 -0
  22. package/dist/chunks/files-ef8fgs3w.js +72 -0
  23. package/dist/chunks/format-host-3c33nwr8.js +40 -0
  24. package/dist/chunks/fs-events-13tj6sex.js +18 -0
  25. package/dist/chunks/git-panel-4wp2rn9b.js +49 -0
  26. package/dist/chunks/icons-yy10wk9r.js +402 -0
  27. package/dist/chunks/iframe-entry-15g3n6xv.js +114 -0
  28. package/dist/chunks/iframe-entry-b27vq81n.js +203 -0
  29. package/dist/chunks/iframe-entry-nbyxee1y.js +154 -0
  30. package/dist/chunks/iframe-host-jgesd924.js +115 -0
  31. package/dist/chunks/{index-wcnt3r9g.js → index-mdmyx6s2.js} +11 -11
  32. package/dist/chunks/index-n4j7qxyr.js +109 -0
  33. package/dist/chunks/{javascript-q8kpmfah.js → javascript-xvrfrpkb.js} +8 -9
  34. package/dist/chunks/{jsonMode-dkr040ga.js → jsonMode-tyx2kj6p.js} +526 -527
  35. package/dist/chunks/jx-validate-j0wxk72w.js +15 -0
  36. package/dist/chunks/layers-1nq5evsh.js +29 -0
  37. package/dist/chunks/layers-panel-ar2gh90g.js +40 -0
  38. package/dist/chunks/listbox-6v2ac08j.js +44 -0
  39. package/dist/chunks/lit-html-m244w9nh.js +17 -0
  40. package/dist/chunks/media-picker-2qbetq73.js +33 -0
  41. package/dist/chunks/menu-q99sy9rf.js +285 -0
  42. package/dist/chunks/menu-rf7n72mf.js +14 -0
  43. package/dist/chunks/{monaco-binding-rj6xpx9y.js → monaco-binding-sw6en4dw.js} +12 -15
  44. package/dist/chunks/monaco-buffer-bhy3hb6m.js +24 -0
  45. package/dist/chunks/{monaco-setup-vx9bhp1d.js → monaco-setup-8r62fj6y.js} +27 -37
  46. package/dist/chunks/notify-628t0anh.js +21 -0
  47. package/dist/chunks/number-field-5cndyft8.js +72 -0
  48. package/dist/chunks/parse-0zx14y15.js +10 -0
  49. package/dist/chunks/platform-ts9cg1a4.js +15 -0
  50. package/dist/chunks/popover-47z3ytva.js +25 -0
  51. package/dist/chunks/publish-panel-98f7sr3g.js +27 -0
  52. package/dist/chunks/quick-search-srzz83k2.js +45 -0
  53. package/dist/chunks/references-n553f0e1.js +26 -0
  54. package/dist/chunks/right-panel-rrgx2dn3.js +45 -0
  55. package/dist/chunks/section-registry-5pq32t0q.js +25 -0
  56. package/dist/chunks/select-2r16ez41.js +49 -0
  57. package/dist/chunks/split-g7nm1rgb.js +191 -0
  58. package/dist/chunks/studio-0hqbpbd0.js +62 -0
  59. package/dist/chunks/studio-18avnhjp.js +2430 -0
  60. package/dist/chunks/{studio-kryvsw6j.js → studio-1k325pwf.js} +48 -48
  61. package/dist/chunks/{studio-msd847zn.js → studio-25hkdrkw.js} +357 -86
  62. package/dist/chunks/studio-26d7myd1.js +258 -0
  63. package/dist/chunks/{studio-4r1pv6zf.js → studio-38emantv.js} +22 -5
  64. package/dist/chunks/studio-3gxv60tn.js +422 -0
  65. package/dist/chunks/{studio-fbf92ckf.js → studio-3hxkd92t.js} +275 -163
  66. package/dist/chunks/studio-4m0haseg.js +185 -0
  67. package/dist/chunks/{studio-ynxwkrzd.js → studio-4wbb9ct0.js} +1953 -1785
  68. package/dist/chunks/{studio-1wagb550.js → studio-5523bpzt.js} +11 -11
  69. package/dist/chunks/{studio-x4qkdat5.js → studio-57mf66w2.js} +1749 -2481
  70. package/dist/chunks/studio-5jy81t3s.js +17463 -0
  71. package/dist/chunks/studio-5rt7sqa0.js +1168 -0
  72. package/dist/chunks/studio-5te5tqng.js +81 -0
  73. package/dist/chunks/{studio-p4ngc046.js → studio-6ewqv390.js} +9 -9
  74. package/dist/chunks/{studio-9ab8gqsm.js → studio-6nzaktvy.js} +7 -7
  75. package/dist/chunks/studio-6xa21ej9.js +28 -0
  76. package/dist/chunks/{studio-5ehhackm.js → studio-727xh0e3.js} +19 -19
  77. package/dist/chunks/{studio-ahn3pdgx.js → studio-79y5sz51.js} +52 -38
  78. package/dist/chunks/{studio-gcye7qka.js → studio-7e11jpa9.js} +21 -21
  79. package/dist/chunks/{studio-q7v10cg2.js → studio-7r42c6ca.js} +17 -7
  80. package/dist/chunks/studio-7xptrg0j.js +954 -0
  81. package/dist/chunks/{studio-cft9r4r7.js → studio-81390n6f.js} +22 -22
  82. package/dist/chunks/{studio-q43a5y9h.js → studio-8jn5yhyn.js} +16 -16
  83. package/dist/chunks/studio-8qtrpzr3.js +839 -0
  84. package/dist/chunks/{studio-dg7zyt5x.js → studio-98b3z07n.js} +1 -1
  85. package/dist/chunks/studio-9xxz1q69.js +1356 -0
  86. package/dist/chunks/studio-akbww0j5.js +13615 -0
  87. package/dist/chunks/{studio-x813zp48.js → studio-arfpe389.js} +30 -30
  88. package/dist/chunks/{studio-trxrabqf.js → studio-az3zd49t.js} +475 -283
  89. package/dist/chunks/studio-cpvb2ed1.js +1171 -0
  90. package/dist/chunks/{studio-f3wqjtk5.js → studio-d0300636.js} +5076 -18
  91. package/dist/chunks/{studio-bgxt93ga.js → studio-d055c37e.js} +13 -13
  92. package/dist/chunks/studio-d1ja2x9r.js +362 -0
  93. package/dist/chunks/{studio-b9b6t1dg.js → studio-e1f24eff.js} +5664 -5666
  94. package/dist/chunks/{studio-3bqpr0zh.js → studio-em9nw8eh.js} +299 -110
  95. package/dist/chunks/studio-erdatzvp.js +1190 -0
  96. package/dist/chunks/{studio-g1wdche0.js → studio-esrxgwh6.js} +80 -80
  97. package/dist/chunks/studio-fabxk6r9.js +2811 -0
  98. package/dist/chunks/{studio-3n4ndrzh.js → studio-h4nvnjvz.js} +303 -303
  99. package/dist/chunks/{studio-dm19q43r.js → studio-hhvs4sdg.js} +10 -10
  100. package/dist/chunks/{studio-q9jd1a60.js → studio-kcgff4r0.js} +15 -18
  101. package/dist/chunks/{studio-685s0ytq.js → studio-nqgawfks.js} +572 -572
  102. package/dist/chunks/{studio-xrapxwwc.js → studio-p1dw8wfw.js} +55 -29
  103. package/dist/chunks/studio-pm6hgy7r.js +4763 -0
  104. package/dist/chunks/studio-q0a3yk4n.js +33 -0
  105. package/dist/chunks/{studio-wcy8trfx.js → studio-q3x06vmj.js} +23 -22
  106. package/dist/chunks/studio-qahxvnan.js +111 -0
  107. package/dist/chunks/{studio-53n8bp04.js → studio-r6xmmtfh.js} +1 -1
  108. package/dist/chunks/{studio-2b946z26.js → studio-rkstz940.js} +3658 -6134
  109. package/dist/chunks/{studio-tvgyw9xw.js → studio-rnyf3f8e.js} +83 -250
  110. package/dist/chunks/studio-rpyah2ew.js +2805 -0
  111. package/dist/chunks/studio-rs76k67r.js +12 -0
  112. package/dist/chunks/{studio-jkftxyvz.js → studio-s6z853aq.js} +5858 -2152
  113. package/dist/chunks/{studio-6yw4y3my.js → studio-sgdc5pfc.js} +8 -8
  114. package/dist/chunks/studio-tb3ev01j.js +763 -0
  115. package/dist/chunks/{studio-t5wqwzdh.js → studio-tjjk7jvk.js} +1 -1
  116. package/dist/chunks/studio-vhv5tgxm.js +51 -0
  117. package/dist/chunks/{studio-qjy2z9bv.js → studio-vz68yn9e.js} +32 -137
  118. package/dist/chunks/studio-wqpngpsk.js +174 -0
  119. package/dist/chunks/{studio-b55y6ewx.js → studio-x3rty6tr.js} +58 -58
  120. package/dist/chunks/studio-xsykpvsh.js +8448 -0
  121. package/dist/chunks/{studio-92ab2jqe.js → studio-y9zedyjn.js} +14 -14
  122. package/dist/chunks/studio-yxa81f45.js +12 -0
  123. package/dist/chunks/swatch-group-t0n6h2rn.js +139 -0
  124. package/dist/chunks/tabs-wbp1cdws.js +156 -0
  125. package/dist/chunks/textfield-abk6qyee.js +73 -0
  126. package/dist/chunks/toast-780pvfbv.js +27 -0
  127. package/dist/chunks/toast-host-3sqv46sn.js +116 -0
  128. package/dist/chunks/toolbar-xbh5bhtr.js +194 -0
  129. package/dist/chunks/tooltip-eptb614w.js +369 -0
  130. package/dist/chunks/tree-a73p0pqm.js +367 -0
  131. package/dist/chunks/{tsMode-76kr53q0.js → tsMode-jy4m86rv.js} +83 -85
  132. package/dist/chunks/workspace-wrew8zk4.js +69 -0
  133. package/dist/chunks/{ws-client-6shc5rze.js → ws-client-ny4zc51r.js} +20 -22
  134. package/dist/iframe-entry.js +1780 -667
  135. package/dist/studio.js +52819 -36480
  136. package/dist/workers/editor.worker.js +1040 -1085
  137. package/dist/workers/json.worker.js +1946 -1991
  138. package/dist/workers/ts.worker.js +4960 -5005
  139. package/index.html +1 -0
  140. package/package.json +18 -52
  141. package/src/about/about-modal.ts +72 -123
  142. package/src/browse/library-commands.ts +20 -49
  143. package/src/browse/library-layouts.ts +87 -218
  144. package/src/browse/library-pane.ts +406 -438
  145. package/src/canvas/canvas-helpers.ts +0 -49
  146. package/src/canvas/canvas-live-render.ts +25 -2
  147. package/src/canvas/canvas-render.ts +666 -231
  148. package/src/canvas/canvas-surface.ts +0 -1
  149. package/src/canvas/canvas-utils.ts +310 -117
  150. package/src/canvas/dialog-path.ts +76 -0
  151. package/src/canvas/dialog-state.ts +67 -0
  152. package/src/canvas/diff-marks.ts +252 -0
  153. package/src/canvas/diff-toolbar.ts +349 -0
  154. package/src/canvas/diff-view.ts +123 -0
  155. package/src/canvas/edit-width-drag.ts +187 -0
  156. package/src/canvas/edit-width.ts +150 -0
  157. package/src/canvas/iframe-entry.ts +125 -8
  158. package/src/canvas/iframe-host.ts +271 -15
  159. package/src/canvas/iframe-interaction.ts +133 -13
  160. package/src/canvas/iframe-patch.ts +7 -1
  161. package/src/canvas/iframe-position.ts +5 -6
  162. package/src/canvas/iframe-protocol.ts +106 -5
  163. package/src/canvas/iframe-render.ts +373 -5
  164. package/src/canvas/iframe-slash.ts +2 -2
  165. package/src/canvas/iframe-subtree.ts +5 -8
  166. package/src/canvas/path-mapping.ts +25 -3
  167. package/src/canvas/popover-path.ts +106 -0
  168. package/src/canvas/popover-state.ts +155 -0
  169. package/src/canvas/surface-registry.ts +21 -10
  170. package/src/collab/presence-chips.ts +51 -73
  171. package/src/commands/app-commands.ts +10 -0
  172. package/src/commands/budget.ts +12 -0
  173. package/src/commands/command-args.ts +369 -6
  174. package/src/commands/defaults.ts +44 -14
  175. package/src/commands/live-context.ts +11 -5
  176. package/src/commands/reference.ts +12 -2
  177. package/src/commands/registry.ts +165 -8
  178. package/src/content/entry-commands.ts +16 -23
  179. package/src/content/entry-editor.ts +144 -101
  180. package/src/editor/canvas-slash-bridge.ts +2 -2
  181. package/src/editor/context-menu.ts +49 -200
  182. package/src/editor/convert-to-component.ts +42 -82
  183. package/src/editor/convert-to-repeater.ts +132 -173
  184. package/src/editor/inline-edit.ts +11 -0
  185. package/src/editor/shortcuts.ts +65 -26
  186. package/src/editor/slash-menu.ts +150 -157
  187. package/src/files/file-ops.ts +117 -11
  188. package/src/files/files.ts +943 -660
  189. package/src/files/json-layout.ts +474 -0
  190. package/src/files/serialize-document.ts +8 -1
  191. package/src/format/convert-file.ts +16 -10
  192. package/src/format/format-host.ts +50 -1
  193. package/src/github/github-auth.ts +71 -29
  194. package/src/github/github-publish.ts +57 -65
  195. package/src/grid/cell-editors.ts +46 -4
  196. package/src/grid/cell-popovers.ts +65 -62
  197. package/src/grid/grid-open.ts +86 -64
  198. package/src/grid/grid-panel.ts +390 -469
  199. package/src/grid/redirects-grid.ts +40 -44
  200. package/src/hosting/layout.ts +2 -0
  201. package/src/i18n/i18n-commands.ts +127 -62
  202. package/src/media/media-pane.ts +83 -133
  203. package/src/new-project/add-repo-modal.ts +125 -176
  204. package/src/new-project/import-tab.ts +181 -252
  205. package/src/new-project/location-fields.ts +93 -160
  206. package/src/new-project/new-project-modal.ts +376 -367
  207. package/src/packages/jxsuite-update.ts +76 -18
  208. package/src/panels/activity-panel.ts +137 -104
  209. package/src/panels/ai-chat/chat-markdown.ts +15 -13
  210. package/src/panels/ai-chat/chat-view.ts +307 -472
  211. package/src/panels/ai-chat/composer.ts +175 -163
  212. package/src/panels/ai-chat/sessions-view.ts +31 -62
  213. package/src/panels/ai-panel.ts +210 -185
  214. package/src/panels/block-action-bar.ts +437 -643
  215. package/src/panels/bottom-dock.ts +112 -47
  216. package/src/panels/chat-panel.ts +19 -14
  217. package/src/panels/data-explorer.ts +141 -102
  218. package/src/panels/data-grid.ts +183 -150
  219. package/src/panels/dnd.ts +75 -20
  220. package/src/panels/editors.ts +26 -19
  221. package/src/panels/elements-panel.ts +243 -186
  222. package/src/panels/empty-state.ts +26 -42
  223. package/src/panels/events-panel.ts +950 -729
  224. package/src/panels/formula-workspace.ts +434 -207
  225. package/src/panels/frontmatter-fields.ts +185 -153
  226. package/src/panels/frontmatter-panel.ts +411 -187
  227. package/src/panels/git-diff-open.ts +148 -0
  228. package/src/panels/git-panel.ts +679 -605
  229. package/src/panels/head-panel.ts +617 -435
  230. package/src/panels/i18n-panel.ts +153 -133
  231. package/src/panels/imports-panel.ts +388 -414
  232. package/src/panels/jump-bar.ts +174 -147
  233. package/src/panels/layers-panel.ts +785 -671
  234. package/src/panels/left-panel.ts +166 -94
  235. package/src/panels/navigator-panels.ts +1 -1
  236. package/src/panels/pane-context.ts +529 -677
  237. package/src/panels/pane-grid.ts +265 -241
  238. package/src/panels/panel-registry.ts +15 -4
  239. package/src/panels/problems-panel.ts +177 -99
  240. package/src/panels/properties-panel.ts +1525 -966
  241. package/src/panels/provenance.ts +31 -113
  242. package/src/panels/quick-search.ts +217 -172
  243. package/src/panels/right-panel.ts +135 -169
  244. package/src/panels/seo-modal.ts +346 -167
  245. package/src/panels/settings-menu.ts +109 -646
  246. package/src/panels/settings-pane.ts +102 -86
  247. package/src/panels/signals-panel.ts +1318 -1172
  248. package/src/panels/statement-editor.ts +556 -428
  249. package/src/panels/style-panel.ts +1367 -630
  250. package/src/panels/style-utils.ts +36 -32
  251. package/src/panels/stylebook-doc.ts +30 -73
  252. package/src/panels/stylebook-layers-panel.ts +202 -109
  253. package/src/panels/stylebook-panel.ts +124 -88
  254. package/src/panels/tab-strip.ts +385 -287
  255. package/src/platforms/cloud.ts +106 -16
  256. package/src/platforms/devserver.ts +13 -0
  257. package/src/publish/deploy-checklist.ts +124 -78
  258. package/src/publish/publish-commands.ts +4 -12
  259. package/src/publish/publish-panel.ts +134 -328
  260. package/src/services/a11y-report.ts +100 -43
  261. package/src/services/ai-command-tools.ts +468 -0
  262. package/src/services/ai-session-store.ts +6 -0
  263. package/src/services/ai-system-prompt.ts +110 -18
  264. package/src/services/ai-tools.ts +28 -143
  265. package/src/services/ai-write-report.ts +174 -0
  266. package/src/services/document-assistant.ts +50 -2
  267. package/src/services/idle.ts +16 -14
  268. package/src/services/live-surfaces.ts +237 -0
  269. package/src/services/model-uri.ts +75 -0
  270. package/src/services/notify.ts +63 -6
  271. package/src/services/popover-report.ts +325 -0
  272. package/src/services/surface-registry.ts +56 -0
  273. package/src/services/tool-executor.ts +6 -0
  274. package/src/settings/contexts-section.ts +301 -299
  275. package/src/settings/contributed-section.ts +361 -222
  276. package/src/settings/css-vars-editor.ts +320 -325
  277. package/src/settings/defs-editor.ts +572 -535
  278. package/src/settings/dependencies-editor.ts +79 -107
  279. package/src/settings/extension-commands.ts +379 -0
  280. package/src/settings/extension-rows.ts +113 -0
  281. package/src/settings/extensions-section.ts +287 -0
  282. package/src/settings/general-settings.ts +130 -181
  283. package/src/settings/head-editor.ts +10 -305
  284. package/src/settings/locales-section.ts +146 -196
  285. package/src/settings/preferences-accounts.ts +1 -1
  286. package/src/settings/preferences-dialog.ts +350 -330
  287. package/src/settings/project-sections.ts +108 -181
  288. package/src/settings/schema-field-ui.ts +11 -399
  289. package/src/settings/section-registry.ts +8 -1
  290. package/src/settings/settings-document.ts +31 -29
  291. package/src/shell/tree.ts +42 -87
  292. package/src/shell.ts +48 -36
  293. package/src/studio.ts +90 -67
  294. package/src/style/token-ref.ts +0 -39
  295. package/src/surfaces/about.json +263 -0
  296. package/src/surfaces/about.ts +163 -0
  297. package/src/surfaces/add-repo.json +486 -0
  298. package/src/surfaces/add-repo.ts +236 -0
  299. package/src/surfaces/ai-chat.json +2185 -0
  300. package/src/surfaces/ai-chat.ts +549 -0
  301. package/src/surfaces/ai-credentials-form.json +332 -0
  302. package/src/surfaces/ai-credentials-form.ts +151 -0
  303. package/src/surfaces/ai-managed-connect.json +108 -0
  304. package/src/surfaces/ai-managed-connect.ts +123 -0
  305. package/src/surfaces/ai-model-picker.json +114 -0
  306. package/src/surfaces/ai-model-picker.ts +139 -0
  307. package/src/surfaces/block-action-bar.json +640 -0
  308. package/src/surfaces/block-action-bar.ts +368 -0
  309. package/src/surfaces/bottom-dock.json +154 -0
  310. package/src/surfaces/bottom-dock.ts +125 -0
  311. package/src/surfaces/canvas-stage.json +444 -0
  312. package/src/surfaces/canvas-stage.ts +253 -0
  313. package/src/surfaces/cf-account-picker.json +300 -0
  314. package/src/surfaces/cf-account-picker.ts +214 -0
  315. package/src/surfaces/commandbar.json +984 -0
  316. package/src/{panels/toolbar.ts → surfaces/commandbar.ts} +414 -389
  317. package/src/surfaces/convert-repeater.json +309 -0
  318. package/src/surfaces/convert-repeater.ts +276 -0
  319. package/src/surfaces/data-actions.json +157 -0
  320. package/src/surfaces/data-actions.ts +115 -0
  321. package/src/surfaces/dialog.json +289 -0
  322. package/src/surfaces/dialog.ts +343 -0
  323. package/src/surfaces/diff-toolbar.json +266 -0
  324. package/src/surfaces/diff-toolbar.ts +139 -0
  325. package/src/surfaces/doc-header.json +739 -0
  326. package/src/surfaces/doc-header.ts +223 -0
  327. package/src/surfaces/empty-state.json +152 -0
  328. package/src/surfaces/empty-state.ts +173 -0
  329. package/src/surfaces/entry-editor.json +281 -0
  330. package/src/surfaces/entry-editor.ts +191 -0
  331. package/src/surfaces/expression-editor.json +977 -0
  332. package/src/surfaces/expression-editor.ts +266 -0
  333. package/src/surfaces/files-panel.json +592 -0
  334. package/src/surfaces/files-panel.ts +301 -0
  335. package/src/surfaces/formula-palette.json +364 -0
  336. package/src/surfaces/formula-palette.ts +340 -0
  337. package/src/surfaces/git-panel.json +1822 -0
  338. package/src/surfaces/git-panel.ts +272 -0
  339. package/src/surfaces/github-auth.json +112 -0
  340. package/src/surfaces/github-auth.ts +139 -0
  341. package/src/surfaces/github-publish.json +206 -0
  342. package/src/surfaces/github-publish.ts +169 -0
  343. package/src/surfaces/grid-cell.json +218 -0
  344. package/src/surfaces/grid-cell.ts +120 -0
  345. package/src/surfaces/grid-open.json +147 -0
  346. package/src/surfaces/grid-open.ts +87 -0
  347. package/src/surfaces/grid-panel.json +706 -0
  348. package/src/surfaces/grid-panel.ts +206 -0
  349. package/src/surfaces/grid-replace.json +179 -0
  350. package/src/surfaces/grid-replace.ts +89 -0
  351. package/src/surfaces/grid-views.json +446 -0
  352. package/src/surfaces/grid-views.ts +172 -0
  353. package/src/surfaces/inspector-dock.json +187 -0
  354. package/src/surfaces/inspector-dock.ts +161 -0
  355. package/src/surfaces/jump-bar.json +243 -0
  356. package/src/surfaces/jump-bar.ts +129 -0
  357. package/src/surfaces/jxsuite-update.json +146 -0
  358. package/src/surfaces/jxsuite-update.ts +149 -0
  359. package/src/surfaces/library-pane.json +1509 -0
  360. package/src/surfaces/library-pane.ts +363 -0
  361. package/src/surfaces/logic-panel.json +1949 -0
  362. package/src/surfaces/logic-panel.ts +369 -0
  363. package/src/surfaces/logic-workspace.json +685 -0
  364. package/src/surfaces/logic-workspace.ts +238 -0
  365. package/src/surfaces/media-browser.json +303 -0
  366. package/src/surfaces/media-browser.ts +145 -0
  367. package/src/surfaces/media-field.json +163 -0
  368. package/src/surfaces/media-field.ts +116 -0
  369. package/src/surfaces/media-pane.json +513 -0
  370. package/src/surfaces/media-pane.ts +197 -0
  371. package/src/surfaces/menu.json +232 -0
  372. package/src/surfaces/menu.ts +375 -0
  373. package/src/surfaces/navigator-dock.json +113 -0
  374. package/src/surfaces/navigator-dock.ts +130 -0
  375. package/src/surfaces/new-project.json +1654 -0
  376. package/src/surfaces/new-project.ts +411 -0
  377. package/src/surfaces/palette.json +535 -0
  378. package/src/surfaces/pane-context.json +1497 -0
  379. package/src/surfaces/pane-context.ts +513 -0
  380. package/src/surfaces/pane-grid.json +188 -0
  381. package/src/surfaces/pane-grid.ts +250 -0
  382. package/src/surfaces/panel-activity.json +563 -0
  383. package/src/surfaces/panel-activity.ts +187 -0
  384. package/src/surfaces/panel-data.json +141 -0
  385. package/src/surfaces/panel-data.ts +156 -0
  386. package/src/surfaces/panel-deploy-checklist.json +283 -0
  387. package/src/surfaces/panel-deploy-checklist.ts +175 -0
  388. package/src/surfaces/panel-elements.json +367 -0
  389. package/src/surfaces/panel-elements.ts +175 -0
  390. package/src/surfaces/panel-i18n.json +569 -0
  391. package/src/surfaces/panel-i18n.ts +212 -0
  392. package/src/surfaces/panel-imports.json +780 -0
  393. package/src/surfaces/panel-imports.ts +209 -0
  394. package/src/surfaces/panel-outline.json +734 -0
  395. package/src/surfaces/panel-outline.ts +326 -0
  396. package/src/surfaces/panel-page.json +1017 -0
  397. package/src/surfaces/panel-page.ts +240 -0
  398. package/src/surfaces/panel-problems.json +497 -0
  399. package/src/surfaces/panel-problems.ts +157 -0
  400. package/src/surfaces/panel-signals.json +1973 -0
  401. package/src/surfaces/panel-signals.ts +436 -0
  402. package/src/surfaces/panel-stylebook-layers.json +317 -0
  403. package/src/surfaces/panel-stylebook-layers.ts +155 -0
  404. package/src/surfaces/preferences.json +850 -0
  405. package/src/surfaces/preferences.ts +332 -0
  406. package/src/surfaces/progress-modal.json +110 -0
  407. package/src/surfaces/progress-modal.ts +150 -0
  408. package/src/surfaces/properties-panel.json +1578 -0
  409. package/src/surfaces/properties-panel.ts +337 -0
  410. package/src/surfaces/publish.json +945 -0
  411. package/src/surfaces/publish.ts +392 -0
  412. package/src/surfaces/push-plan.json +110 -0
  413. package/src/surfaces/push-plan.ts +87 -0
  414. package/src/surfaces/rail.json +255 -0
  415. package/src/surfaces/rail.ts +206 -0
  416. package/src/surfaces/reference-field.json +191 -0
  417. package/src/surfaces/reference-field.ts +168 -0
  418. package/src/surfaces/schema-builder.json +1011 -0
  419. package/src/surfaces/schema-builder.ts +181 -0
  420. package/src/surfaces/schema-form.json +1013 -0
  421. package/src/surfaces/schema-form.ts +287 -0
  422. package/src/surfaces/secret-field.json +60 -0
  423. package/src/surfaces/secret-field.ts +146 -0
  424. package/src/surfaces/seo.json +932 -0
  425. package/src/surfaces/seo.ts +334 -0
  426. package/src/surfaces/settings-contexts.json +538 -0
  427. package/src/surfaces/settings-contexts.ts +196 -0
  428. package/src/surfaces/settings-contributed.json +489 -0
  429. package/src/surfaces/settings-contributed.ts +199 -0
  430. package/src/surfaces/settings-css-vars.json +820 -0
  431. package/src/surfaces/settings-css-vars.ts +199 -0
  432. package/src/surfaces/settings-defs.json +1363 -0
  433. package/src/surfaces/settings-defs.ts +232 -0
  434. package/src/surfaces/settings-deploy.json +108 -0
  435. package/src/surfaces/settings-deploy.ts +135 -0
  436. package/src/surfaces/settings-extensions.json +486 -0
  437. package/src/surfaces/settings-extensions.ts +201 -0
  438. package/src/surfaces/settings-head.json +779 -0
  439. package/src/surfaces/settings-head.ts +397 -0
  440. package/src/surfaces/settings-locales.json +420 -0
  441. package/src/surfaces/settings-locales.ts +137 -0
  442. package/src/surfaces/settings-overview.json +423 -0
  443. package/src/surfaces/settings-overview.ts +218 -0
  444. package/src/surfaces/settings-packages.json +549 -0
  445. package/src/surfaces/settings-packages.ts +158 -0
  446. package/src/surfaces/settings-pane.json +147 -0
  447. package/src/surfaces/settings-pane.ts +150 -0
  448. package/src/surfaces/settings-rawjson.json +104 -0
  449. package/src/surfaces/settings-rawjson.ts +107 -0
  450. package/src/surfaces/shell.json +99 -0
  451. package/src/surfaces/shell.ts +30 -0
  452. package/src/surfaces/slash-menu.json +180 -0
  453. package/src/surfaces/slash-menu.ts +272 -0
  454. package/src/surfaces/statements.json +607 -0
  455. package/src/surfaces/statements.ts +238 -0
  456. package/src/surfaces/statusbar.json +94 -0
  457. package/src/{panels → surfaces}/statusbar.ts +163 -90
  458. package/src/surfaces/style-panel.json +1643 -0
  459. package/src/surfaces/style-panel.ts +338 -0
  460. package/src/surfaces/stylebook-chrome.json +122 -0
  461. package/src/surfaces/stylebook-chrome.ts +122 -0
  462. package/src/surfaces/tab-strip.json +448 -0
  463. package/src/surfaces/tab-strip.ts +200 -0
  464. package/src/surfaces/target-line.json +419 -0
  465. package/src/surfaces/target-line.ts +349 -0
  466. package/src/surfaces/toasts.json +189 -0
  467. package/src/surfaces/welcome.json +571 -0
  468. package/src/surfaces/welcome.ts +338 -0
  469. package/src/tabs/project-config.ts +71 -15
  470. package/src/tabs/tab.ts +52 -1
  471. package/src/types.ts +22 -0
  472. package/src/ui/ai-credentials-form.ts +104 -100
  473. package/src/ui/ai-managed-connect.ts +54 -36
  474. package/src/ui/ai-model-picker.ts +75 -47
  475. package/src/ui/cf-account-picker.ts +76 -141
  476. package/src/ui/color-selector.ts +80 -301
  477. package/src/ui/dynamic-slot.ts +43 -283
  478. package/src/ui/expression-editor.ts +797 -576
  479. package/src/ui/field-input.ts +8 -181
  480. package/src/ui/form-controls.ts +838 -366
  481. package/src/ui/formula-chips.ts +80 -85
  482. package/src/ui/kit.ts +33 -0
  483. package/src/ui/layers.ts +293 -593
  484. package/src/ui/media-picker.ts +203 -284
  485. package/src/ui/panel-resize.ts +251 -64
  486. package/src/ui/popover-surface.ts +153 -0
  487. package/src/ui/progress-modal.ts +22 -60
  488. package/src/ui/regions.ts +13 -7
  489. package/src/ui/schema-form.ts +906 -440
  490. package/src/ui/surface.ts +122 -0
  491. package/src/ui/unit-selector.ts +15 -131
  492. package/src/ui/value-source.ts +14 -0
  493. package/src/ui/virtual-window.ts +88 -9
  494. package/src/utils/canvas-media.ts +72 -0
  495. package/src/utils/edit-display.ts +7 -2
  496. package/src/utils/element-selectors.ts +69 -0
  497. package/src/utils/link-target.ts +2 -2
  498. package/src/utils/studio-utils.ts +0 -10
  499. package/src/view.ts +15 -0
  500. package/src/workspace/pane-derive.ts +36 -14
  501. package/src/workspace/workspace.ts +15 -6
  502. package/styles/canvas.css +72 -467
  503. package/styles/forced-colors.css +48 -82
  504. package/styles/forced-colors.json +41 -0
  505. package/styles/inspector.css +2 -1301
  506. package/styles/overlays.css +96 -2823
  507. package/styles/panels.css +6 -1423
  508. package/styles/shell-frame.css +272 -0
  509. package/styles/shell-frame.json +227 -0
  510. package/styles/shell.css +0 -1568
  511. package/styles/tokens.css +65 -136
  512. package/styles/tokens.json +84 -0
  513. package/dist/chunks/Overlay.dev-etqjwyf9.js +0 -23
  514. package/dist/chunks/adapter-jkcyhgtr.js +0 -14
  515. package/dist/chunks/cf-account-picker-en86v7x7.js +0 -163
  516. package/dist/chunks/cf-settings-45fgyx8y.js +0 -21
  517. package/dist/chunks/components-zmx10t62.js +0 -21
  518. package/dist/chunks/content-source-48xg86wj.js +0 -49
  519. package/dist/chunks/convert-to-repeater-43tfn7cs.js +0 -268
  520. package/dist/chunks/editor-cptq5jp1.js +0 -37
  521. package/dist/chunks/entry-commands-e63f1xc0.js +0 -46
  522. package/dist/chunks/extension-sections-txv08xxg.js +0 -311
  523. package/dist/chunks/file-ops-wbh4hhsx.js +0 -48
  524. package/dist/chunks/files-3kfkwhk4.js +0 -93
  525. package/dist/chunks/flow-qbfgrpeh.js +0 -634
  526. package/dist/chunks/focus-trap.esm-9t2drp0g.js +0 -1025
  527. package/dist/chunks/focus-visible-6eg70z18.js +0 -167
  528. package/dist/chunks/format-host-w16q81tf.js +0 -43
  529. package/dist/chunks/fs-events-hrrg328g.js +0 -21
  530. package/dist/chunks/git-panel-532whr1y.js +0 -59
  531. package/dist/chunks/index-zqxmqxmh.js +0 -109
  532. package/dist/chunks/jx-validate-8er6gbxy.js +0 -19
  533. package/dist/chunks/layers-panel-07hm7g5j.js +0 -67
  534. package/dist/chunks/layers-q75tj2mf.js +0 -45
  535. package/dist/chunks/lit-html-j055mkh8.js +0 -22
  536. package/dist/chunks/monaco-buffer-dqw0xxpx.js +0 -25
  537. package/dist/chunks/notify-yjm79n4s.js +0 -30
  538. package/dist/chunks/parse-24d0gay3.js +0 -19
  539. package/dist/chunks/platform-ba1j1gbh.js +0 -16
  540. package/dist/chunks/publish-panel-v9st96ja.js +0 -29
  541. package/dist/chunks/quick-search-zccjp6gv.js +0 -66
  542. package/dist/chunks/references-3qx8fkyp.js +0 -29
  543. package/dist/chunks/right-panel-vm3b6kwy.js +0 -46
  544. package/dist/chunks/section-registry-sx1ykvkw.js +0 -30
  545. package/dist/chunks/sp-overlay.dev-qgvhnxf4.js +0 -18
  546. package/dist/chunks/sp-popover.dev-n2etmqdp.js +0 -9
  547. package/dist/chunks/sp-progress-circle.dev-hryhj0es.js +0 -15
  548. package/dist/chunks/sp-tooltip.dev-4sastdnw.js +0 -15
  549. package/dist/chunks/sp-tray.dev-tkbscm06.js +0 -199
  550. package/dist/chunks/studio-0a5qrh01.js +0 -3
  551. package/dist/chunks/studio-0bq6eh7v.js +0 -12
  552. package/dist/chunks/studio-18j3bmcz.js +0 -14
  553. package/dist/chunks/studio-1ngbejft.js +0 -181
  554. package/dist/chunks/studio-4b5z1x43.js +0 -424
  555. package/dist/chunks/studio-4n2b5gzb.js +0 -357
  556. package/dist/chunks/studio-4rzyrtjz.js +0 -426
  557. package/dist/chunks/studio-5fx3g9jg.js +0 -4325
  558. package/dist/chunks/studio-5myknm0a.js +0 -1903
  559. package/dist/chunks/studio-7afd21nw.js +0 -67
  560. package/dist/chunks/studio-7nte2hj4.js +0 -613
  561. package/dist/chunks/studio-8jpzqk5s.js +0 -128
  562. package/dist/chunks/studio-8q517dfr.js +0 -24
  563. package/dist/chunks/studio-950k0dx6.js +0 -6939
  564. package/dist/chunks/studio-9n4mrmnb.js +0 -184
  565. package/dist/chunks/studio-a0tswy0w.js +0 -58
  566. package/dist/chunks/studio-ahnzd9rg.js +0 -23
  567. package/dist/chunks/studio-cmb03bg5.js +0 -13890
  568. package/dist/chunks/studio-d1ks410h.js +0 -175
  569. package/dist/chunks/studio-ef49pnzx.js +0 -387
  570. package/dist/chunks/studio-eqq1w638.js +0 -113
  571. package/dist/chunks/studio-ew0djmhg.js +0 -341
  572. package/dist/chunks/studio-gfgb8pe6.js +0 -1652
  573. package/dist/chunks/studio-h4rxscfc.js +0 -10
  574. package/dist/chunks/studio-jc994dnr.js +0 -1066
  575. package/dist/chunks/studio-kyh9avvv.js +0 -28
  576. package/dist/chunks/studio-m3hwn7y1.js +0 -120
  577. package/dist/chunks/studio-mtfnaqs9.js +0 -659
  578. package/dist/chunks/studio-n6j9t10q.js +0 -318
  579. package/dist/chunks/studio-n8b9wqwy.js +0 -291
  580. package/dist/chunks/studio-qcy05dp8.js +0 -1743
  581. package/dist/chunks/studio-qq6jym04.js +0 -53
  582. package/dist/chunks/studio-rdx8jcxy.js +0 -83
  583. package/dist/chunks/studio-rn9ta2mz.js +0 -111
  584. package/dist/chunks/studio-t7qb9db8.js +0 -665
  585. package/dist/chunks/studio-tmc5emrw.js +0 -8
  586. package/dist/chunks/studio-z6nw2ek2.js +0 -18
  587. package/dist/chunks/studio-zczps70q.js +0 -378
  588. package/dist/chunks/studio-zqazsct2.js +0 -1823
  589. package/dist/chunks/workspace-fjx52ryv.js +0 -89
  590. package/src/panels/activity-bar.ts +0 -251
  591. package/src/panels/panel-scheduler.ts +0 -219
  592. package/src/panels/style-inputs.ts +0 -237
  593. package/src/panels/target-line.ts +0 -274
  594. package/src/panels/welcome-screen.ts +0 -346
  595. package/src/ui/button-group.ts +0 -102
  596. package/src/ui/choice-field.ts +0 -72
  597. package/src/ui/field-row.ts +0 -249
  598. package/src/ui/formula-palette.ts +0 -213
  599. package/src/ui/icons.ts +0 -52
  600. package/src/ui/jx-theme.ts +0 -130
  601. package/src/ui/spectrum.ts +0 -340
  602. package/src/ui/value-selector.ts +0 -174
  603. package/src/ui/widgets.ts +0 -172
  604. /package/dist/chunks/{javascript-s56a8dpk.css → javascript-4abzjcy9.css} +0 -0
  605. /package/dist/chunks/{jsonMode-zr9sw0c7.css → jsonMode-vvmpmk34.css} +0 -0
  606. /package/dist/chunks/{monaco-setup-pav68602.css → monaco-setup-8vbyqnhr.css} +0 -0
  607. /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
+ }
@@ -1,138 +1,22 @@
1
- /// <reference lib="dom" />
2
1
  /**
3
- * Unit-selector.js — Number + unit picker widget.
2
+ * The CSS length grammar the Style tab parses a typed value with.
4
3
  *
5
- * Renders a text field for numeric input paired with a unit picker dropdown. Handles keywords
6
- * (auto, inherit, etc.) alongside numeric+unit values.
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
- * Render a number + unit selector widget.
15
+ * A number and, optionally, one of the units the panel offers.
18
16
  *
19
- * @param {Record<string, unknown>} entry — css-meta entry with $units and $keywords arrays
20
- * @param {string} prop — property key (for debounce namespace)
21
- * @param {string | number | undefined} value — current value (e.g. "12px", "auto", "")
22
- * @param {(val: string) => void} onChange — commit callback
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 function renderUnitSelector(
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)?$/;
@@ -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 —
@@ -114,9 +114,24 @@ export function computeWindow(spec: WindowSpec): WindowRange {
114
114
  };
115
115
  }
116
116
 
117
- /** Two ranges are the same window — the guard that keeps scrolling from repainting every frame. */
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 a.start === b.start && a.end === b.end && a.totalRows === b.totalRows;
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(() => measure());
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 (`styles/panels.css` gives `.layer-row` and
341
- * `.file-tree-item` a `block-size`) is what lets the FIRST render window anything at all, before
342
- * any row has been laid out. The MEASUREMENT is what stops that constant becoming a lie the day
343
- * someone changes the row's padding, a user zooms, or a locale's font raises the line box: a window
344
- * computed from a stale height does not fail loudly, it drifts, and the list quietly ends a few
345
- * rows short of its own scrollbar.
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
- // Replace template strings in style values with empty strings
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
- s[sk] = typeof sv === "string" && sv.includes("${") ? "" : sv;
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
+ }
@@ -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
- * 4. absolute (`http(s)://…`) or protocol-relative (`//…`) → `{ kind: "external", value: href }` 5.
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. */