@tmagic/stage 1.8.0-beta.2 → 1.8.0-beta.21

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.
@@ -107,7 +107,8 @@
107
107
  //#endregion
108
108
  //#region node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/_baseGetTag.js
109
109
  /** `Object#toString` result references. */
110
- var nullTag = "[object Null]", undefinedTag = "[object Undefined]";
110
+ var nullTag = "[object Null]";
111
+ var undefinedTag = "[object Undefined]";
111
112
  /** Built-in value references. */
112
113
  var symToStringTag = Symbol$1 ? Symbol$1.toStringTag : void 0;
113
114
  /**
@@ -333,7 +334,10 @@
333
334
  //#endregion
334
335
  //#region node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/isFunction.js
335
336
  /** `Object#toString` result references. */
336
- var asyncTag = "[object AsyncFunction]", funcTag$1 = "[object Function]", genTag = "[object GeneratorFunction]", proxyTag = "[object Proxy]";
337
+ var asyncTag = "[object AsyncFunction]";
338
+ var funcTag$1 = "[object Function]";
339
+ var genTag = "[object GeneratorFunction]";
340
+ var proxyTag = "[object Proxy]";
337
341
  /**
338
342
  * Checks if `value` is classified as a `Function` object.
339
343
  *
@@ -409,7 +413,8 @@
409
413
  /** Used to detect host constructors (Safari). */
410
414
  var reIsHostCtor = /^\[object .+?Constructor\]$/;
411
415
  /** Used for built-in method references. */
412
- var funcProto$1 = Function.prototype, objectProto$3 = Object.prototype;
416
+ var funcProto$1 = Function.prototype;
417
+ var objectProto$3 = Object.prototype;
413
418
  /** Used to resolve the decompiled source of functions. */
414
419
  var funcToString$1 = funcProto$1.toString;
415
420
  /** Used to check objects for own properties. */
@@ -518,7 +523,8 @@
518
523
  //#endregion
519
524
  //#region node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/_shortOut.js
520
525
  /** Used to detect hot functions by number of calls within a span of milliseconds. */
521
- var HOT_COUNT = 800, HOT_SPAN = 16;
526
+ var HOT_COUNT = 800;
527
+ var HOT_SPAN = 16;
522
528
  var nativeNow = Date.now;
523
529
  /**
524
530
  * Creates a function that'll short out and invoke `identity` instead
@@ -978,8 +984,30 @@
978
984
  //#endregion
979
985
  //#region node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/_baseIsTypedArray.js
980
986
  /** `Object#toString` result references. */
981
- var argsTag = "[object Arguments]", arrayTag = "[object Array]", boolTag = "[object Boolean]", dateTag = "[object Date]", errorTag = "[object Error]", funcTag = "[object Function]", mapTag = "[object Map]", numberTag = "[object Number]", objectTag$1 = "[object Object]", regexpTag = "[object RegExp]", setTag = "[object Set]", stringTag = "[object String]", weakMapTag = "[object WeakMap]";
982
- var arrayBufferTag = "[object ArrayBuffer]", dataViewTag = "[object DataView]", float32Tag = "[object Float32Array]", float64Tag = "[object Float64Array]", int8Tag = "[object Int8Array]", int16Tag = "[object Int16Array]", int32Tag = "[object Int32Array]", uint8Tag = "[object Uint8Array]", uint8ClampedTag = "[object Uint8ClampedArray]", uint16Tag = "[object Uint16Array]", uint32Tag = "[object Uint32Array]";
987
+ var argsTag = "[object Arguments]";
988
+ var arrayTag = "[object Array]";
989
+ var boolTag = "[object Boolean]";
990
+ var dateTag = "[object Date]";
991
+ var errorTag = "[object Error]";
992
+ var funcTag = "[object Function]";
993
+ var mapTag = "[object Map]";
994
+ var numberTag = "[object Number]";
995
+ var objectTag$1 = "[object Object]";
996
+ var regexpTag = "[object RegExp]";
997
+ var setTag = "[object Set]";
998
+ var stringTag = "[object String]";
999
+ var weakMapTag = "[object WeakMap]";
1000
+ var arrayBufferTag = "[object ArrayBuffer]";
1001
+ var dataViewTag = "[object DataView]";
1002
+ var float32Tag = "[object Float32Array]";
1003
+ var float64Tag = "[object Float64Array]";
1004
+ var int8Tag = "[object Int8Array]";
1005
+ var int16Tag = "[object Int16Array]";
1006
+ var int32Tag = "[object Int32Array]";
1007
+ var uint8Tag = "[object Uint8Array]";
1008
+ var uint8ClampedTag = "[object Uint8ClampedArray]";
1009
+ var uint16Tag = "[object Uint16Array]";
1010
+ var uint32Tag = "[object Uint32Array]";
983
1011
  /** Used to identify `toStringTag` values of typed arrays. */
984
1012
  var typedArrayTags = {};
985
1013
  typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = typedArrayTags[uint32Tag] = true;
@@ -1513,7 +1541,8 @@
1513
1541
  /** `Object#toString` result references. */
1514
1542
  var objectTag = "[object Object]";
1515
1543
  /** Used for built-in method references. */
1516
- var funcProto = Function.prototype, objectProto = Object.prototype;
1544
+ var funcProto = Function.prototype;
1545
+ var objectProto = Object.prototype;
1517
1546
  /** Used to resolve the decompiled source of functions. */
1518
1547
  var funcToString = funcProto.toString;
1519
1548
  /** Used to check objects for own properties. */
@@ -1666,7 +1695,8 @@
1666
1695
  /** Detect free variable `module`. */
1667
1696
  var freeModule = freeExports && typeof module == "object" && module && !module.nodeType && module;
1668
1697
  /** Built-in value references. */
1669
- var Buffer$1 = freeModule && freeModule.exports === freeExports ? root.Buffer : void 0, allocUnsafe = Buffer$1 ? Buffer$1.allocUnsafe : void 0;
1698
+ var Buffer$1 = freeModule && freeModule.exports === freeExports ? root.Buffer : void 0;
1699
+ var allocUnsafe = Buffer$1 ? Buffer$1.allocUnsafe : void 0;
1670
1700
  /**
1671
1701
  * Creates a clone of `buffer`.
1672
1702
  *
@@ -1783,7 +1813,8 @@
1783
1813
  //#region node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/debounce.js
1784
1814
  /** Error message constants. */
1785
1815
  var FUNC_ERROR_TEXT$1 = "Expected a function";
1786
- var nativeMax = Math.max, nativeMin = Math.min;
1816
+ var nativeMax = Math.max;
1817
+ var nativeMin = Math.min;
1787
1818
  /**
1788
1819
  * Creates a debounced function that delays invoking `func` until after `wait`
1789
1820
  * milliseconds have elapsed since the last time the debounced function was
@@ -2175,6 +2206,8 @@
2175
2206
  var DRAG_EL_ID_PREFIX = "drag_el_";
2176
2207
  /** 高亮时需要在蒙层中创建一个占位节点,该节点的id前缀 */
2177
2208
  var HIGHLIGHT_EL_ID_PREFIX = "highlight_el_";
2209
+ /** 闪烁提示时需要在蒙层中创建一个占位节点,该节点的id前缀 */
2210
+ var FLASH_EL_ID_PREFIX = "flash_el_";
2178
2211
  var CONTAINER_HIGHLIGHT_CLASS_NAME = "tmagic-stage-container-highlight";
2179
2212
  var PAGE_CLASS = "magic-ui-page";
2180
2213
  /** 默认放到缩小倍数 */
@@ -2349,6 +2382,33 @@
2349
2382
  }
2350
2383
  return null;
2351
2384
  };
2385
+ /**
2386
+ * 将元素滚动到指定滚动容器的可视区域内(仅垂直方向,滚动最小距离)
2387
+ * @description 与原生 scrollIntoView 不同,只滚动指定的容器自身,不会连带滚动外层祖先滚动容器,
2388
+ * 避免编辑器画布外层容器(如 stage 外层使用 transform 模拟滚动的容器)被浏览器自动滚动导致整个画布位移
2389
+ * @param el 目标元素
2390
+ * @param container 滚动容器
2391
+ */
2392
+ var scrollElementIntoView = (el, container) => {
2393
+ const { ownerDocument } = container;
2394
+ const win = ownerDocument?.defaultView;
2395
+ if (!ownerDocument || !win) return;
2396
+ const elRect = el.getBoundingClientRect();
2397
+ let viewTop = 0;
2398
+ let viewHeight = 0;
2399
+ if (container === ownerDocument.documentElement || container === ownerDocument.body) {
2400
+ viewTop = 0;
2401
+ viewHeight = win.innerHeight;
2402
+ } else {
2403
+ viewTop = container.getBoundingClientRect().top + container.clientTop;
2404
+ viewHeight = container.clientHeight;
2405
+ }
2406
+ const viewBottom = viewTop + viewHeight;
2407
+ let delta = 0;
2408
+ if (elRect.top < viewTop) delta = elRect.top - viewTop;
2409
+ else if (elRect.bottom > viewBottom) delta = Math.min(elRect.bottom - viewBottom, elRect.top - viewTop);
2410
+ if (delta !== 0) container.scrollTop += delta;
2411
+ };
2352
2412
  var removeSelectedClassName = (doc) => {
2353
2413
  const oldEl = doc.querySelector(`.${SELECTED_CLASS}`);
2354
2414
  if (oldEl) {
@@ -2786,7 +2846,7 @@
2786
2846
  };
2787
2847
  //#endregion
2788
2848
  //#region packages/stage/src/moveable-able.css?raw
2789
- var moveable_able_default = ".moveable-button {\n width: 20px;\n height: 20px;\n background: #4af;\n border-radius: 4px;\n appearance: none;\n border: 0;\n color: white;\n font-size: 12px;\n font-weight: bold;\n margin-left: 2px;\n position: relative;\n cursor: pointer;\n}\n.moveable-remove-button:before, .moveable-remove-button:after {\n content: \"\";\n position: absolute;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%) rotate(45deg);\n width: 14px;\n height: 2px;\n background: #fff;\n border-radius: 1px;\n cursor: pointer;\n}\n.moveable-remove-button:after {\n transform: translate(-50%, -50%) rotate(-45deg);\n}\n\n.moveable-select-parent-arrow-top-icon {\n transform: rotateZ(-45deg);\n width: 4px;\n height: 4px;\n border-color: #fff;\n border-width: 2px 2px 0 0;\n border-style: solid;\n position: absolute;\n left: 4px;\n top: 4px;\n}\n\n.moveable-select-parent-arrow-body-icon {\n width: 7px;\n height: 11px;\n border-color: #fff;\n border-width: 0 0 2px 2px;\n border-style: solid;\n}\n\n.moveable-drag-area-button {\n cursor: move;\n}\n\n.moveable-drag-area-button .moveable-select-parent-arrow-top-icon {\n width: 2px;\n height: 2px;\n}\n\n.moveable-drag-area-button .moveable-select-parent-arrow-top-icon-top {\n transform: rotateZ(-45deg) translateX(-50%);\n left: 50%;\n top: 3px;\n transform-origin: left;\n}\n\n.moveable-drag-area-button .moveable-select-parent-arrow-top-icon-bottom {\n transform: rotateZ(135deg) translateX(-50%);\n transform-origin: left;\n left: 50%;\n top: auto;\n bottom: 3px;\n}\n\n.moveable-drag-area-button .moveable-select-parent-arrow-top-icon-right {\n transform: rotateZ(45deg) translateY(-50%);\n transform-origin: top;\n right: 3px;\n left: auto;\n top: 50%;\n}\n\n.moveable-drag-area-button .moveable-select-parent-arrow-top-icon-left {\n transform: rotateZ(235deg) translateY(-50%);\n transform-origin: top;\n left: 3px;\n top: 50%;\n}\n\n.moveable-drag-area-button .moveable-select-parent-arrow-body-icon-horizontal {\n width: 2px;\n height: 11px;\n background-color: #fff;\n position: absolute;\n transform: translateX(-50%);\n left: 50%;\n top: 4px;\n}\n\n.moveable-drag-area-button .moveable-select-parent-arrow-body-icon-vertical {\n width: 11px;\n height: 2px;\n background-color: #fff;\n position: absolute;\n transform: translateY(-50%);\n left: 4px;\n top: 50%;;\n}\n\n.moveable-rerender-button img {\n position: absolute;\n left: 2px;\n top: 2px;\n}\n";
2849
+ var moveable_able_default = ".moveable-button {\n width: 20px;\n height: 20px;\n background: var(--el-color-primary,#4af);\n border-radius: 4px;\n appearance: none;\n border: 0;\n color: white;\n font-size: 12px;\n font-weight: bold;\n margin-left: 2px;\n position: relative;\n cursor: pointer;\n}\n.moveable-remove-button:before, .moveable-remove-button:after {\n content: \"\";\n position: absolute;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%) rotate(45deg);\n width: 14px;\n height: 2px;\n background: #fff;\n border-radius: 1px;\n cursor: pointer;\n}\n.moveable-remove-button:after {\n transform: translate(-50%, -50%) rotate(-45deg);\n}\n\n.moveable-select-parent-arrow-top-icon {\n transform: rotateZ(-45deg);\n width: 4px;\n height: 4px;\n border-color: #fff;\n border-width: 2px 2px 0 0;\n border-style: solid;\n position: absolute;\n left: 4px;\n top: 4px;\n}\n\n.moveable-select-parent-arrow-body-icon {\n width: 7px;\n height: 11px;\n border-color: #fff;\n border-width: 0 0 2px 2px;\n border-style: solid;\n}\n\n.moveable-drag-area-button {\n cursor: move;\n}\n\n.moveable-drag-area-button .moveable-select-parent-arrow-top-icon {\n width: 2px;\n height: 2px;\n}\n\n.moveable-drag-area-button .moveable-select-parent-arrow-top-icon-top {\n transform: rotateZ(-45deg) translateX(-50%);\n left: 50%;\n top: 3px;\n transform-origin: left;\n}\n\n.moveable-drag-area-button .moveable-select-parent-arrow-top-icon-bottom {\n transform: rotateZ(135deg) translateX(-50%);\n transform-origin: left;\n left: 50%;\n top: auto;\n bottom: 3px;\n}\n\n.moveable-drag-area-button .moveable-select-parent-arrow-top-icon-right {\n transform: rotateZ(45deg) translateY(-50%);\n transform-origin: top;\n right: 3px;\n left: auto;\n top: 50%;\n}\n\n.moveable-drag-area-button .moveable-select-parent-arrow-top-icon-left {\n transform: rotateZ(235deg) translateY(-50%);\n transform-origin: top;\n left: 3px;\n top: 50%;\n}\n\n.moveable-drag-area-button .moveable-select-parent-arrow-body-icon-horizontal {\n width: 2px;\n height: 11px;\n background-color: #fff;\n position: absolute;\n transform: translateX(-50%);\n left: 50%;\n top: 4px;\n}\n\n.moveable-drag-area-button .moveable-select-parent-arrow-body-icon-vertical {\n width: 11px;\n height: 2px;\n background-color: #fff;\n position: absolute;\n transform: translateY(-50%);\n left: 4px;\n top: 50%;;\n}\n\n.moveable-rerender-button img {\n position: absolute;\n left: 2px;\n top: 2px;\n}\n";
2790
2850
  //#endregion
2791
2851
  //#region packages/stage/src/MoveableActionsAble.ts
2792
2852
  var MoveableActionsAble_default = (handler, customizedButton = []) => ({
@@ -3507,6 +3567,8 @@
3507
3567
  containerHighlightDuration;
3508
3568
  /** 将组件加入容器的操作方式 */
3509
3569
  containerHighlightType;
3570
+ /** 是否仅在新增组件时才启用将组件加入容器 */
3571
+ containerHighlightAddOnly = false;
3510
3572
  isAltKeydown = false;
3511
3573
  getTargetElement;
3512
3574
  getElementsFromPoint;
@@ -3540,6 +3602,7 @@
3540
3602
  this.containerHighlightClassName = config.containerHighlightClassName || "tmagic-stage-container-highlight";
3541
3603
  this.containerHighlightDuration = config.containerHighlightDuration || defaultContainerHighlightDuration;
3542
3604
  this.containerHighlightType = config.containerHighlightType;
3605
+ this.containerHighlightAddOnly = config.containerHighlightAddOnly ?? false;
3543
3606
  this.disabledMultiSelect = config.disabledMultiSelect ?? false;
3544
3607
  this.alwaysMultiSelect = config.alwaysMultiSelect ?? false;
3545
3608
  this.getTargetElement = config.getTargetElement;
@@ -3771,10 +3834,11 @@
3771
3834
  * 标记的作用:1、高亮容器,给用户一个加入容器的交互感知;2、释放鼠标后,通过标记的标志找到要加入的容器
3772
3835
  * @param event 鼠标事件
3773
3836
  * @param excludeElList 计算鼠标所在容器时要排除的元素列表
3837
+ * @param isAdd 当前操作是否为新增组件(从组件列表拖入),开启 containerHighlightAddOnly 时只有新增才会标记
3774
3838
  * @returns timeoutId,调用方在鼠标移走时要取消该timeout,阻止标记
3775
3839
  */
3776
- delayedMarkContainer(event, excludeElList = []) {
3777
- if (this.canAddToContainer()) return globalThis.setTimeout(() => {
3840
+ delayedMarkContainer(event, excludeElList = [], isAdd = false) {
3841
+ if (this.canAddToContainer(isAdd)) return globalThis.setTimeout(() => {
3778
3842
  this.addContainerHighlightClassName(event, excludeElList);
3779
3843
  }, this.containerHighlightDuration);
3780
3844
  }
@@ -3893,9 +3957,12 @@
3893
3957
  } else this.selectedElList.push(el);
3894
3958
  }
3895
3959
  /**
3896
- * 当前状态下能否将组件加入容器,默认是鼠标悬停一段时间加入,alt模式则是按住alt+鼠标悬停一段时间加入
3960
+ * 当前状态下能否将组件加入容器,默认是鼠标悬停一段时间加入,alt模式则是按住alt+鼠标悬停一段时间加入;
3961
+ * 开启containerHighlightAddOnly时,画布中拖动已有组件不能加入容器
3962
+ * @param isAdd 当前操作是否为新增组件
3897
3963
  */
3898
- canAddToContainer() {
3964
+ canAddToContainer(isAdd = false) {
3965
+ if (this.containerHighlightAddOnly && !isAdd) return false;
3899
3966
  return this.containerHighlightType === ContainerHighlightType.DEFAULT || this.containerHighlightType === ContainerHighlightType.ALT && this.isAltKeydown;
3900
3967
  }
3901
3968
  /**
@@ -3904,8 +3971,9 @@
3904
3971
  */
3905
3972
  markContainerEnd() {
3906
3973
  const doc = this.getRenderDocument();
3907
- if (doc && this.canAddToContainer()) return (0, _tmagic_core.removeClassNameByClassName)(doc, this.containerHighlightClassName);
3908
- return null;
3974
+ if (!doc) return null;
3975
+ const markedContainer = (0, _tmagic_core.removeClassNameByClassName)(doc, this.containerHighlightClassName);
3976
+ return this.canAddToContainer() ? markedContainer : null;
3909
3977
  }
3910
3978
  initMouseEvent() {
3911
3979
  this.container.addEventListener("mousedown", this.mouseDownHandler);
@@ -3993,6 +4061,104 @@
3993
4061
  };
3994
4062
  };
3995
4063
  //#endregion
4064
+ //#region packages/stage/src/StageFlashHighlight.ts
4065
+ /** 闪烁提示节点的 class name */
4066
+ var FLASH_TIP_CLASS_NAME = "tmagic-stage-flash-tip";
4067
+ /** 闪烁动画名称 */
4068
+ var FLASH_ANIMATION_NAME = "tmagic-stage-flash";
4069
+ /** 闪烁动画时长(ms) */
4070
+ var FLASH_DURATION = 1500;
4071
+ /**
4072
+ * 选中区域闪烁提示
4073
+ * @description 当组件不是通过点击画布选中(如从图层树、面包屑等外部选中)时,在画布上对选中区域做一次高亮闪烁,
4074
+ * 帮助用户快速定位组件在画布中的位置。
4075
+ */
4076
+ var StageFlashHighlight = class {
4077
+ /** 复用 TargetShadow 负责节点的定位校准(updateDragEl、fixed、滚动偏移等) */
4078
+ targetShadow;
4079
+ timer;
4080
+ styleEl;
4081
+ constructor(config) {
4082
+ this.targetShadow = new TargetShadow({
4083
+ container: config.container,
4084
+ updateDragEl: config.updateDragEl,
4085
+ zIndex: ZIndex.SELECTED_EL,
4086
+ idPrefix: FLASH_EL_ID_PREFIX
4087
+ });
4088
+ }
4089
+ /**
4090
+ * 在目标元素所在区域做一次高亮闪烁
4091
+ * @param el 选中组件的Dom节点元素
4092
+ */
4093
+ flash(el) {
4094
+ if (!el) return;
4095
+ this.injectStyle();
4096
+ this.clear();
4097
+ const flashEl = this.targetShadow.update(el);
4098
+ flashEl.classList.add(FLASH_TIP_CLASS_NAME);
4099
+ flashEl.style.boxSizing = "border-box";
4100
+ flashEl.style.pointerEvents = "none";
4101
+ flashEl.style.border = "";
4102
+ this.timer = globalThis.setTimeout(() => {
4103
+ this.clear();
4104
+ }, FLASH_DURATION);
4105
+ }
4106
+ /**
4107
+ * 清除闪烁节点
4108
+ */
4109
+ clear() {
4110
+ if (this.timer) {
4111
+ globalThis.clearTimeout(this.timer);
4112
+ this.timer = void 0;
4113
+ }
4114
+ this.targetShadow.destroyEl();
4115
+ }
4116
+ /**
4117
+ * 销毁实例
4118
+ */
4119
+ destroy() {
4120
+ this.clear();
4121
+ this.targetShadow.destroy();
4122
+ this.styleEl?.remove();
4123
+ this.styleEl = void 0;
4124
+ }
4125
+ /**
4126
+ * 注入闪烁动画样式(仅注入一次)
4127
+ */
4128
+ injectStyle() {
4129
+ if (this.styleEl) return;
4130
+ this.styleEl = (0, _tmagic_core.injectStyle)((0, _tmagic_core.getDocument)(), `
4131
+ @keyframes ${FLASH_ANIMATION_NAME} {
4132
+ 0% {
4133
+ opacity: 0;
4134
+ background-color: rgba(146, 84, 222, 0);
4135
+ }
4136
+ 20% {
4137
+ opacity: 1;
4138
+ background-color: rgba(146, 84, 222, 0.7);
4139
+ }
4140
+ 45% {
4141
+ opacity: 0.6;
4142
+ background-color: rgba(146, 84, 222, 0.4);
4143
+ }
4144
+ 70% {
4145
+ opacity: 1;
4146
+ background-color: rgba(146, 84, 222, 0.7);
4147
+ }
4148
+ 100% {
4149
+ opacity: 0;
4150
+ background-color: rgba(146, 84, 222, 0);
4151
+ }
4152
+ }
4153
+ .${FLASH_TIP_CLASS_NAME} {
4154
+ border: 2px solid #9254de;
4155
+ border-radius: 2px;
4156
+ animation: ${FLASH_ANIMATION_NAME} ${FLASH_DURATION}ms cubic-bezier(0.4, 0, 0.2, 1) both;
4157
+ }
4158
+ `);
4159
+ }
4160
+ };
4161
+ //#endregion
3996
4162
  //#region packages/stage/src/Rule.ts
3997
4163
  var guidesClass = "tmagic-stage-guides";
3998
4164
  var Rule = class extends events.default {
@@ -4244,8 +4410,8 @@
4244
4410
  this.scrollIntoView(scrollParent);
4245
4411
  return;
4246
4412
  }
4247
- el.scrollIntoView();
4248
4413
  if (!this.pageScrollParent) return;
4414
+ scrollElementIntoView(el, this.pageScrollParent);
4249
4415
  this.scrollLeft = this.pageScrollParent.scrollLeft;
4250
4416
  this.scrollTop = this.pageScrollParent.scrollTop;
4251
4417
  this.scroll();
@@ -4586,13 +4752,17 @@
4586
4752
  renderer = null;
4587
4753
  mask = null;
4588
4754
  actionManager = null;
4755
+ flashHighlight = null;
4589
4756
  pageResizeObserver = null;
4590
4757
  autoScrollIntoView;
4591
4758
  customizedRender;
4759
+ /** 非点击画布选中组件时,是否对选中区域做高亮闪烁提示,默认开启 */
4760
+ disabledFlashTip;
4592
4761
  constructor(config) {
4593
4762
  super();
4594
4763
  this.autoScrollIntoView = config.autoScrollIntoView;
4595
4764
  this.customizedRender = config.render;
4765
+ this.disabledFlashTip = config.disabledFlashTip ?? false;
4596
4766
  this.renderer = new StageRender({
4597
4767
  runtimeUrl: config.runtimeUrl,
4598
4768
  zoom: config.zoom,
@@ -4607,6 +4777,10 @@
4607
4777
  disabledRule: config.disabledRule
4608
4778
  });
4609
4779
  this.actionManager = new ActionManager(this.getActionManagerConfig(config));
4780
+ this.flashHighlight = new StageFlashHighlight({
4781
+ container: this.mask.content,
4782
+ updateDragEl: config.updateDragEl
4783
+ });
4610
4784
  this.initRenderEvent();
4611
4785
  this.initActionEvent();
4612
4786
  this.initMaskEvent();
@@ -4615,7 +4789,7 @@
4615
4789
  * 单选选中元素
4616
4790
  * @param id 选中的id
4617
4791
  */
4618
- async select(id, event) {
4792
+ async select(id, event, options = {}) {
4619
4793
  if (!this.renderer) return;
4620
4794
  let el = this.renderer.getTargetElement(id) || null;
4621
4795
  if (!el) el = await new Promise((resolve) => {
@@ -4646,6 +4820,8 @@
4646
4820
  if (el) this.mask?.setLayout(el);
4647
4821
  this.actionManager?.select(el, event);
4648
4822
  if (el && (this.autoScrollIntoView || el.dataset.autoScrollIntoView)) this.mask?.observerIntersection(el);
4823
+ const isPage = el === this.mask?.page || el?.className.includes("magic-ui-page");
4824
+ if (el && !event && options.flash !== false && !this.disabledFlashTip && !isPage) this.flashHighlight?.flash(el);
4649
4825
  }
4650
4826
  /**
4651
4827
  * 多选选中多个元素
@@ -4733,10 +4909,11 @@
4733
4909
  * 标记的作用:1、高亮容器,给用户一个加入容器的交互感知;2、释放鼠标后,通过标记的标志找到要加入的容器
4734
4910
  * @param event 鼠标事件
4735
4911
  * @param excludeElList 计算鼠标所在容器时要排除的元素列表
4912
+ * @param isAdd 当前操作是否为新增组件(从组件列表拖入),开启 containerHighlightAddOnly 时只有新增才会标记
4736
4913
  * @returns timeoutId,调用方在鼠标移走时要取消该timeout,阻止标记
4737
4914
  */
4738
- delayedMarkContainer(event, excludeElList = []) {
4739
- return this.actionManager?.delayedMarkContainer(event, excludeElList);
4915
+ delayedMarkContainer(event, excludeElList = [], isAdd = false) {
4916
+ return this.actionManager?.delayedMarkContainer(event, excludeElList, isAdd);
4740
4917
  }
4741
4918
  getMoveableOption(key) {
4742
4919
  return this.actionManager?.getMoveableOption(key);
@@ -4771,16 +4948,18 @@
4771
4948
  * 销毁实例
4772
4949
  */
4773
4950
  destroy() {
4774
- const { mask, renderer, actionManager, pageResizeObserver } = this;
4951
+ const { mask, renderer, actionManager, flashHighlight, pageResizeObserver } = this;
4775
4952
  renderer?.destroy();
4776
4953
  mask?.destroy();
4777
4954
  actionManager?.destroy();
4955
+ flashHighlight?.destroy();
4778
4956
  pageResizeObserver?.disconnect();
4779
4957
  this.removeAllListeners();
4780
4958
  this.container = void 0;
4781
4959
  this.renderer = null;
4782
4960
  this.mask = null;
4783
4961
  this.actionManager = null;
4962
+ this.flashHighlight = null;
4784
4963
  this.pageResizeObserver = null;
4785
4964
  }
4786
4965
  on(eventName, listener) {
@@ -4807,6 +4986,7 @@
4807
4986
  containerHighlightClassName: config.containerHighlightClassName,
4808
4987
  containerHighlightDuration: config.containerHighlightDuration,
4809
4988
  containerHighlightType: config.containerHighlightType,
4989
+ containerHighlightAddOnly: config.containerHighlightAddOnly,
4810
4990
  moveableOptions: config.moveableOptions,
4811
4991
  container: this.mask.content,
4812
4992
  disabledDragStart: config.disabledDragStart,
@@ -4925,6 +5105,7 @@
4925
5105
  exports.ContainerHighlightType = ContainerHighlightType;
4926
5106
  exports.DEFAULT_ZOOM = DEFAULT_ZOOM;
4927
5107
  exports.DRAG_EL_ID_PREFIX = DRAG_EL_ID_PREFIX;
5108
+ exports.FLASH_EL_ID_PREFIX = FLASH_EL_ID_PREFIX;
4928
5109
  exports.GHOST_EL_ID_PREFIX = GHOST_EL_ID_PREFIX;
4929
5110
  exports.GuidesType = GuidesType;
4930
5111
  exports.HIGHLIGHT_EL_ID_PREFIX = HIGHLIGHT_EL_ID_PREFIX;
@@ -4957,6 +5138,7 @@
4957
5138
  exports.isRelative = isRelative;
4958
5139
  exports.isStatic = isStatic;
4959
5140
  exports.removeSelectedClassName = removeSelectedClassName;
5141
+ exports.scrollElementIntoView = scrollElementIntoView;
4960
5142
  exports.up = up;
4961
5143
  Object.keys(moveable).forEach(function(k) {
4962
5144
  if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.8.0-beta.2",
2
+ "version": "1.8.0-beta.21",
3
3
  "name": "@tmagic/stage",
4
4
  "type": "module",
5
5
  "sideEffects": false,
@@ -44,7 +44,7 @@
44
44
  },
45
45
  "peerDependencies": {
46
46
  "typescript": "^6.0.3",
47
- "@tmagic/core": "1.8.0-beta.2"
47
+ "@tmagic/core": "1.8.0-beta.21"
48
48
  },
49
49
  "peerDependenciesMeta": {
50
50
  "typescript": {
@@ -84,6 +84,8 @@ export default class ActionManager extends EventEmitter {
84
84
  private containerHighlightDuration: number;
85
85
  /** 将组件加入容器的操作方式 */
86
86
  private containerHighlightType?: ContainerHighlightType;
87
+ /** 是否仅在新增组件时才启用将组件加入容器 */
88
+ private containerHighlightAddOnly = false;
87
89
  private isAltKeydown = false;
88
90
  private getTargetElement: GetTargetElement;
89
91
  private getElementsFromPoint: GetElementsFromPoint;
@@ -124,6 +126,7 @@ export default class ActionManager extends EventEmitter {
124
126
  this.containerHighlightClassName = config.containerHighlightClassName || CONTAINER_HIGHLIGHT_CLASS_NAME;
125
127
  this.containerHighlightDuration = config.containerHighlightDuration || defaultContainerHighlightDuration;
126
128
  this.containerHighlightType = config.containerHighlightType;
129
+ this.containerHighlightAddOnly = config.containerHighlightAddOnly ?? false;
127
130
  this.disabledMultiSelect = config.disabledMultiSelect ?? false;
128
131
  this.alwaysMultiSelect = config.alwaysMultiSelect ?? false;
129
132
  this.getTargetElement = config.getTargetElement;
@@ -428,10 +431,15 @@ export default class ActionManager extends EventEmitter {
428
431
  * 标记的作用:1、高亮容器,给用户一个加入容器的交互感知;2、释放鼠标后,通过标记的标志找到要加入的容器
429
432
  * @param event 鼠标事件
430
433
  * @param excludeElList 计算鼠标所在容器时要排除的元素列表
434
+ * @param isAdd 当前操作是否为新增组件(从组件列表拖入),开启 containerHighlightAddOnly 时只有新增才会标记
431
435
  * @returns timeoutId,调用方在鼠标移走时要取消该timeout,阻止标记
432
436
  */
433
- public delayedMarkContainer(event: MouseEvent, excludeElList: Element[] = []): NodeJS.Timeout | undefined {
434
- if (this.canAddToContainer()) {
437
+ public delayedMarkContainer(
438
+ event: MouseEvent,
439
+ excludeElList: Element[] = [],
440
+ isAdd = false,
441
+ ): NodeJS.Timeout | undefined {
442
+ if (this.canAddToContainer(isAdd)) {
435
443
  return globalThis.setTimeout(() => {
436
444
  this.addContainerHighlightClassName(event, excludeElList);
437
445
  }, this.containerHighlightDuration);
@@ -609,9 +617,13 @@ export default class ActionManager extends EventEmitter {
609
617
  }
610
618
 
611
619
  /**
612
- * 当前状态下能否将组件加入容器,默认是鼠标悬停一段时间加入,alt模式则是按住alt+鼠标悬停一段时间加入
620
+ * 当前状态下能否将组件加入容器,默认是鼠标悬停一段时间加入,alt模式则是按住alt+鼠标悬停一段时间加入;
621
+ * 开启containerHighlightAddOnly时,画布中拖动已有组件不能加入容器
622
+ * @param isAdd 当前操作是否为新增组件
613
623
  */
614
- private canAddToContainer(): boolean {
624
+ private canAddToContainer(isAdd = false): boolean {
625
+ if (this.containerHighlightAddOnly && !isAdd) return false;
626
+
615
627
  return (
616
628
  this.containerHighlightType === ContainerHighlightType.DEFAULT ||
617
629
  (this.containerHighlightType === ContainerHighlightType.ALT && this.isAltKeydown)
@@ -624,10 +636,10 @@ export default class ActionManager extends EventEmitter {
624
636
  */
625
637
  private markContainerEnd(): HTMLElement | null {
626
638
  const doc = this.getRenderDocument();
627
- if (doc && this.canAddToContainer()) {
628
- return removeClassNameByClassName(doc, this.containerHighlightClassName);
629
- }
630
- return null;
639
+ if (!doc) return null;
640
+
641
+ const markedContainer = removeClassNameByClassName(doc, this.containerHighlightClassName);
642
+ return this.canAddToContainer() ? markedContainer : null;
631
643
  }
632
644
 
633
645
  private initMouseEvent(): void {
package/src/StageCore.ts CHANGED
@@ -25,7 +25,8 @@ import type { Id } from '@tmagic/core';
25
25
  import { getIdFromEl } from '@tmagic/core';
26
26
 
27
27
  import ActionManager from './ActionManager';
28
- import { DEFAULT_ZOOM } from './const';
28
+ import { DEFAULT_ZOOM, PAGE_CLASS } from './const';
29
+ import StageFlashHighlight from './StageFlashHighlight';
29
30
  import StageMask from './StageMask';
30
31
  import StageRender from './StageRender';
31
32
  import type {
@@ -51,16 +52,20 @@ export default class StageCore extends EventEmitter {
51
52
  public renderer: StageRender | null = null;
52
53
  public mask: StageMask | null = null;
53
54
  public actionManager: ActionManager | null = null;
55
+ public flashHighlight: StageFlashHighlight | null = null;
54
56
 
55
57
  private pageResizeObserver: ResizeObserver | null = null;
56
58
  private autoScrollIntoView: boolean | undefined;
57
59
  private customizedRender?: CustomizeRender;
60
+ /** 非点击画布选中组件时,是否对选中区域做高亮闪烁提示,默认开启 */
61
+ private disabledFlashTip: boolean;
58
62
 
59
63
  constructor(config: StageCoreConfig) {
60
64
  super();
61
65
 
62
66
  this.autoScrollIntoView = config.autoScrollIntoView;
63
67
  this.customizedRender = config.render;
68
+ this.disabledFlashTip = config.disabledFlashTip ?? false;
64
69
 
65
70
  this.renderer = new StageRender({
66
71
  runtimeUrl: config.runtimeUrl,
@@ -78,6 +83,10 @@ export default class StageCore extends EventEmitter {
78
83
  disabledRule: config.disabledRule,
79
84
  });
80
85
  this.actionManager = new ActionManager(this.getActionManagerConfig(config));
86
+ this.flashHighlight = new StageFlashHighlight({
87
+ container: this.mask.content,
88
+ updateDragEl: config.updateDragEl,
89
+ });
81
90
 
82
91
  this.initRenderEvent();
83
92
  this.initActionEvent();
@@ -88,7 +97,7 @@ export default class StageCore extends EventEmitter {
88
97
  * 单选选中元素
89
98
  * @param id 选中的id
90
99
  */
91
- public async select(id: Id, event?: MouseEvent): Promise<void> {
100
+ public async select(id: Id, event?: MouseEvent, options: { flash?: boolean } = {}): Promise<void> {
92
101
  if (!this.renderer) {
93
102
  return;
94
103
  }
@@ -133,6 +142,13 @@ export default class StageCore extends EventEmitter {
133
142
  if (el && (this.autoScrollIntoView || el.dataset.autoScrollIntoView)) {
134
143
  this.mask?.observerIntersection(el);
135
144
  }
145
+
146
+ // 非点击画布选中(如从图层树、面包屑等外部选中,此时没有鼠标事件)时,对选中区域做一次高亮闪烁,帮助用户定位组件
147
+ // 选中页面(mask.page 或带有 magic-ui-page class 的节点)时不做闪烁提示
148
+ const isPage = el === this.mask?.page || el?.className.includes(PAGE_CLASS);
149
+ if (el && !event && options.flash !== false && !this.disabledFlashTip && !isPage) {
150
+ this.flashHighlight?.flash(el);
151
+ }
136
152
  }
137
153
 
138
154
  /**
@@ -247,10 +263,15 @@ export default class StageCore extends EventEmitter {
247
263
  * 标记的作用:1、高亮容器,给用户一个加入容器的交互感知;2、释放鼠标后,通过标记的标志找到要加入的容器
248
264
  * @param event 鼠标事件
249
265
  * @param excludeElList 计算鼠标所在容器时要排除的元素列表
266
+ * @param isAdd 当前操作是否为新增组件(从组件列表拖入),开启 containerHighlightAddOnly 时只有新增才会标记
250
267
  * @returns timeoutId,调用方在鼠标移走时要取消该timeout,阻止标记
251
268
  */
252
- public delayedMarkContainer(event: MouseEvent, excludeElList: Element[] = []): NodeJS.Timeout | undefined {
253
- return this.actionManager?.delayedMarkContainer(event, excludeElList);
269
+ public delayedMarkContainer(
270
+ event: MouseEvent,
271
+ excludeElList: Element[] = [],
272
+ isAdd = false,
273
+ ): NodeJS.Timeout | undefined {
274
+ return this.actionManager?.delayedMarkContainer(event, excludeElList, isAdd);
254
275
  }
255
276
 
256
277
  public getMoveableOption<K extends keyof MoveableOptions>(key: K): MoveableOptions[K] | undefined {
@@ -300,11 +321,12 @@ export default class StageCore extends EventEmitter {
300
321
  * 销毁实例
301
322
  */
302
323
  public destroy(): void {
303
- const { mask, renderer, actionManager, pageResizeObserver } = this;
324
+ const { mask, renderer, actionManager, flashHighlight, pageResizeObserver } = this;
304
325
 
305
326
  renderer?.destroy();
306
327
  mask?.destroy();
307
328
  actionManager?.destroy();
329
+ flashHighlight?.destroy();
308
330
  pageResizeObserver?.disconnect();
309
331
 
310
332
  this.removeAllListeners();
@@ -313,6 +335,7 @@ export default class StageCore extends EventEmitter {
313
335
  this.renderer = null;
314
336
  this.mask = null;
315
337
  this.actionManager = null;
338
+ this.flashHighlight = null;
316
339
  this.pageResizeObserver = null;
317
340
  }
318
341
 
@@ -350,6 +373,7 @@ export default class StageCore extends EventEmitter {
350
373
  containerHighlightClassName: config.containerHighlightClassName,
351
374
  containerHighlightDuration: config.containerHighlightDuration,
352
375
  containerHighlightType: config.containerHighlightType,
376
+ containerHighlightAddOnly: config.containerHighlightAddOnly,
353
377
  moveableOptions: config.moveableOptions,
354
378
  container: this.mask!.content,
355
379
  disabledDragStart: config.disabledDragStart,