UNPKG

react-flexbox-layout

Version:
105 lines (85 loc) 3.08 kB
import includes from 'lodash/includes'; import debounce from 'lodash/debounce'; import invokeMap from 'lodash/invokeMap'; /** * UpdateEngineIE9 * * Singleton that handles updating *LayoutIE9 components outside of the React's update flow */ // array of mounted *LayoutiE9 components // invariant: parent Layout components will have lower index than child Layout components let components = []; /** * register registers a Layout component with the UpdateEngine * @param {LayoutComponent} component */ export function register(component) { if (!includes(components, component)) { components.push(component); } } /** * deregister removes a Layout component from the UpdateEngine * @param {LayoutComponent} component */ export function deregister(component) { const i = components.indexOf(component); if (i !== -1) { components.splice(i, 1); } } /** * update synchronously updates all registered Layout components */ export function update() { // first unset all styles, since existing styles will mess with measurements invokeMap(components, '_unsetLayoutStyles'); // NOTE: batch measurements and style application as much as possible to prevent excessive reflows // apply widths first because heights are dependent on widths (e.g., text wrap), but not the other way around invokeMap(components, '_measureInheritedStyles'); invokeMap(components, '_measureWidths'); invokeMap(components, '_applyInheritedStyles'); invokeMap(components, '_applyWidths'); // apply heights now that widths have been set invokeMap(components, '_measureItemHeights'); invokeMap(components, '_applyFlexHeights'); // NOTE: each container must be set sequentially instead of batched because child Layout heights can depend on // parent Layout heights (e.g., child is vertical flexGrow on parent). In-order traversal of array works because of the // invariant described above: parent Layout components will have lower index than child Layout components. invokeMap(components, '_setContainerHeights'); invokeMap(components, '_callDidLayout'); } /** * requestAsyncUpdate guarantees that `update` will be run sometime in the future */ export const requestAsyncUpdate = debounce(updateAfterDelay, 0); export function updateOnWindowResize() { window.addEventListener('resize', debounce(requestAsyncUpdate, 16)); } var nextDelay = 0; /** * Request that the next re-layout be at least @delay ms from now. * @param {Number} delay */ export function requestNextLayoutMinDelay(delay) { nextDelay = Math.max(nextDelay, delay); } var delayedUpdate, delayedUpdateTime; function updateAfterDelay() { if (nextDelay === 0 && !delayedUpdate) { update(); return; } var potentialUpdateTime = Date.now() + nextDelay; if (!delayedUpdate || potentialUpdateTime > delayedUpdateTime) { clearTimeout(delayedUpdate); delayedUpdateTime = potentialUpdateTime; delayedUpdate = setTimeout(performDelayedUpdate, nextDelay); } nextDelay = 0; } function performDelayedUpdate() { delayedUpdate = null; update(); }