@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,293 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Components – Le Truc Docs</title>
7
+ <meta name="description" content="Anatomy, lifecycle, signals, effects" />
8
+ <link
9
+ rel="preload"
10
+ href="./assets/main.css?v=mj7yz3d3"
11
+ as="style"
12
+ />
13
+ <link
14
+ rel="modulepreload"
15
+ href="./assets/main.js?v=mj7yz3d3"
16
+ />
17
+ <link
18
+ rel="stylesheet"
19
+ href="./assets/main.css?v=mj7yz3d3"
20
+ />
21
+ <script
22
+ type="module"
23
+ src="./assets/main.js?v=mj7yz3d3"
24
+ ></script>
25
+ </head>
26
+ <body class="">
27
+ <context-router>
28
+ <header class="content-grid">
29
+ <a href="#main" class="skiplink visually-hidden">
30
+ Skip to main content
31
+ </a>
32
+ <h1 class="content">Le Truc Docs <small>Version 0.15.0</small></h1>
33
+ <section-menu>
34
+ <nav>
35
+ <h2 class="visually-hidden">Main Menu</h2>
36
+ <ol>
37
+ <li>
38
+ <a href="index.html">
39
+ <span class="icon">📖</span>
40
+ <strong>Introduction</strong>
41
+ <small>Overview and key benefits of Le Truc</small>
42
+ </a>
43
+ </li><li>
44
+ <a href="getting-started.html">
45
+ <span class="icon">🚀</span>
46
+ <strong>Getting Started</strong>
47
+ <small>Installation, setup, and first steps</small>
48
+ </a>
49
+ </li><li>
50
+ <a href="components.html">
51
+ <span class="icon">🏗️</span>
52
+ <strong>Components</strong>
53
+ <small>Anatomy, lifecycle, signals, effects</small>
54
+ </a>
55
+ </li><li>
56
+ <a href="styling.html">
57
+ <span class="icon">🎨</span>
58
+ <strong>Styling</strong>
59
+ <small>Scoped styles, CSS custom properties</small>
60
+ </a>
61
+ </li><li>
62
+ <a href="data-flow.html">
63
+ <span class="icon">🔄</span>
64
+ <strong>Data Flow</strong>
65
+ <small>Passing state, events, context</small>
66
+ </a>
67
+ </li><li>
68
+ <a href="about.html">
69
+ <span class="icon">🤝</span>
70
+ <strong>About</strong>
71
+ <small>License, versioning, getting involved</small>
72
+ </a>
73
+ </li>
74
+ </ol>
75
+ </nav>
76
+ </section-menu>
77
+ <card-callout class="content danger" hidden>
78
+ <p class="error" role="alert" aria-live="assertive"></p>
79
+ </card-callout>
80
+ </header>
81
+ <main id="main" class="content-grid"><section-hero><h1 id="-components"><a name="-components" class="anchor" href="#-components"><span class="permalink">🔗</span><span class="title">🏗️ Components</span></a></h1><div class="hero-layout"><div class="lead"><p><strong>Create lightweight, self-contained Web Components with built-in reactivity</strong>. Le Truc lets you define custom elements that manage state efficiently, update the DOM automatically, and enhance server-rendered pages without an SPA framework.</p></div><module-toc>
82
+ <nav>
83
+ <h2>On This Page</h2>
84
+ <ol>
85
+ <li>
86
+ <a href="#defining-a-component">Defining a Component</a>
87
+ </li><li>
88
+ <a href="#component-lifecycle">Component Lifecycle</a>
89
+ </li><li>
90
+ <a href="#managing-state-with-signals">Managing State with Signals</a>
91
+ </li><li>
92
+ <a href="#selecting-elements">Selecting Elements</a>
93
+ </li><li>
94
+ <a href="#adding-event-listeners">Adding Event Listeners</a>
95
+ </li><li>
96
+ <a href="#synchronizing-state-with-effects">Synchronizing State with Effects</a>
97
+ </li>
98
+ </ol>
99
+ </nav>
100
+ </module-toc></div></section-hero><section><h2 id="defining-a-component"><a name="defining-a-component" class="anchor" href="#defining-a-component"><span class="permalink">🔗</span><span class="title">Defining a Component</span></a></h2><p>Le Truc builds on <strong>Web Components</strong>, extending <code>HTMLElement</code> to provide <strong>built-in state management and reactive updates</strong>.</p><p>Le Truc creates components using the <code>defineComponent()</code> function:</p><module-codeblock language="js" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><p class="meta"><span class="language">js</span></p><pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#A6E22E">defineComponent</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'my-component'</span><span style="color:#F8F8F2">, {}, {}, () </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> [</span></span>
101
+ <span class="line"><span style="color:#88846F"> // Component setup</span></span>
102
+ <span class="line"><span style="color:#F8F8F2">])</span></span>
103
+ <span class="line"></span></code></pre><basic-button class="copy" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><button type="button" class="secondary small"><span class="label">Copy</span></button></basic-button></module-codeblock><p>Every Le Truc component must be registered with a valid custom element tag name (two or more words joined with <code>-</code>) as the first parameter.</p><h3 id="using-the-custom-element-in-html"><a name="using-the-custom-element-in-html" class="anchor" href="#using-the-custom-element-in-html"><span class="permalink">🔗</span><span class="title">Using the Custom Element in HTML</span></a></h3><p>Once registered, the component can be used like any native HTML element:</p><module-codeblock language="html" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><p class="meta"><span class="language">html</span></p><pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#F8F8F2">&#x3C;</span><span style="color:#F92672">my-component</span><span style="color:#F8F8F2">>Content goes here&#x3C;/</span><span style="color:#F92672">my-component</span><span style="color:#F8F8F2">></span></span>
104
+ <span class="line"></span></code></pre><basic-button class="copy" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><button type="button" class="secondary small"><span class="label">Copy</span></button></basic-button></module-codeblock><h3 id="anatomy-of-a-component"><a name="anatomy-of-a-component" class="anchor" href="#anatomy-of-a-component"><span class="permalink">🔗</span><span class="title">Anatomy of a Component</span></a></h3><p>Let's examine a complete component example to understand how Le Truc works:</p><module-codeblock language="js" copy-success="Copied!" copy-error="Error trying to copy to clipboard!" collapsed=""><p class="meta"><span class="language">js</span></p><pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#A6E22E">defineComponent</span><span style="color:#F8F8F2">(</span></span>
105
+ <span class="line"><span style="color:#E6DB74"> 'basic-hello'</span><span style="color:#F8F8F2">,</span></span>
106
+ <span class="line"><span style="color:#F8F8F2"> {</span></span>
107
+ <span class="line"><span style="color:#F8F8F2"> name: </span><span style="color:#A6E22E">asString</span><span style="color:#F8F8F2">(</span><span style="color:#FD971F;font-style:italic">ui</span><span style="color:#66D9EF;font-style:italic"> =></span><span style="color:#F8F8F2"> ui.output.textContent),</span></span>
108
+ <span class="line"><span style="color:#F8F8F2"> },</span></span>
109
+ <span class="line"><span style="color:#F8F8F2"> ({ </span><span style="color:#FD971F;font-style:italic">first</span><span style="color:#F8F8F2"> }) </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> ({</span></span>
110
+ <span class="line"><span style="color:#F8F8F2"> input: </span><span style="color:#A6E22E">first</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'input'</span><span style="color:#F8F8F2">, </span><span style="color:#E6DB74">'Needed to enter the name.'</span><span style="color:#F8F8F2">),</span></span>
111
+ <span class="line"><span style="color:#F8F8F2"> output: </span><span style="color:#A6E22E">first</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'output'</span><span style="color:#F8F8F2">, </span><span style="color:#E6DB74">'Needed to display the name.'</span><span style="color:#F8F8F2">),</span></span>
112
+ <span class="line"><span style="color:#F8F8F2"> }),</span></span>
113
+ <span class="line"><span style="color:#F8F8F2"> ({ </span><span style="color:#FD971F;font-style:italic">host</span><span style="color:#F8F8F2">, </span><span style="color:#FD971F;font-style:italic">input</span><span style="color:#F8F8F2"> }) </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> {</span></span>
114
+ <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> fallback </span><span style="color:#F92672">=</span><span style="color:#F8F8F2"> host.name</span></span>
115
+ <span class="line"><span style="color:#F92672"> return</span><span style="color:#F8F8F2"> {</span></span>
116
+ <span class="line"><span style="color:#F8F8F2"> input: </span><span style="color:#A6E22E">on</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'input'</span><span style="color:#F8F8F2">, () </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> {</span></span>
117
+ <span class="line"><span style="color:#F8F8F2"> host.name </span><span style="color:#F92672">=</span><span style="color:#F8F8F2"> input.value </span><span style="color:#F92672">||</span><span style="color:#F8F8F2"> fallback</span></span>
118
+ <span class="line"><span style="color:#F8F8F2"> }),</span></span>
119
+ <span class="line"><span style="color:#F8F8F2"> output: </span><span style="color:#A6E22E">setText</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'name'</span><span style="color:#F8F8F2">),</span></span>
120
+ <span class="line"><span style="color:#F8F8F2"> }</span></span>
121
+ <span class="line"><span style="color:#F8F8F2"> },</span></span>
122
+ <span class="line"><span style="color:#F8F8F2">)</span></span>
123
+ <span class="line"></span></code></pre><basic-button class="copy" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><button type="button" class="secondary small"><span class="label">Copy</span></button></basic-button><button type="button" class="overlay" aria-expanded="false">Expand</button></module-codeblock><h4 id="reactive-properties"><a name="reactive-properties" class="anchor" href="#reactive-properties"><span class="permalink">🔗</span><span class="title">Reactive Properties</span></a></h4><module-codeblock language="js" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><p class="meta"><span class="language">js</span></p><pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#F8F8F2">{</span></span>
124
+ <span class="line"><span style="color:#F8F8F2"> name: </span><span style="color:#A6E22E">asString</span><span style="color:#F8F8F2">(</span><span style="color:#FD971F;font-style:italic">ui</span><span style="color:#66D9EF;font-style:italic"> =></span><span style="color:#F8F8F2"> ui.output.textContent),</span></span>
125
+ <span class="line"><span style="color:#F8F8F2">}</span></span>
126
+ <span class="line"></span></code></pre><basic-button class="copy" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><button type="button" class="secondary small"><span class="label">Copy</span></button></basic-button></module-codeblock><p>This creates a reactive property called <code>name</code>:</p><ul><li><code>asString()</code> observes the attribute <code>name</code> and assigns its value as a string to the <code>name</code> property</li><li><code>ui =&gt; ...</code> is an instruction how to get the fallback value in the DOM if there is no name attribute</li><li>Le Truc automatically reads &quot;World&quot; from the <code>&lt;output&gt;</code> element as the initial value</li><li>When <code>name</code> changes, any effects that depend on it automatically update</li></ul><h4 id="select-function"><a name="select-function" class="anchor" href="#select-function"><span class="permalink">🔗</span><span class="title">Select Function</span></a></h4><p>The select function is used to find descendant elements within the component's DOM:</p><module-codeblock language="js" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><p class="meta"><span class="language">js</span></p><pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#F8F8F2">({ </span><span style="color:#FD971F;font-style:italic">first</span><span style="color:#F8F8F2"> }) </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> ({</span></span>
127
+ <span class="line"><span style="color:#F8F8F2"> input: </span><span style="color:#A6E22E">first</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'input'</span><span style="color:#F8F8F2">, </span><span style="color:#E6DB74">'Needed to enter the name.'</span><span style="color:#F8F8F2">),</span></span>
128
+ <span class="line"><span style="color:#F8F8F2"> output: </span><span style="color:#A6E22E">first</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'output'</span><span style="color:#F8F8F2">, </span><span style="color:#E6DB74">'Needed to display the name.'</span><span style="color:#F8F8F2">),</span></span>
129
+ <span class="line"><span style="color:#F8F8F2">}),</span></span>
130
+ <span class="line"></span></code></pre><basic-button class="copy" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><button type="button" class="secondary small"><span class="label">Copy</span></button></basic-button></module-codeblock><p>The select function must return a record of the selected elements, commonly called <code>ui</code> to which initializer functions for reactive properties and the setup function for effects have access to. In the above example, the helper function <code>first()</code> is used to find the first descendant matching a selector. Also available is <code>all()</code> to find all descendants matching a selector, dynamically updating the list of elements when the DOM changes. Both helper functions take a selector string and an optional error message to display if no element is found.</p><h4 id="setup-function"><a name="setup-function" class="anchor" href="#setup-function"><span class="permalink">🔗</span><span class="title">Setup Function</span></a></h4><p>The setup function must return a record with an array of effects for properties of the <code>ui</code> object that is passed in. The additional <code>host</code> key of the <code>ui</code> object holds the component element itself.</p><module-codeblock language="js" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><p class="meta"><span class="language">js</span></p><pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#F8F8F2">({ </span><span style="color:#FD971F;font-style:italic">host</span><span style="color:#F8F8F2">, </span><span style="color:#FD971F;font-style:italic">input</span><span style="color:#F8F8F2"> }) </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> {</span></span>
131
+ <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> fallback </span><span style="color:#F92672">=</span><span style="color:#F8F8F2"> host.name</span></span>
132
+ <span class="line"><span style="color:#F92672"> return</span><span style="color:#F8F8F2"> {</span></span>
133
+ <span class="line"><span style="color:#F8F8F2"> input: </span><span style="color:#A6E22E">on</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'input'</span><span style="color:#F8F8F2">, () </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> {</span></span>
134
+ <span class="line"><span style="color:#F8F8F2"> host.name </span><span style="color:#F92672">=</span><span style="color:#F8F8F2"> input.value </span><span style="color:#F92672">||</span><span style="color:#F8F8F2"> fallback</span></span>
135
+ <span class="line"><span style="color:#F8F8F2"> }),</span></span>
136
+ <span class="line"><span style="color:#F8F8F2"> output: </span><span style="color:#A6E22E">setText</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'name'</span><span style="color:#F8F8F2">),</span></span>
137
+ <span class="line"><span style="color:#F8F8F2"> }</span></span>
138
+ <span class="line"><span style="color:#F8F8F2">},</span></span>
139
+ <span class="line"></span></code></pre><basic-button class="copy" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><button type="button" class="secondary small"><span class="label">Copy</span></button></basic-button></module-codeblock><p>Effects define <strong>component behaviors</strong>:</p><ul><li><code>input: on('input', ...)</code> adds an event listener to the <code>&lt;input&gt;</code> element</li><li><code>output: setText('name')</code> keeps its text in sync with the <code>name</code> property</li></ul><p>Characteristics of effects:</p><ul><li>Effects run when the component is added to the page</li><li>Effects rerun when their dependencies change</li><li>Effects may return a cleanup function to be executed when the target element or the component is removed from the page</li></ul><p>The bundled effects <code>on()</code> and <code>setText()</code> in this case are partially applied functions that connect to component properties and the target element and return the appropriate cleanup function.</p></section><section><h2 id="component-lifecycle"><a name="component-lifecycle" class="anchor" href="#component-lifecycle"><span class="permalink">🔗</span><span class="title">Component Lifecycle</span></a></h2><p>Le Truc manages the <strong>Web Component lifecycle</strong> from creation to removal. Here's what happens.</p><h3 id="connected-to-the-dom"><a name="connected-to-the-dom" class="anchor" href="#connected-to-the-dom"><span class="permalink">🔗</span><span class="title">Connected to the DOM</span></a></h3><p>In the <code>connectedCallback()</code> reactive properties are initialized. You pass a second argument to the <code>defineComponent()</code> function to define initial values for <strong>component states</strong>.</p><module-codeblock language="js" copy-success="Copied!" copy-error="Error trying to copy to clipboard!" collapsed=""><p class="meta"><span class="language">js</span></p><pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#A6E22E">defineComponent</span><span style="color:#F8F8F2">(</span></span>
140
+ <span class="line"><span style="color:#E6DB74"> 'my-component'</span><span style="color:#F8F8F2">,</span></span>
141
+ <span class="line"><span style="color:#F8F8F2"> {</span></span>
142
+ <span class="line"><span style="color:#F8F8F2"> count: </span><span style="color:#AE81FF">0</span><span style="color:#F8F8F2">, </span><span style="color:#88846F">// Initial value of "count" signal</span></span>
143
+ <span class="line"><span style="color:#F8F8F2"> value: </span><span style="color:#A6E22E">asInteger</span><span style="color:#F8F8F2">(</span><span style="color:#AE81FF">5</span><span style="color:#F8F8F2">), </span><span style="color:#88846F">// Parse "value" attribute as integer defaulting to 5</span></span>
144
+ <span class="line"><span style="color:#A6E22E"> isEven</span><span style="color:#F8F8F2">: </span><span style="color:#FD971F;font-style:italic">ui</span><span style="color:#66D9EF;font-style:italic"> =></span><span style="color:#F8F8F2"> () </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F92672"> !</span><span style="color:#F8F8F2">(ui.host.count </span><span style="color:#F92672">%</span><span style="color:#AE81FF"> 2</span><span style="color:#F8F8F2">), </span><span style="color:#88846F">// Computed signal based on "count" signal</span></span>
145
+ <span class="line"><span style="color:#F8F8F2"> name: </span><span style="color:#A6E22E">fromContext</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'display-name'</span><span style="color:#F8F8F2">, </span><span style="color:#E6DB74">'World'</span><span style="color:#F8F8F2">), </span><span style="color:#88846F">// Consume "display-name" signal from closest context provider</span></span>
146
+ <span class="line"><span style="color:#F8F8F2"> },</span></span>
147
+ <span class="line"><span style="color:#F8F8F2"> () </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> ({</span></span>
148
+ <span class="line"><span style="color:#88846F"> // Component UI</span></span>
149
+ <span class="line"><span style="color:#F8F8F2"> }),</span></span>
150
+ <span class="line"><span style="color:#FD971F;font-style:italic"> ui</span><span style="color:#66D9EF;font-style:italic"> =></span><span style="color:#F8F8F2"> ({</span></span>
151
+ <span class="line"><span style="color:#88846F"> // Component setup</span></span>
152
+ <span class="line"><span style="color:#F8F8F2"> })</span></span>
153
+ <span class="line"><span style="color:#F8F8F2">)</span></span>
154
+ <span class="line"></span></code></pre><basic-button class="copy" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><button type="button" class="secondary small"><span class="label">Copy</span></button></basic-button><button type="button" class="overlay" aria-expanded="false">Expand</button></module-codeblock><p>In this example you see all three ways to define a reactive property:</p><ul><li>A <strong>static initial value</strong> creates a <code>State</code> signal with the initial value</li><li>An <strong>attribute parser</strong> creates a <code>State</code> signal may from the attribute or fallback value, updating the state whenever the attribute changes</li><li>An <strong>initializer</strong> function that creates a <code>State</code> or a <code>Computed</code> signal depending on the return type of the function. If the function returns a value, it creates a <code>State</code> signal. If the function returns a function, it creates a <code>Computed</code> signal. Initializer functions have access to the component's <code>ui</code> object, allowing them to create signals based on the component's state or descendant elements.</li></ul><h3 id="disconnected-from-the-dom"><a name="disconnected-from-the-dom" class="anchor" href="#disconnected-from-the-dom"><span class="permalink">🔗</span><span class="title">Disconnected from the DOM</span></a></h3><p>In the <code>disconnectedCallback()</code> Le Truc runs all cleanup functions returned by effects during the setup phase in <code>connectedCallback()</code>. This will remove all event listeners and unsubscribe all signals the component is subscribed to, so you don't need to worry about memory leaks.</p><p>If you added <strong>event listeners</strong> outside the scope of your component or <strong>subscribed manually to external APIs</strong> in a custom effect, you need to return a cleanup function:</p><module-codeblock language="js" copy-success="Copied!" copy-error="Error trying to copy to clipboard!" collapsed=""><p class="meta"><span class="language">js</span></p><pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#A6E22E">defineComponent</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'my-component'</span><span style="color:#F8F8F2">, {}, {}, ({ </span><span style="color:#FD971F;font-style:italic">host</span><span style="color:#F8F8F2"> }) </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> {</span></span>
155
+ <span class="line"><span style="color:#88846F"> // Setup logic</span></span>
156
+ <span class="line"><span style="color:#F8F8F2"> host: () </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> {</span></span>
157
+ <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> observer </span><span style="color:#F92672">=</span><span style="color:#F92672"> new</span><span style="color:#A6E22E"> IntersectionObserver</span><span style="color:#F8F8F2">(([</span><span style="color:#FD971F;font-style:italic">entry</span><span style="color:#F8F8F2">]) </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> {</span></span>
158
+ <span class="line"><span style="color:#88846F"> // Do something</span></span>
159
+ <span class="line"><span style="color:#F8F8F2"> })</span></span>
160
+ <span class="line"><span style="color:#F8F8F2"> observer.</span><span style="color:#A6E22E">observe</span><span style="color:#F8F8F2">(host)</span></span>
161
+ <span class="line"></span>
162
+ <span class="line"><span style="color:#88846F"> // Cleanup logic</span></span>
163
+ <span class="line"><span style="color:#F92672"> return</span><span style="color:#F8F8F2"> () </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> observer.</span><span style="color:#A6E22E">disconnect</span><span style="color:#F8F8F2">()</span></span>
164
+ <span class="line"><span style="color:#F8F8F2"> },</span></span>
165
+ <span class="line"><span style="color:#F8F8F2">})</span></span>
166
+ <span class="line"></span></code></pre><basic-button class="copy" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><button type="button" class="secondary small"><span class="label">Copy</span></button></basic-button><button type="button" class="overlay" aria-expanded="false">Expand</button></module-codeblock><h2 id="managing-state-with-signals"><a name="managing-state-with-signals" class="anchor" href="#managing-state-with-signals"><span class="permalink">🔗</span><span class="title">Managing State with Signals</span></a></h2><p>Le Truc manages state using <strong>signals</strong>, which are atomic reactive states that trigger updates when they change. We use regular properties for public component states:</p><module-codeblock language="js" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><p class="meta"><span class="language">js</span></p><pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#F8F8F2">console.</span><span style="color:#A6E22E">log</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'count'</span><span style="color:#F92672"> in</span><span style="color:#F8F8F2"> el) </span><span style="color:#88846F">// Check if the signal exists</span></span>
167
+ <span class="line"><span style="color:#F8F8F2">console.</span><span style="color:#A6E22E">log</span><span style="color:#F8F8F2">(el.count) </span><span style="color:#88846F">// Read the signal value</span></span>
168
+ <span class="line"><span style="color:#F8F8F2">el.count </span><span style="color:#F92672">=</span><span style="color:#AE81FF"> 42</span><span style="color:#88846F"> // Update the signal value</span></span>
169
+ <span class="line"></span></code></pre><basic-button class="copy" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><button type="button" class="secondary small"><span class="label">Copy</span></button></basic-button></module-codeblock><h3 id="characteristics-and-special-values"><a name="characteristics-and-special-values" class="anchor" href="#characteristics-and-special-values"><span class="permalink">🔗</span><span class="title">Characteristics and Special Values</span></a></h3><p>Signals in Le Truc are of a <strong>static type</strong> and <strong>non-nullable</strong>. This allows to <strong>simplify the logic</strong> as you will never have to check the type or perform null-checks.</p><ul><li>If you use <strong>TypeScript</strong> (recommended), <strong>you will be warned</strong> that <code>null</code> or <code>undefined</code> cannot be assigned to a signal or if you try to assign a value of a wrong type.</li><li>If you use vanilla <strong>JavaScript</strong> without a build step, setting a signal to <code>null</code> or <code>undefined</code> <strong>will throw a <code>NullishSignalValueError</code></strong>. However, strict type checking is not enforced at runtime.</li></ul><p>Because of the <strong>non-nullable nature of signals</strong> in Le Truc, we need two special values that can be assigned to any signal type:</p><ul><li><strong><code>RESET</code></strong>: Will <strong>reset to the server-rendered version</strong> that was there before Le Truc took control. This is what you want to do most of the times when a signal lacks a specific value.</li><li><strong><code>UNSET</code></strong>: Will <strong>delete the signal</strong>, <strong>unsubscribe its watchers</strong> and also <strong>delete related attributes or style properties</strong> in effects. Use this with special care!</li></ul><h3 id="initializing-state-from-attributes"><a name="initializing-state-from-attributes" class="anchor" href="#initializing-state-from-attributes"><span class="permalink">🔗</span><span class="title">Initializing State from Attributes</span></a></h3><p>The standard way to set initial state in Le Truc is via <strong>server-rendered attributes</strong> on the component that needs it. No props drilling as in other frameworks. Le Trucs provides some bundled attribute parsers to convert attribute values to the desired type. And you can also define your own custom parsers.</p><module-codeblock language="js" copy-success="Copied!" copy-error="Error trying to copy to clipboard!" collapsed=""><p class="meta"><span class="language">js</span></p><pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#A6E22E">defineComponent</span><span style="color:#F8F8F2">(</span></span>
170
+ <span class="line"><span style="color:#E6DB74"> 'my-component'</span><span style="color:#F8F8F2">,</span></span>
171
+ <span class="line"><span style="color:#F8F8F2"> {</span></span>
172
+ <span class="line"><span style="color:#F8F8F2"> count: </span><span style="color:#A6E22E">asInteger</span><span style="color:#F8F8F2">(), </span><span style="color:#88846F">// Bundled parser: Convert '42' -> 42</span></span>
173
+ <span class="line"><span style="color:#A6E22E"> date</span><span style="color:#F8F8F2">: (</span><span style="color:#FD971F;font-style:italic">_</span><span style="color:#F8F8F2">, </span><span style="color:#FD971F;font-style:italic">v</span><span style="color:#F8F8F2">) </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F92672"> new</span><span style="color:#A6E22E"> Date</span><span style="color:#F8F8F2">(v), </span><span style="color:#88846F">// Custom parser: '2025-12-12' -> Date object</span></span>
174
+ <span class="line"><span style="color:#F8F8F2"> },</span></span>
175
+ <span class="line"><span style="color:#F8F8F2"> () </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> ({</span></span>
176
+ <span class="line"><span style="color:#88846F"> // Component UI</span></span>
177
+ <span class="line"><span style="color:#F8F8F2"> })</span></span>
178
+ <span class="line"><span style="color:#F8F8F2"> () </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> ({</span></span>
179
+ <span class="line"><span style="color:#88846F"> // Component setup</span></span>
180
+ <span class="line"><span style="color:#F8F8F2"> }),</span></span>
181
+ <span class="line"><span style="color:#F8F8F2">)</span></span>
182
+ <span class="line"></span></code></pre><basic-button class="copy" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><button type="button" class="secondary small"><span class="label">Copy</span></button></basic-button><button type="button" class="overlay" aria-expanded="false">Expand</button></module-codeblock><card-callout class="caution"><p><strong>Careful</strong>: Attributes <strong>may not be present</strong> on the element or <strong>parsing to the desired type may fail</strong>. To ensure <strong>non-nullability</strong> of signals, Le Truc falls back to neutral defaults if no fallback value is provided:</p><ul><li><code>&quot;&quot;</code> (empty string) for <code>string</code></li><li><code>0</code> for <code>number</code></li><li><code>{}</code> (empty object) for objects of any kind</li></ul></card-callout><h3 id="bundled-attribute-parsers"><a name="bundled-attribute-parsers" class="anchor" href="#bundled-attribute-parsers"><span class="permalink">🔗</span><span class="title">Bundled Attribute Parsers</span></a></h3><p>Le Truc provides several built-in parsers for common attribute types. See the <a href="api.html#parsers">Parsers section</a> in the API reference for detailed descriptions and usage examples.</p></section><section><h2 id="selecting-elements"><a name="selecting-elements" class="anchor" href="#selecting-elements"><span class="permalink">🔗</span><span class="title">Selecting Elements</span></a></h2><p>Use the provided selector utilities to find descendant elements within your component:</p><h3 id="first"><a name="first" class="anchor" href="#first"><span class="permalink">🔗</span><span class="title">first()</span></a></h3><p>Selects the first matching element:</p><module-codeblock language="js" copy-success="Copied!" copy-error="Error trying to copy to clipboard!" collapsed=""><p class="meta"><span class="language">js</span></p><pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#A6E22E">defineComponent</span><span style="color:#F8F8F2">(</span></span>
183
+ <span class="line"><span style="color:#E6DB74"> 'basic-counter'</span><span style="color:#F8F8F2">,</span></span>
184
+ <span class="line"><span style="color:#F8F8F2"> {</span></span>
185
+ <span class="line"><span style="color:#88846F"> // Initialize properties</span></span>
186
+ <span class="line"><span style="color:#F8F8F2"> },</span></span>
187
+ <span class="line"><span style="color:#F8F8F2"> ({ </span><span style="color:#FD971F;font-style:italic">first</span><span style="color:#F8F8F2"> }) </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> ({</span></span>
188
+ <span class="line"><span style="color:#F8F8F2"> increment: </span><span style="color:#A6E22E">first</span><span style="color:#F8F8F2">(</span></span>
189
+ <span class="line"><span style="color:#E6DB74"> 'button'</span><span style="color:#F8F8F2">,</span></span>
190
+ <span class="line"><span style="color:#E6DB74"> 'Add a native button element to increment the count.'</span><span style="color:#F8F8F2">,</span></span>
191
+ <span class="line"><span style="color:#F8F8F2"> ),</span></span>
192
+ <span class="line"><span style="color:#F8F8F2"> count: </span><span style="color:#A6E22E">first</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'span'</span><span style="color:#F8F8F2">, </span><span style="color:#E6DB74">'Add a span to display the count.'</span><span style="color:#F8F8F2">),</span></span>
193
+ <span class="line"><span style="color:#F8F8F2"> }),</span></span>
194
+ <span class="line"><span style="color:#FD971F;font-style:italic"> ui</span><span style="color:#66D9EF;font-style:italic"> =></span><span style="color:#F8F8F2"> ({</span></span>
195
+ <span class="line"><span style="color:#88846F"> // Component setup</span></span>
196
+ <span class="line"><span style="color:#F8F8F2"> }),</span></span>
197
+ <span class="line"><span style="color:#F8F8F2">)</span></span>
198
+ <span class="line"></span></code></pre><basic-button class="copy" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><button type="button" class="secondary small"><span class="label">Copy</span></button></basic-button><button type="button" class="overlay" aria-expanded="false">Expand</button></module-codeblock><h3 id="all"><a name="all" class="anchor" href="#all"><span class="permalink">🔗</span><span class="title">all()</span></a></h3><p>Selects all matching elements:</p><module-codeblock language="js" copy-success="Copied!" copy-error="Error trying to copy to clipboard!" collapsed=""><p class="meta"><span class="language">js</span></p><pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#A6E22E">defineComponent</span><span style="color:#F8F8F2">(</span></span>
199
+ <span class="line"><span style="color:#E6DB74"> 'module-tabgroup'</span><span style="color:#F8F8F2">,</span></span>
200
+ <span class="line"><span style="color:#F8F8F2"> {</span></span>
201
+ <span class="line"><span style="color:#88846F"> // Initialize properties</span></span>
202
+ <span class="line"><span style="color:#F8F8F2"> },</span></span>
203
+ <span class="line"><span style="color:#F8F8F2"> ({ </span><span style="color:#FD971F;font-style:italic">all</span><span style="color:#F8F8F2"> }) </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> ({</span></span>
204
+ <span class="line"><span style="color:#F8F8F2"> tabs: </span><span style="color:#A6E22E">all</span><span style="color:#F8F8F2">(</span></span>
205
+ <span class="line"><span style="color:#E6DB74"> 'button[role="tab"]'</span><span style="color:#F8F8F2">,</span></span>
206
+ <span class="line"><span style="color:#E6DB74"> 'At least 2 tabs as children of a &#x3C;[role="tablist"]> element are needed. Each tab must reference a unique id of a &#x3C;[role="tabpanel"]> element.'</span><span style="color:#F8F8F2">,</span></span>
207
+ <span class="line"><span style="color:#F8F8F2"> ),</span></span>
208
+ <span class="line"><span style="color:#F8F8F2"> panels: </span><span style="color:#A6E22E">all</span><span style="color:#F8F8F2">(</span></span>
209
+ <span class="line"><span style="color:#E6DB74"> '[role="tabpanel"]'</span><span style="color:#F8F8F2">,</span></span>
210
+ <span class="line"><span style="color:#E6DB74"> 'At least 2 tabpanels are needed. Each tabpanel must have a unique id.'</span><span style="color:#F8F8F2">,</span></span>
211
+ <span class="line"><span style="color:#F8F8F2"> ),</span></span>
212
+ <span class="line"><span style="color:#F8F8F2"> }),</span></span>
213
+ <span class="line"><span style="color:#FD971F;font-style:italic"> ui</span><span style="color:#66D9EF;font-style:italic"> =></span><span style="color:#F8F8F2"> ({</span></span>
214
+ <span class="line"><span style="color:#88846F"> // Component setup</span></span>
215
+ <span class="line"><span style="color:#F8F8F2"> }),</span></span>
216
+ <span class="line"><span style="color:#F8F8F2">)</span></span>
217
+ <span class="line"></span></code></pre><basic-button class="copy" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><button type="button" class="secondary small"><span class="label">Copy</span></button></basic-button><button type="button" class="overlay" aria-expanded="false">Expand</button></module-codeblock><p>The <code>first()</code> function expects the matched element to be present at connection time. If not, it will silently ignore the call.</p><p>On the other hand, the <code>all()</code> function creates a dynamic array of elements that will be updated whenever the matching elements are added or removed from the component's DOM branch. Le Truc will apply the given setup functions to added elements and run the cleanup functions on removed elements.</p><card-callout class="tip"><p><strong>Tip</strong>: The <code>all()</code> function is more flexible but also more resource-intensive than <code>first()</code>. Prefer <code>first()</code> when targeting a single element known to be present at connection time.</p></card-callout></section><section><h2 id="adding-event-listeners"><a name="adding-event-listeners" class="anchor" href="#adding-event-listeners"><span class="permalink">🔗</span><span class="title">Adding Event Listeners</span></a></h2><p>Event listeners allow to respond to user interactions. They are the the main cause for changes in the component's state. Le Truc provides the <code>on()</code> function to add event listeners to elements and remove them when the component is disconnected.</p><module-codeblock language="js" copy-success="Copied!" copy-error="Error trying to copy to clipboard!" collapsed=""><p class="meta"><span class="language">js</span></p><pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#A6E22E">defineComponent</span><span style="color:#F8F8F2">(</span></span>
218
+ <span class="line"><span style="color:#E6DB74"> 'my-component'</span><span style="color:#F8F8F2">,</span></span>
219
+ <span class="line"><span style="color:#F8F8F2"> {</span></span>
220
+ <span class="line"><span style="color:#F8F8F2"> active: </span><span style="color:#AE81FF">0</span><span style="color:#F8F8F2">,</span></span>
221
+ <span class="line"><span style="color:#F8F8F2"> value: </span><span style="color:#E6DB74">''</span></span>
222
+ <span class="line"><span style="color:#F8F8F2"> },</span></span>
223
+ <span class="line"><span style="color:#F8F8F2"> ({ </span><span style="color:#FD971F;font-style:italic">all</span><span style="color:#F8F8F2">, </span><span style="color:#FD971F;font-style:italic">first</span><span style="color:#F8F8F2"> }) </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> ({</span></span>
224
+ <span class="line"><span style="color:#F8F8F2"> buttons: </span><span style="color:#A6E22E">all</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'button'</span><span style="color:#F8F8F2">),</span></span>
225
+ <span class="line"><span style="color:#F8F8F2"> input: </span><span style="color:#A6E22E">first</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'input'</span><span style="color:#F8F8F2">)</span></span>
226
+ <span class="line"><span style="color:#F8F8F2"> }),</span></span>
227
+ <span class="line"><span style="color:#F8F8F2"> ({ </span><span style="color:#FD971F;font-style:italic">host</span><span style="color:#F8F8F2">, </span><span style="color:#FD971F;font-style:italic">input</span><span style="color:#F8F8F2"> }) </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> ({</span></span>
228
+ <span class="line"><span style="color:#F8F8F2"> buttons: </span><span style="color:#A6E22E">on</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'click'</span><span style="color:#F8F8F2">, ({ </span><span style="color:#FD971F;font-style:italic">target</span><span style="color:#F8F8F2"> }) </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> {</span></span>
229
+ <span class="line"><span style="color:#88846F"> // Set 'active' signal to value of data-index attribute of button</span></span>
230
+ <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> index </span><span style="color:#F92672">=</span><span style="color:#A6E22E"> parseInt</span><span style="color:#F8F8F2">(target.dataset.index, </span><span style="color:#AE81FF">10</span><span style="color:#F8F8F2">);</span></span>
231
+ <span class="line"><span style="color:#F8F8F2"> host.active </span><span style="color:#F92672">=</span><span style="color:#F8F8F2"> Number.</span><span style="color:#A6E22E">isInteger</span><span style="color:#F8F8F2">(index) </span><span style="color:#F92672">?</span><span style="color:#F8F8F2"> index </span><span style="color:#F92672">:</span><span style="color:#AE81FF"> 0</span><span style="color:#F8F8F2">;</span></span>
232
+ <span class="line"><span style="color:#F8F8F2"> })</span></span>
233
+ <span class="line"><span style="color:#F8F8F2"> input: </span><span style="color:#A6E22E">on</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'change'</span><span style="color:#F8F8F2">, () </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> {</span></span>
234
+ <span class="line"><span style="color:#88846F"> // Set 'value' signal to value of input element</span></span>
235
+ <span class="line"><span style="color:#F8F8F2"> host.value </span><span style="color:#F92672">=</span><span style="color:#F8F8F2"> target.value;</span></span>
236
+ <span class="line"><span style="color:#F8F8F2"> })</span></span>
237
+ <span class="line"><span style="color:#F8F8F2"> })</span></span>
238
+ <span class="line"><span style="color:#F8F8F2">)</span></span>
239
+ <span class="line"></span></code></pre><basic-button class="copy" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><button type="button" class="secondary small"><span class="label">Copy</span></button></basic-button><button type="button" class="overlay" aria-expanded="false">Expand</button></module-codeblock></section><section><h2 id="synchronizing-state-with-effects"><a name="synchronizing-state-with-effects" class="anchor" href="#synchronizing-state-with-effects"><span class="permalink">🔗</span><span class="title">Synchronizing State with Effects</span></a></h2><p>Effects <strong>automatically update the DOM</strong> when signals change, avoiding manual DOM manipulation.</p><h3 id="applying-effects"><a name="applying-effects" class="anchor" href="#applying-effects"><span class="permalink">🔗</span><span class="title">Applying Effects</span></a></h3><p>Apply one or multiple effects in the setup function (for component itself) or in element selector functions:</p><module-codeblock language="js" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><p class="meta"><span class="language">js</span></p><pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#F92672">return</span><span style="color:#F8F8F2"> {</span></span>
240
+ <span class="line"><span style="color:#88846F"> // On the component itself</span></span>
241
+ <span class="line"><span style="color:#F8F8F2"> host: </span><span style="color:#A6E22E">setAttribute</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'open'</span><span style="color:#F8F8F2">, </span><span style="color:#E6DB74">'open'</span><span style="color:#F8F8F2">), </span><span style="color:#88846F">// Set 'open' attribute according to 'open' signal</span></span>
242
+ <span class="line"><span style="color:#88846F"> // On element for the 'count' property of the UI object</span></span>
243
+ <span class="line"><span style="color:#F8F8F2"> count: [</span></span>
244
+ <span class="line"><span style="color:#A6E22E"> setText</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'count'</span><span style="color:#F8F8F2">), </span><span style="color:#88846F">// Update text content according to 'count' signal</span></span>
245
+ <span class="line"><span style="color:#A6E22E"> toggleClass</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'even'</span><span style="color:#F8F8F2">, </span><span style="color:#E6DB74">'isEven'</span><span style="color:#F8F8F2">) </span><span style="color:#88846F">// Toggle 'even' class according to 'isEven' signal</span></span>
246
+ <span class="line"><span style="color:#F8F8F2"> ]</span></span>
247
+ <span class="line"><span style="color:#F8F8F2">}</span></span>
248
+ <span class="line"></span></code></pre><basic-button class="copy" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><button type="button" class="secondary small"><span class="label">Copy</span></button></basic-button></module-codeblock><p>The order of effects is not important. Feel free to apply them in any order that suits your needs.</p><h3 id="bundled-effects"><a name="bundled-effects" class="anchor" href="#bundled-effects"><span class="permalink">🔗</span><span class="title">Bundled Effects</span></a></h3><p>Le Truc provides many built-in effects for common DOM operations. See the <a href="api.html#effects">Effects section</a> in the API reference for detailed descriptions and usage examples.</p><h3 id="simplifying-effect-notation"><a name="simplifying-effect-notation" class="anchor" href="#simplifying-effect-notation"><span class="permalink">🔗</span><span class="title">Simplifying Effect Notation</span></a></h3><p>For effects that take two arguments, <strong>the second argument can be omitted</strong> if the signal key matches the targeted property name, attribute, class, or style property.</p><p>The following are equivalent:</p><module-codeblock language="js" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><p class="meta"><span class="language">js</span></p><pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#88846F">// setAttribute('open', 'open')</span></span>
249
+ <span class="line"><span style="color:#A6E22E">setAttribute</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'open'</span><span style="color:#F8F8F2">)</span></span>
250
+ <span class="line"></span></code></pre><basic-button class="copy" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><button type="button" class="secondary small"><span class="label">Copy</span></button></basic-button></module-codeblock><p>Here, <code>setAttribute('open')</code> automatically uses the <code>open</code> signal.</p><h3 id="using-local-signals-for-private-state"><a name="using-local-signals-for-private-state" class="anchor" href="#using-local-signals-for-private-state"><span class="permalink">🔗</span><span class="title">Using Local Signals for Private State</span></a></h3><p>Local signals are useful for storing state that should not be exposed to the outside world. They can be used to manage internal state within a component:</p><module-codeblock language="js" copy-success="Copied!" copy-error="Error trying to copy to clipboard!" collapsed=""><p class="meta"><span class="language">js</span></p><pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#A6E22E">defineComponent</span><span style="color:#F8F8F2">(</span></span>
251
+ <span class="line"><span style="color:#E6DB74"> 'my-component'</span><span style="color:#F8F8F2">,</span></span>
252
+ <span class="line"><span style="color:#F8F8F2"> {},</span></span>
253
+ <span class="line"><span style="color:#F8F8F2"> ({ </span><span style="color:#FD971F;font-style:italic">first</span><span style="color:#F8F8F2"> }) </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> ({</span></span>
254
+ <span class="line"><span style="color:#F8F8F2"> increment: </span><span style="color:#A6E22E">first</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'button.increment'</span><span style="color:#F8F8F2">),</span></span>
255
+ <span class="line"><span style="color:#F8F8F2"> count: </span><span style="color:#A6E22E">first</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'.count'</span><span style="color:#F8F8F2">),</span></span>
256
+ <span class="line"><span style="color:#F8F8F2"> double: </span><span style="color:#A6E22E">first</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'.double'</span><span style="color:#F8F8F2">)</span></span>
257
+ <span class="line"><span style="color:#F8F8F2"> }),</span></span>
258
+ <span class="line"><span style="color:#F8F8F2"> () </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> {</span></span>
259
+ <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> count </span><span style="color:#F92672">=</span><span style="color:#A6E22E"> createState</span><span style="color:#F8F8F2">(</span><span style="color:#AE81FF">0</span><span style="color:#F8F8F2">)</span></span>
260
+ <span class="line"><span style="color:#66D9EF;font-style:italic"> const</span><span style="color:#F8F8F2"> double </span><span style="color:#F92672">=</span><span style="color:#A6E22E"> createComputed</span><span style="color:#F8F8F2">(() </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> count.</span><span style="color:#A6E22E">get</span><span style="color:#F8F8F2">() </span><span style="color:#F92672">*</span><span style="color:#AE81FF"> 2</span><span style="color:#F8F8F2">)</span></span>
261
+ <span class="line"><span style="color:#F92672"> return</span><span style="color:#F8F8F2"> {</span></span>
262
+ <span class="line"><span style="color:#F8F8F2"> increment: </span><span style="color:#A6E22E">on</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'click'</span><span style="color:#F8F8F2">, () </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> {</span></span>
263
+ <span class="line"><span style="color:#F8F8F2"> count.</span><span style="color:#A6E22E">update</span><span style="color:#F8F8F2">(</span><span style="color:#FD971F;font-style:italic">v</span><span style="color:#66D9EF;font-style:italic"> =></span><span style="color:#F92672"> ++</span><span style="color:#F8F8F2">v)</span></span>
264
+ <span class="line"><span style="color:#F8F8F2"> }),</span></span>
265
+ <span class="line"><span style="color:#F8F8F2"> count: </span><span style="color:#A6E22E">setText</span><span style="color:#F8F8F2">(count),</span></span>
266
+ <span class="line"><span style="color:#F8F8F2"> double: </span><span style="color:#A6E22E">setText</span><span style="color:#F8F8F2">(double),</span></span>
267
+ <span class="line"><span style="color:#F8F8F2"> }</span></span>
268
+ <span class="line"><span style="color:#F8F8F2"> }</span></span>
269
+ <span class="line"><span style="color:#F8F8F2">)</span></span>
270
+ <span class="line"></span></code></pre><basic-button class="copy" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><button type="button" class="secondary small"><span class="label">Copy</span></button></basic-button><button type="button" class="overlay" aria-expanded="false">Expand</button></module-codeblock><p>Outside components cannot access the <code>count</code> or <code>double</code> signals.</p><h3 id="using-functions-for-ad-hoc-derived-state"><a name="using-functions-for-ad-hoc-derived-state" class="anchor" href="#using-functions-for-ad-hoc-derived-state"><span class="permalink">🔗</span><span class="title">Using Functions for Ad-hoc Derived State</span></a></h3><p>Instead of a signal key or a local signal, you can <strong>pass a function</strong> that derives a value dynamically:</p><module-codeblock language="js" copy-success="Copied!" copy-error="Error trying to copy to clipboard!" collapsed=""><p class="meta"><span class="language">js</span></p><pre class="shiki monokai" style="background-color:#272822;color:#F8F8F2" tabindex="0"><code><span class="line"><span style="color:#A6E22E">defineComponent</span><span style="color:#F8F8F2">(</span></span>
271
+ <span class="line"><span style="color:#E6DB74"> 'my-component'</span><span style="color:#F8F8F2">,</span></span>
272
+ <span class="line"><span style="color:#F8F8F2"> {</span></span>
273
+ <span class="line"><span style="color:#F8F8F2"> count: </span><span style="color:#AE81FF">0</span><span style="color:#F8F8F2">,</span></span>
274
+ <span class="line"><span style="color:#F8F8F2"> },</span></span>
275
+ <span class="line"><span style="color:#F8F8F2"> ({ </span><span style="color:#FD971F;font-style:italic">first</span><span style="color:#F8F8F2"> }) </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> ({</span></span>
276
+ <span class="line"><span style="color:#F8F8F2"> count: </span><span style="color:#A6E22E">first</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'.count'</span><span style="color:#F8F8F2">),</span></span>
277
+ <span class="line"><span style="color:#F8F8F2"> double: </span><span style="color:#A6E22E">first</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'.double'</span><span style="color:#F8F8F2">)</span></span>
278
+ <span class="line"><span style="color:#F8F8F2"> }),</span></span>
279
+ <span class="line"><span style="color:#F8F8F2"> ({ </span><span style="color:#FD971F;font-style:italic">host</span><span style="color:#F8F8F2"> }) </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F8F8F2"> ({</span></span>
280
+ <span class="line"><span style="color:#F8F8F2"> count: </span><span style="color:#A6E22E">toggleClass</span><span style="color:#F8F8F2">(</span><span style="color:#E6DB74">'even'</span><span style="color:#F8F8F2">, () </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#F92672"> !</span><span style="color:#F8F8F2">(host.count </span><span style="color:#F92672">%</span><span style="color:#AE81FF"> 2</span><span style="color:#F8F8F2">)),</span></span>
281
+ <span class="line"><span style="color:#F8F8F2"> double: </span><span style="color:#A6E22E">setText</span><span style="color:#F8F8F2">(() </span><span style="color:#66D9EF;font-style:italic">=></span><span style="color:#A6E22E"> String</span><span style="color:#F8F8F2">(host.count </span><span style="color:#F92672">*</span><span style="color:#AE81FF"> 2</span><span style="color:#F8F8F2">))</span></span>
282
+ <span class="line"><span style="color:#F8F8F2"> })</span></span>
283
+ <span class="line"><span style="color:#F8F8F2">)</span></span>
284
+ <span class="line"></span></code></pre><basic-button class="copy" copy-success="Copied!" copy-error="Error trying to copy to clipboard!"><button type="button" class="secondary small"><span class="label">Copy</span></button></basic-button><button type="button" class="overlay" aria-expanded="false">Expand</button></module-codeblock><card-callout class="tip"><p><strong>When to use</strong></p><ul><li><strong>Use a signal key or a local signal</strong> when the state is part of the component's public interface or internally reused.</li><li><strong>Use a function</strong> to <strong>derive a value on the fly</strong> when it is needed only in this one place.</li></ul><p>Ad-hoc derived state is more efficient than the overhead of a memoized computed signal for simple functions like converting to a string or boolean, formatting a value or performing a calculation.</p></card-callout><h3 id="efficient-fine-grained-updates"><a name="efficient-fine-grained-updates" class="anchor" href="#efficient-fine-grained-updates"><span class="permalink">🔗</span><span class="title">Efficient &amp; Fine-Grained Updates</span></a></h3><p>Unlike some frameworks that <strong>re-render entire components</strong>, Le Truc updates only what changes:</p><ul><li><strong>No virtual DOM</strong> – Le Truc modifies the DOM directly.</li><li><strong>Signals propagate automatically</strong> – no need to track dependencies manually.</li><li><strong>Optimized with a scheduler</strong> – multiple updates are batched efficiently.</li></ul></section></main>
285
+ <footer class="content-grid">
286
+ <div class="content">
287
+ <h2 class="visually-hidden">Footer</h2>
288
+ <p>© 2024 – 2025 Zeix AG</p>
289
+ </div>
290
+ </footer>
291
+ </context-router>
292
+ </body>
293
+ </html>