@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,98 @@
1
+ ---
2
+ title: 'Introduction'
3
+ emoji: '📖'
4
+ description: 'Overview and key benefits of Le Truc'
5
+ ---
6
+
7
+ {% hero %}
8
+
9
+ # 📖 Introduction
10
+
11
+ **Web development doesn't need to be complicated**. Le Truc lets you create reactive Web Components that enhance your existing HTML.
12
+ {% /hero %}
13
+
14
+ {% section class="breakout" %}
15
+
16
+ ## What is Le Truc?
17
+
18
+ {% carousel %}
19
+
20
+ {% slide title="We Can Have Nice Things!" style="background: var(--color-purple-20);" %}
21
+ - Embrace the Web Platform
22
+ - Use any server-side technology to render HTML
23
+ - Have components
24
+ - Have reactivity
25
+ - Have type safety
26
+ - Have optimal performance
27
+ - Have fun!
28
+ {% /slide %}
29
+
30
+ {% slide title="HTML First." style="background: var(--color-pink-20);" %}
31
+ Le Truc assumes you start with semantic HTML and want to enhance it with behavior:
32
+
33
+ ```html
34
+ <hello-world>
35
+ <p>Hello, <span>Alice</span>!</p>
36
+ </hello-world>
37
+ ```
38
+
39
+ This means better SEO, faster initial page loads, and progressive enhancement that works even when JavaScript fails.
40
+ {% /slide %}
41
+
42
+ {% slide title="Add JavaScript." style="background: var(--color-orange-20);" %}
43
+ Progressively enhance the user experience by adding interactivity:
44
+
45
+ ```js
46
+ import { asString, defineComponent, setText } from '@zeix/le-truc'
47
+
48
+ defineComponent(
49
+ 'hello-world',
50
+ { name: asString() },
51
+ q => ({ span: q.first('span') }),
52
+ () => ({ span: setText('name') }),
53
+ ])
54
+ ```
55
+
56
+ Le Truc augments what the platform already provides. It leverages the Web Components standard while adding just enough convenience functions to make reactive UI behaviors easy to implement.
57
+ {% /slide %}
58
+
59
+ {% slide title="Faster. Because We Do Less." style="background: var(--color-green-20);" %}
60
+ - Unlike SPA frameworks (React, Vue, Angular, Svelte, Lit, etc.) we **never render** on the client. Instead, the server and browser do this work. Like it's 1995.
61
+ - Because we never render on the client, we need no JSON data and no JS templates either. This means less data over the wire and no plumbing DB → JSON → JS → HTML.
62
+ - Unlike Hypermedia frameworks (HTMX, Datastar) we don't compensate for the lack of client-side rendering by a network request if not needed. If possible, we calculate the new state on the client.
63
+ - We just add event listeners and set up a signal graph. Invisible work that doesn't cause layout shifts.
64
+ - When the user interacts with the UI, we know exactly what to do. We just do fine-grained updates to the DOM. No VDOM, no diffing. Wait for signal 🚦 and go! 🏁
65
+ {% /slide %}
66
+
67
+ {% slide title="Minimal Size." style="background: var(--color-blue-20);" %}
68
+ Because we add less abstractions, we can keep the library small (approximately 8kB gzipped).
69
+
70
+ Le Truc is a lightweight library that provides a simple and efficient way to build reactive user interfaces. It is designed to be easy to use and understand, while still providing powerful features for building complex applications.
71
+
72
+ HTML ain't broken. CSS ain't broken. JavaScript ain't broken. We just want to split it in chunks (components), detect bugs early (type safety), and have predictable updates without tight coupling (reactivity). That's what we stand for.
73
+ {% /slide %}
74
+
75
+ {% /carousel %}
76
+
77
+ {% /section %}
78
+
79
+ {% section %}
80
+
81
+ ## Why Choose Le Truc?
82
+
83
+ Le Truc shines when you want:
84
+
85
+ - **Server-rendered content** with client-side enhancements
86
+ - **High performance** on all devices (no virtual DOM overhead)
87
+ - **Component reusability** without framework lock-in
88
+ - **Future-proof** code built on web standards
89
+ - **Easy integration** with existing codebases
90
+
91
+ **Key Benefits:**
92
+
93
+ - ~8kB gzipped with no dependencies
94
+ - TypeScript support with full type safety
95
+ - Works with any backend or build setup
96
+ - Progressive enhancement friendly
97
+
98
+ {% /section %}
@@ -0,0 +1,165 @@
1
+ ---
2
+ title: 'Styling'
3
+ emoji: '🎨'
4
+ description: 'Scoped styles, CSS custom properties'
5
+ ---
6
+
7
+ {% hero %}
8
+ # 🎨 Styling
9
+
10
+ **Keep your components' styles self-contained while supporting shared design tokens.** Le Truc offers a refreshingly simple approach to create reactive Web Components that enhance your existing HTML.
11
+ {% /hero %}
12
+
13
+ {% section %}
14
+ ## Design Principles
15
+
16
+ Le Truc is focused on **state management and reactivity**, not styling. However, to **ensure consistent, maintainable, and reusable styles**, we recommend techniques that **scope component styles properly while allowing shared design tokens** (e.g., spacing, font sizes, colors, layout grids).
17
+
18
+ - **Each component brings along its own specific styles.**
19
+ - Component styles should be **scoped or encapsulated** so they don't leak out.
20
+ - **Allow customizations** via CSS custom properties or pre-defined classes.
21
+
22
+ Parent components may apply styles to the wrapper element of known sub-components for layout purposes. But avoid styling inner elements of sub-components directly. This would tightly couple the styles of the outer and inner components.
23
+
24
+ {% /section %}
25
+
26
+ {% section %}
27
+ ## Scope Styles to Custom Element
28
+
29
+ Use the **custom element name** to scope component styles if **you control the page and the components within**. This protects against component styles leaking out, while still allowing to use the CSS cascade. No need for Shadow DOM, no duplicate style rules.
30
+
31
+ ```css
32
+ my-component {
33
+ & button {
34
+ /* Button style rules */
35
+ }
36
+
37
+ /* More selectors for inner elements */
38
+ }
39
+ ```
40
+
41
+ ### Advantages of Custom Element Names
42
+
43
+ - By definition **unique within the document** with a descriptive name.
44
+ - **Low specificity**, making it easy to override when you need to with a single class.
45
+
46
+ {% callout class="tip" %}
47
+ **When to use**
48
+
49
+ **Best when** you control the page and need styles to cascade naturally.
50
+ **Avoid if** you expect style clashes from third-party styles.
51
+ {% /callout %}
52
+
53
+ {% /section %}
54
+
55
+ {% section %}
56
+ ## Encapsulate Styles with Shadow DOM
57
+
58
+ Use **Shadow DOM** to encapsulate styles if your component is going to be used in a pages **where you don't control the styles**. This way you make sure page styles don't leak in and component styles don't leak out.
59
+
60
+ ```html
61
+ <my-component>
62
+ <template shadowrootmode="open">
63
+ <style>
64
+ button {
65
+ /* Button style rules */
66
+ }
67
+
68
+ /* More selectors for inner elements */
69
+ </style>
70
+ <!-- Inner elements -->
71
+ </template>
72
+ </my-component>
73
+ ```
74
+
75
+ {% callout class="tip" %}
76
+ **When to use**
77
+
78
+ **Best when** your component is used in environments where you don’t control styles.
79
+ **Avoid if** you need global styles to apply inside the component.
80
+ {% /callout %}
81
+
82
+ {% /section %}
83
+
84
+ {% section %}
85
+ ## Shared Design Tokens with CSS Custom Properties
86
+
87
+ Web Components can't inherit global styles inside **Shadow DOM**, but CSS custom properties allow components to remain **flexible and themeable**.
88
+
89
+ ### Defining Design Tokens
90
+
91
+ Set global tokens in a stylesheet:
92
+
93
+ ```css
94
+ :root {
95
+ --button-bg: #007bff;
96
+ --button-text: #fff;
97
+ --spacing: 1rem;
98
+ }
99
+ ```
100
+
101
+ ### Using Tokens in a Component
102
+
103
+ ```css
104
+ my-component {
105
+ padding: var(--spacing);
106
+
107
+ & button {
108
+ background: var(--button-bg);
109
+ color: var(--button-text);
110
+ }
111
+ }
112
+ ```
113
+
114
+ ### Advantages of CSS Custom Properties
115
+
116
+ - **Supports theming** – users can override styles globally.
117
+ - **Works inside Shadow DOM** – unlike normal CSS, custom properties are inherited inside the shadow tree.
118
+ {% /section %}
119
+
120
+ {% section %}
121
+ ## Defined Variants with Classes
122
+
123
+ Use **classes** if your components can appear in a **limited set of specific manifestations**. For example, buttons could come in certain sizes and have primary, secondary and tertiary variants.
124
+
125
+ ```css
126
+ my-button {
127
+ /* Style rules for default (medium-sized, secondary) buttons */
128
+
129
+ &.small {
130
+ /* Style rules for small buttons */
131
+ }
132
+
133
+ &.large {
134
+ /* Style rules for large buttons */
135
+ }
136
+
137
+ &.primary {
138
+ /* Style rules for primary buttons */
139
+ }
140
+
141
+ &.tertiary {
142
+ /* Style rules for tertiary buttons */
143
+ }
144
+ }
145
+ ```
146
+ {% /section %}
147
+
148
+ {% section %}
149
+ ## CSS-only Components
150
+
151
+ Just because Le Truc is a JavaScript library doesn't mean you have to use JavaScript in every component. It's perfectly fine to use custom elements just for styling purposes.
152
+
153
+ Here's the example of the `<card-callout>` we're using in this documentation:
154
+
155
+ {% demo %}
156
+ <card-callout>This is an informational message.</card-callout>
157
+ <card-callout class="tip">Remember to hydrate while coding!</card-callout>
158
+ <card-callout class="caution">Be careful with this operation.</card-callout>
159
+ <card-callout class="danger">This action is irreversible!</card-callout>
160
+ <card-callout class="note">This is just a side note.</card-callout>
161
+ ---
162
+ {% source title="Source code" src="./examples/card-callout.html" /%}
163
+ {% /demo %}
164
+
165
+ {% /section %}
@@ -0,0 +1,64 @@
1
+ import pluginJs from '@eslint/js'
2
+ import globals from 'globals'
3
+ import tseslint from 'typescript-eslint'
4
+
5
+ /** @type {import('eslint').Linter.Config[]} */
6
+ export default [
7
+ // Global ignores to prevent warnings about these files
8
+ {
9
+ ignores: [
10
+ 'index.js',
11
+ 'index.dev.js',
12
+ 'types/**/*.d.ts',
13
+ 'docs/assets/**/*.js',
14
+ '**/*.min.js',
15
+ ],
16
+ },
17
+ // Base configuration for all files
18
+ {
19
+ files: [
20
+ 'index.ts',
21
+ 'index.dev.ts',
22
+ 'src/**/*.{js,mjs,cjs,ts}',
23
+ 'docs-src/**/*.{js,mjs,cjs,ts}',
24
+ ],
25
+ languageOptions: { globals: globals.browser },
26
+ ...pluginJs.configs.recommended,
27
+ },
28
+ // TypeScript configuration
29
+ ...tseslint.configs.recommended.map(config => ({
30
+ ...config,
31
+ files: [
32
+ 'index.ts',
33
+ 'index.dev.ts',
34
+ 'src/**/*.{js,mjs,cjs,ts}',
35
+ 'docs-src/**/*.{js,mjs,cjs,ts}',
36
+ ],
37
+ })),
38
+ // Custom rule overrides for all files
39
+ {
40
+ files: [
41
+ 'index.ts',
42
+ 'index.dev.ts',
43
+ 'src/**/*.{js,mjs,cjs,ts}',
44
+ 'docs-src/**/*.{js,mjs,cjs,ts}',
45
+ ],
46
+ rules: {
47
+ // we know what we're doing ;-)
48
+ '@typescript-eslint/no-empty-object-type': 'off',
49
+ '@typescript-eslint/no-explicit-any': 'off',
50
+ '@typescript-eslint/no-unused-vars': [
51
+ 'error',
52
+ {
53
+ args: 'all',
54
+ argsIgnorePattern: '^_',
55
+ caughtErrors: 'all',
56
+ caughtErrorsIgnorePattern: '^_',
57
+ destructuredArrayIgnorePattern: '^_',
58
+ varsIgnorePattern: '^_',
59
+ ignoreRestSiblings: true,
60
+ },
61
+ ],
62
+ },
63
+ },
64
+ ]
@@ -0,0 +1,49 @@
1
+ import { type Component, ComponentUI, type Effect, on, show, UI } from '../..'
2
+
3
+ /**
4
+ * Creates a clear method for input components
5
+ *
6
+ * @param {HTMLInputElement | HTMLTextAreaElement} selector - The native input or textarea element
7
+ */
8
+ export const clearMethod = <
9
+ P extends {
10
+ clear: () => void
11
+ value: string | number
12
+ readonly length: number
13
+ },
14
+ U extends {
15
+ host: Component<P>
16
+ textbox: HTMLInputElement | HTMLTextAreaElement
17
+ },
18
+ >({
19
+ host,
20
+ textbox,
21
+ }: ComponentUI<P, U>) => {
22
+ host.clear = () => {
23
+ host.value = ''
24
+ textbox.value = ''
25
+ textbox.setCustomValidity('')
26
+ textbox.checkValidity()
27
+ textbox.dispatchEvent(new Event('input', { bubbles: true }))
28
+ textbox.dispatchEvent(new Event('change', { bubbles: true }))
29
+ textbox.focus()
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Standard effects for clearing input components on button elements
35
+ *
36
+ * @param {ComponentUI<P, U>} ui - The component UI with a host that has clear, length properties
37
+ * @returns {Effect<P, HTMLElement>[]} - Effects for clearing the input component
38
+ */
39
+ export const clearEffects = <
40
+ P extends { clear: () => void; readonly length: number },
41
+ U extends UI,
42
+ >(
43
+ ui: ComponentUI<P, U>,
44
+ ): Effect<P, HTMLElement>[] => [
45
+ show(() => !!ui.host.length),
46
+ on('click', () => {
47
+ ui.host.clear()
48
+ }),
49
+ ]
@@ -0,0 +1,160 @@
1
+ /* === Types === */
2
+
3
+ type CacheEntry<T = unknown> = {
4
+ content: T
5
+ timestamp: number
6
+ etag?: string
7
+ lastModified?: string
8
+ maxAge?: number
9
+ }
10
+
11
+ /* === Internal Stuff === */
12
+
13
+ const cache = new Map<string, CacheEntry>()
14
+
15
+ const parseCacheControl = (
16
+ header: string,
17
+ ): { maxAge?: number; noCache: boolean; noStore: boolean } => {
18
+ const directives = header
19
+ .toLowerCase()
20
+ .split(',')
21
+ .map(d => d.trim())
22
+ const result = {
23
+ noCache: false,
24
+ noStore: false,
25
+ maxAge: undefined as number | undefined,
26
+ }
27
+
28
+ for (const directive of directives) {
29
+ if (directive === 'no-cache') result.noCache = true
30
+ else if (directive === 'no-store') result.noStore = true
31
+ else if (directive.startsWith('max-age=')) {
32
+ const value = parseInt(directive.substring(8), 10)
33
+ if (!isNaN(value)) result.maxAge = value
34
+ }
35
+ }
36
+
37
+ return result
38
+ }
39
+
40
+ const isCacheEntryValid = (entry: CacheEntry): boolean => {
41
+ if (entry.maxAge !== undefined) {
42
+ const age = (Date.now() - entry.timestamp) / 1000
43
+ return age < entry.maxAge
44
+ }
45
+ return true
46
+ }
47
+
48
+ /* === Exported Functions === */
49
+
50
+ /**
51
+ * Check if an URL is recursive
52
+ *
53
+ * @param {string} value - URL to check
54
+ * @param {HTMLElement} host - Host element
55
+ * @param {string} attr - Attribute name
56
+ * @returns {boolean} - True if the URL is recursive, false otherwise
57
+ */
58
+ export const isRecursiveURL = (
59
+ value: string,
60
+ host: HTMLElement,
61
+ attr: string = 'src',
62
+ ): boolean =>
63
+ !!value &&
64
+ !!(host.parentElement || (host.getRootNode() as ShadowRoot).host)?.closest(
65
+ `${host.localName}[${attr}="${value}"]`,
66
+ )
67
+
68
+ /**
69
+ * Check if an URL is valid
70
+ *
71
+ * @param {string} value - URL to check
72
+ * @returns {boolean} - True if the URL is valid, false otherwise
73
+ */
74
+ export const isValidURL = (value: string): boolean => {
75
+ if (!value) return false
76
+ try {
77
+ const url = new URL(value, location.href)
78
+ if (url.origin === location.origin) return true
79
+ } catch {
80
+ return false
81
+ }
82
+ return false
83
+ }
84
+
85
+ /**
86
+ * Fetch with HTTP caching support
87
+ *
88
+ * @param url - URL to fetch
89
+ * @param signal - AbortSignal for cancellation
90
+ * @param parseResponse - Function to parse the response body (defaults to text)
91
+ * @returns Promise with parsed content and cache status
92
+ */
93
+ export const fetchWithCache = async <T = string>(
94
+ url: string,
95
+ signal?: AbortSignal,
96
+ parseResponse: (response: Response) => Promise<T> = (response: Response) =>
97
+ response.text() as Promise<T>,
98
+ ): Promise<{ content: T; fromCache: boolean }> => {
99
+ const cached = cache.get(url) as CacheEntry<T> | undefined
100
+ const headers: HeadersInit = {}
101
+
102
+ // Add conditional headers if we have cached data
103
+ if (cached?.etag) headers['If-None-Match'] = cached.etag
104
+ if (cached?.lastModified) headers['If-Modified-Since'] = cached.lastModified
105
+
106
+ const response = await fetch(url, { signal, headers })
107
+
108
+ // Handle 304 Not Modified
109
+ if (response.status === 304 && cached)
110
+ return { content: cached.content, fromCache: true }
111
+
112
+ if (!response.ok) throw new Error(`HTTP error: ${response.statusText}`)
113
+
114
+ const content = await parseResponse(response)
115
+ const cacheControl = response.headers.get('cache-control')
116
+ const etag = response.headers.get('etag')
117
+ const lastModified = response.headers.get('last-modified')
118
+
119
+ // Parse cache directives
120
+ const cacheDirectives = cacheControl
121
+ ? parseCacheControl(cacheControl)
122
+ : { noCache: false, noStore: false }
123
+
124
+ // Store in cache if allowed
125
+ if (!cacheDirectives.noStore) {
126
+ const entry: CacheEntry<T> = {
127
+ content,
128
+ timestamp: Date.now(),
129
+ etag: etag || undefined,
130
+ lastModified: lastModified || undefined,
131
+ maxAge: cacheDirectives.maxAge,
132
+ }
133
+
134
+ if (!cacheDirectives.noCache || isCacheEntryValid(entry))
135
+ cache.set(url, entry)
136
+ }
137
+
138
+ return { content, fromCache: false }
139
+ }
140
+
141
+ /**
142
+ * Clear the entire cache
143
+ */
144
+ export const clearCache = (): void => {
145
+ cache.clear()
146
+ }
147
+
148
+ /**
149
+ * Remove a specific URL from cache
150
+ */
151
+ export const removeCacheEntry = (url: string): boolean => {
152
+ return cache.delete(url)
153
+ }
154
+
155
+ /**
156
+ * Get cache size
157
+ */
158
+ export const getCacheSize = (): number => {
159
+ return cache.size
160
+ }
@@ -0,0 +1,45 @@
1
+ import { type Collection, on } from '../..'
2
+
3
+ /* === Constants === */
4
+
5
+ const ENTER_KEY = 'Enter'
6
+ const DECREMENT_KEYS = ['ArrowLeft', 'ArrowUp']
7
+ const INCREMENT_KEYS = ['ArrowRight', 'ArrowDown']
8
+ const FIRST_KEY = 'Home'
9
+ const LAST_KEY = 'End'
10
+ const HANDLED_KEYS = [...DECREMENT_KEYS, ...INCREMENT_KEYS, FIRST_KEY, LAST_KEY]
11
+
12
+ /* === Exported Functions === */
13
+
14
+ export const manageFocus = <E extends HTMLInputElement | HTMLButtonElement>(
15
+ collection: Collection<E>,
16
+ getSelectedIndex: (radios: Collection<E>) => number,
17
+ ) => {
18
+ let index = getSelectedIndex(collection)
19
+
20
+ return [
21
+ on('click', ({ target }) => {
22
+ if (!(target instanceof HTMLElement)) return
23
+ if (target && target.hasAttribute('value'))
24
+ index = collection.get().findIndex(item => item === target)
25
+ }),
26
+ on('keydown', e => {
27
+ const { key } = e
28
+ if (!HANDLED_KEYS.includes(key)) return
29
+ e.preventDefault()
30
+ e.stopPropagation()
31
+ if (key === FIRST_KEY) index = 0
32
+ else if (key === LAST_KEY) index = collection.length - 1
33
+ else
34
+ index =
35
+ (index +
36
+ (INCREMENT_KEYS.includes(key) ? 1 : -1) +
37
+ collection.length) %
38
+ collection.length
39
+ if (collection[index]) collection[index].focus()
40
+ }),
41
+ on('keyup', ({ key }) => {
42
+ if (key === ENTER_KEY && collection[index]) collection[index].click()
43
+ }),
44
+ ]
45
+ }
@@ -0,0 +1,5 @@
1
+ export const highlightMatch = (text: string, query: string): string => {
2
+ if (!query) return text
3
+ const regex = new RegExp(query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi')
4
+ return text.replace(regex, '<mark>$&</mark>')
5
+ }