@seatlayer/core 0.23.0 → 0.24.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/{de-DRWMZ2FV.js → de-EIG65UFU.js} +2 -34
- package/dist/de-EIG65UFU.js.map +1 -0
- package/dist/{es-N73CIVTC.js → es-47HFAWS6.js} +2 -34
- package/dist/es-47HFAWS6.js.map +1 -0
- package/dist/{fr-SOY2OB4P.js → fr-7IXNNFBS.js} +2 -34
- package/dist/fr-7IXNNFBS.js.map +1 -0
- package/dist/index.cjs +199 -159
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +97 -3
- package/dist/index.d.ts +97 -3
- package/dist/index.js +197 -63
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/de-DRWMZ2FV.js.map +0 -1
- package/dist/es-N73CIVTC.js.map +0 -1
- package/dist/fr-SOY2OB4P.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -41,29 +41,17 @@ var init_es = __esm({
|
|
|
41
41
|
"common.done": "Listo",
|
|
42
42
|
"common.copied": "\u2713 Copiado",
|
|
43
43
|
// buyer picker (extraction in progress — P4 of the port plan)
|
|
44
|
-
"picker.holdSeats": "Retener asientos y comprar",
|
|
45
|
-
"picker.completeBooking": "Completar reserva",
|
|
46
|
-
"picker.seatsHeld": "Asientos retenidos \u2014 {time}",
|
|
47
44
|
"picker.holdExpired": "Tu retenci\xF3n expir\xF3 \u2014 los asientos fueron liberados. Elige de nuevo.",
|
|
48
|
-
"picker.seatTaken": "El asiento {label} fue tomado por otro comprador.",
|
|
49
45
|
"picker.poweredBy": "Con la tecnolog\xEDa de SeatLayer",
|
|
50
46
|
"picker.testMode": "MODO DE PRUEBA",
|
|
51
|
-
"picker.colorblind": "Colores aptos para daltonismo",
|
|
52
47
|
"picker.orphanHint": "Esto deja un asiento aislado \u2014 considera desplazarte un asiento.",
|
|
53
|
-
"picker.seats.one": "{count} asiento",
|
|
54
|
-
"picker.seats.other": "{count} asientos",
|
|
55
48
|
// renderer (drawn on the Konva map — shared by the embed SDK)
|
|
56
49
|
"map.aria": "Mapa de asientos. Usa las flechas para moverte entre asientos, Intro para seleccionar.",
|
|
57
50
|
"map.seatsLeft": "{count} LIBRES",
|
|
58
51
|
"map.statusHeld": "En espera",
|
|
59
52
|
"map.statusTaken": "Ocupado",
|
|
60
53
|
"map.fromPrice": "DESDE {price}",
|
|
61
|
-
// buyer picker
|
|
62
|
-
"picker.language": "Idioma",
|
|
63
|
-
"picker.zoomToFit": "Ajustar zoom",
|
|
64
|
-
"picker.seatCountLabel": "asientos",
|
|
65
|
-
"picker.capacity": "capacidad",
|
|
66
|
-
"picker.viewMode": "Modo de vista",
|
|
54
|
+
// buyer picker widget (src/picker/widget/SeatPicker.ts)
|
|
67
55
|
"picker.floor": "Piso",
|
|
68
56
|
"picker.zoomLevel": "Nivel de zoom",
|
|
69
57
|
"picker.rungTip.zones": "Vista general \u2014 grupos de secciones como Grada norte o VIP",
|
|
@@ -78,31 +66,11 @@ var init_es = __esm({
|
|
|
78
66
|
"picker.seatsLeftInSection.other": "{count} asientos disponibles",
|
|
79
67
|
"picker.overview": "Descripci\xF3n general",
|
|
80
68
|
"picker.tapSeatHint": "Toca cualquier asiento para ver su vista",
|
|
81
|
-
"picker.chartSize": "Tama\xF1o del gr\xE1fico",
|
|
82
|
-
"picker.custom": "Personalizado",
|
|
83
|
-
"picker.categories": "Categor\xEDas",
|
|
84
|
-
"picker.accessibility": "Accesibilidad",
|
|
85
|
-
"picker.showAnyAccessible": "Mostrar cualquier asiento accesible",
|
|
86
|
-
"picker.any": "Cualquiera",
|
|
87
|
-
"picker.yourSeats": "Tus asientos",
|
|
88
|
-
"picker.emptySeats": "Toca asientos en el mapa",
|
|
89
|
-
"picker.emptySeatsWithGa": "Toca asientos en el mapa \xB7 toca un \xE1rea de pie para entradas de entrada general",
|
|
90
|
-
"picker.oneFewer": "Uno menos",
|
|
91
|
-
"picker.oneMore": "Uno m\xE1s",
|
|
92
|
-
"picker.remove": "Eliminar {label}",
|
|
93
69
|
"picker.ticketTierFor": "Categor\xEDa de entrada para {label}",
|
|
94
|
-
"picker.total": "Total: {amount}",
|
|
95
70
|
"picker.viewFromSeat": "Vista desde el asiento {label}",
|
|
96
71
|
"picker.real360": "REAL 360\xB0",
|
|
97
72
|
"picker.preview": "VISTA PREVIA",
|
|
98
|
-
"picker.open360": "Abrir vista de 360\xB0",
|
|
99
73
|
"picker.sightline": "\u2248 {m} m al escenario \xB7 visi\xF3n despejada",
|
|
100
|
-
"picker.bookedDemo": "\xA1Reservado! (demostraci\xF3n)",
|
|
101
|
-
"picker.bookButton.one": "Reservar {count} entrada \u2014 {amount}",
|
|
102
|
-
"picker.bookButton.other": "Reservar {count} entradas \u2014 {amount}",
|
|
103
|
-
"picker.simulateCrowd": "Simular multitud: {state}",
|
|
104
|
-
"picker.on": "ACTIVADO",
|
|
105
|
-
"picker.off": "DESACTIVADO",
|
|
106
74
|
"picker.panorama360": "Foto de 360\xB0 del lugar",
|
|
107
75
|
"picker.illustrationCaption": "ilustraci\xF3n \xB7 \u2248 {m} m del escenario",
|
|
108
76
|
"picker.restrictedView": "Visibilidad restringida",
|
|
@@ -131,29 +99,17 @@ var init_de = __esm({
|
|
|
131
99
|
"common.done": "Fertig",
|
|
132
100
|
"common.copied": "\u2713 Kopiert",
|
|
133
101
|
// buyer picker (extraction in progress — P4 of the port plan)
|
|
134
|
-
"picker.holdSeats": "Pl\xE4tze reservieren & Kasse",
|
|
135
|
-
"picker.completeBooking": "Buchung abschlie\xDFen",
|
|
136
|
-
"picker.seatsHeld": "Pl\xE4tze reserviert \u2014 {time}",
|
|
137
102
|
"picker.holdExpired": "Ihre Reservierung ist abgelaufen \u2014 die Pl\xE4tze wurden freigegeben. Bitte erneut ausw\xE4hlen.",
|
|
138
|
-
"picker.seatTaken": "Platz {label} wurde gerade von einem anderen K\xE4ufer gebucht.",
|
|
139
103
|
"picker.poweredBy": "Bereitgestellt von SeatLayer",
|
|
140
104
|
"picker.testMode": "TESTMODUS",
|
|
141
|
-
"picker.colorblind": "Farbenblind-freundliche Farben",
|
|
142
105
|
"picker.orphanHint": "Dadurch bleibt ein einzelner Platz \xFCbrig \u2014 r\xFCcken Sie ggf. einen Platz weiter.",
|
|
143
|
-
"picker.seats.one": "{count} Platz",
|
|
144
|
-
"picker.seats.other": "{count} Pl\xE4tze",
|
|
145
106
|
// renderer (drawn on the Konva map — shared by the embed SDK)
|
|
146
107
|
"map.aria": "Sitzplan. Mit Pfeiltasten zwischen Pl\xE4tzen navigieren, Eingabe zum Ausw\xE4hlen.",
|
|
147
108
|
"map.seatsLeft": "{count} FREI",
|
|
148
109
|
"map.statusHeld": "Reserviert",
|
|
149
110
|
"map.statusTaken": "Vergeben",
|
|
150
111
|
"map.fromPrice": "AB {price}",
|
|
151
|
-
// buyer picker
|
|
152
|
-
"picker.language": "Sprache",
|
|
153
|
-
"picker.zoomToFit": "Auf Gr\xF6\xDFe anpassen",
|
|
154
|
-
"picker.seatCountLabel": "Pl\xE4tze",
|
|
155
|
-
"picker.capacity": "Kapazit\xE4t",
|
|
156
|
-
"picker.viewMode": "Ansichtsmodus",
|
|
112
|
+
// buyer picker widget (src/picker/widget/SeatPicker.ts)
|
|
157
113
|
"picker.floor": "Etage",
|
|
158
114
|
"picker.zoomLevel": "Zoomstufe",
|
|
159
115
|
"picker.rungTip.zones": "\xDCbersicht \u2014 Bereichsgruppen wie Nordtrib\xFCne oder VIP",
|
|
@@ -168,31 +124,11 @@ var init_de = __esm({
|
|
|
168
124
|
"picker.seatsLeftInSection.other": "{count} Pl\xE4tze verf\xFCgbar",
|
|
169
125
|
"picker.overview": "\xDCbersicht",
|
|
170
126
|
"picker.tapSeatHint": "Tippen Sie auf einen Platz, um die Ansicht zu pr\xFCfen",
|
|
171
|
-
"picker.chartSize": "Kartengr\xF6\xDFe",
|
|
172
|
-
"picker.custom": "Benutzerdefiniert",
|
|
173
|
-
"picker.categories": "Kategorien",
|
|
174
|
-
"picker.accessibility": "Barrierefreiheit",
|
|
175
|
-
"picker.showAnyAccessible": "Jeden barrierefreien Platz anzeigen",
|
|
176
|
-
"picker.any": "Beliebig",
|
|
177
|
-
"picker.yourSeats": "Ihre Pl\xE4tze",
|
|
178
|
-
"picker.emptySeats": "Tippen Sie auf die Pl\xE4tze auf der Karte",
|
|
179
|
-
"picker.emptySeatsWithGa": "Tippen Sie auf die Pl\xE4tze auf der Karte \xB7 tippen Sie auf einen Stehbereich f\xFCr Stehplatztickets",
|
|
180
|
-
"picker.oneFewer": "Einen weniger",
|
|
181
|
-
"picker.oneMore": "Einen mehr",
|
|
182
|
-
"picker.remove": "{label} entfernen",
|
|
183
127
|
"picker.ticketTierFor": "Ticketklasse f\xFCr {label}",
|
|
184
|
-
"picker.total": "Gesamt: {amount}",
|
|
185
128
|
"picker.viewFromSeat": "Ansicht von Platz {label}",
|
|
186
129
|
"picker.real360": "REAL 360\xB0",
|
|
187
130
|
"picker.preview": "VORSCHAU",
|
|
188
|
-
"picker.open360": "\xD6ffnen Sie die 360\xB0-Ansicht",
|
|
189
131
|
"picker.sightline": "\u2248 {m} m zur B\xFChne \xB7 freie Sicht",
|
|
190
|
-
"picker.bookedDemo": "Gebucht! (Demo)",
|
|
191
|
-
"picker.bookButton.one": "{count} Ticket buchen \u2014 {amount}",
|
|
192
|
-
"picker.bookButton.other": "{count} Tickets buchen \u2014 {amount}",
|
|
193
|
-
"picker.simulateCrowd": "Menschenmenge simulieren: {state}",
|
|
194
|
-
"picker.on": "AN",
|
|
195
|
-
"picker.off": "AUS",
|
|
196
132
|
"picker.panorama360": "360\xB0-Veranstaltungsfotos",
|
|
197
133
|
"picker.illustrationCaption": "Illustration \xB7 \u2248 {m} m von der B\xFChne",
|
|
198
134
|
"picker.restrictedView": "Eingeschr\xE4nkte Sicht",
|
|
@@ -221,29 +157,17 @@ var init_fr = __esm({
|
|
|
221
157
|
"common.done": "Termin\xE9",
|
|
222
158
|
"common.copied": "\u2713 Copi\xE9",
|
|
223
159
|
// buyer picker (extraction in progress — P4 of the port plan)
|
|
224
|
-
"picker.holdSeats": "R\xE9server les si\xE8ges et valider",
|
|
225
|
-
"picker.completeBooking": "Terminer la r\xE9servation",
|
|
226
|
-
"picker.seatsHeld": "Si\xE8ges r\xE9serv\xE9s \u2014 {time}",
|
|
227
160
|
"picker.holdExpired": "Votre r\xE9servation a expir\xE9 \u2014 les si\xE8ges ont \xE9t\xE9 lib\xE9r\xE9s. S\xE9lectionnez \xE0 nouveau.",
|
|
228
|
-
"picker.seatTaken": "Le si\xE8ge {label} vient d'\xEAtre r\xE9serv\xE9 par un autre acheteur.",
|
|
229
161
|
"picker.poweredBy": "Propuls\xE9 par SeatLayer",
|
|
230
162
|
"picker.testMode": "MODE TEST",
|
|
231
|
-
"picker.colorblind": "Couleurs adapt\xE9es au daltonisme",
|
|
232
163
|
"picker.orphanHint": "Cela laisse un si\xE8ge isol\xE9 \u2014 pensez \xE0 vous d\xE9caler d'un si\xE8ge.",
|
|
233
|
-
"picker.seats.one": "{count} si\xE8ge",
|
|
234
|
-
"picker.seats.other": "{count} si\xE8ges",
|
|
235
164
|
// renderer (drawn on the Konva map — shared by the embed SDK)
|
|
236
165
|
"map.aria": "Plan de salle. Utilisez les fl\xE8ches pour naviguer entre les si\xE8ges, Entr\xE9e pour s\xE9lectionner.",
|
|
237
166
|
"map.seatsLeft": "{count} LIBRES",
|
|
238
167
|
"map.statusHeld": "En attente",
|
|
239
168
|
"map.statusTaken": "Pris",
|
|
240
169
|
"map.fromPrice": "D\xC8S {price}",
|
|
241
|
-
// buyer picker
|
|
242
|
-
"picker.language": "Langue",
|
|
243
|
-
"picker.zoomToFit": "Ajuster le zoom",
|
|
244
|
-
"picker.seatCountLabel": "si\xE8ges",
|
|
245
|
-
"picker.capacity": "capacit\xE9",
|
|
246
|
-
"picker.viewMode": "Mode d'affichage",
|
|
170
|
+
// buyer picker widget (src/picker/widget/SeatPicker.ts)
|
|
247
171
|
"picker.floor": "\xC9tage",
|
|
248
172
|
"picker.zoomLevel": "Niveau de zoom",
|
|
249
173
|
"picker.rungTip.zones": "Vue g\xE9n\xE9rale \u2014 groupes de sections comme Tribune nord ou VIP",
|
|
@@ -258,31 +182,11 @@ var init_fr = __esm({
|
|
|
258
182
|
"picker.seatsLeftInSection.other": "{count} si\xE8ges restants",
|
|
259
183
|
"picker.overview": "Vue d'ensemble",
|
|
260
184
|
"picker.tapSeatHint": "Appuyez sur un si\xE8ge pour v\xE9rifier sa vue",
|
|
261
|
-
"picker.chartSize": "Taille du plan",
|
|
262
|
-
"picker.custom": "Personnalis\xE9",
|
|
263
|
-
"picker.categories": "Cat\xE9gories",
|
|
264
|
-
"picker.accessibility": "Accessibilit\xE9",
|
|
265
|
-
"picker.showAnyAccessible": "Afficher un si\xE8ge accessible",
|
|
266
|
-
"picker.any": "N'importe quel",
|
|
267
|
-
"picker.yourSeats": "Vos si\xE8ges",
|
|
268
|
-
"picker.emptySeats": "Appuyez sur les si\xE8ges sur le plan",
|
|
269
|
-
"picker.emptySeatsWithGa": "Appuyez sur les si\xE8ges sur le plan \xB7 appuyez sur une zone debout pour les billets GA",
|
|
270
|
-
"picker.oneFewer": "Un de moins",
|
|
271
|
-
"picker.oneMore": "Un de plus",
|
|
272
|
-
"picker.remove": "Supprimer {label}",
|
|
273
185
|
"picker.ticketTierFor": "Cat\xE9gorie de billet pour {label}",
|
|
274
|
-
"picker.total": "Total : {amount}",
|
|
275
186
|
"picker.viewFromSeat": "Vue depuis le si\xE8ge {label}",
|
|
276
187
|
"picker.real360": "VRAI 360\xB0",
|
|
277
188
|
"picker.preview": "APER\xC7U",
|
|
278
|
-
"picker.open360": "Ouvrir la vue \xE0 360\xB0",
|
|
279
189
|
"picker.sightline": "\u2248 {m} m de la sc\xE8ne \xB7 vue d\xE9gag\xE9e",
|
|
280
|
-
"picker.bookedDemo": "R\xE9serv\xE9 ! (d\xE9mo)",
|
|
281
|
-
"picker.bookButton.one": "R\xE9server {count} billet \u2014 {amount}",
|
|
282
|
-
"picker.bookButton.other": "R\xE9server {count} billets \u2014 {amount}",
|
|
283
|
-
"picker.simulateCrowd": "Simuler la foule : {state}",
|
|
284
|
-
"picker.on": "ACTIV\xC9",
|
|
285
|
-
"picker.off": "D\xC9SACTIV\xC9",
|
|
286
190
|
"picker.panorama360": "Photo panoramique 360\xB0 du lieu",
|
|
287
191
|
"picker.illustrationCaption": "illustration \xB7 \u2248 {m} m de la sc\xE8ne",
|
|
288
192
|
"picker.restrictedView": "Visibilit\xE9 r\xE9duite",
|
|
@@ -343,6 +247,8 @@ __export(index_exports, {
|
|
|
343
247
|
pointInPolygonWithHoles: () => pointInPolygonWithHoles,
|
|
344
248
|
polygonLabelPoint: () => polygonLabelPoint,
|
|
345
249
|
resolveLocale: () => resolveLocale,
|
|
250
|
+
rowSeatPositions: () => rowSeatPositions,
|
|
251
|
+
seatLabelPart: () => seatLabelPart,
|
|
346
252
|
setLocale: () => setLocale,
|
|
347
253
|
setMoneyLocale: () => setMoneyLocale,
|
|
348
254
|
setStringOverrides: () => setStringOverrides,
|
|
@@ -465,6 +371,53 @@ function transformSectionOutlinePath(path, transform, radiusScale = 1, reflected
|
|
|
465
371
|
};
|
|
466
372
|
}
|
|
467
373
|
|
|
374
|
+
// src/core/labeling.ts
|
|
375
|
+
var FULL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
376
|
+
var LOWER_ALPHABET = "abcdefghijklmnopqrstuvwxyz";
|
|
377
|
+
function toBijectiveBase(index, alphabet) {
|
|
378
|
+
const base = alphabet.length;
|
|
379
|
+
let n = index + 1;
|
|
380
|
+
let out = "";
|
|
381
|
+
while (n > 0) {
|
|
382
|
+
n -= 1;
|
|
383
|
+
const rem = n % base;
|
|
384
|
+
out = alphabet[rem] + out;
|
|
385
|
+
n = Math.floor(n / base);
|
|
386
|
+
}
|
|
387
|
+
return out;
|
|
388
|
+
}
|
|
389
|
+
function toLetters(value, lower = false) {
|
|
390
|
+
const alphabet = lower ? LOWER_ALPHABET : FULL_ALPHABET;
|
|
391
|
+
return toBijectiveBase(Math.max(0, Math.floor(value) - 1), alphabet);
|
|
392
|
+
}
|
|
393
|
+
var ROMAN_TABLE = [
|
|
394
|
+
[1e3, "M"],
|
|
395
|
+
[900, "CM"],
|
|
396
|
+
[500, "D"],
|
|
397
|
+
[400, "CD"],
|
|
398
|
+
[100, "C"],
|
|
399
|
+
[90, "XC"],
|
|
400
|
+
[50, "L"],
|
|
401
|
+
[40, "XL"],
|
|
402
|
+
[10, "X"],
|
|
403
|
+
[9, "IX"],
|
|
404
|
+
[5, "V"],
|
|
405
|
+
[4, "IV"],
|
|
406
|
+
[1, "I"]
|
|
407
|
+
];
|
|
408
|
+
function toRoman(value) {
|
|
409
|
+
if (!Number.isFinite(value) || value <= 0) return String(value);
|
|
410
|
+
let remaining = Math.floor(value);
|
|
411
|
+
let out = "";
|
|
412
|
+
for (const [n, sym] of ROMAN_TABLE) {
|
|
413
|
+
while (remaining >= n) {
|
|
414
|
+
out += sym;
|
|
415
|
+
remaining -= n;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return out;
|
|
419
|
+
}
|
|
420
|
+
|
|
468
421
|
// src/core/layout.ts
|
|
469
422
|
function overrideAccessibility(o) {
|
|
470
423
|
if (!o) return [];
|
|
@@ -510,24 +463,62 @@ function overrideMap(row) {
|
|
|
510
463
|
if (row.overrides) for (const o of row.overrides) m.set(o.index, o);
|
|
511
464
|
return m;
|
|
512
465
|
}
|
|
513
|
-
function
|
|
514
|
-
const
|
|
466
|
+
function centerRank(n) {
|
|
467
|
+
const rank = new Array(n);
|
|
468
|
+
Array.from({ length: n }, (_, i) => i).sort((a, b) => Math.abs(2 * a - (n - 1)) - Math.abs(2 * b - (n - 1)) || a - b).forEach((idx, k) => rank[idx] = k);
|
|
469
|
+
return rank;
|
|
470
|
+
}
|
|
471
|
+
function seatLabelPart(row, i) {
|
|
472
|
+
const rawStart = row.seatLabelStart ?? 1;
|
|
515
473
|
const dir = row.seatNumbering?.direction ?? "ltr";
|
|
516
474
|
const step = row.seatNumbering?.step ?? 1;
|
|
475
|
+
const scheme = row.seatNumbering?.scheme ?? "decimal";
|
|
476
|
+
const prefix = row.seatNumbering?.prefix ?? "";
|
|
477
|
+
const endAt = row.seatNumbering?.endAt;
|
|
517
478
|
const n = row.seatCount;
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
const
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
479
|
+
if (scheme === "updown") {
|
|
480
|
+
const half = Math.ceil(n / 2);
|
|
481
|
+
const core2 = i < half ? rawStart + 2 * i : rawStart - 1 + 2 * (n - i);
|
|
482
|
+
return `${prefix}${core2}`;
|
|
483
|
+
}
|
|
484
|
+
const effStep = scheme === "odd" || scheme === "even" ? 2 : step;
|
|
485
|
+
const start = endAt != null && Number.isFinite(endAt) ? endAt - (n - 1) * effStep : rawStart;
|
|
486
|
+
const p = dir === "center" ? centerRank(n)[i] : dir === "rtl" ? n - 1 - i : i;
|
|
487
|
+
let core;
|
|
488
|
+
switch (scheme) {
|
|
489
|
+
case "odd": {
|
|
490
|
+
const firstOdd = start % 2 === 1 ? start : start + 1;
|
|
491
|
+
core = String(firstOdd + p * 2);
|
|
492
|
+
break;
|
|
493
|
+
}
|
|
494
|
+
case "even": {
|
|
495
|
+
const firstEven = start % 2 === 0 ? start : start + 1;
|
|
496
|
+
core = String(firstEven + p * 2);
|
|
497
|
+
break;
|
|
498
|
+
}
|
|
499
|
+
case "roman":
|
|
500
|
+
core = toRoman(start + p * step);
|
|
501
|
+
break;
|
|
502
|
+
case "letters-upper":
|
|
503
|
+
core = toLetters(start + p * step, false);
|
|
504
|
+
break;
|
|
505
|
+
case "letters-lower":
|
|
506
|
+
core = toLetters(start + p * step, true);
|
|
507
|
+
break;
|
|
508
|
+
case "decimal":
|
|
509
|
+
default:
|
|
510
|
+
core = String(start + p * step);
|
|
511
|
+
break;
|
|
525
512
|
}
|
|
513
|
+
return `${prefix}${core}`;
|
|
514
|
+
}
|
|
515
|
+
function expandRowSlots(row) {
|
|
526
516
|
const ov = overrideMap(row);
|
|
527
517
|
return rowSeatPositions(row).map((p, i) => {
|
|
528
518
|
const o = ov.get(i);
|
|
529
519
|
const accessibility = overrideAccessibility(o);
|
|
530
|
-
const
|
|
520
|
+
const part = seatLabelPart(row, i);
|
|
521
|
+
const inventoryLabel = o?.label ?? `${row.label}-${part}`;
|
|
531
522
|
const displayPrefix = row.displayLabel ?? row.label;
|
|
532
523
|
const commercial = { ...row.commercial, ...o?.commercial };
|
|
533
524
|
return {
|
|
@@ -535,7 +526,7 @@ function expandRowSlots(row) {
|
|
|
535
526
|
x: p.x + (o?.dx ?? 0),
|
|
536
527
|
y: p.y + (o?.dy ?? 0),
|
|
537
528
|
label: inventoryLabel,
|
|
538
|
-
displayLabel: o?.displayLabel ?? `${displayPrefix}-${
|
|
529
|
+
displayLabel: o?.displayLabel ?? `${displayPrefix}-${part}`,
|
|
539
530
|
categoryKey: o?.categoryKey ?? row.categoryKey,
|
|
540
531
|
skipped: !!o?.skip,
|
|
541
532
|
accessible: accessibility.length > 0,
|
|
@@ -1002,6 +993,7 @@ var import_Rect = require("konva/lib/shapes/Rect");
|
|
|
1002
993
|
var import_Ellipse = require("konva/lib/shapes/Ellipse");
|
|
1003
994
|
var import_Line = require("konva/lib/shapes/Line");
|
|
1004
995
|
var import_Text = require("konva/lib/shapes/Text");
|
|
996
|
+
var import_Path = require("konva/lib/shapes/Path");
|
|
1005
997
|
var import_Image = require("konva/lib/shapes/Image");
|
|
1006
998
|
var import_Shape = require("konva/lib/Shape");
|
|
1007
999
|
|
|
@@ -1018,6 +1010,8 @@ var LIGHT_BOOKABLE_LABEL_INK = "#ffffff";
|
|
|
1018
1010
|
function isBookableLabelLegibleAtScale(fontSize, effectiveScale) {
|
|
1019
1011
|
return fontSize * effectiveScale >= MIN_VISIBLE_BOOKABLE_LABEL_PX;
|
|
1020
1012
|
}
|
|
1013
|
+
var ACCESS_GLYPH_VIEWBOX = 24;
|
|
1014
|
+
var ACCESS_GLYPH_PATH = "M12 2c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm9 7h-6v13h-2v-6h-2v6H9V9H3V7h18v2z";
|
|
1021
1015
|
function bookableMarkerLabel(publicLabel) {
|
|
1022
1016
|
return /-(\d{1,5})$/.exec(publicLabel)?.[1] ?? publicLabel;
|
|
1023
1017
|
}
|
|
@@ -1097,29 +1091,17 @@ var en = {
|
|
|
1097
1091
|
"common.done": "Done",
|
|
1098
1092
|
"common.copied": "\u2713 Copied",
|
|
1099
1093
|
// buyer picker
|
|
1100
|
-
"picker.holdSeats": "Hold seats & checkout",
|
|
1101
|
-
"picker.completeBooking": "Complete booking",
|
|
1102
|
-
"picker.seatsHeld": "Seats held \u2014 {time}",
|
|
1103
1094
|
"picker.holdExpired": "Your hold expired \u2014 the seats were released. Pick again.",
|
|
1104
|
-
"picker.seatTaken": "Seat {label} was just taken by another buyer.",
|
|
1105
1095
|
"picker.poweredBy": "Powered by SeatLayer",
|
|
1106
1096
|
"picker.testMode": "TEST MODE",
|
|
1107
|
-
"picker.colorblind": "Colorblind-friendly colors",
|
|
1108
1097
|
"picker.orphanHint": "This leaves a single seat stranded \u2014 consider shifting one seat over.",
|
|
1109
|
-
"picker.seats.one": "{count} seat",
|
|
1110
|
-
"picker.seats.other": "{count} seats",
|
|
1111
1098
|
// renderer (drawn on the Konva map — shared by the embed SDK)
|
|
1112
1099
|
"map.aria": "Seating map. Use arrow keys to move between seats, Enter to select.",
|
|
1113
1100
|
"map.seatsLeft": "{count} LEFT",
|
|
1114
1101
|
"map.fromPrice": "FROM {price}",
|
|
1115
1102
|
"map.statusHeld": "On hold",
|
|
1116
1103
|
"map.statusTaken": "Taken",
|
|
1117
|
-
// buyer picker
|
|
1118
|
-
"picker.language": "Language",
|
|
1119
|
-
"picker.zoomToFit": "Zoom to fit",
|
|
1120
|
-
"picker.seatCountLabel": "seats",
|
|
1121
|
-
"picker.capacity": "capacity",
|
|
1122
|
-
"picker.viewMode": "View mode",
|
|
1104
|
+
// buyer picker widget (src/picker/widget/SeatPicker.ts)
|
|
1123
1105
|
"picker.floor": "Floor",
|
|
1124
1106
|
"picker.zoomLevel": "Zoom level",
|
|
1125
1107
|
"picker.rungTip.zones": "Venue overview \u2014 groups of sections such as North Stand or VIP",
|
|
@@ -1134,31 +1116,11 @@ var en = {
|
|
|
1134
1116
|
"picker.seatsLeftInSection.other": "{count} seats left",
|
|
1135
1117
|
"picker.overview": "Overview",
|
|
1136
1118
|
"picker.tapSeatHint": "Tap any seat to check its view",
|
|
1137
|
-
"picker.chartSize": "Chart size",
|
|
1138
|
-
"picker.custom": "Custom",
|
|
1139
|
-
"picker.categories": "Categories",
|
|
1140
|
-
"picker.accessibility": "Accessibility",
|
|
1141
|
-
"picker.showAnyAccessible": "Show any accessible seat",
|
|
1142
|
-
"picker.any": "Any",
|
|
1143
|
-
"picker.yourSeats": "Your seats",
|
|
1144
|
-
"picker.emptySeats": "Tap seats on the map",
|
|
1145
|
-
"picker.emptySeatsWithGa": "Tap seats on the map \xB7 tap a standing area for GA tickets",
|
|
1146
|
-
"picker.oneFewer": "One fewer",
|
|
1147
|
-
"picker.oneMore": "One more",
|
|
1148
|
-
"picker.remove": "Remove {label}",
|
|
1149
1119
|
"picker.ticketTierFor": "Ticket tier for {label}",
|
|
1150
|
-
"picker.total": "Total: {amount}",
|
|
1151
1120
|
"picker.viewFromSeat": "View from seat {label}",
|
|
1152
1121
|
"picker.real360": "REAL 360\xB0",
|
|
1153
1122
|
"picker.preview": "PREVIEW",
|
|
1154
|
-
"picker.open360": "Open 360\xB0 view",
|
|
1155
1123
|
"picker.sightline": "\u2248 {m} m to stage \xB7 clear sightline",
|
|
1156
|
-
"picker.bookedDemo": "Booked! (demo)",
|
|
1157
|
-
"picker.bookButton.one": "Book {count} ticket \u2014 {amount}",
|
|
1158
|
-
"picker.bookButton.other": "Book {count} tickets \u2014 {amount}",
|
|
1159
|
-
"picker.simulateCrowd": "Simulate crowd: {state}",
|
|
1160
|
-
"picker.on": "ON",
|
|
1161
|
-
"picker.off": "OFF",
|
|
1162
1124
|
"picker.panorama360": "360\xB0 venue photo",
|
|
1163
1125
|
"picker.illustrationCaption": "illustration \xB7 \u2248 {m} m from stage",
|
|
1164
1126
|
"picker.restrictedView": "Restricted view",
|
|
@@ -1217,6 +1179,7 @@ var CACHE_THRESHOLD = 0.55 * SEAT_LEGIBLE_SCALE;
|
|
|
1217
1179
|
var LABEL_SCALE = MIN_VISIBLE_BOOKABLE_LABEL_PX / SEAT_LABEL_FONT_SIZE;
|
|
1218
1180
|
var MIN_FITTED_SEAT_LABEL_FONT_SIZE = 4;
|
|
1219
1181
|
var SEAT_TAP_SLOP_PX = 14;
|
|
1182
|
+
var SEAT_GLYPH_MIN_PX = 6.5;
|
|
1220
1183
|
var SECTION_PROMINENT_SCALE = 0.45 * SEAT_LEGIBLE_SCALE;
|
|
1221
1184
|
var BLOCK_MELT_TOP = 0.9 * SEAT_LEGIBLE_SCALE;
|
|
1222
1185
|
var SEAT_FOCUS_SCALE = Math.max(SEAT_LEGIBLE_SCALE * 1.1, BLOCK_MELT_TOP);
|
|
@@ -1506,6 +1469,15 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
1506
1469
|
this.boothLabelById = /* @__PURE__ */ new Map();
|
|
1507
1470
|
/** Viewport seat labels are rebuilt after each settled camera change. */
|
|
1508
1471
|
this.seatLabelById = /* @__PURE__ */ new Map();
|
|
1472
|
+
/** Coloured accommodation ring per accessible seat (few per chart). */
|
|
1473
|
+
this.accessRingById = /* @__PURE__ */ new Map();
|
|
1474
|
+
/** Centred accessibility glyph per accessible seat — shown once the seat is
|
|
1475
|
+
* big enough on-screen (see {@link SEAT_GLYPH_MIN_PX}); the ring is the
|
|
1476
|
+
* smaller-zoom fallback. Kept in a map so zoom toggles touch only the handful
|
|
1477
|
+
* of accessible seats, never all 13k nodes. */
|
|
1478
|
+
this.accessGlyphById = /* @__PURE__ */ new Map();
|
|
1479
|
+
/** Whether the accessibility glyph is legible at the current camera scale. */
|
|
1480
|
+
this.accessGlyphVisible = false;
|
|
1509
1481
|
/** Authored free-text nodes obey the same rendered-size visibility floor. */
|
|
1510
1482
|
this.freeTextById = /* @__PURE__ */ new Map();
|
|
1511
1483
|
/** Stage/rink landmarks retain a readable screen-space caption at overview. */
|
|
@@ -1818,6 +1790,8 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
1818
1790
|
this.boothDims.clear();
|
|
1819
1791
|
this.boothLabelById.clear();
|
|
1820
1792
|
this.seatLabelById.clear();
|
|
1793
|
+
this.accessRingById.clear();
|
|
1794
|
+
this.accessGlyphById.clear();
|
|
1821
1795
|
this.freeTextById.clear();
|
|
1822
1796
|
this.primaryFocalLabels.clear();
|
|
1823
1797
|
this.gaById.clear();
|
|
@@ -2726,18 +2700,21 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
2726
2700
|
this.paintSeat(c, seat.id);
|
|
2727
2701
|
target.add(c);
|
|
2728
2702
|
if (seat.accessible) {
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
);
|
|
2703
|
+
const ring = new import_Circle.Circle({
|
|
2704
|
+
x: seat.x,
|
|
2705
|
+
y: seat.y,
|
|
2706
|
+
radius: this.seatR + 1.5,
|
|
2707
|
+
stroke: accessibilityRingColor(seat.accessibility),
|
|
2708
|
+
strokeWidth: 2.5,
|
|
2709
|
+
listening: false,
|
|
2710
|
+
perfectDrawEnabled: false,
|
|
2711
|
+
shadowForStrokeEnabled: false
|
|
2712
|
+
});
|
|
2713
|
+
this.accessRingById.set(seat.id, ring);
|
|
2714
|
+
target.add(ring);
|
|
2715
|
+
const glyph = this.buildAccessGlyph(seat, typeof c.fill() === "string" ? c.fill() : "");
|
|
2716
|
+
this.accessGlyphById.set(seat.id, glyph);
|
|
2717
|
+
target.add(glyph);
|
|
2741
2718
|
}
|
|
2742
2719
|
}
|
|
2743
2720
|
}
|
|
@@ -2781,6 +2758,53 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
2781
2758
|
target.add(t2);
|
|
2782
2759
|
this.paintSeat(rect, seat.id);
|
|
2783
2760
|
}
|
|
2761
|
+
/**
|
|
2762
|
+
* Build the centred accessibility glyph for a seat. Sized relative to the seat
|
|
2763
|
+
* radius (so it always fills the marker at any zoom) and given a contrast-aware
|
|
2764
|
+
* fill against the seat's paint — recomputed per state in {@link paintSeat}.
|
|
2765
|
+
*/
|
|
2766
|
+
buildAccessGlyph(seat, seatFill) {
|
|
2767
|
+
const k = this.seatR * 1.5 / ACCESS_GLYPH_VIEWBOX;
|
|
2768
|
+
return new import_Path.Path({
|
|
2769
|
+
x: seat.x,
|
|
2770
|
+
y: seat.y,
|
|
2771
|
+
data: ACCESS_GLYPH_PATH,
|
|
2772
|
+
offsetX: ACCESS_GLYPH_VIEWBOX / 2,
|
|
2773
|
+
offsetY: ACCESS_GLYPH_VIEWBOX / 2,
|
|
2774
|
+
scaleX: k,
|
|
2775
|
+
scaleY: k,
|
|
2776
|
+
fill: stateAwareBookableLabelInk(seatFill, "#ffffff"),
|
|
2777
|
+
listening: false,
|
|
2778
|
+
visible: this.accessGlyphVisible,
|
|
2779
|
+
perfectDrawEnabled: false,
|
|
2780
|
+
shadowForStrokeEnabled: false
|
|
2781
|
+
});
|
|
2782
|
+
}
|
|
2783
|
+
/**
|
|
2784
|
+
* Toggle the accessibility glyphs for the current camera scale: shown once the
|
|
2785
|
+
* effective on-screen seat radius clears {@link SEAT_GLYPH_MIN_PX}, otherwise
|
|
2786
|
+
* hidden so only the ring remains. Iterates the (small) accessible-seat set,
|
|
2787
|
+
* never the full node graph, so it is cheap to call on every view change.
|
|
2788
|
+
*/
|
|
2789
|
+
updateAccessGlyphs(scale) {
|
|
2790
|
+
if (!this.accessGlyphById.size) return;
|
|
2791
|
+
this.accessGlyphVisible = this.seatR * scale >= SEAT_GLYPH_MIN_PX;
|
|
2792
|
+
for (const [id, glyph] of this.accessGlyphById) {
|
|
2793
|
+
glyph.visible(this.accessGlyphVisible && this.accessGlyphEligible(id));
|
|
2794
|
+
}
|
|
2795
|
+
}
|
|
2796
|
+
/**
|
|
2797
|
+
* Whether an accessible seat's glyph should show for its current status. It is
|
|
2798
|
+
* hidden on seats a buyer cannot take (sold, or another buyer's hold) where the
|
|
2799
|
+
* overlay status cue (diagonal mark / lock) carries the state instead — mirrors
|
|
2800
|
+
* the `unavailable` test in {@link updateLabels} so the two never collide.
|
|
2801
|
+
*/
|
|
2802
|
+
accessGlyphEligible(id) {
|
|
2803
|
+
const status = this.statusById.get(id) ?? "free";
|
|
2804
|
+
if (status === "booked") return false;
|
|
2805
|
+
if (status === "held" && !this.ownedHold.has(id) && !this.opts.manageMode) return false;
|
|
2806
|
+
return true;
|
|
2807
|
+
}
|
|
2784
2808
|
/** The category's display color — Okabe-Ito hue when colorblind-safe is on. */
|
|
2785
2809
|
seatBaseColor(categoryKey) {
|
|
2786
2810
|
if (!this.colorblind) return this.catColor.get(categoryKey) ?? "#6e7bff";
|
|
@@ -2894,6 +2918,14 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
2894
2918
|
isBookableLabelLegibleAtScale(bookableLabel.fontSize(), this.effScale()) && c.opacity() >= 0.5
|
|
2895
2919
|
);
|
|
2896
2920
|
}
|
|
2921
|
+
const accessGlyph = this.accessGlyphById.get(id);
|
|
2922
|
+
if (accessGlyph) {
|
|
2923
|
+
const fill = c.fill();
|
|
2924
|
+
accessGlyph.fill(stateAwareBookableLabelInk(typeof fill === "string" ? fill : "", "#ffffff"));
|
|
2925
|
+
accessGlyph.opacity(c.opacity());
|
|
2926
|
+
accessGlyph.visible(this.accessGlyphVisible && this.accessGlyphEligible(id));
|
|
2927
|
+
}
|
|
2928
|
+
this.accessRingById.get(id)?.opacity(c.opacity());
|
|
2897
2929
|
}
|
|
2898
2930
|
/** True when a seat sits in a section/zone currently marked `closed`. */
|
|
2899
2931
|
seatInClosedSection(id) {
|
|
@@ -4619,6 +4651,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
4619
4651
|
if (this.hasSections) this.applySectionLod(scale);
|
|
4620
4652
|
else if (this.primaryFocalLabels.size) this.bgLayer.batchDraw();
|
|
4621
4653
|
this.paintGAStateForView();
|
|
4654
|
+
this.updateAccessGlyphs(scale);
|
|
4622
4655
|
const shouldCache = scale < CACHE_THRESHOLD;
|
|
4623
4656
|
if (shouldCache && !this.cached) {
|
|
4624
4657
|
this.cacheSeatLayer();
|
|
@@ -4701,6 +4734,7 @@ var _SeatmapRenderer = class _SeatmapRenderer {
|
|
|
4701
4734
|
for (const seat of this.seats) {
|
|
4702
4735
|
if (seat.kind === "booth") continue;
|
|
4703
4736
|
if (seat.x < x0 || seat.x > x1 || seat.y < y0 || seat.y > y1) continue;
|
|
4737
|
+
if (seat.accessible && this.accessGlyphVisible) continue;
|
|
4704
4738
|
const shape = this.circleById.get(seat.id);
|
|
4705
4739
|
if ((shape?.opacity() ?? 1) < 0.5) continue;
|
|
4706
4740
|
const status = this.statusById.get(seat.id) ?? "free";
|
|
@@ -5050,9 +5084,11 @@ var PickerController = class {
|
|
|
5050
5084
|
this.allIds.push(s.id);
|
|
5051
5085
|
const source = chartObjects.get(s.rowId);
|
|
5052
5086
|
const sourceLabel = source && "label" in source && typeof source.label === "string" ? source.label : void 0;
|
|
5053
|
-
const
|
|
5054
|
-
const
|
|
5055
|
-
const
|
|
5087
|
+
const sourceDisplayLabel = source && "displayLabel" in source && typeof source.displayLabel === "string" && source.displayLabel ? source.displayLabel : sourceLabel;
|
|
5088
|
+
const rowLabel = s.kind === "booth" ? void 0 : sourceDisplayLabel;
|
|
5089
|
+
const visibleSeatLabel = s.displayLabel ?? s.label;
|
|
5090
|
+
const labelParts = visibleSeatLabel.split("-");
|
|
5091
|
+
const seatNumber = sourceDisplayLabel && visibleSeatLabel.startsWith(`${sourceDisplayLabel}-`) ? visibleSeatLabel.slice(sourceDisplayLabel.length + 1) : s.kind === "booth" ? visibleSeatLabel : labelParts[labelParts.length - 1] ?? visibleSeatLabel;
|
|
5056
5092
|
this.seatContext.set(s.id, {
|
|
5057
5093
|
sectionLabel: sectionLabels.get(membership.objectToSection.get(s.rowId) ?? ""),
|
|
5058
5094
|
rowLabel,
|
|
@@ -5722,14 +5758,16 @@ var PickerController = class {
|
|
|
5722
5758
|
// ---- internals ------------------------------------------------------------
|
|
5723
5759
|
toSeat(s) {
|
|
5724
5760
|
const commercial = s.commercial ? { commercial: s.commercial } : void 0;
|
|
5761
|
+
const display = s.displayLabel ? { displayLabel: s.displayLabel } : void 0;
|
|
5725
5762
|
const tiers = this.tiersFor(s.categoryKey);
|
|
5726
5763
|
if (!tiers) {
|
|
5727
|
-
return { id: s.id, label: s.label, categoryKey: s.categoryKey, price: this.priceFor(s.categoryKey), ...commercial };
|
|
5764
|
+
return { id: s.id, label: s.label, ...display, categoryKey: s.categoryKey, price: this.priceFor(s.categoryKey), ...commercial };
|
|
5728
5765
|
}
|
|
5729
5766
|
const chosen = tiers.find((t2) => t2.id === this.seatTiers.get(s.id)) ?? tiers[0];
|
|
5730
5767
|
return {
|
|
5731
5768
|
id: s.id,
|
|
5732
5769
|
label: s.label,
|
|
5770
|
+
...display,
|
|
5733
5771
|
categoryKey: s.categoryKey,
|
|
5734
5772
|
price: chosen.price,
|
|
5735
5773
|
tiers,
|
|
@@ -6290,6 +6328,8 @@ async function loadLocale(code) {
|
|
|
6290
6328
|
pointInPolygonWithHoles,
|
|
6291
6329
|
polygonLabelPoint,
|
|
6292
6330
|
resolveLocale,
|
|
6331
|
+
rowSeatPositions,
|
|
6332
|
+
seatLabelPart,
|
|
6293
6333
|
setLocale,
|
|
6294
6334
|
setMoneyLocale,
|
|
6295
6335
|
setStringOverrides,
|