@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,192 +0,0 @@
1
- # Shadow DOM + Forms
2
-
3
- Using `useForm()` with custom input components that have Shadow DOM requires
4
- awareness of two browser-level behaviours:
5
-
6
- 1. **Event retargeting** — events that bubble from Shadow DOM have their
7
- `e.target` retargeted to the host element. `useForm().onInput` reads
8
- `e.target.name` and `e.target.value`, but an `<x-input>` host element
9
- doesn't natively have these properties.
10
-
11
- 2. **Form association** — a `<button type="submit">` inside a Shadow Root is
12
- NOT part of the form-owner algorithm for `<form>` in Light DOM. Clicking it
13
- does not trigger form submit.
14
-
15
- Both are spec-level limitations, not Mado bugs. But the framework provides
16
- patterns that make them painless.
17
-
18
- ## Pattern: Proxy Properties on Input Components
19
-
20
- When wrapping `<input>` in a Shadow DOM component, expose `name` and `value`
21
- as DOM properties on the host so that `useForm().onInput` works after event
22
- 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
- // Proxy properties for useForm() compatibility.
33
- // After Shadow DOM retargets e.target from <input> to <x-input>,
34
- // useForm reads e.target.name / e.target.value — these getters bridge the gap.
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
- The `input` event from the inner `<input>` has `composed: true` by default, so
53
- it will bubble through the shadow boundary. After retargeting, `e.target` is
54
- `<x-input>`, but now it has `.name` and `.value` getters → `useForm` works.
55
-
56
- ## Pattern: Form Submit from Shadow DOM Buttons
57
-
58
- A `<button type="submit">` inside Shadow DOM cannot trigger `<form>` submit in
59
- Light DOM. Bridge it with `requestSubmit()`:
60
-
61
- ```ts
62
- import { component, css, html } from "@madojs/mado";
63
-
64
- component("x-button", ({ host, attr }) => {
65
- const disabled = attr("disabled");
66
-
67
- const handleClick = () => {
68
- const typeAttr = host.getAttribute("type");
69
- if (typeAttr === "button" || typeAttr === "reset") return;
70
- const form = host.closest("form");
71
- if (form && !host.hasAttribute("disabled")) form.requestSubmit();
72
- };
73
-
74
- return () => html`
75
- <button ?disabled=${() => disabled() !== ""} @click=${handleClick}>
76
- <slot></slot>
77
- </button>
78
- `;
79
- });
80
- ```
81
-
82
- `host.closest("form")` works because the host element itself lives in Light DOM
83
- (only its internals are shadowed). `requestSubmit()` triggers validation and the
84
- `submit` event exactly as if the user had clicked a native submit button inside
85
- the form.
86
-
87
- ## Pattern: Reactive Attributes with ctx.attr()
88
-
89
- Since v0.7, `ctx.attr(name, defaultValue?)` returns a `Signal<string>` that
90
- updates automatically when the attribute changes on the host. No more
91
- `MutationObserver` boilerplate:
92
-
93
- ```ts
94
- component("x-badge", ({ attr }) => {
95
- const variant = attr("variant", "default"); // Signal<string>
96
-
97
- return () =>
98
- html`<span class=${() => `badge badge-${variant()}`}>
99
- <slot></slot>
100
- </span>`;
101
- });
102
- ```
103
-
104
- The parent can use `?disabled=${() => !form.isValid()}` (boolean attribute) or
105
- `.variant=${"danger"}` — the component re-renders reactively either way.
106
-
107
- ## Complete Form Example
108
-
109
- ```ts
110
- import { page, html, useForm, navigate } from "@madojs/mado";
111
- import "../components/x-input.js";
112
- import "../components/x-button.js";
113
-
114
- export default page({
115
- title: "Login",
116
- view: () => {
117
- const form = useForm({
118
- email: { required: true, type: "email" },
119
- password: { required: true, minLength: 6 },
120
- });
121
-
122
- const handleLogin = async (values) => {
123
- await api("/auth/login", { method: "POST", json: values });
124
- navigate("/admin");
125
- };
126
-
127
- return html`
128
- <form @submit=${form.onSubmit(handleLogin)}>
129
- <x-input
130
- name="email"
131
- type="email"
132
- label="Email"
133
- required
134
- @input=${form.onInput}
135
- @blur=${form.onBlur}
136
- ></x-input>
137
- ${() =>
138
- form.errors().email
139
- ? html`<small class="err">${form.errors().email}</small>`
140
- : null}
141
-
142
- <x-input
143
- name="password"
144
- type="password"
145
- label="Password"
146
- required
147
- @input=${form.onInput}
148
- @blur=${form.onBlur}
149
- ></x-input>
150
-
151
- <x-button type="submit" ?disabled=${() => !form.isValid()}>
152
- Sign in
153
- </x-button>
154
- </form>
155
- `;
156
- },
157
- });
158
- ```
159
-
160
- ## When to Use Light DOM Instead
161
-
162
- If your input component is just a styled wrapper without encapsulation needs,
163
- `shadow: false` avoids both retargeting and form-association issues entirely:
164
-
165
- ```ts
166
- component(
167
- "x-field",
168
- ({ attr }) => {
169
- const label = attr("label", "");
170
- return () => html`
171
- <label>
172
- <span>${label}</span>
173
- <slot></slot>
174
- </label>
175
- `;
176
- },
177
- { shadow: false },
178
- );
179
- ```
180
-
181
- With Light DOM, the native `<input>` is part of the document tree, events
182
- are not retargeted, and form submission works natively. The tradeoff: styles
183
- are not encapsulated (you must scope them yourself).
184
-
185
- ## Summary
186
-
187
- | Concern | Shadow DOM Solution | Light DOM Alternative |
188
- | ------------------------ | --------------------------------------- | ----------------------------- |
189
- | `useForm` + custom input | Proxy `name`/`value` on host | Use native `<input>` in slot |
190
- | Form submit | `form.requestSubmit()` in click handler | Native button works |
191
- | Reactive attributes | `ctx.attr()` → auto-signal | `ctx.attr()` works everywhere |
192
- | Style encapsulation | Yes (automatic) | Manual `@scope` or BEM |
@@ -1,85 +0,0 @@
1
- # La voie Mado
2
-
3
- > Une seule bonne façon. Des contrats stricts. Pas de magie.
4
-
5
- Mado est un framework pour les équipes qui construisent des panneaux d'admin,
6
- des outils internes et des SPA métier. Ces apps doivent être simples à créer
7
- et ennuyeuses à maintenir. Mado préfère donc des conventions claires à cinq
8
- styles équivalents.
9
-
10
- ## Principes
11
-
12
- 1. **Une seule voie.** Si vous écrivez quelque chose d'inhabituel, vérifiez
13
- d'abord s'il existe déjà un helper/API canonique.
14
- 2. **L'explicite plutôt que la magie.** Pas de file-system scanners, globals
15
- implicites ou side effects cachés.
16
- 3. **La plateforme d'abord.** Web Components, History API, `<form>`, `fetch` et
17
- Shadow DOM restent visibles.
18
- 4. **Types stricts.** `tsc --strict --noUncheckedIndexedAccess` toujours.
19
- 5. **Pas de dépendances runtime.** Le tooling dev/build est acceptable ; le
20
- runtime Mado reste natif.
21
-
22
- ## Structure du projet
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
- Le starter par défaut est la version canonique de cette forme. Si d'anciens
42
- exemples divergent, le starter et `docs/10-app-architecture.md` gagnent.
43
-
44
- ## Un composant = un fichier
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
- Importer le fichier du composant enregistre l'élément. Importez-le là où le tag
57
- est utilisé.
58
-
59
- ## Une seule façon de décrire une page
60
-
61
- ```ts
62
- import { html, page, resource, jsonFetcher } from "@madojs/mado";
63
-
64
- export default page({
65
- title: ({ id }) => `User #${id}`,
66
- view: ({ params }) => {
67
- const user = resource(() => `/api/users/${params.id}`, jsonFetcher());
68
- return html`...`;
69
- },
70
- });
71
- ```
72
-
73
- Les signals, resources et forms locaux à une page vivent dans `view()`. L'état
74
- partagé par un module vit dans `*.service.ts`.
75
-
76
- ## Ce que nous ne faisons pas
77
-
78
- - Pas de JSX/Vue/Svelte syntax.
79
- - Pas de custom elements sans trait d'union.
80
- - Pas de lecture de signal via `.value`; un signal est une fonction.
81
- - Pas de `innerHTML` direct.
82
- - Pas de runtime packages sans discussion.
83
-
84
- En cas de doute, documentez une recette claire plutôt que d'ajouter un nouveau
85
- primitive au core.
@@ -1,120 +0,0 @@
1
- # Routage
2
-
3
- > Une seule app map. Pas de folder scanners. Pas de syntaxe magique.
4
-
5
- Mado ne déduit pas les routes depuis les fichiers. La composition doit rester
6
- lisible dans un seul endroit.
7
-
8
- ## App Manifest
9
-
10
- Utilisez `src/app.routes.ts` comme carte de l'application :
11
-
12
- ```ts
13
- import { layout, routes } from "@madojs/mado";
14
- import { requireAuth } from "./modules/auth/auth.public";
15
- import { authRoutes } from "./modules/auth/auth.routes";
16
- import { billingRoutes } from "./modules/billing/billing.routes";
17
-
18
- export const manifest = {
19
- "/": () => import("./modules/home/home.page.js"),
20
- "/login": layout({
21
- layout: () => import("./layouts/auth-shell.layout.js"),
22
- routes: authRoutes,
23
- }),
24
- "/billing": layout({
25
- layout: () => import("./layouts/app-shell.layout.js"),
26
- guard: requireAuth,
27
- routes: billingRoutes,
28
- }),
29
- "*": () => import("./modules/home/not-found.page.js"),
30
- };
31
-
32
- export default routes(manifest);
33
- ```
34
-
35
- Ouvrez `app.routes.ts` pour voir les zones de l'app : pages publiques, auth,
36
- zones protégées, guards et shells.
37
-
38
- Exportez `manifest` pour `mado bake`.
39
-
40
- ## Module Routes
41
-
42
- Les modules exportent de simples route maps. Ils n'appellent pas `layout()` et
43
- ne décident pas quel shell les enveloppe.
44
-
45
- ```ts
46
- export const billingRoutes = {
47
- "/invoices": () => import("./pages/invoices-list.page.js"),
48
- "/invoices/:id": () => import("./pages/invoice-detail.page.js"),
49
- };
50
- ```
51
-
52
- Le prefix est appliqué par `src/app.routes.ts` quand le module est monté sous
53
- `"/billing"`.
54
-
55
- ## Layout Group
56
-
57
- ```ts
58
- "/admin": layout({
59
- layout: () => import("./layouts/app-shell.layout.js"),
60
- guard: requireAuth,
61
- routes: adminRoutes,
62
- }),
63
- ```
64
-
65
- Un layout est un fichier `page({...})` ordinaire :
66
-
67
- ```ts
68
- import { html, page } from "@madojs/mado";
69
-
70
- export default page({
71
- view: ({ child }) => html`
72
- <div class="layout layout--app">
73
- <main class="app-main">${child}</main>
74
- </div>
75
- `,
76
- });
77
- ```
78
-
79
- Gardez les layout views stateless. Les signals, resources et forms spécifiques
80
- à une page vivent dans les pages/components/resources.
81
-
82
- ## Page Contract
83
-
84
- ```ts
85
- import { html, page } from "@madojs/mado";
86
-
87
- export default page<{ id: string }>({
88
- title: ({ id }) => `User ${id}`,
89
- view: ({ params }) => html`<h1>${params.id}</h1>`,
90
- });
91
- ```
92
-
93
- ## Navigation
94
-
95
- ```ts
96
- import appRoutes from "./app.routes.js";
97
-
98
- appRoutes.navigate("/billing/invoices");
99
- appRoutes.navigate("/billing/invoices?page=2");
100
- appRoutes.navigate("/login", { replace: true });
101
- ```
102
-
103
- ## Query Parameters
104
-
105
- ```ts
106
- import { queryParam } from "@madojs/mado";
107
-
108
- const page = queryParam("page", "1");
109
- page();
110
- page.set("2");
111
- page.set(null);
112
- page.set("3", { push: true });
113
- ```
114
-
115
- ## Ce qui est absent volontairement
116
-
117
- - Pas d'auto-scan des dossiers de pages.
118
- - Pas de syntaxe filesystem comme `[id]`, `(group)`, `_layout`.
119
- - Pas de server routes dans le manifest client.
120
- - Pas de découverte cachée des layouts.
@@ -1,84 +0,0 @@
1
- # Structure du projet
2
-
3
- Chaque application Mado utilise la même forme canonique. Cette convention
4
- permet aux humains et aux assistants IA de savoir où placer le code.
5
-
6
- ```txt
7
- my-app/
8
- ├── package.json # runtime dep: @madojs/mado
9
- ├── tsconfig.json # strict TS, ES2022, Bundler resolution
10
- ├── vite.config.ts # mado() from @madojs/mado/vite
11
- ├── index.html # entrée Vite + shell SPA
12
- ├── public/ # assets statiques: favicon, images, robots.txt
13
- └── src/
14
- ├── main.ts # importe le CSS et monte le router dans #app
15
- ├── app.routes.ts # app map: manifest + default routes(...)
16
- ├── layouts/ # layouts de zones d'application
17
- ├── shared/ # ui, http, lib, styles
18
- └── modules/ # bounded contexts
19
- └── billing/
20
- ├── billing.routes.ts
21
- ├── billing.public.ts
22
- ├── billing.types.ts
23
- ├── pages/
24
- ├── data/
25
- ├── api/
26
- └── _contracts/
27
- ```
28
-
29
- ## États Des Artefacts
30
-
31
- | Dossier | Ce que c'est | Écrit par | Déployer ? |
32
- | --- | --- | --- | --- |
33
- | `src/` | sources TypeScript | vous | non |
34
- | `public/` | assets statiques copiés tels quels | vous | via `out/` |
35
- | `out/` | artefact déployable: shell SPA + assets + HTML baked | `mado release` | oui |
36
-
37
- `mado release` = `typecheck` + build Vite (`out/index.html`, `out/assets/`,
38
- `public/*`) + `bake` directement dans les chemins de routes + `sitemap.xml` +
39
- precompression.
40
-
41
- `index.html` reste à la racine car Vite le traite comme entry template. Mettez
42
- dans `public/` uniquement les fichiers à copier tels quels.
43
-
44
- ## Où mettre un nouveau fichier ?
45
-
46
- | Quoi | Où |
47
- | --- | --- |
48
- | Page pour une nouvelle URL | `src/modules/<module>/pages/<name>.page.ts` + module routes |
49
- | Route map de module | `src/modules/<module>/<module>.routes.ts` |
50
- | App shell/layout | `src/layouts/<zone>.layout.ts` |
51
- | Widget UI partagé | `src/shared/ui/<x-name>.component.ts` |
52
- | Widget UI propre à un module | `src/modules/<module>/components/<name>.component.ts` |
53
- | API connector | `src/modules/<module>/api/<provider>.connector.ts` |
54
- | Data resource/mutation | `src/modules/<module>/data/<name>.resource.ts` |
55
- | Auth/session | `src/modules/auth/` |
56
- | Surface publique de module | `src/modules/<module>/<module>.public.ts` |
57
- | Fonction pure sans UI | `src/shared/lib/<name>.ts` |
58
- | Image statique / favicon | `public/<file>` |
59
- | CSS de shell | `src/shared/styles/shell.css` |
60
- | CSS de contenu page | `src/shared/styles/content.css` |
61
-
62
- ## Vite Config
63
-
64
- ```ts
65
- import { defineConfig } from "vite";
66
- import { mado } from "@madojs/mado/vite";
67
-
68
- export default defineConfig({
69
- plugins: [mado()],
70
- css: {
71
- transformer: "lightningcss",
72
- },
73
- });
74
- ```
75
-
76
- Le starter active le transformer Lightning CSS de Vite. Mado ne possède pas le
77
- prefixing, le lowering CSS ou la minification.
78
-
79
- ## Ce qui ne va PAS dans `src/`
80
-
81
- - Configs de build-tool supplémentaires — utilisez `vite.config.ts`.
82
- - Fichiers `.env` — lisez l'env dans `src/shared/lib/config.ts` puis importez
83
- ce module.
84
- - Tests mélangés au code — gardez-les dans `test/`.