@flowgram.ai/form-materials 0.1.0-alpha.10 → 0.1.0-alpha.12

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.
Files changed (126) hide show
  1. package/bin/index.ts +11 -5
  2. package/bin/materials.ts +10 -1
  3. package/dist/esm/index.js +1996 -1361
  4. package/dist/esm/index.js.map +1 -1
  5. package/dist/index.d.mts +328 -114
  6. package/dist/index.d.ts +328 -114
  7. package/dist/index.js +2096 -1472
  8. package/dist/index.js.map +1 -1
  9. package/package.json +7 -5
  10. package/src/components/assign-row/components/blur-input.tsx +27 -0
  11. package/src/components/assign-row/config.json +11 -0
  12. package/src/components/assign-row/index.tsx +84 -0
  13. package/src/components/assign-row/types.ts +25 -0
  14. package/src/components/assign-rows/config.json +11 -0
  15. package/src/components/assign-rows/index.tsx +59 -0
  16. package/src/components/batch-outputs/config.json +2 -1
  17. package/src/components/batch-outputs/index.tsx +4 -12
  18. package/src/components/batch-variable-selector/config.json +6 -2
  19. package/src/components/batch-variable-selector/index.tsx +1 -1
  20. package/src/components/code-editor/config.json +2 -1
  21. package/src/components/code-editor/index.tsx +23 -1
  22. package/src/components/code-editor/language-features.ts +23 -3
  23. package/src/components/code-editor/theme/light.ts +2 -2
  24. package/src/components/code-editor-mini/config.json +7 -0
  25. package/src/components/code-editor-mini/index.tsx +31 -0
  26. package/src/components/condition-row/config.json +10 -2
  27. package/src/components/condition-row/constants.ts +6 -8
  28. package/src/components/condition-row/hooks/useOp.tsx +3 -1
  29. package/src/components/condition-row/hooks/useRule.ts +2 -2
  30. package/src/components/condition-row/index.tsx +2 -1
  31. package/src/components/condition-row/types.ts +3 -1
  32. package/src/components/constant-input/config.json +6 -3
  33. package/src/components/constant-input/index.tsx +18 -62
  34. package/src/components/constant-input/types.ts +6 -9
  35. package/src/components/display-flow-value/config.json +8 -0
  36. package/src/components/display-flow-value/index.tsx +59 -0
  37. package/src/components/display-inputs-values/config.json +9 -0
  38. package/src/components/display-inputs-values/index.tsx +27 -0
  39. package/src/components/display-inputs-values/styles.ts +12 -0
  40. package/src/components/display-outputs/config.json +10 -0
  41. package/src/components/display-outputs/index.tsx +64 -0
  42. package/src/components/display-outputs/styles.ts +12 -0
  43. package/src/components/display-schema-tag/config.json +10 -0
  44. package/src/components/display-schema-tag/index.tsx +44 -0
  45. package/src/components/display-schema-tag/styles.ts +28 -0
  46. package/src/components/display-schema-tree/config.json +11 -0
  47. package/src/components/display-schema-tree/index.tsx +74 -0
  48. package/src/components/display-schema-tree/styles.tsx +90 -0
  49. package/src/components/dynamic-value-input/config.json +11 -2
  50. package/src/components/dynamic-value-input/hooks.ts +53 -0
  51. package/src/components/dynamic-value-input/index.tsx +64 -13
  52. package/src/components/dynamic-value-input/styles.tsx +28 -2
  53. package/src/components/index.ts +9 -0
  54. package/src/components/inputs-values/components/blur-input.tsx +27 -0
  55. package/src/components/inputs-values/config.json +13 -0
  56. package/src/components/inputs-values/index.tsx +73 -0
  57. package/src/components/inputs-values/styles.tsx +19 -0
  58. package/src/components/inputs-values/types.ts +22 -0
  59. package/src/components/json-editor-with-variables/index.tsx +47 -1
  60. package/src/components/json-schema-editor/config.json +2 -2
  61. package/src/components/json-schema-editor/default-value.tsx +1 -1
  62. package/src/components/json-schema-editor/hooks.tsx +4 -2
  63. package/src/components/json-schema-editor/index.tsx +15 -2
  64. package/src/components/json-schema-editor/types.ts +1 -1
  65. package/src/components/prompt-editor/index.tsx +2 -1
  66. package/src/components/prompt-editor/types.tsx +1 -0
  67. package/src/components/prompt-editor-with-inputs/inputs-picker.tsx +1 -1
  68. package/src/components/prompt-editor-with-variables/extensions/variable-tag.tsx +6 -3
  69. package/src/components/type-selector/config.json +6 -2
  70. package/src/components/type-selector/index.tsx +55 -12
  71. package/src/components/variable-selector/config.json +6 -2
  72. package/src/components/variable-selector/index.tsx +34 -13
  73. package/src/components/variable-selector/styles.tsx +18 -8
  74. package/src/components/variable-selector/use-variable-tree.tsx +19 -22
  75. package/src/effects/auto-rename-ref/index.ts +59 -8
  76. package/src/effects/index.ts +3 -1
  77. package/src/effects/listen-ref-schema-change/config.json +10 -0
  78. package/src/effects/listen-ref-schema-change/index.ts +56 -0
  79. package/src/effects/listen-ref-value-change/config.json +9 -0
  80. package/src/effects/listen-ref-value-change/index.ts +53 -0
  81. package/src/effects/provide-json-schema-outputs/config.json +4 -5
  82. package/src/effects/provide-json-schema-outputs/index.ts +1 -3
  83. package/src/effects/sync-variable-title/index.ts +1 -0
  84. package/src/effects/validate-when-variable-sync/config.json +5 -0
  85. package/src/effects/validate-when-variable-sync/index.ts +35 -0
  86. package/src/form-plugins/index.ts +3 -1
  87. package/src/form-plugins/infer-assign-plugin/config.json +7 -0
  88. package/src/form-plugins/infer-assign-plugin/index.ts +90 -0
  89. package/src/form-plugins/infer-inputs-plugin/config.json +9 -0
  90. package/src/form-plugins/infer-inputs-plugin/index.ts +108 -0
  91. package/src/hooks/index.tsx +6 -0
  92. package/src/hooks/use-object-list/config.json +8 -0
  93. package/src/hooks/use-object-list/index.tsx +136 -0
  94. package/src/index.ts +3 -1
  95. package/src/{typings/json-schema → plugins/disable-declaration-plugin}/config.json +1 -1
  96. package/src/plugins/disable-declaration-plugin/create-disable-declaration-plugin.ts +31 -0
  97. package/src/plugins/disable-declaration-plugin/index.tsx +6 -0
  98. package/src/plugins/index.ts +7 -0
  99. package/src/plugins/json-schema-preset/config.json +9 -0
  100. package/src/plugins/json-schema-preset/create-type-preset-plugin.tsx +28 -0
  101. package/src/plugins/json-schema-preset/index.tsx +41 -0
  102. package/src/plugins/json-schema-preset/manager.ts +18 -0
  103. package/src/plugins/json-schema-preset/type-definition/array.tsx +24 -0
  104. package/src/plugins/json-schema-preset/type-definition/boolean.tsx +32 -0
  105. package/src/plugins/json-schema-preset/type-definition/index.tsx +24 -0
  106. package/src/plugins/json-schema-preset/type-definition/integer.tsx +24 -0
  107. package/src/plugins/json-schema-preset/type-definition/number.tsx +24 -0
  108. package/src/plugins/json-schema-preset/type-definition/object.tsx +24 -0
  109. package/src/plugins/json-schema-preset/type-definition/string.tsx +18 -0
  110. package/src/{utils → shared}/index.ts +0 -1
  111. package/src/typings/flow-value/config.json +3 -1
  112. package/src/typings/flow-value/index.ts +11 -0
  113. package/src/typings/index.ts +0 -1
  114. package/src/validate/index.tsx +6 -0
  115. package/src/validate/validate-flow-value/config.json +7 -0
  116. package/src/validate/validate-flow-value/index.tsx +73 -0
  117. package/src/components/batch-outputs/use-list.ts +0 -86
  118. package/src/components/type-selector/constants.tsx +0 -364
  119. package/src/effects/provide-batch-outputs/config.json +0 -5
  120. package/src/effects/provide-batch-outputs/index.ts +0 -38
  121. package/src/typings/json-schema/index.ts +0 -36
  122. package/src/utils/json-schema/config.json +0 -5
  123. package/src/utils/json-schema/index.ts +0 -180
  124. /package/src/{utils → shared}/format-legacy-refs/config.json +0 -0
  125. /package/src/{utils → shared}/format-legacy-refs/index.ts +0 -0
  126. /package/src/{utils → shared}/format-legacy-refs/readme.md +0 -0
@@ -5,18 +5,26 @@
5
5
 
6
6
  import React, { useMemo } from 'react';
7
7
 
8
- import { Button, Cascader } from '@douyinfe/semi-ui';
8
+ import { IJsonSchema } from '@flowgram.ai/json-schema';
9
+ import { Cascader, Icon, IconButton } from '@douyinfe/semi-ui';
9
10
 
10
- import { IJsonSchema } from '../../typings';
11
- import { ArrayIcons, VariableTypeIcons, getSchemaIcon, options } from './constants';
11
+ import { useTypeManager } from '../../plugins';
12
12
 
13
13
  interface PropTypes {
14
14
  value?: Partial<IJsonSchema>;
15
- onChange: (value?: Partial<IJsonSchema>) => void;
15
+ onChange?: (value?: Partial<IJsonSchema>) => void;
16
+ readonly?: boolean;
17
+ /**
18
+ * @deprecated use readonly instead
19
+ */
16
20
  disabled?: boolean;
17
21
  style?: React.CSSProperties;
18
22
  }
19
23
 
24
+ const labelStyle: React.CSSProperties = { display: 'flex', alignItems: 'center', gap: 5 };
25
+
26
+ const firstUppercase = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);
27
+
20
28
  export const getTypeSelectValue = (value?: Partial<IJsonSchema>): string[] | undefined => {
21
29
  if (value?.type === 'array' && value?.items) {
22
30
  return [value.type, ...(getTypeSelectValue(value.items) || [])];
@@ -36,27 +44,62 @@ export const parseTypeSelectValue = (value?: string[]): Partial<IJsonSchema> | u
36
44
  };
37
45
 
38
46
  export function TypeSelector(props: PropTypes) {
39
- const { value, onChange, disabled, style } = props;
47
+ const { value, onChange, readonly, disabled, style } = props;
40
48
 
41
49
  const selectValue = useMemo(() => getTypeSelectValue(value), [value]);
42
50
 
51
+ const typeManager = useTypeManager();
52
+
53
+ const icon = typeManager.getDisplayIcon(value || {});
54
+
55
+ const options = useMemo(
56
+ () =>
57
+ typeManager.getTypeRegistriesWithParentType().map((_type) => {
58
+ const isArray = _type.type === 'array';
59
+
60
+ return {
61
+ label: (
62
+ <div style={labelStyle}>
63
+ <Icon size="small" svg={_type.icon} />
64
+ {firstUppercase(_type.type)}
65
+ </div>
66
+ ),
67
+ value: _type.type,
68
+ children: isArray
69
+ ? typeManager.getTypeRegistriesWithParentType('array').map((_type) => ({
70
+ label: (
71
+ <div style={labelStyle}>
72
+ <Icon
73
+ size="small"
74
+ svg={typeManager.getDisplayIcon({
75
+ type: 'array',
76
+ items: { type: _type.type },
77
+ })}
78
+ />
79
+ {firstUppercase(_type.type)}
80
+ </div>
81
+ ),
82
+ value: _type.type,
83
+ }))
84
+ : [],
85
+ };
86
+ }),
87
+ []
88
+ );
89
+
43
90
  return (
44
91
  <Cascader
45
- disabled={disabled}
92
+ disabled={readonly || disabled}
46
93
  size="small"
47
94
  triggerRender={() => (
48
- <Button size="small" style={style}>
49
- {getSchemaIcon(value)}
50
- </Button>
95
+ <IconButton size="small" style={style} disabled={readonly || disabled} icon={icon} />
51
96
  )}
52
97
  treeData={options}
53
98
  value={selectValue}
54
99
  leafOnly={true}
55
100
  onChange={(value) => {
56
- onChange(parseTypeSelectValue(value as string[]));
101
+ onChange?.(parseTypeSelectValue(value as string[]));
57
102
  }}
58
103
  />
59
104
  );
60
105
  }
61
-
62
- export { VariableTypeIcons, ArrayIcons, getSchemaIcon };
@@ -1,5 +1,9 @@
1
1
  {
2
2
  "name": "variable-selector",
3
- "depMaterials": ["type-selector", "utils/json-schema", "typings/json-schema"],
4
- "depPackages": ["@douyinfe/semi-ui", "styled-components"]
3
+ "depMaterials": [],
4
+ "depPackages": [
5
+ "@douyinfe/semi-ui",
6
+ "styled-components",
7
+ "@flowgram.ai/json-schema"
8
+ ]
5
9
  }
@@ -5,13 +5,14 @@
5
5
 
6
6
  import React, { useMemo } from 'react';
7
7
 
8
+ import { IJsonSchema } from '@flowgram.ai/json-schema';
8
9
  import { TriggerRenderProps } from '@douyinfe/semi-ui/lib/es/treeSelect';
9
10
  import { TreeNodeData } from '@douyinfe/semi-ui/lib/es/tree';
11
+ import { Popover } from '@douyinfe/semi-ui';
10
12
  import { IconChevronDownStroked, IconIssueStroked } from '@douyinfe/semi-icons';
11
13
 
12
- import { IJsonSchema } from '../../typings/json-schema';
13
14
  import { useVariableTree } from './use-variable-tree';
14
- import { UIRootTitle, UITag, UITreeSelect, UIVarName } from './styles';
15
+ import { UIPopoverContent, UIRootTitle, UITag, UITreeSelect, UIVarName } from './styles';
15
16
 
16
17
  interface PropTypes {
17
18
  value?: string[];
@@ -93,23 +94,43 @@ export const VariableSelector = ({
93
94
  );
94
95
  }
95
96
 
97
+ const rootIcon = renderIcon(_option.rootMeta?.icon || _option?.icon);
98
+
99
+ const rootTitle = (
100
+ <UIRootTitle>
101
+ {_option.rootMeta?.title
102
+ ? `${_option.rootMeta?.title} ${_option.isRoot ? '' : '-'} `
103
+ : null}
104
+ </UIRootTitle>
105
+ );
106
+
96
107
  return (
97
- <UITag
98
- prefixIcon={renderIcon(_option.rootMeta?.icon || _option?.icon)}
99
- closable={!readonly}
100
- onClose={() => onChange(undefined)}
101
- >
102
- <UIRootTitle>
103
- {_option.rootMeta?.title ? `${_option.rootMeta?.title} -` : null}
104
- </UIRootTitle>
105
- <UIVarName>{_option.label}</UIVarName>
106
- </UITag>
108
+ <div>
109
+ <Popover
110
+ content={
111
+ <UIPopoverContent>
112
+ {rootIcon}
113
+ {rootTitle}
114
+ <UIVarName>{_option.keyPath.slice(1).join('.')}</UIVarName>
115
+ </UIPopoverContent>
116
+ }
117
+ >
118
+ <UITag
119
+ prefixIcon={rootIcon}
120
+ closable={!readonly}
121
+ onClose={() => onChange(undefined)}
122
+ >
123
+ {rootTitle}
124
+ {!_option.isRoot && <UIVarName $inSelector>{_option.label}</UIVarName>}
125
+ </UITag>
126
+ </Popover>
127
+ </div>
107
128
  );
108
129
  }}
109
130
  showClear={false}
110
131
  arrowIcon={<IconChevronDownStroked size="small" />}
111
132
  triggerRender={triggerRender}
112
- placeholder={config?.placeholder ?? 'Select Variable...'}
133
+ placeholder={config?.placeholder ?? 'Select Variable'}
113
134
  />
114
135
  </>
115
136
  );
@@ -3,7 +3,7 @@
3
3
  * SPDX-License-Identifier: MIT
4
4
  */
5
5
 
6
- import styled from 'styled-components';
6
+ import styled, { css } from 'styled-components';
7
7
  import { Tag, TreeSelect } from '@douyinfe/semi-ui';
8
8
 
9
9
  export const UIRootTitle = styled.div`
@@ -15,11 +15,16 @@ export const UIRootTitle = styled.div`
15
15
  color: var(--semi-color-text-2);
16
16
  `;
17
17
 
18
- export const UIVarName = styled.div`
18
+ export const UIVarName = styled.div<{ $inSelector?: boolean }>`
19
19
  overflow: hidden;
20
20
  text-overflow: ellipsis;
21
21
  white-space: nowrap;
22
- min-width: 50%;
22
+
23
+ ${({ $inSelector }) =>
24
+ $inSelector &&
25
+ css`
26
+ min-width: 50%;
27
+ `}
23
28
  `;
24
29
 
25
30
  export const UITag = styled(Tag)`
@@ -34,18 +39,15 @@ export const UITag = styled(Tag)`
34
39
 
35
40
  &.semi-tag {
36
41
  margin: 0;
42
+ height: 22px;
37
43
  }
38
44
  `;
39
45
 
40
46
  export const UITreeSelect = styled(TreeSelect)<{ $error?: boolean }>`
41
47
  outline: ${({ $error }) => ($error ? '1px solid red' : 'none')};
42
48
 
43
- height: 22px;
44
- min-height: 22px;
45
- line-height: 22px;
46
-
47
49
  & .semi-tree-select-selection {
48
- padding: 0 2px;
50
+ padding: 0px;
49
51
  height: 22px;
50
52
  }
51
53
 
@@ -57,3 +59,11 @@ export const UITreeSelect = styled(TreeSelect)<{ $error?: boolean }>`
57
59
  padding-left: 10px;
58
60
  }
59
61
  `;
62
+
63
+ export const UIPopoverContent = styled.div`
64
+ padding: 10px;
65
+ display: inline-flex;
66
+ align-items: center;
67
+ justify-content: flex-start;
68
+ white-space: nowrap;
69
+ `;
@@ -5,22 +5,27 @@
5
5
 
6
6
  import React, { useCallback } from 'react';
7
7
 
8
+ import { IJsonSchema, JsonSchemaUtils } from '@flowgram.ai/json-schema';
8
9
  import { ASTMatch, BaseVariableField, useAvailableVariables } from '@flowgram.ai/editor';
9
10
  import { TreeNodeData } from '@douyinfe/semi-ui/lib/es/tree';
10
11
  import { Icon } from '@douyinfe/semi-ui';
11
12
 
12
- import { ArrayIcons, VariableTypeIcons } from '../type-selector/constants';
13
- import { JsonSchemaUtils } from '../../utils/json-schema';
14
- import { IJsonSchema } from '../../typings/json-schema';
13
+ import { useTypeManager } from '../../plugins';
15
14
 
16
- type VariableField = BaseVariableField<{ icon?: string | JSX.Element; title?: string }>;
15
+ type VariableField = BaseVariableField<{
16
+ icon?: string | JSX.Element;
17
+ title?: string;
18
+ disabled?: boolean;
19
+ }>;
17
20
 
18
21
  export function useVariableTree(params: {
19
22
  includeSchema?: IJsonSchema | IJsonSchema[];
20
23
  excludeSchema?: IJsonSchema | IJsonSchema[];
24
+ customSkip?: (variable: VariableField) => boolean;
21
25
  }): TreeNodeData[] {
22
- const { includeSchema, excludeSchema } = params;
26
+ const { includeSchema, excludeSchema, customSkip } = params;
23
27
 
28
+ const typeManager = useTypeManager();
24
29
  const variables = useAvailableVariables();
25
30
 
26
31
  const getVariableTypeIcon = useCallback((variable: VariableField) => {
@@ -32,22 +37,9 @@ export function useVariableTree(params: {
32
37
  return variable.meta.icon;
33
38
  }
34
39
 
35
- const _type = variable.type;
40
+ const schema = JsonSchemaUtils.astToSchema(variable.type, { drilldownObject: false });
36
41
 
37
- if (ASTMatch.isArray(_type)) {
38
- return (
39
- <Icon
40
- size="small"
41
- svg={ArrayIcons[_type.items?.kind.toLowerCase()] || VariableTypeIcons.array}
42
- />
43
- );
44
- }
45
-
46
- if (ASTMatch.isCustomType(_type)) {
47
- return <Icon size="small" svg={VariableTypeIcons[_type.typeName.toLowerCase()]} />;
48
- }
49
-
50
- return <Icon size="small" svg={VariableTypeIcons[variable.type?.kind.toLowerCase()]} />;
42
+ return <Icon size="small" svg={typeManager.getDisplayIcon(schema || {})} />;
51
43
  }, []);
52
44
 
53
45
  const renderVariable = (
@@ -77,8 +69,12 @@ export function useVariableTree(params: {
77
69
  const isSchemaExclude = excludeSchema
78
70
  ? JsonSchemaUtils.isASTMatchSchema(type, excludeSchema)
79
71
  : false;
72
+ const isCustomSkip = customSkip ? customSkip(variable) : false;
73
+
74
+ // disabled in meta when created
75
+ const isMetaDisabled = variable.meta?.disabled;
80
76
 
81
- const isSchemaMatch = isSchemaInclude && !isSchemaExclude;
77
+ const isSchemaMatch = isSchemaInclude && !isSchemaExclude && !isCustomSkip && !isMetaDisabled;
82
78
 
83
79
  // If not match, and no children, return null
84
80
  if (!isSchemaMatch && !children?.length) {
@@ -93,7 +89,8 @@ export function useVariableTree(params: {
93
89
  icon: getVariableTypeIcon(variable),
94
90
  children,
95
91
  disabled: !isSchemaMatch,
96
- rootMeta: parentFields[0]?.meta,
92
+ rootMeta: parentFields[0]?.meta || variable.meta,
93
+ isRoot: !parentFields?.length,
97
94
  };
98
95
  };
99
96
 
@@ -3,7 +3,7 @@
3
3
  * SPDX-License-Identifier: MIT
4
4
  */
5
5
 
6
- import { isArray, isObject } from 'lodash';
6
+ import { isArray, isObject, uniq } from 'lodash';
7
7
  import {
8
8
  DataEvent,
9
9
  Effect,
@@ -11,7 +11,7 @@ import {
11
11
  VariableFieldKeyRenameService,
12
12
  } from '@flowgram.ai/editor';
13
13
 
14
- import { IFlowRefValue } from '../../typings';
14
+ import { IFlowRefValue, IFlowTemplateValue } from '../../typings';
15
15
 
16
16
  /**
17
17
  * Auto rename ref when form item's key is renamed
@@ -44,9 +44,34 @@ export const autoRenameRefEffect: EffectOptions[] = [
44
44
 
45
45
  // traverse rename refs inside form item 'name'
46
46
  traverseRef(name, form.getValueIn(name), (_drilldownName, _v) => {
47
- if (isRefMatch(_v, beforeKeyPath)) {
48
- _v.content = [...afterKeyPath, ...(_v.content || [])?.slice(beforeKeyPath.length)];
49
- form.setValueIn(_drilldownName, _v);
47
+ if (_v.type === 'ref') {
48
+ // ref auto rename
49
+ if (isKeyPathMatch(_v.content, beforeKeyPath)) {
50
+ _v.content = [...afterKeyPath, ...(_v.content || [])?.slice(beforeKeyPath.length)];
51
+ form.setValueIn(_drilldownName, _v);
52
+ }
53
+ } else if (_v.type === 'template') {
54
+ // template auto rename
55
+ const templateKeyPaths = getTemplateKeyPaths(_v);
56
+ let hasMatch = false;
57
+
58
+ templateKeyPaths.forEach((_keyPath) => {
59
+ if (isKeyPathMatch(_keyPath, beforeKeyPath)) {
60
+ hasMatch = true;
61
+ const nextKeyPath = [
62
+ ...afterKeyPath,
63
+ ...(_keyPath || [])?.slice(beforeKeyPath.length),
64
+ ];
65
+ _v.content = _v.content?.replace(
66
+ `{{${_keyPath.join('.')}}`,
67
+ `{{${nextKeyPath.join('.')}}`
68
+ );
69
+ }
70
+ });
71
+
72
+ if (hasMatch) {
73
+ form.setValueIn(_drilldownName, { ..._v });
74
+ }
50
75
  }
51
76
  });
52
77
  });
@@ -64,8 +89,21 @@ export const autoRenameRefEffect: EffectOptions[] = [
64
89
  * @param targetKeyPath
65
90
  * @returns
66
91
  */
67
- function isRefMatch(value: IFlowRefValue, targetKeyPath: string[]) {
68
- return targetKeyPath.every((_key, index) => _key === value.content?.[index]);
92
+ function isKeyPathMatch(keyPath: string[] = [], targetKeyPath: string[]) {
93
+ return targetKeyPath.every((_key, index) => _key === keyPath[index]);
94
+ }
95
+
96
+ /**
97
+ * get template key paths
98
+ * @param value
99
+ * @returns
100
+ */
101
+ function getTemplateKeyPaths(value: IFlowTemplateValue) {
102
+ // find all keyPath wrapped in {{}}
103
+ const keyPathReg = /{{(.*?)}}/g;
104
+ return uniq(value.content?.match(keyPathReg) || []).map((_keyPath) =>
105
+ _keyPath.slice(2, -2).split('.')
106
+ );
69
107
  }
70
108
 
71
109
  /**
@@ -79,19 +117,32 @@ function isRef(value: any): value is IFlowRefValue {
79
117
  );
80
118
  }
81
119
 
120
+ function isTemplate(value: any): value is IFlowTemplateValue {
121
+ return value?.type === 'template' && typeof value?.content === 'string';
122
+ }
123
+
82
124
  /**
83
125
  * Traverse value to find ref
84
126
  * @param value
85
127
  * @param options
86
128
  * @returns
87
129
  */
88
- function traverseRef(name: string, value: any, cb: (name: string, _v: IFlowRefValue) => void) {
130
+ function traverseRef(
131
+ name: string,
132
+ value: any,
133
+ cb: (name: string, _v: IFlowRefValue | IFlowTemplateValue) => void
134
+ ) {
89
135
  if (isObject(value)) {
90
136
  if (isRef(value)) {
91
137
  cb(name, value);
92
138
  return;
93
139
  }
94
140
 
141
+ if (isTemplate(value)) {
142
+ cb(name, value);
143
+ return;
144
+ }
145
+
95
146
  Object.entries(value).forEach(([_key, _value]) => {
96
147
  traverseRef(`${name}.${_key}`, _value, cb);
97
148
  });
@@ -4,7 +4,9 @@
4
4
  */
5
5
 
6
6
  export * from './provide-batch-input';
7
- export * from './provide-batch-outputs';
8
7
  export * from './auto-rename-ref';
9
8
  export * from './provide-json-schema-outputs';
10
9
  export * from './sync-variable-title';
10
+ export * from './validate-when-variable-sync';
11
+ export * from './listen-ref-value-change';
12
+ export * from './listen-ref-schema-change';
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "listen-ref-schema-change",
3
+ "depMaterials": [
4
+ "flow-value"
5
+ ],
6
+ "depPackages": [
7
+ "lodash",
8
+ "@flowgram.ai/json-schema"
9
+ ]
10
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { IJsonSchema, JsonSchemaUtils } from '@flowgram.ai/json-schema';
7
+ import {
8
+ BaseType,
9
+ DataEvent,
10
+ Effect,
11
+ EffectFuncProps,
12
+ EffectOptions,
13
+ getNodeScope,
14
+ } from '@flowgram.ai/editor';
15
+
16
+ import { IFlowRefValue } from '../../typings';
17
+
18
+ /**
19
+ * Example:
20
+ * const formMeta = {
21
+ * effect: {
22
+ * 'inputsValues.*': listenRefSchemaChange(({ name, schema, form }) => {
23
+ * form.setValueIn(`${name}.schema`, schema);
24
+ * })
25
+ * }
26
+ * }
27
+ * @param cb
28
+ * @returns
29
+ */
30
+ export const listenRefSchemaChange = (
31
+ cb: (props: EffectFuncProps<IFlowRefValue> & { schema?: IJsonSchema }) => void
32
+ ): EffectOptions[] => [
33
+ {
34
+ event: DataEvent.onValueInitOrChange,
35
+ effect: ((params) => {
36
+ const { context, value } = params;
37
+
38
+ if (value?.type !== 'ref') {
39
+ return () => null;
40
+ }
41
+
42
+ const disposable = getNodeScope(context.node).available.trackByKeyPath<BaseType | undefined>(
43
+ value?.content || [],
44
+ (_type) => {
45
+ cb({ ...params, schema: JsonSchemaUtils.astToSchema(_type) });
46
+ },
47
+ {
48
+ selector: (_v) => _v?.type,
49
+ }
50
+ );
51
+ return () => {
52
+ disposable.dispose();
53
+ };
54
+ }) as Effect,
55
+ },
56
+ ];
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "listen-ref-value-change",
3
+ "depMaterials": [
4
+ "flow-value"
5
+ ],
6
+ "depPackages": [
7
+ "lodash"
8
+ ]
9
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import {
7
+ BaseVariableField,
8
+ DataEvent,
9
+ Effect,
10
+ EffectFuncProps,
11
+ EffectOptions,
12
+ getNodeScope,
13
+ } from '@flowgram.ai/editor';
14
+
15
+ import { IFlowRefValue } from '../../typings';
16
+
17
+ /**
18
+ * Example:
19
+ * const formMeta = {
20
+ * effect: {
21
+ * 'inputsValues.*': listenRefValueChange(({ name, variable, form }) => {
22
+ * const schema = JsonSchemaUtils.astToSchema(variable?.type);
23
+ * form.setValueIn(`${name}.schema`, schema);
24
+ * })
25
+ * }
26
+ * }
27
+ * @param cb
28
+ * @returns
29
+ */
30
+ export const listenRefValueChange = (
31
+ cb: (props: EffectFuncProps<IFlowRefValue> & { variable?: BaseVariableField }) => void
32
+ ): EffectOptions[] => [
33
+ {
34
+ event: DataEvent.onValueInitOrChange,
35
+ effect: ((params) => {
36
+ const { context, value } = params;
37
+
38
+ if (value?.type !== 'ref') {
39
+ return () => null;
40
+ }
41
+
42
+ const disposable = getNodeScope(context.node).available.trackByKeyPath(
43
+ value?.content || [],
44
+ (v) => {
45
+ cb({ ...params, variable: v });
46
+ }
47
+ );
48
+ return () => {
49
+ disposable.dispose();
50
+ };
51
+ }) as Effect,
52
+ },
53
+ ];
@@ -1,8 +1,7 @@
1
1
  {
2
2
  "name": "provide-json-schema-outputs",
3
- "depMaterials": [
4
- "typings/json-schema",
5
- "utils/json-schema"
6
- ],
7
- "depPackages": []
3
+ "depMaterials": [],
4
+ "depPackages": [
5
+ "@flowgram.ai/json-schema"
6
+ ]
8
7
  }
@@ -3,6 +3,7 @@
3
3
  * SPDX-License-Identifier: MIT
4
4
  */
5
5
 
6
+ import { JsonSchemaUtils, IJsonSchema } from '@flowgram.ai/json-schema';
6
7
  import {
7
8
  ASTFactory,
8
9
  EffectOptions,
@@ -11,9 +12,6 @@ import {
11
12
  getNodeForm,
12
13
  } from '@flowgram.ai/editor';
13
14
 
14
- import { JsonSchemaUtils } from '../../utils';
15
- import { IJsonSchema } from '../../typings';
16
-
17
15
  export const provideJsonSchemaOutputs: EffectOptions[] = createEffectFromVariableProvider({
18
16
  parse: (value: IJsonSchema, ctx) => [
19
17
  ASTFactory.createVariableDeclaration({
@@ -18,6 +18,7 @@ export const syncVariableTitle: EffectOptions[] = [
18
18
  context.node.getData(FlowNodeVariableData).allScopes.forEach((_scope) => {
19
19
  _scope.output.variables.forEach((_var) => {
20
20
  _var.updateMeta({
21
+ ...(_var.meta || {}),
21
22
  title: value || context.node.id,
22
23
  icon: context.node.getNodeRegistry<FlowNodeRegistry>().info?.icon,
23
24
  });
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "validate-when-variable-sync",
3
+ "depMaterials": [],
4
+ "depPackages": []
5
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { isEmpty } from 'lodash';
7
+ import {
8
+ DataEvent,
9
+ Effect,
10
+ EffectOptions,
11
+ getNodeScope,
12
+ getNodePrivateScope,
13
+ } from '@flowgram.ai/editor';
14
+
15
+ export const validateWhenVariableSync = ({
16
+ scope,
17
+ }: {
18
+ scope?: 'private' | 'public';
19
+ } = {}): EffectOptions[] => [
20
+ {
21
+ event: DataEvent.onValueInit,
22
+ effect: (({ context, form }) => {
23
+ const nodeScope =
24
+ scope === 'private' ? getNodePrivateScope(context.node) : getNodeScope(context.node);
25
+
26
+ const disposable = nodeScope.available.onListOrAnyVarChange(() => {
27
+ if (!isEmpty(form.state.errors)) {
28
+ form.validate();
29
+ }
30
+ });
31
+
32
+ return () => disposable.dispose();
33
+ }) as Effect,
34
+ },
35
+ ];
@@ -3,4 +3,6 @@
3
3
  * SPDX-License-Identifier: MIT
4
4
  */
5
5
 
6
- export { createBatchOutputsFormPlugin } from './batch-outputs-plugin';
6
+ export * from './batch-outputs-plugin';
7
+ export * from './infer-inputs-plugin';
8
+ export * from './infer-assign-plugin';