@seatlayer/core 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.cjs CHANGED
@@ -518,7 +518,8 @@ function expandRowSlots(row) {
518
518
  accessible: accessibility.length > 0,
519
519
  accessibility,
520
520
  commercial: Object.values(commercial).some((value) => value !== void 0 && value !== false && value !== "") ? commercial : void 0,
521
- viewUrl: o?.viewFromSeatUrl ?? row.viewFromSeatUrl
521
+ viewUrl: o?.viewFromSeatUrl ?? row.viewFromSeatUrl,
522
+ labelStyle: o?.labelStyle
522
523
  };
523
524
  });
524
525
  }
@@ -537,7 +538,8 @@ function expandRow(row) {
537
538
  accessible: slot.accessible || void 0,
538
539
  accessibility: slot.accessibility.length ? slot.accessibility : void 0,
539
540
  commercial: slot.commercial,
540
- viewUrl: slot.viewUrl
541
+ viewUrl: slot.viewUrl,
542
+ labelStyle: slot.labelStyle
541
543
  });
542
544
  }
543
545
  return seats;
@@ -2733,14 +2735,22 @@ var _SeatmapRenderer = class _SeatmapRenderer {
2733
2735
  const idx = this.catOrder.indexOf(categoryKey);
2734
2736
  return CB_PALETTE[(idx >= 0 ? idx : 0) % CB_PALETTE.length];
2735
2737
  }
2736
- /** Resolve label ink against the paint that is actually visible. The theme
2737
- * ink remains preferred, but mixed category palettes cannot always share one
2738
- * accessible text colour, so every free and transient state gets the same
2739
- * deterministic dark/light fallback used by Designer. */
2740
- renderedBookableLabelInk(shape) {
2741
- const preferred = this.theme.seatLabelColor ?? DEF_SEAT_LABEL;
2738
+ /** Per-seat authored label size relative to the neutral default (1 = default),
2739
+ * mirroring the section convention (labelStyle.size ?? 18) / 18. Only real
2740
+ * seats carry labelStyle, so booths and unstyled seats resolve to 1. */
2741
+ seatLabelScale(seat) {
2742
+ return (seat.labelStyle?.size ?? 18) / 18;
2743
+ }
2744
+ /** Preferred label ink for a seat: the authored per-seat colour when set,
2745
+ * otherwise today's theme default. Fed through auto-contrast by seatLabelInk. */
2746
+ seatPreferredLabelInk(seat) {
2747
+ return seat.labelStyle?.color ?? this.theme.seatLabelColor ?? DEF_SEAT_LABEL;
2748
+ }
2749
+ /** Resolve a seat's label ink against the paint actually visible, honouring an
2750
+ * authored per-seat colour through the same auto-contrast rule as sections. */
2751
+ seatLabelInk(seat, shape) {
2742
2752
  const fill = shape.fill();
2743
- return stateAwareBookableLabelInk(typeof fill === "string" ? fill : "", preferred);
2753
+ return stateAwareBookableLabelInk(typeof fill === "string" ? fill : "", this.seatPreferredLabelInk(seat));
2744
2754
  }
2745
2755
  /** Apply fill/stroke/opacity for a seat's current status + selection. */
2746
2756
  paintSeat(c, id) {
@@ -2824,7 +2834,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
2824
2834
  if (this.selectionFocusId && id !== this.selectionFocusId) c.opacity(Math.min(c.opacity(), 0.16));
2825
2835
  const bookableLabel = this.boothLabelById.get(id) ?? this.seatLabelById.get(id);
2826
2836
  if (bookableLabel) {
2827
- bookableLabel.fill(this.renderedBookableLabelInk(c));
2837
+ bookableLabel.fill(this.seatLabelInk(seat, c));
2828
2838
  bookableLabel.visible(
2829
2839
  isBookableLabelLegibleAtScale(bookableLabel.fontSize(), this.effScale()) && c.opacity() >= 0.5
2830
2840
  );
@@ -4204,7 +4214,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
4204
4214
  const labels = this.seats.map((seat) => {
4205
4215
  const shape = this.circleById.get(seat.id);
4206
4216
  const label = this.boothLabelById.get(seat.id) ?? this.seatLabelById.get(seat.id);
4207
- const authoredFontSize = seat.kind === "booth" ? BOOTH_LABEL_FONT_SIZE : SEAT_LABEL_FONT_SIZE;
4217
+ const authoredFontSize = seat.kind === "booth" ? BOOTH_LABEL_FONT_SIZE : SEAT_LABEL_FONT_SIZE * this.seatLabelScale(seat);
4208
4218
  const renderedFontPx = rounded((label?.fontSize() ?? authoredFontSize) * effectiveScale);
4209
4219
  const screen = this.worldToScreen(seat);
4210
4220
  const outside = screen.x < 0 || screen.x > viewport.width || screen.y < 0 || screen.y > viewport.height;
@@ -4521,9 +4531,10 @@ var _SeatmapRenderer = class _SeatmapRenderer {
4521
4531
  minimumFont = Math.min(minimumFont, BOOTH_LABEL_FONT_SIZE);
4522
4532
  continue;
4523
4533
  }
4524
- measure.fontSize(SEAT_LABEL_FONT_SIZE);
4534
+ const authoredFontSize = SEAT_LABEL_FONT_SIZE * this.seatLabelScale(seat);
4535
+ measure.fontSize(authoredFontSize);
4525
4536
  measure.text(bookableMarkerLabel(seat.displayLabel ?? seat.label));
4526
- const fitted = measure.width() > maxWidth ? Math.max(MIN_FITTED_SEAT_LABEL_FONT_SIZE, SEAT_LABEL_FONT_SIZE * maxWidth / measure.width()) : SEAT_LABEL_FONT_SIZE;
4537
+ const fitted = measure.width() > maxWidth ? Math.max(MIN_FITTED_SEAT_LABEL_FONT_SIZE, authoredFontSize * maxWidth / measure.width()) : authoredFontSize;
4527
4538
  minimumFont = Math.min(minimumFont, fitted);
4528
4539
  }
4529
4540
  measure.destroy();
@@ -4673,19 +4684,20 @@ var _SeatmapRenderer = class _SeatmapRenderer {
4673
4684
  if (++count >= MAX_LABELS) break;
4674
4685
  continue;
4675
4686
  }
4687
+ const authoredFontSize = SEAT_LABEL_FONT_SIZE * this.seatLabelScale(seat);
4676
4688
  const t2 = new import_Text.Text({
4677
4689
  x: seat.x,
4678
4690
  y: seat.y,
4679
4691
  text: bookableMarkerLabel(seat.displayLabel ?? seat.label),
4680
- fontSize: SEAT_LABEL_FONT_SIZE,
4692
+ fontSize: authoredFontSize,
4681
4693
  fontStyle: "600",
4682
4694
  fontFamily: this.labelFont(),
4683
- fill: shape ? this.renderedBookableLabelInk(shape) : this.theme.seatLabelColor ?? DEF_SEAT_LABEL,
4695
+ fill: shape ? this.seatLabelInk(seat, shape) : this.seatPreferredLabelInk(seat),
4684
4696
  listening: false,
4685
4697
  perfectDrawEnabled: false
4686
4698
  });
4687
4699
  const maxW = this.seatR * 2 - 3;
4688
- if (t2.width() > maxW) t2.fontSize(Math.max(MIN_FITTED_SEAT_LABEL_FONT_SIZE, SEAT_LABEL_FONT_SIZE * maxW / t2.width()));
4700
+ if (t2.width() > maxW) t2.fontSize(Math.max(MIN_FITTED_SEAT_LABEL_FONT_SIZE, authoredFontSize * maxW / t2.width()));
4689
4701
  if (t2.width() > maxW + 0.01) {
4690
4702
  t2.destroy();
4691
4703
  continue;
@@ -5645,6 +5657,15 @@ var PickerController = class {
5645
5657
  } catch {
5646
5658
  }
5647
5659
  }
5660
+ /**
5661
+ * Re-pull the status snapshot on demand. Live surfaces rarely need this (the
5662
+ * socket keeps them fresh); local/mock transports with no socket call it
5663
+ * after they mutate state (e.g. the demo books a hold) so the renderer and
5664
+ * every onStatusChange consumer repaint from the new truth.
5665
+ */
5666
+ async refresh() {
5667
+ await this.resnapshot();
5668
+ }
5648
5669
  // ---- realtime socket ------------------------------------------------------
5649
5670
  /**
5650
5671
  * Buyer catch-up on tab regain. While a tab is hidden Chrome pauses rAF, so
@@ -5679,9 +5700,11 @@ var PickerController = class {
5679
5700
  }
5680
5701
  connect() {
5681
5702
  if (this.closed) return;
5703
+ const url = this.api.socketUrl(this.key);
5704
+ if (!url) return;
5682
5705
  let ws;
5683
5706
  try {
5684
- ws = new WebSocket(this.api.socketUrl(this.key));
5707
+ ws = new WebSocket(url);
5685
5708
  } catch {
5686
5709
  this.scheduleReconnect();
5687
5710
  return;