UNPKG

@indielayer/ui

Version:

Indielayer UI Components with Tailwind CSS build for Vue 3

163 lines (125 loc) 3.49 kB
import EventEmitter from 'node:events' type GetDOMRect = (element: HTMLElement) => DOMRectReadOnly | undefined | void; const emitter = new EventEmitter() emitter.setMaxListeners(100) const elementToDOMRect = new Map<HTMLElement, DOMRect>() let defaultDomRect: DOMRectReadOnly = new DOMRect(0, 0, 0, 0) let disabled: boolean = false let getDOMRect: GetDOMRect | undefined = undefined export function disableResizeObserverForCurrentTest() { disabled = true } export function setDefaultElementSize({ height, width, }: { height: number; width: number; }) { defaultDomRect = new DOMRect(0, 0, width, height) emitter.emit('change') } export function setElementSizeFunction(value: GetDOMRect) { getDOMRect = value emitter.emit('change') } export function setElementSize({ element, height, width, }: { element: HTMLElement; height: number; width: number; }) { elementToDOMRect.set(element, new DOMRect(0, 0, width, height)) emitter.emit('change', element) } export function simulateUnsupportedEnvironmentForTest() { // @ts-expect-error Simulate API being unsupported window.ResizeObserver = null } export function mockResizeObserver() { disabled = false const originalResizeObserver = window.ResizeObserver window.ResizeObserver = MockResizeObserver return function unmockResizeObserver() { window.ResizeObserver = originalResizeObserver defaultDomRect = new DOMRect(0, 0, 0, 0) disabled = false getDOMRect = undefined elementToDOMRect.clear() } } class MockResizeObserver implements ResizeObserver { readonly #callback: ResizeObserverCallback #disconnected: boolean = false #elements: Set<HTMLElement> = new Set() constructor(callback: ResizeObserverCallback) { this.#callback = callback emitter.addListener('change', this.#onChange) } observe(element: HTMLElement) { if (this.#disconnected) { return } this.#elements.add(element) this.#notify([element]) } unobserve(element: HTMLElement) { this.#elements.delete(element) } disconnect() { this.#disconnected = true this.#elements.clear() emitter.removeListener('change', this.#onChange) } #notify(elements: HTMLElement[]) { if (disabled) { return } const entries = elements.map((element) => { const computedStyle = window.getComputedStyle(element) const writingMode = computedStyle.writingMode let contentRect: DOMRectReadOnly = elementToDOMRect.get(element) ?? defaultDomRect if (getDOMRect) { const contentRectOverride = getDOMRect(element) if (contentRectOverride) { contentRect = contentRectOverride } } let blockSize = 0 let inlineSize = 0 if (writingMode.includes('vertical')) { blockSize = contentRect.width inlineSize = contentRect.height } else { blockSize = contentRect.height inlineSize = contentRect.width } return { borderBoxSize: [ { blockSize, inlineSize, }, ], contentBoxSize: [], contentRect, devicePixelContentBoxSize: [], target: element, } }) this.#callback(entries, this) } #onChange = (target?: HTMLElement) => { if (target) { if (this.#elements.has(target)) { this.#notify([target]) } } else { this.#notify(Array.from(this.#elements)) } } }