# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## What this is `modern-sk` — a tactile, dark-first React component library built on [Radix](https://www.radix-ui.com/) primitives. Distributed as a git-installable / publishable package; only `dist/` ships. Consumers get built ESM + CJS, `.d.ts` types, and a single `styles.css`. ## Commands ```bash npm run dev # Rsbuild playground at http://localhost:3000 (renders src/App.tsx — every component on one page) npm run storybook # Storybook component explorer + autodocs at http://localhost:6006 npm run build # build publishable package: tsup (JS/types) + build:css into dist/ npm run lint # rslint (rslint.config.ts) — covers src/ including stories npm run format # prettier --write . ``` No test suite exists. `npm run build` runs automatically on install via the `prepare` script — consumers build the package themselves. The build is two steps that must both run (the `build` script chains them): - `tsup` bundles `src/index.ts` → ESM/CJS + types. `react`/`react-dom` are externalized (peer deps); `radix-ui` + `@phosphor-icons/react` are bundled. - `build:css` runs esbuild twice: `src/styles/index.css` → `dist/styles.css` (fontless core), and `src/styles/fonts.css` → `dist/fonts.css` with `--loader:.ttf=dataurl` (inlines the self-hosted Anta font). Both are package exports. ## Architecture Two parallel surfaces share the same source but never mix at publish time: - **Library (shipped):** `src/index.ts` is the public entry. It re-exports everything from `src/components/ui.tsx`, plus `ThemeProvider`/`useTheme` from `src/components/theme.tsx`, and exposes `TooltipProvider` (Radix's `Tooltip.Provider`). The shipped stylesheet entry is `src/styles/index.css`. - **Playground (dev-only, never published):** two of them — `src/index.tsx` mounts the `src/App.tsx` kitchen sink (Rsbuild dev target, `src/styles/global.css`), and Storybook (`.storybook/` config + `src/stories/*.stories.tsx`) is the component catalogue with autodocs. Only `dist/` ships (`files: ["dist"]`), so the playground, stories, and `.storybook/` are excluded from the package automatically — but they ARE committed to git so anyone can run them. `src/styles/index.css` (shipped) vs `src/styles/global.css` (dev) is a deliberate split: `index.css` imports only `tokens.css` + `components.css` and applies box-sizing at **zero specificity** via `:where([class^='modern-sk-'])` so it never touches consumer elements. `global.css` adds a global reset, the optional `fonts.css`, and kitchen-sink layout helpers — those must stay out of the shipped bundle. ### Fonts (`src/styles/fonts.css`) Fonts are NOT in the core stylesheet. `tokens.css` defines `--font-display/sans/mono` chains that degrade to `system-ui`; the actual faces (Anta `@font-face` + Onest/Geist Mono Google Fonts `@import`) live in `src/styles/fonts.css`, shipped as the optional `modern-sk/fonts.css` export. Consumers either import it, or override the `--font-*` tokens to remap typefaces. Storybook's `preview.tsx` and the dev `global.css` both import `fonts.css` so the playgrounds stay branded. ### Components (`src/components/ui.tsx`) All components live in one file. Pattern: Radix provides logic/accessibility, every visual comes from CSS. Components are thin wrappers that attach `modern-sk-*` classes and spread props. The `cx()` helper joins class names (no classnames dependency). Components forward refs where they wrap a DOM element. There is no inline styling and no CSS-in-JS — **all appearance is driven by `modern-sk-*` classes resolving against CSS custom properties.** ### Styling system (`src/styles/`) - `tokens.css` — single source of truth: color/type CSS custom properties (no font loading — see Fonts above). Every component reads from here. - `components.css` — the `modern-sk-*` class definitions. - Dark/light is driven by `data-theme` on ``, set by `ThemeProvider` (persisted to `localStorage` under key `modern-sk-theme`, default `dark`). When adding or changing a component: add the wrapper in `ui.tsx`, define its `modern-sk-*` styles in `components.css`, and pull any new color/spacing value from a token in `tokens.css` rather than hardcoding. ## Consumer contract Consumers import `modern-sk/styles.css` once at app root, wrap their tree in `ThemeProvider`, and wrap any tooltip-using subtree in `TooltipProvider`. Keep these provider requirements intact when refactoring exports. ## Conventions - React 19, React Compiler is enabled (`babel-plugin-react-compiler` in the Rsbuild dev pipeline). - TypeScript is `noEmit` + `verbatimModuleSyntax`: use `import type` for type-only imports. `noUnusedLocals`/`noUnusedParameters` are on. - ESM-only package (`"type": "module"`).