UNPKG

@expressive/react

Version:
173 lines (171 loc) 4.73 kB
import { Layers, provide } from "./context.js"; import { Context, State, event, watch } from "@expressive/state"; //#region src/state.ts const Pragma = {}; const OUTER = /* @__PURE__ */ new WeakMap(); const PROPS = /* @__PURE__ */ new WeakMap(); var ReactState = class ReactState extends State { /** * Create and manage instance of this State within React component. * * @param args Arguments to pass to constructor or `use` method (if defined). * @returns Managed instance of this State. */ static use(...args) { const ambient = Context.use(); const state = Pragma.useState(() => { let ready; let active; let use = (...args) => Promise.all(args.flat().map((arg) => typeof arg == "object" && instance.set(arg))); const instance = new this((x) => { if (x instanceof ReactState && x.use) { use = x.use?.bind(x); use(...args); } else return args; }); const context = ambient.push(instance); watch(instance, (current) => { active = current; if (ready) state[1]((x) => x.bind(null)); }); function didMount() { ready = true; return () => { context.pop(); instance.set(null); }; } return (...args) => { Pragma.useEffect(didMount, []); if (ready) { ready = false; Promise.resolve(use(...args)).finally(() => ready = true); } return active; }; }); return state[0](...args); } static get(argument) { const context = Context.use(); const state = Pragma.useState(() => { const instance = context.get(this); if (!instance) if (argument === false) return () => void 0; else throw new Error(`Could not find ${this} in context.`); let ready; let value; function render() { state[1]((x) => x.bind(null)); } function refresh(action) { if (typeof action == "function") action = action(); render(); if (action) return action.finally(render); } const unwatch = watch(instance, (current) => { if (typeof argument === "function") { const next = argument.call(current, current, refresh); if (next === value) return; value = next; } else value = current; if (ready) render(); }, argument === true); if (value instanceof Promise) { let error; unwatch(); value.then((x) => value = x, (e) => error = e).finally(render); value = null; return () => { if (error) throw error; return value === void 0 ? null : value; }; } if (value === null) { unwatch(); return () => null; } function onMount() { ready = true; return unwatch; } return () => { Pragma.useEffect(onMount, []); return value === void 0 ? null : value; }; }); return state[0](); } static as(argument) { const Type = this; const render = typeof argument === "function" ? argument : void 0; class ReactType extends Type { static { this.contextType = Layers; } get props() { return PROPS.get(this); } set props(props) { PROPS.set(this, props); this.set(props); } get context() { return Context.get(this); } set context(context) { if (OUTER.get(this) === context) return; OUTER.set(this, context); context.push(this); } get state() { return this.get(); } set state(_state) {} constructor(nextProps, ...rest) { const { is } = nextProps; const defaults = typeof argument === "object" ? argument : {}; if (rest[0] instanceof Context) rest.shift(); super(nextProps, defaults, is, rest); this.fallback = void 0; PROPS.set(this, nextProps); if (render) { const Self = Render.bind(this, render); this.render = () => Pragma.createElement(Self); } else if (!this.render) this.render = () => provide(this.context, this.props.children || null, this.props.fallback, String(this)); } } Object.defineProperty(ReactType, "name", { value: "React" + this.name }); Object.defineProperty(ReactType.prototype, "isReactComponent", { get: () => true }); return ReactType; } }; function Render(render) { const state = Pragma.useState(() => { event(this); const { context } = this; let ready; let active; watch(this, (current) => { active = current; if (ready) state[1]((x) => x.bind(null)); }); const didMount = () => { ready = true; return () => { context.pop(); this.set(null); }; }; const View = () => render.call(active, this.props, active); return () => { ready = false; Pragma.useEffect(didMount, []); setTimeout(() => ready = true, 0); return provide(context, Pragma.createElement(View), this.props.fallback, String(this)); }; }); return state[0](); } //#endregion export { Pragma, ReactState }; //# sourceMappingURL=state.js.map