@suiteop/storefront 0.5.0 → 0.6.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 (49) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +4 -2
  3. package/dist/astro-content-model.cjs +3 -3
  4. package/dist/astro-content-model.js +2 -2
  5. package/dist/astro.cjs +1 -1
  6. package/dist/astro.d.cts +66 -1
  7. package/dist/astro.d.ts +66 -1
  8. package/dist/astro.js +1 -1
  9. package/dist/{availability-Dh0yLSkj.d.cts → availability.d-Cla9GuGc.d.cts} +8 -8
  10. package/dist/{availability-Dh0yLSkj.d.ts → availability.d-Cla9GuGc.d.ts} +8 -8
  11. package/dist/checkout.d.cts +11 -0
  12. package/dist/checkout.d.ts +11 -0
  13. package/dist/{chunk-IUNIQSFB.js → chunk-3B6ZYRYF.js} +1 -1
  14. package/dist/chunk-3NE27PHL.cjs +19 -0
  15. package/dist/chunk-JF245QUY.cjs +9 -0
  16. package/dist/{chunk-NNWJZUQL.cjs → chunk-OXCLLFCY.cjs} +2 -2
  17. package/dist/chunk-QBHOJGZI.cjs +21 -0
  18. package/dist/chunk-UQWQPTHO.js +3 -0
  19. package/dist/chunk-XOCFEVP4.js +6 -0
  20. package/dist/chunk-YIYGBTAM.js +9 -0
  21. package/dist/{client-C9Igm7O-.d.ts → client-CX8K7JNt.d.cts} +65 -11
  22. package/dist/{client-2KyVv-2l.d.cts → client-s-lEwqzc.d.ts} +65 -11
  23. package/dist/components.d.cts +43 -1
  24. package/dist/components.d.ts +43 -1
  25. package/dist/config.cjs +3 -3
  26. package/dist/config.d.cts +78 -74
  27. package/dist/config.d.ts +78 -74
  28. package/dist/config.js +2 -2
  29. package/dist/content.cjs +9 -9
  30. package/dist/content.d.cts +53 -9
  31. package/dist/content.d.ts +53 -9
  32. package/dist/content.js +2 -2
  33. package/dist/{errors-DpImb0Uf.d.cts → errors-Oax7djdp.d.ts} +54 -13
  34. package/dist/{errors-BGgJ--XR.d.ts → errors-welPvrD6.d.cts} +54 -13
  35. package/dist/index.cjs +12 -12
  36. package/dist/index.d.cts +27 -8
  37. package/dist/index.d.ts +27 -8
  38. package/dist/index.js +3 -3
  39. package/dist/react.cjs +4 -4
  40. package/dist/react.d.cts +24 -3
  41. package/dist/react.d.ts +24 -3
  42. package/dist/react.js +3 -3
  43. package/package.json +1 -1
  44. package/dist/chunk-5TUJX6GY.js +0 -5
  45. package/dist/chunk-LY73ZYN5.cjs +0 -20
  46. package/dist/chunk-NZWYOV5Y.cjs +0 -19
  47. package/dist/chunk-PYVUDQSQ.js +0 -3
  48. package/dist/chunk-YSKWSL2F.js +0 -9
  49. package/dist/chunk-ZLAOY6IF.cjs +0 -9
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { e as StorefrontStay, a as StorefrontBuildingAvailabilityQuery, g as StorefrontUnitAvailability, S as StorefrontAvailability, d as StorefrontCalendarQuery, b as StorefrontCalendar } from './availability-Dh0yLSkj.cjs';
2
+ import { e as StorefrontStay, a as StorefrontBuildingAvailabilityQuery, g as StorefrontUnitAvailability, S as StorefrontAvailability, d as StorefrontCalendarQuery, b as StorefrontCalendar } from './availability.d-Cla9GuGc.js';
3
3
 
4
4
  declare const storefrontGuestInputSchema: z.ZodObject<{
5
5
  firstName: z.ZodString;
@@ -27,13 +27,13 @@ type ConfirmCheckoutSessionInput = z.infer<typeof confirmCheckoutSessionInputSch
27
27
  declare const bookingResultSchema: z.ZodObject<{
28
28
  bookingRequestId: z.ZodUUID;
29
29
  confirmationToken: z.ZodString;
30
- status: z.ZodType<"inquiry" | "processing" | "confirmed" | "failed" | "expired" | "pending_pms_sync" | "pending_payment" | "authorized" | "reserved" | "cancelled" | (string & {}), unknown, z.core.$ZodTypeInternals<"inquiry" | "processing" | "confirmed" | "failed" | "expired" | "pending_pms_sync" | "pending_payment" | "authorized" | "reserved" | "cancelled" | (string & {}), unknown>>;
30
+ status: z.ZodType<"authorized" | "cancelled" | "confirmed" | "expired" | "failed" | "inquiry" | "pending_payment" | "pending_pms_sync" | "processing" | "reserved" | (string & {}), unknown, z.core.$ZodTypeInternals<"authorized" | "cancelled" | "confirmed" | "expired" | "failed" | "inquiry" | "pending_payment" | "pending_pms_sync" | "processing" | "reserved" | (string & {}), unknown>>;
31
31
  confirmationCode: z.ZodNullable<z.ZodString>;
32
32
  }, z.core.$strip>;
33
33
  type BookingResult = z.infer<typeof bookingResultSchema>;
34
34
  declare const storefrontBookingSchema: z.ZodObject<{
35
35
  id: z.ZodUUID;
36
- status: z.ZodType<"inquiry" | "processing" | "confirmed" | "failed" | "expired" | "pending_pms_sync" | "pending_payment" | "authorized" | "reserved" | "cancelled" | (string & {}), unknown, z.core.$ZodTypeInternals<"inquiry" | "processing" | "confirmed" | "failed" | "expired" | "pending_pms_sync" | "pending_payment" | "authorized" | "reserved" | "cancelled" | (string & {}), unknown>>;
36
+ status: z.ZodType<"authorized" | "cancelled" | "confirmed" | "expired" | "failed" | "inquiry" | "pending_payment" | "pending_pms_sync" | "processing" | "reserved" | (string & {}), unknown, z.core.$ZodTypeInternals<"authorized" | "cancelled" | "confirmed" | "expired" | "failed" | "inquiry" | "pending_payment" | "pending_pms_sync" | "processing" | "reserved" | (string & {}), unknown>>;
37
37
  propertyId: z.ZodNullable<z.ZodUUID>;
38
38
  checkIn: z.ZodNullable<z.ZodISODate>;
39
39
  checkOut: z.ZodNullable<z.ZodISODate>;
@@ -123,7 +123,7 @@ declare const storefrontListingSchema: z.ZodObject<{
123
123
  countryCode: z.ZodOptional<z.ZodNullable<z.ZodString>>;
124
124
  }, z.core.$strip>;
125
125
  type StorefrontListing = z.infer<typeof storefrontListingSchema>;
126
- declare const STOREFRONT_LISTING_SORTS: readonly ["recommended", "price_asc", "price_desc", "rating"];
126
+ declare const STOREFRONT_LISTING_SORTS: readonly ['recommended', 'price_asc', 'price_desc', 'rating'];
127
127
  type StorefrontListingSort = (typeof STOREFRONT_LISTING_SORTS)[number];
128
128
  interface StorefrontListingsQuery {
129
129
  location?: string | readonly string[];
@@ -135,6 +135,8 @@ interface StorefrontListingsQuery {
135
135
  priceMax?: number;
136
136
  amenities?: readonly string[];
137
137
  bounds?: readonly [number, number, number, number] | string;
138
+ checkIn?: string;
139
+ checkOut?: string;
138
140
  sort?: StorefrontListingSort;
139
141
  facets?: boolean;
140
142
  limit?: number;
@@ -284,7 +286,7 @@ declare const createCheckoutSessionInputSchema: z.ZodObject<{
284
286
  wbraid: string | null;
285
287
  fbclid: string | null;
286
288
  msclkid: string | null;
287
- paidClick: "google" | "microsoft" | "meta" | null;
289
+ paidClick: "google" | "meta" | "microsoft" | null;
288
290
  } | null;
289
291
  last: {
290
292
  ts: string;
@@ -300,7 +302,7 @@ declare const createCheckoutSessionInputSchema: z.ZodObject<{
300
302
  wbraid: string | null;
301
303
  fbclid: string | null;
302
304
  msclkid: string | null;
303
- paidClick: "google" | "microsoft" | "meta" | null;
305
+ paidClick: "google" | "meta" | "microsoft" | null;
304
306
  } | null;
305
307
  ids: {
306
308
  gaClientId: string | null;
@@ -312,7 +314,7 @@ declare const createCheckoutSessionInputSchema: z.ZodObject<{
312
314
  analytics: boolean;
313
315
  ads: boolean;
314
316
  source: "default" | "user";
315
- region: "restricted" | "other";
317
+ region: "other" | "restricted";
316
318
  decidedAt: string | null;
317
319
  };
318
320
  experiment?: {
@@ -334,7 +336,7 @@ declare const createCheckoutSessionInputSchema: z.ZodObject<{
334
336
  wbraid: string | null;
335
337
  fbclid: string | null;
336
338
  msclkid: string | null;
337
- paidClick: "google" | "microsoft" | "meta" | null;
339
+ paidClick: "google" | "meta" | "microsoft" | null;
338
340
  } | null;
339
341
  last: {
340
342
  ts: string;
@@ -350,7 +352,7 @@ declare const createCheckoutSessionInputSchema: z.ZodObject<{
350
352
  wbraid: string | null;
351
353
  fbclid: string | null;
352
354
  msclkid: string | null;
353
- paidClick: "google" | "microsoft" | "meta" | null;
355
+ paidClick: "google" | "meta" | "microsoft" | null;
354
356
  } | null;
355
357
  ids: {
356
358
  gaClientId: string | null;
@@ -362,7 +364,7 @@ declare const createCheckoutSessionInputSchema: z.ZodObject<{
362
364
  analytics: boolean;
363
365
  ads: boolean;
364
366
  source: "default" | "user";
365
- region: "restricted" | "other";
367
+ region: "other" | "restricted";
366
368
  decidedAt: string | null;
367
369
  };
368
370
  experiment?: {
@@ -382,7 +384,7 @@ declare const createCheckoutSessionInputSchema: z.ZodObject<{
382
384
  type CreateCheckoutSessionInput = z.infer<typeof createCheckoutSessionInputSchema>;
383
385
  declare const checkoutSessionSchema: z.ZodObject<{
384
386
  id: z.ZodUUID;
385
- status: z.ZodType<"inquiry" | "processing" | "confirmed" | "failed" | "expired" | "pending_pms_sync" | "pending_payment" | "authorized" | "reserved" | "cancelled" | (string & {}), unknown, z.core.$ZodTypeInternals<"inquiry" | "processing" | "confirmed" | "failed" | "expired" | "pending_pms_sync" | "pending_payment" | "authorized" | "reserved" | "cancelled" | (string & {}), unknown>>;
387
+ status: z.ZodType<"authorized" | "cancelled" | "confirmed" | "expired" | "failed" | "inquiry" | "pending_payment" | "pending_pms_sync" | "processing" | "reserved" | (string & {}), unknown, z.core.$ZodTypeInternals<"authorized" | "cancelled" | "confirmed" | "expired" | "failed" | "inquiry" | "pending_payment" | "pending_pms_sync" | "processing" | "reserved" | (string & {}), unknown>>;
386
388
  quote: z.ZodObject<{
387
389
  listingId: z.ZodUUID;
388
390
  checkIn: z.ZodISODate;
@@ -557,18 +559,33 @@ type StorefrontQuote = z.infer<typeof storefrontQuoteSchema>;
557
559
  declare const STOREFRONT_API_PATH = "/api/storefront/v1";
558
560
  interface StorefrontClientOptions {
559
561
  publishableKey: string;
562
+ /**
563
+ * `'same-origin'` → `/api/storefront/v1` on the page's origin (SuiteOp-hosted sites, via the
564
+ * storefront edge). A URL → that origin (a `WrongRegionError.baseUrl` works as is). Omitted →
565
+ * the key's regional host: `https://api-<region>.suiteop.com` for `pk_live_`, the region's
566
+ * staging host for `pk_test_`.
567
+ */
560
568
  baseUrl?: 'same-origin' | (string & {});
569
+ /** Per-request timeout. Default 10 s for reads, 20 s for quotes and checkout. */
561
570
  timeoutMs?: number;
562
571
  fetch?: typeof fetch;
572
+ /** Sent as `Accept-Language`, so API-side copy (cancellation policy text) localises. */
563
573
  locale?: string;
564
574
  }
565
575
  interface RequestOptions {
576
+ /** Aborting rejects the call with the signal's reason (an `AbortError`). */
566
577
  signal?: AbortSignal;
567
578
  }
568
579
  interface CreateCheckoutSessionOptions extends RequestOptions {
580
+ /**
581
+ * Omitted → one UUID v4 per quoteRef + ratePlanId, reused by every retry on this client until
582
+ * the outcome is final (a dead session or a definitive refusal releases it).
583
+ */
569
584
  idempotencyKey?: string;
570
585
  }
586
+ /** `collections.list` paging. */
571
587
  interface ContentListQuery {
588
+ /** 1–100, default 20. */
572
589
  limit?: number;
573
590
  offset?: number;
574
591
  }
@@ -578,17 +595,25 @@ interface Page<T> {
578
595
  limit: number;
579
596
  offset: number;
580
597
  }
598
+ /** The session plus the Idempotency-Key it was created with — `<suiteop-checkout>` replays both. */
581
599
  type CreatedCheckoutSession = CheckoutSession & {
582
600
  idempotencyKey: string;
583
601
  };
602
+ /** `POST /checkout-sessions/:id/confirm` body as sent (consents and language are optional). */
584
603
  type ConfirmCheckoutSessionRequest = z.input<typeof confirmCheckoutSessionInputSchema>;
585
604
  interface StorefrontClient {
605
+ /** The publishable key this client sends (public by design). */
586
606
  readonly publishableKey: string;
607
+ /** The resolved Storefront API base, ending in `/api/storefront/v1`. */
587
608
  readonly baseUrl: string;
588
609
  site: {
589
610
  get(opts?: RequestOptions): Promise<StorefrontSite>;
590
611
  };
591
612
  listings: {
613
+ /**
614
+ * The site's listings, filtered and sorted. `facets: true` adds the filters sheet's
615
+ * `facets` (one more query on the API).
616
+ */
592
617
  list(query?: StorefrontListingsQuery, opts?: RequestOptions): Promise<Page<StorefrontListingSummary> & {
593
618
  facets?: StorefrontListingFacets;
594
619
  }>;
@@ -597,22 +622,40 @@ interface StorefrontClient {
597
622
  buildings: {
598
623
  list(opts?: RequestOptions): Promise<StorefrontBuilding[]>;
599
624
  get(id: string, opts?: RequestOptions): Promise<StorefrontBuilding>;
625
+ /**
626
+ * Every unit of the building for one stay — status, stay total and the next free window of the
627
+ * same length — in one call. Display only: read from the synced calendar, and the total is the
628
+ * nightly rates plus the cleaning fee, before taxes. `quotes.create` gives the bookable price.
629
+ * Pages like `listings.list` (`limit` 1–100, default 50).
630
+ */
600
631
  availability(id: string, query: StorefrontStay & Partial<Pick<StorefrontBuildingAvailabilityQuery, 'limit' | 'offset'>>, opts?: RequestOptions): Promise<Page<StorefrontUnitAvailability>>;
601
632
  };
602
633
  locations: {
603
634
  list(opts?: RequestOptions): Promise<StorefrontLocation[]>;
604
635
  };
636
+ /**
637
+ * "Things to do": the guest-portal guide lists the manager shows on booking sites, with their
638
+ * places, in the client's `locale` (English fallback). Lists with no place are left out.
639
+ */
605
640
  guides: {
606
641
  list(opts?: RequestOptions): Promise<StorefrontGuide[]>;
642
+ /** By id; null when the site does not show that list. */
607
643
  get(id: string, opts?: RequestOptions): Promise<StorefrontGuide | null>;
608
644
  };
645
+ /** The site's content model as its code declared it (hidden types and fields left out). */
609
646
  contentModel: {
610
647
  get(opts?: RequestOptions): Promise<StorefrontContentModel>;
611
648
  };
649
+ /**
650
+ * Items of a collection the site declares (`defineContent`): published ones only, dated up to
651
+ * now, in the collection's order. `createContentReader` gives the typed version.
652
+ */
612
653
  collections: {
613
654
  list(key: string, query?: ContentListQuery, opts?: RequestOptions): Promise<Page<StorefrontContentItem>>;
655
+ /** By slug or id; null when there is none published (a draft, a future post, a typo). */
614
656
  get(key: string, slugOrId: string, opts?: RequestOptions): Promise<StorefrontContentItem | null>;
615
657
  };
658
+ /** A page section's one item. A section nobody filled in yet has `fields: {}`. */
616
659
  sections: {
617
660
  get(key: string, opts?: RequestOptions): Promise<StorefrontContentItem>;
618
661
  };
@@ -634,7 +677,17 @@ interface StorefrontClient {
634
677
  checkoutSessions: {
635
678
  create(input: CreateCheckoutSessionInput, opts?: CreateCheckoutSessionOptions): Promise<CreatedCheckoutSession>;
636
679
  get(id: string, opts?: RequestOptions): Promise<CheckoutSession>;
680
+ /**
681
+ * Drop the kept Idempotency-Key for this quote + rate plan; the next `create` opens a new
682
+ * session and a new payment hold. Never call it after a `failed` session or booking result:
683
+ * the guest may already have been charged, and a new session would take a second payment.
684
+ */
637
685
  forget(quoteRef: string, ratePlanId?: string): void;
686
+ /**
687
+ * Idempotent on the session: a double submit or a second tab gets the same booking. A
688
+ * confirm error that ends the session (`session_expired`, or `requiresNewSession`) releases
689
+ * the quote's key, so the next `create` opens a new session. A `failed` result does not.
690
+ */
638
691
  confirm(id: string, input: ConfirmCheckoutSessionRequest, opts?: RequestOptions): Promise<BookingResult>;
639
692
  };
640
693
  bookings: {
@@ -644,6 +697,7 @@ interface StorefrontClient {
644
697
  create(input: StorefrontContactInput, opts?: RequestOptions): Promise<void>;
645
698
  };
646
699
  }
700
+ /** A typed client for one site's Storefront API, bound to its publishable key. */
647
701
  declare function createStorefrontClient(options: StorefrontClientOptions): StorefrontClient;
648
702
 
649
703
  export { type StorefrontQuoteInput as A, type BookingResult as B, type CheckoutMountDescriptor as C, type StorefrontRatePlanQuote as D, type StorefrontReview as E, type StorefrontReviewsQuery as F, type StorefrontSite as G, createStorefrontClient as H, type Page as P, type RequestOptions as R, STOREFRONT_API_PATH as S, type CheckoutSession as a, type ConfirmCheckoutSessionInput as b, type ConfirmCheckoutSessionRequest as c, type ContentListQuery as d, type CreateCheckoutSessionInput as e, type CreateCheckoutSessionOptions as f, type CreatedCheckoutSession as g, type StorefrontBooking as h, type StorefrontBuilding as i, type StorefrontClient as j, type StorefrontClientOptions as k, type StorefrontContactInput as l, type StorefrontContentItem as m, type StorefrontContentModel as n, type StorefrontContentRef as o, type StorefrontGuestInput as p, type StorefrontGuide as q, type StorefrontGuideItem as r, type StorefrontImage as s, type StorefrontListing as t, type StorefrontListingFacets as u, type StorefrontListingSort as v, type StorefrontListingSummary as w, type StorefrontListingsQuery as x, type StorefrontLocation as y, type StorefrontQuote as z };
@@ -1,11 +1,17 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
- import { c as StorefrontCalendarDay } from './availability-Dh0yLSkj.cjs';
3
+ import { c as StorefrontCalendarDay } from './availability.d-Cla9GuGc.cjs';
4
4
  import 'zod';
5
5
 
6
+ /**
7
+ * The components' English defaults. The SDK ships no other copy: pass `labels` (any subset)
8
+ * with your site's own translations.
9
+ */
6
10
  declare const defaultLabels: {
7
11
  dateRangePicker: {
12
+ /** Grid label; `monthStart` is the month's first day, YYYY-MM-DD. */
8
13
  month: (monthStart: string) => string;
14
+ /** Column header; 0 = Sunday. */
9
15
  weekday: (dayIndex: number) => string;
10
16
  day: (date: string) => string;
11
17
  previousMonth: string;
@@ -19,6 +25,7 @@ declare const defaultLabels: {
19
25
  };
20
26
  gallery: {
21
27
  region: string;
28
+ /** Fallback alt text and slide label; `index` is zero-based. */
22
29
  photo: (index: number, total: number) => string;
23
30
  previous: string;
24
31
  next: string;
@@ -28,6 +35,7 @@ type DateRangePickerLabels = typeof defaultLabels.dateRangePicker;
28
35
  type GuestPickerLabels = typeof defaultLabels.guestPicker;
29
36
  type GalleryLabels = typeof defaultLabels.gallery;
30
37
 
38
+ /** Listing-local dates, YYYY-MM-DD. `checkOut` null while the guest is picking it. */
31
39
  interface DateRangeValue {
32
40
  checkIn: string | null;
33
41
  checkOut: string | null;
@@ -36,16 +44,27 @@ type Slot$2 = 'header' | 'title' | 'nav' | 'grid' | 'weekday' | 'day';
36
44
  interface DateRangePickerProps {
37
45
  value: DateRangeValue;
38
46
  onChange(value: DateRangeValue): void;
47
+ /** Nights that cannot be booked (see `unavailableDates`); checking out on one is allowed. */
39
48
  unavailable?: Iterable<string>;
49
+ /** Minimum nights for the stay. Default 1. */
40
50
  minNights?: number;
51
+ /** Earlier days are disabled. Default: the browser's local date. */
41
52
  today?: string;
53
+ /** Month shown first, YYYY-MM. Default: the check-in's month, else today's. */
42
54
  defaultMonth?: string;
55
+ /** 0 = Sunday (default), 1 = Monday. */
43
56
  weekStartsOn?: 0 | 1;
44
57
  labels?: Partial<DateRangePickerLabels>;
45
58
  className?: string;
46
59
  classNames?: Partial<Record<Slot$2, string>>;
47
60
  }
61
+ /** The nights a `calendar.get` answer marks as not bookable. */
48
62
  declare function unavailableDates(days: readonly Pick<StorefrontCalendarDay, 'date' | 'status'>[]): string[];
63
+ /**
64
+ * A controlled, unstyled stay picker: one month grid (`role="grid"`), arrow keys move by day
65
+ * and week, Enter / Space / click pick the check-in then the check-out. Each day carries
66
+ * `data-state` = `start` | `end` | `in-range` | `disabled` | `available`.
67
+ */
49
68
  declare function DateRangePicker({ value, onChange, unavailable, minNights, today: todayProp, defaultMonth, weekStartsOn, labels: labelsProp, className, classNames, }: DateRangePickerProps): react.JSX.Element;
50
69
 
51
70
  interface GalleryPhoto {
@@ -57,13 +76,29 @@ interface GalleryPhoto {
57
76
  type Slot$1 = 'viewport' | 'slide' | 'image' | 'button';
58
77
  interface GalleryProps {
59
78
  photos: readonly GalleryPhoto[];
79
+ /** Called with the zero-based index of the photo now shown. */
60
80
  onIndexChange?(index: number): void;
61
81
  labels?: Partial<GalleryLabels>;
82
+ /** The slide's rendered width, for the browser to pick a size (`<img sizes>`). */
62
83
  sizes?: string;
63
84
  className?: string;
64
85
  classNames?: Partial<Record<Slot$1, string>>;
65
86
  }
87
+ /**
88
+ * A listing's photos for `Gallery`. Pass the listing: its `images` (the photos as SuiteOp hosts
89
+ * them) come first; with none — not copied yet, or an API revision without them — its `pictures`.
90
+ *
91
+ * `StorefrontListing.pictures` is the PMS's own photo array, passed through untyped (it can also
92
+ * be passed directly). This reads the shapes Guesty (`original` / `thumbnail`, `caption`),
93
+ * Hostaway (`url`, `caption`) and Streamline (`original_path` / `image_path` / `thumbnail_path`,
94
+ * `description`) send, plus bare URL strings, and drops anything without a URL.
95
+ */
66
96
  declare function listingPhotos(listingOrPictures: unknown): GalleryPhoto[];
97
+ /**
98
+ * An unstyled carousel (`role="region"`, `aria-roledescription="carousel"`). Every photo is in
99
+ * the DOM — only the first loads eagerly — and inactive slides are `hidden`; each slide carries
100
+ * `data-state` = `active` | `inactive`.
101
+ */
67
102
  declare function Gallery({ photos, onIndexChange, labels: labelsProp, sizes, className, classNames, }: GalleryProps): react.JSX.Element;
68
103
 
69
104
  interface GuestCounts {
@@ -74,11 +109,13 @@ type Slot = 'field' | 'label' | 'button' | 'value';
74
109
  interface GuestPickerProps {
75
110
  value: GuestCounts;
76
111
  onChange(value: GuestCounts): void;
112
+ /** Most guests in total (the listing's `maxGuests`). Default 50, the API's ceiling. */
77
113
  max?: number;
78
114
  labels?: Partial<GuestPickerLabels>;
79
115
  className?: string;
80
116
  classNames?: Partial<Record<Slot, string>>;
81
117
  }
118
+ /** Adults (at least 1) and children as two spinbuttons whose sum never exceeds `max`. */
82
119
  declare function GuestPicker({ value, onChange, max, labels: labelsProp, className, classNames, }: GuestPickerProps): react.JSX.Element;
83
120
 
84
121
  interface MapListing {
@@ -100,12 +137,17 @@ interface MapBounds {
100
137
  }
101
138
  interface MapRenderProps<T extends MapListing> {
102
139
  markers: MapMarker<T>[];
140
+ /** null when no listing has coordinates. */
103
141
  bounds: MapBounds | null;
104
142
  }
105
143
  interface MapProps<T extends MapListing> {
106
144
  listings: readonly T[];
107
145
  children(props: MapRenderProps<T>): ReactNode;
108
146
  }
147
+ /**
148
+ * Ships no map library: computes markers (listings without usable coordinates dropped) and
149
+ * their bounds, and hands them to `children` — plug in MapLibre, Google Maps or a static image.
150
+ */
109
151
  declare function Map<T extends MapListing>({ listings, children }: MapProps<T>): react.JSX.Element;
110
152
 
111
153
  export { DateRangePicker, type DateRangePickerLabels, type DateRangePickerProps, type DateRangeValue, Gallery, type GalleryLabels, type GalleryPhoto, type GalleryProps, type GuestCounts, GuestPicker, type GuestPickerLabels, type GuestPickerProps, Map, type MapBounds, type MapListing, type MapMarker, type MapProps, type MapRenderProps, defaultLabels, listingPhotos, unavailableDates };
@@ -1,11 +1,17 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
- import { c as StorefrontCalendarDay } from './availability-Dh0yLSkj.js';
3
+ import { c as StorefrontCalendarDay } from './availability.d-Cla9GuGc.js';
4
4
  import 'zod';
5
5
 
6
+ /**
7
+ * The components' English defaults. The SDK ships no other copy: pass `labels` (any subset)
8
+ * with your site's own translations.
9
+ */
6
10
  declare const defaultLabels: {
7
11
  dateRangePicker: {
12
+ /** Grid label; `monthStart` is the month's first day, YYYY-MM-DD. */
8
13
  month: (monthStart: string) => string;
14
+ /** Column header; 0 = Sunday. */
9
15
  weekday: (dayIndex: number) => string;
10
16
  day: (date: string) => string;
11
17
  previousMonth: string;
@@ -19,6 +25,7 @@ declare const defaultLabels: {
19
25
  };
20
26
  gallery: {
21
27
  region: string;
28
+ /** Fallback alt text and slide label; `index` is zero-based. */
22
29
  photo: (index: number, total: number) => string;
23
30
  previous: string;
24
31
  next: string;
@@ -28,6 +35,7 @@ type DateRangePickerLabels = typeof defaultLabels.dateRangePicker;
28
35
  type GuestPickerLabels = typeof defaultLabels.guestPicker;
29
36
  type GalleryLabels = typeof defaultLabels.gallery;
30
37
 
38
+ /** Listing-local dates, YYYY-MM-DD. `checkOut` null while the guest is picking it. */
31
39
  interface DateRangeValue {
32
40
  checkIn: string | null;
33
41
  checkOut: string | null;
@@ -36,16 +44,27 @@ type Slot$2 = 'header' | 'title' | 'nav' | 'grid' | 'weekday' | 'day';
36
44
  interface DateRangePickerProps {
37
45
  value: DateRangeValue;
38
46
  onChange(value: DateRangeValue): void;
47
+ /** Nights that cannot be booked (see `unavailableDates`); checking out on one is allowed. */
39
48
  unavailable?: Iterable<string>;
49
+ /** Minimum nights for the stay. Default 1. */
40
50
  minNights?: number;
51
+ /** Earlier days are disabled. Default: the browser's local date. */
41
52
  today?: string;
53
+ /** Month shown first, YYYY-MM. Default: the check-in's month, else today's. */
42
54
  defaultMonth?: string;
55
+ /** 0 = Sunday (default), 1 = Monday. */
43
56
  weekStartsOn?: 0 | 1;
44
57
  labels?: Partial<DateRangePickerLabels>;
45
58
  className?: string;
46
59
  classNames?: Partial<Record<Slot$2, string>>;
47
60
  }
61
+ /** The nights a `calendar.get` answer marks as not bookable. */
48
62
  declare function unavailableDates(days: readonly Pick<StorefrontCalendarDay, 'date' | 'status'>[]): string[];
63
+ /**
64
+ * A controlled, unstyled stay picker: one month grid (`role="grid"`), arrow keys move by day
65
+ * and week, Enter / Space / click pick the check-in then the check-out. Each day carries
66
+ * `data-state` = `start` | `end` | `in-range` | `disabled` | `available`.
67
+ */
49
68
  declare function DateRangePicker({ value, onChange, unavailable, minNights, today: todayProp, defaultMonth, weekStartsOn, labels: labelsProp, className, classNames, }: DateRangePickerProps): react.JSX.Element;
50
69
 
51
70
  interface GalleryPhoto {
@@ -57,13 +76,29 @@ interface GalleryPhoto {
57
76
  type Slot$1 = 'viewport' | 'slide' | 'image' | 'button';
58
77
  interface GalleryProps {
59
78
  photos: readonly GalleryPhoto[];
79
+ /** Called with the zero-based index of the photo now shown. */
60
80
  onIndexChange?(index: number): void;
61
81
  labels?: Partial<GalleryLabels>;
82
+ /** The slide's rendered width, for the browser to pick a size (`<img sizes>`). */
62
83
  sizes?: string;
63
84
  className?: string;
64
85
  classNames?: Partial<Record<Slot$1, string>>;
65
86
  }
87
+ /**
88
+ * A listing's photos for `Gallery`. Pass the listing: its `images` (the photos as SuiteOp hosts
89
+ * them) come first; with none — not copied yet, or an API revision without them — its `pictures`.
90
+ *
91
+ * `StorefrontListing.pictures` is the PMS's own photo array, passed through untyped (it can also
92
+ * be passed directly). This reads the shapes Guesty (`original` / `thumbnail`, `caption`),
93
+ * Hostaway (`url`, `caption`) and Streamline (`original_path` / `image_path` / `thumbnail_path`,
94
+ * `description`) send, plus bare URL strings, and drops anything without a URL.
95
+ */
66
96
  declare function listingPhotos(listingOrPictures: unknown): GalleryPhoto[];
97
+ /**
98
+ * An unstyled carousel (`role="region"`, `aria-roledescription="carousel"`). Every photo is in
99
+ * the DOM — only the first loads eagerly — and inactive slides are `hidden`; each slide carries
100
+ * `data-state` = `active` | `inactive`.
101
+ */
67
102
  declare function Gallery({ photos, onIndexChange, labels: labelsProp, sizes, className, classNames, }: GalleryProps): react.JSX.Element;
68
103
 
69
104
  interface GuestCounts {
@@ -74,11 +109,13 @@ type Slot = 'field' | 'label' | 'button' | 'value';
74
109
  interface GuestPickerProps {
75
110
  value: GuestCounts;
76
111
  onChange(value: GuestCounts): void;
112
+ /** Most guests in total (the listing's `maxGuests`). Default 50, the API's ceiling. */
77
113
  max?: number;
78
114
  labels?: Partial<GuestPickerLabels>;
79
115
  className?: string;
80
116
  classNames?: Partial<Record<Slot, string>>;
81
117
  }
118
+ /** Adults (at least 1) and children as two spinbuttons whose sum never exceeds `max`. */
82
119
  declare function GuestPicker({ value, onChange, max, labels: labelsProp, className, classNames, }: GuestPickerProps): react.JSX.Element;
83
120
 
84
121
  interface MapListing {
@@ -100,12 +137,17 @@ interface MapBounds {
100
137
  }
101
138
  interface MapRenderProps<T extends MapListing> {
102
139
  markers: MapMarker<T>[];
140
+ /** null when no listing has coordinates. */
103
141
  bounds: MapBounds | null;
104
142
  }
105
143
  interface MapProps<T extends MapListing> {
106
144
  listings: readonly T[];
107
145
  children(props: MapRenderProps<T>): ReactNode;
108
146
  }
147
+ /**
148
+ * Ships no map library: computes markers (listings without usable coordinates dropped) and
149
+ * their bounds, and hands them to `children` — plug in MapLibre, Google Maps or a static image.
150
+ */
109
151
  declare function Map<T extends MapListing>({ listings, children }: MapProps<T>): react.JSX.Element;
110
152
 
111
153
  export { DateRangePicker, type DateRangePickerLabels, type DateRangePickerProps, type DateRangeValue, Gallery, type GalleryLabels, type GalleryPhoto, type GalleryProps, type GuestCounts, GuestPicker, type GuestPickerLabels, type GuestPickerProps, Map, type MapBounds, type MapListing, type MapMarker, type MapProps, type MapRenderProps, defaultLabels, listingPhotos, unavailableDates };
package/dist/config.cjs CHANGED
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
- var chunkZLAOY6IF_cjs = require('./chunk-ZLAOY6IF.cjs');
3
+ var chunkJF245QUY_cjs = require('./chunk-JF245QUY.cjs');
4
4
  var zod = require('zod');
5
5
 
6
- var STOREFRONT_LOCALES=["en","fr","es","de","it","pt","nl"];var STOREFRONT_LAYOUTS=["listings","locations","areas","single"];var STOREFRONT_THEMES=["folio","hearth","circuit","tide","noir","fjord"];var REQUIRED="validation.required";var TOO_LONG="validation.max_length";var TOO_MANY="validation.too_large";var INVALID="validation.invalid";var text=max=>zod.z.string(INVALID).max(max,TOO_LONG);var localeSchema=zod.z.enum(STOREFRONT_LOCALES,"validation.storefront.locale_unsupported");var hexSchema=zod.z.string(INVALID).regex(/^#[0-9A-Fa-f]{6}$/,"validation.storefront.color_hex");var assetUrlSchema=zod.z.url({protocol:/^https$/,error:"validation.storefront.url_https"});var localizedSchema=zod.z.partialRecord(localeSchema,text(200),INVALID);var linkSchema=zod.z.object({label:localizedSchema,href:text(500).regex(/^(\/(?!\/)|https:\/\/)/,"validation.storefront.link_href")},INVALID);var fontSchema=zod.z.enum(chunkZLAOY6IF_cjs.STOREFRONT_FONTS,"validation.invalid_option");var storefrontSiteConfigSchema=zod.z.object({layout:zod.z.enum(STOREFRONT_LAYOUTS).optional().catch(void 0),theme:zod.z.enum(STOREFRONT_THEMES).optional().catch(void 0),brand:zod.z.object({name:text(80).min(1,REQUIRED),logoUrl:assetUrlSchema.nullable(),logoOnDarkUrl:assetUrlSchema.nullable().optional(),faviconUrl:assetUrlSchema.nullable()},INVALID),colors:zod.z.object({primary:hexSchema,secondary:hexSchema.nullable().optional(),primaryForeground:hexSchema.optional(),background:hexSchema.optional(),foreground:hexSchema.optional(),accent:hexSchema.optional()},INVALID),fonts:zod.z.object({heading:fontSchema.optional(),body:fontSchema.optional()},INVALID).optional(),nav:zod.z.array(linkSchema,INVALID).max(8,TOO_MANY),footer:zod.z.object({text:localizedSchema,links:zod.z.array(linkSchema,INVALID).max(12,TOO_MANY)},INVALID),defaultLocale:localeSchema,locales:zod.z.array(localeSchema,INVALID).min(1,REQUIRED).max(STOREFRONT_LOCALES.length,TOO_MANY),seo:zod.z.object({titleTemplate:text(80).includes("%s",{error:"validation.storefront.title_template_placeholder"}),defaultDescription:localizedSchema,ogImageUrl:assetUrlSchema.nullable()},INVALID)},INVALID).refine(c=>c.locales.includes(c.defaultLocale),{path:["defaultLocale"],message:"validation.storefront.default_locale_not_listed"});var DEFAULT_STOREFRONT_LAYOUT="listings";var DEFAULT_STOREFRONT_THEME="tide";var STOREFRONT_THEME_RECIPES={folio:{mode:"light",fonts:{heading:"eb_garamond",body:"libre_franklin"},radius:{sm:0,md:0,lg:0,btn:0},btn:{size:12,w:600,ls:"0.14em",tt:"uppercase",h:46},type:{display:[88,1,400,"-0.015em"],h1:[56,1.05,400,"-0.01em"],h2:[36,1.15,400,"0"],h3:[24,1.25,500,"0"],body:[18,1.6,400,"0"],small:[14,1.5,400,"0"],label:[11,1.3,600,"0.16em","uppercase"]},space:{section:144,gutter:32},neutral:{hue:null,mix:0,c:.006},L:{bg:.985,surface:1,surface2:.955,tint:.95,border:.87,ink:.19,muted:.47,dark:.22},C:{ink:.02,dark:.04,tint:.022},shadow:false},hearth:{mode:"light",fonts:{heading:"lora",body:"karla"},radius:{sm:6,md:12,lg:18,btn:8},btn:{size:15,w:700,ls:"0",tt:"none",h:48},type:{display:[64,1.08,500,"-0.01em"],h1:[48,1.12,500,"-0.01em"],h2:[32,1.2,500,"0"],h3:[22,1.3,600,"0"],body:[17,1.6,400,"0"],small:[14,1.5,400,"0"],label:[12,1.3,700,"0.1em","uppercase"]},space:{section:112,gutter:28},neutral:{hue:75,mix:.85,c:.014},L:{bg:.972,surface:.99,surface2:.945,tint:.935,border:.885,ink:.25,muted:.48,dark:.28},C:{ink:.025,dark:.05,tint:.032},shadow:true},circuit:{mode:"light",fonts:{heading:"space_grotesk",body:"ibm_plex_sans"},radius:{sm:8,md:12,lg:16,btn:999},btn:{size:15,w:600,ls:"-0.005em",tt:"none",h:44},type:{display:[64,1.02,600,"-0.035em"],h1:[44,1.08,600,"-0.03em"],h2:[30,1.15,600,"-0.02em"],h3:[20,1.3,600,"-0.01em"],body:[16,1.55,400,"0"],small:[14,1.45,400,"0"],label:[12,1.3,600,"0.02em"]},space:{section:88,gutter:20},neutral:{hue:null,mix:0,c:.004},L:{bg:1,surface:.975,surface2:.958,tint:.958,border:.915,ink:.17,muted:.48,dark:.19},C:{ink:.012,dark:.03,tint:.035},shadow:true},tide:{mode:"light",fonts:{heading:"outfit",body:"mulish"},radius:{sm:12,md:20,lg:28,btn:999},btn:{size:15,w:700,ls:"0.01em",tt:"none",h:50},type:{display:[76,1.02,300,"-0.02em"],h1:[48,1.1,400,"-0.015em"],h2:[34,1.15,400,"-0.01em"],h3:[21,1.3,500,"0"],body:[17,1.6,400,"0"],small:[14,1.5,400,"0"],label:[12,1.3,700,"0.08em","uppercase"]},space:{section:120,gutter:24},neutral:{hue:null,mix:0,c:.005},L:{bg:.99,surface:.968,surface2:.945,tint:.95,border:.905,ink:.26,muted:.48,dark:.29},C:{ink:.035,dark:.055,tint:.028},shadow:true},noir:{mode:"dark",fonts:{heading:"cormorant_garamond",body:"manrope"},radius:{sm:0,md:2,lg:2,btn:0},btn:{size:11,w:600,ls:"0.22em",tt:"uppercase",h:48},type:{display:[84,1,300,"0.02em","uppercase"],h1:[56,1.05,300,"0.01em"],h2:[38,1.15,400,"0"],h3:[24,1.25,500,"0.02em"],body:[16,1.7,400,"0"],small:[13,1.55,400,"0.01em"],label:[11,1.3,600,"0.24em","uppercase"]},space:{section:152,gutter:32},neutral:{hue:null,mix:0,c:.016},L:{bg:.165,surface:.205,surface2:.245,tint:.24,border:.34,ink:.94,muted:.76,dark:.12},C:{ink:.01,dark:.014,tint:.035},shadow:false},fjord:{mode:"light",fonts:{heading:"dm_sans",body:"dm_sans"},radius:{sm:2,md:4,lg:6,btn:4},btn:{size:14,w:500,ls:"0",tt:"none",h:44},type:{display:[60,1.05,500,"-0.03em"],h1:[42,1.1,500,"-0.025em"],h2:[28,1.2,500,"-0.015em"],h3:[19,1.35,500,"-0.005em"],body:[16,1.6,400,"0"],small:[13,1.5,400,"0"],label:[12,1.3,500,"0"]},space:{section:128,gutter:24},neutral:{hue:85,mix:.85,c:.006},L:{bg:.976,surface:.995,surface2:.948,tint:.945,border:.895,ink:.23,muted:.49,dark:.26},C:{ink:.008,dark:.02,tint:.022},shadow:false}};var clamp=(v,a,b)=>Math.min(b,Math.max(a,v));var toLin=c=>c<=.04045?c/12.92:Math.pow((c+.055)/1.055,2.4);var toGam=c=>c<=.0031308?12.92*c:1.055*Math.pow(c,1/2.4)-.055;var hexToRgb=hex=>{const h=hex.replace("#","");return [0,2,4].map(i=>parseInt(h.slice(i,i+2),16)/255)};var rgbToHex=rgb=>"#"+rgb.map(v=>Math.round(clamp(v,0,1)*255).toString(16).padStart(2,"0")).join("").toUpperCase();function hexToOklch(hex){const[r,g,b]=hexToRgb(hex).map(toLin);const l=Math.cbrt(.4122214708*r+.5363325363*g+.0514459929*b);const m=Math.cbrt(.2119034982*r+.6806995451*g+.1073969566*b);const s=Math.cbrt(.0883024619*r+.2817188376*g+.6299787005*b);const L=.2104542553*l+.793617785*m-.0040720468*s;const A=1.9779984951*l-2.428592205*m+.4505937099*s;const B=.0259040371*l+.7827717662*m-.808675766*s;let H=Math.atan2(B,A)*180/Math.PI;if(H<0)H+=360;return [L,Math.sqrt(A*A+B*B),H]}function oklchToLinear(L,C,H){const a=C*Math.cos(H*Math.PI/180);const b=C*Math.sin(H*Math.PI/180);const l=(L+.3963377774*a+.2158037573*b)**3;const m=(L-.1055613458*a-.0638541728*b)**3;const s=(L-.0894841775*a-1.291485548*b)**3;return [4.0767416621*l-3.3077115913*m+.2309699292*s,-1.2684380046*l+2.6097574011*m-.3413193965*s,-0.0041960863*l-.7034186147*m+1.707614701*s]}var inGamut=rgb=>rgb.every(v=>v>=-1e-4&&v<=1.0001);function oklchToHex(lightness,C,H){const L=clamp(lightness,0,1);let rgb=oklchToLinear(L,C,H);if(!inGamut(rgb)){let lo=0;let hi=C;for(let i=0;i<22;i++){const mid=(lo+hi)/2;if(inGamut(oklchToLinear(L,mid,H)))lo=mid;else hi=mid;}rgb=oklchToLinear(L,lo,H);}return rgbToHex(rgb.map(v=>toGam(clamp(v,0,1))))}var luminance=hex=>{const[r,g,b]=hexToRgb(hex).map(toLin);return .2126*r+.7152*g+.0722*b};function contrastRatio(a,b){const x=luminance(a);const y=luminance(b);return (Math.max(x,y)+.05)/(Math.min(x,y)+.05)}var minContrast=(hex,grounds)=>Math.min(...grounds.map(g=>contrastRatio(hex,g)));var rgba=(hex,alpha)=>{const[r,g,b]=hexToRgb(hex).map(v=>Math.round(v*255));return `rgba(${r},${g},${b},${alpha})`};var mixHue=(a,b,t)=>{const d=(b-a+540)%360-180;return (a+d*t+360)%360};function fit(lightness,C,H,grounds,target,dir){let L=lightness;let hex=oklchToHex(L,C,H);let steps=0;while(minContrast(hex,grounds)<target&&steps<100){L=clamp(L+dir*.01,0,1);hex=oklchToHex(L,C,H);steps++;}return {hex,L,steps}}var SERIF_FONTS=new Set(["playfair_display","merriweather","bitter","fraunces","cormorant_garamond","eb_garamond","lora","crimson_pro","source_serif_4","ibm_plex_serif"]);function storefrontFontStack(font){return `'${chunkZLAOY6IF_cjs.STOREFRONT_FONT_FAMILIES[font]}', ${SERIF_FONTS.has(font)?"serif":"sans-serif"}`}var AA=4.5;var INK=7;function derivePalette(recipe,brandHex,secondary,overrides){const[bL,bC,bH]=hexToOklch(brandHex);const nh=recipe.neutral.hue==null?bH:mixHue(bH,recipe.neutral.hue,recipe.neutral.mix);const nc=recipe.neutral.c;const{L,C}=recipe;const dark=recipe.mode==="dark";const dir=dark?1:-1;const N=(l,c=nc)=>oklchToHex(l,c,nh);const bg=overrides.background?.toUpperCase()??N(L.bg);const surface=N(L.surface,L.surface>=.999?0:nc);const surface2=N(L.surface2);const tint=oklchToHex(L.tint,Math.min(bC,C.tint),bH);const border=N(L.border,nc*1.5);const borderStrong=N(dark?L.border+.12:L.border-.2,nc*1.5);const grounds=[bg,surface,surface2,tint];const ink=overrides.foreground?.toUpperCase()??fit(L.ink,C.ink,nh,grounds,INK,dir).hex;const muted=fit(L.muted,nc*2.5,nh,grounds,AA,dir).hex;const brandText=fit(bL,bC,bH,grounds,AA,dir);const accentText=overrides.accent?.toUpperCase()??brandText.hex;const notes=[];let p;let on;if(!dark){const white=oklchToHex(.995,.003,bH);if(contrastRatio(brandHex,white)>=AA){p={hex:brandHex.toUpperCase(),L:bL};on=white;}else if(bL>=.7&&contrastRatio(brandHex,ink)>=AA){p={hex:brandHex.toUpperCase(),L:bL};on=ink;notes.push({code:"light_brand_ink_label",text:"Light brand: button keeps the colour and takes an ink label"});}else {p=fit(bL,bC,bH,[white],AA,-1);on=white;notes.push({code:"button_darkened",from:round2(bL),to:round2(p.L),text:`Button darkened L ${bL.toFixed(2)} \u2192 ${p.L.toFixed(2)} for a white label`});}}else {on=bg;p=fit(Math.max(bL,.72),bC,bH,[bg,surface],AA,1);if(p.L>bL+.005){notes.push({code:"brand_lifted",from:round2(bL),to:round2(p.L),text:`Brand lifted L ${bL.toFixed(2)} \u2192 ${p.L.toFixed(2)} to read on dark`});}}const onPrimary=overrides.primaryForeground?.toUpperCase()??on;let primaryHover=oklchToHex(p.L+(dark?.05:-0.06),bC,bH);if(contrastRatio(primaryHover,onPrimary)<AA){primaryHover=oklchToHex(p.L+(dark?-0.04:.04),bC,bH);}const darkToken=oklchToHex(L.dark,Math.min(bC,C.dark),bH);const phBg=dark?oklchToHex(.27,Math.min(bC,.03),bH):oklchToHex(L.tint-.045,Math.min(bC,.03),bH);const t={bg,surface,surface2,tint,border,borderStrong,ink,muted,primary:p.hex,onPrimary,primaryHover,accentText,dark:darkToken,onDark:oklchToHex(.97,.008,bH),onDarkMuted:fit(.82,.012,bH,[darkToken],AA,1).hex,darkAccent:fit(Math.max(bL,.72),bC,bH,[darkToken],AA,1).hex,focus:dark?p.hex:accentText,phBg,phText:fit(dark?.7:.48,.02,bH,[phBg],AA,dir).hex};if(secondary)t.accent2=fit(...hexToOklch(secondary),grounds,AA,dir).hex;if(!dark&&brandText.steps>0&&accentText===brandText.hex){notes.push({code:"brand_text_darkened",steps:brandText.steps,text:`Brand text darkened ${brandText.steps} step${brandText.steps>1?"s":""} to reach 4.5:1`});}return {t,notes}}var round2=n=>Math.round(n*100)/100;function failingOverride(t,overrides){const grounds=[t.bg,t.surface,t.surface2,t.tint];if(overrides.foreground){const ratio=minContrast(t.ink,grounds);if(ratio<AA)return {field:"foreground",ratio,against:"background"}}if(overrides.accent){const ratio=minContrast(t.accentText,grounds);if(ratio<AA)return {field:"accent",ratio,against:"background"}}if(overrides.primaryForeground){const ratio=contrastRatio(t.onPrimary,t.primary);if(ratio<AA)return {field:"primaryForeground",ratio,against:"button"}}if(overrides.background){const ratio=Math.min(contrastRatio(t.ink,t.bg),contrastRatio(t.muted,t.bg));if(ratio<AA)return {field:"background",ratio,against:"text"}}return null}function deriveStorefrontTheme(theme,brandHex,opts={}){const recipe=STOREFRONT_THEME_RECIPES[theme];const overrides={...opts.overrides};const problems=[];let palette=derivePalette(recipe,brandHex,opts.secondary,overrides);for(let problem=failingOverride(palette.t,overrides);problem;){problems.push({...problem,ratio:Math.round(problem.ratio*10)/10});delete overrides[problem.field];palette=derivePalette(recipe,brandHex,opts.secondary,overrides);problem=failingOverride(palette.t,overrides);}const{t,notes}=palette;const r=recipe.radius;const px=n=>`${n}px`;const vars={"--so-bg":t.bg,"--so-surface":t.surface,"--so-surface-2":t.surface2,"--so-tint":t.tint,"--so-border":t.border,"--so-border-strong":t.borderStrong,"--so-ink":t.ink,"--so-muted":t.muted,"--so-primary":t.primary,"--so-on-primary":t.onPrimary,"--so-primary-hover":t.primaryHover,"--so-accent-text":t.accentText,"--so-dark":t.dark,"--so-on-dark":t.onDark,"--so-on-dark-muted":t.onDarkMuted,"--so-dark-accent":t.darkAccent,"--so-focus":t.focus,"--so-ph-bg":t.phBg,"--so-ph-text":t.phText,"--so-ph-line":rgba(t.phText,.16),"--so-accent-2":t.accent2??t.accentText,"--so-scrim":`linear-gradient(180deg, ${rgba(t.dark,.55)} 0%, ${rgba(t.dark,0)} 26%, ${rgba(t.dark,0)} 40%, ${rgba(t.dark,.72)} 100%)`,"--so-scrim-solid":rgba(t.dark,.45),"--so-shadow":recipe.shadow?`0 1px 2px ${rgba(t.dark,.06)}, 0 10px 30px ${rgba(t.dark,.1)}`:"none","--so-shadow-float":`0 2px 6px ${rgba(t.dark,.08)}, 0 18px 50px ${rgba(t.dark,.18)}`,"--so-font-heading":storefrontFontStack(opts.heading??recipe.fonts.heading),"--so-font-body":storefrontFontStack(opts.body??recipe.fonts.body),"--so-r-sm":px(r.sm),"--so-r-md":px(r.md),"--so-r-lg":px(r.lg),"--so-r-btn":px(r.btn),"--so-btn-size":px(recipe.btn.size),"--so-btn-w":String(recipe.btn.w),"--so-btn-ls":recipe.btn.ls,"--so-btn-tt":recipe.btn.tt,"--so-btn-h":px(recipe.btn.h),"--so-section":px(recipe.space.section),"--so-gutter":px(recipe.space.gutter)};for(const[step,[size,lh,w,ls,tt]]of Object.entries(recipe.type)){vars[`--t-${step}-size`]=px(size);vars[`--t-${step}-lh`]=String(lh);vars[`--t-${step}-w`]=String(w);vars[`--t-${step}-ls`]=ls;vars[`--t-${step}-tt`]=tt??"none";}const grade=x=>x>=7?"AAA":x>=AA?"AA":"Fail";const checks=[["Body text",t.ink,t.bg],["Muted text",t.muted,t.surface2],["Button label",t.onPrimary,t.primary],["Brand text",t.accentText,t.bg],["On dark section",t.onDark,t.dark],["Brand on dark",t.darkAccent,t.dark]].map(([label,a,b])=>{const x=Math.round(contrastRatio(a,b)*10)/10;return {label,ratio:x.toFixed(1),grade:grade(x),pass:x>=AA}});return {theme,tokens:t,vars,checks,notes,problems}}function storefrontThemeFonts(theme,fonts){const pair=STOREFRONT_THEME_RECIPES[theme].fonts;return {heading:fonts?.heading??pair.heading,body:fonts?.body??pair.body}}function resolveStorefrontTheme(config){const theme=config.theme??DEFAULT_STOREFRONT_THEME;const fonts=storefrontThemeFonts(theme,config.fonts);const{primary,secondary,background,foreground,accent,primaryForeground}=explicitThemeChoices(config).colors;const derived=deriveStorefrontTheme(theme,primary,{secondary,...fonts,overrides:{background,foreground,accent,primaryForeground}});return {theme,layout:config.layout??DEFAULT_STOREFRONT_LAYOUT,fonts,derived,cssVariables:derived.vars}}var OVERRIDE_TOKENS={background:"bg",foreground:"ink",accent:"accentText",primaryForeground:"onPrimary"};var OVERRIDES=Object.keys(OVERRIDE_TOKENS);function legacyButtonLabel(primary,t){if(contrastRatio(t.onPrimary,primary)>=AA)return t.onPrimary;const reads=[t.onDark,t.ink,t.dark,t.bg].filter(hex=>contrastRatio(hex,primary)>=AA);return (reads.length?reads:["#FFFFFF","#000000"]).reduce((best,hex)=>contrastRatio(hex,primary)>contrastRatio(best,primary)?hex:best)}function explicitThemeChoices(config){const theme=config.theme??DEFAULT_STOREFRONT_THEME;const given=pickOverrides(config.colors);const colors={...config.colors};for(const field of OVERRIDES){const value=given[field];if(!value)continue;const others={...given};delete others[field];const{tokens}=deriveStorefrontTheme(theme,config.colors.primary,{overrides:others});const derived=field==="primaryForeground"?[tokens.onPrimary,legacyButtonLabel(config.colors.primary,tokens)]:[tokens[OVERRIDE_TOKENS[field]]];if(derived.includes(value.toUpperCase()))delete colors[field];}const pair=STOREFRONT_THEME_RECIPES[theme].fonts;const fonts={...config.fonts?.heading&&config.fonts.heading!==pair.heading?{heading:config.fonts.heading}:{},...config.fonts?.body&&config.fonts.body!==pair.body?{body:config.fonts.body}:{}};const{fonts:_fonts,...rest}=config;return {...rest,colors,...fonts.heading||fonts.body?{fonts}:{}}}function pickOverrides(colors){const{background,foreground,accent,primaryForeground}=colors;return Object.fromEntries(Object.entries({background,foreground,accent,primaryForeground}).filter(([,v])=>!!v))}function defineSuiteOpConfig(config){return storefrontSiteConfigSchema.parse(config)}
6
+ var STOREFRONT_LOCALES=["en","fr","es","de","it","pt","nl"];var STOREFRONT_LAYOUTS=["listings","locations","areas","single"];var STOREFRONT_THEMES=["folio","hearth","circuit","tide","noir","fjord"];var REQUIRED="validation.required";var TOO_LONG="validation.max_length";var TOO_MANY="validation.too_large";var INVALID="validation.invalid";var text=max=>zod.z.string(INVALID).max(max,TOO_LONG);var localeSchema=zod.z.enum(STOREFRONT_LOCALES,"validation.storefront.locale_unsupported");var hexSchema=zod.z.string(INVALID).regex(/^#[0-9A-Fa-f]{6}$/,"validation.storefront.color_hex");var assetUrlSchema=zod.z.url({protocol:/^https$/,error:"validation.storefront.url_https"});var localizedSchema=zod.z.partialRecord(localeSchema,text(200),INVALID);var linkSchema=zod.z.object({label:localizedSchema,href:text(500).regex(/^(\/(?!\/)|https:\/\/)/,"validation.storefront.link_href")},INVALID);var fontSchema=zod.z.enum(chunkJF245QUY_cjs.STOREFRONT_FONTS,"validation.invalid_option");var storefrontSiteConfigSchema=zod.z.object({layout:zod.z.enum(STOREFRONT_LAYOUTS).optional().catch(void 0),theme:zod.z.enum(STOREFRONT_THEMES).optional().catch(void 0),brand:zod.z.object({name:text(80).min(1,REQUIRED),logoUrl:assetUrlSchema.nullable(),logoOnDarkUrl:assetUrlSchema.nullable().optional(),faviconUrl:assetUrlSchema.nullable()},INVALID),colors:zod.z.object({primary:hexSchema,secondary:hexSchema.nullable().optional(),primaryForeground:hexSchema.optional(),background:hexSchema.optional(),foreground:hexSchema.optional(),accent:hexSchema.optional()},INVALID),fonts:zod.z.object({heading:fontSchema.optional(),body:fontSchema.optional()},INVALID).optional(),nav:zod.z.array(linkSchema,INVALID).max(8,TOO_MANY),footer:zod.z.object({text:localizedSchema,links:zod.z.array(linkSchema,INVALID).max(12,TOO_MANY)},INVALID),defaultLocale:localeSchema,locales:zod.z.array(localeSchema,INVALID).min(1,REQUIRED).max(STOREFRONT_LOCALES.length,TOO_MANY),seo:zod.z.object({titleTemplate:text(80).includes("%s",{error:"validation.storefront.title_template_placeholder"}),defaultDescription:localizedSchema,ogImageUrl:assetUrlSchema.nullable()},INVALID)},INVALID).refine(c=>c.locales.includes(c.defaultLocale),{path:["defaultLocale"],message:"validation.storefront.default_locale_not_listed"});var DEFAULT_STOREFRONT_LAYOUT="listings";var DEFAULT_STOREFRONT_THEME="tide";var STOREFRONT_THEME_RECIPES={folio:{mode:"light",fonts:{heading:"eb_garamond",body:"libre_franklin"},radius:{sm:0,md:0,lg:0,btn:0},btn:{size:12,w:600,ls:"0.14em",tt:"uppercase",h:46},type:{display:[88,1,400,"-0.015em"],h1:[56,1.05,400,"-0.01em"],h2:[36,1.15,400,"0"],h3:[24,1.25,500,"0"],body:[18,1.6,400,"0"],small:[14,1.5,400,"0"],label:[11,1.3,600,"0.16em","uppercase"]},space:{section:144,gutter:32},neutral:{hue:null,mix:0,c:.006},L:{bg:.985,surface:1,surface2:.955,tint:.95,border:.87,ink:.19,muted:.47,dark:.22},C:{ink:.02,dark:.04,tint:.022},shadow:false},hearth:{mode:"light",fonts:{heading:"lora",body:"karla"},radius:{sm:6,md:12,lg:18,btn:8},btn:{size:15,w:700,ls:"0",tt:"none",h:48},type:{display:[64,1.08,500,"-0.01em"],h1:[48,1.12,500,"-0.01em"],h2:[32,1.2,500,"0"],h3:[22,1.3,600,"0"],body:[17,1.6,400,"0"],small:[14,1.5,400,"0"],label:[12,1.3,700,"0.1em","uppercase"]},space:{section:112,gutter:28},neutral:{hue:75,mix:.85,c:.014},L:{bg:.972,surface:.99,surface2:.945,tint:.935,border:.885,ink:.25,muted:.48,dark:.28},C:{ink:.025,dark:.05,tint:.032},shadow:true},circuit:{mode:"light",fonts:{heading:"space_grotesk",body:"ibm_plex_sans"},radius:{sm:8,md:12,lg:16,btn:999},btn:{size:15,w:600,ls:"-0.005em",tt:"none",h:44},type:{display:[64,1.02,600,"-0.035em"],h1:[44,1.08,600,"-0.03em"],h2:[30,1.15,600,"-0.02em"],h3:[20,1.3,600,"-0.01em"],body:[16,1.55,400,"0"],small:[14,1.45,400,"0"],label:[12,1.3,600,"0.02em"]},space:{section:88,gutter:20},neutral:{hue:null,mix:0,c:.004},L:{bg:1,surface:.975,surface2:.958,tint:.958,border:.915,ink:.17,muted:.48,dark:.19},C:{ink:.012,dark:.03,tint:.035},shadow:true},tide:{mode:"light",fonts:{heading:"outfit",body:"mulish"},radius:{sm:12,md:20,lg:28,btn:999},btn:{size:15,w:700,ls:"0.01em",tt:"none",h:50},type:{display:[76,1.02,300,"-0.02em"],h1:[48,1.1,400,"-0.015em"],h2:[34,1.15,400,"-0.01em"],h3:[21,1.3,500,"0"],body:[17,1.6,400,"0"],small:[14,1.5,400,"0"],label:[12,1.3,700,"0.08em","uppercase"]},space:{section:120,gutter:24},neutral:{hue:null,mix:0,c:.005},L:{bg:.99,surface:.968,surface2:.945,tint:.95,border:.905,ink:.26,muted:.48,dark:.29},C:{ink:.035,dark:.055,tint:.028},shadow:true},noir:{mode:"dark",fonts:{heading:"cormorant_garamond",body:"manrope"},radius:{sm:0,md:2,lg:2,btn:0},btn:{size:11,w:600,ls:"0.22em",tt:"uppercase",h:48},type:{display:[84,1,300,"0.02em","uppercase"],h1:[56,1.05,300,"0.01em"],h2:[38,1.15,400,"0"],h3:[24,1.25,500,"0.02em"],body:[16,1.7,400,"0"],small:[13,1.55,400,"0.01em"],label:[11,1.3,600,"0.24em","uppercase"]},space:{section:152,gutter:32},neutral:{hue:null,mix:0,c:.016},L:{bg:.165,surface:.205,surface2:.245,tint:.24,border:.34,ink:.94,muted:.76,dark:.12},C:{ink:.01,dark:.014,tint:.035},shadow:false},fjord:{mode:"light",fonts:{heading:"dm_sans",body:"dm_sans"},radius:{sm:2,md:4,lg:6,btn:4},btn:{size:14,w:500,ls:"0",tt:"none",h:44},type:{display:[60,1.05,500,"-0.03em"],h1:[42,1.1,500,"-0.025em"],h2:[28,1.2,500,"-0.015em"],h3:[19,1.35,500,"-0.005em"],body:[16,1.6,400,"0"],small:[13,1.5,400,"0"],label:[12,1.3,500,"0"]},space:{section:128,gutter:24},neutral:{hue:85,mix:.85,c:.006},L:{bg:.976,surface:.995,surface2:.948,tint:.945,border:.895,ink:.23,muted:.49,dark:.26},C:{ink:.008,dark:.02,tint:.022},shadow:false}};var clamp=(v,a,b)=>Math.min(b,Math.max(a,v));var toLin=c=>c<=.04045?c/12.92:Math.pow((c+.055)/1.055,2.4);var toGam=c=>c<=.0031308?12.92*c:1.055*Math.pow(c,1/2.4)-.055;var hexToRgb=hex=>{const h=hex.replace("#","");return [0,2,4].map(i=>parseInt(h.slice(i,i+2),16)/255)};var rgbToHex=rgb=>"#"+rgb.map(v=>Math.round(clamp(v,0,1)*255).toString(16).padStart(2,"0")).join("").toUpperCase();function hexToOklch(hex){const[r,g,b]=hexToRgb(hex).map(toLin);const l=Math.cbrt(.4122214708*r+.5363325363*g+.0514459929*b);const m=Math.cbrt(.2119034982*r+.6806995451*g+.1073969566*b);const s=Math.cbrt(.0883024619*r+.2817188376*g+.6299787005*b);const L=.2104542553*l+.793617785*m-.0040720468*s;const A=1.9779984951*l-2.428592205*m+.4505937099*s;const B=.0259040371*l+.7827717662*m-.808675766*s;let H=Math.atan2(B,A)*180/Math.PI;if(H<0)H+=360;return [L,Math.sqrt(A*A+B*B),H]}function oklchToLinear(L,C,H){const a=C*Math.cos(H*Math.PI/180);const b=C*Math.sin(H*Math.PI/180);const l=(L+.3963377774*a+.2158037573*b)**3;const m=(L-.1055613458*a-.0638541728*b)**3;const s=(L-.0894841775*a-1.291485548*b)**3;return [4.0767416621*l-3.3077115913*m+.2309699292*s,-1.2684380046*l+2.6097574011*m-.3413193965*s,-0.0041960863*l-.7034186147*m+1.707614701*s]}var inGamut=rgb=>rgb.every(v=>v>=-1e-4&&v<=1.0001);function oklchToHex(lightness,C,H){const L=clamp(lightness,0,1);let rgb=oklchToLinear(L,C,H);if(!inGamut(rgb)){let lo=0;let hi=C;for(let i=0;i<22;i++){const mid=(lo+hi)/2;if(inGamut(oklchToLinear(L,mid,H)))lo=mid;else hi=mid;}rgb=oklchToLinear(L,lo,H);}return rgbToHex(rgb.map(v=>toGam(clamp(v,0,1))))}var luminance=hex=>{const[r,g,b]=hexToRgb(hex).map(toLin);return .2126*r+.7152*g+.0722*b};function contrastRatio(a,b){const x=luminance(a);const y=luminance(b);return (Math.max(x,y)+.05)/(Math.min(x,y)+.05)}var minContrast=(hex,grounds)=>Math.min(...grounds.map(g=>contrastRatio(hex,g)));var rgba=(hex,alpha)=>{const[r,g,b]=hexToRgb(hex).map(v=>Math.round(v*255));return `rgba(${r},${g},${b},${alpha})`};var mixHue=(a,b,t)=>{const d=(b-a+540)%360-180;return (a+d*t+360)%360};function fit(lightness,C,H,grounds,target,dir){let L=lightness;let hex=oklchToHex(L,C,H);let steps=0;while(minContrast(hex,grounds)<target&&steps<100){L=clamp(L+dir*.01,0,1);hex=oklchToHex(L,C,H);steps++;}return {hex,L,steps}}var SERIF_FONTS=new Set(["playfair_display","merriweather","bitter","fraunces","cormorant_garamond","eb_garamond","lora","crimson_pro","source_serif_4","ibm_plex_serif"]);function storefrontFontStack(font){return `'${chunkJF245QUY_cjs.STOREFRONT_FONT_FAMILIES[font]}', ${SERIF_FONTS.has(font)?"serif":"sans-serif"}`}var AA=4.5;var INK=7;function derivePalette(recipe,brandHex,secondary,overrides){const[bL,bC,bH]=hexToOklch(brandHex);const nh=recipe.neutral.hue==null?bH:mixHue(bH,recipe.neutral.hue,recipe.neutral.mix);const nc=recipe.neutral.c;const{L,C}=recipe;const dark=recipe.mode==="dark";const dir=dark?1:-1;const N=(l,c=nc)=>oklchToHex(l,c,nh);const bg=overrides.background?.toUpperCase()??N(L.bg);const surface=N(L.surface,L.surface>=.999?0:nc);const surface2=N(L.surface2);const tint=oklchToHex(L.tint,Math.min(bC,C.tint),bH);const border=N(L.border,nc*1.5);const borderStrong=N(dark?L.border+.12:L.border-.2,nc*1.5);const grounds=[bg,surface,surface2,tint];const ink=overrides.foreground?.toUpperCase()??fit(L.ink,C.ink,nh,grounds,INK,dir).hex;const muted=fit(L.muted,nc*2.5,nh,grounds,AA,dir).hex;const brandText=fit(bL,bC,bH,grounds,AA,dir);const accentText=overrides.accent?.toUpperCase()??brandText.hex;const notes=[];let p;let on;if(!dark){const white=oklchToHex(.995,.003,bH);if(contrastRatio(brandHex,white)>=AA){p={hex:brandHex.toUpperCase(),L:bL};on=white;}else if(bL>=.7&&contrastRatio(brandHex,ink)>=AA){p={hex:brandHex.toUpperCase(),L:bL};on=ink;notes.push({code:"light_brand_ink_label",text:"Light brand: button keeps the colour and takes an ink label"});}else {p=fit(bL,bC,bH,[white],AA,-1);on=white;notes.push({code:"button_darkened",from:round2(bL),to:round2(p.L),text:`Button darkened L ${bL.toFixed(2)} \u2192 ${p.L.toFixed(2)} for a white label`});}}else {on=bg;p=fit(Math.max(bL,.72),bC,bH,[bg,surface],AA,1);if(p.L>bL+.005){notes.push({code:"brand_lifted",from:round2(bL),to:round2(p.L),text:`Brand lifted L ${bL.toFixed(2)} \u2192 ${p.L.toFixed(2)} to read on dark`});}}const onPrimary=overrides.primaryForeground?.toUpperCase()??on;let primaryHover=oklchToHex(p.L+(dark?.05:-0.06),bC,bH);if(contrastRatio(primaryHover,onPrimary)<AA){primaryHover=oklchToHex(p.L+(dark?-0.04:.04),bC,bH);}const darkToken=oklchToHex(L.dark,Math.min(bC,C.dark),bH);const phBg=dark?oklchToHex(.27,Math.min(bC,.03),bH):oklchToHex(L.tint-.045,Math.min(bC,.03),bH);const t={bg,surface,surface2,tint,border,borderStrong,ink,muted,primary:p.hex,onPrimary,primaryHover,accentText,dark:darkToken,onDark:oklchToHex(.97,.008,bH),onDarkMuted:fit(.82,.012,bH,[darkToken],AA,1).hex,darkAccent:fit(Math.max(bL,.72),bC,bH,[darkToken],AA,1).hex,focus:dark?p.hex:accentText,phBg,phText:fit(dark?.7:.48,.02,bH,[phBg],AA,dir).hex};if(secondary)t.accent2=fit(...hexToOklch(secondary),grounds,AA,dir).hex;if(!dark&&brandText.steps>0&&accentText===brandText.hex){notes.push({code:"brand_text_darkened",steps:brandText.steps,text:`Brand text darkened ${brandText.steps} step${brandText.steps>1?"s":""} to reach 4.5:1`});}return {t,notes}}var round2=n=>Math.round(n*100)/100;function failingOverride(t,overrides){const grounds=[t.bg,t.surface,t.surface2,t.tint];if(overrides.foreground){const ratio=minContrast(t.ink,grounds);if(ratio<AA)return {field:"foreground",ratio,against:"background"}}if(overrides.accent){const ratio=minContrast(t.accentText,grounds);if(ratio<AA)return {field:"accent",ratio,against:"background"}}if(overrides.primaryForeground){const ratio=contrastRatio(t.onPrimary,t.primary);if(ratio<AA)return {field:"primaryForeground",ratio,against:"button"}}if(overrides.background){const ratio=Math.min(contrastRatio(t.ink,t.bg),contrastRatio(t.muted,t.bg));if(ratio<AA)return {field:"background",ratio,against:"text"}}return null}function deriveStorefrontTheme(theme,brandHex,opts={}){const recipe=STOREFRONT_THEME_RECIPES[theme];const overrides={...opts.overrides};const problems=[];let palette=derivePalette(recipe,brandHex,opts.secondary,overrides);for(let problem=failingOverride(palette.t,overrides);problem;){problems.push({...problem,ratio:Math.round(problem.ratio*10)/10});delete overrides[problem.field];palette=derivePalette(recipe,brandHex,opts.secondary,overrides);problem=failingOverride(palette.t,overrides);}const{t,notes}=palette;const r=recipe.radius;const px=n=>`${n}px`;const vars={"--so-bg":t.bg,"--so-surface":t.surface,"--so-surface-2":t.surface2,"--so-tint":t.tint,"--so-border":t.border,"--so-border-strong":t.borderStrong,"--so-ink":t.ink,"--so-muted":t.muted,"--so-primary":t.primary,"--so-on-primary":t.onPrimary,"--so-primary-hover":t.primaryHover,"--so-accent-text":t.accentText,"--so-dark":t.dark,"--so-on-dark":t.onDark,"--so-on-dark-muted":t.onDarkMuted,"--so-dark-accent":t.darkAccent,"--so-focus":t.focus,"--so-ph-bg":t.phBg,"--so-ph-text":t.phText,"--so-ph-line":rgba(t.phText,.16),"--so-accent-2":t.accent2??t.accentText,"--so-scrim":`linear-gradient(180deg, ${rgba(t.dark,.55)} 0%, ${rgba(t.dark,0)} 26%, ${rgba(t.dark,0)} 40%, ${rgba(t.dark,.72)} 100%)`,"--so-scrim-solid":rgba(t.dark,.45),"--so-shadow":recipe.shadow?`0 1px 2px ${rgba(t.dark,.06)}, 0 10px 30px ${rgba(t.dark,.1)}`:"none","--so-shadow-float":`0 2px 6px ${rgba(t.dark,.08)}, 0 18px 50px ${rgba(t.dark,.18)}`,"--so-font-heading":storefrontFontStack(opts.heading??recipe.fonts.heading),"--so-font-body":storefrontFontStack(opts.body??recipe.fonts.body),"--so-r-sm":px(r.sm),"--so-r-md":px(r.md),"--so-r-lg":px(r.lg),"--so-r-btn":px(r.btn),"--so-btn-size":px(recipe.btn.size),"--so-btn-w":String(recipe.btn.w),"--so-btn-ls":recipe.btn.ls,"--so-btn-tt":recipe.btn.tt,"--so-btn-h":px(recipe.btn.h),"--so-section":px(recipe.space.section),"--so-gutter":px(recipe.space.gutter)};for(const[step,[size,lh,w,ls,tt]]of Object.entries(recipe.type)){vars[`--t-${step}-size`]=px(size);vars[`--t-${step}-lh`]=String(lh);vars[`--t-${step}-w`]=String(w);vars[`--t-${step}-ls`]=ls;vars[`--t-${step}-tt`]=tt??"none";}const grade=x=>x>=7?"AAA":x>=AA?"AA":"Fail";const checks=[["Body text",t.ink,t.bg],["Muted text",t.muted,t.surface2],["Button label",t.onPrimary,t.primary],["Brand text",t.accentText,t.bg],["On dark section",t.onDark,t.dark],["Brand on dark",t.darkAccent,t.dark]].map(([label,a,b])=>{const x=Math.round(contrastRatio(a,b)*10)/10;return {label,ratio:x.toFixed(1),grade:grade(x),pass:x>=AA}});return {theme,tokens:t,vars,checks,notes,problems}}function storefrontThemeFonts(theme,fonts){const pair=STOREFRONT_THEME_RECIPES[theme].fonts;return {heading:fonts?.heading??pair.heading,body:fonts?.body??pair.body}}function resolveStorefrontTheme(config){const theme=config.theme??DEFAULT_STOREFRONT_THEME;const fonts=storefrontThemeFonts(theme,config.fonts);const{primary,secondary,background,foreground,accent,primaryForeground}=explicitThemeChoices(config).colors;const derived=deriveStorefrontTheme(theme,primary,{secondary,...fonts,overrides:{background,foreground,accent,primaryForeground}});return {theme,layout:config.layout??DEFAULT_STOREFRONT_LAYOUT,fonts,derived,cssVariables:derived.vars}}var OVERRIDE_TOKENS={background:"bg",foreground:"ink",accent:"accentText",primaryForeground:"onPrimary"};var OVERRIDES=Object.keys(OVERRIDE_TOKENS);function legacyButtonLabel(primary,t){if(contrastRatio(t.onPrimary,primary)>=AA)return t.onPrimary;const reads=[t.onDark,t.ink,t.dark,t.bg].filter(hex=>contrastRatio(hex,primary)>=AA);return (reads.length?reads:["#FFFFFF","#000000"]).reduce((best,hex)=>contrastRatio(hex,primary)>contrastRatio(best,primary)?hex:best)}function explicitThemeChoices(config){const theme=config.theme??DEFAULT_STOREFRONT_THEME;const given=pickOverrides(config.colors);const colors={...config.colors};for(const field of OVERRIDES){const value=given[field];if(!value)continue;const others={...given};delete others[field];const{tokens}=deriveStorefrontTheme(theme,config.colors.primary,{overrides:others});const derived=field==="primaryForeground"?[tokens.onPrimary,legacyButtonLabel(config.colors.primary,tokens)]:[tokens[OVERRIDE_TOKENS[field]]];if(derived.includes(value.toUpperCase()))delete colors[field];}const pair=STOREFRONT_THEME_RECIPES[theme].fonts;const fonts={...config.fonts?.heading&&config.fonts.heading!==pair.heading?{heading:config.fonts.heading}:{},...config.fonts?.body&&config.fonts.body!==pair.body?{body:config.fonts.body}:{}};const{fonts:_fonts,...rest}=config;return {...rest,colors,...fonts.heading||fonts.body?{fonts}:{}}}function pickOverrides(colors){const{background,foreground,accent,primaryForeground}=colors;return Object.fromEntries(Object.entries({background,foreground,accent,primaryForeground}).filter(([,v])=>!!v))}function defineSuiteOpConfig(config){return storefrontSiteConfigSchema.parse(config)}
7
7
 
8
8
  Object.defineProperty(exports, "STOREFRONT_FONT_FAMILIES", {
9
9
  enumerable: true,
10
- get: function () { return chunkZLAOY6IF_cjs.STOREFRONT_FONT_FAMILIES; }
10
+ get: function () { return chunkJF245QUY_cjs.STOREFRONT_FONT_FAMILIES; }
11
11
  });
12
12
  exports.DEFAULT_STOREFRONT_LAYOUT = DEFAULT_STOREFRONT_LAYOUT;
13
13
  exports.DEFAULT_STOREFRONT_THEME = DEFAULT_STOREFRONT_THEME;