@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,218 @@
1
+ import type { ManifestComponent } from './emit/manifest.js';
2
+ import type { OptionValue } from './options.js';
3
+ import { PREVIEW_MOUNT_ELEMENT_ID, PREVIEW_RENDER_ERROR_FLAG, type PreviewScriptedTarget } from './protocol.js';
4
+ /** The id of the element a preview page mounts its story or view in. */
5
+ export { PREVIEW_MOUNT_ELEMENT_ID };
6
+ /** A component as the preview manifest lists it: the parts a browser test
7
+ * reads. */
8
+ export type PreviewManifestComponent = Pick<ManifestComponent, 'id' | 'name'> & Partial<Pick<ManifestComponent, 'defaultProps' | 'previewDefaults' | 'standalone' | 'targets' | 'bindings'>> & {
9
+ /** The story's scenarios, each with the props it sets over the defaults
10
+ * and, for one with slot content of its own, that content and the id
11
+ * its story mounts by. */
12
+ scenarios?: (Pick<ManifestComponent['scenarios'][number], 'id'> & Partial<Pick<ManifestComponent['scenarios'][number], 'label' | 'props' | 'content' | 'story'>>)[];
13
+ };
14
+ /**
15
+ * Read the components of a kit's preview manifest,
16
+ * `.preview-generated/manifest.json`, which the preview writes when it
17
+ * starts.
18
+ *
19
+ * @param kitRoot - The kit's root directory.
20
+ * @returns The components the manifest lists.
21
+ * @example
22
+ * ```ts
23
+ * for (const component of readPreviewManifest('.')) {
24
+ * test(component.id, async ({ page }) => {});
25
+ * }
26
+ * ```
27
+ */
28
+ export declare function readPreviewManifest(kitRoot: string): PreviewManifestComponent[];
29
+ /** The window property a story page sets to what its story threw; see
30
+ * {@link readRenderError}. */
31
+ export { PREVIEW_RENDER_ERROR_FLAG };
32
+ /** A target whose preview page the helpers load: `react`, `vue` or `svelte`. */
33
+ export type { PreviewScriptedTarget };
34
+ /** Preview option values keyed by option id, such as `{ mode: 'dark' }`. */
35
+ export type PreviewOptionValues = Record<string, OptionValue>;
36
+ /**
37
+ * The part of a browser page the helpers use. A Playwright `Page` satisfies
38
+ * it, as does any object with these three methods.
39
+ */
40
+ export interface PreviewPage {
41
+ /** Navigate to `url`, resolving once the page has loaded. */
42
+ goto(url: string, options?: {
43
+ waitUntil?: 'load';
44
+ }): Promise<unknown>;
45
+ /** Resolve once `pageFunction`, run in the page with `argument`, returns a truthy value. */
46
+ waitForFunction<Argument>(pageFunction: (argument: Argument) => unknown, argument: Argument): Promise<unknown>;
47
+ /** Run `pageFunction` in the page with `argument` and resolve with its result. */
48
+ evaluate<Result, Argument>(pageFunction: (argument: Argument) => Result | Promise<Result>, argument: Argument): Promise<Result>;
49
+ }
50
+ /** Where the preview is served. */
51
+ export interface PreviewLocationOptions {
52
+ /** Prefixed to the preview page's path, such as `http://localhost:6100`.
53
+ * Omit it to navigate by path alone (resolved against the test runner's
54
+ * base URL, such as Playwright's `use.baseURL`). */
55
+ baseUrl?: string;
56
+ }
57
+ /**
58
+ * Load a target's preview page and wait until it listens for messages. The
59
+ * page shows nothing until a story is set.
60
+ *
61
+ * @param page - The browser page.
62
+ * @param target - The target whose preview page to load.
63
+ * @param options - Where the preview is served.
64
+ * @throws When the target has no story page, the message naming those that
65
+ * do, or when the page never starts listening, such as after an import
66
+ * fails to load.
67
+ * @example
68
+ * ```ts
69
+ * test.beforeEach(async ({ page }) => {
70
+ * await gotoPreview(page, 'vue');
71
+ * });
72
+ * ```
73
+ */
74
+ export declare function gotoPreview(page: PreviewPage, target: PreviewScriptedTarget, options?: PreviewLocationOptions): Promise<void>;
75
+ /**
76
+ * The ids of the stories a preview page can mount.
77
+ *
78
+ * @param page - A page {@link gotoPreview} loaded.
79
+ * @returns The story ids.
80
+ * @throws When the page is not a preview page that mounts stories.
81
+ */
82
+ export declare function readStoryIds(page: PreviewPage): Promise<string[]>;
83
+ /**
84
+ * What the story mounted on a preview page threw as it rendered, as the pane
85
+ * reports it: only a throw that reaches the pane counts, so a story with its
86
+ * own error boundary, or the word "error" in its content, reads as rendering.
87
+ *
88
+ * @param page - A page {@link gotoPreview} loaded.
89
+ * @returns The error's message, which may be empty, or `undefined` when the
90
+ * story renders.
91
+ * @example
92
+ * ```ts
93
+ * await mountStory(page, 'components-button');
94
+ * await settle(page);
95
+ * expect(await readRenderError(page)).toBeUndefined();
96
+ * ```
97
+ */
98
+ export declare function readRenderError(page: PreviewPage): Promise<string | undefined>;
99
+ /**
100
+ * Mount a story by id with the given root props, replacing what the page
101
+ * shows. Setting the story already shown with other props keeps its component
102
+ * instance on some targets; use {@link mountStory} for a guaranteed fresh
103
+ * mount.
104
+ *
105
+ * @param page - A page {@link gotoPreview} loaded.
106
+ * @param id - The story's id.
107
+ * @param props - The story's root props.
108
+ * @throws When the page has no story with the id; the message lists those it
109
+ * has.
110
+ */
111
+ export declare function setStory(page: PreviewPage, id: string, props?: Record<string, unknown>): Promise<void>;
112
+ /**
113
+ * Mount a story from nothing: blur the focused element, unmount the current
114
+ * story and wait for the mount point to empty, then set the story. The new
115
+ * story inherits neither focus nor component state from the one before, which
116
+ * a sweep over a component's states needs (a state read at mount, such as an
117
+ * initially open panel, only applies to a fresh instance).
118
+ *
119
+ * @param page - A page {@link gotoPreview} loaded.
120
+ * @param id - The story's id.
121
+ * @param props - The story's root props.
122
+ * @throws When the page has no story with the id, the message listing those
123
+ * it has, or when the mount is not empty within 15 seconds of the unmount.
124
+ */
125
+ export declare function mountStory(page: PreviewPage, id: string, props?: Record<string, unknown>): Promise<void>;
126
+ /**
127
+ * Wait until a story set with {@link mountStory} has finished mounting,
128
+ * whatever it rendered: a story can legitimately render nothing, which an
129
+ * element to wait for would never show, and a story that throws counts as
130
+ * mounted. It follows `mountStory`, which clears the page's last report;
131
+ * after {@link setStory} that report can be the same story's from before.
132
+ *
133
+ * @param page - A page {@link gotoPreview} loaded.
134
+ * @param id - The story's id.
135
+ * @throws When the story does not finish mounting within 15 seconds.
136
+ * @example
137
+ * ```ts
138
+ * await mountStory(page, 'components-banner', { visible: false });
139
+ * await waitForStory(page, 'components-banner');
140
+ * await expect(page.locator('#app > *')).toHaveCount(0);
141
+ * ```
142
+ */
143
+ export declare function waitForStory(page: PreviewPage, id: string): Promise<void>;
144
+ /**
145
+ * Replace the mounted story's root props, keeping its component instance (and
146
+ * any state machine driving it) alive.
147
+ *
148
+ * @param page - A page {@link gotoPreview} loaded.
149
+ * @param props - The story's new root props.
150
+ */
151
+ export declare function setProps(page: PreviewPage, props: Record<string, unknown>): Promise<void>;
152
+ /**
153
+ * Apply preview option values (a color mode, a surface, a frame around the
154
+ * story) to the page, as the preview's controls do.
155
+ *
156
+ * @param page - A page {@link gotoPreview} loaded.
157
+ * @param options - Option values keyed by option id.
158
+ * @throws When an id is not one of the kit's options, or a value is not one
159
+ * the option takes, either of which the page would ignore; the message lists
160
+ * what it defines.
161
+ */
162
+ export declare function setOptions(page: PreviewPage, options: PreviewOptionValues): Promise<void>;
163
+ /**
164
+ * Wait until the frame after the next paint. A component can show its final
165
+ * markup before the effects that attach its event handling have run; call this
166
+ * after asserting a change has rendered and before sending input, such as a
167
+ * key press, that would otherwise be dropped.
168
+ *
169
+ * @param page - The browser page.
170
+ */
171
+ export declare function settle(page: PreviewPage): Promise<void>;
172
+ /** What {@link openStory} loads and mounts. */
173
+ export interface OpenStoryOptions extends PreviewLocationOptions {
174
+ /** The target whose preview page to load. */
175
+ target: PreviewScriptedTarget;
176
+ /** The story's id, as the catalog and the address name it, such as
177
+ * `components-button` (`PreviewComponent.id`). */
178
+ id: string;
179
+ /** The story's root props. */
180
+ props?: Record<string, unknown>;
181
+ /** Preview option values applied before the story mounts. */
182
+ options?: PreviewOptionValues;
183
+ }
184
+ /** A story open in a page, with the page's controls bound to it. */
185
+ export interface PreviewStory<Page extends PreviewPage = PreviewPage> {
186
+ /** The page showing the story; the preview page is loaded at the top level,
187
+ * so locators and keyboard input go straight to it. */
188
+ page: Page;
189
+ /** The target the story renders in. */
190
+ target: PreviewScriptedTarget;
191
+ /** Replace the story's root props, keeping its component instance. */
192
+ setProps(props: Record<string, unknown>): Promise<void>;
193
+ /** Apply preview option values. */
194
+ setOptions(options: PreviewOptionValues): Promise<void>;
195
+ /** Show another story (see {@link setStory}). */
196
+ setStory(id: string, props?: Record<string, unknown>): Promise<void>;
197
+ /** Show another story from a fresh mount (see {@link mountStory}). */
198
+ mountStory(id: string, props?: Record<string, unknown>): Promise<void>;
199
+ /** Wait until the frame after the next paint (see {@link settle}). */
200
+ settle(): Promise<void>;
201
+ }
202
+ /**
203
+ * Load a target's preview page and mount one story in it.
204
+ *
205
+ * @param page - The browser page.
206
+ * @param options - The target, the story and its props, and option values.
207
+ * @returns The open story.
208
+ * @throws When the page has no story with the id, or an option id is not one
209
+ * of the kit's; the message lists those it has.
210
+ * @example
211
+ * ```ts
212
+ * const story = await openStory(page, { target: 'vue', id: 'components-button', props: { variant: 'solid' } });
213
+ * await story.setProps({ variant: 'ghost' });
214
+ * await story.setOptions({ mode: 'dark' });
215
+ * await expect(story.page.getByRole('button')).toHaveClass(/ghost/);
216
+ * ```
217
+ */
218
+ export declare function openStory<Page extends PreviewPage>(page: Page, options: OpenStoryOptions): Promise<PreviewStory<Page>>;
@@ -0,0 +1,284 @@
1
+ // Browser-test helpers for a kit's components: load one target's preview page
2
+ // on its own and drive it over the messages the preview host sends it. The page
3
+ // object is typed structurally, so a Playwright `Page` fits without the preview
4
+ // depending on Playwright. The functions handed to `evaluate` and
5
+ // `waitForFunction` run in the browser, so they read only their argument and
6
+ // browser globals, never this module's bindings.
7
+ import { readFileSync } from 'node:fs';
8
+ import { join } from 'node:path';
9
+ import { componentFrameUrl, globalsMessage, PREVIEW_MOUNT_ELEMENT_ID, PREVIEW_MOUNTED_STORY_FLAG, PREVIEW_OPTIONS_FLAG, PREVIEW_READY_FLAG, PREVIEW_RENDER_ERROR_FLAG, PREVIEW_SCRIPTED_TARGETS, PREVIEW_STORIES_FLAG, propsMessage, setStoryMessage, } from './protocol.js';
10
+ /** The id of the element a preview page mounts its story or view in. */
11
+ export { PREVIEW_MOUNT_ELEMENT_ID };
12
+ /**
13
+ * Read the components of a kit's preview manifest,
14
+ * `.preview-generated/manifest.json`, which the preview writes when it
15
+ * starts.
16
+ *
17
+ * @param kitRoot - The kit's root directory.
18
+ * @returns The components the manifest lists.
19
+ * @example
20
+ * ```ts
21
+ * for (const component of readPreviewManifest('.')) {
22
+ * test(component.id, async ({ page }) => {});
23
+ * }
24
+ * ```
25
+ */
26
+ export function readPreviewManifest(kitRoot) {
27
+ const manifest = JSON.parse(readFileSync(join(kitRoot, '.preview-generated', 'manifest.json'), 'utf8'));
28
+ return manifest.components;
29
+ }
30
+ /** The window property a story page sets to what its story threw; see
31
+ * {@link readRenderError}. */
32
+ export { PREVIEW_RENDER_ERROR_FLAG };
33
+ /** How long a loaded preview page has to start listening. The page's load
34
+ * has already waited for its modules, so only a page that failed to run
35
+ * them comes near this. */
36
+ const READY_TIMEOUT_MILLISECONDS = 15_000;
37
+ /** How long a story set on a loaded page has to finish mounting. Mounting
38
+ * needs no network, so only a page that has stopped comes near this. */
39
+ const STORY_TIMEOUT_MILLISECONDS = 15_000;
40
+ /** Wait for `wait`, or throw `message` past the deadline. A wait left past
41
+ * the deadline rejects when the page closes, which is ignored. */
42
+ async function withinDeadline(wait, milliseconds, message) {
43
+ wait.catch(() => { });
44
+ let timer;
45
+ const deadline = new Promise((_, reject) => {
46
+ timer = setTimeout(() => reject(new Error(message)), milliseconds);
47
+ });
48
+ try {
49
+ await Promise.race([wait, deadline]);
50
+ }
51
+ finally {
52
+ clearTimeout(timer);
53
+ }
54
+ }
55
+ /**
56
+ * Load a target's preview page and wait until it listens for messages. The
57
+ * page shows nothing until a story is set.
58
+ *
59
+ * @param page - The browser page.
60
+ * @param target - The target whose preview page to load.
61
+ * @param options - Where the preview is served.
62
+ * @throws When the target has no story page, the message naming those that
63
+ * do, or when the page never starts listening, such as after an import
64
+ * fails to load.
65
+ * @example
66
+ * ```ts
67
+ * test.beforeEach(async ({ page }) => {
68
+ * await gotoPreview(page, 'vue');
69
+ * });
70
+ * ```
71
+ */
72
+ export async function gotoPreview(page, target, options = {}) {
73
+ if (!PREVIEW_SCRIPTED_TARGETS.includes(target)) {
74
+ throw new Error(`'${target}' has no story page; the story pages are ${PREVIEW_SCRIPTED_TARGETS.join(', ')}`);
75
+ }
76
+ const baseUrl = (options.baseUrl ?? '').replace(/\/+$/, '');
77
+ const url = `${baseUrl}${componentFrameUrl(target)}`;
78
+ await page.goto(url, { waitUntil: 'load' });
79
+ await withinDeadline(page.waitForFunction((flag) => window[flag] === true, PREVIEW_READY_FLAG), READY_TIMEOUT_MILLISECONDS, `gotoPreview: the preview page at ${url} never announced itself: look for a page error (an import that fails to load) in the browser console or the web server log.`);
80
+ }
81
+ /** Post a preview message to the page's own window, where the preview listens. */
82
+ async function post(page, message) {
83
+ await page.evaluate((posted) => window.postMessage(posted, '*'), message);
84
+ }
85
+ /**
86
+ * What a preview page lists under a window property. A message posted to a
87
+ * page that lists nothing would reach nothing, so that throws, saying whether
88
+ * the page is a preview page at all.
89
+ */
90
+ async function listedEntries(page, flag, helper) {
91
+ const read = (name) => window[name];
92
+ const ids = await page.evaluate(read, flag);
93
+ if (!Array.isArray(ids)) {
94
+ throw new Error((await page.evaluate(read, PREVIEW_READY_FLAG)) === true
95
+ ? `${helper}: this is a preview page that mounts no story (its html or view page, or a preview older than these helpers).`
96
+ : `${helper} needs a loaded preview page, and this page is not one: load it with gotoPreview first.`);
97
+ }
98
+ return ids;
99
+ }
100
+ /**
101
+ * The ids of the stories a preview page can mount.
102
+ *
103
+ * @param page - A page {@link gotoPreview} loaded.
104
+ * @returns The story ids.
105
+ * @throws When the page is not a preview page that mounts stories.
106
+ */
107
+ export function readStoryIds(page) {
108
+ return listedEntries(page, PREVIEW_STORIES_FLAG, 'readStoryIds');
109
+ }
110
+ /**
111
+ * What the story mounted on a preview page threw as it rendered, as the pane
112
+ * reports it: only a throw that reaches the pane counts, so a story with its
113
+ * own error boundary, or the word "error" in its content, reads as rendering.
114
+ *
115
+ * @param page - A page {@link gotoPreview} loaded.
116
+ * @returns The error's message, which may be empty, or `undefined` when the
117
+ * story renders.
118
+ * @example
119
+ * ```ts
120
+ * await mountStory(page, 'components-button');
121
+ * await settle(page);
122
+ * expect(await readRenderError(page)).toBeUndefined();
123
+ * ```
124
+ */
125
+ export async function readRenderError(page) {
126
+ const message = await page.evaluate((flag) => window[flag], PREVIEW_RENDER_ERROR_FLAG);
127
+ return typeof message === 'string' ? message : undefined;
128
+ }
129
+ /** Throw unless the page can mount the story: a page shows nothing for an id
130
+ * it does not know, and every check on the empty mount would pass. */
131
+ async function requireStory(page, id, helper) {
132
+ const known = await listedEntries(page, PREVIEW_STORIES_FLAG, helper);
133
+ if (!known.includes(id)) {
134
+ throw new Error(`${helper}: this preview has no story with the id '${id}'. Its stories: ${known.join(', ') || 'none'}.`);
135
+ }
136
+ }
137
+ /**
138
+ * Mount a story by id with the given root props, replacing what the page
139
+ * shows. Setting the story already shown with other props keeps its component
140
+ * instance on some targets; use {@link mountStory} for a guaranteed fresh
141
+ * mount.
142
+ *
143
+ * @param page - A page {@link gotoPreview} loaded.
144
+ * @param id - The story's id.
145
+ * @param props - The story's root props.
146
+ * @throws When the page has no story with the id; the message lists those it
147
+ * has.
148
+ */
149
+ export async function setStory(page, id, props = {}) {
150
+ await requireStory(page, id, 'setStory');
151
+ await post(page, setStoryMessage(id, props));
152
+ }
153
+ /**
154
+ * Mount a story from nothing: blur the focused element, unmount the current
155
+ * story and wait for the mount point to empty, then set the story. The new
156
+ * story inherits neither focus nor component state from the one before, which
157
+ * a sweep over a component's states needs (a state read at mount, such as an
158
+ * initially open panel, only applies to a fresh instance).
159
+ *
160
+ * @param page - A page {@link gotoPreview} loaded.
161
+ * @param id - The story's id.
162
+ * @param props - The story's root props.
163
+ * @throws When the page has no story with the id, the message listing those
164
+ * it has, or when the mount is not empty within 15 seconds of the unmount.
165
+ */
166
+ export async function mountStory(page, id, props = {}) {
167
+ await requireStory(page, id, 'mountStory');
168
+ await page.evaluate(() => document.activeElement?.blur?.(), undefined);
169
+ // No story is registered under the empty id, so every target unmounts.
170
+ await post(page, setStoryMessage('', {}));
171
+ await withinDeadline(page.waitForFunction((mountId) => document.getElementById(mountId)?.childElementCount === 0, PREVIEW_MOUNT_ELEMENT_ID), STORY_TIMEOUT_MILLISECONDS, `mountStory: the page never cleared the mount ahead of the story '${id}': the story before it may have thrown as it unmounted; look for a page error in the browser console.`);
172
+ // The page's last report is cleared here, not awaited from the page: the
173
+ // pane reports its own unmount, but after its paint in React, which a mount
174
+ // already empty may be read before, and a story set twice in a row would
175
+ // then pass {@link waitForStory} on its first mount's report.
176
+ await page.evaluate((flag) => {
177
+ window[flag] = '';
178
+ }, PREVIEW_MOUNTED_STORY_FLAG);
179
+ await post(page, setStoryMessage(id, props));
180
+ }
181
+ /**
182
+ * Wait until a story set with {@link mountStory} has finished mounting,
183
+ * whatever it rendered: a story can legitimately render nothing, which an
184
+ * element to wait for would never show, and a story that throws counts as
185
+ * mounted. It follows `mountStory`, which clears the page's last report;
186
+ * after {@link setStory} that report can be the same story's from before.
187
+ *
188
+ * @param page - A page {@link gotoPreview} loaded.
189
+ * @param id - The story's id.
190
+ * @throws When the story does not finish mounting within 15 seconds.
191
+ * @example
192
+ * ```ts
193
+ * await mountStory(page, 'components-banner', { visible: false });
194
+ * await waitForStory(page, 'components-banner');
195
+ * await expect(page.locator('#app > *')).toHaveCount(0);
196
+ * ```
197
+ */
198
+ export async function waitForStory(page, id) {
199
+ await withinDeadline(page.waitForFunction((argument) => window[argument.flag] ===
200
+ argument.id, { id, flag: PREVIEW_MOUNTED_STORY_FLAG }), STORY_TIMEOUT_MILLISECONDS, `waitForStory: the story '${id}' never finished mounting: look for a page error in the browser console, or a page that has stopped responding.`);
201
+ }
202
+ /**
203
+ * Replace the mounted story's root props, keeping its component instance (and
204
+ * any state machine driving it) alive.
205
+ *
206
+ * @param page - A page {@link gotoPreview} loaded.
207
+ * @param props - The story's new root props.
208
+ */
209
+ export async function setProps(page, props) {
210
+ await post(page, propsMessage(props));
211
+ }
212
+ /**
213
+ * Apply preview option values (a color mode, a surface, a frame around the
214
+ * story) to the page, as the preview's controls do.
215
+ *
216
+ * @param page - A page {@link gotoPreview} loaded.
217
+ * @param options - Option values keyed by option id.
218
+ * @throws When an id is not one of the kit's options, or a value is not one
219
+ * the option takes, either of which the page would ignore; the message lists
220
+ * what it defines.
221
+ */
222
+ export async function setOptions(page, options) {
223
+ const listed = await listedEntries(page, PREVIEW_OPTIONS_FLAG, 'setOptions');
224
+ const known = listed.map((option) => option.id);
225
+ const unknown = Object.keys(options).filter((id) => !known.includes(id));
226
+ if (unknown.length > 0) {
227
+ throw new Error(`setOptions: this preview defines no option ${unknown.map((id) => `'${id}'`).join(', ')}. Its options: ${known.join(', ') || 'none'}.`);
228
+ }
229
+ for (const [id, value] of Object.entries(options)) {
230
+ const { values } = listed.find((option) => option.id === id);
231
+ if (values ? !values.includes(value) : typeof value !== 'boolean') {
232
+ throw new Error(values
233
+ ? `setOptions: option '${id}' has no value ${JSON.stringify(value)}. Its values: ${values.join(', ')}.`
234
+ : `setOptions: option '${id}' takes true or false, not ${JSON.stringify(value)}.`);
235
+ }
236
+ }
237
+ await post(page, globalsMessage(options));
238
+ }
239
+ /**
240
+ * Wait until the frame after the next paint. A component can show its final
241
+ * markup before the effects that attach its event handling have run; call this
242
+ * after asserting a change has rendered and before sending input, such as a
243
+ * key press, that would otherwise be dropped.
244
+ *
245
+ * @param page - The browser page.
246
+ */
247
+ export async function settle(page) {
248
+ await page.evaluate(() => new Promise((resolve) => {
249
+ requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
250
+ }), undefined);
251
+ }
252
+ /**
253
+ * Load a target's preview page and mount one story in it.
254
+ *
255
+ * @param page - The browser page.
256
+ * @param options - The target, the story and its props, and option values.
257
+ * @returns The open story.
258
+ * @throws When the page has no story with the id, or an option id is not one
259
+ * of the kit's; the message lists those it has.
260
+ * @example
261
+ * ```ts
262
+ * const story = await openStory(page, { target: 'vue', id: 'components-button', props: { variant: 'solid' } });
263
+ * await story.setProps({ variant: 'ghost' });
264
+ * await story.setOptions({ mode: 'dark' });
265
+ * await expect(story.page.getByRole('button')).toHaveClass(/ghost/);
266
+ * ```
267
+ */
268
+ export async function openStory(page, options) {
269
+ const { target, id, props = {}, options: optionValues, baseUrl } = options;
270
+ await gotoPreview(page, target, { baseUrl });
271
+ if (optionValues)
272
+ await setOptions(page, optionValues);
273
+ await requireStory(page, id, 'openStory');
274
+ await post(page, setStoryMessage(id, props));
275
+ return {
276
+ page,
277
+ target,
278
+ setProps: (next) => setProps(page, next),
279
+ setOptions: (next) => setOptions(page, next),
280
+ setStory: (nextId, nextProps) => setStory(page, nextId, nextProps),
281
+ mountStory: (nextId, nextProps) => mountStory(page, nextId, nextProps),
282
+ settle: () => settle(page),
283
+ };
284
+ }
@@ -0,0 +1,152 @@
1
+ import type { OptionValue } from './options.js';
2
+ export { reactView, type ReactViewRender } from './react-view.js';
3
+ /** One entry of the component index a view receives: a browseable story the
4
+ * view can cross-reference or select. */
5
+ export interface ViewContextComponent {
6
+ /** The component's selection id - pass to `selectComponent` to open its story. */
7
+ id: string;
8
+ /** The full title (source label prefix included). */
9
+ title: string;
10
+ /** The preview source (navigation section) the component belongs to. */
11
+ source: string;
12
+ }
13
+ /** A source as a view sees it - the kit's own source plus any other package whose components it shows. */
14
+ export interface ViewContextSource {
15
+ id: string;
16
+ label: string;
17
+ order: number;
18
+ }
19
+ /** What the preview passes a view. `options` is live (a new context arrives
20
+ * on every change, see `ViewContextUpdates`); the catalog fields are a
21
+ * read-only snapshot of the kit's catalog, so a view can cross-link into a
22
+ * component story. A view reads
23
+ * what it needs (a foundations view reads `options.theme` to pick its palette;
24
+ * a gallery resolves a component from `components` and deep-links via
25
+ * `selectComponent`). */
26
+ export interface ViewContext {
27
+ options: Record<string, OptionValue>;
28
+ /** The kit being previewed. Empty until the host handshake delivers the catalog. */
29
+ kitName: string;
30
+ /** The sources, ordered. Empty until the handshake delivers the catalog. */
31
+ sources: ViewContextSource[];
32
+ /** The browseable component stories (components that are not standalone and unlisted
33
+ * stories excluded; an unlisted story's id still selects it). Empty until
34
+ * the handshake delivers the catalog. */
35
+ components: ViewContextComponent[];
36
+ /**
37
+ * Ask the preview to select a component story, as choosing it in the
38
+ * preview's navigation does. With `props`, the story opens with those root props merged
39
+ * over the component's defaults (a gallery opens the clicked entry's variant);
40
+ * without, it opens on its baseline scenario. Unknown ids are ignored.
41
+ */
42
+ selectComponent: (id: string, props?: Record<string, unknown>) => void;
43
+ }
44
+ /** Fields common to every navigation entry a kit registers. */
45
+ interface PreviewEntryBase {
46
+ /** Reserved selection id - also the view iframe's `?view=` parameter. */
47
+ id: string;
48
+ /** The entry's name in the navigation. */
49
+ label: string;
50
+ /** The source whose entries list this one (a source id from
51
+ * `preview.sources`); defaults to the kit's own (first) source. */
52
+ source?: string;
53
+ /** Position among the source's entries - lower first. Views and the
54
+ * auto-generated component tree interleave by this. */
55
+ order?: number;
56
+ }
57
+ /** The framework a view mounts with. The view iframe loads the kit's setup
58
+ * module for that framework (`preview.setupModules`) before it
59
+ * mounts the view; `'dom'` loads none. */
60
+ export type ViewFramework = 'react' | 'vue' | 'svelte' | 'dom';
61
+ /** How a mounted view hears of a changed context: the options as the
62
+ * preview applies them, and the catalog once the handshake delivers it. */
63
+ export interface ViewContextUpdates {
64
+ /**
65
+ * Call `listener` with each new context.
66
+ *
67
+ * @returns A function that stops the calls.
68
+ */
69
+ subscribe(listener: (context: ViewContext) => void): () => void;
70
+ }
71
+ /**
72
+ * Mount a view into `element` with the context as it stands. The view stays
73
+ * mounted for the life of the view iframe and follows later changes through
74
+ * `updates`; a view that ignores them shows the context it mounted with.
75
+ *
76
+ * @param element - The element the view renders into.
77
+ * @param context - The context as it stands when the view mounts.
78
+ * @param updates - Delivers each new context.
79
+ * @returns A function that unmounts the view, or nothing.
80
+ */
81
+ export type ViewMount = (element: HTMLElement, context: ViewContext, updates: ViewContextUpdates) => (() => void) | void;
82
+ /** A consumer-authored panel: the preview lists it beside the component stories
83
+ * and mounts it in the generic view iframe (`?view=<id>`) under the live
84
+ * options. */
85
+ export interface RenderedView extends PreviewEntryBase {
86
+ /** Discriminant - omit (or `false`) for a rendered view. */
87
+ componentTree?: false;
88
+ /** The framework `mount` renders with. Default `'dom'`. */
89
+ framework?: ViewFramework;
90
+ /** Mount the view inside the view iframe. */
91
+ mount: ViewMount;
92
+ }
93
+ /** The "magic" entry standing in for the source's auto-generated component tree (its
94
+ * stories) at a chosen position. It mounts no iframe, so it carries no `mount`. */
95
+ export interface ComponentTreeEntry extends PreviewEntryBase {
96
+ componentTree: true;
97
+ mount?: never;
98
+ }
99
+ /** A navigation entry a kit's `viewsModule` registers: either a rendered view or the
100
+ * component-tree marker. The two interleave by `order`. */
101
+ export type PreviewView = RenderedView | ComponentTreeEntry;
102
+ /** What the kit's `viewsModule` must export. */
103
+ export interface PreviewViewsModule {
104
+ views: PreviewView[];
105
+ viewById: (id: string) => PreviewView | undefined;
106
+ }
107
+ /** The language of a code block's source, as a highlighter names it: a
108
+ * scripted target's file (`tsx`, `vue`, `svelte`) or the html target's
109
+ * markup. */
110
+ export type CodeBlockLanguage = 'tsx' | 'vue' | 'svelte' | 'html';
111
+ /** What a code block shows: one target's source of the story, or, while it
112
+ * has none, nothing (it is being printed) or why there is none. */
113
+ export interface CodeBlockContent {
114
+ /** The target the source is for: a scripted target, or `html`. */
115
+ target: 'react' | 'vue' | 'svelte' | 'html';
116
+ language: CodeBlockLanguage;
117
+ /** The source, as a consumer writes it. */
118
+ source?: string;
119
+ /** Why the target has no source, when it has none to be had. */
120
+ reason?: string;
121
+ /** Whether the shell wraps its code panes' long lines: the block wraps
122
+ * them when true and scrolls sideways when false. A shell with no such
123
+ * choice sends false. */
124
+ wrap: boolean;
125
+ }
126
+ /** How a mounted code block hears of a new source: each time the story, its
127
+ * props or its content change, or the shell's wrapping does. */
128
+ export interface CodeBlockUpdates {
129
+ /**
130
+ * Call `listener` with each new content.
131
+ *
132
+ * @returns A function that stops the calls.
133
+ */
134
+ subscribe(listener: (content: CodeBlockContent) => void): () => void;
135
+ }
136
+ /**
137
+ * Mount a kit's code block into `element`, showing `content`, the default
138
+ * export of the module the kit names as its `codeBlock`. The block stays
139
+ * mounted for the life of its iframe, one per code pane, and follows later
140
+ * sources through `updates`. It wraps long lines while `content.wrap` is
141
+ * true and scrolls sideways while it is false, as the shell's own panes do.
142
+ * The iframe's page is the block's alone: its root carries
143
+ * `data-preview-frame="code"`, so the kit's stylesheet may style the frame's
144
+ * `html` and `body` by it, say in the block's background so an overscroll
145
+ * shows no other color.
146
+ *
147
+ * @param element - The element the block renders into.
148
+ * @param content - The source as it stands when the block mounts.
149
+ * @param updates - Delivers each new source.
150
+ * @returns A function that unmounts the block, or nothing.
151
+ */
152
+ export type CodeBlockMount = (element: HTMLElement, content: CodeBlockContent, updates: CodeBlockUpdates) => (() => void) | void;
package/dist/views.js ADDED
@@ -0,0 +1,7 @@
1
+ // The custom-view contract: what a kit's `viewsModule` exports. A view is a
2
+ // consumer-authored panel the preview lists beside the component stories and
3
+ // mounts in the dedicated view iframe (`?view=<id>`) under the live options
4
+ // context - tokens pages, galleries, composed demos. A view mounts itself into
5
+ // an element in any of the preview's frameworks, or in plain DOM; `reactView`
6
+ // adapts a React render function. Browser-safe.
7
+ export { reactView } from './react-view.js';