@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.
- package/INDEX.md +74 -0
- package/INDEX.vi.md +75 -0
- package/README.md +44 -0
- package/README.vi.md +43 -0
- package/SKILL.md +135 -0
- package/SKILL.vi.md +128 -0
- package/alias/INDEX.md +104 -0
- package/alias/INDEX.vi.md +104 -0
- package/alias/alias.json +297 -0
- package/bin/starci-skills.mjs +219 -0
- package/knowledge/INDEX.md +22 -0
- package/knowledge/INDEX.vi.md +22 -0
- package/knowledge/grammars/starci/DNA.md +146 -0
- package/knowledge/grammars/starci/DNA.vi.md +146 -0
- package/knowledge/grammars/starci/INDEX.md +25 -0
- package/knowledge/grammars/starci/INDEX.vi.md +25 -0
- package/knowledge/grammars/starci/family.md +50 -0
- package/knowledge/grammars/starci/family.vi.md +50 -0
- package/knowledge/grammars/starci/idioms.md +120 -0
- package/knowledge/grammars/starci/idioms.vi.md +121 -0
- package/knowledge/grammars/starci/playbook.md +36 -0
- package/knowledge/grammars/starci/playbook.vi.md +35 -0
- package/knowledge/patterns/be/INDEX.md +29 -0
- package/knowledge/patterns/be/INDEX.vi.md +29 -0
- package/knowledge/patterns/be/comment.md +80 -0
- package/knowledge/patterns/be/comment.vi.md +80 -0
- package/knowledge/patterns/be/error.md +86 -0
- package/knowledge/patterns/be/error.vi.md +86 -0
- package/knowledge/patterns/be/folder.md +87 -0
- package/knowledge/patterns/be/folder.vi.md +86 -0
- package/knowledge/patterns/be/function.md +80 -0
- package/knowledge/patterns/be/function.vi.md +80 -0
- package/knowledge/patterns/be/imports.md +79 -0
- package/knowledge/patterns/be/imports.vi.md +79 -0
- package/knowledge/patterns/be/naming.md +87 -0
- package/knowledge/patterns/be/naming.vi.md +87 -0
- package/knowledge/patterns/be/test.md +79 -0
- package/knowledge/patterns/be/test.vi.md +79 -0
- package/knowledge/patterns/be/typing.md +73 -0
- package/knowledge/patterns/be/typing.vi.md +73 -0
- package/knowledge/patterns/fe/INDEX.md +29 -0
- package/knowledge/patterns/fe/INDEX.vi.md +29 -0
- package/knowledge/patterns/fe/comment.md +70 -0
- package/knowledge/patterns/fe/comment.vi.md +70 -0
- package/knowledge/patterns/fe/error.md +61 -0
- package/knowledge/patterns/fe/error.vi.md +61 -0
- package/knowledge/patterns/fe/folder.md +98 -0
- package/knowledge/patterns/fe/folder.vi.md +95 -0
- package/knowledge/patterns/fe/function.md +70 -0
- package/knowledge/patterns/fe/function.vi.md +70 -0
- package/knowledge/patterns/fe/imports.md +87 -0
- package/knowledge/patterns/fe/imports.vi.md +87 -0
- package/knowledge/patterns/fe/naming.md +77 -0
- package/knowledge/patterns/fe/naming.vi.md +77 -0
- package/knowledge/patterns/fe/test.md +73 -0
- package/knowledge/patterns/fe/test.vi.md +73 -0
- package/knowledge/patterns/fe/typing.md +67 -0
- package/knowledge/patterns/fe/typing.vi.md +67 -0
- package/knowledge/ui/INDEX.md +101 -0
- package/knowledge/ui/INDEX.vi.md +101 -0
- package/knowledge/ui/composition/INDEX.md +60 -0
- package/knowledge/ui/composition/INDEX.vi.md +63 -0
- package/knowledge/ui/composition/accent.md +73 -0
- package/knowledge/ui/composition/accent.vi.md +74 -0
- package/knowledge/ui/composition/action.md +55 -0
- package/knowledge/ui/composition/action.vi.md +56 -0
- package/knowledge/ui/composition/coverage.md +37 -0
- package/knowledge/ui/composition/coverage.vi.md +37 -0
- package/knowledge/ui/composition/cta.md +79 -0
- package/knowledge/ui/composition/cta.vi.md +79 -0
- package/knowledge/ui/composition/feedback.md +55 -0
- package/knowledge/ui/composition/feedback.vi.md +56 -0
- package/knowledge/ui/composition/hierarchy.md +83 -0
- package/knowledge/ui/composition/hierarchy.vi.md +82 -0
- package/knowledge/ui/composition/layout.md +91 -0
- package/knowledge/ui/composition/layout.vi.md +93 -0
- package/knowledge/ui/composition/responsive.md +67 -0
- package/knowledge/ui/composition/responsive.vi.md +67 -0
- package/knowledge/ui/composition/state.md +105 -0
- package/knowledge/ui/composition/state.vi.md +106 -0
- package/knowledge/ui/presentation/INDEX.md +94 -0
- package/knowledge/ui/presentation/INDEX.vi.md +69 -0
- package/knowledge/ui/presentation/boundary.md +170 -0
- package/knowledge/ui/presentation/boundary.vi.md +169 -0
- package/knowledge/ui/presentation/font.md +155 -0
- package/knowledge/ui/presentation/font.vi.md +156 -0
- package/knowledge/ui/presentation/gap.md +181 -0
- package/knowledge/ui/presentation/gap.vi.md +181 -0
- package/knowledge/ui/presentation/margin.md +168 -0
- package/knowledge/ui/presentation/margin.vi.md +171 -0
- package/knowledge/ui/presentation/measure.md +174 -0
- package/knowledge/ui/presentation/measure.vi.md +178 -0
- package/knowledge/ui/presentation/overflow.md +142 -0
- package/knowledge/ui/presentation/overflow.vi.md +142 -0
- package/knowledge/ui/presentation/padding.md +293 -0
- package/knowledge/ui/presentation/padding.vi.md +292 -0
- package/knowledge/ui/presentation/surface.md +166 -0
- package/knowledge/ui/presentation/surface.vi.md +166 -0
- package/knowledge/ui/presentation/text-flow.md +123 -0
- package/knowledge/ui/presentation/text-flow.vi.md +123 -0
- package/knowledge/ui/presentation/tone.md +114 -0
- package/knowledge/ui/presentation/tone.vi.md +113 -0
- package/knowledge/ui/proof/INDEX.md +55 -0
- package/knowledge/ui/proof/INDEX.vi.md +55 -0
- package/knowledge/ui/proof/accessibility.md +67 -0
- package/knowledge/ui/proof/accessibility.vi.md +68 -0
- package/knowledge/ui/proof/contrast.md +58 -0
- package/knowledge/ui/proof/contrast.vi.md +57 -0
- package/knowledge/ui/proof/focus.md +76 -0
- package/knowledge/ui/proof/focus.vi.md +76 -0
- package/knowledge/ui/proof/motion.md +63 -0
- package/knowledge/ui/proof/motion.vi.md +64 -0
- package/knowledge/ui/proof/render-truth.md +63 -0
- package/knowledge/ui/proof/render-truth.vi.md +63 -0
- package/operators/INDEX.md +199 -0
- package/operators/INDEX.vi.md +199 -0
- package/operators/architecture-decide/errors.json +115 -0
- package/operators/architecture-decide/operator.json +20 -0
- package/operators/architecture-decide/operator.md +133 -0
- package/operators/architecture-decide/operator.vi.md +130 -0
- package/operators/architecture-decide/self-test.mjs +221 -0
- package/operators/architecture-decide/validate.mjs +112 -0
- package/operators/backend-source-apply/errors.json +66 -0
- package/operators/backend-source-apply/operator.json +20 -0
- package/operators/backend-source-apply/operator.md +189 -0
- package/operators/backend-source-apply/operator.vi.md +185 -0
- package/operators/backend-source-apply/self-test.mjs +257 -0
- package/operators/backend-source-apply/validate.mjs +240 -0
- package/operators/business-decide/errors.json +78 -0
- package/operators/business-decide/operator.json +20 -0
- package/operators/business-decide/operator.md +176 -0
- package/operators/business-decide/operator.vi.md +174 -0
- package/operators/business-decide/self-test.mjs +225 -0
- package/operators/business-decide/validate.mjs +277 -0
- package/operators/content-generate/errors.json +106 -0
- package/operators/content-generate/operator.json +21 -0
- package/operators/content-generate/operator.md +155 -0
- package/operators/content-generate/operator.vi.md +155 -0
- package/operators/content-generate/self-test.mjs +288 -0
- package/operators/content-generate/validate.mjs +196 -0
- package/operators/errors.json +178 -0
- package/operators/frontend-direction-decide/errors.json +135 -0
- package/operators/frontend-direction-decide/operator.json +21 -0
- package/operators/frontend-direction-decide/operator.md +167 -0
- package/operators/frontend-direction-decide/operator.vi.md +167 -0
- package/operators/frontend-direction-decide/self-test.mjs +226 -0
- package/operators/frontend-direction-decide/validate.mjs +146 -0
- package/operators/frontend-presentation-resolve/errors.json +42 -0
- package/operators/frontend-presentation-resolve/operator.json +19 -0
- package/operators/frontend-presentation-resolve/operator.md +142 -0
- package/operators/frontend-presentation-resolve/operator.vi.md +140 -0
- package/operators/frontend-presentation-resolve/self-test.mjs +163 -0
- package/operators/frontend-presentation-resolve/validate.mjs +143 -0
- package/operators/frontend-source-apply/errors.json +30 -0
- package/operators/frontend-source-apply/operator.json +20 -0
- package/operators/frontend-source-apply/operator.md +127 -0
- package/operators/frontend-source-apply/operator.vi.md +126 -0
- package/operators/frontend-source-apply/self-test.mjs +214 -0
- package/operators/frontend-source-apply/validate.mjs +133 -0
- package/operators/frontend-surface-audit/errors.json +5 -0
- package/operators/frontend-surface-audit/operator.json +22 -0
- package/operators/frontend-surface-audit/operator.md +121 -0
- package/operators/frontend-surface-audit/operator.vi.md +121 -0
- package/operators/frontend-surface-audit/self-test.mjs +185 -0
- package/operators/frontend-surface-audit/validate.mjs +127 -0
- package/operators/git-publish/errors.json +54 -0
- package/operators/git-publish/operator.json +20 -0
- package/operators/git-publish/operator.md +180 -0
- package/operators/git-publish/operator.vi.md +178 -0
- package/operators/git-publish/self-test.mjs +177 -0
- package/operators/git-publish/validate.mjs +106 -0
- package/operators/platform-operate/errors.json +90 -0
- package/operators/platform-operate/operator.json +22 -0
- package/operators/platform-operate/operator.md +162 -0
- package/operators/platform-operate/operator.vi.md +160 -0
- package/operators/platform-operate/self-test.mjs +202 -0
- package/operators/platform-operate/validate.mjs +193 -0
- package/operators/quality-verify/errors.json +54 -0
- package/operators/quality-verify/operator.json +20 -0
- package/operators/quality-verify/operator.md +185 -0
- package/operators/quality-verify/operator.vi.md +177 -0
- package/operators/quality-verify/self-test.mjs +210 -0
- package/operators/quality-verify/validate.mjs +197 -0
- package/operators/release-deploy/errors.json +158 -0
- package/operators/release-deploy/operator.json +23 -0
- package/operators/release-deploy/operator.md +183 -0
- package/operators/release-deploy/operator.vi.md +181 -0
- package/operators/release-deploy/self-test.mjs +235 -0
- package/operators/release-deploy/validate.mjs +129 -0
- package/operators/uat-verify/errors.json +78 -0
- package/operators/uat-verify/operator.json +25 -0
- package/operators/uat-verify/operator.md +162 -0
- package/operators/uat-verify/operator.vi.md +161 -0
- package/operators/uat-verify/self-test.mjs +270 -0
- package/operators/uat-verify/validate.mjs +202 -0
- package/operators/workspace-bind/errors.json +90 -0
- package/operators/workspace-bind/operator.json +21 -0
- package/operators/workspace-bind/operator.md +148 -0
- package/operators/workspace-bind/operator.vi.md +148 -0
- package/operators/workspace-bind/self-test.mjs +205 -0
- package/operators/workspace-bind/validate.mjs +152 -0
- package/package.json +50 -0
- package/readiness/initialization/workspaces/commit-policy.json +91 -0
- package/readiness/initialization/workspaces/config.schema.json +35 -0
- package/readiness/initialization/workspaces/device-state.schema.json +54 -0
- package/readiness/initialization/workspaces/local-route.schema.json +206 -0
- package/readiness/initialization/workspaces/portable-route.schema.json +200 -0
- package/resources/INDEX.md +96 -0
- package/resources/INDEX.vi.md +99 -0
- package/resources/agents/profiles/claude.json +131 -0
- package/resources/agents/profiles/openai.json +131 -0
- package/resources/orchestrator.json +71 -0
- package/resources/tools.json +85 -0
- package/routing.json +272 -0
- package/scripts/alias-registry.mjs +31 -0
- package/scripts/device-state.mjs +497 -0
- package/scripts/device-state.spec.mjs +18 -0
- package/scripts/errors-registry.mjs +68 -0
- package/scripts/generate-alias-doc.mjs +66 -0
- package/scripts/generate-grammar-dna.mjs +387 -0
- package/scripts/generate-operators-index.mjs +95 -0
- package/scripts/generate-presentation-owned.mjs +681 -0
- package/scripts/install-cli.spec.mjs +74 -0
- package/scripts/json-schema.mjs +94 -0
- package/scripts/operator-md.mjs +96 -0
- package/scripts/run-operator-self-tests.mjs +36 -0
- package/scripts/validate-alias.mjs +165 -0
- package/scripts/validate-defaults.mjs +72 -0
- package/scripts/validate-knowledge-citations.mjs +90 -0
- package/scripts/validate-operator.mjs +125 -0
- package/scripts/validate-request.mjs +80 -0
- package/scripts/validate-resources.mjs +117 -0
- package/scripts/validate-response.mjs +141 -0
- package/scripts/validate-routing.mjs +91 -0
- package/scripts/validate-step.mjs +50 -0
- package/scripts/validate-templates.mjs +226 -0
- package/scripts/validate-templates.spec.mjs +144 -0
- package/scripts/validate-workflows.mjs +106 -0
- package/scripts/workspace-portable.mjs +389 -0
- package/scripts/workspace-portable.spec.mjs +246 -0
- package/templates/README.md +47 -0
- package/templates/README.vi.md +45 -0
- package/templates/changes.example.md +27 -0
- package/templates/grammars.template.md +34 -0
- package/templates/kinds/architecture-decision.contract.json +14 -0
- package/templates/kinds/architecture-decision.skeleton.md +52 -0
- package/templates/kinds/backend-source-application.contract.json +10 -0
- package/templates/kinds/backend-source-application.skeleton.md +34 -0
- package/templates/kinds/business-promise-authority.contract.json +13 -0
- package/templates/kinds/business-promise-authority.skeleton.md +67 -0
- package/templates/kinds/capture.schema.json +33 -0
- package/templates/kinds/changes.contract.json +10 -0
- package/templates/kinds/changes.skeleton.md +26 -0
- package/templates/kinds/checks.schema.json +44 -0
- package/templates/kinds/claims.schema.json +165 -0
- package/templates/kinds/conformance.schema.json +15 -0
- package/templates/kinds/content-brief.contract.json +12 -0
- package/templates/kinds/content-brief.skeleton.md +45 -0
- package/templates/kinds/content-generation-receipt.contract.json +11 -0
- package/templates/kinds/content-generation-receipt.skeleton.md +40 -0
- package/templates/kinds/content-review.contract.json +11 -0
- package/templates/kinds/content-review.skeleton.md +45 -0
- package/templates/kinds/contract.schema.json +28 -0
- package/templates/kinds/coverage-matrix.schema.json +86 -0
- package/templates/kinds/coverage.schema.json +62 -0
- package/templates/kinds/current-state.schema.json +40 -0
- package/templates/kinds/delta.schema.json +95 -0
- package/templates/kinds/e2e.schema.json +63 -0
- package/templates/kinds/frontend-direction-decision.contract.json +93 -0
- package/templates/kinds/frontend-direction-decision.skeleton.md +68 -0
- package/templates/kinds/frontend-presentation-resolution.contract.json +11 -0
- package/templates/kinds/frontend-presentation-resolution.skeleton.md +32 -0
- package/templates/kinds/frontend-source-application.contract.json +10 -0
- package/templates/kinds/frontend-source-application.skeleton.md +30 -0
- package/templates/kinds/frontend-surface-audit.contract.json +52 -0
- package/templates/kinds/frontend-surface-audit.skeleton.md +32 -0
- package/templates/kinds/gate-result.schema.json +64 -0
- package/templates/kinds/git-publication.contract.json +82 -0
- package/templates/kinds/git-publication.skeleton.md +61 -0
- package/templates/kinds/independent-critique.contract.json +9 -0
- package/templates/kinds/independent-critique.skeleton.md +28 -0
- package/templates/kinds/inventory.schema.json +35 -0
- package/templates/kinds/model.schema.json +99 -0
- package/templates/kinds/mutations.schema.json +65 -0
- package/templates/kinds/platform-operation-receipt.contract.json +76 -0
- package/templates/kinds/platform-operation-receipt.skeleton.md +54 -0
- package/templates/kinds/probes.schema.json +130 -0
- package/templates/kinds/proof.schema.json +17 -0
- package/templates/kinds/quality-verification.contract.json +87 -0
- package/templates/kinds/quality-verification.skeleton.md +58 -0
- package/templates/kinds/release-deployment.contract.json +85 -0
- package/templates/kinds/release-deployment.skeleton.md +67 -0
- package/templates/kinds/route.schema.json +293 -0
- package/templates/kinds/stack-model.schema.json +90 -0
- package/templates/kinds/uat-capture.schema.json +35 -0
- package/templates/kinds/uat-flow-verification.contract.json +11 -0
- package/templates/kinds/uat-flow-verification.skeleton.md +47 -0
- package/templates/kinds/uat-snapshot.schema.json +96 -0
- package/templates/kinds/uat-verdicts.schema.json +41 -0
- package/templates/kinds/ui-coverage.schema.json +77 -0
- package/templates/kinds/verdicts.schema.json +39 -0
- package/templates/kinds/workspace-route-binding.contract.json +12 -0
- package/templates/kinds/workspace-route-binding.skeleton.md +60 -0
- package/templates/kinds/writes.schema.json +37 -0
- package/templates/operator.template.md +73 -0
- package/templates/patterns.template.md +31 -0
- package/templates/step/request.schema.json +42 -0
- package/templates/step/response.schema.json +144 -0
- package/templates/ui-composition.template.md +36 -0
- package/templates/ui-presentation.template.md +57 -0
- package/templates/ui-proof.template.md +34 -0
- package/workflows/README.md +37 -0
- package/workflows/README.vi.md +37 -0
- package/workflows/backend-feature.json +59 -0
- package/workflows/content-unit.json +19 -0
- package/workflows/frontend-new-surface.json +81 -0
- package/workflows/frontend-reconstruct.json +67 -0
- package/workflows/frontend-refine.json +67 -0
- package/workflows/frontend-with-uat.json +78 -0
- package/workflows/full-feature.json +104 -0
- 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).
|