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 = $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 ) ); 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 = (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, }; };