Files
Michael Ramos 352f880ebc feat(ui): add Viewer-owned document header (#1450)
* feat(ui): add Viewer-owned document header

* chore(guides): refresh viewer integrity manifest

* fix(ui): harden Viewer document header transitions

* fix(ui): exclude document header from annotations
2026-09-01 17:25:15 -07:00

53 lines
1.9 KiB
TypeScript

/** Responsive presentation chosen for a measured compact document header. */
export type CompactHeaderLayout = 'wide' | 'tight' | 'narrow';
/** Measurements used to place a compact leading lane beside trailing actions. */
export interface CompactHeaderMeasurements {
/** Measured width of the full header container. */
readonly containerWidth: number;
/** Measured width occupied by the trailing action cluster. */
readonly trailingWidth: number;
/** Leading inset that is unavailable to the compact controls. */
readonly leadingInset: number;
}
/** Resolved responsive geometry for a compact document header. */
export interface CompactHeaderGeometry {
/** Pixels available to the leading controls after actions and spacing. */
readonly availableForLeading: number;
/** Whether controls keep labels, become icon-only, or stack. */
readonly layout: CompactHeaderLayout;
/** Whether both required measurements have arrived. */
readonly measured: boolean;
}
const GRID_SIZE = 16;
const CLUSTER_GAP = 16;
const WIDE_LEADING_WIDTH = 460;
const MIN_LEADING_WIDTH = 300;
/**
* Quantize a ResizeObserver width to avoid rendering for every dragged pixel.
* Floors toward the more conservative responsive layout.
*/
export function snapCompactHeaderWidth(width: number): number {
return Math.floor(width / GRID_SIZE) * GRID_SIZE;
}
/** Resolve the shared wide, tight, and narrow compact-header states. */
export function resolveCompactHeaderGeometry({
containerWidth,
trailingWidth,
leadingInset,
}: CompactHeaderMeasurements): CompactHeaderGeometry {
const measured = containerWidth > 0 && trailingWidth > 0;
const availableForLeading = containerWidth - leadingInset - trailingWidth - CLUSTER_GAP;
const layout = !measured || availableForLeading >= WIDE_LEADING_WIDTH
? 'wide'
: availableForLeading >= MIN_LEADING_WIDTH
? 'tight'
: 'narrow';
return { availableForLeading, layout, measured };
}