# Migration Guide: shadcn/ui to itech-fluentui

> Complete step-by-step guide to migrate from shadcn/ui to itech-fluentui

## 📑 Table of Contents

1. [Overview](#overview)
2. [Installation](#installation)
3. [Theme Provider Migration](#theme-provider-migration)
4. [Component Migration](#component-migration)
5. [Design Tokens & Theming](#design-tokens--theming)
6. [Icons Migration](#icons-migration)
7. [Styling & Utilities](#styling--utilities)
8. [Common Patterns](#common-patterns)
9. [Troubleshooting](#troubleshooting)
10. [Complete Example](#complete-example)

---

## Overview

### Key Differences

| Feature           | shadcn/ui                  | itech-fluentui                                       |
| ----------------- | -------------------------- | ---------------------------------------------------- |
| **Base Library**  | Radix UI + Tailwind CSS    | Fluent UI v9                                         |
| **Theme System**  | Single ThemeProvider       | DesignProvider + ThemeProvider + FluentThemeProvider |
| **Brand Support** | Single brand               | 4 brand variants (vivid_blue, blue, brand_1, irepo)  |
| **Styling**       | Tailwind CSS classes       | Fluent UI tokens + CSS-in-JS                         |
| **Icons**         | lucide-react               | Fluent UI Icons (200+ icons)                         |
| **Package**       | Copy components to project | NPM package                                          |

### Benefits of Migration

- ✅ **Consistent Design System** - All iTech products use the same components
- ✅ **Multi-Brand Support** - Switch between brand variants easily
- ✅ **Better TypeScript** - Full type safety with Fluent UI
- ✅ **Figma Integration** - Direct mapping from Figma design tokens
- ✅ **Maintained Package** - Updates via npm, no manual copying

---

## Installation

### Step 1: Install the Package

```bash
npm install itech-fluentui
# or
yarn add itech-fluentui
# or
pnpm add itech-fluentui
```

### Step 2: Install Peer Dependencies

```bash
npm install @fluentui/react-components react react-dom
```

### Step 3: Import Styles

Add the CSS file to your main entry point:

```typescript
// main.tsx or App.tsx
import "itech-fluentui/styles";
```

Or if using CSS imports:

```typescript
import "itech-fluentui/index.css";
```

### Step 4: Import Fonts (Optional)

If you want to use the Inter font family:

```typescript
// Import the font CSS
import "itech-fluentui/fonts/inter.css";
```

Or manually import in your CSS:

```css
@import url("itech-fluentui/fonts/inter.css");
```

---

## Theme Provider Migration

### Before (shadcn/ui)

```tsx
import { ThemeProvider } from "@/components/theme-provider";

function App() {
  return (
    <ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
      <YourApp />
    </ThemeProvider>
  );
}
```

### After (itech-fluentui)

```tsx
import {
  DesignProvider,
  ThemeProvider,
  FluentThemeProvider,
} from "itech-fluentui";

function App() {
  return (
    <DesignProvider brand="vivid_blue" mode="light">
      <ThemeProvider defaultTheme="light" storageKey="vite-ui-theme">
        <FluentThemeProvider>
          <YourApp />
        </FluentThemeProvider>
      </ThemeProvider>
    </DesignProvider>
  );
}
```

### Provider Hierarchy

The providers must be nested in this specific order:

```
DesignProvider (brand & mode)
  └── ThemeProvider (theme persistence)
      └── FluentThemeProvider (Fluent UI theme)
          └── Your App Components
```

### Provider Props

#### DesignProvider

```tsx
<DesignProvider
  brand="vivid_blue"        // 'vivid_blue' | 'blue' | 'brand_1' | 'irepo'
  mode="light"              // 'light' | 'dark'
  onBrandChange={(brand) => console.log(brand)}
  onModeChange={(mode) => console.log(mode)}
>
```

#### ThemeProvider

```tsx
<ThemeProvider
  defaultTheme="light"       // 'light' | 'dark' | 'system'
  storageKey="vite-ui-theme" // localStorage key
>
```

#### FluentThemeProvider

```tsx
<FluentThemeProvider>
  {/* No props needed - reads from DesignProvider and ThemeProvider */}
</FluentThemeProvider>
```

### Using Theme Hooks

```tsx
import { useDesign, useTheme } from "itech-fluentui";

function ThemeSwitcher() {
  const { theme, setTheme } = useTheme();
  const { brand, mode, setBrand, toggleMode } = useDesign();

  return (
    <div>
      <button onClick={toggleMode}>
        Toggle {mode === "light" ? "Dark" : "Light"} Mode
      </button>
      <select value={brand} onChange={(e) => setBrand(e.target.value)}>
        <option value="vivid_blue">Vivid Blue</option>
        <option value="blue">Blue</option>
        <option value="brand_1">Brand 1</option>
        <option value="irepo">iRepo</option>
      </select>
    </div>
  );
}
```

---

## Component Migration

### General Pattern

Most components have similar APIs, but there are some differences:

1. **Import Path**: Change from local imports to package imports
2. **Props**: Some props may have different names
3. **Styling**: Use Fluent UI tokens instead of Tailwind classes

### Component-by-Component Guide

#### Button

**Before (shadcn/ui):**

```tsx
import { Button } from "@/components/ui/button";

<Button variant="default" size="lg" className="custom-class">
  Click me
</Button>;
```

**After (itech-fluentui):**

```tsx
import { Button } from "itech-fluentui/components";

<Button appearance="primary" size="large" className="custom-class">
  Click me
</Button>;
```

**Key Changes:**

- `variant` → `appearance` (primary, secondary, outline, subtle, transparent)
- `size` values: `small`, `medium`, `large` (instead of `sm`, `md`, `lg`)

#### Input

**Before (shadcn/ui):**

```tsx
import { Input } from "@/components/ui/input";

<Input type="email" placeholder="Email" className="w-full" />;
```

**After (itech-fluentui):**

```tsx
import { Input } from "itech-fluentui/components";

<Input type="email" placeholder="Email" className="w-full" />;
```

**React Hook Form Integration:**

```tsx
import { useForm } from 'react-hook-form';
import { Input } from 'itech-fluentui/components';

const { register } = useForm();

// ✅ Correct - spread register directly
<Input {...register('email')} type="email" />

// ❌ Wrong - don't pass register as prop
<Input register={register('email')} type="email" />
```

#### Dialog

**Before (shadcn/ui):**

```tsx
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogDescription,
  DialogFooter,
} from "@/components/ui/dialog";

<Dialog open={open} onOpenChange={setOpen}>
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Title</DialogTitle>
      <DialogDescription>Description</DialogDescription>
    </DialogHeader>
    <DialogFooter>
      <Button>Close</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>;
```

**After (itech-fluentui):**

```tsx
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogDescription,
  DialogFooter,
} from "itech-fluentui/components";

<Dialog open={open} onOpenChange={(e, data) => setOpen(data.open)}>
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Title</DialogTitle>
      <DialogDescription>Description</DialogDescription>
    </DialogHeader>
    <DialogFooter>
      <Button>Close</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>;
```

**Key Changes:**

- `onOpenChange` receives `(event, data)` instead of just `boolean`
- Use `data.open` to get the new state

#### Accordion

**Before (shadcn/ui):**

```tsx
import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from "@/components/ui/accordion";

<Accordion type="single" collapsible>
  <AccordionItem value="item-1">
    <AccordionTrigger>Is it accessible?</AccordionTrigger>
    <AccordionContent>Yes.</AccordionContent>
  </AccordionItem>
</Accordion>;
```

**After (itech-fluentui):**

```tsx
import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from "itech-fluentui/components";

<Accordion collapsible>
  <AccordionItem value="item-1">
    <AccordionTrigger>Is it accessible?</AccordionTrigger>
    <AccordionContent>Yes.</AccordionContent>
  </AccordionItem>
</Accordion>;
```

**Direct Fluent UI Components:**

```tsx
// You can also use Fluent UI components directly
import { AccordionPanel, AccordionHeader } from "itech-fluentui/components";

<AccordionPanel>
  <AccordionHeader>Header</AccordionHeader>
  Content here
</AccordionPanel>;
```

#### Avatar

**Before (shadcn/ui):**

```tsx
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";

<Avatar>
  <AvatarImage src="/avatar.jpg" alt="User" />
  <AvatarFallback>JD</AvatarFallback>
</Avatar>;
```

**After (itech-fluentui):**

```tsx
import { Avatar, AvatarImage, AvatarFallback } from "itech-fluentui/components";

<Avatar name="John Doe">
  <AvatarImage src="/avatar.jpg" alt="User" />
  <AvatarFallback>JD</AvatarFallback>
</Avatar>;
```

**Key Changes:**

- Add `name` prop to `Avatar` for better accessibility
- API is otherwise compatible

#### Badge

**Before (shadcn/ui):**

```tsx
import { Badge } from "@/components/ui/badge";

<Badge variant="default">Badge</Badge>;
```

**After (itech-fluentui):**

```tsx
import { Badge } from "itech-fluentui/components";

<Badge appearance="filled" color="brand">
  Badge
</Badge>;
```

**Key Changes:**

- `variant` → `appearance` (filled, outline, subtle, tinted)
- Add `color` prop (brand, danger, warning, success, important)

#### Card

**Before (shadcn/ui):**

```tsx
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";

<Card>
  <CardHeader>
    <CardTitle>Title</CardTitle>
  </CardHeader>
  <CardContent>Content</CardContent>
</Card>;
```

**After (itech-fluentui):**

```tsx
import {
  Card,
  CardHeader,
  CardTitle,
  CardContent,
} from "itech-fluentui/components";

<Card>
  <CardHeader>
    <CardTitle>Title</CardTitle>
  </CardHeader>
  <CardContent>Content</CardContent>
</Card>;
```

**Note:** Card API is very similar, minimal changes needed.

#### Select

**Before (shadcn/ui):**

```tsx
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";

<Select>
  <SelectTrigger>
    <SelectValue placeholder="Select option" />
  </SelectTrigger>
  <SelectContent>
    <SelectItem value="option1">Option 1</SelectItem>
    <SelectItem value="option2">Option 2</SelectItem>
  </SelectContent>
</Select>;
```

**After (itech-fluentui):**

```tsx
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "itech-fluentui/components";

<Select>
  <SelectTrigger>
    <SelectValue placeholder="Select option" />
  </SelectTrigger>
  <SelectContent>
    <SelectItem value="option1">Option 1</SelectItem>
    <SelectItem value="option2">Option 2</SelectItem>
  </SelectContent>
</Select>;
```

**Note:** Select API is compatible, minimal changes needed.

#### Toast

**Before (shadcn/ui):**

```tsx
import { useToast } from "@/components/ui/use-toast";

const { toast } = useToast();

toast({
  title: "Success",
  description: "Operation completed",
});
```

**After (itech-fluentui):**

```tsx
import { useToast } from "itech-fluentui/components";

const { toast } = useToast();

toast({
  title: "Success",
  description: "Operation completed",
  intent: "success", // 'success' | 'error' | 'warning' | 'info'
});
```

**Key Changes:**

- Add `intent` prop for toast type
- Similar API otherwise

#### Breadcrumb

**Before (shadcn/ui):**

```tsx
import {
  Breadcrumb,
  BreadcrumbList,
  BreadcrumbItem,
  BreadcrumbLink,
  BreadcrumbPage,
  BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
```

**After (itech-fluentui):**

```tsx
import {
  Breadcrumb,
  BreadcrumbList,
  BreadcrumbItem,
  BreadcrumbLink,
  BreadcrumbPage,
  BreadcrumbSeparator,
  // Aliases for compatibility
  BreadcrumbDivider, // Alias for BreadcrumbSeparator
  BreadcrumbButton, // Alias for BreadcrumbLink
} from "itech-fluentui/components";
```

---

## Design Tokens & Theming

### Using Design Tokens

**Before (shadcn/ui with Tailwind):**

```tsx
<div className="p-4 text-lg text-blue-600">Content</div>
```

**After (itech-fluentui with tokens):**

```tsx
import { tokens, makeStyles } from "itech-fluentui/components";

const useStyles = makeStyles({
  container: {
    padding: tokens.spacingHorizontalM,
    fontSize: tokens.fontSizeBase500,
    color: tokens.colorBrandForeground1,
  },
});

function Component() {
  const styles = useStyles();
  return <div className={styles.container}>Content</div>;
}
```

### Brand Colors

```tsx
import { getBrandColor, useDesign } from "itech-fluentui";

function Component() {
  const { brand } = useDesign();

  // Get brand color for current brand
  const primaryColor = getBrandColor(brand, 80);

  return <div style={{ color: primaryColor }}>Branded content</div>;
}
```

### Theme Hooks

```tsx
import { useDesign, useITechTheme } from "itech-fluentui";

function ThemedComponent() {
  const { brand, mode } = useDesign();
  const theme = useITechTheme();

  return (
    <div>
      <p>Current brand: {brand}</p>
      <p>Current mode: {mode}</p>
      <p>Theme color: {theme.colorBrandForeground1}</p>
    </div>
  );
}
```

---

## Icons Migration

### Before (shadcn/ui with lucide-react)

```tsx
import { Sun, Moon, User } from "lucide-react";

<Sun className="w-4 h-4" />
<Moon className="w-5 h-5" />
<User size={24} />
```

### After (itech-fluentui)

```tsx
import {
  SunIcon,
  MoonIcon,
  PersonIcon,
  // Or specific sizes
  SunIcon20Regular,
  MoonIcon24Filled,
} from 'itech-fluentui/components';

// Default (20Regular)
<SunIcon />
<MoonIcon />
<PersonIcon />

// Specific size and style
<SunIcon20Regular />
<MoonIcon24Filled />
<PersonIcon32Regular />
```

### Icon Naming Convention

- Base export: `IconName` (defaults to 20Regular)
- Size variants: `IconName16Regular`, `IconName24Filled`, etc.
- Styles: `Regular` (outline) or `Filled` (solid)

### Available Icons

All Fluent UI icons are available. Common ones:

```tsx
import {
  HomeIcon,
  PersonIcon,
  SettingsIcon,
  SearchIcon,
  AddIcon,
  DeleteIcon,
  EditIcon,
  SaveIcon,
  CheckIcon,
  CloseIcon,
  // ... 200+ more icons
} from "itech-fluentui/components";
```

---

## Styling & Utilities

### CSS Classes

You can still use Tailwind classes if you have Tailwind configured:

```tsx
<Button className="w-full mt-4">Button</Button>
```

### Fluent UI Styles

For Fluent UI-specific styling:

```tsx
import { makeStyles, tokens, mergeClasses } from "itech-fluentui/components";

const useStyles = makeStyles({
  button: {
    padding: tokens.spacingHorizontalM,
    borderRadius: tokens.borderRadiusMedium,
    backgroundColor: tokens.colorBrandBackground,
    color: tokens.colorBrandForeground1,
  },
});

function Component() {
  const styles = useStyles();
  return (
    <button className={mergeClasses(styles.button, "custom-class")}>
      Click
    </button>
  );
}
```

### Utility Functions

```tsx
import { cn } from "itech-fluentui"; // If you have a utils file

<div className={cn("base-class", condition && "conditional-class")} />;
```

---

## Common Patterns

### Form with React Hook Form

```tsx
import { useForm } from "react-hook-form";
import { Input, Button, Label } from "itech-fluentui/components";

function LoginForm() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm();

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Label htmlFor="email">Email</Label>
      <Input
        {...register("email", { required: "Email is required" })}
        type="email"
        id="email"
        aria-invalid={Boolean(errors.email)}
      />
      {errors.email && <span>{errors.email.message}</span>}

      <Button type="submit">Submit</Button>
    </form>
  );
}
```

### Theme Toggle Component

```tsx
import { useDesign, useTheme } from "itech-fluentui";
import { SunIcon, MoonIcon } from "itech-fluentui/components";

function ThemeToggle() {
  const { mode, toggleMode } = useDesign();
  const { theme, setTheme } = useTheme();

  return (
    <button onClick={toggleMode}>
      {mode === "light" ? <MoonIcon /> : <SunIcon />}
    </button>
  );
}
```

### Brand Switcher

```tsx
import { useDesign } from "itech-fluentui";

function BrandSwitcher() {
  const { brand, setBrand } = useDesign();

  return (
    <select value={brand} onChange={(e) => setBrand(e.target.value)}>
      <option value="vivid_blue">Vivid Blue</option>
      <option value="blue">Blue</option>
      <option value="brand_1">Brand 1</option>
      <option value="irepo">iRepo</option>
    </select>
  );
}
```

---

## Troubleshooting

### Issue: Components not styled correctly

**Solution:** Ensure all three providers are wrapped correctly:

```tsx
<DesignProvider brand="vivid_blue" mode="light">
  <ThemeProvider defaultTheme="light">
    <FluentThemeProvider>{/* Your app */}</FluentThemeProvider>
  </ThemeProvider>
</DesignProvider>
```

### Issue: Icons not showing

**Solution:** Icons are exported from the components path:

```tsx
// ✅ Correct
import { HomeIcon } from "itech-fluentui/components";

// ❌ Wrong
import { HomeIcon } from "itech-fluentui";
```

### Issue: TypeScript errors with Dialog onOpenChange

**Solution:** Fluent UI Dialog uses a different signature:

```tsx
// ✅ Correct
<Dialog onOpenChange={(e, data) => setOpen(data.open)} />

// ❌ Wrong
<Dialog onOpenChange={setOpen} />
```

### Issue: Theme not persisting

**Solution:** Check that ThemeProvider has the correct storageKey:

```tsx
<ThemeProvider
  defaultTheme="light"
  storageKey="your-app-theme" // Make sure this is unique
>
```

### Issue: Brand colors not updating

**Solution:** Ensure DesignProvider is at the top level and brand prop is set:

```tsx
<DesignProvider brand="vivid_blue" mode="light">
  {/* Rest of app */}
</DesignProvider>
```

---

## Complete Example

### App Setup

```tsx
// main.tsx or App.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import {
  DesignProvider,
  ThemeProvider,
  FluentThemeProvider,
} from "itech-fluentui";
import "itech-fluentui/styles";
import App from "./App";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <DesignProvider brand="vivid_blue" mode="light">
      <ThemeProvider defaultTheme="light" storageKey="my-app-theme">
        <FluentThemeProvider>
          <App />
        </FluentThemeProvider>
      </ThemeProvider>
    </DesignProvider>
  </React.StrictMode>
);
```

### Component Example

```tsx
// components/LoginForm.tsx
import { useState } from "react";
import { useForm } from "react-hook-form";
import {
  Button,
  Input,
  Label,
  Card,
  CardHeader,
  CardTitle,
  CardContent,
} from "itech-fluentui/components";

export function LoginForm() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm();

  const onSubmit = (data: any) => {
    console.log(data);
  };

  return (
    <Card>
      <CardHeader>
        <CardTitle>Login</CardTitle>
      </CardHeader>
      <CardContent>
        <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
          <div>
            <Label htmlFor="email">Email</Label>
            <Input
              {...register("email", { required: "Email is required" })}
              type="email"
              id="email"
              placeholder="Enter your email"
              aria-invalid={Boolean(errors.email)}
            />
            {errors.email && (
              <span className="text-red-500 text-sm">
                {errors.email.message as string}
              </span>
            )}
          </div>

          <div>
            <Label htmlFor="password">Password</Label>
            <Input
              {...register("password", { required: "Password is required" })}
              type="password"
              id="password"
              placeholder="Enter your password"
              aria-invalid={Boolean(errors.password)}
            />
            {errors.password && (
              <span className="text-red-500 text-sm">
                {errors.password.message as string}
              </span>
            )}
          </div>

          <Button type="submit" appearance="primary" className="w-full">
            Login
          </Button>
        </form>
      </CardContent>
    </Card>
  );
}
```

### Theme Toggle Component

```tsx
// components/ThemeToggle.tsx
import { useDesign } from "itech-fluentui";
import { SunIcon, MoonIcon } from "itech-fluentui/components";

export function ThemeToggle() {
  const { mode, toggleMode } = useDesign();

  return (
    <button
      onClick={toggleMode}
      className="p-2 rounded-md hover:bg-gray-100 dark:hover:bg-gray-800"
      aria-label={`Switch to ${mode === "light" ? "dark" : "light"} mode`}
    >
      {mode === "light" ? (
        <MoonIcon className="w-5 h-5" />
      ) : (
        <SunIcon className="w-5 h-5" />
      )}
    </button>
  );
}
```

---

## Migration Checklist

- [ ] Install `itech-fluentui` package
- [ ] Install peer dependencies (`@fluentui/react-components`)
- [ ] Import styles (`itech-fluentui/styles`)
- [ ] Replace ThemeProvider with DesignProvider + ThemeProvider + FluentThemeProvider
- [ ] Update component imports (from local to package)
- [ ] Update component props (variant → appearance, etc.)
- [ ] Replace lucide-react icons with Fluent UI icons
- [ ] Update Dialog onOpenChange handlers
- [ ] Test React Hook Form integration
- [ ] Update styling (Tailwind → Fluent UI tokens where needed)
- [ ] Test theme switching
- [ ] Test brand switching
- [ ] Remove old shadcn/ui components
- [ ] Update TypeScript types

---

## Additional Resources

- [Complete Documentation](./DOCUMENTATION.md)
- [Component API Reference](./COMPONENT_API.md) (if available)
- [Fluent UI v9 Documentation](https://react.fluentui.dev/)
- [Design Tokens Guide](./DESIGN_TOKENS.md) (if available)

---

## Need Help?

If you encounter issues during migration:

1. Check the [Troubleshooting](#troubleshooting) section
2. Review component examples in Storybook
3. Check the source code in `src/components/ui/`
4. Contact the iTech Design Team

---

**Last Updated:** 2024
**Version:** 1.0.5
