npm package: @firstform/spinnerwheel
Description: React spinner wheel component for random selection with animations
Author: ahzs645
Latest version: 1.1.0

# @firstform/spinnerwheel

A customizable React spinner wheel component for random selection with smooth animations, sound effects, and confetti celebrations.

## Installation

```bash
npm install @firstform/spinnerwheel
```

## Quick Start

```tsx
import { SpinnerWheel, useSpinnerWheelState } from '@firstform/spinnerwheel';
import '@firstform/spinnerwheel/styles';

function App() {
  const wheel = useSpinnerWheelState({
    initialEntries: [
      { id: '1', name: 'Pizza' },
      { id: '2', name: 'Burger' },
      { id: '3', name: 'Sushi' },
    ],
  });

  return (
    <SpinnerWheel
      entries={wheel.entries}
      isSpinning={wheel.isSpinning}
      winner={wheel.winner}
      currentSegment={wheel.currentSegment}
      showWinnerPopup={wheel.showWinnerPopup}
      onEntriesChange={wheel.setEntries}
      onSpin={wheel.spin}
      onSpinComplete={wheel.handleSpinComplete}
      onSegmentChange={wheel.handleSegmentChange}
      onWinnerPopupClose={wheel.closeWinnerPopup}
    />
  );
}
```

## Features

- Smooth spinning animations powered by GSAP
- Confetti celebration on winner selection
- Audio feedback (tick sounds and celebration)
- URL sync for shareable wheels
- Multiple color themes
- Dark and light theme variants
- Table and default layout options
- Fully typed with TypeScript

## Components

### SpinnerWheel

The main component that includes the wheel, entry management, and winner popup.

```tsx
<SpinnerWheel
  // Required props
  entries={entries}
  isSpinning={isSpinning}
  winner={winner}
  currentSegment={currentSegment}
  showWinnerPopup={showWinnerPopup}
  onEntriesChange={setEntries}
  onSpin={spin}
  onSpinComplete={handleSpinComplete}
  onWinnerPopupClose={closeWinnerPopup}

  // Optional props
  canvasSize={465}
  variant="white" // 'white' | 'dark'
  layout="default" // 'default' | 'table'
  showEntryInput={true}
  audioEnabled={true}
  confettiEnabled={true}
  colorTheme="default" // 'rainbow' | 'sunset' | 'ocean' | 'forest' | etc.
  spinDuration={10}
  spinRevolutions={7}
/>
```

### SpinnerWheelCanvas

Just the wheel canvas without entry management UI.

```tsx
import { SpinnerWheelCanvas } from '@firstform/spinnerwheel';

<SpinnerWheelCanvas
  entries={entries}
  isSpinning={isSpinning}
  onSpinComplete={handleComplete}
  onSegmentChange={handleSegmentChange}
  onSpin={handleSpin}
/>
```

## Hooks

### useSpinnerWheelState

Manages all wheel state with optional URL synchronization.

```tsx
const wheel = useSpinnerWheelState({
  initialEntries: [],
  syncToUrl: true, // Sync entries to URL for sharing
  onWinnerSelected: (winner) => console.log('Winner:', winner),
});

// Returns:
// - entries, isSpinning, winner, currentSegment, showWinnerPopup
// - setEntries, addEntries, removeEntry, clearEntries
// - spin, handleSpinComplete, handleSegmentChange, closeWinnerPopup, reset
```

### useAudio

Control audio playback.

```tsx
const audio = useAudio({ enabled: true });
audio.playTick();
audio.playCelebration();
```

### useConfetti

Trigger confetti effects.

```tsx
const confetti = useConfetti({ enabled: true });
confetti.fire();
```

## Types

```tsx
interface WheelEntry {
  id: string;
  name: string;
}

type ThemeVariant = 'white' | 'dark';
type LayoutVariant = 'default' | 'table';
type ColorTheme =
  | 'default' | 'rainbow' | 'sunset' | 'ocean'
  | 'forest' | 'candy' | 'neon' | 'pastel'
  | 'blues' | 'reds' | 'greens' | 'earth' | 'retro';
```

## Color Themes

Choose from 13 built-in color themes:

- `default` - Balanced mix of colors
- `rainbow` - Full spectrum
- `sunset` - Warm oranges and reds
- `ocean` - Blues and teals
- `forest` - Greens and earth tones
- `candy` - Bright pinks and purples
- `neon` - Vibrant glowing colors
- `pastel` - Soft muted tones
- `blues` / `reds` / `greens` - Monochromatic
- `earth` - Natural brown tones
- `retro` - Vintage color palette

## URL Sharing

Enable `syncToUrl` to automatically encode entries in the URL:

```tsx
const wheel = useSpinnerWheelState({
  syncToUrl: true,
});

// Get shareable URL
import { getShareableUrl } from '@firstform/spinnerwheel';
const url = getShareableUrl(entries);
```

## License

MIT