@seatlayer/js 0.30.1 → 0.31.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/README.md +1 -0
- package/dist/index.cjs +127 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -2
- package/dist/index.d.ts +35 -2
- package/dist/index.js +127 -15
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -208,6 +208,7 @@ The browser **holds**; your **server books** with a secret key. See
|
|
|
208
208
|
- [Holds and checkout](https://docs.seatlayer.io/buyer-sdk/holds-and-checkout/)
|
|
209
209
|
- [Complete checkout example](https://docs.seatlayer.io/examples/complete-checkout/)
|
|
210
210
|
- [`@seatlayer/react`](https://www.npmjs.com/package/@seatlayer/react)
|
|
211
|
+
- [React Native SDK](https://github.com/seatlayer/seatlayer-react-native)
|
|
211
212
|
- [iOS SDK](https://github.com/seatlayer/seatlayer-ios)
|
|
212
213
|
- [Flutter package](https://pub.dev/packages/seatlayer)
|
|
213
214
|
- [Agent-readable documentation](https://docs.seatlayer.io/llms.txt)
|
package/dist/index.cjs
CHANGED
|
@@ -131,6 +131,9 @@ var PubApi = class {
|
|
|
131
131
|
}
|
|
132
132
|
};
|
|
133
133
|
|
|
134
|
+
// src/seatLayerBrand.ts
|
|
135
|
+
var SEATLAYER_ATTRIBUTION_MARK_SVG = '<svg viewBox="0 0 64 56" width="12" height="11" fill="none" aria-hidden="true" focusable="false" style="display:block"><path d="M4 13 Q16 6 29 7 L28.5 17 Q17 16.5 7 22 Z" fill="#f4b740"/><path d="M4 13 Q16 6 29 7 L28.5 17 Q17 16.5 7 22 Z" fill="#f4b740" transform="translate(64 0) scale(-1 1)"/><path d="M8 28 Q18 22 28.6 23 L28.2 32 Q18 28.5 10 36 Z" fill="#fcf7ee"/><path d="M8 28 Q18 22 28.6 23 L28.2 32 Q18 28.5 10 36 Z" fill="#fcf7ee" transform="translate(64 0) scale(-1 1)"/><path d="M11 41 Q19 35 28.2 36 L27.8 45 Q19.5 42 13.5 49 Z" fill="#fcf7ee"/><path d="M11 41 Q19 35 28.2 36 L27.8 45 Q19.5 42 13.5 49 Z" fill="#fcf7ee" transform="translate(64 0) scale(-1 1)"/></svg>';
|
|
136
|
+
|
|
134
137
|
// src/SeatingChart.ts
|
|
135
138
|
var DEFAULT_API_BASE = "https://api.seatlayer.io";
|
|
136
139
|
var DEFAULT_MAX_SELECTION = 10;
|
|
@@ -246,7 +249,7 @@ var SeatingChart = class {
|
|
|
246
249
|
badge.rel = "noopener noreferrer";
|
|
247
250
|
badge.setAttribute("aria-label", (0, import_core.t)("picker.poweredBy"));
|
|
248
251
|
badge.style.cssText = 'position:absolute;bottom:10px;right:12px;z-index:5;display:inline-flex;align-items:center;gap:6px;padding:5px 9px;border-radius:999px;background:rgba(255,255,255,.92);color:#4a5163;text-decoration:none;font:600 11px/1 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;letter-spacing:.02em;box-shadow:0 2px 8px rgba(0,0,0,.12);';
|
|
249
|
-
badge.innerHTML =
|
|
252
|
+
badge.innerHTML = '<span aria-hidden="true" style="width:16px;height:16px;border-radius:4px;flex:none;display:flex;align-items:center;justify-content:center;background:#0c1220;color:#fcf7ee">' + SEATLAYER_ATTRIBUTION_MARK_SVG + `</span><span>${(0, import_core.t)("picker.poweredBy")}</span>`;
|
|
250
253
|
host.appendChild(badge);
|
|
251
254
|
}
|
|
252
255
|
placeTooltip() {
|
|
@@ -1107,6 +1110,8 @@ var import_meta = {};
|
|
|
1107
1110
|
var DEFAULT_API_BASE2 = "https://api.seatlayer.io";
|
|
1108
1111
|
var DEFAULT_MAX_SELECTION2 = 10;
|
|
1109
1112
|
var EXTEND_PROMPT_MS = 6e4;
|
|
1113
|
+
var MAX_3D_SEATS_DEFAULT = 15e3;
|
|
1114
|
+
var MAX_3D_SECTION_PILLS = 12;
|
|
1110
1115
|
function pointInPolygon(x, y, poly) {
|
|
1111
1116
|
let inside = false;
|
|
1112
1117
|
for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
|
|
@@ -1526,14 +1531,14 @@ var CSS = `
|
|
|
1526
1531
|
.sl-closed-pill.on{display:inline-flex}
|
|
1527
1532
|
.sl-closed-pill svg{width:13px;height:13px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}
|
|
1528
1533
|
|
|
1529
|
-
/* "Powered by SeatLayer" attribution badge (side-panel foot) \u2014 the
|
|
1530
|
-
|
|
1534
|
+
/* "Powered by SeatLayer" attribution badge (side-panel foot) \u2014 the canonical
|
|
1535
|
+
Layered Rows mark + wordmark. Hidden when the host opts out or the org's paid
|
|
1531
1536
|
theme sets hideBadge. */
|
|
1532
1537
|
.sl-powered{display:flex;align-items:center;justify-content:center;gap:6px;margin-top:10px;
|
|
1533
1538
|
font-size:11px;letter-spacing:.03em;color:var(--sl-muted)}
|
|
1534
1539
|
.sl-powered-mark{width:16px;height:16px;border-radius:4px;flex:none;display:flex;align-items:center;justify-content:center;
|
|
1535
|
-
background
|
|
1536
|
-
.sl-powered-mark svg{width:
|
|
1540
|
+
background:#0c1220;color:#fcf7ee}
|
|
1541
|
+
.sl-powered-mark svg{width:12px;height:11px}
|
|
1537
1542
|
|
|
1538
1543
|
/* a11y filter chips (flow within the top-left region) */
|
|
1539
1544
|
.sl-chips{display:flex;gap:6px;flex-wrap:wrap}
|
|
@@ -1715,6 +1720,20 @@ var CSS = `
|
|
|
1715
1720
|
color:#e6edf3;background:rgba(10,14,20,.62);border:1px solid rgba(255,255,255,.22);backdrop-filter:blur(6px)}
|
|
1716
1721
|
.sl-view3d-back:hover,.sl-view3d-back:focus-visible{background:rgba(16,22,30,.82);border-color:rgba(255,255,255,.4)}
|
|
1717
1722
|
.sl-view3d-back svg{width:15px;height:15px;stroke:currentColor;stroke-width:2.4;fill:none;stroke-linecap:round;stroke-linejoin:round}
|
|
1723
|
+
/* Venue navigation inside 3D: levels (isolate a floor) and areas (fly to a zone).
|
|
1724
|
+
Bottom-LEFT, clear of the module's own chips (Overview bottom-right, 360
|
|
1725
|
+
bottom-centre) and of the bottom-sheeted confirm card. Horizontally scrollable
|
|
1726
|
+
so a venue with many zones never pushes the rail off a phone screen. */
|
|
1727
|
+
.sl-view3d-nav{position:absolute;left:12px;bottom:16px;z-index:3;display:flex;flex-direction:column;gap:6px;
|
|
1728
|
+
max-width:calc(100% - 24px);pointer-events:none}
|
|
1729
|
+
.sl-view3d-nav > div{display:flex;gap:6px;overflow-x:auto;scrollbar-width:none;pointer-events:auto;
|
|
1730
|
+
padding:1px;-webkit-overflow-scrolling:touch}
|
|
1731
|
+
.sl-view3d-nav > div::-webkit-scrollbar{display:none}
|
|
1732
|
+
.sl-view3d-nav button{flex:0 0 auto;min-height:32px;padding:7px 12px;border-radius:999px;white-space:nowrap;
|
|
1733
|
+
font-size:11.5px;font-weight:700;color:#c9d4ea;background:rgba(12,18,32,.72);
|
|
1734
|
+
border:1px solid rgba(150,165,205,.35);backdrop-filter:blur(6px);cursor:pointer}
|
|
1735
|
+
.sl-view3d-nav button:hover,.sl-view3d-nav button:focus-visible{color:#eef1f8;border-color:rgba(190,205,240,.6)}
|
|
1736
|
+
.sl-view3d-nav button[aria-pressed="true"]{background:var(--sl-accent);color:var(--sl-accent-ink);border-color:transparent}
|
|
1718
1737
|
/* While immersed, the 2D-only chrome is meaningless \u2014 hide it, keep Map|3D. */
|
|
1719
1738
|
.sl-picker[data-view3d="on"] .sl-rungs,
|
|
1720
1739
|
.sl-picker[data-view3d="on"] .sl-floors,
|
|
@@ -1988,6 +2007,8 @@ var SeatPicker = class _SeatPicker {
|
|
|
1988
2007
|
// F4 price-band filter — active band's category keys (null = all prices)
|
|
1989
2008
|
this.priceBandKeys = null;
|
|
1990
2009
|
this.focusedCatKey = null;
|
|
2010
|
+
/** "Hide limited-view seats" — mirrored into 3D by `seatState3dFor`. */
|
|
2011
|
+
this.limitedViewFilter = false;
|
|
1991
2012
|
this.pricesExpanded = false;
|
|
1992
2013
|
/** Last surfaced section summary (re-rendered when the price band changes). */
|
|
1993
2014
|
this.lastSection = null;
|
|
@@ -2656,12 +2677,13 @@ var SeatPicker = class _SeatPicker {
|
|
|
2656
2677
|
limited.setAttribute("aria-pressed", "false");
|
|
2657
2678
|
limited.innerHTML = `\u25D0 ${this.tf("picker.hideLimitedView", "Hide limited-view seats")}`;
|
|
2658
2679
|
chips.appendChild(limited);
|
|
2659
|
-
let limitedOn = false;
|
|
2660
2680
|
limited.addEventListener("click", () => {
|
|
2661
|
-
limitedOn = !
|
|
2681
|
+
const limitedOn = !this.limitedViewFilter;
|
|
2682
|
+
this.limitedViewFilter = limitedOn;
|
|
2662
2683
|
limited.classList.toggle("on", limitedOn);
|
|
2663
2684
|
limited.setAttribute("aria-pressed", String(limitedOn));
|
|
2664
2685
|
this.controller.setCommercialLimitedFilter(limitedOn);
|
|
2686
|
+
this.pushAvailabilityTo3d();
|
|
2665
2687
|
if (limitedOn) focusSeatsForFilter();
|
|
2666
2688
|
});
|
|
2667
2689
|
}
|
|
@@ -2819,7 +2841,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
2819
2841
|
if (!foot) return;
|
|
2820
2842
|
const el = document.createElement("div");
|
|
2821
2843
|
el.className = "sl-powered";
|
|
2822
|
-
el.innerHTML = `<span class="sl-powered-mark" aria-hidden="true"
|
|
2844
|
+
el.innerHTML = `<span class="sl-powered-mark" aria-hidden="true">` + SEATLAYER_ATTRIBUTION_MARK_SVG + `</span><span>${this.tf("picker.poweredBy", "Powered by SeatLayer")}</span>`;
|
|
2823
2845
|
foot.appendChild(el);
|
|
2824
2846
|
}
|
|
2825
2847
|
// ---- Feature 6: chrome anchor regions -------------------------------------
|
|
@@ -3250,6 +3272,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
3250
3272
|
this.priceBandKeys = keys ? new Set(keys) : null;
|
|
3251
3273
|
this.controller.setCategoryFilter(keys);
|
|
3252
3274
|
this.controller.focusCategoryFilter(keys);
|
|
3275
|
+
this.pushAvailabilityTo3d();
|
|
3253
3276
|
this.syncFloors();
|
|
3254
3277
|
this.syncRung();
|
|
3255
3278
|
this.refreshMinimap();
|
|
@@ -3347,10 +3370,23 @@ var SeatPicker = class _SeatPicker {
|
|
|
3347
3370
|
button.setAttribute("aria-pressed", String(on));
|
|
3348
3371
|
});
|
|
3349
3372
|
}
|
|
3350
|
-
/** Can this picker offer the 3D venue view? Requires the option (default on)
|
|
3351
|
-
*
|
|
3373
|
+
/** Can this picker offer the 3D venue view? Requires the option (default on),
|
|
3374
|
+
* WebGL2, a chart to render, and a chart small enough to render WELL. */
|
|
3352
3375
|
canOffer3d() {
|
|
3353
|
-
|
|
3376
|
+
if (this.opts.enable3D === false || !this.controller.doc || !hasWebGL2()) return false;
|
|
3377
|
+
return this.allSeats().length <= this.max3dSeats();
|
|
3378
|
+
}
|
|
3379
|
+
/**
|
|
3380
|
+
* The seat ceiling for offering 3D. See `max3DSeats` — an explicit host value
|
|
3381
|
+
* always wins; otherwise a small/low-core device gets half the desktop budget,
|
|
3382
|
+
* because it is the device that turns "slow" into "stalled".
|
|
3383
|
+
*/
|
|
3384
|
+
max3dSeats() {
|
|
3385
|
+
const authored = this.opts.max3DSeats;
|
|
3386
|
+
if (typeof authored === "number" && authored > 0) return authored;
|
|
3387
|
+
const nav = globalThis.navigator;
|
|
3388
|
+
const small = (nav?.hardwareConcurrency ?? 8) <= 4 || (nav?.deviceMemory ?? 8) <= 4 || (globalThis.matchMedia?.("(pointer: coarse)").matches ?? false);
|
|
3389
|
+
return small ? MAX_3D_SEATS_DEFAULT / 2 : MAX_3D_SEATS_DEFAULT;
|
|
3354
3390
|
}
|
|
3355
3391
|
/** Reflect the active floor onto the switcher rail. */
|
|
3356
3392
|
syncFloors() {
|
|
@@ -3903,6 +3939,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
3903
3939
|
if (select) select.value = "all";
|
|
3904
3940
|
this.controller.setCategoryFilter(next ? [next] : null);
|
|
3905
3941
|
this.controller.focusCategoryFilter(next ? [next] : null);
|
|
3942
|
+
this.pushAvailabilityTo3d();
|
|
3906
3943
|
this.syncFloors();
|
|
3907
3944
|
this.syncRung();
|
|
3908
3945
|
this.refreshMinimap();
|
|
@@ -4594,8 +4631,8 @@ var SeatPicker = class _SeatPicker {
|
|
|
4594
4631
|
void this.enter3d(flyToSeatId);
|
|
4595
4632
|
}
|
|
4596
4633
|
/** SeatStatus → the view3d palette state. Selection is layered separately. */
|
|
4597
|
-
seatState3dFor(
|
|
4598
|
-
switch (this.controller.getStatus(id)) {
|
|
4634
|
+
seatState3dFor(seat) {
|
|
4635
|
+
switch (this.controller.getStatus(seat.id)) {
|
|
4599
4636
|
case "held":
|
|
4600
4637
|
return "held";
|
|
4601
4638
|
case "booked":
|
|
@@ -4603,14 +4640,19 @@ var SeatPicker = class _SeatPicker {
|
|
|
4603
4640
|
case "not_for_sale":
|
|
4604
4641
|
return "dimmed";
|
|
4605
4642
|
default:
|
|
4606
|
-
|
|
4643
|
+
break;
|
|
4644
|
+
}
|
|
4645
|
+
if (this.priceBandKeys != null && !this.priceBandKeys.has(seat.categoryKey)) return "dimmed";
|
|
4646
|
+
if (this.limitedViewFilter && (seat.commercial?.restrictedView || seat.commercial?.obstructedView)) {
|
|
4647
|
+
return "dimmed";
|
|
4607
4648
|
}
|
|
4649
|
+
return "available";
|
|
4608
4650
|
}
|
|
4609
4651
|
/** Push the full live availability snapshot into the 3D handle (selection is
|
|
4610
4652
|
* preserved inside the module). Cheap enough per status delta. */
|
|
4611
4653
|
pushAvailabilityTo3d() {
|
|
4612
4654
|
if (!this.view3dHandle) return;
|
|
4613
|
-
const updates = this.allSeats().map((s) => ({ seatId: s.id, state: this.seatState3dFor(s
|
|
4655
|
+
const updates = this.allSeats().map((s) => ({ seatId: s.id, state: this.seatState3dFor(s) }));
|
|
4614
4656
|
this.view3dHandle.setAvailability(updates);
|
|
4615
4657
|
}
|
|
4616
4658
|
/** Mirror the authoritative widget selection into the 3D handle. */
|
|
@@ -4662,6 +4704,75 @@ var SeatPicker = class _SeatPicker {
|
|
|
4662
4704
|
if (this.opts.confirmSelection !== false) this.showConfirm(seat);
|
|
4663
4705
|
else this.syncTray();
|
|
4664
4706
|
}
|
|
4707
|
+
/**
|
|
4708
|
+
* The venue-navigation rail inside 3D: levels and areas.
|
|
4709
|
+
*
|
|
4710
|
+
* In 2D a buyer moves through the venue by floor switcher and by the LOD
|
|
4711
|
+
* rungs. Both are hidden while immersed, and the 3D module's own chips only
|
|
4712
|
+
* cover "go home" and "see the 360" — so on a multi-floor or multi-zone chart
|
|
4713
|
+
* the buyer entered 3D and LOST the ability to reach the level or area they
|
|
4714
|
+
* were booking. The camera moves for both already exist on the handle
|
|
4715
|
+
* (`focusFloor` / `focusZone`); this is the surface that offers them.
|
|
4716
|
+
*
|
|
4717
|
+
* Levels are a TOGGLE (a floor stays isolated until you pick another), areas
|
|
4718
|
+
* are an ACTION (the camera flies there and you are then free to orbit), which
|
|
4719
|
+
* is why only the level pills carry a pressed state.
|
|
4720
|
+
*/
|
|
4721
|
+
buildView3dNav(overlay, handle) {
|
|
4722
|
+
const floors = handle.floors();
|
|
4723
|
+
const zones = handle.zones().filter((z) => z.seatCount > 0);
|
|
4724
|
+
const sections = zones.length > 1 ? [] : handle.sections().filter((s) => s.seatCount > 0).slice(0, MAX_3D_SECTION_PILLS);
|
|
4725
|
+
const wantFloors = floors.length > 1;
|
|
4726
|
+
const wantZones = zones.length > 1;
|
|
4727
|
+
const wantSections = sections.length > 1;
|
|
4728
|
+
if (!wantFloors && !wantZones && !wantSections) return;
|
|
4729
|
+
const nav = document.createElement("div");
|
|
4730
|
+
nav.className = "sl-view3d-nav";
|
|
4731
|
+
if (wantFloors) {
|
|
4732
|
+
const row = document.createElement("div");
|
|
4733
|
+
row.setAttribute("role", "group");
|
|
4734
|
+
row.setAttribute("aria-label", this.tf("picker.levels", "Levels"));
|
|
4735
|
+
const pills = [];
|
|
4736
|
+
const select = (index) => {
|
|
4737
|
+
if (!handle.focusFloor(index)) return;
|
|
4738
|
+
pills.forEach((p) => {
|
|
4739
|
+
p.setAttribute("aria-pressed", String((p.dataset.floor === "" ? null : Number(p.dataset.floor)) === index));
|
|
4740
|
+
});
|
|
4741
|
+
};
|
|
4742
|
+
const add = (label, index) => {
|
|
4743
|
+
const b = document.createElement("button");
|
|
4744
|
+
b.type = "button";
|
|
4745
|
+
b.textContent = label;
|
|
4746
|
+
b.dataset.floor = index === null ? "" : String(index);
|
|
4747
|
+
b.setAttribute("aria-pressed", String(index === null));
|
|
4748
|
+
b.addEventListener("click", () => select(index));
|
|
4749
|
+
pills.push(b);
|
|
4750
|
+
row.appendChild(b);
|
|
4751
|
+
};
|
|
4752
|
+
add(this.tf("picker.allLevels", "All levels"), null);
|
|
4753
|
+
for (const f of floors) add(f.label || `Level ${f.index + 1}`, f.index);
|
|
4754
|
+
nav.appendChild(row);
|
|
4755
|
+
}
|
|
4756
|
+
if (wantZones || wantSections) {
|
|
4757
|
+
const row = document.createElement("div");
|
|
4758
|
+
row.setAttribute("role", "group");
|
|
4759
|
+
row.setAttribute("aria-label", this.tf("picker.areas", "Areas"));
|
|
4760
|
+
const entries = wantZones ? zones.map((z) => ({ id: z.id, label: z.label || z.id, go: () => {
|
|
4761
|
+
handle.focusZone(z.id);
|
|
4762
|
+
} })) : sections.map((s) => ({ id: s.id, label: s.label || s.id, go: () => {
|
|
4763
|
+
handle.focusSection(s.id);
|
|
4764
|
+
} }));
|
|
4765
|
+
for (const e of entries) {
|
|
4766
|
+
const b = document.createElement("button");
|
|
4767
|
+
b.type = "button";
|
|
4768
|
+
b.textContent = e.label;
|
|
4769
|
+
b.addEventListener("click", e.go);
|
|
4770
|
+
row.appendChild(b);
|
|
4771
|
+
}
|
|
4772
|
+
nav.appendChild(row);
|
|
4773
|
+
}
|
|
4774
|
+
overlay.appendChild(nav);
|
|
4775
|
+
}
|
|
4665
4776
|
async enter3d(flySeatId) {
|
|
4666
4777
|
if (this.view3dEl || !this.canOffer3d() || !this.els.map) return;
|
|
4667
4778
|
const doc = this.controller.doc;
|
|
@@ -4712,6 +4823,7 @@ var SeatPicker = class _SeatPicker {
|
|
|
4712
4823
|
this.view3dHandle = handle;
|
|
4713
4824
|
this.pushAvailabilityTo3d();
|
|
4714
4825
|
this.syncSelectionTo3d();
|
|
4826
|
+
this.buildView3dNav(overlay, handle);
|
|
4715
4827
|
if (flySeatId) void handle.flyToSeat(flySeatId);
|
|
4716
4828
|
} catch (err) {
|
|
4717
4829
|
this.opts.onError?.(err);
|