@tmagic/stage 1.2.0-beta.2 → 1.2.0-beta.21

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 (41) hide show
  1. package/README.md +62 -1
  2. package/dist/tmagic-stage.js +2157 -0
  3. package/dist/tmagic-stage.js.map +1 -0
  4. package/dist/{tmagic-stage.umd.js → tmagic-stage.umd.cjs} +1436 -993
  5. package/dist/tmagic-stage.umd.cjs.map +1 -0
  6. package/package.json +9 -8
  7. package/src/ActionManager.ts +534 -0
  8. package/src/DragResizeHelper.ts +338 -0
  9. package/src/MoveableOptionsManager.ts +249 -0
  10. package/src/MoveableSelectParentAble.ts +76 -0
  11. package/src/Rule.ts +13 -9
  12. package/src/StageCore.ts +220 -260
  13. package/src/StageDragResize.ts +83 -339
  14. package/src/StageHighlight.ts +17 -16
  15. package/src/StageMask.ts +88 -140
  16. package/src/StageMultiDragResize.ts +97 -198
  17. package/src/StageRender.ts +90 -15
  18. package/src/TargetShadow.ts +120 -0
  19. package/src/const.ts +1 -1
  20. package/src/types.ts +97 -19
  21. package/src/util.ts +24 -11
  22. package/types/ActionManager.d.ts +141 -0
  23. package/types/DragResizeHelper.d.ts +70 -0
  24. package/types/MoveableOptionsManager.d.ts +86 -0
  25. package/types/MoveableSelectParentAble.d.ts +8 -0
  26. package/types/Rule.d.ts +4 -3
  27. package/types/StageCore.d.ts +65 -39
  28. package/types/StageDragResize.d.ts +11 -40
  29. package/types/StageHighlight.d.ts +3 -4
  30. package/types/StageMask.d.ts +23 -22
  31. package/types/StageMultiDragResize.d.ts +8 -24
  32. package/types/StageRender.d.ts +24 -6
  33. package/types/TargetShadow.d.ts +22 -0
  34. package/types/const.d.ts +1 -1
  35. package/types/types.d.ts +85 -18
  36. package/types/util.d.ts +9 -8
  37. package/dist/tmagic-stage.mjs +0 -1715
  38. package/dist/tmagic-stage.mjs.map +0 -1
  39. package/dist/tmagic-stage.umd.js.map +0 -1
  40. package/src/TargetCalibrate.ts +0 -119
  41. package/types/TargetCalibrate.d.ts +0 -20
@@ -16,39 +16,46 @@
16
16
  * limitations under the License.
17
17
  */
18
18
 
19
- import { EventEmitter } from 'events';
20
-
21
- import type { MoveableOptions, OnDragStart, OnResizeStart } from 'moveable';
22
19
  import Moveable from 'moveable';
23
- import MoveableHelper from 'moveable-helper';
24
20
 
25
- import { DRAG_EL_ID_PREFIX, PAGE_CLASS } from './const';
26
- import StageCore from './StageCore';
27
- import StageMask from './StageMask';
28
- import { StageDragResizeConfig, StageDragStatus } from './types';
29
- import { calcValueByFontsize, getMode, getTargetElStyle } from './util';
21
+ import { DRAG_EL_ID_PREFIX, Mode } from './const';
22
+ import DragResizeHelper from './DragResizeHelper';
23
+ import MoveableOptionsManager from './MoveableOptionsManager';
24
+ import { GetRenderDocument, MoveableOptionsManagerConfig, StageDragStatus, StageMultiDragResizeConfig } from './types';
25
+ import { calcValueByFontsize, getMode } from './util';
30
26
 
31
- export default class StageMultiDragResize extends EventEmitter {
32
- public core: StageCore;
33
- public mask: StageMask;
27
+ export default class StageMultiDragResize extends MoveableOptionsManager {
34
28
  /** 画布容器 */
35
29
  public container: HTMLElement;
36
30
  /** 多选:目标节点组 */
37
31
  public targetList: HTMLElement[] = [];
38
- /** 多选:目标节点在蒙层中的占位节点组 */
39
- public dragElList: HTMLDivElement[] = [];
40
32
  /** Moveable多选拖拽类实例 */
41
33
  public moveableForMulti?: Moveable;
42
- /** 拖动状态 */
43
34
  public dragStatus: StageDragStatus = StageDragStatus.END;
44
- private multiMoveableHelper?: MoveableHelper;
45
-
46
- constructor(config: StageDragResizeConfig) {
47
- super();
35
+ private dragResizeHelper: DragResizeHelper;
36
+ private getRenderDocument: GetRenderDocument;
37
+
38
+ constructor(config: StageMultiDragResizeConfig) {
39
+ const moveableOptionsManagerConfig: MoveableOptionsManagerConfig = {
40
+ container: config.container,
41
+ moveableOptions: config.multiMoveableOptions,
42
+ getRootContainer: config.getRootContainer,
43
+ };
44
+ super(moveableOptionsManagerConfig);
48
45
 
49
- this.core = config.core;
50
46
  this.container = config.container;
51
- this.mask = config.mask;
47
+ this.getRenderDocument = config.getRenderDocument;
48
+
49
+ this.dragResizeHelper = new DragResizeHelper({
50
+ container: config.container,
51
+ updateDragEl: config.updateDragEl,
52
+ });
53
+
54
+ this.on('update-moveable', () => {
55
+ if (this.moveableForMulti) {
56
+ this.updateMoveable();
57
+ }
58
+ });
52
59
  }
53
60
 
54
61
  /**
@@ -56,168 +63,108 @@ export default class StageMultiDragResize extends EventEmitter {
56
63
  * @param els
57
64
  */
58
65
  public multiSelect(els: HTMLElement[]): void {
66
+ if (els.length === 0) {
67
+ return;
68
+ }
69
+ this.mode = getMode(els[0]);
59
70
  this.targetList = els;
60
- this.core.dr.destroyDragEl();
61
- this.destroyDragElList();
62
- // 生成虚拟多选节点
63
- this.dragElList = els.map((elItem) => {
64
- const dragElDiv = globalThis.document.createElement('div');
65
- this.container.append(dragElDiv);
66
- dragElDiv.style.cssText = getTargetElStyle(elItem);
67
- dragElDiv.id = `${DRAG_EL_ID_PREFIX}${elItem.id}`;
68
- // 业务方校准
69
- if (typeof this.core.config.updateDragEl === 'function') {
70
- this.core.config.updateDragEl(dragElDiv, elItem);
71
- }
72
- return dragElDiv;
73
- });
71
+
72
+ this.dragResizeHelper.updateGroup(els);
73
+
74
+ // 设置周围元素,用于选中元素跟周围元素的对齐辅助
75
+ const elementGuidelines: HTMLElement[] =
76
+ Array.prototype.slice.call(this.targetList[0].parentElement?.children) || [];
77
+ this.setElementGuidelines(this.targetList, elementGuidelines);
78
+
74
79
  this.moveableForMulti?.destroy();
75
- this.multiMoveableHelper?.clear();
80
+ this.dragResizeHelper.clear();
76
81
  this.moveableForMulti = new Moveable(
77
82
  this.container,
78
- this.getOptions({
79
- target: this.dragElList,
83
+ this.getOptions(true, {
84
+ target: this.dragResizeHelper.getShadowEls(),
80
85
  }),
81
86
  );
82
- this.multiMoveableHelper = MoveableHelper.create({
83
- useBeforeRender: true,
84
- useRender: false,
85
- createAuto: true,
86
- });
87
- const frames: { left: number; top: number; id: string }[] = [];
88
-
89
- const setFrames = (events: OnDragStart[] | OnResizeStart[]) => {
90
- // 记录拖动前快照
91
- events.forEach((ev) => {
92
- // 实际目标元素
93
- const matchEventTarget = this.targetList.find(
94
- (targetItem) => targetItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, ''),
95
- );
96
- if (!matchEventTarget) return;
97
- frames.push({
98
- left: matchEventTarget.offsetLeft,
99
- top: matchEventTarget.offsetTop,
100
- id: matchEventTarget.id,
101
- });
102
- });
103
- };
104
87
 
105
88
  this.moveableForMulti
106
- .on('resizeGroupStart', (params) => {
107
- const { events } = params;
108
- this.multiMoveableHelper?.onResizeGroupStart(params);
109
- setFrames(events);
89
+ .on('resizeGroupStart', (e) => {
90
+ this.dragResizeHelper.onResizeGroupStart(e);
110
91
  this.dragStatus = StageDragStatus.START;
111
92
  })
112
- .on('resizeGroup', (params) => {
113
- const { events } = params;
114
- // 拖动过程更新
115
- events.forEach((ev) => {
116
- const { width, height, beforeTranslate } = ev.drag;
117
- const frameSnapShot = frames.find(
118
- (frameItem) => frameItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, ''),
119
- );
120
- if (!frameSnapShot) return;
121
- const targeEl = this.targetList.find(
122
- (targetItem) => targetItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, ''),
123
- );
124
- if (!targeEl) return;
125
- // 元素与其所属组同时加入多选列表时,只更新父元素
126
- const isParentIncluded = this.targetList.find((targetItem) => targetItem.id === targeEl.parentElement?.id);
127
- if (!isParentIncluded) {
128
- // 更新页面元素位置
129
- targeEl.style.left = `${frameSnapShot.left + beforeTranslate[0]}px`;
130
- targeEl.style.top = `${frameSnapShot.top + beforeTranslate[1]}px`;
131
- }
132
-
133
- // 更新页面元素位置
134
- targeEl.style.width = `${width}px`;
135
- targeEl.style.height = `${height}px`;
136
- });
137
- this.multiMoveableHelper?.onResizeGroup(params);
93
+ .on('resizeGroup', (e) => {
94
+ this.dragResizeHelper.onResizeGroup(e);
138
95
  this.dragStatus = StageDragStatus.ING;
139
96
  })
140
97
  .on('resizeGroupEnd', () => {
141
98
  this.update(true);
142
99
  this.dragStatus = StageDragStatus.END;
143
100
  })
144
- .on('dragGroupStart', (params) => {
145
- const { events } = params;
146
- this.multiMoveableHelper?.onDragGroupStart(params);
147
- // 记录拖动前快照
148
- setFrames(events);
101
+ .on('dragGroupStart', (e) => {
102
+ this.dragResizeHelper.onDragGroupStart(e);
149
103
  this.dragStatus = StageDragStatus.START;
150
104
  })
151
- .on('dragGroup', (params) => {
152
- const { events } = params;
153
- // 拖动过程更新
154
- events.forEach((ev) => {
155
- const frameSnapShot = frames.find(
156
- (frameItem) => frameItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, ''),
157
- );
158
- if (!frameSnapShot) return;
159
- const targeEl = this.targetList.find(
160
- (targetItem) => targetItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, ''),
161
- );
162
- if (!targeEl) return;
163
- // 元素与其所属组同时加入多选列表时,只更新父元素
164
- const isParentIncluded = this.targetList.find((targetItem) => targetItem.id === targeEl.parentElement?.id);
165
- if (!isParentIncluded) {
166
- // 更新页面元素位置
167
- targeEl.style.left = `${frameSnapShot.left + ev.beforeTranslate[0]}px`;
168
- targeEl.style.top = `${frameSnapShot.top + ev.beforeTranslate[1]}px`;
169
- }
170
- });
171
- this.multiMoveableHelper?.onDragGroup(params);
105
+ .on('dragGroup', (e) => {
106
+ this.dragResizeHelper.onDragGroup(e);
172
107
  this.dragStatus = StageDragStatus.ING;
173
108
  })
174
109
  .on('dragGroupEnd', () => {
175
110
  this.update();
176
111
  this.dragStatus = StageDragStatus.END;
177
112
  })
178
- .on('clickGroup', (params) => {
179
- const { inputTarget, targets } = params;
180
- // 如果此时mask不处于多选状态下,且有多个元素被选中,同时点击的元素在选中元素中的其中一项,代表多选态切换为该元素的单选态
181
- if (!this.mask.isMultiSelectStatus && targets.length > 1 && targets.includes(inputTarget)) {
182
- this.emit('select', inputTarget.id.replace(DRAG_EL_ID_PREFIX, ''));
113
+ .on('clickGroup', (e) => {
114
+ const { inputTarget, targets } = e;
115
+ // 如果有多个元素被选中,同时点击的元素在选中元素中的其中一项,可能是多选态切换为该元素的单选态,抛事件给上一层继续判断是否切换
116
+ if (targets.length > 1 && targets.includes(inputTarget)) {
117
+ this.emit('change-to-select', inputTarget.id.replace(DRAG_EL_ID_PREFIX, ''));
183
118
  }
184
119
  });
185
120
  }
186
121
 
187
- public canSelect(el: HTMLElement, stop: () => boolean): Boolean {
188
- // 多选状态下不可以选中magic-ui-page,并停止继续向上层选中
189
- if (el.className.includes(PAGE_CLASS)) {
190
- this.core.highlightedDom = undefined;
191
- this.core.highlightLayer.clearHighlight();
192
- stop();
193
- return false;
194
- }
122
+ public canSelect(el: HTMLElement, selectedEl: HTMLElement | undefined): boolean {
195
123
  const currentTargetMode = getMode(el);
196
- let selectedDomMode = '';
197
- if (this.core.selectedDom?.className.includes(PAGE_CLASS)) {
198
- // 先单击选中了页面(magic-ui-page),再按住多选键多选时,任一元素均可选中
199
- return true;
124
+ let selectedElMode = '';
125
+
126
+ // 流式布局不支持多选
127
+ if (currentTargetMode === Mode.SORTABLE) {
128
+ return false;
200
129
  }
201
- if (this.targetList.length === 0 && this.core.selectedDom) {
130
+
131
+ if (this.targetList.length === 0 && selectedEl) {
202
132
  // 单选后添加到多选的情况
203
- selectedDomMode = getMode(this.core.selectedDom);
133
+ selectedElMode = getMode(selectedEl);
204
134
  } else if (this.targetList.length > 0) {
205
135
  // 已加入多选列表的布局模式是一样的,取第一个判断
206
- selectedDomMode = getMode(this.targetList[0]);
136
+ selectedElMode = getMode(this.targetList[0]);
207
137
  }
208
138
  // 定位模式不同,不可混选
209
- if (currentTargetMode !== selectedDomMode) {
139
+ if (currentTargetMode !== selectedElMode) {
210
140
  return false;
211
141
  }
212
142
  return true;
213
143
  }
214
144
 
145
+ public updateMoveable(eleList = this.targetList) {
146
+ if (!this.moveableForMulti) return;
147
+ if (!eleList) throw new Error('未选中任何节点');
148
+
149
+ this.targetList = eleList;
150
+ this.dragResizeHelper.setTargetList(eleList);
151
+
152
+ const options = this.getOptions(true, {
153
+ target: this.dragResizeHelper.getShadowEls(),
154
+ });
155
+
156
+ Object.entries(options).forEach(([key, value]) => {
157
+ (this.moveableForMulti as any)[key] = value;
158
+ });
159
+ this.moveableForMulti.updateTarget();
160
+ }
161
+
215
162
  /**
216
163
  * 清除多选状态
217
164
  */
218
165
  public clearSelectStatus(): void {
219
166
  if (!this.moveableForMulti) return;
220
- this.destroyDragElList();
167
+ this.dragResizeHelper.clearMultiSelectStatus();
221
168
  this.moveableForMulti.target = null;
222
169
  this.moveableForMulti.updateTarget();
223
170
  this.targetList = [];
@@ -228,14 +175,7 @@ export default class StageMultiDragResize extends EventEmitter {
228
175
  */
229
176
  public destroy(): void {
230
177
  this.moveableForMulti?.destroy();
231
- this.destroyDragElList();
232
- }
233
-
234
- /**
235
- * 清除蒙层占位节点
236
- */
237
- public destroyDragElList(): void {
238
- this.dragElList.forEach((dragElItem) => dragElItem?.remove());
178
+ this.dragResizeHelper.destroy();
239
179
  }
240
180
 
241
181
  /**
@@ -245,60 +185,19 @@ export default class StageMultiDragResize extends EventEmitter {
245
185
  private update(isResize = false): void {
246
186
  if (this.targetList.length === 0) return;
247
187
 
248
- const { contentWindow } = this.core.renderer;
249
- const doc = contentWindow?.document;
188
+ const doc = this.getRenderDocument();
250
189
  if (!doc) return;
251
190
 
252
- this.emit('update', {
253
- data: this.targetList.map((targetItem) => {
254
- const offset = { left: targetItem.offsetLeft, top: targetItem.offsetTop };
255
- const left = calcValueByFontsize(doc, offset.left);
256
- const top = calcValueByFontsize(doc, offset.top);
257
- const width = calcValueByFontsize(doc, targetItem.clientWidth);
258
- const height = calcValueByFontsize(doc, targetItem.clientHeight);
259
- return {
260
- el: targetItem,
261
- style: isResize ? { left, top, width, height } : { left, top },
262
- };
263
- }),
264
- parentEl: null,
191
+ const data = this.targetList.map((targetItem) => {
192
+ const left = calcValueByFontsize(doc, targetItem.offsetLeft);
193
+ const top = calcValueByFontsize(doc, targetItem.offsetTop);
194
+ const width = calcValueByFontsize(doc, targetItem.clientWidth);
195
+ const height = calcValueByFontsize(doc, targetItem.clientHeight);
196
+ return {
197
+ el: targetItem,
198
+ style: isResize ? { left, top, width, height } : { left, top },
199
+ };
265
200
  });
266
- }
267
-
268
- /**
269
- * 获取moveable options参数
270
- * @param {MoveableOptions} options
271
- * @return {MoveableOptions} moveable options参数
272
- */
273
- private getOptions(options: MoveableOptions = {}): MoveableOptions {
274
- let { multiMoveableOptions = {} } = this.core.config;
275
-
276
- if (typeof multiMoveableOptions === 'function') {
277
- multiMoveableOptions = multiMoveableOptions(this.core);
278
- }
279
-
280
- return {
281
- defaultGroupRotate: 0,
282
- defaultGroupOrigin: '50% 50%',
283
- draggable: true,
284
- resizable: true,
285
- throttleDrag: 0,
286
- startDragRotate: 0,
287
- throttleDragRotate: 0,
288
- zoom: 1,
289
- origin: true,
290
- padding: { left: 0, top: 0, right: 0, bottom: 0 },
291
- snappable: true,
292
- bounds: {
293
- top: 0,
294
- // 设置0的话无法移动到left为0,所以只能设置为-1
295
- left: -1,
296
- right: this.container.clientWidth - 1,
297
- bottom: this.container.clientHeight,
298
- ...(multiMoveableOptions.bounds || {}),
299
- },
300
- ...options,
301
- ...multiMoveableOptions,
302
- };
201
+ this.emit('update', data, null);
303
202
  }
304
203
  }
@@ -18,32 +18,30 @@
18
18
 
19
19
  import { EventEmitter } from 'events';
20
20
 
21
+ import { Id } from '@tmagic/schema';
21
22
  import { getHost, injectStyle, isSameDomain } from '@tmagic/utils';
22
23
 
23
- import StageCore from './StageCore';
24
+ import { DEFAULT_ZOOM } from './const';
24
25
  import style from './style.css?raw';
25
- import type { Runtime, RuntimeWindow, StageRenderConfig } from './types';
26
+ import type { Point, RemoveData, Runtime, RuntimeWindow, StageRenderConfig, UpdateData } from './types';
27
+ import { addSelectedClassName, removeSelectedClassName } from './util';
26
28
 
27
29
  export default class StageRender extends EventEmitter {
28
30
  /** 组件的js、css执行的环境,直接渲染为当前window,iframe渲染则为iframe.contentWindow */
29
31
  public contentWindow: RuntimeWindow | null = null;
30
-
31
32
  public runtime: Runtime | null = null;
32
-
33
33
  public iframe?: HTMLIFrameElement;
34
34
 
35
- public runtimeUrl?: string;
36
-
37
- public core: StageCore;
35
+ private runtimeUrl?: string;
36
+ private zoom = DEFAULT_ZOOM;
37
+ private customizedRender?: () => Promise<HTMLElement | null>;
38
38
 
39
- private render?: (renderer: StageCore) => Promise<HTMLElement> | HTMLElement;
40
-
41
- constructor({ core }: StageRenderConfig) {
39
+ constructor({ runtimeUrl, zoom, customizedRender }: StageRenderConfig) {
42
40
  super();
43
41
 
44
- this.core = core;
45
- this.runtimeUrl = core.config.runtimeUrl || '';
46
- this.render = core.config.render;
42
+ this.runtimeUrl = runtimeUrl || '';
43
+ this.customizedRender = customizedRender;
44
+ this.setZoom(zoom);
47
45
 
48
46
  this.iframe = globalThis.document.createElement('iframe');
49
47
  // 同源,直接加载
@@ -67,6 +65,38 @@ export default class StageRender extends EventEmitter {
67
65
  },
68
66
  });
69
67
 
68
+ public async add(data: UpdateData): Promise<void> {
69
+ const runtime = await this.getRuntime();
70
+ return runtime?.add?.(data);
71
+ }
72
+
73
+ public async remove(data: RemoveData): Promise<void> {
74
+ const runtime = await this.getRuntime();
75
+ return runtime?.remove?.(data);
76
+ }
77
+
78
+ public async update(data: UpdateData): Promise<void> {
79
+ const runtime = await this.getRuntime();
80
+ // 更新画布中的组件
81
+ runtime?.update?.(data);
82
+ }
83
+
84
+ public async select(els: HTMLElement[]): Promise<void> {
85
+ const runtime = await this.getRuntime();
86
+
87
+ for (const el of els) {
88
+ await runtime?.select?.(el.id);
89
+ if (runtime?.beforeSelect) {
90
+ await runtime.beforeSelect(el);
91
+ }
92
+ this.flagSelectedEl(el);
93
+ }
94
+ }
95
+
96
+ public setZoom(zoom: number = DEFAULT_ZOOM): void {
97
+ this.zoom = zoom;
98
+ }
99
+
70
100
  /**
71
101
  * 挂载Dom节点
72
102
  * @param el 将页面挂载到该Dom节点上
@@ -101,6 +131,39 @@ export default class StageRender extends EventEmitter {
101
131
  });
102
132
  };
103
133
 
134
+ public getDocument(): Document | undefined {
135
+ return this.contentWindow?.document;
136
+ }
137
+
138
+ /**
139
+ * 通过坐标获得坐标下所有HTML元素数组
140
+ * @param point 坐标
141
+ * @returns 坐标下方所有HTML元素数组,会包含父元素直至html,元素层叠时返回顺序是从上到下
142
+ */
143
+ public getElementsFromPoint(point: Point): HTMLElement[] {
144
+ let x = point.clientX;
145
+ let y = point.clientY;
146
+
147
+ if (this.iframe) {
148
+ const rect = this.iframe.getClientRects()[0];
149
+ if (rect) {
150
+ x = x - rect.left;
151
+ y = y - rect.top;
152
+ }
153
+ }
154
+
155
+ return this.getDocument()?.elementsFromPoint(x / this.zoom, y / this.zoom) as HTMLElement[];
156
+ }
157
+
158
+ public getTargetElement(idOrEl: Id | HTMLElement): HTMLElement {
159
+ if (typeof idOrEl === 'string' || typeof idOrEl === 'number') {
160
+ const el = this.getDocument()?.getElementById(`${idOrEl}`);
161
+ if (!el) throw new Error(`不存在ID为${idOrEl}的元素`);
162
+ return el;
163
+ }
164
+ return idOrEl;
165
+ }
166
+
104
167
  /**
105
168
  * 销毁实例
106
169
  */
@@ -112,6 +175,18 @@ export default class StageRender extends EventEmitter {
112
175
  this.removeAllListeners();
113
176
  }
114
177
 
178
+ /**
179
+ * 在runtime中对被选中的元素进行标记,部分组件有对选中态进行特殊显示的需求
180
+ * @param el 被选中的元素
181
+ */
182
+ private flagSelectedEl(el: HTMLElement): void {
183
+ const doc = this.getDocument();
184
+ if (doc) {
185
+ removeSelectedClassName(doc);
186
+ addSelectedClassName(el, doc);
187
+ }
188
+ }
189
+
115
190
  private loadHandler = async () => {
116
191
  if (!this.contentWindow?.magic) {
117
192
  this.postTmagicRuntimeReady();
@@ -119,8 +194,8 @@ export default class StageRender extends EventEmitter {
119
194
 
120
195
  if (!this.contentWindow) return;
121
196
 
122
- if (this.render) {
123
- const el = await this.render(this.core);
197
+ if (this.customizedRender) {
198
+ const el = await this.customizedRender();
124
199
  if (el) {
125
200
  this.contentWindow.document?.body?.appendChild(el);
126
201
  }
@@ -0,0 +1,120 @@
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
+ import { Mode, ZIndex } from './const';
19
+ import type { TargetElement as ShadowElement, TargetShadowConfig, UpdateDragEl } from './types';
20
+ import { getTargetElStyle, isFixedParent } from './util';
21
+
22
+ /**
23
+ * 将选中的节点修正定位后,添加一个操作节点到蒙层上
24
+ */
25
+ export default class TargetShadow {
26
+ public el?: ShadowElement;
27
+ public els: ShadowElement[] = [];
28
+
29
+ private idPrefix = 'target_calibrate_';
30
+ private container: HTMLElement;
31
+ private scrollLeft = 0;
32
+ private scrollTop = 0;
33
+ private zIndex?: ZIndex;
34
+
35
+ private updateDragEl?: UpdateDragEl;
36
+
37
+ constructor(config: TargetShadowConfig) {
38
+ this.container = config.container;
39
+
40
+ if (config.updateDragEl) {
41
+ this.updateDragEl = config.updateDragEl;
42
+ }
43
+
44
+ if (typeof config.zIndex !== 'undefined') {
45
+ this.zIndex = config.zIndex;
46
+ }
47
+
48
+ if (config.idPrefix) {
49
+ this.idPrefix = config.idPrefix;
50
+ }
51
+
52
+ this.container.addEventListener('customScroll', this.scrollHandler);
53
+ }
54
+
55
+ public update(target: ShadowElement): ShadowElement {
56
+ this.el = this.updateEl(target, this.el);
57
+
58
+ return this.el;
59
+ }
60
+
61
+ public updateGroup(targetGroup: ShadowElement[]): ShadowElement[] {
62
+ if (this.els.length > targetGroup.length) {
63
+ this.els.slice(targetGroup.length - 1).forEach((el) => {
64
+ el.remove();
65
+ });
66
+ }
67
+
68
+ this.els = targetGroup.map((target, index) => this.updateEl(target, this.els[index]));
69
+
70
+ return this.els;
71
+ }
72
+
73
+ public destroyEl(): void {
74
+ this.el?.remove();
75
+ this.el = undefined;
76
+ }
77
+
78
+ public destroyEls(): void {
79
+ this.els.forEach((el) => {
80
+ el.remove();
81
+ });
82
+ this.els = [];
83
+ }
84
+
85
+ public destroy(): void {
86
+ this.container.removeEventListener('customScroll', this.scrollHandler);
87
+ this.destroyEl();
88
+ this.destroyEls();
89
+ }
90
+
91
+ private updateEl(target: ShadowElement, src?: ShadowElement): ShadowElement {
92
+ const el = src || globalThis.document.createElement('div');
93
+
94
+ el.id = `${this.idPrefix}${target.id}`;
95
+
96
+ el.style.cssText = getTargetElStyle(target, this.zIndex);
97
+
98
+ if (typeof this.updateDragEl === 'function') {
99
+ this.updateDragEl(el, target);
100
+ }
101
+ const isFixed = isFixedParent(target);
102
+ const mode = this.container.dataset.mode || Mode.ABSOLUTE;
103
+ if (isFixed && mode !== Mode.FIXED) {
104
+ el.style.transform = `translate3d(${this.scrollLeft}px, ${this.scrollTop}px, 0)`;
105
+ } else if (!isFixed && mode === Mode.FIXED) {
106
+ el.style.transform = `translate3d(${-this.scrollLeft}px, ${-this.scrollTop}px, 0)`;
107
+ }
108
+
109
+ if (!globalThis.document.getElementById(el.id)) {
110
+ this.container.append(el);
111
+ }
112
+
113
+ return el;
114
+ }
115
+
116
+ private scrollHandler = (e: any) => {
117
+ this.scrollLeft = e.detail.scrollLeft;
118
+ this.scrollTop = e.detail.scrollTop;
119
+ };
120
+ }
package/src/const.ts CHANGED
@@ -25,7 +25,7 @@ export const DRAG_EL_ID_PREFIX = 'drag_el_';
25
25
  /** 高亮时需要在蒙层中创建一个占位节点,该节点的id前缀 */
26
26
  export const HIGHLIGHT_EL_ID_PREFIX = 'highlight_el_';
27
27
 
28
- export const CONTAINER_HIGHLIGHT_CLASS = 'tmagic-stage-container-highlight';
28
+ export const CONTAINER_HIGHLIGHT_CLASS_NAME = 'tmagic-stage-container-highlight';
29
29
 
30
30
  export const PAGE_CLASS = 'magic-ui-page';
31
31