Browse Source

feat(variable): add @flowgram.ai/json-schema and adjust json schema's materials (#602)

* feat(variable): add @flowgram.ai/json-schema and adjust json schema's materials

feat: init json schema

feat: json schema plugin

feat: add json schema context provider

feat: inputs values refresh

feat: display flow valuewarning

fix: loop initial data

feat: remove variable type icons constant

feat: object array constant input

fix: variable panel display

feat: display outputs

feat: display outputs

feat: display schema tree

feat: json schema preset

feat: flowgram json schema convert

* feat: optimize code

* feat: global type editor

* feat: remove useless code
Yiwei Mao 5 months ago
parent
commit
9700456bf3
100 changed files with 1236 additions and 815 deletions
  1. 2 2
      apps/demo-fixed-layout/src/form-components/form-item/index.tsx
  2. 2 19
      apps/demo-fixed-layout/src/form-components/form-outputs/index.tsx
  3. 0 2
      apps/demo-fixed-layout/src/form-components/index.ts
  4. 0 53
      apps/demo-fixed-layout/src/form-components/type-tag.tsx
  5. 0 22
      apps/demo-fixed-layout/src/form-components/value-display/index.tsx
  6. 0 20
      apps/demo-fixed-layout/src/form-components/value-display/styles.tsx
  7. 2 7
      apps/demo-fixed-layout/src/initial-data.ts
  8. 27 35
      apps/demo-fixed-layout/src/nodes/end/form-meta.tsx
  9. 11 3
      apps/demo-free-layout/src/components/testrun/testrun-form/index.tsx
  10. 5 2
      apps/demo-free-layout/src/form-components/form-item/index.tsx
  11. 0 39
      apps/demo-free-layout/src/form-components/form-outputs/index.tsx
  12. 0 19
      apps/demo-free-layout/src/form-components/form-outputs/styles.tsx
  13. 0 3
      apps/demo-free-layout/src/form-components/index.ts
  14. 0 53
      apps/demo-free-layout/src/form-components/type-tag.tsx
  15. 0 22
      apps/demo-free-layout/src/form-components/value-display/index.tsx
  16. 0 20
      apps/demo-free-layout/src/form-components/value-display/styles.tsx
  17. 13 7
      apps/demo-free-layout/src/initial-data.ts
  18. 12 2
      apps/demo-free-layout/src/nodes/code/components/inputs.tsx
  19. 9 2
      apps/demo-free-layout/src/nodes/code/components/outputs.tsx
  20. 1 3
      apps/demo-free-layout/src/nodes/code/form-meta.tsx
  21. 5 2
      apps/demo-free-layout/src/nodes/default-form-meta.tsx
  22. 9 4
      apps/demo-free-layout/src/nodes/end/form-meta.tsx
  23. 13 2
      apps/demo-free-layout/src/nodes/http/components/headers.tsx
  24. 13 2
      apps/demo-free-layout/src/nodes/http/components/params.tsx
  25. 5 4
      apps/demo-free-layout/src/nodes/http/form-meta.tsx
  26. 4 3
      apps/demo-free-layout/src/nodes/loop/form-meta.tsx
  27. 4 2
      apps/demo-free-layout/src/nodes/start/form-meta.tsx
  28. 1 0
      apps/demo-vite/package.json
  29. 10 0
      apps/demo-vite/src/hooks/use-editor-props.tsx
  30. 75 12
      common/config/rush/pnpm-lock.yaml
  31. 11 5
      packages/materials/form-materials/bin/index.ts
  32. 1 1
      packages/materials/form-materials/bin/materials.ts
  33. 1 0
      packages/materials/form-materials/package.json
  34. 6 2
      packages/materials/form-materials/src/components/batch-variable-selector/config.json
  35. 1 1
      packages/materials/form-materials/src/components/batch-variable-selector/index.tsx
  36. 7 0
      packages/materials/form-materials/src/components/code-editor-mini/config.json
  37. 31 0
      packages/materials/form-materials/src/components/code-editor-mini/index.tsx
  38. 1 1
      packages/materials/form-materials/src/components/code-editor/theme/light.ts
  39. 10 2
      packages/materials/form-materials/src/components/condition-row/config.json
  40. 2 2
      packages/materials/form-materials/src/components/condition-row/hooks/useRule.ts
  41. 1 1
      packages/materials/form-materials/src/components/condition-row/index.tsx
  42. 3 1
      packages/materials/form-materials/src/components/condition-row/types.ts
  43. 6 3
      packages/materials/form-materials/src/components/constant-input/config.json
  44. 10 71
      packages/materials/form-materials/src/components/constant-input/index.tsx
  45. 6 10
      packages/materials/form-materials/src/components/constant-input/types.ts
  46. 8 0
      packages/materials/form-materials/src/components/display-flow-value/config.json
  47. 59 0
      packages/materials/form-materials/src/components/display-flow-value/index.tsx
  48. 9 0
      packages/materials/form-materials/src/components/display-inputs-values/config.json
  49. 27 0
      packages/materials/form-materials/src/components/display-inputs-values/index.tsx
  50. 12 0
      packages/materials/form-materials/src/components/display-inputs-values/styles.ts
  51. 10 0
      packages/materials/form-materials/src/components/display-outputs/config.json
  52. 58 0
      packages/materials/form-materials/src/components/display-outputs/index.tsx
  53. 12 0
      packages/materials/form-materials/src/components/display-outputs/styles.ts
  54. 10 0
      packages/materials/form-materials/src/components/display-schema-tag/config.json
  55. 44 0
      packages/materials/form-materials/src/components/display-schema-tag/index.tsx
  56. 28 0
      packages/materials/form-materials/src/components/display-schema-tag/styles.ts
  57. 11 0
      packages/materials/form-materials/src/components/display-schema-tree/config.json
  58. 74 0
      packages/materials/form-materials/src/components/display-schema-tree/index.tsx
  59. 90 0
      packages/materials/form-materials/src/components/display-schema-tree/styles.tsx
  60. 11 2
      packages/materials/form-materials/src/components/dynamic-value-input/config.json
  61. 53 0
      packages/materials/form-materials/src/components/dynamic-value-input/hooks.ts
  62. 30 28
      packages/materials/form-materials/src/components/dynamic-value-input/index.tsx
  63. 6 0
      packages/materials/form-materials/src/components/index.ts
  64. 2 1
      packages/materials/form-materials/src/components/inputs-values/config.json
  65. 3 1
      packages/materials/form-materials/src/components/inputs-values/types.ts
  66. 3 3
      packages/materials/form-materials/src/components/json-schema-editor/config.json
  67. 1 1
      packages/materials/form-materials/src/components/json-schema-editor/default-value.tsx
  68. 1 1
      packages/materials/form-materials/src/components/json-schema-editor/hooks.tsx
  69. 1 1
      packages/materials/form-materials/src/components/json-schema-editor/index.tsx
  70. 1 1
      packages/materials/form-materials/src/components/json-schema-editor/types.ts
  71. 6 2
      packages/materials/form-materials/src/components/type-selector/config.json
  72. 0 255
      packages/materials/form-materials/src/components/type-selector/constants.tsx
  73. 47 11
      packages/materials/form-materials/src/components/type-selector/index.tsx
  74. 6 2
      packages/materials/form-materials/src/components/variable-selector/config.json
  75. 1 1
      packages/materials/form-materials/src/components/variable-selector/index.tsx
  76. 14 20
      packages/materials/form-materials/src/components/variable-selector/use-variable-tree.tsx
  77. 4 5
      packages/materials/form-materials/src/effects/provide-json-schema-outputs/config.json
  78. 1 3
      packages/materials/form-materials/src/effects/provide-json-schema-outputs/index.ts
  79. 1 0
      packages/materials/form-materials/src/effects/sync-variable-title/index.ts
  80. 3 1
      packages/materials/form-materials/src/form-plugins/infer-inputs-plugin/config.json
  81. 2 2
      packages/materials/form-materials/src/form-plugins/infer-inputs-plugin/index.ts
  82. 1 1
      packages/materials/form-materials/src/index.ts
  83. 0 0
      packages/materials/form-materials/src/shared/format-legacy-refs/config.json
  84. 0 0
      packages/materials/form-materials/src/shared/format-legacy-refs/index.ts
  85. 0 0
      packages/materials/form-materials/src/shared/format-legacy-refs/readme.md
  86. 1 1
      packages/materials/form-materials/src/shared/index.ts
  87. 9 0
      packages/materials/form-materials/src/shared/json-schema-preset/config.json
  88. 26 0
      packages/materials/form-materials/src/shared/json-schema-preset/create-type-preset-plugin.tsx
  89. 39 0
      packages/materials/form-materials/src/shared/json-schema-preset/index.tsx
  90. 18 0
      packages/materials/form-materials/src/shared/json-schema-preset/manager.ts
  91. 23 0
      packages/materials/form-materials/src/shared/json-schema-preset/type-definition/array.tsx
  92. 32 0
      packages/materials/form-materials/src/shared/json-schema-preset/type-definition/boolean.tsx
  93. 24 0
      packages/materials/form-materials/src/shared/json-schema-preset/type-definition/index.tsx
  94. 24 0
      packages/materials/form-materials/src/shared/json-schema-preset/type-definition/integer.tsx
  95. 24 0
      packages/materials/form-materials/src/shared/json-schema-preset/type-definition/number.tsx
  96. 23 0
      packages/materials/form-materials/src/shared/json-schema-preset/type-definition/object.tsx
  97. 18 0
      packages/materials/form-materials/src/shared/json-schema-preset/type-definition/string.tsx
  98. 4 4
      packages/materials/form-materials/src/typings/flow-value/config.json
  99. 1 1
      packages/materials/form-materials/src/typings/flow-value/index.ts
  100. 0 1
      packages/materials/form-materials/src/typings/index.ts

+ 2 - 2
apps/demo-fixed-layout/src/form-components/form-item/index.tsx

@@ -5,9 +5,9 @@
 
 import React, { useCallback } from 'react';
 
+import { DisplaySchemaTag } from '@flowgram.ai/form-materials';
 import { Typography, Tooltip } from '@douyinfe/semi-ui';
 
-import { TypeTag } from '../type-tag';
 import './index.css';
 
 const { Text } = Typography;
@@ -70,7 +70,7 @@ export function FormItem({
           flexShrink: 0,
         }}
       >
-        <TypeTag className="form-item-type-tag" type={type} />
+        <DisplaySchemaTag value={{ type }} />
         {description ? <Tooltip content={description}>{renderTitle()}</Tooltip> : renderTitle(true)}
       </div>
 

+ 2 - 19
apps/demo-fixed-layout/src/form-components/form-outputs/index.tsx

@@ -3,31 +3,14 @@
  * SPDX-License-Identifier: MIT
  */
 
-import { Field } from '@flowgram.ai/fixed-layout-editor';
+import { DisplayOutputs } from '@flowgram.ai/form-materials';
 
-import { TypeTag } from '../type-tag';
-import { JsonSchema } from '../../typings';
 import { useIsSidebar } from '../../hooks';
-import { FormOutputsContainer } from './styles';
 
 export function FormOutputs() {
   const isSidebar = useIsSidebar();
   if (isSidebar) {
     return null;
   }
-  return (
-    <Field<JsonSchema> name={'outputs'}>
-      {({ field }) => {
-        const properties = field.value?.properties;
-        if (properties) {
-          const content = Object.keys(properties).map((key) => {
-            const property = properties[key];
-            return <TypeTag key={key} name={key} type={property.type as string} />;
-          });
-          return <FormOutputsContainer>{content}</FormOutputsContainer>;
-        }
-        return <></>;
-      }}
-    </Field>
-  );
+  return <DisplayOutputs displayFromScope />;
 }

+ 0 - 2
apps/demo-fixed-layout/src/form-components/index.ts

@@ -9,6 +9,4 @@ export * from './form-outputs';
 export * from './form-inputs';
 export * from './form-header';
 export * from './form-item';
-export * from './type-tag';
 export * from './properties-edit';
-export * from './value-display';

+ 0 - 53
apps/demo-fixed-layout/src/form-components/type-tag.tsx

@@ -1,53 +0,0 @@
-/**
- * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
- * SPDX-License-Identifier: MIT
- */
-
-import styled from 'styled-components';
-import { VariableTypeIcons, ArrayIcons } from '@flowgram.ai/form-materials';
-import { Tag, Tooltip } from '@douyinfe/semi-ui';
-
-interface PropsType {
-  name?: string | JSX.Element;
-  type: string;
-  className?: string;
-  isArray?: boolean;
-}
-
-const TooltipContainer = styled.div`
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  column-gap: 6px;
-`;
-
-export function TypeTag({ name, type, isArray, className }: PropsType) {
-  const icon = isArray ? ArrayIcons[type] : VariableTypeIcons[type];
-  return (
-    <Tooltip
-      content={
-        <TooltipContainer>
-          {icon} {type}
-        </TooltipContainer>
-      }
-    >
-      <Tag color="white" className={className} style={{ padding: 4, maxWidth: 450 }}>
-        {icon}
-        {name && (
-          <span
-            style={{
-              display: 'inline-block',
-              marginLeft: 4,
-              marginTop: -1,
-              overflow: 'hidden',
-              textOverflow: 'ellipsis',
-            }}
-          >
-            {' '}
-            {name}
-          </span>
-        )}
-      </Tag>
-    </Tooltip>
-  );
-}

+ 0 - 22
apps/demo-fixed-layout/src/form-components/value-display/index.tsx

@@ -1,22 +0,0 @@
-/**
- * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
- * SPDX-License-Identifier: MIT
- */
-
-// import { TypeTag } from '../type-tag'
-import { ValueDisplayStyle } from './styles';
-
-export interface ValueDisplayProps {
-  value: string;
-  placeholder?: string;
-  hasError?: boolean;
-}
-
-export const ValueDisplay: React.FC<ValueDisplayProps> = (props) => (
-  <ValueDisplayStyle className={props.hasError ? 'has-error' : ''}>
-    {props.value}
-    {props.value === undefined || props.value === '' ? (
-      <span style={{ color: 'var(--semi-color-text-2)' }}>{props.placeholder || '--'}</span>
-    ) : null}
-  </ValueDisplayStyle>
-);

+ 0 - 20
apps/demo-fixed-layout/src/form-components/value-display/styles.tsx

@@ -1,20 +0,0 @@
-/**
- * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
- * SPDX-License-Identifier: MIT
- */
-
-import styled from 'styled-components';
-
-export const ValueDisplayStyle = styled.div`
-  background-color: var(--semi-color-fill-0);
-  border-radius: var(--semi-border-radius-small);
-  padding-left: 12px;
-  width: 100%;
-  min-height: 24px;
-  line-height: 24px;
-  display: flex;
-  align-items: center;
-  &.has-error {
-    outline: red solid 1px;
-  }
-`;

+ 2 - 7
apps/demo-fixed-layout/src/initial-data.ts

@@ -373,13 +373,8 @@ export const initialData: FlowDocumentJSON = {
       blocks: [],
       data: {
         title: 'End',
-        outputs: {
-          type: 'object',
-          properties: {
-            result: {
-              type: 'string',
-            },
-          },
+        inputsValues: {
+          success: { type: 'constant', content: true, schema: { type: 'boolean' } },
         },
       },
     },

+ 27 - 35
apps/demo-fixed-layout/src/nodes/end/form-meta.tsx

@@ -3,14 +3,17 @@
  * SPDX-License-Identifier: MIT
  */
 
-import { mapValues } from 'lodash-es';
-import { IFlowValue } from '@flowgram.ai/form-materials';
-import { Field, FieldRenderProps, FormMeta } from '@flowgram.ai/fixed-layout-editor';
+import {
+  createInferInputsPlugin,
+  DisplayInputsValues,
+  IFlowValue,
+  InputsValues,
+} from '@flowgram.ai/form-materials';
+import { Field, FormMeta } from '@flowgram.ai/fixed-layout-editor';
 
 import { defaultFormMeta } from '../default-form-meta';
-import { JsonSchema } from '../../typings';
 import { useIsSidebar } from '../../hooks';
-import { FormHeader, FormContent, FormOutputs, PropertiesEdit } from '../../form-components';
+import { FormHeader, FormContent } from '../../form-components';
 
 export const renderForm = () => {
   const isSidebar = useIsSidebar();
@@ -19,36 +22,13 @@ export const renderForm = () => {
       <>
         <FormHeader />
         <FormContent>
-          <Field
-            name="outputs.properties"
-            render={({
-              field: { value: propertiesSchemaValue, onChange: propertiesSchemaChange },
-            }: FieldRenderProps<Record<string, JsonSchema>>) => (
-              <Field<Record<string, IFlowValue>> name="inputsValues">
-                {({ field: { value: propertiesValue, onChange: propertiesValueChange } }) => {
-                  const onChange = (newProperties: Record<string, JsonSchema>) => {
-                    const newPropertiesValue = mapValues(newProperties, (v) => v.default);
-                    const newPropetiesSchema = mapValues(newProperties, (v) => {
-                      delete v.default;
-                      return v;
-                    });
-                    propertiesValueChange(newPropertiesValue);
-                    propertiesSchemaChange(newPropetiesSchema);
-                  };
-                  const value = mapValues(propertiesSchemaValue, (v, key) => ({
-                    ...v,
-                    default: propertiesValue?.[key],
-                  }));
-                  return (
-                    <>
-                      <PropertiesEdit value={value} onChange={onChange} useFx={true} />
-                    </>
-                  );
-                }}
-              </Field>
+          <Field<Record<string, IFlowValue | undefined> | undefined> name="inputsValues">
+            {({ field: { value, onChange } }) => (
+              <>
+                <InputsValues value={value} onChange={(_v) => onChange(_v)} />
+              </>
             )}
-          />
-          <FormOutputs />
+          </Field>
         </FormContent>
       </>
     );
@@ -57,7 +37,13 @@ export const renderForm = () => {
     <>
       <FormHeader />
       <FormContent>
-        <FormOutputs />
+        <Field<Record<string, IFlowValue | undefined> | undefined> name="inputsValues">
+          {({ field: { value } }) => (
+            <>
+              <DisplayInputsValues value={value} />
+            </>
+          )}
+        </Field>
       </FormContent>
     </>
   );
@@ -66,4 +52,10 @@ export const renderForm = () => {
 export const formMeta: FormMeta = {
   ...defaultFormMeta,
   render: renderForm,
+  plugins: [
+    createInferInputsPlugin({
+      sourceKey: 'inputsValues',
+      targetKey: 'inputs',
+    }),
+  ],
 };

+ 11 - 3
apps/demo-free-layout/src/components/testrun/testrun-form/index.tsx

@@ -6,13 +6,12 @@
 import { FC } from 'react';
 
 import classNames from 'classnames';
-import { CodeEditor } from '@flowgram.ai/form-materials';
+import { CodeEditor, DisplaySchemaTag } from '@flowgram.ai/form-materials';
 import { Input, Switch, InputNumber } from '@douyinfe/semi-ui';
 
 import { useFormMeta } from '../hooks/use-form-meta';
 import { useFields } from '../hooks/use-fields';
 import { useSyncDefault } from '../hooks';
-import { TypeTag } from '../../../form-components';
 
 import styles from './index.module.less';
 
@@ -118,7 +117,16 @@ export const TestRunForm: FC<TestRunFormProps> = ({ values, setValues }) => {
             {field.name}
             {field.required && <span className={styles.requiredIndicator}>*</span>}
             <span className={styles.fieldTypeIndicator}>
-              <TypeTag type={field.itemsType ?? field.type} isArray={field.type === 'array'} />
+              <DisplaySchemaTag
+                value={{
+                  type: field.type,
+                  items: field.itemsType
+                    ? {
+                        type: field.itemsType,
+                      }
+                    : undefined,
+                }}
+              />
             </span>
           </label>
           {renderField(field)}

+ 5 - 2
apps/demo-free-layout/src/form-components/form-item/index.tsx

@@ -5,9 +5,9 @@
 
 import React, { useCallback } from 'react';
 
+import { DisplaySchemaTag } from '@flowgram.ai/form-materials';
 import { Typography, Tooltip } from '@douyinfe/semi-ui';
 
-import { TypeTag } from '../type-tag';
 import './index.css';
 
 const { Text } = Typography;
@@ -19,6 +19,7 @@ interface FormItemProps {
   required?: boolean;
   description?: string;
   labelWidth?: number;
+  labelStyle?: React.CSSProperties;
   vertical?: boolean;
   style?: React.CSSProperties;
 }
@@ -29,6 +30,7 @@ export function FormItem({
   description,
   type,
   labelWidth,
+  labelStyle,
   vertical,
   style,
 }: FormItemProps): JSX.Element {
@@ -73,9 +75,10 @@ export function FormItem({
           display: 'flex',
           columnGap: 4,
           flexShrink: 0,
+          ...labelStyle,
         }}
       >
-        {type && <TypeTag className="form-item-type-tag" type={type} />}
+        {type && <DisplaySchemaTag value={{ type }} />}
         {description ? <Tooltip content={description}>{renderTitle()}</Tooltip> : renderTitle(true)}
       </div>
 

+ 0 - 39
apps/demo-free-layout/src/form-components/form-outputs/index.tsx

@@ -1,39 +0,0 @@
-/**
- * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
- * SPDX-License-Identifier: MIT
- */
-
-import { FC } from 'react';
-
-import { Field } from '@flowgram.ai/free-layout-editor';
-
-import { TypeTag } from '../type-tag';
-import { JsonSchema } from '../../typings';
-import { useIsSidebar } from '../../hooks';
-import { FormOutputsContainer } from './styles';
-
-interface FormOutputsProps {
-  name?: string;
-}
-
-export const FormOutputs: FC<FormOutputsProps> = ({ name = 'outputs' }) => {
-  const isSidebar = useIsSidebar();
-  if (isSidebar) {
-    return null;
-  }
-  return (
-    <Field<JsonSchema> name={name}>
-      {({ field }) => {
-        const properties = field.value?.properties;
-        if (properties) {
-          const content = Object.keys(properties).map((key) => {
-            const property = properties[key];
-            return <TypeTag key={key} name={key} type={property.type as string} />;
-          });
-          return <FormOutputsContainer>{content}</FormOutputsContainer>;
-        }
-        return <></>;
-      }}
-    </Field>
-  );
-};

+ 0 - 19
apps/demo-free-layout/src/form-components/form-outputs/styles.tsx

@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
- * SPDX-License-Identifier: MIT
- */
-
-import styled from 'styled-components';
-
-export const FormOutputsContainer = styled.div`
-  display: flex;
-  gap: 6px;
-  flex-wrap: wrap;
-  border-top: 1px solid var(--semi-color-border);
-  padding: 8px 0 0;
-  width: 100%;
-
-  :global(.semi-tag .semi-tag-content) {
-    font-size: 10px;
-  }
-`;

+ 0 - 3
apps/demo-free-layout/src/form-components/index.ts

@@ -5,9 +5,6 @@
 
 export * from './feedback';
 export * from './form-content';
-export * from './form-outputs';
 export * from './form-inputs';
 export * from './form-header';
 export * from './form-item';
-export * from './type-tag';
-export * from './value-display';

+ 0 - 53
apps/demo-free-layout/src/form-components/type-tag.tsx

@@ -1,53 +0,0 @@
-/**
- * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
- * SPDX-License-Identifier: MIT
- */
-
-import styled from 'styled-components';
-import { VariableTypeIcons, ArrayIcons } from '@flowgram.ai/form-materials';
-import { Tag, Tooltip } from '@douyinfe/semi-ui';
-
-interface PropsType {
-  name?: string | JSX.Element;
-  type: string;
-  className?: string;
-  isArray?: boolean;
-}
-
-const TooltipContainer = styled.div`
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  column-gap: 6px;
-`;
-
-export function TypeTag({ name, type, isArray, className }: PropsType) {
-  const icon = isArray ? ArrayIcons[type] : VariableTypeIcons[type];
-  return (
-    <Tooltip
-      content={
-        <TooltipContainer>
-          {icon} {type}
-        </TooltipContainer>
-      }
-    >
-      <Tag color="white" className={className} style={{ padding: 4, maxWidth: 450 }}>
-        {icon}
-        {name && (
-          <span
-            style={{
-              display: 'inline-block',
-              marginLeft: 4,
-              marginTop: -1,
-              overflow: 'hidden',
-              textOverflow: 'ellipsis',
-            }}
-          >
-            {' '}
-            {name}
-          </span>
-        )}
-      </Tag>
-    </Tooltip>
-  );
-}

+ 0 - 22
apps/demo-free-layout/src/form-components/value-display/index.tsx

@@ -1,22 +0,0 @@
-/**
- * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
- * SPDX-License-Identifier: MIT
- */
-
-// import { TypeTag } from '../type-tag'
-import { ValueDisplayStyle } from './styles';
-
-export interface ValueDisplayProps {
-  value: string;
-  placeholder?: string;
-  hasError?: boolean;
-}
-
-export const ValueDisplay: React.FC<ValueDisplayProps> = (props) => (
-  <ValueDisplayStyle className={props.hasError ? 'has-error' : ''}>
-    {props.value}
-    {props.value === undefined || props.value === '' ? (
-      <span style={{ color: 'var(--semi-color-text-2)' }}>{props.placeholder || '--'}</span>
-    ) : null}
-  </ValueDisplayStyle>
-);

+ 0 - 20
apps/demo-free-layout/src/form-components/value-display/styles.tsx

@@ -1,20 +0,0 @@
-/**
- * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
- * SPDX-License-Identifier: MIT
- */
-
-import styled from 'styled-components';
-
-export const ValueDisplayStyle = styled.div`
-  background-color: var(--semi-color-fill-0);
-  border-radius: var(--semi-border-radius-small);
-  padding-left: 12px;
-  width: 100%;
-  min-height: 24px;
-  line-height: 24px;
-  display: flex;
-  align-items: center;
-  &.has-error {
-    outline: red solid 1px;
-  }
-`;

+ 13 - 7
apps/demo-free-layout/src/initial-data.ts

@@ -97,13 +97,9 @@ export const initialData: FlowDocumentJSON = {
       },
       data: {
         title: 'End',
-        inputs: {
-          type: 'object',
-          properties: {
-            result: {
-              type: 'string',
-            },
-          },
+        inputsValues: {
+          success: { type: 'constant', content: true, schema: { type: 'boolean' } },
+          query: { type: 'ref', content: ['start_0', 'query'] },
         },
       },
     },
@@ -176,6 +172,16 @@ export const initialData: FlowDocumentJSON = {
       },
       data: {
         title: 'Loop_1',
+        loopFor: {
+          type: 'ref',
+          content: ['start_0', 'array_obj'],
+        },
+        loopOutputs: {
+          acm: {
+            type: 'ref',
+            content: ['llm_6aSyo', 'result'],
+          },
+        },
       },
       blocks: [
         {

+ 12 - 2
apps/demo-free-layout/src/nodes/code/components/inputs.tsx

@@ -4,14 +4,24 @@
  */
 
 import { Field } from '@flowgram.ai/free-layout-editor';
-import { IFlowValue, InputsValues } from '@flowgram.ai/form-materials';
+import { DisplayInputsValues, IFlowValue, InputsValues } from '@flowgram.ai/form-materials';
 
-import { useNodeRenderContext } from '../../../hooks';
+import { useIsSidebar, useNodeRenderContext } from '../../../hooks';
 import { FormItem } from '../../../form-components';
 
 export function Inputs() {
+  const isSidebar = useIsSidebar();
+
   const { readonly } = useNodeRenderContext();
 
+  if (!isSidebar) {
+    return (
+      <Field<Record<string, IFlowValue | undefined> | undefined> name="inputsValues">
+        {({ field }) => <DisplayInputsValues value={field.value} />}
+      </Field>
+    );
+  }
+
   return (
     <FormItem name="inputs" type="object" vertical>
       <Field<Record<string, IFlowValue | undefined> | undefined> name="inputsValues">

+ 9 - 2
apps/demo-free-layout/src/nodes/code/components/outputs.tsx

@@ -4,7 +4,7 @@
  */
 
 import { Field } from '@flowgram.ai/free-layout-editor';
-import { IJsonSchema, JsonSchemaEditor } from '@flowgram.ai/form-materials';
+import { DisplayOutputs, IJsonSchema, JsonSchemaEditor } from '@flowgram.ai/form-materials';
 import { Divider } from '@douyinfe/semi-ui';
 
 import { useIsSidebar, useNodeRenderContext } from '../../../hooks';
@@ -15,7 +15,14 @@ export function Outputs() {
   const isSidebar = useIsSidebar();
 
   if (!isSidebar) {
-    return null;
+    return (
+      <>
+        <Divider />
+        <Field<IJsonSchema> name="outputs">
+          {({ field }) => <DisplayOutputs value={field.value} />}
+        </Field>
+      </>
+    );
   }
 
   return (

+ 1 - 3
apps/demo-free-layout/src/nodes/code/form-meta.tsx

@@ -5,9 +5,8 @@
 
 import { FormMeta, FormRenderProps } from '@flowgram.ai/free-layout-editor';
 import { createInferInputsPlugin } from '@flowgram.ai/form-materials';
-import { Divider } from '@douyinfe/semi-ui';
 
-import { FormHeader, FormContent, FormOutputs } from '../../form-components';
+import { FormHeader, FormContent } from '../../form-components';
 import { CodeNodeJSON } from './types';
 import { Outputs } from './components/outputs';
 import { Inputs } from './components/inputs';
@@ -21,7 +20,6 @@ export const FormRender = ({ form }: FormRenderProps<CodeNodeJSON>) => (
       <Inputs />
       <Code />
       <Outputs />
-      <FormOutputs />
     </FormContent>
   </>
 );

+ 5 - 2
apps/demo-free-layout/src/nodes/default-form-meta.tsx

@@ -13,17 +13,20 @@ import {
   autoRenameRefEffect,
   provideJsonSchemaOutputs,
   syncVariableTitle,
+  DisplayOutputs,
 } from '@flowgram.ai/form-materials';
+import { Divider } from '@douyinfe/semi-ui';
 
 import { FlowNodeJSON } from '../typings';
-import { FormHeader, FormContent, FormInputs, FormOutputs } from '../form-components';
+import { FormHeader, FormContent, FormInputs } from '../form-components';
 
 export const renderForm = ({ form }: FormRenderProps<FlowNodeJSON>) => (
   <>
     <FormHeader />
     <FormContent>
       <FormInputs />
-      <FormOutputs />
+      <Divider />
+      <DisplayOutputs displayFromScope />
     </FormContent>
   </>
 );

+ 9 - 4
apps/demo-free-layout/src/nodes/end/form-meta.tsx

@@ -4,11 +4,16 @@
  */
 
 import { Field, FormMeta } from '@flowgram.ai/free-layout-editor';
-import { createInferInputsPlugin, IFlowValue, InputsValues } from '@flowgram.ai/form-materials';
+import {
+  createInferInputsPlugin,
+  DisplayInputsValues,
+  IFlowValue,
+  InputsValues,
+} from '@flowgram.ai/form-materials';
 
 import { defaultFormMeta } from '../default-form-meta';
 import { useIsSidebar } from '../../hooks';
-import { FormHeader, FormContent, FormOutputs } from '../../form-components';
+import { FormHeader, FormContent } from '../../form-components';
 
 export const renderForm = () => {
   const isSidebar = useIsSidebar();
@@ -33,9 +38,9 @@ export const renderForm = () => {
       <FormHeader />
       <FormContent>
         <Field<Record<string, IFlowValue | undefined> | undefined> name="inputsValues">
-          {({ field: { value, onChange } }) => (
+          {({ field: { value } }) => (
             <>
-              <InputsValues value={value} onChange={(_v) => onChange(_v)} />
+              <DisplayInputsValues value={value} />
             </>
           )}
         </Field>

+ 13 - 2
apps/demo-free-layout/src/nodes/http/components/headers.tsx

@@ -4,13 +4,24 @@
  */
 
 import { Field } from '@flowgram.ai/free-layout-editor';
-import { IFlowValue, InputsValues } from '@flowgram.ai/form-materials';
+import { DisplayInputsValues, IFlowValue, InputsValues } from '@flowgram.ai/form-materials';
 
-import { useNodeRenderContext } from '../../../hooks';
+import { useIsSidebar, useNodeRenderContext } from '../../../hooks';
 import { FormItem } from '../../../form-components';
 
 export function Headers() {
   const { readonly } = useNodeRenderContext();
+  const isSidebar = useIsSidebar();
+
+  if (!isSidebar) {
+    return (
+      <FormItem name="headers" type="object" vertical>
+        <Field<Record<string, IFlowValue | undefined> | undefined> name="headersValues">
+          {({ field }) => <DisplayInputsValues value={field.value} />}
+        </Field>
+      </FormItem>
+    );
+  }
 
   return (
     <FormItem name="headers" type="object" vertical>

+ 13 - 2
apps/demo-free-layout/src/nodes/http/components/params.tsx

@@ -4,13 +4,24 @@
  */
 
 import { Field } from '@flowgram.ai/free-layout-editor';
-import { IFlowValue, InputsValues } from '@flowgram.ai/form-materials';
+import { DisplayInputsValues, IFlowValue, InputsValues } from '@flowgram.ai/form-materials';
 
-import { useNodeRenderContext } from '../../../hooks';
+import { useIsSidebar, useNodeRenderContext } from '../../../hooks';
 import { FormItem } from '../../../form-components';
 
 export function Params() {
   const { readonly } = useNodeRenderContext();
+  const isSidebar = useIsSidebar();
+
+  if (!isSidebar) {
+    return (
+      <FormItem name="params" type="object" vertical>
+        <Field<Record<string, IFlowValue | undefined> | undefined> name="paramsValues">
+          {({ field }) => <DisplayInputsValues value={field.value} />}
+        </Field>
+      </FormItem>
+    );
+  }
 
   return (
     <FormItem name="params" type="object" vertical>

+ 5 - 4
apps/demo-free-layout/src/nodes/http/form-meta.tsx

@@ -3,11 +3,11 @@
  * SPDX-License-Identifier: MIT
  */
 
-import { FormMeta, FormRenderProps } from '@flowgram.ai/free-layout-editor';
-import { createInferInputsPlugin } from '@flowgram.ai/form-materials';
+import { Field, FormMeta, FormRenderProps } from '@flowgram.ai/free-layout-editor';
+import { createInferInputsPlugin, DisplayOutputs, IJsonSchema } from '@flowgram.ai/form-materials';
 import { Divider } from '@douyinfe/semi-ui';
 
-import { FormHeader, FormContent, FormOutputs } from '../../form-components';
+import { FormHeader, FormContent } from '../../form-components';
 import { HTTPNodeJSON } from './types';
 import { Timeout } from './components/timeout';
 import { Params } from './components/params';
@@ -29,7 +29,8 @@ export const FormRender = ({ form }: FormRenderProps<HTTPNodeJSON>) => (
       <Body />
       <Divider />
       <Timeout />
-      <FormOutputs />
+      <Divider />
+      <DisplayOutputs displayFromScope />
     </FormContent>
   </>
 );

+ 4 - 3
apps/demo-free-layout/src/nodes/loop/form-meta.tsx

@@ -9,13 +9,15 @@ import {
   BatchOutputs,
   BatchVariableSelector,
   createBatchOutputsFormPlugin,
+  DisplayOutputs,
   IFlowRefValue,
+  IJsonSchema,
   provideBatchInputEffect,
 } from '@flowgram.ai/form-materials';
 
 import { defaultFormMeta } from '../default-form-meta';
 import { useIsSidebar, useNodeRenderContext } from '../../hooks';
-import { FormHeader, FormContent, FormOutputs, FormItem, Feedback } from '../../form-components';
+import { FormHeader, FormContent, FormItem, Feedback } from '../../form-components';
 
 interface LoopNodeJSON extends FlowNodeJSON {
   data: {
@@ -69,7 +71,6 @@ export const LoopFormRender = ({ form }: FormRenderProps<LoopNodeJSON>) => {
         <FormContent>
           {loopFor}
           {loopOutputs}
-          <FormOutputs />
         </FormContent>
       </>
     );
@@ -80,7 +81,7 @@ export const LoopFormRender = ({ form }: FormRenderProps<LoopNodeJSON>) => {
       <FormContent>
         {loopFor}
         <SubCanvasRender offsetY={-formHeight} />
-        <FormOutputs />
+        <DisplayOutputs displayFromScope />
       </FormContent>
     </>
   );

+ 4 - 2
apps/demo-free-layout/src/nodes/start/form-meta.tsx

@@ -11,6 +11,8 @@ import {
   ValidateTrigger,
 } from '@flowgram.ai/free-layout-editor';
 import {
+  DisplayOutputs,
+  IJsonSchema,
   JsonSchemaEditor,
   provideJsonSchemaOutputs,
   syncVariableTitle,
@@ -18,7 +20,7 @@ import {
 
 import { FlowNodeJSON, JsonSchema } from '../../typings';
 import { useIsSidebar } from '../../hooks';
-import { FormHeader, FormContent, FormOutputs } from '../../form-components';
+import { FormHeader, FormContent } from '../../form-components';
 
 export const renderForm = ({ form }: FormRenderProps<FlowNodeJSON>) => {
   const isSidebar = useIsSidebar();
@@ -46,7 +48,7 @@ export const renderForm = ({ form }: FormRenderProps<FlowNodeJSON>) => {
     <>
       <FormHeader />
       <FormContent>
-        <FormOutputs />
+        <DisplayOutputs displayFromScope />
       </FormContent>
     </>
   );

+ 1 - 0
apps/demo-vite/package.json

@@ -31,6 +31,7 @@
     "@flowgram.ai/free-layout-editor": "workspace:*",
     "@flowgram.ai/free-snap-plugin": "workspace:*",
     "@flowgram.ai/minimap-plugin": "workspace:*",
+    "@flowgram.ai/form-materials": "workspace:*",
     "react": "^18",
     "react-dom": "^18"
   },

+ 10 - 0
apps/demo-vite/src/hooks/use-editor-props.tsx

@@ -14,6 +14,7 @@ import {
   Field,
   useNodeRender,
 } from '@flowgram.ai/free-layout-editor';
+import { CodeEditor } from '@flowgram.ai/form-materials';
 
 import { nodeRegistries } from '../node-registries';
 import { initialData } from '../initial-data';
@@ -58,6 +59,15 @@ export const useEditorProps = () =>
                 <Field<string> name="title">
                   {({ field }) => <div className="demo-free-node-title">{field.value}</div>}
                 </Field>
+                <Field<string> name="code">
+                  {({ field }) => (
+                    <CodeEditor
+                      languageId="typescript"
+                      value={field.value}
+                      onChange={field.onChange}
+                    />
+                  )}
+                </Field>
                 <div className="demo-free-node-content">
                   <Field<string> name="content">
                     <input />

+ 75 - 12
common/config/rush/pnpm-lock.yaml

@@ -704,6 +704,9 @@ importers:
 
   ../../apps/demo-vite:
     dependencies:
+      '@flowgram.ai/form-materials':
+        specifier: workspace:*
+        version: link:../../packages/materials/form-materials
       '@flowgram.ai/free-layout-editor':
         specifier: workspace:*
         version: link:../../packages/client/free-layout-editor
@@ -2148,6 +2151,9 @@ importers:
       '@flowgram.ai/editor':
         specifier: workspace:*
         version: link:../../client/editor
+      '@flowgram.ai/json-schema':
+        specifier: workspace:*
+        version: link:../../variable-engine/json-schema
       chalk:
         specifier: ^5.3.0
         version: 5.4.1
@@ -4075,6 +4081,70 @@ importers:
         specifier: ^1.0.1
         version: 1.1.0
 
+  ../../packages/variable-engine/json-schema:
+    dependencies:
+      '@flowgram.ai/core':
+        specifier: workspace:*
+        version: link:../../canvas-engine/core
+      '@flowgram.ai/utils':
+        specifier: workspace:*
+        version: link:../../common/utils
+      '@flowgram.ai/variable-core':
+        specifier: workspace:*
+        version: link:../variable-core
+      fast-equals:
+        specifier: ^2.0.0
+        version: 2.0.4
+      inversify:
+        specifier: ^6.0.1
+        version: 6.2.0(reflect-metadata@0.2.2)
+      lodash:
+        specifier: ^4.17.21
+        version: 4.17.21
+      nanoid:
+        specifier: ^4.0.2
+        version: 4.0.2
+      react:
+        specifier: '>=16.8'
+        version: 18.3.1
+      react-dom:
+        specifier: '>=16.8'
+        version: 18.3.1(react@18.3.1)
+      reflect-metadata:
+        specifier: ~0.2.2
+        version: 0.2.2
+    devDependencies:
+      '@flowgram.ai/eslint-config':
+        specifier: workspace:*
+        version: link:../../../config/eslint-config
+      '@flowgram.ai/ts-config':
+        specifier: workspace:*
+        version: link:../../../config/ts-config
+      '@types/lodash':
+        specifier: ^4.14.137
+        version: 4.17.13
+      '@types/react':
+        specifier: ^18
+        version: 18.3.16
+      '@types/react-dom':
+        specifier: ^18
+        version: 18.3.5(@types/react@18.3.16)
+      '@vitest/coverage-v8':
+        specifier: ^0.32.0
+        version: 0.32.4(vitest@0.34.6)
+      eslint:
+        specifier: ^8.54.0
+        version: 8.57.1
+      tsup:
+        specifier: ^8.0.1
+        version: 8.3.5(typescript@5.8.3)
+      typescript:
+        specifier: ^5.8.3
+        version: 5.8.3
+      vitest:
+        specifier: ^0.34.6
+        version: 0.34.6(jsdom@22.1.0)
+
   ../../packages/variable-engine/variable-core:
     dependencies:
       '@flowgram.ai/core':
@@ -10404,7 +10474,7 @@ packages:
   /@vitest/snapshot@0.34.6:
     resolution: {integrity: sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==}
     dependencies:
-      magic-string: 0.30.15
+      magic-string: 0.30.17
       pathe: 1.1.2
       pretty-format: 29.7.0
     dev: true
@@ -14934,7 +15004,6 @@ packages:
     resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
     dependencies:
       '@jridgewell/sourcemap-codec': 1.5.0
-    dev: false
 
   /make-dir@1.3.0:
     resolution: {integrity: sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==}
@@ -16163,12 +16232,6 @@ packages:
     resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
     engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
     hasBin: true
-    dev: false
-
-  /nanoid@3.3.8:
-    resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==}
-    engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
-    hasBin: true
 
   /nanoid@4.0.2:
     resolution: {integrity: sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw==}
@@ -16867,7 +16930,7 @@ packages:
     resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
     engines: {node: ^10 || ^12 || >=14}
     dependencies:
-      nanoid: 3.3.8
+      nanoid: 3.3.11
       picocolors: 1.1.1
       source-map-js: 1.2.1
 
@@ -16875,7 +16938,7 @@ packages:
     resolution: {integrity: sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==}
     engines: {node: ^10 || ^12 || >=14}
     dependencies:
-      nanoid: 3.3.8
+      nanoid: 3.3.11
       picocolors: 1.1.1
       source-map-js: 1.2.1
     dev: true
@@ -16884,7 +16947,7 @@ packages:
     resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==}
     engines: {node: ^10 || ^12 || >=14}
     dependencies:
-      nanoid: 3.3.8
+      nanoid: 3.3.11
       picocolors: 1.1.1
       source-map-js: 1.2.1
 
@@ -20256,7 +20319,7 @@ packages:
       debug: 4.4.0(supports-color@5.5.0)
       jsdom: 22.1.0
       local-pkg: 0.4.3
-      magic-string: 0.30.15
+      magic-string: 0.30.17
       pathe: 1.1.2
       picocolors: 1.1.1
       std-env: 3.8.0

+ 11 - 5
packages/materials/form-materials/bin/index.ts

@@ -72,11 +72,17 @@ program
     const { allMaterials, allPackages } = bfsMaterials(material!, materials);
 
     // 4. Install the dependencies
-    let flowgramPackage = `@flowgram.ai/editor`;
-    if (projectInfo.flowgramVersion !== 'workspace:*') {
-      flowgramPackage = `@flowgram.ai/editor@${projectInfo.flowgramVersion}`;
-    }
-    const packagesToInstall: string[] = [flowgramPackage, ...allPackages];
+    allPackages.push(`@flowgram.ai/editor`);
+    const packagesToInstall: string[] = allPackages.map((_pkg) => {
+      if (
+        _pkg.startsWith(`@flowgram.ai/`) &&
+        projectInfo.flowgramVersion !== 'workspace:*' &&
+        !_pkg.endsWith(`@${projectInfo.flowgramVersion}`)
+      ) {
+        return `${_pkg}@${projectInfo.flowgramVersion}`;
+      }
+      return _pkg;
+    });
 
     console.log(chalk.bold('These npm dependencies will be added to your project'));
     console.log(packagesToInstall);

+ 1 - 1
packages/materials/form-materials/bin/materials.ts

@@ -22,7 +22,7 @@ export interface Material {
   [key: string]: any; // For other properties from config.json
 }
 
-const _types: string[] = ['components', 'effects', 'utils', 'typings', 'form-plugins', 'hooks'];
+const _types: string[] = ['components', 'effects', 'shared', 'typings', 'form-plugins', 'hooks'];
 
 export function listAllMaterials(): Material[] {
   const _materials: Material[] = [];

+ 1 - 0
packages/materials/form-materials/package.json

@@ -36,6 +36,7 @@
     "@douyinfe/semi-illustrations": "^2.80.0",
     "@douyinfe/semi-ui": "^2.80.0",
     "@flowgram.ai/editor": "workspace:*",
+    "@flowgram.ai/json-schema": "workspace:*",
     "lodash": "^4.17.21",
     "nanoid": "^4.0.2",
     "commander": "^11.0.0",

+ 6 - 2
packages/materials/form-materials/src/components/batch-variable-selector/config.json

@@ -1,5 +1,9 @@
 {
   "name": "batch-variable-selector",
-  "depMaterials": ["variable-selector"],
-  "depPackages": []
+  "depMaterials": [
+    "variable-selector"
+  ],
+  "depPackages": [
+    "@flowgram.ai/json-schema"
+  ]
 }

+ 1 - 1
packages/materials/form-materials/src/components/batch-variable-selector/index.tsx

@@ -5,10 +5,10 @@
 
 import React from 'react';
 
+import { IJsonSchema } from '@flowgram.ai/json-schema';
 import { PrivateScopeProvider } from '@flowgram.ai/editor';
 
 import { VariableSelector, VariableSelectorProps } from '../variable-selector';
-import { IJsonSchema } from '../../typings';
 
 const batchVariableSchema: IJsonSchema = {
   type: 'array',

+ 7 - 0
packages/materials/form-materials/src/components/code-editor-mini/config.json

@@ -0,0 +1,7 @@
+{
+  "name": "code-editor-mini",
+  "depMaterials": [
+    "code-editor"
+  ],
+  "depPackages": []
+}

+ 31 - 0
packages/materials/form-materials/src/components/code-editor-mini/index.tsx

@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import React from 'react';
+
+import styled from 'styled-components';
+
+import { CodeEditor, CodeEditorPropsType } from '../code-editor';
+
+const UIMini = styled.div`
+  .ͼ1 .cm-content {
+    padding: 0;
+  }
+`;
+
+export function CodeEditorMini(props: CodeEditorPropsType) {
+  return (
+    <UIMini>
+      <CodeEditor
+        {...props}
+        options={{
+          lineNumbersGutter: false,
+          foldGutter: false,
+          ...(props.options || {}),
+        }}
+      />
+    </UIMini>
+  );
+}

+ 1 - 1
packages/materials/form-materials/src/components/code-editor/theme/light.ts

@@ -29,7 +29,7 @@ export const lightTheme: Extension = createTheme({
     gutterForeground: '#666',
     gutterBorderColor: 'transparent',
     gutterBorderWidth: 0,
-    lineHighlight: '#f0f0f0',
+    lineHighlight: '#e1e1e180',
     bracketColors: ['#FFD700', '#DD99FF', '#78B0FF'],
     tooltip: {
       backgroundColor: '#f0f0f0',

+ 10 - 2
packages/materials/form-materials/src/components/condition-row/config.json

@@ -1,5 +1,13 @@
 {
   "name": "condition-row",
-  "depMaterials": ["variable-selector", "dynamic-value-input", "flow-value", "utils/json-schema", "typings/json-schema"],
-  "depPackages": ["@douyinfe/semi-ui", "styled-components"]
+  "depMaterials": [
+    "variable-selector",
+    "dynamic-value-input",
+    "flow-value"
+  ],
+  "depPackages": [
+    "@douyinfe/semi-ui",
+    "styled-components",
+    "@flowgram.ai/json-schema"
+  ]
 }

+ 2 - 2
packages/materials/form-materials/src/components/condition-row/hooks/useRule.ts

@@ -5,11 +5,11 @@
 
 import { useMemo } from 'react';
 
+import { JsonSchemaUtils, JsonSchemaBasicType } from '@flowgram.ai/json-schema';
 import { useScopeAvailable } from '@flowgram.ai/editor';
 
 import { rules } from '../constants';
-import { JsonSchemaUtils } from '../../../utils';
-import { IFlowRefValue, JsonSchemaBasicType } from '../../../typings';
+import { IFlowRefValue } from '../../../typings';
 
 export function useRule(left?: IFlowRefValue) {
   const available = useScopeAvailable();

+ 1 - 1
packages/materials/form-materials/src/components/condition-row/index.tsx

@@ -5,6 +5,7 @@
 
 import React, { useMemo } from 'react';
 
+import { JsonSchemaBasicType } from '@flowgram.ai/json-schema';
 import { Input } from '@douyinfe/semi-ui';
 
 import { ConditionRowValueType, Op } from './types';
@@ -13,7 +14,6 @@ import { useRule } from './hooks/useRule';
 import { useOp } from './hooks/useOp';
 import { VariableSelector } from '../variable-selector';
 import { DynamicValueInput } from '../dynamic-value-input';
-import { JsonSchemaBasicType } from '../../typings';
 
 interface PropTypes {
   value?: ConditionRowValueType;

+ 3 - 1
packages/materials/form-materials/src/components/condition-row/types.ts

@@ -3,7 +3,9 @@
  * SPDX-License-Identifier: MIT
  */
 
-import { IFlowConstantRefValue, IFlowRefValue, JsonSchemaBasicType } from '../../typings';
+import { JsonSchemaBasicType } from '@flowgram.ai/json-schema';
+
+import { IFlowConstantRefValue, IFlowRefValue } from '../../typings';
 
 export enum Op {
   EQ = 'eq',

+ 6 - 3
packages/materials/form-materials/src/components/constant-input/config.json

@@ -1,6 +1,9 @@
-
 {
   "name": "constant-input",
-  "depMaterials": ["typings/json-schema"],
-  "depPackages": ["@douyinfe/semi-ui"]
+  "depMaterials": [
+    "shared/json-schema-preset"
+  ],
+  "depPackages": [
+    "@douyinfe/semi-ui"
+  ]
 }

+ 10 - 71
packages/materials/form-materials/src/components/constant-input/index.tsx

@@ -6,83 +6,22 @@
 /* eslint-disable react/prop-types */
 import React, { useMemo } from 'react';
 
-import { Input, InputNumber, Select } from '@douyinfe/semi-ui';
+import { Input } from '@douyinfe/semi-ui';
 
-import { PropsType, Strategy } from './types';
-
-const defaultStrategies: Strategy[] = [
-  {
-    hit: (schema) => schema?.type === 'string',
-    Renderer: (props) => (
-      <Input placeholder="Please Input String" size="small" disabled={props.readonly} {...props} />
-    ),
-  },
-  {
-    hit: (schema) => schema?.type === 'number',
-    Renderer: (props) => (
-      <InputNumber
-        placeholder="Please Input Number"
-        size="small"
-        disabled={props.readonly}
-        hideButtons
-        {...props}
-      />
-    ),
-  },
-  {
-    hit: (schema) => schema?.type === 'integer',
-    Renderer: (props) => (
-      <InputNumber
-        placeholder="Please Input Integer"
-        size="small"
-        disabled={props.readonly}
-        hideButtons
-        precision={0}
-        {...props}
-      />
-    ),
-  },
-  {
-    hit: (schema) => schema?.type === 'boolean',
-    Renderer: (props) => {
-      const { value, onChange, ...rest } = props;
-      return (
-        <Select
-          placeholder="Please Select Boolean"
-          size="small"
-          disabled={props.readonly}
-          optionList={[
-            { label: 'True', value: 1 },
-            { label: 'False', value: 0 },
-          ]}
-          value={value ? 1 : 0}
-          onChange={(value) => onChange?.(!!value)}
-          {...rest}
-        />
-      );
-    },
-  },
-];
+import { useTypeManager } from '../../shared';
+import { PropsType } from './types';
 
 export function ConstantInput(props: PropsType) {
-  const {
-    value,
-    onChange,
-    schema,
-    strategies: extraStrategies,
-    fallbackRenderer,
-    readonly,
-    ...rest
-  } = props;
+  const { value, onChange, schema, strategies, fallbackRenderer, readonly, ...rest } = props;
 
-  const strategies = useMemo(
-    // user's extraStrategies first
-    () => [...(extraStrategies || []), ...defaultStrategies],
-    [extraStrategies]
-  );
+  const typeManager = useTypeManager();
 
   const Renderer = useMemo(() => {
-    const strategy = strategies.find((_strategy) => _strategy.hit(schema));
+    const strategy = (strategies || []).find((_strategy) => _strategy.hit(schema));
+
+    if (!strategy) {
+      return typeManager.getTypeBySchema(schema)?.ConstantRenderer;
+    }
 
     return strategy?.Renderer;
   }, [strategies, schema]);

+ 6 - 10
packages/materials/form-materials/src/components/constant-input/types.ts

@@ -3,22 +3,18 @@
  * SPDX-License-Identifier: MIT
  */
 
-import { IJsonSchema } from '../../typings';
+import { IJsonSchema } from '@flowgram.ai/json-schema';
+
+import { ConstantRendererProps } from '../../shared';
 
 export interface Strategy<Value = any> {
   hit: (schema: IJsonSchema) => boolean;
-  Renderer: React.FC<RendererProps<Value>>;
-}
-
-export interface RendererProps<Value = any> {
-  value?: Value;
-  onChange?: (value: Value) => void;
-  readonly?: boolean;
+  Renderer: React.FC<ConstantRendererProps<Value>>;
 }
 
-export interface PropsType extends RendererProps {
+export interface PropsType extends ConstantRendererProps {
   schema: IJsonSchema;
   strategies?: Strategy[];
-  fallbackRenderer?: React.FC<RendererProps>;
+  fallbackRenderer?: React.FC<ConstantRendererProps>;
   [key: string]: any;
 }

+ 8 - 0
packages/materials/form-materials/src/components/display-flow-value/config.json

@@ -0,0 +1,8 @@
+{
+  "name": "display-flow-value",
+  "depMaterials": [
+    "components/display-schema-tag",
+    "typings/flow-value"
+  ],
+  "depPackages": []
+}

+ 59 - 0
packages/materials/form-materials/src/components/display-flow-value/index.tsx

@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import React, { useMemo } from 'react';
+
+import { JsonSchemaTypeManager, JsonSchemaUtils } from '@flowgram.ai/json-schema';
+import { useScopeAvailable } from '@flowgram.ai/editor';
+
+import { DisplaySchemaTag } from '../display-schema-tag';
+import { IFlowValue } from '../../typings';
+
+interface PropsType {
+  value?: IFlowValue;
+  title?: JSX.Element | string;
+  showIconInTree?: boolean;
+  typeManager?: JsonSchemaTypeManager;
+}
+
+export function DisplayFlowValue({ value, title, showIconInTree }: PropsType) {
+  const available = useScopeAvailable();
+
+  const variable = value?.type === 'ref' ? available.getByKeyPath(value?.content) : undefined;
+
+  const schema = useMemo(() => {
+    if (value?.type === 'ref') {
+      return JsonSchemaUtils.astToSchema(variable?.type);
+    }
+    if (value?.type === 'template') {
+      return { type: 'string' };
+    }
+    if (value?.type === 'constant') {
+      if (value?.schema) {
+        return value?.schema;
+      }
+      if (typeof value?.content === 'string') {
+        return { type: 'string' };
+      }
+      if (typeof value?.content === 'number') {
+        return { type: 'number' };
+      }
+      if (typeof value?.content === 'boolean') {
+        return { type: 'boolean' };
+      }
+    }
+
+    return { type: 'unknown' };
+  }, [value, variable?.hash]);
+
+  return (
+    <DisplaySchemaTag
+      title={title}
+      value={schema}
+      showIconInTree={showIconInTree}
+      warning={value?.type === 'ref' && !variable}
+    />
+  );
+}

+ 9 - 0
packages/materials/form-materials/src/components/display-inputs-values/config.json

@@ -0,0 +1,9 @@
+{
+  "name": "display-outputs",
+  "depMaterials": [
+    "components/display-schema-tag"
+  ],
+  "depPackages": [
+    "@douyinfe/semi-ui"
+  ]
+}

+ 27 - 0
packages/materials/form-materials/src/components/display-inputs-values/index.tsx

@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import React from 'react';
+
+import { DisplayFlowValue } from '../display-flow-value';
+import { IFlowValue } from '../../typings';
+import { DisplayInputsWrapper } from './styles';
+
+interface PropsType {
+  value?: Record<string, IFlowValue | undefined>;
+  showIconInTree?: boolean;
+}
+
+export function DisplayInputsValues({ value, showIconInTree }: PropsType) {
+  const childEntries = Object.entries(value || {});
+
+  return (
+    <DisplayInputsWrapper>
+      {childEntries.map(([key, value]) => (
+        <DisplayFlowValue key={key} title={key} value={value} showIconInTree={showIconInTree} />
+      ))}
+    </DisplayInputsWrapper>
+  );
+}

+ 12 - 0
packages/materials/form-materials/src/components/display-inputs-values/styles.ts

@@ -0,0 +1,12 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import styled from 'styled-components';
+
+export const DisplayInputsWrapper = styled.div`
+  display: flex;
+  gap: 5px;
+  flex-wrap: wrap;
+`;

+ 10 - 0
packages/materials/form-materials/src/components/display-outputs/config.json

@@ -0,0 +1,10 @@
+{
+  "name": "display-outputs",
+  "depMaterials": [
+    "components/display-flow-value"
+  ],
+  "depPackages": [
+    "@douyinfe/semi-ui",
+    "styled-components"
+  ]
+}

+ 58 - 0
packages/materials/form-materials/src/components/display-outputs/index.tsx

@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import React, { useEffect } from 'react';
+
+import { IJsonSchema, JsonSchemaTypeManager, JsonSchemaUtils } from '@flowgram.ai/json-schema';
+import { useCurrentScope, useRefresh } from '@flowgram.ai/editor';
+
+import { DisplaySchemaTag } from '../display-schema-tag';
+import { DisplayOutputsWrapper } from './styles';
+
+interface PropsType {
+  value?: IJsonSchema;
+  showIconInTree?: boolean;
+  displayFromScope?: boolean;
+  typeManager?: JsonSchemaTypeManager;
+}
+
+export function DisplayOutputs({ value, showIconInTree, displayFromScope }: PropsType) {
+  const scope = useCurrentScope();
+  const refresh = useRefresh();
+
+  useEffect(() => {
+    if (!displayFromScope) {
+      return () => null;
+    }
+
+    const disposable = scope.output.onListOrAnyVarChange(() => {
+      refresh();
+    });
+
+    return () => {
+      disposable.dispose();
+    };
+  }, [displayFromScope]);
+
+  const properties: IJsonSchema['properties'] = displayFromScope
+    ? scope.output.variables?.reduce((acm, curr) => {
+        acm = {
+          ...acm,
+          ...(JsonSchemaUtils.astToSchema(curr.type)?.properties || {}),
+        };
+        return acm;
+      }, {})
+    : value?.properties || {};
+
+  const childEntries = Object.entries(properties || {});
+
+  return (
+    <DisplayOutputsWrapper>
+      {childEntries.map(([key, schema]) => (
+        <DisplaySchemaTag key={key} title={key} value={schema} showIconInTree={showIconInTree} />
+      ))}
+    </DisplayOutputsWrapper>
+  );
+}

+ 12 - 0
packages/materials/form-materials/src/components/display-outputs/styles.ts

@@ -0,0 +1,12 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import styled from 'styled-components';
+
+export const DisplayOutputsWrapper = styled.div`
+  display: flex;
+  gap: 5px;
+  flex-wrap: wrap;
+`;

+ 10 - 0
packages/materials/form-materials/src/components/display-schema-tag/config.json

@@ -0,0 +1,10 @@
+{
+  "name": "display-schema-tag",
+  "depMaterials": [
+    "components/display-schema-tree"
+  ],
+  "depPackages": [
+    "@douyinfe/semi-ui",
+    "styled-components"
+  ]
+}

+ 44 - 0
packages/materials/form-materials/src/components/display-schema-tag/index.tsx

@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import React from 'react';
+
+import { IJsonSchema } from '@flowgram.ai/json-schema';
+import { Popover } from '@douyinfe/semi-ui';
+
+import { DisplaySchemaTree } from '../display-schema-tree';
+import { useTypeManager } from '../../shared';
+import { PopoverContent, StyledTag, TitleSpan } from './styles';
+
+interface PropsType {
+  title?: JSX.Element | string;
+  value?: IJsonSchema;
+  showIconInTree?: boolean;
+  warning?: boolean;
+}
+
+export function DisplaySchemaTag({ value = {}, showIconInTree, title, warning }: PropsType) {
+  const typeManager = useTypeManager();
+  const icon =
+    typeManager?.getDisplayIcon(value) || typeManager.getDisplayIcon({ type: 'unknown' });
+
+  return (
+    <Popover
+      content={
+        <PopoverContent>
+          <DisplaySchemaTree value={value} typeManager={typeManager} showIcon={showIconInTree} />
+        </PopoverContent>
+      }
+    >
+      <StyledTag color={warning ? 'amber' : 'white'}>
+        {icon &&
+          React.cloneElement(icon, {
+            className: 'tag-icon',
+          })}
+        {title && <TitleSpan>{title}</TitleSpan>}
+      </StyledTag>
+    </Popover>
+  );
+}

+ 28 - 0
packages/materials/form-materials/src/components/display-schema-tag/styles.ts

@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import styled from 'styled-components';
+import { Tag } from '@douyinfe/semi-ui';
+
+export const PopoverContent = styled.div`
+  padding: 10px;
+`;
+
+export const StyledTag = styled(Tag)`
+  padding: 4px;
+
+  .tag-icon {
+    width: 12px;
+    height: 12px;
+  }
+`;
+
+export const TitleSpan = styled.span`
+  display: inline-block;
+  margin-left: 4px;
+  margin-top: -1px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+`;

+ 11 - 0
packages/materials/form-materials/src/components/display-schema-tree/config.json

@@ -0,0 +1,11 @@
+{
+  "name": "display-schema-tree",
+  "depMaterials": [
+    "shared/json-schema-preset"
+  ],
+  "depPackages": [
+    "@douyinfe/semi-ui",
+    "styled-components",
+    "@flowgram.ai/json-schema"
+  ]
+}

+ 74 - 0
packages/materials/form-materials/src/components/display-schema-tree/index.tsx

@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import React from 'react';
+
+import { IJsonSchema, JsonSchemaTypeManager } from '@flowgram.ai/json-schema';
+
+import { useTypeManager } from '../../shared';
+import { HorizontalLine, TreeItem, TreeLevel, TreeRow, TreeTitle } from './styles';
+
+interface PropsType {
+  value?: IJsonSchema;
+  parentKey?: string;
+  depth?: number;
+  drilldown?: boolean;
+  showIcon?: boolean;
+  typeManager?: JsonSchemaTypeManager;
+}
+
+export function DisplaySchemaTree(props: Omit<PropsType, 'parentKey' | 'depth'>) {
+  return <SchemaTree {...props} />;
+}
+
+function SchemaTree(props: PropsType) {
+  const {
+    value: schema = {},
+    drilldown = true,
+    depth = 0,
+    showIcon = true,
+    parentKey = '',
+  } = props || {};
+
+  const typeManager = useTypeManager();
+
+  const config = typeManager.getTypeBySchema(schema);
+  const title = typeManager.getComplexText(schema);
+  const icon = typeManager?.getDisplayIcon(schema);
+  let properties: IJsonSchema['properties'] =
+    drilldown && config ? config.getTypeSchemaProperties(schema) : {};
+  const childEntries = Object.entries(properties || {});
+
+  return (
+    <TreeItem depth={depth} key={parentKey || 'root'}>
+      <TreeRow>
+        {depth !== 0 && <HorizontalLine />}
+        {showIcon &&
+          icon &&
+          React.cloneElement(icon, {
+            className: 'tree-icon',
+          })}
+        <TreeTitle>
+          {parentKey ? (
+            <>
+              {`${parentKey} (`}
+              {title}
+              {')'}
+            </>
+          ) : (
+            title
+          )}
+        </TreeTitle>
+      </TreeRow>
+      {childEntries?.length ? (
+        <TreeLevel>
+          {childEntries.map(([key, value]) => (
+            <SchemaTree key={key} {...props} parentKey={key} value={value} depth={depth + 1} />
+          ))}
+        </TreeLevel>
+      ) : null}
+    </TreeItem>
+  );
+}

+ 90 - 0
packages/materials/form-materials/src/components/display-schema-tree/styles.tsx

@@ -0,0 +1,90 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import styled, { css } from 'styled-components';
+
+export const TreeRow = styled.div`
+  display: flex;
+  align-items: center;
+
+  .tree-icon {
+    margin-right: 8px;
+    width: 14px;
+    height: 14px;
+  }
+
+  height: 27px;
+  white-space: nowrap;
+`;
+
+export const HorizontalLine = styled.div`
+  position: relative;
+
+  &::before,
+  &::after {
+    content: '';
+    position: absolute;
+    background-color: var(--semi-color-text-3);
+  }
+
+  &::after {
+    top: 0px;
+    right: 6px;
+    width: 15px;
+    height: 1px;
+  }
+`;
+
+export const TreeTitle = styled.div`
+  // overflow: hidden;
+  // text-overflow: ellipsis;
+`;
+
+export const TreeLevel = styled.div`
+  padding-left: 30px;
+  position: relative;
+
+  /* &::before {
+    content: '';
+    position: absolute;
+    background-color: var(--semi-color-text-3);
+    top: 0px;
+    bottom: 0px;
+    left: -22px;
+    width: 1px;
+  } */
+`;
+
+export const TreeItem = styled.div<{ depth: number }>`
+  position: relative;
+
+  &::before {
+    content: '';
+    position: absolute;
+    background-color: var(--semi-color-text-3);
+  }
+
+  &:not(:last-child)::before {
+    width: 1px;
+    top: 0;
+    bottom: 0;
+    left: -22px;
+  }
+
+  &:last-child::before {
+    width: 1px;
+    top: 0;
+    height: 14px;
+    left: -22px;
+  }
+
+  ${(props) =>
+    props.depth === 0 &&
+    css`
+      &::before {
+        width: 0px !important;
+      }
+    `}
+`;

+ 11 - 2
packages/materials/form-materials/src/components/dynamic-value-input/config.json

@@ -1,5 +1,14 @@
 {
   "name": "dynamic-value-input",
-  "depMaterials": ["flow-value", "constant-input", "variable-selector"],
-  "depPackages": ["@douyinfe/semi-ui", "@douyinfe/semi-icons", "styled-components"]
+  "depMaterials": [
+    "flow-value",
+    "constant-input",
+    "variable-selector"
+  ],
+  "depPackages": [
+    "@douyinfe/semi-ui",
+    "@douyinfe/semi-icons",
+    "styled-components",
+    "@flowgram.ai/json-schema"
+  ]
 }

+ 53 - 0
packages/materials/form-materials/src/components/dynamic-value-input/hooks.ts

@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import { useMemo, useState } from 'react';
+
+import { IJsonSchema } from '@flowgram.ai/json-schema';
+import { useScopeAvailable } from '@flowgram.ai/editor';
+
+import { IFlowConstantRefValue } from '../../typings/flow-value';
+
+export function useRefVariable(value?: IFlowConstantRefValue) {
+  const available = useScopeAvailable();
+  const refVariable = useMemo(() => {
+    if (value?.type === 'ref') {
+      return available.getByKeyPath(value.content);
+    }
+  }, [value, available]);
+
+  return refVariable;
+}
+
+export function useSelectSchema(
+  schemaFromProps?: IJsonSchema,
+  constantProps?: {
+    schema?: IJsonSchema;
+  },
+  value?: IFlowConstantRefValue
+) {
+  let defaultSelectSchema = schemaFromProps || constantProps?.schema || { type: 'string' };
+  if (value?.type === 'constant') {
+    defaultSelectSchema = value?.schema || defaultSelectSchema;
+  }
+
+  const [selectSchema, setSelectSchema] = useState(defaultSelectSchema);
+
+  return [selectSchema, setSelectSchema] as const;
+}
+
+export function useIncludeSchema(schemaFromProps?: IJsonSchema) {
+  const includeSchema = useMemo(() => {
+    if (!schemaFromProps) {
+      return;
+    }
+    if (schemaFromProps?.type === 'number') {
+      return [schemaFromProps, { type: 'integer' }];
+    }
+    return { ...schemaFromProps, extra: { ...schemaFromProps?.extra, weak: true } };
+  }, [schemaFromProps]);
+
+  return includeSchema;
+}

+ 30 - 28
packages/materials/form-materials/src/components/dynamic-value-input/index.tsx

@@ -3,20 +3,19 @@
  * SPDX-License-Identifier: MIT
  */
 
-import React, { useMemo, useState } from 'react';
+import React from 'react';
 
-import { useScopeAvailable } from '@flowgram.ai/editor';
+import { JsonSchemaUtils, IJsonSchema } from '@flowgram.ai/json-schema';
 import { IconButton } from '@douyinfe/semi-ui';
 import { IconSetting } from '@douyinfe/semi-icons';
 
+import { VariableSelector } from '../variable-selector';
+import { TypeSelector } from '../type-selector';
 import { Strategy } from '../constant-input/types';
 import { ConstantInput } from '../constant-input';
-import { JsonSchemaUtils } from '../../utils';
 import { IFlowConstantRefValue } from '../../typings/flow-value';
 import { UIContainer, UIMain, UITrigger, UIType } from './styles';
-import { VariableSelector } from '../variable-selector';
-import { TypeSelector } from '../type-selector';
-import { IJsonSchema } from '../../typings';
+import { useIncludeSchema, useRefVariable, useSelectSchema } from './hooks';
 
 interface PropsType {
   value?: IFlowConstantRefValue;
@@ -40,16 +39,9 @@ export function DynamicValueInput({
   schema: schemaFromProps,
   constantProps,
 }: PropsType) {
-  const available = useScopeAvailable();
-  const refVariable = useMemo(() => {
-    if (value?.type === 'ref') {
-      return available.getByKeyPath(value.content);
-    }
-  }, [value, available]);
-
-  const [selectSchema, setSelectSchema] = useState(
-    schemaFromProps || constantProps?.schema || { type: 'string' }
-  );
+  const refVariable = useRefVariable(value);
+  const [selectSchema, setSelectSchema] = useSelectSchema(schemaFromProps, constantProps, value);
+  const includeSchema = useIncludeSchema(schemaFromProps);
 
   const renderTypeSelector = () => {
     if (schemaFromProps) {
@@ -65,23 +57,33 @@ export function DynamicValueInput({
     return (
       <TypeSelector
         value={selectSchema}
-        onChange={(_v) => setSelectSchema(_v || { type: 'string' })}
+        onChange={(_v) => {
+          setSelectSchema(_v || { type: 'string' });
+          let content;
+
+          if (_v?.type === 'object') {
+            content = '{}';
+          }
+
+          if (_v?.type === 'array') {
+            content = '[]';
+          }
+
+          if (_v?.type === 'boolean') {
+            content = false;
+          }
+
+          onChange({
+            type: 'constant',
+            content,
+            schema: _v || { type: 'string' },
+          });
+        }}
         readonly={readonly}
       />
     );
   };
 
-  // When is number type, include integer as well
-  const includeSchema = useMemo(() => {
-    if (!schemaFromProps) {
-      return;
-    }
-    if (schemaFromProps?.type === 'number') {
-      return [schemaFromProps, { type: 'integer' }];
-    }
-    return { ...schemaFromProps, extra: { ...schemaFromProps?.extra, weak: true } };
-  }, [schemaFromProps]);
-
   const renderMain = () => {
     if (value?.type === 'ref') {
       // Display Variable Or Delete

+ 6 - 0
packages/materials/form-materials/src/components/index.ts

@@ -15,5 +15,11 @@ export * from './prompt-editor';
 export * from './prompt-editor-with-variables';
 export * from './prompt-editor-with-inputs';
 export * from './code-editor';
+export * from './code-editor-mini';
 export * from './json-editor-with-variables';
 export * from './inputs-values';
+export * from './display-schema-tree';
+export * from './display-outputs';
+export * from './display-schema-tag';
+export * from './display-flow-value';
+export * from './display-inputs-values';

+ 2 - 1
packages/materials/form-materials/src/components/inputs-values/config.json

@@ -7,6 +7,7 @@
   "depPackages": [
     "@douyinfe/semi-ui",
     "@douyinfe/semi-icons",
-    "styled-components"
+    "styled-components",
+    "@flowgram.ai/json-schema"
   ]
 }

+ 3 - 1
packages/materials/form-materials/src/components/inputs-values/types.ts

@@ -3,8 +3,10 @@
  * SPDX-License-Identifier: MIT
  */
 
+import { IJsonSchema } from '@flowgram.ai/json-schema';
+
 import { Strategy } from '../constant-input/types';
-import { IFlowValue, IJsonSchema } from '../../typings';
+import { IFlowValue } from '../../typings';
 
 export interface PropsType {
   value?: Record<string, IFlowValue | undefined>;

+ 3 - 3
packages/materials/form-materials/src/components/json-schema-editor/config.json

@@ -2,12 +2,12 @@
   "name": "json-schema-editor",
   "depMaterials": [
     "type-selector",
-    "typings/json-schema",
-    "constant-inputs"
+    "constant-inputs",
   ],
   "depPackages": [
     "@douyinfe/semi-ui",
     "@douyinfe/semi-icons",
-    "styled-components"
+    "styled-components",
+    "@flowgram.ai/json-schema"
   ]
 }

+ 1 - 1
packages/materials/form-materials/src/components/json-schema-editor/default-value.tsx

@@ -5,6 +5,7 @@
 
 import React, { useRef, useState, useCallback } from 'react';
 
+import { IJsonSchema } from '@flowgram.ai/json-schema';
 import { IconButton, JsonViewer, Tooltip } from '@douyinfe/semi-ui';
 import { IconBrackets } from '@douyinfe/semi-icons';
 
@@ -17,7 +18,6 @@ import {
   JSONViewerWrapper,
 } from './styles';
 import { ConstantInput } from '../constant-input';
-import { IJsonSchema } from '../../typings';
 
 /**
  * 根据不同的数据类型渲染对应的默认值输入组件。

+ 1 - 1
packages/materials/form-materials/src/components/json-schema-editor/hooks.tsx

@@ -6,8 +6,8 @@
 import { useEffect, useMemo, useRef, useState } from 'react';
 
 import { omit } from 'lodash';
+import { IJsonSchema } from '@flowgram.ai/json-schema';
 
-import { IJsonSchema } from '../../typings';
 import { PropertyValueType } from './types';
 
 let _id = 0;

+ 1 - 1
packages/materials/form-materials/src/components/json-schema-editor/index.tsx

@@ -5,6 +5,7 @@
 
 import React, { useMemo, useState } from 'react';
 
+import { IJsonSchema } from '@flowgram.ai/json-schema';
 import { Button, Checkbox, IconButton } from '@douyinfe/semi-ui';
 import {
   IconExpand,
@@ -16,7 +17,6 @@ import {
 } from '@douyinfe/semi-icons';
 
 import { TypeSelector } from '../type-selector';
-import { IJsonSchema } from '../../typings';
 import { ConfigType, PropertyValueType } from './types';
 import {
   IconAddChildren,

+ 1 - 1
packages/materials/form-materials/src/components/json-schema-editor/types.ts

@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: MIT
  */
 
-import { IJsonSchema } from '../../typings';
+import { IJsonSchema } from '@flowgram.ai/json-schema';
 
 export interface PropertyValueType extends IJsonSchema {
   name?: string;

+ 6 - 2
packages/materials/form-materials/src/components/type-selector/config.json

@@ -1,5 +1,9 @@
 {
   "name": "type-selector",
-  "depMaterials": ["typings/json-schema"],
-  "depPackages": ["@douyinfe/semi-ui", "@douyinfe/semi-icons"]
+  "depMaterials": [],
+  "depPackages": [
+    "@douyinfe/semi-ui",
+    "@douyinfe/semi-icons",
+    "@flowgram.ai/json-schema"
+  ]
 }

File diff suppressed because it is too large
+ 0 - 255
packages/materials/form-materials/src/components/type-selector/constants.tsx


+ 47 - 11
packages/materials/form-materials/src/components/type-selector/index.tsx

@@ -5,10 +5,10 @@
 
 import React, { useMemo } from 'react';
 
-import { Cascader, IconButton } from '@douyinfe/semi-ui';
+import { IJsonSchema } from '@flowgram.ai/json-schema';
+import { Cascader, Icon, IconButton } from '@douyinfe/semi-ui';
 
-import { IJsonSchema } from '../../typings';
-import { ArrayIcons, VariableTypeIcons, getSchemaIcon, options } from './constants';
+import { useTypeManager } from '../../shared';
 
 interface PropTypes {
   value?: Partial<IJsonSchema>;
@@ -21,6 +21,10 @@ interface PropTypes {
   style?: React.CSSProperties;
 }
 
+const labelStyle: React.CSSProperties = { display: 'flex', alignItems: 'center', gap: 5 };
+
+const firstUppercase = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);
+
 export const getTypeSelectValue = (value?: Partial<IJsonSchema>): string[] | undefined => {
   if (value?.type === 'array' && value?.items) {
     return [value.type, ...(getTypeSelectValue(value.items) || [])];
@@ -44,17 +48,51 @@ export function TypeSelector(props: PropTypes) {
 
   const selectValue = useMemo(() => getTypeSelectValue(value), [value]);
 
+  const typeManager = useTypeManager();
+
+  const icon = typeManager.getDisplayIcon(value || {});
+
+  const options = useMemo(
+    () =>
+      typeManager.getTypeRegistriesWithParentType().map((_type) => {
+        const isArray = _type.type === 'array';
+
+        return {
+          label: (
+            <div style={labelStyle}>
+              <Icon size="small" svg={_type.icon} />
+              {firstUppercase(_type.type)}
+            </div>
+          ),
+          value: _type.type,
+          children: isArray
+            ? typeManager.getTypeRegistriesWithParentType('array').map((_type) => ({
+                label: (
+                  <div style={labelStyle}>
+                    <Icon
+                      size="small"
+                      svg={typeManager.getDisplayIcon({
+                        type: 'array',
+                        items: { type: _type.type },
+                      })}
+                    />
+                    {firstUppercase(_type.type)}
+                  </div>
+                ),
+                value: _type.type,
+              }))
+            : [],
+        };
+      }),
+    []
+  );
+
   return (
     <Cascader
       disabled={readonly || disabled}
       size="small"
       triggerRender={() => (
-        <IconButton
-          size="small"
-          style={style}
-          disabled={readonly || disabled}
-          icon={getSchemaIcon(value)}
-        />
+        <IconButton size="small" style={style} disabled={readonly || disabled} icon={icon} />
       )}
       treeData={options}
       value={selectValue}
@@ -65,5 +103,3 @@ export function TypeSelector(props: PropTypes) {
     />
   );
 }
-
-export { VariableTypeIcons, ArrayIcons, getSchemaIcon };

+ 6 - 2
packages/materials/form-materials/src/components/variable-selector/config.json

@@ -1,5 +1,9 @@
 {
   "name": "variable-selector",
-  "depMaterials": ["type-selector", "utils/json-schema", "typings/json-schema"],
-  "depPackages": ["@douyinfe/semi-ui", "styled-components"]
+  "depMaterials": [],
+  "depPackages": [
+    "@douyinfe/semi-ui",
+    "styled-components",
+    "@flowgram.ai/json-schema"
+  ]
 }

+ 1 - 1
packages/materials/form-materials/src/components/variable-selector/index.tsx

@@ -5,12 +5,12 @@
 
 import React, { useMemo } from 'react';
 
+import { IJsonSchema } from '@flowgram.ai/json-schema';
 import { TriggerRenderProps } from '@douyinfe/semi-ui/lib/es/treeSelect';
 import { TreeNodeData } from '@douyinfe/semi-ui/lib/es/tree';
 import { Popover } from '@douyinfe/semi-ui';
 import { IconChevronDownStroked, IconIssueStroked } from '@douyinfe/semi-icons';
 
-import { IJsonSchema } from '../../typings/json-schema';
 import { useVariableTree } from './use-variable-tree';
 import { UIPopoverContent, UIRootTitle, UITag, UITreeSelect, UIVarName } from './styles';
 

+ 14 - 20
packages/materials/form-materials/src/components/variable-selector/use-variable-tree.tsx

@@ -5,15 +5,18 @@
 
 import React, { useCallback } from 'react';
 
+import { IJsonSchema, JsonSchemaUtils } from '@flowgram.ai/json-schema';
 import { ASTMatch, BaseVariableField, useAvailableVariables } from '@flowgram.ai/editor';
 import { TreeNodeData } from '@douyinfe/semi-ui/lib/es/tree';
 import { Icon } from '@douyinfe/semi-ui';
 
-import { ArrayIcons, VariableTypeIcons } from '../type-selector/constants';
-import { JsonSchemaUtils } from '../../utils/json-schema';
-import { IJsonSchema } from '../../typings/json-schema';
+import { useTypeManager } from '../../shared';
 
-type VariableField = BaseVariableField<{ icon?: string | JSX.Element; title?: string }>;
+type VariableField = BaseVariableField<{
+  icon?: string | JSX.Element;
+  title?: string;
+  disabled?: boolean;
+}>;
 
 export function useVariableTree(params: {
   includeSchema?: IJsonSchema | IJsonSchema[];
@@ -22,6 +25,7 @@ export function useVariableTree(params: {
 }): TreeNodeData[] {
   const { includeSchema, excludeSchema, customSkip } = params;
 
+  const typeManager = useTypeManager();
   const variables = useAvailableVariables();
 
   const getVariableTypeIcon = useCallback((variable: VariableField) => {
@@ -33,22 +37,9 @@ export function useVariableTree(params: {
       return variable.meta.icon;
     }
 
-    const _type = variable.type;
+    const schema = JsonSchemaUtils.astToSchema(variable.type, { drilldownObject: false });
 
-    if (ASTMatch.isArray(_type)) {
-      return (
-        <Icon
-          size="small"
-          svg={ArrayIcons[_type.items?.kind.toLowerCase()] || VariableTypeIcons.array}
-        />
-      );
-    }
-
-    if (ASTMatch.isCustomType(_type)) {
-      return <Icon size="small" svg={VariableTypeIcons[_type.typeName.toLowerCase()]} />;
-    }
-
-    return <Icon size="small" svg={VariableTypeIcons[variable.type?.kind.toLowerCase()]} />;
+    return <Icon size="small" svg={typeManager.getDisplayIcon(schema || {})} />;
   }, []);
 
   const renderVariable = (
@@ -80,7 +71,10 @@ export function useVariableTree(params: {
       : false;
     const isCustomSkip = customSkip ? customSkip(variable) : false;
 
-    const isSchemaMatch = isSchemaInclude && !isSchemaExclude && !isCustomSkip;
+    // disabled in meta when created
+    const isMetaDisabled = variable.meta?.disabled;
+
+    const isSchemaMatch = isSchemaInclude && !isSchemaExclude && !isCustomSkip && !isMetaDisabled;
 
     // If not match, and no children, return null
     if (!isSchemaMatch && !children?.length) {

+ 4 - 5
packages/materials/form-materials/src/effects/provide-json-schema-outputs/config.json

@@ -1,8 +1,7 @@
 {
   "name": "provide-json-schema-outputs",
-  "depMaterials": [
-    "typings/json-schema",
-    "utils/json-schema"
-  ],
-  "depPackages": []
+  "depMaterials": [],
+  "depPackages": [
+    "@flowgram.ai/json-schema"
+  ]
 }

+ 1 - 3
packages/materials/form-materials/src/effects/provide-json-schema-outputs/index.ts

@@ -3,6 +3,7 @@
  * SPDX-License-Identifier: MIT
  */
 
+import { JsonSchemaUtils, IJsonSchema } from '@flowgram.ai/json-schema';
 import {
   ASTFactory,
   EffectOptions,
@@ -11,9 +12,6 @@ import {
   getNodeForm,
 } from '@flowgram.ai/editor';
 
-import { JsonSchemaUtils } from '../../utils';
-import { IJsonSchema } from '../../typings';
-
 export const provideJsonSchemaOutputs: EffectOptions[] = createEffectFromVariableProvider({
   parse: (value: IJsonSchema, ctx) => [
     ASTFactory.createVariableDeclaration({

+ 1 - 0
packages/materials/form-materials/src/effects/sync-variable-title/index.ts

@@ -18,6 +18,7 @@ export const syncVariableTitle: EffectOptions[] = [
       context.node.getData(FlowNodeVariableData).allScopes.forEach((_scope) => {
         _scope.output.variables.forEach((_var) => {
           _var.updateMeta({
+            ...(_var.meta || {}),
             title: value || context.node.id,
             icon: context.node.getNodeRegistry<FlowNodeRegistry>().info?.icon,
           });

+ 3 - 1
packages/materials/form-materials/src/form-plugins/infer-inputs-plugin/config.json

@@ -3,5 +3,7 @@
   "depMaterials": [
     "flow-value"
   ],
-  "depPackages": []
+  "depPackages": [
+    "@flowgram.ai/json-schema"
+  ]
 }

+ 2 - 2
packages/materials/form-materials/src/form-plugins/infer-inputs-plugin/index.ts

@@ -4,6 +4,7 @@
  */
 
 import { get, set } from 'lodash';
+import { JsonSchemaUtils, IJsonSchema } from '@flowgram.ai/json-schema';
 import {
   defineFormPluginCreator,
   getNodePrivateScope,
@@ -11,8 +12,7 @@ import {
   Scope,
 } from '@flowgram.ai/editor';
 
-import { JsonSchemaUtils } from '../../utils';
-import { IFlowConstantValue, IFlowRefValue, IFlowTemplateValue, IJsonSchema } from '../../typings';
+import { IFlowConstantValue, IFlowRefValue, IFlowTemplateValue } from '../../typings';
 
 interface InputConfig {
   sourceKey: string;

+ 1 - 1
packages/materials/form-materials/src/index.ts

@@ -5,6 +5,6 @@
 
 export * from './components';
 export * from './effects';
-export * from './utils';
+export * from './shared';
 export * from './typings';
 export * from './form-plugins';

+ 0 - 0
packages/materials/form-materials/src/utils/format-legacy-refs/config.json → packages/materials/form-materials/src/shared/format-legacy-refs/config.json


+ 0 - 0
packages/materials/form-materials/src/utils/format-legacy-refs/index.ts → packages/materials/form-materials/src/shared/format-legacy-refs/index.ts


+ 0 - 0
packages/materials/form-materials/src/utils/format-legacy-refs/readme.md → packages/materials/form-materials/src/shared/format-legacy-refs/readme.md


+ 1 - 1
packages/materials/form-materials/src/utils/index.ts → packages/materials/form-materials/src/shared/index.ts

@@ -4,4 +4,4 @@
  */
 
 export * from './format-legacy-refs';
-export * from './json-schema';
+export * from './json-schema-preset';

+ 9 - 0
packages/materials/form-materials/src/shared/json-schema-preset/config.json

@@ -0,0 +1,9 @@
+{
+  "name": "json-schema-preset",
+  "depMaterials": [
+    "components/code-editor-mini"
+  ],
+  "depPackages": [
+    "@flowgram.ai/json-schema"
+  ]
+}

+ 26 - 0
packages/materials/form-materials/src/shared/json-schema-preset/create-type-preset-plugin.tsx

@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import {
+  BaseTypeManager,
+  jsonSchemaContainerModule,
+  JsonSchemaTypeManager,
+} from '@flowgram.ai/json-schema';
+import { definePluginCreator } from '@flowgram.ai/editor';
+
+import { jsonSchemaTypePreset } from './type-definition';
+import { JsonSchemaTypeRegistry } from './manager';
+
+export const createTypePresetPlugin = definePluginCreator<{
+  types: JsonSchemaTypeRegistry[];
+}>({
+  onInit(ctx, opts) {
+    const typeManager = ctx.get(BaseTypeManager) as JsonSchemaTypeManager;
+    jsonSchemaTypePreset.forEach((_type) => typeManager.register(_type));
+
+    opts.types.forEach((_type) => typeManager.register(_type));
+  },
+  containerModules: [jsonSchemaContainerModule],
+});

+ 39 - 0
packages/materials/form-materials/src/shared/json-schema-preset/index.tsx

@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+import React from 'react';
+
+import {
+  type IJsonSchema,
+  JsonSchemaUtils,
+  useTypeManager as useOriginTypeManager,
+  TypePresetProvider as OriginTypePresetProvider,
+  JsonSchemaTypeManager,
+} from '@flowgram.ai/json-schema';
+
+import { jsonSchemaTypePreset } from './type-definition';
+import { type JsonSchemaTypeRegistry, type ConstantRendererProps } from './manager';
+import { createTypePresetPlugin } from './create-type-preset-plugin';
+
+const useTypeManager = () =>
+  useOriginTypeManager() as JsonSchemaTypeManager<IJsonSchema, JsonSchemaTypeRegistry>;
+
+const JsonSchemaTypePresetProvider = ({
+  types = [],
+  children,
+}: React.PropsWithChildren<{ types: JsonSchemaTypeRegistry[] }>) => (
+  <OriginTypePresetProvider types={[...jsonSchemaTypePreset, ...types]}>
+    {children}
+  </OriginTypePresetProvider>
+);
+
+export {
+  createTypePresetPlugin,
+  useTypeManager,
+  JsonSchemaTypePresetProvider,
+  IJsonSchema,
+  JsonSchemaUtils,
+  JsonSchemaTypeRegistry,
+  ConstantRendererProps,
+};

+ 18 - 0
packages/materials/form-materials/src/shared/json-schema-preset/manager.ts

@@ -0,0 +1,18 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import { JsonSchemaTypeRegistry as OriginJsonSchemaTypeRegistry } from '@flowgram.ai/json-schema';
+
+export interface ConstantRendererProps<Value = any> {
+  value?: Value;
+  onChange?: (value: Value) => void;
+  readonly?: boolean;
+}
+export interface JsonSchemaTypeRegistry<Value = any> extends OriginJsonSchemaTypeRegistry {
+  /**
+   * Render Constant Input
+   */
+  ConstantRenderer: React.FC<ConstantRendererProps<Value>>;
+}

+ 23 - 0
packages/materials/form-materials/src/shared/json-schema-preset/type-definition/array.tsx

@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+/* eslint-disable react/prop-types */
+import React from 'react';
+
+import { type JsonSchemaTypeRegistry } from '../manager';
+import { CodeEditorMini } from '../../../components/code-editor-mini';
+
+export const arrayRegistry: Partial<JsonSchemaTypeRegistry> = {
+  type: 'array',
+  ConstantRenderer: (props) => (
+    <CodeEditorMini
+      value={props.value}
+      languageId="json"
+      onChange={(v) => props.onChange?.(v)}
+      placeholder="Please Input Array"
+      readonly={props.readonly}
+    />
+  ),
+};

+ 32 - 0
packages/materials/form-materials/src/shared/json-schema-preset/type-definition/boolean.tsx

@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+/* eslint-disable react/prop-types */
+import React from 'react';
+
+import { Select } from '@douyinfe/semi-ui';
+
+import { type JsonSchemaTypeRegistry } from '../manager';
+
+export const booleanRegistry: Partial<JsonSchemaTypeRegistry> = {
+  type: 'boolean',
+  ConstantRenderer: (props) => {
+    const { value, onChange, ...rest } = props;
+    return (
+      <Select
+        placeholder="Please Select Boolean"
+        size="small"
+        disabled={props.readonly}
+        optionList={[
+          { label: 'True', value: 1 },
+          { label: 'False', value: 0 },
+        ]}
+        value={value ? 1 : 0}
+        onChange={(value) => onChange?.(!!value)}
+        {...rest}
+      />
+    );
+  },
+};

+ 24 - 0
packages/materials/form-materials/src/shared/json-schema-preset/type-definition/index.tsx

@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import { jsonSchemaTypeManager } from '@flowgram.ai/json-schema';
+
+import { stringRegistry } from './string';
+import { objectRegistry } from './object';
+import { numberRegistry } from './number';
+import { integerRegistry } from './integer';
+import { booleanRegistry } from './boolean';
+import { arrayRegistry } from './array';
+
+export const jsonSchemaTypePreset = [
+  stringRegistry,
+  objectRegistry,
+  numberRegistry,
+  integerRegistry,
+  booleanRegistry,
+  arrayRegistry,
+];
+
+jsonSchemaTypePreset.forEach((_type) => jsonSchemaTypeManager.register(_type));

+ 24 - 0
packages/materials/form-materials/src/shared/json-schema-preset/type-definition/integer.tsx

@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+/* eslint-disable react/prop-types */
+import React from 'react';
+
+import { InputNumber } from '@douyinfe/semi-ui';
+
+import { type JsonSchemaTypeRegistry } from '../manager';
+
+export const integerRegistry: Partial<JsonSchemaTypeRegistry> = {
+  type: 'integer',
+  ConstantRenderer: (props) => (
+    <InputNumber
+      placeholder="Please Input Integer"
+      size="small"
+      disabled={props.readonly}
+      precision={0}
+      {...props}
+    />
+  ),
+};

+ 24 - 0
packages/materials/form-materials/src/shared/json-schema-preset/type-definition/number.tsx

@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+/* eslint-disable react/prop-types */
+import React from 'react';
+
+import { InputNumber } from '@douyinfe/semi-ui';
+
+import { type JsonSchemaTypeRegistry } from '../manager';
+
+export const numberRegistry: Partial<JsonSchemaTypeRegistry> = {
+  type: 'number',
+  ConstantRenderer: (props) => (
+    <InputNumber
+      placeholder="Please Input Number"
+      size="small"
+      disabled={props.readonly}
+      hideButtons
+      {...props}
+    />
+  ),
+};

+ 23 - 0
packages/materials/form-materials/src/shared/json-schema-preset/type-definition/object.tsx

@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+/* eslint-disable react/prop-types */
+import React from 'react';
+
+import { type JsonSchemaTypeRegistry } from '../manager';
+import { CodeEditorMini } from '../../../components/code-editor-mini';
+
+export const objectRegistry: Partial<JsonSchemaTypeRegistry> = {
+  type: 'object',
+  ConstantRenderer: (props) => (
+    <CodeEditorMini
+      value={props.value}
+      onChange={(v) => props.onChange?.(v)}
+      languageId="json"
+      placeholder="Please Input Object"
+      readonly={props.readonly}
+    />
+  ),
+};

+ 18 - 0
packages/materials/form-materials/src/shared/json-schema-preset/type-definition/string.tsx

@@ -0,0 +1,18 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+/* eslint-disable react/prop-types */
+import React from 'react';
+
+import { Input } from '@douyinfe/semi-ui';
+
+import { type JsonSchemaTypeRegistry } from '../manager';
+
+export const stringRegistry: Partial<JsonSchemaTypeRegistry> = {
+  type: 'string',
+  ConstantRenderer: (props) => (
+    <Input placeholder="Please Input String" size="small" disabled={props.readonly} {...props} />
+  ),
+};

+ 4 - 4
packages/materials/form-materials/src/typings/flow-value/config.json

@@ -1,7 +1,7 @@
 {
   "name": "flow-value",
-  "depMaterials": [
-    "typings/json-schema"
-  ],
-  "depPackages": []
+  "depMaterials": [],
+  "depPackages": [
+    "@flowgram.ai/json-schema"
+  ]
 }

+ 1 - 1
packages/materials/form-materials/src/typings/flow-value/index.ts

@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: MIT
  */
 
-import { IJsonSchema } from '../json-schema';
+import { IJsonSchema } from '@flowgram.ai/json-schema';
 
 export interface IFlowValueExtra {
   index?: number;

+ 0 - 1
packages/materials/form-materials/src/typings/index.ts

@@ -4,4 +4,3 @@
  */
 
 export * from './flow-value';
-export * from './json-schema';

Some files were not shown because too many files changed in this diff