✨ Multiple Instance Support

This demo shows the widget's ability to initialize on multiple elements. Below you'll see four widget instances:

The widget automatically finds and initializes on all matching containers (#demo-local, .demo-local, #demo-compact). Just include the script and add your container divs.

Widget #1: ID Selector #demo-local
Widget #2: Class Selector .demo-local
Widget #3: Class Selector .demo-local
Widget #4: Compact UI #demo-compact

🔧 How to Embed This Widget

1. Add Container HTML

<!-- Option A: Single widget using ID -->
<div id="bushire-nz"></div>

<!-- Option B: Multiple widgets using class -->
<div class="bushire-nz"></div>
<div class="bushire-nz"></div>

<!-- Option C: Mix both (ID and class) -->
<div id="bushire-nz"></div>
<div class="bushire-nz"></div>

Place container div(s) where you want the widget to appear. Use an ID selector for a single widget or a class selector for multiple widgets. The widget will initialize on all matching elements based on your widgetId config.

2. Include Widget Script (Choose ONE of 2a, 2b, or 2c)

2a. HTML Script Tag (Simplest)

<script type="module"
        src="https://your-widget-domain.com/demo.js"></script>

Add this script tag to load the widget. The config is embedded in the JS file.

2b. Dynamic JavaScript Loading

Load the widget dynamically (e.g., after user interaction or conditionally):

// Create container
const container = document.createElement('div');
container.id = 'bushire-nz';
document.body.appendChild(container);

// Load widget script dynamically
const script = document.createElement('script');
script.type = 'module';
script.src = 'https://your-widget-domain.com/bushire-nz.js';
document.head.appendChild(script);

The widget auto-initializes when the script loads. No callback needed.

2c. React/Modern Frameworks

For React, Vue, or other modern frameworks, load the widget in useEffect:

// React example
import { useEffect } from 'react';

function BookingWidget() {
  useEffect(() => {
    import('https://your-widget-domain.com/bushire-nz.js');
  }, []);

  return <div id="bushire-nz" />;
}

The widget auto-initializes when loaded and finds the container by ID.

3. Create Custom Entry Points (For Developers)

To create a new widget bundle for a different site or a different configuration, create a new .ts file in the src/ directory. Vite will automatically build it into a separate JS bundle.

// src/your-site.ts  <-- Create this file in the src/ folder
import createWidget from './main';

createWidget({
  widgetId: "your-site", // Used to find #your-site or .your-site
  theme: {
    primary: "#your-color",
    accent: "#your-accent"
  },
  api: {
    proxyBase: "https://your-api.com/api",
    transportersBase: "https://bookings.your-site.com"
  },
  maps: {
    apiKey: "YOUR_GOOGLE_MAPS_API_KEY",
    defaultRegion: "AU"
  }
});

Then run npm run build to generate dist/your-site.js. Include this built file in your HTML:

<div id="your-site"></div>
<script type="module" src="https://cdn.your-site.com/your-site.js"></script>

4. Listen for Custom Events

The widget dispatches custom events that you can listen to for tracking, analytics, or custom integrations.

form_submission_new

Fired when a booking form is successfully submitted. Use this to track conversions, send data to analytics, or trigger custom workflows.

window.addEventListener('form_submission_new', (event) => {
  const { formData, timestamp } = event.detail;

  // Example: Send to analytics
  console.log('Booking submitted:', formData.orderId);

  // Access the full payload
  console.log('Order ID:', formData.orderId);
  console.log('Contact:', formData.contactName, formData.contactEmail);
  console.log('Submitted at:', timestamp);
});

Event Payload Structure:

{
  detail: {
    formData: {
      orderId: number,           // Unique order reference
      vehicleType: string,       // e.g., "mini-bus", "coach"
      journeyType: string,       // e.g., "one-way", "return", "charter"
      passengers: number,        // Number of passengers
      suitcaseLuggage: number,   // Number of large luggage items
      handLuggage: number,       // Number of hand luggage items
      pickupLocation: {
        address: string,         // Full address text
        lat: number,             // Latitude coordinate
        lng: number              // Longitude coordinate
      },
      destination: {
        address: string,         // Full address text
        lat: number,             // Latitude coordinate
        lng: number              // Longitude coordinate
      },
      pickupDate: string,        // Format: "DD/MM/YYYY"
      pickupTime: string,        // Format: "HH:MM"
      returnDate: string | null, // For return trips
      returnTime: string | null, // For return trips
      charterDuration: string | null, // For charter bookings
      contactName: string,       // Full name (first + last)
      contactEmail: string,      // Email address
      phoneNumber: string,       // Phone (spaces removed)
      contactPreferences: string[], // e.g., ["email", "phone"]
      bookingDetails: string     // Additional notes/details
    },
    timestamp: string            // ISO 8601 format
  }
}