@madojs/mado 0.10.1 → 0.11.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.
Files changed (219) hide show
  1. package/AGENTS.md +24 -26
  2. package/CHANGELOG.md +95 -0
  3. package/README.md +22 -47
  4. package/TODO.md +52 -48
  5. package/dist/src/component.d.ts +2 -1
  6. package/dist/src/component.js +5 -2
  7. package/dist/src/component.js.map +1 -1
  8. package/dist/src/each.d.ts +1 -1
  9. package/dist/src/each.js +1 -1
  10. package/dist/src/each.js.map +1 -1
  11. package/dist/src/html/bindings.js +3 -3
  12. package/dist/src/html/bindings.js.map +1 -1
  13. package/dist/src/index.d.ts +11 -6
  14. package/dist/src/index.js +5 -3
  15. package/dist/src/index.js.map +1 -1
  16. package/dist/src/lazy.d.ts +1 -1
  17. package/dist/src/lazy.js +1 -1
  18. package/dist/src/lazy.js.map +1 -1
  19. package/dist/src/page.d.ts +17 -21
  20. package/dist/src/page.js +7 -12
  21. package/dist/src/page.js.map +1 -1
  22. package/dist/src/router/manifest.d.ts +1 -1
  23. package/dist/src/router/manifest.js +21 -13
  24. package/dist/src/router/manifest.js.map +1 -1
  25. package/dist/src/router/match.d.ts +2 -2
  26. package/dist/src/router/match.js +3 -3
  27. package/dist/src/router/match.js.map +1 -1
  28. package/dist/src/router/navigation.js +1 -1
  29. package/dist/src/router/navigation.js.map +1 -1
  30. package/dist/src/vite/index.d.ts +10 -0
  31. package/dist/src/vite/index.js +33 -0
  32. package/dist/src/vite/index.js.map +1 -0
  33. package/docs/en/00-the-mado-way.md +25 -12
  34. package/docs/en/01-routing.md +90 -142
  35. package/docs/en/02-project-layout.md +59 -53
  36. package/docs/en/03-static-bake.md +5 -6
  37. package/docs/en/05-why-mado.md +6 -6
  38. package/docs/en/06-for-backenders.md +18 -22
  39. package/docs/en/08-llm-zero-history-test.md +9 -14
  40. package/docs/en/09-shadow-vs-light-dom.md +28 -36
  41. package/docs/en/10-app-architecture.md +158 -96
  42. package/docs/en/11-layouts.md +22 -24
  43. package/docs/en/12-auth-and-api.md +89 -182
  44. package/docs/en/13-deployment.md +18 -22
  45. package/docs/en/14-testing.md +4 -4
  46. package/docs/en/16-bake-cookbook.md +11 -12
  47. package/docs/en/18-api-freeze-map.md +6 -4
  48. package/docs/en/20-v1-stability.md +1 -1
  49. package/docs/fr/00-the-mado-way.md +55 -90
  50. package/docs/fr/01-routing.md +70 -152
  51. package/docs/fr/02-project-layout.md +61 -42
  52. package/docs/fr/03-static-bake.md +1 -1
  53. package/docs/fr/05-why-mado.md +6 -6
  54. package/docs/fr/06-for-backenders.md +7 -7
  55. package/docs/fr/08-llm-zero-history-test.md +21 -48
  56. package/docs/fr/09-shadow-vs-light-dom.md +43 -162
  57. package/docs/fr/10-app-architecture.md +110 -33
  58. package/docs/fr/11-layouts.md +24 -12
  59. package/docs/fr/12-auth-and-api.md +63 -22
  60. package/docs/fr/13-deployment.md +7 -10
  61. package/docs/fr/14-testing.md +1 -1
  62. package/docs/fr/16-bake-cookbook.md +2 -2
  63. package/docs/fr/18-api-freeze-map.md +1 -1
  64. package/docs/fr/20-v1-stability.md +1 -1
  65. package/docs/recipes/nginx/README.md +13 -0
  66. package/docs/ru/00-the-mado-way.md +53 -75
  67. package/docs/ru/01-routing.md +68 -143
  68. package/docs/ru/02-project-layout.md +61 -41
  69. package/docs/ru/03-static-bake.md +2 -2
  70. package/docs/ru/05-why-mado.md +6 -6
  71. package/docs/ru/06-for-backenders.md +7 -7
  72. package/docs/ru/08-llm-zero-history-test.md +9 -14
  73. package/docs/ru/09-shadow-vs-light-dom.md +43 -178
  74. package/docs/ru/10-app-architecture.md +115 -63
  75. package/docs/ru/11-layouts.md +24 -24
  76. package/docs/ru/12-auth-and-api.md +57 -35
  77. package/docs/ru/13-deployment.md +7 -11
  78. package/docs/ru/14-testing.md +1 -1
  79. package/docs/ru/16-bake-cookbook.md +12 -6
  80. package/docs/ru/18-api-freeze-map.md +5 -3
  81. package/docs/ru/20-v1-stability.md +1 -1
  82. package/docs/uk/00-the-mado-way.md +70 -44
  83. package/docs/uk/01-routing.md +41 -47
  84. package/docs/uk/02-project-layout.md +68 -41
  85. package/docs/uk/03-static-bake.md +1 -2
  86. package/docs/uk/06-for-backenders.md +3 -3
  87. package/docs/uk/08-llm-zero-history-test.md +22 -24
  88. package/docs/uk/09-shadow-vs-light-dom.md +37 -86
  89. package/docs/uk/10-app-architecture.md +72 -31
  90. package/docs/uk/11-layouts.md +25 -12
  91. package/docs/uk/12-auth-and-api.md +58 -22
  92. package/docs/uk/13-deployment.md +4 -3
  93. package/docs/uk/14-testing.md +1 -1
  94. package/docs/uk/18-api-freeze-map.md +1 -1
  95. package/docs/uk/20-v1-stability.md +1 -1
  96. package/llms.txt +14 -15
  97. package/package.json +18 -11
  98. package/scripts/_config.mjs +15 -161
  99. package/scripts/bake.mjs +74 -63
  100. package/scripts/cli/generate.mjs +348 -0
  101. package/scripts/cli/help.mjs +27 -0
  102. package/scripts/cli/index.mjs +79 -0
  103. package/scripts/cli/init.mjs +153 -0
  104. package/scripts/cli/release.mjs +152 -0
  105. package/scripts/cli/run.mjs +96 -0
  106. package/scripts/cli.mjs +2 -621
  107. package/scripts/package-smoke.mjs +4 -1
  108. package/scripts/preview.mjs +13 -37
  109. package/scripts/size-budget.mjs +5 -2
  110. package/scripts/vite.default.mjs +11 -0
  111. package/starters/default/.editorconfig +12 -0
  112. package/starters/default/README.md +74 -0
  113. package/starters/default/eslint.config.mjs +256 -0
  114. package/starters/default/index.html +13 -0
  115. package/starters/default/package.json +30 -0
  116. package/starters/default/public/favicon.svg +4 -0
  117. package/starters/default/src/app.routes.ts +39 -0
  118. package/starters/default/src/layouts/app-shell.layout.ts +35 -0
  119. package/starters/default/src/layouts/auth-shell.layout.ts +17 -0
  120. package/starters/default/src/main.ts +16 -0
  121. package/starters/default/src/modules/auth/_contracts/auth-api.types.ts +17 -0
  122. package/starters/default/src/modules/auth/auth.connector.ts +45 -0
  123. package/starters/default/src/modules/auth/auth.guard.ts +22 -0
  124. package/starters/default/src/modules/auth/auth.public.ts +9 -0
  125. package/starters/default/src/modules/auth/auth.routes.ts +8 -0
  126. package/starters/default/src/modules/auth/auth.service.ts +71 -0
  127. package/starters/default/src/modules/auth/auth.types.ts +15 -0
  128. package/starters/default/src/modules/auth/login.page.ts +62 -0
  129. package/starters/default/src/modules/billing/_contracts/stripe.types.ts +17 -0
  130. package/starters/default/src/modules/billing/api/stripe.connector.ts +71 -0
  131. package/starters/default/src/modules/billing/billing.public.ts +5 -0
  132. package/starters/default/src/modules/billing/billing.routes.ts +9 -0
  133. package/starters/default/src/modules/billing/billing.types.ts +15 -0
  134. package/starters/default/src/modules/billing/components/invoice-status-badge.component.ts +43 -0
  135. package/starters/default/src/modules/billing/data/invoices.resource.ts +35 -0
  136. package/starters/default/src/modules/billing/pages/invoice-detail.page.ts +70 -0
  137. package/starters/default/src/modules/billing/pages/invoices-list.page.ts +73 -0
  138. package/starters/default/src/modules/home/home.page.ts +34 -0
  139. package/starters/default/src/modules/home/not-found.page.ts +11 -0
  140. package/starters/default/src/shared/http/http-client.ts +86 -0
  141. package/starters/default/src/shared/http/http-error.ts +37 -0
  142. package/starters/default/src/shared/http/interceptors.ts +59 -0
  143. package/starters/default/src/shared/lib/format-date.ts +19 -0
  144. package/starters/default/src/shared/styles/content.css +70 -0
  145. package/starters/default/src/shared/styles/reset.css +32 -0
  146. package/starters/default/src/shared/styles/shell.css +57 -0
  147. package/starters/default/src/shared/styles/tokens.css +44 -0
  148. package/starters/default/src/shared/ui/x-button.component.ts +49 -0
  149. package/starters/default/src/shared/ui/x-spinner.component.ts +22 -0
  150. package/starters/default/src/styles.d.ts +1 -0
  151. package/starters/default/src/vite-env.d.ts +1 -0
  152. package/starters/default/tsconfig.json +24 -0
  153. package/starters/default/vite.config.ts +9 -0
  154. package/MADO_V1_PLAN.md +0 -179
  155. package/ROADMAP.md +0 -178
  156. package/dist/src/html.d.ts +0 -18
  157. package/dist/src/html.js +0 -17
  158. package/dist/src/html.js.map +0 -1
  159. package/dist/src/router.d.ts +0 -13
  160. package/dist/src/router.js +0 -13
  161. package/dist/src/router.js.map +0 -1
  162. package/scripts/bundle.mjs +0 -212
  163. package/scripts/llm-zero-history-smoke.mjs +0 -93
  164. package/scripts/new.mjs +0 -80
  165. package/scripts/showcase-regression.mjs +0 -392
  166. package/server/serve.mjs +0 -455
  167. package/starters/admin/README.md +0 -63
  168. package/starters/admin/index.html +0 -28
  169. package/starters/admin/mado.config.json +0 -22
  170. package/starters/admin/package.json +0 -24
  171. package/starters/admin/public/favicon.svg +0 -4
  172. package/starters/admin/src/components/x-button.ts +0 -82
  173. package/starters/admin/src/components/x-input.ts +0 -105
  174. package/starters/admin/src/layouts/app.ts +0 -101
  175. package/starters/admin/src/layouts/auth.ts +0 -41
  176. package/starters/admin/src/lib/api.ts +0 -184
  177. package/starters/admin/src/lib/auth.ts +0 -83
  178. package/starters/admin/src/main.ts +0 -15
  179. package/starters/admin/src/pages/admin/dashboard.ts +0 -48
  180. package/starters/admin/src/pages/admin/order-detail.ts +0 -80
  181. package/starters/admin/src/pages/admin/orders.ts +0 -117
  182. package/starters/admin/src/pages/home.ts +0 -34
  183. package/starters/admin/src/pages/login.ts +0 -70
  184. package/starters/admin/src/pages/not-found.ts +0 -12
  185. package/starters/admin/src/routes.ts +0 -40
  186. package/starters/admin/src/styles/global.ts +0 -86
  187. package/starters/admin/tsconfig.json +0 -15
  188. package/starters/crud/README.md +0 -33
  189. package/starters/crud/index.html +0 -28
  190. package/starters/crud/mado.config.json +0 -20
  191. package/starters/crud/package.json +0 -24
  192. package/starters/crud/src/components/app-shell.ts +0 -56
  193. package/starters/crud/src/components/ticket-detail.ts +0 -33
  194. package/starters/crud/src/components/ticket-form.ts +0 -69
  195. package/starters/crud/src/components/ticket-list.ts +0 -66
  196. package/starters/crud/src/lib/api.ts +0 -76
  197. package/starters/crud/src/main.ts +0 -9
  198. package/starters/crud/src/pages/home.ts +0 -34
  199. package/starters/crud/src/pages/not-found.ts +0 -12
  200. package/starters/crud/src/pages/ticket-detail.ts +0 -7
  201. package/starters/crud/src/pages/ticket-new.ts +0 -7
  202. package/starters/crud/src/pages/tickets.ts +0 -7
  203. package/starters/crud/src/routes.ts +0 -11
  204. package/starters/crud/src/styles/global.ts +0 -155
  205. package/starters/crud/tsconfig.json +0 -15
  206. package/starters/minimal/README.md +0 -21
  207. package/starters/minimal/index.html +0 -28
  208. package/starters/minimal/mado.config.json +0 -20
  209. package/starters/minimal/package.json +0 -24
  210. package/starters/minimal/src/components/app-counter.ts +0 -31
  211. package/starters/minimal/src/main.ts +0 -9
  212. package/starters/minimal/src/pages/home.ts +0 -35
  213. package/starters/minimal/src/pages/not-found.ts +0 -14
  214. package/starters/minimal/src/routes.ts +0 -8
  215. package/starters/minimal/src/styles/global.ts +0 -60
  216. package/starters/minimal/tsconfig.json +0 -15
  217. package/templates/page-detail.ts +0 -63
  218. package/templates/page-form.ts +0 -94
  219. package/templates/page-list.ts +0 -79
@@ -1,64 +1,84 @@
1
1
  # Project Layout
2
2
 
3
- Каждый new-проект на Mado имеет одинаковую структуру. Это **обязательное** соглашение.
3
+ Каждое Mado-приложение использует одну каноничную форму. Это не примерная
4
+ рекомендация, а соглашение, чтобы люди и AI-ассистенты одинаково понимали,
5
+ куда класть код.
4
6
 
5
- ```
7
+ ```txt
6
8
  my-app/
7
9
  ├── package.json # runtime dep: @madojs/mado
8
10
  ├── tsconfig.json # strict TS, ES2022, Bundler resolution
9
- ├── mado.config.json # dev/build/bake/bundle config
10
- ├── index.html # SPA shell и template для bake
11
- ├── public/ # статика (favicon, images, robots.txt)
11
+ ├── vite.config.ts # mado() from @madojs/mado/vite
12
+ ├── index.html # Vite entry + SPA shell
13
+ ├── public/ # статика: favicon, images, robots.txt
12
14
  └── src/
13
- ├── main.ts # точка входа: mount router в #app
14
- ├── routes.ts # route manifest (default + named manifest)
15
- ├── pages/ # одна страница = один файл = `export default page({...})`
16
- ├── components/ # переиспользуемые компоненты (x-*)
17
- ├── layouts/ # layout-страницы (для nested)
18
- └── lib/
19
- ├── api.ts # все fetch-обёртки
20
- ├── contexts.ts # createContext(...)
21
- ├── theme.ts # темы
22
- └── ... # утилиты, типы, бизнес-правила
15
+ ├── main.ts # импорт CSS и mount router в #app
16
+ ├── app.routes.ts # app map: manifest + default routes(...)
17
+ ├── layouts/ # layouts app-зон, не доменные модули
18
+ ├── shared/ # ui, http, lib, styles
19
+ └── modules/ # bounded contexts
20
+ └── billing/
21
+ ├── billing.routes.ts
22
+ ├── billing.public.ts
23
+ ├── billing.types.ts
24
+ ├── pages/
25
+ ├── data/
26
+ ├── api/
27
+ └── _contracts/
23
28
  ```
24
29
 
25
30
  ## Artifact States
26
31
 
27
32
  | Folder | Что это | Кто пишет | Deploy? |
28
- |---|---|---|---|
33
+ | --- | --- | --- | --- |
29
34
  | `src/` | исходники TypeScript | ты | no |
30
- | `dist/` | output `tsc`, native ESM для dev | `mado build` | no |
31
- | `public/` | авторская статика | ты | через `out/` |
32
- | `out/` | deploy artifact: SPA shell + bundles + promoted baked HTML | `mado release` | yes |
35
+ | `public/` | статика, копируется как есть | ты | через `out/` |
36
+ | `out/` | deploy artifact: SPA shell + assets + baked HTML | `mado release` | yes |
37
+
38
+ `mado release` = `typecheck` + Vite build (`out/index.html`, `out/assets/`,
39
+ `public/*`) + `bake` прямо в route paths + `sitemap.xml` + precompression.
33
40
 
34
- `mado release` = `typecheck` + `build` (`dist/`) + `bundle`
35
- (`out/assets/`) + `bake` (`out/baked/`) + promote baked HTML и
36
- `sitemap.xml` в deployable `out/` paths + copy `public/*`.
41
+ `index.html` лежит в корне, потому что для Vite это entry template. В
42
+ `public/` кладите только файлы, которые нужно скопировать как есть.
37
43
 
38
44
  ## Куда положить новый файл?
39
45
 
40
46
  | Что | Куда |
41
- |---|---|
42
- | Страница на новый URL | `src/pages/foo.ts` + добавить в `src/routes.ts` |
43
- | Переиспользуемая UI-штука | `src/components/foo-bar.ts` |
44
- | Обёртка над API | `src/lib/api.ts` (добавить метод) |
45
- | Глобальный контекст (тема, юзер, i18n) | `src/lib/<name>.ts` |
46
- | Чистая функция без UI | `src/lib/util/<name>.ts` |
47
+ | --- | --- |
48
+ | Страница на новый URL | `src/modules/<module>/pages/<name>.page.ts` + module routes |
49
+ | Module route map | `src/modules/<module>/<module>.routes.ts` |
50
+ | App shell/layout | `src/layouts/<zone>.layout.ts` |
51
+ | Shared UI widget | `src/shared/ui/<x-name>.component.ts` |
52
+ | Module-only UI widget | `src/modules/<module>/components/<name>.component.ts` |
53
+ | API connector | `src/modules/<module>/api/<provider>.connector.ts` |
54
+ | Data resource/mutation | `src/modules/<module>/data/<name>.resource.ts` |
55
+ | Auth/session | `src/modules/auth/` |
56
+ | Public module surface | `src/modules/<module>/<module>.public.ts` |
57
+ | Pure function без UI | `src/shared/lib/<name>.ts` |
58
+ | Static image / favicon | `public/<file>` |
59
+ | App-zone shell CSS | `src/shared/styles/shell.css` |
60
+ | Page-level CSS | `src/shared/styles/content.css` |
47
61
 
48
- Если не понимаешь куда — это сигнал что **архитектура страдает**. Спроси команду, **зафиксируй** ответ в `docs/`.
62
+ ## Vite Config
49
63
 
50
- ## Правила именования
64
+ ```ts
65
+ import { defineConfig } from "vite";
66
+ import { mado } from "@madojs/mado/vite";
67
+
68
+ export default defineConfig({
69
+ plugins: [mado()],
70
+ css: {
71
+ transformer: "lightningcss",
72
+ },
73
+ });
74
+ ```
51
75
 
52
- | Что | Стиль | Пример |
53
- |---|---|---|
54
- | Файл | kebab-case | `user-profile.ts` |
55
- | Тэг компонента | `x-` + kebab | `<x-user-profile>` |
56
- | Контекст | PascalCase + `Ctx` | `ThemeCtx`, `AuthCtx` |
57
- | Сигнал | camelCase | `userId`, `isLoggedIn` |
58
- | Page-функция (внутренний компонент) | `x-<route>-page` | `<x-posts-page>` |
76
+ Starter включает Vite Lightning CSS transformer. Mado не владеет prefixing,
77
+ CSS lowering или minification.
59
78
 
60
- ## Что НЕ кладём в src/
79
+ ## Что НЕ кладём в `src/`
61
80
 
62
- - Конфиги билдеров (webpack, rollup, vite) у нас их нет.
63
- - `.env`-файлыenv читается из `process.env`/`import.meta.env` в `lib/config.ts`.
64
- - ❌ Тесты вперемешку с кодом — все в `test/`.
81
+ - Лишние build-tool configsнастройка живет в `vite.config.ts`.
82
+ - `.env` files читайте env в `src/shared/lib/config.ts` и импортируйте этот
83
+ модуль.
84
+ - Tests рядом с кодом — держите их в `test/`.
@@ -100,7 +100,7 @@ export default routes(manifest, { titleSuffix: " · MyShop" });
100
100
  ## Запуск
101
101
 
102
102
  ```bash
103
- npm install -D linkedom esbuild
103
+ npm install -D linkedom vite
104
104
  npm run build
105
105
  npm run bake
106
106
  ```
@@ -144,7 +144,7 @@ out/
144
144
  {"slug":"mado-mug","name":"Mado-кружка","price":12,"..."}
145
145
  </script>
146
146
 
147
- <script type="module" src="/dist/examples/main.js"></script>
147
+ <script type="module" src="/assets/index-HASH.js"></script>
148
148
  </body>
149
149
  ```
150
150
 
@@ -31,11 +31,11 @@ Mado — не «убийца» React/Vue/Svelte. Это узкоспециали
31
31
  | Размер | ~6 КБ | ~16 КБ |
32
32
  | Возраст / поддержка | ~10 лет, Google | 6 месяцев, один автор |
33
33
  | Реактивность | декораторы `@property` + ручной `requestUpdate` | сигналы (`signal`/`computed`/`effect`) из коробки |
34
- | Роутер | нет, нужно искать (`@lit-labs/router`, etc) | в комплекте: `routes()` + nested + prefetch + sync-cache |
34
+ | Роутер | нет, нужно искать (`@lit-labs/router`, etc) | в комплекте: `routes()` + layout groups + prefetch |
35
35
  | Data fetching | нет, нужно собирать | `resource()` + `mutation()` + glob-инвалидация |
36
36
  | Формы | нет | `useForm()` с HTML-like constraints |
37
37
  | SEO / static | сложно (`@lit-labs/ssr`) | `bake` (linkedom) + edge-prerender |
38
- | Билд | нужен esbuild/rollup/webpack | хватает `tsc` |
38
+ | Билд | нужны framework-specific build plugins | Vite transport + native runtime |
39
39
  | Стиль кода | классы + декораторы | функции + tagged templates |
40
40
  | Экосистема | реальная (Shoelace, Material Web, и т.д.) | нет |
41
41
  | Когда выбрать | пишете дизайн-систему / Web-Components-библиотеку для встраивания | пишете приложение целиком, хотите всё в одной коробке |
@@ -55,14 +55,14 @@ Mado — не «убийца» React/Vue/Svelte. Это узкоспециали
55
55
  | Реактивность | сигналы (тот же класс идей) | сигналы |
56
56
  | Шаблоны | JSX (компилируется в реактивные expressions) | tagged template `html\`\`` |
57
57
  | Компонентная модель | функции, виртуальные узлы Solid | Web Components |
58
- | Билд | Vite + babel-plugin-solid обязательны | только `tsc` |
58
+ | Билд | Vite + babel-plugin-solid обязательны | Vite для dev/build, без runtime-зависимостей |
59
59
  | Роутер | `@solidjs/router` | в комплекте |
60
60
  | Data | `createResource` | `resource()` |
61
61
  | SSR | поддерживается серьёзно (SolidStart) | намеренно нет |
62
62
  | Экосистема | растёт, ~50 пакетов | нет |
63
- | Когда выбрать | нужен топовый перф + JSX + готов настраивать билд | хотите запустить без билда / минимум инфраструктуры |
63
+ | Когда выбрать | нужен топовый перф + JSX + готов настраивать билд | нужен browser-native runtime с простым tooling |
64
64
 
65
- **Честный pitch:** *«Solid технически быстрее и зрелее. Но Solid требует Vite + babel-плагин. Mado не требует ничего, кроме `tsc` это «открой VS Code, F5 и работай». Если эта разница не критична — берите Solid.»*
65
+ **Честный pitch:** *«Solid технически быстрее и зрелее. Mado проще концептуально: browser-native runtime, Web Components, tagged templates, а Vite забирает на себя скучный dev/build. Если нужны JSX и большая экосистема — берите Solid.»*
66
66
 
67
67
  ---
68
68
 
@@ -153,7 +153,7 @@ Mado — не «убийца» React/Vue/Svelte. Это узкоспециали
153
153
 
154
154
  Не размер, не перф, не сигналы — у всего этого есть конкуренты лучше.
155
155
 
156
- > **«Открой исходник и прочитай его за вечер. ~3500 строк, 12 модулей. Если что-то сломалось — ты не идёшь в issue на 3000 комментариев. Ты идёшь в `src/router.ts` и читаешь 500 строк.»**
156
+ > **«Открой исходник и прочитай его за вечер. ~3500 строк, маленькие модули. Если что-то сломалось — ты не идёшь в issue на 3000 комментариев. Ты идёшь в `src/router/` и читаешь код.»**
157
157
 
158
158
  Это называется **ownership** — ты владеешь кодом, а не зависишь от чужого.
159
159
 
@@ -13,7 +13,7 @@ Mado устроен **как HTTP-сервер**. Серьёзно:
13
13
  |---|---|
14
14
  | HTTP-роутер (chi, axum, mux) | `routes()` — манифест путей |
15
15
  | Handler `func(req, resp)` | `page({ view: (ctx) => html\`...\` })` |
16
- | Middleware | `layout` в `nested()` (оборачивает handler) |
16
+ | Middleware | route group через `layout()` (оборачивает handler) |
17
17
  | Шаблонизатор (Jinja, Handlebars) | `html\`\`` tagged template |
18
18
  | HTTP-клиент с кешем | `resource()` — fetch + cache + invalidation |
19
19
  | Reactive variable / atom | `signal()` — реактивный геттер |
@@ -350,17 +350,17 @@ export default page({
350
350
  ```
351
351
 
352
352
  ```ts
353
- // src/routes.ts
354
- import { routes, nested } from "@madojs/mado";
353
+ // src/app.routes.ts
354
+ import { layout, routes } from "@madojs/mado";
355
355
 
356
356
  export default routes({
357
357
  "/login": () => import("./pages/login.js"),
358
358
 
359
- "/app/*": nested({
359
+ "/app": layout({
360
360
  layout: () => import("./layouts/auth-layout.js"),
361
361
  routes: {
362
- "dashboard": () => import("./pages/dashboard.js"),
363
- "users": () => import("./pages/users.js"),
362
+ "/dashboard": () => import("./pages/dashboard.js"),
363
+ "/users": () => import("./pages/users.js"),
364
364
  },
365
365
  }),
366
366
  });
@@ -423,6 +423,6 @@ export const api = new ApiClient("/api");
423
423
  - **[`01-routing.md`](./01-routing.md)** — детально про роутер.
424
424
  - **[`02-project-layout.md`](./02-project-layout.md)** — структура проекта.
425
425
  - **[`03-static-bake.md`](./03-static-bake.md)** — SEO без SSR.
426
- - **[`examples/showcase/`](../../examples/showcase/)**полный пример (landing + admin).
426
+ - **Внешний workspace `madojs-examples`**полные демо (landing + admin).
427
427
 
428
428
  Если что-то непонятно — open issue, или просто открой исходник. Это правда читается за вечер.
@@ -13,15 +13,15 @@
13
13
  - `AGENTS.md`
14
14
  - `README.md`
15
15
  - `docs/en/07-llm-pitfalls.md`
16
- - `examples/basic/README.md` если нужен минимальный обзор API
17
- - конкретные файлы из `examples/showcase/**` только если агент сам попросит паттерн более крупного приложения
16
+ - файлы из внешнего workspace `madojs-examples` только если агент сам попросит
17
+ паттерн более крупного приложения
18
18
 
19
19
  Агент может искать целевые API в `src/` когда заблокирован, но не должен
20
20
  загружать весь фреймворк в контекст.
21
21
 
22
22
  ## Задание
23
23
 
24
- Построить `examples/tickets`: маленький ticket-admin SPA для соло/бекенд-разработчика.
24
+ Построить маленький ticket-admin SPA для соло/бекенд-разработчика.
25
25
 
26
26
  Требуемое поведение:
27
27
 
@@ -48,15 +48,10 @@
48
48
 
49
49
  ## Заметки по результатам
50
50
 
51
- Текущая реализация `examples/tickets` не потребовала новых публичных API или
52
- runtime-зависимостей.
51
+ Историческая реализация tickets живет во внешнем workspace `madojs-examples`.
52
+ Core-репозиторий больше не поставляет этот артефакт и отдельную smoke-команду;
53
+ используйте этот документ как ручной сценарий оценки при обновлении LLM-guidance.
53
54
 
54
- CI запускает `npm run llm:smoke` как детерминированный proxy для этой задачи:
55
- проверяет, что `llms.txt` всё ещё содержит ключевые правила, сверяет
56
- зафиксированный артефакт `examples/tickets` с нужной Mado API surface и
57
- failure patterns, затем собирает проект и запускает `test/tickets-smoke.test.mjs`.
58
-
59
- Основная болевая точка в документации остается lifecycle: старые примеры могут
60
- создать впечатление, что создание `resource()` прямо в `page.view()` допустимо.
61
- Пример tickets использует page-level wrapper-компоненты вместо этого, поэтому
62
- ресурсы регистрируются внутри component setup и очищаются вместе с компонентом.
55
+ Основная болевая точка в документации остается lifecycle: примеры не должны
56
+ создавать впечатление, что long-lived `resource()` можно случайно держать на
57
+ module scope или в route-коде без cleanup.
@@ -1,198 +1,63 @@
1
1
  # Shadow DOM vs Light DOM
2
2
 
3
- Компоненты Mado по умолчанию используют Shadow DOM. Это хороший дефолт для
4
- самодостаточных виджетов, но не для каждого компонента в приложении.
3
+ Mado components используют Shadow DOM по умолчанию. Это хороший default для
4
+ самодостаточных виджетов, но app zones и страницы обычно должны оставаться
5
+ простыми light DOM templates.
5
6
 
6
- ## Правило большого пальца
7
+ ## Правило
7
8
 
8
- В Mado layout это тоже component. Если файл описывает видимую переиспользуемую
9
- часть UI-дерева — app shell, sidebar, modal, table, page section — по умолчанию
10
- делайте Web Component через `component()`.
11
-
12
- Обычные функции оставляйте для маленьких inline helpers:
9
+ Используйте route layouts для app zones:
13
10
 
14
11
  ```ts
15
- const money = (value: number) => html`<span>${formatMoney(value)}</span>`;
12
+ export default page({
13
+ view: ({ child }) => html`<main class="app-main">${child}</main>`,
14
+ });
16
15
  ```
17
16
 
18
- Не стоит делать app shell функцией в публичных примерах. Это работает, но
19
- прячет browser model вместо того, чтобы её объяснять.
20
-
21
- Используйте **Shadow DOM** для leaf-виджетов:
22
-
23
- - кнопки, бейджи, карточки, метрики;
24
- - модалы, тосты, маленькие визуальные компоненты;
25
- - embed-виджеты, которые не должны наследовать CSS приложения случайно;
26
- - компоненты, стили которых принадлежат самому компоненту.
27
-
28
- Используйте **Light DOM** (`{ shadow: false }`) для структуры приложения,
29
- которая хочет разделять глобальные CSS-утилиты:
30
-
31
- - route/page компоненты;
32
- - admin-экраны с плотными таблицами/формами;
33
- - data-heavy экраны с таблицами и формами;
34
- - компоненты, которые намеренно используют глобальные layout/form/table утилиты;
35
- - места, где children должны оставаться обычным document DOM.
36
-
37
- Используйте **Shadow DOM** для slot-based layouts:
38
-
39
- - app shells с `<slot>`;
40
- - sidebar/content wrappers;
41
- - reusable layout frames, которые владеют своим grid/header/sidebar CSS.
42
-
43
- `<slot>` — это feature Shadow DOM. В компоненте с `shadow: false` тег `<slot>`
44
- становится обычным DOM-элементом и не переносит children в это место layout.
45
-
46
- ## Подвох
47
-
48
- Глобальный CSS не пересекает границу Shadow DOM.
49
-
50
- ```ts
51
- // global.ts
52
- export const globalStyles = css`
53
- .page-head {
54
- display: flex;
55
- justify-content: space-between;
56
- }
57
- .metric-grid {
58
- display: grid;
59
- grid-template-columns: repeat(4, 1fr);
60
- }
61
- `;
62
-
63
- // ❌ .page-head и .metric-grid НЕ применятся внутри shadowRoot x-dashboard
64
- component(
65
- "x-dashboard",
66
- () => () => html`
67
- <header class="page-head">...</header>
68
- <div class="metric-grid">...</div>
69
- `,
70
- );
71
- ```
17
+ Такие файлы живут в `src/layouts/` и подключаются в `src/app.routes.ts` через
18
+ `layout()`. Они стилизуются обычным CSS из `src/shared/styles/shell.css`.
72
19
 
73
- Решение — сделать route/page компонент Light DOM:
20
+ Используйте page files для screens:
74
21
 
75
22
  ```ts
76
- component(
77
- "x-dashboard",
78
- () => () => html`
79
- <header class="page-head">...</header>
80
- <div class="metric-grid">...</div>
81
- `,
82
- {
83
- shadow: false,
84
- styles: css`
85
- x-dashboard {
86
- display: block;
87
- }
88
- x-dashboard .panel {
89
- padding: 1rem;
90
- }
91
- `,
92
- },
93
- );
23
+ export default page({
24
+ view: () => html`<section><h1>Users</h1></section>`,
25
+ });
94
26
  ```
95
27
 
96
- Теперь глобальные утилиты и локальные scoped-стили работают вместе.
97
-
98
- ## Как ведут себя стили
28
+ Page-level tables, forms, prose and simple states стилизуются из
29
+ `src/shared/styles/content.css`.
99
30
 
100
- - `styles: css\`\`` в Shadow DOM адоптируется в shadowRoot компонента.
101
- - `styles: css\`\``с`shadow: false` скоупится по имени тега и адоптируется
102
- глобально.
103
- - CSS custom properties (`--accent`, `--bg` и т.д.) пересекают границу Shadow DOM.
104
- - Селекторы по классу (`.btn`, `.form-grid`, `.page-head`) **не** пересекают
105
- границу Shadow DOM.
106
- - Slotted-children сохраняют свои стили из документа; shadow-компонент может
107
- таргетировать их только через `::slotted(...)`.
108
- - `<slot>` проецирует children только в Shadow DOM. В компоненте с `shadow: false`
109
- это обычный `<slot>` элемент, который не перемещает children в своё место.
31
+ Используйте Shadow DOM components для leaf widgets:
110
32
 
111
- ## Рекомендованная архитектура
33
+ - buttons, badges, cards, metrics;
34
+ - spinners, modals, toasts;
35
+ - widgets, которые должны владеть своим CSS.
112
36
 
113
37
  ```ts
114
- // root и pages: Light DOM
115
- component("x-app", setup, { shadow: false });
116
- component("x-users-page", setup, { shadow: false });
117
-
118
- // slot-based layout: Shadow DOM по умолчанию, потому что владеет shell grid
119
- component("x-app-layout", setup);
120
-
121
- // leaf widgets: Shadow DOM по умолчанию
122
- component("x-status-badge", setup);
123
- component("x-stat-card", setup);
124
- component("x-toast-stack", setup);
125
- ```
126
-
127
- Это даёт backend-admin экранам предсказуемый CSS, сохраняя инкапсуляцию
128
- для переиспользуемых виджетов и slot-based shells.
129
-
130
- Import model специально browser-native:
131
-
132
- ```ts
133
- import "./components/app-layout.js";
134
-
135
- render(html`<x-app-layout>${router.view}</x-app-layout>`, app);
136
- ```
137
-
138
- Import регистрирует custom element через `customElements.define()`. Template
139
- создаёт `<x-app-layout>` элемент. Дальше браузер сам связывает тег с классом
140
- компонента. Тут нет React-style component value, который передаётся как функция.
141
-
142
- Если layout не нуждается в slot projection и должен стилизоваться полностью
143
- глобальным CSS, `shadow: false` — хороший выбор. Если он содержит `<slot>`,
144
- оставьте Shadow DOM и поместите стили shell в этот компонент.
145
-
146
- ## Маршрутизация и ссылки
147
-
148
- `data-link` работает внутри Shadow DOM. Роутер использует `event.composedPath()`,
149
- поэтому перехват кликов и hover-prefetch видят ссылки из open shadow roots.
150
-
151
- ```ts
152
- component(
153
- "x-card-link",
154
- () => () => html` <a href="/app/accounts" data-link>Accounts</a> `,
155
- );
156
- ```
157
-
158
- Ссылка может быть внутри Shadow DOM — навигация всё равно остаётся SPA.
159
-
160
- ## Где импортировать компоненты
161
-
162
- Custom elements становятся глобальными после регистрации, но регистрация всё
163
- равно остаётся явным JavaScript import.
164
-
165
- ```ts
166
- // main.ts: global app frame
167
- import "./components/app-shell.js";
168
-
169
- // pages/tickets.ts: component, которым владеет эта page
170
- import "../components/ticket-list.js";
38
+ component("x-status-badge", ({ attr }) => {
39
+ const status = attr("status", "draft");
40
+ return () => html`<span>${status}</span>`;
41
+ }, {
42
+ styles: css`
43
+ :host { display: inline-block; }
44
+ span { color: var(--color-text-muted); }
45
+ `,
46
+ });
171
47
  ```
172
48
 
173
- Браузер **не** скачивает `ticket-list.js` только потому, что увидел
174
- `<ticket-list>`. Файл должен быть где-то импортирован. После import он вызывает
175
- `customElements.define(...)`, и тег становится известен текущему document.
176
-
177
- Не стоит bulk-import всех компонентов в `main.ts` «на всякий случай». Для маленьких
178
- demo это работает, но прячет ownership и ломает lazy route loading. Лучше:
179
-
180
- - global app shell/providers импортировать в `main.ts`;
181
- - components, которыми владеет одна page, импортировать в этой page;
182
- - shared components feature-а импортировать в feature entry page;
183
- - truly global leaf components импортировать в `main.ts` только если они реально
184
- используются везде.
185
-
186
- ## Урок из showcase
187
-
188
- `examples/showcase` использует это разделение намеренно:
189
-
190
- - `x-app` и CRM route pages — Light DOM;
191
- - `x-app-layout` остаётся в Shadow DOM, потому что владеет slot-based
192
- sidebar/content shell;
193
- - table/form/page утилиты живут в `styles/global.ts`;
194
- - leaf-компоненты типа `x-stat-card`, `x-status-badge`, `x-modal` и
195
- `x-toast-stack` остаются в Shadow DOM.
49
+ ## Как ведут себя стили
196
50
 
197
- Если страница внезапно выглядит без стилей, проверьте не используете ли вы
198
- глобальные классы внутри Shadow DOM компонента. Обычно проблема именно в этом.
51
+ - `tokens.css` задает CSS custom properties; `var(...)` проходит через Shadow
52
+ DOM.
53
+ - `reset.css`, `shell.css`, `content.css` применяются только к document/light
54
+ DOM.
55
+ - Class selectors вроде `.data`, `.app-main`, `.error` не проходят внутрь
56
+ Shadow DOM.
57
+ - Component-local styles пишутся в ``css`...` `` внутри `component()` options.
58
+ - Если Shadow component принимает children, используйте `<slot>` и стилизуйте
59
+ frame внутри component styles.
60
+
61
+ Если page выглядит без стилей, почти всегда вы использовали global classes
62
+ внутри Shadow DOM component. Вынесите markup в page/layout или перенесите CSS в
63
+ component styles.