npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@fullstackcolombia/roseselect

v1.0.3

Published

A beautiful React component for azimuth angle selection with radar-style interface and multiple themes. No Tailwind CSS required - includes all styles pre-compiled.

Readme

RoseSelector 🧭

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

Version License TypeScript

🚀 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

npm install @fullstackcolombia/roseselect
yarn add @fullstackcolombia/roseselect
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:

// 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

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.

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.

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.

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.

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.

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:

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.

🤝 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

🌐 More Information

For more projects and development resources, visit: FullStack Colombia