UNPKG

element-vir

Version:

Heroic. Reactive. Declarative. Type safe. Web components without compromise.

115 lines (114 loc) 3.4 kB
import { AsyncDirective, directive } from '../../lit-exports/all-lit-exports.js'; import { assertIsElementPartInfo } from './directive-helpers.js'; const directiveName = 'onResize'; /** * A directive that fires its listener any time the element that it's attached to is resized. This * uses the [built-in `ResizeObserver` * API](https://developer.mozilla.org/docs/Web/API/ResizeObserver), so it is very efficient. * * @category Directives * @example * * ```ts * import {html, defineElement, onResize} from 'element-vir'; * * const MyElement = defineElement()({ * tagName: 'my-element', * render() { * return html` * <div * ${onResize((size, element) => { * console.log('resized!', element, size); * })} * > * Some div * </div> * `; * }, * }); * ``` */ export const onResize = directive(class extends AsyncDirective { element; resizeObserver = new ResizeObserver((entries) => { if (this.element && this.callback) { handleOnResizeCallback(this.element, this.callback, entries); } }); callback; constructor(partInfo) { super(partInfo); assertIsElementPartInfo(partInfo, directiveName); } update(partInfo, [callback]) { assertIsElementPartInfo(partInfo, directiveName); this.callback = callback; const newElement = partInfo.element; const oldElement = this.element; // if the element changes we need to observe the new one if (newElement !== oldElement) { this.element = newElement; if (oldElement) { this.resizeObserver.unobserve(oldElement); } this.resizeObserver.observe(newElement); } return this.render(callback); } // eslint-disable-next-line @typescript-eslint/no-unused-vars render(callback) { return undefined; } disconnected() { this.resizeObserver.disconnect(); } reconnected() { if (this.element) { this.resizeObserver.observe(this.element); } } }); function handleOnResizeCallback(element, callback, entries) { const resizeEntry = entries[0]; if (!resizeEntry) { console.error(entries); throw new Error('Resize observation triggered but the first entry was empty.'); } void callback({ target: resizeEntry.target, contentRect: resizeEntry.contentRect, }, element); } /** * A function that attaches a * [`ResizeObserver`](https://developer.mozilla.org/docs/Web/API/ResizeObserver) to any given * element, so it is very efficient. * * @category Directives * @example * * ```ts * import {html, defineElement, attachOnResize} from 'element-vir'; * * const MyElement = defineElement()({ * tagName: 'my-element', * render({host}) { * attachOnResize(host, (size, element) => { * console.log('resized!', element, size); * }); * * return ''; * }, * }); * ``` */ export function attachOnResize(element, callback) { const resizeObserver = new ResizeObserver((entries) => { handleOnResizeCallback(element, callback, entries); }); resizeObserver.observe(element); return { resizeObserver, element, }; }