svelte
Version:
Cybernetically enhanced web apps
109 lines (91 loc) • 2.89 kB
JavaScript
import { effect, teardown } from '../../../reactivity/effects.js';
import { untrack } from '../../../runtime.js';
/**
* Resize observer singleton.
* One listener per element only!
* https://groups.google.com/a/chromium.org/g/blink-dev/c/z6ienONUb5A/m/F5-VcUZtBAAJ
*/
class ResizeObserverSingleton {
/** */
#listeners = new WeakMap();
/** @type {ResizeObserver | undefined} */
#observer;
/** @type {ResizeObserverOptions} */
#options;
/** @static */
static entries = new WeakMap();
/** @param {ResizeObserverOptions} options */
constructor(options) {
this.#options = options;
}
/**
* @param {Element} element
* @param {(entry: ResizeObserverEntry) => any} listener
*/
observe(element, listener) {
var listeners = this.#listeners.get(element) || new Set();
listeners.add(listener);
this.#listeners.set(element, listeners);
this.#getObserver().observe(element, this.#options);
return () => {
var listeners = this.#listeners.get(element);
listeners.delete(listener);
if (listeners.size === 0) {
this.#listeners.delete(element);
/** @type {ResizeObserver} */ (this.#observer).unobserve(element);
}
};
}
#getObserver() {
return (
this.#observer ??
(this.#observer = new ResizeObserver(
/** @param {any} entries */ (entries) => {
for (var entry of entries) {
ResizeObserverSingleton.entries.set(entry.target, entry);
for (var listener of this.#listeners.get(entry.target) || []) {
listener(entry);
}
}
}
))
);
}
}
var resize_observer_content_box = /* @__PURE__ */ new ResizeObserverSingleton({
box: 'content-box'
});
var resize_observer_border_box = /* @__PURE__ */ new ResizeObserverSingleton({
box: 'border-box'
});
var resize_observer_device_pixel_content_box = /* @__PURE__ */ new ResizeObserverSingleton({
box: 'device-pixel-content-box'
});
/**
* @param {Element} element
* @param {'contentRect' | 'contentBoxSize' | 'borderBoxSize' | 'devicePixelContentBoxSize'} type
* @param {(entry: keyof ResizeObserverEntry) => void} set
*/
export function bind_resize_observer(element, type, set) {
var observer =
type === 'contentRect' || type === 'contentBoxSize'
? resize_observer_content_box
: type === 'borderBoxSize'
? resize_observer_border_box
: resize_observer_device_pixel_content_box;
var unsub = observer.observe(element, /** @param {any} entry */ (entry) => set(entry[type]));
teardown(unsub);
}
/**
* @param {HTMLElement} element
* @param {'clientWidth' | 'clientHeight' | 'offsetWidth' | 'offsetHeight'} type
* @param {(size: number) => void} set
*/
export function bind_element_size(element, type, set) {
var unsub = resize_observer_border_box.observe(element, () => set(element[type]));
effect(() => {
// The update could contain reads which should be ignored
untrack(() => set(element[type]));
return unsub;
});
}