@tmagic/stage 1.2.0-beta.6 → 1.2.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/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.2.0-beta.6",
2
+ "version": "1.2.0-beta.8",
3
3
  "name": "@tmagic/stage",
4
4
  "sideEffects": [
5
5
  "dist/*"
@@ -29,9 +29,9 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "@scena/guides": "^0.17.0",
32
- "@tmagic/core": "1.2.0-beta.6",
33
- "@tmagic/schema": "1.2.0-beta.6",
34
- "@tmagic/utils": "1.2.0-beta.6",
32
+ "@tmagic/core": "1.2.0-beta.8",
33
+ "@tmagic/schema": "1.2.0-beta.8",
34
+ "@tmagic/utils": "1.2.0-beta.8",
35
35
  "events": "^3.3.0",
36
36
  "keycon": "^1.1.2",
37
37
  "lodash-es": "^4.17.21",
@@ -0,0 +1,78 @@
1
+ import { MoveableManagerInterface, Renderer } from 'moveable';
2
+
3
+ import type StageDragResize from './StageDragResize';
4
+
5
+ export default (dr: StageDragResize) => ({
6
+ name: 'selectParent',
7
+ props: {},
8
+ events: {},
9
+ render(moveable: MoveableManagerInterface<any, any>, React: Renderer) {
10
+ const rect = moveable.getRect();
11
+ const { pos2 } = moveable.state;
12
+
13
+ // use css for able
14
+ const editableViewer = moveable.useCSS(
15
+ 'div',
16
+ `
17
+ {
18
+ position: absolute;
19
+ left: 0px;
20
+ top: 0px;
21
+ will-change: transform;
22
+ transform-origin: 0px 0px;
23
+ display: flex;
24
+ }
25
+ .moveable-button {
26
+ width: 20px;
27
+ height: 20px;
28
+ background: #4af;
29
+ border-radius: 4px;
30
+ appearance: none;
31
+ border: 0;
32
+ color: white;
33
+ font-size: 12px;
34
+ font-weight: bold;
35
+ }
36
+ `,
37
+ );
38
+ // Add key (required)
39
+ // Add class prefix moveable-(required)
40
+ return React.createElement(
41
+ editableViewer,
42
+ {
43
+ className: 'moveable-editable',
44
+ style: {
45
+ transform: `translate(${pos2[0] - 25}px, ${pos2[1] - 30}px) rotate(${rect.rotation}deg) translate(10px)`,
46
+ },
47
+ },
48
+ React.createElement(
49
+ 'button',
50
+ {
51
+ className: 'moveable-button',
52
+ title: '选中父组件',
53
+ onClick: () => {
54
+ dr.emit('select-parent');
55
+ },
56
+ },
57
+ React.createElement(
58
+ 'svg',
59
+ {
60
+ width: '1em',
61
+ height: '1em',
62
+ viewBox: '0 0 16 16',
63
+ fill: 'none',
64
+ xmlns: 'http://www.w3.org/2000/svg',
65
+ style: {
66
+ transform: 'rotate(90deg)',
67
+ },
68
+ },
69
+ React.createElement('path', {
70
+ d: 'M13.0001 4V10H4.20718L5.85363 8.35355L5.14652 7.64645L2.64652 10.1464C2.45126 10.3417 2.45126 10.6583 2.64652 10.8536L5.14652 13.3536L5.85363 12.6464L4.20718 11H13.0001C13.5524 11 14.0001 10.5523 14.0001 10V4H13.0001Z',
71
+ fill: 'currentColor',
72
+ fillOpacity: '0.9',
73
+ }),
74
+ ),
75
+ ),
76
+ );
77
+ },
78
+ });
package/src/Rule.ts CHANGED
@@ -12,6 +12,7 @@ export default class Rule extends EventEmitter {
12
12
 
13
13
  private container: HTMLDivElement;
14
14
  private containerResizeObserver: ResizeObserver;
15
+ private isShowGuides = true;
15
16
 
16
17
  constructor(container: HTMLDivElement) {
17
18
  super();
@@ -32,16 +33,18 @@ export default class Rule extends EventEmitter {
32
33
  }
33
34
 
34
35
  /**
35
- * 是否显示标尺
36
- * @param show 是否显示
36
+ * 是否显示辅助线
37
+ * @param isShowGuides 是否显示
37
38
  */
38
- public showGuides(show = true) {
39
+ public showGuides(isShowGuides = true) {
40
+ this.isShowGuides = isShowGuides;
41
+
39
42
  this.hGuides.setState({
40
- showGuides: show,
43
+ showGuides: isShowGuides,
41
44
  });
42
45
 
43
46
  this.vGuides.setState({
44
- showGuides: show,
47
+ showGuides: isShowGuides,
45
48
  });
46
49
  }
47
50
 
@@ -135,6 +138,7 @@ export default class Rule extends EventEmitter {
135
138
  lineColor: '#000',
136
139
  textColor: '#000',
137
140
  style: this.getGuidesStyle(type),
141
+ showGuides: this.isShowGuides,
138
142
  });
139
143
 
140
144
  private hGuidesChangeGuidesHandler = (e: GuidesEvents['changeGuides']) => {
package/src/StageCore.ts CHANGED
@@ -62,6 +62,7 @@ export default class StageCore extends EventEmitter {
62
62
  public isContainer: IsContainer;
63
63
 
64
64
  private canSelect: CanSelect;
65
+ private pageResizeObserver: ResizeObserver | null = null;
65
66
 
66
67
  constructor(config: StageCoreConfig) {
67
68
  super();
@@ -75,8 +76,8 @@ export default class StageCore extends EventEmitter {
75
76
  this.containerHighlightDuration = config.containerHighlightDuration || 800;
76
77
  this.containerHighlightType = config.containerHighlightType;
77
78
 
78
- this.renderer = new StageRender({ core: this });
79
- this.mask = new StageMask({ core: this });
79
+ this.renderer = new StageRender({ runtimeUrl: config.runtimeUrl, render: this.render.bind(this) });
80
+ this.mask = new StageMask();
80
81
  this.dr = new StageDragResize({ core: this, container: this.mask.content, mask: this.mask });
81
82
  this.multiDr = new StageMultiDragResize({ core: this, container: this.mask.content, mask: this.mask });
82
83
  this.highlightLayer = new StageHighlight({ core: this, container: this.mask.wrapper });
@@ -86,6 +87,7 @@ export default class StageCore extends EventEmitter {
86
87
  });
87
88
  this.renderer.on('page-el-update', (el: HTMLElement) => {
88
89
  this.mask?.observe(el);
90
+ this.observePageResize(el);
89
91
  });
90
92
 
91
93
  this.mask
@@ -144,6 +146,9 @@ export default class StageCore extends EventEmitter {
144
146
  })
145
147
  .on('sort', (data: UpdateEventData) => {
146
148
  setTimeout(() => this.emit('sort', data));
149
+ })
150
+ .on('select-parent', () => {
151
+ this.emit('select-parent');
147
152
  });
148
153
 
149
154
  this.multiDr
@@ -160,7 +165,6 @@ export default class StageCore extends EventEmitter {
160
165
  public getElementsFromPoint(event: MouseEvent) {
161
166
  const { renderer, zoom } = this;
162
167
 
163
- const doc = renderer.contentWindow?.document;
164
168
  let x = event.clientX;
165
169
  let y = event.clientY;
166
170
 
@@ -172,7 +176,7 @@ export default class StageCore extends EventEmitter {
172
176
  }
173
177
  }
174
178
 
175
- return doc?.elementsFromPoint(x / zoom, y / zoom) as HTMLElement[];
179
+ return renderer.getDocument()?.elementsFromPoint(x / zoom, y / zoom) as HTMLElement[];
176
180
  }
177
181
 
178
182
  public async getElementFromPoint(event: MouseEvent) {
@@ -220,15 +224,16 @@ export default class StageCore extends EventEmitter {
220
224
  this.dr.select(el, event);
221
225
 
222
226
  if (this.config.autoScrollIntoView || el.dataset.autoScrollIntoView) {
223
- this.mask.intersectionObserver?.observe(el);
227
+ this.mask.observerIntersection(el);
224
228
  }
225
229
 
226
230
  this.selectedDom = el;
227
231
 
228
- if (this.renderer.contentWindow) {
229
- removeSelectedClassName(this.renderer.contentWindow.document);
232
+ const doc = this.renderer.getDocument();
233
+ if (doc) {
234
+ removeSelectedClassName(doc);
230
235
  if (this.selectedDom) {
231
- addSelectedClassName(this.selectedDom, this.renderer.contentWindow.document);
236
+ addSelectedClassName(this.selectedDom, doc);
232
237
  }
233
238
  }
234
239
  }
@@ -254,7 +259,7 @@ export default class StageCore extends EventEmitter {
254
259
  runtime?.update?.(data);
255
260
  // 更新配置后,需要等组件渲染更新
256
261
  setTimeout(() => {
257
- const el = this.renderer.contentWindow?.document.getElementById(`${config.id}`);
262
+ const el = this.renderer.getDocument()?.getElementById(`${config.id}`);
258
263
  // 有可能dom已经重新渲染,不再是原来的dom了,所以这里判断id,而不是判断el === this.selectedDom
259
264
  if (el && el.id === this.selectedDom?.id) {
260
265
  this.selectedDom = el;
@@ -337,7 +342,7 @@ export default class StageCore extends EventEmitter {
337
342
  public async addContainerHighlightClassName(event: MouseEvent, exclude: Element[]) {
338
343
  const els = this.getElementsFromPoint(event);
339
344
  const { renderer } = this;
340
- const doc = renderer.contentWindow?.document;
345
+ const doc = renderer.getDocument();
341
346
 
342
347
  if (!doc) return;
343
348
 
@@ -359,21 +364,49 @@ export default class StageCore extends EventEmitter {
359
364
  * 销毁实例
360
365
  */
361
366
  public destroy(): void {
362
- const { mask, renderer, dr, highlightLayer } = this;
367
+ const { mask, renderer, dr, highlightLayer, pageResizeObserver } = this;
363
368
 
364
369
  renderer.destroy();
365
370
  mask.destroy();
366
371
  dr.destroy();
367
372
  highlightLayer.destroy();
373
+ pageResizeObserver?.disconnect();
368
374
 
369
375
  this.removeAllListeners();
370
376
 
371
377
  this.container = undefined;
372
378
  }
373
379
 
380
+ /**
381
+ * 监听页面大小变化
382
+ */
383
+ private observePageResize(page: HTMLElement): void {
384
+ if (typeof ResizeObserver !== 'undefined') {
385
+ this.pageResizeObserver = new ResizeObserver((entries) => {
386
+ this.mask.pageResize(entries);
387
+
388
+ if (this.dr.moveable) {
389
+ this.dr.updateMoveable();
390
+ }
391
+ });
392
+
393
+ this.pageResizeObserver.observe(page);
394
+ }
395
+ }
396
+
397
+ /**
398
+ * 传入stageRender供其回调,获取业务方自定义渲染画布页面渲染结果
399
+ */
400
+ private async render(): Promise<HTMLElement | null> {
401
+ if (this.config?.render) {
402
+ return await this.config.render(this);
403
+ }
404
+ return null;
405
+ }
406
+
374
407
  private async getTargetElement(idOrEl: Id | HTMLElement): Promise<HTMLElement> {
375
408
  if (typeof idOrEl === 'string' || typeof idOrEl === 'number') {
376
- const el = this.renderer.contentWindow?.document.getElementById(`${idOrEl}`);
409
+ const el = this.renderer.getDocument()?.getElementById(`${idOrEl}`);
377
410
  if (!el) throw new Error(`不存在ID为${idOrEl}的元素`);
378
411
  return el;
379
412
  }
@@ -27,6 +27,7 @@ import MoveableHelper from 'moveable-helper';
27
27
  import { removeClassNameByClassName } from '@tmagic/utils';
28
28
 
29
29
  import { DRAG_EL_ID_PREFIX, GHOST_EL_ID_PREFIX, GuidesType, Mode, ZIndex } from './const';
30
+ import selectParentAbles from './MoveableSelectParentAble';
30
31
  import StageCore from './StageCore';
31
32
  import StageMask from './StageMask';
32
33
  import type { StageDragResizeConfig } from './types';
@@ -593,6 +594,13 @@ export default class StageDragResize extends EventEmitter {
593
594
  bottom: isSortable ? undefined : this.container.clientHeight,
594
595
  ...(moveableOptions.bounds || {}),
595
596
  },
597
+
598
+ props: {
599
+ selectParent: true,
600
+ },
601
+
602
+ ables: [selectParentAbles(this)],
603
+
596
604
  ...options,
597
605
  ...moveableOptions,
598
606
  };
package/src/StageMask.ts CHANGED
@@ -23,9 +23,7 @@ import { createDiv, injectStyle } from '@tmagic/utils';
23
23
 
24
24
  import { Mode, MouseButton, ZIndex } from './const';
25
25
  import Rule from './Rule';
26
- import type StageCore from './StageCore';
27
- import type { StageMaskConfig } from './types';
28
- import { getScrollParent, isFixedParent } from './util';
26
+ import { getScrollParent, isFixedParent, isMoveableButton } from './util';
29
27
 
30
28
  const wrapperClassName = 'editor-mask-wrapper';
31
29
  const throttleTime = 100;
@@ -71,9 +69,7 @@ const createWrapper = (): HTMLDivElement => {
71
69
  export default class StageMask extends Rule {
72
70
  public content: HTMLDivElement = createContent();
73
71
  public wrapper: HTMLDivElement;
74
- public core: StageCore;
75
72
  public page: HTMLElement | null = null;
76
- public pageScrollParent: HTMLElement | null = null;
77
73
  public scrollTop = 0;
78
74
  public scrollLeft = 0;
79
75
  public width = 0;
@@ -82,12 +78,13 @@ export default class StageMask extends Rule {
82
78
  public wrapperWidth = 0;
83
79
  public maxScrollTop = 0;
84
80
  public maxScrollLeft = 0;
85
- public intersectionObserver: IntersectionObserver | null = null;
86
81
  public isMultiSelectStatus: Boolean = false;
87
82
 
88
83
  private mode: Mode = Mode.ABSOLUTE;
89
- private pageResizeObserver: ResizeObserver | null = null;
84
+ private pageScrollParent: HTMLElement | null = null;
85
+ private intersectionObserver: IntersectionObserver | null = null;
90
86
  private wrapperResizeObserver: ResizeObserver | null = null;
87
+
91
88
  /**
92
89
  * 高亮事件处理函数
93
90
  * @param event 事件对象
@@ -96,35 +93,16 @@ export default class StageMask extends Rule {
96
93
  this.emit('highlight', event);
97
94
  }, throttleTime);
98
95
 
99
- constructor(config: StageMaskConfig) {
96
+ constructor() {
100
97
  const wrapper = createWrapper();
101
98
  super(wrapper);
102
99
 
103
100
  this.wrapper = wrapper;
104
- this.core = config.core;
105
101
 
106
- this.content.addEventListener('mousedown', this.mouseDownHandler);
102
+ this.initContentEventListener();
107
103
  this.wrapper.appendChild(this.content);
108
- this.content.addEventListener('wheel', this.mouseWheelHandler);
109
- this.content.addEventListener('mousemove', this.highlightHandler);
110
- this.content.addEventListener('mouseleave', this.mouseLeaveHandler);
111
-
112
- const isMac = /mac os x/.test(navigator.userAgent.toLowerCase());
113
-
114
- const ctrl = isMac ? 'meta' : 'ctrl';
115
104
 
116
- KeyController.global.keydown(ctrl, (e) => {
117
- e.inputEvent.preventDefault();
118
- this.isMultiSelectStatus = true;
119
- });
120
- // ctrl+tab切到其他窗口,需要将多选状态置为false
121
- KeyController.global.on('blur', () => {
122
- this.isMultiSelectStatus = false;
123
- });
124
- KeyController.global.keyup(ctrl, (e) => {
125
- e.inputEvent.preventDefault();
126
- this.isMultiSelectStatus = false;
127
- });
105
+ this.initMultiSelectEvent();
128
106
  }
129
107
 
130
108
  public setMode(mode: Mode) {
@@ -140,63 +118,37 @@ export default class StageMask extends Rule {
140
118
  }
141
119
 
142
120
  /**
143
- * 监听页面大小变化
144
- * @description 同步页面与mask的大小
121
+ * 初始化视窗和蒙层监听,监听元素是否在视窗区域、监听mask蒙层所在的wrapper大小变化
122
+ * @description 初始化视窗和蒙层监听
145
123
  * @param page 页面Dom节点
146
124
  */
147
125
  public observe(page: HTMLElement): void {
148
126
  if (!page) return;
149
127
 
150
128
  this.page = page;
151
- this.pageScrollParent = getScrollParent(page) || this.core.renderer.contentWindow?.document.documentElement || null;
152
- this.pageResizeObserver?.disconnect();
153
- this.wrapperResizeObserver?.disconnect();
154
- this.intersectionObserver?.disconnect();
155
-
156
- if (typeof IntersectionObserver !== 'undefined') {
157
- this.intersectionObserver = new IntersectionObserver(
158
- (entries) => {
159
- entries.forEach((entry) => {
160
- const { target, intersectionRatio } = entry;
161
- if (intersectionRatio <= 0) {
162
- this.scrollIntoView(target);
163
- }
164
- this.intersectionObserver?.unobserve(target);
165
- });
166
- },
167
- {
168
- root: this.pageScrollParent,
169
- rootMargin: '0px',
170
- threshold: 1.0,
171
- },
172
- );
173
- }
174
-
175
- if (typeof ResizeObserver !== 'undefined') {
176
- this.pageResizeObserver = new ResizeObserver((entries) => {
177
- const [entry] = entries;
178
- const { clientHeight, clientWidth } = entry.target;
179
- this.setHeight(clientHeight);
180
- this.setWidth(clientWidth);
129
+ this.initObserverIntersection();
130
+ this.initObserverWrapper();
131
+ }
181
132
 
182
- this.scroll();
183
- if (this.core.dr.moveable) {
184
- this.core.dr.updateMoveable();
185
- }
186
- });
133
+ /**
134
+ * 处理页面大小变更,同步页面和mask大小
135
+ * @param entries ResizeObserverEntry,获取页面最新大小
136
+ */
137
+ public pageResize(entries: ResizeObserverEntry[]): void {
138
+ const [entry] = entries;
139
+ const { clientHeight, clientWidth } = entry.target;
140
+ this.setHeight(clientHeight);
141
+ this.setWidth(clientWidth);
187
142
 
188
- this.pageResizeObserver.observe(page);
143
+ this.scroll();
144
+ }
189
145
 
190
- this.wrapperResizeObserver = new ResizeObserver((entries) => {
191
- const [entry] = entries;
192
- const { clientHeight, clientWidth } = entry.target;
193
- this.wrapperHeight = clientHeight;
194
- this.wrapperWidth = clientWidth;
195
- this.setMaxScrollLeft();
196
- this.setMaxScrollTop();
197
- });
198
- this.wrapperResizeObserver.observe(this.wrapper);
199
- }
146
+ /**
147
+ * 监听一个组件是否在画布可视区域内
148
+ * @param el 被选中的组件,可能是左侧目录树中选中的
149
+ */
150
+ public observerIntersection(el: HTMLElement): void {
151
+ this.intersectionObserver?.observe(el);
200
152
  }
201
153
 
202
154
  /**
@@ -228,13 +180,89 @@ export default class StageMask extends Rule {
228
180
  this.content?.remove();
229
181
  this.page = null;
230
182
  this.pageScrollParent = null;
231
- this.pageResizeObserver?.disconnect();
232
183
  this.wrapperResizeObserver?.disconnect();
233
184
 
234
185
  this.content.removeEventListener('mouseleave', this.mouseLeaveHandler);
235
186
  super.destroy();
236
187
  }
237
188
 
189
+ /**
190
+ * 初始化content的事件监听
191
+ */
192
+ private initContentEventListener(): void {
193
+ this.content.addEventListener('mousedown', this.mouseDownHandler);
194
+ this.content.addEventListener('wheel', this.mouseWheelHandler);
195
+ this.content.addEventListener('mousemove', this.highlightHandler);
196
+ this.content.addEventListener('mouseleave', this.mouseLeaveHandler);
197
+ }
198
+
199
+ /**
200
+ * 初始化多选事件监听
201
+ */
202
+ private initMultiSelectEvent(): void {
203
+ const isMac = /mac os x/.test(navigator.userAgent.toLowerCase());
204
+
205
+ const ctrl = isMac ? 'meta' : 'ctrl';
206
+
207
+ KeyController.global.keydown(ctrl, (e) => {
208
+ e.inputEvent.preventDefault();
209
+ this.isMultiSelectStatus = true;
210
+ });
211
+ // ctrl+tab切到其他窗口,需要将多选状态置为false
212
+ KeyController.global.on('blur', () => {
213
+ this.isMultiSelectStatus = false;
214
+ });
215
+ KeyController.global.keyup(ctrl, (e) => {
216
+ e.inputEvent.preventDefault();
217
+ this.isMultiSelectStatus = false;
218
+ });
219
+ }
220
+
221
+ /**
222
+ * 监听选中元素是否在画布可视区域内,如果目标元素不在可视区域内,通过滚动使该元素出现在可视区域
223
+ */
224
+ private initObserverIntersection(): void {
225
+ this.pageScrollParent = getScrollParent(this.page as HTMLElement) || null;
226
+ this.intersectionObserver?.disconnect();
227
+
228
+ if (typeof IntersectionObserver !== 'undefined') {
229
+ this.intersectionObserver = new IntersectionObserver(
230
+ (entries) => {
231
+ entries.forEach((entry) => {
232
+ const { target, intersectionRatio } = entry;
233
+ if (intersectionRatio <= 0) {
234
+ this.scrollIntoView(target);
235
+ }
236
+ this.intersectionObserver?.unobserve(target);
237
+ });
238
+ },
239
+ {
240
+ root: this.pageScrollParent,
241
+ rootMargin: '0px',
242
+ threshold: 1.0,
243
+ },
244
+ );
245
+ }
246
+ }
247
+
248
+ /**
249
+ * 监听mask的容器大小变化
250
+ */
251
+ private initObserverWrapper(): void {
252
+ this.wrapperResizeObserver?.disconnect();
253
+ if (typeof ResizeObserver !== 'undefined') {
254
+ this.wrapperResizeObserver = new ResizeObserver((entries) => {
255
+ const [entry] = entries;
256
+ const { clientHeight, clientWidth } = entry.target;
257
+ this.wrapperHeight = clientHeight;
258
+ this.wrapperWidth = clientWidth;
259
+ this.setMaxScrollLeft();
260
+ this.setMaxScrollTop();
261
+ });
262
+ this.wrapperResizeObserver.observe(this.wrapper);
263
+ }
264
+ }
265
+
238
266
  private scroll() {
239
267
  this.fixScrollValue();
240
268
 
@@ -315,13 +343,16 @@ export default class StageMask extends Rule {
315
343
  event.stopPropagation();
316
344
 
317
345
  if (event.button !== MouseButton.LEFT && event.button !== MouseButton.RIGHT) return;
346
+ if (!event.target) return;
347
+
348
+ const targetClassList = (event.target as HTMLDivElement).classList;
318
349
 
319
350
  // 如果单击多选选中区域,则不需要再触发选中了,而可能是拖动行为
320
- if (!this.isMultiSelectStatus && (event.target as HTMLDivElement).className.indexOf('moveable-area') !== -1) {
351
+ if (!this.isMultiSelectStatus && targetClassList.contains('moveable-area')) {
321
352
  return;
322
353
  }
323
- // 点击对象如果是边框锚点,则可能是resize
324
- if ((event.target as HTMLDivElement).className.indexOf('moveable-control') !== -1) {
354
+ // 点击对象如果是边框锚点,则可能是resize; 点击对象是功能按钮
355
+ if (targetClassList.contains('moveable-control') || isMoveableButton(event.target as Element)) {
325
356
  return;
326
357
  }
327
358
 
@@ -20,7 +20,6 @@ import { EventEmitter } from 'events';
20
20
 
21
21
  import { getHost, injectStyle, isSameDomain } from '@tmagic/utils';
22
22
 
23
- import StageCore from './StageCore';
24
23
  import style from './style.css?raw';
25
24
  import type { Runtime, RuntimeWindow, StageRenderConfig } from './types';
26
25
 
@@ -34,16 +33,13 @@ export default class StageRender extends EventEmitter {
34
33
 
35
34
  public runtimeUrl?: string;
36
35
 
37
- public core: StageCore;
36
+ private render?: () => Promise<HTMLElement | null>;
38
37
 
39
- private render?: (renderer: StageCore) => Promise<HTMLElement> | HTMLElement;
40
-
41
- constructor({ core }: StageRenderConfig) {
38
+ constructor({ runtimeUrl, render }: StageRenderConfig) {
42
39
  super();
43
40
 
44
- this.core = core;
45
- this.runtimeUrl = core.config.runtimeUrl || '';
46
- this.render = core.config.render;
41
+ this.runtimeUrl = runtimeUrl || '';
42
+ this.render = render;
47
43
 
48
44
  this.iframe = globalThis.document.createElement('iframe');
49
45
  // 同源,直接加载
@@ -101,6 +97,10 @@ export default class StageRender extends EventEmitter {
101
97
  });
102
98
  };
103
99
 
100
+ public getDocument(): Document | undefined {
101
+ return this.contentWindow?.document;
102
+ }
103
+
104
104
  /**
105
105
  * 销毁实例
106
106
  */
@@ -120,7 +120,7 @@ export default class StageRender extends EventEmitter {
120
120
  if (!this.contentWindow) return;
121
121
 
122
122
  if (this.render) {
123
- const el = await this.render(this.core);
123
+ const el = await this.render();
124
124
  if (el) {
125
125
  this.contentWindow.document?.body?.appendChild(el);
126
126
  }
package/src/types.ts CHANGED
@@ -54,7 +54,8 @@ export type StageCoreConfig = {
54
54
  };
55
55
 
56
56
  export interface StageRenderConfig {
57
- core: StageCore;
57
+ runtimeUrl?: string;
58
+ render?: () => Promise<HTMLElement | null>;
58
59
  }
59
60
 
60
61
  export interface StageMaskConfig {
package/src/util.ts CHANGED
@@ -119,6 +119,9 @@ export const getScrollParent = (element: HTMLElement, includeHidden = false): HT
119
119
 
120
120
  for (let parent = element; parent.parentElement; ) {
121
121
  parent = parent.parentElement;
122
+
123
+ if (parent.tagName === 'HTML') return parent;
124
+
122
125
  style = getComputedStyle(parent);
123
126
 
124
127
  if (isAbsolute(style) && isStatic(style)) continue;
@@ -229,3 +232,6 @@ export const up = (deltaTop: number, target: HTMLElement | SVGElement): SortEven
229
232
  dist: upEls.length && swapIndex > -1 ? upEls[swapIndex].id : target.id,
230
233
  };
231
234
  };
235
+
236
+ export const isMoveableButton = (target: Element) =>
237
+ target.classList.contains('moveable-button') || target.parentElement?.classList.contains('moveable-button');
@@ -0,0 +1,9 @@
1
+ import { MoveableManagerInterface, Renderer } from 'moveable';
2
+ import type StageDragResize from './StageDragResize';
3
+ declare const _default: (dr: StageDragResize) => {
4
+ name: string;
5
+ props: {};
6
+ events: {};
7
+ render(moveable: MoveableManagerInterface<any, any>, React: Renderer): any;
8
+ };
9
+ export default _default;
package/types/Rule.d.ts CHANGED
@@ -8,12 +8,13 @@ export default class Rule extends EventEmitter {
8
8
  verticalGuidelines: number[];
9
9
  private container;
10
10
  private containerResizeObserver;
11
+ private isShowGuides;
11
12
  constructor(container: HTMLDivElement);
12
13
  /**
13
- * 是否显示标尺
14
- * @param show 是否显示
14
+ * 是否显示辅助线
15
+ * @param isShowGuides 是否显示
15
16
  */
16
- showGuides(show?: boolean): void;
17
+ showGuides(isShowGuides?: boolean): void;
17
18
  setGuides([hLines, vLines]: [number[], number[]]): void;
18
19
  /**
19
20
  * 清空所有参考线