@ticketlayer/elements 0.3.3 → 1.0.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 (179) hide show
  1. package/README.md +3 -2
  2. package/dist/cjs/{index-BpfoKd9Q.js → index-DanPUX0s.js} +1 -1
  3. package/dist/cjs/index.cjs.js +2 -1
  4. package/dist/cjs/loader.cjs.js +2 -2
  5. package/dist/cjs/ticket-selector-BYVL13k_.js +3623 -0
  6. package/dist/cjs/ticketlayer-elements.cjs.js +2 -2
  7. package/dist/cjs/tl-buy-modal.cjs.entry.js +4 -4
  8. package/dist/cjs/tl-buy-tickets-button.cjs.entry.js +89 -71
  9. package/dist/cjs/tl-buy-tickets-wrapper.cjs.entry.js +62 -31
  10. package/dist/cjs/tl-cart-badge.cjs.entry.js +75 -62
  11. package/dist/cjs/tl-cart-drawer.cjs.entry.js +52 -24
  12. package/dist/cjs/tl-cart.cjs.entry.js +72 -98
  13. package/dist/cjs/tl-checkout-wrapper.cjs.entry.js +52 -30
  14. package/dist/cjs/tl-event-card.cjs.entry.js +44 -105
  15. package/dist/cjs/tl-event-list.cjs.entry.js +73 -36
  16. package/dist/cjs/tl-login.cjs.entry.js +75 -141
  17. package/dist/cjs/tl-my-orders.cjs.entry.js +53 -92
  18. package/dist/cjs/tl-occurrence-selector_2.cjs.entry.js +205 -641
  19. package/dist/cjs/tl-order-confirmation.cjs.entry.js +72 -105
  20. package/dist/cjs/tl-order-tickets_2.cjs.entry.js +50 -76
  21. package/dist/cjs/tl-promo-code.cjs.entry.js +51 -47
  22. package/dist/cjs/tl-seat-map.cjs.entry.js +4 -4
  23. package/dist/cjs/web-query-Ce73jB4k.js +16 -0
  24. package/dist/collection/components/tl-buy-modal/tl-buy-modal.css +12 -19
  25. package/dist/collection/components/tl-buy-modal/tl-buy-modal.js +2 -2
  26. package/dist/collection/components/tl-buy-tickets-button/tl-buy-tickets-button.css +41 -4
  27. package/dist/collection/components/tl-buy-tickets-button/tl-buy-tickets-button.js +105 -76
  28. package/dist/collection/components/tl-buy-tickets-wrapper/tl-buy-tickets-wrapper.css +2 -2
  29. package/dist/collection/components/tl-buy-tickets-wrapper/tl-buy-tickets-wrapper.js +73 -30
  30. package/dist/collection/components/tl-cart/tl-cart.css +52 -51
  31. package/dist/collection/components/tl-cart/tl-cart.js +82 -101
  32. package/dist/collection/components/tl-cart-badge/tl-cart-badge.css +11 -11
  33. package/dist/collection/components/tl-cart-badge/tl-cart-badge.js +62 -62
  34. package/dist/collection/components/tl-cart-drawer/tl-cart-drawer.css +6 -6
  35. package/dist/collection/components/tl-cart-drawer/tl-cart-drawer.js +56 -24
  36. package/dist/collection/components/tl-checkout-wrapper/tl-checkout-wrapper.css +2 -2
  37. package/dist/collection/components/tl-checkout-wrapper/tl-checkout-wrapper.js +61 -29
  38. package/dist/collection/components/tl-event-card/event-card-adapter.js +11 -23
  39. package/dist/collection/components/tl-event-card/tl-event-card.css +22 -22
  40. package/dist/collection/components/tl-event-card/tl-event-card.js +51 -84
  41. package/dist/collection/components/tl-event-list/tl-event-list.css +17 -17
  42. package/dist/collection/components/tl-event-list/tl-event-list.js +82 -38
  43. package/dist/collection/components/tl-login/tl-login.css +26 -26
  44. package/dist/collection/components/tl-login/tl-login.js +83 -147
  45. package/dist/collection/components/tl-my-orders/tl-my-orders.css +40 -40
  46. package/dist/collection/components/tl-my-orders/tl-my-orders.js +58 -96
  47. package/dist/collection/components/tl-occurrence-selector/tl-occurrence-selector.css +54 -65
  48. package/dist/collection/components/tl-occurrence-selector/tl-occurrence-selector.js +137 -516
  49. package/dist/collection/components/tl-order-confirmation/tl-order-confirmation.css +38 -38
  50. package/dist/collection/components/tl-order-confirmation/tl-order-confirmation.js +81 -113
  51. package/dist/collection/components/tl-order-tickets/tl-order-tickets.css +9 -9
  52. package/dist/collection/components/tl-order-tickets/tl-order-tickets.js +57 -92
  53. package/dist/collection/components/tl-promo-code/tl-promo-code.css +25 -25
  54. package/dist/collection/components/tl-promo-code/tl-promo-code.js +55 -50
  55. package/dist/collection/components/tl-seat-map/tl-seat-map.css +10 -10
  56. package/dist/collection/components/tl-seat-map/tl-seat-map.js +2 -2
  57. package/dist/collection/components/tl-ticket/tl-ticket.css +13 -13
  58. package/dist/collection/components/tl-ticket-selector/tl-ticket-selector.css +74 -49
  59. package/dist/collection/components/tl-ticket-selector/tl-ticket-selector.js +95 -135
  60. package/dist/collection/utils/cart-totals.js +9 -0
  61. package/dist/collection/utils/order-summary.js +15 -99
  62. package/dist/collection/utils/testing/deep-text.js +29 -0
  63. package/dist/collection/utils/testing/fixtures.js +290 -0
  64. package/dist/collection/utils/testing/mock-sdk.js +13 -2
  65. package/dist/collection/utils/web-query.js +12 -0
  66. package/dist/collection/utils/web-storage.js +22 -0
  67. package/dist/components/ticket-selector.js +1 -0
  68. package/dist/components/tl-buy-modal.js +1 -1
  69. package/dist/components/tl-buy-tickets-button.js +1 -1
  70. package/dist/components/tl-buy-tickets-wrapper2.js +1 -1
  71. package/dist/components/tl-cart-badge.js +1 -1
  72. package/dist/components/tl-cart-drawer.js +1 -1
  73. package/dist/components/tl-cart2.js +1 -1
  74. package/dist/components/tl-checkout-wrapper2.js +1 -1
  75. package/dist/components/tl-event-card2.js +1 -1
  76. package/dist/components/tl-event-list.js +1 -1
  77. package/dist/components/tl-login2.js +1 -1
  78. package/dist/components/tl-my-orders.js +1 -1
  79. package/dist/components/tl-occurrence-selector2.js +1 -1
  80. package/dist/components/tl-order-confirmation.js +1 -1
  81. package/dist/components/tl-order-tickets2.js +1 -1
  82. package/dist/components/tl-promo-code.js +1 -1
  83. package/dist/components/tl-seat-map.js +1 -1
  84. package/dist/components/tl-ticket-selector2.js +1 -1
  85. package/dist/components/tl-ticket2.js +1 -1
  86. package/dist/components/web-query.js +1 -0
  87. package/dist/elements.docs.json +36 -36
  88. package/dist/esm/{index-CNX8hZa8.js → index-imfxp765.js} +1 -1
  89. package/dist/esm/index.js +2 -1
  90. package/dist/esm/loader.js +3 -3
  91. package/dist/esm/ticket-selector-BwChnHVC.js +3606 -0
  92. package/dist/esm/ticketlayer-elements.js +3 -3
  93. package/dist/esm/tl-buy-modal.entry.js +4 -4
  94. package/dist/esm/tl-buy-tickets-button.entry.js +90 -72
  95. package/dist/esm/tl-buy-tickets-wrapper.entry.js +63 -32
  96. package/dist/esm/tl-cart-badge.entry.js +76 -63
  97. package/dist/esm/tl-cart-drawer.entry.js +53 -25
  98. package/dist/esm/tl-cart.entry.js +73 -99
  99. package/dist/esm/tl-checkout-wrapper.entry.js +53 -31
  100. package/dist/esm/tl-event-card.entry.js +45 -106
  101. package/dist/esm/tl-event-list.entry.js +74 -37
  102. package/dist/esm/tl-login.entry.js +76 -142
  103. package/dist/esm/tl-my-orders.entry.js +54 -93
  104. package/dist/esm/tl-occurrence-selector_2.entry.js +206 -642
  105. package/dist/esm/tl-order-confirmation.entry.js +73 -106
  106. package/dist/esm/tl-order-tickets_2.entry.js +51 -77
  107. package/dist/esm/tl-promo-code.entry.js +52 -48
  108. package/dist/esm/tl-seat-map.entry.js +4 -4
  109. package/dist/esm/web-query-Bdbb2lk5.js +14 -0
  110. package/dist/ticketlayer-elements/index.esm.js +1 -1
  111. package/dist/ticketlayer-elements/p-45923d2c.entry.js +1 -0
  112. package/dist/ticketlayer-elements/p-492adc77.entry.js +1 -0
  113. package/dist/ticketlayer-elements/p-4cfc9e53.entry.js +1 -0
  114. package/dist/ticketlayer-elements/p-5135630e.entry.js +1 -0
  115. package/dist/ticketlayer-elements/p-5bbce3b5.entry.js +1 -0
  116. package/dist/ticketlayer-elements/p-7d547721.entry.js +1 -0
  117. package/dist/ticketlayer-elements/p-7fe7b6ba.entry.js +1 -0
  118. package/dist/ticketlayer-elements/p-8122f0c1.entry.js +1 -0
  119. package/dist/ticketlayer-elements/p-98d40869.entry.js +1 -0
  120. package/dist/ticketlayer-elements/p-Bdbb2lk5.js +1 -0
  121. package/dist/ticketlayer-elements/p-BwChnHVC.js +1 -0
  122. package/dist/ticketlayer-elements/p-abec290a.entry.js +1 -0
  123. package/dist/ticketlayer-elements/p-ac79a3f6.entry.js +1 -0
  124. package/dist/ticketlayer-elements/p-d01f4429.entry.js +1 -0
  125. package/dist/ticketlayer-elements/p-d7ffaf46.entry.js +1 -0
  126. package/dist/ticketlayer-elements/p-e7170f3c.entry.js +1 -0
  127. package/dist/ticketlayer-elements/p-e787e862.entry.js +1 -0
  128. package/dist/ticketlayer-elements/p-f1ff931f.entry.js +1 -0
  129. package/dist/ticketlayer-elements/p-imfxp765.js +3 -0
  130. package/dist/ticketlayer-elements/ticketlayer-elements.css +1 -1
  131. package/dist/ticketlayer-elements/ticketlayer-elements.esm.js +1 -1
  132. package/dist/types/components/tl-buy-tickets-button/tl-buy-tickets-button.d.ts +40 -8
  133. package/dist/types/components/tl-buy-tickets-wrapper/tl-buy-tickets-wrapper.d.ts +20 -1
  134. package/dist/types/components/tl-cart/tl-cart.d.ts +40 -32
  135. package/dist/types/components/tl-cart-badge/tl-cart-badge.d.ts +22 -7
  136. package/dist/types/components/tl-cart-drawer/tl-cart-drawer.d.ts +28 -5
  137. package/dist/types/components/tl-checkout-wrapper/tl-checkout-wrapper.d.ts +18 -1
  138. package/dist/types/components/tl-event-card/event-card-adapter.d.ts +9 -20
  139. package/dist/types/components/tl-event-card/tl-event-card.d.ts +25 -28
  140. package/dist/types/components/tl-event-list/tl-event-list.d.ts +46 -6
  141. package/dist/types/components/tl-login/tl-login.d.ts +68 -22
  142. package/dist/types/components/tl-my-orders/tl-my-orders.d.ts +30 -12
  143. package/dist/types/components/tl-occurrence-selector/tl-occurrence-selector.d.ts +73 -161
  144. package/dist/types/components/tl-order-confirmation/tl-order-confirmation.d.ts +48 -15
  145. package/dist/types/components/tl-order-tickets/tl-order-tickets.d.ts +29 -31
  146. package/dist/types/components/tl-promo-code/tl-promo-code.d.ts +28 -10
  147. package/dist/types/components/tl-ticket/tl-ticket.d.ts +2 -11
  148. package/dist/types/components/tl-ticket-selector/tl-ticket-selector.d.ts +61 -32
  149. package/dist/types/components.d.ts +302 -62
  150. package/dist/types/utils/cart-totals.d.ts +10 -0
  151. package/dist/types/utils/order-summary.d.ts +16 -65
  152. package/dist/types/utils/testing/deep-text.d.ts +13 -0
  153. package/dist/types/utils/testing/fixtures.d.ts +225 -0
  154. package/dist/types/utils/testing/mock-sdk.d.ts +14 -1
  155. package/dist/types/utils/web-query.d.ts +18 -0
  156. package/dist/types/utils/web-storage.d.ts +16 -0
  157. package/elements.catalogue.json +676 -55
  158. package/package.json +14 -6
  159. package/dist/cjs/order-summary-ZMkJ5bez.js +0 -116
  160. package/dist/components/order-summary.js +0 -1
  161. package/dist/esm/order-summary-BGekdjN9.js +0 -103
  162. package/dist/ticketlayer-elements/p-0b1d16f8.entry.js +0 -1
  163. package/dist/ticketlayer-elements/p-1471f6d8.entry.js +0 -1
  164. package/dist/ticketlayer-elements/p-1c51cbc1.entry.js +0 -1
  165. package/dist/ticketlayer-elements/p-5169f68b.entry.js +0 -1
  166. package/dist/ticketlayer-elements/p-895ba1f3.entry.js +0 -1
  167. package/dist/ticketlayer-elements/p-8d5722e1.entry.js +0 -1
  168. package/dist/ticketlayer-elements/p-917d8e09.entry.js +0 -1
  169. package/dist/ticketlayer-elements/p-9629029a.entry.js +0 -1
  170. package/dist/ticketlayer-elements/p-BGekdjN9.js +0 -1
  171. package/dist/ticketlayer-elements/p-CNX8hZa8.js +0 -3
  172. package/dist/ticketlayer-elements/p-a22714d0.entry.js +0 -1
  173. package/dist/ticketlayer-elements/p-bf73044b.entry.js +0 -1
  174. package/dist/ticketlayer-elements/p-e02079fa.entry.js +0 -1
  175. package/dist/ticketlayer-elements/p-e04ace15.entry.js +0 -1
  176. package/dist/ticketlayer-elements/p-e6fab1d5.entry.js +0 -1
  177. package/dist/ticketlayer-elements/p-f826b753.entry.js +0 -1
  178. package/dist/ticketlayer-elements/p-fa639d88.entry.js +0 -1
  179. package/dist/ticketlayer-elements/p-fbaca948.entry.js +0 -1
@@ -1,6 +1,7 @@
1
1
  import { h } from "@stencil/core";
2
- import { whenSDK } from "../../utils/sdk-connector";
3
- import { errorMessage } from "../../utils/order-summary";
2
+ import { createElement, loginCore, } from "@ticketlayer/elements-core";
3
+ import { getSDK, whenSDK } from "../../utils/sdk-connector";
4
+ import { webQuery } from "../../utils/web-query";
4
5
  /**
5
6
  * tl-login - magic-link sign-in. The customer enters an email, we ask the SDK
6
7
  * to send a link (POST /sales/customer-auth/magic-link), then either the link
@@ -11,6 +12,13 @@ import { errorMessage } from "../../utils/order-summary";
11
12
  * States: enter email -> check your inbox (resend, enter code) -> signed in
12
13
  * (email + sign out).
13
14
  *
15
+ * The web harness for `loginCore`: it renders and it forwards. The phases, the
16
+ * exchange, the auth subscriptions and every string are in
17
+ * `@ticketlayer/elements-core` (AGENTS.md, TKT-11). What is left here is the
18
+ * Stencil surface and the two genuinely web things: the client the page
19
+ * published on `window.Ticketlayer`, and `window.location.search`, which is
20
+ * where this runtime keeps the `?code=` the core asks for.
21
+ *
14
22
  * Usage: <tl-login></tl-login>
15
23
  *
16
24
  * @event tlAuthChanged - signed in or out ({ customer, authenticated })
@@ -23,167 +31,92 @@ export class TlLogin {
23
31
  this.heading = 'Sign in';
24
32
  /** Offer a "enter the code" path alongside the emailed link (default true). */
25
33
  this.allowCodeEntry = true;
26
- this.phase = 'email';
27
- this.email = '';
28
- this.code = '';
29
- this.busy = false;
30
- this.error = null;
31
- this.notice = null;
32
- this.customer = null;
33
- this.auth = null;
34
- this.unsubscribes = [];
35
- // A magic-link code is single-use; never exchange the URL code twice.
36
- this.urlCodeUsed = false;
34
+ this.element = createElement(loginCore, {
35
+ client: () => getSDK(),
36
+ clientReady: () => whenSDK(),
37
+ query: webQuery,
38
+ emit: (event, detail) => this.forward(event, detail),
39
+ });
40
+ /** The core's whole view. Assigning it is what makes Stencil re-render. */
41
+ this.view = this.element.view;
37
42
  this.handleEmailInput = (e) => {
38
- this.email = e.target.value;
39
- this.error = null;
43
+ this.element.actions.setEmail(e.target.value);
40
44
  };
41
45
  this.handleCodeInput = (e) => {
42
- this.code = e.target.value;
43
- this.error = null;
46
+ this.element.actions.setCode(e.target.value);
44
47
  };
45
48
  this.handleEmailSubmit = (e) => {
46
49
  e.preventDefault();
47
- this.requestLink();
50
+ this.element.actions.requestLink();
48
51
  };
49
52
  this.handleCodeSubmit = (e) => {
50
53
  e.preventDefault();
51
- this.exchange(this.code.trim());
54
+ this.element.actions.submitCode();
52
55
  };
53
56
  }
54
- async componentWillLoad() {
55
- const sdk = await whenSDK().catch(() => null);
56
- if (!sdk) {
57
- this.error = 'Sign-in is not available right now';
58
- return;
59
- }
60
- this.auth = sdk.getAuthManager?.() ?? null;
61
- if (!this.auth) {
62
- this.error = 'Sign-in is not available with this SDK';
63
- return;
64
- }
65
- this.syncFromSDK();
66
- // The session hydrates after the SDK publishes; follow both signals.
67
- this.unsubscribes.push(sdk.on('auth:changed', () => this.syncFromSDK()));
68
- this.unsubscribes.push(sdk.on('session:changed', () => this.syncFromSDK()));
69
- const urlCode = this.codeFromUrl();
70
- if (urlCode && !this.auth.authenticated) {
71
- await this.exchange(urlCode);
72
- }
57
+ syncProps() {
58
+ this.element.setProps({ heading: this.heading, allowCodeEntry: this.allowCodeEntry });
73
59
  }
74
- disconnectedCallback() {
75
- this.unsubscribes.forEach((off) => off());
76
- this.unsubscribes = [];
77
- }
78
- codeFromUrl() {
79
- if (typeof window === 'undefined' || !window.location?.search || this.urlCodeUsed)
80
- return null;
81
- const code = new URLSearchParams(window.location.search).get('code');
82
- if (code)
83
- this.urlCodeUsed = true;
84
- return code;
60
+ connectedCallback() {
61
+ this.syncProps();
62
+ this.unsubscribe ?? (this.unsubscribe = this.element.subscribe((view) => {
63
+ this.view = view;
64
+ }));
65
+ this.view = this.element.view;
66
+ this.teardown = this.element.mount();
85
67
  }
86
- syncFromSDK() {
87
- if (!this.auth)
88
- return;
89
- if (this.auth.authenticated) {
90
- this.customer = this.auth.customer ?? null;
91
- this.phase = 'signed-in';
92
- }
93
- else if (this.phase === 'signed-in') {
94
- this.customer = null;
95
- this.phase = 'email';
96
- }
97
- }
98
- async requestLink(resend = false) {
99
- const email = this.email.trim();
100
- if (!email) {
101
- this.error = 'Enter your email address';
102
- return;
103
- }
104
- if (!this.auth)
105
- return;
106
- this.busy = true;
107
- this.error = null;
108
- this.notice = null;
109
- try {
110
- // Always reports success; account existence is never revealed.
111
- await this.auth.requestMagicLink({ email });
112
- this.phase = 'sent';
113
- this.notice = resend ? 'Sent again. Check your inbox.' : null;
114
- this.tlMagicLinkSent.emit({ email });
115
- }
116
- catch (err) {
117
- console.error('[tl-login] Magic-link request failed:', err);
118
- this.error = errorMessage(err, 'Could not send your sign-in link');
119
- this.tlError.emit({ message: this.error });
120
- }
121
- finally {
122
- this.busy = false;
123
- }
68
+ /**
69
+ * Nothing is painted until this page's client is up.
70
+ *
71
+ * A rendering decision, and the harness's to make: Stencil waits on this
72
+ * promise before the first render, and without it the form would flash
73
+ * disabled for a microtask on every page. The core is already at work by
74
+ * now - `connectedCallback` mounted it - so this waits on the same
75
+ * `whenSDK()` it is waiting on rather than deciding anything of its own, and
76
+ * a page that never starts Live renders the core's "not available" state
77
+ * instead of hanging.
78
+ */
79
+ componentWillLoad() {
80
+ return whenSDK().catch(() => undefined);
124
81
  }
125
- async exchange(code) {
126
- if (!code) {
127
- this.error = 'Enter the code from your email';
128
- return;
129
- }
130
- if (!this.auth)
131
- return;
132
- const previous = this.phase;
133
- this.busy = true;
134
- this.error = null;
135
- this.phase = 'verifying';
136
- try {
137
- const res = (await this.auth.exchange(code));
138
- this.customer = this.auth.customer ?? res?.customer ?? null;
139
- this.phase = 'signed-in';
140
- this.code = '';
141
- this.tlAuthChanged.emit({ customer: this.customer, authenticated: true });
142
- }
143
- catch (err) {
144
- console.error('[tl-login] Code exchange failed:', err);
145
- this.phase = previous === 'verifying' || previous === 'email' ? 'email' : 'code';
146
- this.error = 'That code did not work. Check it and try again, or request a new link.';
147
- this.tlError.emit({ message: this.error });
148
- }
149
- finally {
150
- this.busy = false;
151
- }
82
+ /**
83
+ * Off screen: run the mount's teardown, which drops both auth
84
+ * subscriptions. Not `destroy()`: Stencil calls this for a DOM move as well
85
+ * as a removal, and a destroyed core never mounts again.
86
+ */
87
+ disconnectedCallback() {
88
+ this.teardown?.();
89
+ this.teardown = undefined;
90
+ this.unsubscribe?.();
91
+ this.unsubscribe = undefined;
152
92
  }
153
- async signOut() {
154
- if (!this.auth)
155
- return;
156
- this.busy = true;
157
- try {
158
- await this.auth.logout();
159
- }
160
- catch (err) {
161
- console.error('[tl-login] Sign out failed:', err);
162
- }
163
- finally {
164
- this.busy = false;
165
- this.customer = null;
166
- this.phase = 'email';
167
- this.tlAuthChanged.emit({ customer: null, authenticated: false });
168
- }
93
+ forward(event, detail) {
94
+ if (event === 'tlAuthChanged')
95
+ this.tlAuthChanged.emit(detail);
96
+ else if (event === 'tlMagicLinkSent')
97
+ this.tlMagicLinkSent.emit(detail);
98
+ else if (event === 'tlError')
99
+ this.tlError.emit(detail);
169
100
  }
170
101
  renderError() {
171
- return this.error ? (h("p", { class: "error", role: "alert" }, this.error)) : null;
102
+ const error = this.view.state.error;
103
+ return error ? (h("p", { class: "error", role: "alert" }, error)) : null;
172
104
  }
173
105
  render() {
174
- if (this.phase === 'signed-in') {
175
- return (h("div", { class: "login signed-in" }, h("p", { class: "signed-in-text" }, "Signed in as ", h("strong", null, this.customer?.email ?? 'your account')), h("button", { type: "button", class: "secondary", disabled: this.busy, onClick: () => this.signOut() }, "Sign out")));
106
+ const { status, state, strings, derived } = this.view;
107
+ if (status === 'signed-in') {
108
+ return (h("div", { class: "login signed-in" }, h("p", { class: "signed-in-text" }, strings.signedInPrefix, h("strong", null, derived.signedInEmail)), h("button", { type: "button", class: "secondary", disabled: state.busy, onClick: () => this.element.actions.signOut() }, strings.signOut)));
176
109
  }
177
- if (this.phase === 'verifying') {
178
- return (h("div", { class: "login" }, h("h2", { class: "title" }, "Signing you in\u2026"), h("p", { class: "lead" }, "Just a moment.")));
110
+ if (status === 'verifying') {
111
+ return (h("div", { class: "login" }, h("h2", { class: "title" }, strings.verifyingTitle), h("p", { class: "lead" }, strings.verifyingLead)));
179
112
  }
180
- if (this.phase === 'sent') {
181
- return (h("div", { class: "login" }, h("h2", { class: "title" }, "Check your inbox"), h("p", { class: "lead" }, "We've sent a sign-in link to ", h("strong", null, this.email), ". Open it on this device to continue."), this.notice && h("p", { class: "notice" }, this.notice), this.renderError(), h("div", { class: "actions" }, h("button", { type: "button", class: "secondary", disabled: this.busy, onClick: () => this.requestLink(true) }, this.busy ? 'Sending…' : 'Resend link'), this.allowCodeEntry && (h("button", { type: "button", class: "link", onClick: () => (this.phase = 'code') }, "Enter the code instead")), h("button", { type: "button", class: "link", onClick: () => (this.phase = 'email') }, "Use a different email"))));
113
+ if (status === 'sent') {
114
+ return (h("div", { class: "login" }, h("h2", { class: "title" }, strings.sentTitle), h("p", { class: "lead" }, strings.sentLeadBefore, h("strong", null, state.email), strings.sentLeadAfter), state.notice && h("p", { class: "notice" }, state.notice), this.renderError(), h("div", { class: "actions" }, h("button", { type: "button", class: "secondary", disabled: state.busy, onClick: () => this.element.actions.requestLink(true) }, derived.resendLabel), derived.showCodeEntry && (h("button", { type: "button", class: "link", onClick: () => this.element.actions.goTo('code') }, strings.enterCodeInstead)), h("button", { type: "button", class: "link", onClick: () => this.element.actions.goTo('email') }, strings.differentEmail))));
182
115
  }
183
- if (this.phase === 'code') {
184
- return (h("form", { class: "login", onSubmit: this.handleCodeSubmit }, h("h2", { class: "title" }, "Enter your code"), h("p", { class: "lead" }, "Type the 6-digit code from the email we sent to ", h("strong", null, this.email), "."), h("label", { class: "label", htmlFor: "tl-login-code" }, "Code"), h("input", { id: "tl-login-code", class: "input code-input", type: "text", inputmode: "numeric", autocomplete: "one-time-code", placeholder: "123456", value: this.code, disabled: this.busy, onInput: this.handleCodeInput }), this.renderError(), h("button", { type: "submit", class: "primary", disabled: this.busy }, this.busy ? 'Checking…' : 'Sign in'), h("div", { class: "actions" }, h("button", { type: "button", class: "link", onClick: () => this.requestLink(true) }, "Resend link"), h("button", { type: "button", class: "link", onClick: () => (this.phase = 'sent') }, "Back"))));
116
+ if (status === 'code') {
117
+ return (h("form", { class: "login", onSubmit: this.handleCodeSubmit }, h("h2", { class: "title" }, strings.codeTitle), h("p", { class: "lead" }, strings.codeLeadBefore, h("strong", null, state.email), strings.codeLeadAfter), h("label", { class: "label", htmlFor: "tl-login-code" }, strings.codeLabel), h("input", { id: "tl-login-code", class: "input code-input", type: "text", inputmode: "numeric", autocomplete: "one-time-code", placeholder: strings.codePlaceholder, value: state.code, disabled: state.busy, onInput: this.handleCodeInput }), this.renderError(), h("button", { type: "submit", class: "primary", disabled: state.busy }, derived.codeSubmitLabel), h("div", { class: "actions" }, h("button", { type: "button", class: "link", onClick: () => this.element.actions.requestLink(true) }, strings.resendLink), h("button", { type: "button", class: "link", onClick: () => this.element.actions.goTo('sent') }, strings.back))));
185
118
  }
186
- return (h("form", { class: "login", onSubmit: this.handleEmailSubmit }, h("h2", { class: "title" }, this.heading), h("p", { class: "lead" }, "Enter your email and we'll send you a secure sign-in link. No password needed."), h("label", { class: "label", htmlFor: "tl-login-email" }, "Email address"), h("input", { id: "tl-login-email", class: "input", type: "email", autocomplete: "email", placeholder: "you@example.com", required: true, value: this.email, disabled: this.busy || !this.auth, onInput: this.handleEmailInput }), this.renderError(), h("button", { type: "submit", class: "primary", disabled: this.busy || !this.auth }, this.busy ? 'Sending link…' : 'Email me a sign-in link')));
119
+ return (h("form", { class: "login", onSubmit: this.handleEmailSubmit }, h("h2", { class: "title" }, this.heading), h("p", { class: "lead" }, strings.emailLead), h("label", { class: "label", htmlFor: "tl-login-email" }, strings.emailLabel), h("input", { id: "tl-login-email", class: "input", type: "email", autocomplete: "email", placeholder: strings.emailPlaceholder, required: true, value: state.email, disabled: derived.inputsDisabled, onInput: this.handleEmailInput }), this.renderError(), h("button", { type: "submit", class: "primary", disabled: derived.inputsDisabled }, derived.emailSubmitLabel)));
187
120
  }
188
121
  static get is() { return "tl-login"; }
189
122
  static get encapsulation() { return "shadow"; }
@@ -243,13 +176,7 @@ export class TlLogin {
243
176
  }
244
177
  static get states() {
245
178
  return {
246
- "phase": {},
247
- "email": {},
248
- "code": {},
249
- "busy": {},
250
- "error": {},
251
- "notice": {},
252
- "customer": {}
179
+ "view": {}
253
180
  };
254
181
  }
255
182
  static get events() {
@@ -306,4 +233,13 @@ export class TlLogin {
306
233
  }
307
234
  }];
308
235
  }
236
+ static get watchers() {
237
+ return [{
238
+ "propName": "heading",
239
+ "methodName": "syncProps"
240
+ }, {
241
+ "propName": "allowCodeEntry",
242
+ "methodName": "syncProps"
243
+ }];
244
+ }
309
245
  }
@@ -1,13 +1,13 @@
1
1
  :host {
2
2
  display: block;
3
- font-family: var(--tl-font-family, system-ui, sans-serif);
4
- color: var(--tl-foreground, #111827);
3
+ font-family: var(--tl-font-family);
4
+ color: var(--tl-foreground);
5
5
  }
6
6
 
7
7
  .orders {
8
8
  display: flex;
9
9
  flex-direction: column;
10
- gap: var(--tl-spacing-4, 1rem);
10
+ gap: var(--tl-spacing-4);
11
11
  }
12
12
 
13
13
  .order-list {
@@ -16,20 +16,20 @@
16
16
  padding: 0;
17
17
  display: flex;
18
18
  flex-direction: column;
19
- gap: var(--tl-spacing-3, 0.75rem);
19
+ gap: var(--tl-spacing-3);
20
20
  }
21
21
 
22
22
  .order {
23
- background: var(--tl-background, #ffffff);
24
- border: 1px solid var(--tl-border, #e5e7eb);
25
- border-radius: var(--tl-radius-lg, 0.75rem);
23
+ background: var(--tl-background);
24
+ border: 1px solid var(--tl-border);
25
+ border-radius: var(--tl-radius-lg);
26
26
  overflow: hidden;
27
27
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
28
28
  }
29
29
 
30
30
  .order:hover,
31
31
  .order.expanded {
32
- border-color: var(--tl-primary, #6366f1);
32
+ border-color: var(--tl-primary);
33
33
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
34
34
  }
35
35
 
@@ -37,9 +37,9 @@
37
37
  display: flex;
38
38
  align-items: center;
39
39
  justify-content: space-between;
40
- gap: var(--tl-spacing-4, 1rem);
40
+ gap: var(--tl-spacing-4);
41
41
  width: 100%;
42
- padding: var(--tl-spacing-4, 1rem);
42
+ padding: var(--tl-spacing-4);
43
43
  font: inherit;
44
44
  color: inherit;
45
45
  text-align: left;
@@ -51,7 +51,7 @@
51
51
  .order-main {
52
52
  display: flex;
53
53
  flex-direction: column;
54
- gap: var(--tl-spacing-1, 0.25rem);
54
+ gap: var(--tl-spacing-1);
55
55
  min-width: 0;
56
56
  }
57
57
 
@@ -60,7 +60,7 @@
60
60
  font-weight: 500;
61
61
  text-transform: uppercase;
62
62
  letter-spacing: 0.05em;
63
- color: var(--tl-muted-foreground, #6b7280);
63
+ color: var(--tl-muted-foreground);
64
64
  }
65
65
 
66
66
  .order-event {
@@ -74,15 +74,15 @@
74
74
  .order-meta {
75
75
  display: flex;
76
76
  flex-wrap: wrap;
77
- gap: var(--tl-spacing-3, 0.75rem);
77
+ gap: var(--tl-spacing-3);
78
78
  font-size: 0.8125rem;
79
- color: var(--tl-muted-foreground, #6b7280);
79
+ color: var(--tl-muted-foreground);
80
80
  }
81
81
 
82
82
  .order-side {
83
83
  display: flex;
84
84
  align-items: center;
85
- gap: var(--tl-spacing-3, 0.75rem);
85
+ gap: var(--tl-spacing-3);
86
86
  flex-shrink: 0;
87
87
  }
88
88
 
@@ -95,34 +95,34 @@
95
95
  font-size: 0.75rem;
96
96
  font-weight: 500;
97
97
  border-radius: 9999px;
98
- background: var(--tl-secondary, #f3f4f6);
99
- color: var(--tl-secondary-foreground, #111827);
98
+ background: var(--tl-secondary);
99
+ color: var(--tl-secondary-foreground);
100
100
  }
101
101
 
102
102
  .status-success {
103
- background: var(--tl-success, #10b981);
104
- color: var(--tl-success-foreground, #ffffff);
103
+ background: var(--tl-success);
104
+ color: var(--tl-success-foreground);
105
105
  }
106
106
 
107
107
  .status-info {
108
- background: var(--tl-primary, #6366f1);
109
- color: var(--tl-primary-foreground, #ffffff);
108
+ background: var(--tl-primary);
109
+ color: var(--tl-primary-foreground);
110
110
  }
111
111
 
112
112
  .status-warning {
113
- background: var(--tl-warning, #f59e0b);
114
- color: var(--tl-warning-foreground, #ffffff);
113
+ background: var(--tl-warning);
114
+ color: var(--tl-warning-foreground);
115
115
  }
116
116
 
117
117
  .status-error {
118
- background: var(--tl-error, #ef4444);
119
- color: var(--tl-error-foreground, #ffffff);
118
+ background: var(--tl-error);
119
+ color: var(--tl-error-foreground);
120
120
  }
121
121
 
122
122
  .chevron {
123
123
  width: 1.125rem;
124
124
  height: 1.125rem;
125
- color: var(--tl-muted-foreground, #6b7280);
125
+ color: var(--tl-muted-foreground);
126
126
  transition: transform 0.2s ease;
127
127
  }
128
128
 
@@ -131,9 +131,9 @@
131
131
  }
132
132
 
133
133
  .order-tickets {
134
- padding: 0 var(--tl-spacing-4, 1rem) var(--tl-spacing-4, 1rem);
135
- border-top: 1px solid var(--tl-border, #e5e7eb);
136
- padding-top: var(--tl-spacing-4, 1rem);
134
+ padding: 0 var(--tl-spacing-4) var(--tl-spacing-4);
135
+ border-top: 1px solid var(--tl-border);
136
+ padding-top: var(--tl-spacing-4);
137
137
  }
138
138
 
139
139
  @media (max-width: 480px) {
@@ -161,35 +161,35 @@
161
161
 
162
162
  .signin-text,
163
163
  .state-text {
164
- margin: var(--tl-spacing-1, 0.25rem) 0 0;
164
+ margin: var(--tl-spacing-1) 0 0;
165
165
  font-size: 0.875rem;
166
- color: var(--tl-muted-foreground, #6b7280);
166
+ color: var(--tl-muted-foreground);
167
167
  }
168
168
 
169
169
  .state {
170
- padding: var(--tl-spacing-8, 2rem) var(--tl-spacing-4, 1rem);
170
+ padding: var(--tl-spacing-8) var(--tl-spacing-4);
171
171
  text-align: center;
172
- background: var(--tl-background, #ffffff);
173
- border: 1px solid var(--tl-border, #e5e7eb);
174
- border-radius: var(--tl-radius-lg, 0.75rem);
172
+ background: var(--tl-background);
173
+ border: 1px solid var(--tl-border);
174
+ border-radius: var(--tl-radius-lg);
175
175
  }
176
176
 
177
177
  .state.error .state-title {
178
- color: var(--tl-error, #ef4444);
178
+ color: var(--tl-error);
179
179
  }
180
180
 
181
181
  .empty-icon {
182
182
  width: 3rem;
183
183
  height: 3rem;
184
- margin: 0 auto var(--tl-spacing-3, 0.75rem);
185
- color: var(--tl-primary, #6366f1);
184
+ margin: 0 auto var(--tl-spacing-3);
185
+ color: var(--tl-primary);
186
186
  }
187
187
 
188
188
  /* Skeleton */
189
189
  .skeleton {
190
190
  height: 5rem;
191
- background: var(--tl-secondary, #f3f4f6);
192
- border-radius: var(--tl-radius-lg, 0.75rem);
191
+ background: var(--tl-secondary);
192
+ border-radius: var(--tl-radius-lg);
193
193
  animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
194
194
  }
195
195