@plait/core 0.24.0-next.9 → 0.29.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 (60) hide show
  1. package/board/board.component.d.ts +1 -1
  2. package/constants/selection.d.ts +1 -0
  3. package/core/children/children.component.d.ts +3 -3
  4. package/core/element/element.component.d.ts +1 -1
  5. package/esm2022/board/board.component.mjs +11 -9
  6. package/esm2022/constants/resize.mjs +1 -1
  7. package/esm2022/constants/selection.mjs +2 -1
  8. package/esm2022/core/children/children.component.mjs +11 -9
  9. package/esm2022/core/element/context.mjs +1 -1
  10. package/esm2022/core/element/element.component.mjs +6 -5
  11. package/esm2022/core/element/plugin-element.mjs +4 -4
  12. package/esm2022/core/island/island-base.component.mjs +7 -7
  13. package/esm2022/interfaces/board.mjs +1 -1
  14. package/esm2022/interfaces/direction.mjs +8 -0
  15. package/esm2022/interfaces/index.mjs +2 -1
  16. package/esm2022/interfaces/plugin-key.mjs +1 -1
  17. package/esm2022/interfaces/point.mjs +1 -1
  18. package/esm2022/interfaces/rectangle-client.mjs +4 -1
  19. package/esm2022/interfaces/viewport.mjs +2 -2
  20. package/esm2022/plugins/create-board.mjs +10 -9
  21. package/esm2022/plugins/with-hotkey.mjs +5 -3
  22. package/esm2022/plugins/with-moving.mjs +17 -4
  23. package/esm2022/plugins/with-options.mjs +1 -1
  24. package/esm2022/plugins/with-selection.mjs +37 -25
  25. package/esm2022/public-api.mjs +1 -2
  26. package/esm2022/services/image-context.service.mjs +4 -4
  27. package/esm2022/testing/core/fake-weak-map.mjs +2 -2
  28. package/esm2022/testing/core/index.mjs +1 -1
  29. package/esm2022/testing/fake-events/event-objects.mjs +1 -1
  30. package/esm2022/testing/fake-events/index.mjs +1 -1
  31. package/esm2022/testing/index.mjs +1 -1
  32. package/esm2022/testing/test-element.mjs +1 -1
  33. package/esm2022/transforms/element.mjs +4 -4
  34. package/esm2022/transforms/selection.mjs +16 -6
  35. package/esm2022/utils/board.mjs +1 -1
  36. package/esm2022/utils/draw/rectangle.mjs +1 -1
  37. package/esm2022/utils/element.mjs +3 -3
  38. package/esm2022/utils/reaction-manager.mjs +370 -0
  39. package/esm2022/utils/to-image.mjs +106 -34
  40. package/esm2022/utils/tree.mjs +2 -2
  41. package/esm2022/utils/weak-maps.mjs +1 -1
  42. package/fesm2022/plait-core.mjs +745 -270
  43. package/fesm2022/plait-core.mjs.map +1 -1
  44. package/interfaces/board.d.ts +2 -1
  45. package/interfaces/direction.d.ts +7 -0
  46. package/interfaces/index.d.ts +1 -0
  47. package/interfaces/rectangle-client.d.ts +6 -0
  48. package/package.json +3 -2
  49. package/plugins/with-selection.d.ts +5 -1
  50. package/public-api.d.ts +0 -1
  51. package/styles/styles.scss +1 -1
  52. package/testing/core/fake-weak-map.d.ts +2 -2
  53. package/transforms/element.d.ts +2 -2
  54. package/transforms/selection.d.ts +2 -2
  55. package/utils/reaction-manager.d.ts +41 -0
  56. package/utils/to-image.d.ts +11 -0
  57. package/utils/tree.d.ts +2 -2
  58. package/utils/weak-maps.d.ts +4 -1
  59. package/esm2022/plait.module.mjs +0 -21
  60. package/plait.module.d.ts +0 -10
@@ -1,12 +1,11 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Directive, Input, Injectable, Component, ChangeDetectionStrategy, EventEmitter, ElementRef, Output, HostBinding, ViewChild, ContentChildren, NgModule } from '@angular/core';
2
+ import { Directive, Input, Injectable, Component, ChangeDetectionStrategy, EventEmitter, ElementRef, 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';
6
6
  import { isKeyHotkey, isHotkey } from 'is-hotkey';
7
7
  import produce, { createDraft, finishDraft, isDraft } from 'immer';
8
- import * as i1 from '@angular/common';
9
- import { CommonModule } from '@angular/common';
8
+ import { NgFor } from '@angular/common';
10
9
 
11
10
  // record richtext type status
12
11
  const IS_BOARD_CACHE = new WeakMap();
@@ -271,6 +270,7 @@ var ResizeCursorClass;
271
270
 
272
271
  const ATTACHED_ELEMENT_CLASS_NAME = 'plait-board-attached';
273
272
  const ACTIVE_STROKE_WIDTH = 1;
273
+ const SELECTION_RECTANGLE_CLASS_NAME = 'selection-rectangle';
274
274
 
275
275
  const CLIP_BOARD_FORMAT_KEY = 'x-plait-fragment';
276
276
  const HOST_CLASS_NAME = 'plait-board-container';
@@ -431,10 +431,10 @@ class PlaitPluginElementComponent {
431
431
  removeSelectedElement(this.board, this.element);
432
432
  (this.rootG || this.g).remove();
433
433
  }
434
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitPluginElementComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); }
435
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.3", type: PlaitPluginElementComponent, inputs: { context: "context" }, ngImport: i0 }); }
434
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PlaitPluginElementComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); }
435
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: PlaitPluginElementComponent, inputs: { context: "context" }, ngImport: i0 }); }
436
436
  }
437
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitPluginElementComponent, decorators: [{
437
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PlaitPluginElementComponent, decorators: [{
438
438
  type: Directive
439
439
  }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { context: [{
440
440
  type: Input
@@ -503,6 +503,9 @@ const RectangleClient = {
503
503
  [rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height],
504
504
  [rectangle.x, rectangle.y + rectangle.height / 2]
505
505
  ];
506
+ },
507
+ getConnectionPoint: (rectangle, point) => {
508
+ return [rectangle.x + rectangle.width * point[0], rectangle.y + rectangle.height * point[1]];
506
509
  }
507
510
  };
508
511
 
@@ -1241,6 +1244,68 @@ const cacheMovingElements = (board, elements) => {
1241
1244
  BOARD_TO_MOVING_ELEMENT.set(board, elements);
1242
1245
  };
1243
1246
 
1247
+ const IMAGE_CONTAINER = 'plait-image-container';
1248
+ /**
1249
+ * Is element node
1250
+ * @param node
1251
+ * @returns
1252
+ */
1253
+ function isElementNode(node) {
1254
+ return node.nodeType === Node.ELEMENT_NODE;
1255
+ }
1256
+ /**
1257
+ * load image resources
1258
+ * @param url image url
1259
+ * @returns image element
1260
+ */
1261
+ function loadImage(src) {
1262
+ return new Promise((resolve, reject) => {
1263
+ const img = new Image();
1264
+ img.crossOrigin = 'anonymous';
1265
+ img.onload = () => resolve(img);
1266
+ img.onerror = () => reject(new Error('Failed to load image'));
1267
+ img.src = src;
1268
+ });
1269
+ }
1270
+ /**
1271
+ * create and return canvas and context
1272
+ * @param width canvas width
1273
+ * @param height canvas height
1274
+ * @param fillStyle fill style
1275
+ * @returns canvas and context
1276
+ */
1277
+ function createCanvas(width, height, fillStyle = 'transparent') {
1278
+ const canvas = document.createElement('canvas');
1279
+ const ctx = canvas.getContext('2d');
1280
+ canvas.width = width;
1281
+ canvas.height = height;
1282
+ canvas.style.width = `${width}px`;
1283
+ canvas.style.height = `${height}px`;
1284
+ ctx.strokeStyle = '#ffffff';
1285
+ ctx.fillStyle = fillStyle;
1286
+ ctx.fillRect(0, 0, width, height);
1287
+ return {
1288
+ canvas,
1289
+ ctx
1290
+ };
1291
+ }
1292
+ /**
1293
+ * convert image to base64
1294
+ * @param url image url
1295
+ * @returns image base64
1296
+ */
1297
+ function convertImageToBase64(url) {
1298
+ return loadImage(url).then(img => {
1299
+ const { canvas, ctx } = createCanvas(img.width, img.height);
1300
+ ctx?.drawImage(img, 0, 0);
1301
+ return canvas.toDataURL('image/png');
1302
+ });
1303
+ }
1304
+ /**
1305
+ * clone node style
1306
+ * @param nativeNode source node
1307
+ * @param clonedNode clone node
1308
+ */
1244
1309
  function cloneCSSStyle(nativeNode, clonedNode) {
1245
1310
  const targetStyle = clonedNode.style;
1246
1311
  if (!targetStyle) {
@@ -1258,25 +1323,13 @@ function cloneCSSStyle(nativeNode, clonedNode) {
1258
1323
  });
1259
1324
  }
1260
1325
  }
1261
- function createCanvas(width, height, fillStyle) {
1262
- const canvas = document.createElement('canvas');
1263
- const ctx = canvas.getContext('2d');
1264
- canvas.width = width;
1265
- canvas.height = height;
1266
- canvas.style.width = `${width}px`;
1267
- canvas.style.height = `${height}px`;
1268
- ctx.strokeStyle = '#ffffff';
1269
- ctx.fillStyle = fillStyle;
1270
- ctx.fillRect(0, 0, width, height);
1271
- return {
1272
- canvas,
1273
- ctx
1274
- };
1275
- }
1276
- function isElementNode(node) {
1277
- return node.nodeType === Node.ELEMENT_NODE;
1278
- }
1279
- function cloneSvg(board, options) {
1326
+ /**
1327
+ * clone svg element
1328
+ * @param board board
1329
+ * @param options parameter configuration
1330
+ * @returns clone svg element
1331
+ */
1332
+ async function cloneSvg(board, options) {
1280
1333
  const elementHostBox = getRectangleByElements(board, board.children, true);
1281
1334
  const { width, height, x, y } = elementHostBox;
1282
1335
  const { padding = 4, inlineStyleClassNames } = options;
@@ -1289,8 +1342,9 @@ function cloneSvg(board, options) {
1289
1342
  cloneSvgElement.setAttribute('height', `${height}`);
1290
1343
  cloneSvgElement.setAttribute('viewBox', [x - padding, y - padding, width + 2 * padding, height + 2 * padding].join(','));
1291
1344
  if (inlineStyleClassNames) {
1292
- const sourceNodes = Array.from(sourceSvg.querySelectorAll(inlineStyleClassNames));
1293
- const cloneNodes = Array.from(cloneSvgElement.querySelectorAll(inlineStyleClassNames));
1345
+ const classNames = inlineStyleClassNames + `,.${IMAGE_CONTAINER}`;
1346
+ const sourceNodes = Array.from(sourceSvg.querySelectorAll(classNames));
1347
+ const cloneNodes = Array.from(cloneSvgElement.querySelectorAll(classNames));
1294
1348
  sourceNodes.forEach((node, index) => {
1295
1349
  const cloneNode = cloneNodes[index];
1296
1350
  const childElements = Array.from(node.querySelectorAll('*')).filter(isElementNode);
@@ -1298,21 +1352,38 @@ function cloneSvg(board, options) {
1298
1352
  sourceNodes.push(...childElements);
1299
1353
  cloneNodes.push(...cloneChildElements);
1300
1354
  });
1301
- sourceNodes.forEach((node, index) => {
1355
+ // processing styles
1356
+ sourceNodes.map((node, index) => {
1302
1357
  const cloneNode = cloneNodes[index];
1303
1358
  cloneCSSStyle(node, cloneNode);
1304
1359
  });
1305
1360
  }
1361
+ // 使用 Promise.all 等待所有异步操作完成
1362
+ const sourceImageNodes = Array.from(sourceSvg.querySelectorAll(`.${IMAGE_CONTAINER}`));
1363
+ const cloneImageNodes = Array.from(cloneSvgElement.querySelectorAll(`.${IMAGE_CONTAINER}`));
1364
+ await Promise.all(sourceImageNodes.map((_, index) => {
1365
+ return new Promise(resolve => {
1366
+ const cloneNode = cloneImageNodes[index];
1367
+ // processing image
1368
+ const image = cloneNode.querySelector('img');
1369
+ const url = image?.getAttribute('src');
1370
+ if (!url) {
1371
+ return resolve(true);
1372
+ }
1373
+ convertImageToBase64(url).then(base64Image => {
1374
+ image?.setAttribute('src', base64Image);
1375
+ resolve(true);
1376
+ });
1377
+ });
1378
+ }));
1306
1379
  return cloneSvgElement;
1307
1380
  }
1308
- function loadImage(src) {
1309
- return new Promise((resolve, reject) => {
1310
- const img = new Image();
1311
- img.onload = () => resolve(img);
1312
- img.onerror = () => reject(new Error('Failed to load image'));
1313
- img.src = src;
1314
- });
1315
- }
1381
+ /**
1382
+ * current board transfer pictures
1383
+ * @param board board
1384
+ * @param options parameter configuration
1385
+ * @returns images in the specified format base64
1386
+ */
1316
1387
  async function toImage(board, options) {
1317
1388
  if (!board) {
1318
1389
  return undefined;
@@ -1322,21 +1393,25 @@ async function toImage(board, options) {
1322
1393
  const { width, height } = elementHostBox;
1323
1394
  const ratioWidth = width * ratio;
1324
1395
  const ratioHeight = height * ratio;
1325
- const cloneSvgElement = cloneSvg(board, options);
1396
+ const cloneSvgElement = await cloneSvg(board, options);
1326
1397
  const { canvas, ctx } = createCanvas(ratioWidth, ratioHeight, fillStyle);
1327
1398
  const svgStr = new XMLSerializer().serializeToString(cloneSvgElement);
1328
1399
  const imgSrc = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgStr)}`;
1329
1400
  try {
1330
1401
  const img = await loadImage(imgSrc);
1331
1402
  ctx.drawImage(img, 0, 0, ratioWidth, ratioHeight);
1332
- const url = canvas.toDataURL('image/png');
1333
- return url;
1403
+ return canvas.toDataURL('image/png');
1334
1404
  }
1335
1405
  catch (error) {
1336
1406
  console.error('Error converting SVG to image:', error);
1337
1407
  return undefined;
1338
1408
  }
1339
1409
  }
1410
+ /**
1411
+ * download the file with the specified name
1412
+ * @param url download url
1413
+ * @param name file name
1414
+ */
1340
1415
  function downloadImage(url, name) {
1341
1416
  const a = document.createElement('a');
1342
1417
  a.href = url;
@@ -1755,7 +1830,7 @@ const Point = {
1755
1830
  const Viewport = {
1756
1831
  isViewport: (value) => {
1757
1832
  return !isNullOrUndefined(value.zoom) && !isNullOrUndefined(value.viewBackgroundColor);
1758
- },
1833
+ }
1759
1834
  };
1760
1835
 
1761
1836
  const SAVING = new WeakMap();
@@ -1814,6 +1889,14 @@ const ThemeColors = [
1814
1889
  StarryThemeColor
1815
1890
  ];
1816
1891
 
1892
+ var Direction;
1893
+ (function (Direction) {
1894
+ Direction["left"] = "left";
1895
+ Direction["top"] = "top";
1896
+ Direction["right"] = "right";
1897
+ Direction["bottom"] = "bottom";
1898
+ })(Direction || (Direction = {}));
1899
+
1817
1900
  function getRectangleByElements(board, elements, recursion) {
1818
1901
  const boundaryBox = {
1819
1902
  left: Number.MAX_VALUE,
@@ -1861,9 +1944,9 @@ function getBoardRectangle(board) {
1861
1944
  }
1862
1945
  function getElementById(board, id, dataSource) {
1863
1946
  if (!dataSource) {
1864
- dataSource = findElements(board, { match: (element) => true, recursion: (element) => true });
1947
+ dataSource = findElements(board, { match: element => true, recursion: element => true });
1865
1948
  }
1866
- let element = dataSource.find((element) => element.id === id);
1949
+ let element = dataSource.find(element => element.id === id);
1867
1950
  return element;
1868
1951
  }
1869
1952
  function findElements(board, options) {
@@ -2155,19 +2238,209 @@ const NodeTransforms = {
2155
2238
  moveNode
2156
2239
  };
2157
2240
 
2241
+ function withSelection(board) {
2242
+ const { pointerDown, globalPointerMove, globalPointerUp, onChange } = board;
2243
+ let start = null;
2244
+ let end = null;
2245
+ let selectionMovingG;
2246
+ let selectionRectangleG;
2247
+ let previousSelectedElements;
2248
+ // prevent text from being selected when user pressed main pointer and is moving
2249
+ let needPreventNativeSelectionWhenMoving = false;
2250
+ board.pointerDown = (event) => {
2251
+ if (event.target instanceof Element && !event.target.closest('.plait-richtext-container')) {
2252
+ needPreventNativeSelectionWhenMoving = true;
2253
+ }
2254
+ if (!isMainPointer(event)) {
2255
+ pointerDown(event);
2256
+ return;
2257
+ }
2258
+ const options = board.getPluginOptions(PlaitPluginKey.withSelection);
2259
+ const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
2260
+ const range = { anchor: point, focus: point };
2261
+ const hitElements = getHitElements(board, { ranges: [range] });
2262
+ const selectedElements = getSelectedElements(board);
2263
+ if (hitElements.length === 1 && selectedElements.includes(hitElements[0]) && !options.isDisabledSelect) {
2264
+ pointerDown(event);
2265
+ return;
2266
+ }
2267
+ if (PlaitBoard.isPointer(board, PlaitPointerType.selection) &&
2268
+ hitElements.length === 0 &&
2269
+ options.isMultiple &&
2270
+ !options.isDisabledSelect) {
2271
+ selectionRectangleG?.remove();
2272
+ start = point;
2273
+ preventTouchMove(board, event, true);
2274
+ }
2275
+ Transforms.setSelection(board, { ranges: [range] });
2276
+ pointerDown(event);
2277
+ };
2278
+ board.globalPointerMove = (event) => {
2279
+ if (needPreventNativeSelectionWhenMoving) {
2280
+ // prevent text from being selected
2281
+ event.preventDefault();
2282
+ }
2283
+ if (start) {
2284
+ const movedTarget = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
2285
+ const rectangle = RectangleClient.toRectangleClient([start, movedTarget]);
2286
+ selectionMovingG?.remove();
2287
+ if (Math.hypot(rectangle.width, rectangle.height) > 5) {
2288
+ end = movedTarget;
2289
+ throttleRAF(() => {
2290
+ if (start && end) {
2291
+ Transforms.setSelection(board, { ranges: [{ anchor: start, focus: end }] });
2292
+ }
2293
+ });
2294
+ setSelectionMoving(board);
2295
+ selectionMovingG = drawRectangle(board, rectangle, {
2296
+ stroke: SELECTION_BORDER_COLOR,
2297
+ strokeWidth: 1,
2298
+ fill: SELECTION_FILL_COLOR,
2299
+ fillStyle: 'solid'
2300
+ });
2301
+ PlaitBoard.getHost(board).append(selectionMovingG);
2302
+ }
2303
+ }
2304
+ globalPointerMove(event);
2305
+ };
2306
+ board.globalPointerUp = (event) => {
2307
+ if (start && end) {
2308
+ selectionMovingG?.remove();
2309
+ clearSelectionMoving(board);
2310
+ Transforms.setSelection(board, { ranges: [{ anchor: start, focus: end }] });
2311
+ }
2312
+ if (PlaitBoard.isFocus(board)) {
2313
+ const isInBoard = event.target instanceof Node && PlaitBoard.getBoardContainer(board).contains(event.target);
2314
+ const isInDocument = event.target instanceof Node && document.contains(event.target);
2315
+ const isAttachedElement = event.target instanceof Element && event.target.closest(`.${ATTACHED_ELEMENT_CLASS_NAME}`);
2316
+ // Clear selection when mouse board outside area
2317
+ // The framework needs to determine whether the board is focused through selection
2318
+ if (!isInBoard && !start && !isAttachedElement && isInDocument) {
2319
+ Transforms.setSelection(board, null);
2320
+ }
2321
+ }
2322
+ start = null;
2323
+ end = null;
2324
+ needPreventNativeSelectionWhenMoving = false;
2325
+ preventTouchMove(board, event, false);
2326
+ globalPointerUp(event);
2327
+ };
2328
+ board.onChange = () => {
2329
+ const options = board.getPluginOptions(PlaitPluginKey.withSelection);
2330
+ if (options.isDisabledSelect) {
2331
+ clearSelectedElement(board);
2332
+ }
2333
+ // calc selected elements entry
2334
+ if (board.pointer !== PlaitPointerType.hand && !options.isDisabledSelect) {
2335
+ try {
2336
+ if (board.operations.find(value => value.type === 'set_selection')) {
2337
+ selectionRectangleG?.remove();
2338
+ const temporaryElements = getTemporaryElements(board);
2339
+ let elements = temporaryElements ? temporaryElements : getHitElements(board);
2340
+ if (!options.isMultiple && elements.length > 1) {
2341
+ elements = [elements[0]];
2342
+ }
2343
+ cacheSelectedElements(board, elements);
2344
+ previousSelectedElements = elements;
2345
+ deleteTemporaryElements(board);
2346
+ if (!isSelectionMoving(board) && elements.length > 1) {
2347
+ selectionRectangleG = createSelectionRectangleG(board);
2348
+ }
2349
+ }
2350
+ else {
2351
+ // wait node destroy and remove selected element state
2352
+ setTimeout(() => {
2353
+ const currentSelectedElements = getSelectedElements(board);
2354
+ if (currentSelectedElements.length && currentSelectedElements.length > 1) {
2355
+ if (currentSelectedElements.length !== previousSelectedElements.length ||
2356
+ currentSelectedElements.some((c, index) => c !== previousSelectedElements[index])) {
2357
+ selectionRectangleG?.remove();
2358
+ selectionRectangleG = createSelectionRectangleG(board);
2359
+ previousSelectedElements = currentSelectedElements;
2360
+ }
2361
+ }
2362
+ else {
2363
+ selectionRectangleG?.remove();
2364
+ }
2365
+ });
2366
+ }
2367
+ }
2368
+ catch (error) {
2369
+ console.error(error);
2370
+ }
2371
+ }
2372
+ onChange();
2373
+ };
2374
+ board.setPluginOptions(PlaitPluginKey.withSelection, {
2375
+ isMultiple: true,
2376
+ isDisabledSelect: false
2377
+ });
2378
+ return board;
2379
+ }
2380
+ function getTemporaryElements(board) {
2381
+ const ref = BOARD_TO_TEMPORARY_ELEMENTS.get(board);
2382
+ if (ref) {
2383
+ return ref.elements;
2384
+ }
2385
+ else {
2386
+ return undefined;
2387
+ }
2388
+ }
2389
+ function getTemporaryRef(board) {
2390
+ return BOARD_TO_TEMPORARY_ELEMENTS.get(board);
2391
+ }
2392
+ function deleteTemporaryElements(board) {
2393
+ BOARD_TO_TEMPORARY_ELEMENTS.delete(board);
2394
+ }
2395
+ function isSelectionMoving(board) {
2396
+ return !!BOARD_TO_IS_SELECTION_MOVING.get(board);
2397
+ }
2398
+ function setSelectionMoving(board) {
2399
+ PlaitBoard.getBoardContainer(board).classList.add('selection-moving');
2400
+ BOARD_TO_IS_SELECTION_MOVING.set(board, true);
2401
+ }
2402
+ function clearSelectionMoving(board) {
2403
+ PlaitBoard.getBoardContainer(board).classList.remove('selection-moving');
2404
+ BOARD_TO_IS_SELECTION_MOVING.delete(board);
2405
+ }
2406
+ function createSelectionRectangleG(board) {
2407
+ const elements = getSelectedElements(board);
2408
+ const rectangle = getRectangleByElements(board, elements, false);
2409
+ if (rectangle.width > 0 && rectangle.height > 0 && elements.length > 1) {
2410
+ const selectionRectangleG = drawRectangle(board, RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH), {
2411
+ stroke: SELECTION_BORDER_COLOR,
2412
+ strokeWidth: ACTIVE_STROKE_WIDTH,
2413
+ fillStyle: 'solid'
2414
+ });
2415
+ selectionRectangleG.classList.add(SELECTION_RECTANGLE_CLASS_NAME);
2416
+ PlaitBoard.getHost(board).append(selectionRectangleG);
2417
+ return selectionRectangleG;
2418
+ }
2419
+ return null;
2420
+ }
2421
+
2158
2422
  function setSelection(board, selection) {
2159
2423
  const operation = { type: 'set_selection', properties: board.selection, newProperties: selection };
2160
2424
  board.apply(operation);
2161
2425
  }
2162
2426
  const SelectionTransforms = {
2163
2427
  setSelection,
2164
- setSelectionWithTemporaryElements
2428
+ addSelectionWithTemporaryElements
2165
2429
  };
2166
- function setSelectionWithTemporaryElements(board, elements) {
2167
- setTimeout(() => {
2168
- BOARD_TO_TEMPORARY_ELEMENTS.set(board, elements);
2430
+ function addSelectionWithTemporaryElements(board, elements) {
2431
+ const timeoutId = setTimeout(() => {
2169
2432
  setSelection(board, { ranges: [] });
2170
- });
2433
+ }, 0);
2434
+ let ref = getTemporaryRef(board);
2435
+ if (ref) {
2436
+ clearTimeout(ref.timeoutId);
2437
+ const currentElements = ref.elements;
2438
+ ref.elements.push(...elements.filter(element => !currentElements.includes(element)));
2439
+ ref.timeoutId = timeoutId;
2440
+ }
2441
+ else {
2442
+ BOARD_TO_TEMPORARY_ELEMENTS.set(board, { timeoutId, elements });
2443
+ }
2171
2444
  }
2172
2445
 
2173
2446
  function setViewport(board, viewport) {
@@ -2424,14 +2697,15 @@ function createBoard(children, options) {
2424
2697
  isMovable: element => false,
2425
2698
  getRectangle: element => null,
2426
2699
  applyTheme: (element) => { },
2427
- pointerDown: (pointer) => { },
2428
- pointerMove: (pointer) => { },
2429
- pointerUp: (pointer) => { },
2430
- pointerCancel: (pointer) => { },
2431
- pointerOut: (pointer) => { },
2432
- pointerLeave: (pointer) => { },
2433
- globalPointerMove: (pointer) => { },
2434
- globalPointerUp: (pointer) => { },
2700
+ isAlign: element => false,
2701
+ pointerDown: pointer => { },
2702
+ pointerMove: pointer => { },
2703
+ pointerUp: pointer => { },
2704
+ pointerCancel: pointer => { },
2705
+ pointerOut: pointer => { },
2706
+ pointerLeave: pointer => { },
2707
+ globalPointerMove: pointer => { },
2708
+ globalPointerUp: pointer => { }
2435
2709
  };
2436
2710
  return board;
2437
2711
  }
@@ -2586,175 +2860,6 @@ function withHandPointer(board) {
2586
2860
  return board;
2587
2861
  }
2588
2862
 
2589
- function withSelection(board) {
2590
- const { pointerDown, globalPointerMove, globalPointerUp, onChange } = board;
2591
- let start = null;
2592
- let end = null;
2593
- let selectionMovingG;
2594
- let selectionOuterG;
2595
- let previousSelectedElements;
2596
- // prevent text from being selected when user pressed main pointer and is moving
2597
- let needPreventNativeSelectionWhenMoving = false;
2598
- board.pointerDown = (event) => {
2599
- if (event.target instanceof Element && !event.target.closest('.plait-richtext-container')) {
2600
- needPreventNativeSelectionWhenMoving = true;
2601
- }
2602
- if (!isMainPointer(event)) {
2603
- pointerDown(event);
2604
- return;
2605
- }
2606
- const options = board.getPluginOptions(PlaitPluginKey.withSelection);
2607
- const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
2608
- const range = { anchor: point, focus: point };
2609
- const hitElements = getHitElements(board, { ranges: [range] });
2610
- const selectedElements = getSelectedElements(board);
2611
- if (hitElements.length === 1 && selectedElements.includes(hitElements[0]) && !options.isDisabledSelect) {
2612
- pointerDown(event);
2613
- return;
2614
- }
2615
- if (PlaitBoard.isPointer(board, PlaitPointerType.selection) &&
2616
- hitElements.length === 0 &&
2617
- options.isMultiple &&
2618
- !options.isDisabledSelect) {
2619
- start = point;
2620
- preventTouchMove(board, event, true);
2621
- }
2622
- Transforms.setSelection(board, { ranges: [range] });
2623
- pointerDown(event);
2624
- };
2625
- board.globalPointerMove = (event) => {
2626
- if (needPreventNativeSelectionWhenMoving) {
2627
- // prevent text from being selected
2628
- event.preventDefault();
2629
- }
2630
- if (start) {
2631
- const movedTarget = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
2632
- const rectangle = RectangleClient.toRectangleClient([start, movedTarget]);
2633
- selectionMovingG?.remove();
2634
- if (Math.hypot(rectangle.width, rectangle.height) > 5) {
2635
- end = movedTarget;
2636
- throttleRAF(() => {
2637
- if (start && end) {
2638
- Transforms.setSelection(board, { ranges: [{ anchor: start, focus: end }] });
2639
- }
2640
- });
2641
- setSelectionMoving(board);
2642
- selectionMovingG = drawRectangle(board, rectangle, {
2643
- stroke: SELECTION_BORDER_COLOR,
2644
- strokeWidth: 1,
2645
- fill: SELECTION_FILL_COLOR,
2646
- fillStyle: 'solid'
2647
- });
2648
- PlaitBoard.getHost(board).append(selectionMovingG);
2649
- }
2650
- }
2651
- globalPointerMove(event);
2652
- };
2653
- board.globalPointerUp = (event) => {
2654
- if (start && end) {
2655
- selectionMovingG?.remove();
2656
- clearSelectionMoving(board);
2657
- Transforms.setSelection(board, { ranges: [{ anchor: start, focus: end }] });
2658
- }
2659
- if (PlaitBoard.isFocus(board)) {
2660
- const isInBoard = event.target instanceof Node && PlaitBoard.getBoardContainer(board).contains(event.target);
2661
- const isInDocument = event.target instanceof Node && document.contains(event.target);
2662
- const isAttachedElement = event.target instanceof Element && event.target.closest(`.${ATTACHED_ELEMENT_CLASS_NAME}`);
2663
- // Clear selection when mouse board outside area
2664
- // The framework needs to determine whether the board is focused through selection
2665
- if (!isInBoard && !start && !isAttachedElement && isInDocument) {
2666
- Transforms.setSelection(board, null);
2667
- }
2668
- }
2669
- start = null;
2670
- end = null;
2671
- needPreventNativeSelectionWhenMoving = false;
2672
- preventTouchMove(board, event, false);
2673
- globalPointerUp(event);
2674
- };
2675
- board.onChange = () => {
2676
- const options = board.getPluginOptions(PlaitPluginKey.withSelection);
2677
- if (options.isDisabledSelect) {
2678
- selectionOuterG?.remove();
2679
- clearSelectedElement(board);
2680
- }
2681
- // calc selected elements entry
2682
- if (board.pointer !== PlaitPointerType.hand && !options.isDisabledSelect) {
2683
- try {
2684
- if (board.operations.find(value => value.type === 'set_selection')) {
2685
- selectionOuterG?.remove();
2686
- const temporaryElements = getTemporaryElements(board);
2687
- let elements = temporaryElements ? temporaryElements : getHitElements(board);
2688
- if (!options.isMultiple && elements.length > 1) {
2689
- elements = [elements[0]];
2690
- }
2691
- cacheSelectedElements(board, elements);
2692
- previousSelectedElements = elements;
2693
- const { width, height } = getRectangleByElements(board, elements, false);
2694
- if (width > 0 && height > 0 && elements.length > 1) {
2695
- selectionOuterG = createSelectionOuterG(board, elements);
2696
- selectionOuterG.classList.add('selection-outer');
2697
- PlaitBoard.getHost(board).append(selectionOuterG);
2698
- }
2699
- deleteTemporaryElements(board);
2700
- }
2701
- else {
2702
- // wait node destroy and remove selected element state
2703
- setTimeout(() => {
2704
- const currentSelectedElements = getSelectedElements(board);
2705
- if (currentSelectedElements.length && currentSelectedElements.length > 1) {
2706
- const selectedElementChange = currentSelectedElements.some(item => !previousSelectedElements.includes(item));
2707
- if (selectedElementChange) {
2708
- selectionOuterG?.remove();
2709
- selectionOuterG = createSelectionOuterG(board, currentSelectedElements);
2710
- selectionOuterG.classList.add('selection-outer');
2711
- PlaitBoard.getHost(board).append(selectionOuterG);
2712
- }
2713
- }
2714
- else {
2715
- selectionOuterG?.remove();
2716
- }
2717
- });
2718
- }
2719
- }
2720
- catch (error) {
2721
- console.error(error);
2722
- }
2723
- }
2724
- onChange();
2725
- };
2726
- board.setPluginOptions(PlaitPluginKey.withSelection, {
2727
- isMultiple: true,
2728
- isDisabledSelect: false
2729
- });
2730
- return board;
2731
- }
2732
- function getTemporaryElements(board) {
2733
- return BOARD_TO_TEMPORARY_ELEMENTS.get(board);
2734
- }
2735
- function deleteTemporaryElements(board) {
2736
- BOARD_TO_TEMPORARY_ELEMENTS.delete(board);
2737
- }
2738
- function isSelectionMoving(board) {
2739
- return !!BOARD_TO_IS_SELECTION_MOVING.get(board);
2740
- }
2741
- function setSelectionMoving(board) {
2742
- PlaitBoard.getBoardContainer(board).classList.add('selection-moving');
2743
- BOARD_TO_IS_SELECTION_MOVING.set(board, true);
2744
- }
2745
- function clearSelectionMoving(board) {
2746
- PlaitBoard.getBoardContainer(board).classList.remove('selection-moving');
2747
- BOARD_TO_IS_SELECTION_MOVING.delete(board);
2748
- }
2749
- function createSelectionOuterG(board, selectElements) {
2750
- const rectangle = getRectangleByElements(board, selectElements, false);
2751
- return drawRectangle(board, RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH), {
2752
- stroke: SELECTION_BORDER_COLOR,
2753
- strokeWidth: ACTIVE_STROKE_WIDTH,
2754
- fillStyle: 'solid'
2755
- });
2756
- }
2757
-
2758
2863
  function withViewport(board) {
2759
2864
  const { onChange } = board;
2760
2865
  const throttleUpdate = debounce(() => {
@@ -2783,6 +2888,372 @@ function withViewport(board) {
2783
2888
  return board;
2784
2889
  }
2785
2890
 
2891
+ const ALIGN_TOLERANCE = 2;
2892
+ class AlignReaction {
2893
+ constructor(board, activeElements, activeRectangle) {
2894
+ this.board = board;
2895
+ this.activeElements = activeElements;
2896
+ this.activeRectangle = activeRectangle;
2897
+ this.alignRectangles = this.getAlignRectangle();
2898
+ }
2899
+ getAlignRectangle() {
2900
+ const result = [];
2901
+ depthFirstRecursion(this.board, node => {
2902
+ if (PlaitBoard.isBoard(node) || this.activeElements.some(element => node.id === element.id) || !this.board.isAlign(node)) {
2903
+ return;
2904
+ }
2905
+ const rectangle = this.board.getRectangle(node);
2906
+ rectangle && result.push(rectangle);
2907
+ }, node => {
2908
+ if (node && (PlaitBoard.isBoard(node) || this.board.isRecursion(node))) {
2909
+ return true;
2910
+ }
2911
+ else {
2912
+ return false;
2913
+ }
2914
+ }, true);
2915
+ return result;
2916
+ }
2917
+ handleAlign() {
2918
+ const alignRectangles = this.getAlignRectangle();
2919
+ const g = createG();
2920
+ let alignLines = [];
2921
+ const offset = 12;
2922
+ let deltaX = 0;
2923
+ let deltaY = 0;
2924
+ let isCorrectX = false;
2925
+ let isCorrectY = false;
2926
+ for (let alignRectangle of alignRectangles) {
2927
+ const closestDistances = this.calculateClosestDistances(this.activeRectangle, alignRectangle);
2928
+ let canDrawHorizontal = false;
2929
+ if (!isCorrectX && closestDistances.absXDistance < ALIGN_TOLERANCE) {
2930
+ deltaX = closestDistances.xDistance;
2931
+ this.activeRectangle.x -= deltaX;
2932
+ isCorrectX = true;
2933
+ canDrawHorizontal = true;
2934
+ }
2935
+ if (closestDistances.absXDistance === 0) {
2936
+ canDrawHorizontal = true;
2937
+ }
2938
+ if (canDrawHorizontal) {
2939
+ const verticalY = [
2940
+ alignRectangle.y,
2941
+ alignRectangle.y + alignRectangle.height,
2942
+ this.activeRectangle.y,
2943
+ this.activeRectangle.y + this.activeRectangle.height
2944
+ ];
2945
+ const lineTopY = Math.min(...verticalY) - offset;
2946
+ const lineBottomY = Math.max(...verticalY) + offset;
2947
+ const leftLine = [this.activeRectangle.x, lineTopY, this.activeRectangle.x, lineBottomY];
2948
+ const middleLine = [
2949
+ this.activeRectangle.x + this.activeRectangle.width / 2,
2950
+ lineTopY,
2951
+ this.activeRectangle.x + this.activeRectangle.width / 2,
2952
+ lineBottomY
2953
+ ];
2954
+ const rightLine = [
2955
+ this.activeRectangle.x + this.activeRectangle.width,
2956
+ lineTopY,
2957
+ this.activeRectangle.x + this.activeRectangle.width,
2958
+ lineBottomY
2959
+ ];
2960
+ const shouldDrawLeftLine = closestDistances.indexX === 0 ||
2961
+ closestDistances.indexX === 1 ||
2962
+ (closestDistances.indexX === 2 && this.activeRectangle.width === alignRectangle.width);
2963
+ if (shouldDrawLeftLine && !alignLines[0]) {
2964
+ alignLines[0] = leftLine;
2965
+ }
2966
+ const shouldDrawRightLine = closestDistances.indexX === 2 ||
2967
+ closestDistances.indexX === 3 ||
2968
+ (closestDistances.indexX === 0 && this.activeRectangle.width === alignRectangle.width);
2969
+ if (shouldDrawRightLine && !alignLines[2]) {
2970
+ alignLines[2] = rightLine;
2971
+ }
2972
+ const shouldDrawMiddleLine = closestDistances.indexX === 4 || (!shouldDrawLeftLine && !shouldDrawRightLine);
2973
+ if (shouldDrawMiddleLine && !alignLines[1]) {
2974
+ alignLines[1] = middleLine;
2975
+ }
2976
+ isCorrectX = true;
2977
+ }
2978
+ let canDrawVertical = false;
2979
+ if (!isCorrectY && closestDistances.absYDistance < ALIGN_TOLERANCE) {
2980
+ deltaY = closestDistances.yDistance;
2981
+ this.activeRectangle.y -= deltaY;
2982
+ isCorrectY = true;
2983
+ canDrawVertical = true;
2984
+ }
2985
+ if (closestDistances.absYDistance === 0) {
2986
+ canDrawVertical = true;
2987
+ }
2988
+ if (canDrawVertical) {
2989
+ const horizontalX = [
2990
+ alignRectangle.x,
2991
+ alignRectangle.x + alignRectangle.width,
2992
+ this.activeRectangle.x,
2993
+ this.activeRectangle.x + this.activeRectangle.width
2994
+ ];
2995
+ const lineLeftX = Math.min(...horizontalX) - offset;
2996
+ const lineRightX = Math.max(...horizontalX) + offset;
2997
+ const topLine = [lineLeftX, this.activeRectangle.y, lineRightX, this.activeRectangle.y];
2998
+ const horizontalMiddleLine = [
2999
+ lineLeftX,
3000
+ this.activeRectangle.y + this.activeRectangle.height / 2,
3001
+ lineRightX,
3002
+ this.activeRectangle.y + this.activeRectangle.height / 2
3003
+ ];
3004
+ const bottomLine = [
3005
+ lineLeftX,
3006
+ this.activeRectangle.y + this.activeRectangle.height,
3007
+ lineRightX,
3008
+ this.activeRectangle.y + this.activeRectangle.height
3009
+ ];
3010
+ const shouldDrawTopLine = closestDistances.indexY === 0 ||
3011
+ closestDistances.indexY === 1 ||
3012
+ (closestDistances.indexY === 2 && this.activeRectangle.height === alignRectangle.height);
3013
+ if (shouldDrawTopLine && !alignLines[3]) {
3014
+ alignLines[3] = topLine;
3015
+ }
3016
+ const shouldDrawBottomLine = closestDistances.indexY === 2 ||
3017
+ closestDistances.indexY === 3 ||
3018
+ (closestDistances.indexY === 0 && this.activeRectangle.width === alignRectangle.width);
3019
+ if (shouldDrawBottomLine && !alignLines[5]) {
3020
+ alignLines[5] = bottomLine;
3021
+ }
3022
+ const shouldDrawMiddleLine = closestDistances.indexY === 4 || (!shouldDrawTopLine && !shouldDrawBottomLine);
3023
+ if (shouldDrawMiddleLine && !alignLines[4]) {
3024
+ alignLines[4] = horizontalMiddleLine;
3025
+ }
3026
+ }
3027
+ }
3028
+ const alignDeltaX = deltaX;
3029
+ const alignDeltaY = deltaY;
3030
+ this.activeRectangle.x += deltaX;
3031
+ const distributeHorizontalResult = this.alignDistribute(alignRectangles, true);
3032
+ const distributeVerticalResult = this.alignDistribute(alignRectangles, false);
3033
+ const distributeLines = [...distributeHorizontalResult.distributeLines, ...distributeVerticalResult.distributeLines];
3034
+ if (distributeHorizontalResult.delta) {
3035
+ deltaX = distributeHorizontalResult.delta;
3036
+ if (alignDeltaX !== deltaX) {
3037
+ alignLines[0] = [];
3038
+ alignLines[1] = [];
3039
+ alignLines[2] = [];
3040
+ }
3041
+ }
3042
+ if (distributeVerticalResult.delta) {
3043
+ deltaY = distributeVerticalResult.delta;
3044
+ if (alignDeltaY !== deltaY) {
3045
+ alignLines[3] = [];
3046
+ alignLines[4] = [];
3047
+ alignLines[5] = [];
3048
+ }
3049
+ }
3050
+ if (alignLines.length) {
3051
+ this.drawAlignLines(alignLines, g);
3052
+ }
3053
+ if (distributeLines.length) {
3054
+ this.drawDistributeLines(distributeLines, g);
3055
+ }
3056
+ return { deltaX, deltaY, g };
3057
+ }
3058
+ calculateClosestDistances(activeRectangle, alignRectangle) {
3059
+ const activeRectangleCenter = [activeRectangle.x + activeRectangle.width / 2, activeRectangle.y + activeRectangle.height / 2];
3060
+ const alignRectangleCenter = [alignRectangle.x + alignRectangle.width / 2, alignRectangle.y + alignRectangle.height / 2];
3061
+ const centerXDistance = activeRectangleCenter[0] - alignRectangleCenter[0];
3062
+ const centerYDistance = activeRectangleCenter[1] - alignRectangleCenter[1];
3063
+ const leftToLeft = activeRectangle.x - alignRectangle.x;
3064
+ const leftToRight = activeRectangle.x - (alignRectangle.x + alignRectangle.width);
3065
+ const rightToRight = activeRectangle.x + activeRectangle.width - (alignRectangle.x + alignRectangle.width);
3066
+ const rightToLeft = activeRectangle.x + activeRectangle.width - alignRectangle.x;
3067
+ const topToTop = activeRectangle.y - alignRectangle.y;
3068
+ const topToBottom = activeRectangle.y - (alignRectangle.y + alignRectangle.height);
3069
+ const bottomToTop = activeRectangle.y + activeRectangle.height - alignRectangle.y;
3070
+ const bottomToBottom = activeRectangle.y + activeRectangle.height - (alignRectangle.y + alignRectangle.height);
3071
+ const xDistances = [leftToLeft, leftToRight, rightToRight, rightToLeft, centerXDistance];
3072
+ const yDistances = [topToTop, topToBottom, bottomToBottom, bottomToTop, centerYDistance];
3073
+ const xDistancesAbs = xDistances.map(distance => Math.abs(distance));
3074
+ const yDistancesAbs = yDistances.map(distance => Math.abs(distance));
3075
+ const indexX = xDistancesAbs.indexOf(Math.min(...xDistancesAbs));
3076
+ const indexY = yDistancesAbs.indexOf(Math.min(...yDistancesAbs));
3077
+ return {
3078
+ absXDistance: xDistancesAbs[indexX],
3079
+ xDistance: xDistances[indexX],
3080
+ absYDistance: yDistancesAbs[indexY],
3081
+ yDistance: yDistances[indexY],
3082
+ indexX,
3083
+ indexY
3084
+ };
3085
+ }
3086
+ alignDistribute(alignRectangles, isHorizontal) {
3087
+ let distributeLines = [];
3088
+ let delta = 0;
3089
+ let rectangles = [];
3090
+ const axis = isHorizontal ? 'x' : 'y';
3091
+ const side = isHorizontal ? 'width' : 'height';
3092
+ const activeRectangleCenter = this.activeRectangle[axis] + this.activeRectangle[side] / 2;
3093
+ alignRectangles.forEach(rec => {
3094
+ const isCross = isHorizontal ? isHorizontalCross(rec, this.activeRectangle) : isVerticalCross(rec, this.activeRectangle);
3095
+ if (isCross && !RectangleClient.isHit(rec, this.activeRectangle)) {
3096
+ rectangles.push(rec);
3097
+ }
3098
+ });
3099
+ rectangles = [...rectangles, this.activeRectangle].sort((a, b) => a[axis] - b[axis]);
3100
+ const refArray = [];
3101
+ let distributeDistance = 0;
3102
+ let beforeIndex = undefined;
3103
+ let afterIndex = undefined;
3104
+ for (let i = 0; i < rectangles.length; i++) {
3105
+ for (let j = i + 1; j < rectangles.length; j++) {
3106
+ const before = rectangles[i];
3107
+ const after = rectangles[j];
3108
+ const distance = after[axis] - (before[axis] + before[side]);
3109
+ let dif = Infinity;
3110
+ if (refArray[i]?.after) {
3111
+ refArray[i].after.push({ distance, index: j });
3112
+ }
3113
+ else {
3114
+ refArray[i] = { ...refArray[i], after: [{ distance, index: j }] };
3115
+ }
3116
+ if (refArray[j]?.before) {
3117
+ refArray[j].before.push({ distance, index: i });
3118
+ }
3119
+ else {
3120
+ refArray[j] = { ...refArray[j], before: [{ distance, index: i }] };
3121
+ }
3122
+ //middle
3123
+ let _center = (before[axis] + before[side] + after[axis]) / 2;
3124
+ dif = Math.abs(activeRectangleCenter - _center);
3125
+ if (dif < ALIGN_TOLERANCE) {
3126
+ distributeDistance = (after[axis] - (before[axis] + before[side]) - this.activeRectangle[side]) / 2;
3127
+ delta = activeRectangleCenter - _center;
3128
+ beforeIndex = i;
3129
+ afterIndex = j;
3130
+ }
3131
+ //after
3132
+ const distanceRight = after[axis] - (before[axis] + before[side]);
3133
+ _center = after[axis] + after[side] + distanceRight + this.activeRectangle[side] / 2;
3134
+ dif = Math.abs(activeRectangleCenter - _center);
3135
+ if (!distributeDistance && dif < ALIGN_TOLERANCE) {
3136
+ distributeDistance = distanceRight;
3137
+ beforeIndex = j;
3138
+ delta = activeRectangleCenter - _center;
3139
+ }
3140
+ //before
3141
+ const distanceBefore = after[axis] - (before[axis] + before[side]);
3142
+ _center = before[axis] - distanceBefore - this.activeRectangle[side] / 2;
3143
+ dif = Math.abs(activeRectangleCenter - _center);
3144
+ if (!distributeDistance && dif < ALIGN_TOLERANCE) {
3145
+ distributeDistance = distanceBefore;
3146
+ afterIndex = i;
3147
+ delta = activeRectangleCenter - _center;
3148
+ }
3149
+ }
3150
+ }
3151
+ const activeIndex = rectangles.indexOf(this.activeRectangle);
3152
+ let beforeIndexes = [];
3153
+ let afterIndexes = [];
3154
+ if (beforeIndex !== undefined) {
3155
+ beforeIndexes.push(beforeIndex);
3156
+ findRectangle(distributeDistance, refArray[beforeIndex], 'before', beforeIndexes);
3157
+ }
3158
+ if (afterIndex !== undefined) {
3159
+ afterIndexes.push(afterIndex);
3160
+ findRectangle(distributeDistance, refArray[afterIndex], 'after', afterIndexes);
3161
+ }
3162
+ if (beforeIndexes.length || afterIndexes.length) {
3163
+ const indexArr = [...beforeIndexes.reverse(), activeIndex, ...afterIndexes];
3164
+ this.activeRectangle[axis] -= delta;
3165
+ for (let i = 1; i < indexArr.length; i++) {
3166
+ distributeLines.push(getLinePoints(rectangles[indexArr[i - 1]], rectangles[indexArr[i]]));
3167
+ }
3168
+ }
3169
+ function findRectangle(distance, ref, direction, rectangleIndexes) {
3170
+ const arr = ref[direction];
3171
+ const index = refArray.indexOf(ref);
3172
+ if ((index === 0 && direction === 'before') || (index === refArray.length - 1 && direction === 'after'))
3173
+ return;
3174
+ for (let i = 0; i < arr.length; i++) {
3175
+ if (Math.abs(arr[i].distance - distance) < 0.1) {
3176
+ rectangleIndexes.push(arr[i].index);
3177
+ findRectangle(distance, refArray[arr[i].index], direction, rectangleIndexes);
3178
+ return;
3179
+ }
3180
+ }
3181
+ }
3182
+ function getLinePoints(beforeRectangle, afterRectangle) {
3183
+ const oppositeAxis = axis === 'x' ? 'y' : 'x';
3184
+ const oppositeSide = side === 'width' ? 'height' : 'width';
3185
+ const align = [
3186
+ beforeRectangle[oppositeAxis],
3187
+ beforeRectangle[oppositeAxis] + beforeRectangle[oppositeSide],
3188
+ afterRectangle[oppositeAxis],
3189
+ afterRectangle[oppositeAxis] + afterRectangle[oppositeSide]
3190
+ ];
3191
+ const sortArr = align.sort((a, b) => a - b);
3192
+ const average = (sortArr[1] + sortArr[2]) / 2;
3193
+ const offset = 3;
3194
+ return isHorizontal
3195
+ ? [
3196
+ [beforeRectangle.x + beforeRectangle.width + offset, average],
3197
+ [afterRectangle.x - offset, average]
3198
+ ]
3199
+ : [
3200
+ [average, beforeRectangle.y + beforeRectangle.height + offset],
3201
+ [average, afterRectangle.y - offset]
3202
+ ];
3203
+ }
3204
+ return { delta, distributeLines };
3205
+ }
3206
+ drawAlignLines(lines, g) {
3207
+ lines.forEach(points => {
3208
+ if (!points.length)
3209
+ return;
3210
+ const xAlign = PlaitBoard.getRoughSVG(this.board).line(points[0], points[1], points[2], points[3], {
3211
+ stroke: SELECTION_BORDER_COLOR,
3212
+ strokeWidth: 1,
3213
+ strokeLineDash: [4, 4]
3214
+ });
3215
+ g.appendChild(xAlign);
3216
+ });
3217
+ }
3218
+ drawDistributeLines(lines, g) {
3219
+ lines.forEach(line => {
3220
+ if (!line.length)
3221
+ return;
3222
+ let isHorizontal = line[0][1] === line[1][1];
3223
+ const yAlign = PlaitBoard.getRoughSVG(this.board).line(line[0][0], line[0][1], line[1][0], line[1][1], {
3224
+ stroke: SELECTION_BORDER_COLOR,
3225
+ strokeWidth: 1
3226
+ });
3227
+ g.appendChild(yAlign);
3228
+ line.forEach(point => {
3229
+ const barPoint = getBarPoint(point, isHorizontal);
3230
+ const bar = PlaitBoard.getRoughSVG(this.board).line(barPoint[0][0], barPoint[0][1], barPoint[1][0], barPoint[1][1], {
3231
+ stroke: SELECTION_BORDER_COLOR,
3232
+ strokeWidth: 1
3233
+ });
3234
+ g.appendChild(bar);
3235
+ });
3236
+ });
3237
+ }
3238
+ }
3239
+ function isHorizontalCross(rectangle, other) {
3240
+ return !(rectangle.y + rectangle.height < other.y || rectangle.y > other.y + other.height);
3241
+ }
3242
+ function isVerticalCross(rectangle, other) {
3243
+ return !(rectangle.x + rectangle.width < other.x || rectangle.x > other.x + other.width);
3244
+ }
3245
+ function getBarPoint(point, isHorizontal) {
3246
+ return isHorizontal
3247
+ ? [
3248
+ [point[0], point[1] - 4],
3249
+ [point[0], point[1] + 4]
3250
+ ]
3251
+ : [
3252
+ [point[0] - 4, point[1]],
3253
+ [point[0] + 4, point[1]]
3254
+ ];
3255
+ }
3256
+
2786
3257
  function withMoving(board) {
2787
3258
  const { pointerDown, pointerMove, globalPointerUp, globalPointerMove } = board;
2788
3259
  let offsetX = 0;
@@ -2790,6 +3261,7 @@ function withMoving(board) {
2790
3261
  let isPreventDefault = false;
2791
3262
  let startPoint;
2792
3263
  let activeElements = [];
3264
+ let alignG = null;
2793
3265
  board.pointerDown = (event) => {
2794
3266
  const host = BOARD_TO_HOST.get(board);
2795
3267
  const point = transformPoint(board, toPoint(event.x, event.y, host));
@@ -2816,13 +3288,23 @@ function withMoving(board) {
2816
3288
  if (!isPreventDefault) {
2817
3289
  isPreventDefault = true;
2818
3290
  }
3291
+ alignG?.remove();
2819
3292
  const host = BOARD_TO_HOST.get(board);
2820
3293
  const endPoint = transformPoint(board, toPoint(event.x, event.y, host));
2821
3294
  offsetX = endPoint[0] - startPoint[0];
2822
3295
  offsetY = endPoint[1] - startPoint[1];
2823
- const offsetBuffer = 5;
2824
- if (Math.abs(offsetX) > offsetBuffer || Math.abs(offsetY) > offsetBuffer || getMovingElements(board).length > 0) {
3296
+ const tolerance = 5;
3297
+ if (Math.abs(offsetX) > tolerance || Math.abs(offsetY) > tolerance || getMovingElements(board).length > 0) {
2825
3298
  throttleRAF(() => {
3299
+ const activeElementsRectangle = getRectangleByElements(board, activeElements, true);
3300
+ activeElementsRectangle.x += offsetX;
3301
+ activeElementsRectangle.y += offsetY;
3302
+ const reactionManager = new AlignReaction(board, activeElements, activeElementsRectangle);
3303
+ const ref = reactionManager.handleAlign();
3304
+ offsetX -= ref.deltaX;
3305
+ offsetY -= ref.deltaY;
3306
+ alignG = ref.g;
3307
+ PlaitBoard.getElementActiveHost(board).append(alignG);
2826
3308
  handleTouchTarget(board);
2827
3309
  const currentElements = activeElements.map(activeElement => {
2828
3310
  const points = activeElement.points || [];
@@ -2864,6 +3346,7 @@ function withMoving(board) {
2864
3346
  globalPointerUp(event);
2865
3347
  };
2866
3348
  function cancelMove(board) {
3349
+ alignG?.remove();
2867
3350
  startPoint = null;
2868
3351
  offsetX = 0;
2869
3352
  offsetY = 0;
@@ -2899,10 +3382,10 @@ class PlaitIslandBaseComponent {
2899
3382
  markForCheck() {
2900
3383
  this.cdr.markForCheck();
2901
3384
  }
2902
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitIslandBaseComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); }
2903
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.3", type: PlaitIslandBaseComponent, host: { classAttribute: "plait-island-container" }, ngImport: i0 }); }
3385
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PlaitIslandBaseComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); }
3386
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: PlaitIslandBaseComponent, host: { classAttribute: "plait-island-container" }, ngImport: i0 }); }
2904
3387
  }
2905
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitIslandBaseComponent, decorators: [{
3388
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PlaitIslandBaseComponent, decorators: [{
2906
3389
  type: Directive,
2907
3390
  args: [{
2908
3391
  host: {
@@ -2935,10 +3418,10 @@ class PlaitIslandPopoverBaseComponent {
2935
3418
  this.subscription?.unsubscribe();
2936
3419
  this.islandOnDestroy();
2937
3420
  }
2938
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitIslandPopoverBaseComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); }
2939
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.3", type: PlaitIslandPopoverBaseComponent, inputs: { board: "board" }, host: { classAttribute: "plait-island-popover-container" }, ngImport: i0 }); }
3421
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PlaitIslandPopoverBaseComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); }
3422
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: PlaitIslandPopoverBaseComponent, inputs: { board: "board" }, host: { classAttribute: "plait-island-popover-container" }, ngImport: i0 }); }
2940
3423
  }
2941
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitIslandPopoverBaseComponent, decorators: [{
3424
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PlaitIslandPopoverBaseComponent, decorators: [{
2942
3425
  type: Directive,
2943
3426
  args: [{
2944
3427
  host: {
@@ -2977,11 +3460,13 @@ const withHotkey = (board) => {
2977
3460
  return false;
2978
3461
  }
2979
3462
  }, true);
2980
- Transforms.setSelectionWithTemporaryElements(board, elements);
3463
+ Transforms.addSelectionWithTemporaryElements(board, elements);
2981
3464
  return;
2982
3465
  }
2983
3466
  const selectedElements = getSelectedElements(board);
2984
- if (!PlaitBoard.isReadonly(board) && selectedElements.length > 0 && (hotkeys.isDeleteBackward(event) || hotkeys.isDeleteForward(event))) {
3467
+ if (!PlaitBoard.isReadonly(board) &&
3468
+ selectedElements.length > 0 &&
3469
+ (hotkeys.isDeleteBackward(event) || hotkeys.isDeleteForward(event))) {
2985
3470
  event.preventDefault();
2986
3471
  board.deleteFragment(null);
2987
3472
  }
@@ -3028,10 +3513,10 @@ class PlaitContextService {
3028
3513
  removeUploadingFile(fileEntry) {
3029
3514
  this.uploadingFiles = this.uploadingFiles.filter(file => file.url !== fileEntry.url);
3030
3515
  }
3031
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitContextService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3032
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitContextService }); }
3516
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PlaitContextService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3517
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PlaitContextService }); }
3033
3518
  }
3034
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitContextService, decorators: [{
3519
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PlaitContextService, decorators: [{
3035
3520
  type: Injectable
3036
3521
  }] });
3037
3522
 
@@ -3108,15 +3593,16 @@ class PlaitElementComponent {
3108
3593
  ngOnDestroy() {
3109
3594
  this.board.destroyElement(this.getContext());
3110
3595
  }
3111
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitElementComponent, deps: [{ token: i0.Renderer2 }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Component }); }
3112
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.3", 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 }); }
3596
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PlaitElementComponent, deps: [{ token: i0.Renderer2 }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Component }); }
3597
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: PlaitElementComponent, isStandalone: true, 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 }); }
3113
3598
  }
3114
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitElementComponent, decorators: [{
3599
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PlaitElementComponent, decorators: [{
3115
3600
  type: Component,
3116
3601
  args: [{
3117
3602
  selector: 'plait-element',
3118
3603
  template: '',
3119
- changeDetection: ChangeDetectionStrategy.OnPush
3604
+ changeDetection: ChangeDetectionStrategy.OnPush,
3605
+ standalone: true
3120
3606
  }]
3121
3607
  }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.ViewContainerRef }]; }, propDecorators: { index: [{
3122
3608
  type: Input
@@ -3132,7 +3618,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImpor
3132
3618
  type: Input
3133
3619
  }] } });
3134
3620
 
3135
- class PlaitChildrenElement {
3621
+ class PlaitChildrenElementComponent {
3136
3622
  constructor() {
3137
3623
  this.trackBy = (index, element) => {
3138
3624
  return element.id;
@@ -3146,8 +3632,8 @@ class PlaitChildrenElement {
3146
3632
  this.parentG = PlaitBoard.getElementHost(this.board);
3147
3633
  }
3148
3634
  }
3149
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitChildrenElement, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3150
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.3", type: PlaitChildrenElement, selector: "plait-children", inputs: { board: "board", parent: "parent", effect: "effect", parentG: "parentG" }, ngImport: i0, template: `
3635
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PlaitChildrenElementComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3636
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: PlaitChildrenElementComponent, isStandalone: true, selector: "plait-children", inputs: { board: "board", parent: "parent", effect: "effect", parentG: "parentG" }, ngImport: i0, template: `
3151
3637
  <plait-element
3152
3638
  *ngFor="let item of parent.children; let index = index; trackBy: trackBy"
3153
3639
  [index]="index"
@@ -3157,9 +3643,9 @@ class PlaitChildrenElement {
3157
3643
  [effect]="effect"
3158
3644
  [parentG]="parentG"
3159
3645
  ></plait-element>
3160
- `, 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"] }] }); }
3646
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: PlaitElementComponent, selector: "plait-element", inputs: ["index", "element", "parent", "board", "effect", "parentG"] }] }); }
3161
3647
  }
3162
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitChildrenElement, decorators: [{
3648
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PlaitChildrenElementComponent, decorators: [{
3163
3649
  type: Component,
3164
3650
  args: [{
3165
3651
  selector: 'plait-children',
@@ -3173,7 +3659,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImpor
3173
3659
  [effect]="effect"
3174
3660
  [parentG]="parentG"
3175
3661
  ></plait-element>
3176
- `
3662
+ `,
3663
+ standalone: true,
3664
+ imports: [NgFor, PlaitElementComponent]
3177
3665
  }]
3178
3666
  }], ctorParameters: function () { return []; }, propDecorators: { board: [{
3179
3667
  type: Input
@@ -3405,7 +3893,7 @@ class PlaitBoardComponent {
3405
3893
  const selectedElements = getSelectedElements(this.board);
3406
3894
  event.preventDefault();
3407
3895
  const rectangle = getRectangleByElements(this.board, selectedElements, false);
3408
- this.board.setFragment(event.clipboardData, rectangle);
3896
+ this.board.setFragment(event.clipboardData, rectangle, 'copy');
3409
3897
  });
3410
3898
  fromEvent(document, 'paste')
3411
3899
  .pipe(takeUntil(this.destroy$), filter(() => this.isFocused && !PlaitBoard.isReadonly(this.board) && !PlaitBoard.hasBeenTextEditing(this.board)))
@@ -3422,7 +3910,7 @@ class PlaitBoardComponent {
3422
3910
  const selectedElements = getSelectedElements(this.board);
3423
3911
  event.preventDefault();
3424
3912
  const rectangle = getRectangleByElements(this.board, selectedElements, false);
3425
- this.board.setFragment(event.clipboardData, rectangle);
3913
+ this.board.setFragment(event.clipboardData, rectangle, 'cut');
3426
3914
  this.board.deleteFragment(event.clipboardData);
3427
3915
  });
3428
3916
  }
@@ -3496,8 +3984,8 @@ class PlaitBoardComponent {
3496
3984
  this.updateIslands();
3497
3985
  });
3498
3986
  }
3499
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitBoardComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ViewContainerRef }, { token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
3500
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.3", type: PlaitBoardComponent, selector: "plait-board", inputs: { plaitValue: "plaitValue", plaitViewport: "plaitViewport", plaitPlugins: "plaitPlugins", plaitOptions: "plaitOptions", plaitTheme: "plaitTheme" }, outputs: { plaitChange: "plaitChange", plaitBoardInitialized: "plaitBoardInitialized" }, host: { properties: { "class": "this.hostClass", "class.readonly": "this.readonly", "class.focused": "this.isFocused", "class.disabled-scroll": "this.disabledScrollOnNonFocus" } }, providers: [PlaitContextService], queries: [{ propertyName: "islands", predicate: PlaitIslandBaseComponent, 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: `
3987
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PlaitBoardComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ViewContainerRef }, { token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
3988
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: PlaitBoardComponent, isStandalone: true, selector: "plait-board", inputs: { plaitValue: "plaitValue", plaitViewport: "plaitViewport", plaitPlugins: "plaitPlugins", plaitOptions: "plaitOptions", plaitTheme: "plaitTheme" }, outputs: { plaitChange: "plaitChange", plaitBoardInitialized: "plaitBoardInitialized" }, host: { properties: { "class": "this.hostClass", "class.readonly": "this.readonly", "class.focused": "this.isFocused", "class.disabled-scroll": "this.disabledScrollOnNonFocus" } }, providers: [PlaitContextService], queries: [{ propertyName: "islands", predicate: PlaitIslandBaseComponent, 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: `
3501
3989
  <div class="viewport-container" #viewportContainer>
3502
3990
  <svg #svg width="100%" height="100%" style="position: relative;" class="board-host-svg">
3503
3991
  <g class="element-host"></g>
@@ -3507,9 +3995,9 @@ class PlaitBoardComponent {
3507
3995
  <plait-children [board]="board" [effect]="effect"></plait-children>
3508
3996
  </div>
3509
3997
  <ng-content></ng-content>
3510
- `, isInline: true, dependencies: [{ kind: "component", type: PlaitChildrenElement, selector: "plait-children", inputs: ["board", "parent", "effect", "parentG"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3998
+ `, isInline: true, dependencies: [{ kind: "component", type: PlaitChildrenElementComponent, selector: "plait-children", inputs: ["board", "parent", "effect", "parentG"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3511
3999
  }
3512
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitBoardComponent, decorators: [{
4000
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PlaitBoardComponent, decorators: [{
3513
4001
  type: Component,
3514
4002
  args: [{
3515
4003
  selector: 'plait-board',
@@ -3525,7 +4013,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImpor
3525
4013
  <ng-content></ng-content>
3526
4014
  `,
3527
4015
  changeDetection: ChangeDetectionStrategy.OnPush,
3528
- providers: [PlaitContextService]
4016
+ providers: [PlaitContextService],
4017
+ standalone: true,
4018
+ imports: [PlaitChildrenElementComponent]
3529
4019
  }]
3530
4020
  }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.ViewContainerRef }, { type: i0.ElementRef }, { type: i0.NgZone }]; }, propDecorators: { plaitValue: [{
3531
4021
  type: Input
@@ -3564,21 +4054,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImpor
3564
4054
  args: [PlaitIslandBaseComponent, { descendants: true }]
3565
4055
  }] } });
3566
4056
 
3567
- const COMPONENTS = [PlaitBoardComponent, PlaitChildrenElement, PlaitElementComponent];
3568
- class PlaitModule {
3569
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
3570
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.3", ngImport: i0, type: PlaitModule, declarations: [PlaitBoardComponent, PlaitChildrenElement, PlaitElementComponent], imports: [CommonModule], exports: [PlaitBoardComponent, PlaitChildrenElement, PlaitElementComponent] }); }
3571
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitModule, imports: [CommonModule] }); }
3572
- }
3573
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitModule, decorators: [{
3574
- type: NgModule,
3575
- args: [{
3576
- declarations: [...COMPONENTS],
3577
- imports: [CommonModule],
3578
- exports: [...COMPONENTS]
3579
- }]
3580
- }] });
3581
-
3582
4057
  /**
3583
4058
  * 1.create board instance
3584
4059
  * 2.build fake node weak map
@@ -3747,5 +4222,5 @@ function createModModifierKeys() {
3747
4222
  * Generated bundle index. Do not edit.
3748
4223
  */
3749
4224
 
3750
- export { A, ACTIVE_STROKE_WIDTH, ALT, APOSTROPHE, ATTACHED_ELEMENT_CLASS_NAME, AT_SIGN, B, BACKSLASH, BACKSPACE, 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, CLIP_BOARD_FORMAT_KEY, CLOSE_SQUARE_BRACKET, COMMA, CONTEXT_MENU, CONTROL, ColorfulThemeColor, CoreTransforms, D, DASH, DELETE, DOWN_ARROW, DarkThemeColor, DefaultThemeColor, 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, HOME, HOST_CLASS_NAME, I, INSERT, IS_APPLE, IS_BOARD_CACHE, IS_CHROME, IS_CHROME_LEGACY, 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_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, PlaitChildrenElement, PlaitContextService, PlaitElement, PlaitElementComponent, PlaitHistoryBoard, PlaitIslandBaseComponent, PlaitIslandPopoverBaseComponent, PlaitModule, PlaitNode, PlaitOperation, PlaitPluginElementComponent, PlaitPluginKey, PlaitPointerType, Point, Q, QUESTION_MARK, R, RIGHT_ARROW, RectangleClient, ResizeCursorClass, RetroThemeColor, S, SAVING, SCROLL_BAR_WIDTH, SCROLL_LOCK, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, SEMICOLON, SEVEN, SHIFT, SINGLE_QUOTE, SIX, SLASH, SPACE, Selection, SoftThemeColor, StarryThemeColor, T, TAB, THREE, TILDE, TWO, ThemeColorMode, ThemeColors, Transforms, U, UP_ARROW, V, VOLUME_DOWN, VOLUME_UP, Viewport, W, X, Y, Z, ZERO, addMovingElements, addSelectedElement, arrowPoints, cacheMovingElements, cacheSelectedElements, clampZoomLevel, clearNodeWeakMap, clearSelectedElement, clearSelectionMoving, clearViewportOrigination, createFakeEvent, createForeignObject, createG, createKeyboardEvent, createMask, createModModifierKeys, createMouseEvent, createPath, createPointerEvent, createRect, createSVG, createSelectionOuterG, createTestingBoard, createText, createTouchEvent, debounce, deleteTemporaryElements, depthFirstRecursion, distanceBetweenPointAndPoint, distanceBetweenPointAndRectangle, distanceBetweenPointAndSegment, distanceBetweenPointAndSegments, downloadImage, drawArrow, drawBezierPath, drawCircle, drawLine, drawLinearPath, drawRectangle, drawRoundRectangle, fakeNodeWeakMap, findElements, getBoardRectangle, getClipboardByKey, getClipboardDataByMedia, getDataFromClipboard, getElementById, getElementHostBBox, getHitElementOfRoot, getHitElements, getIsRecursionFunc, getMovingElements, getNearestPointBetweenPointAndSegment, getNearestPointBetweenPointAndSegments, getRealScrollBarWidth, getRectangleByElements, getSelectedElements, getTemporaryElements, getTextFromClipboard, getViewBox, getViewBoxCenterPoint, getViewportContainerRect, getViewportOrigination, handleTouchTarget, hasBeforeContextChange, hasInputOrTextareaTarget, hasOnBoardChange, hasOnContextChanged, hotkeys, idCreator, initializeViewBox, initializeViewportContainer, initializeViewportOffset, inverse, isDOMElement, isDOMNode, isFromScrolling, isFromViewportChange, isHitElements, isInPlaitBoard, isLineHitLine, isMainPointer, isNullOrUndefined, isPointInEllipse, isPointInPolygon, isPointInRoundRectangle, isPolylineHitRectangle, isPreventTouchMove, isSecondaryPointer, isSelectedElement, isSelectionMoving, isSetViewportOperation, normalizePoint, preventTouchMove, removeMovingElements, removeSelectedElement, rotate, scrollToRectangle, setClipboardData, setClipboardDataByMedia, setClipboardDataByText, setIsFromScrolling, setIsFromViewportChange, setPathStrokeLinecap, setSVGViewBox, setSelectionMoving, setStrokeLinecap, shouldClear, shouldMerge, shouldSave, throttleRAF, toImage, toPoint, transformPoint, transformPoints, updateForeignObject, updateForeignObjectWidth, updateViewportContainerScroll, updateViewportOffset, updateViewportOrigination, withMoving, withOptions, withSelection };
4225
+ export { A, ACTIVE_STROKE_WIDTH, ALT, APOSTROPHE, ATTACHED_ELEMENT_CLASS_NAME, AT_SIGN, B, BACKSLASH, BACKSPACE, 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, CLIP_BOARD_FORMAT_KEY, CLOSE_SQUARE_BRACKET, COMMA, CONTEXT_MENU, CONTROL, ColorfulThemeColor, CoreTransforms, D, DASH, DELETE, DOWN_ARROW, DarkThemeColor, 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, HOME, HOST_CLASS_NAME, I, INSERT, IS_APPLE, IS_BOARD_CACHE, IS_CHROME, IS_CHROME_LEGACY, 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_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, PlaitChildrenElementComponent, PlaitContextService, PlaitElement, PlaitElementComponent, PlaitHistoryBoard, PlaitIslandBaseComponent, PlaitIslandPopoverBaseComponent, PlaitNode, PlaitOperation, PlaitPluginElementComponent, PlaitPluginKey, PlaitPointerType, Point, Q, QUESTION_MARK, R, RIGHT_ARROW, RectangleClient, ResizeCursorClass, RetroThemeColor, S, SAVING, SCROLL_BAR_WIDTH, SCROLL_LOCK, SELECTION_BORDER_COLOR, SELECTION_FILL_COLOR, SELECTION_RECTANGLE_CLASS_NAME, SEMICOLON, SEVEN, SHIFT, SINGLE_QUOTE, SIX, SLASH, SPACE, Selection, SoftThemeColor, StarryThemeColor, T, TAB, THREE, TILDE, TWO, ThemeColorMode, ThemeColors, Transforms, U, UP_ARROW, V, VOLUME_DOWN, VOLUME_UP, Viewport, W, X, Y, Z, ZERO, addMovingElements, addSelectedElement, arrowPoints, cacheMovingElements, cacheSelectedElements, clampZoomLevel, clearNodeWeakMap, clearSelectedElement, clearSelectionMoving, clearViewportOrigination, createFakeEvent, createForeignObject, createG, createKeyboardEvent, createMask, createModModifierKeys, createMouseEvent, createPath, createPointerEvent, createRect, createSVG, createSelectionRectangleG, createTestingBoard, createText, createTouchEvent, debounce, deleteTemporaryElements, depthFirstRecursion, distanceBetweenPointAndPoint, distanceBetweenPointAndRectangle, distanceBetweenPointAndSegment, distanceBetweenPointAndSegments, downloadImage, drawArrow, drawBezierPath, drawCircle, drawLine, drawLinearPath, drawRectangle, drawRoundRectangle, fakeNodeWeakMap, findElements, getBoardRectangle, getClipboardByKey, getClipboardDataByMedia, getDataFromClipboard, getElementById, getElementHostBBox, getHitElementOfRoot, getHitElements, getIsRecursionFunc, getMovingElements, getNearestPointBetweenPointAndSegment, getNearestPointBetweenPointAndSegments, getRealScrollBarWidth, getRectangleByElements, getSelectedElements, getTemporaryElements, getTemporaryRef, getTextFromClipboard, getViewBox, getViewBoxCenterPoint, getViewportContainerRect, getViewportOrigination, handleTouchTarget, hasBeforeContextChange, hasInputOrTextareaTarget, hasOnBoardChange, hasOnContextChanged, hotkeys, idCreator, initializeViewBox, initializeViewportContainer, initializeViewportOffset, inverse, isDOMElement, isDOMNode, isFromScrolling, isFromViewportChange, isHitElements, isInPlaitBoard, isLineHitLine, isMainPointer, isNullOrUndefined, isPointInEllipse, isPointInPolygon, isPointInRoundRectangle, isPolylineHitRectangle, isPreventTouchMove, isSecondaryPointer, isSelectedElement, isSelectionMoving, isSetViewportOperation, normalizePoint, preventTouchMove, removeMovingElements, removeSelectedElement, rotate, scrollToRectangle, setClipboardData, setClipboardDataByMedia, setClipboardDataByText, setIsFromScrolling, setIsFromViewportChange, setPathStrokeLinecap, setSVGViewBox, setSelectionMoving, setStrokeLinecap, shouldClear, shouldMerge, shouldSave, throttleRAF, toImage, toPoint, transformPoint, transformPoints, updateForeignObject, updateForeignObjectWidth, updateViewportContainerScroll, updateViewportOffset, updateViewportOrigination, withMoving, withOptions, withSelection };
3751
4226
  //# sourceMappingURL=plait-core.mjs.map