npm package: @fullstackcolombia/roseselect
Description: A beautiful React component for azimuth angle selection with radar-style interface and multiple themes. No Tailwind CSS required - includes all styles pre-compiled.
Author: FullStack Colombia
Latest version: 1.0.3

# RoseSelector 🧭

A beautiful and highly customizable React component for azimuth angle selection with radar-style interface and multiple themes.

![Version](https://img.shields.io/npm/v/@fullstackcolombia/roseselect)
![License](https://img.shields.io/npm/l/@fullstackcolombia/roseselect)
![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue)

<div align="center">
  <img src="https://fullstackcolombia.com/example/roseselect.png" alt="RoseSelector Component Preview" width="300" />
</div>

## 🚀 Features

- ✨ Intuitive radar-style user interface
- 🎨 7 predefined themes (light, dark, forest, ocean, sunset, matrix, solarized)
- 🔊 Optional sound effects with Tone.js
- 📱 Responsive design
- ⌨️ Full accessibility
- 🎯 Configurable intervals (5°, 15°, or 30°)
- 🧭 Customizable north offset
- 💾 Data copy functionality
- 🎵 Optional interactive sounds

## 📦 Installation

```bash
npm install @fullstackcolombia/roseselect
```

```bash
yarn add @fullstackcolombia/roseselect
```

```bash
pnpm add @fullstackcolombia/roseselect
```

### 🎨 Style Imports

Component styles are automatically included when importing the component. However, if you need to import them manually, you can do so like this:

```tsx
// Styles are automatically imported with the component
import { RoseSelector } from '@fullstackcolombia/roseselect'

// Or import manually if needed
import '@fullstackcolombia/roseselect/dist/roseselect.css'
```

**Note:** This component includes all necessary CSS styles without depending on Tailwind CSS in your project. The styles are pre-compiled and optimized.

## 🎯 Basic Usage

```tsx
import React, { useState } from 'react'
import { RoseSelector } from '@fullstackcolombia/roseselect'
// CSS is automatically imported

function App() {
  const [selectedAngles, setSelectedAngles] = useState<number[]>([])

  return (
    <RoseSelector
      setOptions={setSelectedAngles}
    />
  )
}
```

## 📖 Usage Examples

### 1. Basic Setup with Light Theme

The simplest use of the component with default configuration.

```tsx
import React, { useState } from 'react'
import { RoseSelector } from '@fullstackcolombia/roseselect'
// CSS styles are automatically included

function BasicExample() {
  const [selectedAngles, setSelectedAngles] = useState<number[]>([])

  return (
    <div style={{ padding: '2rem' }}>
      <h2>Basic Azimuth Selection</h2>
      <RoseSelector
        setOptions={setSelectedAngles}
        initialTheme="light"
        initialInterval={15}
      />
      <div style={{ marginTop: '1rem' }}>
        <p>Selected angles: {selectedAngles.join(', ')}°</p>
      </div>
    </div>
  )
}
```

### 2. Dark Theme for Night Applications

Perfect for night navigation applications or astronomical interfaces.

```tsx
import React, { useState } from 'react'
import { RoseSelector } from '@fullstackcolombia/roseselect'
// All styles including dark theme are automatically imported

function DarkThemeExample() {
  const [windDirections, setWindDirections] = useState<number[]>([])

  return (
    <div style={{ 
      minHeight: '100vh', 
      backgroundColor: '#0f172a', 
      padding: '2rem' 
    }}>
      <h2 style={{ 
        color: 'white', 
        fontSize: '1.5rem', 
        marginBottom: '1.5rem' 
      }}>
        Wind Direction Monitor
      </h2>
      <RoseSelector
        setOptions={setWindDirections}
        initialTheme="dark"
        initialInterval={30}
      />
      <div style={{ marginTop: '1.5rem', color: 'white' }}>
        <h3>Monitored wind directions:</h3>
        <p style={{ color: '#93c5fd' }}>
          {windDirections.length} active directions
        </p>
      </div>
    </div>
  )
}
```

### 3. Matrix Theme for Futuristic Interfaces

Ideal for science fiction applications or gaming.

```tsx
import React, { useState } from 'react'
import { RoseSelector } from '@fullstackcolombia/roseselect'
// Matrix theme styles are included automatically

function MatrixThemeExample() {
  const [radarSectors, setRadarSectors] = useState<number[]>([])

  const handleSectorChange = (angles: number[]) => {
    setRadarSectors(angles)
    console.log('Radar sectors updated:', angles)
  }

  return (
    <div style={{ 
      minHeight: '100vh', 
      backgroundColor: '#000', 
      padding: '2rem' 
    }}>
      <h2 style={{ 
        color: '#4ade80', 
        fontSize: '2rem', 
        fontFamily: 'monospace', 
        marginBottom: '1.5rem' 
      }}>
        MATRIX RADAR SYSTEM
      </h2>
      <RoseSelector
        setOptions={handleSectorChange}
        initialTheme="matrix"
        initialInterval={5}
      />
      <div style={{ 
        marginTop: '1.5rem', 
        color: '#4ade80', 
        fontFamily: 'monospace' 
      }}>
        <p>ACTIVE SECTORS: {radarSectors.length}</p>
        <p>COVERAGE: {radarSectors.length * 5}°</p>
      </div>
    </div>
  )
}
```

### 4. Nautical Configuration with Ocean Theme

Perfect for maritime and navigation applications.

```tsx
import React, { useState } from 'react'
import { RoseSelector, ThemeType } from '@fullstackcolombia/roseselect'
// Ocean theme styles automatically imported

function NauticalExample() {
  const [compassBearing, setCompassBearing] = useState<number[]>([])
  const [currentTheme] = useState<ThemeType>('ocean')

  const formatBearing = (angles: number[]) => {
    return angles.map(angle => {
      const cardinal = getCardinalDirection(angle)
      return `${angle}° (${cardinal})`
    }).join(', ')
  }

  const getCardinalDirection = (angle: number) => {
    const directions = ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE',
                       'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW']
    const index = Math.round(angle / 22.5) % 16
    return directions[index]
  }

  return (
    <div style={{ 
      minHeight: '100vh', 
      backgroundColor: '#f0f9ff', 
      padding: '2rem' 
    }}>
      <h2 style={{ 
        color: '#1e40af', 
        fontSize: '1.5rem', 
        marginBottom: '1.5rem' 
      }}>
        Nautical Navigation System
      </h2>
      <div style={{ 
        backgroundColor: 'white', 
        borderRadius: '0.5rem', 
        boxShadow: '0 10px 15px -3px rgba(0, 0, 0, 0.1)', 
        padding: '1.5rem' 
      }}>
        <RoseSelector
          setOptions={setCompassBearing}
          initialTheme={currentTheme}
          initialInterval={15}
        />
        <div style={{ 
          marginTop: '1.5rem', 
          padding: '1rem', 
          backgroundColor: '#dbeafe', 
          borderRadius: '0.375rem' 
        }}>
          <h3 style={{ color: '#1d4ed8', fontWeight: '600' }}>
            Selected Course:
          </h3>
          <p style={{ color: '#2563eb' }}>
            {formatBearing(compassBearing)}
          </p>
        </div>
      </div>
    </div>
  )
}
```

### 5. Advanced Setup with Multiple Features

Complete example showing all advanced component features.

```tsx
import React, { useState, useEffect } from 'react'
import { RoseSelector, ThemeType } from '@fullstackcolombia/roseselect'
// All component styles are automatically included

function AdvancedExample() {
  const [selectedAngles, setSelectedAngles] = useState<number[]>([])
  const [currentTheme, setCurrentTheme] = useState<ThemeType>('sunset')
  const [statistics, setStatistics] = useState({
    totalSelected: 0,
    coverage: 0,
    avgAngle: 0
  })

  useEffect(() => {
    const totalSelected = selectedAngles.length
    const coverage = (totalSelected * 15) // Assuming 15° interval
    const avgAngle = selectedAngles.length > 0 
      ? selectedAngles.reduce((a, b) => a + b, 0) / selectedAngles.length 
      : 0

    setStatistics({
      totalSelected,
      coverage,
      avgAngle: Math.round(avgAngle)
    })
  }, [selectedAngles])

  const themeOptions: ThemeType[] = ['light', 'dark', 'forest', 'ocean', 'sunset', 'matrix', 'solarized']

  const exportData = () => {
    const data = {
      timestamp: new Date().toISOString(),
      theme: currentTheme,
      selectedAngles,
      statistics
    }
    
    const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' })
    const url = URL.createObjectURL(blob)
    const a = document.createElement('a')
    a.href = url
    a.download = 'azimuth-selection.json'
    a.click()
    URL.revokeObjectURL(url)
  }

  return (
    <div style={{ 
      minHeight: '100vh', 
      padding: '2rem', 
      transition: 'colors 300ms' 
    }}>
      <div style={{ maxWidth: '64rem', margin: '0 auto' }}>
        <h1 style={{ 
          fontSize: '1.875rem', 
          fontWeight: 'bold', 
          marginBottom: '2rem' 
        }}>
          Advanced Azimuth Selection System
        </h1>
        
        {/* Theme Control */}
        <div style={{ 
          marginBottom: '1.5rem', 
          padding: '1rem', 
          backgroundColor: 'white', 
          borderRadius: '0.5rem', 
          boxShadow: '0 1px 3px 0 rgba(0, 0, 0, 0.1)' 
        }}>
          <h3 style={{ 
            fontSize: '1.125rem', 
            fontWeight: '600', 
            marginBottom: '0.75rem' 
          }}>
            Theme Selector
          </h3>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.5rem' }}>
            {themeOptions.map(theme => (
              <button
                key={theme}
                onClick={() => setCurrentTheme(theme)}
                style={{
                  padding: '0.5rem 1rem',
                  borderRadius: '9999px',
                  fontSize: '0.875rem',
                  fontWeight: '500',
                  transition: 'all 150ms',
                  backgroundColor: currentTheme === theme ? '#3b82f6' : '#e5e7eb',
                  color: currentTheme === theme ? 'white' : 'black',
                  border: 'none',
                  cursor: 'pointer',
                  boxShadow: currentTheme === theme ? '0 10px 15px -3px rgba(0, 0, 0, 0.1)' : 'none'
                }}
              >
                {theme.charAt(0).toUpperCase() + theme.slice(1)}
              </button>
            ))}
          </div>
        </div>

        {/* Main Component */}
        <div style={{ marginBottom: '2rem' }}>
          <RoseSelector
            setOptions={setSelectedAngles}
            initialTheme={currentTheme}
            initialInterval={15}
          />
        </div>

        {/* Statistics Panel */}
        <div style={{ 
          display: 'grid', 
          gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))', 
          gap: '1.5rem' 
        }}>
          <div style={{ 
            backgroundColor: 'white', 
            padding: '1.5rem', 
            borderRadius: '0.5rem', 
            boxShadow: '0 1px 3px 0 rgba(0, 0, 0, 0.1)' 
          }}>
            <h3 style={{ 
              fontSize: '1.25rem', 
              fontWeight: '600', 
              marginBottom: '1rem' 
            }}>
              Statistics
            </h3>
            <div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
              <div style={{ display: 'flex', justifyContent: 'space-between' }}>
                <span>Selected Sectors:</span>
                <span style={{ fontWeight: 'bold' }}>{statistics.totalSelected}</span>
              </div>
              <div style={{ display: 'flex', justifyContent: 'space-between' }}>
                <span>Total Coverage:</span>
                <span style={{ fontWeight: 'bold' }}>{statistics.coverage}°</span>
              </div>
              <div style={{ display: 'flex', justifyContent: 'space-between' }}>
                <span>Average Angle:</span>
                <span style={{ fontWeight: 'bold' }}>{statistics.avgAngle}°</span>
              </div>
            </div>
          </div>

          <div style={{ 
            backgroundColor: 'white', 
            padding: '1.5rem', 
            borderRadius: '0.5rem', 
            boxShadow: '0 1px 3px 0 rgba(0, 0, 0, 0.1)' 
          }}>
            <h3 style={{ 
              fontSize: '1.25rem', 
              fontWeight: '600', 
              marginBottom: '1rem' 
            }}>
              Actions
            </h3>
            <div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
              <button
                onClick={exportData}
                style={{
                  width: '100%',
                  backgroundColor: '#10b981',
                  color: 'white',
                  padding: '0.5rem 1rem',
                  borderRadius: '0.375rem',
                  border: 'none',
                  cursor: 'pointer',
                  transition: 'background-color 150ms'
                }}
                onMouseOver={(e) => e.currentTarget.style.backgroundColor = '#059669'}
                onMouseOut={(e) => e.currentTarget.style.backgroundColor = '#10b981'}
              >
                Export Data
              </button>
              <div style={{ 
                fontSize: '0.875rem', 
                color: '#6b7280' 
              }}>
                <p>Current theme: <strong>{currentTheme}</strong></p>
                <p>Angles: {selectedAngles.join(', ')}°</p>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  )
}
```

## 📋 Props API

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `setOptions` | `(value: number[]) => void` | **Required** | Callback that receives the selected angles |
| `initialTheme` | `ThemeType` | `'light'` | Initial component theme |
| `initialInterval` | `number` | `15` | Initial interval in degrees (5, 15, or 30) |

## 🎨 Available Themes

- **light**: Light theme for daytime use
- **dark**: Elegant dark theme
- **forest**: Nature-inspired green theme
- **ocean**: Maritime blue theme
- **sunset**: Warm orange theme
- **matrix**: Matrix-style green theme
- **solarized**: Soft yellow theme

## 🔊 Audio Features

The component includes optional sound effects using Tone.js:

- Click sounds when selecting elements
- Swoosh effects for group actions
- Unique sounds for each action (select all, clear, etc.)
- Integrated mute control in the context menu

## 🎯 TypeScript

The component is fully typed with TypeScript:

```tsx
import type { ThemeType, QuadrantType } from '@fullstackcolombia/roseselect'
```

## 💡 No Tailwind CSS Required

This component works standalone without requiring Tailwind CSS in your project:

- ✅ All styles are pre-compiled and included
- ✅ No external CSS dependencies
- ✅ Works with any React setup
- ✅ Compatible with Create React App, Vite, Next.js, etc.

For projects without any styling framework, see our [No Tailwind Setup Guide](docs/NO-TAILWIND-SETUP.md).

## 🤝 Contributing

Contributions are welcome. Please:

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## 📄 License

MIT © [FullStack Colombia](https://fullstackcolombia.com)

## 🌐 More Information

For more projects and development resources, visit: **[FullStack Colombia](https://fullstackcolombia.com)**

---

<div align="center">
  <p>Made with ❤️ by <a href="https://fullstackcolombia.com">FullStack Colombia</a></p>
</div>