@dark-engine/core
Version:
The lightweight and powerful UI rendering engine without dependencies and written in TypeScript (Browser, Node.js, Android, iOS, Windows, Linux, macOS)
60 lines (59 loc) • 1.96 kB
JavaScript
import { component } from '../component';
import { useLayoutEffect } from '../use-layout-effect';
import { __useCursor as useCursor } from '../internal';
import { EventEmitter } from '../emitter';
import { useUpdate } from '../use-update';
import { detectIsEqual } from '../utils';
import { useMemo } from '../use-memo';
function createContext(defaultValue, options) {
const { displayName = 'Component' } = options || {};
const context = component(
({ value = defaultValue, slot }) => {
const cursor = useCursor();
const { hook } = cursor;
let providers = hook.getProviders();
if (!providers) {
providers = new Map();
providers.set(context, { value, emitter: new EventEmitter() });
hook.setProviders(providers);
}
const provider = providers.get(context);
useLayoutEffect(() => {
provider.emitter.emit('publish', value);
}, [value]);
provider.value = value;
return slot;
},
{ displayName: `Context(${displayName})` },
);
context.defaultValue = defaultValue;
Object.freeze(context);
return context;
}
function useContext(context) {
const { defaultValue } = context;
const cursor = useCursor();
const scope = useMemo(() => ({ value: null, provider: getProvider(context, cursor) }), []);
const update = useUpdate();
const { provider } = scope;
const value = provider ? provider.value : defaultValue;
useLayoutEffect(() => {
if (!provider) return;
return provider.emitter.on('publish', value => {
!detectIsEqual(scope.value, value) && update();
});
}, []);
scope.value = value;
return value;
}
function getProvider(context, fiber) {
let $fiber = fiber;
while ($fiber) {
const providers = $fiber.hook?.getProviders();
if (providers?.has(context)) return providers.get(context);
$fiber = $fiber.parent;
}
return null;
}
export { createContext, useContext };
//# sourceMappingURL=context.js.map