@propeller-commerce/propeller-v2-react-ui 0.20.0 → 0.21.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
@@ -1687,6 +1687,20 @@ interface UseSparePartsOptions {
1687
1687
  sortOrder?: SortOrder | string;
1688
1688
  /** Items per page. Defaults to 12. */
1689
1689
  pageSize?: number;
1690
+ /**
1691
+ * Controlled page. When provided the hook renders (and fetches) this page and
1692
+ * `goToPage` becomes advisory - the host owns the number, typically from the
1693
+ * URL.
1694
+ *
1695
+ * Every other listing input (term, textFilters, sortField, pageSize) was
1696
+ * already an option, so its absence read as "paging is internal" and it was
1697
+ * not: driving the hook from URL state and rendering GridPagination changed
1698
+ * the URL but re-rendered the same first page, because the only way in was a
1699
+ * `useEffect(() => goToPage(page))` that MachineGrid does internally and
1700
+ * nothing documented (PWP-995b). Omit it to keep the previous uncontrolled
1701
+ * behaviour.
1702
+ */
1703
+ page?: number;
1690
1704
  /** Image filter config, mirroring `useProductSearch`'s `configuration`. */
1691
1705
  configuration?: {
1692
1706
  /** The channel's anonymous user, seeded by the host. Scopes logged-out
@@ -3898,14 +3912,22 @@ interface MachineCardProps {
3898
3912
  * URL is its ancestor path (`/machines/a/b/c`), which only the host route
3899
3913
  * knows; the machine object carries just its own slug.
3900
3914
  */
3901
- href: string;
3915
+ href?: string;
3902
3916
  /** Show the machine image. Defaults to true. */
3903
3917
  showImage?: boolean;
3904
3918
  /** Show the machine description under the name. Defaults to false. */
3905
3919
  showDescription?: boolean;
3906
3920
  /** Language used to resolve the localized name/description. */
3907
3921
  language?: string;
3908
- /** UI label overrides. Supported key: `viewMachine`. */
3922
+ /**
3923
+ * UI label overrides. Key read here: `viewMachine`.
3924
+ *
3925
+ * `MachineGrid` passes its own `machineCardLabels` straight through to this
3926
+ * prop and additionally reads `loading` and `noMachines` from it for its own
3927
+ * empty/loading states, so the object a grid host supplies carries all three.
3928
+ * This doc used to name only `viewMachine`, which left the other two in
3929
+ * English for anyone who followed it (PWP-995d).
3930
+ */
3909
3931
  labels?: Record<string, string>;
3910
3932
  /** Extra classes on the card root. */
3911
3933
  className?: string;
@@ -3923,225 +3945,522 @@ interface MachineCardProps {
3923
3945
  declare function MachineCard(props: MachineCardProps): React$1.JSX.Element;
3924
3946
 
3925
3947
  /**
3926
- * @rsc-blocked — Client-only component: hooks + effects (via useSpareParts /
3927
- * useMachines) and event handlers. Render inside a Client boundary.
3928
- */
3929
- /**
3930
- * MachineGrid — the spare-parts machine tree, as one self-contained grid.
3931
- *
3932
- * The machine-tree sibling of `ProductGrid`. Driven by the current URL path
3933
- * (`segments`), it renders one of two modes:
3934
- *
3935
- * - **Root** (`segments` empty): resolves the company's installations in ONE
3936
- * concatenated request via `useMachines(source, sourceIds)` and renders them
3937
- * as `MachineCard`s.
3938
- * - **Node** (`segments` non-empty): fetches that machine by its leaf slug via
3939
- * `useSpareParts`, and renders its child machines (`MachineCard`s) above a
3940
- * category-style spare-parts listing (facets + toolbar + a permanently
3941
- * controlled `ProductGrid` + pagination, with the qty-in-machine `belowName`).
3942
- *
3943
- * Navigation between levels is via `MachineCard`'s `href` (built from `basePath`
3944
- * + segments + child slug) — the package owns no router. The parts listing is
3945
- * **controlled**: the current state comes in via `listing`, and every filter /
3946
- * sort / page / search interaction emits the next state via `onListingChange`.
3947
- * The host route maps that to the URL (so a filtered view is shareable), exactly
3948
- * as `ProductGrid` + the category island already do.
3949
- */
3950
-
3951
- /**
3952
- * The controlled listing state for the spare-parts view — mirrors what the host
3953
- * derives from the URL (`page`/`offset`/`sort`/attribute-`filters`/`price`/`term`).
3954
- * Primitives + SDK enums only, so no app type leaks into the package.
3948
+ * Props for the root `<ProductCard>` (and the back-compat monolithic
3949
+ * variant). Most fields are display toggles preserved for back-compat; in
3950
+ * the new compound API, consumers control rendering by composition instead
3951
+ * — see the Subcomponents section below.
3955
3952
  */
3956
- interface MachineListingState {
3957
- page: number;
3958
- offset: number;
3959
- sortField: ProductSortField | string;
3960
- sortOrder: SortOrder | string;
3961
- /** Attribute name → selected facet values. */
3962
- filters: Record<string, string[]>;
3963
- minPrice?: number;
3964
- maxPrice?: number;
3965
- term: string;
3966
- }
3967
- interface MachineGridProps {
3968
- /** Current URL path under the machines root, e.g. `['mixer','frame']`. `[]` = root. */
3969
- segments: string[];
3970
- /** Localized machines base path (e.g. `/nl/machines`) — used to build hrefs. */
3971
- basePath: string;
3972
- /** External system the installation ids belong to (root mode). */
3973
- source?: string;
3974
- /** Installation ids from `MY_INSTALLATIONS` (root mode). */
3975
- sourceIds?: string[];
3976
- /** Title for the root list. Defaults to `'Machines'`. */
3977
- rootTitle?: string;
3978
- /** Language the machine tree is authored in (usually EN). Defaults to `'EN'`. */
3979
- machineLanguage?: string;
3980
- listing: MachineListingState;
3981
- onListingChange: (next: MachineListingState) => void;
3982
- graphqlClient?: GraphQLClient;
3983
- user?: Contact | Customer | null;
3984
- companyId?: number;
3985
- /** Storefront language (parts). */
3986
- language?: string;
3987
- taxZone?: string;
3988
- configuration?: {
3989
- imageSearchFiltersGrid?: unknown;
3990
- imageVariantFiltersMedium?: unknown;
3991
- };
3992
- portalMode?: string;
3993
- cartId?: string;
3994
- createCart?: boolean;
3995
- onCartCreated?: (cart: Cart) => void;
3953
+ interface ProductCardProps {
3954
+ /** The product object to display */
3955
+ product: Product;
3996
3956
  /**
3997
- * Fired after every successful add-to-cart (adds into an EXISTING cart too, not
3998
- * just the first create). Forward this to `CartContext.saveCart` or the cart
3999
- * icon/sidebar/page won't reflect parts added from the grid — `onCartCreated`
4000
- * alone only fires when a brand-new cart is created.
3957
+ * Compound API: provide subcomponents as children. When omitted, the
3958
+ * monolithic legacy layout renders based on the show*/ children?: React$1.ReactNode;
3959
+ /** Show the product name. Defaults to true. */
3960
+ showName?: boolean;
3961
+ /** Show the product image. Defaults to true. */
3962
+ showImage?: boolean;
3963
+ /** Show the product short description. Defaults to false. */
3964
+ showShortDescription?: boolean;
3965
+ /** Show the product SKU. Defaults to true. */
3966
+ showSku?: boolean;
3967
+ /** Show the product manufacturer. Defaults to false. */
3968
+ showManufacturer?: boolean;
3969
+ /**
3970
+ * Show the stock / availability widget below the product name.
3971
+ * Uses the embedded `ItemStock` component driven by `product.inventory`.
3972
+ * Defaults to false.
4001
3973
  */
4002
- afterAddToCart?: (cart: Cart, item?: CartMainItem) => void;
4003
- allowAddToCart?: boolean;
4004
- showPrice?: boolean;
4005
3974
  showStock?: boolean;
4006
- showAvailability?: boolean;
4007
- onProductClick?: (product: Product) => void;
4008
- paginationLabels?: Record<string, string>;
4009
- filtersLabels?: Record<string, string>;
4010
- toolbarLabels?: Record<string, string>;
4011
- machineCardLabels?: Record<string, string>;
4012
- className?: string;
4013
- }
4014
- declare function MachineGrid(rawProps: MachineGridProps): React$1.JSX.Element;
4015
-
4016
- /**
4017
- * @rsc-blocked — Client-only component: side effects (useEffect).
4018
- * Must be rendered inside (or below) a Client Component boundary; cannot be
4019
- * imported directly into a React Server Component. The 'use client' header
4020
- * above marks this boundary to Next.js.
4021
- */
4022
-
4023
- /**
4024
- * A computed object containing a cluster config setting enriched with
4025
- * its current UI state: available values for drilldown, the currently
4026
- * selected value, and whether the selector should be disabled.
4027
- */
4028
- interface ClusterConfiguratorProps {
4029
- /** The cluster ID this configurator belongs to. Required. */
4030
- clusterId: number;
4031
3975
  /**
4032
- * All products that belong to the cluster. Required.
4033
- * Used to derive available values per attribute and to match
4034
- * the configured product when all selections are made.
3976
+ * Show only the availability indicator (Available / Not available) inside ItemStock.
3977
+ * Only relevant when `showStock` is true.
3978
+ * Defaults to true.
4035
3979
  */
4036
- products: Product[];
3980
+ showAvailability?: boolean;
4037
3981
  /**
4038
- * Cluster configuration object (`cluster.config`). Required.
4039
- * Provides the ordered list of attribute settings.
3982
+ * Show the price below the product name.
3983
+ * Defaults to true.
4040
3984
  */
4041
- config: ClusterConfig;
3985
+ showPrice?: boolean;
4042
3986
  /**
4043
- * Fired whenever the user completes a set of attribute selections
4044
- * that uniquely identifies a cluster product.
4045
- * Also fired whenever any selection changes and a matching product
4046
- * can already be determined (e.g. only one setting exists).
3987
+ * Show the AddToCart component.
3988
+ * Defaults to true.
4047
3989
  */
4048
- onConfigurationChange?: (product: Product) => void;
4049
- /** Default product to pre-populate the attribute selections on mount. */
4050
- defaultProduct?: Product;
4051
- /** Override any UI string. Available keys: selectOption */
4052
- labels?: Record<string, string>;
4053
- /** Extra CSS class applied to the root element. */
4054
- className?: string;
4055
- }
4056
- /**
4057
- * Renders attribute selectors (dropdown, radio, colour or image swatches) for
4058
- * configuring a cluster, narrowing available values as the user selects and
4059
- * emitting the matching product.
4060
- *
4061
- * @remarks Uses {@link useClusterConfigurator} to derive selectable values and
4062
- * resolve the configured product.
4063
- */
4064
- declare function ClusterConfigurator(props: ClusterConfiguratorProps): React$1.JSX.Element;
4065
-
4066
- /**
4067
- * @rsc-blocked — Client-only component: side effects (useEffect).
4068
- * Must be rendered inside (or below) a Client Component boundary; cannot be
4069
- * imported directly into a React Server Component. The 'use client' header
4070
- * above marks this boundary to Next.js.
4071
- */
4072
-
4073
- interface ClusterInfoProps {
4074
- /** The authenticated user (Contact or Customer). Resolved from PropellerProvider when omitted. */
4075
- user?: Contact | Customer | null;
3990
+ allowAddToCart?: boolean;
4076
3991
  /**
4077
- * Pre-fetched cluster object to display.
4078
- * When provided the component skips internal fetching.
3992
+ * Label overrides forwarded to the embedded ItemStock component.
3993
+ * Keys: inStock, outOfStock, lowStock, available, notAvailable, pieces
4079
3994
  */
4080
- cluster?: Cluster;
3995
+ stockLabels?: Record<string, string>;
4081
3996
  /**
4082
- * Cluster ID to fetch data for when no `cluster` prop is provided.
4083
- * Requires `graphqlClient` to be set.
3997
+ * Attribute codes/names to look up and display as badge overlays on the product image.
3998
+ * Example: ['new', 'sale']
4084
3999
  */
4085
- clusterId?: number;
4000
+ imageLabels?: string[];
4086
4001
  /**
4087
- * Initialised Propeller SDK GraphQL client.
4088
- * Required when `clusterId` is provided for internal data fetching.
4002
+ * Attribute codes/names to look up and display as extra text rows below the product name.
4003
+ * Example: ['brand', 'color']
4089
4004
  */
4090
- graphqlClient?: GraphQLClient;
4005
+ textLabels?: string[];
4006
+ /** Override any UI string. Keys: addToFavorites, removeFromFavorites */
4007
+ labels?: Record<string, string>;
4008
+ /** Renders a heart-icon toggle button on the product image. Defaults to false. */
4009
+ enableAddFavorite?: boolean;
4010
+ /** Called whenever the favourite state is toggled. */
4011
+ onToggleFavorite?: (product: Product, isFavorite: boolean) => void;
4091
4012
  /**
4092
- * Called once the cluster data is loaded — either immediately (when
4093
- * `cluster` prop is supplied) or after the internal fetch completes.
4094
- * Use this to hydrate sibling components (configurator, price, gallery, etc.).
4013
+ * Called when the product name or image is clicked.
4014
+ * When provided, the default `<a>` navigation is prevented.
4095
4015
  */
4096
- onClusterLoaded?: (cluster: Cluster) => void;
4097
- /** Show the cluster name. Defaults to true. */
4098
- showTitle?: boolean;
4099
- /** Show the cluster SKU. Defaults to true. */
4100
- showSku?: boolean;
4101
- /** Language code used to resolve localised names. Defaults to 'NL'. */
4102
- language?: string;
4016
+ onProductClick?: (product: Product) => void;
4017
+ /** When true, tax-inclusive (net) price is the leading price. Defaults to false. */
4018
+ includeTax?: boolean;
4019
+ /** Number of grid columns — when 1 the card renders as a compact horizontal row. */
4020
+ columns?: number;
4103
4021
  /** Extra CSS class applied to the root element. */
4104
4022
  className?: string;
4105
4023
  /**
4106
- * Tax zone to use for price calculation.
4107
- */
4108
- taxZone?: string;
4109
- /**
4110
- * Image search filter passed to ProductService.getProduct().
4111
- * Controls how many image items are returned.
4112
- * Example: { page: 1, offset: 20 }
4024
+ * URL pattern controlling which segments appear in product links.
4025
+ * Tokens: page → 'product', id → productId, slug → slug value.
4026
+ * Defaults to 'page/id/slug'.
4113
4027
  */
4114
- imageSearchFilters?: any;
4028
+ urlPattern?: string;
4029
+ /** GraphQL client for the embedded AddToCart. Resolved from PropellerProvider when omitted. */
4030
+ graphqlClient?: GraphQLClient;
4031
+ /** Authenticated user. Resolved from PropellerProvider when omitted. */
4032
+ user?: Contact | Customer | null;
4115
4033
  /**
4116
- * Image variant transformation filter passed to ProductService.getProduct().
4117
- * Controls image size/format variants returned with the product.
4118
- * Example: imageVariantFiltersLarge from @/data/defaults
4119
- * Defaults to { transformations: [] } when omitted.
4034
+ * Portal access mode — `'open'` / `'semi-closed'` / `'closed'`. Resolved from
4035
+ * PropellerProvider when omitted. In `'semi-closed'` the card hides price and
4036
+ * stock from anonymous visitors and offers a log-in action in place of
4037
+ * add-to-cart; signed-in users are unaffected.
4120
4038
  */
4121
- imageVariantFilters?: any;
4039
+ portalMode?: string;
4122
4040
  /**
4123
- * Config object providing imageSearchFiltersGrid and imageVariantFiltersSmall.
4041
+ * Invoked when an anonymous visitor clicks the log-in action that replaces
4042
+ * add-to-cart in a semi-closed portal. The host owns navigation.
4124
4043
  */
4044
+ onLoginClick?: () => void;
4045
+ /** ID of the cart that add-to-cart targets. */
4046
+ cartId?: string;
4047
+ /** Configuration object (URL builders, image filters, etc.). */
4125
4048
  configuration?: any;
4126
- /**
4127
- * Attribute codes/names to look up and display as badge overlays on the product image.
4128
- * Each code is resolved against `product.attributes.items[].attributeDescription.code`
4129
- * (or `.name`). Attributes with no matching value are silently omitted.
4130
- * Example: ['new', 'sale']
4131
- */
4132
- imageLabels?: string[];
4133
- /**
4134
- * Attribute codes/names to look up and display as extra text rows below the product name.
4135
- * Resolved the same way as `imageLabels`.
4136
- * Example: ['brand', 'color']
4137
- */
4138
- textLabels?: string[];
4139
- }
4140
- /**
4141
- * Displays a cluster's name and SKU heading, either from a supplied `cluster`
4142
- * prop or by fetching it from the SDK by `clusterId`.
4143
- *
4144
- * @remarks Uses {@link useProductInfo} to fetch the cluster when only an ID is given.
4049
+ /** Cluster ID when this card represents a variant of a product cluster. */
4050
+ clusterId?: number;
4051
+ /** Pre-selected child item product IDs added alongside the product. */
4052
+ childItems?: number[];
4053
+ /** Order-line notes forwarded with the add-to-cart request. */
4054
+ notes?: string;
4055
+ /** Custom price override forwarded with the add-to-cart request. */
4056
+ price?: number;
4057
+ /** When true, a new cart is created if no `cartId` is set. */
4058
+ createCart?: boolean;
4059
+ /** Fires when add-to-cart creates a new cart. */
4060
+ onCartCreated?: (cart: Cart) => void;
4061
+ /** Delegation handler — when provided, the parent performs the add-to-cart itself. */
4062
+ onAddToCart?: (product: Product, clusterId?: number, quantity?: number, childItems?: CartChildItemInput[], notes?: string, price?: number, showModal?: boolean) => Cart;
4063
+ /** Fires after an item has been added to the cart. */
4064
+ afterAddToCart?: (cart: Cart, item?: CartMainItem) => void;
4065
+ /** When true, show a confirmation modal after add-to-cart instead of a toast. */
4066
+ showModal?: boolean;
4067
+ /** When true, the AddToCart shows quantity increment/decrement controls. */
4068
+ allowIncrDecr?: boolean;
4069
+ /** When true, stock availability is validated before adding to cart. */
4070
+ enableStockValidation?: boolean;
4071
+ /** Language code for localised content. Resolved from PropellerProvider when omitted. */
4072
+ language?: string;
4073
+ /** Active company ID from the company switcher. */
4074
+ companyId?: number;
4075
+ /** Fires when the "Proceed to checkout" modal button is clicked. */
4076
+ onProceedToCheckout?: () => void;
4077
+ /** Fires when the user requests a quote from the AddToCart modal. */
4078
+ onRequestQuoteClick?: (cart: Cart) => void;
4079
+ /** Label overrides forwarded to the embedded AddToCart component. */
4080
+ addToCartLabels?: Record<string, string>;
4081
+ /** Translated labels forwarded to the embedded `<ProductPrice>` display.
4082
+ * See `ProductPriceProps.labels` for slugs (inclTax, exclTax, loginToSeePrices). */
4083
+ priceLabels?: Record<string, string>;
4084
+ /** Replaces the default price block. Receives `PriceComponentProps`. */
4085
+ /** Currency symbol used when formatting the price. Falls back to PropellerInfra.currency, then `'€'`. */
4086
+ currency?: string;
4087
+ priceComponent?: React$1.ComponentType<_propeller_commerce_propeller_v2_core_ui.PriceComponentProps>;
4088
+ /** Replaces the default stock/availability block. Receives `StockComponentProps`. */
4089
+ stockComponent?: React$1.ComponentType<_propeller_commerce_propeller_v2_core_ui.StockComponentProps>;
4090
+ /** Replaces the default add-to-cart control. Receives `AddToCartComponentProps`. */
4091
+ addToCartComponent?: React$1.ComponentType<_propeller_commerce_propeller_v2_core_ui.AddToCartComponentProps>;
4092
+ /** Replaces the default product image block. Receives `ImageComponentProps`. */
4093
+ imageComponent?: React$1.ComponentType<_propeller_commerce_propeller_v2_core_ui.ImageComponentProps>;
4094
+ /** Replaces the default product badges block. Receives `BadgesComponentProps`. */
4095
+ badgesComponent?: React$1.ComponentType<_propeller_commerce_propeller_v2_core_ui.BadgesComponentProps>;
4096
+ /** Replaces the default favorite-toggle. Receives `FavoriteComponentProps`. */
4097
+ favoriteComponent?: React$1.ComponentType<_propeller_commerce_propeller_v2_core_ui.FavoriteComponentProps>;
4098
+ /**
4099
+ * Render arbitrary content directly below the product name (and above the
4100
+ * short description / price), in both the grid and row layouts. Receives the
4101
+ * product so hosts can surface extra info — e.g. package descriptions, custom
4102
+ * badges — without forking the card. Return `null`/`undefined` to render
4103
+ * nothing for a given product.
4104
+ */
4105
+ belowName?: (product: Product) => React$1.ReactNode;
4106
+ }
4107
+ /**
4108
+ * Root of the `<ProductCard>` compound component. Renders either the
4109
+ * consumer-composed children (compound mode) or the legacy monolithic layout
4110
+ * driven by `show*`/`allow*` toggles, and provides the shared card context.
4111
+ */
4112
+ declare function ProductCardRoot(rawProps: ProductCardProps): React$1.JSX.Element;
4113
+ /**
4114
+ * Product image with optional badge overlays and favourite button.
4115
+ * Reads `derived.imageUrl`, `derived.imageLabelValues`, `derived.productUrl`,
4116
+ * and the `favorite` state from context.
4117
+ *
4118
+ * Trade-off: when `imageComponent` is injected, the consumer takes over the
4119
+ * ENTIRE image area — including the badge / favorite overlay layer.
4120
+ * The default markup wraps the `<img>` in a link with absolute-positioned
4121
+ * badges and a favorite button; an injected component receives only the
4122
+ * `ImageComponentProps` contract and is free to re-render those overlays
4123
+ * itself (e.g. by composing `<DefaultProductBadges>` / `<DefaultAddToFavorite>`)
4124
+ * or omit them entirely.
4125
+ */
4126
+ declare function ProductCardImage(props: {
4127
+ /** Override the wrapper class. */
4128
+ className?: string;
4129
+ /** Render the favourite heart button. Defaults to context `enableAddFavorite`. */
4130
+ showFavorite?: boolean;
4131
+ }): React$1.JSX.Element;
4132
+ /** Image-overlay badge list (e.g. "new", "sale" attributes), or the
4133
+ * injected `badgesComponent` from context when set. */
4134
+ declare function ProductCardBadges(props: {
4135
+ /** Override the badge container class. */
4136
+ className?: string;
4137
+ }): React$1.JSX.Element | null;
4138
+ /** Favourite (heart) toggle button — typically placed inside `<ProductCard.Image>`,
4139
+ * or the injected `favoriteComponent` from context when set.
4140
+ *
4141
+ * The default render is the inline self-contained heart button (local state
4142
+ * only, fires `onToggleFavorite`); the injected variant receives the full
4143
+ * `FavoriteComponentProps` contract (product, user, callback) so consumers
4144
+ * can plug in real favorite-list mutations. The unused import of
4145
+ * `DefaultAddToFavoriteImpl` is kept so consumers can wrap-and-call it. */
4146
+ declare function ProductCardFavorite(props: {
4147
+ /** Override the button class. */
4148
+ className?: string;
4149
+ }): React$1.JSX.Element;
4150
+ /** Product name. `linkable` (default true) wraps it in an `<a>` to the PDP. */
4151
+ declare function ProductCardName(props: {
4152
+ /** When true (default), wraps the name in a link to the product page. */
4153
+ linkable?: boolean;
4154
+ /** Override the name element class. */
4155
+ className?: string;
4156
+ }): React$1.JSX.Element;
4157
+ /** Renders the product SKU. */
4158
+ declare function ProductCardSku(props: {
4159
+ /** Override the SKU element class. */
4160
+ className?: string;
4161
+ }): React$1.JSX.Element | null;
4162
+ /** Renders the product's short description. */
4163
+ declare function ProductCardShortDescription(props: {
4164
+ /** Override the description element class. */
4165
+ className?: string;
4166
+ }): React$1.JSX.Element | null;
4167
+ /** Renders the product manufacturer name. */
4168
+ declare function ProductCardManufacturer(props: {
4169
+ /** Override the manufacturer element class. */
4170
+ className?: string;
4171
+ }): React$1.JSX.Element | null;
4172
+ /** Renders the resolved `textLabels` attribute values as text rows. */
4173
+ declare function ProductCardTextLabels(props: {
4174
+ /** Override the label container class. */
4175
+ className?: string;
4176
+ }): React$1.JSX.Element | null;
4177
+ /** Renders the embedded stock/availability widget for the product, or the
4178
+ * injected `stockComponent` from context when set. */
4179
+ declare function ProductCardStock(props: {
4180
+ /** Show only the availability indicator. Defaults to context `showAvailability`. */
4181
+ showAvailability?: boolean;
4182
+ }): React$1.JSX.Element | null;
4183
+ /** Renders host-supplied content directly below the name, via the `belowName`
4184
+ * render prop (explicit or from grid context). Renders nothing when unset or
4185
+ * when the render prop returns a nullish value. */
4186
+ declare function ProductCardBelowName(): React$1.JSX.Element | null;
4187
+ /** Renders the product price via the embedded `ProductPrice` component, or
4188
+ * the injected `priceComponent` from context when set. */
4189
+ declare function ProductCardPrice(props: {
4190
+ /** Tailwind text-size class for the price. Defaults to `'text-base sm:text-lg'`. */
4191
+ priceSize?: string;
4192
+ /** Override the price wrapper class. */
4193
+ className?: string;
4194
+ }): React$1.JSX.Element | null;
4195
+ /** Renders the embedded `AddToCart` control with all pass-through props from
4196
+ * context, or the injected `addToCartComponent` when set.
4197
+ *
4198
+ * Note: the default `AddToCartImpl` accepts a richer prop set (graphqlClient,
4199
+ * configuration, etc.) than the public `AddToCartComponentProps` contract.
4200
+ * Injected components only receive the contract surface; the extra infra
4201
+ * props stay default-only. */
4202
+ declare function ProductCardAddToCart(props: {
4203
+ /** Override the AddToCart wrapper class. */
4204
+ className?: string;
4205
+ }): React$1.JSX.Element;
4206
+ declare const MemoizedRoot: React$1.MemoExoticComponent<typeof ProductCardRoot>;
4207
+ /**
4208
+ * Compound component. Use either:
4209
+ *
4210
+ * **Compound mode (new — preferred):**
4211
+ * ```tsx
4212
+ * <ProductCard product={p}>
4213
+ * <ProductCard.Image variant="grid" />
4214
+ * <ProductCard.Name linkable />
4215
+ * <ProductCard.Sku />
4216
+ * <ProductCard.Price />
4217
+ * <ProductCard.AddToCart />
4218
+ * </ProductCard>
4219
+ * ```
4220
+ *
4221
+ * **Legacy mode (deprecated — kept for back-compat):**
4222
+ * ```tsx
4223
+ * <ProductCard product={p} showName showPrice allowAddToCart />
4224
+ * ```
4225
+ * All the show* / allow* toggles still work and render the canonical layout
4226
+ * using the compound subcomponents internally.
4227
+ */
4228
+ type ProductCardComponent = typeof MemoizedRoot & {
4229
+ Image: typeof ProductCardImage;
4230
+ Badges: typeof ProductCardBadges;
4231
+ Favorite: typeof ProductCardFavorite;
4232
+ Name: typeof ProductCardName;
4233
+ Sku: typeof ProductCardSku;
4234
+ BelowName: typeof ProductCardBelowName;
4235
+ ShortDescription: typeof ProductCardShortDescription;
4236
+ Manufacturer: typeof ProductCardManufacturer;
4237
+ TextLabels: typeof ProductCardTextLabels;
4238
+ Stock: typeof ProductCardStock;
4239
+ Price: typeof ProductCardPrice;
4240
+ AddToCart: typeof ProductCardAddToCart;
4241
+ };
4242
+ declare const ProductCard: ProductCardComponent;
4243
+
4244
+ /**
4245
+ * The controlled listing state for the spare-parts view — mirrors what the host
4246
+ * derives from the URL (`page`/`offset`/`sort`/attribute-`filters`/`price`/`term`).
4247
+ * Primitives + SDK enums only, so no app type leaks into the package.
4248
+ */
4249
+ interface MachineListingState {
4250
+ page: number;
4251
+ offset: number;
4252
+ sortField: ProductSortField | string;
4253
+ sortOrder: SortOrder | string;
4254
+ /** Attribute name → selected facet values. */
4255
+ filters: Record<string, string[]>;
4256
+ minPrice?: number;
4257
+ maxPrice?: number;
4258
+ term: string;
4259
+ }
4260
+ interface MachineGridProps {
4261
+ /** Current URL path under the machines root, e.g. `['mixer','frame']`. `[]` = root. */
4262
+ segments: string[];
4263
+ /** Localized machines base path (e.g. `/nl/machines`) — used to build hrefs. */
4264
+ basePath: string;
4265
+ /** External system the installation ids belong to (root mode). */
4266
+ source?: string;
4267
+ /** Installation ids from `MY_INSTALLATIONS` (root mode). */
4268
+ sourceIds?: string[];
4269
+ /** Title for the root list. Defaults to `'Machines'`. */
4270
+ rootTitle?: string;
4271
+ /** Language the machine tree is authored in (usually EN). Defaults to `'EN'`. */
4272
+ machineLanguage?: string;
4273
+ listing: MachineListingState;
4274
+ onListingChange: (next: MachineListingState) => void;
4275
+ graphqlClient?: GraphQLClient;
4276
+ user?: Contact | Customer | null;
4277
+ companyId?: number;
4278
+ /** Storefront language (parts). */
4279
+ language?: string;
4280
+ taxZone?: string;
4281
+ configuration?: {
4282
+ imageSearchFiltersGrid?: unknown;
4283
+ imageVariantFiltersMedium?: unknown;
4284
+ };
4285
+ portalMode?: string;
4286
+ cartId?: string;
4287
+ createCart?: boolean;
4288
+ onCartCreated?: (cart: Cart) => void;
4289
+ /**
4290
+ * Fired after every successful add-to-cart (adds into an EXISTING cart too, not
4291
+ * just the first create). Forward this to `CartContext.saveCart` or the cart
4292
+ * icon/sidebar/page won't reflect parts added from the grid — `onCartCreated`
4293
+ * alone only fires when a brand-new cart is created.
4294
+ */
4295
+ afterAddToCart?: (cart: Cart, item?: CartMainItem) => void;
4296
+ allowAddToCart?: boolean;
4297
+ showPrice?: boolean;
4298
+ showStock?: boolean;
4299
+ showAvailability?: boolean;
4300
+ onProductClick?: (product: Product) => void;
4301
+ /**
4302
+ * Custom card for the PARTS list, forwarded to the inner ProductGrid. Without
4303
+ * it a product rendered with the host's custom card on a normal listing and
4304
+ * with the stock card here, so the same product looked different depending on
4305
+ * the page it was reached from (PWP-995c).
4306
+ */
4307
+ productCardComponent?: React$1.ComponentType<ProductCardProps>;
4308
+ paginationLabels?: Record<string, string>;
4309
+ filtersLabels?: Record<string, string>;
4310
+ toolbarLabels?: Record<string, string>;
4311
+ /**
4312
+ * Labels for the machine side of the grid. Keys read here: `loading` and
4313
+ * `noMachines`. The same object is passed to each `MachineCard` as its
4314
+ * `labels`, which reads `viewMachine` — so all three keys belong in it.
4315
+ */
4316
+ machineCardLabels?: Record<string, string>;
4317
+ /**
4318
+ * Labels for the PARTS list, forwarded verbatim to the inner ProductGrid and
4319
+ * the components it embeds.
4320
+ *
4321
+ * MachineGrid used to forward none of these and expose no way to reach them,
4322
+ * so a translated storefront rendered "In stock", "Add" and "Search parts…"
4323
+ * in English in the middle of its own copy. A monolingual shop never noticed
4324
+ * (PWP-995a).
4325
+ */
4326
+ productCardLabels?: Record<string, string>;
4327
+ addToCartLabels?: Record<string, string>;
4328
+ stockLabels?: Record<string, string>;
4329
+ priceLabels?: Record<string, string>;
4330
+ labels?: Record<string, string>;
4331
+ className?: string;
4332
+ }
4333
+ declare function MachineGrid(rawProps: MachineGridProps): React$1.JSX.Element;
4334
+
4335
+ /**
4336
+ * @rsc-blocked — Client-only component: side effects (useEffect).
4337
+ * Must be rendered inside (or below) a Client Component boundary; cannot be
4338
+ * imported directly into a React Server Component. The 'use client' header
4339
+ * above marks this boundary to Next.js.
4340
+ */
4341
+
4342
+ /**
4343
+ * A computed object containing a cluster config setting enriched with
4344
+ * its current UI state: available values for drilldown, the currently
4345
+ * selected value, and whether the selector should be disabled.
4346
+ */
4347
+ interface ClusterConfiguratorProps {
4348
+ /** The cluster ID this configurator belongs to. Required. */
4349
+ clusterId: number;
4350
+ /**
4351
+ * All products that belong to the cluster. Required.
4352
+ * Used to derive available values per attribute and to match
4353
+ * the configured product when all selections are made.
4354
+ */
4355
+ products: Product[];
4356
+ /**
4357
+ * Cluster configuration object (`cluster.config`). Required.
4358
+ * Provides the ordered list of attribute settings.
4359
+ */
4360
+ config: ClusterConfig;
4361
+ /**
4362
+ * Fired whenever the user completes a set of attribute selections
4363
+ * that uniquely identifies a cluster product.
4364
+ * Also fired whenever any selection changes and a matching product
4365
+ * can already be determined (e.g. only one setting exists).
4366
+ */
4367
+ onConfigurationChange?: (product: Product) => void;
4368
+ /** Default product to pre-populate the attribute selections on mount. */
4369
+ defaultProduct?: Product;
4370
+ /** Override any UI string. Available keys: selectOption */
4371
+ labels?: Record<string, string>;
4372
+ /** Extra CSS class applied to the root element. */
4373
+ className?: string;
4374
+ }
4375
+ /**
4376
+ * Renders attribute selectors (dropdown, radio, colour or image swatches) for
4377
+ * configuring a cluster, narrowing available values as the user selects and
4378
+ * emitting the matching product.
4379
+ *
4380
+ * @remarks Uses {@link useClusterConfigurator} to derive selectable values and
4381
+ * resolve the configured product.
4382
+ */
4383
+ declare function ClusterConfigurator(props: ClusterConfiguratorProps): React$1.JSX.Element;
4384
+
4385
+ /**
4386
+ * @rsc-blocked — Client-only component: side effects (useEffect).
4387
+ * Must be rendered inside (or below) a Client Component boundary; cannot be
4388
+ * imported directly into a React Server Component. The 'use client' header
4389
+ * above marks this boundary to Next.js.
4390
+ */
4391
+
4392
+ interface ClusterInfoProps {
4393
+ /** The authenticated user (Contact or Customer). Resolved from PropellerProvider when omitted. */
4394
+ user?: Contact | Customer | null;
4395
+ /**
4396
+ * Pre-fetched cluster object to display.
4397
+ * When provided the component skips internal fetching.
4398
+ */
4399
+ cluster?: Cluster;
4400
+ /**
4401
+ * Cluster ID to fetch data for when no `cluster` prop is provided.
4402
+ * Requires `graphqlClient` to be set.
4403
+ */
4404
+ clusterId?: number;
4405
+ /**
4406
+ * Initialised Propeller SDK GraphQL client.
4407
+ * Required when `clusterId` is provided for internal data fetching.
4408
+ */
4409
+ graphqlClient?: GraphQLClient;
4410
+ /**
4411
+ * Called once the cluster data is loaded — either immediately (when
4412
+ * `cluster` prop is supplied) or after the internal fetch completes.
4413
+ * Use this to hydrate sibling components (configurator, price, gallery, etc.).
4414
+ */
4415
+ onClusterLoaded?: (cluster: Cluster) => void;
4416
+ /** Show the cluster name. Defaults to true. */
4417
+ showTitle?: boolean;
4418
+ /** Show the cluster SKU. Defaults to true. */
4419
+ showSku?: boolean;
4420
+ /** Language code used to resolve localised names. Defaults to 'NL'. */
4421
+ language?: string;
4422
+ /** Extra CSS class applied to the root element. */
4423
+ className?: string;
4424
+ /**
4425
+ * Tax zone to use for price calculation.
4426
+ */
4427
+ taxZone?: string;
4428
+ /**
4429
+ * Image search filter passed to ProductService.getProduct().
4430
+ * Controls how many image items are returned.
4431
+ * Example: { page: 1, offset: 20 }
4432
+ */
4433
+ imageSearchFilters?: any;
4434
+ /**
4435
+ * Image variant transformation filter passed to ProductService.getProduct().
4436
+ * Controls image size/format variants returned with the product.
4437
+ * Example: imageVariantFiltersLarge from @/data/defaults
4438
+ * Defaults to { transformations: [] } when omitted.
4439
+ */
4440
+ imageVariantFilters?: any;
4441
+ /**
4442
+ * Config object providing imageSearchFiltersGrid and imageVariantFiltersSmall.
4443
+ */
4444
+ configuration?: any;
4445
+ /**
4446
+ * Attribute codes/names to look up and display as badge overlays on the product image.
4447
+ * Each code is resolved against `product.attributes.items[].attributeDescription.code`
4448
+ * (or `.name`). Attributes with no matching value are silently omitted.
4449
+ * Example: ['new', 'sale']
4450
+ */
4451
+ imageLabels?: string[];
4452
+ /**
4453
+ * Attribute codes/names to look up and display as extra text rows below the product name.
4454
+ * Resolved the same way as `imageLabels`.
4455
+ * Example: ['brand', 'color']
4456
+ */
4457
+ textLabels?: string[];
4458
+ }
4459
+ /**
4460
+ * Displays a cluster's name and SKU heading, either from a supplied `cluster`
4461
+ * prop or by fetching it from the SDK by `clusterId`.
4462
+ *
4463
+ * @remarks Uses {@link useProductInfo} to fetch the cluster when only an ID is given.
4145
4464
  */
4146
4465
  declare function ClusterInfo(rawProps: ClusterInfoProps): React$1.JSX.Element;
4147
4466
 
@@ -5916,353 +6235,56 @@ interface ProductBundlesProps {
5916
6235
  * When true, the individual bundle items are listed inside each bundle card.
5917
6236
  * Defaults to true.
5918
6237
  */
5919
- showIndividualItems?: boolean;
5920
- /** Additional configuration object passed through to the component. */
5921
- configuration?: any;
5922
- /**
5923
- * Layout variant for the bundle display.
5924
- * - 'vertical' — stacked layout
5925
- * - 'horizontal' — side-by-side (default)
5926
- * - 'compact' — condensed, hides individual items
5927
- */
5928
- layout?: 'vertical' | 'horizontal' | 'compact';
5929
- /**
5930
- * Override any UI string.
5931
- * Available keys: title, condition_ALL, condition_EP, leaderItem,
5932
- * youSave, adding, addToCart, loginToSeePrices, addedToCart,
5933
- * modalTitle, continueShopping, proceedToCheckout, noCartId
5934
- */
5935
- labels?: Record<string, string>;
5936
- /**
5937
- * Show the "log in to see prices" prompt when prices are hidden.
5938
- * Defaults to true; pass false to render nothing in its place.
5939
- */
5940
- showLoginPrompt?: boolean;
5941
- /**
5942
- * When true a modal popup is shown after a successful add-to-cart
5943
- * with buttons to continue shopping or proceed to checkout.
5944
- * Defaults to false (only a brief inline toast is shown).
5945
- */
5946
- showModal?: boolean;
5947
- /** Callback fired when the "Proceed to checkout" modal button is clicked */
5948
- onProceedToCheckout?: () => void;
5949
- /**
5950
- * Callback triggered before adding the bundle to cart.
5951
- */
5952
- beforeBundleAddToCart?: (bundleId: string, quantity: number) => boolean;
5953
- /** Called when the user clicks "Add bundle to cart". Receives bundleId and quantity (always 1). */
5954
- onAddBundleToCart?: (bundleId: string, quantity: number) => void;
5955
- /**
5956
- * Callback triggered after adding the bundle to cart.
5957
- */
5958
- afterBundleAddToCart?: (cart: Cart, bundle?: Bundle) => void;
5959
- /** Extra CSS class applied to the root wrapper element. */
5960
- className?: string;
5961
- }
5962
- /**
5963
- * Renders combo-deal bundles for a product, each with its constituent items,
5964
- * pricing and savings, plus add-to-cart with toast or modal feedback.
5965
- *
5966
- * @remarks Uses {@link useProductBundles} to fetch bundles and add them to a cart.
5967
- */
5968
- declare function ProductBundles(rawProps: ProductBundlesProps): React$1.JSX.Element;
5969
-
5970
- /**
5971
- * Props for the root `<ProductCard>` (and the back-compat monolithic
5972
- * variant). Most fields are display toggles preserved for back-compat; in
5973
- * the new compound API, consumers control rendering by composition instead
5974
- * — see the Subcomponents section below.
5975
- */
5976
- interface ProductCardProps {
5977
- /** The product object to display */
5978
- product: Product;
5979
- /**
5980
- * Compound API: provide subcomponents as children. When omitted, the
5981
- * monolithic legacy layout renders based on the show*/ children?: React$1.ReactNode;
5982
- /** Show the product name. Defaults to true. */
5983
- showName?: boolean;
5984
- /** Show the product image. Defaults to true. */
5985
- showImage?: boolean;
5986
- /** Show the product short description. Defaults to false. */
5987
- showShortDescription?: boolean;
5988
- /** Show the product SKU. Defaults to true. */
5989
- showSku?: boolean;
5990
- /** Show the product manufacturer. Defaults to false. */
5991
- showManufacturer?: boolean;
5992
- /**
5993
- * Show the stock / availability widget below the product name.
5994
- * Uses the embedded `ItemStock` component driven by `product.inventory`.
5995
- * Defaults to false.
5996
- */
5997
- showStock?: boolean;
5998
- /**
5999
- * Show only the availability indicator (Available / Not available) inside ItemStock.
6000
- * Only relevant when `showStock` is true.
6001
- * Defaults to true.
6002
- */
6003
- showAvailability?: boolean;
6004
- /**
6005
- * Show the price below the product name.
6006
- * Defaults to true.
6007
- */
6008
- showPrice?: boolean;
6009
- /**
6010
- * Show the AddToCart component.
6011
- * Defaults to true.
6012
- */
6013
- allowAddToCart?: boolean;
6014
- /**
6015
- * Label overrides forwarded to the embedded ItemStock component.
6016
- * Keys: inStock, outOfStock, lowStock, available, notAvailable, pieces
6017
- */
6018
- stockLabels?: Record<string, string>;
6019
- /**
6020
- * Attribute codes/names to look up and display as badge overlays on the product image.
6021
- * Example: ['new', 'sale']
6022
- */
6023
- imageLabels?: string[];
6024
- /**
6025
- * Attribute codes/names to look up and display as extra text rows below the product name.
6026
- * Example: ['brand', 'color']
6027
- */
6028
- textLabels?: string[];
6029
- /** Override any UI string. Keys: addToFavorites, removeFromFavorites */
6030
- labels?: Record<string, string>;
6031
- /** Renders a heart-icon toggle button on the product image. Defaults to false. */
6032
- enableAddFavorite?: boolean;
6033
- /** Called whenever the favourite state is toggled. */
6034
- onToggleFavorite?: (product: Product, isFavorite: boolean) => void;
6238
+ showIndividualItems?: boolean;
6239
+ /** Additional configuration object passed through to the component. */
6240
+ configuration?: any;
6035
6241
  /**
6036
- * Called when the product name or image is clicked.
6037
- * When provided, the default `<a>` navigation is prevented.
6242
+ * Layout variant for the bundle display.
6243
+ * - 'vertical' — stacked layout
6244
+ * - 'horizontal' — side-by-side (default)
6245
+ * - 'compact' — condensed, hides individual items
6038
6246
  */
6039
- onProductClick?: (product: Product) => void;
6040
- /** When true, tax-inclusive (net) price is the leading price. Defaults to false. */
6041
- includeTax?: boolean;
6042
- /** Number of grid columns — when 1 the card renders as a compact horizontal row. */
6043
- columns?: number;
6044
- /** Extra CSS class applied to the root element. */
6045
- className?: string;
6247
+ layout?: 'vertical' | 'horizontal' | 'compact';
6046
6248
  /**
6047
- * URL pattern controlling which segments appear in product links.
6048
- * Tokens: page → 'product', id → productId, slug → slug value.
6049
- * Defaults to 'page/id/slug'.
6249
+ * Override any UI string.
6250
+ * Available keys: title, condition_ALL, condition_EP, leaderItem,
6251
+ * youSave, adding, addToCart, loginToSeePrices, addedToCart,
6252
+ * modalTitle, continueShopping, proceedToCheckout, noCartId
6050
6253
  */
6051
- urlPattern?: string;
6052
- /** GraphQL client for the embedded AddToCart. Resolved from PropellerProvider when omitted. */
6053
- graphqlClient?: GraphQLClient;
6054
- /** Authenticated user. Resolved from PropellerProvider when omitted. */
6055
- user?: Contact | Customer | null;
6254
+ labels?: Record<string, string>;
6056
6255
  /**
6057
- * Portal access mode — `'open'` / `'semi-closed'` / `'closed'`. Resolved from
6058
- * PropellerProvider when omitted. In `'semi-closed'` the card hides price and
6059
- * stock from anonymous visitors and offers a log-in action in place of
6060
- * add-to-cart; signed-in users are unaffected.
6256
+ * Show the "log in to see prices" prompt when prices are hidden.
6257
+ * Defaults to true; pass false to render nothing in its place.
6061
6258
  */
6062
- portalMode?: string;
6259
+ showLoginPrompt?: boolean;
6063
6260
  /**
6064
- * Invoked when an anonymous visitor clicks the log-in action that replaces
6065
- * add-to-cart in a semi-closed portal. The host owns navigation.
6261
+ * When true a modal popup is shown after a successful add-to-cart
6262
+ * with buttons to continue shopping or proceed to checkout.
6263
+ * Defaults to false (only a brief inline toast is shown).
6066
6264
  */
6067
- onLoginClick?: () => void;
6068
- /** ID of the cart that add-to-cart targets. */
6069
- cartId?: string;
6070
- /** Configuration object (URL builders, image filters, etc.). */
6071
- configuration?: any;
6072
- /** Cluster ID when this card represents a variant of a product cluster. */
6073
- clusterId?: number;
6074
- /** Pre-selected child item product IDs added alongside the product. */
6075
- childItems?: number[];
6076
- /** Order-line notes forwarded with the add-to-cart request. */
6077
- notes?: string;
6078
- /** Custom price override forwarded with the add-to-cart request. */
6079
- price?: number;
6080
- /** When true, a new cart is created if no `cartId` is set. */
6081
- createCart?: boolean;
6082
- /** Fires when add-to-cart creates a new cart. */
6083
- onCartCreated?: (cart: Cart) => void;
6084
- /** Delegation handler — when provided, the parent performs the add-to-cart itself. */
6085
- onAddToCart?: (product: Product, clusterId?: number, quantity?: number, childItems?: CartChildItemInput[], notes?: string, price?: number, showModal?: boolean) => Cart;
6086
- /** Fires after an item has been added to the cart. */
6087
- afterAddToCart?: (cart: Cart, item?: CartMainItem) => void;
6088
- /** When true, show a confirmation modal after add-to-cart instead of a toast. */
6089
6265
  showModal?: boolean;
6090
- /** When true, the AddToCart shows quantity increment/decrement controls. */
6091
- allowIncrDecr?: boolean;
6092
- /** When true, stock availability is validated before adding to cart. */
6093
- enableStockValidation?: boolean;
6094
- /** Language code for localised content. Resolved from PropellerProvider when omitted. */
6095
- language?: string;
6096
- /** Active company ID from the company switcher. */
6097
- companyId?: number;
6098
- /** Fires when the "Proceed to checkout" modal button is clicked. */
6266
+ /** Callback fired when the "Proceed to checkout" modal button is clicked */
6099
6267
  onProceedToCheckout?: () => void;
6100
- /** Fires when the user requests a quote from the AddToCart modal. */
6101
- onRequestQuoteClick?: (cart: Cart) => void;
6102
- /** Label overrides forwarded to the embedded AddToCart component. */
6103
- addToCartLabels?: Record<string, string>;
6104
- /** Translated labels forwarded to the embedded `<ProductPrice>` display.
6105
- * See `ProductPriceProps.labels` for slugs (inclTax, exclTax, loginToSeePrices). */
6106
- priceLabels?: Record<string, string>;
6107
- /** Replaces the default price block. Receives `PriceComponentProps`. */
6108
- /** Currency symbol used when formatting the price. Falls back to PropellerInfra.currency, then `'€'`. */
6109
- currency?: string;
6110
- priceComponent?: React$1.ComponentType<_propeller_commerce_propeller_v2_core_ui.PriceComponentProps>;
6111
- /** Replaces the default stock/availability block. Receives `StockComponentProps`. */
6112
- stockComponent?: React$1.ComponentType<_propeller_commerce_propeller_v2_core_ui.StockComponentProps>;
6113
- /** Replaces the default add-to-cart control. Receives `AddToCartComponentProps`. */
6114
- addToCartComponent?: React$1.ComponentType<_propeller_commerce_propeller_v2_core_ui.AddToCartComponentProps>;
6115
- /** Replaces the default product image block. Receives `ImageComponentProps`. */
6116
- imageComponent?: React$1.ComponentType<_propeller_commerce_propeller_v2_core_ui.ImageComponentProps>;
6117
- /** Replaces the default product badges block. Receives `BadgesComponentProps`. */
6118
- badgesComponent?: React$1.ComponentType<_propeller_commerce_propeller_v2_core_ui.BadgesComponentProps>;
6119
- /** Replaces the default favorite-toggle. Receives `FavoriteComponentProps`. */
6120
- favoriteComponent?: React$1.ComponentType<_propeller_commerce_propeller_v2_core_ui.FavoriteComponentProps>;
6121
6268
  /**
6122
- * Render arbitrary content directly below the product name (and above the
6123
- * short description / price), in both the grid and row layouts. Receives the
6124
- * product so hosts can surface extra info — e.g. package descriptions, custom
6125
- * badges — without forking the card. Return `null`/`undefined` to render
6126
- * nothing for a given product.
6269
+ * Callback triggered before adding the bundle to cart.
6127
6270
  */
6128
- belowName?: (product: Product) => React$1.ReactNode;
6129
- }
6130
- /**
6131
- * Root of the `<ProductCard>` compound component. Renders either the
6132
- * consumer-composed children (compound mode) or the legacy monolithic layout
6133
- * driven by `show*`/`allow*` toggles, and provides the shared card context.
6134
- */
6135
- declare function ProductCardRoot(rawProps: ProductCardProps): React$1.JSX.Element;
6136
- /**
6137
- * Product image with optional badge overlays and favourite button.
6138
- * Reads `derived.imageUrl`, `derived.imageLabelValues`, `derived.productUrl`,
6139
- * and the `favorite` state from context.
6140
- *
6141
- * Trade-off: when `imageComponent` is injected, the consumer takes over the
6142
- * ENTIRE image area — including the badge / favorite overlay layer.
6143
- * The default markup wraps the `<img>` in a link with absolute-positioned
6144
- * badges and a favorite button; an injected component receives only the
6145
- * `ImageComponentProps` contract and is free to re-render those overlays
6146
- * itself (e.g. by composing `<DefaultProductBadges>` / `<DefaultAddToFavorite>`)
6147
- * or omit them entirely.
6148
- */
6149
- declare function ProductCardImage(props: {
6150
- /** Override the wrapper class. */
6151
- className?: string;
6152
- /** Render the favourite heart button. Defaults to context `enableAddFavorite`. */
6153
- showFavorite?: boolean;
6154
- }): React$1.JSX.Element;
6155
- /** Image-overlay badge list (e.g. "new", "sale" attributes), or the
6156
- * injected `badgesComponent` from context when set. */
6157
- declare function ProductCardBadges(props: {
6158
- /** Override the badge container class. */
6159
- className?: string;
6160
- }): React$1.JSX.Element | null;
6161
- /** Favourite (heart) toggle button — typically placed inside `<ProductCard.Image>`,
6162
- * or the injected `favoriteComponent` from context when set.
6163
- *
6164
- * The default render is the inline self-contained heart button (local state
6165
- * only, fires `onToggleFavorite`); the injected variant receives the full
6166
- * `FavoriteComponentProps` contract (product, user, callback) so consumers
6167
- * can plug in real favorite-list mutations. The unused import of
6168
- * `DefaultAddToFavoriteImpl` is kept so consumers can wrap-and-call it. */
6169
- declare function ProductCardFavorite(props: {
6170
- /** Override the button class. */
6171
- className?: string;
6172
- }): React$1.JSX.Element;
6173
- /** Product name. `linkable` (default true) wraps it in an `<a>` to the PDP. */
6174
- declare function ProductCardName(props: {
6175
- /** When true (default), wraps the name in a link to the product page. */
6176
- linkable?: boolean;
6177
- /** Override the name element class. */
6178
- className?: string;
6179
- }): React$1.JSX.Element;
6180
- /** Renders the product SKU. */
6181
- declare function ProductCardSku(props: {
6182
- /** Override the SKU element class. */
6183
- className?: string;
6184
- }): React$1.JSX.Element | null;
6185
- /** Renders the product's short description. */
6186
- declare function ProductCardShortDescription(props: {
6187
- /** Override the description element class. */
6188
- className?: string;
6189
- }): React$1.JSX.Element | null;
6190
- /** Renders the product manufacturer name. */
6191
- declare function ProductCardManufacturer(props: {
6192
- /** Override the manufacturer element class. */
6193
- className?: string;
6194
- }): React$1.JSX.Element | null;
6195
- /** Renders the resolved `textLabels` attribute values as text rows. */
6196
- declare function ProductCardTextLabels(props: {
6197
- /** Override the label container class. */
6198
- className?: string;
6199
- }): React$1.JSX.Element | null;
6200
- /** Renders the embedded stock/availability widget for the product, or the
6201
- * injected `stockComponent` from context when set. */
6202
- declare function ProductCardStock(props: {
6203
- /** Show only the availability indicator. Defaults to context `showAvailability`. */
6204
- showAvailability?: boolean;
6205
- }): React$1.JSX.Element | null;
6206
- /** Renders host-supplied content directly below the name, via the `belowName`
6207
- * render prop (explicit or from grid context). Renders nothing when unset or
6208
- * when the render prop returns a nullish value. */
6209
- declare function ProductCardBelowName(): React$1.JSX.Element | null;
6210
- /** Renders the product price via the embedded `ProductPrice` component, or
6211
- * the injected `priceComponent` from context when set. */
6212
- declare function ProductCardPrice(props: {
6213
- /** Tailwind text-size class for the price. Defaults to `'text-base sm:text-lg'`. */
6214
- priceSize?: string;
6215
- /** Override the price wrapper class. */
6216
- className?: string;
6217
- }): React$1.JSX.Element | null;
6218
- /** Renders the embedded `AddToCart` control with all pass-through props from
6219
- * context, or the injected `addToCartComponent` when set.
6220
- *
6221
- * Note: the default `AddToCartImpl` accepts a richer prop set (graphqlClient,
6222
- * configuration, etc.) than the public `AddToCartComponentProps` contract.
6223
- * Injected components only receive the contract surface; the extra infra
6224
- * props stay default-only. */
6225
- declare function ProductCardAddToCart(props: {
6226
- /** Override the AddToCart wrapper class. */
6271
+ beforeBundleAddToCart?: (bundleId: string, quantity: number) => boolean;
6272
+ /** Called when the user clicks "Add bundle to cart". Receives bundleId and quantity (always 1). */
6273
+ onAddBundleToCart?: (bundleId: string, quantity: number) => void;
6274
+ /**
6275
+ * Callback triggered after adding the bundle to cart.
6276
+ */
6277
+ afterBundleAddToCart?: (cart: Cart, bundle?: Bundle) => void;
6278
+ /** Extra CSS class applied to the root wrapper element. */
6227
6279
  className?: string;
6228
- }): React$1.JSX.Element;
6229
- declare const MemoizedRoot: React$1.MemoExoticComponent<typeof ProductCardRoot>;
6280
+ }
6230
6281
  /**
6231
- * Compound component. Use either:
6232
- *
6233
- * **Compound mode (new — preferred):**
6234
- * ```tsx
6235
- * <ProductCard product={p}>
6236
- * <ProductCard.Image variant="grid" />
6237
- * <ProductCard.Name linkable />
6238
- * <ProductCard.Sku />
6239
- * <ProductCard.Price />
6240
- * <ProductCard.AddToCart />
6241
- * </ProductCard>
6242
- * ```
6282
+ * Renders combo-deal bundles for a product, each with its constituent items,
6283
+ * pricing and savings, plus add-to-cart with toast or modal feedback.
6243
6284
  *
6244
- * **Legacy mode (deprecated — kept for back-compat):**
6245
- * ```tsx
6246
- * <ProductCard product={p} showName showPrice allowAddToCart />
6247
- * ```
6248
- * All the show* / allow* toggles still work and render the canonical layout
6249
- * using the compound subcomponents internally.
6285
+ * @remarks Uses {@link useProductBundles} to fetch bundles and add them to a cart.
6250
6286
  */
6251
- type ProductCardComponent = typeof MemoizedRoot & {
6252
- Image: typeof ProductCardImage;
6253
- Badges: typeof ProductCardBadges;
6254
- Favorite: typeof ProductCardFavorite;
6255
- Name: typeof ProductCardName;
6256
- Sku: typeof ProductCardSku;
6257
- BelowName: typeof ProductCardBelowName;
6258
- ShortDescription: typeof ProductCardShortDescription;
6259
- Manufacturer: typeof ProductCardManufacturer;
6260
- TextLabels: typeof ProductCardTextLabels;
6261
- Stock: typeof ProductCardStock;
6262
- Price: typeof ProductCardPrice;
6263
- AddToCart: typeof ProductCardAddToCart;
6264
- };
6265
- declare const ProductCard: ProductCardComponent;
6287
+ declare function ProductBundles(rawProps: ProductBundlesProps): React$1.JSX.Element;
6266
6288
 
6267
6289
  /**
6268
6290
  * @rsc-blocked — Client-only component: interactive state (useState/useReducer).