@flowgram.ai/form-materials 0.4.2 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/index.js +105 -41
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.mts +25 -3
- package/dist/index.d.ts +25 -3
- package/dist/index.js +95 -33
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/components/dynamic-value-input/index.tsx +20 -11
- package/src/components/inputs-values/index.tsx +12 -1
- package/src/components/inputs-values-tree/hooks/use-child-list.tsx +1 -1
- package/src/components/inputs-values-tree/index.tsx +7 -1
- package/src/components/inputs-values-tree/row.tsx +5 -1
- package/src/components/json-editor-with-variables/extensions/variable-tag.tsx +1 -1
- package/src/components/prompt-editor-with-inputs/extensions/inputs-tree.tsx +11 -0
- package/src/components/prompt-editor-with-inputs/index.tsx +1 -2
- package/src/components/prompt-editor-with-inputs/inputs-picker.tsx +34 -17
- package/src/components/prompt-editor-with-variables/extensions/variable-tag.tsx +1 -1
- package/src/components/prompt-editor-with-variables/extensions/variable-tree.tsx +13 -1
- package/src/components/type-selector/index.tsx +12 -2
- package/src/index.ts +1 -0
- package/src/shared/flow-value/utils.ts +1 -1
- package/src/typings/flow-value/index.ts +1 -1
- package/src/validate/validate-flow-value/index.tsx +4 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowgram.ai/form-materials",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"homepage": "https://flowgram.ai/",
|
|
5
5
|
"repository": "https://github.com/bytedance/flowgram.ai",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"@codemirror/state": "~6.5.2",
|
|
36
36
|
"typescript": "^5.8.3",
|
|
37
37
|
"zod": "^3.24.4",
|
|
38
|
-
"@flowgram.ai/editor": "0.4.
|
|
39
|
-
"@flowgram.ai/json-schema": "0.4.
|
|
38
|
+
"@flowgram.ai/editor": "0.4.3",
|
|
39
|
+
"@flowgram.ai/json-schema": "0.4.3"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/lodash": "^4.14.137",
|
|
@@ -52,8 +52,8 @@
|
|
|
52
52
|
"tsup": "^8.0.1",
|
|
53
53
|
"typescript": "^5.8.3",
|
|
54
54
|
"vitest": "^0.34.6",
|
|
55
|
-
"@flowgram.ai/
|
|
56
|
-
"@flowgram.ai/
|
|
55
|
+
"@flowgram.ai/eslint-config": "0.4.3",
|
|
56
|
+
"@flowgram.ai/ts-config": "0.4.3"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"react": ">=16.8",
|
|
@@ -5,11 +5,16 @@
|
|
|
5
5
|
|
|
6
6
|
import React from 'react';
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
JsonSchemaUtils,
|
|
10
|
+
IJsonSchema,
|
|
11
|
+
useTypeManager,
|
|
12
|
+
type JsonSchemaTypeManager,
|
|
13
|
+
} from '@flowgram.ai/json-schema';
|
|
9
14
|
import { IconButton } from '@douyinfe/semi-ui';
|
|
10
15
|
import { IconSetting } from '@douyinfe/semi-icons';
|
|
11
16
|
|
|
12
|
-
import { IFlowConstantRefValue } from '@/typings';
|
|
17
|
+
import { IFlowConstantRefValue, IFlowConstantValue } from '@/typings';
|
|
13
18
|
import { createInjectMaterial } from '@/shared';
|
|
14
19
|
import { InjectVariableSelector } from '@/components/variable-selector';
|
|
15
20
|
import { TypeSelector } from '@/components/type-selector';
|
|
@@ -32,6 +37,12 @@ interface PropsType {
|
|
|
32
37
|
};
|
|
33
38
|
}
|
|
34
39
|
|
|
40
|
+
const DEFAULT_VALUE: IFlowConstantValue = {
|
|
41
|
+
type: 'constant',
|
|
42
|
+
content: '',
|
|
43
|
+
schema: { type: 'string' },
|
|
44
|
+
};
|
|
45
|
+
|
|
35
46
|
export function DynamicValueInput({
|
|
36
47
|
value,
|
|
37
48
|
onChange,
|
|
@@ -44,6 +55,8 @@ export function DynamicValueInput({
|
|
|
44
55
|
const [selectSchema, setSelectSchema] = useSelectSchema(schemaFromProps, constantProps, value);
|
|
45
56
|
const includeSchema = useIncludeSchema(schemaFromProps);
|
|
46
57
|
|
|
58
|
+
const typeManager = useTypeManager() as JsonSchemaTypeManager;
|
|
59
|
+
|
|
47
60
|
const renderTypeSelector = () => {
|
|
48
61
|
if (schemaFromProps) {
|
|
49
62
|
return <TypeSelector value={schemaFromProps} readonly={true} />;
|
|
@@ -60,24 +73,20 @@ export function DynamicValueInput({
|
|
|
60
73
|
value={selectSchema}
|
|
61
74
|
onChange={(_v) => {
|
|
62
75
|
setSelectSchema(_v || { type: 'string' });
|
|
63
|
-
let content;
|
|
64
76
|
|
|
77
|
+
const schema = _v || { type: 'string' };
|
|
78
|
+
let content = typeManager.getDefaultValue(schema);
|
|
65
79
|
if (_v?.type === 'object') {
|
|
66
80
|
content = '{}';
|
|
67
81
|
}
|
|
68
|
-
|
|
69
82
|
if (_v?.type === 'array') {
|
|
70
83
|
content = '[]';
|
|
71
84
|
}
|
|
72
85
|
|
|
73
|
-
if (_v?.type === 'boolean') {
|
|
74
|
-
content = false;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
86
|
onChange({
|
|
78
87
|
type: 'constant',
|
|
79
88
|
content,
|
|
80
|
-
schema
|
|
89
|
+
schema,
|
|
81
90
|
});
|
|
82
91
|
}}
|
|
83
92
|
readonly={readonly}
|
|
@@ -92,7 +101,7 @@ export function DynamicValueInput({
|
|
|
92
101
|
<InjectVariableSelector
|
|
93
102
|
style={{ width: '100%' }}
|
|
94
103
|
value={value?.content}
|
|
95
|
-
onChange={(_v) => onChange(_v ? { type: 'ref', content: _v } :
|
|
104
|
+
onChange={(_v) => onChange(_v ? { type: 'ref', content: _v } : DEFAULT_VALUE)}
|
|
96
105
|
includeSchema={includeSchema}
|
|
97
106
|
readonly={readonly}
|
|
98
107
|
/>
|
|
@@ -110,7 +119,7 @@ export function DynamicValueInput({
|
|
|
110
119
|
fallbackRenderer={() => (
|
|
111
120
|
<InjectVariableSelector
|
|
112
121
|
style={{ width: '100%' }}
|
|
113
|
-
onChange={(_v) => onChange(_v ? { type: 'ref', content: _v } :
|
|
122
|
+
onChange={(_v) => onChange(_v ? { type: 'ref', content: _v } : DEFAULT_VALUE)}
|
|
114
123
|
includeSchema={includeSchema}
|
|
115
124
|
readonly={readonly}
|
|
116
125
|
/>
|
|
@@ -67,7 +67,18 @@ export function InputsValues({
|
|
|
67
67
|
</UIRow>
|
|
68
68
|
))}
|
|
69
69
|
</UIRows>
|
|
70
|
-
<Button
|
|
70
|
+
<Button
|
|
71
|
+
disabled={readonly}
|
|
72
|
+
icon={<IconPlus />}
|
|
73
|
+
size="small"
|
|
74
|
+
onClick={() =>
|
|
75
|
+
add({
|
|
76
|
+
type: 'constant',
|
|
77
|
+
content: '',
|
|
78
|
+
schema: { type: 'string' },
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
>
|
|
71
82
|
{I18n.t('Add')}
|
|
72
83
|
</Button>
|
|
73
84
|
</div>
|
|
@@ -23,7 +23,7 @@ export function useChildList(
|
|
|
23
23
|
canAddField: boolean;
|
|
24
24
|
hasChildren: boolean;
|
|
25
25
|
list: ListItem[];
|
|
26
|
-
add: (
|
|
26
|
+
add: (defaultValue?: any) => void;
|
|
27
27
|
updateKey: (id: string, key: string) => void;
|
|
28
28
|
updateValue: (id: string, value: any) => void;
|
|
29
29
|
remove: (id: string) => void;
|
|
@@ -47,7 +47,13 @@ export function InputsValuesTree(props: PropsType) {
|
|
|
47
47
|
disabled={readonly}
|
|
48
48
|
icon={<IconPlus />}
|
|
49
49
|
size="small"
|
|
50
|
-
onClick={
|
|
50
|
+
onClick={() => {
|
|
51
|
+
add({
|
|
52
|
+
type: 'constant',
|
|
53
|
+
content: '',
|
|
54
|
+
schema: { type: 'string' },
|
|
55
|
+
});
|
|
56
|
+
}}
|
|
51
57
|
>
|
|
52
58
|
{I18n.t('Add')}
|
|
53
59
|
</Button>
|
|
@@ -134,7 +134,7 @@ export function VariableTagInject() {
|
|
|
134
134
|
// 基于 {{var}} 的正则进行匹配,匹配后进行自定义渲染
|
|
135
135
|
useLayoutEffect(() => {
|
|
136
136
|
const atMatcher = new MatchDecorator({
|
|
137
|
-
regexp: /\{\{([^\}]+)\}\}/g,
|
|
137
|
+
regexp: /\{\{([^\}\{]+)\}\}/g,
|
|
138
138
|
decoration: (match) =>
|
|
139
139
|
Decoration.replace({
|
|
140
140
|
widget: new VariableTagWidget({
|
|
@@ -32,6 +32,17 @@ export function InputsTree({ inputsValues }: { inputsValues: Record<string, IFlo
|
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
/**
|
|
36
|
+
* When user input {{xxxx}}, {{{xxx}}}(more brackets if possible), replace all brackets with {{xxxx}}
|
|
37
|
+
*/
|
|
38
|
+
let { from, to } = range;
|
|
39
|
+
while (editor.$view.state.doc.sliceString(from - 1, from) === '{') {
|
|
40
|
+
from--;
|
|
41
|
+
}
|
|
42
|
+
while (editor.$view.state.doc.sliceString(to, to + 1) === '}') {
|
|
43
|
+
to++;
|
|
44
|
+
}
|
|
45
|
+
|
|
35
46
|
editor.replaceText({
|
|
36
47
|
...range,
|
|
37
48
|
text: '{{' + variablePath + '}}',
|
|
@@ -5,13 +5,12 @@
|
|
|
5
5
|
|
|
6
6
|
import React from 'react';
|
|
7
7
|
|
|
8
|
-
import { IFlowValue } from '@/typings';
|
|
9
8
|
import { PromptEditor, PromptEditorPropsType } from '@/components/prompt-editor';
|
|
10
9
|
|
|
11
10
|
import { InputsTree } from './extensions/inputs-tree';
|
|
12
11
|
|
|
13
12
|
interface PropsType extends PromptEditorPropsType {
|
|
14
|
-
inputsValues:
|
|
13
|
+
inputsValues: any;
|
|
15
14
|
}
|
|
16
15
|
|
|
17
16
|
export function PromptEditorWithInputs({ inputsValues, ...restProps }: PropsType) {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import React, { useMemo } from 'react';
|
|
7
7
|
|
|
8
|
-
import { last } from 'lodash';
|
|
8
|
+
import { isPlainObject, last } from 'lodash';
|
|
9
9
|
import {
|
|
10
10
|
type ArrayType,
|
|
11
11
|
ASTMatch,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
import { TreeNodeData } from '@douyinfe/semi-ui/lib/es/tree';
|
|
17
17
|
import { Tree } from '@douyinfe/semi-ui';
|
|
18
18
|
|
|
19
|
-
import {
|
|
19
|
+
import { FlowValueUtils } from '@/shared';
|
|
20
20
|
|
|
21
21
|
type VariableField = BaseVariableField<{ icon?: string | JSX.Element; title?: string }>;
|
|
22
22
|
|
|
@@ -24,7 +24,7 @@ export function InputsPicker({
|
|
|
24
24
|
inputsValues,
|
|
25
25
|
onSelect,
|
|
26
26
|
}: {
|
|
27
|
-
inputsValues:
|
|
27
|
+
inputsValues: any;
|
|
28
28
|
onSelect: (v: string) => void;
|
|
29
29
|
}) {
|
|
30
30
|
const available = useScopeAvailable();
|
|
@@ -76,23 +76,40 @@ export function InputsPicker({
|
|
|
76
76
|
};
|
|
77
77
|
};
|
|
78
78
|
|
|
79
|
-
const
|
|
80
|
-
()
|
|
81
|
-
Object.entries(inputsValues).map(([key, value]) => {
|
|
82
|
-
if (value?.type === 'ref') {
|
|
83
|
-
const variable = available.getByKeyPath(value.content || []);
|
|
79
|
+
const getTreeData = (value: any, keyPath: string[]): TreeNodeData | undefined => {
|
|
80
|
+
const currKey = keyPath.join('.');
|
|
84
81
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
82
|
+
if (FlowValueUtils.isFlowValue(value)) {
|
|
83
|
+
if (FlowValueUtils.isRef(value)) {
|
|
84
|
+
const variable = available.getByKeyPath(value.content || []);
|
|
85
|
+
if (variable) {
|
|
86
|
+
return renderVariable(variable, keyPath);
|
|
88
87
|
}
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
key: currKey,
|
|
91
|
+
value: currKey,
|
|
92
|
+
label: last(keyPath),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
89
95
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
+
if (isPlainObject(value)) {
|
|
97
|
+
return {
|
|
98
|
+
key: currKey,
|
|
99
|
+
value: currKey,
|
|
100
|
+
label: last(keyPath),
|
|
101
|
+
children: Object.entries(value)
|
|
102
|
+
.map(([key, value]) => getTreeData(value, [...keyPath, key])!)
|
|
103
|
+
.filter(Boolean),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const treeData: TreeNodeData[] = useMemo(
|
|
109
|
+
() =>
|
|
110
|
+
Object.entries(inputsValues)
|
|
111
|
+
.map(([key, value]) => getTreeData(value, [key])!)
|
|
112
|
+
.filter(Boolean),
|
|
96
113
|
[]
|
|
97
114
|
);
|
|
98
115
|
|
|
@@ -143,7 +143,7 @@ export function VariableTagInject() {
|
|
|
143
143
|
// 基于 {{var}} 的正则进行匹配,匹配后进行自定义渲染
|
|
144
144
|
useLayoutEffect(() => {
|
|
145
145
|
const atMatcher = new MatchDecorator({
|
|
146
|
-
regexp: /\{\{([^\}]+)\}\}/g,
|
|
146
|
+
regexp: /\{\{([^\}\{]+)\}\}/g,
|
|
147
147
|
decoration: (match) =>
|
|
148
148
|
Decoration.replace({
|
|
149
149
|
widget: new VariableTagWidget({
|
|
@@ -30,8 +30,20 @@ export function VariableTree() {
|
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
/**
|
|
34
|
+
* When user input {{xxxx}}, {{{xxx}}}(more brackets if possible), replace all brackets with {{xxxx}}
|
|
35
|
+
*/
|
|
36
|
+
let { from, to } = range;
|
|
37
|
+
while (editor.$view.state.doc.sliceString(from - 1, from) === '{') {
|
|
38
|
+
from--;
|
|
39
|
+
}
|
|
40
|
+
while (editor.$view.state.doc.sliceString(to, to + 1) === '}') {
|
|
41
|
+
to++;
|
|
42
|
+
}
|
|
43
|
+
|
|
33
44
|
editor.replaceText({
|
|
34
|
-
|
|
45
|
+
from,
|
|
46
|
+
to,
|
|
35
47
|
text: '{{' + variablePath + '}}',
|
|
36
48
|
});
|
|
37
49
|
|
|
@@ -86,12 +86,22 @@ export function TypeSelector(props: TypeSelectorProps) {
|
|
|
86
86
|
[]
|
|
87
87
|
);
|
|
88
88
|
|
|
89
|
+
const isDisabled = readonly || disabled;
|
|
90
|
+
|
|
89
91
|
return (
|
|
90
92
|
<Cascader
|
|
91
|
-
disabled={
|
|
93
|
+
disabled={isDisabled}
|
|
92
94
|
size="small"
|
|
93
95
|
triggerRender={() => (
|
|
94
|
-
<IconButton
|
|
96
|
+
<IconButton
|
|
97
|
+
size="small"
|
|
98
|
+
style={{
|
|
99
|
+
...(isDisabled ? { pointerEvents: 'none' } : {}),
|
|
100
|
+
...(style || {}),
|
|
101
|
+
}}
|
|
102
|
+
disabled={isDisabled}
|
|
103
|
+
icon={icon}
|
|
104
|
+
/>
|
|
95
105
|
)}
|
|
96
106
|
treeData={options}
|
|
97
107
|
value={selectValue}
|
package/src/index.ts
CHANGED
|
@@ -121,7 +121,7 @@ export namespace FlowValueUtils {
|
|
|
121
121
|
*/
|
|
122
122
|
export function getTemplateKeyPaths(value: IFlowTemplateValue) {
|
|
123
123
|
// find all keyPath wrapped in {{}}
|
|
124
|
-
const keyPathReg =
|
|
124
|
+
const keyPathReg = /\{\{([^\}\{]+)\}\}/g;
|
|
125
125
|
return uniq(value.content?.match(keyPathReg) || []).map((_keyPath) =>
|
|
126
126
|
_keyPath.slice(2, -2).split('.')
|
|
127
127
|
);
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
* SPDX-License-Identifier: MIT
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { isNil
|
|
6
|
+
import { isNil } from 'lodash';
|
|
7
7
|
import { FeedbackLevel, FlowNodeEntity, getNodeScope } from '@flowgram.ai/editor';
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import { IFlowValue } from '@/typings';
|
|
10
|
+
import { FlowValueUtils } from '@/shared';
|
|
10
11
|
|
|
11
12
|
interface Context {
|
|
12
13
|
node: FlowNodeEntity;
|
|
@@ -43,7 +44,7 @@ export function validateFlowValue(value: IFlowValue | undefined, ctx: Context) {
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
if (value?.type === 'template') {
|
|
46
|
-
const allRefs = getTemplateKeyPaths(value);
|
|
47
|
+
const allRefs = FlowValueUtils.getTemplateKeyPaths(value);
|
|
47
48
|
|
|
48
49
|
for (const ref of allRefs) {
|
|
49
50
|
const variable = getNodeScope(node).available.getByKeyPath(ref);
|
|
@@ -58,16 +59,3 @@ export function validateFlowValue(value: IFlowValue | undefined, ctx: Context) {
|
|
|
58
59
|
|
|
59
60
|
return undefined;
|
|
60
61
|
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* get template key paths
|
|
64
|
-
* @param value
|
|
65
|
-
* @returns
|
|
66
|
-
*/
|
|
67
|
-
function getTemplateKeyPaths(value: IFlowTemplateValue) {
|
|
68
|
-
// find all keyPath wrapped in {{}}
|
|
69
|
-
const keyPathReg = /{{(.*?)}}/g;
|
|
70
|
-
return uniq(value.content?.match(keyPathReg) || []).map((_keyPath) =>
|
|
71
|
-
_keyPath.slice(2, -2).split('.')
|
|
72
|
-
);
|
|
73
|
-
}
|