@wordpress/compose
Version:
WordPress higher-order components (HOCs).
138 lines (132 loc) • 5.38 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = useLegacyResizeObserver;
var _element = require("@wordpress/element");
var _useResizeObserver = require("../use-resize-observer");
var _jsxRuntime = require("react/jsx-runtime");
/**
* External dependencies
*/
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
// We're only using the first element of the size sequences, until future versions of the spec solidify on how
// exactly it'll be used for fragments in multi-column scenarios:
// From the spec:
// > The box size properties are exposed as FrozenArray in order to support elements that have multiple fragments,
// > which occur in multi-column scenarios. However the current definitions of content rect and border box do not
// > mention how those boxes are affected by multi-column layout. In this spec, there will only be a single
// > ResizeObserverSize returned in the FrozenArray, which will correspond to the dimensions of the first column.
// > A future version of this spec will extend the returned FrozenArray to contain the per-fragment size information.
// (https://drafts.csswg.org/resize-observer/#resize-observer-entry-interface)
//
// Also, testing these new box options revealed that in both Chrome and FF everything is returned in the callback,
// regardless of the "box" option.
// The spec states the following on this:
// > This does not have any impact on which box dimensions are returned to the defined callback when the event
// > is fired, it solely defines which box the author wishes to observe layout changes on.
// (https://drafts.csswg.org/resize-observer/#resize-observer-interface)
// I'm not exactly clear on what this means, especially when you consider a later section stating the following:
// > This section is non-normative. An author may desire to observe more than one CSS box.
// > In this case, author will need to use multiple ResizeObservers.
// (https://drafts.csswg.org/resize-observer/#resize-observer-interface)
// Which is clearly not how current browser implementations behave, and seems to contradict the previous quote.
// For this reason I decided to only return the requested size,
// even though it seems we have access to results for all box types.
// This also means that we get to keep the current api, being able to return a simple { width, height } pair,
// regardless of box option.
const extractSize = entry => {
let entrySize;
if (!entry.contentBoxSize) {
// The dimensions in `contentBoxSize` and `contentRect` are equivalent according to the spec.
// See the 6th step in the description for the RO algorithm:
// https://drafts.csswg.org/resize-observer/#create-and-populate-resizeobserverentry-h
// > Set this.contentRect to logical this.contentBoxSize given target and observedBox of "content-box".
// In real browser implementations of course these objects differ, but the width/height values should be equivalent.
entrySize = [entry.contentRect.width, entry.contentRect.height];
} else if (entry.contentBoxSize[0]) {
const contentBoxSize = entry.contentBoxSize[0];
entrySize = [contentBoxSize.inlineSize, contentBoxSize.blockSize];
} else {
// TS complains about this, because the RO entry type follows the spec and does not reflect Firefox's buggy
// behaviour of returning objects instead of arrays for `borderBoxSize` and `contentBoxSize`.
const contentBoxSize = entry.contentBoxSize;
entrySize = [contentBoxSize.inlineSize, contentBoxSize.blockSize];
}
const [width, height] = entrySize.map(d => Math.round(d));
return {
width,
height
};
};
const RESIZE_ELEMENT_STYLES = {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
pointerEvents: 'none',
opacity: 0,
overflow: 'hidden',
zIndex: -1
};
function ResizeElement({
onResize
}) {
const resizeElementRef = (0, _useResizeObserver.useResizeObserver)(entries => {
const newSize = extractSize(entries.at(-1)); // Entries are never empty.
onResize(newSize);
});
return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
ref: resizeElementRef,
style: RESIZE_ELEMENT_STYLES,
"aria-hidden": "true"
});
}
function sizeEquals(a, b) {
return a.width === b.width && a.height === b.height;
}
const NULL_SIZE = {
width: null,
height: null
};
/**
* Hook which allows to listen to the resize event of any target element when it changes size.
* _Note: `useResizeObserver` will report `null` sizes until after first render.
*
* @example
*
* ```js
* const App = () => {
* const [ resizeListener, sizes ] = useResizeObserver();
*
* return (
* <div>
* { resizeListener }
* Your content here
* </div>
* );
* };
* ```
*/
function useLegacyResizeObserver() {
const [size, setSize] = (0, _element.useState)(NULL_SIZE);
// Using a ref to track the previous width / height to avoid unnecessary renders.
const previousSizeRef = (0, _element.useRef)(NULL_SIZE);
const handleResize = (0, _element.useCallback)(newSize => {
if (!sizeEquals(previousSizeRef.current, newSize)) {
previousSizeRef.current = newSize;
setSize(newSize);
}
}, []);
const resizeElement = /*#__PURE__*/(0, _jsxRuntime.jsx)(ResizeElement, {
onResize: handleResize
});
return [resizeElement, size];
}
//# sourceMappingURL=index.js.map
;