// Pure fit decision for a single-line chip lane that must share its width with fixed trailing // controls (the feed's applied-filter row + Sort/View). Lifted out of ActiveFilterChips so the // all/some/count math is unit-testable without a layout engine (jsdom reports 0-width boxes), the // same split as lib/dateFilter and lib/columnSort. The caller measures real widths off a hidden // mirror (including the live rem gap, so nothing is frozen in px) and hands them here. // // A sibling one-line-fit measurer lives in ChannelTags (ChannelTagsControl); if a third appears, // promote the DOM-measurement half to a shared hook and keep this as its policy core. export interface ChipFitInput { /** Number of chips. */ n: number; /** Right edge (offsetLeft + offsetWidth) of the leading label, in the measurer. */ labelRight: number; /** Right edge of each chip, in the measurer (index-aligned to the chips). */ chipRights: number[]; /** Width of the "+N" overflow pill. */ plusW: number; /** Width the trailing "Clear all" button needs INCLUDING its leading gap (0 when n <= 1, since it * only renders with more than one chip). Reserved only in the "all" branch, which renders it. */ clearW: number; /** Available lane width. */ avail: number; /** The real (rem-scaled) inter-item gap. */ gap: number; /** At or below this lane width an overflow collapses to a single count pill instead of "+N". */ narrowPx: number; } export type ChipFit = { mode: "all" | "some" | "count"; visible: number }; export function decideChipLayout(p: ChipFitInput): ChipFit { const { n, labelRight, chipRights, plusW, clearW, avail, gap, narrowPx } = p; if (n <= 0) return { mode: "all", visible: 0 }; // Do all chips (plus the Clear all button it renders) fit? Use the last chip's right edge. const allRight = chipRights[n - 1] ?? labelRight; if (allRight + clearW <= avail) return { mode: "all", visible: n }; // Overflow. On a narrow lane, collapse everything into one count pill. if (avail < narrowPx) return { mode: "count", visible: 0 }; // Otherwise fit as many chips as leave room for the "+N" pill after them. let k = 0; for (let i = 0; i < n; i++) { const right = chipRights[i] ?? 0; if (right + gap + plusW <= avail) k = i + 1; else break; } // If not even one chip fits beside the pill, fall back to the count pill. if (k === 0 && labelRight + gap + plusW > avail) return { mode: "count", visible: 0 }; return { mode: "some", visible: k }; }