@seatlayer/js 0.18.0 → 0.19.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.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { PickerSeat, SeatHoverDetails, ChartDoc, ChartTheme, ExpandedSeat } from '@seatlayer/core';
1
+ import { PickerSeat, SeatHoverDetails, PickerTransport, ChartDoc, AvailabilityRule, ChartTheme, ExpandedSeat } from '@seatlayer/core';
2
2
  export { ExpandedSeat, SeatHoverDetails } from '@seatlayer/core';
3
3
 
4
4
  /**
@@ -254,6 +254,12 @@ interface EmbeddedDesignerOptions {
254
254
  * Only used when `showLoadingState` is enabled.
255
255
  */
256
256
  loadingTimeoutMs?: number;
257
+ /**
258
+ * Auto-grow the iframe to the height the Designer reports over the resize
259
+ * protocol (`seatlayer.designer.resize`). Defaults to `true`. Set `false` when
260
+ * the host sizes the iframe itself (e.g. a fixed-height chrome).
261
+ */
262
+ autoResize?: boolean;
257
263
  /**
258
264
  * Called when the user presses "Try again" on the error card. Use it to mint a
259
265
  * fresh Designer session and call `setDesignerUrl()` with the new URL, which
@@ -276,6 +282,13 @@ declare class EmbeddedDesigner {
276
282
  private timeoutTimer;
277
283
  private phase;
278
284
  private restoreContainerPosition;
285
+ private pinned;
286
+ private frameStyleBeforeFs;
287
+ private docOverflowBeforeFs;
288
+ private bodyOverflowBeforeFs;
289
+ private fsKeyHandler;
290
+ /** Latest height (px string) the Designer reported; re-applied after unpin. */
291
+ private lastAutoHeight;
279
292
  constructor(options: EmbeddedDesignerOptions);
280
293
  mount(): HTMLIFrameElement;
281
294
  /** Replace the iframe instead of assigning a new fragment to an existing one. */
@@ -283,6 +296,15 @@ declare class EmbeddedDesigner {
283
296
  getIframe(): HTMLIFrameElement | null;
284
297
  destroy(): void;
285
298
  private loadingStateEnabled;
299
+ private autoResizeEnabled;
300
+ /**
301
+ * Pin the iframe over the host page as a viewport-filling overlay. We save the
302
+ * iframe's inline style and the document scroll state so `unpinFullscreen`
303
+ * restores everything exactly. Escape (host-side) also exits.
304
+ */
305
+ private pinFullscreen;
306
+ /** Undo `pinFullscreen`: restore the iframe style + scroll lock. Idempotent. */
307
+ private unpinFullscreen;
286
308
  private clearTimeoutTimer;
287
309
  private ensureContainerPositioned;
288
310
  private restoreContainerStyle;
@@ -354,6 +376,16 @@ interface CheckoutHandoff {
354
376
  /** Convenience total in major units (Σ unitPrice × quantity). */
355
377
  total: number;
356
378
  }
379
+ /** Host-authoritative pricing — see {@link SeatPickerOptions.pricing}. */
380
+ interface SeatPickerPricing {
381
+ /** Unit prices by category key: a flat number, or `{ base, tiers: { tierId: price } }`. */
382
+ prices?: Record<string, number | {
383
+ base?: number;
384
+ tiers?: Record<string, number>;
385
+ }>;
386
+ /** Custom money renderer (e.g. `(n) => n + '€'`). Defaults to Intl currency formatting. */
387
+ formatter?: (amount: number, currency: string) => string;
388
+ }
357
389
  /** Host theme overrides — any subset; unset keys fall back to the org's chart theme, then defaults. */
358
390
  interface SeatPickerTheme {
359
391
  /** Brand accent (CTA, active chips, hold pill). */
@@ -386,6 +418,12 @@ interface SeatPickerOptions {
386
418
  event: string;
387
419
  /** API origin. Defaults to https://api.seatlayer.io. */
388
420
  apiBase?: string;
421
+ /**
422
+ * Custom data transport. Defaults to the CORS-trivial PubApi against
423
+ * `apiBase`. Inject to run the widget against another backend adapter (the
424
+ * SeatLayer dashboard's own transport) or a fully local mock (demos).
425
+ */
426
+ transport?: PickerTransport;
389
427
  /** Reserved for future authenticated rendering. */
390
428
  publicKey?: string;
391
429
  /** Max seats selectable at once (default 10). */
@@ -398,8 +436,23 @@ interface SeatPickerOptions {
398
436
  currency?: string;
399
437
  /** Colorblind-safe rendering (Okabe-Ito palette, hollow booked seats). */
400
438
  colorblindSafe?: boolean;
439
+ /**
440
+ * Hide the "Powered by SeatLayer" attribution badge in the side panel foot.
441
+ * The chart theme's own `hideBadge` flag (paid orgs) also hides it — the badge
442
+ * is shown only when BOTH this option and the theme flag are unset/false.
443
+ */
444
+ hideBadge?: boolean;
401
445
  /** Host theme overrides — see SeatPickerTheme. */
402
446
  theme?: SeatPickerTheme;
447
+ /**
448
+ * Host-authoritative pricing. When your shop charges different prices than
449
+ * the chart's stored category prices, pass them here so the buyer sees the
450
+ * price they will actually pay — on the map tooltip, confirm popover, price
451
+ * panel, tray, totals, and in the checkout handoff's line items. Keyed by
452
+ * category key; per-tier overrides nest under `tiers`. Unlisted categories
453
+ * fall back to the chart price.
454
+ */
455
+ pricing?: SeatPickerPricing;
403
456
  /** Hold TTL in ms passed to hold(); server clamps to its own limits. */
404
457
  holdTtlMs?: number;
405
458
  /**
@@ -491,23 +544,27 @@ declare class SeatPicker {
491
544
  private confirmEl;
492
545
  private confirmSeat;
493
546
  private srEl;
494
- private a11yFilter;
495
547
  private baQty;
496
548
  private baCat;
497
549
  private bestAvailableConfirm;
498
550
  private releasingHold;
551
+ /** Event sales window is closed (read-only load state / live close). */
552
+ private salesClosed;
553
+ /** Every seated category's live availability is 0 (sold-out overlay is up). */
554
+ private soldOut;
555
+ private soldoutEl;
556
+ /** Resolved colorblind-safe state — stored preference wins over the option. */
557
+ private cbSafe;
499
558
  private rungsEl;
500
559
  private floorsEl;
501
560
  private secCardEl;
502
561
  private viewEl;
503
562
  private viewCleanup;
504
563
  private allSeatsCache;
505
- private miniEl;
506
564
  private miniCanvas;
507
565
  private miniBase;
508
566
  private miniTf;
509
567
  private priceBandKeys;
510
- private priceFilterEl;
511
568
  /** Last surfaced section summary (re-rendered when the price band changes). */
512
569
  private lastSection;
513
570
  /** Section card collapsed to its slim pill (seat-picking has begun). */
@@ -526,6 +583,55 @@ declare class SeatPicker {
526
583
  private holdingLabels;
527
584
  private ctaPhase;
528
585
  private a11yChipsEl;
586
+ private fsFallback;
587
+ private fsChangeHandler;
588
+ private fsEscHandler;
589
+ /** True once we've asked the host page to pin us fullscreen (framed, no native). */
590
+ private framedFs;
591
+ /** Last height (px) posted to a host frame; dedupes redundant reports. */
592
+ private lastPostedHeight;
593
+ /**
594
+ * Eager sightline preview for the confirm card: a cheap generated forward
595
+ * view (or the organizer's real photo) plus a "Nm to stage · clear
596
+ * sightline" line — the premium at-a-glance moment; click opens the 360.
597
+ */
598
+ private confirmThumbHtml;
599
+ /** True when the picker is rendered inside an iframe (snippet embed at /e/:key). */
600
+ private isFramed;
601
+ /**
602
+ * Post a widget→host message when framed. targetOrigin is '*' because the
603
+ * payload carries nothing sensitive (a height number / a fullscreen flag);
604
+ * hosts verify `event.origin` on their side (see `attachPickerFrame`).
605
+ */
606
+ private postToHost;
607
+ /**
608
+ * Height (px) to advertise to a host frame.
609
+ *
610
+ * The picker fills whatever box it's given: `.sl-picker` is `height:100%;
611
+ * overflow:hidden`, and the /e/:key shell mounts it `position:fixed; inset:0`.
612
+ * So it has no intrinsic *document* height to read — `scrollHeight` just
613
+ * collapses to the current viewport, which for a framed embed would echo the
614
+ * host's own iframe height straight back (a circular value). We therefore
615
+ * report a width-driven *desired* height: a pleasant landscape box on desktop,
616
+ * taller on narrow widths where the bottom sheet needs room, clamped to the
617
+ * widget's `min-height` of 420. Width is host-controlled and never moves in
618
+ * response to the height we report, so this cannot feedback-loop.
619
+ */
620
+ private measureFramedHeight;
621
+ /** Post `seatlayer:height` to the host when framed and the value changed. */
622
+ private reportFramedHeight;
623
+ /** Full screen via the native API, falling back to a fixed-position overlay (iOS Safari). */
624
+ private toggleFullscreen;
625
+ /**
626
+ * Native element-fullscreen was unavailable or rejected. When framed, a CSS
627
+ * `.sl-fs` overlay can't escape the iframe, so we ask the host page to pin us
628
+ * (`seatlayer:fullscreen`). Otherwise (iOS Safari, same document) fall back to
629
+ * the `.sl-fs` overlay as before.
630
+ */
631
+ private enterFsFallback;
632
+ /** Toggle host-driven (framed) fullscreen: post the flag + own the Esc key. */
633
+ private setFramedFs;
634
+ private setFsFallback;
529
635
  private cbEl;
530
636
  private modalScrim;
531
637
  private prevFocus;
@@ -553,6 +659,41 @@ declare class SeatPicker {
553
659
  private buildExtendPrompt;
554
660
  /** Success overlay + onBooked fire when the held seats settle to booked. */
555
661
  private buildBookedOverlay;
662
+ /**
663
+ * Localized string with a literal fallback. `t()` returns the key itself for
664
+ * unknown keys, so this collapses that to `fallback` — while still honoring a
665
+ * host `messages` override (which makes `t()` return the override, not the key).
666
+ */
667
+ private tf;
668
+ /** Sold-out overlay — centered over the map, disabled waitlist stub (Gap 2). */
669
+ private buildSoldoutOverlay;
670
+ /**
671
+ * Recompute the sold-out state on every price/availability sync. Sold-out ⇔
672
+ * every SEATED category's live free count is 0. Suppressed when the chart has
673
+ * GA areas (GA capacity isn't per-seat, so seated counts would read 0 and
674
+ * falsely block standing room) — mirrors the public page. Clears live when WS
675
+ * frees a seat up.
676
+ */
677
+ private syncSoldout;
678
+ /**
679
+ * Pure sold-out predicate: every SEATED category's free count is 0, there is at
680
+ * least one seated category, and there are no GA areas (GA capacity isn't
681
+ * per-seat, so seated counts read 0 and would falsely block standing room).
682
+ * `left` is seeded implicitly — a missing key means a fully-booked tier (0 free).
683
+ */
684
+ private isSoldOut;
685
+ /**
686
+ * Sales-closed read-only state (Gap 3): persistent header pill, disabled CTA
687
+ * with a closed label, and frozen best-available / GA controls. `setSalesClosed`
688
+ * is the reactive entry (live 409 event_closed); `applySalesClosed` is the
689
+ * idempotent DOM apply used at load and on transition.
690
+ */
691
+ private setSalesClosed;
692
+ private applySalesClosed;
693
+ /** The badge is hidden when the host opts out OR the org's theme sets hideBadge. */
694
+ private badgeHidden;
695
+ /** Attribution badge in the side-panel foot (Gap 7). Hidden per host/theme. */
696
+ private buildBadge;
556
697
  /**
557
698
  * Create the positioned flex containers that own every persistent map overlay.
558
699
  * Appended once after controller.render(); each chrome piece is then appended
@@ -608,7 +749,7 @@ declare class SeatPicker {
608
749
  private drawMinimapRect;
609
750
  /** Minimap click → focus the section under the point (or overview on a miss). */
610
751
  private minimapJump;
611
- /** Effective price of a category (first tier when tiered, else base price). */
752
+ /** Effective display price of a category: host pricing override → first tier base. */
612
753
  private catPrice;
613
754
  /** Derive price bands: one chip per distinct price (≤5), else quantile ranges. */
614
755
  private priceBands;
@@ -659,7 +800,22 @@ declare class SeatPicker {
659
800
  private openSeatView;
660
801
  private closeSeatView;
661
802
  private money;
803
+ /**
804
+ * The price the buyer will actually pay for a category (+tier): the host's
805
+ * `pricing` override when present, else the chart's stored price. Every
806
+ * price the widget DISPLAYS or hands off must flow through here — a map
807
+ * that shows one price while checkout charges another destroys trust.
808
+ */
809
+ private paidPrice;
662
810
  private syncPrices;
811
+ /**
812
+ * Live-activity strip: turn WS availability deltas into one quiet line of
813
+ * social proof ("2 seats just taken in VIP · 118 left"). Diffs per-category
814
+ * counts on every status change — no per-seat payload needed. Skips the very
815
+ * first computation (initial load is not "activity").
816
+ */
817
+ private narrateAvailability;
818
+ private lastCatAvail;
663
819
  /** A live delta took one of OUR selected (not yet held) seats — evict + tell the buyer. */
664
820
  private evictTakenSelections;
665
821
  private syncTray;
@@ -686,6 +842,15 @@ declare class SeatPicker {
686
842
  private emitHoldChange;
687
843
  private toast;
688
844
  private placeTooltip;
845
+ /**
846
+ * Row label without the redundant section prefix. Charts commonly name row
847
+ * objects "104-A" while the Section column already shows "104" — so the Row
848
+ * cell repeats the section and, in the compact hover card, truncates to
849
+ * "10…". Strip a leading "<section><sep>" so Row reads a clean "A". Only when
850
+ * the prefix is exact (won't touch "1040-A" under section "104"); otherwise
851
+ * the label is shown verbatim.
852
+ */
853
+ private rowShort;
689
854
  private updateTooltip;
690
855
  getSelection(): PickerSeat[];
691
856
  /** Current active/restored hold reflected in the tray. */
@@ -699,6 +864,45 @@ declare class SeatPicker {
699
864
  destroy(): void;
700
865
  }
701
866
 
867
+ /**
868
+ * Host-side helper for embedding the SeatLayer picker as an iframe.
869
+ *
870
+ * The picker (the /e/:key page, mounted `position:fixed; inset:0`) reports its
871
+ * desired height and fullscreen intent to whatever page frames it, using the
872
+ * picker wire contract:
873
+ *
874
+ * • `{ type: 'seatlayer:height', px:number }` — grow the iframe to `px`.
875
+ * • `{ type: 'seatlayer:fullscreen', on:boolean }` — pin/unpin over the host.
876
+ *
877
+ * A framed picker cannot escape its own iframe with CSS, so it delegates both
878
+ * concerns to the host. `attachPickerFrame` wires those two behaviours onto a
879
+ * picker iframe and returns a detach function that tears everything back down.
880
+ */
881
+ interface AttachPickerFrameOptions {
882
+ /**
883
+ * Origin to accept messages from. Defaults to the origin parsed from
884
+ * `iframe.src`. Messages from any other origin (or any other window) are
885
+ * ignored — the picker posts with `targetOrigin:'*'`, so the host is the side
886
+ * that must verify `event.origin`.
887
+ */
888
+ origin?: string;
889
+ }
890
+ /**
891
+ * Attach the picker resize + fullscreen protocol to a picker iframe.
892
+ *
893
+ * ```ts
894
+ * const iframe = document.querySelector('iframe#seatlayer')!;
895
+ * const detach = attachPickerFrame(iframe);
896
+ * // …later, when removing the embed:
897
+ * detach();
898
+ * ```
899
+ *
900
+ * @param iframe The `<iframe>` element pointing at a SeatLayer picker embed.
901
+ * @param opts Optional `{ origin }` override for the accepted message origin.
902
+ * @returns A detach function: removes the listener and restores any pinned state.
903
+ */
904
+ declare function attachPickerFrame(iframe: HTMLIFrameElement, opts?: AttachPickerFrameOptions): () => void;
905
+
702
906
  /**
703
907
  * Organizer manage-surface client for workers/api (the `/v1/events/:key/*`
704
908
  * inventory routes + the public realtime channel). Companion to api.ts (the
@@ -900,6 +1104,22 @@ declare class ManageApi {
900
1104
  ok: true;
901
1105
  holdTtlMs: number | null;
902
1106
  }>;
1107
+ /** The organizer's current per section/zone availability windows (needs
1108
+ * `event:view`). Ids absent from `rules` are open / on sale. */
1109
+ availability(key: string): Promise<{
1110
+ rules: Record<string, AvailabilityRule>;
1111
+ }>;
1112
+ /** Replace the availability windows for a set of section/zone ids (needs
1113
+ * `event:block`). Ids absent from `rules` become open / on sale; a zone rule
1114
+ * cascades to its sections. The worker derives each id's seat labels, so
1115
+ * `labels` on the sent rules is best-effort. Resolves with the authoritative
1116
+ * effective `hidden` set (a due rule may fire at once) and the server-cleaned
1117
+ * `rules` map (fired timed/threshold windows dropped). */
1118
+ setAvailability(key: string, rules: Record<string, AvailabilityRule>): Promise<{
1119
+ ok: true;
1120
+ hidden: string[];
1121
+ rules: Record<string, AvailabilityRule>;
1122
+ }>;
903
1123
  report(key: string): Promise<ReportResult>;
904
1124
  controlRoom(key: string, windowMinutes?: number): Promise<ControlRoomSnapshot>;
905
1125
  log(key: string, opts?: {
@@ -933,7 +1153,7 @@ declare class ManageApi {
933
1153
  * {@link ManageApi}. Box office + Sections + full Reports UI are M2/M3.
934
1154
  */
935
1155
 
936
- type SeatManagerMode = 'view' | 'inspect' | 'block';
1156
+ type SeatManagerMode = 'view' | 'inspect' | 'block' | 'sections';
937
1157
  /** DO seat status — 'blocked' has no engine analogue (→ 'not_for_sale'). */
938
1158
  type DoStatus = 'free' | 'held' | 'booked' | 'blocked';
939
1159
  /** Live KPI snapshot pushed to `onTallies` on every state change. */
@@ -1073,6 +1293,11 @@ declare class SeatManager {
1073
1293
  private tokenRefreshInFlight;
1074
1294
  private sectionByObject;
1075
1295
  private sectionLabelById;
1296
+ private sectionsBase;
1297
+ private availabilityRules;
1298
+ private effectiveHidden;
1299
+ private effectiveClosed;
1300
+ private availabilitySaving;
1076
1301
  private lastSyncedAt;
1077
1302
  private blockedQuery;
1078
1303
  private blockedSection;
@@ -1178,6 +1403,36 @@ declare class SeatManager {
1178
1403
  private paintMonitorInsights;
1179
1404
  private applyHeatOverlay;
1180
1405
  private renderInspectRail;
1406
+ /** Pull the organizer's availability rules (event:view). Called on load and on
1407
+ * every WS (re)connect, mirroring how the other panels re-hydrate. `closed` is
1408
+ * deterministic from the rules; `hidden` (which folds in already-due timed /
1409
+ * threshold windows) comes from the snapshot + WS effective set. */
1410
+ private refreshAvailability;
1411
+ /** Run a token-authed op; on a 401 re-mint via onTokenRefresh and retry once. */
1412
+ private withAuthRetry;
1413
+ private closedIdsFromRules;
1414
+ /** Adopt a new effective hidden/closed set (from a snapshot or WS broadcast) and
1415
+ * repaint the rail + canvas when it actually moves. */
1416
+ private updateEffectiveAvailability;
1417
+ /** Canvas read of the availability state: dim hidden sections to a whisper,
1418
+ * half-light closed sections, leave open sections normal. Only in Sections mode;
1419
+ * cleared in every other tool. */
1420
+ private applySectionCanvasTreatment;
1421
+ /** Zone-grouped render tree: each zone header then its sections (which follow the
1422
+ * zone window), then loose sections + the ungrouped bucket. Effective hidden /
1423
+ * closed come from the live sets, rules from the organizer map. */
1424
+ private buildSectionRows;
1425
+ private renderSectionsRail;
1426
+ private sectionRowHtml;
1427
+ private wireSectionRail;
1428
+ /** Change one row's availability mode. A zone rule subsumes its child section
1429
+ * rules, so those are dropped from the map (the zone window is the truth). */
1430
+ private setSectionMode;
1431
+ /** Edit a timed reveal time / threshold percent on an existing row rule. */
1432
+ private setSectionRulePatch;
1433
+ /** Optimistically adopt the new rules, then reconcile with the server-cleaned
1434
+ * map + effective hidden/closed sets. Rolls back the rules on failure. */
1435
+ private persistAvailability;
1181
1436
  private paintLegend;
1182
1437
  private paintFeed;
1183
1438
  private renderBlockRail;
@@ -1199,4 +1454,4 @@ declare class SeatManager {
1199
1454
  private fail;
1200
1455
  }
1201
1456
 
1202
- export { ApiError, type BestAvailableResult, type CheckoutHandoff, type CheckoutLineItem, type ControlRoomActivityEntry, type ControlRoomSectionMetric, type ControlRoomSnapshot, EmbeddedDesigner, type EmbeddedDesignerEventType, type EmbeddedDesignerMessage, type EmbeddedDesignerOptions, type GAAreaAvailability, type HoldConflict, type HoldLineItem, type HoldResult, type LogEntry, type LogPage, ManageApi, ManageApiError, type ReportByStatus, type ReportCategoryMeta, type ReportCategoryRow, type ReportResult, type ResumedHoldResult, SeatManager, type SeatManagerActionResult, type SeatManagerActivity, type SeatManagerMode, type SeatManagerOptions, type SeatManagerTallies, SeatPicker, type SeatPickerOptions, type SeatPickerTheme, SeatingChart, type SeatingChartOptions, type SelectedSeat };
1457
+ export { ApiError, type AttachPickerFrameOptions, type BestAvailableResult, type CheckoutHandoff, type CheckoutLineItem, type ControlRoomActivityEntry, type ControlRoomSectionMetric, type ControlRoomSnapshot, EmbeddedDesigner, type EmbeddedDesignerEventType, type EmbeddedDesignerMessage, type EmbeddedDesignerOptions, type GAAreaAvailability, type HoldConflict, type HoldLineItem, type HoldResult, type LogEntry, type LogPage, ManageApi, ManageApiError, type ReportByStatus, type ReportCategoryMeta, type ReportCategoryRow, type ReportResult, type ResumedHoldResult, SeatManager, type SeatManagerActionResult, type SeatManagerActivity, type SeatManagerMode, type SeatManagerOptions, type SeatManagerTallies, SeatPicker, type SeatPickerOptions, type SeatPickerTheme, SeatingChart, type SeatingChartOptions, type SelectedSeat, attachPickerFrame };