@assistant-ui/react
Version:
Open-source TypeScript/React library for building production-grade AI chat experiences
59 lines (49 loc) • 1.9 kB
text/typescript
"use client";
/**
* Convert a supported CSS length string (`px`, `em`, `rem`) into pixels,
* resolving font-relative units against the supplied element's computed style.
* Unsupported or malformed values disable the tall-message clamp.
*
* Part of the top-anchor package's public input contract: consumers may pass
* clamp configuration as supported CSS-length strings, and this function is the
* single place that converts them into the pixel values the package operates on.
*/
export const parseCssLength = (value: string, element: HTMLElement): number => {
const match = value.trim().match(/^(\d+(?:\.\d+)?|\.\d+)(em|px|rem)$/);
if (!match) return Number.POSITIVE_INFINITY;
const num = Number(match[1]);
const unit = match[2];
if (unit === "px") return num;
if (unit === "em") {
const fontSize = parseFloat(getComputedStyle(element).fontSize) || 16;
return num * fontSize;
}
if (unit === "rem") {
const rootFontSize =
parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;
return num * rootFontSize;
}
return Number.POSITIVE_INFINITY;
};
export const getAnchorId = (anchor: HTMLElement) => anchor.dataset.messageId;
export const createReserveElement = () => {
const reserve = document.createElement("div");
reserve.dataset.auiTopAnchorReserve = "";
reserve.style.height = "0px";
reserve.style.flexShrink = "0";
reserve.style.pointerEvents = "none";
reserve.setAttribute("aria-hidden", "true");
return reserve;
};
export const setReserveHeight = (reserve: HTMLElement, height: number) => {
const nextHeight = `${height}px`;
if (reserve.style.height !== nextHeight) {
reserve.style.height = nextHeight;
return true;
}
return false;
};
export const snapScrollTop = (top: number) => {
const pixelRatio = window.devicePixelRatio || 1;
return Math.round(top * pixelRatio) / pixelRatio;
};