@seatlayer/js 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/SeatingChart.ts","../src/api.ts","../src/EmbeddedDesigner.ts"],"sourcesContent":["/**\n * SeatingChart — the embeddable buyer picker.\n *\n * A thin wrapper over the shared PickerController (src/picker/PickerController):\n * it owns the mount <div> + the public embed contract (hold-only — the SDK hands\n * the holdId to the host page for a server-side book) and delegates all transport\n * + booking to the controller, so the SDK inherits every fix made for the live\n * buyer page and the demo picker.\n */\nimport { PickerController, loadLocale, setStringOverrides, t, type PickerSeat, type SeatHoverDetails } from '@seatlayer/core';\nimport { PubApi, type BestAvailableResult, type HoldResult } from './api';\n\nconst DEFAULT_API_BASE = 'https://api.seatlayer.io';\nconst DEFAULT_MAX_SELECTION = 10;\n\n/** A seat as surfaced to the host page (prices resolved from the chart's categories). */\nexport type SelectedSeat = PickerSeat;\nexport interface GAAreaAvailability {\n id: string; label: string; capacity: number; available: number; categoryKey: string; price: number; currency: string;\n tiers?: Array<{ id: string; name: string; price: number }>;\n}\n\nexport interface SeatingChartOptions {\n /** CSS selector or an HTMLElement to render into. */\n container: string | HTMLElement;\n /** Event key, e.g. `ev_xxx`. */\n event: string;\n /** API origin. Defaults to https://api.seatlayer.io. */\n apiBase?: string;\n /** Reserved for future authenticated rendering — accepted + stored, not yet sent. */\n publicKey?: string;\n /** Max seats selectable at once (default 10). */\n maxSelection?: number;\n /**\n * BCP 47 language for the widget UI — `'de'`, `'es-MX'`, etc. Falls back to\n * the browser language, then English. Built-in: en, es, de, fr. The German\n * bundle (etc.) is fetched on demand so unused languages cost nothing.\n */\n locale?: string;\n /**\n * Per-key string overrides layered over the active locale — white-label copy\n * without shipping a whole bundle, e.g. `{ 'map.fromPrice': 'ab {price}' }`.\n */\n messages?: Record<string, string>;\n /** ISO 4217 currency for on-map prices (default USD). */\n currency?: string;\n /**\n * Colorblind-safe rendering: category hues switch to an Okabe-Ito palette\n * and booked seats render hollow, so state never relies on hue alone.\n * Toggleable later with setColorblindSafe().\n */\n colorblindSafe?: boolean;\n /**\n * Built-in seat tooltip on mouse hover (seat · category · price · status).\n * Rendered inside the widget so every host gets it; default true. Turn off\n * to draw your own popover from onSeatHover.\n */\n seatTooltip?: boolean;\n /**\n * Seat hover with everything a popover needs (category label/color, resolved\n * tier-aware price, live status, currency); null on hover-out. Fires whether\n * or not the built-in tooltip is enabled.\n */\n onSeatHover?: (details: SeatHoverDetails | null) => void;\n onSelectionChange?: (seats: SelectedSeat[]) => void;\n onHold?: (result: HoldResult) => void;\n onHoldExpired?: () => void;\n onGAClick?: (area: GAAreaAvailability) => void;\n onError?: (err: unknown) => void;\n /**\n * Multi-floor charts only: fires when the buyer taps a deck in the stacked\n * 3D view, after the picker switches to that floor — lets the host page sync\n * its own floor UI (tabs, labels) with the map.\n */\n onDeckTap?: (floorId: string) => void;\n /**\n * Non-blocking, localized selection advice — currently the orphan-seat hint\n * (the selection would strand a single free seat between taken neighbors).\n * `null` clears it. Purely informational; nothing is ever prevented.\n */\n onHint?: (message: string | null) => void;\n}\n\nfunction resolveContainer(container: string | HTMLElement): HTMLElement {\n if (typeof container === 'string') {\n const el = document.querySelector(container);\n if (!el) throw new Error(`seatmap: container \"${container}\" not found`);\n return el as HTMLElement;\n }\n if (!(container instanceof HTMLElement)) {\n throw new Error('seatmap: container must be a CSS selector or an HTMLElement');\n }\n return container;\n}\n\nexport class SeatingChart {\n private readonly opts: SeatingChartOptions;\n private readonly controller: PickerController;\n /** Reserved for future authenticated rendering — stored, not yet sent on any request. */\n readonly publicKey?: string;\n\n private mount: HTMLElement | null = null;\n private hostEl: HTMLDivElement | null = null;\n private rendered = false;\n private tipEl: HTMLDivElement | null = null;\n private tipPos = { x: 0, y: 0 };\n private onTipMove: ((e: MouseEvent) => void) | null = null;\n\n constructor(options: SeatingChartOptions) {\n if (!options || typeof options !== 'object') throw new Error('seatmap: options object is required');\n if (!options.container) throw new Error('seatmap: `container` is required');\n if (!options.event || typeof options.event !== 'string') throw new Error('seatmap: `event` key is required');\n\n this.opts = options;\n this.publicKey = options.publicKey;\n const api = new PubApi((options.apiBase ?? DEFAULT_API_BASE).replace(/\\/+$/, ''));\n this.controller = new PickerController({\n transport: api,\n eventKey: options.event,\n maxSelection: options.maxSelection ?? DEFAULT_MAX_SELECTION,\n currency: options.currency,\n onSelectionChange: (seats) => this.opts.onSelectionChange?.(seats),\n onHold: (h) => this.opts.onHold?.({ holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items }),\n onHoldExpired: () => this.opts.onHoldExpired?.(),\n onGAClick: (areaId) => {\n const area = this.controller.getGAAreas().find((candidate) => candidate.id === areaId);\n if (area) this.opts.onGAClick?.(area);\n },\n onError: (err) => this.opts.onError?.(err),\n onDeckTap: (floorId) => this.opts.onDeckTap?.(floorId),\n onHint: (message) => this.opts.onHint?.(message),\n // Live-activity cue: pulse seats that other buyers take while the map is\n // open — the WS feed already streams the status change, this makes it felt.\n flashOnLiveChange: true,\n onSeatHover: (details) => {\n this.opts.onSeatHover?.(details);\n if (this.opts.seatTooltip !== false) this.updateTooltip(details);\n },\n colorblindSafe: options.colorblindSafe,\n });\n }\n\n /** Fetch the chart, mount the renderer, seed statuses and go live. Idempotent. */\n async render(): Promise<this> {\n if (this.rendered) return this;\n this.rendered = true;\n\n // Resolve + load the UI language before the first paint so on-map labels\n // (\"N LEFT\", \"FROM …\", the map aria-label) render translated. English and\n // already-loaded locales resolve synchronously; others fetch one small chunk.\n await loadLocale(this.opts.locale);\n if (this.opts.messages) setStringOverrides(this.opts.messages);\n\n // Mount an owned <div> inside the caller's container so we never fight their\n // layout and can cleanly remove it on destroy().\n this.mount = resolveContainer(this.opts.container);\n const host = document.createElement('div');\n host.style.width = '100%';\n host.style.height = '100%';\n host.style.position = 'relative';\n this.mount.appendChild(host);\n this.hostEl = host;\n\n const info = await this.controller.render(host);\n if (!info) {\n this.rendered = false;\n return this;\n }\n\n // Tooltip element + cursor tracking (mouse only — touch selects directly and\n // reviews seats in the host tray). Positioned at the cursor, flipped at edges.\n // Appended AFTER controller.render — mounting the canvas replaces the host's\n // prior children, so anything added earlier would be wiped.\n if (this.opts.seatTooltip !== false) {\n const tip = document.createElement('div');\n tip.setAttribute('role', 'tooltip');\n tip.style.cssText =\n 'position:absolute;z-index:7;pointer-events:none;display:none;max-width:240px;' +\n 'background:#10162a;color:#fff;border-radius:10px;padding:9px 12px;' +\n 'font:500 12px/1.45 -apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif;' +\n 'box-shadow:0 10px 30px -10px rgba(0,0,0,.5);';\n host.appendChild(tip);\n this.tipEl = tip;\n this.onTipMove = (e: MouseEvent) => {\n const r = host.getBoundingClientRect();\n this.tipPos = { x: e.clientX - r.left, y: e.clientY - r.top };\n if (this.tipEl && this.tipEl.style.display !== 'none') this.placeTooltip();\n };\n host.addEventListener('mousemove', this.onTipMove);\n }\n if (info.mode === 'test') {\n host.style.overflow = 'hidden';\n const ribbon = document.createElement('div');\n ribbon.textContent = t('picker.testMode');\n ribbon.setAttribute('aria-label', t('picker.testMode'));\n ribbon.style.cssText =\n 'position:absolute;top:18px;right:-34px;z-index:6;transform:rotate(45deg);' +\n 'width:140px;text-align:center;padding:4px 0;background:#f4b740;color:#1a1200;' +\n 'font:800 10.5px/1.4 -apple-system,BlinkMacSystemFont,sans-serif;letter-spacing:.12em;' +\n 'box-shadow:0 2px 8px rgba(0,0,0,.25);pointer-events:none;';\n host.appendChild(ribbon);\n }\n return this;\n }\n\n private placeTooltip(): void {\n if (!this.tipEl || !this.hostEl) return;\n const hw = this.hostEl.clientWidth;\n const tw = this.tipEl.offsetWidth;\n const th = this.tipEl.offsetHeight;\n let x = this.tipPos.x + 14;\n let y = this.tipPos.y - th - 12;\n if (x + tw > hw - 8) x = this.tipPos.x - tw - 14;\n if (y < 8) y = this.tipPos.y + 18;\n this.tipEl.style.left = `${Math.max(8, x)}px`;\n this.tipEl.style.top = `${Math.max(8, y)}px`;\n }\n\n private updateTooltip(details: SeatHoverDetails | null): void {\n if (!this.tipEl) return;\n if (!details) {\n this.tipEl.style.display = 'none';\n return;\n }\n const money = (() => {\n try {\n return new Intl.NumberFormat(undefined, { style: 'currency', currency: details.currency }).format(details.price);\n } catch {\n return `${details.price} ${details.currency}`;\n }\n })();\n const statusLine =\n details.status === 'free'\n ? ''\n : `<div style=\"margin-top:5px;font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:#fca5a5;font-weight:700\">${\n details.status === 'held' ? t('map.statusHeld') : t('map.statusTaken')\n }</div>`;\n this.tipEl.innerHTML =\n `<div style=\"font-weight:700;font-size:13px\">${details.label}</div>` +\n `<div style=\"display:flex;align-items:center;gap:6px;margin-top:4px;color:#c7cddc\">` +\n `<span style=\"width:9px;height:9px;border-radius:50%;flex:none;background:${details.categoryColor}\"></span>` +\n `<span>${details.categoryLabel}</span>` +\n `<span style=\"margin-left:auto;font-weight:700;color:#fff\">${money}</span></div>` +\n statusLine;\n this.tipEl.style.display = 'block';\n this.placeTooltip();\n }\n\n /** Current selection with prices resolved from the chart categories. */\n getSelection(): SelectedSeat[] {\n return this.controller.getSelection();\n }\n\n /** Hold the current selection. Resolves the hold, or null on a 409 conflict. */\n async hold(options: { ttlMs?: number } = {}): Promise<HoldResult | null> {\n try {\n const h = await this.controller.hold(undefined, options.ttlMs);\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n getGAAreas(): GAAreaAvailability[] {\n return this.controller.getGAAreas();\n }\n\n async holdGA(\n areaId: string,\n qty: number,\n options: { tierId?: string | null; ttlMs?: number } = {},\n ): Promise<HoldResult | null> {\n try {\n const h = await this.controller.holdGA(areaId, qty, options);\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n /** Ask the server for the `qty` best free seats and hold them atomically. */\n async bestAvailable(qty: number, categoryKey?: string): Promise<BestAvailableResult | null> {\n try {\n const h = await this.controller.bestAvailable(qty, categoryKey);\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt, labels: h.labels, seats: h.seats, items: h.items } : null;\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n /**\n * Choose a ticket tier for a selected seat (e.g. Adult → Child). The seat's\n * available `tiers` are on each `SelectedSeat` from `getSelection()` /\n * `onSelectionChange`. Re-emits the selection with the new tier + price, and\n * the tier rides along in the next `hold()` / `onHold` per seat. `tierId=null`\n * reverts to the default tier.\n */\n setSeatTier(seatId: string, tierId: string | null): void {\n this.controller.setSeatTier(seatId, tierId);\n }\n\n /**\n * Floors of a multi-floor chart — `[{ id, name }]` (single-floor charts\n * return one entry; empty before render()). Pair with setFloor() to build a\n * host-side floor switcher.\n */\n getFloors(): { id: string; name: string }[] {\n return this.controller.getFloors();\n }\n\n /** Switch the shown floor (2D). Warns + no-ops on single-floor charts. */\n setFloor(floorId: string): void {\n if (this.controller.getFloors().length <= 1) {\n console.warn('seatmap: setFloor() ignored — this chart has a single floor');\n return;\n }\n this.controller.setFloor(floorId);\n }\n\n /** Toggle colorblind-safe rendering at runtime (see options.colorblindSafe). */\n setColorblindSafe(on: boolean): void {\n this.controller.setColorblindSafe(on);\n }\n\n /** Zoom in one step (same increment as the wheel/pinch gesture). */\n zoomIn(): void {\n this.controller.zoomIn();\n }\n\n /** Zoom out one step. */\n zoomOut(): void {\n this.controller.zoomOut();\n }\n\n /** Reset the camera so the whole chart fits the container. */\n zoomToFit(): void {\n this.controller.zoomToFit();\n }\n\n /** Release the current hold (if any). No-op when nothing is held. */\n async release(): Promise<void> {\n await this.controller.release();\n }\n\n /** Tear everything down: close the socket, stop timers, drop the canvas. */\n destroy(): void {\n if (this.hostEl && this.onTipMove) this.hostEl.removeEventListener('mousemove', this.onTipMove);\n this.tipEl = null;\n this.onTipMove = null;\n this.controller.destroy();\n if (this.hostEl && this.hostEl.parentNode) this.hostEl.parentNode.removeChild(this.hostEl);\n this.hostEl = null;\n this.mount = null;\n this.rendered = false;\n }\n}\n","/**\n * Minimal client for the public embed surface of workers/api (the `/pub/*`\n * routes). Deliberately self-contained — it does NOT reuse src/lib/api.ts,\n * which bakes in a build-time API base and dashboard session credentials. The\n * SDK runs cross-origin on a third-party ticketing page, so:\n * - apiBase is per-instance (constructor option), not a build constant;\n * - credentials are omitted (no cookie to send, avoids CORS-credential setup);\n * - no custom headers on mutating calls (keeps the CORS preflight trivial).\n */\nimport type { ChartDoc, PickerSeat as SelectedSeat } from '@seatlayer/core';\n\nexport interface HoldConflict {\n label: string;\n status: string;\n}\n\nexport interface HoldLineItem {\n label: string; objectId: string; objectType: 'seat' | 'booth' | 'ga'; categoryKey: string;\n tierId: string | null;\n /** Price in major currency units (for example 45 means $45.00). */\n unitPrice: number;\n currency: string;\n quantity?: number;\n}\n\nexport class ApiError extends Error {\n status: number;\n code?: string;\n /** Present when a hold 409s because seats were just taken/held. */\n conflicts?: HoldConflict[];\n /** Present when best-available 409s ('not_enough_together' | 'sold_out'). */\n reason?: string;\n\n constructor(status: number, message: string, code?: string, conflicts?: HoldConflict[], reason?: string) {\n super(message);\n this.name = 'ApiError';\n this.status = status;\n this.code = code;\n this.conflicts = conflicts;\n this.reason = reason;\n }\n}\n\nexport interface PubChartResult {\n event: { key: string; name: string };\n doc: ChartDoc;\n}\n\nexport interface PubObjectsResult {\n /** Every non-free seat's status, keyed by seat label. */\n seats: Record<string, string>;\n updatedAt: number;\n}\n\nexport interface HoldResult {\n holdId: string;\n expiresAt: number;\n /** The held seats with the buyer's chosen ticket tier per seat (present on hold). */\n seats?: SelectedSeat[];\n items?: HoldLineItem[];\n}\n\n/** Best-available response — the server-picked seats plus the hold they landed in. */\nexport interface BestAvailableResult {\n holdId: string;\n expiresAt: number;\n labels: string[];\n seats?: SelectedSeat[];\n items?: HoldResult['items'];\n}\n\nasync function request<T>(\n base: string,\n path: string,\n init: { method?: 'GET' | 'POST'; body?: unknown } = {},\n): Promise<T> {\n const method = init.method ?? 'GET';\n const headers: Record<string, string> = {};\n let body: string | undefined;\n if (init.body !== undefined) {\n headers['Content-Type'] = 'application/json';\n body = JSON.stringify(init.body);\n }\n\n const res = await fetch(`${base}${path}`, { method, headers, body, credentials: 'omit' });\n\n const isJson = (res.headers.get('content-type') ?? '').includes('application/json');\n const data = isJson ? await res.json().catch(() => null) : null;\n\n if (!res.ok) {\n const err = data as\n | { error?: string; code?: string; conflicts?: HoldConflict[]; reason?: string }\n | null;\n throw new ApiError(res.status, err?.error ?? `request_failed_${res.status}`, err?.code, err?.conflicts, err?.reason);\n }\n return data as T;\n}\n\n/** Public-surface client bound to one apiBase (e.g. https://api.seatlayer.io). */\nexport class PubApi {\n constructor(private readonly base: string) {}\n\n chart(key: string): Promise<PubChartResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/chart`);\n }\n\n objects(key: string): Promise<PubObjectsResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/objects`);\n }\n\n hold(key: string, selections: Array<{ label: string; tierId?: string | null }>, ttlMs?: number, replaceHoldId?: string): Promise<HoldResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/hold`, {\n method: 'POST',\n body: { selections, ...(ttlMs ? { ttlMs } : {}), ...(replaceHoldId ? { replaceHoldId } : {}) },\n });\n }\n\n bestAvailable(key: string, qty: number, categoryKey?: string): Promise<BestAvailableResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/best-available`, {\n method: 'POST',\n body: { qty, ...(categoryKey ? { categoryKey } : {}) },\n });\n }\n\n release(key: string, labels: string[], holdId: string): Promise<{ ok: true }> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/release`, {\n method: 'POST',\n body: { labels, holdId },\n });\n }\n\n socketUrl(key: string): string {\n const wsBase = this.base.replace(/^http/, 'ws');\n return `${wsBase}/pub/events/${encodeURIComponent(key)}/subscribe`;\n }\n}\n","/**\n * A secure, framework-neutral host for the SeatLayer chart Designer.\n *\n * The Designer remains an iframe so a platform never gives its SeatLayer secret\n * key to a browser. This class owns the iframe lifecycle and accepts messages\n * only from that iframe's exact origin.\n */\nexport type EmbeddedDesignerEventType =\n | 'seatlayer.designer.ready'\n | 'seatlayer.designer.saved'\n | 'seatlayer.designer.published'\n | 'seatlayer.designer.close'\n | 'seatlayer.designer.error';\n\nexport interface EmbeddedDesignerMessage {\n type: EmbeddedDesignerEventType;\n chartId?: string;\n workspaceId?: string;\n expiresAt?: number;\n code?: string;\n message?: string;\n meta?: unknown;\n}\n\nexport interface EmbeddedDesignerOptions {\n /** The short-lived URL returned by your backend's Designer-session call. */\n designerUrl: string;\n /** CSS selector or element where the iframe is mounted. */\n container: string | HTMLElement;\n /** Verify the message belongs to the chart your backend opened. */\n expectedChartId?: string;\n /** Verify the message belongs to the workspace your backend opened. */\n expectedWorkspaceId?: string;\n title?: string;\n className?: string;\n style?: Partial<CSSStyleDeclaration>;\n allow?: string;\n referrerPolicy?: ReferrerPolicy;\n onReady?: (message: EmbeddedDesignerMessage) => void;\n onSaved?: (message: EmbeddedDesignerMessage) => void;\n onPublished?: (message: EmbeddedDesignerMessage) => void;\n onClose?: (message: EmbeddedDesignerMessage) => void;\n onError?: (message: EmbeddedDesignerMessage) => void;\n}\n\nconst TYPES = new Set<EmbeddedDesignerEventType>([\n 'seatlayer.designer.ready',\n 'seatlayer.designer.saved',\n 'seatlayer.designer.published',\n 'seatlayer.designer.close',\n 'seatlayer.designer.error',\n]);\n\nfunction resolveContainer(container: string | HTMLElement): HTMLElement {\n if (typeof container !== 'string') return container;\n const element = document.querySelector<HTMLElement>(container);\n if (!element) throw new Error(`EmbeddedDesigner container not found: ${container}`);\n return element;\n}\n\n/** Mount, replace, and destroy a scoped Designer iframe safely. */\nexport class EmbeddedDesigner {\n private options: EmbeddedDesignerOptions;\n private frame: HTMLIFrameElement | null = null;\n private designerOrigin = '';\n\n constructor(options: EmbeddedDesignerOptions) {\n this.options = options;\n }\n\n mount(): HTMLIFrameElement {\n this.destroy();\n const url = new URL(this.options.designerUrl, window.location.href);\n if (url.protocol !== 'https:' && url.hostname !== 'localhost' && url.hostname !== '127.0.0.1') {\n throw new Error('EmbeddedDesigner requires an HTTPS designerUrl outside local development.');\n }\n this.designerOrigin = url.origin;\n\n const frame = document.createElement('iframe');\n frame.title = this.options.title ?? 'Venue chart Designer';\n frame.allow = this.options.allow ?? 'clipboard-write';\n frame.referrerPolicy = this.options.referrerPolicy ?? 'origin';\n frame.src = url.toString();\n frame.style.width = '100%';\n frame.style.height = '100%';\n frame.style.border = '0';\n Object.assign(frame.style, this.options.style);\n if (this.options.className) frame.className = this.options.className;\n\n window.addEventListener('message', this.handleMessage);\n resolveContainer(this.options.container).append(frame);\n this.frame = frame;\n return frame;\n }\n\n /** Replace the iframe instead of assigning a new fragment to an existing one. */\n setDesignerUrl(designerUrl: string): HTMLIFrameElement {\n this.options = { ...this.options, designerUrl };\n return this.mount();\n }\n\n getIframe(): HTMLIFrameElement | null {\n return this.frame;\n }\n\n destroy(): void {\n window.removeEventListener('message', this.handleMessage);\n this.frame?.remove();\n this.frame = null;\n this.designerOrigin = '';\n }\n\n private handleMessage = (event: MessageEvent<unknown>) => {\n if (!this.frame || event.origin !== this.designerOrigin || event.source !== this.frame.contentWindow) return;\n if (!event.data || typeof event.data !== 'object') return;\n const data = event.data as Record<string, unknown>;\n if (typeof data.type !== 'string' || !TYPES.has(data.type as EmbeddedDesignerEventType)) return;\n\n const message: EmbeddedDesignerMessage = {\n type: data.type as EmbeddedDesignerEventType,\n chartId: typeof data.chartId === 'string' ? data.chartId : undefined,\n workspaceId: typeof data.workspaceId === 'string' ? data.workspaceId : undefined,\n expiresAt: typeof data.expiresAt === 'number' ? data.expiresAt : undefined,\n code: typeof data.code === 'string' ? data.code : undefined,\n message: typeof data.message === 'string' ? data.message : undefined,\n meta: data.meta,\n };\n if (this.options.expectedChartId && message.chartId && message.chartId !== this.options.expectedChartId) return;\n if (this.options.expectedWorkspaceId && message.workspaceId && message.workspaceId !== this.options.expectedWorkspaceId) return;\n\n switch (message.type) {\n case 'seatlayer.designer.ready': this.options.onReady?.(message); break;\n case 'seatlayer.designer.saved': this.options.onSaved?.(message); break;\n case 'seatlayer.designer.published': this.options.onPublished?.(message); break;\n case 'seatlayer.designer.close': this.options.onClose?.(message); break;\n case 'seatlayer.designer.error': this.options.onError?.(message); break;\n }\n };\n}\n"],"mappings":"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","names":["resolveContainer"]}
1
+ {"version":3,"sources":["../src/SeatingChart.ts","../src/api.ts","../src/EmbeddedDesigner.ts","../src/SeatPicker.ts"],"sourcesContent":["/**\n * SeatingChart — the embeddable buyer picker.\n *\n * A thin wrapper over the shared PickerController (src/picker/PickerController):\n * it owns the mount <div> + the public embed contract (hold-only — the SDK hands\n * the holdId to the host page for a server-side book) and delegates all transport\n * + booking to the controller, so the SDK inherits every fix made for the live\n * buyer page and the demo picker.\n */\nimport { PickerController, loadLocale, setStringOverrides, t, type PickerSeat, type SeatHoverDetails } from '@seatlayer/core';\nimport { PubApi, type BestAvailableResult, type HoldResult } from './api';\n\nconst DEFAULT_API_BASE = 'https://api.seatlayer.io';\nconst DEFAULT_MAX_SELECTION = 10;\n\n/** A seat as surfaced to the host page (prices resolved from the chart's categories). */\nexport type SelectedSeat = PickerSeat;\nexport interface GAAreaAvailability {\n id: string; label: string; capacity: number; available: number; categoryKey: string; price: number; currency: string;\n tiers?: Array<{ id: string; name: string; price: number }>;\n}\n\nexport interface SeatingChartOptions {\n /** CSS selector or an HTMLElement to render into. */\n container: string | HTMLElement;\n /** Event key, e.g. `ev_xxx`. */\n event: string;\n /** API origin. Defaults to https://api.seatlayer.io. */\n apiBase?: string;\n /** Reserved for future authenticated rendering — accepted + stored, not yet sent. */\n publicKey?: string;\n /** Max seats selectable at once (default 10). */\n maxSelection?: number;\n /**\n * BCP 47 language for the widget UI — `'de'`, `'es-MX'`, etc. Falls back to\n * the browser language, then English. Built-in: en, es, de, fr. The German\n * bundle (etc.) is fetched on demand so unused languages cost nothing.\n */\n locale?: string;\n /**\n * Per-key string overrides layered over the active locale — white-label copy\n * without shipping a whole bundle, e.g. `{ 'map.fromPrice': 'ab {price}' }`.\n */\n messages?: Record<string, string>;\n /** ISO 4217 currency for on-map prices (default USD). */\n currency?: string;\n /**\n * Colorblind-safe rendering: category hues switch to an Okabe-Ito palette\n * and booked seats render hollow, so state never relies on hue alone.\n * Toggleable later with setColorblindSafe().\n */\n colorblindSafe?: boolean;\n /**\n * Built-in seat tooltip on mouse hover (seat · category · price · status).\n * Rendered inside the widget so every host gets it; default true. Turn off\n * to draw your own popover from onSeatHover.\n */\n seatTooltip?: boolean;\n /**\n * Seat hover with everything a popover needs (category label/color, resolved\n * tier-aware price, live status, currency); null on hover-out. Fires whether\n * or not the built-in tooltip is enabled.\n */\n onSeatHover?: (details: SeatHoverDetails | null) => void;\n onSelectionChange?: (seats: SelectedSeat[]) => void;\n onHold?: (result: HoldResult) => void;\n onHoldExpired?: () => void;\n onGAClick?: (area: GAAreaAvailability) => void;\n onError?: (err: unknown) => void;\n /**\n * Multi-floor charts only: fires when the buyer taps a deck in the stacked\n * 3D view, after the picker switches to that floor — lets the host page sync\n * its own floor UI (tabs, labels) with the map.\n */\n onDeckTap?: (floorId: string) => void;\n /**\n * Non-blocking, localized selection advice — currently the orphan-seat hint\n * (the selection would strand a single free seat between taken neighbors).\n * `null` clears it. Purely informational; nothing is ever prevented.\n */\n onHint?: (message: string | null) => void;\n}\n\nfunction resolveContainer(container: string | HTMLElement): HTMLElement {\n if (typeof container === 'string') {\n const el = document.querySelector(container);\n if (!el) throw new Error(`seatmap: container \"${container}\" not found`);\n return el as HTMLElement;\n }\n if (!(container instanceof HTMLElement)) {\n throw new Error('seatmap: container must be a CSS selector or an HTMLElement');\n }\n return container;\n}\n\nexport class SeatingChart {\n private readonly opts: SeatingChartOptions;\n private readonly controller: PickerController;\n /** Reserved for future authenticated rendering — stored, not yet sent on any request. */\n readonly publicKey?: string;\n\n private mount: HTMLElement | null = null;\n private hostEl: HTMLDivElement | null = null;\n private rendered = false;\n private tipEl: HTMLDivElement | null = null;\n private tipPos = { x: 0, y: 0 };\n private onTipMove: ((e: MouseEvent) => void) | null = null;\n\n constructor(options: SeatingChartOptions) {\n if (!options || typeof options !== 'object') throw new Error('seatmap: options object is required');\n if (!options.container) throw new Error('seatmap: `container` is required');\n if (!options.event || typeof options.event !== 'string') throw new Error('seatmap: `event` key is required');\n\n this.opts = options;\n this.publicKey = options.publicKey;\n const api = new PubApi((options.apiBase ?? DEFAULT_API_BASE).replace(/\\/+$/, ''));\n this.controller = new PickerController({\n transport: api,\n eventKey: options.event,\n maxSelection: options.maxSelection ?? DEFAULT_MAX_SELECTION,\n currency: options.currency,\n onSelectionChange: (seats) => this.opts.onSelectionChange?.(seats),\n onHold: (h) => this.opts.onHold?.({ holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items }),\n onHoldExpired: () => this.opts.onHoldExpired?.(),\n onGAClick: (areaId) => {\n const area = this.controller.getGAAreas().find((candidate) => candidate.id === areaId);\n if (area) this.opts.onGAClick?.(area);\n },\n onError: (err) => this.opts.onError?.(err),\n onDeckTap: (floorId) => this.opts.onDeckTap?.(floorId),\n onHint: (message) => this.opts.onHint?.(message),\n // Live-activity cue: pulse seats that other buyers take while the map is\n // open — the WS feed already streams the status change, this makes it felt.\n flashOnLiveChange: true,\n onSeatHover: (details) => {\n this.opts.onSeatHover?.(details);\n if (this.opts.seatTooltip !== false) this.updateTooltip(details);\n },\n colorblindSafe: options.colorblindSafe,\n });\n }\n\n /** Fetch the chart, mount the renderer, seed statuses and go live. Idempotent. */\n async render(): Promise<this> {\n if (this.rendered) return this;\n this.rendered = true;\n\n // Resolve + load the UI language before the first paint so on-map labels\n // (\"N LEFT\", \"FROM …\", the map aria-label) render translated. English and\n // already-loaded locales resolve synchronously; others fetch one small chunk.\n await loadLocale(this.opts.locale);\n if (this.opts.messages) setStringOverrides(this.opts.messages);\n\n // Mount an owned <div> inside the caller's container so we never fight their\n // layout and can cleanly remove it on destroy().\n this.mount = resolveContainer(this.opts.container);\n const host = document.createElement('div');\n host.style.width = '100%';\n host.style.height = '100%';\n host.style.position = 'relative';\n this.mount.appendChild(host);\n this.hostEl = host;\n\n const info = await this.controller.render(host);\n if (!info) {\n this.rendered = false;\n return this;\n }\n\n // Tooltip element + cursor tracking (mouse only — touch selects directly and\n // reviews seats in the host tray). Positioned at the cursor, flipped at edges.\n // Appended AFTER controller.render — mounting the canvas replaces the host's\n // prior children, so anything added earlier would be wiped.\n if (this.opts.seatTooltip !== false) {\n const tip = document.createElement('div');\n tip.setAttribute('role', 'tooltip');\n tip.style.cssText =\n 'position:absolute;z-index:7;pointer-events:none;display:none;max-width:240px;' +\n 'background:#10162a;color:#fff;border-radius:10px;padding:9px 12px;' +\n 'font:500 12px/1.45 -apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif;' +\n 'box-shadow:0 10px 30px -10px rgba(0,0,0,.5);';\n host.appendChild(tip);\n this.tipEl = tip;\n this.onTipMove = (e: MouseEvent) => {\n const r = host.getBoundingClientRect();\n this.tipPos = { x: e.clientX - r.left, y: e.clientY - r.top };\n if (this.tipEl && this.tipEl.style.display !== 'none') this.placeTooltip();\n };\n host.addEventListener('mousemove', this.onTipMove);\n }\n if (info.mode === 'test') {\n host.style.overflow = 'hidden';\n const ribbon = document.createElement('div');\n ribbon.textContent = t('picker.testMode');\n ribbon.setAttribute('aria-label', t('picker.testMode'));\n ribbon.style.cssText =\n 'position:absolute;top:18px;right:-34px;z-index:6;transform:rotate(45deg);' +\n 'width:140px;text-align:center;padding:4px 0;background:#f4b740;color:#1a1200;' +\n 'font:800 10.5px/1.4 -apple-system,BlinkMacSystemFont,sans-serif;letter-spacing:.12em;' +\n 'box-shadow:0 2px 8px rgba(0,0,0,.25);pointer-events:none;';\n host.appendChild(ribbon);\n }\n return this;\n }\n\n private placeTooltip(): void {\n if (!this.tipEl || !this.hostEl) return;\n const hw = this.hostEl.clientWidth;\n const tw = this.tipEl.offsetWidth;\n const th = this.tipEl.offsetHeight;\n let x = this.tipPos.x + 14;\n let y = this.tipPos.y - th - 12;\n if (x + tw > hw - 8) x = this.tipPos.x - tw - 14;\n if (y < 8) y = this.tipPos.y + 18;\n this.tipEl.style.left = `${Math.max(8, x)}px`;\n this.tipEl.style.top = `${Math.max(8, y)}px`;\n }\n\n private updateTooltip(details: SeatHoverDetails | null): void {\n if (!this.tipEl) return;\n if (!details) {\n this.tipEl.style.display = 'none';\n return;\n }\n const money = (() => {\n try {\n return new Intl.NumberFormat(undefined, { style: 'currency', currency: details.currency }).format(details.price);\n } catch {\n return `${details.price} ${details.currency}`;\n }\n })();\n const statusLine =\n details.status === 'free'\n ? ''\n : `<div style=\"margin-top:5px;font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:#fca5a5;font-weight:700\">${\n details.status === 'held' ? t('map.statusHeld') : t('map.statusTaken')\n }</div>`;\n this.tipEl.innerHTML =\n `<div style=\"font-weight:700;font-size:13px\">${details.label}</div>` +\n `<div style=\"display:flex;align-items:center;gap:6px;margin-top:4px;color:#c7cddc\">` +\n `<span style=\"width:9px;height:9px;border-radius:50%;flex:none;background:${details.categoryColor}\"></span>` +\n `<span>${details.categoryLabel}</span>` +\n `<span style=\"margin-left:auto;font-weight:700;color:#fff\">${money}</span></div>` +\n statusLine;\n this.tipEl.style.display = 'block';\n this.placeTooltip();\n }\n\n /** Current selection with prices resolved from the chart categories. */\n getSelection(): SelectedSeat[] {\n return this.controller.getSelection();\n }\n\n /** Hold the current selection. Resolves the hold, or null on a 409 conflict. */\n async hold(options: { ttlMs?: number } = {}): Promise<HoldResult | null> {\n try {\n const h = await this.controller.hold(undefined, options.ttlMs);\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n getGAAreas(): GAAreaAvailability[] {\n return this.controller.getGAAreas();\n }\n\n async holdGA(\n areaId: string,\n qty: number,\n options: { tierId?: string | null; ttlMs?: number } = {},\n ): Promise<HoldResult | null> {\n try {\n const h = await this.controller.holdGA(areaId, qty, options);\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n /** Ask the server for the `qty` best free seats and hold them atomically. */\n async bestAvailable(qty: number, categoryKey?: string): Promise<BestAvailableResult | null> {\n try {\n const h = await this.controller.bestAvailable(qty, categoryKey);\n return h ? { holdId: h.holdId, expiresAt: h.expiresAt, labels: h.labels, seats: h.seats, items: h.items } : null;\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n /**\n * Choose a ticket tier for a selected seat (e.g. Adult → Child). The seat's\n * available `tiers` are on each `SelectedSeat` from `getSelection()` /\n * `onSelectionChange`. Re-emits the selection with the new tier + price, and\n * the tier rides along in the next `hold()` / `onHold` per seat. `tierId=null`\n * reverts to the default tier.\n */\n setSeatTier(seatId: string, tierId: string | null): void {\n this.controller.setSeatTier(seatId, tierId);\n }\n\n /**\n * Floors of a multi-floor chart — `[{ id, name }]` (single-floor charts\n * return one entry; empty before render()). Pair with setFloor() to build a\n * host-side floor switcher.\n */\n getFloors(): { id: string; name: string }[] {\n return this.controller.getFloors();\n }\n\n /** Switch the shown floor (2D). Warns + no-ops on single-floor charts. */\n setFloor(floorId: string): void {\n if (this.controller.getFloors().length <= 1) {\n console.warn('seatmap: setFloor() ignored — this chart has a single floor');\n return;\n }\n this.controller.setFloor(floorId);\n }\n\n /** Toggle colorblind-safe rendering at runtime (see options.colorblindSafe). */\n setColorblindSafe(on: boolean): void {\n this.controller.setColorblindSafe(on);\n }\n\n /** Zoom in one step (same increment as the wheel/pinch gesture). */\n zoomIn(): void {\n this.controller.zoomIn();\n }\n\n /** Zoom out one step. */\n zoomOut(): void {\n this.controller.zoomOut();\n }\n\n /** Reset the camera so the whole chart fits the container. */\n zoomToFit(): void {\n this.controller.zoomToFit();\n }\n\n /** Release the current hold (if any). No-op when nothing is held. */\n async release(): Promise<void> {\n await this.controller.release();\n }\n\n /** Tear everything down: close the socket, stop timers, drop the canvas. */\n destroy(): void {\n if (this.hostEl && this.onTipMove) this.hostEl.removeEventListener('mousemove', this.onTipMove);\n this.tipEl = null;\n this.onTipMove = null;\n this.controller.destroy();\n if (this.hostEl && this.hostEl.parentNode) this.hostEl.parentNode.removeChild(this.hostEl);\n this.hostEl = null;\n this.mount = null;\n this.rendered = false;\n }\n}\n","/**\n * Minimal client for the public embed surface of workers/api (the `/pub/*`\n * routes). Deliberately self-contained — it does NOT reuse src/lib/api.ts,\n * which bakes in a build-time API base and dashboard session credentials. The\n * SDK runs cross-origin on a third-party ticketing page, so:\n * - apiBase is per-instance (constructor option), not a build constant;\n * - credentials are omitted (no cookie to send, avoids CORS-credential setup);\n * - no custom headers on mutating calls (keeps the CORS preflight trivial).\n */\nimport type { ChartDoc, PickerSeat as SelectedSeat } from '@seatlayer/core';\n\nexport interface HoldConflict {\n label: string;\n status: string;\n}\n\nexport interface HoldLineItem {\n label: string; objectId: string; objectType: 'seat' | 'booth' | 'ga'; categoryKey: string;\n tierId: string | null;\n /** Price in major currency units (for example 45 means $45.00). */\n unitPrice: number;\n currency: string;\n quantity?: number;\n}\n\nexport class ApiError extends Error {\n status: number;\n code?: string;\n /** Present when a hold 409s because seats were just taken/held. */\n conflicts?: HoldConflict[];\n /** Present when best-available 409s ('not_enough_together' | 'sold_out'). */\n reason?: string;\n\n constructor(status: number, message: string, code?: string, conflicts?: HoldConflict[], reason?: string) {\n super(message);\n this.name = 'ApiError';\n this.status = status;\n this.code = code;\n this.conflicts = conflicts;\n this.reason = reason;\n }\n}\n\nexport interface PubChartResult {\n event: { key: string; name: string };\n doc: ChartDoc;\n}\n\nexport interface PubObjectsResult {\n /** Every non-free seat's status, keyed by seat label. */\n seats: Record<string, string>;\n updatedAt: number;\n}\n\nexport interface HoldResult {\n holdId: string;\n expiresAt: number;\n /** The held seats with the buyer's chosen ticket tier per seat (present on hold). */\n seats?: SelectedSeat[];\n items?: HoldLineItem[];\n}\n\n/** Best-available response — the server-picked seats plus the hold they landed in. */\nexport interface BestAvailableResult {\n holdId: string;\n expiresAt: number;\n labels: string[];\n seats?: SelectedSeat[];\n items?: HoldResult['items'];\n}\n\nasync function request<T>(\n base: string,\n path: string,\n init: { method?: 'GET' | 'POST'; body?: unknown } = {},\n): Promise<T> {\n const method = init.method ?? 'GET';\n const headers: Record<string, string> = {};\n let body: string | undefined;\n if (init.body !== undefined) {\n headers['Content-Type'] = 'application/json';\n body = JSON.stringify(init.body);\n }\n\n const res = await fetch(`${base}${path}`, { method, headers, body, credentials: 'omit' });\n\n const isJson = (res.headers.get('content-type') ?? '').includes('application/json');\n const data = isJson ? await res.json().catch(() => null) : null;\n\n if (!res.ok) {\n const err = data as\n | { error?: string; code?: string; conflicts?: HoldConflict[]; reason?: string }\n | null;\n throw new ApiError(res.status, err?.error ?? `request_failed_${res.status}`, err?.code, err?.conflicts, err?.reason);\n }\n return data as T;\n}\n\n/** Public-surface client bound to one apiBase (e.g. https://api.seatlayer.io). */\nexport class PubApi {\n constructor(private readonly base: string) {}\n\n chart(key: string): Promise<PubChartResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/chart`);\n }\n\n objects(key: string): Promise<PubObjectsResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/objects`);\n }\n\n hold(key: string, selections: Array<{ label: string; tierId?: string | null }>, ttlMs?: number, replaceHoldId?: string): Promise<HoldResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/hold`, {\n method: 'POST',\n body: { selections, ...(ttlMs ? { ttlMs } : {}), ...(replaceHoldId ? { replaceHoldId } : {}) },\n });\n }\n\n bestAvailable(key: string, qty: number, categoryKey?: string): Promise<BestAvailableResult> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/best-available`, {\n method: 'POST',\n body: { qty, ...(categoryKey ? { categoryKey } : {}) },\n });\n }\n\n release(key: string, labels: string[], holdId: string): Promise<{ ok: true }> {\n return request(this.base, `/pub/events/${encodeURIComponent(key)}/release`, {\n method: 'POST',\n body: { labels, holdId },\n });\n }\n\n socketUrl(key: string): string {\n const wsBase = this.base.replace(/^http/, 'ws');\n return `${wsBase}/pub/events/${encodeURIComponent(key)}/subscribe`;\n }\n}\n","/**\n * A secure, framework-neutral host for the SeatLayer chart Designer.\n *\n * The Designer remains an iframe so a platform never gives its SeatLayer secret\n * key to a browser. This class owns the iframe lifecycle and accepts messages\n * only from that iframe's exact origin.\n */\nexport type EmbeddedDesignerEventType =\n | 'seatlayer.designer.ready'\n | 'seatlayer.designer.saved'\n | 'seatlayer.designer.published'\n | 'seatlayer.designer.close'\n | 'seatlayer.designer.error';\n\nexport interface EmbeddedDesignerMessage {\n type: EmbeddedDesignerEventType;\n chartId?: string;\n workspaceId?: string;\n expiresAt?: number;\n code?: string;\n message?: string;\n meta?: unknown;\n}\n\nexport interface EmbeddedDesignerOptions {\n /** The short-lived URL returned by your backend's Designer-session call. */\n designerUrl: string;\n /** CSS selector or element where the iframe is mounted. */\n container: string | HTMLElement;\n /** Verify the message belongs to the chart your backend opened. */\n expectedChartId?: string;\n /** Verify the message belongs to the workspace your backend opened. */\n expectedWorkspaceId?: string;\n title?: string;\n className?: string;\n style?: Partial<CSSStyleDeclaration>;\n allow?: string;\n referrerPolicy?: ReferrerPolicy;\n onReady?: (message: EmbeddedDesignerMessage) => void;\n onSaved?: (message: EmbeddedDesignerMessage) => void;\n onPublished?: (message: EmbeddedDesignerMessage) => void;\n onClose?: (message: EmbeddedDesignerMessage) => void;\n onError?: (message: EmbeddedDesignerMessage) => void;\n}\n\nconst TYPES = new Set<EmbeddedDesignerEventType>([\n 'seatlayer.designer.ready',\n 'seatlayer.designer.saved',\n 'seatlayer.designer.published',\n 'seatlayer.designer.close',\n 'seatlayer.designer.error',\n]);\n\nfunction resolveContainer(container: string | HTMLElement): HTMLElement {\n if (typeof container !== 'string') return container;\n const element = document.querySelector<HTMLElement>(container);\n if (!element) throw new Error(`EmbeddedDesigner container not found: ${container}`);\n return element;\n}\n\n/** Mount, replace, and destroy a scoped Designer iframe safely. */\nexport class EmbeddedDesigner {\n private options: EmbeddedDesignerOptions;\n private frame: HTMLIFrameElement | null = null;\n private designerOrigin = '';\n\n constructor(options: EmbeddedDesignerOptions) {\n this.options = options;\n }\n\n mount(): HTMLIFrameElement {\n this.destroy();\n const url = new URL(this.options.designerUrl, window.location.href);\n if (url.protocol !== 'https:' && url.hostname !== 'localhost' && url.hostname !== '127.0.0.1') {\n throw new Error('EmbeddedDesigner requires an HTTPS designerUrl outside local development.');\n }\n this.designerOrigin = url.origin;\n\n const frame = document.createElement('iframe');\n frame.title = this.options.title ?? 'Venue chart Designer';\n frame.allow = this.options.allow ?? 'clipboard-write';\n frame.referrerPolicy = this.options.referrerPolicy ?? 'origin';\n frame.src = url.toString();\n frame.style.width = '100%';\n frame.style.height = '100%';\n frame.style.border = '0';\n Object.assign(frame.style, this.options.style);\n if (this.options.className) frame.className = this.options.className;\n\n window.addEventListener('message', this.handleMessage);\n resolveContainer(this.options.container).append(frame);\n this.frame = frame;\n return frame;\n }\n\n /** Replace the iframe instead of assigning a new fragment to an existing one. */\n setDesignerUrl(designerUrl: string): HTMLIFrameElement {\n this.options = { ...this.options, designerUrl };\n return this.mount();\n }\n\n getIframe(): HTMLIFrameElement | null {\n return this.frame;\n }\n\n destroy(): void {\n window.removeEventListener('message', this.handleMessage);\n this.frame?.remove();\n this.frame = null;\n this.designerOrigin = '';\n }\n\n private handleMessage = (event: MessageEvent<unknown>) => {\n if (!this.frame || event.origin !== this.designerOrigin || event.source !== this.frame.contentWindow) return;\n if (!event.data || typeof event.data !== 'object') return;\n const data = event.data as Record<string, unknown>;\n if (typeof data.type !== 'string' || !TYPES.has(data.type as EmbeddedDesignerEventType)) return;\n\n const message: EmbeddedDesignerMessage = {\n type: data.type as EmbeddedDesignerEventType,\n chartId: typeof data.chartId === 'string' ? data.chartId : undefined,\n workspaceId: typeof data.workspaceId === 'string' ? data.workspaceId : undefined,\n expiresAt: typeof data.expiresAt === 'number' ? data.expiresAt : undefined,\n code: typeof data.code === 'string' ? data.code : undefined,\n message: typeof data.message === 'string' ? data.message : undefined,\n meta: data.meta,\n };\n if (this.options.expectedChartId && message.chartId && message.chartId !== this.options.expectedChartId) return;\n if (this.options.expectedWorkspaceId && message.workspaceId && message.workspaceId !== this.options.expectedWorkspaceId) return;\n\n switch (message.type) {\n case 'seatlayer.designer.ready': this.options.onReady?.(message); break;\n case 'seatlayer.designer.saved': this.options.onSaved?.(message); break;\n case 'seatlayer.designer.published': this.options.onPublished?.(message); break;\n case 'seatlayer.designer.close': this.options.onClose?.(message); break;\n case 'seatlayer.designer.error': this.options.onError?.(message); break;\n }\n };\n}\n","/**\n * SeatPicker — the full buyer experience as a widget.\n *\n * Where `SeatingChart` is canvas-only, SeatPicker owns the complete chrome\n * from the canonical UX (SeatmapUX/11 Buyer Picker.dc.html): branded header,\n * live price panel, selection tray with GA steppers, hold countdown, snipe\n * toasts and expiry recovery — all on top of the shared PickerController, so\n * every host gets the whole experience with one mount.\n *\n * Render contexts (owner requirement): the SAME widget adapts to a full-screen\n * takeover, an inline <div> in a content page, or a popup — breakpoints key\n * off the CONTAINER via ResizeObserver, never the viewport. `SeatPicker.open()`\n * mounts a document-level modal (scrim, ESC, focus restore) in one call.\n *\n * Theming (owner requirement): org account customization flows automatically —\n * the chart payload's ChartTheme (accent, accentInk, logoUrl, brand name,\n * fontFamily, …) seeds the look; the host `theme` option overrides any subset;\n * and every value lands as a `--sl-*` CSS custom property on the widget root\n * so plain host CSS can restyle too.\n */\nimport {\n PickerController,\n loadLocale,\n setStringOverrides,\n t,\n type ChartTheme,\n type PickerSeat,\n type SeatHoverDetails,\n} from '@seatlayer/core';\nimport { PubApi, type HoldResult } from './api';\nimport type { GAAreaAvailability } from './SeatingChart';\n\nconst DEFAULT_API_BASE = 'https://api.seatlayer.io';\nconst DEFAULT_MAX_SELECTION = 10;\n\n/** Host theme overrides — any subset; unset keys fall back to the org's chart theme, then defaults. */\nexport interface SeatPickerTheme {\n /** Brand accent (CTA, active chips, hold pill). */\n accent?: string;\n /** Ink on the accent (button labels). */\n accentInk?: string;\n /** Widget background. */\n background?: string;\n /** Panel/card surface color. */\n surface?: string;\n /** Primary text color. */\n text?: string;\n /** Secondary text color. */\n muted?: string;\n /** Hairline/border color. */\n line?: string;\n /** Font stack for all widget chrome. */\n fontFamily?: string;\n /** Corner radius base (px). */\n radius?: number;\n /** Header logo URL (falls back to the org logo from the chart theme, then a monogram). */\n logoUrl?: string;\n /** Brand/event fallback name for the monogram. */\n brandName?: string;\n}\n\nexport interface SeatPickerOptions {\n /** CSS selector or element to mount into. Omit when using SeatPicker.open(). */\n container?: string | HTMLElement;\n /** Event key, e.g. `ev_xxx`. */\n event: string;\n /** API origin. Defaults to https://api.seatlayer.io. */\n apiBase?: string;\n /** Reserved for future authenticated rendering. */\n publicKey?: string;\n /** Max seats selectable at once (default 10). */\n maxSelection?: number;\n /** BCP 47 language for the widget UI. Built-in: en, es, de, fr. */\n locale?: string;\n /** Per-key string overrides layered over the active locale. */\n messages?: Record<string, string>;\n /** ISO 4217 currency fallback (the org/event currency on the chart wins). */\n currency?: string;\n /** Colorblind-safe rendering (Okabe-Ito palette, hollow booked seats). */\n colorblindSafe?: boolean;\n /** Host theme overrides — see SeatPickerTheme. */\n theme?: SeatPickerTheme;\n /** Hold TTL in ms passed to hold(); server clamps to its own limits. */\n holdTtlMs?: number;\n /**\n * Buyer pressed the CTA and the hold succeeded — hand off to YOUR checkout.\n * The hold carries holdId, expiresAt, seat labels and priced line items.\n */\n onCheckout?: (hold: HoldResult, seats: PickerSeat[]) => void;\n /** Selection changed (tap or best-available). */\n onSelectionChange?: (seats: PickerSeat[]) => void;\n /** The open hold expired server-side (widget already reset itself). */\n onHoldExpired?: () => void;\n /** Modal only: the buyer closed the picker (ESC / scrim / ✕). */\n onClose?: () => void;\n onError?: (err: unknown) => void;\n}\n\nfunction resolveContainer(container: string | HTMLElement): HTMLElement {\n if (typeof container === 'string') {\n const el = document.querySelector(container);\n if (!el) throw new Error(`seatmap: container \"${container}\" not found`);\n return el as HTMLElement;\n }\n if (!(container instanceof HTMLElement)) {\n throw new Error('seatmap: container must be a CSS selector or an HTMLElement');\n }\n return container;\n}\n\n/** Widget stylesheet — injected once per document. Every color/font/radius is a --sl-* token. */\nconst STYLE_ID = 'seatlayer-picker-style';\nconst CSS = `\n.sl-picker{position:relative;display:flex;flex-direction:column;width:100%;height:100%;min-height:420px;overflow:hidden;\n background:var(--sl-bg);color:var(--sl-text);font-family:var(--sl-font);border-radius:var(--sl-radius);\n --sl-r-sm:calc(var(--sl-radius) * .55)}\n.sl-picker *{box-sizing:border-box;margin:0;padding:0}\n.sl-picker button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}\n\n/* header */\n.sl-head{display:flex;align-items:center;gap:12px;padding:12px 16px;border-bottom:1px solid var(--sl-line);flex:none}\n.sl-logo{width:34px;height:34px;border-radius:9px;flex:none;display:flex;align-items:center;justify-content:center;\n background:var(--sl-accent);color:var(--sl-accent-ink);font-weight:800;font-size:15px;overflow:hidden}\n.sl-logo img{width:100%;height:100%;object-fit:cover;display:block}\n.sl-head-info{min-width:0;flex:1}\n.sl-head-name{font-weight:700;font-size:15px;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sl-head-meta{font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--sl-muted);margin-top:3px;\n white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:600}\n.sl-hold-pill{display:none;align-items:center;gap:6px;padding:6px 12px;border-radius:999px;flex:none;\n background:var(--sl-accent);color:var(--sl-accent-ink);font-weight:700;font-size:12px;font-variant-numeric:tabular-nums}\n.sl-hold-pill.on{display:inline-flex}\n.sl-close{width:32px;height:32px;border-radius:999px;flex:none;display:none;align-items:center;justify-content:center;\n border:1px solid var(--sl-line);color:var(--sl-muted);transition:color .15s,border-color .15s}\n.sl-close:hover{color:var(--sl-text);border-color:var(--sl-muted)}\n.sl-close.on{display:inline-flex}\n.sl-close svg{width:14px;height:14px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round}\n\n/* body */\n.sl-body{display:flex;flex:1;min-height:0}\n.sl-map{position:relative;flex:1;min-width:0}\n.sl-map-host{position:absolute;inset:0}\n.sl-side{width:300px;flex:none;border-left:1px solid var(--sl-line);display:flex;flex-direction:column;min-height:0;overflow-y:auto}\n\n/* narrow (container < 640px): side panel becomes a bottom sheet */\n.sl-picker[data-layout=\"narrow\"] .sl-body{flex-direction:column}\n.sl-picker[data-layout=\"narrow\"] .sl-map{min-height:0;flex:1}\n.sl-picker[data-layout=\"narrow\"] .sl-side{width:100%;max-height:46%;border-left:0;border-top:1px solid var(--sl-line)}\n\n/* price panel */\n.sl-sec{padding:14px 16px 4px;font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--sl-muted);font-weight:700}\n.sl-prices{padding:4px 16px 10px;border-bottom:1px solid var(--sl-line)}\n.sl-price-row{display:flex;align-items:center;gap:8px;padding:5px 0;font-size:13px}\n.sl-dot{width:9px;height:9px;border-radius:50%;flex:none}\n.sl-price-label{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:600}\n.sl-price-left{font-size:11px;color:var(--sl-muted);font-variant-numeric:tabular-nums}\n.sl-price-amt{font-weight:800;font-variant-numeric:tabular-nums}\n\n/* tray */\n.sl-tray{flex:1;padding:10px 16px;display:flex;flex-direction:column;gap:8px;min-height:0}\n.sl-tray-hint{font-size:12.5px;color:var(--sl-muted);line-height:1.5}\n.sl-chip{display:flex;align-items:center;gap:9px;padding:9px 11px;border:1px solid var(--sl-line);\n border-radius:var(--sl-r-sm);background:var(--sl-surface);font-size:13px}\n.sl-chip b{font-weight:800}\n.sl-chip .cat{color:var(--sl-muted);font-size:11.5px;flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.sl-chip .amt{font-weight:700;font-variant-numeric:tabular-nums}\n.sl-chip .rm{width:22px;height:22px;border-radius:999px;flex:none;display:flex;align-items:center;justify-content:center;color:var(--sl-muted)}\n.sl-chip .rm:hover{color:var(--sl-text)}\n.sl-chip .rm svg{width:11px;height:11px;stroke:currentColor;stroke-width:2.4;fill:none;stroke-linecap:round}\n\n/* GA rows */\n.sl-ga{display:flex;align-items:center;gap:10px;padding:9px 11px;border:1px dashed var(--sl-line);border-radius:var(--sl-r-sm)}\n.sl-ga-info{flex:1;min-width:0}\n.sl-ga-name{font-weight:700;font-size:13px}\n.sl-ga-sub{font-size:11px;color:var(--sl-muted);margin-top:2px}\n.sl-ga-qty{display:flex;align-items:center;gap:8px}\n.sl-ga-qty button{width:26px;height:26px;border-radius:999px;background:var(--sl-surface);border:1px solid var(--sl-line);\n font-size:15px;font-weight:700;display:flex;align-items:center;justify-content:center;transition:border-color .15s}\n.sl-ga-qty button:hover{border-color:var(--sl-muted)}\n.sl-ga-qty span{min-width:16px;text-align:center;font-weight:800;font-variant-numeric:tabular-nums}\n\n/* footer */\n.sl-foot{padding:12px 16px 14px;border-top:1px solid var(--sl-line);flex:none}\n.sl-total{display:flex;justify-content:space-between;align-items:center;font-size:13px;margin-bottom:10px}\n.sl-total b{font-size:17px;font-variant-numeric:tabular-nums}\n.sl-cta{width:100%;padding:13px;border-radius:var(--sl-r-sm);font-weight:800;font-size:14px;\n background:var(--sl-accent);color:var(--sl-accent-ink);transition:filter .15s,opacity .15s}\n.sl-cta:hover{filter:brightness(1.08)}\n.sl-cta:disabled{opacity:.45;cursor:not-allowed}\n\n/* zoom column */\n.sl-zoom{position:absolute;right:12px;bottom:12px;display:flex;flex-direction:column;gap:6px;z-index:5}\n.sl-zoom button{width:36px;height:36px;border-radius:999px;background:var(--sl-surface);border:1px solid var(--sl-line);\n color:var(--sl-text);font-size:17px;font-weight:700;display:flex;align-items:center;justify-content:center;transition:border-color .15s}\n.sl-zoom button:hover{border-color:var(--sl-muted)}\n.sl-zoom svg{width:14px;height:14px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}\n\n/* toast + boot states */\n.sl-toast{position:absolute;left:50%;bottom:16px;transform:translateX(-50%) translateY(6px);z-index:8;max-width:88%;\n background:var(--sl-surface);border:1px solid var(--sl-line);color:var(--sl-text);border-radius:999px;padding:9px 16px;\n font-size:12.5px;font-weight:600;opacity:0;pointer-events:none;transition:opacity .2s,transform .2s;white-space:nowrap;\n overflow:hidden;text-overflow:ellipsis}\n.sl-toast.on{opacity:1;transform:translateX(-50%) translateY(0)}\n.sl-boot{position:absolute;inset:0;z-index:6;display:flex;flex-direction:column;align-items:center;justify-content:center;\n gap:10px;background:var(--sl-bg);font-size:13px;font-weight:600;color:var(--sl-muted)}\n.sl-boot-spin{width:24px;height:24px;border-radius:50%;border:3px solid var(--sl-line);border-top-color:var(--sl-accent);\n animation:slspin .8s linear infinite}\n@keyframes slspin{to{transform:rotate(360deg)}}\n.sl-boot-title{font-weight:800;font-size:15px;color:var(--sl-text)}\n.sl-boot-retry{margin-top:4px;padding:9px 20px;border-radius:var(--sl-r-sm);background:var(--sl-accent);\n color:var(--sl-accent-ink);font-weight:700;font-size:13px}\n\n/* modal host */\n.sl-modal-scrim{position:fixed;inset:0;z-index:2147483000;background:rgba(5,7,12,.66);display:flex;align-items:center;justify-content:center;padding:18px}\n.sl-modal-frame{width:min(1200px,100%);height:min(820px,100%);border-radius:16px;overflow:hidden;box-shadow:0 40px 120px -30px rgba(0,0,0,.8)}\n@media(max-width:640px){.sl-modal-scrim{padding:0}.sl-modal-frame{width:100%;height:100%;border-radius:0}}\n`;\n\nfunction ensureStyle(): void {\n if (document.getElementById(STYLE_ID)) return;\n const el = document.createElement('style');\n el.id = STYLE_ID;\n el.textContent = CSS;\n document.head.appendChild(el);\n}\n\n/** Merge order: defaults ← org chart theme ← host overrides. */\nfunction resolveTokens(chart: ChartTheme | undefined, host: SeatPickerTheme | undefined): Record<string, string> {\n const accent = host?.accent ?? chart?.accent ?? '#f4b740';\n const accentInk = host?.accentInk ?? chart?.accentInk ?? '#1a1200';\n return {\n '--sl-accent': accent,\n '--sl-accent-ink': accentInk,\n '--sl-bg': host?.background ?? chart?.background ?? '#0f1522',\n '--sl-surface': host?.surface ?? '#1a2234',\n '--sl-text': host?.text ?? chart?.textColor ?? '#eef1f8',\n '--sl-muted': host?.muted ?? '#8b93a7',\n '--sl-line': host?.line ?? 'rgba(139,147,167,.22)',\n '--sl-font': host?.fontFamily ?? chart?.fontFamily ?? \"-apple-system,BlinkMacSystemFont,'Segoe UI',Inter,sans-serif\",\n '--sl-radius': `${host?.radius ?? 14}px`,\n };\n}\n\nexport class SeatPicker {\n private readonly opts: SeatPickerOptions;\n private readonly controller: PickerController;\n\n private root: HTMLDivElement | null = null;\n private mapHost: HTMLDivElement | null = null;\n private rendered = false;\n private destroyed = false;\n\n // chrome refs\n private els: Record<string, HTMLElement> = {};\n private ro: ResizeObserver | null = null;\n private holdTimer: ReturnType<typeof setInterval> | null = null;\n private toastTimer: ReturnType<typeof setTimeout> | null = null;\n\n // state\n private currency = 'USD';\n private hold: HoldResult | null = null;\n private gaQty = new Map<string, number>();\n private tipEl: HTMLDivElement | null = null;\n private tipPos = { x: 0, y: 0 };\n\n // modal plumbing (set by open())\n private modalScrim: HTMLElement | null = null;\n private prevFocus: Element | null = null;\n private escHandler: ((e: KeyboardEvent) => void) | null = null;\n\n /** Mount the full picker as a document-level modal. Resolves after render. */\n static async open(options: Omit<SeatPickerOptions, 'container'>): Promise<SeatPicker> {\n ensureStyle();\n const scrim = document.createElement('div');\n scrim.className = 'sl-modal-scrim';\n const frame = document.createElement('div');\n frame.className = 'sl-modal-frame';\n scrim.appendChild(frame);\n document.body.appendChild(scrim);\n const prevOverflow = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n\n const picker = new SeatPicker({ ...options, container: frame });\n picker.modalScrim = scrim;\n picker.prevFocus = document.activeElement;\n const close = (): void => {\n document.body.style.overflow = prevOverflow;\n picker.destroy();\n options.onClose?.();\n };\n scrim.addEventListener('mousedown', (e) => {\n if (e.target === scrim) close();\n });\n picker.escHandler = (e: KeyboardEvent) => {\n if (e.key === 'Escape') close();\n };\n document.addEventListener('keydown', picker.escHandler);\n await picker.render();\n picker.els.close?.classList.add('on');\n picker.els.close?.addEventListener('click', close);\n return picker;\n }\n\n constructor(options: SeatPickerOptions) {\n if (!options || typeof options !== 'object') throw new Error('seatmap: options object is required');\n if (!options.event || typeof options.event !== 'string') throw new Error('seatmap: `event` key is required');\n if (!options.container) throw new Error('seatmap: `container` is required (or use SeatPicker.open())');\n this.opts = options;\n const api = new PubApi((options.apiBase ?? DEFAULT_API_BASE).replace(/\\/+$/, ''));\n this.controller = new PickerController({\n transport: api,\n eventKey: options.event,\n maxSelection: options.maxSelection ?? DEFAULT_MAX_SELECTION,\n currency: options.currency,\n flashOnLiveChange: true,\n colorblindSafe: options.colorblindSafe,\n onSelectionChange: () => this.syncTray(),\n onStatusChange: () => {\n this.syncPrices();\n this.evictTakenSelections();\n },\n onHoldExpired: () => {\n this.hold = null;\n this.stopHoldTimer();\n this.gaQty.clear();\n this.toast(t('picker.holdExpired', undefined) || 'Your hold expired — seats released. Pick again.');\n this.syncTray();\n this.opts.onHoldExpired?.();\n },\n onSeatHover: (d) => this.updateTooltip(d),\n onHint: (m) => {\n if (m) this.toast(m);\n },\n onError: (err) => this.opts.onError?.(err),\n });\n }\n\n async render(): Promise<this> {\n if (this.rendered) return this;\n this.rendered = true;\n ensureStyle();\n await loadLocale(this.opts.locale);\n if (this.opts.messages) setStringOverrides(this.opts.messages);\n\n const mount = resolveContainer(this.opts.container!);\n const root = document.createElement('div');\n root.className = 'sl-picker';\n this.root = root;\n mount.appendChild(root);\n\n // skeleton first — tokens get re-applied once the chart theme arrives\n Object.entries(resolveTokens(undefined, this.opts.theme)).forEach(([k, v]) => root.style.setProperty(k, v));\n root.innerHTML = `\n <div class=\"sl-head\">\n <div class=\"sl-logo\" data-ref=\"logo\"></div>\n <div class=\"sl-head-info\">\n <div class=\"sl-head-name\" data-ref=\"name\"></div>\n <div class=\"sl-head-meta\" data-ref=\"meta\"></div>\n </div>\n <span class=\"sl-hold-pill\" data-ref=\"hold\"></span>\n <button type=\"button\" class=\"sl-close\" data-ref=\"close\" aria-label=\"Close\">\n <svg viewBox=\"0 0 24 24\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>\n </button>\n </div>\n <div class=\"sl-body\">\n <div class=\"sl-map\">\n <div class=\"sl-map-host\" data-ref=\"map\"></div>\n <div class=\"sl-zoom\">\n <button type=\"button\" aria-label=\"Zoom in\" data-ref=\"zin\">+</button>\n <button type=\"button\" aria-label=\"Zoom out\" data-ref=\"zout\">−</button>\n <button type=\"button\" aria-label=\"Fit to screen\" data-ref=\"zfit\">\n <svg viewBox=\"0 0 24 24\"><path d=\"M8 3H5a2 2 0 0 0-2 2v3M16 3h3a2 2 0 0 1 2 2v3M8 21H5a2 2 0 0 1-2-2v-3M16 21h3a2 2 0 0 0 2-2v-3\"/></svg>\n </button>\n </div>\n <div class=\"sl-boot\" data-ref=\"boot\"><span class=\"sl-boot-spin\"></span>Loading seat map…</div>\n <div class=\"sl-toast\" data-ref=\"toast\" role=\"status\" aria-live=\"polite\"></div>\n </div>\n <div class=\"sl-side\">\n <div class=\"sl-sec\" data-ref=\"pricesSec\">Prices</div>\n <div class=\"sl-prices\" data-ref=\"prices\"></div>\n <div class=\"sl-sec\">Your seats</div>\n <div class=\"sl-tray\" data-ref=\"tray\"></div>\n <div class=\"sl-foot\">\n <div class=\"sl-total\"><span data-ref=\"count\"></span><b data-ref=\"total\"></b></div>\n <button type=\"button\" class=\"sl-cta\" data-ref=\"cta\" disabled></button>\n </div>\n </div>\n </div>`;\n root.querySelectorAll<HTMLElement>('[data-ref]').forEach((el) => {\n this.els[el.dataset.ref!] = el;\n });\n this.mapHost = this.els.map as HTMLDivElement;\n\n // container-adaptive layout\n this.ro = new ResizeObserver(() => {\n const w = root.clientWidth;\n root.dataset.layout = w < 640 ? 'narrow' : 'wide';\n });\n this.ro.observe(root);\n\n // zoom + tooltip wiring\n this.els.zin.addEventListener('click', () => this.controller.zoomIn());\n this.els.zout.addEventListener('click', () => this.controller.zoomOut());\n this.els.zfit.addEventListener('click', () => this.controller.zoomToFit());\n this.tipEl = document.createElement('div');\n this.tipEl.setAttribute('role', 'tooltip');\n this.tipEl.style.cssText =\n 'position:absolute;z-index:7;pointer-events:none;display:none;max-width:240px;background:var(--sl-surface);' +\n 'color:var(--sl-text);border:1px solid var(--sl-line);border-radius:10px;padding:9px 12px;font-size:12px;line-height:1.45;';\n this.els.map.appendChild(this.tipEl);\n this.els.map.addEventListener('mousemove', (e: MouseEvent) => {\n const r = this.els.map.getBoundingClientRect();\n this.tipPos = { x: e.clientX - r.left, y: e.clientY - r.top };\n if (this.tipEl && this.tipEl.style.display !== 'none') this.placeTooltip();\n });\n\n this.els.cta.addEventListener('click', () => void this.handleCta());\n\n const canvasHost = document.createElement('div');\n canvasHost.style.cssText = 'position:absolute;inset:0';\n this.mapHost.appendChild(canvasHost);\n const info = await this.controller.render(canvasHost);\n if (this.destroyed) return this;\n if (!info) {\n this.els.boot.innerHTML =\n '<div class=\"sl-boot-title\">The seat map didn’t load</div>' +\n '<div>Check your connection and try again.</div>' +\n '<button type=\"button\" class=\"sl-boot-retry\">Try again</button>';\n this.els.boot.querySelector('button')!.addEventListener('click', () => {\n // full remount: cheapest reliable recovery\n const container = this.opts.container!;\n const opts = this.opts;\n this.destroy();\n void new SeatPicker({ ...opts, container }).render();\n });\n return this;\n }\n this.els.boot.remove();\n\n // theme: defaults ← org chart theme ← host overrides\n const chartTheme = this.controller.doc?.theme;\n Object.entries(resolveTokens(chartTheme, this.opts.theme)).forEach(([k, v]) => root.style.setProperty(k, v));\n this.currency = info.currency ?? this.opts.currency ?? 'USD';\n\n // header\n const logoUrl = this.opts.theme?.logoUrl ?? chartTheme?.logoUrl;\n if (logoUrl) this.els.logo.innerHTML = `<img src=\"${logoUrl}\" alt=\"\">`;\n else this.els.logo.textContent = (this.opts.theme?.brandName ?? chartTheme?.brandName ?? info.eventName ?? '?').slice(0, 1).toUpperCase();\n this.els.name.textContent = info.eventName ?? '';\n const when = info.startsAt\n ? new Date(info.startsAt).toLocaleString(this.opts.locale, { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' })\n : '';\n this.els.meta.textContent = [info.venue, when].filter(Boolean).join(' · ');\n\n this.syncPrices();\n this.syncTray();\n return this;\n }\n\n // ---- chrome sync ----------------------------------------------------------\n\n private money(n: number): string {\n try {\n return new Intl.NumberFormat(this.opts.locale, { style: 'currency', currency: this.currency }).format(n);\n } catch {\n return `${n} ${this.currency}`;\n }\n }\n\n private syncPrices(): void {\n const doc = this.controller.doc;\n if (!doc || !this.els.prices) return;\n const left = this.controller.categoryAvailability();\n this.els.prices.innerHTML = doc.categories\n .map((c) => {\n const price = c.tiers?.length ? c.tiers[0].price : c.price;\n return (\n `<div class=\"sl-price-row\"><span class=\"sl-dot\" style=\"background:${c.color}\"></span>` +\n `<span class=\"sl-price-label\">${c.label}</span>` +\n `<span class=\"sl-price-left\">${left[c.key] ?? 0} left</span>` +\n (price != null ? `<span class=\"sl-price-amt\">${this.money(price)}</span>` : '') +\n `</div>`\n );\n })\n .join('');\n }\n\n /** A live delta took one of OUR selected (not yet held) seats — evict + tell the buyer. */\n private evictTakenSelections(): void {\n // Our own hold's WS echo paints our seats 'held' — never treat those as sniped.\n const ownLabels = new Set<string>(this.controller.currentHold()?.labels ?? []);\n const gone = this.controller\n .getSelection()\n .filter((s) => !ownLabels.has(s.label) && (this.controller.getStatus(s.id) ?? 'free') !== 'free');\n if (!gone.length) return;\n this.controller.deselect(gone.map((s) => s.id));\n this.toast(`Seat ${gone[0].label} was just taken by another buyer.`);\n }\n\n private syncTray(): void {\n if (!this.els.tray) return;\n const seats = this.controller.getSelection();\n const gaAreas = this.controller.getGAAreas();\n const parts: string[] = [];\n\n if (!seats.length && !gaAreas.length) {\n parts.push(`<div class=\"sl-tray-hint\">Tap a seat on the map, or let us pick the best available for you.</div>`);\n } else if (!seats.length) {\n parts.push(`<div class=\"sl-tray-hint\">Tap a seat on the map — or grab standing tickets below.</div>`);\n }\n\n for (const s of seats) {\n const cat = this.controller.doc?.categories.find((c) => c.key === s.categoryKey);\n parts.push(\n `<div class=\"sl-chip\" data-seat=\"${s.id}\"><b>${s.label}</b>` +\n `<span class=\"cat\">${cat?.label ?? s.categoryKey}</span>` +\n `<span class=\"amt\">${this.money(s.price)}</span>` +\n `<button type=\"button\" class=\"rm\" aria-label=\"Remove ${s.label}\">` +\n `<svg viewBox=\"0 0 24 24\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>` +\n `</button></div>`,\n );\n }\n\n for (const area of gaAreas) {\n const qty = this.gaQty.get(area.id) ?? 0;\n parts.push(\n `<div class=\"sl-ga\" data-ga=\"${area.id}\"><div class=\"sl-ga-info\">` +\n `<div class=\"sl-ga-name\">${area.label}</div>` +\n `<div class=\"sl-ga-sub\">${this.money(area.price)} · ${area.available} left</div></div>` +\n `<div class=\"sl-ga-qty\">` +\n `<button type=\"button\" data-d=\"-1\" aria-label=\"Fewer\">−</button><span>${qty}</span>` +\n `<button type=\"button\" data-d=\"1\" aria-label=\"More\">+</button></div></div>`,\n );\n }\n\n this.els.tray.innerHTML = parts.join('');\n this.els.tray.querySelectorAll<HTMLElement>('.sl-chip .rm').forEach((btn) => {\n btn.addEventListener('click', () => {\n const id = (btn.closest('.sl-chip') as HTMLElement).dataset.seat!;\n this.controller.deselect([id]);\n });\n });\n this.els.tray.querySelectorAll<HTMLElement>('.sl-ga button').forEach((btn) => {\n btn.addEventListener('click', () => {\n const areaEl = btn.closest('.sl-ga') as HTMLElement;\n const id = areaEl.dataset.ga!;\n const area = gaAreas.find((a) => a.id === id);\n const next = Math.max(0, Math.min(area?.available ?? 0, (this.gaQty.get(id) ?? 0) + Number(btn.dataset.d)));\n this.gaQty.set(id, next);\n this.syncTray();\n });\n });\n\n // totals + CTA\n const gaTotal = gaAreas.reduce((sum, a) => sum + a.price * (this.gaQty.get(a.id) ?? 0), 0);\n const gaCount = [...this.gaQty.values()].reduce((a, b) => a + b, 0);\n const total = seats.reduce((sum, s) => sum + s.price, 0) + gaTotal;\n const count = seats.length + gaCount;\n this.els.count.textContent = count\n ? `${count} ${count === 1 ? 'ticket' : 'tickets'}`\n : 'No seats selected';\n this.els.total.textContent = count ? this.money(total) : '';\n const cta = this.els.cta as HTMLButtonElement;\n cta.disabled = count === 0;\n cta.textContent = count ? 'Hold seats & checkout' : 'Select seats';\n this.opts.onSelectionChange?.(seats);\n }\n\n private async handleCta(): Promise<void> {\n const cta = this.els.cta as HTMLButtonElement;\n cta.disabled = true;\n cta.textContent = 'Holding…';\n try {\n // seats first (controller.hold covers selected seats); GA quantities ride along\n let hold: HoldResult | null = null;\n const gaEntries = [...this.gaQty.entries()].filter(([, q]) => q > 0);\n // Snapshot before hold — the hold's own WS echo repaints these seats.\n const chosenSeats = this.controller.getSelection();\n if (chosenSeats.length) {\n const h = await this.controller.hold(undefined, this.opts.holdTtlMs);\n hold = h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : null;\n }\n for (const [areaId, qty] of gaEntries) {\n const h = await this.controller.holdGA(areaId, qty, { ttlMs: this.opts.holdTtlMs });\n hold = h ? { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items } : hold;\n }\n if (!hold) {\n this.toast('One or more seats were just taken. Please pick again.');\n this.syncTray();\n return;\n }\n this.hold = hold;\n this.startHoldTimer(hold.expiresAt);\n this.opts.onCheckout?.(hold, chosenSeats);\n } catch (err) {\n this.opts.onError?.(err);\n this.toast('One or more seats were just taken. Please pick again.');\n } finally {\n this.syncTray();\n }\n }\n\n private startHoldTimer(expiresAt: number): void {\n this.stopHoldTimer();\n const pill = this.els.hold;\n const tick = (): void => {\n const ms = Math.max(0, expiresAt - Date.now());\n const m = Math.floor(ms / 60000);\n const s = String(Math.floor((ms % 60000) / 1000)).padStart(2, '0');\n pill.textContent = `Held ${m}:${s}`;\n pill.classList.add('on');\n if (ms <= 0) this.stopHoldTimer();\n };\n tick();\n this.holdTimer = setInterval(tick, 500);\n }\n\n private stopHoldTimer(): void {\n if (this.holdTimer) clearInterval(this.holdTimer);\n this.holdTimer = null;\n this.els.hold?.classList.remove('on');\n }\n\n private toast(msg: string): void {\n const el = this.els.toast;\n if (!el) return;\n el.textContent = msg;\n el.classList.add('on');\n if (this.toastTimer) clearTimeout(this.toastTimer);\n this.toastTimer = setTimeout(() => el.classList.remove('on'), 4200);\n }\n\n private placeTooltip(): void {\n if (!this.tipEl) return;\n const hw = this.els.map.clientWidth;\n const tw = this.tipEl.offsetWidth;\n const th = this.tipEl.offsetHeight;\n let x = this.tipPos.x + 14;\n let y = this.tipPos.y - th - 12;\n if (x + tw > hw - 8) x = this.tipPos.x - tw - 14;\n if (y < 8) y = this.tipPos.y + 18;\n this.tipEl.style.left = `${Math.max(8, x)}px`;\n this.tipEl.style.top = `${Math.max(8, y)}px`;\n }\n\n private updateTooltip(details: SeatHoverDetails | null): void {\n if (!this.tipEl) return;\n if (!details) {\n this.tipEl.style.display = 'none';\n return;\n }\n const statusLine =\n details.status === 'free'\n ? ''\n : `<div style=\"margin-top:5px;font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;font-weight:700\">${\n details.status === 'held' ? t('map.statusHeld') : t('map.statusTaken')\n }</div>`;\n this.tipEl.innerHTML =\n `<div style=\"font-weight:800;font-size:13px\">${details.label}</div>` +\n `<div style=\"display:flex;align-items:center;gap:6px;margin-top:4px\">` +\n `<span style=\"width:9px;height:9px;border-radius:50%;flex:none;background:${details.categoryColor}\"></span>` +\n `<span style=\"opacity:.75\">${details.categoryLabel}</span>` +\n `<span style=\"margin-left:auto;font-weight:800\">${this.money(details.price)}</span></div>` +\n statusLine;\n this.tipEl.style.display = 'block';\n this.placeTooltip();\n }\n\n // ---- public conveniences ----------------------------------------------------\n\n getSelection(): PickerSeat[] {\n return this.controller.getSelection();\n }\n\n async bestAvailable(qty: number, categoryKey?: string): Promise<HoldResult | null> {\n try {\n const h = await this.controller.bestAvailable(qty, categoryKey);\n if (h) {\n this.hold = { holdId: h.holdId, expiresAt: h.expiresAt, seats: h.seats, items: h.items };\n this.startHoldTimer(h.expiresAt);\n this.syncTray();\n return this.hold;\n }\n return null;\n } catch (err) {\n this.opts.onError?.(err);\n return null;\n }\n }\n\n async release(): Promise<void> {\n await this.controller.release();\n this.hold = null;\n this.stopHoldTimer();\n this.gaQty.clear();\n this.syncTray();\n }\n\n destroy(): void {\n this.destroyed = true;\n this.stopHoldTimer();\n if (this.toastTimer) clearTimeout(this.toastTimer);\n this.ro?.disconnect();\n this.ro = null;\n if (this.escHandler) document.removeEventListener('keydown', this.escHandler);\n this.controller.destroy();\n this.root?.remove();\n this.root = null;\n if (this.modalScrim) {\n this.modalScrim.remove();\n this.modalScrim = null;\n (this.prevFocus as HTMLElement | null)?.focus?.();\n }\n }\n}\n"],"mappings":"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","names":["resolveContainer","PickerController","loadLocale","setStringOverrides","t","DEFAULT_API_BASE","DEFAULT_MAX_SELECTION","resolveContainer","PickerController","t","loadLocale","setStringOverrides"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seatlayer/js",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "The SeatLayer embed SDK — render an interactive seat picker and hold seats from the browser. Works in any JS framework.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://docs.seatlayer.io",
@@ -35,7 +35,7 @@
35
35
  "reserved-seating"
36
36
  ],
37
37
  "dependencies": {
38
- "@seatlayer/core": "^0.5.0"
38
+ "@seatlayer/core": "^0.6.0"
39
39
  },
40
40
  "devDependencies": {
41
41
  "tsup": "^8.5.1",