ui-foundations 0.4.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +8 -7
  2. package/dist/core/index.css +1 -0
  3. package/dist/macros/ui.njk +61 -0
  4. package/dist/main.css +528 -89
  5. package/dist/react/accordion.js +36 -0
  6. package/dist/react/avatar.js +34 -0
  7. package/dist/react/button.js +1 -12
  8. package/dist/react/checkbox.js +3 -20
  9. package/dist/react/divider.js +31 -0
  10. package/dist/react/icon.js +1 -12
  11. package/dist/react/index.js +6 -0
  12. package/dist/react/radio.js +3 -20
  13. package/dist/react/switch.js +3 -20
  14. package/dist/react/tabs.js +72 -0
  15. package/dist/react/textarea.js +38 -0
  16. package/dist/react/tooltip.js +25 -0
  17. package/dist/react/warn-dev.js +15 -0
  18. package/dist/tokens/css/appearance-modes.tokens.mode-dark.css +6 -6
  19. package/dist/tokens/css/appearance-modes.tokens.mode-light.css +1 -1
  20. package/dist/tokens/css/components-ui.tokens.css +66 -68
  21. package/dist/tokens/css/core-primitives.tokens.css +72 -1
  22. package/dist/tokens/css/semantics-roles.tokens.css +1 -1
  23. package/dist/tokens/css/themes-brands.tokens.brand-a.css +11 -11
  24. package/dist/tokens/css/themes-brands.tokens.brand-b.css +1 -1
  25. package/dist/tokens/css/themes-brands.tokens.brand-c.css +22 -0
  26. package/dist/tokens/json/components-ui.tokens.json +275 -277
  27. package/dist/tokens/json/core-primitives.tokens.json +302 -0
  28. package/dist/tokens/json/themes-brands.tokens.brand-a.json +10 -10
  29. package/dist/tokens/json/themes-brands.tokens.brand-b.json +10 -10
  30. package/dist/tokens/json/themes-brands.tokens.brand-c.json +81 -0
  31. package/dist/tokens/tokens.yaml +1701 -583
  32. package/dist/tokens/ts/appearance-modes.tokens.mode-dark.ts +6 -6
  33. package/dist/tokens/ts/appearance-modes.tokens.mode-light.ts +1 -1
  34. package/dist/tokens/ts/components-ui.tokens.ts +67 -69
  35. package/dist/tokens/ts/core-primitives.tokens.ts +73 -2
  36. package/dist/tokens/ts/semantics-roles.tokens.ts +1 -1
  37. package/dist/tokens/ts/themes-brands.tokens.brand-a.ts +11 -11
  38. package/dist/tokens/ts/themes-brands.tokens.brand-b.ts +1 -1
  39. package/dist/tokens/ts/themes-brands.tokens.brand-c.ts +32 -0
  40. package/dist/ui/index.css +6 -0
  41. package/dist/ui/patterns/accordion.css +81 -0
  42. package/dist/ui/patterns/avatar.css +57 -0
  43. package/dist/ui/patterns/divider.css +25 -0
  44. package/dist/ui/patterns/tabs.css +71 -0
  45. package/dist/ui/patterns/textarea.css +50 -0
  46. package/dist/ui/patterns/tooltip.css +64 -0
  47. package/docs/agentic/README.md +1 -0
  48. package/docs/agentic/skills/component-accessibility-audit.md +132 -0
  49. package/docs/foundations/foundation-007-typography-selectors-and-specificity.md +1 -1
  50. package/package.json +2 -1
  51. package/dist/tokens/missing-tokens.json +0 -43
@@ -0,0 +1,50 @@
1
+ @layer components {
2
+ .textarea {
3
+ display: block;
4
+ inline-size: 100%;
5
+ min-block-size: calc(var(--line-height-md) * 3 + var(--size-spacing-300) * 2);
6
+ padding-inline: var(--size-spacing-300);
7
+ padding-block: var(--size-spacing-300);
8
+ font-family: var(--font-family-sans);
9
+ font-size: var(--font-size-md);
10
+ line-height: var(--line-height-md);
11
+ color: var(--color-text-default);
12
+ background: var(--color-fill-surface);
13
+ border: var(--size-border-100) solid var(--color-border-default);
14
+ border-radius: var(--size-radius-300);
15
+ resize: vertical;
16
+ transition: border-color 0.15s ease;
17
+ }
18
+
19
+ .textarea::placeholder {
20
+ color: var(--color-text-disabled);
21
+ }
22
+
23
+ .textarea:hover,
24
+ .textarea.is-hover {
25
+ border-color: var(--color-border-strong);
26
+ }
27
+
28
+ .textarea:focus-visible,
29
+ .textarea.is-focus-visible {
30
+ border-color: var(--color-focus);
31
+ outline: none;
32
+ box-shadow: 0 0 0 var(--shadow-focus) var(--color-focus);
33
+ }
34
+
35
+ .textarea:disabled,
36
+ .textarea.is-disabled {
37
+ color: var(--color-text-disabled);
38
+ background: var(--color-fill-disabled);
39
+ border-color: var(--color-border-disabled);
40
+ cursor: not-allowed;
41
+ resize: none;
42
+ }
43
+
44
+ .textarea[readonly] {
45
+ background: var(--color-fill-surface);
46
+ border-color: var(--color-border-default);
47
+ cursor: default;
48
+ resize: none;
49
+ }
50
+ }
@@ -0,0 +1,64 @@
1
+ @layer components {
2
+ .tooltip {
3
+ position: absolute;
4
+ z-index: var(--zindex-tooltip);
5
+ max-inline-size: 15rem;
6
+ padding-inline: var(--size-spacing-300);
7
+ padding-block: var(--size-spacing-200);
8
+ font-family: var(--font-family-sans);
9
+ font-size: var(--font-size-sm);
10
+ line-height: var(--line-height-sm);
11
+ color: var(--color-text-inverse);
12
+ background: var(--color-neutral-900);
13
+ border-radius: var(--size-radius-300);
14
+ pointer-events: none;
15
+ opacity: 0;
16
+ transition: opacity 0.15s ease;
17
+ }
18
+
19
+ .tooltip.is-visible {
20
+ opacity: 1;
21
+ }
22
+
23
+ /* ── Placement ── */
24
+
25
+ .tooltip[data-placement="top"] {
26
+ inset-block-end: 100%;
27
+ inset-inline-start: 50%;
28
+ transform: translateX(-50%);
29
+ margin-block-end: var(--size-spacing-200);
30
+ }
31
+
32
+ .tooltip[data-placement="bottom"] {
33
+ inset-block-start: 100%;
34
+ inset-inline-start: 50%;
35
+ transform: translateX(-50%);
36
+ margin-block-start: var(--size-spacing-200);
37
+ }
38
+
39
+ .tooltip[data-placement="left"] {
40
+ inset-inline-end: 100%;
41
+ inset-block-start: 50%;
42
+ transform: translateY(-50%);
43
+ margin-inline-end: var(--size-spacing-200);
44
+ }
45
+
46
+ .tooltip[data-placement="right"] {
47
+ inset-inline-start: 100%;
48
+ inset-block-start: 50%;
49
+ transform: translateY(-50%);
50
+ margin-inline-start: var(--size-spacing-200);
51
+ }
52
+
53
+ /* ── Trigger wrapper ── */
54
+
55
+ .tooltip-trigger {
56
+ position: relative;
57
+ display: inline-flex;
58
+ }
59
+
60
+ .tooltip-trigger:hover > .tooltip,
61
+ .tooltip-trigger:focus-within > .tooltip {
62
+ opacity: 1;
63
+ }
64
+ }
@@ -32,3 +32,4 @@ in the repository.
32
32
  ## Skills
33
33
 
34
34
  - `skills/ux-writing-coach.md` — multilingual UX writing review skill for product copy
35
+ - `skills/component-accessibility-audit.md` — repeatable workflow and template for single-component accessibility audits
@@ -0,0 +1,132 @@
1
+ # Component Accessibility Audit Skill
2
+
3
+ ## Purpose
4
+
5
+ Create a repeatable, component-level accessibility audit workflow before implementation fixes.
6
+
7
+ Use this skill to evaluate one interactive component at a time and produce findings in a consistent format that can drive small follow-up PRs.
8
+
9
+ ## Governance references (must read first)
10
+
11
+ 1. `DESIGN.md`
12
+ 2. `AGENTS.md`
13
+ 3. `docs/playbook.md`
14
+ 4. `docs/working-context.md`
15
+ 5. `docs/ui-foundations-rules.md`
16
+ 6. `docs/foundations/`
17
+ 7. `docs/agentic/assistant-behavior-rules.md`
18
+ 8. `IMPLEMENTATION.md`
19
+
20
+ Never contradict these sources. Prefer explicit, verifiable findings over assumptions.
21
+
22
+ ## Scope
23
+
24
+ Apply this skill to interactive components (e.g., Button, Link, Input, Select, Checkbox, Radio, Switch, Tabs, Accordion, Modal, Flyout, Dropdown, Tooltip, Pagination, Show More/Show Less, Tags).
25
+
26
+ Do not use this skill to implement broad fixes in the same PR. This skill is audit-first.
27
+
28
+ ## Audit workflow (repeatable)
29
+
30
+ 1. **Plan**
31
+ - Select exactly one component target.
32
+ - Confirm component surfaces in scope (CSS pattern, macro/template, React wrapper, docs, tests).
33
+
34
+ 2. **Collect evidence**
35
+ - Inspect source implementation files.
36
+ - Inspect usage examples and docs.
37
+ - Inspect test coverage.
38
+ - Record exact file paths and relevant lines.
39
+
40
+ 3. **Run checks**
41
+ - Semantic HTML
42
+ - Accessible names
43
+ - Keyboard behavior
44
+ - Focus management
45
+ - ARIA/state handling
46
+ - Form association (where relevant)
47
+ - Icon-only usage
48
+ - Contrast/token risks
49
+ - Test coverage
50
+ - Documentation gaps
51
+ - Manual screen reader validation needs
52
+
53
+ 4. **Score severity**
54
+ - Assign one severity per finding using the model below.
55
+
56
+ 5. **Propose minimal fix**
57
+ - Suggest the smallest safe change that resolves the finding.
58
+ - Keep fixes scoped to one component per follow-up PR.
59
+
60
+ 6. **Report**
61
+ - Output findings using the template in this document.
62
+
63
+ ## Severity model
64
+
65
+ Use one of these labels:
66
+
67
+ - **blocker**
68
+ - Breaks core accessibility behavior (e.g., no accessible name, unusable keyboard path, broken form semantics, missing focus trap in modal).
69
+ - Should be fixed before release.
70
+
71
+ - **high**
72
+ - Major accessibility risk with likely user impact, but possible workaround exists.
73
+ - Prioritize immediately after blockers.
74
+
75
+ - **medium**
76
+ - Important gap or drift that reduces accessibility quality/reliability.
77
+ - Schedule in near-term follow-up.
78
+
79
+ - **low**
80
+ - Minor issue, documentation gap, or optimization with limited immediate impact.
81
+ - Track and resolve in routine improvements.
82
+
83
+ ## Findings template
84
+
85
+ Use this exact structure for each finding:
86
+
87
+ - **Component:**
88
+ - **Check area:** (semantic HTML / accessible name / keyboard / focus / ARIA-state / form association / icon-only / contrast-token / tests / docs / manual SR)
89
+ - **Observed behavior:**
90
+ - **Expected behavior:**
91
+ - **Evidence:** (file paths + line refs)
92
+ - **Severity:** blocker | high | medium | low
93
+ - **Minimal fix strategy:**
94
+ - **Follow-up test need:**
95
+ - **Manual SR validation need:**
96
+
97
+ ## Minimal-fix strategy
98
+
99
+ When proposing a fix:
100
+
101
+ 1. Prefer native semantics over custom ARIA.
102
+ 2. Change the smallest surface that safely resolves the issue.
103
+ 3. Keep API compatibility unless current API is inherently inaccessible.
104
+ 4. Update docs and tests in the same small PR when behavior changes.
105
+ 5. Avoid cross-component refactors in accessibility fix PRs.
106
+
107
+ ## Manual screen reader validation guidance
108
+
109
+ For each audited component, explicitly state whether manual SR validation is needed and why.
110
+
111
+ Recommended baseline matrix:
112
+ - VoiceOver + Safari (macOS)
113
+ - NVDA + Firefox (Windows)
114
+ - Optional: JAWS + Chrome for enterprise parity
115
+
116
+ Validate at minimum:
117
+ - role announcement
118
+ - name announcement
119
+ - state announcement
120
+ - focus order
121
+ - action feedback after interaction
122
+
123
+ ## Example audit prompt (single component)
124
+
125
+ > Audit the `Link` component only using the Component Accessibility Audit Skill. Check semantic HTML, accessible names, keyboard behavior, focus management, ARIA/state handling, icon-only usage, contrast/token risks, tests, docs, and manual screen reader validation needs. Output findings using the required template and assign severity with blocker/high/medium/low. Do not implement fixes.
126
+
127
+ ## Output expectations
128
+
129
+ - Be explicit and evidence-based.
130
+ - Distinguish verified findings from assumptions.
131
+ - Keep findings actionable for small follow-up PRs.
132
+ - If not verified, mark as "not verified".
@@ -22,7 +22,7 @@ Provide a consistent typography API with low selector specificity and predictabl
22
22
 
23
23
  4. Use `:where()` for zero-specificity size/scale selectors where possible.
24
24
 
25
- 5. Reserve data attributes (for example `[data-theme]`, `[data-density]`) for context/state, not as primary styling API.
25
+ 5. Reserve data attributes (for example `[data-brand]`, `[data-mode]`, `[data-density]`) for context/state, not as primary styling API.
26
26
 
27
27
  ## Implications
28
28
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ui-foundations",
3
- "version": "0.4.1",
3
+ "version": "0.6.0",
4
4
  "description": "Token-first UI foundations with CSS, tokens, and React exports.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -33,6 +33,7 @@
33
33
  "./tokens/primitives.css": "./dist/tokens/css/core-primitives.tokens.css",
34
34
  "./tokens/brand-a.css": "./dist/tokens/css/themes-brands.tokens.brand-a.css",
35
35
  "./tokens/brand-b.css": "./dist/tokens/css/themes-brands.tokens.brand-b.css",
36
+ "./tokens/brand-c.css": "./dist/tokens/css/themes-brands.tokens.brand-c.css",
36
37
  "./tokens/color.css": "./dist/tokens/css/appearance-modes.tokens.mode-light.css",
37
38
  "./tokens/color-light.css": "./dist/tokens/css/appearance-modes.tokens.mode-light.css",
38
39
  "./tokens/color-dark.css": "./dist/tokens/css/appearance-modes.tokens.mode-dark.css",
@@ -1,43 +0,0 @@
1
- {
2
- "generated": "2026-04-19T14:37:39.153Z",
3
- "description": "Missing alias targets — these tokens are referenced but do not exist in any Figma export. Create them in Figma or add temporary mocks.",
4
- "missing": [
5
- {
6
- "ref": "Size/Spacing/50",
7
- "referencedBy": [
8
- "Form/Slider/Track Height",
9
- "Form/Slider/Track Height"
10
- ],
11
- "suggestedMock": {
12
- "type": "number",
13
- "value": 2,
14
- "unit": "px",
15
- "note": "Core: spacing 50 — add to Core (Primitives)"
16
- }
17
- },
18
- {
19
- "ref": "Color/Fill/Muted",
20
- "referencedBy": [
21
- "Form/Slider/Track Color",
22
- "Form/Slider/Track Color"
23
- ],
24
- "suggestedMock": {
25
- "type": "color",
26
- "value": "#e5e5e5",
27
- "note": "Semantic: muted fill — add to Appearance (Modes)"
28
- }
29
- },
30
- {
31
- "ref": "Color/Border/Focus",
32
- "referencedBy": [
33
- "Form/Slider/Focus Ring Color",
34
- "Form/Slider/Focus Ring Color"
35
- ],
36
- "suggestedMock": {
37
- "type": "color",
38
- "value": "#3b82f6",
39
- "note": "Semantic: focus border — add to Appearance (Modes)"
40
- }
41
- }
42
- ]
43
- }