@tmagic/editor 1.4.7 → 1.4.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.
Files changed (152) hide show
  1. package/dist/style.css +1 -1
  2. package/dist/tmagic-editor.js +314 -452
  3. package/dist/tmagic-editor.umd.cjs +313 -450
  4. package/package.json +15 -11
  5. package/types/layouts/sidebar/layer/use-click.d.ts +1 -1
  6. package/types/services/editor.d.ts +19 -2
  7. package/types/services/props.d.ts +5 -5
  8. package/types/type.d.ts +6 -0
  9. package/types/utils/editor.d.ts +1 -0
  10. package/src/Editor.vue +0 -211
  11. package/src/components/CodeBlockEditor.vue +0 -268
  12. package/src/components/CodeParams.vue +0 -60
  13. package/src/components/ContentMenu.vue +0 -193
  14. package/src/components/FloatingBox.vue +0 -178
  15. package/src/components/Icon.vue +0 -27
  16. package/src/components/Resizer.vue +0 -23
  17. package/src/components/ScrollBar.vue +0 -151
  18. package/src/components/ScrollViewer.vue +0 -128
  19. package/src/components/SearchInput.vue +0 -37
  20. package/src/components/SplitView.vue +0 -186
  21. package/src/components/ToolButton.vue +0 -138
  22. package/src/components/Tree.vue +0 -71
  23. package/src/components/TreeNode.vue +0 -150
  24. package/src/editorProps.ts +0 -117
  25. package/src/fields/Code.vue +0 -50
  26. package/src/fields/CodeLink.vue +0 -80
  27. package/src/fields/CodeSelect.vue +0 -132
  28. package/src/fields/CodeSelectCol.vue +0 -139
  29. package/src/fields/DataSourceFieldSelect.vue +0 -149
  30. package/src/fields/DataSourceFields.vue +0 -323
  31. package/src/fields/DataSourceInput.vue +0 -331
  32. package/src/fields/DataSourceMethodSelect.vue +0 -153
  33. package/src/fields/DataSourceMethods.vue +0 -104
  34. package/src/fields/DataSourceMocks.vue +0 -255
  35. package/src/fields/DataSourceSelect.vue +0 -98
  36. package/src/fields/EventSelect.vue +0 -375
  37. package/src/fields/KeyValue.vue +0 -137
  38. package/src/fields/PageFragmentSelect.vue +0 -63
  39. package/src/fields/UISelect.vue +0 -135
  40. package/src/hooks/index.ts +0 -24
  41. package/src/hooks/use-code-block-edit.ts +0 -83
  42. package/src/hooks/use-data-source-edit.ts +0 -46
  43. package/src/hooks/use-data-source-method.ts +0 -100
  44. package/src/hooks/use-editor-content-height.ts +0 -26
  45. package/src/hooks/use-filter.ts +0 -55
  46. package/src/hooks/use-float-box.ts +0 -76
  47. package/src/hooks/use-getso.ts +0 -35
  48. package/src/hooks/use-next-float-box-position.ts +0 -29
  49. package/src/hooks/use-node-status.ts +0 -48
  50. package/src/hooks/use-stage.ts +0 -129
  51. package/src/hooks/use-window-rect.ts +0 -20
  52. package/src/icons/AppManageIcon.vue +0 -15
  53. package/src/icons/CenterIcon.vue +0 -13
  54. package/src/icons/CodeIcon.vue +0 -28
  55. package/src/icons/FolderMinusIcon.vue +0 -22
  56. package/src/icons/PinIcon.vue +0 -25
  57. package/src/icons/PinnedIcon.vue +0 -25
  58. package/src/index.ts +0 -118
  59. package/src/initService.ts +0 -443
  60. package/src/layouts/AddPageBox.vue +0 -55
  61. package/src/layouts/CodeEditor.vue +0 -226
  62. package/src/layouts/Framework.vue +0 -163
  63. package/src/layouts/NavMenu.vue +0 -200
  64. package/src/layouts/PropsPanel.vue +0 -130
  65. package/src/layouts/page-bar/AddButton.vue +0 -48
  66. package/src/layouts/page-bar/PageBar.vue +0 -159
  67. package/src/layouts/page-bar/PageBarScrollContainer.vue +0 -156
  68. package/src/layouts/page-bar/SwitchTypeButton.vue +0 -45
  69. package/src/layouts/sidebar/ComponentListPanel.vue +0 -134
  70. package/src/layouts/sidebar/Sidebar.vue +0 -278
  71. package/src/layouts/sidebar/code-block/CodeBlockList.vue +0 -160
  72. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +0 -70
  73. package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +0 -84
  74. package/src/layouts/sidebar/data-source/DataSourceList.vue +0 -172
  75. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +0 -106
  76. package/src/layouts/sidebar/layer/LayerMenu.vue +0 -128
  77. package/src/layouts/sidebar/layer/LayerNodeTool.vue +0 -32
  78. package/src/layouts/sidebar/layer/LayerPanel.vue +0 -119
  79. package/src/layouts/sidebar/layer/use-click.ts +0 -110
  80. package/src/layouts/sidebar/layer/use-drag.ts +0 -161
  81. package/src/layouts/sidebar/layer/use-keybinding.ts +0 -54
  82. package/src/layouts/sidebar/layer/use-node-status.ts +0 -114
  83. package/src/layouts/workspace/Breadcrumb.vue +0 -35
  84. package/src/layouts/workspace/Workspace.vue +0 -46
  85. package/src/layouts/workspace/viewer/NodeListMenu.vue +0 -115
  86. package/src/layouts/workspace/viewer/Stage.vue +0 -246
  87. package/src/layouts/workspace/viewer/StageOverlay.vue +0 -68
  88. package/src/layouts/workspace/viewer/ViewerMenu.vue +0 -145
  89. package/src/services/BaseService.ts +0 -230
  90. package/src/services/codeBlock.ts +0 -327
  91. package/src/services/componentList.ts +0 -58
  92. package/src/services/dataSource.ts +0 -216
  93. package/src/services/dep.ts +0 -152
  94. package/src/services/editor.ts +0 -1096
  95. package/src/services/events.ts +0 -93
  96. package/src/services/history.ts +0 -126
  97. package/src/services/keybinding.ts +0 -220
  98. package/src/services/props.ts +0 -271
  99. package/src/services/stageOverlay.ts +0 -212
  100. package/src/services/storage.ts +0 -155
  101. package/src/services/ui.ts +0 -156
  102. package/src/shims-vue.d.ts +0 -6
  103. package/src/theme/breadcrumb.scss +0 -6
  104. package/src/theme/code-block.scss +0 -6
  105. package/src/theme/code-editor.scss +0 -38
  106. package/src/theme/common/var.scss +0 -14
  107. package/src/theme/component-list-panel.scss +0 -95
  108. package/src/theme/content-menu.scss +0 -76
  109. package/src/theme/data-source-field.scss +0 -12
  110. package/src/theme/data-source-fields.scss +0 -13
  111. package/src/theme/data-source-input.scss +0 -18
  112. package/src/theme/data-source-methods.scss +0 -13
  113. package/src/theme/data-source.scss +0 -28
  114. package/src/theme/event.scss +0 -37
  115. package/src/theme/floating-box.scss +0 -32
  116. package/src/theme/framework.scss +0 -69
  117. package/src/theme/icon.scss +0 -12
  118. package/src/theme/index.scss +0 -10
  119. package/src/theme/key-value.scss +0 -20
  120. package/src/theme/layer-panel.scss +0 -26
  121. package/src/theme/layout.scss +0 -9
  122. package/src/theme/nav-menu.scss +0 -78
  123. package/src/theme/page-bar.scss +0 -89
  124. package/src/theme/page-fragment-select.scss +0 -14
  125. package/src/theme/props-panel.scss +0 -55
  126. package/src/theme/resizer.scss +0 -66
  127. package/src/theme/ruler.scss +0 -38
  128. package/src/theme/search-input.scss +0 -14
  129. package/src/theme/sidebar.scss +0 -79
  130. package/src/theme/stage.scss +0 -76
  131. package/src/theme/theme.scss +0 -27
  132. package/src/theme/tree.scss +0 -89
  133. package/src/theme/workspace.scss +0 -9
  134. package/src/type.ts +0 -746
  135. package/src/utils/compose.ts +0 -52
  136. package/src/utils/config.ts +0 -29
  137. package/src/utils/content-menu.ts +0 -95
  138. package/src/utils/data-source/formConfigs/base.ts +0 -30
  139. package/src/utils/data-source/formConfigs/http.ts +0 -60
  140. package/src/utils/data-source/index.ts +0 -243
  141. package/src/utils/editor.ts +0 -294
  142. package/src/utils/idle-task.ts +0 -72
  143. package/src/utils/index.ts +0 -24
  144. package/src/utils/keybinding-config.ts +0 -125
  145. package/src/utils/logger.ts +0 -47
  146. package/src/utils/monaco-editor.ts +0 -8
  147. package/src/utils/operator.ts +0 -106
  148. package/src/utils/props.ts +0 -504
  149. package/src/utils/scroll-viewer.ts +0 -165
  150. package/src/utils/tree.ts +0 -15
  151. package/src/utils/undo-redo.ts +0 -76
  152. package/tsconfig.build.json +0 -16
@@ -1,60 +0,0 @@
1
- <template>
2
- <MForm
3
- ref="form"
4
- :config="codeParamsConfig"
5
- :init-values="model"
6
- :disabled="disabled"
7
- :size="size"
8
- :watch-props="false"
9
- @change="onParamsChangeHandler"
10
- ></MForm>
11
- </template>
12
-
13
- <script lang="ts" setup>
14
- import { computed, ref } from 'vue';
15
-
16
- import { FormConfig, MForm } from '@tmagic/form';
17
-
18
- import type { CodeParamStatement } from '@editor/type';
19
- import { error } from '@editor/utils';
20
-
21
- defineOptions({
22
- name: 'MEditorCodeParams',
23
- });
24
-
25
- const props = defineProps<{
26
- model: any;
27
- size?: 'small' | 'default' | 'large';
28
- disabled?: boolean;
29
- name: string;
30
- paramsConfig: CodeParamStatement[];
31
- }>();
32
-
33
- const emit = defineEmits(['change']);
34
-
35
- const form = ref<InstanceType<typeof MForm>>();
36
-
37
- const getFormConfig = (items: FormConfig = []) => [
38
- {
39
- type: 'fieldset',
40
- items,
41
- legend: '参数',
42
- labelWidth: '70px',
43
- name: props.name,
44
- },
45
- ];
46
-
47
- const codeParamsConfig = computed(() => getFormConfig(props.paramsConfig));
48
-
49
- /**
50
- * 参数值修改更新
51
- */
52
- const onParamsChangeHandler = async () => {
53
- try {
54
- const value = await form.value?.submitForm(true);
55
- emit('change', value);
56
- } catch (e) {
57
- error(e);
58
- }
59
- };
60
- </script>
@@ -1,193 +0,0 @@
1
- <template>
2
- <transition name="fade">
3
- <div
4
- v-show="visible"
5
- class="magic-editor-content-menu"
6
- ref="menu"
7
- :style="menuStyle"
8
- @mouseenter="mouseenterHandler()"
9
- >
10
- <slot name="title"></slot>
11
- <div>
12
- <ToolButton
13
- v-for="(item, index) in menuData"
14
- event-type="mouseup"
15
- ref="buttons"
16
- :class="{ active: active && item.id === active }"
17
- :data="item"
18
- :key="index"
19
- @mouseup="clickHandler"
20
- @mouseenter="showSubMenu(item, index)"
21
- ></ToolButton>
22
- </div>
23
- <teleport to="body">
24
- <content-menu
25
- v-if="subMenuData.length"
26
- class="sub-menu"
27
- ref="subMenu"
28
- :active="active"
29
- :menu-data="subMenuData"
30
- :is-sub-menu="true"
31
- @hide="hide"
32
- ></content-menu>
33
- </teleport>
34
- </div>
35
- </transition>
36
- </template>
37
-
38
- <script lang="ts" setup>
39
- import { computed, nextTick, onBeforeUnmount, onMounted, ref } from 'vue';
40
-
41
- import { MenuButton, MenuComponent } from '@editor/type';
42
-
43
- import ToolButton from './ToolButton.vue';
44
-
45
- defineOptions({
46
- name: 'MEditorContentMenu',
47
- });
48
-
49
- const props = withDefaults(
50
- defineProps<{
51
- menuData?: (MenuButton | MenuComponent)[];
52
- isSubMenu?: boolean;
53
- active?: string | number;
54
- autoHide?: boolean;
55
- }>(),
56
- {
57
- menuData: () => [],
58
- isSubMenu: false,
59
- autoHide: true,
60
- },
61
- );
62
-
63
- const emit = defineEmits<{
64
- hide: [];
65
- show: [];
66
- mouseenter: [];
67
- }>();
68
-
69
- const menu = ref<HTMLDivElement>();
70
- const buttons = ref<InstanceType<typeof ToolButton>[]>();
71
- const subMenu = ref<any>();
72
- const visible = ref(false);
73
- const subMenuData = ref<(MenuButton | MenuComponent)[]>([]);
74
-
75
- const menuPosition = ref({
76
- left: 0,
77
- top: 0,
78
- });
79
-
80
- const menuStyle = computed(() => ({
81
- top: `${menuPosition.value.top}px`,
82
- left: `${menuPosition.value.left}px`,
83
- }));
84
-
85
- const contains = (el: HTMLElement) => menu.value?.contains(el) || subMenu.value?.contains(el);
86
-
87
- const hide = () => {
88
- if (!visible.value) return;
89
-
90
- visible.value = false;
91
- subMenu.value?.hide();
92
-
93
- emit('hide');
94
- };
95
-
96
- const clickHandler = () => {
97
- if (!props.autoHide) return;
98
-
99
- hide();
100
- };
101
-
102
- const outsideClickHideHandler = (e: MouseEvent) => {
103
- if (!props.autoHide) return;
104
-
105
- const target = e.target as HTMLElement | undefined;
106
- if (!visible.value || !target) {
107
- return;
108
- }
109
- if (contains(target)) {
110
- return;
111
- }
112
- hide();
113
- };
114
-
115
- const setPosition = (e: { clientY: number; clientX: number }) => {
116
- const menuHeight = menu.value?.clientHeight || 0;
117
-
118
- let top = e.clientY;
119
- if (menuHeight + e.clientY > document.body.clientHeight) {
120
- top = document.body.clientHeight - menuHeight;
121
- }
122
-
123
- menuPosition.value = {
124
- top,
125
- left: e.clientX,
126
- };
127
- };
128
-
129
- const show = (e?: { clientY: number; clientX: number }) => {
130
- // 加settimeout是以为,如果菜单中的按钮监听的是mouseup,那么菜单显示出来时鼠标如果正好在菜单上就会马上触发按钮的mouseup
131
- setTimeout(() => {
132
- visible.value = true;
133
-
134
- nextTick(() => {
135
- e && setPosition(e);
136
-
137
- emit('show');
138
- });
139
- }, 300);
140
- };
141
-
142
- const showSubMenu = (item: MenuButton | MenuComponent, index: number) => {
143
- const menuItem = item as MenuButton;
144
- if (typeof item !== 'object') {
145
- return;
146
- }
147
-
148
- subMenuData.value = menuItem.items || [];
149
- setTimeout(() => {
150
- if (!visible.value) {
151
- return;
152
- }
153
-
154
- if (menu.value) {
155
- // 将子菜单放置在按钮右侧,与按钮齐平
156
- let y = menu.value.offsetTop;
157
- if (buttons.value?.[index].$el) {
158
- const rect = buttons.value?.[index].$el.getBoundingClientRect();
159
- y = rect.top;
160
- }
161
- subMenu.value?.show({
162
- clientX: menu.value.offsetLeft + menu.value.clientWidth,
163
- clientY: y,
164
- });
165
- }
166
- }, 0);
167
- };
168
-
169
- const mouseenterHandler = () => {
170
- emit('mouseenter');
171
- };
172
-
173
- onMounted(() => {
174
- if (props.isSubMenu) return;
175
-
176
- globalThis.addEventListener('mousedown', outsideClickHideHandler, true);
177
- });
178
-
179
- onBeforeUnmount(() => {
180
- if (props.isSubMenu) return;
181
-
182
- globalThis.removeEventListener('mousedown', outsideClickHideHandler, true);
183
- });
184
-
185
- defineExpose({
186
- menu,
187
- menuPosition,
188
- hide,
189
- show,
190
- contains,
191
- setPosition,
192
- });
193
- </script>
@@ -1,178 +0,0 @@
1
- <template>
2
- <Teleport to="body" v-if="visible">
3
- <div ref="target" class="m-editor-float-box" :style="{ ...style, zIndex: curZIndex }" @mousedown="nextZIndex">
4
- <div ref="titleEl" class="m-editor-float-box-title">
5
- <slot name="title">
6
- <span>{{ title }}</span>
7
- </slot>
8
- <div>
9
- <TMagicButton link size="small" @click="closeHandler"><MIcon :icon="Close"></MIcon></TMagicButton>
10
- </div>
11
- </div>
12
- <div class="m-editor-float-box-body" :style="{ height: `${bodyHeight}px` }">
13
- <slot name="body"></slot>
14
- </div>
15
- </div>
16
- </Teleport>
17
- </template>
18
-
19
- <script setup lang="ts">
20
- import { computed, inject, nextTick, onBeforeUnmount, provide, ref, watch } from 'vue';
21
- import { Close } from '@element-plus/icons-vue';
22
- import VanillaMoveable from 'moveable';
23
-
24
- import { TMagicButton, useZIndex } from '@tmagic/design';
25
-
26
- import MIcon from '@editor/components/Icon.vue';
27
- import type { Services } from '@editor/type';
28
-
29
- interface Position {
30
- left: number;
31
- top: number;
32
- }
33
-
34
- const width = defineModel<number>('width', { default: 0 });
35
- const height = defineModel<number>('height', { default: 0 });
36
- const visible = defineModel<boolean>('visible', { default: false });
37
-
38
- const props = withDefaults(
39
- defineProps<{
40
- position?: Position;
41
- title?: string;
42
- beforeClose?: (done: (cancel?: boolean) => void) => void;
43
- }>(),
44
- {
45
- title: '',
46
- position: () => ({ left: 0, top: 0 }),
47
- },
48
- );
49
-
50
- const target = ref<HTMLDivElement>();
51
- const titleEl = ref<HTMLDivElement>();
52
-
53
- const zIndex = useZIndex();
54
- const curZIndex = ref<number>(0);
55
-
56
- const titleHeight = ref(0);
57
- const bodyHeight = computed(() => {
58
- if (height.value) {
59
- return height.value - titleHeight.value;
60
- }
61
-
62
- if (target.value) {
63
- return target.value.clientHeight - titleHeight.value;
64
- }
65
-
66
- return 'auto';
67
- });
68
-
69
- const services = inject<Services>('services');
70
- const frameworkWidth = computed(() => services?.uiService.get('frameworkRect').width || 0);
71
- const style = computed(() => {
72
- let { left } = props.position;
73
- if (width.value) {
74
- left = left + width.value > frameworkWidth.value ? frameworkWidth.value - width.value : left;
75
- }
76
-
77
- return {
78
- left: `${left}px`,
79
- top: `${props.position.top}px`,
80
- width: width.value ? `${width.value}px` : 'auto',
81
- height: height.value ? `${height.value}px` : 'auto',
82
- };
83
- });
84
-
85
- let moveable: VanillaMoveable | null = null;
86
-
87
- const initMoveable = () => {
88
- moveable = new VanillaMoveable(globalThis.document.body, {
89
- className: 'm-editor-floating-box-moveable',
90
- target: target.value,
91
- draggable: true,
92
- resizable: true,
93
- edge: true,
94
- keepRatio: false,
95
- origin: false,
96
- snappable: true,
97
- dragTarget: titleEl.value,
98
- dragTargetSelf: false,
99
- linePadding: 10,
100
- controlPadding: 10,
101
- bounds: { left: 0, top: 0, right: 0, bottom: 0, position: 'css' },
102
- });
103
-
104
- moveable.on('drag', (e) => {
105
- e.target.style.transform = e.transform;
106
- });
107
-
108
- moveable.on('resize', (e) => {
109
- width.value = e.width;
110
- height.value = e.height;
111
- e.target.style.width = `${e.width}px`;
112
- e.target.style.height = `${e.height}px`;
113
- e.target.style.transform = e.drag.transform;
114
- });
115
- };
116
-
117
- const destroyMoveable = () => {
118
- moveable?.destroy();
119
- moveable = null;
120
- };
121
-
122
- watch(
123
- visible,
124
- async (visible) => {
125
- if (visible) {
126
- await nextTick();
127
- curZIndex.value = zIndex.nextZIndex();
128
-
129
- const targetRect = target.value?.getBoundingClientRect();
130
- if (targetRect) {
131
- width.value = targetRect.width;
132
- height.value = targetRect.height;
133
- initMoveable();
134
- }
135
-
136
- if (titleEl.value) {
137
- const titleRect = titleEl.value.getBoundingClientRect();
138
- titleHeight.value = titleRect.height;
139
- }
140
- } else {
141
- destroyMoveable();
142
- }
143
- },
144
- {
145
- immediate: true,
146
- },
147
- );
148
-
149
- onBeforeUnmount(() => {
150
- destroyMoveable();
151
- });
152
-
153
- const hide = (cancel?: boolean) => {
154
- if (cancel !== false) {
155
- visible.value = false;
156
- }
157
- };
158
-
159
- const closeHandler = () => {
160
- if (typeof props.beforeClose === 'function') {
161
- props.beforeClose(hide);
162
- } else {
163
- hide();
164
- }
165
- };
166
-
167
- const nextZIndex = () => {
168
- curZIndex.value = zIndex.nextZIndex();
169
- };
170
-
171
- provide('parentFloating', target);
172
-
173
- defineExpose({
174
- bodyHeight,
175
- target,
176
- titleEl,
177
- });
178
- </script>
@@ -1,27 +0,0 @@
1
- <template>
2
- <TMagicIcon v-if="!icon" class="magic-editor-icon"><Edit></Edit></TMagicIcon>
3
- <TMagicIcon
4
- v-else-if="typeof icon === 'string' && (icon.startsWith('http') || isRelativePath(icon))"
5
- class="magic-editor-icon"
6
- ><img :src="icon"
7
- /></TMagicIcon>
8
- <i v-else-if="typeof icon === 'string'" class="magic-editor-icon" :class="icon"></i>
9
- <TMagicIcon v-else class="magic-editor-icon"><component :is="toRaw(icon)"></component></TMagicIcon>
10
- </template>
11
-
12
- <script lang="ts" setup>
13
- import { toRaw } from 'vue';
14
- import { Edit } from '@element-plus/icons-vue';
15
-
16
- import { TMagicIcon } from '@tmagic/design';
17
-
18
- defineOptions({
19
- name: 'MEditorIcon',
20
- });
21
-
22
- defineProps<{
23
- icon?: any;
24
- }>();
25
-
26
- const isRelativePath = (str: string) => /^(\.|(\.\.)?\/)/.test(str);
27
- </script>
@@ -1,23 +0,0 @@
1
- <template>
2
- <span ref="target" class="m-editor-resizer" :class="{ 'm-editor-resizer-draging': isDraging }">
3
- <slot></slot>
4
- </span>
5
- </template>
6
-
7
- <script lang="ts" setup>
8
- import { ref } from 'vue';
9
- import type { OnDrag } from 'gesto';
10
-
11
- import { useGetSo } from '@editor/hooks/use-getso';
12
-
13
- defineOptions({
14
- name: 'MEditorResizer',
15
- });
16
-
17
- const emit = defineEmits<{
18
- change: [e: OnDrag];
19
- }>();
20
-
21
- const target = ref<HTMLSpanElement>();
22
- const { isDraging } = useGetSo(target, emit);
23
- </script>
@@ -1,151 +0,0 @@
1
- <template>
2
- <div ref="bar" class="m-editor-scroll-bar" :class="isHorizontal ? 'horizontal' : 'vertical'">
3
- <div ref="thumb" class="m-editor-scroll-bar-thumb" :style="thumbStyle"></div>
4
- </div>
5
- </template>
6
-
7
- <script lang="ts" setup>
8
- import { computed, onBeforeUnmount, onMounted, ref } from 'vue';
9
- import Gesto from 'gesto';
10
-
11
- defineOptions({
12
- name: 'MEditorScrollBar',
13
- });
14
-
15
- const props = defineProps<{
16
- size: number;
17
- scrollSize: number;
18
- isHorizontal?: boolean;
19
- pos: number;
20
- }>();
21
-
22
- const emit = defineEmits(['scroll']);
23
-
24
- const bar = ref<HTMLDivElement>();
25
- const thumb = ref<HTMLDivElement>();
26
-
27
- const thumbSize = computed(() => props.size * (props.size / props.scrollSize));
28
- const thumbPos = computed(() => (props.pos / props.scrollSize) * props.size);
29
-
30
- const thumbStyle = computed(() => ({
31
- [props.isHorizontal ? 'width' : 'height']: `${thumbSize.value}px`,
32
- transform: `translate${props.isHorizontal ? 'X' : 'Y'}(${thumbPos.value}px)`,
33
- }));
34
-
35
- let gesto: Gesto;
36
-
37
- onMounted(() => {
38
- if (!thumb.value) return;
39
- const thumbEl = thumb.value;
40
- gesto = new Gesto(thumbEl, {
41
- container: window,
42
- });
43
-
44
- gesto
45
- .on('dragStart', (e) => {
46
- e.inputEvent.stopPropagation();
47
- e.inputEvent.preventDefault();
48
- })
49
- .on('drag', (e) => {
50
- scrollBy(getDelta(e));
51
- });
52
-
53
- bar.value?.addEventListener('wheel', wheelHandler, false);
54
- });
55
-
56
- onBeforeUnmount(() => {
57
- if (gesto) gesto.off();
58
- bar.value?.removeEventListener('wheel', wheelHandler, false);
59
- });
60
-
61
- const wheelHandler = (e: WheelEvent) => {
62
- const delta = props.isHorizontal ? e.deltaX : e.deltaY;
63
- if (delta) {
64
- e.preventDefault();
65
- }
66
- scrollBy(delta);
67
- };
68
-
69
- const getDelta = (e: any) => {
70
- const ratio = (props.isHorizontal ? e.deltaX : e.deltaY) / props.size;
71
- return props.scrollSize * ratio;
72
- };
73
-
74
- const scrollBy = (delta: number) => {
75
- if (delta < 0) {
76
- if (props.pos <= 0) {
77
- emit('scroll', 0);
78
- } else {
79
- emit('scroll', -Math.min(-delta, props.pos));
80
- }
81
- } else {
82
- const leftPos = props.size - (thumbSize.value + thumbPos.value);
83
- if (leftPos <= 0) {
84
- emit('scroll', 0);
85
- } else {
86
- emit('scroll', Math.min(delta, leftPos));
87
- }
88
- }
89
- };
90
- </script>
91
-
92
- <style lang="scss">
93
- .m-editor-scroll-bar {
94
- position: absolute;
95
- background-color: transparent;
96
- opacity: 0.3;
97
- transition: background-color 0.2s linear, opacity 0.2s linear;
98
-
99
- .m-editor-scroll-bar-thumb {
100
- background-color: #aaa;
101
- border-radius: 6px;
102
- position: absolute;
103
- }
104
-
105
- &.horizontal {
106
- width: 100%;
107
- height: 15px;
108
- bottom: 0;
109
-
110
- .m-editor-scroll-bar-thumb {
111
- height: 6px;
112
- transition: background-color 0.2s linear, height 0.2s ease-in-out;
113
- bottom: 2px;
114
- }
115
- }
116
-
117
- &.vertical {
118
- height: 100%;
119
- width: 15px;
120
- right: 5px;
121
-
122
- .m-editor-scroll-bar-thumb {
123
- width: 6px;
124
- transition: background-color 0.2s linear, width 0.2s ease-in-out;
125
- right: 2px;
126
- }
127
- }
128
-
129
- &:hover,
130
- &:focus {
131
- background-color: #eee;
132
- opacity: 0.9;
133
-
134
- .m-editor-scroll-bar-thumb {
135
- background-color: #999;
136
- }
137
-
138
- &.horizontal {
139
- .m-editor-scroll-bar-thumb {
140
- height: 11px;
141
- }
142
- }
143
-
144
- &.vertical {
145
- .m-editor-scroll-bar-thumb {
146
- width: 11px;
147
- }
148
- }
149
- }
150
- }
151
- </style>