Takazudo Modular Docs

Type to search...

to open search from anywhere

/sub-packages/styleguide/CLAUDE.md

CLAUDE.md at /sub-packages/styleguide/CLAUDE.md

Path: sub-packages/styleguide/CLAUDE.md

Styleguide

Custom Preact-native component styleguide for Takazudo Modular. Replaces the old astrobook (which used @astrojs/react and broke after the Preact migration).

Architecture

Astro 6 + @astrojs/preact with compat mode. Each story variant renders in its own iframe via a preview route — providing full CSS isolation (like Storybook’s preview iframe pattern).

/                           → Homepage (category listing)
/tokens/                    → Design token preview
/[slug]/                    → Story page (iframes per variant)
/preview/[slug]/[variant]/  → Single variant rendered in isolation (iframe target)

Why iframes

Components render inside iframes so they get the full design system CSS in isolation. The styleguide chrome (sidebar, controls) doesn’t leak into component rendering. Token tweaker panels inject CSS variable overrides into iframes via iframe.contentDocument.documentElement.style.setProperty().

Tailwind CSS scanning

Since components render via client:only="preact" (client-side only), Tailwind v4’s Vite plugin can’t see them in the server module graph. The @source directives in src/styles/global.css explicitly tell Tailwind to scan the root project’s component directories.

Story Format

Stories use a custom format (not Storybook CSF). Each *.stories.tsx file exports:

meta (required)

export const meta = {
  title: 'Category/ComponentName',
};

title determines sidebar category (before /) and display name (after /).

Variants (required)

Each named export (except meta and controls) is a variant. Use arrow functions:

export const Default = () => <ActionButton>Click me</ActionButton>;
export const Disabled = () => <ActionButton disabled>Disabled</ActionButton>;
export const Loading = () => <ActionButton loading>Loading...</ActionButton>;

controls (optional)

Declares dynamic props that users can tweak in real-time via a controls panel below each variant preview. Changes are sent via postMessage to the iframe — no reload.

export const controls = {
  label: { type: 'text', default: '入荷通知を受け取る' },
  disabled: { type: 'boolean', default: false },
  loading: { type: 'boolean', default: false },
  size: { type: 'select', options: ['sm', 'md', 'lg'], default: 'md' },
  count: { type: 'number', default: 1, min: 0, max: 10, step: 1 },
  color: { type: 'color', default: '#ea580c' },
};

Control types: text, boolean, number, select, color

When controls are declared, the Default variant should accept props:

export const Default = (props: Record<string, unknown>) => (
  <ActionButton
    disabled={props.disabled as boolean}
    loading={props.loading as boolean}
  >
    {props.label as string}
  </ActionButton>
);

Other variants can remain static — they demonstrate specific states.

MSW support (optional)

For components that need API mocking (e.g., notify dialogs), add parameters.msw.handlers to meta:

export const meta = {
  title: 'Notify/ReservationDialog',
  parameters: { msw: { handlers: [mockReservationHandler] } },
};

Flat Props Pattern

Components should accept flat, simple props instead of complex nested objects. This makes stories easy to write and the styleguide previews straightforward.

// Component accepts flat props
export interface ArticleListItemProps {
  title: string;
  imageSlug: string;
  date: string;
  tags: string[];
  href: string;
}

// Adapter function for page-level usage (exported from same file)
export function articleSummaryToListItemProps(article: ArticleSummary): ArticleListItemProps {
  return { title: article.frontmatter.title, ... };
}

// Story uses flat props directly — simple
export const Default = () => (
  <ArticleListItem title="My Article" imageSlug="product-front" date="2024-06-01" ... />
);

Token Tweaker Panels

Two floating panels for live token tweaking:

PanelToggleTargetWhat it tweaks
Component Tokens (green)Top-right green circleIframes onlyPalette colors (p0-p15) + semantic mapping
Styleguide UI (orange)Top-right orange circlePage root onlyColor + spacing + typography tokens

Commands

pnpm styleguide:dev        # Dev server (port 44322)
pnpm styleguide:dev:net    # Dev server with network access
pnpm styleguide:build      # Production build

Key Files

FilePurpose
src/data/stories.tsAuto-discovers stories via import.meta.glob, builds category tree
src/data/control-types.tsControlDef and ControlsMap type definitions
src/data/zmod-tokens.tsToken definitions for tweak panels
src/components/variant-preview.tsxIframe container with viewport switcher, controls panel, auto-height
src/components/variant-renderer.tsxRenders a single variant inside iframe, listens for postMessage
src/components/controls-panel.tsxDynamic prop controls UI
src/components/color-tweak-panel.tsxPalette + semantic color tweaker (→ iframes)
src/components/token-tweak-panel.tsxSpacing + typography + color tweaker (→ page root)
src/lib/iframe-registry.tsManages CSS variable overrides across all iframes
src/mocks/Mock components (ResponsiveImage, next/link, server-only, etc.)
src/pages/preview/[...path].astroDynamic preview route (iframe target)