UNPKG

wana

Version:

Easy observable state for React

356 lines (343 loc) 10.5 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); require('./shims.js'); var mountAuto = require('./shared/23f6edd1.js'); var no = require('./shared/ffee02eb.js'); require('@alloc/queue-microtask'); var reactBatchedUpdates = require('react-batched-updates'); var is = require('@alloc/is'); var useMemoOne = require('use-memo-one'); var symbols = require('./shared/c9633b27.js'); var React = require('react'); var reactLayoutEffect = require('react-layout-effect'); var isDev = require('@alloc/is-dev'); var useChanges = require('./shared/4c241fe8.js'); function _interopNamespace(e) { if (e && e.__esModule) return 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__*/_interopNamespace(React); function useDerived(compute, discardOrDeps, deps) { let discard; if (typeof discardOrDeps == "function") { discard = discardOrDeps; } else { deps = discardOrDeps; } const [derived, setState] = React.useMemo(() => { if (!compute) { return [null, null]; } const derived2 = mountAuto.derive((auto) => { const observer = auto.start(compute); try { var result = compute(); } finally { auto.stop(); } setState2({observer}); return result; }, discard); const setState2 = mountAuto.mountAuto(derived2.auto); return [derived2, setState2]; }, deps || symbols.emptyArray); reactLayoutEffect.useLayoutEffect(() => { if (setState) { setState({mounted: true}); return () => setState({mounted: false}); } }, [setState]); return derived; } function useO(state, deps) { const result = useMemoOne.useMemoOne(() => convertDerived(is.is.function(state) ? no.noto(state) : state), deps || symbols.emptyArray); return is.is.function(result) ? useDerived(result, [result]) : mountAuto.o(result); } function convertDerived(state) { if (is.is.plainObject(state)) { for (const key in state) { const desc = symbols.getOwnDescriptor(state, key); if (mountAuto.isDerived(desc.value) && desc.configurable) { Object.defineProperty(state, key, { get: desc.value }); } } } return state; } const RenderAction = ({useAction}) => (useAction(), null); function useForceUpdate() { const update = React.useState()[1]; const mounted = React.useMemo(makeMountedRef, []); React.useEffect(mounted.unmount, symbols.emptyArray); return () => { if (mounted.current) { update({}); } }; } function makeMountedRef() { const mounted = { current: true, unmount: () => () => { mounted.current = false; } }; return mounted; } const useConstant = (create) => useMemoOne.useMemoOne(create, symbols.emptyArray); const useDispose = (dispose) => React.useEffect(() => dispose, symbols.emptyArray); function useAuto(computeOrEffect, effectOrDeps, deps) { const auto = useConstant(() => new mountAuto.Auto()); useDispose(() => auto.dispose()); let effect; if (is.is.function(effectOrDeps)) { const compute = useDerived(computeOrEffect, deps); effect = () => no.no(effectOrDeps)(compute()); } else { effect = computeOrEffect; deps = effectOrDeps; } React.useEffect(() => reactBatchedUpdates.batchedUpdates(() => { auto.run(effect); }), deps); return auto; } function withAuto(render) { let component = (props, ref) => { const {auto, depth, commit} = useAutoRender(component); reactLayoutEffect.useLayoutEffect(() => commit(observer, nonce)); const observer = auto.start(render); try { var content = render(props, ref); } finally { auto.stop(); } const {nonce} = observer; const recon = /* @__PURE__ */ React__namespace.createElement(RenderAction, { useAction: () => { auto.nonce = nonce; } }); return /* @__PURE__ */ React__namespace.createElement(useChanges.AutoDepth, { value: depth + 1 }, recon, content); }; if (render.length > 1) { Object.defineProperty(component, "displayName", { get: () => component.displayName }); component = React.forwardRef(component); } if (/^[A-Z]/.test(render.name)) { component.displayName = render.name; } if (isDev.isDev) { Object.defineProperty(component, "__render", { value: render }); } return component; } if (isDev.isDev) { withAuto.dev = (render) => { const Component = render.length > 1 ? React__namespace.forwardRef(render) : render; const AutoRender = React__namespace.forwardRef((props, ref) => { const {auto, depth, commit} = useAutoRender(Component); function useCommit(observer) { let nonce = 0; reactLayoutEffect.useLayoutEffect(() => commit(observer, nonce)); return () => { nonce = observer.nonce; return /* @__PURE__ */ React__namespace.createElement(RenderAction, { useAction: () => { auto.nonce = nonce; } }); }; } return /* @__PURE__ */ React__namespace.createElement(useChanges.AutoDepth, { value: depth + 1 }, /* @__PURE__ */ React__namespace.createElement(Component, { ...props, ref, $auto: auto, $useCommit: useCommit })); }); Object.defineProperty(AutoRender, "displayName", { get: () => "AutoRender", set(displayName) { Component.displayName = displayName; } }); return AutoRender; }; } function useAutoRender(component) { const depth = useChanges.useAutoDepth(); const forceUpdate = useForceUpdate(); const auto = React.useMemo(() => { const auto2 = new mountAuto.Auto({ onDirty() { if (isDev.isDev) { no.addDebugAction(auto2, "dirty"); } const {observer} = auto2; if (!observer) { return; } mountAuto.batch.render(depth, () => { if (observer == auto2.observer) { if (observer.nonce > auto2.nonce) { if (isDev.isDev) { no.addDebugAction(auto2, "batch"); } forceUpdate(); } else { auto2.dirty = false; } } }); } }); if (isDev.isDev) { no.setDebug(auto2, { name: component.displayName || "Anonymous", actions: ["init"], renders: 0 }); } return auto2; }, []); if (isDev.isDev) { no.getDebug(auto).renders++; if (symbols.globals.onRender) { symbols.globals.onRender(auto, depth, component); } } useDispose(() => auto.dispose()); return { auto, depth, commit(observer, nonce) { if (isDev.isDev) { no.getDebug(auto).actions = []; } if (!auto.commit(observer, nonce)) { if (isDev.isDev) { no.addDebugAction(auto, "dirty"); } forceUpdate(); } else if (isDev.isDev) { no.addDebugAction(auto, "observe"); } } }; } function useEffects(source, effect, deps) { const unmountFns = React.useMemo(() => new Map(), []); const usedEffect = React.useRef(effect); reactLayoutEffect.useLayoutEffect(() => { usedEffect.current = effect; }, deps); const target = no.no(source); const isValueBased = is.is.array(target) || is.is.set(target); reactLayoutEffect.useLayoutEffect(() => { if (is.is.function(target.forEach)) { target.forEach(mount); } else { Object.keys(target).forEach((key) => mount(target[key], key)); } return () => unmountFns.forEach((unmount) => unmount()); }, [source]); useChanges.useChanges(source, onChange); function mount(value, key) { const cacheKey = isValueBased ? value : key; if (!(is.is.array(target) && unmountFns.has(cacheKey))) { const effect2 = usedEffect.current; const unmount = isValueBased ? effect2(value) : effect2(value, key); unmountFns.set(cacheKey, unmount || symbols.noop); } } function onChange({op, key, value, oldValue}) { if (key == symbols.SIZE) return; if (op == "clear") { unmountFns.forEach((unmount) => unmount()); unmountFns.clear(); } else if (op == "splice") { if (is.is.array(target)) { oldValue.forEach((value2) => { if (!target.includes(value2)) { unmountFns.get(value2)(); unmountFns.delete(value2); } }); value.forEach((value2) => { if (!unmountFns.has(value2)) { mount(value2); } }); } } else { if (op != "add") { const cacheKey = isValueBased ? oldValue : key; if (!(is.is.array(target) && target.includes(cacheKey))) { unmountFns.get(cacheKey)(); unmountFns.delete(cacheKey); } } if (op != "remove") { const cacheKey = isValueBased ? value : key; if (!(is.is.array(target) && unmountFns.has(cacheKey))) { mount(value, key); } } } } } function useBinding(target, key) { const observable = target[symbols.$O]; const forceUpdate = useForceUpdate(); reactLayoutEffect.useLayoutEffect(() => observable?.observe(resolveKey(target, key), (change) => { if (change.op == "clear" && is.is.function(target)) return; forceUpdate(); }).dispose, [observable, key]); return key ? is.is.map(target) ? target.get(key) : target[key] : is.is.function(target) ? target() : target; } const resolveKey = (target, key = symbols.$O) => key == "length" && is.is.array(target) || key == "size" && is.is.set(target) ? symbols.SIZE : key; exports.Auto = mountAuto.Auto; exports.auto = mountAuto.auto; exports.isDerived = mountAuto.isDerived; exports.o = mountAuto.o; exports.shallowChanges = mountAuto.shallowChanges; exports.watch = mountAuto.watch; exports.when = mountAuto.when; exports.no = no.no; exports.noto = no.noto; exports.useChanges = useChanges.useChanges; exports.useAuto = useAuto; exports.useBinding = useBinding; exports.useDerived = useDerived; exports.useEffects = useEffects; exports.useO = useO; exports.withAuto = withAuto; //# sourceMappingURL=wana.js.map