@vimeo/iris
Version:
Vimeo Design System
170 lines (156 loc) • 5.01 kB
JavaScript
;
var React = require('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__*/React.createContext(null);
var isBrowser = typeof document !== "undefined";
var useIsomorphicLayoutEffect = isBrowser ? React.useLayoutEffect : React.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 = React.useRef(null);
if (ref.current === null) {
ref.current = init();
}
return ref.current;
}
var LayoutGroupContext = /*#__PURE__*/React.createContext({});
function useUnmountEffect(callback) {
return React.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);
};
exports.LayoutGroupContext = LayoutGroupContext;
exports.PresenceContext = PresenceContext;
exports.cancelSync = cancelSync;
exports.env = env;
exports.flushSync = flushSync;
exports.getFrameData = getFrameData;
exports.isBrowser = isBrowser;
exports.sync = sync;
exports.useConstant = useConstant;
exports.useId = useId;
exports.useIsomorphicLayoutEffect = useIsomorphicLayoutEffect;
exports.useUnmountEffect = useUnmountEffect;