Spaces:
Build error
Build error
import { AnimationFrames } from "runed"; | |
import type { Attachment } from "svelte/attachments"; | |
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; | |
useRaf?: boolean; | |
}; | |
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 function observe(args: ObserveArgs): Attachment<HTMLElement> { | |
return node => { | |
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 onWindowChange() { | |
setVars(args.name); | |
} | |
/** Initialize */ | |
const 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 | |
if (args.useRaf) { | |
new AnimationFrames(() => { | |
setVars(args.name); | |
}); | |
} | |
return function destroy() { | |
resizeObserver.disconnect(); | |
window.removeEventListener("scroll", onWindowChange, true); | |
window.removeEventListener("resize", onWindowChange, true); | |
}; | |
}; | |
} | |