@madojs/mado 0.11.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +116 -32
- package/CHANGELOG.md +216 -1
- package/README.md +158 -173
- package/dist/src/component.d.ts +6 -3
- package/dist/src/component.d.ts.map +1 -0
- package/dist/src/component.js +163 -36
- package/dist/src/component.js.map +1 -1
- package/dist/src/context.d.ts +13 -32
- package/dist/src/context.d.ts.map +1 -0
- package/dist/src/context.js +73 -48
- package/dist/src/context.js.map +1 -1
- package/dist/src/css.d.ts +1 -0
- package/dist/src/css.d.ts.map +1 -0
- package/dist/src/css.js +34 -5
- package/dist/src/css.js.map +1 -1
- package/dist/src/devtools-hook.d.ts +14 -0
- package/dist/src/devtools-hook.d.ts.map +1 -0
- package/dist/src/devtools-hook.js +27 -0
- package/dist/src/devtools-hook.js.map +1 -0
- package/dist/src/devtools.d.ts +24 -22
- package/dist/src/devtools.d.ts.map +1 -0
- package/dist/src/devtools.js +230 -58
- package/dist/src/devtools.js.map +1 -1
- package/dist/src/diagnostics.d.ts +12 -0
- package/dist/src/diagnostics.d.ts.map +1 -0
- package/dist/src/diagnostics.js +68 -8
- package/dist/src/diagnostics.js.map +1 -1
- package/dist/src/each.d.ts +1 -5
- package/dist/src/each.d.ts.map +1 -0
- package/dist/src/each.js +0 -8
- package/dist/src/each.js.map +1 -1
- package/dist/src/forms.d.ts +27 -96
- package/dist/src/forms.d.ts.map +1 -0
- package/dist/src/forms.js +184 -394
- package/dist/src/forms.js.map +1 -1
- package/dist/src/head.d.ts +7 -6
- package/dist/src/head.d.ts.map +1 -0
- package/dist/src/head.js +8 -7
- package/dist/src/head.js.map +1 -1
- package/dist/src/html/bindings.d.ts +1 -0
- package/dist/src/html/bindings.d.ts.map +1 -0
- package/dist/src/html/bindings.js.map +1 -1
- package/dist/src/html/parser.d.ts +4 -5
- package/dist/src/html/parser.d.ts.map +1 -0
- package/dist/src/html/parser.js +64 -15
- package/dist/src/html/parser.js.map +1 -1
- package/dist/src/html/template-types.d.ts +1 -0
- package/dist/src/html/template-types.d.ts.map +1 -0
- package/dist/src/html/template-types.js.map +1 -1
- package/dist/src/html/template.d.ts +5 -1
- package/dist/src/html/template.d.ts.map +1 -0
- package/dist/src/html/template.js +102 -13
- package/dist/src/html/template.js.map +1 -1
- package/dist/src/index.d.ts +15 -12
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +18 -10
- package/dist/src/index.js.map +1 -1
- package/dist/src/json.d.ts +3 -0
- package/dist/src/json.d.ts.map +1 -0
- package/dist/src/json.js +14 -0
- package/dist/src/json.js.map +1 -0
- package/dist/src/lifecycle.d.ts +1 -0
- package/dist/src/lifecycle.d.ts.map +1 -0
- package/dist/src/lifecycle.js +3 -2
- package/dist/src/lifecycle.js.map +1 -1
- package/dist/src/page.d.ts +63 -28
- package/dist/src/page.d.ts.map +1 -0
- package/dist/src/page.js +5 -0
- package/dist/src/page.js.map +1 -1
- package/dist/src/persisted.d.ts +6 -1
- package/dist/src/persisted.d.ts.map +1 -0
- package/dist/src/persisted.js +17 -11
- package/dist/src/persisted.js.map +1 -1
- package/dist/src/resource.d.ts +2 -1
- package/dist/src/resource.d.ts.map +1 -0
- package/dist/src/resource.js +128 -50
- package/dist/src/resource.js.map +1 -1
- package/dist/src/router/base.d.ts +66 -0
- package/dist/src/router/base.d.ts.map +1 -0
- package/dist/src/router/base.js +168 -0
- package/dist/src/router/base.js.map +1 -0
- package/dist/src/router/manifest.d.ts +1 -0
- package/dist/src/router/manifest.d.ts.map +1 -0
- package/dist/src/router/manifest.js +156 -171
- package/dist/src/router/manifest.js.map +1 -1
- package/dist/src/router/match.d.ts +17 -2
- package/dist/src/router/match.d.ts.map +1 -0
- package/dist/src/router/match.js +60 -6
- package/dist/src/router/match.js.map +1 -1
- package/dist/src/router/navigation.d.ts +1 -0
- package/dist/src/router/navigation.d.ts.map +1 -0
- package/dist/src/router/navigation.js +58 -9
- package/dist/src/router/navigation.js.map +1 -1
- package/dist/src/signal.d.ts +1 -0
- package/dist/src/signal.d.ts.map +1 -0
- package/dist/src/signal.js +46 -17
- package/dist/src/signal.js.map +1 -1
- package/dist/src/static-runtime.d.ts +82 -0
- package/dist/src/static-runtime.d.ts.map +1 -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 +32 -3
- package/dist/src/vite/index.d.ts.map +1 -0
- package/dist/src/vite/index.js +49 -17
- 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/architecture/v1-roadmap.md +19 -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 +279 -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 +227 -0
- package/docs/en/14-forms.md +91 -0
- package/docs/en/15-static-snapshots.md +181 -0
- package/docs/en/{10-app-architecture.md → 16-app-architecture.md} +56 -4
- package/docs/en/{13-deployment.md → 20-deployment.md} +79 -17
- package/docs/en/{15-error-handling.md → 21-error-handling.md} +9 -6
- package/docs/en/{14-testing.md → 22-testing.md} +6 -5
- package/docs/en/23-cookbook.md +292 -0
- package/docs/en/24-devtools-and-diagnostics.md +45 -0
- package/docs/en/{18-api-freeze-map.md → 30-api-freeze-map.md} +17 -9
- package/docs/en/{20-v1-stability.md → 32-v1-stability.md} +5 -5
- package/docs/en/33-migration-0.12-0.13.md +56 -0
- package/docs/en/40-llm-guide.md +774 -0
- package/docs/en/{06-for-backenders.md → 41-for-backenders.md} +28 -25
- package/docs/en/{05-why-mado.md → 42-why-mado.md} +3 -3
- package/docs/en/README.md +99 -27
- package/docs/recipes/nginx/Containerfile +26 -0
- package/docs/recipes/nginx/nginx.conf +42 -0
- package/llms.txt +263 -210
- package/package.json +51 -23
- package/scripts/clean.mjs +8 -0
- package/scripts/cli/generate.mjs +57 -10
- package/scripts/cli/help.mjs +13 -5
- package/scripts/cli/index.mjs +31 -7
- package/scripts/cli/init.mjs +19 -19
- package/scripts/cli/release.mjs +38 -83
- package/scripts/cli/run.mjs +5 -3
- package/scripts/logger.mjs +117 -0
- package/scripts/output-guard.mjs +128 -0
- package/scripts/preview.mjs +105 -24
- package/scripts/static/browser.mjs +695 -0
- package/scripts/static/discover.mjs +284 -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 +205 -0
- package/starters/default/README.md +57 -55
- package/starters/default/package.json +6 -12
- 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/tsconfig.node.json +13 -0
- package/starters/default/vite.config.ts +14 -4
- 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 +9 -7
- 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/auth/login.page.ts +5 -12
- package/starters/{default → modular}/src/modules/billing/pages/invoice-detail.page.ts +3 -4
- package/starters/{default → modular}/src/modules/billing/pages/invoices-list.page.ts +4 -4
- 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/{default → modular}/src/shared/styles/reset.css +21 -1
- package/starters/modular/src/styles.d.ts +1 -0
- package/starters/modular/src/vite-env.d.ts +1 -0
- package/starters/modular/tsconfig.json +33 -0
- package/starters/modular/tsconfig.node.json +13 -0
- package/starters/modular/vite.config.ts +132 -0
- package/TODO.md +0 -79
- package/dist/src/lazy.d.ts +0 -38
- package/dist/src/lazy.js +0 -73
- package/dist/src/lazy.js.map +0 -1
- 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/scripts/bake.mjs +0 -570
- package/scripts/package-smoke.mjs +0 -77
- package/scripts/release-notes.mjs +0 -66
- package/scripts/size-budget.mjs +0 -91
- package/starters/default/src/modules/home/not-found.page.ts +0 -11
- package/starters/default/src/shared/ui/x-button.component.ts +0 -49
- /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/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/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/shell.css +0 -0
- /package/starters/{default → modular}/src/shared/styles/tokens.css +0 -0
- /package/starters/{default → modular}/src/shared/ui/x-spinner.component.ts +0 -0
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
# Shadow DOM + формы
|
|
2
|
-
|
|
3
|
-
Использование `useForm()` с кастомными input-компонентами в Shadow DOM требует
|
|
4
|
-
знания двух поведений на уровне браузера:
|
|
5
|
-
|
|
6
|
-
1. **Ретаргетинг событий** — события, всплывающие из Shadow DOM, получают
|
|
7
|
-
`e.target`, перенаправленный на host-элемент. `useForm().onInput` читает
|
|
8
|
-
`e.target.name` и `e.target.value`, но host-элемент `<x-input>`
|
|
9
|
-
не имеет этих свойств нативно.
|
|
10
|
-
|
|
11
|
-
2. **Ассоциация с формой** — `<button type="submit">` внутри Shadow Root
|
|
12
|
-
НЕ участвует в алгоритме form-owner для `<form>` в Light DOM. Клик по ней
|
|
13
|
-
не триггерит submit формы.
|
|
14
|
-
|
|
15
|
-
Оба ограничения — на уровне спецификации, не баги Mado. Но фреймворк предоставляет
|
|
16
|
-
паттерны, которые делают их безболезненными.
|
|
17
|
-
|
|
18
|
-
## Паттерн: Proxy-свойства на input-компонентах
|
|
19
|
-
|
|
20
|
-
Оборачивая `<input>` в Shadow DOM компонент, экспонируйте `name` и `value`
|
|
21
|
-
как DOM-свойства на host, чтобы `useForm().onInput` работал после ретаргетинга:
|
|
22
|
-
|
|
23
|
-
```ts
|
|
24
|
-
import { component, css, html } from "@madojs/mado";
|
|
25
|
-
|
|
26
|
-
component("x-input", ({ host, attr }) => {
|
|
27
|
-
const name = attr("name", "");
|
|
28
|
-
const type = attr("type", "text");
|
|
29
|
-
const value = attr("value", "");
|
|
30
|
-
|
|
31
|
-
// Proxy-свойства для совместимости с useForm().
|
|
32
|
-
// После ретаргетинга Shadow DOM e.target из <input> → <x-input>,
|
|
33
|
-
// useForm читает e.target.name / e.target.value — эти геттеры наводят мост.
|
|
34
|
-
Object.defineProperty(host, "name", {
|
|
35
|
-
get: () => host.getAttribute("name") ?? "",
|
|
36
|
-
configurable: true,
|
|
37
|
-
});
|
|
38
|
-
Object.defineProperty(host, "value", {
|
|
39
|
-
get: () => host.shadowRoot?.querySelector("input")?.value ?? "",
|
|
40
|
-
set: (v: string) => {
|
|
41
|
-
const input = host.shadowRoot?.querySelector("input");
|
|
42
|
-
if (input) input.value = v;
|
|
43
|
-
},
|
|
44
|
-
configurable: true,
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
return () => html`<input name=${name} type=${type} .value=${value} />`;
|
|
48
|
-
});
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
Событие `input` от внутреннего `<input>` имеет `composed: true` по умолчанию,
|
|
52
|
-
поэтому оно всплывает через границу shadow. После ретаргетинга `e.target` —
|
|
53
|
-
это `<x-input>`, но теперь у него есть геттеры `.name` и `.value` → `useForm`
|
|
54
|
-
работает.
|
|
55
|
-
|
|
56
|
-
## Паттерн: Submit формы из Shadow DOM кнопок
|
|
57
|
-
|
|
58
|
-
`<button type="submit">` внутри Shadow DOM не может триггерить submit `<form>`
|
|
59
|
-
в Light DOM. Мост через `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")` работает, потому что сам host-элемент живёт в Light DOM
|
|
83
|
-
(только его внутренности в тени). `requestSubmit()` триггерит валидацию и
|
|
84
|
-
событие `submit` точно так, как если бы пользователь кликнул нативную submit-кнопку
|
|
85
|
-
внутри формы.
|
|
86
|
-
|
|
87
|
-
## Паттерн: Реактивные атрибуты через ctx.attr()
|
|
88
|
-
|
|
89
|
-
С версии 0.7 `ctx.attr(name, defaultValue?)` возвращает `Signal<string>`,
|
|
90
|
-
который автоматически обновляется при изменении атрибута на host. Никакого
|
|
91
|
-
`MutationObserver` бойлерплейта:
|
|
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
|
-
Родитель может использовать `?disabled=${() => !form.isValid()}` (boolean атрибут)
|
|
105
|
-
или `.variant=${"danger"}` — компонент перерендеривается реактивно в любом случае.
|
|
106
|
-
|
|
107
|
-
## Полный пример формы
|
|
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: "Вход",
|
|
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="Пароль"
|
|
146
|
-
required
|
|
147
|
-
@input=${form.onInput}
|
|
148
|
-
@blur=${form.onBlur}
|
|
149
|
-
></x-input>
|
|
150
|
-
|
|
151
|
-
<x-button type="submit" ?disabled=${() => !form.isValid()}>
|
|
152
|
-
Войти
|
|
153
|
-
</x-button>
|
|
154
|
-
</form>
|
|
155
|
-
`;
|
|
156
|
-
},
|
|
157
|
-
});
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
## Когда использовать Light DOM
|
|
161
|
-
|
|
162
|
-
Если ваш input-компонент — это просто стилизованная обёртка без нужды в
|
|
163
|
-
инкапсуляции, `shadow: false` избегает обеих проблем (ретаргетинг и
|
|
164
|
-
form-association):
|
|
165
|
-
|
|
166
|
-
```ts
|
|
167
|
-
component(
|
|
168
|
-
"x-field",
|
|
169
|
-
({ attr }) => {
|
|
170
|
-
const label = attr("label", "");
|
|
171
|
-
return () => html`
|
|
172
|
-
<label>
|
|
173
|
-
<span>${label}</span>
|
|
174
|
-
<slot></slot>
|
|
175
|
-
</label>
|
|
176
|
-
`;
|
|
177
|
-
},
|
|
178
|
-
{ shadow: false },
|
|
179
|
-
);
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
С Light DOM нативный `<input>` — часть дерева документа, события не
|
|
183
|
-
ретаргетируются, и submit формы работает нативно. Компромисс: стили не
|
|
184
|
-
инкапсулированы (нужно скоупить самостоятельно).
|
|
185
|
-
|
|
186
|
-
## Итого
|
|
187
|
-
|
|
188
|
-
| Задача | Решение Shadow DOM | Альтернатива Light DOM |
|
|
189
|
-
| --------------------------- | -------------------------------------- | --------------------------- |
|
|
190
|
-
| `useForm` + кастомный input | Proxy `name`/`value` на host | Нативный `<input>` в slot |
|
|
191
|
-
| Submit формы | `form.requestSubmit()` в click handler | Нативная кнопка работает |
|
|
192
|
-
| Реактивные атрибуты | `ctx.attr()` → авто-сигнал | `ctx.attr()` работает везде |
|
|
193
|
-
| Инкапсуляция стилей | Да (автоматически) | Ручной `@scope` или BEM |
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
# Карта заморозки API
|
|
2
|
-
|
|
3
|
-
> Что публично, что внутреннее, и что SemVer будет защищать в v1.
|
|
4
|
-
|
|
5
|
-
Контракт Mado v1 намеренно небольшой. Код приложения импортирует API из корня
|
|
6
|
-
пакета:
|
|
7
|
-
|
|
8
|
-
```ts
|
|
9
|
-
import { component, html, resource, routes, signal } from "@madojs/mado";
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
Публичные subpaths — side-effect модуль devtools и Vite integration:
|
|
13
|
-
|
|
14
|
-
```ts
|
|
15
|
-
import "@madojs/mado/devtools.js";
|
|
16
|
-
import { mado } from "@madojs/mado/vite";
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
Все остальное под `dist/src/` — деталь реализации, даже если файл виден в
|
|
20
|
-
репозитории.
|
|
21
|
-
|
|
22
|
-
## Стабильный публичный API
|
|
23
|
-
|
|
24
|
-
Эти имена публичны и будут защищены SemVer после v1:
|
|
25
|
-
|
|
26
|
-
- Reactivity: `signal`, `computed`, `effect`, `untracked`, `batch`,
|
|
27
|
-
`flushSync`.
|
|
28
|
-
- Templates и directives: `html`, `render`, `each`, `list`, `unsafeHTML`,
|
|
29
|
-
`ref`, `classMap`, `styleMap`.
|
|
30
|
-
- Components и CSS: `component`, `css`, `cssVars`.
|
|
31
|
-
- Routing и pages: `routes`, `router`, `page`, `layout`,
|
|
32
|
-
`navigate`, `queryParam`, `prefetchPath`.
|
|
33
|
-
- Data: `resource`, `mutation`, `invalidate`, `jsonFetcher`, `HttpError`.
|
|
34
|
-
- Forms: `useForm`.
|
|
35
|
-
- Head и persistence: `applyHead`, `persisted`.
|
|
36
|
-
- Context: `createContext`, `provide`, `inject`.
|
|
37
|
-
- Advanced lifecycle helpers: `createLifecycle`, `runInLifecycle`,
|
|
38
|
-
`getCurrentLifecycle`.
|
|
39
|
-
- Публичные TypeScript-типы, экспортируемые из `@madojs/mado`.
|
|
40
|
-
|
|
41
|
-
## Внутреннее или нестабильное
|
|
42
|
-
|
|
43
|
-
Это не публичный API:
|
|
44
|
-
|
|
45
|
-
- Package subpaths кроме `@madojs/mado`, `@madojs/mado/devtools.js` и
|
|
46
|
-
`@madojs/mado/vite`.
|
|
47
|
-
- Internals парсера/биндингов: `html/parser.js`, `html/bindings.js`,
|
|
48
|
-
`ChildState`, `EachEntry`.
|
|
49
|
-
- Internals роутера: `router/match.js`, `router/navigation.js`,
|
|
50
|
-
`router/manifest.js`.
|
|
51
|
-
- Diagnostics internals и все `_testHooks`.
|
|
52
|
-
- Точный текст bundle, имена chunks и внутренняя структура файлов.
|
|
53
|
-
|
|
54
|
-
Тесты репозитория могут импортировать внутренние файлы через относительные
|
|
55
|
-
пути `dist/`. Код приложений так делать не должен.
|
|
56
|
-
|
|
57
|
-
## Что может меняться
|
|
58
|
-
|
|
59
|
-
Patch и minor релизы могут добавлять root exports, опции, diagnostics, docs или
|
|
60
|
-
starter files. Они также могут менять internals, форму bundle и детали
|
|
61
|
-
реализации, если стабильный API и задокументированное поведение остаются
|
|
62
|
-
совместимыми.
|
|
63
|
-
|
|
64
|
-
Ломающие изменения стабильного API требуют major version.
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
# Порядок reactivity
|
|
2
|
-
|
|
3
|
-
> Небольшой набор ordering-гарантий, которые Mado считает публичным поведением.
|
|
4
|
-
|
|
5
|
-
Reactivity в Mado синхронна для чтения и планирует side effects. Цель —
|
|
6
|
-
предсказуемые UI-обновления без большой scheduling-модели.
|
|
7
|
-
|
|
8
|
-
## Signals
|
|
9
|
-
|
|
10
|
-
`signal(value)` возвращает getter-функцию. `set(next)` меняет значение сразу,
|
|
11
|
-
если `Object.is(previous, next)` не вернул `true`.
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
const count = signal(0);
|
|
15
|
-
count.set(1);
|
|
16
|
-
count(); // 1, сразу
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
`computed` помечается до запуска effects, поэтому effect, читающий computed,
|
|
20
|
-
видит актуальные dependencies, а не старый кеш.
|
|
21
|
-
|
|
22
|
-
## Effects
|
|
23
|
-
|
|
24
|
-
`effect(fn)` запускается один раз сразу. Последующие изменения dependencies
|
|
25
|
-
планируют один запуск effect в microtask. В тестах можно вызвать `flushSync()`,
|
|
26
|
-
чтобы синхронно очистить очередь.
|
|
27
|
-
|
|
28
|
-
Если effect возвращает cleanup-функцию, Mado запускает ее перед следующим
|
|
29
|
-
запуском effect и еще раз при вызове disposer.
|
|
30
|
-
|
|
31
|
-
```ts
|
|
32
|
-
const stop = effect(() => {
|
|
33
|
-
const id = setInterval(tick, 1000);
|
|
34
|
-
return () => clearInterval(id);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
stop();
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
В компонентах и pages для unmount cleanup предпочитайте `ctx.onDispose()` /
|
|
41
|
-
page `onDispose()`. Cleanup effect — это cleanup между запусками.
|
|
42
|
-
|
|
43
|
-
## Batch
|
|
44
|
-
|
|
45
|
-
`batch(fn)` группирует записи signals в один subscriber pass. Effects не
|
|
46
|
-
запускаются до выхода из внешнего batch, включая вложенные batches.
|
|
47
|
-
|
|
48
|
-
```ts
|
|
49
|
-
batch(() => {
|
|
50
|
-
first.set("Ada");
|
|
51
|
-
batch(() => last.set("Lovelace"));
|
|
52
|
-
});
|
|
53
|
-
// effects увидят только финальную пару
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
Наблюдаемые `computed({ equals })` также сохраняют batch atomicity: они
|
|
57
|
-
пересчитываются один раз после внешнего batch на полностью примененном state.
|
|
58
|
-
Они не должны видеть половинчатый batch вроде `(new x, old y)`.
|
|
59
|
-
|
|
60
|
-
## DOM updates
|
|
61
|
-
|
|
62
|
-
`render(result, container)` переиспользует существующий template instance, когда
|
|
63
|
-
следующий render имеет те же template strings. Для child bindings, возвращающих
|
|
64
|
-
вложенный `html```, действует то же правило: те же strings обновляются на
|
|
65
|
-
месте, другие strings пересобирают ветку.
|
|
66
|
-
|
|
67
|
-
Это значит, что несвязанные изменения signals не пересоздают `<input>` внутри
|
|
68
|
-
стабильного вложенного template, поэтому focus, DOM state и listeners
|
|
69
|
-
сохраняются.
|
|
70
|
-
|
|
71
|
-
Списки должны использовать `each(items, key, renderItem)`. Keys задают DOM
|
|
72
|
-
identity. Duplicate keys предупреждают в development и получают positional
|
|
73
|
-
suffix, чтобы все элементы все равно отрендерились, но duplicate keys — это
|
|
74
|
-
ошибка данных.
|
|
75
|
-
|
|
76
|
-
## Teardown компонентов
|
|
77
|
-
|
|
78
|
-
Custom elements могут получить `disconnectedCallback()`, а затем
|
|
79
|
-
`connectedCallback()` во время same-tick move. Mado откладывает teardown
|
|
80
|
-
компонента до microtask и отменяет его при reconnect, поэтому keyed reorders
|
|
81
|
-
сохраняют state компонента. Настоящее удаление все равно запускает cleanup на
|
|
82
|
-
следующей microtask.
|
|
83
|
-
|
|
84
|
-
## Не гарантируется
|
|
85
|
-
|
|
86
|
-
Mado не гарантирует точное число внутренних scheduler microtasks, порядок
|
|
87
|
-
независимых effects без общих dependencies, форму generated bundle или
|
|
88
|
-
внутреннюю структуру modules. Это детали реализации.
|
|
89
|
-
|
|
90
|
-
Invariant tests для этого контракта:
|
|
91
|
-
|
|
92
|
-
- `test/reactivity-ordering.test.mjs`
|
|
93
|
-
- `test/signal-batch-equals.test.mjs`
|
|
94
|
-
- `test/update-nested-reuse.test.mjs`
|
|
95
|
-
- `test/each-component-state.test.mjs`
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
# Стабильность v1
|
|
2
|
-
|
|
3
|
-
> Что Mado обещает после v1, и что остается свободным для развития.
|
|
4
|
-
|
|
5
|
-
Mado v1 означает, что публичный app-facing contract достаточно стабилен для
|
|
6
|
-
реальных business apps. Это не значит, что каждый внутренний файл, generated
|
|
7
|
-
byte, starter copy или diagnostic string заморожены навсегда.
|
|
8
|
-
|
|
9
|
-
Читайте вместе с:
|
|
10
|
-
|
|
11
|
-
- [Карта заморозки API](./18-api-freeze-map.md)
|
|
12
|
-
- [Порядок reactivity](./19-reactivity-ordering.md)
|
|
13
|
-
|
|
14
|
-
## Стабильно под SemVer
|
|
15
|
-
|
|
16
|
-
После v1 Mado считает SemVer-protected:
|
|
17
|
-
|
|
18
|
-
- Public exports из `@madojs/mado`.
|
|
19
|
-
- Public TypeScript types из `@madojs/mado`.
|
|
20
|
-
- Side-effect subpath `@madojs/mado/devtools.js`.
|
|
21
|
-
- Template binding syntax: child `${}`, `@event`, `.prop`, `?boolean`,
|
|
22
|
-
attribute bindings, directives и `each()`.
|
|
23
|
-
- Signal semantics, описанные в reactivity ordering guide.
|
|
24
|
-
- Component lifecycle semantics: setup один раз за connection lifetime,
|
|
25
|
-
deferred teardown для same-tick moves, cleanup через `ctx.onDispose`.
|
|
26
|
-
- Router/page/resource/form contracts, описанные в English docs.
|
|
27
|
-
- Имена CLI commands и широкий смысл команд (`build`, `dev`, `release`,
|
|
28
|
-
`bake`, `preview`, `init`, `new`).
|
|
29
|
-
|
|
30
|
-
Ломать это можно только в major version.
|
|
31
|
-
|
|
32
|
-
## Разрешено в minor releases
|
|
33
|
-
|
|
34
|
-
Minor releases могут добавлять:
|
|
35
|
-
|
|
36
|
-
- New root exports.
|
|
37
|
-
- New options на существующих API.
|
|
38
|
-
- New diagnostics и warnings.
|
|
39
|
-
- New starters, examples, docs и CLI flags.
|
|
40
|
-
- Performance improvements и внутренние rewrites.
|
|
41
|
-
|
|
42
|
-
Minor release не должен требовать изменений в уже корректных apps.
|
|
43
|
-
|
|
44
|
-
## Разрешено в patch releases
|
|
45
|
-
|
|
46
|
-
Patch releases могут исправлять bugs, ужесточать diagnostics, улучшать docs и
|
|
47
|
-
делать совместимые implementation changes. Patch может изменить timing только
|
|
48
|
-
когда старый timing был незадокументированным bug и новое поведение сохраняет
|
|
49
|
-
reactivity ordering contract.
|
|
50
|
-
|
|
51
|
-
## Нестабильно
|
|
52
|
-
|
|
53
|
-
Это намеренно не защищено SemVer:
|
|
54
|
-
|
|
55
|
-
- Internal package subpaths кроме `@madojs/mado/devtools.js`.
|
|
56
|
-
- Файлы под `src/`, `dist/src/` и implementation module boundaries.
|
|
57
|
-
- `_testHooks`, diagnostics internals и warning codes.
|
|
58
|
-
- Точный JavaScript output, chunk names, sourcemap content и bundle byte layout.
|
|
59
|
-
- Internal parser, binding, router и resource cache data structures.
|
|
60
|
-
- Visual copy и demo data в starters.
|
|
61
|
-
|
|
62
|
-
Apps не должны импортировать internal files или проверять точный bundle output.
|
|
63
|
-
|
|
64
|
-
## Bundle и release output
|
|
65
|
-
|
|
66
|
-
Mado держит size budget и deterministic release tests, но v1 stability не
|
|
67
|
-
замораживает byte-for-byte bundler output. Hashes, chunk boundaries и asset
|
|
68
|
-
names могут меняться, если задокументированный deployment contract продолжает
|
|
69
|
-
работать.
|
|
70
|
-
|
|
71
|
-
## Если релиз вас сломал
|
|
72
|
-
|
|
73
|
-
Если update ломает код, который использует только public exports и
|
|
74
|
-
задокументированное поведение, считайте это bug. Откройте issue и укажите:
|
|
75
|
-
|
|
76
|
-
- версию Mado до и после;
|
|
77
|
-
- задействованный public API;
|
|
78
|
-
- минимальную репродукцию;
|
|
79
|
-
- это runtime behaviour, TypeScript types, CLI output или docs.
|
|
80
|
-
|
|
81
|
-
Если поломка зависит от internal subpath или точного generated output, ее все
|
|
82
|
-
равно можно зарепортить, но это не считается SemVer break.
|
package/docs/ru/README.md
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# Mado docs — Русский
|
|
2
|
-
|
|
3
|
-
| Раздел | Файл |
|
|
4
|
-
| --------------------------- | ------------------------------------------------------------ |
|
|
5
|
-
| Принципы | [00-the-mado-way.md](./00-the-mado-way.md) |
|
|
6
|
-
| Маршрутизация | [01-routing.md](./01-routing.md) |
|
|
7
|
-
| Структура проекта | [02-project-layout.md](./02-project-layout.md) |
|
|
8
|
-
| Статический bake и SEO | [03-static-bake.md](./03-static-bake.md) |
|
|
9
|
-
| Настройка IDE | [04-ide-setup.md](./04-ide-setup.md) |
|
|
10
|
-
| Почему Mado | [05-why-mado.md](./05-why-mado.md) |
|
|
11
|
-
| Для бекендеров | [06-for-backenders.md](./06-for-backenders.md) |
|
|
12
|
-
| Типичные ошибки LLM | [07-llm-pitfalls.md](./07-llm-pitfalls.md) |
|
|
13
|
-
| Тест LLM с нулевой историей | [08-llm-zero-history-test.md](./08-llm-zero-history-test.md) |
|
|
14
|
-
| Shadow DOM vs Light DOM | [09-shadow-vs-light-dom.md](./09-shadow-vs-light-dom.md) |
|
|
15
|
-
| Архитектура приложения | [10-app-architecture.md](./10-app-architecture.md) |
|
|
16
|
-
| Макеты (layouts) | [11-layouts.md](./11-layouts.md) |
|
|
17
|
-
| Авторизация и API | [12-auth-and-api.md](./12-auth-and-api.md) |
|
|
18
|
-
| Развёртывание | [13-deployment.md](./13-deployment.md) |
|
|
19
|
-
| Тестирование | [14-testing.md](./14-testing.md) |
|
|
20
|
-
| Обработка ошибок | [15-error-handling.md](./15-error-handling.md) |
|
|
21
|
-
| Рецепты bake | [16-bake-cookbook.md](./16-bake-cookbook.md) |
|
|
22
|
-
| Shadow DOM + формы | [17-shadow-dom-forms.md](./17-shadow-dom-forms.md) |
|
|
23
|
-
| Карта заморозки API | [18-api-freeze-map.md](./18-api-freeze-map.md) |
|
|
24
|
-
| Порядок reactivity | [19-reactivity-ordering.md](./19-reactivity-ordering.md) |
|
|
25
|
-
| Стабильность v1 | [20-v1-stability.md](./20-v1-stability.md) |
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
# Шлях Mado
|
|
2
|
-
|
|
3
|
-
> Один зрозумілий шлях. Жорсткі контракти. Мінімум магії.
|
|
4
|
-
|
|
5
|
-
Mado — framework для команд, що будують admin panels, internal tools і
|
|
6
|
-
business SPA. Такі apps мають бути простими у розробці та нудними в підтримці,
|
|
7
|
-
тому Mado обирає чіткі conventions замість п'яти рівноправних стилів.
|
|
8
|
-
|
|
9
|
-
## Principles
|
|
10
|
-
|
|
11
|
-
1. **One way.** If code feels unusual, first check whether a canonical helper/API
|
|
12
|
-
already exists.
|
|
13
|
-
2. **Explicit over magic.** No file-system scanners, implicit globals or hidden
|
|
14
|
-
side effects.
|
|
15
|
-
3. **Platform first.** Web Components, History API, `<form>`, `fetch` and Shadow
|
|
16
|
-
DOM stay visible.
|
|
17
|
-
4. **Strict types.** `tsc --strict --noUncheckedIndexedAccess` always.
|
|
18
|
-
5. **No runtime dependencies.** Dev/build tooling is fine; Mado runtime stays
|
|
19
|
-
native.
|
|
20
|
-
|
|
21
|
-
## Project Structure
|
|
22
|
-
|
|
23
|
-
```txt
|
|
24
|
-
src/
|
|
25
|
-
├── main.ts ← boot: global CSS/providers + render router
|
|
26
|
-
├── app.routes.ts ← readable app map, exports `manifest` + default routes()
|
|
27
|
-
├── layouts/ ← app-zone wrappers (`page({ view: ({ child }) => ... })`)
|
|
28
|
-
├── shared/ ← UI bricks, http client, pure lib, global CSS
|
|
29
|
-
└── modules/ ← bounded contexts
|
|
30
|
-
└── billing/
|
|
31
|
-
├── billing.routes.ts
|
|
32
|
-
├── billing.public.ts
|
|
33
|
-
├── billing.types.ts
|
|
34
|
-
├── pages/
|
|
35
|
-
├── data/
|
|
36
|
-
├── api/
|
|
37
|
-
└── _contracts/
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
The default starter is the canonical version of this shape.
|
|
41
|
-
|
|
42
|
-
## One Component = One File
|
|
43
|
-
|
|
44
|
-
```ts
|
|
45
|
-
import { component, css, html } from "@madojs/mado";
|
|
46
|
-
|
|
47
|
-
component("x-user-card", () => () => html`<div class="card"><slot></slot></div>`, {
|
|
48
|
-
styles: css`
|
|
49
|
-
.card { padding: 1rem; }
|
|
50
|
-
`,
|
|
51
|
-
});
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Importing the component file registers the element. Import it where the tag is
|
|
55
|
-
used.
|
|
56
|
-
|
|
57
|
-
## One Way To Describe A Page
|
|
58
|
-
|
|
59
|
-
```ts
|
|
60
|
-
import { html, page, resource, jsonFetcher } from "@madojs/mado";
|
|
61
|
-
|
|
62
|
-
export default page({
|
|
63
|
-
title: ({ id }) => `User #${id}`,
|
|
64
|
-
view: ({ params }) => {
|
|
65
|
-
const user = resource(() => `/api/users/${params.id}`, jsonFetcher());
|
|
66
|
-
return html`...`;
|
|
67
|
-
},
|
|
68
|
-
});
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Page-local signals, resources and forms live inside `view()`. Module-wide state
|
|
72
|
-
lives in `*.service.ts`.
|
|
73
|
-
|
|
74
|
-
## What We Do Not Do
|
|
75
|
-
|
|
76
|
-
- No JSX/Vue/Svelte syntax.
|
|
77
|
-
- No custom elements without a hyphen.
|
|
78
|
-
- No signal `.value`; a signal is a function.
|
|
79
|
-
- No direct `innerHTML`.
|
|
80
|
-
- No runtime packages without discussion.
|
|
81
|
-
|
|
82
|
-
When in doubt, document one clear recipe instead of adding a new core primitive.
|
package/docs/uk/01-routing.md
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
# Routing
|
|
2
|
-
|
|
3
|
-
> One app map. No folder scanners. No magic path syntax.
|
|
4
|
-
|
|
5
|
-
Mado uses an explicit route manifest. Route composition should be readable in
|
|
6
|
-
one place: `src/app.routes.ts`.
|
|
7
|
-
|
|
8
|
-
```ts
|
|
9
|
-
import { layout, routes } from "@madojs/mado";
|
|
10
|
-
import { requireAuth } from "./modules/auth/auth.public";
|
|
11
|
-
import { authRoutes } from "./modules/auth/auth.routes";
|
|
12
|
-
import { billingRoutes } from "./modules/billing/billing.routes";
|
|
13
|
-
|
|
14
|
-
export const manifest = {
|
|
15
|
-
"/": () => import("./modules/home/home.page.js"),
|
|
16
|
-
"/login": layout({
|
|
17
|
-
layout: () => import("./layouts/auth-shell.layout.js"),
|
|
18
|
-
routes: authRoutes,
|
|
19
|
-
}),
|
|
20
|
-
"/billing": layout({
|
|
21
|
-
layout: () => import("./layouts/app-shell.layout.js"),
|
|
22
|
-
guard: requireAuth,
|
|
23
|
-
routes: billingRoutes,
|
|
24
|
-
}),
|
|
25
|
-
"*": () => import("./modules/home/not-found.page.js"),
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export default routes(manifest);
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
Export `manifest` so `mado bake` can read it.
|
|
32
|
-
|
|
33
|
-
## Module Routes
|
|
34
|
-
|
|
35
|
-
Modules export plain route maps. They do not call `layout()`.
|
|
36
|
-
|
|
37
|
-
```ts
|
|
38
|
-
export const billingRoutes = {
|
|
39
|
-
"/invoices": () => import("./pages/invoices-list.page.js"),
|
|
40
|
-
"/invoices/:id": () => import("./pages/invoice-detail.page.js"),
|
|
41
|
-
};
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
The prefix is applied by `src/app.routes.ts`.
|
|
45
|
-
|
|
46
|
-
## Page
|
|
47
|
-
|
|
48
|
-
```ts
|
|
49
|
-
import { html, page } from "@madojs/mado";
|
|
50
|
-
|
|
51
|
-
export default page<{ id: string }>({
|
|
52
|
-
title: ({ id }) => `User ${id}`,
|
|
53
|
-
view: ({ params }) => html`<h1>${params.id}</h1>`,
|
|
54
|
-
});
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
## Navigation
|
|
58
|
-
|
|
59
|
-
```ts
|
|
60
|
-
import appRoutes from "./app.routes.js";
|
|
61
|
-
|
|
62
|
-
appRoutes.navigate("/billing/invoices");
|
|
63
|
-
appRoutes.navigate("/billing/invoices?page=2");
|
|
64
|
-
appRoutes.navigate("/login", { replace: true });
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## Query Params
|
|
68
|
-
|
|
69
|
-
```ts
|
|
70
|
-
import { queryParam } from "@madojs/mado";
|
|
71
|
-
|
|
72
|
-
const search = queryParam("q", "");
|
|
73
|
-
search.set("mado");
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
`queryParam()` returns a signal-like API and syncs state with the URL.
|