# @bchen/ui Shared CSS tokens and UI components for the bchen.dev fleet. ## What's included | Export | Contents | |--------|----------| | `@bchen/ui/tokens.css` | Semantic-token palette — light mode `:root` block + `@media (prefers-color-scheme: dark)` override | | `@bchen/ui/base.css` | `input, textarea, select { font-size: 16px; }` — prevents iOS Safari auto-zoom on focus | ## Consumer integration (four steps) ### 1. Add the dependency ```json // package.json "dependencies": { "@bchen/ui": "git+https://gitea.bchen.dev/brendan/bchen-ui.git#v0.1.0" } ``` Then run `npm install` (requires `git` in your build image — see Step 2). ### 2. Dockerfile — copy CSS to your public dir After `npm ci`, copy the dist files into your served static directory so they're available at runtime without bundler involvement: ```dockerfile FROM node:24-alpine RUN apk add --no-cache python3 make g++ git WORKDIR /app COPY package*.json ./ RUN npm ci # Copy @bchen/ui dist files into public vendor dir RUN mkdir -p public/vendor/@bchen/ui && \ cp -r node_modules/@bchen/ui/dist/. public/vendor/@bchen/ui/ COPY . . ``` ### 3. HTML — link vendor CSS before your app stylesheet ```html ``` ### 4. App CSS — your overrides come after vendor Your `style.css` can reference the tokens directly: ```css /* style.css — loaded after vendor, so tokens are already defined */ body { background: var(--bg); color: var(--fg); font-family: var(--font); } a { color: var(--accent); } .muted { color: var(--fg-muted); } ``` Dark mode is automatic — no JavaScript required. The `tokens.css` `@media (prefers-color-scheme: dark)` block overrides the palette based on the OS setting. ## Token reference ### Primitive palette (resolve base values) | Token | Light | Dark | |-------|-------|------| | `--black` | `#000` | — | | `--white` | `#fff` | — | | `--gray-50` | `#fafafa` | — | | `--gray-100` | `#f0f0f0` | — | | `--gray-200` | `#e0e0e0` | — | | `--gray-400` | `#999` | — | | `--gray-600` | `#555` | — | | `--red` | `#c00` | — | ### Semantic color tokens | Token | Light | Dark | |-------|-------|------| | `--fg` | `#000` | `#e5e7eb` | | `--fg-muted` | `#555` | `#9ca3af` | | `--bg` | `#fff` | `#0f1115` | | `--bg-elevated` | `#fafafa` | `#1a1d23` | | `--surface` | `#fff` | `#0f1115` | | `--accent` | `#000` | `#e5e7eb` | | `--accent-fg` | `#fff` | `#0f1115` | | `--accent-hover` | `#555` | `#cbd5e1` | | `--danger` | `#c00` | `#f87171` | | `--danger-fg` | `#fff` | `#0f1115` | | `--danger-bg` | `#fff5f5` | `rgba(248,113,113,0.12)` | | `--warning` | `#555` | — | | `--border-color` | `#e0e0e0` | `#374151` | | `--border-strong` | `#000` | `#6b7280` | | `--border` | `1px solid #000` | `1px solid #6b7280` | ### Input tokens | Token | Light | Dark | |-------|-------|------| | `--input-bg` | `#fff` | `#1a1d23` | | `--input-fg` | `#000` | `#e5e7eb` | | `--input-border` | `#000` | `#6b7280` | | `--input-bg-focus` | `#fafafa` | `#0f1115` | ## WCAG contrast guarantees All values in `tokens.css` are tested (see `tests/tokens.test.ts`) to meet: - **AA body text (≥ 4.5:1):** `--fg/--bg`, `--fg-muted/--bg` in both light and dark - **UI elements (≥ 3.0:1):** `--border-strong/--bg` in both light and dark ## Changelog See [CHANGELOG.md](./CHANGELOG.md).