@codecademy/gamut 68.6.2-alpha.671e56.0 → 68.6.2-alpha.d2f2df.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/AccordionButtonDeprecated/ButtonDeprecated/index.d.ts +2 -2
- package/dist/AccordionButtonDeprecated/ButtonDeprecated/index.js +1 -1
- package/dist/Alert/elements.d.ts +2 -2
- package/dist/Anchor/index.d.ts +19 -9
- package/dist/Anchor/index.js +9 -6
- package/dist/BarChart/BarRow/elements.d.ts +47 -45
- package/dist/BarChart/utils/hooks.d.ts +2 -2
- package/dist/BarChart/utils/hooks.js +3 -1
- package/dist/Box/GridBox.d.ts +1 -0
- package/dist/Box/GridBox.js +1 -1
- package/dist/Box/props.d.ts +1 -1
- package/dist/Breadcrumbs/index.d.ts +5 -5
- package/dist/Breadcrumbs/index.js +2 -2
- package/dist/Button/CTAButton.d.ts +2 -2
- package/dist/Button/FillButton.d.ts +4 -4
- package/dist/Button/IconButton.d.ts +4 -4
- package/dist/Button/StrokeButton.d.ts +4 -4
- package/dist/Button/TextButton.d.ts +4 -4
- package/dist/Button/shared/InlineIconButton.d.ts +2 -2
- package/dist/Button/shared/styles.d.ts +3 -3
- package/dist/Button/shared/types.d.ts +1 -1
- package/dist/ButtonBase/ButtonBase.d.ts +9 -4
- package/dist/ButtonBase/ButtonBase.js +11 -4
- package/dist/Card/elements.d.ts +109 -103
- package/dist/Card/styles.d.ts +8 -8
- package/dist/Coachmark/index.d.ts +1 -1
- package/dist/ConnectedForm/ConnectedForm.d.ts +1 -1
- package/dist/ConnectedForm/ConnectedFormGroup.js +4 -3
- package/dist/ConnectedForm/utils.d.ts +1 -1
- package/dist/ConnectedForm/utils.js +1 -1
- package/dist/DatePicker/DatePickerInput/index.d.ts +1 -1
- package/dist/Disclosure/elements.d.ts +18 -12
- package/dist/FeatureShimmer/index.js +1 -1
- package/dist/Form/SelectDropdown/SelectDropdown.js +1 -1
- package/dist/Form/SelectDropdown/elements/containers.js +1 -1
- package/dist/Form/SelectDropdown/elements/controls.js +2 -2
- package/dist/Form/SelectDropdown/elements/multi-value.js +2 -2
- package/dist/Form/SelectDropdown/types/internal.d.ts +2 -2
- package/dist/Form/SelectDropdown/utils.js +2 -1
- package/dist/Form/elements/Form.d.ts +15 -15
- package/dist/Form/elements/FormGroup.d.ts +1 -1
- package/dist/Form/styles/Checkbox-styles.d.ts +1 -1
- package/dist/GridForm/GridFormButtons/index.d.ts +4 -4
- package/dist/List/ListProvider.d.ts +1 -1
- package/dist/List/elements.d.ts +44 -42
- package/dist/Menu/MenuItem.js +10 -6
- package/dist/Menu/elements.d.ts +2 -2
- package/dist/Modals/Dialog.js +6 -2
- package/dist/Modals/Modal.js +5 -2
- package/dist/Modals/elements.d.ts +1 -1
- package/dist/Pagination/AnimatedPaginationButtons.d.ts +31 -29
- package/dist/Pagination/EllipsisButton.d.ts +2 -2
- package/dist/Pagination/PaginationButton.d.ts +6 -6
- package/dist/Pagination/utils.d.ts +31 -29
- package/dist/Pagination/utils.js +14 -11
- package/dist/Popover/Popover.js +6 -6
- package/dist/Popover/types.d.ts +4 -3
- package/dist/PopoverContainer/PopoverContainer.js +9 -9
- package/dist/PopoverContainer/hooks.d.ts +16 -4
- package/dist/PopoverContainer/hooks.js +50 -27
- package/dist/PopoverContainer/types.d.ts +2 -1
- package/dist/Tabs/TabButton.d.ts +2 -2
- package/dist/Tabs/TabNavLink.d.ts +2 -2
- package/dist/Tag/elements.d.ts +14 -8
- package/dist/Tag/index.js +1 -1
- package/dist/Tip/InfoTip/InfoTipButton.d.ts +4 -4
- package/dist/Tip/PreviewTip/elements.d.ts +12 -6
- package/dist/Tip/__tests__/helpers.d.ts +1 -1
- package/dist/Tip/shared/FloatingTip.js +2 -2
- package/dist/Tip/shared/types.d.ts +2 -2
- package/dist/Tip/shared/utils.js +1 -1
- package/dist/utils/nullish.d.ts +10 -0
- package/dist/utils/nullish.js +11 -0
- package/dist/utils/react.js +4 -2
- package/package.json +12 -15
- 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 -643
- package/agent-tools/DESIGN.LXStudio.md +0 -437
- package/agent-tools/DESIGN.Percipio.md +0 -433
- package/agent-tools/DESIGN.md +0 -1
- package/agent-tools/agents/.gitkeep +0 -0
- package/agent-tools/rules/accessibility.mdc +0 -78
- package/agent-tools/skills/gamut-accessibility/SKILL.md +0 -214
- package/agent-tools/skills/gamut-buttons/SKILL.md +0 -96
- package/agent-tools/skills/gamut-color-mode/SKILL.md +0 -257
- package/agent-tools/skills/gamut-forms/SKILL.md +0 -84
- package/agent-tools/skills/gamut-layout/SKILL.md +0 -109
- package/agent-tools/skills/gamut-list/SKILL.md +0 -273
- package/agent-tools/skills/gamut-review/SKILL.md +0 -254
- package/agent-tools/skills/gamut-style-utilities/SKILL.md +0 -107
- package/agent-tools/skills/gamut-system-props/SKILL.md +0 -203
- package/agent-tools/skills/gamut-testing/SKILL.md +0 -221
- package/agent-tools/skills/gamut-theming/SKILL.md +0 -115
- package/agent-tools/skills/gamut-typography/SKILL.md +0 -98
- package/bin/commands/plugin/install.mjs +0 -212
- 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
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: gamut-forms
|
|
3
|
-
description: Implementing or auditing Gamut forms — FormGroup, ConnectedForm, ConnectedFormGroup, GridForm, react-hook-form wiring, labels, and accessible error/description regions. Pair with `gamut-accessibility` for non-form widgets and `accessibility.mdc` for universal HTML/ARIA rules.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Gamut forms
|
|
7
|
-
|
|
8
|
-
Canonical wiring for `FormGroup`, `ConnectedForm`, `ConnectedFormGroup`, `GridForm`, and field renderers. Source: `packages/gamut/src/Form/`, `ConnectedForm/`, `GridForm/`.
|
|
9
|
-
|
|
10
|
-
Universal label and primitive guidance: [`accessibility.mdc`](../../rules/accessibility.mdc) · overlay and composite patterns: [`gamut-accessibility`](../gamut-accessibility/SKILL.md).
|
|
11
|
-
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## Prefer connected layouts
|
|
15
|
-
|
|
16
|
-
For typical product forms, prefer `GridForm` (declarative `fields`, `LayoutGrid`, submit/cancel) or `ConnectedForm` with `ConnectedFormGroup` / `useConnectedForm`. Use raw `FormGroup` + atoms only when the layout is simple and you fully own `id`, `htmlFor`, invalid state, and any `aria-describedby` (see below).
|
|
17
|
-
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
## Labels and controls
|
|
21
|
-
|
|
22
|
-
`htmlFor` / `id` pairing — universal rule in [`accessibility.mdc`](../../rules/accessibility.mdc) (Form label association). Form-specific notes:
|
|
23
|
-
|
|
24
|
-
- `FormGroupLabel` → control `id` (or stable `name` when that is your field’s id convention).
|
|
25
|
-
- Checkbox, Radio, Select: same pairing; checkbox/radio use the visually hidden input pattern from `@codecademy/gamut-styles` where applicable.
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## `FormGroup` (baseline)
|
|
30
|
-
|
|
31
|
-
[`FormGroup.tsx`](https://github.com/Codecademy/gamut/blob/main/packages/gamut/src/Form/elements/FormGroup.tsx)
|
|
32
|
-
|
|
33
|
-
- `description` → `FormGroupDescription` with `aria-live="assertive"`.
|
|
34
|
-
- `error` (string) → `FormError` with `aria-live="polite"` and `role="alert"`.
|
|
35
|
-
|
|
36
|
-
Raw `FormGroup` does not set `aria-describedby` or `aria-invalid` on `children`. If you compose fields outside `ConnectedFormGroup` / `GridForm`, wire those yourself or accept that only the live regions above communicate errors/descriptions.
|
|
37
|
-
|
|
38
|
-
---
|
|
39
|
-
|
|
40
|
-
## `ConnectedFormGroup`
|
|
41
|
-
|
|
42
|
-
[`ConnectedFormGroup.tsx`](https://github.com/Codecademy/gamut/blob/main/packages/gamut/src/ConnectedForm/ConnectedFormGroup.tsx)
|
|
43
|
-
|
|
44
|
-
- Passes `aria-describedby` (error region id when shown) and `aria-invalid` on the rendered field component.
|
|
45
|
-
- `FormError`: `aria-live="assertive"` and `role="alert"` only when `isFirstError`; otherwise `aria-live="off"` and `role="status"` so subsequent errors do not interrupt repeatedly.
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
|
|
49
|
-
## `GridForm`
|
|
50
|
-
|
|
51
|
-
[`GridFormInputGroup/index.tsx`](https://github.com/Codecademy/gamut/blob/main/packages/gamut/src/GridForm/GridFormInputGroup/index.tsx) · [`GridFormTextInput`](https://github.com/Codecademy/gamut/blob/main/packages/gamut/src/GridForm/GridFormInputGroup/GridFormTextInput/index.tsx)
|
|
52
|
-
|
|
53
|
-
- Composes `ConnectedForm`, `LayoutGrid`, `GridFormButtons`, and field metadata. `FormError` uses the same first-error assertive pattern as `ConnectedFormGroup` (`aria-live` assertive vs off, `role` alert vs status).
|
|
54
|
-
- Built-in text inputs set `aria-invalid` and register with react-hook-form via `register`. Custom / `custom` / `custom-group` renderers must still expose correct `id`, `label`, and error surfacing consistent with this pattern.
|
|
55
|
-
|
|
56
|
-
---
|
|
57
|
-
|
|
58
|
-
## Live regions — do not double up
|
|
59
|
-
|
|
60
|
-
`FormGroup`, `ConnectedFormGroup`, and `GridForm` already render `FormError` (and base `FormGroup` renders `FormGroupDescription`) with live-region attributes. Do not add a second `aria-live` wrapper for the same message stream.
|
|
61
|
-
|
|
62
|
-
---
|
|
63
|
-
|
|
64
|
-
## Storybook
|
|
65
|
-
|
|
66
|
-
- [Organisms / GridForm / About](https://gamut.codecademy.com/?path=/docs-organisms-gridform-about--docs) · [Usage](https://gamut.codecademy.com/?path=/docs-organisms-gridform-usage--docs) · [Validation](https://gamut.codecademy.com/?path=/docs-organisms-gridform-validation--docs) · [Fields](https://gamut.codecademy.com/?path=/docs-organisms-gridform-fields--docs)
|
|
67
|
-
- [Organisms / ConnectedForm / ConnectedForm](https://gamut.codecademy.com/?path=/docs-organisms-connectedform-connectedform--docs) · [ConnectedFormGroup](https://gamut.codecademy.com/?path=/docs-organisms-connectedform-connectedformgroup--docs)
|
|
68
|
-
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
## Example — baseline `FormGroup`
|
|
72
|
-
|
|
73
|
-
```tsx
|
|
74
|
-
<FormGroup
|
|
75
|
-
htmlFor="email-input"
|
|
76
|
-
description="Used for login"
|
|
77
|
-
error={errors.email}
|
|
78
|
-
>
|
|
79
|
-
<FormGroupLabel htmlFor="email-input">Email</FormGroupLabel>
|
|
80
|
-
<Input id="email-input" type="email" />
|
|
81
|
-
</FormGroup>
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
When using `ConnectedFormGroup` or `GridForm`, prefer their docs and defaults over hand-rolling the above for every field.
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: gamut-layout
|
|
3
|
-
description: Use this skill when applying Gamut spacing scale, border radii, viewport or container breakpoints, or page layout grid (LayoutGrid vs GridBox) — complements gamut-system-props for system.space and responsive props.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Gamut Layout
|
|
7
|
-
|
|
8
|
-
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).
|
|
9
|
-
|
|
10
|
-
See also: [`gamut-system-props`](../gamut-system-props/SKILL.md) — `system.space`, responsive `Box` / `FlexBox` / `GridBox` props. [Meta / Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page) — responsive examples.
|
|
11
|
-
|
|
12
|
-
## System props for spacing
|
|
13
|
-
|
|
14
|
-
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`.
|
|
15
|
-
|
|
16
|
-
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.
|
|
17
|
-
|
|
18
|
-
## Two different “grids”
|
|
19
|
-
|
|
20
|
-
- **Design / page grid** (12 columns, margins/gutters) — product layout; implement with [`LayoutGrid`](https://gamut.codecademy.com/?path=/docs-layouts-layoutgrid-layoutgrid--docs) and responsive `columnGap` / `rowGap` where appropriate.
|
|
21
|
-
- **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.
|
|
22
|
-
|
|
23
|
-
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).
|
|
24
|
-
|
|
25
|
-
## Spacing scale
|
|
26
|
-
|
|
27
|
-
All spacing is multiples of 4px on an 8px grid.
|
|
28
|
-
|
|
29
|
-
| Token | Value |
|
|
30
|
-
| ----- | ----- |
|
|
31
|
-
| `0` | 0 |
|
|
32
|
-
| `4` | 4px |
|
|
33
|
-
| `8` | 8px |
|
|
34
|
-
| `12` | 12px |
|
|
35
|
-
| `16` | 16px |
|
|
36
|
-
| `24` | 24px |
|
|
37
|
-
| `32` | 32px |
|
|
38
|
-
| `40` | 40px |
|
|
39
|
-
| `48` | 48px |
|
|
40
|
-
| `64` | 64px |
|
|
41
|
-
| `96` | 96px |
|
|
42
|
-
|
|
43
|
-
Use multiples of 8px for block-element spacing. Use 4px only for inline or typographic relationships.
|
|
44
|
-
|
|
45
|
-
## Border radius
|
|
46
|
-
|
|
47
|
-
| Token | Value | Use |
|
|
48
|
-
| ------ | ----- | ---------------------------------- |
|
|
49
|
-
| `none` | 0px | Square / non-interactive elements |
|
|
50
|
-
| `sm` | 2px | Subtle rounding, tags |
|
|
51
|
-
| `md` | 4px | Buttons, inputs, interactive cards |
|
|
52
|
-
| `lg` | 8px | Cards, panels |
|
|
53
|
-
| `xl` | 16px | Large cards, modals |
|
|
54
|
-
| `full` | 999px | Pills, avatars, circular elements |
|
|
55
|
-
|
|
56
|
-
## Breakpoints
|
|
57
|
-
|
|
58
|
-
Mobile-first. Styles apply from the named breakpoint and up.
|
|
59
|
-
|
|
60
|
-
| Token | Min-width | Max content width |
|
|
61
|
-
| -------- | --------- | ----------------- |
|
|
62
|
-
| _(base)_ | 0 | 288px |
|
|
63
|
-
| `xs` | 480px | 448px |
|
|
64
|
-
| `sm` | 768px | 704px |
|
|
65
|
-
| `md` | 1024px | 896px |
|
|
66
|
-
| `lg` | 1200px | 1072px |
|
|
67
|
-
| `xl` | 1440px | 1248px |
|
|
68
|
-
|
|
69
|
-
## Container query breakpoints
|
|
70
|
-
|
|
71
|
-
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.
|
|
72
|
-
|
|
73
|
-
| Key | Min container width |
|
|
74
|
-
| -------- | ------------------- |
|
|
75
|
-
| `c_base` | 1px |
|
|
76
|
-
| `c_xs` | 480px |
|
|
77
|
-
| `c_sm` | 768px |
|
|
78
|
-
| `c_md` | 1024px |
|
|
79
|
-
| `c_lg` | 1200px |
|
|
80
|
-
| `c_xl` | 1440px |
|
|
81
|
-
|
|
82
|
-
Requirements:
|
|
83
|
-
|
|
84
|
-
- A descendant of an element that establishes a container — e.g. parent `<FlexBox containerType="inline-size">`. Without that, `c_*` rules never match.
|
|
85
|
-
- Prefer a viewport fallback alongside `c_*` (e.g. `display={{ _: 'block', sm: 'flex', c_md: 'grid' }}`) for browsers or trees without container support.
|
|
86
|
-
|
|
87
|
-
When to use which:
|
|
88
|
-
|
|
89
|
-
- Viewport keys (`_`, `xs`, … `xl`) — page-level layout, full-bleed sections, global nav.
|
|
90
|
-
- Container keys (`c_base`, … `c_xl`) — reusable widgets whose width is driven by layout, not the device alone.
|
|
91
|
-
|
|
92
|
-
## Page layout grid (12 columns)
|
|
93
|
-
|
|
94
|
-
12-column grid at all breakpoints.
|
|
95
|
-
|
|
96
|
-
| Property | xl/lg | md | sm/xs | base |
|
|
97
|
-
| ------------------ | ----- | ---- | ----- | ---- |
|
|
98
|
-
| Horizontal margins | 64px | 48px | 32px | 16px |
|
|
99
|
-
| Column gutters | 32px | 24px | 16px | 8px |
|
|
100
|
-
| Row gaps | 32px | 24px | 16px | 8px |
|
|
101
|
-
|
|
102
|
-
Minimum touch target on mobile: 44×44px — see [`gamut-accessibility`](../gamut-accessibility/SKILL.md).
|
|
103
|
-
|
|
104
|
-
## Responsive rules
|
|
105
|
-
|
|
106
|
-
- Begin design work at 1440px (XL), then adapt down.
|
|
107
|
-
- Multi-column layouts collapse to fewer columns — do not stretch or squish.
|
|
108
|
-
- Catalog cards and non-lockup elements should align on one axis (usually left), not fill column widths.
|
|
109
|
-
- Avoid dense or small components at the base (mobile) breakpoint.
|
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: gamut-list
|
|
3
|
-
description: Use this skill when building list or table layouts with List, ListRow, ListCol, and TableHeader — including variant and spacing selection, expandable row patterns, ordered/table layouts, and the rule that a list of disclosure-style items must use List's expandable row pattern (not multiple Disclosure components). See gamut-accessibility for ARIA and focus guidance.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Gamut List
|
|
7
|
-
|
|
8
|
-
Structured, repeating layouts built from `List`, `ListRow`, `ListCol`, and `TableHeader`. Colors, borders, and spacing are wired through the `variant` and `spacing` props — consumers do not override these with raw CSS values.
|
|
9
|
-
|
|
10
|
-
Source: `@codecademy/gamut` — [List.tsx](https://github.com/Codecademy/gamut/blob/main/packages/gamut/src/List/List.tsx)
|
|
11
|
-
|
|
12
|
-
See also: [`gamut-accessibility`](../gamut-accessibility/SKILL.md) — ARIA, focus, and keyboard interaction rules. [`gamut-layout`](../gamut-layout/SKILL.md) — spacing tokens and system props.
|
|
13
|
-
|
|
14
|
-
Storybook:
|
|
15
|
-
|
|
16
|
-
- [Organisms / Lists & Tables / List](https://gamut.codecademy.com/?path=/docs-organisms-lists-tables-list-list--docs)
|
|
17
|
-
- [ListRow](https://gamut.codecademy.com/?path=/docs-organisms-lists-tables-list-listrow--docs)
|
|
18
|
-
- [ListCol](https://gamut.codecademy.com/?path=/docs-organisms-lists-tables-list-listcol--docs)
|
|
19
|
-
|
|
20
|
-
## Components
|
|
21
|
-
|
|
22
|
-
```tsx
|
|
23
|
-
import { List, ListRow, ListCol, TableHeader } from '@codecademy/gamut';
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
| Component | Role |
|
|
27
|
-
| ------------- | ----------------------------------------------------------------------- |
|
|
28
|
-
| `List` | Root wrapper; sets `variant`, `spacing`, `as`, and context for children |
|
|
29
|
-
| `ListRow` | Single row; handles expandable content and click interactions |
|
|
30
|
-
| `ListCol` | Column cell; controls `type`, `size`, `fill`, and justification |
|
|
31
|
-
| `TableHeader` | Sticky header row; use only with `List as="table"` |
|
|
32
|
-
|
|
33
|
-
## When to use List
|
|
34
|
-
|
|
35
|
-
- Displaying repetitive content where individual rows may contain interactive elements, metrics, or controls — use List, not Card.
|
|
36
|
-
- Comparing data across rows — use `variant="table"` (or `as="table"`) rather than a plain `<table>`.
|
|
37
|
-
- Needing numbered rows — use `as="ol"`.
|
|
38
|
-
- **Needing multiple expandable/disclosure-style items** — use List's expandable row pattern (see [Expandable rows](#expandable-rows)), not multiple standalone `Disclosure` components.
|
|
39
|
-
|
|
40
|
-
## Variants
|
|
41
|
-
|
|
42
|
-
```tsx
|
|
43
|
-
<List variant="default" />
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
| `variant` | Use for |
|
|
47
|
-
| --------- | ------------------------------------------------------------------------------------------------------- |
|
|
48
|
-
| `default` | Rows with abstract content (buttons, custom renders); bordered, no gutter |
|
|
49
|
-
| `table` | Metrics or comparable data; alternating row backgrounds |
|
|
50
|
-
| `card` | Content that doesn't need to be adjacent (e.g. curriculum progress); bordered rows with vertical gutter |
|
|
51
|
-
| `block` | Feature-forward designs or page scaffolding; always on a colored background |
|
|
52
|
-
| `plain` | Minimal styling — no borders or backgrounds; apply custom styles per row via Emotion `styled` |
|
|
53
|
-
|
|
54
|
-
## Spacing
|
|
55
|
-
|
|
56
|
-
```tsx
|
|
57
|
-
<List spacing="condensed" />
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
| `spacing` | Use for |
|
|
61
|
-
| ----------- | -------------------------------------------- |
|
|
62
|
-
| `normal` | Mixed content that needs room for components |
|
|
63
|
-
| `condensed` | Default choice; reduced padding between rows |
|
|
64
|
-
| `compact` | Tightest layout; data-dense views |
|
|
65
|
-
|
|
66
|
-
## `as` prop
|
|
67
|
-
|
|
68
|
-
Default is `ul`. Pass `as="ol"` for numbered rows or `as="table"` for semantic table output.
|
|
69
|
-
|
|
70
|
-
```tsx
|
|
71
|
-
// ordered list — always include one ListCol with type="header" so numbering renders correctly
|
|
72
|
-
<List as="ol">
|
|
73
|
-
<ListRow>
|
|
74
|
-
<ListCol type="header">Step one</ListCol>
|
|
75
|
-
<ListCol>Details</ListCol>
|
|
76
|
-
</ListRow>
|
|
77
|
-
</List>
|
|
78
|
-
|
|
79
|
-
// semantic table with sticky header
|
|
80
|
-
<List as="table">
|
|
81
|
-
<TableHeader>
|
|
82
|
-
<ListCol columnHeader>Name</ListCol>
|
|
83
|
-
<ListCol columnHeader>Role</ListCol>
|
|
84
|
-
</TableHeader>
|
|
85
|
-
<ListRow>
|
|
86
|
-
<ListCol type="header">Worf</ListCol>
|
|
87
|
-
<ListCol>Lieutenant Commander</ListCol>
|
|
88
|
-
</ListRow>
|
|
89
|
-
</List>
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
## Key props
|
|
93
|
-
|
|
94
|
-
### List
|
|
95
|
-
|
|
96
|
-
| Prop | Type | Default | Effect |
|
|
97
|
-
| ----------------------- | ------------------------------------------------------ | ----------- | -------------------------------------------------------- |
|
|
98
|
-
| `variant` | `'default' \| 'table' \| 'card' \| 'block' \| 'plain'` | `'default'` | Row styling |
|
|
99
|
-
| `spacing` | `'normal' \| 'condensed' \| 'compact'` | `'normal'` | Row padding |
|
|
100
|
-
| `as` | `'ul' \| 'ol' \| 'table'` | `'ul'` | Rendered element and semantic meaning |
|
|
101
|
-
| `header` | `React.ReactNode` | — | Node rendered above the row list |
|
|
102
|
-
| `emptyMessage` | `React.ReactNode` | — | Shown when children is empty |
|
|
103
|
-
| `loading` | `boolean` | — | Shows placeholder while data loads |
|
|
104
|
-
| `scrollable` | `boolean` | `false` | Enables horizontal scroll with sticky first column |
|
|
105
|
-
| `shadow` | `boolean` | `false` | Right-side shadow when scrollable content overflows |
|
|
106
|
-
| `disableContainerQuery` | `boolean` | `false` | Falls back to media queries instead of container queries |
|
|
107
|
-
| `rowBreakpoint` | `'xs' \| 'sm' \| 'md'` | `'xs'` | Breakpoint at which columns stack |
|
|
108
|
-
|
|
109
|
-
### ListRow
|
|
110
|
-
|
|
111
|
-
| Prop | Type | Notes |
|
|
112
|
-
| -------------------------- | ----------------------- | ----------------------------------------------------------------------- |
|
|
113
|
-
| `expanded` | `boolean` | Required when `renderExpanded` is set |
|
|
114
|
-
| `renderExpanded` | `() => React.ReactNode` | Content revealed when `expanded` is true; animates in/out |
|
|
115
|
-
| `expandedRowAriaLabel` | `string` | `aria-label` for the revealed region |
|
|
116
|
-
| `keepSpacingWhileExpanded` | `boolean` | Maintains row spacing while content is expanded |
|
|
117
|
-
| `onClick` | mouse event handler | Makes the full row interactive (adds `role="button"`, keyboard support) |
|
|
118
|
-
|
|
119
|
-
### ListCol `type`
|
|
120
|
-
|
|
121
|
-
| `type` | Use for |
|
|
122
|
-
| --------------- | ------------------------------------------------------ |
|
|
123
|
-
| `header` | Primary label column; sticky when `List` is scrollable |
|
|
124
|
-
| `content` | Secondary text content |
|
|
125
|
-
| `control` | Action controls (buttons, menus) |
|
|
126
|
-
| `expand` | Expanded content area |
|
|
127
|
-
| `expandControl` | The toggle button column (no right-padding) |
|
|
128
|
-
| `select` | Checkbox / selection column |
|
|
129
|
-
|
|
130
|
-
### ListCol `size`
|
|
131
|
-
|
|
132
|
-
`'content'` (default, fits content) | `'sm'` | `'md'` | `'lg'` | `'xl'`
|
|
133
|
-
|
|
134
|
-
Pass `fill` to grow a column to fill remaining space.
|
|
135
|
-
|
|
136
|
-
## Expandable rows
|
|
137
|
-
|
|
138
|
-
List provides two patterns for rows that reveal content. Both animate open/closed via framer-motion.
|
|
139
|
-
|
|
140
|
-
### Expand on button click
|
|
141
|
-
|
|
142
|
-
Use `ExpandControl` in a `type="expandControl"` column to toggle a specific row.
|
|
143
|
-
|
|
144
|
-
```tsx
|
|
145
|
-
const [isExpanded, setExpanded] = useState(false);
|
|
146
|
-
|
|
147
|
-
<ListRow
|
|
148
|
-
expanded={isExpanded}
|
|
149
|
-
renderExpanded={() => <Text>Revealed content</Text>}
|
|
150
|
-
expandedRowAriaLabel="Row details"
|
|
151
|
-
>
|
|
152
|
-
<ListCol type="header">Row label</ListCol>
|
|
153
|
-
<ListCol type="content">Secondary detail</ListCol>
|
|
154
|
-
<ListCol type="expandControl">
|
|
155
|
-
<ExpandControl
|
|
156
|
-
expanded={isExpanded}
|
|
157
|
-
onExpand={() => setExpanded(!isExpanded)}
|
|
158
|
-
/>
|
|
159
|
-
</ListCol>
|
|
160
|
-
</ListRow>;
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
### Expand on row click
|
|
164
|
-
|
|
165
|
-
Pass `onClick` to `ListRow` to make the entire row the toggle target. The row receives `role="button"` and keyboard Enter support automatically.
|
|
166
|
-
|
|
167
|
-
```tsx
|
|
168
|
-
const [isExpanded, setExpanded] = useState(false);
|
|
169
|
-
|
|
170
|
-
<ListRow
|
|
171
|
-
expanded={isExpanded}
|
|
172
|
-
onClick={() => setExpanded(!isExpanded)}
|
|
173
|
-
renderExpanded={() => <Text>Revealed content</Text>}
|
|
174
|
-
>
|
|
175
|
-
<ListCol type="header">Row label</ListCol>
|
|
176
|
-
<ListCol type="content">Secondary detail</ListCol>
|
|
177
|
-
<ListCol type="control">
|
|
178
|
-
<Rotation rotated={isExpanded}>
|
|
179
|
-
<ArrowChevronDownIcon color="text-disabled" />
|
|
180
|
-
</Rotation>
|
|
181
|
-
</ListCol>
|
|
182
|
-
</ListRow>;
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
## List of disclosure-style items
|
|
186
|
-
|
|
187
|
-
When you need multiple expandable items (an FAQ, an accordion, a list of sections), **use List's expandable row pattern above — do not render multiple standalone `Disclosure` components**.
|
|
188
|
-
|
|
189
|
-
`Disclosure` is designed for a single, isolated expandable container. For two or more expandable items, the correct pattern is `List` + `ListRow` with `expanded` / `renderExpanded`:
|
|
190
|
-
|
|
191
|
-
```tsx
|
|
192
|
-
// correct — list of expandable items
|
|
193
|
-
<List variant="default" spacing="normal">
|
|
194
|
-
{items.map(({ id, title, body }) => {
|
|
195
|
-
const [isExpanded, setExpanded] = useState(false);
|
|
196
|
-
return (
|
|
197
|
-
<ListRow
|
|
198
|
-
key={id}
|
|
199
|
-
expanded={isExpanded}
|
|
200
|
-
renderExpanded={() => <Box p={16}>{body}</Box>}
|
|
201
|
-
expandedRowAriaLabel={`${title} details`}
|
|
202
|
-
>
|
|
203
|
-
<ListCol type="header" fill>{title}</ListCol>
|
|
204
|
-
<ListCol type="expandControl">
|
|
205
|
-
<ExpandControl
|
|
206
|
-
expanded={isExpanded}
|
|
207
|
-
onExpand={() => setExpanded(!isExpanded)}
|
|
208
|
-
/>
|
|
209
|
-
</ListCol>
|
|
210
|
-
</ListRow>
|
|
211
|
-
);
|
|
212
|
-
})}
|
|
213
|
-
</List>
|
|
214
|
-
|
|
215
|
-
// wrong — multiple Disclosure components
|
|
216
|
-
<Disclosure heading="Item 1" body="..." />
|
|
217
|
-
<Disclosure heading="Item 2" body="..." />
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
## Empty state and loading
|
|
221
|
-
|
|
222
|
-
```tsx
|
|
223
|
-
// custom empty message
|
|
224
|
-
<List emptyMessage={<Text>No results found.</Text>}>
|
|
225
|
-
{rows}
|
|
226
|
-
</List>
|
|
227
|
-
|
|
228
|
-
// loading placeholder
|
|
229
|
-
<List loading>{rows}</List>
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
## Scrollable layout
|
|
233
|
-
|
|
234
|
-
Use `scrollable` when a list has many columns and collapsing would lose information. The first (`type="header"`) column sticks to the left.
|
|
235
|
-
|
|
236
|
-
```tsx
|
|
237
|
-
<List scrollable shadow>
|
|
238
|
-
<TableHeader>
|
|
239
|
-
<ListCol type="header" columnHeader>
|
|
240
|
-
Name
|
|
241
|
-
</ListCol>
|
|
242
|
-
<ListCol size="md" columnHeader>
|
|
243
|
-
Score
|
|
244
|
-
</ListCol>
|
|
245
|
-
<ListCol size="md" columnHeader>
|
|
246
|
-
Progress
|
|
247
|
-
</ListCol>
|
|
248
|
-
</TableHeader>
|
|
249
|
-
{rows}
|
|
250
|
-
</List>
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
## Container queries
|
|
254
|
-
|
|
255
|
-
By default `List` uses CSS container queries for responsive column stacking. Disable only when:
|
|
256
|
-
|
|
257
|
-
- The `List` lives in a container narrower than its breakpoint
|
|
258
|
-
- You are managing your own responsive logic
|
|
259
|
-
- The list has very few rows and container query overhead is unwanted
|
|
260
|
-
|
|
261
|
-
```tsx
|
|
262
|
-
<List disableContainerQuery spacing="condensed">
|
|
263
|
-
{rows}
|
|
264
|
-
</List>
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
## Accessibility
|
|
268
|
-
|
|
269
|
-
- `ListRow` sets `aria-live="polite"` automatically when `renderExpanded` is present — do not add a duplicate live region.
|
|
270
|
-
- Pass `expandedRowAriaLabel` to label the revealed `role="region"`.
|
|
271
|
-
- `onClick` on `ListRow` adds `role="button"` and keyboard Enter support automatically.
|
|
272
|
-
- For sortable columns pass `aria-sort` on the relevant `ListCol`.
|
|
273
|
-
- Ordered lists (`as="ol"`) must include at least one `ListCol type="header"` per row for numbering to render correctly.
|