@madojs/mado 0.5.0 → 0.5.1
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 +23 -1
- package/CHANGELOG.md +35 -0
- package/README.md +23 -2
- package/ROADMAP.md +12 -2
- package/dist/src/forms.d.ts +4 -3
- package/dist/src/forms.js +3 -2
- package/dist/src/forms.js.map +1 -1
- package/dist/src/router/navigation.js +2 -9
- package/dist/src/router/navigation.js.map +1 -1
- package/docs/en/05-why-mado.md +1 -1
- package/docs/en/06-for-backenders.md +1 -1
- package/docs/en/07-llm-pitfalls.md +1 -1
- package/docs/en/09-shadow-vs-light-dom.md +60 -0
- package/docs/fr/05-why-mado.md +1 -1
- package/docs/fr/06-for-backenders.md +1 -1
- package/docs/fr/07-llm-pitfalls.md +1 -1
- package/docs/fr/09-shadow-vs-light-dom.md +63 -0
- package/docs/ru/05-why-mado.md +2 -2
- package/docs/ru/06-for-backenders.md +1 -1
- package/docs/ru/09-shadow-vs-light-dom.md +60 -0
- package/docs/uk/06-for-backenders.md +2 -2
- package/docs/uk/09-shadow-vs-light-dom.md +91 -24
- package/llms.txt +15 -0
- package/package.json +1 -1
- package/scripts/bundle.mjs +3 -3
- package/scripts/cli.mjs +8 -1
- package/server/serve.mjs +19 -7
- package/starters/crud/README.md +14 -2
- package/starters/crud/package.json +2 -1
- package/starters/crud/src/components/app-shell.ts +13 -8
- package/starters/crud/src/main.ts +1 -4
- package/starters/crud/src/pages/ticket-detail.ts +1 -0
- package/starters/crud/src/pages/ticket-new.ts +1 -0
- package/starters/crud/src/pages/tickets.ts +1 -0
- package/starters/minimal/README.md +4 -2
- package/starters/minimal/package.json +2 -1
- package/starters/minimal/src/components/app-counter.ts +1 -1
package/AGENTS.md
CHANGED
|
@@ -247,6 +247,28 @@ component("x-child", ({ host }) => {
|
|
|
247
247
|
});
|
|
248
248
|
```
|
|
249
249
|
|
|
250
|
+
### 13. Component registration imports
|
|
251
|
+
|
|
252
|
+
Custom elements are global after registration, but the browser never imports a
|
|
253
|
+
component file automatically.
|
|
254
|
+
|
|
255
|
+
```ts
|
|
256
|
+
import "./components/app-shell.js";
|
|
257
|
+
|
|
258
|
+
render(html`<x-app-shell>${router.view}</x-app-shell>`, app);
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
The import runs `customElements.define("x-app-shell", ...)`. After that,
|
|
262
|
+
`<x-app-shell>` works anywhere in the current document.
|
|
263
|
+
|
|
264
|
+
Rules:
|
|
265
|
+
|
|
266
|
+
- App shell / global providers → import in `main.ts`.
|
|
267
|
+
- Components used only by one page → import in that page.
|
|
268
|
+
- Components shared by a feature → import in the feature entry/page.
|
|
269
|
+
- Tiny leaf components used everywhere → importing in `main.ts` is acceptable.
|
|
270
|
+
- Do **not** bulk-import every component "just in case".
|
|
271
|
+
|
|
250
272
|
## SOFT GUIDELINES — recommended, but not critical
|
|
251
273
|
|
|
252
274
|
- **TypeScript strict.** Use `noUncheckedIndexedAccess`-aware code (with `!` or a type guard).
|
|
@@ -263,7 +285,7 @@ src/
|
|
|
263
285
|
├── main.ts ← entry: mount to #app
|
|
264
286
|
├── pages/ ← one page = one file
|
|
265
287
|
├── components/ ← reusable x-* components
|
|
266
|
-
├── layouts/ ← layout
|
|
288
|
+
├── layouts/ ← optional route layout modules (`page({ child })`)
|
|
267
289
|
└── lib/ ← API client, contexts, pure logic
|
|
268
290
|
```
|
|
269
291
|
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.1
|
|
4
|
+
|
|
5
|
+
Patch release focused on first-user DX after the public npm launch.
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Generated starter apps can now run `mado dev` / `mado serve` from the app
|
|
10
|
+
root instead of assuming the framework repository layout.
|
|
11
|
+
- The CRUD starter shell is a real Web Component again, using Shadow DOM and
|
|
12
|
+
`<slot>` for route projection.
|
|
13
|
+
- Feature components in the CRUD starter are imported by the pages that render
|
|
14
|
+
them, avoiding a confusing "import everything in main" pattern.
|
|
15
|
+
- The minimal starter counter tag registration now matches the rendered
|
|
16
|
+
`<x-app-counter>` tag.
|
|
17
|
+
- The router default 404 view is rendered through `html` templates, not dynamic
|
|
18
|
+
`innerHTML`.
|
|
19
|
+
- `npm run bundle` defaults to the existing showcase entry instead of the old
|
|
20
|
+
removed `examples/main.ts`.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- Starter packages include `npm run dev` and generated `.gitignore` defaults.
|
|
25
|
+
- README and docs clarify that Mado works with browser primitives rather than
|
|
26
|
+
replacing the platform.
|
|
27
|
+
- Form documentation now describes `useForm()` as schema-based validation close
|
|
28
|
+
to HTML constraints, matching the implementation.
|
|
29
|
+
- Shadow DOM / Light DOM docs now explain layout components, `<slot>`, and
|
|
30
|
+
component registration imports.
|
|
31
|
+
- Deep imports are documented as internal/unstable before v1.
|
|
32
|
+
- CI workflows use Node24-based GitHub actions and the obsolete Cloudflare
|
|
33
|
+
showcase deploy workflow was removed.
|
|
34
|
+
- The release workflow updates npm before publish and creates GitHub releases
|
|
35
|
+
through the GitHub CLI.
|
|
36
|
+
- Browser regression now runs on a weekly schedule as well as manually.
|
|
37
|
+
|
|
3
38
|
## 0.5.0
|
|
4
39
|
|
|
5
40
|
First public release preparation for Mado.
|
package/README.md
CHANGED
|
@@ -19,6 +19,11 @@
|
|
|
19
19
|
|
|
20
20
|
> A small native-web SPA framework you can read in an evening.
|
|
21
21
|
|
|
22
|
+
[](https://www.npmjs.com/package/@madojs/mado)
|
|
23
|
+
[](https://github.com/madojs/mado/actions/workflows/ci.yml)
|
|
24
|
+
[](https://github.com/madojs/mado/actions/workflows/browser.yml)
|
|
25
|
+
[](./LICENSE)
|
|
26
|
+
|
|
22
27
|
Mado is a thin TypeScript framework on top of the browser platform: Web
|
|
23
28
|
Components, signals, tagged-template `html`, a router, resources, forms,
|
|
24
29
|
context, persisted state and static prerender. No runtime dependencies, no
|
|
@@ -27,6 +32,12 @@ required bundler, no hidden build pipeline: `tsc → browser`.
|
|
|
27
32
|
Mado (`窓`) means “window” in Japanese: a calm native-web window into an app,
|
|
28
33
|
without dragging a whole frontend factory into the room.
|
|
29
34
|
|
|
35
|
+
Mado does not try to replace the browser platform. The browser already gives
|
|
36
|
+
us modules, custom elements, attributes, events, forms, CSS, URLs, history,
|
|
37
|
+
fetch and the DOM. Mado's job is to make those primitives comfortable enough
|
|
38
|
+
for small and serious applications, without taking away your understanding of
|
|
39
|
+
what is happening.
|
|
40
|
+
|
|
30
41
|
```txt
|
|
31
42
|
Runtime budget after build:
|
|
32
43
|
native ESM graph: ~60 KB raw, ~24 KB gzip across separate modules
|
|
@@ -314,8 +325,18 @@ html`
|
|
|
314
325
|
`;
|
|
315
326
|
```
|
|
316
327
|
|
|
317
|
-
Validation is based
|
|
318
|
-
`
|
|
328
|
+
Validation is schema-based and intentionally close to native HTML constraints:
|
|
329
|
+
`required`, `min`, `max`, `pattern`, `type=email/url/number`, plus optional
|
|
330
|
+
custom `validate(values)`.
|
|
331
|
+
|
|
332
|
+
Only the root import is the stable public API:
|
|
333
|
+
|
|
334
|
+
```ts
|
|
335
|
+
import { html, component, signal } from "@madojs/mado";
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
Deep imports may exist in the package for tooling and generated files, but they
|
|
339
|
+
are internal and can change before v1.
|
|
319
340
|
|
|
320
341
|
## Static HTML Without Hydration
|
|
321
342
|
|
package/ROADMAP.md
CHANGED
|
@@ -14,11 +14,20 @@ readable and reliable under real application pressure.
|
|
|
14
14
|
|
|
15
15
|
## Before v1
|
|
16
16
|
|
|
17
|
+
- Generated app DX: `mado dev`/`serve`/starter scripts should feel as polished
|
|
18
|
+
outside the framework repo as they do inside it.
|
|
19
|
+
- Generated app production story: `mado bundle` and `mado preview` should work
|
|
20
|
+
from a starter app without repository-only assumptions.
|
|
17
21
|
- Browser compatibility pass across current Chrome, Edge, Firefox and Safari.
|
|
18
22
|
- Accessibility pass for examples and common component patterns.
|
|
19
23
|
- Public API audit: names, warnings, lifecycle rules, docs coverage.
|
|
20
|
-
-
|
|
24
|
+
- Public exports audit: root import is stable; deep imports must either become
|
|
25
|
+
explicit public subpaths or remain clearly unsupported before v1.
|
|
26
|
+
- Release hygiene: npm provenance / Trusted Publishing, GitHub repo metadata,
|
|
27
|
+
tags and changelog.
|
|
21
28
|
- Size reporting command or CI summary with ESM and bundled/minified budgets.
|
|
29
|
+
- Public demo site built with Mado: docs, CRUD starter and showcase as a live
|
|
30
|
+
proof instead of another README claim.
|
|
22
31
|
- Real commercial app test: validate auth, forms, tables, resources, route
|
|
23
32
|
transitions and long-lived sessions outside toy examples.
|
|
24
33
|
|
|
@@ -43,8 +52,9 @@ readable and reliable under real application pressure.
|
|
|
43
52
|
| 2026-06-03 | v0.3 hardening | Nested template cleanup, stale async route guard, Shadow DOM link/prefetch tests, scroll behavior, `warnOnce`, component reconnect/style tests. |
|
|
44
53
|
| 2026-06-05 | v0.4 showcase max | `examples/showcase` became a SaaS CRM pressure app with accounts, deals, activity, nested routes, context services and browser regression. |
|
|
45
54
|
| 2026-06-06 | v0.5 project shape | Unified `mado` CLI, dev server logs, docs language skeleton, examples cleanup (`basic`, `tickets`, `showcase`, `cloudflare`). |
|
|
46
|
-
| 2026-06-06 | Mado rebrand | Public package/import name
|
|
55
|
+
| 2026-06-06 | Mado rebrand | Public package/import name `@madojs/mado`, CLI `mado`, brand/docs/examples updated, internal legacy markers cleaned. |
|
|
47
56
|
| 2026-06-06 | Public polish | English public surface, localized docs, translated code comments/examples/templates/GitHub files. |
|
|
57
|
+
| 2026-06-07 | First npm release | Published `@madojs/mado@0.5.0` with the `mado` CLI, minimal/crud starters, CI and release workflow. |
|
|
48
58
|
|
|
49
59
|
## Future Ideas
|
|
50
60
|
|
package/dist/src/forms.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Forms without pain. Built on
|
|
2
|
+
* Forms without pain. Built on native `<form>` submit/input events plus a
|
|
3
|
+
* small schema validator whose rules mirror common HTML constraints.
|
|
3
4
|
*
|
|
4
5
|
* const f = useForm({
|
|
5
6
|
* email: { required: true, type: 'email' },
|
|
@@ -20,7 +21,7 @@
|
|
|
20
21
|
* `;
|
|
21
22
|
*
|
|
22
23
|
* What's inside:
|
|
23
|
-
* - validation
|
|
24
|
+
* - validation rules mirror common HTML constraints
|
|
24
25
|
* (required, min, max, pattern, type=email/url/number, etc.);
|
|
25
26
|
* - custom rules via a validate(values) function returning
|
|
26
27
|
* { field: 'msg' } or null;
|
|
@@ -34,7 +35,7 @@
|
|
|
34
35
|
import { type Signal } from "./signal.js";
|
|
35
36
|
export type FormValues = Record<string, string | number | boolean | undefined>;
|
|
36
37
|
export type FormErrors = Record<string, string | undefined>;
|
|
37
|
-
/** Field declaration.
|
|
38
|
+
/** Field declaration. Rules intentionally match common HTML constraints. */
|
|
38
39
|
export interface FieldSchema {
|
|
39
40
|
required?: boolean;
|
|
40
41
|
type?: "text" | "email" | "url" | "number" | "tel" | "password";
|
package/dist/src/forms.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Forms without pain. Built on
|
|
2
|
+
* Forms without pain. Built on native `<form>` submit/input events plus a
|
|
3
|
+
* small schema validator whose rules mirror common HTML constraints.
|
|
3
4
|
*
|
|
4
5
|
* const f = useForm({
|
|
5
6
|
* email: { required: true, type: 'email' },
|
|
@@ -20,7 +21,7 @@
|
|
|
20
21
|
* `;
|
|
21
22
|
*
|
|
22
23
|
* What's inside:
|
|
23
|
-
* - validation
|
|
24
|
+
* - validation rules mirror common HTML constraints
|
|
24
25
|
* (required, min, max, pattern, type=email/url/number, etc.);
|
|
25
26
|
* - custom rules via a validate(values) function returning
|
|
26
27
|
* { field: 'msg' } or null;
|
package/dist/src/forms.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forms.js","sourceRoot":"","sources":["../../src/forms.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"forms.js","sourceRoot":"","sources":["../../src/forms.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* so match.ts remains clean and testable without jsdom.
|
|
7
7
|
*/
|
|
8
8
|
import { signal } from "./../signal.js";
|
|
9
|
+
import { html } from "../html.js";
|
|
9
10
|
import { compile, matchRoute, } from "./match.js";
|
|
10
11
|
/**
|
|
11
12
|
* Minimal History API router.
|
|
@@ -166,15 +167,7 @@ function findAnchor(e, selector) {
|
|
|
166
167
|
}
|
|
167
168
|
/** Default 404, if the manifest had no `'*'`. */
|
|
168
169
|
function defaultFallback() {
|
|
169
|
-
return compile("*", () => {
|
|
170
|
-
const tpl = document.createElement("template");
|
|
171
|
-
tpl.innerHTML = `<pre>404: ${location.pathname}</pre>`;
|
|
172
|
-
return {
|
|
173
|
-
_mado: true,
|
|
174
|
-
strings: Object.assign([""], { raw: [""] }),
|
|
175
|
-
values: [tpl.content],
|
|
176
|
-
};
|
|
177
|
-
});
|
|
170
|
+
return compile("*", () => html `<pre>404: ${location.pathname}</pre>`);
|
|
178
171
|
}
|
|
179
172
|
// ---------- navigate() ----------
|
|
180
173
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation.js","sourceRoot":"","sources":["../../../src/router/navigation.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"navigation.js","sourceRoot":"","sources":["../../../src/router/navigation.ts"],"names":[],"mappings":"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"}
|
package/docs/en/05-why-mado.md
CHANGED
|
@@ -33,7 +33,7 @@ If your case does not fall into the last point — Mado is most likely not the b
|
|
|
33
33
|
| Reactivity | `@property` decorators + manual `requestUpdate` | signals (`signal`/`computed`/`effect`) out of the box |
|
|
34
34
|
| Router | none, you need to find one (`@lit-labs/router`, etc) | included: `routes()` + nested + prefetch + sync-cache |
|
|
35
35
|
| Data fetching | none, you need to assemble it | `resource()` + `mutation()` + glob invalidation |
|
|
36
|
-
| Forms | none | `useForm()`
|
|
36
|
+
| Forms | none | `useForm()` with HTML-like constraints |
|
|
37
37
|
| SEO / static | complex (`@lit-labs/ssr`) | `bake` (linkedom) + edge-prerender |
|
|
38
38
|
| Build | needs esbuild/rollup/webpack | `tsc` is enough |
|
|
39
39
|
| Code style | classes + decorators | functions + tagged templates |
|
|
@@ -188,7 +188,7 @@ We register the `<x-counter>` tag in the browser — it becomes a "function" tha
|
|
|
188
188
|
|
|
189
189
|
## Forms — like `form.Validate()` on the backend
|
|
190
190
|
|
|
191
|
-
Mado uses **native
|
|
191
|
+
Mado uses **schema-based validation close to native HTML constraints**, plus adds state tracking.
|
|
192
192
|
|
|
193
193
|
```ts
|
|
194
194
|
import { useForm } from "@madojs/mado";
|
|
@@ -256,7 +256,7 @@ This means:
|
|
|
256
256
|
// ❌ No such API
|
|
257
257
|
const f = useForm({ resolver: zodResolver(schema) });
|
|
258
258
|
|
|
259
|
-
// ✅ Correct:
|
|
259
|
+
// ✅ Correct: HTML-like validation through useForm schema
|
|
260
260
|
const f = useForm({
|
|
261
261
|
email: { required: true, type: "email" },
|
|
262
262
|
age: { required: true, type: "number", min: 18 },
|
|
@@ -6,6 +6,19 @@ an application.
|
|
|
6
6
|
|
|
7
7
|
## Rule of Thumb
|
|
8
8
|
|
|
9
|
+
In Mado, layouts are components too. If a file represents a visible reusable
|
|
10
|
+
part of the app tree — app shell, sidebar, modal, table, page section — prefer a
|
|
11
|
+
Web Component registered with `component()`.
|
|
12
|
+
|
|
13
|
+
Use plain functions only for small inline template helpers:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
const money = (value: number) => html`<span>${formatMoney(value)}</span>`;
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Do not use functions for app shells in public examples. They work, but they
|
|
20
|
+
hide the browser model instead of teaching it.
|
|
21
|
+
|
|
9
22
|
Use **Shadow DOM** for leaf widgets:
|
|
10
23
|
|
|
11
24
|
- buttons, badges, cards, metrics;
|
|
@@ -22,6 +35,15 @@ global CSS utilities:
|
|
|
22
35
|
- components that intentionally share global layout, form and table utilities;
|
|
23
36
|
- places where children should simply remain normal document DOM.
|
|
24
37
|
|
|
38
|
+
Use **Shadow DOM** for slot-based layouts:
|
|
39
|
+
|
|
40
|
+
- app shells that render `<slot>`;
|
|
41
|
+
- sidebar/content wrappers;
|
|
42
|
+
- reusable layout frames that own their own grid/header/sidebar CSS.
|
|
43
|
+
|
|
44
|
+
`<slot>` is a Shadow DOM feature. In a `shadow: false` component, `<slot>` is
|
|
45
|
+
just a normal element and does not move children into that position.
|
|
46
|
+
|
|
25
47
|
## The Footgun
|
|
26
48
|
|
|
27
49
|
Global CSS does not cross a Shadow DOM boundary.
|
|
@@ -90,6 +112,18 @@ component("x-toast-stack", setup);
|
|
|
90
112
|
This gives backend-admin screens predictable CSS while preserving encapsulation
|
|
91
113
|
for reusable widgets and slot-based shells.
|
|
92
114
|
|
|
115
|
+
The import model is deliberately browser-native:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import "./components/app-layout.js";
|
|
119
|
+
|
|
120
|
+
render(html`<x-app-layout>${router.view}</x-app-layout>`, app);
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The import registers the custom element with `customElements.define()`. The
|
|
124
|
+
template creates an `<x-app-layout>` element. The browser connects the two.
|
|
125
|
+
There is no React-style component value being passed around.
|
|
126
|
+
|
|
93
127
|
If a layout does not need slot projection and should be styled entirely by
|
|
94
128
|
global CSS, `shadow: false` can still be a good choice. If it contains
|
|
95
129
|
`<slot>`, keep Shadow DOM and put the shell styles in that component.
|
|
@@ -107,6 +141,32 @@ component("x-card-link", () => () => html`
|
|
|
107
141
|
|
|
108
142
|
The link can be in Shadow DOM; navigation still stays SPA.
|
|
109
143
|
|
|
144
|
+
## Where To Import Components
|
|
145
|
+
|
|
146
|
+
Custom elements are global after registration, but registration is still an
|
|
147
|
+
explicit JavaScript import.
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
// main.ts: global app frame
|
|
151
|
+
import "./components/app-shell.js";
|
|
152
|
+
|
|
153
|
+
// pages/tickets.ts: page-owned feature component
|
|
154
|
+
import "../components/ticket-list.js";
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
The browser does **not** download `ticket-list.js` just because it sees
|
|
158
|
+
`<ticket-list>`. The file must be imported somewhere first. Once imported, it
|
|
159
|
+
calls `customElements.define(...)`, and the tag becomes known in the current
|
|
160
|
+
document.
|
|
161
|
+
|
|
162
|
+
Do not bulk-import every component in `main.ts` "just in case". It works for
|
|
163
|
+
tiny demos, but it hides ownership and defeats lazy route loading. Prefer:
|
|
164
|
+
|
|
165
|
+
- global app shell/providers in `main.ts`;
|
|
166
|
+
- page-owned components in that page file;
|
|
167
|
+
- feature-owned shared components in the feature entry page;
|
|
168
|
+
- truly global leaf components in `main.ts` only when they are used everywhere.
|
|
169
|
+
|
|
110
170
|
## Showcase Lesson
|
|
111
171
|
|
|
112
172
|
`examples/showcase` uses this split deliberately:
|
package/docs/fr/05-why-mado.md
CHANGED
|
@@ -33,7 +33,7 @@ Si votre cas ne tombe pas dans le dernier point — Mado n'est probablement pas
|
|
|
33
33
|
| Réactivité | décorateurs `@property` + `requestUpdate` manuel | signals (`signal`/`computed`/`effect`) intégrés |
|
|
34
34
|
| Router | aucun, vous devez en trouver un (`@lit-labs/router`, etc.) | inclus : `routes()` + nested + prefetch + sync-cache |
|
|
35
35
|
| Chargement de données | aucun, vous devez l'assembler | `resource()` + `mutation()` + invalidation glob |
|
|
36
|
-
| Forms | aucun | `useForm()`
|
|
36
|
+
| Forms | aucun | `useForm()` avec contraintes proches du HTML |
|
|
37
37
|
| SEO / statique | complexe (`@lit-labs/ssr`) | `bake` (linkedom) + edge-prerender |
|
|
38
38
|
| Build | nécessite esbuild/rollup/webpack | `tsc` suffit |
|
|
39
39
|
| Style de code | classes + décorateurs | fonctions + tagged templates |
|
|
@@ -195,7 +195,7 @@ Mado ne fait que le coller avec les signals.
|
|
|
195
195
|
|
|
196
196
|
## Forms — comme `form.Validate()` côté backend
|
|
197
197
|
|
|
198
|
-
Mado utilise
|
|
198
|
+
Mado utilise une **validation par schéma proche des contraintes HTML natives**, plus le suivi d'état.
|
|
199
199
|
|
|
200
200
|
```ts
|
|
201
201
|
import { useForm } from "@madojs/mado";
|
|
@@ -256,7 +256,7 @@ Cela signifie :
|
|
|
256
256
|
// ❌ Pas une telle API
|
|
257
257
|
const f = useForm({ resolver: zodResolver(schema) });
|
|
258
258
|
|
|
259
|
-
// ✅ Correct : validation
|
|
259
|
+
// ✅ Correct : validation proche du HTML via le schéma useForm
|
|
260
260
|
const f = useForm({
|
|
261
261
|
email: { required: true, type: "email" },
|
|
262
262
|
age: { required: true, type: "number", min: 18 },
|
|
@@ -5,6 +5,19 @@ autonomes, mais ce n'est pas le bon défaut pour chaque composant dans une appli
|
|
|
5
5
|
|
|
6
6
|
## Règle générale
|
|
7
7
|
|
|
8
|
+
Dans Mado, un layout est aussi un composant. Si un fichier décrit une partie
|
|
9
|
+
visible et réutilisable de l'arbre UI — app shell, sidebar, modal, table,
|
|
10
|
+
section de page — préférez un Web Component déclaré avec `component()`.
|
|
11
|
+
|
|
12
|
+
Gardez les fonctions simples pour de petits helpers inline :
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
const money = (value: number) => html`<span>${formatMoney(value)}</span>`;
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Ne faites pas d'app shell sous forme de fonction dans les exemples publics. Cela
|
|
19
|
+
fonctionne, mais cela cache le modèle du navigateur au lieu de l'enseigner.
|
|
20
|
+
|
|
8
21
|
Utilisez **Shadow DOM** pour les widgets feuilles :
|
|
9
22
|
|
|
10
23
|
- boutons, badges, cartes, métriques ;
|
|
@@ -22,6 +35,16 @@ les utilitaires CSS globaux :
|
|
|
22
35
|
tableau ;
|
|
23
36
|
- endroits où les enfants doivent simplement rester dans le DOM normal du document.
|
|
24
37
|
|
|
38
|
+
Utilisez **Shadow DOM** pour les layouts basés sur des slots :
|
|
39
|
+
|
|
40
|
+
- app shells qui rendent `<slot>` ;
|
|
41
|
+
- wrappers sidebar/contenu ;
|
|
42
|
+
- frames de layout réutilisables qui possèdent leur propre CSS grid/header/sidebar.
|
|
43
|
+
|
|
44
|
+
`<slot>` est une fonctionnalité Shadow DOM. Dans un composant `shadow: false`,
|
|
45
|
+
`<slot>` est juste un élément DOM normal et ne déplace pas les enfants à cet
|
|
46
|
+
endroit du layout.
|
|
47
|
+
|
|
25
48
|
## Le piège
|
|
26
49
|
|
|
27
50
|
Le CSS global ne franchit pas une frontière Shadow DOM.
|
|
@@ -89,6 +112,18 @@ component("x-toast-stack", setup);
|
|
|
89
112
|
Cela donne aux écrans d'admin backend un CSS prévisible tout en préservant l'encapsulation
|
|
90
113
|
pour les widgets réutilisables et les shells basés sur slot.
|
|
91
114
|
|
|
115
|
+
Le modèle d'import est volontairement natif au navigateur :
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import "./components/app-layout.js";
|
|
119
|
+
|
|
120
|
+
render(html`<x-app-layout>${router.view}</x-app-layout>`, app);
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
L'import enregistre le custom element avec `customElements.define()`. Le template
|
|
124
|
+
crée un élément `<x-app-layout>`. Le navigateur relie les deux. Il n'y a pas de
|
|
125
|
+
valeur de composant à la React que l'on passe comme fonction.
|
|
126
|
+
|
|
92
127
|
Si un layout n'a pas besoin de projection slot et doit être entièrement stylé par du CSS
|
|
93
128
|
global, `shadow: false` peut rester un bon choix. S'il contient `<slot>`, gardez Shadow DOM
|
|
94
129
|
et mettez les styles du shell dans `styles: css\`\``.
|
|
@@ -107,6 +142,34 @@ component("x-card-link", () => () => html`
|
|
|
107
142
|
|
|
108
143
|
Le lien peut être en Shadow DOM ; la navigation reste SPA.
|
|
109
144
|
|
|
145
|
+
## Où importer les composants
|
|
146
|
+
|
|
147
|
+
Les custom elements sont globaux après leur enregistrement, mais cet
|
|
148
|
+
enregistrement reste un import JavaScript explicite.
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
// main.ts : frame global de l'app
|
|
152
|
+
import "./components/app-shell.js";
|
|
153
|
+
|
|
154
|
+
// pages/tickets.ts : composant possédé par cette page
|
|
155
|
+
import "../components/ticket-list.js";
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Le navigateur ne télécharge **pas** `ticket-list.js` simplement parce qu'il voit
|
|
159
|
+
`<ticket-list>`. Le fichier doit d'abord être importé quelque part. Une fois
|
|
160
|
+
importé, il appelle `customElements.define(...)`, et le tag devient connu dans
|
|
161
|
+
le document courant.
|
|
162
|
+
|
|
163
|
+
N'importez pas tous les composants en masse dans `main.ts` "au cas où". Cela
|
|
164
|
+
fonctionne pour de petites démos, mais cache l'ownership et casse le chargement
|
|
165
|
+
paresseux des routes. Préférez :
|
|
166
|
+
|
|
167
|
+
- app shell/providers globaux dans `main.ts` ;
|
|
168
|
+
- composants utilisés par une seule page dans ce fichier page ;
|
|
169
|
+
- composants partagés d'une feature dans la page d'entrée de cette feature ;
|
|
170
|
+
- petits leaf components vraiment globaux dans `main.ts` seulement s'ils sont
|
|
171
|
+
utilisés partout.
|
|
172
|
+
|
|
110
173
|
## Leçon du Showcase
|
|
111
174
|
|
|
112
175
|
`examples/showcase` utilise cette séparation délibérément :
|
package/docs/ru/05-why-mado.md
CHANGED
|
@@ -33,7 +33,7 @@ Mado — не «убийца» React/Vue/Svelte. Это узкоспециали
|
|
|
33
33
|
| Реактивность | декораторы `@property` + ручной `requestUpdate` | сигналы (`signal`/`computed`/`effect`) из коробки |
|
|
34
34
|
| Роутер | нет, нужно искать (`@lit-labs/router`, etc) | в комплекте: `routes()` + nested + prefetch + sync-cache |
|
|
35
35
|
| Data fetching | нет, нужно собирать | `resource()` + `mutation()` + glob-инвалидация |
|
|
36
|
-
| Формы | нет | `useForm()`
|
|
36
|
+
| Формы | нет | `useForm()` с HTML-like constraints |
|
|
37
37
|
| SEO / static | сложно (`@lit-labs/ssr`) | `bake` (linkedom) + edge-prerender |
|
|
38
38
|
| Билд | нужен esbuild/rollup/webpack | хватает `tsc` |
|
|
39
39
|
| Стиль кода | классы + декораторы | функции + tagged templates |
|
|
@@ -190,4 +190,4 @@ Mado — это **узкий** инструмент с честным позиц
|
|
|
190
190
|
|
|
191
191
|
Если хоть один пункт не про вас — берите альтернативу из таблицы выше. Не миритесь с инструментом, который не подходит.
|
|
192
192
|
|
|
193
|
-
— Автор Mado, бывший React-разработчик, перешедший на бекенд и теперь склеивающий фронт в свободное время.
|
|
193
|
+
— Автор Mado, бывший React-разработчик, перешедший на бекенд и теперь склеивающий фронт в свободное время.
|
|
@@ -188,7 +188,7 @@ html`<x-counter></x-counter>`
|
|
|
188
188
|
|
|
189
189
|
## Формы — как `form.Validate()` на бекенде
|
|
190
190
|
|
|
191
|
-
Mado использует
|
|
191
|
+
Mado использует **schema-based validation в духе HTML constraints**, плюс добавляет state-tracking.
|
|
192
192
|
|
|
193
193
|
```ts
|
|
194
194
|
import { useForm } from "@madojs/mado";
|
|
@@ -6,6 +6,19 @@ an application.
|
|
|
6
6
|
|
|
7
7
|
## Rule of Thumb
|
|
8
8
|
|
|
9
|
+
В Mado layout — это тоже component. Если файл описывает видимую переиспользуемую
|
|
10
|
+
часть UI-дерева — app shell, sidebar, modal, table, page section — по умолчанию
|
|
11
|
+
делайте Web Component через `component()`.
|
|
12
|
+
|
|
13
|
+
Обычные функции оставляйте для маленьких inline helpers:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
const money = (value: number) => html`<span>${formatMoney(value)}</span>`;
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Не стоит делать app shell функцией в публичных примерах. Это работает, но
|
|
20
|
+
прячет browser model вместо того, чтобы ее объяснять.
|
|
21
|
+
|
|
9
22
|
Use **Shadow DOM** for leaf widgets:
|
|
10
23
|
|
|
11
24
|
- buttons, badges, cards, metrics;
|
|
@@ -22,6 +35,15 @@ global CSS utilities:
|
|
|
22
35
|
- components that intentionally share global layout, form and table utilities;
|
|
23
36
|
- places where children should simply remain normal document DOM.
|
|
24
37
|
|
|
38
|
+
Use **Shadow DOM** для slot-based layouts:
|
|
39
|
+
|
|
40
|
+
- app shells с `<slot>`;
|
|
41
|
+
- sidebar/content wrappers;
|
|
42
|
+
- reusable layout frames, которые владеют своим grid/header/sidebar CSS.
|
|
43
|
+
|
|
44
|
+
`<slot>` — это feature Shadow DOM. В компоненте с `shadow: false` тег `<slot>`
|
|
45
|
+
становится обычным DOM-элементом и не переносит children в это место layout.
|
|
46
|
+
|
|
25
47
|
## The Footgun
|
|
26
48
|
|
|
27
49
|
Global CSS does not cross a Shadow DOM boundary.
|
|
@@ -90,6 +112,18 @@ component("x-toast-stack", setup);
|
|
|
90
112
|
This gives backend-admin screens predictable CSS while preserving encapsulation
|
|
91
113
|
for reusable widgets and slot-based shells.
|
|
92
114
|
|
|
115
|
+
Import model специально browser-native:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import "./components/app-layout.js";
|
|
119
|
+
|
|
120
|
+
render(html`<x-app-layout>${router.view}</x-app-layout>`, app);
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Import регистрирует custom element через `customElements.define()`. Template
|
|
124
|
+
создает `<x-app-layout>` element. Дальше браузер сам связывает тег с классом
|
|
125
|
+
компонента. Тут нет React-style component value, который передается как функция.
|
|
126
|
+
|
|
93
127
|
If a layout does not need slot projection and should be styled entirely by
|
|
94
128
|
global CSS, `shadow: false` can still be a good choice. If it contains
|
|
95
129
|
`<slot>`, keep Shadow DOM and put the shell styles in that component.
|
|
@@ -107,6 +141,32 @@ component("x-card-link", () => () => html`
|
|
|
107
141
|
|
|
108
142
|
The link can be in Shadow DOM; navigation still stays SPA.
|
|
109
143
|
|
|
144
|
+
## Где импортировать компоненты
|
|
145
|
+
|
|
146
|
+
Custom elements становятся глобальными после регистрации, но регистрация все
|
|
147
|
+
равно остается явным JavaScript import.
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
// main.ts: global app frame
|
|
151
|
+
import "./components/app-shell.js";
|
|
152
|
+
|
|
153
|
+
// pages/tickets.ts: component, которым владеет эта page
|
|
154
|
+
import "../components/ticket-list.js";
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Браузер **не** скачивает `ticket-list.js` только потому, что увидел
|
|
158
|
+
`<ticket-list>`. Файл должен быть где-то импортирован. После import он вызывает
|
|
159
|
+
`customElements.define(...)`, и тег становится известен текущему document.
|
|
160
|
+
|
|
161
|
+
Не стоит bulk-import всех компонентов в `main.ts` "just in case". Для маленьких
|
|
162
|
+
demo это работает, но прячет ownership и ломает lazy route loading. Лучше:
|
|
163
|
+
|
|
164
|
+
- global app shell/providers импортировать в `main.ts`;
|
|
165
|
+
- components, которыми владеет одна page, импортировать в этой page;
|
|
166
|
+
- shared components feature-а импортировать в feature entry page;
|
|
167
|
+
- truly global leaf components импортировать в `main.ts` только если они реально
|
|
168
|
+
используются везде.
|
|
169
|
+
|
|
110
170
|
## Showcase Lesson
|
|
111
171
|
|
|
112
172
|
`examples/showcase` uses this split deliberately:
|
|
@@ -34,8 +34,8 @@ const form = useForm({
|
|
|
34
34
|
});
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
Mado
|
|
38
|
-
|
|
37
|
+
Mado використовує schema-based validation, близьку до HTML constraints, а не
|
|
38
|
+
окрему validation ecosystem.
|
|
39
39
|
|
|
40
40
|
## Auth
|
|
41
41
|
|
|
@@ -1,40 +1,107 @@
|
|
|
1
1
|
# Shadow DOM vs Light DOM
|
|
2
2
|
|
|
3
|
-
Mado використовує Shadow DOM за
|
|
4
|
-
|
|
3
|
+
Mado використовує Shadow DOM за замовчуванням. Це хороший default для
|
|
4
|
+
самодостатніх widgets, але не для кожного компонента в app.
|
|
5
5
|
|
|
6
|
-
##
|
|
6
|
+
## Практичне правило
|
|
7
|
+
|
|
8
|
+
У Mado layout — це теж component. Якщо файл описує видиму reusable частину
|
|
9
|
+
UI-дерева — app shell, sidebar, modal, table, page section — за замовчуванням
|
|
10
|
+
робіть Web Component через `component()`.
|
|
7
11
|
|
|
8
|
-
|
|
9
|
-
- isolated widgets;
|
|
10
|
-
- badges, cards, modals, buttons;
|
|
11
|
-
- компонентів, які мають не ламатися від зовнішнього CSS.
|
|
12
|
+
Звичайні функції залишайте для маленьких inline helpers:
|
|
12
13
|
|
|
13
14
|
```ts
|
|
14
|
-
|
|
15
|
-
styles: css`:host { display: inline-block; }`,
|
|
16
|
-
});
|
|
15
|
+
const money = (value: number) => html`<span>${formatMoney(value)}</span>`;
|
|
17
16
|
```
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
Не варто робити app shell функцією в public examples. Це працює, але ховає
|
|
19
|
+
browser model замість того, щоб її пояснювати.
|
|
20
|
+
|
|
21
|
+
Використовуйте **Shadow DOM** для leaf widgets:
|
|
22
|
+
|
|
23
|
+
- buttons, badges, cards, metrics;
|
|
24
|
+
- modals, toasts, small visual components;
|
|
25
|
+
- embedded widgets, які не мають випадково успадковувати app CSS;
|
|
26
|
+
- components, чиї styles належать самому component.
|
|
27
|
+
|
|
28
|
+
Використовуйте **Light DOM** (`{ shadow: false }`) для app structure, якій
|
|
29
|
+
потрібні global CSS utilities:
|
|
30
|
+
|
|
31
|
+
- route/page components;
|
|
32
|
+
- admin screens з dense table/form layouts;
|
|
33
|
+
- data-heavy screens з tables and forms;
|
|
34
|
+
- місця, де children мають залишатися normal document DOM.
|
|
35
|
+
|
|
36
|
+
Використовуйте **Shadow DOM** для slot-based layouts:
|
|
20
37
|
|
|
21
|
-
- app
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
|
|
38
|
+
- app shells, які render `<slot>`;
|
|
39
|
+
- sidebar/content wrappers;
|
|
40
|
+
- reusable layout frames, які володіють своїм grid/header/sidebar CSS.
|
|
41
|
+
|
|
42
|
+
`<slot>` — це feature Shadow DOM. У component з `shadow: false` тег `<slot>` є
|
|
43
|
+
звичайним DOM element і не переносить children у це місце layout.
|
|
44
|
+
|
|
45
|
+
## Як працює import
|
|
26
46
|
|
|
27
47
|
```ts
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
});
|
|
48
|
+
import "./components/app-layout.js";
|
|
49
|
+
|
|
50
|
+
render(html`<x-app-layout>${router.view}</x-app-layout>`, app);
|
|
32
51
|
```
|
|
33
52
|
|
|
34
|
-
|
|
53
|
+
Import реєструє custom element через `customElements.define()`. Template створює
|
|
54
|
+
`<x-app-layout>` element. Далі browser сам з'єднує tag з component class. Це не
|
|
55
|
+
React-style component value, який передається як function.
|
|
35
56
|
|
|
36
|
-
|
|
37
|
-
app layout або page composition, часто краще Light DOM.
|
|
57
|
+
## Routing and links
|
|
38
58
|
|
|
39
|
-
|
|
59
|
+
`data-link` працює всередині Shadow DOM, бо router використовує
|
|
40
60
|
`event.composedPath()`.
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
component("x-card-link", () => () => html`
|
|
64
|
+
<a href="/app/accounts" data-link>Accounts</a>
|
|
65
|
+
`);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Link може бути в Shadow DOM; navigation все одно залишається SPA.
|
|
69
|
+
|
|
70
|
+
## Де імпортувати компоненти
|
|
71
|
+
|
|
72
|
+
Custom elements стають global після registration, але registration все одно є
|
|
73
|
+
явним JavaScript import.
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
// main.ts: global app frame
|
|
77
|
+
import "./components/app-shell.js";
|
|
78
|
+
|
|
79
|
+
// pages/tickets.ts: component, яким володіє ця page
|
|
80
|
+
import "../components/ticket-list.js";
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Browser **не** завантажує `ticket-list.js` лише тому, що побачив
|
|
84
|
+
`<ticket-list>`. File має бути imported десь першим. Після import він викликає
|
|
85
|
+
`customElements.define(...)`, і tag стає відомим у поточному document.
|
|
86
|
+
|
|
87
|
+
Не робіть bulk-import усіх components у `main.ts` "just in case". Це працює в
|
|
88
|
+
tiny demos, але ховає ownership і ламає lazy route loading. Краще:
|
|
89
|
+
|
|
90
|
+
- global app shell/providers імпортувати в `main.ts`;
|
|
91
|
+
- components, якими володіє одна page, імпортувати в цій page;
|
|
92
|
+
- shared feature components імпортувати у feature entry page;
|
|
93
|
+
- truly global leaf components імпортувати в `main.ts` лише якщо вони реально
|
|
94
|
+
використовуються всюди.
|
|
95
|
+
|
|
96
|
+
## Showcase lesson
|
|
97
|
+
|
|
98
|
+
`examples/showcase` використовує цей split навмисно:
|
|
99
|
+
|
|
100
|
+
- `x-app` і CRM route pages — Light DOM;
|
|
101
|
+
- `x-app-layout` — Shadow DOM, бо він володіє slot-based sidebar/content shell;
|
|
102
|
+
- table/form/page utilities живуть у `styles/global.ts`;
|
|
103
|
+
- leaf components на кшталт `x-stat-card`, `x-status-badge`, `x-modal`,
|
|
104
|
+
`x-toast-stack` залишають Shadow DOM.
|
|
105
|
+
|
|
106
|
+
Якщо page раптом виглядає unstyled, перевірте, чи не використовує вона global
|
|
107
|
+
classes всередині Shadow DOM component. Зазвичай проблема саме в цьому.
|
package/llms.txt
CHANGED
|
@@ -11,6 +11,7 @@ Mado is a narrowly-focused frontend framework that deliberately avoids React pat
|
|
|
11
11
|
- **All templates are tagged template `html\`...\``** (not JSX). Allowed bindings inside: `${value}`, `attr=${v}`, `@evt=${fn}`, `.prop=${v}`, `?attr=${flag}`.
|
|
12
12
|
- **Reactivity via signals.** `signal()`, `computed()`, `effect()`. A signal is a getter function (`count()`), not an object field (`count.value`).
|
|
13
13
|
- **Components are Web Components.** Registered via `component('x-name', setupFn, options)`. Names must include a hyphen (`x-foo`, `my-button`).
|
|
14
|
+
- **Component files register tags as side effects.** The browser does not auto-import files by tag name. If `<x-card>` works, some imported module already ran `customElements.define("x-card", ...)`.
|
|
14
15
|
- **Cleanup via `ctx.onDispose(fn)`** in setup, not via return from effect.
|
|
15
16
|
|
|
16
17
|
## Critical template rules
|
|
@@ -94,6 +95,20 @@ export default page({
|
|
|
94
95
|
});
|
|
95
96
|
```
|
|
96
97
|
|
|
98
|
+
## Component registration imports
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
// main.ts: global shell/provider components only
|
|
102
|
+
import "./components/app-shell.js";
|
|
103
|
+
|
|
104
|
+
// pages/tickets.ts: feature/page-owned components
|
|
105
|
+
import "../components/ticket-list.js";
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Do not bulk-import every component in `main.ts` "just in case". Import the
|
|
109
|
+
registration near the route/page that owns the tag. This preserves lazy loading
|
|
110
|
+
and makes the code readable to humans and LLMs.
|
|
111
|
+
|
|
97
112
|
## Canonical CRUD pattern (for backend developers)
|
|
98
113
|
|
|
99
114
|
```ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@madojs/mado",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Mado — a small native-web SPA framework with Web Components, signals, tagged-template html, router, resources, and forms. TypeScript-only build, zero runtime dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/scripts/bundle.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
//
|
|
3
3
|
// Usage:
|
|
4
4
|
// node scripts/bundle.mjs # → out/<hash>.js + chunks + out/index.html
|
|
5
|
-
// ENTRY=
|
|
5
|
+
// ENTRY=src/index.ts HTML=examples/index.html node scripts/bundle.mjs
|
|
6
6
|
//
|
|
7
7
|
// What it does:
|
|
8
8
|
// 1. Bundles entry with code splitting (each dynamic import → a chunk).
|
|
@@ -26,9 +26,9 @@ import { gzipSync, brotliCompressSync, constants as zlibConst } from "node:zlib"
|
|
|
26
26
|
import { join, basename } from "node:path";
|
|
27
27
|
import { existsSync } from "node:fs";
|
|
28
28
|
|
|
29
|
-
const ENTRY = process.env.ENTRY ?? "examples/main.ts";
|
|
29
|
+
const ENTRY = process.env.ENTRY ?? "examples/showcase/main.ts";
|
|
30
30
|
const OUT_DIR = process.env.OUT_DIR ?? "out";
|
|
31
|
-
const HTML = process.env.HTML ?? "examples/index.html";
|
|
31
|
+
const HTML = process.env.HTML ?? "examples/showcase/index.html";
|
|
32
32
|
|
|
33
33
|
await mkdir(OUT_DIR, { recursive: true });
|
|
34
34
|
|
package/scripts/cli.mjs
CHANGED
|
@@ -40,7 +40,7 @@ switch (command) {
|
|
|
40
40
|
await runNodeScript("scripts/showcase-regression.mjs", args.slice(1));
|
|
41
41
|
} else {
|
|
42
42
|
const files = await listTestFiles();
|
|
43
|
-
await run(process.execPath, ["--test", "--test-timeout=
|
|
43
|
+
await run(process.execPath, ["--test", "--test-timeout=20000", ...files, ...args]);
|
|
44
44
|
}
|
|
45
45
|
break;
|
|
46
46
|
case "serve":
|
|
@@ -120,6 +120,7 @@ async function runInit(rawArgs) {
|
|
|
120
120
|
await mkdir(target, { recursive: true });
|
|
121
121
|
await cp(source, target, { recursive: true, force: true });
|
|
122
122
|
await copyCanonicalAgentFiles(target);
|
|
123
|
+
await ensureStarterGitignore(target);
|
|
123
124
|
|
|
124
125
|
const packageName = packageNameFromDir(target);
|
|
125
126
|
if (!isValidPackageName(packageName)) {
|
|
@@ -204,6 +205,12 @@ async function copyCanonicalAgentFiles(target) {
|
|
|
204
205
|
}
|
|
205
206
|
}
|
|
206
207
|
|
|
208
|
+
async function ensureStarterGitignore(target) {
|
|
209
|
+
const file = join(target, ".gitignore");
|
|
210
|
+
if (existsSync(file)) return;
|
|
211
|
+
await writeFile(file, "node_modules\ndist\nout\n.DS_Store\n*.log\n");
|
|
212
|
+
}
|
|
213
|
+
|
|
207
214
|
async function runNodeBin(bin, args) {
|
|
208
215
|
await run(process.execPath, [resolveBin(bin), ...args]);
|
|
209
216
|
}
|
package/server/serve.mjs
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
// node server/serve.mjs basic # mount examples/basic/ at /
|
|
7
7
|
// EXAMPLE=showcase node server/serve.mjs # mount examples/showcase/ at /
|
|
8
8
|
//
|
|
9
|
-
// Without EXAMPLE, / serves examples/index.html
|
|
9
|
+
// Without EXAMPLE, / serves examples/index.html when running inside the Mado
|
|
10
|
+
// repository, or ./index.html when running inside a generated app.
|
|
10
11
|
// With EXAMPLE, all extensionless and /index.html requests fall back to
|
|
11
12
|
// examples/<EXAMPLE>/index.html so the client router works from root, just
|
|
12
13
|
// like a production SPA deploy.
|
|
@@ -26,6 +27,9 @@ const EXAMPLE_DIR = EXAMPLE
|
|
|
26
27
|
? resolve(join(ROOT, "examples", EXAMPLE))
|
|
27
28
|
: "";
|
|
28
29
|
const EXAMPLE_INDEX = EXAMPLE ? join(EXAMPLE_DIR, "index.html") : "";
|
|
30
|
+
const EXAMPLES_INDEX = join(ROOT, "examples", "index.html");
|
|
31
|
+
const APP_INDEX = join(ROOT, "index.html");
|
|
32
|
+
const DEFAULT_INDEX = existsSync(EXAMPLES_INDEX) ? EXAMPLES_INDEX : APP_INDEX;
|
|
29
33
|
|
|
30
34
|
if (EXAMPLE) {
|
|
31
35
|
if (!existsSync(EXAMPLE_INDEX)) {
|
|
@@ -133,9 +137,7 @@ const server = createServer(async (req, res) => {
|
|
|
133
137
|
|
|
134
138
|
// A mounted example owns root and SPA fallback. Otherwise serve the
|
|
135
139
|
// examples index page.
|
|
136
|
-
const fallbackIndex = EXAMPLE
|
|
137
|
-
? EXAMPLE_INDEX
|
|
138
|
-
: join(ROOT, "examples", "index.html");
|
|
140
|
+
const fallbackIndex = EXAMPLE ? EXAMPLE_INDEX : DEFAULT_INDEX;
|
|
139
141
|
|
|
140
142
|
if (pathname === "/") {
|
|
141
143
|
// Resolved through fallback below.
|
|
@@ -260,6 +262,10 @@ async function buildPreloadHints() {
|
|
|
260
262
|
}
|
|
261
263
|
}
|
|
262
264
|
}
|
|
265
|
+
} else if (!existsSync(EXAMPLES_INDEX)) {
|
|
266
|
+
if (existsSync(join(ROOT, "dist/main.js"))) {
|
|
267
|
+
hrefs.push("/dist/main.js");
|
|
268
|
+
}
|
|
263
269
|
}
|
|
264
270
|
cachedPreloadHints = hrefs
|
|
265
271
|
.map((h) => ` <link rel="modulepreload" href="${h}">`)
|
|
@@ -274,16 +280,22 @@ server.on("error", (err) => {
|
|
|
274
280
|
});
|
|
275
281
|
|
|
276
282
|
server.listen(PORT, () => {
|
|
277
|
-
const distReady = existsSync(join(ROOT, "dist/src/index.js"))
|
|
283
|
+
const distReady = existsSync(join(ROOT, "dist/src/index.js"))
|
|
284
|
+
|| existsSync(join(ROOT, "dist/main.js"));
|
|
285
|
+
const mount = EXAMPLE
|
|
286
|
+
? `examples/${EXAMPLE}/ -> /`
|
|
287
|
+
: existsSync(EXAMPLES_INDEX)
|
|
288
|
+
? "examples/index.html landing"
|
|
289
|
+
: "index.html app";
|
|
278
290
|
console.log("");
|
|
279
291
|
console.log("Mado dev server");
|
|
280
292
|
console.log(` url: http://localhost:${PORT}/`);
|
|
281
293
|
console.log(` root: ${ROOT}`);
|
|
282
|
-
console.log(`
|
|
294
|
+
console.log(` mount: ${mount}`);
|
|
283
295
|
console.log(` hmr: ${HMR ? "on" : "off"}`);
|
|
284
296
|
console.log(` preload: ${PRELOAD}`);
|
|
285
297
|
console.log(` dist: ${distReady ? "ready" : "missing (run mado build)"}`);
|
|
286
|
-
if (!EXAMPLE) {
|
|
298
|
+
if (!EXAMPLE && existsSync(EXAMPLES_INDEX)) {
|
|
287
299
|
console.log(" try: mado serve basic");
|
|
288
300
|
console.log(" mado serve showcase");
|
|
289
301
|
console.log(" mado serve tickets");
|
package/starters/crud/README.md
CHANGED
|
@@ -4,18 +4,30 @@ Generated with the Mado CRUD starter.
|
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
npm install
|
|
7
|
-
npm run
|
|
8
|
-
npm run serve
|
|
7
|
+
npm run dev
|
|
9
8
|
```
|
|
10
9
|
|
|
11
10
|
Open http://localhost:5173.
|
|
12
11
|
|
|
12
|
+
Use `npm run build` for a production TypeScript build and `npm run serve` to
|
|
13
|
+
serve an already-built app.
|
|
14
|
+
|
|
13
15
|
This starter demonstrates:
|
|
14
16
|
|
|
15
17
|
- lazy routes;
|
|
16
18
|
- Web Components through `component()`;
|
|
19
|
+
- an app shell component with Shadow DOM and `<slot>`;
|
|
17
20
|
- query params through `queryParam()`;
|
|
18
21
|
- async data through `resource()`;
|
|
19
22
|
- mutations with invalidation;
|
|
20
23
|
- forms through `useForm()`;
|
|
21
24
|
- keyed tables through `each()`.
|
|
25
|
+
|
|
26
|
+
`x-app-shell` uses Shadow DOM because it owns the page frame and projects route
|
|
27
|
+
pages through `<slot>`. Page/table/form components can still use global styles:
|
|
28
|
+
slotted route pages remain normal document DOM.
|
|
29
|
+
|
|
30
|
+
Component imports are explicit registration side effects. `main.ts` imports the
|
|
31
|
+
global app shell. Feature pages import the components they render, for example
|
|
32
|
+
`src/pages/tickets.ts` imports `../components/ticket-list.js` before rendering
|
|
33
|
+
`<ticket-list>`.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { component, css, html } from "@madojs/mado";
|
|
2
2
|
|
|
3
3
|
component(
|
|
4
|
-
"app-shell",
|
|
4
|
+
"x-app-shell",
|
|
5
5
|
() => () => html`
|
|
6
6
|
<header>
|
|
7
7
|
<a class="brand" href="/" data-link>__APP_NAME__</a>
|
|
@@ -11,17 +11,18 @@ component(
|
|
|
11
11
|
<a href="/tickets/new" data-link>New ticket</a>
|
|
12
12
|
</nav>
|
|
13
13
|
</header>
|
|
14
|
-
<
|
|
14
|
+
<main>
|
|
15
|
+
<slot></slot>
|
|
16
|
+
</main>
|
|
15
17
|
`,
|
|
16
18
|
{
|
|
17
|
-
shadow: false,
|
|
18
19
|
styles: css`
|
|
19
|
-
|
|
20
|
+
:host {
|
|
20
21
|
min-height: 100vh;
|
|
21
22
|
display: block;
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
header {
|
|
25
26
|
display: flex;
|
|
26
27
|
align-items: center;
|
|
27
28
|
justify-content: space-between;
|
|
@@ -31,18 +32,22 @@ component(
|
|
|
31
32
|
padding: 0.9rem 1.25rem;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
main {
|
|
36
|
+
display: block;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
nav {
|
|
35
40
|
display: flex;
|
|
36
41
|
gap: 0.75rem;
|
|
37
42
|
flex-wrap: wrap;
|
|
38
43
|
}
|
|
39
44
|
|
|
40
|
-
|
|
45
|
+
a {
|
|
41
46
|
color: #334155;
|
|
42
47
|
text-decoration: none;
|
|
43
48
|
}
|
|
44
49
|
|
|
45
|
-
|
|
50
|
+
.brand {
|
|
46
51
|
color: #111827;
|
|
47
52
|
font-weight: 800;
|
|
48
53
|
}
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import { html, render } from "@madojs/mado";
|
|
2
2
|
import "./styles/global.js";
|
|
3
3
|
import "./components/app-shell.js";
|
|
4
|
-
import "./components/ticket-list.js";
|
|
5
|
-
import "./components/ticket-form.js";
|
|
6
|
-
import "./components/ticket-detail.js";
|
|
7
4
|
import router from "./routes.js";
|
|
8
5
|
|
|
9
6
|
const app = document.getElementById("app");
|
|
10
7
|
if (!app) throw new Error("#app not found");
|
|
11
8
|
|
|
12
|
-
render(html`<app-shell>${router.view}</app-shell>`, app);
|
|
9
|
+
render(html`<x-app-shell>${router.view}</x-app-shell>`, app);
|
|
@@ -4,12 +4,14 @@ Generated with Mado __MADO_VERSION__.
|
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
npm install
|
|
7
|
-
npm run
|
|
8
|
-
npm run serve
|
|
7
|
+
npm run dev
|
|
9
8
|
```
|
|
10
9
|
|
|
11
10
|
Open http://localhost:5173.
|
|
12
11
|
|
|
12
|
+
Use `npm run build` for a production TypeScript build and `npm run serve` to
|
|
13
|
+
serve an already-built app.
|
|
14
|
+
|
|
13
15
|
## Files
|
|
14
16
|
|
|
15
17
|
- `src/main.ts` mounts the router into `#app`.
|