@tmagic/stage 1.7.13 → 1.7.14-beta.0

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.
@@ -40,8 +40,12 @@ var ActionManager = class extends EventEmitter$1 {
40
40
  getElementsFromPoint;
41
41
  canSelect;
42
42
  isContainer;
43
+ /** 见 ActionManagerConfig.canDropIn */
44
+ canDropIn;
43
45
  getRenderDocument;
44
46
  disabledMultiSelect = false;
47
+ /** 始终启用多选模式(无需按住 Ctrl/Meta),优先级低于 disabledMultiSelect */
48
+ alwaysMultiSelect = false;
45
49
  config;
46
50
  mouseMoveHandler = throttle((event) => {
47
51
  const handler = async () => {
@@ -65,13 +69,18 @@ var ActionManager = class extends EventEmitter$1 {
65
69
  this.containerHighlightDuration = config.containerHighlightDuration || defaultContainerHighlightDuration;
66
70
  this.containerHighlightType = config.containerHighlightType;
67
71
  this.disabledMultiSelect = config.disabledMultiSelect ?? false;
72
+ this.alwaysMultiSelect = config.alwaysMultiSelect ?? false;
68
73
  this.getTargetElement = config.getTargetElement;
69
74
  this.getElementsFromPoint = config.getElementsFromPoint;
70
75
  this.canSelect = config.canSelect || ((el) => Boolean(getIdFromEl()(el)));
71
76
  this.getRenderDocument = config.getRenderDocument;
72
77
  this.isContainer = config.isContainer;
78
+ this.canDropIn = config.canDropIn;
73
79
  this.dr = this.createDr(config);
74
- if (!this.disabledMultiSelect) this.multiDr = this.createMultiDr(config);
80
+ if (!this.disabledMultiSelect) {
81
+ this.multiDr = this.createMultiDr(config);
82
+ if (this.alwaysMultiSelect) this.isMultiSelectStatus = true;
83
+ }
75
84
  this.highlightLayer = new StageHighlight({
76
85
  container: config.container,
77
86
  updateDragEl: config.updateDragEl,
@@ -82,6 +91,7 @@ var ActionManager = class extends EventEmitter$1 {
82
91
  }
83
92
  disableMultiSelect() {
84
93
  this.disabledMultiSelect = true;
94
+ this.isMultiSelectStatus = false;
85
95
  if (this.multiDr) {
86
96
  this.multiDr.destroy();
87
97
  this.multiDr = null;
@@ -90,6 +100,16 @@ var ActionManager = class extends EventEmitter$1 {
90
100
  enableMultiSelect() {
91
101
  this.disabledMultiSelect = false;
92
102
  if (!this.multiDr) this.multiDr = this.createMultiDr(this.config);
103
+ if (this.alwaysMultiSelect) this.isMultiSelectStatus = true;
104
+ }
105
+ /**
106
+ * 设置是否始终启用多选模式(无需按住 Ctrl/Meta),
107
+ * 当 `disabledMultiSelect` 为 true 时本方法不会启用多选。
108
+ */
109
+ setAlwaysMultiSelect(value) {
110
+ this.alwaysMultiSelect = value;
111
+ if (this.disabledMultiSelect) return;
112
+ this.isMultiSelectStatus = value;
93
113
  }
94
114
  /**
95
115
  * 设置水平/垂直参考线
@@ -255,9 +275,23 @@ var ActionManager = class extends EventEmitter$1 {
255
275
  const doc = this.getRenderDocument();
256
276
  if (!doc) return;
257
277
  const els = this.getElementsFromPoint(event);
258
- for (const el of els) if (!getIdFromEl()(el)?.startsWith("ghost_el_") && await this.isContainer?.(el) && !excludeElList.includes(el)) {
259
- addClassName(el, doc, this.containerHighlightClassName);
260
- break;
278
+ const sourceIds = excludeElList.map((el) => el instanceof HTMLElement ? getIdFromEl()(el) : void 0).filter((id) => Boolean(id));
279
+ for (const el of els) {
280
+ const targetId = getIdFromEl()(el);
281
+ if (!targetId?.startsWith("ghost_el_") && await this.isContainer?.(el) && !excludeElList.includes(el)) {
282
+ let highlightEl = el;
283
+ if (targetId && this.canDropIn) {
284
+ const result = this.canDropIn(sourceIds, targetId);
285
+ if (result === false) continue;
286
+ if (typeof result === "string" || typeof result === "number") {
287
+ const redirectedEl = this.getTargetElement(result);
288
+ if (!redirectedEl) continue;
289
+ highlightEl = redirectedEl;
290
+ }
291
+ }
292
+ addClassName(highlightEl, doc, this.containerHighlightClassName);
293
+ break;
294
+ }
261
295
  }
262
296
  }
263
297
  /**
@@ -419,12 +453,12 @@ var ActionManager = class extends EventEmitter$1 {
419
453
  if (!this.disabledMultiSelect) this.isMultiSelectStatus = true;
420
454
  });
421
455
  KeyController.global.on("blur", () => {
422
- if (!this.disabledMultiSelect) this.isMultiSelectStatus = false;
456
+ if (!this.disabledMultiSelect && !this.alwaysMultiSelect) this.isMultiSelectStatus = false;
423
457
  this.isAltKeydown = false;
424
458
  });
425
459
  KeyController.global.keyup(ctrl, (e) => {
426
460
  e.inputEvent.preventDefault();
427
- if (!this.disabledMultiSelect) this.isMultiSelectStatus = false;
461
+ if (!this.disabledMultiSelect && !this.alwaysMultiSelect) this.isMultiSelectStatus = false;
428
462
  });
429
463
  KeyController.global.keydown("alt", (e) => {
430
464
  e.inputEvent.preventDefault();
@@ -177,6 +177,13 @@ var StageCore = class extends EventEmitter {
177
177
  enableMultiSelect() {
178
178
  this.actionManager?.enableMultiSelect();
179
179
  }
180
+ /**
181
+ * 设置是否始终启用多选模式(无需按住 Ctrl/Meta)。
182
+ * 当多选被 `disabledMultiSelect` 禁用时,本方法不会启用多选。
183
+ */
184
+ setAlwaysMultiSelect(value) {
185
+ this.actionManager?.setAlwaysMultiSelect(value);
186
+ }
180
187
  reloadIframe(url) {
181
188
  this.renderer?.reloadIframe(url);
182
189
  }
@@ -231,8 +238,10 @@ var StageCore = class extends EventEmitter {
231
238
  container: this.mask.content,
232
239
  disabledDragStart: config.disabledDragStart,
233
240
  disabledMultiSelect: config.disabledMultiSelect,
241
+ alwaysMultiSelect: config.alwaysMultiSelect,
234
242
  canSelect: config.canSelect,
235
243
  isContainer: config.isContainer,
244
+ canDropIn: config.canDropIn,
236
245
  updateDragEl: config.updateDragEl,
237
246
  getRootContainer: () => this.container,
238
247
  getRenderDocument: () => this.renderer.getDocument(),
@@ -3512,8 +3512,12 @@
3512
3512
  getElementsFromPoint;
3513
3513
  canSelect;
3514
3514
  isContainer;
3515
+ /** 见 ActionManagerConfig.canDropIn */
3516
+ canDropIn;
3515
3517
  getRenderDocument;
3516
3518
  disabledMultiSelect = false;
3519
+ /** 始终启用多选模式(无需按住 Ctrl/Meta),优先级低于 disabledMultiSelect */
3520
+ alwaysMultiSelect = false;
3517
3521
  config;
3518
3522
  mouseMoveHandler = throttle((event) => {
3519
3523
  const handler = async () => {
@@ -3537,13 +3541,18 @@
3537
3541
  this.containerHighlightDuration = config.containerHighlightDuration || defaultContainerHighlightDuration;
3538
3542
  this.containerHighlightType = config.containerHighlightType;
3539
3543
  this.disabledMultiSelect = config.disabledMultiSelect ?? false;
3544
+ this.alwaysMultiSelect = config.alwaysMultiSelect ?? false;
3540
3545
  this.getTargetElement = config.getTargetElement;
3541
3546
  this.getElementsFromPoint = config.getElementsFromPoint;
3542
3547
  this.canSelect = config.canSelect || ((el) => Boolean((0, _tmagic_core.getIdFromEl)()(el)));
3543
3548
  this.getRenderDocument = config.getRenderDocument;
3544
3549
  this.isContainer = config.isContainer;
3550
+ this.canDropIn = config.canDropIn;
3545
3551
  this.dr = this.createDr(config);
3546
- if (!this.disabledMultiSelect) this.multiDr = this.createMultiDr(config);
3552
+ if (!this.disabledMultiSelect) {
3553
+ this.multiDr = this.createMultiDr(config);
3554
+ if (this.alwaysMultiSelect) this.isMultiSelectStatus = true;
3555
+ }
3547
3556
  this.highlightLayer = new StageHighlight({
3548
3557
  container: config.container,
3549
3558
  updateDragEl: config.updateDragEl,
@@ -3554,6 +3563,7 @@
3554
3563
  }
3555
3564
  disableMultiSelect() {
3556
3565
  this.disabledMultiSelect = true;
3566
+ this.isMultiSelectStatus = false;
3557
3567
  if (this.multiDr) {
3558
3568
  this.multiDr.destroy();
3559
3569
  this.multiDr = null;
@@ -3562,6 +3572,16 @@
3562
3572
  enableMultiSelect() {
3563
3573
  this.disabledMultiSelect = false;
3564
3574
  if (!this.multiDr) this.multiDr = this.createMultiDr(this.config);
3575
+ if (this.alwaysMultiSelect) this.isMultiSelectStatus = true;
3576
+ }
3577
+ /**
3578
+ * 设置是否始终启用多选模式(无需按住 Ctrl/Meta),
3579
+ * 当 `disabledMultiSelect` 为 true 时本方法不会启用多选。
3580
+ */
3581
+ setAlwaysMultiSelect(value) {
3582
+ this.alwaysMultiSelect = value;
3583
+ if (this.disabledMultiSelect) return;
3584
+ this.isMultiSelectStatus = value;
3565
3585
  }
3566
3586
  /**
3567
3587
  * 设置水平/垂直参考线
@@ -3727,9 +3747,23 @@
3727
3747
  const doc = this.getRenderDocument();
3728
3748
  if (!doc) return;
3729
3749
  const els = this.getElementsFromPoint(event);
3730
- for (const el of els) if (!(0, _tmagic_core.getIdFromEl)()(el)?.startsWith("ghost_el_") && await this.isContainer?.(el) && !excludeElList.includes(el)) {
3731
- (0, _tmagic_core.addClassName)(el, doc, this.containerHighlightClassName);
3732
- break;
3750
+ const sourceIds = excludeElList.map((el) => el instanceof HTMLElement ? (0, _tmagic_core.getIdFromEl)()(el) : void 0).filter((id) => Boolean(id));
3751
+ for (const el of els) {
3752
+ const targetId = (0, _tmagic_core.getIdFromEl)()(el);
3753
+ if (!targetId?.startsWith("ghost_el_") && await this.isContainer?.(el) && !excludeElList.includes(el)) {
3754
+ let highlightEl = el;
3755
+ if (targetId && this.canDropIn) {
3756
+ const result = this.canDropIn(sourceIds, targetId);
3757
+ if (result === false) continue;
3758
+ if (typeof result === "string" || typeof result === "number") {
3759
+ const redirectedEl = this.getTargetElement(result);
3760
+ if (!redirectedEl) continue;
3761
+ highlightEl = redirectedEl;
3762
+ }
3763
+ }
3764
+ (0, _tmagic_core.addClassName)(highlightEl, doc, this.containerHighlightClassName);
3765
+ break;
3766
+ }
3733
3767
  }
3734
3768
  }
3735
3769
  /**
@@ -3891,12 +3925,12 @@
3891
3925
  if (!this.disabledMultiSelect) this.isMultiSelectStatus = true;
3892
3926
  });
3893
3927
  keycon.default.global.on("blur", () => {
3894
- if (!this.disabledMultiSelect) this.isMultiSelectStatus = false;
3928
+ if (!this.disabledMultiSelect && !this.alwaysMultiSelect) this.isMultiSelectStatus = false;
3895
3929
  this.isAltKeydown = false;
3896
3930
  });
3897
3931
  keycon.default.global.keyup(ctrl, (e) => {
3898
3932
  e.inputEvent.preventDefault();
3899
- if (!this.disabledMultiSelect) this.isMultiSelectStatus = false;
3933
+ if (!this.disabledMultiSelect && !this.alwaysMultiSelect) this.isMultiSelectStatus = false;
3900
3934
  });
3901
3935
  keycon.default.global.keydown("alt", (e) => {
3902
3936
  e.inputEvent.preventDefault();
@@ -4716,6 +4750,13 @@
4716
4750
  enableMultiSelect() {
4717
4751
  this.actionManager?.enableMultiSelect();
4718
4752
  }
4753
+ /**
4754
+ * 设置是否始终启用多选模式(无需按住 Ctrl/Meta)。
4755
+ * 当多选被 `disabledMultiSelect` 禁用时,本方法不会启用多选。
4756
+ */
4757
+ setAlwaysMultiSelect(value) {
4758
+ this.actionManager?.setAlwaysMultiSelect(value);
4759
+ }
4719
4760
  reloadIframe(url) {
4720
4761
  this.renderer?.reloadIframe(url);
4721
4762
  }
@@ -4770,8 +4811,10 @@
4770
4811
  container: this.mask.content,
4771
4812
  disabledDragStart: config.disabledDragStart,
4772
4813
  disabledMultiSelect: config.disabledMultiSelect,
4814
+ alwaysMultiSelect: config.alwaysMultiSelect,
4773
4815
  canSelect: config.canSelect,
4774
4816
  isContainer: config.isContainer,
4817
+ canDropIn: config.canDropIn,
4775
4818
  updateDragEl: config.updateDragEl,
4776
4819
  getRootContainer: () => this.container,
4777
4820
  getRenderDocument: () => this.renderer.getDocument(),
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.7.13",
2
+ "version": "1.7.14-beta.0",
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.7.13"
47
+ "@tmagic/core": "1.7.14-beta.0"
48
48
  },
49
49
  "peerDependenciesMeta": {
50
50
  "typescript": {
@@ -42,6 +42,7 @@ import StageMultiDragResize from './StageMultiDragResize';
42
42
  import type {
43
43
  ActionManagerConfig,
44
44
  ActionManagerEvents,
45
+ CanDropIn,
45
46
  CanSelect,
46
47
  CustomizeMoveableOptions,
47
48
  CustomizeMoveableOptionsCallbackConfig,
@@ -88,8 +89,12 @@ export default class ActionManager extends EventEmitter {
88
89
  private getElementsFromPoint: GetElementsFromPoint;
89
90
  private canSelect: CanSelect;
90
91
  private isContainer?: IsContainer;
92
+ /** 见 ActionManagerConfig.canDropIn */
93
+ private canDropIn?: CanDropIn;
91
94
  private getRenderDocument: GetRenderDocument;
92
95
  private disabledMultiSelect = false;
96
+ /** 始终启用多选模式(无需按住 Ctrl/Meta),优先级低于 disabledMultiSelect */
97
+ private alwaysMultiSelect = false;
93
98
  private config: ActionManagerConfig;
94
99
 
95
100
  private mouseMoveHandler = throttle((event: MouseEvent): void => {
@@ -120,16 +125,21 @@ export default class ActionManager extends EventEmitter {
120
125
  this.containerHighlightDuration = config.containerHighlightDuration || defaultContainerHighlightDuration;
121
126
  this.containerHighlightType = config.containerHighlightType;
122
127
  this.disabledMultiSelect = config.disabledMultiSelect ?? false;
128
+ this.alwaysMultiSelect = config.alwaysMultiSelect ?? false;
123
129
  this.getTargetElement = config.getTargetElement;
124
130
  this.getElementsFromPoint = config.getElementsFromPoint;
125
131
  this.canSelect = config.canSelect || ((el: HTMLElement) => Boolean(getIdFromEl()(el)));
126
132
  this.getRenderDocument = config.getRenderDocument;
127
133
  this.isContainer = config.isContainer;
134
+ this.canDropIn = config.canDropIn;
128
135
 
129
136
  this.dr = this.createDr(config);
130
137
 
131
138
  if (!this.disabledMultiSelect) {
132
139
  this.multiDr = this.createMultiDr(config);
140
+ if (this.alwaysMultiSelect) {
141
+ this.isMultiSelectStatus = true;
142
+ }
133
143
  }
134
144
 
135
145
  this.highlightLayer = new StageHighlight({
@@ -144,6 +154,7 @@ export default class ActionManager extends EventEmitter {
144
154
 
145
155
  public disableMultiSelect() {
146
156
  this.disabledMultiSelect = true;
157
+ this.isMultiSelectStatus = false;
147
158
  if (this.multiDr) {
148
159
  this.multiDr.destroy();
149
160
  this.multiDr = null;
@@ -156,6 +167,20 @@ export default class ActionManager extends EventEmitter {
156
167
  if (!this.multiDr) {
157
168
  this.multiDr = this.createMultiDr(this.config);
158
169
  }
170
+
171
+ if (this.alwaysMultiSelect) {
172
+ this.isMultiSelectStatus = true;
173
+ }
174
+ }
175
+
176
+ /**
177
+ * 设置是否始终启用多选模式(无需按住 Ctrl/Meta),
178
+ * 当 `disabledMultiSelect` 为 true 时本方法不会启用多选。
179
+ */
180
+ public setAlwaysMultiSelect(value: boolean) {
181
+ this.alwaysMultiSelect = value;
182
+ if (this.disabledMultiSelect) return;
183
+ this.isMultiSelectStatus = value;
159
184
  }
160
185
 
161
186
  /**
@@ -371,14 +396,28 @@ export default class ActionManager extends EventEmitter {
371
396
  if (!doc) return;
372
397
 
373
398
  const els = this.getElementsFromPoint(event);
399
+ // 取出源元素的节点 id 列表(多选拖动时为多个;从组件列表拖入时为空数组)
400
+ const sourceIds: Id[] = excludeElList
401
+ .map((el) => (el instanceof HTMLElement ? getIdFromEl()(el) : undefined))
402
+ .filter((id): id is string => Boolean(id));
374
403
 
375
404
  for (const el of els) {
376
- if (
377
- !getIdFromEl()(el)?.startsWith(GHOST_EL_ID_PREFIX) &&
378
- (await this.isContainer?.(el)) &&
379
- !excludeElList.includes(el)
380
- ) {
381
- addClassName(el, doc, this.containerHighlightClassName);
405
+ const targetId = getIdFromEl()(el);
406
+ if (!targetId?.startsWith(GHOST_EL_ID_PREFIX) && (await this.isContainer?.(el)) && !excludeElList.includes(el)) {
407
+ // 用户配置的钩子可以:
408
+ // - 返回 false 阻止某些源拖入命中的容器(例如禁止 button 拖入 list)
409
+ // - 返回 Id 将拖入目标重定向到另一个容器(例如把命中的 list 重定向到其内层的 list-content)
410
+ let highlightEl: HTMLElement = el;
411
+ if (targetId && this.canDropIn) {
412
+ const result = this.canDropIn(sourceIds, targetId);
413
+ if (result === false) continue;
414
+ if (typeof result === 'string' || typeof result === 'number') {
415
+ const redirectedEl = this.getTargetElement(result);
416
+ if (!redirectedEl) continue;
417
+ highlightEl = redirectedEl;
418
+ }
419
+ }
420
+ addClassName(highlightEl, doc, this.containerHighlightClassName);
382
421
  break;
383
422
  }
384
423
  }
@@ -615,14 +654,14 @@ export default class ActionManager extends EventEmitter {
615
654
  });
616
655
  // ctrl+tab切到其他窗口,需要将多选状态置为false
617
656
  KeyController.global.on('blur', () => {
618
- if (!this.disabledMultiSelect) {
657
+ if (!this.disabledMultiSelect && !this.alwaysMultiSelect) {
619
658
  this.isMultiSelectStatus = false;
620
659
  }
621
660
  this.isAltKeydown = false;
622
661
  });
623
662
  KeyController.global.keyup(ctrl, (e) => {
624
663
  e.inputEvent.preventDefault();
625
- if (!this.disabledMultiSelect) {
664
+ if (!this.disabledMultiSelect && !this.alwaysMultiSelect) {
626
665
  this.isMultiSelectStatus = false;
627
666
  }
628
667
  });
package/src/StageCore.ts CHANGED
@@ -269,6 +269,14 @@ export default class StageCore extends EventEmitter {
269
269
  this.actionManager?.enableMultiSelect();
270
270
  }
271
271
 
272
+ /**
273
+ * 设置是否始终启用多选模式(无需按住 Ctrl/Meta)。
274
+ * 当多选被 `disabledMultiSelect` 禁用时,本方法不会启用多选。
275
+ */
276
+ public setAlwaysMultiSelect(value: boolean) {
277
+ this.actionManager?.setAlwaysMultiSelect(value);
278
+ }
279
+
272
280
  public reloadIframe(url: string) {
273
281
  this.renderer?.reloadIframe(url);
274
282
  }
@@ -346,8 +354,10 @@ export default class StageCore extends EventEmitter {
346
354
  container: this.mask!.content,
347
355
  disabledDragStart: config.disabledDragStart,
348
356
  disabledMultiSelect: config.disabledMultiSelect,
357
+ alwaysMultiSelect: config.alwaysMultiSelect,
349
358
  canSelect: config.canSelect,
350
359
  isContainer: config.isContainer,
360
+ canDropIn: config.canDropIn,
351
361
  updateDragEl: config.updateDragEl,
352
362
  getRootContainer: () => this.container,
353
363
  getRenderDocument: () => this.renderer!.getDocument(),
package/src/types.ts CHANGED
@@ -30,6 +30,18 @@ export type TargetElement = HTMLElement | SVGElement;
30
30
 
31
31
  export type CanSelect = (el: HTMLElement, event: MouseEvent, stop: () => boolean) => boolean | Promise<boolean>;
32
32
  export type IsContainer = (el: HTMLElement) => boolean | Promise<boolean>;
33
+ /**
34
+ * 判断当前正在拖动的源是否可以拖入目标容器(用于画布上拖入组件时的容器高亮命中)
35
+ * @param sourceIds 当前正在拖动的源节点 id 列表
36
+ * - 在画布上拖动已有组件时:为被拖动的组件 id(多选拖动时为多个)
37
+ * - 从组件列表拖入新组件时:为空数组(此时尚无 id,可仅依据 targetId 判断)
38
+ * @param targetId 已通过 isContainer 命中的候选容器节点 id
39
+ * @returns
40
+ * - `false`:阻止该容器被视为合法拖入目标(不会被高亮命中)
41
+ * - `Id`(string | number):将拖入目标重定向到该 id 对应的节点
42
+ * - 其他(`true` / `void` / `undefined`):按命中的 targetId 正常拖入
43
+ */
44
+ export type CanDropIn = (sourceIds: Id[], targetId: Id) => Id | boolean | void;
33
45
  export type CustomizeRender = (renderer: StageCore) => Promise<HTMLElement | void> | HTMLElement | void;
34
46
 
35
47
  export type CustomizeMoveableOptionsFunction = (config: CustomizeMoveableOptionsCallbackConfig) => MoveableOptions;
@@ -54,6 +66,11 @@ export interface StageCoreConfig {
54
66
  zoom?: number;
55
67
  canSelect?: CanSelect;
56
68
  isContainer?: IsContainer;
69
+ /**
70
+ * 画布上拖动组件时,对已通过 isContainer 命中的候选容器进行二次过滤,
71
+ * 用于实现"某些源不允许拖入某些容器内部"的场景。返回 false 时阻止该容器被高亮命中
72
+ */
73
+ canDropIn?: CanDropIn;
57
74
  containerHighlightClassName?: string;
58
75
  containerHighlightDuration?: number;
59
76
  containerHighlightType?: ContainerHighlightType;
@@ -67,6 +84,11 @@ export interface StageCoreConfig {
67
84
  renderType?: RenderType;
68
85
  guidesOptions?: Partial<GuidesOptions>;
69
86
  disabledMultiSelect?: boolean;
87
+ /**
88
+ * 始终启用多选模式(无需按住 Ctrl/Meta),默认 false。
89
+ * 当 `disabledMultiSelect` 为 true 时,本配置失效。
90
+ */
91
+ alwaysMultiSelect?: boolean;
70
92
  disabledRule?: boolean;
71
93
  }
72
94
 
@@ -78,8 +100,15 @@ export interface ActionManagerConfig {
78
100
  moveableOptions?: CustomizeMoveableOptions;
79
101
  disabledDragStart?: boolean;
80
102
  disabledMultiSelect?: boolean;
103
+ /**
104
+ * 始终启用多选模式(无需按住 Ctrl/Meta),默认 false。
105
+ * 当 `disabledMultiSelect` 为 true 时,本配置失效。
106
+ */
107
+ alwaysMultiSelect?: boolean;
81
108
  canSelect?: CanSelect;
82
109
  isContainer?: IsContainer;
110
+ /** 见 StageCoreConfig.canDropIn */
111
+ canDropIn?: CanDropIn;
83
112
  getRootContainer: GetRootContainer;
84
113
  getRenderDocument: GetRenderDocument;
85
114
  updateDragEl?: UpdateDragEl;
package/types/index.d.ts CHANGED
@@ -160,6 +160,18 @@ declare class DragResizeHelper {
160
160
  type TargetElement = HTMLElement | SVGElement;
161
161
  type CanSelect = (el: HTMLElement, event: MouseEvent, stop: () => boolean) => boolean | Promise<boolean>;
162
162
  type IsContainer = (el: HTMLElement) => boolean | Promise<boolean>;
163
+ /**
164
+ * 判断当前正在拖动的源是否可以拖入目标容器(用于画布上拖入组件时的容器高亮命中)
165
+ * @param sourceIds 当前正在拖动的源节点 id 列表
166
+ * - 在画布上拖动已有组件时:为被拖动的组件 id(多选拖动时为多个)
167
+ * - 从组件列表拖入新组件时:为空数组(此时尚无 id,可仅依据 targetId 判断)
168
+ * @param targetId 已通过 isContainer 命中的候选容器节点 id
169
+ * @returns
170
+ * - `false`:阻止该容器被视为合法拖入目标(不会被高亮命中)
171
+ * - `Id`(string | number):将拖入目标重定向到该 id 对应的节点
172
+ * - 其他(`true` / `void` / `undefined`):按命中的 targetId 正常拖入
173
+ */
174
+ type CanDropIn = (sourceIds: Id[], targetId: Id) => Id | boolean | void;
163
175
  type CustomizeRender = (renderer: StageCore) => Promise<HTMLElement | void> | HTMLElement | void;
164
176
  type CustomizeMoveableOptionsFunction = (config: CustomizeMoveableOptionsCallbackConfig) => MoveableOptions;
165
177
  /** 业务方自定义的moveableOptions,可以是配置,也可以是回调函数 */
@@ -180,6 +192,11 @@ interface StageCoreConfig {
180
192
  zoom?: number;
181
193
  canSelect?: CanSelect;
182
194
  isContainer?: IsContainer;
195
+ /**
196
+ * 画布上拖动组件时,对已通过 isContainer 命中的候选容器进行二次过滤,
197
+ * 用于实现"某些源不允许拖入某些容器内部"的场景。返回 false 时阻止该容器被高亮命中
198
+ */
199
+ canDropIn?: CanDropIn;
183
200
  containerHighlightClassName?: string;
184
201
  containerHighlightDuration?: number;
185
202
  containerHighlightType?: ContainerHighlightType;
@@ -193,6 +210,11 @@ interface StageCoreConfig {
193
210
  renderType?: RenderType;
194
211
  guidesOptions?: Partial<GuidesOptions$1>;
195
212
  disabledMultiSelect?: boolean;
213
+ /**
214
+ * 始终启用多选模式(无需按住 Ctrl/Meta),默认 false。
215
+ * 当 `disabledMultiSelect` 为 true 时,本配置失效。
216
+ */
217
+ alwaysMultiSelect?: boolean;
196
218
  disabledRule?: boolean;
197
219
  }
198
220
  interface ActionManagerConfig {
@@ -203,8 +225,15 @@ interface ActionManagerConfig {
203
225
  moveableOptions?: CustomizeMoveableOptions;
204
226
  disabledDragStart?: boolean;
205
227
  disabledMultiSelect?: boolean;
228
+ /**
229
+ * 始终启用多选模式(无需按住 Ctrl/Meta),默认 false。
230
+ * 当 `disabledMultiSelect` 为 true 时,本配置失效。
231
+ */
232
+ alwaysMultiSelect?: boolean;
206
233
  canSelect?: CanSelect;
207
234
  isContainer?: IsContainer;
235
+ /** 见 StageCoreConfig.canDropIn */
236
+ canDropIn?: CanDropIn;
208
237
  getRootContainer: GetRootContainer;
209
238
  getRenderDocument: GetRenderDocument;
210
239
  updateDragEl?: UpdateDragEl;
@@ -433,13 +462,22 @@ declare class ActionManager extends EventEmitter$1 {
433
462
  private getElementsFromPoint;
434
463
  private canSelect;
435
464
  private isContainer?;
465
+ /** 见 ActionManagerConfig.canDropIn */
466
+ private canDropIn?;
436
467
  private getRenderDocument;
437
468
  private disabledMultiSelect;
469
+ /** 始终启用多选模式(无需按住 Ctrl/Meta),优先级低于 disabledMultiSelect */
470
+ private alwaysMultiSelect;
438
471
  private config;
439
472
  private mouseMoveHandler;
440
473
  constructor(config: ActionManagerConfig);
441
474
  disableMultiSelect(): void;
442
475
  enableMultiSelect(): void;
476
+ /**
477
+ * 设置是否始终启用多选模式(无需按住 Ctrl/Meta),
478
+ * 当 `disabledMultiSelect` 为 true 时本方法不会启用多选。
479
+ */
480
+ setAlwaysMultiSelect(value: boolean): void;
443
481
  /**
444
482
  * 设置水平/垂直参考线
445
483
  * @param type 参考线类型
@@ -814,6 +852,11 @@ declare class StageCore extends EventEmitter {
814
852
  getDragStatus(): _$_tmagic_editor0.StageDragStatus | undefined;
815
853
  disableMultiSelect(): void;
816
854
  enableMultiSelect(): void;
855
+ /**
856
+ * 设置是否始终启用多选模式(无需按住 Ctrl/Meta)。
857
+ * 当多选被 `disabledMultiSelect` 禁用时,本方法不会启用多选。
858
+ */
859
+ setAlwaysMultiSelect(value: boolean): void;
817
860
  reloadIframe(url: string): void;
818
861
  /**
819
862
  * 将指定id的dom元素生成为图片
@@ -1060,4 +1103,4 @@ declare const _default: (handler: (type: AbleActionEventType) => void, customize
1060
1103
  render(moveable: MoveableManagerInterface<any, any>, React: Renderer): any;
1061
1104
  };
1062
1105
  //#endregion
1063
- export { AbleActionEventType, AbleCustomizedButton, ActionManagerConfig, ActionManagerEvents, CONTAINER_HIGHLIGHT_CLASS_NAME, CanSelect, ContainerHighlightType, CoreEvents, CustomizeMoveableOptions, CustomizeMoveableOptionsCallbackConfig, CustomizeMoveableOptionsFunction, CustomizeRender, DEFAULT_ZOOM, DRAG_EL_ID_PREFIX, DelayedMarkContainer, DrEvents, DragResizeHelperConfig, GHOST_EL_ID_PREFIX, GetElementsFromPoint, GetRenderDocument, GetRootContainer, GetTargetElement, GuidesEventData, type GuidesOptions, GuidesType, HIGHLIGHT_EL_ID_PREFIX, IsContainer, Magic, MarkContainerEnd, MaskEvents, Mode, MouseButton, _default as MoveableActionsAble, MoveableOptionsManagerConfig, MultiDrEvents, Offset, PAGE_CLASS, Point, Rect, RemoveData, RemoveEventData, RenderEvents, RenderType, RuleOptions, Runtime, RuntimeWindow, SELECTED_CLASS, SelectStatus, SortEventData, StageCoreConfig, StageDragResize, StageDragResizeConfig, StageDragStatus, StageHighlightConfig, StageMask, StageMaskConfig, StageMultiDragResizeConfig, StageRender, StageRenderConfig, TargetElement, TargetShadowConfig, UpdateData, UpdateDragEl, UpdateEventData, ZIndex, addSelectedClassName, StageCore as default, down, getAbsolutePosition, getBorderWidth, getMarginValue, getMode, getOffset, getScrollParent, getTargetElStyle, isAbsolute, isFixed, isFixedParent, isMoveableButton, isRelative, isStatic, removeSelectedClassName, up };
1106
+ export { AbleActionEventType, AbleCustomizedButton, ActionManagerConfig, ActionManagerEvents, CONTAINER_HIGHLIGHT_CLASS_NAME, CanDropIn, CanSelect, ContainerHighlightType, CoreEvents, CustomizeMoveableOptions, CustomizeMoveableOptionsCallbackConfig, CustomizeMoveableOptionsFunction, CustomizeRender, DEFAULT_ZOOM, DRAG_EL_ID_PREFIX, DelayedMarkContainer, DrEvents, DragResizeHelperConfig, GHOST_EL_ID_PREFIX, GetElementsFromPoint, GetRenderDocument, GetRootContainer, GetTargetElement, GuidesEventData, type GuidesOptions, GuidesType, HIGHLIGHT_EL_ID_PREFIX, IsContainer, Magic, MarkContainerEnd, MaskEvents, Mode, MouseButton, _default as MoveableActionsAble, MoveableOptionsManagerConfig, MultiDrEvents, Offset, PAGE_CLASS, Point, Rect, RemoveData, RemoveEventData, RenderEvents, RenderType, RuleOptions, Runtime, RuntimeWindow, SELECTED_CLASS, SelectStatus, SortEventData, StageCoreConfig, StageDragResize, StageDragResizeConfig, StageDragStatus, StageHighlightConfig, StageMask, StageMaskConfig, StageMultiDragResizeConfig, StageRender, StageRenderConfig, TargetElement, TargetShadowConfig, UpdateData, UpdateDragEl, UpdateEventData, ZIndex, addSelectedClassName, StageCore as default, down, getAbsolutePosition, getBorderWidth, getMarginValue, getMode, getOffset, getScrollParent, getTargetElStyle, isAbsolute, isFixed, isFixedParent, isMoveableButton, isRelative, isStatic, removeSelectedClassName, up };