All files / composables useResizeObserver.ts

20% Statements 5/25
37.5% Branches 3/8
20% Functions 1/5
20% Lines 5/25

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 871x                     1x       21x           21x         21x                                                                                                                        
import { ref, Ref, onMounted, onUnmounted, watch } from 'vue';
import { BoxDimensions } from '../types';
 
/**
 * Sets up a basic ResizeObserver which attaches to the provided template ref
 * when the component is mounted. Returns a ref whose value is an object
 * containing current "width" and "height" properties.
 *
 * @param templateRef
 * @return ref with "width" and "height" properties
 */
export default function useResizeObserver(
	templateRef: Ref<Element|undefined>
) : Ref<BoxDimensions> {
	// Set up the empty dimensions ref
	const currentDimensions = ref<BoxDimensions>(
		{ width: undefined, height: undefined }
	);
 
	// Exit early if we are not running in a browser,
	// or if ResizeObserver is not supported
	if (
		typeof window !== 'object' ||
		!( 'ResizeObserver' in window ) ||
		!( 'ResizeObserverEntry' in window )
	) {
		return currentDimensions;
	}
 
	// Set up the ResizeObserver
	const observer = new window.ResizeObserver(
		( entries: ResizeObserverEntry[] ) => {
			const entry = entries[ 0 ];
 
			/**
			 * When writing direction is horizontal, inlineSize corresponds to
			 * width and blockSize corresponds to height. In vertical-direction
			 * layouts, these are reversed. For now this composable only
			 * supports horizontal directionality.
			 */
			Iif ( entry ) {
				currentDimensions.value = {
					width: entry.borderBoxSize[ 0 ].inlineSize,
					height: entry.borderBoxSize[ 0 ].blockSize
				};
			}
		}
	);
 
	let mounted = false;
 
	onMounted( () => {
		mounted = true;
		Iif ( templateRef.value ) {
			observer.observe( templateRef.value );
		}
	} );
 
	onUnmounted( () => {
		mounted = false;
		observer.disconnect();
	} );
 
	// If the templateRef changes to point to a different element, disconnect the observer from the
	// old element and observe the new one instead
	watch( templateRef, ( newElement ) => {
		// Don't try to observe the element before the component has been mounted; doing that leads
		// to strange bugs.
		Iif ( !mounted ) {
			return;
		}
		observer.disconnect();
 
		// Reset the current width and height value and observe the new element
		currentDimensions.value = {
			width: undefined,
			height: undefined
		};
 
		Iif ( newElement ) {
			observer.observe( newElement );
		}
	} );
 
	return currentDimensions;
}