@scaffold-ui-kit/preview 0.0.0-stage → 2.3.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 (350) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1868 -2
  3. package/application/host/bootstrap.ts +43 -0
  4. package/application/host/main.ts +31 -0
  5. package/application/host/shell-host.ts +47 -0
  6. package/application/index.html +12 -0
  7. package/application/lib/base-url.ts +15 -0
  8. package/application/lib/no-code-block.ts +7 -0
  9. package/application/lib/no-setup.ts +3 -0
  10. package/application/lib/no-views.ts +6 -0
  11. package/application/preview/code/code.html +12 -0
  12. package/application/preview/code/main.ts +89 -0
  13. package/application/preview/globals.ts +254 -0
  14. package/application/preview/html/main.ts +93 -0
  15. package/application/preview/html/preview.html +12 -0
  16. package/application/preview/react/main.tsx +146 -0
  17. package/application/preview/react/preview.html +12 -0
  18. package/application/preview/svelte/Preview.svelte +104 -0
  19. package/application/preview/svelte/main.ts +13 -0
  20. package/application/preview/svelte/preview.html +12 -0
  21. package/application/preview/svelte/story-props.ts +172 -0
  22. package/application/preview/view/main.ts +124 -0
  23. package/application/preview/view/view.html +12 -0
  24. package/application/preview/vue/main.ts +145 -0
  25. package/application/preview/vue/preview.html +12 -0
  26. package/application/shells/charcell/components/Application/index.css +37 -0
  27. package/application/shells/charcell/components/Application/index.tsx +65 -0
  28. package/application/shells/charcell/components/Bar/index.css +68 -0
  29. package/application/shells/charcell/components/Bar/index.tsx +60 -0
  30. package/application/shells/charcell/components/CodePane/index.css +60 -0
  31. package/application/shells/charcell/components/CodePane/index.tsx +113 -0
  32. package/application/shells/charcell/components/ComponentStage/index.css +26 -0
  33. package/application/shells/charcell/components/ComponentStage/index.tsx +110 -0
  34. package/application/shells/charcell/components/Control/index.css +20 -0
  35. package/application/shells/charcell/components/Control/index.tsx +118 -0
  36. package/application/shells/charcell/components/CopyLink/index.tsx +35 -0
  37. package/application/shells/charcell/components/Description/index.css +6 -0
  38. package/application/shells/charcell/components/Description/index.tsx +24 -0
  39. package/application/shells/charcell/components/EditorAddDialog/index.css +9 -0
  40. package/application/shells/charcell/components/EditorAddDialog/index.tsx +158 -0
  41. package/application/shells/charcell/components/EditorPanel/index.css +48 -0
  42. package/application/shells/charcell/components/EditorPanel/index.tsx +496 -0
  43. package/application/shells/charcell/components/EventsRow/index.css +42 -0
  44. package/application/shells/charcell/components/EventsRow/index.tsx +68 -0
  45. package/application/shells/charcell/components/HeadingRow/index.css +11 -0
  46. package/application/shells/charcell/components/HeadingRow/index.tsx +16 -0
  47. package/application/shells/charcell/components/Hint/index.css +16 -0
  48. package/application/shells/charcell/components/Hint/index.tsx +81 -0
  49. package/application/shells/charcell/components/HtmlWarnings/index.tsx +45 -0
  50. package/application/shells/charcell/components/KeyHints/index.css +27 -0
  51. package/application/shells/charcell/components/KeyHints/index.tsx +106 -0
  52. package/application/shells/charcell/components/KitCodeBlock/index.css +55 -0
  53. package/application/shells/charcell/components/KitCodeBlock/index.tsx +18 -0
  54. package/application/shells/charcell/components/Markdown/index.tsx +16 -0
  55. package/application/shells/charcell/components/Navigation/index.css +13 -0
  56. package/application/shells/charcell/components/Navigation/index.tsx +98 -0
  57. package/application/shells/charcell/components/NavigationSplit/index.css +16 -0
  58. package/application/shells/charcell/components/NavigationSplit/index.tsx +82 -0
  59. package/application/shells/charcell/components/OptionControls/index.tsx +93 -0
  60. package/application/shells/charcell/components/PaneStatus/index.css +7 -0
  61. package/application/shells/charcell/components/PaneStatus/index.tsx +47 -0
  62. package/application/shells/charcell/components/PaneWidth/index.tsx +45 -0
  63. package/application/shells/charcell/components/PreviewGrid/index.css +39 -0
  64. package/application/shells/charcell/components/PreviewGrid/index.tsx +344 -0
  65. package/application/shells/charcell/components/PreviewPane/index.css +127 -0
  66. package/application/shells/charcell/components/PreviewPane/index.tsx +182 -0
  67. package/application/shells/charcell/components/PromptBar/index.tsx +133 -0
  68. package/application/shells/charcell/components/ScenarioRow/index.css +36 -0
  69. package/application/shells/charcell/components/ScenarioRow/index.tsx +71 -0
  70. package/application/shells/charcell/components/Select/index.tsx +48 -0
  71. package/application/shells/charcell/components/SlotOutlet/index.css +7 -0
  72. package/application/shells/charcell/components/SlotOutlet/index.tsx +25 -0
  73. package/application/shells/charcell/components/StageBar/index.css +7 -0
  74. package/application/shells/charcell/components/StageBar/index.tsx +109 -0
  75. package/application/shells/charcell/components/StageSplit/index.css +11 -0
  76. package/application/shells/charcell/components/StageSplit/index.tsx +99 -0
  77. package/application/shells/charcell/components/StatusBar/index.tsx +30 -0
  78. package/application/shells/charcell/components/ViewControls/index.css +15 -0
  79. package/application/shells/charcell/components/ViewControls/index.tsx +58 -0
  80. package/application/shells/charcell/components/ViewHeading/index.css +13 -0
  81. package/application/shells/charcell/components/ViewHeading/index.tsx +8 -0
  82. package/application/shells/charcell/components/ViewStage/index.css +9 -0
  83. package/application/shells/charcell/components/ViewStage/index.tsx +25 -0
  84. package/application/shells/charcell/components/WrapToggle/index.tsx +27 -0
  85. package/application/shells/charcell/configuration.ts +45 -0
  86. package/application/shells/charcell/controller-context.ts +27 -0
  87. package/application/shells/charcell/fit-labels.ts +42 -0
  88. package/application/shells/charcell/html-warnings.ts +18 -0
  89. package/application/shells/charcell/index.tsx +82 -0
  90. package/application/shells/charcell/page-loading.html +57 -0
  91. package/application/shells/charcell/placement.ts +24 -0
  92. package/application/shells/charcell/shell-options.ts +23 -0
  93. package/application/shells/charcell/shell.css +37 -0
  94. package/application/shells/charcell/shell.tsx +25 -0
  95. package/application/shells/charcell/split-reset.ts +47 -0
  96. package/application/shells/charcell/stacked-rows.ts +117 -0
  97. package/application/shells/charcell/stage-toggles.ts +93 -0
  98. package/application/types/manifest.d.ts +6 -0
  99. package/application/types/preview-configuration.d.ts +10 -0
  100. package/application/types/preview-shell.d.ts +7 -0
  101. package/application/types/react-registry.d.ts +15 -0
  102. package/application/types/vue-registry.d.ts +6 -0
  103. package/dist/build.d.ts +24 -0
  104. package/dist/build.js +34 -0
  105. package/dist/check.d.ts +48 -0
  106. package/dist/check.js +781 -0
  107. package/dist/cli.d.ts +2 -0
  108. package/dist/cli.js +88 -0
  109. package/dist/context.d.ts +179 -0
  110. package/dist/context.js +783 -0
  111. package/dist/controller/catalog.d.ts +339 -0
  112. package/dist/controller/catalog.js +367 -0
  113. package/dist/controller/create-preview-controller.d.ts +532 -0
  114. package/dist/controller/create-preview-controller.js +1707 -0
  115. package/dist/controller/editor-tree.d.ts +161 -0
  116. package/dist/controller/editor-tree.js +373 -0
  117. package/dist/controller/html-source.d.ts +62 -0
  118. package/dist/controller/html-source.js +61 -0
  119. package/dist/controller/index.d.ts +9 -0
  120. package/dist/controller/index.js +12 -0
  121. package/dist/controller/persistence.d.ts +191 -0
  122. package/dist/controller/persistence.js +315 -0
  123. package/dist/controller/regeneration.d.ts +30 -0
  124. package/dist/controller/regeneration.js +27 -0
  125. package/dist/controller/source.d.ts +80 -0
  126. package/dist/controller/source.js +236 -0
  127. package/dist/controller/store.d.ts +27 -0
  128. package/dist/controller/store.js +40 -0
  129. package/dist/declarations/application/shells/charcell/components/Application/index.d.ts +2 -0
  130. package/dist/declarations/application/shells/charcell/components/Bar/index.d.ts +11 -0
  131. package/dist/declarations/application/shells/charcell/components/CodePane/index.d.ts +5 -0
  132. package/dist/declarations/application/shells/charcell/components/ComponentStage/index.d.ts +2 -0
  133. package/dist/declarations/application/shells/charcell/components/Control/index.d.ts +9 -0
  134. package/dist/declarations/application/shells/charcell/components/CopyLink/index.d.ts +1 -0
  135. package/dist/declarations/application/shells/charcell/components/Description/index.d.ts +5 -0
  136. package/dist/declarations/application/shells/charcell/components/EditorAddDialog/index.d.ts +6 -0
  137. package/dist/declarations/application/shells/charcell/components/EditorPanel/index.d.ts +2 -0
  138. package/dist/declarations/application/shells/charcell/components/EventsRow/index.d.ts +4 -0
  139. package/dist/declarations/application/shells/charcell/components/HeadingRow/index.d.ts +6 -0
  140. package/dist/declarations/application/shells/charcell/components/Hint/index.d.ts +11 -0
  141. package/dist/declarations/application/shells/charcell/components/HtmlWarnings/index.d.ts +5 -0
  142. package/dist/declarations/application/shells/charcell/components/KeyHints/index.d.ts +2 -0
  143. package/dist/declarations/application/shells/charcell/components/KitCodeBlock/index.d.ts +5 -0
  144. package/dist/declarations/application/shells/charcell/components/Markdown/index.d.ts +3 -0
  145. package/dist/declarations/application/shells/charcell/components/Navigation/index.d.ts +8 -0
  146. package/dist/declarations/application/shells/charcell/components/NavigationSplit/index.d.ts +7 -0
  147. package/dist/declarations/application/shells/charcell/components/OptionControls/index.d.ts +7 -0
  148. package/dist/declarations/application/shells/charcell/components/PaneStatus/index.d.ts +2 -0
  149. package/dist/declarations/application/shells/charcell/components/PaneWidth/index.d.ts +4 -0
  150. package/dist/declarations/application/shells/charcell/components/PreviewGrid/index.d.ts +7 -0
  151. package/dist/declarations/application/shells/charcell/components/PreviewPane/index.d.ts +9 -0
  152. package/dist/declarations/application/shells/charcell/components/PromptBar/index.d.ts +1 -0
  153. package/dist/declarations/application/shells/charcell/components/ScenarioRow/index.d.ts +2 -0
  154. package/dist/declarations/application/shells/charcell/components/Select/index.d.ts +16 -0
  155. package/dist/declarations/application/shells/charcell/components/SlotOutlet/index.d.ts +5 -0
  156. package/dist/declarations/application/shells/charcell/components/StageBar/index.d.ts +2 -0
  157. package/dist/declarations/application/shells/charcell/components/StageSplit/index.d.ts +17 -0
  158. package/dist/declarations/application/shells/charcell/components/StatusBar/index.d.ts +1 -0
  159. package/dist/declarations/application/shells/charcell/components/ViewControls/index.d.ts +9 -0
  160. package/dist/declarations/application/shells/charcell/components/ViewHeading/index.d.ts +4 -0
  161. package/dist/declarations/application/shells/charcell/components/ViewStage/index.d.ts +4 -0
  162. package/dist/declarations/application/shells/charcell/components/WrapToggle/index.d.ts +1 -0
  163. package/dist/declarations/application/shells/charcell/configuration.d.ts +31 -0
  164. package/dist/declarations/application/shells/charcell/controller-context.d.ts +9 -0
  165. package/dist/declarations/application/shells/charcell/fit-labels.d.ts +18 -0
  166. package/dist/declarations/application/shells/charcell/html-warnings.d.ts +5 -0
  167. package/dist/declarations/application/shells/charcell/index.d.ts +39 -0
  168. package/dist/declarations/application/shells/charcell/placement.d.ts +7 -0
  169. package/dist/declarations/application/shells/charcell/shell-options.d.ts +15 -0
  170. package/dist/declarations/application/shells/charcell/shell.d.ts +9 -0
  171. package/dist/declarations/application/shells/charcell/split-reset.d.ts +30 -0
  172. package/dist/declarations/application/shells/charcell/stacked-rows.d.ts +58 -0
  173. package/dist/declarations/application/shells/charcell/stage-toggles.d.ts +28 -0
  174. package/dist/declarations/src/controller/catalog.d.ts +339 -0
  175. package/dist/declarations/src/controller/create-preview-controller.d.ts +532 -0
  176. package/dist/declarations/src/controller/editor-tree.d.ts +161 -0
  177. package/dist/declarations/src/controller/html-source.d.ts +62 -0
  178. package/dist/declarations/src/controller/index.d.ts +9 -0
  179. package/dist/declarations/src/controller/persistence.d.ts +191 -0
  180. package/dist/declarations/src/controller/regeneration.d.ts +30 -0
  181. package/dist/declarations/src/controller/source.d.ts +80 -0
  182. package/dist/declarations/src/controller/store.d.ts +27 -0
  183. package/dist/declarations/src/emit/common.d.ts +103 -0
  184. package/dist/declarations/src/emit/manifest.d.ts +138 -0
  185. package/dist/declarations/src/emit/source.d.ts +87 -0
  186. package/dist/declarations/src/lib/jsx-roots.d.ts +22 -0
  187. package/dist/declarations/src/lib/module-of-source.d.ts +18 -0
  188. package/dist/declarations/src/lib/naming.d.ts +29 -0
  189. package/dist/declarations/src/lib/react-spelling.d.ts +68 -0
  190. package/dist/declarations/src/lib/scenario-story.d.ts +41 -0
  191. package/dist/declarations/src/lib/slot-fill.d.ts +15 -0
  192. package/dist/declarations/src/lib/types.d.ts +741 -0
  193. package/dist/declarations/src/options.d.ts +224 -0
  194. package/dist/declarations/src/protocol.d.ts +541 -0
  195. package/dist/declarations/src/react-view.d.ts +22 -0
  196. package/dist/declarations/src/react.d.ts +17 -0
  197. package/dist/declarations/src/shell.d.ts +99 -0
  198. package/dist/declarations/src/views.d.ts +152 -0
  199. package/dist/development-server.d.ts +121 -0
  200. package/dist/development-server.js +331 -0
  201. package/dist/emit/common.d.ts +103 -0
  202. package/dist/emit/common.js +170 -0
  203. package/dist/emit/html-source.d.ts +46 -0
  204. package/dist/emit/html-source.js +322 -0
  205. package/dist/emit/manifest.d.ts +138 -0
  206. package/dist/emit/manifest.js +74 -0
  207. package/dist/emit/react.d.ts +16 -0
  208. package/dist/emit/react.js +210 -0
  209. package/dist/emit/scratch.d.ts +40 -0
  210. package/dist/emit/scratch.js +116 -0
  211. package/dist/emit/source.d.ts +87 -0
  212. package/dist/emit/source.js +789 -0
  213. package/dist/emit/svelte.d.ts +9 -0
  214. package/dist/emit/svelte.js +177 -0
  215. package/dist/emit/vue.d.ts +2 -0
  216. package/dist/emit/vue.js +152 -0
  217. package/dist/enumerate.d.ts +2 -0
  218. package/dist/enumerate.js +162 -0
  219. package/dist/generate.d.ts +43 -0
  220. package/dist/generate.js +302 -0
  221. package/dist/html-stylesheet.d.ts +43 -0
  222. package/dist/html-stylesheet.js +145 -0
  223. package/dist/index.d.ts +18 -0
  224. package/dist/index.js +21 -0
  225. package/dist/landing.d.ts +16 -0
  226. package/dist/landing.js +45 -0
  227. package/dist/lib/exported-types.d.ts +42 -0
  228. package/dist/lib/exported-types.js +86 -0
  229. package/dist/lib/html-attributes.d.ts +2 -0
  230. package/dist/lib/html-attributes.js +111 -0
  231. package/dist/lib/html-warnings.d.ts +19 -0
  232. package/dist/lib/html-warnings.js +79 -0
  233. package/dist/lib/jsx-roots.d.ts +22 -0
  234. package/dist/lib/jsx-roots.js +243 -0
  235. package/dist/lib/module-of-source.d.ts +18 -0
  236. package/dist/lib/module-of-source.js +24 -0
  237. package/dist/lib/naming.d.ts +29 -0
  238. package/dist/lib/naming.js +56 -0
  239. package/dist/lib/parse-type.d.ts +32 -0
  240. package/dist/lib/parse-type.js +103 -0
  241. package/dist/lib/react-spelling.d.ts +68 -0
  242. package/dist/lib/react-spelling.js +197 -0
  243. package/dist/lib/scenario-story.d.ts +41 -0
  244. package/dist/lib/scenario-story.js +84 -0
  245. package/dist/lib/slot-fill.d.ts +15 -0
  246. package/dist/lib/slot-fill.js +92 -0
  247. package/dist/lib/template-files.d.ts +14 -0
  248. package/dist/lib/template-files.js +25 -0
  249. package/dist/lib/types.d.ts +741 -0
  250. package/dist/lib/types.js +13 -0
  251. package/dist/lib/void-elements.d.ts +7 -0
  252. package/dist/lib/void-elements.js +13 -0
  253. package/dist/load.d.ts +37 -0
  254. package/dist/load.js +82 -0
  255. package/dist/model.d.ts +44 -0
  256. package/dist/model.js +464 -0
  257. package/dist/options.d.ts +224 -0
  258. package/dist/options.js +223 -0
  259. package/dist/prop-types.d.ts +26 -0
  260. package/dist/prop-types.js +102 -0
  261. package/dist/props-from.d.ts +84 -0
  262. package/dist/props-from.js +510 -0
  263. package/dist/protocol.d.ts +541 -0
  264. package/dist/protocol.js +819 -0
  265. package/dist/react-view.d.ts +22 -0
  266. package/dist/react-view.js +36 -0
  267. package/dist/react.d.ts +17 -0
  268. package/dist/react.js +23 -0
  269. package/dist/sass-importers.d.ts +26 -0
  270. package/dist/sass-importers.js +32 -0
  271. package/dist/shell-acceptance.d.ts +21 -0
  272. package/dist/shell-acceptance.js +37 -0
  273. package/dist/shell-page.d.ts +36 -0
  274. package/dist/shell-page.js +90 -0
  275. package/dist/shell-peers.d.ts +38 -0
  276. package/dist/shell-peers.js +61 -0
  277. package/dist/shell.d.ts +99 -0
  278. package/dist/shell.js +52 -0
  279. package/dist/shells/charcell/page.d.ts +8 -0
  280. package/dist/shells/charcell/page.js +69 -0
  281. package/dist/story-source.d.ts +113 -0
  282. package/dist/story-source.js +271 -0
  283. package/dist/story.d.ts +5 -0
  284. package/dist/story.js +28 -0
  285. package/dist/testing.d.ts +218 -0
  286. package/dist/testing.js +284 -0
  287. package/dist/views.d.ts +152 -0
  288. package/dist/views.js +7 -0
  289. package/dist/vite-configuration.d.ts +114 -0
  290. package/dist/vite-configuration.js +578 -0
  291. package/package.json +123 -3
  292. package/src/build.ts +51 -0
  293. package/src/check.ts +1062 -0
  294. package/src/cli.ts +123 -0
  295. package/src/context.ts +1168 -0
  296. package/src/controller/catalog.ts +719 -0
  297. package/src/controller/create-preview-controller.ts +2683 -0
  298. package/src/controller/editor-tree.ts +530 -0
  299. package/src/controller/html-source.ts +114 -0
  300. package/src/controller/index.ts +105 -0
  301. package/src/controller/persistence.ts +403 -0
  302. package/src/controller/regeneration.ts +55 -0
  303. package/src/controller/source.ts +333 -0
  304. package/src/controller/store.ts +55 -0
  305. package/src/development-server.ts +442 -0
  306. package/src/emit/common.ts +201 -0
  307. package/src/emit/html-source.ts +402 -0
  308. package/src/emit/manifest.ts +241 -0
  309. package/src/emit/react.ts +263 -0
  310. package/src/emit/scratch.ts +175 -0
  311. package/src/emit/source.ts +1094 -0
  312. package/src/emit/svelte.ts +230 -0
  313. package/src/emit/vue.ts +194 -0
  314. package/src/enumerate.ts +220 -0
  315. package/src/generate.ts +443 -0
  316. package/src/html-stylesheet.ts +173 -0
  317. package/src/index.ts +60 -0
  318. package/src/landing.ts +58 -0
  319. package/src/lib/exported-types.ts +114 -0
  320. package/src/lib/html-attributes.ts +113 -0
  321. package/src/lib/html-warnings.ts +81 -0
  322. package/src/lib/jsx-roots.ts +238 -0
  323. package/src/lib/module-of-source.ts +26 -0
  324. package/src/lib/naming.ts +65 -0
  325. package/src/lib/parse-type.ts +143 -0
  326. package/src/lib/react-spelling.ts +235 -0
  327. package/src/lib/scenario-story.ts +97 -0
  328. package/src/lib/slot-fill.ts +102 -0
  329. package/src/lib/template-files.ts +31 -0
  330. package/src/lib/types.ts +778 -0
  331. package/src/lib/void-elements.ts +15 -0
  332. package/src/load.ts +144 -0
  333. package/src/model.ts +568 -0
  334. package/src/options.ts +435 -0
  335. package/src/prop-types.ts +133 -0
  336. package/src/props-from.ts +678 -0
  337. package/src/protocol.ts +1135 -0
  338. package/src/react-view.ts +45 -0
  339. package/src/react.ts +34 -0
  340. package/src/sass-importers.ts +45 -0
  341. package/src/shell-acceptance.ts +45 -0
  342. package/src/shell-page.ts +133 -0
  343. package/src/shell-peers.ts +70 -0
  344. package/src/shell.ts +194 -0
  345. package/src/shells/charcell/page.ts +82 -0
  346. package/src/story-source.ts +391 -0
  347. package/src/story.ts +42 -0
  348. package/src/testing.ts +497 -0
  349. package/src/views.ts +183 -0
  350. package/src/vite-configuration.ts +675 -0
@@ -0,0 +1,146 @@
1
+ // React preview entry. Mounts the generated render-registry by id, holds props in
2
+ // state, and updates reactively from the host over postMessage - the same App
3
+ // instance re-renders, so the Zag driver machine stays alive across prop changes.
4
+ import { Component, useEffect, useState, type ReactNode } from 'react';
5
+ import { createRoot } from 'react-dom/client';
6
+ import { declaredAttributes, reactAttributeNames, registry } from '@preview-generated/react/registry';
7
+ // The scenario editor's regenerated scratch story, merged under its reserved id.
8
+ // Its module is a placeholder registry until the editor's first edit.
9
+ import * as scratch from '@preview-generated/scratch/react';
10
+ // The kit's per-target setup module (side effects only): ambient providers a
11
+ // story needs mounted once (a toast container), another package's stylesheets, and any
12
+ // other integration the kit's react stories assume. Aliased to the kit's
13
+ // `preview.setupModules.react` (or an empty module).
14
+ import '@preview-setup/react';
15
+ import { applyGlobals } from '../globals';
16
+ import {
17
+ announcePreviewReady,
18
+ announcePreviewShown,
19
+ announcePreviewStories,
20
+ announceStoryMounted,
21
+ PREVIEW_MESSAGE,
22
+ PREVIEW_MOUNT_ELEMENT_ID,
23
+ readPreviewMessage,
24
+ reportContentSize,
25
+ reportRenderError,
26
+ withEventRecorders,
27
+ withWriteBacks,
28
+ PendingWriteBacks,
29
+ type PreviewWriteBack,
30
+ } from '../../../src/protocol';
31
+ import { reactProps } from '../../../src/lib/react-spelling';
32
+
33
+ // What a story threw as a message; it need not have thrown an Error.
34
+ function errorMessage(error: unknown): string {
35
+ return error instanceof Error ? error.message : String(error);
36
+ }
37
+
38
+ // Isolate a throwing component so it can't poison the persistent root (which
39
+ // would blank every later story). Reset per story via a `key` on the boundary;
40
+ // the host hears of the error, and of each story mounted since.
41
+ class ErrorBoundary extends Component<{ children: ReactNode }, { message: string | null }> {
42
+ state = { message: null as string | null };
43
+ static getDerivedStateFromError(error: unknown) {
44
+ return { message: errorMessage(error) };
45
+ }
46
+ componentDidCatch(error: unknown) {
47
+ reportRenderError(errorMessage(error));
48
+ }
49
+ render() {
50
+ if (this.state.message !== null) return <pre>render error: {this.state.message}</pre>;
51
+ return this.props.children;
52
+ }
53
+ }
54
+
55
+ // The values this pane has written back itself and the host has not yet
56
+ // answered: props the host sent before it took the newest keep that value.
57
+ const pending = new PendingWriteBacks();
58
+
59
+ function Application() {
60
+ const [id, setId] = useState('');
61
+ const [props, setProps] = useState<Record<string, unknown>>({});
62
+ // The story's events, recorded with each set of props it gets.
63
+ const [events, setEvents] = useState<string[]>([]);
64
+ // The story's two-way props, each written back as its event reports a value.
65
+ const [bindings, setBindings] = useState<PreviewWriteBack[]>([]);
66
+ // Each story or scenario the host sets mounts fresh, so uncontrolled state
67
+ // never carries over from the last one; live prop edits update in place.
68
+ const [mount, setMount] = useState(0);
69
+ // The host's mount of the story, which each recorded event carries.
70
+ const [hostMount, setHostMount] = useState<number | undefined>(undefined);
71
+
72
+ useEffect(() => {
73
+ function onMessage(event: MessageEvent) {
74
+ const message = readPreviewMessage(event.data);
75
+ if (!message) return;
76
+ if (message.type === PREVIEW_MESSAGE.setStory) {
77
+ reportRenderError();
78
+ pending.clear();
79
+ setId(message.id);
80
+ setProps(message.props ?? {});
81
+ setEvents(message.events ?? []);
82
+ setBindings(message.bindings ?? []);
83
+ setHostMount(message.mount);
84
+ setMount((count) => count + 1);
85
+ } else if (message.type === PREVIEW_MESSAGE.props) {
86
+ setProps(pending.reconcile(message.props, message.answers));
87
+ } else if (message.type === PREVIEW_MESSAGE.globals) {
88
+ applyGlobals(message.options);
89
+ }
90
+ }
91
+ window.addEventListener('message', onMessage);
92
+ announcePreviewStories(Object.keys({ ...registry, ...scratch.registry }));
93
+ announcePreviewReady();
94
+ return () => window.removeEventListener('message', onMessage);
95
+ }, []);
96
+
97
+ // The first story the host sets, once painted, lets the host show the pane.
98
+ // The story's own effects have run by now, so a test can read the mount.
99
+ useEffect(() => {
100
+ if (mount === 0) return;
101
+ announcePreviewShown();
102
+ announceStoryMounted(id);
103
+ }, [mount]);
104
+
105
+ const render = { ...registry, ...scratch.registry }[id];
106
+ if (!render) return null;
107
+ // A story spells the attributes it gives the component as HTML does:
108
+ // React takes `class` as `className`, a `style` string as an object and
109
+ // the attributes it renames by their React names, unless the component
110
+ // declares a prop by that name.
111
+ const declared = { ...declaredAttributes, ...scratch.declaredAttributes }[id] ?? [];
112
+ // A controlled story takes a two-way prop's new value here, in the event
113
+ // that reports it, before React restores a controlled input to its prop's
114
+ // value: typing mid-text keeps the caret where it is. The host's
115
+ // write-back follows with the same value. Each write is numbered, the
116
+ // event reporting it carries the number, and props the host sent before
117
+ // it took the newest keep the pane's own value (`pending`).
118
+ const story = withWriteBacks(withEventRecorders(props, events, window, hostMount, pending), bindings, (prop, value) => {
119
+ pending.wrote(prop, value);
120
+ setProps((current) => (current[prop] === undefined ? current : { ...current, [prop]: value }));
121
+ });
122
+ const spelled = reactProps(story, (name) => declared.includes(name), reactAttributeNames ?? {});
123
+ return <ErrorBoundary key={`${id}:${mount}`}>{render(spelled)}</ErrorBoundary>;
124
+ }
125
+
126
+ // Cache the root across HMR: when the editor's scratch registry hot-updates,
127
+ // Fast Refresh re-runs this module - reuse the existing root (and re-render Application so
128
+ // it picks up the new scratch registry) instead of calling createRoot twice.
129
+ const container = document.getElementById(PREVIEW_MOUNT_ELEMENT_ID)!;
130
+ const store = window as unknown as {
131
+ __previewRoot?: ReturnType<typeof createRoot>;
132
+ };
133
+ const root = store.__previewRoot ?? (store.__previewRoot = createRoot(container));
134
+ root.render(<Application />);
135
+ // The story's size reaches the host on each change, so a shell can size the pane to it.
136
+ reportContentSize(container);
137
+
138
+ // The editor regenerates .preview-generated/scratch/react.tsx on each edit. Self-accept
139
+ // that dep (a no-op) so Vite scopes the change to *this* iframe instead of
140
+ // broadcasting a full-reload to every client on the shared dev server - which
141
+ // would wipe the host's editor state. The actual refresh is host-driven: after a
142
+ // regeneration it bumps this iframe's src, reloading it to pick up the new (invalidated)
143
+ // scratch module - deterministic, unlike relying on Vite's HMR event delivery.
144
+ if (import.meta.hot) {
145
+ import.meta.hot.accept('@preview-generated/scratch/react', () => {});
146
+ }
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>preview - react</title>
7
+ </head>
8
+ <body>
9
+ <div id="app"></div>
10
+ <script type="module" src="./main.tsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,104 @@
1
+ <script lang="ts">
2
+ // Runes-mode host for the Svelte preview. The generated wrappers (registry
3
+ // values) are runes components. The wrapper gets one object for the
4
+ // story's props that never changes, each of whose props is a signal of its
5
+ // own: an update sets the props that changed alone - a prop update on the
6
+ // same instance, not a remount, keeping the Zag driver machine alive - and
7
+ // a prop the story leaves out is never set, so a component keeps its own
8
+ // two-way value while another prop changes.
9
+ // Each story or scenario the host sets mounts fresh (`mount`), so
10
+ // uncontrolled state never carries over from the last one. An error the
11
+ // story throws shows in its place, as the React page's error boundary
12
+ // shows one, rather than an empty pane, and the host hears of it, and of
13
+ // each story mounted since.
14
+ import { flushSync } from 'svelte';
15
+ import { registry } from '@preview-generated/svelte/registry';
16
+ // The scenario editor's regenerated scratch story, merged under its reserved id.
17
+ import { registry as scratchRegistry } from '@preview-generated/scratch/registry';
18
+ import { applyGlobals } from '../globals';
19
+ import { paneProps, storyProps, type GivenProps } from './story-props';
20
+ import {
21
+ announcePreviewReady,
22
+ announcePreviewShown,
23
+ announcePreviewStories,
24
+ announceStoryMounted,
25
+ PREVIEW_MESSAGE,
26
+ readPreviewMessage,
27
+ reportRenderError,
28
+ } from '../../../src/protocol';
29
+
30
+ const all = { ...registry, ...scratchRegistry };
31
+
32
+ let id = $state('');
33
+ let mount = $state(0);
34
+
35
+ // The story's props, each a signal of its own (see story-props.ts).
36
+ const given = $state<GivenProps>({});
37
+ const props = storyProps(given);
38
+ // The story's events recorded and its two-way props written back as they
39
+ // report a value, props the host sent before it took the newest keeping
40
+ // the pane's own value (see story-props.ts).
41
+ const story = paneProps(given);
42
+
43
+ // Apply what is pending now, so what follows sees the story mounted or
44
+ // gone. An error the flush lets through (one a story throws as it unmounts,
45
+ // past the boundary) is the host's to hear of, not the pane's to stop on.
46
+ function flush(): void {
47
+ try {
48
+ flushSync();
49
+ } catch (error) {
50
+ console.error(error);
51
+ reportRenderError(error instanceof Error ? error.message : String(error));
52
+ }
53
+ }
54
+
55
+ $effect(() => {
56
+ function onMessage(event: MessageEvent) {
57
+ const message = readPreviewMessage(event.data);
58
+ if (!message) return;
59
+ if (message.type === PREVIEW_MESSAGE.setStory) {
60
+ reportRenderError();
61
+ // The story mounted comes down before its props change: set first,
62
+ // the next story's props would reach the one still mounted as it
63
+ // unmounts, and a story that reads a prop it needs then, as one
64
+ // stopping a headless machine does, would read it gone and throw.
65
+ id = '';
66
+ flush();
67
+ story.setStory(message.props ?? {}, message);
68
+ id = message.id;
69
+ mount += 1;
70
+ // Mounted, its effects run: the host may show the pane, and a test
71
+ // may read the mount. Reported here rather than from an effect of
72
+ // this component, which an error let through would stop for good.
73
+ flush();
74
+ announcePreviewShown();
75
+ announceStoryMounted(message.id);
76
+ } else if (message.type === PREVIEW_MESSAGE.props) {
77
+ story.setProps(message.props, message.answers);
78
+ } else if (message.type === PREVIEW_MESSAGE.globals) {
79
+ applyGlobals(message.options);
80
+ }
81
+ }
82
+ window.addEventListener('message', onMessage);
83
+ announcePreviewStories(Object.keys(all));
84
+ announcePreviewReady();
85
+ return () => window.removeEventListener('message', onMessage);
86
+ });
87
+ </script>
88
+
89
+ {#if id && all[id]}
90
+ {@const Comp = all[id]}
91
+ {#key mount}
92
+ <svelte:boundary
93
+ onerror={(error) => {
94
+ console.error(error);
95
+ reportRenderError(error instanceof Error ? error.message : String(error));
96
+ }}
97
+ >
98
+ <Comp {props} />
99
+ {#snippet failed(error)}
100
+ <pre>render error: {error instanceof Error ? error.message : String(error)}</pre>
101
+ {/snippet}
102
+ </svelte:boundary>
103
+ {/key}
104
+ {/if}
@@ -0,0 +1,13 @@
1
+ // Svelte preview entry. The postMessage wiring + reactive props live in
2
+ // Preview.svelte (runes); this just mounts it. The theme stylesheet is loaded
3
+ // by globals.ts (imported via Preview.svelte).
4
+ // The kit's per-target setup module (side effects only) - see react/main.tsx.
5
+ import '@preview-setup/svelte';
6
+ import { mount } from 'svelte';
7
+ import Preview from './Preview.svelte';
8
+ import { PREVIEW_MOUNT_ELEMENT_ID, reportContentSize } from '../../../src/protocol';
9
+
10
+ const target = document.getElementById(PREVIEW_MOUNT_ELEMENT_ID)!;
11
+ mount(Preview, { target });
12
+ // The story's size reaches the host on each change, so a shell can size the pane to it.
13
+ reportContentSize(target);
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>preview - svelte</title>
7
+ </head>
8
+ <body>
9
+ <div id="app"></div>
10
+ <script type="module" src="./main.ts"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,172 @@
1
+ // The Svelte pane's story props: one object for the component's props that
2
+ // never changes, each of whose props reads a signal of its own. An update
3
+ // sets the props whose values changed alone, and a prop the story leaves out
4
+ // is never set, as a parent leaves it. Were the whole object replaced, every
5
+ // prop would read as set again, and a component's own two-way value (a
6
+ // bindable the story leaves out) would go back to its default whenever
7
+ // another prop changed: Svelte keeps a prop the component assigns only until
8
+ // the prop is read anew. An array or object the story gives again with the
9
+ // same content, as each message from the host does, is the same value: the
10
+ // host compares values the same way.
11
+
12
+ import { stableStringify } from '../../../src/controller/editor-tree';
13
+ import {
14
+ isPlainData,
15
+ PendingWriteBacks,
16
+ withEventRecorders,
17
+ withWriteBacks,
18
+ type PreviewWriteBack,
19
+ } from '../../../src/protocol';
20
+
21
+ /** A prop's value in a box, so it stays the value it is: a `$state` record
22
+ * wraps an array or plain object in a proxy of its own, a class instance not. */
23
+ export class GivenProp {
24
+ constructor(readonly value: unknown) {}
25
+ }
26
+
27
+ /** The props a story gives, by name, each in a box: a `$state` record, so
28
+ * each prop is a signal of its own. */
29
+ export type GivenProps = Record<string, GivenProp>;
30
+
31
+ /**
32
+ * The component's props, read from `given`: an object that never changes,
33
+ * whose each prop reads its own box, so a read of one prop depends on that
34
+ * prop alone.
35
+ *
36
+ * @param given - The story's props, a `$state` record of boxes.
37
+ * @returns The props to spread on the component.
38
+ * @example
39
+ * ```ts
40
+ * const given = $state<GivenProps>({});
41
+ * const props = storyProps(given);
42
+ * ```
43
+ */
44
+ export function storyProps(given: GivenProps): Record<string, unknown> {
45
+ return new Proxy(
46
+ {},
47
+ {
48
+ get: (_, key) =>
49
+ typeof key === 'string' ? given[key]?.value : undefined,
50
+ has: (_, key) => typeof key === 'string' && key in given,
51
+ ownKeys: () => Reflect.ownKeys(given),
52
+ getOwnPropertyDescriptor: (_, key) =>
53
+ typeof key === 'string' && key in given
54
+ ? {
55
+ value: given[key].value,
56
+ enumerable: true,
57
+ configurable: true,
58
+ writable: true,
59
+ }
60
+ : undefined,
61
+ }
62
+ );
63
+ }
64
+
65
+ /**
66
+ * Whether a prop's value is the one it had: the same value, or arrays or
67
+ * plain objects of plain data holding the same content.
68
+ *
69
+ * @param previous - The value it had.
70
+ * @param next - The value it is given.
71
+ * @returns `true` when nothing changed.
72
+ */
73
+ export function sameValue(previous: unknown, next: unknown): boolean {
74
+ if (Object.is(previous, next)) return true;
75
+ return (
76
+ typeof previous === 'object' &&
77
+ previous !== null &&
78
+ typeof next === 'object' &&
79
+ next !== null &&
80
+ isPlainData(previous) &&
81
+ isPlainData(next) &&
82
+ stableStringify(previous) === stableStringify(next)
83
+ );
84
+ }
85
+
86
+ /**
87
+ * Set the story's props to `next`: a prop whose value changed gets a new box,
88
+ * one `next` leaves out is deleted, and the others stay as they are. An array
89
+ * or object with the content it had stays as it is (see {@link sameValue}).
90
+ *
91
+ * @param given - The story's props, a `$state` record of boxes.
92
+ * @param next - The props the story gives now.
93
+ */
94
+ export function setStoryProps(
95
+ given: GivenProps,
96
+ next: Record<string, unknown>
97
+ ): void {
98
+ for (const key of Object.keys(given)) if (!(key in next)) delete given[key];
99
+ for (const [key, value] of Object.entries(next))
100
+ if (!(key in given) || !sameValue(given[key].value, value))
101
+ given[key] = new GivenProp(value);
102
+ }
103
+
104
+ /** What a story the host sets brings beside its props. */
105
+ export interface StorySettings {
106
+ /** The function props whose calls the pane records. */
107
+ events?: readonly string[];
108
+ /** The two-way props and the events they report through. */
109
+ bindings?: readonly PreviewWriteBack[];
110
+ /** The host's mount of the story, which each recorded event carries. */
111
+ mount?: number;
112
+ }
113
+
114
+ /**
115
+ * The Svelte pane's story props as the host's messages set them. A story's
116
+ * events are recorded, and a controlled story takes a two-way prop's new
117
+ * value in the event that reports it, as the React and Vue panes do: the
118
+ * story's prop holds the value the component has taken by the time the
119
+ * host echoes it, and props the host sent before it took the pane's newest
120
+ * write keep that value (`answers`, see {@link PendingWriteBacks}). A new
121
+ * story forgets the last one's writes.
122
+ *
123
+ * @param given - The story's props, a `$state` record of boxes.
124
+ * @param target - The pane's window, which events are reported from.
125
+ * @returns `setStory` for a story the host sets, `setProps` for its props.
126
+ * @example
127
+ * ```ts
128
+ * const story = paneProps(given);
129
+ * story.setStory({ value: 'a' }, { bindings: [{ prop: 'value', changeProp: 'onValueChange' }] });
130
+ * story.setProps({ value: 'ab' }, 1);
131
+ * ```
132
+ */
133
+ export function paneProps(
134
+ given: GivenProps,
135
+ target: Window = window
136
+ ): {
137
+ setStory: (props: Record<string, unknown>, settings?: StorySettings) => void;
138
+ setProps: (props: Record<string, unknown>, answers?: number) => void;
139
+ } {
140
+ let settings: StorySettings = {};
141
+ const pending = new PendingWriteBacks();
142
+ function apply(next: Record<string, unknown>): void {
143
+ setStoryProps(
144
+ given,
145
+ withWriteBacks(
146
+ withEventRecorders(
147
+ next,
148
+ settings.events,
149
+ target,
150
+ settings.mount,
151
+ pending
152
+ ),
153
+ settings.bindings,
154
+ (prop, value) => {
155
+ pending.wrote(prop, value);
156
+ if (prop in given && !sameValue(given[prop].value, value))
157
+ given[prop] = new GivenProp(value);
158
+ }
159
+ )
160
+ );
161
+ }
162
+ return {
163
+ setStory(props, next = {}) {
164
+ settings = next;
165
+ pending.clear();
166
+ apply(props);
167
+ },
168
+ setProps(props, answers) {
169
+ apply(pending.reconcile(props, answers));
170
+ },
171
+ };
172
+ }
@@ -0,0 +1,124 @@
1
+ // Generic custom-view iframe entry. The host points this iframe at a registered
2
+ // view by `?view=<id>` and drives its globals over the same postMessage handshake
3
+ // the component previews use. The entry loads the kit's setup module for the
4
+ // view's framework (named by `?framework=`, so its stylesheets come first, as
5
+ // in the framework iframes), then the theme and canvas, then the kit's views;
6
+ // it mounts the view under the live theme and options (so a tokens view paints
7
+ // from the kit's real custom properties, with its theme stylesheet in scope).
8
+ // The view stays mounted and hears of each new context - the options the host
9
+ // applies, and the catalog once the handshake delivers it - through the
10
+ // `updates` it mounts with. No view is named here - the kit's views module is
11
+ // the only place a view is registered, so a new view needs no change to this
12
+ // entry or the host.
13
+ import type {
14
+ RenderedView,
15
+ ViewContext,
16
+ ViewFramework,
17
+ } from '../../../src/views';
18
+ import { options as previewOptions } from '@preview-configuration';
19
+ import { optionDefaults } from '../../../src/options';
20
+ import {
21
+ announcePreviewReady,
22
+ announcePreviewShown,
23
+ PREVIEW_MESSAGE,
24
+ PREVIEW_MOUNT_ELEMENT_ID,
25
+ readPreviewMessage,
26
+ reportContentSize,
27
+ selectMessage,
28
+ VIEW_FRAMEWORK_PARAMETER,
29
+ VIEW_PARAMETER,
30
+ } from '../../../src/protocol';
31
+
32
+ const parameters = new URLSearchParams(window.location.search);
33
+ const viewId = parameters.get(VIEW_PARAMETER) ?? '';
34
+
35
+ type SetupFramework = Exclude<ViewFramework, 'dom'>;
36
+
37
+ // Each framework's setup module, loaded only for a view of that framework.
38
+ const SETUP_MODULES: Record<SetupFramework, () => Promise<unknown>> = {
39
+ react: () => import('@preview-setup/react'),
40
+ vue: () => import('@preview-setup/vue'),
41
+ svelte: () => import('@preview-setup/svelte'),
42
+ };
43
+ const loadedSetups = new Set<ViewFramework>(['dom']);
44
+
45
+ async function loadSetup(framework: ViewFramework): Promise<void> {
46
+ if (loadedSetups.has(framework)) return;
47
+ loadedSetups.add(framework);
48
+ await SETUP_MODULES[framework as SetupFramework]();
49
+ }
50
+
51
+ function isSetupFramework(value: string | null): value is SetupFramework {
52
+ return value !== null && Object.hasOwn(SETUP_MODULES, value);
53
+ }
54
+
55
+ // The view-side half of the select back-channel: ViewContext exposes this as
56
+ // `selectComponent`, and this iframe relays it to the host as `preview:select` -
57
+ // a view never learns the postMessage vocabulary.
58
+ function selectComponent(id: string, props?: Record<string, unknown>) {
59
+ window.parent?.postMessage(selectMessage(id, props), '*');
60
+ }
61
+
62
+ let context: ViewContext = {
63
+ options: optionDefaults(previewOptions),
64
+ kitName: '',
65
+ sources: [],
66
+ components: [],
67
+ selectComponent,
68
+ };
69
+ const listeners = new Set<(context: ViewContext) => void>();
70
+
71
+ function update(changes: Partial<ViewContext>): void {
72
+ context = { ...context, ...changes };
73
+ for (const listener of listeners) listener(context);
74
+ }
75
+
76
+ async function start(): Promise<void> {
77
+ const named = parameters.get(VIEW_FRAMEWORK_PARAMETER);
78
+ if (isSetupFramework(named)) await loadSetup(named);
79
+ const { applyGlobals } = await import('../globals');
80
+ const { viewById } = await import('@preview-views');
81
+ const entry = viewById(viewId);
82
+ // A component-tree entry is navigation only (no mount); only a rendered view mounts here.
83
+ const view: RenderedView | undefined =
84
+ entry && !entry.componentTree ? entry : undefined;
85
+ // A page loaded without `?framework=` still gets the view's setup module.
86
+ await loadSetup(view?.framework ?? 'dom');
87
+ const element = document.getElementById(PREVIEW_MOUNT_ELEMENT_ID);
88
+ if (view && element) {
89
+ view.mount(element, context, {
90
+ subscribe(listener) {
91
+ listeners.add(listener);
92
+ return () => {
93
+ listeners.delete(listener);
94
+ };
95
+ },
96
+ });
97
+ }
98
+
99
+ window.addEventListener('message', (event: MessageEvent) => {
100
+ const message = readPreviewMessage(event.data);
101
+ if (!message) return;
102
+ if (message.type === PREVIEW_MESSAGE.globals) {
103
+ applyGlobals(message.options);
104
+ update({ options: message.options ?? {} });
105
+ }
106
+ if (message.type === PREVIEW_MESSAGE.catalog) {
107
+ update({
108
+ kitName: message.kitName ?? '',
109
+ sources: message.sources ?? [],
110
+ components: message.components ?? [],
111
+ });
112
+ // The view with its catalog, once painted, lets the host show the pane.
113
+ announcePreviewShown();
114
+ }
115
+ });
116
+ // Signal readiness so the host replays the current globals (an iframe
117
+ // re-handshakes after each reload), and set the ready flag a test that
118
+ // loads this page on its own waits on.
119
+ announcePreviewReady();
120
+ // The view's size reaches the host on each change, so a shell can size the pane to it.
121
+ if (element) reportContentSize(element);
122
+ }
123
+
124
+ void start();
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>preview - view</title>
7
+ </head>
8
+ <body>
9
+ <div id="app"></div>
10
+ <script type="module" src="./main.ts"></script>
11
+ </body>
12
+ </html>