# Plan: Creación del Componente Button para BL Consultores DS con Tailwind CSS

## Contexto

Se necesita crear el componente de botones para el Design System de BL Consultores. El proyecto es una librería React de componentes (`bl-consultores-ds`) basada en `create-react-component-library`.

Actualmente el starter kit incluye un componente `Card` genérico que **debe eliminarse** — es solo el template por defecto del starter kit y no forma parte del diseño system real de BL Consultores.

El diseño de los botones proviene de Penpot y está documentado en Docmost con **11 variantes exactas** (colores, tamaños, estados hover). Se usará **Tailwind CSS** para los estilos.

---

## Paso 0: Instalar y configurar Tailwind CSS

### 0.1 Instalar dependencias
```bash
npm install -D tailwindcss postcss autoprefixer
```

### 0.2 Crear `tailwind.config.js`

Configurar con los tokens exactos del diseño de Penpot:

```js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './src/**/*.{js,jsx,ts,tsx}',
  ],
  theme: {
    extend: {
      colors: {
        gold: '#EABF2D',
        amber: '#D4880F',
        black: '#1A1A2E',
        danger: '#DE3626',
        muted: '#9AA0A6',
        gray: '#6B6B7B',
        inputBorder: '#DADCE0',
      },
      borderRadius: {
        pill: '20px',
        circle: '28px',
      },
      fontSize: {
        btn: ['11px', { lineHeight: '1', fontWeight: '700' }],
        btnPrimary: ['12px', { lineHeight: '1', fontWeight: '700' }],
        btnNormal: ['12px', { lineHeight: '1', fontWeight: '400' }],
      },
      height: {
        btn: '40px',
        btnLg: '60px',
        btnCircle: '56px',
        btnIcon: '36px',
      },
      width: {
        btnPrimary: '170px',
        btnOutlineGold: '230px',
        btnOutline: '110px',
        btnOutlineLight: '140px',
        btnGhost: '110px',
        btnFileUpload: '200px',
        btnCircle: '56px',
        btnIcon: '36px',
      },
      fontFamily: {
        sans: ['sourcesanspro', 'system-ui', 'sans-serif'],
      },
    },
  },
  plugins: [],
}
```

### 0.3 Crear `postcss.config.js`
```js
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}
```

### 0.4 Ajustar `webpack.config.ts`
- Agregar `postcss-loader` como dependencia
- Agregar regla postcss en las rules de webpack (entre css-loader y sass-loader, o antes de them)
- Para componentes sin SCSS, el CSS se genera vía Tailwind classes directamente

---

## Paso 1: Eliminar el Card del starter kit

| Archivo | Acción |
|---|---|
| `src/components/Card/` | Eliminar directorio completo |
| `src/components/__tests__/Card.test.tsx` | Eliminar |
| `src/components/__tests__/Card.test.cy.tsx` | Eliminar |
| `src/components/index.tsx` | Remover `export * from './Card'` |

---

## Paso 2: Crear el componente Button

### Estructura de archivos

```
src/components/Button/
  ├── index.tsx              # Componente React + tipos
  └── Button.stories.tsx     # Storybook stories
```

Sin archivo SCSS separado — los estilos se manejan con clases Tailwind.

### TypeScript — Tipos

```tsx
type ButtonVariant =
  | 'primary'
  | 'outline-gold'
  | 'outline-dark'
  | 'outline-light'
  | 'ghost'
  | 'circular'
  | 'icon-edit'
  | 'icon-delete'
  | 'file-upload';

interface ButtonProps {
  /** Variant style of the button */
  variant?: ButtonVariant;
  /** Button text content */
  children?: React.ReactNode;
  /** Click handler */
  onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
  /** HTML button type */
  type?: 'button' | 'submit' | 'reset';
  /** Disabled state */
  disabled?: boolean;
  /** For file-upload variant: accept attribute */
  accept?: string;
  /** Optional className for additional styling */
  className?: string;
}
```

### JSX — Estructura

El componente usa un `<button>` nativo con clases Tailwind compuestas. Para `file-upload`, renderiza un `<input type="file">` oculto dentro de un `<label>`.

```tsx
const Button: FC<ButtonProps> = ({
  variant = 'primary',
  children,
  onClick,
  type = 'button',
  disabled = false,
  accept,
  className = '',
}) => {
  if (variant === 'file-upload') {
    return (
      <label
        className={`btn file-upload ${className}`.trim()}
      >
        <input
          type="file"
          accept={accept}
          className="file-input"
          onChange={onClick as any}
          disabled={disabled}
        />
        <span className="btn-content">{children}</span>
      </label>
    );
  }

  return (
    <button
      className={`btn ${variantClasses[variant]} ${className}`.trim()}
      onClick={onClick}
      type={type}
      disabled={disabled}
    >
      {children}
    </button>
  );
};
```

### Variantes — Clases Tailwind exactas desde Penpot

Cada variante tiene clases Tailwind derivadas de los valores exactos de Penpot:

| Variant | Clases Tailwind |
|---|---|
| **primary** | `w-btnPrimary h-btn bg-gold text-black font-sans font-bold text-btnPrimary px-5 rounded-btn flex items-center justify-center gap-2 transition-all duration-200 cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed` |
| **outline-gold** | `w-btnOutlineGold h-btn bg-white border-[1.5px] border-gold text-amber font-sans font-bold text-btnPrimary px-5 rounded-btn flex items-center justify-center gap-2 transition-all duration-200 cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed` |
| **outline-dark** | `w-btnOutline h-btn bg-white border-[1.5px] border-black text-black font-sans font-bold text-btn px-4 rounded-sm flex items-center justify-center gap-2 transition-all duration-200 cursor-pointer hover:bg-amber hover:text-white disabled:opacity-50 disabled:cursor-not-allowed` |
| **outline-light** | `w-btnOutlineLight h-btnLg bg-black border-[1.5px] border-white text-white font-sans font-bold text-btn px-4 rounded-sm flex items-center justify-center gap-2 transition-all duration-200 cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed` |
| **ghost** | `w-btnGhost h-btn bg-white border-[1.5px] border-black text-black font-sans font-bold text-btn px-4 rounded-pill flex items-center justify-center gap-2 transition-all duration-200 cursor-pointer hover:bg-amber hover:text-white disabled:opacity-50 disabled:cursor-not-allowed` |
| **circular** | `w-btnCircle h-btnCircle bg-white border-[1.5px] border-black rounded-circle flex items-center justify-center transition-all duration-200 cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed` |
| **icon-edit** | `w-btnIcon h-btnIcon bg-white border-[1.5px] border-gold rounded-sm flex items-center justify-center transition-all duration-200 cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed` |
| **icon-delete** | `w-btnIcon h-btnIcon bg-white border-[1.5px] border-danger rounded-sm flex items-center justify-center transition-all duration-200 cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed` |
| **file-upload** | `relative w-btnFileUpload h-btn bg-white border-[1.5px] border-gold text-amber font-sans font-normal text-btnPrimary px-4 rounded-sm flex items-center justify-center cursor-pointer disabled:opacity-50` |

**Hover states** (automáticos en las clases):
- `outline-dark` y `ghost`: `hover:bg-amber hover:text-white`

**File upload input**: `absolute inset-0 opacity-0 cursor-pointer`

---

## Paso 3: Storybook Stories

```tsx
export const Primary: Story = { args: { variant: 'primary', children: '+ Agregar' } };
export const OutlineGold: Story = { args: { variant: 'outline-gold', children: 'Editar Estructura del Clima' } };
export const OutlineDark: Story = { args: { variant: 'outline-dark', children: 'VER MÁS' } };
export const OutlineLight: Story = { args: { variant: 'outline-light', children: 'VER MÁS' } };
export const Ghost: Story = { args: { variant: 'ghost', children: 'VER MÁS' } };
export const Circular: Story = { args: { variant: 'circular', children: '↓' } };
export const IconEdit: Story = { args: { variant: 'icon-edit', children: '✏️' } };
export const IconDelete: Story = { args: { variant: 'icon-delete', children: '✕' } };
export const FileUpload: Story = { args: { variant: 'file-upload', children: 'Seleccionar CV' } };
```

Incluir también stories de:
- **States**: disabled, hover (usando `play` function)
- **Sizes**: mostrar cada variante con su tamaño design
- **Composition**: botones en grupos, con iconos

---

## Paso 4: Tests

### Jest (`Button.test.tsx`)
- Renderiza con variant default (primary)
- Click handler se llama al hacer click
- Estado disabled deshabilita interacción
- File upload renderiza input file
- Textos y props se renderizan correctamente
- Clases CSS correctas por variante

### Cypress (`Button.test.cy.tsx`)
- Mount y verifica visual de cada variant
- Hover states (outline-dark, ghost)
- Disabled state visual
- File upload label structure

---

## Paso 5: Actualizar exports

`src/components/index.tsx`:
```tsx
export * from './Button';
```

---

## Verificación

1. `npm run storybook` — verificar que todas las variantes se muestran correctamente en Storybook
2. `npm run test` — Jest tests pasan
3. `npm run cy:run` — Cypress tests pasan
4. `npm run build` — build exitoso sin errores
5. Verificar que el Card fue eliminado y no queda referencia rota
6. Verificar que Tailwind se compila correctamente en el bundle final
