react-async-states-utils
Version:
utilities for react-async-states package
239 lines (230 loc) • 9.81 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('react-async-states'), require('async-states')) :
typeof define === 'function' && define.amd ? define(['exports', 'react', 'react-async-states', 'async-states'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ReactAsyncStatesUtils = {}, global.React, global.ReactAsyncStates, global.AsyncStates));
})(this, (function (exports, React, reactAsyncStates, asyncStates) { 'use strict';
function _interopNamespaceDefault(e) {
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
let emptyArray = [];
function isFunction(fn) {
return typeof fn === "function";
}
const StateBoundaryContext = React__namespace.createContext(null);
function StateBoundary(props) {
return React__namespace.createElement(StateBoundaryImpl, Object.assign({ key: props.strategy }, props), props.children);
}
exports.RenderStrategy = void 0;
(function (RenderStrategy) {
RenderStrategy[RenderStrategy["FetchAsYouRender"] = 0] = "FetchAsYouRender";
RenderStrategy[RenderStrategy["FetchThenRender"] = 1] = "FetchThenRender";
RenderStrategy[RenderStrategy["RenderThenFetch"] = 2] = "RenderThenFetch";
})(exports.RenderStrategy || (exports.RenderStrategy = {}));
let BoundarySourceContext = React__namespace.createContext(null);
function BoundarySource({ source, children, }) {
let parentSource = React__namespace.useContext(BoundarySourceContext);
let contextValue = React__namespace.useMemo(() => ({
source,
parent: parentSource,
}), [source, parentSource]);
return (React__namespace.createElement(BoundarySourceContext.Provider, { value: contextValue }, children));
}
function StateBoundaryImpl(props) {
if (props.strategy === exports.RenderStrategy.FetchThenRender) {
return React__namespace.createElement(FetchThenRenderBoundary, props);
}
if (props.strategy === exports.RenderStrategy.FetchAsYouRender) {
return React__namespace.createElement(FetchAsYouRenderBoundary, props);
}
return React__namespace.createElement(RenderThenFetchBoundary, props);
}
function inferBoundaryChildren(result, props) {
if (!props.render || !result.source) {
return props.children;
}
const { status } = result.source.getState();
return props.render[status] ? props.render[status] : props.children;
}
function renderChildren(children, props) {
return isFunction(children) ? React__namespace.createElement(children, props) : children;
}
function RenderThenFetchBoundary(props) {
let result = reactAsyncStates.useAsyncState(props.config, props.dependencies);
const children = inferBoundaryChildren(result, props);
let Context = StateBoundaryContext;
return (React__namespace.createElement(BoundarySource, { source: result.source },
React__namespace.createElement(Context.Provider, { value: result }, renderChildren(children, result))));
}
function FetchAsYouRenderBoundary(props) {
let result = reactAsyncStates.useAsyncState(props.config, props.dependencies);
result.read(); // throws
const children = inferBoundaryChildren(result, props);
let Context = StateBoundaryContext;
return (React__namespace.createElement(BoundarySource, { source: result.source },
React__namespace.createElement(Context.Provider, { value: result }, renderChildren(children, result))));
}
function FetchThenRenderInitialBoundary({ dependencies = emptyArray, result, config, }) {
result.source?.patchConfig({
skipPendingStatus: true,
});
React__namespace.useEffect(() => {
if (config.condition !== false) {
const autoRunArgs = config
.autoRunArgs;
if (Array.isArray(autoRunArgs)) {
return result.source.run.apply(null, autoRunArgs);
}
return result.source.run.apply(null);
}
}, dependencies);
return null;
}
function FetchThenRenderBoundary(props) {
let result = reactAsyncStates.useAsyncState(props.config, props.dependencies);
let Context = StateBoundaryContext;
switch (result.source?.getState().status) {
case reactAsyncStates.Status.pending:
case reactAsyncStates.Status.initial: {
return (React__namespace.createElement(FetchThenRenderInitialBoundary, { result: result, config: props.config, dependencies: props.dependencies }));
}
case reactAsyncStates.Status.error:
case reactAsyncStates.Status.success: {
const children = inferBoundaryChildren(result, props);
return (React__namespace.createElement(BoundarySource, { source: result.source },
React__namespace.createElement(Context.Provider, { value: result }, renderChildren(children, result))));
}
}
return null;
}
function useCurrentState() {
const ctxValue = React__namespace.useContext(StateBoundaryContext);
if (ctxValue === null) {
throw new Error("useCurrentState used outside StateBoundary");
}
return ctxValue;
}
function recursivelyTraverseContextAndGetSource(ctxValue, stateKey) {
if (!stateKey) {
return ctxValue.source;
}
let currentSource = ctxValue.source;
if (currentSource.key === stateKey) {
return currentSource;
}
if (ctxValue.parent !== null) {
return recursivelyTraverseContextAndGetSource(ctxValue.parent, stateKey);
}
throw new Error(`(${stateKey}) was not found in boundary tree`);
}
function useBoundary(stateKey) {
const ctxValue = React__namespace.useContext(BoundarySourceContext);
if (ctxValue === null) {
throw new Error("useBoundary used outside StateBoundary");
}
let source = recursivelyTraverseContextAndGetSource(ctxValue, stateKey);
return reactAsyncStates.useAsync(source);
}
function run(keyOrSource, ...args) {
return runImpl(keyOrSource, null, undefined, ...args);
}
function runLane(keyOrSource, lane, ...args) {
return runImpl(keyOrSource, null, lane, ...args);
}
function runInContext(keyOrSource, context, ...args) {
return runImpl(keyOrSource, context, undefined, ...args);
}
function runLaneInContext(keyOrSource, context, lane, ...args) {
return runImpl(keyOrSource, context, lane, ...args);
}
function runImpl(keyOrSource, context, lane, ...args) {
if (asyncStates.isSource(keyOrSource)) {
return keyOrSource.getLane(lane).run(...args);
}
if (typeof keyOrSource === "string") {
let instance = asyncStates.requestContext(context).get(keyOrSource);
if (instance) {
return instance.actions.run.apply(null, args);
}
}
return undefined;
}
function extendStatus(state) {
let status = state.status;
switch (status) {
case reactAsyncStates.Status.initial: {
return {
isInitial: true,
isPending: false,
isError: false,
isAborted: false,
isSuccess: false,
};
}
case reactAsyncStates.Status.pending: {
return {
isInitial: false,
isPending: true,
isError: false,
isAborted: false,
isSuccess: false,
};
}
case reactAsyncStates.Status.success: {
return {
isInitial: false,
isPending: false,
isError: false,
isAborted: false,
isSuccess: true,
};
}
case reactAsyncStates.Status.error: {
return {
isInitial: false,
isPending: false,
isError: true,
isAborted: false,
isSuccess: false,
};
}
}
throw new Error(`Status ${status} isn't recognized!`);
}
function addBooleanStatus(state) {
let extended = extendStatus(state);
return Object.assign({}, extended, state);
}
let didWarnAboutDeprecation = false;
if (!didWarnAboutDeprecation) {
didWarnAboutDeprecation = true;
console.error("[Warning] react-async-states-utils is deprecated.\n" +
"It was on top of react-async-states and you can find the latest" +
"version in this link: https://github.com/incepter/react-async-states/tree/d8317cbee86f119d9a3286d9f1ef648897a0484a/packages/react-async-states-utils/src .");
}
exports.FetchAsYouRenderBoundary = FetchAsYouRenderBoundary;
exports.FetchThenRenderBoundary = FetchThenRenderBoundary;
exports.RenderThenFetchBoundary = RenderThenFetchBoundary;
exports.StateBoundary = StateBoundary;
exports.addBooleanStatus = addBooleanStatus;
exports.run = run;
exports.runInContext = runInContext;
exports.runLane = runLane;
exports.runLaneInContext = runLaneInContext;
exports.useBoundary = useBoundary;
exports.useCurrentState = useCurrentState;
}));
//# sourceMappingURL=react-async-states-utils.development.js.map