@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.
- package/CHANGELOG.md +14 -0
- package/README.md +4 -2
- package/dist/astro-content-model.cjs +3 -3
- package/dist/astro-content-model.js +2 -2
- package/dist/astro.cjs +1 -1
- package/dist/astro.d.cts +66 -1
- package/dist/astro.d.ts +66 -1
- package/dist/astro.js +1 -1
- package/dist/{availability-Dh0yLSkj.d.cts → availability.d-Cla9GuGc.d.cts} +8 -8
- package/dist/{availability-Dh0yLSkj.d.ts → availability.d-Cla9GuGc.d.ts} +8 -8
- package/dist/checkout.d.cts +11 -0
- package/dist/checkout.d.ts +11 -0
- package/dist/{chunk-IUNIQSFB.js → chunk-3B6ZYRYF.js} +1 -1
- package/dist/chunk-3NE27PHL.cjs +19 -0
- package/dist/chunk-JF245QUY.cjs +9 -0
- package/dist/{chunk-NNWJZUQL.cjs → chunk-OXCLLFCY.cjs} +2 -2
- package/dist/chunk-QBHOJGZI.cjs +21 -0
- package/dist/chunk-UQWQPTHO.js +3 -0
- package/dist/chunk-XOCFEVP4.js +6 -0
- package/dist/chunk-YIYGBTAM.js +9 -0
- package/dist/{client-C9Igm7O-.d.ts → client-CX8K7JNt.d.cts} +65 -11
- package/dist/{client-2KyVv-2l.d.cts → client-s-lEwqzc.d.ts} +65 -11
- package/dist/components.d.cts +43 -1
- package/dist/components.d.ts +43 -1
- package/dist/config.cjs +3 -3
- package/dist/config.d.cts +78 -74
- package/dist/config.d.ts +78 -74
- package/dist/config.js +2 -2
- package/dist/content.cjs +9 -9
- package/dist/content.d.cts +53 -9
- package/dist/content.d.ts +53 -9
- package/dist/content.js +2 -2
- package/dist/{errors-DpImb0Uf.d.cts → errors-Oax7djdp.d.ts} +54 -13
- package/dist/{errors-BGgJ--XR.d.ts → errors-welPvrD6.d.cts} +54 -13
- package/dist/index.cjs +12 -12
- package/dist/index.d.cts +27 -8
- package/dist/index.d.ts +27 -8
- package/dist/index.js +3 -3
- package/dist/react.cjs +4 -4
- package/dist/react.d.cts +24 -3
- package/dist/react.d.ts +24 -3
- package/dist/react.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-5TUJX6GY.js +0 -5
- package/dist/chunk-LY73ZYN5.cjs +0 -20
- package/dist/chunk-NZWYOV5Y.cjs +0 -19
- package/dist/chunk-PYVUDQSQ.js +0 -3
- package/dist/chunk-YSKWSL2F.js +0 -9
- 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-
|
|
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<"
|
|
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<"
|
|
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 [
|
|
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" | "
|
|
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" | "
|
|
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: "
|
|
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" | "
|
|
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" | "
|
|
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: "
|
|
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<"
|
|
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 };
|
package/dist/components.d.cts
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { c as StorefrontCalendarDay } from './availability-
|
|
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 };
|
package/dist/components.d.ts
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { c as StorefrontCalendarDay } from './availability-
|
|
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
|
|
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
|
|
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;
|