mirror of
https://gitee.com/ByteDance/flowgram.ai.git
synced 2025-07-07 17:43:29 +08:00
refactor(container): allow user to customize render content component
This commit is contained in:
parent
429164671e
commit
088368d48c
@ -38,7 +38,9 @@ export const BaseNode = ({ node }: { node: FlowNodeEntity }) => {
|
|||||||
outline: form?.state.invalid ? '1px solid red' : 'none',
|
outline: form?.state.invalid ? '1px solid red' : 'none',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<NodeRenderContext.Provider value={{}}>{form?.render()}</NodeRenderContext.Provider>
|
<NodeRenderContext.Provider value={nodeRender}>
|
||||||
|
{form?.render()}
|
||||||
|
</NodeRenderContext.Provider>
|
||||||
</BaseNodeStyle>
|
</BaseNodeStyle>
|
||||||
</WorkflowNodeRenderer>
|
</WorkflowNodeRenderer>
|
||||||
</ConfigProvider>
|
</ConfigProvider>
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
import { useNodeRender } from '@flowgram.ai/free-layout-editor';
|
||||||
|
import { ContainerNodeForm } from '@flowgram.ai/free-container-plugin';
|
||||||
|
|
||||||
|
import { NodeRenderContext } from '../../context';
|
||||||
|
|
||||||
|
export const ContainerNodeContent = () => {
|
||||||
|
const nodeRender = useNodeRender();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NodeRenderContext.Provider value={nodeRender}>
|
||||||
|
<ContainerNodeForm />;
|
||||||
|
</NodeRenderContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,3 +1,4 @@
|
|||||||
export * from './base-node';
|
export * from './base-node';
|
||||||
export * from './line-add-button';
|
export * from './line-add-button';
|
||||||
export * from './node-panel';
|
export * from './node-panel';
|
||||||
|
export * from './container-content';
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
interface INodeRenderContext {}
|
import type { NodeRenderReturnType } from '@flowgram.ai/free-layout-editor';
|
||||||
|
|
||||||
|
interface INodeRenderContext extends NodeRenderReturnType {}
|
||||||
|
|
||||||
/** 业务自定义节点上下文 */
|
/** 业务自定义节点上下文 */
|
||||||
export const NodeRenderContext = React.createContext<INodeRenderContext>({});
|
export const NodeRenderContext = React.createContext<INodeRenderContext>({} as INodeRenderContext);
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { FlowNodeRegistry, useNodeRender } from '@flowgram.ai/free-layout-editor';
|
import { FlowNodeRegistry } from '@flowgram.ai/free-layout-editor';
|
||||||
|
|
||||||
|
import { useNodeRenderContext } from '../../hooks';
|
||||||
import { FormTitleDescription, FormWrapper } from './styles';
|
import { FormTitleDescription, FormWrapper } from './styles';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -9,7 +10,7 @@ import { FormTitleDescription, FormWrapper } from './styles';
|
|||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
export function FormContent(props: { children?: React.ReactNode }) {
|
export function FormContent(props: { children?: React.ReactNode }) {
|
||||||
const { expanded, node } = useNodeRender();
|
const { expanded, node } = useNodeRenderContext();
|
||||||
const registry = node.getNodeRegistry<FlowNodeRegistry>();
|
const registry = node.getNodeRegistry<FlowNodeRegistry>();
|
||||||
return (
|
return (
|
||||||
<FormWrapper>
|
<FormWrapper>
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import {
|
|||||||
Field,
|
Field,
|
||||||
FieldRenderProps,
|
FieldRenderProps,
|
||||||
useClientContext,
|
useClientContext,
|
||||||
useNodeRender,
|
|
||||||
useService,
|
useService,
|
||||||
} from '@flowgram.ai/free-layout-editor';
|
} from '@flowgram.ai/free-layout-editor';
|
||||||
import { NodeIntoContainerService } from '@flowgram.ai/free-container-plugin';
|
import { NodeIntoContainerService } from '@flowgram.ai/free-container-plugin';
|
||||||
@ -14,6 +13,7 @@ import { IconMore } from '@douyinfe/semi-icons';
|
|||||||
|
|
||||||
import { Feedback } from '../feedback';
|
import { Feedback } from '../feedback';
|
||||||
import { FlowNodeRegistry } from '../../typings';
|
import { FlowNodeRegistry } from '../../typings';
|
||||||
|
import { useNodeRenderContext } from '../../hooks';
|
||||||
import { getIcon } from './utils';
|
import { getIcon } from './utils';
|
||||||
import { Header, Operators, Title } from './styles';
|
import { Header, Operators, Title } from './styles';
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ const { Text } = Typography;
|
|||||||
|
|
||||||
function DropdownButton() {
|
function DropdownButton() {
|
||||||
const [key, setKey] = useState(0);
|
const [key, setKey] = useState(0);
|
||||||
const { node, deleteNode } = useNodeRender();
|
const { node, deleteNode } = useNodeRenderContext();
|
||||||
const clientContext = useClientContext();
|
const clientContext = useClientContext();
|
||||||
const registry = node.getNodeRegistry<FlowNodeRegistry>();
|
const registry = node.getNodeRegistry<FlowNodeRegistry>();
|
||||||
const nodeIntoContainerService = useService<NodeIntoContainerService>(NodeIntoContainerService);
|
const nodeIntoContainerService = useService<NodeIntoContainerService>(NodeIntoContainerService);
|
||||||
@ -76,7 +76,7 @@ function DropdownButton() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function FormHeader() {
|
export function FormHeader() {
|
||||||
const { node, readonly } = useNodeRender();
|
const { node, readonly } = useNodeRenderContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Header>
|
<Header>
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
import { Field, useNodeRender } from '@flowgram.ai/free-layout-editor';
|
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||||
|
|
||||||
import { FxExpression } from '../fx-expression';
|
import { FxExpression } from '../fx-expression';
|
||||||
import { FormItem } from '../form-item';
|
import { FormItem } from '../form-item';
|
||||||
import { Feedback } from '../feedback';
|
import { Feedback } from '../feedback';
|
||||||
import { JsonSchema } from '../../typings';
|
import { JsonSchema } from '../../typings';
|
||||||
|
import { useNodeRenderContext } from '../../hooks';
|
||||||
|
|
||||||
export function FormInputs() {
|
export function FormInputs() {
|
||||||
const { readonly } = useNodeRender();
|
const { readonly } = useNodeRenderContext();
|
||||||
return (
|
return (
|
||||||
<Field<JsonSchema> name="inputs">
|
<Field<JsonSchema> name="inputs">
|
||||||
{({ field: inputsField }) => {
|
{({ field: inputsField }) => {
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
import { useNodeRender } from '@flowgram.ai/free-layout-editor';
|
|
||||||
import { Button } from '@douyinfe/semi-ui';
|
import { Button } from '@douyinfe/semi-ui';
|
||||||
import { IconPlus } from '@douyinfe/semi-icons';
|
import { IconPlus } from '@douyinfe/semi-icons';
|
||||||
|
|
||||||
import { JsonSchema } from '../../typings';
|
import { JsonSchema } from '../../typings';
|
||||||
|
import { useNodeRenderContext } from '../../hooks';
|
||||||
import { PropertyEdit } from './property-edit';
|
import { PropertyEdit } from './property-edit';
|
||||||
|
|
||||||
export interface PropertiesEditProps {
|
export interface PropertiesEditProps {
|
||||||
@ -15,7 +15,7 @@ export interface PropertiesEditProps {
|
|||||||
|
|
||||||
export const PropertiesEdit: React.FC<PropertiesEditProps> = (props) => {
|
export const PropertiesEdit: React.FC<PropertiesEditProps> = (props) => {
|
||||||
const value = (props.value || {}) as Record<string, JsonSchema>;
|
const value = (props.value || {}) as Record<string, JsonSchema>;
|
||||||
const { readonly } = useNodeRender();
|
const { readonly } = useNodeRenderContext();
|
||||||
const [newProperty, updateNewPropertyFromCache] = useState<{ key: string; value: JsonSchema }>({
|
const [newProperty, updateNewPropertyFromCache] = useState<{ key: string; value: JsonSchema }>({
|
||||||
key: '',
|
key: '',
|
||||||
value: { type: 'string' },
|
value: { type: 'string' },
|
||||||
|
|||||||
@ -1 +1,2 @@
|
|||||||
export { useEditorProps } from './use-editor-props';
|
export { useEditorProps } from './use-editor-props';
|
||||||
|
export { useNodeRenderContext } from './use-node-render-context';
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import { createSyncVariablePlugin } from '../plugins';
|
|||||||
import { defaultFormMeta } from '../nodes/default-form-meta';
|
import { defaultFormMeta } from '../nodes/default-form-meta';
|
||||||
import { SelectorBoxPopover } from '../components/selector-box-popover';
|
import { SelectorBoxPopover } from '../components/selector-box-popover';
|
||||||
import { BaseNode, LineAddButton, NodePanel } from '../components';
|
import { BaseNode, LineAddButton, NodePanel } from '../components';
|
||||||
|
import { ContainerNodeContent } from '../components';
|
||||||
|
|
||||||
export function useEditorProps(
|
export function useEditorProps(
|
||||||
initialData: FlowDocumentJSON,
|
initialData: FlowDocumentJSON,
|
||||||
@ -200,7 +201,9 @@ export function useEditorProps(
|
|||||||
createFreeNodePanelPlugin({
|
createFreeNodePanelPlugin({
|
||||||
renderer: NodePanel,
|
renderer: NodePanel,
|
||||||
}),
|
}),
|
||||||
createContainerNodePlugin({}),
|
createContainerNodePlugin({
|
||||||
|
renderContent: <ContainerNodeContent />,
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
[]
|
[]
|
||||||
|
|||||||
@ -0,0 +1,5 @@
|
|||||||
|
import { useContext } from 'react';
|
||||||
|
|
||||||
|
import { NodeRenderContext } from '../context';
|
||||||
|
|
||||||
|
export const useNodeRenderContext = () => useContext(NodeRenderContext);
|
||||||
@ -1,9 +1,10 @@
|
|||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import { Field, FieldArray, useNodeRender } from '@flowgram.ai/free-layout-editor';
|
import { Field, FieldArray } from '@flowgram.ai/free-layout-editor';
|
||||||
import { Button } from '@douyinfe/semi-ui';
|
import { Button } from '@douyinfe/semi-ui';
|
||||||
import { IconPlus, IconCrossCircleStroked } from '@douyinfe/semi-icons';
|
import { IconPlus, IconCrossCircleStroked } from '@douyinfe/semi-icons';
|
||||||
|
|
||||||
import { FlowLiteralValueSchema, FlowRefValueSchema } from '../../../typings';
|
import { FlowLiteralValueSchema, FlowRefValueSchema } from '../../../typings';
|
||||||
|
import { useNodeRenderContext } from '../../../hooks';
|
||||||
import { FxExpression } from '../../../form-components/fx-expression';
|
import { FxExpression } from '../../../form-components/fx-expression';
|
||||||
import { FormItem } from '../../../form-components';
|
import { FormItem } from '../../../form-components';
|
||||||
import { Feedback } from '../../../form-components';
|
import { Feedback } from '../../../form-components';
|
||||||
@ -15,7 +16,7 @@ interface ConditionValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function ConditionInputs() {
|
export function ConditionInputs() {
|
||||||
const { readonly } = useNodeRender();
|
const { readonly } = useNodeRenderContext();
|
||||||
return (
|
return (
|
||||||
<FieldArray name="inputsValues.conditions">
|
<FieldArray name="inputsValues.conditions">
|
||||||
{({ field }) => (
|
{({ field }) => (
|
||||||
|
|||||||
@ -0,0 +1,5 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { NodeRenderReturnType } from './typings';
|
||||||
|
|
||||||
|
export const NodeRenderContext = React.createContext<NodeRenderReturnType>({} as any);
|
||||||
@ -1,3 +1,4 @@
|
|||||||
export { ContainerNodeRenderKey } from './constant';
|
export { ContainerNodeRenderKey } from './constant';
|
||||||
export { ContainerNodeRender } from './render';
|
export { ContainerNodeRender } from './render';
|
||||||
export type { ContainerNodeMetaRenderProps, ContainerNodeRenderProps } from './type';
|
export type { ContainerNodeMetaRenderProps, ContainerNodeRenderProps } from './type';
|
||||||
|
export * from './components';
|
||||||
|
|||||||
@ -7,16 +7,13 @@ import {
|
|||||||
ContainerNodePorts,
|
ContainerNodePorts,
|
||||||
ContainerNodeBorder,
|
ContainerNodeBorder,
|
||||||
ContainerNodeContainer,
|
ContainerNodeContainer,
|
||||||
ContainerNodeForm,
|
|
||||||
} from './components';
|
} from './components';
|
||||||
|
|
||||||
export const ContainerNodeRender: FC<ContainerNodeRenderProps> = () => (
|
export const ContainerNodeRender: FC<ContainerNodeRenderProps> = ({ content }) => (
|
||||||
<ContainerNodeContainer>
|
<ContainerNodeContainer>
|
||||||
<ContainerNodeBackground />
|
<ContainerNodeBackground />
|
||||||
<ContainerNodeBorder />
|
<ContainerNodeBorder />
|
||||||
<ContainerNodeHeader>
|
<ContainerNodeHeader>{content}</ContainerNodeHeader>
|
||||||
<ContainerNodeForm />
|
|
||||||
</ContainerNodeHeader>
|
|
||||||
<ContainerNodePorts />
|
<ContainerNodePorts />
|
||||||
</ContainerNodeContainer>
|
</ContainerNodeContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
import type { WorkflowNodeEntity } from '@flowgram.ai/free-layout-core';
|
import type { WorkflowNodeEntity } from '@flowgram.ai/free-layout-core';
|
||||||
|
|
||||||
export interface ContainerNodeMetaRenderProps {
|
export interface ContainerNodeMetaRenderProps {
|
||||||
@ -13,4 +15,5 @@ export interface ContainerNodeMetaRenderProps {
|
|||||||
|
|
||||||
export interface ContainerNodeRenderProps {
|
export interface ContainerNodeRenderProps {
|
||||||
node: WorkflowNodeEntity;
|
node: WorkflowNodeEntity;
|
||||||
|
content?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +1,27 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
import { FlowRendererRegistry } from '@flowgram.ai/renderer';
|
import { FlowRendererRegistry } from '@flowgram.ai/renderer';
|
||||||
import { definePluginCreator } from '@flowgram.ai/core';
|
import { definePluginCreator } from '@flowgram.ai/core';
|
||||||
|
|
||||||
import type { WorkflowContainerPluginOptions } from './type';
|
import type { WorkflowContainerPluginOptions } from './type';
|
||||||
import { NodeIntoContainerService } from './node-into-container';
|
import { NodeIntoContainerService } from './node-into-container';
|
||||||
import { ContainerNodeRenderKey, ContainerNodeRender } from './container-node-render';
|
import {
|
||||||
|
ContainerNodeRenderKey,
|
||||||
|
ContainerNodeRender,
|
||||||
|
ContainerNodeRenderProps,
|
||||||
|
} from './container-node-render';
|
||||||
|
|
||||||
export const createContainerNodePlugin = definePluginCreator<WorkflowContainerPluginOptions>({
|
export const createContainerNodePlugin = definePluginCreator<WorkflowContainerPluginOptions>({
|
||||||
onBind: ({ bind }) => {
|
onBind: ({ bind }) => {
|
||||||
bind(NodeIntoContainerService).toSelf().inSingletonScope();
|
bind(NodeIntoContainerService).toSelf().inSingletonScope();
|
||||||
},
|
},
|
||||||
onInit(ctx) {
|
onInit(ctx, options) {
|
||||||
ctx.get(NodeIntoContainerService).init();
|
ctx.get(NodeIntoContainerService).init();
|
||||||
|
|
||||||
const registry = ctx.get<FlowRendererRegistry>(FlowRendererRegistry);
|
const registry = ctx.get<FlowRendererRegistry>(FlowRendererRegistry);
|
||||||
registry.registerReactComponent(ContainerNodeRenderKey, ContainerNodeRender);
|
registry.registerReactComponent(ContainerNodeRenderKey, (props: ContainerNodeRenderProps) => (
|
||||||
|
<ContainerNodeRender {...props} content={options.renderContent} />
|
||||||
|
));
|
||||||
},
|
},
|
||||||
onReady(ctx, options) {
|
onReady(ctx, options) {
|
||||||
if (options.disableNodeIntoContainer !== true) {
|
if (options.disableNodeIntoContainer !== true) {
|
||||||
@ -1,3 +1,6 @@
|
|||||||
|
import type { ReactNode } from 'react';
|
||||||
|
|
||||||
export interface WorkflowContainerPluginOptions {
|
export interface WorkflowContainerPluginOptions {
|
||||||
disableNodeIntoContainer?: boolean;
|
disableNodeIntoContainer?: boolean;
|
||||||
|
renderContent?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user