@tyx1703/json-schema-editor-visual 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +109 -0
- package/dist/JsonSchemaEditor.d.ts +19 -0
- package/dist/JsonSchemaEditor.js +478 -0
- package/dist/components/LocalProvider/index.d.ts +79 -0
- package/dist/components/LocalProvider/index.js +80 -0
- package/dist/components/MockSelect/index.d.ts +9 -0
- package/dist/components/MockSelect/index.js +40 -0
- package/dist/components/MonacoEditor/index.d.ts +16 -0
- package/dist/components/MonacoEditor/index.js +77 -0
- package/dist/components/SchemaComponents/FieldInput.d.ts +8 -0
- package/dist/components/SchemaComponents/FieldInput.js +36 -0
- package/dist/components/SchemaComponents/SchemaJson.d.ts +36 -0
- package/dist/components/SchemaComponents/SchemaJson.js +634 -0
- package/dist/components/SchemaComponents/SchemaOther.d.ts +9 -0
- package/dist/components/SchemaComponents/SchemaOther.js +735 -0
- package/dist/components/SchemaComponents/schemaJson.css +128 -0
- package/dist/index.css +53 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +15 -0
- package/dist/schema.d.ts +15 -0
- package/dist/schema.js +24 -0
- package/dist/store/index.d.ts +16 -0
- package/dist/store/index.js +11 -0
- package/dist/store/schemaSlice.d.ts +49 -0
- package/dist/store/schemaSlice.js +208 -0
- package/dist/types.d.ts +56 -0
- package/dist/types.js +0 -0
- package/dist/utils.d.ts +31 -0
- package/dist/utils.js +164 -0
- package/package.json +76 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import { ConfigProvider } from "antd";
|
|
3
|
+
const langs = {
|
|
4
|
+
en_US: {
|
|
5
|
+
title: 'Title',
|
|
6
|
+
import_json: 'Import JSON',
|
|
7
|
+
base_setting: 'Base Setting',
|
|
8
|
+
all_setting: 'Source Code',
|
|
9
|
+
default: 'Default',
|
|
10
|
+
description: "Description",
|
|
11
|
+
adv_setting: 'Advanced Settings',
|
|
12
|
+
add_child_node: 'Add child node',
|
|
13
|
+
add_sibling_node: 'Add sibling nodes',
|
|
14
|
+
add_node: 'Add sibling/child nodes',
|
|
15
|
+
child_node: 'Child node',
|
|
16
|
+
sibling_node: 'Sibling node',
|
|
17
|
+
ok: 'OK',
|
|
18
|
+
cancel: 'Cancel',
|
|
19
|
+
minLength: 'Min length',
|
|
20
|
+
maxLength: 'Max length',
|
|
21
|
+
pattern: 'MUST be a string and SHOULD be a valid regular expression.',
|
|
22
|
+
exclusiveMinimum: 'Value strictly less than',
|
|
23
|
+
exclusiveMaximum: 'Value strictly more than',
|
|
24
|
+
minimum: 'Min',
|
|
25
|
+
maximum: 'Max',
|
|
26
|
+
unique_items: 'Unique Items',
|
|
27
|
+
min_items: 'MinItems',
|
|
28
|
+
max_items: 'MaxItems',
|
|
29
|
+
checked_all: 'Checked All',
|
|
30
|
+
valid_json: 'Not valid json',
|
|
31
|
+
enum: 'Enum',
|
|
32
|
+
enum_msg: 'One value per line',
|
|
33
|
+
enum_desc: 'desc',
|
|
34
|
+
enum_desc_msg: "enum description",
|
|
35
|
+
required: 'required',
|
|
36
|
+
mock: 'mock',
|
|
37
|
+
mockLink: 'Help'
|
|
38
|
+
},
|
|
39
|
+
zh_CN: {
|
|
40
|
+
title: '标题',
|
|
41
|
+
import_json: '导入 json',
|
|
42
|
+
base_setting: '基础设置',
|
|
43
|
+
all_setting: '编辑源码',
|
|
44
|
+
default: '默认值',
|
|
45
|
+
description: '备注',
|
|
46
|
+
adv_setting: '高级设置',
|
|
47
|
+
add_child_node: '添加子节点',
|
|
48
|
+
add_sibling_node: '添加兄弟节点',
|
|
49
|
+
add_node: '添加兄弟/子节点',
|
|
50
|
+
child_node: '子节点',
|
|
51
|
+
sibling_node: '兄弟节点',
|
|
52
|
+
ok: '确定',
|
|
53
|
+
cancel: '取消',
|
|
54
|
+
minLength: '最小长度',
|
|
55
|
+
maxLength: '最大长度',
|
|
56
|
+
pattern: '用正则表达式约束字符串',
|
|
57
|
+
exclusiveMinimum: '开启后,数据必须大于最小值',
|
|
58
|
+
exclusiveMaximum: '开启后,数据必须小于最大值',
|
|
59
|
+
minimum: '最小值',
|
|
60
|
+
maximum: '最大值',
|
|
61
|
+
unique_items: '开启后,每个元素都不相同',
|
|
62
|
+
min_items: '最小元素个数',
|
|
63
|
+
max_items: '最大元素个数',
|
|
64
|
+
checked_all: '全选',
|
|
65
|
+
valid_json: '不是合法的json字符串',
|
|
66
|
+
enum: '枚举',
|
|
67
|
+
enum_msg: '每行只能写一个值',
|
|
68
|
+
enum_desc: '备注',
|
|
69
|
+
enum_desc_msg: '备注描述信息',
|
|
70
|
+
required: '是否必须',
|
|
71
|
+
mock: 'mock',
|
|
72
|
+
mockLink: '查看文档'
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
function useLocalProvider() {
|
|
76
|
+
const { locale } = useContext(ConfigProvider.ConfigContext);
|
|
77
|
+
const langKey = locale?.locale.startsWith('zh') ? 'zh_CN' : 'en_US';
|
|
78
|
+
return (message)=>langs[langKey][message];
|
|
79
|
+
}
|
|
80
|
+
export { useLocalProvider };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { JsonSchema, MockSource } from '../../types';
|
|
2
|
+
interface MockSelectProps {
|
|
3
|
+
schema: JsonSchema;
|
|
4
|
+
showEdit: () => void;
|
|
5
|
+
onChange: (value: string) => void;
|
|
6
|
+
mock?: MockSource;
|
|
7
|
+
}
|
|
8
|
+
export default function MockSelect({ schema, showEdit, onChange, mock, }: MockSelectProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import { AutoComplete, Button, Space } from "antd";
|
|
4
|
+
import { EditOutlined } from "@ant-design/icons";
|
|
5
|
+
import { useLocalProvider } from "../LocalProvider/index.js";
|
|
6
|
+
function MockSelect({ schema, showEdit, onChange, mock }) {
|
|
7
|
+
const LocaleProvider = useLocalProvider();
|
|
8
|
+
const disabled = 'object' === schema.type || 'array' === schema.type;
|
|
9
|
+
const options = useMemo(()=>(mock || []).map((item)=>({
|
|
10
|
+
value: item.mock
|
|
11
|
+
})), [
|
|
12
|
+
mock
|
|
13
|
+
]);
|
|
14
|
+
return /*#__PURE__*/ jsxs(Space.Compact, {
|
|
15
|
+
className: "mock-select",
|
|
16
|
+
children: [
|
|
17
|
+
/*#__PURE__*/ jsx(AutoComplete, {
|
|
18
|
+
className: "certain-category-search",
|
|
19
|
+
style: {
|
|
20
|
+
flex: 1
|
|
21
|
+
},
|
|
22
|
+
popupMatchSelectWidth: false,
|
|
23
|
+
options: options,
|
|
24
|
+
placeholder: LocaleProvider('mock'),
|
|
25
|
+
filterOption: true,
|
|
26
|
+
value: schema.mock?.mock,
|
|
27
|
+
onChange: onChange,
|
|
28
|
+
disabled: disabled
|
|
29
|
+
}),
|
|
30
|
+
/*#__PURE__*/ jsx(Button, {
|
|
31
|
+
icon: /*#__PURE__*/ jsx(EditOutlined, {}),
|
|
32
|
+
onClick: (e)=>{
|
|
33
|
+
e.stopPropagation();
|
|
34
|
+
showEdit();
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
]
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
export default MockSelect;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface MockEditorData {
|
|
3
|
+
text: string;
|
|
4
|
+
format: boolean | string;
|
|
5
|
+
jsonData: Record<string, unknown> | null;
|
|
6
|
+
}
|
|
7
|
+
declare const LanguageMap: Record<string, string>;
|
|
8
|
+
type ModeKey = keyof typeof LanguageMap;
|
|
9
|
+
interface AceEditorProps {
|
|
10
|
+
data?: string;
|
|
11
|
+
onChange?: (data: MockEditorData) => void;
|
|
12
|
+
className?: string;
|
|
13
|
+
mode?: ModeKey;
|
|
14
|
+
}
|
|
15
|
+
declare const _default: React.NamedExoticComponent<AceEditorProps>;
|
|
16
|
+
export default _default;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import react, { useCallback } from "react";
|
|
3
|
+
import _monaco_editor_react, { loader } from "@monaco-editor/react";
|
|
4
|
+
const LanguageMap = {
|
|
5
|
+
javascript: "javascript",
|
|
6
|
+
json: 'json',
|
|
7
|
+
text: 'plaintext',
|
|
8
|
+
xml: 'xml',
|
|
9
|
+
html: 'html'
|
|
10
|
+
};
|
|
11
|
+
function buildMockEditorData(text) {
|
|
12
|
+
try {
|
|
13
|
+
const jsonData = JSON.parse(text);
|
|
14
|
+
return {
|
|
15
|
+
text,
|
|
16
|
+
format: true,
|
|
17
|
+
jsonData
|
|
18
|
+
};
|
|
19
|
+
} catch (e) {
|
|
20
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
21
|
+
return {
|
|
22
|
+
text,
|
|
23
|
+
format: message,
|
|
24
|
+
jsonData: null
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const isBrowser = "u" > typeof window;
|
|
29
|
+
const AceEditor = ({ data, onChange, className, mode = 'json' })=>{
|
|
30
|
+
const handleChange = useCallback((value)=>{
|
|
31
|
+
const text = value ?? '';
|
|
32
|
+
onChange?.(buildMockEditorData(text));
|
|
33
|
+
}, [
|
|
34
|
+
onChange
|
|
35
|
+
]);
|
|
36
|
+
const handleBeforeMount = useCallback(async ()=>{
|
|
37
|
+
const monaco = await import("monaco-editor");
|
|
38
|
+
self.MonacoEnvironment = {
|
|
39
|
+
getWorker (_moduleId, label) {
|
|
40
|
+
if ('json' === label) return new Worker(new URL('monaco-editor/esm/vs/language/json/json.worker', import.meta.url));
|
|
41
|
+
if ('html' === label || 'handlebars' === label || 'razor' === label) return new Worker(new URL('monaco-editor/esm/vs/language/html/html.worker', import.meta.url));
|
|
42
|
+
if ("typescript" === label || "javascript" === label) return new Worker(new URL("monaco-editor/esm/vs/language/typescript/ts.worker", import.meta.url));
|
|
43
|
+
return new Worker(new URL('monaco-editor/esm/vs/editor/editor.worker', import.meta.url));
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
loader.config({
|
|
47
|
+
monaco
|
|
48
|
+
});
|
|
49
|
+
}, []);
|
|
50
|
+
if (!isBrowser) return null;
|
|
51
|
+
return /*#__PURE__*/ jsx("div", {
|
|
52
|
+
className: className ?? 'monaco-editor-container',
|
|
53
|
+
style: className ? void 0 : {
|
|
54
|
+
width: '100%',
|
|
55
|
+
height: '200px'
|
|
56
|
+
},
|
|
57
|
+
children: /*#__PURE__*/ jsx(_monaco_editor_react, {
|
|
58
|
+
height: "100%",
|
|
59
|
+
language: LanguageMap[mode] ?? 'plaintext',
|
|
60
|
+
value: data ?? '',
|
|
61
|
+
onChange: handleChange,
|
|
62
|
+
beforeMount: handleBeforeMount,
|
|
63
|
+
options: {
|
|
64
|
+
minimap: {
|
|
65
|
+
enabled: false
|
|
66
|
+
},
|
|
67
|
+
fontSize: 14,
|
|
68
|
+
scrollBeyondLastLine: false,
|
|
69
|
+
automaticLayout: true,
|
|
70
|
+
tabSize: 2,
|
|
71
|
+
wordWrap: 'on'
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
const MonacoEditor = /*#__PURE__*/ react.memo(AceEditor);
|
|
77
|
+
export default MonacoEditor;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { InputProps } from 'antd';
|
|
3
|
+
interface FieldInputProps extends Omit<InputProps, 'value' | 'onChange'> {
|
|
4
|
+
value?: string;
|
|
5
|
+
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
6
|
+
}
|
|
7
|
+
export default function FieldInput({ value, onChange, ...restProps }: FieldInputProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
import { Input } from "antd";
|
|
4
|
+
function FieldInput({ value = '', onChange, ...restProps }) {
|
|
5
|
+
const [internalValue, setInternalValue] = useState(value);
|
|
6
|
+
const propsValueRef = useRef(value);
|
|
7
|
+
const onChangeRef = useRef(onChange);
|
|
8
|
+
useEffect(()=>{
|
|
9
|
+
propsValueRef.current = value;
|
|
10
|
+
setInternalValue(value);
|
|
11
|
+
}, [
|
|
12
|
+
value
|
|
13
|
+
]);
|
|
14
|
+
useEffect(()=>{
|
|
15
|
+
onChangeRef.current = onChange;
|
|
16
|
+
}, [
|
|
17
|
+
onChange
|
|
18
|
+
]);
|
|
19
|
+
const handleChange = useCallback((e)=>{
|
|
20
|
+
setInternalValue(e.target.value);
|
|
21
|
+
}, []);
|
|
22
|
+
const handlePressEnter = useCallback((e)=>{
|
|
23
|
+
if (e.target.value !== propsValueRef.current) onChangeRef.current?.(e);
|
|
24
|
+
}, []);
|
|
25
|
+
const handleBlur = useCallback((e)=>{
|
|
26
|
+
if (e.target.value !== propsValueRef.current) onChangeRef.current?.(e);
|
|
27
|
+
}, []);
|
|
28
|
+
return /*#__PURE__*/ jsx(Input, {
|
|
29
|
+
...restProps,
|
|
30
|
+
value: internalValue,
|
|
31
|
+
onChange: handleChange,
|
|
32
|
+
onPressEnter: handlePressEnter,
|
|
33
|
+
onBlur: handleBlur
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
export default FieldInput;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import './schemaJson.css';
|
|
2
|
+
import { JsonSchema, MockSource } from '../../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* 通用属性接口
|
|
5
|
+
* @property prefix - 当前节点的路径前缀
|
|
6
|
+
* @property data - 当前节点的 JSON Schema 数据
|
|
7
|
+
* @property showEdit - 打开备注/mock 编辑弹窗的回调
|
|
8
|
+
* @property showAdv - 打开高级设置弹窗的回调
|
|
9
|
+
*/
|
|
10
|
+
export interface CommonProps {
|
|
11
|
+
prefix: string[];
|
|
12
|
+
data: JsonSchema;
|
|
13
|
+
showEdit: (prefix: string[], name: string, value: unknown, type: string) => void;
|
|
14
|
+
showAdv: (prefix: string[], value: unknown) => void;
|
|
15
|
+
mock?: MockSource;
|
|
16
|
+
}
|
|
17
|
+
export interface SchemaItemProps extends CommonProps {
|
|
18
|
+
name: string;
|
|
19
|
+
}
|
|
20
|
+
export interface DropPlusProps {
|
|
21
|
+
prefix: string[];
|
|
22
|
+
name: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Schema 编辑器入口组件,根据根节点数据类型渲染对应的 Schema 子树
|
|
26
|
+
* @property data - 根节点的 JSON Schema 数据
|
|
27
|
+
* @property showEdit - 打开备注/mock 编辑弹窗的回调
|
|
28
|
+
* @property showAdv - 打开高级设置弹窗的回调
|
|
29
|
+
*/
|
|
30
|
+
export interface SchemaJsonProps {
|
|
31
|
+
data: JsonSchema;
|
|
32
|
+
showEdit: (prefix: string[], name: string, value: unknown, type: string) => void;
|
|
33
|
+
showAdv: (prefix: string[], value: unknown) => void;
|
|
34
|
+
mock?: MockSource;
|
|
35
|
+
}
|
|
36
|
+
export default function SchemaJson({ data, showEdit, showAdv, mock, }: SchemaJsonProps): import("react/jsx-runtime").JSX.Element;
|