@codecademy/gamut 68.6.1-alpha.c211a2.0 → 68.6.1-alpha.d46fc5.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 (38) hide show
  1. package/agent-tools/.claude-plugin/marketplace.json +16 -0
  2. package/agent-tools/.claude-plugin/plugin.json +7 -0
  3. package/agent-tools/.cursor-plugin/plugin.json +7 -0
  4. package/agent-tools/DESIGN.Codecademy.md +643 -0
  5. package/agent-tools/DESIGN.LXStudio.md +444 -0
  6. package/agent-tools/DESIGN.Percipio.md +435 -0
  7. package/agent-tools/DESIGN.md +1 -0
  8. package/agent-tools/agents/.gitkeep +0 -0
  9. package/agent-tools/commands/gamut-review.md +246 -0
  10. package/agent-tools/guidelines/components/buttons.md +91 -0
  11. package/agent-tools/guidelines/components/overview.md +52 -0
  12. package/agent-tools/guidelines/foundations/color.md +172 -0
  13. package/agent-tools/guidelines/foundations/modes.md +47 -0
  14. package/agent-tools/guidelines/foundations/spacing.md +107 -0
  15. package/agent-tools/guidelines/foundations/typography.md +84 -0
  16. package/agent-tools/guidelines/overview.md +46 -0
  17. package/agent-tools/guidelines/setup.md +81 -0
  18. package/agent-tools/rules/accessibility.mdc +78 -0
  19. package/agent-tools/skills/gamut-accessibility/SKILL.md +214 -0
  20. package/agent-tools/skills/gamut-color-mode/SKILL.md +140 -0
  21. package/agent-tools/skills/gamut-forms/SKILL.md +84 -0
  22. package/agent-tools/skills/gamut-style-utilities/SKILL.md +107 -0
  23. package/agent-tools/skills/gamut-system-props/SKILL.md +203 -0
  24. package/agent-tools/skills/gamut-testing/SKILL.md +221 -0
  25. package/agent-tools/skills/gamut-theming/SKILL.md +48 -0
  26. package/agent-tools/skills/gamut-typography/SKILL.md +75 -0
  27. package/bin/commands/plugin/install.mjs +213 -0
  28. package/bin/commands/plugin/list.mjs +73 -0
  29. package/bin/commands/plugin/remove.mjs +108 -0
  30. package/bin/commands/plugin/update.mjs +59 -0
  31. package/bin/gamut.mjs +96 -0
  32. package/bin/lib/claude.mjs +52 -0
  33. package/bin/lib/cursor.mjs +40 -0
  34. package/bin/lib/design.mjs +71 -0
  35. package/bin/lib/io.mjs +14 -0
  36. package/bin/lib/resolve-plugin-dir.mjs +38 -0
  37. package/bin/lib/run-command.mjs +22 -0
  38. package/package.json +11 -8
@@ -0,0 +1,246 @@
1
+ ---
2
+ description: Use this command when auditing existing code for Gamut usage — dependencies, GamutProvider, deep imports, hardcoded hex colors, and test patterns — and you need a consolidated report with pointers to the matching Gamut skills.
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–5, then print a single consolidated report using the format at the end of this file.
12
+
13
+ ---
14
+
15
+ ## Check 0 — DESIGN.md present
16
+
17
+ 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).
18
+
19
+ | Result | Action |
20
+ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
21
+ | **Found** | Report `✓ DESIGN.md present (<path>)`. Proceed with Checks 1–5 using this file for product/theme context. |
22
+ | **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. |
23
+
24
+ ---
25
+
26
+ ## Check 1 — Dependencies
27
+
28
+ Read `package.json` (and `package.json` in `$ARGUMENTS` if a path was given). Inspect `dependencies`, `devDependencies`, and `peerDependencies` combined.
29
+
30
+ | Package | Expectation |
31
+ | -------------------------- | ------------------------------------------------------- |
32
+ | `@codecademy/gamut` | **Required** — core component library |
33
+ | `@codecademy/gamut-styles` | Recommended — design tokens and theme primitives |
34
+ | `@codecademy/variance` | Recommended — style-prop system used by Gamut internals |
35
+
36
+ ---
37
+
38
+ ## Check 2 — Setup
39
+
40
+ Search source files (`.ts`, `.tsx`, `.js`, `.jsx`) for these symbols. Skip `node_modules`, `dist`, `.next`, `build`, `.turbo`.
41
+
42
+ | Symbol | Expectation |
43
+ | --------------- | ------------------------------------------------------------------- |
44
+ | `GamutProvider` | **Required** — must appear at least once (app root wrapper) |
45
+ | `ColorMode` | Recommended — enables semantic light/dark theming |
46
+ | `Background` | Recommended — semantic surface color via `@codecademy/gamut-styles` |
47
+
48
+ For each found symbol report the first file path where it appears.
49
+
50
+ ---
51
+
52
+ ## Check 3 — Import patterns
53
+
54
+ Grep source files for any of these patterns. Each match is an error.
55
+
56
+ | Pattern | Reason |
57
+ | ------------------------------- | ----------------------------------------------------------------------- |
58
+ | `@codecademy/gamut/dist/` | Deep dist import — bypasses public API and breaks on internal refactors |
59
+ | `@codecademy/gamut/src/` | Deep src import — not part of the published package |
60
+ | `@codecademy/gamut-styles/src/` | Deep src import — use the package root |
61
+ | `@codecademy/variance/src/` | Deep src import — use the package root |
62
+
63
+ Report each violation as `file:line`.
64
+
65
+ ---
66
+
67
+ ## Check 4 — Hardcoded colors (semantic-first)
68
+
69
+ **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).
70
+
71
+ Align findings with project docs and Storybook:
72
+
73
+ - [@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.
74
+ - [Foundations / ColorMode](https://gamut.codecademy.com/?path=/docs-foundations-colormode--page) — aliases per mode; `<Background>` behavior.
75
+ - [Meta / Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page) — semantic colors + `css` / `variant` / `states` from `gamut-styles`.
76
+ - Foundations / Theme stories (Core, Admin, Platform, Percipio, LX Studio) — verify hex ↔ semantic if the product is not Codecademy Core.
77
+
78
+ **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.
79
+
80
+ **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).
81
+
82
+ ### Workflow (each hex match)
83
+
84
+ 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).
85
+ 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.
86
+ 3. **Recommend semantic first** — Use **Appendix B** (Core **light** literals from `color.md`) plus role:
87
+ - Body / UI foreground → `text`; strong emphasis → `text-accent`.
88
+ - Page or card fill → `background` / `background-primary` / state surfaces (`background-success`, `background-warning`, `background-error`).
89
+ - CTAs, links, hyper accents → `primary` (+ `primary-hover` on hover); toggles / checkboxes → `interface`.
90
+ - Ghost / secondary buttons → `secondary`.
91
+ - Destructive → `danger` / `danger-hover`.
92
+ - Dividers / outlines → `border-primary` / `border-secondary` / `border-tertiary`.
93
+ - Inline feedback copy → `feedback-error` / `feedback-success` / `feedback-warning`.
94
+ - **Disambiguation:** `#FFD300` — warning copy → `feedback-warning`; yellow accent on top of primary-colored surfaces → `primary-inverse`.
95
+ - Same hex can map to multiple semantics (e.g. `#10162F` → `text` vs `border-primary` vs `secondary`): pick from **property + component role**.
96
+ 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.
97
+
98
+ **Severity:** Hex on adaptive UI (random wrappers, `styled-components`, inline `style`) → **error**. Hex inside documented exceptions → **warning** with note.
99
+
100
+ **Reporting:** For each match outside token definition files:
101
+
102
+ `file:line 'HEX' → semantic: <token(s)> | palette: <token> | note: <theme/disambiguation>`
103
+
104
+ Use `semantic: (n/a)` only when no semantic applies (e.g. pure illustration); still give `palette: …`. If unmappable: `→ no Gamut token`.
105
+
106
+ Ignore hex inside design token definition files (e.g. `variables/colors.ts`, `_colors.scss`) — source of truth, not violations.
107
+
108
+ ### Appendix B — Core light: hex → suggested semantic (shortcut)
109
+
110
+ Use with step 3; verify for non-Core themes. Opacity variants in `color.md` are not listed here — keep using the named semantic token.
111
+
112
+ | Hex (normalized) | Typical semantic direction |
113
+ | ---------------- | ------------------------------------------------------------------------------------------------------------------------ |
114
+ | `#10162f` | `text`, `border-primary`, or `secondary` (by role) |
115
+ | `#0a0d1c` | `text-accent` |
116
+ | `#ffffff` | `background` (fills), `secondary` (inverse ghost on dark — rare in light-only grep context) |
117
+ | `#fff0e5` | `background-primary` |
118
+ | `#f5ffe3` | `background-success` |
119
+ | `#fffae5` | `background-warning` |
120
+ | `#fbf1f0` | `background-error` |
121
+ | `#3a10e5` | `primary`, `interface` (controls vs marketing CTA — prefer `primary` for links/buttons) |
122
+ | `#5533ff` | `primary-hover`, `interface-hover` |
123
+ | `#ffd300` | `feedback-warning` or `primary-inverse` (see disambiguation above) |
124
+ | `#cca900` | Often pairs with hover in dark mode; in light UI as literal hex → check palette appendix (`yellow-400`) then assign role |
125
+ | `#e91c11` | `danger` |
126
+ | `#be1809` | `danger-hover`, `feedback-error` |
127
+ | `#008a27` | `feedback-success` |
128
+
129
+ 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`).
130
+
131
+ ### Appendix A — Hex → palette token (identification only)
132
+
133
+ Case-insensitive. Use to label `palette:` in the report; **do not** stop at this step without Appendix B / role triage.
134
+
135
+ | Hex | Token |
136
+ | --------- | -------------------------- |
137
+ | `#000000` | `black` |
138
+ | `#ffffff` | `white` |
139
+ | `#10162f` | `navy` / `navy-800` |
140
+ | `#0a0d1c` | `navy-900` |
141
+ | `#fff0e5` | `beige-100` |
142
+ | `#f5fcff` | `blue-0` |
143
+ | `#d3f2ff` | `blue-100` |
144
+ | `#66c4ff` | `blue-300` |
145
+ | `#3388ff` | `blue-400` |
146
+ | `#1557ff` | `blue-500` |
147
+ | `#1d2340` | `blue-800` |
148
+ | `#f5ffe3` | `green-0` |
149
+ | `#eafdc6` | `green-100` |
150
+ | `#aee938` | `green-400` / `lightGreen` |
151
+ | `#008a27` | `green-700` |
152
+ | `#151c07` | `green-900` |
153
+ | `#fffae5` | `yellow-0` |
154
+ | `#cca900` | `yellow-400` |
155
+ | `#ffd300` | `yellow-500` / `yellow` |
156
+ | `#211b00` | `yellow-900` |
157
+ | `#fff5ff` | `pink-0` |
158
+ | `#f966ff` | `pink-400` / `pink` |
159
+ | `#fbf1f0` | `red-0` |
160
+ | `#e85d7f` | `red-300` |
161
+ | `#dc5879` | `red-400` / `paleRed` |
162
+ | `#e91c11` | `red-500` / `red` |
163
+ | `#be1809` | `red-600` |
164
+ | `#280503` | `red-900` |
165
+ | `#ffe8cc` | `orange-100` |
166
+ | `#ff8c00` | `orange-500` / `orange` |
167
+ | `#5533ff` | `hyper-400` |
168
+ | `#3a10e5` | `hyper-500` / `hyper` |
169
+ | `#f5f5f5` | `gray-100` |
170
+ | `#eeeeee` | `gray-200` |
171
+ | `#e0e0e0` | `gray-300` |
172
+ | `#9e9e9e` | `gray-600` |
173
+ | `#616161` | `gray-800` |
174
+ | `#424242` | `gray-900` |
175
+ | `#fffbf8` | `beige-0` |
176
+ | `#8a7300` | `gold-800` / `gold` |
177
+ | `#d14900` | `orange-800` |
178
+ | `#ca00d1` | `pink-800` |
179
+ | `#006d82` | `teal-500` / `teal` |
180
+ | `#b3ccff` | `purple-300` / `purple` |
181
+
182
+ ---
183
+
184
+ ## Check 5 — Test setup
185
+
186
+ Grep test files (`**/__tests__/**/*.{ts,tsx}`, `**/*.test.{ts,tsx}`, `**/*.spec.{ts,tsx}`) for these patterns. Skip `node_modules`, `dist`.
187
+
188
+ | Pattern | Verdict | Reason |
189
+ | ----------------------------------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
190
+ | `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 |
191
+ | `jest.mock\(.*@codecademy/gamut-styles` | **Error** | Same issue as above — mocking gamut-styles breaks token resolution |
192
+ | `from '@codecademy/gamut-tests'` | Good — report count of files using it | Correct import for `setupRtl` and `MockGamutProvider` |
193
+ | `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 |
194
+ | `new GamutProvider` or `<GamutProvider` in test files | **Warning** | Prefer **`setupRtl`**; use **`MockGamutProvider`** (sets `useCache={false}`, `useGlobals={false}`) in harnesses or stories, not **`GamutProvider`** directly |
195
+
196
+ Skill reference for remediation: `gamut-testing`
197
+
198
+ ---
199
+
200
+ ## Output format
201
+
202
+ ```
203
+ Gamut Review — <absolute path>
204
+ ══════════════════════════════════════════════════
205
+
206
+ DESIGN.md
207
+ ✓ present <path>/DESIGN.md
208
+ ✗ missing run: gamut plugin install cursor --theme <core|percipio|lxstudio|…> [blocking for color audit]
209
+
210
+ Dependencies
211
+ ✓ @codecademy/gamut <version>
212
+ ⚠ @codecademy/gamut-styles not found — recommended
213
+ ✗ @codecademy/variance not found — recommended
214
+
215
+ Setup
216
+ ✓ GamutProvider found (src/App.tsx)
217
+ ⚠ ColorMode not found — use ColorMode for light/dark theming [→ gamut-color-mode]
218
+ ⚠ Background not found — use <Background> for semantic surfaces [→ gamut-color-mode]
219
+
220
+ Import patterns
221
+ ✓ Deep dist imports none found
222
+ ✗ Deep src imports 2 occurrences
223
+ src/Thing.tsx:7
224
+ src/Other.tsx:12
225
+
226
+ Hardcoded colors [→ gamut-color-mode]
227
+ ✗ src/Card.tsx:22 '#10162F' → semantic: text | palette: navy-800 | note: Core light body copy
228
+ ⚠ src/Hero.tsx:14 '#1557FF' → semantic: primary (if link/CTA) | palette: blue-500 | note: no exact semantic; confirm theme
229
+ ⚠ src/Nav.tsx:8 '#BADA55' → semantic: (n/a) | palette: — | note: no Gamut token
230
+
231
+ Test setup [→ gamut-testing]
232
+ ✓ @codecademy/gamut-tests used in 12 test files
233
+ ✗ jest.mock(@codecademy/gamut) 2 occurrences — remove; prefer setupRtl (or harness + setupRtl)
234
+ src/components/Foo/__tests__/Foo.test.tsx:3
235
+ src/components/Bar/__tests__/Bar.test.tsx:5
236
+ ⚠ direct component-test-setup import 1 occurrence — import from @codecademy/gamut-tests
237
+ src/components/Baz/__tests__/Baz.test.tsx:2
238
+
239
+ ══════════════════════════════════════════════════
240
+ <N> error(s), <N> warning(s) found. (or "All checks passed." if none)
241
+ ```
242
+
243
+ Icons: `✓` = pass, `⚠` = warning (recommended, not required), `✗` = error (required).
244
+ `[→ skill-name]` annotations indicate which Gamut skill has remediation guidance for that category.
245
+
246
+ After printing the report, offer one sentence of prioritized next-step advice based on what was found.
@@ -0,0 +1,91 @@
1
+ # Buttons
2
+
3
+ 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.
4
+
5
+ **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
6
+
7
+ **Storybook (UX source of truth):**
8
+
9
+ - [Atoms / Buttons / Button](https://gamut.codecademy.com/?path=/docs-atoms-buttons-button--docs) — variants, light/dark examples
10
+ - [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)
11
+ - [Meta / Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page) — semantic tokens for custom `css` / `variant` / `states`, not prebuilt atoms
12
+ - [UX Writing / Component guidelines / Buttons](https://gamut.codecademy.com/?path=/docs-ux-writing-component-guidelines-buttons--docs) — label copy
13
+
14
+ ## Component selection
15
+
16
+ | Component | Use for | Default `variant` |
17
+ | -------------- | --------------------------------------------- | ------------------------------------------------ |
18
+ | `FillButton` | Primary / high-emphasis actions | `primary` |
19
+ | `StrokeButton` | Secondary / outlined actions | `primary` (often pass `secondary` per Storybook) |
20
+ | `TextButton` | Low-emphasis, inline actions | `primary` |
21
+ | `IconButton` | Icon-only; requires `tip` and accessible name | `secondary` |
22
+ | `CTAButton` | Marketing / high-visibility CTA only | `primary` (only option) |
23
+
24
+ ## `variant` prop
25
+
26
+ Shared by `FillButton`, `StrokeButton`, `TextButton`, and `IconButton`. `CTAButton` only supports `primary`.
27
+
28
+ | `variant` | Typical use |
29
+ | ----------- | ------------------------------ |
30
+ | `primary` | Submit, main CTA |
31
+ | `secondary` | Close, cancel, low priority |
32
+ | `danger` | Destructive actions |
33
+ | `interface` | Controls styled like UI chrome |
34
+
35
+ ```tsx
36
+ <FillButton variant="primary">Submit</FillButton>
37
+ <StrokeButton variant="secondary">Cancel</StrokeButton>
38
+ <IconButton icon={SearchIcon} tip="Search" variant="secondary" />
39
+ <CTAButton>Try Pro for free</CTAButton>
40
+ ```
41
+
42
+ ## Sizes
43
+
44
+ `small` | `normal` (default) | `large`
45
+
46
+ ## Key props
47
+
48
+ | Prop | Type | Effect |
49
+ | -------------- | ----------------------------------------------------- | ------------------------------------------------ |
50
+ | `variant` | `"primary" \| "secondary" \| "danger" \| "interface"` | Color emphasis (see table above) |
51
+ | `size` | `"small" \| "normal" \| "large"` | Padding and font size |
52
+ | `icon` | Icon component | Leading or trailing icon (Fill, Stroke, Text) |
53
+ | `iconPosition` | `"left" \| "right"` | Defaults to left |
54
+ | `disabled` | boolean | Disabled state styling |
55
+ | `href` | string | Renders as `<a>` tag |
56
+ | `tip` | string | Required on `IconButton` (tooltip + hover label) |
57
+
58
+ ## States
59
+
60
+ Hover, active, and disabled colors are handled by the component. Do not override state colors with `color` / `bg` props.
61
+
62
+ ## Accessibility — `disabled` vs `aria-disabled`
63
+
64
+ | Situation | Use | Why |
65
+ | ------------------------------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
66
+ | Button should not be activatable (default) | `disabled` prop | Renders native `disabled` on `<button>`; removed from tab order; correct for most forms and actions |
67
+ | 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) |
68
+
69
+ ```tsx
70
+ // Default — not interactive
71
+ <FillButton disabled>Submit</FillButton>
72
+
73
+ // Disabled but focusable (e.g. wrapped in ToolTip explaining why)
74
+ <ToolTip id="why-disabled" info="Complete the lesson first">
75
+ <FillButton aria-describedby="why-disabled" aria-disabled>
76
+ Submit
77
+ </FillButton>
78
+ </ToolTip>
79
+ ```
80
+
81
+ - **`href` + `disabled`:** `ButtonBase` (internal) drops `href` and renders a `<button disabled>` — link-style buttons cannot stay anchors while disabled.
82
+ - **`IconButton`:** provide an accessible name via `tip` (used as `aria-label` when `aria-label` is omitted). See ToolTip / IconButton Storybook pages.
83
+ - **`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`.
84
+
85
+ ## Rules
86
+
87
+ - Use `FillButton` for primary actions and `StrokeButton` for secondary — do not use both at equal weight on the same screen.
88
+ - Reserve `CTAButton` for marketing / high-visibility promotions; do not use it for standard UI actions.
89
+ - 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).
90
+ - Every interactive `Card` wrapped in `<Anchor>` should have `isInteractive` — not a button inside.
91
+ - 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,52 @@
1
+ # Components
2
+
3
+ 52 components have Figma ↔ code mappings via Figma Code Connect (`packages/code-connect/`). Live code snippets appear in Figma's inspect panel when you select a component.
4
+
5
+ ## Atoms — foundational, single-purpose
6
+
7
+ Badge, Button (FillButton, StrokeButton, CTAButton, TextButton, IconButton), ButtonBase, Card, Checkbox, CodeBlock, ColorMode, Drawer, FlexBox, FormGroup, GridBox, HiddenText, Icon, Input, Label, Loader, Radio, Select, Spinner, Tag, TextArea, Toggle, Tooltip
8
+
9
+ ## Molecules — composed of atoms
10
+
11
+ Alert, Anchor, Breadcrumbs, Coachmark, Disclosure, GridForm, Markdown, Menu, Modal, Pagination, Popover, ProgressBar, Table, Tabs, Toast, Toaster, Video
12
+
13
+ ## Organisms — page-level compositions
14
+
15
+ ContentContainer, GridContainer, Layout, LayoutGrid
16
+
17
+ ## Key patterns
18
+
19
+ ### Buttons
20
+
21
+ See [buttons.md](buttons.md) for full reference. Use `FillButton` for primary actions, `StrokeButton` for secondary.
22
+
23
+ ### Forms and accessibility
24
+
25
+ **`FormGroup`**, **`GridForm`**, **`ConnectedForm`**, tips, dialogs, composite widgets: **[`skills/gamut-forms/SKILL.md`](../../skills/gamut-forms/SKILL.md)** (forms) · **[`skills/gamut-accessibility/SKILL.md`](../../skills/gamut-accessibility/SKILL.md)** (overlays, composites, checklists) · Storybook [Meta / Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page).
26
+
27
+ ### Cards
28
+
29
+ - **Background variants**: `default` (ColorMode-responsive), `white`, `yellow`, `beige`, `navy`, `hyper`
30
+ - **Shadow variants**: `none` (default), `outline`, `patternLeft`, `patternRight`
31
+ - Add `isInteractive` when wrapping in `<Anchor>` — enables hover shadow + `borderRadius: md`
32
+ - Default `borderRadius` is `none`; override with `borderRadius` prop
33
+
34
+ ### Color-aware components
35
+
36
+ - `<ColorMode mode="light|dark|system">` — scopes a subtree to an explicit color mode
37
+ - `<Background bg="<color>">` — applies background color + auto-switches inner color mode for contrast
38
+
39
+ ### Alerts
40
+
41
+ | Variant | Tokens |
42
+ | ------- | ----------------------------------------- |
43
+ | Error | `feedback-error` + `background-error` |
44
+ | Success | `feedback-success` + `background-success` |
45
+ | Warning | `feedback-warning` + `background-warning` |
46
+
47
+ ## Global tokens
48
+
49
+ | Token | Value | Use |
50
+ | -------------- | ----------------------- | ------------------------------ |
51
+ | `headerHeight` | 64px (base), 80px (md+) | Global page header height |
52
+ | `headerZ` | 15 | Z-index for global page header |
@@ -0,0 +1,172 @@
1
+ # Color
2
+
3
+ Use **semantic aliases** for UI that should respond to **color mode** (light/dark) and **theme** (Core, Admin, Platform, Percipio, LX Studio). The **same semantic token names** (`text`, `primary`, `background`, …) exist across themes; **resolved palette values and hex differ** by `GamutProvider` theme and active ColorMode. Never assume Codecademy Core hex when advising another product.
4
+
5
+ Prefer **`css` / `variant` / `states`** from `@codecademy/gamut-styles` with semantic names (see Storybook [Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page)).
6
+
7
+ **Related:** [`setup.md`](../setup.md) (which theme to import) · [`gamut-theming` skill](../../skills/gamut-theming/SKILL.md) · [`gamut-style-utilities` skill](../../skills/gamut-style-utilities/SKILL.md) · [`gamut-color-mode` skill](../../skills/gamut-color-mode/SKILL.md) · [`modes.md`](modes.md) (`<ColorMode>`, `<Background>`)
8
+
9
+ Percipio, LX Studio, Admin, and Platform override subsets of semantic mappings while keeping the shared alias API — see theme sources below before hardcoding palette names or hex.
10
+
11
+ ## Semantic aliases (theme-stable names)
12
+
13
+ These tokens describe **roles**. Actual colors come from the active theme + ColorMode.
14
+
15
+ ### Text
16
+
17
+ | Token | Use for | Notes |
18
+ | ---------------- | --------------------------- | -------------------------- |
19
+ | `text` | Default body and UI text | |
20
+ | `text-accent` | Stronger emphasis text | |
21
+ | `text-secondary` | Supporting / secondary copy | Often opacity on base text |
22
+ | `text-disabled` | Disabled state labels | |
23
+
24
+ ### Background
25
+
26
+ | Token | Use for | Notes |
27
+ | --------------------- | --------------------------------- | ------------------------- |
28
+ | `background` | Default page/component background | |
29
+ | `background-primary` | Slightly elevated surfaces | |
30
+ | `background-contrast` | Maximum contrast surface | |
31
+ | `background-selected` | Selected row / item | Often low-opacity overlay |
32
+ | `background-hover` | Hover state overlay | |
33
+ | `background-disabled` | Disabled surface | |
34
+ | `background-success` | Success state container | |
35
+ | `background-warning` | Warning state container | |
36
+ | `background-error` | Error state container | |
37
+
38
+ ### Interactive
39
+
40
+ | Token | Use for | Notes |
41
+ | ----------------- | ----------------------------------------- | ---------------------------- |
42
+ | `primary` | Primary CTA, links, focus accents | Pairs with `primary-hover` |
43
+ | `primary-hover` | Hover on primary interactive | |
44
+ | `primary-inverse` | Accent on top of primary-colored surfaces | |
45
+ | `secondary` | Secondary CTA, ghost buttons | Pairs with `secondary-hover` |
46
+ | `secondary-hover` | Hover on secondary interactive | |
47
+ | `interface` | Checkboxes, toggles, sliders | Pairs with `interface-hover` |
48
+ | `interface-hover` | Hover on interface elements | |
49
+ | `danger` | Destructive actions, error emphasis | Pairs with `danger-hover` |
50
+ | `danger-hover` | Hover on danger interactive | |
51
+
52
+ ### Border
53
+
54
+ | Token | Use for | Notes |
55
+ | ------------------ | -------------------------- | ----- |
56
+ | `border-primary` | Strong borders, dividers | |
57
+ | `border-secondary` | Medium-weight borders | |
58
+ | `border-tertiary` | Subtle borders, separators | |
59
+ | `border-disabled` | Disabled input borders | |
60
+
61
+ ### Feedback
62
+
63
+ | Token | Use for | Notes |
64
+ | ------------------ | -------------------------- | ----- |
65
+ | `feedback-error` | Error messages, validation | |
66
+ | `feedback-success` | Success messages | |
67
+ | `feedback-warning` | Warning messages | |
68
+
69
+ ## Where resolved colors are documented
70
+
71
+ Use these instead of memorizing hex:
72
+
73
+ - **Storybook [ColorMode](https://gamut.codecademy.com/?path=/docs-foundations-colormode--page)** — how aliases map per light/dark for reference layouts.
74
+ - **Storybook Foundations → Theme** — per-product tables and guidance:
75
+ - [Core Theme](https://gamut.codecademy.com/?path=/docs-foundations-theme-core-theme--docs)
76
+ - [Admin Theme](https://gamut.codecademy.com/?path=/docs-foundations-theme-admin-theme--docs)
77
+ - [Platform Theme](https://gamut.codecademy.com/?path=/docs-foundations-theme-platform-theme--docs)
78
+ - [Percipio Theme](https://gamut.codecademy.com/?path=/docs-foundations-theme-percipio-theme--docs)
79
+ - [LX Studio Theme](https://gamut.codecademy.com/?path=/docs-foundations-theme-lx-studio-theme--docs)
80
+ - [Creating Themes](https://gamut.codecademy.com/?path=/docs-foundations-theme-creating-themes--docs) — authoring new themes in `gamut-styles`
81
+ - **Product design YAML** (root `DESIGN.md` from agent-tools): [`DESIGN.Codecademy.md`](../../DESIGN.Codecademy.md), [`DESIGN.Percipio.md`](../../DESIGN.Percipio.md), [`DESIGN.LXStudio.md`](../../DESIGN.LXStudio.md) — semantic ↔ palette for that product.
82
+ - **Source:** theme definitions in [`packages/gamut-styles/src/themes`](https://github.com/Codecademy/gamut/tree/main/packages/gamut-styles/src/themes), palette scales in [`packages/gamut-styles/src/variables`](https://github.com/Codecademy/gamut/tree/main/packages/gamut-styles/src/variables).
83
+
84
+ ## Codecademy Core — illustrative light/dark hex only
85
+
86
+ The tables below are **not** valid for Percipio, LX Studio, or other themes. They are a quick mental model for Codecademy **Core** defaults only.
87
+
88
+ ### Text
89
+
90
+ | Token | Light | Dark |
91
+ | ---------------- | ------------ | --------- |
92
+ | `text` | `#10162F` | `#ffffff` |
93
+ | `text-accent` | `#0A0D1C` | `#FFF0E5` |
94
+ | `text-secondary` | navy-800 75% | white 65% |
95
+ | `text-disabled` | navy-800 63% | white 50% |
96
+
97
+ ### Background
98
+
99
+ | Token | Light | Dark |
100
+ | --------------------- | ------------ | --------- |
101
+ | `background` | `#ffffff` | `#10162F` |
102
+ | `background-primary` | `#FFF0E5` | `#0A0D1C` |
103
+ | `background-contrast` | white | black |
104
+ | `background-selected` | navy-800 4% | white 4% |
105
+ | `background-hover` | navy-800 12% | white 9% |
106
+ | `background-disabled` | navy-800 12% | white 9% |
107
+ | `background-success` | `#F5FFE3` | `#151C07` |
108
+ | `background-warning` | `#FFFAE5` | `#211B00` |
109
+ | `background-error` | `#FBF1F0` | `#280503` |
110
+
111
+ ### Interactive
112
+
113
+ | Token | Light | Dark |
114
+ | ----------------- | ------------ | --------- |
115
+ | `primary` | `#3A10E5` | `#FFD300` |
116
+ | `primary-hover` | `#5533FF` | `#CCA900` |
117
+ | `primary-inverse` | `#FFD300` | `#3A10E5` |
118
+ | `secondary` | `#10162F` | `#ffffff` |
119
+ | `secondary-hover` | navy-800 86% | white 80% |
120
+ | `interface` | `#3A10E5` | `#FFD300` |
121
+ | `interface-hover` | `#5533FF` | `#CCA900` |
122
+ | `danger` | `#E91C11` | `#E85D7F` |
123
+ | `danger-hover` | `#BE1809` | `#DC5879` |
124
+
125
+ ### Border
126
+
127
+ | Token | Light | Dark |
128
+ | ------------------ | ------------ | --------- |
129
+ | `border-primary` | `#10162F` | `#ffffff` |
130
+ | `border-secondary` | navy-800 75% | white 65% |
131
+ | `border-tertiary` | navy-800 28% | white 20% |
132
+ | `border-disabled` | navy-800 63% | white 50% |
133
+
134
+ ### Feedback
135
+
136
+ | Token | Light | Dark |
137
+ | ------------------ | --------- | --------- |
138
+ | `feedback-error` | `#BE1809` | `#E85D7F` |
139
+ | `feedback-success` | `#008A27` | `#AEE938` |
140
+ | `feedback-warning` | `#FFD300` | `#FFFAE5` |
141
+
142
+ ## Raw palette (Core-centric reference)
143
+
144
+ Raw tokens name **fixed** swatches (surfaces, illustration, `<Background bg="…">` on Codecademy). **Palette keys and hex vary by theme** — Percipio and others add or remap scales (`percipioPalette`, etc.). Confirm allowed keys in the active theme or `DESIGN.md` before using a raw token in a non-Core app.
145
+
146
+ For Codecademy Core defaults:
147
+
148
+ | Name | Weights | Key values (illustrative) |
149
+ | -------- | -------------------------- | -------------------------------- |
150
+ | `navy` | 100–900 | 800 = `#10162F`, 900 = `#0A0D1C` |
151
+ | `hyper` | 400, 500 | 500 = `#3A10E5`, 400 = `#5533FF` |
152
+ | `yellow` | 0, 400, 500, 900 | 500 = `#FFD300` |
153
+ | `red` | 0, 300, 400, 500, 600, 900 | 500 = `#E91C11` |
154
+ | `green` | 0, 100, 400, 700, 900 | 700 = `#008A27` |
155
+ | `blue` | 0, 100, 300, 400, 500, 800 | 500 = `#1557FF` |
156
+ | `beige` | — | `#FFF0E5` |
157
+ | `pink` | 0, 400 | 400 = `#F966FF` |
158
+ | `orange` | 100, 500 | 500 = `#FF8C00` |
159
+
160
+ Named shorthand aliases commonly used on Core surfaces: `beige`, `blue`, `green`, `hyper`, `navy`, `orange`, `pink`, `red`, `yellow`, `black`, `white`
161
+
162
+ ## Decision guide
163
+
164
+ ```
165
+ Which product theme is GamutProvider using?
166
+ └─ Unknown → check setup.md / DESIGN.md / Storybook theme page before assuming hex or palette name
167
+
168
+ Coloring UI text or backgrounds?
169
+ └─ Must adapt to light/dark OR theme? → semantic alias (text, background, primary, …)
170
+ └─ Must stay fixed regardless of mode? → raw palette token (confirm key exists in that theme)
171
+ └─ Section background with content inside? → <Background bg="…"> (see modes.md)
172
+ ```
@@ -0,0 +1,47 @@
1
+ # Color Modes
2
+
3
+ Gamut uses **semantic color aliases** so components adapt to light/dark mode without configuration. See [color.md](color.md) for the full alias reference.
4
+
5
+ ## `<ColorMode>`
6
+
7
+ Wraps a subtree in an explicit color mode. Nest to create scoped mode regions.
8
+
9
+ ```tsx
10
+ import { ColorMode } from '@codecademy/gamut-styles';
11
+
12
+ <ColorMode mode="light">{children}</ColorMode> // force light
13
+ <ColorMode mode="dark">{children}</ColorMode> // force dark
14
+ <ColorMode mode="system">{children}</ColorMode> // follows OS preference
15
+ ```
16
+
17
+ **Props**: `mode="light" | "dark" | "system"`
18
+
19
+ ## `<Background>`
20
+
21
+ Use `<Background>` — not a raw `bg` prop — whenever setting a colored background on a section that contains text or interactive elements. It automatically switches the color mode inside to maintain accessible contrast.
22
+
23
+ ```tsx
24
+ import { Background } from '@codecademy/gamut-styles';
25
+
26
+ <Background bg="hyper">{children}</Background>;
27
+ ```
28
+
29
+ Nesting is supported — each `<Background>` creates its own accessible color context.
30
+
31
+ ## Hooks
32
+
33
+ | Hook | Returns | Use |
34
+ | ---------------------- | --------------------------------- | ------------------------------------------------- |
35
+ | `useCurrentMode()` | `"light" \| "dark"` | Active mode key only |
36
+ | `useColorMode()` | `[modeKey, modeColors, allModes]` | Full mode data + resolver for semantic color keys |
37
+ | `usePrefersDarkMode()` | `boolean` | Read OS dark preference only |
38
+
39
+ Import from `@codecademy/gamut-styles`.
40
+
41
+ **Storybook:** [Foundations / ColorMode](https://gamut.codecademy.com/?path=/docs-foundations-colormode--page) · [Meta / Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page)
42
+
43
+ ## Common mistakes
44
+
45
+ - Do not use raw color tokens (`navy-400`, `white`) for text/backgrounds that must be accessible across modes — use semantic aliases.
46
+ - Do not use a raw `bg` prop on colored sections containing content — use `<Background>` so contrast is guaranteed.
47
+ - Do not manually toggle modes from `usePrefersDarkMode()` — use `<ColorMode mode="system">` instead.