@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,110 @@
1
+ // A component story: the stage bar (StageBar), which picks the component
2
+ // and its scenario and sets the context the story is shown in. Then the
3
+ // stage's views, each a row the top bar toggles and the address keeps, each
4
+ // under its heading (ViewHeading): the scenario row (ScenarioRow) over the
5
+ // grid (PreviewGrid) of the output row, a preview pane per target, and the
6
+ // code row, each target's source under its pane (CodePane), over the events
7
+ // row (EventsRow), the rows sharing the height in a split the reader can drag
8
+ // (StageSplit). A row after the scenario row is headed on its handle's row,
9
+ // or on a row of its own with none above, with that view's controls at the
10
+ // row's end (ViewControls): output's options, its width (PaneWidth) among
11
+ // them, code's options and wrap toggle
12
+ // (WrapToggle), or the events' options and clear (EventsClear). With no view
13
+ // showing, a note says how to show one.
14
+ //
15
+ // The editor is the scenario row's: it is open while the row shows, where the
16
+ // preview can regenerate, and closed while it is hidden. Closing it keeps its
17
+ // tree, so showing the row again brings the same tree back, until another
18
+ // story or scenario is picked; selecting another story closes the editor, and
19
+ // the row opens it again on the new story. Where there is an editor, the row
20
+ // first shows once it is open, before the page paints, so the row starts at
21
+ // the height of its content with the editor's tree in it; it then stays
22
+ // through another story's selection, at the height the reader left it.
23
+ import { useLayoutEffect, useRef } from 'react';
24
+ import { usePreviewController, usePreviewState } from '../../controller-context';
25
+ import { PaneWidth, usePaneWidthShown } from '../PaneWidth';
26
+ import { PreviewGrid } from '../PreviewGrid';
27
+ import { ScenarioRow } from '../ScenarioRow';
28
+ import { StageSplit } from '../StageSplit';
29
+ import { EventsClear, EventsRow } from '../EventsRow';
30
+ import { CODE_VIEW_OPTION, EVENTS_VIEW_OPTION, OUTPUT_VIEW_OPTION, SCENARIO_VIEW_OPTION } from '../../shell-options';
31
+ import { useStage } from '../../stage-toggles';
32
+ import { StageBar } from '../StageBar';
33
+ import { ViewControls } from '../ViewControls';
34
+ import { ViewHeading } from '../ViewHeading';
35
+ import { WrapToggle } from '../WrapToggle';
36
+ import './index.css';
37
+
38
+ export function ComponentStage() {
39
+ const controller = usePreviewController();
40
+ const selection = usePreviewState((state) => state.selection);
41
+ const editorOpen = usePreviewState((state) => state.editor.open);
42
+ // The views and panes the stage shows: in a narrow window the first of each.
43
+ const { views, panes } = useStage();
44
+ const scenarioShown = views.has(SCENARIO_VIEW_OPTION);
45
+ const outputShown = views.has(OUTPUT_VIEW_OPTION);
46
+ const codeShown = views.has(CODE_VIEW_OPTION);
47
+ const eventsShown = views.has(EVENTS_VIEW_OPTION);
48
+ const sourced = usePreviewState((state) => state.code !== undefined);
49
+ const paneWidthShown = usePaneWidthShown();
50
+ const selected = controller.catalog.components.find((component) => component.id === selection.id);
51
+ const editable = controller.capabilities.regeneration && selected !== undefined;
52
+ const code = Boolean(selected && codeShown && sourced);
53
+
54
+ // Whether the scenario row shows: once the editor is open, where there is
55
+ // one, and from then on until the view is hidden.
56
+ const rowShown = useRef(false);
57
+ rowShown.current = Boolean(selected && scenarioShown && (editorOpen || !editable || rowShown.current));
58
+
59
+ // The editor follows the scenario row.
60
+ useLayoutEffect(() => {
61
+ if (!editable) return;
62
+ if (scenarioShown && !editorOpen) controller.editor.open();
63
+ else if (!scenarioShown && editorOpen) controller.editor.close();
64
+ }, [controller, editable, scenarioShown, editorOpen, selection]);
65
+
66
+ return (
67
+ <div className="ComponentStage">
68
+ <StageBar />
69
+ <div className="ComponentStage__body">
70
+ {!scenarioShown && !outputShown && !code && !eventsShown && (
71
+ <p className="ComponentStage__note" data-testid="stage-note">
72
+ No view is showing: turn on scenario, output, code or events in the top bar.
73
+ </p>
74
+ )}
75
+ <StageSplit
76
+ rows={[
77
+ { id: 'scenario', shown: rowShown.current, content: <ScenarioRow /> },
78
+ {
79
+ id: 'grid',
80
+ shown: outputShown || code,
81
+ label: 'resize scenario and panes',
82
+ content: <PreviewGrid targets={panes} output={outputShown} code={code} />,
83
+ heading: <ViewHeading>{outputShown || !code ? 'output' : 'code'}</ViewHeading>,
84
+ controls:
85
+ outputShown || !code ? (
86
+ <ViewControls view="output" options={paneWidthShown ? <PaneWidth /> : undefined} />
87
+ ) : (
88
+ <ViewControls view="code">
89
+ <WrapToggle />
90
+ </ViewControls>
91
+ ),
92
+ },
93
+ {
94
+ id: 'events',
95
+ shown: Boolean(selected && eventsShown),
96
+ label: outputShown || code ? 'resize panes and events' : 'resize scenario and events',
97
+ content: <EventsRow />,
98
+ heading: <ViewHeading>events</ViewHeading>,
99
+ controls: (
100
+ <ViewControls view="events">
101
+ <EventsClear />
102
+ </ViewControls>
103
+ ),
104
+ },
105
+ ]}
106
+ />
107
+ </div>
108
+ </div>
109
+ );
110
+ }
@@ -0,0 +1,20 @@
1
+ @layer charcell.components {
2
+ /* A control's name and its control are two cells of the grid it sits in
3
+ (the props window's), so the names line up in one column and the
4
+ controls in the next. */
5
+ .Control {
6
+ display: contents;
7
+ }
8
+ .Control__label {
9
+ min-height: var(--charcell-row);
10
+ display: flex;
11
+ align-items: center;
12
+ color: var(--charcell-mid);
13
+ }
14
+ .Control__value {
15
+ min-width: 0;
16
+ min-height: var(--charcell-row);
17
+ display: flex;
18
+ align-items: center;
19
+ }
20
+ }
@@ -0,0 +1,118 @@
1
+ // One prop control (text / boolean / number / select / color-select) in the
2
+ // scenario editor's props window: the prop's name and its control, laid as two
3
+ // cells of the window's grid, so every name lines up in one column and every
4
+ // control in the next. A prop left unset shows the default the component
5
+ // declares or documents: in a select's unset option (`(unset: solid)`), as a
6
+ // field's placeholder, and as a boolean's state. Composed from charcell's
7
+ // TextInput and Toggle and the preview's Select. Styled in its index.css.
8
+ import { useId } from 'react';
9
+ import { TextInput, Toggle } from 'charcell/react/unlinked';
10
+ import type { PreviewPropType } from '../../../../../src/shell';
11
+ import { usePreviewController } from '../../controller-context';
12
+ import { Select } from '../Select';
13
+ import { Hint } from '../Hint';
14
+ import './index.css';
15
+
16
+ type Json = unknown;
17
+
18
+ /** The default a prop takes while unset, as the reader reads it: the
19
+ * component's declared default, or else the one it documents, its quotes
20
+ * dropped. */
21
+ function defaultOf(propType: PreviewPropType): string | undefined {
22
+ if (propType.declaredDefault !== undefined && propType.declaredDefault !== null)
23
+ return typeof propType.declaredDefault === 'string'
24
+ ? propType.declaredDefault
25
+ : JSON.stringify(propType.declaredDefault);
26
+ return propType.documentedDefault?.replace(/^(['"`])(.*)\1$/, '$2');
27
+ }
28
+
29
+ export function Control(props: { propType: PreviewPropType; value: Json; onChange: (nextValue: Json) => void }) {
30
+ const { propType, value, onChange } = props;
31
+ const controller = usePreviewController();
32
+ const id = useId();
33
+ const fallback = defaultOf(propType);
34
+ let control: React.ReactNode;
35
+ let labeled = true;
36
+ if (propType.control === 'boolean') {
37
+ // Unset, a boolean shows the state its default gives it.
38
+ const on = value === undefined ? fallback === 'true' : Boolean(value);
39
+ // The toggle's text is its state; the prop's name names it.
40
+ labeled = false;
41
+ control = (
42
+ <Toggle variant="dense" aria-labelledby={`${id}-label`} label={on ? 'on' : 'off'} pressed={on} onPressedChange={() => onChange(!on)} />
43
+ );
44
+ } else if (propType.control === 'number') {
45
+ const numberRange = propType.number ?? {};
46
+ control = (
47
+ <TextInput
48
+ id={id}
49
+ variant="dense"
50
+ type="number"
51
+ min={numberRange.min}
52
+ max={numberRange.max}
53
+ step={numberRange.step}
54
+ placeholder={fallback}
55
+ value={value === undefined ? '' : String(value)}
56
+ onChange={(event) => onChange(event.target.value === '' ? undefined : Number(event.target.value))}
57
+ />
58
+ );
59
+ } else if (propType.control === 'select' || propType.control === 'color-select') {
60
+ // A select's values are strings or booleans (`boolean | 'indeterminate'`
61
+ // offers true, false and 'indeterminate'), each written as its text and
62
+ // read back as the value it stands for.
63
+ const raw: (string | boolean | null | undefined)[] =
64
+ propType.control === 'color-select' ? controller.catalog.colorTokens : propType.options ?? [];
65
+ const unset = fallback === undefined ? '(unset)' : `(unset: ${fallback})`;
66
+ control = (
67
+ <Select
68
+ id={id}
69
+ value={value === undefined ? '' : String(value)}
70
+ onChange={(selected) =>
71
+ onChange(
72
+ selected === ''
73
+ ? undefined
74
+ : raw.find((option) => option !== null && option !== undefined && String(option) === selected) ?? selected
75
+ )
76
+ }
77
+ options={raw.map((option) => ({
78
+ value: option === null || option === undefined ? '' : String(option),
79
+ label: option === null || option === undefined ? unset : String(option),
80
+ }))}
81
+ />
82
+ );
83
+ } else {
84
+ control = (
85
+ <TextInput
86
+ id={id}
87
+ variant="dense"
88
+ type="text"
89
+ placeholder={fallback}
90
+ value={value === undefined ? '' : String(value)}
91
+ onChange={(event) => onChange(event.target.value)}
92
+ />
93
+ );
94
+ }
95
+ return (
96
+ // The description is a hint over the name: the row itself has no box
97
+ // to hover.
98
+ <div className="Control">
99
+ {/* `<id>-label`, as charcell's Field gives a label: a select and a
100
+ boolean's toggle name themselves from it. The hint takes it as its
101
+ trigger's id, so it opens beside the name. */}
102
+ <Hint text={propType.description} markdown triggerProps={{ id: `${id}-label` }}>
103
+ {(hint) =>
104
+ labeled ? (
105
+ <label {...hint} className="Control__label" htmlFor={id}>
106
+ {propType.name}
107
+ </label>
108
+ ) : (
109
+ <span {...hint} className="Control__label">
110
+ {propType.name}
111
+ </span>
112
+ )
113
+ }
114
+ </Hint>
115
+ <span className="Control__value">{control}</span>
116
+ </div>
117
+ );
118
+ }
@@ -0,0 +1,35 @@
1
+ // The status bar's `copy link`: the address of what the preview shows now -
2
+ // the story, its scenario and props, the options and the views - which opens
3
+ // it as it is. It says `link copied` for a moment after.
4
+ import { Button } from 'charcell/react/unlinked';
5
+ import { useEffect, useState } from 'react';
6
+ import { Hint } from '../Hint';
7
+
8
+ /** How long the confirmation shows, in milliseconds. */
9
+ const COPIED_MILLISECONDS = 1500;
10
+
11
+ export function CopyLink() {
12
+ const [copied, setCopied] = useState(false);
13
+ useEffect(() => {
14
+ if (!copied) return;
15
+ const timer = setTimeout(() => setCopied(false), COPIED_MILLISECONDS);
16
+ return () => clearTimeout(timer);
17
+ }, [copied]);
18
+ return (
19
+ <Hint text="copy the address of what the preview shows now">
20
+ {(hint) => (
21
+ <Button
22
+ {...hint}
23
+ variant="dense"
24
+ label={copied ? 'link copied' : 'copy link'}
25
+ onClick={() =>
26
+ navigator.clipboard?.writeText(window.location.href).then(
27
+ () => setCopied(true),
28
+ () => undefined,
29
+ )
30
+ }
31
+ />
32
+ )}
33
+ </Hint>
34
+ );
35
+ }
@@ -0,0 +1,6 @@
1
+ @layer charcell.components {
2
+ /* The info button's `i`, in italics, as an information sign is set. */
3
+ .Description__button {
4
+ font-style: italic;
5
+ }
6
+ }
@@ -0,0 +1,24 @@
1
+ // The info button beside a picker in the stage bar: an italic `i`, which opens a
2
+ // charcell Popover holding a description, its markdown rendered (Markdown).
3
+ // Nothing renders without a description. Styled in its index.css.
4
+ import { Button, Popover } from 'charcell/react/unlinked';
5
+ import { Hint } from '../Hint';
6
+ import { Markdown } from '../Markdown';
7
+ import './index.css';
8
+
9
+ export function Description({ text, label }: { text?: string; label: string }) {
10
+ if (!text?.trim()) return null;
11
+ return (
12
+ <Popover
13
+ label={label}
14
+ width={48}
15
+ trigger={({ triggerProps }) => (
16
+ <Hint text={label} triggerProps={triggerProps}>
17
+ {(props) => <Button variant="dense" className="Description__button" label="i" aria-label={label} {...props} />}
18
+ </Hint>
19
+ )}
20
+ >
21
+ <Markdown text={text} />
22
+ </Popover>
23
+ );
24
+ }
@@ -0,0 +1,9 @@
1
+ @layer charcell.components {
2
+ /* The add dialog. Its root is the positioner, the
3
+ shell's own element: it takes charcell's popover layer, as charcell's own
4
+ Popover does. */
5
+ .EditorAddDialog {
6
+ --z-index: var(--charcell-layer-popover);
7
+ z-index: var(--charcell-layer-popover);
8
+ }
9
+ }
@@ -0,0 +1,158 @@
1
+ // The editor's add-content control: a charcell Popover whose trigger is the
2
+ // `add...` button and whose content is the add form - pick the kind (text,
3
+ // component or html tag), the value (the text, which component, or a tag),
4
+ // the scenario a component comes in at, and - only when there is a choice -
5
+ // which slot to add into. The node itself is the controller's to make
6
+ // (`editor.createNode`); the form only gathers the request.
7
+ import { useId, useState } from 'react';
8
+ import { Portal } from '@zag-js/react';
9
+ import { Button, Field, PopoverDriver, PopoverPanel, TextInput } from 'charcell/react/unlinked';
10
+ import { Hint } from '../Hint';
11
+ import { DEFAULT_SLOT, type EditorNode, type PreviewNodeRequest } from '../../../../../src/shell';
12
+ import { usePreviewController } from '../../controller-context';
13
+ import { Select } from '../Select';
14
+ import './index.css';
15
+
16
+ type Kind = 'text' | 'component' | 'html';
17
+
18
+ export function EditorAddDialog(props: { slots: string[]; onAdd: (slot: string, child: EditorNode) => void }) {
19
+ const { slots, onAdd } = props;
20
+ const controller = usePreviewController();
21
+ const { htmlTags } = controller.catalog;
22
+ // An unlisted story is not offered: it is reachable at its address alone.
23
+ const components = controller.catalog.components.filter((candidate) => !candidate.unlisted);
24
+ const [open, setOpen] = useState(false);
25
+ const textId = useId();
26
+ const [kind, setKind] = useState<Kind>('text');
27
+ const [text, setText] = useState('text');
28
+ const [tag, setTag] = useState(htmlTags[0]);
29
+ const [component, setComponent] = useState(components[0]?.name ?? '');
30
+ // Which configuration a component comes in at - `empty` (the default: a blank
31
+ // node), `default` (the curated defaults and slot content), or a named scenario.
32
+ const [importAs, setImportAs] = useState('empty');
33
+ const [slot, setSlot] = useState(slots[0] ?? DEFAULT_SLOT);
34
+
35
+ const found = components.find((candidate) => candidate.name === component);
36
+ // The baseline scenario (its label names the "default" option) and the rest the
37
+ // dialog offers - excluding the preview's `empty` and the `default` one.
38
+ const defaultScenario = (found?.scenarios ?? []).find((scenario) => scenario.default);
39
+ const namedScenarios = (found?.scenarios ?? []).filter((scenario) => !scenario.empty && !scenario.default);
40
+ // "Empty" is a composable-content concept: the scenario choice is offered only
41
+ // when the component has slot content to strip (or a named scenario). A
42
+ // content-less component (an icon) comes in at its default.
43
+ const hasImportChoice =
44
+ !!found && (found.slots.default || found.slots.named.length > 0 || namedScenarios.length > 0);
45
+
46
+ function add() {
47
+ let request: PreviewNodeRequest | null = null;
48
+ if (kind === 'text') request = { kind: 'text', value: text };
49
+ else if (kind === 'html') request = { kind: 'html', tag };
50
+ else if (found) {
51
+ request = {
52
+ kind: 'component',
53
+ name: found.name,
54
+ importAs:
55
+ importAs === 'empty' || importAs === 'default' ? importAs : { scenario: importAs.replace(/^scenario:/, '') },
56
+ };
57
+ }
58
+ if (request) onAdd(slot, controller.editor.createNode(request));
59
+ setOpen(false);
60
+ }
61
+
62
+ // charcell's PopoverDriver and Visuals composed directly (controlled open):
63
+ // the same escape hatch as the panes. The positioner is the dialog's own
64
+ // element. The panel is at least 32 cells wide and grows past that with its
65
+ // content, for a long component name.
66
+ return (
67
+ <PopoverDriver open={open} onOpenChange={setOpen}>
68
+ {({ api }) => (
69
+ <>
70
+ <Hint text="add content" triggerProps={api.getTriggerProps()}>
71
+ {(props) => <Button variant="dense" label="add…" {...props} />}
72
+ </Hint>
73
+ {api.open && (
74
+ <Portal>
75
+ <div className="EditorAddDialog" {...api.getPositionerProps()}>
76
+ <PopoverPanel minWidth={32} {...api.getContentProps()} data-preview-dialog>
77
+ <p>
78
+ <Select
79
+ label="kind"
80
+ testId="add-dialog-kind"
81
+ value={kind}
82
+ onChange={(value) => setKind(value as Kind)}
83
+ options={[
84
+ { value: 'text', label: 'text' },
85
+ { value: 'component', label: 'component' },
86
+ { value: 'html', label: 'html tag' },
87
+ ]}
88
+ />
89
+ </p>
90
+ <p>
91
+ {kind === 'text' ? (
92
+ <Field label="value" htmlFor={textId}>
93
+ <TextInput
94
+ id={textId}
95
+ variant="dense"
96
+ type="text"
97
+ value={text}
98
+ onChange={(event) => setText(event.target.value)}
99
+ />
100
+ </Field>
101
+ ) : kind === 'html' ? (
102
+ <Select
103
+ label="tag"
104
+ testId="add-dialog-tag"
105
+ value={tag}
106
+ onChange={setTag}
107
+ options={htmlTags.map((tag) => ({ value: tag, label: tag }))}
108
+ />
109
+ ) : (
110
+ <Select
111
+ label="component"
112
+ testId="add-dialog-component"
113
+ value={component}
114
+ onChange={(value) => {
115
+ setComponent(value);
116
+ setImportAs('empty');
117
+ }}
118
+ options={components.map((candidate) => ({ value: candidate.name, label: candidate.name }))}
119
+ />
120
+ )}
121
+ </p>
122
+ {kind === 'component' && hasImportChoice && (
123
+ <p>
124
+ <Select
125
+ label="scenario"
126
+ testId="add-dialog-scenario"
127
+ value={importAs}
128
+ onChange={setImportAs}
129
+ options={[
130
+ { value: 'empty', label: 'empty' },
131
+ { value: 'default', label: defaultScenario?.label ?? 'default' },
132
+ ...namedScenarios.map((scenario) => ({ value: `scenario:${scenario.id}`, label: scenario.label })),
133
+ ]}
134
+ />
135
+ </p>
136
+ )}
137
+ {slots.length > 1 && (
138
+ <p>
139
+ <Select
140
+ label="slot"
141
+ testId="add-dialog-slot"
142
+ value={slot}
143
+ onChange={setSlot}
144
+ options={slots.map((slot) => ({ value: slot, label: slot }))}
145
+ />
146
+ </p>
147
+ )}
148
+ <Button variant="dense" label="add" onClick={add} />{' '}
149
+ <Button variant="dense" label="cancel" onClick={() => setOpen(false)} />
150
+ </PopoverPanel>
151
+ </div>
152
+ </Portal>
153
+ )}
154
+ </>
155
+ )}
156
+ </PopoverDriver>
157
+ );
158
+ }
@@ -0,0 +1,48 @@
1
+ @layer charcell.components {
2
+ /* The editor panel's nodes, props and slots are quiet Frames: a window's
3
+ name is its Frame title with its action in the legend, the drop target's
4
+ ring goes foreground (`active`), and the lifted clone is raised (a double
5
+ right and bottom border). Rows carry the spacing: adjacent rings sit a
6
+ full row apart by their own ring geometry. */
7
+ .EditorPanel__row {
8
+ display: flex;
9
+ align-items: center;
10
+ flex-wrap: wrap;
11
+ min-height: var(--charcell-row);
12
+ gap: 1ch;
13
+ row-gap: 0;
14
+ }
15
+ .EditorPanel__label {
16
+ color: var(--charcell-mid);
17
+ }
18
+ /* The remove control's own box, pushed to the row's end. */
19
+ .EditorPanel__remove {
20
+ display: flex;
21
+ margin-left: auto;
22
+ }
23
+ /* A locked raw or scoped fill, or the content beside the root: on one
24
+ line, cut to the row. */
25
+ .EditorPanel__opaque {
26
+ flex: 1 1 0;
27
+ min-width: 0;
28
+ overflow: hidden;
29
+ white-space: nowrap;
30
+ text-overflow: ellipsis;
31
+ }
32
+ /* A props window's controls: the names in one column, the controls in the
33
+ next, a row each. */
34
+ .EditorPanel__controls {
35
+ display: grid;
36
+ grid-template-columns: max-content minmax(0, 1fr);
37
+ column-gap: 2ch;
38
+ row-gap: 0;
39
+ }
40
+ .EditorPanel__add {
41
+ position: relative;
42
+ display: flex;
43
+ align-items: center;
44
+ gap: 1ch;
45
+ justify-content: flex-end;
46
+ min-height: var(--charcell-row);
47
+ }
48
+ }