@coras-io/embed 0.1.2 → 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.
Files changed (236) hide show
  1. package/CHANGELOG.md +139 -0
  2. package/README.md +8 -7
  3. package/dist/components/accordion/accordion-item/accordion-item.styles.js +1 -1
  4. package/dist/components/alert/alert.styles.js +14 -14
  5. package/dist/components/attraction-card/base/attraction-card.styles.js +7 -3
  6. package/dist/components/attraction-discovery/attraction-discovery.styles.js +1 -1
  7. package/dist/components/attraction-header/attraction-header.styles.js +1 -1
  8. package/dist/components/attraction-option/attraction-option.styles.js +4 -4
  9. package/dist/components/basket/basket.styles.js +27 -26
  10. package/dist/components/basket-empty/basket-empty.styles.js +1 -0
  11. package/dist/components/basket-item/basket-item.component.js +10 -4
  12. package/dist/components/basket-item/basket-item.styles.js +9 -3
  13. package/dist/components/basket-item-ticket/basket-item-ticket.styles.js +1 -3
  14. package/dist/components/basket-mobile/basket-mobile.styles.js +5 -5
  15. package/dist/components/better-carousel/better-carousel.styles.js +2 -0
  16. package/dist/components/bottom-drawer/bottom-drawer.styles.js +6 -4
  17. package/dist/components/button/button.component.d.ts +0 -1
  18. package/dist/components/button/button.component.js +1 -8
  19. package/dist/components/button/button.constants.d.ts +1 -1
  20. package/dist/components/button/button.constants.js +1 -1
  21. package/dist/components/button/button.styles.js +66 -39
  22. package/dist/components/calendar/base/calendar.styles.js +3 -5
  23. package/dist/components/calendar/multi/multi.styles.js +7 -0
  24. package/dist/components/category-tag/category-tag.styles.js +10 -7
  25. package/dist/components/checkbox/checkbox.styles.js +2 -2
  26. package/dist/components/chip/chip.styles.js +2 -2
  27. package/dist/components/collect-fida/collect-fida.component.js +5 -3
  28. package/dist/components/collect-fida/collect-fida.styles.js +9 -16
  29. package/dist/components/crypto-auth-modal/crypto-auth-modal.component.js +6 -4
  30. package/dist/components/crypto-auth-modal/crypto-auth-modal.styles.js +2 -2
  31. package/dist/components/dialog/dialog.styles.js +10 -17
  32. package/dist/components/drawer/drawer.component.js +6 -0
  33. package/dist/components/drawer/drawer.styles.js +17 -3
  34. package/dist/components/dropdown/dropdown.component.js +7 -0
  35. package/dist/components/dropdown/dropdown.styles.js +3 -6
  36. package/dist/components/expiration-timer/expiration-timer.styles.js +3 -3
  37. package/dist/components/explore-card/explore-card.styles.js +1 -1
  38. package/dist/components/filter-chip/filter-chip.styles.js +11 -9
  39. package/dist/components/filters-drawer/filters-drawer.component.js +1 -1
  40. package/dist/components/filters-drawer/filters-drawer.styles.js +6 -5
  41. package/dist/components/image/image.styles.js +3 -3
  42. package/dist/components/image-chip/image-chip.styles.js +1 -1
  43. package/dist/components/input-field/input-field.styles.js +22 -17
  44. package/dist/components/itinerary/itinerary-item/itinerary-item.styles.js +1 -1
  45. package/dist/components/joined-fields/joined-fields.styles.js +10 -6
  46. package/dist/components/loading-spinner/loading-spinner.styles.js +1 -1
  47. package/dist/components/location-image/location-image.component.d.ts +6 -0
  48. package/dist/components/location-image/location-image.component.js +15 -2
  49. package/dist/components/location-image/location-image.styles.js +1 -1
  50. package/dist/components/locations-results/locations-results.styles.js +4 -6
  51. package/dist/components/marketing-tag/marketing-tag.styles.js +1 -1
  52. package/dist/components/message-card/message-card.styles.js +6 -6
  53. package/dist/components/option-group/option-chip/option-chip.styles.js +4 -3
  54. package/dist/components/order-confirmation/order-confirmation-item/order-confirmation-item.styles.js +9 -0
  55. package/dist/components/order-confirmation/order-confirmation.component.js +4 -3
  56. package/dist/components/order-confirmation/order-confirmation.styles.js +1 -1
  57. package/dist/components/otp/otp.styles.js +6 -6
  58. package/dist/components/overlay/overlay.styles.js +5 -1
  59. package/dist/components/pay-in/pay-in.styles.js +2 -2
  60. package/dist/components/payment-fiat-method/payment-fiat-method.styles.js +20 -4
  61. package/dist/components/payment-option/payment-option.styles.js +10 -12
  62. package/dist/components/performance-time/performance-time.styles.js +2 -2
  63. package/dist/components/phone-country-code/phone-country-code.styles.js +1 -1
  64. package/dist/components/points/points.styles.js +1 -1
  65. package/dist/components/search-button/search-button.styles.js +15 -7
  66. package/dist/components/seated-selector/seated-selector.component.d.ts +4 -1
  67. package/dist/components/seated-selector/seated-selector.component.js +90 -36
  68. package/dist/components/seated-selector/seated-selector.styles.js +89 -14
  69. package/dist/components/seats-io/seats-io.component.d.ts +2 -0
  70. package/dist/components/seats-io/seats-io.component.js +35 -2
  71. package/dist/components/seats-io/seats-io.constants.d.ts +5 -0
  72. package/dist/components/seats-io/seats-io.constants.js +12 -0
  73. package/dist/components/seats-io/seats-io.transform.d.ts +8 -2
  74. package/dist/components/seats-io/seats-io.transform.js +12 -4
  75. package/dist/components/select-list/select-list.styles.js +1 -0
  76. package/dist/components/select-list/select-option/select-option.styles.js +3 -3
  77. package/dist/components/sort-dropdown/sort-dropdown.styles.js +1 -1
  78. package/dist/components/sort-list/sort-list.styles.js +1 -1
  79. package/dist/components/sport-options/sport-option/sport-option.styles.js +2 -2
  80. package/dist/components/star-rating/star-rating.component.d.ts +1 -0
  81. package/dist/components/star-rating/star-rating.component.js +19 -23
  82. package/dist/components/star-rating/star-rating.styles.js +32 -6
  83. package/dist/components/tab/tab.styles.js +1 -1
  84. package/dist/components/tabs/tabs.styles.js +1 -1
  85. package/dist/components/tag/tag.styles.js +7 -7
  86. package/dist/components/text-section/text-section.styles.js +2 -1
  87. package/dist/components/time-tag/time-tag.styles.js +1 -2
  88. package/dist/components/tooltip/tooltip.styles.js +3 -3
  89. package/dist/components/tour-ticket-type-selector/tour-ticket-type/tour-ticket-type.styles.js +2 -2
  90. package/dist/components/tour-ticket-type-selector/tour-ticket-type-selector.component.js +1 -1
  91. package/dist/components/tour-ticket-type-selector/tour-ticket-type-selector.styles.js +1 -9
  92. package/dist/components/transfer-modal/transfer-modal.component.js +3 -3
  93. package/dist/components/transfer-modal/transfer-modal.styles.js +6 -8
  94. package/dist/containers/basket/basket.component.d.ts +1 -1
  95. package/dist/containers/basket/basket.component.js +56 -25
  96. package/dist/containers/footer/footer.styles.js +4 -0
  97. package/dist/containers/navbar/navbar.component.d.ts +5 -1
  98. package/dist/containers/navbar/navbar.component.js +38 -9
  99. package/dist/containers/navbar/navbar.styles.js +38 -12
  100. package/dist/contexts/basket/basket.provider.d.ts +1 -0
  101. package/dist/contexts/basket/basket.provider.js +31 -4
  102. package/dist/contexts/properties.context.d.ts +4 -4
  103. package/dist/core/api/middlewares/booking-session/booking-session.constants.d.ts +1 -0
  104. package/dist/core/api/middlewares/booking-session/booking-session.constants.js +1 -0
  105. package/dist/core/api/middlewares/booking-session/booking-session.js +18 -27
  106. package/dist/core/api/middlewares/booking-session/booking-session.utils.d.ts +4 -4
  107. package/dist/core/api/middlewares/booking-session/booking-session.utils.js +13 -10
  108. package/dist/core/api/queries.js +3 -2
  109. package/dist/core/color-scheme.d.ts +14 -0
  110. package/dist/core/color-scheme.js +48 -0
  111. package/dist/core/currency/constants.d.ts +1 -1
  112. package/dist/core/currency/constants.js +4 -3
  113. package/dist/core/i18n/date.js +20 -9
  114. package/dist/core/i18n/locale-codes.d.ts +2 -2
  115. package/dist/core/i18n/locale-codes.js +4 -0
  116. package/dist/core/images/constants.d.ts +0 -5
  117. package/dist/core/images/constants.js +0 -5
  118. package/dist/core/images/helpers.d.ts +8 -0
  119. package/dist/core/images/helpers.js +14 -6
  120. package/dist/core/images/srcset.js +2 -2
  121. package/dist/core/storybook/demo.d.ts +4 -0
  122. package/dist/core/storybook/demo.js +17 -0
  123. package/dist/core/types/locales.d.ts +7 -0
  124. package/dist/core/utils/datetime.js +10 -4
  125. package/dist/core/utils/locale.d.ts +8 -1
  126. package/dist/core/utils/locale.js +10 -0
  127. package/dist/helpers/helpers.d.ts +1 -1
  128. package/dist/index.d.ts +2 -3
  129. package/dist/index.js +1 -2
  130. package/dist/locales/ar-SA.d.ts +279 -0
  131. package/dist/locales/ar-SA.js +288 -0
  132. package/dist/locales/da-DK.d.ts +100 -82
  133. package/dist/locales/da-DK.js +104 -89
  134. package/dist/locales/de-DE.d.ts +100 -82
  135. package/dist/locales/de-DE.js +104 -89
  136. package/dist/locales/en-IE.d.ts +250 -232
  137. package/dist/locales/en-IE.js +253 -238
  138. package/dist/locales/en-US.d.ts +100 -82
  139. package/dist/locales/en-US.js +105 -90
  140. package/dist/locales/es-ES.d.ts +100 -82
  141. package/dist/locales/es-ES.js +104 -89
  142. package/dist/locales/fr-FR.d.ts +100 -82
  143. package/dist/locales/fr-FR.js +104 -89
  144. package/dist/locales/fr-MA.d.ts +100 -82
  145. package/dist/locales/fr-MA.js +104 -89
  146. package/dist/locales/is-IS.d.ts +100 -82
  147. package/dist/locales/is-IS.js +104 -89
  148. package/dist/locales/it-IT.d.ts +100 -82
  149. package/dist/locales/it-IT.js +104 -89
  150. package/dist/locales/ms-MY.d.ts +100 -82
  151. package/dist/locales/ms-MY.js +104 -89
  152. package/dist/locales/nb-NO.d.ts +100 -82
  153. package/dist/locales/nb-NO.js +104 -89
  154. package/dist/locales/pl-PL.d.ts +100 -82
  155. package/dist/locales/pl-PL.js +104 -89
  156. package/dist/locales/pt-PT.d.ts +100 -82
  157. package/dist/locales/pt-PT.js +104 -89
  158. package/dist/locales/sv-SE.d.ts +100 -82
  159. package/dist/locales/sv-SE.js +104 -89
  160. package/dist/locales/th-TH.d.ts +100 -82
  161. package/dist/locales/th-TH.js +104 -89
  162. package/dist/locales/tr-TR.d.ts +100 -82
  163. package/dist/locales/tr-TR.js +104 -89
  164. package/dist/locales/zh-CN.d.ts +100 -82
  165. package/dist/locales/zh-CN.js +105 -90
  166. package/dist/locales/zh-HK.d.ts +279 -0
  167. package/dist/locales/zh-HK.js +288 -0
  168. package/dist/mixins/coinbase.mixin.js +1 -1
  169. package/dist/mixins/error-modal.styles.js +2 -2
  170. package/dist/mixins/location-search/location-search.js +3 -3
  171. package/dist/mixins/location-search/location-search.styles.js +6 -5
  172. package/dist/sdk/chrome.d.ts +9 -3
  173. package/dist/sdk/chrome.js +21 -9
  174. package/dist/sdk/element-adapter.js +11 -8
  175. package/dist/sdk/mount.d.ts +3 -3
  176. package/dist/sdk/mount.js +150 -42
  177. package/dist/sdk/navigation-intent.js +3 -0
  178. package/dist/sdk/page-registry.d.ts +14 -2
  179. package/dist/sdk/page-registry.js +33 -13
  180. package/dist/sdk/theme.d.ts +1 -15
  181. package/dist/sdk/theme.js +4 -39
  182. package/dist/sdk/types.d.ts +55 -24
  183. package/dist/sdk/url.d.ts +24 -3
  184. package/dist/sdk/url.js +66 -27
  185. package/dist/sdk/validation.d.ts +0 -7
  186. package/dist/sdk/validation.js +105 -47
  187. package/dist/styles/contrast-fixtures.d.ts +0 -5
  188. package/dist/styles/contrast-fixtures.js +79 -9
  189. package/dist/styles/contrast.js +4 -3
  190. package/dist/styles/defaults/component.js +17 -1
  191. package/dist/styles/primitives.d.ts +0 -10
  192. package/dist/styles/primitives.js +2 -12
  193. package/dist/styles/tokens.d.ts +1 -1
  194. package/dist/styles/tokens.generated.d.ts +1 -1
  195. package/dist/styles/tokens.generated.js +1 -1
  196. package/dist/styles/tokens.metadata.d.ts +1 -1
  197. package/dist/styles/tokens.metadata.js +360 -90
  198. package/dist/views/details-page/details-page.component.d.ts +5 -5
  199. package/dist/views/details-page/details-page.component.js +97 -71
  200. package/dist/views/details-page/details-page.styles.js +64 -9
  201. package/dist/views/details-page/partials/theater-description/theater-description.component.js +5 -0
  202. package/dist/views/help-page/help-page.component.d.ts +1 -0
  203. package/dist/views/help-page/help-page.component.js +11 -4
  204. package/dist/views/help-page/help-page.styles.js +21 -8
  205. package/dist/views/landing-page/landing-page.component.d.ts +4 -4
  206. package/dist/views/landing-page/landing-page.component.js +65 -65
  207. package/dist/views/landing-page/landing-page.styles.js +70 -3
  208. package/dist/views/payment-page/partials/activity-details/activity-details.styles.js +10 -33
  209. package/dist/views/payment-page/partials/billing-address/billing-address.styles.js +4 -9
  210. package/dist/views/payment-page/partials/confirmation/confirmation.styles.js +6 -6
  211. package/dist/views/payment-page/partials/hotel-pickup-list/hotel-pickup-list.styles.js +4 -4
  212. package/dist/views/payment-page/partials/payment-type-selector/payment-type-selector.styles.js +1 -0
  213. package/dist/views/payment-page/partials/stripe/stripe.component.d.ts +1 -1
  214. package/dist/views/payment-page/partials/stripe/stripe.component.js +11 -12
  215. package/dist/views/payment-page/partials/stripe/stripe.constants.d.ts +2 -15
  216. package/dist/views/payment-page/partials/stripe/stripe.constants.js +4 -17
  217. package/dist/views/payment-page/partials/stripe/stripe.styles.js +16 -23
  218. package/dist/views/payment-page/partials/stripe/stripe.utils.d.ts +25 -14
  219. package/dist/views/payment-page/partials/stripe/stripe.utils.js +111 -62
  220. package/dist/views/payment-page/partials/terms-checkbox/terms-checkbox.styles.js +1 -1
  221. package/dist/views/payment-page/payment-page.component.d.ts +1 -0
  222. package/dist/views/payment-page/payment-page.component.js +19 -9
  223. package/dist/views/payment-page/payment-page.styles.js +37 -32
  224. package/dist/views/payment-page/payment-page.utils.d.ts +7 -0
  225. package/dist/views/payment-page/payment-page.utils.js +29 -14
  226. package/dist/views/payment-page/payment-page.validators.js +9 -3
  227. package/dist/views/payment-page/services/payment-api.service.d.ts +1 -1
  228. package/dist/views/search-page/search-page.component.d.ts +1 -0
  229. package/dist/views/search-page/search-page.component.js +12 -6
  230. package/dist/views/search-page/search-page.styles.js +24 -2
  231. package/dist/views/suggestion-widget/suggestion-widget.styles.js +1 -1
  232. package/package.json +62 -75
  233. package/dist/custom-elements.json +0 -37378
  234. package/dist/sdk/meta.d.ts +0 -7
  235. package/dist/sdk/meta.js +0 -9
  236. package/dist/styles/tokens.css +0 -359
@@ -20,7 +20,7 @@ import type { SearchMixinInterface } from "../../mixins/search-mixin/types.js";
20
20
  import type { PageName } from "../../core/types/shared.js";
21
21
  import type { paths } from "../../core/types/api-schema.js";
22
22
  import type { Client } from "openapi-fetch";
23
- declare const CorasNavBar_base: import("../../contexts/utils.js").Constructor<SearchMixinInterface> & typeof LitElement;
23
+ declare const CorasNavBar_base: import("../../contexts/utils.js").Constructor<SearchMixinInterface> & typeof LitElement & (new (...args: any[]) => import("@lit-labs/signals").SignalWatcherApi);
24
24
  export declare class CorasNavBar extends CorasNavBar_base implements SearchMixinInterface {
25
25
  static styles: CSSResultGroup;
26
26
  assetsURL: string;
@@ -30,6 +30,9 @@ export declare class CorasNavBar extends CorasNavBar_base implements SearchMixin
30
30
  showBasket: boolean;
31
31
  showSearch: boolean;
32
32
  logo?: string;
33
+ logoDark?: string;
34
+ navbarLogo?: string;
35
+ private readonly colorScheme;
33
36
  locale: SupportedLocales;
34
37
  locales: SupportedLocales[];
35
38
  currency: SupportedCurrencies;
@@ -94,6 +97,7 @@ export declare class CorasNavBar extends CorasNavBar_base implements SearchMixin
94
97
  private renderMobileMenuIcon;
95
98
  private renderReturnButton;
96
99
  private renderMobileMenuDrawer;
100
+ private handleLogoClick;
97
101
  private renderBrand;
98
102
  private renderSearchOnlyHeader;
99
103
  private renderFullHeader;
@@ -6,6 +6,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  };
7
7
  import { html, LitElement, nothing } from "lit";
8
8
  import { property, state } from "lit/decorators.js";
9
+ import { ColorSchemeController } from "../../core/color-scheme.js";
9
10
  import { when } from "lit/directives/when.js";
10
11
  import { localized, msg } from "@lit/localize";
11
12
  import { consume, ContextConsumer } from "@lit/context";
@@ -45,6 +46,8 @@ let CorasNavBar = class CorasNavBar extends SearchMixin(SignalWatcher(LitElement
45
46
  this.showCurrencySelector = true;
46
47
  this.showBasket = true;
47
48
  this.showSearch = true;
49
+ // Reactive effective scheme, so the fallback logo swaps light/dark live.
50
+ this.colorScheme = new ColorSchemeController(this);
48
51
  this.searchValue = "";
49
52
  this.isCurrenciesDropdownOpen = false;
50
53
  this.isLocalesDropdownOpen = false;
@@ -89,6 +92,15 @@ let CorasNavBar = class CorasNavBar extends SearchMixin(SignalWatcher(LitElement
89
92
  this.searchValue = event.detail.value;
90
93
  this.throttledSearch(event);
91
94
  };
95
+ // The logo is a home link. The embed owns no router, so it dispatches a
96
+ // `landing` navigation the host applies (a no-op when already on landing).
97
+ this.handleLogoClick = () => {
98
+ this.dispatchPageUpdate({
99
+ page: "landing",
100
+ locale: this.locale,
101
+ currency: this.currency,
102
+ });
103
+ };
92
104
  }
93
105
  static { this.styles = styles; }
94
106
  get shouldRenderMobileMenu() {
@@ -596,18 +608,29 @@ let CorasNavBar = class CorasNavBar extends SearchMixin(SignalWatcher(LitElement
596
608
  </coras-drawer>
597
609
  `;
598
610
  }
599
- // The host's `brand` slot wins; the default logo is slot fallback content
600
- // shown only when nothing is slotted and `config.theme.logo` is set.
611
+ // The host's `brand` slot wins and keeps its own semantics: slotted content is
612
+ // projected as-is, never wrapped, so a slotted link/button is not nested inside
613
+ // our button (invalid interactive-in-interactive) and owns its own navigation.
614
+ // The home-link button wraps only the SDK fallback logo, and is rendered as the
615
+ // slot's fallback content, so nothing focusable exists when there is no logo and
616
+ // nothing slotted.
601
617
  renderBrand() {
618
+ const logo = this.navbarLogo ||
619
+ (this.colorScheme.scheme === "dark" && this.logoDark
620
+ ? this.logoDark
621
+ : this.logo);
602
622
  return html `
603
623
  <slot name="brand">
604
- ${this.logo
605
- ? html `<img
606
- class="brand-logo"
607
- part="brand-logo"
608
- src=${this.logo}
609
- alt=""
610
- />`
624
+ ${logo
625
+ ? html `<button
626
+ class="brand-button"
627
+ part="brand-button"
628
+ type="button"
629
+ aria-label=${msg("Go to the home page")}
630
+ @click=${this.handleLogoClick}
631
+ >
632
+ <img class="brand-logo" part="brand-logo" src=${logo} alt="" />
633
+ </button>`
611
634
  : nothing}
612
635
  </slot>
613
636
  `;
@@ -679,6 +702,12 @@ __decorate([
679
702
  __decorate([
680
703
  property({ type: String })
681
704
  ], CorasNavBar.prototype, "logo", void 0);
705
+ __decorate([
706
+ property({ type: String, attribute: "logo-dark" })
707
+ ], CorasNavBar.prototype, "logoDark", void 0);
708
+ __decorate([
709
+ property({ type: String, attribute: "navbar-logo" })
710
+ ], CorasNavBar.prototype, "navbarLogo", void 0);
682
711
  __decorate([
683
712
  consume({ context: localeContext, subscribe: true })
684
713
  ], CorasNavBar.prototype, "locale", void 0);
@@ -22,17 +22,15 @@ export default css `
22
22
  --no-results-font-weight: var(--coras-font-weight-medium);
23
23
  --no-results-color: var(--coras-color-text);
24
24
 
25
- --mobile-menu-drawer-icon-color: var(--coras-color-text);
26
- --mobile-menu-color: var(--coras-color-text);
25
+ --mobile-menu-drawer-icon-color: var(--coras-navbar-icon-color);
26
+ --mobile-menu-color: var(--coras-navbar-text-color);
27
27
 
28
28
  --navbar-gap: 3rem;
29
29
  --navbar-dropdown-gap: 0.5rem;
30
30
  --navbar-mobile-menu-gap: 3rem;
31
31
  --navbar-mobile-menu-padding-top: 5rem;
32
32
  --navbar-mobile-search-padding: 0 2rem;
33
- /* Logo is constrained by height with intrinsic width, so any aspect ratio
34
- stays crisp. Override --navbar-logo-* on the element to rebrand. */
35
- --navbar-logo-height: 2rem;
33
+ --navbar-logo-height: var(--coras-navbar-logo-height);
36
34
  --navbar-logo-max-width: 11.25rem;
37
35
 
38
36
  container-type: inline-size;
@@ -49,13 +47,31 @@ export default css `
49
47
  fill: var(--navbar-icon-color);
50
48
  }
51
49
 
50
+ /* The nav search reads as body copy rather than a form field waiting for
51
+ input, so its resting label follows the body text colour. */
52
+ .search coras-field,
53
+ .input-wrapper-mobile coras-field {
54
+ --field-input-placeholder-color: var(--coras-color-text);
55
+ --field-prefix-icon-color: var(--navbar-icon-color);
56
+ }
57
+
58
+ coras-search-button {
59
+ --search-button-color: var(--coras-color-text);
60
+ --search-button-icon-color: var(--navbar-icon-color);
61
+ }
62
+
52
63
  .locale,
53
- .currency-symbol,
54
64
  .currency-name,
55
65
  .basket-items-quantity {
56
66
  color: var(--navbar-text-color);
57
67
  }
58
68
 
69
+ /* Currency symbols are text glyphs but read as icons, so they follow the
70
+ Nav Bar Icon Colour like the basket and search icons. */
71
+ .currency-symbol {
72
+ color: var(--navbar-icon-color);
73
+ }
74
+
59
75
  .container {
60
76
  max-width: var(--coras-container-max-width);
61
77
  margin: 0 auto;
@@ -130,10 +146,17 @@ export default css `
130
146
  flex-shrink: 0;
131
147
  transition: width 0.3s ease;
132
148
 
133
- /* Size both a host-slotted brand element and the default logo (the img
134
- rendered from the config.theme.logo URL) by height, letting width follow
135
- the aspect ratio. object-fit keeps raster logos undistorted; max-width
136
- guards against a very wide wordmark blowing out the bar. */
149
+ .brand-button {
150
+ display: flex;
151
+ align-items: center;
152
+ padding: 0;
153
+ border: none;
154
+ background: none;
155
+ color: inherit;
156
+ font: inherit;
157
+ cursor: pointer;
158
+ }
159
+
137
160
  ::slotted([slot="brand"]),
138
161
  .brand-logo {
139
162
  height: var(--navbar-logo-height);
@@ -144,11 +167,11 @@ export default css `
144
167
  }
145
168
 
146
169
  @container navbar (max-width: 800px) {
147
- --navbar-logo-height: 1.5rem;
170
+ --navbar-logo-height: calc(var(--coras-navbar-logo-height) * 0.75);
148
171
  }
149
172
 
150
173
  @media (max-width: 800px) {
151
- --navbar-logo-height: 1.5rem;
174
+ --navbar-logo-height: calc(var(--coras-navbar-logo-height) * 0.75);
152
175
  }
153
176
  }
154
177
 
@@ -238,6 +261,9 @@ export default css `
238
261
  }
239
262
 
240
263
  coras-drawer {
264
+ --drawer-background-color: var(--coras-navbar-background);
265
+ color: var(--coras-navbar-text-color);
266
+
241
267
  coras-button > coras-icon {
242
268
  fill: var(--mobile-menu-drawer-icon-color);
243
269
  }
@@ -10,6 +10,7 @@ export declare class CorasBasketProvider extends LitElement {
10
10
  client: Client<paths>;
11
11
  private expirationTimer;
12
12
  private lowestExpiresInReservationId;
13
+ private mountRoot;
13
14
  basketState: BasketContext;
14
15
  constructor();
15
16
  connectedCallback(): void;
@@ -14,10 +14,30 @@ import { distributorIdContext, localeContext } from "../properties.context.js";
14
14
  import { clientContext } from "../client.context.js";
15
15
  import { apiGet, apiDelete, withErrorHandling, } from "../../core/api/queries.js";
16
16
  import styles from "./basket.styles.js";
17
+ // Walk up (crossing shadow boundaries) to the mount root the SDK marks with
18
+ // `data-coras-root`. Null when rendered outside a mount (e.g. Storybook).
19
+ function findMountRoot(start) {
20
+ let node = start;
21
+ while (node) {
22
+ if (node instanceof HTMLElement && node.hasAttribute("data-coras-root")) {
23
+ return node;
24
+ }
25
+ if (node.parentNode) {
26
+ node = node.parentNode;
27
+ continue;
28
+ }
29
+ const root = node.getRootNode();
30
+ node = root instanceof ShadowRoot ? root.host : null;
31
+ }
32
+ return null;
33
+ }
17
34
  export class CorasBasketProvider extends LitElement {
18
35
  static { this.styles = styles; }
19
36
  constructor() {
20
37
  super();
38
+ // The mount this provider belongs to, used to ignore reservation events from
39
+ // other Coras mounts on the same page (the listener is on `window`).
40
+ this.mountRoot = null;
21
41
  this.basketState = {
22
42
  items: null,
23
43
  status: TaskStatus.INITIAL,
@@ -29,12 +49,17 @@ export class CorasBasketProvider extends LitElement {
29
49
  removeItem: () => { },
30
50
  clearBasket: () => { },
31
51
  };
32
- this.handleReservationCreated = () => {
52
+ this.handleReservationCreated = (event) => {
53
+ // A composed event's path runs through this mount's root only when the
54
+ // reservation was created inside this mount; ignore other mounts' events.
55
+ if (this.mountRoot && !event.composedPath().includes(this.mountRoot)) {
56
+ return;
57
+ }
33
58
  this.getReservations();
34
59
  };
35
60
  this.reservationsTask = new Task(this, {
36
61
  task: async ([locale]) => {
37
- const bookingSession = getBookingSession();
62
+ const bookingSession = getBookingSession(this.distributorID);
38
63
  if (!bookingSession) {
39
64
  return null;
40
65
  }
@@ -62,7 +87,7 @@ export class CorasBasketProvider extends LitElement {
62
87
  this.deleteReservationTask = new Task(this, {
63
88
  autoRun: false,
64
89
  task: async ([reservationId]) => {
65
- const bookingSession = getBookingSession();
90
+ const bookingSession = getBookingSession(this.distributorID);
66
91
  if (!bookingSession) {
67
92
  return null;
68
93
  }
@@ -130,9 +155,11 @@ export class CorasBasketProvider extends LitElement {
130
155
  }
131
156
  connectedCallback() {
132
157
  super.connectedCallback();
158
+ this.mountRoot = findMountRoot(this);
133
159
  // Reservation creation is dispatched by the page host as a host-facing
134
160
  // event. The basket provider lives inside coras-layout, so it is not on the
135
- // event path when the host dispatches the event.
161
+ // event path when the host dispatches the event; listen on `window` and
162
+ // filter to this mount so other mounts on the page are unaffected.
136
163
  window.addEventListener("coras:reservation-created", this.handleReservationCreated, true);
137
164
  }
138
165
  disconnectedCallback() {
@@ -1,14 +1,14 @@
1
1
  export declare const localesContext: {
2
- __context__: ("en-GB" | "da-DK" | "de-DE" | "en-IE" | "en-US" | "es-ES" | "fr-FR" | "fr-MA" | "is-IS" | "it-IT" | "ms-MY" | "nb-NO" | "pl-PL" | "pt-PT" | "sv-SE" | "th-TH" | "tr-TR" | "zh-CN")[];
2
+ __context__: ("en-GB" | "ar-SA" | "da-DK" | "de-DE" | "en-IE" | "en-US" | "es-ES" | "fr-FR" | "fr-MA" | "is-IS" | "it-IT" | "ms-MY" | "nb-NO" | "pl-PL" | "pt-PT" | "sv-SE" | "th-TH" | "tr-TR" | "zh-CN" | "zh-HK")[];
3
3
  };
4
4
  export declare const localeContext: {
5
- __context__: "en-GB" | "da-DK" | "de-DE" | "en-IE" | "en-US" | "es-ES" | "fr-FR" | "fr-MA" | "is-IS" | "it-IT" | "ms-MY" | "nb-NO" | "pl-PL" | "pt-PT" | "sv-SE" | "th-TH" | "tr-TR" | "zh-CN";
5
+ __context__: "en-GB" | "ar-SA" | "da-DK" | "de-DE" | "en-IE" | "en-US" | "es-ES" | "fr-FR" | "fr-MA" | "is-IS" | "it-IT" | "ms-MY" | "nb-NO" | "pl-PL" | "pt-PT" | "sv-SE" | "th-TH" | "tr-TR" | "zh-CN" | "zh-HK";
6
6
  };
7
7
  export declare const currencyContext: {
8
- __context__: "AED" | "ALL" | "AUD" | "CAD" | "CHF" | "CNY" | "DKK" | "EUR" | "GBP" | "HRK" | "HUF" | "IDR" | "ISK" | "JPY" | "MAD" | "MYR" | "NOK" | "PHP" | "PLN" | "SEK" | "SGD" | "THB" | "TRY" | "USD" | "VND";
8
+ __context__: "AED" | "ALL" | "AUD" | "CAD" | "CHF" | "CNY" | "DKK" | "EUR" | "GBP" | "HUF" | "IDR" | "ISK" | "JPY" | "MAD" | "MYR" | "NOK" | "PHP" | "PLN" | "SAR" | "SEK" | "SGD" | "THB" | "TRY" | "USD" | "VND";
9
9
  };
10
10
  export declare const currenciesContext: {
11
- __context__: ("AED" | "ALL" | "AUD" | "CAD" | "CHF" | "CNY" | "DKK" | "EUR" | "GBP" | "HRK" | "HUF" | "IDR" | "ISK" | "JPY" | "MAD" | "MYR" | "NOK" | "PHP" | "PLN" | "SEK" | "SGD" | "THB" | "TRY" | "USD" | "VND")[];
11
+ __context__: ("AED" | "ALL" | "AUD" | "CAD" | "CHF" | "CNY" | "DKK" | "EUR" | "GBP" | "HUF" | "IDR" | "ISK" | "JPY" | "MAD" | "MYR" | "NOK" | "PHP" | "PLN" | "SAR" | "SEK" | "SGD" | "THB" | "TRY" | "USD" | "VND")[];
12
12
  };
13
13
  export declare const distributorIdContext: {
14
14
  __context__: string;
@@ -1,5 +1,6 @@
1
1
  export declare const BOOKING_SESSION_STORAGE_KEY = "coras-booking-session";
2
2
  export declare const BOOKING_SESSION_HEADER = "Booking-Session";
3
3
  export declare const BOOKING_SESSION_EXPIRES_HEADER = "booking-session-expires";
4
+ export declare const DISTRIBUTOR_HEADER = "Coras-Distributor";
4
5
  export declare const RETRY_ATTEMPTS = 3;
5
6
  export declare const RETRY_DELAY = 1000;
@@ -1,5 +1,6 @@
1
1
  export const BOOKING_SESSION_STORAGE_KEY = "coras-booking-session";
2
2
  export const BOOKING_SESSION_HEADER = "Booking-Session";
3
3
  export const BOOKING_SESSION_EXPIRES_HEADER = "booking-session-expires";
4
+ export const DISTRIBUTOR_HEADER = "Coras-Distributor";
4
5
  export const RETRY_ATTEMPTS = 3;
5
6
  export const RETRY_DELAY = 1000;
@@ -1,28 +1,23 @@
1
- import { BOOKING_SESSION_EXPIRES_HEADER, BOOKING_SESSION_HEADER, } from "./booking-session.constants.js";
1
+ import { BOOKING_SESSION_EXPIRES_HEADER, BOOKING_SESSION_HEADER, DISTRIBUTOR_HEADER, } from "./booking-session.constants.js";
2
2
  import { getBookingSession, removeBookingSession, retryWithExponentialBackoff, updateBookingSessionExpiration, } from "./booking-session.utils.js";
3
3
  export const bookingSessionMiddleware = {
4
- async onError({ error, request }) {
5
- console.log("Request failed with error, attempting retry:", error);
6
- try {
7
- return await retryWithExponentialBackoff(async () => {
8
- const response = await fetch(request.clone());
9
- if (!response.ok) {
10
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
11
- }
12
- return response;
13
- });
14
- }
15
- catch (retryError) {
16
- console.error("All retry attempts failed:", retryError);
17
- throw retryError;
18
- }
4
+ async onError({ request }) {
5
+ return await retryWithExponentialBackoff(async () => {
6
+ const response = await fetch(request.clone());
7
+ if (!response.ok) {
8
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
9
+ }
10
+ return response;
11
+ });
19
12
  },
20
13
  async onResponse({ response, request }) {
14
+ // The booking session is per-distributor; scope every read/write to the
15
+ // distributor this request was made for (set on the client's headers).
16
+ const distributorId = request.headers.get(DISTRIBUTOR_HEADER);
21
17
  if (response.status === 401) {
22
- console.log("Received 401 response, removing booking session");
23
- removeBookingSession();
18
+ if (distributorId)
19
+ removeBookingSession(distributorId);
24
20
  if (request.method === "GET") {
25
- console.log("Retrying GET request after removing booking session");
26
21
  const newHeaders = new Headers(request.headers);
27
22
  newHeaders.delete(BOOKING_SESSION_HEADER);
28
23
  const newRequest = new Request(request, {
@@ -31,23 +26,19 @@ export const bookingSessionMiddleware = {
31
26
  try {
32
27
  return await fetch(newRequest);
33
28
  }
34
- catch (error) {
35
- console.error("Error retrying request after 401:", error);
29
+ catch {
36
30
  return response;
37
31
  }
38
32
  }
39
33
  return response;
40
34
  }
41
35
  const expiresHeader = response.headers.get(BOOKING_SESSION_EXPIRES_HEADER);
42
- if (expiresHeader) {
43
- const currentBookingSession = getBookingSession();
36
+ if (expiresHeader && distributorId) {
37
+ const currentBookingSession = getBookingSession(distributorId);
44
38
  if (currentBookingSession) {
45
39
  const expirationDate = new Date(expiresHeader);
46
40
  if (!isNaN(expirationDate.getTime())) {
47
- updateBookingSessionExpiration(expirationDate);
48
- }
49
- else {
50
- console.error("Failed to parse booking session expiration date:", expiresHeader);
41
+ updateBookingSessionExpiration(distributorId, expirationDate);
51
42
  }
52
43
  }
53
44
  }
@@ -1,5 +1,5 @@
1
- export declare const getBookingSession: () => string | undefined;
2
- export declare const storeBookingSession: (bookingSession: string, expirationDate: Date) => void;
3
- export declare const updateBookingSessionExpiration: (expirationDate: Date) => void;
4
- export declare const removeBookingSession: () => void;
1
+ export declare const getBookingSession: (distributorId: string) => string | undefined;
2
+ export declare const storeBookingSession: (distributorId: string, bookingSession: string, expirationDate: Date) => void;
3
+ export declare const updateBookingSessionExpiration: (distributorId: string, expirationDate: Date) => void;
4
+ export declare const removeBookingSession: (distributorId: string) => void;
5
5
  export declare const retryWithExponentialBackoff: <T>(operation: () => Promise<T>, maxRetries?: number, baseDelayMs?: number, maxDelayMs?: number) => Promise<T>;
@@ -1,12 +1,15 @@
1
1
  import { BOOKING_SESSION_STORAGE_KEY, RETRY_ATTEMPTS, RETRY_DELAY, } from "./booking-session.constants.js";
2
- export const getBookingSession = () => {
2
+ // The token is scoped per distributor: two embeds on the same origin pointing at
3
+ // different distributors must not share a booking session (basket/checkout).
4
+ const storageKey = (distributorId) => `${BOOKING_SESSION_STORAGE_KEY}:${distributorId}`;
5
+ export const getBookingSession = (distributorId) => {
3
6
  try {
4
- const raw = localStorage.getItem(BOOKING_SESSION_STORAGE_KEY);
7
+ const raw = localStorage.getItem(storageKey(distributorId));
5
8
  if (!raw)
6
9
  return undefined;
7
10
  const { token, expiresAt } = JSON.parse(raw);
8
11
  if (!token || expiresAt <= Date.now()) {
9
- removeBookingSession();
12
+ removeBookingSession(distributorId);
10
13
  return undefined;
11
14
  }
12
15
  return token;
@@ -16,27 +19,27 @@ export const getBookingSession = () => {
16
19
  return undefined;
17
20
  }
18
21
  };
19
- export const storeBookingSession = (bookingSession, expirationDate) => {
22
+ export const storeBookingSession = (distributorId, bookingSession, expirationDate) => {
20
23
  try {
21
24
  const value = {
22
25
  token: bookingSession,
23
26
  expiresAt: expirationDate.getTime(),
24
27
  };
25
- localStorage.setItem(BOOKING_SESSION_STORAGE_KEY, JSON.stringify(value));
28
+ localStorage.setItem(storageKey(distributorId), JSON.stringify(value));
26
29
  }
27
30
  catch {
28
31
  // localStorage may be blocked (private browsing).
29
32
  }
30
33
  };
31
- export const updateBookingSessionExpiration = (expirationDate) => {
32
- const currentSession = getBookingSession();
34
+ export const updateBookingSessionExpiration = (distributorId, expirationDate) => {
35
+ const currentSession = getBookingSession(distributorId);
33
36
  if (currentSession) {
34
- storeBookingSession(currentSession, expirationDate);
37
+ storeBookingSession(distributorId, currentSession, expirationDate);
35
38
  }
36
39
  };
37
- export const removeBookingSession = () => {
40
+ export const removeBookingSession = (distributorId) => {
38
41
  try {
39
- localStorage.removeItem(BOOKING_SESSION_STORAGE_KEY);
42
+ localStorage.removeItem(storageKey(distributorId));
40
43
  }
41
44
  catch {
42
45
  // localStorage may be blocked (private browsing).
@@ -1,16 +1,17 @@
1
1
  import { API_VERSION } from "../constants/api-version.js";
2
2
  import { getBookingSession } from "./middlewares/booking-session/booking-session.utils.js";
3
+ import { getApiLanguageCode } from "../utils/locale.js";
3
4
  const createBaseRequestConfig = (distributorID, locale, customBookingSession) => {
4
5
  const bookingSession = customBookingSession !== undefined
5
6
  ? customBookingSession
6
- : getBookingSession();
7
+ : getBookingSession(distributorID);
7
8
  const headers = {
8
9
  "Content-Type": "application/json",
9
10
  "Coras-Distributor": distributorID,
10
11
  ...(bookingSession && { "Booking-Session": bookingSession }),
11
12
  };
12
13
  const path = { api_version: API_VERSION };
13
- const language_code = locale.split("-")[0];
14
+ const language_code = getApiLanguageCode(locale);
14
15
  return { headers, path, language_code };
15
16
  };
16
17
  export const apiGet = async ({ client, distributorID, locale, endpoint, query, path: customPath, bookingSession, }) => {
@@ -0,0 +1,14 @@
1
+ import type { ReactiveController, ReactiveControllerHost } from "lit";
2
+ export type ColorScheme = "light" | "dark";
3
+ export declare function resolveColorScheme(element: Element): ColorScheme;
4
+ export declare class ColorSchemeController implements ReactiveController {
5
+ scheme: ColorScheme;
6
+ private readonly host;
7
+ private media?;
8
+ private observer?;
9
+ private readonly onChange;
10
+ constructor(host: ReactiveControllerHost & Element);
11
+ hostConnected(): void;
12
+ hostDisconnected(): void;
13
+ private sync;
14
+ }
@@ -0,0 +1,48 @@
1
+ function schemeRoot(el) {
2
+ return el.closest("[data-coras-root]") ?? el.ownerDocument.documentElement;
3
+ }
4
+ function prefersDark() {
5
+ return (typeof matchMedia === "function" &&
6
+ matchMedia("(prefers-color-scheme: dark)").matches);
7
+ }
8
+ export function resolveColorScheme(element) {
9
+ const scheme = getComputedStyle(element).colorScheme.toLowerCase();
10
+ const hasLight = scheme.includes("light");
11
+ const hasDark = scheme.includes("dark");
12
+ if (hasLight && hasDark)
13
+ return prefersDark() ? "dark" : "light";
14
+ if (hasDark)
15
+ return "dark";
16
+ return "light";
17
+ }
18
+ export class ColorSchemeController {
19
+ constructor(host) {
20
+ this.scheme = "light";
21
+ this.onChange = () => this.sync();
22
+ this.host = host;
23
+ host.addController(this);
24
+ }
25
+ hostConnected() {
26
+ if (typeof matchMedia === "function") {
27
+ this.media = matchMedia("(prefers-color-scheme: dark)");
28
+ this.media.addEventListener("change", this.onChange);
29
+ }
30
+ this.observer = new MutationObserver(this.onChange);
31
+ this.observer.observe(schemeRoot(this.host), {
32
+ attributes: true,
33
+ attributeFilter: ["style", "class", "data-coras-color-scheme"],
34
+ });
35
+ this.scheme = resolveColorScheme(this.host);
36
+ }
37
+ hostDisconnected() {
38
+ this.media?.removeEventListener("change", this.onChange);
39
+ this.observer?.disconnect();
40
+ }
41
+ sync() {
42
+ const next = resolveColorScheme(this.host);
43
+ if (next !== this.scheme) {
44
+ this.scheme = next;
45
+ this.host.requestUpdate();
46
+ }
47
+ }
48
+ }
@@ -1,5 +1,5 @@
1
1
  import type { allLocales } from "../i18n/locale-codes.js";
2
- export declare const supportedCurrencies: readonly ["AED", "ALL", "AUD", "CAD", "CHF", "CNY", "DKK", "EUR", "GBP", "HRK", "HUF", "IDR", "ISK", "JPY", "MAD", "MYR", "NOK", "PHP", "PLN", "SEK", "SGD", "THB", "TRY", "USD", "VND"];
2
+ export declare const supportedCurrencies: readonly ["AED", "ALL", "AUD", "CAD", "CHF", "CNY", "DKK", "EUR", "GBP", "HUF", "IDR", "ISK", "JPY", "MAD", "MYR", "NOK", "PHP", "PLN", "SAR", "SEK", "SGD", "THB", "TRY", "USD", "VND"];
3
3
  export declare const currencySymbol: Record<(typeof supportedCurrencies)[number], string>;
4
4
  export declare const currencyName: Record<(typeof supportedCurrencies)[number], string>;
5
5
  export declare const localeToCurrencyMapping: Partial<Record<(typeof allLocales)[number], keyof typeof currencySymbol>>;
@@ -8,7 +8,6 @@ export const supportedCurrencies = [
8
8
  "DKK",
9
9
  "EUR",
10
10
  "GBP",
11
- "HRK",
12
11
  "HUF",
13
12
  "IDR",
14
13
  "ISK",
@@ -18,6 +17,7 @@ export const supportedCurrencies = [
18
17
  "NOK",
19
18
  "PHP",
20
19
  "PLN",
20
+ "SAR",
21
21
  "SEK",
22
22
  "SGD",
23
23
  "THB",
@@ -35,7 +35,6 @@ export const currencySymbol = {
35
35
  DKK: "kr",
36
36
  EUR: "€",
37
37
  GBP: "£",
38
- HRK: "kn",
39
38
  HUF: "Ft",
40
39
  IDR: "Rp",
41
40
  ISK: "kr",
@@ -45,6 +44,7 @@ export const currencySymbol = {
45
44
  NOK: "kr",
46
45
  PHP: "₱",
47
46
  PLN: "zł",
47
+ SAR: "ر.س",
48
48
  SEK: "kr",
49
49
  SGD: "S$",
50
50
  THB: "฿",
@@ -62,7 +62,6 @@ export const currencyName = {
62
62
  DKK: "Danske kroner",
63
63
  EUR: "Euro",
64
64
  GBP: "Pound sterling",
65
- HRK: "Croatian Kuna",
66
65
  HUF: "Hungarian Forint",
67
66
  IDR: "Indonesian Rupiah",
68
67
  ISK: "Íslensk króna",
@@ -72,6 +71,7 @@ export const currencyName = {
72
71
  NOK: "Norsk krone",
73
72
  PHP: "Philippine Peso",
74
73
  PLN: "Złoty",
74
+ SAR: "ريال سعودي",
75
75
  SEK: "Svensk krona",
76
76
  SGD: "Singapore Dollar",
77
77
  THB: "Baht",
@@ -80,6 +80,7 @@ export const currencyName = {
80
80
  VND: "Vietnamese Dong",
81
81
  };
82
82
  export const localeToCurrencyMapping = {
83
+ "ar-SA": "SAR",
83
84
  "da-DK": "DKK",
84
85
  "de-DE": "EUR",
85
86
  "en-GB": "GBP",