@asteby/storefront-react 0.4.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/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode, ComponentPropsWithoutRef, ComponentType, FormEvent } from 'react';
3
- import { StorefrontClient, Shop, StorefrontClientOptions, Cart, CartLineInput, CartLineMerchandise, CartLineUpdateInput, CartBuyerInput, AddressInput, DeliveryInput, DeliveryOptions, ProductVariant, Product, Image, Collection, Section, Theme, GeoPoint, ShopBranch, Money } from '@asteby/storefront';
3
+ import { StorefrontClient, Shop, StorefrontClientOptions, Cart, CartLineInput, CartLineMerchandise, CartLineUpdateInput, CartBuyerInput, AddressInput, DeliveryInput, DeliveryOptions, Availability, ProductVariant, Product, resolveAvailability, AvailabilityMessages, CartLine, CartLineProblem as CartLineProblem$1, AvailabilityView, Image, Collection, ResolveAvailabilityOptions, Section, Theme, GeoPoint, ShopBranch, Money } from '@asteby/storefront';
4
4
  export { D as DEFAULT_IMAGE_WIDTHS, I as Image, a as ImageLoader, b as ImageProps, M as Money, c as MoneyProps, P as ProductPrice, d as ProductPriceProps, e as defaultImageLoader } from './components-B5XhSH-m.cjs';
5
5
  import { OpeningHours, GeoPoint as GeoPoint$1, OpenStatus as OpenStatus$1 } from '@asteby/storefront/geo';
6
6
 
@@ -135,6 +135,8 @@ type ProductOptionValueState = {
135
135
  available: boolean;
136
136
  /** The variant this value would select, if it exists. */
137
137
  variant: ProductVariant | null;
138
+ /** Availability of that variant (polyfilled for servers older than contract 1.1); with the other options not chosen yet, the best among matching variants. `null` when no variant matches. Feed it to `<VariantOptionState availability>`. */
139
+ availability: Availability | null;
138
140
  /** Query string (`?Talla=M&Color=Rojo`) selecting this value, preserving other params. */
139
141
  search: string;
140
142
  };
@@ -196,13 +198,130 @@ declare function toMerchandise(product: Pick<Product, 'handle' | 'title' | 'feat
196
198
  type AddToCartButtonProps = Omit<ComponentPropsWithoutRef<'button'>, 'onClick'> & {
197
199
  variantId: string | null | undefined;
198
200
  quantity?: number;
201
+ /**
202
+ * Availability of the variant (server `availability`, or the variant itself to polyfill). When given: the label
203
+ * comes from the server state ("Agotado", "Pedir bajo pedido"...) unless `children` is set, the button is
204
+ * disabled when it cannot be bought, and the quantity is capped at `max_per_order`.
205
+ */
206
+ availability?: Availability | null;
207
+ /** Variant to derive the availability from when the server did not send it. */
208
+ availabilitySource?: ProductVariant | null;
209
+ /** Polyfill only: shop-level low-stock threshold. */
210
+ lowStockThreshold?: number | null;
211
+ /** BCP 47; defaults to the provider locale. */
212
+ locale?: string;
199
213
  /** Variant data for an instant optimistic cart line. */
200
214
  merchandise?: CartLineMerchandise;
201
215
  onAdded?: () => void;
202
216
  onClick?: ComponentPropsWithoutRef<'button'>['onClick'];
203
217
  };
204
218
  /** Adds a variant to the cart via `useCart().addLines`. Disabled without a variant or while adding. */
205
- declare function AddToCartButton({ variantId, quantity, merchandise, onAdded, onClick, disabled, children, type, ...rest }: AddToCartButtonProps): react.JSX.Element;
219
+ declare function AddToCartButton({ variantId, quantity, availability, availabilitySource, lowStockThreshold, locale, merchandise, onAdded, onClick, disabled, children, type, ...rest }: AddToCartButtonProps): react.JSX.Element;
220
+
221
+ /** Visually hidden text for screen readers. */
222
+ declare function SrOnly({ children }: {
223
+ children: ReactNode;
224
+ }): react.JSX.Element;
225
+ type AvailabilitySource = Parameters<typeof resolveAvailability>[0];
226
+ type AvailabilityInput = {
227
+ /** Availability sent by the server. */
228
+ availability?: Availability | null;
229
+ /** Variant or product: used when `availability` is absent (polyfill for servers older than contract 1.1). */
230
+ source?: AvailabilitySource | null;
231
+ /** Polyfill only: shop-level low-stock threshold (never hard-coded here). */
232
+ lowStockThreshold?: number | null;
233
+ /** BCP 47; defaults to the provider locale, then `es-MX`. */
234
+ locale?: string;
235
+ /** Per-key text overrides. */
236
+ messages?: Partial<AvailabilityMessages>;
237
+ };
238
+ /** `AvailabilityView` for a server `availability` or a variant/product (polyfilled). `null` when nothing is given. */
239
+ declare function useAvailability(input: AvailabilityInput): AvailabilityView | null;
240
+ type AvailabilityBadgeProps = AvailabilityInput & {
241
+ /**
242
+ * `card` (listing): renders `null` for plain `in_stock` so cards are not saturated.
243
+ * `detail` (product page): always renders, with the ETA and the order cap.
244
+ */
245
+ placement?: 'card' | 'detail';
246
+ /** Announce changes (e.g. after the client refreshes the stock): `role="status"`. */
247
+ live?: boolean;
248
+ } & Omit<ComponentPropsWithoutRef<'span'>, 'children'>;
249
+ /**
250
+ * Availability label. `data-availability` is the status and `data-tone` the tone, so a
251
+ * card can dim its image with CSS (`[data-availability=out_of_stock]`).
252
+ */
253
+ declare function AvailabilityBadge({ availability, source, lowStockThreshold, locale, messages, placement, live, ...rest }: AvailabilityBadgeProps): react.JSX.Element | null;
254
+ type VariantOptionStateProps = AvailabilityInput & {
255
+ /** The option text (e.g. the flavor). */
256
+ children: ReactNode;
257
+ } & Omit<ComponentPropsWithoutRef<'span'>, 'children'>;
258
+ /**
259
+ * Content for one option of a flavor/variant selector. A sold-out option is struck through
260
+ * (`<s>`) and announced as "agotado" to screen readers; it stays selectable so the buyer can
261
+ * see it and subscribe. Backorder / preorder options get a visible tag. Plain in-stock: just the text.
262
+ * Without any availability it renders `children` untouched.
263
+ */
264
+ declare function VariantOptionState({ children, availability, source, lowStockThreshold, locale, messages, ...rest }: VariantOptionStateProps): react.JSX.Element;
265
+ type RestockNotifyFormProps = AvailabilityInput & {
266
+ sku: string;
267
+ /** Market (country) of the buyer, if the shop has several. */
268
+ market?: string;
269
+ /** Offer a phone / WhatsApp field next to the email. Default false (email only). */
270
+ allowPhone?: boolean;
271
+ /**
272
+ * Destination of the native POST. Without JavaScript the browser posts `sku`, `email`, `phone`, `locale`,
273
+ * `market` and `consent` there, so the shop's own route can call `client.restock.subscribe`. Default: the current page.
274
+ */
275
+ action?: string;
276
+ /** Client override (defaults to the `StorefrontProvider` client). */
277
+ client?: StorefrontClient;
278
+ /** With JavaScript the form submits through the SDK; set `false` to always post natively. */
279
+ enhance?: boolean;
280
+ onSubscribed?: () => void;
281
+ onError?: (error: unknown) => void;
282
+ } & Omit<ComponentPropsWithoutRef<'form'>, 'action' | 'method' | 'onSubmit' | 'children'>;
283
+ /**
284
+ * Subscription form. Renders `null` unless the server says `notify_available` and the state is
285
+ * `out_of_stock`. Works without JavaScript (native POST); with it, submits via the SDK and shows
286
+ * the result in place (`role="status"` / `role="alert"`).
287
+ */
288
+ declare function RestockNotifyForm({ sku, market, allowPhone, action, client: clientProp, enhance, onSubscribed, onError, availability, source, lowStockThreshold, locale, messages, ...rest }: RestockNotifyFormProps): react.JSX.Element | null;
289
+ type CartLineProblemProps = {
290
+ /** The cart line; its `problem` is shown. Renders `null` when there is none. */
291
+ line: Pick<CartLine, 'id' | 'quantity'> & {
292
+ problem?: CartLineProblem$1 | null;
293
+ };
294
+ locale?: string;
295
+ messages?: Partial<AvailabilityMessages>;
296
+ /** Defaults to `useCart().updateLines` when inside a `CartProvider`. */
297
+ onAdjust?: (lineId: string, quantity: number) => void | Promise<unknown>;
298
+ /** Defaults to `useCart().removeLines` when inside a `CartProvider`. */
299
+ onRemove?: (lineId: string) => void | Promise<unknown>;
300
+ } & Omit<ComponentPropsWithoutRef<'div'>, 'children'>;
301
+ /**
302
+ * Problem of one cart line, shown as soon as the cart loads (before checkout): "Ya no hay existencias" or
303
+ * "Solo puedes llevar N", with "Ajustar a N" (only when the server lets the number be seen) and "Quitar".
304
+ */
305
+ declare function CartLineProblem({ line, locale, messages, onAdjust, onRemove, ...rest }: CartLineProblemProps): react.JSX.Element | null;
306
+ type StockConflictAlertProps = {
307
+ /** Error to inspect. Defaults to `useCart().error`. Renders `null` unless it is a `409 insufficient_stock`. */
308
+ error?: unknown;
309
+ /** Cart used to name the affected lines. Defaults to `useCart().cart`. */
310
+ cart?: Cart | null;
311
+ locale?: string;
312
+ messages?: Partial<AvailabilityMessages>;
313
+ onAdjust?: (lineId: string, quantity: number) => void | Promise<unknown>;
314
+ onRemove?: (lineId: string) => void | Promise<unknown>;
315
+ onDismiss?: () => void;
316
+ /** Move focus to the alert when it appears (default true). */
317
+ autoFocus?: boolean;
318
+ } & Omit<ComponentPropsWithoutRef<'div'>, 'children' | 'role' | 'tabIndex'>;
319
+ /**
320
+ * Recoverable stock conflict. The cart and the form data are NOT touched: it shows our own text (never the raw
321
+ * `error.message`), the affected lines with "Ajustar a N" / "Quitar", and takes focus (`role="alert"`) without
322
+ * moving the page. Drop it above the checkout form: `<StockConflictAlert />` reads the error from the cart.
323
+ */
324
+ declare function StockConflictAlert({ error: errorProp, cart: cartProp, locale, messages, onAdjust, onRemove, onDismiss, autoFocus, ...rest }: StockConflictAlertProps): react.JSX.Element | null;
206
325
 
207
326
  /**
208
327
  * SEO helpers: pure functions returning meta descriptors (React Router v7
@@ -248,12 +367,11 @@ type SeoMetaInput = {
248
367
  };
249
368
  /** Generic title/description/canonical/Open Graph/Twitter descriptors. */
250
369
  declare function seoMeta(input: SeoMetaInput): MetaDescriptor[];
251
- /** Product page descriptors (`og:type=product` and price tags). */
252
- declare function productMeta(product: Product, shop: Pick<Shop, 'name' | 'locale'> | null, url: string): MetaDescriptor[];
370
+ declare function productMeta(product: Product, shop: Pick<Shop, 'name' | 'locale'> | null, url: string, options?: ResolveAvailabilityOptions): MetaDescriptor[];
253
371
  /** Collection page descriptors. */
254
372
  declare function collectionMeta(collection: Collection, shop: Pick<Shop, 'name' | 'locale'> | null, url: string): MetaDescriptor[];
255
373
  /** schema.org `Product` with one `Offer` per variant. */
256
- declare function productJsonLd(product: Product, shop: Pick<Shop, 'name' | 'domain'> | null, url: string): JsonLdObject;
374
+ declare function productJsonLd(product: Product, shop: Pick<Shop, 'name' | 'domain'> | null, url: string, options?: ResolveAvailabilityOptions): JsonLdObject;
257
375
  /** schema.org `Organization` for the shop (logo, contact, url). */
258
376
  declare function organizationJsonLd(shop: Shop, url?: string): JsonLdObject;
259
377
  type LocalBusinessOptions = {
@@ -302,6 +420,97 @@ type JsonLdProps = {
302
420
  /** Renders `<script type="application/ld+json">` safely (works in SSR). */
303
421
  declare function JsonLd({ data, nonce }: JsonLdProps): react.JSX.Element | null;
304
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
+
305
514
  type SectionPropKind = 'text' | 'textarea' | 'richtext' | 'number' | 'boolean' | 'url' | 'image' | 'color' | 'select' | 'collection' | 'product' | 'products' | 'list';
306
515
  type SectionPropSchema = {
307
516
  label: string;
@@ -347,6 +556,10 @@ type SectionDefinition<P = Record<string, unknown>, C = any> = {
347
556
  type: string;
348
557
  label?: string;
349
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;
350
563
  schema: SectionSchema;
351
564
  component: ComponentType<SectionComponentProps<P, C>>;
352
565
  };
@@ -367,6 +580,8 @@ declare function defineSection<const S extends SectionSchema, C = any>(definitio
367
580
  type: string;
368
581
  label?: string;
369
582
  description?: string;
583
+ category?: string;
584
+ maxPerPage?: number;
370
585
  schema: S;
371
586
  component: ComponentType<SectionComponentProps<InferSectionProps<S>, C>>;
372
587
  }): SectionDefinition<InferSectionProps<S>, C>;
@@ -395,6 +610,12 @@ declare class SectionRegistry {
395
610
  definitions(): SectionDefinition<any, any>[];
396
611
  /** JSON Schemas of every registered section, keyed by type. */
397
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;
398
619
  }
399
620
  declare function createSectionRegistry(definitions?: readonly SectionDefinition<any, any>[]): SectionRegistry;
400
621
  type SectionsProps<C = unknown> = {
@@ -655,4 +876,4 @@ type NearestLocationFormProps<L extends ShopBranch = ShopBranch> = {
655
876
  */
656
877
  declare function NearestLocationForm<L extends ShopBranch = ShopBranch>({ locations, action, name, defaultValue, onSubmitPostalCode, onLocate, labels, children, ...rest }: NearestLocationFormProps<L>): react.JSX.Element | null;
657
878
 
658
- export { AddToCartButton, type AddToCartButtonProps, type BreadcrumbItem, CART_COOKIE_NAME, type CartContextValue, type CartCookieOptions, type CartLineAddInput, 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, 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, type StorefrontContextValue, StorefrontProvider, type StorefrontProviderProps, type ThemeCssOptions, ThemeStyle, type ThemeStyleProps, type UseGeolocationOptions, type UseGeolocationResult, type UseNearestLocationsOptions, type UseNearestLocationsResult, type UseProductOptionsConfig, type UseSelectedLocationOptions, type UseSelectedLocationResult, 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, 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
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode, ComponentPropsWithoutRef, ComponentType, FormEvent } from 'react';
3
- import { StorefrontClient, Shop, StorefrontClientOptions, Cart, CartLineInput, CartLineMerchandise, CartLineUpdateInput, CartBuyerInput, AddressInput, DeliveryInput, DeliveryOptions, ProductVariant, Product, Image, Collection, Section, Theme, GeoPoint, ShopBranch, Money } from '@asteby/storefront';
3
+ import { StorefrontClient, Shop, StorefrontClientOptions, Cart, CartLineInput, CartLineMerchandise, CartLineUpdateInput, CartBuyerInput, AddressInput, DeliveryInput, DeliveryOptions, Availability, ProductVariant, Product, resolveAvailability, AvailabilityMessages, CartLine, CartLineProblem as CartLineProblem$1, AvailabilityView, Image, Collection, ResolveAvailabilityOptions, Section, Theme, GeoPoint, ShopBranch, Money } from '@asteby/storefront';
4
4
  export { D as DEFAULT_IMAGE_WIDTHS, I as Image, a as ImageLoader, b as ImageProps, M as Money, c as MoneyProps, P as ProductPrice, d as ProductPriceProps, e as defaultImageLoader } from './components-B5XhSH-m.js';
5
5
  import { OpeningHours, GeoPoint as GeoPoint$1, OpenStatus as OpenStatus$1 } from '@asteby/storefront/geo';
6
6
 
@@ -135,6 +135,8 @@ type ProductOptionValueState = {
135
135
  available: boolean;
136
136
  /** The variant this value would select, if it exists. */
137
137
  variant: ProductVariant | null;
138
+ /** Availability of that variant (polyfilled for servers older than contract 1.1); with the other options not chosen yet, the best among matching variants. `null` when no variant matches. Feed it to `<VariantOptionState availability>`. */
139
+ availability: Availability | null;
138
140
  /** Query string (`?Talla=M&Color=Rojo`) selecting this value, preserving other params. */
139
141
  search: string;
140
142
  };
@@ -196,13 +198,130 @@ declare function toMerchandise(product: Pick<Product, 'handle' | 'title' | 'feat
196
198
  type AddToCartButtonProps = Omit<ComponentPropsWithoutRef<'button'>, 'onClick'> & {
197
199
  variantId: string | null | undefined;
198
200
  quantity?: number;
201
+ /**
202
+ * Availability of the variant (server `availability`, or the variant itself to polyfill). When given: the label
203
+ * comes from the server state ("Agotado", "Pedir bajo pedido"...) unless `children` is set, the button is
204
+ * disabled when it cannot be bought, and the quantity is capped at `max_per_order`.
205
+ */
206
+ availability?: Availability | null;
207
+ /** Variant to derive the availability from when the server did not send it. */
208
+ availabilitySource?: ProductVariant | null;
209
+ /** Polyfill only: shop-level low-stock threshold. */
210
+ lowStockThreshold?: number | null;
211
+ /** BCP 47; defaults to the provider locale. */
212
+ locale?: string;
199
213
  /** Variant data for an instant optimistic cart line. */
200
214
  merchandise?: CartLineMerchandise;
201
215
  onAdded?: () => void;
202
216
  onClick?: ComponentPropsWithoutRef<'button'>['onClick'];
203
217
  };
204
218
  /** Adds a variant to the cart via `useCart().addLines`. Disabled without a variant or while adding. */
205
- declare function AddToCartButton({ variantId, quantity, merchandise, onAdded, onClick, disabled, children, type, ...rest }: AddToCartButtonProps): react.JSX.Element;
219
+ declare function AddToCartButton({ variantId, quantity, availability, availabilitySource, lowStockThreshold, locale, merchandise, onAdded, onClick, disabled, children, type, ...rest }: AddToCartButtonProps): react.JSX.Element;
220
+
221
+ /** Visually hidden text for screen readers. */
222
+ declare function SrOnly({ children }: {
223
+ children: ReactNode;
224
+ }): react.JSX.Element;
225
+ type AvailabilitySource = Parameters<typeof resolveAvailability>[0];
226
+ type AvailabilityInput = {
227
+ /** Availability sent by the server. */
228
+ availability?: Availability | null;
229
+ /** Variant or product: used when `availability` is absent (polyfill for servers older than contract 1.1). */
230
+ source?: AvailabilitySource | null;
231
+ /** Polyfill only: shop-level low-stock threshold (never hard-coded here). */
232
+ lowStockThreshold?: number | null;
233
+ /** BCP 47; defaults to the provider locale, then `es-MX`. */
234
+ locale?: string;
235
+ /** Per-key text overrides. */
236
+ messages?: Partial<AvailabilityMessages>;
237
+ };
238
+ /** `AvailabilityView` for a server `availability` or a variant/product (polyfilled). `null` when nothing is given. */
239
+ declare function useAvailability(input: AvailabilityInput): AvailabilityView | null;
240
+ type AvailabilityBadgeProps = AvailabilityInput & {
241
+ /**
242
+ * `card` (listing): renders `null` for plain `in_stock` so cards are not saturated.
243
+ * `detail` (product page): always renders, with the ETA and the order cap.
244
+ */
245
+ placement?: 'card' | 'detail';
246
+ /** Announce changes (e.g. after the client refreshes the stock): `role="status"`. */
247
+ live?: boolean;
248
+ } & Omit<ComponentPropsWithoutRef<'span'>, 'children'>;
249
+ /**
250
+ * Availability label. `data-availability` is the status and `data-tone` the tone, so a
251
+ * card can dim its image with CSS (`[data-availability=out_of_stock]`).
252
+ */
253
+ declare function AvailabilityBadge({ availability, source, lowStockThreshold, locale, messages, placement, live, ...rest }: AvailabilityBadgeProps): react.JSX.Element | null;
254
+ type VariantOptionStateProps = AvailabilityInput & {
255
+ /** The option text (e.g. the flavor). */
256
+ children: ReactNode;
257
+ } & Omit<ComponentPropsWithoutRef<'span'>, 'children'>;
258
+ /**
259
+ * Content for one option of a flavor/variant selector. A sold-out option is struck through
260
+ * (`<s>`) and announced as "agotado" to screen readers; it stays selectable so the buyer can
261
+ * see it and subscribe. Backorder / preorder options get a visible tag. Plain in-stock: just the text.
262
+ * Without any availability it renders `children` untouched.
263
+ */
264
+ declare function VariantOptionState({ children, availability, source, lowStockThreshold, locale, messages, ...rest }: VariantOptionStateProps): react.JSX.Element;
265
+ type RestockNotifyFormProps = AvailabilityInput & {
266
+ sku: string;
267
+ /** Market (country) of the buyer, if the shop has several. */
268
+ market?: string;
269
+ /** Offer a phone / WhatsApp field next to the email. Default false (email only). */
270
+ allowPhone?: boolean;
271
+ /**
272
+ * Destination of the native POST. Without JavaScript the browser posts `sku`, `email`, `phone`, `locale`,
273
+ * `market` and `consent` there, so the shop's own route can call `client.restock.subscribe`. Default: the current page.
274
+ */
275
+ action?: string;
276
+ /** Client override (defaults to the `StorefrontProvider` client). */
277
+ client?: StorefrontClient;
278
+ /** With JavaScript the form submits through the SDK; set `false` to always post natively. */
279
+ enhance?: boolean;
280
+ onSubscribed?: () => void;
281
+ onError?: (error: unknown) => void;
282
+ } & Omit<ComponentPropsWithoutRef<'form'>, 'action' | 'method' | 'onSubmit' | 'children'>;
283
+ /**
284
+ * Subscription form. Renders `null` unless the server says `notify_available` and the state is
285
+ * `out_of_stock`. Works without JavaScript (native POST); with it, submits via the SDK and shows
286
+ * the result in place (`role="status"` / `role="alert"`).
287
+ */
288
+ declare function RestockNotifyForm({ sku, market, allowPhone, action, client: clientProp, enhance, onSubscribed, onError, availability, source, lowStockThreshold, locale, messages, ...rest }: RestockNotifyFormProps): react.JSX.Element | null;
289
+ type CartLineProblemProps = {
290
+ /** The cart line; its `problem` is shown. Renders `null` when there is none. */
291
+ line: Pick<CartLine, 'id' | 'quantity'> & {
292
+ problem?: CartLineProblem$1 | null;
293
+ };
294
+ locale?: string;
295
+ messages?: Partial<AvailabilityMessages>;
296
+ /** Defaults to `useCart().updateLines` when inside a `CartProvider`. */
297
+ onAdjust?: (lineId: string, quantity: number) => void | Promise<unknown>;
298
+ /** Defaults to `useCart().removeLines` when inside a `CartProvider`. */
299
+ onRemove?: (lineId: string) => void | Promise<unknown>;
300
+ } & Omit<ComponentPropsWithoutRef<'div'>, 'children'>;
301
+ /**
302
+ * Problem of one cart line, shown as soon as the cart loads (before checkout): "Ya no hay existencias" or
303
+ * "Solo puedes llevar N", with "Ajustar a N" (only when the server lets the number be seen) and "Quitar".
304
+ */
305
+ declare function CartLineProblem({ line, locale, messages, onAdjust, onRemove, ...rest }: CartLineProblemProps): react.JSX.Element | null;
306
+ type StockConflictAlertProps = {
307
+ /** Error to inspect. Defaults to `useCart().error`. Renders `null` unless it is a `409 insufficient_stock`. */
308
+ error?: unknown;
309
+ /** Cart used to name the affected lines. Defaults to `useCart().cart`. */
310
+ cart?: Cart | null;
311
+ locale?: string;
312
+ messages?: Partial<AvailabilityMessages>;
313
+ onAdjust?: (lineId: string, quantity: number) => void | Promise<unknown>;
314
+ onRemove?: (lineId: string) => void | Promise<unknown>;
315
+ onDismiss?: () => void;
316
+ /** Move focus to the alert when it appears (default true). */
317
+ autoFocus?: boolean;
318
+ } & Omit<ComponentPropsWithoutRef<'div'>, 'children' | 'role' | 'tabIndex'>;
319
+ /**
320
+ * Recoverable stock conflict. The cart and the form data are NOT touched: it shows our own text (never the raw
321
+ * `error.message`), the affected lines with "Ajustar a N" / "Quitar", and takes focus (`role="alert"`) without
322
+ * moving the page. Drop it above the checkout form: `<StockConflictAlert />` reads the error from the cart.
323
+ */
324
+ declare function StockConflictAlert({ error: errorProp, cart: cartProp, locale, messages, onAdjust, onRemove, onDismiss, autoFocus, ...rest }: StockConflictAlertProps): react.JSX.Element | null;
206
325
 
207
326
  /**
208
327
  * SEO helpers: pure functions returning meta descriptors (React Router v7
@@ -248,12 +367,11 @@ type SeoMetaInput = {
248
367
  };
249
368
  /** Generic title/description/canonical/Open Graph/Twitter descriptors. */
250
369
  declare function seoMeta(input: SeoMetaInput): MetaDescriptor[];
251
- /** Product page descriptors (`og:type=product` and price tags). */
252
- declare function productMeta(product: Product, shop: Pick<Shop, 'name' | 'locale'> | null, url: string): MetaDescriptor[];
370
+ declare function productMeta(product: Product, shop: Pick<Shop, 'name' | 'locale'> | null, url: string, options?: ResolveAvailabilityOptions): MetaDescriptor[];
253
371
  /** Collection page descriptors. */
254
372
  declare function collectionMeta(collection: Collection, shop: Pick<Shop, 'name' | 'locale'> | null, url: string): MetaDescriptor[];
255
373
  /** schema.org `Product` with one `Offer` per variant. */
256
- declare function productJsonLd(product: Product, shop: Pick<Shop, 'name' | 'domain'> | null, url: string): JsonLdObject;
374
+ declare function productJsonLd(product: Product, shop: Pick<Shop, 'name' | 'domain'> | null, url: string, options?: ResolveAvailabilityOptions): JsonLdObject;
257
375
  /** schema.org `Organization` for the shop (logo, contact, url). */
258
376
  declare function organizationJsonLd(shop: Shop, url?: string): JsonLdObject;
259
377
  type LocalBusinessOptions = {
@@ -302,6 +420,97 @@ type JsonLdProps = {
302
420
  /** Renders `<script type="application/ld+json">` safely (works in SSR). */
303
421
  declare function JsonLd({ data, nonce }: JsonLdProps): react.JSX.Element | null;
304
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
+
305
514
  type SectionPropKind = 'text' | 'textarea' | 'richtext' | 'number' | 'boolean' | 'url' | 'image' | 'color' | 'select' | 'collection' | 'product' | 'products' | 'list';
306
515
  type SectionPropSchema = {
307
516
  label: string;
@@ -347,6 +556,10 @@ type SectionDefinition<P = Record<string, unknown>, C = any> = {
347
556
  type: string;
348
557
  label?: string;
349
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;
350
563
  schema: SectionSchema;
351
564
  component: ComponentType<SectionComponentProps<P, C>>;
352
565
  };
@@ -367,6 +580,8 @@ declare function defineSection<const S extends SectionSchema, C = any>(definitio
367
580
  type: string;
368
581
  label?: string;
369
582
  description?: string;
583
+ category?: string;
584
+ maxPerPage?: number;
370
585
  schema: S;
371
586
  component: ComponentType<SectionComponentProps<InferSectionProps<S>, C>>;
372
587
  }): SectionDefinition<InferSectionProps<S>, C>;
@@ -395,6 +610,12 @@ declare class SectionRegistry {
395
610
  definitions(): SectionDefinition<any, any>[];
396
611
  /** JSON Schemas of every registered section, keyed by type. */
397
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;
398
619
  }
399
620
  declare function createSectionRegistry(definitions?: readonly SectionDefinition<any, any>[]): SectionRegistry;
400
621
  type SectionsProps<C = unknown> = {
@@ -655,4 +876,4 @@ type NearestLocationFormProps<L extends ShopBranch = ShopBranch> = {
655
876
  */
656
877
  declare function NearestLocationForm<L extends ShopBranch = ShopBranch>({ locations, action, name, defaultValue, onSubmitPostalCode, onLocate, labels, children, ...rest }: NearestLocationFormProps<L>): react.JSX.Element | null;
657
878
 
658
- export { AddToCartButton, type AddToCartButtonProps, type BreadcrumbItem, CART_COOKIE_NAME, type CartContextValue, type CartCookieOptions, type CartLineAddInput, 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, 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, type StorefrontContextValue, StorefrontProvider, type StorefrontProviderProps, type ThemeCssOptions, ThemeStyle, type ThemeStyleProps, type UseGeolocationOptions, type UseGeolocationResult, type UseNearestLocationsOptions, type UseNearestLocationsResult, type UseProductOptionsConfig, type UseSelectedLocationOptions, type UseSelectedLocationResult, 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, 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 };