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 🙏

© 2025 – Pkg Stats / Ryan Hefner

ticket-selector

v1.0.8

Published

A professional stadium seat selection widget with multi-language support

Readme

TicketSelector Widget

Version License: MIT JavaScript Bundle Size CSS Size

A professional stadium seat selection widget with multi-language support and comprehensive functionality. Perfect for event ticketing systems, stadium booking platforms, and venue management applications.

✨ Features

  • 🎯 Interactive seat selection with real-time feedback and visual indicators
  • 🌍 Multi-language support (English, Azerbaijani, and more) with automatic browser detection
  • 🔄 Pan and zoom controls with smooth animations and fullscreen mode
  • 📱 Responsive design that works flawlessly on all devices and screen sizes
  • 🎨 Customizable styling with BEM CSS methodology and SCSS variables
  • Professional build system with minification, tree-shaking, and optimization
  • 🧩 Modular architecture with ES6 modules and bundled dependencies
  • 🔧 Event-driven API for seamless integration with any backend system
  • 🎪 Dynamic sector loading with loading states and error handling
  • 🖱️ Advanced tooltips with seat information and availability status

🚀 Installation

Via Local Files (Recommended)

Download and include the built files from the dist directory:

<!-- Include CSS -->
<link rel="stylesheet" href="../dist/ticket-selector.min.css">

<!-- Include JavaScript (Panzoom is bundled) -->
<script src="../dist/ticket-selector.js"></script>

Alternative Installation

  1. Clone the repository and build the project:

    git clone https://github.com/IBP-LLC/ticket-selector.git
    cd ticket-selector
    npm install
    npm run build
  2. Include the CSS and JS files in your project:

    <link rel="stylesheet" href="path/to/dist/ticket-selector.min.css">
    <script src="path/to/dist/ticket-selector.js"></script>

📖 Quick Start

1. HTML Structure

<div id="ticket-selector" class="ticket-select">
    <div class="ticket-select__container">
        <div class="ticket-select__wrapper">
            <div class="ticket-select__viewport">
                <div class="ticket-select__content">
                    <div class="ticket-select__stadium">
                        <img src="stadium.jpg" alt="Stadium" class="ticket-select__stadium-image">
                        <div class="ticket-select__stadium-overlay">
                            <svg class="ticket-select__stadium-svg" viewBox="0 0 1000 600">
                                <!-- Define your stadium sectors -->
                                <path class="ticket-select__sector" 
                                      data-sector-id="1" 
                                      data-sector-color="blue"
                                      d="M100,100 L300,100 L300,200 L100,200 Z"/>
                                      
                                <path class="ticket-select__sector" 
                                      data-sector-id="2" 
                                      data-sector-color="red"
                                      d="M100,400 L300,400 L300,500 L100,500 Z"/>
                                      
                                <path class="ticket-select__sector" 
                                      data-sector-id="3" 
                                      data-sector-color="green"
                                      d="M400,100 L600,100 L600,200 L400,200 Z"/>
                                <!-- Add more sectors... -->
                            </svg>
                        </div>
                    </div>
                </div>
            </div>
            <!-- Info bar with seat counter -->
            <div class="ticket-select__info">
                <span class="ticket-select__selected-count">No seats selected</span>
                <a href="#" disabled class="ticket-select__info-btn">Buy <span data-ticket-selector-count style="display: none;"></span></a>
            </div>
        </div>
    </div>
</div>

2. Initialize the Widget

const ticketSelector = new TicketSelector('#ticket-selector', {
    lang: 'en', // 'en', 'az' or auto-detect
    showControls: true,
    showInfo: true,
    maxSeat: Infinity // Maximum number of seats that can be selected (default: Infinity)
});

// Initialize sector summaries for dynamic loading
ticketSelector.addEventListener('ready', (event) => {
    console.log(`TicketSelector v${event.detail.version} is ready!`);
    
    // Load sector summaries to update HTML attributes dynamically
    const sectorSummaries = {
        '1': {
            name: 'North Stand',
            price: '100 USD',
            availability: { available: 45, total: 50 },
            disabled: false
        },
        '2': {
            name: 'South Stand',
            price: '80 USD', 
            availability: { available: 0, total: 30 },
            disabled: true
        }
    };
    
    ticketSelector.loadSectorSummaries(sectorSummaries);
});

// Listen for sector clicks
ticketSelector.addEventListener('sectorClick', async (event) => {
    const { sectorId, sectorName, element } = event.detail;
    
    // Show loading state
    ticketSelector.showLoading('Loading seats...');
    
    try {
        // Load sector data from your API
        const response = await fetch(`/api/sectors/${sectorId}/seats`);
        const sectorData = await response.json();
        
        // Load seats into the widget
        ticketSelector.setSectorData(sectorData, {
            sectorId,
            sectorName,
            sectorColor: element.dataset.sectorColor
        });
    } catch (error) {
        console.error('Failed to load sector:', error);
        alert('Failed to load seat information. Please try again.');
    }
});

// Get selected seats when user is ready to proceed
document.querySelector('.ticket-select__info-btn').addEventListener('click', () => {
    const selectedSeats = ticketSelector.getSelectedSeats();
    console.log('User selected:', selectedSeats);
    
    // Process the selection...
    processTicketSelection(selectedSeats);
});

📚 API Reference

Constructor Options

new TicketSelector(container, options)

| Option | Type | Default | Description | |--------|------|---------|-------------| | lang | string | auto-detect | Language code ('en', 'az', 'tr') | | showControls | boolean | true | Show zoom/pan/fullscreen controls | | showInfo | boolean | true | Show selected seats counter | | maxSeat | number | Infinity | Maximum number of seats that can be selected |

Methods

setSectorData(sectorData, sectorInfo?)

Load seats for a specific sector with detailed configuration.

const sectorData = {
    id: 'north-stand',
    name: 'North Stand',
    price: '100 USD',
    availability: { available: 45, total: 50 },
    disabled: false,
    seats: [
        {
            id: 1,
            name: 'Row 1',
            data: [
                { id: 1001, available: true },
                { id: 1002, available: false },
                { id: 1003, available: true, skipLeft: 2 }, // Gap before seat  
                { id: 1004, available: true, skipRight: 1 }, // Gap after seat
                { id: 1005, available: true, number: 15 } // Manual seat number
            ]
        },
        {
            id: 2,
            name: 'Row 2', 
            data: [
                { id: 2001, available: true },
                { id: 2002, available: true }
            ]
        }
    ]
};

ticketSelector.setSectorData(sectorData, {
    sectorId: '1',
    sectorName: 'North Stand',
    sectorColor: 'blue' // Applies color theme to seats
});

Seat Data Properties:

| Property | Type | Description | |----------|------|-------------| | id | number | Unique seat identifier (required) | | available | boolean | Whether seat is available for selection | | skipLeft | number | Number of empty spaces before this seat | | skipRight | number | Number of empty spaces after this seat | | number | number | Manual seat number (optional - if not provided, auto-numbered) |

getSelectedSeats()

Returns array of selected seats with comprehensive information.

const selectedSeats = ticketSelector.getSelectedSeats();
// Returns:
// [
//   {
//     sector: "North Stand",
//     row: 1,
//     seat: 3,
//     seatId: "seat-1003",
//     price: "50 USD",
//     category: "Standard"
//   }
// ]

setLanguage(lang)

Change language dynamically with instant UI updates.

ticketSelector.setLanguage('az'); // Switch to Azerbaijani
ticketSelector.setLanguage('en'); // Switch to English

showLoading(message?)

Display loading state with optional custom message.

ticketSelector.showLoading('Loading seat data...');

destroy()

Clean up the widget and remove all event listeners.

ticketSelector.destroy();

Events

sectorClick

Triggered when a sector/zone is clicked in the stadium view.

ticketSelector.addEventListener('sectorClick', (event) => {
    const { sectorId, sectorName, element } = event.detail;
    console.log(`User clicked on ${sectorName} (ID: ${sectorId})`);
});

🛠️ Development

Prerequisites

  • Node.js 16+
  • npm, yarn, or pnpm

Setup

git clone https://github.com/IBP-LLC/ticket-selector.git
cd ticket-selector
npm install  # or yarn install / pnpm install

Development Server

npm run dev

This will start:

  • 📦 Rollup in watch mode (JavaScript bundling)
  • 🎨 Sass in watch mode (CSS compilation)
  • 🔄 PostCSS processor (CSS optimization)
  • 🌐 Live server at http://localhost:8080 with hot reload

Build Commands

npm run build        # Production build
npm run clean        # Clean dist folder
npm run lint         # Run ESLint
npm run lint:fix     # Fix linting issues
npm run format       # Format code with Prettier
npm run test         # Run tests (when available)

Package Manager Support

The project works with any modern package manager:

# npm
npm install && npm run dev

# yarn  
yarn install && yarn dev

# pnpm
pnpm install && pnpm dev

📁 Project Structure

src/
├── TicketSelector.js           # Main widget class
├── i18n/                       # Internationalization
│   ├── index.js               # I18n system core
│   └── translations.js        # All language translations
└── styles/                    # SCSS styles
    ├── main.scss              # Main stylesheet
    └── _variables.scss        # SCSS variables & theming

dist/                          # Built files (generated)
├── ticket-selector.js         # UMD bundle
├── ticket-selector.esm.js     # ES module bundle  
├── ticket-selector.min.css    # Minified CSS
└── *.map                      # Source maps

examples/                      # Usage examples
├── index.html                 # Basic implementation example
└── stadium.jpg                # Sample stadium image

docs/                          # Documentation (generated)
tests/                         # Test files (when available)

🌐 Browser Support

| Browser | Version | |---------|---------| | Chrome/Chromium | 60+ | | Firefox | 55+ | | Safari | 12+ | | Edge | 79+ | | iOS Safari | 12+ | | Android WebView | 60+ |

🎨 Customization

CSS Variables

:root {
  --ticket-select-primary: #2175bf;
  --ticket-select-secondary: #f8ad02;
  --ticket-select-success: #0a8837;
  --ticket-select-danger: #bb2932;
  --ticket-select-bg: #f1f1f1;
  --ticket-select-white: #ffffff;
}

Theming

The widget supports custom color schemes through SCSS variables and CSS custom properties. See src/styles/_variables.scss for all available options.

📈 Performance

  • Bundle size: ~56KB minified (includes Panzoom)
  • CSS size: ~8KB minified
  • Zero external dependencies - everything is bundled
  • Tree-shakeable ES modules
  • Optimized rendering with efficient DOM updates
  • Smooth initialization with loading states
  • Mobile optimized with touch event support

🔄 Changelog

v1.0.8 (Latest)

  • 🎯 Maximum Seat Selection: New maxSeat option to limit the number of seats that can be selected
  • ⚠️ Seat Limit Warnings: Informative tooltip notifications when maximum seat limit is reached
  • 🌍 Multi-language Seat Limits: Added translations for seat limit messages in English, Azerbaijani, and Turkish
  • 🔧 Sector Drag Fix: Fixed click event triggering after pan/zoom drag on sector paths
  • 🖱️ Improved Drag Detection: Separate drag handling for sectors and seats to prevent false clicks
  • Better UX for Limits: Visual feedback with cursor changes and informative tooltips
  • 📏 Drag Threshold Optimization: Consistent 5px drag threshold for both sectors and seats

v1.0.7

  • 🔢 Manual Seat Numbering: Added optional number property for custom seat numbering from backend
  • 🔧 Flexible Numbering System: Backend can now override automatic seat numbers
  • 📈 Enhanced Data Structure: Seats can now have custom numbers from backend
  • 📚 Documentation Updates: Added seat data properties table with number parameter
  • 💡 Example Implementation: Updated examples to show manual seat numbering usage
  • 🔄 Backward Compatibility: Automatic numbering still works when number is not provided

v1.0.6

  • 🖼️ Stadium Image Support: Added stadium image support in the widget
  • Enhanced Seat Styling: Visual improvements and seat styling enhancements
  • 🐛 Bug Fixes: Various minor bugs and performance optimizations

v1.0.5

  • 🎯 Dynamic Seat Counter: Purchase button now shows selected seat count (e.g., "Buy (3)")
  • 🔄 Enhanced Button States: Purchase button automatically enables/disables based on seat selection
  • 🚫 Improved Disabled Sectors: Better visual feedback for unavailable sectors
  • 🎨 Button UX Improvements: Disabled by default when no seats selected, dynamic count display
  • Sector Interaction Refinements: Better hover states and cursor feedback
  • 🛠️ CSS & JavaScript Enhancements: Improved styling consistency and responsive behavior

v1.0.4

  • 🔄 Dynamic Sector Loading: Backend/mock data integration for sector information
  • 🚫 Disabled Sector Functionality: Visual feedback and proper state management
  • 📄 Custom HTML Preservation: Info section content maintained during updates
  • 🤖 Automated Version Updates: Husky hooks for version management
  • 🏷️ Enhanced Tooltips: Improved sector tooltip system with price and availability
  • 🌍 Better Internationalization: Enhanced multi-language support

v1.0.3

  • 🌍 Multi-language Support: Added English, Azerbaijani, and Turkish language support
  • 🔧 Dynamic Internationalization: Professional i18n system implementation
  • Professional Build System: Automated workflows and build optimizations
  • 🎨 Code Formatting: Improved style consistency and formatting
  • 🛠️ Error Handling: Better user feedback and error management
  • 📖 Enhanced Documentation: Improved examples and documentation

v1.0.2

  • 📱 Mobile Touch Support: Added touchend events for perfect mobile interaction
  • Instant UI Feedback: Viewport class applied immediately on sector click for responsive UI
  • 🔄 Improved Loading States: CSS-based loading control with instant visual feedback
  • 🚫 Touch/Click Conflict Fix: Prevented event conflicts with preventDefault for smooth mobile experience
  • 🎯 Enhanced Mobile UX: Complete mobile user experience optimization

v1.0.1

  • 📦 Bundled Panzoom: No more external CDN dependencies - panzoom is now included in the bundle
  • 🔄 Initial Loading: Added professional loading screen during widget initialization
  • 🎯 Version Tracking: Added version property to constructor for debugging and tracking
  • 🚀 Ready Event: Widget now emits 'ready' event when fully initialized
  • 🛠️ Improved Error Handling: Better error messages and loading states
  • Self-contained: Widget is now completely standalone with no external dependencies

v1.0.0

  • ✨ Initial release with full functionality
  • 🌍 Multi-language support (EN, AZ)
  • 🖼️ Fullscreen mode with cross-browser compatibility
  • 📱 Responsive design for all screen sizes
  • ⚡ Professional build system with hot reload
  • 🎯 Interactive seat selection with visual feedback
  • 🔧 Event-driven API for easy integration
  • 📖 Comprehensive documentation and examples

🤝 Contributing

We welcome contributions! Please follow these steps:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes and add tests if applicable
  4. Run npm run lint and npm run build to ensure code quality
  5. Commit your changes (git commit -m 'Add amazing feature')
  6. Push to the branch (git push origin feature/amazing-feature)
  7. Open a Pull Request

Development Guidelines

  • Follow the existing code style and use Prettier for formatting
  • Add JSDoc comments for new public methods
  • Ensure backward compatibility when possible
  • Update documentation for any API changes

📄 License

MIT License - see LICENSE file for details.

🆘 Support

🙏 Acknowledgments

  • Panzoom for zoom and pan functionality
  • All contributors who help improve this project