mirror of
https://gitee.com/ByteDance/flowgram.ai.git
synced 2025-07-07 17:43:29 +08:00
doc: add form effect examples
This commit is contained in:
parent
8027436e06
commit
b4450db944
@ -16,3 +16,9 @@
|
|||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.field-note{
|
||||||
|
color: #a3a0a0 !important;
|
||||||
|
font-size: 12px;
|
||||||
|
margin: 6px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,15 +7,18 @@ interface FieldWrapperProps {
|
|||||||
title: string;
|
title: string;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
error?: string;
|
error?: string;
|
||||||
|
note?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FieldWrapper = ({ required, title, children, error }: FieldWrapperProps) => (
|
export const FieldWrapper = ({ required, title, children, error, note }: FieldWrapperProps) => (
|
||||||
<div className="field-wrapper">
|
<div className="field-wrapper">
|
||||||
<div className="field-title">
|
<div className="field-title">
|
||||||
{title}
|
{title}
|
||||||
|
{note ? <p className="field-note">{note}</p> : null}
|
||||||
{required ? <span className="required">*</span> : null}
|
{required ? <span className="required">*</span> : null}
|
||||||
</div>
|
</div>
|
||||||
{children}
|
{children}
|
||||||
<p className="error-message">{error}</p>
|
<p className="error-message">{error}</p>
|
||||||
|
{note ? <br /> : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,22 +1,25 @@
|
|||||||
export const fieldWrapperTs = `import React from 'react';
|
export const fieldWrapperTs = `import React from 'react';
|
||||||
|
|
||||||
import './index.css';
|
import './field-wrapper.css';
|
||||||
|
|
||||||
interface FieldWrapperProps {
|
interface FieldWrapperProps {
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
title: string;
|
title: string;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
error?: string;
|
error?: string;
|
||||||
|
note?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FieldWrapper = ({ required, title, children, error }: FieldWrapperProps) => (
|
export const FieldWrapper = ({ required, title, children, error, note }: FieldWrapperProps) => (
|
||||||
<div className="field-wrapper">
|
<div className="field-wrapper">
|
||||||
<div className="field-title">
|
<div className="field-title">
|
||||||
{title}
|
{title}
|
||||||
|
{note ? <p className="field-note">{note}</p> : null}
|
||||||
{required ? <span className="required">*</span> : null}
|
{required ? <span className="required">*</span> : null}
|
||||||
</div>
|
</div>
|
||||||
{children}
|
{children}
|
||||||
<p className="error-message">{error}</p>
|
<p className="error-message">{error}</p>
|
||||||
|
{note ? <br /> : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
`;
|
`;
|
||||||
@ -38,4 +41,25 @@ export const fieldWrapperCss = `.error-message {
|
|||||||
.field-title {
|
.field-title {
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.field-note{
|
||||||
|
color: #a3a0a0 !important;
|
||||||
|
font-size: 12px;
|
||||||
|
margin: 6px 0;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const defaultInitialDataTs = `import { WorkflowJSON } from '@flowgram.ai/free-layout-editor';
|
||||||
|
|
||||||
|
export const DEFAULT_INITIAL_DATA: WorkflowJSON = {
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
id: 'node_0',
|
||||||
|
type: 'custom',
|
||||||
|
meta: {
|
||||||
|
position: { x: 400, y: 0 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
edges: [],
|
||||||
|
};`;
|
||||||
|
|||||||
@ -14,7 +14,7 @@ interface EditorProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const Editor = ({ registry, initialData }: EditorProps) => {
|
export const Editor = ({ registry, initialData }: EditorProps) => {
|
||||||
const editorProps = useEditorProps({ registry, initialData });
|
const editorProps = useEditorProps({ registries: [registry], initialData });
|
||||||
return (
|
return (
|
||||||
<FreeLayoutEditorProvider {...editorProps}>
|
<FreeLayoutEditorProvider {...editorProps}>
|
||||||
<div className="demo-free-container">
|
<div className="demo-free-container">
|
||||||
|
|||||||
@ -3,4 +3,4 @@ export { FieldTitle, FieldWrapper } from './components';
|
|||||||
export { DEFAULT_FORM_META } from './form-meta';
|
export { DEFAULT_FORM_META } from './form-meta';
|
||||||
export { DEFAULT_DEMO_REGISTRY } from './node-registries';
|
export { DEFAULT_DEMO_REGISTRY } from './node-registries';
|
||||||
export { DEFAULT_INITIAL_DATA } from './initial-data';
|
export { DEFAULT_INITIAL_DATA } from './initial-data';
|
||||||
export { fieldWrapperTs, fieldWrapperCss } from './constant';
|
export { fieldWrapperTs, fieldWrapperCss, defaultInitialDataTs } from './constant';
|
||||||
|
|||||||
@ -5,4 +5,4 @@ export { FreeLayoutSimple } from './free-layout-simple';
|
|||||||
export { FreeLayoutSimplePreview } from './free-layout-simple/preview';
|
export { FreeLayoutSimplePreview } from './free-layout-simple/preview';
|
||||||
export { FixedLayoutSimple } from './fixed-layout-simple';
|
export { FixedLayoutSimple } from './fixed-layout-simple';
|
||||||
export { FixedLayoutSimplePreview } from './fixed-layout-simple/preview';
|
export { FixedLayoutSimplePreview } from './fixed-layout-simple/preview';
|
||||||
export { NodeFormBasicPreview } from './form-basic/preview.tsx';
|
export { NodeFormBasicPreview, NodeFormEffectPreview } from './node-form';
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
import {
|
import {
|
||||||
DEFAULT_DEMO_REGISTRY,
|
DEFAULT_DEMO_REGISTRY,
|
||||||
DEFAULT_INITIAL_DATA,
|
DEFAULT_INITIAL_DATA,
|
||||||
|
defaultInitialDataTs,
|
||||||
fieldWrapperCss,
|
fieldWrapperCss,
|
||||||
fieldWrapperTs,
|
fieldWrapperTs,
|
||||||
} from '@flowgram.ai/demo-node-form';
|
} from '@flowgram.ai/demo-node-form';
|
||||||
|
|
||||||
import { PreviewEditor } from '../preview-editor';
|
import { PreviewEditor } from '../preview-editor';
|
||||||
import { Editor } from '.';
|
import { Editor } from './editor';
|
||||||
|
|
||||||
const registryCode = {
|
const registryCode = {
|
||||||
code: `import {
|
code: `import {
|
||||||
@ -71,28 +72,10 @@ export const nodeRegistry: WorkflowNodeRegistry = {
|
|||||||
active: true,
|
active: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialDataCode = {
|
|
||||||
code: `import { WorkflowJSON } from '@flowgram.ai/free-layout-editor';
|
|
||||||
|
|
||||||
export const DEFAULT_INITIAL_DATA: WorkflowJSON = {
|
|
||||||
nodes: [
|
|
||||||
{
|
|
||||||
id: 'node_0',
|
|
||||||
type: 'custom',
|
|
||||||
meta: {
|
|
||||||
position: { x: 400, y: 0 },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
edges: [],
|
|
||||||
};`,
|
|
||||||
active: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const NodeFormBasicPreview = () => {
|
export const NodeFormBasicPreview = () => {
|
||||||
const files = {
|
const files = {
|
||||||
'node-registry.tsx': registryCode,
|
'node-registry.tsx': registryCode,
|
||||||
'initial-data.ts': initialDataCode,
|
'initial-data.ts': { code: defaultInitialDataTs, active: true },
|
||||||
'field-wrapper.tsx': { code: fieldWrapperTs, active: true },
|
'field-wrapper.tsx': { code: fieldWrapperTs, active: true },
|
||||||
'field-wrapper.css': { code: fieldWrapperCss, active: true },
|
'field-wrapper.css': { code: fieldWrapperCss, active: true },
|
||||||
};
|
};
|
||||||
82
apps/docs/components/node-form/effect/node-registry.tsx
Normal file
82
apps/docs/components/node-form/effect/node-registry.tsx
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import {
|
||||||
|
DataEvent,
|
||||||
|
EffectProps,
|
||||||
|
Field,
|
||||||
|
FieldRenderProps,
|
||||||
|
FormMeta,
|
||||||
|
ValidateTrigger,
|
||||||
|
WorkflowNodeRegistry,
|
||||||
|
} from '@flowgram.ai/free-layout-editor';
|
||||||
|
import { FieldWrapper } from '@flowgram.ai/demo-node-form';
|
||||||
|
import { Input } from '@douyinfe/semi-ui';
|
||||||
|
import '../index.css';
|
||||||
|
|
||||||
|
const render = () => (
|
||||||
|
<div className="demo-node-content">
|
||||||
|
<div className="demo-node-title">Effect Examples</div>
|
||||||
|
<Field name="field1">
|
||||||
|
{({ field }: FieldRenderProps<string>) => (
|
||||||
|
<FieldWrapper
|
||||||
|
title="Basic effect"
|
||||||
|
note={'The following field will console.log field value on value change'}
|
||||||
|
>
|
||||||
|
<Input size={'small'} {...field} />
|
||||||
|
</FieldWrapper>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field name="field2">
|
||||||
|
{({ field }: FieldRenderProps<string>) => (
|
||||||
|
<FieldWrapper
|
||||||
|
title="Control other fields"
|
||||||
|
note={'The following field will change Field 3 value on value change'}
|
||||||
|
>
|
||||||
|
<Input size={'small'} {...field} />
|
||||||
|
</FieldWrapper>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
<Field name="field3">
|
||||||
|
{({ field }: FieldRenderProps<string>) => (
|
||||||
|
<FieldWrapper title="Controlled by other fields">
|
||||||
|
<Input size={'small'} {...field} />
|
||||||
|
</FieldWrapper>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
interface FormData {
|
||||||
|
field1: string;
|
||||||
|
field2: string;
|
||||||
|
field3: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formMeta: FormMeta<FormData> = {
|
||||||
|
render,
|
||||||
|
validateTrigger: ValidateTrigger.onChange,
|
||||||
|
effect: {
|
||||||
|
field1: [
|
||||||
|
{
|
||||||
|
event: DataEvent.onValueChange,
|
||||||
|
effect: ({ value }: EffectProps<string, FormData>) => {
|
||||||
|
console.log('field1 value:', value);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
field2: [
|
||||||
|
{
|
||||||
|
event: DataEvent.onValueChange,
|
||||||
|
effect: ({ value, form }: EffectProps<string, FormData>) => {
|
||||||
|
form.setValueIn('field3', 'field2 value is ' + value);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const nodeRegistry: WorkflowNodeRegistry = {
|
||||||
|
type: 'custom',
|
||||||
|
meta: {},
|
||||||
|
defaultPorts: [{ type: 'output' }, { type: 'input' }],
|
||||||
|
formMeta,
|
||||||
|
};
|
||||||
112
apps/docs/components/node-form/effect/preview.tsx
Normal file
112
apps/docs/components/node-form/effect/preview.tsx
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import {
|
||||||
|
DEFAULT_INITIAL_DATA,
|
||||||
|
defaultInitialDataTs,
|
||||||
|
fieldWrapperCss,
|
||||||
|
fieldWrapperTs,
|
||||||
|
} from '@flowgram.ai/demo-node-form';
|
||||||
|
|
||||||
|
import { Editor } from '../editor.tsx';
|
||||||
|
import { PreviewEditor } from '../../preview-editor.tsx';
|
||||||
|
import { nodeRegistry } from './node-registry.tsx';
|
||||||
|
|
||||||
|
const nodeRegistryFile = {
|
||||||
|
code: `import {
|
||||||
|
DataEvent,
|
||||||
|
EffectProps,
|
||||||
|
Field,
|
||||||
|
FieldRenderProps,
|
||||||
|
FormMeta,
|
||||||
|
ValidateTrigger,
|
||||||
|
WorkflowNodeRegistry,
|
||||||
|
} from '@flowgram.ai/free-layout-editor';
|
||||||
|
import { FieldWrapper } from '@flowgram.ai/demo-node-form';
|
||||||
|
import { Input } from '@douyinfe/semi-ui';
|
||||||
|
import '../index.css';
|
||||||
|
|
||||||
|
const render = () => (
|
||||||
|
<div className="demo-node-content">
|
||||||
|
<div className="demo-node-title">Effect Examples</div>
|
||||||
|
<Field name="field1">
|
||||||
|
{({ field }: FieldRenderProps<string>) => (
|
||||||
|
<FieldWrapper
|
||||||
|
title="Basic effect"
|
||||||
|
note={'The following field will console.log field value on value change'}
|
||||||
|
>
|
||||||
|
<Input size={'small'} {...field} />
|
||||||
|
</FieldWrapper>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field name="field2">
|
||||||
|
{({ field }: FieldRenderProps<string>) => (
|
||||||
|
<FieldWrapper
|
||||||
|
title="Control other fields"
|
||||||
|
note={'The following field will change Field 3 value on value change'}
|
||||||
|
>
|
||||||
|
<Input size={'small'} {...field} />
|
||||||
|
</FieldWrapper>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
<Field name="field3">
|
||||||
|
{({ field }: FieldRenderProps<string>) => (
|
||||||
|
<FieldWrapper title="Controlled by other fields">
|
||||||
|
<Input size={'small'} {...field} />
|
||||||
|
</FieldWrapper>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
interface FormData {
|
||||||
|
field1: string;
|
||||||
|
field2: string;
|
||||||
|
field3: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formMeta: FormMeta<FormData> = {
|
||||||
|
render,
|
||||||
|
validateTrigger: ValidateTrigger.onChange,
|
||||||
|
effect: {
|
||||||
|
field1: [
|
||||||
|
{
|
||||||
|
event: DataEvent.onValueChange,
|
||||||
|
effect: ({ value }: EffectProps<string, FormData>) => {
|
||||||
|
console.log('field1 value:', value);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
field2: [
|
||||||
|
{
|
||||||
|
event: DataEvent.onValueChange,
|
||||||
|
effect: ({ value, form }: EffectProps<string, FormData>) => {
|
||||||
|
form.setValueIn('field3', 'field2 value is ' + value);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const nodeRegistry: WorkflowNodeRegistry = {
|
||||||
|
type: 'custom',
|
||||||
|
meta: {},
|
||||||
|
defaultPorts: [{ type: 'output' }, { type: 'input' }],
|
||||||
|
formMeta,
|
||||||
|
};
|
||||||
|
|
||||||
|
`,
|
||||||
|
active: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NodeFormEffectPreview = () => {
|
||||||
|
const files = {
|
||||||
|
'node-registry.tsx': nodeRegistryFile,
|
||||||
|
'initial-data.ts': { code: defaultInitialDataTs, active: true },
|
||||||
|
'field-wrapper.tsx': { code: fieldWrapperTs, active: true },
|
||||||
|
'field-wrapper.css': { code: fieldWrapperCss, active: true },
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<PreviewEditor files={files} previewStyle={{ height: 500 }} editorStyle={{ height: 500 }}>
|
||||||
|
<Editor registry={nodeRegistry} initialData={DEFAULT_INITIAL_DATA} />
|
||||||
|
</PreviewEditor>
|
||||||
|
);
|
||||||
|
};
|
||||||
12
apps/docs/components/node-form/index.css
Normal file
12
apps/docs/components/node-form/index.css
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
.demo-node-content {
|
||||||
|
padding: 8px 12px;
|
||||||
|
flex-grow: 1;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-node-title {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
width: 100%;
|
||||||
|
margin: 4px 0px 12px 0px;
|
||||||
|
}
|
||||||
2
apps/docs/components/node-form/index.ts
Normal file
2
apps/docs/components/node-form/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export { NodeFormBasicPreview } from './basic-preview';
|
||||||
|
export { NodeFormEffectPreview } from './effect/preview';
|
||||||
@ -1,3 +1,4 @@
|
|||||||
[
|
[
|
||||||
"basic"
|
"basic",
|
||||||
|
"effect"
|
||||||
]
|
]
|
||||||
|
|||||||
10
apps/docs/src/zh/examples/node-form/effect.mdx
Normal file
10
apps/docs/src/zh/examples/node-form/effect.mdx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
outline: false
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
# 表单项变更副作用 ( effect)
|
||||||
|
|
||||||
|
import { NodeFormEffectPreview } from '../../../../components';
|
||||||
|
|
||||||
|
<NodeFormEffectPreview />
|
||||||
@ -51,14 +51,18 @@ export enum DataEvent {
|
|||||||
|
|
||||||
export type EffectReturn = () => void;
|
export type EffectReturn = () => void;
|
||||||
|
|
||||||
export type Effect<TFieldValue = any, TFormValues = any> = (props: {
|
export interface EffectProps<TFieldValue = any, TFormValues = any> {
|
||||||
name: FieldName;
|
name: FieldName;
|
||||||
value: TFieldValue;
|
value: TFieldValue;
|
||||||
prevValue?: TFieldValue;
|
prevValue?: TFieldValue;
|
||||||
formValues: TFormValues;
|
formValues: TFormValues;
|
||||||
form: IForm;
|
form: IForm;
|
||||||
context: NodeContext;
|
context: NodeContext;
|
||||||
}) => void | EffectReturn;
|
}
|
||||||
|
|
||||||
|
export type Effect<TFieldValue = any, TFormValues = any> = (
|
||||||
|
props: EffectProps<TFieldValue, TFormValues>
|
||||||
|
) => void | EffectReturn;
|
||||||
|
|
||||||
export type ArrayAppendEffect<TFieldValue = any, TFormValues = any> = (props: {
|
export type ArrayAppendEffect<TFieldValue = any, TFormValues = any> = (props: {
|
||||||
index: number;
|
index: number;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user