react-external-subject
Version:
Wrap mutable sources into React-safe mutable source
195 lines (189 loc) • 5.74 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __markAsModule = (target) => __defProp(target, "__esModule", {value: true});
var __export = (target, all) => {
__markAsModule(target);
for (var name in all)
__defProp(target, name, {get: all[name], enumerable: true});
};
var __exportStar = (target, module2, desc) => {
__markAsModule(target);
if (module2 && typeof module2 === "object" || typeof module2 === "function") {
for (let key of __getOwnPropNames(module2))
if (!__hasOwnProp.call(target, key) && key !== "default")
__defProp(target, key, {get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable});
}
return target;
};
var __toModule = (module2) => {
if (module2 && module2.__esModule)
return module2;
return __exportStar(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", {value: module2, enumerable: true}), module2);
};
// src/index.ts
__export(exports, {
ExternalSubjectSynchronizer: () => ExternalSubjectSynchronizer,
createExternalSubject: () => createExternalSubject,
useExternalSubject: () => useExternalSubject
});
// src/create-external-subject.ts
function defaultShouldUpdate(a, b) {
return !Object.is(a, b);
}
function createExternalSubject(options) {
var _a;
const shouldUpdate = (_a = options.shouldUpdate) != null ? _a : defaultShouldUpdate;
let cache;
const listeners = new Set();
let request;
const getCachedValue = () => {
if (!cache) {
cache = {
value: options.read()
};
}
return cache.value;
};
let synchronize;
const setSynchronizer = (sync) => {
if (!synchronize) {
synchronize = sync;
}
};
const requestUpdate = () => {
if (shouldUpdate(getCachedValue(), options.read())) {
if (request) {
request.alive = false;
}
request = {
promise: Promise.resolve().then(() => new Promise((resolve) => {
if (request == null ? void 0 : request.alive) {
request = void 0;
const onResolve = () => {
if (cache) {
cache.value = options.read();
}
listeners.forEach((listener) => {
listener();
});
resolve();
};
if (synchronize) {
synchronize(onResolve);
} else {
onResolve();
}
}
})),
alive: true
};
}
};
let unsubscribe;
const subscribe = (handler) => {
listeners.add(handler);
if (options.lazySubscribe && options.subscribe && listeners.size === 1) {
const unsub = options.subscribe(requestUpdate);
if (unsub) {
unsubscribe = unsub;
}
}
return () => {
listeners.delete(handler);
if (options.lazySubscribe && unsubscribe) {
unsubscribe();
}
};
};
if (!options.lazySubscribe && options.subscribe) {
unsubscribe = options.subscribe(requestUpdate);
}
const destroy = () => {
if (request) {
request.alive = false;
}
listeners.clear();
if (unsubscribe) {
unsubscribe();
}
};
return {
subscribe,
shouldUpdate,
requestUpdate,
getRequest: () => request,
getCachedValue,
getCurrentValue: options.read,
setSynchronizer,
destroy
};
}
// src/use-external-subject.ts
var react_hooks2 = __toModule(require("@lyonph/react-hooks"));
var react2 = __toModule(require("react"));
// src/ExternalSubjectSynchronizer.tsx
var react = __toModule(require("react"));
var react_hooks = __toModule(require("@lyonph/react-hooks"));
var ExternalSubjectSynchronizerContext = react.createContext(void 0);
function useExternalSubjectSynchronize() {
const context = react.useContext(ExternalSubjectSynchronizerContext);
if (context) {
return context;
}
throw new Error("Found no synchronizer.");
}
function ExternalSubjectSynchronizer({children}) {
const [state, setState] = react.useState([]);
const synchronize = react_hooks.useConstantCallback((cb) => {
setState((current) => [...current, cb]);
});
react.useEffect(() => {
if (state.length) {
setState([]);
state.forEach((update) => {
update();
});
}
}, [state]);
return /* @__PURE__ */ react.default.createElement(ExternalSubjectSynchronizerContext.Provider, {
value: synchronize
}, /* @__PURE__ */ react.default.createElement(react.Suspense, {
fallback: null
}, children));
}
// src/use-external-subject.ts
function useExternalSubjectInternal(subject, suspense = false) {
subject.setSynchronizer(useExternalSubjectSynchronize());
const subscription = react_hooks2.useMemoCondition(() => ({
read: () => subject.getCachedValue(),
subscribe: (handler) => subject.subscribe(handler),
shouldUpdate: (a, b) => subject.shouldUpdate(a, b)
}), subject);
const state = react_hooks2.useSubscription(subscription);
const ongoing = subject.getRequest();
if (ongoing) {
if (suspense) {
throw ongoing.promise;
}
} else {
subject.requestUpdate();
const current = subject.getRequest();
if (current) {
if (suspense) {
throw current.promise;
}
}
}
return state;
}
function useExternalSubject(subject, suspense = false) {
const value = useExternalSubjectInternal(subject, suspense);
react2.useDebugValue(value);
return value;
}
//# sourceMappingURL=react-external-subject.development.js.map