@tmagic/stage 1.0.0-rc.3 → 1.0.0-rc.6

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.
@@ -1,4 +1,4 @@
1
- import { Mode } from './const';
1
+ import { GuidesType, Mode } from './const';
2
2
  import type { Offset } from './types';
3
3
  export declare const getOffset: (el: HTMLElement) => Offset;
4
4
  export declare const getAbsolutePosition: (el: HTMLElement, { top, left }: Offset) => {
@@ -20,3 +20,4 @@ export declare const createDiv: ({ className, cssText }: {
20
20
  }) => HTMLDivElement;
21
21
  export declare const removeSelectedClassName: (doc: Document) => void;
22
22
  export declare const addSelectedClassName: (el: Element, doc: Document) => void;
23
+ export declare const getGuideLineFromCache: (type: GuidesType) => number[];
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.0.0-rc.3",
2
+ "version": "1.0.0-rc.6",
3
3
  "name": "@tmagic/stage",
4
4
  "sideEffects": [
5
5
  "dist/*"
@@ -27,8 +27,9 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "@scena/guides": "^0.17.0",
30
- "@tmagic/schema": "^1.0.0-rc.3",
31
- "@tmagic/utils": "^1.0.0-rc.3",
30
+ "@tmagic/core": "^1.0.0-rc.6",
31
+ "@tmagic/schema": "^1.0.0-rc.6",
32
+ "@tmagic/utils": "^1.0.0-rc.6",
32
33
  "events": "^3.3.0",
33
34
  "lodash-es": "^4.17.21",
34
35
  "moveable": "^0.29.4",
@@ -43,5 +44,5 @@
43
44
  "vite": "^2.3.7",
44
45
  "vite-plugin-dts": "^0.9.6"
45
46
  },
46
- "gitHead": "d9f6ca25a0a6efba35d183e643a306e164b74af7"
47
+ "gitHead": "a93928e56d73b7924991e899a4dfaf9614cd357c"
47
48
  }
package/src/Rule.ts CHANGED
@@ -2,13 +2,14 @@ import EventEmitter from 'events';
2
2
 
3
3
  import Guides, { GuidesEvents } from '@scena/guides';
4
4
 
5
- import { GuidesType } from './const';
5
+ import { GuidesType, H_GUIDE_LINE_STORAGE_KEY, V_GUIDE_LINE_STORAGE_KEY } from './const';
6
+ import { getGuideLineFromCache } from './util';
6
7
 
7
8
  export default class Rule extends EventEmitter {
8
9
  public hGuides: Guides;
9
10
  public vGuides: Guides;
10
- public horizontalGuidelines: number[] = [];
11
- public verticalGuidelines: number[] = [];
11
+ public horizontalGuidelines: number[] = getGuideLineFromCache(GuidesType.HORIZONTAL);
12
+ public verticalGuidelines: number[] = getGuideLineFromCache(GuidesType.VERTICAL);
12
13
 
13
14
  private container: HTMLDivElement;
14
15
  private containerResizeObserver: ResizeObserver;
@@ -17,8 +18,8 @@ export default class Rule extends EventEmitter {
17
18
  super();
18
19
 
19
20
  this.container = container;
20
- this.hGuides = this.createGuides(GuidesType.HORIZONTAL);
21
- this.vGuides = this.createGuides(GuidesType.VERTICAL);
21
+ this.hGuides = this.createGuides(GuidesType.HORIZONTAL, this.horizontalGuidelines);
22
+ this.vGuides = this.createGuides(GuidesType.VERTICAL, this.verticalGuidelines);
22
23
 
23
24
  this.hGuides.on('changeGuides', this.hGuidesChangeGuidesHandler);
24
25
  this.vGuides.on('changeGuides', this.vGuidesChangeGuidesHandler);
@@ -68,6 +69,9 @@ export default class Rule extends EventEmitter {
68
69
  type: GuidesType.HORIZONTAL,
69
70
  guides: [],
70
71
  });
72
+
73
+ globalThis.localStorage.setItem(V_GUIDE_LINE_STORAGE_KEY, '[]');
74
+ globalThis.localStorage.setItem(H_GUIDE_LINE_STORAGE_KEY, '[]');
71
75
  }
72
76
 
73
77
  /**
@@ -138,6 +142,8 @@ export default class Rule extends EventEmitter {
138
142
  type: GuidesType.HORIZONTAL,
139
143
  guides: this.horizontalGuidelines,
140
144
  });
145
+
146
+ globalThis.localStorage.setItem(H_GUIDE_LINE_STORAGE_KEY, JSON.stringify(e.guides));
141
147
  };
142
148
 
143
149
  private vGuidesChangeGuidesHandler = (e: GuidesEvents['changeGuides']) => {
@@ -146,5 +152,7 @@ export default class Rule extends EventEmitter {
146
152
  type: GuidesType.VERTICAL,
147
153
  guides: this.verticalGuidelines,
148
154
  });
155
+
156
+ globalThis.localStorage.setItem(V_GUIDE_LINE_STORAGE_KEY, JSON.stringify(e.guides));
149
157
  };
150
158
  }
@@ -23,14 +23,18 @@ import type { MoveableOptions } from 'moveable';
23
23
  import Moveable from 'moveable';
24
24
  import MoveableHelper from 'moveable-helper';
25
25
 
26
- import { DRAG_EL_ID_PREFIX, GHOST_EL_ID_PREFIX, GuidesType, Mode } from './const';
26
+ import { DRAG_EL_ID_PREFIX, GHOST_EL_ID_PREFIX, GuidesType, Mode, ZIndex } from './const';
27
27
  import StageCore from './StageCore';
28
- import type { Offset, Runtime, SortEventData, StageDragResizeConfig } from './types';
29
- import { getAbsolutePosition, getMode, getOffset } from './util';
28
+ import type { Offset, SortEventData, StageDragResizeConfig } from './types';
29
+ import { getAbsolutePosition, getGuideLineFromCache, getMode, getOffset } from './util';
30
30
 
31
+ /** 拖动状态 */
31
32
  enum ActionStatus {
33
+ /** 开始拖动 */
32
34
  START = 'start',
35
+ /** 拖动中 */
33
36
  ING = 'ing',
37
+ /** 拖动结束 */
34
38
  END = 'end',
35
39
  }
36
40
 
@@ -39,17 +43,27 @@ enum ActionStatus {
39
43
  */
40
44
  export default class StageDragResize extends EventEmitter {
41
45
  public core: StageCore;
46
+ /** 画布容器 */
42
47
  public container: HTMLElement;
48
+ /** 目标节点 */
43
49
  public target?: HTMLElement;
50
+ /** 目标节点在蒙层中的占位节点 */
44
51
  public dragEl: HTMLElement;
52
+ /** Moveable拖拽类实例 */
45
53
  public moveable?: Moveable;
46
- public horizontalGuidelines: number[] = [];
47
- public verticalGuidelines: number[] = [];
54
+ /** 水平参考线 */
55
+ public horizontalGuidelines: number[] = getGuideLineFromCache(GuidesType.HORIZONTAL);
56
+ /** 垂直参考线 */
57
+ public verticalGuidelines: number[] = getGuideLineFromCache(GuidesType.VERTICAL);
58
+ /** 对齐元素集合 */
48
59
  public elementGuidelines: HTMLElement[] = [];
60
+ /** 布局方式:流式布局、绝对定位、固定定位 */
49
61
  public mode: Mode = Mode.ABSOLUTE;
50
62
 
51
63
  private moveableOptions: MoveableOptions = {};
64
+ /** 拖动状态 */
52
65
  private dragStatus: ActionStatus = ActionStatus.END;
66
+ /** 流式布局下,目标节点的镜像节点 */
53
67
  private ghostEl: HTMLElement | undefined;
54
68
  private moveableHelper?: MoveableHelper;
55
69
 
@@ -157,6 +171,29 @@ export default class StageDragResize extends EventEmitter {
157
171
  });
158
172
  }
159
173
 
174
+ private setElementGuidelines(nodes: HTMLElement[]) {
175
+ this.elementGuidelines.forEach((node) => {
176
+ node.remove();
177
+ });
178
+ this.elementGuidelines = [];
179
+
180
+ if (this.mode === Mode.ABSOLUTE) {
181
+ const frame = document.createDocumentFragment();
182
+
183
+ for (const node of nodes) {
184
+ const { width, height } = node.getBoundingClientRect();
185
+ if (node === this.target) continue;
186
+ const { left, top } = getOffset(node as HTMLElement);
187
+ const elementGuideline = document.createElement('div');
188
+ elementGuideline.style.cssText = `position: absolute;width: ${width}px;height: ${height}px;top: ${top}px;left: ${left}px`;
189
+ this.elementGuidelines.push(elementGuideline);
190
+ frame.append(elementGuideline);
191
+ }
192
+
193
+ this.container.append(frame);
194
+ }
195
+ }
196
+
160
197
  private initMoveable() {
161
198
  this.moveable?.destroy();
162
199
 
@@ -274,19 +311,6 @@ export default class StageDragResize extends EventEmitter {
274
311
  });
275
312
  }
276
313
 
277
- private getSnapElements(runtime: Runtime, el?: HTMLElement): HTMLElement[] {
278
- const { renderer, mask } = this.core;
279
- const getSnapElements =
280
- runtime?.getSnapElements ||
281
- (() => {
282
- const doc = renderer.contentWindow?.document;
283
- return doc ? Array.from(doc.querySelectorAll('[id]')) : [];
284
- });
285
- return getSnapElements(el).filter(
286
- (element) => element !== this.target && !this.target?.contains(element) && element !== mask.page,
287
- );
288
- }
289
-
290
314
  private sort(): void {
291
315
  if (!this.target || !this.ghostEl) throw new Error('未知错误');
292
316
  const { top } = this.ghostEl.getBoundingClientRect();
@@ -330,7 +354,7 @@ export default class StageDragResize extends EventEmitter {
330
354
  const ghostEl = el.cloneNode(true) as HTMLElement;
331
355
  const { top, left } = getAbsolutePosition(el, getOffset(el));
332
356
  ghostEl.id = `${GHOST_EL_ID_PREFIX}${el.id}`;
333
- ghostEl.style.zIndex = '5';
357
+ ghostEl.style.zIndex = ZIndex.GHOST_EL;
334
358
  ghostEl.style.opacity = '.5';
335
359
  ghostEl.style.position = 'absolute';
336
360
  ghostEl.style.left = `${left}px`;
@@ -354,7 +378,7 @@ export default class StageDragResize extends EventEmitter {
354
378
  top: ${offset.top}px;
355
379
  width: ${width}px;
356
380
  height: ${height}px;
357
- z-index: 9;
381
+ z-index: ${ZIndex.DRAG_EL};
358
382
  `;
359
383
 
360
384
  this.dragEl.id = `${DRAG_EL_ID_PREFIX}${el.id}`;
@@ -376,6 +400,14 @@ export default class StageDragResize extends EventEmitter {
376
400
  moveableOptions = moveableOptions(this.core);
377
401
  }
378
402
 
403
+ const elementGuidelines: any = moveableOptions.elementGuidelines || this.target.parentElement?.children || [];
404
+
405
+ this.setElementGuidelines(elementGuidelines);
406
+
407
+ if (moveableOptions.elementGuidelines) {
408
+ delete moveableOptions.elementGuidelines;
409
+ }
410
+
379
411
  return {
380
412
  origin: false,
381
413
  rootContainer: this.core.container,
package/src/StageMask.ts CHANGED
@@ -162,9 +162,10 @@ export default class StageMask extends Rule {
162
162
  this.setHeight(clientHeight);
163
163
  this.setWidth(clientWidth);
164
164
 
165
- this.fixScrollValue();
166
165
  this.scroll();
167
- this.core.dr.updateMoveable();
166
+ if (this.core.dr.moveable) {
167
+ this.core.dr.updateMoveable();
168
+ }
168
169
  });
169
170
 
170
171
  this.pageResizeObserver.observe(page);
@@ -218,6 +219,8 @@ export default class StageMask extends Rule {
218
219
  }
219
220
 
220
221
  private scroll() {
222
+ this.fixScrollValue();
223
+
221
224
  let { scrollLeft, scrollTop } = this;
222
225
 
223
226
  if (this.pageScrollParent) {
@@ -264,14 +267,14 @@ export default class StageMask extends Rule {
264
267
  * 计算并设置最大滚动宽度
265
268
  */
266
269
  private setMaxScrollLeft(): void {
267
- this.maxScrollLeft = this.width - this.wrapperWidth;
270
+ this.maxScrollLeft = Math.max(this.width - this.wrapperWidth, 0);
268
271
  }
269
272
 
270
273
  /**
271
274
  * 计算并设置最大滚动高度
272
275
  */
273
276
  private setMaxScrollTop(): void {
274
- this.maxScrollTop = this.height - this.wrapperHeight;
277
+ this.maxScrollTop = Math.max(this.height - this.wrapperHeight, 0);
275
278
  }
276
279
 
277
280
  /**
@@ -333,8 +336,6 @@ export default class StageMask extends Rule {
333
336
  this.scrollLeft = this.scrollLeft + deltaX;
334
337
  }
335
338
 
336
- this.fixScrollValue();
337
-
338
339
  this.scroll();
339
340
 
340
341
  this.emit('scroll', event);
@@ -18,7 +18,6 @@
18
18
 
19
19
  import { EventEmitter } from 'events';
20
20
 
21
- import { SELECTED_CLASS, ZIndex } from './const';
22
21
  import StageCore from './StageCore';
23
22
  import type { Runtime, RuntimeWindow, StageRenderConfig } from './types';
24
23
  import { getHost, isSameDomain } from './util';
@@ -122,16 +121,5 @@ export default class StageRender extends EventEmitter {
122
121
  this.iframe?.contentDocument?.body?.appendChild(el);
123
122
  }
124
123
  }
125
-
126
- if (this.contentWindow) {
127
- const style = this.contentWindow.document.createElement('style');
128
- style.id = 'tmagic-stage-render';
129
- style.innerHTML = `
130
- .${SELECTED_CLASS}, .${SELECTED_CLASS}-parent {
131
- z-index: ${ZIndex.SELECTED_EL};
132
- }
133
- `;
134
- this.contentWindow.document.head.appendChild(style);
135
- }
136
124
  };
137
125
  }
package/src/const.ts CHANGED
@@ -16,36 +16,58 @@
16
16
  * limitations under the License.
17
17
  */
18
18
 
19
- // 流式布局下拖动时需要clone一个镜像节点,镜像节点的id前缀
19
+ /** 流式布局下拖动时需要clone一个镜像节点,镜像节点的id前缀 */
20
20
  export const GHOST_EL_ID_PREFIX = 'ghost_el_';
21
21
 
22
+ /** 拖动的时候需要在蒙层中创建一个占位节点,该节点的id前缀 */
22
23
  export const DRAG_EL_ID_PREFIX = 'drag_el_';
23
24
 
25
+ /** 高亮事需要在蒙层中创建一个占位节点,该节点的id前缀 */
24
26
  export const HIGHLIGHT_EL_ID_PREFIX = 'highlight_el_';
25
27
 
26
- // 默认放到缩小倍数
28
+ /** 默认放到缩小倍数 */
27
29
  export const DEFAULT_ZOOM = 1;
28
30
 
31
+ /** 参考线类型 */
29
32
  export enum GuidesType {
33
+ /** 水平 */
30
34
  HORIZONTAL = 'horizontal',
35
+ /** 垂直 */
31
36
  VERTICAL = 'vertical',
32
37
  }
33
38
 
39
+ /** css z-index */
34
40
  export enum ZIndex {
41
+ /** 蒙层,用于监听用户操作,需要置于顶层 */
35
42
  MASK = '99999',
43
+ /** 选中的节点 */
36
44
  SELECTED_EL = '666',
45
+ GHOST_EL = '700',
46
+ DRAG_EL = '9',
37
47
  }
38
48
 
49
+ /** 鼠标按键 */
39
50
  export enum MouseButton {
51
+ /** 左键 */
40
52
  LEFT = 0,
53
+ /** z中健 */
41
54
  MIDDLE = 1,
55
+ /** 右键 */
42
56
  RIGHT = 2,
43
57
  }
44
58
 
59
+ /** 布局方式 */
45
60
  export enum Mode {
61
+ /** 绝对定位布局 */
46
62
  ABSOLUTE = 'absolute',
63
+ /** 固定定位布局 */
47
64
  FIXED = 'fixed',
65
+ /** 流式布局 */
48
66
  SORTABLE = 'sortable',
49
67
  }
50
68
 
69
+ /** 选中节点的class name */
51
70
  export const SELECTED_CLASS = 'tmagic-stage-selected-area';
71
+
72
+ export const H_GUIDE_LINE_STORAGE_KEY = '$MagicStageHorizontalGuidelinesData';
73
+ export const V_GUIDE_LINE_STORAGE_KEY = '$MagicStageVerticalGuidelinesData';
package/src/types.ts CHANGED
@@ -18,6 +18,7 @@
18
18
 
19
19
  import { MoveableOptions } from 'react-moveable/declaration/types';
20
20
 
21
+ import Core from '@tmagic/core';
21
22
  import { Id, MApp, MNode } from '@tmagic/schema';
22
23
 
23
24
  import { GuidesType } from './const';
@@ -95,6 +96,7 @@ export interface RemoveData {
95
96
  }
96
97
 
97
98
  export interface Runtime {
99
+ getApp?: () => Core;
98
100
  beforeSelect?: (el: HTMLElement) => Promise<boolean> | boolean;
99
101
  getSnapElements?: (el?: HTMLElement) => HTMLElement[];
100
102
  updateRootConfig: (config: MApp) => void;
package/src/util.ts CHANGED
@@ -16,7 +16,7 @@
16
16
  * limitations under the License.
17
17
  */
18
18
 
19
- import { Mode, SELECTED_CLASS } from './const';
19
+ import { GuidesType, H_GUIDE_LINE_STORAGE_KEY, Mode, SELECTED_CLASS, V_GUIDE_LINE_STORAGE_KEY } from './const';
20
20
  import type { Offset } from './types';
21
21
 
22
22
  const getParents = (el: Element, relative: Element) => {
@@ -184,3 +184,23 @@ export const addSelectedClassName = (el: Element, doc: Document) => {
184
184
  item.classList.add(`${SELECTED_CLASS}-parents`);
185
185
  });
186
186
  };
187
+
188
+ export const getGuideLineFromCache = (type: GuidesType): number[] => {
189
+ const key = {
190
+ [GuidesType.HORIZONTAL]: H_GUIDE_LINE_STORAGE_KEY,
191
+ [GuidesType.VERTICAL]: V_GUIDE_LINE_STORAGE_KEY,
192
+ }[type];
193
+
194
+ if (!key) return [];
195
+
196
+ const guideLineCacheData = globalThis.localStorage.getItem(key);
197
+ if (guideLineCacheData) {
198
+ try {
199
+ return JSON.parse(guideLineCacheData) || [];
200
+ } catch (e) {
201
+ console.error(e);
202
+ }
203
+ }
204
+
205
+ return [];
206
+ };