@plait/core 0.24.0-next.8 → 0.28.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 +9 -7
  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 +4 -3
  11. package/esm2022/interfaces/board.mjs +1 -1
  12. package/esm2022/interfaces/direction.mjs +8 -0
  13. package/esm2022/interfaces/index.mjs +2 -1
  14. package/esm2022/interfaces/plugin-key.mjs +1 -1
  15. package/esm2022/interfaces/point.mjs +1 -1
  16. package/esm2022/interfaces/rectangle-client.mjs +4 -1
  17. package/esm2022/interfaces/viewport.mjs +2 -2
  18. package/esm2022/plugins/create-board.mjs +10 -9
  19. package/esm2022/plugins/with-hotkey.mjs +5 -3
  20. package/esm2022/plugins/with-moving.mjs +17 -4
  21. package/esm2022/plugins/with-options.mjs +1 -1
  22. package/esm2022/plugins/with-selection.mjs +37 -25
  23. package/esm2022/public-api.mjs +1 -2
  24. package/esm2022/testing/core/fake-weak-map.mjs +2 -2
  25. package/esm2022/testing/core/index.mjs +1 -1
  26. package/esm2022/testing/fake-events/event-objects.mjs +1 -1
  27. package/esm2022/testing/fake-events/index.mjs +1 -1
  28. package/esm2022/testing/index.mjs +1 -1
  29. package/esm2022/testing/test-element.mjs +1 -1
  30. package/esm2022/transforms/element.mjs +4 -4
  31. package/esm2022/transforms/selection.mjs +16 -6
  32. package/esm2022/utils/board.mjs +1 -1
  33. package/esm2022/utils/draw/line.mjs +2 -1
  34. package/esm2022/utils/draw/rectangle.mjs +1 -1
  35. package/esm2022/utils/element.mjs +3 -3
  36. package/esm2022/utils/reaction-manager.mjs +370 -0
  37. package/esm2022/utils/to-image.mjs +106 -34
  38. package/esm2022/utils/touch.mjs +3 -3
  39. package/esm2022/utils/tree.mjs +2 -2
  40. package/esm2022/utils/weak-maps.mjs +1 -1
  41. package/fesm2022/plait-core.mjs +732 -256
  42. package/fesm2022/plait-core.mjs.map +1 -1
  43. package/interfaces/board.d.ts +2 -1
  44. package/interfaces/direction.d.ts +7 -0
  45. package/interfaces/index.d.ts +1 -0
  46. package/interfaces/rectangle-client.d.ts +6 -0
  47. package/package.json +3 -2
  48. package/plugins/with-selection.d.ts +5 -1
  49. package/public-api.d.ts +0 -1
  50. package/styles/styles.scss +1 -1
  51. package/testing/core/fake-weak-map.d.ts +2 -2
  52. package/transforms/element.d.ts +2 -2
  53. package/transforms/selection.d.ts +2 -2
  54. package/utils/reaction-manager.d.ts +41 -0
  55. package/utils/to-image.d.ts +11 -0
  56. package/utils/touch.d.ts +1 -1
  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';
@@ -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
 
@@ -1014,6 +1017,7 @@ function drawLinearPath(points, options, closePath) {
1014
1017
  path.setAttribute('stroke', `${options?.stroke}`);
1015
1018
  path.setAttribute('stroke-width', `${options?.strokeWidth}`);
1016
1019
  path.setAttribute('fill', `${options?.fill || 'none'}`);
1020
+ options?.strokeLineDash && path.setAttribute('stroke-dasharray', `${options.strokeLineDash}`);
1017
1021
  g.appendChild(path);
1018
1022
  return g;
1019
1023
  }
@@ -1240,6 +1244,68 @@ const cacheMovingElements = (board, elements) => {
1240
1244
  BOARD_TO_MOVING_ELEMENT.set(board, elements);
1241
1245
  };
1242
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
+ */
1243
1309
  function cloneCSSStyle(nativeNode, clonedNode) {
1244
1310
  const targetStyle = clonedNode.style;
1245
1311
  if (!targetStyle) {
@@ -1257,25 +1323,13 @@ function cloneCSSStyle(nativeNode, clonedNode) {
1257
1323
  });
1258
1324
  }
1259
1325
  }
1260
- function createCanvas(width, height, fillStyle) {
1261
- const canvas = document.createElement('canvas');
1262
- const ctx = canvas.getContext('2d');
1263
- canvas.width = width;
1264
- canvas.height = height;
1265
- canvas.style.width = `${width}px`;
1266
- canvas.style.height = `${height}px`;
1267
- ctx.strokeStyle = '#ffffff';
1268
- ctx.fillStyle = fillStyle;
1269
- ctx.fillRect(0, 0, width, height);
1270
- return {
1271
- canvas,
1272
- ctx
1273
- };
1274
- }
1275
- function isElementNode(node) {
1276
- return node.nodeType === Node.ELEMENT_NODE;
1277
- }
1278
- 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) {
1279
1333
  const elementHostBox = getRectangleByElements(board, board.children, true);
1280
1334
  const { width, height, x, y } = elementHostBox;
1281
1335
  const { padding = 4, inlineStyleClassNames } = options;
@@ -1288,8 +1342,9 @@ function cloneSvg(board, options) {
1288
1342
  cloneSvgElement.setAttribute('height', `${height}`);
1289
1343
  cloneSvgElement.setAttribute('viewBox', [x - padding, y - padding, width + 2 * padding, height + 2 * padding].join(','));
1290
1344
  if (inlineStyleClassNames) {
1291
- const sourceNodes = Array.from(sourceSvg.querySelectorAll(inlineStyleClassNames));
1292
- 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));
1293
1348
  sourceNodes.forEach((node, index) => {
1294
1349
  const cloneNode = cloneNodes[index];
1295
1350
  const childElements = Array.from(node.querySelectorAll('*')).filter(isElementNode);
@@ -1297,21 +1352,38 @@ function cloneSvg(board, options) {
1297
1352
  sourceNodes.push(...childElements);
1298
1353
  cloneNodes.push(...cloneChildElements);
1299
1354
  });
1300
- sourceNodes.forEach((node, index) => {
1355
+ // processing styles
1356
+ sourceNodes.map((node, index) => {
1301
1357
  const cloneNode = cloneNodes[index];
1302
1358
  cloneCSSStyle(node, cloneNode);
1303
1359
  });
1304
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
+ }));
1305
1379
  return cloneSvgElement;
1306
1380
  }
1307
- function loadImage(src) {
1308
- return new Promise((resolve, reject) => {
1309
- const img = new Image();
1310
- img.onload = () => resolve(img);
1311
- img.onerror = () => reject(new Error('Failed to load image'));
1312
- img.src = src;
1313
- });
1314
- }
1381
+ /**
1382
+ * current board transfer pictures
1383
+ * @param board board
1384
+ * @param options parameter configuration
1385
+ * @returns images in the specified format base64
1386
+ */
1315
1387
  async function toImage(board, options) {
1316
1388
  if (!board) {
1317
1389
  return undefined;
@@ -1321,21 +1393,25 @@ async function toImage(board, options) {
1321
1393
  const { width, height } = elementHostBox;
1322
1394
  const ratioWidth = width * ratio;
1323
1395
  const ratioHeight = height * ratio;
1324
- const cloneSvgElement = cloneSvg(board, options);
1396
+ const cloneSvgElement = await cloneSvg(board, options);
1325
1397
  const { canvas, ctx } = createCanvas(ratioWidth, ratioHeight, fillStyle);
1326
1398
  const svgStr = new XMLSerializer().serializeToString(cloneSvgElement);
1327
1399
  const imgSrc = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgStr)}`;
1328
1400
  try {
1329
1401
  const img = await loadImage(imgSrc);
1330
1402
  ctx.drawImage(img, 0, 0, ratioWidth, ratioHeight);
1331
- const url = canvas.toDataURL('image/png');
1332
- return url;
1403
+ return canvas.toDataURL('image/png');
1333
1404
  }
1334
1405
  catch (error) {
1335
1406
  console.error('Error converting SVG to image:', error);
1336
1407
  return undefined;
1337
1408
  }
1338
1409
  }
1410
+ /**
1411
+ * download the file with the specified name
1412
+ * @param url download url
1413
+ * @param name file name
1414
+ */
1339
1415
  function downloadImage(url, name) {
1340
1416
  const a = document.createElement('a');
1341
1417
  a.href = url;
@@ -1394,7 +1470,7 @@ const isPreventTouchMove = (board) => {
1394
1470
  };
1395
1471
  const preventTouchMove = (board, event, state) => {
1396
1472
  if (state && (event.target instanceof HTMLElement || event.target instanceof SVGElement)) {
1397
- BOARD_TO_TOUCH_REF.set(board, { state, target: event.target });
1473
+ BOARD_TO_TOUCH_REF.set(board, { state, target: event.target instanceof SVGElement ? event.target : undefined });
1398
1474
  }
1399
1475
  else {
1400
1476
  const ref = BOARD_TO_TOUCH_REF.get(board);
@@ -1412,7 +1488,7 @@ const preventTouchMove = (board, event, state) => {
1412
1488
  */
1413
1489
  const handleTouchTarget = (board) => {
1414
1490
  const touchRef = BOARD_TO_TOUCH_REF.get(board);
1415
- if (touchRef && !touchRef.target.contains(PlaitBoard.getElementActiveHost(board))) {
1491
+ if (touchRef && touchRef.target && !touchRef.target.contains(PlaitBoard.getElementActiveHost(board))) {
1416
1492
  touchRef.target.style.opacity = '0';
1417
1493
  const host = createG();
1418
1494
  host.appendChild(touchRef.target);
@@ -1754,7 +1830,7 @@ const Point = {
1754
1830
  const Viewport = {
1755
1831
  isViewport: (value) => {
1756
1832
  return !isNullOrUndefined(value.zoom) && !isNullOrUndefined(value.viewBackgroundColor);
1757
- },
1833
+ }
1758
1834
  };
1759
1835
 
1760
1836
  const SAVING = new WeakMap();
@@ -1813,6 +1889,14 @@ const ThemeColors = [
1813
1889
  StarryThemeColor
1814
1890
  ];
1815
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
+
1816
1900
  function getRectangleByElements(board, elements, recursion) {
1817
1901
  const boundaryBox = {
1818
1902
  left: Number.MAX_VALUE,
@@ -1860,9 +1944,9 @@ function getBoardRectangle(board) {
1860
1944
  }
1861
1945
  function getElementById(board, id, dataSource) {
1862
1946
  if (!dataSource) {
1863
- dataSource = findElements(board, { match: (element) => true, recursion: (element) => true });
1947
+ dataSource = findElements(board, { match: element => true, recursion: element => true });
1864
1948
  }
1865
- let element = dataSource.find((element) => element.id === id);
1949
+ let element = dataSource.find(element => element.id === id);
1866
1950
  return element;
1867
1951
  }
1868
1952
  function findElements(board, options) {
@@ -2154,19 +2238,209 @@ const NodeTransforms = {
2154
2238
  moveNode
2155
2239
  };
2156
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
+
2157
2422
  function setSelection(board, selection) {
2158
2423
  const operation = { type: 'set_selection', properties: board.selection, newProperties: selection };
2159
2424
  board.apply(operation);
2160
2425
  }
2161
2426
  const SelectionTransforms = {
2162
2427
  setSelection,
2163
- setSelectionWithTemporaryElements
2428
+ addSelectionWithTemporaryElements
2164
2429
  };
2165
- function setSelectionWithTemporaryElements(board, elements) {
2166
- setTimeout(() => {
2167
- BOARD_TO_TEMPORARY_ELEMENTS.set(board, elements);
2430
+ function addSelectionWithTemporaryElements(board, elements) {
2431
+ const timeoutId = setTimeout(() => {
2168
2432
  setSelection(board, { ranges: [] });
2169
- });
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
+ }
2170
2444
  }
2171
2445
 
2172
2446
  function setViewport(board, viewport) {
@@ -2423,14 +2697,15 @@ function createBoard(children, options) {
2423
2697
  isMovable: element => false,
2424
2698
  getRectangle: element => null,
2425
2699
  applyTheme: (element) => { },
2426
- pointerDown: (pointer) => { },
2427
- pointerMove: (pointer) => { },
2428
- pointerUp: (pointer) => { },
2429
- pointerCancel: (pointer) => { },
2430
- pointerOut: (pointer) => { },
2431
- pointerLeave: (pointer) => { },
2432
- globalPointerMove: (pointer) => { },
2433
- 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 => { }
2434
2709
  };
2435
2710
  return board;
2436
2711
  }
@@ -2585,175 +2860,6 @@ function withHandPointer(board) {
2585
2860
  return board;
2586
2861
  }
2587
2862
 
2588
- function withSelection(board) {
2589
- const { pointerDown, globalPointerMove, globalPointerUp, onChange } = board;
2590
- let start = null;
2591
- let end = null;
2592
- let selectionMovingG;
2593
- let selectionOuterG;
2594
- let previousSelectedElements;
2595
- // prevent text from being selected when user pressed main pointer and is moving
2596
- let needPreventNativeSelectionWhenMoving = false;
2597
- board.pointerDown = (event) => {
2598
- if (event.target instanceof Element && !event.target.closest('.plait-richtext-container')) {
2599
- needPreventNativeSelectionWhenMoving = true;
2600
- }
2601
- if (!isMainPointer(event)) {
2602
- pointerDown(event);
2603
- return;
2604
- }
2605
- const options = board.getPluginOptions(PlaitPluginKey.withSelection);
2606
- const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
2607
- const range = { anchor: point, focus: point };
2608
- const hitElements = getHitElements(board, { ranges: [range] });
2609
- const selectedElements = getSelectedElements(board);
2610
- if (hitElements.length === 1 && selectedElements.includes(hitElements[0]) && !options.isDisabledSelect) {
2611
- pointerDown(event);
2612
- return;
2613
- }
2614
- if (PlaitBoard.isPointer(board, PlaitPointerType.selection) &&
2615
- hitElements.length === 0 &&
2616
- options.isMultiple &&
2617
- !options.isDisabledSelect) {
2618
- start = point;
2619
- preventTouchMove(board, event, true);
2620
- }
2621
- Transforms.setSelection(board, { ranges: [range] });
2622
- pointerDown(event);
2623
- };
2624
- board.globalPointerMove = (event) => {
2625
- if (needPreventNativeSelectionWhenMoving) {
2626
- // prevent text from being selected
2627
- event.preventDefault();
2628
- }
2629
- if (start) {
2630
- const movedTarget = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
2631
- const rectangle = RectangleClient.toRectangleClient([start, movedTarget]);
2632
- selectionMovingG?.remove();
2633
- if (Math.hypot(rectangle.width, rectangle.height) > 5) {
2634
- end = movedTarget;
2635
- throttleRAF(() => {
2636
- if (start && end) {
2637
- Transforms.setSelection(board, { ranges: [{ anchor: start, focus: end }] });
2638
- }
2639
- });
2640
- setSelectionMoving(board);
2641
- selectionMovingG = drawRectangle(board, rectangle, {
2642
- stroke: SELECTION_BORDER_COLOR,
2643
- strokeWidth: 1,
2644
- fill: SELECTION_FILL_COLOR,
2645
- fillStyle: 'solid'
2646
- });
2647
- PlaitBoard.getHost(board).append(selectionMovingG);
2648
- }
2649
- }
2650
- globalPointerMove(event);
2651
- };
2652
- board.globalPointerUp = (event) => {
2653
- if (start && end) {
2654
- selectionMovingG?.remove();
2655
- clearSelectionMoving(board);
2656
- Transforms.setSelection(board, { ranges: [{ anchor: start, focus: end }] });
2657
- }
2658
- if (PlaitBoard.isFocus(board)) {
2659
- const isInBoard = event.target instanceof Node && PlaitBoard.getBoardContainer(board).contains(event.target);
2660
- const isInDocument = event.target instanceof Node && document.contains(event.target);
2661
- const isAttachedElement = event.target instanceof Element && event.target.closest(`.${ATTACHED_ELEMENT_CLASS_NAME}`);
2662
- // Clear selection when mouse board outside area
2663
- // The framework needs to determine whether the board is focused through selection
2664
- if (!isInBoard && !start && !isAttachedElement && isInDocument) {
2665
- Transforms.setSelection(board, null);
2666
- }
2667
- }
2668
- start = null;
2669
- end = null;
2670
- needPreventNativeSelectionWhenMoving = false;
2671
- preventTouchMove(board, event, false);
2672
- globalPointerUp(event);
2673
- };
2674
- board.onChange = () => {
2675
- const options = board.getPluginOptions(PlaitPluginKey.withSelection);
2676
- if (options.isDisabledSelect) {
2677
- selectionOuterG?.remove();
2678
- clearSelectedElement(board);
2679
- }
2680
- // calc selected elements entry
2681
- if (board.pointer !== PlaitPointerType.hand && !options.isDisabledSelect) {
2682
- try {
2683
- if (board.operations.find(value => value.type === 'set_selection')) {
2684
- selectionOuterG?.remove();
2685
- const temporaryElements = getTemporaryElements(board);
2686
- let elements = temporaryElements ? temporaryElements : getHitElements(board);
2687
- if (!options.isMultiple && elements.length > 1) {
2688
- elements = [elements[0]];
2689
- }
2690
- cacheSelectedElements(board, elements);
2691
- previousSelectedElements = elements;
2692
- const { width, height } = getRectangleByElements(board, elements, false);
2693
- if (width > 0 && height > 0 && elements.length > 1) {
2694
- selectionOuterG = createSelectionOuterG(board, elements);
2695
- selectionOuterG.classList.add('selection-outer');
2696
- PlaitBoard.getHost(board).append(selectionOuterG);
2697
- }
2698
- deleteTemporaryElements(board);
2699
- }
2700
- else {
2701
- // wait node destroy and remove selected element state
2702
- setTimeout(() => {
2703
- const currentSelectedElements = getSelectedElements(board);
2704
- if (currentSelectedElements.length && currentSelectedElements.length > 1) {
2705
- const selectedElementChange = currentSelectedElements.some(item => !previousSelectedElements.includes(item));
2706
- if (selectedElementChange) {
2707
- selectionOuterG?.remove();
2708
- selectionOuterG = createSelectionOuterG(board, currentSelectedElements);
2709
- selectionOuterG.classList.add('selection-outer');
2710
- PlaitBoard.getHost(board).append(selectionOuterG);
2711
- }
2712
- }
2713
- else {
2714
- selectionOuterG?.remove();
2715
- }
2716
- });
2717
- }
2718
- }
2719
- catch (error) {
2720
- console.error(error);
2721
- }
2722
- }
2723
- onChange();
2724
- };
2725
- board.setPluginOptions(PlaitPluginKey.withSelection, {
2726
- isMultiple: true,
2727
- isDisabledSelect: false
2728
- });
2729
- return board;
2730
- }
2731
- function getTemporaryElements(board) {
2732
- return BOARD_TO_TEMPORARY_ELEMENTS.get(board);
2733
- }
2734
- function deleteTemporaryElements(board) {
2735
- BOARD_TO_TEMPORARY_ELEMENTS.delete(board);
2736
- }
2737
- function isSelectionMoving(board) {
2738
- return !!BOARD_TO_IS_SELECTION_MOVING.get(board);
2739
- }
2740
- function setSelectionMoving(board) {
2741
- PlaitBoard.getBoardContainer(board).classList.add('selection-moving');
2742
- BOARD_TO_IS_SELECTION_MOVING.set(board, true);
2743
- }
2744
- function clearSelectionMoving(board) {
2745
- PlaitBoard.getBoardContainer(board).classList.remove('selection-moving');
2746
- BOARD_TO_IS_SELECTION_MOVING.delete(board);
2747
- }
2748
- function createSelectionOuterG(board, selectElements) {
2749
- const rectangle = getRectangleByElements(board, selectElements, false);
2750
- return drawRectangle(board, RectangleClient.inflate(rectangle, ACTIVE_STROKE_WIDTH), {
2751
- stroke: SELECTION_BORDER_COLOR,
2752
- strokeWidth: ACTIVE_STROKE_WIDTH,
2753
- fillStyle: 'solid'
2754
- });
2755
- }
2756
-
2757
2863
  function withViewport(board) {
2758
2864
  const { onChange } = board;
2759
2865
  const throttleUpdate = debounce(() => {
@@ -2782,6 +2888,372 @@ function withViewport(board) {
2782
2888
  return board;
2783
2889
  }
2784
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
+
2785
3257
  function withMoving(board) {
2786
3258
  const { pointerDown, pointerMove, globalPointerUp, globalPointerMove } = board;
2787
3259
  let offsetX = 0;
@@ -2789,6 +3261,7 @@ function withMoving(board) {
2789
3261
  let isPreventDefault = false;
2790
3262
  let startPoint;
2791
3263
  let activeElements = [];
3264
+ let alignG = null;
2792
3265
  board.pointerDown = (event) => {
2793
3266
  const host = BOARD_TO_HOST.get(board);
2794
3267
  const point = transformPoint(board, toPoint(event.x, event.y, host));
@@ -2815,13 +3288,23 @@ function withMoving(board) {
2815
3288
  if (!isPreventDefault) {
2816
3289
  isPreventDefault = true;
2817
3290
  }
3291
+ alignG?.remove();
2818
3292
  const host = BOARD_TO_HOST.get(board);
2819
3293
  const endPoint = transformPoint(board, toPoint(event.x, event.y, host));
2820
3294
  offsetX = endPoint[0] - startPoint[0];
2821
3295
  offsetY = endPoint[1] - startPoint[1];
2822
- const offsetBuffer = 5;
2823
- 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) {
2824
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);
2825
3308
  handleTouchTarget(board);
2826
3309
  const currentElements = activeElements.map(activeElement => {
2827
3310
  const points = activeElement.points || [];
@@ -2863,6 +3346,7 @@ function withMoving(board) {
2863
3346
  globalPointerUp(event);
2864
3347
  };
2865
3348
  function cancelMove(board) {
3349
+ alignG?.remove();
2866
3350
  startPoint = null;
2867
3351
  offsetX = 0;
2868
3352
  offsetY = 0;
@@ -2976,11 +3460,13 @@ const withHotkey = (board) => {
2976
3460
  return false;
2977
3461
  }
2978
3462
  }, true);
2979
- Transforms.setSelectionWithTemporaryElements(board, elements);
3463
+ Transforms.addSelectionWithTemporaryElements(board, elements);
2980
3464
  return;
2981
3465
  }
2982
3466
  const selectedElements = getSelectedElements(board);
2983
- 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))) {
2984
3470
  event.preventDefault();
2985
3471
  board.deleteFragment(null);
2986
3472
  }
@@ -3108,14 +3594,15 @@ class PlaitElementComponent {
3108
3594
  this.board.destroyElement(this.getContext());
3109
3595
  }
3110
3596
  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 }); }
3111
- 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 }); }
3597
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.3", 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 }); }
3112
3598
  }
3113
3599
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitElementComponent, decorators: [{
3114
3600
  type: Component,
3115
3601
  args: [{
3116
3602
  selector: 'plait-element',
3117
3603
  template: '',
3118
- changeDetection: ChangeDetectionStrategy.OnPush
3604
+ changeDetection: ChangeDetectionStrategy.OnPush,
3605
+ standalone: true
3119
3606
  }]
3120
3607
  }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.ViewContainerRef }]; }, propDecorators: { index: [{
3121
3608
  type: Input
@@ -3131,7 +3618,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImpor
3131
3618
  type: Input
3132
3619
  }] } });
3133
3620
 
3134
- class PlaitChildrenElement {
3621
+ class PlaitChildrenElementComponent {
3135
3622
  constructor() {
3136
3623
  this.trackBy = (index, element) => {
3137
3624
  return element.id;
@@ -3145,8 +3632,8 @@ class PlaitChildrenElement {
3145
3632
  this.parentG = PlaitBoard.getElementHost(this.board);
3146
3633
  }
3147
3634
  }
3148
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitChildrenElement, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3149
- 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.3", ngImport: i0, type: PlaitChildrenElementComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3636
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.3", type: PlaitChildrenElementComponent, isStandalone: true, selector: "plait-children", inputs: { board: "board", parent: "parent", effect: "effect", parentG: "parentG" }, ngImport: i0, template: `
3150
3637
  <plait-element
3151
3638
  *ngFor="let item of parent.children; let index = index; trackBy: trackBy"
3152
3639
  [index]="index"
@@ -3156,9 +3643,9 @@ class PlaitChildrenElement {
3156
3643
  [effect]="effect"
3157
3644
  [parentG]="parentG"
3158
3645
  ></plait-element>
3159
- `, 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"] }] }); }
3160
3647
  }
3161
- 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.3", ngImport: i0, type: PlaitChildrenElementComponent, decorators: [{
3162
3649
  type: Component,
3163
3650
  args: [{
3164
3651
  selector: 'plait-children',
@@ -3172,7 +3659,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImpor
3172
3659
  [effect]="effect"
3173
3660
  [parentG]="parentG"
3174
3661
  ></plait-element>
3175
- `
3662
+ `,
3663
+ standalone: true,
3664
+ imports: [NgFor, PlaitElementComponent]
3176
3665
  }]
3177
3666
  }], ctorParameters: function () { return []; }, propDecorators: { board: [{
3178
3667
  type: Input
@@ -3404,7 +3893,7 @@ class PlaitBoardComponent {
3404
3893
  const selectedElements = getSelectedElements(this.board);
3405
3894
  event.preventDefault();
3406
3895
  const rectangle = getRectangleByElements(this.board, selectedElements, false);
3407
- this.board.setFragment(event.clipboardData, rectangle);
3896
+ this.board.setFragment(event.clipboardData, rectangle, 'copy');
3408
3897
  });
3409
3898
  fromEvent(document, 'paste')
3410
3899
  .pipe(takeUntil(this.destroy$), filter(() => this.isFocused && !PlaitBoard.isReadonly(this.board) && !PlaitBoard.hasBeenTextEditing(this.board)))
@@ -3421,7 +3910,7 @@ class PlaitBoardComponent {
3421
3910
  const selectedElements = getSelectedElements(this.board);
3422
3911
  event.preventDefault();
3423
3912
  const rectangle = getRectangleByElements(this.board, selectedElements, false);
3424
- this.board.setFragment(event.clipboardData, rectangle);
3913
+ this.board.setFragment(event.clipboardData, rectangle, 'cut');
3425
3914
  this.board.deleteFragment(event.clipboardData);
3426
3915
  });
3427
3916
  }
@@ -3496,7 +3985,7 @@ class PlaitBoardComponent {
3496
3985
  });
3497
3986
  }
3498
3987
  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 }); }
3499
- 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: `
3988
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.3", 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: `
3500
3989
  <div class="viewport-container" #viewportContainer>
3501
3990
  <svg #svg width="100%" height="100%" style="position: relative;" class="board-host-svg">
3502
3991
  <g class="element-host"></g>
@@ -3506,7 +3995,7 @@ class PlaitBoardComponent {
3506
3995
  <plait-children [board]="board" [effect]="effect"></plait-children>
3507
3996
  </div>
3508
3997
  <ng-content></ng-content>
3509
- `, 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 }); }
3510
3999
  }
3511
4000
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitBoardComponent, decorators: [{
3512
4001
  type: Component,
@@ -3524,7 +4013,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImpor
3524
4013
  <ng-content></ng-content>
3525
4014
  `,
3526
4015
  changeDetection: ChangeDetectionStrategy.OnPush,
3527
- providers: [PlaitContextService]
4016
+ providers: [PlaitContextService],
4017
+ standalone: true,
4018
+ imports: [PlaitChildrenElementComponent]
3528
4019
  }]
3529
4020
  }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.ViewContainerRef }, { type: i0.ElementRef }, { type: i0.NgZone }]; }, propDecorators: { plaitValue: [{
3530
4021
  type: Input
@@ -3563,21 +4054,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImpor
3563
4054
  args: [PlaitIslandBaseComponent, { descendants: true }]
3564
4055
  }] } });
3565
4056
 
3566
- const COMPONENTS = [PlaitBoardComponent, PlaitChildrenElement, PlaitElementComponent];
3567
- class PlaitModule {
3568
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
3569
- 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] }); }
3570
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitModule, imports: [CommonModule] }); }
3571
- }
3572
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.3", ngImport: i0, type: PlaitModule, decorators: [{
3573
- type: NgModule,
3574
- args: [{
3575
- declarations: [...COMPONENTS],
3576
- imports: [CommonModule],
3577
- exports: [...COMPONENTS]
3578
- }]
3579
- }] });
3580
-
3581
4057
  /**
3582
4058
  * 1.create board instance
3583
4059
  * 2.build fake node weak map
@@ -3746,5 +4222,5 @@ function createModModifierKeys() {
3746
4222
  * Generated bundle index. Do not edit.
3747
4223
  */
3748
4224
 
3749
- 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 };
3750
4226
  //# sourceMappingURL=plait-core.mjs.map