@plait/core 0.1.8 → 0.2.0-next.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.
Files changed (63) hide show
  1. package/board/board.component.d.ts +5 -4
  2. package/core/children/children.component.d.ts +17 -0
  3. package/core/children/effect.d.ts +2 -0
  4. package/core/element/context-change.d.ts +10 -0
  5. package/core/element/context.d.ts +4 -2
  6. package/core/element/element.component.d.ts +10 -13
  7. package/core/element/plugin-element.d.ts +5 -4
  8. package/esm2020/board/board.component.mjs +16 -24
  9. package/esm2020/core/children/children.component.mjs +58 -0
  10. package/esm2020/core/children/effect.mjs +2 -0
  11. package/esm2020/core/element/context-change.mjs +13 -0
  12. package/esm2020/core/element/context.mjs +1 -1
  13. package/esm2020/core/element/element.component.mjs +47 -37
  14. package/esm2020/core/element/plugin-element.mjs +36 -27
  15. package/esm2020/interfaces/board.mjs +33 -2
  16. package/esm2020/interfaces/element.mjs +15 -4
  17. package/esm2020/interfaces/node.mjs +23 -3
  18. package/esm2020/interfaces/operation.mjs +1 -1
  19. package/esm2020/interfaces/path.mjs +36 -1
  20. package/esm2020/interfaces/rectangle-client.mjs +9 -1
  21. package/esm2020/plait.module.mjs +4 -3
  22. package/esm2020/plugins/create-board.mjs +2 -1
  23. package/esm2020/plugins/with-hand.mjs +2 -2
  24. package/esm2020/plugins/with-moving.mjs +4 -4
  25. package/esm2020/plugins/with-selection.mjs +42 -45
  26. package/esm2020/plugins/with-viewport.mjs +2 -2
  27. package/esm2020/public-api.mjs +3 -3
  28. package/esm2020/utils/draw/circle.mjs +4 -0
  29. package/esm2020/utils/draw/line.mjs +4 -0
  30. package/esm2020/utils/draw/rectangle.mjs +43 -1
  31. package/esm2020/utils/element.mjs +2 -2
  32. package/esm2020/utils/index.mjs +3 -1
  33. package/esm2020/utils/moving-element.mjs +3 -3
  34. package/esm2020/utils/selected-element.mjs +13 -6
  35. package/esm2020/utils/tree.mjs +7 -5
  36. package/esm2020/utils/viewport.mjs +5 -5
  37. package/esm2020/utils/weak-maps.mjs +4 -1
  38. package/fesm2015/plait-core.mjs +464 -237
  39. package/fesm2015/plait-core.mjs.map +1 -1
  40. package/fesm2020/plait-core.mjs +463 -235
  41. package/fesm2020/plait-core.mjs.map +1 -1
  42. package/interfaces/board.d.ts +5 -0
  43. package/interfaces/element.d.ts +6 -3
  44. package/interfaces/node.d.ts +17 -9
  45. package/interfaces/operation.d.ts +1 -1
  46. package/interfaces/path.d.ts +18 -0
  47. package/interfaces/rectangle-client.d.ts +6 -0
  48. package/package.json +1 -1
  49. package/plait.module.d.ts +5 -4
  50. package/public-api.d.ts +2 -2
  51. package/styles/styles.scss +5 -1
  52. package/utils/draw/circle.d.ts +4 -0
  53. package/utils/draw/line.d.ts +4 -0
  54. package/utils/draw/rectangle.d.ts +1 -0
  55. package/utils/index.d.ts +2 -0
  56. package/utils/selected-element.d.ts +2 -2
  57. package/utils/tree.d.ts +1 -1
  58. package/utils/viewport.d.ts +1 -1
  59. package/utils/weak-maps.d.ts +4 -0
  60. package/core/base/detector.d.ts +0 -7
  61. package/core/element/before-context-change.d.ts +0 -6
  62. package/esm2020/core/base/detector.mjs +0 -2
  63. package/esm2020/core/element/before-context-change.mjs +0 -7
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, ChangeDetectionStrategy, Input, EventEmitter, HostBinding, Output, ElementRef, ViewChild, ContentChild, Directive, NgModule } from '@angular/core';
2
+ import { Directive, Input, Component, ChangeDetectionStrategy, EventEmitter, HostBinding, Output, ElementRef, ViewChild, ContentChild, NgModule } from '@angular/core';
3
3
  import rough from 'roughjs/bin/rough';
4
4
  import { timer, Subject, fromEvent } from 'rxjs';
5
5
  import { takeUntil, filter } from 'rxjs/operators';
@@ -9,7 +9,10 @@ import * as i1 from '@angular/common';
9
9
  import { BrowserModule } from '@angular/platform-browser';
10
10
 
11
11
  // record richtext type status
12
+ const IS_BOARD_CACHE = new WeakMap();
12
13
  const FLUSHING = new WeakMap();
14
+ const NODE_TO_INDEX = new WeakMap();
15
+ const NODE_TO_PARENT = new WeakMap();
13
16
  const IS_TEXT_EDITABLE = new WeakMap();
14
17
  const BOARD_TO_ON_CHANGE = new WeakMap();
15
18
  const BOARD_TO_COMPONENT = new WeakMap();
@@ -24,11 +27,13 @@ const BOARD_TO_IS_SELECTION_MOVING = new WeakMap();
24
27
  const BOARD_TO_TEMPORARY_ELEMENTS = new WeakMap();
25
28
  const BOARD_TO_MOVING_ELEMENT = new WeakMap();
26
29
 
27
- function depthFirstRecursion(node, callback) {
30
+ function depthFirstRecursion(node, callback, recursion) {
28
31
  var _a;
29
- (_a = node.children) === null || _a === void 0 ? void 0 : _a.forEach(child => {
30
- depthFirstRecursion(child, callback);
31
- });
32
+ if (!recursion || recursion(node)) {
33
+ (_a = node.children) === null || _a === void 0 ? void 0 : _a.forEach(child => {
34
+ depthFirstRecursion(child, callback, recursion);
35
+ });
36
+ }
32
37
  callback(node);
33
38
  }
34
39
 
@@ -50,7 +55,7 @@ function getRectangleByElements(board, elements, recursion) {
50
55
  };
51
56
  elements.forEach(element => {
52
57
  if (recursion) {
53
- depthFirstRecursion(element, node => calcRectangleClient(node));
58
+ depthFirstRecursion(element, node => calcRectangleClient(node), node => board.isRecursion(node));
54
59
  }
55
60
  else {
56
61
  calcRectangleClient(element);
@@ -68,6 +73,37 @@ function getBoardRectangle(board) {
68
73
  }
69
74
 
70
75
  const PlaitBoard = {
76
+ isBoard(value) {
77
+ const cachedIsBoard = IS_BOARD_CACHE.get(value);
78
+ if (cachedIsBoard !== undefined) {
79
+ return cachedIsBoard;
80
+ }
81
+ const isBoard = typeof value.onChange === 'function' && typeof value.apply === 'function';
82
+ IS_BOARD_CACHE.set(value, isBoard);
83
+ return isBoard;
84
+ },
85
+ findPath(board, node) {
86
+ const path = [];
87
+ let child = node;
88
+ while (true) {
89
+ const parent = NODE_TO_PARENT.get(child);
90
+ if (parent == null) {
91
+ if (PlaitBoard.isBoard(child)) {
92
+ return path;
93
+ }
94
+ else {
95
+ break;
96
+ }
97
+ }
98
+ const i = NODE_TO_INDEX.get(child);
99
+ if (i == null) {
100
+ break;
101
+ }
102
+ path.unshift(i);
103
+ child = parent;
104
+ }
105
+ throw new Error(`Unable to find the path for Plait node: ${JSON.stringify(node)}`);
106
+ },
71
107
  getHost(board) {
72
108
  return BOARD_TO_HOST.get(board);
73
109
  },
@@ -130,6 +166,41 @@ const Viewport = {
130
166
  };
131
167
 
132
168
  const Path = {
169
+ /**
170
+ * Get a list of ancestor paths for a given path.
171
+ *
172
+ * The paths are sorted from shallowest to deepest ancestor. However, if the
173
+ * `reverse: true` option is passed, they are reversed.
174
+ */
175
+ ancestors(path, options = {}) {
176
+ const { reverse = false } = options;
177
+ let paths = Path.levels(path, options);
178
+ if (reverse) {
179
+ paths = paths.slice(1);
180
+ }
181
+ else {
182
+ paths = paths.slice(0, -1);
183
+ }
184
+ return paths;
185
+ },
186
+ /**
187
+ * Get a list of paths at every level down to a path. Note: this is the same
188
+ * as `Path.ancestors`, but including the path itself.
189
+ *
190
+ * The paths are sorted from shallowest to deepest. However, if the `reverse:
191
+ * true` option is passed, they are reversed.
192
+ */
193
+ levels(path, options = {}) {
194
+ const { reverse = false } = options;
195
+ const list = [];
196
+ for (let i = 0; i <= path.length; i++) {
197
+ list.push(path.slice(0, i));
198
+ }
199
+ if (reverse) {
200
+ list.reverse();
201
+ }
202
+ return list;
203
+ },
133
204
  parent(path) {
134
205
  if (path.length === 0) {
135
206
  throw new Error(`Cannot get the parent path of the root path [${path}].`);
@@ -273,8 +344,20 @@ const PlaitNode = {
273
344
  const p = PlaitNode.get(board, parentPath);
274
345
  return p;
275
346
  },
276
- get(board, path) {
277
- let node = board;
347
+ /**
348
+ * Return a generator of all the ancestor nodes above a specific path.
349
+ *
350
+ * By default the order is top-down, from highest to lowest ancestor in
351
+ * the tree, but you can pass the `reverse: true` option to go bottom-up.
352
+ */
353
+ *parents(root, path, options = {}) {
354
+ for (const p of Path.ancestors(path, options)) {
355
+ const n = PlaitNode.get(root, p);
356
+ yield n;
357
+ }
358
+ },
359
+ get(root, path) {
360
+ let node = root;
278
361
  for (let i = 0; i < path.length; i++) {
279
362
  const p = path[i];
280
363
  if (!node || !node.children || !node.children[p]) {
@@ -283,6 +366,14 @@ const PlaitNode = {
283
366
  node = node.children[p];
284
367
  }
285
368
  return node;
369
+ },
370
+ last(board, path) {
371
+ let n = PlaitNode.get(board, path);
372
+ while (n && n.children) {
373
+ const i = n.children.length - 1;
374
+ n = n.children[i];
375
+ }
376
+ return n;
286
377
  }
287
378
  };
288
379
 
@@ -584,10 +675,153 @@ const IS_CHROME = typeof navigator !== 'undefined' && /Chrome/i.test(navigator.u
584
675
  // Native beforeInput events don't work well with react on Chrome 75 and older, Chrome 76+ can use beforeInput
585
676
  const IS_CHROME_LEGACY = typeof navigator !== 'undefined' && /Chrome?\/(?:[0-7][0-5]|[0-6][0-9])/i.test(navigator.userAgent);
586
677
 
678
+ const getHitElements = (board) => {
679
+ const selectedElements = [];
680
+ depthFirstRecursion(board, node => {
681
+ var _a;
682
+ if (!PlaitBoard.isBoard(node) &&
683
+ ((_a = board.selection) === null || _a === void 0 ? void 0 : _a.ranges.some(range => {
684
+ return board.isHitSelection(node, range);
685
+ }))) {
686
+ selectedElements.push(node);
687
+ }
688
+ }, node => {
689
+ if (PlaitBoard.isBoard(node) || board.isRecursion(node)) {
690
+ return true;
691
+ }
692
+ else {
693
+ return false;
694
+ }
695
+ });
696
+ return selectedElements;
697
+ };
698
+ const isIntersectionElements = (board, elements, ranges) => {
699
+ let isIntersectionElements = false;
700
+ if (elements.length) {
701
+ elements.map(item => {
702
+ if (!isIntersectionElements) {
703
+ isIntersectionElements = ranges.some(range => {
704
+ return board.isHitSelection(item, range);
705
+ });
706
+ }
707
+ });
708
+ }
709
+ return isIntersectionElements;
710
+ };
711
+ const cacheSelectedElements = (board, selectedElements) => {
712
+ BOARD_TO_SELECTED_ELEMENT.set(board, selectedElements);
713
+ };
714
+ const getSelectedElements = (board) => {
715
+ return BOARD_TO_SELECTED_ELEMENT.get(board) || [];
716
+ };
717
+ const addSelectedElement = (board, element) => {
718
+ const selectedElements = getSelectedElements(board);
719
+ cacheSelectedElements(board, [...selectedElements, element]);
720
+ };
721
+ const removeSelectedElement = (board, element) => {
722
+ const selectedElements = getSelectedElements(board);
723
+ const newSelectedElements = selectedElements.filter(value => value !== element);
724
+ cacheSelectedElements(board, newSelectedElements);
725
+ };
726
+ const isSelectedElement = (board, element) => {
727
+ const selectedElements = getSelectedElements(board);
728
+ return !!selectedElements.find(value => value === element);
729
+ };
730
+
731
+ function hasBeforeContextChange(value) {
732
+ if (value.beforeContextChange) {
733
+ return true;
734
+ }
735
+ return false;
736
+ }
737
+ function hasOnContextChanged(value) {
738
+ if (value.onContextChanged) {
739
+ return true;
740
+ }
741
+ return false;
742
+ }
743
+
744
+ class PlaitPluginElementComponent {
745
+ set context(value) {
746
+ if (hasBeforeContextChange(this)) {
747
+ this.beforeContextChange(value);
748
+ }
749
+ const previousContext = this._context;
750
+ this._context = value;
751
+ if (this.element) {
752
+ ELEMENT_TO_COMPONENT.set(this.element, this);
753
+ }
754
+ if (this.initialized) {
755
+ this.cdr.markForCheck();
756
+ if (hasOnContextChanged(this)) {
757
+ this.onContextChanged(value, previousContext);
758
+ }
759
+ }
760
+ else {
761
+ if (PlaitElement.isRootElement(this.element) && this.element.children && this.element.children.length > 0) {
762
+ this.g = createG();
763
+ this.rootG = createG();
764
+ this.rootG.append(this.g);
765
+ }
766
+ else {
767
+ this.g = createG();
768
+ }
769
+ }
770
+ }
771
+ get context() {
772
+ return this._context;
773
+ }
774
+ get element() {
775
+ return this.context && this.context.element;
776
+ }
777
+ get board() {
778
+ return this.context && this.context.board;
779
+ }
780
+ get selected() {
781
+ return this.context && this.context.selected;
782
+ }
783
+ get effect() {
784
+ return this.context && this.context.effect;
785
+ }
786
+ constructor(cdr) {
787
+ this.cdr = cdr;
788
+ this.initialized = false;
789
+ }
790
+ ngOnInit() {
791
+ if (this.element.type) {
792
+ (this.rootG || this.g).setAttribute(`plait-${this.element.type}`, 'true');
793
+ }
794
+ this.initialized = true;
795
+ }
796
+ ngOnDestroy() {
797
+ if (ELEMENT_TO_COMPONENT.get(this.element) === this) {
798
+ ELEMENT_TO_COMPONENT.delete(this.element);
799
+ }
800
+ removeSelectedElement(this.board, this.element);
801
+ (this.rootG || this.g).remove();
802
+ }
803
+ }
804
+ PlaitPluginElementComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: PlaitPluginElementComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive });
805
+ PlaitPluginElementComponent.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.5", type: PlaitPluginElementComponent, inputs: { context: "context" }, ngImport: i0 });
806
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: PlaitPluginElementComponent, decorators: [{
807
+ type: Directive
808
+ }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { context: [{
809
+ type: Input
810
+ }] } });
811
+ const ELEMENT_TO_COMPONENT = new WeakMap();
812
+
587
813
  const PlaitElement = {
588
- // board node don't contain id
589
- isElement: (value) => {
590
- return !!value.id;
814
+ isRootElement(value) {
815
+ const parent = NODE_TO_PARENT.get(value);
816
+ if (parent && PlaitBoard.isBoard(parent)) {
817
+ return true;
818
+ }
819
+ else {
820
+ return false;
821
+ }
822
+ },
823
+ getComponent(value) {
824
+ return ELEMENT_TO_COMPONENT.get(value);
591
825
  }
592
826
  };
593
827
 
@@ -613,6 +847,14 @@ const RectangleClient = {
613
847
  const yMax = Math.max(...yArray);
614
848
  const rect = { x: xMin, y: yMin, width: xMax - xMin, height: yMax - yMin };
615
849
  return rect;
850
+ },
851
+ getOutlineRectangle: (rectangle, offset) => {
852
+ return {
853
+ x: rectangle.x + offset,
854
+ y: rectangle.y + offset,
855
+ width: rectangle.width + Math.abs(offset) * 2,
856
+ height: rectangle.height + Math.abs(offset) * 2
857
+ };
616
858
  }
617
859
  };
618
860
 
@@ -873,52 +1115,6 @@ function idCreator(length = 5) {
873
1115
  return key;
874
1116
  }
875
1117
 
876
- const calcElementIntersectionSelection = (board) => {
877
- const selectedElements = [];
878
- depthFirstRecursion(board, node => {
879
- var _a;
880
- if (PlaitElement.isElement(node) &&
881
- ((_a = board.selection) === null || _a === void 0 ? void 0 : _a.ranges.some(range => {
882
- return board.isHitSelection(node, range);
883
- }))) {
884
- selectedElements.push(node);
885
- }
886
- });
887
- return selectedElements;
888
- };
889
- const isIntersectionElements = (board, elements, ranges) => {
890
- let isIntersectionElements = false;
891
- if (elements.length) {
892
- elements.map(item => {
893
- if (!isIntersectionElements) {
894
- isIntersectionElements = ranges.some(range => {
895
- return board.isHitSelection(item, range);
896
- });
897
- }
898
- });
899
- }
900
- return isIntersectionElements;
901
- };
902
- const cacheSelectedElements = (board, selectedElements) => {
903
- BOARD_TO_SELECTED_ELEMENT.set(board, selectedElements);
904
- };
905
- const getSelectedElements = (board) => {
906
- return BOARD_TO_SELECTED_ELEMENT.get(board) || [];
907
- };
908
- const addSelectedElement = (board, element) => {
909
- const selectedElements = getSelectedElements(board);
910
- cacheSelectedElements(board, [...selectedElements, element]);
911
- };
912
- const removeSelectedElement = (board, element) => {
913
- const selectedElements = getSelectedElements(board);
914
- const newselectedElements = selectedElements.filter(value => value !== element);
915
- cacheSelectedElements(board, newselectedElements);
916
- };
917
- const isSelectedElement = (board, element) => {
918
- const selectedElements = getSelectedElements(board);
919
- return !!selectedElements.find(value => value === element);
920
- };
921
-
922
1118
  const CLIP_BOARD_FORMAT_KEY = 'x-plait-fragment';
923
1119
  const SCROLL_BAR_WIDTH = 20;
924
1120
  const MAX_RADIUS = 16;
@@ -944,6 +1140,48 @@ function drawRoundRectangle(rs, x1, y1, x2, y2, options, outline = false, border
944
1140
  const point8 = [x1, y1 + radius];
945
1141
  return rs.path(`M${point2[0]} ${point2[1]} A ${radius} ${radius}, 0, 0, 1, ${point3[0]} ${point3[1]} L ${point4[0]} ${point4[1]} A ${radius} ${radius}, 0, 0, 1, ${point5[0]} ${point5[1]} L ${point6[0]} ${point6[1]} A ${radius} ${radius}, 0, 0, 1, ${point7[0]} ${point7[1]} L ${point8[0]} ${point8[1]} A ${radius} ${radius}, 0, 0, 1, ${point1[0]} ${point1[1]} Z`, options);
946
1142
  }
1143
+ function drawAbstractRoundRectangle(rs, x1, y1, x2, y2, isHorizontal, options) {
1144
+ const width = Math.abs(x1 - x2);
1145
+ const height = Math.abs(y1 - y2);
1146
+ const radius = 3;
1147
+ const handleGap = 4;
1148
+ const handleLength = 10;
1149
+ const handleSpace = handleLength + handleGap * 2;
1150
+ if (isHorizontal) {
1151
+ const handleSideLine = (width - handleSpace - radius * 2) / 2;
1152
+ const sideLine = height - radius * 2;
1153
+ return rs.path(`M${x1 + radius},${y1}
1154
+ l${handleSideLine},0
1155
+ m${handleSpace},0
1156
+ l${handleSideLine},0
1157
+ a${radius},${radius},0,0,1,${radius},${radius}
1158
+ l0,${sideLine}
1159
+ a${radius},${radius},0,0,1,-${radius},${radius}
1160
+ l-${handleSideLine},0
1161
+ m-${handleSpace},0
1162
+ l-${handleSideLine},0
1163
+ a${radius},${radius},0,0,1,-${radius},-${radius}
1164
+ l0,-${sideLine}
1165
+ a${radius},${radius},0,0,1,${radius},-${radius}`, options);
1166
+ }
1167
+ else {
1168
+ const handleSideLine = (height - handleSpace - radius * 2) / 2;
1169
+ const sideLine = width - radius * 2;
1170
+ return rs.path(`M${x1 + radius},${y1}
1171
+ l${sideLine},0
1172
+ a${radius},${radius},0,0,1,${radius},${radius}
1173
+ l0,${handleSideLine}
1174
+ m0,${handleSpace}
1175
+ l0,${handleSideLine}
1176
+ a${radius},${radius},0,0,1,-${radius},${radius}
1177
+ l-${sideLine},0
1178
+ a${radius},${radius},0,0,1,-${radius},-${radius}
1179
+ l0,-${handleSideLine}
1180
+ m0,-${handleSpace}
1181
+ l0,-${handleSideLine}
1182
+ a${radius},${radius},0,0,1,${radius},-${radius}`, options);
1183
+ }
1184
+ }
947
1185
 
948
1186
  function arrowPoints(start, end, maxHypotenuseLength = 10, degree = 40) {
949
1187
  const width = Math.abs(start[0] - end[0]);
@@ -967,6 +1205,14 @@ function drawArrow(rs, start, end, options, maxHypotenuseLength = 10, degree = 4
967
1205
  return [arrowLineLeft, arrowLineRight];
968
1206
  }
969
1207
 
1208
+ function drawCircle(roughSVG, point, diameter, options) {
1209
+ return roughSVG.circle(point[0], point[1], diameter, options);
1210
+ }
1211
+
1212
+ function drawLine(rs, start, end, options) {
1213
+ return rs.linearPath([start, end], options);
1214
+ }
1215
+
970
1216
  const IS_FROM_SCROLLING = new WeakMap();
971
1217
  const IS_FROM_VIEWPORT_CHANGE = new WeakMap();
972
1218
  function getViewportContainerRect(board) {
@@ -980,7 +1226,7 @@ function getViewportContainerRect(board) {
980
1226
  }
981
1227
  function getElementHostBBox(board, zoom) {
982
1228
  const childrenRect = getRectangleByElements(board, board.children, true);
983
- const viewportContainerRect = getViewportContainerRect(board);
1229
+ const viewportContainerRect = PlaitBoard.getBoardNativeElement(board).getBoundingClientRect();
984
1230
  const containerWidth = viewportContainerRect.width / zoom;
985
1231
  const containerHeight = viewportContainerRect.height / zoom;
986
1232
  let left;
@@ -1027,7 +1273,7 @@ function clampZoomLevel(zoom, minZoom = 0.2, maxZoom = 4) {
1027
1273
  function getViewBox(board, zoom) {
1028
1274
  const { hideScrollbar } = board.options;
1029
1275
  const scrollBarWidth = hideScrollbar ? SCROLL_BAR_WIDTH : 0;
1030
- const viewportContainerRect = getViewportContainerRect(board);
1276
+ const viewportContainerRect = PlaitBoard.getBoardNativeElement(board).getBoundingClientRect();
1031
1277
  const elementHostBBox = getElementHostBBox(board, zoom);
1032
1278
  const horizontalPadding = viewportContainerRect.width / 2;
1033
1279
  const verticalPadding = viewportContainerRect.height / 2;
@@ -1061,12 +1307,12 @@ function updateViewportOffset(board) {
1061
1307
  const scrollTop = (origination[1] - viewBox[1]) * zoom;
1062
1308
  updateViewportContainerScroll(board, scrollLeft, scrollTop);
1063
1309
  }
1064
- function updateViewportContainerScroll(board, left, top) {
1310
+ function updateViewportContainerScroll(board, left, top, isFromViewportChange = true) {
1065
1311
  const viewportContainer = PlaitBoard.getViewportContainer(board);
1066
1312
  if (viewportContainer.scrollLeft !== left || viewportContainer.scrollTop !== top) {
1067
1313
  viewportContainer.scrollLeft = left;
1068
1314
  viewportContainer.scrollTop = top;
1069
- setIsFromViewportChange(board, true);
1315
+ isFromViewportChange && setIsFromViewportChange(board, true);
1070
1316
  }
1071
1317
  }
1072
1318
  function initializeViewportContainer(board) {
@@ -1208,8 +1454,8 @@ const getMovingElements = (board) => {
1208
1454
  };
1209
1455
  const addMovingElements = (board, elements) => {
1210
1456
  const movingElements = getMovingElements(board);
1211
- const neweElements = elements.filter(item => !movingElements.find(movingElement => movingElement.key === item.key));
1212
- cacheMovingElements(board, [...movingElements, ...neweElements]);
1457
+ const newElements = elements.filter(item => !movingElements.find(movingElement => movingElement.key === item.key));
1458
+ cacheMovingElements(board, [...movingElements, ...newElements]);
1213
1459
  };
1214
1460
  const removeMovingElements = (board) => {
1215
1461
  BOARD_TO_MOVING_ELEMENT.delete(board);
@@ -1278,6 +1524,7 @@ function createBoard(children, options) {
1278
1524
  destroyElement: (context) => { },
1279
1525
  isWithinSelection: element => false,
1280
1526
  isHitSelection: element => false,
1527
+ isRecursion: element => true,
1281
1528
  isMovable: element => false,
1282
1529
  getRectangle: element => null
1283
1530
  };
@@ -1407,7 +1654,7 @@ function withHandPointer(board) {
1407
1654
  const viewportContainer = PlaitBoard.getViewportContainer(board);
1408
1655
  const left = viewportContainer.scrollLeft - (event.x - plaitBoardMove.x);
1409
1656
  const top = viewportContainer.scrollTop - (event.y - plaitBoardMove.y);
1410
- updateViewportContainerScroll(board, left, top);
1657
+ updateViewportContainerScroll(board, left, top, false);
1411
1658
  plaitBoardMove.x = event.x;
1412
1659
  plaitBoardMove.y = event.y;
1413
1660
  }
@@ -1450,25 +1697,20 @@ function withSelection(board) {
1450
1697
  let selectionOuterG;
1451
1698
  let previousSelectedElements;
1452
1699
  board.mousedown = (event) => {
1453
- if (board.pointer === PlaitPointerType.hand && board.selection) {
1454
- mousedown(event);
1455
- return;
1456
- }
1457
1700
  if (event.button === 0) {
1458
1701
  start = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
1459
1702
  }
1460
1703
  if (start) {
1461
1704
  const ranges = [{ anchor: start, focus: start }];
1462
1705
  const selectedElements = getSelectedElements(board);
1463
- const intersectionSelectedElement = isIntersectionElements(board, selectedElements, ranges);
1464
- if (intersectionSelectedElement) {
1706
+ if (isIntersectionElements(board, selectedElements, ranges)) {
1465
1707
  start = null;
1708
+ mousedown(event);
1709
+ return;
1466
1710
  }
1467
- else {
1468
- Transforms.setSelection(board, { ranges: ranges });
1469
- if (calcElementIntersectionSelection(board).length) {
1470
- start = null;
1471
- }
1711
+ Transforms.setSelection(board, { ranges: ranges });
1712
+ if (getHitElements(board).length || board.pointer === PlaitPointerType.hand) {
1713
+ start = null;
1472
1714
  }
1473
1715
  }
1474
1716
  mousedown(event);
@@ -1516,42 +1758,44 @@ function withSelection(board) {
1516
1758
  };
1517
1759
  board.onChange = () => {
1518
1760
  // calc selected elements entry
1519
- try {
1520
- if (board.operations.find(value => value.type === 'set_selection')) {
1521
- selectionOuterG === null || selectionOuterG === void 0 ? void 0 : selectionOuterG.remove();
1522
- const temporaryElements = getTemporaryElements(board);
1523
- const elements = temporaryElements ? temporaryElements : calcElementIntersectionSelection(board);
1524
- cacheSelectedElements(board, elements);
1525
- previousSelectedElements = elements;
1526
- const { width, height } = getRectangleByElements(board, elements, false);
1527
- if (width > 0 && height > 0 && elements.length > 1) {
1528
- selectionOuterG = createSelectionOuterG(board, elements);
1529
- selectionOuterG.classList.add('selection-outer');
1530
- PlaitBoard.getHost(board).append(selectionOuterG);
1761
+ if (board.pointer !== PlaitPointerType.hand) {
1762
+ try {
1763
+ if (board.operations.find(value => value.type === 'set_selection')) {
1764
+ selectionOuterG === null || selectionOuterG === void 0 ? void 0 : selectionOuterG.remove();
1765
+ const temporaryElements = getTemporaryElements(board);
1766
+ const elements = temporaryElements ? temporaryElements : getHitElements(board);
1767
+ cacheSelectedElements(board, elements);
1768
+ previousSelectedElements = elements;
1769
+ const { width, height } = getRectangleByElements(board, elements, false);
1770
+ if (width > 0 && height > 0 && elements.length > 1) {
1771
+ selectionOuterG = createSelectionOuterG(board, elements);
1772
+ selectionOuterG.classList.add('selection-outer');
1773
+ PlaitBoard.getHost(board).append(selectionOuterG);
1774
+ }
1775
+ deleteTemporaryElements(board);
1531
1776
  }
1532
- deleteTemporaryElements(board);
1533
- }
1534
- else {
1535
- // wait node destroy and remove selected element state
1536
- setTimeout(() => {
1537
- const currentSelectedElements = getSelectedElements(board);
1538
- if (currentSelectedElements.length && currentSelectedElements.length > 1) {
1539
- const selectedElementChange = currentSelectedElements.some(item => !previousSelectedElements.includes(item));
1540
- if (selectedElementChange) {
1777
+ else {
1778
+ // wait node destroy and remove selected element state
1779
+ setTimeout(() => {
1780
+ const currentSelectedElements = getSelectedElements(board);
1781
+ if (currentSelectedElements.length && currentSelectedElements.length > 1) {
1782
+ const selectedElementChange = currentSelectedElements.some(item => !previousSelectedElements.includes(item));
1783
+ if (selectedElementChange) {
1784
+ selectionOuterG === null || selectionOuterG === void 0 ? void 0 : selectionOuterG.remove();
1785
+ selectionOuterG = createSelectionOuterG(board, currentSelectedElements);
1786
+ selectionOuterG.classList.add('selection-outer');
1787
+ PlaitBoard.getHost(board).append(selectionOuterG);
1788
+ }
1789
+ }
1790
+ else {
1541
1791
  selectionOuterG === null || selectionOuterG === void 0 ? void 0 : selectionOuterG.remove();
1542
- selectionOuterG = createSelectionOuterG(board, currentSelectedElements);
1543
- selectionOuterG.classList.add('selection-outer');
1544
- PlaitBoard.getHost(board).append(selectionOuterG);
1545
1792
  }
1546
- }
1547
- else {
1548
- selectionOuterG === null || selectionOuterG === void 0 ? void 0 : selectionOuterG.remove();
1549
- }
1550
- });
1793
+ });
1794
+ }
1795
+ }
1796
+ catch (error) {
1797
+ console.error(error);
1551
1798
  }
1552
- }
1553
- catch (error) {
1554
- console.error(error);
1555
1799
  }
1556
1800
  onChange();
1557
1801
  };
@@ -1586,7 +1830,7 @@ function createSelectionOuterG(board, selectElements) {
1586
1830
 
1587
1831
  function withViewport(board) {
1588
1832
  const { onChange } = board;
1589
- const throttleUpdate = () => debounce(() => {
1833
+ const throttleUpdate = debounce(() => {
1590
1834
  initializeViewBox(board);
1591
1835
  updateViewportOffset(board);
1592
1836
  }, 500, { leading: true });
@@ -1623,7 +1867,7 @@ function withMoving(board) {
1623
1867
  const host = BOARD_TO_HOST.get(board);
1624
1868
  const point = transformPoint(board, toPoint(event.x, event.y, host));
1625
1869
  const ranges = [{ anchor: point, focus: point }];
1626
- let movableElements = board.children.filter(item => PlaitElement.isElement(item) && board.isMovable(item));
1870
+ let movableElements = board.children.filter(item => board.isMovable(item));
1627
1871
  if (movableElements.length) {
1628
1872
  startPoint = point;
1629
1873
  const selectedRootElements = getSelectedElements(board).filter(item => movableElements.includes(item));
@@ -1701,71 +1945,76 @@ class PlaitElementComponent {
1701
1945
  this.renderer2 = renderer2;
1702
1946
  this.viewContainerRef = viewContainerRef;
1703
1947
  this.initialized = false;
1704
- this.selection = null;
1705
1948
  }
1706
1949
  ngOnInit() {
1707
1950
  this.initialize();
1708
1951
  this.drawElement();
1709
1952
  }
1710
1953
  initialize() {
1954
+ NODE_TO_INDEX.set(this.element, this.index);
1955
+ NODE_TO_PARENT.set(this.element, this.parent);
1711
1956
  this.initialized = true;
1712
- this.gGroup = createG();
1713
- this.renderer2.setAttribute(this.gGroup, 'plait-element-group', this.index.toString());
1714
- PlaitBoard.getElementHost(this.board).append(this.gGroup);
1715
1957
  }
1716
1958
  drawElement() {
1717
1959
  const context = this.getContext();
1718
- const result = this.board.drawElement(context.current);
1960
+ const result = this.board.drawElement(context);
1719
1961
  if (Array.isArray(result)) {
1720
- result.forEach(g => {
1721
- this.gGroup.appendChild(g);
1722
- });
1723
1962
  }
1724
1963
  else {
1725
1964
  const componentRef = this.viewContainerRef.createComponent(result);
1726
1965
  const instance = componentRef.instance;
1727
- instance.context = context.current;
1728
- this.gGroup.appendChild(instance.g);
1966
+ instance.context = context;
1967
+ this.insertG(instance.rootG ? instance.rootG : instance.g);
1729
1968
  this.instance = instance;
1730
1969
  }
1731
1970
  }
1732
- ngOnChanges() {
1971
+ insertG(g) {
1972
+ if (PlaitBoard.isBoard(this.parent)) {
1973
+ this.parentG.prepend(g);
1974
+ }
1975
+ else {
1976
+ let siblingG = PlaitElement.getComponent(this.parent).g;
1977
+ if (this.index > 0) {
1978
+ const brotherElement = this.parent.children[this.index - 1];
1979
+ const lastElement = PlaitNode.last(this.board, PlaitBoard.findPath(this.board, brotherElement));
1980
+ const siblingElement = lastElement || brotherElement;
1981
+ siblingG = PlaitElement.getComponent(siblingElement).g;
1982
+ }
1983
+ this.parentG.insertBefore(g, siblingG);
1984
+ }
1985
+ }
1986
+ ngOnChanges(simpleChanges) {
1733
1987
  if (this.initialized) {
1988
+ NODE_TO_INDEX.set(this.element, this.index);
1989
+ NODE_TO_PARENT.set(this.element, this.parent);
1990
+ const elementChanged = simpleChanges['element'];
1734
1991
  const context = this.getContext();
1735
- if (this.instance) {
1736
- this.instance.context = context.current;
1992
+ if (elementChanged && isSelectedElement(this.board, elementChanged.previousValue)) {
1993
+ context.selected = true;
1994
+ removeSelectedElement(this.board, elementChanged.previousValue);
1995
+ addSelectedElement(this.board, this.element);
1737
1996
  }
1738
- const result = this.board.redrawElement(context.current, context.previous);
1739
- if (result && result.length > 0) {
1740
- this.gGroup.childNodes.forEach(g => g.remove());
1741
- result.forEach(g => {
1742
- this.gGroup.appendChild(g);
1743
- });
1997
+ if (this.instance) {
1998
+ this.instance.context = context;
1744
1999
  }
1745
2000
  }
1746
2001
  }
1747
2002
  getContext() {
1748
- const current = {
2003
+ const isSelected = isSelectedElement(this.board, this.element);
2004
+ const context = {
1749
2005
  element: this.element,
1750
- selection: this.selection,
1751
- board: this.board
2006
+ board: this.board,
2007
+ selected: isSelected,
2008
+ effect: this.effect
1752
2009
  };
1753
- if (this.context) {
1754
- const previous = Object.assign({}, this.context);
1755
- this.context = current;
1756
- return { current, previous };
1757
- }
1758
- else {
1759
- return { current };
1760
- }
2010
+ return context;
1761
2011
  }
1762
2012
  ngOnDestroy() {
1763
- this.gGroup.remove();
1764
- this.board.destroyElement(this.getContext().current);
2013
+ this.board.destroyElement(this.getContext());
1765
2014
  }
1766
2015
  }
1767
2016
  PlaitElementComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: PlaitElementComponent, deps: [{ token: i0.Renderer2 }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Component });
1768
- PlaitElementComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.5", type: PlaitElementComponent, selector: "plait-element", inputs: { index: "index", element: "element", board: "board", viewport: "viewport", selection: "selection" }, usesOnChanges: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
2017
+ PlaitElementComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.5", type: PlaitElementComponent, selector: "plait-element", inputs: { index: "index", element: "element", parent: "parent", board: "board", effect: "effect", parentG: "parentG" }, usesOnChanges: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
1769
2018
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: PlaitElementComponent, decorators: [{
1770
2019
  type: Component,
1771
2020
  args: [{
@@ -1777,11 +2026,66 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
1777
2026
  type: Input
1778
2027
  }], element: [{
1779
2028
  type: Input
2029
+ }], parent: [{
2030
+ type: Input
1780
2031
  }], board: [{
1781
2032
  type: Input
1782
- }], viewport: [{
2033
+ }], effect: [{
1783
2034
  type: Input
1784
- }], selection: [{
2035
+ }], parentG: [{
2036
+ type: Input
2037
+ }] } });
2038
+
2039
+ class PlaitChildrenElement {
2040
+ constructor() {
2041
+ this.trackBy = (index, element) => {
2042
+ return element.id;
2043
+ };
2044
+ }
2045
+ ngOnInit() {
2046
+ if (!this.parent) {
2047
+ this.parent = this.board;
2048
+ }
2049
+ if (!this.parentG) {
2050
+ this.parentG = PlaitBoard.getElementHost(this.board);
2051
+ }
2052
+ }
2053
+ }
2054
+ PlaitChildrenElement.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: PlaitChildrenElement, deps: [], target: i0.ɵɵFactoryTarget.Component });
2055
+ PlaitChildrenElement.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.5", type: PlaitChildrenElement, selector: "plait-children", inputs: { board: "board", parent: "parent", effect: "effect", parentG: "parentG" }, ngImport: i0, template: `
2056
+ <plait-element
2057
+ *ngFor="let item of parent.children; let index = index; trackBy: trackBy"
2058
+ [index]="index"
2059
+ [element]="item"
2060
+ [parent]="parent"
2061
+ [board]="board"
2062
+ [effect]="effect"
2063
+ [parentG]="parentG"
2064
+ ></plait-element>
2065
+ `, isInline: true, dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: PlaitElementComponent, selector: "plait-element", inputs: ["index", "element", "parent", "board", "effect", "parentG"] }] });
2066
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: PlaitChildrenElement, decorators: [{
2067
+ type: Component,
2068
+ args: [{
2069
+ selector: 'plait-children',
2070
+ template: `
2071
+ <plait-element
2072
+ *ngFor="let item of parent.children; let index = index; trackBy: trackBy"
2073
+ [index]="index"
2074
+ [element]="item"
2075
+ [parent]="parent"
2076
+ [board]="board"
2077
+ [effect]="effect"
2078
+ [parentG]="parentG"
2079
+ ></plait-element>
2080
+ `
2081
+ }]
2082
+ }], ctorParameters: function () { return []; }, propDecorators: { board: [{
2083
+ type: Input
2084
+ }], parent: [{
2085
+ type: Input
2086
+ }], effect: [{
2087
+ type: Input
2088
+ }], parentG: [{
1785
2089
  type: Input
1786
2090
  }] } });
1787
2091
 
@@ -1858,19 +2162,19 @@ class PlaitBoardComponent {
1858
2162
  get nativeElement() {
1859
2163
  return this.elementRef.nativeElement;
1860
2164
  }
1861
- constructor(cdr, renderer2, elementRef, ngZone) {
2165
+ constructor(cdr, elementRef, ngZone) {
1862
2166
  this.cdr = cdr;
1863
- this.renderer2 = renderer2;
1864
2167
  this.elementRef = elementRef;
1865
2168
  this.ngZone = ngZone;
1866
2169
  this.hasInitialized = false;
2170
+ this.effect = {};
1867
2171
  this.destroy$ = new Subject();
1868
2172
  this.plaitValue = [];
1869
2173
  this.plaitPlugins = [];
1870
2174
  this.plaitChange = new EventEmitter();
1871
2175
  this.plaitBoardInitialized = new EventEmitter();
1872
2176
  this.trackBy = (index, element) => {
1873
- return index;
2177
+ return element.id;
1874
2178
  };
1875
2179
  }
1876
2180
  ngOnInit() {
@@ -1889,7 +2193,7 @@ class PlaitBoardComponent {
1889
2193
  BOARD_TO_HOST.set(this.board, this.host);
1890
2194
  BOARD_TO_ELEMENT_HOST.set(this.board, elementHost);
1891
2195
  BOARD_TO_ON_CHANGE.set(this.board, () => {
1892
- this.cdr.detectChanges();
2196
+ this.detect();
1893
2197
  const changeEvent = {
1894
2198
  children: this.board.children,
1895
2199
  operations: this.board.operations,
@@ -1900,6 +2204,10 @@ class PlaitBoardComponent {
1900
2204
  });
1901
2205
  this.hasInitialized = true;
1902
2206
  }
2207
+ detect() {
2208
+ this.effect = {};
2209
+ this.cdr.detectChanges();
2210
+ }
1903
2211
  mouseLeaveListener() {
1904
2212
  fromEvent(this.host, 'mouseleave')
1905
2213
  .pipe(takeUntil(this.destroy$))
@@ -2071,17 +2379,11 @@ class PlaitBoardComponent {
2071
2379
  this.cdr.markForCheck();
2072
2380
  }
2073
2381
  }
2074
- PlaitBoardComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: PlaitBoardComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
2382
+ PlaitBoardComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: PlaitBoardComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
2075
2383
  PlaitBoardComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.5", type: PlaitBoardComponent, selector: "plait-board", inputs: { plaitValue: "plaitValue", plaitViewport: "plaitViewport", plaitPlugins: "plaitPlugins", plaitOptions: "plaitOptions" }, outputs: { plaitChange: "plaitChange", plaitBoardInitialized: "plaitBoardInitialized" }, host: { properties: { "class": "this.hostClass", "class.readonly": "this.readonly", "class.focused": "this.isFocused" } }, queries: [{ propertyName: "toolbarTemplateRef", first: true, predicate: ["plaitToolbar"], descendants: true }], viewQueries: [{ propertyName: "svg", first: true, predicate: ["svg"], descendants: true, static: true }, { propertyName: "viewportContainer", first: true, predicate: ["viewportContainer"], descendants: true, read: ElementRef, static: true }], usesOnChanges: true, ngImport: i0, template: `
2076
2384
  <div class="viewport-container" #viewportContainer>
2077
2385
  <svg #svg width="100%" height="100%" style="position: relative;"><g class="element-host"></g></svg>
2078
- <plait-element
2079
- *ngFor="let item of board.children; let index = index; trackBy: trackBy"
2080
- [index]="index"
2081
- [element]="item"
2082
- [board]="board"
2083
- [selection]="board.selection"
2084
- ></plait-element>
2386
+ <plait-children [board]="board" [effect]="effect"></plait-children>
2085
2387
  </div>
2086
2388
  <plait-toolbar
2087
2389
  *ngIf="isFocused && !toolbarTemplateRef"
@@ -2092,7 +2394,7 @@ PlaitBoardComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", ve
2092
2394
  (resetZoomHandel)="resetZoomHandel()"
2093
2395
  ></plait-toolbar>
2094
2396
  <ng-content></ng-content>
2095
- `, isInline: true, dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: PlaitElementComponent, selector: "plait-element", inputs: ["index", "element", "board", "viewport", "selection"] }, { kind: "component", type: PlaitToolbarComponent, selector: "plait-toolbar", inputs: ["board"], outputs: ["adaptHandle", "zoomInHandle", "zoomOutHandle", "resetZoomHandel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2397
+ `, isInline: true, dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: PlaitChildrenElement, selector: "plait-children", inputs: ["board", "parent", "effect", "parentG"] }, { kind: "component", type: PlaitToolbarComponent, selector: "plait-toolbar", inputs: ["board"], outputs: ["adaptHandle", "zoomInHandle", "zoomOutHandle", "resetZoomHandel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2096
2398
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: PlaitBoardComponent, decorators: [{
2097
2399
  type: Component,
2098
2400
  args: [{
@@ -2100,13 +2402,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
2100
2402
  template: `
2101
2403
  <div class="viewport-container" #viewportContainer>
2102
2404
  <svg #svg width="100%" height="100%" style="position: relative;"><g class="element-host"></g></svg>
2103
- <plait-element
2104
- *ngFor="let item of board.children; let index = index; trackBy: trackBy"
2105
- [index]="index"
2106
- [element]="item"
2107
- [board]="board"
2108
- [selection]="board.selection"
2109
- ></plait-element>
2405
+ <plait-children [board]="board" [effect]="effect"></plait-children>
2110
2406
  </div>
2111
2407
  <plait-toolbar
2112
2408
  *ngIf="isFocused && !toolbarTemplateRef"
@@ -2120,7 +2416,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
2120
2416
  `,
2121
2417
  changeDetection: ChangeDetectionStrategy.OnPush
2122
2418
  }]
2123
- }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: i0.NgZone }]; }, propDecorators: { plaitValue: [{
2419
+ }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i0.NgZone }]; }, propDecorators: { plaitValue: [{
2124
2420
  type: Input
2125
2421
  }], plaitViewport: [{
2126
2422
  type: Input
@@ -2152,80 +2448,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
2152
2448
  args: ['viewportContainer', { read: ElementRef, static: true }]
2153
2449
  }] } });
2154
2450
 
2155
- function hasBeforeContextChange(value) {
2156
- if (value.beforeContextChange) {
2157
- return true;
2158
- }
2159
- return false;
2160
- }
2161
-
2162
- class PlaitPluginElementComponent {
2163
- set context(value) {
2164
- if (hasBeforeContextChange(this)) {
2165
- this.beforeContextChange(value);
2166
- }
2167
- const elementChanged = this.element && this.element !== value.element;
2168
- if (elementChanged) {
2169
- if (isSelectedElement(this.board, this.element)) {
2170
- removeSelectedElement(this.board, this.element);
2171
- addSelectedElement(this.board, value.element);
2172
- }
2173
- }
2174
- this._context = value;
2175
- if (this.element) {
2176
- ELEMENT_TO_PLUGIN_COMPONENT.set(this.element, this);
2177
- }
2178
- this.onContextChange();
2179
- }
2180
- get context() {
2181
- return this._context;
2182
- }
2183
- get element() {
2184
- return this.context && this.context.element;
2185
- }
2186
- get selection() {
2187
- return this.context && this.context.selection;
2188
- }
2189
- get board() {
2190
- return this.context && this.context.board;
2191
- }
2192
- constructor(cdr) {
2193
- this.cdr = cdr;
2194
- this.initialized = false;
2195
- this.g = createG();
2196
- }
2197
- onContextChange() {
2198
- if (!this.initialized) {
2199
- return;
2200
- }
2201
- this.cdr.markForCheck();
2202
- }
2203
- ngOnInit() {
2204
- var _a;
2205
- const type = ((_a = this.element) === null || _a === void 0 ? void 0 : _a.type) || 'default-plugin-element';
2206
- this.g.setAttribute(`plait-${type}`, 'true');
2207
- this.initialized = true;
2208
- }
2209
- ngOnDestroy() {
2210
- ELEMENT_TO_PLUGIN_COMPONENT.delete(this.element);
2211
- removeSelectedElement(this.board, this.element);
2212
- this.g.remove();
2213
- }
2214
- }
2215
- PlaitPluginElementComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: PlaitPluginElementComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive });
2216
- PlaitPluginElementComponent.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.5", type: PlaitPluginElementComponent, inputs: { context: "context" }, ngImport: i0 });
2217
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: PlaitPluginElementComponent, decorators: [{
2218
- type: Directive
2219
- }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { context: [{
2220
- type: Input
2221
- }] } });
2222
- const ELEMENT_TO_PLUGIN_COMPONENT = new WeakMap();
2223
-
2224
- const COMPONENTS = [PlaitBoardComponent, PlaitElementComponent, PlaitToolbarComponent];
2451
+ const COMPONENTS = [PlaitBoardComponent, PlaitChildrenElement, PlaitElementComponent, PlaitToolbarComponent];
2225
2452
  class PlaitModule {
2226
2453
  }
2227
2454
  PlaitModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: PlaitModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2228
- PlaitModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.5", ngImport: i0, type: PlaitModule, declarations: [PlaitBoardComponent, PlaitElementComponent, PlaitToolbarComponent], imports: [BrowserModule], exports: [PlaitBoardComponent, PlaitElementComponent, PlaitToolbarComponent] });
2455
+ PlaitModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.5", ngImport: i0, type: PlaitModule, declarations: [PlaitBoardComponent, PlaitChildrenElement, PlaitElementComponent, PlaitToolbarComponent], imports: [BrowserModule], exports: [PlaitBoardComponent, PlaitChildrenElement, PlaitElementComponent, PlaitToolbarComponent] });
2229
2456
  PlaitModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: PlaitModule, imports: [BrowserModule] });
2230
2457
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: PlaitModule, decorators: [{
2231
2458
  type: NgModule,
@@ -2244,5 +2471,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
2244
2471
  * Generated bundle index. Do not edit.
2245
2472
  */
2246
2473
 
2247
- export { 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_ON_CHANGE, BOARD_TO_ROUGH_SVG, BOARD_TO_SELECTED_ELEMENT, BOARD_TO_TEMPORARY_ELEMENTS, BOARD_TO_VIEWPORT_ORIGINATION, BoardTransforms, CLIP_BOARD_FORMAT_KEY, ELEMENT_TO_PLUGIN_COMPONENT, FLUSHING, IS_APPLE, IS_CHROME, IS_CHROME_LEGACY, IS_EDGE_LEGACY, IS_FIREFOX, IS_IOS, IS_SAFARI, IS_TEXT_EDITABLE, MAX_RADIUS, MERGING, NS, Path, PlaitBoard, PlaitBoardComponent, PlaitElement, PlaitElementComponent, PlaitHistoryBoard, PlaitModule, PlaitNode, PlaitOperation, PlaitPluginElementComponent, PlaitPointerType, PlaitToolbarComponent, Point, RectangleClient, SAVING, SCROLL_BAR_WIDTH, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, Selection, Transforms, Viewport, addMovingElements, addSelectedElement, arrowPoints, cacheMovingElements, cacheSelectedElements, calcElementIntersectionSelection, changeZoom, clampZoomLevel, clearSelectionMoving, clearViewportOrigination, createG, createSVG, createSelectionOuterG, createText, debounce, deleteTemporaryElements, depthFirstRecursion, distanceBetweenPointAndPoint, distanceBetweenPointAndRectangle, distanceBetweenPointAndSegment, drawArrow, drawRoundRectangle, fitViewport, getBoardRectangle, getElementHostBBox, getMovingElements, getRectangleByElements, getSelectedElements, getTemporaryElements, getViewBox, getViewportContainerRect, getViewportOrigination, hasBeforeContextChange, hotkeys, idCreator, initializeViewBox, initializeViewportContainer, initializeViewportOffset, inverse, isFromScrolling, isFromViewportChange, isInPlaitBoard, isIntersectionElements, isNullOrUndefined, isSelectedElement, isSelectionMoving, isSetViewportOperation, normalizePoint, removeMovingElements, removeSelectedElement, rotate, scrollToRectangle, setIsFromScrolling, setIsFromViewportChange, setSVGViewBox, setSelectionMoving, setViewport, shouldClear, shouldMerge, shouldSave, throttleRAF, toPoint, transformPoint, transformPoints, updateViewportContainerScroll, updateViewportOffset, updateViewportOrigination, withMoving, withSelection };
2474
+ export { 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_ON_CHANGE, BOARD_TO_ROUGH_SVG, BOARD_TO_SELECTED_ELEMENT, BOARD_TO_TEMPORARY_ELEMENTS, BOARD_TO_VIEWPORT_ORIGINATION, BoardTransforms, CLIP_BOARD_FORMAT_KEY, ELEMENT_TO_COMPONENT, FLUSHING, IS_APPLE, IS_BOARD_CACHE, IS_CHROME, IS_CHROME_LEGACY, IS_EDGE_LEGACY, IS_FIREFOX, IS_IOS, IS_SAFARI, IS_TEXT_EDITABLE, MAX_RADIUS, MERGING, NODE_TO_INDEX, NODE_TO_PARENT, NS, Path, PlaitBoard, PlaitBoardComponent, PlaitChildrenElement, PlaitElement, PlaitElementComponent, PlaitHistoryBoard, PlaitModule, PlaitNode, PlaitOperation, PlaitPluginElementComponent, PlaitPointerType, PlaitToolbarComponent, Point, RectangleClient, SAVING, SCROLL_BAR_WIDTH, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, Selection, Transforms, Viewport, addMovingElements, addSelectedElement, arrowPoints, cacheMovingElements, cacheSelectedElements, changeZoom, clampZoomLevel, clearSelectionMoving, clearViewportOrigination, createG, createSVG, createSelectionOuterG, createText, debounce, deleteTemporaryElements, depthFirstRecursion, distanceBetweenPointAndPoint, distanceBetweenPointAndRectangle, distanceBetweenPointAndSegment, drawAbstractRoundRectangle, drawArrow, drawCircle, drawLine, drawRoundRectangle, fitViewport, getBoardRectangle, getElementHostBBox, getHitElements, getMovingElements, getRectangleByElements, getSelectedElements, getTemporaryElements, getViewBox, getViewportContainerRect, getViewportOrigination, hasBeforeContextChange, hasOnContextChanged, hotkeys, idCreator, initializeViewBox, initializeViewportContainer, initializeViewportOffset, inverse, isFromScrolling, isFromViewportChange, isInPlaitBoard, isIntersectionElements, isNullOrUndefined, isSelectedElement, isSelectionMoving, isSetViewportOperation, normalizePoint, removeMovingElements, removeSelectedElement, rotate, scrollToRectangle, setIsFromScrolling, setIsFromViewportChange, setSVGViewBox, setSelectionMoving, setViewport, shouldClear, shouldMerge, shouldSave, throttleRAF, toPoint, transformPoint, transformPoints, updateViewportContainerScroll, updateViewportOffset, updateViewportOrigination, withMoving, withSelection };
2248
2475
  //# sourceMappingURL=plait-core.mjs.map