@starci/skills 1.1.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 (321) hide show
  1. package/INDEX.md +74 -0
  2. package/INDEX.vi.md +75 -0
  3. package/README.md +44 -0
  4. package/README.vi.md +43 -0
  5. package/SKILL.md +135 -0
  6. package/SKILL.vi.md +128 -0
  7. package/alias/INDEX.md +104 -0
  8. package/alias/INDEX.vi.md +104 -0
  9. package/alias/alias.json +297 -0
  10. package/bin/starci-skills.mjs +219 -0
  11. package/knowledge/INDEX.md +22 -0
  12. package/knowledge/INDEX.vi.md +22 -0
  13. package/knowledge/grammars/starci/DNA.md +146 -0
  14. package/knowledge/grammars/starci/DNA.vi.md +146 -0
  15. package/knowledge/grammars/starci/INDEX.md +25 -0
  16. package/knowledge/grammars/starci/INDEX.vi.md +25 -0
  17. package/knowledge/grammars/starci/family.md +50 -0
  18. package/knowledge/grammars/starci/family.vi.md +50 -0
  19. package/knowledge/grammars/starci/idioms.md +120 -0
  20. package/knowledge/grammars/starci/idioms.vi.md +121 -0
  21. package/knowledge/grammars/starci/playbook.md +36 -0
  22. package/knowledge/grammars/starci/playbook.vi.md +35 -0
  23. package/knowledge/patterns/be/INDEX.md +29 -0
  24. package/knowledge/patterns/be/INDEX.vi.md +29 -0
  25. package/knowledge/patterns/be/comment.md +80 -0
  26. package/knowledge/patterns/be/comment.vi.md +80 -0
  27. package/knowledge/patterns/be/error.md +86 -0
  28. package/knowledge/patterns/be/error.vi.md +86 -0
  29. package/knowledge/patterns/be/folder.md +87 -0
  30. package/knowledge/patterns/be/folder.vi.md +86 -0
  31. package/knowledge/patterns/be/function.md +80 -0
  32. package/knowledge/patterns/be/function.vi.md +80 -0
  33. package/knowledge/patterns/be/imports.md +79 -0
  34. package/knowledge/patterns/be/imports.vi.md +79 -0
  35. package/knowledge/patterns/be/naming.md +87 -0
  36. package/knowledge/patterns/be/naming.vi.md +87 -0
  37. package/knowledge/patterns/be/test.md +79 -0
  38. package/knowledge/patterns/be/test.vi.md +79 -0
  39. package/knowledge/patterns/be/typing.md +73 -0
  40. package/knowledge/patterns/be/typing.vi.md +73 -0
  41. package/knowledge/patterns/fe/INDEX.md +29 -0
  42. package/knowledge/patterns/fe/INDEX.vi.md +29 -0
  43. package/knowledge/patterns/fe/comment.md +70 -0
  44. package/knowledge/patterns/fe/comment.vi.md +70 -0
  45. package/knowledge/patterns/fe/error.md +61 -0
  46. package/knowledge/patterns/fe/error.vi.md +61 -0
  47. package/knowledge/patterns/fe/folder.md +98 -0
  48. package/knowledge/patterns/fe/folder.vi.md +95 -0
  49. package/knowledge/patterns/fe/function.md +70 -0
  50. package/knowledge/patterns/fe/function.vi.md +70 -0
  51. package/knowledge/patterns/fe/imports.md +87 -0
  52. package/knowledge/patterns/fe/imports.vi.md +87 -0
  53. package/knowledge/patterns/fe/naming.md +77 -0
  54. package/knowledge/patterns/fe/naming.vi.md +77 -0
  55. package/knowledge/patterns/fe/test.md +73 -0
  56. package/knowledge/patterns/fe/test.vi.md +73 -0
  57. package/knowledge/patterns/fe/typing.md +67 -0
  58. package/knowledge/patterns/fe/typing.vi.md +67 -0
  59. package/knowledge/ui/INDEX.md +101 -0
  60. package/knowledge/ui/INDEX.vi.md +101 -0
  61. package/knowledge/ui/composition/INDEX.md +60 -0
  62. package/knowledge/ui/composition/INDEX.vi.md +63 -0
  63. package/knowledge/ui/composition/accent.md +73 -0
  64. package/knowledge/ui/composition/accent.vi.md +74 -0
  65. package/knowledge/ui/composition/action.md +55 -0
  66. package/knowledge/ui/composition/action.vi.md +56 -0
  67. package/knowledge/ui/composition/coverage.md +37 -0
  68. package/knowledge/ui/composition/coverage.vi.md +37 -0
  69. package/knowledge/ui/composition/cta.md +79 -0
  70. package/knowledge/ui/composition/cta.vi.md +79 -0
  71. package/knowledge/ui/composition/feedback.md +55 -0
  72. package/knowledge/ui/composition/feedback.vi.md +56 -0
  73. package/knowledge/ui/composition/hierarchy.md +83 -0
  74. package/knowledge/ui/composition/hierarchy.vi.md +82 -0
  75. package/knowledge/ui/composition/layout.md +91 -0
  76. package/knowledge/ui/composition/layout.vi.md +93 -0
  77. package/knowledge/ui/composition/responsive.md +67 -0
  78. package/knowledge/ui/composition/responsive.vi.md +67 -0
  79. package/knowledge/ui/composition/state.md +105 -0
  80. package/knowledge/ui/composition/state.vi.md +106 -0
  81. package/knowledge/ui/presentation/INDEX.md +94 -0
  82. package/knowledge/ui/presentation/INDEX.vi.md +69 -0
  83. package/knowledge/ui/presentation/boundary.md +170 -0
  84. package/knowledge/ui/presentation/boundary.vi.md +169 -0
  85. package/knowledge/ui/presentation/font.md +155 -0
  86. package/knowledge/ui/presentation/font.vi.md +156 -0
  87. package/knowledge/ui/presentation/gap.md +181 -0
  88. package/knowledge/ui/presentation/gap.vi.md +181 -0
  89. package/knowledge/ui/presentation/margin.md +168 -0
  90. package/knowledge/ui/presentation/margin.vi.md +171 -0
  91. package/knowledge/ui/presentation/measure.md +174 -0
  92. package/knowledge/ui/presentation/measure.vi.md +178 -0
  93. package/knowledge/ui/presentation/overflow.md +142 -0
  94. package/knowledge/ui/presentation/overflow.vi.md +142 -0
  95. package/knowledge/ui/presentation/padding.md +293 -0
  96. package/knowledge/ui/presentation/padding.vi.md +292 -0
  97. package/knowledge/ui/presentation/surface.md +166 -0
  98. package/knowledge/ui/presentation/surface.vi.md +166 -0
  99. package/knowledge/ui/presentation/text-flow.md +123 -0
  100. package/knowledge/ui/presentation/text-flow.vi.md +123 -0
  101. package/knowledge/ui/presentation/tone.md +114 -0
  102. package/knowledge/ui/presentation/tone.vi.md +113 -0
  103. package/knowledge/ui/proof/INDEX.md +55 -0
  104. package/knowledge/ui/proof/INDEX.vi.md +55 -0
  105. package/knowledge/ui/proof/accessibility.md +67 -0
  106. package/knowledge/ui/proof/accessibility.vi.md +68 -0
  107. package/knowledge/ui/proof/contrast.md +58 -0
  108. package/knowledge/ui/proof/contrast.vi.md +57 -0
  109. package/knowledge/ui/proof/focus.md +76 -0
  110. package/knowledge/ui/proof/focus.vi.md +76 -0
  111. package/knowledge/ui/proof/motion.md +63 -0
  112. package/knowledge/ui/proof/motion.vi.md +64 -0
  113. package/knowledge/ui/proof/render-truth.md +63 -0
  114. package/knowledge/ui/proof/render-truth.vi.md +63 -0
  115. package/operators/INDEX.md +199 -0
  116. package/operators/INDEX.vi.md +199 -0
  117. package/operators/architecture-decide/errors.json +115 -0
  118. package/operators/architecture-decide/operator.json +20 -0
  119. package/operators/architecture-decide/operator.md +133 -0
  120. package/operators/architecture-decide/operator.vi.md +130 -0
  121. package/operators/architecture-decide/self-test.mjs +221 -0
  122. package/operators/architecture-decide/validate.mjs +112 -0
  123. package/operators/backend-source-apply/errors.json +66 -0
  124. package/operators/backend-source-apply/operator.json +20 -0
  125. package/operators/backend-source-apply/operator.md +189 -0
  126. package/operators/backend-source-apply/operator.vi.md +185 -0
  127. package/operators/backend-source-apply/self-test.mjs +257 -0
  128. package/operators/backend-source-apply/validate.mjs +240 -0
  129. package/operators/business-decide/errors.json +78 -0
  130. package/operators/business-decide/operator.json +20 -0
  131. package/operators/business-decide/operator.md +176 -0
  132. package/operators/business-decide/operator.vi.md +174 -0
  133. package/operators/business-decide/self-test.mjs +225 -0
  134. package/operators/business-decide/validate.mjs +277 -0
  135. package/operators/content-generate/errors.json +106 -0
  136. package/operators/content-generate/operator.json +21 -0
  137. package/operators/content-generate/operator.md +155 -0
  138. package/operators/content-generate/operator.vi.md +155 -0
  139. package/operators/content-generate/self-test.mjs +288 -0
  140. package/operators/content-generate/validate.mjs +196 -0
  141. package/operators/errors.json +178 -0
  142. package/operators/frontend-direction-decide/errors.json +135 -0
  143. package/operators/frontend-direction-decide/operator.json +21 -0
  144. package/operators/frontend-direction-decide/operator.md +167 -0
  145. package/operators/frontend-direction-decide/operator.vi.md +167 -0
  146. package/operators/frontend-direction-decide/self-test.mjs +226 -0
  147. package/operators/frontend-direction-decide/validate.mjs +146 -0
  148. package/operators/frontend-presentation-resolve/errors.json +42 -0
  149. package/operators/frontend-presentation-resolve/operator.json +19 -0
  150. package/operators/frontend-presentation-resolve/operator.md +142 -0
  151. package/operators/frontend-presentation-resolve/operator.vi.md +140 -0
  152. package/operators/frontend-presentation-resolve/self-test.mjs +163 -0
  153. package/operators/frontend-presentation-resolve/validate.mjs +143 -0
  154. package/operators/frontend-source-apply/errors.json +30 -0
  155. package/operators/frontend-source-apply/operator.json +20 -0
  156. package/operators/frontend-source-apply/operator.md +127 -0
  157. package/operators/frontend-source-apply/operator.vi.md +126 -0
  158. package/operators/frontend-source-apply/self-test.mjs +214 -0
  159. package/operators/frontend-source-apply/validate.mjs +133 -0
  160. package/operators/frontend-surface-audit/errors.json +5 -0
  161. package/operators/frontend-surface-audit/operator.json +22 -0
  162. package/operators/frontend-surface-audit/operator.md +121 -0
  163. package/operators/frontend-surface-audit/operator.vi.md +121 -0
  164. package/operators/frontend-surface-audit/self-test.mjs +185 -0
  165. package/operators/frontend-surface-audit/validate.mjs +127 -0
  166. package/operators/git-publish/errors.json +54 -0
  167. package/operators/git-publish/operator.json +20 -0
  168. package/operators/git-publish/operator.md +180 -0
  169. package/operators/git-publish/operator.vi.md +178 -0
  170. package/operators/git-publish/self-test.mjs +177 -0
  171. package/operators/git-publish/validate.mjs +106 -0
  172. package/operators/platform-operate/errors.json +90 -0
  173. package/operators/platform-operate/operator.json +22 -0
  174. package/operators/platform-operate/operator.md +162 -0
  175. package/operators/platform-operate/operator.vi.md +160 -0
  176. package/operators/platform-operate/self-test.mjs +202 -0
  177. package/operators/platform-operate/validate.mjs +193 -0
  178. package/operators/quality-verify/errors.json +54 -0
  179. package/operators/quality-verify/operator.json +20 -0
  180. package/operators/quality-verify/operator.md +185 -0
  181. package/operators/quality-verify/operator.vi.md +177 -0
  182. package/operators/quality-verify/self-test.mjs +210 -0
  183. package/operators/quality-verify/validate.mjs +197 -0
  184. package/operators/release-deploy/errors.json +158 -0
  185. package/operators/release-deploy/operator.json +23 -0
  186. package/operators/release-deploy/operator.md +183 -0
  187. package/operators/release-deploy/operator.vi.md +181 -0
  188. package/operators/release-deploy/self-test.mjs +235 -0
  189. package/operators/release-deploy/validate.mjs +129 -0
  190. package/operators/uat-verify/errors.json +78 -0
  191. package/operators/uat-verify/operator.json +25 -0
  192. package/operators/uat-verify/operator.md +162 -0
  193. package/operators/uat-verify/operator.vi.md +161 -0
  194. package/operators/uat-verify/self-test.mjs +270 -0
  195. package/operators/uat-verify/validate.mjs +202 -0
  196. package/operators/workspace-bind/errors.json +90 -0
  197. package/operators/workspace-bind/operator.json +21 -0
  198. package/operators/workspace-bind/operator.md +148 -0
  199. package/operators/workspace-bind/operator.vi.md +148 -0
  200. package/operators/workspace-bind/self-test.mjs +205 -0
  201. package/operators/workspace-bind/validate.mjs +152 -0
  202. package/package.json +50 -0
  203. package/readiness/initialization/workspaces/commit-policy.json +91 -0
  204. package/readiness/initialization/workspaces/config.schema.json +35 -0
  205. package/readiness/initialization/workspaces/device-state.schema.json +54 -0
  206. package/readiness/initialization/workspaces/local-route.schema.json +206 -0
  207. package/readiness/initialization/workspaces/portable-route.schema.json +200 -0
  208. package/resources/INDEX.md +96 -0
  209. package/resources/INDEX.vi.md +99 -0
  210. package/resources/agents/profiles/claude.json +131 -0
  211. package/resources/agents/profiles/openai.json +131 -0
  212. package/resources/orchestrator.json +71 -0
  213. package/resources/tools.json +85 -0
  214. package/routing.json +272 -0
  215. package/scripts/alias-registry.mjs +31 -0
  216. package/scripts/device-state.mjs +497 -0
  217. package/scripts/device-state.spec.mjs +18 -0
  218. package/scripts/errors-registry.mjs +68 -0
  219. package/scripts/generate-alias-doc.mjs +66 -0
  220. package/scripts/generate-grammar-dna.mjs +387 -0
  221. package/scripts/generate-operators-index.mjs +95 -0
  222. package/scripts/generate-presentation-owned.mjs +681 -0
  223. package/scripts/install-cli.spec.mjs +74 -0
  224. package/scripts/json-schema.mjs +94 -0
  225. package/scripts/operator-md.mjs +96 -0
  226. package/scripts/run-operator-self-tests.mjs +36 -0
  227. package/scripts/validate-alias.mjs +165 -0
  228. package/scripts/validate-defaults.mjs +72 -0
  229. package/scripts/validate-knowledge-citations.mjs +90 -0
  230. package/scripts/validate-operator.mjs +125 -0
  231. package/scripts/validate-request.mjs +80 -0
  232. package/scripts/validate-resources.mjs +117 -0
  233. package/scripts/validate-response.mjs +141 -0
  234. package/scripts/validate-routing.mjs +91 -0
  235. package/scripts/validate-step.mjs +50 -0
  236. package/scripts/validate-templates.mjs +226 -0
  237. package/scripts/validate-templates.spec.mjs +144 -0
  238. package/scripts/validate-workflows.mjs +106 -0
  239. package/scripts/workspace-portable.mjs +389 -0
  240. package/scripts/workspace-portable.spec.mjs +246 -0
  241. package/templates/README.md +47 -0
  242. package/templates/README.vi.md +45 -0
  243. package/templates/changes.example.md +27 -0
  244. package/templates/grammars.template.md +34 -0
  245. package/templates/kinds/architecture-decision.contract.json +14 -0
  246. package/templates/kinds/architecture-decision.skeleton.md +52 -0
  247. package/templates/kinds/backend-source-application.contract.json +10 -0
  248. package/templates/kinds/backend-source-application.skeleton.md +34 -0
  249. package/templates/kinds/business-promise-authority.contract.json +13 -0
  250. package/templates/kinds/business-promise-authority.skeleton.md +67 -0
  251. package/templates/kinds/capture.schema.json +33 -0
  252. package/templates/kinds/changes.contract.json +10 -0
  253. package/templates/kinds/changes.skeleton.md +26 -0
  254. package/templates/kinds/checks.schema.json +44 -0
  255. package/templates/kinds/claims.schema.json +165 -0
  256. package/templates/kinds/conformance.schema.json +15 -0
  257. package/templates/kinds/content-brief.contract.json +12 -0
  258. package/templates/kinds/content-brief.skeleton.md +45 -0
  259. package/templates/kinds/content-generation-receipt.contract.json +11 -0
  260. package/templates/kinds/content-generation-receipt.skeleton.md +40 -0
  261. package/templates/kinds/content-review.contract.json +11 -0
  262. package/templates/kinds/content-review.skeleton.md +45 -0
  263. package/templates/kinds/contract.schema.json +28 -0
  264. package/templates/kinds/coverage-matrix.schema.json +86 -0
  265. package/templates/kinds/coverage.schema.json +62 -0
  266. package/templates/kinds/current-state.schema.json +40 -0
  267. package/templates/kinds/delta.schema.json +95 -0
  268. package/templates/kinds/e2e.schema.json +63 -0
  269. package/templates/kinds/frontend-direction-decision.contract.json +93 -0
  270. package/templates/kinds/frontend-direction-decision.skeleton.md +68 -0
  271. package/templates/kinds/frontend-presentation-resolution.contract.json +11 -0
  272. package/templates/kinds/frontend-presentation-resolution.skeleton.md +32 -0
  273. package/templates/kinds/frontend-source-application.contract.json +10 -0
  274. package/templates/kinds/frontend-source-application.skeleton.md +30 -0
  275. package/templates/kinds/frontend-surface-audit.contract.json +52 -0
  276. package/templates/kinds/frontend-surface-audit.skeleton.md +32 -0
  277. package/templates/kinds/gate-result.schema.json +64 -0
  278. package/templates/kinds/git-publication.contract.json +82 -0
  279. package/templates/kinds/git-publication.skeleton.md +61 -0
  280. package/templates/kinds/independent-critique.contract.json +9 -0
  281. package/templates/kinds/independent-critique.skeleton.md +28 -0
  282. package/templates/kinds/inventory.schema.json +35 -0
  283. package/templates/kinds/model.schema.json +99 -0
  284. package/templates/kinds/mutations.schema.json +65 -0
  285. package/templates/kinds/platform-operation-receipt.contract.json +76 -0
  286. package/templates/kinds/platform-operation-receipt.skeleton.md +54 -0
  287. package/templates/kinds/probes.schema.json +130 -0
  288. package/templates/kinds/proof.schema.json +17 -0
  289. package/templates/kinds/quality-verification.contract.json +87 -0
  290. package/templates/kinds/quality-verification.skeleton.md +58 -0
  291. package/templates/kinds/release-deployment.contract.json +85 -0
  292. package/templates/kinds/release-deployment.skeleton.md +67 -0
  293. package/templates/kinds/route.schema.json +293 -0
  294. package/templates/kinds/stack-model.schema.json +90 -0
  295. package/templates/kinds/uat-capture.schema.json +35 -0
  296. package/templates/kinds/uat-flow-verification.contract.json +11 -0
  297. package/templates/kinds/uat-flow-verification.skeleton.md +47 -0
  298. package/templates/kinds/uat-snapshot.schema.json +96 -0
  299. package/templates/kinds/uat-verdicts.schema.json +41 -0
  300. package/templates/kinds/ui-coverage.schema.json +77 -0
  301. package/templates/kinds/verdicts.schema.json +39 -0
  302. package/templates/kinds/workspace-route-binding.contract.json +12 -0
  303. package/templates/kinds/workspace-route-binding.skeleton.md +60 -0
  304. package/templates/kinds/writes.schema.json +37 -0
  305. package/templates/operator.template.md +73 -0
  306. package/templates/patterns.template.md +31 -0
  307. package/templates/step/request.schema.json +42 -0
  308. package/templates/step/response.schema.json +144 -0
  309. package/templates/ui-composition.template.md +36 -0
  310. package/templates/ui-presentation.template.md +57 -0
  311. package/templates/ui-proof.template.md +34 -0
  312. package/workflows/README.md +37 -0
  313. package/workflows/README.vi.md +37 -0
  314. package/workflows/backend-feature.json +59 -0
  315. package/workflows/content-unit.json +19 -0
  316. package/workflows/frontend-new-surface.json +81 -0
  317. package/workflows/frontend-reconstruct.json +67 -0
  318. package/workflows/frontend-refine.json +67 -0
  319. package/workflows/frontend-with-uat.json +78 -0
  320. package/workflows/full-feature.json +104 -0
  321. package/workflows/release.json +29 -0
@@ -0,0 +1,171 @@
1
+ # Margin presentation
2
+
3
+ File này trả lời đúng một câu hỏi: khi nào một object do ứng dụng sở hữu được phép đẩy ra khỏi xung
4
+ quanh bằng một khoảng lệch ngoài, và lệch bao nhiêu.
5
+
6
+ Margin là ngoại lệ trong hệ này chứ không phải mặc định. Khoảng cách giữa các phần tử ngang hàng
7
+ thuộc về gap của cha, còn khoảng cách từ ranh giới tới nội dung thuộc về padding của chính ranh giới
8
+ đó. Margin chỉ đúng khi một object cần một khoảng lệch mà không quan hệ cha nào diễn đạt được, và lý
9
+ do đó phải gọi được tên.
10
+
11
+ Common phản ánh đúng như vậy: nó reset `margin` về `0` ở gần như mọi renderer nó sở hữu và để cha
12
+ nắm nhịp. Ứng dụng nào với tay tới margin trước là tạo ra hai chủ cho cùng một khoảng cách, tức
13
+ `DOUBLE_OWNER`.
14
+
15
+ ## Thang giá trị
16
+
17
+ `COMMON_SPACING_SCALE` là thang đóng. Số của rule là thứ tự trên thang đó. Nó không phải số bậc
18
+ Tailwind, và hai số này lệch nhau từ MARGIN-5 trở đi.
19
+
20
+ | Rule | Class | Giá trị | Token Common |
21
+ | --- | --- | --- | --- |
22
+ | MARGIN-0 | `m-0` | `0` | không có |
23
+ | MARGIN-1 | `m-1` | `.25rem` | không có |
24
+ | MARGIN-2 | `m-2` | `.5rem` | không có |
25
+ | MARGIN-3 | `m-3` | `.75rem` | không có |
26
+ | MARGIN-4 | `m-4` | `1rem` | không có |
27
+ | MARGIN-5 | `m-6` | `1.5rem` | không có |
28
+ | MARGIN-6 | `m-8` | `2rem` | không có |
29
+
30
+ Common không publish token margin nào. `MARGIN-AUTO` đứng riêng và không mang giá trị nào trên thang.
31
+
32
+ Các giá trị rem chỉ quy ra `0 / 4 / 8 / 12 / 16 / 24 / 32` pixel CSS khi root font size tính được là
33
+ `16px`. Khi kiểm tra lúc chạy thì dùng `expectedPx = remFactor * observedRootFontPx`.
34
+
35
+ ## Owner
36
+
37
+ Mỗi case gọi tên ai sở hữu khoảng lệch. Owner quyết định ứng dụng có được viết class hay không.
38
+
39
+ | Owner | Nghĩa | Ứng dụng viết |
40
+ | --- | --- | --- |
41
+ | `App` | Khoảng lệch là một ngoại lệ đặt chỗ có tên của ứng dụng | Viết class |
42
+ | Tên component | Common đã đặt hoặc reset margin bên trong component đó | Không viết gì, chỉ ghép component |
43
+ | `—` | Common chưa có đường dùng công khai cho quan hệ này | Viết class, ghi nhận là workaround |
44
+
45
+ Viết class ở chỗ owner là một component chính là `APP_REIMPLEMENTATION`. Thêm margin cho con trong
46
+ khi cha đã có gap diễn đạt đúng khoảng cách đó là `DOUBLE_OWNER`.
47
+
48
+ ## Margin mà Common đã sở hữu
49
+
50
+ Sinh từ claim của `@grammar/core` bằng `scripts/generate-presentation-owned.mjs`; muốn đổi thì sửa component, đừng sửa bảng này.
51
+
52
+ | Component | Phần tử hoặc điều kiện | Rule |
53
+ | --- | --- | --- |
54
+ | `Label` | root | MARGIN-0 |
55
+ | `MediaFrame` | root | MARGIN-0 |
56
+ | `PageContainer` | root | MARGIN-AUTO |
57
+ | `SectionHeader` | title | MARGIN-0 |
58
+ | `SurfaceAccordionCard` | accordion trigger wrapper | MARGIN-0 |
59
+ | `WorkspaceShell` | header, hasHeader | MARGIN-5 |
60
+
61
+ ## MARGIN-0 — `m-0` / `0`
62
+
63
+ Khoảng lệch bị gỡ đi để một quan hệ của cha trở thành chủ duy nhất của khoảng cách.
64
+
65
+ | Case | Dùng khi | Owner | Render |
66
+ | --- | --- | --- | --- |
67
+ | Case 1 | Một thẻ HTML mang margin mặc định chọi lại composition | `App` | `<h2 className="m-0">` trong section app đã tự nắm gap |
68
+ | Case 2 | Nội dung article đã render, nhịp do chính article nắm | `MarkdownArticle` | Ghép article, không viết margin |
69
+ | Case 3 | Bất kỳ renderer Common nào đã tự reset margin của nó | Chính component đó | Ghép nó, không viết margin |
70
+
71
+ Không phải rule này: xóa một khoảng lệch có chủ ý mà không chuyển quyết định đó cho một chủ thật sự
72
+ thì quan hệ đó thành vô chủ.
73
+
74
+ ## MARGIN-1 — `m-1` / `.25rem`
75
+
76
+ Khoảng hở ngoài nhỏ nhất, cho một object đặt chính xác mà chỉ cần vừa đủ rời khỏi mép.
77
+
78
+ | Case | Dùng khi | Owner | Render |
79
+ | --- | --- | --- | --- |
80
+ | Case 1 | Một nhãn đặt tuyệt đối, nếu không lệch thì chạm luôn vào mép khung chứa | `App` | `<span className="absolute left-0 top-0 m-1">` |
81
+
82
+ Không phải rule này: lặp lại trên nhiều phần tử ngang hàng là đang dựng lại một cái gap. Dùng GAP-1
83
+ trên cha.
84
+
85
+ ## MARGIN-2 — `m-2` / `.5rem`
86
+
87
+ Khoảng lệch gọn cho một object đặt độc lập.
88
+
89
+ | Case | Dùng khi | Owner | Render |
90
+ | --- | --- | --- | --- |
91
+ | Case 1 | Chú thích hoặc control phủ lên, neo vào một góc canvas do app sở hữu | `App` | `<aside className="absolute bottom-0 right-0 m-2">` |
92
+
93
+ Không phải rule này: dùng thay cho padding của container hoặc gap giữa các phần tử. Dùng PADDING-2
94
+ hoặc GAP-2.
95
+
96
+ ## MARGIN-3 — `m-3` / `.75rem`
97
+
98
+ Khoảng lệch dày dặn nhưng vẫn thấy rõ, cho một ngoại lệ đặt chỗ có tên.
99
+
100
+ | Case | Dùng khi | Owner | Render |
101
+ | --- | --- | --- | --- |
102
+ | Case 1 | Một object đặt trên nền nhiều chi tiết, để `.5rem` thì đọc thành chật | `App` | `<aside className="absolute right-0 top-0 m-3">` |
103
+
104
+ Không phải rule này: các mục lặp lại trong một danh sách. Dùng GAP-3 trên cha.
105
+
106
+ ## MARGIN-4 — `m-4` / `1rem`
107
+
108
+ Khoảng lệch ngoài chuẩn cho một object có ngoại lệ đặt chỗ tường minh.
109
+
110
+ | Case | Dùng khi | Owner | Render |
111
+ | --- | --- | --- | --- |
112
+ | Case 1 | Một object đứng riêng cần khoảng hở đều với khung chứa mà khung đó không sở hữu được | `App` | `<aside className="m-4">` |
113
+ | Case 2 | Khoảng trống phía sau một khối code trong nội dung article | `FencedCodeBlock` | Ghép khối, không viết margin |
114
+ | Case 3 | Nhịp trục block quanh một đường kẻ ngang trong nội dung article | `MarkdownArticle` | Ghép article, không viết margin |
115
+
116
+ Không phải rule này: ghép nó với padding của cha cho cùng một mục đích mép tới nội dung là tạo hai
117
+ chủ cho một khoảng cách.
118
+
119
+ ## MARGIN-5 — `m-6` / `1.5rem`
120
+
121
+ Khoảng lệch lớn, làm một object đứng riêng tách hẳn khỏi khung chứa của nó.
122
+
123
+ | Case | Dùng khi | Owner | Render |
124
+ | --- | --- | --- | --- |
125
+ | Case 1 | Một ngoại lệ có tên cần rời khỏi ranh giới xa hơn mức lệch chuẩn | `App` | `<aside className="m-6">` |
126
+ | Case 2 | Khoảng tách bên dưới header của một workspace | `WorkspaceShell` | Ghép shell, không viết margin |
127
+
128
+ Không phải rule này: khoảng tách giữa các phần tử ngang hàng cỡ lớn. Dùng GAP-5 trên cha.
129
+
130
+ ## MARGIN-6 — `m-8` / `2rem`
131
+
132
+ Khoảng hở ngoài lớn nhất, cho một object cố ý tách rời.
133
+
134
+ | Case | Dùng khi | Owner | Render |
135
+ | --- | --- | --- | --- |
136
+ | Case 1 | Một object phải đọc lên là tách khỏi mọi thứ quanh nó, và có lý do nói được | `App` | `<aside className="m-8">` |
137
+
138
+ Không phải rule này: nhịp chung của trang, hoặc lặp lại trên nhiều phần tử ngang hàng. Dùng GAP-6
139
+ trên cha.
140
+
141
+ ## MARGIN-AUTO — `mx-auto`
142
+
143
+ Margin ngang tự động chia đều khoảng trống còn lại và canh giữa một container đã giới hạn chiều rộng.
144
+ Nó không mang giá trị nào trên thang và không phải một quyết định về khoảng lệch.
145
+
146
+ | Case | Dùng khi | Owner | Render |
147
+ | --- | --- | --- | --- |
148
+ | Case 1 | Một container do app sở hữu, tự giới hạn chiều rộng và phải nằm giữa | `App` | `<main className="mx-auto max-w-3xl">` |
149
+ | Case 2 | Một trang dùng khổ và inset đóng gói sẵn | `PageContainer` | Ghép container, nó đã canh giữa sẵn |
150
+
151
+ Không phải rule này: một phần tử rộng hết khung, hoặc dùng để rải đều khoảng cách giữa các phần tử.
152
+ Việc rải đều thuộc về layout của cha.
153
+
154
+ ## Biến thể theo trục
155
+
156
+ `mx-*` và `my-*` không phải rule riêng. Chúng áp một rule đã có lên một trục, khi chỉ một trục mang
157
+ ngoại lệ đó.
158
+
159
+ | Trục | Class | Nghĩa |
160
+ | --- | --- | --- |
161
+ | Inline | `mx-*` | Rule đã chọn chỉ áp cho cạnh đầu và cuối theo chiều ngang |
162
+ | Block | `my-*` | Rule đã chọn chỉ áp cho cạnh trên và dưới |
163
+
164
+ Trên cùng một phần tử, `m-*` và `mx-*` tranh nhau hai cạnh ngang chứ không cộng vào nhau. Margin
165
+ trục block của hai phần tử kề nhau còn bị gộp lại, và đó là lý do thứ hai để gap của cha mới là chủ
166
+ đáng tin của nhịp giữa các phần tử.
167
+
168
+ ## File này không quyết định
169
+
170
+ Khoảng cách giữa các phần tử ngang hàng thuộc về [Gap](gap.md). Khoảng cách từ ranh giới tới nội
171
+ dung thuộc về [Padding](padding.md). Giới hạn chiều rộng thuộc về [Measure](measure.md).
@@ -0,0 +1,174 @@
1
+ # Measure presentation
2
+
3
+ This file answers one question: how much room does an application-owned content region take?
4
+
5
+ Composition has already chosen the DOM tree and the Grammar objects. Measure resolves width and
6
+ height constraints on regions the application owns. The internal dimensions of a card, input, control,
7
+ or shell belong to Grammar.
8
+
9
+ ## Catalog
10
+
11
+ Height has no closed value scale, and width has one only for caps (see Width scale), so the rule
12
+ ID is an address over constraint kinds rather than a position on a ramp. Prefer the earliest rule that works: fluid before fitted, fitted
13
+ before capped, capped before fixed.
14
+
15
+ | Rule | Constraint | Decides |
16
+ | --- | --- | --- |
17
+ | MEASURE-1 | Page measure | Which packaged width a routed page adopts |
18
+ | MEASURE-2 | Fluid width | A region follows the width it is given |
19
+ | MEASURE-3 | Content width | A region grows only as far as its content |
20
+ | MEASURE-4 | Capped width | A fluid region stops widening past a readable bound |
21
+ | MEASURE-5 | Minimum height | A region reserves a floor and grows past it |
22
+ | MEASURE-6 | Inherited height | A region fills a height its host already defines |
23
+ | MEASURE-7 | Capped height | A region stops growing and hands scrolling to a boundary |
24
+
25
+ A fixed width or height is absent from this catalog on purpose. A region whose size cannot respond to
26
+ its content or its viewport is a layout decision made before presentation, and it is reported rather
27
+ than written here.
28
+
29
+ ## Owner
30
+
31
+ | Owner | Meaning | Application writes |
32
+ | --- | --- | --- |
33
+ | `App` | The region belongs to the application | The class |
34
+ | A component name | Common already constrains this dimension | Nothing. Pass the prop |
35
+ | `—` | Common exposes no public path | The class, recorded as a workaround |
36
+
37
+ Every region that can receive long content also carries `min-w-0`. Without it a flex or grid child
38
+ refuses to shrink below its content and pushes its neighbours out of the viewport. Common applies it
39
+ throughout its own renderers; an application region that wraps text must do the same.
40
+
41
+ ## Width scale
42
+
43
+ A capped width takes one step of this closed scale and nothing else; an arbitrary width such as
44
+ `max-w-[720px]` is outside the scale and is removed by `frontend.presentation.resolve`. The prose cap
45
+ `max-w-[65ch]` is the one character-based step, because line length follows the text. Owner ruling
46
+ 2026-09-03: the scale is fixed for every application, not derived per project.
47
+
48
+ | Step | Class | Width |
49
+ | --- | --- | --- |
50
+ | W-sm | `max-w-sm` | 24rem |
51
+ | W-md | `max-w-md` | 28rem |
52
+ | W-lg | `max-w-lg` | 32rem |
53
+ | W-xl | `max-w-xl` | 36rem |
54
+ | W-2xl | `max-w-2xl` | 42rem |
55
+ | W-3xl | `max-w-3xl` | 48rem |
56
+ | W-4xl | `max-w-4xl` | 56rem |
57
+ | W-5xl | `max-w-5xl` | 64rem |
58
+ | W-6xl | `max-w-6xl` | 72rem |
59
+ | W-7xl | `max-w-7xl` | 80rem |
60
+ | W-prose | `max-w-[65ch]` | 65 characters |
61
+
62
+ ## Measure Common already owns
63
+
64
+ Generated from `@grammar/core` claims by `scripts/generate-presentation-owned.mjs`; edit the component, not this table.
65
+
66
+ | Component | Element or condition | Rule |
67
+ | --- | --- | --- |
68
+ | `HorizontalScrollRegion` | root | MEASURE-3 |
69
+ | `NavigationFeatureNav` | root | MEASURE-2 |
70
+ | `PageContainer` | root | MEASURE-1 |
71
+ | `Progress` | root | MEASURE-2 |
72
+ | `Rail` | body, height="fill" | MEASURE-6 |
73
+ | `Sidebar` | root, presentation!="drawer" | MEASURE-6 |
74
+ | `Sidebar` | root, presentation="drawer" | MEASURE-2 |
75
+ | `TextAction` | root | MEASURE-3 |
76
+ | `VerticalScrollRegion` | root, isScrollable | MEASURE-7 |
77
+ | `WorkspaceShell` | layout | MEASURE-1 |
78
+
79
+ ## MEASURE-1 — Page measure
80
+
81
+ A routed page adopts one packaged width instead of inventing its own.
82
+
83
+ | Case | When | Owner | Render |
84
+ | --- | --- | --- | --- |
85
+ | Case 1 | A page of continuous prose that must stay readable | `PageContainer` | `<PageContainer measure="reading">` |
86
+ | Case 2 | An ordinary product page of cards, tables, and controls | `PageContainer` | `<PageContainer>`, the product default |
87
+ | Case 3 | A page whose content genuinely spans the viewport, such as a board or canvas | `PageContainer` | `<PageContainer measure="full">` |
88
+
89
+ Not this rule: recreating the page width with a cap and a centring margin. That reproduces a
90
+ component the page already has.
91
+
92
+ ## MEASURE-2 — Fluid width
93
+
94
+ The region takes the width it is given and stays responsive.
95
+
96
+ | Case | When | Owner | Render |
97
+ | --- | --- | --- | --- |
98
+ | Case 1 | A region that should follow the width supplied by its layout host | `App` | `<section className="w-full">` |
99
+ | Case 2 | A control or field that must span its column | `App` | `w-full` on the app-owned wrapper, never inside the control |
100
+
101
+ Not this rule: forcing a child past its parent's intended measure.
102
+
103
+ ## MEASURE-3 — Content width
104
+
105
+ The region grows only as far as its content needs.
106
+
107
+ | Case | When | Owner | Render |
108
+ | --- | --- | --- | --- |
109
+ | Case 1 | A compact region whose width should follow its own content | `App` | `<aside className="w-fit max-w-full">` |
110
+ | Case 2 | Row content inside a horizontal scroll region | `HorizontalScrollRegion` | Compose the region; children already take `max-content` |
111
+
112
+ Always pair `w-fit` with `max-w-full`. Without the cap, content longer than expected widens the
113
+ region past its container and creates page-level horizontal scrolling.
114
+
115
+ Not this rule: long prose, or a region that must fill its host.
116
+
117
+ ## MEASURE-4 — Capped width
118
+
119
+ A fluid region stops widening once further width stops helping the reader.
120
+
121
+ | Case | When | Owner | Render |
122
+ | --- | --- | --- | --- |
123
+ | Case 1 | A prose region whose line length needs a readable upper bound | `App` | `<article className="max-w-[65ch]">` |
124
+ | Case 2 | A content region that loses its grouping past a known width | `App` | `<main className="w-full max-w-6xl">`, the cap one step of the Width scale |
125
+ | Case 3 | A capped region whose content is narrower than the column it sits in, so the free space would otherwise gather on one side (a game table, a form, a media frame) | `App` | `<section className="w-full max-w-4xl mx-auto">`: the cap plus `mx-auto`, never a left-aligned cap |
126
+
127
+ Character-based caps follow the text itself and belong to prose. Length-based caps belong to mixed
128
+ content. Neither applies to tables, media, or code, which have their own intrinsic width.
129
+
130
+ Not this rule: adding a cap because a screenshot looks sparse.
131
+
132
+ ## MEASURE-5 — Minimum height
133
+
134
+ The region reserves a floor and still grows with its content.
135
+
136
+ | Case | When | Owner | Render |
137
+ | --- | --- | --- | --- |
138
+ | Case 1 | A region needing a stable canvas before its content height is known | `App` | `<section className="min-h-[24rem]">` |
139
+ | Case 2 | A region whose empty and populated states must not shift the page | `App` | The same floor on both states |
140
+
141
+ Not this rule: reserving space for content that is absent by design. An empty state occupies its own
142
+ region rather than a held-open gap.
143
+
144
+ ## MEASURE-6 — Inherited height
145
+
146
+ The region fills a height its host already defines.
147
+
148
+ | Case | When | Owner | Render |
149
+ | --- | --- | --- | --- |
150
+ | Case 1 | A region inside a host that supplies a definite height | `App` | `<section className="h-full">` inside a sized parent |
151
+ | Case 2 | A rail that must run the full height of its shell | `Rail` | `height="fill"` on the rail |
152
+
153
+ `h-full` resolves against a definite parent height and does nothing without one. In an indefinite
154
+ chain it silently has no effect, which reads as a styling bug rather than a missing height.
155
+
156
+ Not this rule: stretching ordinary document content.
157
+
158
+ ## MEASURE-7 — Capped height
159
+
160
+ The region stops growing, and something inside it scrolls.
161
+
162
+ | Case | When | Owner | Render |
163
+ | --- | --- | --- | --- |
164
+ | Case 1 | A list or panel that must not push the page beyond the viewport | `VerticalScrollRegion` | Compose the region; it owns the boundary |
165
+ | Case 2 | An app-owned region with a bounded height and its own scroll | `App` | `max-h-*` together with the matching overflow rule |
166
+
167
+ A capped height without a scroll owner clips content silently. The two decisions travel together.
168
+
169
+ Not this rule: capping a region to hide content the reader still needs.
170
+
171
+ ## What this file does not decide
172
+
173
+ Which boundary scrolls or clips is [Overflow](overflow.md). How text behaves inside the region is
174
+ [Text flow](text-flow.md). Space around and inside the region is [Gap](gap.md) and [Padding](padding.md).
@@ -0,0 +1,178 @@
1
+ # Measure presentation
2
+
3
+ File này trả lời đúng một câu hỏi: một vùng nội dung do ứng dụng sở hữu thì chiếm bao nhiêu chỗ.
4
+
5
+ Bước composition đã chọn xong cây DOM và các Grammar object. Measure giải quyết ràng buộc chiều rộng
6
+ và chiều cao trên những vùng ứng dụng sở hữu. Kích thước bên trong một card, input, control hay shell
7
+ đều thuộc về Grammar.
8
+
9
+ ## Danh mục
10
+
11
+ Chiều cao không có thang giá trị đóng, còn chiều rộng chỉ có thang cho trần (xem Thang chiều rộng),
12
+ nên số của rule ở đây là địa chỉ trên tập các kiểu ràng buộc chứ không phải vị trí trên một thang. Ưu tiên rule sớm nhất mà vẫn chạy được: co giãn
13
+ trước, vừa nội dung sau, rồi mới tới chặn trần, cuối cùng mới tới cố định.
14
+
15
+ | Rule | Ràng buộc | Quyết định |
16
+ | --- | --- | --- |
17
+ | MEASURE-1 | Khổ trang | Một trang được route lấy khổ đóng gói nào |
18
+ | MEASURE-2 | Rộng co giãn | Vùng đi theo chiều rộng nó được cấp |
19
+ | MEASURE-3 | Rộng theo nội dung | Vùng chỉ nở đúng bằng nội dung của nó |
20
+ | MEASURE-4 | Chặn trần chiều rộng | Vùng co giãn ngừng nở khi qua ngưỡng đọc được |
21
+ | MEASURE-5 | Chiều cao tối thiểu | Vùng giữ một mức sàn rồi vẫn cao thêm được |
22
+ | MEASURE-6 | Chiều cao kế thừa | Vùng lấp đầy một chiều cao mà host đã định |
23
+ | MEASURE-7 | Chặn trần chiều cao | Vùng ngừng cao và giao việc cuộn cho một ranh giới |
24
+
25
+ Chiều rộng hay chiều cao cố định cố ý không có trong danh mục. Một vùng không phản ứng được với nội
26
+ dung hay viewport là quyết định layout đã chốt trước bước presentation, và nó được báo cáo chứ không
27
+ được viết ở đây.
28
+
29
+ ## Owner
30
+
31
+ | Owner | Nghĩa | Ứng dụng viết |
32
+ | --- | --- | --- |
33
+ | `App` | Vùng thuộc về ứng dụng | Viết class |
34
+ | Tên component | Common đã ràng buộc kích thước này | Không viết gì, chỉ truyền prop |
35
+ | `—` | Common chưa có đường dùng công khai | Viết class, ghi nhận là workaround |
36
+
37
+ Mọi vùng có thể nhận nội dung dài đều phải mang thêm `min-w-0`. Thiếu nó, một phần tử con trong flex
38
+ hay grid từ chối co nhỏ hơn nội dung của nó và đẩy các phần tử kề ra khỏi viewport. Common áp nó
39
+ xuyên suốt các renderer của mình; một vùng của ứng dụng có bọc chữ thì phải làm y như vậy.
40
+
41
+ ## Thang chiều rộng
42
+
43
+ Một chiều rộng bị chặn trần lấy đúng một bậc của thang đóng này, không gì khác; chiều rộng tuỳ ý như
44
+ `max-w-[720px]` nằm ngoài thang và bị `frontend.presentation.resolve` gỡ bỏ. Trần cho văn xuôi `max-w-[65ch]`
45
+ là bậc duy nhất tính theo ký tự, vì độ dài dòng đi theo con chữ. Chốt của owner ngày 2026-09-03: thang
46
+ này cố định cho mọi ứng dụng, không suy ra theo từng dự án.
47
+
48
+ | Bậc | Class | Chiều rộng |
49
+ | --- | --- | --- |
50
+ | W-sm | `max-w-sm` | 24rem |
51
+ | W-md | `max-w-md` | 28rem |
52
+ | W-lg | `max-w-lg` | 32rem |
53
+ | W-xl | `max-w-xl` | 36rem |
54
+ | W-2xl | `max-w-2xl` | 42rem |
55
+ | W-3xl | `max-w-3xl` | 48rem |
56
+ | W-4xl | `max-w-4xl` | 56rem |
57
+ | W-5xl | `max-w-5xl` | 64rem |
58
+ | W-6xl | `max-w-6xl` | 72rem |
59
+ | W-7xl | `max-w-7xl` | 80rem |
60
+ | W-prose | `max-w-[65ch]` | 65 ký tự |
61
+
62
+ ## Measure mà Common đã sở hữu
63
+
64
+ Sinh từ claim của `@grammar/core` bằng `scripts/generate-presentation-owned.mjs`; muốn đổi thì sửa component, đừng sửa bảng này.
65
+
66
+ | Component | Phần tử hoặc điều kiện | Rule |
67
+ | --- | --- | --- |
68
+ | `HorizontalScrollRegion` | root | MEASURE-3 |
69
+ | `NavigationFeatureNav` | root | MEASURE-2 |
70
+ | `PageContainer` | root | MEASURE-1 |
71
+ | `Progress` | root | MEASURE-2 |
72
+ | `Rail` | body, height="fill" | MEASURE-6 |
73
+ | `Sidebar` | root, presentation!="drawer" | MEASURE-6 |
74
+ | `Sidebar` | root, presentation="drawer" | MEASURE-2 |
75
+ | `TextAction` | root | MEASURE-3 |
76
+ | `VerticalScrollRegion` | root, isScrollable | MEASURE-7 |
77
+ | `WorkspaceShell` | layout | MEASURE-1 |
78
+
79
+ ## MEASURE-1 — Khổ trang
80
+
81
+ Một trang được route lấy đúng một khổ đóng gói sẵn thay vì tự chế khổ riêng.
82
+
83
+ | Case | Dùng khi | Owner | Render |
84
+ | --- | --- | --- | --- |
85
+ | Case 1 | Trang toàn văn xuôi liên tục, phải giữ cho đọc được | `PageContainer` | `<PageContainer measure="reading">` |
86
+ | Case 2 | Trang sản phẩm thường gồm card, bảng và control | `PageContainer` | `<PageContainer>`, mặc định product |
87
+ | Case 3 | Trang mà nội dung thật sự trải hết viewport, kiểu bảng kéo thả hay canvas | `PageContainer` | `<PageContainer measure="full">` |
88
+
89
+ Không phải rule này: dựng lại khổ trang bằng một cái chặn trần cộng margin canh giữa. Như vậy là chế
90
+ lại một component mà trang đã có sẵn.
91
+
92
+ ## MEASURE-2 — Rộng co giãn
93
+
94
+ Vùng lấy đúng chiều rộng nó được cấp và giữ tính responsive.
95
+
96
+ | Case | Dùng khi | Owner | Render |
97
+ | --- | --- | --- | --- |
98
+ | Case 1 | Một vùng cần đi theo chiều rộng do layout host cấp | `App` | `<section className="w-full">` |
99
+ | Case 2 | Một control hoặc field phải trải hết cột của nó | `App` | `w-full` trên wrapper do app sở hữu, không bao giờ viết bên trong control |
100
+
101
+ Không phải rule này: ép một phần tử con vượt quá khổ mà cha dự định.
102
+
103
+ ## MEASURE-3 — Rộng theo nội dung
104
+
105
+ Vùng chỉ nở đúng bằng phần nội dung của nó cần.
106
+
107
+ | Case | Dùng khi | Owner | Render |
108
+ | --- | --- | --- | --- |
109
+ | Case 1 | Một vùng gọn mà chiều rộng nên đi theo chính nội dung của nó | `App` | `<aside className="w-fit max-w-full">` |
110
+ | Case 2 | Nội dung hàng bên trong một vùng cuộn ngang | `HorizontalScrollRegion` | Ghép region, các con đã tự lấy `max-content` |
111
+
112
+ Luôn đi kèm `w-fit` với `max-w-full`. Không có cái chặn đó, nội dung dài hơn dự tính sẽ nong vùng
113
+ vượt khỏi container và đẻ ra thanh cuộn ngang ở cấp trang.
114
+
115
+ Không phải rule này: văn xuôi dài, hoặc một vùng phải lấp đầy host của nó.
116
+
117
+ ## MEASURE-4 — Chặn trần chiều rộng
118
+
119
+ Vùng co giãn ngừng nở khi nở thêm không còn giúp người đọc.
120
+
121
+ | Case | Dùng khi | Owner | Render |
122
+ | --- | --- | --- | --- |
123
+ | Case 1 | Vùng văn xuôi mà độ dài dòng cần một ngưỡng trên để còn đọc được | `App` | `<article className="max-w-[65ch]">` |
124
+ | Case 2 | Vùng nội dung mất tính gom nhóm khi vượt một chiều rộng đã biết | `App` | `<main className="w-full max-w-6xl">`, trần là một bậc của Thang chiều rộng |
125
+ | Case 3 | Vùng bị chặn trần mà nội dung hẹp hơn cột chứa nó, khoảng trống sẽ dồn về một bên nếu để nguyên (sân bida, một form, một khung media) | `App` | `<section className="w-full max-w-4xl mx-auto">`: trần cộng `mx-auto`, không bao giờ chặn trần mà canh trái |
126
+
127
+ Chặn theo số ký tự thì đi theo chính con chữ và thuộc về văn xuôi. Chặn theo độ dài thì thuộc về nội
128
+ dung hỗn hợp. Cả hai đều không áp cho bảng, media hay code, vì những thứ đó có chiều rộng nội tại
129
+ riêng.
130
+
131
+ Không phải rule này: thêm chặn trần chỉ vì ảnh chụp nhìn trống.
132
+
133
+ ## MEASURE-5 — Chiều cao tối thiểu
134
+
135
+ Vùng giữ một mức sàn mà vẫn cao thêm được theo nội dung.
136
+
137
+ | Case | Dùng khi | Owner | Render |
138
+ | --- | --- | --- | --- |
139
+ | Case 1 | Một vùng cần khung ổn định trước khi biết chiều cao nội dung | `App` | `<section className="min-h-[24rem]">` |
140
+ | Case 2 | Một vùng mà trạng thái rỗng và trạng thái có dữ liệu không được làm nhảy trang | `App` | Cùng một mức sàn cho cả hai trạng thái |
141
+
142
+ Không phải rule này: chừa chỗ cho nội dung vốn dĩ không tồn tại. Trạng thái rỗng chiếm vùng của chính
143
+ nó chứ không phải một khoảng trống giữ sẵn.
144
+
145
+ ## MEASURE-6 — Chiều cao kế thừa
146
+
147
+ Vùng lấp đầy một chiều cao mà host đã định sẵn.
148
+
149
+ | Case | Dùng khi | Owner | Render |
150
+ | --- | --- | --- | --- |
151
+ | Case 1 | Một vùng nằm trong host đã cấp chiều cao xác định | `App` | `<section className="h-full">` trong một cha đã có kích thước |
152
+ | Case 2 | Một rail phải chạy hết chiều cao shell của nó | `Rail` | `height="fill"` trên rail |
153
+
154
+ `h-full` quy chiếu theo chiều cao xác định của cha và không làm gì nếu cha không có. Trong một chuỗi
155
+ không xác định, nó im lặng không có tác dụng, và điều đó đọc lên như lỗi style chứ không phải như
156
+ thiếu chiều cao.
157
+
158
+ Không phải rule này: kéo giãn nội dung tài liệu thông thường.
159
+
160
+ ## MEASURE-7 — Chặn trần chiều cao
161
+
162
+ Vùng ngừng cao thêm, và một thứ gì đó bên trong nó cuộn.
163
+
164
+ | Case | Dùng khi | Owner | Render |
165
+ | --- | --- | --- | --- |
166
+ | Case 1 | Một danh sách hoặc panel không được đẩy trang vượt quá viewport | `VerticalScrollRegion` | Ghép region, nó sở hữu ranh giới đó |
167
+ | Case 2 | Một vùng do app sở hữu, có chiều cao giới hạn và có cuộn riêng | `App` | `max-h-*` đi cùng rule overflow tương ứng |
168
+
169
+ Chặn trần chiều cao mà không có chủ cuộn thì cắt cụt nội dung trong im lặng. Hai quyết định đó đi
170
+ liền nhau.
171
+
172
+ Không phải rule này: chặn một vùng để giấu nội dung mà người đọc vẫn cần.
173
+
174
+ ## File này không quyết định
175
+
176
+ Ranh giới nào cuộn hay cắt thuộc về [Overflow](overflow.md). Chữ hành xử ra sao bên trong vùng thuộc
177
+ về [Text flow](text-flow.md). Khoảng cách quanh và bên trong vùng thuộc về [Gap](gap.md) và
178
+ [Padding](padding.md).
@@ -0,0 +1,142 @@
1
+ # Overflow presentation
2
+
3
+ This file answers one question: when content exceeds its region, which boundary owns that, and what
4
+ does it do?
5
+
6
+ Composition has chosen the tree and [Measure](measure.md) has bounded the region. Overflow resolves
7
+ what happens at the edge of a boundary the application owns. Clipping and scrolling inside a card,
8
+ rail, table frame, or shell belong to Grammar.
9
+
10
+ ## Catalog
11
+
12
+ | Rule | Boundary behaviour | Content beyond the edge |
13
+ | --- | --- | --- |
14
+ | OVERFLOW-1 | Visible | Escapes the boundary and remains readable |
15
+ | OVERFLOW-2 | Clipped | Is cut and unreachable |
16
+ | OVERFLOW-3 | Scrolls on one axis | Is reachable by scrolling that axis |
17
+ | OVERFLOW-4 | Scrolls when needed | Is reachable only when it exists |
18
+ | OVERFLOW-5 | Contained | Scrolls without handing the gesture to the page |
19
+
20
+ Exactly one boundary owns each axis. Two nested scrollers on the same axis trap the reader between
21
+ them, and neither reaches the end reliably.
22
+
23
+ ## Owner
24
+
25
+ | Owner | Meaning | Application writes |
26
+ | --- | --- | --- |
27
+ | `App` | The boundary belongs to the application | The class |
28
+ | A component name | Common already owns this boundary | Nothing. Compose it |
29
+ | `—` | Common exposes no public path | The class, recorded as a workaround |
30
+
31
+ A scroll boundary is never written alone. It travels with a bound from [Measure](measure.md), because
32
+ a region with no height cap never overflows and its scroll class does nothing.
33
+
34
+ ## Overflow Common already owns
35
+
36
+ Generated from `@grammar/core` claims by `scripts/generate-presentation-owned.mjs`; edit the component, not this table.
37
+
38
+ | Component | Element or condition | Rule |
39
+ | --- | --- | --- |
40
+ | `ChatWorkspace` | conversation | OVERFLOW-4 |
41
+ | `ChatWorkspace` | conversation | OVERFLOW-5 |
42
+ | `ChatWorkspace` | drawer body, hasRail, isCompactRail | OVERFLOW-2 |
43
+ | `ChatWorkspace` | overlay rail, hasRail, isCompactRail | OVERFLOW-4 |
44
+ | `ChatWorkspace` | overlay rail, hasRail, isCompactRail | OVERFLOW-5 |
45
+ | `ChatWorkspace` | overlay rail, hasRail, not isCompactRail | OVERFLOW-4 |
46
+ | `ChatWorkspace` | overlay rail, hasRail, not isCompactRail | OVERFLOW-5 |
47
+ | `FencedCodeBlock` | root | OVERFLOW-4 |
48
+ | `HorizontalScrollRegion` | root | OVERFLOW-3 |
49
+ | `HorizontalScrollRegion` | root | OVERFLOW-5 |
50
+ | `IconTile` | root | OVERFLOW-2 |
51
+ | `MarkdownTableFrame` | root | OVERFLOW-4 |
52
+ | `MediaFrame` | root | OVERFLOW-2 |
53
+ | `OtpInput` | root | OVERFLOW-3 |
54
+ | `OtpInput` | root | OVERFLOW-5 |
55
+ | `Rail` | body, height!="fill" | OVERFLOW-3 |
56
+ | `Sidebar` | root | OVERFLOW-2 |
57
+ | `SurfaceAccordionCard` | accordion shell | OVERFLOW-2 |
58
+ | `SurfaceAccordionCard` | accordion shell, not bounded | OVERFLOW-1 |
59
+ | `SurfaceCard` | card content | OVERFLOW-2 |
60
+ | `SurfaceCard` | card content, frame="frameless" | OVERFLOW-1 |
61
+ | `SurfaceListCard` | root | OVERFLOW-2 |
62
+ | `Tabs` | scroll | OVERFLOW-4 |
63
+ | `VerticalScrollRegion` | root, isScrollable | OVERFLOW-3 |
64
+ | `WorkspaceShell` | floating layer, hasFloatingLayer | OVERFLOW-4 |
65
+
66
+ ## OVERFLOW-1 — Visible
67
+
68
+ The boundary does not clip, because something must be allowed to cross it.
69
+
70
+ | Case | When | Owner | Render |
71
+ | --- | --- | --- | --- |
72
+ | Case 1 | A region whose child carries a focus ring, shadow, or badge that sits outside the box | `App` | No class. Visible is the default |
73
+ | Case 2 | A surface that must not clip its own highlight | `SurfaceCard` | The frameless variant already stays visible |
74
+
75
+ Not this rule: leaving a bounded region visible to avoid deciding. Content that escapes silently
76
+ overlaps whatever follows it.
77
+
78
+ ## OVERFLOW-2 — Clipped
79
+
80
+ Content is cut at the boundary and cannot be reached.
81
+
82
+ | Case | When | Owner | Render |
83
+ | --- | --- | --- | --- |
84
+ | Case 1 | A rounded region whose children must stay inside the radius | `SurfaceCard` | Compose the card; it already clips |
85
+ | Case 2 | A media viewport that crops its image to a fixed frame | `MediaFrame` | Compose the frame; it already clips |
86
+ | Case 3 | An app-owned decorative region whose overflow carries no information | `App` | `overflow-hidden` |
87
+
88
+ Clipping content the reader needs is silent data loss. It looks correct in a screenshot at one width
89
+ and fails at another, which is why it is the hardest overflow defect to find.
90
+
91
+ Not this rule: text that does not fit. That is [Text flow](text-flow.md), and it truncates visibly
92
+ rather than disappearing.
93
+
94
+ ## OVERFLOW-3 — Scrolls on one axis
95
+
96
+ The boundary always scrolls one axis, because its content is expected to exceed it.
97
+
98
+ | Case | When | Owner | Render |
99
+ | --- | --- | --- | --- |
100
+ | Case 1 | A row of items intentionally wider than the viewport | `HorizontalScrollRegion` | Compose the region |
101
+ | Case 2 | A bounded panel or list whose content grows | `VerticalScrollRegion` | Compose the region |
102
+ | Case 3 | A rail body that scrolls while its shell stays put | `Rail` | Compose the rail |
103
+
104
+ The other axis stays clipped or visible on purpose. A region that scrolls both axes hides content in
105
+ a direction the reader has no reason to look.
106
+
107
+ Not this rule: a region whose content usually fits. Use OVERFLOW-4 so the bar appears only when it
108
+ means something.
109
+
110
+ ## OVERFLOW-4 — Scrolls when needed
111
+
112
+ The boundary scrolls only when content actually exceeds it.
113
+
114
+ | Case | When | Owner | Render |
115
+ | --- | --- | --- | --- |
116
+ | Case 1 | A wide table inside a narrower column | `MarkdownTableFrame` | Compose the frame |
117
+ | Case 2 | Long code lines that must not wrap | `FencedCodeBlock` | Compose the block |
118
+ | Case 3 | A tab strip that exceeds its width only in some languages | `Tabs` | Compose the tabs |
119
+ | Case 4 | An app-owned bounded region whose content sometimes exceeds it | `App` | `overflow-auto` with the matching height cap |
120
+
121
+ Not this rule: an always-visible bar on a region that usually fits, which reads as a defect the first
122
+ time a reader sees it empty.
123
+
124
+ ## OVERFLOW-5 — Contained
125
+
126
+ Scrolling stops at this boundary instead of continuing into the page behind it.
127
+
128
+ | Case | When | Owner | Render |
129
+ | --- | --- | --- | --- |
130
+ | Case 1 | A scrolling panel, drawer, or overlay above page content | `—` | `overscroll-contain` with the scroll rule |
131
+ | Case 2 | A horizontal row inside a vertically scrolling page | `HorizontalScrollRegion` | Compose the region; it already contains the inline axis |
132
+
133
+ Without containment, reaching the end of the inner region hands the gesture to the page and the
134
+ reader loses their place. On a touch device the effect is worse, because the page moves under a
135
+ finger that was scrolling something else.
136
+
137
+ Not this rule: containment on the page's own scroller, which would trap the reader.
138
+
139
+ ## What this file does not decide
140
+
141
+ How large the region is, and whether it has a height cap at all, is [Measure](measure.md). What text
142
+ does when it does not fit is [Text flow](text-flow.md).