@madojs/mado 0.11.1 → 0.12.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 (219) hide show
  1. package/AGENTS.md +102 -25
  2. package/CHANGELOG.md +158 -1
  3. package/README.md +135 -172
  4. package/dist/src/component.d.ts +3 -2
  5. package/dist/src/component.js +98 -6
  6. package/dist/src/component.js.map +1 -1
  7. package/dist/src/css.js +34 -5
  8. package/dist/src/css.js.map +1 -1
  9. package/dist/src/head.d.ts +6 -6
  10. package/dist/src/head.js +6 -6
  11. package/dist/src/html/parser.d.ts +1 -1
  12. package/dist/src/html/parser.js +1 -1
  13. package/dist/src/html/template.js +24 -10
  14. package/dist/src/html/template.js.map +1 -1
  15. package/dist/src/index.d.ts +8 -4
  16. package/dist/src/index.js +13 -3
  17. package/dist/src/index.js.map +1 -1
  18. package/dist/src/page.d.ts +62 -28
  19. package/dist/src/page.js +5 -0
  20. package/dist/src/page.js.map +1 -1
  21. package/dist/src/resource.js +2 -1
  22. package/dist/src/resource.js.map +1 -1
  23. package/dist/src/router/base.d.ts +65 -0
  24. package/dist/src/router/base.js +168 -0
  25. package/dist/src/router/base.js.map +1 -0
  26. package/dist/src/router/manifest.js +75 -31
  27. package/dist/src/router/manifest.js.map +1 -1
  28. package/dist/src/router/match.d.ts +16 -2
  29. package/dist/src/router/match.js +41 -1
  30. package/dist/src/router/match.js.map +1 -1
  31. package/dist/src/router/navigation.js +58 -9
  32. package/dist/src/router/navigation.js.map +1 -1
  33. package/dist/src/static-runtime.d.ts +81 -0
  34. package/dist/src/static-runtime.js +209 -0
  35. package/dist/src/static-runtime.js.map +1 -0
  36. package/dist/src/vite/index.d.ts +31 -3
  37. package/dist/src/vite/index.js +49 -18
  38. package/dist/src/vite/index.js.map +1 -1
  39. package/docs/README.md +5 -8
  40. package/docs/architecture/adr/0001-browser-static-snapshots.md +132 -0
  41. package/docs/en/00-the-mado-way.md +1 -1
  42. package/docs/en/01-quickstart.md +183 -0
  43. package/docs/en/10-pages-and-components.md +271 -0
  44. package/docs/en/11-templates-and-signals.md +211 -0
  45. package/docs/en/12-routing.md +229 -0
  46. package/docs/en/13-data.md +225 -0
  47. package/docs/en/14-forms.md +244 -0
  48. package/docs/en/15-static-snapshots.md +181 -0
  49. package/docs/en/{10-app-architecture.md → 16-app-architecture.md} +53 -2
  50. package/docs/en/{13-deployment.md → 20-deployment.md} +59 -10
  51. package/docs/en/{14-testing.md → 22-testing.md} +6 -5
  52. package/docs/en/23-cookbook.md +292 -0
  53. package/docs/en/{18-api-freeze-map.md → 30-api-freeze-map.md} +12 -3
  54. package/docs/en/{20-v1-stability.md → 32-v1-stability.md} +3 -3
  55. package/docs/en/40-llm-guide.md +776 -0
  56. package/docs/en/{06-for-backenders.md → 41-for-backenders.md} +15 -16
  57. package/docs/en/{05-why-mado.md → 42-why-mado.md} +1 -1
  58. package/docs/en/README.md +97 -27
  59. package/docs/recipes/nginx/Containerfile +26 -0
  60. package/docs/recipes/nginx/nginx.conf +42 -0
  61. package/llms.txt +246 -211
  62. package/package.json +17 -10
  63. package/scripts/bake.mjs +4 -569
  64. package/scripts/cli/generate.mjs +55 -5
  65. package/scripts/cli/help.mjs +11 -5
  66. package/scripts/cli/index.mjs +20 -4
  67. package/scripts/cli/init.mjs +7 -2
  68. package/scripts/cli/release.mjs +20 -68
  69. package/scripts/docs-lint.mjs +170 -0
  70. package/scripts/package-smoke.mjs +67 -9
  71. package/scripts/preview.mjs +95 -6
  72. package/scripts/size-budget.mjs +5 -1
  73. package/scripts/static/browser.mjs +654 -0
  74. package/scripts/static/discover.mjs +281 -0
  75. package/scripts/static/output.mjs +141 -0
  76. package/scripts/static/serialize.mjs +212 -0
  77. package/scripts/static/server.mjs +167 -0
  78. package/scripts/static.mjs +191 -0
  79. package/starters/default/README.md +57 -55
  80. package/starters/default/package.json +3 -9
  81. package/starters/default/src/app.routes.ts +20 -33
  82. package/starters/default/src/components/feature-card.component.ts +40 -0
  83. package/starters/default/src/components/live-counter.component.ts +57 -0
  84. package/starters/default/src/content/guides.ts +55 -0
  85. package/starters/default/src/main.ts +9 -13
  86. package/starters/default/src/pages/app.page.ts +41 -0
  87. package/starters/default/src/pages/guide.page.ts +40 -0
  88. package/starters/default/src/pages/home.page.ts +49 -0
  89. package/starters/default/src/pages/not-found.page.ts +18 -0
  90. package/starters/default/src/styles/document.css +39 -0
  91. package/starters/default/src/styles/reset.css +37 -0
  92. package/starters/default/src/styles/tokens.css +30 -0
  93. package/starters/default/src/styles.d.ts +3 -1
  94. package/starters/default/src/vite-env.d.ts +1 -1
  95. package/starters/default/vite.config.ts +14 -1
  96. package/starters/modular/README.md +142 -0
  97. package/starters/modular/index.html +13 -0
  98. package/starters/modular/package.json +30 -0
  99. package/starters/modular/src/app.routes.ts +39 -0
  100. package/starters/{default → modular}/src/layouts/app-shell.layout.ts +8 -5
  101. package/starters/{default → modular}/src/layouts/auth-shell.layout.ts +3 -3
  102. package/starters/modular/src/main.ts +16 -0
  103. package/starters/{default → modular}/src/modules/billing/pages/invoices-list.page.ts +3 -3
  104. package/starters/{default → modular}/src/modules/home/home.page.ts +5 -7
  105. package/starters/modular/src/modules/home/not-found.page.ts +14 -0
  106. package/starters/modular/src/styles.d.ts +1 -0
  107. package/starters/modular/src/vite-env.d.ts +1 -0
  108. package/starters/modular/tsconfig.json +24 -0
  109. package/starters/modular/vite.config.ts +131 -0
  110. package/TODO.md +0 -79
  111. package/docs/en/01-routing.md +0 -152
  112. package/docs/en/02-project-layout.md +0 -124
  113. package/docs/en/03-static-bake.md +0 -249
  114. package/docs/en/04-ide-setup.md +0 -162
  115. package/docs/en/07-llm-pitfalls.md +0 -724
  116. package/docs/en/08-llm-zero-history-test.md +0 -56
  117. package/docs/en/09-shadow-vs-light-dom.md +0 -174
  118. package/docs/en/11-layouts.md +0 -113
  119. package/docs/en/12-auth-and-api.md +0 -124
  120. package/docs/en/16-bake-cookbook.md +0 -100
  121. package/docs/en/17-shadow-dom-forms.md +0 -192
  122. package/docs/fr/00-the-mado-way.md +0 -85
  123. package/docs/fr/01-routing.md +0 -120
  124. package/docs/fr/02-project-layout.md +0 -84
  125. package/docs/fr/03-static-bake.md +0 -289
  126. package/docs/fr/04-ide-setup.md +0 -162
  127. package/docs/fr/05-why-mado.md +0 -193
  128. package/docs/fr/06-for-backenders.md +0 -438
  129. package/docs/fr/07-llm-pitfalls.md +0 -625
  130. package/docs/fr/08-llm-zero-history-test.md +0 -38
  131. package/docs/fr/09-shadow-vs-light-dom.md +0 -65
  132. package/docs/fr/10-app-architecture.md +0 -138
  133. package/docs/fr/11-layouts.md +0 -47
  134. package/docs/fr/12-auth-and-api.md +0 -76
  135. package/docs/fr/13-deployment.md +0 -57
  136. package/docs/fr/14-testing.md +0 -41
  137. package/docs/fr/15-error-handling.md +0 -50
  138. package/docs/fr/16-bake-cookbook.md +0 -88
  139. package/docs/fr/17-shadow-dom-forms.md +0 -196
  140. package/docs/fr/18-api-freeze-map.md +0 -63
  141. package/docs/fr/19-reactivity-ordering.md +0 -97
  142. package/docs/fr/20-v1-stability.md +0 -88
  143. package/docs/fr/README.md +0 -27
  144. package/docs/ru/00-the-mado-way.md +0 -84
  145. package/docs/ru/01-routing.md +0 -119
  146. package/docs/ru/02-project-layout.md +0 -84
  147. package/docs/ru/03-static-bake.md +0 -250
  148. package/docs/ru/04-ide-setup.md +0 -144
  149. package/docs/ru/05-why-mado.md +0 -193
  150. package/docs/ru/06-for-backenders.md +0 -428
  151. package/docs/ru/07-llm-pitfalls.md +0 -624
  152. package/docs/ru/08-llm-zero-history-test.md +0 -57
  153. package/docs/ru/09-shadow-vs-light-dom.md +0 -63
  154. package/docs/ru/10-app-architecture.md +0 -152
  155. package/docs/ru/11-layouts.md +0 -47
  156. package/docs/ru/12-auth-and-api.md +0 -75
  157. package/docs/ru/13-deployment.md +0 -66
  158. package/docs/ru/14-testing.md +0 -50
  159. package/docs/ru/15-error-handling.md +0 -56
  160. package/docs/ru/16-bake-cookbook.md +0 -95
  161. package/docs/ru/17-shadow-dom-forms.md +0 -193
  162. package/docs/ru/18-api-freeze-map.md +0 -64
  163. package/docs/ru/19-reactivity-ordering.md +0 -95
  164. package/docs/ru/20-v1-stability.md +0 -82
  165. package/docs/ru/README.md +0 -25
  166. package/docs/uk/00-the-mado-way.md +0 -82
  167. package/docs/uk/01-routing.md +0 -76
  168. package/docs/uk/02-project-layout.md +0 -73
  169. package/docs/uk/03-static-bake.md +0 -48
  170. package/docs/uk/04-ide-setup.md +0 -26
  171. package/docs/uk/05-why-mado.md +0 -34
  172. package/docs/uk/06-for-backenders.md +0 -55
  173. package/docs/uk/07-llm-pitfalls.md +0 -145
  174. package/docs/uk/08-llm-zero-history-test.md +0 -34
  175. package/docs/uk/09-shadow-vs-light-dom.md +0 -58
  176. package/docs/uk/10-app-architecture.md +0 -97
  177. package/docs/uk/11-layouts.md +0 -47
  178. package/docs/uk/12-auth-and-api.md +0 -70
  179. package/docs/uk/13-deployment.md +0 -40
  180. package/docs/uk/14-testing.md +0 -34
  181. package/docs/uk/15-error-handling.md +0 -32
  182. package/docs/uk/16-bake-cookbook.md +0 -36
  183. package/docs/uk/17-shadow-dom-forms.md +0 -193
  184. package/docs/uk/18-api-freeze-map.md +0 -61
  185. package/docs/uk/19-reactivity-ordering.md +0 -95
  186. package/docs/uk/20-v1-stability.md +0 -83
  187. package/docs/uk/README.md +0 -27
  188. package/starters/default/src/modules/home/not-found.page.ts +0 -11
  189. /package/docs/en/{15-error-handling.md → 21-error-handling.md} +0 -0
  190. /package/docs/en/{19-reactivity-ordering.md → 31-reactivity-ordering.md} +0 -0
  191. /package/starters/{default → modular}/.editorconfig +0 -0
  192. /package/starters/{default → modular}/eslint.config.mjs +0 -0
  193. /package/starters/{default → modular}/public/favicon.svg +0 -0
  194. /package/starters/{default → modular}/src/modules/auth/_contracts/auth-api.types.ts +0 -0
  195. /package/starters/{default → modular}/src/modules/auth/auth.connector.ts +0 -0
  196. /package/starters/{default → modular}/src/modules/auth/auth.guard.ts +0 -0
  197. /package/starters/{default → modular}/src/modules/auth/auth.public.ts +0 -0
  198. /package/starters/{default → modular}/src/modules/auth/auth.routes.ts +0 -0
  199. /package/starters/{default → modular}/src/modules/auth/auth.service.ts +0 -0
  200. /package/starters/{default → modular}/src/modules/auth/auth.types.ts +0 -0
  201. /package/starters/{default → modular}/src/modules/auth/login.page.ts +0 -0
  202. /package/starters/{default → modular}/src/modules/billing/_contracts/stripe.types.ts +0 -0
  203. /package/starters/{default → modular}/src/modules/billing/api/stripe.connector.ts +0 -0
  204. /package/starters/{default → modular}/src/modules/billing/billing.public.ts +0 -0
  205. /package/starters/{default → modular}/src/modules/billing/billing.routes.ts +0 -0
  206. /package/starters/{default → modular}/src/modules/billing/billing.types.ts +0 -0
  207. /package/starters/{default → modular}/src/modules/billing/components/invoice-status-badge.component.ts +0 -0
  208. /package/starters/{default → modular}/src/modules/billing/data/invoices.resource.ts +0 -0
  209. /package/starters/{default → modular}/src/modules/billing/pages/invoice-detail.page.ts +0 -0
  210. /package/starters/{default → modular}/src/shared/http/http-client.ts +0 -0
  211. /package/starters/{default → modular}/src/shared/http/http-error.ts +0 -0
  212. /package/starters/{default → modular}/src/shared/http/interceptors.ts +0 -0
  213. /package/starters/{default → modular}/src/shared/lib/format-date.ts +0 -0
  214. /package/starters/{default → modular}/src/shared/styles/content.css +0 -0
  215. /package/starters/{default → modular}/src/shared/styles/reset.css +0 -0
  216. /package/starters/{default → modular}/src/shared/styles/shell.css +0 -0
  217. /package/starters/{default → modular}/src/shared/styles/tokens.css +0 -0
  218. /package/starters/{default → modular}/src/shared/ui/x-button.component.ts +0 -0
  219. /package/starters/{default → modular}/src/shared/ui/x-spinner.component.ts +0 -0
@@ -1,196 +0,0 @@
1
- # Shadow DOM + formulaires
2
-
3
- L'utilisation de `useForm()` avec des composants input personnalisés en Shadow DOM
4
- nécessite de connaître deux comportements au niveau du navigateur :
5
-
6
- 1. **Retargeting des événements** — les événements qui remontent du Shadow DOM ont
7
- leur `e.target` redirigé vers l'élément host. `useForm().onInput` lit
8
- `e.target.name` et `e.target.value`, mais un élément host `<x-input>`
9
- ne possède pas nativement ces propriétés.
10
-
11
- 2. **Association de formulaire** — un `<button type="submit">` à l'intérieur d'un
12
- Shadow Root ne fait PAS partie de l'algorithme form-owner pour `<form>` dans
13
- le Light DOM. Cliquer dessus ne déclenche pas le submit du formulaire.
14
-
15
- Ces deux limitations sont au niveau de la spécification, pas des bugs Mado. Mais
16
- le framework fournit des patterns qui les rendent indolores.
17
-
18
- ## Pattern : Propriétés proxy sur les composants input
19
-
20
- En encapsulant un `<input>` dans un composant Shadow DOM, exposez `name` et
21
- `value` comme propriétés DOM sur le host pour que `useForm().onInput` fonctionne
22
- après le retargeting :
23
-
24
- ```ts
25
- import { component, css, html } from "@madojs/mado";
26
-
27
- component("x-input", ({ host, attr }) => {
28
- const name = attr("name", "");
29
- const type = attr("type", "text");
30
- const value = attr("value", "");
31
-
32
- // Propriétés proxy pour la compatibilité useForm().
33
- // Après le retargeting Shadow DOM de e.target : <input> → <x-input>,
34
- // useForm lit e.target.name / e.target.value — ces getters font le pont.
35
- Object.defineProperty(host, "name", {
36
- get: () => host.getAttribute("name") ?? "",
37
- configurable: true,
38
- });
39
- Object.defineProperty(host, "value", {
40
- get: () => host.shadowRoot?.querySelector("input")?.value ?? "",
41
- set: (v: string) => {
42
- const input = host.shadowRoot?.querySelector("input");
43
- if (input) input.value = v;
44
- },
45
- configurable: true,
46
- });
47
-
48
- return () => html`<input name=${name} type=${type} .value=${value} />`;
49
- });
50
- ```
51
-
52
- L'événement `input` du `<input>` interne a `composed: true` par défaut, donc
53
- il remonte à travers la frontière shadow. Après le retargeting, `e.target` est
54
- `<x-input>`, mais maintenant il a les getters `.name` et `.value` → `useForm`
55
- fonctionne.
56
-
57
- ## Pattern : Submit de formulaire depuis des boutons Shadow DOM
58
-
59
- Un `<button type="submit">` dans le Shadow DOM ne peut pas déclencher le submit
60
- d'un `<form>` dans le Light DOM. Pont via `requestSubmit()` :
61
-
62
- ```ts
63
- import { component, css, html } from "@madojs/mado";
64
-
65
- component("x-button", ({ host, attr }) => {
66
- const disabled = attr("disabled");
67
-
68
- const handleClick = () => {
69
- const typeAttr = host.getAttribute("type");
70
- if (typeAttr === "button" || typeAttr === "reset") return;
71
- const form = host.closest("form");
72
- if (form && !host.hasAttribute("disabled")) form.requestSubmit();
73
- };
74
-
75
- return () => html`
76
- <button ?disabled=${() => disabled() !== ""} @click=${handleClick}>
77
- <slot></slot>
78
- </button>
79
- `;
80
- });
81
- ```
82
-
83
- `host.closest("form")` fonctionne parce que l'élément host lui-même vit dans
84
- le Light DOM (seuls ses éléments internes sont dans l'ombre). `requestSubmit()`
85
- déclenche la validation et l'événement `submit` exactement comme si l'utilisateur
86
- avait cliqué sur un bouton submit natif à l'intérieur du formulaire.
87
-
88
- ## Pattern : Attributs réactifs avec ctx.attr()
89
-
90
- Depuis la v0.7, `ctx.attr(name, defaultValue?)` retourne un `Signal<string>` qui
91
- se met à jour automatiquement quand l'attribut change sur le host. Plus besoin de
92
- `MutationObserver` :
93
-
94
- ```ts
95
- component("x-badge", ({ attr }) => {
96
- const variant = attr("variant", "default"); // Signal<string>
97
-
98
- return () =>
99
- html`<span class=${() => `badge badge-${variant()}`}>
100
- <slot></slot>
101
- </span>`;
102
- });
103
- ```
104
-
105
- Le parent peut utiliser `?disabled=${() => !form.isValid()}` (attribut booléen)
106
- ou `.variant=${"danger"}` — le composant se re-rend de manière réactive dans
107
- les deux cas.
108
-
109
- ## Exemple complet de formulaire
110
-
111
- ```ts
112
- import { page, html, useForm, navigate } from "@madojs/mado";
113
- import "../components/x-input.js";
114
- import "../components/x-button.js";
115
-
116
- export default page({
117
- title: "Connexion",
118
- view: () => {
119
- const form = useForm({
120
- email: { required: true, type: "email" },
121
- password: { required: true, minLength: 6 },
122
- });
123
-
124
- const handleLogin = async (values) => {
125
- await api("/auth/login", { method: "POST", json: values });
126
- navigate("/admin");
127
- };
128
-
129
- return html`
130
- <form @submit=${form.onSubmit(handleLogin)}>
131
- <x-input
132
- name="email"
133
- type="email"
134
- label="Email"
135
- required
136
- @input=${form.onInput}
137
- @blur=${form.onBlur}
138
- ></x-input>
139
- ${() =>
140
- form.errors().email
141
- ? html`<small class="err">${form.errors().email}</small>`
142
- : null}
143
-
144
- <x-input
145
- name="password"
146
- type="password"
147
- label="Mot de passe"
148
- required
149
- @input=${form.onInput}
150
- @blur=${form.onBlur}
151
- ></x-input>
152
-
153
- <x-button type="submit" ?disabled=${() => !form.isValid()}>
154
- Se connecter
155
- </x-button>
156
- </form>
157
- `;
158
- },
159
- });
160
- ```
161
-
162
- ## Quand utiliser Light DOM à la place
163
-
164
- Si votre composant input est juste un wrapper stylisé sans besoin
165
- d'encapsulation, `shadow: false` évite les deux problèmes (retargeting et
166
- association de formulaire) :
167
-
168
- ```ts
169
- component(
170
- "x-field",
171
- ({ attr }) => {
172
- const label = attr("label", "");
173
- return () => html`
174
- <label>
175
- <span>${label}</span>
176
- <slot></slot>
177
- </label>
178
- `;
179
- },
180
- { shadow: false },
181
- );
182
- ```
183
-
184
- Avec Light DOM, le `<input>` natif fait partie de l'arbre du document, les
185
- événements ne sont pas retargetés, et le submit fonctionne nativement.
186
- Le compromis : les styles ne sont pas encapsulés (vous devez les scoper
187
- vous-même).
188
-
189
- ## Résumé
190
-
191
- | Problème | Solution Shadow DOM | Alternative Light DOM |
192
- | ------------------------------ | -------------------------------------------- | ------------------------------- |
193
- | `useForm` + input personnalisé | Proxy `name`/`value` sur le host | `<input>` natif dans un slot |
194
- | Submit de formulaire | `form.requestSubmit()` dans le click handler | Le bouton natif fonctionne |
195
- | Attributs réactifs | `ctx.attr()` → signal auto | `ctx.attr()` fonctionne partout |
196
- | Encapsulation des styles | Oui (automatique) | `@scope` manuel ou BEM |
@@ -1,63 +0,0 @@
1
- # Carte de gel de l'API
2
-
3
- > Ce qui est public, ce qui est interne, et ce que SemVer protégera en v1.
4
-
5
- Le contrat v1 de Mado est volontairement petit. Le code applicatif importe
6
- depuis la racine du package :
7
-
8
- ```ts
9
- import { component, html, resource, routes, signal } from "@madojs/mado";
10
- ```
11
-
12
- Le seul subpath public est le module side-effect devtools :
13
-
14
- ```ts
15
- import "@madojs/mado/devtools.js";
16
- ```
17
-
18
- Tout le reste sous `dist/src/` est un détail d'implémentation, même si le
19
- fichier est visible dans le dépôt.
20
-
21
- ## API publique stable
22
-
23
- Ces noms sont publics et protégés par SemVer une fois v1 publiée :
24
-
25
- - Réactivité : `signal`, `computed`, `effect`, `untracked`, `batch`,
26
- `flushSync`.
27
- - Templates et directives : `html`, `render`, `each`, `list`, `unsafeHTML`,
28
- `ref`, `classMap`, `styleMap`.
29
- - Composants et CSS : `component`, `css`, `cssVars`.
30
- - Routage et pages : `routes`, `router`, `page`, `layout`,
31
- `navigate`, `queryParam`, `prefetchPath`.
32
- - Data : `resource`, `mutation`, `invalidate`, `jsonFetcher`, `HttpError`.
33
- - Formulaires : `useForm`.
34
- - Head et persistence : `applyHead`, `persisted`.
35
- - Context : `createContext`, `provide`, `inject`.
36
- - Helpers lifecycle avancés : `createLifecycle`, `runInLifecycle`,
37
- `getCurrentLifecycle`.
38
- - Types TypeScript publics exportés depuis `@madojs/mado`.
39
-
40
- ## Interne ou instable
41
-
42
- Ce n'est pas de l'API publique :
43
-
44
- - Subpaths du package autres que `@madojs/mado` et
45
- `@madojs/mado/devtools.js`.
46
- - Internals du parser/binding comme `html/parser.js`, `html/bindings.js`,
47
- `ChildState` et `EachEntry`.
48
- - Internals du routeur comme `router/match.js`, `router/navigation.js` et
49
- `router/manifest.js`.
50
- - Internals de diagnostics et tous les `_testHooks`.
51
- - Texte exact du bundle généré, noms des chunks et layout interne des fichiers.
52
-
53
- Les tests du dépôt peuvent importer des fichiers internes via des chemins
54
- relatifs `dist/`. Le code applicatif ne doit pas le faire.
55
-
56
- ## Ce qui peut changer
57
-
58
- Les patch et minor releases peuvent ajouter des root exports, options,
59
- diagnostics, docs ou starters. Elles peuvent aussi changer les internals, la
60
- forme du bundle et les détails d'implémentation tant que l'API stable et le
61
- comportement documenté restent compatibles.
62
-
63
- Les changements cassants de l'API stable nécessitent une version majeure.
@@ -1,97 +0,0 @@
1
- # Ordre de la réactivité
2
-
3
- > Le petit ensemble de garanties d'ordre que Mado traite comme comportement public.
4
-
5
- La réactivité de Mado est synchrone pour les lectures et planifiée pour les
6
- side effects. Le but est une mise à jour UI prévisible plutôt qu'un grand modèle
7
- de scheduling.
8
-
9
- ## Signals
10
-
11
- `signal(value)` renvoie une fonction getter. `set(next)` change la valeur
12
- immédiatement sauf si `Object.is(previous, next)` vaut `true`.
13
-
14
- ```ts
15
- const count = signal(0);
16
- count.set(1);
17
- count(); // 1, immédiatement
18
- ```
19
-
20
- Les computed values sont marquées avant l'exécution des effects : un effect qui
21
- lit un computed observe les dépendances courantes, pas un cache obsolète.
22
-
23
- ## Effects
24
-
25
- `effect(fn)` s'exécute une première fois immédiatement. Les changements
26
- ultérieurs de dépendances planifient une seule exécution en microtask. Les tests
27
- peuvent appeler `flushSync()` pour vider cette file de façon synchrone.
28
-
29
- Si un effect retourne une fonction de cleanup, Mado l'exécute avant l'exécution
30
- suivante de l'effect et à nouveau quand le disposer est appelé.
31
-
32
- ```ts
33
- const stop = effect(() => {
34
- const id = setInterval(tick, 1000);
35
- return () => clearInterval(id);
36
- });
37
-
38
- stop();
39
- ```
40
-
41
- Dans les composants et pages, préférez `ctx.onDispose()` / page `onDispose()`
42
- pour le cleanup à l'unmount. Le cleanup d'un effect est un cleanup par run.
43
-
44
- ## Batch
45
-
46
- `batch(fn)` regroupe les écritures de signals en un seul passage des
47
- subscribers. Les effects ne s'exécutent pas avant la sortie du batch le plus
48
- extérieur, y compris avec des batches imbriqués.
49
-
50
- ```ts
51
- batch(() => {
52
- first.set("Ada");
53
- batch(() => last.set("Lovelace"));
54
- });
55
- // les effects ne voient que la paire finale
56
- ```
57
-
58
- Les `computed({ equals })` observés préservent aussi l'atomicité du batch : ils
59
- se recalculent une fois après le batch extérieur, sur l'état entièrement
60
- appliqué. Ils ne doivent pas observer un batch à moitié appliqué comme
61
- `(new x, old y)`.
62
-
63
- ## Mises à jour DOM
64
-
65
- `render(result, container)` réutilise l'instance de template existante quand le
66
- render suivant a les mêmes template strings. Pour les child bindings qui
67
- retournent un `html``` imbriqué, la même règle s'applique : mêmes strings =
68
- mise à jour sur place, autres strings = reconstruction de cette branche.
69
-
70
- Ainsi, des changements de signals sans rapport ne recréent pas un `<input>`
71
- dans un template imbriqué stable : focus, état DOM et listeners survivent.
72
-
73
- Les listes doivent utiliser `each(items, key, renderItem)`. Les keys définissent
74
- l'identité DOM. Les duplicate keys avertissent en development et retombent sur
75
- un suffixe positionnel pour que chaque item soit rendu, mais les duplicate keys
76
- sont un bug de données.
77
-
78
- ## Teardown des composants
79
-
80
- Les custom elements peuvent recevoir `disconnectedCallback()` puis
81
- `connectedCallback()` pendant un déplacement dans le même tick. Mado diffère le
82
- teardown du composant jusqu'à une microtask et l'annule si l'élément est
83
- reconnecté, donc les reorders keyed préservent l'état du composant. Une vraie
84
- suppression lance tout de même le cleanup lifecycle à la microtask suivante.
85
-
86
- ## Non garanti
87
-
88
- Mado ne garantit pas le nombre exact de microtasks internes du scheduler,
89
- l'ordre des effects indépendants sans dépendances communes, la forme du bundle
90
- généré ni le layout interne des modules. Ce sont des détails d'implémentation.
91
-
92
- Les tests invariants de ce contrat vivent dans :
93
-
94
- - `test/reactivity-ordering.test.mjs`
95
- - `test/signal-batch-equals.test.mjs`
96
- - `test/update-nested-reuse.test.mjs`
97
- - `test/each-component-state.test.mjs`
@@ -1,88 +0,0 @@
1
- # Stabilité v1
2
-
3
- > Ce que Mado promet après v1, et ce qui reste libre d'évoluer.
4
-
5
- Mado v1 signifie que le contrat public côté application est assez stable pour
6
- de vraies applications métier. Cela ne veut pas dire que chaque fichier interne,
7
- octet généré, starter copy ou diagnostic string est gelé pour toujours.
8
-
9
- À lire avec :
10
-
11
- - [Carte de gel de l'API](./18-api-freeze-map.md)
12
- - [Ordre de la réactivité](./19-reactivity-ordering.md)
13
-
14
- ## Stable sous SemVer
15
-
16
- Après v1, Mado considère comme protégés par SemVer :
17
-
18
- - Les exports publics de `@madojs/mado`.
19
- - Les types TypeScript publics exportés depuis `@madojs/mado`.
20
- - Le subpath side-effect `@madojs/mado/devtools.js`.
21
- - La syntaxe de template binding : child `${}`, `@event`, `.prop`,
22
- `?boolean`, attribute bindings, directives et `each()`.
23
- - Les semantics des signals documentées dans le guide d'ordre de réactivité.
24
- - Les semantics du lifecycle composant : setup une fois par connection
25
- lifetime, teardown différé pour les same-tick moves, cleanup via
26
- `ctx.onDispose`.
27
- - Les contrats router/page/resource/form documentés dans les docs anglaises.
28
- - Les noms de commandes CLI et leur intention générale (`build`, `dev`,
29
- `release`, `bake`, `preview`, `init`, `new`).
30
-
31
- Casser cela nécessite une version majeure.
32
-
33
- ## Autorisé en minor releases
34
-
35
- Les minor releases peuvent ajouter :
36
-
37
- - De nouveaux root exports.
38
- - De nouvelles options sur des API existantes.
39
- - De nouveaux diagnostics et warnings.
40
- - De nouveaux starters, examples, docs et flags CLI.
41
- - Des améliorations de performance et des rewrites internes.
42
-
43
- Une minor release ne devrait pas forcer les apps correctes existantes à changer
44
- leur code.
45
-
46
- ## Autorisé en patch releases
47
-
48
- Les patch releases peuvent corriger des bugs, durcir les diagnostics, améliorer
49
- les docs et faire des changements d'implémentation compatibles. Un patch peut
50
- changer le timing seulement si l'ancien timing était un bug non documenté et
51
- que le changement conserve le contrat d'ordre de réactivité.
52
-
53
- ## Non stable
54
-
55
- Ne sont volontairement pas protégés par SemVer :
56
-
57
- - Les subpaths internes du package autres que `@madojs/mado/devtools.js`.
58
- - Les fichiers sous `src/`, `dist/src/` et les frontières de modules
59
- d'implémentation.
60
- - `_testHooks`, internals de diagnostics et warning codes.
61
- - Le JavaScript exact généré, les noms de chunks, le contenu sourcemap et le
62
- byte layout du bundle.
63
- - Les structures internes du parser, des bindings, du routeur et du cache
64
- resource.
65
- - Le texte visuel et les données de démonstration des starters.
66
-
67
- Les apps ne doivent pas importer de fichiers internes ni vérifier l'output exact
68
- du bundle.
69
-
70
- ## Bundle et output de release
71
-
72
- Mado gardera un size budget et des tests de release déterministe, mais la
73
- stabilité v1 ne fige pas l'output du bundler octet par octet. Les hashes,
74
- frontières de chunks et noms d'assets générés peuvent changer tant que le
75
- contrat de déploiement documenté continue de fonctionner.
76
-
77
- ## Si une release vous casse
78
-
79
- Si une mise à jour casse du code qui utilise seulement les exports publics et le
80
- comportement documenté, traitez-le comme un bug. Ouvrez une issue avec :
81
-
82
- - la version de Mado avant et après ;
83
- - l'API publique impliquée ;
84
- - une reproduction minimale ;
85
- - si la casse concerne le runtime, les types TypeScript, l'output CLI ou les docs.
86
-
87
- Si la casse dépend d'un subpath interne ou de l'output généré exact, cela peut
88
- quand même valoir un rapport, mais ce n'est pas considéré comme une casse SemVer.
package/docs/fr/README.md DELETED
@@ -1,27 +0,0 @@
1
- # Mado docs — Français
2
-
3
- Documentation française.
4
-
5
- | Section | Fichier |
6
- | ----------------------------- | ------------------------------------------------------------ |
7
- | La voie Mado | [00-the-mado-way.md](./00-the-mado-way.md) |
8
- | Routage | [01-routing.md](./01-routing.md) |
9
- | Structure du projet | [02-project-layout.md](./02-project-layout.md) |
10
- | Prérendu statique & SEO | [03-static-bake.md](./03-static-bake.md) |
11
- | Configuration IDE | [04-ide-setup.md](./04-ide-setup.md) |
12
- | Pourquoi Mado | [05-why-mado.md](./05-why-mado.md) |
13
- | Pour les développeurs backend | [06-for-backenders.md](./06-for-backenders.md) |
14
- | Pièges LLM | [07-llm-pitfalls.md](./07-llm-pitfalls.md) |
15
- | Test LLM sans historique | [08-llm-zero-history-test.md](./08-llm-zero-history-test.md) |
16
- | Shadow DOM vs Light DOM | [09-shadow-vs-light-dom.md](./09-shadow-vs-light-dom.md) |
17
- | Architecture d'application | [10-app-architecture.md](./10-app-architecture.md) |
18
- | Mises en page (layouts) | [11-layouts.md](./11-layouts.md) |
19
- | Auth et API | [12-auth-and-api.md](./12-auth-and-api.md) |
20
- | Déploiement | [13-deployment.md](./13-deployment.md) |
21
- | Tests | [14-testing.md](./14-testing.md) |
22
- | Gestion des erreurs | [15-error-handling.md](./15-error-handling.md) |
23
- | Guide de recettes bake | [16-bake-cookbook.md](./16-bake-cookbook.md) |
24
- | Shadow DOM + formulaires | [17-shadow-dom-forms.md](./17-shadow-dom-forms.md) |
25
- | Carte de gel de l'API | [18-api-freeze-map.md](./18-api-freeze-map.md) |
26
- | Ordre de la réactivité | [19-reactivity-ordering.md](./19-reactivity-ordering.md) |
27
- | Stabilité v1 | [20-v1-stability.md](./20-v1-stability.md) |
@@ -1,84 +0,0 @@
1
- # The Mado Way
2
-
3
- > Один правильный путь. Жёсткие контракты. Никакой магии.
4
-
5
- Mado — фреймворк для команд, которые строят админки, внутренние инструменты и
6
- business SPA. Такие приложения должны быть простыми в разработке и скучными в
7
- поддержке. Поэтому Mado задает соглашения, а не предлагает пять равноценных
8
- стилей.
9
-
10
- ## Принципы
11
-
12
- 1. **Один способ.** Если пишешь что-то необычное, сначала проверь, нет ли уже
13
- каноничного helper/API.
14
- 2. **Явность над магией.** Никаких file-system scanners, implicit globals и
15
- скрытых side effects.
16
- 3. **Платформа сначала.** Web Components, History API, `<form>`, `fetch` и
17
- Shadow DOM остаются платформой, а не прячутся под тяжелыми абстракциями.
18
- 4. **Strict types.** `tsc --strict --noUncheckedIndexedAccess` всегда.
19
- 5. **No runtime dependencies.** Dev/build tooling допустим, runtime Mado
20
- остается нативным.
21
-
22
- ## Структура проекта
23
-
24
- ```txt
25
- src/
26
- ├── main.ts ← boot: global CSS/providers + render router
27
- ├── app.routes.ts ← readable app map, exports `manifest` + default routes()
28
- ├── layouts/ ← app-zone wrappers (`page({ view: ({ child }) => ... })`)
29
- ├── shared/ ← UI bricks, http client, pure lib, global CSS
30
- └── modules/ ← bounded contexts
31
- └── billing/
32
- ├── billing.routes.ts
33
- ├── billing.public.ts
34
- ├── billing.types.ts
35
- ├── pages/
36
- ├── data/
37
- ├── api/
38
- └── _contracts/
39
- ```
40
-
41
- Default starter — каноничная версия этой формы. Если docs и старые примеры
42
- расходятся, starter и `docs/10-app-architecture.md` главнее.
43
-
44
- ## Один компонент = один файл
45
-
46
- ```ts
47
- import { component, css, html } from "@madojs/mado";
48
-
49
- component("x-user-card", () => () => html`<div class="card"><slot></slot></div>`, {
50
- styles: css`
51
- .card { padding: 1rem; }
52
- `,
53
- });
54
- ```
55
-
56
- Import component file registers the element. Import it where the tag is used.
57
-
58
- ## Один способ описать страницу
59
-
60
- ```ts
61
- import { html, page, resource, jsonFetcher } from "@madojs/mado";
62
-
63
- export default page({
64
- title: ({ id }) => `User #${id}`,
65
- view: ({ params }) => {
66
- const user = resource(() => `/api/users/${params.id}`, jsonFetcher());
67
- return html`...`;
68
- },
69
- });
70
- ```
71
-
72
- Page-local signals, resources and forms live inside `view()`. Module-wide state
73
- belongs in `*.service.ts`.
74
-
75
- ## Чего НЕ делаем
76
-
77
- - Не используем JSX/Vue/Svelte syntax.
78
- - Не пишем custom elements без дефиса.
79
- - Не читаем signals через `.value`; signal читается как function.
80
- - Не используем `innerHTML` напрямую.
81
- - Не добавляем runtime packages без обсуждения.
82
-
83
- Когда сомневаешься, лучше записать один честный рецепт в docs, чем добавить
84
- новый primitive в core.
@@ -1,119 +0,0 @@
1
- # Routing
2
-
3
- > Один app map. Никаких folder scanners. Никаких специальных path symbols.
4
-
5
- Mado не выводит routes из файлов. Composition должна читаться в одном месте.
6
-
7
- ## App Manifest
8
-
9
- Используйте `src/app.routes.ts` как карту приложения:
10
-
11
- ```ts
12
- import { layout, routes } from "@madojs/mado";
13
- import { requireAuth } from "./modules/auth/auth.public";
14
- import { authRoutes } from "./modules/auth/auth.routes";
15
- import { billingRoutes } from "./modules/billing/billing.routes";
16
-
17
- export const manifest = {
18
- "/": () => import("./modules/home/home.page.js"),
19
- "/login": layout({
20
- layout: () => import("./layouts/auth-shell.layout.js"),
21
- routes: authRoutes,
22
- }),
23
- "/billing": layout({
24
- layout: () => import("./layouts/app-shell.layout.js"),
25
- guard: requireAuth,
26
- routes: billingRoutes,
27
- }),
28
- "*": () => import("./modules/home/not-found.page.js"),
29
- };
30
-
31
- export default routes(manifest);
32
- ```
33
-
34
- Открываешь `app.routes.ts` и видишь все зоны приложения: public pages, auth,
35
- protected app zones, guards и shells.
36
-
37
- `manifest` экспортируется отдельно, чтобы `mado bake` мог его прочитать.
38
-
39
- ## Module Routes
40
-
41
- Modules экспортируют plain route maps. Они не вызывают `layout()` и не решают,
42
- какой shell их оборачивает.
43
-
44
- ```ts
45
- export const billingRoutes = {
46
- "/invoices": () => import("./pages/invoices-list.page.js"),
47
- "/invoices/:id": () => import("./pages/invoice-detail.page.js"),
48
- };
49
- ```
50
-
51
- Prefix применяет `src/app.routes.ts`, когда module монтируется под
52
- `"/billing"`.
53
-
54
- ## Layout Group
55
-
56
- ```ts
57
- "/admin": layout({
58
- layout: () => import("./layouts/app-shell.layout.js"),
59
- guard: requireAuth,
60
- routes: adminRoutes,
61
- }),
62
- ```
63
-
64
- Layout — обычный `page({...})` file:
65
-
66
- ```ts
67
- import { html, page } from "@madojs/mado";
68
-
69
- export default page({
70
- view: ({ child }) => html`
71
- <div class="layout layout--app">
72
- <main class="app-main">${child}</main>
73
- </div>
74
- `,
75
- });
76
- ```
77
-
78
- Layout view держим stateless. Page-specific signals, resources и forms живут в
79
- pages/components/resources, не в layout locals.
80
-
81
- ## Page Contract
82
-
83
- ```ts
84
- import { html, page } from "@madojs/mado";
85
-
86
- export default page<{ id: string }>({
87
- title: ({ id }) => `User ${id}`,
88
- view: ({ params }) => html`<h1>${params.id}</h1>`,
89
- });
90
- ```
91
-
92
- ## Navigation
93
-
94
- ```ts
95
- import appRoutes from "./app.routes.js";
96
-
97
- appRoutes.navigate("/billing/invoices");
98
- appRoutes.navigate("/billing/invoices?page=2");
99
- appRoutes.navigate("/login", { replace: true });
100
- ```
101
-
102
- ## Query Parameters
103
-
104
- ```ts
105
- import { queryParam } from "@madojs/mado";
106
-
107
- const page = queryParam("page", "1");
108
- page();
109
- page.set("2");
110
- page.set(null);
111
- page.set("3", { push: true });
112
- ```
113
-
114
- ## Чего нет намеренно
115
-
116
- - Auto-scan of page folders.
117
- - Filesystem syntax вроде `[id]`, `(group)`, `_layout`.
118
- - Server routes в client manifest.
119
- - Hidden layout discovery.