@madojs/mado 0.11.1 → 0.13.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 (298) hide show
  1. package/AGENTS.md +116 -32
  2. package/CHANGELOG.md +216 -1
  3. package/README.md +158 -173
  4. package/dist/src/component.d.ts +6 -3
  5. package/dist/src/component.d.ts.map +1 -0
  6. package/dist/src/component.js +163 -36
  7. package/dist/src/component.js.map +1 -1
  8. package/dist/src/context.d.ts +13 -32
  9. package/dist/src/context.d.ts.map +1 -0
  10. package/dist/src/context.js +73 -48
  11. package/dist/src/context.js.map +1 -1
  12. package/dist/src/css.d.ts +1 -0
  13. package/dist/src/css.d.ts.map +1 -0
  14. package/dist/src/css.js +34 -5
  15. package/dist/src/css.js.map +1 -1
  16. package/dist/src/devtools-hook.d.ts +14 -0
  17. package/dist/src/devtools-hook.d.ts.map +1 -0
  18. package/dist/src/devtools-hook.js +27 -0
  19. package/dist/src/devtools-hook.js.map +1 -0
  20. package/dist/src/devtools.d.ts +24 -22
  21. package/dist/src/devtools.d.ts.map +1 -0
  22. package/dist/src/devtools.js +230 -58
  23. package/dist/src/devtools.js.map +1 -1
  24. package/dist/src/diagnostics.d.ts +12 -0
  25. package/dist/src/diagnostics.d.ts.map +1 -0
  26. package/dist/src/diagnostics.js +68 -8
  27. package/dist/src/diagnostics.js.map +1 -1
  28. package/dist/src/each.d.ts +1 -5
  29. package/dist/src/each.d.ts.map +1 -0
  30. package/dist/src/each.js +0 -8
  31. package/dist/src/each.js.map +1 -1
  32. package/dist/src/forms.d.ts +27 -96
  33. package/dist/src/forms.d.ts.map +1 -0
  34. package/dist/src/forms.js +184 -394
  35. package/dist/src/forms.js.map +1 -1
  36. package/dist/src/head.d.ts +7 -6
  37. package/dist/src/head.d.ts.map +1 -0
  38. package/dist/src/head.js +8 -7
  39. package/dist/src/head.js.map +1 -1
  40. package/dist/src/html/bindings.d.ts +1 -0
  41. package/dist/src/html/bindings.d.ts.map +1 -0
  42. package/dist/src/html/bindings.js.map +1 -1
  43. package/dist/src/html/parser.d.ts +4 -5
  44. package/dist/src/html/parser.d.ts.map +1 -0
  45. package/dist/src/html/parser.js +64 -15
  46. package/dist/src/html/parser.js.map +1 -1
  47. package/dist/src/html/template-types.d.ts +1 -0
  48. package/dist/src/html/template-types.d.ts.map +1 -0
  49. package/dist/src/html/template-types.js.map +1 -1
  50. package/dist/src/html/template.d.ts +5 -1
  51. package/dist/src/html/template.d.ts.map +1 -0
  52. package/dist/src/html/template.js +102 -13
  53. package/dist/src/html/template.js.map +1 -1
  54. package/dist/src/index.d.ts +15 -12
  55. package/dist/src/index.d.ts.map +1 -0
  56. package/dist/src/index.js +18 -10
  57. package/dist/src/index.js.map +1 -1
  58. package/dist/src/json.d.ts +3 -0
  59. package/dist/src/json.d.ts.map +1 -0
  60. package/dist/src/json.js +14 -0
  61. package/dist/src/json.js.map +1 -0
  62. package/dist/src/lifecycle.d.ts +1 -0
  63. package/dist/src/lifecycle.d.ts.map +1 -0
  64. package/dist/src/lifecycle.js +3 -2
  65. package/dist/src/lifecycle.js.map +1 -1
  66. package/dist/src/page.d.ts +63 -28
  67. package/dist/src/page.d.ts.map +1 -0
  68. package/dist/src/page.js +5 -0
  69. package/dist/src/page.js.map +1 -1
  70. package/dist/src/persisted.d.ts +6 -1
  71. package/dist/src/persisted.d.ts.map +1 -0
  72. package/dist/src/persisted.js +17 -11
  73. package/dist/src/persisted.js.map +1 -1
  74. package/dist/src/resource.d.ts +2 -1
  75. package/dist/src/resource.d.ts.map +1 -0
  76. package/dist/src/resource.js +128 -50
  77. package/dist/src/resource.js.map +1 -1
  78. package/dist/src/router/base.d.ts +66 -0
  79. package/dist/src/router/base.d.ts.map +1 -0
  80. package/dist/src/router/base.js +168 -0
  81. package/dist/src/router/base.js.map +1 -0
  82. package/dist/src/router/manifest.d.ts +1 -0
  83. package/dist/src/router/manifest.d.ts.map +1 -0
  84. package/dist/src/router/manifest.js +156 -171
  85. package/dist/src/router/manifest.js.map +1 -1
  86. package/dist/src/router/match.d.ts +17 -2
  87. package/dist/src/router/match.d.ts.map +1 -0
  88. package/dist/src/router/match.js +60 -6
  89. package/dist/src/router/match.js.map +1 -1
  90. package/dist/src/router/navigation.d.ts +1 -0
  91. package/dist/src/router/navigation.d.ts.map +1 -0
  92. package/dist/src/router/navigation.js +58 -9
  93. package/dist/src/router/navigation.js.map +1 -1
  94. package/dist/src/signal.d.ts +1 -0
  95. package/dist/src/signal.d.ts.map +1 -0
  96. package/dist/src/signal.js +46 -17
  97. package/dist/src/signal.js.map +1 -1
  98. package/dist/src/static-runtime.d.ts +82 -0
  99. package/dist/src/static-runtime.d.ts.map +1 -0
  100. package/dist/src/static-runtime.js +209 -0
  101. package/dist/src/static-runtime.js.map +1 -0
  102. package/dist/src/vite/index.d.ts +32 -3
  103. package/dist/src/vite/index.d.ts.map +1 -0
  104. package/dist/src/vite/index.js +49 -17
  105. package/dist/src/vite/index.js.map +1 -1
  106. package/docs/README.md +5 -8
  107. package/docs/architecture/adr/0001-browser-static-snapshots.md +132 -0
  108. package/docs/architecture/v1-roadmap.md +19 -0
  109. package/docs/en/00-the-mado-way.md +1 -1
  110. package/docs/en/01-quickstart.md +183 -0
  111. package/docs/en/10-pages-and-components.md +279 -0
  112. package/docs/en/11-templates-and-signals.md +211 -0
  113. package/docs/en/12-routing.md +229 -0
  114. package/docs/en/13-data.md +227 -0
  115. package/docs/en/14-forms.md +91 -0
  116. package/docs/en/15-static-snapshots.md +181 -0
  117. package/docs/en/{10-app-architecture.md → 16-app-architecture.md} +56 -4
  118. package/docs/en/{13-deployment.md → 20-deployment.md} +79 -17
  119. package/docs/en/{15-error-handling.md → 21-error-handling.md} +9 -6
  120. package/docs/en/{14-testing.md → 22-testing.md} +6 -5
  121. package/docs/en/23-cookbook.md +292 -0
  122. package/docs/en/24-devtools-and-diagnostics.md +45 -0
  123. package/docs/en/{18-api-freeze-map.md → 30-api-freeze-map.md} +17 -9
  124. package/docs/en/{20-v1-stability.md → 32-v1-stability.md} +5 -5
  125. package/docs/en/33-migration-0.12-0.13.md +56 -0
  126. package/docs/en/40-llm-guide.md +774 -0
  127. package/docs/en/{06-for-backenders.md → 41-for-backenders.md} +28 -25
  128. package/docs/en/{05-why-mado.md → 42-why-mado.md} +3 -3
  129. package/docs/en/README.md +99 -27
  130. package/docs/recipes/nginx/Containerfile +26 -0
  131. package/docs/recipes/nginx/nginx.conf +42 -0
  132. package/llms.txt +263 -210
  133. package/package.json +51 -23
  134. package/scripts/clean.mjs +8 -0
  135. package/scripts/cli/generate.mjs +57 -10
  136. package/scripts/cli/help.mjs +13 -5
  137. package/scripts/cli/index.mjs +31 -7
  138. package/scripts/cli/init.mjs +19 -19
  139. package/scripts/cli/release.mjs +38 -83
  140. package/scripts/cli/run.mjs +5 -3
  141. package/scripts/logger.mjs +117 -0
  142. package/scripts/output-guard.mjs +128 -0
  143. package/scripts/preview.mjs +105 -24
  144. package/scripts/static/browser.mjs +695 -0
  145. package/scripts/static/discover.mjs +284 -0
  146. package/scripts/static/output.mjs +141 -0
  147. package/scripts/static/serialize.mjs +212 -0
  148. package/scripts/static/server.mjs +167 -0
  149. package/scripts/static.mjs +205 -0
  150. package/starters/default/README.md +57 -55
  151. package/starters/default/package.json +6 -12
  152. package/starters/default/src/app.routes.ts +20 -33
  153. package/starters/default/src/components/feature-card.component.ts +40 -0
  154. package/starters/default/src/components/live-counter.component.ts +57 -0
  155. package/starters/default/src/content/guides.ts +55 -0
  156. package/starters/default/src/main.ts +9 -13
  157. package/starters/default/src/pages/app.page.ts +41 -0
  158. package/starters/default/src/pages/guide.page.ts +40 -0
  159. package/starters/default/src/pages/home.page.ts +49 -0
  160. package/starters/default/src/pages/not-found.page.ts +18 -0
  161. package/starters/default/src/styles/document.css +39 -0
  162. package/starters/default/src/styles/reset.css +37 -0
  163. package/starters/default/src/styles/tokens.css +30 -0
  164. package/starters/default/src/styles.d.ts +3 -1
  165. package/starters/default/src/vite-env.d.ts +1 -1
  166. package/starters/default/tsconfig.node.json +13 -0
  167. package/starters/default/vite.config.ts +14 -4
  168. package/starters/modular/README.md +142 -0
  169. package/starters/modular/index.html +13 -0
  170. package/starters/modular/package.json +30 -0
  171. package/starters/modular/src/app.routes.ts +39 -0
  172. package/starters/{default → modular}/src/layouts/app-shell.layout.ts +9 -7
  173. package/starters/{default → modular}/src/layouts/auth-shell.layout.ts +3 -3
  174. package/starters/modular/src/main.ts +16 -0
  175. package/starters/{default → modular}/src/modules/auth/login.page.ts +5 -12
  176. package/starters/{default → modular}/src/modules/billing/pages/invoice-detail.page.ts +3 -4
  177. package/starters/{default → modular}/src/modules/billing/pages/invoices-list.page.ts +4 -4
  178. package/starters/{default → modular}/src/modules/home/home.page.ts +5 -7
  179. package/starters/modular/src/modules/home/not-found.page.ts +14 -0
  180. package/starters/{default → modular}/src/shared/styles/reset.css +21 -1
  181. package/starters/modular/src/styles.d.ts +1 -0
  182. package/starters/modular/src/vite-env.d.ts +1 -0
  183. package/starters/modular/tsconfig.json +33 -0
  184. package/starters/modular/tsconfig.node.json +13 -0
  185. package/starters/modular/vite.config.ts +132 -0
  186. package/TODO.md +0 -79
  187. package/dist/src/lazy.d.ts +0 -38
  188. package/dist/src/lazy.js +0 -73
  189. package/dist/src/lazy.js.map +0 -1
  190. package/docs/en/01-routing.md +0 -152
  191. package/docs/en/02-project-layout.md +0 -124
  192. package/docs/en/03-static-bake.md +0 -249
  193. package/docs/en/04-ide-setup.md +0 -162
  194. package/docs/en/07-llm-pitfalls.md +0 -724
  195. package/docs/en/08-llm-zero-history-test.md +0 -56
  196. package/docs/en/09-shadow-vs-light-dom.md +0 -174
  197. package/docs/en/11-layouts.md +0 -113
  198. package/docs/en/12-auth-and-api.md +0 -124
  199. package/docs/en/16-bake-cookbook.md +0 -100
  200. package/docs/en/17-shadow-dom-forms.md +0 -192
  201. package/docs/fr/00-the-mado-way.md +0 -85
  202. package/docs/fr/01-routing.md +0 -120
  203. package/docs/fr/02-project-layout.md +0 -84
  204. package/docs/fr/03-static-bake.md +0 -289
  205. package/docs/fr/04-ide-setup.md +0 -162
  206. package/docs/fr/05-why-mado.md +0 -193
  207. package/docs/fr/06-for-backenders.md +0 -438
  208. package/docs/fr/07-llm-pitfalls.md +0 -625
  209. package/docs/fr/08-llm-zero-history-test.md +0 -38
  210. package/docs/fr/09-shadow-vs-light-dom.md +0 -65
  211. package/docs/fr/10-app-architecture.md +0 -138
  212. package/docs/fr/11-layouts.md +0 -47
  213. package/docs/fr/12-auth-and-api.md +0 -76
  214. package/docs/fr/13-deployment.md +0 -57
  215. package/docs/fr/14-testing.md +0 -41
  216. package/docs/fr/15-error-handling.md +0 -50
  217. package/docs/fr/16-bake-cookbook.md +0 -88
  218. package/docs/fr/17-shadow-dom-forms.md +0 -196
  219. package/docs/fr/18-api-freeze-map.md +0 -63
  220. package/docs/fr/19-reactivity-ordering.md +0 -97
  221. package/docs/fr/20-v1-stability.md +0 -88
  222. package/docs/fr/README.md +0 -27
  223. package/docs/ru/00-the-mado-way.md +0 -84
  224. package/docs/ru/01-routing.md +0 -119
  225. package/docs/ru/02-project-layout.md +0 -84
  226. package/docs/ru/03-static-bake.md +0 -250
  227. package/docs/ru/04-ide-setup.md +0 -144
  228. package/docs/ru/05-why-mado.md +0 -193
  229. package/docs/ru/06-for-backenders.md +0 -428
  230. package/docs/ru/07-llm-pitfalls.md +0 -624
  231. package/docs/ru/08-llm-zero-history-test.md +0 -57
  232. package/docs/ru/09-shadow-vs-light-dom.md +0 -63
  233. package/docs/ru/10-app-architecture.md +0 -152
  234. package/docs/ru/11-layouts.md +0 -47
  235. package/docs/ru/12-auth-and-api.md +0 -75
  236. package/docs/ru/13-deployment.md +0 -66
  237. package/docs/ru/14-testing.md +0 -50
  238. package/docs/ru/15-error-handling.md +0 -56
  239. package/docs/ru/16-bake-cookbook.md +0 -95
  240. package/docs/ru/17-shadow-dom-forms.md +0 -193
  241. package/docs/ru/18-api-freeze-map.md +0 -64
  242. package/docs/ru/19-reactivity-ordering.md +0 -95
  243. package/docs/ru/20-v1-stability.md +0 -82
  244. package/docs/ru/README.md +0 -25
  245. package/docs/uk/00-the-mado-way.md +0 -82
  246. package/docs/uk/01-routing.md +0 -76
  247. package/docs/uk/02-project-layout.md +0 -73
  248. package/docs/uk/03-static-bake.md +0 -48
  249. package/docs/uk/04-ide-setup.md +0 -26
  250. package/docs/uk/05-why-mado.md +0 -34
  251. package/docs/uk/06-for-backenders.md +0 -55
  252. package/docs/uk/07-llm-pitfalls.md +0 -145
  253. package/docs/uk/08-llm-zero-history-test.md +0 -34
  254. package/docs/uk/09-shadow-vs-light-dom.md +0 -58
  255. package/docs/uk/10-app-architecture.md +0 -97
  256. package/docs/uk/11-layouts.md +0 -47
  257. package/docs/uk/12-auth-and-api.md +0 -70
  258. package/docs/uk/13-deployment.md +0 -40
  259. package/docs/uk/14-testing.md +0 -34
  260. package/docs/uk/15-error-handling.md +0 -32
  261. package/docs/uk/16-bake-cookbook.md +0 -36
  262. package/docs/uk/17-shadow-dom-forms.md +0 -193
  263. package/docs/uk/18-api-freeze-map.md +0 -61
  264. package/docs/uk/19-reactivity-ordering.md +0 -95
  265. package/docs/uk/20-v1-stability.md +0 -83
  266. package/docs/uk/README.md +0 -27
  267. package/scripts/bake.mjs +0 -570
  268. package/scripts/package-smoke.mjs +0 -77
  269. package/scripts/release-notes.mjs +0 -66
  270. package/scripts/size-budget.mjs +0 -91
  271. package/starters/default/src/modules/home/not-found.page.ts +0 -11
  272. package/starters/default/src/shared/ui/x-button.component.ts +0 -49
  273. /package/docs/en/{19-reactivity-ordering.md → 31-reactivity-ordering.md} +0 -0
  274. /package/starters/{default → modular}/.editorconfig +0 -0
  275. /package/starters/{default → modular}/eslint.config.mjs +0 -0
  276. /package/starters/{default → modular}/public/favicon.svg +0 -0
  277. /package/starters/{default → modular}/src/modules/auth/_contracts/auth-api.types.ts +0 -0
  278. /package/starters/{default → modular}/src/modules/auth/auth.connector.ts +0 -0
  279. /package/starters/{default → modular}/src/modules/auth/auth.guard.ts +0 -0
  280. /package/starters/{default → modular}/src/modules/auth/auth.public.ts +0 -0
  281. /package/starters/{default → modular}/src/modules/auth/auth.routes.ts +0 -0
  282. /package/starters/{default → modular}/src/modules/auth/auth.service.ts +0 -0
  283. /package/starters/{default → modular}/src/modules/auth/auth.types.ts +0 -0
  284. /package/starters/{default → modular}/src/modules/billing/_contracts/stripe.types.ts +0 -0
  285. /package/starters/{default → modular}/src/modules/billing/api/stripe.connector.ts +0 -0
  286. /package/starters/{default → modular}/src/modules/billing/billing.public.ts +0 -0
  287. /package/starters/{default → modular}/src/modules/billing/billing.routes.ts +0 -0
  288. /package/starters/{default → modular}/src/modules/billing/billing.types.ts +0 -0
  289. /package/starters/{default → modular}/src/modules/billing/components/invoice-status-badge.component.ts +0 -0
  290. /package/starters/{default → modular}/src/modules/billing/data/invoices.resource.ts +0 -0
  291. /package/starters/{default → modular}/src/shared/http/http-client.ts +0 -0
  292. /package/starters/{default → modular}/src/shared/http/http-error.ts +0 -0
  293. /package/starters/{default → modular}/src/shared/http/interceptors.ts +0 -0
  294. /package/starters/{default → modular}/src/shared/lib/format-date.ts +0 -0
  295. /package/starters/{default → modular}/src/shared/styles/content.css +0 -0
  296. /package/starters/{default → modular}/src/shared/styles/shell.css +0 -0
  297. /package/starters/{default → modular}/src/shared/styles/tokens.css +0 -0
  298. /package/starters/{default → modular}/src/shared/ui/x-spinner.component.ts +0 -0
package/dist/src/each.js CHANGED
@@ -18,18 +18,10 @@
18
18
  * Template usage:
19
19
  * html`<ul>${() => each(items(), t => t.id, t => html`<li>${t.text}</li>`)}</ul>`
20
20
  */
21
- import { html } from "./html/template.js";
22
21
  export const isEachResult = (v) => typeof v === "object" &&
23
22
  v !== null &&
24
23
  v._madoEach === true;
25
24
  export function each(items, keyOf, render) {
26
25
  return { _madoEach: true, items, keyOf, render };
27
26
  }
28
- /**
29
- * Sugar: returns a ready TemplateResult with the given list as children.
30
- * Convenient when you need a list without a wrapping parent.
31
- */
32
- export function list(items, keyOf, render) {
33
- return html `${each(items, keyOf, render)}`;
34
- }
35
27
  //# sourceMappingURL=each.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"each.js","sourceRoot":"","sources":["../../src/each.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAgB1C,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAU,EAAmB,EAAE,CAC1D,OAAO,CAAC,KAAK,QAAQ;IACrB,CAAC,KAAK,IAAI;IACT,CAAgB,CAAC,SAAS,KAAK,IAAI,CAAC;AAEvC,MAAM,UAAU,IAAI,CAClB,KAAmB,EACnB,KAA0C,EAC1C,MAAkD;IAElD,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AACnD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,IAAI,CAClB,KAAmB,EACnB,KAA0C,EAC1C,MAAkD;IAElD,OAAO,IAAI,CAAA,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC;AAC7C,CAAC"}
1
+ {"version":3,"file":"each.js","sourceRoot":"","sources":["../../src/each.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAiBH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAU,EAAmB,EAAE,CAC1D,OAAO,CAAC,KAAK,QAAQ;IACrB,CAAC,KAAK,IAAI;IACT,CAAgB,CAAC,SAAS,KAAK,IAAI,CAAC;AAEvC,MAAM,UAAU,IAAI,CAClB,KAAmB,EACnB,KAA0C,EAC1C,MAAkD;IAElD,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AACnD,CAAC","sourcesContent":["/**\n * Keyed list rendering.\n *\n * each() returns a special EachResult descriptor. The html binder recognizes\n * it by the `_madoEach` flag and applies keyed reconciliation: on every\n * update it reuses DOM nodes for the same keys and moves them with\n * insertBefore instead of recreating everything.\n *\n * Key differences from a naive implementation:\n * - state lives in the parent's ChildState, not globally by renderFn, so two\n * each() calls with the same render function do not interfere;\n * - DOM nodes are actually reused, so input focus, animations,\n * IntersectionObserver state and .scrollTop survive reorder.\n *\n * API:\n * each(items, item => item.id, item => html`<li>${item.name}</li>`)\n *\n * Template usage:\n * html`<ul>${() => each(items(), t => t.id, t => html`<li>${t.text}</li>`)}</ul>`\n */\n\nimport type { TemplateResult } from \"./html/template-types.js\";\n\nexport type EachKey = string | number;\n\n/**\n * Marker recognised by the html binder.\n * Do not set `_madoEach` yourself — use each().\n */\nexport interface EachResult<T = unknown> {\n readonly _madoEach: true;\n readonly items: readonly T[];\n readonly keyOf: (item: T, index: number) => EachKey;\n readonly render: (item: T, index: number) => TemplateResult;\n}\n\nexport const isEachResult = (v: unknown): v is EachResult =>\n typeof v === \"object\" &&\n v !== null &&\n (v as EachResult)._madoEach === true;\n\nexport function each<T>(\n items: readonly T[],\n keyOf: (item: T, index: number) => EachKey,\n render: (item: T, index: number) => TemplateResult,\n): EachResult<T> {\n return { _madoEach: true, items, keyOf, render };\n}\n"]}
@@ -1,105 +1,36 @@
1
1
  /**
2
- * Forms without pain. Built on native `<form>` submit/input events plus a
3
- * small schema validator whose rules mirror common HTML constraints.
4
- *
5
- * const f = useForm({
6
- * email: { required: true, type: 'email' },
7
- * age: { min: 18 },
8
- * });
9
- *
10
- * html`
11
- * <form @submit=${f.onSubmit(async values => { await save(values) })}>
12
- * <input name="email" .value=${() => f.values().email ?? ''}
13
- * @input=${f.onInput} />
14
- * ${() => f.errors().email ? html`<err>${f.errors().email}</err>` : null}
15
- *
16
- * <input name="age" type="number" .value=${() => f.values().age ?? ''}
17
- * @input=${f.onInput} />
18
- *
19
- * <button ?disabled=${() => !f.isValid() || f.submitting()}>Save</button>
20
- * </form>
21
- * `;
22
- *
23
- * What's inside:
24
- * - validation rules mirror common HTML constraints
25
- * (required, min, max, pattern, type=email/url/number, etc.);
26
- * - custom rules via a validate(values) function returning
27
- * { field: 'msg' } or null;
28
- * - all fields are automatically "touched" on blur — errors
29
- * are shown only after user interaction;
30
- * - submit() is aborted if the form is invalid.
31
- *
32
- * No Yup/Zod/Formik dependencies. If you really want them —
33
- * pass your own validate(values) and wire it to anything.
2
+ * Typed form state over the browser's native form and constraint-validation
3
+ * model. HTML owns required/type/min/max/pattern; Mado owns reactive state,
4
+ * touched/dirty flags, async validation cancellation and submit state.
34
5
  */
35
- import { type Signal, type Computed } from "./signal.js";
36
- export type FormValue = string | number | boolean | null | undefined | FormValue[] | {
37
- [key: string]: FormValue;
38
- };
39
- export type FormValues = Record<string, FormValue>;
40
- export type FormErrors = Record<string, string | undefined>;
41
- export type FieldValidator<V extends FormValues = FormValues> = (value: FormValue, values: V, path: string) => string | null | undefined;
42
- export type AsyncFieldValidator<V extends FormValues = FormValues> = (value: FormValue, values: V, path: string) => Promise<string | null | undefined>;
43
- /** Field declaration. Rules intentionally match common HTML constraints. */
44
- export interface FieldSchema {
45
- required?: boolean;
46
- type?: "text" | "email" | "url" | "number" | "tel" | "password";
47
- min?: number;
48
- max?: number;
49
- minLength?: number;
50
- maxLength?: number;
51
- pattern?: string;
52
- /** Default value */
53
- default?: FormValue;
54
- /** Synchronous custom validator for this field. */
55
- validate?: FieldValidator;
56
- /** Asynchronous custom validator for this field. */
57
- validateAsync?: AsyncFieldValidator;
6
+ import { type Computed, type Signal } from "./signal.js";
7
+ export type FormValue = unknown;
8
+ export type FormValues = Record<string, unknown>;
9
+ export type FormErrors<V extends FormValues = FormValues> = Partial<Record<string, string>>;
10
+ export type FormTouched<V extends FormValues = FormValues> = Partial<Record<string, boolean>>;
11
+ export interface FormValidationContext {
12
+ signal: AbortSignal;
13
+ form: HTMLFormElement | null;
58
14
  }
59
- export type Schema = Record<string, FieldSchema>;
15
+ export type FormValidator<V extends FormValues> = (values: Readonly<V>, context: FormValidationContext) => FormErrors<V> | null | Promise<FormErrors<V> | null>;
60
16
  export interface UseFormOptions<V extends FormValues> {
61
- /** Custom validator: returns errors or null. */
62
- validate?: (values: V) => FormErrors | null;
63
- /** Async custom validator, usually for server-backed uniqueness checks. */
64
- validateAsync?: (values: V) => Promise<FormErrors | null>;
65
- }
66
- export interface FieldArrayApi<T extends FormValue = FormValue> {
67
- /** Current array value. */
68
- items: () => T[];
69
- /** Field name helper: `items.0.title`. */
70
- path(index: number, field?: string): string;
71
- append(value: T): void;
72
- prepend(value: T): void;
73
- insert(index: number, value: T): void;
74
- remove(index: number): void;
75
- move(from: number, to: number): void;
76
- replace(items: readonly T[]): void;
77
- set(index: number, value: T): void;
17
+ initial: V;
18
+ validate?: FormValidator<V>;
78
19
  }
79
20
  export interface FormApi<V extends FormValues> {
80
21
  values: Signal<V>;
81
- errors: () => FormErrors;
82
- touched: Signal<Record<string, boolean>>;
22
+ errors: Computed<FormErrors<V>>;
23
+ touched: Signal<FormTouched<V>>;
24
+ dirty: Computed<boolean>;
83
25
  submitting: Signal<boolean>;
84
- validating: Computed<boolean>;
85
- validatingFields: Signal<Record<string, boolean>>;
86
- isValid: () => boolean;
87
- /** Binding for @input/@change: automatically picks up name+value+type. */
88
- onInput: (e: Event) => void;
89
- /** Binding for @blur: marks the field as touched. */
90
- onBlur: (e: Event) => void;
91
- /** Submit wrapper: calls handler only if the form is valid. */
92
- onSubmit: (handler: (values: V) => void | Promise<void>) => (e: Event) => void;
93
- /** Set a field value programmatically. */
94
- setField<K extends keyof V & string>(name: K, value: V[K]): void;
95
- setField(name: string, value: FormValue): void;
96
- /** Run async validators for a single field path. */
97
- validateField(name: string): Promise<boolean>;
98
- /** Run all sync + async validators and update errors. */
99
- validate(): Promise<boolean>;
100
- /** Helper for dynamic arrays stored under one form field. */
101
- array<T extends FormValue = FormValue>(name: keyof V & string): FieldArrayApi<T>;
102
- /** Reset to defaults. */
103
- reset(): void;
26
+ validating: Signal<boolean>;
27
+ isValid: Computed<boolean>;
28
+ onInput(event: Event): void;
29
+ onBlur(event: Event): void;
30
+ onSubmit(handler: (values: Readonly<V>, event: SubmitEvent) => void | Promise<void>): (event: SubmitEvent) => void;
31
+ setField<K extends Extract<keyof V, string>>(name: K, value: V[K]): void;
32
+ reset(nextInitial?: V): void;
33
+ validate(form?: HTMLFormElement | null): Promise<boolean>;
104
34
  }
105
- export declare function useForm<V extends FormValues>(schema: Schema, options?: UseFormOptions<V>): FormApi<V>;
35
+ export declare function useForm<V extends FormValues>(options: UseFormOptions<V>): FormApi<V>;
36
+ //# sourceMappingURL=forms.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forms.d.ts","sourceRoot":"","sources":["../../src/forms.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAoB,KAAK,QAAQ,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAG3E,MAAM,MAAM,SAAS,GAAG,OAAO,CAAC;AAChC,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AACjD,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,IAAI,OAAO,CACjE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CACvB,CAAC;AACF,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,IAAI,OAAO,CAClE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CACxB,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,eAAe,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,UAAU,IAAI,CAChD,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,EACnB,OAAO,EAAE,qBAAqB,KAC3B,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AAE1D,MAAM,WAAW,cAAc,CAAC,CAAC,SAAS,UAAU;IAClD,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,OAAO,CAAC,CAAC,SAAS,UAAU;IAC3C,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IAClB,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAChC,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5B,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3B,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAC5B,MAAM,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAC3B,QAAQ,CACN,OAAO,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GACzE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IAChC,QAAQ,CAAC,CAAC,SAAS,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IACzE,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,eAAe,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3D;AAID,wBAAgB,OAAO,CAAC,CAAC,SAAS,UAAU,EAC1C,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,GACzB,OAAO,CAAC,CAAC,CAAC,CAuJZ"}