# @humain-foundation/ui

![Bundle Size](docs/assets/bundle-size-badge.svg)

Humain Foundation UI - A React component library for internal use, built with modern tooling and best practices.

> **Live Storybook:** [foundation.humain.com](https://foundation.humain.com)

> **New here?** Start with the [Usage Guide](docs/usage-guide.md) for CSS setup, design tokens, icons, animations, and composition patterns. AI coding agents should use [llms.txt](docs/llms.txt) for machine-readable component reference and recipes.

## Features

- **React 19** with TypeScript
- **Tailwind CSS v4** with CSS custom properties (design tokens)
- **Storybook 10** for component documentation
- **shadcn/ui patterns** with Base UI primitives
- **Tree-shakeable** ES modules
- **Dark mode** with theme provider, toggle component, and SSR support

## Installation

### From npm (public)

```bash
npm add @humain-foundation/ui lucide-react
```

### From GitLab Package Registry (internal)

Configure your `.npmrc` first:

```ini
# .npmrc
@humain-foundation:registry=https://gitlab.humain.com/api/v4/projects/13237/packages/npm/
//gitlab.humain.com/api/v4/projects/13237/packages/npm/:_authToken=${GITLAB_TOKEN}
```

Set the `GITLAB_TOKEN` environment variable with a personal access token (requires `read_api` scope).

Then install:

```bash
bun add @humain-foundation/ui lucide-react
```

## Usage

```tsx
import { Button, Badge } from '@humain-foundation/ui';
import { Check, ArrowRight } from 'lucide-react';
import '@humain-foundation/ui/styles.css';

function App() {
  return (
    <>
      <Button leftIcon={<Check />}>Confirm</Button>
      <Badge variant="success">Active</Badge>
      <ArrowRight className="size-4 text-primary" />
    </>
  );
}
```

### CSS Contract

The package provides two CSS entry points for different use cases:

| Export | Contains | Use Case |
|--------|----------|----------|
| `styles.css` | Compiled Tailwind + design tokens | Most apps (drop-in styling) |
| `tokens.css` | Design tokens only (CSS variables) | Apps with own Tailwind config |

```css
/* Option 1: Compiled styles (recommended for most apps) */
@import '@humain-foundation/ui/styles.css';

/* Option 2: Tokens only (for custom Tailwind setups) */
@import '@humain-foundation/ui/tokens.css';
```

**Choose `styles.css` if:**
- You want all component styles to work out of the box
- You don't have your own Tailwind configuration
- You want the simplest integration

**Choose `tokens.css` if:**
- You have your own Tailwind v4 setup
- You only need the design tokens (colors, spacing, etc.)
- You want to avoid duplicate Tailwind preflight/reset styles

## Dark Mode

The library provides built-in dark mode support with automatic system preference detection and manual toggle controls.

### Basic Usage

Dark mode is activated by applying the `.dark` class to the `<html>` element. The library uses the [next-themes](https://github.com/pacocoursey/next-themes) provider for theme management.

```tsx
import { ThemeProvider, ThemeToggle } from '@humain-foundation/ui';
import '@humain-foundation/ui/styles.css';

function App() {
  return (
    <ThemeProvider attribute="class" defaultTheme="system">
      <header>
        <ThemeToggle size="md" />
      </header>
      {/* Your app content */}
    </ThemeProvider>
  );
}
```

### Components

**`ThemeProvider`** - Wraps your app to enable theme switching

Props:
- `attribute?: string` - HTML attribute to set (default: `"class"`)
- `defaultTheme?: string` - Default theme if no preference (default: `"system"`)
- `storageKey?: string` - localStorage key (default: `"theme"`)
- `enableSystem?: boolean` - Enable system preference detection (default: `true`)

**`ThemeToggle`** - Segmented control for switching between light and dark themes

Props:
- `size?: 'sm' | 'md' | 'lg'` - Toggle size (default: `"md"`)
- `className?: string` - Additional CSS classes

**`useTheme`** - Hook to access and control the current theme

```tsx
import { useTheme } from '@humain-foundation/ui';

function CustomToggle() {
  const { theme, setTheme, resolvedTheme } = useTheme();

  return (
    <button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>
      Current: {resolvedTheme}
    </button>
  );
}
```

### Next.js App Router

To prevent flash of wrong theme on server-side rendering, use the `getThemeScript` utility:

```tsx
// app/layout.tsx
import { getThemeScript } from '@humain-foundation/ui';

export default function RootLayout({ children }) {
  return (
    <html suppressHydrationWarning>
      <head>
        <script dangerouslySetInnerHTML={{ __html: getThemeScript() }} />
      </head>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}
```

```tsx
// app/providers.tsx
'use client';

import { ThemeProvider } from '@humain-foundation/ui';

export function Providers({ children }) {
  return (
    <ThemeProvider attribute="class" defaultTheme="system">
      {children}
    </ThemeProvider>
  );
}
```

The script runs before React hydrates, reading from localStorage or system preferences to immediately apply the correct theme class.

**Options:**

```tsx
getThemeScript({
  storageKey: 'theme',        // localStorage key
  defaultTheme: 'system',     // fallback theme
  attribute: 'class',         // HTML attribute
  nonce: '...'                // CSP nonce (optional)
})
```

For more details, see [docs/adr/008-dark-mode-theme-provider.md](docs/adr/008-dark-mode-theme-provider.md).

## Web Components (Experimental)

> **Note:** Web Components support is experimental and may change in future releases. Please report issues you encounter.

Components are also available as Web Components for use in non-React frameworks (Vue, Angular, Svelte, vanilla HTML, etc.).

```html
<script type="module">
  import '@humain-foundation/ui/wc/hf-button.js';
</script>
<link rel="stylesheet" href="node_modules/@humain-foundation/ui/dist/styles.css">

<hf-button variant="primary">Click me</hf-button>
```

See [docs/web-components.md](docs/web-components.md) for the full component list, prop mappings, and framework-specific integration guides.

> **Note:** React usage remains unchanged - continue using the standard React imports as documented above.

## UMD Bundle (Script Tag)

A UMD bundle is built during releases for use in prototyping apps without a bundler. It exposes all core visual components on `window.HumainUI`.

```html
<!-- React 18 UMD (React 19 dropped UMD builds) -->
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>

<!-- Humain UI -->
<link rel="stylesheet" href="./humain-ui.css">
<script src="./humain-ui.umd.js"></script>

<script>
  const { Button, ThemeProvider } = window.HumainUI;
  const root = ReactDOM.createRoot(document.getElementById('root'));
  root.render(
    React.createElement(ThemeProvider, null,
      React.createElement(Button, null, 'Click me')
    )
  );
</script>
```

Files are at `dist/umd/humain-ui.umd.js` (~307KB gz) and `dist/umd/humain-ui.css` (~49KB gz).

See [docs/superpowers/specs/2026-04-24-umd-bundle-design.md](docs/superpowers/specs/2026-04-24-umd-bundle-design.md) for component list, consumer usage, and React version notes.

## App Shell

The library includes a compound layout system for building full application shells with sidebar navigation, multi-panel layouts, and mobile responsiveness — all handled automatically.

### Basic Layout

```tsx
import {
  AppShell, AppShellCard, AppSidebar, SidebarProvider
} from '@humain-foundation/ui';
import { Home, MessageCircle, Settings } from 'lucide-react';
import '@humain-foundation/ui/styles.css';

function App() {
  return (
    <AppShell.Root gap={12}>
      <AppShell.Sidebar>
        <SidebarProvider defaultOpen={false}>
          <AppSidebar>
            <AppSidebar.Nav>
              <AppSidebar.NavItem icon={<Home />} label="Dashboard" isActive />
              <AppSidebar.NavItem icon={<MessageCircle />} label="Chat" />
              <AppSidebar.NavItem icon={<Settings />} label="Settings" />
            </AppSidebar.Nav>
            <AppSidebar.Account name="Jane Doe" subtitle="jane@example.com" />
          </AppSidebar>
        </SidebarProvider>
      </AppShell.Sidebar>

      <AppShell.Panel flex={1}>
        <AppShellCard>
          <AppShellCard.Header>
            <AppShellCard.Title>Dashboard</AppShellCard.Title>
            <AppShellCard.Subtitle>Overview</AppShellCard.Subtitle>
          </AppShellCard.Header>
          <AppShellCard.Actions>
            <Button size="sm">Save</Button>
          </AppShellCard.Actions>
          {/* Body content — everything not Header/Actions/Menu becomes scrollable body */}
          <p>Your content here</p>
        </AppShellCard>
      </AppShell.Panel>
    </AppShell.Root>
  );
}
```

### Two-Panel Layout

Add a second `AppShell.Panel` for side-by-side content. On mobile, panels automatically switch to a tab bar.

```tsx
<AppShell.Root gap={12}>
  <AppShell.Sidebar>{/* ... */}</AppShell.Sidebar>

  <AppShell.Panel width={400} label="Chat">
    <AppShellCard>
      <AppShellCard.Header>
        <AppShellCard.Title>Chat</AppShellCard.Title>
      </AppShellCard.Header>
      <p>Chat messages...</p>
    </AppShellCard>
  </AppShell.Panel>

  <AppShell.Panel flex={1} label="Main">
    <AppShellCard>
      <AppShellCard.Header>
        <AppShellCard.Title>Dashboard</AppShellCard.Title>
      </AppShellCard.Header>
      <p>Main content...</p>
    </AppShellCard>
  </AppShell.Panel>
</AppShell.Root>
```

### Key Features

- **Auto-sizing sidebar** — detects expanded/collapsed state via CSS, no manual width wiring
- **Mobile responsive** — 2-panel layouts get a tab bar; sidebar becomes a slide-out drawer
- **Expandable panels** — set `expanded`/`onExpandedChange` on a Panel; `AppShellCard` auto-wires a maximize/minimize button
- **Connected mode** — `<AppShell.Root connected>` joins panel edges for a seamless look
- **AppShellCard toolbar** — built-in title, subtitle, actions, and kebab menu slots

## Components

The library exports 80+ components including:

- **Layout**: Card, AspectRatio, ScrollArea, Separator, Resizable
- **Forms**: Button, ButtonGroup, Input, Textarea, Checkbox, CheckboxGroup, RadioButtonGroup, Select, Switch, Slider, Field, ValidatedField, Form, ComboboxMenu, TagInput, RichTextarea
- **Feedback**: Badge, Tag, Progress, ProgressCircle, ProgressSteps, LoadingIndicator, Skeleton, Sonner (Toast)
- **Overlays**: Dialog, AlertDialog, Drawer, Sheet, Popover, Tooltip, HoverCard
- **Navigation**: Tabs, Accordion, Breadcrumb, Pagination, DropdownMenu, CommandMenu
- **Data Display**: Table, DataTable, Avatar, Calendar, WeekCalendar, DatePicker, DisplayField, MetricItem
- **Notifications**: NotificationItem, NotificationPanel
- **Charts**: LineChart, BarChart, HorizontalBarChart, DonutChart, PieChart, RadarChart
- **AI Components**: AIInput, AIMessage, AIContainer, AICodeBlock, AIMarkdown, AISource, AISteps, AIToolCall, AIReasoningBlock, AISystemMessage, AITextShimmer, AIThinkingLoader, and more
- **File Upload**: FileUpload, FileUploadArea, FileUploadItem
- **Pages**: EmptyState, NotFound, LogInPage, SignUp, ForgotPassword, VerifyEmailPage
- **Icons**: Use `lucide-react` directly (peer dependency, tree-shakeable)

## Development

### Prerequisites

- Node.js 18+
- Bun 1.0+

### Commands

```bash
bun install           # Install dependencies
bun dev               # Start Vite dev server
bun storybook         # Start Storybook on port 6006
bun run build         # Build for production
bun lint              # Run Biome linter
bun lint:fix          # Auto-fix lint issues
```

### Viewport Testing

```bash
bun run test:viewport      # Test all stories at all viewports
```

Detects overflow and overlap issues across mobile, tablet, laptop, and desktop viewports. See [docs/viewport-testing.md](docs/viewport-testing.md) for details.

### Component Architecture

The codebase follows a two-layer component pattern:

1. **`src/components/ui/`** - Base shadcn/ui components
   - Direct Base UI primitives with `class-variance-authority` (cva) for variants
   - Standard shadcn/ui patterns

2. **`src/components/wrapper/`** - Extended wrapper components
   - Import and extend base UI components
   - Add additional props (e.g., `loading`, `leftIcon`, `rightIcon` on Button)
   - Include Storybook stories

### Styling

- Design tokens in `src/tokens.css` (hex colors)
- `src/index.css` imports tokens and adds Tailwind configuration
- Dark mode via `.dark` class selector
- `cn()` utility combines `clsx` + `tailwind-merge`

## AI Skills for Claude Code

This project includes skills for [Claude Code](https://docs.anthropic.com/en/docs/claude-code) that give the AI deep knowledge of the component library and design workflows. There are two categories: a **project skill** bundled in this repo, and **design skills** installed per-user.

### Project Skill: `humain-ui`

The `humain-ui` skill gives Claude knowledge of all components, composition patterns, design tokens, recipes, and Figma-to-code mappings. It auto-detects whether you're building new UI, adopting the library in an existing project, or bootstrapping a new project.

**Install** (run once per machine):

```bash
claude install-skill skills/humain-ui.skill
```

**Usage** — ask Claude naturally:

```text
Build a settings page with a form, tabs, and a data table
Create an AI chat interface with file upload
How do I use the DatePicker with a form?
```

**Update references** after modifying components:

```bash
bun scripts/generate-skill-references.ts
```

### Design Skills

A separate set of design-focused skills provides production-grade frontend design guidance. These are user-level skills (not bundled in this repo) and require a one-time installation.

| Skill | Command | Purpose |
|-------|---------|---------|
| Frontend Design | `/frontend-design` | Core design principles, typography, color, layout, motion, and anti-patterns |
| Delight | `/delight` | Add micro-interactions, personality, and polish to interfaces |
| Adapt | `/adapt` | Make designs work across screen sizes, devices, and platforms |

**Install** (run once per machine — ask your team lead for the skills repo URL):

```bash
# Clone the skills repo (get URL from your team)
git clone <your-skills-repo-url> ~/.agents/skills

# Symlink into Claude Code's skill directory
mkdir -p ~/.claude/skills
for skill in frontend-design delight adapt; do
  ln -sf ~/.agents/skills/$skill ~/.claude/skills/$skill
done
```

**Usage** — invoke with slash commands in Claude Code:

```text
/delight    Add subtle micro-interactions to the FileUpload component
/adapt      Make this dashboard responsive for mobile
/frontend-design    Review this page's typography and color
```

### Design Context (`.impeccable.md`)

Design skills rely on a `.impeccable.md` file at the project root that defines brand personality, target audience, and aesthetic direction. This project already includes one. For other projects, run `/teach-impeccable` to generate it.

## Documentation

- [Usage Guide](docs/usage-guide.md) - CSS setup, design tokens, icons, animations, composition patterns
- [LLM Documentation](docs/llms.txt) - Machine-readable component documentation for AI assistants
- [Claude Code Skills](#ai-skills-for-claude-code) - AI skills for building UIs with this library
- [Publishing Guide](docs/publishing.md) - How to publish to npm
- [Architecture Decision Records](docs/adr/) - Key architectural decisions

### ADRs

| ADR | Title |
|-----|-------|
| [001](docs/adr/001-two-layer-component-architecture.md) | Two-Layer Component Architecture |
| [002](docs/adr/002-tailwind-css-v4-oklch-colors.md) | Tailwind CSS v4 with CSS Custom Properties |
| [003](docs/adr/003-icon-re-export-strategy.md) | Icon Re-export Strategy |
| [004](docs/adr/004-package-export-structure.md) | Package Export Structure |
| [005](docs/adr/005-peer-dependencies.md) | Peer Dependencies Strategy |
| [008](docs/adr/008-dark-mode-theme-provider.md) | Dark Mode Theme Provider |

## Publishing

**Internal** (GitLab, via CI/CD):
```bash
bun run release:patch   # bumps version, tags, pushes — CI publishes automatically
```

**Public npm** (manual sync):
```bash
bun run release:npm:sync   # builds and publishes current version to npmjs.com
```

See [docs/publishing.md](docs/publishing.md) for detailed instructions.

## License

Apache License 2.0 — see [LICENSE](LICENSE) for full text. The [NOTICE](NOTICE) file must be included in any distribution or derivative work.
