@coras-io/embed 0.1.1 → 0.2.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/CHANGELOG.md +21 -0
- package/dist/components/seated-selector/seated-selector.component.d.ts +2 -1
- package/dist/components/seated-selector/seated-selector.component.js +44 -33
- package/dist/components/seated-selector/seated-selector.styles.js +17 -5
- package/dist/components/seats-io/seats-io.component.js +10 -0
- package/dist/components/seats-io/seats-io.constants.d.ts +4 -0
- package/dist/components/seats-io/seats-io.constants.js +7 -0
- package/dist/components/tour-ticket-type-selector/tour-ticket-type-selector.styles.js +4 -3
- package/dist/core/currency/index.d.ts +1 -3
- package/dist/core/currency/index.js +16 -6
- package/dist/custom-elements.json +268 -249
- package/dist/styles/tokens.css +1 -1
- package/dist/styles/tokens.d.ts +1 -1
- package/dist/styles/tokens.generated.d.ts +1 -1
- package/dist/styles/tokens.generated.js +1 -1
- package/dist/views/details-page/details-page.component.js +36 -3
- package/dist/views/details-page/partials/theater-description/theater-description.component.js +5 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @coras-io/embed
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- c7714d5: Hover and selected states on dropdown rows, calendar days, chips and the ticket-type selector now take a faint tint from the brand primary colour instead of a fixed neutral grey, so they follow a rebrand and match the search button. The ticket-type selector's radius now follows the brand button radius (and the general brand radius by default) rather than staying fixed.
|
|
8
|
+
- e157901: Refine the seated theater booking flow: shoppers can change their seat count directly on the map, hover and legend prices show formatted currency, the map offers a full-screen view, "Add to basket" shows progress while it works, and the map closes and the ticket selector resets after a booking. The static seat map illustration is hidden when the interactive picker is available.
|
|
9
|
+
|
|
10
|
+
### Patch Changes
|
|
11
|
+
|
|
12
|
+
- Updated dependencies [c7714d5]
|
|
13
|
+
- @coras-io/brand-tokens@0.2.0
|
|
14
|
+
|
|
15
|
+
## 0.1.2
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- 90975a0: Render prices with the decimal places each currency actually uses instead of
|
|
20
|
+
always showing two. Zero-decimal currencies (JPY, VND, ISK, HUF and others) now
|
|
21
|
+
display as whole amounts (`¥1,000` rather than `¥1,000.00`), and IDR is shown
|
|
22
|
+
without its defunct sen subunit. Two-decimal currencies are unaffected.
|
|
23
|
+
|
|
3
24
|
## 0.1.1
|
|
4
25
|
|
|
5
26
|
### Patch Changes
|
|
@@ -14,7 +14,8 @@ export declare class CorasSeatedSelector extends LitElement {
|
|
|
14
14
|
workspaceKey: string;
|
|
15
15
|
dateLabel: string;
|
|
16
16
|
region: string;
|
|
17
|
-
|
|
17
|
+
maxSeats: number;
|
|
18
|
+
reserving: boolean;
|
|
18
19
|
private selectedSeats;
|
|
19
20
|
private selectionValid;
|
|
20
21
|
private violations;
|
|
@@ -34,9 +34,14 @@ let CorasSeatedSelector = class CorasSeatedSelector extends LitElement {
|
|
|
34
34
|
// Formatted performance date shown in the heading, e.g. "Sat 16 Mar 2023".
|
|
35
35
|
this.dateLabel = "";
|
|
36
36
|
this.region = "eu";
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
|
|
37
|
+
// Upper bound on how many seats can be picked (the venue's per-order max). 0
|
|
38
|
+
// means no cap. It only limits the map; it does not require an exact count,
|
|
39
|
+
// so the shopper is free to pick fewer or more than the upfront selection.
|
|
40
|
+
this.maxSeats = 0;
|
|
41
|
+
// Set by the host while the reservation request is in flight, so the confirm
|
|
42
|
+
// button shows a spinner instead of looking inert for the few seconds the
|
|
43
|
+
// basket call takes.
|
|
44
|
+
this.reserving = false;
|
|
40
45
|
this.selectedSeats = [];
|
|
41
46
|
this.selectionValid = true;
|
|
42
47
|
this.violations = [];
|
|
@@ -143,7 +148,7 @@ let CorasSeatedSelector = class CorasSeatedSelector extends LitElement {
|
|
|
143
148
|
// Drop seats chosen for the previous one before the next chart renders so they
|
|
144
149
|
// never carry into the new chart or reservation.
|
|
145
150
|
willUpdate(changed) {
|
|
146
|
-
if (changed.has("instanceId") || changed.has("
|
|
151
|
+
if (changed.has("instanceId") || changed.has("maxSeats")) {
|
|
147
152
|
this.selectedSeats = [];
|
|
148
153
|
this.selectionValid = true;
|
|
149
154
|
this.violations = [];
|
|
@@ -171,13 +176,11 @@ let CorasSeatedSelector = class CorasSeatedSelector extends LitElement {
|
|
|
171
176
|
reservationCreated() {
|
|
172
177
|
this.reserved = true;
|
|
173
178
|
}
|
|
179
|
+
// Any valid, non-empty selection can be booked. The seat count is no longer
|
|
180
|
+
// tied to the upfront ticket count - the map's own cap (maxSeats) and orphan
|
|
181
|
+
// validator are the only constraints.
|
|
174
182
|
get isComplete() {
|
|
175
|
-
|
|
176
|
-
return false;
|
|
177
|
-
}
|
|
178
|
-
return this.ticketCount
|
|
179
|
-
? this.selectedSeats.length === this.ticketCount
|
|
180
|
-
: true;
|
|
183
|
+
return this.selectedSeats.length > 0 && this.selectionValid;
|
|
181
184
|
}
|
|
182
185
|
formatPrice(value) {
|
|
183
186
|
return convertToLocaleCurrency({
|
|
@@ -207,27 +210,32 @@ let CorasSeatedSelector = class CorasSeatedSelector extends LitElement {
|
|
|
207
210
|
const { groups, total } = buildSelectionSummary(this.selectedSeats, data.availableSeats, data.flatPriceBands, data.categories);
|
|
208
211
|
return html `
|
|
209
212
|
<div class="drawer" part="drawer">
|
|
210
|
-
<div class="drawer-
|
|
211
|
-
<
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
213
|
+
<div class="drawer-inner">
|
|
214
|
+
<div class="drawer-summary">
|
|
215
|
+
<p class="drawer-total">
|
|
216
|
+
${msg("Total")} ${this.formatPrice(total)}
|
|
217
|
+
</p>
|
|
218
|
+
${map(groups, (group) => html `
|
|
219
|
+
<p class="drawer-group">
|
|
220
|
+
<span
|
|
221
|
+
class="drawer-dot"
|
|
222
|
+
style="background:${group.color}"
|
|
223
|
+
></span>
|
|
224
|
+
${msg(str `${group.count} ${group.label} Tickets : ${group.seatLabels.join(", ")} (${this.formatPrice(group.unitPrice)} each)`)}
|
|
225
|
+
</p>
|
|
226
|
+
`)}
|
|
227
|
+
</div>
|
|
222
228
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
229
|
+
<coras-button
|
|
230
|
+
variant="primary"
|
|
231
|
+
height="sm"
|
|
232
|
+
?loading=${this.reserving}
|
|
233
|
+
?disabled=${!this.isComplete || this.reserving}
|
|
234
|
+
@click=${this.handleConfirm}
|
|
235
|
+
>
|
|
236
|
+
${msg("Add to basket")}
|
|
237
|
+
</coras-button>
|
|
238
|
+
</div>
|
|
231
239
|
</div>
|
|
232
240
|
`;
|
|
233
241
|
}
|
|
@@ -254,7 +262,7 @@ let CorasSeatedSelector = class CorasSeatedSelector extends LitElement {
|
|
|
254
262
|
language=${this.locale.split("-")[0] || "en"}
|
|
255
263
|
currency=${this.currency}
|
|
256
264
|
currency-locale=${this.locale}
|
|
257
|
-
max-selected-objects=${this.
|
|
265
|
+
max-selected-objects=${this.maxSeats}
|
|
258
266
|
.chartData=${chartData}
|
|
259
267
|
.selectedObjects=${this.selectedLabels}
|
|
260
268
|
@seats-io-object-selected=${this.handleObjectSelected}
|
|
@@ -301,8 +309,11 @@ __decorate([
|
|
|
301
309
|
property({ type: String })
|
|
302
310
|
], CorasSeatedSelector.prototype, "region", void 0);
|
|
303
311
|
__decorate([
|
|
304
|
-
property({ type: Number, attribute: "
|
|
305
|
-
], CorasSeatedSelector.prototype, "
|
|
312
|
+
property({ type: Number, attribute: "max-seats" })
|
|
313
|
+
], CorasSeatedSelector.prototype, "maxSeats", void 0);
|
|
314
|
+
__decorate([
|
|
315
|
+
property({ type: Boolean, reflect: true })
|
|
316
|
+
], CorasSeatedSelector.prototype, "reserving", void 0);
|
|
306
317
|
__decorate([
|
|
307
318
|
state()
|
|
308
319
|
], CorasSeatedSelector.prototype, "selectedSeats", void 0);
|
|
@@ -33,16 +33,25 @@ export default css `
|
|
|
33
33
|
bottom: 0;
|
|
34
34
|
z-index: 20;
|
|
35
35
|
display: flex;
|
|
36
|
-
|
|
37
|
-
justify-content: space-between;
|
|
38
|
-
gap: 24px;
|
|
36
|
+
justify-content: center;
|
|
39
37
|
box-sizing: border-box;
|
|
40
|
-
padding: 24px clamp(
|
|
38
|
+
padding: 24px clamp(16px, 4vw, 48px);
|
|
41
39
|
background: var(--coras-color-background, #fcfcff);
|
|
42
40
|
border-top: 1px solid var(--coras-color-neutral-200, #e6e6e6);
|
|
43
41
|
box-shadow: 1px -4px 8px 4px rgba(0, 0, 0, 0.03);
|
|
44
42
|
}
|
|
45
43
|
|
|
44
|
+
/* Cap the content width and centre it so the summary and the button stay
|
|
45
|
+
close together on wide screens instead of hugging opposite edges. */
|
|
46
|
+
.drawer-inner {
|
|
47
|
+
display: flex;
|
|
48
|
+
align-items: center;
|
|
49
|
+
justify-content: space-between;
|
|
50
|
+
gap: 24px;
|
|
51
|
+
width: 100%;
|
|
52
|
+
max-width: 720px;
|
|
53
|
+
}
|
|
54
|
+
|
|
46
55
|
.drawer-summary {
|
|
47
56
|
display: flex;
|
|
48
57
|
flex-direction: column;
|
|
@@ -75,10 +84,13 @@ export default css `
|
|
|
75
84
|
|
|
76
85
|
@media (max-width: 600px) {
|
|
77
86
|
.drawer {
|
|
87
|
+
padding: 16px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.drawer-inner {
|
|
78
91
|
flex-direction: column;
|
|
79
92
|
align-items: stretch;
|
|
80
93
|
gap: 12px;
|
|
81
|
-
padding: 16px;
|
|
82
94
|
}
|
|
83
95
|
}
|
|
84
96
|
`;
|
|
@@ -7,6 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
import { html, LitElement, } from "lit";
|
|
8
8
|
import { property, query } from "lit/decorators.js";
|
|
9
9
|
import { fireInternalEvent } from "../../core/events.js";
|
|
10
|
+
import { convertToLocaleCurrency } from "../../core/currency/index.js";
|
|
10
11
|
import { SEATS_IO_DEFAULTS } from "./seats-io.constants.js";
|
|
11
12
|
import styles from "./seats-io.styles.js";
|
|
12
13
|
export class CorasSeatsIO extends LitElement {
|
|
@@ -49,6 +50,15 @@ export class CorasSeatsIO extends LitElement {
|
|
|
49
50
|
workspaceKey: this.workspaceKey,
|
|
50
51
|
event: this.event,
|
|
51
52
|
language: this.language,
|
|
53
|
+
// Prices reach seats.io as raw minor units (e.g. 3500). Format them to the
|
|
54
|
+
// shopper's currency and locale so tooltips and the legend read "£35.00",
|
|
55
|
+
// not "3500". A presentation-layer callback, so unlike the renderer-engine
|
|
56
|
+
// callbacks it may close over the element's currency/locale.
|
|
57
|
+
priceFormatter: (price) => convertToLocaleCurrency({
|
|
58
|
+
value: price,
|
|
59
|
+
locale: this.currencyLocale,
|
|
60
|
+
currency: this.currency,
|
|
61
|
+
}),
|
|
52
62
|
};
|
|
53
63
|
if (!this.chartData) {
|
|
54
64
|
return base;
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
export declare const SEATS_IO_DEFAULTS: {
|
|
2
2
|
showRowLabels: boolean;
|
|
3
3
|
showRowLines: boolean;
|
|
4
|
+
showFullScreenButton: boolean;
|
|
4
5
|
legend: {
|
|
5
6
|
hideNonSelectableCategories: boolean;
|
|
6
7
|
};
|
|
8
|
+
objectTooltip: {
|
|
9
|
+
showUnavailableNotice: boolean;
|
|
10
|
+
};
|
|
7
11
|
loading: string;
|
|
8
12
|
showActiveSectionTooltipOnMobile: boolean;
|
|
9
13
|
};
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
export const SEATS_IO_DEFAULTS = {
|
|
2
2
|
showRowLabels: true,
|
|
3
3
|
showRowLines: true,
|
|
4
|
+
// Let shoppers pop the map out to full screen; the enlarge affordance sits
|
|
5
|
+
// next to seats.io's own zoom controls.
|
|
6
|
+
showFullScreenButton: true,
|
|
4
7
|
legend: {
|
|
5
8
|
hideNonSelectableCategories: true,
|
|
6
9
|
},
|
|
10
|
+
// Show an "unavailable" note when hovering a seat that can't be picked.
|
|
11
|
+
objectTooltip: {
|
|
12
|
+
showUnavailableNotice: true,
|
|
13
|
+
},
|
|
7
14
|
loading: " ",
|
|
8
15
|
showActiveSectionTooltipOnMobile: false,
|
|
9
16
|
};
|
|
@@ -20,10 +20,11 @@ export default css `
|
|
|
20
20
|
width: 100%;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
/* The trigger
|
|
24
|
-
|
|
23
|
+
/* The trigger is a button, so its radius follows the brand button radius
|
|
24
|
+
(which tracks the general brand radius until a separate button radius is
|
|
25
|
+
set) rather than a fixed field radius. */
|
|
25
26
|
coras-button {
|
|
26
|
-
--button-border-radius-small: var(--coras-radius-
|
|
27
|
+
--button-border-radius-small: var(--coras-radius-button);
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
|
|
@@ -5,8 +5,6 @@ type convertToLocaleCurrencyProps = {
|
|
|
5
5
|
locale: (typeof allLocales)[number];
|
|
6
6
|
currency: SupportedCurrencies;
|
|
7
7
|
isSmallestCurrencyUnit?: boolean;
|
|
8
|
-
maximumFractionDigits?: number;
|
|
9
|
-
minimumFractionDigits?: number;
|
|
10
8
|
};
|
|
11
|
-
export declare const convertToLocaleCurrency: ({ value, locale, currency,
|
|
9
|
+
export declare const convertToLocaleCurrency: ({ value, locale, currency, isSmallestCurrencyUnit, }: convertToLocaleCurrencyProps) => string;
|
|
12
10
|
export {};
|
|
@@ -1,6 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
// Currencies we render without decimals even though their CLDR default is 2.
|
|
2
|
+
// Intl already drops decimals for genuinely zero-decimal currencies (JPY, VND,
|
|
3
|
+
// ISK, HUF, ALL); IDR's default is 2 (the defunct sen subunit) but amounts are
|
|
4
|
+
// only ever whole rupiah, so we force it to 0 here.
|
|
5
|
+
const forcedZeroDecimalCurrencies = new Set(["IDR"]);
|
|
6
|
+
export const convertToLocaleCurrency = ({ value = 10000, locale = "en-US", currency = "USD", isSmallestCurrencyUnit = true, }) => {
|
|
7
|
+
const fractionDigits = forcedZeroDecimalCurrencies.has(currency)
|
|
8
|
+
? 0
|
|
9
|
+
: undefined;
|
|
10
|
+
return new Intl.NumberFormat(locale, {
|
|
11
|
+
style: "currency",
|
|
12
|
+
currency: currency,
|
|
13
|
+
minimumFractionDigits: fractionDigits,
|
|
14
|
+
maximumFractionDigits: fractionDigits,
|
|
15
|
+
}).format(isSmallestCurrencyUnit ? value / 100 : value);
|
|
16
|
+
};
|