@plait/core 0.55.1 → 0.56.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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { IterableDiffers, inject, ViewContainerRef, Directive, Input, Injectable, EventEmitter, ElementRef, Component, ChangeDetectionStrategy, Output, HostBinding, ViewChild, ContentChildren } from '@angular/core';
2
+ import { IterableDiffers, inject, ViewContainerRef, ChangeDetectorRef, Directive, Input, Injectable, EventEmitter, ElementRef, Component, ChangeDetectionStrategy, Output, HostBinding, ViewChild, ContentChildren } from '@angular/core';
3
3
  import rough from 'roughjs/bin/rough';
4
4
  import { timer, Subject, fromEvent } from 'rxjs';
5
5
  import { takeUntil, filter, tap } from 'rxjs/operators';
@@ -30,6 +30,7 @@ const BOARD_TO_IS_SELECTION_MOVING = new WeakMap();
30
30
  const BOARD_TO_TEMPORARY_ELEMENTS = new WeakMap();
31
31
  const BOARD_TO_MOVING_ELEMENT = new WeakMap();
32
32
  const PATH_REFS = new WeakMap();
33
+ const ELEMENT_TO_REF = new WeakMap();
33
34
 
34
35
  var PlaitPointerType;
35
36
  (function (PlaitPointerType) {
@@ -278,7 +279,7 @@ const getHitElementByPoint = (board, point, match = () => true) => {
278
279
  if (hitElement) {
279
280
  return;
280
281
  }
281
- if (PlaitBoard.isBoard(node) || !match(node)) {
282
+ if (PlaitBoard.isBoard(node) || !match(node) || !PlaitElement.hasMounted(node)) {
282
283
  return;
283
284
  }
284
285
  if (board.isHit(node, point)) {
@@ -544,26 +545,6 @@ function createRect(rectangle, options) {
544
545
  const setStrokeLinecap = (g, value) => {
545
546
  g.setAttribute('stroke-linecap', value);
546
547
  };
547
- const setAngleForG = (g, centerPoint, angle) => {
548
- if (angle === 0) {
549
- g.removeAttribute('transform');
550
- return;
551
- }
552
- var centerX = centerPoint[0];
553
- var centerY = centerPoint[1];
554
- let cosTheta = Math.cos(angle);
555
- let sinTheta = Math.sin(angle);
556
- let transformMatrix = [
557
- cosTheta,
558
- sinTheta,
559
- -sinTheta,
560
- cosTheta,
561
- centerX * (1 - cosTheta) + centerY * sinTheta,
562
- centerY * (1 - cosTheta) - centerX * sinTheta
563
- ];
564
- let matrix = 'matrix(' + transformMatrix.join(',') + ')';
565
- g.setAttribute('transform', `${matrix}`);
566
- };
567
548
  const setPathStrokeLinecap = (g, value) => {
568
549
  g.querySelectorAll('path').forEach(path => {
569
550
  path.setAttribute('stroke-linecap', value);
@@ -848,6 +829,7 @@ class PlaitPluginElementComponent {
848
829
  const containerG = this.getContainerG();
849
830
  NODE_TO_G.set(this.element, elementG);
850
831
  NODE_TO_CONTAINER_G.set(this.element, containerG);
832
+ ELEMENT_TO_REF.set(this.element, this.ref);
851
833
  this.updateListRender();
852
834
  this.cdr.markForCheck();
853
835
  if (hasOnContextChanged(this)) {
@@ -866,6 +848,7 @@ class PlaitPluginElementComponent {
866
848
  }
867
849
  NODE_TO_G.set(this.element, this._g);
868
850
  NODE_TO_CONTAINER_G.set(this.element, this._containerG);
851
+ ELEMENT_TO_REF.set(this.element, this.ref);
869
852
  }
870
853
  }
871
854
  get context() {
@@ -886,9 +869,10 @@ class PlaitPluginElementComponent {
886
869
  getElementG() {
887
870
  return this._g;
888
871
  }
889
- constructor(cdr) {
890
- this.cdr = cdr;
872
+ constructor(ref) {
873
+ this.ref = ref;
891
874
  this.viewContainerRef = inject(ViewContainerRef);
875
+ this.cdr = inject(ChangeDetectorRef);
892
876
  this.initialized = false;
893
877
  }
894
878
  ngOnInit() {
@@ -916,6 +900,9 @@ class PlaitPluginElementComponent {
916
900
  }
917
901
  }
918
902
  }
903
+ getRef() {
904
+ return this.ref;
905
+ }
919
906
  updateListRender() {
920
907
  if (this.hasChildren) {
921
908
  if (!this.listRender) {
@@ -951,15 +938,18 @@ class PlaitPluginElementComponent {
951
938
  if (NODE_TO_CONTAINER_G.get(this.element) === this._containerG) {
952
939
  NODE_TO_CONTAINER_G.delete(this.element);
953
940
  }
941
+ if (ELEMENT_TO_REF.get(this.element) === this.ref) {
942
+ ELEMENT_TO_REF.set(this.element, this.ref);
943
+ }
954
944
  removeSelectedElement(this.board, this.element);
955
945
  this.getContainerG().remove();
956
946
  }
957
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: PlaitPluginElementComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); }
947
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: PlaitPluginElementComponent, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive }); }
958
948
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.2.4", type: PlaitPluginElementComponent, inputs: { context: "context" }, ngImport: i0 }); }
959
949
  }
960
950
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: PlaitPluginElementComponent, decorators: [{
961
951
  type: Directive
962
- }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { context: [{
952
+ }], ctorParameters: () => [{ type: undefined }], propDecorators: { context: [{
963
953
  type: Input
964
954
  }] } });
965
955
  const ELEMENT_TO_COMPONENT = new WeakMap();
@@ -1052,6 +1042,41 @@ function getNearestPointBetweenPointAndSegments(point, points, isClose = true) {
1052
1042
  }
1053
1043
  return result;
1054
1044
  }
1045
+ function getNearestPointBetweenPointAndEllipse(point, center, rx, ry, rotation = 0) {
1046
+ const rectangleClient = {
1047
+ x: center[0] - rx,
1048
+ y: center[1] - ry,
1049
+ height: ry * 2,
1050
+ width: rx * 2
1051
+ };
1052
+ // https://stackoverflow.com/a/46007540/232122
1053
+ const px = Math.abs(point[0] - rectangleClient.x - rectangleClient.width / 2);
1054
+ const py = Math.abs(point[1] - rectangleClient.y - rectangleClient.height / 2);
1055
+ let tx = 0.707;
1056
+ let ty = 0.707;
1057
+ const a = Math.abs(rectangleClient.width) / 2;
1058
+ const b = Math.abs(rectangleClient.height) / 2;
1059
+ [0, 1, 2, 3].forEach(x => {
1060
+ const xx = a * tx;
1061
+ const yy = b * ty;
1062
+ const ex = ((a * a - b * b) * tx ** 3) / a;
1063
+ const ey = ((b * b - a * a) * ty ** 3) / b;
1064
+ const rx = xx - ex;
1065
+ const ry = yy - ey;
1066
+ const qx = px - ex;
1067
+ const qy = py - ey;
1068
+ const r = Math.hypot(ry, rx);
1069
+ const q = Math.hypot(qy, qx);
1070
+ tx = Math.min(1, Math.max(0, ((qx * r) / q + ex) / a));
1071
+ ty = Math.min(1, Math.max(0, ((qy * r) / q + ey) / b));
1072
+ const t = Math.hypot(ty, tx);
1073
+ tx /= t;
1074
+ ty /= t;
1075
+ });
1076
+ const signX = point[0] > center[0] ? 1 : -1;
1077
+ const signY = point[1] > center[1] ? 1 : -1;
1078
+ return [center[0] + a * tx * signX, center[1] + b * ty * signY];
1079
+ }
1055
1080
  function rotate(x1, y1, x2, y2, angle) {
1056
1081
  // 𝑎′𝑥=(𝑎𝑥−𝑐𝑥)cos𝜃−(𝑎𝑦−𝑐𝑦)sin𝜃+𝑐𝑥
1057
1082
  // 𝑎′𝑦=(𝑎𝑥−𝑐𝑥)sin𝜃+(𝑎𝑦−𝑐𝑦)cos𝜃+𝑐𝑦.
@@ -3425,6 +3450,29 @@ const getAngleBetweenPoints = (startPoint, endPoint, centerPoint) => {
3425
3450
  const endAngle = (5 * Math.PI) / 2 + Math.atan2(endPoint[1] - centerPoint[1], endPoint[0] - centerPoint[0]);
3426
3451
  return normalizeAngle(endAngle - startAngle);
3427
3452
  };
3453
+ const getAngleByElement = (element) => {
3454
+ return element?.angle;
3455
+ };
3456
+ const setAngleForG = (g, centerPoint, angle) => {
3457
+ if (angle === 0) {
3458
+ g.removeAttribute('transform');
3459
+ return;
3460
+ }
3461
+ var centerX = centerPoint[0];
3462
+ var centerY = centerPoint[1];
3463
+ let cosTheta = Math.cos(angle);
3464
+ let sinTheta = Math.sin(angle);
3465
+ let transformMatrix = [
3466
+ cosTheta,
3467
+ sinTheta,
3468
+ -sinTheta,
3469
+ cosTheta,
3470
+ centerX * (1 - cosTheta) + centerY * sinTheta,
3471
+ centerY * (1 - cosTheta) - centerX * sinTheta
3472
+ ];
3473
+ let matrix = 'matrix(' + transformMatrix.join(',') + ')';
3474
+ g.setAttribute('transform', `${matrix}`);
3475
+ };
3428
3476
 
3429
3477
  function isSelectionMoving(board) {
3430
3478
  return !!BOARD_TO_IS_SELECTION_MOVING.get(board);
@@ -3592,14 +3640,14 @@ const getRectangleByGroup = (board, group, recursion) => {
3592
3640
  const elementsInGroup = getAllElementsInGroup(board, group, recursion);
3593
3641
  return getRectangleByElements(board, elementsInGroup, false);
3594
3642
  };
3595
- const getGroupByElement = (board, element, recursion, source) => {
3596
- const group = (source || board.children).find(item => item.id === element?.groupId);
3643
+ const getGroupByElement = (board, element, recursion, originElements) => {
3644
+ const group = (originElements || board.children).find(item => item.id === element?.groupId);
3597
3645
  if (!group) {
3598
3646
  return recursion ? [] : null;
3599
3647
  }
3600
3648
  if (recursion) {
3601
3649
  const groups = [group];
3602
- const grandGroups = getGroupByElement(board, group, recursion, source);
3650
+ const grandGroups = getGroupByElement(board, group, recursion, originElements);
3603
3651
  if (grandGroups.length) {
3604
3652
  groups.push(...grandGroups);
3605
3653
  }
@@ -3626,14 +3674,14 @@ const getElementsInGroupByElement = (board, element) => {
3626
3674
  }
3627
3675
  };
3628
3676
  const isSelectedElementOrGroup = (board, element, elements) => {
3629
- const selectedElements = elements || getSelectedElements(board);
3677
+ const selectedElements = elements?.length ? elements : getSelectedElements(board);
3630
3678
  if (PlaitGroupElement.isGroup(element)) {
3631
3679
  return isSelectedAllElementsInGroup(board, element, elements);
3632
3680
  }
3633
3681
  return selectedElements.map(item => item.id).includes(element.id);
3634
3682
  };
3635
3683
  const isSelectedAllElementsInGroup = (board, group, elements) => {
3636
- const selectedElements = elements || getSelectedElements(board);
3684
+ const selectedElements = elements?.length ? elements : getSelectedElements(board);
3637
3685
  const elementsInGroup = getElementsInGroup(board, group, true);
3638
3686
  return elementsInGroup.every(item => selectedElements.map(element => element.id).includes(item.id));
3639
3687
  };
@@ -3646,8 +3694,8 @@ const filterSelectedGroups = (board, groups, elements) => {
3646
3694
  });
3647
3695
  return selectedGroups;
3648
3696
  };
3649
- const getSelectedGroups = (board, elements) => {
3650
- const highestSelectedGroups = getHighestSelectedGroups(board, elements);
3697
+ const getSelectedGroups = (board, elements, originElements) => {
3698
+ const highestSelectedGroups = getHighestSelectedGroups(board, elements, originElements);
3651
3699
  const groups = [];
3652
3700
  highestSelectedGroups.forEach(item => {
3653
3701
  groups.push(item);
@@ -3656,20 +3704,20 @@ const getSelectedGroups = (board, elements) => {
3656
3704
  });
3657
3705
  return groups;
3658
3706
  };
3659
- const getHighestSelectedGroup = (board, element, elements) => {
3660
- const hitElementGroups = getGroupByElement(board, element, true, elements);
3707
+ const getHighestSelectedGroup = (board, element, elements, originElements) => {
3708
+ const hitElementGroups = getGroupByElement(board, element, true, originElements);
3661
3709
  const selectedGroups = filterSelectedGroups(board, hitElementGroups, elements);
3662
3710
  if (selectedGroups.length) {
3663
3711
  return selectedGroups[selectedGroups.length - 1];
3664
3712
  }
3665
3713
  return null;
3666
3714
  };
3667
- const getHighestSelectedGroups = (board, elements) => {
3715
+ const getHighestSelectedGroups = (board, elements, originElements) => {
3668
3716
  let result = [];
3669
- const selectedElements = elements || getSelectedElements(board);
3717
+ const selectedElements = elements?.length ? elements : getSelectedElements(board);
3670
3718
  selectedElements.forEach(item => {
3671
3719
  if (item.groupId) {
3672
- const group = getHighestSelectedGroup(board, item, elements);
3720
+ const group = getHighestSelectedGroup(board, item, elements, originElements);
3673
3721
  if (group && !result.includes(group)) {
3674
3722
  result.push(group);
3675
3723
  }
@@ -3679,7 +3727,7 @@ const getHighestSelectedGroups = (board, elements) => {
3679
3727
  };
3680
3728
  const getSelectedIsolatedElements = (board, elements) => {
3681
3729
  let result = [];
3682
- const selectedElements = elements || getSelectedElements(board);
3730
+ const selectedElements = elements?.length ? elements : getSelectedElements(board);
3683
3731
  selectedElements
3684
3732
  .filter(item => !PlaitGroupElement.isGroup(item))
3685
3733
  .forEach(item => {
@@ -3754,9 +3802,9 @@ const canAddGroup = (board, elements) => {
3754
3802
  }
3755
3803
  return false;
3756
3804
  };
3757
- const canRemoveGroup = (board, elements) => {
3758
- const selectedGroups = getHighestSelectedGroups(board, elements);
3759
- const selectedElements = elements || getSelectedElements(board);
3805
+ const canRemoveGroup = (board, elements, originElements) => {
3806
+ const selectedGroups = getHighestSelectedGroups(board, elements, originElements);
3807
+ const selectedElements = elements?.length ? elements : getSelectedElements(board);
3760
3808
  return selectedElements.length > 0 && selectedGroups.length > 0;
3761
3809
  };
3762
3810
  const getEditingGroup = (board, element) => {
@@ -3794,17 +3842,17 @@ const setFragment = (board, type, clipboardData) => {
3794
3842
  const clipboardContext = board.buildFragment(null, rectangle, type);
3795
3843
  clipboardContext && setClipboardData(clipboardData, clipboardContext);
3796
3844
  };
3797
- const duplicateElements = (board, elements) => {
3798
- const selectedElements = elements || getSelectedElements(board);
3799
- const rectangle = getRectangleByElements(board, selectedElements, false);
3800
- const clipboardContext = board.buildFragment(null, rectangle, 'copy');
3845
+ const duplicateElements = (board, elements, point) => {
3846
+ const targetElements = elements?.length ? elements : getSelectedElements(board);
3847
+ const targetRectangle = getRectangleByElements(board, targetElements, false);
3848
+ const clipboardContext = board.buildFragment(null, targetRectangle, 'copy', targetElements);
3801
3849
  const stringifiedContext = clipboardContext && JSON.stringify(clipboardContext);
3802
3850
  const clonedContext = stringifiedContext && JSON.parse(stringifiedContext);
3803
3851
  clonedContext &&
3804
3852
  board.insertFragment({
3805
3853
  ...clonedContext,
3806
3854
  text: undefined
3807
- }, [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2]);
3855
+ }, point || [targetRectangle.x + targetRectangle.width / 2, targetRectangle.y + targetRectangle.height / 2]);
3808
3856
  };
3809
3857
 
3810
3858
  const SNAP_TOLERANCE = 2;
@@ -4024,6 +4072,9 @@ const PlaitElement = {
4024
4072
  getComponent(value) {
4025
4073
  return ELEMENT_TO_COMPONENT.get(value);
4026
4074
  },
4075
+ getElementRef(value) {
4076
+ return ELEMENT_TO_REF.get(value);
4077
+ },
4027
4078
  getElementG(value) {
4028
4079
  const g = NODE_TO_G.get(value);
4029
4080
  if (!g) {
@@ -4490,7 +4541,7 @@ function createBoard(children, options) {
4490
4541
  globalKeyDown: (event) => { },
4491
4542
  keyUp: (event) => { },
4492
4543
  dblClick: (event) => { },
4493
- buildFragment: (clipboardContext) => clipboardContext,
4544
+ buildFragment: (clipboardContext, rectangle, type, originData) => clipboardContext,
4494
4545
  insertFragment: () => { },
4495
4546
  deleteFragment: (elements) => {
4496
4547
  CoreTransforms.removeElements(board, elements);
@@ -5111,7 +5162,7 @@ function isVerticalCross(rectangle, other) {
5111
5162
  }
5112
5163
 
5113
5164
  function withMoving(board) {
5114
- const { pointerDown, pointerMove, globalPointerUp, globalPointerMove } = board;
5165
+ const { pointerDown, pointerMove, globalPointerUp, globalPointerMove, globalKeyDown, keyUp } = board;
5115
5166
  let offsetX = 0;
5116
5167
  let offsetY = 0;
5117
5168
  let isPreventDefault = false;
@@ -5122,6 +5173,31 @@ function withMoving(board) {
5122
5173
  let selectedTargetElements = null;
5123
5174
  let hitTargetElement = undefined;
5124
5175
  let isHitSelectedTarget = undefined;
5176
+ let pendingNodesG = null;
5177
+ board.globalKeyDown = (event) => {
5178
+ if (!PlaitBoard.isReadonly(board)) {
5179
+ if (isKeyHotkey('option', event)) {
5180
+ event.preventDefault();
5181
+ if (startPoint && activeElements.length && !PlaitBoard.hasBeenTextEditing(board)) {
5182
+ pendingNodesG = drawPendingNodesG(board, activeElements, offsetX, offsetY);
5183
+ pendingNodesG && PlaitBoard.getElementActiveHost(board).append(pendingNodesG);
5184
+ }
5185
+ }
5186
+ }
5187
+ globalKeyDown(event);
5188
+ };
5189
+ board.keyUp = (event) => {
5190
+ if (!PlaitBoard.isReadonly(board)) {
5191
+ if (event.altKey && pendingNodesG && startPoint && activeElements.length && !PlaitBoard.hasBeenTextEditing(board)) {
5192
+ event.preventDefault();
5193
+ const currentElements = updatePoints(board, activeElements, offsetX, offsetY);
5194
+ PlaitBoard.getBoardContainer(board).classList.add('element-moving');
5195
+ cacheMovingElements(board, currentElements);
5196
+ }
5197
+ }
5198
+ pendingNodesG?.remove();
5199
+ keyUp(event);
5200
+ };
5125
5201
  board.pointerDown = (event) => {
5126
5202
  if (PlaitBoard.isReadonly(board) ||
5127
5203
  !PlaitBoard.isPointer(board, PlaitPointerType.selection) ||
@@ -5167,6 +5243,7 @@ function withMoving(board) {
5167
5243
  isPreventDefault = true;
5168
5244
  }
5169
5245
  snapG?.remove();
5246
+ pendingNodesG?.remove();
5170
5247
  const endPoint = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));
5171
5248
  offsetX = endPoint[0] - startPoint[0];
5172
5249
  offsetY = endPoint[1] - startPoint[1];
@@ -5195,9 +5272,15 @@ function withMoving(board) {
5195
5272
  snapG.classList.add(ACTIVE_MOVING_CLASS_NAME);
5196
5273
  PlaitBoard.getElementActiveHost(board).append(snapG);
5197
5274
  handleTouchTarget(board);
5198
- const currentElements = updatePoints(board, activeElements, offsetX, offsetY);
5199
- PlaitBoard.getBoardContainer(board).classList.add('element-moving');
5200
- cacheMovingElements(board, currentElements);
5275
+ if (event.altKey) {
5276
+ pendingNodesG = drawPendingNodesG(board, activeElements, offsetX, offsetY);
5277
+ pendingNodesG && PlaitBoard.getElementActiveHost(board).append(pendingNodesG);
5278
+ }
5279
+ else {
5280
+ const currentElements = updatePoints(board, activeElements, offsetX, offsetY);
5281
+ PlaitBoard.getBoardContainer(board).classList.add('element-moving');
5282
+ cacheMovingElements(board, currentElements);
5283
+ }
5201
5284
  });
5202
5285
  }
5203
5286
  }
@@ -5217,6 +5300,11 @@ function withMoving(board) {
5217
5300
  globalPointerMove(event);
5218
5301
  };
5219
5302
  board.globalPointerUp = event => {
5303
+ if (event.altKey && activeElements.length) {
5304
+ const validElements = getValidElements(board, activeElements);
5305
+ const rectangle = getRectangleByElements(board, validElements, false);
5306
+ duplicateElements(board, validElements, [rectangle.x + offsetX, rectangle.y + offsetY]);
5307
+ }
5220
5308
  isPreventDefault = false;
5221
5309
  hitTargetElement = undefined;
5222
5310
  selectedTargetElements = null;
@@ -5229,6 +5317,7 @@ function withMoving(board) {
5229
5317
  };
5230
5318
  function cancelMove(board) {
5231
5319
  snapG?.remove();
5320
+ pendingNodesG?.remove();
5232
5321
  startPoint = null;
5233
5322
  activeElementsRectangle = null;
5234
5323
  offsetX = 0;
@@ -5292,8 +5381,12 @@ function getSelectedTargetElements(board) {
5292
5381
  targetElements.push(...relatedElements);
5293
5382
  return targetElements;
5294
5383
  }
5295
- function updatePoints(board, targetElements, offsetX, offsetY) {
5296
- const validElements = targetElements.filter(element => !PlaitGroupElement.isGroup(element) && board.children.findIndex(item => item.id === element.id) > -1);
5384
+ function getValidElements(board, activeElements) {
5385
+ const validElements = [...activeElements].filter(element => !PlaitGroupElement.isGroup(element) && board.children.findIndex(item => item.id === element.id) > -1);
5386
+ return validElements;
5387
+ }
5388
+ function updatePoints(board, activeElements, offsetX, offsetY) {
5389
+ const validElements = getValidElements(board, activeElements);
5297
5390
  const currentElements = validElements.map(element => {
5298
5391
  const points = element.points || [];
5299
5392
  const newPoints = points.map(p => [p[0] + offsetX, p[1] + offsetY]);
@@ -5306,6 +5399,41 @@ function updatePoints(board, targetElements, offsetX, offsetY) {
5306
5399
  });
5307
5400
  return currentElements;
5308
5401
  }
5402
+ function drawPendingNodesG(board, activeElements, offsetX, offsetY) {
5403
+ let pendingNodesG = null;
5404
+ const elements = [];
5405
+ const validElements = getValidElements(board, activeElements);
5406
+ validElements.forEach(element => {
5407
+ depthFirstRecursion(element, node => {
5408
+ elements.push(node);
5409
+ }, () => true);
5410
+ });
5411
+ elements.forEach(item => {
5412
+ let rectangle = board.getRectangle(item);
5413
+ if (rectangle) {
5414
+ rectangle = {
5415
+ x: rectangle.x + offsetX,
5416
+ y: rectangle.y + offsetY,
5417
+ width: rectangle.width,
5418
+ height: rectangle.height
5419
+ };
5420
+ const movingG = drawRectangle(board, rectangle, {
5421
+ stroke: SELECTION_BORDER_COLOR,
5422
+ strokeWidth: 1,
5423
+ fill: SELECTION_FILL_COLOR,
5424
+ fillStyle: 'solid'
5425
+ });
5426
+ if (!pendingNodesG) {
5427
+ pendingNodesG = createG();
5428
+ pendingNodesG.classList.add(ACTIVE_MOVING_CLASS_NAME);
5429
+ }
5430
+ const angle = getAngleByElement(item);
5431
+ angle && setAngleForG(movingG, RectangleClient.getCenterPoint(rectangle), angle);
5432
+ pendingNodesG.append(movingG);
5433
+ }
5434
+ });
5435
+ return pendingNodesG;
5436
+ }
5309
5437
 
5310
5438
  const withOptions = (board) => {
5311
5439
  const pluginOptions = new Map();
@@ -5438,7 +5566,7 @@ const withHotkey = (board) => {
5438
5566
  if (!PlaitBoard.isReadonly(board) && selectedElements.length > 0) {
5439
5567
  if (isKeyHotkey('mod+d', event)) {
5440
5568
  event.preventDefault();
5441
- duplicateElements(board, selectedElements);
5569
+ duplicateElements(board);
5442
5570
  return;
5443
5571
  }
5444
5572
  }
@@ -5510,19 +5638,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImpor
5510
5638
 
5511
5639
  function withRelatedFragment(board) {
5512
5640
  const { buildFragment } = board;
5513
- board.buildFragment = (clipboardContext, rectangle, type) => {
5514
- const relatedFragment = board.getRelatedFragment([]);
5515
- if (!clipboardContext) {
5516
- clipboardContext = createClipboardContext(WritableClipboardType.elements, relatedFragment, '');
5517
- }
5518
- else {
5519
- clipboardContext = addClipboardContext(clipboardContext, {
5520
- text: '',
5521
- type: WritableClipboardType.elements,
5522
- elements: relatedFragment
5523
- });
5641
+ board.buildFragment = (clipboardContext, rectangle, type, originData) => {
5642
+ let relatedFragment = board.getRelatedFragment(originData || []);
5643
+ if (relatedFragment) {
5644
+ if (originData?.length) {
5645
+ relatedFragment = relatedFragment.filter(item => !originData.map(element => element.id).includes(item.id));
5646
+ }
5647
+ if (relatedFragment.length) {
5648
+ if (!clipboardContext) {
5649
+ clipboardContext = createClipboardContext(WritableClipboardType.elements, relatedFragment, '');
5650
+ }
5651
+ else {
5652
+ clipboardContext = addClipboardContext(clipboardContext, {
5653
+ text: '',
5654
+ type: WritableClipboardType.elements,
5655
+ elements: relatedFragment
5656
+ });
5657
+ }
5658
+ }
5524
5659
  }
5525
- return buildFragment(clipboardContext, rectangle, type);
5660
+ return buildFragment(clipboardContext, rectangle, type, originData);
5526
5661
  };
5527
5662
  return board;
5528
5663
  }
@@ -5636,10 +5771,13 @@ class PlaitBoardComponent {
5636
5771
  if (this.hasInitialized) {
5637
5772
  const valueChange = changes['plaitValue'];
5638
5773
  const options = changes['plaitOptions'];
5639
- if (valueChange)
5774
+ if (valueChange) {
5640
5775
  this.board.children = valueChange.currentValue;
5641
- if (options)
5776
+ this.updateListRender();
5777
+ }
5778
+ if (options) {
5642
5779
  this.board.options = options.currentValue;
5780
+ }
5643
5781
  this.cdr.markForCheck();
5644
5782
  }
5645
5783
  }
@@ -6199,5 +6337,5 @@ const isDebug = (key) => {
6199
6337
  * Generated bundle index. Do not edit.
6200
6338
  */
6201
6339
 
6202
- export { A, ACTIVE_MOVING_CLASS_NAME, ACTIVE_STROKE_WIDTH, ALT, APOSTROPHE, ATTACHED_ELEMENT_CLASS_NAME, AT_SIGN, B, BACKSLASH, BACKSPACE, BOARD_TO_AFTER_CHANGE, BOARD_TO_COMPONENT, BOARD_TO_ELEMENT_HOST, BOARD_TO_HOST, BOARD_TO_IS_SELECTION_MOVING, BOARD_TO_MOVING_ELEMENT, BOARD_TO_MOVING_POINT, BOARD_TO_MOVING_POINT_IN_BOARD, BOARD_TO_ON_CHANGE, BOARD_TO_ROUGH_SVG, BOARD_TO_SELECTED_ELEMENT, BOARD_TO_TEMPORARY_ELEMENTS, BOARD_TO_TOUCH_REF, BOARD_TO_VIEWPORT_ORIGINATION, BoardTransforms, C, CAPS_LOCK, CLOSE_SQUARE_BRACKET, COMMA, CONTEXT_MENU, CONTROL, ColorfulThemeColor, CoreTransforms, CursorClass, D, DASH, DELETE, DOWN_ARROW, DarkThemeColor, DebugGenerator, DefaultThemeColor, Direction, E, EIGHT, ELEMENT_TO_COMPONENT, END, ENTER, EQUALS, ESCAPE, F, F1, F10, F11, F12, F2, F3, F4, F5, F6, F7, F8, F9, FF_EQUALS, FF_MINUS, FF_MUTE, FF_SEMICOLON, FF_VOLUME_DOWN, FF_VOLUME_UP, FIRST_MEDIA, FIVE, FLUSHING, FOUR, G, H, HIT_DISTANCE_BUFFER, HOME, HOST_CLASS_NAME, I, INSERT, IS_APPLE, IS_BOARD_ALIVE, IS_BOARD_CACHE, IS_CHROME, IS_CHROME_LEGACY, IS_DRAGGING, IS_EDGE_LEGACY, IS_FIREFOX, IS_IOS, IS_MAC, IS_SAFARI, IS_TEXT_EDITABLE, J, K, L, LAST_MEDIA, LEFT_ARROW, M, MAC_ENTER, MAC_META, MAC_WK_CMD_LEFT, MAC_WK_CMD_RIGHT, MAX_RADIUS, MERGING, META, MUTE, N, NINE, NODE_TO_CONTAINER_G, NODE_TO_G, NODE_TO_INDEX, NODE_TO_PARENT, NS, NUMPAD_DIVIDE, NUMPAD_EIGHT, NUMPAD_FIVE, NUMPAD_FOUR, NUMPAD_MINUS, NUMPAD_MULTIPLY, NUMPAD_NINE, NUMPAD_ONE, NUMPAD_PERIOD, NUMPAD_PLUS, NUMPAD_SEVEN, NUMPAD_SIX, NUMPAD_THREE, NUMPAD_TWO, NUMPAD_ZERO, NUM_CENTER, NUM_LOCK, O, ONE, OPEN_SQUARE_BRACKET, P, PAGE_DOWN, PAGE_UP, PATH_REFS, PAUSE, PERIOD, PLUS_SIGN, POINTER_BUTTON, PRESS_AND_MOVE_BUFFER, PRINT_SCREEN, Path, PlaitBoard, PlaitBoardComponent, PlaitContextService, PlaitElement, PlaitGroupElement, PlaitHistoryBoard, PlaitIslandBaseComponent, PlaitIslandPopoverBaseComponent, PlaitNode, PlaitOperation, PlaitPluginElementComponent, PlaitPluginKey, PlaitPointerType, Point, Q, QUESTION_MARK, R, RESIZE_CURSORS, RESIZE_HANDLE_CLASS_NAME, RIGHT_ARROW, ROTATE_HANDLE_CLASS_NAME, RectangleClient, ResizeCursorClass, RetroThemeColor, RgbaToHEX, S, SAVING, SCROLL_BAR_WIDTH, SCROLL_LOCK, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, SELECTION_RECTANGLE_CLASS_NAME, SEMICOLON, SEVEN, SHIFT, SINGLE_QUOTE, SIX, SLASH, SNAPPING_STROKE_WIDTH, SNAP_TOLERANCE, SPACE, Selection, SoftThemeColor, StarryThemeColor, T, TAB, THREE, TILDE, TWO, ThemeColorMode, ThemeColors, Transforms, U, UP_ARROW, V, VOLUME_DOWN, VOLUME_UP, Viewport, W, WritableClipboardType, X, Y, Z, ZERO, addClipboardContext, addSelectedElement, approximately, arrowPoints, buildPlaitHtml, cacheMovingElements, cacheSelectedElements, cacheSelectedElementsWithGroup, cacheSelectedElementsWithGroupOnShift, calcNewViewBox, canAddGroup, canRemoveGroup, canSetZIndex, catmullRomFitting, clampZoomLevel, clearNodeWeakMap, clearSelectedElement, clearSelectionMoving, clearViewportOrigination, createClipboardContext, createDebugGenerator, createFakeEvent, createForeignObject, createG, createGroup, createGroupRectangleG, createKeyboardEvent, createMask, createModModifierKeys, createMouseEvent, createPath, createPointerEvent, createRect, createSVG, createTestingBoard, createText, createTouchEvent, debounce, degreesToRadians, deleteFragment, deleteTemporaryElements, depthFirstRecursion, distanceBetweenPointAndPoint, distanceBetweenPointAndRectangle, distanceBetweenPointAndSegment, distanceBetweenPointAndSegments, downloadImage, drawArrow, drawBezierPath, drawCircle, drawDashedLines, drawEntireActiveRectangleG, drawLine, drawLinearPath, drawPointSnapLines, drawRectangle, drawRoundRectangle, drawSolidLines, duplicateElements, fakeNodeWeakMap, filterSelectedGroups, findElements, findIndex, findLastIndex, getAllElementsInGroup, getAllMoveOptions, getAngleBetweenPoints, getBarPoint, getBoardRectangle, getClipboardData, getClipboardFromHtml, getCrossingPointsBetweenEllipseAndSegment, getDataTransferClipboard, getDataTransferClipboardText, getEditingGroup, getElementById, getElementHostBBox, getElementsInGroup, getElementsInGroupByElement, getElementsIndices, getEllipseTangentSlope, getGroupByElement, getHighestGroup, getHighestIndexOfElement, getHighestSelectedElements, getHighestSelectedGroup, getHighestSelectedGroups, getHitElementByPoint, getHitElementsBySelection, getHitSelectedElements, getIsRecursionFunc, getMinPointDelta, getMovingElements, getNearestDelta, getNearestPointBetweenPointAndSegment, getNearestPointBetweenPointAndSegments, getNearestPointRectangle, getOffsetAfterRotate, getOneMoveOptions, getProbablySupportsClipboardRead, getProbablySupportsClipboardWrite, getProbablySupportsClipboardWriteText, getRealScrollBarWidth, getRectangleByAngle, getRectangleByElements, getRectangleByGroup, getRotatedBoundingRectangle, getSelectedElements, getSelectedGroups, getSelectedIsolatedElements, getSelectedIsolatedElementsCanAddToGroup, getSelectedTargetElements, getSelectionAngle, getSnapRectangles, getTemporaryElements, getTemporaryRef, getTripleAxis, getVectorFromPointAndSlope, getViewBox, getViewBoxCenterPoint, getViewportContainerRect, getViewportOrigination, handleTouchTarget, hasBeforeContextChange, hasInputOrTextareaTarget, hasOnBoardChange, hasOnContextChanged, hasSameAngle, hasSelectedElementsInSameGroup, hasValidAngle, hotkeys, idCreator, initializeViewBox, initializeViewportContainer, initializeViewportOffset, inverse, isAxisChangedByAngle, isContextmenu, isDOMElement, isDOMNode, isDebug, isDragging, isFromScrolling, isFromViewportChange, isHandleSelection, isInPlaitBoard, isIndicesContinuous, isLineHitLine, isMainPointer, isMovingElements, isNullOrUndefined, isPointInEllipse, isPointInPolygon, isPointInRoundRectangle, isPolylineHitRectangle, isPreventTouchMove, isSecondaryPointer, isSelectedAllElementsInGroup, isSelectedElement, isSelectedElementOrGroup, isSelectionMoving, isSetSelectionOperation, isSetViewportOperation, isSnapPoint, moveElementsToNewPath, moveElementsToNewPathAfterAddGroup, nonGroupInHighestSelectedElements, normalizeAngle, normalizePoint, preventTouchMove, radiansToDegrees, removeMovingElements, removeSelectedElement, rotate, rotateAntiPointsByElement, rotateElements, rotatePoints, rotatePointsByElement, rotatedDataPoints, scrollToRectangle, setAngleForG, setClipboardData, setDataTransferClipboard, setDataTransferClipboardText, setDragging, setFragment, setIsFromScrolling, setIsFromViewportChange, setPathStrokeLinecap, setSVGViewBox, setSelectedElementsWithGroup, setSelectionMoving, setStrokeLinecap, shouldClear, shouldMerge, shouldSave, sortElements, stripHtml, temporaryDisableSelection, throttleRAF, toDomPrecision, toFixed, toHostPoint, toHostPointFromViewBoxPoint, toImage, toScreenPointFromHostPoint, toViewBoxPoint, toViewBoxPoints, uniqueById, updateForeignObject, updateForeignObjectWidth, updatePoints, updateViewportByScrolling, updateViewportContainerScroll, updateViewportOffset, updateViewportOrigination, withArrowMoving, withMoving, withOptions, withSelection };
6340
+ export { A, ACTIVE_MOVING_CLASS_NAME, ACTIVE_STROKE_WIDTH, ALT, APOSTROPHE, ATTACHED_ELEMENT_CLASS_NAME, AT_SIGN, B, BACKSLASH, BACKSPACE, BOARD_TO_AFTER_CHANGE, BOARD_TO_COMPONENT, BOARD_TO_ELEMENT_HOST, BOARD_TO_HOST, BOARD_TO_IS_SELECTION_MOVING, BOARD_TO_MOVING_ELEMENT, BOARD_TO_MOVING_POINT, BOARD_TO_MOVING_POINT_IN_BOARD, BOARD_TO_ON_CHANGE, BOARD_TO_ROUGH_SVG, BOARD_TO_SELECTED_ELEMENT, BOARD_TO_TEMPORARY_ELEMENTS, BOARD_TO_TOUCH_REF, BOARD_TO_VIEWPORT_ORIGINATION, BoardTransforms, C, CAPS_LOCK, CLOSE_SQUARE_BRACKET, COMMA, CONTEXT_MENU, CONTROL, ColorfulThemeColor, CoreTransforms, CursorClass, D, DASH, DELETE, DOWN_ARROW, DarkThemeColor, DebugGenerator, DefaultThemeColor, Direction, E, EIGHT, ELEMENT_TO_COMPONENT, ELEMENT_TO_REF, END, ENTER, EQUALS, ESCAPE, F, F1, F10, F11, F12, F2, F3, F4, F5, F6, F7, F8, F9, FF_EQUALS, FF_MINUS, FF_MUTE, FF_SEMICOLON, FF_VOLUME_DOWN, FF_VOLUME_UP, FIRST_MEDIA, FIVE, FLUSHING, FOUR, G, H, HIT_DISTANCE_BUFFER, HOME, HOST_CLASS_NAME, I, INSERT, IS_APPLE, IS_BOARD_ALIVE, IS_BOARD_CACHE, IS_CHROME, IS_CHROME_LEGACY, IS_DRAGGING, IS_EDGE_LEGACY, IS_FIREFOX, IS_IOS, IS_MAC, IS_SAFARI, IS_TEXT_EDITABLE, J, K, L, LAST_MEDIA, LEFT_ARROW, M, MAC_ENTER, MAC_META, MAC_WK_CMD_LEFT, MAC_WK_CMD_RIGHT, MAX_RADIUS, MERGING, META, MUTE, N, NINE, NODE_TO_CONTAINER_G, NODE_TO_G, NODE_TO_INDEX, NODE_TO_PARENT, NS, NUMPAD_DIVIDE, NUMPAD_EIGHT, NUMPAD_FIVE, NUMPAD_FOUR, NUMPAD_MINUS, NUMPAD_MULTIPLY, NUMPAD_NINE, NUMPAD_ONE, NUMPAD_PERIOD, NUMPAD_PLUS, NUMPAD_SEVEN, NUMPAD_SIX, NUMPAD_THREE, NUMPAD_TWO, NUMPAD_ZERO, NUM_CENTER, NUM_LOCK, O, ONE, OPEN_SQUARE_BRACKET, P, PAGE_DOWN, PAGE_UP, PATH_REFS, PAUSE, PERIOD, PLUS_SIGN, POINTER_BUTTON, PRESS_AND_MOVE_BUFFER, PRINT_SCREEN, Path, PlaitBoard, PlaitBoardComponent, PlaitContextService, PlaitElement, PlaitGroupElement, PlaitHistoryBoard, PlaitIslandBaseComponent, PlaitIslandPopoverBaseComponent, PlaitNode, PlaitOperation, PlaitPluginElementComponent, PlaitPluginKey, PlaitPointerType, Point, Q, QUESTION_MARK, R, RESIZE_CURSORS, RESIZE_HANDLE_CLASS_NAME, RIGHT_ARROW, ROTATE_HANDLE_CLASS_NAME, RectangleClient, ResizeCursorClass, RetroThemeColor, RgbaToHEX, S, SAVING, SCROLL_BAR_WIDTH, SCROLL_LOCK, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, SELECTION_RECTANGLE_CLASS_NAME, SEMICOLON, SEVEN, SHIFT, SINGLE_QUOTE, SIX, SLASH, SNAPPING_STROKE_WIDTH, SNAP_TOLERANCE, SPACE, Selection, SoftThemeColor, StarryThemeColor, T, TAB, THREE, TILDE, TWO, ThemeColorMode, ThemeColors, Transforms, U, UP_ARROW, V, VOLUME_DOWN, VOLUME_UP, Viewport, W, WritableClipboardType, X, Y, Z, ZERO, addClipboardContext, addSelectedElement, approximately, arrowPoints, buildPlaitHtml, cacheMovingElements, cacheSelectedElements, cacheSelectedElementsWithGroup, cacheSelectedElementsWithGroupOnShift, calcNewViewBox, canAddGroup, canRemoveGroup, canSetZIndex, catmullRomFitting, clampZoomLevel, clearNodeWeakMap, clearSelectedElement, clearSelectionMoving, clearViewportOrigination, createClipboardContext, createDebugGenerator, createFakeEvent, createForeignObject, createG, createGroup, createGroupRectangleG, createKeyboardEvent, createMask, createModModifierKeys, createMouseEvent, createPath, createPointerEvent, createRect, createSVG, createTestingBoard, createText, createTouchEvent, debounce, degreesToRadians, deleteFragment, deleteTemporaryElements, depthFirstRecursion, distanceBetweenPointAndPoint, distanceBetweenPointAndRectangle, distanceBetweenPointAndSegment, distanceBetweenPointAndSegments, downloadImage, drawArrow, drawBezierPath, drawCircle, drawDashedLines, drawEntireActiveRectangleG, drawLine, drawLinearPath, drawPendingNodesG, drawPointSnapLines, drawRectangle, drawRoundRectangle, drawSolidLines, duplicateElements, fakeNodeWeakMap, filterSelectedGroups, findElements, findIndex, findLastIndex, getAllElementsInGroup, getAllMoveOptions, getAngleBetweenPoints, getAngleByElement, getBarPoint, getBoardRectangle, getClipboardData, getClipboardFromHtml, getCrossingPointsBetweenEllipseAndSegment, getDataTransferClipboard, getDataTransferClipboardText, getEditingGroup, getElementById, getElementHostBBox, getElementsInGroup, getElementsInGroupByElement, getElementsIndices, getEllipseTangentSlope, getGroupByElement, getHighestGroup, getHighestIndexOfElement, getHighestSelectedElements, getHighestSelectedGroup, getHighestSelectedGroups, getHitElementByPoint, getHitElementsBySelection, getHitSelectedElements, getIsRecursionFunc, getMinPointDelta, getMovingElements, getNearestDelta, getNearestPointBetweenPointAndEllipse, getNearestPointBetweenPointAndSegment, getNearestPointBetweenPointAndSegments, getNearestPointRectangle, getOffsetAfterRotate, getOneMoveOptions, getProbablySupportsClipboardRead, getProbablySupportsClipboardWrite, getProbablySupportsClipboardWriteText, getRealScrollBarWidth, getRectangleByAngle, getRectangleByElements, getRectangleByGroup, getRotatedBoundingRectangle, getSelectedElements, getSelectedGroups, getSelectedIsolatedElements, getSelectedIsolatedElementsCanAddToGroup, getSelectedTargetElements, getSelectionAngle, getSnapRectangles, getTemporaryElements, getTemporaryRef, getTripleAxis, getValidElements, getVectorFromPointAndSlope, getViewBox, getViewBoxCenterPoint, getViewportContainerRect, getViewportOrigination, handleTouchTarget, hasBeforeContextChange, hasInputOrTextareaTarget, hasOnBoardChange, hasOnContextChanged, hasSameAngle, hasSelectedElementsInSameGroup, hasValidAngle, hotkeys, idCreator, initializeViewBox, initializeViewportContainer, initializeViewportOffset, inverse, isAxisChangedByAngle, isContextmenu, isDOMElement, isDOMNode, isDebug, isDragging, isFromScrolling, isFromViewportChange, isHandleSelection, isInPlaitBoard, isIndicesContinuous, isLineHitLine, isMainPointer, isMovingElements, isNullOrUndefined, isPointInEllipse, isPointInPolygon, isPointInRoundRectangle, isPolylineHitRectangle, isPreventTouchMove, isSecondaryPointer, isSelectedAllElementsInGroup, isSelectedElement, isSelectedElementOrGroup, isSelectionMoving, isSetSelectionOperation, isSetViewportOperation, isSnapPoint, moveElementsToNewPath, moveElementsToNewPathAfterAddGroup, nonGroupInHighestSelectedElements, normalizeAngle, normalizePoint, preventTouchMove, radiansToDegrees, removeMovingElements, removeSelectedElement, rotate, rotateAntiPointsByElement, rotateElements, rotatePoints, rotatePointsByElement, rotatedDataPoints, scrollToRectangle, setAngleForG, setClipboardData, setDataTransferClipboard, setDataTransferClipboardText, setDragging, setFragment, setIsFromScrolling, setIsFromViewportChange, setPathStrokeLinecap, setSVGViewBox, setSelectedElementsWithGroup, setSelectionMoving, setStrokeLinecap, shouldClear, shouldMerge, shouldSave, sortElements, stripHtml, temporaryDisableSelection, throttleRAF, toDomPrecision, toFixed, toHostPoint, toHostPointFromViewBoxPoint, toImage, toScreenPointFromHostPoint, toViewBoxPoint, toViewBoxPoints, uniqueById, updateForeignObject, updateForeignObjectWidth, updatePoints, updateViewportByScrolling, updateViewportContainerScroll, updateViewportOffset, updateViewportOrigination, withArrowMoving, withMoving, withOptions, withSelection };
6203
6341
  //# sourceMappingURL=plait-core.mjs.map