/**
* Responsive-media intent — Save-Data / DPR / Client Hints projection (#125).
*
* Pure resolution and srcset/image-set builders. Hosts inject capabilities from
* `@czap/edge` `ClientHints` or `@czap/detect`; core stays dependency-free.
*
* @module
*/
/** Capability slice required to resolve a responsive media intent. */
export interface ResponsiveMediaCapabilities {
readonly devicePixelRatio: number;
readonly saveData: boolean;
}
/** One candidate source in a responsive set. */
export interface ResponsiveMediaVariant {
readonly src: string;
/** Intrinsic width in CSS pixels — used for `Nw` descriptors. */
readonly width?: number;
/** Explicit density descriptor (e.g. `2x`); overrides width-based DPR inference. */
readonly descriptor?: string;
}
/** Authoring input to {@link ResponsiveMedia.intent}. */
export interface ResponsiveMediaIntentInput {
readonly id: string;
readonly alt: string;
readonly variants: readonly ResponsiveMediaVariant[];
/** Lighter asset used when Save-Data is on. */
readonly saveDataVariant?: ResponsiveMediaVariant;
readonly sizes?: string;
}
/** Sealed responsive-media intent — data over graph, no behavior authority. */
export interface ResponsiveMediaIntent extends ResponsiveMediaIntentInput {
readonly _tag: 'ResponsiveMediaIntent';
}
/** Why a particular variant was chosen. */
export type ResponsiveMediaResolutionReason = 'save-data' | 'save-data-floor' | 'dpr-match' | 'dpr-floor' | 'fallback';
/** Resolved single source for SSR or runtime ``. */
export interface ResolvedResponsiveMedia {
readonly src: string;
readonly reason: ResponsiveMediaResolutionReason;
}
/**
* The EFFECTIVE candidate set — the single law every responsive-media output derives
* from ({@link selectCandidates}). Under `caps.saveData` the set is capped to the ONE
* light/floor variant, so no artifact (`srcset`, ``, the preload `imagesrcset`,
* CSS `image-set()`, the cache-key digest) can ever advertise a heavier candidate — the
* browser cannot re-fetch what no output lists (F-RM-1a..e).
*/
export interface ResponsiveMediaCandidateSet {
/**
* The candidates safe to advertise under `caps`. Save-Data caps this to a single
* light/floor variant; otherwise it is the full authored set. `srcset`, the general
* ``, the preload `imagesrcset`, and CSS `image-set()` all enumerate THIS.
*/
readonly candidates: readonly ResponsiveMediaVariant[];
/** The single best variant for `` — the DPR pick WITHIN `candidates`. */
readonly resolved: ResponsiveMediaVariant;
/** Why `resolved` was chosen and how `candidates` was capped. */
readonly reason: ResponsiveMediaResolutionReason;
}
/** Structured `` projection. */
export interface ResponsiveMediaPictureProjection {
readonly picture: string;
readonly img: string;
readonly srcset: string;
readonly sizes: string;
readonly resolved: ResolvedResponsiveMedia;
/**
* Optional `` for the resolved (or full srcset)
* asset — hosts put this in `` for LCP (#125).
*/
readonly preload: string;
}
/**
* Build a `srcset` string from variants with `w` or `x` descriptors.
*
* Variants without enough metadata are skipped; result is empty when none qualify.
*/
export declare function buildResponsiveSrcset(variants: readonly ResponsiveMediaVariant[], baseWidth?: number): string;
/**
* Build a CSS `image-set()` value from variants (native CSS first).
*
* Uses `type()` only when variants carry standard image extensions; unknown
* types are omitted rather than guessed.
*/
export declare function buildResponsiveImageSet(variants: readonly ResponsiveMediaVariant[], baseWidth?: number): string;
/**
* THE one effective-candidate law — the single function every responsive-media
* output consumes (#140). Returns the {@link ResponsiveMediaCandidateSet}: the
* candidates safe to advertise under `caps`, the single best `src`, and the reason.
*
* Save-Data wins over DPR and caps ALL candidates to the floor: the authored
* `saveDataVariant` when present (`save-data`), else the LIGHTEST available variant
* (`save-data-floor`) — a Save-Data client must never be advertised a heavier
* candidate through ANY artifact, even when the author skipped the explicit light
* variant. Otherwise the full authored set is advertised and `resolved` is the DPR
* pick: the variant whose DPR is closest without going under the device ratio
* (`dpr-match`), else the largest available (`dpr-floor`), else the first (`fallback`).
*/
export declare function selectCandidates(intent: ResponsiveMediaIntent, caps: ResponsiveMediaCapabilities): ResponsiveMediaCandidateSet;
/**
* Resolve the single best `src` for SSR / fallback `` given capabilities.
*
* A thin projection of {@link selectCandidates}: takes its `resolved` variant and
* `reason`. Kept as its own export for hosts that only need the one `src` — but it
* derives from the SAME law as `srcset` / `` / preload / image-set, so a
* Save-Data client is never SILENTLY served a light `src` while a heavy candidate
* leaks through another artifact.
*/
export declare function resolveResponsiveMedia(intent: ResponsiveMediaIntent, caps: ResponsiveMediaCapabilities): ResolvedResponsiveMedia;
/**
* Project a responsive-media intent to a `` + fallback ``.
*
* Native markup first: `` per density band; runtime/SSR picks
* `resolved.src` on the inner `` for hosts without picture support.
*/
export declare function projectResponsiveMediaPicture(intent: ResponsiveMediaIntent, caps: ResponsiveMediaCapabilities): ResponsiveMediaPictureProjection;
/** Authoring sugar namespace — data over intent, no behavior authority. */
export declare const ResponsiveMedia: {
/** Seal a responsive-media intent from authoring input. */
readonly intent: (input: ResponsiveMediaIntentInput) => ResponsiveMediaIntent;
};
//# sourceMappingURL=responsive-media.d.ts.map