UNPKG

react-external-subject

Version:

Wrap mutable sources into React-safe mutable source

195 lines (189 loc) 5.74 kB
"use strict"; 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