@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/StageCore.ts
CHANGED
|
@@ -18,16 +18,22 @@
|
|
|
18
18
|
|
|
19
19
|
import { EventEmitter } from 'events';
|
|
20
20
|
|
|
21
|
-
import { GuidesEvents } from '@scena/guides';
|
|
22
|
-
|
|
23
21
|
import { Id } from '@tmagic/schema';
|
|
24
22
|
|
|
25
|
-
import { DEFAULT_ZOOM } from './const';
|
|
23
|
+
import { DEFAULT_ZOOM, GHOST_EL_ID_PREFIX } from './const';
|
|
26
24
|
import StageDragResize from './StageDragResize';
|
|
27
25
|
import StageMask from './StageMask';
|
|
28
26
|
import StageRender from './StageRender';
|
|
29
|
-
import {
|
|
30
|
-
|
|
27
|
+
import {
|
|
28
|
+
CanSelect,
|
|
29
|
+
GuidesEventData,
|
|
30
|
+
RemoveData,
|
|
31
|
+
Runtime,
|
|
32
|
+
SortEventData,
|
|
33
|
+
StageCoreConfig,
|
|
34
|
+
UpdateData,
|
|
35
|
+
UpdateEventData,
|
|
36
|
+
} from './types';
|
|
31
37
|
|
|
32
38
|
export default class StageCore extends EventEmitter {
|
|
33
39
|
public selectedDom: Element | undefined;
|
|
@@ -37,6 +43,7 @@ export default class StageCore extends EventEmitter {
|
|
|
37
43
|
public dr: StageDragResize;
|
|
38
44
|
public config: StageCoreConfig;
|
|
39
45
|
public zoom = DEFAULT_ZOOM;
|
|
46
|
+
private canSelect: CanSelect;
|
|
40
47
|
|
|
41
48
|
constructor(config: StageCoreConfig) {
|
|
42
49
|
super();
|
|
@@ -44,6 +51,7 @@ export default class StageCore extends EventEmitter {
|
|
|
44
51
|
this.config = config;
|
|
45
52
|
|
|
46
53
|
this.setZoom(config.zoom);
|
|
54
|
+
this.canSelect = config.canSelect || ((el: HTMLElement) => !!el.id);
|
|
47
55
|
|
|
48
56
|
this.renderer = new StageRender({ core: this });
|
|
49
57
|
this.mask = new StageMask({ core: this });
|
|
@@ -52,24 +60,61 @@ export default class StageCore extends EventEmitter {
|
|
|
52
60
|
this.renderer.on('runtime-ready', (runtime: Runtime) => this.emit('runtime-ready', runtime));
|
|
53
61
|
this.renderer.on('page-el-update', (el: HTMLElement) => this.mask?.observe(el));
|
|
54
62
|
|
|
55
|
-
this.mask
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
this.mask
|
|
64
|
+
.on('beforeSelect', (event: MouseEvent) => {
|
|
65
|
+
this.setElementFromPoint(event);
|
|
66
|
+
})
|
|
67
|
+
.on('select', () => {
|
|
68
|
+
this.emit('select', this.selectedDom);
|
|
69
|
+
})
|
|
70
|
+
.on('changeGuides', (data: GuidesEventData) => {
|
|
71
|
+
this.dr.setGuidelines(data.type, data.guides);
|
|
72
|
+
this.emit('changeGuides', data);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// 要先触发select,在触发update
|
|
76
|
+
this.dr
|
|
77
|
+
.on('update', (data: UpdateEventData) => {
|
|
78
|
+
setTimeout(() => this.emit('update', data));
|
|
79
|
+
})
|
|
80
|
+
.on('sort', (data: UpdateEventData) => {
|
|
81
|
+
setTimeout(() => this.emit('sort', data));
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
public async setElementFromPoint(event: MouseEvent) {
|
|
86
|
+
const { renderer, zoom } = this;
|
|
87
|
+
|
|
88
|
+
const doc = renderer.contentWindow?.document;
|
|
89
|
+
let x = event.clientX;
|
|
90
|
+
let y = event.clientY;
|
|
63
91
|
|
|
64
|
-
|
|
65
|
-
|
|
92
|
+
if (renderer.iframe) {
|
|
93
|
+
const rect = renderer.iframe.getClientRects()[0];
|
|
94
|
+
if (rect) {
|
|
95
|
+
x = x - rect.left;
|
|
96
|
+
y = y - rect.top;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const els = doc?.elementsFromPoint(x / zoom, y / zoom) as HTMLElement[];
|
|
101
|
+
|
|
102
|
+
let stopped = false;
|
|
103
|
+
const stop = () => (stopped = true);
|
|
104
|
+
for (const el of els) {
|
|
105
|
+
if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && (await this.canSelect(el, stop))) {
|
|
106
|
+
if (stopped) break;
|
|
107
|
+
this.select(el, event);
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
66
111
|
}
|
|
67
112
|
|
|
68
113
|
/**
|
|
69
114
|
* 选中组件
|
|
70
115
|
* @param idOrEl 组件Dom节点的id属性,或者Dom节点
|
|
71
116
|
*/
|
|
72
|
-
public async select(idOrEl: Id | HTMLElement): Promise<void> {
|
|
117
|
+
public async select(idOrEl: Id | HTMLElement, event?: MouseEvent): Promise<void> {
|
|
73
118
|
let el;
|
|
74
119
|
if (typeof idOrEl === 'string' || typeof idOrEl === 'number') {
|
|
75
120
|
const runtime = await this.renderer?.getRuntime();
|
|
@@ -79,15 +124,22 @@ export default class StageCore extends EventEmitter {
|
|
|
79
124
|
el = idOrEl;
|
|
80
125
|
}
|
|
81
126
|
|
|
82
|
-
if (this.selectedDom
|
|
127
|
+
if (el === this.selectedDom) return;
|
|
83
128
|
|
|
84
|
-
await this.
|
|
129
|
+
const runtime = await this.renderer?.getRuntime();
|
|
130
|
+
if (runtime?.beforeSelect) {
|
|
131
|
+
await runtime.beforeSelect(el);
|
|
132
|
+
}
|
|
85
133
|
|
|
134
|
+
this.mask.setLayout(el);
|
|
135
|
+
this.dr?.select(el, event);
|
|
86
136
|
this.selectedDom = el;
|
|
87
|
-
this.setMaskLayout(el);
|
|
88
|
-
this.dr?.select(el);
|
|
89
137
|
}
|
|
90
138
|
|
|
139
|
+
/**
|
|
140
|
+
* 更新选中的节点
|
|
141
|
+
* @param data 更新的数据
|
|
142
|
+
*/
|
|
91
143
|
public update(data: UpdateData): void {
|
|
92
144
|
const { config } = data;
|
|
93
145
|
|
|
@@ -98,9 +150,9 @@ export default class StageCore extends EventEmitter {
|
|
|
98
150
|
const el = this.renderer.contentWindow?.document.getElementById(`${config.id}`);
|
|
99
151
|
if (el) {
|
|
100
152
|
// 更新了组件的布局,需要重新设置mask是否可以滚动
|
|
101
|
-
this.
|
|
153
|
+
this.mask.setLayout(el);
|
|
154
|
+
this.dr?.select(el);
|
|
102
155
|
}
|
|
103
|
-
this.dr?.refresh();
|
|
104
156
|
}, 0);
|
|
105
157
|
});
|
|
106
158
|
}
|
|
@@ -131,12 +183,6 @@ export default class StageCore extends EventEmitter {
|
|
|
131
183
|
renderer.mount(el);
|
|
132
184
|
mask.mount(el);
|
|
133
185
|
|
|
134
|
-
const { wrapper: maskWrapper, hGuides, vGuides } = mask;
|
|
135
|
-
|
|
136
|
-
maskWrapper.addEventListener('scroll', this.maskScrollHandler);
|
|
137
|
-
hGuides.on('changeGuides', this.hGuidesChangeGuidesHandler);
|
|
138
|
-
vGuides.on('changeGuides', this.vGuidesChangeGuidesHandler);
|
|
139
|
-
|
|
140
186
|
this.emit('mounted');
|
|
141
187
|
}
|
|
142
188
|
|
|
@@ -145,8 +191,7 @@ export default class StageCore extends EventEmitter {
|
|
|
145
191
|
*/
|
|
146
192
|
public clearGuides() {
|
|
147
193
|
this.mask.clearGuides();
|
|
148
|
-
this.dr.
|
|
149
|
-
this.dr.setVGuidelines([]);
|
|
194
|
+
this.dr.clearGuides();
|
|
150
195
|
}
|
|
151
196
|
|
|
152
197
|
/**
|
|
@@ -154,69 +199,11 @@ export default class StageCore extends EventEmitter {
|
|
|
154
199
|
*/
|
|
155
200
|
public destroy(): void {
|
|
156
201
|
const { mask, renderer, dr } = this;
|
|
157
|
-
const { wrapper: maskWrapper, hGuides, vGuides } = mask;
|
|
158
202
|
|
|
159
203
|
renderer.destroy();
|
|
160
204
|
mask.destroy();
|
|
161
205
|
dr.destroy();
|
|
162
|
-
maskWrapper.removeEventListener('scroll', this.maskScrollHandler);
|
|
163
|
-
hGuides.off('changeGuides', this.hGuidesChangeGuidesHandler);
|
|
164
|
-
vGuides.off('changeGuides', this.vGuidesChangeGuidesHandler);
|
|
165
|
-
this.removeAllListeners();
|
|
166
|
-
}
|
|
167
206
|
|
|
168
|
-
|
|
169
|
-
const { mask, renderer } = this;
|
|
170
|
-
const { wrapper: maskWrapper, hGuides, vGuides } = mask;
|
|
171
|
-
const { scrollTop } = maskWrapper;
|
|
172
|
-
|
|
173
|
-
renderer?.contentWindow?.document.documentElement.scrollTo({ top: scrollTop });
|
|
174
|
-
|
|
175
|
-
hGuides.scrollGuides(scrollTop);
|
|
176
|
-
hGuides.scroll(0);
|
|
177
|
-
|
|
178
|
-
vGuides.scrollGuides(0);
|
|
179
|
-
vGuides.scroll(scrollTop);
|
|
180
|
-
|
|
181
|
-
this.emit('scroll', event);
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
private hGuidesChangeGuidesHandler = (e: GuidesEvents['changeGuides']) => {
|
|
185
|
-
this.dr.setHGuidelines(e.guides);
|
|
186
|
-
this.emit('changeGuides');
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
private vGuidesChangeGuidesHandler = (e: GuidesEvents['changeGuides']) => {
|
|
190
|
-
this.dr.setVGuidelines(e.guides);
|
|
191
|
-
this.emit('changeGuides');
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
private setMaskLayout(el: HTMLElement): void {
|
|
195
|
-
let fixed = false;
|
|
196
|
-
let dom = el;
|
|
197
|
-
while (dom) {
|
|
198
|
-
fixed = isFixed(dom);
|
|
199
|
-
if (fixed) {
|
|
200
|
-
break;
|
|
201
|
-
}
|
|
202
|
-
const { parentElement } = dom;
|
|
203
|
-
if (!parentElement || parentElement.tagName === 'BODY') {
|
|
204
|
-
break;
|
|
205
|
-
}
|
|
206
|
-
dom = parentElement;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
if (fixed) {
|
|
210
|
-
this.mask?.setFixed();
|
|
211
|
-
} else {
|
|
212
|
-
this.mask?.setAbsolute();
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
private async beforeSelect(el: HTMLElement): Promise<void> {
|
|
217
|
-
const runtime = await this.renderer?.getRuntime();
|
|
218
|
-
if (runtime?.beforeSelect) {
|
|
219
|
-
await runtime.beforeSelect(el);
|
|
220
|
-
}
|
|
207
|
+
this.removeAllListeners();
|
|
221
208
|
}
|
|
222
209
|
}
|