npm package: @remodl/ui
Description: A comprehensive React component library built on Radix UI and Tailwind CSS
Author: Remodl AI
Latest version: 1.0.96

# @remodl/ui

Shared UI components for the Remodl ecosystem. This package provides a comprehensive set of React components optimized for Next.js applications.

## Features

- 🎨 **Modular Design**: Tree-shakable component exports
- 🚀 **Next.js Optimized**: Built specifically for Next.js applications
- 📦 **Dual Module Support**: ESM and CommonJS builds
- 🎯 **TypeScript First**: Full TypeScript support with type definitions
- 🎨 **Tailwind CSS**: Styled with Tailwind CSS and Radix UI primitives
- 🔧 **Customizable**: Built with tailwind-variants for easy theming

## Compatibility

⚠️ **Important**: @remodl/ui is currently compatible with **Next.js 14.x** only.

- ✅ **Next.js 14.x** - Fully compatible
- ❌ **Next.js 15.x** - Not compatible (known issues with chart rendering)

This is due to changes in Next.js 15's server component handling and hydration behavior that affect client-side chart libraries like Recharts. We are working on Next.js 15 compatibility for a future release.

## Installation

```bash
npm install @remodl/ui
```

### Peer Dependencies

This package requires the following peer dependencies:

```bash
npm install react react-dom @radix-ui/react-* lucide-react recharts
```

### Required Setup

#### 1. Import Global Styles

**Important**: To ensure components render with the correct design language, you must import the global styles in your application:

```css
/* In your app's global CSS file (e.g., app/globals.css) */
@import '@remodl/ui/styles/globals.css';
```

Or in your root layout:

```typescript
// app/layout.tsx
import '@remodl/ui/styles/globals.css';
```

This provides:
- ✅ Inter font family
- ✅ Proper text colors and dark mode support
- ✅ Base Tailwind directives
- ✅ Essential design system foundation

#### 2. Configure Tailwind CSS

**Critical**: You MUST add @remodl/ui to your Tailwind content configuration. Without this, the component styles will not be generated:

```javascript
// tailwind.config.js or tailwind.config.ts
module.exports = {
  content: [
    // ... your app's content paths
    './node_modules/@remodl/ui/dist/**/*.{js,ts,jsx,tsx}',
  ],
  // ... rest of your config
}
```

⚠️ **Why this is required**: @remodl/ui components use Tailwind utility classes. If Tailwind doesn't scan the package files, it won't generate the CSS for these utilities, resulting in unstyled or broken components.

## Usage

### Import Everything

```typescript
import { Button, Input, Card } from '@remodl/ui';
```

### Import by Category (Tree-shakable)

```typescript
import { Button } from '@remodl/ui/buttons';
import { Input, Label, SearchInput, RemodlSearchInputWithAutocomplete } from '@remodl/ui/forms';
import { Card, Table } from '@remodl/ui/display';
import { Tabs, Dropdown } from '@remodl/ui/navigation';
import { Layout, Container } from '@remodl/ui/layout';
import { SparkAreaChart } from '@remodl/ui/charts';
import { cn, focusRing } from '@remodl/ui/utils';
import { colors, spacing } from '@remodl/ui/styles';
```

## Using with State Management

@remodl/ui components are designed to be state-agnostic and work seamlessly with any state management solution. While components manage their own internal UI state (animations, transitions), you can easily integrate them with external state management for business logic and persistence.

### Example: Using with Zustand

Here's how to use @remodl/ui components with Zustand for persistent state management:

```typescript
// store.ts - Your Zustand store
import { create } from 'zustand';
import { persist } from 'zustand/middleware';

interface AppStore {
  // Track which banners have been dismissed
  dismissedBanners: Record<string, boolean>;
  dismissBanner: (bannerId: string) => void;
  
  // Track notification preferences
  notificationSettings: {
    showAlerts: boolean;
    emailNotifications: boolean;
  };
  updateNotificationSettings: (settings: Partial<AppStore['notificationSettings']>) => void;
}

export const useAppStore = create<AppStore>()(
  persist(
    (set) => ({
      dismissedBanners: {},
      dismissBanner: (bannerId) =>
        set((state) => ({
          dismissedBanners: {
            ...state.dismissedBanners,
            [bannerId]: true,
          },
        })),
      
      notificationSettings: {
        showAlerts: true,
        emailNotifications: false,
      },
      updateNotificationSettings: (settings) =>
        set((state) => ({
          notificationSettings: {
            ...state.notificationSettings,
            ...settings,
          },
        })),
    }),
    {
      name: 'app-storage', // localStorage key
    }
  )
);
```

```typescript
// BannerContainer.tsx - Using @remodl/ui with Zustand
import { BasicBanner } from '@remodl/ui/display';
import { useAppStore } from './store';

export function WelcomeBanner() {
  const { dismissedBanners, dismissBanner } = useAppStore();
  
  // If banner was previously dismissed (persisted in localStorage), don't render
  if (dismissedBanners['welcome-banner']) {
    return null;
  }
  
  return (
    <BasicBanner
      title="Welcome to Remodl!"
      message="Get started by exploring our documentation."
      onDismiss={() => {
        // Update Zustand store - this persists to localStorage
        dismissBanner('welcome-banner');
      }}
    />
  );
}
```

### Key Principles

1. **Separation of Concerns**: 
   - @remodl/ui components handle UI state (animations, transitions, hover states)
   - Your state management handles business logic (user preferences, data persistence)

2. **No Conflicts**: 
   - Component internal state is completely isolated
   - External state management controls whether components render
   - Both can coexist without interference

3. **Progressive Enhancement**:
   - Start with basic components using local state
   - Add persistence later without changing component code
   - Mix stateful and stateless usage as needed

### Other State Management Solutions

The same pattern works with any state management solution:

```typescript
// Redux Toolkit
const bannerSlice = createSlice({
  name: 'banners',
  initialState: { dismissed: {} },
  reducers: {
    dismissBanner: (state, action) => {
      state.dismissed[action.payload] = true;
    }
  }
});

// Jotai
const dismissedBannersAtom = atomWithStorage('dismissedBanners', {});

// Valtio
const appState = proxy({
  dismissedBanners: {}
});
```

The integration pattern remains the same: use your state management to control component visibility and persistence, while letting @remodl/ui handle the presentation layer.

## Component Categories

- **`/buttons`** - Button components and variants
- **`/forms`** - Form controls (inputs, labels, selects, search components, etc.)
  - SearchInput - Basic search input with Enter key handling
  - RemodlSearchInputWithAutocomplete - Advanced search with dropdown autocomplete
  - [📖 Search Components Documentation](./docs/components/SEARCH.md)
- **`/charts`** - Chart components (spark charts, progress circles)
- **`/display`** - Display components (cards, tables, dialogs)
- **`/navigation`** - Navigation components (tabs, dropdowns, breadcrumbs)
- **`/layout`** - Layout components (containers, grids, sections)
- **`/patterns`** - Complex component patterns from admin showcase
- **`/utils`** - Utility functions (className merging, focus rings)
- **`/styles`** - Style utilities and design tokens

## Development

This package follows the proven patterns established by `@lexiq/types` for consistency across the Remodl ecosystem.

### Building

```bash
npm run build        # Build both ESM and CJS
npm run build:esm    # Build ESM only
npm run build:cjs    # Build CJS only
npm run clean        # Clean dist folder
```

## License

MIT License - see LICENSE file for details.

## Changelog

### v1.0.41
- Added SearchInput component - lightweight wrapper for search with Enter key handling
- Added RemodlSearchInputWithAutocomplete - advanced search with dropdown supporting:
  - Static items (simple string arrays)
  - Async search functions
  - LexIQ knowledge API integration
- Full keyboard navigation (Arrow keys, Enter, Escape)
- Debounced search with configurable delay
- ARIA accessibility compliance
- Created dedicated search showcase page

### v1.0.18
- Fixed missing className prop on SparkAreaChart linearGradient element
- Discovered and documented Next.js 14.x compatibility requirement
- Charts now render correctly in Next.js 14.x environments

### v1.0.9
- Fixed SparkAreaChart SSR hydration issue
- Replaced React.useId() with stable ID generation to prevent gradient reference mismatches
- Charts now render correctly in all Next.js environments

### v1.0.8
- Moved all component dependencies from peerDependencies to dependencies
- Now includes: recharts, all Radix UI packages, lucide-react, and @remixicon/react
- Only React and React DOM remain as peer dependencies
- Consuming applications no longer need to manually install component dependencies

### v1.0.6
- Added missing chart colors (rose, teal, orange, green) to chartUtils
- All original colors preserved plus new additions

### v1.0.5
- Fixed chart components (SparkAreaChart, SparkBarChart, SparkLineChart) not rendering by adding stroke and fill utilities to Tailwind configuration
- Extended theme to properly support SVG stroke and fill colors

### v1.0.4
- Initial release with complete component set from remodl-next
- Added critical Tailwind configuration documentation

## Contributing

This package is part of the internal Remodl ecosystem. Components are extracted from battle-tested implementations in the Remodl platform.