chore: import upstream snapshot with attribution
CI / build (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:09:51 +08:00
commit 0232b4e2bb
3528 changed files with 291404 additions and 0 deletions
@@ -0,0 +1,36 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { createDisableDeclarationPlugin } from '@flowgram.ai/form-materials';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const VariableSelector = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.VariableSelector,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
plugins={() => [createDisableDeclarationPlugin()]}
formMeta={{
render: () => (
<>
<FormHeader />
<Field<string[] | undefined> name="variable_selector">
{({ field }) => (
<VariableSelector value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
</>
),
}}
/>
);
@@ -0,0 +1,10 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
.json-schema-color-picker-container {
.semi-colorPicker-popover-defaultChildren {
width: 100%;
}
}
@@ -0,0 +1,114 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import {
ConditionRow,
ConditionRowValueType,
createTypePresetPlugin,
DynamicValueInput,
IFlowConstantRefValue,
type IJsonSchema,
} from '@flowgram.ai/form-materials';
import { ColorPicker } from '@douyinfe/semi-ui';
import { IconColorPalette } from '@douyinfe/semi-icons';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
import './json-schema-preset.css';
const TypeSelector = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.TypeSelector,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
transformInitialNode={{
start_0: (node) => {
node.data.outputs = {
type: 'object',
properties: {
color_output: {
type: 'color',
},
},
};
return node;
},
}}
plugins={() => [
createTypePresetPlugin({
types: [
{
type: 'color',
icon: <IconColorPalette />,
label: 'Color',
ConstantRenderer: ({ value, onChange }) => (
<div className="json-schema-color-picker-container ">
<ColorPicker
alpha={true}
usePopover={true}
value={value ? ColorPicker.colorStringToValue(value) : undefined}
onChange={(_value) => onChange?.(_value.hex)}
/>
</div>
),
conditionRule: {
eq: { type: 'color' },
},
},
],
}),
]}
formMeta={{
render: () => (
<>
<FormHeader />
<b>Type Selector: </b>
<Field<Partial<IJsonSchema> | undefined>
name="type_selector"
defaultValue={{ type: 'color' }}
>
{({ field }) => (
<TypeSelector value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
<br />
<b>DynamicValueInput: </b>
<Field<IFlowConstantRefValue | undefined>
name="dynamic_value_input"
defaultValue={{ type: 'constant', schema: { type: 'color' }, content: '#b5ed0c' }}
>
{({ field }) => (
<DynamicValueInput value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
<br />
<b>Condition: </b>
<Field<ConditionRowValueType | undefined>
name="condition_row"
defaultValue={{
left: { type: 'ref', content: ['start_0', 'color_output'] },
operator: 'eq',
right: { type: 'ref', content: ['start_0', 'color_output'] },
}}
>
{({ field }) => (
<ConditionRow value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
<br />
</>
),
}}
/>
);
@@ -0,0 +1,71 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { AssignValueType } from '@flowgram.ai/form-materials';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const AssignRow = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.AssignRow,
}))
);
export const AssignModeStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<AssignValueType | undefined>
defaultValue={{
operator: 'assign',
left: { type: 'ref', content: ['start_0', 'str'] },
right: { type: 'constant', content: 'Hello World', schema: { type: 'string' } },
}}
name="assign_row"
>
{({ field }) => (
<AssignRow value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
</>
),
}}
/>
);
export const DeclareModeStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<AssignValueType | undefined> name="assign_row">
{({ field }) => (
<AssignRow
value={{
operator: 'declare',
left: 'newVariable',
right: {
type: 'constant',
content: 'Hello World',
schema: { type: 'string' },
},
}}
onChange={(value) => field.onChange(value)}
/>
)}
</Field>
</>
),
}}
/>
);
@@ -0,0 +1,28 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const AssignRows = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.AssignRows,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<AssignRows name="assign_rows" />
</>
),
}}
/>
);
@@ -0,0 +1,171 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field, FlowNodeRegistry } from '@flowgram.ai/free-layout-editor';
import { SubCanvasRender, createContainerNodePlugin } from '@flowgram.ai/free-container-plugin';
import {
provideBatchInputEffect,
createBatchOutputsFormPlugin,
type IFlowRefValue,
DisplayOutputs,
} from '@flowgram.ai/form-materials';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const BatchVariableSelector = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.BatchVariableSelector,
}))
);
const BatchOutputs = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.BatchOutputs,
}))
);
type BatchOutputsValueType = Record<string, IFlowRefValue | undefined>;
const createLoopRegistry = (): FlowNodeRegistry => ({
type: 'custom',
meta: {
isContainer: true,
size: {
width: 500,
height: 260,
},
padding: () => ({
top: 160,
bottom: 40,
left: 50,
right: 50,
}),
},
formMeta: {
render: () => (
<>
<FormHeader />
<div style={{ marginBottom: 16 }}>
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
Loop input (select array variable):
</div>
<Field<IFlowRefValue | undefined>
name="loopFor"
defaultValue={{ type: 'ref', content: ['start_0', 'arr', 'arr_obj'] }}
>
{({ field }) => (
<BatchVariableSelector
style={{ width: '100%' }}
value={field.value?.content}
onChange={(val) => field.onChange({ type: 'ref', content: val })}
/>
)}
</Field>
</div>
<SubCanvasRender offsetY={-100} />
<div style={{ marginBottom: 16 }}>
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
Loop outputs (key-value pairs collected into arrays):
</div>
<Field<BatchOutputsValueType | undefined>
name="loopOutputs"
defaultValue={{
result: { type: 'ref', content: ['variable_0', 'result'] },
count: { type: 'ref', content: ['variable_0', 'count'] },
}}
>
{({ field }) => (
<BatchOutputs
style={{ width: '100%' }}
value={field.value}
onChange={(val) => field.onChange(val)}
/>
)}
</Field>
<div>
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
Generated output variables:
</div>
<DisplayOutputs displayFromScope />
</div>
</div>
</>
),
effect: {
loopFor: provideBatchInputEffect,
},
plugins: [
createBatchOutputsFormPlugin({ outputKey: 'loopOutputs', inferTargetKey: 'outputs' }),
],
},
});
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
height={550}
initialData={{
nodes: [
{
id: 'custom_0',
type: 'custom',
data: {
title: 'Loop',
loopFor: { type: 'ref', content: ['start_0', 'arr', 'arr_obj'] },
},
blocks: [
{
id: 'block_start_0',
type: 'block-start',
data: { title: 'Start' },
meta: { position: { x: 20, y: 0 } },
},
{
id: 'variable_0',
type: 'variable',
data: {
title: 'Variable',
assign: [
{
operator: 'declare',
left: 'result',
right: { type: 'ref', content: ['custom_0_locals', 'item', 'str'] },
},
{
operator: 'declare',
left: 'count',
right: { type: 'ref', content: ['custom_0_locals', 'index'] },
},
],
},
meta: { position: { x: 100, y: 0 } },
},
{
id: 'block_end_0',
type: 'block-end',
data: { title: 'End' },
meta: { position: { x: 360, y: 0 } },
},
],
edges: [
{ sourceNodeID: 'block_start_0', targetNodeID: 'variable_0' },
{ sourceNodeID: 'variable_0', targetNodeID: 'block_end_0' },
],
},
],
edges: [{ sourceNodeID: 'start_0', targetNodeID: 'custom_0' }],
}}
transformRegistry={(props) => ({
...props,
nodeRegistries: [
...(props.nodeRegistries || []).filter((r) => r.type !== 'custom'),
createLoopRegistry(),
],
})}
plugins={(ctx) => [createContainerNodePlugin({})]}
/>
);
@@ -0,0 +1,58 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const BatchVariableSelector = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.BatchVariableSelector,
}))
);
const VariableSelector = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.VariableSelector,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<div style={{ marginBottom: 16 }}>
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
BatchVariableSelector (Array variables only):
</div>
<Field<string[] | undefined> name="batch_variable">
{({ field }) => (
<BatchVariableSelector
value={field.value}
onChange={(value) => field.onChange(value)}
/>
)}
</Field>
</div>
<div>
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
VariableSelector (All variables):
</div>
<Field<string[] | undefined> name="normal_variable">
{({ field }) => (
<VariableSelector value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
</div>
</>
),
}}
/>
);
@@ -0,0 +1,90 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const BlurInput = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.BlurInput,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
filterStartNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<string> name="blur_input" defaultValue="Initial text">
{({ field }) => (
<>
<BlurInput
value={field.value}
onChange={(value) => field.onChange(value)}
placeholder="Please enter text"
/>
<p className="mt-2">Current value: {field.value}</p>
<p className="text-sm text-gray-500">
Note: Value updates after clicking outside the input
</p>
</>
)}
</Field>
</>
),
}}
/>
);
export const PlaceholderStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
filterStartNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<string> name="blur_input_placeholder" defaultValue="">
{({ field }) => (
<>
<BlurInput
value={field.value}
onChange={(value) => field.onChange(value)}
placeholder="This is an input field with placeholder"
/>
<p className="mt-2">Current value: {field.value || 'Empty'}</p>
</>
)}
</Field>
</>
),
}}
/>
);
export const DisabledStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
filterStartNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<string> name="blur_input_disabled" defaultValue="Disabled state text">
{({ field }) => (
<BlurInput value={field.value} onChange={(value) => field.onChange(value)} disabled />
)}
</Field>
</>
),
}}
/>
);
@@ -0,0 +1,60 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const CodeEditor = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.CodeEditor,
}))
);
const defaultTsCode = `// Here, you can retrieve input variables from the node using 'params' and output results using 'ret'.
// 'params' has been correctly injected into the environment.
// Here's an example of getting the value of the parameter named 'input' from the node input:
// const input = params.input;
// Here's an example of outputting a 'ret' object containing multiple data types:
// const ret = { "name": 'Xiaoming', "hobbies": ["Reading", "Traveling"] };
async function main({ params }) {
// Build the output object
const ret = {
key0: params.input + params.input, // Concatenate the input parameter 'input' twice
key1: ["hello", "world"], // Output an array
key2: { // Output an Object
key21: "hi"
},
};
return ret;
}`;
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterStartNode
filterEndNode
height={600}
formMeta={{
render: () => (
<div style={{ width: 500 }}>
<FormHeader />
<Field<string | undefined> name="code_editor" defaultValue={defaultTsCode}>
{({ field }) => (
<CodeEditor
value={field.value}
onChange={(value) => field.onChange(value)}
languageId="typescript"
/>
)}
</Field>
</div>
),
}}
/>
);
@@ -0,0 +1,77 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import type { ConditionOpConfigs, IConditionRule } from '@flowgram.ai/form-materials';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const ConditionRow = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.ConditionRow,
}))
);
const DBConditionRow = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.DBConditionRow,
}))
);
const ConditionProvider = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.ConditionProvider,
}))
);
const OPS: ConditionOpConfigs = {
cop: {
abbreviation: 'C',
label: 'Custom Operator',
},
};
const RULES: Record<string, IConditionRule> = {
string: {
cop: { type: 'string' },
},
};
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<ConditionProvider ops={OPS} rules={RULES}>
<Field<any | undefined> name="condition_row">
{({ field }) => (
<ConditionRow value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
<Field<any | undefined> name="db_condition_row">
{({ field }) => (
<DBConditionRow
options={[
{
label: 'UserName',
value: 'username',
schema: { type: 'string' },
},
]}
value={field.value}
onChange={(value) => field.onChange(value)}
/>
)}
</Field>
</ConditionProvider>
</>
),
}}
/>
);
@@ -0,0 +1,50 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const ConditionRow = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.ConditionRow,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<any | undefined>
name="condition_row"
defaultValue={{
left: {
type: 'ref',
content: ['start_0', 'str'],
},
operator: 'eq',
right: {
type: 'constant',
content: 'Hello World!',
schema: {
type: 'string',
},
},
}}
>
{({ field }) => (
<ConditionRow value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
</>
),
}}
/>
);
@@ -0,0 +1,163 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const ConstantInput = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.ConstantInput,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterStartNode
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
<b>String</b>
<Field<string> name="constant_string" defaultValue="Hello World">
{({ field }) => (
<ConstantInput
value={field.value}
onChange={(value) => field.onChange(value)}
schema={{ type: 'string' }}
/>
)}
</Field>
<b>Enum</b>
<Field<string> name="constant_enum" defaultValue="morning">
{({ field }) => (
<ConstantInput
value={field.value}
onChange={(value) => field.onChange(value)}
schema={{ type: 'string', enum: ['morning', 'afternoon'] }}
/>
)}
</Field>
<b>Number</b>
<Field<number> name="constant_number" defaultValue={42}>
{({ field }) => (
<ConstantInput
value={field.value}
onChange={(value) => field.onChange(value)}
schema={{ type: 'number' }}
/>
)}
</Field>
<b>Boolean</b>
<Field<boolean> name="constant_boolean" defaultValue={true}>
{({ field }) => (
<ConstantInput
value={field.value}
onChange={(value) => field.onChange(value)}
schema={{ type: 'boolean' }}
/>
)}
</Field>
<b>Object</b>
<Field<string>
name="constant_object"
defaultValue={JSON.stringify({ key: 'value', nested: { data: 'test' } })}
>
{({ field }) => (
<ConstantInput
value={field.value}
onChange={(value) => field.onChange(value)}
schema={{ type: 'object' }}
/>
)}
</Field>
<b>Array</b>
<Field<string>
name="constant_array"
defaultValue={JSON.stringify([1, 2, 3, 'four', true])}
>
{({ field }) => (
<ConstantInput
value={field.value}
onChange={(value) => field.onChange(value)}
schema={{ type: 'array' }}
/>
)}
</Field>
</div>
</>
),
}}
/>
);
export const FallbackRendererStory = () => (
<FreeFormMetaStoryBuilder
filterStartNode
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<any>
name="constant_fallback"
defaultValue={{ custom: 'data', type: 'unsupported' }}
>
{({ field }) => (
<ConstantInput
value={field.value}
onChange={(value) => field.onChange(value)}
schema={{ type: 'custom-unsupported-type' }}
fallbackRenderer={({ value, onChange, readonly }) => (
<div style={{ padding: '8px', background: '#f0f0f0', border: '1px dashed #ccc' }}>
<p>Fallback renderer for unsupported type</p>
</div>
)}
/>
)}
</Field>
</>
),
}}
/>
);
export const CustomStrategyStory = () => (
<FreeFormMetaStoryBuilder
filterStartNode
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<string> name="constant_custom" defaultValue="Custom Value">
{({ field }) => (
<ConstantInput
value={field.value}
onChange={(value) => field.onChange(value)}
schema={{ type: 'object' }}
strategies={[
{
hit: (schema) => schema.type === 'object',
Renderer: ({ value, onChange, readonly }) => <p>Object is not supported now</p>,
},
]}
/>
)}
</Field>
</>
),
}}
/>
);
@@ -0,0 +1,77 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const DBConditionRow = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.DBConditionRow,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<any | undefined>
name="db_condition_row"
defaultValue={{
left: 'amount',
operator: 'gt',
right: {
type: 'constant',
content: 1000,
schema: {
type: 'number',
},
},
}}
>
{({ field }) => (
<DBConditionRow
options={[
{
label: 'TransactionID',
value: 'transaction_id',
schema: { type: 'integer' },
},
{
label: 'Amount',
value: 'amount',
schema: { type: 'number' },
},
{
label: 'Description',
value: 'description',
schema: { type: 'string' },
},
{
label: 'Archived',
value: 'archived',
schema: { type: 'boolean' },
},
{
label: 'CreateTime',
value: 'create_time',
schema: { type: 'date-time' },
},
]}
value={field.value}
onChange={(value) => field.onChange(value)}
/>
)}
</Field>
</>
),
}}
/>
);
@@ -0,0 +1,58 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const DynamicValueInput = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.DynamicValueInput,
}))
);
const DisplayFlowValue = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.DisplayFlowValue,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode={true}
transformInitialNode={{
custom_0: (node) => {
node.data.dynamic_value_input = {
type: 'constant',
content: 'Hello World',
};
return node;
},
}}
formMeta={{
render: () => (
<>
<FormHeader />
<Field<any> name="dynamic_value_input">
{({ field }) => (
<DynamicValueInput value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
<br />
<div>
<Field<any> name="dynamic_value_input">
{({ field }) => {
console.log('debugger field value', field);
return <DisplayFlowValue value={field.value} title="Display Flow Value" />;
}}
</Field>
</div>
</>
),
}}
/>
);
@@ -0,0 +1,69 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const InputsValuesTree = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.InputsValuesTree,
}))
);
const DisplayInputsValues = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.DisplayInputsValues,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode={true}
transformInitialNode={{
custom_0: (node) => {
node.data.inputs_values = {
a: {
b: {
type: 'ref',
content: ['start_0', 'str'],
},
c: {
type: 'constant',
content: 'hello',
},
},
d: {
type: 'ref',
content: ['start_0', 'arr', 'arr_str'],
},
e: {
type: 'ref',
content: ['start_0', 'obj'],
},
};
return node;
},
}}
formMeta={{
render: () => (
<>
<FormHeader />
<Field<Record<string, any> | undefined> name="inputs_values">
{({ field }) => (
<InputsValuesTree value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
<br />
<Field<Record<string, any> | undefined> name="inputs_values">
{({ field }) => <DisplayInputsValues value={field.value} />}
</Field>
</>
),
}}
/>
);
@@ -0,0 +1,96 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { provideJsonSchemaOutputs, type IJsonSchema } from '@flowgram.ai/form-materials';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const DisplayOutputs = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.DisplayOutputs,
}))
);
const JsonSchemaEditor = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.JsonSchemaEditor,
}))
);
export const DisplayFromScopeStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
filterStartNode
transformInitialNode={{
custom_0: (node) => {
node.data.outputs = {
type: 'object',
properties: {
result: { type: 'string' },
status: { type: 'number' },
},
};
return node;
},
}}
formMeta={{
render: () => (
<>
<FormHeader />
<Field<IJsonSchema | undefined> name="outputs">
{({ field }) => (
<JsonSchemaEditor value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
<br />
<b>Display Outputs by Scope:</b>
<DisplayOutputs displayFromScope />
</>
),
effect: {
outputs: provideJsonSchemaOutputs,
},
}}
/>
);
export const DisplayFromFieldStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
filterStartNode
transformInitialNode={{
custom_0: (node) => {
node.data.outputs = {
type: 'object',
properties: {
result: { type: 'string' },
status: { type: 'number' },
},
};
return node;
},
}}
formMeta={{
render: () => (
<>
<FormHeader />
<Field<IJsonSchema | undefined> name="outputs">
{({ field }) => (
<JsonSchemaEditor value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
<br />
<b>Display Outputs By Schema</b>
<Field<IJsonSchema | undefined> name="outputs">
{({ field }) => <DisplayOutputs value={field.value} />}
</Field>
</>
),
}}
/>
);
@@ -0,0 +1,59 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const DisplaySchemaTag = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.DisplaySchemaTag,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
filterStartNode
formMeta={{
render: () => (
<>
<FormHeader />
<div>
<DisplaySchemaTag
title="Transaction"
value={{
type: 'object',
properties: {
transaction_id: { type: 'integer' },
amount: { type: 'number' },
description: { type: 'string' },
archived: { type: 'boolean' },
owner: {
type: 'object',
properties: {
id: { type: 'integer' },
username: { type: 'string' },
friends: {
type: 'array',
items: {
type: 'object',
properties: {
id: { type: 'integer' },
username: { type: 'string' },
},
},
},
},
},
},
}}
/>
</div>
</>
),
}}
/>
);
@@ -0,0 +1,56 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const DisplaySchemaTree = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.DisplaySchemaTree,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
filterStartNode
formMeta={{
render: () => (
<>
<FormHeader />
<DisplaySchemaTree
value={{
type: 'object',
properties: {
transaction_id: { type: 'integer' },
amount: { type: 'number' },
description: { type: 'string' },
archived: { type: 'boolean' },
owner: {
type: 'object',
properties: {
id: { type: 'integer' },
username: { type: 'string' },
friends: {
type: 'array',
items: {
type: 'object',
properties: {
id: { type: 'integer' },
username: { type: 'string' },
},
},
},
},
},
},
}}
/>
</>
),
}}
/>
);
@@ -0,0 +1,56 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const DynamicValueInput = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.DynamicValueInput,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<any> name="dynamic_value_input">
{({ field }) => (
<DynamicValueInput value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
</>
),
}}
/>
);
export const WithSchemaStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<any> name="dynamic_value_input">
{({ field }) => (
<DynamicValueInput
value={field.value}
onChange={(value) => field.onChange(value)}
schema={{ type: 'string' }}
/>
)}
</Field>
</>
),
}}
/>
);
@@ -0,0 +1,53 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const InputsValuesTree = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.InputsValuesTree,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<Record<string, any> | undefined>
name="inputs_values"
defaultValue={{
a: {
b: {
type: 'ref',
content: ['start_0', 'str'],
},
c: {
type: 'constant',
content: 'hello',
},
},
d: {
type: 'constant',
content: '{ "a": "b"}',
schema: { type: 'object' },
},
}}
>
{({ field }) => (
<InputsValuesTree value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
</>
),
}}
/>
);
@@ -0,0 +1,74 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const InputsValues = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.InputsValues,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<Record<string, any> | undefined>
name="inputs_values"
defaultValue={{
a: {
type: 'ref',
content: ['start_0', 'str'],
},
}}
>
{({ field }) => (
<InputsValues value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
</>
),
}}
/>
);
export const WithSchemaStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<Record<string, any> | undefined>
name="inputs_values"
defaultValue={{
a: {
type: 'ref',
content: ['start_0', 'str'],
},
}}
>
{({ field }) => (
<InputsValues
value={field.value}
onChange={(value) => field.onChange(value)}
schema={{
type: 'string',
}}
/>
)}
</Field>
</>
),
}}
/>
);
@@ -0,0 +1,37 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const JsonEditorWithVariables = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.JsonEditorWithVariables,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<div style={{ width: 400 }}>
<FormHeader />
<Field<any> name="json_editor_with_variables" defaultValue={`{ "a": {{start_0.str}}}`}>
{({ field }) => (
<JsonEditorWithVariables
value={field.value}
onChange={(value) => field.onChange(value)}
/>
)}
</Field>
</div>
),
}}
/>
);
@@ -0,0 +1,49 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import type { IJsonSchema } from '@flowgram.ai/form-materials';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const JsonSchemaCreator = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.JsonSchemaCreator,
}))
);
const JsonSchemaEditor = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.JsonSchemaEditor,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<IJsonSchema | undefined> name="json_schema">
{({ field }) => (
<div>
<JsonSchemaCreator onSchemaCreate={(schema) => field.onChange(schema)} />
<div style={{ marginTop: 16 }}>
<JsonSchemaEditor
value={field.value}
onChange={(value) => field.onChange(value)}
/>
</div>
</div>
)}
</Field>
</>
),
}}
/>
);
@@ -0,0 +1,45 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import type { IJsonSchema } from '@flowgram.ai/form-materials';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const JsonSchemaEditor = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.JsonSchemaEditor,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterStartNode
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<IJsonSchema | undefined>
name="json_schema_editor"
defaultValue={{
type: 'object',
properties: {
name: { type: 'string' },
age: { type: 'number' },
},
}}
>
{({ field }) => (
<JsonSchemaEditor value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
</>
),
}}
/>
);
@@ -0,0 +1,86 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React, { useState } from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { IFlowTemplateValue, IInputsValues, InputsValuesTree } from '@flowgram.ai/form-materials';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const PromptEditorWithInputs = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.PromptEditorWithInputs,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<div style={{ width: 400 }}>
<FormHeader />
<Field<IInputsValues | undefined>
name="inputsValues"
defaultValue={{
a: { type: 'constant', content: '123' },
b: { type: 'ref', content: ['start_0', 'obj'] },
}}
>
{({ field }) => (
<InputsValuesTree value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
<br />
<Field<IInputsValues | undefined> name="inputsValues">
{({ field: inputsField }) => (
<Field<IFlowTemplateValue | undefined>
name="prompt_editor_with_inputs"
defaultValue={{
type: 'template',
content: '# Query \n {{b.obj2.num}}',
}}
>
{({ field }) => (
<PromptEditorWithInputs
value={field.value}
onChange={(value) => field.onChange(value)}
inputsValues={inputsField.value || {}}
/>
)}
</Field>
)}
</Field>
</div>
),
}}
/>
);
export const WithoutCanvas = () => {
const [value, setValue] = useState<IFlowTemplateValue | undefined>({
type: 'template',
content: '# Role \nYou are a helpful assistant. \n\n# Query \n{{b.obj2.num}} \n\n',
});
return (
<div>
<PromptEditorWithInputs
value={value}
onChange={(value) => setValue(value)}
inputsValues={{
a: { type: 'constant', content: '123' },
b: {
c: {
d: { type: 'constant', content: 456 },
},
e: { type: 'constant', content: 789 },
},
}}
/>
</div>
);
};
@@ -0,0 +1,84 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const PromptEditorWithVariables = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.PromptEditorWithVariables,
}))
);
const VariableSelectorProvider = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.VariableSelectorProvider,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<div style={{ width: 400 }}>
<FormHeader />
<Field<any | undefined>
name="prompt_editor"
defaultValue={{
type: 'template',
content: `# Role
You are a helpful assistant
# Query
{{start_0.str}}`,
}}
>
{({ field }) => (
<PromptEditorWithVariables
value={field.value}
onChange={(value) => field.onChange(value)}
/>
)}
</Field>
</div>
),
}}
/>
);
const STRING_ONLY_SCHEMA = { type: 'string' };
export const StringOnlyStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<div style={{ width: 400 }}>
<FormHeader />
<VariableSelectorProvider includeSchema={STRING_ONLY_SCHEMA}>
<Field<any | undefined>
name="prompt_editor"
defaultValue={{
type: 'template',
content: `# Role
You are a helpful assistant`,
}}
>
{({ field }) => (
<PromptEditorWithVariables
value={field.value}
onChange={(value) => field.onChange(value)}
/>
)}
</Field>
</VariableSelectorProvider>
</div>
),
}}
/>
);
@@ -0,0 +1,40 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const PromptEditor = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.PromptEditor,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<any | undefined>
name="prompt_editor"
defaultValue={{
type: 'template',
content: '# Role \n You are a helpful assistant',
}}
>
{({ field }) => (
<PromptEditor value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
</>
),
}}
/>
);
@@ -0,0 +1,40 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const SQLEditorWithVariables = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.SQLEditorWithVariables,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<div style={{ width: 400 }}>
<FormHeader />
<Field<string | undefined>
name="sql_editor_with_variables"
defaultValue={'SELECT * FROM users \n WHERE user_id = {{start_0.str}}'}
>
{({ field }) => (
<SQLEditorWithVariables
value={field.value}
onChange={(value) => field.onChange(value)}
/>
)}
</Field>
</div>
),
}}
/>
);
@@ -0,0 +1,39 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import type { IJsonSchema } from '@flowgram.ai/form-materials';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const TypeSelector = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.TypeSelector,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterStartNode
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<Partial<IJsonSchema> | undefined>
name="type_selector"
defaultValue={{ type: 'string' }}
>
{({ field }) => (
<TypeSelector value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
</>
),
}}
/>
);
@@ -0,0 +1,105 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { useVariableTree } from '@flowgram.ai/form-materials';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const VariableSelector = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.VariableSelector,
}))
);
const VariableSelectorProvider = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.VariableSelectorProvider,
}))
);
const Tree = React.lazy(() =>
import('@douyinfe/semi-ui').then((module) => ({
default: module.Tree,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<string[] | undefined> name="variable_selector">
{({ field }) => (
<VariableSelector value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
</>
),
}}
/>
);
export const FilterSchemaStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<>
<FormHeader />
<Field<string[] | undefined> name="variable_selector">
{({ field }) => (
<VariableSelector
value={field.value}
onChange={(value) => field.onChange(value)}
includeSchema={{ type: 'string' }}
/>
)}
</Field>
</>
),
}}
/>
);
export const CustomFilterStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => (
<VariableSelectorProvider skipVariable={(variable) => variable?.key === 'str'}>
<FormHeader />
<Field<string[] | undefined> name="variable_selector">
{({ field }) => (
<VariableSelector value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
</VariableSelectorProvider>
),
}}
/>
);
export const CustomVariableTreeStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
render: () => {
const treeData = useVariableTree({});
return (
<VariableSelectorProvider skipVariable={(variable) => variable?.key === 'str'}>
<FormHeader />
<Tree treeData={treeData} defaultExpandAll />
</VariableSelectorProvider>
);
},
}}
/>
);
@@ -0,0 +1,46 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { autoRenameRefEffect } from '@flowgram.ai/form-materials';
import { Field } from '@flowgram.ai/fixed-layout-editor';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const InputsValues = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.InputsValues,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
effect: {
inputsValues: autoRenameRefEffect,
},
render: () => (
<>
<FormHeader />
<Field<Record<string, any> | undefined>
name="inputsValues"
defaultValue={{
a: {
type: 'ref',
content: ['start_0', 'str'],
},
}}
>
{({ field }) => (
<InputsValues value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
</>
),
}}
/>
);
@@ -0,0 +1,67 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { listenRefSchemaChange } from '@flowgram.ai/form-materials';
import { Field } from '@flowgram.ai/fixed-layout-editor';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const InputsValues = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.InputsValues,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
effect: {
'inputsValues.*': listenRefSchemaChange(({ name, schema, form, formValues }) => {
form.setValueIn(
`log`,
`${form.getValueIn(`log`) || ''}${name}: ${JSON.stringify(schema)}\n`
);
}),
},
render: () => (
<>
<FormHeader />
<Field<Record<string, any> | undefined>
name="inputsValues"
defaultValue={{
a: {
type: 'ref',
content: ['start_0', 'str'],
},
}}
>
{({ field }) => (
<InputsValues value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
<br />
<Field<any> name="log" defaultValue={'When schema updated, log changes:\n'}>
{({ field }) => (
<pre
style={{
width: 500,
padding: 4,
background: '#f5f5f5',
fontSize: 12,
whiteSpace: 'pre-wrap',
}}
>
{field.value}
</pre>
)}
</Field>
</>
),
}}
/>
);
@@ -0,0 +1,67 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { listenRefValueChange } from '@flowgram.ai/form-materials';
import { Field } from '@flowgram.ai/fixed-layout-editor';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const InputsValues = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.InputsValues,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
formMeta={{
effect: {
'inputsValues.*': listenRefValueChange(({ name, variable, form }) => {
form.setValueIn(
`log`,
`${form.getValueIn(`log`) || ''}${name}: ${JSON.stringify(variable?.toJSON() || {})} \n`
);
}),
},
render: () => (
<>
<FormHeader />
<Field<Record<string, any> | undefined>
name="inputsValues"
defaultValue={{
a: {
type: 'ref',
content: ['start_0', 'str'],
},
}}
>
{({ field }) => (
<InputsValues value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
<br />
<Field<any> name="log" defaultValue={'When variable value updated, log changes:\n'}>
{({ field }) => (
<pre
style={{
width: 500,
padding: 4,
background: '#f5f5f5',
fontSize: 12,
whiteSpace: 'pre-wrap',
}}
>
{field.value}
</pre>
)}
</Field>
</>
),
}}
/>
);
@@ -0,0 +1,176 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field, FlowNodeRegistry } from '@flowgram.ai/free-layout-editor';
import { SubCanvasRender, createContainerNodePlugin } from '@flowgram.ai/free-container-plugin';
import {
provideBatchInputEffect,
createBatchOutputsFormPlugin,
type IFlowRefValue,
DisplayOutputs,
} from '@flowgram.ai/form-materials';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const BatchVariableSelector = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.BatchVariableSelector,
}))
);
const BatchOutputs = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.BatchOutputs,
}))
);
const VariableSelector = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.VariableSelector,
}))
);
type BatchOutputsValueType = Record<string, IFlowRefValue | undefined>;
const createLoopRegistry = (): FlowNodeRegistry => ({
type: 'custom',
meta: {
isContainer: true,
size: {
width: 500,
height: 260,
},
padding: () => ({
top: 180,
bottom: 40,
left: 50,
right: 50,
}),
},
formMeta: {
render: () => (
<>
<FormHeader />
<div style={{ marginBottom: 16 }}>
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
Loop input (select array variable):
</div>
<Field<IFlowRefValue | undefined>
name="loopFor"
defaultValue={{ type: 'ref', content: ['start_0', 'arr', 'arr_obj'] }}
>
{({ field }) => (
<BatchVariableSelector
style={{ width: '100%' }}
value={field.value?.content}
onChange={(val) => field.onChange({ type: 'ref', content: val })}
/>
)}
</Field>
</div>
<SubCanvasRender offsetY={-120} />
<div style={{ marginBottom: 16 }}>
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
Available local variables (item & index generated by provideBatchInputEffect):
</div>
<Field<string[] | undefined> name="localVariable">
{({ field }) => (
<VariableSelector value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
</div>
<div style={{ marginBottom: 16 }}>
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
Loop outputs (collected into arrays):
</div>
<Field<BatchOutputsValueType | undefined>
name="loopOutputs"
defaultValue={{
names: { type: 'ref', content: ['variable_0', 'name'] },
}}
>
{({ field }) => (
<BatchOutputs
style={{ width: '100%' }}
value={field.value}
onChange={(val) => field.onChange(val)}
/>
)}
</Field>
</div>
<DisplayOutputs displayFromScope />
</>
),
effect: {
loopFor: provideBatchInputEffect,
},
plugins: [
createBatchOutputsFormPlugin({ outputKey: 'loopOutputs', inferTargetKey: 'outputs' }),
],
},
});
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
height={550}
initialData={{
nodes: [
{
id: 'custom_0',
type: 'custom',
data: {
title: 'Loop',
loopFor: { type: 'ref', content: ['start_0', 'arr', 'arr_obj'] },
},
blocks: [
{
id: 'block_start_0',
type: 'block-start',
data: { title: 'Start' },
meta: { position: { x: 20, y: 0 } },
},
{
id: 'variable_0',
type: 'variable',
data: {
title: 'Variable',
assign: [
{
operator: 'declare',
left: 'name',
right: { type: 'ref', content: ['custom_0_locals', 'item', 'str'] },
},
],
},
meta: { position: { x: 100, y: 0 } },
},
{
id: 'block_end_0',
type: 'block-end',
data: { title: 'End' },
meta: { position: { x: 360, y: 0 } },
},
],
edges: [
{ sourceNodeID: 'block_start_0', targetNodeID: 'variable_0' },
{ sourceNodeID: 'variable_0', targetNodeID: 'block_end_0' },
],
},
],
edges: [{ sourceNodeID: 'start_0', targetNodeID: 'custom_0' }],
}}
transformRegistry={(props) => ({
...props,
nodeRegistries: [
...(props.nodeRegistries || []).filter((r) => r.type !== 'custom'),
createLoopRegistry(),
],
})}
plugins={(ctx) => [createContainerNodePlugin({})]}
/>
);
@@ -0,0 +1,62 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import {
provideJsonSchemaOutputs,
syncVariableTitle,
type IJsonSchema,
} from '@flowgram.ai/form-materials';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const JsonSchemaEditor = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.JsonSchemaEditor,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterStartNode
transformInitialNode={{
end_0: (node) => {
node.data.inputsValues = {
success: { type: 'constant', content: true, schema: { type: 'boolean' } },
message: { type: 'ref', content: ['custom_0', 'name'] },
};
return node;
},
}}
formMeta={{
render: () => (
<>
<FormHeader />
<Field<IJsonSchema | undefined>
name="outputs"
defaultValue={{
type: 'object',
properties: {
name: { type: 'string' },
age: { type: 'number' },
},
}}
>
{({ field }) => (
<JsonSchemaEditor value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
</>
),
effect: {
// Sync the title to variables
title: syncVariableTitle,
outputs: provideJsonSchemaOutputs,
},
}}
/>
);
@@ -0,0 +1,60 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { provideJsonSchemaOutputs, syncVariableTitle } from '@flowgram.ai/form-materials';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const Input = React.lazy(() =>
import('@douyinfe/semi-ui').then((module) => ({
default: module.Input,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterStartNode
transformInitialNode={{
end_0: (node) => {
node.data.inputsValues = {
success: { type: 'constant', content: true, schema: { type: 'boolean' } },
message: { type: 'ref', content: ['custom_0', 'name'] },
};
return node;
},
custom_0: (node) => {
node.data.outputs = {
type: 'object',
properties: {
name: { type: 'string' },
age: { type: 'number' },
},
};
return node;
},
}}
formMeta={{
render: () => (
<>
<FormHeader />
<p>Please Edit Title below to sync to variables:</p>
<Field<string | undefined> name="title">
{({ field }) => (
<Input value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
</>
),
effect: {
// Sync the title to variables
title: syncVariableTitle,
outputs: provideJsonSchemaOutputs,
},
}}
/>
);
@@ -0,0 +1,77 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React, { useEffect } from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { validateFlowValue, validateWhenVariableSync } from '@flowgram.ai/form-materials';
import { Button } from '@douyinfe/semi-ui';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const DynamicValueInput = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.DynamicValueInput,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
transformInitialNode={{
custom_0: (node) => {
node.data.value = {
type: 'ref',
content: ['start_0', 'query'],
};
return node;
},
}}
formMeta={{
effect: {
value: validateWhenVariableSync(),
},
validate: {
value: ({ value, context }) =>
validateFlowValue(value, {
node: context.node,
errorMessages: {
unknownVariable: 'Unknown Variable',
},
}),
},
render: ({ form }) => {
useEffect(() => {
form.validate();
}, []);
return (
<>
<FormHeader />
<b>{"Add 'query' in Start"}</b>
<Field<any> name="value">
{({ field, fieldState }) => (
<>
<DynamicValueInput
value={field.value}
onChange={(value) => field.onChange(value)}
/>
<span style={{ color: 'red' }}>
{fieldState.errors?.map((e) => e.message).join('\n')}
</span>
</>
)}
</Field>
<br />
<Button onClick={() => form.validate()}>Trigger Validate</Button>
</>
);
},
}}
/>
);
@@ -0,0 +1,303 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field, FlowNodeRegistry } from '@flowgram.ai/free-layout-editor';
import { SubCanvasRender, createContainerNodePlugin } from '@flowgram.ai/free-container-plugin';
import {
provideBatchInputEffect,
createBatchOutputsFormPlugin,
type IFlowRefValue,
DisplayOutputs,
} from '@flowgram.ai/form-materials';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const BatchVariableSelector = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.BatchVariableSelector,
}))
);
const BatchOutputs = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.BatchOutputs,
}))
);
type BatchOutputsValueType = Record<string, IFlowRefValue | undefined>;
const createLoopRegistry = (): FlowNodeRegistry => ({
type: 'custom',
meta: {
isContainer: true,
size: {
width: 500,
height: 260,
},
padding: () => ({
top: 160,
bottom: 40,
left: 50,
right: 50,
}),
},
formMeta: {
render: () => (
<>
<FormHeader />
<div style={{ marginBottom: 16 }}>
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
Loop input (select array variable):
</div>
<Field<IFlowRefValue | undefined>
name="loopFor"
defaultValue={{ type: 'ref', content: ['start_0', 'arr', 'arr_obj'] }}
>
{({ field }) => (
<BatchVariableSelector
style={{ width: '100%' }}
value={field.value?.content}
onChange={(val) => field.onChange({ type: 'ref', content: val })}
/>
)}
</Field>
</div>
<SubCanvasRender offsetY={-100} />
<div style={{ marginBottom: 16 }}>
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
Loop outputs (collected into arrays):
</div>
<Field<BatchOutputsValueType | undefined>
name="loopOutputs"
defaultValue={{
names: { type: 'ref', content: ['variable_0', 'name'] },
}}
>
{({ field }) => (
<BatchOutputs
style={{ width: '100%' }}
value={field.value}
onChange={(val) => field.onChange(val)}
/>
)}
</Field>
</div>
<div>
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
Generated output variables:
</div>
<DisplayOutputs displayFromScope />
</div>
</>
),
effect: {
loopFor: provideBatchInputEffect,
},
plugins: [
createBatchOutputsFormPlugin({ outputKey: 'loopOutputs', inferTargetKey: 'outputs' }),
],
},
});
const createLoopRegistryWithInfer = (): FlowNodeRegistry => ({
type: 'custom',
meta: {
isContainer: true,
size: {
width: 500,
height: 260,
},
padding: () => ({
top: 160,
bottom: 40,
left: 50,
right: 50,
}),
},
formMeta: {
render: () => (
<>
<FormHeader />
<div style={{ marginBottom: 16 }}>
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>Loop input:</div>
<Field<IFlowRefValue | undefined>
name="loopFor"
defaultValue={{ type: 'ref', content: ['start_0', 'arr', 'arr_obj'] }}
>
{({ field }) => (
<BatchVariableSelector
style={{ width: '100%' }}
value={field.value?.content}
onChange={(val) => field.onChange({ type: 'ref', content: val })}
/>
)}
</Field>
</div>
<SubCanvasRender offsetY={-100} />
<div style={{ marginBottom: 16 }}>
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
Loop outputs (with schema inference):
</div>
<Field<BatchOutputsValueType | undefined>
name="loopOutputs"
defaultValue={{
items: { type: 'ref', content: ['variable_0', 'item_name'] },
values: { type: 'ref', content: ['variable_0', 'item_index'] },
}}
>
{({ field }) => (
<BatchOutputs
style={{ width: '100%' }}
value={field.value}
onChange={(val) => field.onChange(val)}
/>
)}
</Field>
</div>
<div>
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
Output variables (check Debug panel for inferred schema):
</div>
<DisplayOutputs displayFromScope />
</div>
</>
),
effect: {
loopFor: provideBatchInputEffect,
},
plugins: [
createBatchOutputsFormPlugin({ outputKey: 'loopOutputs', inferTargetKey: 'outputs' }),
],
},
});
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
height={550}
initialData={{
nodes: [
{
id: 'custom_0',
type: 'custom',
data: {
title: 'Loop',
loopFor: { type: 'ref', content: ['start_0', 'arr', 'arr_obj'] },
},
blocks: [
{
id: 'block_start_0',
type: 'block-start',
data: { title: 'Start' },
meta: { position: { x: 20, y: 0 } },
},
{
id: 'variable_0',
type: 'variable',
data: {
title: 'Variable',
assign: [
{
operator: 'declare',
left: 'name',
right: { type: 'ref', content: ['custom_0_locals', 'item', 'str'] },
},
],
},
meta: { position: { x: 100, y: 0 } },
},
{
id: 'block_end_0',
type: 'block-end',
data: { title: 'End' },
meta: { position: { x: 360, y: 0 } },
},
],
edges: [
{ sourceNodeID: 'block_start_0', targetNodeID: 'variable_0' },
{ sourceNodeID: 'variable_0', targetNodeID: 'block_end_0' },
],
},
],
edges: [{ sourceNodeID: 'start_0', targetNodeID: 'custom_0' }],
}}
transformRegistry={(props) => ({
...props,
nodeRegistries: [
...(props.nodeRegistries || []).filter((r) => r.type !== 'custom'),
createLoopRegistry(),
],
})}
plugins={(ctx) => [createContainerNodePlugin({})]}
/>
);
export const WithInferSchemaStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
height={550}
initialData={{
nodes: [
{
id: 'custom_0',
type: 'custom',
data: {
title: 'Loop',
loopFor: { type: 'ref', content: ['start_0', 'arr', 'arr_obj'] },
},
blocks: [
{
id: 'block_start_0',
type: 'block-start',
data: { title: 'Start' },
meta: { position: { x: 20, y: 0 } },
},
{
id: 'variable_0',
type: 'variable',
data: {
title: 'Variable',
assign: [
{
operator: 'declare',
left: 'item_name',
right: { type: 'ref', content: ['custom_0_locals', 'item', 'str'] },
},
{
operator: 'declare',
left: 'item_index',
right: { type: 'ref', content: ['custom_0_locals', 'index'] },
},
],
},
meta: { position: { x: 100, y: 0 } },
},
{
id: 'block_end_0',
type: 'block-end',
data: { title: 'End' },
meta: { position: { x: 360, y: 0 } },
},
],
edges: [
{ sourceNodeID: 'block_start_0', targetNodeID: 'variable_0' },
{ sourceNodeID: 'variable_0', targetNodeID: 'block_end_0' },
],
},
],
edges: [{ sourceNodeID: 'start_0', targetNodeID: 'custom_0' }],
}}
transformRegistry={(props) => ({
...props,
nodeRegistries: [
...(props.nodeRegistries || []).filter((r) => r.type !== 'custom'),
createLoopRegistryWithInfer(),
],
})}
plugins={(ctx) => [createContainerNodePlugin({})]}
/>
);
@@ -0,0 +1,90 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { createInferAssignPlugin } from '@flowgram.ai/form-materials';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const AssignRows = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.AssignRows,
}))
);
const DisplayOutputs = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.DisplayOutputs,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
transformInitialNode={{
end_0: (node) => {
node.data.inputsValues = {
info: {
type: 'ref',
content: ['custom_0', 'userInfo'],
},
};
return node;
},
}}
formMeta={{
render: () => (
<>
<FormHeader />
<AssignRows
name="assign"
defaultValue={[
// 从常量声明变量
{
operator: 'declare',
left: 'userName',
right: {
type: 'constant',
content: 'John Doe',
schema: { type: 'string' },
},
},
// 从变量声明变量
{
operator: 'declare',
left: 'userInfo',
right: {
type: 'ref',
content: ['start_0', 'obj'],
},
},
// 赋值现有变量
{
operator: 'assign',
left: {
type: 'ref',
content: ['start_0', 'str'],
},
right: {
type: 'constant',
content: 'Hello Flowgram',
schema: { type: 'string' },
},
},
]}
/>
<DisplayOutputs displayFromScope style={{ marginTop: 10 }} />
</>
),
plugins: [
createInferAssignPlugin({
assignKey: 'assign',
outputKey: 'outputs',
}),
],
}}
/>
);
@@ -0,0 +1,104 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { createInferInputsPlugin } from '@flowgram.ai/form-materials';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const InputsValues = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.InputsValues,
}))
);
const InputsValuesTree = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.InputsValuesTree,
}))
);
/**
* Basic usage story - demonstrates automatic schema inference from InputsValues
*/
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
height={500}
formMeta={{
render: () => (
<>
<FormHeader />
<div>
<div>
<h4>Headers</h4>
<Field<Record<string, any> | undefined>
name="headersValues"
defaultValue={{
'Content-Type': {
type: 'constant',
content: 'application/json',
schema: { type: 'string' },
},
Authorization: {
type: 'ref',
content: ['start_0', 'str'],
},
}}
>
{({ field }) => (
<InputsValues value={field.value} onChange={(value) => field.onChange(value)} />
)}
</Field>
</div>
<div>
<h4>Body</h4>
<Field<Record<string, any> | undefined>
name="bodyValues"
defaultValue={{
page: {
index: {
type: 'ref',
content: ['start_0', 'obj', 'obj2', 'num'],
},
size: {
type: 'constant',
content: 10,
schema: { type: 'number' },
},
},
query: {
type: 'ref',
content: ['start_0', 'obj'],
},
}}
>
{({ field }) => (
<InputsValuesTree
value={field.value}
onChange={(value) => field.onChange(value)}
/>
)}
</Field>
</div>
</div>
</>
),
plugins: [
createInferInputsPlugin({
sourceKey: 'headersValues',
targetKey: 'headersSchema',
}),
createInferInputsPlugin({
sourceKey: 'bodyValues',
targetKey: 'bodySchema',
}),
],
}}
/>
);
@@ -0,0 +1,135 @@
/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import React from 'react';
import { Field } from '@flowgram.ai/free-layout-editor';
import { validateFlowValue } from '@flowgram.ai/form-materials';
import { Button } from '@douyinfe/semi-ui';
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
const DynamicValueInput = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.DynamicValueInput,
}))
);
const PromptEditorWithVariables = React.lazy(() =>
import('@flowgram.ai/form-materials').then((module) => ({
default: module.PromptEditorWithVariables,
}))
);
export const BasicStory = () => (
<FreeFormMetaStoryBuilder
filterEndNode
transformInitialNode={{
custom_0: (node) => {
node.data.dynamic_value_input = {
type: 'ref',
content: ['start_0', 'unknown_key'],
};
node.data.required_dynamic_value_input = {
type: 'constant',
content: '',
};
node.data.prompt_editor = {
type: 'template',
content: 'Hello {{start_0.unknown_key}}',
};
return node;
},
}}
formMeta={{
validate: {
dynamic_value_input: ({ value, context }) =>
validateFlowValue(value, {
node: context.node,
errorMessages: {
required: 'Value is required',
unknownVariable: 'Unknown Variable',
},
}),
required_dynamic_value_input: ({ value, context }) =>
validateFlowValue(value, {
node: context.node,
required: true,
errorMessages: {
required: 'Value is required',
unknownVariable: 'Unknown Variable',
},
}),
prompt_editor: ({ value, context }) =>
validateFlowValue(value, {
node: context.node,
required: true,
errorMessages: {
required: 'Prompt is required',
unknownVariable: 'Unknown Variable In Template',
},
}),
},
render: ({ form }) => (
<>
<FormHeader />
<b>Validate variable valid</b>
<Field<any> name="dynamic_value_input">
{({ field, fieldState }) => (
<>
<DynamicValueInput
value={field.value}
onChange={(value) => field.onChange(value)}
/>
<span style={{ color: 'red' }}>
{fieldState.errors?.map((e) => e.message).join('\n')}
</span>
</>
)}
</Field>
<br />
<b>Validate required value</b>
<Field<any> name="required_dynamic_value_input">
{({ field, fieldState }) => (
<>
<DynamicValueInput
value={field.value}
onChange={(value) => field.onChange(value)}
/>
<span style={{ color: 'red' }}>
{fieldState.errors?.map((e) => e.message).join('\n')}
</span>
</>
)}
</Field>
<br />
<b>Validate required and variables valid in prompt</b>
<Field<any> name="prompt_editor">
{({ field, fieldState }) => (
<>
<PromptEditorWithVariables
value={field.value}
onChange={(value) => field.onChange(value)}
/>
<span style={{ color: 'red' }}>
{fieldState.errors?.map((e) => e.message).join('\n')}
</span>
</>
)}
</Field>
<br />
<Button onClick={() => form.validate()}>Trigger Validate</Button>
</>
),
}}
/>
);