UNPKG

@spark-web/design-system

Version:

--- title: Design System ---

275 lines (196 loc) 10.5 kB
# 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 externallynever put pagination inside DataTable - All values from useTheme() tokensnever 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` propnever 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.