@juggle/resize-observer
Advanced tools
| declare const isSVG: (target: Element) => boolean; | ||
| declare const isHidden: (target: Element) => boolean; | ||
| export { isSVG, isHidden }; |
| const isSVG = (target) => target instanceof SVGElement && 'getBBox' in target; | ||
| const isHidden = (target) => { | ||
| if (isSVG(target)) { | ||
| const { width, height } = target.getBBox(); | ||
| return !width && !height; | ||
| } | ||
| const { offsetWidth, offsetHeight } = target; | ||
| return !(offsetWidth || offsetHeight || target.getClientRects().length); | ||
| }; | ||
| export { isSVG, isHidden }; |
@@ -8,3 +8,3 @@ import { resizeObservers } from '../ResizeObserverController'; | ||
| const callbacks = []; | ||
| resizeObservers.forEach((ro) => { | ||
| resizeObservers.forEach(function processObserver(ro) { | ||
| if (ro.activeTargets.length === 0) { | ||
@@ -14,3 +14,3 @@ return; | ||
| const entries = []; | ||
| ro.activeTargets.forEach((ot) => { | ||
| ro.activeTargets.forEach(function processTarget(ot) { | ||
| const entry = new ResizeObserverEntry(ot.target); | ||
@@ -24,8 +24,8 @@ const targetDepth = calculateDepthForNode(ot.target); | ||
| }); | ||
| callbacks.push(() => ro.callback(entries, ro.observer)); | ||
| callbacks.push(function resizeObserverCallback() { ro.callback(entries, ro.observer); }); | ||
| ro.activeTargets.splice(0, ro.activeTargets.length); | ||
| }); | ||
| callbacks.forEach(callback => callback()); | ||
| callbacks.forEach(function fireCallback(callback) { return callback(); }); | ||
| return shallowestDepth; | ||
| }; | ||
| export { broadcastActiveObservations }; |
| import { ResizeObserverBoxOptions } from '../ResizeObserverBoxOptions'; | ||
| import { DOMRectReadOnly } from '../DOMRectReadOnly'; | ||
| import { isSVG, isHidden } from '../utils/element'; | ||
| const cache = new Map(); | ||
| const scrollRegexp = /auto|scroll/; | ||
| const IE = (/msie|trident/i).test(navigator.userAgent); | ||
| const parseDimension = (pixel) => parseFloat(pixel || '0'); | ||
| const isSVG = (target) => 'SVGGraphicsElement' in window | ||
| && target instanceof SVGGraphicsElement && 'getBBox' in target; | ||
| const size = (inlineSize = 0, blockSize = 0) => { | ||
| return Object.freeze({ inlineSize, blockSize }); | ||
| }; | ||
| const zeroBoxes = Object.freeze({ | ||
| borderBoxSize: size(), | ||
| contentBoxSize: size(), | ||
| scrollBoxSize: size(), | ||
| devicePixelBorderBoxSize: size(), | ||
| contentRect: new DOMRectReadOnly(0, 0, 0, 0) | ||
| }); | ||
| const calculateBoxSizes = (target) => { | ||
@@ -12,16 +22,20 @@ if (cache.has(target)) { | ||
| } | ||
| if (isHidden(target)) { | ||
| cache.set(target, zeroBoxes); | ||
| return zeroBoxes; | ||
| } | ||
| const cs = getComputedStyle(target); | ||
| const dpr = window.devicePixelRatio; | ||
| const svg = isSVG(target) && target.getBBox(); | ||
| const cs = getComputedStyle(target); | ||
| const removePadding = !IE && cs.boxSizing === 'border-box'; | ||
| const width = parseDimension(cs.width); | ||
| const height = parseDimension(cs.height); | ||
| const hidden = isNaN(width) || isNaN(height) || cs.display === 'none'; | ||
| const paddingTop = svg || hidden ? 0 : parseDimension(cs.paddingTop); | ||
| const paddingRight = svg || hidden ? 0 : parseDimension(cs.paddingRight); | ||
| const paddingBottom = svg || hidden ? 0 : parseDimension(cs.paddingBottom); | ||
| const paddingLeft = svg || hidden ? 0 : parseDimension(cs.paddingLeft); | ||
| const borderTop = svg || hidden ? 0 : parseDimension(cs.borderTopWidth); | ||
| const borderRight = svg || hidden ? 0 : parseDimension(cs.borderRightWidth); | ||
| const borderBottom = svg || hidden ? 0 : parseDimension(cs.borderBottomWidth); | ||
| const borderLeft = svg || hidden ? 0 : parseDimension(cs.borderLeftWidth); | ||
| const canScrollVertically = !svg && scrollRegexp.test(cs.overflowY || ''); | ||
| const canScrollHorizontally = !svg && scrollRegexp.test(cs.overflowX || ''); | ||
| const paddingTop = svg ? 0 : parseDimension(cs.paddingTop); | ||
| const paddingRight = svg ? 0 : parseDimension(cs.paddingRight); | ||
| const paddingBottom = svg ? 0 : parseDimension(cs.paddingBottom); | ||
| const paddingLeft = svg ? 0 : parseDimension(cs.paddingLeft); | ||
| const borderTop = svg ? 0 : parseDimension(cs.borderTopWidth); | ||
| const borderRight = svg ? 0 : parseDimension(cs.borderRightWidth); | ||
| const borderBottom = svg ? 0 : parseDimension(cs.borderBottomWidth); | ||
| const borderLeft = svg ? 0 : parseDimension(cs.borderLeftWidth); | ||
| const horizontalPadding = paddingLeft + paddingRight; | ||
@@ -31,30 +45,17 @@ const verticalPadding = paddingTop + paddingBottom; | ||
| const verticalBorderArea = borderTop + borderBottom; | ||
| const horizontalScrollbarThickness = !canScrollHorizontally ? 0 : target.offsetHeight - verticalBorderArea - target.clientHeight; | ||
| const verticalScrollbarThickness = !canScrollVertically ? 0 : target.offsetWidth - horizontalBorderArea - target.clientWidth; | ||
| const widthReduction = removePadding ? horizontalPadding + horizontalBorderArea : 0; | ||
| const heightReduction = removePadding ? verticalPadding + verticalBorderArea : 0; | ||
| const contentWidth = hidden ? 0 : svg ? svg.width : parseDimension(cs.width) - widthReduction; | ||
| const contentHeight = hidden ? 0 : svg ? svg.height : parseDimension(cs.height) - heightReduction; | ||
| const borderBoxSize = { | ||
| inlineSize: contentWidth + horizontalPadding + horizontalBorderArea, | ||
| blockSize: contentHeight + verticalPadding + verticalBorderArea | ||
| }; | ||
| const contentBoxSize = { | ||
| inlineSize: contentWidth, | ||
| blockSize: contentHeight | ||
| }; | ||
| const scrollBoxSize = { | ||
| inlineSize: contentWidth + horizontalPadding, | ||
| blockSize: contentHeight + verticalPadding | ||
| }; | ||
| const devicePixelBorderBoxSize = { | ||
| inlineSize: borderBoxSize.inlineSize * window.devicePixelRatio, | ||
| blockSize: borderBoxSize.blockSize * window.devicePixelRatio | ||
| }; | ||
| const contentRect = new DOMRectReadOnly(paddingLeft, paddingTop, contentWidth, contentHeight); | ||
| const boxes = { | ||
| borderBoxSize, | ||
| contentBoxSize, | ||
| scrollBoxSize, | ||
| devicePixelBorderBoxSize, | ||
| contentRect | ||
| }; | ||
| const contentWidth = svg ? svg.width : parseDimension(cs.width) - widthReduction - verticalScrollbarThickness; | ||
| const contentHeight = svg ? svg.height : parseDimension(cs.height) - heightReduction - horizontalScrollbarThickness; | ||
| const borderBoxWidth = contentWidth + horizontalPadding + verticalScrollbarThickness + horizontalBorderArea; | ||
| const borderBoxHeight = contentHeight + verticalPadding + horizontalScrollbarThickness + verticalBorderArea; | ||
| const boxes = Object.freeze({ | ||
| borderBoxSize: size(borderBoxWidth, borderBoxHeight), | ||
| contentBoxSize: size(contentWidth, contentHeight), | ||
| scrollBoxSize: size(contentWidth + horizontalPadding, contentHeight + verticalPadding), | ||
| devicePixelBorderBoxSize: size(borderBoxWidth * dpr, borderBoxHeight * dpr), | ||
| contentRect: new DOMRectReadOnly(paddingLeft, paddingTop, contentWidth, contentHeight) | ||
| }); | ||
| cache.set(target, boxes); | ||
@@ -61,0 +62,0 @@ return boxes; |
@@ -0,2 +1,6 @@ | ||
| import { isHidden } from '../utils/element'; | ||
| const calculateDepthForNode = (node) => { | ||
| if (isHidden(node)) { | ||
| return Infinity; | ||
| } | ||
| let depth = 0; | ||
@@ -3,0 +7,0 @@ let parent = node.parentNode; |
| import { resizeObservers } from '../ResizeObserverController'; | ||
| import { calculateDepthForNode } from './calculateDepthForNode'; | ||
| import { cache as boxCache } from './calculateBoxSize'; | ||
| import { cache as sizeCache } from './calculateBoxSize'; | ||
| const gatherActiveObservationsAtDepth = (depth) => { | ||
| boxCache.clear(); | ||
| resizeObservers.forEach((ro) => { | ||
| sizeCache.clear(); | ||
| resizeObservers.forEach(function processObserver(ro) { | ||
| ro.activeTargets.splice(0, ro.activeTargets.length); | ||
| ro.skippedTargets.splice(0, ro.skippedTargets.length); | ||
| ro.observationTargets.forEach((ot) => { | ||
| ro.observationTargets.forEach(function processTarget(ot) { | ||
| if (ot.isActive()) { | ||
@@ -11,0 +11,0 @@ if (calculateDepthForNode(ot.target) > depth) { |
+18
-16
@@ -21,16 +21,17 @@ import { process } from '../ResizeObserverController'; | ||
| ]; | ||
| const rafSlots = new Map(); | ||
| const resizeObserverSlots = new Map(); | ||
| let handle; | ||
| const rafSlot = new Map(); | ||
| const resizeObserverSlot = new Map(); | ||
| let scheduled; | ||
| const dispatchCallbacksOnNextFrame = () => { | ||
| if (typeof handle === 'number') { | ||
| if (scheduled) { | ||
| return; | ||
| } | ||
| function dispatchFrameEvents(t) { | ||
| handle = undefined; | ||
| scheduled = true; | ||
| function runSchedule(t) { | ||
| scheduled = false; | ||
| const callbacks = []; | ||
| rafSlots.forEach(callback => callbacks.push(callback)); | ||
| resizeObserverSlots.forEach(callback => callbacks.push(callback)); | ||
| rafSlots.clear(); | ||
| resizeObserverSlots.clear(); | ||
| rafSlot.forEach(callback => callbacks.push(callback)); | ||
| resizeObserverSlot.forEach(callback => callbacks.push(callback)); | ||
| rafSlot.clear(); | ||
| resizeObserverSlot.clear(); | ||
| for (let callback of callbacks) { | ||
@@ -41,3 +42,3 @@ callback(t); | ||
| ; | ||
| handle = requestAnimationFrame(dispatchFrameEvents); | ||
| requestAnimationFrame(runSchedule); | ||
| }; | ||
@@ -50,8 +51,9 @@ class Scheduler { | ||
| run(frames) { | ||
| resizeObserverSlots.set(this, () => { | ||
| const scheduler = this; | ||
| resizeObserverSlot.set(this, function ResizeObserver() { | ||
| if (process()) { | ||
| this.run(60); | ||
| scheduler.run(60); | ||
| } | ||
| else if (frames) { | ||
| this.run(frames - 1); | ||
| scheduler.run(frames - 1); | ||
| } | ||
@@ -93,3 +95,3 @@ }); | ||
| const handle = rafIdBase += 1; | ||
| rafSlots.set(handle, callback); | ||
| rafSlot.set(handle, function AnimationFrame(t) { return callback(t); }); | ||
| dispatchCallbacksOnNextFrame(); | ||
@@ -99,3 +101,3 @@ return handle; | ||
| window.cancelAnimationFrame = function (handle) { | ||
| rafSlots.delete(handle); | ||
| rafSlot.delete(handle); | ||
| }; | ||
@@ -102,0 +104,0 @@ prettifyConsoleOutput(window.requestAnimationFrame); |
+1
-1
| { | ||
| "name": "@juggle/resize-observer", | ||
| "version": "1.0.0-rc.1", | ||
| "version": "1.0.0-rc.2", | ||
| "description": "ResizeObserver - Based on the official draft specification", | ||
@@ -5,0 +5,0 @@ "main": "./lib/ResizeObserver.js", |
42938
3.06%43
4.88%609
3.4%