@tmagic/stage 1.0.0-beta.5 → 1.0.0-beta.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/LICENSE +5432 -0
- package/dist/tmagic-stage.es.js +466 -17569
- package/dist/tmagic-stage.es.js.map +1 -1
- package/dist/tmagic-stage.umd.js +470 -17574
- package/dist/tmagic-stage.umd.js.map +1 -1
- package/dist/types/src/Rule.d.ts +32 -0
- package/dist/types/src/StageCore.d.ts +7 -6
- package/dist/types/src/StageDragResize.d.ts +14 -11
- package/dist/types/src/StageMask.d.ts +18 -36
- package/dist/types/src/StageRender.d.ts +1 -0
- package/dist/types/src/const.d.ts +17 -0
- package/dist/types/src/types.d.ts +5 -9
- package/dist/types/src/util.d.ts +7 -5
- package/package.json +6 -5
- package/src/Rule.ts +150 -0
- package/src/StageCore.ts +76 -89
- package/src/StageDragResize.ts +150 -168
- package/src/StageMask.ts +125 -166
- package/src/StageRender.ts +12 -9
- package/src/const.ts +21 -0
- package/src/types.ts +23 -28
- package/src/util.ts +43 -7
package/src/StageMask.ts
CHANGED
|
@@ -16,15 +16,11 @@
|
|
|
16
16
|
* limitations under the License.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import {
|
|
20
|
-
|
|
21
|
-
import Guides from '@scena/guides';
|
|
22
|
-
import { isNumber } from 'lodash';
|
|
23
|
-
|
|
24
|
-
import { GHOST_EL_ID_PREFIX } from './const';
|
|
19
|
+
import { Mode, MouseButton, ZIndex } from './const';
|
|
20
|
+
import Rule from './Rule';
|
|
25
21
|
import type StageCore from './StageCore';
|
|
26
|
-
import type {
|
|
27
|
-
import {
|
|
22
|
+
import type { StageMaskConfig } from './types';
|
|
23
|
+
import { createDiv, getScrollParent, isFixedParent } from './util';
|
|
28
24
|
|
|
29
25
|
const wrapperClassName = 'editor-mask-wrapper';
|
|
30
26
|
|
|
@@ -36,30 +32,30 @@ const hideScrollbar = () => {
|
|
|
36
32
|
globalThis.document.head.appendChild(style);
|
|
37
33
|
};
|
|
38
34
|
|
|
39
|
-
const createContent = (): HTMLDivElement =>
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
35
|
+
const createContent = (): HTMLDivElement =>
|
|
36
|
+
createDiv({
|
|
37
|
+
className: 'editor-mask',
|
|
38
|
+
cssText: `
|
|
43
39
|
position: absolute;
|
|
44
40
|
top: 0;
|
|
45
41
|
left: 0;
|
|
46
42
|
transform: translate3d(0, 0, 0);
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
};
|
|
43
|
+
`,
|
|
44
|
+
});
|
|
50
45
|
|
|
51
46
|
const createWrapper = (): HTMLDivElement => {
|
|
52
|
-
const el =
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
47
|
+
const el = createDiv({
|
|
48
|
+
className: wrapperClassName,
|
|
49
|
+
cssText: `
|
|
50
|
+
position: absolute;
|
|
51
|
+
top: 0;
|
|
52
|
+
left: 0;
|
|
53
|
+
height: 100%;
|
|
54
|
+
width: 100%;
|
|
55
|
+
overflow: hidden;
|
|
56
|
+
z-index: ${ZIndex.MASK};
|
|
57
|
+
`,
|
|
58
|
+
});
|
|
63
59
|
|
|
64
60
|
hideScrollbar();
|
|
65
61
|
|
|
@@ -70,54 +66,45 @@ const createWrapper = (): HTMLDivElement => {
|
|
|
70
66
|
* 蒙层
|
|
71
67
|
* @description 用于拦截页面的点击动作,避免点击时触发组件自身动作;在编辑器中点击组件应当是选中组件;
|
|
72
68
|
*/
|
|
73
|
-
export default class StageMask extends
|
|
69
|
+
export default class StageMask extends Rule {
|
|
74
70
|
public content: HTMLDivElement = createContent();
|
|
75
|
-
public wrapper: HTMLDivElement
|
|
71
|
+
public wrapper: HTMLDivElement;
|
|
76
72
|
public core: StageCore;
|
|
77
73
|
public page: HTMLElement | null = null;
|
|
78
|
-
|
|
79
|
-
public
|
|
80
|
-
public
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
74
|
+
public pageScrollParent: HTMLElement | null = null;
|
|
75
|
+
public scrollTop = 0;
|
|
76
|
+
public scrollLeft = 0;
|
|
77
|
+
public width = 0;
|
|
78
|
+
public height = 0;
|
|
79
|
+
public wrapperHeight = 0;
|
|
80
|
+
public wrapperWidth = 0;
|
|
81
|
+
|
|
82
|
+
private mode: Mode = Mode.ABSOLUTE;
|
|
83
|
+
private pageResizeObserver: ResizeObserver | null = null;
|
|
84
|
+
private wrapperResizeObserver: ResizeObserver | null = null;
|
|
86
85
|
|
|
87
86
|
constructor(config: StageMaskConfig) {
|
|
88
|
-
|
|
87
|
+
const wrapper = createWrapper();
|
|
88
|
+
super(wrapper);
|
|
89
89
|
|
|
90
|
+
this.wrapper = wrapper;
|
|
90
91
|
this.core = config.core;
|
|
91
|
-
const { config: coreConfig } = config.core;
|
|
92
92
|
|
|
93
|
-
this.
|
|
94
|
-
this.content.addEventListener('mousedown', this.mouseDownHandler, true);
|
|
95
|
-
this.content.addEventListener('contextmenu', this.contextmenuHandler, true);
|
|
93
|
+
this.content.addEventListener('mousedown', this.mouseDownHandler);
|
|
96
94
|
this.wrapper.appendChild(this.content);
|
|
97
|
-
|
|
98
|
-
this.hGuides = this.createGuides('horizontal');
|
|
99
|
-
this.vGuides = this.createGuides('vertical');
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* 设置成固定定位模式
|
|
104
|
-
*/
|
|
105
|
-
public setFixed(): void {
|
|
106
|
-
this.wrapper.scrollTo({
|
|
107
|
-
top: 0,
|
|
108
|
-
});
|
|
109
|
-
this.wrapper.style.overflow = 'hidden';
|
|
110
|
-
// 要等滚动条滚上去,才刷新选中框
|
|
111
|
-
setTimeout(() => {
|
|
112
|
-
this.core.dr.refresh();
|
|
113
|
-
});
|
|
95
|
+
this.content.addEventListener('wheel', this.mouseWheelHandler);
|
|
114
96
|
}
|
|
115
97
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
98
|
+
public setMode(mode: Mode) {
|
|
99
|
+
this.mode = mode;
|
|
100
|
+
this.scroll();
|
|
101
|
+
if (mode === Mode.FIXED) {
|
|
102
|
+
this.content.style.width = `${this.wrapperWidth}px`;
|
|
103
|
+
this.content.style.height = `${this.wrapperHeight}px`;
|
|
104
|
+
} else {
|
|
105
|
+
this.content.style.width = `${this.width}px`;
|
|
106
|
+
this.content.style.height = `${this.height}px`;
|
|
107
|
+
}
|
|
121
108
|
}
|
|
122
109
|
|
|
123
110
|
/**
|
|
@@ -129,17 +116,26 @@ export default class StageMask extends EventEmitter {
|
|
|
129
116
|
if (!page) return;
|
|
130
117
|
|
|
131
118
|
this.page = page;
|
|
132
|
-
this.
|
|
119
|
+
this.pageScrollParent = getScrollParent(page) || this.core.renderer.contentWindow?.document.documentElement || null;
|
|
120
|
+
this.pageResizeObserver?.disconnect();
|
|
133
121
|
|
|
134
122
|
if (typeof ResizeObserver !== 'undefined') {
|
|
135
|
-
this.
|
|
123
|
+
this.pageResizeObserver = new ResizeObserver((entries) => {
|
|
136
124
|
const [entry] = entries;
|
|
137
125
|
const { clientHeight, clientWidth } = entry.target;
|
|
138
126
|
this.setHeight(clientHeight);
|
|
139
127
|
this.setWidth(clientWidth);
|
|
140
128
|
});
|
|
141
129
|
|
|
142
|
-
this.
|
|
130
|
+
this.pageResizeObserver.observe(page);
|
|
131
|
+
|
|
132
|
+
this.wrapperResizeObserver = new ResizeObserver((entries) => {
|
|
133
|
+
const [entry] = entries;
|
|
134
|
+
const { clientHeight, clientWidth } = entry.target;
|
|
135
|
+
this.wrapperHeight = clientHeight;
|
|
136
|
+
this.wrapperWidth = clientWidth;
|
|
137
|
+
});
|
|
138
|
+
this.wrapperResizeObserver.observe(this.wrapper);
|
|
143
139
|
}
|
|
144
140
|
}
|
|
145
141
|
|
|
@@ -151,12 +147,10 @@ export default class StageMask extends EventEmitter {
|
|
|
151
147
|
if (!this.content) throw new Error('content 不存在');
|
|
152
148
|
|
|
153
149
|
el.appendChild(this.wrapper);
|
|
150
|
+
}
|
|
154
151
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
this.hGuides.resize();
|
|
158
|
-
});
|
|
159
|
-
this.parentResizeObserver.observe(el);
|
|
152
|
+
public setLayout(el: HTMLElement): void {
|
|
153
|
+
this.setMode(isFixedParent(el) ? Mode.FIXED : Mode.ABSOLUTE);
|
|
160
154
|
}
|
|
161
155
|
|
|
162
156
|
/**
|
|
@@ -165,69 +159,44 @@ export default class StageMask extends EventEmitter {
|
|
|
165
159
|
public destroy(): void {
|
|
166
160
|
this.content?.remove();
|
|
167
161
|
this.page = null;
|
|
168
|
-
this.
|
|
169
|
-
this.
|
|
170
|
-
this.
|
|
162
|
+
this.pageScrollParent = null;
|
|
163
|
+
this.pageResizeObserver?.disconnect();
|
|
164
|
+
this.wrapperResizeObserver?.disconnect();
|
|
165
|
+
super.destroy();
|
|
171
166
|
}
|
|
172
167
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
* @param show 是否显示
|
|
176
|
-
*/
|
|
177
|
-
public showGuides(show = true) {
|
|
178
|
-
this.hGuides.setState({
|
|
179
|
-
showGuides: show,
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
this.vGuides.setState({
|
|
183
|
-
showGuides: show,
|
|
184
|
-
});
|
|
185
|
-
}
|
|
168
|
+
private scroll() {
|
|
169
|
+
let { scrollLeft, scrollTop } = this;
|
|
186
170
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
this.
|
|
193
|
-
|
|
194
|
-
visibility: show ? '' : 'hidden',
|
|
195
|
-
},
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
this.vGuides.setState({
|
|
199
|
-
rulerStyle: {
|
|
200
|
-
visibility: show ? '' : 'hidden',
|
|
201
|
-
},
|
|
202
|
-
});
|
|
171
|
+
if (this.mode === Mode.FIXED) {
|
|
172
|
+
scrollLeft = 0;
|
|
173
|
+
scrollTop = 0;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
this.scrollRule(scrollTop);
|
|
177
|
+
this.scrollTo(scrollLeft, scrollTop);
|
|
203
178
|
}
|
|
204
179
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
*/
|
|
208
|
-
public clearGuides() {
|
|
209
|
-
this.vGuides.setState({
|
|
210
|
-
defaultGuides: [],
|
|
211
|
-
});
|
|
212
|
-
this.hGuides.setState({
|
|
213
|
-
defaultGuides: [],
|
|
214
|
-
});
|
|
180
|
+
private scrollTo(scrollLeft: number, scrollTop: number): void {
|
|
181
|
+
this.content.style.transform = `translate3d(${-scrollLeft}px, ${-scrollTop}px, 0)`;
|
|
215
182
|
}
|
|
216
183
|
|
|
217
184
|
/**
|
|
218
185
|
* 设置蒙层高度
|
|
219
186
|
* @param height 高度
|
|
220
187
|
*/
|
|
221
|
-
private setHeight(height: number
|
|
222
|
-
this.
|
|
188
|
+
private setHeight(height: number): void {
|
|
189
|
+
this.height = height;
|
|
190
|
+
this.content.style.height = `${height}px`;
|
|
223
191
|
}
|
|
224
192
|
|
|
225
193
|
/**
|
|
226
194
|
* 设置蒙层宽度
|
|
227
195
|
* @param width 宽度
|
|
228
196
|
*/
|
|
229
|
-
private setWidth(width: number
|
|
230
|
-
this.
|
|
197
|
+
private setWidth(width: number): void {
|
|
198
|
+
this.width = width;
|
|
199
|
+
this.content.style.width = `${width}px`;
|
|
231
200
|
}
|
|
232
201
|
|
|
233
202
|
/**
|
|
@@ -235,74 +204,64 @@ export default class StageMask extends EventEmitter {
|
|
|
235
204
|
* @param event 事件对象
|
|
236
205
|
*/
|
|
237
206
|
private mouseDownHandler = async (event: MouseEvent): Promise<void> => {
|
|
238
|
-
|
|
207
|
+
event.stopImmediatePropagation();
|
|
208
|
+
event.stopPropagation();
|
|
209
|
+
|
|
210
|
+
if (event.button !== MouseButton.LEFT && event.button !== MouseButton.RIGHT) return;
|
|
239
211
|
|
|
240
212
|
// 点击的对象如果是选中框,则不需要再触发选中了,而可能是拖动行为
|
|
241
213
|
if ((event.target as HTMLDivElement).className.indexOf('moveable-control') !== -1) {
|
|
242
214
|
return;
|
|
243
215
|
}
|
|
244
216
|
|
|
245
|
-
this.
|
|
217
|
+
this.emit('beforeSelect', event);
|
|
218
|
+
|
|
219
|
+
// 如果是右键点击,这里的mouseup事件监听没有效果
|
|
220
|
+
globalThis.document.addEventListener('mouseup', this.mouseUpHandler);
|
|
246
221
|
};
|
|
247
222
|
|
|
248
223
|
private mouseUpHandler = (): void => {
|
|
249
|
-
|
|
250
|
-
this.emit('
|
|
251
|
-
this.target = null;
|
|
224
|
+
globalThis.document.removeEventListener('mouseup', this.mouseUpHandler);
|
|
225
|
+
this.emit('select');
|
|
252
226
|
};
|
|
253
227
|
|
|
254
|
-
private
|
|
255
|
-
|
|
256
|
-
this.mouseUpHandler();
|
|
257
|
-
};
|
|
228
|
+
private mouseWheelHandler = (event: WheelEvent) => {
|
|
229
|
+
if (!this.page) throw new Error('page 未初始化');
|
|
258
230
|
|
|
259
|
-
|
|
260
|
-
const {
|
|
231
|
+
const { deltaY, deltaX } = event;
|
|
232
|
+
const { height, wrapperHeight, width, wrapperWidth } = this;
|
|
261
233
|
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
let y = event.clientY;
|
|
234
|
+
const maxScrollTop = height - wrapperHeight;
|
|
235
|
+
const maxScrollLeft = width - wrapperWidth;
|
|
265
236
|
|
|
266
|
-
if (
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
237
|
+
if (maxScrollTop > 0) {
|
|
238
|
+
if (deltaY > 0) {
|
|
239
|
+
this.scrollTop = this.scrollTop + Math.min(maxScrollTop - this.scrollTop, deltaY);
|
|
240
|
+
} else {
|
|
241
|
+
this.scrollTop = Math.max(this.scrollTop + deltaY, 0);
|
|
271
242
|
}
|
|
272
243
|
}
|
|
273
244
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && (await this.canSelect(el, stop))) {
|
|
280
|
-
if (stopped) break;
|
|
281
|
-
|
|
282
|
-
this.emit('select', el, event);
|
|
283
|
-
this.target = el;
|
|
284
|
-
// 如果是右键点击,这里的mouseup事件监听没有效果
|
|
285
|
-
this.content?.addEventListener('mouseup', this.mouseUpHandler, true);
|
|
286
|
-
break;
|
|
245
|
+
if (width > wrapperWidth) {
|
|
246
|
+
if (deltaX > 0) {
|
|
247
|
+
this.scrollLeft = this.scrollLeft + Math.min(maxScrollLeft - this.scrollLeft, deltaX);
|
|
248
|
+
} else {
|
|
249
|
+
this.scrollLeft = Math.max(this.scrollLeft + deltaX, 0);
|
|
287
250
|
}
|
|
288
251
|
}
|
|
289
|
-
}
|
|
290
252
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
top: type === 'horizontal' ? '-30px' : 0,
|
|
295
|
-
width: type === 'horizontal' ? '100%' : '30px',
|
|
296
|
-
height: type === 'horizontal' ? '30px' : '100%',
|
|
297
|
-
});
|
|
253
|
+
if (this.mode !== Mode.FIXED) {
|
|
254
|
+
this.scrollTo(this.scrollLeft, this.scrollTop);
|
|
255
|
+
}
|
|
298
256
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
257
|
+
if (this.pageScrollParent) {
|
|
258
|
+
this.pageScrollParent.scrollTo({
|
|
259
|
+
top: this.scrollTop,
|
|
260
|
+
left: this.scrollLeft,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
this.scroll();
|
|
264
|
+
|
|
265
|
+
this.emit('scroll', event);
|
|
266
|
+
};
|
|
308
267
|
}
|
package/src/StageRender.ts
CHANGED
|
@@ -52,15 +52,7 @@ export default class StageRender extends EventEmitter {
|
|
|
52
52
|
height: 100%;
|
|
53
53
|
`;
|
|
54
54
|
|
|
55
|
-
this.iframe.
|
|
56
|
-
this.emit('onload');
|
|
57
|
-
if (this.render) {
|
|
58
|
-
const el = await this.render(this.core);
|
|
59
|
-
if (el) {
|
|
60
|
-
this.iframe?.contentDocument?.body?.appendChild(el);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
};
|
|
55
|
+
this.iframe.addEventListener('load', this.loadHandler);
|
|
64
56
|
}
|
|
65
57
|
|
|
66
58
|
public getMagicApi = () => ({
|
|
@@ -113,9 +105,20 @@ export default class StageRender extends EventEmitter {
|
|
|
113
105
|
* 销毁实例
|
|
114
106
|
*/
|
|
115
107
|
public destroy(): void {
|
|
108
|
+
this.iframe?.removeEventListener('load', this.loadHandler);
|
|
116
109
|
this.contentWindow = null;
|
|
117
110
|
this.iframe?.remove();
|
|
118
111
|
this.iframe = undefined;
|
|
119
112
|
this.removeAllListeners();
|
|
120
113
|
}
|
|
114
|
+
|
|
115
|
+
private loadHandler = async () => {
|
|
116
|
+
this.emit('onload');
|
|
117
|
+
if (this.render) {
|
|
118
|
+
const el = await this.render(this.core);
|
|
119
|
+
if (el) {
|
|
120
|
+
this.iframe?.contentDocument?.body?.appendChild(el);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
};
|
|
121
124
|
}
|
package/src/const.ts
CHANGED
|
@@ -21,3 +21,24 @@ export const GHOST_EL_ID_PREFIX = 'ghost_el_';
|
|
|
21
21
|
|
|
22
22
|
// 默认放到缩小倍数
|
|
23
23
|
export const DEFAULT_ZOOM = 1;
|
|
24
|
+
|
|
25
|
+
export enum GuidesType {
|
|
26
|
+
HORIZONTAL = 'horizontal',
|
|
27
|
+
VERTICAL = 'vertical',
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export enum ZIndex {
|
|
31
|
+
MASK = '99999',
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export enum MouseButton {
|
|
35
|
+
LEFT = 0,
|
|
36
|
+
MIDDLE = 1,
|
|
37
|
+
RIGHT = 2,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export enum Mode {
|
|
41
|
+
ABSOLUTE = 'absolute',
|
|
42
|
+
FIXED = 'fixed',
|
|
43
|
+
SORTABLE = 'sortable',
|
|
44
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -1,7 +1,26 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
|
3
|
+
*
|
|
4
|
+
* Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/
|
|
18
|
+
|
|
1
19
|
import { MoveableOptions } from 'react-moveable/declaration/types';
|
|
2
20
|
|
|
3
21
|
import { Id, MApp, MNode } from '@tmagic/schema';
|
|
4
22
|
|
|
23
|
+
import { GuidesType } from './const';
|
|
5
24
|
import StageCore from './StageCore';
|
|
6
25
|
|
|
7
26
|
export type CanSelect = (el: HTMLElement, stop: () => boolean) => boolean | Promise<boolean>;
|
|
@@ -41,23 +60,10 @@ export interface Offset {
|
|
|
41
60
|
top: number;
|
|
42
61
|
}
|
|
43
62
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
*
|
|
49
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
50
|
-
* you may not use this file except in compliance with the License.
|
|
51
|
-
* You may obtain a copy of the License at
|
|
52
|
-
*
|
|
53
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
54
|
-
*
|
|
55
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
56
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
57
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
58
|
-
* See the License for the specific language governing permissions and
|
|
59
|
-
* limitations under the License.
|
|
60
|
-
*/
|
|
63
|
+
export interface GuidesEventData {
|
|
64
|
+
type: GuidesType;
|
|
65
|
+
guides: number[];
|
|
66
|
+
}
|
|
61
67
|
|
|
62
68
|
export interface UpdateEventData {
|
|
63
69
|
el: HTMLElement;
|
|
@@ -108,14 +114,3 @@ export interface Magic {
|
|
|
108
114
|
export interface RuntimeWindow extends Window {
|
|
109
115
|
magic: Magic;
|
|
110
116
|
}
|
|
111
|
-
|
|
112
|
-
export enum ZIndex {
|
|
113
|
-
MASK = '99999',
|
|
114
|
-
GHOST_EL = '99998',
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export enum MouseButton {
|
|
118
|
-
LEFT = 0,
|
|
119
|
-
MIDDLE = 1,
|
|
120
|
-
RIGHT = 2,
|
|
121
|
-
}
|
package/src/util.ts
CHANGED
|
@@ -16,14 +16,9 @@
|
|
|
16
16
|
* limitations under the License.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
+
import { Mode } from './const';
|
|
19
20
|
import type { Offset } from './types';
|
|
20
21
|
|
|
21
|
-
export enum Mode {
|
|
22
|
-
ABSOLUTE = 'absolute',
|
|
23
|
-
FIXED = 'fixed',
|
|
24
|
-
SORTABLE = 'sortable',
|
|
25
|
-
}
|
|
26
|
-
|
|
27
22
|
export const getOffset = (el: HTMLElement): Offset => {
|
|
28
23
|
const { transform } = getComputedStyle(el);
|
|
29
24
|
const { offsetParent } = el;
|
|
@@ -113,8 +108,49 @@ export const isFixed = (el?: HTMLElement): boolean => {
|
|
|
113
108
|
return getComputedStyle(el).position === 'fixed';
|
|
114
109
|
};
|
|
115
110
|
|
|
111
|
+
export const isFixedParent = (el: HTMLElement) => {
|
|
112
|
+
let fixed = false;
|
|
113
|
+
let dom = el;
|
|
114
|
+
while (dom) {
|
|
115
|
+
fixed = isFixed(dom);
|
|
116
|
+
if (fixed) {
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
const { parentElement } = dom;
|
|
120
|
+
if (!parentElement || parentElement.tagName === 'BODY') {
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
dom = parentElement;
|
|
124
|
+
}
|
|
125
|
+
return fixed;
|
|
126
|
+
};
|
|
127
|
+
|
|
116
128
|
export const getMode = (el: HTMLElement): Mode => {
|
|
117
|
-
if (
|
|
129
|
+
if (isFixedParent(el)) return Mode.FIXED;
|
|
118
130
|
if (isStatic(el) || isRelative(el)) return Mode.SORTABLE;
|
|
119
131
|
return Mode.ABSOLUTE;
|
|
120
132
|
};
|
|
133
|
+
|
|
134
|
+
export const getScrollParent = (element: HTMLElement, includeHidden = false): HTMLElement | null => {
|
|
135
|
+
let style = getComputedStyle(element);
|
|
136
|
+
const overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/;
|
|
137
|
+
|
|
138
|
+
if (isFixed(element)) return null;
|
|
139
|
+
for (let parent = element; parent.parentElement; ) {
|
|
140
|
+
parent = parent.parentElement;
|
|
141
|
+
style = getComputedStyle(parent);
|
|
142
|
+
if (isAbsolute(element) && isStatic(element)) {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) return parent;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return null;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
export const createDiv = ({ className, cssText }: { className: string; cssText: string }) => {
|
|
152
|
+
const el = globalThis.document.createElement('div');
|
|
153
|
+
el.className = className;
|
|
154
|
+
el.style.cssText = cssText;
|
|
155
|
+
return el;
|
|
156
|
+
};
|