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

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 (164) hide show
  1. package/bin/index.ts +4 -29
  2. package/bin/materials.ts +56 -87
  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/chunk-727SU246.js +13 -0
  7. package/dist/esm/chunk-727SU246.js.map +1 -0
  8. package/dist/esm/chunk-DEZUEMUM.js +284 -0
  9. package/dist/esm/chunk-DEZUEMUM.js.map +1 -0
  10. package/dist/esm/chunk-DUOXDOUE.js +477 -0
  11. package/dist/esm/chunk-DUOXDOUE.js.map +1 -0
  12. package/dist/esm/editor-6UMULJYB.js +180 -0
  13. package/dist/esm/editor-6UMULJYB.js.map +1 -0
  14. package/dist/esm/editor-EYOQTGMT.js +282 -0
  15. package/dist/esm/editor-EYOQTGMT.js.map +1 -0
  16. package/dist/esm/editor-OXPGKPF5.js +167 -0
  17. package/dist/esm/editor-OXPGKPF5.js.map +1 -0
  18. package/dist/esm/editor-VO6YAXRC.js +249 -0
  19. package/dist/esm/editor-VO6YAXRC.js.map +1 -0
  20. package/dist/esm/editor-XYLKTB6L.js +365 -0
  21. package/dist/esm/editor-XYLKTB6L.js.map +1 -0
  22. package/dist/esm/index.js +1186 -2456
  23. package/dist/esm/index.js.map +1 -1
  24. package/dist/index.d.mts +363 -70
  25. package/dist/index.d.ts +363 -70
  26. package/dist/index.js +4064 -2887
  27. package/dist/index.js.map +1 -1
  28. package/package.json +9 -8
  29. package/src/components/assign-row/index.tsx +4 -4
  30. package/src/components/assign-rows/index.tsx +1 -1
  31. package/src/components/batch-outputs/index.tsx +7 -5
  32. package/src/components/batch-outputs/types.ts +1 -1
  33. package/src/components/batch-variable-selector/index.tsx +1 -1
  34. package/src/components/code-editor/editor.tsx +89 -0
  35. package/src/components/code-editor/index.tsx +5 -89
  36. package/src/components/code-editor/language-features.ts +18 -18
  37. package/src/components/code-editor/theme/dark.ts +49 -30
  38. package/src/components/code-editor/theme/light.ts +56 -32
  39. package/src/components/code-editor-mini/index.tsx +2 -2
  40. package/src/components/condition-row/constants.ts +10 -2
  41. package/src/components/condition-row/hooks/useOp.tsx +13 -9
  42. package/src/components/condition-row/hooks/useRule.ts +8 -4
  43. package/src/components/condition-row/index.tsx +31 -10
  44. package/src/components/condition-row/types.ts +5 -7
  45. package/src/components/constant-input/index.tsx +5 -2
  46. package/src/components/constant-input/types.ts +1 -1
  47. package/src/components/db-condition-row/hooks/use-left.tsx +66 -0
  48. package/src/components/db-condition-row/hooks/use-op.tsx +59 -0
  49. package/src/components/db-condition-row/index.tsx +93 -0
  50. package/src/components/db-condition-row/styles.tsx +43 -0
  51. package/src/components/db-condition-row/types.ts +34 -0
  52. package/src/components/display-flow-value/index.tsx +4 -14
  53. package/src/components/display-inputs-values/index.tsx +46 -7
  54. package/src/components/display-outputs/index.tsx +2 -1
  55. package/src/components/display-schema-tag/index.tsx +3 -2
  56. package/src/components/display-schema-tree/index.tsx +2 -1
  57. package/src/components/dynamic-value-input/hooks.ts +25 -4
  58. package/src/components/dynamic-value-input/index.tsx +33 -20
  59. package/src/components/dynamic-value-input/styles.tsx +14 -4
  60. package/src/components/index.ts +3 -0
  61. package/src/components/inputs-values/index.tsx +21 -8
  62. package/src/components/inputs-values/styles.tsx +1 -1
  63. package/src/components/inputs-values/types.ts +3 -3
  64. package/src/components/inputs-values-tree/hooks/use-child-list.tsx +76 -0
  65. package/src/components/inputs-values-tree/index.tsx +62 -0
  66. package/src/components/inputs-values-tree/row.tsx +177 -0
  67. package/src/components/inputs-values-tree/styles.tsx +128 -0
  68. package/src/components/inputs-values-tree/types.ts +21 -0
  69. package/src/components/json-editor-with-variables/editor.tsx +69 -0
  70. package/src/components/json-editor-with-variables/extensions/variable-tag.tsx +6 -5
  71. package/src/components/json-editor-with-variables/extensions/variable-tree.tsx +1 -1
  72. package/src/components/json-editor-with-variables/index.tsx +5 -58
  73. package/src/components/json-schema-editor/default-value.tsx +12 -108
  74. package/src/components/json-schema-editor/hooks.tsx +63 -93
  75. package/src/components/json-schema-editor/index.tsx +36 -70
  76. package/src/components/json-schema-editor/styles.tsx +12 -84
  77. package/src/components/json-schema-editor/types.ts +0 -1
  78. package/src/components/prompt-editor/editor.tsx +81 -0
  79. package/src/components/prompt-editor/index.tsx +5 -62
  80. package/src/components/prompt-editor/types.tsx +1 -1
  81. package/src/components/prompt-editor-with-inputs/editor.tsx +25 -0
  82. package/src/components/prompt-editor-with-inputs/extensions/inputs-tree.tsx +13 -1
  83. package/src/components/prompt-editor-with-inputs/index.tsx +5 -15
  84. package/src/components/prompt-editor-with-inputs/inputs-picker.tsx +34 -17
  85. package/src/components/prompt-editor-with-variables/editor.tsx +22 -0
  86. package/src/components/prompt-editor-with-variables/extensions/variable-tag.tsx +12 -20
  87. package/src/components/prompt-editor-with-variables/extensions/variable-tree.tsx +14 -2
  88. package/src/components/prompt-editor-with-variables/index.tsx +5 -12
  89. package/src/components/type-selector/index.tsx +21 -9
  90. package/src/components/variable-selector/context.tsx +28 -0
  91. package/src/components/variable-selector/index.tsx +19 -6
  92. package/src/components/variable-selector/use-variable-tree.tsx +4 -4
  93. package/src/effects/auto-rename-ref/index.ts +8 -55
  94. package/src/effects/listen-ref-schema-change/index.ts +1 -1
  95. package/src/effects/listen-ref-value-change/index.ts +1 -1
  96. package/src/effects/provide-batch-input/index.ts +1 -1
  97. package/src/effects/validate-when-variable-sync/index.ts +1 -1
  98. package/src/form-plugins/batch-outputs-plugin/index.ts +1 -1
  99. package/src/form-plugins/infer-assign-plugin/index.ts +2 -2
  100. package/src/form-plugins/infer-inputs-plugin/index.ts +4 -76
  101. package/src/hooks/use-object-list/index.tsx +35 -7
  102. package/src/index.ts +1 -0
  103. package/src/plugins/json-schema-preset/manager.ts +1 -0
  104. package/src/plugins/json-schema-preset/type-definition/array.tsx +3 -1
  105. package/src/plugins/json-schema-preset/type-definition/boolean.tsx +4 -3
  106. package/src/plugins/json-schema-preset/type-definition/date-time.tsx +25 -0
  107. package/src/plugins/json-schema-preset/type-definition/index.tsx +2 -0
  108. package/src/plugins/json-schema-preset/type-definition/integer.tsx +2 -1
  109. package/src/plugins/json-schema-preset/type-definition/number.tsx +2 -1
  110. package/src/plugins/json-schema-preset/type-definition/object.tsx +3 -1
  111. package/src/plugins/json-schema-preset/type-definition/string.tsx +19 -4
  112. package/src/shared/flow-value/index.ts +6 -0
  113. package/src/shared/flow-value/schema.ts +38 -0
  114. package/src/shared/flow-value/utils.ts +201 -0
  115. package/src/shared/format-legacy-refs/index.ts +1 -1
  116. package/src/shared/index.ts +4 -0
  117. package/src/shared/inject-material/README.md +170 -0
  118. package/src/shared/inject-material/README.zh.md +174 -0
  119. package/src/shared/inject-material/index.tsx +87 -0
  120. package/src/shared/lazy-suspense/index.tsx +28 -0
  121. package/src/shared/polyfill-create-root/index.tsx +33 -0
  122. package/src/typings/flow-value/index.ts +3 -1
  123. package/src/validate/validate-flow-value/index.tsx +4 -16
  124. package/src/components/assign-row/config.json +0 -11
  125. package/src/components/assign-rows/config.json +0 -11
  126. package/src/components/batch-outputs/config.json +0 -13
  127. package/src/components/batch-variable-selector/config.json +0 -9
  128. package/src/components/code-editor/config.json +0 -10
  129. package/src/components/code-editor-mini/config.json +0 -7
  130. package/src/components/condition-row/config.json +0 -13
  131. package/src/components/constant-input/config.json +0 -9
  132. package/src/components/display-flow-value/config.json +0 -8
  133. package/src/components/display-inputs-values/config.json +0 -9
  134. package/src/components/display-outputs/config.json +0 -10
  135. package/src/components/display-schema-tag/config.json +0 -10
  136. package/src/components/display-schema-tree/config.json +0 -11
  137. package/src/components/dynamic-value-input/config.json +0 -14
  138. package/src/components/inputs-values/config.json +0 -13
  139. package/src/components/json-editor-with-variables/config.json +0 -13
  140. package/src/components/json-schema-editor/components/blur-input.tsx +0 -27
  141. package/src/components/json-schema-editor/config.json +0 -13
  142. package/src/components/json-schema-editor/utils.ts +0 -29
  143. package/src/components/prompt-editor/config.json +0 -9
  144. package/src/components/prompt-editor-with-inputs/config.json +0 -13
  145. package/src/components/prompt-editor-with-variables/config.json +0 -13
  146. package/src/components/type-selector/config.json +0 -9
  147. package/src/components/variable-selector/config.json +0 -9
  148. package/src/effects/auto-rename-ref/config.json +0 -5
  149. package/src/effects/listen-ref-schema-change/config.json +0 -10
  150. package/src/effects/listen-ref-value-change/config.json +0 -9
  151. package/src/effects/provide-batch-input/config.json +0 -5
  152. package/src/effects/provide-json-schema-outputs/config.json +0 -7
  153. package/src/effects/sync-variable-title/config.json +0 -5
  154. package/src/effects/validate-when-variable-sync/config.json +0 -5
  155. package/src/form-plugins/batch-outputs-plugin/config.json +0 -7
  156. package/src/form-plugins/infer-assign-plugin/config.json +0 -7
  157. package/src/form-plugins/infer-inputs-plugin/config.json +0 -9
  158. package/src/hooks/use-object-list/config.json +0 -8
  159. package/src/plugins/disable-declaration-plugin/config.json +0 -5
  160. package/src/plugins/json-schema-preset/config.json +0 -9
  161. package/src/shared/format-legacy-refs/config.json +0 -5
  162. package/src/typings/flow-value/config.json +0 -7
  163. package/src/validate/validate-flow-value/config.json +0 -7
  164. /package/src/components/{inputs-values/components/blur-input.tsx → blur-input/index.tsx} +0 -0
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import React from 'react';
7
+
8
+ import styled, { css } from 'styled-components';
9
+ import Icon from '@douyinfe/semi-icons';
10
+
11
+ export const UIContainer = styled.div``;
12
+
13
+ export const UIRow = styled.div`
14
+ display: flex;
15
+ align-items: flex-start;
16
+ gap: 5px;
17
+ `;
18
+
19
+ export const UICollapseTrigger = styled.div`
20
+ cursor: pointer;
21
+ margin-right: 5px;
22
+ `;
23
+
24
+ export const UITreeItems = styled.div<{ $shrink?: boolean }>`
25
+ display: grid;
26
+ grid-template-columns: auto 1fr;
27
+
28
+ ${({ $shrink }) =>
29
+ $shrink &&
30
+ css`
31
+ padding-left: 3px;
32
+ margin-top: 10px;
33
+ `}
34
+ `;
35
+
36
+ export const UITreeItemLeft = styled.div<{
37
+ $isLast?: boolean;
38
+ $showLine?: boolean;
39
+ $showCollapse?: boolean;
40
+ }>`
41
+ grid-column: 1;
42
+ position: relative;
43
+ width: 16px;
44
+
45
+ ${({ $showLine, $isLast, $showCollapse }) => {
46
+ let height = $isLast ? '24px' : '100%';
47
+ let width = $showCollapse ? '12px' : '30px';
48
+
49
+ return (
50
+ $showLine &&
51
+ css`
52
+ &::before {
53
+ /* 竖线 */
54
+ content: '';
55
+ height: ${height};
56
+ position: absolute;
57
+ left: -14px;
58
+ top: -16px;
59
+ width: 1px;
60
+ background: #d9d9d9;
61
+ display: block;
62
+ }
63
+
64
+ &::after {
65
+ /* 横线 */
66
+ content: '';
67
+ position: absolute;
68
+ left: -14px; // 横线起点和竖线对齐
69
+ top: 8px; // 跟随你的行高调整
70
+ width: ${width}; // 横线长度
71
+ height: 1px;
72
+ background: #d9d9d9;
73
+ display: block;
74
+ }
75
+ `
76
+ );
77
+ }}
78
+ `;
79
+
80
+ export const UITreeItemRight = styled.div`
81
+ grid-column: 2;
82
+ margin-bottom: 10px;
83
+
84
+ &:last-child {
85
+ margin-bottom: 0px;
86
+ }
87
+ `;
88
+
89
+ export const UITreeItemMain = styled.div<{}>`
90
+ display: flex;
91
+ flex-direction: column;
92
+ gap: 10px;
93
+ position: relative;
94
+ `;
95
+
96
+ export const UICollapsible = styled.div<{ $collapse?: boolean }>`
97
+ display: none;
98
+
99
+ ${({ $collapse }) =>
100
+ $collapse &&
101
+ css`
102
+ display: block;
103
+ `}
104
+ `;
105
+
106
+ export const UIActions = styled.div`
107
+ white-space: nowrap;
108
+ `;
109
+
110
+ const iconAddChildrenSvg = (
111
+ <svg
112
+ className="icon-icon icon-icon-coz_add_node "
113
+ width="1em"
114
+ height="1em"
115
+ viewBox="0 0 24 24"
116
+ fill="currentColor"
117
+ xmlns="http://www.w3.org/2000/svg"
118
+ >
119
+ <path
120
+ fillRule="evenodd"
121
+ clipRule="evenodd"
122
+ d="M11 6.49988C11 8.64148 9.50397 10.4337 7.49995 10.8884V15.4998C7.49995 16.0521 7.94767 16.4998 8.49995 16.4998H11.208C11.0742 16.8061 11 17.1443 11 17.4998C11 17.8554 11.0742 18.1936 11.208 18.4998H8.49995C6.8431 18.4998 5.49995 17.1567 5.49995 15.4998V10.8884C3.49599 10.4336 2 8.64145 2 6.49988C2 4.0146 4.01472 1.99988 6.5 1.99988C8.98528 1.99988 11 4.0146 11 6.49988ZM6.5 8.99988C7.88071 8.99988 9 7.88059 9 6.49988C9 5.11917 7.88071 3.99988 6.5 3.99988C5.11929 3.99988 4 5.11917 4 6.49988C4 7.88059 5.11929 8.99988 6.5 8.99988Z"
123
+ ></path>
124
+ <path d="M17.5 12.4999C18.0523 12.4999 18.5 12.9476 18.5 13.4999V16.4999H21.5C22.0523 16.4999 22.5 16.9476 22.5 17.4999C22.5 18.0522 22.0523 18.4999 21.5 18.4999H18.5V21.4999C18.5 22.0522 18.0523 22.4999 17.5 22.4999C16.9477 22.4999 16.5 22.0522 16.5 21.4999V18.4999H13.5C12.9477 18.4999 12.5 18.0522 12.5 17.4999C12.5 16.9476 12.9477 16.4999 13.5 16.4999H16.5V13.4999C16.5 12.9476 16.9477 12.4999 17.5 12.4999Z"></path>
125
+ </svg>
126
+ );
127
+
128
+ export const IconAddChildren = () => <Icon size="small" svg={iconAddChildrenSvg} />;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { IJsonSchema } from '@flowgram.ai/json-schema';
7
+
8
+ import { ConstantInputStrategy } from '@/components/constant-input';
9
+
10
+ export interface PropsType {
11
+ value?: any;
12
+ onChange: (value?: any) => void;
13
+ readonly?: boolean;
14
+ hasError?: boolean;
15
+ schema?: IJsonSchema;
16
+ style?: React.CSSProperties;
17
+ constantProps?: {
18
+ strategies?: ConstantInputStrategy[];
19
+ [key: string]: any;
20
+ };
21
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import React from 'react';
7
+
8
+ import { I18n } from '@flowgram.ai/editor';
9
+ import { transformerCreator } from '@coze-editor/editor/preset-code';
10
+ import { Text } from '@coze-editor/editor/language-json';
11
+
12
+ import { CodeEditor, type CodeEditorPropsType } from '@/components/code-editor';
13
+
14
+ import { VariableTree } from './extensions/variable-tree';
15
+ import { VariableTagInject } from './extensions/variable-tag';
16
+
17
+ type Match = { match: string; range: [number, number] };
18
+ function findAllMatches(inputString: string, regex: RegExp): Match[] {
19
+ const globalRegex = new RegExp(
20
+ regex,
21
+ regex.flags.includes('g') ? regex.flags : regex.flags + 'g'
22
+ );
23
+ let match;
24
+ const matches: Match[] = [];
25
+
26
+ while ((match = globalRegex.exec(inputString)) !== null) {
27
+ if (match.index === globalRegex.lastIndex) {
28
+ globalRegex.lastIndex++;
29
+ }
30
+ matches.push({
31
+ match: match[0],
32
+ range: [match.index, match.index + match[0].length],
33
+ });
34
+ }
35
+
36
+ return matches;
37
+ }
38
+
39
+ const transformer = transformerCreator((text: Text) => {
40
+ const originalSource = text.toString();
41
+ const matches = findAllMatches(originalSource, /\{\{([^\}]*)\}\}/g);
42
+
43
+ if (matches.length > 0) {
44
+ matches.forEach(({ range }) => {
45
+ text.replaceRange(range[0], range[1], 'null');
46
+ });
47
+ }
48
+
49
+ return text;
50
+ });
51
+
52
+ export interface JsonEditorWithVariablesProps extends Omit<CodeEditorPropsType, 'languageId'> {}
53
+
54
+ export function JsonEditorWithVariables(props: JsonEditorWithVariablesProps) {
55
+ return (
56
+ <CodeEditor
57
+ languageId="json"
58
+ activeLinePlaceholder={I18n.t("Press '@' to Select variable")}
59
+ {...props}
60
+ options={{
61
+ transformer,
62
+ ...(props.options || {}),
63
+ }}
64
+ >
65
+ <VariableTree />
66
+ <VariableTagInject />
67
+ </CodeEditor>
68
+ );
69
+ }
@@ -5,8 +5,7 @@
5
5
 
6
6
  import React, { useLayoutEffect } from 'react';
7
7
 
8
- import { createRoot, Root } from 'react-dom/client';
9
- import { isEqual, last } from 'lodash';
8
+ import { isEqual, last } from 'lodash-es';
10
9
  import {
11
10
  BaseVariableField,
12
11
  Disposable,
@@ -26,6 +25,8 @@ import {
26
25
  WidgetType,
27
26
  } from '@codemirror/view';
28
27
 
28
+ import { IPolyfillRoot, polyfillCreateRoot } from '@/shared';
29
+
29
30
  import { UIPopoverContent, UIRootTitle, UITag, UIVarName } from '../styles';
30
31
 
31
32
  class VariableTagWidget extends WidgetType {
@@ -35,7 +36,7 @@ class VariableTagWidget extends WidgetType {
35
36
 
36
37
  scope: Scope;
37
38
 
38
- root: Root;
39
+ root: IPolyfillRoot;
39
40
 
40
41
  constructor({ keyPath, scope }: { keyPath?: string[]; scope: Scope }) {
41
42
  super();
@@ -90,7 +91,7 @@ class VariableTagWidget extends WidgetType {
90
91
  toDOM(view: EditorView): HTMLElement {
91
92
  const dom = document.createElement('span');
92
93
 
93
- this.root = createRoot(dom);
94
+ this.root = polyfillCreateRoot(dom);
94
95
 
95
96
  this.toDispose.push(
96
97
  Disposable.create(() => {
@@ -134,7 +135,7 @@ export function VariableTagInject() {
134
135
  // 基于 {{var}} 的正则进行匹配,匹配后进行自定义渲染
135
136
  useLayoutEffect(() => {
136
137
  const atMatcher = new MatchDecorator({
137
- regexp: /\{\{([^\}]+)\}\}/g,
138
+ regexp: /\{\{([^\}\{]+)\}\}/g,
138
139
  decoration: (match) =>
139
140
  Decoration.replace({
140
141
  widget: new VariableTagWidget({
@@ -15,7 +15,7 @@ import {
15
15
  } from '@coze-editor/editor/react';
16
16
  import { EditorAPI } from '@coze-editor/editor/preset-prompt';
17
17
 
18
- import { useVariableTree } from '../../variable-selector';
18
+ import { useVariableTree } from '@/components/variable-selector';
19
19
 
20
20
  export function VariableTree() {
21
21
  const [posKey, setPosKey] = useState('');
@@ -3,63 +3,10 @@
3
3
  * SPDX-License-Identifier: MIT
4
4
  */
5
5
 
6
- import React from 'react';
6
+ import { lazySuspense } from '@/shared';
7
7
 
8
- import { transformerCreator } from '@coze-editor/editor/preset-code';
9
- import { Text } from '@coze-editor/editor/language-json';
8
+ export const JsonEditorWithVariables = lazySuspense(() =>
9
+ import('./editor').then((module) => ({ default: module.JsonEditorWithVariables }))
10
+ );
10
11
 
11
- import { VariableTree } from './extensions/variable-tree';
12
- import { VariableTagInject } from './extensions/variable-tag';
13
- import { CodeEditor, type CodeEditorPropsType } from '../code-editor';
14
-
15
- type Match = { match: string; range: [number, number] };
16
- function findAllMatches(inputString: string, regex: RegExp): Match[] {
17
- const globalRegex = new RegExp(
18
- regex,
19
- regex.flags.includes('g') ? regex.flags : regex.flags + 'g'
20
- );
21
- let match;
22
- const matches: Match[] = [];
23
-
24
- while ((match = globalRegex.exec(inputString)) !== null) {
25
- if (match.index === globalRegex.lastIndex) {
26
- globalRegex.lastIndex++;
27
- }
28
- matches.push({
29
- match: match[0],
30
- range: [match.index, match.index + match[0].length],
31
- });
32
- }
33
-
34
- return matches;
35
- }
36
-
37
- const transformer = transformerCreator((text: Text) => {
38
- const originalSource = text.toString();
39
- const matches = findAllMatches(originalSource, /\{\{([^\}]*)\}\}/g);
40
-
41
- if (matches.length > 0) {
42
- matches.forEach(({ range }) => {
43
- text.replaceRange(range[0], range[1], 'null');
44
- });
45
- }
46
-
47
- return text;
48
- });
49
-
50
- export function JsonEditorWithVariables(props: Omit<CodeEditorPropsType, 'languageId'>) {
51
- return (
52
- <CodeEditor
53
- languageId="json"
54
- activeLinePlaceholder="Press '@' to Select variable"
55
- {...props}
56
- options={{
57
- transformer,
58
- ...(props.options || {}),
59
- }}
60
- >
61
- <VariableTree />
62
- <VariableTagInject />
63
- </CodeEditor>
64
- );
65
- }
12
+ export type { JsonEditorWithVariablesProps } from './editor';
@@ -3,132 +3,36 @@
3
3
  * SPDX-License-Identifier: MIT
4
4
  */
5
5
 
6
- import React, { useRef, useState, useCallback } from 'react';
6
+ import React from 'react';
7
7
 
8
8
  import { IJsonSchema } from '@flowgram.ai/json-schema';
9
- import { IconButton, JsonViewer, Tooltip } from '@douyinfe/semi-ui';
10
- import { IconBrackets } from '@douyinfe/semi-icons';
9
+ import { I18n } from '@flowgram.ai/editor';
11
10
 
12
- import { getValueType } from './utils';
13
- import {
14
- ConstantInputWrapper,
15
- JSONHeader,
16
- JSONHeaderLeft,
17
- JSONHeaderRight,
18
- JSONViewerWrapper,
19
- } from './styles';
20
- import { ConstantInput } from '../constant-input';
11
+ import { ConstantInput } from '@/components/constant-input';
12
+
13
+ import { ConstantInputWrapper } from './styles';
21
14
 
22
15
  /**
23
- * 根据不同的数据类型渲染对应的默认值输入组件。
24
- * @param props - 组件属性,包括 value, type, placeholder, onChange
25
- * @returns 返回对应类型的输入组件或 null
16
+ * Renders the corresponding default value input component based on different data types.
17
+ * @param props - Component properties, including value, type, placeholder, onChange.
18
+ * @returns Returns the input component of the corresponding type or null.
26
19
  */
27
20
  export function DefaultValue(props: {
28
21
  value: any;
29
22
  schema?: IJsonSchema;
30
- name?: string;
31
- type?: string;
32
23
  placeholder?: string;
33
- jsonFormatText?: string;
34
24
  onChange: (value: any) => void;
35
25
  }) {
36
- const { value, schema, type, onChange, placeholder, jsonFormatText } = props;
37
-
38
- const wrapperRef = useRef<HTMLDivElement>(null);
39
- const JsonViewerRef = useRef<JsonViewer>(null);
40
-
41
- // 为 JsonViewer 添加状态管理
42
- const [internalJsonValue, setInternalJsonValue] = useState<string>(
43
- getValueType(value) === 'string' ? value : ''
44
- );
45
-
46
- // 使用 useCallback 创建稳定的回调函数
47
- const handleJsonChange = useCallback((val: string) => {
48
- // 只在值真正改变时才更新状态
49
- if (val !== internalJsonValue) {
50
- setInternalJsonValue(val);
51
- }
52
- }, []);
53
-
54
- // 处理编辑完成事件
55
- const handleEditComplete = useCallback(() => {
56
- // 只有当存在key,编辑完成时才触发父组件的 onChange
57
- onChange(internalJsonValue);
58
- // 确保在更新后移除焦点
59
- requestAnimationFrame(() => {
60
- // JsonViewerRef.current?.format();
61
- wrapperRef.current?.blur();
62
- });
63
- setJsonReadOnly(true);
64
- }, [internalJsonValue, onChange]);
65
-
66
- const [jsonReadOnly, setJsonReadOnly] = useState<boolean>(true);
67
-
68
- const handleFormatJson = useCallback(() => {
69
- try {
70
- const parsed = JSON.parse(internalJsonValue);
71
- const formatted = JSON.stringify(parsed, null, 4);
72
- setInternalJsonValue(formatted);
73
- onChange(formatted);
74
- } catch (error) {
75
- console.error('Invalid JSON:', error);
76
- }
77
- }, [internalJsonValue, onChange]);
78
-
79
- return type === 'object' ? (
80
- <>
81
- <JSONHeader>
82
- <JSONHeaderLeft>json</JSONHeaderLeft>
83
- <JSONHeaderRight>
84
- <Tooltip content={jsonFormatText ?? 'Format'}>
85
- <IconButton
86
- icon={<IconBrackets style={{ color: 'var(--semi-color-primary)' }} />}
87
- size="small"
88
- type="tertiary"
89
- theme="borderless"
90
- onClick={handleFormatJson}
91
- />
92
- </Tooltip>
93
- </JSONHeaderRight>
94
- </JSONHeader>
26
+ const { value, schema, onChange, placeholder } = props;
95
27
 
96
- <JSONViewerWrapper
97
- ref={wrapperRef}
98
- tabIndex={-1}
99
- onBlur={(e) => {
100
- if (wrapperRef.current && !wrapperRef.current?.contains(e.relatedTarget as Node)) {
101
- handleEditComplete();
102
- }
103
- }}
104
- onClick={(e: React.MouseEvent) => {
105
- setJsonReadOnly(false);
106
- }}
107
- >
108
- <JsonViewer
109
- ref={JsonViewerRef}
110
- value={getValueType(value) === 'string' ? value : ''}
111
- height={120}
112
- width="100%"
113
- showSearch={false}
114
- options={{
115
- readOnly: jsonReadOnly,
116
- formatOptions: { tabSize: 4, insertSpaces: true, eol: '\n' },
117
- }}
118
- style={{
119
- padding: 0,
120
- }}
121
- onChange={handleJsonChange}
122
- />
123
- </JSONViewerWrapper>
124
- </>
125
- ) : (
28
+ return (
126
29
  <ConstantInputWrapper>
127
30
  <ConstantInput
128
31
  value={value}
129
32
  onChange={(_v) => onChange(_v)}
130
33
  schema={schema || { type: 'string' }}
131
- placeholder={placeholder ?? 'Default value if parameter is not provided'}
34
+ placeholder={placeholder ?? I18n.t('Default value if parameter is not provided')}
35
+ enableMultiLineStr
132
36
  />
133
37
  </ConstantInputWrapper>
134
38
  );
@@ -3,10 +3,11 @@
3
3
  * SPDX-License-Identifier: MIT
4
4
  */
5
5
 
6
- import { useEffect, useMemo, useRef, useState } from 'react';
6
+ import { useEffect, useRef, useState } from 'react';
7
7
 
8
- import { omit } from 'lodash';
9
- import { IJsonSchema } from '@flowgram.ai/json-schema';
8
+ import { difference, omit } from 'lodash-es';
9
+ import { produce } from 'immer';
10
+ import { IJsonSchema, type JsonSchemaTypeManager, useTypeManager } from '@flowgram.ai/json-schema';
10
11
 
11
12
  import { PropertyValueType } from './types';
12
13
 
@@ -15,94 +16,59 @@ function genId() {
15
16
  return _id++;
16
17
  }
17
18
 
18
- function getDrilldownSchema(
19
- value?: PropertyValueType,
20
- path?: (keyof PropertyValueType)[]
21
- ): { schema?: PropertyValueType | null; path?: (keyof PropertyValueType)[] } {
22
- if (!value) {
23
- return {};
24
- }
25
-
26
- if (value.type === 'array' && value.items) {
27
- return getDrilldownSchema(value.items, [...(path || []), 'items']);
28
- }
29
-
30
- return { schema: value, path };
31
- }
32
-
33
19
  export function usePropertiesEdit(
34
20
  value?: PropertyValueType,
35
21
  onChange?: (value: PropertyValueType) => void
36
22
  ) {
37
- // Get drilldown (array.items.items...)
38
- const drilldown = useMemo(() => getDrilldownSchema(value), [value, value?.type, value?.items]);
39
-
40
- const isDrilldownObject = drilldown.schema?.type === 'object';
41
-
42
- // Generate Init Property List
43
- const initPropertyList = useMemo(
44
- () =>
45
- isDrilldownObject
46
- ? Object.entries(drilldown.schema?.properties || {})
47
- .sort(([, a], [, b]) => (a.extra?.index ?? 0) - (b.extra?.index ?? 0))
48
- .map(
49
- ([name, _value], index) =>
50
- ({
51
- key: genId(),
52
- name,
53
- isPropertyRequired: drilldown.schema?.required?.includes(name) || false,
54
- ..._value,
55
- extra: {
56
- ...(_value.extra || {}),
57
- index,
58
- },
59
- } as PropertyValueType)
60
- )
61
- : [],
62
- [isDrilldownObject]
63
- );
64
-
65
- const [propertyList, setPropertyList] = useState<PropertyValueType[]>(initPropertyList);
66
-
67
- const mountRef = useRef(false);
23
+ const typeManager = useTypeManager() as JsonSchemaTypeManager;
24
+
25
+ // Get drilldown properties (array.items.items.properties...)
26
+ const drilldownSchema = typeManager.getPropertiesParent(value || {});
27
+ const canAddField = typeManager.canAddField(value || {});
28
+
29
+ const [propertyList, setPropertyList] = useState<PropertyValueType[]>([]);
30
+
31
+ const effectVersion = useRef(0);
32
+ const changeVersion = useRef(0);
68
33
 
69
34
  useEffect(() => {
70
- // If initRef is true, it means the component has been mounted
71
- if (mountRef.current) {
72
- // If the value is changed, update the property list
73
- setPropertyList((_list) => {
74
- const nameMap = new Map<string, PropertyValueType>();
75
-
76
- for (const _property of _list) {
77
- if (_property.name) {
78
- nameMap.set(_property.name, _property);
79
- }
80
- }
81
- return Object.entries(drilldown.schema?.properties || {})
82
- .sort(([, a], [, b]) => (a.extra?.index ?? 0) - (b.extra?.index ?? 0))
83
- .map(([name, _value]) => {
84
- const _property = nameMap.get(name);
85
- if (_property) {
86
- return {
87
- key: _property.key,
88
- name,
89
- isPropertyRequired: drilldown.schema?.required?.includes(name) || false,
90
- ..._value,
91
- };
92
- }
93
- return {
94
- key: genId(),
95
- name,
96
- isPropertyRequired: drilldown.schema?.required?.includes(name) || false,
97
- ..._value,
98
- };
99
- });
100
- });
35
+ effectVersion.current = effectVersion.current + 1;
36
+ if (effectVersion.current === changeVersion.current) {
37
+ return;
101
38
  }
102
- mountRef.current = true;
103
- }, [drilldown.schema]);
39
+ effectVersion.current = changeVersion.current;
40
+
41
+ // If the value is changed, update the property list
42
+ setPropertyList((_list) => {
43
+ const newNames = Object.entries(drilldownSchema?.properties || {})
44
+ .sort(([, a], [, b]) => (a.extra?.index ?? 0) - (b.extra?.index ?? 0))
45
+ .map(([key]) => key);
46
+
47
+ const oldNames = _list.map((item) => item.name).filter(Boolean) as string[];
48
+ const addNames = difference(newNames, oldNames);
49
+
50
+ return _list
51
+ .filter((item) => !item.name || newNames.includes(item.name))
52
+ .map((item) => ({
53
+ key: item.key,
54
+ name: item.name,
55
+ isPropertyRequired: drilldownSchema?.required?.includes(item.name || '') || false,
56
+ ...(drilldownSchema?.properties?.[item.name || ''] || item || {}),
57
+ }))
58
+ .concat(
59
+ addNames.map((_name) => ({
60
+ key: genId(),
61
+ name: _name,
62
+ isPropertyRequired: drilldownSchema?.required?.includes(_name) || false,
63
+ ...(drilldownSchema?.properties?.[_name] || {}),
64
+ }))
65
+ );
66
+ });
67
+ }, [drilldownSchema]);
104
68
 
105
69
  const updatePropertyList = (updater: (list: PropertyValueType[]) => PropertyValueType[]) => {
70
+ changeVersion.current = changeVersion.current + 1;
71
+
106
72
  setPropertyList((_list) => {
107
73
  const next = updater(_list);
108
74
 
@@ -122,21 +88,25 @@ export function usePropertiesEdit(
122
88
  }
123
89
  }
124
90
 
125
- let drilldownSchema = value || {};
126
- if (drilldown.path) {
127
- drilldownSchema = drilldown.path.reduce((acc, key) => acc[key], value || {});
128
- }
129
- drilldownSchema.properties = nextProperties;
130
- drilldownSchema.required = nextRequired;
91
+ onChange?.(
92
+ produce(value || {}, (draft) => {
93
+ const propertiesParent = typeManager.getPropertiesParent(draft);
131
94
 
132
- onChange?.(value || {});
95
+ if (propertiesParent) {
96
+ propertiesParent.properties = nextProperties;
97
+ propertiesParent.required = nextRequired;
98
+ return;
99
+ }
100
+ })
101
+ );
133
102
 
134
103
  return next;
135
104
  });
136
105
  };
137
106
 
138
107
  const onAddProperty = () => {
139
- updatePropertyList((_list) => [
108
+ // set property list only, not trigger updatePropertyList
109
+ setPropertyList((_list) => [
140
110
  ..._list,
141
111
  { key: genId(), name: '', type: 'string', extra: { index: _list.length + 1 } },
142
112
  ]);
@@ -153,14 +123,14 @@ export function usePropertiesEdit(
153
123
  };
154
124
 
155
125
  useEffect(() => {
156
- if (!isDrilldownObject) {
126
+ if (!canAddField) {
157
127
  setPropertyList([]);
158
128
  }
159
- }, [isDrilldownObject]);
129
+ }, [canAddField]);
160
130
 
161
131
  return {
162
132
  propertyList,
163
- isDrilldownObject,
133
+ canAddField,
164
134
  onAddProperty,
165
135
  onRemoveProperty,
166
136
  onEditProperty,