@jxsuite/studio 6.1.0 → 6.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (645) hide show
  1. package/dist/chunks/2020-f2gkpy8d.js +4 -0
  2. package/dist/chunks/{action-group-2mqby73c.js → action-group-4aan7g6g.js} +3 -3
  3. package/dist/chunks/adapter-4912g339.js +4 -0
  4. package/dist/chunks/cf-account-picker-wccaenh6.js +4 -0
  5. package/dist/chunks/cf-settings-br6105tr.js +4 -0
  6. package/dist/chunks/color-28ksk2qm.js +4 -0
  7. package/dist/chunks/color-area-0fj8a4ga.js +4 -0
  8. package/dist/chunks/color-field-xch8kx2g.js +4 -0
  9. package/dist/chunks/color-slider-jxd8v350.js +4 -0
  10. package/dist/chunks/combobox-p0efwjke.js +4 -0
  11. package/dist/chunks/components-db68vsn7.js +4 -0
  12. package/dist/chunks/content-source-1449qesq.js +4 -0
  13. package/dist/chunks/convert-to-repeater-5h457egj.js +4 -0
  14. package/dist/chunks/dialog-c4x05vyx.js +4 -0
  15. package/dist/chunks/editor-x9jn86a7.js +4 -0
  16. package/dist/chunks/entry-commands-may24cpt.js +4 -0
  17. package/dist/chunks/extension-sections-pvr14vxr.js +4 -0
  18. package/dist/chunks/file-ops-x9v54pcj.js +4 -0
  19. package/dist/chunks/files-j3knqf0s.js +4 -0
  20. package/dist/chunks/format-host-tyre2trb.js +4 -0
  21. package/dist/chunks/fs-events-64ma9htc.js +4 -0
  22. package/dist/chunks/git-panel-84ps5dex.js +4 -0
  23. package/dist/chunks/grid-view-d2wq9ezg.js +51 -0
  24. package/dist/chunks/icons-pnfz478q.js +4 -0
  25. package/dist/chunks/iframe-entry-fvbk89gm.js +5 -0
  26. package/dist/chunks/iframe-entry-jdcktez8.js +5 -0
  27. package/dist/chunks/iframe-entry-x0ygf2yr.js +5 -0
  28. package/dist/chunks/iframe-entry-zap785cw.js +5 -0
  29. package/dist/chunks/iframe-host-ck6vejt5.js +4 -0
  30. package/dist/chunks/index-b8xw3vy9.js +4 -0
  31. package/dist/chunks/{index-gybvv7a6.js → index-zpjmzqfk.js} +3 -3
  32. package/dist/chunks/{javascript-rnvdp3k4.js → javascript-m54mnwp6.js} +3 -3
  33. package/dist/chunks/jsonMode-w15cmrcm.js +13 -0
  34. package/dist/chunks/jx-validate-at3zn8wa.js +4 -0
  35. package/dist/chunks/layers-h4xp1pss.js +4 -0
  36. package/dist/chunks/layers-panel-m5hw1d7g.js +4 -0
  37. package/dist/chunks/listbox-e74qjyq6.js +4 -0
  38. package/dist/chunks/lit-html-8t8t3dnr.js +4 -0
  39. package/dist/chunks/media-picker-2cweexc5.js +4 -0
  40. package/dist/chunks/menu-n6yzswmy.js +4 -0
  41. package/dist/chunks/menu-ynw13y0s.js +4 -0
  42. package/dist/chunks/monaco-binding-7gx83x3r.js +4 -0
  43. package/dist/chunks/monaco-buffer-qzxn567r.js +4 -0
  44. package/dist/chunks/monaco-setup-gxf6656g.js +4 -0
  45. package/dist/chunks/notify-cj5zbrs2.js +4 -0
  46. package/dist/chunks/number-field-y62xq0ty.js +4 -0
  47. package/dist/chunks/parse-b7ddhr8m.js +4 -0
  48. package/dist/chunks/platform-3dfws9js.js +4 -0
  49. package/dist/chunks/popover-jt2gxmzs.js +4 -0
  50. package/dist/chunks/publish-panel-1gvxbj21.js +4 -0
  51. package/dist/chunks/quick-search-0dajrwqg.js +4 -0
  52. package/dist/chunks/references-49qgt404.js +4 -0
  53. package/dist/chunks/right-panel-jm1bwe53.js +4 -0
  54. package/dist/chunks/section-registry-6kwc4fky.js +4 -0
  55. package/dist/chunks/select-rzds841e.js +4 -0
  56. package/dist/chunks/split-n2gfpm5m.js +4 -0
  57. package/dist/chunks/{studio-5g0ag7c0.js → studio-0q988f9w.js} +3 -3
  58. package/dist/chunks/studio-0rt52vpq.js +5 -0
  59. package/dist/chunks/studio-18vgbhs5.js +5 -0
  60. package/dist/chunks/{studio-pxg4ap1e.js → studio-1fxkaaea.js} +4 -4
  61. package/dist/chunks/studio-24mccdrj.js +5 -0
  62. package/dist/chunks/studio-2eh507zk.js +9 -0
  63. package/dist/chunks/studio-2hcbccfv.js +5 -0
  64. package/dist/chunks/studio-2j1cb95x.js +5 -0
  65. package/dist/chunks/studio-2jbs3rxv.js +5 -0
  66. package/dist/chunks/{studio-qbj760tx.js → studio-485046te.js} +7 -7
  67. package/dist/chunks/studio-4h8k4dw9.js +5 -0
  68. package/dist/chunks/studio-5f6n18kx.js +5 -0
  69. package/dist/chunks/studio-5gthpky6.js +5 -0
  70. package/dist/chunks/studio-5ve6bbep.js +5 -0
  71. package/dist/chunks/studio-6ep3js6b.js +9 -0
  72. package/dist/chunks/studio-6wkmf3wz.js +9 -0
  73. package/dist/chunks/studio-841rf3cg.js +5 -0
  74. package/dist/chunks/studio-8gmwgheg.js +5 -0
  75. package/dist/chunks/studio-8qm0ep50.js +5 -0
  76. package/dist/chunks/{studio-anyrgzvb.js → studio-90pq9km1.js} +4 -4
  77. package/dist/chunks/studio-924p1tm1.js +6 -0
  78. package/dist/chunks/{studio-v2bvmbjj.js → studio-a3g98wjr.js} +4 -4
  79. package/dist/chunks/studio-a3shpz9y.js +5 -0
  80. package/dist/chunks/studio-amsbaaar.js +6 -0
  81. package/dist/chunks/studio-at5spjbc.js +7 -0
  82. package/dist/chunks/studio-b2xv945e.js +5 -0
  83. package/dist/chunks/studio-bn5nkafw.js +5 -0
  84. package/dist/chunks/studio-bw6q5xjf.js +9 -0
  85. package/dist/chunks/studio-c7q0t9x1.js +5 -0
  86. package/dist/chunks/studio-camnhc96.js +6 -0
  87. package/dist/chunks/studio-cffqvnzd.js +5 -0
  88. package/dist/chunks/studio-d81xfh1g.js +5 -0
  89. package/dist/chunks/studio-dgz8d0c1.js +5 -0
  90. package/dist/chunks/studio-efvfrsf8.js +5 -0
  91. package/dist/chunks/studio-er30bpcx.js +5 -0
  92. package/dist/chunks/studio-ezscgr64.js +5 -0
  93. package/dist/chunks/studio-ffrrncvz.js +5 -0
  94. package/dist/chunks/studio-fpphgn8y.js +10 -0
  95. package/dist/chunks/studio-j1kvhdjk.js +4 -0
  96. package/dist/chunks/{studio-txjjzrsm.js → studio-j430n16g.js} +5 -5
  97. package/dist/chunks/studio-jjkg84nj.js +5 -0
  98. package/dist/chunks/studio-m0q32ars.js +4 -0
  99. package/dist/chunks/studio-m6bdst11.js +5 -0
  100. package/dist/chunks/studio-nv2cptd4.js +64 -0
  101. package/dist/chunks/studio-nwfrc98n.js +5 -0
  102. package/dist/chunks/studio-p1wgvp7r.js +5 -0
  103. package/dist/chunks/studio-pag2wncm.js +5 -0
  104. package/dist/chunks/studio-qvanvzfd.js +5 -0
  105. package/dist/chunks/studio-qwa64kt7.js +5 -0
  106. package/dist/chunks/studio-rk1zc4x3.js +928 -0
  107. package/dist/chunks/studio-se2r3ptc.js +5 -0
  108. package/dist/chunks/studio-sg2a0dh0.js +5 -0
  109. package/dist/chunks/studio-tjzjhe68.js +5 -0
  110. package/dist/chunks/{studio-0x3jyb8r.js → studio-tq0rtfwj.js} +4 -4
  111. package/dist/chunks/{studio-cpxkgjrj.js → studio-v0jzqdjm.js} +4 -4
  112. package/dist/chunks/studio-v2w7q8r1.js +7 -0
  113. package/dist/chunks/studio-v5vjq1h0.js +4 -0
  114. package/dist/chunks/studio-v8aga3vp.js +14 -0
  115. package/dist/chunks/studio-vfcdrfmv.js +5 -0
  116. package/dist/chunks/studio-vmfkgdjf.js +5 -0
  117. package/dist/chunks/studio-wt1816jj.js +5 -0
  118. package/dist/chunks/studio-wz73q5kq.js +4 -0
  119. package/dist/chunks/studio-y04qtxvp.js +7 -0
  120. package/dist/chunks/studio-y21g8zzg.js +5 -0
  121. package/dist/chunks/studio-y64hrt8p.js +12 -0
  122. package/dist/chunks/studio-ynn90f58.js +16 -0
  123. package/dist/chunks/studio-yxz682sx.js +5 -0
  124. package/dist/chunks/studio-zp7snvkq.js +5 -0
  125. package/dist/chunks/studio-zq4z6tm6.js +5 -0
  126. package/dist/chunks/swatch-group-ewh24n1f.js +4 -0
  127. package/dist/chunks/tabs-f5cw3tgp.js +4 -0
  128. package/dist/chunks/textfield-wewc8rq2.js +4 -0
  129. package/dist/chunks/toast-c9fn075p.js +4 -0
  130. package/dist/chunks/toast-host-ke5z4ng7.js +4 -0
  131. package/dist/chunks/{toolbar-2nnzqhrj.js → toolbar-44cm5cta.js} +3 -3
  132. package/dist/chunks/tooltip-5v8ngwj2.js +4 -0
  133. package/dist/chunks/tree-mdq3v5cw.js +4 -0
  134. package/dist/chunks/tsMode-sf49ee9x.js +14 -0
  135. package/dist/chunks/workspace-jtfahpee.js +4 -0
  136. package/dist/chunks/ws-client-nze0k6mv.js +4 -0
  137. package/dist/iframe-entry.js +16 -16
  138. package/dist/manifest.json +63 -63
  139. package/dist/studio.js +98 -98
  140. package/dist/workers/ts.worker.js +3 -3
  141. package/package.json +11 -11
  142. package/src/about/about-modal.ts +4 -3
  143. package/src/account/action-flow.ts +45 -38
  144. package/src/account-status.ts +7 -2
  145. package/src/browse/library-layouts.ts +8 -5
  146. package/src/browse/library-model.ts +18 -6
  147. package/src/browse/library-pane.ts +37 -21
  148. package/src/browse/library-preview.ts +14 -9
  149. package/src/browse/library-source.ts +1 -1
  150. package/src/canvas/asset-refs.ts +24 -9
  151. package/src/canvas/asset-resolve.ts +19 -23
  152. package/src/canvas/canvas-helpers.ts +7 -6
  153. package/src/canvas/canvas-live-render.ts +44 -53
  154. package/src/canvas/canvas-patcher.ts +30 -30
  155. package/src/canvas/canvas-perf.ts +11 -5
  156. package/src/canvas/canvas-render.ts +66 -42
  157. package/src/canvas/canvas-surface.ts +5 -3
  158. package/src/canvas/canvas-utils.ts +163 -64
  159. package/src/canvas/dialog-path.ts +9 -4
  160. package/src/canvas/dialog-state.ts +1 -2
  161. package/src/canvas/diff-marks.ts +9 -16
  162. package/src/canvas/diff-toolbar.ts +8 -7
  163. package/src/canvas/edit-width-drag.ts +4 -1
  164. package/src/canvas/edit-width.ts +1 -3
  165. package/src/canvas/iframe-channel.ts +27 -13
  166. package/src/canvas/iframe-drop.ts +13 -12
  167. package/src/canvas/iframe-editable-root.ts +29 -16
  168. package/src/canvas/iframe-entry.ts +80 -63
  169. package/src/canvas/iframe-eval.ts +73 -49
  170. package/src/canvas/iframe-host.ts +203 -118
  171. package/src/canvas/iframe-inline-edit.ts +69 -32
  172. package/src/canvas/iframe-insert.ts +5 -4
  173. package/src/canvas/iframe-interaction.ts +37 -26
  174. package/src/canvas/iframe-overlay.ts +1 -1
  175. package/src/canvas/iframe-patch.ts +18 -15
  176. package/src/canvas/iframe-position.ts +12 -6
  177. package/src/canvas/iframe-protocol.ts +15 -16
  178. package/src/canvas/iframe-render.ts +41 -36
  179. package/src/canvas/iframe-slash.ts +24 -11
  180. package/src/canvas/iframe-subtree.ts +6 -2
  181. package/src/canvas/path-mapping.ts +19 -12
  182. package/src/canvas/popover-path.ts +7 -3
  183. package/src/canvas/popover-state.ts +1 -2
  184. package/src/canvas/serialize-scope.ts +13 -5
  185. package/src/canvas/stage-scrollbar.ts +2 -1
  186. package/src/canvas/surface-registry.ts +21 -3
  187. package/src/collab/collab-commands.ts +7 -2
  188. package/src/collab/collab-session.ts +84 -45
  189. package/src/collab/collab-state.ts +4 -3
  190. package/src/collab/monaco-binding.ts +16 -13
  191. package/src/collab/monaco-cursors.ts +5 -2
  192. package/src/commands/budget.ts +3 -3
  193. package/src/commands/command-args.ts +103 -71
  194. package/src/commands/context.ts +22 -20
  195. package/src/commands/defaults.ts +4 -1
  196. package/src/commands/keymap.ts +47 -43
  197. package/src/commands/levels.ts +3 -3
  198. package/src/commands/live-context.ts +10 -8
  199. package/src/commands/reference.ts +2 -1
  200. package/src/commands/registry.ts +12 -10
  201. package/src/commands/run-reported.ts +15 -10
  202. package/src/component-props.ts +46 -30
  203. package/src/content/collection-match.ts +5 -4
  204. package/src/content/draft-state.ts +4 -3
  205. package/src/content/entry-commands.ts +3 -2
  206. package/src/content/entry-editor.ts +29 -17
  207. package/src/content/entry-fields.ts +12 -7
  208. package/src/content/entry-model.ts +21 -12
  209. package/src/editor/canvas-context-menu.ts +1 -2
  210. package/src/editor/canvas-slash-bridge.ts +3 -6
  211. package/src/editor/content-slice.ts +16 -14
  212. package/src/editor/context-menu.ts +35 -22
  213. package/src/editor/convert-targets.ts +30 -35
  214. package/src/editor/convert-to-component.ts +11 -5
  215. package/src/editor/convert-to-repeater.ts +34 -22
  216. package/src/editor/editable-tags.ts +17 -2
  217. package/src/editor/file-drop-action.ts +21 -22
  218. package/src/editor/inline-edit-apply.ts +35 -17
  219. package/src/editor/inline-edit.ts +66 -50
  220. package/src/editor/inline-format.ts +59 -56
  221. package/src/editor/inline-link.ts +40 -15
  222. package/src/editor/insert-zone-action.ts +1 -1
  223. package/src/editor/merge-tags.ts +58 -19
  224. package/src/editor/repeater-scope.ts +39 -28
  225. package/src/editor/shortcuts.ts +87 -47
  226. package/src/editor/slash-menu.ts +1 -6
  227. package/src/files/asset-versions.ts +4 -4
  228. package/src/files/components.ts +15 -10
  229. package/src/files/elements.ts +5 -6
  230. package/src/files/file-ops.ts +77 -36
  231. package/src/files/files.ts +90 -95
  232. package/src/files/media-meta.ts +2 -1
  233. package/src/files/media-paths.ts +6 -1
  234. package/src/files/serialize-document.ts +2 -2
  235. package/src/format/constraints.ts +1 -1
  236. package/src/format/convert-file.ts +27 -13
  237. package/src/format/format-choices.ts +2 -1
  238. package/src/format/format-host.ts +76 -50
  239. package/src/github/github-auth-status.ts +27 -3
  240. package/src/github/github-auth.ts +19 -9
  241. package/src/github/github-publish.ts +24 -20
  242. package/src/grid/cell-editors.ts +46 -31
  243. package/src/grid/cell-popovers.ts +5 -3
  244. package/src/grid/edit-buffer.ts +10 -9
  245. package/src/grid/grid-controller.ts +20 -22
  246. package/src/grid/grid-layout.ts +21 -5
  247. package/src/grid/grid-open.ts +3 -6
  248. package/src/grid/grid-panel.ts +11 -4
  249. package/src/grid/grid-source.ts +8 -8
  250. package/src/grid/grid-view.ts +14 -17
  251. package/src/grid/redirects-grid.ts +14 -5
  252. package/src/grid/redirects.ts +16 -14
  253. package/src/grid/schema-columns.ts +25 -19
  254. package/src/grid/sources/connector-source.ts +47 -20
  255. package/src/grid/sources/content-source.ts +25 -24
  256. package/src/grid/sources/csv-file-source.ts +2 -2
  257. package/src/grid/tabulator-tables.d.ts +55 -34
  258. package/src/hosting/stage.ts +7 -7
  259. package/src/i18n/i18n-commands.ts +1 -2
  260. package/src/media/media-pane.ts +4 -1
  261. package/src/new-project/add-repo-modal.ts +20 -19
  262. package/src/new-project/import-tab.ts +10 -14
  263. package/src/new-project/location-fields.ts +2 -1
  264. package/src/new-project/new-project-modal.ts +12 -9
  265. package/src/packages/jxsuite-update.ts +4 -3
  266. package/src/packages/pull-package-sync.ts +26 -25
  267. package/src/page-params.ts +97 -68
  268. package/src/panels/activity-panel.ts +17 -9
  269. package/src/panels/ai-chat/attached-context.ts +13 -7
  270. package/src/panels/ai-chat/chat-view.ts +80 -73
  271. package/src/panels/ai-chat/composer.ts +30 -33
  272. package/src/panels/ai-chat/sessions-view.ts +1 -2
  273. package/src/panels/ai-panel.ts +23 -20
  274. package/src/panels/block-action-bar.ts +46 -35
  275. package/src/panels/bottom-dock.ts +5 -3
  276. package/src/panels/canvas-dnd-bridge.ts +31 -24
  277. package/src/panels/data-explorer.ts +62 -25
  278. package/src/panels/data-grid.ts +14 -11
  279. package/src/panels/dnd.ts +108 -118
  280. package/src/panels/editors.ts +55 -22
  281. package/src/panels/elements-panel.ts +10 -3
  282. package/src/panels/events-panel.ts +84 -69
  283. package/src/panels/formula-workspace.ts +76 -51
  284. package/src/panels/frontmatter-fields.ts +24 -19
  285. package/src/panels/frontmatter-panel.ts +44 -34
  286. package/src/panels/git-diff-open.ts +4 -4
  287. package/src/panels/git-panel.ts +49 -61
  288. package/src/panels/head-panel.ts +131 -111
  289. package/src/panels/i18n-panel.ts +10 -3
  290. package/src/panels/imports-panel.ts +23 -47
  291. package/src/panels/jump-bar.ts +48 -29
  292. package/src/panels/layers-panel.ts +97 -74
  293. package/src/panels/left-panel.ts +3 -3
  294. package/src/panels/pane-context.ts +31 -22
  295. package/src/panels/pane-grid.ts +49 -20
  296. package/src/panels/panel-registry.ts +22 -37
  297. package/src/panels/properties-panel.ts +175 -121
  298. package/src/panels/quick-search.ts +53 -31
  299. package/src/panels/right-panel.ts +3 -3
  300. package/src/panels/seo-modal.ts +13 -17
  301. package/src/panels/settings-menu.ts +15 -15
  302. package/src/panels/signals-panel.ts +153 -131
  303. package/src/panels/statement-editor.ts +230 -140
  304. package/src/panels/style-panel.ts +254 -216
  305. package/src/panels/style-utils.ts +114 -51
  306. package/src/panels/stylebook-doc.ts +57 -54
  307. package/src/panels/stylebook-layers-panel.ts +9 -9
  308. package/src/panels/stylebook-panel.ts +13 -17
  309. package/src/panels/tab-drop.ts +27 -11
  310. package/src/panels/tab-strip.ts +36 -26
  311. package/src/platform-errors.ts +57 -43
  312. package/src/platform.ts +58 -30
  313. package/src/platforms/cloud.ts +345 -175
  314. package/src/platforms/default-platform.ts +10 -4
  315. package/src/platforms/devserver.ts +174 -127
  316. package/src/platforms/read-batcher.ts +16 -8
  317. package/src/project-list.ts +2 -1
  318. package/src/publish/deploy-checklist.ts +8 -2
  319. package/src/publish/pages-service.ts +28 -13
  320. package/src/publish/publish-commands.ts +5 -4
  321. package/src/publish/publish-panel.ts +10 -6
  322. package/src/recent-projects.ts +15 -8
  323. package/src/resize-edges.ts +26 -36
  324. package/src/services/a11y-report.ts +26 -19
  325. package/src/services/agent-seed.ts +23 -11
  326. package/src/services/ai-ask.ts +9 -12
  327. package/src/services/ai-command-tools.ts +68 -62
  328. package/src/services/ai-import-tools.ts +80 -67
  329. package/src/services/ai-models.ts +17 -13
  330. package/src/services/ai-project-tools.ts +68 -32
  331. package/src/services/ai-session-store.ts +19 -10
  332. package/src/services/ai-system-prompt.ts +46 -20
  333. package/src/services/ai-tools.ts +71 -27
  334. package/src/services/ai-write-report.ts +20 -12
  335. package/src/services/ai-writes.ts +4 -4
  336. package/src/services/automation.ts +58 -31
  337. package/src/services/cem-export.ts +149 -58
  338. package/src/services/clock.ts +6 -1
  339. package/src/services/code-services.ts +37 -31
  340. package/src/services/context-manager.ts +14 -10
  341. package/src/services/context-resolver.ts +20 -8
  342. package/src/services/data-service.ts +19 -15
  343. package/src/services/directory-picker.ts +18 -12
  344. package/src/services/document-assistant.ts +39 -19
  345. package/src/services/gated-registry.ts +10 -6
  346. package/src/services/harness/chat-reducer.ts +23 -1
  347. package/src/services/import-client.ts +91 -38
  348. package/src/services/import-seed.ts +8 -2
  349. package/src/services/jx-validate.ts +28 -31
  350. package/src/services/live-preview.ts +0 -0
  351. package/src/services/live-surfaces.ts +6 -3
  352. package/src/services/model-uri.ts +10 -2
  353. package/src/services/module-preloads.ts +12 -8
  354. package/src/services/monaco-buffer.ts +43 -24
  355. package/src/services/monaco-lazy.ts +7 -8
  356. package/src/services/monaco-setup.ts +23 -16
  357. package/src/services/notify.ts +44 -17
  358. package/src/services/popover-report.ts +25 -10
  359. package/src/services/preview-eval.ts +20 -8
  360. package/src/services/profile.ts +13 -6
  361. package/src/services/project-path.ts +13 -10
  362. package/src/services/references.ts +0 -0
  363. package/src/services/render-critic.ts +8 -7
  364. package/src/services/settings/kernel.ts +13 -4
  365. package/src/services/settings/write-queue.ts +9 -9
  366. package/src/services/token-lint.ts +12 -10
  367. package/src/services/tool-executor.ts +17 -5
  368. package/src/services/tool-outcomes.ts +44 -24
  369. package/src/services/trusted-types.ts +24 -7
  370. package/src/settings/contexts-section.ts +11 -8
  371. package/src/settings/contributed-section.ts +79 -60
  372. package/src/settings/css-vars-editor.ts +37 -16
  373. package/src/settings/defs-editor.ts +38 -35
  374. package/src/settings/extension-rows.ts +16 -8
  375. package/src/settings/extension-sections.ts +23 -13
  376. package/src/settings/extensions-section.ts +4 -1
  377. package/src/settings/general-settings.ts +11 -8
  378. package/src/settings/locales-section.ts +20 -12
  379. package/src/settings/preferences-dialog.ts +9 -6
  380. package/src/settings/preferences-keymap.ts +7 -5
  381. package/src/settings/preferences-sections.ts +11 -5
  382. package/src/settings/project-sections.ts +1 -1
  383. package/src/settings/schema-field-ui.ts +9 -0
  384. package/src/settings/settings-document.ts +5 -5
  385. package/src/shell/tree.ts +6 -5
  386. package/src/shell.ts +104 -81
  387. package/src/site-context.ts +37 -22
  388. package/src/state.ts +41 -49
  389. package/src/store.ts +54 -34
  390. package/src/studio.ts +39 -77
  391. package/src/style/live-preview.ts +1 -1
  392. package/src/style/project-styles.ts +6 -7
  393. package/src/style/token-ref.ts +5 -4
  394. package/src/surfaces/about.ts +18 -19
  395. package/src/surfaces/add-repo.ts +17 -19
  396. package/src/surfaces/ai-chat.ts +31 -36
  397. package/src/surfaces/ai-credentials-form.ts +6 -16
  398. package/src/surfaces/ai-managed-connect.ts +3 -4
  399. package/src/surfaces/ai-model-picker.ts +3 -5
  400. package/src/surfaces/block-action-bar.ts +22 -11
  401. package/src/surfaces/boot-failure.ts +4 -5
  402. package/src/surfaces/bottom-dock.ts +9 -18
  403. package/src/surfaces/canvas-stage.ts +12 -11
  404. package/src/surfaces/cf-account-picker.ts +17 -18
  405. package/src/surfaces/commandbar.ts +14 -9
  406. package/src/surfaces/convert-repeater.ts +17 -19
  407. package/src/surfaces/data-actions.ts +9 -7
  408. package/src/surfaces/dialog.ts +26 -28
  409. package/src/surfaces/diff-toolbar.ts +9 -7
  410. package/src/surfaces/doc-header.ts +10 -19
  411. package/src/surfaces/empty-state.ts +7 -10
  412. package/src/surfaces/entry-editor.ts +14 -11
  413. package/src/surfaces/expression-editor.ts +11 -25
  414. package/src/surfaces/files-panel.ts +27 -14
  415. package/src/surfaces/formula-palette.ts +4 -5
  416. package/src/surfaces/git-panel.ts +7 -15
  417. package/src/surfaces/github-auth.ts +16 -20
  418. package/src/surfaces/github-publish.ts +17 -22
  419. package/src/surfaces/grid-cell.ts +30 -31
  420. package/src/surfaces/grid-open.ts +10 -14
  421. package/src/surfaces/grid-panel.ts +13 -9
  422. package/src/surfaces/grid-replace.ts +13 -13
  423. package/src/surfaces/grid-views.ts +15 -18
  424. package/src/surfaces/inspector-dock.ts +13 -12
  425. package/src/surfaces/jump-bar.ts +5 -6
  426. package/src/surfaces/jxsuite-update.ts +16 -22
  427. package/src/surfaces/library-pane.ts +25 -20
  428. package/src/surfaces/logic-panel.ts +17 -30
  429. package/src/surfaces/logic-workspace.ts +13 -15
  430. package/src/surfaces/media-browser.ts +11 -10
  431. package/src/surfaces/media-field.ts +4 -5
  432. package/src/surfaces/media-pane.ts +8 -7
  433. package/src/surfaces/menu.ts +29 -23
  434. package/src/surfaces/navigator-dock.ts +11 -12
  435. package/src/surfaces/new-project.ts +27 -26
  436. package/src/surfaces/pane-context.ts +20 -25
  437. package/src/surfaces/pane-grid.ts +15 -10
  438. package/src/surfaces/panel-activity.ts +5 -6
  439. package/src/surfaces/panel-data.ts +3 -4
  440. package/src/surfaces/panel-deploy-checklist.ts +5 -6
  441. package/src/surfaces/panel-elements.ts +5 -7
  442. package/src/surfaces/panel-i18n.ts +5 -7
  443. package/src/surfaces/panel-imports.ts +6 -13
  444. package/src/surfaces/panel-outline.ts +25 -19
  445. package/src/surfaces/panel-page.ts +11 -18
  446. package/src/surfaces/panel-problems.ts +5 -7
  447. package/src/surfaces/panel-signals.ts +20 -34
  448. package/src/surfaces/panel-stylebook-layers.ts +5 -8
  449. package/src/surfaces/preferences.ts +21 -11
  450. package/src/surfaces/progress-modal.ts +15 -9
  451. package/src/surfaces/properties-panel.json +1 -1
  452. package/src/surfaces/properties-panel.ts +20 -42
  453. package/src/surfaces/publish.ts +18 -18
  454. package/src/surfaces/push-plan.ts +7 -8
  455. package/src/surfaces/rail.json +126 -73
  456. package/src/surfaces/rail.ts +38 -12
  457. package/src/surfaces/reference-field.ts +11 -15
  458. package/src/surfaces/schema-builder.ts +16 -22
  459. package/src/surfaces/schema-form.ts +15 -25
  460. package/src/surfaces/secret-field.ts +9 -6
  461. package/src/surfaces/seo.ts +21 -15
  462. package/src/surfaces/settings-contexts.ts +9 -7
  463. package/src/surfaces/settings-contributed.ts +14 -10
  464. package/src/surfaces/settings-css-vars.ts +5 -12
  465. package/src/surfaces/settings-defs.json +2 -2
  466. package/src/surfaces/settings-defs.ts +17 -21
  467. package/src/surfaces/settings-deploy.ts +8 -15
  468. package/src/surfaces/settings-extensions.ts +5 -6
  469. package/src/surfaces/settings-head.ts +33 -39
  470. package/src/surfaces/settings-locales.ts +8 -20
  471. package/src/surfaces/settings-overview.ts +5 -6
  472. package/src/surfaces/settings-packages.ts +8 -7
  473. package/src/surfaces/settings-pane.ts +9 -18
  474. package/src/surfaces/settings-rawjson.ts +5 -6
  475. package/src/surfaces/shell.ts +1 -2
  476. package/src/surfaces/slash-menu.ts +19 -9
  477. package/src/surfaces/statements.ts +13 -18
  478. package/src/surfaces/statusbar.ts +17 -14
  479. package/src/surfaces/style-panel.ts +18 -31
  480. package/src/surfaces/stylebook-chrome.ts +3 -5
  481. package/src/surfaces/tab-strip.ts +14 -13
  482. package/src/surfaces/target-line.ts +6 -7
  483. package/src/surfaces/welcome.ts +5 -7
  484. package/src/tabs/patch-ops.ts +4 -3
  485. package/src/tabs/project-config.ts +32 -21
  486. package/src/tabs/selection.ts +36 -8
  487. package/src/tabs/tab.ts +52 -41
  488. package/src/tabs/transact.ts +98 -53
  489. package/src/tabs/typing.ts +31 -0
  490. package/src/types.ts +32 -17
  491. package/src/ui/ai-credentials-form.ts +10 -13
  492. package/src/ui/ai-model-picker.ts +3 -3
  493. package/src/ui/cf-account-picker.ts +7 -9
  494. package/src/ui/color-selector.ts +9 -5
  495. package/src/ui/dynamic-slot.ts +7 -8
  496. package/src/ui/expression-editor.ts +112 -105
  497. package/src/ui/form-controls.ts +57 -48
  498. package/src/ui/formula-catalog.ts +239 -230
  499. package/src/ui/formula-chips.ts +33 -18
  500. package/src/ui/layers.ts +44 -31
  501. package/src/ui/media-picker.ts +18 -9
  502. package/src/ui/popover-surface.ts +20 -12
  503. package/src/ui/progress-modal.ts +13 -8
  504. package/src/ui/regions.ts +7 -6
  505. package/src/ui/schema-form.ts +113 -70
  506. package/src/ui/surface.ts +71 -8
  507. package/src/ui/timing.ts +9 -0
  508. package/src/ui/value-source.ts +44 -31
  509. package/src/ui/virtual-window.ts +3 -2
  510. package/src/utils/base64.ts +3 -1
  511. package/src/utils/edit-display.ts +103 -74
  512. package/src/utils/element-selectors.ts +3 -2
  513. package/src/utils/google-fonts.ts +15 -14
  514. package/src/utils/inherited-style.ts +18 -20
  515. package/src/utils/link-target.ts +1 -1
  516. package/src/utils/preview-format.ts +25 -3
  517. package/src/utils/strip-events.ts +49 -22
  518. package/src/utils/studio-utils.ts +29 -14
  519. package/src/view.ts +2 -3
  520. package/src/workspace/pane-derive.ts +10 -12
  521. package/src/workspace/session.ts +53 -43
  522. package/src/workspace/workspace.ts +47 -36
  523. package/dist/chunks/2020-nkxms0ay.js +0 -4
  524. package/dist/chunks/adapter-m948ab5f.js +0 -4
  525. package/dist/chunks/cf-account-picker-n8hr38v7.js +0 -4
  526. package/dist/chunks/cf-settings-356xdtne.js +0 -4
  527. package/dist/chunks/color-area-jqhna8zy.js +0 -4
  528. package/dist/chunks/color-field-embq5ctg.js +0 -4
  529. package/dist/chunks/color-fpezvnkt.js +0 -4
  530. package/dist/chunks/color-slider-1qmw7wqy.js +0 -4
  531. package/dist/chunks/combobox-773hdzyj.js +0 -4
  532. package/dist/chunks/components-yk3t844e.js +0 -4
  533. package/dist/chunks/content-source-bawmyc09.js +0 -4
  534. package/dist/chunks/convert-to-repeater-7wns8kf1.js +0 -4
  535. package/dist/chunks/dialog-mtm9fq5t.js +0 -4
  536. package/dist/chunks/editor-6sc8nacq.js +0 -4
  537. package/dist/chunks/entry-commands-8ay9fh81.js +0 -4
  538. package/dist/chunks/extension-sections-na7rj3nr.js +0 -4
  539. package/dist/chunks/file-ops-gye0qw56.js +0 -4
  540. package/dist/chunks/files-dmc2xvcq.js +0 -4
  541. package/dist/chunks/format-host-t76b53f8.js +0 -4
  542. package/dist/chunks/fs-events-cg4tpz06.js +0 -4
  543. package/dist/chunks/git-panel-yef7bshy.js +0 -4
  544. package/dist/chunks/grid-view-7tt4bxw1.js +0 -51
  545. package/dist/chunks/icons-qbh8akb1.js +0 -4
  546. package/dist/chunks/iframe-entry-f7mqjwpm.js +0 -5
  547. package/dist/chunks/iframe-entry-haw7jkvz.js +0 -5
  548. package/dist/chunks/iframe-entry-z6qrytv3.js +0 -5
  549. package/dist/chunks/iframe-host-tmz30gfp.js +0 -4
  550. package/dist/chunks/index-nag78a9h.js +0 -4
  551. package/dist/chunks/jsonMode-zhwsprqk.js +0 -13
  552. package/dist/chunks/jx-validate-3gbp5nkn.js +0 -4
  553. package/dist/chunks/layers-fvz99859.js +0 -4
  554. package/dist/chunks/layers-panel-gchmbf9p.js +0 -4
  555. package/dist/chunks/listbox-s8fkmnq8.js +0 -4
  556. package/dist/chunks/lit-html-9agdspkt.js +0 -4
  557. package/dist/chunks/media-picker-rhjvyy00.js +0 -4
  558. package/dist/chunks/menu-2e4y9j7b.js +0 -4
  559. package/dist/chunks/menu-37d07z9m.js +0 -4
  560. package/dist/chunks/monaco-binding-2jnhjjvr.js +0 -4
  561. package/dist/chunks/monaco-buffer-rp21359g.js +0 -4
  562. package/dist/chunks/monaco-setup-vhh7gayr.js +0 -4
  563. package/dist/chunks/notify-h3www560.js +0 -4
  564. package/dist/chunks/number-field-gw7sq8rn.js +0 -4
  565. package/dist/chunks/parse-897fvqah.js +0 -4
  566. package/dist/chunks/platform-hz34wcd7.js +0 -4
  567. package/dist/chunks/popover-8htra4er.js +0 -4
  568. package/dist/chunks/publish-panel-exsmjzyj.js +0 -4
  569. package/dist/chunks/quick-search-pgaqeh0m.js +0 -4
  570. package/dist/chunks/references-2cgdxnb8.js +0 -4
  571. package/dist/chunks/right-panel-jf856w5w.js +0 -4
  572. package/dist/chunks/section-registry-jnf8r5gy.js +0 -4
  573. package/dist/chunks/select-n3v7gwas.js +0 -4
  574. package/dist/chunks/split-pff8f3ze.js +0 -4
  575. package/dist/chunks/studio-0f55h9ye.js +0 -5
  576. package/dist/chunks/studio-0sqdhnew.js +0 -12
  577. package/dist/chunks/studio-19x1c75w.js +0 -5
  578. package/dist/chunks/studio-2sqcndak.js +0 -5
  579. package/dist/chunks/studio-3aey7dd3.js +0 -5
  580. package/dist/chunks/studio-3bpdkq2s.js +0 -5
  581. package/dist/chunks/studio-47y6fbpf.js +0 -5
  582. package/dist/chunks/studio-4m3826v2.js +0 -5
  583. package/dist/chunks/studio-4nx2dj1g.js +0 -4
  584. package/dist/chunks/studio-4xv5s47r.js +0 -9
  585. package/dist/chunks/studio-5g4t8v6w.js +0 -5
  586. package/dist/chunks/studio-5py436sf.js +0 -5
  587. package/dist/chunks/studio-77kt594t.js +0 -5
  588. package/dist/chunks/studio-8f87n763.js +0 -10
  589. package/dist/chunks/studio-8mb00b84.js +0 -5
  590. package/dist/chunks/studio-8p51gq2h.js +0 -6
  591. package/dist/chunks/studio-954ds834.js +0 -5
  592. package/dist/chunks/studio-9ft45c83.js +0 -9
  593. package/dist/chunks/studio-a2138x5k.js +0 -7
  594. package/dist/chunks/studio-a9yzstqj.js +0 -5
  595. package/dist/chunks/studio-acdksxx6.js +0 -5
  596. package/dist/chunks/studio-ar8jcf2y.js +0 -5
  597. package/dist/chunks/studio-bmn4mn9j.js +0 -7
  598. package/dist/chunks/studio-e7xxa0sj.js +0 -5
  599. package/dist/chunks/studio-ecaz25vk.js +0 -5
  600. package/dist/chunks/studio-ery42sqr.js +0 -4
  601. package/dist/chunks/studio-fzdywr6p.js +0 -9
  602. package/dist/chunks/studio-g5fmf0c1.js +0 -5
  603. package/dist/chunks/studio-g7nse7zb.js +0 -5
  604. package/dist/chunks/studio-geq1ea6k.js +0 -14
  605. package/dist/chunks/studio-ghkb32r8.js +0 -5
  606. package/dist/chunks/studio-ghrhy2y7.js +0 -5
  607. package/dist/chunks/studio-grawhey1.js +0 -5
  608. package/dist/chunks/studio-h0xgswew.js +0 -5
  609. package/dist/chunks/studio-h9c4p2tx.js +0 -5
  610. package/dist/chunks/studio-jyzj5cxs.js +0 -5
  611. package/dist/chunks/studio-mgx8yhnz.js +0 -64
  612. package/dist/chunks/studio-mpb04y1d.js +0 -6
  613. package/dist/chunks/studio-n17mty64.js +0 -5
  614. package/dist/chunks/studio-nwh2eqsk.js +0 -6
  615. package/dist/chunks/studio-q1h883bt.js +0 -16
  616. package/dist/chunks/studio-q4tv82h7.js +0 -9
  617. package/dist/chunks/studio-qpqa7vk3.js +0 -5
  618. package/dist/chunks/studio-qqz8e5gk.js +0 -5
  619. package/dist/chunks/studio-qvasen3f.js +0 -5
  620. package/dist/chunks/studio-rggdb3hm.js +0 -5
  621. package/dist/chunks/studio-sghy936h.js +0 -4
  622. package/dist/chunks/studio-skprc6ef.js +0 -5
  623. package/dist/chunks/studio-tt2nactf.js +0 -5
  624. package/dist/chunks/studio-tyasmc39.js +0 -5
  625. package/dist/chunks/studio-vk9ezads.js +0 -5
  626. package/dist/chunks/studio-vzacdfsc.js +0 -4
  627. package/dist/chunks/studio-w4c0xmrw.js +0 -5
  628. package/dist/chunks/studio-wfjqhhbk.js +0 -5
  629. package/dist/chunks/studio-wgh5kxpj.js +0 -5
  630. package/dist/chunks/studio-xasj0796.js +0 -5
  631. package/dist/chunks/studio-y78s8r2n.js +0 -5
  632. package/dist/chunks/studio-z8w183sh.js +0 -5
  633. package/dist/chunks/studio-zscd9ty4.js +0 -928
  634. package/dist/chunks/studio-zxp13sss.js +0 -7
  635. package/dist/chunks/studio-zygnmm01.js +0 -5
  636. package/dist/chunks/swatch-group-8qh9a3bm.js +0 -4
  637. package/dist/chunks/tabs-jwthg40w.js +0 -4
  638. package/dist/chunks/textfield-spy3hc77.js +0 -4
  639. package/dist/chunks/toast-4d35zd64.js +0 -4
  640. package/dist/chunks/toast-host-8sjmfed3.js +0 -4
  641. package/dist/chunks/tooltip-fd6g9xy3.js +0 -4
  642. package/dist/chunks/tree-h19v1jfz.js +0 -4
  643. package/dist/chunks/tsMode-gr0m4dzr.js +0 -14
  644. package/dist/chunks/workspace-m15qtcqp.js +0 -4
  645. package/dist/chunks/ws-client-nf61frr1.js +0 -4
@@ -27,26 +27,55 @@
27
27
  * this — an id outside a declared set — and one refusal shape is easier to catch than two.
28
28
  */
29
29
 
30
+ import { isBoolean, isNonNullObject, isNumber, isString } from "@jxsuite/schema/guards";
31
+ import type { JsonValue } from "@jxsuite/schema/types";
32
+
33
+ /**
34
+ * One received argument: a JSON value, or `undefined` for a key a caller left out. Every surface
35
+ * that sends arguments speaks JSON (a palette prompt, a manifest step, an AI tool call), and an
36
+ * explicit `undefined` is how a programmatic caller spells "absent" — JSON cannot carry one.
37
+ */
38
+ export type CommandArgValue = JsonValue | undefined;
39
+
30
40
  /** Arguments as they arrive from a palette prompt, a manifest step or an AI tool call. */
31
- export type CommandArgValues = Record<string, unknown>;
41
+ export type CommandArgValues = Record<string, CommandArgValue>;
32
42
 
33
43
  /** `command "<id>" argument "<key>": <problem>` — the one sentence shape every failure here uses. */
34
44
  function refuse(commandId: string, key: string, problem: string): RangeError {
35
45
  return new RangeError(`command "${commandId}" argument "${key}": ${problem}`);
36
46
  }
37
47
 
48
+ /**
49
+ * The `typeof` word for a non-string JSON value, as every refusal sentence has always printed it:
50
+ * `null`, arrays and objects are all `object` to `typeof`, so they are all `object` here.
51
+ */
52
+ function typeWordOf(value: JsonValue): string {
53
+ if (isNumber(value)) {
54
+ return "number";
55
+ }
56
+ if (isBoolean(value)) {
57
+ return "boolean";
58
+ }
59
+ return isString(value) ? "string" : "object";
60
+ }
61
+
38
62
  /** How a received value is quoted back to the caller. Strings keep their quotes; nothing is elided. */
39
- function describe(value: unknown): string {
63
+ function describe(value: CommandArgValue): string {
40
64
  if (value === undefined) {
41
65
  return "missing";
42
66
  }
43
- return typeof value === "string" ? `"${value}"` : `${typeof value} ${JSON.stringify(value)}`;
67
+ return isString(value) ? `"${value}"` : `${typeWordOf(value)} ${JSON.stringify(value)}`;
68
+ }
69
+
70
+ /** Whether a value is a `JxPath`: an array whose every segment is a string key or a numeric index. */
71
+ function isPathSegments(value: CommandArgValue): value is (string | number)[] {
72
+ return Array.isArray(value) && value.every((segment) => isString(segment) || isNumber(segment));
44
73
  }
45
74
 
46
75
  /** A required string argument. */
47
76
  export function stringArg(commandId: string, args: CommandArgValues, key: string): string {
48
77
  const value = args[key];
49
- if (typeof value !== "string" || value === "") {
78
+ if (!isString(value) || value === "") {
50
79
  throw refuse(commandId, key, `expected a non-empty string, got ${describe(value)}`);
51
80
  }
52
81
  return value;
@@ -67,7 +96,7 @@ export function optionalStringArg(
67
96
  /** A required finite number argument. `NaN` and `Infinity` are refusals, not values. */
68
97
  export function numberArg(commandId: string, args: CommandArgValues, key: string): number {
69
98
  const value = args[key];
70
- if (typeof value !== "number" || !Number.isFinite(value)) {
99
+ if (!isNumber(value) || !Number.isFinite(value)) {
71
100
  throw refuse(commandId, key, `expected a finite number, got ${describe(value)}`);
72
101
  }
73
102
  return value;
@@ -84,7 +113,7 @@ export function numberArg(commandId: string, args: CommandArgValues, key: string
84
113
  */
85
114
  export function integerArg(commandId: string, args: CommandArgValues, key: string): number {
86
115
  const value = args[key];
87
- if (typeof value !== "number" || !Number.isInteger(value)) {
116
+ if (!isNumber(value) || !Number.isInteger(value)) {
88
117
  throw refuse(commandId, key, `expected an integer, got ${describe(value)}`);
89
118
  }
90
119
  return value;
@@ -116,7 +145,7 @@ export function boundedNumberArg(
116
145
  /** A required boolean argument. A setter's whole point is that `false` is a value, so no default. */
117
146
  export function booleanArg(commandId: string, args: CommandArgValues, key: string): boolean {
118
147
  const value = args[key];
119
- if (typeof value !== "boolean") {
148
+ if (!isBoolean(value)) {
120
149
  throw refuse(commandId, key, `expected a boolean, got ${describe(value)}`);
121
150
  }
122
151
  return value;
@@ -136,7 +165,9 @@ export function enumArg<T extends string>(
136
165
  declared: readonly T[],
137
166
  ): T {
138
167
  const value = args[key];
139
- if (typeof value !== "string" || !(declared as readonly string[]).includes(value)) {
168
+ // `find` hands back the DECLARED entry, typed `T`, which is the same string the caller sent.
169
+ const match = isString(value) ? declared.find((entry) => entry === value) : undefined;
170
+ if (match === undefined) {
140
171
  // `none` for an empty set: a derived enum (`derivedEnumProperty`) is honestly empty before the
141
172
  // Project supplies its values, and "declared: " with nothing after it reads as a truncation.
142
173
  throw refuse(
@@ -145,7 +176,7 @@ export function enumArg<T extends string>(
145
176
  `${describe(value)} is not declared — declared: ${declared.join(", ") || "none"}`,
146
177
  );
147
178
  }
148
- return value as T;
179
+ return match;
149
180
  }
150
181
 
151
182
  /**
@@ -160,17 +191,14 @@ export function pathArg(
160
191
  key: string,
161
192
  ): (string | number)[] {
162
193
  const value = args[key];
163
- if (
164
- !Array.isArray(value) ||
165
- !value.every((s) => typeof s === "string" || typeof s === "number")
166
- ) {
194
+ if (!isPathSegments(value)) {
167
195
  throw refuse(
168
196
  commandId,
169
197
  key,
170
198
  `expected an array of path segments (strings or numbers), got ${describe(value)}`,
171
199
  );
172
200
  }
173
- return value as (string | number)[];
201
+ return value;
174
202
  }
175
203
 
176
204
  /** A path argument that may be `null` — "select nothing" is a state a user can be in. */
@@ -203,17 +231,14 @@ export function pathListArg(
203
231
  throw refuse(commandId, key, `expected an array of document paths, got ${describe(value)}`);
204
232
  }
205
233
  return value.map((entry, i) => {
206
- if (
207
- !Array.isArray(entry) ||
208
- !entry.every((s) => typeof s === "string" || typeof s === "number")
209
- ) {
234
+ if (!isPathSegments(entry)) {
210
235
  throw refuse(
211
236
  commandId,
212
237
  key,
213
238
  `entry ${i} is not a document path — expected an array of segments, got ${describe(entry)}`,
214
239
  );
215
240
  }
216
- return entry as (string | number)[];
241
+ return entry;
217
242
  });
218
243
  }
219
244
 
@@ -224,11 +249,39 @@ export function pathListArg(
224
249
  // Them ONE call site, so a schema that disagrees with its coercion is now a refusal rather than a
225
250
  // Defect a reviewer has to spot — which is what this module exists to prevent.
226
251
 
252
+ /**
253
+ * The JSON Schema keywords a command property uses — what the builders below write and what
254
+ * {@link coerceArgs} reads. Read loosely: a keyword with no reader (`description`, `default`) is
255
+ * carried for the palette and the AI tool, and never consulted by the coercion.
256
+ */
257
+ export interface PropertySchema {
258
+ description?: string;
259
+ title?: string;
260
+ default?: JsonValue;
261
+ type?: string | readonly string[];
262
+ /** Strings only: the `enum` row is {@link enumArg}, which admits nothing but a declared string. */
263
+ enum?: readonly string[];
264
+ const?: JsonValue;
265
+ oneOf?: readonly PropertySchema[];
266
+ items?: PropertySchema;
267
+ minimum?: number;
268
+ maximum?: number;
269
+ }
270
+
271
+ /** The object schema {@link argsSchema} writes, as {@link coerceArgs} reads it. */
272
+ export interface CommandArgsSchema {
273
+ additionalProperties?: boolean;
274
+ properties?: Record<string, PropertySchema>;
275
+ required?: readonly string[];
276
+ /** Always `"object"` as {@link argsSchema} writes it; the coercion never reads it. */
277
+ type?: string;
278
+ }
279
+
227
280
  /** `{ type: "object", properties, required, additionalProperties: false }` in one call. */
228
281
  export function argsSchema(
229
- properties: Record<string, object>,
282
+ properties: Record<string, PropertySchema>,
230
283
  required: readonly string[] = Object.keys(properties),
231
- ): object {
284
+ ): CommandArgsSchema {
232
285
  return {
233
286
  additionalProperties: false,
234
287
  properties,
@@ -238,7 +291,7 @@ export function argsSchema(
238
291
  }
239
292
 
240
293
  /** A string property constrained to a declared set, with the human sentence the palette shows. */
241
- export function enumProperty(declared: readonly string[], description: string): object {
294
+ export function enumProperty(declared: readonly string[], description: string): PropertySchema {
242
295
  return { description, enum: [...declared], type: "string" };
243
296
  }
244
297
 
@@ -261,7 +314,7 @@ export function enumProperty(declared: readonly string[], description: string):
261
314
  export function derivedEnumProperty(
262
315
  declared: () => readonly string[],
263
316
  description: string,
264
- ): object {
317
+ ): PropertySchema {
265
318
  return {
266
319
  description,
267
320
  get enum() {
@@ -275,17 +328,17 @@ export function derivedEnumProperty(
275
328
  export function numberProperty(
276
329
  description: string,
277
330
  bounds: { minimum?: number; maximum?: number } = {},
278
- ): object {
331
+ ): PropertySchema {
279
332
  return { description, type: "number", ...bounds };
280
333
  }
281
334
 
282
335
  /** A boolean property. Named `open`/`enabled`/… by the caller; the description carries the sense. */
283
- export function booleanProperty(description: string): object {
336
+ export function booleanProperty(description: string): PropertySchema {
284
337
  return { description, type: "boolean" };
285
338
  }
286
339
 
287
340
  /** A `JxPath` property — an array of string keys and numeric indexes. */
288
- export function pathProperty(description: string, nullable = false): object {
341
+ export function pathProperty(description: string, nullable = false): PropertySchema {
289
342
  const path = {
290
343
  items: { type: ["string", "number"] },
291
344
  type: "array",
@@ -294,7 +347,7 @@ export function pathProperty(description: string, nullable = false): object {
294
347
  }
295
348
 
296
349
  /** A property holding a LIST of `JxPath`s — an array of arrays of segments. */
297
- export function pathListProperty(description: string): object {
350
+ export function pathListProperty(description: string): PropertySchema {
298
351
  return {
299
352
  description,
300
353
  items: { items: { type: ["string", "number"] }, type: "array" },
@@ -303,7 +356,7 @@ export function pathListProperty(description: string): object {
303
356
  }
304
357
 
305
358
  /** A free-form string property. */
306
- export function stringProperty(description: string): object {
359
+ export function stringProperty(description: string): PropertySchema {
307
360
  return { description, type: "string" };
308
361
  }
309
362
 
@@ -314,24 +367,6 @@ export function stringProperty(description: string): object {
314
367
  // Validator that agrees with them today. What the schema cannot say (a breakpoint the document
315
368
  // Defines, a path that addresses a node) stays in `run`; the schema owns the shape.
316
369
 
317
- /** The JSON Schema keywords a command property uses. Read loosely; unknown keywords are ignored. */
318
- interface PropertySchema {
319
- type?: string | readonly string[];
320
- enum?: readonly unknown[];
321
- const?: unknown;
322
- oneOf?: readonly PropertySchema[];
323
- items?: PropertySchema;
324
- minimum?: number;
325
- maximum?: number;
326
- }
327
-
328
- /** The object schema `argsSchema` writes, as {@link coerceArgs} reads it. */
329
- interface ArgsSchemaShape {
330
- properties?: Record<string, PropertySchema>;
331
- required?: readonly string[];
332
- additionalProperties?: boolean;
333
- }
334
-
335
370
  /**
336
371
  * The rows of {@link coerceArgs}'s dispatch table, by name.
337
372
  *
@@ -361,7 +396,7 @@ function isPathSegmentTypes(types: readonly string[]): boolean {
361
396
 
362
397
  /** A single JSON type name, or the list form `["number", "null"]`, as a list. */
363
398
  function typesOf(type: string | readonly string[]): readonly string[] {
364
- return Array.isArray(type) ? type : [type as string];
399
+ return isString(type) ? [type] : type;
365
400
  }
366
401
 
367
402
  /**
@@ -371,8 +406,8 @@ function typesOf(type: string | readonly string[]): readonly string[] {
371
406
  * getter, and this function only classifies. The getter is read by the `enum` row when the value is
372
407
  * coerced, which is what makes the list live at that moment rather than at classification.
373
408
  */
374
- export function describeShape(property: object): CoercionRow {
375
- const p = property as PropertySchema;
409
+ export function coercionRowOf(property: PropertySchema): CoercionRow {
410
+ const p = property;
376
411
  if ("enum" in p) {
377
412
  return "enum";
378
413
  }
@@ -427,28 +462,28 @@ export function describeShape(property: object): CoercionRow {
427
462
  }
428
463
 
429
464
  /** Whether a value is of one JSON type. `number` means FINITE, as {@link numberArg} already insists. */
430
- function isJsonType(type: string, value: unknown): boolean {
465
+ function isJsonType(type: string, value: CommandArgValue): boolean {
431
466
  switch (type) {
432
467
  case "null": {
433
468
  return value === null;
434
469
  }
435
470
  case "boolean": {
436
- return typeof value === "boolean";
471
+ return isBoolean(value);
437
472
  }
438
473
  case "string": {
439
- return typeof value === "string";
474
+ return isString(value);
440
475
  }
441
476
  case "number": {
442
- return typeof value === "number" && Number.isFinite(value);
477
+ return isNumber(value) && Number.isFinite(value);
443
478
  }
444
479
  case "integer": {
445
- return typeof value === "number" && Number.isInteger(value);
480
+ return isNumber(value) && Number.isInteger(value);
446
481
  }
447
482
  case "array": {
448
483
  return Array.isArray(value);
449
484
  }
450
485
  case "object": {
451
- return typeof value === "object" && value !== null && !Array.isArray(value);
486
+ return isNonNullObject(value) && !Array.isArray(value);
452
487
  }
453
488
  default: {
454
489
  break;
@@ -478,17 +513,18 @@ export function typedArg(
478
513
  args: CommandArgValues,
479
514
  key: string,
480
515
  types: readonly string[],
481
- ): unknown {
516
+ ): JsonValue {
482
517
  const value = args[key];
483
- if (!types.some((type) => isJsonType(type, value))) {
518
+ // `undefined` is admitted by no JSON type, so the first test only states what the second proves.
519
+ if (value === undefined || !types.some((type) => isJsonType(type, value))) {
484
520
  throw refuse(commandId, key, `expected ${listTypes(types)}, got ${describe(value)}`);
485
521
  }
486
522
  return value;
487
523
  }
488
524
 
489
525
  /** One line per row, for the sentence a `oneOf` refusal prints when no branch admits the value. */
490
- function shapeOf(property: PropertySchema): string {
491
- switch (describeShape(property)) {
526
+ function expectedValueText(property: PropertySchema): string {
527
+ switch (coercionRowOf(property)) {
492
528
  case "enum": {
493
529
  return `one of ${(property.enum ?? []).map((v) => describe(v)).join(" | ")}`;
494
530
  }
@@ -496,7 +532,7 @@ function shapeOf(property: PropertySchema): string {
496
532
  return `the constant ${describe(property.const)}`;
497
533
  }
498
534
  case "one-of": {
499
- return (property.oneOf ?? []).map((branch) => shapeOf(branch)).join(" or ");
535
+ return (property.oneOf ?? []).map((branch) => expectedValueText(branch)).join(" or ");
500
536
  }
501
537
  case "typed": {
502
538
  return listTypes(typesOf(property.type ?? []));
@@ -545,7 +581,7 @@ function oneOfArg(
545
581
  args: CommandArgValues,
546
582
  key: string,
547
583
  branches: readonly PropertySchema[],
548
- ): unknown {
584
+ ): CommandArgValue {
549
585
  const value = args[key];
550
586
  const refusals: unknown[] = [];
551
587
  for (const branch of branches) {
@@ -567,7 +603,7 @@ function oneOfArg(
567
603
  throw refuse(
568
604
  commandId,
569
605
  key,
570
- `expected ${branches.map((branch) => shapeOf(branch)).join(" or ")}, got ${describe(value)}`,
606
+ `expected ${branches.map((branch) => expectedValueText(branch)).join(" or ")}, got ${describe(value)}`,
571
607
  );
572
608
  }
573
609
 
@@ -577,11 +613,11 @@ function coerceProperty(
577
613
  args: CommandArgValues,
578
614
  key: string,
579
615
  property: PropertySchema,
580
- ): unknown {
581
- switch (describeShape(property)) {
616
+ ): CommandArgValue {
617
+ switch (coercionRowOf(property)) {
582
618
  case "enum": {
583
619
  // The read of `property.enum` is HERE — a derived list is resolved at coercion time.
584
- return enumArg(commandId, args, key, (property.enum ?? []) as readonly string[]);
620
+ return enumArg(commandId, args, key, property.enum ?? []);
585
621
  }
586
622
  case "const": {
587
623
  const value = args[key];
@@ -652,12 +688,8 @@ function coerceProperty(
652
688
  * `run` body keeps its own `stringArg(...)` lines as typed readers and can never disagree with this
653
689
  * pass, because they are the same functions reading the same values.
654
690
  */
655
- export function coerceArgs(
656
- commandId: string,
657
- schema: object,
658
- args: CommandArgValues,
659
- ): CommandArgValues {
660
- const spec = schema as ArgsSchemaShape;
691
+ export function coerceArgs(commandId: string, schema: CommandArgsSchema, args: CommandArgValues) {
692
+ const spec = schema;
661
693
  const properties = spec.properties ?? {};
662
694
  const declared = Object.keys(properties);
663
695
  const required = spec.required ?? [];
@@ -81,28 +81,28 @@ export type CanvasView = "edit" | "design" | "preview";
81
81
  */
82
82
 
83
83
  /** The `canvasMode` strings, mapped onto the editor each one actually names. */
84
- const EDITOR_KIND_BY_MODE: Readonly<Record<string, EditorKind>> = {
85
- design: "canvas",
86
- edit: "canvas",
84
+ const EDITOR_KIND_BY_MODE = new Map<string, EditorKind>([
85
+ ["design", "canvas"],
86
+ ["edit", "canvas"],
87
87
  /* The Entry editor — `content/entry-editor.ts`'s ENTRY_MODE. A form over ONE content entry's
88
88
  frontmatter, typed by its collection's schema; the same document the canvas edits the body of,
89
89
  which is why it is a mode of that tab rather than a tab of its own. */
90
- entry: "entry",
91
- "git-diff": "diff",
92
- grid: "grid",
93
- manage: "library",
90
+ ["entry", "entry"],
91
+ ["git-diff", "diff"],
92
+ ["grid", "grid"],
93
+ ["manage", "library"],
94
94
  /* The Media viewer — `media/media-pane.ts`. An image, a video, a font specimen: files the studio
95
95
  can SHOW but has no document model for, which is why clicking one used to end in "No format
96
96
  class imported for …", advice that means nothing about a PNG. */
97
- media: "media",
98
- preview: "canvas",
97
+ ["media", "media"],
98
+ ["preview", "canvas"],
99
99
  /* Project Settings — `settings/settings-document.ts`'s SETTINGS_MODE. A form over `project.json`,
100
100
  which is a configuration object and not a document tree; `stylebook` (Project Styles) is the
101
101
  second editor over that same document and answers `config` for the same reason. */
102
- settings: "config",
103
- source: "code",
104
- stylebook: "config",
105
- };
102
+ ["settings", "config"],
103
+ ["source", "code"],
104
+ ["stylebook", "config"],
105
+ ]);
106
106
 
107
107
  /**
108
108
  * The editor kind a mode string names.
@@ -131,15 +131,15 @@ export const EDITOR_KIND_LABELS: Readonly<Record<EditorKind, string>> = {
131
131
  };
132
132
 
133
133
  export function editorKindForMode(mode: string): EditorKind {
134
- return EDITOR_KIND_BY_MODE[mode] ?? "canvas";
134
+ return EDITOR_KIND_BY_MODE.get(mode) ?? "canvas";
135
135
  }
136
136
 
137
137
  /** Only the three canvas modes carry a view. */
138
- const CANVAS_VIEW_BY_MODE: Readonly<Record<string, CanvasView>> = {
139
- design: "design",
140
- edit: "edit",
141
- preview: "preview",
142
- };
138
+ const CANVAS_VIEW_BY_MODE = new Map<string, CanvasView>([
139
+ ["design", "design"],
140
+ ["edit", "edit"],
141
+ ["preview", "preview"],
142
+ ]);
143
143
 
144
144
  /**
145
145
  * The Canvas view a mode names — the neutral "design" for a mode that has none.
@@ -147,7 +147,7 @@ const CANVAS_VIEW_BY_MODE: Readonly<Record<string, CanvasView>> = {
147
147
  * Meaningful only where {@link editorKindForMode} answers `"canvas"`; every reader pairs the two.
148
148
  */
149
149
  export function canvasViewForMode(mode: string): CanvasView {
150
- return CANVAS_VIEW_BY_MODE[mode] ?? "design";
150
+ return CANVAS_VIEW_BY_MODE.get(mode) ?? "design";
151
151
  }
152
152
 
153
153
  /** Facts a command may be gated on. Every field is a plain value; predicates read, never write. */
@@ -332,6 +332,8 @@ export function emptyContext(): CommandContext {
332
332
  */
333
333
  export function makeContext(patch: CommandContextPatch = {}): CommandContext {
334
334
  const base = emptyContext();
335
+ /* SAFETY: a `CommandContextPatch` is a mapped type over `keyof CommandContext`, so every own key
336
+ it carries is a context group; `Object.keys` only widens those names to `string`. */
335
337
  for (const key of Object.keys(patch) as (keyof CommandContext)[]) {
336
338
  const group = patch[key];
337
339
  if (group) {
@@ -236,7 +236,10 @@ export function defaultCommands(deps: CommandDeps): AnyCommand[] {
236
236
  group: "1_file",
237
237
  undo: "none",
238
238
  when: documentOpen,
239
- requires: "an open document",
239
+ // Nothing to save is a disabled button, not a no-op one. A disabled chord is still claimed,
240
+ // So ⌘S on a clean document never falls through to the browser's own Save Page.
241
+ enablement: (ctx) => ctx.document.dirty,
242
+ requires: "unsaved changes",
240
243
  run: () => deps.saveDocument(),
241
244
  },
242
245
  {
@@ -27,6 +27,7 @@
27
27
  * colliding still throws, because that one is a bug in the app and nobody's preference.
28
28
  */
29
29
 
30
+ import { isString } from "@jxsuite/schema/guards";
30
31
  import { KEY_SCOPES } from "./levels";
31
32
  import type { KeyScope } from "./levels";
32
33
 
@@ -36,33 +37,33 @@ const MODIFIER_ORDER = ["mod", "ctrl", "alt", "shift"] as const;
36
37
  type Modifier = (typeof MODIFIER_ORDER)[number];
37
38
 
38
39
  /** Spellings people actually write, mapped onto the canonical four. */
39
- const MODIFIER_ALIASES: Readonly<Record<string, Modifier>> = {
40
- mod: "mod",
41
- cmd: "mod",
42
- command: "mod",
43
- meta: "mod",
44
- super: "mod",
45
- ctrl: "ctrl",
46
- control: "ctrl",
47
- alt: "alt",
48
- opt: "alt",
49
- option: "alt",
50
- shift: "shift",
51
- };
40
+ const MODIFIER_ALIASES = new Map<string, Modifier>([
41
+ ["mod", "mod"],
42
+ ["cmd", "mod"],
43
+ ["command", "mod"],
44
+ ["meta", "mod"],
45
+ ["super", "mod"],
46
+ ["ctrl", "ctrl"],
47
+ ["control", "ctrl"],
48
+ ["alt", "alt"],
49
+ ["opt", "alt"],
50
+ ["option", "alt"],
51
+ ["shift", "shift"],
52
+ ]);
52
53
 
53
54
  /** Key aliases — arrow/space spellings and the `KeyboardEvent.key` values that differ. */
54
- const KEY_ALIASES: Readonly<Record<string, string>> = {
55
- up: "arrowup",
56
- down: "arrowdown",
57
- left: "arrowleft",
58
- right: "arrowright",
59
- esc: "escape",
60
- space: " ",
61
- spacebar: " ",
62
- del: "delete",
63
- plus: "=",
64
- return: "enter",
65
- };
55
+ const KEY_ALIASES = new Map<string, string>([
56
+ ["up", "arrowup"],
57
+ ["down", "arrowdown"],
58
+ ["left", "arrowleft"],
59
+ ["right", "arrowright"],
60
+ ["esc", "escape"],
61
+ ["space", " "],
62
+ ["spacebar", " "],
63
+ ["del", "delete"],
64
+ ["plus", "="],
65
+ ["return", "enter"],
66
+ ]);
66
67
 
67
68
  /** How each modifier prints, per platform. */
68
69
  const MAC_GLYPHS: Readonly<Record<Modifier, string>> = {
@@ -80,18 +81,18 @@ const PC_LABELS: Readonly<Record<Modifier, string>> = {
80
81
  };
81
82
 
82
83
  /** Keys whose printed name is not just the uppercased token. */
83
- const KEY_LABELS: Readonly<Record<string, string>> = {
84
- arrowup: "↑",
85
- arrowdown: "↓",
86
- arrowleft: "←",
87
- arrowright: "→",
88
- " ": "Space",
89
- escape: "Esc",
90
- enter: "Enter",
91
- tab: "Tab",
92
- delete: "Delete",
93
- backspace: "Backspace",
94
- };
84
+ const KEY_LABELS = new Map<string, string>([
85
+ ["arrowup", "↑"],
86
+ ["arrowdown", "↓"],
87
+ ["arrowleft", "←"],
88
+ ["arrowright", "→"],
89
+ [" ", "Space"],
90
+ ["escape", "Esc"],
91
+ ["enter", "Enter"],
92
+ ["tab", "Tab"],
93
+ ["delete", "Delete"],
94
+ ["backspace", "Backspace"],
95
+ ]);
95
96
 
96
97
  /**
97
98
  * The five fields the keymap reads off a keyboard event.
@@ -159,12 +160,12 @@ export function parseChord(chord: string): ParsedChord {
159
160
  // Parses the same as "Cmd+Shift+P".
160
161
  const trimmed = token.trim();
161
162
  const lower = trimmed === "" ? " " : trimmed.toLowerCase();
162
- const modifier = MODIFIER_ALIASES[lower];
163
+ const modifier = MODIFIER_ALIASES.get(lower);
163
164
  if (modifier) {
164
165
  parsed[modifier] = true;
165
166
  continue;
166
167
  }
167
- parsed.key = KEY_ALIASES[lower] ?? lower;
168
+ parsed.key = KEY_ALIASES.get(lower) ?? lower;
168
169
  }
169
170
  if (!parsed.key) {
170
171
  throw new Error(`keybinding "${chord}" has no key — a chord needs more than modifiers`);
@@ -185,6 +186,9 @@ export function normalizeChord(chord: string): string {
185
186
 
186
187
  /** Whether the current platform is a mac. `navigator` is injectable so tests never touch globals. */
187
188
  export function isMacPlatform(
189
+ /* SAFETY: this module types without the DOM lib, so `globalThis` does not declare `navigator`.
190
+ Where a host provides one (every webview, Bun), its `platform` and `userAgent` are strings,
191
+ which is all `PlatformInfo` reads; where none exists the `?? {}` default answers. */
188
192
  nav: PlatformInfo = (globalThis as { navigator?: PlatformInfo }).navigator ?? {},
189
193
  ): boolean {
190
194
  return /mac/i.test(nav.platform ?? nav.userAgent ?? "");
@@ -209,7 +213,7 @@ export function chordFromEvent(event: KeyChordEvent, mac: boolean): string {
209
213
  chord needs more than modifiers") — so every bare modifier press threw out of `resolveEvent`,
210
214
  into the keydown listener, and onto the console. `""` is the honest answer, and
211
215
  {@link Keymap.resolveEvent} reads it as "no chord yet". */
212
- if (MODIFIER_ALIASES[key]) {
216
+ if (MODIFIER_ALIASES.has(key)) {
213
217
  return "";
214
218
  }
215
219
  const parsed: ParsedChord = {
@@ -219,7 +223,7 @@ export function chordFromEvent(event: KeyChordEvent, mac: boolean): string {
219
223
  // Shift is implied by an uppercase letter but a chord table cannot rely on that: with ⇧ held
220
224
  // `e.key` is "Z" for ⌘⇧Z and "?" for ⇧/, so the flag is the only stable signal.
221
225
  shift: event.shiftKey,
222
- key: KEY_ALIASES[key] ?? key,
226
+ key: KEY_ALIASES.get(key) ?? key,
223
227
  };
224
228
  return serializeChord(parsed);
225
229
  }
@@ -229,7 +233,7 @@ export function formatChord(chord: string, mac: boolean): string {
229
233
  const parsed = parseChord(chord);
230
234
  const held = MODIFIER_ORDER.filter((modifier) => parsed[modifier]);
231
235
  const key =
232
- KEY_LABELS[parsed.key] ??
236
+ KEY_LABELS.get(parsed.key) ??
233
237
  (parsed.key.length === 1
234
238
  ? parsed.key.toUpperCase()
235
239
  : parsed.key.charAt(0).toUpperCase() + parsed.key.slice(1));
@@ -386,7 +390,7 @@ export function createKeymap(options: { mac?: boolean } = {}): Keymap {
386
390
  if (!raw) {
387
391
  return [];
388
392
  }
389
- return (typeof raw === "string" ? [raw] : [...raw]).map((chord) => normalizeChord(chord));
393
+ return (isString(raw) ? [raw] : [...raw]).map((chord) => normalizeChord(chord));
390
394
  }
391
395
 
392
396
  function tableFor(scope: KeyScope): Map<string, Claim> {