@asteby/storefront-react 0.5.0 → 0.7.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/README.md +41 -0
- package/dist/index.cjs +167 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +104 -1
- package/dist/index.d.ts +104 -1
- package/dist/index.js +163 -2
- package/dist/index.js.map +1 -1
- package/dist/ui.cjs +392 -0
- package/dist/ui.cjs.map +1 -0
- package/dist/ui.css +166 -0
- package/dist/ui.d.cts +137 -0
- package/dist/ui.d.ts +137 -0
- package/dist/ui.js +375 -0
- package/dist/ui.js.map +1 -0
- package/package.json +14 -3
package/dist/index.d.cts
CHANGED
|
@@ -420,6 +420,97 @@ type JsonLdProps = {
|
|
|
420
420
|
/** Renders `<script type="application/ld+json">` safely (works in SSR). */
|
|
421
421
|
declare function JsonLd({ data, nonce }: JsonLdProps): react.JSX.Element | null;
|
|
422
422
|
|
|
423
|
+
/** Types OPS ships built in; they cannot be redefined through the API. */
|
|
424
|
+
declare const OPS_BUILTIN_SECTION_TYPES: readonly ["hero", "product_grid", "collection_list", "rich_text", "faq", "image_with_text"];
|
|
425
|
+
declare const OPS_PROP_KINDS: readonly ["text", "textarea", "richtext", "image", "link", "number", "select", "boolean", "collection", "collection_list", "product", "product_list", "list"];
|
|
426
|
+
type OpsPropKind = (typeof OPS_PROP_KINDS)[number];
|
|
427
|
+
type OpsSectionProp = {
|
|
428
|
+
key: string;
|
|
429
|
+
kind: OpsPropKind;
|
|
430
|
+
label: string;
|
|
431
|
+
required?: boolean;
|
|
432
|
+
default?: unknown;
|
|
433
|
+
options?: {
|
|
434
|
+
value: string;
|
|
435
|
+
label: string;
|
|
436
|
+
}[];
|
|
437
|
+
min?: number;
|
|
438
|
+
max?: number;
|
|
439
|
+
fields?: OpsSectionProp[];
|
|
440
|
+
};
|
|
441
|
+
type OpsSectionType = {
|
|
442
|
+
type: string;
|
|
443
|
+
label: string;
|
|
444
|
+
description?: string;
|
|
445
|
+
category?: string;
|
|
446
|
+
schema: {
|
|
447
|
+
props: OpsSectionProp[];
|
|
448
|
+
};
|
|
449
|
+
max_per_page?: number;
|
|
450
|
+
};
|
|
451
|
+
type SectionTypeIssue = {
|
|
452
|
+
/** Dotted path, e.g. `promo.schema.props[1].fields[0].key`. */
|
|
453
|
+
path: string;
|
|
454
|
+
message: string;
|
|
455
|
+
};
|
|
456
|
+
type SectionTypeWarning = {
|
|
457
|
+
type: string;
|
|
458
|
+
/** Prop key when the warning is about a single prop. */
|
|
459
|
+
prop?: string;
|
|
460
|
+
message: string;
|
|
461
|
+
};
|
|
462
|
+
declare class SectionTypesValidationError extends Error {
|
|
463
|
+
readonly issues: SectionTypeIssue[];
|
|
464
|
+
constructor(issues: SectionTypeIssue[]);
|
|
465
|
+
}
|
|
466
|
+
type ToOpsOptions = {
|
|
467
|
+
/** Skip OPS built-in types (default true). */
|
|
468
|
+
excludeBuiltin?: boolean;
|
|
469
|
+
/**
|
|
470
|
+
* Prop keys OPS already knows for each built-in type (e.g. `{ hero: ['title','subtitle'] }`).
|
|
471
|
+
* With it, only the extra local props are warned about; without it, every
|
|
472
|
+
* locally-defined built-in type gets one generic warning.
|
|
473
|
+
*/
|
|
474
|
+
builtinProps?: Record<string, readonly string[]>;
|
|
475
|
+
};
|
|
476
|
+
type ToOpsResult = {
|
|
477
|
+
types: OpsSectionType[];
|
|
478
|
+
warnings: SectionTypeWarning[];
|
|
479
|
+
};
|
|
480
|
+
/** Local mirror of the OPS validation, so mistakes surface before the request. */
|
|
481
|
+
declare function validateOpsSectionTypes(types: readonly OpsSectionType[]): SectionTypeIssue[];
|
|
482
|
+
type DefinitionsSource = {
|
|
483
|
+
definitions(): SectionDefinition<any, any>[];
|
|
484
|
+
} | readonly SectionDefinition<any, any>[];
|
|
485
|
+
/**
|
|
486
|
+
* Converts the registry (or a list of definitions) to OPS section types.
|
|
487
|
+
* Throws `SectionTypesValidationError` (with `issues`) when something would
|
|
488
|
+
* be rejected by OPS.
|
|
489
|
+
*/
|
|
490
|
+
declare function sectionTypesToOps(source: DefinitionsSource, options?: ToOpsOptions): ToOpsResult;
|
|
491
|
+
type SectionTypesTarget = {
|
|
492
|
+
request<T>(spec: {
|
|
493
|
+
method: 'PUT';
|
|
494
|
+
path: string;
|
|
495
|
+
body?: unknown;
|
|
496
|
+
}): Promise<T>;
|
|
497
|
+
} | {
|
|
498
|
+
baseUrl: string;
|
|
499
|
+
token: string;
|
|
500
|
+
fetch?: typeof fetch;
|
|
501
|
+
};
|
|
502
|
+
type SyncResult = {
|
|
503
|
+
created: number;
|
|
504
|
+
updated: number;
|
|
505
|
+
warnings: SectionTypeWarning[];
|
|
506
|
+
};
|
|
507
|
+
/**
|
|
508
|
+
* Validates locally and then `PUT`s the section types to OPS. Needs an `sk_`
|
|
509
|
+
* token with `content:write`. `target` is a `createStorefrontClient()` client or
|
|
510
|
+
* `{ baseUrl, token, fetch? }`. Returns `{ created, updated, warnings }`.
|
|
511
|
+
*/
|
|
512
|
+
declare function syncSectionTypes(target: SectionTypesTarget, source: DefinitionsSource, options?: ToOpsOptions): Promise<SyncResult>;
|
|
513
|
+
|
|
423
514
|
type SectionPropKind = 'text' | 'textarea' | 'richtext' | 'number' | 'boolean' | 'url' | 'image' | 'color' | 'select' | 'collection' | 'product' | 'products' | 'list';
|
|
424
515
|
type SectionPropSchema = {
|
|
425
516
|
label: string;
|
|
@@ -465,6 +556,10 @@ type SectionDefinition<P = Record<string, unknown>, C = any> = {
|
|
|
465
556
|
type: string;
|
|
466
557
|
label?: string;
|
|
467
558
|
description?: string;
|
|
559
|
+
/** OPS editor grouping (only used when exporting to OPS). */
|
|
560
|
+
category?: string;
|
|
561
|
+
/** Max instances per page (only used when exporting to OPS). */
|
|
562
|
+
maxPerPage?: number;
|
|
468
563
|
schema: SectionSchema;
|
|
469
564
|
component: ComponentType<SectionComponentProps<P, C>>;
|
|
470
565
|
};
|
|
@@ -485,6 +580,8 @@ declare function defineSection<const S extends SectionSchema, C = any>(definitio
|
|
|
485
580
|
type: string;
|
|
486
581
|
label?: string;
|
|
487
582
|
description?: string;
|
|
583
|
+
category?: string;
|
|
584
|
+
maxPerPage?: number;
|
|
488
585
|
schema: S;
|
|
489
586
|
component: ComponentType<SectionComponentProps<InferSectionProps<S>, C>>;
|
|
490
587
|
}): SectionDefinition<InferSectionProps<S>, C>;
|
|
@@ -513,6 +610,12 @@ declare class SectionRegistry {
|
|
|
513
610
|
definitions(): SectionDefinition<any, any>[];
|
|
514
611
|
/** JSON Schemas of every registered section, keyed by type. */
|
|
515
612
|
toJSONSchema(): Record<string, Record<string, unknown>>;
|
|
613
|
+
/**
|
|
614
|
+
* Section types in the OPS `storefront_content` format, ready for
|
|
615
|
+
* `PUT /storefront/content/section-types`. Throws `SectionTypesValidationError`
|
|
616
|
+
* on anything OPS would reject; `warnings` flags built-in types.
|
|
617
|
+
*/
|
|
618
|
+
toOpsSectionTypes(options?: ToOpsOptions): ToOpsResult;
|
|
516
619
|
}
|
|
517
620
|
declare function createSectionRegistry(definitions?: readonly SectionDefinition<any, any>[]): SectionRegistry;
|
|
518
621
|
type SectionsProps<C = unknown> = {
|
|
@@ -773,4 +876,4 @@ type NearestLocationFormProps<L extends ShopBranch = ShopBranch> = {
|
|
|
773
876
|
*/
|
|
774
877
|
declare function NearestLocationForm<L extends ShopBranch = ShopBranch>({ locations, action, name, defaultValue, onSubmitPostalCode, onLocate, labels, children, ...rest }: NearestLocationFormProps<L>): react.JSX.Element | null;
|
|
775
878
|
|
|
776
|
-
export { AddToCartButton, type AddToCartButtonProps, AvailabilityBadge, type AvailabilityBadgeProps, type AvailabilityInput, type BreadcrumbItem, CART_COOKIE_NAME, type CartContextValue, type CartCookieOptions, type CartLineAddInput, CartLineProblem, type CartLineProblemProps, CartProvider, type CartProviderProps, type CartStatus, DirectionsLink, type DirectionsLinkProps, type FaqItem, type GeolocationErrorCode, type GeolocationFailure, type GeolocationPermission, type InferSectionProps, JsonLd, type JsonLdObject, type JsonLdProps, type LocalBusinessOptions, type LocationItemState, LocationList, type LocationListProps, LocationPicker, type LocationPickerProps, type MetaDescriptor, type NearbyLocation, NearestLocationForm, type NearestLocationFormLabels, type NearestLocationFormProps, OpenStatus, type OpenStatusLabels, type OpenStatusProps, type PickupInfo, PickupOption, type PickupOptionProps, type ProductOptionState, type ProductOptionValueState, type ProductOptionsState, RestockNotifyForm, type RestockNotifyFormProps, SELECTED_LOCATION_PARAM, SELECTED_LOCATION_STORAGE_KEY, type SectionComponentProps, type SectionDefinition, type SectionPropError, type SectionPropKind, type SectionPropSchema, SectionRegistry, type SectionSchema, Sections, type SectionsProps, type SeoMetaInput, SrOnly, StockConflictAlert, type StockConflictAlertProps, type StorefrontContextValue, StorefrontProvider, type StorefrontProviderProps, type ThemeCssOptions, ThemeStyle, type ThemeStyleProps, type UseGeolocationOptions, type UseGeolocationResult, type UseNearestLocationsOptions, type UseNearestLocationsResult, type UseProductOptionsConfig, type UseSelectedLocationOptions, type UseSelectedLocationResult, VariantOptionState, type VariantOptionStateProps, VariantSelector, type VariantSelectorProps, type VariantSelectorRenderProps, breadcrumbJsonLd, collectionJsonLd, collectionMeta, createSectionRegistry, defineSection, faqJsonLd, getCartIdFromCookie, isSafeCssValue, localBusinessJsonLd, openingHoursJsonLd, optimisticCart, organizationJsonLd, productJsonLd, productMeta, readCartCookie, readSelectedLocationId, resolveSectionProps, sectionJsonSchema, seoMeta, serializeCartCookie, serializeJsonLd, themeFontsHref, themeToCss, themeToCssVariables, toMerchandise, tokenName, useAvailability, useCart, useGeolocation, useNearestLocations, useOptionalCart, useOptionalStorefront, useProductOptions, useSelectedLocation, useStorefront, useStorefrontClient, writeCartCookie };
|
|
879
|
+
export { AddToCartButton, type AddToCartButtonProps, AvailabilityBadge, type AvailabilityBadgeProps, type AvailabilityInput, type BreadcrumbItem, CART_COOKIE_NAME, type CartContextValue, type CartCookieOptions, type CartLineAddInput, CartLineProblem, type CartLineProblemProps, CartProvider, type CartProviderProps, type CartStatus, DirectionsLink, type DirectionsLinkProps, type FaqItem, type GeolocationErrorCode, type GeolocationFailure, type GeolocationPermission, type InferSectionProps, JsonLd, type JsonLdObject, type JsonLdProps, type LocalBusinessOptions, type LocationItemState, LocationList, type LocationListProps, LocationPicker, type LocationPickerProps, type MetaDescriptor, type NearbyLocation, NearestLocationForm, type NearestLocationFormLabels, type NearestLocationFormProps, OPS_BUILTIN_SECTION_TYPES, OPS_PROP_KINDS, OpenStatus, type OpenStatusLabels, type OpenStatusProps, type OpsPropKind, type OpsSectionProp, type OpsSectionType, type PickupInfo, PickupOption, type PickupOptionProps, type ProductOptionState, type ProductOptionValueState, type ProductOptionsState, RestockNotifyForm, type RestockNotifyFormProps, SELECTED_LOCATION_PARAM, SELECTED_LOCATION_STORAGE_KEY, type SectionComponentProps, type SectionDefinition, type SectionPropError, type SectionPropKind, type SectionPropSchema, SectionRegistry, type SectionSchema, type SectionTypeIssue, type SectionTypeWarning, type SectionTypesTarget, SectionTypesValidationError, Sections, type SectionsProps, type SeoMetaInput, SrOnly, StockConflictAlert, type StockConflictAlertProps, type StorefrontContextValue, StorefrontProvider, type StorefrontProviderProps, type SyncResult, type ThemeCssOptions, ThemeStyle, type ThemeStyleProps, type ToOpsOptions, type ToOpsResult, type UseGeolocationOptions, type UseGeolocationResult, type UseNearestLocationsOptions, type UseNearestLocationsResult, type UseProductOptionsConfig, type UseSelectedLocationOptions, type UseSelectedLocationResult, VariantOptionState, type VariantOptionStateProps, VariantSelector, type VariantSelectorProps, type VariantSelectorRenderProps, breadcrumbJsonLd, collectionJsonLd, collectionMeta, createSectionRegistry, defineSection, faqJsonLd, getCartIdFromCookie, isSafeCssValue, localBusinessJsonLd, openingHoursJsonLd, optimisticCart, organizationJsonLd, productJsonLd, productMeta, readCartCookie, readSelectedLocationId, resolveSectionProps, sectionJsonSchema, sectionTypesToOps, seoMeta, serializeCartCookie, serializeJsonLd, syncSectionTypes, themeFontsHref, themeToCss, themeToCssVariables, toMerchandise, tokenName, useAvailability, useCart, useGeolocation, useNearestLocations, useOptionalCart, useOptionalStorefront, useProductOptions, useSelectedLocation, useStorefront, useStorefrontClient, validateOpsSectionTypes, writeCartCookie };
|
package/dist/index.d.ts
CHANGED
|
@@ -420,6 +420,97 @@ type JsonLdProps = {
|
|
|
420
420
|
/** Renders `<script type="application/ld+json">` safely (works in SSR). */
|
|
421
421
|
declare function JsonLd({ data, nonce }: JsonLdProps): react.JSX.Element | null;
|
|
422
422
|
|
|
423
|
+
/** Types OPS ships built in; they cannot be redefined through the API. */
|
|
424
|
+
declare const OPS_BUILTIN_SECTION_TYPES: readonly ["hero", "product_grid", "collection_list", "rich_text", "faq", "image_with_text"];
|
|
425
|
+
declare const OPS_PROP_KINDS: readonly ["text", "textarea", "richtext", "image", "link", "number", "select", "boolean", "collection", "collection_list", "product", "product_list", "list"];
|
|
426
|
+
type OpsPropKind = (typeof OPS_PROP_KINDS)[number];
|
|
427
|
+
type OpsSectionProp = {
|
|
428
|
+
key: string;
|
|
429
|
+
kind: OpsPropKind;
|
|
430
|
+
label: string;
|
|
431
|
+
required?: boolean;
|
|
432
|
+
default?: unknown;
|
|
433
|
+
options?: {
|
|
434
|
+
value: string;
|
|
435
|
+
label: string;
|
|
436
|
+
}[];
|
|
437
|
+
min?: number;
|
|
438
|
+
max?: number;
|
|
439
|
+
fields?: OpsSectionProp[];
|
|
440
|
+
};
|
|
441
|
+
type OpsSectionType = {
|
|
442
|
+
type: string;
|
|
443
|
+
label: string;
|
|
444
|
+
description?: string;
|
|
445
|
+
category?: string;
|
|
446
|
+
schema: {
|
|
447
|
+
props: OpsSectionProp[];
|
|
448
|
+
};
|
|
449
|
+
max_per_page?: number;
|
|
450
|
+
};
|
|
451
|
+
type SectionTypeIssue = {
|
|
452
|
+
/** Dotted path, e.g. `promo.schema.props[1].fields[0].key`. */
|
|
453
|
+
path: string;
|
|
454
|
+
message: string;
|
|
455
|
+
};
|
|
456
|
+
type SectionTypeWarning = {
|
|
457
|
+
type: string;
|
|
458
|
+
/** Prop key when the warning is about a single prop. */
|
|
459
|
+
prop?: string;
|
|
460
|
+
message: string;
|
|
461
|
+
};
|
|
462
|
+
declare class SectionTypesValidationError extends Error {
|
|
463
|
+
readonly issues: SectionTypeIssue[];
|
|
464
|
+
constructor(issues: SectionTypeIssue[]);
|
|
465
|
+
}
|
|
466
|
+
type ToOpsOptions = {
|
|
467
|
+
/** Skip OPS built-in types (default true). */
|
|
468
|
+
excludeBuiltin?: boolean;
|
|
469
|
+
/**
|
|
470
|
+
* Prop keys OPS already knows for each built-in type (e.g. `{ hero: ['title','subtitle'] }`).
|
|
471
|
+
* With it, only the extra local props are warned about; without it, every
|
|
472
|
+
* locally-defined built-in type gets one generic warning.
|
|
473
|
+
*/
|
|
474
|
+
builtinProps?: Record<string, readonly string[]>;
|
|
475
|
+
};
|
|
476
|
+
type ToOpsResult = {
|
|
477
|
+
types: OpsSectionType[];
|
|
478
|
+
warnings: SectionTypeWarning[];
|
|
479
|
+
};
|
|
480
|
+
/** Local mirror of the OPS validation, so mistakes surface before the request. */
|
|
481
|
+
declare function validateOpsSectionTypes(types: readonly OpsSectionType[]): SectionTypeIssue[];
|
|
482
|
+
type DefinitionsSource = {
|
|
483
|
+
definitions(): SectionDefinition<any, any>[];
|
|
484
|
+
} | readonly SectionDefinition<any, any>[];
|
|
485
|
+
/**
|
|
486
|
+
* Converts the registry (or a list of definitions) to OPS section types.
|
|
487
|
+
* Throws `SectionTypesValidationError` (with `issues`) when something would
|
|
488
|
+
* be rejected by OPS.
|
|
489
|
+
*/
|
|
490
|
+
declare function sectionTypesToOps(source: DefinitionsSource, options?: ToOpsOptions): ToOpsResult;
|
|
491
|
+
type SectionTypesTarget = {
|
|
492
|
+
request<T>(spec: {
|
|
493
|
+
method: 'PUT';
|
|
494
|
+
path: string;
|
|
495
|
+
body?: unknown;
|
|
496
|
+
}): Promise<T>;
|
|
497
|
+
} | {
|
|
498
|
+
baseUrl: string;
|
|
499
|
+
token: string;
|
|
500
|
+
fetch?: typeof fetch;
|
|
501
|
+
};
|
|
502
|
+
type SyncResult = {
|
|
503
|
+
created: number;
|
|
504
|
+
updated: number;
|
|
505
|
+
warnings: SectionTypeWarning[];
|
|
506
|
+
};
|
|
507
|
+
/**
|
|
508
|
+
* Validates locally and then `PUT`s the section types to OPS. Needs an `sk_`
|
|
509
|
+
* token with `content:write`. `target` is a `createStorefrontClient()` client or
|
|
510
|
+
* `{ baseUrl, token, fetch? }`. Returns `{ created, updated, warnings }`.
|
|
511
|
+
*/
|
|
512
|
+
declare function syncSectionTypes(target: SectionTypesTarget, source: DefinitionsSource, options?: ToOpsOptions): Promise<SyncResult>;
|
|
513
|
+
|
|
423
514
|
type SectionPropKind = 'text' | 'textarea' | 'richtext' | 'number' | 'boolean' | 'url' | 'image' | 'color' | 'select' | 'collection' | 'product' | 'products' | 'list';
|
|
424
515
|
type SectionPropSchema = {
|
|
425
516
|
label: string;
|
|
@@ -465,6 +556,10 @@ type SectionDefinition<P = Record<string, unknown>, C = any> = {
|
|
|
465
556
|
type: string;
|
|
466
557
|
label?: string;
|
|
467
558
|
description?: string;
|
|
559
|
+
/** OPS editor grouping (only used when exporting to OPS). */
|
|
560
|
+
category?: string;
|
|
561
|
+
/** Max instances per page (only used when exporting to OPS). */
|
|
562
|
+
maxPerPage?: number;
|
|
468
563
|
schema: SectionSchema;
|
|
469
564
|
component: ComponentType<SectionComponentProps<P, C>>;
|
|
470
565
|
};
|
|
@@ -485,6 +580,8 @@ declare function defineSection<const S extends SectionSchema, C = any>(definitio
|
|
|
485
580
|
type: string;
|
|
486
581
|
label?: string;
|
|
487
582
|
description?: string;
|
|
583
|
+
category?: string;
|
|
584
|
+
maxPerPage?: number;
|
|
488
585
|
schema: S;
|
|
489
586
|
component: ComponentType<SectionComponentProps<InferSectionProps<S>, C>>;
|
|
490
587
|
}): SectionDefinition<InferSectionProps<S>, C>;
|
|
@@ -513,6 +610,12 @@ declare class SectionRegistry {
|
|
|
513
610
|
definitions(): SectionDefinition<any, any>[];
|
|
514
611
|
/** JSON Schemas of every registered section, keyed by type. */
|
|
515
612
|
toJSONSchema(): Record<string, Record<string, unknown>>;
|
|
613
|
+
/**
|
|
614
|
+
* Section types in the OPS `storefront_content` format, ready for
|
|
615
|
+
* `PUT /storefront/content/section-types`. Throws `SectionTypesValidationError`
|
|
616
|
+
* on anything OPS would reject; `warnings` flags built-in types.
|
|
617
|
+
*/
|
|
618
|
+
toOpsSectionTypes(options?: ToOpsOptions): ToOpsResult;
|
|
516
619
|
}
|
|
517
620
|
declare function createSectionRegistry(definitions?: readonly SectionDefinition<any, any>[]): SectionRegistry;
|
|
518
621
|
type SectionsProps<C = unknown> = {
|
|
@@ -773,4 +876,4 @@ type NearestLocationFormProps<L extends ShopBranch = ShopBranch> = {
|
|
|
773
876
|
*/
|
|
774
877
|
declare function NearestLocationForm<L extends ShopBranch = ShopBranch>({ locations, action, name, defaultValue, onSubmitPostalCode, onLocate, labels, children, ...rest }: NearestLocationFormProps<L>): react.JSX.Element | null;
|
|
775
878
|
|
|
776
|
-
export { AddToCartButton, type AddToCartButtonProps, AvailabilityBadge, type AvailabilityBadgeProps, type AvailabilityInput, type BreadcrumbItem, CART_COOKIE_NAME, type CartContextValue, type CartCookieOptions, type CartLineAddInput, CartLineProblem, type CartLineProblemProps, CartProvider, type CartProviderProps, type CartStatus, DirectionsLink, type DirectionsLinkProps, type FaqItem, type GeolocationErrorCode, type GeolocationFailure, type GeolocationPermission, type InferSectionProps, JsonLd, type JsonLdObject, type JsonLdProps, type LocalBusinessOptions, type LocationItemState, LocationList, type LocationListProps, LocationPicker, type LocationPickerProps, type MetaDescriptor, type NearbyLocation, NearestLocationForm, type NearestLocationFormLabels, type NearestLocationFormProps, OpenStatus, type OpenStatusLabels, type OpenStatusProps, type PickupInfo, PickupOption, type PickupOptionProps, type ProductOptionState, type ProductOptionValueState, type ProductOptionsState, RestockNotifyForm, type RestockNotifyFormProps, SELECTED_LOCATION_PARAM, SELECTED_LOCATION_STORAGE_KEY, type SectionComponentProps, type SectionDefinition, type SectionPropError, type SectionPropKind, type SectionPropSchema, SectionRegistry, type SectionSchema, Sections, type SectionsProps, type SeoMetaInput, SrOnly, StockConflictAlert, type StockConflictAlertProps, type StorefrontContextValue, StorefrontProvider, type StorefrontProviderProps, type ThemeCssOptions, ThemeStyle, type ThemeStyleProps, type UseGeolocationOptions, type UseGeolocationResult, type UseNearestLocationsOptions, type UseNearestLocationsResult, type UseProductOptionsConfig, type UseSelectedLocationOptions, type UseSelectedLocationResult, VariantOptionState, type VariantOptionStateProps, VariantSelector, type VariantSelectorProps, type VariantSelectorRenderProps, breadcrumbJsonLd, collectionJsonLd, collectionMeta, createSectionRegistry, defineSection, faqJsonLd, getCartIdFromCookie, isSafeCssValue, localBusinessJsonLd, openingHoursJsonLd, optimisticCart, organizationJsonLd, productJsonLd, productMeta, readCartCookie, readSelectedLocationId, resolveSectionProps, sectionJsonSchema, seoMeta, serializeCartCookie, serializeJsonLd, themeFontsHref, themeToCss, themeToCssVariables, toMerchandise, tokenName, useAvailability, useCart, useGeolocation, useNearestLocations, useOptionalCart, useOptionalStorefront, useProductOptions, useSelectedLocation, useStorefront, useStorefrontClient, writeCartCookie };
|
|
879
|
+
export { AddToCartButton, type AddToCartButtonProps, AvailabilityBadge, type AvailabilityBadgeProps, type AvailabilityInput, type BreadcrumbItem, CART_COOKIE_NAME, type CartContextValue, type CartCookieOptions, type CartLineAddInput, CartLineProblem, type CartLineProblemProps, CartProvider, type CartProviderProps, type CartStatus, DirectionsLink, type DirectionsLinkProps, type FaqItem, type GeolocationErrorCode, type GeolocationFailure, type GeolocationPermission, type InferSectionProps, JsonLd, type JsonLdObject, type JsonLdProps, type LocalBusinessOptions, type LocationItemState, LocationList, type LocationListProps, LocationPicker, type LocationPickerProps, type MetaDescriptor, type NearbyLocation, NearestLocationForm, type NearestLocationFormLabels, type NearestLocationFormProps, OPS_BUILTIN_SECTION_TYPES, OPS_PROP_KINDS, OpenStatus, type OpenStatusLabels, type OpenStatusProps, type OpsPropKind, type OpsSectionProp, type OpsSectionType, type PickupInfo, PickupOption, type PickupOptionProps, type ProductOptionState, type ProductOptionValueState, type ProductOptionsState, RestockNotifyForm, type RestockNotifyFormProps, SELECTED_LOCATION_PARAM, SELECTED_LOCATION_STORAGE_KEY, type SectionComponentProps, type SectionDefinition, type SectionPropError, type SectionPropKind, type SectionPropSchema, SectionRegistry, type SectionSchema, type SectionTypeIssue, type SectionTypeWarning, type SectionTypesTarget, SectionTypesValidationError, Sections, type SectionsProps, type SeoMetaInput, SrOnly, StockConflictAlert, type StockConflictAlertProps, type StorefrontContextValue, StorefrontProvider, type StorefrontProviderProps, type SyncResult, type ThemeCssOptions, ThemeStyle, type ThemeStyleProps, type ToOpsOptions, type ToOpsResult, type UseGeolocationOptions, type UseGeolocationResult, type UseNearestLocationsOptions, type UseNearestLocationsResult, type UseProductOptionsConfig, type UseSelectedLocationOptions, type UseSelectedLocationResult, VariantOptionState, type VariantOptionStateProps, VariantSelector, type VariantSelectorProps, type VariantSelectorRenderProps, breadcrumbJsonLd, collectionJsonLd, collectionMeta, createSectionRegistry, defineSection, faqJsonLd, getCartIdFromCookie, isSafeCssValue, localBusinessJsonLd, openingHoursJsonLd, optimisticCart, organizationJsonLd, productJsonLd, productMeta, readCartCookie, readSelectedLocationId, resolveSectionProps, sectionJsonSchema, sectionTypesToOps, seoMeta, serializeCartCookie, serializeJsonLd, syncSectionTypes, themeFontsHref, themeToCss, themeToCssVariables, toMerchandise, tokenName, useAvailability, useCart, useGeolocation, useNearestLocations, useOptionalCart, useOptionalStorefront, useProductOptions, useSelectedLocation, useStorefront, useStorefrontClient, validateOpsSectionTypes, writeCartCookie };
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ export { ThemeStyle, isSafeCssValue, themeFontsHref, themeToCss, themeToCssVaria
|
|
|
3
3
|
import { useOptionalStorefront } from './chunk-DQBL2DFJ.js';
|
|
4
4
|
export { StorefrontProvider, useOptionalStorefront, useStorefront, useStorefrontClient } from './chunk-DQBL2DFJ.js';
|
|
5
5
|
import { createContext, useRef, useState, useCallback, useEffect, useMemo, useContext, Fragment as Fragment$1, useId } from 'react';
|
|
6
|
-
import { resolveAvailability, productAvailability, availabilityView, availabilityMessages, formatAvailabilityMessage, cartLineProblemView, isStorefrontError, schemaAvailability, formatMoney } from '@asteby/storefront';
|
|
6
|
+
import { resolveAvailability, productAvailability, availabilityView, availabilityMessages, formatAvailabilityMessage, cartLineProblemView, isStorefrontError, schemaAvailability, StorefrontError, formatMoney } from '@asteby/storefront';
|
|
7
7
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
8
8
|
import { toSchemaOpeningHours, isValidPoint, rankByDistance, openStatus, directionsUrl } from '@asteby/storefront/geo';
|
|
9
9
|
|
|
@@ -857,6 +857,156 @@ function JsonLd({ data, nonce }) {
|
|
|
857
857
|
if (!data || Array.isArray(data) && data.length === 0) return null;
|
|
858
858
|
return /* @__PURE__ */ jsx("script", { type: "application/ld+json", nonce, dangerouslySetInnerHTML: { __html: serializeJsonLd(data) } });
|
|
859
859
|
}
|
|
860
|
+
var OPS_BUILTIN_SECTION_TYPES = ["hero", "product_grid", "collection_list", "rich_text", "faq", "image_with_text"];
|
|
861
|
+
var OPS_PROP_KINDS = ["text", "textarea", "richtext", "image", "link", "number", "select", "boolean", "collection", "collection_list", "product", "product_list", "list"];
|
|
862
|
+
var SectionTypesValidationError = class extends Error {
|
|
863
|
+
issues;
|
|
864
|
+
constructor(issues) {
|
|
865
|
+
super(`Invalid section types for OPS:
|
|
866
|
+
${issues.map((i) => ` - ${i.path}: ${i.message}`).join("\n")}`);
|
|
867
|
+
this.name = "SectionTypesValidationError";
|
|
868
|
+
this.issues = issues;
|
|
869
|
+
}
|
|
870
|
+
};
|
|
871
|
+
var SNAKE = /^[a-z][a-z0-9]*(_[a-z0-9]+)*$/;
|
|
872
|
+
var KIND_MAP = {
|
|
873
|
+
text: "text",
|
|
874
|
+
textarea: "textarea",
|
|
875
|
+
richtext: "richtext",
|
|
876
|
+
url: "text",
|
|
877
|
+
color: "text",
|
|
878
|
+
image: "image",
|
|
879
|
+
number: "number",
|
|
880
|
+
boolean: "boolean",
|
|
881
|
+
select: "select",
|
|
882
|
+
collection: "collection",
|
|
883
|
+
product: "product",
|
|
884
|
+
products: "product_list",
|
|
885
|
+
list: "list"
|
|
886
|
+
};
|
|
887
|
+
var LIST_KINDS = /* @__PURE__ */ new Set(["list"]);
|
|
888
|
+
function convertProps(schema, path, issues) {
|
|
889
|
+
const out = [];
|
|
890
|
+
for (const [key, spec] of Object.entries(schema ?? {})) {
|
|
891
|
+
const p = `${path}.${key}`;
|
|
892
|
+
const kind = KIND_MAP[spec.kind];
|
|
893
|
+
if (!kind) {
|
|
894
|
+
issues.push({ path: `${p}.kind`, message: `unknown kind "${String(spec.kind)}"` });
|
|
895
|
+
continue;
|
|
896
|
+
}
|
|
897
|
+
const prop = { key, kind, label: spec.label };
|
|
898
|
+
if (spec.required) prop.required = true;
|
|
899
|
+
if ("default" in spec && spec.default !== void 0) prop.default = spec.default;
|
|
900
|
+
if (spec.options) prop.options = spec.options.map((o) => ({ value: o.value, label: o.label }));
|
|
901
|
+
if (spec.min !== void 0) prop.min = spec.min;
|
|
902
|
+
if (spec.max !== void 0) prop.max = spec.max;
|
|
903
|
+
if (LIST_KINDS.has(kind)) prop.fields = convertProps(spec.items, `${p}.fields`, issues);
|
|
904
|
+
out.push(prop);
|
|
905
|
+
}
|
|
906
|
+
return out;
|
|
907
|
+
}
|
|
908
|
+
function validateOpsSectionTypes(types) {
|
|
909
|
+
const issues = [];
|
|
910
|
+
const seen = /* @__PURE__ */ new Set();
|
|
911
|
+
const walk = (props, path) => {
|
|
912
|
+
if (!Array.isArray(props)) {
|
|
913
|
+
issues.push({ path, message: "must be a list" });
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
const keys = /* @__PURE__ */ new Set();
|
|
917
|
+
props.forEach((prop, i) => {
|
|
918
|
+
const p = `${path}[${i}]`;
|
|
919
|
+
if (typeof prop.key !== "string" || !SNAKE.test(prop.key)) issues.push({ path: `${p}.key`, message: `"${String(prop.key)}" must be snake_case (a-z, 0-9, _)` });
|
|
920
|
+
else if (keys.has(prop.key)) issues.push({ path: `${p}.key`, message: `duplicate key "${prop.key}"` });
|
|
921
|
+
else keys.add(prop.key);
|
|
922
|
+
if (typeof prop.label !== "string" || !prop.label.trim()) issues.push({ path: `${p}.label`, message: "label is required" });
|
|
923
|
+
if (!OPS_PROP_KINDS.includes(prop.kind)) {
|
|
924
|
+
issues.push({ path: `${p}.kind`, message: `unknown kind "${String(prop.kind)}"` });
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
if (prop.kind === "list") {
|
|
928
|
+
if (!prop.fields || prop.fields.length === 0) issues.push({ path: `${p}.fields`, message: 'list requires a non-empty "fields"' });
|
|
929
|
+
else walk(prop.fields, `${p}.fields`);
|
|
930
|
+
}
|
|
931
|
+
if (prop.kind === "select" && (!prop.options || prop.options.length === 0)) issues.push({ path: `${p}.options`, message: 'select requires non-empty "options"' });
|
|
932
|
+
if (prop.min !== void 0 && prop.max !== void 0 && prop.min > prop.max) issues.push({ path: `${p}.max`, message: "max must be >= min" });
|
|
933
|
+
});
|
|
934
|
+
};
|
|
935
|
+
types.forEach((t, i) => {
|
|
936
|
+
const p = t.type ? t.type : `[${i}]`;
|
|
937
|
+
if (!t.type || !t.type.trim()) issues.push({ path: `${p}.type`, message: "type is required" });
|
|
938
|
+
else if (seen.has(t.type)) issues.push({ path: `${p}.type`, message: `duplicate type "${t.type}"` });
|
|
939
|
+
else seen.add(t.type);
|
|
940
|
+
if (!t.label || !t.label.trim()) issues.push({ path: `${p}.label`, message: "label is required" });
|
|
941
|
+
if (t.max_per_page !== void 0 && (!Number.isInteger(t.max_per_page) || t.max_per_page < 1)) issues.push({ path: `${p}.max_per_page`, message: "must be a positive integer" });
|
|
942
|
+
walk(t.schema?.props, `${p}.schema.props`);
|
|
943
|
+
});
|
|
944
|
+
return issues;
|
|
945
|
+
}
|
|
946
|
+
function sectionTypesToOps(source, options = {}) {
|
|
947
|
+
const excludeBuiltin = options.excludeBuiltin ?? true;
|
|
948
|
+
const defs = Array.isArray(source) ? source : source.definitions();
|
|
949
|
+
const builtin = new Set(OPS_BUILTIN_SECTION_TYPES);
|
|
950
|
+
const issues = [];
|
|
951
|
+
const warnings = [];
|
|
952
|
+
const types = [];
|
|
953
|
+
for (const def of defs) {
|
|
954
|
+
if (excludeBuiltin && builtin.has(def.type)) {
|
|
955
|
+
const known = options.builtinProps?.[def.type];
|
|
956
|
+
if (known) {
|
|
957
|
+
for (const name of Object.keys(def.schema ?? {})) {
|
|
958
|
+
if (!known.includes(name)) warnings.push({ type: def.type, prop: name, message: `prop "${name}" of built-in type "${def.type}" does not exist in the OPS schema; built-in types cannot be redefined, so it will not be editable in OPS` });
|
|
959
|
+
}
|
|
960
|
+
} else {
|
|
961
|
+
warnings.push({ type: def.type, message: `"${def.type}" is a built-in OPS type: not synced, and its local props cannot be verified against the OPS schema` });
|
|
962
|
+
}
|
|
963
|
+
continue;
|
|
964
|
+
}
|
|
965
|
+
const entryIssues = [];
|
|
966
|
+
const props = convertProps(def.schema, `${def.type}.schema.props`, entryIssues);
|
|
967
|
+
issues.push(...entryIssues);
|
|
968
|
+
const out = { type: def.type, label: def.label ?? def.type, schema: { props } };
|
|
969
|
+
if (def.description) out.description = def.description;
|
|
970
|
+
if (def.category) out.category = def.category;
|
|
971
|
+
if (def.maxPerPage !== void 0) out.max_per_page = def.maxPerPage;
|
|
972
|
+
types.push(out);
|
|
973
|
+
}
|
|
974
|
+
issues.push(...validateOpsSectionTypes(types));
|
|
975
|
+
if (issues.length) throw new SectionTypesValidationError(issues);
|
|
976
|
+
return { types, warnings };
|
|
977
|
+
}
|
|
978
|
+
var SYNC_PATH = "/storefront/content/section-types";
|
|
979
|
+
var count = (v) => Array.isArray(v) ? v.length : typeof v === "number" ? v : 0;
|
|
980
|
+
async function syncSectionTypes(target, source, options = {}) {
|
|
981
|
+
const { types, warnings } = sectionTypesToOps(source, options);
|
|
982
|
+
let raw;
|
|
983
|
+
if ("request" in target && typeof target.request === "function") {
|
|
984
|
+
raw = await target.request({ method: "PUT", path: SYNC_PATH, body: { section_types: types } });
|
|
985
|
+
} else {
|
|
986
|
+
const t = target;
|
|
987
|
+
if (!t.token.startsWith("sk_")) throw new TypeError("syncSectionTypes: an sk_ token with content:write is required");
|
|
988
|
+
const f = t.fetch ?? globalThis.fetch.bind(globalThis);
|
|
989
|
+
const url = t.baseUrl.replace(/\/+$/, "") + SYNC_PATH;
|
|
990
|
+
const res = await f(url, {
|
|
991
|
+
method: "PUT",
|
|
992
|
+
headers: { Authorization: `Bearer ${t.token}`, "Content-Type": "application/json", Accept: "application/json" },
|
|
993
|
+
body: JSON.stringify({ section_types: types })
|
|
994
|
+
});
|
|
995
|
+
const text = await res.text();
|
|
996
|
+
let body;
|
|
997
|
+
try {
|
|
998
|
+
body = text ? JSON.parse(text) : void 0;
|
|
999
|
+
} catch {
|
|
1000
|
+
body = void 0;
|
|
1001
|
+
}
|
|
1002
|
+
if (!res.ok) {
|
|
1003
|
+
throw new StorefrontError({ status: res.status, code: body?.code ?? body?.error?.code ?? "unknown", message: body?.message ?? body?.error?.message ?? `Section types sync failed (${res.status})`, url });
|
|
1004
|
+
}
|
|
1005
|
+
raw = body;
|
|
1006
|
+
}
|
|
1007
|
+
const data = raw && typeof raw === "object" && "data" in raw ? raw.data : raw;
|
|
1008
|
+
return { created: count(data?.created), updated: count(data?.updated), warnings };
|
|
1009
|
+
}
|
|
860
1010
|
function defineSection(definition) {
|
|
861
1011
|
return definition;
|
|
862
1012
|
}
|
|
@@ -880,6 +1030,9 @@ function resolveSectionProps(schema, raw, path = "") {
|
|
|
880
1030
|
else if (spec.required) errors.push({ prop: key, message: "is required" });
|
|
881
1031
|
continue;
|
|
882
1032
|
}
|
|
1033
|
+
if (spec.kind === "image" && typeof value === "object" && value !== null && typeof value.url === "string") {
|
|
1034
|
+
value = value.url;
|
|
1035
|
+
}
|
|
883
1036
|
if (STRING_KINDS.has(spec.kind)) {
|
|
884
1037
|
if (typeof value !== "string") {
|
|
885
1038
|
fail2("must be a string");
|
|
@@ -1003,6 +1156,14 @@ var SectionRegistry = class {
|
|
|
1003
1156
|
toJSONSchema() {
|
|
1004
1157
|
return Object.fromEntries(this.definitions().map((d) => [d.type, sectionJsonSchema(d)]));
|
|
1005
1158
|
}
|
|
1159
|
+
/**
|
|
1160
|
+
* Section types in the OPS `storefront_content` format, ready for
|
|
1161
|
+
* `PUT /storefront/content/section-types`. Throws `SectionTypesValidationError`
|
|
1162
|
+
* on anything OPS would reject; `warnings` flags built-in types.
|
|
1163
|
+
*/
|
|
1164
|
+
toOpsSectionTypes(options) {
|
|
1165
|
+
return sectionTypesToOps(this, options);
|
|
1166
|
+
}
|
|
1006
1167
|
};
|
|
1007
1168
|
function createSectionRegistry(definitions = []) {
|
|
1008
1169
|
return new SectionRegistry(definitions);
|
|
@@ -1377,6 +1538,6 @@ function NearestLocationForm({
|
|
|
1377
1538
|
);
|
|
1378
1539
|
}
|
|
1379
1540
|
|
|
1380
|
-
export { AddToCartButton, AvailabilityBadge, CART_COOKIE_NAME, CartLineProblem, CartProvider, DirectionsLink, JsonLd, LocationList, LocationPicker, NearestLocationForm, OpenStatus, PickupOption, RestockNotifyForm, SELECTED_LOCATION_PARAM, SELECTED_LOCATION_STORAGE_KEY, SectionRegistry, Sections, SrOnly, StockConflictAlert, VariantOptionState, VariantSelector, breadcrumbJsonLd, collectionJsonLd, collectionMeta, createSectionRegistry, defineSection, faqJsonLd, getCartIdFromCookie, localBusinessJsonLd, openingHoursJsonLd, optimisticCart, organizationJsonLd, productJsonLd, productMeta, readCartCookie, readSelectedLocationId, resolveSectionProps, sectionJsonSchema, seoMeta, serializeCartCookie, serializeJsonLd, toMerchandise, useAvailability, useCart, useGeolocation, useNearestLocations, useOptionalCart, useProductOptions, useSelectedLocation, writeCartCookie };
|
|
1541
|
+
export { AddToCartButton, AvailabilityBadge, CART_COOKIE_NAME, CartLineProblem, CartProvider, DirectionsLink, JsonLd, LocationList, LocationPicker, NearestLocationForm, OPS_BUILTIN_SECTION_TYPES, OPS_PROP_KINDS, OpenStatus, PickupOption, RestockNotifyForm, SELECTED_LOCATION_PARAM, SELECTED_LOCATION_STORAGE_KEY, SectionRegistry, SectionTypesValidationError, Sections, SrOnly, StockConflictAlert, VariantOptionState, VariantSelector, breadcrumbJsonLd, collectionJsonLd, collectionMeta, createSectionRegistry, defineSection, faqJsonLd, getCartIdFromCookie, localBusinessJsonLd, openingHoursJsonLd, optimisticCart, organizationJsonLd, productJsonLd, productMeta, readCartCookie, readSelectedLocationId, resolveSectionProps, sectionJsonSchema, sectionTypesToOps, seoMeta, serializeCartCookie, serializeJsonLd, syncSectionTypes, toMerchandise, useAvailability, useCart, useGeolocation, useNearestLocations, useOptionalCart, useProductOptions, useSelectedLocation, validateOpsSectionTypes, writeCartCookie };
|
|
1381
1542
|
//# sourceMappingURL=index.js.map
|
|
1382
1543
|
//# sourceMappingURL=index.js.map
|