Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | /** * ComponentWidget — dynamically loads and renders a portal component. * * Used as a form field widget with: * `widget: {type: 'component', component: 'portal.page.key', params: {...}}` * * Dispatches `component/${page}` with the configured page key to obtain a * React component, then renders it. Shows a centred spinner while loading. * * Both `component` and `params` values support `${field}` template expressions * resolved against the current form values at mount time. Uses the * blong-template browser engine (Function-constructor based, same syntax as the * server-side trusted engine). */ import type {IWidgetProps} from '@feasibleone/blong'; import {renderAll} from '@feasibleone/blong-template'; import React from 'react'; import {useBlongForm} from '../components/Form/FormContext.js'; import {useBlong} from '../context/BlongContext.js'; import {ProgressSpinner} from '../primereact/index.js'; export function ComponentWidget(widgetProps: IWidgetProps) { const {schema, loading} = widgetProps; const {handler} = useBlong(); const formCtx = useBlongForm(); const page = schema.widget?.component ?? ''; const params = schema.widget?.params; const [errorRender, setErrorRender] = React.useState<Error | null>(null); const [LoadedComponent, setLoadedComponent] = React.useState<React.ComponentType< IWidgetProps > | null>(null); const vars = formCtx?.getValues(); React.useEffect(() => { if (!page || loading) return; let resolvedPage: string; let resolvedParams: Record<string, unknown> = {}; try { resolvedPage = renderAll(page, vars ?? {}); if (!resolvedPage) return; resolvedParams = params ? (renderAll(params, vars ?? {}) as Record<string, unknown>) : {}; } catch (error) { // eslint-disable-next-line @eslint-react/set-state-in-effect setErrorRender(error as Error); return; } void (handler[`component/${resolvedPage}`]({ ...resolvedParams, }, {}) as Promise<React.ComponentType | null>)?.then(component => { if (component) { setErrorRender(null); setLoadedComponent(() => component as React.ComponentType<IWidgetProps>); } }); }, [page, params, formCtx, handler, loading, vars]); if (!LoadedComponent) { return ( <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100%', }} > <ProgressSpinner title={errorRender ? errorRender.message : 'Loading...'} /> </div> ); } return <LoadedComponent {...widgetProps} />; } |