feat: storybook
This commit is contained in:
@@ -7,6 +7,9 @@
|
|||||||
node_modules
|
node_modules
|
||||||
dist/
|
dist/
|
||||||
|
|
||||||
|
# Storybook build output (the .storybook config + *.stories.tsx ARE committed)
|
||||||
|
storybook-static/
|
||||||
|
|
||||||
# Profile
|
# Profile
|
||||||
.rspack-profile-*/
|
.rspack-profile-*/
|
||||||
|
|
||||||
|
|||||||
@@ -4,47 +4,54 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
|
|
||||||
## What this is
|
## What this is
|
||||||
|
|
||||||
`@modernsk/ui` — 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`.
|
`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
|
## Commands
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run dev # Rsbuild playground at http://localhost:3000 (renders src/App.tsx — every component on one page)
|
npm run dev # Rsbuild playground at http://localhost:3000 (renders src/App.tsx — every component on one page)
|
||||||
npm run build # build publishable package: tsup (JS/types) + build:css (bundled stylesheet) into dist/
|
npm run storybook # Storybook component explorer + autodocs at http://localhost:6006
|
||||||
npm run lint # rslint (rslint.config.ts)
|
npm run build # build publishable package: tsup (JS/types) + build:css into dist/
|
||||||
npm run format # prettier --write .
|
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.
|
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):
|
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.
|
- `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 on `src/styles/index.css` with `--loader:.ttf=dataurl`, inlining the self-hosted Anta font so no asset hosting is needed.
|
- `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
|
## Architecture
|
||||||
|
|
||||||
Two parallel surfaces share the same source but never mix at publish time:
|
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`.
|
- **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):** `src/index.tsx` mounts `src/App.tsx`, and uses `src/styles/global.css`. These are the Rsbuild dev target only.
|
- **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.
|
||||||
|
|
||||||
`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^='msk-'])` so it never touches consumer elements. `global.css` adds a global reset and kitchen-sink layout helpers — those must stay out of the shipped bundle.
|
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`)
|
### 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 `msk-*` 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 `msk-*` classes resolving against CSS custom properties.**
|
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/`)
|
### Styling system (`src/styles/`)
|
||||||
|
|
||||||
- `tokens.css` — single source of truth: color/type CSS custom properties, `@font-face`, Google Fonts import. Every component reads from here.
|
- `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 `msk-*` class definitions.
|
- `components.css` — the `modern-sk-*` class definitions.
|
||||||
- Dark/light is driven by `data-theme` on `<html>`, set by `ThemeProvider` (persisted to `localStorage` under key `msk-theme`, default `dark`).
|
- Dark/light is driven by `data-theme` on `<html>`, 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 `msk-*` styles in `components.css`, and pull any new color/spacing value from a token in `tokens.css` rather than hardcoding.
|
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
|
## Consumer contract
|
||||||
|
|
||||||
Consumers import `@modernsk/ui/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.
|
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
|
## Conventions
|
||||||
|
|
||||||
|
|||||||
@@ -73,19 +73,23 @@ after `styles.css` — every component re-reads them:
|
|||||||
|
|
||||||
## Develop
|
## Develop
|
||||||
|
|
||||||
A live playground (every component on one page) runs via Rsbuild:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run dev # playground at http://localhost:3000
|
npm run dev # Rsbuild playground (every component on one page) at http://localhost:3000
|
||||||
npm run build # build the publishable package into dist/
|
npm run storybook # Storybook component explorer + docs at http://localhost:6006
|
||||||
|
npm run build # build the publishable package into dist/
|
||||||
npm run lint
|
npm run lint
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Storybook** is the component catalogue: each component has live controls and an
|
||||||
|
auto-generated prop table, plus a theme toggle in the toolbar. Stories live in
|
||||||
|
`src/stories/*.stories.tsx`; config is in `.storybook/`. It is committed to git so
|
||||||
|
anyone can `npm run storybook` and browse — but it never ships in the package.
|
||||||
|
|
||||||
## What ships
|
## What ships
|
||||||
|
|
||||||
A git install exposes only `dist/` — built ESM + CJS, `.d.ts` types,
|
A git install exposes only `dist/` — built ESM + CJS, `.d.ts` types,
|
||||||
`styles.css`, and `fonts.css`. The playground (`src/App.tsx`, Rsbuild config)
|
`styles.css`, and `fonts.css`. Everything else (`src/App.tsx`, `.storybook/`,
|
||||||
is dev-only and never published.
|
stories, Rsbuild config) is dev-only and never published.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Generated
+4861
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,8 @@
|
|||||||
"build:css": "esbuild src/styles/index.css --bundle --outfile=dist/styles.css && esbuild src/styles/fonts.css --bundle --loader:.ttf=dataurl --outfile=dist/fonts.css",
|
"build:css": "esbuild src/styles/index.css --bundle --outfile=dist/styles.css && esbuild src/styles/fonts.css --bundle --loader:.ttf=dataurl --outfile=dist/fonts.css",
|
||||||
"dev": "rsbuild dev --open",
|
"dev": "rsbuild dev --open",
|
||||||
"preview": "rsbuild preview",
|
"preview": "rsbuild preview",
|
||||||
|
"storybook": "storybook dev -p 6006",
|
||||||
|
"build-storybook": "storybook build",
|
||||||
"lint": "rslint",
|
"lint": "rslint",
|
||||||
"format": "prettier --write .",
|
"format": "prettier --write .",
|
||||||
"prepare": "npm run build"
|
"prepare": "npm run build"
|
||||||
@@ -44,6 +46,7 @@
|
|||||||
"@rsbuild/plugin-babel": "^1.2.0",
|
"@rsbuild/plugin-babel": "^1.2.0",
|
||||||
"@rsbuild/plugin-react": "^2.0.0",
|
"@rsbuild/plugin-react": "^2.0.0",
|
||||||
"@rslint/core": "^0.5.1",
|
"@rslint/core": "^0.5.1",
|
||||||
|
"@storybook/addon-docs": "^10.4.1",
|
||||||
"@types/react": "^19.2.15",
|
"@types/react": "^19.2.15",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"babel-plugin-react-compiler": "^1.0.0",
|
"babel-plugin-react-compiler": "^1.0.0",
|
||||||
@@ -51,6 +54,8 @@
|
|||||||
"prettier": "^3.8.3",
|
"prettier": "^3.8.3",
|
||||||
"react": "^19.2.6",
|
"react": "^19.2.6",
|
||||||
"react-dom": "^19.2.6",
|
"react-dom": "^19.2.6",
|
||||||
|
"storybook": "^10.4.1",
|
||||||
|
"storybook-react-rsbuild": "^3.3.4",
|
||||||
"tsup": "^8.5.0",
|
"tsup": "^8.5.0",
|
||||||
"typescript": "^6.0.3"
|
"typescript": "^6.0.3"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user