@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.
- package/AGENTS.md +102 -25
- package/CHANGELOG.md +158 -1
- package/README.md +135 -172
- package/dist/src/component.d.ts +3 -2
- package/dist/src/component.js +98 -6
- package/dist/src/component.js.map +1 -1
- package/dist/src/css.js +34 -5
- package/dist/src/css.js.map +1 -1
- package/dist/src/head.d.ts +6 -6
- package/dist/src/head.js +6 -6
- package/dist/src/html/parser.d.ts +1 -1
- package/dist/src/html/parser.js +1 -1
- package/dist/src/html/template.js +24 -10
- package/dist/src/html/template.js.map +1 -1
- package/dist/src/index.d.ts +8 -4
- package/dist/src/index.js +13 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/page.d.ts +62 -28
- package/dist/src/page.js +5 -0
- package/dist/src/page.js.map +1 -1
- package/dist/src/resource.js +2 -1
- package/dist/src/resource.js.map +1 -1
- package/dist/src/router/base.d.ts +65 -0
- package/dist/src/router/base.js +168 -0
- package/dist/src/router/base.js.map +1 -0
- package/dist/src/router/manifest.js +75 -31
- package/dist/src/router/manifest.js.map +1 -1
- package/dist/src/router/match.d.ts +16 -2
- package/dist/src/router/match.js +41 -1
- package/dist/src/router/match.js.map +1 -1
- package/dist/src/router/navigation.js +58 -9
- package/dist/src/router/navigation.js.map +1 -1
- package/dist/src/static-runtime.d.ts +81 -0
- package/dist/src/static-runtime.js +209 -0
- package/dist/src/static-runtime.js.map +1 -0
- package/dist/src/vite/index.d.ts +31 -3
- package/dist/src/vite/index.js +49 -18
- package/dist/src/vite/index.js.map +1 -1
- package/docs/README.md +5 -8
- package/docs/architecture/adr/0001-browser-static-snapshots.md +132 -0
- package/docs/en/00-the-mado-way.md +1 -1
- package/docs/en/01-quickstart.md +183 -0
- package/docs/en/10-pages-and-components.md +271 -0
- package/docs/en/11-templates-and-signals.md +211 -0
- package/docs/en/12-routing.md +229 -0
- package/docs/en/13-data.md +225 -0
- package/docs/en/14-forms.md +244 -0
- package/docs/en/15-static-snapshots.md +181 -0
- package/docs/en/{10-app-architecture.md → 16-app-architecture.md} +53 -2
- package/docs/en/{13-deployment.md → 20-deployment.md} +59 -10
- package/docs/en/{14-testing.md → 22-testing.md} +6 -5
- package/docs/en/23-cookbook.md +292 -0
- package/docs/en/{18-api-freeze-map.md → 30-api-freeze-map.md} +12 -3
- package/docs/en/{20-v1-stability.md → 32-v1-stability.md} +3 -3
- package/docs/en/40-llm-guide.md +776 -0
- package/docs/en/{06-for-backenders.md → 41-for-backenders.md} +15 -16
- package/docs/en/{05-why-mado.md → 42-why-mado.md} +1 -1
- package/docs/en/README.md +97 -27
- package/docs/recipes/nginx/Containerfile +26 -0
- package/docs/recipes/nginx/nginx.conf +42 -0
- package/llms.txt +246 -211
- package/package.json +17 -10
- package/scripts/bake.mjs +4 -569
- package/scripts/cli/generate.mjs +55 -5
- package/scripts/cli/help.mjs +11 -5
- package/scripts/cli/index.mjs +20 -4
- package/scripts/cli/init.mjs +7 -2
- package/scripts/cli/release.mjs +20 -68
- package/scripts/docs-lint.mjs +170 -0
- package/scripts/package-smoke.mjs +67 -9
- package/scripts/preview.mjs +95 -6
- package/scripts/size-budget.mjs +5 -1
- package/scripts/static/browser.mjs +654 -0
- package/scripts/static/discover.mjs +281 -0
- package/scripts/static/output.mjs +141 -0
- package/scripts/static/serialize.mjs +212 -0
- package/scripts/static/server.mjs +167 -0
- package/scripts/static.mjs +191 -0
- package/starters/default/README.md +57 -55
- package/starters/default/package.json +3 -9
- package/starters/default/src/app.routes.ts +20 -33
- package/starters/default/src/components/feature-card.component.ts +40 -0
- package/starters/default/src/components/live-counter.component.ts +57 -0
- package/starters/default/src/content/guides.ts +55 -0
- package/starters/default/src/main.ts +9 -13
- package/starters/default/src/pages/app.page.ts +41 -0
- package/starters/default/src/pages/guide.page.ts +40 -0
- package/starters/default/src/pages/home.page.ts +49 -0
- package/starters/default/src/pages/not-found.page.ts +18 -0
- package/starters/default/src/styles/document.css +39 -0
- package/starters/default/src/styles/reset.css +37 -0
- package/starters/default/src/styles/tokens.css +30 -0
- package/starters/default/src/styles.d.ts +3 -1
- package/starters/default/src/vite-env.d.ts +1 -1
- package/starters/default/vite.config.ts +14 -1
- package/starters/modular/README.md +142 -0
- package/starters/modular/index.html +13 -0
- package/starters/modular/package.json +30 -0
- package/starters/modular/src/app.routes.ts +39 -0
- package/starters/{default → modular}/src/layouts/app-shell.layout.ts +8 -5
- package/starters/{default → modular}/src/layouts/auth-shell.layout.ts +3 -3
- package/starters/modular/src/main.ts +16 -0
- package/starters/{default → modular}/src/modules/billing/pages/invoices-list.page.ts +3 -3
- package/starters/{default → modular}/src/modules/home/home.page.ts +5 -7
- package/starters/modular/src/modules/home/not-found.page.ts +14 -0
- package/starters/modular/src/styles.d.ts +1 -0
- package/starters/modular/src/vite-env.d.ts +1 -0
- package/starters/modular/tsconfig.json +24 -0
- package/starters/modular/vite.config.ts +131 -0
- package/TODO.md +0 -79
- package/docs/en/01-routing.md +0 -152
- package/docs/en/02-project-layout.md +0 -124
- package/docs/en/03-static-bake.md +0 -249
- package/docs/en/04-ide-setup.md +0 -162
- package/docs/en/07-llm-pitfalls.md +0 -724
- package/docs/en/08-llm-zero-history-test.md +0 -56
- package/docs/en/09-shadow-vs-light-dom.md +0 -174
- package/docs/en/11-layouts.md +0 -113
- package/docs/en/12-auth-and-api.md +0 -124
- package/docs/en/16-bake-cookbook.md +0 -100
- package/docs/en/17-shadow-dom-forms.md +0 -192
- package/docs/fr/00-the-mado-way.md +0 -85
- package/docs/fr/01-routing.md +0 -120
- package/docs/fr/02-project-layout.md +0 -84
- package/docs/fr/03-static-bake.md +0 -289
- package/docs/fr/04-ide-setup.md +0 -162
- package/docs/fr/05-why-mado.md +0 -193
- package/docs/fr/06-for-backenders.md +0 -438
- package/docs/fr/07-llm-pitfalls.md +0 -625
- package/docs/fr/08-llm-zero-history-test.md +0 -38
- package/docs/fr/09-shadow-vs-light-dom.md +0 -65
- package/docs/fr/10-app-architecture.md +0 -138
- package/docs/fr/11-layouts.md +0 -47
- package/docs/fr/12-auth-and-api.md +0 -76
- package/docs/fr/13-deployment.md +0 -57
- package/docs/fr/14-testing.md +0 -41
- package/docs/fr/15-error-handling.md +0 -50
- package/docs/fr/16-bake-cookbook.md +0 -88
- package/docs/fr/17-shadow-dom-forms.md +0 -196
- package/docs/fr/18-api-freeze-map.md +0 -63
- package/docs/fr/19-reactivity-ordering.md +0 -97
- package/docs/fr/20-v1-stability.md +0 -88
- package/docs/fr/README.md +0 -27
- package/docs/ru/00-the-mado-way.md +0 -84
- package/docs/ru/01-routing.md +0 -119
- package/docs/ru/02-project-layout.md +0 -84
- package/docs/ru/03-static-bake.md +0 -250
- package/docs/ru/04-ide-setup.md +0 -144
- package/docs/ru/05-why-mado.md +0 -193
- package/docs/ru/06-for-backenders.md +0 -428
- package/docs/ru/07-llm-pitfalls.md +0 -624
- package/docs/ru/08-llm-zero-history-test.md +0 -57
- package/docs/ru/09-shadow-vs-light-dom.md +0 -63
- package/docs/ru/10-app-architecture.md +0 -152
- package/docs/ru/11-layouts.md +0 -47
- package/docs/ru/12-auth-and-api.md +0 -75
- package/docs/ru/13-deployment.md +0 -66
- package/docs/ru/14-testing.md +0 -50
- package/docs/ru/15-error-handling.md +0 -56
- package/docs/ru/16-bake-cookbook.md +0 -95
- package/docs/ru/17-shadow-dom-forms.md +0 -193
- package/docs/ru/18-api-freeze-map.md +0 -64
- package/docs/ru/19-reactivity-ordering.md +0 -95
- package/docs/ru/20-v1-stability.md +0 -82
- package/docs/ru/README.md +0 -25
- package/docs/uk/00-the-mado-way.md +0 -82
- package/docs/uk/01-routing.md +0 -76
- package/docs/uk/02-project-layout.md +0 -73
- package/docs/uk/03-static-bake.md +0 -48
- package/docs/uk/04-ide-setup.md +0 -26
- package/docs/uk/05-why-mado.md +0 -34
- package/docs/uk/06-for-backenders.md +0 -55
- package/docs/uk/07-llm-pitfalls.md +0 -145
- package/docs/uk/08-llm-zero-history-test.md +0 -34
- package/docs/uk/09-shadow-vs-light-dom.md +0 -58
- package/docs/uk/10-app-architecture.md +0 -97
- package/docs/uk/11-layouts.md +0 -47
- package/docs/uk/12-auth-and-api.md +0 -70
- package/docs/uk/13-deployment.md +0 -40
- package/docs/uk/14-testing.md +0 -34
- package/docs/uk/15-error-handling.md +0 -32
- package/docs/uk/16-bake-cookbook.md +0 -36
- package/docs/uk/17-shadow-dom-forms.md +0 -193
- package/docs/uk/18-api-freeze-map.md +0 -61
- package/docs/uk/19-reactivity-ordering.md +0 -95
- package/docs/uk/20-v1-stability.md +0 -83
- package/docs/uk/README.md +0 -27
- package/starters/default/src/modules/home/not-found.page.ts +0 -11
- /package/docs/en/{15-error-handling.md → 21-error-handling.md} +0 -0
- /package/docs/en/{19-reactivity-ordering.md → 31-reactivity-ordering.md} +0 -0
- /package/starters/{default → modular}/.editorconfig +0 -0
- /package/starters/{default → modular}/eslint.config.mjs +0 -0
- /package/starters/{default → modular}/public/favicon.svg +0 -0
- /package/starters/{default → modular}/src/modules/auth/_contracts/auth-api.types.ts +0 -0
- /package/starters/{default → modular}/src/modules/auth/auth.connector.ts +0 -0
- /package/starters/{default → modular}/src/modules/auth/auth.guard.ts +0 -0
- /package/starters/{default → modular}/src/modules/auth/auth.public.ts +0 -0
- /package/starters/{default → modular}/src/modules/auth/auth.routes.ts +0 -0
- /package/starters/{default → modular}/src/modules/auth/auth.service.ts +0 -0
- /package/starters/{default → modular}/src/modules/auth/auth.types.ts +0 -0
- /package/starters/{default → modular}/src/modules/auth/login.page.ts +0 -0
- /package/starters/{default → modular}/src/modules/billing/_contracts/stripe.types.ts +0 -0
- /package/starters/{default → modular}/src/modules/billing/api/stripe.connector.ts +0 -0
- /package/starters/{default → modular}/src/modules/billing/billing.public.ts +0 -0
- /package/starters/{default → modular}/src/modules/billing/billing.routes.ts +0 -0
- /package/starters/{default → modular}/src/modules/billing/billing.types.ts +0 -0
- /package/starters/{default → modular}/src/modules/billing/components/invoice-status-badge.component.ts +0 -0
- /package/starters/{default → modular}/src/modules/billing/data/invoices.resource.ts +0 -0
- /package/starters/{default → modular}/src/modules/billing/pages/invoice-detail.page.ts +0 -0
- /package/starters/{default → modular}/src/shared/http/http-client.ts +0 -0
- /package/starters/{default → modular}/src/shared/http/http-error.ts +0 -0
- /package/starters/{default → modular}/src/shared/http/interceptors.ts +0 -0
- /package/starters/{default → modular}/src/shared/lib/format-date.ts +0 -0
- /package/starters/{default → modular}/src/shared/styles/content.css +0 -0
- /package/starters/{default → modular}/src/shared/styles/reset.css +0 -0
- /package/starters/{default → modular}/src/shared/styles/shell.css +0 -0
- /package/starters/{default → modular}/src/shared/styles/tokens.css +0 -0
- /package/starters/{default → modular}/src/shared/ui/x-button.component.ts +0 -0
- /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.
|
package/docs/ru/01-routing.md
DELETED
|
@@ -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.
|