import { type Placement } from "@floating-ui/dom"; import { SwishApp } from "../swish"; import { CreateElementLocatorArgs } from "./dom-utils"; import { type SaveButtonStyle } from "./save-button-style"; /** The placement that wraps the theme's account link. Resolves to one of the * SDK's own custom elements rather than a `` component — see * `NATIVE_ELEMENT_TAGS` in ../swish-ui/swish-ui.ts. */ export declare const ACCOUNT_ICON = "account-icon"; /** A placement's element name, or undefined when it renders via a factory. */ export declare const elementNameOf: (spec: { element?: ElementSpec | RenderFn; }) => string | undefined; export declare function createPlacement(swish: SwishApp, rawSpec: PlacementSpec): { mount(): void; unmount(): void; }; /** -------------------------------------------- * Types * -------------------------------------------- */ export type BreakpointsSpec = { sm?: number; lg?: number; } | Record; export type ResponsiveValue = T | { base?: T; [breakpoint: string]: T | undefined; }; export type ElementName = "save-button" | "header-button" | "list-detail-page" | "account-icon" | "notify-button"; export type SaveButtonDesignSpec = { background?: ResponsiveValue; savedBackground?: ResponsiveValue; color?: ResponsiveValue; savedColor?: ResponsiveValue; width?: ResponsiveValue; height?: ResponsiveValue; /** Was `radius`, which emitted `--swish-placement-radius` — a variable no * stylesheet ever read, so corner radius never applied (SWI-2240). */ borderRadius?: ResponsiveValue; marginTop?: ResponsiveValue; marginBottom?: ResponsiveValue; /** Per-placement overrides of the global Save button icon design. */ iconColor?: ResponsiveValue; iconFill?: ResponsiveValue; /** The icon's fill once saved. Blank falls back to `iconFill`, then to the * look's saved fill (SWI-3358). */ savedIconFill?: ResponsiveValue; iconSize?: ResponsiveValue; iconStrokeWidth?: ResponsiveValue; /** An icon-only button's diameter. `width` / `height` outrank it. */ backgroundSize?: ResponsiveValue; }; export type HomeButtonDesignSpec = { width?: ResponsiveValue; height?: ResponsiveValue; /** Per-placement overrides of the global Save button icon design. */ iconColor?: ResponsiveValue; iconSize?: ResponsiveValue; iconStrokeWidth?: ResponsiveValue; iconMarginLeft?: ResponsiveValue; iconMarginRight?: ResponsiveValue; /** The saved-count badge. */ statusIndicatorBackground?: ResponsiveValue; statusIndicatorTextColor?: ResponsiveValue; statusIndicatorFontSize?: ResponsiveValue; statusIndicatorFontWeight?: ResponsiveValue; statusIndicatorSize?: ResponsiveValue; statusIndicatorPadding?: ResponsiveValue; statusIndicatorBorderRadius?: ResponsiveValue; statusIndicatorOutline?: ResponsiveValue; /** CSS `inset` shorthand picking the badge corner, e.g. "0 0 auto auto". */ statusIndicatorInset?: ResponsiveValue; statusIndicatorOffsetX?: ResponsiveValue; statusIndicatorOffsetY?: ResponsiveValue; }; export type NotifyButtonDesignSpec = { background?: ResponsiveValue; color?: ResponsiveValue; borderRadius?: ResponsiveValue; fontSize?: ResponsiveValue; fontWeight?: ResponsiveValue; width?: ResponsiveValue; height?: ResponsiveValue; marginTop?: ResponsiveValue; marginBottom?: ResponsiveValue; }; type DesignSpecMap = { "save-button": SaveButtonDesignSpec; "header-button": HomeButtonDesignSpec; "notify-button": NotifyButtonDesignSpec; }; export type DesignSpecForElementName = TName extends keyof DesignSpecMap ? DesignSpecMap[TName] : never; export type MountMode = "before" | "after" | "append" | "prepend" | "replace" | "wrap"; export type MountAt = "target" | { closest: string; } | { query: string; } | { nearest: string; } | { withinClosest: { root: string; selector: string; }; }; export type ContainerSpec = { tag?: keyof HTMLElementTagNameMap; classNames?: string[]; }; export type OverlayAnchor = "top-left" | "top-right" | "bottom-left" | "bottom-right"; export type ElementSpec = { name: TName; props?: Record; classNames?: string[]; }; export type OffsetSpec = { x?: number; y?: number; }; export type OverlayLayoutSpec = { type: "overlay"; anchor?: OverlayAnchor; zIndex?: number | string; offset?: OffsetSpec | ResponsiveValue; }; export type InlineLayoutSpec = { type: "inline"; rowSelector?: string; }; export type AnchoredLayoutSpec = { type: "anchored"; to?: MountAt; placement?: Placement; /** Position inside the anchor element's bounds rather than adjacent to it. */ inside?: boolean; offset?: number; zIndex?: number | string; }; export type PlacementLayoutSpec = OverlayLayoutSpec | InlineLayoutSpec | AnchoredLayoutSpec; export type PlacementSpec = { id: string; /** * When true the placement is configured but not rendered — the customiser's * eye control. It stays in the config so it can be un-hidden; nothing mounts * and no stylesheet is emitted until it's cleared. */ hidden?: boolean; target: Omit; mount: { at?: MountAt; mode: MountMode; }; layout?: PlacementLayoutSpec; breakpoints?: BreakpointsSpec; container?: ContainerSpec; element?: ElementSpec | RenderFn; /** * The look a placed save button renders (SWI-3202): "on-image" over product * media as an icon-only chip, or "on-page" in the page flow with a label. * Each look has its own `ui.design.saveButtonOnImage` / `saveButtonOnPage` * tokens and its own preset. Data on the placement, not derived from the * layout; resolved through `resolveSaveButtonStyle` (a product-card context * is always on-image, otherwise the default is on-page) and reflected on the * host as `swish-save-style`. Ignored for every other element. */ style?: SaveButtonStyle; /** Design tokens (typed when element name is known). */ design?: DesignSpecForElementName; /** Custom CSS appended after defaults (one stylesheet per placement). */ css?: string; onMount?: (ctx: MountContext) => void; onUnmount?: (ctx: UnmountContext) => void; }; export type MountContext = { id: string; targetEl: Element; renderTargetEl: Element; mountEl: T; containerEl?: HTMLElement; rowEl?: HTMLElement; cleanup: (fn: () => void) => void; }; export type UnmountContext = Omit, "cleanup">; export type MountedElement = { targetEl: HTMLElement; renderTargetEl: HTMLElement; mountEl: T; containerEl?: HTMLElement; rowEl?: HTMLElement; rowWasCreated?: boolean; rowInlineAttrPrevValue?: string | null; cleanupFns: Array<() => void>; ownsNode: boolean; }; export type RenderFn = (spec: PlacementSpec) => HTMLElement | Promise; export {};