# Types: NotifyMeCopy to BundleGroup (/themes/sdk/reference/product/types-5)

```ts
import { … } from '@poltura/theme-sdk/product';
```

## `NotifyMeCopy` [#notifymecopy]

Texts of [`NotifyMe`](/themes/sdk/reference/product/defaults-2#notifyme) that replace the platform's own.

<TypeTable type={{"title":{"description":"The heading.","type":"string","required":false},"description":{"description":"The line under the heading.","type":"string","required":false},"emailLabel":{"description":"The address field's label.","type":"string","required":false},"emailPlaceholder":{"description":"The address field's placeholder.","type":"string","required":false},"submit":{"description":"The button text.","type":"string","required":false},"submitting":{"description":"The button text while sending.","type":"string","required":false},"newsletter":{"description":"Ignored: the newsletter box always shows the store's consent sentence.","type":"string","required":false,"deprecated":true},"success":{"description":"The message once the request is in.","type":"string","required":false},"privacy":{"description":"The privacy line under the form.","type":"string","required":false}}} />

## `NotifyMeProps` [#notifymeprops]

Props of [`NotifyMe`](/themes/sdk/reference/product/defaults-2#notifyme).

<TypeTable type={{"variantId":{"description":"The variant to hear about.","type":"string","required":true},"reason":{"description":"Why it cannot be bought now.","type":"NotifyMeReason","required":true},"copy":{"description":"Texts that replace the platform's own.","type":"NotifyMeCopy","required":false},"className":{"description":"Classes added to the form.","type":"string","required":false}}} />

## `NotifyMeReason` [#notifymereason]

Why a shopper asks to hear when a variant can be bought.

```ts
type NotifyMeReason = 'comingSoon' | 'preorderFull' | 'outOfStock'
```

## `NotifyMeState` [#notifymestate]

The state of a notify-me form: the address, the newsletter choice and the request.

<TypeTable type={{"enabled":{"description":"Whether the store sends stock notices at all.","type":"boolean","required":true},"email":{"description":"The address the notice goes to, the signed-in customer's by default.","type":"string","required":true},"setEmail":{"description":"Changes the address.","type":"(email: string) => void","required":true},"newsletter":{"description":"Whether the shopper also subscribes to the newsletter.","type":"boolean","required":true},"consent":{"description":"The store's marketing consent sentence: the newsletter box's label, held to every sign-up.","type":"string","required":true},"setNewsletter":{"description":"Changes the newsletter choice.","type":"(newsletter: boolean) => void","required":true},"status":{"description":"Where the request stands.","type":"NotifyMeStatus","required":true},"confirmationSent":{"description":"After `done`, whether a confirmation email was sent that the shopper must click first.","type":"boolean","required":true},"error":{"description":"Why the request failed, in the page language, or null.","type":"string | null","required":true},"submit":{"description":"Sends the request and resolves with the status it ends in.","type":"() => Promise<NotifyMeStatus>","required":true}}} />

## `NotifyMeStatus` [#notifymestatus]

Where a notify-me request stands.

```ts
type NotifyMeStatus = 'idle' | 'invalid' | 'submitting' | 'done' | 'error'
```

## `ProductScopeProps` [#productscopeprops]

Props of [`ProductScope`](/themes/sdk/reference/product/parts-1#productscope).

<TypeTable type={{"product":{"description":"The product the code below is about.","type":"Product","required":true},"children":{"description":"The code that reads the product.","type":"ReactNode","required":true}}} />

## `ProductBuy` [#productbuy]

The buy box of the nearest product: the chosen variant, the quantity and adding it to the cart.

<TypeTable type={{"product":{"description":"The product being bought.","type":"Product","required":true},"variant":{"description":"The chosen variant, or null while the choice matches none.","type":"Variant | null","required":true},"quantity":{"description":"The quantity to add.","type":"number","required":true},"setQuantity":{"description":"Changes the quantity to add.","type":"(quantity: number) => void","required":true},"canAdd":{"description":"Whether the chosen variant can be added now.","type":"boolean","required":true},"isAdding":{"description":"Whether an add is under way.","type":"boolean","required":true},"error":{"description":"Why the last add failed, in the page language, or null.","type":"string | null","required":true},"add":{"description":"Adds the chosen variant and quantity to the cart; on the product page also the personalisation, gift card and bundle filled in.","type":"() => Promise<CartResult>","required":true},"ctaLabel":{"description":"The buy button's text: add to cart, pre-order or sold out, in the page language.","type":"string","required":true},"wallet":{"description":"The express wallets of the product page.","type":"{ readonly visible: boolean; }","required":true},"wholesale":{"description":"A wholesale buyer's tier prices for the chosen variant, or null for everyone else.","type":"WholesaleTiersView | null","required":true},"personalization":{"description":"The texts the shopper fills in to personalise the item, or null when the product has none or the box is not the product page's.","type":"PersonalizationState | null","required":true},"giftCard":{"description":"The gift card's amount, recipient and delivery, or null for a product that is not a gift card or a box that is not the product page's.","type":"GiftCardState | null","required":true},"bundle":{"description":"The bundle offered with the product and the shopper's choice in it, or null without an offer.","type":"BundleSelectionState | null","required":true}}} />

## `GalleryAspect` [#galleryaspect]

How a gallery frame crops its image.

```ts
type GalleryAspect = 'square' | 'portrait' | 'landscape' | 'natural'
```

## `ProductGalleryImageProps` [#productgalleryimageprops]

Props of [`ProductGalleryImage`](/themes/sdk/reference/product/parts-2#productgalleryimage).

<TypeTable type={{"image":{"description":"The image, or null for the placeholder.","type":"MediaImageRef | null","required":true},"aspect":{"description":"How the frame crops the image; defaults to square.","type":"GalleryAspect","required":false},"priority":{"description":"Loads the image first, for the one above the fold.","type":"boolean","required":false},"className":{"description":"Classes added to the frame.","type":"string","required":false}}} />

## `ProductGalleryProps` [#productgalleryprops]

Props of [`ProductGallery`](/themes/sdk/reference/product/defaults-3#productgallery).

<TypeTable type={{"layout":{"description":"Every image stacked, one image with thumbnails, or the first image alone; defaults to the stack.","type":"'grid' | 'carousel' | 'single'","required":false},"aspect":{"description":"How the frames crop the images; defaults to square.","type":"GalleryAspect","required":false},"className":{"description":"Classes added to the gallery.","type":"string","required":false}}} />

## `ProductGalleryThumbsProps` [#productgallerythumbsprops]

Props of [`ProductGalleryThumbs`](/themes/sdk/reference/product/parts-2#productgallerythumbs).

<TypeTable type={{"images":{"description":"The images, in order.","type":"readonly MediaImageRef[]","required":true},"active":{"description":"The index of the image shown.","type":"number","required":true},"onSelect":{"description":"Shows the image at an index.","type":"(index: number) => void","required":true},"className":{"description":"Classes added to the row.","type":"string","required":false}}} />

## `BundleConfiguratorProps` [#bundleconfiguratorprops]

Props of [`BundleConfigurator`](/themes/sdk/reference/product/parts-2#bundleconfigurator).

<TypeTable type={{"bundle":{"description":"The bundle to configure.","type":"Bundle","required":true},"horizontal":{"description":"Lays the items out in a row.","type":"boolean","required":false},"hideHeading":{"description":"Leaves out the bundle's heading.","type":"boolean","required":false},"className":{"description":"Classes added to the configurator.","type":"string","required":false}}} />

## `BundleSuggestionsProps` [#bundlesuggestionsprops]

Props of [`BundleSuggestions`](/themes/sdk/reference/product/parts-2#bundlesuggestions).

<TypeTable type={{"bundles":{"description":"The bundles to suggest, best first.","type":"readonly Bundle[]","required":true},"activeBundleId":{"description":"The id of the bundle being configured, which shows as selected.","type":"string | null","required":true},"onSelectBundle":{"description":"Called with the id of the bundle the shopper chose to configure.","type":"(bundleId: string) => void","required":true},"className":{"description":"Classes added to the panel.","type":"string","required":false}}} />

## `Bundle` [#bundle]

A bundle: products sold together at a saving.

<TypeTable type={{"id":{"description":"The bundle's id.","type":"string","required":true},"title":{"description":"The bundle's title.","type":"string","required":true},"mode":{"description":"How the bundle sells.","type":"BundleMode","required":true},"heading":{"description":"The merchant's heading for the offer, or null.","type":"string | null","required":true},"subtext":{"description":"The merchant's line under the heading, or null.","type":"string | null","required":true},"badge":{"description":"The merchant's badge text, such as \"Save 15%\", or null.","type":"string | null","required":true},"productId":{"description":"The product the bundle is offered with.","type":"string","required":true},"currencyCode":{"description":"The currency of the bundle's amounts, or null while unknown.","type":"string | null","required":true},"groups":{"description":"The groups items are chosen in.","type":"readonly BundleGroup[]","required":true},"items":{"description":"The items, in the merchant's order.","type":"readonly BundleItem[]","required":true}}} />

## `BundleGroup` [#bundlegroup]

A group of bundle items the shopper picks a number of, such as "Choose 2 sauces".

<TypeTable type={{"id":{"description":"The group's id.","type":"string","required":true},"label":{"description":"The group's label in the page language.","type":"string","required":true},"min":{"description":"The fewest items to choose.","type":"number","required":true},"max":{"description":"The most items to choose.","type":"number","required":true}}} />
