@vimeo/iris
Version:
Vimeo Design System
157 lines (144 loc) • 4.81 kB
JavaScript
import { createContext, useLayoutEffect, useEffect, useRef } from 'react';
/**
* Browser-safe usage of process
*/
var defaultEnvironment = "production";
var env = typeof process === "undefined" || process.env === undefined ? defaultEnvironment : process.env.NODE_ENV || defaultEnvironment;
/**
* @public
*/
var PresenceContext = /*#__PURE__*/createContext(null);
var isBrowser = typeof document !== "undefined";
var useIsomorphicLayoutEffect = isBrowser ? useLayoutEffect : useEffect;
/**
* Creates a constant value over the lifecycle of a component.
*
* Even if `useMemo` is provided an empty array as its final argument, it doesn't offer
* a guarantee that it won't re-run for performance reasons later on. By using `useConstant`
* you can ensure that initialisers don't execute twice or more.
*/
function useConstant(init) {
var ref = useRef(null);
if (ref.current === null) {
ref.current = init();
}
return ref.current;
}
var LayoutGroupContext = /*#__PURE__*/createContext({});
function useUnmountEffect(callback) {
return useEffect(function () {
return function () {
return callback();
};
}, []);
}
const defaultTimestep = 1 / 60 * 1000;
const getCurrentTime = typeof performance !== "undefined" ? () => performance.now() : () => Date.now();
const onNextFrame = typeof window !== "undefined" ? callback => window.requestAnimationFrame(callback) : callback => setTimeout(() => callback(getCurrentTime()), defaultTimestep);
function createRenderStep(runNextFrame) {
let toRun = [];
let toRunNextFrame = [];
let numToRun = 0;
let isProcessing = false;
let flushNextFrame = false;
const toKeepAlive = new WeakSet();
const step = {
schedule: (callback, keepAlive = false, immediate = false) => {
const addToCurrentFrame = immediate && isProcessing;
const buffer = addToCurrentFrame ? toRun : toRunNextFrame;
if (keepAlive) toKeepAlive.add(callback);
if (buffer.indexOf(callback) === -1) {
buffer.push(callback);
if (addToCurrentFrame && isProcessing) numToRun = toRun.length;
}
return callback;
},
cancel: callback => {
const index = toRunNextFrame.indexOf(callback);
if (index !== -1) toRunNextFrame.splice(index, 1);
toKeepAlive.delete(callback);
},
process: frameData => {
if (isProcessing) {
flushNextFrame = true;
return;
}
isProcessing = true;
[toRun, toRunNextFrame] = [toRunNextFrame, toRun];
toRunNextFrame.length = 0;
numToRun = toRun.length;
if (numToRun) {
for (let i = 0; i < numToRun; i++) {
const callback = toRun[i];
callback(frameData);
if (toKeepAlive.has(callback)) {
step.schedule(callback);
runNextFrame();
}
}
}
isProcessing = false;
if (flushNextFrame) {
flushNextFrame = false;
step.process(frameData);
}
}
};
return step;
}
const maxElapsed = 40;
let useDefaultElapsed = true;
let runNextFrame = false;
let isProcessing = false;
const frame = {
delta: 0,
timestamp: 0
};
const stepsOrder = ["read", "update", "preRender", "render", "postRender"];
const steps = stepsOrder.reduce((acc, key) => {
acc[key] = createRenderStep(() => runNextFrame = true);
return acc;
}, {});
const sync = stepsOrder.reduce((acc, key) => {
const step = steps[key];
acc[key] = (process, keepAlive = false, immediate = false) => {
if (!runNextFrame) startLoop();
return step.schedule(process, keepAlive, immediate);
};
return acc;
}, {});
const cancelSync = stepsOrder.reduce((acc, key) => {
acc[key] = steps[key].cancel;
return acc;
}, {});
const flushSync = stepsOrder.reduce((acc, key) => {
acc[key] = () => steps[key].process(frame);
return acc;
}, {});
const processStep = stepId => steps[stepId].process(frame);
const processFrame = timestamp => {
runNextFrame = false;
frame.delta = useDefaultElapsed ? defaultTimestep : Math.max(Math.min(timestamp - frame.timestamp, maxElapsed), 1);
frame.timestamp = timestamp;
isProcessing = true;
stepsOrder.forEach(processStep);
isProcessing = false;
if (runNextFrame) {
useDefaultElapsed = false;
onNextFrame(processFrame);
}
};
const startLoop = () => {
runNextFrame = true;
useDefaultElapsed = true;
if (!isProcessing) onNextFrame(processFrame);
};
const getFrameData = () => frame;
var counter = 0;
var incrementId = function () {
return counter++;
};
var useId = function () {
return useConstant(incrementId);
};
export { LayoutGroupContext as L, PresenceContext as P, useConstant as a, useUnmountEffect as b, cancelSync as c, useId as d, env as e, flushSync as f, getFrameData as g, isBrowser as i, sync as s, useIsomorphicLayoutEffect as u };