Files
rio/frontend/code/highlighter.ts
2024-06-22 21:58:55 +02:00

68 lines
2.2 KiB
TypeScript

/// Helper class for highlighting components.
export class Highlighter {
private target: Element | null = null;
private intervalHandlerId: number | undefined = undefined;
private highlighter: HTMLElement;
constructor() {
// Create the highlighter and hide it
this.highlighter = document.createElement('div');
this.highlighter.classList.add('rio-dev-tools-component-highlighter');
document.body.appendChild(this.highlighter);
this.moveTo(null);
}
destroy(): void {
this.highlighter.remove();
clearInterval(this.intervalHandlerId);
}
/// Transition the highlighter to the given component. If the component is
/// `null`, transition it out.
public moveTo(target: HTMLElement | null): void {
this.target = target;
this.updatePosition();
// If the element is moved or resized or if the user scrolls, the
// position of the highlighter becomes wrong. So we'll register a
// handler that periodically updates it.
clearInterval(this.intervalHandlerId);
if (target !== null) {
this.intervalHandlerId = setInterval(
() => this.updatePosition(),
100
);
}
}
private updatePosition(): void {
// If no component is to be highlighted, make the highlighter the size
// of the window, effectively hiding it. Overshoot by a bit to make sure
// the highlighter's pulse animation doesn't make it visible by
// accident.
let left, top, width, height;
if (this.target === null) {
left = -10;
top = -10;
width = window.innerWidth + 20;
height = window.innerHeight + 20;
} else {
let rect = this.target.getBoundingClientRect();
left = rect.left;
top = rect.top;
width = rect.width;
height = rect.height;
}
// Move the highlighter
this.highlighter.style.top = `${top}px`;
this.highlighter.style.left = `${left}px`;
this.highlighter.style.width = `${width}px`;
this.highlighter.style.height = `${height}px`;
}
}