@jxsuite/studio 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (419) hide show
  1. package/canvas.html +21 -0
  2. package/dist/chunks/Overlay.dev-qfjzkms8.js +23 -0
  3. package/dist/chunks/{Overlay.dev-cszx7yn5.js.map → Overlay.dev-qfjzkms8.js.map} +1 -1
  4. package/dist/chunks/{adapter-z8fkmbmv.js → adapter-qfnesn5v.js} +2 -2
  5. package/dist/chunks/{cf-settings-mmyv436d.js → cf-settings-73sh5z4p.js} +3 -3
  6. package/dist/chunks/{components-0hzentwq.js → components-2bpqp4mq.js} +5 -7
  7. package/dist/chunks/{components-0hzentwq.js.map → components-2bpqp4mq.js.map} +1 -1
  8. package/dist/chunks/content-source-34gnkbnn.js +38 -0
  9. package/dist/chunks/content-source-34gnkbnn.js.map +9 -0
  10. package/dist/chunks/convert-to-repeater-t8kxre5s.js +258 -0
  11. package/dist/chunks/convert-to-repeater-t8kxre5s.js.map +10 -0
  12. package/dist/chunks/extension-sections-6mqydz35.js +301 -0
  13. package/dist/chunks/extension-sections-6mqydz35.js.map +11 -0
  14. package/dist/chunks/files-8kn321h1.js +70 -0
  15. package/dist/chunks/files-8kn321h1.js.map +9 -0
  16. package/dist/chunks/{format-host-2c188n41.js → format-host-mkwsmt8d.js} +3 -3
  17. package/dist/chunks/git-panel-tjbr191d.js +51 -0
  18. package/dist/chunks/git-panel-tjbr191d.js.map +9 -0
  19. package/dist/chunks/{index-baeg2x3y.js → index-7pxchcce.js} +4 -3
  20. package/dist/chunks/{index-baeg2x3y.js.map → index-7pxchcce.js.map} +3 -3
  21. package/dist/chunks/{jx-validate-qx8degj7.js → jx-validate-v6qgknrs.js} +3 -3
  22. package/dist/chunks/layers-panel-87pb25km.js +58 -0
  23. package/dist/chunks/layers-panel-87pb25km.js.map +9 -0
  24. package/dist/chunks/{monaco-setup-zjdp9zdw.js → monaco-setup-e0yh25j4.js} +4 -75
  25. package/dist/chunks/{monaco-setup-zjdp9zdw.js.map → monaco-setup-e0yh25j4.js.map} +3 -4
  26. package/dist/chunks/publish-panel-m0fcgdrt.js +21 -0
  27. package/dist/chunks/publish-panel-m0fcgdrt.js.map +9 -0
  28. package/dist/chunks/quick-search-rhs6cbsb.js +53 -0
  29. package/dist/chunks/quick-search-rhs6cbsb.js.map +9 -0
  30. package/dist/chunks/right-panel-zpdxd98t.js +37 -0
  31. package/dist/chunks/right-panel-zpdxd98t.js.map +9 -0
  32. package/dist/chunks/section-registry-zmckaxf4.js +30 -0
  33. package/dist/chunks/section-registry-zmckaxf4.js.map +9 -0
  34. package/dist/chunks/sp-overlay.dev-9ran0sfq.js +18 -0
  35. package/dist/chunks/sp-overlay.dev-9ran0sfq.js.map +9 -0
  36. package/dist/chunks/sp-popover.dev-rebmdncr.js +9 -0
  37. package/dist/chunks/sp-popover.dev-rebmdncr.js.map +9 -0
  38. package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js +15 -0
  39. package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js.map +9 -0
  40. package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js +15 -0
  41. package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js.map +9 -0
  42. package/dist/chunks/{sp-tray.dev-pb2fsd65.js → sp-tray.dev-ey59vfh7.js} +10 -8
  43. package/dist/chunks/{sp-tray.dev-pb2fsd65.js.map → sp-tray.dev-ey59vfh7.js.map} +2 -2
  44. package/dist/chunks/{studio-9qr6fq7p.js → studio-0rqqhrdy.js} +10 -378
  45. package/dist/chunks/{studio-9qr6fq7p.js.map → studio-0rqqhrdy.js.map} +4 -14
  46. package/dist/chunks/{studio-5x6tqqec.js → studio-2sj1jj3v.js} +10 -8
  47. package/dist/chunks/{studio-5x6tqqec.js.map → studio-2sj1jj3v.js.map} +2 -2
  48. package/dist/chunks/{studio-h3fw0wn8.js → studio-3fk1ac9z.js} +6 -4
  49. package/dist/chunks/{studio-h3fw0wn8.js.map → studio-3fk1ac9z.js.map} +2 -2
  50. package/dist/chunks/studio-41exgzhq.js +6690 -0
  51. package/dist/chunks/studio-41exgzhq.js.map +38 -0
  52. package/dist/chunks/{studio-7v2bpweq.js → studio-4mqb9a0j.js} +6 -4
  53. package/dist/chunks/{studio-7v2bpweq.js.map → studio-4mqb9a0j.js.map} +2 -2
  54. package/dist/chunks/studio-50k77cca.js +1787 -0
  55. package/dist/chunks/studio-50k77cca.js.map +18 -0
  56. package/dist/chunks/{studio-56v3zwk6.js → studio-6a0h7sne.js} +10 -8
  57. package/dist/chunks/{studio-56v3zwk6.js.map → studio-6a0h7sne.js.map} +2 -2
  58. package/dist/chunks/studio-6f0am8f2.js +53 -0
  59. package/dist/chunks/studio-6f0am8f2.js.map +10 -0
  60. package/dist/chunks/studio-6nmjc5qk.js +7002 -0
  61. package/dist/chunks/studio-6nmjc5qk.js.map +32 -0
  62. package/dist/chunks/studio-7afd21nw.js +67 -0
  63. package/dist/chunks/studio-7afd21nw.js.map +10 -0
  64. package/dist/chunks/{studio-xze4zrs1.js → studio-7bmdvzne.js} +2 -2
  65. package/dist/chunks/studio-7bmdvzne.js.map +10 -0
  66. package/dist/chunks/studio-8jpzqk5s.js +128 -0
  67. package/dist/chunks/studio-8jpzqk5s.js.map +10 -0
  68. package/dist/chunks/studio-94m77tgk.js +1482 -0
  69. package/dist/chunks/studio-94m77tgk.js.map +13 -0
  70. package/dist/chunks/studio-9je6w5sq.js +1000 -0
  71. package/dist/chunks/studio-9je6w5sq.js.map +16 -0
  72. package/dist/chunks/{studio-w7c6kvk7.js → studio-a7pzveq1.js} +2 -2
  73. package/dist/chunks/{studio-97qcgvdn.js → studio-adn0z1k3.js} +14 -8
  74. package/dist/chunks/{studio-97qcgvdn.js.map → studio-adn0z1k3.js.map} +3 -3
  75. package/dist/chunks/{studio-kr88ryr7.js → studio-bsxxx3x2.js} +17 -15
  76. package/dist/chunks/{studio-kr88ryr7.js.map → studio-bsxxx3x2.js.map} +7 -6
  77. package/dist/chunks/studio-bw5dz6km.js +608 -0
  78. package/dist/chunks/studio-bw5dz6km.js.map +21 -0
  79. package/dist/chunks/studio-c6s5getc.js +4232 -0
  80. package/dist/chunks/studio-c6s5getc.js.map +39 -0
  81. package/dist/chunks/studio-cjm7fdjf.js +451 -0
  82. package/dist/chunks/studio-cjm7fdjf.js.map +14 -0
  83. package/dist/chunks/{studio-cx91mnh8.js → studio-ckwz4d3x.js} +53 -53
  84. package/dist/chunks/{studio-cx91mnh8.js.map → studio-ckwz4d3x.js.map} +5 -5
  85. package/dist/chunks/studio-dg7zyt5x.js +28 -0
  86. package/dist/chunks/studio-dg7zyt5x.js.map +10 -0
  87. package/dist/chunks/studio-dzcyvvvz.js +166 -0
  88. package/dist/chunks/studio-dzcyvvvz.js.map +10 -0
  89. package/dist/chunks/{studio-7kqe41sa.js → studio-evkr5d3b.js} +15 -7
  90. package/dist/chunks/{studio-7kqe41sa.js.map → studio-evkr5d3b.js.map} +5 -4
  91. package/dist/chunks/studio-f12h6177.js +411 -0
  92. package/dist/chunks/studio-f12h6177.js.map +13 -0
  93. package/dist/chunks/studio-hbp1s8m9.js +1817 -0
  94. package/dist/chunks/studio-hbp1s8m9.js.map +14 -0
  95. package/dist/chunks/studio-k2sxjph5.js +15295 -0
  96. package/dist/chunks/studio-k2sxjph5.js.map +235 -0
  97. package/dist/chunks/studio-myje51t3.js +385 -0
  98. package/dist/chunks/studio-myje51t3.js.map +12 -0
  99. package/dist/chunks/studio-na6rwzhw.js +353 -0
  100. package/dist/chunks/studio-na6rwzhw.js.map +11 -0
  101. package/dist/chunks/{studio-4k0m4fmp.js → studio-p471gg5n.js} +126 -3
  102. package/dist/chunks/studio-p471gg5n.js.map +14 -0
  103. package/dist/chunks/{studio-9bjwf0d4.js → studio-rgwcpast.js} +5 -46
  104. package/dist/chunks/{studio-9bjwf0d4.js.map → studio-rgwcpast.js.map} +4 -5
  105. package/dist/chunks/{studio-hhj92gcr.js → studio-s519zc99.js} +3 -3
  106. package/dist/chunks/studio-sas7mt3k.js +75 -0
  107. package/dist/chunks/studio-sas7mt3k.js.map +10 -0
  108. package/dist/chunks/studio-t5wqwzdh.js +74 -0
  109. package/dist/chunks/studio-t5wqwzdh.js.map +10 -0
  110. package/dist/chunks/{studio-9qpspwfn.js → studio-temv5bw4.js} +5 -5
  111. package/dist/chunks/{studio-9qpspwfn.js.map → studio-temv5bw4.js.map} +1 -1
  112. package/dist/chunks/{studio-qkvt37c0.js → studio-tr20m8g8.js} +669 -18
  113. package/dist/chunks/studio-tr20m8g8.js.map +9 -0
  114. package/dist/chunks/{studio-ygzav7z5.js → studio-v96qfnww.js} +5514 -4291
  115. package/dist/chunks/studio-v96qfnww.js.map +54 -0
  116. package/dist/chunks/studio-vcetc91k.js +659 -0
  117. package/dist/chunks/studio-vcetc91k.js.map +10 -0
  118. package/dist/chunks/{studio-n9zmpxjg.js → studio-vmymjefp.js} +2972 -4937
  119. package/dist/chunks/studio-vmymjefp.js.map +98 -0
  120. package/dist/chunks/{studio-bghqfmea.js → studio-wwseqyw0.js} +2 -2
  121. package/dist/chunks/studio-x9hmy5kr.js +390 -0
  122. package/dist/chunks/studio-x9hmy5kr.js.map +10 -0
  123. package/dist/chunks/studio-xa0ce0n7.js +335 -0
  124. package/dist/chunks/studio-xa0ce0n7.js.map +10 -0
  125. package/dist/chunks/studio-xm3dbxvn.js +378 -0
  126. package/dist/chunks/studio-xm3dbxvn.js.map +19 -0
  127. package/dist/chunks/{studio-nqw433kv.js → studio-xmvbhg31.js} +2 -2
  128. package/dist/chunks/studio-zv37yrfa.js +1054 -0
  129. package/dist/chunks/studio-zv37yrfa.js.map +13 -0
  130. package/dist/chunks/{ws-client-q7hkz3j9.js → ws-client-654ts66j.js} +6 -4
  131. package/dist/chunks/ws-client-654ts66j.js.map +11 -0
  132. package/dist/iframe-entry.js +668 -230
  133. package/dist/studio.js +23711 -35185
  134. package/index.html +35 -4685
  135. package/package.json +17 -15
  136. package/src/about/about-modal.ts +42 -11
  137. package/src/browse/library-commands.ts +240 -0
  138. package/src/browse/library-layouts.ts +369 -0
  139. package/src/browse/library-model.ts +396 -0
  140. package/src/browse/library-pane.ts +1049 -0
  141. package/src/browse/library-preview.ts +252 -0
  142. package/src/browse/library-source.ts +150 -0
  143. package/src/canvas/canvas-helpers.ts +33 -9
  144. package/src/canvas/canvas-live-render.ts +45 -29
  145. package/src/canvas/canvas-patcher.ts +151 -31
  146. package/src/canvas/canvas-perf.ts +46 -7
  147. package/src/canvas/canvas-render.ts +1092 -220
  148. package/src/canvas/canvas-surface.ts +240 -0
  149. package/src/canvas/canvas-utils.ts +1166 -124
  150. package/src/canvas/iframe-drop.ts +2 -1
  151. package/src/canvas/iframe-entry.ts +241 -4
  152. package/src/canvas/iframe-host.ts +1226 -143
  153. package/src/canvas/iframe-inline-edit.ts +31 -0
  154. package/src/canvas/iframe-interaction.ts +76 -16
  155. package/src/canvas/iframe-keys.ts +107 -45
  156. package/src/canvas/iframe-overlay.ts +38 -1
  157. package/src/canvas/iframe-protocol.ts +137 -2
  158. package/src/canvas/iframe-render.ts +70 -2
  159. package/src/canvas/iframe-slash.ts +6 -0
  160. package/src/canvas/path-mapping.ts +56 -6
  161. package/src/canvas/surface-registry.ts +292 -0
  162. package/src/collab/collab-commands.ts +244 -0
  163. package/src/collab/collab-session.ts +198 -32
  164. package/src/collab/collab-state.ts +28 -2
  165. package/src/collab/presence-chips.ts +100 -9
  166. package/src/commands/active-registry.ts +42 -0
  167. package/src/commands/app-commands.ts +176 -0
  168. package/src/commands/budget.ts +158 -0
  169. package/src/commands/command-args.ts +253 -0
  170. package/src/commands/context.ts +387 -0
  171. package/src/commands/defaults.ts +580 -0
  172. package/src/commands/keymap.ts +571 -0
  173. package/src/commands/levels.ts +345 -0
  174. package/src/commands/live-context.ts +193 -0
  175. package/src/commands/reference.ts +227 -0
  176. package/src/commands/registry.ts +293 -0
  177. package/src/component-props.ts +3 -2
  178. package/src/content/draft-state.ts +106 -0
  179. package/src/content/entry-commands.ts +282 -0
  180. package/src/content/entry-editor.ts +327 -0
  181. package/src/content/entry-fields.ts +116 -0
  182. package/src/content/entry-model.ts +175 -0
  183. package/src/editor/canvas-context-menu.ts +17 -11
  184. package/src/editor/canvas-slash-bridge.ts +11 -4
  185. package/src/editor/context-menu.ts +804 -204
  186. package/src/editor/convert-to-component.ts +31 -10
  187. package/src/editor/convert-to-repeater.ts +3 -2
  188. package/src/editor/inline-edit-apply.ts +5 -5
  189. package/src/editor/inline-edit.ts +86 -50
  190. package/src/editor/insert-zone-action.ts +1 -1
  191. package/src/editor/shortcuts.ts +1043 -329
  192. package/src/editor/slash-menu.ts +1 -0
  193. package/src/files/elements.ts +166 -0
  194. package/src/files/file-ops.ts +178 -31
  195. package/src/files/files.ts +898 -268
  196. package/src/files/fs-events.ts +21 -0
  197. package/src/files/media-meta.ts +203 -0
  198. package/src/files/media-paths.ts +141 -0
  199. package/src/files/media-upload.ts +7 -3
  200. package/src/files/media-usage.ts +189 -0
  201. package/src/github/github-auth.ts +235 -33
  202. package/src/github/github-publish.ts +80 -21
  203. package/src/grid/grid-controller.ts +152 -12
  204. package/src/grid/grid-layout.ts +225 -20
  205. package/src/grid/grid-open.ts +120 -0
  206. package/src/grid/grid-panel.ts +554 -39
  207. package/src/grid/grid-source.ts +27 -1
  208. package/src/grid/redirects-grid.ts +599 -0
  209. package/src/grid/redirects.ts +398 -0
  210. package/src/grid/sources/content-source.ts +108 -2
  211. package/src/i18n/i18n-commands.ts +322 -0
  212. package/src/new-project/add-repo-modal.ts +8 -10
  213. package/src/new-project/import-tab.ts +34 -9
  214. package/src/new-project/location-fields.ts +9 -1
  215. package/src/new-project/new-project-modal.ts +270 -262
  216. package/src/packages/jxsuite-update.ts +97 -48
  217. package/src/packages/pull-package-sync.ts +18 -9
  218. package/src/page-params.ts +2 -1
  219. package/src/panels/activity-bar.ts +152 -91
  220. package/src/panels/activity-panel.ts +481 -0
  221. package/src/panels/ai-chat/chat-markdown.ts +8 -3
  222. package/src/panels/ai-chat/chat-view.ts +245 -18
  223. package/src/panels/ai-chat/composer.ts +31 -5
  224. package/src/panels/ai-chat/sessions-view.ts +17 -10
  225. package/src/panels/ai-panel.ts +279 -120
  226. package/src/panels/block-action-bar.ts +1115 -224
  227. package/src/panels/bottom-dock.ts +337 -0
  228. package/src/panels/canvas-dnd-bridge.ts +37 -8
  229. package/src/panels/chat-panel.ts +29 -12
  230. package/src/panels/data-explorer.ts +254 -112
  231. package/src/panels/data-grid.ts +10 -4
  232. package/src/panels/dnd.ts +28 -51
  233. package/src/panels/editors.ts +434 -107
  234. package/src/panels/elements-panel.ts +66 -2
  235. package/src/panels/empty-state.ts +112 -0
  236. package/src/panels/events-panel.ts +596 -82
  237. package/src/panels/formula-workspace.ts +408 -218
  238. package/src/panels/frontmatter-fields.ts +51 -10
  239. package/src/panels/frontmatter-panel.ts +357 -79
  240. package/src/panels/git-panel.ts +375 -164
  241. package/src/panels/head-panel.ts +791 -85
  242. package/src/panels/i18n-panel.ts +592 -0
  243. package/src/panels/imports-panel.ts +95 -85
  244. package/src/panels/jump-bar.ts +584 -0
  245. package/src/panels/layers-panel.ts +1106 -328
  246. package/src/panels/left-panel.ts +109 -204
  247. package/src/panels/navigator-panels.ts +131 -0
  248. package/src/panels/overlays.ts +7 -2
  249. package/src/panels/pane-context.ts +1477 -0
  250. package/src/panels/pane-grid.ts +406 -0
  251. package/src/panels/panel-registry.ts +340 -0
  252. package/src/panels/panel-scheduler.ts +75 -0
  253. package/src/panels/problems-panel.ts +234 -0
  254. package/src/panels/properties-panel.ts +946 -1139
  255. package/src/panels/provenance.ts +258 -0
  256. package/src/panels/quick-search.ts +791 -122
  257. package/src/panels/right-panel.ts +228 -102
  258. package/src/panels/seo-modal.ts +395 -0
  259. package/src/panels/settings-pane.ts +203 -0
  260. package/src/panels/signals-panel.ts +354 -137
  261. package/src/panels/statement-editor.ts +41 -25
  262. package/src/panels/statusbar.ts +342 -106
  263. package/src/panels/style-panel.ts +974 -463
  264. package/src/panels/style-utils.ts +3 -3
  265. package/src/panels/stylebook-doc.ts +4 -2
  266. package/src/panels/stylebook-layers-panel.ts +3 -2
  267. package/src/panels/stylebook-panel.ts +51 -26
  268. package/src/panels/tab-strip.ts +1058 -78
  269. package/src/panels/target-line.ts +274 -0
  270. package/src/panels/toolbar.ts +631 -484
  271. package/src/panels/welcome-screen.ts +301 -198
  272. package/src/platform-errors.ts +26 -3
  273. package/src/platform.ts +96 -2
  274. package/src/platforms/cloud.ts +71 -8
  275. package/src/platforms/devserver.ts +92 -29
  276. package/src/publish/deploy-checklist.ts +383 -0
  277. package/src/publish/pages-service.ts +10 -1
  278. package/src/publish/publish-commands.ts +218 -0
  279. package/src/publish/publish-panel.ts +110 -16
  280. package/src/recent-projects.ts +3 -2
  281. package/src/services/a11y-report.ts +505 -0
  282. package/src/services/ai-models.ts +75 -2
  283. package/src/services/ai-project-tools.ts +29 -10
  284. package/src/services/ai-system-prompt.ts +53 -14
  285. package/src/services/ai-tools.ts +39 -3
  286. package/src/services/ai-writes.ts +154 -0
  287. package/src/services/announce.ts +97 -0
  288. package/src/services/automation.ts +424 -175
  289. package/src/services/cem-export.ts +9 -4
  290. package/src/services/clock.ts +61 -0
  291. package/src/services/document-assistant.ts +36 -8
  292. package/src/services/idle.ts +179 -0
  293. package/src/services/import-client.ts +26 -0
  294. package/src/services/monaco-buffer.ts +627 -0
  295. package/src/services/monaco-lazy.ts +36 -0
  296. package/src/services/notify.ts +271 -0
  297. package/src/services/profile.ts +155 -0
  298. package/src/services/references.ts +0 -0
  299. package/src/services/token-lint.ts +3 -2
  300. package/src/services/tool-executor.ts +53 -7
  301. package/src/services/trusted-types.ts +123 -0
  302. package/src/settings/contexts-section.ts +427 -0
  303. package/src/settings/contributed-section.ts +149 -11
  304. package/src/settings/css-vars-editor.ts +306 -349
  305. package/src/settings/defs-editor.ts +93 -34
  306. package/src/settings/dependencies-editor.ts +7 -7
  307. package/src/settings/extension-sections.ts +37 -5
  308. package/src/settings/general-settings.ts +204 -121
  309. package/src/settings/locales-section.ts +347 -0
  310. package/src/settings/preferences-accounts.ts +140 -0
  311. package/src/settings/preferences-dialog.ts +620 -0
  312. package/src/settings/preferences-keymap.ts +270 -0
  313. package/src/settings/project-sections.ts +260 -0
  314. package/src/settings/section-registry.ts +169 -0
  315. package/src/settings/settings-document.ts +385 -0
  316. package/src/shell.ts +1549 -0
  317. package/src/site-context.ts +45 -20
  318. package/src/state.ts +14 -275
  319. package/src/store.ts +88 -43
  320. package/src/studio.ts +790 -346
  321. package/src/style/live-preview.ts +36 -0
  322. package/src/style/project-styles.ts +349 -0
  323. package/src/style/token-ref.ts +123 -0
  324. package/src/tabs/patch-ops.ts +16 -4
  325. package/src/tabs/project-config.ts +416 -0
  326. package/src/tabs/selection.ts +323 -0
  327. package/src/tabs/tab.ts +182 -47
  328. package/src/tabs/transact.ts +209 -28
  329. package/src/types.ts +68 -13
  330. package/src/ui/ai-credentials-form.ts +39 -35
  331. package/src/ui/ai-managed-connect.ts +113 -0
  332. package/src/ui/dynamic-slot.ts +224 -81
  333. package/src/ui/expression-editor.ts +71 -63
  334. package/src/ui/field-input.ts +4 -6
  335. package/src/ui/field-row.ts +215 -38
  336. package/src/ui/form-controls.ts +194 -7
  337. package/src/ui/layers.ts +492 -69
  338. package/src/ui/media-picker.ts +115 -25
  339. package/src/ui/panel-resize.ts +109 -91
  340. package/src/ui/progress-modal.ts +131 -50
  341. package/src/ui/regions.ts +462 -0
  342. package/src/ui/schema-form.ts +229 -45
  343. package/src/ui/spectrum.ts +24 -8
  344. package/src/ui/timing.ts +49 -0
  345. package/src/ui/value-selector.ts +20 -0
  346. package/src/ui/value-source.ts +348 -0
  347. package/src/ui/virtual-window.ts +400 -0
  348. package/src/utils/edit-display.ts +3 -2
  349. package/src/utils/inherited-style.ts +67 -37
  350. package/src/view.ts +64 -78
  351. package/src/workspace/pane-derive.ts +1258 -0
  352. package/src/workspace/session.ts +317 -0
  353. package/src/workspace/workspace.ts +1345 -23
  354. package/styles/canvas.css +653 -0
  355. package/styles/forced-colors.css +106 -0
  356. package/styles/inspector.css +1454 -0
  357. package/styles/overlays.css +2704 -0
  358. package/styles/panels.css +1701 -0
  359. package/styles/shell.css +1423 -0
  360. package/styles/tokens.css +151 -0
  361. package/dist/chunks/Overlay.dev-cszx7yn5.js +0 -22
  362. package/dist/chunks/extension-sections-qct0gt8f.js +0 -531
  363. package/dist/chunks/extension-sections-qct0gt8f.js.map +0 -12
  364. package/dist/chunks/files-02zn5y24.js +0 -50
  365. package/dist/chunks/files-02zn5y24.js.map +0 -9
  366. package/dist/chunks/git-panel-mbb0y0hz.js +0 -28
  367. package/dist/chunks/git-panel-mbb0y0hz.js.map +0 -9
  368. package/dist/chunks/layers-panel-9qekmqk1.js +0 -26
  369. package/dist/chunks/layers-panel-9qekmqk1.js.map +0 -9
  370. package/dist/chunks/settings-modal-gj0hrah4.js +0 -29
  371. package/dist/chunks/settings-modal-gj0hrah4.js.map +0 -9
  372. package/dist/chunks/sp-overlay.dev-earn5as8.js +0 -17
  373. package/dist/chunks/sp-overlay.dev-earn5as8.js.map +0 -9
  374. package/dist/chunks/sp-popover.dev-frxtfejn.js +0 -8
  375. package/dist/chunks/sp-popover.dev-frxtfejn.js.map +0 -9
  376. package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js +0 -14
  377. package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js.map +0 -9
  378. package/dist/chunks/sp-tooltip.dev-a9fywesm.js +0 -21
  379. package/dist/chunks/sp-tooltip.dev-a9fywesm.js.map +0 -10
  380. package/dist/chunks/studio-4k0m4fmp.js.map +0 -13
  381. package/dist/chunks/studio-568nx4t5.js +0 -469
  382. package/dist/chunks/studio-568nx4t5.js.map +0 -14
  383. package/dist/chunks/studio-9smfzqhc.js +0 -19
  384. package/dist/chunks/studio-9smfzqhc.js.map +0 -10
  385. package/dist/chunks/studio-asvf0j9e.js +0 -429
  386. package/dist/chunks/studio-asvf0j9e.js.map +0 -13
  387. package/dist/chunks/studio-d77qm3pk.js +0 -3427
  388. package/dist/chunks/studio-d77qm3pk.js.map +0 -26
  389. package/dist/chunks/studio-j6gqyjf4.js +0 -1854
  390. package/dist/chunks/studio-j6gqyjf4.js.map +0 -18
  391. package/dist/chunks/studio-n9zmpxjg.js.map +0 -115
  392. package/dist/chunks/studio-qkvt37c0.js.map +0 -9
  393. package/dist/chunks/studio-rq0vxb19.js +0 -3744
  394. package/dist/chunks/studio-rq0vxb19.js.map +0 -22
  395. package/dist/chunks/studio-wd6ewdvd.js +0 -853
  396. package/dist/chunks/studio-wd6ewdvd.js.map +0 -12
  397. package/dist/chunks/studio-xq0t7n5t.js +0 -140
  398. package/dist/chunks/studio-xq0t7n5t.js.map +0 -10
  399. package/dist/chunks/studio-xze4zrs1.js.map +0 -10
  400. package/dist/chunks/studio-ygzav7z5.js.map +0 -46
  401. package/dist/chunks/studio-zmy7241e.js +0 -399
  402. package/dist/chunks/studio-zmy7241e.js.map +0 -12
  403. package/dist/chunks/ws-client-q7hkz3j9.js.map +0 -11
  404. package/src/browse/browse-modal.ts +0 -69
  405. package/src/browse/browse.ts +0 -904
  406. package/src/canvas/canvas-diff.ts +0 -216
  407. package/src/canvas/nested-site-style.ts +0 -58
  408. package/src/new-project/design-fields.ts +0 -264
  409. package/src/new-project/templates.ts +0 -61
  410. package/src/panels/tab-bar.ts +0 -548
  411. package/src/settings/settings-modal.ts +0 -203
  412. /package/dist/chunks/{adapter-z8fkmbmv.js.map → adapter-qfnesn5v.js.map} +0 -0
  413. /package/dist/chunks/{cf-settings-mmyv436d.js.map → cf-settings-73sh5z4p.js.map} +0 -0
  414. /package/dist/chunks/{format-host-2c188n41.js.map → format-host-mkwsmt8d.js.map} +0 -0
  415. /package/dist/chunks/{jx-validate-qx8degj7.js.map → jx-validate-v6qgknrs.js.map} +0 -0
  416. /package/dist/chunks/{studio-w7c6kvk7.js.map → studio-a7pzveq1.js.map} +0 -0
  417. /package/dist/chunks/{studio-hhj92gcr.js.map → studio-s519zc99.js.map} +0 -0
  418. /package/dist/chunks/{studio-bghqfmea.js.map → studio-wwseqyw0.js.map} +0 -0
  419. /package/dist/chunks/{studio-nqw433kv.js.map → studio-xmvbhg31.js.map} +0 -0
@@ -1,399 +0,0 @@
1
- import {
2
- classMap,
3
- ifDefined,
4
- styleMap
5
- } from "./studio-cx91mnh8.js";
6
- import {
7
- live
8
- } from "./studio-nqw433kv.js";
9
- import {
10
- isRef
11
- } from "./studio-rq0vxb19.js";
12
- import {
13
- html,
14
- nothing
15
- } from "./studio-5x5774ak.js";
16
-
17
- // src/ui/field-row.ts
18
- function renderFieldRow({
19
- prop,
20
- label,
21
- hasValue,
22
- onClear,
23
- widget,
24
- labelExtra,
25
- span,
26
- warning
27
- }) {
28
- return html`
29
- <div
30
- class=${classMap({ "style-row": true, "style-row--warning": Boolean(warning) })}
31
- data-prop=${prop}
32
- style=${span === 2 ? "grid-column: 1 / -1" : ""}
33
- >
34
- <div class="style-row-label">
35
- ${hasValue && onClear ? html`<span
36
- class="set-dot"
37
- title="Clear ${prop}"
38
- @click=${(e) => {
39
- e.stopPropagation();
40
- onClear();
41
- }}
42
- ></span>` : nothing}
43
- <sp-field-label size="s" title=${prop}>${label}</sp-field-label>
44
- ${labelExtra ?? nothing}
45
- </div>
46
- ${widget}
47
- </div>
48
- `;
49
- }
50
-
51
- // src/ui/schema-form.ts
52
- var controlRegistry = new Map;
53
- function registerFormControl(name, control) {
54
- controlRegistry.set(name, control);
55
- }
56
- var NULL_CONTEXT = {
57
- resolvePointer: () => {}
58
- };
59
- function resolveFormEnum(enumDef, ctx, scope) {
60
- if (Array.isArray(enumDef)) {
61
- return enumDef;
62
- }
63
- let pointer;
64
- if (enumDef && typeof enumDef === "object") {
65
- const ref = enumDef.$ref;
66
- if (typeof ref === "string") {
67
- pointer = ref;
68
- }
69
- } else if (typeof enumDef === "string") {
70
- pointer = enumDef;
71
- }
72
- if (pointer === undefined || !ctx) {
73
- return;
74
- }
75
- const resolved = ctx.resolvePointer(pointer, scope);
76
- if (Array.isArray(resolved)) {
77
- return resolved.map(String);
78
- }
79
- if (resolved && typeof resolved === "object") {
80
- return Object.keys(resolved);
81
- }
82
- return;
83
- }
84
- function parseNumericField(raw, integer) {
85
- if (raw.trim() === "") {
86
- return Number.NaN;
87
- }
88
- return integer ? Math.trunc(Number(raw)) : Number(raw);
89
- }
90
- function refTextField(key, refVal, onChange) {
91
- return html`<sp-textfield
92
- size="s"
93
- label=${key}
94
- placeholder=${key}
95
- .value=${live(refVal)}
96
- @change=${(e) => {
97
- const v = e.target.value.trim();
98
- onChange(v ? { $ref: v } : undefined);
99
- }}
100
- ></sp-textfield>`;
101
- }
102
- function renderInlineField(key, schema, value, onChange, ctx, scope) {
103
- if (isRef(value)) {
104
- return refTextField(key, value.$ref, onChange);
105
- }
106
- const enumValues = resolveFormEnum(schema.enum, ctx, scope);
107
- if (enumValues) {
108
- return html`<sp-picker
109
- size="s"
110
- label=${key}
111
- value=${value !== undefined ? String(value) : "__none__"}
112
- @change=${(e) => onChange(e.target.value === "__none__" ? undefined : e.target.value)}
113
- >
114
- <sp-menu-item value="__none__">—</sp-menu-item>
115
- ${enumValues.map((v) => html`<sp-menu-item value=${v}>${v}</sp-menu-item>`)}
116
- </sp-picker>`;
117
- }
118
- if (schema.type === "boolean") {
119
- return html`<sp-switch
120
- size="s"
121
- ?checked=${Boolean(value)}
122
- @change=${(e) => onChange(e.target.checked)}
123
- >${key}</sp-switch
124
- >`;
125
- }
126
- if (schema.type === "integer" || schema.type === "number") {
127
- return html`<sp-number-field
128
- size="s"
129
- label=${key}
130
- .value=${value !== undefined ? value : nothing}
131
- step=${schema.type === "integer" ? "1" : nothing}
132
- @change=${(e) => {
133
- const parsed = parseNumericField(e.target.value, schema.type === "integer");
134
- onChange(Number.isNaN(parsed) ? undefined : parsed);
135
- }}
136
- ></sp-number-field>`;
137
- }
138
- return html`<sp-textfield
139
- size="s"
140
- label=${key}
141
- placeholder=${key}
142
- .value=${value ?? ""}
143
- @input=${(e) => onChange(e.target.value || undefined)}
144
- ></sp-textfield>`;
145
- }
146
- function renderJsonTextField(currentValue, ps, commit) {
147
- let debounce;
148
- return html`<sp-textfield
149
- multiline
150
- size="s"
151
- style="min-height:40px"
152
- .value=${currentValue !== undefined ? JSON.stringify(currentValue, null, 2) : ""}
153
- placeholder=${ps.default !== undefined ? JSON.stringify(ps.default) : nothing}
154
- @input=${(e) => {
155
- clearTimeout(debounce);
156
- debounce = setTimeout(() => {
157
- try {
158
- commit(JSON.parse(e.target.value));
159
- } catch {}
160
- }, 500);
161
- }}
162
- ></sp-textfield>`;
163
- }
164
- function renderPropertyControl(prop, ps, value, required, opts, ctx) {
165
- const currentValue = value[prop];
166
- const commit = (next) => opts.onChange({ [prop]: next });
167
- const controlArgs = {
168
- ctx,
169
- key: prop,
170
- onChange: commit,
171
- rerender: opts.rerender,
172
- schema: ps,
173
- value: currentValue
174
- };
175
- const overrideName = opts.ui?.[prop]?.control;
176
- if (overrideName) {
177
- const custom = controlRegistry.get(overrideName);
178
- if (custom) {
179
- return custom(controlArgs);
180
- }
181
- }
182
- if (isRef(currentValue) && ps.format !== "json-schema" && ps.type !== "object" && ps.type !== "array") {
183
- const binding = controlRegistry.get("binding");
184
- if (binding) {
185
- return binding(controlArgs);
186
- }
187
- return refTextField(prop, currentValue.$ref, commit);
188
- }
189
- const enumValues = resolveFormEnum(opts.ui?.[prop]?.enum ?? ps.enum, ctx, value);
190
- if (enumValues) {
191
- return html`
192
- <sp-picker
193
- size="s"
194
- value=${currentValue !== undefined ? String(currentValue) : ps.default !== undefined ? String(ps.default) : "__none__"}
195
- @change=${(e) => commit(e.target.value === "__none__" ? undefined : e.target.value)}
196
- >
197
- ${!required.has(prop) ? html`<sp-menu-item value="__none__">—</sp-menu-item>` : nothing}
198
- ${enumValues.map((val) => html`<sp-menu-item value=${val}>${val}</sp-menu-item>`)}
199
- </sp-picker>
200
- `;
201
- }
202
- if (ps.type === "boolean") {
203
- return html`<sp-checkbox
204
- ?checked=${currentValue ?? ps.default ?? false}
205
- @change=${(e) => commit(e.target.checked)}
206
- ></sp-checkbox>`;
207
- }
208
- if (ps.type === "integer" || ps.type === "number") {
209
- let debounce2;
210
- return html`<sp-number-field
211
- size="s"
212
- min=${ifDefined(ps.minimum)}
213
- max=${ifDefined(ps.maximum)}
214
- step=${ps.type === "integer" ? "1" : nothing}
215
- .value=${currentValue !== undefined ? currentValue : nothing}
216
- placeholder=${ps.default != null ? String(ps.default) : nothing}
217
- @change=${(e) => {
218
- clearTimeout(debounce2);
219
- debounce2 = setTimeout(() => {
220
- const parsed = parseNumericField(e.target.value, ps.type === "integer");
221
- commit(Number.isNaN(parsed) ? undefined : parsed);
222
- }, 400);
223
- }}
224
- ></sp-number-field>`;
225
- }
226
- if (ps.format === "json-schema") {
227
- const hasValue = currentValue && typeof currentValue === "object" && Object.keys(currentValue).length > 0;
228
- const cv = currentValue;
229
- const isSchemaRef = hasValue && cv.$ref;
230
- let debounce2;
231
- return html`
232
- <div class="schema-param-editor">
233
- ${hasValue && !isSchemaRef && cv.properties ? html`
234
- <div style="display:flex;flex-wrap:wrap;gap:3px;margin-bottom:4px">
235
- ${Object.entries(cv.properties).map(([k, v]) => html`
236
- <span
237
- style="background:var(--bg);padding:1px 6px;border-radius:var(--radius);font-size:10px;color:var(--fg-dim)"
238
- >${k}: ${v.type ?? "any"}</span
239
- >
240
- `)}
241
- </div>
242
- ` : nothing}
243
- <sp-textfield
244
- multiline
245
- size="s"
246
- style=${styleMap({
247
- fontFamily: "monospace",
248
- fontSize: "11px",
249
- minHeight: hasValue ? "80px" : "40px"
250
- })}
251
- .value=${currentValue !== undefined ? JSON.stringify(currentValue, null, 2) : ""}
252
- placeholder=${ps.description ?? "JSON Schema defining the data shape…"}
253
- @input=${(e) => {
254
- clearTimeout(debounce2);
255
- debounce2 = setTimeout(() => {
256
- try {
257
- commit(JSON.parse(e.target.value));
258
- } catch {}
259
- }, 500);
260
- }}
261
- ></sp-textfield>
262
- </div>
263
- `;
264
- }
265
- if (ps.type === "array" && ps.items?.type === "object" && ps.items?.properties) {
266
- const rows = Array.isArray(currentValue) ? currentValue : [];
267
- const itemProps = ps.items.properties;
268
- return html`
269
- <div class="array-object-field">
270
- ${rows.map((row, idx) => html`
271
- <div
272
- class="array-object-row"
273
- style="display:flex;gap:4px;align-items:center;margin-bottom:4px"
274
- >
275
- ${Object.entries(itemProps).map(([propKey, propSchema]) => renderInlineField(propKey, propSchema, row[propKey], (val) => {
276
- const updated = [...rows];
277
- updated[idx] = { ...updated[idx], [propKey]: val };
278
- commit(updated);
279
- }, ctx, value))}
280
- <sp-action-button
281
- quiet
282
- size="s"
283
- @click=${() => {
284
- const updated = rows.filter((_, i) => i !== idx);
285
- commit(updated.length > 0 ? updated : undefined);
286
- opts.rerender?.();
287
- }}
288
- >
289
- <sp-icon-delete slot="icon"></sp-icon-delete>
290
- </sp-action-button>
291
- </div>
292
- `)}
293
- <sp-action-button
294
- quiet
295
- size="s"
296
- @click=${(e) => {
297
- e.stopPropagation();
298
- const newRow = {};
299
- for (const [k, v] of Object.entries(itemProps)) {
300
- if (v.default !== undefined) {
301
- newRow[k] = v.default;
302
- }
303
- }
304
- commit([...rows, newRow]);
305
- opts.rerender?.();
306
- }}
307
- >+ Add</sp-action-button
308
- >
309
- </div>
310
- `;
311
- }
312
- if (ps.type === "array" || ps.type === "object") {
313
- return renderJsonTextField(currentValue, ps, commit);
314
- }
315
- let debounce;
316
- const params = ctx.params ?? [];
317
- const ph = ps.default !== undefined ? String(ps.default) : ps.examples?.[0] ?? "";
318
- return html`<div style="display:flex;gap:4px;align-items:center">
319
- <sp-textfield
320
- size="s"
321
- style="flex:1"
322
- .value=${currentValue ?? ""}
323
- placeholder=${ph || nothing}
324
- title=${ps.description || nothing}
325
- @input=${(e) => {
326
- clearTimeout(debounce);
327
- debounce = setTimeout(() => commit(e.target.value || undefined), 400);
328
- }}
329
- ></sp-textfield>
330
- ${params.length > 0 ? html`<sp-action-button
331
- quiet
332
- size="s"
333
- title="Bind to route param"
334
- @click=${() => {
335
- commit({ $ref: `#/$params/${params[0]}` });
336
- opts.rerender?.();
337
- }}
338
- ><sp-icon-link slot="icon"></sp-icon-link
339
- ></sp-action-button>` : nothing}
340
- </div>`;
341
- }
342
- function renderForm(schema, value, opts) {
343
- const required = new Set(schema.required);
344
- const ctx = opts.context ?? NULL_CONTEXT;
345
- const propertyFields = Object.entries(schema.properties ?? {}).map(([prop, ps]) => {
346
- const labelText = prop + (required.has(prop) ? " *" : "");
347
- return renderFieldRow({
348
- hasValue: false,
349
- label: labelText,
350
- prop: ps.name || prop,
351
- widget: renderPropertyControl(prop, ps, value, required, opts, ctx)
352
- });
353
- });
354
- return html`${propertyFields}`;
355
- }
356
-
357
- // src/services/context-resolver.ts
358
- var PARAM_SEGMENT = /^\{@(\w+)\}$/;
359
- function resolveContextPointer(pointer, opts) {
360
- if (!pointer.startsWith("#/$context/")) {
361
- return;
362
- }
363
- const segments = [];
364
- for (const raw of pointer.slice("#/$context/".length).split("/")) {
365
- const match = raw.match(PARAM_SEGMENT);
366
- if (match) {
367
- const value = opts.scope?.[match[1]];
368
- if (typeof value !== "string" && typeof value !== "number") {
369
- return;
370
- }
371
- const substituted = String(value);
372
- if (!substituted) {
373
- return;
374
- }
375
- segments.push(substituted);
376
- } else {
377
- segments.push(raw);
378
- }
379
- }
380
- if (segments[0] === "$formats") {
381
- if (segments.length !== 1) {
382
- return;
383
- }
384
- return (opts.formats ?? []).map((format) => format.name);
385
- }
386
- let node = opts.projectConfig;
387
- for (const segment of segments) {
388
- if (node === null || typeof node !== "object") {
389
- return;
390
- }
391
- node = node[segment];
392
- }
393
- return node;
394
- }
395
-
396
- export { renderFieldRow, registerFormControl, renderForm, resolveContextPointer };
397
-
398
- //# debugId=C2BB6E7E97CDF54564756E2164756E21
399
- //# sourceMappingURL=studio-zmy7241e.js.map
@@ -1,12 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/ui/field-row.ts", "../src/ui/schema-form.ts", "../src/services/context-resolver.ts"],
4
- "sourcesContent": [
5
- "/// <reference lib=\"dom\" />\n/**\n * Field-row.js — Universal field row layout for all Studio panels.\n *\n * Renders the consistent pattern: indicator dot + label + widget slot. Used by style panel,\n * attributes panel, frontmatter panel, signals panel, etc.\n */\n\nimport { html, nothing } from \"lit-html\";\nimport { classMap } from \"lit-html/directives/class-map.js\";\n\n/**\n * Render a universal field row with indicator dot, label, and widget.\n *\n * @param {{\n * prop: string;\n * label: string;\n * hasValue: boolean;\n * onClear?: () => void;\n * widget: unknown;\n * labelExtra?: unknown;\n * span?: number;\n * warning?: boolean;\n * }} opts\n * @returns {import(\"lit-html\").TemplateResult}\n */\nexport function renderFieldRow({\n prop,\n label,\n hasValue,\n onClear,\n widget,\n labelExtra,\n span,\n warning,\n}: {\n prop: string;\n label: string;\n hasValue: boolean;\n onClear?: () => void;\n widget: unknown;\n /** Rendered after the label inside the label cell (e.g. the dynamic-slot mode button). */\n labelExtra?: unknown;\n span?: number;\n warning?: boolean;\n}) {\n return html`\n <div\n class=${classMap({ \"style-row\": true, \"style-row--warning\": Boolean(warning) })}\n data-prop=${prop}\n style=${span === 2 ? \"grid-column: 1 / -1\" : \"\"}\n >\n <div class=\"style-row-label\">\n ${\n hasValue && onClear\n ? html`<span\n class=\"set-dot\"\n title=\"Clear ${prop}\"\n @click=${(e: Event) => {\n e.stopPropagation();\n onClear();\n }}\n ></span>`\n : nothing\n }\n <sp-field-label size=\"s\" title=${prop}>${label}</sp-field-label>\n ${labelExtra ?? nothing}\n </div>\n ${widget}\n </div>\n `;\n}\n",
6
- "/// <reference lib=\"dom\" />\n/**\n * Schema-form — reusable JSON-Schema → form rendering engine, extracted from the signals panel.\n *\n * Maps schema property types to Spectrum controls (enum → picker, boolean → checkbox,\n * number/integer → number-field, `json-schema` format → multiline JSON editor, array-of-objects →\n * multi-row inline form, other array/object → JSON text field, default → textfield). Hosts commit\n * edits through a single `onChange(patch)` callback; dynamic enum choices and `$ref` bindings\n * resolve through a {@link SchemaFormContext}. Custom controls register by name via\n * {@link registerFormControl} and are consulted first for `ui` overrides.\n */\n\nimport { html, nothing } from \"lit-html\";\nimport { ifDefined } from \"lit-html/directives/if-defined.js\";\nimport { live } from \"lit-html/directives/live.js\";\nimport { styleMap } from \"lit-html/directives/style-map.js\";\nimport { isRef } from \"@jxsuite/schema/guards\";\nimport { renderFieldRow } from \"./field-row\";\nimport type { TemplateResult } from \"lit-html\";\n\n/** A (possibly nested) JSON Schema node, covering both object and property level keys. */\nexport interface JsonSchema {\n type?: string;\n properties?: Record<string, JsonSchema>;\n required?: string[];\n description?: string;\n enum?: unknown;\n default?: unknown;\n format?: string;\n minimum?: number;\n maximum?: number;\n examples?: string[];\n name?: string;\n items?: JsonSchema;\n}\n\n/** Host-provided context threaded to every control. */\nexport interface SchemaFormContext {\n /** Resolve a `#/$context/…` pointer (or legacy sentinel) against the host's project config. */\n resolvePointer: (pointer: string, scope?: Record<string, unknown>) => unknown;\n /** Route params available for `$ref` bindings (e.g. from the document path). */\n params?: string[] | undefined;\n /** Unique prefix for per-field ephemeral UI state (e.g. the binding control's custom mode). */\n fieldKeyPrefix?: string | undefined;\n /**\n * Commit hook for the \"secret\" control: stores the VALUE in the platform's secret store (never\n * project.json) and returns the derived env-var NAME, which the control persists to the field\n * instead of the value.\n */\n commitSecret?: ((key: string, value: string) => string | Promise<string>) | undefined;\n}\n\n/** Arguments passed to a registered form control. */\nexport interface SchemaFormControlArgs {\n key: string;\n schema: JsonSchema;\n value: unknown;\n onChange: (next: unknown) => void;\n ctx: SchemaFormContext;\n rerender?: (() => void) | undefined;\n}\n\nexport type SchemaFormControl = (args: SchemaFormControlArgs) => TemplateResult;\n\n/** Options for {@link renderForm}. */\nexport interface RenderFormOptions {\n onChange: (patch: Record<string, unknown>) => void;\n context?: SchemaFormContext | undefined;\n /**\n * Per-field overrides from `$studio.settings.entry.ui`: a registered control name, and/or an\n * `enum` source (choice list or `{ \"$ref\": \"#/$context/<pointer>\" }`) layered over the field\n * schema — fragments stay valid JSON Schema while descriptors add dynamic choices.\n */\n ui?: Record<string, { control?: string; enum?: unknown }> | undefined;\n rerender?: (() => void) | undefined;\n}\n\n// ─── Control registry ────────────────────────────────────────────────────────\n\nconst controlRegistry = new Map<string, SchemaFormControl>();\n\n/** Register (or replace) a named form control. */\nexport function registerFormControl(name: string, control: SchemaFormControl): void {\n controlRegistry.set(name, control);\n}\n\n/** Look up a registered form control by name. */\nexport function getFormControl(name: string): SchemaFormControl | undefined {\n return controlRegistry.get(name);\n}\n\n/** Inert context used when a host renders a form without one. */\nconst NULL_CONTEXT: SchemaFormContext = {\n resolvePointer: () => {\n // Nothing to resolve against without a host context\n },\n};\n\n// ─── Enum resolution ─────────────────────────────────────────────────────────\n\n/**\n * Resolve a schema enum definition to concrete choices. Plain arrays pass through; `$ref` objects\n * and sentinel strings resolve through the context's pointer resolver, applying object →\n * `Object.keys` and string[] → itself.\n *\n * @param {unknown} enumDef\n * @param {SchemaFormContext | undefined} ctx\n * @param {Record<string, unknown>} [scope] - Scope for `{@param}` substitution (the form value)\n * @returns {string[] | undefined}\n */\nexport function resolveFormEnum(\n enumDef: unknown,\n ctx?: SchemaFormContext,\n scope?: Record<string, unknown>,\n): string[] | undefined {\n if (Array.isArray(enumDef)) {\n return enumDef as string[];\n }\n let pointer: string | undefined;\n if (enumDef && typeof enumDef === \"object\") {\n const ref = (enumDef as Record<string, unknown>).$ref;\n if (typeof ref === \"string\") {\n pointer = ref;\n }\n } else if (typeof enumDef === \"string\") {\n // Legacy sentinel strings (e.g. \"$contentTypes\") resolve through the host's pointer resolver\n pointer = enumDef;\n }\n if (pointer === undefined || !ctx) {\n return undefined;\n }\n const resolved = ctx.resolvePointer(pointer, scope);\n if (Array.isArray(resolved)) {\n return resolved.map(String);\n }\n if (resolved && typeof resolved === \"object\") {\n return Object.keys(resolved);\n }\n return undefined;\n}\n\n// ─── Field helpers ───────────────────────────────────────────────────────────\n\n/** Parse a numeric field value, returning NaN for blank input (so callers can treat it as unset). */\nexport function parseNumericField(raw: string, integer: boolean): number {\n if (raw.trim() === \"\") {\n return Number.NaN;\n }\n return integer ? Math.trunc(Number(raw)) : Number(raw);\n}\n\n/** Plain textfield editing a `{ $ref }` value directly — the fallback when no binding control. */\nfunction refTextField(key: string, refVal: string, onChange: (next: unknown) => void) {\n return html`<sp-textfield\n size=\"s\"\n label=${key}\n placeholder=${key}\n .value=${live(refVal)}\n @change=${(e: Event) => {\n const v = (e.target as HTMLInputElement).value.trim();\n onChange(v ? { $ref: v } : undefined);\n }}\n ></sp-textfield>`;\n}\n\n/**\n * Render a single inline field within an array-of-objects row. Dispatches by schema type: enum →\n * picker, boolean → switch, number → number-field, else → textfield.\n *\n * @param {string} key\n * @param {JsonSchema} schema\n * @param {unknown} value\n * @param {(val: unknown) => void} onChange\n * @param {SchemaFormContext | undefined} ctx\n * @param {Record<string, unknown>} [scope] - Scope for dependent enum refs (the parent form value)\n */\nexport function renderInlineField(\n key: string,\n schema: JsonSchema,\n value: unknown,\n onChange: (val: unknown) => void,\n ctx?: SchemaFormContext,\n scope?: Record<string, unknown>,\n) {\n if (isRef(value)) {\n return refTextField(key, value.$ref, onChange);\n }\n const enumValues = resolveFormEnum(schema.enum, ctx, scope);\n\n if (enumValues) {\n return html`<sp-picker\n size=\"s\"\n label=${key}\n value=${value !== undefined ? String(value) : \"__none__\"}\n @change=${(e: Event) =>\n onChange(\n (e.target as HTMLInputElement).value === \"__none__\"\n ? undefined\n : (e.target as HTMLInputElement).value,\n )}\n >\n <sp-menu-item value=\"__none__\">—</sp-menu-item>\n ${enumValues.map((v: string) => html`<sp-menu-item value=${v}>${v}</sp-menu-item>`)}\n </sp-picker>`;\n }\n if (schema.type === \"boolean\") {\n return html`<sp-switch\n size=\"s\"\n ?checked=${Boolean(value)}\n @change=${(e: Event) => onChange((e.target as HTMLInputElement).checked)}\n >${key}</sp-switch\n >`;\n }\n if (schema.type === \"integer\" || schema.type === \"number\") {\n return html`<sp-number-field\n size=\"s\"\n label=${key}\n .value=${value !== undefined ? value : nothing}\n step=${schema.type === \"integer\" ? \"1\" : nothing}\n @change=${(e: Event) => {\n const parsed = parseNumericField(\n (e.target as HTMLInputElement).value,\n schema.type === \"integer\",\n );\n onChange(Number.isNaN(parsed) ? undefined : parsed);\n }}\n ></sp-number-field>`;\n }\n return html`<sp-textfield\n size=\"s\"\n label=${key}\n placeholder=${key}\n .value=${value ?? \"\"}\n @input=${(e: Event) => onChange((e.target as HTMLInputElement).value || undefined)}\n ></sp-textfield>`;\n}\n\n/** Render a debounced multiline JSON text field for array/object schema properties. */\nfunction renderJsonTextField(currentValue: unknown, ps: JsonSchema, commit: (v: unknown) => void) {\n /** @type {ReturnType<typeof setTimeout> | undefined} */\n let debounce: ReturnType<typeof setTimeout> | undefined;\n return html`<sp-textfield\n multiline\n size=\"s\"\n style=\"min-height:40px\"\n .value=${currentValue !== undefined ? JSON.stringify(currentValue, null, 2) : \"\"}\n placeholder=${ps.default !== undefined ? JSON.stringify(ps.default) : nothing}\n @input=${(e: Event) => {\n clearTimeout(debounce);\n debounce = setTimeout(() => {\n try {\n commit(JSON.parse((e.target as HTMLInputElement).value) as unknown);\n } catch {}\n }, 500);\n }}\n ></sp-textfield>`;\n}\n\n// ─── Per-property control dispatch ───────────────────────────────────────────\n\n/** Render the widget for one schema property, honoring registered-control overrides. */\nfunction renderPropertyControl(\n prop: string,\n ps: JsonSchema,\n value: Record<string, unknown>,\n required: Set<string>,\n opts: RenderFormOptions,\n ctx: SchemaFormContext,\n): TemplateResult {\n const currentValue = value[prop];\n const commit = (next: unknown) => opts.onChange({ [prop]: next });\n const controlArgs: SchemaFormControlArgs = {\n ctx,\n key: prop,\n onChange: commit,\n rerender: opts.rerender,\n schema: ps,\n value: currentValue,\n };\n\n // Explicit ui override → consult the control registry first\n const overrideName = opts.ui?.[prop]?.control;\n if (overrideName) {\n const custom = controlRegistry.get(overrideName);\n if (custom) {\n return custom(controlArgs);\n }\n }\n\n if (\n isRef(currentValue) &&\n ps.format !== \"json-schema\" &&\n ps.type !== \"object\" &&\n ps.type !== \"array\"\n ) {\n const binding = controlRegistry.get(\"binding\");\n if (binding) {\n return binding(controlArgs);\n }\n return refTextField(prop, currentValue.$ref, commit);\n }\n\n const enumValues = resolveFormEnum(opts.ui?.[prop]?.enum ?? ps.enum, ctx, value);\n if (enumValues) {\n return html`\n <sp-picker\n size=\"s\"\n value=${\n currentValue !== undefined\n ? String(currentValue)\n : ps.default !== undefined\n ? String(ps.default)\n : \"__none__\"\n }\n @change=${(e: Event) =>\n commit(\n (e.target as HTMLInputElement).value === \"__none__\"\n ? undefined\n : (e.target as HTMLInputElement).value,\n )}\n >\n ${!required.has(prop) ? html`<sp-menu-item value=\"__none__\">—</sp-menu-item>` : nothing}\n ${enumValues.map((val: string) => html`<sp-menu-item value=${val}>${val}</sp-menu-item>`)}\n </sp-picker>\n `;\n }\n if (ps.type === \"boolean\") {\n return html`<sp-checkbox\n ?checked=${currentValue ?? ps.default ?? false}\n @change=${(e: Event) => commit((e.target as HTMLInputElement).checked)}\n ></sp-checkbox>`;\n }\n if (ps.type === \"integer\" || ps.type === \"number\") {\n /** @type {ReturnType<typeof setTimeout> | undefined} */\n let debounce: ReturnType<typeof setTimeout> | undefined;\n return html`<sp-number-field\n size=\"s\"\n min=${ifDefined(ps.minimum)}\n max=${ifDefined(ps.maximum)}\n step=${ps.type === \"integer\" ? \"1\" : nothing}\n .value=${currentValue !== undefined ? currentValue : nothing}\n placeholder=${ps.default != null ? String(ps.default) : nothing}\n @change=${(e: Event) => {\n clearTimeout(debounce);\n debounce = setTimeout(() => {\n const parsed = parseNumericField(\n (e.target as HTMLInputElement).value,\n ps.type === \"integer\",\n );\n commit(Number.isNaN(parsed) ? undefined : parsed);\n }, 400);\n }}\n ></sp-number-field>`;\n }\n if (ps.format === \"json-schema\") {\n const hasValue =\n currentValue && typeof currentValue === \"object\" && Object.keys(currentValue).length > 0;\n const cv = currentValue as Record<string, unknown>;\n const isSchemaRef = hasValue && cv.$ref;\n /** @type {ReturnType<typeof setTimeout> | undefined} */\n let debounce: ReturnType<typeof setTimeout> | undefined;\n return html`\n <div class=\"schema-param-editor\">\n ${\n hasValue && !isSchemaRef && cv.properties\n ? html`\n <div style=\"display:flex;flex-wrap:wrap;gap:3px;margin-bottom:4px\">\n ${Object.entries(cv.properties as Record<string, Record<string, unknown>>).map(\n ([k, v]) => html`\n <span\n style=\"background:var(--bg);padding:1px 6px;border-radius:var(--radius);font-size:10px;color:var(--fg-dim)\"\n >${k}: ${v.type ?? \"any\"}</span\n >\n `,\n )}\n </div>\n `\n : nothing\n }\n <sp-textfield\n multiline\n size=\"s\"\n style=${styleMap({\n fontFamily: \"monospace\",\n fontSize: \"11px\",\n minHeight: hasValue ? \"80px\" : \"40px\",\n })}\n .value=${currentValue !== undefined ? JSON.stringify(currentValue, null, 2) : \"\"}\n placeholder=${ps.description ?? \"JSON Schema defining the data shape…\"}\n @input=${(e: Event) => {\n clearTimeout(debounce);\n debounce = setTimeout(() => {\n try {\n commit(JSON.parse((e.target as HTMLInputElement).value) as unknown);\n } catch {}\n }, 500);\n }}\n ></sp-textfield>\n </div>\n `;\n }\n if (ps.type === \"array\" && ps.items?.type === \"object\" && ps.items?.properties) {\n // Array of objects with defined schema → multi-row inline form\n const rows: Record<string, unknown>[] = Array.isArray(currentValue)\n ? (currentValue as Record<string, unknown>[])\n : [];\n const itemProps = ps.items.properties;\n return html`\n <div class=\"array-object-field\">\n ${rows.map(\n (row: Record<string, unknown>, idx: number) => html`\n <div\n class=\"array-object-row\"\n style=\"display:flex;gap:4px;align-items:center;margin-bottom:4px\"\n >\n ${Object.entries(itemProps).map(([propKey, propSchema]) =>\n renderInlineField(\n propKey,\n propSchema,\n row[propKey],\n (val) => {\n const updated = [...rows];\n updated[idx] = { ...updated[idx], [propKey]: val };\n commit(updated);\n },\n ctx,\n value,\n ),\n )}\n <sp-action-button\n quiet\n size=\"s\"\n @click=${() => {\n const updated = rows.filter((_: unknown, i: number) => i !== idx);\n commit(updated.length > 0 ? updated : undefined);\n opts.rerender?.();\n }}\n >\n <sp-icon-delete slot=\"icon\"></sp-icon-delete>\n </sp-action-button>\n </div>\n `,\n )}\n <sp-action-button\n quiet\n size=\"s\"\n @click=${(e: Event) => {\n e.stopPropagation();\n const newRow: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(itemProps)) {\n if (v.default !== undefined) {\n newRow[k] = v.default;\n }\n }\n commit([...rows, newRow]);\n opts.rerender?.();\n }}\n >+ Add</sp-action-button\n >\n </div>\n `;\n }\n if (ps.type === \"array\" || ps.type === \"object\") {\n return renderJsonTextField(currentValue, ps, commit) as TemplateResult;\n }\n\n /** @type {ReturnType<typeof setTimeout> | undefined} */\n let debounce: ReturnType<typeof setTimeout> | undefined;\n const params = ctx.params ?? [];\n const ph = ps.default !== undefined ? String(ps.default) : (ps.examples?.[0] ?? \"\");\n return html`<div style=\"display:flex;gap:4px;align-items:center\">\n <sp-textfield\n size=\"s\"\n style=\"flex:1\"\n .value=${currentValue ?? \"\"}\n placeholder=${ph || nothing}\n title=${ps.description || nothing}\n @input=${(e: Event) => {\n clearTimeout(debounce);\n debounce = setTimeout(() => commit((e.target as HTMLInputElement).value || undefined), 400);\n }}\n ></sp-textfield>\n ${\n params.length > 0\n ? html`<sp-action-button\n quiet\n size=\"s\"\n title=\"Bind to route param\"\n @click=${() => {\n commit({ $ref: `#/$params/${params[0]}` });\n opts.rerender?.();\n }}\n ><sp-icon-link slot=\"icon\"></sp-icon-link\n ></sp-action-button>`\n : nothing\n }\n </div>`;\n}\n\n// ─── Form rendering ──────────────────────────────────────────────────────────\n\n/**\n * Render form field rows for a JSON Schema's `properties`, committing edits through `opts.onChange`\n * as single-key patches (`undefined` values mean \"unset the key\").\n *\n * @param {JsonSchema} schema\n * @param {Record<string, unknown>} value - The record being edited\n * @param {RenderFormOptions} opts\n * @returns {TemplateResult}\n */\nexport function renderForm(\n schema: JsonSchema,\n value: Record<string, unknown>,\n opts: RenderFormOptions,\n): TemplateResult {\n const required = new Set(schema.required);\n const ctx = opts.context ?? NULL_CONTEXT;\n\n const propertyFields = Object.entries(schema.properties ?? {}).map(([prop, ps]) => {\n const labelText = prop + (required.has(prop) ? \" *\" : \"\");\n return renderFieldRow({\n hasValue: false,\n label: labelText,\n prop: ps.name || prop,\n widget: renderPropertyControl(prop, ps, value, required, opts, ctx),\n });\n });\n\n return html`${propertyFields}`;\n}\n",
7
- "/**\n * Context resolver — generic `#/$context/<pointer>` resolution over the project config\n * (specs/extensions.md §9.1).\n *\n * Pointers walk the project config segment by segment. `{@param}` segments substitute values from a\n * caller-provided scope (e.g. the form's current value record), and the `$formats` virtual root\n * resolves to the registered format names instead of a project.json key.\n */\n\n/** Options for {@link resolveContextPointer}. */\nexport interface ResolveContextOptions {\n /** The project configuration object the pointer walks over. */\n projectConfig: Record<string, unknown>;\n /** Scope record supplying `{@param}` substitutions (e.g. the enclosing form value). */\n scope?: Record<string, unknown> | undefined;\n /** Registered formats backing the `$formats` virtual root. */\n formats?: { name: string }[] | undefined;\n}\n\n/** Matches a `{@param}` pointer segment, capturing the param name. */\nconst PARAM_SEGMENT = /^\\{@(\\w+)\\}$/;\n\n/**\n * Resolve a `#/$context/<seg>/<seg>…` pointer.\n *\n * - `{@param}` segments substitute from `opts.scope`; an unresolvable param yields `undefined`.\n * - The `$formats` virtual root returns the format names from `opts.formats`.\n * - Every other pointer is a plain JSON-pointer walk over `opts.projectConfig` — no key is\n * special-cased, so both legacy (`contentTypes`) and newer (`content`) sections resolve alike.\n *\n * @param {string} pointer\n * @param {ResolveContextOptions} opts\n * @returns {unknown} The resolved value, or `undefined` when the pointer does not resolve.\n */\nexport function resolveContextPointer(pointer: string, opts: ResolveContextOptions): unknown {\n if (!pointer.startsWith(\"#/$context/\")) {\n return undefined;\n }\n\n const segments: string[] = [];\n for (const raw of pointer.slice(\"#/$context/\".length).split(\"/\")) {\n const match = raw.match(PARAM_SEGMENT);\n if (match) {\n const value = opts.scope?.[match[1]!];\n if (typeof value !== \"string\" && typeof value !== \"number\") {\n return undefined;\n }\n const substituted = String(value);\n if (!substituted) {\n return undefined;\n }\n segments.push(substituted);\n } else {\n segments.push(raw);\n }\n }\n\n if (segments[0] === \"$formats\") {\n if (segments.length !== 1) {\n return undefined;\n }\n return (opts.formats ?? []).map((format) => format.name);\n }\n\n let node: unknown = opts.projectConfig;\n for (const segment of segments) {\n if (node === null || typeof node !== \"object\") {\n return undefined;\n }\n node = (node as Record<string, unknown>)[segment];\n }\n return node;\n}\n"
8
- ],
9
- "mappings": "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",
10
- "debugId": "C2BB6E7E97CDF54564756E2164756E21",
11
- "names": []
12
- }
@@ -1,11 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../node_modules/y-protocols/sync.js", "../../collab/src/ws-client.ts"],
4
- "sourcesContent": [
5
- "/**\n * @module sync-protocol\n */\n\nimport * as encoding from 'lib0/encoding'\nimport * as decoding from 'lib0/decoding'\nimport * as Y from 'yjs'\n\n/**\n * @typedef {Map<number, number>} StateMap\n */\n\n/**\n * Core Yjs defines two message types:\n * • YjsSyncStep1: Includes the State Set of the sending client. When received, the client should reply with YjsSyncStep2.\n * • YjsSyncStep2: Includes all missing structs and the complete delete set. When received, the client is assured that it\n * received all information from the remote client.\n *\n * In a peer-to-peer network, you may want to introduce a SyncDone message type. Both parties should initiate the connection\n * with SyncStep1. When a client received SyncStep2, it should reply with SyncDone. When the local client received both\n * SyncStep2 and SyncDone, it is assured that it is synced to the remote client.\n *\n * In a client-server model, you want to handle this differently: The client should initiate the connection with SyncStep1.\n * When the server receives SyncStep1, it should reply with SyncStep2 immediately followed by SyncStep1. The client replies\n * with SyncStep2 when it receives SyncStep1. Optionally the server may send a SyncDone after it received SyncStep2, so the\n * client knows that the sync is finished. There are two reasons for this more elaborated sync model: 1. This protocol can\n * easily be implemented on top of http and websockets. 2. The server should only reply to requests, and not initiate them.\n * Therefore it is necessary that the client initiates the sync.\n *\n * Construction of a message:\n * [messageType : varUint, message definition..]\n *\n * Note: A message does not include information about the room name. This must to be handled by the upper layer protocol!\n *\n * stringify[messageType] stringifies a message definition (messageType is already read from the bufffer)\n */\n\nexport const messageYjsSyncStep1 = 0\nexport const messageYjsSyncStep2 = 1\nexport const messageYjsUpdate = 2\n\n/**\n * Create a sync step 1 message based on the state of the current shared document.\n *\n * @param {encoding.Encoder} encoder\n * @param {Y.Doc} doc\n */\nexport const writeSyncStep1 = (encoder, doc) => {\n encoding.writeVarUint(encoder, messageYjsSyncStep1)\n const sv = Y.encodeStateVector(doc)\n encoding.writeVarUint8Array(encoder, sv)\n}\n\n/**\n * @param {encoding.Encoder} encoder\n * @param {Y.Doc} doc\n * @param {Uint8Array} [encodedStateVector]\n */\nexport const writeSyncStep2 = (encoder, doc, encodedStateVector) => {\n encoding.writeVarUint(encoder, messageYjsSyncStep2)\n encoding.writeVarUint8Array(encoder, Y.encodeStateAsUpdate(doc, encodedStateVector))\n}\n\n/**\n * Read SyncStep1 message and reply with SyncStep2.\n *\n * @param {decoding.Decoder} decoder The reply to the received message\n * @param {encoding.Encoder} encoder The received message\n * @param {Y.Doc} doc\n */\nexport const readSyncStep1 = (decoder, encoder, doc) =>\n writeSyncStep2(encoder, doc, decoding.readVarUint8Array(decoder))\n\n/**\n * Read and apply Structs and then DeleteStore to a y instance.\n *\n * @param {decoding.Decoder} decoder\n * @param {Y.Doc} doc\n * @param {any} transactionOrigin\n * @param {(error:Error)=>any} [errorHandler]\n */\nexport const readSyncStep2 = (decoder, doc, transactionOrigin, errorHandler) => {\n try {\n Y.applyUpdate(doc, decoding.readVarUint8Array(decoder), transactionOrigin)\n } catch (error) {\n if (errorHandler != null) errorHandler(/** @type {Error} */ (error))\n // This catches errors that are thrown by event handlers\n console.error('Caught error while handling a Yjs update', error)\n }\n}\n\n/**\n * @param {encoding.Encoder} encoder\n * @param {Uint8Array} update\n */\nexport const writeUpdate = (encoder, update) => {\n encoding.writeVarUint(encoder, messageYjsUpdate)\n encoding.writeVarUint8Array(encoder, update)\n}\n\n/**\n * Read and apply Structs and then DeleteStore to a y instance.\n *\n * @param {decoding.Decoder} decoder\n * @param {Y.Doc} doc\n * @param {any} transactionOrigin\n * @param {(error:Error)=>any} [errorHandler]\n */\nexport const readUpdate = readSyncStep2\n\n/**\n * @param {decoding.Decoder} decoder A message received from another client\n * @param {encoding.Encoder} encoder The reply message. Does not need to be sent if empty.\n * @param {Y.Doc} doc\n * @param {any} transactionOrigin\n * @param {(error:Error)=>any} [errorHandler] Optional error handler that catches errors when reading Yjs messages.\n */\nexport const readSyncMessage = (decoder, encoder, doc, transactionOrigin, errorHandler) => {\n const messageType = decoding.readVarUint(decoder)\n switch (messageType) {\n case messageYjsSyncStep1:\n readSyncStep1(decoder, encoder, doc)\n break\n case messageYjsSyncStep2:\n readSyncStep2(decoder, doc, transactionOrigin, errorHandler)\n break\n case messageYjsUpdate:\n readUpdate(decoder, doc, transactionOrigin, errorHandler)\n break\n default:\n throw new Error('Unknown message type')\n }\n return messageType\n}\n",
6
- "/**\n * The browser half of the wire envelope: one WebSocket per project, multiplexing every open\n * document. `createWsCollabConnection` owns the socket (exponential-backoff reconnect, re-open of\n * live docs on reconnect), the shared project-level Awareness, and per-doc sync state;\n * `openDoc(path)` hands out {@link CollabHandle}s for `StudioPlatform.collab`.\n */\n\nimport * as Y from \"yjs\";\nimport * as decoding from \"lib0/decoding\";\nimport * as encoding from \"lib0/encoding\";\nimport {\n applyAwarenessUpdate,\n Awareness,\n encodeAwarenessUpdate,\n removeAwarenessStates,\n} from \"y-protocols/awareness\";\nimport * as syncProtocol from \"y-protocols/sync\";\nimport { decodeFrame, encodeFrame } from \"./envelope.ts\";\nimport type { CollabFrame, ControlMessage } from \"./envelope.ts\";\nimport type { CollabHandle, CollabIdentity, CollabStatus } from \"./provider.ts\";\n\n/** The subset of the WebSocket API the connection uses (injectable for tests). */\nexport interface WsLike {\n binaryType: string;\n readyState: number;\n send: (data: Uint8Array) => void;\n close: () => void;\n onopen: (() => void) | null;\n onclose: (() => void) | null;\n onerror: (() => void) | null;\n onmessage: ((event: { data: unknown }) => void) | null;\n}\n\nexport interface WsCollabConnectionOptions {\n /** The ws(s):// endpoint for this project's collab socket. */\n url: string;\n /** WebSocket constructor override (tests, non-browser runtimes). */\n webSocketImpl?: new (url: string) => WsLike;\n /**\n * Called when the server refuses a doc with content-not-loaded: hydrate the file over HTTP (which\n * caches it server-side) so the retry can seed. One retry per open.\n */\n hydratePath?: (path: string) => Promise<void>;\n /** Give up on an openDoc after this long (falls back to solo editing). */\n openTimeoutMs?: number;\n /** Initial reconnect backoff (doubles to 30s). */\n reconnectDelayMs?: number;\n}\n\nexport interface WsCollabConnection {\n openDoc: (path: string) => Promise<CollabHandle | null>;\n status: () => CollabStatus;\n destroy: () => void;\n}\n\nconst WS_OPEN = 1;\n\ninterface DocEntry {\n doc: Y.Doc;\n epoch: number;\n opened: boolean;\n synced: boolean;\n hydrated: boolean;\n resolveOpen: ((ok: boolean) => void) | null;\n resolveSynced: () => void;\n whenSynced: Promise<void>;\n resetCbs: Set<() => void>;\n pendingFlush: Set<() => void>;\n handleDestroyed: boolean;\n /** Latest room-level dirty state from the server (survives reconnect on the same entry). */\n dirty: boolean;\n dirtyCbs: Set<(dirty: boolean) => void>;\n}\n\nexport function createWsCollabConnection(options: WsCollabConnectionOptions): WsCollabConnection {\n const WebSocketCtor =\n options.webSocketImpl ?? (globalThis.WebSocket as unknown as new (url: string) => WsLike);\n const openTimeoutMs = options.openTimeoutMs ?? 10_000;\n const docs = new Map<string, DocEntry>();\n const statusCbs = new Set<(status: CollabStatus) => void>();\n const awarenessDoc = new Y.Doc();\n const awareness = new Awareness(awarenessDoc);\n /* Clear the constructor's implicit {} state: it sits at clock 0, which applyAwarenessUpdate on\n the receiving side can never apply (currClock 0 < clock 0 is false) — publishing it would\n poison the server's controlled-id tracking. Real state arrives via setLocalState (clock ≥ 2). */\n awareness.setLocalState(null);\n\n let socket: WsLike | null = null;\n let identity: CollabIdentity | null = null;\n let status: CollabStatus = \"connecting\";\n let destroyed = false;\n let retryMs = options.reconnectDelayMs ?? 1000;\n let retryTimer: ReturnType<typeof setTimeout> | null = null;\n\n const setStatus = (next: CollabStatus) => {\n if (status === next) {\n return;\n }\n status = next;\n for (const cb of statusCbs) {\n cb(next);\n }\n };\n\n const sendFrame = (frame: CollabFrame) => {\n if (socket && socket.readyState === WS_OPEN) {\n try {\n socket.send(encodeFrame(frame));\n } catch {\n // The close handler owns recovery.\n }\n }\n };\n\n const sendOpen = (path: string) => {\n sendFrame({ message: { path, type: \"open\" }, type: \"control\" });\n };\n\n // Local awareness changes always go to the wire (queued sends drop; awareness self-heals on\n // Reconnect via the full-state re-publish below).\n awareness.on(\n \"update\",\n (changes: { added: number[]; updated: number[]; removed: number[] }, origin: unknown) => {\n if (origin === \"remote\") {\n return;\n }\n const changed = [...changes.added, ...changes.updated, ...changes.removed];\n sendFrame({ body: encodeAwarenessUpdate(awareness, changed), type: \"awareness\" });\n },\n );\n\n const handleControl = (message: ControlMessage) => {\n switch (message.type) {\n case \"hello\": {\n identity = {\n color: message.color,\n login: message.login,\n permission: message.permission,\n ...(message.name === undefined ? {} : { name: message.name }),\n ...(message.avatarUrl === undefined ? {} : { avatarUrl: message.avatarUrl }),\n };\n return;\n }\n case \"opened\": {\n const entry = docs.get(message.path);\n if (!entry) {\n return;\n }\n if (entry.opened && entry.epoch !== message.epoch) {\n // The doc's history moved while we were away: this handle is dead.\n fireReset(message.path, entry);\n return;\n }\n entry.epoch = message.epoch;\n entry.opened = true;\n entry.resolveOpen?.(true);\n entry.resolveOpen = null;\n // Client-initiated step1 (mirrors y-websocket): fetch the server's state.\n const body = encoding.createEncoder();\n syncProtocol.writeSyncStep1(body, entry.doc);\n sendFrame({\n body: encoding.toUint8Array(body),\n epoch: entry.epoch,\n path: message.path,\n type: \"doc-sync\",\n });\n return;\n }\n case \"doc-reset\": {\n const entry = docs.get(message.path);\n if (entry) {\n fireReset(message.path, entry);\n }\n return;\n }\n case \"flush-ack\": {\n const entry = docs.get(message.path);\n if (entry) {\n for (const resolve of entry.pendingFlush) {\n resolve();\n }\n entry.pendingFlush.clear();\n }\n return;\n }\n case \"doc-dirty\": {\n const entry = docs.get(message.path);\n if (entry) {\n entry.dirty = message.dirty;\n for (const cb of entry.dirtyCbs) {\n cb(message.dirty);\n }\n }\n return;\n }\n case \"error\": {\n if (!message.path) {\n return;\n }\n const entry = docs.get(message.path);\n if (!entry) {\n return;\n }\n if (message.code === \"content-not-loaded\" && options.hydratePath && !entry.hydrated) {\n entry.hydrated = true;\n void options.hydratePath(message.path).then(\n () => sendOpen(message.path!),\n () => {\n entry.resolveOpen?.(false);\n entry.resolveOpen = null;\n },\n );\n return;\n }\n if (!entry.opened) {\n // Fatal refusal (binary-file, too-large, unresolved hydration): fall back to solo.\n entry.resolveOpen?.(false);\n entry.resolveOpen = null;\n }\n break;\n }\n default: {\n break;\n }\n }\n };\n\n const handleDocSync = (path: string, epoch: number, body: Uint8Array) => {\n const entry = docs.get(path);\n if (!entry || !entry.opened || entry.epoch !== epoch) {\n return;\n }\n const decoder = decoding.createDecoder(body);\n const reply = encoding.createEncoder();\n const messageType = syncProtocol.readSyncMessage(decoder, reply, entry.doc, \"remote\");\n if (encoding.length(reply) > 0) {\n sendFrame({ body: encoding.toUint8Array(reply), epoch, path, type: \"doc-sync\" });\n }\n if (messageType === syncProtocol.messageYjsSyncStep2 && !entry.synced) {\n entry.synced = true;\n entry.resolveSynced();\n }\n };\n\n const fireReset = (path: string, entry: DocEntry) => {\n docs.delete(path);\n entry.resolveOpen?.(false);\n entry.resolveOpen = null;\n for (const cb of entry.resetCbs) {\n cb();\n }\n entry.doc.destroy();\n };\n\n const connect = () => {\n if (destroyed) {\n return;\n }\n setStatus(\"connecting\");\n const ws = new WebSocketCtor(options.url);\n socket = ws;\n ws.binaryType = \"arraybuffer\";\n /* Each connect() builds a FRESH socket; single-assignment handlers are the point (and keep\n the injectable WsLike test surface minimal). */\n // oxlint-disable-next-line unicorn/prefer-add-event-listener\n ws.onopen = () => {\n retryMs = options.reconnectDelayMs ?? 1000;\n setStatus(\"connected\");\n // Re-open every live doc and re-publish our awareness state.\n for (const path of docs.keys()) {\n sendOpen(path);\n }\n const local = awareness.getLocalState();\n if (local !== null) {\n sendFrame({\n body: encodeAwarenessUpdate(awareness, [awareness.clientID]),\n type: \"awareness\",\n });\n }\n };\n // oxlint-disable-next-line unicorn/prefer-add-event-listener\n ws.onmessage = (event) => {\n const raw = event.data;\n const data =\n raw instanceof ArrayBuffer ? new Uint8Array(raw) : raw instanceof Uint8Array ? raw : null;\n if (!data) {\n return;\n }\n let frame: CollabFrame;\n try {\n frame = decodeFrame(data);\n } catch {\n return;\n }\n switch (frame.type) {\n case \"control\": {\n handleControl(frame.message);\n return;\n }\n case \"doc-sync\": {\n handleDocSync(frame.path, frame.epoch, frame.body);\n return;\n }\n case \"awareness\": {\n applyAwarenessUpdate(awareness, frame.body, \"remote\");\n break;\n }\n default: {\n break;\n }\n }\n };\n // oxlint-disable-next-line unicorn/prefer-add-event-listener\n ws.onclose = () => {\n if (destroyed) {\n return;\n }\n setStatus(\"offline\");\n for (const entry of docs.values()) {\n entry.opened = false;\n }\n retryTimer = setTimeout(connect, retryMs);\n retryMs = Math.min(retryMs * 2, 30_000);\n };\n // oxlint-disable-next-line unicorn/prefer-add-event-listener\n ws.onerror = () => {\n // The close handler follows and owns retry.\n };\n };\n connect();\n\n return {\n destroy() {\n if (destroyed) {\n return;\n }\n destroyed = true;\n if (retryTimer) {\n clearTimeout(retryTimer);\n }\n removeAwarenessStates(awareness, [awareness.clientID], \"destroy\");\n awareness.destroy();\n awarenessDoc.destroy();\n for (const [path, entry] of docs) {\n entry.resolveOpen?.(false);\n entry.doc.destroy();\n docs.delete(path);\n }\n socket?.close();\n },\n\n async openDoc(path: string): Promise<CollabHandle | null> {\n if (destroyed) {\n return null;\n }\n const existing = docs.get(path);\n if (existing && !existing.handleDestroyed) {\n return null;\n }\n let resolveSynced: () => void = () => {};\n const whenSynced = new Promise<void>((resolve) => {\n resolveSynced = resolve;\n });\n const entry: DocEntry = {\n dirty: false,\n dirtyCbs: new Set(),\n doc: new Y.Doc(),\n epoch: 0,\n handleDestroyed: false,\n hydrated: false,\n opened: false,\n pendingFlush: new Set(),\n resetCbs: new Set(),\n resolveOpen: null,\n resolveSynced,\n synced: false,\n whenSynced,\n };\n docs.set(path, entry);\n\n // Local doc updates go to the wire (unless they came FROM the wire).\n entry.doc.on(\"update\", (update: Uint8Array, origin: unknown) => {\n if (origin === \"remote\" || !entry.opened) {\n return;\n }\n const body = encoding.createEncoder();\n syncProtocol.writeUpdate(body, update);\n sendFrame({\n body: encoding.toUint8Array(body),\n epoch: entry.epoch,\n path,\n type: \"doc-sync\",\n });\n });\n\n const openedOk = await new Promise<boolean>((resolve) => {\n entry.resolveOpen = resolve;\n const timer = setTimeout(() => {\n entry.resolveOpen = null;\n resolve(false);\n }, openTimeoutMs);\n entry.resolveOpen = (ok) => {\n clearTimeout(timer);\n resolve(ok);\n };\n sendOpen(path);\n });\n if (!openedOk) {\n if (docs.get(path) === entry) {\n docs.delete(path);\n }\n entry.doc.destroy();\n return null;\n }\n\n const handle: CollabHandle = {\n awareness,\n destroy: () => {\n if (entry.handleDestroyed) {\n return;\n }\n entry.handleDestroyed = true;\n if (docs.get(path) === entry) {\n docs.delete(path);\n sendFrame({ path, type: \"doc-close\" });\n }\n entry.doc.destroy();\n },\n doc: entry.doc,\n flush: () =>\n new Promise<void>((resolve) => {\n entry.pendingFlush.add(resolve);\n sendFrame({ message: { path, type: \"flush\" }, type: \"control\" });\n }),\n identity: () => identity,\n onDirty: (cb) => {\n entry.dirtyCbs.add(cb);\n // Deliver current state synchronously: the server's open-handshake `doc-dirty` may have\n // Already landed before the caller subscribes, and it must not miss the initial value.\n cb(entry.dirty);\n return () => entry.dirtyCbs.delete(cb);\n },\n onReset: (cb) => {\n entry.resetCbs.add(cb);\n return () => entry.resetCbs.delete(cb);\n },\n onStatus: (cb) => {\n statusCbs.add(cb);\n return () => statusCbs.delete(cb);\n },\n whenSynced: entry.whenSynced,\n };\n return handle;\n },\n\n status: () => status,\n };\n}\n"
7
- ],
8
- "mappings": "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",
9
- "debugId": "A5C0E576FD4383EF64756E2164756E21",
10
- "names": []
11
- }
@@ -1,69 +0,0 @@
1
- /// <reference lib="dom" />
2
- /**
3
- * Browse modal — fullscreen overlay for the project file browser (Manage view). Opens via toolbar
4
- * button; selecting a file closes the modal and opens it in the editor.
5
- */
6
-
7
- import { html } from "lit-html";
8
- import { ref } from "lit-html/directives/ref.js";
9
- import { renderBrowse } from "./browse";
10
- import { openFileInTab } from "../files/files";
11
- import { openModal } from "../ui/layers";
12
-
13
- let _handle: ReturnType<typeof openModal> | null = null;
14
-
15
- let _escHandler: ((e: KeyboardEvent) => void) | null = null;
16
-
17
- export function openBrowseModal() {
18
- if (_handle) {
19
- return;
20
- }
21
-
22
- _escHandler = (e: KeyboardEvent) => {
23
- if (e.key === "Escape") {
24
- closeBrowseModal();
25
- }
26
- };
27
- document.addEventListener("keydown", _escHandler, true);
28
-
29
- const tpl = html`
30
- <sp-underlay open @close=${closeBrowseModal}></sp-underlay>
31
- <div class="browse-modal">
32
- <div class="browse-modal-header">
33
- <h2 class="browse-modal-title">Manage Files</h2>
34
- <sp-action-button quiet size="s" @click=${closeBrowseModal} title="Close">
35
- <sp-icon-close slot="icon"></sp-icon-close>
36
- </sp-action-button>
37
- </div>
38
- <div
39
- class="browse-modal-content"
40
- ${ref((el) => {
41
- if (el) {
42
- requestAnimationFrame(() => {
43
- void renderBrowse(el as HTMLElement, {
44
- openFile: (path: string) => {
45
- closeBrowseModal();
46
- void openFileInTab(path);
47
- },
48
- });
49
- });
50
- }
51
- })}
52
- ></div>
53
- </div>
54
- `;
55
-
56
- _handle = openModal(tpl);
57
- }
58
-
59
- export function closeBrowseModal() {
60
- if (!_handle) {
61
- return;
62
- }
63
- if (_escHandler) {
64
- document.removeEventListener("keydown", _escHandler, true);
65
- _escHandler = null;
66
- }
67
- _handle.close();
68
- _handle = null;
69
- }