@seatlayer/core 0.10.1 → 0.11.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.cts CHANGED
@@ -383,6 +383,13 @@ interface RendererCallbacks {
383
383
  onDeckTap?: (floorId: string) => void;
384
384
  /** Fired after any pan/zoom/resize settles — re-anchor screen-space overlays. */
385
385
  onViewChange?: () => void;
386
+ /**
387
+ * Organizer manage-mode only (`manageMode` + `marqueeSelect`): fired on
388
+ * pointer-UP after a rubber-band marquee drag, or a ⌘A/Escape bulk shortcut,
389
+ * with the FULL current selection (selectable seats only). The host toolbar
390
+ * reads this to drive bulk block/unblock. Never fires when manageMode is off.
391
+ */
392
+ onMarquee?: (seats: ExpandedSeat[]) => void;
386
393
  }
387
394
  /** Far-zoom level-of-detail rung: whole zones → section blocks → individual seats. */
388
395
  type LodRung = 'zones' | 'sections' | 'seats';
@@ -402,6 +409,21 @@ interface RendererOptions extends RendererCallbacks {
402
409
  /** ISO 4217 currency for on-map prices ("FROM …"); defaults to money.DEFAULT_CURRENCY.
403
410
  * Locale for grouping/symbol placement comes from the active i18n locale. */
404
411
  currency?: string;
412
+ /**
413
+ * Organizer manage surface (SDK SeatManager). Opt-in — enables the manage-mode
414
+ * gestures (marquee, ⌘A/Escape) and the bulk-selection helpers. Buyer pan /
415
+ * pinch / tap and every existing code path are byte-identical when this is
416
+ * false (every manage branch is gated on it). Default false.
417
+ */
418
+ manageMode?: boolean;
419
+ /**
420
+ * When `manageMode` is on, a mouse/pen primary-button drag at the seats rung
421
+ * draws a rubber-band marquee that bulk-selects the seats it covers (emitting
422
+ * `onMarquee` on pointer-up) instead of panning. Touch keeps single-finger
423
+ * pan (pinch to zoom); a middle-button drag pans with a mouse. Disabled below
424
+ * the seats rung (zoom in first). No effect unless `manageMode` is also set.
425
+ */
426
+ marqueeSelect?: boolean;
405
427
  }
406
428
  interface ISeatmapRenderer {
407
429
  /** Replace the chart. Resets selection and statuses, zooms to fit.
@@ -411,9 +433,32 @@ interface ISeatmapRenderer {
411
433
  }): void;
412
434
  /** Bulk status update; re-renders affected seats only. */
413
435
  setStatus(seatIds: string[], status: SeatStatus): void;
436
+ /**
437
+ * SYNCHRONOUS repaint that bypasses requestAnimationFrame. Konva's batchDraw()
438
+ * (used by setStatus and friends) schedules the actual paint on the next rAF
439
+ * tick, which Chrome throttles/pauses on hidden, backgrounded, or occluded
440
+ * tabs — so a seat-status delta updates the scene graph but the pixels never
441
+ * change until the tab is foregrounded again. forceDraw() paints the affected
442
+ * layers immediately (Layer.draw() is synchronous) and flushes any pending
443
+ * cache-debounce, so a caller (visibilitychange catch-up, or an opted-in
444
+ * always-live board) can guarantee the canvas reflects current state
445
+ * regardless of tab visibility. No-op difference in the foreground.
446
+ */
447
+ forceDraw(): void;
414
448
  getStatus(seatId: string): SeatStatus;
415
449
  getSelection(): ExpandedSeat[];
416
450
  clearSelection(): void;
451
+ /**
452
+ * Manage-mode bulk selection helpers (no-op / empty unless `manageMode`).
453
+ * They select the matching SELECTABLE seats (respecting `selectableStatuses`
454
+ * + closed sections), union with the current selection, and return the seats
455
+ * they added — the SDK SeatManager expands category/row/section picks to
456
+ * labels and drives one batched block/unblock from them.
457
+ */
458
+ selectAllSelectable?(): ExpandedSeat[];
459
+ selectByLabels?(labels: string[]): ExpandedSeat[];
460
+ /** Selectable seats belonging to a section OR zone id (no selection side-effect). */
461
+ getSelectableInSection?(sectionId: string): ExpandedSeat[];
417
462
  /** Programmatic deselect of specific seats (e.g. chip × in the cart). */
418
463
  deselect(seatIds: string[]): void;
419
464
  /**
@@ -794,6 +839,13 @@ declare class SeatmapRenderer implements ISeatmapRenderer {
794
839
  private panLast;
795
840
  /** Cumulative gesture movement in px — clicks are suppressed after a real pan/pinch. */
796
841
  private moved;
842
+ /**
843
+ * Manage-mode rubber-band marquee (option-gated). `start`/`cur` are WORLD-space
844
+ * points (overlayLayer rides the stage transform); `rect` is the on-canvas
845
+ * selection band. Null except during an active manage-mode drag.
846
+ */
847
+ private marquee;
848
+ private marqueeCur;
797
849
  constructor(container: HTMLDivElement, options?: RendererOptions);
798
850
  setChart(doc: ChartDoc, opts?: {
799
851
  floorId?: string;
@@ -818,6 +870,30 @@ declare class SeatmapRenderer implements ISeatmapRenderer {
818
870
  getSelection(): ExpandedSeat[];
819
871
  clearSelection(): void;
820
872
  deselect(seatIds: string[]): void;
873
+ /** Select every selectable seat on the chart (⌘A). Returns the added seats. */
874
+ selectAllSelectable(): ExpandedSeat[];
875
+ /** Select the selectable seats matching these public labels (category/row/
876
+ * section bulk resolves to labels host-side). Returns the newly added seats. */
877
+ selectByLabels(labels: string[]): ExpandedSeat[];
878
+ /** Selectable seats in a section OR zone id — pure read (no selection change). */
879
+ getSelectableInSection(sectionId: string): ExpandedSeat[];
880
+ /**
881
+ * Union `ids` into the selection in one batched pass. Beyond MARQUEE_RING_CAP
882
+ * total selected we skip the per-seat ring nodes (fill paint still marks the
883
+ * seats) so a whole-arena select doesn't spawn thousands of Konva shapes.
884
+ * Returns the full current selection.
885
+ */
886
+ private selectMany;
887
+ private beginMarquee;
888
+ private updateMarquee;
889
+ private cancelMarquee;
890
+ /**
891
+ * Pointer-up: hit-test the marquee world-rect against the in-memory seat
892
+ * centres (NOT the Konva hit-graph — that's a cached bitmap when zoomed and
893
+ * far slower), keep only SELECTABLE seats, union them into the selection and
894
+ * fire `onMarquee`. A near-zero drag reads as a click: clear the selection.
895
+ */
896
+ private finishMarquee;
821
897
  flashSeat(seatId: string, color?: string): void;
822
898
  private onKeyDown;
823
899
  /** Nearest seat from `fromId` in a cardinal direction (aligned + close wins). */
@@ -1109,7 +1185,22 @@ declare class SeatmapRenderer implements ISeatmapRenderer {
1109
1185
  /** rAF-coalesced `onViewChange` — at most one host callback per animation frame. */
1110
1186
  private scheduleViewChange;
1111
1187
  private updateLOD;
1188
+ /** Rebuild the seat-layer bitmap synchronously (no paint). Shared by the
1189
+ * debounced cacheSeatLayer() and the synchronous forceDraw() catch-up. */
1190
+ private rebuildSeatCache;
1112
1191
  private cacheSeatLayer;
1192
+ /**
1193
+ * SYNCHRONOUS repaint that bypasses requestAnimationFrame — see the
1194
+ * ISeatmapRenderer.forceDraw() contract. Chrome pauses rAF (and therefore
1195
+ * Konva's batchDraw) on hidden/backgrounded/occluded tabs, so seat-status
1196
+ * deltas applied via setStatus() mutate the scene graph but never reach the
1197
+ * canvas until the tab is foregrounded. This flushes the cache-debounce and
1198
+ * paints every layer setStatus() can touch, immediately.
1199
+ *
1200
+ * Additive: the foreground path never calls this, so foreground behaviour is
1201
+ * byte-identical.
1202
+ */
1203
+ forceDraw(): void;
1113
1204
  private updateLabels;
1114
1205
  private handleResize;
1115
1206
  private startFpsLoop;
@@ -1280,6 +1371,18 @@ interface PickerOptions extends PickerCallbacks {
1280
1371
  flashOnLiveChange?: boolean;
1281
1372
  /** Start in colorblind-safe rendering (Okabe-Ito hues + hollow booked seats). */
1282
1373
  colorblindSafe?: boolean;
1374
+ /**
1375
+ * Keep painting seat-status deltas even while the tab is hidden/backgrounded.
1376
+ *
1377
+ * Default FALSE — the buyer widget stays efficient: it lets rAF stay paused
1378
+ * while hidden and does a single synchronous catch-up repaint on regain (the
1379
+ * visibilitychange handler resnapshots + forceDraw()s). Set TRUE only for an
1380
+ * always-live surface — the future organizer control-room board — where a
1381
+ * backgrounded monitor must keep repainting; then each delta calls
1382
+ * renderer.forceDraw() when the tab is hidden. Purely a paint hint; enforcement
1383
+ * and the WS protocol are identical either way.
1384
+ */
1385
+ keepLiveWhileHidden?: boolean;
1283
1386
  }
1284
1387
  declare class PickerController {
1285
1388
  private readonly opts;
@@ -1305,6 +1408,10 @@ declare class PickerController {
1305
1408
  private reconnectTimer;
1306
1409
  private attempt;
1307
1410
  private closed;
1411
+ /** Bound visibilitychange listener (buyer catch-up on tab regain). Kept on the
1412
+ * instance so destroy() can detach it; null when not attached (guards double
1413
+ * mounts / non-DOM environments). */
1414
+ private onVisibilityChange;
1308
1415
  private hold_;
1309
1416
  private liveStatuses;
1310
1417
  private currency;
@@ -1498,6 +1605,19 @@ declare class PickerController {
1498
1605
  private applySeatsMap;
1499
1606
  private clearBookedHoldIfSettled;
1500
1607
  private resnapshot;
1608
+ /**
1609
+ * Buyer catch-up on tab regain. While a tab is hidden Chrome pauses rAF, so
1610
+ * seat-status deltas that arrived over the WS mutated the scene graph but the
1611
+ * canvas colors never repainted. When the tab becomes visible again we (1)
1612
+ * resnapshot to pull authoritative state for anything the socket may have
1613
+ * missed while backgrounded, then (2) forceDraw() a synchronous repaint so the
1614
+ * seat colors are correct immediately rather than on the next incidental draw.
1615
+ *
1616
+ * Attached once per mount; guarded against double-attach and non-DOM
1617
+ * environments; detached in destroy() (no leaks).
1618
+ */
1619
+ private attachVisibilityListener;
1620
+ private detachVisibilityListener;
1501
1621
  private connect;
1502
1622
  private scheduleReconnect;
1503
1623
  }
package/dist/index.d.ts CHANGED
@@ -383,6 +383,13 @@ interface RendererCallbacks {
383
383
  onDeckTap?: (floorId: string) => void;
384
384
  /** Fired after any pan/zoom/resize settles — re-anchor screen-space overlays. */
385
385
  onViewChange?: () => void;
386
+ /**
387
+ * Organizer manage-mode only (`manageMode` + `marqueeSelect`): fired on
388
+ * pointer-UP after a rubber-band marquee drag, or a ⌘A/Escape bulk shortcut,
389
+ * with the FULL current selection (selectable seats only). The host toolbar
390
+ * reads this to drive bulk block/unblock. Never fires when manageMode is off.
391
+ */
392
+ onMarquee?: (seats: ExpandedSeat[]) => void;
386
393
  }
387
394
  /** Far-zoom level-of-detail rung: whole zones → section blocks → individual seats. */
388
395
  type LodRung = 'zones' | 'sections' | 'seats';
@@ -402,6 +409,21 @@ interface RendererOptions extends RendererCallbacks {
402
409
  /** ISO 4217 currency for on-map prices ("FROM …"); defaults to money.DEFAULT_CURRENCY.
403
410
  * Locale for grouping/symbol placement comes from the active i18n locale. */
404
411
  currency?: string;
412
+ /**
413
+ * Organizer manage surface (SDK SeatManager). Opt-in — enables the manage-mode
414
+ * gestures (marquee, ⌘A/Escape) and the bulk-selection helpers. Buyer pan /
415
+ * pinch / tap and every existing code path are byte-identical when this is
416
+ * false (every manage branch is gated on it). Default false.
417
+ */
418
+ manageMode?: boolean;
419
+ /**
420
+ * When `manageMode` is on, a mouse/pen primary-button drag at the seats rung
421
+ * draws a rubber-band marquee that bulk-selects the seats it covers (emitting
422
+ * `onMarquee` on pointer-up) instead of panning. Touch keeps single-finger
423
+ * pan (pinch to zoom); a middle-button drag pans with a mouse. Disabled below
424
+ * the seats rung (zoom in first). No effect unless `manageMode` is also set.
425
+ */
426
+ marqueeSelect?: boolean;
405
427
  }
406
428
  interface ISeatmapRenderer {
407
429
  /** Replace the chart. Resets selection and statuses, zooms to fit.
@@ -411,9 +433,32 @@ interface ISeatmapRenderer {
411
433
  }): void;
412
434
  /** Bulk status update; re-renders affected seats only. */
413
435
  setStatus(seatIds: string[], status: SeatStatus): void;
436
+ /**
437
+ * SYNCHRONOUS repaint that bypasses requestAnimationFrame. Konva's batchDraw()
438
+ * (used by setStatus and friends) schedules the actual paint on the next rAF
439
+ * tick, which Chrome throttles/pauses on hidden, backgrounded, or occluded
440
+ * tabs — so a seat-status delta updates the scene graph but the pixels never
441
+ * change until the tab is foregrounded again. forceDraw() paints the affected
442
+ * layers immediately (Layer.draw() is synchronous) and flushes any pending
443
+ * cache-debounce, so a caller (visibilitychange catch-up, or an opted-in
444
+ * always-live board) can guarantee the canvas reflects current state
445
+ * regardless of tab visibility. No-op difference in the foreground.
446
+ */
447
+ forceDraw(): void;
414
448
  getStatus(seatId: string): SeatStatus;
415
449
  getSelection(): ExpandedSeat[];
416
450
  clearSelection(): void;
451
+ /**
452
+ * Manage-mode bulk selection helpers (no-op / empty unless `manageMode`).
453
+ * They select the matching SELECTABLE seats (respecting `selectableStatuses`
454
+ * + closed sections), union with the current selection, and return the seats
455
+ * they added — the SDK SeatManager expands category/row/section picks to
456
+ * labels and drives one batched block/unblock from them.
457
+ */
458
+ selectAllSelectable?(): ExpandedSeat[];
459
+ selectByLabels?(labels: string[]): ExpandedSeat[];
460
+ /** Selectable seats belonging to a section OR zone id (no selection side-effect). */
461
+ getSelectableInSection?(sectionId: string): ExpandedSeat[];
417
462
  /** Programmatic deselect of specific seats (e.g. chip × in the cart). */
418
463
  deselect(seatIds: string[]): void;
419
464
  /**
@@ -794,6 +839,13 @@ declare class SeatmapRenderer implements ISeatmapRenderer {
794
839
  private panLast;
795
840
  /** Cumulative gesture movement in px — clicks are suppressed after a real pan/pinch. */
796
841
  private moved;
842
+ /**
843
+ * Manage-mode rubber-band marquee (option-gated). `start`/`cur` are WORLD-space
844
+ * points (overlayLayer rides the stage transform); `rect` is the on-canvas
845
+ * selection band. Null except during an active manage-mode drag.
846
+ */
847
+ private marquee;
848
+ private marqueeCur;
797
849
  constructor(container: HTMLDivElement, options?: RendererOptions);
798
850
  setChart(doc: ChartDoc, opts?: {
799
851
  floorId?: string;
@@ -818,6 +870,30 @@ declare class SeatmapRenderer implements ISeatmapRenderer {
818
870
  getSelection(): ExpandedSeat[];
819
871
  clearSelection(): void;
820
872
  deselect(seatIds: string[]): void;
873
+ /** Select every selectable seat on the chart (⌘A). Returns the added seats. */
874
+ selectAllSelectable(): ExpandedSeat[];
875
+ /** Select the selectable seats matching these public labels (category/row/
876
+ * section bulk resolves to labels host-side). Returns the newly added seats. */
877
+ selectByLabels(labels: string[]): ExpandedSeat[];
878
+ /** Selectable seats in a section OR zone id — pure read (no selection change). */
879
+ getSelectableInSection(sectionId: string): ExpandedSeat[];
880
+ /**
881
+ * Union `ids` into the selection in one batched pass. Beyond MARQUEE_RING_CAP
882
+ * total selected we skip the per-seat ring nodes (fill paint still marks the
883
+ * seats) so a whole-arena select doesn't spawn thousands of Konva shapes.
884
+ * Returns the full current selection.
885
+ */
886
+ private selectMany;
887
+ private beginMarquee;
888
+ private updateMarquee;
889
+ private cancelMarquee;
890
+ /**
891
+ * Pointer-up: hit-test the marquee world-rect against the in-memory seat
892
+ * centres (NOT the Konva hit-graph — that's a cached bitmap when zoomed and
893
+ * far slower), keep only SELECTABLE seats, union them into the selection and
894
+ * fire `onMarquee`. A near-zero drag reads as a click: clear the selection.
895
+ */
896
+ private finishMarquee;
821
897
  flashSeat(seatId: string, color?: string): void;
822
898
  private onKeyDown;
823
899
  /** Nearest seat from `fromId` in a cardinal direction (aligned + close wins). */
@@ -1109,7 +1185,22 @@ declare class SeatmapRenderer implements ISeatmapRenderer {
1109
1185
  /** rAF-coalesced `onViewChange` — at most one host callback per animation frame. */
1110
1186
  private scheduleViewChange;
1111
1187
  private updateLOD;
1188
+ /** Rebuild the seat-layer bitmap synchronously (no paint). Shared by the
1189
+ * debounced cacheSeatLayer() and the synchronous forceDraw() catch-up. */
1190
+ private rebuildSeatCache;
1112
1191
  private cacheSeatLayer;
1192
+ /**
1193
+ * SYNCHRONOUS repaint that bypasses requestAnimationFrame — see the
1194
+ * ISeatmapRenderer.forceDraw() contract. Chrome pauses rAF (and therefore
1195
+ * Konva's batchDraw) on hidden/backgrounded/occluded tabs, so seat-status
1196
+ * deltas applied via setStatus() mutate the scene graph but never reach the
1197
+ * canvas until the tab is foregrounded. This flushes the cache-debounce and
1198
+ * paints every layer setStatus() can touch, immediately.
1199
+ *
1200
+ * Additive: the foreground path never calls this, so foreground behaviour is
1201
+ * byte-identical.
1202
+ */
1203
+ forceDraw(): void;
1113
1204
  private updateLabels;
1114
1205
  private handleResize;
1115
1206
  private startFpsLoop;
@@ -1280,6 +1371,18 @@ interface PickerOptions extends PickerCallbacks {
1280
1371
  flashOnLiveChange?: boolean;
1281
1372
  /** Start in colorblind-safe rendering (Okabe-Ito hues + hollow booked seats). */
1282
1373
  colorblindSafe?: boolean;
1374
+ /**
1375
+ * Keep painting seat-status deltas even while the tab is hidden/backgrounded.
1376
+ *
1377
+ * Default FALSE — the buyer widget stays efficient: it lets rAF stay paused
1378
+ * while hidden and does a single synchronous catch-up repaint on regain (the
1379
+ * visibilitychange handler resnapshots + forceDraw()s). Set TRUE only for an
1380
+ * always-live surface — the future organizer control-room board — where a
1381
+ * backgrounded monitor must keep repainting; then each delta calls
1382
+ * renderer.forceDraw() when the tab is hidden. Purely a paint hint; enforcement
1383
+ * and the WS protocol are identical either way.
1384
+ */
1385
+ keepLiveWhileHidden?: boolean;
1283
1386
  }
1284
1387
  declare class PickerController {
1285
1388
  private readonly opts;
@@ -1305,6 +1408,10 @@ declare class PickerController {
1305
1408
  private reconnectTimer;
1306
1409
  private attempt;
1307
1410
  private closed;
1411
+ /** Bound visibilitychange listener (buyer catch-up on tab regain). Kept on the
1412
+ * instance so destroy() can detach it; null when not attached (guards double
1413
+ * mounts / non-DOM environments). */
1414
+ private onVisibilityChange;
1308
1415
  private hold_;
1309
1416
  private liveStatuses;
1310
1417
  private currency;
@@ -1498,6 +1605,19 @@ declare class PickerController {
1498
1605
  private applySeatsMap;
1499
1606
  private clearBookedHoldIfSettled;
1500
1607
  private resnapshot;
1608
+ /**
1609
+ * Buyer catch-up on tab regain. While a tab is hidden Chrome pauses rAF, so
1610
+ * seat-status deltas that arrived over the WS mutated the scene graph but the
1611
+ * canvas colors never repainted. When the tab becomes visible again we (1)
1612
+ * resnapshot to pull authoritative state for anything the socket may have
1613
+ * missed while backgrounded, then (2) forceDraw() a synchronous repaint so the
1614
+ * seat colors are correct immediately rather than on the next incidental draw.
1615
+ *
1616
+ * Attached once per mount; guarded against double-attach and non-DOM
1617
+ * environments; detached in destroy() (no leaks).
1618
+ */
1619
+ private attachVisibilityListener;
1620
+ private detachVisibilityListener;
1501
1621
  private connect;
1502
1622
  private scheduleReconnect;
1503
1623
  }