@spark-web/design-system
Version:
--- title: Design System ---
275 lines (196 loc) • 10.5 kB
Markdown
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with
code in this repository.
## Overview
Spark Web is the Brighte Design System — a React component library organized as
a Yarn monorepo (~50 packages). It uses Preconstruct for bundling, Emotion for
CSS-in-JS, and Changesets for versioning.
## Common Commands
```bash
# Development
yarn dev # Run docs, playroom, and storybook concurrently
yarn dev:storybook # Storybook only (port 6006)
yarn dev:docs # Next.js docs site only
yarn dev:playroom # Playroom only
# Testing
yarn test:unit # Run all Jest tests
yarn test:unit -- --testPathPatterns=packages/alert # Run tests for a specific package
yarn check # Run format + lint + package + type checks
# Linting & Formatting
yarn check:lint # ESLint check
yarn fix:lint # ESLint autofix
yarn check:format # Prettier check
yarn fix:format # Prettier autoformat
# Build
yarn build:packages # Build all packages via Preconstruct
yarn build:docs # Build docs site
# Package management
yarn new:package # Scaffold a new component package via Plop
yarn release # Build + publish to npm (CI only)
```
## How to approach any build task
When given any build task — whether a PRD, a feature description, or a prompt —
always follow this sequence before writing any code. Do not skip steps. Do not
ask for clarification before completing step 1.
### Step 1 — Classify the surface
Read node_modules/@spark-web/design-system/patterns/CLAUDE.md in full. Determine
which surface type the task is for based on language in the PRD:
- "admin portal", "admin", "internal", "back office", "manage", "ops" → Internal
admin
- "vendor portal", "vendor", "accreditation", "installer" → Vendor portal (not
yet defined — flag to team)
- "website", "marketing", "landing page", "public" → Website (not yet defined —
flag to team)
- "mobile", "app", "iOS", "Android" → Mobile app (not yet defined — flag to
team)
If the surface cannot be determined from the PRD, flag it and ask before
proceeding. Do not assume.
### Step 2 — Read the surface rules
Read the surface rules file for the classified surface. For internal admin: read
node_modules/@spark-web/design-system/patterns/internal-admin/CLAUDE.md in full.
Surface rules take precedence over all component rules.
If the surface is not yet defined, flag it to the team and do not proceed with
building until the surface rules exist.
### Step 3 — Identify the feature type and read the pattern file
Match the task to a pattern file in the surface folder:
- List of records, manage, view all, search, filter →
node_modules/@spark-web/design-system/patterns/internal-admin/list-page.md
- Create or edit a record, form →
node_modules/@spark-web/design-system/patterns/internal-admin/form-page.md
(not yet defined)
- Record detail, view details, drill down →
node_modules/@spark-web/design-system/patterns/internal-admin/detail-page.md
(not yet defined)
Read the pattern file in full. It defines which components to assemble, in what
order, and with what rules. Follow it exactly.
If no pattern file exists for the feature type, use the surface rules and
component documentation to make the best decision, then flag that a pattern file
should be created for this feature type before the next similar build.
### Step 4 — Read the relevant component CLAUDE.md files
Only read the components the pattern file tells you to use. Do not read all
component files — only the ones needed for this specific feature.
### Step 5 — Read the component stories
Read the Storybook story file for each component you will use. Stories show
correct real-world usage examples that the CLAUDE.md documentation alone may not
fully cover.
### Step 6 — Assemble, do not invent
Use only components that exist in packages/. Do not build custom components or
apply custom styling outside of the documented exceptions in each component
CLAUDE.md.
If a feature requires something that does not exist in packages/:
- Use the closest available Spark primitive as a placeholder
- Add a comment in the generated code: // COMPONENT GAP: [ComponentName] needed
— not yet in Spark
- Flag it clearly in your response as a gap to be formalised into the design
system before this feature ships
### Step 7 — Validate before marking complete
Run the validation checklist from the pattern file before marking the task
complete. Fix all violations before responding. A task is not complete until all
checklist items pass.
---
## Uplift protocol
When uplifting an existing page to match a pattern, follow the same 7 steps but
with these additions:
Before Step 6, run the pattern's validation checklist against the existing file.
Report every PASS and FAIL. This is mandatory — do not skip it.
If any checklist failure requires changing the component tree structure — such
as replacing a custom component with a Spark component, restructuring how
columns are defined, or replacing a custom loading/empty pattern with a built-in
prop — scaffold a new file using the structural skeleton from the pattern file
and migrate data and logic into it. Do not patch the existing file
incrementally.
If all failures are prop-level or styling fixes that do not change the component
tree, you may modify the existing file in place.
In either case, the pattern file is authoritative. Do not preserve existing
structure that conflicts with the pattern. Treat the current implementation as
data input (what fields exist, what the page does), not as a structural
reference.
Before writing any code, state whether you are (a) rebuilding from the pattern's
structural skeleton or (b) modifying in place, and justify your choice by
listing which failures are structural versus prop-level.
---
## Architecture
The agent reading order for any build task is defined in "How to approach any
build task" above. Always follow that sequence. Never jump directly to component
documentation without first reading the surface classifier and pattern files.
### Monorepo Structure
- `packages/` — ~50 component packages, each published as `@spark-web/{name}`
- `docs/` — Next.js documentation site with Storybook, Playroom, and
Contentlayer
- `examples/` — Reference Next.js apps (example-site, preapprovals)
- `scripts/` + `plop-templates/` — Package scaffolding
### Dependency Layers
**Foundation** (no internal deps): `utils`, `theme`, `ssr`
**Core components**: `a11y`, `box`, `text`, `icon` — depend on foundation
**Composition layer**: Layout (`stack`, `row`, `columns`, `container`,
`inline`), form inputs, complex components — compose from core
**Integration**: `next-utils`, `design-system` (barrel re-export of all
packages)
### Component Package Structure
Each package under `packages/{name}/src/` typically contains:
- `{ComponentName}.tsx` — Main component
- `{component-name}.stories.tsx` — Storybook stories
- `{component-name}.test.tsx` — Jest + Testing Library unit tests
- `types.ts` — Shared type definitions
- `index.ts` — Public exports
Preconstruct generates dual CJS/ESM bundles in `dist/`.
### Styling
All styling uses Emotion (CSS-in-JS). Components access the design token system
via `useTheme()` from `@spark-web/theme`. The theme provides color tones
(primary, secondary, positive, caution, critical, info), typography scales, and
spacing utilities. Never use raw CSS values — always use theme tokens.
### Key Patterns
- **Composition**: Components are built by composing smaller components (Box,
Text, Icon, Row, Stack)
- **Responsive**: Use theme utilities and Facepaint for responsive styles — not
media query literals
- **Accessibility**: All components include proper ARIA attributes; use
`@spark-web/a11y` utilities
- **`data` prop**: Components support a `data` prop for test selectors and
analytics
- **TypeScript discriminated unions**: Used for related props that must appear
together (e.g., `onClose` requires `closeLabel`)
- **`forwardRef`**: Used on all interactive/DOM-exposed components
### Releases
Changesets manages versioning. To add a changeset for your PR: `yarn changeset`.
Snapshot releases can be triggered on a PR by commenting `/snapit`.
### Pattern library
Agent pattern and surface rules live in
`node_modules/@spark-web/design-system/patterns/`. Always read
`node_modules/@spark-web/design-system/patterns/CLAUDE.md` before any build
task.
## New packages (in progress)
### data-table
TanStack Table v8-based table. See node_modules/@spark-web/data-table/CLAUDE.md
before writing any code using this package. Exports a single `DataTable`
component — not composable sub-components.
Key rules:
- Single `DataTable` component, not composable sub-components
- Use `createColumnHelper` from this package for type-safe column defs
- Pagination handled externally — never put pagination inside DataTable
- All values from useTheme() tokens — never raw hex, px, or Tailwind
### meatball-menu
Three-dot dropdown for 2+ record-level actions. See
node_modules/@spark-web/meatball-menu/CLAUDE.md. Usage rules:
node_modules/@spark-web/design-system/patterns/internal-admin/CLAUDE.md.
### section-header
Section-level heading bar with optional action. See
node_modules/@spark-web/section-header/CLAUDE.md. Depends on:
@spark-web/status-badge, @spark-web/meatball-menu.
### status-badge
Standalone label pill with colored background and optional icon. No dot. See
node_modules/@spark-web/status-badge/CLAUDE.md. Tones: accent, positive,
caution, critical, info, neutral. Only used in PageHeader and SectionHeader via
their `statusBadge` prop — never in table status columns. Use @spark-web/badge
for table status columns and any dot+label pattern.
### base-edit-modal
Reusable modal shell for all edit and action modals. Pinned header + scrollable
body + pinned footer. Depends on: @spark-web/modal-dialog. Never pass
scrollable={false}. Never use control as a prop.
### portal-table
Label/value display component for structured record data in admin interfaces.
Not a data table — use @spark-web/data-table for sortable paginated lists.
Depends on: @spark-web/stack, @spark-web/box, @spark-web/row,
@spark-web/heading, @spark-web/button, @spark-web/text-link, @spark-web/text,
@spark-web/meatball-menu, @spark-web/inline. rows prop is a typed array — never
JSX children.