@codecademy/gamut 68.6.1-alpha.e6c390.0 → 68.6.1-alpha.f6b2ce.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 (47) hide show
  1. package/agent-tools/.cursor-plugin/plugin.json +1 -1
  2. package/agent-tools/DESIGN.Codecademy.md +239 -191
  3. package/agent-tools/DESIGN.LXStudio.md +236 -184
  4. package/agent-tools/DESIGN.Percipio.md +232 -182
  5. package/agent-tools/DESIGN.md +1 -1
  6. package/agent-tools/commands/gamut-review.md +176 -87
  7. package/agent-tools/guidelines/components/animations.md +74 -0
  8. package/agent-tools/guidelines/components/buttons.md +74 -23
  9. package/agent-tools/guidelines/components/card.md +19 -0
  10. package/agent-tools/guidelines/components/coachmark.md +21 -0
  11. package/agent-tools/guidelines/components/data-table.md +79 -0
  12. package/agent-tools/guidelines/components/forms.md +106 -0
  13. package/agent-tools/guidelines/components/loading-states.md +17 -0
  14. package/agent-tools/guidelines/components/menu.md +58 -0
  15. package/agent-tools/guidelines/components/overview.md +97 -17
  16. package/agent-tools/guidelines/components/radial-progress.md +13 -0
  17. package/agent-tools/guidelines/components/select.md +23 -0
  18. package/agent-tools/guidelines/components/tooltips.md +22 -0
  19. package/agent-tools/guidelines/components/video.md +29 -0
  20. package/agent-tools/guidelines/foundations/color.md +140 -58
  21. package/agent-tools/guidelines/foundations/modes.md +39 -17
  22. package/agent-tools/guidelines/foundations/spacing.md +78 -37
  23. package/agent-tools/guidelines/foundations/typography.md +69 -37
  24. package/agent-tools/guidelines/overview-icons.md +19 -0
  25. package/agent-tools/guidelines/overview-illustrations.md +7 -0
  26. package/agent-tools/guidelines/overview-patterns.md +7 -0
  27. package/agent-tools/guidelines/overview.md +69 -23
  28. package/agent-tools/guidelines/setup.md +59 -18
  29. package/agent-tools/rules/accessibility.mdc +22 -13
  30. package/agent-tools/skills/gamut-accessibility/SKILL.md +97 -112
  31. package/agent-tools/skills/gamut-color-mode/SKILL.md +79 -29
  32. package/agent-tools/skills/gamut-components/SKILL.md +46 -0
  33. package/agent-tools/skills/gamut-forms/SKILL.md +101 -0
  34. package/agent-tools/skills/gamut-style-utilities/SKILL.md +111 -0
  35. package/agent-tools/skills/gamut-system-props/SKILL.md +70 -26
  36. package/agent-tools/skills/gamut-testing/SKILL.md +106 -62
  37. package/agent-tools/skills/gamut-theming/SKILL.md +34 -86
  38. package/agent-tools/skills/gamut-typography/SKILL.md +36 -80
  39. package/bin/commands/plugin/install.mjs +96 -56
  40. package/bin/commands/plugin/list.mjs +11 -43
  41. package/bin/commands/plugin/remove.mjs +30 -38
  42. package/bin/commands/plugin/update.mjs +15 -5
  43. package/bin/gamut.mjs +17 -13
  44. package/bin/lib/design.mjs +71 -0
  45. package/bin/lib/io.mjs +14 -0
  46. package/package.json +6 -6
  47. package/bin/lib/figma.mjs +0 -49
@@ -1,14 +1,39 @@
1
1
  ---
2
- description: Use this command when auditing existing code for Gamut usage — dependencies, GamutProvider, deep imports, hardcoded hex colors, and test patternsand you need a consolidated report with pointers to the matching Gamut skills.
2
+ description: Audit Gamut usage before shipping DESIGN.md, dependencies, GamutProvider, imports, hex colors, tests, and pre-ship design guardrails with a consolidated report and skill pointers.
3
3
  argument-hint: [path]
4
4
  allowed-tools: Read Glob Grep
5
5
  ---
6
6
 
7
- This is an audit of **existing code** at **`$ARGUMENTS`** (default: current working directory). Your job is to find violations and misuse, not to generate new code.
7
+ This is an audit of existing code at `$ARGUMENTS` (default: current working directory). Your job is to find violations and misuse, not to generate new code.
8
8
 
9
- Use `DESIGN.md` at the project root as the authoritative reference for the product's design intent, token names, and component patterns. This file is distributed as `DESIGN.Codecademy.md` or `DESIGN.Percipio.md` from the `@codecademy/gamut` agent-tools package and renamed to `DESIGN.md` by the consuming project. When a finding maps to a skill, note it in the report so the developer knows where to get remediation guidance.
9
+ When `DESIGN.md` is present at the audit root, use it as the authoritative reference for product design intent, token names, and component patterns. It is copied from `DESIGN.Codecademy.md`, `DESIGN.Percipio.md`, or `DESIGN.LXStudio.md` in `@codecademy/gamut` agent-tools (via `gamut plugin install --theme <name>`). When a finding maps to a skill, note it in the report so the developer knows where to get remediation guidance.
10
10
 
11
- Run all five checks below, then print a single consolidated report using the format at the end of this file.
11
+ Run Check 0 first, then Checks 1–6, then print a single consolidated report using the format at the end of this file.
12
+
13
+ Before reporting: Read [`guidelines/validation-checklist.md`](../guidelines/validation-checklist.md) and any [`guidelines/components/`](../guidelines/components/) guides relevant to findings (e.g. `data-table.md`, `menu.md`, `forms.md`).
14
+
15
+ ---
16
+
17
+ ## How to run
18
+
19
+ | Step | Guidance |
20
+ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
21
+ | Install plugin | Cursor: `gamut plugin install` (or `gamut plugin install cursor`) from `@codecademy/gamut`. Claude Code: `gamut plugin install claude`. Use `--theme core`, `percipio`, or `lxstudio` to copy `DESIGN.md` to the app repo root. |
22
+ | When | Before marking Gamut UI work final, before large PRs, when onboarding a codebase |
23
+ | Where | App repo root (directory containing `DESIGN.md`), or pass a subpath: `/gamut-review packages/web` |
24
+ | In editor | Slash command `/gamut-review` (Cursor and Claude Code after plugin install; Claude may need `/reload-plugins` once) |
25
+ | Severity | Errors (`✗`) are blocking — fix before ship. Warnings (`⚠`) are recommended follow-ups. |
26
+
27
+ ---
28
+
29
+ ## Check 0 — DESIGN.md present
30
+
31
+ Resolve the audit root: `$ARGUMENTS` if provided, otherwise the current working directory. Look for `DESIGN.md` at that root (not inside `node_modules` or package subfolders unless the audit path is explicitly that folder).
32
+
33
+ | Result | Action |
34
+ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
35
+ | Found | Report `✓ DESIGN.md present (<path>)`. Proceed with Checks 1–6 using this file for product/theme context. Infer product (Codecademy, Percipio, LX Studio) from `DESIGN.md` content for Check 6 theme-specific manual items. |
36
+ | Missing | Report `✗ DESIGN.md not found` as a blocking finding. Include remediation: from the repo root run `gamut plugin install cursor --theme core` (or `percipio`, `lxstudio`, `admin`, `platform`; also `claude`), or manually copy the matching `DESIGN.*.md` from `@codecademy/gamut` agent-tools and rename to `DESIGN.md`. Still run Checks 1–3 and 5. For Check 4, list hex violations with `palette:` / `semantic:` only where Appendix A/B apply without product YAML — prefix the Hardcoded colors section with `⚠ low confidence — no DESIGN.md` and do not assume Codecademy Core semantics; do not use Appendix B shortcuts as authoritative. |
12
37
 
13
38
  ---
14
39
 
@@ -16,11 +41,11 @@ Run all five checks below, then print a single consolidated report using the for
16
41
 
17
42
  Read `package.json` (and `package.json` in `$ARGUMENTS` if a path was given). Inspect `dependencies`, `devDependencies`, and `peerDependencies` combined.
18
43
 
19
- | Package | Expectation |
20
- |---|---|
21
- | `@codecademy/gamut` | **Required** — core component library |
22
- | `@codecademy/gamut-styles` | Recommended — design tokens and theme primitives |
23
- | `@codecademy/variance` | Recommended — style-prop system used by Gamut internals |
44
+ | Package | Expectation |
45
+ | -------------------------- | ------------------------------------------------------- |
46
+ | `@codecademy/gamut` | Required — core component library |
47
+ | `@codecademy/gamut-styles` | Recommended — design tokens and theme primitives |
48
+ | `@codecademy/variance` | Recommended — style-prop system used by Gamut internals |
24
49
 
25
50
  ---
26
51
 
@@ -28,11 +53,11 @@ Read `package.json` (and `package.json` in `$ARGUMENTS` if a path was given). In
28
53
 
29
54
  Search source files (`.ts`, `.tsx`, `.js`, `.jsx`) for these symbols. Skip `node_modules`, `dist`, `.next`, `build`, `.turbo`.
30
55
 
31
- | Symbol | Expectation |
32
- |---|---|
33
- | `GamutProvider` | **Required** — must appear at least once (app root wrapper) |
34
- | `ColorMode` | Recommended — enables semantic light/dark theming |
35
- | `Background` | Recommended — semantic surface color via `@codecademy/gamut-styles` |
56
+ | Symbol | Expectation |
57
+ | --------------- | ------------------------------------------------------------------- |
58
+ | `GamutProvider` | Required — must appear at least once (app root wrapper) |
59
+ | `ColorMode` | Recommended — enables semantic light/dark theming |
60
+ | `Background` | Recommended — semantic surface color via `@codecademy/gamut-styles` |
36
61
 
37
62
  For each found symbol report the first file path where it appears.
38
63
 
@@ -42,89 +67,147 @@ For each found symbol report the first file path where it appears.
42
67
 
43
68
  Grep source files for any of these patterns. Each match is an error.
44
69
 
45
- | Pattern | Reason |
46
- |---|---|
47
- | `@codecademy/gamut/dist/` | Deep dist import — bypasses public API and breaks on internal refactors |
48
- | `@codecademy/gamut/src/` | Deep src import — not part of the published package |
49
- | `@codecademy/gamut-styles/src/` | Deep src import — use the package root |
50
- | `@codecademy/variance/src/` | Deep src import — use the package root |
70
+ | Pattern | Reason |
71
+ | ------------------------------- | ----------------------------------------------------------------------- |
72
+ | `@codecademy/gamut/dist/` | Deep dist import — bypasses public API and breaks on internal refactors |
73
+ | `@codecademy/gamut/src/` | Deep src import — not part of the published package |
74
+ | `@codecademy/gamut-styles/src/` | Deep src import — use the package root |
75
+ | `@codecademy/variance/src/` | Deep src import — use the package root |
51
76
 
52
77
  Report each violation as `file:line`.
53
78
 
54
79
  ---
55
80
 
56
- ## Check 4 — Hardcoded colors
57
-
58
- Grep source files (`.ts`, `.tsx`, `.js`, `.jsx`, `.css`, `.scss`, `.less`) for inline hex color literals (`#RGB` or `#RRGGBB`). For each match, suggest the Gamut token name using this table (case-insensitive comparison):
59
-
60
- | Hex | Token |
61
- |---|---|
62
- | `#000000` | `black` |
63
- | `#ffffff` | `white` |
64
- | `#10162f` | `navy` / `navy-800` |
65
- | `#0a0d1c` | `navy-900` |
66
- | `#fff0e5` | `beige-100` |
67
- | `#f5fcff` | `blue-0` |
68
- | `#d3f2ff` | `blue-100` |
69
- | `#66c4ff` | `blue-300` |
70
- | `#3388ff` | `blue-400` |
71
- | `#1557ff` | `blue-500` |
72
- | `#1d2340` | `blue-800` |
73
- | `#f5ffe3` | `green-0` |
74
- | `#eafdc6` | `green-100` |
81
+ ## Check 4 — Hardcoded colors (semantic-first)
82
+
83
+ Rule: Inline hex literals in application UI code are violations. Remediation is not “replace hex with `navy-800`” — prefer semantic ColorMode tokens (`text`, `background`, `primary`, …) so light/dark and theme switches stay correct. Reserve raw palette tokens for colors that must stay fixed and for `bg` on `<Background>` from `@codecademy/gamut-styles` (section surfaces with content).
84
+
85
+ Align findings with project docs and Storybook:
86
+
87
+ - [@codecademy/gamut agent-tools `guidelines/foundations/color.md`](https://github.com/Codecademy/gamut/blob/main/packages/gamut/agent-tools/guidelines/foundations/color.md) — decision guide and semantic tables.
88
+ - [Foundations / ColorMode](https://gamut.codecademy.com/?path=/docs-foundations-colormode--page) — aliases per mode; `<Background>` behavior.
89
+ - [Meta / Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page) — semantic colors + `css` / `variant` / `states` from `gamut-styles`.
90
+ - Foundations / Theme stories (Core, Admin, Platform, Percipio, LX Studio) — verify hex ↔ semantic if the product is not Codecademy Core.
91
+
92
+ Theme context: If Check 0 passed, infer product/theme from root `DESIGN.md` and `GamutProvider` / app config. If Check 0 failed, follow the low-confidence rules in Check 0 — do not assume Codecademy Core semantics. If `DESIGN.md` exists but theme is still unclear, add a report note to confirm against the correct theme Storybook page.
93
+
94
+ Discovery: Grep source files (`.ts`, `.tsx`, `.js`, `.jsx`, `.css`, `.scss`, `.less`) for inline hex literals (`#RGB` or `#RRGGBB`). Comparison is case-insensitive. Skip `node_modules`, `dist`, `.next`, `build`, `.turbo` (same spirit as other checks).
95
+
96
+ ### Workflow (each hex match)
97
+
98
+ 1. Context — Inspect the surrounding line(s): CSS property (`color`, `background`, `border-color`, …), JSX prop (`color`, `bg`, `borderColor`, SVG fill), or asset. Note whether the subtree is a section with content (candidate for `<Background>` + palette `bg`) vs component chrome (prefer semantics).
99
+ 2. Identify palette — Normalize hex (case-insensitive); map to a Gamut palette name using Appendix A below. If missing from the appendix, match against `DESIGN.md` / `packages/gamut-styles` palette definitions.
100
+ 3. Recommend semantic first — Use Appendix B (Core light literals from `color.md`) plus role:
101
+ - Body / UI foreground → `text`; strong emphasis → `text-accent`.
102
+ - Page or card fill → `background` / `background-primary` / state surfaces (`background-success`, `background-warning`, `background-error`).
103
+ - CTAs, links, hyper accents → `primary` (+ `primary-hover` on hover); toggles / checkboxes → `interface`.
104
+ - Ghost / secondary buttons → `secondary`.
105
+ - Destructive → `danger` / `danger-hover`.
106
+ - Dividers / outlines → `border-primary` / `border-secondary` / `border-tertiary`.
107
+ - Inline feedback copy → `feedback-error` / `feedback-success` / `feedback-warning`.
108
+ - Disambiguation: `#FFD300` — warning copy → `feedback-warning`; yellow accent on top of primary-colored surfaces → `primary-inverse`.
109
+ - Same hex can map to multiple semantics (e.g. `#10162F` → `text` vs `border-primary` vs `secondary`): pick from property + component role.
110
+ 4. When palette-only is OK — `bg` prop on `<Background>` (`<Background bg="hyper">`, etc.) is the primary place for fixed surface palette colors on sections (see `color.md` decision guide + ColorMode docs). After replacing hex there, use a named palette token, not hex. Exceptions (flag with rationale): charts/data viz, third-party widgets, exported static illustrations — still prefer tokens over hex when feasible.
111
+
112
+ Severity: Hex on adaptive UI (random wrappers, `styled-components`, inline `style`) → error. Hex inside documented exceptions → warning with note.
113
+
114
+ Reporting: For each match outside token definition files:
115
+
116
+ `file:line 'HEX' → semantic: <token(s)> | palette: <token> | note: <theme/disambiguation>`
117
+
118
+ Use `semantic: (n/a)` only when no semantic applies (e.g. pure illustration); still give `palette: …`. If unmappable: `→ no Gamut token`.
119
+
120
+ Ignore hex inside design token definition files (e.g. `variables/colors.ts`, `_colors.scss`) — source of truth, not violations.
121
+
122
+ ### Appendix B — Core light: hex → suggested semantic (shortcut)
123
+
124
+ Use with step 3; verify for non-Core themes. Opacity variants in `color.md` are not listed here — keep using the named semantic token.
125
+
126
+ | Hex (normalized) | Typical semantic direction |
127
+ | ---------------- | ------------------------------------------------------------------------------------------------------------------------ |
128
+ | `#10162f` | `text`, `border-primary`, or `secondary` (by role) |
129
+ | `#0a0d1c` | `text-accent` |
130
+ | `#ffffff` | `background` (fills), `secondary` (inverse ghost on dark — rare in light-only grep context) |
131
+ | `#fff0e5` | `background-primary` |
132
+ | `#f5ffe3` | `background-success` |
133
+ | `#fffae5` | `background-warning` |
134
+ | `#fbf1f0` | `background-error` |
135
+ | `#3a10e5` | `primary`, `interface` (controls vs marketing CTA — prefer `primary` for links/buttons) |
136
+ | `#5533ff` | `primary-hover`, `interface-hover` |
137
+ | `#ffd300` | `feedback-warning` or `primary-inverse` (see disambiguation above) |
138
+ | `#cca900` | Often pairs with hover in dark mode; in light UI as literal hex → check palette appendix (`yellow-400`) then assign role |
139
+ | `#e91c11` | `danger` |
140
+ | `#be1809` | `danger-hover`, `feedback-error` |
141
+ | `#008a27` | `feedback-success` |
142
+
143
+ Hexes with no row above still get Appendix A palette id + role-based semantic guess (e.g. blue scale → often decorative or legacy marketing; prefer design review unless mapping clearly to `primary`).
144
+
145
+ ### Appendix A — Hex → palette token (identification only)
146
+
147
+ Case-insensitive. Use to label `palette:` in the report; do not stop at this step without Appendix B / role triage.
148
+
149
+ | Hex | Token |
150
+ | --------- | -------------------------- |
151
+ | `#000000` | `black` |
152
+ | `#ffffff` | `white` |
153
+ | `#10162f` | `navy` / `navy-800` |
154
+ | `#0a0d1c` | `navy-900` |
155
+ | `#fff0e5` | `beige-100` |
156
+ | `#f5fcff` | `blue-0` |
157
+ | `#d3f2ff` | `blue-100` |
158
+ | `#66c4ff` | `blue-300` |
159
+ | `#3388ff` | `blue-400` |
160
+ | `#1557ff` | `blue-500` |
161
+ | `#1d2340` | `blue-800` |
162
+ | `#f5ffe3` | `green-0` |
163
+ | `#eafdc6` | `green-100` |
75
164
  | `#aee938` | `green-400` / `lightGreen` |
76
- | `#008a27` | `green-700` |
77
- | `#151c07` | `green-900` |
78
- | `#fffae5` | `yellow-0` |
79
- | `#cca900` | `yellow-400` |
80
- | `#ffd300` | `yellow-500` / `yellow` |
81
- | `#211b00` | `yellow-900` |
82
- | `#fff5ff` | `pink-0` |
83
- | `#f966ff` | `pink-400` / `pink` |
84
- | `#fbf1f0` | `red-0` |
85
- | `#e85d7f` | `red-300` |
86
- | `#dc5879` | `red-400` / `paleRed` |
87
- | `#e91c11` | `red-500` / `red` |
88
- | `#be1809` | `red-600` |
89
- | `#280503` | `red-900` |
90
- | `#ffe8cc` | `orange-100` |
91
- | `#ff8c00` | `orange-500` / `orange` |
92
- | `#5533ff` | `hyper-400` |
93
- | `#3a10e5` | `hyper-500` / `hyper` |
94
- | `#f5f5f5` | `gray-100` |
95
- | `#eeeeee` | `gray-200` |
96
- | `#e0e0e0` | `gray-300` |
97
- | `#9e9e9e` | `gray-600` |
98
- | `#616161` | `gray-800` |
99
- | `#424242` | `gray-900` |
100
- | `#fffbf8` | `beige-0` |
101
- | `#8a7300` | `gold-800` / `gold` |
102
- | `#d14900` | `orange-800` |
103
- | `#ca00d1` | `pink-800` |
104
- | `#006d82` | `teal-500` / `teal` |
105
- | `#b3ccff` | `purple-300` / `purple` |
106
-
107
- Ignore hex values inside design token definition files themselves (e.g. `variables/colors.ts`, `_colors.scss`) — those are the source of truth, not violations.
108
-
109
- For each match outside token files report: `file:line 'HEX' → token` (or `→ no Gamut token` if unknown).
165
+ | `#008a27` | `green-700` |
166
+ | `#151c07` | `green-900` |
167
+ | `#fffae5` | `yellow-0` |
168
+ | `#cca900` | `yellow-400` |
169
+ | `#ffd300` | `yellow-500` / `yellow` |
170
+ | `#211b00` | `yellow-900` |
171
+ | `#fff5ff` | `pink-0` |
172
+ | `#f966ff` | `pink-400` / `pink` |
173
+ | `#fbf1f0` | `red-0` |
174
+ | `#e85d7f` | `red-300` |
175
+ | `#dc5879` | `red-400` / `paleRed` |
176
+ | `#e91c11` | `red-500` / `red` |
177
+ | `#be1809` | `red-600` |
178
+ | `#280503` | `red-900` |
179
+ | `#ffe8cc` | `orange-100` |
180
+ | `#ff8c00` | `orange-500` / `orange` |
181
+ | `#5533ff` | `hyper-400` |
182
+ | `#3a10e5` | `hyper-500` / `hyper` |
183
+ | `#f5f5f5` | `gray-100` |
184
+ | `#eeeeee` | `gray-200` |
185
+ | `#e0e0e0` | `gray-300` |
186
+ | `#9e9e9e` | `gray-600` |
187
+ | `#616161` | `gray-800` |
188
+ | `#424242` | `gray-900` |
189
+ | `#fffbf8` | `beige-0` |
190
+ | `#8a7300` | `gold-800` / `gold` |
191
+ | `#d14900` | `orange-800` |
192
+ | `#ca00d1` | `pink-800` |
193
+ | `#006d82` | `teal-500` / `teal` |
194
+ | `#b3ccff` | `purple-300` / `purple` |
110
195
 
111
196
  ---
112
197
 
113
198
  ## Check 5 — Test setup
114
199
 
115
- Grep test files (`**/__tests__/**/*.{ts,tsx}`, `**/*.test.{ts,tsx}`, `**/*.spec.{ts,tsx}`) for these patterns. Skip `node_modules`, `dist`.
200
+ Grep test files (`/__tests__//*.{ts,tsx}`, `**/*.test.{ts,tsx}`, `**/*.spec.{ts,tsx}`) for these patterns. Skip `node_modules`, `dist`.
116
201
 
117
- | Pattern | Verdict | Reason |
118
- |---|---|---|
119
- | `jest.mock\(.*@codecademy/gamut` | **Error** | Manual mocking bypasses theme context and produces false-positive tests; use `setupRtl` or `MockGamutProvider` instead |
120
- | `jest.mock\(.*@codecademy/gamut-styles` | **Error** | Same issue as above — mocking gamut-styles breaks token resolution |
121
- | `from '@codecademy/gamut-tests'` | Good — report count of files using it | Correct import for `setupRtl` and `MockGamutProvider` |
122
- | `from 'component-test-setup'` (without gamut-tests) | **Warning** | Should import `setupRtl` from `@codecademy/gamut-tests`, not directly from `component-test-setup` — the gamut-tests wrapper adds `MockGamutProvider` automatically |
123
- | `new GamutProvider` or `<GamutProvider` in test files | **Warning** | Tests should use `MockGamutProvider` (sets `useCache={false}`, `useGlobals={false}`), not `GamutProvider` directly |
202
+ | Pattern | Verdict | Reason |
203
+ | ----------------------------------------------------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
204
+ | `jest.mock\(.*@codecademy/gamut` | Error | Manual mocking bypasses theme context and produces false-positive tests; prefer `setupRtl` from `@codecademy/gamut-tests` (or a harness + `setupRtl`); use raw `MockGamutProvider` + `render` only for rare one-offs or Storybook mocks |
205
+ | `jest.mock\(.*@codecademy/gamut-styles` | Error | Same issue as above — mocking gamut-styles breaks token resolution |
206
+ | `from '@codecademy/gamut-tests'` | Good — report count of files using it | Correct import for `setupRtl` and `MockGamutProvider` |
207
+ | `from 'component-test-setup'` (without gamut-tests) | Warning | Should import `setupRtl` from `@codecademy/gamut-tests`, not directly from `component-test-setup` — the gamut-tests wrapper adds `MockGamutProvider` automatically |
208
+ | `new GamutProvider` or `<GamutProvider` in test files | Warning | Prefer `setupRtl`; use `MockGamutProvider` (sets `useCache={false}`, `useGlobals={false}`) in harnesses or stories, not `GamutProvider` directly |
124
209
 
125
- Skill reference for remediation: `gamut-testing`
126
-
127
- ---
210
+ ## Skill reference for remediation: `gamut-testing`
128
211
 
129
212
  ## Output format
130
213
 
@@ -132,6 +215,10 @@ Skill reference for remediation: `gamut-testing`
132
215
  Gamut Review — <absolute path>
133
216
  ══════════════════════════════════════════════════
134
217
 
218
+ DESIGN.md
219
+ ✓ present <path>/DESIGN.md
220
+ ✗ missing run: gamut plugin install cursor --theme <core|percipio|lxstudio|…> [blocking for color audit]
221
+
135
222
  Dependencies
136
223
  ✓ @codecademy/gamut <version>
137
224
  ⚠ @codecademy/gamut-styles not found — recommended
@@ -149,17 +236,19 @@ Import patterns
149
236
  src/Other.tsx:12
150
237
 
151
238
  Hardcoded colors [→ gamut-color-mode]
152
- src/Hero.tsx:14 '#1557FF' → blue-500
153
- ⚠ src/Nav.tsx:8 '#BADA55' → no Gamut token
239
+ src/Card.tsx:22 '#10162F' → semantic: text | palette: navy-800 | note: Core light body copy
240
+ ⚠ src/Hero.tsx:14 '#1557FF' → semantic: primary (if link/CTA) | palette: blue-500 | note: no exact semantic; confirm theme
241
+ ⚠ src/Nav.tsx:8 '#BADA55' → semantic: (n/a) | palette: — | note: no Gamut token
154
242
 
155
243
  Test setup [→ gamut-testing]
156
244
  ✓ @codecademy/gamut-tests used in 12 test files
157
- ✗ jest.mock(@codecademy/gamut) 2 occurrences — remove and use setupRtl instead
245
+ ✗ jest.mock(@codecademy/gamut) 2 occurrences — remove; prefer setupRtl (or harness + setupRtl)
158
246
  src/components/Foo/__tests__/Foo.test.tsx:3
159
247
  src/components/Bar/__tests__/Bar.test.tsx:5
160
248
  ⚠ direct component-test-setup import 1 occurrence — import from @codecademy/gamut-tests
161
249
  src/components/Baz/__tests__/Baz.test.tsx:2
162
250
 
251
+
163
252
  ══════════════════════════════════════════════════
164
253
  <N> error(s), <N> warning(s) found. (or "All checks passed." if none)
165
254
  ```
@@ -0,0 +1,74 @@
1
+ # Animations
2
+
3
+ `Animation` is a namespace of controlled containers from `@codecademy/gamut` — one primitive per pattern. Use these instead of raw CSS keyframes, inline `transition`, or third-party motion libraries when a Gamut primitive covers the case.
4
+
5
+ Storybook: [Atoms / Animation](https://gamut.codecademy.com/?path=/docs-atoms-animation--docs)
6
+
7
+ ## Cross-cutting rule: animations contain content, not click targets
8
+
9
+ Never put `onClick` on the animation container. The action element (`FillButton`, `StrokeButton`, etc.) wraps the animation; the primitive wraps the visual content that animates.
10
+
11
+ ```tsx
12
+ // Wrong
13
+ <Rotation onClick={handleClick}>
14
+ <MiniChevronDownIcon />
15
+ </Rotation>
16
+
17
+ // Right
18
+ <StrokeButton onClick={handleClick}>
19
+ <Rotation>
20
+ <MiniChevronDownIcon />
21
+ </Rotation>
22
+ </StrokeButton>
23
+ ```
24
+
25
+ ## Primitives
26
+
27
+ ### `Rotation`
28
+
29
+ Rotates children — common for expand/collapse chevrons.
30
+
31
+ Props: `rotated`, `degrees` (default `180`), `height`, `width`, `aria-hidden`, `children`
32
+
33
+ ```tsx
34
+ <StrokeButton onClick={toggleExpanded}>
35
+ <Rotation rotated={isExpanded}>
36
+ <MiniChevronDownIcon />
37
+ </Rotation>
38
+ </StrokeButton>
39
+ ```
40
+
41
+ ### `ExpandInCollapseOut`
42
+
43
+ Expand/collapse via Framer Motion. Required: wrap in `<AnimatePresence>` and conditionally render.
44
+
45
+ ```tsx
46
+ import { AnimatePresence } from 'framer-motion';
47
+
48
+ <AnimatePresence>
49
+ {isExpanded && <ExpandInCollapseOut>{/* content */}</ExpandInCollapseOut>}
50
+ </AnimatePresence>;
51
+ ```
52
+
53
+ ### `FadeInSlideOut`
54
+
55
+ Fade in / slide out via Framer Motion. Required: `<AnimatePresence>` + conditional mount — toggling CSS does not trigger the animation.
56
+
57
+ ```tsx
58
+ <AnimatePresence>
59
+ {isVisible && (
60
+ <FadeInSlideOut>
61
+ <Box border={1} p={8}>
62
+ {/* content */}
63
+ </Box>
64
+ </FadeInSlideOut>
65
+ )}
66
+ </AnimatePresence>
67
+ ```
68
+
69
+ ## Rules
70
+
71
+ 1. Prefer Gamut animation primitives over raw keyframes or ad-hoc motion libraries.
72
+ 2. Never put click handlers on animation containers.
73
+ 3. Enter/exit: `AnimatePresence` + conditional render — not CSS show/hide.
74
+ 4. Import `AnimatePresence` from `framer-motion` (peer dependency via Gamut).
@@ -1,15 +1,45 @@
1
1
  # Buttons
2
2
 
3
- ## Variants
3
+ There is no generic `Button` export from `@codecademy/gamut`. Never import `Button` — use the specific variant that matches the design.
4
4
 
5
- | Component | Use for | Background | Text |
6
- |---|---|---|---|
7
- | `FillButton` | Primary CTA, high-emphasis actions | `primary` | `white` |
8
- | `StrokeButton` | Secondary actions, outlined style | transparent | `secondary` |
9
- | `CTAButton` | High-visibility marketing promotions | `primary` | `white` |
10
- | `CTAButton` (inverse) | CTA on a colored surface | `primary-inverse` | `secondary` |
11
- | `TextButton` | Low-emphasis, inline text actions | transparent | `primary` |
12
- | `IconButton` | Compact icon-only actions | | |
5
+ Agent reference: which button component and which `variant` to use. Colors are wired inside each atom — consumers do not pass `color`, `bg`, hex, or semantic token names on stock buttons.
6
+
7
+ Related docs: [overview.md](../overview.md) (reading order) · [foundations/color.md](../foundations/color.md) and `gamut-color-mode` skill semantic tokens for custom styled controls only, not stock button atoms · [foundations/modes.md](../foundations/modes.md) — ColorMode / `<Background>` when placing buttons on colored surfaces
8
+
9
+ Storybook (UX source of truth):
10
+
11
+ - [Atoms / Buttons / Button](https://gamut.codecademy.com/?path=/docs-atoms-buttons-button--docs) variants, light/dark examples
12
+ - [FillButton](https://gamut.codecademy.com/?path=/docs-atoms-buttons-fillbutton--docs) · [StrokeButton](https://gamut.codecademy.com/?path=/docs-atoms-buttons-strokebutton--docs) · [TextButton](https://gamut.codecademy.com/?path=/docs-atoms-buttons-textbutton--docs) · [IconButton](https://gamut.codecademy.com/?path=/docs-atoms-buttons-iconbutton--docs) · [CTAButton](https://gamut.codecademy.com/?path=/docs-atoms-buttons-ctabutton--docs)
13
+ - [Meta / Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page) — semantic tokens for custom `css` / `variant` / `states`, not prebuilt atoms
14
+ - [UX Writing / Component guidelines / Buttons](https://gamut.codecademy.com/?path=/docs-ux-writing-component-guidelines-buttons--docs) — label copy
15
+
16
+ ## Component selection
17
+
18
+ | Component | Use for | Default `variant` |
19
+ | -------------- | --------------------------------------------- | ------------------------------------------------ |
20
+ | `FillButton` | Primary / high-emphasis actions | `primary` |
21
+ | `StrokeButton` | Secondary / outlined actions | `primary` (often pass `secondary` per Storybook) |
22
+ | `TextButton` | Low-emphasis, inline actions | `primary` |
23
+ | `IconButton` | Icon-only; requires `tip` and accessible name | `secondary` |
24
+ | `CTAButton` | Marketing / high-visibility CTA only | `primary` (only option) |
25
+
26
+ ## `variant` prop
27
+
28
+ Shared by `FillButton`, `StrokeButton`, `TextButton`, and `IconButton`. `CTAButton` only supports `primary`.
29
+
30
+ | `variant` | Typical use |
31
+ | ----------- | ------------------------------ |
32
+ | `primary` | Submit, main CTA |
33
+ | `secondary` | Close, cancel, low priority |
34
+ | `danger` | Destructive actions |
35
+ | `interface` | Controls styled like UI chrome |
36
+
37
+ ```tsx
38
+ <FillButton variant="primary">Submit</FillButton>
39
+ <StrokeButton variant="secondary">Cancel</StrokeButton>
40
+ <IconButton icon={SearchIcon} tip="Search" variant="secondary" />
41
+ <CTAButton>Try Pro for free</CTAButton>
42
+ ```
13
43
 
14
44
  ## Sizes
15
45
 
@@ -17,28 +47,49 @@
17
47
 
18
48
  ## Key props
19
49
 
20
- | Prop | Type | Effect |
21
- |---|---|---|
22
- | `size` | `"small" \| "normal" \| "large"` | Controls padding and font size |
23
- | `icon` | Icon component | Leading or trailing icon |
24
- | `iconPosition` | `"left" \| "right"` | Defaults to left |
25
- | `disabled` | boolean | Disabled state styling |
26
- | `href` | string | Renders as `<a>` tag |
50
+ | Prop | Type | Effect |
51
+ | -------------- | ----------------------------------------------------- | ------------------------------------------------ |
52
+ | `variant` | `"primary" \| "secondary" \| "danger" \| "interface"` | Color emphasis (see table above) |
53
+ | `size` | `"small" \| "normal" \| "large"` | Padding and font size |
54
+ | `icon` | Icon component | Leading or trailing icon (Fill, Stroke, Text) |
55
+ | `iconPosition` | `"left" \| "right"` | Defaults to left |
56
+ | `disabled` | boolean | Disabled state styling |
57
+ | `href` | string | Renders as `<a>` tag |
58
+ | `tip` | string | Required on `IconButton` (tooltip + hover label) |
27
59
 
28
60
  ## States
29
61
 
30
- `default` `hover` (`primary-hover` / `secondary-hover`) `active` `disabled` (`text-disabled` + `background-disabled`)
62
+ Hover, active, and disabled colors are handled by the component. Do not override state colors with `color` / `bg` props.
31
63
 
32
- ## Token cheatsheet
64
+ ## Accessibility — `disabled` vs `aria-disabled`
33
65
 
66
+ | Situation | Use | Why |
67
+ | --------------------------------------------------------------- | -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
68
+ | Button should not be activatable (default) | `disabled` prop | Renders native `disabled` on `<button>`; removed from tab order; correct for most forms and actions |
69
+ | Disabled button with a tooltip that must stay readable on focus | `aria-disabled` only — do not also pass `disabled` | Native `disabled` blocks keyboard focus, so the tooltip cannot be reached. Gamut disabled styles also match `[aria-disabled='true']`. See [ToolTip — With a disabled Button](https://gamut.codecademy.com/?path=/docs-molecules-tips-tooltip--docs) |
70
+
71
+ ```tsx
72
+ // Default — not interactive
73
+ <FillButton disabled>Submit</FillButton>
74
+
75
+ // Disabled but focusable (e.g. wrapped in ToolTip explaining why)
76
+ <ToolTip id="why-disabled" info="Complete the lesson first">
77
+ <FillButton aria-describedby="why-disabled" aria-disabled>
78
+ Submit
79
+ </FillButton>
80
+ </ToolTip>
34
81
  ```
35
- FillButton → bg: primary (#3A10E5 light / #FFD300 dark), color: white, hover: primary-hover
36
- StrokeButton bg: transparent, border: secondary (#10162F / #fff), hover: secondary-hover
37
- TextButton → bg: transparent, color: primary, hover: primary-hover
38
- ```
82
+
83
+ - `href` + `disabled`: `ButtonBase` (internal) drops `href` and renders a `<button disabled>` — link-style buttons cannot stay anchors while disabled.
84
+ - `IconButton`: provide an accessible name via `tip` (used as `aria-label` when `aria-label` is omitted). See ToolTip / IconButton Storybook pages.
85
+ - `ButtonBase` is not exported from `@codecademy/gamut` (only the `ButtonBaseElements` type is). Prefer stock atoms; custom button styling belongs in Gamut itself or via `css` / `variant` from `gamut-styles`, not by importing `ButtonBase`.
39
86
 
40
87
  ## Rules
41
88
 
42
- - Use `FillButton` for primary actions and `StrokeButton` for secondary do not use both at equal weight.
89
+ - Never set the `mode` prop on buttons they inherit color context from parent `ColorMode` / `<Background>` wrappers.
90
+ - Match variant to design intent: filled → `FillButton`, outlined → `StrokeButton`, text-only → `TextButton`, icon-only → `IconButton` (with `tip`).
91
+ - Use `FillButton` for primary actions and `StrokeButton` for secondary — do not use both at equal weight on the same screen.
43
92
  - Reserve `CTAButton` for marketing / high-visibility promotions; do not use it for standard UI actions.
93
+ - Avoid placing buttons in the wrong color-mode context (e.g. light-mode buttons on a navy band without `<Background>`). See [modes.md](../foundations/modes.md).
44
94
  - Every interactive `Card` wrapped in `<Anchor>` should have `isInteractive` — not a button inside.
95
+ - Do not set `color`, `bg`, or hex on stock button components. For custom styled controls, follow [color.md](../foundations/color.md) and `gamut-styles` utilities — do not import internal `ButtonBase`.
@@ -0,0 +1,19 @@
1
+ # Card
2
+
3
+ `Card` accepts specific `variant` values that map to internal color tokens via `polished`'s parser. Invalid variants (e.g. `"navy-on-white"` instead of `"white"`) cause a runtime crash in `parseToHsl()`.
4
+
5
+ Storybook: [Atoms / Card](https://gamut.codecademy.com/?path=/docs-atoms-card--docs)
6
+
7
+ ## Valid `Card` variants
8
+
9
+ `"default"`, `"white"`, `"yellow"`, `"hyper"`, `"navy"`
10
+
11
+ Never guess or invent compound variant names. Inspect TypeScript definitions in `@codecademy/gamut` if unsure.
12
+
13
+ ## Defaults and props
14
+
15
+ 1. Default `shadow` to `"none"` unless the design explicitly calls for elevation.
16
+ 2. Pass `isInteractive` when the card is wrapped in `<Anchor>` or acts as a clickable surface — enables hover shadow and `borderRadius: md`.
17
+ 3. Default `borderRadius` is `none` — override with the `borderRadius` prop when the design specifies rounding.
18
+
19
+ Confirm semantic surface colors against root `DESIGN.md` and the active theme Storybook page — variants are palette-backed, not arbitrary hex.
@@ -0,0 +1,21 @@
1
+ # Coachmark
2
+
3
+ Storybook: [Molecules / Coachmark](https://gamut.codecademy.com/?path=/docs-molecules-coachmark--docs)
4
+
5
+ ## Popovers: `outline` and `CheckerDense` by default
6
+
7
+ Pass `outline: true` and `pattern: CheckerDense` (from `@codecademy/gamut-patterns`) via `popoverProps` unless explicitly overridden.
8
+
9
+ ```tsx
10
+ import { Coachmark } from '@codecademy/gamut';
11
+ import { CheckerDense } from '@codecademy/gamut-patterns';
12
+
13
+ <Coachmark
14
+ popoverProps={{
15
+ outline: true,
16
+ pattern: CheckerDense,
17
+ }}
18
+ >
19
+ {/* ... */}
20
+ </Coachmark>;
21
+ ```