UNPKG

seat-picker

Version:

> πŸ“š [Full Documentation & Live Demo](https://seat-picker-docs.vercel.app/)

386 lines (313 loc) β€’ 14.8 kB
# [Seat Picker](https://seat-picker-docs.vercel.app/) > πŸ“š [Full Documentation & Live Demo](https://seat-picker-docs.vercel.app/) A flexible and customizable seating arrangement GUI component for React applications. This library provides an interactive canvas for creating and managing seat layouts, perfect for event venues, theaters, restaurants, and more. --- ## ✨ Features ### Canvas Editing & Layout - **Interactive Canvas:** Drag, drop, and arrange seats, shapes, and text. - **Multi-Select & Grouping:** Select multiple objects to move, align, or edit as a group. - **Grid Arrangement:** Instantly arrange selected seats into a grid with adjustable rows, columns, and spacing. - **Customizable Properties:** Edit seat number, color, size, shape, and more from the sidebar. - **Shape & Text Tools:** Add rectangles, circles, and text labels to your layout. - **Undo/Redo:** Easily revert or reapply changes with keyboard shortcuts or toolbar buttons. - **Delete, Copy, Cut, Paste:** Full clipboard support for objects and groups. - **Lock/Unlock Selection:** Prevent accidental changes by locking selected objects. - **Zoom & Pan:** Zoom in/out (80%–120%) and pan to focus on any part of your layout. - **Snap to Grid:** Enable smart snapping for precise alignment. - **Background Image:** Upload a background image (e.g., venue map) and adjust its opacity. ### Seat & Zone Management - **Seat Attributes:** Assign seat numbers, categories, prices, and status (available, sold, etc.). - **Zone Management:** Group seats into zones for pricing or sectioning. - **Bulk Editing:** Edit properties for multiple selected seats at once. ### Export, Import, and Sharing - **Export Layout:** Save your seat map as a JSON file for backup or sharing. - **Import Layout:** Load a previously saved layout to continue editing. - **Download:** Download the current layout instantly from the toolbar. ### Customer-Facing Features - **Read-Only Viewer:** Customers can view seat layouts without editing. - **Drag & Drop Upload:** Customers can upload a seat layout JSON to view and interact. - **Seat Details Modal:** Clicking a seat opens a modal with all details and purchase options. - **Purchase Integration:** Hook into seat actions (buy, reserve, etc.) with your own logic. - **No Edit Mode:** Customers cannot move, edit, or delete seats. ### Developer Experience - **TypeScript Support:** Full typings for all components and props. - **Customizable Styling:** Easily override styles with your own CSS or Tailwind classes. - **Composable Components:** Use only what you need (e.g., just the renderer for read-only views). --- ## πŸš€ Getting Started ### Installation ```bash npm install seat-picker # or yarn add seat-picker ``` --- ## πŸ› οΈ Usage (Admin/Editor) ```tsx import { SeatPicker } from 'seat-picker'; function App() { const handleChange = (layout) => { console.log('Layout updated:', layout); }; const handleSave = (layout) => { console.log('Saving layout:', layout); // Save to your backend or file system }; return ( <SeatPicker onChange={handleChange} onSave={handleSave} style={{ width: 800, height: 600, backgroundColor: '#f8fafc', showSeatNumbers: true, seatNumberStyle: { fontSize: 14, fill: '#222', fontWeight: 'bold', }, seatStyle: { fill: 'transparent', stroke: 'black', strokeWidth: 1, radius: 10, }, }} labels={{ buyButton: 'Buy Seat', cancelButton: 'Cancel', seatNumber: 'Seat Number', category: 'Category', price: 'Price', status: 'Status', }} /> ); } ``` ### Toolbar Actions - **Open/Save/Download:** Import/export layouts as JSON. - **Select/Move:** Use the pointer tool to select and move objects. - **Add Seat/Shape/Text:** Quickly add new elements to your layout. - **Grid Tool:** Arrange selected seats in a grid. - **Undo/Redo:** Step backward or forward through your changes. - **Clipboard:** Cut, copy, paste, and delete selected objects. - **Zoom:** Zoom in/out (80%–120%) and keep the layout centered. - **Lock/Unlock:** Lock selection to prevent changes. ### Sidebar Actions - **No Selection:** See helpful tips and keyboard shortcuts. - **Single Selection:** Edit all properties of the selected object. - **Multiple Selection:** Edit properties in bulk and use the grid arrangement tool. ### Keyboard Shortcuts - **Ctrl+Z:** Undo - **Ctrl+Y:** Redo - **Del:** Delete selected - **Shift+Click:** Multi-select - **Ctrl+K:** Open command palette --- ## πŸ‘₯ Customer-Facing Seat Viewer A dedicated, safe page for customers to view and purchase seats. This page is read-only and does not allow editing. ### How to Use 1. **Start the development server:** ```bash npm run dev # or yarn dev ``` 2. **Visit the customer page:** - Go to [http://localhost:5173/seats](http://localhost:5173/seats) 3. **Upload a seat layout:** - Drag and drop your exported seat JSON file onto the upload area, or click to browse and select the file. - Only JSON files exported from the admin/editor are supported. 4. **View and purchase seats:** - The seat layout will be displayed on a canvas. - Click any seat to view its details in a modal. - Use the **Buy** or **Cancel** buttons in the modal (customize the buy logic as needed). - Seats and other objects are not editable or selectable by customers. ### Customer Features - **Drag & Drop Upload:** Easily upload seat layouts by dragging your JSON file onto the upload area. - **Modal Details:** Clicking a seat opens a modal with seat number, category, price, status, and purchase options. - **Read-Only:** Customers cannot move, edit, or select seatsβ€”only view and purchase. ### πŸ–ΌοΈ Rendering a Saved Layout (Read-Only) You can render a saved seat layout in read-only mode using the provided `SeatPicker` component with the `readOnly` prop set to `true`. This is ideal for customer-facing pages or embeddable widgets where you want to display a seat map and allow seat selection/purchase, but prevent editing or uploading. ### Example ```tsx import { SeatPicker } from 'seat-picker'; function CustomerView() { const [layout, setLayout] = useState(null); const handleSeatAction = (action, seat) => { console.log('Action:', action, 'on seat:', seat); // Implement your buy functionality here }; return ( <div className="min-h-screen bg-gray-100 p-8"> <h1 className="mb-4 text-2xl font-bold">Customer Seat Viewer</h1> {/* Upload area for layout JSON */} <div className="mb-6"> <div className="rounded-lg border-2 border-dashed border-gray-300 p-6"> {/* Your file upload UI here */} </div> </div> {layout ? ( <SeatPicker layout={layout} readOnly style={{ width: 800, height: 600, backgroundColor: '#f8fafc', showSeatNumbers: true, seatNumberStyle: { fontSize: 14, fill: '#222', fontWeight: 'bold', }, seatStyle: { fill: 'transparent', stroke: 'black', strokeWidth: 1, radius: 10, }, }} labels={{ buyButton: 'Buy Seat', cancelButton: 'Cancel', seatNumber: 'Seat Number', category: 'Category', price: 'Price', status: 'Status', }} onSeatAction={handleSeatAction} /> ) : ( <div className="rounded-lg border bg-white p-4 shadow"> <div className="flex h-[600px] items-center justify-center text-gray-500"> Please upload a seat layout file </div> </div> )} </div> ); } ``` --- ## βš™οΈ Props Reference & Customization ### SeatPicker | Prop | Type | Default | Description | | ------------------- | -------------------------------------------- | ------- | ---------------------------------------------------------------- | | `width` | `number` | 800 | Canvas width in pixels | | `height` | `number` | 600 | Canvas height in pixels | | `layout` | `object` | β€” | (Optional) Layout JSON to load (for editing an existing layout) | | `initialSeats` | `Seat[]` | `[]` | (Deprecated, use `layout`) Initial seats to render | | `initialZones` | `Zone[]` | `[]` | (Deprecated, use `layout`) Initial zones for grouping seats | | `onChange` | `(layout: object) => void` | β€” | Callback when the layout changes (add, move, edit, delete, etc.) | | `onSave` | `(layout: object) => void` | β€” | Callback when the user clicks the Save button | | `onZoneChange` | `(zones: Zone[]) => void` | β€” | Callback when zones change | | `className` | `string` | β€” | Additional CSS class name for the root container | | `style` | `object` | β€” | Additional inline styles or style overrides (see below) | | `labels` | `object` | β€” | Override default button/label text (see below) | | `readOnly` | `boolean` | `false` | If true, disables all editing and only allows viewing | | `renderToolbar` | `(props) => ReactNode` | β€” | Custom render function for the toolbar | | `renderSidebar` | `() => ReactNode` | β€” | Custom render function for the sidebar | | `renderSeatDetails` | `({ seat, onClose, onAction }) => ReactNode` | β€” | Custom render function for the seat details modal | | `onSeatClick` | `(seat: SeatData) => void` | β€” | Callback when a seat is clicked (read-only mode) | | `onSeatAction` | `(action: string, seat: SeatData) => void` | β€” | Callback for seat actions (e.g., buy, reserve) | #### Example: Customizing Style and Labels ```tsx <SeatPicker width={1000} height={700} style={{ backgroundColor: '#fffbe6', seatNumberStyle: { fontSize: 16, fill: '#333' }, seatStyle: { fill: '#e0e7ff', stroke: '#6366f1', radius: 12 }, }} labels={{ buyButton: 'Purchase', cancelButton: 'Back', seatNumber: 'No.', category: 'Section', price: 'Cost', status: 'Availability', }} /> ``` #### Example: Custom Toolbar ```tsx <SeatPicker renderToolbar={({ onSave, onBgLayout }) => ( <div> <button onClick={onSave}>Custom Save</button> <button onClick={onBgLayout}>Background</button> {/* ...add more custom controls */} </div> )} /> ``` #### Example: Custom Sidebar ```tsx <SeatPicker renderSidebar={() => ( <div> <h3>Custom Sidebar</h3> {/* Add your own controls or info */} </div> )} /> ``` #### Example: Custom Seat Details Modal ```tsx <SeatPicker renderSeatDetails={({ seat, onClose, onAction }) => ( <div> <h2>Seat {seat.number}</h2> <p>Price: {seat.price}</p> <button onClick={() => onAction('buy', seat)}>Buy</button> <button onClick={onClose}>Close</button> </div> )} /> ``` --- ### SeatLayoutRenderer | Prop | Type | Default | Description | | ------------------- | -------------------------------------------- | ------- | --------------------------------------------- | | `layout` | object | β€” | The seat layout JSON exported from the editor | | `width` | number | 800 | Canvas width in pixels | | `height` | number | 600 | Canvas height in pixels | | `labels` | object | β€” | Override default button/label text | | `onSeatClick` | `(seat: SeatData) => void` | β€” | Callback when a seat is clicked (read-only) | | `onSeatAction` | `(action: string, seat: SeatData) => void` | β€” | Callback for seat actions (e.g., buy) | | `renderSeatDetails` | `({ seat, onClose, onAction }) => ReactNode` | β€” | Custom seat modal | #### Example: Read-Only Renderer with Custom Modal ```tsx <SeatLayoutRenderer layout={seatLayoutJson} width={900} height={700} labels={{ buyButton: 'Book Now' }} renderSeatDetails={({ seat, onClose, onAction }) => ( <div> <h2>VIP Seat {seat.number}</h2> <button onClick={() => onAction('buy', seat)}>Book</button> <button onClick={onClose}>Close</button> </div> )} /> ``` --- ### Customization Tips - **Styling:** Use the `style` prop to override canvas, seat, and label styles. You can use Tailwind, CSS-in-JS, or plain CSS. - **Labels:** Pass a `labels` object to override any button or field text for localization or branding. - **Component Composition:** Use the `renderToolbar`, `renderSidebar`, and `renderSeatDetails` props to inject your own React components for a fully custom UI. - **Callbacks:** Use `onChange`, `onSave`, `onSeatClick`, and `onSeatAction` to hook into all user actions and integrate with your backend or analytics. --- ## πŸ§‘β€πŸ’» Contributing Contributions are welcome! Please feel free to submit a Pull Request. ## πŸ“„ License MIT Β© Emmanuel Michael