@wodira/browser 0.1.0 → 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 (71) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +259 -17
  3. package/dist/index.cjs +38 -5
  4. package/dist/index.d.ts +110 -2
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +38 -4
  7. package/dist/types.d.ts +56 -2
  8. package/dist/types.d.ts.map +1 -1
  9. package/dist/ui/boxes/cdn.d.ts +2 -0
  10. package/dist/ui/boxes/cdn.d.ts.map +1 -0
  11. package/dist/ui/boxes/cdn.js +743 -0
  12. package/dist/ui/boxes/client.d.ts +30 -0
  13. package/dist/ui/boxes/client.d.ts.map +1 -0
  14. package/dist/ui/boxes/components.d.ts +246 -0
  15. package/dist/ui/boxes/components.d.ts.map +1 -0
  16. package/dist/ui/boxes/i18n.d.ts +107 -0
  17. package/dist/ui/boxes/i18n.d.ts.map +1 -0
  18. package/dist/ui/boxes/index.d.ts +16 -0
  19. package/dist/ui/boxes/index.d.ts.map +1 -0
  20. package/dist/ui/boxes/index.js +3071 -0
  21. package/dist/ui/boxes/styles.d.ts +2 -0
  22. package/dist/ui/boxes/styles.d.ts.map +1 -0
  23. package/dist/ui/boxes/types.d.ts +105 -0
  24. package/dist/ui/boxes/types.d.ts.map +1 -0
  25. package/dist/ui/components.d.ts +158 -4
  26. package/dist/ui/components.d.ts.map +1 -1
  27. package/dist/ui/events.d.ts +1 -1
  28. package/dist/ui/events.d.ts.map +1 -1
  29. package/dist/ui/i18n.d.ts +4 -1
  30. package/dist/ui/i18n.d.ts.map +1 -1
  31. package/dist/ui/index-tfej862z.js +3264 -0
  32. package/dist/ui/index-xdhg885t.js +997 -0
  33. package/dist/ui/index.d.ts +19 -3
  34. package/dist/ui/index.d.ts.map +1 -1
  35. package/dist/ui/index.js +9038 -2030
  36. package/dist/ui/layout-styles.d.ts +3 -0
  37. package/dist/ui/layout-styles.d.ts.map +1 -0
  38. package/dist/ui/registration-eligibility.d.ts +52 -0
  39. package/dist/ui/registration-eligibility.d.ts.map +1 -0
  40. package/dist/ui/shirt-3d-renderer-jyks1h8f.js +10 -0
  41. package/dist/ui/shirt-sponsors/cdn.d.ts +2 -0
  42. package/dist/ui/shirt-sponsors/cdn.d.ts.map +1 -0
  43. package/dist/ui/shirt-sponsors/cdn.js +5125 -0
  44. package/dist/ui/shirt-sponsors/index.d.ts +9 -0
  45. package/dist/ui/shirt-sponsors/index.d.ts.map +1 -0
  46. package/dist/ui/shirt-sponsors/index.js +10 -0
  47. package/dist/ui/shirt-sponsors/render/auction-model.d.ts +55 -0
  48. package/dist/ui/shirt-sponsors/render/auction-model.d.ts.map +1 -0
  49. package/dist/ui/shirt-sponsors/render/index.d.ts +7 -0
  50. package/dist/ui/shirt-sponsors/render/index.d.ts.map +1 -0
  51. package/dist/ui/shirt-sponsors/render/index.js +34 -0
  52. package/dist/ui/shirt-sponsors/render/shirt-3d-renderer.d.ts +109 -0
  53. package/dist/ui/shirt-sponsors/render/shirt-3d-renderer.d.ts.map +1 -0
  54. package/dist/ui/shirt-sponsors/render/shirt-artwork-projection.d.ts +13 -0
  55. package/dist/ui/shirt-sponsors/render/shirt-artwork-projection.d.ts.map +1 -0
  56. package/dist/ui/shirt-sponsors/render/shirt-artwork.d.ts +17 -0
  57. package/dist/ui/shirt-sponsors/render/shirt-artwork.d.ts.map +1 -0
  58. package/dist/ui/shirt-sponsors/render/shirt-cloth-motion.d.ts +31 -0
  59. package/dist/ui/shirt-sponsors/render/shirt-cloth-motion.d.ts.map +1 -0
  60. package/dist/ui/shirt-sponsors/render/shirt-silhouette.d.ts +9 -0
  61. package/dist/ui/shirt-sponsors/render/shirt-silhouette.d.ts.map +1 -0
  62. package/dist/ui/shirt-sponsors/shirt-auction.d.ts +137 -0
  63. package/dist/ui/shirt-sponsors/shirt-auction.d.ts.map +1 -0
  64. package/dist/ui/signature-pad.d.ts +29 -0
  65. package/dist/ui/signature-pad.d.ts.map +1 -0
  66. package/dist/ui/styles.d.ts.map +1 -1
  67. package/dist/ui/theme.d.ts +63 -0
  68. package/dist/ui/theme.d.ts.map +1 -0
  69. package/dist/ui/validators.d.ts +1 -1
  70. package/dist/ui/validators.d.ts.map +1 -1
  71. package/package.json +42 -13
@@ -0,0 +1,3071 @@
1
+ // ../../node_modules/.pnpm/@lit+reactive-element@2.1.2/node_modules/@lit/reactive-element/development/css-tag.js
2
+ var NODE_MODE = false;
3
+ var global = globalThis;
4
+ var supportsAdoptingStyleSheets = global.ShadowRoot && (global.ShadyCSS === undefined || global.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype;
5
+ var constructionToken = Symbol();
6
+ var cssTagCache = new WeakMap;
7
+
8
+ class CSSResult {
9
+ constructor(cssText, strings, safeToken) {
10
+ this["_$cssResult$"] = true;
11
+ if (safeToken !== constructionToken) {
12
+ throw new Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");
13
+ }
14
+ this.cssText = cssText;
15
+ this._strings = strings;
16
+ }
17
+ get styleSheet() {
18
+ let styleSheet = this._styleSheet;
19
+ const strings = this._strings;
20
+ if (supportsAdoptingStyleSheets && styleSheet === undefined) {
21
+ const cacheable = strings !== undefined && strings.length === 1;
22
+ if (cacheable) {
23
+ styleSheet = cssTagCache.get(strings);
24
+ }
25
+ if (styleSheet === undefined) {
26
+ (this._styleSheet = styleSheet = new CSSStyleSheet).replaceSync(this.cssText);
27
+ if (cacheable) {
28
+ cssTagCache.set(strings, styleSheet);
29
+ }
30
+ }
31
+ }
32
+ return styleSheet;
33
+ }
34
+ toString() {
35
+ return this.cssText;
36
+ }
37
+ }
38
+ var textFromCSSResult = (value) => {
39
+ if (value["_$cssResult$"] === true) {
40
+ return value.cssText;
41
+ } else if (typeof value === "number") {
42
+ return value;
43
+ } else {
44
+ throw new Error(`Value passed to 'css' function must be a 'css' function result: ` + `${value}. Use 'unsafeCSS' to pass non-literal values, but take care ` + `to ensure page security.`);
45
+ }
46
+ };
47
+ var unsafeCSS = (value) => new CSSResult(typeof value === "string" ? value : String(value), undefined, constructionToken);
48
+ var css = (strings, ...values) => {
49
+ const cssText = strings.length === 1 ? strings[0] : values.reduce((acc, v, idx) => acc + textFromCSSResult(v) + strings[idx + 1], strings[0]);
50
+ return new CSSResult(cssText, strings, constructionToken);
51
+ };
52
+ var adoptStyles = (renderRoot, styles) => {
53
+ if (supportsAdoptingStyleSheets) {
54
+ renderRoot.adoptedStyleSheets = styles.map((s) => s instanceof CSSStyleSheet ? s : s.styleSheet);
55
+ } else {
56
+ for (const s of styles) {
57
+ const style = document.createElement("style");
58
+ const nonce = global["litNonce"];
59
+ if (nonce !== undefined) {
60
+ style.setAttribute("nonce", nonce);
61
+ }
62
+ style.textContent = s.cssText;
63
+ renderRoot.appendChild(style);
64
+ }
65
+ }
66
+ };
67
+ var cssResultFromStyleSheet = (sheet) => {
68
+ let cssText = "";
69
+ for (const rule of sheet.cssRules) {
70
+ cssText += rule.cssText;
71
+ }
72
+ return unsafeCSS(cssText);
73
+ };
74
+ var getCompatibleStyle = supportsAdoptingStyleSheets || NODE_MODE && global.CSSStyleSheet === undefined ? (s) => s : (s) => s instanceof CSSStyleSheet ? cssResultFromStyleSheet(s) : s;
75
+
76
+ // ../../node_modules/.pnpm/@lit+reactive-element@2.1.2/node_modules/@lit/reactive-element/development/reactive-element.js
77
+ var { is, defineProperty, getOwnPropertyDescriptor, getOwnPropertyNames, getOwnPropertySymbols, getPrototypeOf } = Object;
78
+ var NODE_MODE2 = false;
79
+ var global2 = globalThis;
80
+ if (NODE_MODE2) {
81
+ global2.customElements ??= customElements;
82
+ }
83
+ var DEV_MODE = true;
84
+ var issueWarning;
85
+ var trustedTypes = global2.trustedTypes;
86
+ var emptyStringForBooleanAttribute = trustedTypes ? trustedTypes.emptyScript : "";
87
+ var polyfillSupport = DEV_MODE ? global2.reactiveElementPolyfillSupportDevMode : global2.reactiveElementPolyfillSupport;
88
+ if (DEV_MODE) {
89
+ global2.litIssuedWarnings ??= new Set;
90
+ issueWarning = (code, warning) => {
91
+ warning += ` See https://lit.dev/msg/${code} for more information.`;
92
+ if (!global2.litIssuedWarnings.has(warning) && !global2.litIssuedWarnings.has(code)) {
93
+ console.warn(warning);
94
+ global2.litIssuedWarnings.add(warning);
95
+ }
96
+ };
97
+ queueMicrotask(() => {
98
+ issueWarning("dev-mode", `Lit is in dev mode. Not recommended for production!`);
99
+ if (global2.ShadyDOM?.inUse && polyfillSupport === undefined) {
100
+ issueWarning("polyfill-support-missing", `Shadow DOM is being polyfilled via \`ShadyDOM\` but ` + `the \`polyfill-support\` module has not been loaded.`);
101
+ }
102
+ });
103
+ }
104
+ var debugLogEvent = DEV_MODE ? (event) => {
105
+ const shouldEmit = global2.emitLitDebugLogEvents;
106
+ if (!shouldEmit) {
107
+ return;
108
+ }
109
+ global2.dispatchEvent(new CustomEvent("lit-debug", {
110
+ detail: event
111
+ }));
112
+ } : undefined;
113
+ var JSCompiler_renameProperty = (prop, _obj) => prop;
114
+ var defaultConverter = {
115
+ toAttribute(value, type) {
116
+ switch (type) {
117
+ case Boolean:
118
+ value = value ? emptyStringForBooleanAttribute : null;
119
+ break;
120
+ case Object:
121
+ case Array:
122
+ value = value == null ? value : JSON.stringify(value);
123
+ break;
124
+ }
125
+ return value;
126
+ },
127
+ fromAttribute(value, type) {
128
+ let fromValue = value;
129
+ switch (type) {
130
+ case Boolean:
131
+ fromValue = value !== null;
132
+ break;
133
+ case Number:
134
+ fromValue = value === null ? null : Number(value);
135
+ break;
136
+ case Object:
137
+ case Array:
138
+ try {
139
+ fromValue = JSON.parse(value);
140
+ } catch (e) {
141
+ fromValue = null;
142
+ }
143
+ break;
144
+ }
145
+ return fromValue;
146
+ }
147
+ };
148
+ var notEqual = (value, old) => !is(value, old);
149
+ var defaultPropertyDeclaration = {
150
+ attribute: true,
151
+ type: String,
152
+ converter: defaultConverter,
153
+ reflect: false,
154
+ useDefault: false,
155
+ hasChanged: notEqual
156
+ };
157
+ Symbol.metadata ??= Symbol("metadata");
158
+ global2.litPropertyMetadata ??= new WeakMap;
159
+
160
+ class ReactiveElement extends HTMLElement {
161
+ static addInitializer(initializer) {
162
+ this.__prepare();
163
+ (this._initializers ??= []).push(initializer);
164
+ }
165
+ static get observedAttributes() {
166
+ this.finalize();
167
+ return this.__attributeToPropertyMap && [...this.__attributeToPropertyMap.keys()];
168
+ }
169
+ static createProperty(name, options = defaultPropertyDeclaration) {
170
+ if (options.state) {
171
+ options.attribute = false;
172
+ }
173
+ this.__prepare();
174
+ if (this.prototype.hasOwnProperty(name)) {
175
+ options = Object.create(options);
176
+ options.wrapped = true;
177
+ }
178
+ this.elementProperties.set(name, options);
179
+ if (!options.noAccessor) {
180
+ const key = DEV_MODE ? Symbol.for(`${String(name)} (@property() cache)`) : Symbol();
181
+ const descriptor = this.getPropertyDescriptor(name, key, options);
182
+ if (descriptor !== undefined) {
183
+ defineProperty(this.prototype, name, descriptor);
184
+ }
185
+ }
186
+ }
187
+ static getPropertyDescriptor(name, key, options) {
188
+ const { get, set } = getOwnPropertyDescriptor(this.prototype, name) ?? {
189
+ get() {
190
+ return this[key];
191
+ },
192
+ set(v) {
193
+ this[key] = v;
194
+ }
195
+ };
196
+ if (DEV_MODE && get == null) {
197
+ if ("value" in (getOwnPropertyDescriptor(this.prototype, name) ?? {})) {
198
+ throw new Error(`Field ${JSON.stringify(String(name))} on ` + `${this.name} was declared as a reactive property ` + `but it's actually declared as a value on the prototype. ` + `Usually this is due to using @property or @state on a method.`);
199
+ }
200
+ issueWarning("reactive-property-without-getter", `Field ${JSON.stringify(String(name))} on ` + `${this.name} was declared as a reactive property ` + `but it does not have a getter. This will be an error in a ` + `future version of Lit.`);
201
+ }
202
+ return {
203
+ get,
204
+ set(value) {
205
+ const oldValue = get?.call(this);
206
+ set?.call(this, value);
207
+ this.requestUpdate(name, oldValue, options);
208
+ },
209
+ configurable: true,
210
+ enumerable: true
211
+ };
212
+ }
213
+ static getPropertyOptions(name) {
214
+ return this.elementProperties.get(name) ?? defaultPropertyDeclaration;
215
+ }
216
+ static __prepare() {
217
+ if (this.hasOwnProperty(JSCompiler_renameProperty("elementProperties", this))) {
218
+ return;
219
+ }
220
+ const superCtor = getPrototypeOf(this);
221
+ superCtor.finalize();
222
+ if (superCtor._initializers !== undefined) {
223
+ this._initializers = [...superCtor._initializers];
224
+ }
225
+ this.elementProperties = new Map(superCtor.elementProperties);
226
+ }
227
+ static finalize() {
228
+ if (this.hasOwnProperty(JSCompiler_renameProperty("finalized", this))) {
229
+ return;
230
+ }
231
+ this.finalized = true;
232
+ this.__prepare();
233
+ if (this.hasOwnProperty(JSCompiler_renameProperty("properties", this))) {
234
+ const props = this.properties;
235
+ const propKeys = [
236
+ ...getOwnPropertyNames(props),
237
+ ...getOwnPropertySymbols(props)
238
+ ];
239
+ for (const p of propKeys) {
240
+ this.createProperty(p, props[p]);
241
+ }
242
+ }
243
+ const metadata = this[Symbol.metadata];
244
+ if (metadata !== null) {
245
+ const properties = litPropertyMetadata.get(metadata);
246
+ if (properties !== undefined) {
247
+ for (const [p, options] of properties) {
248
+ this.elementProperties.set(p, options);
249
+ }
250
+ }
251
+ }
252
+ this.__attributeToPropertyMap = new Map;
253
+ for (const [p, options] of this.elementProperties) {
254
+ const attr = this.__attributeNameForProperty(p, options);
255
+ if (attr !== undefined) {
256
+ this.__attributeToPropertyMap.set(attr, p);
257
+ }
258
+ }
259
+ this.elementStyles = this.finalizeStyles(this.styles);
260
+ if (DEV_MODE) {
261
+ if (this.hasOwnProperty("createProperty")) {
262
+ issueWarning("no-override-create-property", "Overriding ReactiveElement.createProperty() is deprecated. " + "The override will not be called with standard decorators");
263
+ }
264
+ if (this.hasOwnProperty("getPropertyDescriptor")) {
265
+ issueWarning("no-override-get-property-descriptor", "Overriding ReactiveElement.getPropertyDescriptor() is deprecated. " + "The override will not be called with standard decorators");
266
+ }
267
+ }
268
+ }
269
+ static finalizeStyles(styles) {
270
+ const elementStyles = [];
271
+ if (Array.isArray(styles)) {
272
+ const set = new Set(styles.flat(Infinity).reverse());
273
+ for (const s of set) {
274
+ elementStyles.unshift(getCompatibleStyle(s));
275
+ }
276
+ } else if (styles !== undefined) {
277
+ elementStyles.push(getCompatibleStyle(styles));
278
+ }
279
+ return elementStyles;
280
+ }
281
+ static __attributeNameForProperty(name, options) {
282
+ const attribute = options.attribute;
283
+ return attribute === false ? undefined : typeof attribute === "string" ? attribute : typeof name === "string" ? name.toLowerCase() : undefined;
284
+ }
285
+ constructor() {
286
+ super();
287
+ this.__instanceProperties = undefined;
288
+ this.isUpdatePending = false;
289
+ this.hasUpdated = false;
290
+ this.__reflectingProperty = null;
291
+ this.__initialize();
292
+ }
293
+ __initialize() {
294
+ this.__updatePromise = new Promise((res) => this.enableUpdating = res);
295
+ this._$changedProperties = new Map;
296
+ this.__saveInstanceProperties();
297
+ this.requestUpdate();
298
+ this.constructor._initializers?.forEach((i) => i(this));
299
+ }
300
+ addController(controller) {
301
+ (this.__controllers ??= new Set).add(controller);
302
+ if (this.renderRoot !== undefined && this.isConnected) {
303
+ controller.hostConnected?.();
304
+ }
305
+ }
306
+ removeController(controller) {
307
+ this.__controllers?.delete(controller);
308
+ }
309
+ __saveInstanceProperties() {
310
+ const instanceProperties = new Map;
311
+ const elementProperties = this.constructor.elementProperties;
312
+ for (const p of elementProperties.keys()) {
313
+ if (this.hasOwnProperty(p)) {
314
+ instanceProperties.set(p, this[p]);
315
+ delete this[p];
316
+ }
317
+ }
318
+ if (instanceProperties.size > 0) {
319
+ this.__instanceProperties = instanceProperties;
320
+ }
321
+ }
322
+ createRenderRoot() {
323
+ const renderRoot = this.shadowRoot ?? this.attachShadow(this.constructor.shadowRootOptions);
324
+ adoptStyles(renderRoot, this.constructor.elementStyles);
325
+ return renderRoot;
326
+ }
327
+ connectedCallback() {
328
+ this.renderRoot ??= this.createRenderRoot();
329
+ this.enableUpdating(true);
330
+ this.__controllers?.forEach((c) => c.hostConnected?.());
331
+ }
332
+ enableUpdating(_requestedUpdate) {}
333
+ disconnectedCallback() {
334
+ this.__controllers?.forEach((c) => c.hostDisconnected?.());
335
+ }
336
+ attributeChangedCallback(name, _old, value) {
337
+ this._$attributeToProperty(name, value);
338
+ }
339
+ __propertyToAttribute(name, value) {
340
+ const elemProperties = this.constructor.elementProperties;
341
+ const options = elemProperties.get(name);
342
+ const attr = this.constructor.__attributeNameForProperty(name, options);
343
+ if (attr !== undefined && options.reflect === true) {
344
+ const converter = options.converter?.toAttribute !== undefined ? options.converter : defaultConverter;
345
+ const attrValue = converter.toAttribute(value, options.type);
346
+ if (DEV_MODE && this.constructor.enabledWarnings.includes("migration") && attrValue === undefined) {
347
+ issueWarning("undefined-attribute-value", `The attribute value for the ${name} property is ` + `undefined on element ${this.localName}. The attribute will be ` + `removed, but in the previous version of \`ReactiveElement\`, ` + `the attribute would not have changed.`);
348
+ }
349
+ this.__reflectingProperty = name;
350
+ if (attrValue == null) {
351
+ this.removeAttribute(attr);
352
+ } else {
353
+ this.setAttribute(attr, attrValue);
354
+ }
355
+ this.__reflectingProperty = null;
356
+ }
357
+ }
358
+ _$attributeToProperty(name, value) {
359
+ const ctor = this.constructor;
360
+ const propName = ctor.__attributeToPropertyMap.get(name);
361
+ if (propName !== undefined && this.__reflectingProperty !== propName) {
362
+ const options = ctor.getPropertyOptions(propName);
363
+ const converter = typeof options.converter === "function" ? { fromAttribute: options.converter } : options.converter?.fromAttribute !== undefined ? options.converter : defaultConverter;
364
+ this.__reflectingProperty = propName;
365
+ const convertedValue = converter.fromAttribute(value, options.type);
366
+ this[propName] = convertedValue ?? this.__defaultValues?.get(propName) ?? convertedValue;
367
+ this.__reflectingProperty = null;
368
+ }
369
+ }
370
+ requestUpdate(name, oldValue, options, useNewValue = false, newValue) {
371
+ if (name !== undefined) {
372
+ if (DEV_MODE && name instanceof Event) {
373
+ issueWarning(``, `The requestUpdate() method was called with an Event as the property name. This is probably a mistake caused by binding this.requestUpdate as an event listener. Instead bind a function that will call it with no arguments: () => this.requestUpdate()`);
374
+ }
375
+ const ctor = this.constructor;
376
+ if (useNewValue === false) {
377
+ newValue = this[name];
378
+ }
379
+ options ??= ctor.getPropertyOptions(name);
380
+ const changed = (options.hasChanged ?? notEqual)(newValue, oldValue) || options.useDefault && options.reflect && newValue === this.__defaultValues?.get(name) && !this.hasAttribute(ctor.__attributeNameForProperty(name, options));
381
+ if (changed) {
382
+ this._$changeProperty(name, oldValue, options);
383
+ } else {
384
+ return;
385
+ }
386
+ }
387
+ if (this.isUpdatePending === false) {
388
+ this.__updatePromise = this.__enqueueUpdate();
389
+ }
390
+ }
391
+ _$changeProperty(name, oldValue, { useDefault, reflect, wrapped }, initializeValue) {
392
+ if (useDefault && !(this.__defaultValues ??= new Map).has(name)) {
393
+ this.__defaultValues.set(name, initializeValue ?? oldValue ?? this[name]);
394
+ if (wrapped !== true || initializeValue !== undefined) {
395
+ return;
396
+ }
397
+ }
398
+ if (!this._$changedProperties.has(name)) {
399
+ if (!this.hasUpdated && !useDefault) {
400
+ oldValue = undefined;
401
+ }
402
+ this._$changedProperties.set(name, oldValue);
403
+ }
404
+ if (reflect === true && this.__reflectingProperty !== name) {
405
+ (this.__reflectingProperties ??= new Set).add(name);
406
+ }
407
+ }
408
+ async __enqueueUpdate() {
409
+ this.isUpdatePending = true;
410
+ try {
411
+ await this.__updatePromise;
412
+ } catch (e) {
413
+ Promise.reject(e);
414
+ }
415
+ const result = this.scheduleUpdate();
416
+ if (result != null) {
417
+ await result;
418
+ }
419
+ return !this.isUpdatePending;
420
+ }
421
+ scheduleUpdate() {
422
+ const result = this.performUpdate();
423
+ if (DEV_MODE && this.constructor.enabledWarnings.includes("async-perform-update") && typeof result?.then === "function") {
424
+ issueWarning("async-perform-update", `Element ${this.localName} returned a Promise from performUpdate(). ` + `This behavior is deprecated and will be removed in a future ` + `version of ReactiveElement.`);
425
+ }
426
+ return result;
427
+ }
428
+ performUpdate() {
429
+ if (!this.isUpdatePending) {
430
+ return;
431
+ }
432
+ debugLogEvent?.({ kind: "update" });
433
+ if (!this.hasUpdated) {
434
+ this.renderRoot ??= this.createRenderRoot();
435
+ if (DEV_MODE) {
436
+ const ctor = this.constructor;
437
+ const shadowedProperties = [...ctor.elementProperties.keys()].filter((p) => this.hasOwnProperty(p) && (p in getPrototypeOf(this)));
438
+ if (shadowedProperties.length) {
439
+ throw new Error(`The following properties on element ${this.localName} will not ` + `trigger updates as expected because they are set using class ` + `fields: ${shadowedProperties.join(", ")}. ` + `Native class fields and some compiled output will overwrite ` + `accessors used for detecting changes. See ` + `https://lit.dev/msg/class-field-shadowing ` + `for more information.`);
440
+ }
441
+ }
442
+ if (this.__instanceProperties) {
443
+ for (const [p, value] of this.__instanceProperties) {
444
+ this[p] = value;
445
+ }
446
+ this.__instanceProperties = undefined;
447
+ }
448
+ const elementProperties = this.constructor.elementProperties;
449
+ if (elementProperties.size > 0) {
450
+ for (const [p, options] of elementProperties) {
451
+ const { wrapped } = options;
452
+ const value = this[p];
453
+ if (wrapped === true && !this._$changedProperties.has(p) && value !== undefined) {
454
+ this._$changeProperty(p, undefined, options, value);
455
+ }
456
+ }
457
+ }
458
+ }
459
+ let shouldUpdate = false;
460
+ const changedProperties = this._$changedProperties;
461
+ try {
462
+ shouldUpdate = this.shouldUpdate(changedProperties);
463
+ if (shouldUpdate) {
464
+ this.willUpdate(changedProperties);
465
+ this.__controllers?.forEach((c) => c.hostUpdate?.());
466
+ this.update(changedProperties);
467
+ } else {
468
+ this.__markUpdated();
469
+ }
470
+ } catch (e) {
471
+ shouldUpdate = false;
472
+ this.__markUpdated();
473
+ throw e;
474
+ }
475
+ if (shouldUpdate) {
476
+ this._$didUpdate(changedProperties);
477
+ }
478
+ }
479
+ willUpdate(_changedProperties) {}
480
+ _$didUpdate(changedProperties) {
481
+ this.__controllers?.forEach((c) => c.hostUpdated?.());
482
+ if (!this.hasUpdated) {
483
+ this.hasUpdated = true;
484
+ this.firstUpdated(changedProperties);
485
+ }
486
+ this.updated(changedProperties);
487
+ if (DEV_MODE && this.isUpdatePending && this.constructor.enabledWarnings.includes("change-in-update")) {
488
+ issueWarning("change-in-update", `Element ${this.localName} scheduled an update ` + `(generally because a property was set) ` + `after an update completed, causing a new update to be scheduled. ` + `This is inefficient and should be avoided unless the next update ` + `can only be scheduled as a side effect of the previous update.`);
489
+ }
490
+ }
491
+ __markUpdated() {
492
+ this._$changedProperties = new Map;
493
+ this.isUpdatePending = false;
494
+ }
495
+ get updateComplete() {
496
+ return this.getUpdateComplete();
497
+ }
498
+ getUpdateComplete() {
499
+ return this.__updatePromise;
500
+ }
501
+ shouldUpdate(_changedProperties) {
502
+ return true;
503
+ }
504
+ update(_changedProperties) {
505
+ this.__reflectingProperties &&= this.__reflectingProperties.forEach((p) => this.__propertyToAttribute(p, this[p]));
506
+ this.__markUpdated();
507
+ }
508
+ updated(_changedProperties) {}
509
+ firstUpdated(_changedProperties) {}
510
+ }
511
+ ReactiveElement.elementStyles = [];
512
+ ReactiveElement.shadowRootOptions = { mode: "open" };
513
+ ReactiveElement[JSCompiler_renameProperty("elementProperties", ReactiveElement)] = new Map;
514
+ ReactiveElement[JSCompiler_renameProperty("finalized", ReactiveElement)] = new Map;
515
+ polyfillSupport?.({ ReactiveElement });
516
+ if (DEV_MODE) {
517
+ ReactiveElement.enabledWarnings = [
518
+ "change-in-update",
519
+ "async-perform-update"
520
+ ];
521
+ const ensureOwnWarnings = function(ctor) {
522
+ if (!ctor.hasOwnProperty(JSCompiler_renameProperty("enabledWarnings", ctor))) {
523
+ ctor.enabledWarnings = ctor.enabledWarnings.slice();
524
+ }
525
+ };
526
+ ReactiveElement.enableWarning = function(warning) {
527
+ ensureOwnWarnings(this);
528
+ if (!this.enabledWarnings.includes(warning)) {
529
+ this.enabledWarnings.push(warning);
530
+ }
531
+ };
532
+ ReactiveElement.disableWarning = function(warning) {
533
+ ensureOwnWarnings(this);
534
+ const i = this.enabledWarnings.indexOf(warning);
535
+ if (i >= 0) {
536
+ this.enabledWarnings.splice(i, 1);
537
+ }
538
+ };
539
+ }
540
+ (global2.reactiveElementVersions ??= []).push("2.1.2");
541
+ if (DEV_MODE && global2.reactiveElementVersions.length > 1) {
542
+ queueMicrotask(() => {
543
+ issueWarning("multiple-versions", `Multiple versions of Lit loaded. Loading multiple versions ` + `is not recommended.`);
544
+ });
545
+ }
546
+
547
+ // ../../node_modules/.pnpm/lit-html@3.3.3/node_modules/lit-html/development/lit-html.js
548
+ var DEV_MODE2 = true;
549
+ var ENABLE_EXTRA_SECURITY_HOOKS = true;
550
+ var ENABLE_SHADYDOM_NOPATCH = true;
551
+ var NODE_MODE3 = false;
552
+ var global3 = globalThis;
553
+ var debugLogEvent2 = DEV_MODE2 ? (event) => {
554
+ const shouldEmit = global3.emitLitDebugLogEvents;
555
+ if (!shouldEmit) {
556
+ return;
557
+ }
558
+ global3.dispatchEvent(new CustomEvent("lit-debug", {
559
+ detail: event
560
+ }));
561
+ } : undefined;
562
+ var debugLogRenderId = 0;
563
+ var issueWarning2;
564
+ if (DEV_MODE2) {
565
+ global3.litIssuedWarnings ??= new Set;
566
+ issueWarning2 = (code, warning) => {
567
+ warning += code ? ` See https://lit.dev/msg/${code} for more information.` : "";
568
+ if (!global3.litIssuedWarnings.has(warning) && !global3.litIssuedWarnings.has(code)) {
569
+ console.warn(warning);
570
+ global3.litIssuedWarnings.add(warning);
571
+ }
572
+ };
573
+ queueMicrotask(() => {
574
+ issueWarning2("dev-mode", `Lit is in dev mode. Not recommended for production!`);
575
+ });
576
+ }
577
+ var wrap = ENABLE_SHADYDOM_NOPATCH && global3.ShadyDOM?.inUse && global3.ShadyDOM?.noPatch === true ? global3.ShadyDOM.wrap : (node) => node;
578
+ var trustedTypes2 = global3.trustedTypes;
579
+ var policy = trustedTypes2 ? trustedTypes2.createPolicy("lit-html", {
580
+ createHTML: (s) => s
581
+ }) : undefined;
582
+ var identityFunction = (value) => value;
583
+ var noopSanitizer = (_node, _name, _type) => identityFunction;
584
+ var setSanitizer = (newSanitizer) => {
585
+ if (!ENABLE_EXTRA_SECURITY_HOOKS) {
586
+ return;
587
+ }
588
+ if (sanitizerFactoryInternal !== noopSanitizer) {
589
+ throw new Error(`Attempted to overwrite existing lit-html security policy.` + ` setSanitizeDOMValueFactory should be called at most once.`);
590
+ }
591
+ sanitizerFactoryInternal = newSanitizer;
592
+ };
593
+ var _testOnlyClearSanitizerFactoryDoNotCallOrElse = () => {
594
+ sanitizerFactoryInternal = noopSanitizer;
595
+ };
596
+ var createSanitizer = (node, name, type) => {
597
+ return sanitizerFactoryInternal(node, name, type);
598
+ };
599
+ var boundAttributeSuffix = "$lit$";
600
+ var marker = `lit$${Math.random().toFixed(9).slice(2)}$`;
601
+ var markerMatch = "?" + marker;
602
+ var nodeMarker = `<${markerMatch}>`;
603
+ var d = NODE_MODE3 && global3.document === undefined ? {
604
+ createTreeWalker() {
605
+ return {};
606
+ }
607
+ } : document;
608
+ var createMarker = () => d.createComment("");
609
+ var isPrimitive = (value) => value === null || typeof value != "object" && typeof value != "function";
610
+ var isArray = Array.isArray;
611
+ var isIterable = (value) => isArray(value) || typeof value?.[Symbol.iterator] === "function";
612
+ var SPACE_CHAR = `[
613
+ \f\r]`;
614
+ var ATTR_VALUE_CHAR = `[^
615
+ \f\r"'\`<>=]`;
616
+ var NAME_CHAR = `[^\\s"'>=/]`;
617
+ var textEndRegex = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g;
618
+ var COMMENT_START = 1;
619
+ var TAG_NAME = 2;
620
+ var DYNAMIC_TAG_NAME = 3;
621
+ var commentEndRegex = /-->/g;
622
+ var comment2EndRegex = />/g;
623
+ var tagEndRegex = new RegExp(`>|${SPACE_CHAR}(?:(${NAME_CHAR}+)(${SPACE_CHAR}*=${SPACE_CHAR}*(?:${ATTR_VALUE_CHAR}|("|')|))|$)`, "g");
624
+ var ENTIRE_MATCH = 0;
625
+ var ATTRIBUTE_NAME = 1;
626
+ var SPACES_AND_EQUALS = 2;
627
+ var QUOTE_CHAR = 3;
628
+ var singleQuoteAttrEndRegex = /'/g;
629
+ var doubleQuoteAttrEndRegex = /"/g;
630
+ var rawTextElement = /^(?:script|style|textarea|title)$/i;
631
+ var HTML_RESULT = 1;
632
+ var SVG_RESULT = 2;
633
+ var MATHML_RESULT = 3;
634
+ var ATTRIBUTE_PART = 1;
635
+ var CHILD_PART = 2;
636
+ var PROPERTY_PART = 3;
637
+ var BOOLEAN_ATTRIBUTE_PART = 4;
638
+ var EVENT_PART = 5;
639
+ var ELEMENT_PART = 6;
640
+ var COMMENT_PART = 7;
641
+ var tag = (type) => (strings, ...values) => {
642
+ if (DEV_MODE2 && strings.some((s) => s === undefined)) {
643
+ console.warn(`Some template strings are undefined.
644
+ ` + "This is probably caused by illegal octal escape sequences.");
645
+ }
646
+ if (DEV_MODE2) {
647
+ if (values.some((val) => val?.["_$litStatic$"])) {
648
+ issueWarning2("", `Static values 'literal' or 'unsafeStatic' cannot be used as values to non-static templates.
649
+ ` + `Please use the static 'html' tag function. See https://lit.dev/docs/templates/expressions/#static-expressions`);
650
+ }
651
+ }
652
+ return {
653
+ ["_$litType$"]: type,
654
+ strings,
655
+ values
656
+ };
657
+ };
658
+ var html = tag(HTML_RESULT);
659
+ var svg = tag(SVG_RESULT);
660
+ var mathml = tag(MATHML_RESULT);
661
+ var noChange = Symbol.for("lit-noChange");
662
+ var nothing = Symbol.for("lit-nothing");
663
+ var templateCache = new WeakMap;
664
+ var walker = d.createTreeWalker(d, 129);
665
+ var sanitizerFactoryInternal = noopSanitizer;
666
+ function trustFromTemplateString(tsa, stringFromTSA) {
667
+ if (!isArray(tsa) || !tsa.hasOwnProperty("raw")) {
668
+ let message = "invalid template strings array";
669
+ if (DEV_MODE2) {
670
+ message = `
671
+ Internal Error: expected template strings to be an array
672
+ with a 'raw' field. Faking a template strings array by
673
+ calling html or svg like an ordinary function is effectively
674
+ the same as calling unsafeHtml and can lead to major security
675
+ issues, e.g. opening your code up to XSS attacks.
676
+ If you're using the html or svg tagged template functions normally
677
+ and still seeing this error, please file a bug at
678
+ https://github.com/lit/lit/issues/new?template=bug_report.md
679
+ and include information about your build tooling, if any.
680
+ `.trim().replace(/\n */g, `
681
+ `);
682
+ }
683
+ throw new Error(message);
684
+ }
685
+ return policy !== undefined ? policy.createHTML(stringFromTSA) : stringFromTSA;
686
+ }
687
+ var getTemplateHtml = (strings, type) => {
688
+ const l = strings.length - 1;
689
+ const attrNames = [];
690
+ let html = type === SVG_RESULT ? "<svg>" : type === MATHML_RESULT ? "<math>" : "";
691
+ let rawTextEndRegex;
692
+ let regex = textEndRegex;
693
+ for (let i = 0;i < l; i++) {
694
+ const s = strings[i];
695
+ let attrNameEndIndex = -1;
696
+ let attrName;
697
+ let lastIndex = 0;
698
+ let match;
699
+ while (lastIndex < s.length) {
700
+ regex.lastIndex = lastIndex;
701
+ match = regex.exec(s);
702
+ if (match === null) {
703
+ break;
704
+ }
705
+ lastIndex = regex.lastIndex;
706
+ if (regex === textEndRegex) {
707
+ if (match[COMMENT_START] === "!--") {
708
+ regex = commentEndRegex;
709
+ } else if (match[COMMENT_START] !== undefined) {
710
+ regex = comment2EndRegex;
711
+ } else if (match[TAG_NAME] !== undefined) {
712
+ if (rawTextElement.test(match[TAG_NAME])) {
713
+ rawTextEndRegex = new RegExp(`</${match[TAG_NAME]}`, "g");
714
+ }
715
+ regex = tagEndRegex;
716
+ } else if (match[DYNAMIC_TAG_NAME] !== undefined) {
717
+ if (DEV_MODE2) {
718
+ throw new Error("Bindings in tag names are not supported. Please use static templates instead. " + "See https://lit.dev/docs/templates/expressions/#static-expressions");
719
+ }
720
+ regex = tagEndRegex;
721
+ }
722
+ } else if (regex === tagEndRegex) {
723
+ if (match[ENTIRE_MATCH] === ">") {
724
+ regex = rawTextEndRegex ?? textEndRegex;
725
+ attrNameEndIndex = -1;
726
+ } else if (match[ATTRIBUTE_NAME] === undefined) {
727
+ attrNameEndIndex = -2;
728
+ } else {
729
+ attrNameEndIndex = regex.lastIndex - match[SPACES_AND_EQUALS].length;
730
+ attrName = match[ATTRIBUTE_NAME];
731
+ regex = match[QUOTE_CHAR] === undefined ? tagEndRegex : match[QUOTE_CHAR] === '"' ? doubleQuoteAttrEndRegex : singleQuoteAttrEndRegex;
732
+ }
733
+ } else if (regex === doubleQuoteAttrEndRegex || regex === singleQuoteAttrEndRegex) {
734
+ regex = tagEndRegex;
735
+ } else if (regex === commentEndRegex || regex === comment2EndRegex) {
736
+ regex = textEndRegex;
737
+ } else {
738
+ regex = tagEndRegex;
739
+ rawTextEndRegex = undefined;
740
+ }
741
+ }
742
+ if (DEV_MODE2) {
743
+ console.assert(attrNameEndIndex === -1 || regex === tagEndRegex || regex === singleQuoteAttrEndRegex || regex === doubleQuoteAttrEndRegex, "unexpected parse state B");
744
+ }
745
+ const end = regex === tagEndRegex && strings[i + 1].startsWith("/>") ? " " : "";
746
+ html += regex === textEndRegex ? s + nodeMarker : attrNameEndIndex >= 0 ? (attrNames.push(attrName), s.slice(0, attrNameEndIndex) + boundAttributeSuffix + s.slice(attrNameEndIndex)) + marker + end : s + marker + (attrNameEndIndex === -2 ? i : end);
747
+ }
748
+ const htmlResult = html + (strings[l] || "<?>") + (type === SVG_RESULT ? "</svg>" : type === MATHML_RESULT ? "</math>" : "");
749
+ return [trustFromTemplateString(strings, htmlResult), attrNames];
750
+ };
751
+
752
+ class Template {
753
+ constructor({ strings, ["_$litType$"]: type }, options) {
754
+ this.parts = [];
755
+ let node;
756
+ let nodeIndex = 0;
757
+ let attrNameIndex = 0;
758
+ const partCount = strings.length - 1;
759
+ const parts = this.parts;
760
+ const [html, attrNames] = getTemplateHtml(strings, type);
761
+ this.el = Template.createElement(html, options);
762
+ walker.currentNode = this.el.content;
763
+ if (type === SVG_RESULT || type === MATHML_RESULT) {
764
+ const wrapper = this.el.content.firstChild;
765
+ wrapper.replaceWith(...wrapper.childNodes);
766
+ }
767
+ while ((node = walker.nextNode()) !== null && parts.length < partCount) {
768
+ if (node.nodeType === 1) {
769
+ if (DEV_MODE2) {
770
+ const tag = node.localName;
771
+ if (/^(?:textarea|template)$/i.test(tag) && node.innerHTML.includes(marker)) {
772
+ const m = `Expressions are not supported inside \`${tag}\` ` + `elements. See https://lit.dev/msg/expression-in-${tag} for more ` + `information.`;
773
+ if (tag === "template") {
774
+ throw new Error(m);
775
+ } else
776
+ issueWarning2("", m);
777
+ }
778
+ }
779
+ if (node.hasAttributes()) {
780
+ for (const name of node.getAttributeNames()) {
781
+ if (name.endsWith(boundAttributeSuffix)) {
782
+ const realName = attrNames[attrNameIndex++];
783
+ const value = node.getAttribute(name);
784
+ const statics = value.split(marker);
785
+ const m = /([.?@])?(.*)/.exec(realName);
786
+ parts.push({
787
+ type: ATTRIBUTE_PART,
788
+ index: nodeIndex,
789
+ name: m[2],
790
+ strings: statics,
791
+ ctor: m[1] === "." ? PropertyPart : m[1] === "?" ? BooleanAttributePart : m[1] === "@" ? EventPart : AttributePart
792
+ });
793
+ node.removeAttribute(name);
794
+ } else if (name.startsWith(marker)) {
795
+ parts.push({
796
+ type: ELEMENT_PART,
797
+ index: nodeIndex
798
+ });
799
+ node.removeAttribute(name);
800
+ }
801
+ }
802
+ }
803
+ if (rawTextElement.test(node.tagName)) {
804
+ const strings = node.textContent.split(marker);
805
+ const lastIndex = strings.length - 1;
806
+ if (lastIndex > 0) {
807
+ node.textContent = trustedTypes2 ? trustedTypes2.emptyScript : "";
808
+ for (let i = 0;i < lastIndex; i++) {
809
+ node.append(strings[i], createMarker());
810
+ walker.nextNode();
811
+ parts.push({ type: CHILD_PART, index: ++nodeIndex });
812
+ }
813
+ node.append(strings[lastIndex], createMarker());
814
+ }
815
+ }
816
+ } else if (node.nodeType === 8) {
817
+ const data = node.data;
818
+ if (data === markerMatch) {
819
+ parts.push({ type: CHILD_PART, index: nodeIndex });
820
+ } else {
821
+ let i = -1;
822
+ while ((i = node.data.indexOf(marker, i + 1)) !== -1) {
823
+ parts.push({ type: COMMENT_PART, index: nodeIndex });
824
+ i += marker.length - 1;
825
+ }
826
+ }
827
+ }
828
+ nodeIndex++;
829
+ }
830
+ if (DEV_MODE2) {
831
+ if (attrNames.length !== attrNameIndex) {
832
+ throw new Error(`Detected duplicate attribute bindings. This occurs if your template ` + `has duplicate attributes on an element tag. For example ` + `"<input ?disabled=\${true} ?disabled=\${false}>" contains a ` + `duplicate "disabled" attribute. The error was detected in ` + `the following template:
833
+ ` + "`" + strings.join("${...}") + "`");
834
+ }
835
+ }
836
+ debugLogEvent2 && debugLogEvent2({
837
+ kind: "template prep",
838
+ template: this,
839
+ clonableTemplate: this.el,
840
+ parts: this.parts,
841
+ strings
842
+ });
843
+ }
844
+ static createElement(html, _options) {
845
+ const el = d.createElement("template");
846
+ el.innerHTML = html;
847
+ return el;
848
+ }
849
+ }
850
+ function resolveDirective(part, value, parent = part, attributeIndex) {
851
+ if (value === noChange) {
852
+ return value;
853
+ }
854
+ let currentDirective = attributeIndex !== undefined ? parent.__directives?.[attributeIndex] : parent.__directive;
855
+ const nextDirectiveConstructor = isPrimitive(value) ? undefined : value["_$litDirective$"];
856
+ if (currentDirective?.constructor !== nextDirectiveConstructor) {
857
+ currentDirective?.["_$notifyDirectiveConnectionChanged"]?.(false);
858
+ if (nextDirectiveConstructor === undefined) {
859
+ currentDirective = undefined;
860
+ } else {
861
+ currentDirective = new nextDirectiveConstructor(part);
862
+ currentDirective._$initialize(part, parent, attributeIndex);
863
+ }
864
+ if (attributeIndex !== undefined) {
865
+ (parent.__directives ??= [])[attributeIndex] = currentDirective;
866
+ } else {
867
+ parent.__directive = currentDirective;
868
+ }
869
+ }
870
+ if (currentDirective !== undefined) {
871
+ value = resolveDirective(part, currentDirective._$resolve(part, value.values), currentDirective, attributeIndex);
872
+ }
873
+ return value;
874
+ }
875
+
876
+ class TemplateInstance {
877
+ constructor(template, parent) {
878
+ this._$parts = [];
879
+ this._$disconnectableChildren = undefined;
880
+ this._$template = template;
881
+ this._$parent = parent;
882
+ }
883
+ get parentNode() {
884
+ return this._$parent.parentNode;
885
+ }
886
+ get _$isConnected() {
887
+ return this._$parent._$isConnected;
888
+ }
889
+ _clone(options) {
890
+ const { el: { content }, parts } = this._$template;
891
+ const fragment = (options?.creationScope ?? d).importNode(content, true);
892
+ walker.currentNode = fragment;
893
+ let node = walker.nextNode();
894
+ let nodeIndex = 0;
895
+ let partIndex = 0;
896
+ let templatePart = parts[0];
897
+ while (templatePart !== undefined) {
898
+ if (nodeIndex === templatePart.index) {
899
+ let part;
900
+ if (templatePart.type === CHILD_PART) {
901
+ part = new ChildPart(node, node.nextSibling, this, options);
902
+ } else if (templatePart.type === ATTRIBUTE_PART) {
903
+ part = new templatePart.ctor(node, templatePart.name, templatePart.strings, this, options);
904
+ } else if (templatePart.type === ELEMENT_PART) {
905
+ part = new ElementPart(node, this, options);
906
+ }
907
+ this._$parts.push(part);
908
+ templatePart = parts[++partIndex];
909
+ }
910
+ if (nodeIndex !== templatePart?.index) {
911
+ node = walker.nextNode();
912
+ nodeIndex++;
913
+ }
914
+ }
915
+ walker.currentNode = d;
916
+ return fragment;
917
+ }
918
+ _update(values) {
919
+ let i = 0;
920
+ for (const part of this._$parts) {
921
+ if (part !== undefined) {
922
+ debugLogEvent2 && debugLogEvent2({
923
+ kind: "set part",
924
+ part,
925
+ value: values[i],
926
+ valueIndex: i,
927
+ values,
928
+ templateInstance: this
929
+ });
930
+ if (part.strings !== undefined) {
931
+ part._$setValue(values, part, i);
932
+ i += part.strings.length - 2;
933
+ } else {
934
+ part._$setValue(values[i]);
935
+ }
936
+ }
937
+ i++;
938
+ }
939
+ }
940
+ }
941
+
942
+ class ChildPart {
943
+ get _$isConnected() {
944
+ return this._$parent?._$isConnected ?? this.__isConnected;
945
+ }
946
+ constructor(startNode, endNode, parent, options) {
947
+ this.type = CHILD_PART;
948
+ this._$committedValue = nothing;
949
+ this._$disconnectableChildren = undefined;
950
+ this._$startNode = startNode;
951
+ this._$endNode = endNode;
952
+ this._$parent = parent;
953
+ this.options = options;
954
+ this.__isConnected = options?.isConnected ?? true;
955
+ if (ENABLE_EXTRA_SECURITY_HOOKS) {
956
+ this._textSanitizer = undefined;
957
+ }
958
+ }
959
+ get parentNode() {
960
+ let parentNode = wrap(this._$startNode).parentNode;
961
+ const parent = this._$parent;
962
+ if (parent !== undefined && parentNode?.nodeType === 11) {
963
+ parentNode = parent.parentNode;
964
+ }
965
+ return parentNode;
966
+ }
967
+ get startNode() {
968
+ return this._$startNode;
969
+ }
970
+ get endNode() {
971
+ return this._$endNode;
972
+ }
973
+ _$setValue(value, directiveParent = this) {
974
+ if (DEV_MODE2 && this.parentNode === null) {
975
+ throw new Error(`This \`ChildPart\` has no \`parentNode\` and therefore cannot accept a value. This likely means the element containing the part was manipulated in an unsupported way outside of Lit's control such that the part's marker nodes were ejected from DOM. For example, setting the element's \`innerHTML\` or \`textContent\` can do this.`);
976
+ }
977
+ value = resolveDirective(this, value, directiveParent);
978
+ if (isPrimitive(value)) {
979
+ if (value === nothing || value == null || value === "") {
980
+ if (this._$committedValue !== nothing) {
981
+ debugLogEvent2 && debugLogEvent2({
982
+ kind: "commit nothing to child",
983
+ start: this._$startNode,
984
+ end: this._$endNode,
985
+ parent: this._$parent,
986
+ options: this.options
987
+ });
988
+ this._$clear();
989
+ }
990
+ this._$committedValue = nothing;
991
+ } else if (value !== this._$committedValue && value !== noChange) {
992
+ this._commitText(value);
993
+ }
994
+ } else if (value["_$litType$"] !== undefined) {
995
+ this._commitTemplateResult(value);
996
+ } else if (value.nodeType !== undefined) {
997
+ if (DEV_MODE2 && this.options?.host === value) {
998
+ this._commitText(`[probable mistake: rendered a template's host in itself ` + `(commonly caused by writing \${this} in a template]`);
999
+ console.warn(`Attempted to render the template host`, value, `inside itself. This is almost always a mistake, and in dev mode `, `we render some warning text. In production however, we'll `, `render it, which will usually result in an error, and sometimes `, `in the element disappearing from the DOM.`);
1000
+ return;
1001
+ }
1002
+ this._commitNode(value);
1003
+ } else if (isIterable(value)) {
1004
+ this._commitIterable(value);
1005
+ } else {
1006
+ this._commitText(value);
1007
+ }
1008
+ }
1009
+ _insert(node) {
1010
+ return wrap(wrap(this._$startNode).parentNode).insertBefore(node, this._$endNode);
1011
+ }
1012
+ _commitNode(value) {
1013
+ if (this._$committedValue !== value) {
1014
+ this._$clear();
1015
+ if (ENABLE_EXTRA_SECURITY_HOOKS && sanitizerFactoryInternal !== noopSanitizer) {
1016
+ const parentNodeName = this._$startNode.parentNode?.nodeName;
1017
+ if (parentNodeName === "STYLE" || parentNodeName === "SCRIPT") {
1018
+ let message = "Forbidden";
1019
+ if (DEV_MODE2) {
1020
+ if (parentNodeName === "STYLE") {
1021
+ message = `Lit does not support binding inside style nodes. ` + `This is a security risk, as style injection attacks can ` + `exfiltrate data and spoof UIs. ` + `Consider instead using css\`...\` literals ` + `to compose styles, and do dynamic styling with ` + `css custom properties, ::parts, <slot>s, ` + `and by mutating the DOM rather than stylesheets.`;
1022
+ } else {
1023
+ message = `Lit does not support binding inside script nodes. ` + `This is a security risk, as it could allow arbitrary ` + `code execution.`;
1024
+ }
1025
+ }
1026
+ throw new Error(message);
1027
+ }
1028
+ }
1029
+ debugLogEvent2 && debugLogEvent2({
1030
+ kind: "commit node",
1031
+ start: this._$startNode,
1032
+ parent: this._$parent,
1033
+ value,
1034
+ options: this.options
1035
+ });
1036
+ this._$committedValue = this._insert(value);
1037
+ }
1038
+ }
1039
+ _commitText(value) {
1040
+ if (this._$committedValue !== nothing && isPrimitive(this._$committedValue)) {
1041
+ const node = wrap(this._$startNode).nextSibling;
1042
+ if (ENABLE_EXTRA_SECURITY_HOOKS) {
1043
+ if (this._textSanitizer === undefined) {
1044
+ this._textSanitizer = createSanitizer(node, "data", "property");
1045
+ }
1046
+ value = this._textSanitizer(value);
1047
+ }
1048
+ debugLogEvent2 && debugLogEvent2({
1049
+ kind: "commit text",
1050
+ node,
1051
+ value,
1052
+ options: this.options
1053
+ });
1054
+ node.data = value;
1055
+ } else {
1056
+ if (ENABLE_EXTRA_SECURITY_HOOKS) {
1057
+ const textNode = d.createTextNode("");
1058
+ this._commitNode(textNode);
1059
+ if (this._textSanitizer === undefined) {
1060
+ this._textSanitizer = createSanitizer(textNode, "data", "property");
1061
+ }
1062
+ value = this._textSanitizer(value);
1063
+ debugLogEvent2 && debugLogEvent2({
1064
+ kind: "commit text",
1065
+ node: textNode,
1066
+ value,
1067
+ options: this.options
1068
+ });
1069
+ textNode.data = value;
1070
+ } else {
1071
+ this._commitNode(d.createTextNode(value));
1072
+ debugLogEvent2 && debugLogEvent2({
1073
+ kind: "commit text",
1074
+ node: wrap(this._$startNode).nextSibling,
1075
+ value,
1076
+ options: this.options
1077
+ });
1078
+ }
1079
+ }
1080
+ this._$committedValue = value;
1081
+ }
1082
+ _commitTemplateResult(result) {
1083
+ const { values, ["_$litType$"]: type } = result;
1084
+ const template = typeof type === "number" ? this._$getTemplate(result) : (type.el === undefined && (type.el = Template.createElement(trustFromTemplateString(type.h, type.h[0]), this.options)), type);
1085
+ if (this._$committedValue?._$template === template) {
1086
+ debugLogEvent2 && debugLogEvent2({
1087
+ kind: "template updating",
1088
+ template,
1089
+ instance: this._$committedValue,
1090
+ parts: this._$committedValue._$parts,
1091
+ options: this.options,
1092
+ values
1093
+ });
1094
+ this._$committedValue._update(values);
1095
+ } else {
1096
+ const instance = new TemplateInstance(template, this);
1097
+ const fragment = instance._clone(this.options);
1098
+ debugLogEvent2 && debugLogEvent2({
1099
+ kind: "template instantiated",
1100
+ template,
1101
+ instance,
1102
+ parts: instance._$parts,
1103
+ options: this.options,
1104
+ fragment,
1105
+ values
1106
+ });
1107
+ instance._update(values);
1108
+ debugLogEvent2 && debugLogEvent2({
1109
+ kind: "template instantiated and updated",
1110
+ template,
1111
+ instance,
1112
+ parts: instance._$parts,
1113
+ options: this.options,
1114
+ fragment,
1115
+ values
1116
+ });
1117
+ this._commitNode(fragment);
1118
+ this._$committedValue = instance;
1119
+ }
1120
+ }
1121
+ _$getTemplate(result) {
1122
+ let template = templateCache.get(result.strings);
1123
+ if (template === undefined) {
1124
+ templateCache.set(result.strings, template = new Template(result));
1125
+ }
1126
+ return template;
1127
+ }
1128
+ _commitIterable(value) {
1129
+ if (!isArray(this._$committedValue)) {
1130
+ this._$committedValue = [];
1131
+ this._$clear();
1132
+ }
1133
+ const itemParts = this._$committedValue;
1134
+ let partIndex = 0;
1135
+ let itemPart;
1136
+ for (const item of value) {
1137
+ if (partIndex === itemParts.length) {
1138
+ itemParts.push(itemPart = new ChildPart(this._insert(createMarker()), this._insert(createMarker()), this, this.options));
1139
+ } else {
1140
+ itemPart = itemParts[partIndex];
1141
+ }
1142
+ itemPart._$setValue(item);
1143
+ partIndex++;
1144
+ }
1145
+ if (partIndex < itemParts.length) {
1146
+ this._$clear(itemPart && wrap(itemPart._$endNode).nextSibling, partIndex);
1147
+ itemParts.length = partIndex;
1148
+ }
1149
+ }
1150
+ _$clear(start = wrap(this._$startNode).nextSibling, from) {
1151
+ this._$notifyConnectionChanged?.(false, true, from);
1152
+ while (start !== this._$endNode) {
1153
+ const n = wrap(start).nextSibling;
1154
+ wrap(start).remove();
1155
+ start = n;
1156
+ }
1157
+ }
1158
+ setConnected(isConnected) {
1159
+ if (this._$parent === undefined) {
1160
+ this.__isConnected = isConnected;
1161
+ this._$notifyConnectionChanged?.(isConnected);
1162
+ } else if (DEV_MODE2) {
1163
+ throw new Error("part.setConnected() may only be called on a " + "RootPart returned from render().");
1164
+ }
1165
+ }
1166
+ }
1167
+
1168
+ class AttributePart {
1169
+ get tagName() {
1170
+ return this.element.tagName;
1171
+ }
1172
+ get _$isConnected() {
1173
+ return this._$parent._$isConnected;
1174
+ }
1175
+ constructor(element, name, strings, parent, options) {
1176
+ this.type = ATTRIBUTE_PART;
1177
+ this._$committedValue = nothing;
1178
+ this._$disconnectableChildren = undefined;
1179
+ this.element = element;
1180
+ this.name = name;
1181
+ this._$parent = parent;
1182
+ this.options = options;
1183
+ if (strings.length > 2 || strings[0] !== "" || strings[1] !== "") {
1184
+ this._$committedValue = new Array(strings.length - 1).fill(new String);
1185
+ this.strings = strings;
1186
+ } else {
1187
+ this._$committedValue = nothing;
1188
+ }
1189
+ if (ENABLE_EXTRA_SECURITY_HOOKS) {
1190
+ this._sanitizer = undefined;
1191
+ }
1192
+ }
1193
+ _$setValue(value, directiveParent = this, valueIndex, noCommit) {
1194
+ const strings = this.strings;
1195
+ let change = false;
1196
+ if (strings === undefined) {
1197
+ value = resolveDirective(this, value, directiveParent, 0);
1198
+ change = !isPrimitive(value) || value !== this._$committedValue && value !== noChange;
1199
+ if (change) {
1200
+ this._$committedValue = value;
1201
+ }
1202
+ } else {
1203
+ const values = value;
1204
+ value = strings[0];
1205
+ let i, v;
1206
+ for (i = 0;i < strings.length - 1; i++) {
1207
+ v = resolveDirective(this, values[valueIndex + i], directiveParent, i);
1208
+ if (v === noChange) {
1209
+ v = this._$committedValue[i];
1210
+ }
1211
+ change ||= !isPrimitive(v) || v !== this._$committedValue[i];
1212
+ if (v === nothing) {
1213
+ value = nothing;
1214
+ } else if (value !== nothing) {
1215
+ value += (v ?? "") + strings[i + 1];
1216
+ }
1217
+ this._$committedValue[i] = v;
1218
+ }
1219
+ }
1220
+ if (change && !noCommit) {
1221
+ this._commitValue(value);
1222
+ }
1223
+ }
1224
+ _commitValue(value) {
1225
+ if (value === nothing) {
1226
+ wrap(this.element).removeAttribute(this.name);
1227
+ } else {
1228
+ if (ENABLE_EXTRA_SECURITY_HOOKS) {
1229
+ if (this._sanitizer === undefined) {
1230
+ this._sanitizer = sanitizerFactoryInternal(this.element, this.name, "attribute");
1231
+ }
1232
+ value = this._sanitizer(value ?? "");
1233
+ }
1234
+ debugLogEvent2 && debugLogEvent2({
1235
+ kind: "commit attribute",
1236
+ element: this.element,
1237
+ name: this.name,
1238
+ value,
1239
+ options: this.options
1240
+ });
1241
+ wrap(this.element).setAttribute(this.name, value ?? "");
1242
+ }
1243
+ }
1244
+ }
1245
+
1246
+ class PropertyPart extends AttributePart {
1247
+ constructor() {
1248
+ super(...arguments);
1249
+ this.type = PROPERTY_PART;
1250
+ }
1251
+ _commitValue(value) {
1252
+ if (ENABLE_EXTRA_SECURITY_HOOKS) {
1253
+ if (this._sanitizer === undefined) {
1254
+ this._sanitizer = sanitizerFactoryInternal(this.element, this.name, "property");
1255
+ }
1256
+ value = this._sanitizer(value);
1257
+ }
1258
+ debugLogEvent2 && debugLogEvent2({
1259
+ kind: "commit property",
1260
+ element: this.element,
1261
+ name: this.name,
1262
+ value,
1263
+ options: this.options
1264
+ });
1265
+ this.element[this.name] = value === nothing ? undefined : value;
1266
+ }
1267
+ }
1268
+
1269
+ class BooleanAttributePart extends AttributePart {
1270
+ constructor() {
1271
+ super(...arguments);
1272
+ this.type = BOOLEAN_ATTRIBUTE_PART;
1273
+ }
1274
+ _commitValue(value) {
1275
+ debugLogEvent2 && debugLogEvent2({
1276
+ kind: "commit boolean attribute",
1277
+ element: this.element,
1278
+ name: this.name,
1279
+ value: !!(value && value !== nothing),
1280
+ options: this.options
1281
+ });
1282
+ wrap(this.element).toggleAttribute(this.name, !!value && value !== nothing);
1283
+ }
1284
+ }
1285
+
1286
+ class EventPart extends AttributePart {
1287
+ constructor(element, name, strings, parent, options) {
1288
+ super(element, name, strings, parent, options);
1289
+ this.type = EVENT_PART;
1290
+ if (DEV_MODE2 && this.strings !== undefined) {
1291
+ throw new Error(`A \`<${element.localName}>\` has a \`@${name}=...\` listener with ` + "invalid content. Event listeners in templates must have exactly " + "one expression and no surrounding text.");
1292
+ }
1293
+ }
1294
+ _$setValue(newListener, directiveParent = this) {
1295
+ newListener = resolveDirective(this, newListener, directiveParent, 0) ?? nothing;
1296
+ if (newListener === noChange) {
1297
+ return;
1298
+ }
1299
+ const oldListener = this._$committedValue;
1300
+ const shouldRemoveListener = newListener === nothing && oldListener !== nothing || newListener.capture !== oldListener.capture || newListener.once !== oldListener.once || newListener.passive !== oldListener.passive;
1301
+ const shouldAddListener = newListener !== nothing && (oldListener === nothing || shouldRemoveListener);
1302
+ debugLogEvent2 && debugLogEvent2({
1303
+ kind: "commit event listener",
1304
+ element: this.element,
1305
+ name: this.name,
1306
+ value: newListener,
1307
+ options: this.options,
1308
+ removeListener: shouldRemoveListener,
1309
+ addListener: shouldAddListener,
1310
+ oldListener
1311
+ });
1312
+ if (shouldRemoveListener) {
1313
+ this.element.removeEventListener(this.name, this, oldListener);
1314
+ }
1315
+ if (shouldAddListener) {
1316
+ this.element.addEventListener(this.name, this, newListener);
1317
+ }
1318
+ this._$committedValue = newListener;
1319
+ }
1320
+ handleEvent(event) {
1321
+ if (typeof this._$committedValue === "function") {
1322
+ this._$committedValue.call(this.options?.host ?? this.element, event);
1323
+ } else {
1324
+ this._$committedValue.handleEvent(event);
1325
+ }
1326
+ }
1327
+ }
1328
+
1329
+ class ElementPart {
1330
+ constructor(element, parent, options) {
1331
+ this.element = element;
1332
+ this.type = ELEMENT_PART;
1333
+ this._$disconnectableChildren = undefined;
1334
+ this._$parent = parent;
1335
+ this.options = options;
1336
+ }
1337
+ get _$isConnected() {
1338
+ return this._$parent._$isConnected;
1339
+ }
1340
+ _$setValue(value) {
1341
+ debugLogEvent2 && debugLogEvent2({
1342
+ kind: "commit to element binding",
1343
+ element: this.element,
1344
+ value,
1345
+ options: this.options
1346
+ });
1347
+ resolveDirective(this, value);
1348
+ }
1349
+ }
1350
+ var polyfillSupport2 = DEV_MODE2 ? global3.litHtmlPolyfillSupportDevMode : global3.litHtmlPolyfillSupport;
1351
+ polyfillSupport2?.(Template, ChildPart);
1352
+ (global3.litHtmlVersions ??= []).push("3.3.3");
1353
+ if (DEV_MODE2 && global3.litHtmlVersions.length > 1) {
1354
+ queueMicrotask(() => {
1355
+ issueWarning2("multiple-versions", `Multiple versions of Lit loaded. ` + `Loading multiple versions is not recommended.`);
1356
+ });
1357
+ }
1358
+ var render = (value, container, options) => {
1359
+ if (DEV_MODE2 && container == null) {
1360
+ throw new TypeError(`The container to render into may not be ${container}`);
1361
+ }
1362
+ const renderId = DEV_MODE2 ? debugLogRenderId++ : 0;
1363
+ const partOwnerNode = options?.renderBefore ?? container;
1364
+ let part = partOwnerNode["_$litPart$"];
1365
+ debugLogEvent2 && debugLogEvent2({
1366
+ kind: "begin render",
1367
+ id: renderId,
1368
+ value,
1369
+ container,
1370
+ options,
1371
+ part
1372
+ });
1373
+ if (part === undefined) {
1374
+ const endNode = options?.renderBefore ?? null;
1375
+ partOwnerNode["_$litPart$"] = part = new ChildPart(container.insertBefore(createMarker(), endNode), endNode, undefined, options ?? {});
1376
+ }
1377
+ part._$setValue(value);
1378
+ debugLogEvent2 && debugLogEvent2({
1379
+ kind: "end render",
1380
+ id: renderId,
1381
+ value,
1382
+ container,
1383
+ options,
1384
+ part
1385
+ });
1386
+ return part;
1387
+ };
1388
+ if (ENABLE_EXTRA_SECURITY_HOOKS) {
1389
+ render.setSanitizer = setSanitizer;
1390
+ render.createSanitizer = createSanitizer;
1391
+ if (DEV_MODE2) {
1392
+ render._testOnlyClearSanitizerFactoryDoNotCallOrElse = _testOnlyClearSanitizerFactoryDoNotCallOrElse;
1393
+ }
1394
+ }
1395
+
1396
+ // ../../node_modules/.pnpm/lit-element@4.2.2/node_modules/lit-element/development/lit-element.js
1397
+ var JSCompiler_renameProperty2 = (prop, _obj) => prop;
1398
+ var DEV_MODE3 = true;
1399
+ var global4 = globalThis;
1400
+ var issueWarning3;
1401
+ if (DEV_MODE3) {
1402
+ global4.litIssuedWarnings ??= new Set;
1403
+ issueWarning3 = (code, warning) => {
1404
+ warning += ` See https://lit.dev/msg/${code} for more information.`;
1405
+ if (!global4.litIssuedWarnings.has(warning) && !global4.litIssuedWarnings.has(code)) {
1406
+ console.warn(warning);
1407
+ global4.litIssuedWarnings.add(warning);
1408
+ }
1409
+ };
1410
+ }
1411
+
1412
+ class LitElement extends ReactiveElement {
1413
+ constructor() {
1414
+ super(...arguments);
1415
+ this.renderOptions = { host: this };
1416
+ this.__childPart = undefined;
1417
+ }
1418
+ createRenderRoot() {
1419
+ const renderRoot = super.createRenderRoot();
1420
+ this.renderOptions.renderBefore ??= renderRoot.firstChild;
1421
+ return renderRoot;
1422
+ }
1423
+ update(changedProperties) {
1424
+ const value = this.render();
1425
+ if (!this.hasUpdated) {
1426
+ this.renderOptions.isConnected = this.isConnected;
1427
+ }
1428
+ super.update(changedProperties);
1429
+ this.__childPart = render(value, this.renderRoot, this.renderOptions);
1430
+ }
1431
+ connectedCallback() {
1432
+ super.connectedCallback();
1433
+ this.__childPart?.setConnected(true);
1434
+ }
1435
+ disconnectedCallback() {
1436
+ super.disconnectedCallback();
1437
+ this.__childPart?.setConnected(false);
1438
+ }
1439
+ render() {
1440
+ return noChange;
1441
+ }
1442
+ }
1443
+ LitElement["_$litElement$"] = true;
1444
+ LitElement[JSCompiler_renameProperty2("finalized", LitElement)] = true;
1445
+ global4.litElementHydrateSupport?.({ LitElement });
1446
+ var polyfillSupport3 = DEV_MODE3 ? global4.litElementPolyfillSupportDevMode : global4.litElementPolyfillSupport;
1447
+ polyfillSupport3?.({ LitElement });
1448
+ (global4.litElementVersions ??= []).push("4.2.2");
1449
+ if (DEV_MODE3 && global4.litElementVersions.length > 1) {
1450
+ queueMicrotask(() => {
1451
+ issueWarning3("multiple-versions", `Multiple versions of Lit loaded. Loading multiple versions ` + `is not recommended.`);
1452
+ });
1453
+ }
1454
+ // src/index.ts
1455
+ class WodiraBrowserApiError extends Error {
1456
+ status;
1457
+ statusText;
1458
+ payload;
1459
+ constructor(params) {
1460
+ super(params.message);
1461
+ this.name = "WodiraBrowserApiError";
1462
+ this.status = params.status;
1463
+ this.statusText = params.statusText;
1464
+ this.payload = params.payload;
1465
+ }
1466
+ }
1467
+
1468
+ // src/ui/boxes/client.ts
1469
+ class WodiraBoxWidgetClient {
1470
+ options;
1471
+ baseUrl;
1472
+ prefix;
1473
+ fetcher;
1474
+ constructor(options) {
1475
+ this.options = options;
1476
+ if (!options.publishableKey?.startsWith("wpk_live_")) {
1477
+ throw new Error("WODira Boxes widgets require a wpk_live_ publishable key.");
1478
+ }
1479
+ if (!options.installationId?.trim()) {
1480
+ throw new Error("WODira Boxes widgets require an installation-id.");
1481
+ }
1482
+ this.baseUrl = (options.baseUrl ?? "https://api.wodira.app").replace(/\/+$/, "");
1483
+ this.prefix = `/external/v1/browser/box-widgets/${encodeURIComponent(options.installationId)}`;
1484
+ this.fetcher = options.fetch ?? globalThis.fetch.bind(globalThis);
1485
+ }
1486
+ getContext(signal) {
1487
+ return this.request("/context", signal ? { signal } : {});
1488
+ }
1489
+ getCalendar(from, weeks = 1, signal) {
1490
+ const query = new URLSearchParams({ from: from.toISOString(), weeks: String(weeks) });
1491
+ return this.request(`/calendar?${query}`, signal ? { signal } : {});
1492
+ }
1493
+ getPlans(signal) {
1494
+ return this.request("/plans", signal ? { signal } : {});
1495
+ }
1496
+ getTrialClasses(signal) {
1497
+ return this.request("/trial-classes", signal ? { signal } : {});
1498
+ }
1499
+ createFlow(input, signal) {
1500
+ return this.request("/flows", {
1501
+ method: "POST",
1502
+ body: input,
1503
+ ...signal ? { signal } : {}
1504
+ });
1505
+ }
1506
+ recordTelemetry(events, signal) {
1507
+ return this.request("/telemetry", {
1508
+ method: "POST",
1509
+ body: { events },
1510
+ ...signal ? { signal } : {}
1511
+ });
1512
+ }
1513
+ verifyResult(resultToken, signal) {
1514
+ return this.request(`/results/${encodeURIComponent(resultToken)}`, signal ? { signal } : {});
1515
+ }
1516
+ async request(path, options) {
1517
+ const headers = new Headers({
1518
+ accept: "application/json",
1519
+ "x-publishable-key": this.options.publishableKey
1520
+ });
1521
+ const init = { method: options.method ?? "GET", headers };
1522
+ if (options.signal)
1523
+ init.signal = options.signal;
1524
+ if (options.body !== undefined) {
1525
+ headers.set("content-type", "application/json");
1526
+ init.body = JSON.stringify(options.body);
1527
+ }
1528
+ const response = await this.fetcher(`${this.baseUrl}${this.prefix}${path}`, init);
1529
+ if (!response.ok) {
1530
+ const text = await response.text();
1531
+ let payload = text || null;
1532
+ try {
1533
+ payload = text ? JSON.parse(text) : null;
1534
+ } catch {}
1535
+ throw new WodiraBrowserApiError({
1536
+ status: response.status,
1537
+ statusText: response.statusText,
1538
+ message: typeof payload === "object" && typeof payload?.["message"] === "string" ? payload["message"] : "WODira Boxes widget request failed.",
1539
+ payload
1540
+ });
1541
+ }
1542
+ const text = await response.text();
1543
+ return text ? JSON.parse(text) : undefined;
1544
+ }
1545
+ }
1546
+ function createWodiraBoxWidgetClient(options) {
1547
+ return new WodiraBoxWidgetClient(options);
1548
+ }
1549
+
1550
+ // src/ui/boxes/i18n.ts
1551
+ var copy = {
1552
+ es: {
1553
+ calendar: "Horario de clases",
1554
+ trial: "Prueba una clase",
1555
+ plans: "Planes",
1556
+ previous: "Semana anterior",
1557
+ next: "Semana siguiente",
1558
+ reserve: "Continuar",
1559
+ loading: "Cargando…",
1560
+ empty: "No hay opciones disponibles en estas fechas.",
1561
+ error: "No pudimos cargar este contenido. Inténtalo de nuevo.",
1562
+ available: "Disponible",
1563
+ last: "Últimas plazas",
1564
+ waitlist: "Lista de espera",
1565
+ full: "Completa",
1566
+ coach: "Coach",
1567
+ duration: "min",
1568
+ free: "Gratis",
1569
+ unlimited: "Ilimitado",
1570
+ email: "Tu email",
1571
+ privacy: "Acepto la política de privacidad de WODira y del box.",
1572
+ trialCta: "Continuar",
1573
+ chooseClass: "Elige una clase",
1574
+ result: "¡Todo listo! Tu solicitud se ha completado.",
1575
+ powered: "Tecnología de WODira",
1576
+ retry: "Reintentar",
1577
+ per: "por",
1578
+ credits: "créditos",
1579
+ once: "pago único",
1580
+ daily: "diario",
1581
+ weekly: "semanal",
1582
+ monthly: "mensual",
1583
+ yearly: "anual"
1584
+ },
1585
+ en: {
1586
+ calendar: "Class schedule",
1587
+ trial: "Try a class",
1588
+ plans: "Plans",
1589
+ previous: "Previous week",
1590
+ next: "Next week",
1591
+ reserve: "Continue",
1592
+ loading: "Loading…",
1593
+ empty: "No options are available for these dates.",
1594
+ error: "We could not load this content. Try again.",
1595
+ available: "Available",
1596
+ last: "Last spots",
1597
+ waitlist: "Waitlist",
1598
+ full: "Full",
1599
+ coach: "Coach",
1600
+ duration: "min",
1601
+ free: "Free",
1602
+ unlimited: "Unlimited",
1603
+ email: "Your email",
1604
+ privacy: "I accept WODira and the gym privacy policies.",
1605
+ trialCta: "Continue",
1606
+ chooseClass: "Choose a class",
1607
+ result: "All set! Your request is complete.",
1608
+ powered: "Powered by WODira",
1609
+ retry: "Retry",
1610
+ per: "per",
1611
+ credits: "credits",
1612
+ once: "one-time",
1613
+ daily: "daily",
1614
+ weekly: "weekly",
1615
+ monthly: "monthly",
1616
+ yearly: "yearly"
1617
+ },
1618
+ pt: {
1619
+ calendar: "Horário de aulas",
1620
+ trial: "Experimente uma aula",
1621
+ plans: "Planos",
1622
+ previous: "Semana anterior",
1623
+ next: "Semana seguinte",
1624
+ reserve: "Continuar",
1625
+ loading: "A carregar…",
1626
+ empty: "Não há opções disponíveis nestas datas.",
1627
+ error: "Não foi possível carregar. Tente novamente.",
1628
+ available: "Disponível",
1629
+ last: "Últimas vagas",
1630
+ waitlist: "Lista de espera",
1631
+ full: "Lotada",
1632
+ coach: "Coach",
1633
+ duration: "min",
1634
+ free: "Grátis",
1635
+ unlimited: "Ilimitado",
1636
+ email: "O seu email",
1637
+ privacy: "Aceito as políticas de privacidade da WODira e do box.",
1638
+ trialCta: "Continuar",
1639
+ chooseClass: "Escolha uma aula",
1640
+ result: "Tudo pronto! O seu pedido foi concluído.",
1641
+ powered: "Tecnologia WODira",
1642
+ retry: "Tentar novamente",
1643
+ per: "por",
1644
+ credits: "créditos",
1645
+ once: "pagamento único",
1646
+ daily: "diário",
1647
+ weekly: "semanal",
1648
+ monthly: "mensal",
1649
+ yearly: "anual"
1650
+ }
1651
+ };
1652
+ function resolveBoxWidgetLanguage(locale) {
1653
+ const candidate = locale === "auto" || !locale ? document.documentElement.lang || navigator.language : locale;
1654
+ const language = candidate.toLowerCase().split("-")[0];
1655
+ return language === "en" || language === "pt" ? language : "es";
1656
+ }
1657
+ function boxText(locale, key) {
1658
+ return copy[resolveBoxWidgetLanguage(locale)][key];
1659
+ }
1660
+
1661
+ // src/ui/boxes/styles.ts
1662
+ var boxWidgetStyles = css`
1663
+ :host {
1664
+ color: var(--wodira-box-text, var(--wodira-color-text, #17132e));
1665
+ display: block;
1666
+ font-family: var(--wodira-box-font-family, var(--wodira-font-family, inherit));
1667
+ font-size: var(--wodira-font-size, 1rem);
1668
+ line-height: 1.5;
1669
+ min-width: 0;
1670
+ overflow-wrap: anywhere;
1671
+ container-type: inline-size;
1672
+ }
1673
+ *,
1674
+ *::before,
1675
+ *::after {
1676
+ box-sizing: border-box;
1677
+ }
1678
+ button,
1679
+ input {
1680
+ font: inherit;
1681
+ }
1682
+ [part~='shell'] {
1683
+ background: var(--wodira-box-surface, var(--wodira-color-surface, #fff));
1684
+ border: 1px solid var(--wodira-box-border, var(--wodira-color-border, #dcd9e3));
1685
+ border-radius: var(--wodira-box-radius, var(--wodira-radius, 1rem));
1686
+ box-shadow: var(--wodira-box-shadow, var(--wodira-shadow, 0 4px 18px rgb(23 19 46 / 0.04)));
1687
+ overflow: hidden;
1688
+ }
1689
+ [part~='composite'] {
1690
+ display: grid;
1691
+ gap: var(--wodira-space, 0.75rem);
1692
+ }
1693
+ [part~='hero'] {
1694
+ align-items: center;
1695
+ background: linear-gradient(
1696
+ 135deg,
1697
+ var(
1698
+ --wodira-box-primary,
1699
+ var(--wodira-color-primary, var(--_wodira-box-brand-primary, #17132e))
1700
+ ),
1701
+ color-mix(
1702
+ in srgb,
1703
+ var(
1704
+ --wodira-box-primary,
1705
+ var(--wodira-color-primary, var(--_wodira-box-brand-primary, #17132e))
1706
+ )
1707
+ 76%,
1708
+ #475467
1709
+ )
1710
+ );
1711
+ color: var(--wodira-box-primary-contrast, var(--wodira-color-primary-contrast, #fff));
1712
+ display: flex;
1713
+ gap: 14px;
1714
+ min-height: 86px;
1715
+ overflow: hidden;
1716
+ padding: 18px 20px;
1717
+ position: relative;
1718
+ }
1719
+ [part~='hero'][data-cover] {
1720
+ min-height: 132px;
1721
+ }
1722
+ [part~='hero']::after {
1723
+ background: radial-gradient(
1724
+ circle at 90% 15%,
1725
+ color-mix(
1726
+ in srgb,
1727
+ var(
1728
+ --wodira-box-accent,
1729
+ var(--wodira-color-accent, var(--_wodira-box-brand-accent, #c40072))
1730
+ )
1731
+ 55%,
1732
+ transparent
1733
+ ),
1734
+ transparent 45%
1735
+ );
1736
+ content: '';
1737
+ inset: 0;
1738
+ pointer-events: none;
1739
+ position: absolute;
1740
+ }
1741
+ [part~='cover'] {
1742
+ height: 100%;
1743
+ inset: 0;
1744
+ object-fit: cover;
1745
+ opacity: 0.38;
1746
+ position: absolute;
1747
+ width: 100%;
1748
+ }
1749
+ [part~='logo'] {
1750
+ background: var(--wodira-box-surface, var(--wodira-color-surface, #fff));
1751
+ border-radius: var(--wodira-radius-sm, 0.625rem);
1752
+ height: 54px;
1753
+ object-fit: contain;
1754
+ padding: 6px;
1755
+ width: 54px;
1756
+ z-index: 1;
1757
+ }
1758
+ [part~='brand'] {
1759
+ min-width: 0;
1760
+ z-index: 1;
1761
+ }
1762
+ [part~='brand-name'] {
1763
+ font-size: 0.8rem;
1764
+ font-weight: 750;
1765
+ letter-spacing: 0.08em;
1766
+ margin: 0 0 4px;
1767
+ opacity: 0.78;
1768
+ text-transform: uppercase;
1769
+ }
1770
+ [part~='title'] {
1771
+ font-size: clamp(1.25rem, 5cqi, 1.8rem);
1772
+ font-weight: 850;
1773
+ letter-spacing: -0.035em;
1774
+ margin: 0;
1775
+ }
1776
+ [part~='body'] {
1777
+ padding: clamp(16px, 4cqi, 24px);
1778
+ }
1779
+ [part~='toolbar'] {
1780
+ align-items: center;
1781
+ display: flex;
1782
+ gap: 8px;
1783
+ justify-content: space-between;
1784
+ margin-bottom: 16px;
1785
+ }
1786
+ [part~='nav-button'],
1787
+ [part~='button'] {
1788
+ align-items: center;
1789
+ border: 0;
1790
+ border-radius: var(--wodira-radius-sm, 0.625rem);
1791
+ cursor: pointer;
1792
+ display: inline-flex;
1793
+ font-weight: 760;
1794
+ justify-content: center;
1795
+ min-height: var(--wodira-control-height, 2.75rem);
1796
+ padding: 10px 14px;
1797
+ }
1798
+ [part~='nav-button'] {
1799
+ background: var(--wodira-box-subtle, var(--wodira-color-muted, #f6f5f8));
1800
+ color: var(--wodira-box-text, var(--wodira-color-text, #17132e));
1801
+ }
1802
+ [part~='button'] {
1803
+ background: var(
1804
+ --wodira-box-primary,
1805
+ var(--wodira-color-primary, var(--_wodira-box-brand-primary, #17132e))
1806
+ );
1807
+ color: var(--wodira-box-primary-contrast, var(--wodira-color-primary-contrast, #fff));
1808
+ width: 100%;
1809
+ }
1810
+ [part~='button']:hover {
1811
+ transform: translateY(-1px);
1812
+ }
1813
+ button:focus-visible,
1814
+ input:focus-visible {
1815
+ outline: 3px solid
1816
+ color-mix(
1817
+ in srgb,
1818
+ var(
1819
+ --wodira-box-accent,
1820
+ var(--wodira-color-accent, var(--_wodira-box-brand-accent, #c40072))
1821
+ )
1822
+ 60%,
1823
+ transparent
1824
+ );
1825
+ outline-offset: 2px;
1826
+ }
1827
+ button:disabled {
1828
+ cursor: not-allowed;
1829
+ opacity: 0.5;
1830
+ }
1831
+ [part~='grid'] {
1832
+ display: grid;
1833
+ gap: var(--wodira-space, 0.75rem);
1834
+ grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--wodira-grid-min, 15rem)), 1fr));
1835
+ }
1836
+ [part~='card'] {
1837
+ background: var(--wodira-box-subtle, var(--wodira-color-muted, #f6f5f8));
1838
+ border: 1px solid transparent;
1839
+ border-radius: var(--wodira-box-radius, var(--wodira-radius, 1rem));
1840
+ display: grid;
1841
+ gap: var(--wodira-space, 0.75rem);
1842
+ padding: var(--wodira-card-padding, 1rem);
1843
+ }
1844
+ [part~='card']:hover {
1845
+ border-color: color-mix(
1846
+ in srgb,
1847
+ var(--wodira-box-accent, var(--wodira-color-accent, var(--_wodira-box-brand-accent, #c40072)))
1848
+ 50%,
1849
+ var(--wodira-box-border, var(--wodira-color-border, #dcd9e3))
1850
+ );
1851
+ }
1852
+ [part~='card-heading'] {
1853
+ align-items: start;
1854
+ display: flex;
1855
+ gap: var(--wodira-space, 0.75rem);
1856
+ justify-content: space-between;
1857
+ }
1858
+ [part~='card-title'] {
1859
+ font-size: 1rem;
1860
+ font-weight: 820;
1861
+ margin: 0;
1862
+ }
1863
+ [part~='meta'] {
1864
+ color: var(--wodira-box-muted, var(--wodira-color-text-muted, #625e70));
1865
+ display: flex;
1866
+ flex-wrap: wrap;
1867
+ font-size: 0.86rem;
1868
+ gap: 5px 12px;
1869
+ }
1870
+ [part~='badge'] {
1871
+ background: #e7f8ee;
1872
+ border-radius: 999px;
1873
+ color: #067647;
1874
+ font-size: 0.72rem;
1875
+ font-weight: 800;
1876
+ padding: 5px 8px;
1877
+ white-space: nowrap;
1878
+ }
1879
+ [part~='badge'][data-status='LAST_SPOTS'] {
1880
+ background: #fff3d6;
1881
+ color: #b54708;
1882
+ }
1883
+ [part~='badge'][data-status='WAITLIST'],
1884
+ [part~='badge'][data-status='FULL'] {
1885
+ background: #fee4e2;
1886
+ color: #b42318;
1887
+ }
1888
+ [part~='price'] {
1889
+ font-size: 1.45rem;
1890
+ font-weight: 860;
1891
+ letter-spacing: -0.04em;
1892
+ }
1893
+ [part~='features'] {
1894
+ color: var(--wodira-box-muted, var(--wodira-color-text-muted, #625e70));
1895
+ display: grid;
1896
+ font-size: 0.9rem;
1897
+ gap: 6px;
1898
+ margin: 0;
1899
+ padding-left: 18px;
1900
+ }
1901
+ [part~='field'] {
1902
+ display: grid;
1903
+ gap: 6px;
1904
+ }
1905
+ [part~='input'] {
1906
+ background: var(--wodira-box-surface, var(--wodira-color-surface, #fff));
1907
+ border: 1px solid var(--wodira-box-border, var(--wodira-color-border, #dcd9e3));
1908
+ border-radius: var(--wodira-radius-sm, 0.625rem);
1909
+ color: var(--wodira-box-text, var(--wodira-color-text, #17132e));
1910
+ min-height: var(--wodira-control-height, 2.75rem);
1911
+ padding: 10px 12px;
1912
+ width: 100%;
1913
+ }
1914
+ [part~='choice'] {
1915
+ align-items: start;
1916
+ border: 1px solid var(--wodira-box-border, var(--wodira-color-border, #dcd9e3));
1917
+ border-radius: var(--wodira-radius-sm, 0.625rem);
1918
+ cursor: pointer;
1919
+ display: flex;
1920
+ gap: 10px;
1921
+ padding: 12px;
1922
+ }
1923
+ [part~='legal'] {
1924
+ color: var(--wodira-box-muted, var(--wodira-color-text-muted, #625e70));
1925
+ font-size: 0.78rem;
1926
+ line-height: 1.5;
1927
+ }
1928
+ [part~='legal'] a {
1929
+ color: inherit;
1930
+ }
1931
+ [part~='state'] {
1932
+ color: var(--wodira-box-muted, var(--wodira-color-text-muted, #625e70));
1933
+ padding: 34px 12px;
1934
+ text-align: center;
1935
+ }
1936
+ [part~='error'] {
1937
+ color: var(--wodira-color-danger, #b42318);
1938
+ }
1939
+ [part~='success'] {
1940
+ background: var(--wodira-box-subtle, var(--wodira-color-muted, #f6f5f8));
1941
+ color: var(--wodira-color-success, #16703c);
1942
+ font-weight: 700;
1943
+ padding: 14px 18px;
1944
+ text-align: center;
1945
+ }
1946
+ [part~='footer'] {
1947
+ color: var(--wodira-box-muted, var(--wodira-color-text-muted, #625e70));
1948
+ font-size: 0.72rem;
1949
+ padding: 13px 18px;
1950
+ text-align: center;
1951
+ }
1952
+ [part~='tabs'] {
1953
+ background: var(--wodira-box-surface, var(--wodira-color-surface, #fff));
1954
+ border: 1px solid var(--wodira-box-border, var(--wodira-color-border, #dcd9e3));
1955
+ border-radius: calc(var(--wodira-box-radius, var(--wodira-radius, 1rem)) - 4px);
1956
+ box-shadow: 0 10px 30px rgb(16 24 40 / 0.08);
1957
+ display: flex;
1958
+ gap: 6px;
1959
+ overflow-x: auto;
1960
+ padding: 10px;
1961
+ }
1962
+ [part~='tab'] {
1963
+ background: transparent;
1964
+ color: var(--wodira-box-muted, var(--wodira-color-text-muted, #625e70));
1965
+ white-space: nowrap;
1966
+ }
1967
+ [part~='tab'][aria-selected='true'] {
1968
+ background: var(
1969
+ --wodira-box-primary,
1970
+ var(--wodira-color-primary, var(--_wodira-box-brand-primary, #17132e))
1971
+ );
1972
+ color: var(--wodira-box-primary-contrast, var(--wodira-color-primary-contrast, #fff));
1973
+ }
1974
+ @container (max-width: 520px) {
1975
+ [part~='hero'] {
1976
+ padding: var(--wodira-card-padding, 1rem);
1977
+ }
1978
+ [part~='body'] {
1979
+ padding: 14px;
1980
+ }
1981
+ [part~='toolbar'] {
1982
+ align-items: stretch;
1983
+ flex-direction: column;
1984
+ }
1985
+ [part~='toolbar'] button {
1986
+ width: 100%;
1987
+ }
1988
+ [part~='grid'] {
1989
+ grid-template-columns: 1fr;
1990
+ }
1991
+ }
1992
+ @media (prefers-reduced-motion: no-preference) {
1993
+ [part~='button'],
1994
+ [part~='card'] {
1995
+ transition:
1996
+ border-color 0.18s ease,
1997
+ transform 0.18s ease;
1998
+ }
1999
+ }
2000
+ `;
2001
+
2002
+ // src/ui/layout-styles.ts
2003
+ var wodiraLayoutStyles = css`
2004
+ :host {
2005
+ min-width: 0;
2006
+ color-scheme: var(--wodira-color-scheme, light);
2007
+ }
2008
+ input[type='checkbox'],
2009
+ input[type='radio'] {
2010
+ accent-color: var(--wodira-color-accent, #c40072);
2011
+ }
2012
+ :host,
2013
+ button,
2014
+ input,
2015
+ select,
2016
+ textarea {
2017
+ font-variant-numeric: tabular-nums;
2018
+ }
2019
+ button,
2020
+ input,
2021
+ select,
2022
+ textarea,
2023
+ a {
2024
+ -webkit-tap-highlight-color: transparent;
2025
+ }
2026
+ input,
2027
+ select,
2028
+ textarea {
2029
+ min-width: 0;
2030
+ font-size: max(1rem, 1em);
2031
+ }
2032
+ button {
2033
+ transition:
2034
+ background-color 160ms ease,
2035
+ transform 160ms ease;
2036
+ }
2037
+ button:active:not(:disabled) {
2038
+ transform: translateY(1px);
2039
+ }
2040
+ :is(button, input, select, textarea, a, summary):focus-visible {
2041
+ outline: 3px solid var(--wodira-color-accent, #c40072);
2042
+ outline-offset: 3px;
2043
+ }
2044
+ [part~='title'] {
2045
+ letter-spacing: -0.025em;
2046
+ text-wrap: balance;
2047
+ }
2048
+ [part~='meta'],
2049
+ [part~='hint'] {
2050
+ margin-block: 0.25rem;
2051
+ line-height: 1.5;
2052
+ }
2053
+ [part~='checkout-flow'] {
2054
+ width: 100%;
2055
+ max-width: var(--wodira-content-width, 76rem);
2056
+ margin-inline: auto;
2057
+ }
2058
+ [part~='event-list'],
2059
+ [part~='pricing-cards'] {
2060
+ display: grid;
2061
+ grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--wodira-grid-min, 16rem)), 1fr));
2062
+ align-items: stretch;
2063
+ }
2064
+ [part~='event-card'],
2065
+ [part~='pricing-card'] {
2066
+ height: 100%;
2067
+ }
2068
+ [part~='pricing-card'] > [part~='stack'],
2069
+ [part~='event-card'] > [part~='stack'] {
2070
+ display: flex;
2071
+ flex-direction: column;
2072
+ flex: 1;
2073
+ }
2074
+ [part~='event-card'] {
2075
+ display: flex;
2076
+ flex-direction: column;
2077
+ }
2078
+ [part~='pricing-card'] [part~='button'],
2079
+ [part~='event-card'] [part~='button']:last-child {
2080
+ margin-top: auto;
2081
+ }
2082
+ [part~='pricing-card'][part~='selected'] {
2083
+ border-color: var(--wodira-color-accent, #c40072);
2084
+ box-shadow: inset 0 0 0 1px var(--wodira-color-accent, #c40072);
2085
+ }
2086
+ [part~='registration-form'] {
2087
+ padding: 0;
2088
+ border: 0;
2089
+ box-shadow: none;
2090
+ background: transparent;
2091
+ }
2092
+ [part~='registration-layout'] {
2093
+ display: grid;
2094
+ gap: calc(var(--wodira-space, 1rem) * 1.5);
2095
+ }
2096
+ [part~='registration-fields'] {
2097
+ min-width: 0;
2098
+ background: var(--wodira-color-surface, #fff);
2099
+ border: 1px solid var(--wodira-color-border, #dcd9e3);
2100
+ border-radius: var(--wodira-radius, 1rem);
2101
+ padding: var(--wodira-card-padding, clamp(1rem, 3cqi, 1.75rem));
2102
+ }
2103
+ [part~='registration-fields'] [part~='card'] {
2104
+ box-shadow: none;
2105
+ }
2106
+ [part~='checkout-sidebar'] {
2107
+ display: grid;
2108
+ align-content: start;
2109
+ gap: var(--wodira-space, 1rem);
2110
+ min-width: 0;
2111
+ }
2112
+ [part~='summary'] {
2113
+ display: grid;
2114
+ gap: 0.8rem;
2115
+ }
2116
+ [part~='summary-row'] {
2117
+ align-items: baseline;
2118
+ }
2119
+ [part~='summary-row'] strong {
2120
+ flex-shrink: 0;
2121
+ }
2122
+ [part~='summary-total'] {
2123
+ border-top: 1px solid var(--wodira-color-border, #dcd9e3);
2124
+ padding-top: 1rem;
2125
+ font-size: 1.2em;
2126
+ }
2127
+ [part~='submit'] {
2128
+ width: 100%;
2129
+ }
2130
+ [part~='progress'] {
2131
+ display: flex;
2132
+ flex-wrap: wrap;
2133
+ gap: 0.75rem 1.5rem;
2134
+ list-style: none;
2135
+ padding: 0.25rem 0;
2136
+ margin: 0;
2137
+ color: var(--wodira-color-text-muted, #625e70);
2138
+ }
2139
+ [part~='progress-step'] {
2140
+ display: flex;
2141
+ align-items: center;
2142
+ gap: 0.5rem;
2143
+ font-size: 0.875rem;
2144
+ }
2145
+ [part~='progress-step'][aria-current='step'] {
2146
+ color: var(--wodira-color-text, #17132e);
2147
+ font-weight: 700;
2148
+ }
2149
+ [part~='step-number'] {
2150
+ display: grid;
2151
+ place-items: center;
2152
+ inline-size: 1.75rem;
2153
+ block-size: 1.75rem;
2154
+ border: 1px solid var(--wodira-color-border, #dcd9e3);
2155
+ border-radius: 50%;
2156
+ background: var(--wodira-color-surface, #fff);
2157
+ }
2158
+ [aria-current='step'] [part~='step-number'] {
2159
+ border-color: currentColor;
2160
+ }
2161
+ [part~='error'],
2162
+ [part~='empty'],
2163
+ [part~='loader'] {
2164
+ line-height: 1.5;
2165
+ overflow-wrap: anywhere;
2166
+ }
2167
+ [part~='loader']::before {
2168
+ content: '';
2169
+ display: block;
2170
+ height: 0.5rem;
2171
+ max-width: 16rem;
2172
+ margin: 0 auto 0.75rem;
2173
+ border-radius: var(--wodira-radius-sm, 0.625rem);
2174
+ background: var(--wodira-color-border, #dcd9e3);
2175
+ }
2176
+ ::slotted(*) {
2177
+ max-width: 100%;
2178
+ }
2179
+ @container (min-width: 56rem) {
2180
+ [part~='registration-layout'] {
2181
+ grid-template-columns: minmax(0, 1fr) minmax(16rem, var(--wodira-summary-width, 21rem));
2182
+ }
2183
+ [part~='checkout-sidebar'] {
2184
+ position: sticky;
2185
+ top: var(--wodira-sticky-offset, 1rem);
2186
+ align-self: start;
2187
+ }
2188
+ }
2189
+ @media (prefers-reduced-motion: reduce) {
2190
+ *,
2191
+ *::before,
2192
+ *::after {
2193
+ transition: none !important;
2194
+ animation: none !important;
2195
+ scroll-behavior: auto !important;
2196
+ }
2197
+ button:hover,
2198
+ button:active {
2199
+ transform: none !important;
2200
+ }
2201
+ }
2202
+ @media (forced-colors: active) {
2203
+ button,
2204
+ [part~='card'],
2205
+ input,
2206
+ select,
2207
+ textarea {
2208
+ border: 1px solid ButtonText;
2209
+ }
2210
+ [aria-pressed='true'],
2211
+ [aria-selected='true'] {
2212
+ outline: 2px solid Highlight;
2213
+ }
2214
+ }
2215
+ `;
2216
+
2217
+ // src/ui/theme.ts
2218
+ var wodiraThemeTokens = {
2219
+ primary: "--wodira-color-primary",
2220
+ primaryContrast: "--wodira-color-primary-contrast",
2221
+ accent: "--wodira-color-accent",
2222
+ accentContrast: "--wodira-color-accent-contrast",
2223
+ surface: "--wodira-color-surface",
2224
+ muted: "--wodira-color-muted",
2225
+ border: "--wodira-color-border",
2226
+ text: "--wodira-color-text",
2227
+ textMuted: "--wodira-color-text-muted",
2228
+ danger: "--wodira-color-danger",
2229
+ success: "--wodira-color-success",
2230
+ fontFamily: "--wodira-font-family",
2231
+ fontSize: "--wodira-font-size",
2232
+ colorScheme: "--wodira-color-scheme",
2233
+ radius: "--wodira-radius",
2234
+ radiusSmall: "--wodira-radius-sm",
2235
+ space: "--wodira-space",
2236
+ shadow: "--wodira-shadow",
2237
+ controlHeight: "--wodira-control-height",
2238
+ cardPadding: "--wodira-card-padding",
2239
+ gridMin: "--wodira-grid-min",
2240
+ contentWidth: "--wodira-content-width",
2241
+ summaryWidth: "--wodira-summary-width",
2242
+ stickyOffset: "--wodira-sticky-offset"
2243
+ };
2244
+ var wodiraThemes = {
2245
+ light: {
2246
+ colorScheme: "light",
2247
+ primary: "#17132e",
2248
+ primaryContrast: "#ffffff",
2249
+ accent: "#c40072",
2250
+ accentContrast: "#ffffff",
2251
+ surface: "#ffffff",
2252
+ muted: "#f6f5f8",
2253
+ border: "#dcd9e3",
2254
+ text: "#17132e",
2255
+ textMuted: "#625e70",
2256
+ danger: "#b42318",
2257
+ success: "#16703c"
2258
+ },
2259
+ dark: {
2260
+ colorScheme: "dark",
2261
+ primary: "#f6f2fb",
2262
+ primaryContrast: "#211b2f",
2263
+ accent: "#ff8cca",
2264
+ accentContrast: "#211b2f",
2265
+ surface: "#211b2f",
2266
+ muted: "#30293f",
2267
+ border: "#60566e",
2268
+ text: "#f6f2fb",
2269
+ textMuted: "#c3bace",
2270
+ danger: "#ffaba3",
2271
+ success: "#8cdeb2"
2272
+ }
2273
+ };
2274
+ function applyWodiraTheme(element, theme) {
2275
+ for (const key of Object.keys(wodiraThemeTokens)) {
2276
+ const value = theme[key];
2277
+ if (value === undefined)
2278
+ continue;
2279
+ if (value === null)
2280
+ element.style.removeProperty(wodiraThemeTokens[key]);
2281
+ else
2282
+ element.style.setProperty(wodiraThemeTokens[key], value);
2283
+ }
2284
+ }
2285
+ var wodiraUiParts = [
2286
+ "stack",
2287
+ "grid",
2288
+ "card",
2289
+ "event-card",
2290
+ "event-list",
2291
+ "pricing-cards",
2292
+ "pricing-card",
2293
+ "registration-form",
2294
+ "registration-layout",
2295
+ "registration-fields",
2296
+ "registration-title",
2297
+ "availability",
2298
+ "legal-signature",
2299
+ "checkout-sidebar",
2300
+ "summary",
2301
+ "summary-row",
2302
+ "summary-total",
2303
+ "button",
2304
+ "submit",
2305
+ "secondary",
2306
+ "text-button",
2307
+ "input",
2308
+ "select",
2309
+ "textarea",
2310
+ "checkbox",
2311
+ "label",
2312
+ "title",
2313
+ "price",
2314
+ "meta",
2315
+ "hint",
2316
+ "description",
2317
+ "description-heading",
2318
+ "description-list",
2319
+ "image",
2320
+ "error",
2321
+ "field-error",
2322
+ "loader",
2323
+ "empty",
2324
+ "success",
2325
+ "waiver",
2326
+ "supplement",
2327
+ "eligibility-summary",
2328
+ "participant-mode",
2329
+ "participant-mode-button",
2330
+ "deferred-participant-hint",
2331
+ "gender-composition",
2332
+ "composition-options",
2333
+ "composition-option",
2334
+ "tier-list",
2335
+ "tier-row",
2336
+ "tier-heading",
2337
+ "tier-name",
2338
+ "tier-price",
2339
+ "badge",
2340
+ "current-tier",
2341
+ "read-more",
2342
+ "event-card-description",
2343
+ "event-card-description-full",
2344
+ "purchaser-grid",
2345
+ "participant",
2346
+ "guest-registration",
2347
+ "terms",
2348
+ "selected",
2349
+ "active",
2350
+ "current",
2351
+ "retry",
2352
+ "inline-code",
2353
+ "tier-meta",
2354
+ "field",
2355
+ "athlete",
2356
+ "deferred",
2357
+ "athlete-grid",
2358
+ "custom-fields",
2359
+ "custom-fields-grid",
2360
+ "custom-field",
2361
+ "supplements",
2362
+ "guest-registrations",
2363
+ "add-guest",
2364
+ "guest-grid",
2365
+ "remove-guest",
2366
+ "guest-athlete",
2367
+ "guest-supplements",
2368
+ "waivers",
2369
+ "guest-summary-row"
2370
+ ].join(",");
2371
+ var wodiraBoxParts = [
2372
+ "shell",
2373
+ "widget-shell",
2374
+ "hero",
2375
+ "widget-hero",
2376
+ "cover",
2377
+ "box-cover",
2378
+ "logo",
2379
+ "box-logo",
2380
+ "brand",
2381
+ "brand-name",
2382
+ "title",
2383
+ "body",
2384
+ "widget-body",
2385
+ "toolbar",
2386
+ "nav-button",
2387
+ "button",
2388
+ "grid",
2389
+ "card",
2390
+ "card-heading",
2391
+ "card-title",
2392
+ "meta",
2393
+ "badge",
2394
+ "price",
2395
+ "features",
2396
+ "field",
2397
+ "input",
2398
+ "choice",
2399
+ "legal",
2400
+ "state",
2401
+ "loader",
2402
+ "error",
2403
+ "success",
2404
+ "footer",
2405
+ "retry",
2406
+ "class-cta",
2407
+ "trial-cta",
2408
+ "plan-cta",
2409
+ "class-card",
2410
+ "class-meta",
2411
+ "availability",
2412
+ "calendar-toolbar",
2413
+ "previous",
2414
+ "next",
2415
+ "empty",
2416
+ "class-grid",
2417
+ "plans-grid",
2418
+ "plan-card",
2419
+ "trial-form",
2420
+ "choices",
2421
+ "trial-class-grid",
2422
+ "trial-choice",
2423
+ "email",
2424
+ "legal-choice"
2425
+ ].join(",");
2426
+
2427
+ // src/ui/boxes/components.ts
2428
+ var AVAILABILITY_COPY = {
2429
+ AVAILABLE: "available",
2430
+ LAST_SPOTS: "last",
2431
+ WAITLIST: "waitlist",
2432
+ FULL: "full"
2433
+ };
2434
+
2435
+ class WodiraBoxElement extends LitElement {
2436
+ static properties = {
2437
+ publishableKey: { type: String, attribute: "publishable-key" },
2438
+ installationId: { type: String, attribute: "installation-id" },
2439
+ baseUrl: { type: String, attribute: "base-url" },
2440
+ locale: { type: String },
2441
+ context: { state: true },
2442
+ loading: { state: true },
2443
+ error: { state: true },
2444
+ resultMessage: { state: true }
2445
+ };
2446
+ static styles = [boxWidgetStyles, wodiraLayoutStyles];
2447
+ client = null;
2448
+ abortController = null;
2449
+ didInitialLoad = false;
2450
+ pendingResultToken = "";
2451
+ constructor() {
2452
+ super();
2453
+ this.publishableKey = "";
2454
+ this.installationId = "";
2455
+ this.baseUrl = "";
2456
+ this.locale = "auto";
2457
+ this.context = null;
2458
+ this.loading = true;
2459
+ this.error = "";
2460
+ this.resultMessage = "";
2461
+ }
2462
+ firstUpdated() {
2463
+ this.pendingResultToken = this.consumeResult();
2464
+ this.refresh();
2465
+ }
2466
+ disconnectedCallback() {
2467
+ this.abortController?.abort();
2468
+ super.disconnectedCallback();
2469
+ }
2470
+ updated(changes) {
2471
+ if (!this.didInitialLoad) {
2472
+ this.didInitialLoad = true;
2473
+ return;
2474
+ }
2475
+ if ((changes.has("publishableKey") || changes.has("installationId") || changes.has("baseUrl")) && this.didInitialLoad) {
2476
+ this.refresh();
2477
+ }
2478
+ if (this.context) {
2479
+ this.style.setProperty("--_wodira-box-brand-primary", this.context.box.theme.primary);
2480
+ this.style.setProperty("--_wodira-box-brand-accent", this.context.box.theme.secondary);
2481
+ }
2482
+ }
2483
+ async refresh() {
2484
+ if (!this.publishableKey || !this.installationId) {
2485
+ this.loading = false;
2486
+ this.error = "publishable-key and installation-id are required.";
2487
+ return;
2488
+ }
2489
+ this.abortController?.abort();
2490
+ this.abortController = new AbortController;
2491
+ this.loading = true;
2492
+ this.error = "";
2493
+ try {
2494
+ this.client = createWodiraBoxWidgetClient({
2495
+ publishableKey: this.publishableKey,
2496
+ installationId: this.installationId,
2497
+ ...this.baseUrl ? { baseUrl: this.baseUrl } : {}
2498
+ });
2499
+ this.context = await this.client.getContext(this.abortController.signal);
2500
+ if (this.pendingResultToken) {
2501
+ await this.verifyResultWithRetry(this.pendingResultToken, this.abortController.signal);
2502
+ this.pendingResultToken = "";
2503
+ this.resultMessage = boxText(this.locale, "result");
2504
+ }
2505
+ if (this.locale === "auto")
2506
+ this.locale = this.context.locale;
2507
+ await this.loadData(this.abortController.signal);
2508
+ this.telemetry("IMPRESSION");
2509
+ } catch (error) {
2510
+ if (error instanceof Error && error.name === "AbortError")
2511
+ return;
2512
+ this.error = error instanceof Error ? error.message : boxText(this.locale, "error");
2513
+ } finally {
2514
+ this.loading = false;
2515
+ }
2516
+ }
2517
+ frame(title, body) {
2518
+ const context = this.context;
2519
+ return html`
2520
+ <section part="shell widget-shell" aria-busy=${this.loading ? "true" : "false"}>
2521
+ <slot name="header"></slot>
2522
+ ${context ? html`<header part="hero widget-hero" ?data-cover=${Boolean(context.box.coverUrl)}>
2523
+ ${context.box.coverUrl ? html`<img part="cover box-cover" src=${context.box.coverUrl} alt="" />` : nothing}
2524
+ ${context.box.logoUrl ? html`<img part="logo box-logo" src=${context.box.logoUrl} alt="" />` : nothing}
2525
+ <div part="brand">
2526
+ <p part="brand-name">${context.box.name}</p>
2527
+ <h2 part="title">${title}</h2>
2528
+ </div>
2529
+ </header>` : nothing}
2530
+ ${this.resultMessage ? html`<div part="success" role="status">${this.resultMessage}</div>` : nothing}
2531
+ <div part="body widget-body">
2532
+ <slot name="intro"></slot>
2533
+ ${this.loading ? html`<div part="state loader" role="status">
2534
+ ${boxText(this.locale, "loading")}
2535
+ </div>` : this.error ? html`<div part="state error" role="alert">
2536
+ <p>${boxText(this.locale, "error")}</p>
2537
+ <button part="nav-button retry" type="button" @click=${() => this.refresh()}>
2538
+ ${boxText(this.locale, "retry")}
2539
+ </button>
2540
+ </div>` : body}
2541
+ </div>
2542
+ <slot name="footer"></slot>
2543
+ <footer part="footer"><span>${boxText(this.locale, "powered")}</span></footer>
2544
+ </section>
2545
+ `;
2546
+ }
2547
+ classCard(entry, action) {
2548
+ const language = resolveBoxWidgetLanguage(this.locale);
2549
+ const date = new Intl.DateTimeFormat(language, {
2550
+ weekday: "short",
2551
+ day: "numeric",
2552
+ month: "short",
2553
+ hour: "2-digit",
2554
+ minute: "2-digit",
2555
+ timeZone: entry.timezone || this.context?.box.timezone
2556
+ }).format(new Date(entry.startsAt));
2557
+ const isDisabled = entry.availability === "FULL";
2558
+ return html`<article part="card class-card">
2559
+ <div part="card-heading">
2560
+ <div>
2561
+ <h3 part="card-title">${entry.name}</h3>
2562
+ <div part="meta class-meta"><time datetime=${entry.startsAt}>${date}</time></div>
2563
+ </div>
2564
+ <span part="badge availability" data-status=${entry.availability}>
2565
+ ${boxText(this.locale, AVAILABILITY_COPY[entry.availability])}
2566
+ </span>
2567
+ </div>
2568
+ <div part="meta">
2569
+ ${entry.coachName ? html`<span>${boxText(this.locale, "coach")}: ${entry.coachName}</span>` : nothing}
2570
+ ${entry.location ? html`<span>${entry.location}</span>` : nothing}
2571
+ ${entry.durationMinutes ? html`<span>${entry.durationMinutes} ${boxText(this.locale, "duration")}</span>` : nothing}
2572
+ ${entry.directPurchase ? html`<span
2573
+ >${formatMoney(entry.directPurchase.amount, entry.directPurchase.currency, language)}</span
2574
+ >` : nothing}
2575
+ </div>
2576
+ <button part="button class-cta" type="button" ?disabled=${isDisabled} @click=${action}>
2577
+ ${boxText(this.locale, "reserve")}
2578
+ </button>
2579
+ </article>`;
2580
+ }
2581
+ emit(name, detail) {
2582
+ this.dispatchEvent(new CustomEvent(name, { detail, bubbles: true, composed: true }));
2583
+ }
2584
+ async startFlow(intent, targetId, extra = {}) {
2585
+ if (!this.client)
2586
+ return;
2587
+ const result = await this.client.createFlow({
2588
+ intent,
2589
+ targetId,
2590
+ idempotencyKey: [
2591
+ this.installationId,
2592
+ intent,
2593
+ targetId,
2594
+ extra.privacyVersion ?? "none",
2595
+ sessionId()
2596
+ ].join(":"),
2597
+ ...extra,
2598
+ ...utm()
2599
+ });
2600
+ if (result.continuationUrl)
2601
+ globalThis.location.assign(result.continuationUrl);
2602
+ }
2603
+ telemetry(kind, entityId) {
2604
+ if (!this.client)
2605
+ return Promise.resolve();
2606
+ return this.client.recordTelemetry([
2607
+ {
2608
+ id: cryptoId(),
2609
+ kind,
2610
+ widgetKind: this.widgetKind(),
2611
+ ...entityId ? { entityId } : {},
2612
+ sessionId: sessionId(),
2613
+ occurredAt: new Date().toISOString(),
2614
+ ...utm()
2615
+ }
2616
+ ]).then(() => {
2617
+ return;
2618
+ }).catch(() => {
2619
+ return;
2620
+ });
2621
+ }
2622
+ syncStructuredData(value) {
2623
+ let script = this.querySelector("script[data-wodira-widget-jsonld]");
2624
+ if (!script) {
2625
+ script = document.createElement("script");
2626
+ script.type = "application/ld+json";
2627
+ script.dataset["wodiraWidgetJsonld"] = "";
2628
+ this.append(script);
2629
+ }
2630
+ script.textContent = JSON.stringify(value).replaceAll("<", "\\u003c");
2631
+ }
2632
+ consumeResult() {
2633
+ try {
2634
+ const url = new URL(globalThis.location.href);
2635
+ const result = url.searchParams.get("wodira_widget_result") ?? "";
2636
+ if (!result)
2637
+ return "";
2638
+ url.searchParams.delete("wodira_widget_result");
2639
+ globalThis.history?.replaceState({}, "", url);
2640
+ return result;
2641
+ } catch {
2642
+ return "";
2643
+ }
2644
+ }
2645
+ async verifyResultWithRetry(token, signal) {
2646
+ if (!this.client)
2647
+ return;
2648
+ let lastError;
2649
+ for (let attempt = 0;attempt < 10; attempt += 1) {
2650
+ try {
2651
+ await this.client.verifyResult(token, signal);
2652
+ return;
2653
+ } catch (error) {
2654
+ lastError = error;
2655
+ if (signal.aborted || attempt === 9)
2656
+ break;
2657
+ await new Promise((resolve, reject) => {
2658
+ const timeout = globalThis.setTimeout(resolve, 1000);
2659
+ signal.addEventListener("abort", () => {
2660
+ globalThis.clearTimeout(timeout);
2661
+ reject(new DOMException("Aborted", "AbortError"));
2662
+ }, { once: true });
2663
+ });
2664
+ }
2665
+ }
2666
+ throw lastError;
2667
+ }
2668
+ }
2669
+
2670
+ class WodiraBoxCalendar extends WodiraBoxElement {
2671
+ static properties = {
2672
+ ...WodiraBoxElement.properties,
2673
+ calendar: { state: true },
2674
+ week: { state: true }
2675
+ };
2676
+ constructor() {
2677
+ super();
2678
+ this.calendar = null;
2679
+ this.week = 0;
2680
+ }
2681
+ widgetKind() {
2682
+ return "CALENDAR";
2683
+ }
2684
+ async loadData(signal) {
2685
+ const from = new Date;
2686
+ from.setDate(from.getDate() + this.week * 7);
2687
+ this.calendar = await this.client?.getCalendar(from, 1, signal) ?? null;
2688
+ this.syncStructuredData({
2689
+ "@context": "https://schema.org",
2690
+ "@type": "SportsActivityLocation",
2691
+ name: this.context?.box.name,
2692
+ event: this.calendar?.classes.map((entry) => ({
2693
+ "@type": "SportsEvent",
2694
+ name: entry.name,
2695
+ startDate: entry.startsAt,
2696
+ location: entry.location ? { "@type": "Place", name: entry.location } : undefined
2697
+ }))
2698
+ });
2699
+ }
2700
+ changeWeek(offset) {
2701
+ this.week = Math.min(3, Math.max(0, this.week + offset));
2702
+ this.refresh();
2703
+ }
2704
+ choose(entry) {
2705
+ this.emit("wodira:box-class-selected", {
2706
+ installationId: this.installationId,
2707
+ classId: entry.id
2708
+ });
2709
+ this.telemetry("CLASS_SELECTED", entry.id);
2710
+ this.startFlow("RESERVE_CLASS", entry.id);
2711
+ }
2712
+ render() {
2713
+ return this.frame(boxText(this.locale, "calendar"), html`
2714
+ <div part="toolbar calendar-toolbar">
2715
+ <button
2716
+ part="nav-button previous"
2717
+ type="button"
2718
+ ?disabled=${this.week === 0}
2719
+ @click=${() => this.changeWeek(-1)}
2720
+ >
2721
+ ← ${boxText(this.locale, "previous")}
2722
+ </button>
2723
+ <button
2724
+ part="nav-button next"
2725
+ type="button"
2726
+ ?disabled=${this.week === 3}
2727
+ @click=${() => this.changeWeek(1)}
2728
+ >
2729
+ ${boxText(this.locale, "next")} →
2730
+ </button>
2731
+ </div>
2732
+ ${this.calendar?.classes.length ? html`<div part="grid class-grid">
2733
+ ${this.calendar.classes.map((entry) => this.classCard(entry, () => this.choose(entry)))}
2734
+ </div>` : html`<div part="state empty">${boxText(this.locale, "empty")}</div>`}
2735
+ `);
2736
+ }
2737
+ }
2738
+
2739
+ class WodiraBoxPlans extends WodiraBoxElement {
2740
+ static properties = { ...WodiraBoxElement.properties, plans: { state: true } };
2741
+ constructor() {
2742
+ super();
2743
+ this.plans = null;
2744
+ }
2745
+ widgetKind() {
2746
+ return "PLANS";
2747
+ }
2748
+ async loadData(signal) {
2749
+ this.plans = await this.client?.getPlans(signal) ?? null;
2750
+ this.syncStructuredData({
2751
+ "@context": "https://schema.org",
2752
+ "@type": "ItemList",
2753
+ itemListElement: this.plans?.plans.map((plan, position) => ({
2754
+ "@type": "Offer",
2755
+ position: position + 1,
2756
+ name: plan.name,
2757
+ price: plan.price,
2758
+ priceCurrency: plan.currency
2759
+ }))
2760
+ });
2761
+ }
2762
+ choose(plan) {
2763
+ this.emit("wodira:box-plan-selected", { installationId: this.installationId, planId: plan.id });
2764
+ this.telemetry("PLAN_SELECTED", plan.id);
2765
+ this.startFlow("BUY_PLAN", plan.id);
2766
+ }
2767
+ render() {
2768
+ const language = resolveBoxWidgetLanguage(this.locale);
2769
+ return this.frame(boxText(this.locale, "plans"), html`
2770
+ ${this.plans?.plans.length ? html`<div part="grid plans-grid">
2771
+ ${this.plans.plans.map((plan) => html` <article part="card plan-card">
2772
+ <div>
2773
+ <h3 part="card-title">${plan.name}</h3>
2774
+ ${plan.description ? html`<p part="meta">${plan.description}</p>` : nothing}
2775
+ </div>
2776
+ <div part="price">${formatMoney(plan.price, plan.currency, language)}</div>
2777
+ <div part="meta">
2778
+ ${plan.credits === null ? boxText(this.locale, "unlimited") : `${plan.credits} ${boxText(this.locale, "credits")}`}
2779
+ · ${formatPlanInterval(plan.interval, this.locale)}
2780
+ </div>
2781
+ ${plan.features.length ? html`<ul part="features">
2782
+ ${plan.features.map((feature) => html`<li>${feature}</li>`)}
2783
+ </ul>` : nothing}
2784
+ <button
2785
+ part="button plan-cta"
2786
+ data-plan-id=${plan.id}
2787
+ type="button"
2788
+ @click=${() => this.choose(plan)}
2789
+ >
2790
+ ${boxText(this.locale, "reserve")}
2791
+ </button>
2792
+ </article>`)}
2793
+ </div>` : html`<div part="state empty">${boxText(this.locale, "empty")}</div>`}
2794
+ `);
2795
+ }
2796
+ }
2797
+
2798
+ class WodiraBoxTrial extends WodiraBoxElement {
2799
+ static properties = {
2800
+ ...WodiraBoxElement.properties,
2801
+ trials: { state: true },
2802
+ selectedClassId: { state: true },
2803
+ email: { state: true },
2804
+ privacyAccepted: { state: true },
2805
+ submitting: { state: true },
2806
+ formError: { state: true }
2807
+ };
2808
+ constructor() {
2809
+ super();
2810
+ this.trials = null;
2811
+ this.selectedClassId = "";
2812
+ this.email = "";
2813
+ this.privacyAccepted = false;
2814
+ this.submitting = false;
2815
+ this.formError = "";
2816
+ }
2817
+ widgetKind() {
2818
+ return "TRIAL";
2819
+ }
2820
+ async loadData(signal) {
2821
+ this.trials = await this.client?.getTrialClasses(signal) ?? null;
2822
+ this.selectedClassId = this.trials?.classes[0]?.id ?? "";
2823
+ }
2824
+ async submit(event) {
2825
+ event.preventDefault();
2826
+ if (!this.email.includes("@") || !this.selectedClassId || !this.privacyAccepted || !this.context) {
2827
+ this.formError = boxText(this.locale, "error");
2828
+ return;
2829
+ }
2830
+ this.submitting = true;
2831
+ this.formError = "";
2832
+ this.emit("wodira:box-trial-selected", {
2833
+ installationId: this.installationId,
2834
+ classId: this.selectedClassId
2835
+ });
2836
+ this.telemetry("TRIAL_SELECTED", this.selectedClassId);
2837
+ try {
2838
+ const form = event.currentTarget;
2839
+ const website = String(new FormData(form).get("website") ?? "");
2840
+ await this.startFlow("START_TRIAL", this.selectedClassId, {
2841
+ email: this.email,
2842
+ privacyAccepted: true,
2843
+ privacyVersion: this.context.legal.acceptanceVersion,
2844
+ website
2845
+ });
2846
+ } catch (error) {
2847
+ this.formError = error instanceof Error ? error.message : boxText(this.locale, "error");
2848
+ } finally {
2849
+ this.submitting = false;
2850
+ }
2851
+ }
2852
+ render() {
2853
+ return this.frame(boxText(this.locale, "trial"), html`
2854
+ ${this.trials?.enabled && this.trials.classes.length ? html`<form part="trial-form" @submit=${this.submit}>
2855
+ <fieldset part="field choices">
2856
+ <legend>${boxText(this.locale, "chooseClass")}</legend>
2857
+ <div part="grid trial-class-grid">
2858
+ ${this.trials.classes.map((entry) => html` <label part="choice trial-choice"
2859
+ ><input
2860
+ type="radio"
2861
+ name="trialClass"
2862
+ .value=${entry.id}
2863
+ .checked=${this.selectedClassId === entry.id}
2864
+ @change=${() => {
2865
+ this.selectedClassId = entry.id;
2866
+ }}
2867
+ />
2868
+ <span
2869
+ ><strong>${entry.name}</strong><br /><small
2870
+ >${new Intl.DateTimeFormat(resolveBoxWidgetLanguage(this.locale), { dateStyle: "medium", timeStyle: "short", timeZone: entry.timezone || this.context?.box.timezone }).format(new Date(entry.startsAt))}</small
2871
+ ></span
2872
+ >
2873
+ </label>`)}
2874
+ </div>
2875
+ </fieldset>
2876
+ <label part="field"
2877
+ ><span>${boxText(this.locale, "email")}</span
2878
+ ><input
2879
+ part="input email"
2880
+ type="email"
2881
+ autocomplete="email"
2882
+ required
2883
+ .value=${this.email}
2884
+ @input=${(event) => {
2885
+ this.email = event.currentTarget.value;
2886
+ }}
2887
+ /></label>
2888
+ <input
2889
+ name="website"
2890
+ tabindex="-1"
2891
+ autocomplete="off"
2892
+ aria-hidden="true"
2893
+ style="position:absolute;left:-10000px"
2894
+ />
2895
+ <label part="choice legal-choice"
2896
+ ><input
2897
+ type="checkbox"
2898
+ required
2899
+ .checked=${this.privacyAccepted}
2900
+ @change=${(event) => {
2901
+ this.privacyAccepted = event.currentTarget.checked;
2902
+ }}
2903
+ />
2904
+ <span part="legal"
2905
+ >${boxText(this.locale, "privacy")}
2906
+ <a
2907
+ href=${this.context?.legal.wodiraPrivacyUrl ?? "#"}
2908
+ target="_blank"
2909
+ rel="noopener noreferrer"
2910
+ >WODira</a
2911
+ >
2912
+ ${this.context?.legal.boxPrivacyUrl ? html` · <a href=${this.context.legal.boxPrivacyUrl} target="_blank" rel="noopener noreferrer">${this.context.box.name}</a>` : nothing}
2913
+ </span>
2914
+ </label>
2915
+ ${this.formError ? html`<p part="error" role="alert">${this.formError}</p>` : nothing}
2916
+ <button part="button trial-cta" type="submit" ?disabled=${this.submitting}>
2917
+ ${this.submitting ? boxText(this.locale, "loading") : boxText(this.locale, "trialCta")}
2918
+ </button>
2919
+ </form>` : html`<div part="state empty">${boxText(this.locale, "empty")}</div>`}
2920
+ `);
2921
+ }
2922
+ }
2923
+
2924
+ class WodiraBoxWidget extends LitElement {
2925
+ static properties = {
2926
+ publishableKey: { type: String, attribute: "publishable-key" },
2927
+ installationId: { type: String, attribute: "installation-id" },
2928
+ baseUrl: { type: String, attribute: "base-url" },
2929
+ locale: { type: String },
2930
+ active: { state: true }
2931
+ };
2932
+ static styles = [boxWidgetStyles, wodiraLayoutStyles];
2933
+ panelId = `wodira-box-panel-${cryptoId()}`;
2934
+ constructor() {
2935
+ super();
2936
+ this.publishableKey = "";
2937
+ this.installationId = "";
2938
+ this.baseUrl = "";
2939
+ this.locale = "auto";
2940
+ this.active = "calendar";
2941
+ }
2942
+ render() {
2943
+ const attrs = {
2944
+ publishableKey: this.publishableKey,
2945
+ installationId: this.installationId,
2946
+ baseUrl: this.baseUrl,
2947
+ locale: this.locale
2948
+ };
2949
+ return html`<section part="composite composite-shell">
2950
+ <slot name="header"></slot>
2951
+ <nav part="tabs" role="tablist" aria-label="Widgets">
2952
+ ${["calendar", "trial", "plans"].map((tab) => html`<button
2953
+ part="nav-button tab"
2954
+ type="button"
2955
+ role="tab"
2956
+ aria-selected=${this.active === tab ? "true" : "false"}
2957
+ aria-controls=${this.panelId}
2958
+ tabindex=${this.active === tab ? "0" : "-1"}
2959
+ @keydown=${(event) => this.navigateTabs(event, tab)}
2960
+ @click=${() => {
2961
+ this.active = tab;
2962
+ }}
2963
+ >
2964
+ ${boxText(this.locale, tab)}
2965
+ </button>`)}
2966
+ </nav>
2967
+ <div id=${this.panelId} part="composite-content" role="tabpanel" tabindex="0">
2968
+ ${this.active === "calendar" ? html`<wodira-box-calendar exportparts=${wodiraBoxParts} .publishableKey=${attrs.publishableKey} .installationId=${attrs.installationId} .baseUrl=${attrs.baseUrl} .locale=${attrs.locale}><slot name="calendar-intro" slot="intro"></slot></wodira-box-calendar>` : nothing}
2969
+ ${this.active === "trial" ? html`<wodira-box-trial exportparts=${wodiraBoxParts} .publishableKey=${attrs.publishableKey} .installationId=${attrs.installationId} .baseUrl=${attrs.baseUrl} .locale=${attrs.locale}><slot name="trial-intro" slot="intro"></slot></wodira-box-trial>` : nothing}
2970
+ ${this.active === "plans" ? html`<wodira-box-plans exportparts=${wodiraBoxParts} .publishableKey=${attrs.publishableKey} .installationId=${attrs.installationId} .baseUrl=${attrs.baseUrl} .locale=${attrs.locale}><slot name="plans-intro" slot="intro"></slot></wodira-box-plans>` : nothing}
2971
+ </div>
2972
+ <slot name="footer"></slot>
2973
+ </section>`;
2974
+ }
2975
+ navigateTabs(event, current) {
2976
+ const tabs = ["calendar", "trial", "plans"];
2977
+ const currentIndex = tabs.indexOf(current);
2978
+ const nextIndex = event.key === "Home" ? 0 : event.key === "End" ? tabs.length - 1 : event.key === "ArrowRight" ? (currentIndex + 1) % tabs.length : event.key === "ArrowLeft" ? (currentIndex - 1 + tabs.length) % tabs.length : -1;
2979
+ if (nextIndex < 0)
2980
+ return;
2981
+ const next = tabs[nextIndex];
2982
+ if (!next)
2983
+ return;
2984
+ event.preventDefault();
2985
+ this.active = next;
2986
+ this.updateComplete.then(() => {
2987
+ this.renderRoot.querySelectorAll('[role="tab"]')[nextIndex]?.focus();
2988
+ });
2989
+ }
2990
+ }
2991
+ function formatPlanInterval(interval, locale) {
2992
+ const key = interval.trim().toLowerCase();
2993
+ if (key === "once" || key === "one_time")
2994
+ return boxText(locale, "once");
2995
+ if (key === "daily" || key === "day")
2996
+ return boxText(locale, "daily");
2997
+ if (key === "weekly" || key === "week")
2998
+ return boxText(locale, "weekly");
2999
+ if (key === "monthly" || key === "month")
3000
+ return boxText(locale, "monthly");
3001
+ if (key === "yearly" || key === "annual" || key === "year")
3002
+ return boxText(locale, "yearly");
3003
+ return interval;
3004
+ }
3005
+ function formatMoney(value, currency, locale) {
3006
+ return new Intl.NumberFormat(locale, {
3007
+ style: "currency",
3008
+ currency,
3009
+ maximumFractionDigits: 2
3010
+ }).format(value);
3011
+ }
3012
+ function cryptoId() {
3013
+ return globalThis.crypto?.randomUUID?.() ?? `widget-${Date.now()}-${Math.random().toString(36).slice(2)}`;
3014
+ }
3015
+ function sessionId() {
3016
+ const key = "wodira:box-widget-session";
3017
+ try {
3018
+ const existing = globalThis.sessionStorage?.getItem(key);
3019
+ if (existing)
3020
+ return existing;
3021
+ const created = cryptoId();
3022
+ globalThis.sessionStorage?.setItem(key, created);
3023
+ return created;
3024
+ } catch {
3025
+ return cryptoId();
3026
+ }
3027
+ }
3028
+ function utm() {
3029
+ try {
3030
+ const query = new URL(globalThis.location.href).searchParams;
3031
+ const utmSource = query.get("utm_source") ?? undefined;
3032
+ const utmMedium = query.get("utm_medium") ?? undefined;
3033
+ const utmCampaign = query.get("utm_campaign") ?? undefined;
3034
+ return {
3035
+ ...utmSource ? { utmSource } : {},
3036
+ ...utmMedium ? { utmMedium } : {},
3037
+ ...utmCampaign ? { utmCampaign } : {}
3038
+ };
3039
+ } catch {
3040
+ return {};
3041
+ }
3042
+ }
3043
+
3044
+ // src/ui/boxes/index.ts
3045
+ var ELEMENTS = [
3046
+ ["wodira-box-calendar", WodiraBoxCalendar],
3047
+ ["wodira-box-trial", WodiraBoxTrial],
3048
+ ["wodira-box-plans", WodiraBoxPlans],
3049
+ ["wodira-box-widget", WodiraBoxWidget]
3050
+ ];
3051
+ function defineWodiraBoxElements() {
3052
+ if (!globalThis.customElements) {
3053
+ throw new Error("@wodira/browser/ui/boxes requires a Custom Elements environment.");
3054
+ }
3055
+ for (const [tag, element] of ELEMENTS) {
3056
+ if (!customElements.get(tag))
3057
+ customElements.define(tag, element);
3058
+ }
3059
+ }
3060
+ export {
3061
+ WodiraBoxCalendar,
3062
+ WodiraBoxPlans,
3063
+ WodiraBoxTrial,
3064
+ WodiraBoxWidget,
3065
+ WodiraBoxWidgetClient,
3066
+ applyWodiraTheme,
3067
+ createWodiraBoxWidgetClient,
3068
+ defineWodiraBoxElements,
3069
+ wodiraThemeTokens,
3070
+ wodiraThemes
3071
+ };