npm package: @gamut-all/react
Description: React bindings for `@gamut-all/core`. Provides a context provider, components, and hooks that read `data-theme` / `data-stack` / font-size from the DOM and resolve tokens automatically.
Latest version: 0.1.1

# @gamut-all/react

React bindings for `@gamut-all/core`. Provides a context provider, components, and hooks that read `data-theme` / `data-stack` / font-size from the DOM and resolve tokens automatically.

## Installation

```sh
npm install @gamut-all/react @gamut-all/core
```

Requires React 18+.

## Quick start

```tsx
import { TokenProvider } from '@gamut-all/react';
import { registry } from './tokens'; // generated by Vite plugin or built manually

export default function App() {
  return (
    <TokenProvider registry={registry}>
      <html data-theme="light">
        {/* CSS vars are live: --fg-primary, --bg-surface, etc. */}
        <MyApp />
      </html>
    </TokenProvider>
  );
}
```

Set `data-theme` on the root element to activate a theme. Change it at runtime to switch themes — CSS vars update immediately.

## Components

### `<TokenProvider>`

Provides the registry and vision mode to all descendant hooks and components.

```tsx
<TokenProvider
  registry={registry}
  defaultVisionMode="default"  // optional, defaults to 'default'
>
  {children}
</TokenProvider>
```

Renders a `<div data-vision={visionMode} style={{ display: 'contents' }}>` wrapper. The `data-vision` attribute activates CVD-corrected CSS vars for the selected vision mode.

### `<StackLayer>`

Marks an element as belonging to an elevation stack. Emits `data-stack` and optionally `data-theme`.

```tsx
<StackLayer stack="modal" as="section" className="...">
  {/* tokens inside resolve at modal elevation */}
</StackLayer>
```

Props: `stack` (`StackClass`), `bg?` (sets `data-theme`), `as?` (defaults to `div`), any HTML attributes.

### `<TokenizedContainer>`

Shorthand for `<StackLayer>` with `data-theme` and `data-stack`.

```tsx
<TokenizedContainer bg="dark" stack="root" as="main">
  {children}
</TokenizedContainer>
```

### `<TokenizedText>`

Renders an element with its `color` style set to the resolved token hex.

```tsx
<TokenizedText token="fgDanger" as="span">
  Error: something went wrong
</TokenizedText>
```

Props: `token` (token name), `as?` (defaults to `span`), `style?`, any HTML attributes.

### `<TokenResolver>`

Render-prop component that exposes all resolved tokens and the current `DesignContext`.

```tsx
<TokenResolver>
  {(tokens, context) => (
    <div style={{ color: tokens.fgPrimary }}>
      Theme: {context.bgClass} / Stack: {context.stackDepth}
    </div>
  )}
</TokenResolver>
```

### `<TokenInspector>`

Development overlay (fixed, bottom-right) showing the current design context and all resolved token hex values. Renders nothing outside development builds.

```tsx
{import.meta.env.DEV && <TokenInspector />}
```

### `withAutoContrast(Component, options)`

HOC that injects resolved token values as props and CSS variables.

```tsx
const StyledButton = withAutoContrast(Button, {
  tokens: ['fgPrimary', 'borderMain'],
});
```

## Hooks

### `useTokenContext()`

Access the registry, current vision mode, and the setter for vision mode.

```tsx
const { registry, visionMode, setVisionMode } = useTokenContext();
```

Throws if called outside `<TokenProvider>`.

### `useDesignContext(ref)`

Detects the design context (theme, stack, font size, vision mode) from a DOM element. Updates on mutations and resize.

```tsx
const ref = useRef<HTMLDivElement>(null);
const context = useDesignContext(ref); // DesignContext | null
```

### `useToken(tokenName, ref)`

Resolves a single token to its hex string in the element's detected context.

```tsx
const ref = useRef<HTMLSpanElement>(null);
const hex = useToken('fgDanger', ref); // '#ef4444'
```

### `useResolvedTokens(ref)`

Resolves all tokens in the element's detected context.

```tsx
const ref = useRef<HTMLDivElement>(null);
const tokens = useResolvedTokens(ref);
// { fgPrimary: '#0f172a', fgDanger: '#ef4444', ... }
```

### `useTokenVars(ref)`

Returns a `CSSProperties` object of all tokens as CSS custom properties, ready for use in a `style` prop.

```tsx
const ref = useRef<HTMLDivElement>(null);
const vars = useTokenVars(ref);
// { '--fg-primary': '#0f172a', '--fg-danger': '#ef4444', ... }

return <div ref={ref} style={vars}>{children}</div>;
```

### `useTokenColor(tokenName, opts?)`

Direct resolution without DOM detection. Useful for canvas rendering, SVG, or situations where no element ref is available.

```tsx
const color = useTokenColor('fgDanger', {
  bg: 'dark',
  stack: 'modal',
  fontSize: '16px',
});
```

## DOM attributes

| Attribute | Where | Purpose |
|-----------|-------|---------|
| `data-theme` | `<html>` or any ancestor | Activates a theme (`light`, `dark`, etc.) |
| `data-stack` | Any element | Marks elevation context (`root`, `nav`, `modal`, etc.) |
| `data-vision` | Set by `<TokenProvider>` | Activates CVD-corrected token values |

Nesting `data-theme` inside another `data-theme` is not supported via CSS variable cascade. For nested theme demos, resolve tokens with `registry.themes.get(bg)?.surfaces.get(stack)?.hex` and use inline styles.

## Vision mode

Change vision mode at runtime to preview accessibility for different users:

```tsx
const { setVisionMode } = useTokenContext();

<select onChange={e => setVisionMode(e.target.value as VisionMode)}>
  <option value="default">Normal vision</option>
  <option value="deuteranopia">Green-blind</option>
  <option value="protanopia">Red-blind</option>
  <option value="tritanopia">Blue-blind</option>
  {/* + anomaly variants and achromatopsia */}
</select>
```

## Audit helpers

```ts
import { warnMissingDataTheme, checkDataThemeCoverage } from '@gamut-all/react';

// Log a console warning for any element missing a data-theme ancestor
warnMissingDataTheme(document.body);

// Get a coverage percentage
const { coverage, totalElements } = checkDataThemeCoverage(document.body);
```