import { BaseProviderConfig, BaseSearchProviderConfig, ModernDisplayWithPageUrl, SearchFilter, BaseCategoryProviderConfig, ListingQuery, BaseProductListingConfig, ProductCardTemplate, BaseSearchPageConfig, BaseCategoryPageConfig, CategoryTitle, embedded_num_products, DisplayTransformers, SDKColsAtSize, SDKGridSpacing, ImagePlaceholder as _ImagePlaceholder1, TextPlaceholder as _TextPlaceholder1 } from "@depict-ai/ui/latest"; import { search_i18n, category_i18n, plp_shared_i18n } from "@depict-ai/ui/locales/latest"; import { Display, ModernDisplay } from "@depict-ai/utilishared/latest"; import { Accessor, JSX } from "solid-js"; export const version = "4.10.10"; type SearchProviderConfig = BaseProviderConfig & BaseSearchProviderConfig & { locale: search_i18n; }; export class DepictSearchProvider : never> { #private; openModal(alignerElement?: HTMLElement): void; fetchSearchResults(query: string, filters?: SearchFilter[], maxResults?: number): Promise<([OutputDisplay] extends [never] ? OriginalDisplay : ModernDisplayWithPageUrl)[]>; constructor(options: SearchProviderConfig); } type CategoryProviderConfig = BaseCategoryProviderConfig & BaseProviderConfig & { /** * The listing to query Depict for. `type` can be `"listingId"` or `"externalId"`.. * If `id` is `"listingId"`, it should be a uuid where Depict is the source of truth, you can get them here: https://api.depict.ai/docs#tag/Listing/operation/Get_Listings_v3_listings_get. * If `id` is `"externalId"`, it should be the id of the product listing in your system - whatever was passed to Depict during data ingestion. */ listingQuery: ListingQuery; /** * Category internationalisation (strings, price formatting and locale to request from backend) */ locale: category_i18n; }; export class DepictCategoryProvider : never> { #private; readonly imageResizer?: (url: string, width: number) => string; get listingQuery(): ListingQuery; set listingQuery(query: ListingQuery); get disableOverrideListingId(): boolean | undefined; set disableOverrideListingId(disable: boolean | undefined); constructor(options: CategoryProviderConfig); } interface PLPConfig extends BaseProductListingConfig { /** * The product card function to use for rendering products. */ productCard: ProductCardTemplate; } interface RecommendationRenderingConfig extends BaseProductListingConfig { /** * A promise containing the recommendations to render, see https://docs.depict.ai/api-guide/recommendations/api-client/fetching */ recommendations: Promise; /** * The product card function to use for rendering products. */ productCard: ProductCardTemplate; /** * Optional title to show when recommendations are being shown */ title?: string; } /** * The interface for a content block. * Please make sure that you don't have content blocks overlap as that will cause undefined behavior. * The height of the content block will be the height of the tallest item in a row, so if there are no products in a row the content block needs to "bring its own height". * If you need to load any data in the content block, please make sure to return a placeholder while you're doing so (see `ImagePlaceholder`), to avoid layout shifts and ensure scroll restoration works correctly. * * - `spanColumns`: How many columns the block should span. This will be capped to the number of columns available. * - `spanRows`: How many rows the block should span. * - `position`: Where the block should be positioned. Can be `left`, `center` or `right`. * - `content`: The content to render in the block - please provide a function returning one or multiple HTML elements. */ export type JSUIContentBlock = { spanColumns: number; spanRows: number; position: "left" | "center" | "right"; content: () => HTMLElement; }; /** * A sparse array containing content blocks to show (or an empty slot or undefined if there's no block at that index). See JSUIContentBlock for how a content block looks like. The index is the row where the content block should be shown. * For example, to create a block on row 1 and 3 you'd do `[, block1, , block2]`. * Alternatively: * ``` * const blocks = []; * blocks[1] = block1; * blocks[3] = block2; * ``` */ export type JSUIContentBlocksByRow = (undefined | JSUIContentBlock)[]; interface SearchPageConfig extends BaseSearchPageConfig, PLPConfig<[OutputDisplay] extends [never] ? OriginalDisplay : ModernDisplayWithPageUrl> { searchProvider: DepictSearchProvider; /** * Can be used to know when the search query is changed and update other content on the page accordingly. Will be called when the SearchPage is created, every time the query changes and when the SearchPage is destroyed. When newQuery is undefined it means the search page has been closed/left. */ onQueryChange?: (newQuery?: string | undefined, oldQuery?: string | undefined) => void; /** * Function returning content blocks (JSUIContentBlocksByRow). Use contentBlockStore if you want to be able to manipulate the content blocks later on. */ getContentBlocksByRow?: Accessor; } export function SearchPage({ searchProvider, includeInputField, gridSpacing, columnsAtSize, productCard, onQueryChange, getContentBlocksByRow }: SearchPageConfig): HTMLElement; interface SearchFieldConfig { searchProvider: DepictSearchProvider; /** * A DOM element that the modal should be aligned to. * * The top of the modal will be aligned to the top of the element. * * The height of the search field in the modal will be the same as the height of the element. * If not provided, the modal will be aligned to the search field itself. */ alignerRef?: HTMLElement; } export function SearchField({ searchProvider, alignerRef }: SearchFieldConfig): HTMLElement; interface CategoryPageConfig extends BaseCategoryPageConfig, PLPConfig<[OutputDisplay] extends [never] ? OriginalDisplay : ModernDisplayWithPageUrl> { categoryProvider: DepictCategoryProvider; /** * categoryTitlePlugin is an optional plugin that can be used to customize the title of the category page. * The default is `CategoryTitle` which shows the title of the category and the number of products within. * EmbeddedNumProducts on the other hand only displays the number of products within a category and tries to fit this between the sort and filter button on mobile, if the text length of the localisation permits. * @default CategoryTitle * * @example * ```tsx * * ``` */ categoryTitlePlugin?: typeof CategoryTitle | typeof embedded_num_products; /** * Can be used to know when the CategoryPage is navigated to a new category and update other content on the page accordingly. * When newListingId is undefined it means the category page has been closed/left, or you have provided undefined as the listingId prop to the provider. */ onListingQueryChange?: (newListingId?: ListingQuery | undefined, oldListingId?: ListingQuery | undefined) => void; /** * Function returning content blocks (JSUIContentBlocksByRow). Use contentBlockStore if you want to be able to manipulate the content blocks later on. */ getContentBlocksByRow?: Accessor; } export function CategoryPage({ gridSpacing, columnsAtSize, productCard, categoryProvider, showBreadcrumbs, showQuicklinks, categoryTitlePlugin, onListingQueryChange, getContentBlocksByRow, layout }: CategoryPageConfig): HTMLElement; type renderMode = "append" | "replace"; interface PageReplacerConfig { isPageToReplace: (url: URL) => boolean; selectorToReplace: string; renderContent: () => HTMLElement | HTMLElement[]; renderMode?: renderMode; documentTitle?: string; } /** * SetupPageReplacer is a function that can be used to layer SPA (single page application) functionality on top of a standard server side rendered webpage, for certain pages. * An example use case is to instantly (without a server page request) navigate to the Depict search result page, or between one query to the next. * PageReplacer works by listening to URL changes (performed via `history.pushState`), testing if they match the `isPageToReplace` criteria, then replacing a specified element with another element. * The element that is replaced is specified by a CSS selector and usually represents the "main content" container of the page. The "replacement" works by setting `display: none` on the original content and adding the new content immediately after it in the DOM. * @param renderContent A function that returns the element(s) which replace the "page" when `isPageToReplace` returns `true`. * @param documentTitle The title that `document.title` should be changed to when page replacement is active (when `isPageToReplace` returns `true`). * @param isPageToReplace A function that returns `true` if the provided URL is a page where the replacement should be active. * @param selectorToReplace A CSS selector that selects the element to replace. * @param renderMode If set to `"append"`, the new element will be appended to the element that is found by `selectorToReplace` instead of replacing it. This is useful in certain edge cases. * @returns A function that can be called to destroy the page replacer. This will reset the content to the original content if the replacer is currently open. */ export function SetupPageReplacer({ isPageToReplace, selectorToReplace, renderContent, renderMode, documentTitle }: PageReplacerConfig): () => void; interface SliderConfig extends RecommendationRenderingConfig {} /** * Renders a slider of the provided products * @param recommendations a promise resolving to an array of displays to render * @param productCard a function that renders a product card or a placeholder for one * @param columnsAtSize the number of columns to show at each media breakpoint * @param gridSpacing the spacing between the product cards * @param title Optional title to show when recommendations are being shown */ export function RecommendationSlider({ recommendations, productCard, columnsAtSize, gridSpacing, title }: SliderConfig): HTMLElement; interface RecommendationGridConfig extends RecommendationRenderingConfig { viewMoreButton?: { text: string; startRows?: number; rowsPerClick?: number; }; maxRows?: number; } /** * Renders a product grid of the provided products * @param recommendations a promise resolving to an array of displays to render * @param productCard a function that renders a product card or a placeholder for one * @param columnsAtSize the number of columns to show at each media breakpoint * @param gridSpacing the spacing between the product cards * @param maxRows the maximum number of rows to show. * @param viewMoreButton optional configuration for the view more button. If unset, all products will be shown by default. Otherwise, a view more button with the given text will be shown. With the properties startRows and rowsPerClick, you can configure how many rows should be shown initially and how many rows should be added on each click. * @param title Optional title to show when recommendations are being shown */ export function RecommendationGrid({ recommendations, productCard, columnsAtSize, gridSpacing, viewMoreButton, maxRows, title }: RecommendationGridConfig): HTMLElement; /** * Renders a grid or slider containing look cards for the looks available for a certain product (provided productId). */ export function LooksSliderOrGrid({ gridSpacing, gridOptions, market, merchant, priceFormatting, backendLocale, title, productId, columnsAtSize, imagePlaceholderAspectRatio, displayTransformers, class: classValue, imageResizer }: { gridSpacing?: SDKGridSpacing; columnsAtSize?: SDKColsAtSize; /** * The id of the product to show looks for */ productId: string; merchant: string; market: string; /** * The locale to use for the backend requests, a string containing the locale name (for example "en"). Check the dropdown on demo.depict.ai for the available locales. */ backendLocale: string; /** * Aspect ratio of the placeholder for the main (outfit) image. */ imagePlaceholderAspectRatio?: number | string; title?: JSX.Element; class?: string; /** * Display transformers to apply when fetching looks. */ displayTransformers?: DisplayTransformers>; /** * If provided, will render as grid instead of slider */ gridOptions?: { viewMoreButton?: { text: string; startRows?: number; rowsPerClick?: number; }; maxRows?: number; }; /** * Price formatting object for formatting the prices in the looks cards. */ priceFormatting: plp_shared_i18n["price_formatting_"]; imageResizer?: (url: string, width: number) => string; }): HTMLElement; /** * A Placeholder to use instead of some text, while it's loading. This is the inline version, meant to be embedded into sentences (or exist instead of them), etc. * If you want a block version, use `ImagePlaceholder` with `width`and `height` set instead. * @property height height of the placeholder. Set to `1em` by default. * @property width width of the placeholder. For specific number of characters use `ch`, ex: `width="7ch"` * @property class extra classes to add to the placeholder * @property style extra styles to add to the placeholder */ export function TextPlaceholder(options: Parameters[0]): HTMLElement; /** * A placeholder that can be used instead of an image or other block of content while it's loading. * The placeholder has `display:block`, meaning it will create a new "row" in the layout for itself. Can be used either for images with a defined aspect ratio (ContainedImage) or blocks. * @property aspectRatio if aspectRatio is defined the placeholder will be in "image mode" and fill out the available width and then adjust the height according to the aspectRatio * @property width If width and height is set, the defined width and height will be used. * @property height If width and height is set, the defined width and height will be used. * @property class extra classes to add to the placeholder * @property style extra styles to add to the placeholder */ export function ImagePlaceholder(options: Parameters[0]): HTMLElement; /** * Use this to be able to update content blocks. This will contain the blocks, you can pass getContentBlocksByRow to CategoryPage/SearchPage and then use setContentBlocksByRow to dynamically update the blocks. * @returns setContentBlocksByRow which takes a JSUIContentBlocksByRow and updates the blocks and getContentBlocksByRow which is the current blocks. */ export function contentBlockStore(initialValue?: JSUIContentBlocksByRow): { getContentBlocksByRow: import("solid-js").Accessor; setContentBlocksByRow: import("solid-js").Setter; }; type DisconnectFunction = () => void; interface OnExistsObserverReturn { /** * Disconnects the observer * * @returns void * * @example * ```typescript * const { disconnect } = onExistsObserver(".my-class", (element) => { * console.log("Element exists", element); * }); * ... * // Disconnect the observer when you're done with it * disconnect(); * ``` */ disconnect: DisconnectFunction; } /** * Observes an element and calls a callback when the element exists * @param selector - The selector to observe * @param callback - The callback to call when the element exists * @returns An object with a disconnect function * @example Simple usage * ```typescript * onExistsObserver(".my-class", (element) => { * console.log("Element exists", element); * } * ``` * @example Disconnect the observer from the callback itself * ```typescript * onExistsObserver(".my-class", (element, disconnect) => { * console.log("Element exists", element); * disconnect(); * } * ``` * @example Disconnect the observer from outside the callback * ```typescript * const { disconnect } = onExistsObserver(".my-class", (element) => { * console.log("Element exists", element); * }); * ... * // Disconnect the observer when you're done with it * disconnect(); * ``` */ export function onExistsObserver(selector: string, callback: (element: T, disconnect: DisconnectFunction) => void): OnExistsObserverReturn; export function BreadCrumbs({ categoryProvider }: { categoryProvider: DepictCategoryProvider; }): HTMLDivElement; export function QuickLinks({ categoryProvider }: { categoryProvider: DepictCategoryProvider; }): HTMLDivElement; export { fetchDepictRecommendations, ClassicSearchModal, SearchModalV2 } from "@depict-ai/ui"; export type { ProductCardTemplate as DepictProductCard } from "@depict-ai/ui"; export { embedded_num_products as EmbeddedNumProducts, CategoryTitle } from "@depict-ai/ui"; export type { DisplayTransformers } from "@depict-ai/ui"; export { DPC } from "@depict-ai/dpc";