import { type HTMLAttributes, type ReactNode } from 'react';
import { type VariantProps } from 'class-variance-authority';
/**
* One product-hub release entry. The kit is purely presentational —
* the consumer fetches releases (Supabase, REST, …) and maps them into
* this shape.
*/
export interface ProductHubItem {
/** Unique identifier for the release. */
id: string;
/** Release title — rendered bold on the first line. */
title: string;
/** Short release summary — rendered as plain text, clamped to 2 lines. */
summary?: string;
/** ISO-8601 publish date — rendered as a localised, italic absolute date. */
dateIso?: string;
/**
* Thumbnail URL. Guarded through the shared `safeImageSrc` allow-list
* and rendered with `referrerPolicy="no-referrer"`. Unsafe or missing
* sources fall back to a Gift glyph tile.
*/
imageUrl?: string;
/**
* Release deep link. Guarded through `isSafeEntityUrl`; safe URLs make
* the row title an anchor that opens in a new tab. Unsafe URLs render
* the title as plain text.
*/
url?: string;
/** Marks the release as not yet seen — highlights the row and counts toward the trigger badge. */
unseen?: boolean;
}
/**
* Curated imperative handle for ProductHubTray. Exposed to the agent
* registry so a future MCP UI bridge can drive the tray without touching
* the DOM. See `product-hub-tray.agent.ts`.
*/
export interface ProductHubTrayHandle {
open: () => void;
close: () => void;
getUnseenCount: () => number;
}
export interface ProductHubTrayProps extends Omit, 'onClick' | 'children' | 'role' | 'id'>, VariantProps {
/**
* Stable instance id. Surfaced on the root as `data-component-id` so
* an agent / MCP UI bridge can address this specific tray.
*/
id?: string;
/** Releases rendered in the dropdown panel, newest first. */
items: ProductHubItem[];
/**
* Product-hub landing URL. When set (and safe) the panel renders a
* pinned "Open in Product Hub" footer link that opens in a new tab.
*/
hubUrl?: string;
/** When true the panel shows skeleton placeholders. */
loading?: boolean;
/** Error-state slot — rendered inside the panel instead of the list. */
error?: ReactNode;
/**
* Unseen-release count override. Defaults to the number of `items`
* with `unseen: true`. Drives the trigger badge.
*/
unseenCount?: number;
/** Fires when the open state changes. */
onOpenChange?: (open: boolean) => void;
/**
* Analytics hook — fires when a row is activated. Navigation itself is
* owned by the row anchor (new tab); this callback must not be relied
* on for routing.
*/
onItemActivate?: (item: ProductHubItem) => void;
/** Override for the trigger's accessible label. */
triggerLabel?: string;
/** Number of releases rendered before the rest are cut off. Default 10. */
maxVisible?: number;
/** Empty-state slot — replaces the built-in "No product updates yet" panel. */
emptyState?: ReactNode;
/** Open the panel on first mount (uncontrolled). */
defaultOpen?: boolean;
/** BCP-47 locale override for the per-row dates. Falls back to `i18n.language`. */
locale?: string;
/** Panel alignment relative to the trigger. Default `'end'`. */
align?: 'start' | 'center' | 'end';
/** Side of the trigger to open on. Default `'bottom'`. */
side?: 'top' | 'bottom';
}
declare const productHubTrayVariants: (props?: ({
size?: "sm" | "md" | null | undefined;
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
export interface ProductHubUpdateRowProps extends Omit, 'onClick' | 'role' | 'title'> {
/** The release to render. */
item: ProductHubItem;
/** `tray` — compact dropdown row. `panel` — roomier dashboard row. */
density?: 'tray' | 'panel';
/**
* Row chrome. `'flat'` (default) — chrome-less row inside a bordered
* tray/panel. `'elevated'` — own card chrome (border + `--shadow-sm`) for
* rail feeds (e.g. the Inbox), matching the sibling notification/message
* cards.
*/
surface?: 'flat' | 'elevated';
/** BCP-47 locale override for the date. */
locale?: string;
/** Analytics hook — navigation is owned by the row anchor. */
onActivate?: (item: ProductHubItem) => void;
/**
* When supplied, renders a close affordance (revealed on row hover / focus)
* that fires with this item — e.g. dismissing the update from an Inbox feed.
*/
onDismiss?: (item: ProductHubItem) => void;
}
/**
* @internal Shared row between ProductHubTray and ProductHubPanel.
* Exported for the sibling panel only — import the trays, not this.
*/
export declare function ProductHubUpdateRow({ item, density, surface, locale, onActivate, onDismiss, className, ...rest }: ProductHubUpdateRowProps): import("react/jsx-runtime").JSX.Element;
/** @internal Skeleton placeholder mirroring the row layout. */
export declare function UpdateSkeletonRow({ density, }: {
density?: 'tray' | 'panel';
}): import("react/jsx-runtime").JSX.Element;
/** @internal Centered status container for error / consumer-slot states. */
export declare function UpdateStatusPanel({ children }: {
children: ReactNode;
}): import("react/jsx-runtime").JSX.Element;
export declare const ProductHubTray: import("react").ForwardRefExoticComponent>;
export {};
//# sourceMappingURL=product-hub-tray.d.ts.map