@getmicdrop/svelte-components 5.16.2 → 5.17.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.
@@ -2,6 +2,17 @@
2
2
  import { CloseOutline, LogoInstagram } from '../../primitives/Icons';
3
3
  import { typography } from '../../tokens/typography';
4
4
 
5
+ /**
6
+ * Default labels for user-visible strings in AboutShow.
7
+ * Consumers can override via the `labels` prop.
8
+ */
9
+ const defaultLabels = {
10
+ followLabel: (name) => `Follow ${name}:`,
11
+ showLess: 'Show less',
12
+ showMore: 'Show more',
13
+ closePopover: 'Close',
14
+ };
15
+
5
16
  let {
6
17
  performers = [],
7
18
  ShowImage = '',
@@ -10,8 +21,12 @@
10
21
  title = "About the Show",
11
22
  showReadMore = true,
12
23
  getImageUrl = (url) => url,
24
+ /** @type {Partial<typeof defaultLabels>} Override any user-visible string */
25
+ labels: userLabels = {},
13
26
  } = $props();
14
27
 
28
+ let labels = $derived({ ...defaultLabels, ...userLabels });
29
+
15
30
  let activePerformer = $state(null);
16
31
  let characterLimit = 1500;
17
32
  let showFullDescription = $state(false);
@@ -60,7 +75,7 @@
60
75
  onclick={toggleDescription}
61
76
  class={`${typography.label} text-left hover:underline text-blue-700 dark:text-blue-500`}
62
77
  >
63
- Show less
78
+ {labels.showLess}
64
79
  </button>
65
80
  {/if}
66
81
  {:else}
@@ -71,7 +86,7 @@
71
86
  onclick={toggleDescription}
72
87
  class={`${typography.label} text-left hover:underline text-blue-700 dark:text-blue-500`}
73
88
  >
74
- Show more
89
+ {labels.showMore}
75
90
  </button>
76
91
  {/if}
77
92
  {/if}
@@ -106,7 +121,7 @@
106
121
  <button
107
122
  class="absolute top-2 right-2 p-1 rounded-full transition-colors text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-700"
108
123
  onclick={closePerformer}
109
- aria-label="Close"
124
+ aria-label={labels.closePopover}
110
125
  >
111
126
  <CloseOutline class="w-5 h-5" />
112
127
  </button>
@@ -117,7 +132,7 @@
117
132
 
118
133
  {#if profile?.instagram || profile?.twitter}
119
134
  <div class="flex gap-2 items-center {typography.smMuted} mt-3 pt-3 border-t border-gray-200 dark:border-gray-600">
120
- <span>Follow {firstName}:</span>
135
+ <span>{typeof labels.followLabel === 'function' ? labels.followLabel(firstName) : labels.followLabel}</span>
121
136
  {#if profile?.instagram}
122
137
  <a
123
138
  href={profile.instagram}
@@ -11,6 +11,7 @@ declare const AboutShow: import("svelte").Component<{
11
11
  title?: string;
12
12
  showReadMore?: boolean;
13
13
  getImageUrl?: Function;
14
+ labels?: Record<string, any>;
14
15
  }, {}, "">;
15
16
  type $$ComponentProps = {
16
17
  performers?: any[];
@@ -20,5 +21,6 @@ type $$ComponentProps = {
20
21
  title?: string;
21
22
  showReadMore?: boolean;
22
23
  getImageUrl?: Function;
24
+ labels?: Record<string, any>;
23
25
  };
24
26
  //# sourceMappingURL=AboutShow.svelte.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AboutShow.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/calendar/AboutShow/AboutShow.svelte.js"],"names":[],"mappings":";;;;;AAmJA;iBAzIkC,GAAG,EAAE;gBAAc,MAAM;kBAAgB,MAAM;gBAAc,OAAO;YAAU,MAAM;mBAAiB,OAAO;;WAyItF;wBAzIrC;IAAE,UAAU,CAAC,EAAE,GAAG,EAAE,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,WAAU;CAAE"}
1
+ {"version":3,"file":"AboutShow.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/calendar/AboutShow/AboutShow.svelte.js"],"names":[],"mappings":";;;;;AAkKA;iBA7IkC,GAAG,EAAE;gBAAc,MAAM;kBAAgB,MAAM;gBAAc,OAAO;YAAU,MAAM;mBAAiB,OAAO;;aAAmC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;WA6I5I;wBA7IrC;IAAE,UAAU,CAAC,EAAE,GAAG,EAAE,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,WAAW;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAAE"}
@@ -7,6 +7,8 @@
7
7
  title = "FAQs",
8
8
  showTitle = true,
9
9
  accordion = false,
10
+ /** @type {string} Text shown when no FAQs are available */
11
+ emptyMessage = 'No FAQs available.',
10
12
  } = $props();
11
13
 
12
14
  let openIndex = $state(null);
@@ -70,6 +72,6 @@
70
72
  </div>
71
73
  {/if}
72
74
  {:else}
73
- <p class="{typography.smMuted}">No FAQs available.</p>
75
+ <p class="{typography.smMuted}">{emptyMessage}</p>
74
76
  {/if}
75
77
  </div>
@@ -8,11 +8,13 @@ declare const FAQs: import("svelte").Component<{
8
8
  title?: string;
9
9
  showTitle?: boolean;
10
10
  accordion?: boolean;
11
+ emptyMessage?: string;
11
12
  }, {}, "">;
12
13
  type $$ComponentProps = {
13
14
  faqs?: any[];
14
15
  title?: string;
15
16
  showTitle?: boolean;
16
17
  accordion?: boolean;
18
+ emptyMessage?: string;
17
19
  };
18
20
  //# sourceMappingURL=FAQs.svelte.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FAQs.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/calendar/FAQs/FAQs.svelte.js"],"names":[],"mappings":";;;;;AA0EA;WAhE4B,GAAG,EAAE;YAAU,MAAM;gBAAc,OAAO;gBAAc,OAAO;WAgExC;wBAhEhC;IAAE,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE"}
1
+ {"version":3,"file":"FAQs.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/calendar/FAQs/FAQs.svelte.js"],"names":[],"mappings":";;;;;AA4EA;WAlE4B,GAAG,EAAE;YAAU,MAAM;gBAAc,OAAO;gBAAc,OAAO;mBAAiB,MAAM;WAkE/D;wBAlEhC;IAAE,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE"}
@@ -5,6 +5,32 @@
5
5
  import Spinner from '../../primitives/Spinner/Spinner.svelte';
6
6
  import { typography } from '../../tokens/typography';
7
7
 
8
+ /**
9
+ * Default labels for all user-visible strings in OrderSummary.
10
+ * Consumers can override any string via the `labels` prop.
11
+ */
12
+ const defaultLabels = {
13
+ orderSummary: 'Order summary',
14
+ selectTickets: 'Select tickets to continue',
15
+ free: 'Free',
16
+ fullPrice: 'Full Price',
17
+ discount: 'Discount',
18
+ subtotal: 'Subtotal',
19
+ fees: 'Fees',
20
+ taxes: 'Taxes',
21
+ giftCardAppliedLabel: 'Gift Card Applied',
22
+ giftCardBalanceAfterOrder: 'Gift card balance after order',
23
+ amountDue: 'Amount Due',
24
+ fullyCoveredByGiftCard: 'Fully covered by gift card',
25
+ total: 'Total',
26
+ placeOrderTos: 'By selecting Place order, I agree to the',
27
+ termsOfService: 'terms of service',
28
+ checkout: 'Checkout',
29
+ ticketSingular: 'ticket',
30
+ ticketPlural: 'tickets',
31
+ closeOrderSummary: 'Close order summary',
32
+ };
33
+
8
34
  let {
9
35
  loading = false,
10
36
  quantities = {},
@@ -27,8 +53,12 @@
27
53
  },
28
54
  onPriceUpdate,
29
55
  giftCardApplied = null, // { code, giftCardAmount, giftCardBalance, stripeAmount, paymentType, requiresStripe }
56
+ /** @type {Partial<typeof defaultLabels>} Override any user-visible string */
57
+ labels: userLabels = {},
30
58
  } = $props();
31
59
 
60
+ let labels = $derived({ ...defaultLabels, ...userLabels });
61
+
32
62
  // Helper to get effective price for a ticket (handles donation tickets)
33
63
  function getEffectivePrice(ticket) {
34
64
  // Donation ticket (type 2): use user-entered donation amount
@@ -156,14 +186,14 @@
156
186
  >
157
187
  <div class="px-5 py-4 border-b border-gray-200 dark:border-gray-600">
158
188
  <h3 class={typography.h3}>
159
- Order summary
189
+ {labels.orderSummary}
160
190
  </h3>
161
191
  </div>
162
192
 
163
193
  <div class="px-5 pb-5">
164
194
  {#if totalQuantity === 0}
165
195
  <div class="py-8 text-center">
166
- <p class="{typography.smMuted}">Select tickets to continue</p>
196
+ <p class="{typography.smMuted}">{labels.selectTickets}</p>
167
197
  </div>
168
198
  {:else}
169
199
  {#each Object.keys(quantities) as key}
@@ -177,7 +207,7 @@
177
207
  <p class="{typography.label}">{ticket.name}</p>
178
208
  <p class="{typography.smMuted}">
179
209
  {#if ticket.price === 0 && !isDonation}
180
- Free x {quantities[key]}
210
+ {labels.free} x {quantities[key]}
181
211
  {:else if isDonation}
182
212
  ${effectivePrice.toFixed(2)} x {quantities[key]}
183
213
  {:else}
@@ -187,7 +217,7 @@
187
217
  </div>
188
218
  <div class="{typography.label}">
189
219
  {#if ticket.price === 0 && !isDonation}
190
- Free
220
+ {labels.free}
191
221
  {:else}
192
222
  ${(effectivePrice * quantities[key]).toFixed(2)}
193
223
  {/if}
@@ -201,35 +231,35 @@
201
231
  <div class="{`${typography.sm} flex flex-col py-3 gap-2`}">
202
232
  {#if promoSavings > 0 || (promoDiscount > 0 && !currentPromoRule?.provideDiscount)}
203
233
  <div class="flex justify-between text-gray-600 dark:text-gray-300">
204
- <span>Full Price</span><span>${subtotalWithoutDiscount.toFixed(2)}</span>
234
+ <span>{labels.fullPrice}</span><span>${subtotalWithoutDiscount.toFixed(2)}</span>
205
235
  </div>
206
236
  {/if}
207
237
  {#if promoSavings > 0}
208
238
  <div class="flex justify-between text-green-600 dark:text-green-500">
209
- <span>Discount</span><span>-${promoSavings.toFixed(2)}</span>
239
+ <span>{labels.discount}</span><span>-${promoSavings.toFixed(2)}</span>
210
240
  </div>
211
241
  {:else if promoDiscount > 0 && !currentPromoRule?.provideDiscount}
212
242
  <div class="flex justify-between text-green-600 dark:text-green-500">
213
- <span>Discount</span><span>-${promoDiscount.toFixed(2)}</span>
243
+ <span>{labels.discount}</span><span>-${promoDiscount.toFixed(2)}</span>
214
244
  </div>
215
245
  {/if}
216
246
  <div class="flex justify-between text-gray-600 dark:text-gray-300">
217
- <span>Subtotal</span><span>${subtotal.toFixed(2)}</span>
247
+ <span>{labels.subtotal}</span><span>${subtotal.toFixed(2)}</span>
218
248
  </div>
219
249
  <div class="flex justify-between text-gray-600 dark:text-gray-300">
220
- <span>Fees</span><span>${fees.toFixed(2)}</span>
250
+ <span>{labels.fees}</span><span>${fees.toFixed(2)}</span>
221
251
  </div>
222
252
  <div class="flex justify-between text-gray-600 dark:text-gray-300">
223
- <span>Taxes</span><span>${taxes.toFixed(2)}</span>
253
+ <span>{labels.taxes}</span><span>${taxes.toFixed(2)}</span>
224
254
  </div>
225
255
  {#if giftCardApplied}
226
256
  <div class="flex justify-between text-green-600 dark:text-green-500">
227
- <span>Gift Card Applied</span>
257
+ <span>{labels.giftCardAppliedLabel}</span>
228
258
  <span>-${giftCardAmountDisplay}</span>
229
259
  </div>
230
260
  {#if giftCardRemainingBalance && parseFloat(giftCardRemainingBalance) > 0}
231
261
  <div class="flex justify-between text-gray-500 dark:text-gray-400 text-xs">
232
- <span>Gift card balance after order</span>
262
+ <span>{labels.giftCardBalanceAfterOrder}</span>
233
263
  <span>${giftCardRemainingBalance}</span>
234
264
  </div>
235
265
  {/if}
@@ -238,22 +268,22 @@
238
268
 
239
269
  {#if giftCardApplied?.paymentType === 'gift_card_only'}
240
270
  <div class="flex justify-between py-4 text-lg border-t border-gray-200 dark:border-gray-600">
241
- <span class="font-semibold text-gray-900 dark:text-white">Amount Due</span>
271
+ <span class="font-semibold text-gray-900 dark:text-white">{labels.amountDue}</span>
242
272
  <span class="font-bold text-green-600 dark:text-green-400">$0.00</span>
243
273
  </div>
244
274
  <p class="text-xs text-gray-500 dark:text-gray-400 text-center -mt-2 mb-2">
245
- Fully covered by gift card
275
+ {labels.fullyCoveredByGiftCard}
246
276
  </p>
247
277
  {:else}
248
278
  <div class="flex justify-between {typography.h3} py-4 text-lg border-t border-gray-200 dark:border-gray-600">
249
- <span>Total</span><span>${total.toFixed(2)}</span>
279
+ <span>{labels.total}</span><span>${total.toFixed(2)}</span>
250
280
  </div>
251
281
  {/if}
252
282
  {/if}
253
283
 
254
284
  {#if totalQuantity > 0 && btnText === 'Place order'}
255
285
  <p class="{typography.xsMuted} text-center mb-3">
256
- By selecting Place order, I agree to the <a href="https://get-micdrop.com/tos" class="text-blue-700 dark:text-blue-500 underline hover:opacity-80" target="_blank" rel="noopener noreferrer">terms of service</a>
286
+ {labels.placeOrderTos} <a href="https://get-micdrop.com/tos" class="text-blue-700 dark:text-blue-500 underline hover:opacity-80" target="_blank" rel="noopener noreferrer">{labels.termsOfService}</a>
257
287
  </p>
258
288
  {/if}
259
289
 
@@ -282,7 +312,7 @@
282
312
  <button
283
313
  class="min-[872px]:hidden fixed inset-0 bg-black/50 z-40 border-none cursor-pointer"
284
314
  onclick={() => (showOrderSummaryOnMobile = false)}
285
- aria-label="Close order summary"
315
+ aria-label={labels.closeOrderSummary}
286
316
  transition:fade={{ duration: 200 }}
287
317
  ></button>
288
318
  <div
@@ -292,12 +322,12 @@
292
322
  >
293
323
  <div class="flex flex-row justify-between items-center px-5 py-4 border-b border-gray-200 dark:border-gray-600">
294
324
  <h2 class="{typography.h2} text-xl">
295
- Order summary
325
+ {labels.orderSummary}
296
326
  </h2>
297
327
  <button
298
328
  onclick={() => (showOrderSummaryOnMobile = false)}
299
329
  class="transition-colors p-2 rounded-lg text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:bg-gray-50 dark:hover:bg-gray-700"
300
- aria-label="Close order summary"
330
+ aria-label={labels.closeOrderSummary}
301
331
  >
302
332
  <CloseOutline class="w-7 h-7" />
303
333
  </button>
@@ -315,7 +345,7 @@
315
345
  <p class="{typography.h5}">{ticket.name}</p>
316
346
  <p class="{typography.smMuted}">
317
347
  {#if ticket.price === 0 && !isDonation}
318
- Free x {quantities[key]}
348
+ {labels.free} x {quantities[key]}
319
349
  {:else if isDonation}
320
350
  ${effectivePrice.toFixed(2)} x {quantities[key]}
321
351
  {:else}
@@ -325,7 +355,7 @@
325
355
  </div>
326
356
  <div class="{typography.h5}">
327
357
  {#if ticket.price === 0 && !isDonation}
328
- Free
358
+ {labels.free}
329
359
  {:else}
330
360
  ${(effectivePrice * quantities[key]).toFixed(2)}
331
361
  {/if}
@@ -339,35 +369,35 @@
339
369
  <div class="flex flex-col py-4 gap-3 text-gray-600 dark:text-gray-300">
340
370
  {#if promoSavings > 0 || (promoDiscount > 0 && !currentPromoRule?.provideDiscount)}
341
371
  <div class="flex justify-between">
342
- <span>Full Price</span><span>${subtotalWithoutDiscount.toFixed(2)}</span>
372
+ <span>{labels.fullPrice}</span><span>${subtotalWithoutDiscount.toFixed(2)}</span>
343
373
  </div>
344
374
  {/if}
345
375
  {#if promoSavings > 0}
346
376
  <div class="flex justify-between text-green-600 dark:text-green-500">
347
- <span>Discount</span><span>-${promoSavings.toFixed(2)}</span>
377
+ <span>{labels.discount}</span><span>-${promoSavings.toFixed(2)}</span>
348
378
  </div>
349
379
  {:else if promoDiscount > 0 && !currentPromoRule?.provideDiscount}
350
380
  <div class="flex justify-between text-green-600 dark:text-green-500">
351
- <span>Discount</span><span>-${promoDiscount.toFixed(2)}</span>
381
+ <span>{labels.discount}</span><span>-${promoDiscount.toFixed(2)}</span>
352
382
  </div>
353
383
  {/if}
354
384
  <div class="flex justify-between">
355
- <span>Subtotal</span><span>${subtotal.toFixed(2)}</span>
385
+ <span>{labels.subtotal}</span><span>${subtotal.toFixed(2)}</span>
356
386
  </div>
357
387
  <div class="flex justify-between">
358
- <span>Fees</span><span>${fees.toFixed(2)}</span>
388
+ <span>{labels.fees}</span><span>${fees.toFixed(2)}</span>
359
389
  </div>
360
390
  <div class="flex justify-between">
361
- <span>Taxes</span><span>${taxes.toFixed(2)}</span>
391
+ <span>{labels.taxes}</span><span>${taxes.toFixed(2)}</span>
362
392
  </div>
363
393
  {#if giftCardApplied}
364
394
  <div class="flex justify-between text-green-600 dark:text-green-500">
365
- <span>Gift Card Applied</span>
395
+ <span>{labels.giftCardAppliedLabel}</span>
366
396
  <span>-${giftCardAmountDisplay}</span>
367
397
  </div>
368
398
  {#if giftCardRemainingBalance && parseFloat(giftCardRemainingBalance) > 0}
369
399
  <div class="flex justify-between text-gray-500 dark:text-gray-400 text-xs">
370
- <span>Gift card balance after order</span>
400
+ <span>{labels.giftCardBalanceAfterOrder}</span>
371
401
  <span>${giftCardRemainingBalance}</span>
372
402
  </div>
373
403
  {/if}
@@ -376,15 +406,15 @@
376
406
 
377
407
  {#if giftCardApplied?.paymentType === 'gift_card_only'}
378
408
  <div class="flex justify-between py-5 border-t border-gray-200 dark:border-gray-600">
379
- <span class="font-semibold text-gray-900 dark:text-white">Amount Due</span>
409
+ <span class="font-semibold text-gray-900 dark:text-white">{labels.amountDue}</span>
380
410
  <span class="font-bold text-green-600 dark:text-green-400">$0.00</span>
381
411
  </div>
382
412
  <p class="text-xs text-gray-500 dark:text-gray-400 text-center -mt-2 mb-2">
383
- Fully covered by gift card
413
+ {labels.fullyCoveredByGiftCard}
384
414
  </p>
385
415
  {:else}
386
416
  <div class="flex justify-between {typography.h3} py-5 border-t border-gray-200 dark:border-gray-600">
387
- <span>Total</span><span>${total.toFixed(2)}</span>
417
+ <span>{labels.total}</span><span>${total.toFixed(2)}</span>
388
418
  </div>
389
419
  {/if}
390
420
  </div>
@@ -399,7 +429,7 @@
399
429
  <div class="flex items-stretch gap-3">
400
430
  <button class="flex flex-col justify-between items-start shrink-0 whitespace-nowrap bg-transparent border-none p-0 cursor-pointer touch-manipulation" onclick={makeOrderSummaryVisible}>
401
431
  <span class="{`${typography.sm} flex items-center gap-1 text-gray-600 dark:text-gray-300`}">
402
- {totalQuantity} {totalQuantity > 1 ? 'tickets' : 'ticket'}
432
+ {totalQuantity} {totalQuantity > 1 ? labels.ticketPlural : labels.ticketSingular}
403
433
  <ChevronDownOutline class={`w-4 h-4 ${typography.iconMuted} transition-transform duration-200 ${showOrderSummaryOnMobile ? 'rotate-180' : ''}`} />
404
434
  </span>
405
435
  <span class="{typography.h2} text-xl">${total.toFixed(2)}</span>
@@ -419,7 +449,7 @@
419
449
  {#if loading}
420
450
  <Spinner size="sm" color="white" />
421
451
  {:else}
422
- <span translate="no">Checkout</span>
452
+ <span translate="no">{labels.checkout}</span>
423
453
  {/if}
424
454
  </button>
425
455
  </div>
@@ -19,6 +19,7 @@ declare const OrderSummary: import("svelte").Component<{
19
19
  venueServiceCharge?: Record<string, any>;
20
20
  onPriceUpdate: any;
21
21
  giftCardApplied?: any;
22
+ labels?: Record<string, any>;
22
23
  }, {}, "">;
23
24
  type $$ComponentProps = {
24
25
  loading?: boolean;
@@ -36,5 +37,6 @@ type $$ComponentProps = {
36
37
  venueServiceCharge?: Record<string, any>;
37
38
  onPriceUpdate: any;
38
39
  giftCardApplied?: any;
40
+ labels?: Record<string, any>;
39
41
  };
40
42
  //# sourceMappingURL=OrderSummary.svelte.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"OrderSummary.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/calendar/OrderSummary/OrderSummary.svelte.js"],"names":[],"mappings":";;;;;AAgZA;cAhY+B,OAAO;iBAAe,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;sBAAoB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;mBAAiB,GAAG,EAAE;qBAAmB,GAAG;eAAa,OAAO;cAAY,MAAM;mBAAiB,OAAO;oBAAkB,MAAM;uBAAqB,GAAG;sBAAoB,GAAG;eAAa,GAAG;yBAAuB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;mBAAiB,GAAG;sBAAoB,GAAG;WAgY1U;wBAhYxC;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAAC,YAAY,CAAC,EAAE,GAAG,EAAE,CAAC;IAAC,cAAc,CAAC,EAAE,GAAG,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,GAAG,CAAC;IAAC,eAAe,CAAC,EAAE,GAAG,CAAC;IAAC,QAAQ,CAAC,EAAE,GAAG,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAAC,aAAa,EAAE,GAAG,CAAC;IAAC,eAAe,CAAC,EAAE,GAAG,CAAA;CAAE"}
1
+ {"version":3,"file":"OrderSummary.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/calendar/OrderSummary/OrderSummary.svelte.js"],"names":[],"mappings":";;;;;AAobA;cA1Y+B,OAAO;iBAAe,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;sBAAoB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;mBAAiB,GAAG,EAAE;qBAAmB,GAAG;eAAa,OAAO;cAAY,MAAM;mBAAiB,OAAO;oBAAkB,MAAM;uBAAqB,GAAG;sBAAoB,GAAG;eAAa,GAAG;yBAAuB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;mBAAiB,GAAG;sBAAoB,GAAG;aAAW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;WA0YxW;wBA1YxC;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAAC,YAAY,CAAC,EAAE,GAAG,EAAE,CAAC;IAAC,cAAc,CAAC,EAAE,GAAG,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,GAAG,CAAC;IAAC,eAAe,CAAC,EAAE,GAAG,CAAC;IAAC,QAAQ,CAAC,EAAE,GAAG,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAAC,aAAa,EAAE,GAAG,CAAC;IAAC,eAAe,CAAC,EAAE,GAAG,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAAE"}
@@ -1,4 +1,4 @@
1
- import { render, screen } from '@testing-library/svelte';
1
+ import { render } from '@testing-library/svelte';
2
2
  import { expect, describe, test } from 'vitest';
3
3
  import Stack from './Stack.svelte';
4
4
  describe('Stack Component', () => {
@@ -1,6 +1,6 @@
1
1
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
2
  import { formatCleanTimeRange, formatDateRange, formatDayOfWeek, formatEventDate, formatEventDateTime, formatEventTime, formatHour, formatMonth, formatNotificationTime, formatRelativeTime, formatTimeRange, getDateInTimezone, getDateParts, getHourInTimezone, isToday, } from '../format';
3
- import { DateTimeError, DateTimeErrorCode } from '../types';
3
+ import { DateTimeError } from '../types';
4
4
  describe('format utilities', () => {
5
5
  describe('formatEventTime', () => {
6
6
  it('formats time in specified timezone', () => {
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
  import { combineDateAndTime, formatDateTimeForAPI, isNextDayTime, minutesToTimeString, parseDateTimeFromAPI, parseEndOfDay, parseLocalToUTC, parseStartOfDay, parseTimeToMinutes, parseUTCToLocal, stripNextDayPrefix, } from '../parse';
3
- import { DateTimeError, DateTimeErrorCode } from '../types';
3
+ import { DateTimeError } from '../types';
4
4
  describe('parse utilities', () => {
5
5
  describe('parseLocalToUTC', () => {
6
6
  it('converts local datetime to UTC', () => {
@@ -1,4 +1,4 @@
1
- import { beforeEach, describe, expect, it, vi } from 'vitest';
1
+ import { describe, expect, it } from 'vitest';
2
2
  import { getTimezoneDisplayName, getTimezoneOffset, getUserTimezone, getVenueTimezone, isDST, isValidTimezone, normalizeTimezone, getIANATimezone, isValidIANATimezone, getAllTimezones, formatTimezoneForDisplay, getTimezoneOptions, getCommonUSTimezoneOptions, } from '../timezone';
3
3
  import { DateTimeError, DateTimeErrorCode } from '../types';
4
4
  describe('timezone utilities', () => {
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * @module datetime/parse
8
8
  */
9
- import { format, parse } from 'date-fns';
9
+ import { format } from 'date-fns';
10
10
  import { fromZonedTime, toZonedTime } from 'date-fns-tz';
11
11
  import { DATE_FORMATS } from './constants';
12
12
  import { isValidTimezone } from './timezone';
@@ -7,7 +7,6 @@
7
7
  * - UI states (loading, saving, saved)
8
8
  * - Section-level validation for progressive forms
9
9
  */
10
- import { z } from 'zod';
11
10
  // ============================================================================
12
11
  // Implementation
13
12
  // ============================================================================
@@ -5,6 +5,23 @@
5
5
  import { typography } from '../../tokens/typography';
6
6
  import { createImage, supportsWebP } from '../../utils/imageOptimizer';
7
7
 
8
+ /**
9
+ * Default labels for user-visible strings in CropImage.
10
+ * Consumers can override via the `labels` prop.
11
+ */
12
+ const defaultLabels = {
13
+ cropImageTitle: 'Crop image',
14
+ loading: 'Loading...',
15
+ dragToPosition: 'Drag to position. Pinch or use slider to zoom.',
16
+ cancel: 'Cancel',
17
+ uploading: 'Uploading...',
18
+ save: 'Save',
19
+ closeModal: 'Close modal',
20
+ zoomOut: 'Zoom out',
21
+ zoomIn: 'Zoom in',
22
+ zoomLevel: 'Zoom level',
23
+ };
24
+
8
25
  interface Props {
9
26
  /** Whether to show the modal */
10
27
  showModal?: boolean;
@@ -16,6 +33,8 @@
16
33
  onCancel?: () => void;
17
34
  /** Whether image is currently uploading */
18
35
  isUploadingImage?: boolean;
36
+ /** Override user-visible strings */
37
+ labels?: Partial<typeof defaultLabels>;
19
38
  }
20
39
 
21
40
  let {
@@ -23,9 +42,12 @@
23
42
  imageSrc = $bindable(''),
24
43
  onSave = () => {},
25
44
  onCancel = () => {},
26
- isUploadingImage = false
45
+ isUploadingImage = false,
46
+ labels: userLabels = {},
27
47
  }: Props = $props();
28
48
 
49
+ let labels = $derived({ ...defaultLabels, ...userLabels });
50
+
29
51
  let crop = $state({ x: 0, y: 0 });
30
52
  let zoom = $state(1);
31
53
  let croppedAreaPixels = $state<{ x: number; y: number; width: number; height: number } | null>(null);
@@ -120,13 +142,13 @@
120
142
  <div class="relative bg-white rounded-lg shadow-xl dark:bg-gray-800">
121
143
  <div class="flex items-center justify-between p-4 border-b border-gray-200 rounded-t-lg dark:border-gray-600">
122
144
  <h3 class={typography.h2}>
123
- Crop image
145
+ {labels.cropImageTitle}
124
146
  </h3>
125
147
  <Button
126
148
  variant="icon"
127
149
  size="sm"
128
150
  onclick={closeModal}
129
- aria-label="Close modal"
151
+ aria-label={labels.closeModal}
130
152
  >
131
153
  <CloseOutline class="w-3 h-3" />
132
154
  </Button>
@@ -136,7 +158,7 @@
136
158
  <div class="relative w-full aspect-square sm:aspect-[4/3] max-h-80 sm:max-h-96 bg-gray-800 rounded-lg overflow-hidden">
137
159
  {#if isLoading}
138
160
  <div class="absolute inset-0 flex items-center justify-center bg-gray-200 dark:bg-gray-700 z-10">
139
- <span class={typography.smMuted}>Loading...</span>
161
+ <span class={typography.smMuted}>{labels.loading}</span>
140
162
  </div>
141
163
  {/if}
142
164
  <Cropper
@@ -152,7 +174,7 @@
152
174
  </div>
153
175
 
154
176
  <p class={`${typography.smMuted} text-center`}>
155
- Drag to position. Pinch or use slider to zoom.
177
+ {labels.dragToPosition}
156
178
  </p>
157
179
 
158
180
  <div class="flex items-center justify-center gap-3 max-w-xs mx-auto">
@@ -161,7 +183,7 @@
161
183
  size="sm"
162
184
  class="rounded-full! w-9! h-9! p-0! shrink-0"
163
185
  onclick={() => (zoom = Math.max(1, zoom - 0.2))}
164
- aria-label="Zoom out"
186
+ aria-label={labels.zoomOut}
165
187
  >
166
188
  <MinusOutline class="w-4 h-4" />
167
189
  </Button>
@@ -173,7 +195,7 @@
173
195
  step="0.1"
174
196
  bind:value={zoom}
175
197
  class="flex-1 w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700 accent-blue-600"
176
- aria-label="Zoom level"
198
+ aria-label={labels.zoomLevel}
177
199
  />
178
200
 
179
201
  <Button
@@ -181,7 +203,7 @@
181
203
  size="sm"
182
204
  class="rounded-full! w-9! h-9! p-0! shrink-0"
183
205
  onclick={() => (zoom = Math.min(3, zoom + 0.2))}
184
- aria-label="Zoom in"
206
+ aria-label={labels.zoomIn}
185
207
  >
186
208
  <PlusOutline class="w-4 h-4" />
187
209
  </Button>
@@ -197,7 +219,7 @@
197
219
  onclick={closeModal}
198
220
  disabled={isSaving || isUploadingImage}
199
221
  >
200
- Cancel
222
+ {labels.cancel}
201
223
  </Button>
202
224
  <Button
203
225
  type="button"
@@ -207,9 +229,9 @@
207
229
  disabled={isLoading || isSaving || isUploadingImage}
208
230
  >
209
231
  {#if isSaving || isUploadingImage}
210
- Uploading...
232
+ {labels.uploading}
211
233
  {:else}
212
- Save
234
+ {labels.save}
213
235
  {/if}
214
236
  </Button>
215
237
  </div>
@@ -1,4 +1,4 @@
1
- interface Props {
1
+ declare const CropImage: import("svelte").Component<{
2
2
  /** Whether to show the modal */
3
3
  showModal?: boolean;
4
4
  /** Image source to crop */
@@ -9,8 +9,20 @@ interface Props {
9
9
  onCancel?: () => void;
10
10
  /** Whether image is currently uploading */
11
11
  isUploadingImage?: boolean;
12
- }
13
- declare const CropImage: import("svelte").Component<Props, {}, "showModal" | "imageSrc">;
12
+ /** Override user-visible strings */
13
+ labels?: Partial<{
14
+ cropImageTitle: string;
15
+ loading: string;
16
+ dragToPosition: string;
17
+ cancel: string;
18
+ uploading: string;
19
+ save: string;
20
+ closeModal: string;
21
+ zoomOut: string;
22
+ zoomIn: string;
23
+ zoomLevel: string;
24
+ }>;
25
+ }, {}, "showModal" | "imageSrc">;
14
26
  type CropImage = ReturnType<typeof CropImage>;
15
27
  export default CropImage;
16
28
  //# sourceMappingURL=CropImage.svelte.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CropImage.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/recipes/CropImage/CropImage.svelte.ts"],"names":[],"mappings":"AAUE,UAAU,KAAK;IACb,gCAAgC;IAChC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,IAAI,KAAK,IAAI,CAAC;IACtC,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,2CAA2C;IAC3C,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AA6JH,QAAA,MAAM,SAAS,iEAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"CropImage.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/recipes/CropImage/CropImage.svelte.ts"],"names":[],"mappings":"AA2MA,QAAA,MAAM,SAAS;IAzKX,gCAAgC;gBACpB,OAAO;IACnB,2BAA2B;eAChB,MAAM;IACjB,uDAAuD;aAC9C,CAAC,YAAY,EAAE,IAAI,KAAK,IAAI;IACrC,sCAAsC;eAC3B,MAAM,IAAI;IACrB,2CAA2C;uBACxB,OAAO;IAC1B,oCAAoC;aAC3B,OAAO;;;;;;;;;;;MAAsB;gCA8Ja,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}