import type { ListDetail, Subscription } from "@swishapp/api-client/2026-07"; import type { UnsaveItemSuccessResponse, EditItemListsSuccessResponse, EditItemVariantSuccessResponse, EditListSuccessResponse } from "../intents/types"; import { Ref, SwishUiElement } from "../swish"; type ExtractSuccessData = T extends { code: "ok"; data: infer D; } ? D : never; export interface UiResponseBase { code: "ok" | "closed"; } export interface ClosedUiResponse extends UiResponseBase { code: "closed"; } export interface SuccessUiResponse extends UiResponseBase { code: "ok"; data: T; } export type UiResponse = T extends void ? ClosedUiResponse | SuccessUiResponse : ClosedUiResponse | SuccessUiResponse; export interface ToastManager { show(toast: Toast, id?: number): void; hide(id: number): void; clear(): void; } export interface ShowToastOptions { signal?: AbortSignal; } export interface Toast { title?: string; text: string; image?: string; action?: { label: string; }; variant?: "compact" | "full"; icon?: string; } export interface SignInOptions { returnTo?: string; } export interface UnsaveAlertOptions { itemId: string; } export type UnsaveAlertSubmitData = ExtractSuccessData; export interface DeleteListAlertOptions { listId: string; } export interface ConfirmDialogOptions { titleKey?: string; descriptionKey?: string; confirmLabelKey?: string; cancelLabelKey?: string; danger?: boolean; } export interface DrawerOptions { view?: "home" | "list" | "lists" | "saves" | "order" | "orders" | "notifications" | "profile" | "product"; listId?: string; listType?: ListDetail["type"]; productId?: string; variantId?: string; orderId?: string; /** Replay the options of the last non-restore `showDrawer` instead of * navigating (they are already resolved, so no async lookups re-run). * Opens the default (home) view when nothing has been shown yet. Mutually * exclusive with the navigation fields above (they are ignored when * restoring). Whether a restore should happen at all is the caller's * decision — the drawer itself always shows when asked. */ restore?: boolean; } export interface ListMenuOptions { listId: string; } export interface OrderMenuOptions { orderId: string; } export type ListEditorSubmitData = ExtractSuccessData; export interface ListMenuEditAccessData { currentListAccess: "public" | "private"; } export type ListMenuResponse = UiResponse<{ action: "edit"; data: ListEditorSubmitData; } | { action: "delete"; } | { action: "edit-access"; data?: ListMenuEditAccessData; } | { action: "add-items"; } | { action: "share"; }>; export type OrderMenuResponse = UiResponse; export interface ListDetailPageMenuOptions { listId: string; } export interface ListSelectOptions { itemId: string; } export type ListSelectSubmitData = ExtractSuccessData; export type ListSelectResponse = UiResponse<{ action: "submit"; data: ListSelectSubmitData; } | { action: "unsave"; data: UnsaveAlertSubmitData; }>; export interface VariantSelectOptions { itemId?: string; productId?: number; productHandle?: string; variantId?: number; /** Quantity for the item the picker creates. An existing `itemId` keeps its own. */ quantity?: number; /** Tags for the item the picker creates. An existing `itemId` keeps its own. */ tags?: string[]; } export type VariantSelectSubmitData = ExtractSuccessData; export interface QuickBuyOptions { productId?: number; productHandle?: string; variantId?: number; /** The quantity the dialog opens on; 1 when omitted. */ quantity?: number; } export interface QuickBuySubmitData { product: VariantSelectSubmitData["product"]; variant: VariantSelectSubmitData["variant"]; } export interface NotifyMeOptions { productId: number; variantId?: number; } /** The subscription the modal created, as the API returned it. */ export interface NotifyMeSubmitData { subscription: Subscription; } export interface ListEditorOptions { listId?: string; } export interface RequireUiComponentOptions { singleInstance?: boolean; onHydrated?: (ref: Ref) => void; refElement?: HTMLElement; /** Extra CSS adopted into this element's shadow root, after the bundle so it * wins. Used by placements to inject their per-placement "Custom CSS" so it * can style the component itself (`:host { … }` and internal selectors) — * page-level CSS can't reach inside the shadow root. */ shadowCss?: string; } export {};