wana
Version:
Easy observable state for React
356 lines (343 loc) • 10.5 kB
JavaScript
;
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