@tmagic/stage 1.0.0-beta.7 → 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 +462 -17577
- package/dist/tmagic-stage.es.js.map +1 -1
- package/dist/tmagic-stage.umd.js +466 -17582
- 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 +12 -9
- package/dist/types/src/StageMask.d.ts +18 -37
- 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 -88
- package/src/StageDragResize.ts +147 -162
- package/src/StageMask.ts +122 -184
- 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,23 +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
|
-
|
|
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;
|
|
62
91
|
|
|
63
|
-
|
|
64
|
-
|
|
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
|
+
}
|
|
65
111
|
}
|
|
66
112
|
|
|
67
113
|
/**
|
|
68
114
|
* 选中组件
|
|
69
115
|
* @param idOrEl 组件Dom节点的id属性,或者Dom节点
|
|
70
116
|
*/
|
|
71
|
-
public async select(idOrEl: Id | HTMLElement): Promise<void> {
|
|
117
|
+
public async select(idOrEl: Id | HTMLElement, event?: MouseEvent): Promise<void> {
|
|
72
118
|
let el;
|
|
73
119
|
if (typeof idOrEl === 'string' || typeof idOrEl === 'number') {
|
|
74
120
|
const runtime = await this.renderer?.getRuntime();
|
|
@@ -78,15 +124,22 @@ export default class StageCore extends EventEmitter {
|
|
|
78
124
|
el = idOrEl;
|
|
79
125
|
}
|
|
80
126
|
|
|
81
|
-
if (this.selectedDom
|
|
127
|
+
if (el === this.selectedDom) return;
|
|
82
128
|
|
|
83
|
-
await this.
|
|
129
|
+
const runtime = await this.renderer?.getRuntime();
|
|
130
|
+
if (runtime?.beforeSelect) {
|
|
131
|
+
await runtime.beforeSelect(el);
|
|
132
|
+
}
|
|
84
133
|
|
|
134
|
+
this.mask.setLayout(el);
|
|
135
|
+
this.dr?.select(el, event);
|
|
85
136
|
this.selectedDom = el;
|
|
86
|
-
this.setMaskLayout(el);
|
|
87
|
-
this.dr?.select(el);
|
|
88
137
|
}
|
|
89
138
|
|
|
139
|
+
/**
|
|
140
|
+
* 更新选中的节点
|
|
141
|
+
* @param data 更新的数据
|
|
142
|
+
*/
|
|
90
143
|
public update(data: UpdateData): void {
|
|
91
144
|
const { config } = data;
|
|
92
145
|
|
|
@@ -97,9 +150,9 @@ export default class StageCore extends EventEmitter {
|
|
|
97
150
|
const el = this.renderer.contentWindow?.document.getElementById(`${config.id}`);
|
|
98
151
|
if (el) {
|
|
99
152
|
// 更新了组件的布局,需要重新设置mask是否可以滚动
|
|
100
|
-
this.
|
|
153
|
+
this.mask.setLayout(el);
|
|
154
|
+
this.dr?.select(el);
|
|
101
155
|
}
|
|
102
|
-
this.dr?.refresh();
|
|
103
156
|
}, 0);
|
|
104
157
|
});
|
|
105
158
|
}
|
|
@@ -130,12 +183,6 @@ export default class StageCore extends EventEmitter {
|
|
|
130
183
|
renderer.mount(el);
|
|
131
184
|
mask.mount(el);
|
|
132
185
|
|
|
133
|
-
const { wrapper: maskWrapper, hGuides, vGuides } = mask;
|
|
134
|
-
|
|
135
|
-
maskWrapper.addEventListener('scroll', this.maskScrollHandler);
|
|
136
|
-
hGuides.on('changeGuides', this.hGuidesChangeGuidesHandler);
|
|
137
|
-
vGuides.on('changeGuides', this.vGuidesChangeGuidesHandler);
|
|
138
|
-
|
|
139
186
|
this.emit('mounted');
|
|
140
187
|
}
|
|
141
188
|
|
|
@@ -144,8 +191,7 @@ export default class StageCore extends EventEmitter {
|
|
|
144
191
|
*/
|
|
145
192
|
public clearGuides() {
|
|
146
193
|
this.mask.clearGuides();
|
|
147
|
-
this.dr.
|
|
148
|
-
this.dr.setVGuidelines([]);
|
|
194
|
+
this.dr.clearGuides();
|
|
149
195
|
}
|
|
150
196
|
|
|
151
197
|
/**
|
|
@@ -153,69 +199,11 @@ export default class StageCore extends EventEmitter {
|
|
|
153
199
|
*/
|
|
154
200
|
public destroy(): void {
|
|
155
201
|
const { mask, renderer, dr } = this;
|
|
156
|
-
const { wrapper: maskWrapper, hGuides, vGuides } = mask;
|
|
157
202
|
|
|
158
203
|
renderer.destroy();
|
|
159
204
|
mask.destroy();
|
|
160
205
|
dr.destroy();
|
|
161
|
-
maskWrapper.removeEventListener('scroll', this.maskScrollHandler);
|
|
162
|
-
hGuides.off('changeGuides', this.hGuidesChangeGuidesHandler);
|
|
163
|
-
vGuides.off('changeGuides', this.vGuidesChangeGuidesHandler);
|
|
164
|
-
this.removeAllListeners();
|
|
165
|
-
}
|
|
166
206
|
|
|
167
|
-
|
|
168
|
-
const { mask, renderer } = this;
|
|
169
|
-
const { wrapper: maskWrapper, hGuides, vGuides } = mask;
|
|
170
|
-
const { scrollTop } = maskWrapper;
|
|
171
|
-
|
|
172
|
-
renderer?.contentWindow?.document.documentElement.scrollTo({ top: scrollTop });
|
|
173
|
-
|
|
174
|
-
hGuides.scrollGuides(scrollTop);
|
|
175
|
-
hGuides.scroll(0);
|
|
176
|
-
|
|
177
|
-
vGuides.scrollGuides(0);
|
|
178
|
-
vGuides.scroll(scrollTop);
|
|
179
|
-
|
|
180
|
-
this.emit('scroll', event);
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
private hGuidesChangeGuidesHandler = (e: GuidesEvents['changeGuides']) => {
|
|
184
|
-
this.dr.setHGuidelines(e.guides);
|
|
185
|
-
this.emit('changeGuides');
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
private vGuidesChangeGuidesHandler = (e: GuidesEvents['changeGuides']) => {
|
|
189
|
-
this.dr.setVGuidelines(e.guides);
|
|
190
|
-
this.emit('changeGuides');
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
private setMaskLayout(el: HTMLElement): void {
|
|
194
|
-
let fixed = false;
|
|
195
|
-
let dom = el;
|
|
196
|
-
while (dom) {
|
|
197
|
-
fixed = isFixed(dom);
|
|
198
|
-
if (fixed) {
|
|
199
|
-
break;
|
|
200
|
-
}
|
|
201
|
-
const { parentElement } = dom;
|
|
202
|
-
if (!parentElement || parentElement.tagName === 'BODY') {
|
|
203
|
-
break;
|
|
204
|
-
}
|
|
205
|
-
dom = parentElement;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (fixed) {
|
|
209
|
-
this.mask?.setFixed();
|
|
210
|
-
} else {
|
|
211
|
-
this.mask?.setAbsolute();
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
private async beforeSelect(el: HTMLElement): Promise<void> {
|
|
216
|
-
const runtime = await this.renderer?.getRuntime();
|
|
217
|
-
if (runtime?.beforeSelect) {
|
|
218
|
-
await runtime.beforeSelect(el);
|
|
219
|
-
}
|
|
207
|
+
this.removeAllListeners();
|
|
220
208
|
}
|
|
221
209
|
}
|