@jxsuite/studio 6.1.2 → 8.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 (522) hide show
  1. package/README.md +5 -5
  2. package/dist/chunks/2020-5wtzce5g.js +4 -0
  3. package/dist/chunks/adapter-5tphg7xe.js +4 -0
  4. package/dist/chunks/add-new-flow-psym14sn.js +4 -0
  5. package/dist/chunks/cf-account-picker-haqazq5r.js +4 -0
  6. package/dist/chunks/cf-settings-h2wrh6hq.js +4 -0
  7. package/dist/chunks/{color-area-0fj8a4ga.js → color-area-6rbra5dy.js} +2 -2
  8. package/dist/chunks/{color-field-xch8kx2g.js → color-field-gy56c94g.js} +3 -3
  9. package/dist/chunks/color-m7r1vk54.js +4 -0
  10. package/dist/chunks/{color-slider-jxd8v350.js → color-slider-sqqdyf6c.js} +2 -2
  11. package/dist/chunks/{combobox-p0efwjke.js → combobox-72h32ejk.js} +3 -3
  12. package/dist/chunks/components-r22xca09.js +4 -0
  13. package/dist/chunks/content-source-mmppmcyg.js +4 -0
  14. package/dist/chunks/convert-to-repeater-he70fc2b.js +4 -0
  15. package/dist/chunks/editor-ccd9jwsa.js +4 -0
  16. package/dist/chunks/entry-commands-6qxz9e8p.js +4 -0
  17. package/dist/chunks/extension-sections-0egb88dm.js +4 -0
  18. package/dist/chunks/file-ops-qnab36ek.js +4 -0
  19. package/dist/chunks/files-rcn56qvm.js +4 -0
  20. package/dist/chunks/format-host-yxz0kjjs.js +4 -0
  21. package/dist/chunks/fs-events-d1qxq4z4.js +4 -0
  22. package/dist/chunks/grid-open-4z1g062t.js +4 -0
  23. package/dist/chunks/{grid-view-d2wq9ezg.js → grid-view-qg1b5eqx.js} +25 -25
  24. package/dist/chunks/{icons-pnfz478q.js → icons-63bjtbs7.js} +2 -2
  25. package/dist/chunks/{iframe-entry-jdcktez8.js → iframe-entry-2zggzajv.js} +4 -4
  26. package/dist/chunks/{iframe-entry-zap785cw.js → iframe-entry-76j8vwwx.js} +4 -4
  27. package/dist/chunks/iframe-entry-99nr5zfb.js +5 -0
  28. package/dist/chunks/{iframe-entry-x0ygf2yr.js → iframe-entry-pkgmcgp0.js} +4 -4
  29. package/dist/chunks/iframe-host-ssv7kyj0.js +4 -0
  30. package/dist/chunks/{index-zpjmzqfk.js → index-32eqzv1k.js} +3 -3
  31. package/dist/chunks/index-f0jn7nnp.js +4 -0
  32. package/dist/chunks/{javascript-m54mnwp6.js → javascript-pjp734q4.js} +3 -3
  33. package/dist/chunks/jsonMode-njkvsa02.js +13 -0
  34. package/dist/chunks/jx-validate-ttasrbh7.js +4 -0
  35. package/dist/chunks/layers-bgyr11tr.js +4 -0
  36. package/dist/chunks/layers-panel-7ez66zeq.js +4 -0
  37. package/dist/chunks/{listbox-e74qjyq6.js → listbox-c421cf8c.js} +2 -2
  38. package/dist/chunks/lit-html-v9gh687x.js +4 -0
  39. package/dist/chunks/media-library-sq468wts.js +4 -0
  40. package/dist/chunks/media-picker-shfe59pt.js +4 -0
  41. package/dist/chunks/{menu-n6yzswmy.js → menu-bdpzbfvs.js} +2 -2
  42. package/dist/chunks/{monaco-binding-7gx83x3r.js → monaco-binding-vq1hgnn0.js} +3 -3
  43. package/dist/chunks/monaco-buffer-3afgwvbp.js +4 -0
  44. package/dist/chunks/monaco-setup-xrd2cbkp.js +4 -0
  45. package/dist/chunks/notify-kzrjr3fv.js +4 -0
  46. package/dist/chunks/parse-v77xtwv7.js +4 -0
  47. package/dist/chunks/platform-7v4rtd7m.js +4 -0
  48. package/dist/chunks/popover-b89sfej7.js +4 -0
  49. package/dist/chunks/publish-panel-2z9gw8ee.js +4 -0
  50. package/dist/chunks/publish-quick-qx2455cj.js +4 -0
  51. package/dist/chunks/publish-workspace-wrc1dgwx.js +4 -0
  52. package/dist/chunks/quick-search-n0t0eqxb.js +4 -0
  53. package/dist/chunks/references-9547rg5s.js +4 -0
  54. package/dist/chunks/right-panel-wsgnr9pn.js +4 -0
  55. package/dist/chunks/source-control-kwktr9y6.js +4 -0
  56. package/dist/chunks/{split-n2gfpm5m.js → split-c9zfdgxf.js} +2 -2
  57. package/dist/chunks/studio-03ct6yfv.js +9 -0
  58. package/dist/chunks/studio-07rcfje3.js +5 -0
  59. package/dist/chunks/studio-3e54qh39.js +7 -0
  60. package/dist/chunks/studio-3exxhz5g.js +5 -0
  61. package/dist/chunks/studio-3q40e3rj.js +5 -0
  62. package/dist/chunks/studio-3qeh9t0h.js +6 -0
  63. package/dist/chunks/studio-3qqjeep5.js +6 -0
  64. package/dist/chunks/studio-43sd2mam.js +4 -0
  65. package/dist/chunks/studio-4hp8pkyt.js +5 -0
  66. package/dist/chunks/studio-58xg6j2q.js +9 -0
  67. package/dist/chunks/studio-5g0rprdt.js +7 -0
  68. package/dist/chunks/{studio-2j1cb95x.js → studio-6m380wp7.js} +4 -4
  69. package/dist/chunks/studio-80jyh1xh.js +4 -0
  70. package/dist/chunks/studio-83mk4bgg.js +9 -0
  71. package/dist/chunks/{studio-v0jzqdjm.js → studio-881z1xrx.js} +4 -4
  72. package/dist/chunks/studio-8m0y2qe7.js +5 -0
  73. package/dist/chunks/{studio-d81xfh1g.js → studio-8tr6cfrc.js} +4 -4
  74. package/dist/chunks/studio-8vcvfs7r.js +6 -0
  75. package/dist/chunks/studio-9tmebf0s.js +5 -0
  76. package/dist/chunks/studio-a2bvaptz.js +5 -0
  77. package/dist/chunks/studio-b7y5mr30.js +5 -0
  78. package/dist/chunks/studio-bavb31r0.js +5 -0
  79. package/dist/chunks/{studio-dgz8d0c1.js → studio-bbe4c90a.js} +4 -4
  80. package/dist/chunks/studio-c05wdnt3.js +5 -0
  81. package/dist/chunks/studio-ccv2svc6.js +5 -0
  82. package/dist/chunks/studio-d5grtb9e.js +16 -0
  83. package/dist/chunks/studio-df0baea9.js +5 -0
  84. package/dist/chunks/studio-dgk4dqtx.js +7 -0
  85. package/dist/chunks/studio-e1g64q43.js +5 -0
  86. package/dist/chunks/studio-ed1hp6zf.js +6 -0
  87. package/dist/chunks/studio-ed3xx40h.js +7 -0
  88. package/dist/chunks/studio-f14e1zdj.js +5 -0
  89. package/dist/chunks/studio-fbhxxc5f.js +5 -0
  90. package/dist/chunks/studio-fyh0jc96.js +5 -0
  91. package/dist/chunks/studio-gcxk20n7.js +5 -0
  92. package/dist/chunks/studio-jaaz8ce9.js +5 -0
  93. package/dist/chunks/{studio-90pq9km1.js → studio-jcnsdaep.js} +4 -4
  94. package/dist/chunks/studio-jsgf2q5k.js +7 -0
  95. package/dist/chunks/{studio-0q988f9w.js → studio-k3xxbagr.js} +3 -3
  96. package/dist/chunks/{studio-5ve6bbep.js → studio-k7evxqh4.js} +4 -4
  97. package/dist/chunks/studio-kt3pjkwd.js +5 -0
  98. package/dist/chunks/studio-m8g16bgz.js +5 -0
  99. package/dist/chunks/studio-mn0476ag.js +5 -0
  100. package/dist/chunks/studio-mx1smyq0.js +5 -0
  101. package/dist/chunks/studio-n0c5h6mf.js +5 -0
  102. package/dist/chunks/{studio-485046te.js → studio-nh6d342n.js} +7 -7
  103. package/dist/chunks/studio-nqxqf8p2.js +4 -0
  104. package/dist/chunks/studio-p4nrkvqr.js +5 -0
  105. package/dist/chunks/{studio-1fxkaaea.js → studio-pbxa5fpc.js} +4 -4
  106. package/dist/chunks/studio-pgmvdv7z.js +7 -0
  107. package/dist/chunks/studio-ph84avkf.js +5 -0
  108. package/dist/chunks/{studio-tq0rtfwj.js → studio-q0mvbaq6.js} +4 -4
  109. package/dist/chunks/studio-q0tccd43.js +5 -0
  110. package/dist/chunks/studio-q7rtx6zq.js +14 -0
  111. package/dist/chunks/{studio-a3g98wjr.js → studio-qgh13jtz.js} +4 -4
  112. package/dist/chunks/studio-qmn1xc24.js +5 -0
  113. package/dist/chunks/studio-qwdqwkj0.js +5 -0
  114. package/dist/chunks/studio-r5qy30vx.js +5 -0
  115. package/dist/chunks/studio-rj9eamf8.js +5 -0
  116. package/dist/chunks/studio-rptgsk96.js +5 -0
  117. package/dist/chunks/studio-rthyg42z.js +928 -0
  118. package/dist/chunks/studio-s19tp1xr.js +5 -0
  119. package/dist/chunks/studio-s32578pn.js +5 -0
  120. package/dist/chunks/studio-svb7yyve.js +5 -0
  121. package/dist/chunks/studio-syreb644.js +5 -0
  122. package/dist/chunks/studio-tf9jryb1.js +10 -0
  123. package/dist/chunks/studio-tfkznv39.js +5 -0
  124. package/dist/chunks/studio-tft6r105.js +5 -0
  125. package/dist/chunks/studio-txf2kysx.js +5 -0
  126. package/dist/chunks/studio-v8867ddv.js +12 -0
  127. package/dist/chunks/studio-vxq7fcvv.js +5 -0
  128. package/dist/chunks/studio-w4rz9hdk.js +5 -0
  129. package/dist/chunks/studio-wbcjbhy1.js +9 -0
  130. package/dist/chunks/studio-wc649wss.js +5 -0
  131. package/dist/chunks/studio-wys23mxz.js +5 -0
  132. package/dist/chunks/studio-x1x167jh.js +5 -0
  133. package/dist/chunks/studio-x9hsze61.js +5 -0
  134. package/dist/chunks/studio-y0n7yxea.js +9 -0
  135. package/dist/chunks/studio-y3ahhdpx.js +5 -0
  136. package/dist/chunks/studio-z97c48fk.js +5 -0
  137. package/dist/chunks/studio-zat62m0c.js +5 -0
  138. package/dist/chunks/studio-zcd2e7yz.js +5 -0
  139. package/dist/chunks/studio-zz9qe3rw.js +64 -0
  140. package/dist/chunks/toast-1gv0h53h.js +4 -0
  141. package/dist/chunks/{toast-host-ke5z4ng7.js → toast-host-1yg5ar8d.js} +3 -3
  142. package/dist/chunks/{tooltip-5v8ngwj2.js → tooltip-yypz28gq.js} +3 -3
  143. package/dist/chunks/{tree-mdq3v5cw.js → tree-9xa4hm7n.js} +2 -2
  144. package/dist/chunks/tsMode-epyfz1hv.js +14 -0
  145. package/dist/chunks/workspace-dz7nxfhv.js +4 -0
  146. package/dist/chunks/workspace-home-xsd7hkjw.js +4 -0
  147. package/dist/chunks/{ws-client-nze0k6mv.js → ws-client-bv552sfx.js} +3 -3
  148. package/dist/iframe-entry.js +20 -16
  149. package/dist/manifest.json +77 -63
  150. package/dist/studio.js +103 -104
  151. package/dist/workers/ts.worker.js +3 -3
  152. package/package.json +12 -11
  153. package/src/browse/component-examples.ts +272 -0
  154. package/src/browse/library-commands.ts +64 -104
  155. package/src/browse/library-layouts.ts +263 -49
  156. package/src/browse/library-model.ts +181 -133
  157. package/src/browse/library-pane.ts +738 -446
  158. package/src/browse/library-preview.ts +149 -19
  159. package/src/browse/library-source.ts +308 -41
  160. package/src/browse/preview-root.ts +78 -0
  161. package/src/browse/preview-style.ts +155 -0
  162. package/src/canvas/asset-refs.ts +16 -1
  163. package/src/canvas/canvas-live-render.ts +222 -30
  164. package/src/canvas/canvas-origin.ts +37 -12
  165. package/src/canvas/canvas-page-context.ts +112 -0
  166. package/src/canvas/canvas-render.ts +113 -107
  167. package/src/canvas/canvas-utils.ts +57 -12
  168. package/src/canvas/iframe-drop.ts +107 -0
  169. package/src/canvas/iframe-entry.ts +24 -12
  170. package/src/canvas/iframe-host.ts +134 -62
  171. package/src/canvas/iframe-keys.ts +11 -0
  172. package/src/canvas/iframe-patch.ts +8 -7
  173. package/src/canvas/iframe-protocol.ts +24 -5
  174. package/src/canvas/iframe-render.ts +48 -1
  175. package/src/canvas/iframe-subtree.ts +5 -2
  176. package/src/canvas/npm-modules.ts +22 -0
  177. package/src/canvas/preview-navigate.ts +16 -0
  178. package/src/canvas/repeater-sources.ts +200 -0
  179. package/src/canvas/stage-scrollbar.ts +5 -1
  180. package/src/canvas/surface-registry.ts +6 -0
  181. package/src/commands/app-commands.ts +16 -6
  182. package/src/commands/budget.ts +10 -8
  183. package/src/commands/context.ts +35 -10
  184. package/src/commands/defaults.ts +69 -45
  185. package/src/commands/keymap.ts +9 -0
  186. package/src/commands/levels.ts +11 -5
  187. package/src/commands/live-context.ts +2 -0
  188. package/src/commands/registry.ts +10 -1
  189. package/src/content/collection-match.ts +6 -5
  190. package/src/content/collection-pages.ts +412 -0
  191. package/src/content/content-collections.ts +270 -0
  192. package/src/content/entry-commands.ts +51 -60
  193. package/src/content/entry-editor.ts +111 -18
  194. package/src/content/entry-fields.ts +13 -1
  195. package/src/content/entry-inspector.ts +225 -0
  196. package/src/content/entry-model.ts +17 -3
  197. package/src/content/entry-open.ts +80 -0
  198. package/src/content/entry-summaries.ts +440 -0
  199. package/src/content/file-record-ids.ts +80 -0
  200. package/src/content/file-records.ts +125 -0
  201. package/src/content/page-summaries.ts +129 -0
  202. package/src/content/record-entry.ts +201 -0
  203. package/src/content/writing-banner.ts +177 -0
  204. package/src/create/add-new-commands.ts +185 -0
  205. package/src/create/add-new-flow.ts +1116 -0
  206. package/src/create/add-new.ts +1014 -0
  207. package/src/create/element-name.ts +121 -0
  208. package/src/editor/convert-to-component.ts +67 -43
  209. package/src/editor/file-drop-action.ts +9 -1
  210. package/src/editor/inline-edit-apply.ts +44 -0
  211. package/src/editor/inline-edit.ts +10 -0
  212. package/src/editor/insert-component.ts +91 -0
  213. package/src/editor/insert-zone-action.ts +13 -4
  214. package/src/editor/shortcuts.ts +44 -22
  215. package/src/editor/slash-menu.ts +51 -8
  216. package/src/files/components.ts +74 -10
  217. package/src/files/file-ops.ts +15 -5
  218. package/src/files/files.ts +164 -150
  219. package/src/files/fs-events.ts +18 -7
  220. package/src/files/media-meta.ts +95 -1
  221. package/src/files/media-types.ts +55 -0
  222. package/src/files/media-upload.ts +209 -52
  223. package/src/files/new-file-name.ts +156 -0
  224. package/src/files/serialize-document.ts +13 -3
  225. package/src/format/format-host.ts +15 -0
  226. package/src/github/github-auth.ts +2 -2
  227. package/src/github/github-publish.ts +4 -3
  228. package/src/grid/grid-controller.ts +5 -1
  229. package/src/grid/grid-open.ts +0 -27
  230. package/src/grid/grid-panel.ts +54 -2
  231. package/src/grid/grid-reveal.ts +34 -0
  232. package/src/grid/grid-source.ts +3 -25
  233. package/src/grid/grid-view.ts +31 -6
  234. package/src/grid/sources/content-source.ts +75 -7
  235. package/src/grid/tabulator-tables.d.ts +6 -0
  236. package/src/hosting/document.ts +2 -2
  237. package/src/i18n/i18n-commands.ts +2 -1
  238. package/src/media/media-commands.ts +181 -0
  239. package/src/media/media-library-model.ts +232 -0
  240. package/src/media/media-library.ts +1283 -0
  241. package/src/media/media-pane.ts +47 -19
  242. package/src/packages/pull-package-sync.ts +1 -1
  243. package/src/panels/activity-panel.ts +21 -5
  244. package/src/panels/ai-chat/chat-markdown.ts +8 -8
  245. package/src/panels/block-action-bar.ts +11 -11
  246. package/src/panels/canvas-dnd-bridge.ts +5 -2
  247. package/src/panels/chat-panel.ts +6 -6
  248. package/src/panels/collections-panel.ts +306 -0
  249. package/src/panels/component-preview.ts +35 -13
  250. package/src/panels/data-explorer.ts +1 -1
  251. package/src/panels/data-grid.ts +4 -0
  252. package/src/panels/dnd.ts +17 -30
  253. package/src/panels/elements-panel.ts +9 -2
  254. package/src/panels/empty-state.ts +2 -2
  255. package/src/panels/formula-workspace.ts +2 -3
  256. package/src/panels/frontmatter-fields.ts +9 -9
  257. package/src/panels/git-diff-open.ts +9 -5
  258. package/src/panels/head-panel.ts +369 -103
  259. package/src/panels/i18n-panel.ts +11 -10
  260. package/src/panels/imports-panel.ts +2 -0
  261. package/src/panels/jump-bar.ts +27 -2
  262. package/src/panels/layers-panel.ts +36 -30
  263. package/src/panels/left-panel.ts +22 -8
  264. package/src/panels/navigator-panels.ts +23 -11
  265. package/src/panels/pane-context.ts +111 -29
  266. package/src/panels/pane-grid.ts +6 -6
  267. package/src/panels/panel-registry.ts +14 -9
  268. package/src/panels/properties-panel.ts +7 -3
  269. package/src/panels/right-panel.ts +199 -43
  270. package/src/panels/seo-modal.ts +41 -108
  271. package/src/panels/settings-menu.ts +52 -50
  272. package/src/panels/settings-pane.ts +268 -162
  273. package/src/panels/signals-panel.ts +3 -4
  274. package/src/panels/site-model.ts +367 -0
  275. package/src/panels/site-panel.ts +638 -0
  276. package/src/panels/style-panel.ts +37 -3
  277. package/src/panels/stylebook-doc.ts +142 -10
  278. package/src/panels/stylebook-layers-panel.ts +39 -80
  279. package/src/panels/stylebook-panel.ts +47 -10
  280. package/src/panels/styles-panel.ts +327 -0
  281. package/src/panels/tab-strip.ts +109 -25
  282. package/src/platform.ts +1 -1
  283. package/src/platforms/cloud.ts +28 -1
  284. package/src/platforms/default-platform.ts +4 -4
  285. package/src/platforms/devserver.ts +51 -25
  286. package/src/publish/deploy-checklist.ts +12 -7
  287. package/src/publish/pages-service.ts +38 -14
  288. package/src/publish/publish-changes.ts +491 -0
  289. package/src/publish/publish-commands.ts +83 -18
  290. package/src/publish/publish-ids.ts +49 -0
  291. package/src/publish/publish-quick.ts +148 -0
  292. package/src/publish/publish-workspace.ts +926 -0
  293. package/src/publish/source-control.ts +907 -0
  294. package/src/services/automation.ts +16 -20
  295. package/src/services/cf-settings.ts +4 -4
  296. package/src/services/connection.ts +2 -2
  297. package/src/services/directory-picker.ts +2 -2
  298. package/src/services/references.ts +0 -0
  299. package/src/services/render-critic.ts +21 -2
  300. package/src/services/settings/definitions.ts +25 -14
  301. package/src/settings/contributed-section.ts +49 -10
  302. package/src/settings/css-vars-editor.ts +93 -27
  303. package/src/settings/developer-panels.ts +43 -0
  304. package/src/settings/extension-sections.ts +20 -2
  305. package/src/settings/general-settings.ts +91 -21
  306. package/src/settings/preferences-dialog.ts +8 -1
  307. package/src/settings/project-sections.ts +27 -10
  308. package/src/settings/schema-field-ui.ts +3 -1
  309. package/src/settings/section-registry.ts +116 -11
  310. package/src/settings/settings-dialog.ts +192 -0
  311. package/src/settings/settings-document.ts +182 -162
  312. package/src/shell.ts +467 -431
  313. package/src/site-context.ts +64 -10
  314. package/src/state.ts +28 -9
  315. package/src/studio.ts +194 -41
  316. package/src/style/project-styles.ts +34 -0
  317. package/src/style/stylebook-specimens.ts +89 -0
  318. package/src/style/stylebook-target.ts +26 -0
  319. package/src/style/tag-inheritance.ts +105 -0
  320. package/src/style/variables-focus.ts +61 -0
  321. package/src/style/variables-view.ts +235 -0
  322. package/src/surfaces/add-new.json +1482 -0
  323. package/src/surfaces/add-new.ts +325 -0
  324. package/src/surfaces/ai-chat.ts +2 -2
  325. package/src/surfaces/boot-failure.json +4 -3
  326. package/src/surfaces/bottom-dock.json +1 -1
  327. package/src/surfaces/canvas-stage.json +30 -19
  328. package/src/surfaces/canvas-stage.ts +5 -5
  329. package/src/surfaces/collections-panel.json +615 -0
  330. package/src/surfaces/collections-panel.ts +168 -0
  331. package/src/surfaces/commandbar.json +241 -96
  332. package/src/surfaces/commandbar.ts +134 -99
  333. package/src/surfaces/empty-state.json +1 -1
  334. package/src/surfaces/entry-editor.json +136 -0
  335. package/src/surfaces/entry-editor.ts +21 -0
  336. package/src/surfaces/entry-inspector.json +371 -0
  337. package/src/surfaces/entry-inspector.ts +143 -0
  338. package/src/surfaces/inspector-dock.json +162 -14
  339. package/src/surfaces/inspector-dock.ts +46 -19
  340. package/src/surfaces/library-pane.json +670 -437
  341. package/src/surfaces/library-pane.ts +94 -59
  342. package/src/surfaces/media-browser.json +62 -6
  343. package/src/surfaces/media-browser.ts +15 -1
  344. package/src/surfaces/media-field.json +1 -1
  345. package/src/surfaces/media-library.json +1586 -0
  346. package/src/surfaces/media-library.ts +282 -0
  347. package/src/surfaces/media-pick-dialog.json +71 -0
  348. package/src/surfaces/media-pick-dialog.ts +132 -0
  349. package/src/surfaces/menu.ts +18 -0
  350. package/src/surfaces/pane-context.json +144 -77
  351. package/src/surfaces/pane-context.ts +24 -0
  352. package/src/surfaces/panel-deploy-checklist.json +12 -6
  353. package/src/surfaces/panel-deploy-checklist.ts +3 -1
  354. package/src/surfaces/panel-page.json +72 -2
  355. package/src/surfaces/panel-page.ts +38 -7
  356. package/src/surfaces/panel-signals.json +1 -1
  357. package/src/surfaces/panel-signals.ts +5 -5
  358. package/src/surfaces/panel-stylebook-layers.json +71 -204
  359. package/src/surfaces/panel-stylebook-layers.ts +0 -21
  360. package/src/surfaces/preferences.json +120 -48
  361. package/src/surfaces/preferences.ts +8 -0
  362. package/src/surfaces/publish-quick.json +428 -0
  363. package/src/surfaces/publish-quick.ts +165 -0
  364. package/src/surfaces/publish-workspace.json +2892 -0
  365. package/src/surfaces/publish-workspace.ts +391 -0
  366. package/src/surfaces/rail.json +1 -159
  367. package/src/surfaces/rail.ts +18 -75
  368. package/src/surfaces/schema-form.json +10 -2
  369. package/src/surfaces/schema-form.ts +2 -0
  370. package/src/surfaces/seo.json +1 -1
  371. package/src/surfaces/settings-contributed.json +5 -5
  372. package/src/surfaces/settings-contributed.ts +18 -2
  373. package/src/surfaces/settings-css-vars.json +44 -36
  374. package/src/surfaces/settings-css-vars.ts +77 -4
  375. package/src/surfaces/settings-deploy.json +2 -15
  376. package/src/surfaces/settings-deploy.ts +1 -1
  377. package/src/surfaces/settings-dialog.json +51 -0
  378. package/src/surfaces/settings-dialog.ts +169 -0
  379. package/src/surfaces/settings-overview.json +3 -3
  380. package/src/surfaces/settings-overview.ts +9 -2
  381. package/src/surfaces/settings-pane.json +269 -46
  382. package/src/surfaces/settings-pane.ts +85 -24
  383. package/src/surfaces/shell.json +2 -1
  384. package/src/surfaces/site-panel.json +1029 -0
  385. package/src/surfaces/site-panel.ts +233 -0
  386. package/src/surfaces/slash-menu.json +63 -21
  387. package/src/surfaces/slash-menu.ts +23 -0
  388. package/src/surfaces/statusbar.ts +39 -15
  389. package/src/surfaces/styles-panel.json +735 -0
  390. package/src/surfaces/styles-panel.ts +195 -0
  391. package/src/surfaces/styles-variables.json +149 -0
  392. package/src/surfaces/styles-variables.ts +145 -0
  393. package/src/surfaces/tab-strip.json +4 -4
  394. package/src/surfaces/welcome.ts +1 -1
  395. package/src/surfaces/writing-banner.json +94 -0
  396. package/src/surfaces/writing-banner.ts +80 -0
  397. package/src/tabs/bare-repeaters.ts +101 -0
  398. package/src/tabs/tab.ts +47 -7
  399. package/src/types.ts +21 -26
  400. package/src/ui/form-controls.ts +47 -8
  401. package/src/ui/layers.ts +13 -0
  402. package/src/ui/media-picker.ts +284 -40
  403. package/src/ui/regions.ts +7 -6
  404. package/src/ui/schema-form.ts +259 -27
  405. package/src/ui/virtual-window.ts +26 -1
  406. package/src/utils/base64.ts +3 -3
  407. package/src/utils/edit-display.ts +322 -67
  408. package/src/utils/local-day.ts +18 -0
  409. package/src/workspace/pane-derive.ts +4 -4
  410. package/src/workspace/session.ts +28 -7
  411. package/src/workspace/tab-workspace.ts +137 -0
  412. package/src/workspace/workspace-back.ts +189 -0
  413. package/src/workspace/workspace-home.ts +133 -0
  414. package/src/workspace/workspace-ids.ts +129 -0
  415. package/src/workspace/workspace-switch.ts +372 -0
  416. package/src/workspace/workspace.ts +125 -11
  417. package/styles/shell-frame.css +30 -7
  418. package/styles/shell-frame.json +15 -3
  419. package/dist/chunks/2020-f2gkpy8d.js +0 -4
  420. package/dist/chunks/adapter-4912g339.js +0 -4
  421. package/dist/chunks/cf-account-picker-wccaenh6.js +0 -4
  422. package/dist/chunks/cf-settings-br6105tr.js +0 -4
  423. package/dist/chunks/color-28ksk2qm.js +0 -4
  424. package/dist/chunks/components-db68vsn7.js +0 -4
  425. package/dist/chunks/content-source-1449qesq.js +0 -4
  426. package/dist/chunks/convert-to-repeater-5h457egj.js +0 -4
  427. package/dist/chunks/editor-x9jn86a7.js +0 -4
  428. package/dist/chunks/entry-commands-may24cpt.js +0 -4
  429. package/dist/chunks/extension-sections-pvr14vxr.js +0 -4
  430. package/dist/chunks/file-ops-x9v54pcj.js +0 -4
  431. package/dist/chunks/files-j3knqf0s.js +0 -4
  432. package/dist/chunks/format-host-tyre2trb.js +0 -4
  433. package/dist/chunks/fs-events-64ma9htc.js +0 -4
  434. package/dist/chunks/git-panel-84ps5dex.js +0 -4
  435. package/dist/chunks/iframe-entry-fvbk89gm.js +0 -5
  436. package/dist/chunks/iframe-host-ck6vejt5.js +0 -4
  437. package/dist/chunks/index-b8xw3vy9.js +0 -4
  438. package/dist/chunks/jsonMode-w15cmrcm.js +0 -13
  439. package/dist/chunks/jx-validate-at3zn8wa.js +0 -4
  440. package/dist/chunks/layers-h4xp1pss.js +0 -4
  441. package/dist/chunks/layers-panel-m5hw1d7g.js +0 -4
  442. package/dist/chunks/lit-html-8t8t3dnr.js +0 -4
  443. package/dist/chunks/media-picker-2cweexc5.js +0 -4
  444. package/dist/chunks/menu-ynw13y0s.js +0 -4
  445. package/dist/chunks/monaco-buffer-qzxn567r.js +0 -4
  446. package/dist/chunks/monaco-setup-gxf6656g.js +0 -4
  447. package/dist/chunks/notify-cj5zbrs2.js +0 -4
  448. package/dist/chunks/parse-b7ddhr8m.js +0 -4
  449. package/dist/chunks/platform-3dfws9js.js +0 -4
  450. package/dist/chunks/popover-jt2gxmzs.js +0 -4
  451. package/dist/chunks/publish-panel-1gvxbj21.js +0 -4
  452. package/dist/chunks/quick-search-0dajrwqg.js +0 -4
  453. package/dist/chunks/references-49qgt404.js +0 -4
  454. package/dist/chunks/right-panel-jm1bwe53.js +0 -4
  455. package/dist/chunks/section-registry-6kwc4fky.js +0 -4
  456. package/dist/chunks/studio-0rt52vpq.js +0 -5
  457. package/dist/chunks/studio-18vgbhs5.js +0 -5
  458. package/dist/chunks/studio-24mccdrj.js +0 -5
  459. package/dist/chunks/studio-2eh507zk.js +0 -9
  460. package/dist/chunks/studio-2hcbccfv.js +0 -5
  461. package/dist/chunks/studio-2jbs3rxv.js +0 -5
  462. package/dist/chunks/studio-4h8k4dw9.js +0 -5
  463. package/dist/chunks/studio-5f6n18kx.js +0 -5
  464. package/dist/chunks/studio-5gthpky6.js +0 -5
  465. package/dist/chunks/studio-6ep3js6b.js +0 -9
  466. package/dist/chunks/studio-6wkmf3wz.js +0 -9
  467. package/dist/chunks/studio-841rf3cg.js +0 -5
  468. package/dist/chunks/studio-8gmwgheg.js +0 -5
  469. package/dist/chunks/studio-8qm0ep50.js +0 -5
  470. package/dist/chunks/studio-924p1tm1.js +0 -6
  471. package/dist/chunks/studio-a3shpz9y.js +0 -5
  472. package/dist/chunks/studio-amsbaaar.js +0 -6
  473. package/dist/chunks/studio-at5spjbc.js +0 -7
  474. package/dist/chunks/studio-b2xv945e.js +0 -5
  475. package/dist/chunks/studio-bn5nkafw.js +0 -5
  476. package/dist/chunks/studio-bw6q5xjf.js +0 -9
  477. package/dist/chunks/studio-c7q0t9x1.js +0 -5
  478. package/dist/chunks/studio-camnhc96.js +0 -6
  479. package/dist/chunks/studio-cffqvnzd.js +0 -5
  480. package/dist/chunks/studio-efvfrsf8.js +0 -5
  481. package/dist/chunks/studio-er30bpcx.js +0 -5
  482. package/dist/chunks/studio-ezscgr64.js +0 -5
  483. package/dist/chunks/studio-ffrrncvz.js +0 -5
  484. package/dist/chunks/studio-fpphgn8y.js +0 -10
  485. package/dist/chunks/studio-j1kvhdjk.js +0 -4
  486. package/dist/chunks/studio-j430n16g.js +0 -7
  487. package/dist/chunks/studio-jjkg84nj.js +0 -5
  488. package/dist/chunks/studio-m0q32ars.js +0 -4
  489. package/dist/chunks/studio-m6bdst11.js +0 -5
  490. package/dist/chunks/studio-nv2cptd4.js +0 -64
  491. package/dist/chunks/studio-nwfrc98n.js +0 -5
  492. package/dist/chunks/studio-p1wgvp7r.js +0 -5
  493. package/dist/chunks/studio-pag2wncm.js +0 -5
  494. package/dist/chunks/studio-qvanvzfd.js +0 -5
  495. package/dist/chunks/studio-qwa64kt7.js +0 -5
  496. package/dist/chunks/studio-rk1zc4x3.js +0 -928
  497. package/dist/chunks/studio-se2r3ptc.js +0 -5
  498. package/dist/chunks/studio-sg2a0dh0.js +0 -5
  499. package/dist/chunks/studio-tjzjhe68.js +0 -5
  500. package/dist/chunks/studio-v2w7q8r1.js +0 -7
  501. package/dist/chunks/studio-v5vjq1h0.js +0 -4
  502. package/dist/chunks/studio-v8aga3vp.js +0 -14
  503. package/dist/chunks/studio-vfcdrfmv.js +0 -5
  504. package/dist/chunks/studio-vmfkgdjf.js +0 -5
  505. package/dist/chunks/studio-wt1816jj.js +0 -5
  506. package/dist/chunks/studio-wz73q5kq.js +0 -4
  507. package/dist/chunks/studio-y04qtxvp.js +0 -7
  508. package/dist/chunks/studio-y21g8zzg.js +0 -5
  509. package/dist/chunks/studio-y64hrt8p.js +0 -12
  510. package/dist/chunks/studio-ynn90f58.js +0 -16
  511. package/dist/chunks/studio-yxz682sx.js +0 -5
  512. package/dist/chunks/studio-zp7snvkq.js +0 -5
  513. package/dist/chunks/studio-zq4z6tm6.js +0 -5
  514. package/dist/chunks/toast-c9fn075p.js +0 -4
  515. package/dist/chunks/tsMode-sf49ee9x.js +0 -14
  516. package/dist/chunks/workspace-jtfahpee.js +0 -4
  517. package/src/panels/frontmatter-panel.ts +0 -711
  518. package/src/panels/git-panel.ts +0 -1108
  519. package/src/surfaces/doc-header.json +0 -776
  520. package/src/surfaces/doc-header.ts +0 -222
  521. package/src/surfaces/git-panel.json +0 -1880
  522. package/src/surfaces/git-panel.ts +0 -264
@@ -91,6 +91,7 @@ import { showPromptDialog } from "../ui/layers";
91
91
  import { parseMediaEntries, schemeOfQuery } from "../utils/canvas-media";
92
92
  import { getEffectiveMedia, getEffectiveStyle } from "../site-context";
93
93
  import { computeInheritedSources } from "../utils/inherited-style";
94
+ import { tagAncestorSources } from "../style/tag-inheritance";
94
95
  import { loadUsages, peekUsages, usageFiles } from "../services/references";
95
96
  import { mediaDisplayName } from "./shared";
96
97
  import {
@@ -125,6 +126,7 @@ import type { CssFontPreset, CssLonghand, CssMetaEntry } from "./style-utils";
125
126
  import { UNIT_RE } from "../ui/unit-selector";
126
127
  import { colorTokens, resolvedColor } from "../ui/color-selector";
127
128
  import { resolveTokenValue, toTokenRef, tokenRefName } from "../style/token-ref";
129
+ import { PROJECT_VARIABLES_VIEW } from "../style/project-styles";
128
130
  import { mountStylePanelSurface } from "../surfaces/style-panel";
129
131
  import { openMenu } from "../surfaces/menu";
130
132
  import type { MenuHandle, MenuRowProjection } from "../surfaces/menu";
@@ -1382,6 +1384,11 @@ function shorthandPlaceholder(
1382
1384
 
1383
1385
  // ─── The whole view ──────────────────────────────────────────────────────────
1384
1386
 
1387
+ /** What the Style tab says beside the Variables view, where there is no element to style. */
1388
+ export const VARIABLES_INSPECTOR_MESSAGE =
1389
+ "Variables are edited in the view itself. Switch the view to Elements and pick a tag to style " +
1390
+ "its default here.";
1391
+
1385
1392
  /** The three teaching states, and the one that offers a button. */
1386
1393
  function emptyView(message: string, withOpen: boolean): StylePanelView {
1387
1394
  return {
@@ -1401,6 +1408,12 @@ function buildView(canvasMode: () => string): StylePanelView {
1401
1408
  if (!tab) {
1402
1409
  return emptyView("Open a page to style what you click.", true);
1403
1410
  }
1411
+ /* The Styles workspace's Variables view has no canvas to click and edits its custom properties in
1412
+ the pane itself, so the canvas teaching line would ask for something impossible. Say where the
1413
+ Inspector's half of the workspace is instead. */
1414
+ if (canvasMode() === PROJECT_VARIABLES_VIEW) {
1415
+ return emptyView(VARIABLES_INSPECTOR_MESSAGE, false);
1416
+ }
1404
1417
  if (canvasMode() === "stylebook" && shell.stylebook.selection) {
1405
1418
  const node = tab.doc.document;
1406
1419
  /* Checked, not trusted: a tab's document is whatever the file parsed to, asserted rather than
@@ -1442,9 +1455,10 @@ function buildEditor(
1442
1455
  opts: { effectiveStyle?: JxStyle | undefined; stylebookSelector?: string | null },
1443
1456
  ): StylePanelView {
1444
1457
  const { effectiveStyle, stylebookSelector = null } = opts;
1445
- /* SAFETY: `buildView` calls this with a primary selection it has checked, or in Stylebook, where
1446
- `selectStylebookTag` parks the selection on the root path `[[]]` rather than emptying it. */
1447
- const sel = primarySelection(tab.session.selection) as JxPath;
1458
+ /* `buildView` calls this with a primary selection it has checked, or in Stylebook, where the
1459
+ edit targets a TAG and the selection is only parked on the root. A Stylebook tab whose session
1460
+ was never parked (or was cleared since) therefore means the root too, rather than a throw. */
1461
+ const sel: JxPath = primarySelection(tab.session.selection) ?? [];
1448
1462
  /** The document's OWN style — what a commit writes into. */
1449
1463
  const ownRootStyle: JxStyle = node.style || {};
1450
1464
  const style = effectiveStyle ?? ownRootStyle;
@@ -1620,6 +1634,14 @@ function buildEditor(
1620
1634
  };
1621
1635
  }
1622
1636
  }
1637
+ // A Project Styles tag rule also inherits from the rules above it in this same file (`body`,
1638
+ // Then each ancestor tag in its path), which is what its specimen is drawn with. The context walk
1639
+ // Above outranks it: a value the tag itself sets at Base is nearer than anything it inherits.
1640
+ if (stylebookPath) {
1641
+ for (const [p, source] of Object.entries(tagAncestorSources(style, stylebookPath, editMedia))) {
1642
+ inheritedInfo[p] ??= { donor: source.donor, value: source.value };
1643
+ }
1644
+ }
1623
1645
  const inheritedStyle: Record<string, string | number> = {};
1624
1646
  for (const [p, info] of Object.entries(inheritedInfo)) {
1625
1647
  inheritedStyle[p] = info.value;
@@ -2134,6 +2156,11 @@ let _standing: { host: HTMLElement; handle: StylePanelSurface; scope: EffectScop
2134
2156
  export interface StyleHostDeps {
2135
2157
  /** `stylebook` edits a tag catalogue entry; anything else edits the element selection. */
2136
2158
  getCanvasMode: () => string;
2159
+ /**
2160
+ * Whether the tab is the one showing. Read inside the projecting effect, so a hidden tab costs
2161
+ * nothing per selection and re-projects the moment it is opened. Absent means always showing.
2162
+ */
2163
+ isShowing?: () => boolean;
2137
2164
  }
2138
2165
 
2139
2166
  /** The default the tab falls back to when the dock names no mode. */
@@ -2186,9 +2213,16 @@ export function bindStyleHost(el: HTMLElement | null, ctx?: StyleHostDeps): void
2186
2213
  const handle = mountStylePanelSurface(el, first, ACTIONS, {
2187
2214
  target: (element) => attachTargetLine(element ?? undefined),
2188
2215
  });
2216
+ const isShowing = ctx?.isShowing ?? (() => true);
2189
2217
  const scope = effectScope();
2190
2218
  scope.run(() => {
2191
2219
  effect(() => {
2220
+ /* A hidden tab does not project. Its editor is thousands of nodes, and a new selection
2221
+ re-keys every row, so projecting behind the Content tab rebuilt the whole of it on every
2222
+ click — most of what selecting an element cost. */
2223
+ if (!isShowing()) {
2224
+ return;
2225
+ }
2192
2226
  const view = buildView(_canvasMode);
2193
2227
  rememberButtons(view);
2194
2228
  handle.update(view);
@@ -21,8 +21,15 @@ import { isKeyframesAtRule } from "@jxsuite/runtime/css";
21
21
  import type { StylebookEntry } from "./stylebook-panel";
22
22
  import type { ComponentEntry } from "../files/components";
23
23
  import type { JxPath } from "../state";
24
- import { isNonNullObject } from "@jxsuite/schema/guards";
25
- import type { JxMutableNode, JxStyle } from "@jxsuite/schema/types";
24
+ import { isNonNullObject, isRef } from "@jxsuite/schema/guards";
25
+ import type { StylebookSpecimens } from "../style/stylebook-specimens";
26
+ import type {
27
+ JxDocument,
28
+ JxHeadEntry,
29
+ JxMutableNode,
30
+ JxStateDefinition,
31
+ JxStyle,
32
+ } from "@jxsuite/schema/types";
26
33
 
27
34
  export interface StylebookDocResult {
28
35
  /** The specimen document (plain JSON — safe to post over the bridge). */
@@ -142,6 +149,101 @@ export function hasTagStyle(rootStyle: JxStyle, tagPath: string): boolean {
142
149
  return false;
143
150
  }
144
151
 
152
+ /** One catalogue tag as a list of element defaults draws it: the Styles panel's, and the Outline's. */
153
+ export interface CatalogueRow {
154
+ /** The catalogue entry the row stands for. */
155
+ entry: StylebookEntry;
156
+ tag: string;
157
+ /** The compound path (`ul li`): the row's key, and what selecting the row selects. */
158
+ path: string;
159
+ /** How deep in its specimen the tag sits: 0 for a section's own entries. */
160
+ depth: number;
161
+ /** Whether the selection's leaf is this tag ({@link selectionLeaf}). */
162
+ selected: boolean;
163
+ }
164
+
165
+ /**
166
+ * The leaf of a stylebook selection.
167
+ *
168
+ * A selection is a compound path (`"ul li"`) and the catalogue draws one row per TAG, so the row
169
+ * that is marked is the one whose tag is the path's last segment. That is what the tree has always
170
+ * done; it is written down here because "selected" meaning something other than "equal" is exactly
171
+ * the kind of thing a reader assumes is a bug.
172
+ */
173
+ export function selectionLeaf(selection: string | null): string | null {
174
+ if (!selection) {
175
+ return null;
176
+ }
177
+ return selection.split(" ").pop() ?? null;
178
+ }
179
+
180
+ /**
181
+ * Flatten catalogue entries and everything under them into rows, in document order.
182
+ *
183
+ * Children are deduplicated by tag: a `<ul>` specimen carries several `<li>`s and they are one row,
184
+ * because the row selects a TAG and there is one rule per tag path to write. The ONE walk both
185
+ * lists draw from, so the two cannot drift; what each says about a row (its dot, its label) is the
186
+ * caller's.
187
+ *
188
+ * @param entries A section's entries, or several sections' in order
189
+ * @param selection The stylebook selection (`shell.stylebook.selection`)
190
+ */
191
+ export function catalogueRows(
192
+ entries: readonly StylebookEntry[],
193
+ selection: string | null,
194
+ ): CatalogueRow[] {
195
+ const leaf = selectionLeaf(selection);
196
+ const out: CatalogueRow[] = [];
197
+ const walk = (entry: StylebookEntry, depth: number, parentPath: string): void => {
198
+ const path = parentPath ? `${parentPath} ${entry.tag}` : entry.tag;
199
+ out.push({ depth, entry, path, selected: entry.tag === leaf, tag: entry.tag });
200
+ const children = entry.children
201
+ ? [...new Map(entry.children.map((child) => [child.tag, child])).values()]
202
+ : [];
203
+ for (const child of children) {
204
+ walk(child, depth + 1, path);
205
+ }
206
+ };
207
+ for (const entry of entries) {
208
+ walk(entry, 0, "");
209
+ }
210
+ return out;
211
+ }
212
+
213
+ /**
214
+ * A card's specimen for a component drawn as the first row of a list
215
+ * (`style/stylebook-specimens.ts`): the list's repeater, reading its row from `rootState[key]` so
216
+ * two cards' lists cannot collide, and the rest of the page state the row was drawn in, the first
217
+ * card's value winning a shared name (`$page`, `$site`). Null when the sample is not a repeater
218
+ * over a state list.
219
+ */
220
+ export function sampleRowSpecimen(
221
+ sample: JxDocument,
222
+ key: string,
223
+ rootState: Record<string, JxStateDefinition>,
224
+ ): JxMutableNode | null {
225
+ const [list] = Array.isArray(sample.children) ? sample.children : [];
226
+ if (!isNonNullObject(list) || Array.isArray(list) || !isRef(list.items)) {
227
+ return null;
228
+ }
229
+ const { $ref } = list.items;
230
+ const listKey = $ref.startsWith("#/state/") ? $ref.slice("#/state/".length) : "";
231
+ const rows = sample.state?.[listKey];
232
+ if (!Array.isArray(rows)) {
233
+ return null;
234
+ }
235
+ rootState[key] = rows;
236
+ for (const [name, value] of Object.entries(sample.state ?? {})) {
237
+ if (name !== listKey && !(name in rootState)) {
238
+ rootState[name] = value;
239
+ }
240
+ }
241
+ /* SAFETY: `list` is the repeater object a page's `children` held; only its `items` is replaced,
242
+ with a ref of the same shape. */
243
+ const repeater = { ...list, items: { $ref: `#/state/${key}` } } as JxMutableNode;
244
+ return { children: [repeater], tagName: "div" };
245
+ }
246
+
145
247
  /** Options for {@link buildStylebookDoc}. */
146
248
  export interface BuildStylebookDocOpts {
147
249
  meta: { $sections: { label: string; elements: StylebookEntry[] }[] };
@@ -150,9 +252,16 @@ export interface BuildStylebookDocOpts {
150
252
  effectiveStyle: JxStyle;
151
253
  /** Merged $media map (getEffectiveMedia output) — becomes the doc's $media. */
152
254
  effectiveMedia: Record<string, string>;
255
+ /** Merged project+document `$head` (getEffectiveHead output) — becomes the doc's `$head`. */
256
+ effectiveHead?: JxHeadEntry[];
153
257
  filter: string;
154
258
  customizedOnly: boolean;
155
259
  projectRoot: string | null;
260
+ /**
261
+ * How each component card is drawn, by tag (`style/stylebook-specimens.ts`). A component with no
262
+ * entry is drawn bare, with its declared defaults as attributes.
263
+ */
264
+ specimens?: StylebookSpecimens;
156
265
  }
157
266
 
158
267
  /**
@@ -265,6 +374,8 @@ export function buildStylebookDoc(opts: BuildStylebookDocOpts): StylebookDocResu
265
374
 
266
375
  // Custom components from the registry — live custom elements registered via $elements.
267
376
  const $elements: (string | { $ref: string })[] = [];
377
+ // The data the sample-row cards read: each row's list, and the page context it was drawn in.
378
+ const rootState: Record<string, JxStateDefinition> = {};
268
379
  {
269
380
  let comps = opts.components;
270
381
  if (filter) {
@@ -288,17 +399,30 @@ export function buildStylebookDoc(opts: BuildStylebookDocOpts): StylebookDocResu
288
399
  "/",
289
400
  ),
290
401
  });
291
- const attributes: Record<string, string> = {};
292
- for (const p of comp.props ?? []) {
293
- if (p.default !== undefined && p.default !== "false" && p.default !== "''") {
294
- attributes[p.name] = String(p.default).replaceAll(/^'|'$/g, "");
402
+ const drawn = opts.specimens?.get(comp.tagName);
403
+ if (drawn?.kind === "props") {
404
+ const specimen: JxMutableNode = { $props: drawn.props, tagName: comp.tagName };
405
+ return cardNode(comp.tagName, `<${comp.tagName}>`, specimen, cardPath, null);
406
+ }
407
+ if (drawn?.kind === "row") {
408
+ const row = sampleRowSpecimen(drawn.sample.doc, `stylebookRow${ci}`, rootState);
409
+ if (row) {
410
+ return cardNode(comp.tagName, `<${comp.tagName}>`, row, cardPath, null);
295
411
  }
296
412
  }
297
- const specimen: JxMutableNode = { tagName: comp.tagName };
298
- if (Object.keys(attributes).length > 0) {
299
- specimen.attributes = attributes;
413
+ if (drawn?.kind !== "none") {
414
+ const attributes: Record<string, string> = {};
415
+ for (const p of comp.props ?? []) {
416
+ if (p.default !== undefined && p.default !== "false" && p.default !== "''") {
417
+ attributes[p.name] = String(p.default).replaceAll(/^'|'$/g, "");
418
+ }
419
+ }
420
+ const specimen: JxMutableNode = { tagName: comp.tagName };
421
+ if (Object.keys(attributes).length > 0) {
422
+ specimen.attributes = attributes;
423
+ }
424
+ return cardNode(comp.tagName, `<${comp.tagName}>`, specimen, cardPath, null);
300
425
  }
301
- return cardNode(comp.tagName, `<${comp.tagName}>`, specimen, cardPath, null);
302
426
  }
303
427
  // Npm/format-class components can't be $ref-registered — placeholder box (legacy parity).
304
428
  const fallback: JxMutableNode = {
@@ -325,7 +449,15 @@ export function buildStylebookDoc(opts: BuildStylebookDocOpts): StylebookDocResu
325
449
  if ($elements.length > 0) {
326
450
  doc.$elements = $elements;
327
451
  }
452
+ /* The project's `$head` too: its webfont links are what make `fontFamily: 'Barlow'` render as
453
+ Barlow, and a specimen sheet drawn in the system fallback shows styles the site never has. */
454
+ if (opts.effectiveHead && opts.effectiveHead.length > 0) {
455
+ doc.$head = opts.effectiveHead;
456
+ }
328
457
  doc.$media = opts.effectiveMedia;
458
+ if (Object.keys(rootState).length > 0) {
459
+ doc.state = rootState;
460
+ }
329
461
  doc.attributes = { class: "sb-root" };
330
462
  doc.children = sections;
331
463
  doc.style = transposeStylebookStyle(opts.effectiveStyle);
@@ -1,14 +1,21 @@
1
1
  /// <reference lib="dom" />
2
2
  /**
3
- * The Outline panel while the pane is showing Project Styles — the element catalogue and the
4
- * document's own custom properties.
3
+ * The Outline panel while the pane is showing a document's Elements view — the element catalogue.
4
+ *
5
+ * A page or a component offers **Elements** in its Editor control, which styles that file's element
6
+ * defaults (`docs/studio/design/stylebook.md`), and the Outline beside it lists the catalogue's
7
+ * tags instead of the document's tree. `project.json` in the Styles workspace has its own
8
+ * Navigator, the Styles panel (`panels/styles-panel.ts`), which lists the project's CSS custom
9
+ * properties too; the variables list this body used to draw beside the Variables view went there
10
+ * with it.
5
11
  *
6
12
  * **The body is a Jx document** (`surfaces/panel-stylebook-layers.json`, mounted by
7
13
  * `surfaces/panel-stylebook-layers.ts`), so this module renders nothing and projects everything.
8
- * What stays here is what is a DECISION: how the catalogue's recursive `$sections` flatten into a
9
- * list, how a child's compound path is spelled, which children are duplicates of each other, which
10
- * tags the open file has already styled, and which row the current selection marks. The surface
11
- * reads values.
14
+ * What stays here is what is a DECISION: which tags the open file has already styled, and what each
15
+ * row is called. The walk itself (how the catalogue's recursive `$sections` flatten into a list,
16
+ * how a child's compound path is spelled, which children are duplicates of each other, and which
17
+ * row the current selection marks) is `stylebook-doc.ts`'s `catalogueRows`, which the Styles
18
+ * panel's Elements section draws from too. The surface reads values.
12
19
  *
13
20
  * The panel does not own the panel RECORD — `panels/layers-panel.ts` does, because the Outline is
14
21
  * one panel with two bodies and only the record can know which the pane is asking for. That module
@@ -23,13 +30,13 @@ import { activeTab } from "../workspace/workspace";
23
30
  import { shell } from "../shell";
24
31
  import { componentRegistry } from "../files/components";
25
32
  import { mountStylebookLayersSurface } from "../surfaces/panel-stylebook-layers";
33
+ import { catalogueRows } from "./stylebook-doc";
26
34
 
27
35
  import type { StylebookEntry } from "./stylebook-panel";
28
36
  import type {
29
37
  StylebookLayersSurfaceHandle,
30
38
  StylebookLayersValues,
31
39
  StylebookRowView,
32
- StylebookVariableView,
33
40
  } from "../surfaces/panel-stylebook-layers";
34
41
  import { isNonNullObject } from "@jxsuite/schema/guards";
35
42
  import type { JxStyle } from "@jxsuite/schema/types";
@@ -55,61 +62,6 @@ function hasTagStyle(rootStyle: JxStyle, tag: string): boolean {
55
62
  return isNonNullObject(s) && Object.keys(s).length > 0;
56
63
  }
57
64
 
58
- /**
59
- * The leaf of the current selection.
60
- *
61
- * A selection is a compound path (`"ul li"`) and the catalogue draws one row per TAG, so the row
62
- * that is marked is the one whose tag is the path's last segment. That is what the tree has always
63
- * done; it is written down here because "selected" meaning something other than "equal" is exactly
64
- * the kind of thing a reader assumes is a bug.
65
- */
66
- function selectedLeaf(selection: string | null): string | null {
67
- if (!selection) {
68
- return null;
69
- }
70
- return selection.includes(" ") ? (selection.split(" ").pop() ?? null) : selection;
71
- }
72
-
73
- /**
74
- * Flatten one catalogue entry and everything under it into rows.
75
- *
76
- * Children are deduplicated by tag — a `<ul>` specimen carries two `<li>`s and they are one row,
77
- * because the row selects a TAG and there is only one `& li` to write.
78
- */
79
- function elementRows(
80
- entry: StylebookEntry,
81
- rootStyle: JxStyle,
82
- leaf: string | null,
83
- depth: number,
84
- parentPath: string,
85
- out: StylebookRowView[],
86
- ): void {
87
- const { tag } = entry;
88
- const fullPath = parentPath ? `${parentPath} ${tag}` : tag;
89
- out.push({
90
- customized: hasTagStyle(rootStyle, tag),
91
- indent: `${INDENT_BASE + depth * INDENT_STEP}px`,
92
- key: fullPath,
93
- kind: "element",
94
- label: entry.text || `<${tag}>`,
95
- selected: tag === leaf,
96
- tag,
97
- });
98
- const children = entry.children
99
- ? [...new Map(entry.children.map((c: StylebookEntry) => [c.tag, c])).values()]
100
- : [];
101
- for (const child of children) {
102
- elementRows(child, rootStyle, leaf, depth + 1, fullPath, out);
103
- }
104
- }
105
-
106
- /** The custom properties the open file declares, in the order it declares them. */
107
- function variableRows(rootStyle: JxStyle): StylebookVariableView[] {
108
- return Object.entries(rootStyle)
109
- .filter(([k]) => k.startsWith("--"))
110
- .map(([name, value]) => ({ key: name, name, value: String(value) }));
111
- }
112
-
113
65
  /**
114
66
  * What the surface should be showing right now.
115
67
  *
@@ -123,14 +75,20 @@ export function stylebookLayersValues(ctx: StylebookLayersCtx): StylebookLayersV
123
75
  const tab = activeTab.value;
124
76
  const rootStyle: JxStyle = tab?.doc.document?.style || {};
125
77
  const { selection } = shell.stylebook;
126
- const leaf = selectedLeaf(selection);
127
78
 
128
- const rows: StylebookRowView[] = [];
129
- for (const section of ctx.stylebookMeta.$sections) {
130
- for (const entry of section.elements) {
131
- elementRows(entry, rootStyle, leaf, 0, "", rows);
132
- }
133
- }
79
+ /* The stylebook's own walk (`stylebook-doc.ts` `catalogueRows`), which the Styles panel's
80
+ Elements section draws from too: the path, the nesting, the deduplication and the leaf mark
81
+ are one decision, and only the dot and the label are this list's. */
82
+ const entries = ctx.stylebookMeta.$sections.flatMap((section) => section.elements);
83
+ const rows: StylebookRowView[] = catalogueRows(entries, selection).map((row) => ({
84
+ customized: hasTagStyle(rootStyle, row.tag),
85
+ indent: `${INDENT_BASE + row.depth * INDENT_STEP}px`,
86
+ key: row.path,
87
+ kind: "element",
88
+ label: row.entry.text || `<${row.tag}>`,
89
+ selected: row.selected,
90
+ tag: row.tag,
91
+ }));
134
92
  for (const comp of componentRegistry) {
135
93
  rows.push({
136
94
  customized: false,
@@ -145,13 +103,7 @@ export function stylebookLayersValues(ctx: StylebookLayersCtx): StylebookLayersV
145
103
  });
146
104
  }
147
105
 
148
- const variables = variableRows(rootStyle);
149
- return {
150
- hasVariables: variables.length > 0,
151
- rows,
152
- tab: shell.stylebook.tab,
153
- variables,
154
- };
106
+ return { rows };
155
107
  }
156
108
 
157
109
  /**
@@ -161,7 +113,12 @@ export function stylebookLayersValues(ctx: StylebookLayersCtx): StylebookLayersV
161
113
  * one Navigator, so a mount into a DIFFERENT node is the old one being replaced, and holding both
162
114
  * would leave the first one's effects running against a scope nobody writes any more.
163
115
  */
164
- let standing: { host: HTMLElement; handle: StylebookLayersSurfaceHandle } | null = null;
116
+ let standing: {
117
+ /** The latest ctx: the handlers read it, not the one the first mount closed over. */
118
+ ctx: StylebookLayersCtx;
119
+ host: HTMLElement;
120
+ handle: StylebookLayersSurfaceHandle;
121
+ } | null = null;
165
122
 
166
123
  /**
167
124
  * Keep the selected row on screen after a repaint.
@@ -201,12 +158,14 @@ export function mountStylebookLayersPanel(ctx: StylebookLayersCtx, host: HTMLEle
201
158
  }
202
159
  const values = stylebookLayersValues(ctx);
203
160
  if (standing) {
161
+ standing.ctx = ctx;
204
162
  standing.handle.update(values);
205
163
  } else {
206
164
  standing = {
165
+ ctx,
207
166
  handle: mountStylebookLayersSurface(target, values, {
208
167
  selectRow: (path) => {
209
- ctx.selectStylebookTag(path, undefined, { panCanvas: true });
168
+ (standing?.ctx ?? ctx).selectStylebookTag(path, undefined, { panCanvas: true });
210
169
  },
211
170
  }),
212
171
  host: target,
@@ -218,8 +177,8 @@ export function mountStylebookLayersPanel(ctx: StylebookLayersCtx, host: HTMLEle
218
177
  /**
219
178
  * Take the catalogue down.
220
179
  *
221
- * Called by the Outline's record when the pane is no longer showing Project Styles. Without it the
222
- * document survives its own irrelevance: lit's branch renders into the range it owns inside
180
+ * Called by the Outline's record when the pane is no longer showing an Elements view. Without it
181
+ * the document survives its own irrelevance: lit's branch renders into the range it owns inside
223
182
  * `.panel-content` and leaves everything appended after it exactly where it was.
224
183
  */
225
184
  export function detachStylebookLayers(): void {
@@ -24,15 +24,16 @@ import { projectState, updateSession } from "../store";
24
24
  import { createStylebookChromeSurface } from "../surfaces/stylebook-chrome";
25
25
  import type { StylebookChromeSurface } from "../surfaces/stylebook-chrome";
26
26
  import type { CanvasSurface } from "../canvas/canvas-surface";
27
- import { tabOfPane } from "../canvas/canvas-surface";
27
+ import { activeMediaOfPane, tabOfPane } from "../canvas/canvas-surface";
28
28
  import { activeTab } from "../workspace/workspace";
29
29
  import { shell } from "../shell";
30
30
  import { componentRegistry } from "../files/components";
31
- import { getEffectiveMedia, getEffectiveStyle } from "../site-context";
31
+ import { getEffectiveHead, getEffectiveMedia, getEffectiveStyle } from "../site-context";
32
32
  import { parseMediaEntries } from "../utils/canvas-media";
33
33
  import { mediaDisplayName } from "./shared";
34
34
  import { buildStylebookDoc } from "./stylebook-doc";
35
35
  import { PROJECT_STYLES_TITLE } from "../style/project-styles";
36
+ import { loadStylebookSpecimens } from "../style/stylebook-specimens";
36
37
  import { mountStylebookCanvas, panToStylebookTag } from "../canvas/iframe-host";
37
38
  import stylebookMeta from "../../data/stylebook-meta.json";
38
39
  import type { CanvasPanelEntry } from "../canvas/canvas-utils";
@@ -124,11 +125,29 @@ function chromeBar(surface: CanvasSurface): HTMLElement {
124
125
  * a lit template: the hand-over used to be a `TemplateResult` per artboard, which meant the boards
125
126
  * could only be drawn by whoever was already rendering with lit. It is a mount seam instead — the
126
127
  * catalogue's bar is a node this module owns, placed in the empty box the stage draws for it, the
127
- * same way the Compare bar and the Document Header card are.
128
+ * same way the Compare bar and the writing banner are.
128
129
  *
129
130
  * @param {StylebookCtx} ctx
130
131
  * @returns {Promise<void>} Settles once the artboards are in the page
131
132
  */
133
+ /**
134
+ * The one breakpoint the specimen sheet is drawn at: the one the Context bar's size switcher names
135
+ * (its `activeMedia`, or the lens a split pane derives), else the base.
136
+ *
137
+ * It drew every declared breakpoint side by side, as Design does for a page, and fitting four
138
+ * artboards into one pane put a 1280px sheet at 24%, where no heading or paragraph can be read; a
139
+ * sheet of type specimens is read, not compared at a glance. One artboard at the breakpoint being
140
+ * styled is what the Styles workspace's board shows (Desktop · Tablet · Phone, one at a time), and
141
+ * it is the breakpoint a style edit lands on, because selecting a specimen writes `activeMedia`.
142
+ */
143
+ export function stylebookBoards<T extends { name: string }>(
144
+ boards: readonly T[],
145
+ active: string | null,
146
+ ): T[] {
147
+ const named = boards.filter((board) => board.name === (active ?? "base"));
148
+ return named.length > 0 ? named : boards.slice(0, 1);
149
+ }
150
+
132
151
  export async function renderStylebookMode(
133
152
  surface: CanvasSurface,
134
153
  ctx: StylebookCtx,
@@ -142,6 +161,9 @@ export async function renderStylebookMode(
142
161
  const tab = tabOfPane(surface.paneId);
143
162
  const filter = shell.stylebook.filter.toLowerCase();
144
163
  const { customizedOnly } = shell.stylebook;
164
+ const generation = surface.renderGeneration;
165
+ const registry = componentRegistry;
166
+ const specimensPending = loadStylebookSpecimens(registry);
145
167
 
146
168
  const effectiveMedia = getEffectiveMedia(tab?.doc.document?.$media);
147
169
  const { sizeBreakpoints, baseWidth } = parseMediaEntries(effectiveMedia);
@@ -185,7 +207,7 @@ export async function renderStylebookMode(
185
207
  ),
186
208
  ];
187
209
  } else {
188
- panelEntries = allPanelDefs.map((def) =>
210
+ panelEntries = stylebookBoards(allPanelDefs, activeMediaOfPane(surface.paneId)).map((def) =>
189
211
  ctx.canvasPanelEntry(def.name, `${def.displayName} (${def.width}px)`, false, def.width),
190
212
  );
191
213
  }
@@ -220,11 +242,21 @@ export async function renderStylebookMode(
220
242
  chromeHost.replaceChildren(chromeBarNode);
221
243
  }
222
244
 
245
+ /* What each component card is drawn with (started before the stage was drawn), asked once per
246
+ registry, so only the first paint after the project's components are read waits for it. A
247
+ render that began while it was being asked owns the stage now, and this one stops. */
248
+ const specimens = await specimensPending;
249
+ if (surface.renderGeneration !== generation) {
250
+ return;
251
+ }
252
+
223
253
  // ONE generated doc shared by every panel — per-panel @media differentiation comes from each
224
254
  // Iframe's real viewport width, not from a per-panel style flatten.
225
255
  const generated = buildStylebookDoc({
226
- components: componentRegistry,
256
+ components: registry,
257
+ specimens,
227
258
  customizedOnly: Boolean(customizedOnly),
259
+ effectiveHead: getEffectiveHead(tab?.doc.document?.$head),
228
260
  effectiveMedia,
229
261
  effectiveStyle: getEffectiveStyle(tab?.doc.document?.style),
230
262
  filter,
@@ -255,18 +287,23 @@ export async function renderStylebookMode(
255
287
  * @param {string | null} [media]
256
288
  */
257
289
  export function selectStylebookTag(tag: string, media?: string | null, { panCanvas = false } = {}) {
258
- shell.stylebook.selection = tag;
259
290
  const ui: Partial<TabUi> = { activeSelector: tag, rightTab: "style" };
260
291
  if (media !== undefined) {
261
292
  ui.activeMedia = media;
262
293
  }
294
+ // The session is written BEFORE the stylebook selection moves: writing `shell.stylebook.selection`
295
+ // Re-runs the Style panel's effect synchronously, and it should find `activeSelector` and the
296
+ // Breakpoint already in place.
263
297
  updateSession(activeTab.value, {
264
- // The ROOT path, not an empty selection: stylebook mode has always parked the selection on the
265
- // Document element while the Style tab edits a TAG, and widening the field to a list changed
266
- // Which literal spells that — `[[]]` is one selected path, the root — not what it means.
267
- selection: [[]],
298
+ // EMPTY, not the root. A specimen is not a node of the document, so no document path names
299
+ // What is selected; `stylebookTarget` is how the chrome learns the tag. Parking on the root
300
+ // `[[]]` made every reader of the document selection (the command bar, the Inspector header)
301
+ // Name the catalogue's root `div` while `h1` was being edited, and it is what a canvas hit on
302
+ // A specimen already left behind, so the Outline and the canvas now agree.
303
+ selection: [],
268
304
  ui,
269
305
  });
306
+ shell.stylebook.selection = tag;
270
307
 
271
308
  if (tag && panCanvas) {
272
309
  panToStylebookTag(tag);