npm package: @super-resume/ui-kit-experimental
Description: A comprehensive React UI component library with a semantic design token system, built with Tailwind CSS v4.
Latest version: 0.4.0

# @super-resume/ui-kit

A comprehensive React UI component library with a semantic design token system, built with Tailwind CSS v4.

## 🎨 Design Token System

This UI Kit uses a comprehensive semantic token system for consistent, accessible, and theme-ready designs.

### Key Features

- ✅ **Semantic Tokens**: Purpose-driven naming (primary-base, text-primary) instead of hard-coded colors
- ✅ **WCAG AA Compliant**: All color combinations meet accessibility standards
- ✅ **Dark Mode Ready**: Full dark mode support with automatic token switching
- ✅ **Type-Safe**: TypeScript types included for all tokens
- ✅ **4-Point Spacing Scale**: Consistent spacing based on 4px units
- ✅ **Typography Scale**: Harmonious type ramp with predefined sizes and weights

### Token Categories

| Category | Tokens | Example |
|----------|--------|---------|
| **Colors** | Primary, Success, Warning, Error, Text, Surface, Border | `var(--color-primary-base)` |
| **Typography** | display-lg, headline-lg, title-md, body-md, body-sm, label-sm | `var(--font-body-md-size)` |
| **Spacing** | xs (4px), sm (8px), md (16px), lg (24px), xl (32px) | `var(--space-md)` |
| **Radius** | sm (4px), md (8px), lg (16px), xl (24px), full | `var(--radius-md)` |
| **Elevation** | 1, 2, 3, 4 | `var(--elevation-2)` |

### Quick Token Usage

```tsx
// Using semantic color tokens
<div className="bg-[var(--color-primary-base)] text-[var(--color-primary-on)]">
  Primary Button
</div>

// Using typography tokens
<h1 className="text-[length:var(--font-headline-lg-size)] leading-[var(--font-headline-lg-line-height)] font-[var(--font-headline-lg-weight)]">
  Section Title
</h1>

// Using spacing tokens
<div className="p-[var(--space-lg)] gap-[var(--space-md)]">
  Card Content
</div>

// Using TypeScript helpers
import { getColorToken, getSpacingToken } from '@super-resume/ui-kit';

const bgColor = getColorToken('primary-base');    // 'var(--color-primary-base)'
const padding = getSpacingToken('md');             // 'var(--space-md)'
```

### Dark Mode Support

```tsx
// Enable dark mode by adding the 'dark' class to your root element
<html className="dark">
  <body>
    {/* All components automatically adapt to dark mode */}
  </body>
</html>

// Or use next-themes for automatic theme switching
import { ThemeProvider } from 'next-themes';

<ThemeProvider attribute="class">
  <App />
</ThemeProvider>
```

### Responsive Grid

| Device | Breakpoint | Columns |
|--------|------------|---------|
| Mobile | < 768px | 4 |
| Tablet | 768px - 1024px | 8 |
| Desktop | ≥ 1024px | 12 |

```tsx
<div className="grid grid-cols-4 md:grid-cols-8 lg:grid-cols-12">
  {/* Responsive grid content */}
</div>
```

### Documentation

- **Storybook**: View live component demos and token documentation
- **Migration Guide**: See `MIGRATION.md` for upgrading from older versions
- **TypeScript Types**: Full type safety with exported token types

---

## Installation & Usage

## 1. Install the UI Kit

Using npm:
```bash
npm install @super-resume/ui-kit@version
```
Or using yarn:
```bash
yarn add @super-resume/ui-kit@version
```

## 1.1. Configure .npmrc (if using a private or scoped package)
If your UI kit is a private package or uses a custom registry (e.g., GitHub Packages, npm Enterprise), you may need to add an `.npmrc` file to your project root:

```ini
//registry.npmjs.org/:_authToken=<YOUR_NPM_TOKEN>
```
Or for a scoped package (replace `@your-scope` and registry URL):
```ini
@your-scope:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=<YOUR_GITHUB_TOKEN>
```

Refer to your package provider's documentation for more details on authentication and registry configuration.

## 2. Configure CSS

### a. Import the UI Kit CSS in your main CSS file (e.g., `src/index.css` or `App.css`):

If you are using **Tailwind CSS v4**, import Tailwind at the top of your CSS file:

```css
@import "tailwindcss";
@import '<your-ui-kit-package-name>/dist/styles.css';
```

> **Note:** The `@import "tailwindcss";` line replaces the old `@tailwind base;`, `@tailwind components;`, and `@tailwind utilities;` directives in Tailwind v4.

#add config to your global.css file

```config 
@config "../../tailwind.config.js";
```

#add theme variables to your global.css file

Copy and paste the following into your `global.css` (or `src/index.css`) **before any Tailwind or UI kit imports**:

```css

:root {
  --font-main: 'Poppins', 'Kanit', Arial, Helvetica, sans-serif;
  --radius: 0.625rem;
  --background: oklch(1 0 0);
  --foreground: oklch(0.145 0 0);
  --card: oklch(1 0 0);
  --card-foreground: oklch(0.145 0 0);
  --popover: oklch(1 0 0);
  --popover-foreground: oklch(0.145 0 0);
  --primary: oklch(0.205 0 0);
  --primary-foreground: oklch(0.985 0 0);
  --secondary: oklch(0.97 0 0);
  --secondary-foreground: oklch(0.205 0 0);
  --muted: oklch(0.97 0 0);
  --muted-foreground: oklch(0.556 0 0);
  --accent: oklch(0.97 0 0);
  --accent-foreground: oklch(0.205 0 0);
  --destructive: oklch(0.577 0.245 27.325);
  --border: oklch(0.922 0 0);
  --input: oklch(0.922 0 0);
  --ring: #e1ebfeb2;
  --chart-1: oklch(0.646 0.222 41.116);
  --chart-2: oklch(0.6 0.118 184.704);
  --chart-3: oklch(0.398 0.07 227.392);
  --chart-4: oklch(0.828 0.189 84.429);
  --chart-5: oklch(0.769 0.188 70.08);
  --sidebar: oklch(0.985 0 0);
  --sidebar-foreground: oklch(0.145 0 0);
  --sidebar-primary: oklch(0.205 0 0);
  --sidebar-primary-foreground: oklch(0.985 0 0);
  --sidebar-accent: oklch(0.97 0 0);
  --sidebar-accent-foreground: oklch(0.205 0 0);
  --sidebar-border: oklch(0.922 0 0);
  --sidebar-ring: oklch(0.708 0 0);
}

/* Dark mode custom variant - DISABLED
@custom-variant dark (&:is(.dark *));
*/

@theme {
  /* Spacing */
  --spacing-0px: 0px;
  --spacing-1px: 1px;
  --spacing-2px: 2px;
  --spacing-3px: 4px;
  --spacing-4px: 8px;
  --spacing-5px: 10px;
  --spacing-6px: 12px;
  --spacing-7px: 14px;
  --spacing-8px: 16px;
  --spacing-9px: 18px;
  --spacing-10px: 20px;
  --spacing-11px: 22px;
  --spacing-12px: 24px;
  --spacing-13px: 28px;
  --spacing-14px: 32px;
  --spacing-15px: 36px;
  --spacing-16px: 40px;
  --spacing-17px: 44px;
  --spacing-18px: 48px;
  --spacing-19px: 52px;
  --spacing-20px: 56px;
  --spacing-21px: 60px;
  --spacing-22px: 64px;
  --spacing-23px: 80px;

  /* font size */
  --text-heading-h1-desktop: 48px;
  --text-heading-h1-desktop--line-height: 64px;
  --text-heading-h1-mobile: 46px;
  --text-heading-h1-mobile--line-height: 62px;

  --text-heading-h2-desktop: 40px;
  --text-heading-h2-desktop--line-height: 48px;
  --text-heading-h2-mobile: 38px;
  --text-heading-h2-mobile--line-height: 46px;

  --text-heading-h3-desktop: 28px;
  --text-heading-h3-desktop--line-height: 36px;
  --text-heading-h3-mobile: 26px;
  --text-heading-h3-mobile--line-height: 34px;

  --text-title-1-desktop: 24px;
  --text-title-1-desktop--line-height: 36px;
  --text-title-1-mobile: 22px;
  --text-title-1-mobile--line-height: 33px;

  --text-title-2-desktop: 20px;
  --text-title-2-desktop--line-height: 30px;
  --text-title-2-mobile: 18px;
  --text-title-2-mobile--line-height: 28px;

  --text-body-1-desktop: 18px;
  --text-body-1-desktop--line-height: 28px;
  --text-body-1-mobile: 16px;
  --text-body-1-mobile--line-height: 24px;

  --text-body-2-desktop: 16px;
  --text-body-2-desktop--line-height: 24px;
  --text-body-2-mobile: 14px;
  --text-body-2-mobile--line-height: 21px;

  --text-body-3-desktop: 14px;
  --text-body-3-desktop--line-height: 21px;
  --text-body-3-mobile: 12px;
  --text-body-3-mobile--line-height: 18px;

  --text-label-1-desktop: 12px;
  --text-label-1-desktop--line-height: 16px;
  --text-label-1-mobile: 10px;
  --text-label-1-mobile--line-height: 14px;

  --text-label-2-desktop: 10px;
  --text-label-2-desktop--line-height: 14px;
  --text-label-2-mobile: 8px;
  --text-label-2-mobile--line-height: 12px;

  --color-white: #ffffff;
  --color-black: #000000;

  /* Grey Colors */
  --color-grey-100: #f9fafb;
  --color-grey-200: #e5e7eb;
  --color-grey-300: #c8ced7;
  --color-grey-400: #9ca3af;
  --color-grey-500: #6b7280;
  --color-grey-600: #4b5563;
  --color-grey-700: #374151;
  --color-grey-800: #1f2937;
  --color-grey-900: #111827;

  /* Blue Colors */
  --color-blue-100: #f5f8fe;
  --color-blue-200: #e1f6ff;
  --color-blue-300: #7fe6ff;
  --color-blue-400: #06c5f3;
  --color-blue-500: #00bff9;
  --color-blue-600: #007aff;
  --color-blue-700: #003f88;
  --color-blue-800: #17283b;

  /* Green Colors */
  --color-green-100: #f0fdf4;
  --color-green-200: #dcfee6;
  --color-green-400: #23dd9a;
  --color-green-800: #00945f;

  /* Yellow Colors */
  --color-yellow-100: #fff9df;
  --color-yellow-200: #fef4cc;
  --color-yellow-400: #ffd241;
  --color-yellow-800: #c79903;

  /* Orange Colors */
  --color-orange-100: #fff7eb;
  --color-orange-200: #fbeacf;
  --color-orange-400: #f58a50;
  --color-orange-800: #ca6805;

  /* Red Colors */
  --color-red-100: #fef2f2;
  --color-red-200: #ffe2e2;
  --color-red-400: #ef4444;
  --color-red-800: #b20b0b;

  /* Pink Colors */
  --color-pink-100: #fdf2f8;
  --color-pink-200: #ffdde8;
  --color-pink-400: #ff6e86;
  --color-pink-800: #f43968;

  /* Violet Colors */
  --color-violet-100: #f5f3ff;
  --color-violet-200: #e6e2ff;
  --color-violet-400: #8b5cf6;
  --color-violet-800: #4c1d95;

  /* Neutral color */
  --color-neutral-100: #f9fafb;
  --color-neutral-200: #e5e7eb;
  --color-neutral-300: #c8ced7;
  --color-neutral-400: #9ca3af;
  --color-neutral-500: #6b7280;
  --color-neutral-600: #4b5563;
  --color-neutral-700: #374151;
  --color-neutral-800: #1f2937;
  --color-neutral-900: #111827;

  /* Primary Colors */
  --color-primary-50: #f5f8fe;
  --color-primary-100: #eff6ff;
  --color-primary-200: #e1f6ff;
  --color-primary-300: #7fe6ff;
  --color-primary-400: #06c5f3;
  --color-primary-500: #00bff9;
  --color-primary-600: #007aff;
  --color-primary-700: #003f88;
  --color-primary-800: #17283b;
  --color-primary-default-yshs: #06c5f3;
  --color-primary-topgun: #00bff9;
  --color-primary-superresume: #003f88;

  /* Secondary Colors */
  --color-secondary-100: #fdf2f8;
  --color-secondary-200: #ffdde8;
  --color-secondary-400: #ff6e86;
  --color-secondary-800: #f43968;

  /* Error Colors */
  --color-error-100: #fef2f2;
  --color-error-200: #ffe2e2;
  --color-error-400: #ef4444;
  --color-error-800: #b20b0b;

  /* Success Colors */
  --color-success-100: #f0fdf4;
  --color-success-200: #dcfee6;
  --color-success-400: #23dd9a;
  --color-success-800: #00945f;

  /* Warning Colors */
  --color-warning-100: #fff7eb;
  --color-warning-200: #fbeacf;
  --color-warning-400: #f58a50;
  --color-warning-800: #ca6805;

  --color-background-50: #f5f8fe;

  --shadow-button: 0px 2px 6px 0px #04408e0f;
  --shadow-card: 0px 6px 15px -2px #04408e14;
  --shadow-others: 0px 8px 24px -3px #04408e1a, 0px 8px 24px -3px #04408e0d;

  /* Gradient Colors */
  --gradient-primary: linear-gradient(to right, var(--color-primary-600), var(--color-primary-500));
  --gradient-secondary: linear-gradient(
    to right,
    var(--color-background-50),
    var(--color-secondary-400)
  );

  --color-background: var(--background);
  --color-foreground: var(--foreground);
}

@theme inline {
  --radius-sm: calc(var(--radius) - 4px);
  --radius-md: calc(var(--radius) - 2px);
  --radius-lg: var(--radius);
  --radius-xl: calc(var(--radius) + 4px);
  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --color-card: var(--card);
  --color-card-foreground: var(--card-foreground);
  --color-popover: var(--popover);
  --color-popover-foreground: var(--popover-foreground);
  --color-primary: var(--primary);
  --color-primary-foreground: var(--primary-foreground);
  --color-secondary: var(--secondary);
  --color-secondary-foreground: var(--secondary-foreground);
  --color-muted: var(--muted);
  --color-muted-foreground: var(--muted-foreground);
  --color-accent: var(--accent);
  --color-accent-foreground: var(--accent-foreground);
  --color-destructive: var(--destructive);
  --color-border: var(--border);
  --color-input: var(--input);
  --color-ring: var(--ring);
  --color-chart-1: var(--chart-1);
  --color-chart-2: var(--chart-2);
  --color-chart-3: var(--chart-3);
  --color-chart-4: var(--chart-4);
  --color-chart-5: var(--chart-5);
  --color-sidebar: var(--sidebar);
  --color-sidebar-foreground: var(--sidebar-foreground);
  --color-sidebar-primary: var(--sidebar-primary);
  --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
  --color-sidebar-accent: var(--sidebar-accent);
  --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
  --color-sidebar-border: var(--sidebar-border);
  --color-sidebar-ring: var(--sidebar-ring);
}

/* Dark mode styles - DISABLED
.dark {
  --background: oklch(0.145 0 0);
  --foreground: oklch(0.985 0 0);
  --card: oklch(0.205 0 0);
  --card-foreground: oklch(0.985 0 0);
  --popover: oklch(0.205 0 0);
  --popover-foreground: oklch(0.985 0 0);
  --primary: oklch(0.922 0 0);
  --primary-foreground: oklch(0.205 0 0);
  --secondary: oklch(0.269 0 0);
  --secondary-foreground: oklch(0.985 0 0);
  --muted: oklch(0.269 0 0);
  --muted-foreground: oklch(0.708 0 0);
  --accent: oklch(0.269 0 0);
  --accent-foreground: oklch(0.985 0 0);
  --destructive: oklch(0.704 0.191 22.216);
  --border: oklch(1 0 0 / 10%);
  --input: oklch(1 0 0 / 15%);
  --ring: oklch(0.556 0 0);
  --chart-1: oklch(0.488 0.243 264.376);
  --chart-2: oklch(0.696 0.17 162.48);
  --chart-3: oklch(0.769 0.188 70.08);
  --chart-4: oklch(0.627 0.265 303.9);
  --chart-5: oklch(0.645 0.246 16.439);
  --sidebar: oklch(0.205 0 0);
  --sidebar-foreground: oklch(0.985 0 0);
  --sidebar-primary: oklch(0.488 0.243 264.376);
  --sidebar-primary-foreground: oklch(0.985 0 0);
  --sidebar-accent: oklch(0.269 0 0);
  --sidebar-accent-foreground: oklch(0.985 0 0);
  --sidebar-border: oklch(1 0 0 / 10%);
  --sidebar-ring: oklch(0.556 0 0);
}
*/

/* System dark mode preference detection - DISABLED
@media (prefers-color-scheme: dark) {
  :root {
    --background: #0a0a0a;
    --foreground: #ededed;
  }
}
*/

@layer base {
  * {
    @apply border-border outline-ring/50;
  }

  body {
    @apply bg-background text-foreground;
  }
}

body {
  background: var(--color-neutral-100) !important; /* neutral-100 */
  color: var(--foreground);
  font-family: var(--font-main);
}

/* Heart Animation for Double-Click Like Feature */
@keyframes heartScale {
  0% {
    transform: scale(0.8);
    opacity: 0;
  }
  15% {
    transform: scale(1.2);
    opacity: 1;
  }
  30% {
    transform: scale(1);
    opacity: 1;
  }
  100% {
    transform: scale(1);
    opacity: 0;
  }
}
```

---

## 🧩 UI Component Coding Guidelines *(to be updated as needed)*

This project follows a consistent pattern for building reusable UI components. Please follow these rules when creating or modifying components to maintain clarity, scalability, and developer experience.

---

### ✅ File Naming

- Use **PascalCase** for all component filenames and folders.

```bash
✅ Button.tsx
✅ FormItem.tsx
❌ button.tsx
❌ form-item.tsx
```

### ✅ Class Naming
- Always use a unique, specific class name prefix such as ``topgun-{component-name}`` to avoid global class conflicts and improve debugging.
- Use ``cn()`` (className merge) utility to combine dynamic class names safely.

```tsx
<button className={cn('topgun-button', className)}>Click</button>
```
- This naming convention is useful when working with Tailwind CSS, debugging in DevTools, or generating design tokens.

### ✅ CSS Styling Guidelines *(Default: Use Tailwind CSS)*
This UI library uses **Tailwind CSS** as the primary styling system for all components. However, in cases where Tailwind cannot fully support the required styling or specific behavior (e.g., keyframe animations, advanced loaders, browser quirks), we allow the use of `.css` files.

- Always try to use utility classes provided by Tailwind.
- Stick to spacing, typography, color, and layout tokens defined by Tailwind.
- Compose classes using the `cn()` utility if dynamic styling is needed.

```tsx
export const Button = ({ className, ...props }: ButtonProps) => (
  <button className={cn('topgun-button px-4 py-2 text-sm', className)} {...props} />
);
```

#### 🛠️ When Tailwind is Not Enough?
If a component cannot be styled properly using Tailwind (e.g., custom keyframe animation, browser-specific hacks), follow this rule:
- Create a .css file with the same name as the component in the same folder.
- Use a specific, scoped class name like topgun-loader, topgun-tooltip, etc.
- Import the CSS file at the top of the component.
Example
```tsx
// Loader.tsx
import './Loader.css';

export const Loader = () => {
  return <div className="topgun-loader" />;
};
```

```css
/* Loader.css */
.topgun-loader {
  width: 24px;
  height: 24px;
  border: 3px solid #e0e0e0;
  border-top-color: #3b82f6;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}
```

### ✅ Export Style
- Always use ``export const`` to define components — do not use export default.
- This improves auto-import accuracy, prevents naming conflicts, and keeps code more explicit.

```tsx
// ✅ Recommended
export const Button = () => { ... };

// ❌ Avoid
export default Button;
```
### ✅ Export Prop Types
- Each component should export its props type (ComponentNameProps) to enable reusability and extension.

```tsx
export interface ButtonProps {
  size?: 'sm' | 'md' | 'lg';
}

export const Button = ({ size = 'md' }: ButtonProps) => { ... };
```