npm package: @soulbatical/tetra-ui
Description: Shared React frontend framework for Tetra platform projects (Soulbatical BV) — config-driven components, hooks, providers, and styling
Author: Albert Barth
Latest version: 0.10.1

# @soulbatical/tetra-ui

Shared React frontend framework for Tetra platform projects — config-driven components, hooks, providers, and styling.

## Installation

```bash
npm install @soulbatical/tetra-ui
```

Only install the peer dependencies you actually use (all are optional except `react`):

```bash
# Always needed
npm install react react-dom

# Only if you use ./query or ./feature
npm install @tanstack/react-query

# Only if you use ./table
npm install @tanstack/react-table

# Only if you use ./next
npm install next next-themes

# Only if you use ./planner
npm install @daypilot/daypilot-lite-react
```

## Subpath Exports

Import only what you need. Each subpath has its own dependency footprint:

```typescript
// Shadcn/ui primitives (radix + cva + tailwind-merge)
import { Button, Input, Card, Dialog } from '@soulbatical/tetra-ui/primitives';

// Layout & display components (React + lucide only)
import { ListDetailLayout, AutoCard, InfiniteGrid } from '@soulbatical/tetra-ui/components';

// Utility hooks (React only, zero external deps)
import { useDebounce, useDialog, useQueryState } from '@soulbatical/tetra-ui/hooks';

// Auth hooks + API client (requires @supabase/supabase-js)
import { useAuth, apiClient } from '@soulbatical/tetra-ui/auth';

// Query provider + cache hooks (requires @tanstack/react-query)
import { QueryProvider, useCacheInvalidation } from '@soulbatical/tetra-ui/query';

// Data table (requires @tanstack/react-table + tetra-core)
import { FeatureTable } from '@soulbatical/tetra-ui/table';

// Full-stack feature components (requires tetra-core + react-query)
import { FeatureFilters, FeatureForm, useFeature } from '@soulbatical/tetra-ui/feature';

// Next.js providers (requires next + next-themes)
import { ThemeProvider, ThemeToggle } from '@soulbatical/tetra-ui/next';

// Scheduling components (requires @daypilot/daypilot-lite-react)
import { BookingWidget, WeekCalendar } from '@soulbatical/tetra-ui/planner';

// Affiliate dashboard hooks (requires @supabase/supabase-js)
import { useAffiliateDashboard } from '@soulbatical/tetra-ui/affiliate';

// License — provider, watermark, feature gate
import { TetraLicenseProvider, useTetraLicense, ProFeatureGate } from '@soulbatical/tetra-ui/license';

// Barrel export — everything (requires ALL peer deps)
import { Button, ListDetailLayout, useFeature } from '@soulbatical/tetra-ui';
```

| Subpath | What you get | Extra peer deps needed |
|---------|-------------|----------------------|
| `./primitives` | Button, Input, Card, Dialog, Select, Table, Tabs, Badge, Label, Textarea | — |
| `./components` | ListDetailLayout, AutoCard, InfiniteGrid, PageHeader, StatusBadge, LoadingStates, CookieConsent, OAuthButtons | — |
| `./hooks` | useDebounce, useDialog, useIsMobile, useQueryState, useInfiniteScroll, useFormSubmit, usePageContext | — |
| `./auth` | useAuth, apiClient, useOrganizations | @supabase/supabase-js |
| `./query` | QueryProvider, useCacheInvalidation, useFilterConfigs | @tanstack/react-query |
| `./table` | FeatureTable | @tanstack/react-table, tetra-core |
| `./feature` | FeatureFilters, FeatureForm, useFeature | tetra-core, react-query |
| `./next` | ThemeProvider, ThemeToggle | next, next-themes |
| `./planner` | BookingWidget, WeekCalendar, TeamPlanner, AvailabilityEditor | @daypilot/daypilot-lite-react |
| `./affiliate` | useAffiliateDashboard | @supabase/supabase-js |
| `./license` | TetraLicenseProvider, useTetraLicense, ProFeatureGate, LicenseWatermark | — |
| `.` | Everything | All of the above |

## Licensing

Pro UI components (FeatureForm, FeatureTable, ListDetailLayout, BookingWidget, etc.) show a watermark when no valid license key is present. The watermark is suppressed on localhost for frictionless evaluation. Components remain fully functional.

```tsx
import { TetraLicenseProvider } from '@soulbatical/tetra-ui/license';

function App() {
  return (
    <TetraLicenseProvider licenseKey={process.env.NEXT_PUBLIC_TETRA_LICENSE_KEY}>
      <YourApp />
    </TetraLicenseProvider>
  );
}
```

```tsx
import { useTetraLicense, ProFeatureGate } from '@soulbatical/tetra-ui/license';

// Option 1: Hook
const { isLicensed, hasFeature } = useTetraLicense();

// Option 2: Gate component (adds watermark automatically)
<ProFeatureGate feature="BookingWidget" requiredPlan="pro">
  <BookingWidget {...props} />
</ProFeatureGate>
```

## Design Tokens (Theming)

All tetra-ui layout and feature components use `--tetra-*` CSS custom properties for colors. No hardcoded Tailwind color classes. This means you can theme every component by setting CSS variables.

### Quick start

Import the default tokens:

```css
@import '@soulbatical/tetra-ui/styles/tokens.css';
```

Or define your own values:

```css
:root {
  --tetra-bg:             #ffffff;
  --tetra-bg-subtle:      #f9fafb;
  --tetra-bg-muted:       #f3f4f6;
  --tetra-border:         #e5e7eb;
  --tetra-border-subtle:  #f3f4f6;
  --tetra-text:           #111827;
  --tetra-text-muted:     #6b7280;
  --tetra-text-inverted:  #ffffff;
  --tetra-accent:         #3b82f6;
  --tetra-accent-subtle:  #eff6ff;
  --tetra-accent-hover:   #2563eb;
  --tetra-danger:         #ef4444;
  --tetra-danger-subtle:  #fef2f2;
  --tetra-success:        #22c55e;
  --tetra-success-subtle: #f0fdf4;
  --tetra-warning:        #f59e0b;
  --tetra-warning-subtle: #fffbeb;
  --tetra-radius:         8px;
  --tetra-radius-sm:      4px;
  --tetra-radius-lg:      12px;
  --tetra-font:           inherit;
}
```

### Dark mode

Override the tokens in a dark scope:

```css
.dark, [data-theme="dark"] {
  --tetra-bg:             #0f172a;
  --tetra-bg-subtle:      #1e293b;
  --tetra-bg-muted:       #334155;
  --tetra-border:         #334155;
  --tetra-border-subtle:  #1e293b;
  --tetra-text:           #f1f5f9;
  --tetra-text-muted:     #94a3b8;
  --tetra-text-inverted:  #0f172a;
  --tetra-accent:         #60a5fa;
  --tetra-accent-subtle:  rgba(30, 58, 138, 0.3);
  --tetra-accent-hover:   #93bbfc;
}
```

### Per-section theming

Scope tokens to any parent element:

```tsx
<div style={{ '--tetra-accent': '#f97316' } as React.CSSProperties}>
  <ListDetailLayout ... />  {/* Uses orange accent */}
</div>
```

### What about shadcn/ui primitives?

The `./primitives` subpath (Button, Input, Card, etc.) uses shadcn/ui's own token system (`--background`, `--primary`, `--border`, etc.) and is **not** affected by `--tetra-*` tokens. These two systems coexist without conflict.

## Tailwind Preset

For projects using Tailwind CSS, tetra-ui provides a preset with the design system's colors, spacing, and typography:

```javascript
// tailwind.config.js
import tetraPreset from '@soulbatical/tetra-ui/tailwind-preset';

export default {
  presets: [tetraPreset],
  content: [
    './src/**/*.{ts,tsx}',
    './node_modules/@soulbatical/tetra-ui/dist/**/*.js',
  ],
};
```

## Theming Compliance Check

The `@soulbatical/tetra-dev-toolkit` includes a `ui-theming` check that enforces:

- No Tailwind color classes in tetra-ui components (e.g. `bg-blue-500`)
- No hardcoded hex/rgb/hsl color values
- No component-specific CSS vars (e.g. `--ldl-*`) — only `--tetra-*`
- Brand colors (OAuth buttons) are exempt via `// Brand color` comment

This check runs at prepublish time to prevent regressions.