@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.
Files changed (298) hide show
  1. package/AGENTS.md +116 -32
  2. package/CHANGELOG.md +216 -1
  3. package/README.md +158 -173
  4. package/dist/src/component.d.ts +6 -3
  5. package/dist/src/component.d.ts.map +1 -0
  6. package/dist/src/component.js +163 -36
  7. package/dist/src/component.js.map +1 -1
  8. package/dist/src/context.d.ts +13 -32
  9. package/dist/src/context.d.ts.map +1 -0
  10. package/dist/src/context.js +73 -48
  11. package/dist/src/context.js.map +1 -1
  12. package/dist/src/css.d.ts +1 -0
  13. package/dist/src/css.d.ts.map +1 -0
  14. package/dist/src/css.js +34 -5
  15. package/dist/src/css.js.map +1 -1
  16. package/dist/src/devtools-hook.d.ts +14 -0
  17. package/dist/src/devtools-hook.d.ts.map +1 -0
  18. package/dist/src/devtools-hook.js +27 -0
  19. package/dist/src/devtools-hook.js.map +1 -0
  20. package/dist/src/devtools.d.ts +24 -22
  21. package/dist/src/devtools.d.ts.map +1 -0
  22. package/dist/src/devtools.js +230 -58
  23. package/dist/src/devtools.js.map +1 -1
  24. package/dist/src/diagnostics.d.ts +12 -0
  25. package/dist/src/diagnostics.d.ts.map +1 -0
  26. package/dist/src/diagnostics.js +68 -8
  27. package/dist/src/diagnostics.js.map +1 -1
  28. package/dist/src/each.d.ts +1 -5
  29. package/dist/src/each.d.ts.map +1 -0
  30. package/dist/src/each.js +0 -8
  31. package/dist/src/each.js.map +1 -1
  32. package/dist/src/forms.d.ts +27 -96
  33. package/dist/src/forms.d.ts.map +1 -0
  34. package/dist/src/forms.js +184 -394
  35. package/dist/src/forms.js.map +1 -1
  36. package/dist/src/head.d.ts +7 -6
  37. package/dist/src/head.d.ts.map +1 -0
  38. package/dist/src/head.js +8 -7
  39. package/dist/src/head.js.map +1 -1
  40. package/dist/src/html/bindings.d.ts +1 -0
  41. package/dist/src/html/bindings.d.ts.map +1 -0
  42. package/dist/src/html/bindings.js.map +1 -1
  43. package/dist/src/html/parser.d.ts +4 -5
  44. package/dist/src/html/parser.d.ts.map +1 -0
  45. package/dist/src/html/parser.js +64 -15
  46. package/dist/src/html/parser.js.map +1 -1
  47. package/dist/src/html/template-types.d.ts +1 -0
  48. package/dist/src/html/template-types.d.ts.map +1 -0
  49. package/dist/src/html/template-types.js.map +1 -1
  50. package/dist/src/html/template.d.ts +5 -1
  51. package/dist/src/html/template.d.ts.map +1 -0
  52. package/dist/src/html/template.js +102 -13
  53. package/dist/src/html/template.js.map +1 -1
  54. package/dist/src/index.d.ts +15 -12
  55. package/dist/src/index.d.ts.map +1 -0
  56. package/dist/src/index.js +18 -10
  57. package/dist/src/index.js.map +1 -1
  58. package/dist/src/json.d.ts +3 -0
  59. package/dist/src/json.d.ts.map +1 -0
  60. package/dist/src/json.js +14 -0
  61. package/dist/src/json.js.map +1 -0
  62. package/dist/src/lifecycle.d.ts +1 -0
  63. package/dist/src/lifecycle.d.ts.map +1 -0
  64. package/dist/src/lifecycle.js +3 -2
  65. package/dist/src/lifecycle.js.map +1 -1
  66. package/dist/src/page.d.ts +63 -28
  67. package/dist/src/page.d.ts.map +1 -0
  68. package/dist/src/page.js +5 -0
  69. package/dist/src/page.js.map +1 -1
  70. package/dist/src/persisted.d.ts +6 -1
  71. package/dist/src/persisted.d.ts.map +1 -0
  72. package/dist/src/persisted.js +17 -11
  73. package/dist/src/persisted.js.map +1 -1
  74. package/dist/src/resource.d.ts +2 -1
  75. package/dist/src/resource.d.ts.map +1 -0
  76. package/dist/src/resource.js +128 -50
  77. package/dist/src/resource.js.map +1 -1
  78. package/dist/src/router/base.d.ts +66 -0
  79. package/dist/src/router/base.d.ts.map +1 -0
  80. package/dist/src/router/base.js +168 -0
  81. package/dist/src/router/base.js.map +1 -0
  82. package/dist/src/router/manifest.d.ts +1 -0
  83. package/dist/src/router/manifest.d.ts.map +1 -0
  84. package/dist/src/router/manifest.js +156 -171
  85. package/dist/src/router/manifest.js.map +1 -1
  86. package/dist/src/router/match.d.ts +17 -2
  87. package/dist/src/router/match.d.ts.map +1 -0
  88. package/dist/src/router/match.js +60 -6
  89. package/dist/src/router/match.js.map +1 -1
  90. package/dist/src/router/navigation.d.ts +1 -0
  91. package/dist/src/router/navigation.d.ts.map +1 -0
  92. package/dist/src/router/navigation.js +58 -9
  93. package/dist/src/router/navigation.js.map +1 -1
  94. package/dist/src/signal.d.ts +1 -0
  95. package/dist/src/signal.d.ts.map +1 -0
  96. package/dist/src/signal.js +46 -17
  97. package/dist/src/signal.js.map +1 -1
  98. package/dist/src/static-runtime.d.ts +82 -0
  99. package/dist/src/static-runtime.d.ts.map +1 -0
  100. package/dist/src/static-runtime.js +209 -0
  101. package/dist/src/static-runtime.js.map +1 -0
  102. package/dist/src/vite/index.d.ts +32 -3
  103. package/dist/src/vite/index.d.ts.map +1 -0
  104. package/dist/src/vite/index.js +49 -17
  105. package/dist/src/vite/index.js.map +1 -1
  106. package/docs/README.md +5 -8
  107. package/docs/architecture/adr/0001-browser-static-snapshots.md +132 -0
  108. package/docs/architecture/v1-roadmap.md +19 -0
  109. package/docs/en/00-the-mado-way.md +1 -1
  110. package/docs/en/01-quickstart.md +183 -0
  111. package/docs/en/10-pages-and-components.md +279 -0
  112. package/docs/en/11-templates-and-signals.md +211 -0
  113. package/docs/en/12-routing.md +229 -0
  114. package/docs/en/13-data.md +227 -0
  115. package/docs/en/14-forms.md +91 -0
  116. package/docs/en/15-static-snapshots.md +181 -0
  117. package/docs/en/{10-app-architecture.md → 16-app-architecture.md} +56 -4
  118. package/docs/en/{13-deployment.md → 20-deployment.md} +79 -17
  119. package/docs/en/{15-error-handling.md → 21-error-handling.md} +9 -6
  120. package/docs/en/{14-testing.md → 22-testing.md} +6 -5
  121. package/docs/en/23-cookbook.md +292 -0
  122. package/docs/en/24-devtools-and-diagnostics.md +45 -0
  123. package/docs/en/{18-api-freeze-map.md → 30-api-freeze-map.md} +17 -9
  124. package/docs/en/{20-v1-stability.md → 32-v1-stability.md} +5 -5
  125. package/docs/en/33-migration-0.12-0.13.md +56 -0
  126. package/docs/en/40-llm-guide.md +774 -0
  127. package/docs/en/{06-for-backenders.md → 41-for-backenders.md} +28 -25
  128. package/docs/en/{05-why-mado.md → 42-why-mado.md} +3 -3
  129. package/docs/en/README.md +99 -27
  130. package/docs/recipes/nginx/Containerfile +26 -0
  131. package/docs/recipes/nginx/nginx.conf +42 -0
  132. package/llms.txt +263 -210
  133. package/package.json +51 -23
  134. package/scripts/clean.mjs +8 -0
  135. package/scripts/cli/generate.mjs +57 -10
  136. package/scripts/cli/help.mjs +13 -5
  137. package/scripts/cli/index.mjs +31 -7
  138. package/scripts/cli/init.mjs +19 -19
  139. package/scripts/cli/release.mjs +38 -83
  140. package/scripts/cli/run.mjs +5 -3
  141. package/scripts/logger.mjs +117 -0
  142. package/scripts/output-guard.mjs +128 -0
  143. package/scripts/preview.mjs +105 -24
  144. package/scripts/static/browser.mjs +695 -0
  145. package/scripts/static/discover.mjs +284 -0
  146. package/scripts/static/output.mjs +141 -0
  147. package/scripts/static/serialize.mjs +212 -0
  148. package/scripts/static/server.mjs +167 -0
  149. package/scripts/static.mjs +205 -0
  150. package/starters/default/README.md +57 -55
  151. package/starters/default/package.json +6 -12
  152. package/starters/default/src/app.routes.ts +20 -33
  153. package/starters/default/src/components/feature-card.component.ts +40 -0
  154. package/starters/default/src/components/live-counter.component.ts +57 -0
  155. package/starters/default/src/content/guides.ts +55 -0
  156. package/starters/default/src/main.ts +9 -13
  157. package/starters/default/src/pages/app.page.ts +41 -0
  158. package/starters/default/src/pages/guide.page.ts +40 -0
  159. package/starters/default/src/pages/home.page.ts +49 -0
  160. package/starters/default/src/pages/not-found.page.ts +18 -0
  161. package/starters/default/src/styles/document.css +39 -0
  162. package/starters/default/src/styles/reset.css +37 -0
  163. package/starters/default/src/styles/tokens.css +30 -0
  164. package/starters/default/src/styles.d.ts +3 -1
  165. package/starters/default/src/vite-env.d.ts +1 -1
  166. package/starters/default/tsconfig.node.json +13 -0
  167. package/starters/default/vite.config.ts +14 -4
  168. package/starters/modular/README.md +142 -0
  169. package/starters/modular/index.html +13 -0
  170. package/starters/modular/package.json +30 -0
  171. package/starters/modular/src/app.routes.ts +39 -0
  172. package/starters/{default → modular}/src/layouts/app-shell.layout.ts +9 -7
  173. package/starters/{default → modular}/src/layouts/auth-shell.layout.ts +3 -3
  174. package/starters/modular/src/main.ts +16 -0
  175. package/starters/{default → modular}/src/modules/auth/login.page.ts +5 -12
  176. package/starters/{default → modular}/src/modules/billing/pages/invoice-detail.page.ts +3 -4
  177. package/starters/{default → modular}/src/modules/billing/pages/invoices-list.page.ts +4 -4
  178. package/starters/{default → modular}/src/modules/home/home.page.ts +5 -7
  179. package/starters/modular/src/modules/home/not-found.page.ts +14 -0
  180. package/starters/{default → modular}/src/shared/styles/reset.css +21 -1
  181. package/starters/modular/src/styles.d.ts +1 -0
  182. package/starters/modular/src/vite-env.d.ts +1 -0
  183. package/starters/modular/tsconfig.json +33 -0
  184. package/starters/modular/tsconfig.node.json +13 -0
  185. package/starters/modular/vite.config.ts +132 -0
  186. package/TODO.md +0 -79
  187. package/dist/src/lazy.d.ts +0 -38
  188. package/dist/src/lazy.js +0 -73
  189. package/dist/src/lazy.js.map +0 -1
  190. package/docs/en/01-routing.md +0 -152
  191. package/docs/en/02-project-layout.md +0 -124
  192. package/docs/en/03-static-bake.md +0 -249
  193. package/docs/en/04-ide-setup.md +0 -162
  194. package/docs/en/07-llm-pitfalls.md +0 -724
  195. package/docs/en/08-llm-zero-history-test.md +0 -56
  196. package/docs/en/09-shadow-vs-light-dom.md +0 -174
  197. package/docs/en/11-layouts.md +0 -113
  198. package/docs/en/12-auth-and-api.md +0 -124
  199. package/docs/en/16-bake-cookbook.md +0 -100
  200. package/docs/en/17-shadow-dom-forms.md +0 -192
  201. package/docs/fr/00-the-mado-way.md +0 -85
  202. package/docs/fr/01-routing.md +0 -120
  203. package/docs/fr/02-project-layout.md +0 -84
  204. package/docs/fr/03-static-bake.md +0 -289
  205. package/docs/fr/04-ide-setup.md +0 -162
  206. package/docs/fr/05-why-mado.md +0 -193
  207. package/docs/fr/06-for-backenders.md +0 -438
  208. package/docs/fr/07-llm-pitfalls.md +0 -625
  209. package/docs/fr/08-llm-zero-history-test.md +0 -38
  210. package/docs/fr/09-shadow-vs-light-dom.md +0 -65
  211. package/docs/fr/10-app-architecture.md +0 -138
  212. package/docs/fr/11-layouts.md +0 -47
  213. package/docs/fr/12-auth-and-api.md +0 -76
  214. package/docs/fr/13-deployment.md +0 -57
  215. package/docs/fr/14-testing.md +0 -41
  216. package/docs/fr/15-error-handling.md +0 -50
  217. package/docs/fr/16-bake-cookbook.md +0 -88
  218. package/docs/fr/17-shadow-dom-forms.md +0 -196
  219. package/docs/fr/18-api-freeze-map.md +0 -63
  220. package/docs/fr/19-reactivity-ordering.md +0 -97
  221. package/docs/fr/20-v1-stability.md +0 -88
  222. package/docs/fr/README.md +0 -27
  223. package/docs/ru/00-the-mado-way.md +0 -84
  224. package/docs/ru/01-routing.md +0 -119
  225. package/docs/ru/02-project-layout.md +0 -84
  226. package/docs/ru/03-static-bake.md +0 -250
  227. package/docs/ru/04-ide-setup.md +0 -144
  228. package/docs/ru/05-why-mado.md +0 -193
  229. package/docs/ru/06-for-backenders.md +0 -428
  230. package/docs/ru/07-llm-pitfalls.md +0 -624
  231. package/docs/ru/08-llm-zero-history-test.md +0 -57
  232. package/docs/ru/09-shadow-vs-light-dom.md +0 -63
  233. package/docs/ru/10-app-architecture.md +0 -152
  234. package/docs/ru/11-layouts.md +0 -47
  235. package/docs/ru/12-auth-and-api.md +0 -75
  236. package/docs/ru/13-deployment.md +0 -66
  237. package/docs/ru/14-testing.md +0 -50
  238. package/docs/ru/15-error-handling.md +0 -56
  239. package/docs/ru/16-bake-cookbook.md +0 -95
  240. package/docs/ru/17-shadow-dom-forms.md +0 -193
  241. package/docs/ru/18-api-freeze-map.md +0 -64
  242. package/docs/ru/19-reactivity-ordering.md +0 -95
  243. package/docs/ru/20-v1-stability.md +0 -82
  244. package/docs/ru/README.md +0 -25
  245. package/docs/uk/00-the-mado-way.md +0 -82
  246. package/docs/uk/01-routing.md +0 -76
  247. package/docs/uk/02-project-layout.md +0 -73
  248. package/docs/uk/03-static-bake.md +0 -48
  249. package/docs/uk/04-ide-setup.md +0 -26
  250. package/docs/uk/05-why-mado.md +0 -34
  251. package/docs/uk/06-for-backenders.md +0 -55
  252. package/docs/uk/07-llm-pitfalls.md +0 -145
  253. package/docs/uk/08-llm-zero-history-test.md +0 -34
  254. package/docs/uk/09-shadow-vs-light-dom.md +0 -58
  255. package/docs/uk/10-app-architecture.md +0 -97
  256. package/docs/uk/11-layouts.md +0 -47
  257. package/docs/uk/12-auth-and-api.md +0 -70
  258. package/docs/uk/13-deployment.md +0 -40
  259. package/docs/uk/14-testing.md +0 -34
  260. package/docs/uk/15-error-handling.md +0 -32
  261. package/docs/uk/16-bake-cookbook.md +0 -36
  262. package/docs/uk/17-shadow-dom-forms.md +0 -193
  263. package/docs/uk/18-api-freeze-map.md +0 -61
  264. package/docs/uk/19-reactivity-ordering.md +0 -95
  265. package/docs/uk/20-v1-stability.md +0 -83
  266. package/docs/uk/README.md +0 -27
  267. package/scripts/bake.mjs +0 -570
  268. package/scripts/package-smoke.mjs +0 -77
  269. package/scripts/release-notes.mjs +0 -66
  270. package/scripts/size-budget.mjs +0 -91
  271. package/starters/default/src/modules/home/not-found.page.ts +0 -11
  272. package/starters/default/src/shared/ui/x-button.component.ts +0 -49
  273. /package/docs/en/{19-reactivity-ordering.md → 31-reactivity-ordering.md} +0 -0
  274. /package/starters/{default → modular}/.editorconfig +0 -0
  275. /package/starters/{default → modular}/eslint.config.mjs +0 -0
  276. /package/starters/{default → modular}/public/favicon.svg +0 -0
  277. /package/starters/{default → modular}/src/modules/auth/_contracts/auth-api.types.ts +0 -0
  278. /package/starters/{default → modular}/src/modules/auth/auth.connector.ts +0 -0
  279. /package/starters/{default → modular}/src/modules/auth/auth.guard.ts +0 -0
  280. /package/starters/{default → modular}/src/modules/auth/auth.public.ts +0 -0
  281. /package/starters/{default → modular}/src/modules/auth/auth.routes.ts +0 -0
  282. /package/starters/{default → modular}/src/modules/auth/auth.service.ts +0 -0
  283. /package/starters/{default → modular}/src/modules/auth/auth.types.ts +0 -0
  284. /package/starters/{default → modular}/src/modules/billing/_contracts/stripe.types.ts +0 -0
  285. /package/starters/{default → modular}/src/modules/billing/api/stripe.connector.ts +0 -0
  286. /package/starters/{default → modular}/src/modules/billing/billing.public.ts +0 -0
  287. /package/starters/{default → modular}/src/modules/billing/billing.routes.ts +0 -0
  288. /package/starters/{default → modular}/src/modules/billing/billing.types.ts +0 -0
  289. /package/starters/{default → modular}/src/modules/billing/components/invoice-status-badge.component.ts +0 -0
  290. /package/starters/{default → modular}/src/modules/billing/data/invoices.resource.ts +0 -0
  291. /package/starters/{default → modular}/src/shared/http/http-client.ts +0 -0
  292. /package/starters/{default → modular}/src/shared/http/http-error.ts +0 -0
  293. /package/starters/{default → modular}/src/shared/http/interceptors.ts +0 -0
  294. /package/starters/{default → modular}/src/shared/lib/format-date.ts +0 -0
  295. /package/starters/{default → modular}/src/shared/styles/content.css +0 -0
  296. /package/starters/{default → modular}/src/shared/styles/shell.css +0 -0
  297. /package/starters/{default → modular}/src/shared/styles/tokens.css +0 -0
  298. /package/starters/{default → modular}/src/shared/ui/x-spinner.component.ts +0 -0
@@ -1,73 +0,0 @@
1
- # Структура проєкту
2
-
3
- Кожен Mado-застосунок використовує одну канонічну форму. Це потрібно, щоб люди
4
- й AI-асистенти однаково розуміли, де живе код.
5
-
6
- ```txt
7
- my-app/
8
- ├── package.json # runtime dep: @madojs/mado
9
- ├── tsconfig.json # strict TS, ES2022, Bundler resolution
10
- ├── vite.config.ts # mado() from @madojs/mado/vite
11
- ├── index.html # Vite entry + SPA shell
12
- ├── public/ # static assets: favicon, images, robots.txt
13
- └── src/
14
- ├── main.ts # imports CSS and mounts router into #app
15
- ├── app.routes.ts # app map: manifest + default routes(...)
16
- ├── layouts/ # app-zone layouts
17
- ├── shared/ # ui, http, lib, styles
18
- └── modules/ # bounded contexts
19
- └── billing/
20
- ├── billing.routes.ts
21
- ├── billing.public.ts
22
- ├── billing.types.ts
23
- ├── pages/
24
- ├── data/
25
- ├── api/
26
- └── _contracts/
27
- ```
28
-
29
- ## Artifact States
30
-
31
- | Folder | Що це | Хто пише | Deploy? |
32
- | --- | --- | --- | --- |
33
- | `src/` | TypeScript sources | ви | no |
34
- | `public/` | static assets copied as-is | ви | via `out/` |
35
- | `out/` | deploy artifact: SPA shell + assets + baked HTML | `mado release` | yes |
36
-
37
- `mado release` = `typecheck` + Vite build (`out/index.html`, `out/assets/`,
38
- `public/*`) + `bake` directly into route paths + `sitemap.xml` + precompression.
39
-
40
- ## Where To Put Files
41
-
42
- | What | Where |
43
- | --- | --- |
44
- | Page for a new URL | `src/modules/<module>/pages/<name>.page.ts` + module routes |
45
- | Module route map | `src/modules/<module>/<module>.routes.ts` |
46
- | App shell/layout | `src/layouts/<zone>.layout.ts` |
47
- | Shared UI widget | `src/shared/ui/<x-name>.component.ts` |
48
- | Module-only UI widget | `src/modules/<module>/components/<name>.component.ts` |
49
- | API connector | `src/modules/<module>/api/<provider>.connector.ts` |
50
- | Data resource/mutation | `src/modules/<module>/data/<name>.resource.ts` |
51
- | Auth/session | `src/modules/auth/` |
52
- | Public module surface | `src/modules/<module>/<module>.public.ts` |
53
- | Pure function without UI | `src/shared/lib/<name>.ts` |
54
- | Static image / favicon | `public/<file>` |
55
- | App-zone shell CSS | `src/shared/styles/shell.css` |
56
- | Page-level CSS | `src/shared/styles/content.css` |
57
-
58
- ## Vite Config
59
-
60
- ```ts
61
- import { defineConfig } from "vite";
62
- import { mado } from "@madojs/mado/vite";
63
-
64
- export default defineConfig({
65
- plugins: [mado()],
66
- css: {
67
- transformer: "lightningcss",
68
- },
69
- });
70
- ```
71
-
72
- Starter uses Vite's Lightning CSS transformer. Mado does not own prefixing, CSS
73
- lowering or minification.
@@ -1,48 +0,0 @@
1
- # Static Bake & SEO
2
-
3
- Mado навмисно не робить SSR із hydration. Для SEO-сторінок є `bake`: build-time
4
- prerender у статичний HTML із meta-тегами, JSON-LD і baked data.
5
-
6
- ## Коли підходить
7
-
8
- - Блог, документація, landing pages.
9
- - Невеликі каталоги з кінцевим набором сторінок.
10
- - Сторінки, де crawlers мають одразу побачити контент.
11
- - Контент не персоналізований для конкретного користувача.
12
-
13
- ## Коли не підходить
14
-
15
- - Авторизовані dashboards.
16
- - Персоналізований HTML.
17
- - Real-time дані.
18
- - Каталоги, які потребують справжнього server rendering на кожен запит.
19
-
20
- ## Сторінка з bake
21
-
22
- ```ts
23
- import { page, html } from "@madojs/mado";
24
-
25
- export default page<{ slug: string }, Product>({
26
- title: ({ slug }) => `Product ${slug}`,
27
- head: ({ slug }, data) => ({
28
- description: data?.description ?? `Product ${slug}`,
29
- }),
30
- bake: {
31
- paths: () => products.map((p) => ({ slug: p.slug })),
32
- data: ({ slug }) => findProduct(slug),
33
- revalidate: 3600,
34
- },
35
- view: ({ params }) => html`<x-product data-slug=${params.slug}></x-product>`,
36
- });
37
- ```
38
-
39
- `bake.paths()` повертає всі params, `bake.data()` повертає дані для конкретної
40
- сторінки, `head()` формує SEO-метадані.
41
-
42
- ## Edge prerender
43
-
44
- Для великих наборів сторінок можна робити той самий підхід на edge: Cloudflare
45
- Worker генерує HTML на cache miss, кладе в KV і віддає з TTL.
46
-
47
- Це не hydration. Клієнтський Mado-застосунок все одно стартує нормально і
48
- перерендерює сторінку після завантаження.
@@ -1,26 +0,0 @@
1
- # Налаштування IDE
2
-
3
- Mado використовує tagged templates `html`` і `css``. Для TypeScript це звичайні
4
- рядки, тому підсвітка HTML/CSS залежить від IDE.
5
-
6
- ## VS Code
7
-
8
- Рекомендовано встановити `lit-plugin` або інше розширення, яке розуміє
9
- `html``/`css`` tagged templates.
10
-
11
- ## WebStorm
12
-
13
- WebStorm зазвичай розуміє tagged templates без додаткового налаштування.
14
-
15
- ## Neovim / Helix
16
-
17
- Можна використовувати LSP/плагіни для lit-html або inline HTML у template
18
- strings.
19
-
20
- ## Що IDE не перевірить
21
-
22
- - Чи правильно ти обгорнув `count()` у `() => count()`.
23
- - Чи варто використовувати `?disabled` замість `disabled`.
24
- - Чи є `.js` у browser ESM imports.
25
-
26
- Для цього потрібні правила з `AGENTS.md`, тести та уважний review.
@@ -1,34 +0,0 @@
1
- # Чому Mado
2
-
3
- Mado не намагається “вбити React” або довести, що всі інші помиляються. Це
4
- інструмент для людей, які хочуть маленький, читабельний frontend runtime поверх
5
- нативного браузера.
6
-
7
- ## Lit
8
-
9
- Lit чудовий для дизайн-систем і компонентів, які мають жити всередині будь-якого
10
- framework. Mado краще підходить, коли ти пишеш увесь застосунок і хочеш router,
11
- data, forms, context і static bake в одному маленькому пакеті.
12
-
13
- ## Solid
14
-
15
- Solid швидший і зріліший. Якщо тобі комфортно з JSX transform, Vite і mature
16
- ecosystem — Solid може бути кращим вибором. Mado обирає інше: browser ESM,
17
- `tsc`, tagged templates і код, який можна прочитати.
18
-
19
- ## htmx
20
-
21
- htmx сильний, коли backend володіє HTML fragments. Mado потрібен тоді, коли все
22
- ж хочеться SPA: локальний UI state, optimistic updates, query params, cached
23
- resources, persisted state і lazy modules.
24
-
25
- ## React / Vue / Svelte
26
-
27
- Вони мають більші ecosystem, більше відповідей у Google/LLM і більше людей на
28
- ринку. Mado виграє не масштабом ecosystem, а ownership: маленький runtime,
29
- нуль runtime-залежностей і зрозумілі правила.
30
-
31
- ## Головна теза
32
-
33
- Mado — не найшвидший у synthetic benchmarks і не найбагатший ecosystem. Його
34
- сенс у тому, що frontend знову можна тримати в голові.
@@ -1,55 +0,0 @@
1
- # Mado для бекендерів
2
-
3
- Якщо ти пишеш Go, Rust, .NET, Java, Python або Node backend, Mado можна уявляти
4
- як маленький HTTP-сервер у браузері.
5
-
6
- | Backend mental model | Mado |
7
- |---|---|
8
- | router | `routes()` |
9
- | handler | `page().view` |
10
- | middleware/layout | `layout()` route group |
11
- | cache get-or-set | `resource()` |
12
- | POST/PUT/DELETE | `mutation()` |
13
- | cache invalidation | `invalidates` / `invalidate()` |
14
- | dependency injection | `createContext/provide/inject` |
15
-
16
- ## CRUD
17
-
18
- ```ts
19
- const users = resource(
20
- () => "/api/users",
21
- jsonFetcher<User[]>(),
22
- );
23
-
24
- const save = mutation(api.saveUser, {
25
- invalidates: ["/api/users*"],
26
- });
27
- ```
28
-
29
- Ключі `resource()` — це identity кешу. Додавайте endpoint, query params і форму
30
- даних у ключ: два живі `resource()` з однаковим ключем ділять cache та
31
- in-flight request. Якщо той самий ключ використано з іншим fetcher, Mado
32
- попереджає, бо зазвичай це означає, що ключ кешу занадто широкий.
33
-
34
- ## Форми
35
-
36
- ```ts
37
- const form = useForm({
38
- email: { required: true, type: "email" },
39
- });
40
- ```
41
-
42
- Mado використовує schema-based validation, близьку до HTML constraints, а не
43
- окрему validation ecosystem.
44
-
45
- ## Auth
46
-
47
- Auth зазвичай живе в `modules/auth` як signal/context. Protected area зручно
48
- робити через `layout()` group, який перевіряє session і показує dashboard або
49
- redirect/login.
50
-
51
- ## Правило
52
-
53
- Не тягни backend-архітектуру в frontend дослівно. Тримай UI state локальним,
54
- data fetching через `resource()`, mutation через `mutation()`, а shared services
55
- через context.
@@ -1,145 +0,0 @@
1
- # Типові помилки LLM у Mado-коді
2
-
3
- Цей файл потрібен, щоб AI-агенти не писали React/Vue-код у Mado-проєкті.
4
-
5
- ## JSX
6
-
7
- ```ts
8
- // Ні
9
- const view = <button>{count}</button>;
10
-
11
- // Так
12
- const view = html`<button>${count}</button>`;
13
- ```
14
-
15
- ## `useState` / `useEffect`
16
-
17
- ```ts
18
- // Ні
19
- const [count, setCount] = useState(0);
20
-
21
- // Так
22
- const count = signal(0);
23
- count.set(1);
24
- ```
25
-
26
- ## Signal `.value`
27
-
28
- ```ts
29
- // Ні
30
- count.value;
31
-
32
- // Так
33
- count();
34
- ```
35
-
36
- ## Нереактивний child binding
37
-
38
- ```ts
39
- // Нереактивно: count() прочитано один раз
40
- html`<div>${count() * 2}</div>`;
41
-
42
- // Реактивно
43
- html`<div>${() => count() * 2}</div>`;
44
- ```
45
-
46
- ## Boolean attributes
47
-
48
- ```ts
49
- // Ні
50
- html`<button disabled=${loading}>Save</button>`;
51
-
52
- // Так
53
- html`<button ?disabled=${loading}>Save</button>`;
54
- ```
55
-
56
- ## Списки
57
-
58
- ```ts
59
- // Не для динамічного reorder
60
- items().map((item) => html`<li>${item.name}</li>`);
61
-
62
- // Так
63
- each(
64
- items(),
65
- (item) => item.id,
66
- (item) => html`<li>${item.name}</li>`,
67
- );
68
- ```
69
-
70
- ## Imports
71
-
72
- У browser ESM локальні imports мають мати `.js`:
73
-
74
- ```ts
75
- import "./components/x-card.js";
76
- ```
77
-
78
- ## `resource()` lifecycle
79
-
80
- `resource()` створюй у component setup або всередині явного lifecycle, щоб cleanup
81
- відбувався автоматично.
82
-
83
- ## Component names
84
-
85
- Custom element name має містити дефіс. `x-*` — демо-конвенція; production може
86
- мати `app-*`, `crm-*`, `ticket-*`, `admin-*`.
87
-
88
- ## `host.getAttribute()` у render — не реактивно
89
-
90
- ```ts
91
- // Ні: читається один раз, не оновлюється
92
- component("x-badge", ({ host }) => () => {
93
- const variant = host.getAttribute("variant") ?? "default";
94
- return html`<span class=${variant}>...</span>`;
95
- });
96
-
97
- // Так: ctx.attr() — реактивний Signal
98
- component("x-badge", ({ attr }) => {
99
- const variant = attr("variant", "default");
100
- return () => html`<span class=${() => `badge-${variant()}`}>...</span>`;
101
- });
102
- ```
103
-
104
- ## Shadow DOM кнопка і submit форми
105
-
106
- `<button type="submit">` всередині Shadow DOM не тригерить submit `<form>` у Light DOM.
107
- Використовуйте `form.requestSubmit()` у click handler.
108
-
109
- ```ts
110
- const handleClick = () => {
111
- const form = host.closest("form");
112
- if (form && !host.hasAttribute("disabled")) form.requestSubmit();
113
- };
114
- ```
115
-
116
- ## `useForm()` + Shadow DOM input
117
-
118
- Після ретаргетингу `e.target` — це `<x-input>`, у якого немає `.name`/`.value`.
119
- Додайте proxy-властивості на host:
120
-
121
- ```ts
122
- Object.defineProperty(host, "name", {
123
- get: () => host.getAttribute("name") ?? "",
124
- });
125
- Object.defineProperty(host, "value", {
126
- get: () => host.shadowRoot?.querySelector("input")?.value ?? "",
127
- });
128
- ```
129
-
130
- Детальніше: [`17-shadow-dom-forms.md`](./17-shadow-dom-forms.md).
131
-
132
- ## Шпаргалка
133
-
134
- | React/інше | Mado |
135
- | --------------------------- | ---------------------------- |
136
- | `useState(0)` | `signal(0)` |
137
- | `useEffect(() => {...})` | `effect(() => {...})` |
138
- | `useMemo(() => x)` | `computed(() => x)` |
139
- | `useQuery(['key'], fn)` | `resource(() => 'key', fn)` |
140
- | `useRouter().push('/')` | `navigate('/')` |
141
- | `class extends HTMLElement` | `component('x-name', setup)` |
142
- | `host.getAttribute('x')` | `ctx.attr('x', default)` |
143
- | `jsonFetcher()` з auth | `apiFetcher()` |
144
- | `setInterval` в page view | `onDispose(() => clearInterval(id))` |
145
- | читання сигналу в async init | `untracked(() => cursor())` |
@@ -1,34 +0,0 @@
1
- # LLM Zero-History Test
2
-
3
- This document defines a manual validation test: can a fresh LLM write idiomatic
4
- Mado without falling back to React-shaped code?
5
-
6
- ## Allowed Context
7
-
8
- - `AGENTS.md`
9
- - `README.md`
10
- - `docs/uk/07-llm-pitfalls.md` or the English version
11
- - files from the external `madojs-examples` workspace only when the agent asks
12
- for a larger app pattern
13
-
14
- ## Task
15
-
16
- Build a small ticket-admin SPA:
17
-
18
- - routes: `/`, `/tickets`, `/tickets/new`, `/tickets/:id`, `*`;
19
- - in-memory mock API with realistic async delays;
20
- - list page with `resource()`, `queryParam()`, `computed()` and keyed `each()`;
21
- - create/edit flows with `useForm()` + `mutation()` + `invalidates`;
22
- - local UI state with `signal()`.
23
-
24
- ## Failure Checklist
25
-
26
- - JSX, `useState`, `useEffect`, `ref`, `$state`, class-style components;
27
- - `${signal()}` where a reactive child thunk is required;
28
- - `disabled=${...}` instead of `?disabled=${...}`;
29
- - unkeyed `.map()` for dynamic lists;
30
- - `resource()` created outside lifecycle-aware context;
31
- - new runtime dependencies or new public APIs.
32
-
33
- The historical tickets implementation lives in the external examples workspace.
34
- The core repository no longer ships that artifact.
@@ -1,58 +0,0 @@
1
- # Shadow DOM vs Light DOM
2
-
3
- Mado components use Shadow DOM by default. This is good for self-contained
4
- widgets, but app zones and pages usually stay as light DOM templates.
5
-
6
- ## Rule
7
-
8
- Use route layouts for app zones:
9
-
10
- ```ts
11
- export default page({
12
- view: ({ child }) => html`<main class="app-main">${child}</main>`,
13
- });
14
- ```
15
-
16
- These files live in `src/layouts/` and are composed from `src/app.routes.ts`
17
- with `layout()`. They are styled by `src/shared/styles/shell.css`.
18
-
19
- Use page files for screens:
20
-
21
- ```ts
22
- export default page({
23
- view: () => html`<section><h1>Users</h1></section>`,
24
- });
25
- ```
26
-
27
- Page-level tables, forms, prose and simple states are styled by
28
- `src/shared/styles/content.css`.
29
-
30
- Use Shadow DOM components for leaf widgets:
31
-
32
- - buttons, badges, cards, metrics;
33
- - spinners, modals, toasts;
34
- - widgets that should own their CSS.
35
-
36
- ```ts
37
- component("x-status-badge", ({ attr }) => {
38
- const status = attr("status", "draft");
39
- return () => html`<span>${status}</span>`;
40
- }, {
41
- styles: css`
42
- :host { display: inline-block; }
43
- span { color: var(--color-text-muted); }
44
- `,
45
- });
46
- ```
47
-
48
- ## Style Behavior
49
-
50
- - `tokens.css` defines CSS custom properties; `var(...)` crosses Shadow DOM.
51
- - `reset.css`, `shell.css`, `content.css` apply only to document/light DOM.
52
- - Class selectors like `.data`, `.app-main`, `.error` do not cross Shadow DOM.
53
- - Component-local styles live in ``css`...` `` inside `component()` options.
54
- - If a Shadow component accepts children, use `<slot>` and style the frame in
55
- component styles.
56
-
57
- If a page looks unstyled, you probably used global classes inside a Shadow DOM
58
- component. Move markup into a page/layout or move CSS into component styles.
@@ -1,97 +0,0 @@
1
- # Архітектура застосунку
2
-
3
- Офіційний starter — канонічна production-форма Mado-застосунку. Це не
4
- framework всередині framework: лише files, imports, Mado primitives та ESLint
5
- boundaries.
6
-
7
- ```txt
8
- src/
9
- ├── main.ts
10
- ├── app.routes.ts
11
- ├── layouts/
12
- │ ├── app-shell.layout.ts
13
- │ └── auth-shell.layout.ts
14
- ├── shared/
15
- │ ├── http/
16
- │ ├── lib/
17
- │ ├── styles/
18
- │ └── ui/
19
- └── modules/
20
- ├── auth/
21
- │ ├── auth.routes.ts
22
- │ ├── auth.public.ts
23
- │ ├── auth.service.ts
24
- │ ├── auth.connector.ts
25
- │ ├── auth.guard.ts
26
- │ ├── login.page.ts
27
- │ └── _contracts/
28
- └── billing/
29
- ├── billing.routes.ts
30
- ├── billing.public.ts
31
- ├── billing.types.ts
32
- ├── api/
33
- ├── data/
34
- ├── pages/
35
- ├── components/
36
- └── _contracts/
37
- ```
38
-
39
- `src/app.routes.ts` is the app map. Modules export plain route maps; app routes
40
- decide which shell and guard wrap each zone.
41
-
42
- ```ts
43
- import { layout, routes } from "@madojs/mado";
44
- import { requireAuth } from "./modules/auth/auth.public";
45
- import { authRoutes } from "./modules/auth/auth.routes";
46
- import { billingRoutes } from "./modules/billing/billing.routes";
47
-
48
- export const manifest = {
49
- "/": () => import("./modules/home/home.page"),
50
- "/login": layout({
51
- layout: () => import("./layouts/auth-shell.layout"),
52
- routes: authRoutes,
53
- }),
54
- "/billing": layout({
55
- layout: () => import("./layouts/app-shell.layout"),
56
- guard: requireAuth,
57
- routes: billingRoutes,
58
- }),
59
- "*": () => import("./modules/home/not-found.page"),
60
- };
61
-
62
- export default routes(manifest);
63
- ```
64
-
65
- Page-local signals, resources and forms live inside `view()`. Module-wide state
66
- lives in `*.service.ts`.
67
-
68
- ## Styles
69
-
70
- | File | Role |
71
- | --- | --- |
72
- | `src/shared/styles/tokens.css` | design tokens as CSS custom properties |
73
- | `src/shared/styles/reset.css` | document/light DOM reset |
74
- | `src/shared/styles/shell.css` | app-zone layouts from `src/layouts/` |
75
- | `src/shared/styles/content.css` | page-level forms, tables, prose and states |
76
-
77
- Leaf components keep their own styles in ``css`...` `` inside `component()`
78
- options and depend on tokens, not global classes.
79
-
80
- `vite.config.ts` uses Vite's Lightning CSS transformer. Mado does not own
81
- prefixing, CSS lowering or minification.
82
-
83
- ## CLI
84
-
85
- ```bash
86
- mado new module billing
87
- mado new page billing/pages/invoices-list
88
- mado new connector billing/api/stripe
89
- mado new resource billing/data/invoices
90
- mado new service billing/cart
91
- mado new form billing/invoice
92
- mado new component billing/components/invoice-status-badge
93
- mado new guard billing/billing
94
- mado new layout app-shell
95
- ```
96
-
97
- The generator writes files only and does not edit `app.routes.ts`.
@@ -1,47 +0,0 @@
1
- # Layouts
2
-
3
- The blessed layout recipe in Mado is a route group in `src/app.routes.ts`.
4
- Do not put a single global shell in `main.ts` when the app has multiple zones:
5
- public, auth, app, embed.
6
-
7
- ```ts
8
- import { layout, routes } from "@madojs/mado";
9
- import { requireAuth } from "./modules/auth/auth.public";
10
- import { authRoutes } from "./modules/auth/auth.routes";
11
- import { billingRoutes } from "./modules/billing/billing.routes";
12
-
13
- export const manifest = {
14
- "/": () => import("./modules/home/home.page.js"),
15
- "/login": layout({
16
- layout: () => import("./layouts/auth-shell.layout.js"),
17
- routes: authRoutes,
18
- }),
19
- "/billing": layout({
20
- layout: () => import("./layouts/app-shell.layout.js"),
21
- guard: requireAuth,
22
- routes: billingRoutes,
23
- }),
24
- "*": () => import("./modules/home/not-found.page.js"),
25
- };
26
-
27
- export default routes(manifest);
28
- ```
29
-
30
- A layout is a normal `page({ view })` that renders `child`:
31
-
32
- ```ts
33
- export default page({
34
- view: ({ child }) => html`
35
- <div class="layout layout--app">
36
- <main class="app-main">${child}</main>
37
- </div>
38
- `,
39
- });
40
- ```
41
-
42
- Rules:
43
-
44
- - one shell per route group, not per page;
45
- - modules export plain route maps and do not call `layout()`;
46
- - guard on a group protects the whole subtree;
47
- - layout view stays stateless; page-local state lives in pages/components/resources.
@@ -1,70 +0,0 @@
1
- # Auth and API
2
-
3
- The default starter is the blessed recipe. HTTP mechanics live in
4
- `src/shared/http/`, auth state lives in `src/modules/auth/`.
5
-
6
- ```txt
7
- src/shared/http/
8
- http-client.ts
9
- http-error.ts
10
- interceptors.ts
11
-
12
- src/modules/auth/
13
- auth.connector.ts
14
- auth.service.ts
15
- auth.guard.ts
16
- auth.routes.ts
17
- auth.public.ts
18
- _contracts/
19
- ```
20
-
21
- Business module flow:
22
-
23
- ```txt
24
- connector -> resource/mutation -> page
25
- ```
26
-
27
- Pages do not import DTOs and do not call `fetch()` directly. Connectors do not
28
- import Mado reactivity or UI.
29
-
30
- ## Auth Service
31
-
32
- ```ts
33
- const _user = signal<User | null>(null);
34
- const _token = signal<string | null>(null);
35
-
36
- export const user = () => _user();
37
- export const isAuthed = computed(() => _user() !== null);
38
- ```
39
-
40
- Expose only what other modules need through `auth.public.ts`.
41
-
42
- ## Guards
43
-
44
- ```ts
45
- export function requireAuth(): boolean | string {
46
- if (isAuthed()) return true;
47
- return "/login";
48
- }
49
- ```
50
-
51
- Use in `src/app.routes.ts`:
52
-
53
- ```ts
54
- "/billing": layout({
55
- layout: () => import("./layouts/app-shell.layout"),
56
- guard: requireAuth,
57
- routes: billingRoutes,
58
- }),
59
- ```
60
-
61
- ## Dev Proxy
62
-
63
- ```ts
64
- export default defineConfig({
65
- plugins: [mado()],
66
- server: {
67
- proxy: { "/api": "http://localhost:3000" },
68
- },
69
- });
70
- ```