@tmagic/stage 1.8.0-manmanyu.9 → 1.8.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.
- package/dist/es/ActionManager.js +14 -6
- package/dist/es/MoveableOptionsManager.js +4 -2
- package/dist/es/StageCore.js +14 -2
- package/dist/es/StageDragResize.js +12 -9
- package/dist/es/StageFlashHighlight.js +1 -1
- package/dist/es/StageMask.js +57 -9
- package/dist/es/index.js +2 -2
- package/dist/es/util.js +50 -1
- package/dist/tmagic-stage.umd.cjs +306 -149
- package/package.json +5 -5
- package/src/ActionManager.ts +20 -8
- package/src/StageCore.ts +23 -2
- package/src/StageMask.ts +80 -10
- package/src/types.ts +14 -1
- package/src/util.ts +72 -1
- package/types/index.d.ts +150 -97
package/dist/es/ActionManager.js
CHANGED
|
@@ -35,6 +35,8 @@ var ActionManager = class extends EventEmitter$1 {
|
|
|
35
35
|
containerHighlightDuration;
|
|
36
36
|
/** 将组件加入容器的操作方式 */
|
|
37
37
|
containerHighlightType;
|
|
38
|
+
/** 是否仅在新增组件时才启用将组件加入容器 */
|
|
39
|
+
containerHighlightAddOnly = false;
|
|
38
40
|
isAltKeydown = false;
|
|
39
41
|
getTargetElement;
|
|
40
42
|
getElementsFromPoint;
|
|
@@ -68,6 +70,7 @@ var ActionManager = class extends EventEmitter$1 {
|
|
|
68
70
|
this.containerHighlightClassName = config.containerHighlightClassName || "tmagic-stage-container-highlight";
|
|
69
71
|
this.containerHighlightDuration = config.containerHighlightDuration || defaultContainerHighlightDuration;
|
|
70
72
|
this.containerHighlightType = config.containerHighlightType;
|
|
73
|
+
this.containerHighlightAddOnly = config.containerHighlightAddOnly ?? false;
|
|
71
74
|
this.disabledMultiSelect = config.disabledMultiSelect ?? false;
|
|
72
75
|
this.alwaysMultiSelect = config.alwaysMultiSelect ?? false;
|
|
73
76
|
this.getTargetElement = config.getTargetElement;
|
|
@@ -299,10 +302,11 @@ var ActionManager = class extends EventEmitter$1 {
|
|
|
299
302
|
* 标记的作用:1、高亮容器,给用户一个加入容器的交互感知;2、释放鼠标后,通过标记的标志找到要加入的容器
|
|
300
303
|
* @param event 鼠标事件
|
|
301
304
|
* @param excludeElList 计算鼠标所在容器时要排除的元素列表
|
|
305
|
+
* @param isAdd 当前操作是否为新增组件(从组件列表拖入),开启 containerHighlightAddOnly 时只有新增才会标记
|
|
302
306
|
* @returns timeoutId,调用方在鼠标移走时要取消该timeout,阻止标记
|
|
303
307
|
*/
|
|
304
|
-
delayedMarkContainer(event, excludeElList = []) {
|
|
305
|
-
if (this.canAddToContainer()) return globalThis.setTimeout(() => {
|
|
308
|
+
delayedMarkContainer(event, excludeElList = [], isAdd = false) {
|
|
309
|
+
if (this.canAddToContainer(isAdd)) return globalThis.setTimeout(() => {
|
|
306
310
|
this.addContainerHighlightClassName(event, excludeElList);
|
|
307
311
|
}, this.containerHighlightDuration);
|
|
308
312
|
}
|
|
@@ -421,9 +425,12 @@ var ActionManager = class extends EventEmitter$1 {
|
|
|
421
425
|
} else this.selectedElList.push(el);
|
|
422
426
|
}
|
|
423
427
|
/**
|
|
424
|
-
* 当前状态下能否将组件加入容器,默认是鼠标悬停一段时间加入,alt模式则是按住alt
|
|
428
|
+
* 当前状态下能否将组件加入容器,默认是鼠标悬停一段时间加入,alt模式则是按住alt+鼠标悬停一段时间加入;
|
|
429
|
+
* 开启containerHighlightAddOnly时,画布中拖动已有组件不能加入容器
|
|
430
|
+
* @param isAdd 当前操作是否为新增组件
|
|
425
431
|
*/
|
|
426
|
-
canAddToContainer() {
|
|
432
|
+
canAddToContainer(isAdd = false) {
|
|
433
|
+
if (this.containerHighlightAddOnly && !isAdd) return false;
|
|
427
434
|
return this.containerHighlightType === ContainerHighlightType.DEFAULT || this.containerHighlightType === ContainerHighlightType.ALT && this.isAltKeydown;
|
|
428
435
|
}
|
|
429
436
|
/**
|
|
@@ -432,8 +439,9 @@ var ActionManager = class extends EventEmitter$1 {
|
|
|
432
439
|
*/
|
|
433
440
|
markContainerEnd() {
|
|
434
441
|
const doc = this.getRenderDocument();
|
|
435
|
-
if (doc
|
|
436
|
-
|
|
442
|
+
if (!doc) return null;
|
|
443
|
+
const markedContainer = removeClassNameByClassName(doc, this.containerHighlightClassName);
|
|
444
|
+
return this.canAddToContainer() ? markedContainer : null;
|
|
437
445
|
}
|
|
438
446
|
initMouseEvent() {
|
|
439
447
|
this.container.addEventListener("mousedown", this.mouseDownHandler);
|
|
@@ -81,7 +81,7 @@ var MoveableOptionsManager = class extends EventEmitter$1 {
|
|
|
81
81
|
*/
|
|
82
82
|
getDefaultOptions(isMultiSelect) {
|
|
83
83
|
const isSortable = this.mode === Mode.SORTABLE;
|
|
84
|
-
|
|
84
|
+
const commonOptions = {
|
|
85
85
|
draggable: true,
|
|
86
86
|
resizable: true,
|
|
87
87
|
rootContainer: this.getRootContainer(),
|
|
@@ -97,7 +97,9 @@ var MoveableOptionsManager = class extends EventEmitter$1 {
|
|
|
97
97
|
right: this.container.clientWidth,
|
|
98
98
|
bottom: isSortable ? void 0 : this.container.clientHeight
|
|
99
99
|
}
|
|
100
|
-
}
|
|
100
|
+
};
|
|
101
|
+
const differenceOptions = isMultiSelect ? this.getMultiOptions() : this.getSingleOptions();
|
|
102
|
+
return merge(commonOptions, differenceOptions);
|
|
101
103
|
}
|
|
102
104
|
/**
|
|
103
105
|
* 获取单选下的差异化参数
|
package/dist/es/StageCore.js
CHANGED
|
@@ -171,10 +171,11 @@ var StageCore = class extends EventEmitter {
|
|
|
171
171
|
* 标记的作用:1、高亮容器,给用户一个加入容器的交互感知;2、释放鼠标后,通过标记的标志找到要加入的容器
|
|
172
172
|
* @param event 鼠标事件
|
|
173
173
|
* @param excludeElList 计算鼠标所在容器时要排除的元素列表
|
|
174
|
+
* @param isAdd 当前操作是否为新增组件(从组件列表拖入),开启 containerHighlightAddOnly 时只有新增才会标记
|
|
174
175
|
* @returns timeoutId,调用方在鼠标移走时要取消该timeout,阻止标记
|
|
175
176
|
*/
|
|
176
|
-
delayedMarkContainer(event, excludeElList = []) {
|
|
177
|
-
return this.actionManager?.delayedMarkContainer(event, excludeElList);
|
|
177
|
+
delayedMarkContainer(event, excludeElList = [], isAdd = false) {
|
|
178
|
+
return this.actionManager?.delayedMarkContainer(event, excludeElList, isAdd);
|
|
178
179
|
}
|
|
179
180
|
getMoveableOption(key) {
|
|
180
181
|
return this.actionManager?.getMoveableOption(key);
|
|
@@ -242,11 +243,21 @@ var StageCore = class extends EventEmitter {
|
|
|
242
243
|
this.pageResizeObserver.observe(page);
|
|
243
244
|
}
|
|
244
245
|
}
|
|
246
|
+
/**
|
|
247
|
+
* page-el-update 后,若当前选中节点仍在新页面文档中且需要自动滚动,则重新触发 scrollIntoView
|
|
248
|
+
*/
|
|
249
|
+
scrollSelectedIntoViewAfterPageUpdate() {
|
|
250
|
+
const selected = this.actionManager?.getSelectedEl();
|
|
251
|
+
if (!selected?.isConnected) return;
|
|
252
|
+
if (!(this.autoScrollIntoView || selected.dataset.autoScrollIntoView)) return;
|
|
253
|
+
this.mask?.observerIntersection(selected);
|
|
254
|
+
}
|
|
245
255
|
getActionManagerConfig(config) {
|
|
246
256
|
return {
|
|
247
257
|
containerHighlightClassName: config.containerHighlightClassName,
|
|
248
258
|
containerHighlightDuration: config.containerHighlightDuration,
|
|
249
259
|
containerHighlightType: config.containerHighlightType,
|
|
260
|
+
containerHighlightAddOnly: config.containerHighlightAddOnly,
|
|
250
261
|
moveableOptions: config.moveableOptions,
|
|
251
262
|
container: this.mask.content,
|
|
252
263
|
disabledDragStart: config.disabledDragStart,
|
|
@@ -269,6 +280,7 @@ var StageCore = class extends EventEmitter {
|
|
|
269
280
|
this.renderer?.on("page-el-update", (el) => {
|
|
270
281
|
this.mask?.observe(el);
|
|
271
282
|
this.observePageResize(el);
|
|
283
|
+
this.scrollSelectedIntoViewAfterPageUpdate();
|
|
272
284
|
this.emit("page-el-update", el);
|
|
273
285
|
});
|
|
274
286
|
}
|
|
@@ -144,12 +144,14 @@ var StageDragResize = class extends MoveableOptionsManager {
|
|
|
144
144
|
timeout = void 0;
|
|
145
145
|
}
|
|
146
146
|
const parentEl = this.markContainerEnd();
|
|
147
|
-
if (this.dragStatus === StageDragStatus.ING)
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
147
|
+
if (this.dragStatus === StageDragStatus.ING) {
|
|
148
|
+
if (parentEl) this.update(false, parentEl);
|
|
149
|
+
else switch (this.mode) {
|
|
150
|
+
case Mode.SORTABLE:
|
|
151
|
+
this.sort();
|
|
152
|
+
break;
|
|
153
|
+
default: this.update();
|
|
154
|
+
}
|
|
153
155
|
}
|
|
154
156
|
this.dragStatus = StageDragStatus.END;
|
|
155
157
|
this.dragResizeHelper.destroyGhostEl();
|
|
@@ -202,9 +204,10 @@ var StageDragResize = class extends MoveableOptionsManager {
|
|
|
202
204
|
const { top } = this.dragResizeHelper.getGhostEl().getBoundingClientRect();
|
|
203
205
|
const { top: oriTop } = this.target.getBoundingClientRect();
|
|
204
206
|
const deltaTop = top - oriTop;
|
|
205
|
-
if (Math.abs(deltaTop) >= this.target.clientHeight / 2)
|
|
206
|
-
|
|
207
|
-
|
|
207
|
+
if (Math.abs(deltaTop) >= this.target.clientHeight / 2) {
|
|
208
|
+
if (deltaTop > 0) this.emit("sort", down(deltaTop, this.target));
|
|
209
|
+
else this.emit("sort", up(deltaTop, this.target));
|
|
210
|
+
} else {
|
|
208
211
|
const id = getIdFromEl()(this.target);
|
|
209
212
|
id && this.emit("sort", {
|
|
210
213
|
src: id,
|
package/dist/es/StageMask.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Mode, ZIndex } from "./const.js";
|
|
2
|
-
import { getScrollParent, isFixedParent } from "./util.js";
|
|
2
|
+
import { getScrollParent, isDocumentVisible, isElementVisible, isFixedParent, scrollElementIntoView } from "./util.js";
|
|
3
3
|
import Rule from "./Rule.js";
|
|
4
4
|
import { createDiv, getDocument, injectStyle } from "@tmagic/core";
|
|
5
5
|
//#region packages/stage/src/StageMask.ts
|
|
@@ -73,25 +73,38 @@ var StageMask = class extends Rule {
|
|
|
73
73
|
}
|
|
74
74
|
/**
|
|
75
75
|
* 初始化视窗和蒙层监听,监听元素是否在视窗区域、监听mask蒙层所在的wrapper大小变化
|
|
76
|
-
* @description
|
|
76
|
+
* @description 初始化视窗和蒙层监听;切换到新页面 DOM 时重置滚动
|
|
77
77
|
* @param page 页面Dom节点
|
|
78
78
|
*/
|
|
79
79
|
observe(page) {
|
|
80
80
|
if (!page) return;
|
|
81
|
+
const pageChanged = this.page !== page;
|
|
81
82
|
this.page = page;
|
|
82
83
|
this.initObserverIntersection();
|
|
83
84
|
this.initObserverWrapper();
|
|
85
|
+
if (pageChanged) {
|
|
86
|
+
this.pageScrollParent?.scrollTo({
|
|
87
|
+
top: 0,
|
|
88
|
+
left: 0
|
|
89
|
+
});
|
|
90
|
+
this.scrollTop = 0;
|
|
91
|
+
this.scrollLeft = 0;
|
|
92
|
+
this.scroll();
|
|
93
|
+
}
|
|
94
|
+
this.syncPageSize();
|
|
84
95
|
}
|
|
85
96
|
/**
|
|
86
|
-
* 处理页面大小变更,同步页面和mask大小
|
|
97
|
+
* 处理页面大小变更,同步页面和 mask 大小
|
|
98
|
+
* @description 仅处理当前 page 且仍挂载在文档中的 entry;非当前页、已卸载或宽高为 0 的回调会被忽略
|
|
87
99
|
* @param entries ResizeObserverEntry,获取页面最新大小
|
|
88
100
|
*/
|
|
89
101
|
pageResize(entries) {
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
102
|
+
if (!this.page || !entries.length) return;
|
|
103
|
+
const entry = entries.find((item) => item.target === this.page);
|
|
104
|
+
if (!entry) return;
|
|
105
|
+
const { target } = entry;
|
|
106
|
+
if (!target.isConnected) return;
|
|
107
|
+
this.applyPageSize(target.clientWidth, target.clientHeight);
|
|
95
108
|
}
|
|
96
109
|
/**
|
|
97
110
|
* 监听一个组件是否在画布可视区域内
|
|
@@ -111,15 +124,21 @@ var StageMask = class extends Rule {
|
|
|
111
124
|
setLayout(el) {
|
|
112
125
|
this.setMode(isFixedParent(el) ? Mode.FIXED : Mode.ABSOLUTE);
|
|
113
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* 将元素滚动到画布可视区域内
|
|
129
|
+
* @description 页面不可见时不做滚动:此时滚动既无视觉效果,又会记录错误的滚动偏移
|
|
130
|
+
* @param el 目标元素
|
|
131
|
+
*/
|
|
114
132
|
scrollIntoView(el) {
|
|
133
|
+
if (!this.isPageVisible()) return;
|
|
115
134
|
if (!this.page || el.getBoundingClientRect().left >= this.page.scrollWidth) return;
|
|
116
135
|
const scrollParent = getScrollParent(el);
|
|
117
136
|
if (scrollParent && scrollParent !== this.pageScrollParent) {
|
|
118
137
|
this.scrollIntoView(scrollParent);
|
|
119
138
|
return;
|
|
120
139
|
}
|
|
121
|
-
el.scrollIntoView();
|
|
122
140
|
if (!this.pageScrollParent) return;
|
|
141
|
+
scrollElementIntoView(el, this.pageScrollParent);
|
|
123
142
|
this.scrollLeft = this.pageScrollParent.scrollLeft;
|
|
124
143
|
this.scrollTop = this.pageScrollParent.scrollTop;
|
|
125
144
|
this.scroll();
|
|
@@ -132,6 +151,7 @@ var StageMask = class extends Rule {
|
|
|
132
151
|
this.content?.remove();
|
|
133
152
|
this.page = null;
|
|
134
153
|
this.pageScrollParent = null;
|
|
154
|
+
this.intersectionObserver?.disconnect();
|
|
135
155
|
this.wrapperResizeObserver?.disconnect();
|
|
136
156
|
}
|
|
137
157
|
on(eventName, listener) {
|
|
@@ -149,6 +169,7 @@ var StageMask = class extends Rule {
|
|
|
149
169
|
if (typeof IntersectionObserver !== "undefined") this.intersectionObserver = new IntersectionObserver((entries) => {
|
|
150
170
|
entries.forEach((entry) => {
|
|
151
171
|
const { target, intersectionRatio } = entry;
|
|
172
|
+
if (!this.isPageVisible()) return;
|
|
152
173
|
if (intersectionRatio <= 0) this.scrollIntoView(target);
|
|
153
174
|
this.intersectionObserver?.unobserve(target);
|
|
154
175
|
});
|
|
@@ -202,6 +223,33 @@ var StageMask = class extends Rule {
|
|
|
202
223
|
this.content.dispatchEvent(event);
|
|
203
224
|
}
|
|
204
225
|
/**
|
|
226
|
+
* 页面是否可见
|
|
227
|
+
* @description 页面未挂载、或画布容器被隐藏(如编辑器切到其他面板)时页面不可见;
|
|
228
|
+
* 蒙层与页面所在的 iframe 挂载在同一容器中,容器隐藏时页面内部元素仍可能是"可见"的,因此额外判断蒙层;
|
|
229
|
+
* 浏览器 tab 不可见(切到其他标签页、窗口最小化)时同样视为不可见
|
|
230
|
+
*/
|
|
231
|
+
isPageVisible() {
|
|
232
|
+
if (!isDocumentVisible(this.page?.ownerDocument) || !isDocumentVisible(this.wrapper.ownerDocument)) return false;
|
|
233
|
+
if (!isElementVisible(this.page)) return false;
|
|
234
|
+
return !this.wrapper.isConnected || isElementVisible(this.wrapper);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* 从当前页面同步蒙层宽高,并修正滚动偏移
|
|
238
|
+
*/
|
|
239
|
+
syncPageSize() {
|
|
240
|
+
if (!this.page?.isConnected) return;
|
|
241
|
+
this.applyPageSize(this.page.clientWidth, this.page.clientHeight);
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* 应用页面尺寸到蒙层;宽高为 0 时忽略,避免切换/布局过程中把 editor-mask 置空
|
|
245
|
+
*/
|
|
246
|
+
applyPageSize(clientWidth, clientHeight) {
|
|
247
|
+
if (clientWidth <= 0 || clientHeight <= 0) return;
|
|
248
|
+
this.setHeight(clientHeight);
|
|
249
|
+
this.setWidth(clientWidth);
|
|
250
|
+
this.scroll();
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
205
253
|
* 设置蒙层高度
|
|
206
254
|
* @param height 高度
|
|
207
255
|
*/
|
package/dist/es/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AbleActionEventType, CONTAINER_HIGHLIGHT_CLASS_NAME, ContainerHighlightType, DEFAULT_ZOOM, DRAG_EL_ID_PREFIX, FLASH_EL_ID_PREFIX, GHOST_EL_ID_PREFIX, GuidesType, HIGHLIGHT_EL_ID_PREFIX, Mode, MouseButton, PAGE_CLASS, RenderType, SELECTED_CLASS, SelectStatus, StageDragStatus, ZIndex } from "./const.js";
|
|
2
|
-
import { addSelectedClassName, down, getAbsolutePosition, getBorderWidth, getMarginValue, getMode, getOffset, getScrollParent, getTargetElStyle, isAbsolute, isFixed, isFixedParent, isMoveableButton, isRelative, isStatic, removeSelectedClassName, up } from "./util.js";
|
|
2
|
+
import { addSelectedClassName, down, getAbsolutePosition, getBorderWidth, getMarginValue, getMode, getOffset, getScrollParent, getTargetElStyle, isAbsolute, isDocumentVisible, isElementVisible, isFixed, isFixedParent, isMoveableButton, isRelative, isStatic, removeSelectedClassName, scrollElementIntoView, up } from "./util.js";
|
|
3
3
|
import MoveableActionsAble_default from "./MoveableActionsAble.js";
|
|
4
4
|
import StageDragResize from "./StageDragResize.js";
|
|
5
5
|
import StageMask from "./StageMask.js";
|
|
@@ -9,4 +9,4 @@ export * from "moveable";
|
|
|
9
9
|
//#region packages/stage/src/index.ts
|
|
10
10
|
var src_default = StageCore;
|
|
11
11
|
//#endregion
|
|
12
|
-
export { AbleActionEventType, CONTAINER_HIGHLIGHT_CLASS_NAME, ContainerHighlightType, DEFAULT_ZOOM, DRAG_EL_ID_PREFIX, FLASH_EL_ID_PREFIX, GHOST_EL_ID_PREFIX, GuidesType, HIGHLIGHT_EL_ID_PREFIX, Mode, MouseButton, MoveableActionsAble_default as MoveableActionsAble, PAGE_CLASS, RenderType, SELECTED_CLASS, SelectStatus, StageDragResize, StageDragStatus, StageMask, StageRender, ZIndex, addSelectedClassName, src_default as default, down, getAbsolutePosition, getBorderWidth, getMarginValue, getMode, getOffset, getScrollParent, getTargetElStyle, isAbsolute, isFixed, isFixedParent, isMoveableButton, isRelative, isStatic, removeSelectedClassName, up };
|
|
12
|
+
export { AbleActionEventType, CONTAINER_HIGHLIGHT_CLASS_NAME, ContainerHighlightType, DEFAULT_ZOOM, DRAG_EL_ID_PREFIX, FLASH_EL_ID_PREFIX, GHOST_EL_ID_PREFIX, GuidesType, HIGHLIGHT_EL_ID_PREFIX, Mode, MouseButton, MoveableActionsAble_default as MoveableActionsAble, PAGE_CLASS, RenderType, SELECTED_CLASS, SelectStatus, StageDragResize, StageDragStatus, StageMask, StageRender, ZIndex, addSelectedClassName, src_default as default, down, getAbsolutePosition, getBorderWidth, getMarginValue, getMode, getOffset, getScrollParent, getTargetElStyle, isAbsolute, isDocumentVisible, isElementVisible, isFixed, isFixedParent, isMoveableButton, isRelative, isStatic, removeSelectedClassName, scrollElementIntoView, up };
|
package/dist/es/util.js
CHANGED
|
@@ -91,6 +91,55 @@ var getScrollParent = (element, includeHidden = false) => {
|
|
|
91
91
|
}
|
|
92
92
|
return null;
|
|
93
93
|
};
|
|
94
|
+
/**
|
|
95
|
+
* 判断文档是否可见
|
|
96
|
+
* @description 浏览器 tab 切到后台、窗口最小化时文档 visibilityState 为 hidden;
|
|
97
|
+
* 只将 hidden 视为不可见,避免 prerender 等中间态被误判
|
|
98
|
+
* @param doc 目标文档
|
|
99
|
+
*/
|
|
100
|
+
var isDocumentVisible = (doc) => doc?.visibilityState !== "hidden";
|
|
101
|
+
/**
|
|
102
|
+
* 判断元素是否可见
|
|
103
|
+
* @description 元素未挂载到文档、或其自身/祖先被 display:none、visibility:hidden 隐藏时视为不可见;
|
|
104
|
+
* 优先使用浏览器提供的 checkVisibility,不支持时退化为沿祖先链检查计算样式
|
|
105
|
+
* @param el 目标元素
|
|
106
|
+
*/
|
|
107
|
+
var isElementVisible = (el) => {
|
|
108
|
+
if (!el?.isConnected) return false;
|
|
109
|
+
if (typeof el.checkVisibility === "function") return el.checkVisibility({ checkVisibilityCSS: true });
|
|
110
|
+
for (let node = el; node; node = node.parentElement) {
|
|
111
|
+
const { display, visibility } = getComputedStyle(node);
|
|
112
|
+
if (display === "none" || visibility === "hidden") return false;
|
|
113
|
+
}
|
|
114
|
+
return true;
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* 将元素滚动到指定滚动容器的可视区域内(仅垂直方向,滚动最小距离)
|
|
118
|
+
* @description 与原生 scrollIntoView 不同,只滚动指定的容器自身,不会连带滚动外层祖先滚动容器,
|
|
119
|
+
* 避免编辑器画布外层容器(如 stage 外层使用 transform 模拟滚动的容器)被浏览器自动滚动导致整个画布位移
|
|
120
|
+
* @param el 目标元素
|
|
121
|
+
* @param container 滚动容器
|
|
122
|
+
*/
|
|
123
|
+
var scrollElementIntoView = (el, container) => {
|
|
124
|
+
const { ownerDocument } = container;
|
|
125
|
+
const win = ownerDocument?.defaultView;
|
|
126
|
+
if (!ownerDocument || !win) return;
|
|
127
|
+
const elRect = el.getBoundingClientRect();
|
|
128
|
+
let viewTop = 0;
|
|
129
|
+
let viewHeight = 0;
|
|
130
|
+
if (container === ownerDocument.documentElement || container === ownerDocument.body) {
|
|
131
|
+
viewTop = 0;
|
|
132
|
+
viewHeight = win.innerHeight;
|
|
133
|
+
} else {
|
|
134
|
+
viewTop = container.getBoundingClientRect().top + container.clientTop;
|
|
135
|
+
viewHeight = container.clientHeight;
|
|
136
|
+
}
|
|
137
|
+
const viewBottom = viewTop + viewHeight;
|
|
138
|
+
let delta = 0;
|
|
139
|
+
if (elRect.top < viewTop) delta = elRect.top - viewTop;
|
|
140
|
+
else if (elRect.bottom > viewBottom) delta = Math.min(elRect.bottom - viewBottom, elRect.top - viewTop);
|
|
141
|
+
if (delta !== 0) container.scrollTop += delta;
|
|
142
|
+
};
|
|
94
143
|
var removeSelectedClassName = (doc) => {
|
|
95
144
|
const oldEl = doc.querySelector(`.${SELECTED_CLASS}`);
|
|
96
145
|
if (oldEl) {
|
|
@@ -189,4 +238,4 @@ var getBorderWidth = (el) => {
|
|
|
189
238
|
};
|
|
190
239
|
};
|
|
191
240
|
//#endregion
|
|
192
|
-
export { addSelectedClassName, down, getAbsolutePosition, getBorderWidth, getMarginValue, getMode, getOffset, getScrollParent, getTargetElStyle, isAbsolute, isFixed, isFixedParent, isMoveableButton, isRelative, isStatic, removeSelectedClassName, up };
|
|
241
|
+
export { addSelectedClassName, down, getAbsolutePosition, getBorderWidth, getMarginValue, getMode, getOffset, getScrollParent, getTargetElStyle, isAbsolute, isDocumentVisible, isElementVisible, isFixed, isFixedParent, isMoveableButton, isRelative, isStatic, removeSelectedClassName, scrollElementIntoView, up };
|