@zeix/le-truc 0.15.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 (406) hide show
  1. package/.ai-context.md +234 -0
  2. package/.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc +111 -0
  3. package/.editorconfig +12 -0
  4. package/.github/copilot-instructions.md +62 -0
  5. package/.github/workflows/codeql.yml +108 -0
  6. package/.github/workflows/static.yml +43 -0
  7. package/.prettierrc +17 -0
  8. package/CLAUDE.md +215 -0
  9. package/CODE_OF_CONDUCT.md +128 -0
  10. package/CONTRIBUTING.md +160 -0
  11. package/LICENSE +21 -0
  12. package/README.md +474 -0
  13. package/biome.json +295 -0
  14. package/bun.lock +239 -0
  15. package/docs/about.html +105 -0
  16. package/docs/assets/main.css +1 -0
  17. package/docs/assets/main.js +10 -0
  18. package/docs/assets/main.js.map +66 -0
  19. package/docs/components.html +293 -0
  20. package/docs/data-flow.html +308 -0
  21. package/docs/examples/basic-button.html +367 -0
  22. package/docs/examples/basic-counter.html +188 -0
  23. package/docs/examples/basic-hello.html +138 -0
  24. package/docs/examples/basic-number.html +271 -0
  25. package/docs/examples/basic-pluralize.html +214 -0
  26. package/docs/examples/card-callout.html +152 -0
  27. package/docs/examples/card-mediaqueries.html +138 -0
  28. package/docs/examples/context-media.html +198 -0
  29. package/docs/examples/empty.html +37 -0
  30. package/docs/examples/form-checkbox.html +233 -0
  31. package/docs/examples/form-combobox.html +420 -0
  32. package/docs/examples/form-listbox.html +434 -0
  33. package/docs/examples/form-radiogroup.html +296 -0
  34. package/docs/examples/form-spinbutton.html +402 -0
  35. package/docs/examples/form-textbox.html +361 -0
  36. package/docs/examples/layout.html +67 -0
  37. package/docs/examples/module-carousel.html +552 -0
  38. package/docs/examples/module-catalog.html +241 -0
  39. package/docs/examples/module-codeblock.html +270 -0
  40. package/docs/examples/module-dialog.html +343 -0
  41. package/docs/examples/module-lazyload.html +289 -0
  42. package/docs/examples/module-list.html +197 -0
  43. package/docs/examples/module-pagination.html +283 -0
  44. package/docs/examples/module-scrollarea.html +447 -0
  45. package/docs/examples/module-tabgroup.html +526 -0
  46. package/docs/examples/module-todo.html +367 -0
  47. package/docs/examples/module-with-type.html +63 -0
  48. package/docs/examples/nested-components.html +88 -0
  49. package/docs/examples/recursive.html +56 -0
  50. package/docs/examples/simple-text.html +39 -0
  51. package/docs/examples/snippet.html +93 -0
  52. package/docs/examples/with-styles.html +75 -0
  53. package/docs/getting-started.html +143 -0
  54. package/docs/index.html +112 -0
  55. package/docs/sitemap.xml +28 -0
  56. package/docs/styling.html +160 -0
  57. package/docs/sw.js +112 -0
  58. package/docs-src/api/README.md +478 -0
  59. package/docs-src/api/_media/LICENSE +21 -0
  60. package/docs-src/api/classes/CircularDependencyError.md +299 -0
  61. package/docs-src/api/classes/CircularMutationError.md +301 -0
  62. package/docs-src/api/classes/ContextRequestEvent.md +590 -0
  63. package/docs-src/api/classes/DependencyTimeoutError.md +301 -0
  64. package/docs-src/api/classes/InvalidCallbackError.md +303 -0
  65. package/docs-src/api/classes/InvalidComponentNameError.md +295 -0
  66. package/docs-src/api/classes/InvalidCustomElementError.md +301 -0
  67. package/docs-src/api/classes/InvalidEffectsError.md +301 -0
  68. package/docs-src/api/classes/InvalidPropertyNameError.md +307 -0
  69. package/docs-src/api/classes/InvalidReactivesError.md +307 -0
  70. package/docs-src/api/classes/InvalidSignalValueError.md +303 -0
  71. package/docs-src/api/classes/MissingElementError.md +307 -0
  72. package/docs-src/api/classes/NullishSignalValueError.md +299 -0
  73. package/docs-src/api/classes/StoreKeyExistsError.md +303 -0
  74. package/docs-src/api/classes/StoreKeyRangeError.md +299 -0
  75. package/docs-src/api/classes/StoreKeyReadonlyError.md +303 -0
  76. package/docs-src/api/functions/asBoolean.md +21 -0
  77. package/docs-src/api/functions/asEnum.md +31 -0
  78. package/docs-src/api/functions/asInteger.md +39 -0
  79. package/docs-src/api/functions/asJSON.md +49 -0
  80. package/docs-src/api/functions/asNumber.md +37 -0
  81. package/docs-src/api/functions/asString.md +37 -0
  82. package/docs-src/api/functions/createCollection.md +83 -0
  83. package/docs-src/api/functions/createSensor.md +71 -0
  84. package/docs-src/api/functions/dangerouslySetInnerHTML.md +48 -0
  85. package/docs-src/api/functions/defineComponent.md +65 -0
  86. package/docs-src/api/functions/isCollection.md +37 -0
  87. package/docs-src/api/functions/isParser.md +41 -0
  88. package/docs-src/api/functions/match.md +47 -0
  89. package/docs-src/api/functions/on.md +58 -0
  90. package/docs-src/api/functions/pass.md +53 -0
  91. package/docs-src/api/functions/provideContexts.md +47 -0
  92. package/docs-src/api/functions/read.md +47 -0
  93. package/docs-src/api/functions/requestContext.md +51 -0
  94. package/docs-src/api/functions/resolve.md +40 -0
  95. package/docs-src/api/functions/runEffects.md +51 -0
  96. package/docs-src/api/functions/runElementEffects.md +57 -0
  97. package/docs-src/api/functions/schedule.md +33 -0
  98. package/docs-src/api/functions/setAttribute.md +48 -0
  99. package/docs-src/api/functions/setProperty.md +52 -0
  100. package/docs-src/api/functions/setStyle.md +48 -0
  101. package/docs-src/api/functions/setText.md +42 -0
  102. package/docs-src/api/functions/show.md +42 -0
  103. package/docs-src/api/functions/toSignal.md +37 -0
  104. package/docs-src/api/functions/toggleAttribute.md +48 -0
  105. package/docs-src/api/functions/toggleClass.md +48 -0
  106. package/docs-src/api/functions/updateElement.md +53 -0
  107. package/docs-src/api/globals.md +131 -0
  108. package/docs-src/api/type-aliases/Cleanup.md +27 -0
  109. package/docs-src/api/type-aliases/Collection.md +91 -0
  110. package/docs-src/api/type-aliases/CollectionListener.md +27 -0
  111. package/docs-src/api/type-aliases/Component.md +17 -0
  112. package/docs-src/api/type-aliases/ComponentProp.md +11 -0
  113. package/docs-src/api/type-aliases/ComponentProps.md +11 -0
  114. package/docs-src/api/type-aliases/ComponentSetup.md +31 -0
  115. package/docs-src/api/type-aliases/ComponentUI.md +27 -0
  116. package/docs-src/api/type-aliases/Computed.md +49 -0
  117. package/docs-src/api/type-aliases/ComputedCallback.md +29 -0
  118. package/docs-src/api/type-aliases/Context.md +33 -0
  119. package/docs-src/api/type-aliases/ContextType.md +19 -0
  120. package/docs-src/api/type-aliases/DangerouslySetInnerHTMLOptions.md +27 -0
  121. package/docs-src/api/type-aliases/DiffResult.md +61 -0
  122. package/docs-src/api/type-aliases/Effect.md +35 -0
  123. package/docs-src/api/type-aliases/EffectCallback.md +23 -0
  124. package/docs-src/api/type-aliases/Effects.md +21 -0
  125. package/docs-src/api/type-aliases/ElementEffects.md +21 -0
  126. package/docs-src/api/type-aliases/ElementFromKey.md +21 -0
  127. package/docs-src/api/type-aliases/ElementQueries.md +27 -0
  128. package/docs-src/api/type-aliases/ElementUpdater.md +131 -0
  129. package/docs-src/api/type-aliases/EventHandler.md +31 -0
  130. package/docs-src/api/type-aliases/EventType.md +17 -0
  131. package/docs-src/api/type-aliases/Fallback.md +21 -0
  132. package/docs-src/api/type-aliases/Initializers.md +21 -0
  133. package/docs-src/api/type-aliases/LooseReader.md +31 -0
  134. package/docs-src/api/type-aliases/MatchHandlers.md +77 -0
  135. package/docs-src/api/type-aliases/MaybeCleanup.md +23 -0
  136. package/docs-src/api/type-aliases/MaybeSignal.md +17 -0
  137. package/docs-src/api/type-aliases/Parser.md +39 -0
  138. package/docs-src/api/type-aliases/ParserOrFallback.md +21 -0
  139. package/docs-src/api/type-aliases/PassedProp.md +25 -0
  140. package/docs-src/api/type-aliases/PassedProps.md +21 -0
  141. package/docs-src/api/type-aliases/Reactive.md +25 -0
  142. package/docs-src/api/type-aliases/Reader.md +31 -0
  143. package/docs-src/api/type-aliases/ReservedWords.md +11 -0
  144. package/docs-src/api/type-aliases/ResolveResult.md +29 -0
  145. package/docs-src/api/type-aliases/SensorEvents.md +25 -0
  146. package/docs-src/api/type-aliases/Signal.md +41 -0
  147. package/docs-src/api/type-aliases/State.md +85 -0
  148. package/docs-src/api/type-aliases/Store.md +29 -0
  149. package/docs-src/api/type-aliases/UI.md +11 -0
  150. package/docs-src/api/type-aliases/UnknownContext.md +13 -0
  151. package/docs-src/api/variables/CONTEXT_REQUEST.md +11 -0
  152. package/docs-src/api/variables/UNSET.md +23 -0
  153. package/docs-src/api/variables/batch.md +25 -0
  154. package/docs-src/api/variables/createComputed.md +41 -0
  155. package/docs-src/api/variables/createEffect.md +35 -0
  156. package/docs-src/api/variables/createState.md +37 -0
  157. package/docs-src/api/variables/createStore.md +42 -0
  158. package/docs-src/api/variables/diff.md +43 -0
  159. package/docs-src/api/variables/isAbortError.md +33 -0
  160. package/docs-src/api/variables/isAsyncFunction.md +39 -0
  161. package/docs-src/api/variables/isComputed.md +37 -0
  162. package/docs-src/api/variables/isEqual.md +49 -0
  163. package/docs-src/api/variables/isFunction.md +39 -0
  164. package/docs-src/api/variables/isMutableSignal.md +37 -0
  165. package/docs-src/api/variables/isNumber.md +33 -0
  166. package/docs-src/api/variables/isRecord.md +39 -0
  167. package/docs-src/api/variables/isRecordOrArray.md +39 -0
  168. package/docs-src/api/variables/isSignal.md +37 -0
  169. package/docs-src/api/variables/isState.md +37 -0
  170. package/docs-src/api/variables/isStore.md +37 -0
  171. package/docs-src/api/variables/isString.md +33 -0
  172. package/docs-src/api/variables/isSymbol.md +33 -0
  173. package/docs-src/api/variables/toError.md +33 -0
  174. package/docs-src/api/variables/valueString.md +33 -0
  175. package/docs-src/includes/menu.html +44 -0
  176. package/docs-src/pages/about.md +89 -0
  177. package/docs-src/pages/components.md +437 -0
  178. package/docs-src/pages/data-flow.md +449 -0
  179. package/docs-src/pages/getting-started.md +170 -0
  180. package/docs-src/pages/index.md +98 -0
  181. package/docs-src/pages/styling.md +165 -0
  182. package/eslint.config.js +64 -0
  183. package/examples/_common/clear.ts +49 -0
  184. package/examples/_common/fetch.ts +160 -0
  185. package/examples/_common/focus.ts +45 -0
  186. package/examples/_common/highlight.ts +5 -0
  187. package/examples/_global.css +463 -0
  188. package/examples/basic-button/basic-button.css +176 -0
  189. package/examples/basic-button/basic-button.html +46 -0
  190. package/examples/basic-button/basic-button.spec.ts +160 -0
  191. package/examples/basic-button/basic-button.ts +45 -0
  192. package/examples/basic-button/copyToClipboard.ts +37 -0
  193. package/examples/basic-counter/basic-counter.css +21 -0
  194. package/examples/basic-counter/basic-counter.html +24 -0
  195. package/examples/basic-counter/basic-counter.spec.ts +85 -0
  196. package/examples/basic-counter/basic-counter.ts +43 -0
  197. package/examples/basic-hello/basic-hello.html +34 -0
  198. package/examples/basic-hello/basic-hello.spec.ts +110 -0
  199. package/examples/basic-hello/basic-hello.ts +36 -0
  200. package/examples/basic-number/basic-number.html +79 -0
  201. package/examples/basic-number/basic-number.spec.ts +175 -0
  202. package/examples/basic-number/basic-number.ts +124 -0
  203. package/examples/basic-pluralize/basic-pluralize.html +64 -0
  204. package/examples/basic-pluralize/basic-pluralize.spec.ts +258 -0
  205. package/examples/basic-pluralize/basic-pluralize.ts +82 -0
  206. package/examples/card-callout/card-callout.css +79 -0
  207. package/examples/card-callout/card-callout.html +5 -0
  208. package/examples/card-mediaqueries/card-mediaqueries.html +29 -0
  209. package/examples/card-mediaqueries/card-mediaqueries.spec.ts +300 -0
  210. package/examples/card-mediaqueries/card-mediaqueries.ts +41 -0
  211. package/examples/context-media/context-media.html +3 -0
  212. package/examples/context-media/context-media.ts +127 -0
  213. package/examples/form-checkbox/form-checkbox.css +70 -0
  214. package/examples/form-checkbox/form-checkbox.html +13 -0
  215. package/examples/form-checkbox/form-checkbox.spec.ts +357 -0
  216. package/examples/form-checkbox/form-checkbox.ts +50 -0
  217. package/examples/form-checkbox/vanilla-checkbox.ts +101 -0
  218. package/examples/form-combobox/form-combobox.css +118 -0
  219. package/examples/form-combobox/form-combobox.html +74 -0
  220. package/examples/form-combobox/form-combobox.spec.ts +977 -0
  221. package/examples/form-combobox/form-combobox.ts +128 -0
  222. package/examples/form-listbox/form-listbox.css +71 -0
  223. package/examples/form-listbox/form-listbox.html +67 -0
  224. package/examples/form-listbox/form-listbox.spec.ts +1050 -0
  225. package/examples/form-listbox/form-listbox.ts +196 -0
  226. package/examples/form-listbox/mocks/timezones.json +495 -0
  227. package/examples/form-radiogroup/form-radiogroup.css +87 -0
  228. package/examples/form-radiogroup/form-radiogroup.html +51 -0
  229. package/examples/form-radiogroup/form-radiogroup.spec.ts +515 -0
  230. package/examples/form-radiogroup/form-radiogroup.ts +58 -0
  231. package/examples/form-spinbutton/form-spinbutton.css +95 -0
  232. package/examples/form-spinbutton/form-spinbutton.html +96 -0
  233. package/examples/form-spinbutton/form-spinbutton.spec.ts +688 -0
  234. package/examples/form-spinbutton/form-spinbutton.ts +111 -0
  235. package/examples/form-textbox/form-textbox.css +104 -0
  236. package/examples/form-textbox/form-textbox.html +53 -0
  237. package/examples/form-textbox/form-textbox.spec.ts +542 -0
  238. package/examples/form-textbox/form-textbox.ts +104 -0
  239. package/examples/main.css +22 -0
  240. package/examples/main.ts +23 -0
  241. package/examples/module-carousel/module-carousel.css +113 -0
  242. package/examples/module-carousel/module-carousel.html +208 -0
  243. package/examples/module-carousel/module-carousel.spec.ts +523 -0
  244. package/examples/module-carousel/module-carousel.ts +131 -0
  245. package/examples/module-catalog/module-catalog.css +22 -0
  246. package/examples/module-catalog/module-catalog.html +82 -0
  247. package/examples/module-catalog/module-catalog.spec.ts +396 -0
  248. package/examples/module-catalog/module-catalog.ts +37 -0
  249. package/examples/module-codeblock/module-codeblock.css +95 -0
  250. package/examples/module-codeblock/module-codeblock.html +28 -0
  251. package/examples/module-codeblock/module-codeblock.ts +47 -0
  252. package/examples/module-demo/module-demo.css +13 -0
  253. package/examples/module-dialog/module-dialog.css +96 -0
  254. package/examples/module-dialog/module-dialog.html +66 -0
  255. package/examples/module-dialog/module-dialog.spec.ts +557 -0
  256. package/examples/module-dialog/module-dialog.ts +81 -0
  257. package/examples/module-lazyload/mocks/empty.html +1 -0
  258. package/examples/module-lazyload/mocks/module-with-type.html +27 -0
  259. package/examples/module-lazyload/mocks/nested-components.html +52 -0
  260. package/examples/module-lazyload/mocks/recursive.html +20 -0
  261. package/examples/module-lazyload/mocks/simple-text.html +3 -0
  262. package/examples/module-lazyload/mocks/snippet.html +57 -0
  263. package/examples/module-lazyload/mocks/with-styles.html +39 -0
  264. package/examples/module-lazyload/module-lazyload.html +132 -0
  265. package/examples/module-lazyload/module-lazyload.spec.ts +734 -0
  266. package/examples/module-lazyload/module-lazyload.ts +89 -0
  267. package/examples/module-list/module-list.html +30 -0
  268. package/examples/module-list/module-list.spec.ts +592 -0
  269. package/examples/module-list/module-list.ts +99 -0
  270. package/examples/module-pagination/module-pagination.css +79 -0
  271. package/examples/module-pagination/module-pagination.html +16 -0
  272. package/examples/module-pagination/module-pagination.spec.ts +701 -0
  273. package/examples/module-pagination/module-pagination.ts +88 -0
  274. package/examples/module-scrollarea/module-scrollarea.css +77 -0
  275. package/examples/module-scrollarea/module-scrollarea.html +189 -0
  276. package/examples/module-scrollarea/module-scrollarea.spec.ts +445 -0
  277. package/examples/module-scrollarea/module-scrollarea.ts +81 -0
  278. package/examples/module-tabgroup/module-tabgroup.css +55 -0
  279. package/examples/module-tabgroup/module-tabgroup.html +269 -0
  280. package/examples/module-tabgroup/module-tabgroup.spec.ts +631 -0
  281. package/examples/module-tabgroup/module-tabgroup.ts +102 -0
  282. package/examples/module-toc/module-toc.css +34 -0
  283. package/examples/module-todo/module-todo.css +84 -0
  284. package/examples/module-todo/module-todo.html +92 -0
  285. package/examples/module-todo/module-todo.spec.ts +528 -0
  286. package/examples/module-todo/module-todo.ts +91 -0
  287. package/examples/section-hero/section-hero.css +37 -0
  288. package/examples/section-menu/section-menu.css +81 -0
  289. package/examples/server.ts +95 -0
  290. package/examples/test-setup.md +314 -0
  291. package/index.dev.js +1688 -0
  292. package/index.dev.ts +127 -0
  293. package/index.js +3 -0
  294. package/index.js.map +42 -0
  295. package/index.ts +127 -0
  296. package/package.json +64 -0
  297. package/playwright.config.ts +31 -0
  298. package/server/BUILD_SYSTEM.md +428 -0
  299. package/server/SERVER.md +286 -0
  300. package/server/build.ts +91 -0
  301. package/server/config.ts +130 -0
  302. package/server/effects/api.ts +28 -0
  303. package/server/effects/css.ts +31 -0
  304. package/server/effects/examples.ts +109 -0
  305. package/server/effects/js.ts +32 -0
  306. package/server/effects/menu.ts +34 -0
  307. package/server/effects/pages.ts +178 -0
  308. package/server/effects/service-worker.ts +57 -0
  309. package/server/effects/sitemap.ts +27 -0
  310. package/server/file-signals.ts +361 -0
  311. package/server/file-watcher.ts +77 -0
  312. package/server/io.ts +174 -0
  313. package/server/layout-engine.ts +470 -0
  314. package/server/layout-utils.ts +615 -0
  315. package/server/layouts/api.html +76 -0
  316. package/server/layouts/base.html +37 -0
  317. package/server/layouts/blog.html +115 -0
  318. package/server/layouts/example.html +104 -0
  319. package/server/layouts/overview.html +165 -0
  320. package/server/layouts/page.html +36 -0
  321. package/server/layouts/test.html +24 -0
  322. package/server/markdoc-helpers.ts +217 -0
  323. package/server/markdoc.config.ts +29 -0
  324. package/server/schema/callout.markdoc.ts +17 -0
  325. package/server/schema/carousel.markdoc.ts +118 -0
  326. package/server/schema/demo.markdoc.ts +74 -0
  327. package/server/schema/fence.markdoc.ts +84 -0
  328. package/server/schema/heading.markdoc.ts +23 -0
  329. package/server/schema/hero.markdoc.ts +59 -0
  330. package/server/schema/section.markdoc.ts +10 -0
  331. package/server/schema/slide.markdoc.ts +17 -0
  332. package/server/schema/source.markdoc.ts +53 -0
  333. package/server/schema/tabgroup.markdoc.ts +102 -0
  334. package/server/serve.ts +635 -0
  335. package/server/templates/README.md +352 -0
  336. package/server/templates/constants.ts +236 -0
  337. package/server/templates/fragments.ts +159 -0
  338. package/server/templates/hmr.ts +269 -0
  339. package/server/templates/menu.ts +33 -0
  340. package/server/templates/performance-hints.ts +94 -0
  341. package/server/templates/service-worker.ts +403 -0
  342. package/server/templates/sitemap.ts +57 -0
  343. package/server/templates/toc.ts +41 -0
  344. package/server/templates/utils.ts +378 -0
  345. package/src/component.ts +215 -0
  346. package/src/context.ts +156 -0
  347. package/src/effects/attribute.ts +82 -0
  348. package/src/effects/class.ts +28 -0
  349. package/src/effects/event.ts +67 -0
  350. package/src/effects/html.ts +60 -0
  351. package/src/effects/method.ts +57 -0
  352. package/src/effects/pass.ts +103 -0
  353. package/src/effects/property.ts +57 -0
  354. package/src/effects/style.ts +34 -0
  355. package/src/effects/text.ts +28 -0
  356. package/src/effects.ts +412 -0
  357. package/src/errors.ts +160 -0
  358. package/src/parsers/boolean.ts +14 -0
  359. package/src/parsers/json.ts +33 -0
  360. package/src/parsers/number.ts +55 -0
  361. package/src/parsers/string.ts +32 -0
  362. package/src/parsers.ts +90 -0
  363. package/src/scheduler.ts +47 -0
  364. package/src/signals/collection.ts +253 -0
  365. package/src/signals/sensor.ts +131 -0
  366. package/src/ui.ts +236 -0
  367. package/src/util.ts +187 -0
  368. package/tsconfig.json +34 -0
  369. package/types/examples/basic-button/basic-button.d.ts +16 -0
  370. package/types/examples/basic-hello/basic-hello.d.ts +18 -0
  371. package/types/index.d.ts +27 -0
  372. package/types/index.dev.d.ts +27 -0
  373. package/types/src/collection.d.ts +27 -0
  374. package/types/src/component.d.ts +32 -0
  375. package/types/src/context.d.ts +85 -0
  376. package/types/src/effects/attribute.d.ts +23 -0
  377. package/types/src/effects/callMethod.d.ts +23 -0
  378. package/types/src/effects/class.d.ts +13 -0
  379. package/types/src/effects/dangerouslySetInnerHTML.d.ts +18 -0
  380. package/types/src/effects/event.d.ts +18 -0
  381. package/types/src/effects/html.d.ts +17 -0
  382. package/types/src/effects/method.d.ts +22 -0
  383. package/types/src/effects/pass.d.ts +18 -0
  384. package/types/src/effects/property.d.ts +22 -0
  385. package/types/src/effects/setAttribute.d.ts +24 -0
  386. package/types/src/effects/setProperty.d.ts +23 -0
  387. package/types/src/effects/setStyle.d.ts +14 -0
  388. package/types/src/effects/setText.d.ts +13 -0
  389. package/types/src/effects/style.d.ts +13 -0
  390. package/types/src/effects/text.d.ts +12 -0
  391. package/types/src/effects/toggleClass.d.ts +14 -0
  392. package/types/src/effects.d.ts +153 -0
  393. package/types/src/errors.d.ts +99 -0
  394. package/types/src/events.d.ts +27 -0
  395. package/types/src/extractors.d.ts +23 -0
  396. package/types/src/parsers/boolean.d.ts +10 -0
  397. package/types/src/parsers/json.d.ts +13 -0
  398. package/types/src/parsers/number.d.ts +21 -0
  399. package/types/src/parsers/string.d.ts +19 -0
  400. package/types/src/parsers.d.ts +41 -0
  401. package/types/src/scheduler.d.ts +11 -0
  402. package/types/src/sensor.d.ts +27 -0
  403. package/types/src/signals/collection.d.ts +32 -0
  404. package/types/src/signals/sensor.d.ts +27 -0
  405. package/types/src/ui.d.ts +37 -0
  406. package/types/src/util.d.ts +65 -0
@@ -0,0 +1,82 @@
1
+ <module-catalog>
2
+ <header>
3
+ <p>Shop</p>
4
+ <basic-button disabled>
5
+ <button type="button" disabled>
6
+ <span class="label">🛒 Shopping Cart</span>
7
+ <span class="badge"></span>
8
+ </button>
9
+ </basic-button>
10
+ </header>
11
+ <ul>
12
+ <li>
13
+ <p>Product 1</p>
14
+ <form-spinbutton>
15
+ <button type="button" class="decrement" aria-label="Decrement" hidden>
16
+
17
+ </button>
18
+ <input
19
+ type="number"
20
+ class="value"
21
+ name="amount-product1"
22
+ value="0"
23
+ min="0"
24
+ max="10"
25
+ readonly
26
+ disabled
27
+ hidden
28
+ />
29
+ <button type="button" class="increment" aria-label="Increment">
30
+ <span class="zero">Add to Cart</span>
31
+ <span class="other" hidden>+</span>
32
+ </button>
33
+ </form-spinbutton>
34
+ </li>
35
+ <li>
36
+ <p>Product 2</p>
37
+ <form-spinbutton>
38
+ <button type="button" class="decrement" aria-label="Decrement" hidden>
39
+
40
+ </button>
41
+ <input
42
+ type="number"
43
+ class="value"
44
+ name="amount-product2"
45
+ value="0"
46
+ min="0"
47
+ max="5"
48
+ readonly
49
+ disabled
50
+ hidden
51
+ />
52
+ <button type="button" class="increment" aria-label="Increment">
53
+ <span class="zero">Add to Cart</span>
54
+ <span class="other" hidden>+</span>
55
+ </button>
56
+ </form-spinbutton>
57
+ </li>
58
+ <li>
59
+ <p>Product 3</p>
60
+ <form-spinbutton>
61
+ <button type="button" class="decrement" aria-label="Decrement" hidden>
62
+
63
+ </button>
64
+ <input
65
+ type="number"
66
+ class="value"
67
+ name="amount-product3"
68
+ value="0"
69
+ min="0"
70
+ max="20"
71
+ readonly
72
+ disabled
73
+ hidden
74
+ />
75
+ <button type="button" class="increment" aria-label="Increment">
76
+ <span class="zero">Add to Cart</span>
77
+ <span class="other" hidden>+</span>
78
+ </button>
79
+ </form-spinbutton>
80
+ </li>
81
+ </ul>
82
+ </module-catalog>
@@ -0,0 +1,396 @@
1
+ import { expect, test } from '@playwright/test'
2
+
3
+ test.describe('module-catalog component', () => {
4
+ test.beforeEach(async ({ page }) => {
5
+ page.on('console', msg => {
6
+ console.log(`[browser] ${msg.type()}: ${msg.text()}`)
7
+ })
8
+
9
+ await page.goto('http://localhost:3000/test/module-catalog.html')
10
+ await page.waitForSelector('module-catalog')
11
+ })
12
+
13
+ test('renders initial state correctly', async ({ page }) => {
14
+ const catalog = page.locator('module-catalog')
15
+ const button = catalog.locator('basic-button button')
16
+ const badge = catalog.locator('basic-button .badge')
17
+ const spinbuttons = catalog.locator('form-spinbutton')
18
+
19
+ // Should have 3 spinbutton components
20
+ await expect(spinbuttons).toHaveCount(3)
21
+
22
+ // Button should be disabled initially (no items in cart)
23
+ await expect(button).toHaveAttribute('disabled')
24
+ await expect(button).toBeDisabled()
25
+
26
+ // Badge should be empty initially
27
+ await expect(badge).toHaveText('')
28
+
29
+ // All spinbuttons should start at 0
30
+ const inputs = catalog.locator('form-spinbutton input.value')
31
+ await expect(inputs.nth(0)).toHaveValue('0')
32
+ await expect(inputs.nth(1)).toHaveValue('0')
33
+ await expect(inputs.nth(2)).toHaveValue('0')
34
+ })
35
+
36
+ test('calculates total and enables button when items are added', async ({
37
+ page,
38
+ }) => {
39
+ const catalog = page.locator('module-catalog')
40
+ const button = catalog.locator('basic-button button')
41
+ const badge = catalog.locator('basic-button .badge')
42
+
43
+ // Add 2 of Product 1
44
+ const product1Increment = catalog
45
+ .locator('form-spinbutton')
46
+ .nth(0)
47
+ .locator('button.increment')
48
+ await product1Increment.click()
49
+ await product1Increment.click()
50
+
51
+ // Button should be enabled and show total
52
+ await expect(button).not.toHaveAttribute('disabled')
53
+ await expect(button).not.toBeDisabled()
54
+ await expect(badge).toHaveText('2')
55
+
56
+ // Add 3 of Product 2
57
+ const product2Increment = catalog
58
+ .locator('form-spinbutton')
59
+ .nth(1)
60
+ .locator('button.increment')
61
+ await product2Increment.click()
62
+ await product2Increment.click()
63
+ await product2Increment.click()
64
+
65
+ // Total should be updated
66
+ await expect(badge).toHaveText('5')
67
+ await expect(button).not.toBeDisabled()
68
+
69
+ // Add 1 of Product 3
70
+ const product3Increment = catalog
71
+ .locator('form-spinbutton')
72
+ .nth(2)
73
+ .locator('button.increment')
74
+ await product3Increment.click()
75
+
76
+ // Total should be 6
77
+ await expect(badge).toHaveText('6')
78
+ await expect(button).not.toBeDisabled()
79
+ })
80
+
81
+ test('updates total when items are decremented', async ({ page }) => {
82
+ const catalog = page.locator('module-catalog')
83
+ const button = catalog.locator('basic-button button')
84
+ const badge = catalog.locator('basic-button .badge')
85
+
86
+ // First add some items
87
+ const product1Increment = catalog
88
+ .locator('form-spinbutton')
89
+ .nth(0)
90
+ .locator('button.increment')
91
+ const product2Increment = catalog
92
+ .locator('form-spinbutton')
93
+ .nth(1)
94
+ .locator('button.increment')
95
+
96
+ await product1Increment.click()
97
+ await product1Increment.click()
98
+ await product1Increment.click() // 3 items
99
+ await product2Increment.click()
100
+ await product2Increment.click() // 2 items
101
+
102
+ await expect(badge).toHaveText('5')
103
+
104
+ // Now decrement Product 1
105
+ const product1Decrement = catalog
106
+ .locator('form-spinbutton')
107
+ .nth(0)
108
+ .locator('button.decrement')
109
+ await product1Decrement.click()
110
+
111
+ // Total should be updated
112
+ await expect(badge).toHaveText('4')
113
+ await expect(button).not.toBeDisabled()
114
+
115
+ // Decrement Product 2 to 0
116
+ const product2Decrement = catalog
117
+ .locator('form-spinbutton')
118
+ .nth(1)
119
+ .locator('button.decrement')
120
+ await product2Decrement.click()
121
+ await product2Decrement.click()
122
+
123
+ // Total should be 2 (only Product 1 remaining)
124
+ await expect(badge).toHaveText('2')
125
+ await expect(button).not.toBeDisabled()
126
+
127
+ // Decrement Product 1 to 0
128
+ await product1Decrement.click()
129
+ await product1Decrement.click()
130
+
131
+ // Button should be disabled again, badge empty
132
+ await expect(button).toHaveAttribute('disabled')
133
+ await expect(button).toBeDisabled()
134
+ await expect(badge).toHaveText('')
135
+ })
136
+
137
+ test('handles reaching maximum values for individual products', async ({
138
+ page,
139
+ }) => {
140
+ const catalog = page.locator('module-catalog')
141
+ const badge = catalog.locator('basic-button .badge')
142
+
143
+ // Product 1 max is 10, Product 2 max is 5, Product 3 max is 20
144
+ const product1Increment = catalog
145
+ .locator('form-spinbutton')
146
+ .nth(0)
147
+ .locator('button.increment')
148
+ const product2Increment = catalog
149
+ .locator('form-spinbutton')
150
+ .nth(1)
151
+ .locator('button.increment')
152
+
153
+ // Max out Product 1 (10 items)
154
+ for (let i = 0; i < 10; i++) {
155
+ await product1Increment.click()
156
+ }
157
+
158
+ // Max out Product 2 (5 items)
159
+ for (let i = 0; i < 5; i++) {
160
+ await product2Increment.click()
161
+ }
162
+
163
+ // Total should be 15
164
+ await expect(badge).toHaveText('15')
165
+
166
+ // Increment buttons should be disabled at max
167
+ await expect(product1Increment).toHaveAttribute('disabled')
168
+ await expect(product2Increment).toHaveAttribute('disabled')
169
+ })
170
+
171
+ test('reactive computation updates immediately', async ({ page }) => {
172
+ const catalog = page.locator('module-catalog')
173
+ const badge = catalog.locator('basic-button .badge')
174
+
175
+ const product1Increment = catalog
176
+ .locator('form-spinbutton')
177
+ .nth(0)
178
+ .locator('button.increment')
179
+
180
+ // Multiple rapid clicks should update total immediately
181
+ await product1Increment.click()
182
+ await expect(badge).toHaveText('1')
183
+
184
+ await product1Increment.click()
185
+ await expect(badge).toHaveText('2')
186
+
187
+ await product1Increment.click()
188
+ await expect(badge).toHaveText('3')
189
+ })
190
+
191
+ test('total reflects component property values', async ({ page }) => {
192
+ const catalog = page.locator('module-catalog')
193
+
194
+ // Add items to different products
195
+ const product1Increment = catalog
196
+ .locator('form-spinbutton')
197
+ .nth(0)
198
+ .locator('button.increment')
199
+ const product2Increment = catalog
200
+ .locator('form-spinbutton')
201
+ .nth(1)
202
+ .locator('button.increment')
203
+ const product3Increment = catalog
204
+ .locator('form-spinbutton')
205
+ .nth(2)
206
+ .locator('button.increment')
207
+
208
+ await product1Increment.click() // 1
209
+ await product2Increment.click()
210
+ await product2Increment.click() // 2
211
+ await product3Increment.click()
212
+ await product3Increment.click()
213
+ await product3Increment.click() // 3
214
+
215
+ // Verify component properties match expected values
216
+ const componentValues = await page.evaluate(() => {
217
+ const spinbuttons = document.querySelectorAll('form-spinbutton')
218
+ return Array.from(spinbuttons).map((sb: any) => sb.value)
219
+ })
220
+
221
+ expect(componentValues).toEqual([1, 2, 3])
222
+
223
+ // Total should be sum of all values
224
+ const badge = catalog.locator('basic-button .badge')
225
+ await expect(badge).toHaveText('6')
226
+ })
227
+
228
+ test('button disabled state changes correctly', async ({ page }) => {
229
+ const catalog = page.locator('module-catalog')
230
+ const button = catalog.locator('basic-button button')
231
+
232
+ const product1Increment = catalog
233
+ .locator('form-spinbutton')
234
+ .nth(0)
235
+ .locator('button.increment')
236
+ const product1Decrement = catalog
237
+ .locator('form-spinbutton')
238
+ .nth(0)
239
+ .locator('button.decrement')
240
+
241
+ // Initially disabled
242
+ await expect(button).toBeDisabled()
243
+
244
+ // Add item - becomes enabled
245
+ await product1Increment.click()
246
+ await expect(button).not.toBeDisabled()
247
+
248
+ // Remove item - becomes disabled again
249
+ await product1Decrement.click()
250
+ await expect(button).toBeDisabled()
251
+
252
+ // Add multiple items
253
+ await product1Increment.click()
254
+ await product1Increment.click()
255
+ await expect(button).not.toBeDisabled()
256
+
257
+ // Remove one - still enabled
258
+ await product1Decrement.click()
259
+ await expect(button).not.toBeDisabled()
260
+
261
+ // Remove last - disabled
262
+ await product1Decrement.click()
263
+ await expect(button).toBeDisabled()
264
+ })
265
+
266
+ test('handles mixed interactions across all products', async ({ page }) => {
267
+ const catalog = page.locator('module-catalog')
268
+ const badge = catalog.locator('basic-button .badge')
269
+ const button = catalog.locator('basic-button button')
270
+
271
+ // Get all increment buttons
272
+ const increments = [
273
+ catalog.locator('form-spinbutton').nth(0).locator('button.increment'),
274
+ catalog.locator('form-spinbutton').nth(1).locator('button.increment'),
275
+ catalog.locator('form-spinbutton').nth(2).locator('button.increment'),
276
+ ]
277
+
278
+ // Get all decrement buttons
279
+ const decrements = [
280
+ catalog.locator('form-spinbutton').nth(0).locator('button.decrement'),
281
+ catalog.locator('form-spinbutton').nth(1).locator('button.decrement'),
282
+ catalog.locator('form-spinbutton').nth(2).locator('button.decrement'),
283
+ ]
284
+
285
+ // Complex interaction pattern
286
+ await increments[0].click() // Product 1: 1, Total: 1
287
+ await expect(badge).toHaveText('1')
288
+
289
+ await increments[1].click() // Product 2: 1, Total: 2
290
+ await increments[1].click() // Product 2: 2, Total: 3
291
+ await expect(badge).toHaveText('3')
292
+
293
+ await increments[2].click() // Product 3: 1, Total: 4
294
+ await increments[0].click() // Product 1: 2, Total: 5
295
+ await expect(badge).toHaveText('5')
296
+
297
+ // Now some decrements
298
+ await decrements[1].click() // Product 2: 1, Total: 4
299
+ await expect(badge).toHaveText('4')
300
+
301
+ await decrements[0].click() // Product 1: 1, Total: 3
302
+ await decrements[0].click() // Product 1: 0, Total: 2
303
+ await expect(badge).toHaveText('2')
304
+
305
+ // Still enabled because other products have items
306
+ await expect(button).not.toBeDisabled()
307
+
308
+ // Remove remaining items
309
+ await decrements[1].click() // Product 2: 0, Total: 1
310
+ await decrements[2].click() // Product 3: 0, Total: 0
311
+ await expect(badge).toHaveText('')
312
+ await expect(button).toBeDisabled()
313
+ })
314
+
315
+ test('badge text is always string representation of total', async ({
316
+ page,
317
+ }) => {
318
+ const catalog = page.locator('module-catalog')
319
+ const badge = catalog.locator('basic-button .badge')
320
+
321
+ const product1Increment = catalog
322
+ .locator('form-spinbutton')
323
+ .nth(0)
324
+ .locator('button.increment')
325
+
326
+ // Test various totals are properly stringified
327
+ for (let i = 1; i <= 5; i++) {
328
+ await product1Increment.click()
329
+ await expect(badge).toHaveText(String(i))
330
+ }
331
+ })
332
+
333
+ test('component coordination works with keyboard interactions', async ({
334
+ page,
335
+ }) => {
336
+ const catalog = page.locator('module-catalog')
337
+ const badge = catalog.locator('basic-button .badge')
338
+
339
+ // Use keyboard on first product
340
+ const product1Increment = catalog
341
+ .locator('form-spinbutton')
342
+ .nth(0)
343
+ .locator('button.increment')
344
+
345
+ await product1Increment.focus()
346
+ await page.keyboard.press('ArrowUp')
347
+ await expect(badge).toHaveText('1')
348
+
349
+ await page.keyboard.press('ArrowUp')
350
+ await expect(badge).toHaveText('2')
351
+
352
+ await page.keyboard.press('ArrowDown')
353
+ await expect(badge).toHaveText('1')
354
+ })
355
+
356
+ test('all spinbuttons contribute to total calculation', async ({ page }) => {
357
+ const catalog = page.locator('module-catalog')
358
+ const badge = catalog.locator('basic-button .badge')
359
+
360
+ // Verify all 3 spinbuttons are found and contribute
361
+ const spinbuttonCount = await catalog.locator('form-spinbutton').count()
362
+ expect(spinbuttonCount).toBe(3)
363
+
364
+ // Add 1 to each spinbutton
365
+ for (let i = 0; i < 3; i++) {
366
+ const increment = catalog
367
+ .locator('form-spinbutton')
368
+ .nth(i)
369
+ .locator('button.increment')
370
+ await increment.click()
371
+ }
372
+
373
+ // Total should be 3
374
+ await expect(badge).toHaveText('3')
375
+
376
+ // Verify each spinbutton has value 1
377
+ const values = await page.evaluate(() => {
378
+ const spinbuttons = document.querySelectorAll('form-spinbutton')
379
+ return Array.from(spinbuttons).map((sb: any) => sb.value)
380
+ })
381
+ expect(values).toEqual([1, 1, 1])
382
+ })
383
+
384
+ test('component has no public properties exposed', async ({ page }) => {
385
+ // Verify the component doesn't expose any public interface
386
+ const hasPublicProps = await page.evaluate(() => {
387
+ const catalog = document.querySelector('module-catalog') as any
388
+ // Try to access common property names, should all be undefined or internal
389
+ const props = ['total', 'disabled', 'badge', 'value', 'count', 'items']
390
+ return props.some(prop => catalog[prop] !== undefined)
391
+ })
392
+
393
+ // Component should not expose public properties
394
+ expect(hasPublicProps).toBe(false)
395
+ })
396
+ })
@@ -0,0 +1,37 @@
1
+ import {
2
+ type Collection,
3
+ type Component,
4
+ createComputed,
5
+ defineComponent,
6
+ pass,
7
+ } from '../..'
8
+ import { BasicButtonProps } from '../basic-button/basic-button'
9
+ import { FormSpinbuttonProps } from '../form-spinbutton/form-spinbutton'
10
+
11
+ type ModuleCatalogUI = {
12
+ button: Component<BasicButtonProps>
13
+ spinbuttons: Collection<Component<FormSpinbuttonProps>>
14
+ }
15
+
16
+ export default defineComponent<{}, ModuleCatalogUI>(
17
+ 'module-catalog',
18
+ {},
19
+ ({ all, first }) => ({
20
+ button: first('basic-button', 'Add a button to go go the Shopping Cart'),
21
+ spinbuttons: all(
22
+ 'form-spinbutton',
23
+ 'Add spinbutton components to calculate sum from.',
24
+ ),
25
+ }),
26
+ ({ spinbuttons }) => {
27
+ const total = createComputed(() =>
28
+ spinbuttons.get().reduce((sum, item) => sum + item.value, 0),
29
+ )
30
+ return {
31
+ button: pass({
32
+ disabled: () => !total.get(),
33
+ badge: () => (total.get() > 0 ? String(total.get()) : ''),
34
+ }),
35
+ }
36
+ },
37
+ )
@@ -0,0 +1,95 @@
1
+ module-codeblock {
2
+ --color-shiki-monokai-bg: #272822;
3
+
4
+ position: relative;
5
+ display: block;
6
+ margin: 0 0 var(--space-l);
7
+ background: var(--color-shiki-monokai-bg);
8
+ border-radius: var(--space-s);
9
+
10
+ .meta {
11
+ display: flex;
12
+ margin-bottom: 0;
13
+ padding: var(--space-xs) var(--space-s) 0;
14
+ font-size: var(--font-size-s);
15
+ color: var(--color-neutral-20);
16
+ }
17
+
18
+ .language {
19
+ margin-left: auto;
20
+ text-transform: uppercase;
21
+ }
22
+
23
+ & pre {
24
+ font-size: var(--font-size-s);
25
+ padding: var(--space-s);
26
+ border-radius: var(--space-s);
27
+ overflow: auto;
28
+ }
29
+
30
+ .copy {
31
+ position: absolute;
32
+ right: var(--space-s);
33
+ bottom: var(--space-s);
34
+ }
35
+
36
+ .overlay {
37
+ display: none;
38
+ }
39
+
40
+ &[collapsed] {
41
+ max-height: 12rem;
42
+ overflow: hidden;
43
+ border-radius: var(--space-s) var(--space-s) 0 0;
44
+
45
+ &::after {
46
+ content: "";
47
+ display: block;
48
+ position: absolute;
49
+ bottom: 0;
50
+ width: 100%;
51
+ height: var(--space-m);
52
+ background:
53
+ linear-gradient(-135deg, var(--color-secondary) 0.5rem, transparent 0) 0
54
+ 0.5rem,
55
+ linear-gradient(
56
+ 135deg,
57
+ var(--color-secondary) 0.5rem,
58
+ var(--color-background) 0
59
+ )
60
+ 0 0.5rem;
61
+ background-color: var(--color-secondary);
62
+ background-size: var(--space-m) var(--space-m);
63
+ background-position: bottom;
64
+ }
65
+
66
+ .copy {
67
+ display: none;
68
+ }
69
+
70
+ .overlay {
71
+ display: flex;
72
+ flex-direction: column-reverse;
73
+ align-items: center;
74
+ position: absolute;
75
+ bottom: 0;
76
+ left: 0;
77
+ width: 100%;
78
+ height: 6rem;
79
+ color: var(--color-text);
80
+ background: linear-gradient(transparent, var(--color-secondary));
81
+ border: 0;
82
+ cursor: pointer;
83
+ padding: var(--space-xs) var(--space-s);
84
+ margin-bottom: var(--space-m);
85
+ font-size: var(--font-size-s);
86
+ transition: background-color var(--transition-short) var(--easing-inout);
87
+ text-shadow: var(--color-background) 1px 0 var(--space-xs);
88
+
89
+ &:hover,
90
+ &:active {
91
+ text-shadow: var(--color-text-inverted) var(--space-xs) 0 var(--space-s);
92
+ }
93
+ }
94
+ }
95
+ }
@@ -0,0 +1,28 @@
1
+ <module-codeblock
2
+ id="codeblock_module-codeblock-html"
3
+ collapsed
4
+ language="html"
5
+ >
6
+ <p class="meta">
7
+ <span class="file">module-codeblock.html</span>
8
+ <span class="language">html</span>
9
+ </p>
10
+ <pre><code class="language-html"></code></pre>
11
+ <basic-button
12
+ class="copy"
13
+ copy-success="Copied!"
14
+ copy-error="Error trying to copy to clipboard!"
15
+ >
16
+ <button type="button" class="secondary small">
17
+ <span class="label">Copy</span>
18
+ </button>
19
+ </basic-button>
20
+ <button
21
+ type="button"
22
+ class="overlay"
23
+ aria-expanded="false"
24
+ aria-controls="codeblock_module-codeblock-html"
25
+ >
26
+ Expand
27
+ </button>
28
+ </module-codeblock>
@@ -0,0 +1,47 @@
1
+ import {
2
+ asBoolean,
3
+ type Component,
4
+ defineComponent,
5
+ on,
6
+ toggleAttribute,
7
+ } from '../..'
8
+ import type { BasicButtonProps } from '../basic-button/basic-button'
9
+ import { copyToClipboard } from '../basic-button/copyToClipboard'
10
+
11
+ export type ModuleCodeblockProps = {
12
+ collapsed: boolean
13
+ }
14
+
15
+ type ModuleCodeblockUI = {
16
+ code: HTMLElement
17
+ overlay?: HTMLButtonElement
18
+ copy?: Component<BasicButtonProps>
19
+ }
20
+
21
+ declare global {
22
+ interface HTMLElementTagNameMap {
23
+ 'module-codeblock': Component<ModuleCodeblockProps>
24
+ }
25
+ }
26
+
27
+ export default defineComponent<ModuleCodeblockProps, ModuleCodeblockUI>(
28
+ 'module-codeblock',
29
+ { collapsed: asBoolean() },
30
+ ({ first }) => ({
31
+ code: first('code', 'Needed as source container to copy from.'),
32
+ overlay: first('button.overlay'),
33
+ copy: first('basic-button.copy'),
34
+ }),
35
+ ({ host, code, copy }) => ({
36
+ host: toggleAttribute('collapsed'),
37
+ overlay: on('click', () => {
38
+ host.collapsed = false
39
+ }),
40
+ copy: copyToClipboard(code, {
41
+ success: copy?.getAttribute('copy-success') || 'Copied!',
42
+ error:
43
+ copy?.getAttribute('copy-error') ||
44
+ 'Error trying to copy to clipboard!',
45
+ }),
46
+ }),
47
+ )
@@ -0,0 +1,13 @@
1
+ module-demo {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: var(--space-m);
5
+ margin-block-end: var(--space-l);
6
+
7
+ .preview {
8
+ border: 1px dotted var(--color-border);
9
+ border-radius: var(--space-s);
10
+ padding: var(--space-s);
11
+ container: preview / inline-size;
12
+ }
13
+ }