@seatlayer/core 0.1.4 → 0.3.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.
@@ -12,6 +12,7 @@ var de = {
12
12
  "picker.holdExpired": "Ihre Reservierung ist abgelaufen \u2014 die Pl\xE4tze wurden freigegeben. Bitte erneut ausw\xE4hlen.",
13
13
  "picker.seatTaken": "Platz {label} wurde gerade von einem anderen K\xE4ufer gebucht.",
14
14
  "picker.poweredBy": "Bereitgestellt von SeatLayer",
15
+ "picker.testMode": "TESTMODUS",
15
16
  "picker.colorblind": "Farbenblind-freundliche Farben",
16
17
  "picker.orphanHint": "Dadurch bleibt ein einzelner Platz \xFCbrig \u2014 r\xFCcken Sie ggf. einen Platz weiter.",
17
18
  "picker.seats.one": "{count} Platz",
@@ -69,4 +70,4 @@ var de = {
69
70
  export {
70
71
  de
71
72
  };
72
- //# sourceMappingURL=de-A4KJQ374.js.map
73
+ //# sourceMappingURL=de-YMAVF5S2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/i18n/locales/de.ts"],"sourcesContent":["/**\n * German bundle — native-quality translations of the English reference dictionary.\n * Keys are identical to en.ts; values are translated to German (de).\n *\n * Conventions:\n * - flat dot-namespaced keys: \"<surface>.<element>\" (picker.holdSeats)\n * - {name} interpolation, {count} reserved for tCount plural keys\n * - plural keys end in \".one\" / \".other\" (Intl.PluralRules categories)\n */\n\nimport type { Dict } from '../index';\n\nexport const de: Dict = {\n // shared\n 'common.cancel': 'Abbrechen',\n 'common.close': 'Schließen',\n 'common.done': 'Fertig',\n 'common.copied': '✓ Kopiert',\n\n // buyer picker (extraction in progress — P4 of the port plan)\n 'picker.holdSeats': 'Plätze reservieren & Kasse',\n 'picker.completeBooking': 'Buchung abschließen',\n 'picker.seatsHeld': 'Plätze reserviert — {time}',\n 'picker.holdExpired': 'Ihre Reservierung ist abgelaufen — die Plätze wurden freigegeben. Bitte erneut auswählen.',\n 'picker.seatTaken': 'Platz {label} wurde gerade von einem anderen Käufer gebucht.',\n 'picker.poweredBy': 'Bereitgestellt von SeatLayer',\n 'picker.testMode': 'TESTMODUS',\n 'picker.colorblind': 'Farbenblind-freundliche Farben',\n 'picker.orphanHint': 'Dadurch bleibt ein einzelner Platz übrig — rücken Sie ggf. einen Platz weiter.',\n 'picker.seats.one': '{count} Platz',\n 'picker.seats.other': '{count} Plätze',\n\n // renderer (drawn on the Konva map — shared by the embed SDK)\n 'map.aria': 'Sitzplan. Mit Pfeiltasten zwischen Plätzen navigieren, Eingabe zum Auswählen.',\n 'map.seatsLeft': '{count} FREI',\n 'map.fromPrice': 'AB {price}',\n\n // buyer picker page (src/pages/PickerPage.tsx)\n 'picker.language': 'Sprache',\n 'picker.zoomToFit': 'Auf Größe anpassen',\n 'picker.viewMode': 'Ansichtsmodus',\n 'picker.floor': 'Etage',\n 'picker.zoomLevel': 'Zoomstufe',\n 'picker.rungTip.zones': 'Fernste Stufe — Zonen-Blöcke (Etage / Unteres Parterre / Oberes Parterre)',\n 'picker.rungTip.sections': 'Bereichs-Blöcke — Kategoriesortierung + Verfügbarkeitstönung',\n 'picker.rungTip.seats': 'Einzelne Plätze — Blöcke lösen sich zu Punkten auf',\n 'picker.rungLabel.zones': 'ZONEN',\n 'picker.rungLabel.sections': 'BEREICHE',\n 'picker.rungLabel.seats': 'PLÄTZE',\n 'picker.sectionSummaryAria': 'Bereichszusammenfassung {label}',\n 'picker.closeSectionSummary': 'Bereichszusammenfassung schließen',\n 'picker.seatsLeftInSection.one': '{count} Platz verfügbar',\n 'picker.seatsLeftInSection.other': '{count} Plätze verfügbar',\n 'picker.overview': 'Übersicht',\n 'picker.tapSeatHint': 'Tippen Sie auf einen Platz, um die Ansicht zu prüfen',\n 'picker.chartSize': 'Kartengröße',\n 'picker.custom': 'Benutzerdefiniert',\n 'picker.categories': 'Kategorien',\n 'picker.accessibility': 'Barrierefreiheit',\n 'picker.showAnyAccessible': 'Jeden barrierefreien Platz anzeigen',\n 'picker.any': 'Beliebig',\n 'picker.yourSeats': 'Ihre Plätze',\n 'picker.emptySeats': 'Tippen Sie auf die Plätze auf der Karte',\n 'picker.emptySeatsWithGa': 'Tippen Sie auf die Plätze auf der Karte · tippen Sie auf einen Stehbereich für Stehplatztickets',\n 'picker.oneFewer': 'Einen weniger',\n 'picker.oneMore': 'Einen mehr',\n 'picker.remove': '{label} entfernen',\n 'picker.ticketTierFor': 'Ticketklasse für {label}',\n 'picker.total': 'Gesamt: {amount}',\n 'picker.viewFromSeat': 'Ansicht von Platz {label}',\n 'picker.real360': 'REAL 360°',\n 'picker.preview': 'VORSCHAU',\n 'picker.open360': 'Öffnen Sie die 360°-Ansicht',\n 'picker.sightline': '≈ {rows} Reihen von der Bühne · {angle}° seitlich versetzt',\n 'picker.bookedDemo': 'Gebucht! (Demo)',\n 'picker.bookButton.one': '{count} Ticket buchen — {amount}',\n 'picker.bookButton.other': '{count} Tickets buchen — {amount}',\n 'picker.simulateCrowd': 'Menschenmenge simulieren: {state}',\n 'picker.on': 'AN',\n 'picker.off': 'AUS',\n 'picker.panorama360': '360°-Veranstaltungsfotos',\n 'picker.illustrationCaption': 'Illustration · ≈ {m} m von der Bühne',\n};\n"],"mappings":";AAYO,IAAM,KAAW;AAAA;AAAA,EAEtB,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,iBAAiB;AAAA;AAAA,EAGjB,oBAAoB;AAAA,EACpB,0BAA0B;AAAA,EAC1B,oBAAoB;AAAA,EACpB,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,mBAAmB;AAAA,EACnB,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,oBAAoB;AAAA,EACpB,sBAAsB;AAAA;AAAA,EAGtB,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,iBAAiB;AAAA;AAAA,EAGjB,mBAAmB;AAAA,EACnB,oBAAoB;AAAA,EACpB,mBAAmB;AAAA,EACnB,gBAAgB;AAAA,EAChB,oBAAoB;AAAA,EACpB,wBAAwB;AAAA,EACxB,2BAA2B;AAAA,EAC3B,wBAAwB;AAAA,EACxB,0BAA0B;AAAA,EAC1B,6BAA6B;AAAA,EAC7B,0BAA0B;AAAA,EAC1B,6BAA6B;AAAA,EAC7B,8BAA8B;AAAA,EAC9B,iCAAiC;AAAA,EACjC,mCAAmC;AAAA,EACnC,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,wBAAwB;AAAA,EACxB,4BAA4B;AAAA,EAC5B,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,2BAA2B;AAAA,EAC3B,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,wBAAwB;AAAA,EACxB,gBAAgB;AAAA,EAChB,uBAAuB;AAAA,EACvB,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,yBAAyB;AAAA,EACzB,2BAA2B;AAAA,EAC3B,wBAAwB;AAAA,EACxB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,sBAAsB;AAAA,EACtB,8BAA8B;AAChC;","names":[]}
@@ -12,6 +12,7 @@ var es = {
12
12
  "picker.holdExpired": "Tu retenci\xF3n expir\xF3 \u2014 los asientos fueron liberados. Elige de nuevo.",
13
13
  "picker.seatTaken": "El asiento {label} fue tomado por otro comprador.",
14
14
  "picker.poweredBy": "Con la tecnolog\xEDa de SeatLayer",
15
+ "picker.testMode": "MODO DE PRUEBA",
15
16
  "picker.colorblind": "Colores aptos para daltonismo",
16
17
  "picker.orphanHint": "Esto deja un asiento aislado \u2014 considera desplazarte un asiento.",
17
18
  "picker.seats.one": "{count} asiento",
@@ -69,4 +70,4 @@ var es = {
69
70
  export {
70
71
  es
71
72
  };
72
- //# sourceMappingURL=es-YNYMMP37.js.map
73
+ //# sourceMappingURL=es-MLM3IFIY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/i18n/locales/es.ts"],"sourcesContent":["/**\n * Spanish (es) bundle — neutral/international Spanish translation.\n * Follows the same key structure as en.ts; all placeholders and brand\n * names preserved.\n */\n\nimport type { Dict } from '../index';\n\nexport const es: Dict = {\n // shared\n 'common.cancel': 'Cancelar',\n 'common.close': 'Cerrar',\n 'common.done': 'Listo',\n 'common.copied': '✓ Copiado',\n\n // buyer picker (extraction in progress — P4 of the port plan)\n 'picker.holdSeats': 'Retener asientos y comprar',\n 'picker.completeBooking': 'Completar reserva',\n 'picker.seatsHeld': 'Asientos retenidos — {time}',\n 'picker.holdExpired': 'Tu retención expiró — los asientos fueron liberados. Elige de nuevo.',\n 'picker.seatTaken': 'El asiento {label} fue tomado por otro comprador.',\n 'picker.poweredBy': 'Con la tecnología de SeatLayer',\n 'picker.testMode': 'MODO DE PRUEBA',\n 'picker.colorblind': 'Colores aptos para daltonismo',\n 'picker.orphanHint': 'Esto deja un asiento aislado — considera desplazarte un asiento.',\n 'picker.seats.one': '{count} asiento',\n 'picker.seats.other': '{count} asientos',\n\n // renderer (drawn on the Konva map — shared by the embed SDK)\n 'map.aria': 'Mapa de asientos. Usa las flechas para moverte entre asientos, Intro para seleccionar.',\n 'map.seatsLeft': '{count} LIBRES',\n 'map.fromPrice': 'DESDE {price}',\n\n // buyer picker page (src/pages/PickerPage.tsx)\n 'picker.language': 'Idioma',\n 'picker.zoomToFit': 'Ajustar zoom',\n 'picker.viewMode': 'Modo de vista',\n 'picker.floor': 'Piso',\n 'picker.zoomLevel': 'Nivel de zoom',\n 'picker.rungTip.zones': 'Nivel más lejano — bloques de zona (Piso / Patio Bajo / Patio Alto)',\n 'picker.rungTip.sections': 'Bloques de sección — mezcla de categorías + matiz de disponibilidad',\n 'picker.rungTip.seats': 'Asientos individuales — los bloques se convierten en puntos',\n 'picker.rungLabel.zones': 'ZONAS',\n 'picker.rungLabel.sections': 'SECCIONES',\n 'picker.rungLabel.seats': 'ASIENTOS',\n 'picker.sectionSummaryAria': 'Resumen de sección {label}',\n 'picker.closeSectionSummary': 'Cerrar resumen de sección',\n 'picker.seatsLeftInSection.one': '{count} asiento disponible',\n 'picker.seatsLeftInSection.other': '{count} asientos disponibles',\n 'picker.overview': 'Descripción general',\n 'picker.tapSeatHint': 'Toca cualquier asiento para ver su vista',\n 'picker.chartSize': 'Tamaño del gráfico',\n 'picker.custom': 'Personalizado',\n 'picker.categories': 'Categorías',\n 'picker.accessibility': 'Accesibilidad',\n 'picker.showAnyAccessible': 'Mostrar cualquier asiento accesible',\n 'picker.any': 'Cualquiera',\n 'picker.yourSeats': 'Tus asientos',\n 'picker.emptySeats': 'Toca asientos en el mapa',\n 'picker.emptySeatsWithGa': 'Toca asientos en el mapa · toca un área de pie para entradas de entrada general',\n 'picker.oneFewer': 'Uno menos',\n 'picker.oneMore': 'Uno más',\n 'picker.remove': 'Eliminar {label}',\n 'picker.ticketTierFor': 'Categoría de entrada para {label}',\n 'picker.total': 'Total: {amount}',\n 'picker.viewFromSeat': 'Vista desde el asiento {label}',\n 'picker.real360': 'REAL 360°',\n 'picker.preview': 'VISTA PREVIA',\n 'picker.open360': 'Abrir vista de 360°',\n 'picker.sightline': '≈ {rows} filas del escenario · {angle}° fuera del centro',\n 'picker.bookedDemo': '¡Reservado! (demostración)',\n 'picker.bookButton.one': 'Reservar {count} entrada — {amount}',\n 'picker.bookButton.other': 'Reservar {count} entradas — {amount}',\n 'picker.simulateCrowd': 'Simular multitud: {state}',\n 'picker.on': 'ACTIVADO',\n 'picker.off': 'DESACTIVADO',\n 'picker.panorama360': 'Foto de 360° del lugar',\n 'picker.illustrationCaption': 'ilustración · ≈ {m} m del escenario',\n};\n"],"mappings":";AAQO,IAAM,KAAW;AAAA;AAAA,EAEtB,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,iBAAiB;AAAA;AAAA,EAGjB,oBAAoB;AAAA,EACpB,0BAA0B;AAAA,EAC1B,oBAAoB;AAAA,EACpB,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,mBAAmB;AAAA,EACnB,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,oBAAoB;AAAA,EACpB,sBAAsB;AAAA;AAAA,EAGtB,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,iBAAiB;AAAA;AAAA,EAGjB,mBAAmB;AAAA,EACnB,oBAAoB;AAAA,EACpB,mBAAmB;AAAA,EACnB,gBAAgB;AAAA,EAChB,oBAAoB;AAAA,EACpB,wBAAwB;AAAA,EACxB,2BAA2B;AAAA,EAC3B,wBAAwB;AAAA,EACxB,0BAA0B;AAAA,EAC1B,6BAA6B;AAAA,EAC7B,0BAA0B;AAAA,EAC1B,6BAA6B;AAAA,EAC7B,8BAA8B;AAAA,EAC9B,iCAAiC;AAAA,EACjC,mCAAmC;AAAA,EACnC,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,wBAAwB;AAAA,EACxB,4BAA4B;AAAA,EAC5B,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,2BAA2B;AAAA,EAC3B,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,wBAAwB;AAAA,EACxB,gBAAgB;AAAA,EAChB,uBAAuB;AAAA,EACvB,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,yBAAyB;AAAA,EACzB,2BAA2B;AAAA,EAC3B,wBAAwB;AAAA,EACxB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,sBAAsB;AAAA,EACtB,8BAA8B;AAChC;","names":[]}
@@ -12,6 +12,7 @@ var fr = {
12
12
  "picker.holdExpired": "Votre r\xE9servation a expir\xE9 \u2014 les si\xE8ges ont \xE9t\xE9 lib\xE9r\xE9s. S\xE9lectionnez \xE0 nouveau.",
13
13
  "picker.seatTaken": "Le si\xE8ge {label} vient d'\xEAtre r\xE9serv\xE9 par un autre acheteur.",
14
14
  "picker.poweredBy": "Propuls\xE9 par SeatLayer",
15
+ "picker.testMode": "MODE TEST",
15
16
  "picker.colorblind": "Couleurs adapt\xE9es au daltonisme",
16
17
  "picker.orphanHint": "Cela laisse un si\xE8ge isol\xE9 \u2014 pensez \xE0 vous d\xE9caler d'un si\xE8ge.",
17
18
  "picker.seats.one": "{count} si\xE8ge",
@@ -69,4 +70,4 @@ var fr = {
69
70
  export {
70
71
  fr
71
72
  };
72
- //# sourceMappingURL=fr-DQ4KWKKF.js.map
73
+ //# sourceMappingURL=fr-N7AAVATM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/i18n/locales/fr.ts"],"sourcesContent":["/**\n * French (fr) bundle — native French translation.\n * Follows the same key structure as en.ts; all placeholders and brand\n * names preserved.\n */\n\nimport type { Dict } from '../index';\n\nexport const fr: Dict = {\n // shared\n 'common.cancel': 'Annuler',\n 'common.close': 'Fermer',\n 'common.done': 'Terminé',\n 'common.copied': '✓ Copié',\n\n // buyer picker (extraction in progress — P4 of the port plan)\n 'picker.holdSeats': 'Réserver les sièges et valider',\n 'picker.completeBooking': 'Terminer la réservation',\n 'picker.seatsHeld': 'Sièges réservés — {time}',\n 'picker.holdExpired': 'Votre réservation a expiré — les sièges ont été libérés. Sélectionnez à nouveau.',\n 'picker.seatTaken': 'Le siège {label} vient d\\'être réservé par un autre acheteur.',\n 'picker.poweredBy': 'Propulsé par SeatLayer',\n 'picker.testMode': 'MODE TEST',\n 'picker.colorblind': 'Couleurs adaptées au daltonisme',\n 'picker.orphanHint': \"Cela laisse un siège isolé — pensez à vous décaler d'un siège.\",\n 'picker.seats.one': '{count} siège',\n 'picker.seats.other': '{count} sièges',\n\n // renderer (drawn on the Konva map — shared by the embed SDK)\n 'map.aria': 'Plan de salle. Utilisez les flèches pour naviguer entre les sièges, Entrée pour sélectionner.',\n 'map.seatsLeft': '{count} LIBRES',\n 'map.fromPrice': 'DÈS {price}',\n\n // buyer picker page (src/pages/PickerPage.tsx)\n 'picker.language': 'Langue',\n 'picker.zoomToFit': 'Ajuster le zoom',\n 'picker.viewMode': 'Mode d\\'affichage',\n 'picker.floor': 'Étage',\n 'picker.zoomLevel': 'Niveau de zoom',\n 'picker.rungTip.zones': 'Vue la plus large — blocs de zones (Étage / Parquet inférieur / Parquet supérieur)',\n 'picker.rungTip.sections': 'Blocs de sections — mélange de catégories + teinte de disponibilité',\n 'picker.rungTip.seats': 'Sièges individuels — les blocs se transforment en points',\n 'picker.rungLabel.zones': 'ZONES',\n 'picker.rungLabel.sections': 'SECTIONS',\n 'picker.rungLabel.seats': 'SIÈGES',\n 'picker.sectionSummaryAria': 'Résumé de la section {label}',\n 'picker.closeSectionSummary': 'Fermer le résumé de la section',\n 'picker.seatsLeftInSection.one': '{count} siège restant',\n 'picker.seatsLeftInSection.other': '{count} sièges restants',\n 'picker.overview': 'Vue d\\'ensemble',\n 'picker.tapSeatHint': 'Appuyez sur un siège pour vérifier sa vue',\n 'picker.chartSize': 'Taille du plan',\n 'picker.custom': 'Personnalisé',\n 'picker.categories': 'Catégories',\n 'picker.accessibility': 'Accessibilité',\n 'picker.showAnyAccessible': 'Afficher un siège accessible',\n 'picker.any': 'N\\'importe quel',\n 'picker.yourSeats': 'Vos sièges',\n 'picker.emptySeats': 'Appuyez sur les sièges sur le plan',\n 'picker.emptySeatsWithGa': 'Appuyez sur les sièges sur le plan · appuyez sur une zone debout pour les billets GA',\n 'picker.oneFewer': 'Un de moins',\n 'picker.oneMore': 'Un de plus',\n 'picker.remove': 'Supprimer {label}',\n 'picker.ticketTierFor': 'Catégorie de billet pour {label}',\n 'picker.total': 'Total : {amount}',\n 'picker.viewFromSeat': 'Vue depuis le siège {label}',\n 'picker.real360': 'VRAI 360°',\n 'picker.preview': 'APERÇU',\n 'picker.open360': 'Ouvrir la vue à 360°',\n 'picker.sightline': '≈ {rows} rangées de la scène · {angle}° décalé du centre',\n 'picker.bookedDemo': 'Réservé ! (démo)',\n 'picker.bookButton.one': 'Réserver {count} billet — {amount}',\n 'picker.bookButton.other': 'Réserver {count} billets — {amount}',\n 'picker.simulateCrowd': 'Simuler la foule : {state}',\n 'picker.on': 'ACTIVÉ',\n 'picker.off': 'DÉSACTIVÉ',\n 'picker.panorama360': 'Photo panoramique 360° du lieu',\n 'picker.illustrationCaption': 'illustration · ≈ {m} m de la scène',\n};\n"],"mappings":";AAQO,IAAM,KAAW;AAAA;AAAA,EAEtB,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,iBAAiB;AAAA;AAAA,EAGjB,oBAAoB;AAAA,EACpB,0BAA0B;AAAA,EAC1B,oBAAoB;AAAA,EACpB,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,mBAAmB;AAAA,EACnB,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,oBAAoB;AAAA,EACpB,sBAAsB;AAAA;AAAA,EAGtB,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,iBAAiB;AAAA;AAAA,EAGjB,mBAAmB;AAAA,EACnB,oBAAoB;AAAA,EACpB,mBAAmB;AAAA,EACnB,gBAAgB;AAAA,EAChB,oBAAoB;AAAA,EACpB,wBAAwB;AAAA,EACxB,2BAA2B;AAAA,EAC3B,wBAAwB;AAAA,EACxB,0BAA0B;AAAA,EAC1B,6BAA6B;AAAA,EAC7B,0BAA0B;AAAA,EAC1B,6BAA6B;AAAA,EAC7B,8BAA8B;AAAA,EAC9B,iCAAiC;AAAA,EACjC,mCAAmC;AAAA,EACnC,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,wBAAwB;AAAA,EACxB,4BAA4B;AAAA,EAC5B,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,2BAA2B;AAAA,EAC3B,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,wBAAwB;AAAA,EACxB,gBAAgB;AAAA,EAChB,uBAAuB;AAAA,EACvB,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,yBAAyB;AAAA,EACzB,2BAA2B;AAAA,EAC3B,wBAAwB;AAAA,EACxB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,sBAAsB;AAAA,EACtB,8BAA8B;AAChC;","names":[]}
package/dist/index.cjs CHANGED
@@ -42,6 +42,7 @@ var init_es = __esm({
42
42
  "picker.holdExpired": "Tu retenci\xF3n expir\xF3 \u2014 los asientos fueron liberados. Elige de nuevo.",
43
43
  "picker.seatTaken": "El asiento {label} fue tomado por otro comprador.",
44
44
  "picker.poweredBy": "Con la tecnolog\xEDa de SeatLayer",
45
+ "picker.testMode": "MODO DE PRUEBA",
45
46
  "picker.colorblind": "Colores aptos para daltonismo",
46
47
  "picker.orphanHint": "Esto deja un asiento aislado \u2014 considera desplazarte un asiento.",
47
48
  "picker.seats.one": "{count} asiento",
@@ -121,6 +122,7 @@ var init_de = __esm({
121
122
  "picker.holdExpired": "Ihre Reservierung ist abgelaufen \u2014 die Pl\xE4tze wurden freigegeben. Bitte erneut ausw\xE4hlen.",
122
123
  "picker.seatTaken": "Platz {label} wurde gerade von einem anderen K\xE4ufer gebucht.",
123
124
  "picker.poweredBy": "Bereitgestellt von SeatLayer",
125
+ "picker.testMode": "TESTMODUS",
124
126
  "picker.colorblind": "Farbenblind-freundliche Farben",
125
127
  "picker.orphanHint": "Dadurch bleibt ein einzelner Platz \xFCbrig \u2014 r\xFCcken Sie ggf. einen Platz weiter.",
126
128
  "picker.seats.one": "{count} Platz",
@@ -200,6 +202,7 @@ var init_fr = __esm({
200
202
  "picker.holdExpired": "Votre r\xE9servation a expir\xE9 \u2014 les si\xE8ges ont \xE9t\xE9 lib\xE9r\xE9s. S\xE9lectionnez \xE0 nouveau.",
201
203
  "picker.seatTaken": "Le si\xE8ge {label} vient d'\xEAtre r\xE9serv\xE9 par un autre acheteur.",
202
204
  "picker.poweredBy": "Propuls\xE9 par SeatLayer",
205
+ "picker.testMode": "MODE TEST",
203
206
  "picker.colorblind": "Couleurs adapt\xE9es au daltonisme",
204
207
  "picker.orphanHint": "Cela laisse un si\xE8ge isol\xE9 \u2014 pensez \xE0 vous d\xE9caler d'un si\xE8ge.",
205
208
  "picker.seats.one": "{count} si\xE8ge",
@@ -263,6 +266,8 @@ __export(index_exports, {
263
266
  ACCESSIBILITY_TYPES: () => ACCESSIBILITY_TYPES,
264
267
  CHART_STORAGE_KEY: () => CHART_STORAGE_KEY,
265
268
  DEFAULT_CURRENCY: () => DEFAULT_CURRENCY,
269
+ MAX_EVENT_INVENTORY: () => MAX_EVENT_INVENTORY,
270
+ MAX_GA_CAPACITY: () => MAX_GA_CAPACITY,
266
271
  PickerController: () => PickerController,
267
272
  SUPPORTED_LOCALES: () => SUPPORTED_LOCALES,
268
273
  SeatmapRenderer: () => SeatmapRenderer,
@@ -283,8 +288,12 @@ __export(index_exports, {
283
288
  floorsOf: () => floorsOf,
284
289
  formatDate: () => formatDate,
285
290
  formatMoney: () => formatMoney,
291
+ gaAreasOf: () => gaAreasOf,
292
+ gaUnitLabel: () => gaUnitLabel,
293
+ gaUnitLabels: () => gaUnitLabels,
286
294
  getLocale: () => getLocale,
287
295
  hiddenObjectIds: () => hiddenObjectIds,
296
+ isGaUnitLabel: () => isGaUnitLabel,
288
297
  isSectionHidden: () => isSectionHidden,
289
298
  layerOf: () => layerOf,
290
299
  loadLocale: () => loadLocale,
@@ -666,16 +675,35 @@ function chartBounds(doc) {
666
675
  };
667
676
  }
668
677
 
678
+ // src/core/ga.ts
679
+ var PREFIX = "__sl_ga__";
680
+ var MAX_GA_CAPACITY = 1e5;
681
+ var MAX_EVENT_INVENTORY = 1e5;
682
+ function gaUnitLabel(areaId, index) {
683
+ return `${PREFIX}${encodeURIComponent(areaId)}__${index + 1}`;
684
+ }
685
+ function gaUnitLabels(area) {
686
+ const capacity = Math.min(MAX_GA_CAPACITY, Math.max(0, Math.floor(area.capacity)));
687
+ return Array.from({ length: capacity }, (_, i) => gaUnitLabel(area.id, i));
688
+ }
689
+ function gaAreasOf(doc) {
690
+ return allObjects(doc).filter((o) => o.type === "gaArea");
691
+ }
692
+ function isGaUnitLabel(label) {
693
+ return label.startsWith(PREFIX);
694
+ }
695
+
669
696
  // src/core/sections.ts
670
697
  var UNGROUPED_ID = "__ungrouped__";
671
698
  function objectSeatLabels(o) {
672
699
  if (o.type === "row") return expandRow(o).map((s) => s.label);
673
700
  if (o.type === "table") return expandTable(o).map((s) => s.label);
674
701
  if (o.type === "booth") return expandBooth(o).map((s) => s.label);
702
+ if (o.type === "gaArea") return gaUnitLabels(o);
675
703
  return [];
676
704
  }
677
705
  function isSeatObject(o) {
678
- return o.type === "row" || o.type === "table" || o.type === "booth";
706
+ return o.type === "row" || o.type === "table" || o.type === "booth" || o.type === "gaArea";
679
707
  }
680
708
  function computeSections(doc) {
681
709
  const objs = allObjects(doc);
@@ -803,6 +831,7 @@ var en = {
803
831
  "picker.holdExpired": "Your hold expired \u2014 the seats were released. Pick again.",
804
832
  "picker.seatTaken": "Seat {label} was just taken by another buyer.",
805
833
  "picker.poweredBy": "Powered by SeatLayer",
834
+ "picker.testMode": "TEST MODE",
806
835
  "picker.colorblind": "Colorblind-friendly colors",
807
836
  "picker.orphanHint": "This leaves a single seat stranded \u2014 consider shifting one seat over.",
808
837
  "picker.seats.one": "{count} seat",
@@ -2877,6 +2906,8 @@ var PickerController = class {
2877
2906
  this.closed = false;
2878
2907
  // hold state
2879
2908
  this.hold_ = null;
2909
+ this.liveStatuses = /* @__PURE__ */ new Map();
2910
+ this.currency = "USD";
2880
2911
  this.expiryTimer = null;
2881
2912
  /** Whether the last emitted hint was non-null (avoids clearing repeatedly). */
2882
2913
  this.hintShown = false;
@@ -2936,6 +2967,7 @@ var PickerController = class {
2936
2967
  this.allIds.push(s.id);
2937
2968
  }
2938
2969
  const currency = res.event.currency ?? this.opts.currency;
2970
+ this.currency = currency ?? "USD";
2939
2971
  const renderer = createRenderer(host, {
2940
2972
  maxSelection: this.maxSelection,
2941
2973
  confirmSelection: this.opts.confirmSelection,
@@ -2984,7 +3016,9 @@ var PickerController = class {
2984
3016
  eventName: res.event.name,
2985
3017
  venue: res.event.venue,
2986
3018
  startsAt: res.event.startsAt,
2987
- currency
3019
+ currency,
3020
+ // 'test' ⇒ sandbox event: hosts render a TEST MODE ribbon (Phase 11).
3021
+ mode: res.event.mode ?? "live"
2988
3022
  };
2989
3023
  }
2990
3024
  // ---- selection ------------------------------------------------------------
@@ -3007,21 +3041,72 @@ var PickerController = class {
3007
3041
  * re-throws so the caller can choose the banner copy. Returns null only when
3008
3042
  * there's nothing to hold.
3009
3043
  */
3010
- async hold(labelsArg) {
3044
+ async hold(labelsArg, ttlMs) {
3011
3045
  const r = this.renderer;
3012
3046
  if (!r) return null;
3013
3047
  const labels = labelsArg ?? r.getSelection().map((s) => s.label);
3014
- if (!labels.length) return null;
3015
- if (this.hold_ && this.holdCovers(labels)) return this.hold_;
3048
+ const existingGA = (this.hold_?.items ?? []).filter((item) => item.objectType === "ga");
3049
+ const combinedLabels = [.../* @__PURE__ */ new Set([...existingGA.map((item) => item.label), ...labels])];
3050
+ if (!combinedLabels.length) return null;
3051
+ if (this.hold_ && this.holdCovers(combinedLabels)) return this.hold_;
3016
3052
  try {
3017
- const result = await this.api.hold(this.key, labels);
3018
- this.setHold({ holdId: result.holdId, labels: [...labels], expiresAt: result.expiresAt });
3053
+ const selections = combinedLabels.map((label) => {
3054
+ const ga = existingGA.find((item) => item.label === label);
3055
+ if (ga) return { label, tierId: ga.tierId };
3056
+ const seat = this.labelToSeat.get(label);
3057
+ const resolved = seat ? this.toSeat(seat) : null;
3058
+ return { label, ...resolved?.tierId ? { tierId: resolved.tierId } : {} };
3059
+ });
3060
+ const result = await this.api.hold(this.key, selections, ttlMs, this.hold_?.holdId);
3061
+ this.setHold({ holdId: result.holdId, labels: combinedLabels, expiresAt: result.expiresAt, items: result.items });
3019
3062
  return this.hold_;
3020
3063
  } catch (err) {
3021
3064
  this.handle409Conflicts(err);
3022
3065
  throw err;
3023
3066
  }
3024
3067
  }
3068
+ /** Public GA inventory derived from the live synthetic-unit status stream. */
3069
+ getGAAreas() {
3070
+ const doc = this.visibleDoc();
3071
+ if (!doc) return [];
3072
+ return gaAreasOf(doc).map((area) => {
3073
+ const category = doc.categories.find((candidate) => candidate.key === area.categoryKey);
3074
+ return {
3075
+ id: area.id,
3076
+ label: area.label,
3077
+ capacity: Math.max(0, Math.floor(area.capacity)),
3078
+ available: gaUnitLabels(area).filter((label) => (this.liveStatuses.get(label) ?? "free") === "free").length,
3079
+ categoryKey: area.categoryKey,
3080
+ tiers: category?.tiers,
3081
+ price: category?.tiers?.[0]?.price ?? category?.price ?? 0,
3082
+ currency: this.currency
3083
+ };
3084
+ });
3085
+ }
3086
+ /** Select a quantity from one GA area and hold it atomically. */
3087
+ async holdGA(areaId, qty, options = {}) {
3088
+ const doc = this.visibleDoc();
3089
+ if (!doc || !Number.isFinite(qty) || qty < 1) return null;
3090
+ const area = gaAreasOf(doc).find((candidate) => candidate.id === areaId);
3091
+ if (!area) return null;
3092
+ const labels = gaUnitLabels(area).filter((label) => !this.hold_?.labels.includes(label) && (this.liveStatuses.get(label) ?? "free") === "free").slice(0, Math.floor(qty));
3093
+ if (labels.length !== Math.floor(qty)) return null;
3094
+ const selections = /* @__PURE__ */ new Map();
3095
+ for (const item of this.hold_?.items ?? []) selections.set(item.label, { label: item.label, tierId: item.tierId });
3096
+ if (this.hold_ && !this.hold_?.items?.length) {
3097
+ for (const seat of this.hold_.seats) selections.set(seat.label, { label: seat.label, ...seat.tierId ? { tierId: seat.tierId } : {} });
3098
+ }
3099
+ for (const seat of this.renderer?.getSelection() ?? []) {
3100
+ const resolved = this.labelToSeat.get(seat.label);
3101
+ const chosen = resolved ? this.toSeat(resolved) : null;
3102
+ selections.set(seat.label, { label: seat.label, ...chosen?.tierId ? { tierId: chosen.tierId } : {} });
3103
+ }
3104
+ for (const label of labels) selections.set(label, { label, ...options.tierId ? { tierId: options.tierId } : {} });
3105
+ const combined = [...selections.values()];
3106
+ const result = await this.api.hold(this.key, combined, options.ttlMs, this.hold_?.holdId);
3107
+ this.setHold({ holdId: result.holdId, labels: combined.map((s) => s.label), expiresAt: result.expiresAt, items: result.items });
3108
+ return this.hold_;
3109
+ }
3025
3110
  /** Server-picks `qty` best free seats and holds them atomically. Throws on failure. */
3026
3111
  async bestAvailable(qty, categoryKey) {
3027
3112
  const r = this.renderer;
@@ -3032,7 +3117,7 @@ var PickerController = class {
3032
3117
  r.clearSelection();
3033
3118
  const ids = result.labels.map((l) => this.labelToId.get(l)).filter((v) => !!v);
3034
3119
  if (ids.length) r.setStatus(ids, "held");
3035
- this.setHold({ holdId: result.holdId, labels: [...result.labels], expiresAt: result.expiresAt });
3120
+ this.setHold({ holdId: result.holdId, labels: [...result.labels], expiresAt: result.expiresAt, items: result.items });
3036
3121
  const seats = result.labels.map((l) => this.labelToSeat.get(l)).filter((s) => !!s).map((s) => this.toSeat(s));
3037
3122
  this.opts.onSelectionChange?.(seats);
3038
3123
  return this.hold_;
@@ -3061,9 +3146,19 @@ var PickerController = class {
3061
3146
  if (this.hold_ && this.holdCovers(labels)) {
3062
3147
  holdId = this.hold_.holdId;
3063
3148
  } else {
3064
- const h = await this.api.hold(this.key, labels);
3149
+ const replaceHoldId = this.hold_?.holdId;
3150
+ const h = await this.api.hold(
3151
+ this.key,
3152
+ labels.map((label) => {
3153
+ const seat = this.labelToSeat.get(label);
3154
+ const resolved = seat ? this.toSeat(seat) : null;
3155
+ return { label, ...resolved?.tierId ? { tierId: resolved.tierId } : {} };
3156
+ }),
3157
+ void 0,
3158
+ replaceHoldId
3159
+ );
3065
3160
  holdId = h.holdId;
3066
- this.setHold({ holdId, labels: [...labels], expiresAt: h.expiresAt });
3161
+ this.setHold({ holdId, labels: [...labels], expiresAt: h.expiresAt, items: h.items });
3067
3162
  }
3068
3163
  await this.api.book(this.key, labels, holdId, bookingRef);
3069
3164
  } catch (err) {
@@ -3379,7 +3474,13 @@ var PickerController = class {
3379
3474
  }
3380
3475
  holdCovers(labels) {
3381
3476
  const h = this.hold_;
3382
- return !!h && h.labels.length === labels.length && labels.every((l) => h.labels.includes(l));
3477
+ if (!h || h.labels.length !== labels.length || !labels.every((l) => h.labels.includes(l))) return false;
3478
+ const tiers = new Map((h.items ?? []).map((item) => [item.label, item.tierId]));
3479
+ return labels.every((label) => {
3480
+ const seat = this.labelToSeat.get(label);
3481
+ const currentTier = seat ? this.toSeat(seat).tierId ?? null : null;
3482
+ return !tiers.has(label) || tiers.get(label) === currentTier;
3483
+ });
3383
3484
  }
3384
3485
  handle409Conflicts(err) {
3385
3486
  const { status, conflicts } = errInfo(err);
@@ -3399,7 +3500,7 @@ var PickerController = class {
3399
3500
  this.hold_ = full;
3400
3501
  if (this.expiryTimer) clearTimeout(this.expiryTimer);
3401
3502
  const ms = Math.max(0, full.expiresAt - Date.now());
3402
- this.expiryTimer = setTimeout(() => this.onHoldExpired(), ms);
3503
+ this.expiryTimer = setTimeout(() => void this.expireActiveHold(), ms);
3403
3504
  this.opts.onHold?.(full);
3404
3505
  }
3405
3506
  clearHold() {
@@ -3409,18 +3510,31 @@ var PickerController = class {
3409
3510
  this.expiryTimer = null;
3410
3511
  }
3411
3512
  }
3412
- onHoldExpired() {
3513
+ async expireActiveHold() {
3413
3514
  const hold = this.hold_;
3414
- this.clearHold();
3415
- if (hold) {
3416
- const ids = hold.labels.map((l) => this.labelToId.get(l)).filter((v) => !!v);
3417
- if (ids.length) this.renderer?.setStatus(ids, "free");
3515
+ if (!hold) return;
3516
+ try {
3517
+ const snap = await this.api.objects(this.key);
3518
+ if (this.hold_?.holdId !== hold.holdId) return;
3519
+ this.applySeatsMap(snap.seats);
3520
+ } catch {
3521
+ if (this.hold_?.holdId === hold.holdId) {
3522
+ this.expiryTimer = setTimeout(() => void this.expireActiveHold(), 2e3);
3523
+ }
3524
+ return;
3525
+ }
3526
+ if (this.hold_?.holdId !== hold.holdId) return;
3527
+ if (hold.labels.some((label) => this.liveStatuses.get(label) === "held")) {
3528
+ this.expiryTimer = setTimeout(() => void this.expireActiveHold(), 1e3);
3529
+ return;
3418
3530
  }
3531
+ this.clearHold();
3419
3532
  this.opts.onHoldExpired?.();
3420
3533
  }
3421
3534
  applySeatsMap(seats) {
3422
3535
  const r = this.renderer;
3423
3536
  if (!r) return;
3537
+ this.liveStatuses = new Map(Object.entries(seats));
3424
3538
  if (this.allIds.length) r.setStatus(this.allIds, "free");
3425
3539
  const byStatus = { free: [], held: [], booked: [], not_for_sale: [] };
3426
3540
  for (const [label, st] of Object.entries(seats)) {
@@ -3431,6 +3545,10 @@ var PickerController = class {
3431
3545
  if (byStatus[st].length) r.setStatus(byStatus[st], st);
3432
3546
  });
3433
3547
  this.opts.onStatusChange?.();
3548
+ this.clearBookedHoldIfSettled();
3549
+ }
3550
+ clearBookedHoldIfSettled() {
3551
+ if (this.hold_?.labels.every((label) => this.liveStatuses.get(label) === "booked")) this.clearHold();
3434
3552
  }
3435
3553
  async resnapshot() {
3436
3554
  try {
@@ -3473,6 +3591,7 @@ var PickerController = class {
3473
3591
  this.applySeatsMap(m.seats);
3474
3592
  } else if (Array.isArray(m.changes)) {
3475
3593
  for (const ch of m.changes) {
3594
+ this.liveStatuses.set(ch.label, ch.status);
3476
3595
  const id = this.labelToId.get(ch.label);
3477
3596
  if (!id) continue;
3478
3597
  const next = mapStatus(ch.status);
@@ -3481,6 +3600,7 @@ var PickerController = class {
3481
3600
  }
3482
3601
  r.setStatus([id], next);
3483
3602
  }
3603
+ this.clearBookedHoldIfSettled();
3484
3604
  this.opts.onStatusChange?.();
3485
3605
  }
3486
3606
  };
@@ -3534,6 +3654,8 @@ async function loadLocale(code) {
3534
3654
  ACCESSIBILITY_TYPES,
3535
3655
  CHART_STORAGE_KEY,
3536
3656
  DEFAULT_CURRENCY,
3657
+ MAX_EVENT_INVENTORY,
3658
+ MAX_GA_CAPACITY,
3537
3659
  PickerController,
3538
3660
  SUPPORTED_LOCALES,
3539
3661
  SeatmapRenderer,
@@ -3554,8 +3676,12 @@ async function loadLocale(code) {
3554
3676
  floorsOf,
3555
3677
  formatDate,
3556
3678
  formatMoney,
3679
+ gaAreasOf,
3680
+ gaUnitLabel,
3681
+ gaUnitLabels,
3557
3682
  getLocale,
3558
3683
  hiddenObjectIds,
3684
+ isGaUnitLabel,
3559
3685
  isSectionHidden,
3560
3686
  layerOf,
3561
3687
  loadLocale,