@tmagic/stage 1.0.0-beta.8 → 1.0.0-rc.2

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.
@@ -2,7 +2,9 @@ import { MoveableOptions } from 'react-moveable/declaration/types';
2
2
  import { Id, MApp, MNode } from '@tmagic/schema';
3
3
  import { GuidesType } from './const';
4
4
  import StageCore from './StageCore';
5
- export declare type CanSelect = (el: HTMLElement, stop: () => boolean) => boolean | Promise<boolean>;
5
+ import StageDragResize from './StageDragResize';
6
+ import StageMask from './StageMask';
7
+ export declare type CanSelect = (el: HTMLElement, event: MouseEvent, stop: () => boolean) => boolean | Promise<boolean>;
6
8
  export declare type StageCoreConfig = {
7
9
  /** 需要对齐的dom节点的CSS选择器字符串 */
8
10
  snapElementQuerySelector?: string;
@@ -61,7 +63,7 @@ export interface RemoveData {
61
63
  }
62
64
  export interface Runtime {
63
65
  beforeSelect?: (el: HTMLElement) => Promise<boolean> | boolean;
64
- getSnapElements?: (el: HTMLElement) => HTMLElement[];
66
+ getSnapElements?: (el?: HTMLElement) => HTMLElement[];
65
67
  updateRootConfig: (config: MApp) => void;
66
68
  updatePageId?: (id: Id) => void;
67
69
  select?: (id: Id) => Promise<HTMLElement> | HTMLElement;
@@ -78,3 +80,12 @@ export interface Magic {
78
80
  export interface RuntimeWindow extends Window {
79
81
  magic: Magic;
80
82
  }
83
+ export interface StageHighlightConfig {
84
+ core: StageCore;
85
+ container: HTMLElement;
86
+ }
87
+ export interface TargetCalibrateConfig {
88
+ parent: HTMLElement;
89
+ mask: StageMask;
90
+ dr: StageDragResize;
91
+ }
@@ -18,3 +18,5 @@ export declare const createDiv: ({ className, cssText }: {
18
18
  className: string;
19
19
  cssText: string;
20
20
  }) => HTMLDivElement;
21
+ export declare const removeSelectedClassName: (doc: Document) => void;
22
+ export declare const addSelectedClassName: (el: Element, doc: Document) => void;
package/package.json CHANGED
@@ -1,7 +1,9 @@
1
1
  {
2
- "version": "1.0.0-beta.8",
2
+ "version": "1.0.0-rc.2",
3
3
  "name": "@tmagic/stage",
4
- "sideEffects": false,
4
+ "sideEffects": [
5
+ "dist/*"
6
+ ],
5
7
  "main": "dist/tmagic-stage.umd.js",
6
8
  "module": "dist/tmagic-stage.es.js",
7
9
  "types": "dist/types/src/index.d.ts",
@@ -9,8 +11,10 @@
9
11
  ".": {
10
12
  "import": "./dist/tmagic-stage.es.js",
11
13
  "require": "./dist/tmagic-stage.umd.js"
12
- }
14
+ },
15
+ "./*": "./*"
13
16
  },
17
+ "license": "Apache-2.0",
14
18
  "scripts": {
15
19
  "build": "vite build"
16
20
  },
@@ -23,11 +27,12 @@
23
27
  },
24
28
  "dependencies": {
25
29
  "@scena/guides": "^0.17.0",
26
- "@tmagic/schema": "^1.0.0-beta.8",
27
- "@tmagic/utils": "^1.0.0-beta.8",
30
+ "@tmagic/schema": "^1.0.0-rc.2",
31
+ "@tmagic/utils": "^1.0.0-rc.2",
28
32
  "events": "^3.3.0",
29
33
  "lodash-es": "^4.17.21",
30
- "moveable": "^0.28.0"
34
+ "moveable": "^0.29.4",
35
+ "moveable-helper": "^0.4.0"
31
36
  },
32
37
  "devDependencies": {
33
38
  "@types/events": "^3.0.0",
@@ -38,5 +43,5 @@
38
43
  "vite": "^2.3.7",
39
44
  "vite-plugin-dts": "^0.9.6"
40
45
  },
41
- "gitHead": "ff8e32901775ecc145a82f906d6af6119652d61e"
46
+ "gitHead": "3e309780ed33640ab3fc986a93dd0e7b15c167e5"
42
47
  }
package/src/StageCore.ts CHANGED
@@ -22,6 +22,7 @@ import { Id } from '@tmagic/schema';
22
22
 
23
23
  import { DEFAULT_ZOOM, GHOST_EL_ID_PREFIX } from './const';
24
24
  import StageDragResize from './StageDragResize';
25
+ import StageHighlight from './StageHighlight';
25
26
  import StageMask from './StageMask';
26
27
  import StageRender from './StageRender';
27
28
  import {
@@ -34,15 +35,19 @@ import {
34
35
  UpdateData,
35
36
  UpdateEventData,
36
37
  } from './types';
38
+ import { addSelectedClassName, removeSelectedClassName } from './util';
37
39
 
38
40
  export default class StageCore extends EventEmitter {
39
41
  public selectedDom: Element | undefined;
42
+ public highlightedDom: Element | undefined;
40
43
 
41
44
  public renderer: StageRender;
42
45
  public mask: StageMask;
43
46
  public dr: StageDragResize;
47
+ public highlightLayer: StageHighlight;
44
48
  public config: StageCoreConfig;
45
49
  public zoom = DEFAULT_ZOOM;
50
+ public container?: HTMLDivElement;
46
51
  private canSelect: CanSelect;
47
52
 
48
53
  constructor(config: StageCoreConfig) {
@@ -56,9 +61,14 @@ export default class StageCore extends EventEmitter {
56
61
  this.renderer = new StageRender({ core: this });
57
62
  this.mask = new StageMask({ core: this });
58
63
  this.dr = new StageDragResize({ core: this, container: this.mask.content });
64
+ this.highlightLayer = new StageHighlight({ core: this, container: this.mask.wrapper });
59
65
 
60
- this.renderer.on('runtime-ready', (runtime: Runtime) => this.emit('runtime-ready', runtime));
61
- this.renderer.on('page-el-update', (el: HTMLElement) => this.mask?.observe(el));
66
+ this.renderer.on('runtime-ready', (runtime: Runtime) => {
67
+ this.emit('runtime-ready', runtime);
68
+ });
69
+ this.renderer.on('page-el-update', (el: HTMLElement) => {
70
+ this.mask?.observe(el);
71
+ });
62
72
 
63
73
  this.mask
64
74
  .on('beforeSelect', (event: MouseEvent) => {
@@ -70,6 +80,18 @@ export default class StageCore extends EventEmitter {
70
80
  .on('changeGuides', (data: GuidesEventData) => {
71
81
  this.dr.setGuidelines(data.type, data.guides);
72
82
  this.emit('changeGuides', data);
83
+ })
84
+ .on('highlight', async (event: MouseEvent) => {
85
+ await this.setElementFromPoint(event);
86
+ if (this.highlightedDom === this.selectedDom) {
87
+ this.highlightLayer.clearHighlight();
88
+ return;
89
+ }
90
+ this.highlightLayer.highlight(this.highlightedDom as HTMLElement);
91
+ this.emit('highlight', this.highlightedDom);
92
+ })
93
+ .on('clearHighlight', async () => {
94
+ this.highlightLayer.clearHighlight();
73
95
  });
74
96
 
75
97
  // 要先触发select,在触发update
@@ -102,8 +124,12 @@ export default class StageCore extends EventEmitter {
102
124
  let stopped = false;
103
125
  const stop = () => (stopped = true);
104
126
  for (const el of els) {
105
- if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && (await this.canSelect(el, stop))) {
127
+ if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && (await this.canSelect(el, event, stop))) {
106
128
  if (stopped) break;
129
+ if (event.type === 'mousemove') {
130
+ this.highlight(el);
131
+ break;
132
+ }
107
133
  this.select(el, event);
108
134
  break;
109
135
  }
@@ -115,58 +141,82 @@ export default class StageCore extends EventEmitter {
115
141
  * @param idOrEl 组件Dom节点的id属性,或者Dom节点
116
142
  */
117
143
  public async select(idOrEl: Id | HTMLElement, event?: MouseEvent): Promise<void> {
118
- let el;
119
- if (typeof idOrEl === 'string' || typeof idOrEl === 'number') {
120
- const runtime = await this.renderer?.getRuntime();
121
- el = await runtime?.select?.(`${idOrEl}`);
122
- if (!el) throw new Error(`不存在ID为${idOrEl}的元素`);
123
- } else {
124
- el = idOrEl;
125
- }
144
+ const el = await this.getTargetElement(idOrEl);
126
145
 
127
146
  if (el === this.selectedDom) return;
128
147
 
129
- const runtime = await this.renderer?.getRuntime();
148
+ const runtime = await this.renderer.getRuntime();
149
+
150
+ await runtime?.select?.(el.id);
151
+
130
152
  if (runtime?.beforeSelect) {
131
153
  await runtime.beforeSelect(el);
132
154
  }
133
155
 
134
156
  this.mask.setLayout(el);
135
- this.dr?.select(el, event);
157
+ this.dr.select(el, event);
158
+ this.mask.scrollIntoView(el);
159
+
136
160
  this.selectedDom = el;
161
+
162
+ if (this.renderer.contentWindow) {
163
+ removeSelectedClassName(this.renderer.contentWindow.document);
164
+ if (this.selectedDom) {
165
+ addSelectedClassName(this.selectedDom, this.renderer.contentWindow.document);
166
+ }
167
+ }
137
168
  }
138
169
 
139
170
  /**
140
171
  * 更新选中的节点
141
172
  * @param data 更新的数据
142
173
  */
143
- public update(data: UpdateData): void {
174
+ public update(data: UpdateData): Promise<void> {
144
175
  const { config } = data;
145
176
 
146
- this.renderer?.getRuntime().then((runtime) => {
177
+ return this.renderer?.getRuntime().then((runtime) => {
147
178
  runtime?.update?.(data);
148
179
  // 更新配置后,需要等组件渲染更新
149
180
  setTimeout(() => {
150
181
  const el = this.renderer.contentWindow?.document.getElementById(`${config.id}`);
151
- if (el) {
182
+ // 有可能dom已经重新渲染,不再是原来的dom了,所以这里判断id,而不是判断el === this.selectedDom
183
+ if (el && el.id === this.selectedDom?.id) {
184
+ this.selectedDom = el;
152
185
  // 更新了组件的布局,需要重新设置mask是否可以滚动
153
186
  this.mask.setLayout(el);
154
- this.dr?.select(el);
187
+ this.dr.updateMoveable(el);
155
188
  }
156
189
  }, 0);
157
190
  });
158
191
  }
159
192
 
160
- public sortNode(data: SortEventData): void {
161
- this.renderer?.getRuntime().then((runtime) => runtime?.sortNode?.(data));
193
+ /**
194
+ * 高亮选中组件
195
+ * @param el 页面Dom节点
196
+ */
197
+ public async highlight(idOrEl: HTMLElement | Id): Promise<void> {
198
+ let el;
199
+ try {
200
+ el = await this.getTargetElement(idOrEl);
201
+ } catch (error) {
202
+ this.highlightLayer.clearHighlight();
203
+ return;
204
+ }
205
+ if (el === this.highlightedDom) return;
206
+ this.highlightLayer.highlight(el);
207
+ this.highlightedDom = el;
208
+ }
209
+
210
+ public sortNode(data: SortEventData): Promise<void> {
211
+ return this.renderer?.getRuntime().then((runtime) => runtime?.sortNode?.(data));
162
212
  }
163
213
 
164
- public add(data: UpdateData): void {
165
- this.renderer?.getRuntime().then((runtime) => runtime?.add?.(data));
214
+ public add(data: UpdateData): Promise<void> {
215
+ return this.renderer?.getRuntime().then((runtime) => runtime?.add?.(data));
166
216
  }
167
217
 
168
- public remove(data: RemoveData): void {
169
- this.renderer?.getRuntime().then((runtime) => runtime?.remove?.(data));
218
+ public remove(data: RemoveData): Promise<void> {
219
+ return this.renderer?.getRuntime().then((runtime) => runtime?.remove?.(data));
170
220
  }
171
221
 
172
222
  public setZoom(zoom: number = DEFAULT_ZOOM): void {
@@ -178,6 +228,7 @@ export default class StageCore extends EventEmitter {
178
228
  * @param el 将stage挂载到该Dom节点上
179
229
  */
180
230
  public mount(el: HTMLDivElement): void {
231
+ this.container = el;
181
232
  const { mask, renderer } = this;
182
233
 
183
234
  renderer.mount(el);
@@ -198,12 +249,24 @@ export default class StageCore extends EventEmitter {
198
249
  * 销毁实例
199
250
  */
200
251
  public destroy(): void {
201
- const { mask, renderer, dr } = this;
252
+ const { mask, renderer, dr, highlightLayer } = this;
202
253
 
203
254
  renderer.destroy();
204
255
  mask.destroy();
205
256
  dr.destroy();
257
+ highlightLayer.destroy();
206
258
 
207
259
  this.removeAllListeners();
260
+
261
+ this.container = undefined;
262
+ }
263
+
264
+ private async getTargetElement(idOrEl: Id | HTMLElement): Promise<HTMLElement> {
265
+ if (typeof idOrEl === 'string' || typeof idOrEl === 'number') {
266
+ const el = this.renderer.contentWindow?.document.getElementById(`${idOrEl}`);
267
+ if (!el) throw new Error(`不存在ID为${idOrEl}的元素`);
268
+ return el;
269
+ }
270
+ return idOrEl;
208
271
  }
209
272
  }
@@ -21,10 +21,11 @@ import { EventEmitter } from 'events';
21
21
 
22
22
  import type { MoveableOptions } from 'moveable';
23
23
  import Moveable from 'moveable';
24
+ import MoveableHelper from 'moveable-helper';
24
25
 
25
- import { GHOST_EL_ID_PREFIX, GuidesType, Mode } from './const';
26
+ import { DRAG_EL_ID_PREFIX, GHOST_EL_ID_PREFIX, GuidesType, Mode } from './const';
26
27
  import StageCore from './StageCore';
27
- import type { SortEventData, StageDragResizeConfig } from './types';
28
+ import type { Offset, Runtime, SortEventData, StageDragResizeConfig } from './types';
28
29
  import { getAbsolutePosition, getMode, getOffset } from './util';
29
30
 
30
31
  enum ActionStatus {
@@ -40,21 +41,26 @@ export default class StageDragResize extends EventEmitter {
40
41
  public core: StageCore;
41
42
  public container: HTMLElement;
42
43
  public target?: HTMLElement;
43
- public dragEl?: HTMLElement;
44
+ public dragEl: HTMLElement;
44
45
  public moveable?: Moveable;
45
46
  public horizontalGuidelines: number[] = [];
46
47
  public verticalGuidelines: number[] = [];
48
+ public elementGuidelines: HTMLElement[] = [];
49
+ public mode: Mode = Mode.ABSOLUTE;
47
50
 
48
51
  private moveableOptions: MoveableOptions = {};
49
52
  private dragStatus: ActionStatus = ActionStatus.END;
50
53
  private ghostEl: HTMLElement | undefined;
51
- private mode: Mode = Mode.ABSOLUTE;
54
+ private moveableHelper?: MoveableHelper;
52
55
 
53
56
  constructor(config: StageDragResizeConfig) {
54
57
  super();
55
58
 
56
59
  this.core = config.core;
57
60
  this.container = config.container;
61
+
62
+ this.dragEl = globalThis.document.createElement('div');
63
+ this.container.append(this.dragEl);
58
64
  }
59
65
 
60
66
  /**
@@ -63,23 +69,24 @@ export default class StageDragResize extends EventEmitter {
63
69
  * @param el 选中组件的Dom节点元素
64
70
  * @param event 鼠标事件
65
71
  */
66
- public async select(el: HTMLElement, event?: MouseEvent): Promise<void> {
72
+ public select(el: HTMLElement, event?: MouseEvent): void {
73
+ const oldTarget = this.target;
67
74
  this.target = el;
68
- // 如果有滚动条会导致resize时获取到width,height不准确
69
- if (/(auto|scroll)/.test(this.target.style.overflow)) {
70
- this.target.style.overflow = 'hidden';
71
- }
72
- this.mode = getMode(el);
73
- this.destroyDragEl();
74
- this.destroyGhostEl();
75
75
 
76
- this.dragEl = this.generateDragEl(el);
76
+ this.init(el);
77
77
 
78
- this.moveableOptions = await this.getOptions({
79
- target: this.dragEl || this.target,
80
- });
78
+ // 从不能拖动到能拖动的节点之间切换,要重新创建moveable,不然dragStart不生效
79
+ if (!this.moveable || this.target !== oldTarget) {
80
+ this.moveableHelper = MoveableHelper.create({
81
+ useBeforeRender: true,
82
+ useRender: false,
83
+ createAuto: true,
84
+ });
81
85
 
82
- this.initMoveable();
86
+ this.initMoveable();
87
+ } else {
88
+ this.updateMoveable();
89
+ }
83
90
 
84
91
  if (event) {
85
92
  this.moveable?.dragStart(event);
@@ -89,11 +96,15 @@ export default class StageDragResize extends EventEmitter {
89
96
  /**
90
97
  * 初始化选中框并渲染出来
91
98
  */
92
- public async refresh() {
99
+ public updateMoveable(el = this.target): void {
93
100
  if (!this.moveable) throw new Error('未初始化moveable');
101
+ if (!el) throw new Error('为选中任何节点');
94
102
 
95
- const options = await this.getOptions();
96
- Object.entries(options).forEach(([key, value]) => {
103
+ this.target = el;
104
+
105
+ this.init(el);
106
+
107
+ Object.entries(this.moveableOptions).forEach(([key, value]) => {
97
108
  (this.moveable as any)[key] = value;
98
109
  });
99
110
  this.moveable.updateTarget();
@@ -102,17 +113,21 @@ export default class StageDragResize extends EventEmitter {
102
113
  public setGuidelines(type: GuidesType, guidelines: number[]): void {
103
114
  if (type === GuidesType.HORIZONTAL) {
104
115
  this.horizontalGuidelines = guidelines;
116
+ this.moveableOptions.horizontalGuidelines = guidelines;
105
117
  } else if (type === GuidesType.VERTICAL) {
106
118
  this.verticalGuidelines = guidelines;
119
+ this.moveableOptions.verticalGuidelines = guidelines;
107
120
  }
108
121
 
109
- this.refresh();
122
+ this.updateMoveable();
110
123
  }
111
124
 
112
125
  public clearGuides() {
113
- this.verticalGuidelines = [];
114
126
  this.horizontalGuidelines = [];
115
- this.refresh();
127
+ this.verticalGuidelines = [];
128
+ this.moveableOptions.horizontalGuidelines = [];
129
+ this.moveableOptions.verticalGuidelines = [];
130
+ this.updateMoveable();
116
131
  }
117
132
 
118
133
  /**
@@ -126,6 +141,22 @@ export default class StageDragResize extends EventEmitter {
126
141
  this.removeAllListeners();
127
142
  }
128
143
 
144
+ private init(el: HTMLElement): void {
145
+ // 如果有滚动条会导致resize时获取到width,height不准确
146
+ if (/(auto|scroll)/.test(el.style.overflow)) {
147
+ el.style.overflow = 'hidden';
148
+ }
149
+ this.mode = getMode(el);
150
+
151
+ this.destroyGhostEl();
152
+
153
+ this.updateDragEl(el);
154
+
155
+ this.moveableOptions = this.getOptions({
156
+ target: this.dragEl,
157
+ });
158
+ }
159
+
129
160
  private initMoveable() {
130
161
  this.moveable?.destroy();
131
162
 
@@ -188,34 +219,42 @@ export default class StageDragResize extends EventEmitter {
188
219
  private bindDragEvent(): void {
189
220
  if (!this.moveable) throw new Error('moveable 为初始化');
190
221
 
222
+ let offset: Offset | null = null;
223
+
191
224
  this.moveable
192
- .on('dragStart', () => {
225
+ .on('dragStart', (e) => {
193
226
  if (!this.target) throw new Error('未选中组件');
194
227
 
195
228
  this.dragStatus = ActionStatus.START;
196
229
 
230
+ this.moveableHelper?.onDragStart(e);
231
+
197
232
  if (this.mode === Mode.SORTABLE) {
198
233
  this.ghostEl = this.generateGhostEl(this.target);
199
234
  }
200
235
  })
201
- .on('drag', ({ left, top }) => {
236
+ .on('drag', (e) => {
202
237
  if (!this.target || !this.dragEl) return;
238
+
239
+ if (!offset) {
240
+ offset = getAbsolutePosition(this.target, { left: 0, top: 0 });
241
+ }
242
+
203
243
  this.dragStatus = ActionStatus.ING;
204
244
 
205
- const offset = getAbsolutePosition(this.target, { left, top });
245
+ const { left, top } = e;
206
246
 
207
247
  // 流式布局
208
248
  if (this.ghostEl) {
209
249
  this.dragEl.style.top = `${top}px`;
210
- this.ghostEl.style.top = `${offset.top}px`;
250
+ this.ghostEl.style.top = `${top + offset.top}px`;
211
251
  return;
212
252
  }
213
253
 
214
- this.dragEl.style.left = `${left}px`;
215
- this.dragEl.style.top = `${top}px`;
254
+ this.moveableHelper?.onDrag(e);
216
255
 
217
- this.target.style.left = `${offset.left}px`;
218
- this.target.style.top = `${offset.top}px`;
256
+ this.target.style.left = `${left + offset.left}px`;
257
+ this.target.style.top = `${top + offset.top}px`;
219
258
  })
220
259
  .on('dragEnd', () => {
221
260
  // 点击不拖动时会触发dragStart和dragEnd,但是不会有drag事件
@@ -228,24 +267,23 @@ export default class StageDragResize extends EventEmitter {
228
267
  this.update();
229
268
  }
230
269
  }
270
+ offset = null;
231
271
 
232
272
  this.dragStatus = ActionStatus.END;
233
273
  this.destroyGhostEl();
234
274
  });
235
275
  }
236
276
 
237
- private async getSnapElements(el: HTMLElement): Promise<HTMLElement[]> {
238
- const { renderer } = this.core;
277
+ private getSnapElements(runtime: Runtime, el?: HTMLElement): HTMLElement[] {
278
+ const { renderer, mask } = this.core;
239
279
  const getSnapElements =
240
- (await renderer.getRuntime())?.getSnapElements ||
280
+ runtime?.getSnapElements ||
241
281
  (() => {
242
282
  const doc = renderer.contentWindow?.document;
243
283
  return doc ? Array.from(doc.querySelectorAll('[id]')) : [];
244
284
  });
245
- return (
246
- getSnapElements(el)
247
- // 排除掉当前组件本身
248
- .filter((element) => element !== this.target && !this.target?.contains(element))
285
+ return getSnapElements(el).filter(
286
+ (element) => element !== this.target && !this.target?.contains(element) && element !== mask.page,
249
287
  );
250
288
  }
251
289
 
@@ -291,7 +329,7 @@ export default class StageDragResize extends EventEmitter {
291
329
 
292
330
  const ghostEl = el.cloneNode(true) as HTMLElement;
293
331
  const { top, left } = getAbsolutePosition(el, getOffset(el));
294
- ghostEl.id = `${GHOST_EL_ID_PREFIX}${ghostEl.id}`;
332
+ ghostEl.id = `${GHOST_EL_ID_PREFIX}${el.id}`;
295
333
  ghostEl.style.zIndex = '5';
296
334
  ghostEl.style.opacity = '.5';
297
335
  ghostEl.style.position = 'absolute';
@@ -306,34 +344,31 @@ export default class StageDragResize extends EventEmitter {
306
344
  this.ghostEl = undefined;
307
345
  }
308
346
 
309
- private generateDragEl(el: HTMLElement): HTMLElement {
310
- if (this.dragEl) {
311
- this.destroyDragEl();
312
- }
313
-
347
+ private updateDragEl(el: HTMLElement) {
314
348
  const { width, height } = el.getBoundingClientRect();
315
349
  const offset = getOffset(el);
316
- const dragEl = globalThis.document.createElement('div');
317
- dragEl.style.cssText = `
350
+
351
+ this.dragEl.style.cssText = `
318
352
  position: absolute;
319
353
  left: ${offset.left}px;
320
354
  top: ${offset.top}px;
321
355
  width: ${width}px;
322
356
  height: ${height}px;
357
+ z-index: 9;
323
358
  `;
324
- this.container.append(dragEl);
325
- return dragEl;
359
+
360
+ this.dragEl.id = `${DRAG_EL_ID_PREFIX}${el.id}`;
326
361
  }
327
362
 
328
363
  private destroyDragEl(): void {
329
364
  this.dragEl?.remove();
330
- this.dragEl = undefined;
331
365
  }
332
366
 
333
- private async getOptions(options: MoveableOptions = {}): Promise<MoveableOptions> {
367
+ private getOptions(options: MoveableOptions = {}): MoveableOptions {
334
368
  if (!this.target) return {};
335
369
 
336
370
  const isAbsolute = this.mode === Mode.ABSOLUTE;
371
+ const isFixed = this.mode === Mode.FIXED;
337
372
 
338
373
  let { moveableOptions = {} } = this.core.config;
339
374
 
@@ -342,20 +377,36 @@ export default class StageDragResize extends EventEmitter {
342
377
  }
343
378
 
344
379
  return {
345
- scrollable: true,
346
- origin: true,
380
+ origin: false,
381
+ rootContainer: this.core.container,
347
382
  zoom: 1,
348
- dragArea: true,
383
+ dragArea: false,
349
384
  draggable: true,
350
385
  resizable: true,
351
- snappable: isAbsolute,
352
- snapGap: isAbsolute,
353
- snapDirections: { center: isAbsolute, middle: isAbsolute },
354
- elementSnapDirections: { center: isAbsolute, middle: isAbsolute },
355
-
356
- elementGuidelines: isAbsolute ? await this.getSnapElements(this.target) : [],
386
+ snappable: isAbsolute || isFixed,
387
+ snapGap: isAbsolute || isFixed,
388
+ snapThreshold: 5,
389
+ snapDigit: 0,
390
+ throttleDrag: 0,
391
+ isDisplaySnapDigit: isAbsolute,
392
+ snapDirections: {
393
+ top: isAbsolute,
394
+ right: isAbsolute,
395
+ bottom: isAbsolute,
396
+ left: isAbsolute,
397
+ center: isAbsolute,
398
+ middle: isAbsolute,
399
+ },
400
+ elementSnapDirections: {
401
+ top: isAbsolute,
402
+ right: isAbsolute,
403
+ bottom: isAbsolute,
404
+ left: isAbsolute,
405
+ },
406
+ isDisplayInnerSnapDigit: true,
357
407
  horizontalGuidelines: this.horizontalGuidelines,
358
408
  verticalGuidelines: this.verticalGuidelines,
409
+ elementGuidelines: this.elementGuidelines,
359
410
 
360
411
  bounds: {
361
412
  top: 0,