@seatlayer/js 0.21.0 → 0.22.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 +65 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -3
- package/dist/index.d.ts +34 -3
- package/dist/index.js +65 -5
- package/dist/index.js.map +1 -1
- package/package.json +10 -5
package/dist/index.cjs
CHANGED
|
@@ -360,6 +360,7 @@ var TYPES = /* @__PURE__ */ new Set([
|
|
|
360
360
|
"seatlayer.designer.error"
|
|
361
361
|
]);
|
|
362
362
|
var DEFAULT_LOADING_TIMEOUT_MS = 2e4;
|
|
363
|
+
var DEFAULT_MIN_FILL_HEIGHT = 480;
|
|
363
364
|
function resolveContainer2(container) {
|
|
364
365
|
if (typeof container !== "string") return container;
|
|
365
366
|
const element = document.querySelector(container);
|
|
@@ -407,12 +408,23 @@ var EmbeddedDesigner = class {
|
|
|
407
408
|
this.fsKeyHandler = null;
|
|
408
409
|
/** Latest height (px string) the Designer reported; re-applied after unpin. */
|
|
409
410
|
this.lastAutoHeight = "";
|
|
411
|
+
// Viewport-fill sizing: pending rAF handle + whether listeners are attached.
|
|
412
|
+
this.fillRaf = null;
|
|
413
|
+
this.fillListening = false;
|
|
414
|
+
/** rAF-throttled fill recompute, so a burst of scroll/resize ticks coalesces. */
|
|
415
|
+
this.scheduleFill = () => {
|
|
416
|
+
if (this.fillRaf !== null) return;
|
|
417
|
+
this.fillRaf = requestAnimationFrame(() => {
|
|
418
|
+
this.fillRaf = null;
|
|
419
|
+
this.applyFill();
|
|
420
|
+
});
|
|
421
|
+
};
|
|
410
422
|
this.handleMessage = (event) => {
|
|
411
423
|
if (!this.frame || event.origin !== this.designerOrigin || event.source !== this.frame.contentWindow) return;
|
|
412
424
|
if (!event.data || typeof event.data !== "object") return;
|
|
413
425
|
const data = event.data;
|
|
414
426
|
if (data.type === "seatlayer.designer.resize") {
|
|
415
|
-
if (this.autoResizeEnabled() && typeof data.px === "number" && Number.isFinite(data.px) && data.px > 0) {
|
|
427
|
+
if (!this.fillEnabled() && this.autoResizeEnabled() && typeof data.px === "number" && Number.isFinite(data.px) && data.px > 0) {
|
|
416
428
|
this.lastAutoHeight = `${Math.round(data.px)}px`;
|
|
417
429
|
if (!this.pinned) this.frame.style.height = this.lastAutoHeight;
|
|
418
430
|
}
|
|
@@ -470,11 +482,11 @@ var EmbeddedDesigner = class {
|
|
|
470
482
|
this.designerOrigin = url.origin;
|
|
471
483
|
const frame = document.createElement("iframe");
|
|
472
484
|
frame.title = this.options.title ?? "Venue chart Designer";
|
|
473
|
-
frame.allow = this.options.allow ?? "clipboard-write";
|
|
485
|
+
frame.allow = this.options.allow ?? "fullscreen; clipboard-write";
|
|
474
486
|
frame.referrerPolicy = this.options.referrerPolicy ?? "origin";
|
|
475
487
|
frame.src = url.toString();
|
|
476
488
|
frame.style.width = "100%";
|
|
477
|
-
frame.style.height = "100%";
|
|
489
|
+
frame.style.height = typeof this.options.height === "number" ? `${this.options.height}px` : "100%";
|
|
478
490
|
frame.style.border = "0";
|
|
479
491
|
Object.assign(frame.style, this.options.style);
|
|
480
492
|
if (this.options.className) frame.className = this.options.className;
|
|
@@ -482,6 +494,7 @@ var EmbeddedDesigner = class {
|
|
|
482
494
|
window.addEventListener("message", this.handleMessage);
|
|
483
495
|
container.append(frame);
|
|
484
496
|
this.frame = frame;
|
|
497
|
+
if (this.fillEnabled()) this.startFill();
|
|
485
498
|
this.phase = "loading";
|
|
486
499
|
if (this.loadingStateEnabled()) {
|
|
487
500
|
this.ensureContainerPositioned(container);
|
|
@@ -505,6 +518,7 @@ var EmbeddedDesigner = class {
|
|
|
505
518
|
}
|
|
506
519
|
destroy() {
|
|
507
520
|
window.removeEventListener("message", this.handleMessage);
|
|
521
|
+
this.stopFill();
|
|
508
522
|
this.unpinFullscreen();
|
|
509
523
|
this.clearTimeoutTimer();
|
|
510
524
|
this.removeOverlay();
|
|
@@ -521,6 +535,41 @@ var EmbeddedDesigner = class {
|
|
|
521
535
|
autoResizeEnabled() {
|
|
522
536
|
return this.options.autoResize !== false;
|
|
523
537
|
}
|
|
538
|
+
/** Fill mode is the default; a numeric `height` opts into a fixed pixel box. */
|
|
539
|
+
fillEnabled() {
|
|
540
|
+
return typeof this.options.height !== "number";
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Size the iframe so its bottom edge meets the bottom of the viewport
|
|
544
|
+
* (`window.innerHeight - top`), clamped to `minHeight`. No-op while pinned
|
|
545
|
+
* fullscreen (the pin fills the viewport itself).
|
|
546
|
+
*/
|
|
547
|
+
applyFill() {
|
|
548
|
+
if (!this.frame || this.pinned) return;
|
|
549
|
+
const min = this.options.minHeight ?? DEFAULT_MIN_FILL_HEIGHT;
|
|
550
|
+
const top = this.frame.getBoundingClientRect().top;
|
|
551
|
+
const target = Math.max(min, Math.round(window.innerHeight - top));
|
|
552
|
+
this.frame.style.height = `${target}px`;
|
|
553
|
+
}
|
|
554
|
+
startFill() {
|
|
555
|
+
this.applyFill();
|
|
556
|
+
if (this.fillListening) return;
|
|
557
|
+
this.fillListening = true;
|
|
558
|
+
window.addEventListener("resize", this.scheduleFill);
|
|
559
|
+
window.addEventListener("orientationchange", this.scheduleFill);
|
|
560
|
+
window.addEventListener("scroll", this.scheduleFill, { passive: true });
|
|
561
|
+
}
|
|
562
|
+
stopFill() {
|
|
563
|
+
if (this.fillRaf !== null) {
|
|
564
|
+
cancelAnimationFrame(this.fillRaf);
|
|
565
|
+
this.fillRaf = null;
|
|
566
|
+
}
|
|
567
|
+
if (!this.fillListening) return;
|
|
568
|
+
this.fillListening = false;
|
|
569
|
+
window.removeEventListener("resize", this.scheduleFill);
|
|
570
|
+
window.removeEventListener("orientationchange", this.scheduleFill);
|
|
571
|
+
window.removeEventListener("scroll", this.scheduleFill);
|
|
572
|
+
}
|
|
524
573
|
/**
|
|
525
574
|
* Pin the iframe over the host page as a viewport-filling overlay. We save the
|
|
526
575
|
* iframe's inline style and the document scroll state so `unpinFullscreen`
|
|
@@ -559,7 +608,8 @@ var EmbeddedDesigner = class {
|
|
|
559
608
|
if (this.frame) {
|
|
560
609
|
if (this.frameStyleBeforeFs === null) this.frame.removeAttribute("style");
|
|
561
610
|
else this.frame.setAttribute("style", this.frameStyleBeforeFs);
|
|
562
|
-
if (this.
|
|
611
|
+
if (this.fillEnabled()) this.applyFill();
|
|
612
|
+
else if (this.autoResizeEnabled() && this.lastAutoHeight) this.frame.style.height = this.lastAutoHeight;
|
|
563
613
|
}
|
|
564
614
|
this.frameStyleBeforeFs = null;
|
|
565
615
|
if (this.docOverflowBeforeFs !== null) {
|
|
@@ -862,6 +912,11 @@ var CSS = `
|
|
|
862
912
|
.sl-picker[data-layout="narrow"][data-has-selection="true"] .sl-filtersec,
|
|
863
913
|
.sl-picker[data-layout="narrow"][data-has-selection="true"] .sl-filters,
|
|
864
914
|
.sl-picker[data-layout="narrow"][data-has-selection="true"] .sl-prices-sec{display:none}
|
|
915
|
+
/* Reclaim the bottom sheet once the cart has anything: the "Find best seats"
|
|
916
|
+
panel collapses too. EXCEPT the confirm ("Replace your current choices?") and
|
|
917
|
+
in-flight busy states, which legitimately show with a non-empty cart \u2014 those
|
|
918
|
+
set data-ba-active="true" (see setAttribute alongside data-has-selection). */
|
|
919
|
+
.sl-picker[data-layout="narrow"][data-has-selection="true"]:not([data-ba-active="true"]) .sl-ba{display:none}
|
|
865
920
|
/* touch chrome: pinch-zoom exists \u2014 hide +/\u2212 on the sheet layout (keep fit) */
|
|
866
921
|
.sl-picker[data-layout="narrow"] .sl-zoom [data-ref="zin"],
|
|
867
922
|
.sl-picker[data-layout="narrow"] .sl-zoom [data-ref="zout"]{display:none}
|
|
@@ -2712,6 +2767,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
2712
2767
|
if (narrow) {
|
|
2713
2768
|
card.className = "sl-seccard strip on";
|
|
2714
2769
|
card.setAttribute("role", "status");
|
|
2770
|
+
card.setAttribute("aria-label", (0, import_core2.t)("picker.sectionSummaryAria", { label: summary.label }));
|
|
2715
2771
|
card.innerHTML = `<span class="sl-seccard-dot" style="background:${summary.color}"></span><span class="sl-seccard-name">${summary.label}</span><span class="sl-seccard-left">${leftLabel}</span>` + (summary.categories.length ? `<span class="sl-seccard-price">${priceLabel}</span>` : "") + xBtn;
|
|
2716
2772
|
card.querySelector(".sl-seccard-x").addEventListener("click", () => this.controller.overview());
|
|
2717
2773
|
(this.els.sheetHead ?? this.els.side ?? this.els.map).appendChild(card);
|
|
@@ -3122,7 +3178,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
3122
3178
|
} else if (!seats.length && !heldItems.length) {
|
|
3123
3179
|
parts.push(`<div class="sl-tray-hint">Tap a seat on the map \u2014 or grab standing tickets below.</div>`);
|
|
3124
3180
|
}
|
|
3125
|
-
const noPicks = !seats.length && !heldItems.length;
|
|
3181
|
+
const noPicks = !seats.length && !heldItems.length && !this.pendingGACount();
|
|
3126
3182
|
if (!this.hold && (noPicks || this.bestAvailableBusy || this.bestAvailableConfirm)) {
|
|
3127
3183
|
const cats = this.controller.doc?.categories ?? [];
|
|
3128
3184
|
parts.push(this.bestAvailableConfirm ? `<div class="sl-ba" role="alert"><div class="sl-ba-title"><span class="spark" aria-hidden="true">\u2726</span>Replace your current choices?</div><div class="sl-ba-replace"><b>We\u2019ll find ${this.baQty} seats together.</b><span>Your manually selected tickets will be removed only after a new group is secured.</span></div><div class="sl-ba-actions"><button type="button" data-ba-cancel>Keep mine</button><button type="button" class="replace" data-ba-replace>Find new seats</button></div></div>` : `<div class="sl-ba"><div class="sl-ba-title"><span class="spark" aria-hidden="true">\u2726</span>Find the best seats together</div><div class="sl-ba-copy"><span class="wide">We\u2019ll choose the closest available group for you.</span><span class="narrow">Closest available group, chosen instantly.</span></div>` + (cats.length > 1 ? `<select aria-label="Preferred ticket type" data-ba-cat><option value="">Any ticket type</option>` + cats.map((c) => `<option value="${c.key}"${this.baCat === c.key ? " selected" : ""}>${c.label}</option>`).join("") + `</select>` : `<span aria-hidden="true"></span>`) + `<div class="sl-ba-qty"><button type="button" data-ba="-1" aria-label="Fewer seats">\u2212</button><span>${this.baQty}</span><button type="button" data-ba="1" aria-label="More seats">+</button></div><button type="button" class="sl-ba-go"${this.bestAvailableBusy ? " disabled" : ""}>` + (this.bestAvailableBusy ? `<span class="sl-ba-spin" aria-hidden="true"></span>Finding the best seats\u2026` : `Find ${this.baQty} best ${this.baQty === 1 ? "seat" : "seats"}`) + `</button></div>`);
|
|
@@ -3266,6 +3322,10 @@ var SeatPicker = class _SeatPicker {
|
|
|
3266
3322
|
this.els.count.textContent = count ? `${count} ${count === 1 ? "ticket" : "tickets"}` : "No seats selected";
|
|
3267
3323
|
this.els.total.textContent = count ? this.money(total) : "";
|
|
3268
3324
|
this.root?.setAttribute("data-has-selection", String(count > 0));
|
|
3325
|
+
this.root?.setAttribute(
|
|
3326
|
+
"data-ba-active",
|
|
3327
|
+
String(this.bestAvailableConfirm || this.bestAvailableBusy)
|
|
3328
|
+
);
|
|
3269
3329
|
this.els.foot?.classList.toggle("empty", count === 0);
|
|
3270
3330
|
if (this.els.seatSummary) {
|
|
3271
3331
|
this.els.seatSummary.textContent = count ? `${count} selected` : "";
|