@tmagic/editor 1.3.0-alpha.7 → 1.3.0-alpha.8
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/dist/style.css +14 -0
- package/dist/tmagic-editor.js +65 -22
- package/dist/tmagic-editor.js.map +1 -1
- package/dist/tmagic-editor.umd.cjs +65 -21
- package/dist/tmagic-editor.umd.cjs.map +1 -1
- package/package.json +12 -12
- package/src/components/SplitView.vue +2 -2
- package/src/fields/DataSourceInput.vue +11 -10
- package/src/index.ts +1 -0
- package/src/layouts/Framework.vue +1 -2
- package/src/layouts/PropsPanel.vue +2 -1
- package/src/layouts/sidebar/LayerMenu.vue +4 -3
- package/src/layouts/sidebar/LayerPanel.vue +5 -1
- package/src/theme/data-source-input.scss +18 -0
- package/src/theme/theme.scss +1 -0
- package/src/utils/props.ts +34 -0
- package/types/index.d.ts +1 -0
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.3.0-alpha.
|
|
2
|
+
"version": "1.3.0-alpha.8",
|
|
3
3
|
"name": "@tmagic/editor",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": [
|
|
@@ -46,27 +46,27 @@
|
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@babel/core": "^7.18.0",
|
|
48
48
|
"@element-plus/icons-vue": "^2.0.9",
|
|
49
|
-
"@tmagic/core": "1.3.0-alpha.
|
|
50
|
-
"@tmagic/design": "1.3.0-alpha.
|
|
51
|
-
"@tmagic/form": "1.3.0-alpha.
|
|
52
|
-
"@tmagic/schema": "1.3.0-alpha.
|
|
53
|
-
"@tmagic/stage": "1.3.0-alpha.
|
|
54
|
-
"@tmagic/table": "1.3.0-alpha.
|
|
55
|
-
"@tmagic/utils": "1.3.0-alpha.
|
|
49
|
+
"@tmagic/core": "1.3.0-alpha.8",
|
|
50
|
+
"@tmagic/design": "1.3.0-alpha.8",
|
|
51
|
+
"@tmagic/form": "1.3.0-alpha.8",
|
|
52
|
+
"@tmagic/schema": "1.3.0-alpha.8",
|
|
53
|
+
"@tmagic/stage": "1.3.0-alpha.8",
|
|
54
|
+
"@tmagic/table": "1.3.0-alpha.8",
|
|
55
|
+
"@tmagic/utils": "1.3.0-alpha.8",
|
|
56
56
|
"buffer": "^6.0.3",
|
|
57
57
|
"color": "^3.1.3",
|
|
58
58
|
"events": "^3.3.0",
|
|
59
59
|
"gesto": "^1.7.0",
|
|
60
60
|
"keycon": "^1.1.2",
|
|
61
61
|
"lodash-es": "^4.17.21",
|
|
62
|
-
"monaco-editor": "^0.
|
|
62
|
+
"monaco-editor": "^0.39.0",
|
|
63
63
|
"serialize-javascript": "^6.0.0",
|
|
64
64
|
"vue": "^3.3.4"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
|
-
"@tmagic/design": "1.3.0-alpha.
|
|
68
|
-
"@tmagic/form": "1.3.0-alpha.
|
|
69
|
-
"monaco-editor": "^0.
|
|
67
|
+
"@tmagic/design": "1.3.0-alpha.8",
|
|
68
|
+
"@tmagic/form": "1.3.0-alpha.8",
|
|
69
|
+
"monaco-editor": "^0.39.0",
|
|
70
70
|
"vue": "^3.3.4"
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div ref="el" class="m-editor-layout">
|
|
3
|
-
<template v-if="hasLeft">
|
|
3
|
+
<template v-if="hasLeft && $slots.left">
|
|
4
4
|
<div class="m-editor-layout-left" :class="leftClass" :style="`width: ${left}px`">
|
|
5
5
|
<slot name="left"></slot>
|
|
6
6
|
</div>
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<slot name="center"></slot>
|
|
12
12
|
</div>
|
|
13
13
|
|
|
14
|
-
<template v-if="hasRight">
|
|
14
|
+
<template v-if="hasRight && $slots.right">
|
|
15
15
|
<Resizer @change="changeRight"></Resizer>
|
|
16
16
|
<div class="m-editor-layout-right" :class="rightClass" :style="`width: ${right}px`">
|
|
17
17
|
<slot name="right"></slot>
|
|
@@ -30,13 +30,15 @@
|
|
|
30
30
|
</div>
|
|
31
31
|
</template>
|
|
32
32
|
</component>
|
|
33
|
-
<div :class="`el-input el-input--${size}`" @mouseup="mouseupHandler" v-else>
|
|
34
|
-
<div :class="`el-input__wrapper ${isFocused ? ' is-focus' : ''}`">
|
|
33
|
+
<div :class="`tmagic-data-source-input-text el-input el-input--${size}`" @mouseup="mouseupHandler" v-else>
|
|
34
|
+
<div :class="`tmagic-data-source-input-text-wrapper el-input__wrapper ${isFocused ? ' is-focus' : ''}`">
|
|
35
35
|
<div class="el-input__inner">
|
|
36
36
|
<template v-for="(item, index) in displayState">
|
|
37
37
|
<span :key="index" v-if="item.type === 'text'" style="margin-right: 2px">{{ item.value }}</span>
|
|
38
38
|
<TMagicTag :key="index" :size="size" v-if="item.type === 'var'">{{ item.value }}</TMagicTag>
|
|
39
39
|
</template>
|
|
40
|
+
|
|
41
|
+
<Icon class="tmagic-data-source-input-icon" :icon="Coin" />
|
|
40
42
|
</div>
|
|
41
43
|
</div>
|
|
42
44
|
</div>
|
|
@@ -90,7 +92,7 @@ const dataSources = computed(() => dataSourceService?.get('dataSources') || []);
|
|
|
90
92
|
const setDisplayState = () => {
|
|
91
93
|
displayState.value = [];
|
|
92
94
|
|
|
93
|
-
const matches = state.value.matchAll(
|
|
95
|
+
const matches = state.value.matchAll(/\$\{([\s\S]+?)\}/g);
|
|
94
96
|
let index = 0;
|
|
95
97
|
for (const match of matches) {
|
|
96
98
|
if (typeof match.index === 'undefined') break;
|
|
@@ -195,7 +197,7 @@ const getSelectionStart = () => {
|
|
|
195
197
|
* @param leftCurlyBracketIndex {字符索引
|
|
196
198
|
*/
|
|
197
199
|
const curCharIsLeftCurlyBracket = (leftCurlyBracketIndex: number) =>
|
|
198
|
-
leftCurlyBracketIndex >
|
|
200
|
+
leftCurlyBracketIndex > 0 && leftCurlyBracketIndex === getSelectionStart() - 1;
|
|
199
201
|
|
|
200
202
|
/**
|
|
201
203
|
* 当前输入的是.
|
|
@@ -213,7 +215,7 @@ const dsQuerySearch = (queryString: string, leftCurlyBracketIndex: number, cb: (
|
|
|
213
215
|
if (curCharIsLeftCurlyBracket(leftCurlyBracketIndex)) {
|
|
214
216
|
// 当前输入的是{
|
|
215
217
|
result = dataSources.value;
|
|
216
|
-
} else if (leftCurlyBracketIndex >
|
|
218
|
+
} else if (leftCurlyBracketIndex > 0) {
|
|
217
219
|
// 当前输入的是{xx
|
|
218
220
|
const queryName = queryString.substring(leftCurlyBracketIndex + 1).toLowerCase();
|
|
219
221
|
result = dataSources.value.filter((ds) => ds.title?.toLowerCase().includes(queryName) || ds.id.includes(queryName));
|
|
@@ -299,7 +301,7 @@ const querySearch = (queryString: string, cb: (data: { value: string }[]) => voi
|
|
|
299
301
|
const curQueryString = queryString.substring(0, selectionStart);
|
|
300
302
|
|
|
301
303
|
const fieldKeyStringLastIndex = curQueryString.lastIndexOf('.');
|
|
302
|
-
const dsKeyStringLastIndex = curQueryString.lastIndexOf('{');
|
|
304
|
+
const dsKeyStringLastIndex = curQueryString.lastIndexOf('${') + 1;
|
|
303
305
|
|
|
304
306
|
const isFieldTip = fieldKeyStringLastIndex > dsKeyStringLastIndex;
|
|
305
307
|
|
|
@@ -321,7 +323,7 @@ const selectHandler = async ({ value, type }: { value: string; type: 'dataSource
|
|
|
321
323
|
let startText = inputText.substring(0, selectionStart);
|
|
322
324
|
|
|
323
325
|
const dotIndex = startText.lastIndexOf('.');
|
|
324
|
-
const leftCurlyBracketIndex = startText.lastIndexOf('{');
|
|
326
|
+
const leftCurlyBracketIndex = startText.lastIndexOf('${') + 1;
|
|
325
327
|
|
|
326
328
|
const endText = inputText.substring(selectionStart);
|
|
327
329
|
|
|
@@ -336,7 +338,6 @@ const selectHandler = async ({ value, type }: { value: string; type: 'dataSource
|
|
|
336
338
|
if (!isRightCurlyBracket(selectionStart + 1)) {
|
|
337
339
|
suggestText = `${suggestText}}`;
|
|
338
340
|
}
|
|
339
|
-
suggestText = `{${suggestText}}`;
|
|
340
341
|
} else if (!curCharIsDot(dotIndex)) {
|
|
341
342
|
startText = startText.substring(0, dotIndex + 1);
|
|
342
343
|
}
|
|
@@ -345,10 +346,10 @@ const selectHandler = async ({ value, type }: { value: string; type: 'dataSource
|
|
|
345
346
|
|
|
346
347
|
await nextTick();
|
|
347
348
|
|
|
348
|
-
// 由于选择数据源时会在后面补全}
|
|
349
|
+
// 由于选择数据源时会在后面补全}, 所以光标要前移2位
|
|
349
350
|
let newSelectionStart = 0;
|
|
350
351
|
if (isDataSource) {
|
|
351
|
-
newSelectionStart = leftCurlyBracketIndex + suggestText.length
|
|
352
|
+
newSelectionStart = leftCurlyBracketIndex + suggestText.length;
|
|
352
353
|
} else {
|
|
353
354
|
newSelectionStart = dotIndex + suggestText.length + 1;
|
|
354
355
|
}
|
package/src/index.ts
CHANGED
|
@@ -62,6 +62,7 @@ export { default as ContentMenu } from './components/ContentMenu.vue';
|
|
|
62
62
|
export { default as Icon } from './components/Icon.vue';
|
|
63
63
|
export { default as LayoutContainer } from './components/SplitView.vue';
|
|
64
64
|
export { default as SplitView } from './components/SplitView.vue';
|
|
65
|
+
export { default as Resizer } from './components/Resizer.vue';
|
|
65
66
|
|
|
66
67
|
const defaultInstallOpt: InstallOptions = {
|
|
67
68
|
// eslint-disable-next-line no-eval
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
</slot>
|
|
34
34
|
</template>
|
|
35
35
|
|
|
36
|
-
<template v-if="pageLength > 0
|
|
36
|
+
<template v-if="pageLength > 0" #right>
|
|
37
37
|
<TMagicScrollbar>
|
|
38
38
|
<slot name="props-panel"></slot>
|
|
39
39
|
</TMagicScrollbar>
|
|
@@ -68,7 +68,6 @@ const codeOptions = inject('codeOptions', {});
|
|
|
68
68
|
const { editorService, uiService } = inject<Services>('services') || {};
|
|
69
69
|
|
|
70
70
|
const root = computed(() => editorService?.get('root'));
|
|
71
|
-
const nodes = computed(() => editorService?.get('nodes') || []);
|
|
72
71
|
|
|
73
72
|
const pageLength = computed(() => editorService?.get('pageLength') || 0);
|
|
74
73
|
const showSrc = computed(() => uiService?.get('showSrc'));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="m-editor-props-panel">
|
|
2
|
+
<div class="m-editor-props-panel" v-if="nodes.length === 1">
|
|
3
3
|
<slot name="props-panel-header"></slot>
|
|
4
4
|
<MForm
|
|
5
5
|
ref="configForm"
|
|
@@ -35,6 +35,7 @@ const configForm = ref<InstanceType<typeof MForm>>();
|
|
|
35
35
|
const curFormConfig = ref<any>([]);
|
|
36
36
|
const services = inject<Services>('services');
|
|
37
37
|
const node = computed(() => services?.editorService.get('node'));
|
|
38
|
+
const nodes = computed(() => services?.editorService.get('nodes') || []);
|
|
38
39
|
const propsPanelSize = computed(() => services?.uiService.get('propsPanelSize') || 'small');
|
|
39
40
|
const stage = computed(() => services?.editorService.get('stage'));
|
|
40
41
|
|
|
@@ -22,6 +22,7 @@ const props = defineProps<{
|
|
|
22
22
|
const services = inject<Services>('services');
|
|
23
23
|
const menu = ref<InstanceType<typeof ContentMenu>>();
|
|
24
24
|
const node = computed(() => services?.editorService.get('node'));
|
|
25
|
+
const nodes = computed(() => services?.editorService.get('nodes'));
|
|
25
26
|
const isRoot = computed(() => node.value?.type === NodeType.ROOT);
|
|
26
27
|
const isPage = computed(() => node.value?.type === NodeType.PAGE);
|
|
27
28
|
const componentList = computed(() => services?.componentListService.getList() || []);
|
|
@@ -82,7 +83,7 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() => [
|
|
|
82
83
|
type: 'button',
|
|
83
84
|
text: '新增',
|
|
84
85
|
icon: markRaw(Plus),
|
|
85
|
-
display: () => node.value?.items,
|
|
86
|
+
display: () => node.value?.items && nodes.value?.length === 1,
|
|
86
87
|
items: getSubMenuData.value,
|
|
87
88
|
},
|
|
88
89
|
{
|
|
@@ -91,7 +92,7 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() => [
|
|
|
91
92
|
icon: markRaw(CopyDocument),
|
|
92
93
|
display: () => !isRoot.value,
|
|
93
94
|
handler: () => {
|
|
94
|
-
node.value && services?.editorService.copy(
|
|
95
|
+
node.value && services?.editorService.copy(nodes.value || []);
|
|
95
96
|
},
|
|
96
97
|
},
|
|
97
98
|
{
|
|
@@ -100,7 +101,7 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() => [
|
|
|
100
101
|
icon: markRaw(Delete),
|
|
101
102
|
display: () => !isRoot.value && !isPage.value,
|
|
102
103
|
handler: () => {
|
|
103
|
-
node.value && services?.editorService.remove(
|
|
104
|
+
node.value && services?.editorService.remove(nodes.value || []);
|
|
104
105
|
},
|
|
105
106
|
},
|
|
106
107
|
...props.layerContentMenu,
|
|
@@ -350,7 +350,11 @@ const clickHandler = (data: MNode): void => {
|
|
|
350
350
|
// 右键菜单
|
|
351
351
|
const contextmenu = async (event: MouseEvent, data: MNode): Promise<void> => {
|
|
352
352
|
event.preventDefault();
|
|
353
|
-
|
|
353
|
+
|
|
354
|
+
if (nodes.value.length < 2) {
|
|
355
|
+
await select(data);
|
|
356
|
+
}
|
|
357
|
+
|
|
354
358
|
menu.value?.show(event);
|
|
355
359
|
};
|
|
356
360
|
</script>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
.tmagic-data-source-input-text {
|
|
2
|
+
.el-input__wrapper.tmagic-data-source-input-text-wrapper {
|
|
3
|
+
overflow: hidden;
|
|
4
|
+
padding-right: 30px;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.el-input__inner {
|
|
8
|
+
display: flex;
|
|
9
|
+
align-items: center;
|
|
10
|
+
overflow: hidden;
|
|
11
|
+
white-space: nowrap;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.tmagic-data-source-input-icon {
|
|
15
|
+
position: absolute;
|
|
16
|
+
right: 7px;
|
|
17
|
+
}
|
|
18
|
+
}
|
package/src/theme/theme.scss
CHANGED
package/src/utils/props.ts
CHANGED
|
@@ -105,6 +105,40 @@ export const fillConfig = (config: FormConfig = []) => [
|
|
|
105
105
|
},
|
|
106
106
|
],
|
|
107
107
|
},
|
|
108
|
+
{
|
|
109
|
+
type: 'fieldset',
|
|
110
|
+
legend: '边框',
|
|
111
|
+
items: [
|
|
112
|
+
{
|
|
113
|
+
name: 'borderWidth',
|
|
114
|
+
text: '宽度',
|
|
115
|
+
defaultValue: '0',
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: 'borderColor',
|
|
119
|
+
text: '颜色',
|
|
120
|
+
type: 'colorPicker',
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: 'borderStyle',
|
|
124
|
+
text: '样式',
|
|
125
|
+
type: 'select',
|
|
126
|
+
defaultValue: 'none',
|
|
127
|
+
options: [
|
|
128
|
+
{ text: 'none', value: 'none' },
|
|
129
|
+
{ text: 'hidden', value: 'hidden' },
|
|
130
|
+
{ text: 'dotted', value: 'dotted' },
|
|
131
|
+
{ text: 'dashed', value: 'dashed' },
|
|
132
|
+
{ text: 'solid', value: 'solid' },
|
|
133
|
+
{ text: 'double', value: 'double' },
|
|
134
|
+
{ text: 'groove', value: 'groove' },
|
|
135
|
+
{ text: 'ridge', value: 'ridge' },
|
|
136
|
+
{ text: 'inset', value: 'inset' },
|
|
137
|
+
{ text: 'outset', value: 'outset' },
|
|
138
|
+
],
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
},
|
|
108
142
|
{
|
|
109
143
|
type: 'fieldset',
|
|
110
144
|
legend: '背景',
|
package/types/index.d.ts
CHANGED
|
@@ -30,6 +30,7 @@ export { default as ContentMenu } from './components/ContentMenu.vue';
|
|
|
30
30
|
export { default as Icon } from './components/Icon.vue';
|
|
31
31
|
export { default as LayoutContainer } from './components/SplitView.vue';
|
|
32
32
|
export { default as SplitView } from './components/SplitView.vue';
|
|
33
|
+
export { default as Resizer } from './components/Resizer.vue';
|
|
33
34
|
declare const _default: {
|
|
34
35
|
install: (app: App, opt?: Partial<InstallOptions>) => void;
|
|
35
36
|
};
|