@tmagic/stage 1.7.6 → 1.7.8-beta.1

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.
@@ -0,0 +1,256 @@
1
+ import { Mode, ZIndex } from "./const.js";
2
+ import { getScrollParent, isFixedParent } from "./util.js";
3
+ import Rule from "./Rule.js";
4
+ import { createDiv, getDocument, injectStyle } from "@tmagic/core";
5
+ //#region packages/stage/src/StageMask.ts
6
+ var wrapperClassName = "editor-mask-wrapper";
7
+ var hideScrollbar = () => {
8
+ injectStyle(getDocument(), `.${wrapperClassName}::-webkit-scrollbar { width: 0 !important; display: none }`);
9
+ };
10
+ var createContent = () => createDiv({
11
+ className: "editor-mask",
12
+ cssText: `
13
+ position: absolute;
14
+ top: 0;
15
+ left: 0;
16
+ transform: translate3d(0, 0, 0);
17
+ `
18
+ });
19
+ var createWrapper = () => {
20
+ const el = createDiv({
21
+ className: wrapperClassName,
22
+ cssText: `
23
+ position: absolute;
24
+ top: 0;
25
+ left: 0;
26
+ height: 100%;
27
+ width: 100%;
28
+ overflow: hidden;
29
+ z-index: ${ZIndex.MASK};
30
+ `
31
+ });
32
+ hideScrollbar();
33
+ return el;
34
+ };
35
+ /**
36
+ * 蒙层
37
+ * @description 用于拦截页面的点击动作,避免点击时触发组件自身动作;在编辑器中点击组件应当是选中组件;
38
+ */
39
+ var StageMask = class extends Rule {
40
+ content = createContent();
41
+ wrapper;
42
+ page = null;
43
+ scrollTop = 0;
44
+ scrollLeft = 0;
45
+ width = 0;
46
+ height = 0;
47
+ wrapperHeight = 0;
48
+ wrapperWidth = 0;
49
+ maxScrollTop = 0;
50
+ maxScrollLeft = 0;
51
+ mode = Mode.ABSOLUTE;
52
+ pageScrollParent = null;
53
+ intersectionObserver = null;
54
+ wrapperResizeObserver = null;
55
+ constructor(options) {
56
+ const wrapper = createWrapper();
57
+ super(wrapper, options);
58
+ this.wrapper = wrapper;
59
+ this.content.addEventListener("wheel", this.mouseWheelHandler);
60
+ this.wrapper.appendChild(this.content);
61
+ }
62
+ setMode(mode) {
63
+ this.mode = mode;
64
+ this.scroll();
65
+ this.content.dataset.mode = mode;
66
+ if (mode === Mode.FIXED) {
67
+ this.content.style.width = `${this.wrapperWidth}px`;
68
+ this.content.style.height = `${this.wrapperHeight}px`;
69
+ } else {
70
+ this.content.style.width = `${this.width}px`;
71
+ this.content.style.height = `${this.height}px`;
72
+ }
73
+ }
74
+ /**
75
+ * 初始化视窗和蒙层监听,监听元素是否在视窗区域、监听mask蒙层所在的wrapper大小变化
76
+ * @description 初始化视窗和蒙层监听
77
+ * @param page 页面Dom节点
78
+ */
79
+ observe(page) {
80
+ if (!page) return;
81
+ this.page = page;
82
+ this.initObserverIntersection();
83
+ this.initObserverWrapper();
84
+ }
85
+ /**
86
+ * 处理页面大小变更,同步页面和mask大小
87
+ * @param entries ResizeObserverEntry,获取页面最新大小
88
+ */
89
+ pageResize(entries) {
90
+ const [entry] = entries;
91
+ const { clientHeight, clientWidth } = entry.target;
92
+ this.setHeight(clientHeight);
93
+ this.setWidth(clientWidth);
94
+ this.scroll();
95
+ }
96
+ /**
97
+ * 监听一个组件是否在画布可视区域内
98
+ * @param el 被选中的组件,可能是左侧目录树中选中的
99
+ */
100
+ observerIntersection(el) {
101
+ this.intersectionObserver?.observe(el);
102
+ }
103
+ /**
104
+ * 挂载Dom节点
105
+ * @param el 将蒙层挂载到该Dom节点上
106
+ */
107
+ mount(el) {
108
+ if (!this.content) throw new Error("content 不存在");
109
+ el.appendChild(this.wrapper);
110
+ }
111
+ setLayout(el) {
112
+ this.setMode(isFixedParent(el) ? Mode.FIXED : Mode.ABSOLUTE);
113
+ }
114
+ scrollIntoView(el) {
115
+ if (!this.page || el.getBoundingClientRect().left >= this.page.scrollWidth) return;
116
+ const scrollParent = getScrollParent(el);
117
+ if (scrollParent && scrollParent !== this.pageScrollParent) {
118
+ this.scrollIntoView(scrollParent);
119
+ return;
120
+ }
121
+ el.scrollIntoView();
122
+ if (!this.pageScrollParent) return;
123
+ this.scrollLeft = this.pageScrollParent.scrollLeft;
124
+ this.scrollTop = this.pageScrollParent.scrollTop;
125
+ this.scroll();
126
+ }
127
+ /**
128
+ * 销毁实例
129
+ */
130
+ destroy() {
131
+ super.destroy();
132
+ this.content?.remove();
133
+ this.page = null;
134
+ this.pageScrollParent = null;
135
+ this.wrapperResizeObserver?.disconnect();
136
+ }
137
+ on(eventName, listener) {
138
+ return super.on(eventName, listener);
139
+ }
140
+ emit(eventName, ...args) {
141
+ return super.emit(eventName, ...args);
142
+ }
143
+ /**
144
+ * 监听选中元素是否在画布可视区域内,如果目标元素不在可视区域内,通过滚动使该元素出现在可视区域
145
+ */
146
+ initObserverIntersection() {
147
+ this.pageScrollParent = getScrollParent(this.page) || null;
148
+ this.intersectionObserver?.disconnect();
149
+ if (typeof IntersectionObserver !== "undefined") this.intersectionObserver = new IntersectionObserver((entries) => {
150
+ entries.forEach((entry) => {
151
+ const { target, intersectionRatio } = entry;
152
+ if (intersectionRatio <= 0) this.scrollIntoView(target);
153
+ this.intersectionObserver?.unobserve(target);
154
+ });
155
+ }, {
156
+ root: this.pageScrollParent,
157
+ rootMargin: "0px",
158
+ threshold: 1
159
+ });
160
+ }
161
+ /**
162
+ * 监听mask的容器大小变化
163
+ */
164
+ initObserverWrapper() {
165
+ this.wrapperResizeObserver?.disconnect();
166
+ if (typeof ResizeObserver !== "undefined") {
167
+ this.wrapperResizeObserver = new ResizeObserver((entries) => {
168
+ const [entry] = entries;
169
+ const { clientHeight, clientWidth } = entry.target;
170
+ this.wrapperHeight = clientHeight;
171
+ this.wrapperWidth = clientWidth;
172
+ if (this.mode === Mode.FIXED) {
173
+ this.content.style.width = `${this.wrapperWidth}px`;
174
+ this.content.style.height = `${this.wrapperHeight}px`;
175
+ }
176
+ this.setMaxScrollLeft();
177
+ this.setMaxScrollTop();
178
+ });
179
+ this.wrapperResizeObserver.observe(this.wrapper);
180
+ }
181
+ }
182
+ scroll() {
183
+ this.fixScrollValue();
184
+ let { scrollLeft, scrollTop } = this;
185
+ if (this.pageScrollParent) this.pageScrollParent.scrollTo({
186
+ top: scrollTop,
187
+ left: scrollLeft
188
+ });
189
+ if (this.mode === Mode.FIXED) {
190
+ scrollLeft = 0;
191
+ scrollTop = 0;
192
+ }
193
+ this.scrollRule(scrollTop);
194
+ this.scrollTo(scrollLeft, scrollTop);
195
+ }
196
+ scrollTo(scrollLeft, scrollTop) {
197
+ this.content.style.transform = `translate3d(${-scrollLeft}px, ${-scrollTop}px, 0)`;
198
+ const event = new CustomEvent("customScroll", { detail: {
199
+ scrollLeft: this.scrollLeft,
200
+ scrollTop: this.scrollTop
201
+ } });
202
+ this.content.dispatchEvent(event);
203
+ }
204
+ /**
205
+ * 设置蒙层高度
206
+ * @param height 高度
207
+ */
208
+ setHeight(height) {
209
+ this.height = height;
210
+ this.setMaxScrollTop();
211
+ if (this.mode !== Mode.FIXED) this.content.style.height = `${height}px`;
212
+ }
213
+ /**
214
+ * 设置蒙层宽度
215
+ * @param width 宽度
216
+ */
217
+ setWidth(width) {
218
+ this.width = width;
219
+ this.setMaxScrollLeft();
220
+ if (this.mode !== Mode.FIXED) this.content.style.width = `${width}px`;
221
+ }
222
+ /**
223
+ * 计算并设置最大滚动宽度
224
+ */
225
+ setMaxScrollLeft() {
226
+ this.maxScrollLeft = Math.max(this.width - this.wrapperWidth, 0);
227
+ }
228
+ /**
229
+ * 计算并设置最大滚动高度
230
+ */
231
+ setMaxScrollTop() {
232
+ this.maxScrollTop = Math.max(this.height - this.wrapperHeight, 0);
233
+ }
234
+ /**
235
+ * 修复滚动距离
236
+ * 由于滚动容器变化等因素,会导致当前滚动的距离不正确
237
+ */
238
+ fixScrollValue() {
239
+ if (this.scrollTop < 0) this.scrollTop = 0;
240
+ if (this.scrollLeft < 0) this.scrollLeft = 0;
241
+ if (this.maxScrollTop < this.scrollTop) this.scrollTop = this.maxScrollTop;
242
+ if (this.maxScrollLeft < this.scrollLeft) this.scrollLeft = this.maxScrollLeft;
243
+ }
244
+ mouseWheelHandler = (event) => {
245
+ if (!this.page) throw new Error("page 未初始化");
246
+ const { deltaY, deltaX } = event;
247
+ if (this.page.clientHeight < this.wrapperHeight && deltaY) return;
248
+ if (this.page.clientWidth < this.wrapperWidth && deltaX) return;
249
+ if (this.maxScrollTop > 0) this.scrollTop = this.scrollTop + deltaY;
250
+ if (this.maxScrollLeft > 0) this.scrollLeft = this.scrollLeft + deltaX;
251
+ this.scroll();
252
+ this.emit("scroll", event);
253
+ };
254
+ };
255
+ //#endregion
256
+ export { StageMask as default };
@@ -0,0 +1,153 @@
1
+ import { DRAG_EL_ID_PREFIX, Mode, StageDragStatus } from "./const.js";
2
+ import { getMode } from "./util.js";
3
+ import MoveableOptionsManager from "./MoveableOptionsManager.js";
4
+ import { getIdFromEl } from "@tmagic/core";
5
+ import Moveable from "moveable";
6
+ //#region packages/stage/src/StageMultiDragResize.ts
7
+ var StageMultiDragResize = class extends MoveableOptionsManager {
8
+ /** 画布容器 */
9
+ container;
10
+ /** 多选:目标节点组 */
11
+ targetList = [];
12
+ /** Moveable多选拖拽类实例 */
13
+ moveableForMulti;
14
+ dragStatus = StageDragStatus.END;
15
+ dragResizeHelper;
16
+ getRenderDocument;
17
+ delayedMarkContainer;
18
+ markContainerEnd;
19
+ constructor(config) {
20
+ const moveableOptionsManagerConfig = {
21
+ container: config.container,
22
+ moveableOptions: config.moveableOptions,
23
+ getRootContainer: config.getRootContainer
24
+ };
25
+ super(moveableOptionsManagerConfig);
26
+ this.delayedMarkContainer = config.delayedMarkContainer;
27
+ this.markContainerEnd = config.markContainerEnd;
28
+ this.container = config.container;
29
+ this.getRenderDocument = config.getRenderDocument;
30
+ this.dragResizeHelper = config.dragResizeHelper;
31
+ this.on("update-moveable", () => {
32
+ if (this.moveableForMulti) this.updateMoveable();
33
+ });
34
+ }
35
+ /**
36
+ * 多选
37
+ * @param els
38
+ */
39
+ multiSelect(els) {
40
+ if (els.length === 0) return;
41
+ this.mode = getMode(els[0]);
42
+ this.targetList = els;
43
+ this.dragResizeHelper.updateGroup(els);
44
+ this.setElementGuidelines(this.targetList);
45
+ this.moveableForMulti?.destroy();
46
+ this.dragResizeHelper.clear();
47
+ this.moveableForMulti = new Moveable(this.container, this.getOptions(true, { target: this.dragResizeHelper.getShadowEls() }));
48
+ let timeout;
49
+ this.moveableForMulti.on("resizeGroupStart", (e) => {
50
+ this.dragResizeHelper.onResizeGroupStart(e);
51
+ this.dragStatus = StageDragStatus.START;
52
+ }).on("resizeGroup", (e) => {
53
+ this.dragResizeHelper.onResizeGroup(e);
54
+ this.dragStatus = StageDragStatus.ING;
55
+ }).on("resizeGroupEnd", () => {
56
+ this.update(true);
57
+ this.dragStatus = StageDragStatus.END;
58
+ }).on("dragGroupStart", (e) => {
59
+ this.dragResizeHelper.onDragGroupStart(e);
60
+ this.dragStatus = StageDragStatus.START;
61
+ }).on("dragGroup", (e) => {
62
+ if (timeout) {
63
+ globalThis.clearTimeout(timeout);
64
+ timeout = void 0;
65
+ }
66
+ timeout = this.delayedMarkContainer(e.inputEvent, this.targetList);
67
+ this.dragResizeHelper.onDragGroup(e);
68
+ this.dragStatus = StageDragStatus.ING;
69
+ }).on("dragGroupEnd", () => {
70
+ if (timeout) {
71
+ globalThis.clearTimeout(timeout);
72
+ timeout = void 0;
73
+ }
74
+ const parentEl = this.markContainerEnd();
75
+ this.update(false, parentEl);
76
+ this.dragStatus = StageDragStatus.END;
77
+ }).on("clickGroup", (e) => {
78
+ const { inputTarget, targets } = e;
79
+ if (targets.length > 1 && targets.includes(inputTarget)) {
80
+ const id = getIdFromEl()(inputTarget)?.replace(DRAG_EL_ID_PREFIX, "");
81
+ id && this.emit("change-to-select", id, e.inputEvent);
82
+ }
83
+ });
84
+ }
85
+ canSelect(el, selectedEl) {
86
+ const currentTargetMode = getMode(el);
87
+ let selectedElMode = "";
88
+ if (currentTargetMode === Mode.SORTABLE) return false;
89
+ if (this.targetList.length === 0 && selectedEl) selectedElMode = getMode(selectedEl);
90
+ else if (this.targetList.length > 0) selectedElMode = getMode(this.targetList[0]);
91
+ if (currentTargetMode !== selectedElMode) return false;
92
+ return true;
93
+ }
94
+ updateMoveable(eleList = this.targetList) {
95
+ if (!this.moveableForMulti) return;
96
+ if (!eleList) throw new Error("未选中任何节点");
97
+ this.targetList = eleList;
98
+ this.dragResizeHelper.setTargetList(eleList);
99
+ const options = this.getOptions(true, { target: this.dragResizeHelper.getShadowEls() });
100
+ Object.entries(options).forEach(([key, value]) => {
101
+ this.moveableForMulti[key] = value;
102
+ });
103
+ this.moveableForMulti.updateRect();
104
+ }
105
+ /**
106
+ * 清除多选状态
107
+ */
108
+ clearSelectStatus() {
109
+ if (!this.moveableForMulti) return;
110
+ this.dragResizeHelper.clearMultiSelectStatus();
111
+ this.moveableForMulti.target = null;
112
+ this.moveableForMulti.updateTarget();
113
+ this.targetList = [];
114
+ }
115
+ /**
116
+ * 销毁实例
117
+ */
118
+ destroy() {
119
+ this.moveableForMulti?.destroy();
120
+ this.dragResizeHelper.destroy();
121
+ }
122
+ on(eventName, listener) {
123
+ return super.on(eventName, listener);
124
+ }
125
+ emit(eventName, ...args) {
126
+ return super.emit(eventName, ...args);
127
+ }
128
+ /**
129
+ * 拖拽完成后将更新的位置信息暴露给上层业务方,业务方可以接收事件进行保存
130
+ * @param isResize 是否进行大小缩放
131
+ */
132
+ update(isResize = false, parentEl = null) {
133
+ if (this.targetList.length === 0) return;
134
+ const doc = this.getRenderDocument();
135
+ if (!doc) return;
136
+ const data = this.targetList.map((targetItem) => {
137
+ const rect = this.dragResizeHelper.getUpdatedElRect(targetItem, parentEl, doc);
138
+ return {
139
+ el: targetItem,
140
+ style: isResize ? rect : {
141
+ left: rect.left,
142
+ top: rect.top
143
+ }
144
+ };
145
+ });
146
+ this.emit("update", {
147
+ data,
148
+ parentEl
149
+ });
150
+ }
151
+ };
152
+ //#endregion
153
+ export { StageMultiDragResize as default };
@@ -0,0 +1,186 @@
1
+ import { RenderType } from "./const.js";
2
+ import { addSelectedClassName, removeSelectedClassName } from "./util.js";
3
+ import style_default from "./style.js";
4
+ import { EventEmitter } from "events";
5
+ import { getElById, getHost, guid, injectStyle, isSameDomain } from "@tmagic/core";
6
+ //#region packages/stage/src/StageRender.ts
7
+ var StageRender = class extends EventEmitter {
8
+ /** 组件的js、css执行的环境,直接渲染为当前window,iframe渲染则为iframe.contentWindow */
9
+ contentWindow = null;
10
+ runtime = null;
11
+ iframe;
12
+ nativeContainer;
13
+ runtimeUrl;
14
+ zoom = 1;
15
+ renderType;
16
+ customizedRender;
17
+ constructor({ runtimeUrl, zoom, customizedRender, renderType = RenderType.IFRAME }) {
18
+ super();
19
+ this.renderType = renderType;
20
+ this.runtimeUrl = runtimeUrl || "";
21
+ this.customizedRender = customizedRender;
22
+ this.setZoom(zoom);
23
+ if (this.renderType === RenderType.IFRAME) this.createIframe();
24
+ else if (this.renderType === RenderType.NATIVE) this.createNativeContainer();
25
+ }
26
+ getMagicApi = () => ({
27
+ id: guid(),
28
+ onPageElUpdate: (el) => {
29
+ this.emit("page-el-update", el);
30
+ },
31
+ onRuntimeReady: (runtime) => {
32
+ if (this.runtime) return;
33
+ this.runtime = runtime;
34
+ globalThis.runtime = runtime;
35
+ this.emit("runtime-ready", runtime);
36
+ }
37
+ });
38
+ async add(data) {
39
+ return (await this.getRuntime())?.add?.(data);
40
+ }
41
+ async remove(data) {
42
+ return (await this.getRuntime())?.remove?.(data);
43
+ }
44
+ async update(data) {
45
+ (await this.getRuntime())?.update?.(data);
46
+ }
47
+ async select(ids) {
48
+ const runtime = await this.getRuntime();
49
+ for (const id of ids) {
50
+ await runtime?.select?.(id);
51
+ this.flagSelectedEl(this.getTargetElement(id));
52
+ }
53
+ }
54
+ setZoom(zoom = 1) {
55
+ this.zoom = zoom;
56
+ }
57
+ /**
58
+ * 挂载Dom节点
59
+ * @param el 将页面挂载到该Dom节点上
60
+ */
61
+ async mount(el) {
62
+ if (this.iframe) {
63
+ if (!isSameDomain(this.runtimeUrl) && this.runtimeUrl) {
64
+ let html = await fetch(this.runtimeUrl).then((res) => res.text());
65
+ const base = `${location.protocol}//${getHost(this.runtimeUrl)}`;
66
+ html = html.replace("<head>", `<head>\n<base href="${base}">`);
67
+ this.iframe.srcdoc = html;
68
+ }
69
+ el.appendChild(this.iframe);
70
+ this.postTmagicRuntimeReady();
71
+ } else if (this.nativeContainer) el.appendChild(this.nativeContainer);
72
+ }
73
+ getRuntime = () => {
74
+ if (this.runtime) return Promise.resolve(this.runtime);
75
+ return new Promise((resolve) => {
76
+ const listener = (runtime) => {
77
+ this.off("runtime-ready", listener);
78
+ resolve(runtime);
79
+ };
80
+ this.on("runtime-ready", listener);
81
+ });
82
+ };
83
+ getDocument() {
84
+ return this.contentWindow?.document;
85
+ }
86
+ /**
87
+ * 通过坐标获得坐标下所有HTML元素数组
88
+ * @param point 坐标
89
+ * @returns 坐标下方所有HTML元素数组,会包含父元素直至html,元素层叠时返回顺序是从上到下
90
+ */
91
+ getElementsFromPoint(point) {
92
+ let x = point.clientX;
93
+ let y = point.clientY;
94
+ if (this.iframe) {
95
+ const rect = this.iframe.getClientRects()[0];
96
+ if (rect) {
97
+ x = x - rect.left;
98
+ y = y - rect.top;
99
+ }
100
+ }
101
+ return this.getDocument()?.elementsFromPoint(x / this.zoom, y / this.zoom);
102
+ }
103
+ getTargetElement(id) {
104
+ return getElById()(this.getDocument(), id);
105
+ }
106
+ postTmagicRuntimeReady() {
107
+ this.contentWindow = this.iframe?.contentWindow;
108
+ this.contentWindow.magic = this.getMagicApi();
109
+ this.contentWindow.postMessage({ tmagicRuntimeReady: true }, "*");
110
+ }
111
+ reloadIframe(url) {
112
+ if (this.renderType !== RenderType.IFRAME) return;
113
+ const el = this.iframe?.parentElement;
114
+ this.destroyIframe();
115
+ this.runtimeUrl = url;
116
+ this.createIframe();
117
+ this.mount(el);
118
+ this.runtime = null;
119
+ }
120
+ destroyIframe() {
121
+ this.iframe?.removeEventListener("load", this.iframeLoadHandler);
122
+ this.contentWindow = null;
123
+ this.iframe?.remove();
124
+ this.iframe = void 0;
125
+ }
126
+ /**
127
+ * 销毁实例
128
+ */
129
+ destroy() {
130
+ this.destroyIframe();
131
+ globalThis.runtime = void 0;
132
+ this.removeAllListeners();
133
+ }
134
+ on(eventName, listener) {
135
+ return super.on(eventName, listener);
136
+ }
137
+ emit(eventName, ...args) {
138
+ return super.emit(eventName, ...args);
139
+ }
140
+ createIframe() {
141
+ this.iframe = globalThis.document.createElement("iframe");
142
+ this.iframe.src = this.runtimeUrl && isSameDomain(this.runtimeUrl) ? this.runtimeUrl : "";
143
+ this.iframe.style.cssText = `
144
+ border: 0;
145
+ width: 100%;
146
+ height: 100%;
147
+ `;
148
+ this.iframe.addEventListener("load", this.iframeLoadHandler);
149
+ return this.iframe;
150
+ }
151
+ async createNativeContainer() {
152
+ this.contentWindow = globalThis;
153
+ this.nativeContainer = globalThis.document.createElement("div");
154
+ this.contentWindow.magic = this.getMagicApi();
155
+ if (this.customizedRender) {
156
+ const el = await this.customizedRender();
157
+ if (el) this.nativeContainer.appendChild(el);
158
+ }
159
+ }
160
+ /**
161
+ * 在runtime中对被选中的元素进行标记,部分组件有对选中态进行特殊显示的需求
162
+ * @param el 被选中的元素
163
+ */
164
+ flagSelectedEl(el) {
165
+ const doc = this.getDocument();
166
+ if (doc) {
167
+ removeSelectedClassName(doc);
168
+ el && addSelectedClassName(el, doc);
169
+ }
170
+ }
171
+ iframeLoadHandler = () => {
172
+ const handler = async () => {
173
+ if (!this.contentWindow?.magic) this.postTmagicRuntimeReady();
174
+ if (!this.contentWindow) return;
175
+ if (this.customizedRender) {
176
+ const el = await this.customizedRender();
177
+ if (el) this.contentWindow.document?.body?.appendChild(el);
178
+ }
179
+ this.emit("onload");
180
+ injectStyle(this.contentWindow.document, style_default);
181
+ };
182
+ handler();
183
+ };
184
+ };
185
+ //#endregion
186
+ export { StageRender as default };
@@ -0,0 +1,68 @@
1
+ import { Mode } from "./const.js";
2
+ import { getTargetElStyle, isFixedParent } from "./util.js";
3
+ import { getElById, getIdFromEl, guid, setIdToEl } from "@tmagic/core";
4
+ //#region packages/stage/src/TargetShadow.ts
5
+ /**
6
+ * 将选中的节点修正定位后,添加一个操作节点到蒙层上
7
+ */
8
+ var TargetShadow = class {
9
+ el;
10
+ els = [];
11
+ idPrefix = `target_calibrate_${guid()}`;
12
+ container;
13
+ scrollLeft = 0;
14
+ scrollTop = 0;
15
+ zIndex;
16
+ updateDragEl;
17
+ constructor(config) {
18
+ this.container = config.container;
19
+ if (config.updateDragEl) this.updateDragEl = config.updateDragEl;
20
+ if (typeof config.zIndex !== "undefined") this.zIndex = config.zIndex;
21
+ if (config.idPrefix) this.idPrefix = `${config.idPrefix}_${guid()}`;
22
+ this.container.addEventListener("customScroll", this.scrollHandler);
23
+ }
24
+ update(target) {
25
+ this.el = this.updateEl(target, this.el);
26
+ return this.el;
27
+ }
28
+ updateGroup(targetGroup) {
29
+ if (this.els.length > targetGroup.length) this.els.slice(targetGroup.length - 1).forEach((el) => {
30
+ el.remove();
31
+ });
32
+ this.els = targetGroup.map((target, index) => this.updateEl(target, this.els[index]));
33
+ return this.els;
34
+ }
35
+ destroyEl() {
36
+ this.el?.remove();
37
+ this.el = void 0;
38
+ }
39
+ destroyEls() {
40
+ this.els.forEach((el) => {
41
+ el.remove();
42
+ });
43
+ this.els = [];
44
+ }
45
+ destroy() {
46
+ this.container.removeEventListener("customScroll", this.scrollHandler);
47
+ this.destroyEl();
48
+ this.destroyEls();
49
+ }
50
+ updateEl(target, src) {
51
+ const el = src || globalThis.document.createElement("div");
52
+ setIdToEl()(el, `${this.idPrefix}_${getIdFromEl()(target)}`);
53
+ el.style.cssText = getTargetElStyle(target, this.zIndex);
54
+ if (typeof this.updateDragEl === "function") this.updateDragEl(el, target, this.container);
55
+ const isFixed = isFixedParent(target);
56
+ const mode = this.container.dataset.mode || Mode.ABSOLUTE;
57
+ if (isFixed && mode !== Mode.FIXED) el.style.transform = `translate3d(${this.scrollLeft}px, ${this.scrollTop}px, 0)`;
58
+ else if (!isFixed && mode === Mode.FIXED) el.style.transform = `translate3d(${-this.scrollLeft}px, ${-this.scrollTop}px, 0)`;
59
+ if (!getElById()(globalThis.document, getIdFromEl()(el))) this.container.append(el);
60
+ return el;
61
+ }
62
+ scrollHandler = (e) => {
63
+ this.scrollLeft = e.detail.scrollLeft;
64
+ this.scrollTop = e.detail.scrollTop;
65
+ };
66
+ };
67
+ //#endregion
68
+ export { TargetShadow as default };