summit/frontend/node_modules/tunnel-rat/dist/index.js

64 lines
2.0 KiB
JavaScript

import React from 'react';
import { create } from 'zustand';
var _window$document, _window$navigator;
/**
* An SSR-friendly useLayoutEffect.
*
* React currently throws a warning when using useLayoutEffect on the server.
* To get around it, we can conditionally useEffect on the server (no-op) and
* useLayoutEffect elsewhere.
*
* @see https://github.com/facebook/react/issues/14927
*/
const useIsomorphicLayoutEffect = typeof window !== 'undefined' && ((_window$document = window.document) != null && _window$document.createElement || ((_window$navigator = window.navigator) == null ? void 0 : _window$navigator.product) === 'ReactNative') ? React.useLayoutEffect : React.useEffect;
function tunnel() {
const useStore = create(set => ({
current: new Array(),
version: 0,
set
}));
return {
In: ({
children
}) => {
const set = useStore(state => state.set);
const version = useStore(state => state.version);
/* When this component mounts, we increase the store's version number.
This will cause all existing rats to re-render (just like if the Out component
were mapping items to a list.) The re-rendering will cause the final
order of rendered components to match what the user is expecting. */
useIsomorphicLayoutEffect(() => {
set(state => ({
version: state.version + 1
}));
}, []);
/* Any time the children _or_ the store's version number change, insert
the specified React children into the list of rats. */
useIsomorphicLayoutEffect(() => {
set(({
current
}) => ({
current: [...current, children]
}));
return () => set(({
current
}) => ({
current: current.filter(c => c !== children)
}));
}, [children, version]);
return null;
},
Out: () => {
const current = useStore(state => state.current);
return /*#__PURE__*/React.createElement(React.Fragment, null, current);
}
};
}
export { tunnel as default };