fabric 6.0.0-beta6 → 6.0.0-beta7

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 (81) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/fabric.d.ts +2 -0
  3. package/dist/index.js +287 -226
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.min.js +1 -1
  6. package/dist/index.mjs +287 -227
  7. package/dist/index.mjs.map +1 -1
  8. package/dist/index.node.cjs +287 -226
  9. package/dist/index.node.cjs.map +1 -1
  10. package/dist/index.node.mjs +287 -227
  11. package/dist/index.node.mjs.map +1 -1
  12. package/dist/src/canvas/Canvas.d.ts +0 -1
  13. package/dist/src/canvas/StaticCanvas.d.ts +1 -5
  14. package/dist/src/canvas/TextEditingManager.d.ts +4 -0
  15. package/dist/src/constants.d.ts +6 -0
  16. package/dist/src/controls/Control.d.ts +1 -0
  17. package/dist/src/filters/BlendImage.d.ts +1 -1
  18. package/dist/src/filters/FilterBackend.d.ts +1 -0
  19. package/dist/src/filters/WebGLFilterBackend.d.ts +7 -5
  20. package/dist/src/filters/index.d.ts +1 -1
  21. package/dist/src/filters/typedefs.d.ts +1 -1
  22. package/dist/src/shapes/IText/IText.d.ts +1 -1
  23. package/dist/src/shapes/IText/ITextKeyBehavior.d.ts +0 -1
  24. package/dist/src/shapes/Image.d.ts +2 -2
  25. package/dist/src/shapes/Object/InteractiveObject.d.ts +1 -1
  26. package/dist/src/shapes/Object/Object.d.ts +1 -1
  27. package/dist/src/shapes/Path.d.ts +1 -1
  28. package/dist/src/shapes/Text/StyledText.d.ts +11 -9
  29. package/dist/src/shapes/Text/constants.d.ts +7 -1
  30. package/dist/src/shapes/Textbox.d.ts +1 -1
  31. package/fabric.ts +6 -0
  32. package/package.json +1 -1
  33. package/rollup.config.mjs +9 -0
  34. package/src/brushes/CircleBrush.ts +3 -2
  35. package/src/brushes/SprayBrush.ts +3 -2
  36. package/src/canvas/Canvas.ts +5 -9
  37. package/src/canvas/SelectableCanvas.ts +13 -12
  38. package/src/canvas/StaticCanvas.ts +6 -7
  39. package/src/canvas/TextEditingManager.ts +17 -1
  40. package/src/canvas/canvas_gestures.mixin.ts +2 -2
  41. package/src/constants.ts +7 -0
  42. package/src/controls/Control.ts +8 -0
  43. package/src/controls/changeWidth.ts +4 -3
  44. package/src/controls/drag.ts +3 -2
  45. package/src/controls/polyControl.ts +2 -2
  46. package/src/controls/skew.ts +2 -1
  47. package/src/controls/util.ts +4 -3
  48. package/src/filters/BlendImage.ts +1 -1
  49. package/src/filters/FilterBackend.ts +4 -0
  50. package/src/filters/WebGLFilterBackend.ts +49 -23
  51. package/src/filters/index.ts +5 -1
  52. package/src/filters/typedefs.ts +1 -1
  53. package/src/parser/applyViewboxTransform.ts +2 -2
  54. package/src/parser/constants.ts +5 -4
  55. package/src/parser/elements_parser.ts +3 -2
  56. package/src/parser/normalizeValue.ts +5 -4
  57. package/src/shapes/Group.ts +2 -1
  58. package/src/shapes/IText/DraggableTextDelegate.ts +4 -3
  59. package/src/shapes/IText/IText.ts +20 -19
  60. package/src/shapes/IText/ITextBehavior.ts +8 -7
  61. package/src/shapes/IText/ITextKeyBehavior.ts +41 -56
  62. package/src/shapes/IText/constants.ts +26 -20
  63. package/src/shapes/Image.ts +4 -3
  64. package/src/shapes/Line.ts +4 -3
  65. package/src/shapes/Object/FabricObjectSVGExportMixin.ts +2 -1
  66. package/src/shapes/Object/InteractiveObject.ts +15 -19
  67. package/src/shapes/Object/Object.ts +14 -7
  68. package/src/shapes/Object/ObjectOrigin.ts +9 -8
  69. package/src/shapes/Object/defaultValues.ts +6 -4
  70. package/src/shapes/Path.ts +4 -3
  71. package/src/shapes/Polyline.ts +5 -4
  72. package/src/shapes/Text/StyledText.ts +14 -15
  73. package/src/shapes/Text/Text.ts +33 -28
  74. package/src/shapes/Text/TextSVGExportMixin.ts +2 -1
  75. package/src/shapes/Text/constants.ts +24 -4
  76. package/src/shapes/Textbox.ts +2 -2
  77. package/src/util/dom_misc.ts +7 -5
  78. package/src/util/misc/objectTransforms.ts +2 -1
  79. package/src/util/misc/svgParsing.ts +3 -3
  80. package/src/util/misc/textStyles.ts +1 -4
  81. package/src/util/transform_matrix_removal.ts +2 -1
package/dist/index.js CHANGED
@@ -416,7 +416,7 @@
416
416
  }
417
417
  const cache = new Cache();
418
418
 
419
- var version = "6.0.0-beta6";
419
+ var version = "6.0.0-beta7";
420
420
 
421
421
  // use this syntax so babel plugin see this import here
422
422
  const VERSION = version;
@@ -434,6 +434,12 @@
434
434
  const LEFT_CLICK = 1;
435
435
  const MIDDLE_CLICK = 2;
436
436
  const RIGHT_CLICK = 3;
437
+ const CENTER = 'center';
438
+ const LEFT = 'left';
439
+ const TOP = 'top';
440
+ const BOTTOM = 'bottom';
441
+ const RIGHT = 'right';
442
+ const NONE = 'none';
437
443
 
438
444
  /*
439
445
  * This Map connects the objects type value with their
@@ -1587,10 +1593,10 @@
1587
1593
  top: 0
1588
1594
  },
1589
1595
  offsetAttributes = {
1590
- borderLeftWidth: 'left',
1591
- borderTopWidth: 'top',
1592
- paddingLeft: 'left',
1593
- paddingTop: 'top'
1596
+ borderLeftWidth: LEFT,
1597
+ borderTopWidth: TOP,
1598
+ paddingLeft: LEFT,
1599
+ paddingTop: TOP
1594
1600
  };
1595
1601
  if (!doc) {
1596
1602
  return offset;
@@ -1620,7 +1626,7 @@
1620
1626
  if (typeof element.onselectstart !== 'undefined') {
1621
1627
  element.onselectstart = () => false;
1622
1628
  }
1623
- element.style.userSelect = 'none';
1629
+ element.style.userSelect = NONE;
1624
1630
  return element;
1625
1631
  }
1626
1632
 
@@ -2788,9 +2794,9 @@
2788
2794
  // align can be either none or undefined or a combination of mid/max
2789
2795
  const parseAlign = align => {
2790
2796
  //divide align in alignX and alignY
2791
- if (align && align !== 'none') {
2797
+ if (align && align !== NONE) {
2792
2798
  return [align.slice(1, 4), align.slice(5, 8)];
2793
- } else if (align === 'none') {
2799
+ } else if (align === NONE) {
2794
2800
  return [align, align];
2795
2801
  }
2796
2802
  return ['Mid', 'Mid'];
@@ -3735,7 +3741,7 @@
3735
3741
  * @param {Point} center Center point
3736
3742
  */
3737
3743
  _centerObject(object, center) {
3738
- object.setXY(center, 'center', 'center');
3744
+ object.setXY(center, CENTER, CENTER);
3739
3745
  object.setCoords();
3740
3746
  this.renderOnAddRemove && this.requestRenderAll();
3741
3747
  }
@@ -3995,17 +4001,22 @@
3995
4001
  if (!isTextObject(obj)) {
3996
4002
  return;
3997
4003
  }
3998
- let fontFamily = obj.fontFamily;
4004
+ const {
4005
+ styles,
4006
+ fontFamily
4007
+ } = obj;
3999
4008
  if (fontList[fontFamily] || !fontPaths[fontFamily]) {
4000
4009
  return;
4001
4010
  }
4002
4011
  fontList[fontFamily] = true;
4003
- if (!obj.styles) {
4012
+ if (!styles) {
4004
4013
  return;
4005
4014
  }
4006
- Object.values(obj.styles).forEach(styleRow => {
4007
- Object.values(styleRow).forEach(textCharStyle => {
4008
- fontFamily = textCharStyle.fontFamily;
4015
+ Object.values(styles).forEach(styleRow => {
4016
+ Object.values(styleRow).forEach(_ref2 => {
4017
+ let {
4018
+ fontFamily = ''
4019
+ } = _ref2;
4009
4020
  if (!fontList[fontFamily] && fontPaths[fontFamily]) {
4010
4021
  fontList[fontFamily] = true;
4011
4022
  }
@@ -4127,8 +4138,8 @@
4127
4138
  clipPath
4128
4139
  }, {
4129
4140
  signal
4130
- })]).then(_ref2 => {
4131
- let [enlived, enlivedMap] = _ref2;
4141
+ })]).then(_ref3 => {
4142
+ let [enlived, enlivedMap] = _ref3;
4132
4143
  this.clear();
4133
4144
  this.add(...enlived);
4134
4145
  this.set(serialized);
@@ -4457,7 +4468,7 @@
4457
4468
  scaleX,
4458
4469
  scaleY
4459
4470
  });
4460
- object.setPositionByOrigin(center, 'center', 'center');
4471
+ object.setPositionByOrigin(center, CENTER, CENTER);
4461
4472
  };
4462
4473
  /**
4463
4474
  * reset an object transform state to neutral. Top and left are not accounted for
@@ -4672,7 +4683,7 @@
4672
4683
  * @return {Boolean} true if transform is centered
4673
4684
  */
4674
4685
  function isTransformCentered(transform) {
4675
- return transform.originX === 'center' && transform.originY === 'center';
4686
+ return transform.originX === CENTER && transform.originY === CENTER;
4676
4687
  }
4677
4688
  function invertOrigin(origin) {
4678
4689
  return -resolveOrigin(origin) + 0.5;
@@ -4705,7 +4716,7 @@
4705
4716
  */
4706
4717
  function normalizePoint(target, point, originX, originY) {
4707
4718
  const center = target.getRelativeCenterPoint(),
4708
- p = typeof originX !== 'undefined' && typeof originY !== 'undefined' ? target.translateToGivenOrigin(center, 'center', 'center', originX, originY) : new Point(target.left, target.top),
4719
+ p = typeof originX !== 'undefined' && typeof originY !== 'undefined' ? target.translateToGivenOrigin(center, CENTER, CENTER, originX, originY) : new Point(target.left, target.top),
4709
4720
  p2 = target.angle ? point.rotate(-degreesToRadians(target.angle), center) : point;
4710
4721
  return p2.subtract(p);
4711
4722
  }
@@ -4765,8 +4776,8 @@
4765
4776
  newTop = y - offsetY,
4766
4777
  moveX = !isLocked(target, 'lockMovementX') && target.left !== newLeft,
4767
4778
  moveY = !isLocked(target, 'lockMovementY') && target.top !== newTop;
4768
- moveX && target.set('left', newLeft);
4769
- moveY && target.set('top', newTop);
4779
+ moveX && target.set(LEFT, newLeft);
4780
+ moveY && target.set(TOP, newTop);
4770
4781
  if (moveX || moveY) {
4771
4782
  fireEvent('moving', commonEventInfo(eventData, transform, x, y));
4772
4783
  }
@@ -4790,7 +4801,7 @@
4790
4801
  getSvgStyles(skipShadow) {
4791
4802
  const fillRule = this.fillRule ? this.fillRule : 'nonzero',
4792
4803
  strokeWidth = this.strokeWidth ? this.strokeWidth : '0',
4793
- strokeDashArray = this.strokeDashArray ? this.strokeDashArray.join(' ') : 'none',
4804
+ strokeDashArray = this.strokeDashArray ? this.strokeDashArray.join(' ') : NONE,
4794
4805
  strokeDashOffset = this.strokeDashOffset ? this.strokeDashOffset : '0',
4795
4806
  strokeLineCap = this.strokeLineCap ? this.strokeLineCap : 'butt',
4796
4807
  strokeLineJoin = this.strokeLineJoin ? this.strokeLineJoin : 'miter',
@@ -5936,7 +5947,7 @@
5936
5947
  * @return {Point}
5937
5948
  */
5938
5949
  translateToCenterPoint(point, originX, originY) {
5939
- const p = this.translateToGivenOrigin(point, originX, originY, 'center', 'center');
5950
+ const p = this.translateToGivenOrigin(point, originX, originY, CENTER, CENTER);
5940
5951
  if (this.angle) {
5941
5952
  return p.rotate(degreesToRadians(this.angle), point);
5942
5953
  }
@@ -5951,7 +5962,7 @@
5951
5962
  * @return {Point}
5952
5963
  */
5953
5964
  translateToOriginPoint(center, originX, originY) {
5954
- const p = this.translateToGivenOrigin(center, 'center', 'center', originX, originY);
5965
+ const p = this.translateToGivenOrigin(center, CENTER, CENTER, originX, originY);
5955
5966
  if (this.angle) {
5956
5967
  return p.rotate(degreesToRadians(this.angle), center);
5957
5968
  }
@@ -6010,8 +6021,8 @@
6010
6021
  this._originalOriginX = this.originX;
6011
6022
  this._originalOriginY = this.originY;
6012
6023
  const center = this.getRelativeCenterPoint();
6013
- this.originX = 'center';
6014
- this.originY = 'center';
6024
+ this.originX = CENTER;
6025
+ this.originY = CENTER;
6015
6026
  this.left = center.x;
6016
6027
  this.top = center.y;
6017
6028
  }
@@ -6037,7 +6048,7 @@
6037
6048
  * @private
6038
6049
  */
6039
6050
  _getLeftTopCoords() {
6040
- return this.translateToOriginPoint(this.getRelativeCenterPoint(), 'left', 'top');
6051
+ return this.translateToOriginPoint(this.getRelativeCenterPoint(), LEFT, TOP);
6041
6052
  }
6042
6053
  }
6043
6054
 
@@ -7104,11 +7115,11 @@
7104
7115
 
7105
7116
  const cloneDeep = object => JSON.parse(JSON.stringify(object));
7106
7117
 
7107
- const stateProperties = ['top', 'left', 'scaleX', 'scaleY', 'flipX', 'flipY', 'originX', 'originY', 'angle', 'opacity', 'globalCompositeOperation', 'shadow', 'visible', 'skewX', 'skewY'];
7118
+ const stateProperties = [TOP, LEFT, 'scaleX', 'scaleY', 'flipX', 'flipY', 'originX', 'originY', 'angle', 'opacity', 'globalCompositeOperation', 'shadow', 'visible', 'skewX', 'skewY'];
7108
7119
  const cacheProperties = ['fill', 'stroke', 'strokeWidth', 'strokeDashArray', 'width', 'height', 'paintFirst', 'strokeUniform', 'strokeLineCap', 'strokeDashOffset', 'strokeLineJoin', 'strokeMiterLimit', 'backgroundColor', 'clipPath'];
7109
7120
  const fabricObjectDefaultValues = {
7110
- originX: 'left',
7111
- originY: 'top',
7121
+ originX: LEFT,
7122
+ originY: TOP,
7112
7123
  top: 0,
7113
7124
  left: 0,
7114
7125
  width: 0,
@@ -7608,7 +7619,7 @@
7608
7619
  const hasStaticDefaultValues = Object.keys(defaults).length > 0;
7609
7620
  const baseValues = hasStaticDefaultValues ? defaults : Object.getPrototypeOf(this);
7610
7621
  return pickBy(object, (value, key) => {
7611
- if (key === 'left' || key === 'top' || key === 'type') {
7622
+ if (key === LEFT || key === TOP || key === 'type') {
7612
7623
  return true;
7613
7624
  }
7614
7625
  const baseValue = baseValues[key];
@@ -8322,7 +8333,7 @@
8322
8333
  if (options.format === 'jpeg') {
8323
8334
  canvas.backgroundColor = '#fff';
8324
8335
  }
8325
- this.setPositionByOrigin(new Point(canvas.width / 2, canvas.height / 2), 'center', 'center');
8336
+ this.setPositionByOrigin(new Point(canvas.width / 2, canvas.height / 2), CENTER, CENTER);
8326
8337
  const originalCanvas = this.canvas;
8327
8338
  // static canvas and canvas have both an array of InteractiveObjects
8328
8339
  // @ts-ignore this needs to be fixed somehow, or ignored globally
@@ -8400,7 +8411,7 @@
8400
8411
  * @param {TDegree} angle Angle value (in degrees)
8401
8412
  */
8402
8413
  rotate(angle) {
8403
- const shouldCenterOrigin = (this.originX !== 'center' || this.originY !== 'center') && this.centeredRotation;
8414
+ const shouldCenterOrigin = (this.originX !== CENTER || this.originY !== CENTER) && this.centeredRotation;
8404
8415
  if (shouldCenterOrigin) {
8405
8416
  this._setOriginToCenter();
8406
8417
  }
@@ -8543,7 +8554,7 @@
8543
8554
  const changeObjectWidth = (eventData, transform, x, y) => {
8544
8555
  const localPoint = getLocalPoint(transform, transform.originX, transform.originY, x, y);
8545
8556
  // make sure the control changes width ONLY from it's side of target
8546
- if (transform.originX === 'center' || transform.originX === 'right' && localPoint.x < 0 || transform.originX === 'left' && localPoint.x > 0) {
8557
+ if (transform.originX === CENTER || transform.originX === RIGHT && localPoint.x < 0 || transform.originX === LEFT && localPoint.x > 0) {
8547
8558
  const {
8548
8559
  target
8549
8560
  } = transform,
@@ -8797,6 +8808,12 @@
8797
8808
  * @return {Boolean} true if the action/event modified the object
8798
8809
  */
8799
8810
 
8811
+ shouldActivate(controlKey, fabricObject) {
8812
+ var _fabricObject$canvas;
8813
+ // TODO: locking logic can be handled here instead of in the control handler logic
8814
+ return ((_fabricObject$canvas = fabricObject.canvas) === null || _fabricObject$canvas === void 0 ? void 0 : _fabricObject$canvas.getActiveObject()) === fabricObject && fabricObject.isControlVisible(controlKey);
8815
+ }
8816
+
8800
8817
  /**
8801
8818
  * Returns control actionHandler
8802
8819
  * @param {Event} eventData the native mouse event
@@ -9331,7 +9348,7 @@
9331
9348
  skewingSide = -Math.sign(counterOriginFactor) * (target[flipKey] ? -1 : 1),
9332
9349
  skewingDirection = (target[skewKey] === 0 &&
9333
9350
  // in case skewing equals 0 we use the pointer offset from target center to determine the direction of skewing
9334
- getLocalPoint(transform, 'center', 'center', x, y)[axis] > 0 ||
9351
+ getLocalPoint(transform, CENTER, CENTER, x, y)[axis] > 0 ||
9335
9352
  // in case target has skewing we use that as the direction
9336
9353
  target[skewKey] > 0 ? 1 : -1) * skewingSide,
9337
9354
  // anchor to the opposite side of the skewing direction
@@ -9595,23 +9612,23 @@
9595
9612
  */
9596
9613
  _findTargetCorner(pointer) {
9597
9614
  let forTouch = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
9598
- if (!this.hasControls || !this.canvas || this.canvas._activeObject !== this) {
9599
- return 0;
9615
+ if (!this.hasControls || !this.canvas) {
9616
+ return '';
9600
9617
  }
9601
9618
  this.__corner = undefined;
9602
9619
  // had to keep the reverse loop because was breaking tests
9603
9620
  const cornerEntries = Object.entries(this.oCoords);
9604
9621
  for (let i = cornerEntries.length - 1; i >= 0; i--) {
9605
- const [cornerKey, corner] = cornerEntries[i];
9606
- if (!this.isControlVisible(cornerKey)) {
9607
- continue;
9608
- }
9609
- const lines = this._getImageLines(forTouch ? corner.touchCorner : corner.corner);
9610
- const xPoints = this._findCrossPoints(pointer, lines);
9611
- if (xPoints !== 0 && xPoints % 2 === 1) {
9612
- this.__corner = cornerKey;
9613
- return cornerKey;
9622
+ const [key, corner] = cornerEntries[i];
9623
+ if (this.controls[key].shouldActivate(key, this)) {
9624
+ const lines = this._getImageLines(forTouch ? corner.touchCorner : corner.corner);
9625
+ const xPoints = this._findCrossPoints(pointer, lines);
9626
+ if (xPoints !== 0 && xPoints % 2 === 1) {
9627
+ this.__corner = key;
9628
+ return key;
9629
+ }
9614
9630
  }
9631
+
9615
9632
  // // debugging
9616
9633
  //
9617
9634
  // this.canvas.contextTop.fillRect(lines.bottomline.d.x, lines.bottomline.d.y, 2, 2);
@@ -9627,7 +9644,7 @@
9627
9644
  // this.canvas.contextTop.fillRect(lines.rightline.o.x, lines.rightline.o.y, 2, 2);
9628
9645
  }
9629
9646
 
9630
- return 0;
9647
+ return '';
9631
9648
  }
9632
9649
 
9633
9650
  /**
@@ -10119,11 +10136,11 @@
10119
10136
  svgInvalidAncestors = ['pattern', 'defs', 'symbol', 'metadata', 'clipPath', 'mask', 'desc'],
10120
10137
  svgValidParents = ['symbol', 'g', 'a', 'svg', 'clipPath', 'defs'],
10121
10138
  attributesMap = {
10122
- cx: 'left',
10123
- x: 'left',
10139
+ cx: LEFT,
10140
+ x: LEFT,
10124
10141
  r: 'radius',
10125
- cy: 'top',
10126
- y: 'top',
10142
+ cy: TOP,
10143
+ y: TOP,
10127
10144
  display: 'visible',
10128
10145
  visibility: 'visible',
10129
10146
  transform: 'transformMatrix',
@@ -10332,12 +10349,12 @@
10332
10349
  function normalizeValue(attr, value, parentAttributes, fontSize) {
10333
10350
  const isArray = Array.isArray(value);
10334
10351
  let parsed;
10335
- if ((attr === 'fill' || attr === 'stroke') && value === 'none') {
10352
+ if ((attr === 'fill' || attr === 'stroke') && value === NONE) {
10336
10353
  value = '';
10337
10354
  } else if (attr === 'strokeUniform') {
10338
10355
  return value === 'non-scaling-stroke';
10339
10356
  } else if (attr === 'strokeDashArray') {
10340
- if (value === 'none') {
10357
+ if (value === NONE) {
10341
10358
  value = null;
10342
10359
  } else {
10343
10360
  value = value.replace(/,/g, ' ').split(/\s+/).map(parseFloat);
@@ -10349,7 +10366,7 @@
10349
10366
  value = parseTransformAttribute(value);
10350
10367
  }
10351
10368
  } else if (attr === 'visible') {
10352
- value = value !== 'none' && value !== 'hidden';
10369
+ value = value !== NONE && value !== 'hidden';
10353
10370
  // display=none on parent element always takes precedence over child element
10354
10371
  if (parentAttributes && parentAttributes.visible === false) {
10355
10372
  value = false;
@@ -10360,7 +10377,7 @@
10360
10377
  value *= parentAttributes.opacity;
10361
10378
  }
10362
10379
  } else if (attr === 'textAnchor' /* text-anchor */) {
10363
- value = value === 'start' ? 'left' : value === 'end' ? 'right' : 'center';
10380
+ value = value === 'start' ? LEFT : value === 'end' ? RIGHT : CENTER;
10364
10381
  } else if (attr === 'charSpacing') {
10365
10382
  // parseUnit returns px and we convert it to em
10366
10383
  parsed = parseUnit(value, fontSize) / fontSize * 1000;
@@ -11214,7 +11231,7 @@
11214
11231
  !isFirstLayout && this.layout !== 'clip-path' && this.clipPath && !this.clipPath.absolutePositioned && this._adjustObjectPosition(this.clipPath, diff);
11215
11232
  if (!newCenter.eq(center) || initialTransform) {
11216
11233
  // set position
11217
- this.setPositionByOrigin(newCenter, 'center', 'center');
11234
+ this.setPositionByOrigin(newCenter, CENTER, CENTER);
11218
11235
  initialTransform && this.set(initialTransform);
11219
11236
  this.setCoords();
11220
11237
  }
@@ -13264,7 +13281,7 @@
13264
13281
  object.width = preserveAspectRatioOptions.width;
13265
13282
  object.height = preserveAspectRatioOptions.height;
13266
13283
  }
13267
- object.setPositionByOrigin(center, 'center', 'center');
13284
+ object.setPositionByOrigin(center, CENTER, CENTER);
13268
13285
  };
13269
13286
 
13270
13287
  var index$1 = /*#__PURE__*/Object.freeze({
@@ -14013,17 +14030,17 @@
14013
14030
  };
14014
14031
  // is a left control ?
14015
14032
  if (['ml', 'tl', 'bl'].includes(controlName)) {
14016
- origin.x = 'right';
14033
+ origin.x = RIGHT;
14017
14034
  // is a right control ?
14018
14035
  } else if (['mr', 'tr', 'br'].includes(controlName)) {
14019
- origin.x = 'left';
14036
+ origin.x = LEFT;
14020
14037
  }
14021
14038
  // is a top control ?
14022
14039
  if (['tl', 'mt', 'tr'].includes(controlName)) {
14023
- origin.y = 'bottom';
14040
+ origin.y = BOTTOM;
14024
14041
  // is a bottom control ?
14025
14042
  } else if (['bl', 'mb', 'br'].includes(controlName)) {
14026
- origin.y = 'top';
14043
+ origin.y = TOP;
14027
14044
  }
14028
14045
  return origin;
14029
14046
  }
@@ -14079,8 +14096,8 @@
14079
14096
  })
14080
14097
  };
14081
14098
  if (this._shouldCenterTransform(target, action, altKey)) {
14082
- transform.originX = 'center';
14083
- transform.originY = 'center';
14099
+ transform.originX = CENTER;
14100
+ transform.originY = CENTER;
14084
14101
  }
14085
14102
  this._currentTransform = transform;
14086
14103
  // @ts-ignore
@@ -14287,10 +14304,10 @@
14287
14304
  boundsWidth = bounds.width || 0,
14288
14305
  boundsHeight = bounds.height || 0;
14289
14306
  if (!boundsWidth || !boundsHeight) {
14290
- if ('top' in bounds && 'bottom' in bounds) {
14307
+ if (TOP in bounds && BOTTOM in bounds) {
14291
14308
  boundsHeight = Math.abs(bounds.top - bounds.bottom);
14292
14309
  }
14293
- if ('right' in bounds && 'left' in bounds) {
14310
+ if (RIGHT in bounds && LEFT in bounds) {
14294
14311
  boundsWidth = Math.abs(bounds.right - bounds.left);
14295
14312
  }
14296
14313
  }
@@ -14405,8 +14422,8 @@
14405
14422
  height: height + 'px',
14406
14423
  left: 0,
14407
14424
  top: 0,
14408
- 'touch-action': this.allowTouchScrolling ? 'manipulation' : 'none',
14409
- '-ms-touch-action': this.allowTouchScrolling ? 'manipulation' : 'none'
14425
+ 'touch-action': this.allowTouchScrolling ? 'manipulation' : NONE,
14426
+ '-ms-touch-action': this.allowTouchScrolling ? 'manipulation' : NONE
14410
14427
  });
14411
14428
  element.width = width;
14412
14429
  element.height = height;
@@ -14717,7 +14734,7 @@
14717
14734
  */
14718
14735
  _realizeGroupTransformOnObject(instance) {
14719
14736
  if (instance.group && instance.group === this._activeSelection && this._activeObject === instance.group) {
14720
- const layoutProps = ['angle', 'flipX', 'flipY', 'left', 'scaleX', 'scaleY', 'skewX', 'skewY', 'top'];
14737
+ const layoutProps = ['angle', 'flipX', 'flipY', LEFT, 'scaleX', 'scaleY', 'skewX', 'skewY', TOP];
14721
14738
  const originalValues = pick(instance, layoutProps);
14722
14739
  addTransformToObject(instance, this._activeObject.calcOwnMatrix());
14723
14740
  return originalValues;
@@ -14743,8 +14760,16 @@
14743
14760
  * In charge of synchronizing all interactive text instances of a canvas
14744
14761
  */
14745
14762
  class TextEditingManager {
14746
- constructor() {
14763
+ constructor(canvas) {
14747
14764
  _defineProperty(this, "targets", []);
14765
+ _defineProperty(this, "__disposer", void 0);
14766
+ const cb = () => {
14767
+ var _this$target, _this$target$hiddenTe;
14768
+ return (_this$target = this.target) === null || _this$target === void 0 ? void 0 : (_this$target$hiddenTe = _this$target.hiddenTextarea) === null || _this$target$hiddenTe === void 0 ? void 0 : _this$target$hiddenTe.focus();
14769
+ };
14770
+ const el = canvas.upperCanvasEl;
14771
+ el.addEventListener('click', cb);
14772
+ this.__disposer = () => el.removeEventListener('click', cb);
14748
14773
  }
14749
14774
  exitTextEditing() {
14750
14775
  this.target = undefined;
@@ -14770,13 +14795,19 @@
14770
14795
  }
14771
14796
  }
14772
14797
  onMouseMove(e) {
14773
- var _this$target;
14774
- ((_this$target = this.target) === null || _this$target === void 0 ? void 0 : _this$target.isEditing) && this.target.updateSelectionOnMouseMove(e);
14798
+ var _this$target2;
14799
+ ((_this$target2 = this.target) === null || _this$target2 === void 0 ? void 0 : _this$target2.isEditing) && this.target.updateSelectionOnMouseMove(e);
14775
14800
  }
14776
- dispose() {
14801
+ clear() {
14777
14802
  this.targets = [];
14778
14803
  this.target = undefined;
14779
14804
  }
14805
+ dispose() {
14806
+ this.clear();
14807
+ this.__disposer();
14808
+ // @ts-expect-error disposing
14809
+ delete this.__disposer;
14810
+ }
14780
14811
  }
14781
14812
 
14782
14813
  const _excluded$c = ["target", "oldTarget", "fireCanvas", "e"];
@@ -14864,7 +14895,7 @@
14864
14895
  super(el, options);
14865
14896
  // bind event handlers
14866
14897
  _defineProperty(this, "_isClick", void 0);
14867
- _defineProperty(this, "textEditingManager", new TextEditingManager());
14898
+ _defineProperty(this, "textEditingManager", new TextEditingManager(this));
14868
14899
  ['_onMouseDown', '_onTouchStart', '_onMouseMove', '_onMouseUp', '_onTouchEnd', '_onResize',
14869
14900
  // '_onGesture',
14870
14901
  // '_onDrag',
@@ -15056,7 +15087,7 @@
15056
15087
  * @param {DragEvent} e
15057
15088
  */
15058
15089
  _onDragEnd(e) {
15059
- const didDrop = !!e.dataTransfer && e.dataTransfer.dropEffect !== 'none',
15090
+ const didDrop = !!e.dataTransfer && e.dataTransfer.dropEffect !== NONE,
15060
15091
  dropTarget = didDrop ? this._activeObject : undefined,
15061
15092
  options = {
15062
15093
  e,
@@ -16113,15 +16144,12 @@
16113
16144
  this._groupSelector = null;
16114
16145
  return true;
16115
16146
  }
16116
- exitTextEditing() {
16117
- this.textEditingManager.exitTextEditing();
16118
- }
16119
16147
 
16120
16148
  /**
16121
16149
  * @override clear {@link textEditingManager}
16122
16150
  */
16123
16151
  clear() {
16124
- this.textEditingManager.dispose();
16152
+ this.textEditingManager.clear();
16125
16153
  super.clear();
16126
16154
  }
16127
16155
 
@@ -16130,8 +16158,8 @@
16130
16158
  */
16131
16159
  destroy() {
16132
16160
  this.removeListeners();
16133
- super.destroy();
16134
16161
  this.textEditingManager.dispose();
16162
+ super.destroy();
16135
16163
  }
16136
16164
  }
16137
16165
 
@@ -16900,8 +16928,8 @@
16900
16928
  options = _objectWithoutProperties(_ref, _excluded$a);
16901
16929
  super(options);
16902
16930
  this._setPath(path || [], true);
16903
- typeof left === 'number' && this.set('left', left);
16904
- typeof top === 'number' && this.set('top', top);
16931
+ typeof left === 'number' && this.set(LEFT, left);
16932
+ typeof top === 'number' && this.set(TOP, top);
16905
16933
  }
16906
16934
 
16907
16935
  /**
@@ -17097,7 +17125,7 @@
17097
17125
  });
17098
17126
  // using pathOffset because it match the use case.
17099
17127
  // if pathOffset change here we need to use left + width/2 , top + height/2
17100
- adjustPosition && this.setPositionByOrigin(pathOffset, 'center', 'center');
17128
+ adjustPosition && this.setPositionByOrigin(pathOffset, CENTER, CENTER);
17101
17129
  }
17102
17130
  _calcBoundsFromPath() {
17103
17131
  const bounds = [];
@@ -17722,8 +17750,8 @@
17722
17750
  radius: point.radius,
17723
17751
  left: point.x,
17724
17752
  top: point.y,
17725
- originX: 'center',
17726
- originY: 'center',
17753
+ originX: CENTER,
17754
+ originY: CENTER,
17727
17755
  fill: point.fill
17728
17756
  });
17729
17757
  this.shadow && (circle.shadow = new Shadow(this.shadow));
@@ -17876,8 +17904,8 @@
17876
17904
  height: chunck.width,
17877
17905
  left: chunck.x + 1,
17878
17906
  top: chunck.y + 1,
17879
- originX: 'center',
17880
- originY: 'center',
17907
+ originX: CENTER,
17908
+ originY: CENTER,
17881
17909
  fill: this.color
17882
17910
  });
17883
17911
  rects.push(rect);
@@ -18051,8 +18079,8 @@
18051
18079
  left,
18052
18080
  top
18053
18081
  } = options;
18054
- typeof left === 'number' && this.set('left', left);
18055
- typeof top === 'number' && this.set('top', top);
18082
+ typeof left === 'number' && this.set(LEFT, left);
18083
+ typeof top === 'number' && this.set(TOP, top);
18056
18084
  }
18057
18085
 
18058
18086
  /**
@@ -18081,7 +18109,7 @@
18081
18109
  y: y2
18082
18110
  }]);
18083
18111
  const position = new Point(left + width / 2, top + height / 2);
18084
- this.setPositionByOrigin(position, 'center', 'center');
18112
+ this.setPositionByOrigin(position, CENTER, CENTER);
18085
18113
  }
18086
18114
 
18087
18115
  /**
@@ -18523,8 +18551,8 @@
18523
18551
  } = options;
18524
18552
  this.initialized = true;
18525
18553
  this.setBoundingBox(true);
18526
- typeof left === 'number' && this.set('left', left);
18527
- typeof top === 'number' && this.set('top', top);
18554
+ typeof left === 'number' && this.set(LEFT, left);
18555
+ typeof top === 'number' && this.set(TOP, top);
18528
18556
  }
18529
18557
  isOpen() {
18530
18558
  return true;
@@ -18589,7 +18617,7 @@
18589
18617
  pathOffset,
18590
18618
  strokeOffset
18591
18619
  });
18592
- adjustPosition && this.setPositionByOrigin(new Point(left + width / 2, top + height / 2), 'center', 'center');
18620
+ adjustPosition && this.setPositionByOrigin(new Point(left + width / 2, top + height / 2), CENTER, CENTER);
18593
18621
  }
18594
18622
 
18595
18623
  /**
@@ -18763,7 +18791,7 @@
18763
18791
  underline: false,
18764
18792
  overline: false,
18765
18793
  linethrough: false,
18766
- textAlign: 'left',
18794
+ textAlign: LEFT,
18767
18795
  fontStyle: 'normal',
18768
18796
  lineHeight: 1.16,
18769
18797
  superscript: {
@@ -18783,7 +18811,7 @@
18783
18811
  shadow: null,
18784
18812
  path: null,
18785
18813
  pathStartOffset: 0,
18786
- pathSide: 'left',
18814
+ pathSide: LEFT,
18787
18815
  pathAlign: 'baseline',
18788
18816
  _fontSizeFraction: 0.222,
18789
18817
  offsets: {
@@ -18798,8 +18826,10 @@
18798
18826
  CACHE_FONT_SIZE: 400,
18799
18827
  MIN_TEXT_WIDTH: 2
18800
18828
  };
18801
-
18802
- // @TODO properly type this
18829
+ const JUSTIFY = 'justify';
18830
+ const JUSTIFY_LEFT = 'justify-left';
18831
+ const JUSTIFY_RIGHT = 'justify-right';
18832
+ const JUSTIFY_CENTER = 'justify-center';
18803
18833
 
18804
18834
  class StyledText extends FabricObject {
18805
18835
  /**
@@ -18836,7 +18866,7 @@
18836
18866
  * @return {Boolean}
18837
18867
  */
18838
18868
  styleHas(property, lineIndex) {
18839
- if (!this.styles || !property || property === '') {
18869
+ if (!this.styles) {
18840
18870
  return false;
18841
18871
  }
18842
18872
  if (typeof lineIndex !== 'undefined' && !this.styles[lineIndex]) {
@@ -18868,7 +18898,7 @@
18868
18898
  * @param {string} property The property to compare between characters and text.
18869
18899
  */
18870
18900
  cleanStyle(property) {
18871
- if (!this.styles || !property || property === '') {
18901
+ if (!this.styles) {
18872
18902
  return false;
18873
18903
  }
18874
18904
  const obj = this.styles;
@@ -18880,9 +18910,8 @@
18880
18910
  for (const p1 in obj) {
18881
18911
  letterCount = 0;
18882
18912
  for (const p2 in obj[p1]) {
18883
- const styleObject = obj[p1][p2],
18884
- // TODO: this shouldn't be necessary anymore with modern browsers
18885
- stylePropertyHasBeenSet = Object.prototype.hasOwnProperty.call(styleObject, property);
18913
+ const styleObject = obj[p1][p2] || {},
18914
+ stylePropertyHasBeenSet = styleObject[property] !== undefined;
18886
18915
  stylesCount++;
18887
18916
  if (stylePropertyHasBeenSet) {
18888
18917
  if (!stylePropertyValue) {
@@ -18912,6 +18941,7 @@
18912
18941
  graphemeCount += this._textLines[i].length;
18913
18942
  }
18914
18943
  if (allStyleObjectPropertiesMatch && stylesCount === graphemeCount) {
18944
+ // @ts-expect-error conspiracy theory of TS
18915
18945
  this[property] = stylePropertyValue;
18916
18946
  this.removeStyle(property);
18917
18947
  }
@@ -18925,7 +18955,7 @@
18925
18955
  * @param {String} props The property to remove from character styles.
18926
18956
  */
18927
18957
  removeStyle(property) {
18928
- if (!this.styles || !property || property === '') {
18958
+ if (!this.styles) {
18929
18959
  return;
18930
18960
  }
18931
18961
  const obj = this.styles;
@@ -19028,6 +19058,7 @@
19028
19058
  styleProps = this.constructor._styleProperties;
19029
19059
  for (let i = 0; i < styleProps.length; i++) {
19030
19060
  const prop = styleProps[i];
19061
+ // @ts-expect-error TS complains even when we serve everything on a silver plate.
19031
19062
  styleObject[prop] = typeof style[prop] === 'undefined' ? this[prop] : style[prop];
19032
19063
  }
19033
19064
  return styleObject;
@@ -19158,7 +19189,7 @@
19158
19189
  }
19159
19190
  _setSVGTextLineText(textSpans, lineIndex, textLeftOffset, textTopOffset) {
19160
19191
  const lineHeight = this.getHeightOfLine(lineIndex),
19161
- isJustify = this.textAlign.indexOf('justify') !== -1,
19192
+ isJustify = this.textAlign.includes(JUSTIFY),
19162
19193
  line = this._textLines[lineIndex];
19163
19194
  let actualStyle,
19164
19195
  nextStyle,
@@ -19549,7 +19580,7 @@
19549
19580
  this.width = this.calcTextWidth() || this.cursorWidth || this.MIN_TEXT_WIDTH;
19550
19581
  this.height = this.calcTextHeight();
19551
19582
  }
19552
- if (this.textAlign.indexOf('justify') !== -1) {
19583
+ if (this.textAlign.includes(JUSTIFY)) {
19553
19584
  // once text is measured we need to make space fatter to make justified text.
19554
19585
  this.enlargeSpaces();
19555
19586
  }
@@ -19561,7 +19592,7 @@
19561
19592
  enlargeSpaces() {
19562
19593
  let diffSpace, currentLineWidth, numberOfSpaces, accumulatedSpace, line, charBound, spaces;
19563
19594
  for (let i = 0, len = this._textLines.length; i < len; i++) {
19564
- if (this.textAlign !== 'justify' && (i === len - 1 || this.isEndOfWrapping(i))) {
19595
+ if (this.textAlign !== JUSTIFY && (i === len - 1 || this.isEndOfWrapping(i))) {
19565
19596
  continue;
19566
19597
  }
19567
19598
  accumulatedSpace = 0;
@@ -19698,14 +19729,14 @@
19698
19729
  ctx.textBaseline = 'alphabetic';
19699
19730
  if (this.path) {
19700
19731
  switch (this.pathAlign) {
19701
- case 'center':
19732
+ case CENTER:
19702
19733
  ctx.textBaseline = 'middle';
19703
19734
  break;
19704
19735
  case 'ascender':
19705
- ctx.textBaseline = 'top';
19736
+ ctx.textBaseline = TOP;
19706
19737
  break;
19707
19738
  case 'descender':
19708
- ctx.textBaseline = 'bottom';
19739
+ ctx.textBaseline = BOTTOM;
19709
19740
  break;
19710
19741
  }
19711
19742
  }
@@ -19895,7 +19926,7 @@
19895
19926
  let width = 0,
19896
19927
  prevGrapheme,
19897
19928
  graphemeInfo;
19898
- const reverse = this.pathSide === 'right',
19929
+ const reverse = this.pathSide === RIGHT,
19899
19930
  path = this.path,
19900
19931
  line = this._textLines[lineIndex],
19901
19932
  llength = line.length,
@@ -19923,13 +19954,13 @@
19923
19954
  startingPoint.x += path.pathOffset.x;
19924
19955
  startingPoint.y += path.pathOffset.y;
19925
19956
  switch (this.textAlign) {
19926
- case 'left':
19957
+ case LEFT:
19927
19958
  positionInPath = reverse ? totalPathLength - width : 0;
19928
19959
  break;
19929
- case 'center':
19960
+ case CENTER:
19930
19961
  positionInPath = (totalPathLength - width) / 2;
19931
19962
  break;
19932
- case 'right':
19963
+ case RIGHT:
19933
19964
  positionInPath = reverse ? 0 : totalPathLength - width;
19934
19965
  break;
19935
19966
  //todo - add support for justify
@@ -19971,7 +20002,7 @@
19971
20002
  const info = getPointOnPath(path.path, centerPosition, path.segmentsInfo);
19972
20003
  graphemeInfo.renderLeft = info.x - startingPoint.x;
19973
20004
  graphemeInfo.renderTop = info.y - startingPoint.y;
19974
- graphemeInfo.angle = info.angle + (this.pathSide === 'right' ? Math.PI : 0);
20005
+ graphemeInfo.angle = info.angle + (this.pathSide === RIGHT ? Math.PI : 0);
19975
20006
  }
19976
20007
 
19977
20008
  /**
@@ -20117,7 +20148,7 @@
20117
20148
  */
20118
20149
  _renderChars(method, ctx, line, left, top, lineIndex) {
20119
20150
  const lineHeight = this.getHeightOfLine(lineIndex),
20120
- isJustify = this.textAlign.indexOf('justify') !== -1,
20151
+ isJustify = this.textAlign.includes(JUSTIFY),
20121
20152
  path = this.path,
20122
20153
  shortCut = !isJustify && this.charSpacing === 0 && this.isEmptyStyles(lineIndex) && !path,
20123
20154
  isLtr = this.direction === 'ltr',
@@ -20136,7 +20167,7 @@
20136
20167
  if (currentDirection !== this.direction) {
20137
20168
  ctx.canvas.setAttribute('dir', isLtr ? 'ltr' : 'rtl');
20138
20169
  ctx.direction = isLtr ? 'ltr' : 'rtl';
20139
- ctx.textAlign = isLtr ? 'left' : 'right';
20170
+ ctx.textAlign = isLtr ? LEFT : RIGHT;
20140
20171
  }
20141
20172
  top -= lineHeight * this._fontSizeFraction / this.lineHeight;
20142
20173
  if (shortCut) {
@@ -20350,27 +20381,27 @@
20350
20381
  direction = this.direction,
20351
20382
  isEndOfWrapping = this.isEndOfWrapping(lineIndex);
20352
20383
  let leftOffset = 0;
20353
- if (textAlign === 'justify' || textAlign === 'justify-center' && !isEndOfWrapping || textAlign === 'justify-right' && !isEndOfWrapping || textAlign === 'justify-left' && !isEndOfWrapping) {
20384
+ if (textAlign === JUSTIFY || textAlign === JUSTIFY_CENTER && !isEndOfWrapping || textAlign === JUSTIFY_RIGHT && !isEndOfWrapping || textAlign === JUSTIFY_LEFT && !isEndOfWrapping) {
20354
20385
  return 0;
20355
20386
  }
20356
- if (textAlign === 'center') {
20387
+ if (textAlign === CENTER) {
20357
20388
  leftOffset = lineDiff / 2;
20358
20389
  }
20359
- if (textAlign === 'right') {
20390
+ if (textAlign === RIGHT) {
20360
20391
  leftOffset = lineDiff;
20361
20392
  }
20362
- if (textAlign === 'justify-center') {
20393
+ if (textAlign === JUSTIFY_CENTER) {
20363
20394
  leftOffset = lineDiff / 2;
20364
20395
  }
20365
- if (textAlign === 'justify-right') {
20396
+ if (textAlign === JUSTIFY_RIGHT) {
20366
20397
  leftOffset = lineDiff;
20367
20398
  }
20368
20399
  if (direction === 'rtl') {
20369
- if (textAlign === 'right' || textAlign === 'justify' || textAlign === 'justify-right') {
20400
+ if (textAlign === RIGHT || textAlign === JUSTIFY || textAlign === JUSTIFY_RIGHT) {
20370
20401
  leftOffset = 0;
20371
- } else if (textAlign === 'left' || textAlign === 'justify-left') {
20402
+ } else if (textAlign === LEFT || textAlign === JUSTIFY_LEFT) {
20372
20403
  leftOffset = -lineDiff;
20373
- } else if (textAlign === 'center' || textAlign === 'justify-center') {
20404
+ } else if (textAlign === CENTER || textAlign === JUSTIFY_CENTER) {
20374
20405
  leftOffset = -lineDiff / 2;
20375
20406
  }
20376
20407
  }
@@ -20635,7 +20666,7 @@
20635
20666
  const parsedAttributes = parseAttributes(element, Text.ATTRIBUTE_NAMES);
20636
20667
  const _options$parsedAttrib = _objectSpread2(_objectSpread2({}, options), parsedAttributes),
20637
20668
  {
20638
- textAnchor = 'left',
20669
+ textAnchor = LEFT,
20639
20670
  textDecoration = '',
20640
20671
  dx = 0,
20641
20672
  dy = 0,
@@ -20684,10 +20715,10 @@
20684
20715
  x/y attributes in SVG correspond to the bottom-left corner of text bounding box
20685
20716
  fabric output by default at top, left.
20686
20717
  */
20687
- if (textAnchor === 'center') {
20718
+ if (textAnchor === CENTER) {
20688
20719
  offX = text.getScaledWidth() / 2;
20689
20720
  }
20690
- if (textAnchor === 'right') {
20721
+ if (textAnchor === RIGHT) {
20691
20722
  offX = text.getScaledWidth();
20692
20723
  }
20693
20724
  text.set({
@@ -20838,7 +20869,7 @@
20838
20869
  setStyle(dragImage, {
20839
20870
  position: 'fixed',
20840
20871
  left: "".concat(-dragImage.width, "px"),
20841
- border: 'none',
20872
+ border: NONE,
20842
20873
  width: "".concat(dragImage.width / retinaScaling, "px"),
20843
20874
  height: "".concat(dragImage.height / retinaScaling, "px")
20844
20875
  });
@@ -21023,8 +21054,8 @@
21023
21054
  selectionStart,
21024
21055
  selectionEnd
21025
21056
  } = this.__dragStartSelection;
21026
- const dropEffect = ((_e$dataTransfer3 = e.dataTransfer) === null || _e$dataTransfer3 === void 0 ? void 0 : _e$dataTransfer3.dropEffect) || 'none';
21027
- if (dropEffect === 'none') {
21057
+ const dropEffect = ((_e$dataTransfer3 = e.dataTransfer) === null || _e$dataTransfer3 === void 0 ? void 0 : _e$dataTransfer3.dropEffect) || NONE;
21058
+ if (dropEffect === NONE) {
21028
21059
  // pointer is back over selection
21029
21060
  target.selectionStart = selectionStart;
21030
21061
  target.selectionEnd = selectionEnd;
@@ -21900,14 +21931,14 @@
21900
21931
  setSelectionStartEndWithShift(start, end, newSelection) {
21901
21932
  if (newSelection <= start) {
21902
21933
  if (end === start) {
21903
- this._selectionDirection = 'left';
21904
- } else if (this._selectionDirection === 'right') {
21905
- this._selectionDirection = 'left';
21934
+ this._selectionDirection = LEFT;
21935
+ } else if (this._selectionDirection === RIGHT) {
21936
+ this._selectionDirection = LEFT;
21906
21937
  this.selectionEnd = start;
21907
21938
  }
21908
21939
  this.selectionStart = newSelection;
21909
21940
  } else if (newSelection > start && newSelection < end) {
21910
- if (this._selectionDirection === 'right') {
21941
+ if (this._selectionDirection === RIGHT) {
21911
21942
  this.selectionEnd = newSelection;
21912
21943
  } else {
21913
21944
  this.selectionStart = newSelection;
@@ -21915,9 +21946,9 @@
21915
21946
  } else {
21916
21947
  // newSelection is > selection start and end
21917
21948
  if (end === start) {
21918
- this._selectionDirection = 'right';
21919
- } else if (this._selectionDirection === 'left') {
21920
- this._selectionDirection = 'right';
21949
+ this._selectionDirection = RIGHT;
21950
+ } else if (this._selectionDirection === LEFT) {
21951
+ this._selectionDirection = RIGHT;
21921
21952
  this.selectionStart = end;
21922
21953
  }
21923
21954
  this.selectionEnd = newSelection;
@@ -21925,8 +21956,7 @@
21925
21956
  }
21926
21957
  }
21927
21958
 
21928
- //@ts-nocheck
21929
-
21959
+ // @ts-nocheck
21930
21960
  class ITextKeyBehavior extends ITextBehavior {
21931
21961
  /**
21932
21962
  * For functionalities on keyDown
@@ -21962,39 +21992,43 @@
21962
21992
  */
21963
21993
  initHiddenTextarea() {
21964
21994
  const doc = this.canvas && getDocumentFromElement(this.canvas.getElement()) || getFabricDocument();
21965
- this.hiddenTextarea = doc.createElement('textarea');
21966
- this.hiddenTextarea.setAttribute('autocapitalize', 'off');
21967
- this.hiddenTextarea.setAttribute('autocorrect', 'off');
21968
- this.hiddenTextarea.setAttribute('autocomplete', 'off');
21969
- this.hiddenTextarea.setAttribute('spellcheck', 'false');
21970
- this.hiddenTextarea.setAttribute('data-fabric', 'textarea');
21971
- this.hiddenTextarea.setAttribute('wrap', 'off');
21972
- const style = this._calcTextareaPosition();
21995
+ const textarea = doc.createElement('textarea');
21996
+ Object.entries({
21997
+ autocapitalize: 'off',
21998
+ autocorrect: 'off',
21999
+ autocomplete: 'off',
22000
+ spellcheck: 'false',
22001
+ 'data-fabric': 'textarea',
22002
+ wrap: 'off'
22003
+ }).map(_ref => {
22004
+ let [attribute, value] = _ref;
22005
+ return textarea.setAttribute(attribute, value);
22006
+ });
22007
+ const {
22008
+ top,
22009
+ left,
22010
+ fontSize
22011
+ } = this._calcTextareaPosition();
21973
22012
  // line-height: 1px; was removed from the style to fix this:
21974
22013
  // https://bugs.chromium.org/p/chromium/issues/detail?id=870966
21975
- this.hiddenTextarea.style.cssText = "position: absolute; top: ".concat(style.top, "; left: ").concat(style.left, "; z-index: -999; opacity: 0; width: 1px; height: 1px; font-size: 1px; padding-top: ").concat(style.fontSize, ";");
21976
- if (this.hiddenTextareaContainer) {
21977
- this.hiddenTextareaContainer.appendChild(this.hiddenTextarea);
21978
- } else {
21979
- doc.body.appendChild(this.hiddenTextarea);
21980
- }
21981
- this.hiddenTextarea.addEventListener('blur', this.blur.bind(this));
21982
- this.hiddenTextarea.addEventListener('keydown', this.onKeyDown.bind(this));
21983
- this.hiddenTextarea.addEventListener('keyup', this.onKeyUp.bind(this));
21984
- this.hiddenTextarea.addEventListener('input', this.onInput.bind(this));
21985
- this.hiddenTextarea.addEventListener('copy', this.copy.bind(this));
21986
- this.hiddenTextarea.addEventListener('cut', this.copy.bind(this));
21987
- this.hiddenTextarea.addEventListener('paste', this.paste.bind(this));
21988
- this.hiddenTextarea.addEventListener('compositionstart', this.onCompositionStart.bind(this));
21989
- this.hiddenTextarea.addEventListener('compositionupdate', this.onCompositionUpdate.bind(this));
21990
- this.hiddenTextarea.addEventListener('compositionend', this.onCompositionEnd.bind(this));
21991
- if (!this._clickHandlerInitialized && this.canvas) {
21992
- this.canvas.upperCanvasEl.addEventListener('click', this.onClick.bind(this));
21993
- this._clickHandlerInitialized = true;
21994
- }
21995
- }
21996
- onClick() {
21997
- this.hiddenTextarea && this.hiddenTextarea.focus();
22014
+ textarea.style.cssText = "position: absolute; top: ".concat(top, "; left: ").concat(left, "; z-index: -999; opacity: 0; width: 1px; height: 1px; font-size: 1px; padding-top: ").concat(fontSize, ";");
22015
+ (this.hiddenTextareaContainer || doc.body).appendChild(textarea);
22016
+ Object.entries({
22017
+ blur: 'blur',
22018
+ keydown: 'onKeyDown',
22019
+ keyup: 'onKeyUp',
22020
+ input: 'onInput',
22021
+ copy: 'copy',
22022
+ cut: 'copy',
22023
+ paste: 'paste',
22024
+ compositionstart: 'onCompositionStart',
22025
+ compositionupdate: 'onCompositionUpdate',
22026
+ onCompositionUpdate: 'onCompositionEnd'
22027
+ }).map(_ref2 => {
22028
+ let [eventName, handler] = _ref2;
22029
+ return textarea.addEventListener(eventName, this[handler].bind(this));
22030
+ });
22031
+ this.hiddenTextarea = textarea;
21998
22032
  }
21999
22033
 
22000
22034
  /**
@@ -22327,7 +22361,7 @@
22327
22361
  */
22328
22362
  _moveCursorUpOrDown(direction, e) {
22329
22363
  const action = "get".concat(direction, "CursorOffset"),
22330
- offset = this[action](e, this._selectionDirection === 'right');
22364
+ offset = this[action](e, this._selectionDirection === RIGHT);
22331
22365
  if (e.shiftKey) {
22332
22366
  this.moveCursorWithShift(offset);
22333
22367
  } else {
@@ -22350,7 +22384,7 @@
22350
22384
  * @param {Number} offset
22351
22385
  */
22352
22386
  moveCursorWithShift(offset) {
22353
- const newSelection = this._selectionDirection === 'left' ? this.selectionStart + offset : this.selectionEnd + offset;
22387
+ const newSelection = this._selectionDirection === LEFT ? this.selectionStart + offset : this.selectionEnd + offset;
22354
22388
  this.setSelectionStartEndWithShift(this.selectionStart, this.selectionEnd, newSelection);
22355
22389
  return offset !== 0;
22356
22390
  }
@@ -22421,7 +22455,7 @@
22421
22455
  */
22422
22456
  moveCursorLeftWithoutShift(e) {
22423
22457
  let change = true;
22424
- this._selectionDirection = 'left';
22458
+ this._selectionDirection = LEFT;
22425
22459
 
22426
22460
  // only move cursor when there is no selection,
22427
22461
  // otherwise we discard it, and leave cursor on same place
@@ -22437,10 +22471,10 @@
22437
22471
  * @param {TPointerEvent} e
22438
22472
  */
22439
22473
  moveCursorLeftWithShift(e) {
22440
- if (this._selectionDirection === 'right' && this.selectionStart !== this.selectionEnd) {
22474
+ if (this._selectionDirection === RIGHT && this.selectionStart !== this.selectionEnd) {
22441
22475
  return this._moveLeft(e, 'selectionEnd');
22442
22476
  } else if (this.selectionStart !== 0) {
22443
- this._selectionDirection = 'left';
22477
+ this._selectionDirection = LEFT;
22444
22478
  return this._moveLeft(e, 'selectionStart');
22445
22479
  }
22446
22480
  }
@@ -22482,10 +22516,10 @@
22482
22516
  * @param {TPointerEvent} e
22483
22517
  */
22484
22518
  moveCursorRightWithShift(e) {
22485
- if (this._selectionDirection === 'left' && this.selectionStart !== this.selectionEnd) {
22519
+ if (this._selectionDirection === LEFT && this.selectionStart !== this.selectionEnd) {
22486
22520
  return this._moveRight(e, 'selectionStart');
22487
22521
  } else if (this.selectionEnd !== this._text.length) {
22488
- this._selectionDirection = 'right';
22522
+ this._selectionDirection = RIGHT;
22489
22523
  return this._moveRight(e, 'selectionEnd');
22490
22524
  }
22491
22525
  }
@@ -22496,7 +22530,7 @@
22496
22530
  */
22497
22531
  moveCursorRightWithoutShift(e) {
22498
22532
  let changed = true;
22499
- this._selectionDirection = 'right';
22533
+ this._selectionDirection = RIGHT;
22500
22534
  if (this.selectionStart === this.selectionEnd) {
22501
22535
  changed = this._moveRight(e, 'selectionStart');
22502
22536
  this.selectionEnd = this.selectionStart;
@@ -22779,32 +22813,38 @@
22779
22813
  }
22780
22814
  }
22781
22815
 
22816
+ const MOVE_CURSOR_UP = 'moveCursorUp';
22817
+ const MOVE_CURSOR_DOWN = 'moveCursorDown';
22818
+ const MOVE_CURSOR_LEFT = 'moveCursorLeft';
22819
+ const MOVE_CURSOR_RIGHT = 'moveCursorRight';
22820
+ const EXIT_EDITING = 'exitEditing';
22821
+
22782
22822
  // @TODO look into import { Key } from 'ts-key-enum';
22783
22823
  // and transition from keyCode to Key
22784
22824
  // also reduce string duplication
22785
22825
  const keysMap = {
22786
- 9: 'exitEditing',
22787
- 27: 'exitEditing',
22788
- 33: 'moveCursorUp',
22789
- 34: 'moveCursorDown',
22790
- 35: 'moveCursorRight',
22791
- 36: 'moveCursorLeft',
22792
- 37: 'moveCursorLeft',
22793
- 38: 'moveCursorUp',
22794
- 39: 'moveCursorRight',
22795
- 40: 'moveCursorDown'
22826
+ 9: EXIT_EDITING,
22827
+ 27: EXIT_EDITING,
22828
+ 33: MOVE_CURSOR_UP,
22829
+ 34: MOVE_CURSOR_DOWN,
22830
+ 35: MOVE_CURSOR_RIGHT,
22831
+ 36: MOVE_CURSOR_LEFT,
22832
+ 37: MOVE_CURSOR_LEFT,
22833
+ 38: MOVE_CURSOR_UP,
22834
+ 39: MOVE_CURSOR_RIGHT,
22835
+ 40: MOVE_CURSOR_DOWN
22796
22836
  };
22797
22837
  const keysMapRtl = {
22798
- 9: 'exitEditing',
22799
- 27: 'exitEditing',
22800
- 33: 'moveCursorUp',
22801
- 34: 'moveCursorDown',
22802
- 35: 'moveCursorLeft',
22803
- 36: 'moveCursorRight',
22804
- 37: 'moveCursorRight',
22805
- 38: 'moveCursorUp',
22806
- 39: 'moveCursorLeft',
22807
- 40: 'moveCursorDown'
22838
+ 9: EXIT_EDITING,
22839
+ 27: EXIT_EDITING,
22840
+ 33: MOVE_CURSOR_UP,
22841
+ 34: MOVE_CURSOR_DOWN,
22842
+ 35: MOVE_CURSOR_LEFT,
22843
+ 36: MOVE_CURSOR_RIGHT,
22844
+ 37: MOVE_CURSOR_RIGHT,
22845
+ 38: MOVE_CURSOR_UP,
22846
+ 39: MOVE_CURSOR_LEFT,
22847
+ 40: MOVE_CURSOR_DOWN
22808
22848
  };
22809
22849
 
22810
22850
  /**
@@ -23198,11 +23238,11 @@
23198
23238
  left: lineLeftOffset + (leftOffset > 0 ? leftOffset : 0)
23199
23239
  };
23200
23240
  if (this.direction === 'rtl') {
23201
- if (this.textAlign === 'right' || this.textAlign === 'justify' || this.textAlign === 'justify-right') {
23241
+ if (this.textAlign === RIGHT || this.textAlign === JUSTIFY || this.textAlign === JUSTIFY_RIGHT) {
23202
23242
  boundaries.left *= -1;
23203
- } else if (this.textAlign === 'left' || this.textAlign === 'justify-left') {
23243
+ } else if (this.textAlign === LEFT || this.textAlign === JUSTIFY_LEFT) {
23204
23244
  boundaries.left = lineLeftOffset - (leftOffset > 0 ? leftOffset : 0);
23205
- } else if (this.textAlign === 'center' || this.textAlign === 'justify-center') {
23245
+ } else if (this.textAlign === CENTER || this.textAlign === JUSTIFY_CENTER) {
23206
23246
  boundaries.left = lineLeftOffset - (leftOffset > 0 ? leftOffset : 0);
23207
23247
  }
23208
23248
  }
@@ -23281,7 +23321,7 @@
23281
23321
  _renderSelection(ctx, selection, boundaries) {
23282
23322
  const selectionStart = selection.selectionStart,
23283
23323
  selectionEnd = selection.selectionEnd,
23284
- isJustify = this.textAlign.indexOf('justify') !== -1,
23324
+ isJustify = this.textAlign.includes(JUSTIFY),
23285
23325
  start = this.get2DCursorLocation(selectionStart),
23286
23326
  end = this.get2DCursorLocation(selectionEnd),
23287
23327
  startLine = start.lineIndex,
@@ -23323,11 +23363,11 @@
23323
23363
  ctx.fillStyle = this.selectionColor;
23324
23364
  }
23325
23365
  if (this.direction === 'rtl') {
23326
- if (this.textAlign === 'right' || this.textAlign === 'justify' || this.textAlign === 'justify-right') {
23366
+ if (this.textAlign === RIGHT || this.textAlign === JUSTIFY || this.textAlign === JUSTIFY_RIGHT) {
23327
23367
  drawStart = this.width - drawStart - drawWidth;
23328
- } else if (this.textAlign === 'left' || this.textAlign === 'justify-left') {
23368
+ } else if (this.textAlign === LEFT || this.textAlign === JUSTIFY_LEFT) {
23329
23369
  drawStart = boundaries.left + lineOffset - boxEnd;
23330
- } else if (this.textAlign === 'center' || this.textAlign === 'justify-center') {
23370
+ } else if (this.textAlign === CENTER || this.textAlign === JUSTIFY_CENTER) {
23331
23371
  drawStart = boundaries.left + lineOffset - boxEnd;
23332
23372
  }
23333
23373
  }
@@ -23450,7 +23490,7 @@
23450
23490
  if (this.dynamicMinWidth > this.width) {
23451
23491
  this._set('width', this.dynamicMinWidth);
23452
23492
  }
23453
- if (this.textAlign.indexOf('justify') !== -1) {
23493
+ if (this.textAlign.includes(JUSTIFY)) {
23454
23494
  // once text is measured we need to make space fatter to make justified text.
23455
23495
  this.enlargeSpaces();
23456
23496
  }
@@ -24079,22 +24119,35 @@
24079
24119
  * Accepts specific dimensions to initialize the texture to or a source image.
24080
24120
  *
24081
24121
  * @param {WebGLRenderingContext} gl The GL context to use for creating the texture.
24082
- * @param {Number} width The width to initialize the texture at.
24083
- * @param {Number} height The height to initialize the texture.
24084
- * @param {HTMLImageElement|HTMLCanvasElement} textureImageSource A source for the texture data.
24122
+ * @param {number} width The width to initialize the texture at.
24123
+ * @param {number} height The height to initialize the texture.
24124
+ * @param {TexImageSource} textureImageSource A source for the texture data.
24125
+ * @param {number} filter gl.NEAREST default or gl.LINEAR filters for the texture.
24126
+ * This filter is very useful for LUTs filters. If you need interpolation use gl.LINEAR
24085
24127
  * @returns {WebGLTexture}
24086
24128
  */
24087
- createTexture(gl, width, height, textureImageSource) {
24129
+ createTexture(gl, width, height, textureImageSource, filter) {
24130
+ const {
24131
+ NEAREST,
24132
+ TEXTURE_2D,
24133
+ RGBA,
24134
+ UNSIGNED_BYTE,
24135
+ CLAMP_TO_EDGE,
24136
+ TEXTURE_MAG_FILTER,
24137
+ TEXTURE_MIN_FILTER,
24138
+ TEXTURE_WRAP_S,
24139
+ TEXTURE_WRAP_T
24140
+ } = gl;
24088
24141
  const texture = gl.createTexture();
24089
- gl.bindTexture(gl.TEXTURE_2D, texture);
24090
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
24091
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
24092
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
24093
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
24142
+ gl.bindTexture(TEXTURE_2D, texture);
24143
+ gl.texParameteri(TEXTURE_2D, TEXTURE_MAG_FILTER, filter || NEAREST);
24144
+ gl.texParameteri(TEXTURE_2D, TEXTURE_MIN_FILTER, filter || NEAREST);
24145
+ gl.texParameteri(TEXTURE_2D, TEXTURE_WRAP_S, CLAMP_TO_EDGE);
24146
+ gl.texParameteri(TEXTURE_2D, TEXTURE_WRAP_T, CLAMP_TO_EDGE);
24094
24147
  if (textureImageSource) {
24095
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textureImageSource);
24148
+ gl.texImage2D(TEXTURE_2D, 0, RGBA, RGBA, UNSIGNED_BYTE, textureImageSource);
24096
24149
  } else {
24097
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
24150
+ gl.texImage2D(TEXTURE_2D, 0, RGBA, width, height, 0, RGBA, UNSIGNED_BYTE, null);
24098
24151
  }
24099
24152
  return texture;
24100
24153
  }
@@ -24108,12 +24161,17 @@
24108
24161
  * @param {HTMLImageElement|HTMLCanvasElement} textureImageSource A source to use to create the
24109
24162
  * texture cache entry if one does not already exist.
24110
24163
  */
24111
- getCachedTexture(uniqueId, textureImageSource) {
24112
- if (this.textureCache[uniqueId]) {
24113
- return this.textureCache[uniqueId];
24164
+ getCachedTexture(uniqueId, textureImageSource, filter) {
24165
+ const {
24166
+ textureCache
24167
+ } = this;
24168
+ if (textureCache[uniqueId]) {
24169
+ return textureCache[uniqueId];
24114
24170
  } else {
24115
- const texture = this.createTexture(this.gl, textureImageSource.width, textureImageSource.height, textureImageSource);
24116
- this.textureCache[uniqueId] = texture;
24171
+ const texture = this.createTexture(this.gl, textureImageSource.width, textureImageSource.height, textureImageSource, filter);
24172
+ if (texture) {
24173
+ textureCache[uniqueId] = texture;
24174
+ }
24117
24175
  return texture;
24118
24176
  }
24119
24177
  }
@@ -24255,6 +24313,9 @@
24255
24313
  }
24256
24314
  return filterBackend;
24257
24315
  }
24316
+ function setFilterBackend(backend) {
24317
+ filterBackend = backend;
24318
+ }
24258
24319
 
24259
24320
  const _excluded$5 = ["filters", "resizeFilter", "src", "crossOrigin"];
24260
24321
 
@@ -24798,7 +24859,7 @@
24798
24859
  cropX = 0,
24799
24860
  cropY = 0,
24800
24861
  offset;
24801
- if (pAR && (pAR.alignX !== 'none' || pAR.alignY !== 'none')) {
24862
+ if (pAR && (pAR.alignX !== NONE || pAR.alignY !== NONE)) {
24802
24863
  if (pAR.meetOrSlice === 'meet') {
24803
24864
  scaleX = scaleY = findScaleToFit(this._element, parsedAttributes);
24804
24865
  offset = (pWidth - rWidth * scaleX) / 2;
@@ -24933,7 +24994,6 @@
24933
24994
  classRegistry.setSVGClass(Image);
24934
24995
 
24935
24996
  //@ts-nocheck
24936
-
24937
24997
  /**
24938
24998
  * Add a <g> element that envelop all child elements and makes the viewbox transformMatrix descend on all elements
24939
24999
  */
@@ -25002,7 +25062,7 @@
25002
25062
 
25003
25063
  // default is to preserve aspect ratio
25004
25064
  preserveAspectRatio = parsePreserveAspectRatioAttribute(preserveAspectRatio);
25005
- if (preserveAspectRatio.alignX !== 'none') {
25065
+ if (preserveAspectRatio.alignX !== NONE) {
25006
25066
  //translate all container for the effect of Mid, Min, Max
25007
25067
  if (preserveAspectRatio.meetOrSlice === 'meet') {
25008
25068
  scaleY = scaleX = scaleX > scaleY ? scaleY : scaleX;
@@ -25369,7 +25429,7 @@
25369
25429
  skewX,
25370
25430
  skewY: 0
25371
25431
  });
25372
- clipPath.setPositionByOrigin(new Point(translateX, translateY), 'center', 'center');
25432
+ clipPath.setPositionByOrigin(new Point(translateX, translateY), CENTER, CENTER);
25373
25433
  obj.clipPath = clipPath;
25374
25434
  } else {
25375
25435
  // if clip-path does not resolve to any element, delete the property.
@@ -25546,7 +25606,7 @@
25546
25606
  const polyActionHandler = (eventData, transform, x, y) => {
25547
25607
  const poly = transform.target,
25548
25608
  pointIndex = transform.pointIndex,
25549
- mouseLocalPosition = getLocalPoint(transform, 'center', 'center', x, y),
25609
+ mouseLocalPosition = getLocalPoint(transform, CENTER, CENTER, x, y),
25550
25610
  polygonBaseSize = getSize(poly),
25551
25611
  size = poly._getTransformedDimensions(),
25552
25612
  sizeFactor = polygonBaseSize.divide(size),
@@ -28313,6 +28373,7 @@
28313
28373
  exports.parseTransformAttribute = parseTransformAttribute;
28314
28374
  exports.runningAnimations = runningAnimations;
28315
28375
  exports.setEnv = setEnv;
28376
+ exports.setFilterBackend = setFilterBackend;
28316
28377
  exports.util = index$1;
28317
28378
  exports.version = VERSION;
28318
28379