README.md

# ShadcnEx

`shadcn_ex` is a Phoenix component package + tooling pipeline for automated shadcn/ui -> HEEx adaptation.

## Goals

- Extract component metadata from upstream shadcn/ui registry sources.
- Auto-detect props, slots, variants, and interactivity signals.
- Classify components into:
  - `renderable_stateless` (safe for generic renderer/codegen)
  - `custom_interactive` (requires manual adapter/component logic)
- Promote `use client` wrappers only when schema analysis shows static HTML slot rendering
  (no hooks, no JSX event handlers, no non-intrinsic slot tags).
- Keep generated manifests versioned for CI-driven update bots.

## Installation

Add the dependency:

```elixir
# mix.exs
def deps do
  [
    {:shadcn_ex, "~> 0.1"}
  ]
end
```

Run the installer to copy assets and patch your app.js/app.css:

```bash
mix shadcn.install
```

The installer will:

1. Copy `hooks.js` and `shadcn_ex.css` to your app's `priv/static/shadcn_ex/`
2. Patch `assets/js/app.js` with import statements (managed block)
3. Patch `assets/css/app.css` with a Tailwind v4 `@source` directive for class discovery

Each patch is shown as a diff with a y/N prompt before applying.

### Installer Options

| Flag | Description |
|------|-------------|
| `--force` | Skip prompts, auto-apply all patches (CI mode) |
| `--check` | Verify install completeness, exit non-zero on drift |
| `--no-tailwind-patch` | Skip `@source` patching in app.css |
| `--app <name>` | Target a specific app in an umbrella project |

For umbrella projects, the installer auto-detects web apps (apps with an `assets/` directory). If multiple are found, it prompts which to target. Use `--app` to skip the prompt.

### Verifying Install in CI

```bash
mix shadcn.install --check
```

Returns exit code 0 if all managed blocks and assets are in place, non-zero otherwise.

## Consumer Usage

1. Optionally validate project compatibility.
2. `use ShadcnEx` in LiveView/component modules.
3. Use normal HEEx component syntax.

Optional compatibility check:

```bash
mix shadcn.validate_config
```

For informational-only mode (no failure on warnings):

```bash
mix shadcn.validate_config --no-strict
```

In your module:

```elixir
defmodule MyAppWeb.PageLive do
  use MyAppWeb, :live_view
  use ShadcnEx
end
```

In HEEx — each shadcn sub-component maps to its own function component:

```heex
<.button variant="outline" size="sm">Save</.button>

<.card>
  <.card_title>Agents</.card_title>
  <.card_description>Runtime groups</.card_description>
  <.card_content>
    <.badge variant="secondary">Configured</.badge>
  </.card_content>
  <.card_footer>Synced just now</.card_footer>
</.card>
```

## JS Hooks

ShadcnEx ships a tiered hook system for components that need client-side interactivity.

### Tier 1 — Vanilla JS

Safe hooks using only DOM APIs and optional vanilla JS libraries:

- **sidebar** — toggle expanded/collapsed state via `data-state` attribute
- **sonner** — toast notifications using CSS classes and design tokens
- **embla-carousel** — carousel with optional autoplay (requires `embla-carousel` npm package)

### Tier 2 — LiveView Bridges

Lightweight DOM utilities that bridge user interactions to LiveView server events:

- **command-palette** — Cmd+K / Ctrl+K listener, toggles `data-state`, pushes LiveView event
- **drawer** — open/close via trigger elements, CSS transitions, Escape to close

### Tier 3 — Unsupported

React-only libraries that cannot run without a React runtime. These emit a one-time console warning with guidance:

`recharts`, `react-day-picker`, `react-hook-form`, `base-ui`, `cmdk`, `vaul`

For these components, use a React adapter (e.g., LiveSvelte, LiveReact) or a native Elixir alternative.

### Usage

```javascript
import { initHybridComponents, setupAutoInit } from "shadcn_ex/hooks"

// Initialize all [data-js-mount] elements currently in the DOM
initHybridComponents()

// Or auto-init on LiveView mount events
setupAutoInit()
```

## Versioning and Compatibility

`mix shadcn.validate_config` detects:

- shadcn style from `config :shadcn_ex, :style` or `components.json`
- Tailwind major from `assets/package.json` (fallback: `assets/css/app.css`/tailwind config files)

Current compatibility behavior:

- `new-york-v4` requires Tailwind 4
- `new-york` / `default` are treated as Tailwind 3
- strict mode (default) fails on mismatch or missing required detection signals

## Development

These sections are for library maintainers, not consumers.

### Extract Manifest

Re-extract component metadata from upstream shadcn/ui:

```bash
mix shadcn.extract
mix shadcn.extract --style new-york-v4 --ref main
```

### Generate Renderer Registry

Rebuild the Elixir registry from the manifest:

```bash
mix shadcn.codegen
```

### Hardcoded Colors Audit

The extraction manifest includes a `hardcoded_colors` array per component, flagging Tailwind classes that use absolute colors (e.g., `bg-white`) rather than design tokens. Use this to audit which components may need theme overrides.

### Tests

```bash
npx tsx --test scripts/extract_shadcn.test.ts
mix test
```