@codecademy/gamut 68.6.1-alpha.f6b2ce.0 → 68.6.2-alpha.1fc7ca.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/dist/Modals/elements.d.ts +186 -1
- package/dist/Modals/elements.js +3 -3
- package/dist/{InternalFloatingCard/InternalFloatingCard.d.ts → PatternBackdrop/PatternBackdrop.d.ts} +8 -24
- package/dist/PatternBackdrop/PatternBackdrop.js +42 -0
- package/dist/Toast/Toast.js +4 -4
- package/package.json +8 -11
- package/agent-tools/.claude-plugin/marketplace.json +0 -16
- package/agent-tools/.claude-plugin/plugin.json +0 -7
- package/agent-tools/.cursor-plugin/plugin.json +0 -7
- package/agent-tools/DESIGN.Codecademy.md +0 -696
- package/agent-tools/DESIGN.LXStudio.md +0 -512
- package/agent-tools/DESIGN.Percipio.md +0 -513
- package/agent-tools/DESIGN.md +0 -1
- package/agent-tools/agents/.gitkeep +0 -0
- package/agent-tools/commands/gamut-review.md +0 -259
- package/agent-tools/guidelines/components/animations.md +0 -74
- package/agent-tools/guidelines/components/buttons.md +0 -95
- package/agent-tools/guidelines/components/card.md +0 -19
- package/agent-tools/guidelines/components/coachmark.md +0 -21
- package/agent-tools/guidelines/components/data-table.md +0 -79
- package/agent-tools/guidelines/components/forms.md +0 -106
- package/agent-tools/guidelines/components/loading-states.md +0 -17
- package/agent-tools/guidelines/components/menu.md +0 -58
- package/agent-tools/guidelines/components/overview.md +0 -124
- package/agent-tools/guidelines/components/radial-progress.md +0 -13
- package/agent-tools/guidelines/components/select.md +0 -23
- package/agent-tools/guidelines/components/tooltips.md +0 -22
- package/agent-tools/guidelines/components/video.md +0 -29
- package/agent-tools/guidelines/foundations/color.md +0 -168
- package/agent-tools/guidelines/foundations/modes.md +0 -69
- package/agent-tools/guidelines/foundations/spacing.md +0 -107
- package/agent-tools/guidelines/foundations/typography.md +0 -82
- package/agent-tools/guidelines/overview-icons.md +0 -19
- package/agent-tools/guidelines/overview-illustrations.md +0 -7
- package/agent-tools/guidelines/overview-patterns.md +0 -7
- package/agent-tools/guidelines/overview.md +0 -84
- package/agent-tools/guidelines/setup.md +0 -83
- package/agent-tools/rules/accessibility.mdc +0 -78
- package/agent-tools/skills/gamut-accessibility/SKILL.md +0 -224
- package/agent-tools/skills/gamut-color-mode/SKILL.md +0 -149
- package/agent-tools/skills/gamut-components/SKILL.md +0 -46
- package/agent-tools/skills/gamut-forms/SKILL.md +0 -101
- package/agent-tools/skills/gamut-style-utilities/SKILL.md +0 -111
- package/agent-tools/skills/gamut-system-props/SKILL.md +0 -225
- package/agent-tools/skills/gamut-testing/SKILL.md +0 -225
- package/agent-tools/skills/gamut-theming/SKILL.md +0 -63
- package/agent-tools/skills/gamut-typography/SKILL.md +0 -79
- package/bin/commands/plugin/install.mjs +0 -213
- package/bin/commands/plugin/list.mjs +0 -73
- package/bin/commands/plugin/remove.mjs +0 -108
- package/bin/commands/plugin/update.mjs +0 -59
- package/bin/gamut.mjs +0 -96
- package/bin/lib/claude.mjs +0 -52
- package/bin/lib/cursor.mjs +0 -40
- package/bin/lib/design.mjs +0 -71
- package/bin/lib/io.mjs +0 -14
- package/bin/lib/resolve-plugin-dir.mjs +0 -38
- package/bin/lib/run-command.mjs +0 -22
- package/dist/InternalFloatingCard/InternalFloatingCard.js +0 -98
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
---
|
|
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
|
-
argument-hint: [path]
|
|
4
|
-
allowed-tools: Read Glob Grep
|
|
5
|
-
---
|
|
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.
|
|
8
|
-
|
|
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
|
-
|
|
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. |
|
|
37
|
-
|
|
38
|
-
---
|
|
39
|
-
|
|
40
|
-
## Check 1 — Dependencies
|
|
41
|
-
|
|
42
|
-
Read `package.json` (and `package.json` in `$ARGUMENTS` if a path was given). Inspect `dependencies`, `devDependencies`, and `peerDependencies` combined.
|
|
43
|
-
|
|
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 |
|
|
49
|
-
|
|
50
|
-
---
|
|
51
|
-
|
|
52
|
-
## Check 2 — Setup
|
|
53
|
-
|
|
54
|
-
Search source files (`.ts`, `.tsx`, `.js`, `.jsx`) for these symbols. Skip `node_modules`, `dist`, `.next`, `build`, `.turbo`.
|
|
55
|
-
|
|
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` |
|
|
61
|
-
|
|
62
|
-
For each found symbol report the first file path where it appears.
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## Check 3 — Import patterns
|
|
67
|
-
|
|
68
|
-
Grep source files for any of these patterns. Each match is an error.
|
|
69
|
-
|
|
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 |
|
|
76
|
-
|
|
77
|
-
Report each violation as `file:line`.
|
|
78
|
-
|
|
79
|
-
---
|
|
80
|
-
|
|
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` |
|
|
164
|
-
| `#aee938` | `green-400` / `lightGreen` |
|
|
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` |
|
|
195
|
-
|
|
196
|
-
---
|
|
197
|
-
|
|
198
|
-
## Check 5 — Test setup
|
|
199
|
-
|
|
200
|
-
Grep test files (`/__tests__//*.{ts,tsx}`, `**/*.test.{ts,tsx}`, `**/*.spec.{ts,tsx}`) for these patterns. Skip `node_modules`, `dist`.
|
|
201
|
-
|
|
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 |
|
|
209
|
-
|
|
210
|
-
## Skill reference for remediation: `gamut-testing`
|
|
211
|
-
|
|
212
|
-
## Output format
|
|
213
|
-
|
|
214
|
-
```
|
|
215
|
-
Gamut Review — <absolute path>
|
|
216
|
-
══════════════════════════════════════════════════
|
|
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
|
-
|
|
222
|
-
Dependencies
|
|
223
|
-
✓ @codecademy/gamut <version>
|
|
224
|
-
⚠ @codecademy/gamut-styles not found — recommended
|
|
225
|
-
✗ @codecademy/variance not found — recommended
|
|
226
|
-
|
|
227
|
-
Setup
|
|
228
|
-
✓ GamutProvider found (src/App.tsx)
|
|
229
|
-
⚠ ColorMode not found — use ColorMode for light/dark theming [→ gamut-color-mode]
|
|
230
|
-
⚠ Background not found — use <Background> for semantic surfaces [→ gamut-color-mode]
|
|
231
|
-
|
|
232
|
-
Import patterns
|
|
233
|
-
✓ Deep dist imports none found
|
|
234
|
-
✗ Deep src imports 2 occurrences
|
|
235
|
-
src/Thing.tsx:7
|
|
236
|
-
src/Other.tsx:12
|
|
237
|
-
|
|
238
|
-
Hardcoded colors [→ gamut-color-mode]
|
|
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
|
|
242
|
-
|
|
243
|
-
Test setup [→ gamut-testing]
|
|
244
|
-
✓ @codecademy/gamut-tests used in 12 test files
|
|
245
|
-
✗ jest.mock(@codecademy/gamut) 2 occurrences — remove; prefer setupRtl (or harness + setupRtl)
|
|
246
|
-
src/components/Foo/__tests__/Foo.test.tsx:3
|
|
247
|
-
src/components/Bar/__tests__/Bar.test.tsx:5
|
|
248
|
-
⚠ direct component-test-setup import 1 occurrence — import from @codecademy/gamut-tests
|
|
249
|
-
src/components/Baz/__tests__/Baz.test.tsx:2
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
══════════════════════════════════════════════════
|
|
253
|
-
<N> error(s), <N> warning(s) found. (or "All checks passed." if none)
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
Icons: `✓` = pass, `⚠` = warning (recommended, not required), `✗` = error (required).
|
|
257
|
-
`[→ skill-name]` annotations indicate which Gamut skill has remediation guidance for that category.
|
|
258
|
-
|
|
259
|
-
After printing the report, offer one sentence of prioritized next-step advice based on what was found.
|
|
@@ -1,74 +0,0 @@
|
|
|
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,95 +0,0 @@
|
|
|
1
|
-
# Buttons
|
|
2
|
-
|
|
3
|
-
There is no generic `Button` export from `@codecademy/gamut`. Never import `Button` — use the specific variant that matches the design.
|
|
4
|
-
|
|
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
|
-
```
|
|
43
|
-
|
|
44
|
-
## Sizes
|
|
45
|
-
|
|
46
|
-
`small` | `normal` (default) | `large`
|
|
47
|
-
|
|
48
|
-
## Key props
|
|
49
|
-
|
|
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) |
|
|
59
|
-
|
|
60
|
-
## States
|
|
61
|
-
|
|
62
|
-
Hover, active, and disabled colors are handled by the component. Do not override state colors with `color` / `bg` props.
|
|
63
|
-
|
|
64
|
-
## Accessibility — `disabled` vs `aria-disabled`
|
|
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>
|
|
81
|
-
```
|
|
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`.
|
|
86
|
-
|
|
87
|
-
## Rules
|
|
88
|
-
|
|
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.
|
|
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).
|
|
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`.
|
|
@@ -1,19 +0,0 @@
|
|
|
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.
|
|
@@ -1,21 +0,0 @@
|
|
|
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
|
-
```
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
# DataTable & DataList sorting
|
|
2
|
-
|
|
3
|
-
`DataTable` and `DataList` do not sort data automatically. `sortable: true` on a column only renders sort UI. You must implement sorting via `query` and `onQueryChange`, and pass pre-sorted `rows`.
|
|
4
|
-
|
|
5
|
-
## How sorting works
|
|
6
|
-
|
|
7
|
-
1. `sortable: true` — enables sort toggle on the column header. Without `query` / `onQueryChange`, clicks do nothing.
|
|
8
|
-
2. `query` — `Query<Row>` holding current sort (and filter) state. `sort` maps column keys to `'asc' | 'desc'`.
|
|
9
|
-
3. `onQueryChange` — receives `QueryChangeEvent<Row>` when the user clicks a sortable header. Update `query` in your handler.
|
|
10
|
-
4. Sorted rows — sort the `rows` array yourself from `query.sort` before passing to the component.
|
|
11
|
-
|
|
12
|
-
## Required pattern
|
|
13
|
-
|
|
14
|
-
```tsx
|
|
15
|
-
import { useMemo, useReducer } from 'react';
|
|
16
|
-
import { DataTable } from '@codecademy/gamut';
|
|
17
|
-
import type { Query, QueryChangeEvent } from '@codecademy/gamut';
|
|
18
|
-
|
|
19
|
-
function queryReducer<Row>(
|
|
20
|
-
state: Query<Row>,
|
|
21
|
-
event: QueryChangeEvent<Row>
|
|
22
|
-
): Query<Row> {
|
|
23
|
-
switch (event.type) {
|
|
24
|
-
case 'sort': {
|
|
25
|
-
const { dimension, value } = event.payload;
|
|
26
|
-
if (value === 'none') {
|
|
27
|
-
const { [dimension]: _, ...rest } = state.sort ?? {};
|
|
28
|
-
return { ...state, sort: rest };
|
|
29
|
-
}
|
|
30
|
-
return { ...state, sort: { [dimension]: value } };
|
|
31
|
-
}
|
|
32
|
-
case 'filter': {
|
|
33
|
-
const { dimension, value } = event.payload;
|
|
34
|
-
return { ...state, filter: { ...state.filter, [dimension]: value } };
|
|
35
|
-
}
|
|
36
|
-
case 'reset':
|
|
37
|
-
return {};
|
|
38
|
-
default:
|
|
39
|
-
return state;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const [query, onQueryChange] = useReducer(queryReducer, {});
|
|
44
|
-
|
|
45
|
-
const sortedRows = useMemo(() => {
|
|
46
|
-
const sorted = [...rows];
|
|
47
|
-
const sortEntries = Object.entries(query.sort ?? {});
|
|
48
|
-
if (sortEntries.length > 0) {
|
|
49
|
-
const [key, direction] = sortEntries[0];
|
|
50
|
-
sorted.sort((a, b) => {
|
|
51
|
-
const aVal = String(a[key]).toLowerCase();
|
|
52
|
-
const bVal = String(b[key]).toLowerCase();
|
|
53
|
-
if (aVal < bVal) return direction === 'asc' ? -1 : 1;
|
|
54
|
-
if (aVal > bVal) return direction === 'asc' ? 1 : -1;
|
|
55
|
-
return 0;
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
return sorted;
|
|
59
|
-
}, [query.sort, rows]);
|
|
60
|
-
|
|
61
|
-
<DataTable
|
|
62
|
-
id="my-table"
|
|
63
|
-
idKey="id"
|
|
64
|
-
rows={sortedRows}
|
|
65
|
-
columns={columns}
|
|
66
|
-
query={query}
|
|
67
|
-
onQueryChange={onQueryChange}
|
|
68
|
-
/>;
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
## Rules
|
|
72
|
-
|
|
73
|
-
1. Never use `sortable: true` without `query` and `onQueryChange`.
|
|
74
|
-
2. Always sort rows client-side (or server-side before passing) from `query.sort`.
|
|
75
|
-
3. Handle `'sort'`, `'filter'`, and `'reset'` in the reducer even if you only use sorting.
|
|
76
|
-
4. One active sort column in standard usage — replace the previous sort entry when the user picks a new column.
|
|
77
|
-
5. Import `Query` and `QueryChangeEvent` from `@codecademy/gamut` for type safety.
|
|
78
|
-
|
|
79
|
-
Storybook: [Organisms / DataTable](https://gamut.codecademy.com/?path=/docs-organisms-datatable--docs)
|