@mapbox/mr-ui
Version:
UI components for Mapbox projects
84 lines (82 loc) • 3.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = MinimumDurationLoader;
var _react = _interopRequireWildcard(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _use_previous = _interopRequireDefault(require("../utils/use_previous"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
/**
* Display a loading indicator in place of its children until the `isLoaded`
* prop is true. The indicator will be displayed for a minimum
* amount of time as specified by the `minDuration`.
*/
function MinimumDurationLoader(_ref) {
let {
children,
isLoaded,
loader = /*#__PURE__*/_react.default.createElement("div", {
className: "loading",
"data-testid": "minimum-duration-loader"
}),
minDuration = 1000
} = _ref;
// If `isLoaded` is immediately true, load children right away.
const [wasLoaded] = (0, _react.useState)(isLoaded);
const prevIsLoaded = (0, _use_previous.default)(isLoaded);
const startTime = (0, _react.useRef)(0);
const delayedMountTimeoutRef = (0, _react.useRef)(null);
const [delayedLoaded, setDelayedLoaded] = (0, _react.useState)(false);
(0, _react.useEffect)(() => {
// Duration for our timeout to set delayedLoaded to true.
let duration = 0;
if (!prevIsLoaded && isLoaded) {
startTime.current = null;
setDelayedLoaded(false);
}
if (startTime.current) {
// This means the minDuration has changed after we started the timer.
duration = Math.min(0, minDuration - (Date.now() - startTime.current));
} else {
// This is our first time.
startTime.current = Date.now();
duration = minDuration;
}
delayedMountTimeoutRef.current = setTimeout(() => {
delayedMountTimeoutRef.current = null;
setDelayedLoaded(true);
}, duration);
// Clear the existing timeout if the content begins loading again.
return () => {
if (delayedMountTimeoutRef.current) {
clearTimeout(delayedMountTimeoutRef.current);
}
};
}, [startTime, delayedMountTimeoutRef, minDuration, prevIsLoaded, isLoaded]);
const shouldRenderContent = isLoaded && (wasLoaded || delayedLoaded || prevIsLoaded);
if (shouldRenderContent) {
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, children);
}
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, loader);
}
MinimumDurationLoader.propTypes = {
/**
* The content of the modal.
*/
children: _propTypes.default.node.isRequired,
/**
* When `false` the loader will continue to display until this is passed as `true.
*/
isLoaded: _propTypes.default.bool.isRequired,
/**
* An optional for passing a custom loader.
*/
loader: _propTypes.default.node,
/**
* The minimum duration the loader should appear for (defaults to one second).
*/
minDuration: _propTypes.default.number
};