@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,123 @@
|
|
|
1
|
+
# Text flow presentation
|
|
2
|
+
|
|
3
|
+
This file answers one question: how does text behave inside a region whose size is already decided?
|
|
4
|
+
|
|
5
|
+
Composition has chosen the tree, [Font](font.md) has set the rank, and [Measure](measure.md) has set
|
|
6
|
+
the room. Text flow resolves alignment, wrapping, and what happens when the words do not fit.
|
|
7
|
+
|
|
8
|
+
The default is the correct answer far more often than any rule here. Text that starts at the reading
|
|
9
|
+
edge and wraps naturally needs no class at all.
|
|
10
|
+
|
|
11
|
+
## Catalog
|
|
12
|
+
|
|
13
|
+
| Rule | Decides | Default |
|
|
14
|
+
| --- | --- | --- |
|
|
15
|
+
| FLOW-1 | Alignment along the inline axis | Start |
|
|
16
|
+
| FLOW-2 | Whether a line may break | Wrapping |
|
|
17
|
+
| FLOW-3 | Breaking inside an unbroken string | Allowed on overflow |
|
|
18
|
+
| FLOW-4 | Truncating one line | Off |
|
|
19
|
+
| FLOW-5 | Clamping several lines | Off |
|
|
20
|
+
|
|
21
|
+
Truncation removes information. FLOW-4 and FLOW-5 are valid only when the full text remains reachable
|
|
22
|
+
somewhere else, and never for a value the reader must act on.
|
|
23
|
+
|
|
24
|
+
## Owner
|
|
25
|
+
|
|
26
|
+
| Owner | Meaning | Application writes |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| `App` | The text region belongs to the application | The class |
|
|
29
|
+
| A component name | Common already resolves this behaviour | Nothing. Compose it |
|
|
30
|
+
| `—` | Common exposes no public path | The class, recorded as a workaround |
|
|
31
|
+
|
|
32
|
+
Every wrapping region also needs `min-w-0` from [Measure](measure.md). Truncation and clamping fail
|
|
33
|
+
silently without it, because the region never becomes narrower than its longest word.
|
|
34
|
+
|
|
35
|
+
## Text flow Common already owns
|
|
36
|
+
|
|
37
|
+
Generated from `@grammar/core` claims by `scripts/generate-presentation-owned.mjs`; edit the component, not this table.
|
|
38
|
+
|
|
39
|
+
| Component | Element or condition | Rule |
|
|
40
|
+
| --- | --- | --- |
|
|
41
|
+
| `MediaFrame` | caption, caption!=undefined | FLOW-3 |
|
|
42
|
+
| `SectionHeader` | title | FLOW-3 |
|
|
43
|
+
| `Sidebar` | item label, not collapsed | FLOW-4 |
|
|
44
|
+
| `Subnav` | title | FLOW-4 |
|
|
45
|
+
| `Tabs` | hero tabs list container wrapper | FLOW-2 |
|
|
46
|
+
| `Tooltip` | content | FLOW-2 |
|
|
47
|
+
|
|
48
|
+
## FLOW-1 — Alignment
|
|
49
|
+
|
|
50
|
+
Text starts at the reading edge unless the content itself is a quantity being compared.
|
|
51
|
+
|
|
52
|
+
| Case | When | Owner | Render |
|
|
53
|
+
| --- | --- | --- | --- |
|
|
54
|
+
| Case 1 | Any prose, label, heading, or explanation | `App` | No class. Start alignment is the default |
|
|
55
|
+
| Case 2 | A numeric column whose values are compared down the column | `App` | `text-end` on the cell, applied to the whole column |
|
|
56
|
+
| Case 3 | A single short line centred inside a deliberately symmetric region | `App` | `text-center` on the app-owned region only |
|
|
57
|
+
|
|
58
|
+
Not this rule: centring paragraphs. A centred block has a ragged start edge, and every line costs the
|
|
59
|
+
reader a search for where it begins. Justified text is never used, because it opens uneven rivers of
|
|
60
|
+
space at the widths this system supports.
|
|
61
|
+
|
|
62
|
+
## FLOW-2 — Wrapping
|
|
63
|
+
|
|
64
|
+
A line wraps by default. Preventing that is a promise the content is short.
|
|
65
|
+
|
|
66
|
+
| Case | When | Owner | Render |
|
|
67
|
+
| --- | --- | --- | --- |
|
|
68
|
+
| Case 1 | Any content whose length is not fixed | `App` | No class. Wrapping is the default |
|
|
69
|
+
| Case 2 | A control label, badge, or tab that must not break mid-phrase | The component | Compose it; Common already keeps it on one line |
|
|
70
|
+
| Case 3 | Code that must keep its own line breaks | `FencedCodeBlock` | Compose the block; it scrolls instead of wrapping |
|
|
71
|
+
|
|
72
|
+
Not this rule: `whitespace-nowrap` on translated or user-supplied text. A phrase that fits in one
|
|
73
|
+
language overflows in another, and the overflow appears only after release.
|
|
74
|
+
|
|
75
|
+
## FLOW-3 — Breaking inside a word
|
|
76
|
+
|
|
77
|
+
A single unbroken string longer than its region breaks rather than escaping it.
|
|
78
|
+
|
|
79
|
+
| Case | When | Owner | Render |
|
|
80
|
+
| --- | --- | --- | --- |
|
|
81
|
+
| Case 1 | Content that can contain a URL, token, identifier, or pasted string | `App` | `break-words` on the app-owned region |
|
|
82
|
+
| Case 2 | Section titles, captions, and article prose | The component | Compose it; Common already breaks these |
|
|
83
|
+
|
|
84
|
+
This is the rule that prevents page-level horizontal scrolling. One email address in a narrow column
|
|
85
|
+
widens every ancestor without it.
|
|
86
|
+
|
|
87
|
+
Not this rule: breaking short labels, which produces a single stranded character on the second line.
|
|
88
|
+
|
|
89
|
+
## FLOW-4 — Truncating one line
|
|
90
|
+
|
|
91
|
+
One line is cut with an ellipsis because its region has a fixed inline size and the full value is
|
|
92
|
+
available elsewhere.
|
|
93
|
+
|
|
94
|
+
| Case | When | Owner | Render |
|
|
95
|
+
| --- | --- | --- | --- |
|
|
96
|
+
| Case 1 | A title in a fixed-width strip whose full text is on the destination page | `Subnav` | Compose it; Common already truncates |
|
|
97
|
+
| Case 2 | An app-owned row label whose full value is reachable by opening the row | `App` | `truncate` with `min-w-0` on the same element |
|
|
98
|
+
|
|
99
|
+
The visible text must remain the accessible name in full. A truncated label that also truncates its
|
|
100
|
+
accessible name removes the value from assistive output entirely.
|
|
101
|
+
|
|
102
|
+
Not this rule: a price, status, error, deadline, or any value the reader acts on. Give the region
|
|
103
|
+
more room instead.
|
|
104
|
+
|
|
105
|
+
## FLOW-5 — Clamping several lines
|
|
106
|
+
|
|
107
|
+
A block is cut after a fixed number of lines, and the reader can open the full text.
|
|
108
|
+
|
|
109
|
+
| Case | When | Owner | Render |
|
|
110
|
+
| --- | --- | --- | --- |
|
|
111
|
+
| Case 1 | A card description in a grid whose cards must stay the same height | `—` | `line-clamp-2` with an affordance that reveals the rest |
|
|
112
|
+
| Case 2 | A preview whose full body is the destination of the row | `—` | Same, with the row as the affordance |
|
|
113
|
+
|
|
114
|
+
A clamp without a way to read the rest is content deletion. The affordance is part of the rule, not a
|
|
115
|
+
later addition. Common exposes no clamp prop, so both cases stay recorded workarounds.
|
|
116
|
+
|
|
117
|
+
Not this rule: clamping to hide a layout problem. If two cards differ in height because their content
|
|
118
|
+
differs, that is the content, not a defect.
|
|
119
|
+
|
|
120
|
+
## What this file does not decide
|
|
121
|
+
|
|
122
|
+
The size and weight of the text is [Font](font.md). Its colour is [Tone](tone.md). How much room the
|
|
123
|
+
region gets is [Measure](measure.md). Which boundary scrolls is [Overflow](overflow.md).
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Text flow presentation
|
|
2
|
+
|
|
3
|
+
File này trả lời đúng một câu hỏi: chữ hành xử ra sao bên trong một vùng đã chốt kích thước.
|
|
4
|
+
|
|
5
|
+
Composition đã chọn cây DOM, [Font](font.md) đã đặt hạng, và [Measure](measure.md) đã đặt chỗ. Text
|
|
6
|
+
flow giải quyết canh lề, xuống dòng, và chuyện gì xảy ra khi chữ không vừa.
|
|
7
|
+
|
|
8
|
+
Giá trị mặc định mới là đáp án đúng, thường xuyên hơn bất kỳ rule nào ở đây. Chữ bắt đầu từ mép đọc
|
|
9
|
+
và xuống dòng tự nhiên thì không cần class nào cả.
|
|
10
|
+
|
|
11
|
+
## Danh mục
|
|
12
|
+
|
|
13
|
+
| Rule | Quyết định | Mặc định |
|
|
14
|
+
| --- | --- | --- |
|
|
15
|
+
| FLOW-1 | Canh lề theo trục inline | Đầu dòng |
|
|
16
|
+
| FLOW-2 | Một dòng có được phép ngắt không | Có xuống dòng |
|
|
17
|
+
| FLOW-3 | Ngắt bên trong một chuỗi liền không khoảng trắng | Cho phép khi tràn |
|
|
18
|
+
| FLOW-4 | Cắt cụt một dòng | Tắt |
|
|
19
|
+
| FLOW-5 | Chặn số dòng | Tắt |
|
|
20
|
+
|
|
21
|
+
Cắt cụt là gỡ bỏ thông tin. FLOW-4 và FLOW-5 chỉ hợp lệ khi toàn văn còn đọc được ở chỗ khác, và
|
|
22
|
+
không bao giờ dùng cho một giá trị mà người đọc phải hành động theo.
|
|
23
|
+
|
|
24
|
+
## Owner
|
|
25
|
+
|
|
26
|
+
| Owner | Nghĩa | Ứng dụng viết |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| `App` | Vùng chữ thuộc về ứng dụng | Viết class |
|
|
29
|
+
| Tên component | Common đã xử lý hành vi này | Không viết gì, chỉ ghép component |
|
|
30
|
+
| `—` | Common chưa có đường dùng công khai | Viết class, ghi nhận là workaround |
|
|
31
|
+
|
|
32
|
+
Mọi vùng có xuống dòng đều cần thêm `min-w-0` từ [Measure](measure.md). Thiếu nó thì cắt cụt và chặn
|
|
33
|
+
dòng hỏng trong im lặng, vì vùng không bao giờ hẹp hơn từ dài nhất của nó.
|
|
34
|
+
|
|
35
|
+
## Text flow mà Common đã sở hữu
|
|
36
|
+
|
|
37
|
+
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.
|
|
38
|
+
|
|
39
|
+
| Component | Phần tử hoặc điều kiện | Rule |
|
|
40
|
+
| --- | --- | --- |
|
|
41
|
+
| `MediaFrame` | caption, caption!=undefined | FLOW-3 |
|
|
42
|
+
| `SectionHeader` | title | FLOW-3 |
|
|
43
|
+
| `Sidebar` | item label, not collapsed | FLOW-4 |
|
|
44
|
+
| `Subnav` | title | FLOW-4 |
|
|
45
|
+
| `Tabs` | hero tabs list container wrapper | FLOW-2 |
|
|
46
|
+
| `Tooltip` | content | FLOW-2 |
|
|
47
|
+
|
|
48
|
+
## FLOW-1 — Canh lề
|
|
49
|
+
|
|
50
|
+
Chữ bắt đầu từ mép đọc, trừ khi bản thân nội dung là một con số đang được đem so sánh.
|
|
51
|
+
|
|
52
|
+
| Case | Dùng khi | Owner | Render |
|
|
53
|
+
| --- | --- | --- | --- |
|
|
54
|
+
| Case 1 | Mọi văn xuôi, nhãn, tiêu đề hay lời giải thích | `App` | Không viết class. Canh đầu dòng là mặc định |
|
|
55
|
+
| Case 2 | Một cột số mà các giá trị được so sánh dọc theo cột | `App` | `text-end` trên ô, áp cho cả cột |
|
|
56
|
+
| Case 3 | Một dòng ngắn duy nhất canh giữa trong một vùng cố ý đối xứng | `App` | `text-center` chỉ trên vùng do app sở hữu |
|
|
57
|
+
|
|
58
|
+
Không phải rule này: canh giữa cả đoạn văn. Khối canh giữa có mép đầu răng cưa, và mỗi dòng bắt người
|
|
59
|
+
đọc phải đi tìm chỗ bắt đầu. Không bao giờ dùng canh đều hai bên, vì ở những khổ mà hệ này hỗ trợ nó
|
|
60
|
+
mở ra các dòng sông khoảng trắng lệch nhau.
|
|
61
|
+
|
|
62
|
+
## FLOW-2 — Xuống dòng
|
|
63
|
+
|
|
64
|
+
Một dòng mặc định là có xuống dòng. Chặn nó lại là một lời hứa rằng nội dung ngắn.
|
|
65
|
+
|
|
66
|
+
| Case | Dùng khi | Owner | Render |
|
|
67
|
+
| --- | --- | --- | --- |
|
|
68
|
+
| Case 1 | Mọi nội dung mà độ dài không cố định | `App` | Không viết class. Xuống dòng là mặc định |
|
|
69
|
+
| Case 2 | Nhãn control, badge hay tab không được ngắt giữa cụm từ | Chính component đó | Ghép nó, Common đã giữ trên một dòng |
|
|
70
|
+
| Case 3 | Code phải giữ đúng các dấu xuống dòng của chính nó | `FencedCodeBlock` | Ghép khối, nó cuộn thay vì xuống dòng |
|
|
71
|
+
|
|
72
|
+
Không phải rule này: `whitespace-nowrap` trên chữ đã dịch hoặc chữ do người dùng nhập. Một cụm vừa
|
|
73
|
+
khít ở ngôn ngữ này sẽ tràn ở ngôn ngữ khác, và cái tràn đó chỉ lộ ra sau khi phát hành.
|
|
74
|
+
|
|
75
|
+
## FLOW-3 — Ngắt bên trong một từ
|
|
76
|
+
|
|
77
|
+
Một chuỗi liền không khoảng trắng, dài hơn vùng chứa, thì ngắt ra chứ không thoát ra ngoài.
|
|
78
|
+
|
|
79
|
+
| Case | Dùng khi | Owner | Render |
|
|
80
|
+
| --- | --- | --- | --- |
|
|
81
|
+
| Case 1 | Nội dung có thể chứa URL, token, mã định danh hay chuỗi dán vào | `App` | `break-words` trên vùng do app sở hữu |
|
|
82
|
+
| Case 2 | Tiêu đề section, chú thích ảnh và văn xuôi article | Chính component đó | Ghép nó, Common đã ngắt sẵn |
|
|
83
|
+
|
|
84
|
+
Đây là rule chặn thanh cuộn ngang ở cấp trang. Chỉ một địa chỉ email trong một cột hẹp là nong rộng
|
|
85
|
+
mọi phần tử tổ tiên nếu thiếu nó.
|
|
86
|
+
|
|
87
|
+
Không phải rule này: ngắt các nhãn ngắn, vì như vậy đẻ ra một ký tự lạc lõng ở dòng thứ hai.
|
|
88
|
+
|
|
89
|
+
## FLOW-4 — Cắt cụt một dòng
|
|
90
|
+
|
|
91
|
+
Một dòng bị cắt kèm dấu ba chấm vì vùng của nó có chiều rộng cố định và giá trị đầy đủ có ở chỗ khác.
|
|
92
|
+
|
|
93
|
+
| Case | Dùng khi | Owner | Render |
|
|
94
|
+
| --- | --- | --- | --- |
|
|
95
|
+
| Case 1 | Tiêu đề trong một dải rộng cố định, toàn văn nằm ở trang đích | `Subnav` | Ghép nó, Common đã cắt cụt sẵn |
|
|
96
|
+
| Case 2 | Nhãn một hàng do app sở hữu, giá trị đầy đủ mở ra được bằng cách mở hàng đó | `App` | `truncate` cùng `min-w-0` trên chính phần tử đó |
|
|
97
|
+
|
|
98
|
+
Chữ nhìn thấy vẫn phải giữ nguyên accessible name đầy đủ. Một nhãn cắt cụt mà cắt luôn accessible
|
|
99
|
+
name là xóa hẳn giá trị đó khỏi đầu ra cho trình đọc màn hình.
|
|
100
|
+
|
|
101
|
+
Không phải rule này: giá tiền, trạng thái, lỗi, hạn chót, hay bất kỳ giá trị nào người đọc phải hành
|
|
102
|
+
động theo. Cho vùng đó thêm chỗ thay vì cắt.
|
|
103
|
+
|
|
104
|
+
## FLOW-5 — Chặn số dòng
|
|
105
|
+
|
|
106
|
+
Một khối bị cắt sau một số dòng cố định, và người đọc mở ra xem toàn văn được.
|
|
107
|
+
|
|
108
|
+
| Case | Dùng khi | Owner | Render |
|
|
109
|
+
| --- | --- | --- | --- |
|
|
110
|
+
| Case 1 | Mô tả của card trong một lưới mà các card phải bằng chiều cao | `—` | `line-clamp-2` kèm một cách để mở phần còn lại |
|
|
111
|
+
| Case 2 | Một đoạn xem trước mà toàn văn chính là đích đến của hàng đó | `—` | Cũng vậy, chính hàng đó là cách mở |
|
|
112
|
+
|
|
113
|
+
Chặn dòng mà không có đường đọc tiếp là xóa nội dung. Cái đường mở đó là một phần của rule, không
|
|
114
|
+
phải thứ thêm vào sau. Common chưa có prop chặn dòng nào, nên cả hai case đều là workaround có ghi
|
|
115
|
+
nhận.
|
|
116
|
+
|
|
117
|
+
Không phải rule này: chặn dòng để giấu một lỗi layout. Nếu hai card lệch chiều cao vì nội dung khác
|
|
118
|
+
nhau, thì đó là nội dung, không phải lỗi.
|
|
119
|
+
|
|
120
|
+
## File này không quyết định
|
|
121
|
+
|
|
122
|
+
Cỡ chữ và độ đậm thuộc về [Font](font.md). Màu chữ thuộc về [Tone](tone.md). Vùng được bao nhiêu chỗ
|
|
123
|
+
thuộc về [Measure](measure.md). Ranh giới nào cuộn thuộc về [Overflow](overflow.md).
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Tone presentation
|
|
2
|
+
|
|
3
|
+
This file answers one question: given a line of copy whose rank is already decided, which public tone
|
|
4
|
+
prop expresses that rank?
|
|
5
|
+
|
|
6
|
+
Tone is a semantic choice, not a colour choice. The application selects how much attention a line
|
|
7
|
+
deserves; Grammar resolves that to a token. The application never writes a text colour class and
|
|
8
|
+
never overrides colour inside another Grammar component.
|
|
9
|
+
|
|
10
|
+
## Scale
|
|
11
|
+
|
|
12
|
+
The public tone set is closed and ordered by how much attention each level claims.
|
|
13
|
+
|
|
14
|
+
| Rule | Prop | Rendered token | Claims |
|
|
15
|
+
| --- | --- | --- | --- |
|
|
16
|
+
| TONE-1 | `tone="default"` | `text-foreground` | Ordinary reading attention |
|
|
17
|
+
| TONE-2 | `tone="muted"` | `text-muted` | Deliberately less than its neighbour |
|
|
18
|
+
| TONE-3 | `tone="accent"` | `text-accent-soft-foreground` | Scarce, one short span at a time |
|
|
19
|
+
|
|
20
|
+
`Text size="xs"` resolves to muted regardless of the tone requested, because the smallest size is
|
|
21
|
+
supporting information by definition. `Heading level={4}` carries the same muted treatment. Asking
|
|
22
|
+
for another tone at that size does not raise it.
|
|
23
|
+
|
|
24
|
+
## Owner
|
|
25
|
+
|
|
26
|
+
Tone belongs to Grammar. The owner cell names which component resolves the token.
|
|
27
|
+
|
|
28
|
+
| Owner | Meaning | Application writes |
|
|
29
|
+
| --- | --- | --- |
|
|
30
|
+
| A component name | `Text` resolves this tone | The prop only |
|
|
31
|
+
| `—` | The meaning has no public tone | Nothing. Report the gap |
|
|
32
|
+
|
|
33
|
+
There is no `App` owner in this file. A `text-*` colour class written by the application is
|
|
34
|
+
`APP_OVERRIDE`, and a raw hex or palette value is rejected even when it matches the token.
|
|
35
|
+
|
|
36
|
+
Status colour is not tone. Success, warning, danger, and information are semantic states owned by the
|
|
37
|
+
components that carry them, and they are never expressed by choosing a text colour.
|
|
38
|
+
|
|
39
|
+
## Tone Common already owns
|
|
40
|
+
|
|
41
|
+
Generated from `@grammar/core` claims by `scripts/generate-presentation-owned.mjs`; edit the component, not this table.
|
|
42
|
+
|
|
43
|
+
| Component | Element or condition | Rule |
|
|
44
|
+
| --- | --- | --- |
|
|
45
|
+
| `ChatWorkspace` | drawer close, hasRail, isCompactRail | TONE-1 |
|
|
46
|
+
| `ChatWorkspace` | rail trigger, hasRail, isCompactRail | TONE-1 |
|
|
47
|
+
| `Heading` | root, scale!="display", level=4 | TONE-2 |
|
|
48
|
+
| `IconTile` | root, not (isSkeleton || showsArtwork), tone="neutral" | TONE-2 |
|
|
49
|
+
| `Input` | button, not (!isSecret || toggleLabel === undefined) | TONE-2 |
|
|
50
|
+
| `Sidebar` | group label, group.label!=undefined, not collapsed | TONE-2 |
|
|
51
|
+
| `Sidebar` | list box item | TONE-1 |
|
|
52
|
+
| `SurfaceAccordionCard` | accordion body | TONE-1 |
|
|
53
|
+
| `SurfaceListCard` | fact, not (label === undefined || labelHidden), fact!=undefined | TONE-2 |
|
|
54
|
+
| `Text` | root, not isSkeleton, resolvedTone="accent" | TONE-3 |
|
|
55
|
+
| `Text` | root, not isSkeleton, resolvedTone="default" | TONE-1 |
|
|
56
|
+
| `Text` | root, not isSkeleton, resolvedTone="muted" | TONE-2 |
|
|
57
|
+
| `TextAction` | root, appearance="disclosure" | TONE-3 |
|
|
58
|
+
| `TextAction` | root, appearance="muted" | TONE-2 |
|
|
59
|
+
| `TextAction` | root, appearance="plain" | TONE-1 |
|
|
60
|
+
| `TextAction` | root, appearance="route", isCurrent | TONE-3 |
|
|
61
|
+
| `TextAction` | root, appearance="route", not isCurrent | TONE-2 |
|
|
62
|
+
| `TextAction` | root, appearance="section", isCurrent | TONE-3 |
|
|
63
|
+
| `TextAction` | root, appearance="section", not isCurrent | TONE-1 |
|
|
64
|
+
| `TextAction` | root, appearance="tab", not isCurrent | TONE-2 |
|
|
65
|
+
|
|
66
|
+
## TONE-1 — `tone="default"`
|
|
67
|
+
|
|
68
|
+
The line reads at ordinary attention. This is the resolved tone when none is given, except at the
|
|
69
|
+
smallest size.
|
|
70
|
+
|
|
71
|
+
| Case | When | Owner | Render |
|
|
72
|
+
| --- | --- | --- | --- |
|
|
73
|
+
| Case 1 | Copy or a fact the application ranked as normal reading content | `Text` | `<Text tone="default">Enrollment is active.</Text>` |
|
|
74
|
+
| Case 2 | The body of a paired title and explanation where both must be read | `Text` | Both lines stay default; weight separates them |
|
|
75
|
+
|
|
76
|
+
Not this rule: making lower-rank metadata compete with the content beside it. Use TONE-2.
|
|
77
|
+
|
|
78
|
+
## TONE-2 — `tone="muted"`
|
|
79
|
+
|
|
80
|
+
The line recedes on purpose, because something next to it carries the meaning.
|
|
81
|
+
|
|
82
|
+
| Case | When | Owner | Render |
|
|
83
|
+
| --- | --- | --- | --- |
|
|
84
|
+
| Case 1 | A qualifier, unit, or timestamp attached to a fact stated nearby | `Text` | `<Text tone="muted">Taxes are calculated at checkout.</Text>` |
|
|
85
|
+
| Case 2 | The description under a title, where the title carries the identity | `Text` | `<Text size="sm" tone="muted">Ready for junior roles</Text>` |
|
|
86
|
+
| Case 3 | Any line at the smallest size | `Text` | `size="xs"` already resolves to muted |
|
|
87
|
+
|
|
88
|
+
Not this rule: the only sentence explaining an important fact, or hiding copy that is simply too
|
|
89
|
+
long. Muting an explanation nobody else states removes it from the page in practice.
|
|
90
|
+
|
|
91
|
+
## TONE-3 — `tone="accent"`
|
|
92
|
+
|
|
93
|
+
One short span stands out because its meaning is already exceptional in context.
|
|
94
|
+
|
|
95
|
+
| Case | When | Owner | Render |
|
|
96
|
+
| --- | --- | --- | --- |
|
|
97
|
+
| Case 1 | A single short label whose emphasis the application has already decided | `Text` | `<Text tone="accent" weight="semibold">Recommended</Text>` |
|
|
98
|
+
|
|
99
|
+
Not this rule: whole paragraphs, repeated peers, or decoration. Accent repeated across siblings stops
|
|
100
|
+
marking anything. Accent also never carries meaning alone, because colour is not readable by every
|
|
101
|
+
reader.
|
|
102
|
+
|
|
103
|
+
## Contrast
|
|
104
|
+
|
|
105
|
+
Tone tokens are defined against the surface they sit on. A tone chosen on one surface and rendered on
|
|
106
|
+
another is a contrast finding, not a preference, and it is measured against the composed background
|
|
107
|
+
rather than the intended one.
|
|
108
|
+
|
|
109
|
+
The application changes the surface, never the token, when contrast fails.
|
|
110
|
+
|
|
111
|
+
## What this file does not decide
|
|
112
|
+
|
|
113
|
+
How large or heavy the line is set is [Font](font.md). Which surface it sits on, and the semantic
|
|
114
|
+
colour of that surface, are outside presentation entirely.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Tone presentation
|
|
2
|
+
|
|
3
|
+
File này trả lời đúng một câu hỏi: một dòng chữ đã xếp hạng xong thì diễn đạt hạng đó bằng prop tone
|
|
4
|
+
công khai nào.
|
|
5
|
+
|
|
6
|
+
Tone là lựa chọn ngữ nghĩa chứ không phải lựa chọn màu. Ứng dụng chọn dòng đó đáng được chú ý bao
|
|
7
|
+
nhiêu, Grammar quy nó về một token. Ứng dụng không bao giờ viết class màu chữ và không ghi đè màu
|
|
8
|
+
bên trong một Grammar component khác.
|
|
9
|
+
|
|
10
|
+
## Thang giá trị
|
|
11
|
+
|
|
12
|
+
Tập tone công khai là tập đóng, xếp theo mức chú ý mà mỗi bậc đòi hỏi.
|
|
13
|
+
|
|
14
|
+
| Rule | Prop | Token render ra | Đòi hỏi |
|
|
15
|
+
| --- | --- | --- | --- |
|
|
16
|
+
| TONE-1 | `tone="default"` | `text-foreground` | Mức chú ý đọc thông thường |
|
|
17
|
+
| TONE-2 | `tone="muted"` | `text-muted` | Cố ý thấp hơn dòng bên cạnh |
|
|
18
|
+
| TONE-3 | `tone="accent"` | `text-accent-soft-foreground` | Khan hiếm, mỗi lần một đoạn ngắn |
|
|
19
|
+
|
|
20
|
+
`Text size="xs"` quy về muted bất kể tone được yêu cầu là gì, vì cỡ nhỏ nhất đã là thông tin phụ theo
|
|
21
|
+
định nghĩa. `Heading level={4}` mang đúng cách xử lý muted đó. Xin một tone khác ở cỡ này cũng không
|
|
22
|
+
nâng nó lên được.
|
|
23
|
+
|
|
24
|
+
## Owner
|
|
25
|
+
|
|
26
|
+
Tone thuộc về Grammar. Ô owner gọi tên component nào quy ra token.
|
|
27
|
+
|
|
28
|
+
| Owner | Nghĩa | Ứng dụng viết |
|
|
29
|
+
| --- | --- | --- |
|
|
30
|
+
| Tên component | `Text` quy ra tone này | Chỉ truyền prop |
|
|
31
|
+
| `—` | Ý nghĩa này chưa có tone công khai | Không viết gì, báo là thiếu |
|
|
32
|
+
|
|
33
|
+
File này không có owner `App`. Một class màu `text-*` do ứng dụng viết là `APP_OVERRIDE`, và một mã
|
|
34
|
+
hex hay giá trị palette thô thì bị từ chối kể cả khi nó trùng token.
|
|
35
|
+
|
|
36
|
+
Màu trạng thái không phải tone. Thành công, cảnh báo, nguy hiểm và thông tin là những trạng thái ngữ
|
|
37
|
+
nghĩa do chính component mang chúng sở hữu, và không bao giờ được diễn đạt bằng cách chọn màu chữ.
|
|
38
|
+
|
|
39
|
+
## Tone mà Common đã sở hữu
|
|
40
|
+
|
|
41
|
+
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.
|
|
42
|
+
|
|
43
|
+
| Component | Phần tử hoặc điều kiện | Rule |
|
|
44
|
+
| --- | --- | --- |
|
|
45
|
+
| `ChatWorkspace` | drawer close, hasRail, isCompactRail | TONE-1 |
|
|
46
|
+
| `ChatWorkspace` | rail trigger, hasRail, isCompactRail | TONE-1 |
|
|
47
|
+
| `Heading` | root, scale!="display", level=4 | TONE-2 |
|
|
48
|
+
| `IconTile` | root, not (isSkeleton || showsArtwork), tone="neutral" | TONE-2 |
|
|
49
|
+
| `Input` | button, not (!isSecret || toggleLabel === undefined) | TONE-2 |
|
|
50
|
+
| `Sidebar` | group label, group.label!=undefined, not collapsed | TONE-2 |
|
|
51
|
+
| `Sidebar` | list box item | TONE-1 |
|
|
52
|
+
| `SurfaceAccordionCard` | accordion body | TONE-1 |
|
|
53
|
+
| `SurfaceListCard` | fact, not (label === undefined || labelHidden), fact!=undefined | TONE-2 |
|
|
54
|
+
| `Text` | root, not isSkeleton, resolvedTone="accent" | TONE-3 |
|
|
55
|
+
| `Text` | root, not isSkeleton, resolvedTone="default" | TONE-1 |
|
|
56
|
+
| `Text` | root, not isSkeleton, resolvedTone="muted" | TONE-2 |
|
|
57
|
+
| `TextAction` | root, appearance="disclosure" | TONE-3 |
|
|
58
|
+
| `TextAction` | root, appearance="muted" | TONE-2 |
|
|
59
|
+
| `TextAction` | root, appearance="plain" | TONE-1 |
|
|
60
|
+
| `TextAction` | root, appearance="route", isCurrent | TONE-3 |
|
|
61
|
+
| `TextAction` | root, appearance="route", not isCurrent | TONE-2 |
|
|
62
|
+
| `TextAction` | root, appearance="section", isCurrent | TONE-3 |
|
|
63
|
+
| `TextAction` | root, appearance="section", not isCurrent | TONE-1 |
|
|
64
|
+
| `TextAction` | root, appearance="tab", not isCurrent | TONE-2 |
|
|
65
|
+
|
|
66
|
+
## TONE-1 — `tone="default"`
|
|
67
|
+
|
|
68
|
+
Dòng chữ đọc ở mức chú ý thông thường. Đây là tone mặc định khi không truyền gì, trừ ở cỡ nhỏ nhất.
|
|
69
|
+
|
|
70
|
+
| Case | Dùng khi | Owner | Render |
|
|
71
|
+
| --- | --- | --- | --- |
|
|
72
|
+
| Case 1 | Copy hoặc dữ kiện mà ứng dụng xếp là nội dung đọc thường | `Text` | `<Text tone="default">Enrollment is active.</Text>` |
|
|
73
|
+
| Case 2 | Phần thân của một cặp tiêu đề và giải thích mà cả hai đều phải đọc | `Text` | Cả hai dòng giữ default, độ đậm mới là thứ tách chúng |
|
|
74
|
+
|
|
75
|
+
Không phải rule này: để metadata hạng thấp cạnh tranh với nội dung bên cạnh. Dùng TONE-2.
|
|
76
|
+
|
|
77
|
+
## TONE-2 — `tone="muted"`
|
|
78
|
+
|
|
79
|
+
Dòng chữ lùi lại có chủ ý, vì thứ nằm cạnh nó mới mang nghĩa chính.
|
|
80
|
+
|
|
81
|
+
| Case | Dùng khi | Owner | Render |
|
|
82
|
+
| --- | --- | --- | --- |
|
|
83
|
+
| Case 1 | Một dòng bổ nghĩa, đơn vị, hay mốc thời gian gắn với một dữ kiện nêu ngay gần đó | `Text` | `<Text tone="muted">Taxes are calculated at checkout.</Text>` |
|
|
84
|
+
| Case 2 | Phần mô tả dưới một tiêu đề, mà tiêu đề mới mang danh tính | `Text` | `<Text size="sm" tone="muted">Ready for junior roles</Text>` |
|
|
85
|
+
| Case 3 | Bất kỳ dòng nào ở cỡ nhỏ nhất | `Text` | `size="xs"` đã tự quy về muted |
|
|
86
|
+
|
|
87
|
+
Không phải rule này: câu duy nhất giải thích một dữ kiện quan trọng, hoặc để giấu bớt phần copy chỉ
|
|
88
|
+
vì nó dài. Làm mờ một lời giải thích mà không ai khác nói lại, trên thực tế là gỡ nó khỏi trang.
|
|
89
|
+
|
|
90
|
+
## TONE-3 — `tone="accent"`
|
|
91
|
+
|
|
92
|
+
Một đoạn ngắn nổi lên vì ý nghĩa của nó vốn đã đặc biệt trong ngữ cảnh đó.
|
|
93
|
+
|
|
94
|
+
| Case | Dùng khi | Owner | Render |
|
|
95
|
+
| --- | --- | --- | --- |
|
|
96
|
+
| Case 1 | Một nhãn ngắn duy nhất mà ứng dụng đã quyết định là cần nhấn | `Text` | `<Text tone="accent" weight="semibold">Recommended</Text>` |
|
|
97
|
+
|
|
98
|
+
Không phải rule này: cả đoạn văn, các phần tử ngang hàng lặp lại, hay trang trí. Accent lặp trên
|
|
99
|
+
nhiều phần tử ngang hàng thì thôi đánh dấu được gì. Accent cũng không bao giờ mang nghĩa một mình,
|
|
100
|
+
vì không phải người đọc nào cũng đọc được màu.
|
|
101
|
+
|
|
102
|
+
## Tương phản
|
|
103
|
+
|
|
104
|
+
Token tone được định nghĩa so với chính surface mà nó nằm lên. Một tone chọn trên surface này rồi
|
|
105
|
+
render trên surface khác là một phát hiện về tương phản chứ không phải chuyện thẩm mỹ, và nó được đo
|
|
106
|
+
so với nền thật sự đang chồng lên chứ không phải nền dự định.
|
|
107
|
+
|
|
108
|
+
Khi tương phản không đạt thì ứng dụng đổi surface, không bao giờ đổi token.
|
|
109
|
+
|
|
110
|
+
## File này không quyết định
|
|
111
|
+
|
|
112
|
+
Dòng chữ được đặt to hay đậm cỡ nào thuộc về [Font](font.md). Nó nằm trên surface nào, và màu ngữ
|
|
113
|
+
nghĩa của surface đó, thì nằm hoàn toàn ngoài phạm vi presentation.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# UI proof
|
|
2
|
+
|
|
3
|
+
Proof is the decision layer that only exists after the page has rendered:
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
business
|
|
7
|
+
-> composition decides regions, rank, actions, states and emphasis
|
|
8
|
+
-> presentation resolves CSS values on app-owned boundaries
|
|
9
|
+
-> rendered UI <- proof observes here
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Every rule in this folder is consumed by the audit operator. That operator has no access to intent,
|
|
13
|
+
only to output: the accessibility tree that was computed, the element that actually holds focus, the
|
|
14
|
+
frame where the animation stopped, and the claim the page ended up making. These topics belong
|
|
15
|
+
together because none of them can be established by reading source. A `:focus-visible` rule does not
|
|
16
|
+
prove a visible indicator, a `label` prop does not prove a computed name, a `motion` attribute does
|
|
17
|
+
not prove a transition, and an approved copy deck does not prove what the rendered page asserts.
|
|
18
|
+
Each rule therefore states the observation that would falsify it, so a passing verdict always names
|
|
19
|
+
something that was looked at.
|
|
20
|
+
|
|
21
|
+
## Catalog
|
|
22
|
+
|
|
23
|
+
| Knowledge | What it decides | Rules |
|
|
24
|
+
| --- | --- | --- |
|
|
25
|
+
| [Accessibility](accessibility.md) | Whether names, relationships, targets and contrast reach every reader | A11Y-1 to A11Y-4 |
|
|
26
|
+
| [Contrast](contrast.md) | Whether distinctions and text survive measurement in every theme and state | COLOR-3, COLOR-5 |
|
|
27
|
+
| [Focus](focus.md) | Where focus is visible, how far it travels, and where it returns | FOCUS-1 to FOCUS-5 |
|
|
28
|
+
| [Motion](motion.md) | Whether meaning survives with the movement stopped, reduced or interrupted | MOTION-1 to MOTION-4 |
|
|
29
|
+
| [Render truth](render-truth.md) | Whether every rendered claim traces back to real authority | TRUTH-1 to TRUTH-4 |
|
|
30
|
+
|
|
31
|
+
## Rule shape
|
|
32
|
+
|
|
33
|
+
`A11Y-1`, `FOCUS-5`, and the other `PREFIX-n` names are stable ordinal addresses within their topic.
|
|
34
|
+
The number is not a severity or a conformance level. A topic may publish a non-contiguous series:
|
|
35
|
+
`contrast.md` publishes only `COLOR-3` and `COLOR-5`, because the other numbers of that prefix were
|
|
36
|
+
retired with the topic they came from and are never reused.
|
|
37
|
+
|
|
38
|
+
Every rule carries its heading, one line naming what the rule governs, and one table:
|
|
39
|
+
|
|
40
|
+
| Case | When | Observe |
|
|
41
|
+
| --- | --- | --- |
|
|
42
|
+
| Case 1 | The concrete rendered situation that reaches this rule. | The exact runtime evidence, and what seeing it would falsify. |
|
|
43
|
+
|
|
44
|
+
The `Observe` cell names a thing that can be captured from the running page — a computed name, an
|
|
45
|
+
active element, a measured rectangle, a computed duration, a traced result — and says what a
|
|
46
|
+
contrary observation would disprove. It never restates an intention.
|
|
47
|
+
|
|
48
|
+
A case that belongs to a neighbouring rule is not a table row. It goes on one line after the table,
|
|
49
|
+
as `Not this rule: <condition> is PREFIX-n`. Each file closes with a
|
|
50
|
+
`## What this file does not decide` section linking its siblings and the composition knowledge that
|
|
51
|
+
made the decision being tested.
|
|
52
|
+
|
|
53
|
+
Component and prop names in these files resolve to `@starci/grammar/common`. Where the published
|
|
54
|
+
contract offers no owner for a required behaviour, the audit records a capability gap rather than
|
|
55
|
+
approving a local substitute.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# UI proof
|
|
2
|
+
|
|
3
|
+
Proof là tầng quyết định chỉ tồn tại sau khi trang đã render:
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
business
|
|
7
|
+
-> composition quyết định vùng, cấp độ, action, state và điểm nhấn
|
|
8
|
+
-> presentation chốt giá trị CSS trên boundary do app sở hữu
|
|
9
|
+
-> UI đã render <- proof quan sát ở đây
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Mọi rule trong folder này được operator audit tiêu thụ. Operator đó không truy cập được ý định, chỉ
|
|
13
|
+
truy cập được đầu ra: cây accessibility đã được tính, phần tử đang thật sự giữ focus, khung hình nơi
|
|
14
|
+
animation dừng lại, và tuyên bố mà trang cuối cùng đưa ra. Những chủ đề này nằm chung một chỗ vì
|
|
15
|
+
không cái nào xác lập được bằng cách đọc source. Một rule `:focus-visible` không chứng minh có một
|
|
16
|
+
chỉ dấu nhìn thấy được, một prop `label` không chứng minh một cái tên được tính ra, một thuộc tính
|
|
17
|
+
`motion` không chứng minh một transition, và một bản copy đã duyệt không chứng minh điều mà trang
|
|
18
|
+
render ra đang khẳng định. Vì vậy mỗi rule đều nêu quan sát nào sẽ bác bỏ nó, để một kết luận đạt
|
|
19
|
+
luôn gọi tên được thứ đã thật sự được nhìn.
|
|
20
|
+
|
|
21
|
+
## Danh mục
|
|
22
|
+
|
|
23
|
+
| Knowledge | Quyết định điều gì | Rule |
|
|
24
|
+
| --- | --- | --- |
|
|
25
|
+
| [Accessibility](accessibility.vi.md) | Tên, quan hệ, kích thước mục tiêu và tương phản có tới được mọi người đọc không | A11Y-1 đến A11Y-4 |
|
|
26
|
+
| [Contrast](contrast.vi.md) | Khác biệt và chữ có sống sót qua phép đo ở mọi theme và mọi state không | COLOR-3, COLOR-5 |
|
|
27
|
+
| [Focus](focus.vi.md) | Focus nhìn thấy ở đâu, đi xa tới đâu, và quay về đâu | FOCUS-1 đến FOCUS-5 |
|
|
28
|
+
| [Motion](motion.vi.md) | Ý nghĩa có sống sót khi chuyển động dừng, bị giảm hoặc bị cắt ngang không | MOTION-1 đến MOTION-4 |
|
|
29
|
+
| [Render truth](render-truth.vi.md) | Mọi tuyên bố đã render có truy về được authority thật không | TRUTH-1 đến TRUTH-4 |
|
|
30
|
+
|
|
31
|
+
## Cấu trúc rule
|
|
32
|
+
|
|
33
|
+
`A11Y-1`, `FOCUS-5` và các tên `PREFIX-n` khác là địa chỉ thứ tự ổn định trong chủ đề của chúng. Con
|
|
34
|
+
số không phải mức độ nghiêm trọng, cũng không phải một mức tuân thủ. Một chủ đề có thể công bố một
|
|
35
|
+
dãy không liền số: `contrast.vi.md` chỉ công bố `COLOR-3` và `COLOR-5`, vì các số còn lại của tiền tố
|
|
36
|
+
đó đã nghỉ cùng chủ đề sinh ra chúng và không bao giờ được dùng lại.
|
|
37
|
+
|
|
38
|
+
Mỗi rule gồm heading, một dòng gọi tên thứ mà rule chi phối, và đúng một bảng:
|
|
39
|
+
|
|
40
|
+
| Case | Dùng khi | Quan sát |
|
|
41
|
+
| --- | --- | --- |
|
|
42
|
+
| Case 1 | Tình huống đã render cụ thể dẫn tới rule này. | Bằng chứng runtime chính xác, và việc nhìn thấy nó sẽ bác bỏ điều gì. |
|
|
43
|
+
|
|
44
|
+
Ô `Quan sát` gọi tên một thứ chụp được từ trang đang chạy, như một cái tên được tính ra, một phần tử
|
|
45
|
+
đang active, một hình chữ nhật đã đo, một thời lượng đã tính, một kết quả đã truy vết, và nói rõ một
|
|
46
|
+
quan sát ngược lại sẽ bác bỏ điều gì. Nó không bao giờ chỉ nhắc lại một ý định.
|
|
47
|
+
|
|
48
|
+
Một case thuộc về rule hàng xóm thì không nằm trong bảng. Nó đứng thành một dòng ngay sau bảng, theo
|
|
49
|
+
dạng `Không phải rule này: <điều kiện> thuộc PREFIX-n`. Mỗi file khép lại bằng mục
|
|
50
|
+
`## File này không quyết định`, dẫn sang các file anh em và sang nhóm composition, nơi quyết định
|
|
51
|
+
đang bị kiểm chứng đã được đưa ra.
|
|
52
|
+
|
|
53
|
+
Tên component và tên prop trong các file này đều phải phân giải được về `@starci/grammar/common`. Ở
|
|
54
|
+
đâu hợp đồng công khai chưa có owner cho một hành vi cần thiết, phần audit ghi nhận capability gap
|
|
55
|
+
thay vì chấp nhận một giải pháp cục bộ.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Accessibility proof
|
|
2
|
+
|
|
3
|
+
This file answers one question: in the tree that actually rendered, can every reader perceive and
|
|
4
|
+
operate what the direction intended?
|
|
5
|
+
|
|
6
|
+
Nothing here is settled by reading source. A prop in the source is an intention; the accessible name
|
|
7
|
+
computed from the rendered node is the evidence. Each rule below states the observation that would
|
|
8
|
+
falsify it, so a passing claim always names something that was looked at.
|
|
9
|
+
|
|
10
|
+
## A11Y-1 — Field name and relationships
|
|
11
|
+
|
|
12
|
+
Governs whether a field's identity and its current guidance reach assistive output.
|
|
13
|
+
|
|
14
|
+
| Case | When | Observe |
|
|
15
|
+
| --- | --- | --- |
|
|
16
|
+
| Case 1 | A field renders with a visible label | The computed accessible name equals the visible label. A name supplied only by a placeholder, or a field with no name at all, falsifies it |
|
|
17
|
+
| Case 2 | The field has a hint, an error, or both | The message is programmatically related to that input as its description, and the text is the current one. A visible message with no relation to the control falsifies it |
|
|
18
|
+
| Case 3 | The field is required, invalid, or disabled | The rendered semantics match the current business facts. A red border with no invalid semantics falsifies it |
|
|
19
|
+
| Case 4 | The reader types and validation runs again | The entered value survives the state change, and the description is the new one rather than a stale message |
|
|
20
|
+
|
|
21
|
+
Not this rule: whether the failure was placed on the right owner in the first place is decided in
|
|
22
|
+
composition, under FEEDBACK-1.
|
|
23
|
+
|
|
24
|
+
## A11Y-2 — Glyph-only commands still carry a name
|
|
25
|
+
|
|
26
|
+
Governs commands whose visible content is a glyph.
|
|
27
|
+
|
|
28
|
+
| Case | When | Observe |
|
|
29
|
+
| --- | --- | --- |
|
|
30
|
+
| Case 1 | `IconButton` renders a glyph-only command | The button role carries an accessible name equal to its `label`. A tooltip as the only explanation falsifies it |
|
|
31
|
+
| Case 2 | The button contains a decorative leading glyph | The inner glyph is hidden from assistive output. The same name computed twice, once on the button and once on the icon, falsifies it |
|
|
32
|
+
| Case 3 | A standalone glyph itself carries meaning | `Icon.ariaLabel` produces an image role with that name. A meaningful glyph left hidden falsifies it |
|
|
33
|
+
| Case 4 | The command can be disabled | Keyboard activation reaches it when enabled, and produces nothing when disabled |
|
|
34
|
+
|
|
35
|
+
## A11Y-3 — Measurements have an accessible identity
|
|
36
|
+
|
|
37
|
+
Governs numbers rendered as bars.
|
|
38
|
+
|
|
39
|
+
| Case | When | Observe |
|
|
40
|
+
| --- | --- | --- |
|
|
41
|
+
| Case 1 | A resolved measurement renders | The progressbar exposes an accessible name equal to its label, the current value, a minimum of `0`, and a maximum of `100`, and that value equals the product fact |
|
|
42
|
+
| Case 2 | The value has not resolved | The skeleton renders aria-hidden geometry with no progressbar and no label. A named progressbar announcing zero falsifies it |
|
|
43
|
+
| Case 3 | `value` was omitted while data was unknown | The non-skeleton renderer defaults it, so the rendered output announces `0`, which falsifies the claim that the value is unknown |
|
|
44
|
+
| Case 4 | A decorative bar sits beside the measurement | It carries no progressbar role. A second announced measurement for one fact falsifies the region |
|
|
45
|
+
|
|
46
|
+
## A11Y-4 — Perceivable and operable at every required state
|
|
47
|
+
|
|
48
|
+
Governs the evidence that closes an accessibility claim.
|
|
49
|
+
|
|
50
|
+
| Case | When | Observe |
|
|
51
|
+
| --- | --- | --- |
|
|
52
|
+
| Case 1 | A target must be operable by touch | Accordion triggers and controls inside a rail measure at least `44px × 44px` in the current render. Any other target needs its own published contract before a minimum is asserted |
|
|
53
|
+
| Case 2 | The task is attempted by keyboard alone | Every required control is reachable and operable. One unreachable required control falsifies the page |
|
|
54
|
+
| Case 3 | The page is viewed in forced colours, at reduced contrast, or with colour removed | Every state, selection, and focus distinction survives. A distinction carried by fill alone falsifies it |
|
|
55
|
+
| Case 4 | The page is zoomed, the text is scaled, or the viewport narrows | No required content and no focus indicator is clipped |
|
|
56
|
+
| Case 5 | A family or the application styles over the published owner | The isolated published output, the family delta, and the application delta are compared separately, so the failing layer is named |
|
|
57
|
+
|
|
58
|
+
Not this rule: which semantic owner should have been chosen is decided in composition, under
|
|
59
|
+
HIERARCHY-1 and STATE-1.
|
|
60
|
+
|
|
61
|
+
## What this file does not decide
|
|
62
|
+
|
|
63
|
+
Which rank, action, or state the direction chose is [Hierarchy](../composition/hierarchy.md),
|
|
64
|
+
[Action](../composition/action.md), and [State](../composition/state.md). Where the focus indicator
|
|
65
|
+
goes and how far focus may travel is [Focus](focus.md). Whether animation removes meaning is
|
|
66
|
+
[Motion](motion.md), and whether the rendered claim matches authority is
|
|
67
|
+
[Render truth](render-truth.md).
|