npm package: @o269/ui
Description: Omnia Design System — tokens, components, Tailwind preset, and tenant theming for all Omnia ecosystem apps
Latest version: 0.3.0

# @o269/ui

Omnia Design System — the single source of truth for tokens, components, Tailwind preset, and tenant theming across all Omnia ecosystem repos.

## Install

```bash
npm install @o269/ui
```

## What's Inside

| Export | Description |
|--------|------------|
| `@o269/ui` | Everything (tokens + components + layouts + theme + logo) |
| `@o269/ui/tokens` | Design tokens as TypeScript objects (colors, typography, spacing) |
| `@o269/ui/components` | React components (Button, Card, Badge, DataTable, etc.) |
| `@o269/ui/layouts` | Layout components (DashboardLayout, AuthLayout) |
| `@o269/ui/theme` | ThemeProvider + useTheme hook for tenant branding |
| `@o269/ui/logo` | OmniaIcon, OmniaWordmark, OmniaLogo SVG components |
| `@o269/ui/styles` | CSS custom properties (tokens.css) |
| `@o269/ui/styles/shadcn-bridge.css` | shadcn/ui HSL compatibility layer |
| `@o269/ui/styles/omnia-overrides.css` | Focus rings, transitions, tabular nums |
| `@o269/ui/styles/theme.css` | Base reset + typography |
| `@o269/ui/tailwind-preset` | Tailwind 3.x JS preset |
| `@o269/ui/tailwind-v4` | Tailwind 4.x CSS theme |

---

## Integration by Tailwind Version

### Tailwind 3.x (omnia-home-hub, contractor-hub, customer-hub, omnia-landing-page, omnia-logo-engine)

**1. tailwind.config.ts**

```typescript
import type { Config } from "tailwindcss";

export default {
  content: ["./src/**/*.{ts,tsx}"],
  presets: [require("@o269/ui/tailwind-preset")],
} satisfies Config;
```

**2. Global CSS (src/index.css)**

```css
@import "@o269/ui/styles";
@import "@o269/ui/styles/shadcn-bridge.css";
@import "@o269/ui/styles/omnia-overrides.css";

@tailwind base;
@tailwind components;
@tailwind utilities;
```

### Tailwind 4.x (LGM, omnia-meta-agent, Cali-First dashboard)

**1. Global CSS (app/globals.css)**

```css
@import "tailwindcss";
@import "@o269/ui/tailwind-v4";
```

That's it. The `tailwind-v4` import bundles tokens, shadcn bridge, overrides, and the `@theme` block.

---

## Using Components

```tsx
import { Button, Card, Badge, DataTable } from "@o269/ui/components";
import { DashboardLayout } from "@o269/ui/layouts";
import { OmniaLogo } from "@o269/ui/logo";

export function App() {
  return (
    <DashboardLayout sidebar={<Sidebar />}>
      <OmniaLogo variant="horizontal" iconSize={28} />
      <Card>
        <Badge variant="success">Active</Badge>
        <Button variant="primary" size="md">Save</Button>
      </Card>
    </DashboardLayout>
  );
}
```

## Using Tokens Programmatically

```typescript
import { colors, typography, spacing } from "@o269/ui/tokens";

console.log(colors.brand.primary);    // "#0A0A0A"
console.log(typography.fontFamily.body); // "'Inter', ..."
console.log(spacing.space[4]);        // "1rem"
```

## Tenant Branding (Client Customization)

Wrap your app in `ThemeProvider` to override brand colors, fonts, and logo:

```tsx
import { ThemeProvider } from "@o269/ui/theme";

// Cali First Remodel branding
<ThemeProvider
  theme={{
    brandPrimary: "#2C5530",       // Forest Green
    brandPrimaryHover: "#1A3A1F",  // Deep Pine
    brandPrimaryForeground: "#FFFFFF",
    fontHeading: "'Cormorant Garamond', serif",
    fontBody: "'Inter', sans-serif",
  }}
>
  <App />
</ThemeProvider>
```

The ThemeProvider sets CSS custom properties (`--ui-brand-primary`, etc.) on a wrapper div. All components and Tailwind utilities automatically pick up the overrides.

### Fetch branding from API

```tsx
import { useBranding } from "@o269/ui";

function BrandedApp({ tenantSlug }: { tenantSlug: string }) {
  const { branding, loading } = useBranding(tenantSlug);
  if (loading) return null;
  return (
    <ThemeProvider theme={{ brandPrimary: branding.primary_color }}>
      <App />
    </ThemeProvider>
  );
}
```

---

## Migration Guide (for repos with manual token copies)

### omnia-home-hub, contractor-hub, customer-hub

These repos currently have local copies of `tokens.css`, `shadcn-bridge.css`, and `omnia-overrides.css` in `src/styles/`. Replace them:

1. `npm install @o269/ui`
2. Delete `src/styles/tokens.css`, `src/styles/shadcn-bridge.css`, `src/styles/omnia-overrides.css`
3. Update `src/index.css`:

```css
/* BEFORE (local copies) */
@import "./styles/tokens.css";
@import "./styles/shadcn-bridge.css";
@import "./styles/omnia-overrides.css";

/* AFTER (from package) */
@import "@o269/ui/styles";
@import "@o269/ui/styles/shadcn-bridge.css";
@import "@o269/ui/styles/omnia-overrides.css";
```

4. Update `tailwind.config.ts`:

```typescript
/* BEFORE */
presets: [require("../../packages/ui/tailwind.preset")],

/* AFTER */
presets: [require("@o269/ui/tailwind-preset")],
```

### Cali-First (brand/tokens.css)

Cali First has its own `--cf-*` token namespace. To adopt Omnia's system while keeping the Cali First brand:

1. `npm install @o269/ui`
2. In dashboard's `app/globals.css`:

```css
@import "tailwindcss";
@import "@o269/ui/tailwind-v4";
```

3. Wrap the app in ThemeProvider with Cali First colors:

```tsx
<ThemeProvider
  theme={{
    brandPrimary: "#2C5530",
    brandPrimaryHover: "#1A3A1F",
    brandPrimaryForeground: "#FFFFFF",
    fontHeading: "'Cormorant Garamond', serif",
  }}
>
```

### LGM, omnia-meta-agent

These have minimal tokens. Just add:

```css
@import "tailwindcss";
@import "@o269/ui/tailwind-v4";
```

---

## CSS Custom Properties Reference

All tokens are prefixed with `--ui-`:

| Namespace | Variables | Example |
|-----------|-----------|---------|
| `--ui-bg-*` | primary, secondary, tertiary, inverse, hover, active, sidebar | `--ui-bg-primary: #FFFFFF` |
| `--ui-text-*` | primary, secondary, tertiary, inverse, link | `--ui-text-primary: #0A0A0A` |
| `--ui-border-*` | default, subtle, strong, focus | `--ui-border-default: #E5E7EB` |
| `--ui-status-*` | success, warning, error, info | `--ui-status-success: #10B981` |
| `--ui-brand-*` | primary, primary-hover, primary-foreground | Tenant-overridable |
| `--ui-font-*` | body, heading, mono, size-xs to 4xl, weight-* | `--ui-font-body: 'Inter', ...` |
| `--ui-space-*` | 1, 2, 3, 4, 6, 8, 12, 16, 20 | `--ui-space-4: 1rem` |
| `--ui-radius-*` | sm, md, lg, xl, full | `--ui-radius-lg: 0.75rem` |

## Design Principles

- **Attio-inspired**: clean black/white/gray, no glassmorphism
- **Borders over shadows**: 1px subtle borders are the primary separator
- **Sentence case**: no uppercase transforms on headings or buttons
- **Inter font**: universal across all apps
- **Tenant-overridable**: brand colors and fonts via ThemeProvider + CSS vars