2
0
Эх сурвалжийг харах

feat(materials): add JsonSchemaCreator component (#983)

Add a new JsonSchemaCreator component to form-materials that
automatically generates JSON Schema from JSON strings:

Component Features:
- Button to trigger JSON input modal
- JSON code editor with syntax validation
- Automatic schema generation from parsed JSON data
- Recursive schema generation for nested objects and arrays

Documentation:
- Add bilingual (EN/ZH) documentation with API reference
- Add Storybook story for interactive demo
- Add component demo in docs app
- Include sequence diagram showing interaction flow

Development Guide:
- Create Claude skill for material component development
- Document FlowGram component development standards
- Provide complete project structure and coding guidelines

Technical Implementation:
- Core utility: jsonToSchema with recursive generateSchema
- Modal component: JsonInputModal for JSON input
- Integration with Semi UI and JsonCodeEditor
- TypeScript support with IJsonSchema type

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Yiwei Mao 2 сар өмнө
parent
commit
e9c81654fc

+ 367 - 0
.claude/skills/material-component-dev/SKILL.md

@@ -0,0 +1,367 @@
+---
+skill_name: material-component-dev
+description: FlowGram 物料组件开发指南 - 用于在 form-materials 包中创建新的物料组件
+version: 1.0.0
+tags: [flowgram, material, component, development]
+---
+
+# FlowGram Material Component Development
+
+## 概述
+
+本 SKILL 用于指导在 FlowGram 项目的 `@flowgram.ai/form-materials` 包中创建新的物料组件。
+
+## 核心原则
+
+### 1. 组件位置
+- ✅ **在现有包中创建**:直接在 `packages/materials/form-materials/src/components/` 下创建组件目录
+- ❌ **不要单独拆包**:不创建新的 npm 包,保持简洁
+
+### 2. 代码质量
+- ✅ **使用 named export**:所有导出使用 named export 提高 tree shake 性能
+- ❌ **不写单元测试**:通过 Storybook 进行手动测试
+- ✅ **通过类型检查**:必须通过 `yarn ts-check`
+- ✅ **符合代码规范**:遵循项目 ESLint 规则
+
+### 3. 物料设计
+- ✅ **保持精简**:只保留必要的 props,不添加非核心功能配置项
+- ✅ **功能单一**:一个物料只做一件事
+- ✅ **使用内部依赖**:优先使用 FlowGram 内部的组件和类型
+
+### 4. 技术栈
+- **UI 组件库**:`@douyinfe/semi-ui`
+- **代码编辑器**:`JsonCodeEditor`, `CodeEditor` 等来自 `../code-editor`
+- **类型定义**:`IJsonSchema` 来自 `@flowgram.ai/json-schema`(不使用外部的 `json-schema` 包)
+- **React**:必须显式 `import React` 避免 UMD 全局引用错误
+
+## 开发流程
+
+### Step 1: 规划组件结构
+
+确定组件的:
+- **功能**:组件要解决什么问题
+- **Props 接口**:只保留核心必需的 props
+- **命名**:使用 PascalCase,清晰描述功能
+
+### Step 2: 创建目录结构
+
+```bash
+mkdir -p packages/materials/form-materials/src/components/{组件名}/utils
+```
+
+典型结构:
+```
+packages/materials/form-materials/src/components/{组件名}/
+├── index.tsx                 # 导出文件 (named export)
+├── {组件名}.tsx              # 主组件
+├── {辅助组件}.tsx            # 可选的辅助组件
+└── utils/                    # 可选的工具函数
+    └── *.ts
+```
+
+### Step 3: 实现组件
+
+#### 3.1 工具函数(如需要)
+
+```typescript
+// utils/helper.ts
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+export function helperFunction(input: string): Output {
+  // 实现逻辑
+}
+```
+
+#### 3.2 辅助组件(如需要)
+
+```typescript
+// modal.tsx
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import React, { useState } from 'react';
+import { Modal, Typography } from '@douyinfe/semi-ui';
+
+interface ModalProps {
+  visible: boolean;
+  onClose: () => void;
+  onConfirm: (data: SomeType) => void;
+}
+
+export function MyModal({ visible, onClose, onConfirm }: ModalProps) {
+  // 实现
+}
+```
+
+#### 3.3 主组件
+
+```typescript
+// my-component.tsx
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import React, { useState } from 'react';
+import { Button } from '@douyinfe/semi-ui';
+import type { IJsonSchema } from '@flowgram.ai/json-schema';
+
+export interface MyComponentProps {
+  /** 核心功能的回调 */
+  onSomething?: (data: SomeType) => void;
+}
+
+// 使用 named export,不使用 default export
+export function MyComponent({ onSomething }: MyComponentProps) {
+  const [visible, setVisible] = useState(false);
+
+  return (
+    <>
+      <Button onClick={() => setVisible(true)}>
+        操作文本
+      </Button>
+      {/* 其他组件 */}
+    </>
+  );
+}
+```
+
+**关键点**:
+- ✅ 显式 `import React`
+- ✅ 使用 Semi UI 组件
+- ✅ 使用 function 声明而非 React.FC
+- ✅ Props 精简,只保留核心功能
+- ✅ Named export
+
+#### 3.4 导出文件
+
+```typescript
+// index.tsx
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+export { MyComponent } from './my-component';
+export type { MyComponentProps } from './my-component';
+```
+
+### Step 4: 在 form-materials 主入口导出
+
+编辑 `packages/materials/form-materials/src/components/index.ts`:
+
+```typescript
+export {
+  // ... 其他组件按字母序
+  MyComponent,
+  // ... 继续其他组件
+  type MyComponentProps,
+  // ... 继续其他类型
+} from './components';
+```
+
+然后编辑 `packages/materials/form-materials/src/index.ts`,确保新组件在主导出列表中:
+
+```typescript
+export {
+  // ... 其他组件按字母序
+  MyComponent,
+  // ...
+  type MyComponentProps,
+  // ...
+} from './components';
+```
+
+### Step 5: 创建 Storybook Story
+
+在 `apps/demo-materials/src/stories/components/` 创建 Story:
+
+```typescript
+// my-component.stories.tsx
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import React, { useState } from 'react';
+import type { Meta, StoryObj } from 'storybook-react-rsbuild';
+import { MyComponent } from '@flowgram.ai/form-materials';
+import type { SomeType } from '@flowgram.ai/json-schema';
+
+const MyComponentDemo: React.FC = () => {
+  const [result, setResult] = useState<SomeType | null>(null);
+
+  return (
+    <div style={{ padding: '20px' }}>
+      <h2>My Component Demo</h2>
+      <MyComponent
+        onSomething={(data) => {
+          console.log('Generated data:', data);
+          setResult(data);
+        }}
+      />
+
+      {result && (
+        <div style={{ marginTop: '20px' }}>
+          <h3>结果:</h3>
+          <pre style={{
+            background: '#f5f5f5',
+            padding: '16px',
+            borderRadius: '4px',
+            overflow: 'auto'
+          }}>
+            {JSON.stringify(result, null, 2)}
+          </pre>
+        </div>
+      )}
+    </div>
+  );
+};
+
+const meta: Meta<typeof MyComponentDemo> = {
+  title: 'Form Components/MyComponent',
+  component: MyComponentDemo,
+  parameters: {
+    layout: 'centered',
+    docs: {
+      description: {
+        component: '组件功能描述',
+      },
+    },
+  },
+  tags: ['autodocs'],
+};
+
+export default meta;
+type Story = StoryObj<typeof meta>;
+
+export const Default: Story = {};
+```
+
+### Step 6: 运行类型检查
+
+```bash
+cd packages/materials/form-materials
+yarn ts-check
+```
+
+确保通过所有类型检查。
+
+### Step 7: 启动开发环境测试
+
+开启两个 Terminal:
+
+**Terminal 1 - 监听包编译:**
+```bash
+rush build:watch
+```
+
+**Terminal 2 - 启动 Storybook:**
+```bash
+cd apps/demo-materials
+yarn dev
+```
+
+访问 http://localhost:6006/,找到你的组件进行测试。
+
+## 常见问题
+
+### Q1: React 引用错误
+
+**错误信息**:
+```
+error TS2686: 'React' refers to a UMD global, but the current file is a module.
+```
+
+**解决方案**:
+在文件顶部添加:
+```typescript
+import React from 'react';
+```
+
+### Q2: 组件未导出
+
+**错误信息**:
+```
+Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.
+```
+
+**解决方案**:
+检查以下文件的导出:
+1. `components/{组件名}/index.tsx`
+2. `components/index.ts`
+3. `src/index.ts`
+
+### Q3: 类型找不到
+
+**错误信息**:
+```
+Cannot find module '@flowgram.ai/json-schema' or its corresponding type declarations.
+```
+
+**解决方案**:
+- 使用 `type IJsonSchema` 而非 `type JSONSchema7`
+- 从 `@flowgram.ai/json-schema` 导入而非 `json-schema`
+
+### Q4: CodeEditor 没有 height 属性
+
+**错误信息**:
+```
+Property 'height' does not exist on type 'CodeEditorPropsType'.
+```
+
+**解决方案**:
+使用外层 div 设置高度:
+```tsx
+<div style={{ minHeight: 300 }}>
+  <JsonCodeEditor value={value} onChange={onChange} />
+</div>
+```
+
+## 验收标准
+
+- [ ] 组件在 `packages/materials/form-materials/src/components/` 下创建
+- [ ] 使用 named export
+- [ ] 通过 `yarn ts-check` 类型检查
+- [ ] Props 精简,只保留核心功能
+- [ ] 在 Storybook 中可以正常显示和使用
+- [ ] 功能正常,无明显 bug
+- [ ] 代码符合 FlowGram 代码规范
+
+## 最佳实践
+
+### 1. 组件设计
+
+- **单一职责**:一个组件只做一件事
+- **Props 精简**:避免过度配置
+- **命名清晰**:组件名和 Props 名要清晰易懂
+
+### 2. 代码风格
+
+- **使用 TypeScript**:充分利用类型系统
+- **显式导入**:明确导入所需的依赖
+- **注释适度**:关键逻辑添加注释
+
+### 3. UI 一致性
+
+- **使用 Semi UI**:保持 UI 风格一致
+- **响应式设计**:考虑不同屏幕尺寸
+- **错误处理**:友好的错误提示
+
+### 4. 性能优化
+
+- **Named export**:支持 tree shaking
+- **按需加载**:避免不必要的依赖
+- **合理使用 memo**:必要时使用 React.memo
+
+## 示例参考
+
+完整示例请参考:
+- `packages/materials/form-materials/src/components/json-schema-creator/`
+- `apps/demo-materials/src/stories/components/json-schema-creator.stories.tsx`
+

+ 60 - 0
apps/demo-materials/src/stories/components/json-schema-creator.stories.tsx

@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import React, { useState } from 'react';
+
+import type { Meta, StoryObj } from 'storybook-react-rsbuild';
+import { JsonSchemaCreator, IJsonSchema } from '@flowgram.ai/form-materials';
+
+const JsonSchemaCreatorDemo: React.FC = () => {
+  const [schema, setSchema] = useState<IJsonSchema | null>(null);
+
+  return (
+    <div style={{ padding: '20px' }}>
+      <h2>JSON Schema Creator</h2>
+      <JsonSchemaCreator
+        onSchemaCreate={(generatedSchema) => {
+          console.log('生成的 schema:', generatedSchema);
+          setSchema(generatedSchema);
+        }}
+      />
+
+      {schema && (
+        <div style={{ marginTop: '20px' }}>
+          <h3>生成的 Schema:</h3>
+          <pre
+            style={{
+              background: '#f5f5f5',
+              padding: '16px',
+              borderRadius: '4px',
+              overflow: 'auto',
+            }}
+          >
+            {JSON.stringify(schema, null, 2)}
+          </pre>
+        </div>
+      )}
+    </div>
+  );
+};
+
+const meta: Meta<typeof JsonSchemaCreatorDemo> = {
+  title: 'Form Components/JsonSchemaCreator',
+  component: JsonSchemaCreatorDemo,
+  parameters: {
+    layout: 'centered',
+    docs: {
+      description: {
+        component: '从 JSON 字符串自动生成 JSONSchema 的组件',
+      },
+    },
+  },
+  tags: ['autodocs'],
+};
+
+export default meta;
+type Story = StoryObj<typeof meta>;
+
+export const Default: Story = {};

+ 49 - 0
apps/docs/components/form-materials/components/json-schema-creator.tsx

@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import React from 'react';
+
+import { Field } from '@flowgram.ai/free-layout-editor';
+import type { IJsonSchema } from '@flowgram.ai/form-materials';
+
+import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
+
+const JsonSchemaCreator = React.lazy(() =>
+  import('@flowgram.ai/form-materials').then((module) => ({
+    default: module.JsonSchemaCreator,
+  }))
+);
+
+const JsonSchemaEditor = React.lazy(() =>
+  import('@flowgram.ai/form-materials').then((module) => ({
+    default: module.JsonSchemaEditor,
+  }))
+);
+
+export const BasicStory = () => (
+  <FreeFormMetaStoryBuilder
+    filterEndNode
+    formMeta={{
+      render: () => (
+        <>
+          <FormHeader />
+          <Field<IJsonSchema | undefined> name="json_schema">
+            {({ field }) => (
+              <div>
+                <JsonSchemaCreator onSchemaCreate={(schema) => field.onChange(schema)} />
+                <div style={{ marginTop: 16 }}>
+                  <JsonSchemaEditor
+                    value={field.value}
+                    onChange={(value) => field.onChange(value)}
+                  />
+                </div>
+              </div>
+            )}
+          </Field>
+        </>
+      ),
+    }}
+  />
+);

+ 1 - 0
apps/docs/src/en/materials/components/_meta.json

@@ -1,6 +1,7 @@
 [
   "type-selector",
   "json-schema-editor",
+  "json-schema-creator",
   "variable-selector",
   "dynamic-value-input",
   "condition-row",

+ 146 - 0
apps/docs/src/en/materials/components/json-schema-creator.mdx

@@ -0,0 +1,146 @@
+import { SourceCode } from '@theme';
+import { BasicStory } from 'components/form-materials/components/json-schema-creator';
+
+# JsonSchemaCreator
+
+JsonSchemaCreator is a component that automatically generates JSON Schema from JSON strings. It provides a button to trigger a modal where users can paste JSON data, and the component automatically analyzes the data structure and generates the corresponding JSON Schema.
+
+## Demo
+
+### Basic Usage
+
+<BasicStory />
+
+```tsx pure title="form-meta.tsx"
+import { JsonSchemaCreator } from '@flowgram.ai/form-materials';
+
+const formMeta = {
+  render: () => (
+    <>
+      <FormHeader />
+      <Field<IJsonSchema | undefined> name="json_schema">
+        {({ field }) => (
+          <div>
+            <JsonSchemaCreator
+              onSchemaCreate={(schema) => field.onChange(schema)}
+            />
+            <div style={{ marginTop: 16 }}>
+              <JsonSchemaEditor
+                value={field.value}
+                onChange={(value) => field.onChange(value)}
+              />
+            </div>
+          </div>
+        )}
+      </Field>
+    </>
+  ),
+}
+```
+
+## API Reference
+
+### JsonSchemaCreator Props
+
+| Property | Type | Default | Description |
+|----------|------|---------|-------------|
+| `onSchemaCreate` | `(schema: IJsonSchema) => void` | - | Callback function after schema generation |
+
+## Source Code Guide
+
+<SourceCode
+  href="https://github.com/bytedance/flowgram.ai/tree/main/packages/materials/form-materials/src/components/json-schema-creator"
+/>
+
+Use CLI command to copy source code locally:
+
+```bash
+npx @flowgram.ai/cli@latest materials components/json-schema-creator
+```
+
+### Directory Structure
+
+```
+json-schema-creator/
+├── index.tsx              # Main component export, contains JsonSchemaCreator and JsonSchemaCreatorProps
+├── json-schema-creator.tsx # Main component implementation, contains button and state management
+├── json-input-modal.tsx   # JSON input modal component
+└── utils/
+    └── json-to-schema.ts  # Core utility function for JSON to Schema conversion
+```
+
+### Core Implementation
+
+#### JSON Parsing and Schema Generation Process
+
+The following is the complete interaction sequence diagram for JSON Schema creation:
+
+```mermaid
+sequenceDiagram
+    participant User as User
+    participant Creator as JsonSchemaCreator
+    participant Modal as JsonInputModal
+    participant Parser as jsonToSchema
+    participant Generator as generateSchema
+
+    %% Initial interaction
+    User->>Creator: Click "Create from JSON" button
+    Creator->>Creator: setVisible(true)
+    Creator->>Modal: Show modal
+
+    %% User input and confirmation
+    User->>Modal: Input JSON string
+    User->>Modal: Click confirm
+
+    %% JSON parsing and Schema generation
+    Modal->>Parser: Call jsonToSchema(jsonString)
+    Parser->>Parser: JSON.parse(jsonString)
+
+    %% Recursive Schema generation
+    Parser->>Generator: Call generateSchema(data)
+
+    %% Process based on data type
+    alt Data is null
+        Generator->>Generator: Return {type: 'string'}
+    else Data is array
+        Generator->>Generator: schema = {type: 'array'}
+        loop For each array element
+            Generator->>Generator: Recursively call generateSchema(item)
+        end
+    else Data is object
+        Generator->>Generator: schema = {type: 'object', properties: {}, required: []}
+        loop For each property
+            Generator->>Generator: Recursively call generateSchema(value)
+            Generator->>Generator: Add to properties and required
+        end
+    else Primitive type
+        Generator->>Generator: Return {type: typeof value}
+    end
+
+    %% Return result
+    Generator-->>Parser: Return generated schema
+    Parser-->>Modal: Return IJsonSchema
+
+    %% Callback and close
+    Modal->>Creator: Call onSchemaCreate(schema)
+    Creator->>Creator: setVisible(false)
+    Creator->>Modal: Close modal
+    Creator-->>User: Schema creation completed
+```
+
+### FlowGram APIs Used
+
+[**@flowgram.ai/json-schema**](https://github.com/bytedance/flowgram.ai/tree/main/packages/variable/json-schema)
+- [`IJsonSchema`](https://flowgram.ai/auto-docs/json-schema/interfaces/IJsonSchema): JSON Schema type definition
+
+### Other Components Dependencies
+
+[**JsonCodeEditor**](./code-editor) Code editor component
+- Used for editing JSON data in the modal
+
+### Third-party Libraries Used
+
+[**@douyinfe/semi-ui**](https://semi.design/)
+- `Button`: Button component to trigger modal
+- `Modal`: Modal container
+- `Typography`: Text component

+ 1 - 0
apps/docs/src/zh/materials/components/_meta.json

@@ -1,6 +1,7 @@
 [
   "type-selector",
   "json-schema-editor",
+  "json-schema-creator",
   "variable-selector",
   "dynamic-value-input",
   "condition-row",

+ 146 - 0
apps/docs/src/zh/materials/components/json-schema-creator.mdx

@@ -0,0 +1,146 @@
+import { SourceCode } from '@theme';
+import { BasicStory } from 'components/form-materials/components/json-schema-creator';
+
+# JsonSchemaCreator
+
+JsonSchemaCreator 是一个用于从 JSON 字符串自动生成 JSON Schema 的组件。它提供了一个按钮来触发弹窗,用户可以在弹窗中粘贴 JSON 数据,组件会自动分析数据结构并生成对应的 JSON Schema。
+
+## 案例演示
+
+### 基本使用
+
+<BasicStory />
+
+```tsx pure title="form-meta.tsx"
+import { JsonSchemaCreator } from '@flowgram.ai/form-materials';
+
+const formMeta = {
+  render: () => (
+    <>
+      <FormHeader />
+      <Field<IJsonSchema | undefined> name="json_schema">
+        {({ field }) => (
+          <div>
+            <JsonSchemaCreator
+              onSchemaCreate={(schema) => field.onChange(schema)}
+            />
+            <div style={{ marginTop: 16 }}>
+              <JsonSchemaEditor
+                value={field.value}
+                onChange={(value) => field.onChange(value)}
+              />
+            </div>
+          </div>
+        )}
+      </Field>
+    </>
+  ),
+}
+```
+
+## API 参考
+
+### JsonSchemaCreator Props
+
+| 属性名 | 类型 | 默认值 | 描述 |
+|--------|------|--------|------|
+| `onSchemaCreate` | `(schema: IJsonSchema) => void` | - | 生成 schema 后的回调函数 |
+
+## 源码导读
+
+<SourceCode
+  href="https://github.com/bytedance/flowgram.ai/tree/main/packages/materials/form-materials/src/components/json-schema-creator"
+/>
+
+使用 CLI 命令可以复制源代码到本地:
+
+```bash
+npx @flowgram.ai/cli@latest materials components/json-schema-creator
+```
+
+### 目录结构讲解
+
+```
+json-schema-creator/
+├── index.tsx              # 主组件导出,包含 JsonSchemaCreator 和 JsonSchemaCreatorProps
+├── json-schema-creator.tsx # 主组件实现,包含按钮和状态管理
+├── json-input-modal.tsx   # JSON 输入弹窗组件
+└── utils/
+    └── json-to-schema.ts  # JSON 转 Schema 的核心工具函数
+```
+
+### 核心实现说明
+
+#### JSON 解析和 Schema 生成流程
+
+以下是 JSON Schema 创建的完整交互时序图:
+
+```mermaid
+sequenceDiagram
+    participant User as 用户
+    participant Creator as JsonSchemaCreator
+    participant Modal as JsonInputModal
+    participant Parser as jsonToSchema
+    participant Generator as generateSchema
+
+    %% 初始交互
+    User->>Creator: 点击"从 JSON 创建"按钮
+    Creator->>Creator: setVisible(true)
+    Creator->>Modal: 显示弹窗
+
+    %% 用户输入和确认
+    User->>Modal: 输入 JSON 字符串
+    User->>Modal: 点击确认
+
+    %% JSON 解析和 Schema 生成
+    Modal->>Parser: 调用 jsonToSchema(jsonString)
+    Parser->>Parser: JSON.parse(jsonString)
+
+    %% 递归生成 Schema
+    Parser->>Generator: 调用 generateSchema(data)
+
+    %% 根据数据类型处理
+    alt 数据为 null
+        Generator->>Generator: 返回 {type: 'string'}
+    else 数据为数组
+        Generator->>Generator: schema = {type: 'array'}
+        loop 对每个数组元素
+            Generator->>Generator: 递归调用 generateSchema(item)
+        end
+    else 数据为对象
+        Generator->>Generator: schema = {type: 'object', properties: {}, required: []}
+        loop 对每个属性
+            Generator->>Generator: 递归调用 generateSchema(value)
+            Generator->>Generator: 添加到 properties 和 required
+        end
+    else 原始类型
+        Generator->>Generator: 返回 {type: typeof value}
+    end
+
+    %% 返回结果
+    Generator-->>Parser: 返回生成的 schema
+    Parser-->>Modal: 返回 IJsonSchema
+
+    %% 回调和关闭
+    Modal->>Creator: 调用 onSchemaCreate(schema)
+    Creator->>Creator: setVisible(false)
+    Creator->>Modal: 关闭弹窗
+    Creator-->>User: Schema 创建完成
+```
+
+### 使用到的 FlowGram API
+
+[**@flowgram.ai/json-schema**](https://github.com/bytedance/flowgram.ai/tree/main/packages/variable/json-schema)
+- [`IJsonSchema`](https://flowgram.ai/auto-docs/json-schema/interfaces/IJsonSchema): JSON Schema 类型定义
+
+### 依赖的其他物料
+
+[**JsonCodeEditor**](./code-editor) 代码编辑器组件
+- 用于在弹窗中编辑 JSON 数据
+
+### 使用的第三方库
+
+[**@douyinfe/semi-ui**](https://semi.design/)
+- `Button`: 触发弹窗的按钮组件
+- `Modal`: 弹窗容器
+- `Typography`: 文本组件

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

@@ -53,6 +53,7 @@ export {
   JsonEditorWithVariables,
   type JsonEditorWithVariablesProps,
 } from './json-editor-with-variables';
+export { JsonSchemaCreator, type JsonSchemaCreatorProps } from './json-schema-creator';
 export { JsonSchemaEditor } from './json-schema-editor';
 export { PromptEditor, type PromptEditorPropsType } from './prompt-editor';
 export {

+ 7 - 0
packages/materials/form-materials/src/components/json-schema-creator/index.tsx

@@ -0,0 +1,7 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+export { JsonSchemaCreator } from './json-schema-creator';
+export type { JsonSchemaCreatorProps } from './json-schema-creator';

+ 61 - 0
packages/materials/form-materials/src/components/json-schema-creator/json-input-modal.tsx

@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import React, { useState } from 'react';
+
+import type { IJsonSchema } from '@flowgram.ai/json-schema';
+import { I18n } from '@flowgram.ai/editor';
+import { Modal, Typography } from '@douyinfe/semi-ui';
+
+import { jsonToSchema } from './utils/json-to-schema';
+import { JsonCodeEditor } from '../code-editor';
+
+const { Text } = Typography;
+
+interface JsonInputModalProps {
+  visible: boolean;
+  onClose: () => void;
+  onConfirm: (schema: IJsonSchema) => void;
+}
+
+export function JsonInputModal({ visible, onClose, onConfirm }: JsonInputModalProps) {
+  const [jsonInput, setJsonInput] = useState('');
+  const [error, setError] = useState('');
+
+  const handleConfirm = () => {
+    try {
+      const schema = jsonToSchema(jsonInput);
+      onConfirm(schema);
+      setJsonInput('');
+      setError('');
+    } catch (err) {
+      setError((err as Error).message);
+    }
+  };
+
+  return (
+    <Modal
+      visible={visible}
+      onCancel={onClose}
+      onOk={handleConfirm}
+      title={I18n.t('JSON to JSONSchema')}
+      okText={I18n.t('Generate')}
+      cancelText={I18n.t('Cancel')}
+      width={600}
+    >
+      <div style={{ marginBottom: 8 }}>
+        <Text>{I18n.t('Paste JSON data')}:</Text>
+      </div>
+      <div style={{ minHeight: 300 }}>
+        <JsonCodeEditor value={jsonInput} onChange={(value) => setJsonInput(value || '')} />
+      </div>
+      {error && (
+        <div style={{ marginTop: 8 }}>
+          <Text type="danger">{error}</Text>
+        </div>
+      )}
+    </Modal>
+  );
+}

+ 37 - 0
packages/materials/form-materials/src/components/json-schema-creator/json-schema-creator.tsx

@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import React, { useState } from 'react';
+
+import type { IJsonSchema } from '@flowgram.ai/json-schema';
+import { I18n } from '@flowgram.ai/editor';
+import { Button } from '@douyinfe/semi-ui';
+
+import { JsonInputModal } from './json-input-modal';
+
+export interface JsonSchemaCreatorProps {
+  /** 生成 schema 后的回调 */
+  onSchemaCreate?: (schema: IJsonSchema) => void;
+}
+
+export function JsonSchemaCreator({ onSchemaCreate }: JsonSchemaCreatorProps) {
+  const [visible, setVisible] = useState(false);
+
+  const handleCreate = (schema: IJsonSchema) => {
+    onSchemaCreate?.(schema);
+    setVisible(false);
+  };
+
+  return (
+    <>
+      <Button onClick={() => setVisible(true)}>{I18n.t('JSON to JSONSchema')}</Button>
+      <JsonInputModal
+        visible={visible}
+        onClose={() => setVisible(false)}
+        onConfirm={handleCreate}
+      />
+    </>
+  );
+}

+ 50 - 0
packages/materials/form-materials/src/components/json-schema-creator/utils/json-to-schema.ts

@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import type { IJsonSchema } from '@flowgram.ai/json-schema';
+
+export function jsonToSchema(jsonString: string): IJsonSchema {
+  // 1. 解析 JSON
+  const data = JSON.parse(jsonString); // 会自动抛出语法错误
+
+  // 2. 生成 schema
+  return generateSchema(data);
+}
+
+function generateSchema(value: any): IJsonSchema {
+  // null
+  if (value === null) {
+    return { type: 'string' };
+  }
+
+  // array
+  if (Array.isArray(value)) {
+    const schema: IJsonSchema = { type: 'array' };
+    if (value.length > 0) {
+      schema.items = generateSchema(value[0]);
+    }
+    return schema;
+  }
+
+  // object
+  if (typeof value === 'object') {
+    const schema: IJsonSchema = {
+      type: 'object',
+      properties: {},
+      required: [],
+    };
+
+    for (const [key, val] of Object.entries(value)) {
+      schema.properties![key] = generateSchema(val);
+      schema.required!.push(key);
+    }
+
+    return schema;
+  }
+
+  // primitive types
+  const type = typeof value;
+  return { type: type as any };
+}

+ 2 - 0
packages/materials/form-materials/src/index.ts

@@ -34,6 +34,7 @@ export {
   InputsValuesTree,
   JsonCodeEditor,
   JsonEditorWithVariables,
+  JsonSchemaCreator,
   JsonSchemaEditor,
   PromptEditor,
   PromptEditorWithInputs,
@@ -59,6 +60,7 @@ export {
   type IConditionRule,
   type IConditionRuleFactory,
   type JsonEditorWithVariablesProps,
+  type JsonSchemaCreatorProps,
   type PromptEditorPropsType,
   type PromptEditorWithInputsProps,
   type PromptEditorWithVariablesProps,