@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,47 @@
1
+ // The status bar's word on the selection's panes: `regeneration failed` while
2
+ // the scenario editor's last regeneration failed, `regenerating` while one
3
+ // runs, `render error` with the targets whose story threw, `loading` while a
4
+ // pane loads, and `ready` once every pane shows its story. The messages behind
5
+ // a failure open as a hint over it (Hint), from the pointer or the keyboard.
6
+ // Styled in its index.css.
7
+ import { usePreviewState } from '../../controller-context';
8
+ import { Hint } from '../Hint';
9
+ import './index.css';
10
+
11
+ export function PaneStatus() {
12
+ const regeneration = usePreviewState((state) => state.regeneration);
13
+ const frames = usePreviewState((state) => state.frames);
14
+ const errors = usePreviewState((state) => state.frameErrors);
15
+ const failing = Object.entries(errors).filter((entry): entry is [string, string] => entry[1] !== undefined);
16
+ const loading = Object.values(frames).includes('loading');
17
+ const [word, detail, failed] =
18
+ regeneration.status === 'error'
19
+ ? ['regeneration failed', regeneration.message, true]
20
+ : regeneration.status === 'pending'
21
+ ? ['regenerating…', undefined, false]
22
+ : failing.length > 0
23
+ ? [
24
+ `render error · ${failing.map(([target]) => target).join(', ')}`,
25
+ failing.map(([target, message]) => `${target}: ${message}`).join('\n'),
26
+ true,
27
+ ]
28
+ : loading
29
+ ? ['loading…', undefined, false]
30
+ : ['ready', undefined, false];
31
+ return (
32
+ <Hint text={detail}>
33
+ {(hint) => (
34
+ // With messages behind it, the word takes focus, so the keyboard
35
+ // opens them as the pointer does.
36
+ <span
37
+ {...hint}
38
+ className={`PaneStatus${failed ? ' PaneStatus--failed' : ''}`}
39
+ role="status"
40
+ tabIndex={detail ? 0 : undefined}
41
+ >
42
+ {word}
43
+ </span>
44
+ )}
45
+ </Hint>
46
+ );
47
+ }
@@ -0,0 +1,45 @@
1
+ // The output's `width` select, among the output's options with the kit's
2
+ // own (ViewControls): `fit`, the panes sharing the stage's width, or one of
3
+ // the catalog's pane widths, such as `medium 768`, which lays every story
4
+ // pane out that wide so a component that responds to its width shows as it
5
+ // does on such a screen. The output stacks its panes as rows while the width
6
+ // is wider than a column would be (PreviewGrid), and a row still narrower
7
+ // scrolls across (PreviewPane). A width a link names that is not among them
8
+ // shows as its number. The controller keeps the choice, and the address with
9
+ // it (`width=768`). With no pane widths in the catalog and none chosen there
10
+ // is nothing to pick, and no select.
11
+ import { usePreviewController, usePreviewState } from '../../controller-context';
12
+ import { Select, type SelectOption } from '../Select';
13
+
14
+ /** The select's value while the panes fit the stage. */
15
+ const FIT = 'fit';
16
+
17
+ /** Whether there is a width to pick: the catalog offers some, or one is
18
+ * chosen. */
19
+ export function usePaneWidthShown(): boolean {
20
+ const controller = usePreviewController();
21
+ const paneWidth = usePreviewState((state) => state.paneWidth);
22
+ return controller.catalog.paneWidths.length > 0 || paneWidth !== undefined;
23
+ }
24
+
25
+ export function PaneWidth() {
26
+ const controller = usePreviewController();
27
+ const paneWidth = usePreviewState((state) => state.paneWidth);
28
+ const paneWidths = controller.catalog.paneWidths;
29
+ if (paneWidths.length === 0 && paneWidth === undefined) return null;
30
+ const options: SelectOption[] = [
31
+ { value: FIT, label: FIT },
32
+ ...paneWidths.map(({ label, width }) => ({ value: String(width), label: `${label} ${width}` })),
33
+ ];
34
+ if (paneWidth !== undefined && !paneWidths.some(({ width }) => width === paneWidth))
35
+ options.push({ value: String(paneWidth), label: String(paneWidth) });
36
+ return (
37
+ <Select
38
+ label="width"
39
+ testId="select-pane-width"
40
+ value={paneWidth === undefined ? FIT : String(paneWidth)}
41
+ onChange={(value) => controller.actions.setPaneWidth(value === FIT ? undefined : Number(value))}
42
+ options={options}
43
+ />
44
+ );
45
+ }
@@ -0,0 +1,39 @@
1
+ @layer charcell.components {
2
+ /* The panes: the targets' preview and code panes in a charcell SplitGrid
3
+ that fills the grid's place (charcell's `fill`). The frames float on the
4
+ canvas: the stage's side cells their breathing room to the lines beside
5
+ them, the invisible-at-rest handles the gaps. No vertical padding: the
6
+ frames' own ring rows are the breathing room, and their strokes land
7
+ centered in whole grid rows. */
8
+ .PreviewGrid {
9
+ flex: 1;
10
+ display: flex;
11
+ min-width: 0;
12
+ min-height: 0;
13
+ }
14
+ /* The rows' box: the grid's height, or, stacked, at least the rows' least
15
+ (`--preview-grid-least-rows`, in rows), the grid then scrolling down
16
+ past the stage rather than squeezing a row. */
17
+ .PreviewGrid__rows {
18
+ flex: 1 1 0;
19
+ display: flex;
20
+ min-width: 0;
21
+ min-height: 0;
22
+ }
23
+ .PreviewGrid[data-stacked] {
24
+ overflow-y: auto;
25
+ overscroll-behavior: contain;
26
+ }
27
+ .PreviewGrid[data-stacked] > .PreviewGrid__rows {
28
+ min-height: calc(var(--preview-grid-least-rows) * var(--charcell-row));
29
+ }
30
+ /* Under stacked output rows, the code row holds each target's code pane
31
+ side by side, a cell apart. */
32
+ .PreviewGrid__codes {
33
+ flex: 1;
34
+ display: flex;
35
+ gap: 1ch;
36
+ min-width: 0;
37
+ min-height: 0;
38
+ }
39
+ }
@@ -0,0 +1,344 @@
1
+ // The component stage's grid: a column per pane showing (a target's, and
2
+ // the html one where the kit builds html), and a row per view showing of the
3
+ // two the grid holds - the output row, a preview pane in each column, and the
4
+ // code row, that target's code pane under it (CodePane). charcell's
5
+ // SplitGridDriver + SplitGridVisual composed with its SplitGridCell and
6
+ // SplitGridHandle parts: a handle between two columns runs down every row, the
7
+ // handle between the rows across every column, and a press where they cross
8
+ // drags both, each boundary a whole column or row at a time (the driver's own
9
+ // snapping). The handle between the rows draws one grip, in its middle, and
10
+ // carries the code view's heading at its start and the wrap toggle
11
+ // (WrapToggle) at its end. The code row starts at about two fifths of the height and keeps
12
+ // at least eight rows - its ring, the copy row and a few rows of source - and
13
+ // the output row at least three; the columns share the width equally to
14
+ // start. A new set of columns or rows starts over from those sizes. The
15
+ // preview cells are keyed by their target and come first, and stay in the
16
+ // grid while the output row is hidden, laid out nowhere, so the panes keep
17
+ // their place in the tree, and their frames, while either row opens and
18
+ // closes and while a target is turned on or off.
19
+ //
20
+ // While the story panes are laid out at a width (`paneWidth`) wider than a
21
+ // column would be, the output stacks instead: a row per target, each at the
22
+ // grid's full width, the handles between them dragging a row at a time, and
23
+ // the code row under them holding each target's code pane side by side. Each
24
+ // row starts at its story's height, or, when the stories don't fit, at an
25
+ // equal share (stackedRowCells), once every story has reported its height.
26
+ // Each keeps a least: ten rows, its ring and scrollbar rows and about seven
27
+ // rows of story, or its whole story and pane when they take fewer. The grid
28
+ // is tall enough for every row's least and the code row's, so the stage
29
+ // scrolls down only when those don't fit, rather than squeezing a row. The
30
+ // rows follow the stories' heights and the stage's until the reader drags a
31
+ // handle between them or steps it with a key. A story still wider than its row
32
+ // scrolls across, and a taller one down (PreviewPane). The preview cells keep
33
+ // their keys, so the panes keep their frames as the grid stacks and unstacks.
34
+ //
35
+ // A target turned off gives its columns to the others in proportion to their
36
+ // widths, and one turned back on comes back at the width it had, the others
37
+ // giving way in proportion (the driver's `redistribute: 'proportional'`); the
38
+ // stacked rows and the code row share their rows the same way. A double-click
39
+ // on a handle, or Enter while it holds the focus (split-reset.ts), puts its
40
+ // split back where it started: the columns at equal widths, the output and
41
+ // code rows at their starting heights, and stacked rows at their stories'
42
+ // heights again, following the stories as before a handle was moved.
43
+ import { useLayoutEffect, useMemo, useRef, useState, type CSSProperties, type RefObject } from 'react';
44
+ import {
45
+ SplitGridCell,
46
+ SplitGridDriver,
47
+ SplitGridHandle,
48
+ SplitGridHandleRow,
49
+ SplitGridVisual,
50
+ type SplitGridScope,
51
+ } from 'charcell/react/unlinked';
52
+ import type { PreviewTarget } from '../../../../../src/shell';
53
+ import { usePreviewState } from '../../controller-context';
54
+ import { withResetGesture } from '../../split-reset';
55
+ import { stackedLeastCells, stackedRowCells, type StackedCodeRow } from '../../stacked-rows';
56
+ import { CodePane } from '../CodePane';
57
+ import { PreviewPane } from '../PreviewPane';
58
+ import { ViewControls } from '../ViewControls';
59
+ import { ViewHeading } from '../ViewHeading';
60
+ import { WrapToggle } from '../WrapToggle';
61
+ import './index.css';
62
+
63
+ /** The fewest rows the code row keeps, so its copy row and some source still show. */
64
+ const CODE_ROWS = 8;
65
+
66
+ /** The fewest rows the output row keeps. */
67
+ const OUTPUT_ROWS = 3;
68
+
69
+ /** The fewest columns a pane keeps, so its title and some of its story still show. */
70
+ const PANE_COLUMNS = 12;
71
+
72
+ /** The output row's and the code row's starting shares, in percent, while both show. */
73
+ const BOTH_ROWS_SIZE = [60, 40];
74
+
75
+ /** The one row's share while only one shows. */
76
+ const ONE_ROW_SIZE = [100];
77
+
78
+ /** The code row's starting share under stacked output rows, in percent. */
79
+ const STACKED_CODE_SIZE = 30;
80
+
81
+ /** The fewest rows a stacked output row keeps, unless its story and pane
82
+ * take fewer: its ring and scrollbar rows and about seven rows of story. */
83
+ const STACKED_ROWS = 10;
84
+
85
+ /** The keys that step a handle. */
86
+ const STEP_KEYS = new Set(['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End', 'PageUp', 'PageDown']);
87
+
88
+ /** The one column of a stacked grid. */
89
+ const STACK_COLUMN = 'stack';
90
+
91
+ /** The grid's own size, as it changes. */
92
+ function useSize(element: RefObject<HTMLDivElement | null>): {
93
+ width: number;
94
+ height: number;
95
+ } {
96
+ const [size, setSize] = useState({ width: 0, height: 0 });
97
+ useLayoutEffect(() => {
98
+ const current = element.current;
99
+ if (!current) return;
100
+ const { width, height } = current.getBoundingClientRect();
101
+ setSize({ width, height });
102
+ const observer = new ResizeObserver(([entry]) =>
103
+ setSize({
104
+ width: entry.contentRect.width,
105
+ height: entry.contentRect.height,
106
+ }),
107
+ );
108
+ observer.observe(current);
109
+ return () => observer.disconnect();
110
+ }, [element]);
111
+ return size;
112
+ }
113
+
114
+ export function PreviewGrid({ targets, output, code }: { targets: PreviewTarget[]; output: boolean; code: boolean }) {
115
+ const element = useRef<HTMLDivElement>(null);
116
+ const { width, height } = useSize(element);
117
+ const paneWidth = usePreviewState((state) => state.paneWidth);
118
+ // The stories' heights, as one value that changes when any of them does.
119
+ const storyHeights = usePreviewState((state) =>
120
+ targets.map((target) => state.frameSizes[target]?.height ?? '').join(','),
121
+ );
122
+ // Stacked while the output shows and a picked width is wider than a column would be.
123
+ const stacked =
124
+ output && targets.length > 1 && paneWidth !== undefined && width > 0 && paneWidth > width / targets.length;
125
+ const columns = useMemo(
126
+ () =>
127
+ stacked
128
+ ? [{ id: STACK_COLUMN, minimumCells: PANE_COLUMNS }]
129
+ : targets.map((target) => ({ id: target, minimumCells: PANE_COLUMNS })),
130
+ [targets, stacked],
131
+ );
132
+ // With neither row showing the grid is hidden whole (StageSplit),
133
+ // and keeps the output row for its panes.
134
+ const rows = useMemo(
135
+ () =>
136
+ stacked
137
+ ? [
138
+ // Each target's row starts at its story's height (below).
139
+ ...targets.map((target) => ({
140
+ id: `output:${target}`,
141
+ minimumCells: OUTPUT_ROWS,
142
+ })),
143
+ ...(code ? [{ id: 'code', minimumCells: CODE_ROWS }] : []),
144
+ ]
145
+ : [
146
+ // Beside the code row, the output row starts at its panes' content.
147
+ ...(output || !code
148
+ ? [
149
+ {
150
+ id: 'output',
151
+ minimumCells: OUTPUT_ROWS,
152
+ ...(code && output ? { defaultCells: 'content' as const } : {}),
153
+ },
154
+ ]
155
+ : []),
156
+ ...(code ? [{ id: 'code', minimumCells: CODE_ROWS }] : []),
157
+ ],
158
+ [targets, output, code, stacked],
159
+ );
160
+ const defaultColumnSize = useMemo(() => columns.map(() => 100 / columns.length), [columns]);
161
+ const defaultRowSize = useMemo(() => {
162
+ if (!stacked) return rows.length === 2 ? BOTH_ROWS_SIZE : ONE_ROW_SIZE;
163
+ const outputShare = (100 - (code ? STACKED_CODE_SIZE : 0)) / targets.length;
164
+ return [...targets.map(() => outputShare), ...(code ? [STACKED_CODE_SIZE] : [])];
165
+ }, [stacked, rows, code, targets]);
166
+ // The code row is the last; the handle above it carries its heading.
167
+ const codeRow = rows.length - 1;
168
+ const codeRowLimits: StackedCodeRow | undefined = code ? { least: CODE_ROWS, share: STACKED_CODE_SIZE } : undefined;
169
+
170
+ // The grid's parts as the driver last handed them, for the stacked rows' start.
171
+ const scope = useRef<SplitGridScope | null>(null);
172
+ // Whether the reader has moved a handle between the rows since they last
173
+ // stacked: dragged it, or stepped it with a key.
174
+ const moved = useRef(false);
175
+ // A press on a handle, until it ends: a drag while it lasts is the reader's.
176
+ const pressed = useRef(false);
177
+ const layout = `${stacked}:${code}:${targets.join(',')}`;
178
+ useLayoutEffect(() => {
179
+ moved.current = false;
180
+ }, [layout]);
181
+ // The cells the stacked grid needs at least, once the stories report.
182
+ const [leastCells, setLeastCells] = useState(0);
183
+ // A count of the resets of the rows, so a reset of stacked rows lays them
184
+ // out at their stories again.
185
+ const [rowResets, setRowResets] = useState(0);
186
+ // A charcell whose split has no `resetSizes` leaves the split where it is,
187
+ // and shares a leaving track's cells by its own default, whatever
188
+ // `redistribute` says: a reset there does nothing but re-lay stacked rows
189
+ // at their stories.
190
+ const resetColumns = () => scope.current?.columnsApi.resetSizes?.();
191
+ const resetRows = () => {
192
+ scope.current?.rowsApi.resetSizes?.();
193
+ if (!stacked) return;
194
+ moved.current = false;
195
+ setRowResets((count) => count + 1);
196
+ };
197
+ // Stacked, each row starts at its story's height, or an equal share where
198
+ // the stories don't fit, once every story has reported its height, and
199
+ // follows the stories and the stage until the reader moves a handle.
200
+ useLayoutEffect(() => {
201
+ const grid = scope.current;
202
+ if (!stacked || moved.current || !grid) return;
203
+ const gridElement = document.getElementById(String(grid.gridProps.id));
204
+ if (!gridElement) return;
205
+ const cell = parseFloat(getComputedStyle(gridElement).lineHeight);
206
+ if (!(cell > 0)) return;
207
+ const heights = storyHeights.split(',').map(Number);
208
+ if (heights.some((story) => !(story > 0))) return;
209
+ const wanted = targets.map((_, index) => {
210
+ const cellElement = document.getElementById(String(grid.cellProps(0, index).id));
211
+ const viewport = cellElement?.querySelector('[role="region"]');
212
+ if (!cellElement || !viewport) return undefined;
213
+ // The pane around the story: its ring and any scrollbar row.
214
+ const chrome = cellElement.getBoundingClientRect().height - viewport.clientHeight;
215
+ return (heights[index] + chrome) / cell;
216
+ });
217
+ const least = stackedLeastCells(wanted, STACKED_ROWS, codeRowLimits);
218
+ if (least !== leastCells) {
219
+ // The grid grows to it first; this runs again at its new height.
220
+ setLeastCells(least);
221
+ return;
222
+ }
223
+ const total = (gridElement.getBoundingClientRect().height - (grid.rows.length - 1) * cell) / cell;
224
+ if (!(total > 0)) return;
225
+ const cells = stackedRowCells({ wanted, total, least: STACKED_ROWS, code: codeRowLimits });
226
+ // A frame later, once the split has taken in a new set of rows.
227
+ const frame = requestAnimationFrame(() =>
228
+ scope.current?.rowsApi.setSizes(cells.map((length) => (length / total) * 100)),
229
+ );
230
+ return () => cancelAnimationFrame(frame);
231
+ // The layout and stories it follows, the grid's least, the stage's size
232
+ // and a reset of the rows.
233
+ }, [stacked, layout, storyHeights, leastCells, height, width, rowResets]);
234
+ const onHandle = (target: EventTarget) => (target as Element).closest('[data-part="resize-trigger"]') !== null;
235
+ return (
236
+ <div
237
+ ref={element}
238
+ className="PreviewGrid"
239
+ data-stacked={stacked || undefined}
240
+ style={{ '--preview-grid-least-rows': stacked ? leastCells : 0 } as CSSProperties}
241
+ // A drag or a step key on a handle between the rows is the reader's:
242
+ // the rows stay where they leave them. A plain click or a tab to it is not.
243
+ onPointerDownCapture={(event) => {
244
+ pressed.current = onHandle(event.target);
245
+ }}
246
+ onPointerMoveCapture={(event) => {
247
+ if (pressed.current && event.buttons !== 0) moved.current = true;
248
+ }}
249
+ onPointerUpCapture={() => {
250
+ pressed.current = false;
251
+ }}
252
+ onKeyDownCapture={(event) => {
253
+ if (STEP_KEYS.has(event.key) && onHandle(event.target)) moved.current = true;
254
+ }}
255
+ >
256
+ <div className="PreviewGrid__rows">
257
+ <SplitGridDriver
258
+ columns={columns}
259
+ rows={rows}
260
+ defaultColumnSize={defaultColumnSize}
261
+ defaultRowSize={defaultRowSize}
262
+ redistribute="proportional"
263
+ >
264
+ {({ grid }) => {
265
+ scope.current = grid;
266
+ return (
267
+ <SplitGridVisual fill rowGrips="one" {...grid.rootProps} gridProps={grid.gridProps}>
268
+ {targets.map((target, index) => (
269
+ <SplitGridCell
270
+ key={`output:${target}`}
271
+ {...(!output ? { hidden: true } : stacked ? grid.cellProps(0, index) : grid.cellProps(index, 0))}
272
+ >
273
+ <PreviewPane title={target} target={target} />
274
+ </SplitGridCell>
275
+ ))}
276
+ {code &&
277
+ !stacked &&
278
+ targets.map((target, columnIndex) => (
279
+ <SplitGridCell key={`code:${target}`} {...grid.cellProps(columnIndex, codeRow)}>
280
+ <CodePane target={target} />
281
+ </SplitGridCell>
282
+ ))}
283
+ {code && stacked && (
284
+ <SplitGridCell key="code:stack" {...grid.cellProps(0, codeRow)}>
285
+ <div className="PreviewGrid__codes">
286
+ {targets.map((target) => (
287
+ <CodePane key={target} target={target} />
288
+ ))}
289
+ </div>
290
+ </SplitGridCell>
291
+ )}
292
+ {!stacked &&
293
+ targets
294
+ .slice(1)
295
+ .map((target, index) => (
296
+ <SplitGridHandle
297
+ key={`handle:${target}`}
298
+ {...withResetGesture(grid.columnHandleProps(index), resetColumns)}
299
+ axis="column"
300
+ crosses={grid.rows}
301
+ label={`resize ${targets[index]} and ${target}`}
302
+ />
303
+ ))}
304
+ {stacked &&
305
+ targets
306
+ .slice(1)
307
+ .map((target, index) => (
308
+ <SplitGridHandle
309
+ key={`row-handle:${target}`}
310
+ {...withResetGesture(grid.rowHandleProps(index), resetRows)}
311
+ axis="row"
312
+ crosses={grid.columns}
313
+ label={`resize ${targets[index]} and ${target}`}
314
+ />
315
+ ))}
316
+ {code && rows.length > 1 && (
317
+ <SplitGridHandle
318
+ key="handle:code"
319
+ {...withResetGesture(grid.rowHandleProps(codeRow - 1), resetRows)}
320
+ axis="row"
321
+ crosses={grid.columns}
322
+ label="resize panes and code"
323
+ />
324
+ )}
325
+ {code && rows.length > 1 && (
326
+ <SplitGridHandleRow
327
+ key="handle-row:code"
328
+ {...grid.rowHandleRowProps(codeRow - 1)}
329
+ start={<ViewHeading>code</ViewHeading>}
330
+ end={
331
+ <ViewControls view="code">
332
+ <WrapToggle />
333
+ </ViewControls>
334
+ }
335
+ />
336
+ )}
337
+ </SplitGridVisual>
338
+ );
339
+ }}
340
+ </SplitGridDriver>
341
+ </div>
342
+ </div>
343
+ );
344
+ }
@@ -0,0 +1,127 @@
1
+ @layer charcell.components {
2
+ /* One pane: the element the controller mounts the iframe
3
+ in, inside a charcell Frame that fills the pane's place in the row. It fills
4
+ the Frame's body, which is not a flex container, so the iframe's own flex
5
+ sizing has a box to fill. */
6
+ .PreviewPane {
7
+ position: relative;
8
+ height: 100%;
9
+ min-height: 0;
10
+ display: flex;
11
+ flex-direction: column;
12
+ }
13
+ /* While its iframe loads, hidden by the controller until it shows its
14
+ content, the pane says so in the mid gray, its dots counting up - after
15
+ 300ms, so a quick load shows nothing but the ground. The note sits on a
16
+ whole cell counted from the pane's corner, the one nearest the middle. */
17
+ .PreviewPane:has(> iframe:not([data-preview-shown]))::after {
18
+ content: 'loading';
19
+ position: absolute;
20
+ left: round(down, calc((100% - 10ch) / 2), 1ch);
21
+ top: round(
22
+ down,
23
+ calc((100% - var(--charcell-row)) / 2),
24
+ var(--charcell-row)
25
+ );
26
+ white-space: pre;
27
+ color: var(--charcell-mid);
28
+ visibility: hidden;
29
+ animation:
30
+ PreviewPane-loading 0s 300ms forwards,
31
+ PreviewPane-dots 1.2s 300ms steps(1, end) infinite;
32
+ }
33
+ @keyframes PreviewPane-loading {
34
+ to {
35
+ visibility: visible;
36
+ }
37
+ }
38
+ /* The dots count up, one a step; spaces hold the dots' place, so the
39
+ word stays put in the monospace face. */
40
+ @keyframes PreviewPane-dots {
41
+ 0% {
42
+ content: 'loading\00a0\00a0\00a0';
43
+ }
44
+ 25% {
45
+ content: 'loading.\00a0\00a0';
46
+ }
47
+ 50% {
48
+ content: 'loading..\00a0';
49
+ }
50
+ 75%,
51
+ 100% {
52
+ content: 'loading...';
53
+ }
54
+ }
55
+ @media (prefers-reduced-motion: reduce) {
56
+ .PreviewPane:has(> iframe:not([data-preview-shown]))::after {
57
+ animation: PreviewPane-loading 0s 300ms forwards;
58
+ }
59
+ }
60
+ /* The controller's iframe, the pane's one child: based on the height its
61
+ story reports (the iframe's own 150px until it does), so a row measuring
62
+ its content fits the story, and growing to fill a taller pane or
63
+ shrinking with a shorter one. */
64
+ .PreviewPane > iframe {
65
+ display: block;
66
+ flex: 1 1 var(--preview-pane-content, 150px);
67
+ min-height: 0;
68
+ width: 100%;
69
+ border: 0;
70
+ }
71
+ /* At a width the reader picked, inside a scroll area: the iframe is that
72
+ wide and as tall as its story, centered while the pane is wider. The
73
+ scroll area's bars take rows and columns of their own, so a bar never
74
+ covers the story, and a row sized to its content makes room for one. */
75
+ .PreviewPane--fixed {
76
+ display: block;
77
+ height: auto;
78
+ }
79
+ .PreviewPane--fixed > iframe {
80
+ width: var(--preview-pane-width);
81
+ height: var(--preview-pane-content, 150px);
82
+ margin-inline: auto;
83
+ }
84
+ /* Why the html pane has no html, over the pane's own note in the kit's
85
+ canvas: in the mid gray on the shell's ground, centered, as the
86
+ loading note and the code pane's reason are. */
87
+ .PreviewPane__note {
88
+ position: absolute;
89
+ inset: 0;
90
+ margin: 0;
91
+ padding: 0 1ch;
92
+ display: grid;
93
+ place-items: center;
94
+ text-align: center;
95
+ color: var(--charcell-mid);
96
+ background: var(--charcell-background);
97
+ }
98
+ /* What the Frame fills, and takes the pane's whole width from; the cell,
99
+ nothing to see, is the width the labels are cut against. */
100
+ .PreviewPane__frame {
101
+ position: relative;
102
+ flex: 1 1 auto;
103
+ width: 100%;
104
+ height: 100%;
105
+ min-width: 0;
106
+ min-height: 0;
107
+ display: grid;
108
+ grid-template: minmax(0, 1fr) / minmax(0, 1fr);
109
+ }
110
+ .PreviewPane__cell {
111
+ position: absolute;
112
+ width: 1ch;
113
+ visibility: hidden;
114
+ }
115
+ /* The actions at the end of the top row, side by side: each button's own
116
+ padding is the cells between them. */
117
+ .PreviewPane__actions {
118
+ display: flex;
119
+ }
120
+ /* How many warnings the html pane's markup has, first in its legend at
121
+ the foreground, so a part left out at rest is not mistaken for one the
122
+ story does not show; the count opens the warnings (HtmlWarnings). */
123
+ .PreviewPane__warnings {
124
+ white-space: nowrap;
125
+ color: var(--charcell-foreground);
126
+ }
127
+ }