@flowgram.ai/form-materials 0.1.0-alpha.11 → 0.1.0-alpha.13

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 (133) hide show
  1. package/bin/index.ts +14 -22
  2. package/bin/materials.ts +41 -90
  3. package/bin/project.ts +4 -0
  4. package/bin/utils/import.ts +127 -0
  5. package/bin/utils/traverse-file.ts +60 -0
  6. package/dist/esm/index.js +2073 -1601
  7. package/dist/esm/index.js.map +1 -1
  8. package/dist/index.d.mts +392 -131
  9. package/dist/index.d.ts +392 -131
  10. package/dist/index.js +2175 -1710
  11. package/dist/index.js.map +1 -1
  12. package/package.json +5 -4
  13. package/src/components/assign-row/components/blur-input.tsx +27 -0
  14. package/src/components/assign-row/index.tsx +84 -0
  15. package/src/components/assign-row/types.ts +25 -0
  16. package/src/components/assign-rows/index.tsx +59 -0
  17. package/src/components/batch-outputs/index.tsx +7 -14
  18. package/src/components/batch-outputs/types.ts +1 -1
  19. package/src/components/batch-variable-selector/index.tsx +2 -2
  20. package/src/components/code-editor/index.tsx +7 -0
  21. package/src/components/code-editor/language-features.ts +22 -1
  22. package/src/components/code-editor/theme/light.ts +1 -1
  23. package/src/components/code-editor-mini/index.tsx +31 -0
  24. package/src/components/condition-row/constants.ts +8 -10
  25. package/src/components/condition-row/hooks/useOp.tsx +15 -9
  26. package/src/components/condition-row/hooks/useRule.ts +9 -5
  27. package/src/components/condition-row/index.tsx +28 -10
  28. package/src/components/condition-row/types.ts +5 -5
  29. package/src/components/constant-input/index.tsx +20 -61
  30. package/src/components/constant-input/types.ts +6 -9
  31. package/src/components/display-flow-value/index.tsx +59 -0
  32. package/src/components/display-inputs-values/index.tsx +28 -0
  33. package/src/components/display-inputs-values/styles.ts +12 -0
  34. package/src/components/display-outputs/index.tsx +65 -0
  35. package/src/components/display-outputs/styles.ts +12 -0
  36. package/src/components/display-schema-tag/index.tsx +45 -0
  37. package/src/components/display-schema-tag/styles.ts +28 -0
  38. package/src/components/display-schema-tree/index.tsx +75 -0
  39. package/src/components/display-schema-tree/styles.tsx +90 -0
  40. package/src/components/dynamic-value-input/hooks.ts +53 -0
  41. package/src/components/dynamic-value-input/index.tsx +74 -19
  42. package/src/components/dynamic-value-input/styles.tsx +28 -2
  43. package/src/components/index.ts +9 -0
  44. package/src/components/inputs-values/components/blur-input.tsx +27 -0
  45. package/src/components/inputs-values/index.tsx +75 -0
  46. package/src/components/inputs-values/styles.tsx +19 -0
  47. package/src/components/inputs-values/types.ts +22 -0
  48. package/src/components/json-editor-with-variables/extensions/variable-tree.tsx +1 -1
  49. package/src/components/json-editor-with-variables/index.tsx +2 -1
  50. package/src/components/json-schema-editor/default-value.tsx +12 -106
  51. package/src/components/json-schema-editor/hooks.tsx +53 -94
  52. package/src/components/json-schema-editor/index.tsx +32 -13
  53. package/src/components/json-schema-editor/styles.tsx +0 -29
  54. package/src/components/json-schema-editor/types.ts +1 -1
  55. package/src/components/prompt-editor/types.tsx +1 -1
  56. package/src/components/prompt-editor-with-inputs/extensions/inputs-tree.tsx +2 -1
  57. package/src/components/prompt-editor-with-inputs/index.tsx +3 -2
  58. package/src/components/prompt-editor-with-inputs/inputs-picker.tsx +2 -2
  59. package/src/components/prompt-editor-with-variables/extensions/variable-tag.tsx +6 -3
  60. package/src/components/prompt-editor-with-variables/extensions/variable-tree.tsx +1 -1
  61. package/src/components/prompt-editor-with-variables/index.tsx +2 -1
  62. package/src/components/type-selector/index.tsx +58 -13
  63. package/src/components/variable-selector/index.tsx +42 -17
  64. package/src/components/variable-selector/styles.tsx +18 -8
  65. package/src/components/variable-selector/use-variable-tree.tsx +19 -22
  66. package/src/effects/auto-rename-ref/index.ts +1 -1
  67. package/src/effects/index.ts +3 -1
  68. package/src/effects/listen-ref-schema-change/index.ts +56 -0
  69. package/src/effects/listen-ref-value-change/index.ts +53 -0
  70. package/src/effects/provide-batch-input/index.ts +1 -1
  71. package/src/effects/provide-json-schema-outputs/index.ts +1 -3
  72. package/src/effects/sync-variable-title/index.ts +1 -0
  73. package/src/effects/validate-when-variable-sync/index.ts +35 -0
  74. package/src/form-plugins/batch-outputs-plugin/index.ts +1 -1
  75. package/src/form-plugins/index.ts +3 -1
  76. package/src/form-plugins/infer-assign-plugin/index.ts +90 -0
  77. package/src/form-plugins/infer-inputs-plugin/index.ts +108 -0
  78. package/src/hooks/index.tsx +6 -0
  79. package/src/hooks/use-object-list/index.tsx +136 -0
  80. package/src/index.ts +3 -1
  81. package/src/{utils/format-legacy-refs → plugins/disable-declaration-plugin}/config.json +1 -1
  82. package/src/plugins/disable-declaration-plugin/create-disable-declaration-plugin.ts +31 -0
  83. package/src/plugins/disable-declaration-plugin/index.tsx +6 -0
  84. package/src/plugins/index.ts +7 -0
  85. package/src/plugins/json-schema-preset/config.json +9 -0
  86. package/src/plugins/json-schema-preset/create-type-preset-plugin.tsx +28 -0
  87. package/src/plugins/json-schema-preset/index.tsx +41 -0
  88. package/src/plugins/json-schema-preset/manager.ts +18 -0
  89. package/src/plugins/json-schema-preset/type-definition/array.tsx +26 -0
  90. package/src/plugins/json-schema-preset/type-definition/boolean.tsx +33 -0
  91. package/src/plugins/json-schema-preset/type-definition/index.tsx +24 -0
  92. package/src/plugins/json-schema-preset/type-definition/integer.tsx +25 -0
  93. package/src/plugins/json-schema-preset/type-definition/number.tsx +25 -0
  94. package/src/plugins/json-schema-preset/type-definition/object.tsx +26 -0
  95. package/src/plugins/json-schema-preset/type-definition/string.tsx +24 -0
  96. package/src/{utils → shared}/index.ts +1 -1
  97. package/src/shared/inject-material/README.md +170 -0
  98. package/src/shared/inject-material/README.zh.md +174 -0
  99. package/src/shared/inject-material/index.tsx +87 -0
  100. package/src/typings/flow-value/index.ts +11 -0
  101. package/src/typings/index.ts +0 -1
  102. package/src/validate/index.tsx +6 -0
  103. package/src/validate/validate-flow-value/index.tsx +73 -0
  104. package/src/components/batch-outputs/config.json +0 -12
  105. package/src/components/batch-outputs/use-list.ts +0 -86
  106. package/src/components/batch-variable-selector/config.json +0 -5
  107. package/src/components/code-editor/config.json +0 -10
  108. package/src/components/condition-row/config.json +0 -5
  109. package/src/components/constant-input/config.json +0 -6
  110. package/src/components/dynamic-value-input/config.json +0 -5
  111. package/src/components/json-editor-with-variables/config.json +0 -13
  112. package/src/components/json-schema-editor/config.json +0 -13
  113. package/src/components/json-schema-editor/utils.ts +0 -29
  114. package/src/components/prompt-editor/config.json +0 -9
  115. package/src/components/prompt-editor-with-inputs/config.json +0 -13
  116. package/src/components/prompt-editor-with-variables/config.json +0 -13
  117. package/src/components/type-selector/config.json +0 -5
  118. package/src/components/type-selector/constants.tsx +0 -364
  119. package/src/components/variable-selector/config.json +0 -5
  120. package/src/effects/auto-rename-ref/config.json +0 -5
  121. package/src/effects/provide-batch-input/config.json +0 -5
  122. package/src/effects/provide-batch-outputs/config.json +0 -5
  123. package/src/effects/provide-batch-outputs/index.ts +0 -38
  124. package/src/effects/provide-json-schema-outputs/config.json +0 -8
  125. package/src/effects/sync-variable-title/config.json +0 -5
  126. package/src/form-plugins/batch-outputs-plugin/config.json +0 -7
  127. package/src/typings/flow-value/config.json +0 -5
  128. package/src/typings/json-schema/config.json +0 -5
  129. package/src/typings/json-schema/index.ts +0 -36
  130. package/src/utils/json-schema/config.json +0 -5
  131. package/src/utils/json-schema/index.ts +0 -180
  132. /package/src/{utils → shared}/format-legacy-refs/index.ts +0 -0
  133. /package/src/{utils → shared}/format-legacy-refs/readme.md +0 -0
@@ -5,15 +5,19 @@
5
5
 
6
6
  import React, { useMemo } from 'react';
7
7
 
8
+ import { IJsonSchema } from '@flowgram.ai/json-schema';
9
+ import { I18n } from '@flowgram.ai/editor';
8
10
  import { TriggerRenderProps } from '@douyinfe/semi-ui/lib/es/treeSelect';
9
11
  import { TreeNodeData } from '@douyinfe/semi-ui/lib/es/tree';
12
+ import { Popover } from '@douyinfe/semi-ui';
10
13
  import { IconChevronDownStroked, IconIssueStroked } from '@douyinfe/semi-icons';
11
14
 
12
- import { IJsonSchema } from '../../typings/json-schema';
15
+ import { createInjectMaterial } from '@/shared';
16
+
13
17
  import { useVariableTree } from './use-variable-tree';
14
- import { UIRootTitle, UITag, UITreeSelect, UIVarName } from './styles';
18
+ import { UIPopoverContent, UIRootTitle, UITag, UITreeSelect, UIVarName } from './styles';
15
19
 
16
- interface PropTypes {
20
+ export interface VariableSelectorProps {
17
21
  value?: string[];
18
22
  config?: {
19
23
  placeholder?: string;
@@ -28,8 +32,6 @@ interface PropTypes {
28
32
  triggerRender?: (props: TriggerRenderProps) => React.ReactNode;
29
33
  }
30
34
 
31
- export type VariableSelectorProps = PropTypes;
32
-
33
35
  export { useVariableTree };
34
36
 
35
37
  export const VariableSelector = ({
@@ -42,7 +44,7 @@ export const VariableSelector = ({
42
44
  excludeSchema,
43
45
  hasError,
44
46
  triggerRender,
45
- }: PropTypes) => {
47
+ }: VariableSelectorProps) => {
46
48
  const treeData = useVariableTree({ includeSchema, excludeSchema });
47
49
 
48
50
  const treeValue = useMemo(() => {
@@ -93,24 +95,47 @@ export const VariableSelector = ({
93
95
  );
94
96
  }
95
97
 
98
+ const rootIcon = renderIcon(_option.rootMeta?.icon || _option?.icon);
99
+
100
+ const rootTitle = (
101
+ <UIRootTitle>
102
+ {_option.rootMeta?.title
103
+ ? `${_option.rootMeta?.title} ${_option.isRoot ? '' : '-'} `
104
+ : null}
105
+ </UIRootTitle>
106
+ );
107
+
96
108
  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>
109
+ <div>
110
+ <Popover
111
+ content={
112
+ <UIPopoverContent>
113
+ {rootIcon}
114
+ {rootTitle}
115
+ <UIVarName>{_option.keyPath.slice(1).join('.')}</UIVarName>
116
+ </UIPopoverContent>
117
+ }
118
+ >
119
+ <UITag
120
+ prefixIcon={rootIcon}
121
+ closable={!readonly}
122
+ onClose={() => onChange(undefined)}
123
+ >
124
+ {rootTitle}
125
+ {!_option.isRoot && <UIVarName $inSelector>{_option.label}</UIVarName>}
126
+ </UITag>
127
+ </Popover>
128
+ </div>
107
129
  );
108
130
  }}
109
131
  showClear={false}
110
132
  arrowIcon={<IconChevronDownStroked size="small" />}
111
133
  triggerRender={triggerRender}
112
- placeholder={config?.placeholder ?? 'Select Variable...'}
134
+ placeholder={config?.placeholder ?? I18n.t('Select Variable')}
113
135
  />
114
136
  </>
115
137
  );
116
138
  };
139
+
140
+ VariableSelector.renderKey = 'variable-selector-render-key';
141
+ export const InjectVariableSelector = createInjectMaterial(VariableSelector);
@@ -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
 
@@ -11,7 +11,7 @@ import {
11
11
  VariableFieldKeyRenameService,
12
12
  } from '@flowgram.ai/editor';
13
13
 
14
- import { IFlowRefValue, IFlowTemplateValue } from '../../typings';
14
+ import { IFlowRefValue, IFlowTemplateValue } from '@/typings';
15
15
 
16
16
  /**
17
17
  * Auto rename ref when form item's key is renamed
@@ -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,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,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
+ ];
@@ -11,7 +11,7 @@ import {
11
11
  getNodeForm,
12
12
  } from '@flowgram.ai/editor';
13
13
 
14
- import { IFlowRefValue } from '../../typings';
14
+ import { IFlowRefValue } from '@/typings';
15
15
 
16
16
  export const provideBatchInputEffect: EffectOptions[] = createEffectFromVariableProvider({
17
17
  private: true,
@@ -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,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
+ ];
@@ -17,7 +17,7 @@ import {
17
17
  FlowNodeScopeType,
18
18
  } from '@flowgram.ai/editor';
19
19
 
20
- import { IFlowRefValue } from '../../typings';
20
+ import { IFlowRefValue } from '@/typings';
21
21
 
22
22
  export const provideBatchOutputsEffect: EffectOptions[] = createEffectFromVariableProvider({
23
23
  parse: (value: Record<string, IFlowRefValue>, ctx) => [
@@ -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';
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { set, uniqBy } from 'lodash';
7
+ import { JsonSchemaUtils } from '@flowgram.ai/json-schema';
8
+ import {
9
+ ASTFactory,
10
+ createEffectFromVariableProvider,
11
+ defineFormPluginCreator,
12
+ FlowNodeRegistry,
13
+ getNodeForm,
14
+ getNodeScope,
15
+ } from '@flowgram.ai/editor';
16
+
17
+ import { IFlowRefValue, IFlowValue } from '@/typings';
18
+
19
+ type AssignValueType =
20
+ | {
21
+ operator: 'assign';
22
+ left?: IFlowRefValue;
23
+ right?: IFlowValue;
24
+ }
25
+ | {
26
+ operator: 'declare';
27
+ left?: string;
28
+ right?: IFlowValue;
29
+ };
30
+
31
+ interface InputConfig {
32
+ assignKey: string;
33
+ outputKey: string;
34
+ }
35
+
36
+ export const createInferAssignPlugin = defineFormPluginCreator<InputConfig>({
37
+ onSetupFormMeta({ addFormatOnSubmit, mergeEffect }, { assignKey, outputKey }) {
38
+ if (!assignKey || !outputKey) {
39
+ return;
40
+ }
41
+
42
+ mergeEffect({
43
+ [assignKey]: createEffectFromVariableProvider({
44
+ parse: (value: AssignValueType[], ctx) => {
45
+ const declareRows = uniqBy(
46
+ value.filter((_v) => _v.operator === 'declare' && _v.left && _v.right),
47
+ 'left'
48
+ );
49
+
50
+ return [
51
+ ASTFactory.createVariableDeclaration({
52
+ key: `${ctx.node.id}`,
53
+ meta: {
54
+ title: getNodeForm(ctx.node)?.getValueIn('title'),
55
+ icon: ctx.node.getNodeRegistry<FlowNodeRegistry>().info?.icon,
56
+ },
57
+ type: ASTFactory.createObject({
58
+ properties: declareRows.map((_v) =>
59
+ ASTFactory.createProperty({
60
+ key: _v.left as string,
61
+ type:
62
+ _v.right?.type === 'constant'
63
+ ? JsonSchemaUtils.schemaToAST(_v.right?.schema || {})
64
+ : undefined,
65
+ initializer:
66
+ _v.right?.type === 'ref'
67
+ ? ASTFactory.createKeyPathExpression({
68
+ keyPath: _v.right?.content || [],
69
+ })
70
+ : {},
71
+ })
72
+ ),
73
+ }),
74
+ }),
75
+ ];
76
+ },
77
+ }),
78
+ });
79
+
80
+ addFormatOnSubmit((formData, ctx) => {
81
+ set(
82
+ formData,
83
+ outputKey,
84
+ JsonSchemaUtils.astToSchema(getNodeScope(ctx.node).output.variables?.[0]?.type)
85
+ );
86
+
87
+ return formData;
88
+ });
89
+ },
90
+ });
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { get, set } from 'lodash';
7
+ import { JsonSchemaUtils, IJsonSchema } from '@flowgram.ai/json-schema';
8
+ import {
9
+ defineFormPluginCreator,
10
+ getNodePrivateScope,
11
+ getNodeScope,
12
+ Scope,
13
+ } from '@flowgram.ai/editor';
14
+
15
+ import { IFlowConstantValue, IFlowRefValue, IFlowTemplateValue } from '@/typings';
16
+
17
+ interface InputConfig {
18
+ sourceKey: string;
19
+ targetKey: string;
20
+ scope?: 'private' | 'public';
21
+ }
22
+
23
+ export const createInferInputsPlugin = defineFormPluginCreator<InputConfig>({
24
+ onSetupFormMeta({ addFormatOnSubmit }, { sourceKey, targetKey, scope }) {
25
+ if (!sourceKey || !targetKey) {
26
+ return;
27
+ }
28
+
29
+ addFormatOnSubmit((formData, ctx) => {
30
+ set(
31
+ formData,
32
+ targetKey,
33
+ infer(
34
+ get(formData, sourceKey),
35
+ scope === 'private' ? getNodePrivateScope(ctx.node) : getNodeScope(ctx.node)
36
+ )
37
+ );
38
+
39
+ return formData;
40
+ });
41
+ },
42
+ });
43
+
44
+ function isRef(value: any): value is IFlowRefValue {
45
+ return (
46
+ value?.type === 'ref' && Array.isArray(value?.content) && typeof value?.content[0] === 'string'
47
+ );
48
+ }
49
+
50
+ function isTemplate(value: any): value is IFlowTemplateValue {
51
+ return value?.type === 'template' && typeof value?.content === 'string';
52
+ }
53
+
54
+ function isConstant(value: any): value is IFlowConstantValue {
55
+ return value?.type === 'constant' && typeof value?.content !== 'undefined';
56
+ }
57
+
58
+ const infer = (values: any, scope: Scope): IJsonSchema | undefined => {
59
+ if (typeof values === 'object') {
60
+ if (isConstant(values)) {
61
+ if (values?.schema) {
62
+ return values.schema;
63
+ }
64
+
65
+ if (typeof values.content === 'string') {
66
+ return {
67
+ type: 'string',
68
+ };
69
+ }
70
+
71
+ if (typeof values.content === 'number') {
72
+ return {
73
+ type: 'number',
74
+ };
75
+ }
76
+
77
+ if (typeof values.content === 'boolean') {
78
+ return {
79
+ type: 'boolean',
80
+ };
81
+ }
82
+ }
83
+
84
+ if (isRef(values)) {
85
+ const variable = scope.available.getByKeyPath(values?.content);
86
+ const schema = variable?.type ? JsonSchemaUtils.astToSchema(variable?.type) : undefined;
87
+
88
+ return schema;
89
+ }
90
+
91
+ if (isTemplate(values)) {
92
+ return {
93
+ type: 'string',
94
+ };
95
+ }
96
+
97
+ return {
98
+ type: 'object',
99
+ properties: Object.keys(values).reduce((acc, key) => {
100
+ const schema = infer(values[key], scope);
101
+ if (schema) {
102
+ acc[key] = schema;
103
+ }
104
+ return acc;
105
+ }, {} as Record<string, IJsonSchema>),
106
+ };
107
+ }
108
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ export * from './use-object-list';