diff --git a/.atl/AGENTS.md b/.atl/AGENTS.md index 9dfacfd5..e79e1e74 100644 --- a/.atl/AGENTS.md +++ b/.atl/AGENTS.md @@ -21,7 +21,7 @@ Keep it minimal — detailed workflows live in skills (`.atl/skills/`). **Stack**: React 19 · TypeScript strict · Tailwind v4 `@theme` · Radix UI · CVA · Storybook 8 · Biome · Lefthook · Vite · pnpm **Available tooling**: -- `compilot-cli` — scaffolds the 5-file component structure +- `compilot-cli` — scaffolds the 6-file component structure - `pnpm run storybook` — starts Storybook with hot reload - `pnpm run test` — runs Vitest unit tests - `pnpm run test:coverage` — runs tests with coverage report @@ -30,15 +30,16 @@ Keep it minimal — detailed workflows live in skills (`.atl/skills/`). ## Structure -Components live in `src/components/{atoms|molecules|organisms}/{kebab-name}/` with exactly 5 files: +Components live in `src/components/{atoms|molecules|organisms}/{kebab-name}/` with exactly 6 files: | File | Role | |------|------| | `ComponentName.tsx` | Presentational — JSX only, consumes the hook | | `useComponentName.ts` | Logic — state, effects, handlers, CVA class calls | | `types.ts` | Types + CVA variants | +| `ComponentName.test.tsx` | Complete test suite (hook + component tests) | +| `ComponentName.stories.tsx` | Storybook stories (documentation only, no tests) | | `index.ts` | Public API re-exports | -| `ComponentName.stories.tsx` | Storybook stories | --- @@ -48,10 +49,10 @@ Components live in `src/components/{atoms|molecules|organisms}/{kebab-name}/` wi - Never `any` — use `unknown` or narrow properly - Never hardcode colors, spacing or fonts — use tokens from `src/styles/theme.css` - Use Tailwind token classes directly — NEVER `[var(--token)]` when the token exists in `@theme` (e.g. `text-brand-light`, `rounded-pill`, `bg-red-tint-subtle`) +- `var()` is FORBIDDEN in component source files (`src/components/**/*.ts`, `src/components/**/*.tsx`) +- If a token or mixed visual treatment does not exist, define it centrally in `src/styles/theme.css` or `src/styles/base.css` as a reusable token-backed utility/class, then consume that class from the component - If a token does not exist for a value, CREATE it in `theme.css` first — never use raw `rgba()`, hex, or px values inline -- Exceptions where `var()` is acceptable (Tailwind cannot express these as utilities): - - `bg-gradient-*` — multi-stop gradient values (`--gradient-*` tokens) - - `shadow-glow-*` — multi-layer box-shadow values (`--glow-*` tokens) +- `var()` is only acceptable inside the style system (`src/styles/theme.css`, `src/styles/base.css`) to define reusable utilities such as `bg-gradient-*`, `shadow-glow-*`, or semantic component helper classes - Token reference: `docs/DESIGN.md` — read it before building any component - Never modify `theme.css` without explicit user confirmation - Never add dependencies without explicit user confirmation diff --git a/.atl/skill-registry.md b/.atl/skill-registry.md index 9066459f..d7d1af94 100644 --- a/.atl/skill-registry.md +++ b/.atl/skill-registry.md @@ -46,17 +46,20 @@ Each skill has a "When Delegated by SDD Orchestrator" section that defines: ### component-contributor **Load when**: contributor shares a GitHub issue URL or spec and asks to implement a component. -**Workflow**: Phase 0 (onboarding) → Phase 1 (read spec) → Phase 1.5 (spec review — critique before committing) → Phase 2 (plan + confirm) → Phase 3 (implement 5 files) → Phase 4 (explain inline) → Phase 5 (visual review) +**Workflow**: Phase 0 (onboarding) → Phase 1 (read spec) → Phase 1.5 (spec review — critique before committing) → Phase 2 (plan + confirm) → Phase 3 (implement 6 files) → Phase 4 (explain inline) → Phase 5 (visual review) **When delegated from SDD**: skip Phase 0, start from Phase 1, return SDD envelope. -**File order**: `types.ts` → `useComponentName.ts` → `ComponentName.tsx` → `ComponentName.stories.tsx` → `index.ts` +**File order**: `types.ts` → `useComponentName.ts` → `ComponentName.tsx` → `ComponentName.test.tsx` → `ComponentName.stories.tsx` → `index.ts` **Non-negotiables**: - CVA variants ONLY in `types.ts` - Logic ONLY in `useComponentName.ts` - JSX ONLY in `ComponentName.tsx` -- Tokens from `theme.css` only — no hardcoded values, no `[var(--token)]` when token exists in `@theme` +- Complete tests in `ComponentName.test.tsx` — hook tests + component tests, NO play functions in stories +- Stories in `ComponentName.stories.tsx` — documentation only, use `@storybook/addon-actions`, NO play functions +- Tokens from the style system only (`theme.css` / `base.css`) — no hardcoded values, no `[var(--token)]` when token exists in `@theme`, and no direct `var()` in component source files +- Reusable/systemic prop types belong in `src/types`; `component/types.ts` is only for component-specific types and CVA contracts - `type` always, never `interface`, never `any` - Explain every decision after each file - `Default` story args must NOT override `defaultVariants` diff --git a/.atl/skills/component-contributor/SKILL.md b/.atl/skills/component-contributor/SKILL.md index 81c0c971..cda4b84c 100644 --- a/.atl/skills/component-contributor/SKILL.md +++ b/.atl/skills/component-contributor/SKILL.md @@ -2,7 +2,7 @@ name: component-contributor description: > Guides an AI agent through implementing a design system component from a GitHub issue spec. - Covers the full contributor workflow: onboarding → read spec → plan → implement (5-file pattern) → explain decisions → visual review. + Covers the full contributor workflow: onboarding → read spec → plan → implement (6-file pattern) → explain decisions → visual review. Trigger: When a contributor provides a GitHub issue URL or pastes a component spec and asks to implement it. Also delegable from sdd-apply when implementing a component as part of a larger SDD change. license: Apache-2.0 @@ -52,10 +52,11 @@ Return your result in the SDD return envelope format: Before touching the spec, make sure the contributor understands the stack they are about to work with. Ask them to confirm they are familiar with: 1. **React + TypeScript strict** — `type` always, never `interface`, never `any` -2. **Tailwind v4 `@theme`** — token classes only (`text-brand-light`, `bg-surface-dark`); never raw hex, never `[var(--token)]` when the token exists in `@theme` +2. **Tailwind v4 `@theme`** — token classes only (`text-brand-light`, `bg-surface-dark`); never raw hex, never `[var(--token)]` when the token exists in `@theme`, and never `var()` inside component source files 3. **CVA (class-variance-authority)** — all variants live in `types.ts`, nowhere else -4. **The 5-file pattern** — each component has exactly: `types.ts`, `useComponentName.ts`, `ComponentName.tsx`, `ComponentName.stories.tsx`, `index.ts` -5. **Storybook 8** — stories are the living documentation AND the test suite +4. **The 6-file pattern** — each component has exactly: `types.ts`, `useComponentName.ts`, `ComponentName.tsx`, `ComponentName.test.tsx`, `ComponentName.stories.tsx`, `index.ts` +5. **Storybook 8** — stories are the living documentation (not the test suite — tests live in `.test.tsx`) +6. **Project story conventions** — autodocs behavior, action helper, and controls must match the repo's canonical stories exactly If the contributor is unfamiliar with any of these, briefly explain the concept before moving on. Do NOT assume knowledge — a contributor who copies code without understanding it is a liability, not an asset. @@ -163,8 +164,9 @@ Before writing any file, present a clear plan to the contributor: 1. `types.ts` — {X} props, {Y} CVA variants ({list variants}) 2. `useComponentName.ts` — {describe logic: state, handlers, aria} 3. `ComponentName.tsx` — presentational, consumes hook -4. `ComponentName.stories.tsx` — {N} stories: Default, Disabled, {variants} -5. `index.ts` — re-exports +4. `ComponentName.test.tsx` — complete component test suite (hook tests + component tests) +5. `ComponentName.stories.tsx` — {N} stories: Default, Disabled, {variants} +6. `index.ts` — re-exports ### Design decisions - Tokens used: {list tokens from theme.css} @@ -195,7 +197,8 @@ Load these BEFORE writing the relevant file. They contain canonical patterns ext | Module | Path | Load when | |--------|------|-----------| -| `testing` | `references/testing.md` | Writing any test file — Vitest or Storybook play function | +| `testing` | `references/testing.md` | Writing any test file — Vitest tests in `.test.tsx` | +| `stories` | `references/stories.md` | Writing or reviewing any `*.stories.tsx` file; Storybook autodocs/actions/controls conventions | | `html-extension` | `references/html-extension.md` | Component wraps a native HTML element (button, input, select, a, textarea) | | `radix-patterns` | `references/radix-patterns.md` | Component uses any `@radix-ui/*` primitive | | `tailwind-merge` | `references/tailwind-merge.md` | Component combines CVA output with conditional or external `className` | @@ -206,6 +209,11 @@ Load these BEFORE writing the relevant file. They contain canonical patterns ext - `biome-rules` — load before writing any `.ts` or `.tsx` file - `html-extension` — load for any component that renders a native element +**Mandatory story convention check:** +- Before writing `types.ts` or `ComponentName.stories.tsx`, read the project `stories` reference if it exists. +- If no dedicated `stories` reference exists, inspect at least ONE mature atom story already accepted in the repo and mirror its conventions exactly. +- Do NOT invent Storybook conventions from generic knowledge. + **Matching rules by component type:** | Component type | Colors | Spacing & Typography | Effects | @@ -224,9 +232,9 @@ Load these BEFORE writing the relevant file. They contain canonical patterns ext --- -## Phase 3 — Implement (5-file pattern) +## Phase 3 — Implement (6-file pattern) -Implement files in this order: `types.ts` → `useComponentName.ts` → `ComponentName.tsx` → `ComponentName.stories.tsx` → `index.ts` +Implement files in this order: `types.ts` → `useComponentName.ts` → `ComponentName.tsx` → `ComponentName.test.tsx` → `ComponentName.stories.tsx` → `index.ts` After each file, explain what was done and why (Phase 4 runs inline). @@ -234,9 +242,37 @@ After each file, explain what was done and why (Phase 4 runs inline). **Rules:** - ALL `type` definitions here — never `interface` +- Before declaring a new public/shared prop type in `component/types.ts`, check `src/types/index.ts` first; reusable design-system types must live in `src/types` +- Only keep types in `component/types.ts` when they are truly component-specific and not reusable across multiple components - ALL CVA variants here — never in `.tsx` or `.ts` hook files -- JSDoc `/** @control select */` on every prop that needs a Storybook control +- Every PUBLIC prop exposed in stories MUST have `@control` and `@default` (if applicable) JSDoc annotations +- JSDoc format for Storybook controls: + ```typescript + /** + * @control controlType + * @default defaultValue + */ + propName?: Type + ``` +- Props without defaults (e.g. callbacks, optional content) may omit `@default` - Import CVA from `class-variance-authority` +- Never use `[var(--token)]` when an equivalent Tailwind utility exists in `@theme` +- Never use `var()` directly in component source files; if Tailwind cannot express a token-backed visual treatment, define a reusable class/token in `src/styles/theme.css` or `src/styles/base.css` first + +**Available control types:** +- `@control text` — freeform text input +- `@control boolean` — toggle switch +- `@control number` — numeric input +- `@control range` — slider (specify min/max in description if needed) +- `@control select` — dropdown for single selection (requires `options` defined separately or inferred from type) +- `@control radio` — radio buttons for single selection +- `@control inline-radio` — inline radio buttons +- `@control check` — checkboxes for multiple selection +- `@control inline-check` — inline checkboxes +- `@control color` — color picker +- `@control date` — date picker +- `@control file` — file upload +- `@control object` — JSON editor for complex objects ```typescript import { cva, type VariantProps } from 'class-variance-authority' @@ -263,11 +299,19 @@ export const componentVariants = cva( ) export type ComponentProps = VariantProps & { - /** @control text */ + /** + * @control text + * @default Example + */ label?: string - /** @control boolean */ + /** + * @control boolean + * @default false + */ disabled?: boolean - /** Accessibility label for screen readers */ + /** + * @control text + */ ariaLabel?: string } ``` @@ -335,7 +379,51 @@ const Component: FC = (props) => { export default Component ``` -### File 4: `ComponentName.stories.tsx` +### File 4: `ComponentName.test.tsx` + +**Rules:** +- ALL tests here — both hook tests and component behavior tests +- Must test: hook logic with `renderHook`, component rendering with `render/screen`, ARIA attributes, user interactions with `userEvent`, disabled states +- All mocks declared BEFORE component imports +- Never test internal CSS class strings +- Load `references/testing.md` before writing this file + +```typescript +import { renderHook } from '@testing-library/react' +import { render, screen } from '@testing-library/react' +import userEvent from '@testing-library/user-event' +import { describe, expect, it, vi } from 'vitest' +import Component from './Component' +import useComponent from './useComponent' + +// Mocks first +vi.mock('lucide-react/dynamic', () => ({ + DynamicIcon: () => null +})) + +describe('useComponent — hook logic', () => { + it('returns default variant', () => { + const { result } = renderHook(() => useComponent({})) + expect(result.current.variant).toBe('default') + }) +}) + +describe('Component — behavior', () => { + it('renders correctly', () => { + render() + expect(screen.getByRole('button')).toBeInTheDocument() + }) + + it('calls onClick when clicked', async () => { + const handleClick = vi.fn() + render() + await userEvent.click(screen.getByRole('button')) + expect(handleClick).toHaveBeenCalledTimes(1) + }) +}) +``` + +### File 5: `ComponentName.stories.tsx` **Rules:** - English only — titles, descriptions, arg labels @@ -343,6 +431,12 @@ export default Component - Mandatory `args` on `Default` story — must NOT hardcode props that override `defaultVariants` - Always include: `Default`, `Disabled`, one story per key variant - Each story demonstrates ONE axis only — no mixed props across variants in the same story +- If `autodocs` is enabled for the project, do NOT define manual `argTypes` in `meta` or individual stories unless the project reference explicitly allows an exception +- Event handlers in stories must use `@storybook/addon-actions` (`action(...)`) — never invent a different helper +- Never use inline no-op handlers such as `() => undefined` in story args +- Token styling in stories must use Tailwind utility classes or reusable semantic classes from the style system; do not bypass them with `[var(--token)]` or inline `var()` in story/component source +- Story conventions must match the canonical repo pattern for autodocs, controls, and actions +- NO `play` functions — interaction testing belongs in `.test.tsx` ```typescript import type { Meta, StoryObj } from '@storybook/react' @@ -377,12 +471,11 @@ export const Disabled: Story = { } ``` -### File 5: `index.ts` +### File 6: `index.ts` ```typescript -import ComponentName from './ComponentName' +export { ComponentName } from './ComponentName' export * from './types' -export default ComponentName ``` --- @@ -457,10 +550,11 @@ Fix all CRITICAL and MAJOR before marking the component complete. ## Checklist before finishing **Structure** -- [ ] `types.ts` — all props typed, all CVA variants defined, JSDoc controls present +- [ ] `types.ts` — all props typed, all CVA variants defined, full JSDoc present, JSDoc controls present where needed - [ ] `useComponentName.ts` — all logic, no JSX, returns typed object - [ ] `ComponentName.tsx` — only JSX, consumes hook, no logic -- [ ] `ComponentName.stories.tsx` — Default + Disabled + variant stories, English, description present, no overriding defaultVariants in Default args +- [ ] `ComponentName.test.tsx` — complete test suite (hook tests with renderHook + component tests with render/screen/userEvent) +- [ ] `ComponentName.stories.tsx` — Default + Disabled + variant stories, English, description present, no overriding defaultVariants in Default args, canonical autodocs/actions conventions followed, NO play functions - [ ] `index.ts` — re-exports correct **Tokens & theming** diff --git a/.atl/skills/component-contributor/references/git-workflow.md b/.atl/skills/component-contributor/references/git-workflow.md index ec329248..8106c980 100644 --- a/.atl/skills/component-contributor/references/git-workflow.md +++ b/.atl/skills/component-contributor/references/git-workflow.md @@ -138,10 +138,10 @@ A PR will be rejected WITHOUT detailed feedback if: A PR is ready to merge when: - [ ] All CI checks pass (tests, build, a11y) -- [ ] 5-file architecture followed exactly +- [ ] 6-file architecture followed exactly - [ ] No `any`, no `interface` -- [ ] Tests cover hook logic + component behavior -- [ ] Story has args, controls, and description +- [ ] Tests in `.test.tsx` cover hook logic + component behavior +- [ ] Story has args, controls, and description (NO play functions) - [ ] No hardcoded values — only design tokens - [ ] ARIA attributes present and correct - [ ] PR template fully filled diff --git a/.atl/skills/component-contributor/references/radix-patterns.md b/.atl/skills/component-contributor/references/radix-patterns.md index b8cb2576..c76e8a29 100644 --- a/.atl/skills/component-contributor/references/radix-patterns.md +++ b/.atl/skills/component-contributor/references/radix-patterns.md @@ -60,7 +60,7 @@ const Dropdown: FC = ({ ...props }) => { role='menu' aria-labelledby={accessibleLabelId} className={cn( - 'min-w-[8rem] rounded-md border p-1', + 'min-w-32 rounded-md border p-1', 'bg-surface-light dark:bg-surface-dark', // Radix animation data attributes — use these, not custom state 'data-[state=closed]:animate-out data-[state=open]:animate-in', @@ -98,7 +98,7 @@ Key decisions: 'relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm', 'transition-[background,color] duration-150 ease-[ease]', 'hover:bg-white-tint-mid', - 'focus-visible:outline-none focus-visible:shadow-[var(--glow-focus-dark)]' + 'focus-visible:outline-none focus-visible:shadow-(--glow-focus-dark)' )} onClick={element.onClick} > @@ -224,6 +224,6 @@ import * as SelectPrimitive from '@radix-ui/react-select'; - [ ] Radix imported as namespace alias (`* as XxxPrimitive`) - [ ] Floating content wrapped in `Portal` - [ ] Trigger uses `asChild={true}` -- [ ] Focus ring uses `focus-visible:shadow-[var(--glow-focus-dark)]` — no outline +- [ ] Focus ring uses reusable glow classes such as `focus-visible:shadow-glow-focus-light dark:focus-visible:shadow-glow-focus-dark` — no outline - [ ] Animations use `data-[state=open/closed]` attributes - [ ] All open/close logic lives in the hook diff --git a/.atl/skills/component-contributor/references/stories.md b/.atl/skills/component-contributor/references/stories.md new file mode 100644 index 00000000..c933f8ad --- /dev/null +++ b/.atl/skills/component-contributor/references/stories.md @@ -0,0 +1,64 @@ +# Storybook Stories Reference + +Canonical conventions for `*.stories.tsx` in this repository. + +## Purpose + +Use this reference BEFORE writing or reviewing stories. Do not improvise Storybook conventions from generic defaults. + +## Non-negotiable rules + +- Use `autodocs`. +- Do **not** define manual `argTypes` in `meta` or individual stories unless there is a documented exception. +- Use `@storybook/addon-actions` with `action(...)` for event args. +- Never use inline no-op handlers like `() => undefined` in story args. +- Use Tailwind token utility classes from `@theme` or reusable semantic classes from the style system; do **not** use `[var(--token)]` or direct `var()` in stories. +- Keep all story text, descriptions, comments, and labels in English. +- `Default` story args must not override the component `defaultVariants`. +- Interactive components must include `Disabled` and interaction-focused stories as appropriate. +- NO `play` functions — interaction testing belongs in `ComponentName.test.tsx`. + +## Recommended structure + +```tsx +import type { Meta, StoryObj } from '@storybook/react'; +import { action } from '@storybook/addon-actions'; +import { Component } from './Component'; + +const meta: Meta = { + title: 'Atoms/Component', + component: Component, + parameters: { + docs: { + autodocs: true, + description: { + component: 'Concise English description of the component.' + } + } + }, + tags: ['autodocs'] +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + children: 'Example', + onClick: action('click') + } +}; +``` + +## Review checklist + +- Does the story rely on autodocs instead of custom `argTypes`? +- Are actions wired with `action(...)`? +- Are token utilities / semantic style-system classes used instead of `[var(--token)]` or direct `var()` bypasses? +- Are examples aligned with the canonical component API and public docs style? +- Does each story demonstrate one axis clearly? + +## Notes + +- If a future project decision changes the official actions helper or autodocs policy, update this reference FIRST, then update the affected skills. diff --git a/.atl/skills/component-contributor/references/testing.md b/.atl/skills/component-contributor/references/testing.md index a18d92a5..67e6834a 100644 --- a/.atl/skills/component-contributor/references/testing.md +++ b/.atl/skills/component-contributor/references/testing.md @@ -2,17 +2,20 @@ > Canonical source: `src/components/atoms/button/Button.test.tsx` > Testing stack: **Vitest** + **@testing-library/react** + **@testing-library/user-event** +> Test file: `ComponentName.test.tsx` (complete test suite in one file) --- -## Two-layer strategy +## Single-file strategy -Every component has TWO test layers. Both are mandatory. +Every component has ONE test file: `ComponentName.test.tsx` -| Layer | Tool | What it tests | File | -|-------|------|---------------|------| -| **Hook** | `renderHook` | Pure logic — no DOM | `useComponent.ts` | -| **Component** | `render` + `screen` + `userEvent` | Observable DOM behavior | `Component.tsx` | +This file contains TWO test suites: + +| Suite | Tool | What it tests | +|-------|------|---------------| +| **Hook** | `renderHook` | Pure logic — no DOM | +| **Component** | `render` + `screen` + `userEvent` | Observable DOM behavior | ### What to test - State values returned by the hook (disabled, isLoading, variant, etc.) @@ -148,30 +151,13 @@ expect(screen.getByRole('button', { name: 'Blocked' })).toHaveAttribute('aria-di --- -## Storybook play functions (visual interaction tests) +## Storybook stories -For interactive components, ALSO add a `play` function in the `.stories.tsx` file. -These run in a real browser via Playwright, unlike Vitest which runs in jsdom. +Stories are for visual documentation and design exploration — NOT for testing. -```tsx -import { expect, userEvent, within } from '@storybook/test'; -import type { Meta, StoryObj } from '@storybook/react'; -import { MyComponent } from './MyComponent'; - -export const Interactive: StoryObj = { - args: { text: 'Click me' }, - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - const button = canvas.getByRole('button', { name: /click me/i }); - - await expect(button).toBeInTheDocument(); - await userEvent.click(button); - // assert result - } -}; -``` - -Run Storybook tests: `pnpm test-storybook` +- NO `play` functions in stories +- NO interaction testing in Storybook +- ALL tests go in `ComponentName.test.tsx` --- @@ -180,9 +166,6 @@ Run Storybook tests: `pnpm test-storybook` ```bash # Vitest (unit + hook tests) pnpm test - -# Storybook interaction tests (requires Storybook running) -pnpm test-storybook ``` --- @@ -192,5 +175,5 @@ pnpm test-storybook - [ ] Hook tested with `renderHook` — all returned values and computed functions covered - [ ] Component tested with `render/screen/userEvent` — rendering, ARIA, interaction, disabled states - [ ] All required mocks declared BEFORE component imports -- [ ] Interactive component has a `play` function in its story +- [ ] All tests in `ComponentName.test.tsx` - [ ] `pnpm test` passes with no failures diff --git a/.atl/skills/components-auditor/SKILL.md b/.atl/skills/components-auditor/SKILL.md index cfde1a6a..99755694 100644 --- a/.atl/skills/components-auditor/SKILL.md +++ b/.atl/skills/components-auditor/SKILL.md @@ -2,7 +2,7 @@ name: components-auditor description: > Reviews existing components against Stack-and-Flow standards — both code quality and visual correctness. - Covers: 5-file pattern compliance, TypeScript conventions, token usage, CVA structure, Storybook stories, + Covers: 6-file pattern compliance, TypeScript conventions, token usage, CVA structure, tests, Storybook stories, and full visual state audit (glow, transitions, focus rings, accessibility). Trigger: When reviewing an existing component — code quality, visual states, tokens, or accessibility. Also delegable from sdd-verify as the verification gate for a component change. @@ -40,10 +40,11 @@ When delegated: run ALL audit phases and return in the SDD return envelope forma ### Compliance Matrix | Check | Status | Notes | |-------|--------|-------| -| 5-file pattern | ✅ / ❌ | | +| 6-file pattern | ✅ / ❌ | | | TypeScript conventions | ✅ / ❌ | | | Token usage | ✅ / ❌ | | | CVA structure | ✅ / ❌ | | +| Test coverage | ✅ / ❌ | | | Stories coverage | ✅ / ❌ | | | Visual states | ✅ / ❌ | | | Accessibility | ✅ / ❌ | | @@ -68,6 +69,7 @@ Always read in this order: 2. `docs/DESIGN.md` — visual token reference and component specs 3. `src/styles/theme.css` — source of truth for every token value 4. `docs/COMPONENTS.md` — state-by-state spec for every component (if it exists) +5. `.atl/skills/component-contributor/references/stories.md` — canonical Storybook autodocs/actions/controls conventions (if it exists) > **Never flag a token value as wrong without checking `theme.css` first.** @@ -75,13 +77,14 @@ Always read in this order: ## Phase 1 — Code Audit -### 1.1 — 5-File Pattern +### 1.1 — 6-File Pattern -Every component must have exactly these 5 files and nothing else: +Every component must have exactly these 6 files and nothing else: - [ ] `types.ts` — exists - [ ] `useComponentName.ts` — exists - [ ] `ComponentName.tsx` — exists +- [ ] `ComponentName.test.tsx` — exists - [ ] `ComponentName.stories.tsx` — exists - [ ] `index.ts` — exists - [ ] No extra files, no barrel re-exports outside `index.ts` @@ -89,11 +92,20 @@ Every component must have exactly these 5 files and nothing else: ### 1.2 — `types.ts` compliance - [ ] Only `type` declarations — never `interface` +- [ ] Shared/systemic prop types are imported from `src/types` when available; `component/types.ts` only defines component-specific types - [ ] ALL CVA variants defined here — none in `.tsx` or hook files - [ ] `cva` imported from `class-variance-authority` - [ ] `VariantProps` used to derive the props type -- [ ] JSDoc `/** @control select|text|boolean */` present on props that need Storybook controls -- [ ] No logic, no imports from React, no side effects +- [ ] Every public prop exposed in Storybook has JSDoc annotations: `@control type` and `@default value` (if applicable) +- [ ] JSDoc format: annotations only, no prose descriptions required + ```typescript + /** + * @control text + * @default Example + */ + propName?: string + ``` +- [ ] No logic, no side effects, and no React value imports in `types.ts` (type-only React imports are acceptable when needed for public prop typing) ### 1.3 — `useComponentName.ts` compliance @@ -112,17 +124,26 @@ Every component must have exactly these 5 files and nothing else: - [ ] No inline styles - [ ] No hardcoded class strings that belong in CVA -### 1.5 — Token usage +### 1.5 — `ComponentName.test.tsx` compliance + +- [ ] Contains both hook tests (with `renderHook`) and component tests (with `render/screen/userEvent`) +- [ ] All required mocks declared BEFORE component imports +- [ ] Tests cover: hook logic, DOM rendering, ARIA attributes, user interactions, disabled states +- [ ] No tests against internal CSS class strings +- [ ] No animation/ripple/spinner implementation tests + +### 1.6 — Token usage - [ ] No hardcoded hex values (`#ff0036`, `#060C13`, etc.) anywhere in the component files - [ ] No hardcoded spacing values (`px-4`, `mt-2` are fine as utilities; `mt-[13px]` is not) - [ ] No `[var(--token)]` when the token exists in `@theme` as a Tailwind utility class - Wrong: `bg-[var(--color-surface-dark)]` - Right: `bg-surface-dark` -- [ ] `var()` is ONLY acceptable for: `bg-gradient-*` tokens and `shadow-glow-*` tokens (multi-layer values Tailwind cannot express) +- [ ] No `var()` inside component source files (`src/components/**/*.ts`, `src/components/**/*.tsx`) +- [ ] If a component needs token-backed `color-mix()`, gradients, or multi-layer shadows, those values are defined in `src/styles/theme.css` / `src/styles/base.css` and consumed through semantic classes/utilities - [ ] All tokens referenced actually exist in `src/styles/theme.css` -### 1.6 — `ComponentName.stories.tsx` compliance +### 1.7 — `ComponentName.stories.tsx` compliance - [ ] `parameters.docs.description.component` present and in English - [ ] `Default` story has `args` that do NOT override `defaultVariants` @@ -130,14 +151,20 @@ Every component must have exactly these 5 files and nothing else: - [ ] One story per key variant axis (not one story mixing all variants) - [ ] No DOM manipulation in module scope (use `decorators` if needed) - [ ] English only — titles, descriptions, arg labels +- [ ] If project `autodocs` is enabled, manual `argTypes` in `meta` or individual stories are forbidden unless a documented project exception exists +- [ ] Story actions use `@storybook/addon-actions` (`action(...)`) only; no mixed conventions across stories +- [ ] No inline no-op handlers such as `() => undefined` in story args +- [ ] No `[var(--token)]` in stories when equivalent Tailwind utilities exist in `@theme` +- [ ] Story conventions match the canonical project reference/component pattern +- [ ] NO `play` functions — all interaction tests belong in `ComponentName.test.tsx` -### 1.7 — `index.ts` compliance +### 1.8 — `index.ts` compliance -- [ ] Exports the component as default: `export { default } from './ComponentName'` +- [ ] Re-exports the named component: `export { ComponentName } from './ComponentName'` - [ ] Re-exports types: `export * from './types'` - [ ] Nothing else -### 1.8 — TypeScript global rules +### 1.9 — TypeScript global rules - [ ] `strict: true` compliance — no implicit `any`, no loose types - [ ] No `as` type assertions unless absolutely unavoidable (comment why) @@ -166,7 +193,7 @@ Classify every finding with severity: - **CRITICAL** — Accessibility failure: missing focus ring, insufficient contrast, no disabled state, interactive element below 44px, `outline: none` without alternative, WCAG AA failure - **MAJOR** — Compositional rule violation: wrong file structure, CVA in wrong file, `[var(--token)]` bypass, `transition: all`, `border-image`, blur+gradient on same element, wrong glow layer count -- **MINOR** — Spec inconsistency: wrong transition duration, missing transition property, hover tint value slightly off, missing JSDoc control annotation +- **MINOR** — Spec inconsistency: wrong transition duration, missing transition property, hover tint value slightly off, missing JSDoc control annotation, incomplete prop JSDoc, non-canonical story actions/autodocs usage when it does not break behavior - **SUGGESTION** — Enhancement: `will-change` on entrance animations, extracting a repeated pattern to a token, improving story coverage ### Report format @@ -188,10 +215,11 @@ After listing all issues, provide a summary: | Category | Status | Issues | |----------|--------|--------| -| 5-file pattern | ✅ / ⚠️ / ❌ | {count} | +| 6-file pattern | ✅ / ⚠️ / ❌ | {count} | | TypeScript conventions | ✅ / ⚠️ / ❌ | {count} | | Token usage | ✅ / ⚠️ / ❌ | {count} | | CVA structure | ✅ / ⚠️ / ❌ | {count} | +| Test coverage | ✅ / ⚠️ / ❌ | {count} | | Stories coverage | ✅ / ⚠️ / ❌ | {count} | | Visual states | ✅ / ⚠️ / ❌ | {count} | | Accessibility | ✅ / ⚠️ / ❌ | {count} | diff --git a/.atl/skills/pr-reviewer/SKILL.md b/.atl/skills/pr-reviewer/SKILL.md index 2699d617..f20d580d 100644 --- a/.atl/skills/pr-reviewer/SKILL.md +++ b/.atl/skills/pr-reviewer/SKILL.md @@ -66,6 +66,7 @@ Report the failing criterion and stop — do not continue with the detailed chec | Hardcoded Tailwind arbitrary values | Grep for `p-[`, `m-[`, `text-[#`, `bg-[#`, `border-[#` in component files | | Missing tests | No `.test.tsx` file in the component directory | | Missing Storybook story | No `.stories.tsx` file in the component directory | +| Play functions in stories | Stories contain `play` functions — interaction tests belong in `.test.tsx` | --- @@ -73,16 +74,19 @@ Report the failing criterion and stop — do not continue with the detailed chec Run these only AFTER the automatic rejection check passes. +Before the Storybook review, read `.atl/skills/component-contributor/references/stories.md` if it exists. Treat it as the source of truth for autodocs/actions/controls conventions. + ### 1 — File structure -- [ ] Exactly 5 files: `types.ts`, `useComponentName.ts`, `ComponentName.tsx`, `ComponentName.stories.tsx`, `index.ts` +- [ ] Exactly 6 files: `types.ts`, `useComponentName.ts`, `ComponentName.tsx`, `ComponentName.test.tsx`, `ComponentName.stories.tsx`, `index.ts` - [ ] Directory name is `kebab-case` matching the component name - [ ] Correct atomic tier: `atoms/` | `molecules/` | `organisms/` -- [ ] `index.ts` re-exports the component default and all types +- [ ] `index.ts` re-exports the named component and all types ### 2 — TypeScript - [ ] All imports of types use `import type` +- [ ] Reusable design-system prop types come from `src/types` instead of being redefined locally in the component - [ ] All exports of types use `export type` - [ ] No `interface` — only `type` - [ ] No `any` — if present, must have documented justification @@ -102,7 +106,7 @@ Run these only AFTER the automatic rejection check passes. ### 4 — Architecture -- [ ] `types.ts` — all CVA variants defined here, all props typed, JSDoc controls present +- [ ] `types.ts` — all CVA variants defined here, all props typed, complete public-prop JSDoc present (description + `@control` + `@default`), JSDoc controls follow canonical format - [ ] `useComponentName.ts` — all state, effects, handlers, CVA calls live here; no JSX - [ ] `ComponentName.tsx` — only JSX; consumes hook; zero `useState`, `useRef`, or CVA calls - [ ] `cn()` imported from `@/lib/utils` — not `clsx` or `twMerge` directly @@ -126,11 +130,11 @@ Run these only AFTER the automatic rejection check passes. ### 7 — Tests +- [ ] Complete test suite in `ComponentName.test.tsx` - [ ] Hook tested with `renderHook` — all returned values and computed functions covered - [ ] Component tested with `render/screen/userEvent` — rendering, ARIA, interaction, disabled states - [ ] All mocks declared BEFORE component imports (`lucide-react/dynamic`, `spinners-react`, CSS files) - [ ] No tests against internal CSS class strings -- [ ] Interactive component has a `play` function in its story ### 8 — Storybook @@ -139,6 +143,13 @@ Run these only AFTER the automatic rejection check passes. - [ ] `Default` story has `args` set; does NOT override `defaultVariants` - [ ] At least: `Default`, `Disabled`, one story per key variant - [ ] Each story demonstrates ONE axis — no mixed-variant stories +- [ ] If project `autodocs` is enabled, no manual `argTypes` in `meta` or individual stories unless a documented project exception exists +- [ ] Story event actions use `@storybook/addon-actions` (`action(...)`) only +- [ ] No inline no-op handlers such as `() => undefined` in story args +- [ ] No `[var(--token)]` in stories when equivalent Tailwind utilities exist in `@theme` +- [ ] No direct `var()` in stories or component source; reusable token-backed classes must come from `src/styles/theme.css` / `src/styles/base.css` +- [ ] Story conventions match the canonical project story reference/pattern +- [ ] NO `play` functions — all interaction tests belong in `ComponentName.test.tsx` ### 9 — Visual states diff --git a/.storybook/manager.ts b/.storybook/manager.ts index c809bc2c..89c94bd3 100644 --- a/.storybook/manager.ts +++ b/.storybook/manager.ts @@ -1,6 +1,6 @@ -import theme from './theme'; import { addons } from '@storybook/manager-api'; +import theme from './theme'; addons.setConfig({ theme: theme -}); \ No newline at end of file +}); diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index 378e8a9e..8ce6704b 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -82,7 +82,7 @@ const preview: Preview = { ), disableInjectedStyles: true - }, + } } }; diff --git a/.storybook/theme.ts b/.storybook/theme.ts index cc1afa25..20ff0a7e 100644 --- a/.storybook/theme.ts +++ b/.storybook/theme.ts @@ -57,5 +57,5 @@ export default create({ inputBg: '#0F1824', inputBorder: '#172230', inputTextColor: '#ffffff', - inputBorderRadius: 8, + inputBorderRadius: 8 }); diff --git a/.storybook/tsconfig.json b/.storybook/tsconfig.json index 6e662d59..c3641d08 100644 --- a/.storybook/tsconfig.json +++ b/.storybook/tsconfig.json @@ -13,4 +13,4 @@ "types": ["vite/client", "node"] }, "include": ["../src", "./"] -} \ No newline at end of file +} diff --git a/compilot.config.json b/compilot.config.json index eee46d22..e6be9405 100644 --- a/compilot.config.json +++ b/compilot.config.json @@ -1,44 +1,44 @@ { - "config": { - "language": "typescript", - "generatedFiles": true, - "openFiles": true - }, - "components": { - "base": "src/components", - "atomic": true, - "naming": { - "folder": "kebabCase" - }, - "files": { - "types": "file", - "stories": true, - "test": true - } - }, - "pages": { - "base": "src/pages", - "routes": "src/app/Router.tsx", - "files": { - "types": "file", - "lazy": true - } - }, - "hooks": { - "base": "src/infrastructure/hooks", - "context": { - "file": "src/app/main.tsx", - "mode": "tree" - } - }, - "services": { - "base": "src/infrastructure/api", - "axios": "src/config/axios", - "types": "src/infrastructure/models/api", - "mocks": { - "enabled": true, - "data": "src/mocks/data", - "server": "src/mocks/mocksServer.ts" - } - } + "config": { + "language": "typescript", + "generatedFiles": true, + "openFiles": true + }, + "components": { + "base": "src/components", + "atomic": true, + "naming": { + "folder": "kebabCase" + }, + "files": { + "types": "file", + "stories": true, + "test": true + } + }, + "pages": { + "base": "src/pages", + "routes": "src/app/Router.tsx", + "files": { + "types": "file", + "lazy": true + } + }, + "hooks": { + "base": "src/infrastructure/hooks", + "context": { + "file": "src/app/main.tsx", + "mode": "tree" + } + }, + "services": { + "base": "src/infrastructure/api", + "axios": "src/config/axios", + "types": "src/infrastructure/models/api", + "mocks": { + "enabled": true, + "data": "src/mocks/data", + "server": "src/mocks/mocksServer.ts" + } + } } diff --git a/components.json b/components.json index 5de312e2..91ddefc6 100644 --- a/components.json +++ b/components.json @@ -18,4 +18,4 @@ "hooks": "@/hooks" }, "iconLibrary": "lucide" -} \ No newline at end of file +} diff --git a/docs/GUIDELINES.md b/docs/GUIDELINES.md index b8bfa9c3..acf181a2 100644 --- a/docs/GUIDELINES.md +++ b/docs/GUIDELINES.md @@ -149,6 +149,12 @@ export default Button; Usamos Tailwind v4 con configuraciones `@theme` definidas en `src/styles/theme.css`. +### Breakpoints responsivos (Tailwind only) + +- **Fuente de verdad**: usa únicamente prefijos nativos de Tailwind: `sm`, `md`, `lg`, `xl`, `2xl`. +- **Prohibido** introducir o reutilizar aliases custom de breakpoints (por ejemplo `tablet`, `desktop`). +- Si un ajuste responsive requiere un corte intermedio y no hay evidencia fuerte en contra, usa `md` como punto de partida conservador. + - **OBLIGATORIO**: DEBES usar las propiedades CSS personalizadas del design system (tokens) mediante clases de Tailwind. - **SIN HARDCODING**: Nunca escribas colores en duro (ej: `#FF0000`), espaciados (`16px`, `1rem`) ni fuentes en estilos inline o clases Tailwind arbitrarias (ej: `text-[#fce9ea]`). - Usa las clases predefinidas: `text-text-dark`, `bg-secondary`, `gap-sm`, `fs-h1`, etc. diff --git a/lefthook.yml b/lefthook.yml index 6be60689..641a8906 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -2,7 +2,13 @@ pre-commit: parallel: false commands: biome: - glob: "**/*.{ts,tsx,js,jsx,css}" - run: "pnpm exec biome check --write --staged {staged_files}" + glob: "*.{ts,tsx,js,jsx,json,css}" + run: pnpm exec biome check --write --no-errors-on-unmatched --files-ignore-unknown=true {staged_files} + stage_fixed: true typecheck: run: "pnpm exec tsc --noEmit" +pre-push: + parallel: false + commands: + test: + run: "pnpm exec vitest run --run" \ No newline at end of file diff --git a/package.json b/package.json index 131faa75..12b5989f 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "clean": "node -e \"['dist','node_modules','pnpm-lock.yaml','package-lock.json'].forEach(p=>require('fs').rmSync(p,{recursive:true,force:true}))\" && npm cache clean --force", "reinstall": "pnpm run clean && pnpm install", "biome-all": "biome check --write .", - "biome-staged": "biome check . --write --staged --verbose", + "biome-staged": "biome check --write --no-errors-on-unmatched --files-ignore-unknown=true", "storybook": "storybook dev -p 6006", "storybook-build": "storybook build && node scripts/inject-preview-head.js", "storybook-clean-cache": "node -e \"require('fs').rmSync('node_modules/.cache/storybook',{recursive:true,force:true})\"", @@ -104,4 +104,4 @@ "vite-tsconfig-paths": "6.1.1", "vitest": "2.1.8" } -} \ No newline at end of file +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e84a9dea..aa895057 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2369,8 +2369,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.10.21: - resolution: {integrity: sha512-Q+rUQ7Uz8AHM7DEaNdwvfFCTq7a43lNTzuS94eiWqwyxfV/wJv+oUivef51T91mmRY4d4A1u9rcSvkeufCVXlA==} + baseline-browser-mapping@2.10.22: + resolution: {integrity: sha512-6qruVrb5rse6WylFkU0FhBKKGuecWseqdpQfhkawn6ztyk2QlfwSRjsDxMCLJrkfmfN21qvhl9ABgaMeRkuwww==} engines: {node: '>=6.0.0'} hasBin: true @@ -7241,7 +7241,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.10.21: {} + baseline-browser-mapping@2.10.22: {} better-opn@3.0.2: dependencies: @@ -7276,7 +7276,7 @@ snapshots: browserslist@4.28.2: dependencies: - baseline-browser-mapping: 2.10.21 + baseline-browser-mapping: 2.10.22 caniuse-lite: 1.0.30001790 electron-to-chromium: 1.5.344 node-releases: 2.0.38 diff --git a/src/components/atoms/avatar/Avatar.tsx b/src/components/atoms/avatar/Avatar.tsx index 0c6d3e73..353a9e25 100644 --- a/src/components/atoms/avatar/Avatar.tsx +++ b/src/components/atoms/avatar/Avatar.tsx @@ -38,7 +38,7 @@ export const Avatar: FC = ({ ...props }) => { = ({ ...props }) => { { switch (fs) { case 'h1': - return 'fs-h1 tablet:fs-tablet-h1'; + return 'fs-h1'; case 'h2': - return 'fs-h2 tablet:fs-tablet-h2'; + return 'fs-h2'; case 'h3': - return 'fs-h3 tablet:fs-tablet-h3'; + return 'fs-h3'; case 'h4': - return 'fs-h4 tablet:fs-tablet-h4'; + return 'fs-h4'; case 'h5': - return 'fs-h5 tablet:fs-tablet-h5'; + return 'fs-h5'; case 'h6': - return 'fs-h6 tablet:fs-tablet-h6'; + return 'fs-h6'; default: return ''; } diff --git a/src/components/atoms/icon-button/IconButton.stories.tsx b/src/components/atoms/icon-button/IconButton.stories.tsx index 8f57b1a6..e538ae5d 100644 --- a/src/components/atoms/icon-button/IconButton.stories.tsx +++ b/src/components/atoms/icon-button/IconButton.stories.tsx @@ -1,5 +1,5 @@ -import { fn } from '@storybook/test'; import type { Meta, StoryObj } from '@storybook/react'; +import { fn } from '@storybook/test'; import IconButton from './IconButton'; /** @@ -139,60 +139,12 @@ export const Light: Story = { export const RoundedShadow: Story = { render: () => (
- - - - - - + + + + + +
) }; diff --git a/src/components/atoms/icon-button/types.ts b/src/components/atoms/icon-button/types.ts index 1feb8e6a..f34135de 100644 --- a/src/components/atoms/icon-button/types.ts +++ b/src/components/atoms/icon-button/types.ts @@ -17,10 +17,10 @@ export const iconButtonVariants = cva( variant: { primary: [ 'text-white', - 'bg-[image:var(--background-image-btn-primary)]', + 'bg-btn-primary', 'border-transparent', 'shadow-glow-btn-primary-light dark:shadow-glow-btn-primary', - 'hover:bg-[image:var(--background-image-btn-primary-hover)]', + 'hover:bg-btn-primary-hover', 'hover:shadow-glow-btn-primary-hover-light dark:hover:shadow-glow-btn-primary-hover' ], ghost: [ @@ -52,7 +52,7 @@ export const iconButtonVariants = cva( 'border-brand-light dark:border-brand-dark', 'bg-transparent', 'hover:text-white dark:hover:text-white', - 'hover:bg-[image:var(--background-image-btn-primary)]', + 'hover:bg-btn-primary', 'hover:border-transparent', 'hover:shadow-glow-btn-primary-light dark:hover:shadow-glow-btn-primary' ] diff --git a/src/components/atoms/icon/Icon.tsx b/src/components/atoms/icon/Icon.tsx index f24a82b0..8237a09a 100644 --- a/src/components/atoms/icon/Icon.tsx +++ b/src/components/atoms/icon/Icon.tsx @@ -1,6 +1,6 @@ -import { cn } from '@/lib/utils'; import { DynamicIcon } from 'lucide-react/dynamic'; import type { FC } from 'react'; +import { cn } from '@/lib/utils'; import type { IconProps } from './types'; import { useIcon } from './useIcon'; diff --git a/src/components/atoms/input/Input.tsx b/src/components/atoms/input/Input.tsx index f3af80e6..f6c09838 100644 --- a/src/components/atoms/input/Input.tsx +++ b/src/components/atoms/input/Input.tsx @@ -246,7 +246,7 @@ const Input: FC< {getIconByHintType(hint?.type)} = ({ ...props }) => { {endContent && {endContent}} - {label && ( - - {label} - - )} + {label && {label}} ); }; diff --git a/src/components/atoms/text/Text.stories.tsx b/src/components/atoms/text/Text.stories.tsx index 80f7f9a3..0e0e259a 100644 --- a/src/components/atoms/text/Text.stories.tsx +++ b/src/components/atoms/text/Text.stories.tsx @@ -1,5 +1,6 @@ import type { Meta, StoryObj } from '@storybook/react'; import Text from './Text'; + /** * ## DESCRIPTION * diff --git a/src/components/organisms/modal/Modal.tsx b/src/components/organisms/modal/Modal.tsx index 51d9f670..3b2920f9 100644 --- a/src/components/organisms/modal/Modal.tsx +++ b/src/components/organisms/modal/Modal.tsx @@ -36,7 +36,7 @@ const Modal: FC> = ({ ...props }) => {
( # Breakpoints & Spacing
- Responsive breakpoints and spacing scale for the Stack-and-Flow Design System. + Official responsive breakpoints and spacing scale for the Stack-and-Flow Design System.
-

Custom Breakpoints

- -
-
- 0 -
-
-
-
- -
-
- mobile
0 – 899px
- tablet
≥ 900px
- desktop
≥ 1440px
-
-
- -
-
    -
  • --breakpoint-tablet: 900px
  • -
  • --breakpoint-desktop: 1440px
  • -
-
- -

Tailwind CSS Breakpoints

+

Tailwind CSS Native Breakpoints

@@ -63,6 +38,11 @@ export const H2 = ({ children }) => (
+

+ The design system uses Tailwind's native responsive prefixes only: sm,{' '} + md, lg,{' '} + xl, and 2xl. +

  • sm: @media (min-width: 640px)
  • md: @media (min-width: 768px)
  • diff --git a/stories/Design system/4-typography.mdx b/stories/Design system/4-typography.mdx index f9d6b4c9..fb8f3fef 100644 --- a/stories/Design system/4-typography.mdx +++ b/stories/Design system/4-typography.mdx @@ -79,18 +79,18 @@ export const H2 = ({ children }) => ( ))}
-

Type Scale — Tablet

+

Type Scale — Compact (Base < md)

{[ - { token: '--text-h1-tablet', size: '2.4rem', px: '38px', label: 'Heading 1' }, - { token: '--text-h2-tablet', size: '2rem', px: '32px', label: 'Heading 2' }, - { token: '--text-h3-tablet', size: '1.75rem', px: '28px', label: 'Heading 3' }, - { token: '--text-h4-tablet', size: '1.375rem', px: '22px', label: 'Heading 4' }, - { token: '--text-h5-tablet', size: '1.125rem', px: '18px', label: 'Heading 5' }, - { token: '--text-h6-tablet', size: '1rem', px: '16px', label: 'Heading 6' }, - { token: '--text-body-tablet', size: '0.9375rem', px: '15px', label: 'Body' }, - { token: '--text-small-tablet', size: '0.8125rem', px: '13px', label: 'Small' }, + { token: '--text-h1-compact', size: '2.4rem', px: '38px', label: 'Heading 1' }, + { token: '--text-h2-compact', size: '2rem', px: '32px', label: 'Heading 2' }, + { token: '--text-h3-compact', size: '1.75rem', px: '28px', label: 'Heading 3' }, + { token: '--text-h4-compact', size: '1.375rem', px: '22px', label: 'Heading 4' }, + { token: '--text-h5-compact', size: '1.125rem', px: '18px', label: 'Heading 5' }, + { token: '--text-h6-compact', size: '1rem', px: '16px', label: 'Heading 6' }, + { token: '--text-body-compact', size: '0.9375rem', px: '15px', label: 'Body' }, + { token: '--text-small-compact', size: '0.8125rem', px: '13px', label: 'Small' }, ].map(({ token, size, px, label }) => (
diff --git a/tsconfig.node.json b/tsconfig.node.json index de5a23bf..0682568b 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -1,7 +1,7 @@ { "compilerOptions": { "composite": true, - "skipLibCheck": true, + "skipLibCheck": true, "module": "ESNext", "moduleResolution": "bundler", "resolveJsonModule": true, @@ -10,5 +10,5 @@ "outDir": "./dist", "strict": true }, - "include": ["vite.config.ts"], + "include": ["vite.config.ts"] } diff --git a/vite.config.ts b/vite.config.ts index b60f2ae6..c19e437a 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -45,7 +45,7 @@ export default defineConfig({ test: { globals: true, environment: 'jsdom', - setupFiles: ['./tests/setup.ts'], + setupFiles: ['./tests/setup.ts'], css: false, alias: aliases, coverage: {