@flowgram.ai/form-materials 0.2.27 → 0.2.29

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 (37) hide show
  1. package/bin/materials.ts +1 -1
  2. package/dist/esm/index.js +466 -218
  3. package/dist/esm/index.js.map +1 -1
  4. package/dist/index.d.mts +53 -15
  5. package/dist/index.d.ts +53 -15
  6. package/dist/index.js +475 -225
  7. package/dist/index.js.map +1 -1
  8. package/package.json +6 -5
  9. package/src/components/batch-outputs/config.json +2 -1
  10. package/src/components/batch-outputs/index.tsx +4 -12
  11. package/src/components/code-editor/config.json +2 -1
  12. package/src/components/code-editor/language-features.ts +3 -4
  13. package/src/components/constant-input/index.tsx +19 -2
  14. package/src/components/constant-input/types.ts +1 -0
  15. package/src/components/dynamic-value-input/index.tsx +58 -9
  16. package/src/components/dynamic-value-input/styles.tsx +28 -2
  17. package/src/components/index.ts +1 -0
  18. package/src/components/inputs-values/config.json +12 -0
  19. package/src/components/inputs-values/index.tsx +60 -0
  20. package/src/components/inputs-values/styles.tsx +19 -0
  21. package/src/components/inputs-values/types.ts +19 -0
  22. package/src/components/json-schema-editor/index.tsx +14 -1
  23. package/src/components/prompt-editor-with-inputs/inputs-picker.tsx +1 -1
  24. package/src/components/type-selector/index.tsx +15 -8
  25. package/src/components/variable-selector/index.tsx +30 -11
  26. package/src/components/variable-selector/styles.tsx +18 -8
  27. package/src/effects/index.ts +0 -1
  28. package/src/form-plugins/index.ts +2 -1
  29. package/src/form-plugins/infer-inputs-plugin/config.json +7 -0
  30. package/src/form-plugins/infer-inputs-plugin/index.ts +108 -0
  31. package/src/hooks/index.tsx +6 -0
  32. package/src/hooks/use-object-list/config.json +8 -0
  33. package/src/{components/batch-outputs/use-list.ts → hooks/use-object-list/index.tsx} +49 -12
  34. package/src/typings/flow-value/config.json +3 -1
  35. package/src/typings/flow-value/index.ts +3 -0
  36. package/src/effects/provide-batch-outputs/config.json +0 -5
  37. package/src/effects/provide-batch-outputs/index.ts +0 -38
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowgram.ai/form-materials",
3
- "version": "0.2.27",
3
+ "version": "0.2.29",
4
4
  "homepage": "https://flowgram.ai/",
5
5
  "repository": "https://github.com/bytedance/flowgram.ai",
6
6
  "license": "MIT",
@@ -33,7 +33,8 @@
33
33
  "@coze-editor/editor": "0.1.0-alpha.879fbb",
34
34
  "@codemirror/view": "~6.38.0",
35
35
  "@codemirror/state": "~6.5.2",
36
- "@flowgram.ai/editor": "0.2.27"
36
+ "typescript": "^5.8.3",
37
+ "@flowgram.ai/editor": "0.2.29"
37
38
  },
38
39
  "devDependencies": {
39
40
  "@types/lodash": "^4.14.137",
@@ -47,10 +48,10 @@
47
48
  "react-dom": "^18",
48
49
  "styled-components": "^5",
49
50
  "tsup": "^8.0.1",
50
- "typescript": "^5.0.4",
51
+ "typescript": "^5.8.3",
51
52
  "vitest": "^0.34.6",
52
- "@flowgram.ai/eslint-config": "0.2.27",
53
- "@flowgram.ai/ts-config": "0.2.27"
53
+ "@flowgram.ai/eslint-config": "0.2.29",
54
+ "@flowgram.ai/ts-config": "0.2.29"
54
55
  },
55
56
  "peerDependencies": {
56
57
  "react": ">=16.8",
@@ -2,7 +2,8 @@
2
2
  "name": "batch-outputs",
3
3
  "depMaterials": [
4
4
  "flow-value",
5
- "variable-selector"
5
+ "variable-selector",
6
+ "use-object-list"
6
7
  ],
7
8
  "depPackages": [
8
9
  "@douyinfe/semi-ui",
@@ -8,15 +8,15 @@ import React from 'react';
8
8
  import { Button, Input } from '@douyinfe/semi-ui';
9
9
  import { IconDelete, IconPlus } from '@douyinfe/semi-icons';
10
10
 
11
- import { useList } from './use-list';
12
11
  import { PropsType } from './types';
13
12
  import { VariableSelector } from '../variable-selector';
13
+ import { useObjectList } from '../../hooks';
14
14
  import { UIRow, UIRows } from './styles';
15
15
 
16
16
  export function BatchOutputs(props: PropsType) {
17
17
  const { readonly, style } = props;
18
18
 
19
- const { list, add, update, remove } = useList(props);
19
+ const { list, add, updateKey, updateValue, remove } = useObjectList(props);
20
20
 
21
21
  return (
22
22
  <div>
@@ -28,21 +28,13 @@ export function BatchOutputs(props: PropsType) {
28
28
  disabled={readonly}
29
29
  size="small"
30
30
  value={item.key}
31
- onChange={(v) => update({ ...item, key: v })}
31
+ onChange={(v) => updateKey(item.id, v)}
32
32
  />
33
33
  <VariableSelector
34
34
  style={{ flexGrow: 1 }}
35
35
  readonly={readonly}
36
36
  value={item.value?.content}
37
- onChange={(v) =>
38
- update({
39
- ...item,
40
- value: {
41
- type: 'ref',
42
- content: v,
43
- },
44
- })
45
- }
37
+ onChange={(v) => updateValue(item.id, { type: 'ref', content: v })}
46
38
  />
47
39
  <Button
48
40
  disabled={readonly}
@@ -4,6 +4,7 @@
4
4
  "depPackages": [
5
5
  "@coze-editor/editor@0.1.0-alpha.879fbb",
6
6
  "@codemirror/view",
7
- "@codemirror/state"
7
+ "@codemirror/state",
8
+ "typescript"
8
9
  ]
9
10
  }
@@ -4,14 +4,15 @@
4
4
  */
5
5
 
6
6
  import { languages } from '@coze-editor/editor/preset-code';
7
- // import { typescript } from '@coze-editor/editor/language-typescript';
7
+ import { typescript } from '@coze-editor/editor/language-typescript';
8
8
  import { shell } from '@coze-editor/editor/language-shell';
9
9
  import { python } from '@coze-editor/editor/language-python';
10
10
  import { json } from '@coze-editor/editor/language-json';
11
11
  import { mixLanguages } from '@coze-editor/editor';
12
12
 
13
13
  languages.register('python', python);
14
- // languages.register('typescript', typescript);
14
+ languages.register('typescript', typescript);
15
+ languages.register('shell', shell);
15
16
 
16
17
  languages.register('json', {
17
18
  // mixLanguages is used to solve the problem that interpolation also uses parentheses, which causes incorrect highlighting
@@ -20,5 +21,3 @@ languages.register('json', {
20
21
  }),
21
22
  languageService: json.languageService,
22
23
  });
23
-
24
- languages.register('shell', shell);
@@ -65,10 +65,19 @@ const defaultStrategies: Strategy[] = [
65
65
  ];
66
66
 
67
67
  export function ConstantInput(props: PropsType) {
68
- const { value, onChange, schema, strategies: extraStrategies, readonly, ...rest } = props;
68
+ const {
69
+ value,
70
+ onChange,
71
+ schema,
72
+ strategies: extraStrategies,
73
+ fallbackRenderer,
74
+ readonly,
75
+ ...rest
76
+ } = props;
69
77
 
70
78
  const strategies = useMemo(
71
- () => [...defaultStrategies, ...(extraStrategies || [])],
79
+ // user's extraStrategies first
80
+ () => [...(extraStrategies || []), ...defaultStrategies],
72
81
  [extraStrategies]
73
82
  );
74
83
 
@@ -79,6 +88,14 @@ export function ConstantInput(props: PropsType) {
79
88
  }, [strategies, schema]);
80
89
 
81
90
  if (!Renderer) {
91
+ if (fallbackRenderer) {
92
+ return React.createElement(fallbackRenderer, {
93
+ value,
94
+ onChange,
95
+ readonly,
96
+ ...rest,
97
+ });
98
+ }
82
99
  return <Input size="small" disabled placeholder="Unsupported type" />;
83
100
  }
84
101
 
@@ -19,5 +19,6 @@ export interface RendererProps<Value = any> {
19
19
  export interface PropsType extends RendererProps {
20
20
  schema: IJsonSchema;
21
21
  strategies?: Strategy[];
22
+ fallbackRenderer?: React.FC<RendererProps>;
22
23
  [key: string]: any;
23
24
  }
@@ -3,16 +3,19 @@
3
3
  * SPDX-License-Identifier: MIT
4
4
  */
5
5
 
6
- import React, { useMemo } from 'react';
6
+ import React, { useMemo, useState } from 'react';
7
7
 
8
+ import { useScopeAvailable } from '@flowgram.ai/editor';
8
9
  import { IconButton } from '@douyinfe/semi-ui';
9
10
  import { IconSetting } from '@douyinfe/semi-icons';
10
11
 
11
12
  import { Strategy } from '../constant-input/types';
12
13
  import { ConstantInput } from '../constant-input';
14
+ import { JsonSchemaUtils } from '../../utils';
13
15
  import { IFlowConstantRefValue } from '../../typings/flow-value';
14
- import { UIContainer, UIMain, UITrigger } from './styles';
16
+ import { UIContainer, UIMain, UITrigger, UIType } from './styles';
15
17
  import { VariableSelector } from '../variable-selector';
18
+ import { TypeSelector } from '../type-selector';
16
19
  import { IJsonSchema } from '../../typings';
17
20
 
18
21
  interface PropsType {
@@ -34,16 +37,50 @@ export function DynamicValueInput({
34
37
  onChange,
35
38
  readonly,
36
39
  style,
37
- schema,
40
+ schema: schemaFromProps,
38
41
  constantProps,
39
42
  }: PropsType) {
43
+ const available = useScopeAvailable();
44
+ const refVariable = useMemo(() => {
45
+ if (value?.type === 'ref') {
46
+ return available.getByKeyPath(value.content);
47
+ }
48
+ }, [value, available]);
49
+
50
+ const [selectSchema, setSelectSchema] = useState(
51
+ schemaFromProps || constantProps?.schema || { type: 'string' }
52
+ );
53
+
54
+ const renderTypeSelector = () => {
55
+ if (schemaFromProps) {
56
+ return <TypeSelector value={schemaFromProps} readonly={true} />;
57
+ }
58
+
59
+ if (value?.type === 'ref') {
60
+ const schema = refVariable?.type ? JsonSchemaUtils.astToSchema(refVariable?.type) : undefined;
61
+
62
+ return <TypeSelector value={schema} readonly={true} />;
63
+ }
64
+
65
+ return (
66
+ <TypeSelector
67
+ value={selectSchema}
68
+ onChange={(_v) => setSelectSchema(_v || { type: 'string' })}
69
+ readonly={readonly}
70
+ />
71
+ );
72
+ };
73
+
40
74
  // When is number type, include integer as well
41
75
  const includeSchema = useMemo(() => {
42
- if (schema?.type === 'number') {
43
- return [schema, { type: 'integer' }];
76
+ if (!schemaFromProps) {
77
+ return;
44
78
  }
45
- return schema;
46
- }, [schema]);
79
+ if (schemaFromProps?.type === 'number') {
80
+ return [schemaFromProps, { type: 'integer' }];
81
+ }
82
+ return { ...schemaFromProps, extra: { ...schemaFromProps?.extra, weak: true } };
83
+ }, [schemaFromProps]);
47
84
 
48
85
  const renderMain = () => {
49
86
  if (value?.type === 'ref') {
@@ -59,12 +96,23 @@ export function DynamicValueInput({
59
96
  );
60
97
  }
61
98
 
99
+ const constantSchema = schemaFromProps || selectSchema || { type: 'string' };
100
+
62
101
  return (
63
102
  <ConstantInput
64
103
  value={value?.content}
65
- onChange={(_v) => onChange({ type: 'constant', content: _v })}
66
- schema={schema || { type: 'string' }}
104
+ onChange={(_v) => onChange({ type: 'constant', content: _v, schema: constantSchema })}
105
+ schema={constantSchema || { type: 'string' }}
67
106
  readonly={readonly}
107
+ strategies={[...(constantProps?.strategies || [])]}
108
+ fallbackRenderer={() => (
109
+ <VariableSelector
110
+ style={{ width: '100%' }}
111
+ onChange={(_v) => onChange(_v ? { type: 'ref', content: _v } : undefined)}
112
+ includeSchema={includeSchema}
113
+ readonly={readonly}
114
+ />
115
+ )}
68
116
  {...constantProps}
69
117
  />
70
118
  );
@@ -85,6 +133,7 @@ export function DynamicValueInput({
85
133
 
86
134
  return (
87
135
  <UIContainer style={style}>
136
+ <UIType>{renderTypeSelector()}</UIType>
88
137
  <UIMain>{renderMain()}</UIMain>
89
138
  <UITrigger>{renderTrigger()}</UITrigger>
90
139
  </UIContainer>
@@ -8,7 +8,12 @@ import styled from 'styled-components';
8
8
  export const UIContainer = styled.div`
9
9
  display: flex;
10
10
  align-items: center;
11
- gap: 5px;
11
+ border-radius: 4px;
12
+ border: 1px solid var(--semi-color-border);
13
+
14
+ overflow: hidden;
15
+
16
+ background-color: var(--semi-color-fill-0);
12
17
  `;
13
18
 
14
19
  export const UIMain = styled.div`
@@ -20,7 +25,28 @@ export const UIMain = styled.div`
20
25
  & .semi-input-number,
21
26
  & .semi-select {
22
27
  width: 100%;
28
+ border: none;
29
+ border-radius: 0;
30
+ }
31
+
32
+ & .semi-input-wrapper {
33
+ border: none;
34
+ border-radius: 0;
35
+ }
36
+ `;
37
+
38
+ export const UIType = styled.div`
39
+ border-right: 1px solid #e5e5e5;
40
+
41
+ & .semi-button {
42
+ border-radius: 0;
23
43
  }
24
44
  `;
25
45
 
26
- export const UITrigger = styled.div``;
46
+ export const UITrigger = styled.div`
47
+ border-left: 1px solid #e5e5e5;
48
+
49
+ & .semi-button {
50
+ border-radius: 0;
51
+ }
52
+ `;
@@ -16,3 +16,4 @@ export * from './prompt-editor-with-variables';
16
16
  export * from './prompt-editor-with-inputs';
17
17
  export * from './code-editor';
18
18
  export * from './json-editor-with-variables';
19
+ export * from './inputs-values';
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "inputs-values",
3
+ "depMaterials": [
4
+ "flow-value",
5
+ "dynamic-value-input"
6
+ ],
7
+ "depPackages": [
8
+ "@douyinfe/semi-ui",
9
+ "@douyinfe/semi-icons",
10
+ "styled-components"
11
+ ]
12
+ }
@@ -0,0 +1,60 @@
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 { Button, IconButton, Input } from '@douyinfe/semi-ui';
9
+ import { IconDelete, IconPlus } from '@douyinfe/semi-icons';
10
+
11
+ import { PropsType } from './types';
12
+ import { DynamicValueInput } from '../dynamic-value-input';
13
+ import { IFlowConstantRefValue, IFlowValue } from '../../typings';
14
+ import { useObjectList } from '../../hooks';
15
+ import { UIRow, UIRows } from './styles';
16
+
17
+ export function InputsValues({ value, onChange, style, readonly, constantProps }: PropsType) {
18
+ const { list, updateKey, updateValue, remove, add } = useObjectList<IFlowValue | undefined>({
19
+ value,
20
+ onChange,
21
+ });
22
+
23
+ return (
24
+ <div>
25
+ <UIRows style={style}>
26
+ {list.map((item) => (
27
+ <UIRow key={item.id}>
28
+ <Input
29
+ style={{ width: 100, minWidth: 100, maxWidth: 100 }}
30
+ disabled={readonly}
31
+ size="small"
32
+ value={item.key}
33
+ onChange={(v) => updateKey(item.id, v)}
34
+ />
35
+ <DynamicValueInput
36
+ style={{ flexGrow: 1 }}
37
+ readonly={readonly}
38
+ value={item.value as IFlowConstantRefValue}
39
+ onChange={(v) => updateValue(item.id, v)}
40
+ constantProps={{
41
+ ...constantProps,
42
+ strategies: [...(constantProps?.strategies || [])],
43
+ }}
44
+ />
45
+ <IconButton
46
+ disabled={readonly}
47
+ theme="borderless"
48
+ icon={<IconDelete size="small" />}
49
+ size="small"
50
+ onClick={() => remove(item.id)}
51
+ />
52
+ </UIRow>
53
+ ))}
54
+ </UIRows>
55
+ <Button disabled={readonly} icon={<IconPlus />} size="small" onClick={add}>
56
+ Add
57
+ </Button>
58
+ </div>
59
+ );
60
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import styled from 'styled-components';
7
+
8
+ export const UIRows = styled.div`
9
+ display: flex;
10
+ flex-direction: column;
11
+ gap: 10px;
12
+ margin-bottom: 10px;
13
+ `;
14
+
15
+ export const UIRow = styled.div`
16
+ display: flex;
17
+ align-items: center;
18
+ gap: 5px;
19
+ `;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { Strategy } from '../constant-input/types';
7
+ import { IFlowValue } from '../../typings';
8
+
9
+ export interface PropsType {
10
+ value?: Record<string, IFlowValue | undefined>;
11
+ onChange: (value?: Record<string, IFlowValue | undefined>) => void;
12
+ readonly?: boolean;
13
+ hasError?: boolean;
14
+ style?: React.CSSProperties;
15
+ constantProps?: {
16
+ strategies?: Strategy[];
17
+ [key: string]: any;
18
+ };
19
+ }
@@ -44,8 +44,9 @@ export function JsonSchemaEditor(props: {
44
44
  onChange?: (value: IJsonSchema) => void;
45
45
  config?: ConfigType;
46
46
  className?: string;
47
+ readonly?: boolean;
47
48
  }) {
48
- const { value = { type: 'object' }, config = {}, onChange: onChangeProps } = props;
49
+ const { value = { type: 'object' }, config = {}, onChange: onChangeProps, readonly } = props;
49
50
  const { propertyList, onAddProperty, onRemoveProperty, onEditProperty } = usePropertiesEdit(
50
51
  value,
51
52
  onChangeProps
@@ -56,6 +57,7 @@ export function JsonSchemaEditor(props: {
56
57
  <UIProperties>
57
58
  {propertyList.map((_property, index) => (
58
59
  <PropertyEdit
60
+ readonly={readonly}
59
61
  key={_property.key}
60
62
  value={_property}
61
63
  config={config}
@@ -70,6 +72,7 @@ export function JsonSchemaEditor(props: {
70
72
  ))}
71
73
  </UIProperties>
72
74
  <Button
75
+ disabled={readonly}
73
76
  size="small"
74
77
  style={{ marginTop: 10, marginLeft: 16 }}
75
78
  icon={<IconPlus />}
@@ -86,6 +89,7 @@ function PropertyEdit(props: {
86
89
  config?: ConfigType;
87
90
  onChange?: (value: PropertyValueType) => void;
88
91
  onRemove?: () => void;
92
+ readonly?: boolean;
89
93
  $isLast?: boolean;
90
94
  $index?: number;
91
95
  $isFirst?: boolean;
@@ -97,6 +101,7 @@ function PropertyEdit(props: {
97
101
  const {
98
102
  value,
99
103
  config,
104
+ readonly,
100
105
  $level = 0,
101
106
  onChange: onChangeProps,
102
107
  onRemove,
@@ -155,6 +160,7 @@ function PropertyEdit(props: {
155
160
  <UIRow>
156
161
  <UIName>
157
162
  <BlurInput
163
+ disabled={readonly}
158
164
  placeholder={config?.placeholder ?? 'Input Variable Name'}
159
165
  size="small"
160
166
  value={name}
@@ -164,6 +170,7 @@ function PropertyEdit(props: {
164
170
  <UIType>
165
171
  <TypeSelector
166
172
  value={typeSelectorValue}
173
+ readonly={readonly}
167
174
  onChange={(_value) => {
168
175
  onChangeProps?.({
169
176
  ...(value || {}),
@@ -174,12 +181,14 @@ function PropertyEdit(props: {
174
181
  </UIType>
175
182
  <UIRequired>
176
183
  <Checkbox
184
+ disabled={readonly}
177
185
  checked={isPropertyRequired}
178
186
  onChange={(e) => onChange('isPropertyRequired', e.target.checked)}
179
187
  />
180
188
  </UIRequired>
181
189
  <UIActions>
182
190
  <IconButton
191
+ disabled={readonly}
183
192
  size="small"
184
193
  theme="borderless"
185
194
  icon={expand ? <IconShrink size="small" /> : <IconExpand size="small" />}
@@ -189,6 +198,7 @@ function PropertyEdit(props: {
189
198
  />
190
199
  {isDrilldownObject && (
191
200
  <IconButton
201
+ disabled={readonly}
192
202
  size="small"
193
203
  theme="borderless"
194
204
  icon={<IconAddChildren />}
@@ -199,6 +209,7 @@ function PropertyEdit(props: {
199
209
  />
200
210
  )}
201
211
  <IconButton
212
+ disabled={readonly}
202
213
  size="small"
203
214
  theme="borderless"
204
215
  icon={<IconMinus size="small" />}
@@ -210,6 +221,7 @@ function PropertyEdit(props: {
210
221
  <UIExpandDetail>
211
222
  <UILabel>{config?.descTitle ?? 'Description'}</UILabel>
212
223
  <BlurInput
224
+ disabled={readonly}
213
225
  size="small"
214
226
  value={description}
215
227
  onChange={(value) => onChange('description', value)}
@@ -240,6 +252,7 @@ function PropertyEdit(props: {
240
252
  <UIProperties $shrink={true}>
241
253
  {propertyList.map((_property, index) => (
242
254
  <PropertyEdit
255
+ readonly={readonly}
243
256
  key={_property.key}
244
257
  value={_property}
245
258
  config={config}
@@ -79,7 +79,7 @@ export function InputsPicker({
79
79
  const treeData: TreeNodeData[] = useMemo(
80
80
  () =>
81
81
  Object.entries(inputsValues).map(([key, value]) => {
82
- if (value.type === 'ref') {
82
+ if (value?.type === 'ref') {
83
83
  const variable = available.getByKeyPath(value.content || []);
84
84
 
85
85
  if (variable) {
@@ -5,14 +5,18 @@
5
5
 
6
6
  import React, { useMemo } from 'react';
7
7
 
8
- import { Button, Cascader } from '@douyinfe/semi-ui';
8
+ import { Cascader, IconButton } from '@douyinfe/semi-ui';
9
9
 
10
10
  import { IJsonSchema } from '../../typings';
11
11
  import { ArrayIcons, VariableTypeIcons, getSchemaIcon, options } from './constants';
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
  }
@@ -36,24 +40,27 @@ export const parseTypeSelectValue = (value?: string[]): Partial<IJsonSchema> | u
36
40
  };
37
41
 
38
42
  export function TypeSelector(props: PropTypes) {
39
- const { value, onChange, disabled, style } = props;
43
+ const { value, onChange, readonly, disabled, style } = props;
40
44
 
41
45
  const selectValue = useMemo(() => getTypeSelectValue(value), [value]);
42
46
 
43
47
  return (
44
48
  <Cascader
45
- disabled={disabled}
49
+ disabled={readonly || disabled}
46
50
  size="small"
47
51
  triggerRender={() => (
48
- <Button size="small" style={style}>
49
- {getSchemaIcon(value)}
50
- </Button>
52
+ <IconButton
53
+ size="small"
54
+ style={style}
55
+ disabled={readonly || disabled}
56
+ icon={getSchemaIcon(value)}
57
+ />
51
58
  )}
52
59
  treeData={options}
53
60
  value={selectValue}
54
61
  leafOnly={true}
55
62
  onChange={(value) => {
56
- onChange(parseTypeSelectValue(value as string[]));
63
+ onChange?.(parseTypeSelectValue(value as string[]));
57
64
  }}
58
65
  />
59
66
  );
@@ -7,11 +7,12 @@ import React, { useMemo } from 'react';
7
7
 
8
8
  import { TriggerRenderProps } from '@douyinfe/semi-ui/lib/es/treeSelect';
9
9
  import { TreeNodeData } from '@douyinfe/semi-ui/lib/es/tree';
10
+ import { Popover } from '@douyinfe/semi-ui';
10
11
  import { IconChevronDownStroked, IconIssueStroked } from '@douyinfe/semi-icons';
11
12
 
12
13
  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,17 +94,35 @@ 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 ? `${_option.rootMeta?.title} -` : null}
102
+ </UIRootTitle>
103
+ );
104
+
96
105
  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>
106
+ <div>
107
+ <Popover
108
+ content={
109
+ <UIPopoverContent>
110
+ {rootIcon}
111
+ {rootTitle}
112
+ <UIVarName>{_option.keyPath.slice(1).join('.')}</UIVarName>
113
+ </UIPopoverContent>
114
+ }
115
+ >
116
+ <UITag
117
+ prefixIcon={rootIcon}
118
+ closable={!readonly}
119
+ onClose={() => onChange(undefined)}
120
+ >
121
+ {rootTitle}
122
+ <UIVarName $inSelector>{_option.label}</UIVarName>
123
+ </UITag>
124
+ </Popover>
125
+ </div>
107
126
  );
108
127
  }}
109
128
  showClear={false}