# UI Library

📘 **[View Storybook](https://dev.aleph-alpha.de/ui-library)**

## Installation

```bash
pnpm add @aleph-alpha/ui-library
```

### Required Peer Dependencies

```bash
pnpm add -D unocss @unocss/preset-wind4 @unocss/reset unocss-preset-animations unocss-preset-shadcn
```

## Usage

### 1. Configure UnoCSS

The library exports a helper function `getUiLibraryContentConfig()` to simplify UnoCSS configuration:

```typescript
// uno.config.ts
import { defineConfig } from 'unocss'
import { getUiLibraryContentConfig } from '@aleph-alpha/ui-library/config'
import presetWind from '@unocss/preset-wind4'
import presetAnimations from 'unocss-preset-animations'
import presetShadcn from 'unocss-preset-shadcn'

export default defineConfig({
  ...getUiLibraryContentConfig(),
  presets: [
    presetWind(),
    presetAnimations(),
    presetShadcn({ color: 'neutral', darkSelector: 'html.dark' }),
  ],
})
```

### Custom theme (via design tokens)

`@aleph-alpha/ui-library` uses shadcn-style semantic utilities such as `bg-background`, `text-foreground`, `bg-primary`, `border-input`, etc.
These resolve through CSS variables (e.g. `--background`, `--primary`).

#### Option A: Use the built-in `tokens.json` shipped with the library (recommended)

If you added/maintain tokens in `packages/ui-library/tokens.json`, you can load them directly:

```typescript
// uno.config.ts
import { defineConfig } from 'unocss'
import { getUiLibraryContentConfig, presetUiLibraryThemeFromTokens } from '@aleph-alpha/ui-library/config'
import presetWind from '@unocss/preset-wind4'
import presetAnimations from 'unocss-preset-animations'
import presetShadcn from 'unocss-preset-shadcn'

export default defineConfig({
  ...getUiLibraryContentConfig(),
  presets: [
    presetWind(),
    presetAnimations(),
    presetShadcn({ color: 'neutral', darkSelector: 'html.dark' }),
    // Put the theme preset AFTER shadcn so it overrides shadcn's default CSS vars
    presetUiLibraryThemeFromTokens(),
  ],
})
```

#### Option B: Provide your own shadcn vars explicitly

To implement a custom theme from your token values, add `presetUiLibraryTheme()` **after** `presetShadcn()` so it overrides shadcn's default CSS vars:

```typescript
// uno.config.ts
import { defineConfig } from 'unocss'
import { getUiLibraryContentConfig, presetUiLibraryTheme } from '@aleph-alpha/ui-library/config'
import presetWind from '@unocss/preset-wind4'
import presetAnimations from 'unocss-preset-animations'
import presetShadcn from 'unocss-preset-shadcn'

export default defineConfig({
  ...getUiLibraryContentConfig(),
  presets: [
    presetWind(),
    presetAnimations(),
    presetShadcn({ color: 'neutral', darkSelector: 'html.dark' }),
    presetUiLibraryTheme({
      light: {
        // shadcn vars (keys without the leading `--`)
        background: '0 0% 100%',
        foreground: '240 10% 3.9%',
        primary: '222.2 47.4% 11.2%',
        'primary-foreground': '210 40% 98%',
        border: '240 5.9% 90%',
        input: '240 5.9% 90%',
        ring: '240 5.9% 10%',
      },
      dark: {
        background: '240 10% 3.9%',
        foreground: '0 0% 98%',
        primary: '210 40% 98%',
        'primary-foreground': '222.2 47.4% 11.2%',
        border: '240 3.7% 15.9%',
        input: '240 3.7% 15.9%',
        ring: '240 4.9% 83.9%',
      },
    }),
  ],
})
```

Notes:

- **Value formats**: You can pass OKLCH components, or `hex`/`rgb(...)`/`hsl(...)` — they will be converted to shadcn-compatible OKLCH components.
- **Dark mode selector**: Defaults to `html.dark`. If your app uses `.dark` on another element, pass `{ darkSelector: '.dark' }` as the second argument.

### 2. Configure Vite

```typescript
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import UnoCSS from 'unocss/vite'

export default defineConfig({
  plugins: [vue(), UnoCSS()],
})
```

### 3. Import Styles

```typescript
// main.ts
import '@unocss/reset/tailwind.css'
import 'virtual:uno.css'

import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')
```

### 4. Use Components

```vue
<script setup lang="ts">
import { UiButton, UiBadge } from '@aleph-alpha/ui-library'
</script>

<template>
  <UiButton>Click me</UiButton>
  <UiBadge variant="secondary">New</UiBadge>
</template>
```

### Using with @aleph-alpha/ds-components-vue

If you're using both `ui-library` and `ds-components-vue`, configure UnoCSS to include both:

> **⚠️ Important:** Do NOT add `presetWind()` or `presetAnimations()` separately when using `presetsAlephAlpha()`. The DS presets already include these utilities. Adding them again from different packages causes style conflicts.

```typescript
// uno.config.ts
import { defineConfig } from 'unocss'
import { presetsAlephAlpha, getDesignSystemContentPathConfig } from '@aleph-alpha/config-css'
import { getUiLibraryContentConfig } from '@aleph-alpha/ui-library/config'
import presetShadcn from 'unocss-preset-shadcn'

const uiLibraryConfig = getUiLibraryContentConfig()
const dsConfig = getDesignSystemContentPathConfig('vue')

export default defineConfig({
  presets: [
    // DS presets (already includes presetWind + presetAnimations)
    ...presetsAlephAlpha(),
    // UI Library preset (for shadcn CSS variables only)
    presetShadcn({ color: 'neutral' }),
  ],
  content: {
    filesystem: [
      ...(uiLibraryConfig.content.filesystem || []),
      ...(dsConfig.content?.filesystem || []),
    ],
    pipeline: {
      include: [
        /\.(vue|svelte|[jt]sx|mdx?|astro|elm|php|phtml|html)($|\?)/,
        'src/**/*.{js,ts,vue}',
        'node_modules/@aleph-alpha/ui-library/**/*.js',
        'node_modules/@aleph-alpha/ds-components-vue/**/*.{js,ts}',
      ],
    },
  },
})
```

## AI Assistant Integration

Enable component discovery for Claude Code or Cursor:

```bash
npx @aleph-alpha/ui-library mcp-install
```

For Cursor, add `--cursor` flag. Then restart your IDE.

**Available tools:**
- `list_components` - Browse all components (optionally filter by name/category/description)
- `get_component_docs` - Get full documentation for a component

## External Resources

- [shadcn-vue](https://www.shadcn-vue.com/) — The component library we build upon
- [Reka UI](https://reka-ui.com/) — Underlying accessible primitives
- [TanStack Table](https://tanstack.com/table/latest) — Headless table library (used in UiDataTable)
- [WAI-ARIA APG](https://www.w3.org/WAI/ARIA/apg/) — Accessibility patterns guide
- [WCAG 2.2](https://www.w3.org/TR/WCAG22/) — Web accessibility guidelines

## Documentation

- [Architecture](./docs/ARCHITECTURE.md) — Component structure and design decisions
- [Contribution Guidelines](./docs/CONTRIBUTION_GUIDELINES.md) — Accessibility requirements and patterns
- [Storybook Guidelines](./docs/STORYBOOK.md) — Story patterns and guidelines
- [Testing Strategy](./docs/TESTING.md) — What we test and where

## Getting Started

### Node Version

This project requires Node.js v20.19.0. Use `nvm` to switch to the correct version:

```bash
nvm use
```

This will automatically read the `.nvmrc` file in the repository root.

## Developing

### Commit Messages

We follow the [Conventional Commits](https://www.conventionalcommits.org/) specification. Commit messages must be structured as follows:

```
<type>(<scope>): <description>

[optional body]

[optional footer(s)]
```

**Types:**

- `feat`: A new feature
- `fix`: A bug fix
- `docs`: Documentation only changes
- `style`: Changes that do not affect the meaning of the code (formatting, etc.)
- `refactor`: A code change that neither fixes a bug nor adds a feature
- `perf`: A code change that improves performance
- `test`: Adding missing tests or correcting existing tests
- `chore`: Changes to the build process or auxiliary tools

**Examples:**

```bash
git commit -m "feat(button): add loading state"
git commit -m "fix(dropdown): resolve keyboard navigation issue"
git commit -m "docs(readme): update installation instructions"
```

### Adding New Components

To add a new component from shadcn-vue, use the following command:

```bash
pnpm dlx shadcn-vue@latest add [component]
```

Example:

```bash
pnpm dlx shadcn-vue@latest add tooltip
```

Please refer to [CONTRIBUTION_GUIDELINES.md](./docs/CONTRIBUTION_GUIDELINES.md) for more details on the "Strict Facade" pattern and accessibility requirements.

## Testing

| Command               | Purpose                             |
| --------------------- | ----------------------------------- |
| `pnpm test`           | Run unit tests                      |
| `pnpm test:storybook` | Run Storybook + accessibility tests |
| `pnpm lint`           | Run linting including a11y rules    |

See [Testing Strategy](./docs/TESTING.md) for details on what we test and where.

## Pre-commit Workflow

This project uses `nx affected` in pre-commit hooks to ensure code quality. Because `lint` and `test` targets depend on `build`, commits might hang if the build cache is cold.

### If commit hangs:

Run a full build to populate the cache before committing:

```bash
pnpm nx run-many --target=build --all
```

Then try committing again. The pre-commit hook will hit the cache and finish quickly.

### Quick unblock (Emergency only)

If you need to bypass hooks:

```sh
git commit -m "Your message" --no-verify
```

Use this sparingly and ensure CI passes.
