@flowgram-vue/type-editor 0.2.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.
Files changed (55) hide show
  1. package/LICENSE +22 -0
  2. package/dist/index.cjs +0 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.js +0 -0
  6. package/dist/index.js.map +1 -0
  7. package/package.json +63 -0
  8. package/src/components/index.ts +8 -0
  9. package/src/components/type-editor/columns/index.ts +404 -0
  10. package/src/components/type-editor/common.ts +44 -0
  11. package/src/components/type-editor/formatter/index.ts +44 -0
  12. package/src/components/type-editor/hooks/active-pos.ts +20 -0
  13. package/src/components/type-editor/hooks/disabled.ts +22 -0
  14. package/src/components/type-editor/hooks/formatter-value.ts +53 -0
  15. package/src/components/type-editor/hooks/index.ts +8 -0
  16. package/src/components/type-editor/index.ts +9 -0
  17. package/src/components/type-editor/mode/declare-assign.ts +102 -0
  18. package/src/components/type-editor/mode/index.ts +15 -0
  19. package/src/components/type-editor/mode/type-definition.ts +46 -0
  20. package/src/components/type-editor/table.vue +293 -0
  21. package/src/components/type-editor/type-editor.vue +107 -0
  22. package/src/components/type-editor/type.ts +142 -0
  23. package/src/components/type-editor/utils.ts +173 -0
  24. package/src/components/type-selector/index.ts +51 -0
  25. package/src/components/type-selector/type-selector.vue +100 -0
  26. package/src/contexts/index.ts +106 -0
  27. package/src/env.d.ts +10 -0
  28. package/src/index.ts +15 -0
  29. package/src/json-schema-exports.ts +18 -0
  30. package/src/preset/index.ts +6 -0
  31. package/src/preset/object-type-editor.vue +91 -0
  32. package/src/services/clipboard-service.ts +93 -0
  33. package/src/services/index.ts +11 -0
  34. package/src/services/shortcut-service.ts +9 -0
  35. package/src/services/type-editor-service.ts +396 -0
  36. package/src/services/type-operation-service.ts +99 -0
  37. package/src/services/type-registry-manager.ts +14 -0
  38. package/src/services/utils.ts +28 -0
  39. package/src/styles.css +235 -0
  40. package/src/type-registry/array.ts +18 -0
  41. package/src/type-registry/boolean.ts +30 -0
  42. package/src/type-registry/index.ts +22 -0
  43. package/src/type-registry/integer.ts +24 -0
  44. package/src/type-registry/number.ts +23 -0
  45. package/src/type-registry/object.ts +13 -0
  46. package/src/type-registry/string.ts +21 -0
  47. package/src/types/index.ts +7 -0
  48. package/src/types/registry.ts +52 -0
  49. package/src/types/type-editor.ts +150 -0
  50. package/src/utils/index.ts +6 -0
  51. package/src/utils/monitor-data/index.ts +7 -0
  52. package/src/utils/monitor-data/monitor-data.ts +43 -0
  53. package/src/utils/monitor-data/use-monitor-data.ts +29 -0
  54. package/src/utils/registry-adapter.ts +83 -0
  55. package/src/utils/toast.ts +16 -0
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { set, get } from 'lodash-es';
7
+ import { IJsonSchema } from '@flowgram-vue/json-schema';
8
+
9
+ import { typeEditorUtils } from '../utils';
10
+ import { type ModeValueConfig } from '../type';
11
+ import { TypeEditorColumnType, TypeEditorSchema } from '../../../types';
12
+
13
+ const traverseIJsonSchema = (
14
+ root: TypeEditorSchema<IJsonSchema> | undefined,
15
+ path: string[],
16
+ cb: (type: TypeEditorSchema<IJsonSchema>, path: string[]) => void
17
+ ): void => {
18
+ if (root) {
19
+ cb(root, path);
20
+
21
+ if (root.properties) {
22
+ Object.keys(root.properties).forEach((k) => {
23
+ traverseIJsonSchema(root.properties![k], [...path, k], cb);
24
+ });
25
+ }
26
+ }
27
+ };
28
+
29
+ export const declareAssignConfig: ModeValueConfig<'declare-assign', IJsonSchema> = {
30
+ mode: 'declare-assign',
31
+ convertSchemaToValue: (val) => {
32
+ const data = {};
33
+ const newSchema = JSON.parse(JSON.stringify(val));
34
+
35
+ traverseIJsonSchema(newSchema, [], (type, path) => {
36
+ if (type.extra?.value !== undefined) {
37
+ set(data, path, type.extra?.value);
38
+ }
39
+ if (type.extra) {
40
+ delete type.extra;
41
+ }
42
+ });
43
+
44
+ return {
45
+ data,
46
+ definition: { schema: newSchema },
47
+ };
48
+ },
49
+ convertValueToSchema: (schema) => {
50
+ const { data } = schema;
51
+ const newSchema = JSON.parse(JSON.stringify(schema.definition.schema));
52
+ traverseIJsonSchema(newSchema, [], (type, path) => {
53
+ const value = get(data, path);
54
+ if (value !== undefined && type.type !== 'object') {
55
+ type.extra = { value };
56
+ }
57
+ });
58
+ return newSchema;
59
+ },
60
+ commonValueToSubmitValue: (val) => {
61
+ const type: IJsonSchema = val
62
+ ? typeEditorUtils.valueToTypeSchema(val)
63
+ : {
64
+ type: 'object',
65
+ properties: {},
66
+ };
67
+ return {
68
+ data: val || {},
69
+ definition: {
70
+ schema: type,
71
+ },
72
+ };
73
+ },
74
+
75
+ toolConfig: {
76
+ createByData: {
77
+ viewConfig: [
78
+ {
79
+ type: TypeEditorColumnType.Key,
80
+ visible: true,
81
+ },
82
+ {
83
+ type: TypeEditorColumnType.Type,
84
+ visible: true,
85
+ },
86
+ {
87
+ type: TypeEditorColumnType.Value,
88
+ visible: true,
89
+ },
90
+ ],
91
+ genDefaultValue: () => ({
92
+ data: {},
93
+ definition: {
94
+ schema: {
95
+ type: 'object',
96
+ properties: {},
97
+ },
98
+ },
99
+ }),
100
+ },
101
+ },
102
+ };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { IJsonSchema } from '@flowgram-vue/json-schema';
7
+
8
+ import { type ModeValueConfig, type TypeEditorMode } from '../type';
9
+ import { typeDefinitionConfig } from './type-definition';
10
+ import { declareAssignConfig } from './declare-assign';
11
+
12
+ export const modeValueConfig: ModeValueConfig<TypeEditorMode, IJsonSchema>[] = [
13
+ declareAssignConfig,
14
+ typeDefinitionConfig,
15
+ ];
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { IJsonSchema } from '@flowgram-vue/json-schema';
7
+
8
+ import { typeEditorUtils } from '../utils';
9
+ import { type ModeValueConfig } from '../type';
10
+ import { TypeEditorColumnType } from '../../../types';
11
+
12
+ export const typeDefinitionConfig: ModeValueConfig<'type-definition', IJsonSchema> = {
13
+ mode: 'type-definition',
14
+ convertSchemaToValue: (val) => val,
15
+ convertValueToSchema: (val) => val,
16
+ commonValueToSubmitValue: (val) => {
17
+ if (val) {
18
+ return typeEditorUtils.valueToTypeSchema(val);
19
+ }
20
+ return {
21
+ type: 'object',
22
+ properties: {},
23
+ };
24
+ },
25
+
26
+ toolConfig: {
27
+ createByData: {
28
+ viewConfig: [
29
+ {
30
+ type: TypeEditorColumnType.Key,
31
+ visible: true,
32
+ },
33
+ {
34
+ type: TypeEditorColumnType.Type,
35
+ visible: true,
36
+ },
37
+ ],
38
+ genDefaultValue() {
39
+ return {
40
+ type: 'object',
41
+ properties: {},
42
+ };
43
+ },
44
+ },
45
+ },
46
+ };
@@ -0,0 +1,293 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { computed, onMounted, ref, watch } from 'vue';
7
+ import { isEqual } from 'lodash-es';
8
+ import { IJsonSchema } from '@flowgram-vue/json-schema';
9
+
10
+ import {
11
+ TypeEditorColumnType,
12
+ TypeEditorRowData,
13
+ } from '../../types';
14
+ import { TypeEditorOperationService, TypeEditorService } from '../../services';
15
+ import { useService, useTypeDefinitionManager } from '../../contexts';
16
+ import { typeEditorUtils } from './utils';
17
+ import { type TypeEditorMode, type TypeEditorRef, type TypeEditorVueProps } from './type';
18
+ import { useFormatter } from './hooks/formatter-value';
19
+ import { columnConfigs } from './columns';
20
+ import { ROOT_FIELD_ID } from './common';
21
+
22
+ const props = defineProps<TypeEditorVueProps>();
23
+
24
+ const extraConfig = computed(() => ({ ...(props.extraConfig || {}) }));
25
+ const { formatter, deFormatter } = useFormatter({
26
+ mode: props.mode,
27
+ extraConfig: extraConfig.value,
28
+ });
29
+
30
+ const typeEditor = useService<TypeEditorService<IJsonSchema>>(TypeEditorService);
31
+ const typeOperator = useService<TypeEditorOperationService<IJsonSchema>>(
32
+ TypeEditorOperationService
33
+ );
34
+ const typeService = useTypeDefinitionManager();
35
+
36
+ const tableDom = ref<HTMLTableElement>();
37
+ const unOpenKeys = ref<Record<string, boolean>>({});
38
+ const dragId = ref<string>();
39
+
40
+ const typeSchema = computed(() => formatter(props.value));
41
+ const initialSchema = ref<IJsonSchema>(
42
+ typeEditorUtils.clone(typeSchema.value) || typeEditorUtils.getInitialSchema()
43
+ );
44
+
45
+ typeOperator.storeState(initialSchema.value as IJsonSchema);
46
+ typeEditor.registerConfigs(columnConfigs);
47
+ props.viewConfigs.forEach((config) => {
48
+ if (config.config) {
49
+ typeEditor.addConfigProps(config.type, config.config);
50
+ }
51
+ });
52
+
53
+ watch(
54
+ () => typeSchema.value,
55
+ (next) => {
56
+ if (
57
+ !isEqual(next, initialSchema.value) &&
58
+ next &&
59
+ (props.forceUpdate ||
60
+ !typeEditorUtils.isTempState(initialSchema.value, extraConfig.value.customValidateName))
61
+ ) {
62
+ initialSchema.value = typeEditorUtils.clone(next);
63
+ }
64
+ }
65
+ );
66
+
67
+ const displayColumn = computed(() => props.viewConfigs.filter((v) => v.visible).map((v) => v.type));
68
+
69
+ const dataSource = computed(() => {
70
+ const res: TypeEditorRowData<IJsonSchema>[] = [];
71
+ let index = -1;
72
+ const dfs = (
73
+ schema: IJsonSchema,
74
+ config: {
75
+ level: number;
76
+ parentId?: string;
77
+ key?: string;
78
+ parent?: IJsonSchema;
79
+ path: string[];
80
+ }
81
+ ): void => {
82
+ const { parentId, level = -1, key = ROOT_FIELD_ID, path, parent } = config;
83
+ const id = [parentId, key || String(Date.now())].join('-');
84
+ const typeConfig = typeService.getTypeBySchema(schema);
85
+ const uid = parentId ? id : key;
86
+ const rowData: TypeEditorRowData<IJsonSchema> = {
87
+ ...schema,
88
+ key,
89
+ index,
90
+ id: uid,
91
+ level,
92
+ self: schema,
93
+ parentId,
94
+ parent,
95
+ deepChildrenCount: 0,
96
+ isRequired: (parent?.required || []).includes(key),
97
+ childrenCount: 0,
98
+ disableEditColumn: [...(props.disableEditColumn || [])],
99
+ path,
100
+ extraConfig: { ...extraConfig.value },
101
+ };
102
+ index += 1;
103
+ typeEditor.dataSourceMap[rowData.id] = rowData;
104
+ res.push(rowData);
105
+ if (typeConfig) {
106
+ const children = typeConfig.getTypeSchemaProperties?.(schema);
107
+ const childrenParent = typeConfig.getPropertiesParent?.(schema);
108
+ if (children) {
109
+ rowData.childrenCount = Object.keys(children).length;
110
+ if (unOpenKeys.value[uid]) {
111
+ return;
112
+ }
113
+ const parentPath = [...path, ...(typeConfig.getJsonPaths?.(schema) || [])];
114
+ let idx = 0;
115
+ Object.keys(children)
116
+ .map((k) => {
117
+ typeEditorUtils.fixFlowIndex(children[k], idx);
118
+ idx += 1;
119
+ return k;
120
+ })
121
+ .sort((k1, k2) => (children[k1].extra?.index || 0) - (children[k2].extra?.index || 0))
122
+ .forEach((k) => {
123
+ dfs(children[k], {
124
+ key: k,
125
+ parentId: id,
126
+ parent: childrenParent,
127
+ level: level + 1,
128
+ path: [...parentPath, k],
129
+ });
130
+ });
131
+ }
132
+ }
133
+ };
134
+ if (initialSchema.value) {
135
+ dfs(initialSchema.value, { level: -1, path: [] });
136
+ res.shift();
137
+ const newData = props.onEditRowDataSource ? props.onEditRowDataSource(res) : res;
138
+ typeEditor.setDataSource(newData);
139
+ return newData;
140
+ }
141
+ return [];
142
+ });
143
+
144
+ const handleChange = (type?: IJsonSchema, ctx: { storeState?: boolean } = {}) => {
145
+ const { storeState = true } = ctx;
146
+ const newSchema = JSON.parse(JSON.stringify(type || initialSchema.value)) as IJsonSchema;
147
+ initialSchema.value = { ...newSchema };
148
+ const final = typeEditorUtils.formateTypeSchema(newSchema, extraConfig.value);
149
+ if (storeState) {
150
+ typeOperator.storeState(newSchema);
151
+ }
152
+ props.onChange?.(deFormatter(final)!);
153
+ };
154
+
155
+ typeEditor.onChange = handleChange;
156
+
157
+ const activePos = ref(typeEditor.activePos);
158
+ typeEditor.onActivePosChange.event((v) => {
159
+ activePos.value = v;
160
+ });
161
+
162
+ const instance: TypeEditorRef<TypeEditorMode, IJsonSchema> = {
163
+ getService: () => typeEditor,
164
+ getOperator: () => typeOperator,
165
+ getContainer: () => tableDom.value,
166
+ getValue: () => deFormatter(typeEditor.rootTypeSchema),
167
+ setValue(originNewVal) {
168
+ let newVal = originNewVal;
169
+ if (props.onCustomSetValue) {
170
+ newVal = props.onCustomSetValue(newVal);
171
+ }
172
+ const newSchema = formatter(newVal)!;
173
+ initialSchema.value = newSchema;
174
+ typeOperator.storeState(newSchema);
175
+ const final = typeEditorUtils.formateTypeSchema(newSchema, extraConfig.value);
176
+ props.onChange?.(deFormatter(final)!);
177
+ },
178
+ undo: () => {
179
+ typeOperator.undo();
180
+ typeEditor.onChange(typeOperator.getCurrentState(), { storeState: false });
181
+ },
182
+ redo: () => {
183
+ typeOperator.redo();
184
+ typeEditor.onChange(typeOperator.getCurrentState(), { storeState: false });
185
+ },
186
+ };
187
+
188
+ watch(
189
+ () => initialSchema.value,
190
+ (v) => {
191
+ typeEditor.rootTypeSchema = v;
192
+ },
193
+ { immediate: true }
194
+ );
195
+
196
+ onMounted(() => {
197
+ props.onInit?.({ current: instance });
198
+ });
199
+
200
+ defineExpose(instance);
201
+
202
+ const onDropRow = (target: TypeEditorRowData<IJsonSchema>) => {
203
+ if (!dragId.value || dragId.value === target.id) {
204
+ return;
205
+ }
206
+ const dragData = typeEditor.dataSourceMap[dragId.value];
207
+ if (!dragData?.parent?.properties || !target.parent?.properties) {
208
+ dragId.value = undefined;
209
+ return;
210
+ }
211
+ if (target.parent.properties[dragData.key] && target.parent !== dragData.parent) {
212
+ dragId.value = undefined;
213
+ return;
214
+ }
215
+ delete dragData.parent.properties[dragData.key];
216
+ target.parent.properties[dragData.key] = dragData.self;
217
+ typeEditorUtils.fixFlowIndex(dragData);
218
+ dragData.extra!.index = (target.extra?.index || 0) + 0.1;
219
+ typeEditorUtils.sortProperties(target.parent);
220
+ typeEditorUtils.sortProperties(dragData.parent);
221
+ handleChange();
222
+ dragId.value = undefined;
223
+ };
224
+
225
+ const cellProps = (row: TypeEditorRowData<IJsonSchema>, columnType: TypeEditorColumnType) => ({
226
+ rowData: row,
227
+ readonly: props.readonly,
228
+ typeEditor,
229
+ unOpenKeys: unOpenKeys.value,
230
+ error: false,
231
+ onChange: () => handleChange(),
232
+ onViewMode: () => typeEditor.clearActivePos(),
233
+ onEditMode: () => {
234
+ if (!props.readonly) {
235
+ typeEditor.setActivePos({
236
+ x: displayColumn.value.indexOf(columnType),
237
+ y: row.index,
238
+ });
239
+ }
240
+ },
241
+ onChildrenVisibleChange: (id: string, val: boolean) => {
242
+ unOpenKeys.value = { ...unOpenKeys.value, [id]: val };
243
+ },
244
+ });
245
+ </script>
246
+
247
+ <template>
248
+ <div class="fg-type-editor">
249
+ <table ref="tableDom" :class="['fg-type-table', props.tableClassName]">
250
+ <thead>
251
+ <tr>
252
+ <th
253
+ v-for="col in displayColumn"
254
+ :key="col"
255
+ :style="{ width: typeEditor.getConfigByType(col)?.width ? `${typeEditor.getConfigByType(col)?.width}%` : undefined }"
256
+ >
257
+ {{ typeEditor.getConfigByType(col)?.label }}
258
+ </th>
259
+ </tr>
260
+ </thead>
261
+ <tbody>
262
+ <tr v-if="dataSource.length === 0">
263
+ <td :colspan="displayColumn.length">
264
+ <div class="fg-type-empty">No content. Please add.</div>
265
+ </td>
266
+ </tr>
267
+ <tr
268
+ v-for="row in dataSource"
269
+ :key="row.id"
270
+ class="fg-type-row"
271
+ :class="{ 'is-dragging': dragId === row.id }"
272
+ draggable="true"
273
+ @dragstart="dragId = row.id"
274
+ @dragover.prevent
275
+ @drop.prevent="onDropRow(row)"
276
+ >
277
+ <td v-for="col in displayColumn" :key="col">
278
+ <component
279
+ :is="
280
+ activePos.x === displayColumn.indexOf(col) &&
281
+ activePos.y === row.index
282
+ ? typeEditor.getConfigByType(col)?.editRender ||
283
+ typeEditor.getConfigByType(col)?.viewRender
284
+ : typeEditor.getConfigByType(col)?.viewRender
285
+ "
286
+ v-bind="cellProps(row, col)"
287
+ />
288
+ </td>
289
+ </tr>
290
+ </tbody>
291
+ </table>
292
+ </div>
293
+ </template>
@@ -0,0 +1,107 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { computed, ref } from 'vue';
7
+ import { IJsonSchema } from '@flowgram-vue/json-schema';
8
+
9
+ import { TypeEditorProvider } from '../../contexts';
10
+ import { typeEditorUtils } from './utils';
11
+ import { modeValueConfig } from './mode';
12
+ import TypeEditorTable from './table.vue';
13
+ import {
14
+ ToolbarKey,
15
+ type ToolbarConfig,
16
+ type TypeEditorMode,
17
+ type TypeEditorRef,
18
+ type TypeEditorVueProps,
19
+ } from './type';
20
+
21
+ defineOptions({ name: 'TypeEditor' });
22
+
23
+ const props = defineProps<TypeEditorVueProps>();
24
+ const editor = ref<TypeEditorRef<TypeEditorMode, IJsonSchema>>();
25
+ const importVisible = ref(false);
26
+ const importText = ref('{}');
27
+
28
+ const configMap = computed(() => {
29
+ const res = new Map<string, ToolbarConfig>();
30
+ (props.toolbarConfig || []).forEach((tool) => {
31
+ if (typeof tool === 'string') {
32
+ res.set(tool, { type: tool });
33
+ } else {
34
+ res.set(tool.type, tool);
35
+ }
36
+ });
37
+ return res;
38
+ });
39
+
40
+ const importConfig = computed(() => configMap.value.get(ToolbarKey.Import));
41
+ const showUndo = computed(() => configMap.value.has(ToolbarKey.UndoRedo));
42
+
43
+ const onInit = (inst: { current?: TypeEditorRef<TypeEditorMode, IJsonSchema> }) => {
44
+ editor.value = inst.current;
45
+ props.onInit?.(inst);
46
+ };
47
+
48
+ const applyImport = () => {
49
+ const parsed = typeEditorUtils.jsonParse(importText.value);
50
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
51
+ return;
52
+ }
53
+ const modeConfig = modeValueConfig.find((v) => v.mode === props.mode);
54
+ if (modeConfig && editor.value) {
55
+ editor.value.setValue(modeConfig.commonValueToSubmitValue(parsed) as never);
56
+ }
57
+ importVisible.value = false;
58
+ };
59
+
60
+ defineExpose({
61
+ getContainer: () => editor.value?.getContainer(),
62
+ setValue: ((v) => editor.value?.setValue(v)) as TypeEditorRef<
63
+ TypeEditorMode,
64
+ IJsonSchema
65
+ >['setValue'],
66
+ getService: () => editor.value?.getService(),
67
+ undo: () => editor.value?.undo(),
68
+ redo: () => editor.value?.redo(),
69
+ getValue: () => editor.value?.getValue(),
70
+ getOperator: () => editor.value?.getOperator(),
71
+ });
72
+ </script>
73
+
74
+ <template>
75
+ <TypeEditorProvider :type-registry-creators="props.typeRegistryCreators">
76
+ <div class="fg-type-editor">
77
+ <div v-if="editor && (importConfig || showUndo)" class="fg-type-toolbar">
78
+ <button
79
+ v-if="importConfig"
80
+ type="button"
81
+ class="fg-type-btn"
82
+ :disabled="!!importConfig.disabled"
83
+ @click="importVisible = true"
84
+ >
85
+ Import from JSON
86
+ </button>
87
+ <button v-if="showUndo" type="button" class="fg-type-btn" @click="editor.undo()">
88
+ Undo
89
+ </button>
90
+ <button v-if="showUndo" type="button" class="fg-type-btn" @click="editor.redo()">
91
+ Redo
92
+ </button>
93
+ </div>
94
+ <TypeEditorTable v-bind="props" :on-init="onInit" />
95
+ <div v-if="importVisible" class="fg-type-modal" @click.self="importVisible = false">
96
+ <div class="fg-type-modal-card">
97
+ <h3>Import from JSON</h3>
98
+ <textarea v-model="importText" class="fg-type-textarea" rows="12" />
99
+ <div class="fg-type-toolbar" style="margin-top: 12px">
100
+ <button type="button" class="fg-type-btn" @click="importVisible = false">Cancel</button>
101
+ <button type="button" class="fg-type-btn" @click="applyImport">Import</button>
102
+ </div>
103
+ </div>
104
+ </div>
105
+ </div>
106
+ </TypeEditorProvider>
107
+ </template>
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import type { Component } from 'vue';
7
+ import { IJsonSchema } from '@flowgram-vue/json-schema';
8
+
9
+ import {
10
+ type TypeEditorSpecialConfig,
11
+ type TypeEditorColumnViewConfig,
12
+ type TypeEditorRowData,
13
+ type TypeChangeContext,
14
+ type TypeEditorColumnType,
15
+ type TypeEditorSchema,
16
+ TypeEditorColumnConfig,
17
+ } from '../../types';
18
+ import { TypeEditorOperationService, type TypeEditorService } from '../../services';
19
+ import { TypeRegistryCreatorsAdapter } from '../../contexts';
20
+
21
+ export type TypeEditorMode = 'type-definition' | 'declare-assign';
22
+
23
+ export interface DeclareAssignValueType<TypeSchema extends Partial<IJsonSchema>> {
24
+ data: unknown;
25
+ definition: {
26
+ schema: TypeSchema;
27
+ };
28
+ }
29
+
30
+ export type TypeEditorValue<
31
+ Mode extends TypeEditorMode,
32
+ TypeSchema extends Partial<IJsonSchema>
33
+ > = Mode extends 'type-definition'
34
+ ? TypeEditorSchema<TypeSchema>
35
+ : DeclareAssignValueType<TypeSchema>;
36
+
37
+ export enum ToolbarKey {
38
+ Import = 'Import',
39
+ UndoRedo = 'UndoRedo',
40
+ }
41
+
42
+ export type ToolbarConfig = {
43
+ type: ToolbarKey;
44
+ disabled?: string;
45
+ customInputRender?: Component<{
46
+ value: string;
47
+ onChange: (newVal: string) => void;
48
+ }>;
49
+ };
50
+
51
+ export interface TypeEditorProp<
52
+ Mode extends TypeEditorMode,
53
+ TypeSchema extends Partial<IJsonSchema>
54
+ > {
55
+ toolbarConfig?: (ToolbarKey | ToolbarConfig)[];
56
+ mode: Mode;
57
+ readonly?: boolean;
58
+ tableClassName?: string;
59
+ extraConfig?: TypeEditorSpecialConfig<TypeSchema>;
60
+ rootLevel?: number;
61
+ getRootSchema?: (schema: TypeSchema) => TypeSchema;
62
+ typeRegistryCreators?: TypeRegistryCreatorsAdapter<IJsonSchema>[];
63
+ viewConfigs: (TypeEditorColumnViewConfig & {
64
+ config?: Partial<Omit<TypeEditorColumnConfig<TypeSchema>, 'type'>>;
65
+ })[];
66
+ onEditRowDataSource?: (data: TypeEditorRowData<TypeSchema>[]) => TypeEditorRowData<TypeSchema>[];
67
+ forceUpdate?: boolean;
68
+ onError?: (msg?: string[]) => void;
69
+ value?: TypeEditorValue<Mode, TypeSchema>;
70
+ onChange?: (newValue: TypeEditorValue<Mode, TypeSchema>) => void;
71
+ onPaste?: (typeSchema?: TypeSchema) => TypeSchema | undefined;
72
+ onInit?: (editor: { current?: TypeEditorRef<Mode, TypeSchema> }) => void;
73
+ onFieldChange?: (ctx: TypeChangeContext) => void;
74
+ onCustomSetValue?: (
75
+ newValue: TypeEditorValue<Mode, TypeSchema>
76
+ ) => TypeEditorValue<Mode, TypeSchema>;
77
+ customEmptyNode?: Component;
78
+ disableEditColumn?: Array<{ column: TypeEditorColumnType; reason: string }>;
79
+ }
80
+
81
+ /** Vue SFC defineProps-friendly surface (no conditional types). */
82
+ export interface TypeEditorVueProps {
83
+ mode: TypeEditorMode;
84
+ readonly?: boolean;
85
+ tableClassName?: string;
86
+ extraConfig?: TypeEditorSpecialConfig<IJsonSchema>;
87
+ rootLevel?: number;
88
+ getRootSchema?: (schema: IJsonSchema) => IJsonSchema;
89
+ typeRegistryCreators?: TypeRegistryCreatorsAdapter<IJsonSchema>[];
90
+ viewConfigs: Array<{
91
+ type: TypeEditorColumnType;
92
+ visible: boolean;
93
+ config?: Record<string, unknown>;
94
+ }>;
95
+ onEditRowDataSource?: (
96
+ data: TypeEditorRowData<IJsonSchema>[]
97
+ ) => TypeEditorRowData<IJsonSchema>[];
98
+ forceUpdate?: boolean;
99
+ onError?: (msg?: string[]) => void;
100
+ value?: IJsonSchema | DeclareAssignValueType<IJsonSchema>;
101
+ onChange?: (newValue: IJsonSchema | DeclareAssignValueType<IJsonSchema>) => void;
102
+ onPaste?: (typeSchema?: IJsonSchema) => IJsonSchema | undefined;
103
+ onInit?: (editor: { current?: TypeEditorRef<TypeEditorMode, IJsonSchema> }) => void;
104
+ onFieldChange?: (ctx: TypeChangeContext) => void;
105
+ onCustomSetValue?: (
106
+ newValue: IJsonSchema | DeclareAssignValueType<IJsonSchema>
107
+ ) => IJsonSchema | DeclareAssignValueType<IJsonSchema>;
108
+ customEmptyNode?: Component;
109
+ disableEditColumn?: Array<{ column: TypeEditorColumnType; reason: string }>;
110
+ toolbarConfig?: (ToolbarKey | ToolbarConfig)[];
111
+ }
112
+
113
+ export interface TypeEditorRef<
114
+ Mode extends TypeEditorMode,
115
+ TypeSchema extends Partial<IJsonSchema>
116
+ > {
117
+ setValue: (newVal: TypeEditorValue<Mode, TypeSchema>) => void;
118
+ getValue: () => TypeEditorValue<Mode, TypeSchema> | undefined;
119
+ undo: () => void;
120
+ redo: () => void;
121
+ getService: () => TypeEditorService<TypeSchema> | undefined;
122
+ getOperator: () => TypeEditorOperationService<TypeSchema> | undefined;
123
+ getContainer: () => HTMLDivElement | undefined;
124
+ }
125
+
126
+ export interface ModeValueConfig<
127
+ Mode extends TypeEditorMode,
128
+ TypeSchema extends Partial<IJsonSchema>
129
+ > {
130
+ mode: Mode;
131
+ convertValueToSchema: (val: TypeEditorValue<Mode, TypeSchema>) => TypeSchema;
132
+ convertSchemaToValue: (val: TypeSchema) => TypeEditorValue<Mode, TypeSchema>;
133
+ commonValueToSubmitValue: (
134
+ val: Record<string, unknown> | undefined
135
+ ) => TypeEditorValue<Mode, TypeSchema>;
136
+ toolConfig: {
137
+ createByData: {
138
+ viewConfig: TypeEditorColumnViewConfig[];
139
+ genDefaultValue: () => TypeEditorValue<Mode, TypeSchema>;
140
+ };
141
+ };
142
+ }