@codecademy/gamut 68.6.1-alpha.d52035.0 → 68.6.1-alpha.df4bce.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.
@@ -174,13 +174,13 @@ Case-insensitive. Use to label `palette:` in the report; **do not** stop at this
174
174
 
175
175
  Grep test files (`**/__tests__/**/*.{ts,tsx}`, `**/*.test.{ts,tsx}`, `**/*.spec.{ts,tsx}`) for these patterns. Skip `node_modules`, `dist`.
176
176
 
177
- | Pattern | Verdict | Reason |
178
- | ----------------------------------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
179
- | `jest.mock\(.*@codecademy/gamut` | **Error** | Manual mocking bypasses theme context and produces false-positive tests; use `setupRtl` or `MockGamutProvider` instead |
180
- | `jest.mock\(.*@codecademy/gamut-styles` | **Error** | Same issue as above — mocking gamut-styles breaks token resolution |
181
- | `from '@codecademy/gamut-tests'` | Good — report count of files using it | Correct import for `setupRtl` and `MockGamutProvider` |
182
- | `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 |
183
- | `new GamutProvider` or `<GamutProvider` in test files | **Warning** | Tests should use `MockGamutProvider` (sets `useCache={false}`, `useGlobals={false}`), not `GamutProvider` directly |
177
+ | Pattern | Verdict | Reason |
178
+ | ----------------------------------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
179
+ | `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 |
180
+ | `jest.mock\(.*@codecademy/gamut-styles` | **Error** | Same issue as above — mocking gamut-styles breaks token resolution |
181
+ | `from '@codecademy/gamut-tests'` | Good — report count of files using it | Correct import for `setupRtl` and `MockGamutProvider` |
182
+ | `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 |
183
+ | `new GamutProvider` or `<GamutProvider` in test files | **Warning** | Prefer **`setupRtl`**; use **`MockGamutProvider`** (sets `useCache={false}`, `useGlobals={false}`) in harnesses or stories, not **`GamutProvider`** directly |
184
184
 
185
185
  Skill reference for remediation: `gamut-testing`
186
186
 
@@ -215,7 +215,7 @@ Hardcoded colors [→ ga
215
215
 
216
216
  Test setup [→ gamut-testing]
217
217
  ✓ @codecademy/gamut-tests used in 12 test files
218
- ✗ jest.mock(@codecademy/gamut) 2 occurrences — remove and use setupRtl instead
218
+ ✗ jest.mock(@codecademy/gamut) 2 occurrences — remove; prefer setupRtl (or harness + setupRtl)
219
219
  src/components/Foo/__tests__/Foo.test.tsx:3
220
220
  src/components/Bar/__tests__/Bar.test.tsx:5
221
221
  ⚠ direct component-test-setup import 1 occurrence — import from @codecademy/gamut-tests
@@ -17,28 +17,36 @@ ContentContainer, GridContainer, Layout, LayoutGrid
17
17
  ## Key patterns
18
18
 
19
19
  ### Buttons
20
+
20
21
  See [buttons.md](buttons.md) for full reference. Use `FillButton` for primary actions, `StrokeButton` for secondary.
21
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
+
22
27
  ### Cards
28
+
23
29
  - **Background variants**: `default` (ColorMode-responsive), `white`, `yellow`, `beige`, `navy`, `hyper`
24
30
  - **Shadow variants**: `none` (default), `outline`, `patternLeft`, `patternRight`
25
31
  - Add `isInteractive` when wrapping in `<Anchor>` — enables hover shadow + `borderRadius: md`
26
32
  - Default `borderRadius` is `none`; override with `borderRadius` prop
27
33
 
28
34
  ### Color-aware components
35
+
29
36
  - `<ColorMode mode="light|dark|system">` — scopes a subtree to an explicit color mode
30
37
  - `<Background bg="<color>">` — applies background color + auto-switches inner color mode for contrast
31
38
 
32
39
  ### Alerts
33
- | Variant | Tokens |
34
- |---|---|
35
- | Error | `feedback-error` + `background-error` |
40
+
41
+ | Variant | Tokens |
42
+ | ------- | ----------------------------------------- |
43
+ | Error | `feedback-error` + `background-error` |
36
44
  | Success | `feedback-success` + `background-success` |
37
45
  | Warning | `feedback-warning` + `background-warning` |
38
46
 
39
47
  ## Global tokens
40
48
 
41
- | Token | Value | Use |
42
- |---|---|---|
43
- | `headerHeight` | 64px (base), 80px (md+) | Global page header height |
44
- | `headerZ` | 15 | Z-index for global page header |
49
+ | Token | Value | Use |
50
+ | -------------- | ----------------------- | ------------------------------ |
51
+ | `headerHeight` | 64px (base), 80px (md+) | Global page header height |
52
+ | `headerZ` | 15 | Z-index for global page header |
@@ -1,62 +1,103 @@
1
1
  # Spacing, Border Radius & Layout
2
2
 
3
+ Token values match [`packages/gamut-styles/src/variables`](https://github.com/Codecademy/gamut/tree/main/packages/gamut-styles/src/variables) (`spacing.ts`, `borderRadii.ts`, `responsive.ts`). Breakpoints and max-content widths align with Storybook [Foundations / Layout](https://gamut.codecademy.com/?path=/docs-foundations-layout--docs).
4
+
5
+ **In code — use system props for spacing:** Gamut layout primitives (`Box`, `FlexBox`, `GridBox`, …) expose margin, padding, and gap props backed by **`system.space`** from `@codecademy/gamut-styles`. Pass **spacing scale numbers** (`4`, `8`, `16`, …), not raw pixel strings. For custom `styled` components, compose `system.space` (see [`gamut-system-props` skill](../../skills/gamut-system-props/SKILL.md)). [Meta / Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page) shows responsive `Box` examples.
6
+
7
+ **Responsive behavior:** All those props accept mobile-first **object** (`{ _: 8, md: 24 }`) or **array** syntax per [Responsive properties](https://gamut.codecademy.com/?path=/docs-foundations-system-responsive-properties--page). **Container queries** use keys `c_base`, `c_xs`, … `c_xl`; the parent must set a container (e.g. `containerType="inline-size"` on `FlexBox`). Prefer a media-query fallback when mixing `c_*` with viewport breakpoints.
8
+
9
+ **Two different “grids”:**
10
+
11
+ - **Design / page grid** (this doc’s “Grid” section, 12 columns, margins/gutters) — product layout guidelines; implement with [`LayoutGrid`](https://gamut.codecademy.com/?path=/docs-layouts-layoutgrid-layoutgrid--docs) and responsive `columnGap` / `rowGap` where appropriate.
12
+ - **CSS Grid system props** — `system.grid` on styled components or `GridBox` for **local** regions; not the same as full-page `LayoutGrid`. See [System props / Grid](https://gamut.codecademy.com/?path=/docs-foundations-system-props-grid--page). `LayoutGrid` is for flexible full-page sections; use `FlexBox` / `GridBox` / `Box` for smaller areas ([LayoutGrid usage](https://gamut.codecademy.com/?path=/docs-layouts-layoutgrid-layoutgrid--docs)).
13
+
14
+ **Designer vs code names:** Figma / Layout docs often label artboards **XL, LG, MD, SM, XS, Base**. In code, viewport breakpoints are **`xl`, `lg`, `md`, `sm`, `xs`** (min-widths below); **`_`** is the base (no min-width query). The “Max content width” column maps to those design sizes, not the `xs` token name alone.
15
+
3
16
  ## Spacing scale
4
17
 
5
18
  All spacing is multiples of 4px on an 8px grid.
6
19
 
7
20
  | Token | Value |
8
- |---|---|
9
- | `0` | 0 |
10
- | `4` | 4px |
11
- | `8` | 8px |
12
- | `12` | 12px |
13
- | `16` | 16px |
14
- | `24` | 24px |
15
- | `32` | 32px |
16
- | `40` | 40px |
17
- | `48` | 48px |
18
- | `64` | 64px |
19
- | `96` | 96px |
21
+ | ----- | ----- |
22
+ | `0` | 0 |
23
+ | `4` | 4px |
24
+ | `8` | 8px |
25
+ | `12` | 12px |
26
+ | `16` | 16px |
27
+ | `24` | 24px |
28
+ | `32` | 32px |
29
+ | `40` | 40px |
30
+ | `48` | 48px |
31
+ | `64` | 64px |
32
+ | `96` | 96px |
20
33
 
21
34
  Use multiples of 8px for block-element spacing. Use 4px only for inline or typographic relationships.
22
35
 
23
36
  ## Border radius
24
37
 
25
- | Token | Value | Use |
26
- |---|---|---|
27
- | `none` | 0px | Square / non-interactive elements |
28
- | `sm` | 2px | Subtle rounding, tags |
29
- | `md` | 4px | Buttons, inputs, interactive cards |
30
- | `lg` | 8px | Cards, panels |
31
- | `xl` | 16px | Large cards, modals |
32
- | `full` | 999px | Pills, avatars, circular elements |
38
+ | Token | Value | Use |
39
+ | ------ | ----- | ---------------------------------- |
40
+ | `none` | 0px | Square / non-interactive elements |
41
+ | `sm` | 2px | Subtle rounding, tags |
42
+ | `md` | 4px | Buttons, inputs, interactive cards |
43
+ | `lg` | 8px | Cards, panels |
44
+ | `xl` | 16px | Large cards, modals |
45
+ | `full` | 999px | Pills, avatars, circular elements |
33
46
 
34
47
  ## Breakpoints
35
48
 
36
49
  Mobile-first. Styles apply from the named breakpoint and up.
37
50
 
38
- | Token | Min-width | Max content width |
39
- |---|---|---|
40
- | _(base)_ | 0 | 288px |
41
- | `xs` | 480px | 448px |
42
- | `sm` | 768px | 704px |
43
- | `md` | 1024px | 896px |
44
- | `lg` | 1200px | 1072px |
45
- | `xl` | 1440px | 1248px |
51
+ | Token | Min-width | Max content width |
52
+ | -------- | --------- | ----------------- |
53
+ | _(base)_ | 0 | 288px |
54
+ | `xs` | 480px | 448px |
55
+ | `sm` | 768px | 704px |
56
+ | `md` | 1024px | 896px |
57
+ | `lg` | 1200px | 1072px |
58
+ | `xl` | 1440px | 1248px |
59
+
60
+ The grid table below collapses **xl+lg**, **md**, **sm+xs**, and **base** to four implementation tiers; max-content widths still follow the six design sizes in Layout.
61
+
62
+ ## Container query breakpoints
63
+
64
+ Container keys (`c_*`) use the **same min-width numbers** as viewport breakpoints, but they apply to the **width of a CSS containment context** (usually a parent), not the browser viewport. Use them when a component must adapt inside sidebars, split layouts, or embeds. Full detail: [Responsive properties — Container Queries](https://gamut.codecademy.com/?path=/docs-foundations-system-responsive-properties--page).
65
+
66
+ | Key | Min container width | Typical use |
67
+ | -------- | ------------------- | ----------------------------------------------------------------------- |
68
+ | `c_base` | 1px | Always matches once a container exists; base style inside the container |
69
+ | `c_xs` | 480px | Matches viewport `xs` threshold, but on **container** width |
70
+ | `c_sm` | 768px | |
71
+ | `c_md` | 1024px | |
72
+ | `c_lg` | 1200px | |
73
+ | `c_xl` | 1440px | |
74
+
75
+ **Requirements**
76
+
77
+ - A **descendant** of an element that establishes a container — e.g. parent `<FlexBox containerType="inline-size">` (or other `container-type`). Without that, `c_*` rules never match.
78
+ - Prefer a **viewport fallback** alongside `c_*` (e.g. `display={{ _: 'block', sm: 'flex', c_md: 'grid' }}`) for browsers or trees without container support.
79
+
80
+ **Object vs array**
81
+
82
+ - **Object:** `p={{ _: 8, c_md: 24 }}` — readable for a few container-only overrides.
83
+ - **Array:** after the six viewport slots (`_` through `xl`), indices **6–11** are `c_base`, `c_xs`, `c_sm`, `c_md`, `c_lg`, `c_xl` respectively. Use when you need the full ordered chain.
84
+
85
+ **When to use which**
46
86
 
47
- Container query variants (`c_xs`–`c_xl`) mirror these values but trigger on component width.
87
+ - **Viewport keys** (`_`, `xs`, … `xl`) page-level layout, full-bleed sections, global nav.
88
+ - **Container keys** (`c_base`, … `c_xl`) — reusable widgets whose width is driven by layout, not the device alone.
48
89
 
49
- ## Grid
90
+ ## Page layout grid (12 columns)
50
91
 
51
- 12-column grid at all breakpoints.
92
+ 12-column grid at all breakpoints. Tier columns group breakpoints with identical margin/gutter/row-gap numbers from [Layout](https://gamut.codecademy.com/?path=/docs-foundations-layout--docs).
52
93
 
53
- | Property | xl/lg | md | sm/xs | base |
54
- |---|---|---|---|---|
55
- | Horizontal margins | 64px | 48px | 32px | 16px |
56
- | Column gutters | 32px | 24px | 16px | 8px |
57
- | Row gaps | 32px | 24px | 16px | 8px |
94
+ | Property | xl/lg | md | sm/xs | base |
95
+ | ------------------ | ----- | ---- | ----- | ---- |
96
+ | Horizontal margins | 64px | 48px | 32px | 16px |
97
+ | Column gutters | 32px | 24px | 16px | 8px |
98
+ | Row gaps | 32px | 24px | 16px | 8px |
58
99
 
59
- Minimum touch target on mobile: **44×44px**.
100
+ Minimum touch target on mobile: **44×44px** — see `gamut-accessibility` skill for hit-target guidance.
60
101
 
61
102
  ## Responsive rules
62
103
 
@@ -1,50 +1,83 @@
1
1
  # Typography
2
2
 
3
- ## Typefaces
3
+ Use **theme typography tokens** (`fontFamily`, `fontSize`, `fontWeight`, `lineHeight`) — never hardcoded font-family strings or magic px for product UI. Prefer `<Text>` from `@codecademy/gamut`, or `system.typography` / `css()` from `@codecademy/gamut-styles` ([`gamut-system-props` skill](../../skills/gamut-system-props/SKILL.md)).
4
4
 
5
- | Token | Codecademy font | Non-Codecademy | Use for |
6
- |---|---|---|---|
7
- | `base` | Apercu Pro | Hanken Grotesk | All UI text, headlines, body copy |
8
- | `accent` | Suisse Intl Mono | Hanken Grotesk | Code, captions, labels, technical context |
9
- | `monospace` | Monaco / Menlo / Consolas | Monaco / Menlo / Consolas | Code editor contexts |
5
+ Source of truth for scales and stacks: [`packages/gamut-styles/src/variables/typography.ts`](https://github.com/Codecademy/gamut/blob/main/packages/gamut-styles/src/variables/typography.ts) and theme builders under [`packages/gamut-styles/src/themes`](https://github.com/Codecademy/gamut/tree/main/packages/gamut-styles/src/themes).
10
6
 
11
- Percipio overrides all families to Roboto. Apercu is licensed for codecademy.com only.
7
+ **Storybook:** [Typography / Text](https://gamut.codecademy.com/?path=/docs-typography-text--docs) · [Meta / Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page) (system props) · Foundations / Theme: [Core](https://gamut.codecademy.com/?path=/docs-foundations-theme-core-theme--docs), [Percipio](https://gamut.codecademy.com/?path=/docs-foundations-theme-percipio-theme--docs), [LX Studio](https://gamut.codecademy.com/?path=/docs-foundations-theme-lx-studio-theme--docs)
8
+
9
+ **DESIGN.md drift:** [`DESIGN.Percipio.md`](../../DESIGN.Percipio.md) and [`DESIGN.LXStudio.md`](../../DESIGN.LXStudio.md) sometimes describe **Roboto** or **Hanken Grotesk** for those products. **Shipped `gamut-styles` themes** currently use the stacks below (Skillsoft Text / Sans). Treat DESIGN YAML as product narrative until it matches code — confirm with the design platform when they disagree.
10
+
11
+ ## Themes × font families
12
+
13
+ Semantic keys (`base`, `accent`, `monospace`, `system`) are stable; resolved stacks depend on `GamutProvider` theme ([`setup.md`](../setup.md)).
14
+
15
+ | Theme | `fontFamily.base` | `fontFamily.accent` | `fontFamily.monospace` | `fontFamily.system` |
16
+ | --------------------------------- | ------------------------------------ | ------------------------------------- | -------------------------------------- | ------------------------------ |
17
+ | **Core**, **Admin**, **Platform** | Apercu stack (`fontBase`) | Suisse + Apercu stack (`fontAccent`) | Monaco / Menlo stack (`fontMonospace`) | System UI stack (`fontSystem`) |
18
+ | **Percipio** | Skillsoft Text (`fontPercipioBase`) | Skillsoft Sans (`fontPercipioAccent`) | Roboto Mono | Roboto (`system`) |
19
+ | **LX Studio** | Same as Percipio (`base` / `accent`) | Same | Same stack as Core (`fontMonospace`) | Same as Core (`fontSystem`) |
20
+
21
+ Admin and Platform extend Core for colors / modes only — typography matches Core.
22
+
23
+ **Licensing:** Apercu is licensed for Codecademy surfaces only; Skillsoft products use Percipio/LX stacks above.
12
24
 
13
25
  ## Font size scale
14
26
 
15
- | Token | Size | Common use |
16
- |---|---|---|
17
- | `64` | 64px | Hero / display |
18
- | `44` | 44px | Page titles |
19
- | `34` | 34px | Section titles |
20
- | `26` | 26px | Sub-section titles |
21
- | `22` | 22px | Card titles, large UI labels |
22
- | `20` | 20px | Secondary titles |
23
- | `18` | 18px | Large body, intro text |
24
- | `16` | 16px | Default body text |
25
- | `14` | 14px | Small body, captions, labels |
26
-
27
- ## Font weight
28
-
29
- | Token | Value | Use |
30
- |---|---|---|
31
- | `base` | 400 | Body text, UI labels |
32
- | `title` | 700 | Headlines, CTAs, buttons |
27
+ Values are `rem`-backed keys on `theme.fontSize` (aliases shown as px for readability).
28
+
29
+ | Token | Size | Common use |
30
+ | ----- | ---- | ---------------------------- |
31
+ | `64` | 64px | Hero / display |
32
+ | `44` | 44px | Page titles |
33
+ | `34` | 34px | Section titles |
34
+ | `26` | 26px | Sub-section titles |
35
+ | `22` | 22px | Card titles, large UI labels |
36
+ | `20` | 20px | Secondary titles |
37
+ | `18` | 18px | Large body, intro text |
38
+ | `16` | 16px | Default body text |
39
+ | `14` | 14px | Small body, captions, labels |
33
40
 
34
41
  ## Line height
35
42
 
36
- | Token | Value | Use |
37
- |---|---|---|
38
- | `base` | 1.5 | Body text |
39
- | `spacedTitle` | 1.3 | Sub-headlines, medium titles |
40
- | `title` | 1.2 | Large headlines |
43
+ | Token | Value | Use |
44
+ | ------------- | ----- | ---------------------------- |
45
+ | `base` | 1.5 | Body text |
46
+ | `spacedTitle` | 1.3 | Sub-headlines, medium titles |
47
+ | `title` | 1.2 | Large headlines |
48
+
49
+ ## Font weight (semantic)
50
+
51
+ Use **semantic keys** on components — do not assume a numeric bold everywhere.
52
+
53
+ | Token | Core / Admin / Platform | Percipio / LX Studio |
54
+ | ------- | ----------------------- | --------------------------------- |
55
+ | `base` | 400 | 400 |
56
+ | `title` | **700** | **500** (`fontWeightMediumTitle`) |
57
+
58
+ Headlines, CTAs, and buttons should use **`fontWeight="title"`** so Percipio/LX get **500**, Core gets **700**. Literal `700` breaks Skillsoft branding on those themes.
59
+
60
+ Numeric **`400`** and **`700`** keys also exist on the theme for rare explicit needs.
61
+
62
+ ## Codecademy (Core / Admin / Platform) — voice & layout
63
+
64
+ These UX rules target **Apercu + Suisse** products; do not blindly apply to Percipio/LX without brand guidance.
65
+
66
+ - **`fontFamily="base"` (Apercu):** default UI and marketing type. Emphasis inside body copy: **Italic**, not Bold for intra-paragraph stress.
67
+ - **`fontFamily="accent"` (Suisse stack):** technical accent — code snippets, captions, labels with engineering flavor, figures. Use sparingly; glyph box reads larger — step **down ~10–15%** vs equivalent `base` size; give comfortable line-height.
68
+ - **Alignment:** left-align by default; center only short marketing headlines; avoid right-align except tabs / numerics.
69
+ - **Letter-spacing:** do not tweak tracking unless design specifies.
70
+ - **Line length:** ~45–85 characters per line (~66 ideal for single-column body); constrain container width, not arbitrary CSS letter-spacing.
71
+
72
+ ## Line length (all products)
41
73
 
42
- Target 45–85 characters per line (66 ideal for web body text).
74
+ | Context | Target |
75
+ | ------------------ | ------------------- |
76
+ | Single-column body | ~66 chars (max ~85) |
77
+ | Multi-column | ≤50 chars per line |
78
+ | Minimum | ~45 chars |
43
79
 
44
- ## Rules
80
+ ## Related skills
45
81
 
46
- - Use `title` weight (700) for headlines, CTAs, and buttons.
47
- - Use Apercu Italic to emphasize within a Regular paragraph — not Bold.
48
- - Use `accent` (Suisse) sparingly: code snippets, captions, enumerated items. Suisse reads ~10–15% large — size it down relative to Apercu equivalents.
49
- - Left-align text by default. Center-align only for short marketing headlines. Never right-align.
50
- - Do not adjust letter-spacing.
82
+ - [`gamut-typography`](../../skills/gamut-typography/SKILL.md) deeper editorial patterns for agents.
83
+ - [`gamut-theming`](../../skills/gamut-theming/SKILL.md) accessing `theme.font*` in styled components.
@@ -6,33 +6,35 @@ Gamut is the Codecademy / Skillsoft design system — React component library (`
6
6
 
7
7
  **Core principles**:
8
8
 
9
- - Components are color mode–aware by default — never hardcode hex values for adaptive UI
9
+ - Components are color mode–aware by default — never hardcode hex values for adaptive, accessible UI
10
10
  - All components work across all themes without modification
11
- - Mobile-first, 12-column grid
12
- - Semantic color tokens guarantee WCAG AA contrast automatically
11
+ - 12-column grid
12
+ - Use **semantic theme tokens** from `@codecademy/gamut-styles` for **color roles** (ColorMode-aware), **typography**, **spacing**, **border radii**, and shared **layout** values (`elements`, …) — not raw palette hex or magic numbers. Defaults support accessible pairings, but **no token set guarantees WCAG AA** for every composition; validate non-standard combinations.
13
13
 
14
14
  **ColorMode in product UI:** Use `<ColorMode>` and `<Background>` from `@codecademy/gamut-styles` for scoped light/dark and contrast-safe surfaces — see [foundations/modes.md](foundations/modes.md) and the `gamut-color-mode` skill. Storybook: [ColorMode](https://gamut.codecademy.com/?path=/docs-foundations-colormode--page), [Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page) (semantic tokens + `css` / `variant` / `states`).
15
15
 
16
16
  ## Themes
17
17
 
18
- | Theme | Product | Base font | Dark mode |
19
- | ------------- | ------------------------------- | -------------- | --------- |
20
- | **Core** | Codecademy (default) | Apercu | |
21
- | **Admin** | Codecademy admin tools | Apercu | |
22
- | **Platform** | Codecademy learning environment | Apercu | ✓ |
23
- | **LX Studio** | LX Studio application | Hanken Grotesk | |
24
- | **Percipio** | Skillsoft Percipio | Roboto | |
18
+ Runtime stacks come from `@codecademy/gamut-styles` (see [foundations/typography.md](foundations/typography.md)). Product `DESIGN.*.md` may differ until reconciled.
19
+
20
+ | Theme | Product | Primary UI fonts (shipped theme) | Dark mode |
21
+ | ------------- | ------------------------------- | ------------------------------------------------------------------------------ | --------- |
22
+ | **Core** | Codecademy (default) | Apercu + Suisse (`accent`) | ✓ |
23
+ | **Admin** | Codecademy admin tools | Same as Core | |
24
+ | **Platform** | Codecademy learning environment | Same as Core | |
25
+ | **LX Studio** | LX Studio application | Skillsoft Text / Sans (`base` / `accent`); DESIGN docs may list Hanken Grotesk | — |
26
+ | **Percipio** | Skillsoft Percipio | Skillsoft Text / Sans; DESIGN docs may list Roboto | — |
25
27
 
26
28
  Set the theme at the app root via `<GamutProvider theme={...}>`.
27
29
 
28
30
  ## Reading order
29
31
 
30
- | File | What it covers |
31
- | ------------------------------------------------------ | ----------------------------------------------------------------------- |
32
- | [setup.md](setup.md) | Packages, GamutProvider, theme selection |
33
- | [foundations/color.md](foundations/color.md) | Semantic roles (all themes), where to verify hex, Core-only cheatsheets |
34
- | [foundations/modes.md](foundations/modes.md) | Light/dark ColorMode, Background component |
35
- | [foundations/typography.md](foundations/typography.md) | Typefaces, font scale, rules |
36
- | [foundations/spacing.md](foundations/spacing.md) | Spacing, border radius, responsive grid |
37
- | [components/overview.md](components/overview.md) | Full component catalog |
38
- | [components/buttons.md](components/buttons.md) | Button variants, props, decision tree |
32
+ | File | What it covers |
33
+ | ------------------------------------------------------ | ------------------------------------------------------------------------------ |
34
+ | [setup.md](setup.md) | Packages, GamutProvider, theme selection |
35
+ | [foundations/color.md](foundations/color.md) | Semantic roles (all themes), where to verify hex, Core-only cheatsheets |
36
+ | [foundations/modes.md](foundations/modes.md) | Light/dark ColorMode, Background component |
37
+ | [foundations/typography.md](foundations/typography.md) | Theme fonts, scales, semantic `title` weight (700 vs 500), Core voice rules |
38
+ | [foundations/spacing.md](foundations/spacing.md) | Spacing scale, radii, Layout grid; system props + responsive/container queries |
39
+ | [components/overview.md](components/overview.md) | Full component catalog |
40
+ | [components/buttons.md](components/buttons.md) | Button variants, props, decision tree |
@@ -3,40 +3,79 @@
3
3
  ## Install
4
4
 
5
5
  ```sh
6
- npm install @codecademy/gamut-kit
6
+ yarn add @codecademy/gamut-kit @emotion/react @emotion/styled
7
7
  ```
8
8
 
9
9
  `gamut-kit` bundles `gamut`, `gamut-icons`, `gamut-illustrations`, `gamut-patterns`, `gamut-styles`, `variance`, and `gamut-tests`.
10
10
 
11
+ **Full guide:** [Meta / Installation](https://gamut.codecademy.com/?path=/docs-meta-installation--page) in Storybook (CSP `nonce` on `GamutProvider`, Jest, Next/Gatsby entry points). For Emotion + TypeScript, add `theme.d.ts` as in [TypeScript (`theme.d.ts`)](#typescript-themedts) below.
12
+
13
+ Optionally add a `peerDependencies` block in `package.json` listing `@codecademy/gamut`, `@codecademy/gamut-icons`, `@codecademy/gamut-illustrations`, `@codecademy/gamut-patterns`, `@codecademy/gamut-styles`, `@codecademy/gamut-tests`, and `@codecademy/variance` (e.g. `"*"`) so editors surface those packages — see Meta / Installation for the JSON snippet.
14
+
11
15
  ## Required wrapper
12
16
 
13
- Wrap the app root in `<GamutProvider>`. This wires up the theme, color mode, and logical properties for all child components.
17
+ Wrap the app root in `<GamutProvider>` from `@codecademy/gamut-styles`. This wires up the theme, color mode, and logical properties for all child components.
18
+
19
+ At runtime, `GamutProvider` defaults to Core when `theme` is omitted (`theme = coreTheme` in the implementation). For non-Core products and for TypeScript (`theme` is required on `GamutProviderProps`), pass `theme` explicitly using the table below.
14
20
 
15
21
  ```tsx
16
- import { GamutProvider } from '@codecademy/gamut';
17
- import { theme } from '@codecademy/gamut-styles';
22
+ import { GamutProvider, theme } from '@codecademy/gamut-styles';
18
23
 
19
24
  const App = () => (
20
- <GamutProvider theme={theme}>
21
- {/* app content */}
22
- </GamutProvider>
25
+ <GamutProvider theme={theme}>{/* app content */}</GamutProvider>
23
26
  );
24
27
  ```
25
28
 
26
29
  ## Theme selection
27
30
 
28
- | Product | Theme to import |
29
- |---|---|
30
- | Codecademy public | `coreTheme` (default `theme`) |
31
- | Codecademy admin | `adminTheme` |
32
- | Codecademy platform | `platformTheme` |
33
- | LX Studio | `lxStudioTheme` |
34
- | Percipio | `percipioTheme` |
31
+ | Product | Theme to import |
32
+ | ------------------- | ----------------------------- |
33
+ | Codecademy public | `coreTheme` (default `theme`) |
34
+ | Codecademy admin | `adminTheme` |
35
+ | Codecademy platform | `platformTheme` |
36
+ | LX Studio | `lxStudioTheme` |
37
+ | Percipio | `percipioTheme` |
35
38
 
36
39
  All themes are exported from `@codecademy/gamut-styles`.
37
40
 
38
- ## Font licensing
41
+ ## TypeScript (`theme.d.ts`)
42
+
43
+ Augment `@emotion/react` so `props.theme` in `styled` / `css` matches the **same theme object** you pass to `<GamutProvider theme={...}>`. If the types disagree, system props and token autocomplete will not line up with runtime.
44
+
45
+ Add a root `theme.d.ts` (or merge into your existing global types):
46
+
47
+ ```tsx
48
+ // theme.d.ts
49
+ import '@emotion/react';
50
+
51
+ import type { CoreTheme } from '@codecademy/gamut-styles';
52
+
53
+ declare module '@emotion/react' {
54
+ export interface Theme extends CoreTheme {}
55
+ }
56
+ ```
57
+
58
+ Use the **theme interface that matches your provider** — same row as the [theme selection](#theme-selection) table:
59
+
60
+ | `GamutProvider` `theme` prop | Import for `Theme extends …` |
61
+ | ---------------------------- | ---------------------------- |
62
+ | `theme` or `coreTheme` | `CoreTheme` |
63
+ | `adminTheme` | `AdminTheme` |
64
+ | `platformTheme` | `PlatformTheme` |
65
+ | `lxStudioTheme` | `LxStudioTheme` |
66
+ | `percipioTheme` | `PercipioTheme` |
67
+
68
+ Example when the app uses Percipio:
69
+
70
+ ```tsx
71
+ // theme.d.ts
72
+ import '@emotion/react';
73
+
74
+ import type { PercipioTheme } from '@codecademy/gamut-styles';
75
+
76
+ declare module '@emotion/react' {
77
+ export interface Theme extends PercipioTheme {}
78
+ }
79
+ ```
39
80
 
40
- **Apercu Pro** is licensed for codecademy.com only. Non-Codecademy products must use their theme's approved typeface:
41
- - LX Studio → Hanken Grotesk
42
- - Percipio → Roboto
81
+ See Emotion’s [TypeScript / define a theme](https://emotion.sh/docs/typescript#define-a-theme) for details.
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Apply these guardrails when editing Gamut UI in TS/JS/TSX/JSX. Mirrors the General rules in the `gamut-accessibility` skill; see `skills/gamut-accessibility/SKILL.md` in this plugin for full component patterns and checklists. Loaded automatically for matched files.
2
+ description: Apply these guardrails when editing Gamut UI in TS/JS/TSX/JSX. Universal rules (always loaded). Form wiring depth: **`gamut-forms`** skill; other component matrix and audit detail: **`gamut-accessibility`** those skills do not repeat this rule set.
3
3
  alwaysApply: true
4
4
  globs: ['*.tsx', '*.ts', '*.jsx', '*.js']
5
5
  ---
@@ -39,21 +39,20 @@ When there is no visible text for a nameable element, consider this a sign that
39
39
  </ul>
40
40
  ```
41
41
 
42
- ## Use Gamut componentsdon't reimplement what they already solve
42
+ ## Use Gamut primitivesdo not fake buttons or dialogs
43
43
 
44
- - `<Button>` not `<div onClick>` or `<span role="button">`
45
- - `<Tabs>` / `<Tab>` / `<TabList>` / `<TabPanel>`arrow key, Home, End navigation is automatic
46
- - `<Dialog>` / `<Modal>` — always provide an accessible name; **prefer `aria-labelledby`** to a visible title when one exists, otherwise `aria-label`. Focus lock and Escape are handled by the components.
44
+ - **Actions:** use Gamut button atoms (`FillButton`, `TextButton`, `StrokeButton`, `CTAButton`, `IconButton`) — not `<div onClick>`, not `<span role="button">`, not `<a>` without `href` for actions. Variant and `tip` guidance: [`guidelines/components/buttons.md`](../guidelines/components/buttons.md).
45
+ - **Tabs / overlays:** `Tabs`, `Dialog`, `Modal`, and related primitives implement keyboard and focus patterns in code still supply labels, titles, and trigger semantics as documented in the skill.
47
46
 
48
47
  ## Every interactive control needs an accessible name
49
48
 
50
- - **`<IconButton>`** — provide `tip` (becomes the accessible name for icon-only)
51
- - **`<InfoTip>`** — provide `ariaLabel` or `ariaLabelledby`; there is no automatic fallback
52
- - Icon SVGs next to visible text — add `aria-hidden="true"` to decorative icons
49
+ - **`IconButton`** — provide `tip` (accessible name for icon-only).
50
+ - **`InfoTip`** — provide `ariaLabel` or `ariaLabelledby`; there is no automatic fallback.
51
+ - Decorative icon SVGs next to visible text — `aria-hidden="true"` on the icon.
53
52
 
54
53
  ## Form label association
55
54
 
56
- Match `htmlFor` on `<FormGroupLabel>` with the `id` on the input. `<FormGroup>` auto-wires `aria-live` for `error` and `description` — do not add redundant live regions manually.
55
+ Match **`htmlFor`** on **`<FormGroupLabel>`** with the **`id`** on the control. Base **`<FormGroup>`** renders live regions for **`error`** and **`description`**; **`GridForm`** and **`ConnectedForm`** add field wiring (**`aria-describedby`**, **`aria-invalid`**, first-error **`aria-live`** behavior) — do not add redundant duplicate regions. Depth: **[`skills/gamut-forms/SKILL.md`](../skills/gamut-forms/SKILL.md)**.
57
56
 
58
57
  ## Screen-reader-only text
59
58
 
@@ -61,8 +60,19 @@ Use `<Text screenreader>` for visually hidden but announced content. `<HiddenTex
61
60
 
62
61
  ## Color and contrast
63
62
 
64
- Do not hardcode hex values for adaptive UI. Gamut semantic color tokens through `ColorMode` are built for WCAG AA; see the `gamut-color-mode` skill for token usage. Semantic colors only guarantee contrast when the subtree is under the right **ColorMode** or **`<Background>`** context — use those primitives for section surfaces, not ad hoc `background-color`. For non-text contrast, focus order, and ARIA beyond color, see `gamut-accessibility`.
63
+ Do not hardcode hex for adaptive UI. Prefer semantic tokens and **`ColorMode` / `<Background>`** so surfaces track theme and mode — see the **`gamut-color-mode`** skill and [`foundations/modes.md`](../guidelines/foundations/modes.md). Default pairings support accessible UI, but **tokens do not guarantee WCAG compliance** for every layout; validate non-standard combinations.
65
64
 
66
65
  ## Focus visibility
67
66
 
68
- Never suppress focus indicators with `outline: none` or `outline: 0` without a visible replacement. Gamut's focus styles are intentional and meet WCAG 2.4.7.
67
+ Never suppress focus indicators with `outline: none` or `outline: 0` without a visible replacement. Gamuts focus styles are intentional (WCAG 2.4.7).
68
+
69
+ ## Where to read more (minimal index)
70
+
71
+ | Topic | Primary doc |
72
+ | --- | --- |
73
+ | Forms (`GridForm`, `ConnectedForm`, `FormGroup`, validation, live regions) | [`skills/gamut-forms/SKILL.md`](../skills/gamut-forms/SKILL.md) |
74
+ | Component matrix (tips, overlays, composites, checklists; not form wiring) | [`skills/gamut-accessibility/SKILL.md`](../skills/gamut-accessibility/SKILL.md) |
75
+ | Button variants, `IconButton` `tip`, `disabled` vs `aria-disabled` | [`guidelines/components/buttons.md`](../guidelines/components/buttons.md) |
76
+ | ColorMode, `Background`, semantic color roles | **`gamut-color-mode`** skill · [`foundations/modes.md`](../guidelines/foundations/modes.md) · [`foundations/color.md`](../guidelines/foundations/color.md) |
77
+ | Tokens, `css` / `variant` / `states` | Storybook [Meta / Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page) |
78
+ | Install, `GamutProvider`, CSP | Storybook [Meta / Installation](https://gamut.codecademy.com/?path=/docs-meta-installation--page) |