UNPKG

@wener/console

Version:

Base console UI toolkit

166 lines (165 loc) 4.81 kB
import React, { createContext, forwardRef, Fragment, lazy, useContext, useMemo, useRef } from "react"; let _components = []; export function defineComponent({ Component: _Component, load, ...opts }) { { const Component = createComponent({ Component: _Component, load }); // if (Component === Fragment) { // console.warn(`Component ${opts.name} not resolved`); // } const def = { title: opts.title || opts.name, ...opts, Component, metadata: {} }; let last = _components.find((v)=>v.name === def.name); if (last) { console.error(`Component ${def.name} already defined`); // last.schema = def.schema; // last.props = def.props; // last.metadata = def.metadata; } _components.unshift(def); } const name = opts.name; let component = Object.assign(/*#__PURE__*/ forwardRef((props, ref)=>{ return /*#__PURE__*/ React.createElement(ConsumeComponent, { $name: name, ...props, ref: ref }); }), { [ComponentNamePropKey]: name }); return component; } export function getComponents() { return _components; } export const ConsumeComponent = /*#__PURE__*/ forwardRef(({ $name, ...props }, ref)=>{ const [Component] = useComponent($name); return /*#__PURE__*/ React.createElement(Component, { ...props, ref: ref }); }); const ComponentNamePropKey = '$ContextComponentName'; export function createContextComponent(name) { let component = Object.assign(/*#__PURE__*/ forwardRef((props, ref)=>{ return /*#__PURE__*/ React.createElement(ConsumeComponent, { $name: name, ...props, ref: ref }); }), { [ComponentNamePropKey]: name }); component.displayName = `${ComponentNamePropKey}(${name})`; return component; } const RootValue = { get components () { return _components.map((v)=>{ return { provide: v.name, Component: v.Component }; }); }, useComponent: (name)=>resolveComponent(name, RootValue) }; const ComponentContext = /*#__PURE__*/ createContext(RootValue); function resolveName(def) { let name = typeof def === 'string' ? def : def[ComponentNamePropKey]; return { name }; } export function useComponent(comp) { const { useComponent } = useContext(ComponentContext); return useComponent(comp); } export const ComponentProvider = ({ components, children })=>{ const parent = useContext(ComponentContext); const provideRef = useRef(components); const parentRef = useRef(parent); provideRef.current = components; parentRef.current = parent; const val = useMemo(()=>{ return { get parent () { return parentRef.current; }, get components () { return provideRef.current; }, useComponent: (comp)=>{ return resolveComponent(comp, val); } }; }, []); return /*#__PURE__*/ React.createElement(ComponentContext.Provider, { value: val }, children); }; function resolveComponent(comp, obj) { const { name } = resolveName(comp); let cur = obj; let Component = Fragment; let found = false; outer: while(cur){ for (let item of cur.components){ if (resolveName(item.provide).name === name) { Component = createComponent(item); found = true; break outer; } } cur = cur.parent; } if (Component === Fragment || !found) { console.warn(`Component ${name} not found`); } return [ Component, [ { found } ] ]; } function createComponent({ Component, load }) { if (Component) { return Component; } if (load) { return /*#__PURE__*/ lazy(async ()=>{ try { const v = await load(); if ('default' in v) { return v; } if (!v) { throw new Error(`Component not found`); } return { default: v }; } catch (e) { console.error(`Failed to load component`, { load, Component }, e); return { default: Fragment }; } }); } return Fragment; } //# sourceMappingURL=ComponentProvider.js.map