inference-playground / src /lib /actions /observe.svelte.ts
Thomas G. Lopes
fix visual overflow errors & update workflow
09f13ea
raw
history blame
3.48 kB
import type { Action } from "svelte/action";
export enum ObservedElements {
BottomActions = "bottom-actions",
TokenCountEnd = "token-count-end",
TokenCountStart = "token-count-start",
// Add other elements here as needed
}
type ObservedData = {
rect: {
width: number;
height: number;
top: number;
left: number;
right: number;
bottom: number;
};
offset: {
width: number;
height: number;
top: number;
left: number;
right: number;
bottom: number;
};
};
export const observed: Record<ObservedElements, ObservedData> = $state(
Object.values(ObservedElements).reduce(
(acc, key) => {
acc[key] = {
rect: {
width: 0,
height: 0,
top: 0,
left: 0,
right: 0,
bottom: 0,
},
offset: {
width: 0,
height: 0,
top: 0,
left: 0,
right: 0,
bottom: 0,
},
};
return acc;
},
{} as Record<ObservedElements, ObservedData>
)
);
type ObserveArgs = {
name: ObservedElements;
};
function getOffsetPosition(el: HTMLElement) {
let top = 0;
let left = 0;
const width = el.offsetWidth;
const height = el.offsetHeight;
while (el) {
top += el.offsetTop;
left += el.offsetLeft;
el = el.offsetParent as HTMLElement;
}
return { top, left, width, height, right: left + width, bottom: top + height };
}
export const observe: Action<HTMLElement, ObserveArgs> = (node, args) => {
let resizeObserver: ResizeObserver;
function setVars(name: ObservedElements) {
// 1. Standard rect (includes transforms)
const rect = node.getBoundingClientRect();
document.documentElement.style.setProperty(`--${name}-width`, `${rect.width}px`);
document.documentElement.style.setProperty(`--${name}-height`, `${rect.height}px`);
document.documentElement.style.setProperty(`--${name}-top`, `${rect.top}px`);
document.documentElement.style.setProperty(`--${name}-left`, `${rect.left}px`);
document.documentElement.style.setProperty(`--${name}-right`, `${rect.right}px`);
document.documentElement.style.setProperty(`--${name}-bottom`, `${rect.bottom}px`);
// 2. Offset position (ignores transforms)
const offset = getOffsetPosition(node);
document.documentElement.style.setProperty(`--${name}-width-offset`, `${offset.width}px`);
document.documentElement.style.setProperty(`--${name}-height-offset`, `${offset.height}px`);
document.documentElement.style.setProperty(`--${name}-top-offset`, `${offset.top}px`);
document.documentElement.style.setProperty(`--${name}-left-offset`, `${offset.left}px`);
document.documentElement.style.setProperty(`--${name}-right-offset`, `${offset.right}px`);
document.documentElement.style.setProperty(`--${name}-bottom-offset`, `${offset.bottom}px`);
observed[name] = {
rect,
offset,
};
}
function update(args: ObserveArgs) {
if (resizeObserver) {
resizeObserver.disconnect();
}
resizeObserver = new ResizeObserver(() => {
setVars(args.name);
});
resizeObserver.observe(node);
// Listen for scroll and resize events
window.addEventListener("scroll", onWindowChange, true);
window.addEventListener("resize", onWindowChange, true);
setVars(args.name); // Initial set after observing
}
function onWindowChange() {
setVars(args.name);
}
update(args); // Initial setup
function destroy() {
resizeObserver.disconnect();
window.removeEventListener("scroll", onWindowChange, true);
window.removeEventListener("resize", onWindowChange, true);
}
return {
update,
destroy,
};
};