@leapfrog/interactive-canvas 2.0.25-beta-15 → 2.0.25-beta-17

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.
@@ -343,7 +343,6 @@ export declare abstract class AbstractInteractiveCanvas implements IInteractiveC
343
343
  private redrawScheduled;
344
344
  /**
345
345
  * Redraw the canvas.
346
- * Uses requestAnimationFrame to batch multiple redraw calls into a single render.
347
346
  */
348
347
  redraw(): void;
349
348
  syncObjectList(): void;
@@ -20,6 +20,7 @@ export declare class InteractiveCanvas extends AbstractInteractiveCanvas {
20
20
  */
21
21
  redo(): Promise<void>;
22
22
  private onFabricSelectionChanged;
23
+ private enterTextSelectionModeIfRequired;
23
24
  private onTextEditing;
24
25
  private onDoubleClick;
25
26
  }
@@ -270,6 +270,7 @@ class StackObjectsLayoutFunction {
270
270
  const footerObjects = objects[0];
271
271
  const bodyObjects = objects[1];
272
272
  const bodyWidth = canvasDimensions.widthPx - canvasMargin.right - canvasMargin.left;
273
+ canvas.redraw();
273
274
  //Make one pass and set the widths of all elements. This will force objects with dynamic heights (like text) to take on their necessary height before trying to lay them out.
274
275
  this.applyWidths(allObjects, bodyWidth);
275
276
  const bodyRows = this.getRows(bodyObjects);
@@ -356,11 +357,11 @@ class StackObjectsLayoutFunction {
356
357
  object.setPosition({
357
358
  width: actualWidth
358
359
  });
359
- });
360
- _(objects).forEach((object) => {
361
- if (object.getType() !== ObjectType.VERTICAL_RULE) {
362
- object.updateDimensions();
363
- }
360
+ _(objects).forEach((object) => {
361
+ if (object.getType() !== ObjectType.VERTICAL_RULE) {
362
+ object.updateDimensions();
363
+ }
364
+ });
364
365
  });
365
366
  }
366
367
  adjustCanvasSize(canvas, requiredHeight) {
@@ -472,9 +473,7 @@ class AdvancedLayoutManager extends AbstractLayoutManager {
472
473
  dimensionChange() {
473
474
  const canvasMargin = this.canvas.getMargin();
474
475
  const canvasDimensions = this.canvas.getDimensions();
475
- const allObjects = this.canvas.getObjectsByTypesInternal(ObjectType.TEXT, ObjectType.RICH_TEXT,
476
- //ObjectType.IMAGE,
477
- ObjectType.RECTANGLE, ObjectType.VERTICAL_RULE, ObjectType.HORIZONTAL_RULE);
476
+ const allObjects = this.canvas.getObjectsByTypesInternal(ObjectType.TEXT, ObjectType.RICH_TEXT, ObjectType.RECTANGLE, ObjectType.VERTICAL_RULE, ObjectType.HORIZONTAL_RULE);
478
477
  const bodyWidth = canvasDimensions.widthPx - canvasMargin.right - canvasMargin.left;
479
478
  this.canvas.redraw();
480
479
  //Make one pass and set the widths of all elements. This will force objects with dynamic heights (like text) to take on their necessary height before trying to lay them out.
@@ -519,6 +518,7 @@ class StandardLayoutManager extends AbstractLayoutManager {
519
518
  * @override
520
519
  */
521
520
  onCanvasDimensionsChange() {
521
+ this.stackObjects.execute(this.canvas);
522
522
  this.repositionCutoffs.execute(this.canvas);
523
523
  this.repositionBorders.execute(this.canvas);
524
524
  this.repositionBackgrounds.execute(this.canvas);
@@ -542,19 +542,12 @@ class StandardLayoutManager extends AbstractLayoutManager {
542
542
  this.stackAndRedraw();
543
543
  }
544
544
  stackAndRedraw() {
545
- if (this.layoutBatchScheduled) {
546
- return;
547
- }
548
- this.layoutBatchScheduled = true;
549
- Promise.resolve().then(() => {
550
- this.stackObjects.execute(this.canvas);
551
- this.repositionCutoffs.execute(this.canvas);
552
- this.repositionBorders.execute(this.canvas);
553
- this.repositionBackgrounds.execute(this.canvas);
554
- this.updateObjectDimensions.execute(this.canvas);
555
- this.redrawAll.execute(this.canvas);
556
- this.layoutBatchScheduled = false;
557
- });
545
+ this.stackObjects.execute(this.canvas);
546
+ this.repositionCutoffs.execute(this.canvas);
547
+ this.repositionBorders.execute(this.canvas);
548
+ this.repositionBackgrounds.execute(this.canvas);
549
+ this.updateObjectDimensions.execute(this.canvas);
550
+ this.redrawAll.execute(this.canvas);
558
551
  }
559
552
  }
560
553
 
@@ -1117,8 +1110,7 @@ class AbstractCanvasObject {
1117
1110
  mt: options.allowScale,
1118
1111
  mr: options.allowScale,
1119
1112
  mb: options.allowScale,
1120
- mtr: options.allowRotate,
1121
- // dragControl: options.allowMove // Show drag control when movement is allowed
1113
+ mtr: options.allowRotate
1122
1114
  });
1123
1115
  }
1124
1116
  }
@@ -1857,8 +1849,6 @@ class Text extends AbstractCanvasObject {
1857
1849
  });
1858
1850
  this.fabricObject.on("changed", () => this.onTextChange());
1859
1851
  this.fabricObject.on("selection:changed", () => this.onSelectionChange());
1860
- // Note: Removed containsPoint override to allow Fabric's default bounding box
1861
- // detection with padding to work properly for hover detection
1862
1852
  this.fabricObject.on("mousedown", (e) => {
1863
1853
  var _a;
1864
1854
  if (!this.fabricObject.isEditing) {
@@ -2513,7 +2503,6 @@ class Text extends AbstractCanvasObject {
2513
2503
  lockMovementY: true,
2514
2504
  hasControls: false,
2515
2505
  selectable: false,
2516
- // evented: false, // Don't capture mouse events - allows clicks to pass through to textbox
2517
2506
  originX: "left",
2518
2507
  originY: "top"
2519
2508
  });
@@ -2620,16 +2609,12 @@ class Text extends AbstractCanvasObject {
2620
2609
  * @inheritDoc
2621
2610
  */
2622
2611
  updateFabricObjectBehavior() {
2623
- // DON'T call super.updateFabricObjectBehavior() for textboxes
2624
- // because it locks movement which interferes with text editing in Fabric v7
2625
2612
  super.updateFabricObjectBehavior();
2626
2613
  const profile = this.canvas.getProfile();
2627
2614
  const allowManualPositioning = !this.canvas.getLayoutManager().isEnforcedPositioning;
2628
- // For textboxes, we keep them moveable but hide all controls except drag control
2629
- // This allows text editing to work properly while still supporting drag via the icon
2630
2615
  this.fabricObject.set({
2631
2616
  lockMovementX: false, // Allow dragging
2632
- lockMovementY: false, // Allow dragging
2617
+ lockMovementY: false,
2633
2618
  lockScalingY: true,
2634
2619
  lockScalingX: this.isPinToBottom(),
2635
2620
  lockScalingFlip: true,
@@ -2655,7 +2640,6 @@ class Text extends AbstractCanvasObject {
2655
2640
  onTextChange() {
2656
2641
  this.data.userText = this.fabricObject.text;
2657
2642
  this.text$.next(this.fabricObject.text);
2658
- // Only check width bounds if text is close to canvas edge (performance optimization)
2659
2643
  const currentLeft = this.fabricObject.left || 0;
2660
2644
  const canvasWidth = this.canvas.getDimensions().widthPx;
2661
2645
  // Skip expensive getBoundingBox if object is clearly within bounds
@@ -2892,8 +2876,8 @@ class AbstractInteractiveCanvas {
2892
2876
  //Configure canvas behaviour
2893
2877
  this.fabricCanvas.stateful = true;
2894
2878
  this.fabricCanvas.preserveObjectStacking = true;
2895
- this.fabricCanvas.perPixelTargetFind = false; // Disabled for better hover tolerance in Fabric v7
2896
- this.fabricCanvas.targetFindTolerance = 0; // Increased for better hover detection in Fabric v7 (was 4)
2879
+ this.fabricCanvas.perPixelTargetFind = false;
2880
+ this.fabricCanvas.targetFindTolerance = 0;
2897
2881
  this.setBackgroundColor("#FFFFFF");
2898
2882
  }
2899
2883
  /**
@@ -3197,6 +3181,7 @@ class AbstractInteractiveCanvas {
3197
3181
  */
3198
3182
  addImageObject(imageUrl) {
3199
3183
  return __awaiter(this, void 0, void 0, function* () {
3184
+ // Don't let the image be more than half the canvas in size.
3200
3185
  const maxSizeScale = 2;
3201
3186
  const maxWidth = this.dimensions$.value.widthPx / maxSizeScale;
3202
3187
  const options = { crossOrigin: "anonymous" };
@@ -3208,6 +3193,7 @@ class AbstractInteractiveCanvas {
3208
3193
  if (curWidth > maxWidth) {
3209
3194
  newScale = maxWidth / curWidth;
3210
3195
  }
3196
+ // Set image properties and add to the canvas
3211
3197
  const fabricImage = new this.fabric.Image(image, {
3212
3198
  id: id,
3213
3199
  scaleX: newScale,
@@ -3227,6 +3213,7 @@ class AbstractInteractiveCanvas {
3227
3213
  return object;
3228
3214
  }
3229
3215
  else {
3216
+ // Browser-side logic
3230
3217
  return yield new Promise((resolve) => {
3231
3218
  this.fabric.Image.fromURL(imageUrl, options).then((fabricImage) => {
3232
3219
  const id = this.randomId();
@@ -3734,7 +3721,6 @@ class AbstractInteractiveCanvas {
3734
3721
  }
3735
3722
  /**
3736
3723
  * Redraw the canvas.
3737
- * Uses requestAnimationFrame to batch multiple redraw calls into a single render.
3738
3724
  */
3739
3725
  redraw() {
3740
3726
  if (this.redrawScheduled) {
@@ -4073,6 +4059,16 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
4073
4059
  selection.setEvent(event);
4074
4060
  }
4075
4061
  this.selection$.next(selection);
4062
+ //this.enterTextSelectionModeIfRequired();
4063
+ }
4064
+ enterTextSelectionModeIfRequired() {
4065
+ var _a, _b;
4066
+ if (!this.profile$.value.enterTextEditImmediatelyOnSelect && !this.layoutManager$.value.enterTextEditImmediatelyOnSelect)
4067
+ return;
4068
+ if (((_b = (_a = this.selection$.value) === null || _a === void 0 ? void 0 : _a.objects[0]) === null || _b === void 0 ? void 0 : _b.getType()) !== ObjectType.TEXT)
4069
+ return;
4070
+ const text = this.selection$.value.objects[0];
4071
+ text.enterEditing();
4076
4072
  }
4077
4073
  onTextEditing() {
4078
4074
  const selected = this.getFieldsByCanvasObject(this.fabricCanvas.getActiveObjects());
@@ -291,6 +291,7 @@ class StackObjectsLayoutFunction {
291
291
  const footerObjects = objects[0];
292
292
  const bodyObjects = objects[1];
293
293
  const bodyWidth = canvasDimensions.widthPx - canvasMargin.right - canvasMargin.left;
294
+ canvas.redraw();
294
295
  //Make one pass and set the widths of all elements. This will force objects with dynamic heights (like text) to take on their necessary height before trying to lay them out.
295
296
  this.applyWidths(allObjects, bodyWidth);
296
297
  const bodyRows = this.getRows(bodyObjects);
@@ -377,11 +378,11 @@ class StackObjectsLayoutFunction {
377
378
  object.setPosition({
378
379
  width: actualWidth
379
380
  });
380
- });
381
- _(objects).forEach((object) => {
382
- if (object.getType() !== exports.ObjectType.VERTICAL_RULE) {
383
- object.updateDimensions();
384
- }
381
+ _(objects).forEach((object) => {
382
+ if (object.getType() !== exports.ObjectType.VERTICAL_RULE) {
383
+ object.updateDimensions();
384
+ }
385
+ });
385
386
  });
386
387
  }
387
388
  adjustCanvasSize(canvas, requiredHeight) {
@@ -493,9 +494,7 @@ class AdvancedLayoutManager extends AbstractLayoutManager {
493
494
  dimensionChange() {
494
495
  const canvasMargin = this.canvas.getMargin();
495
496
  const canvasDimensions = this.canvas.getDimensions();
496
- const allObjects = this.canvas.getObjectsByTypesInternal(exports.ObjectType.TEXT, exports.ObjectType.RICH_TEXT,
497
- //ObjectType.IMAGE,
498
- exports.ObjectType.RECTANGLE, exports.ObjectType.VERTICAL_RULE, exports.ObjectType.HORIZONTAL_RULE);
497
+ const allObjects = this.canvas.getObjectsByTypesInternal(exports.ObjectType.TEXT, exports.ObjectType.RICH_TEXT, exports.ObjectType.RECTANGLE, exports.ObjectType.VERTICAL_RULE, exports.ObjectType.HORIZONTAL_RULE);
499
498
  const bodyWidth = canvasDimensions.widthPx - canvasMargin.right - canvasMargin.left;
500
499
  this.canvas.redraw();
501
500
  //Make one pass and set the widths of all elements. This will force objects with dynamic heights (like text) to take on their necessary height before trying to lay them out.
@@ -540,6 +539,7 @@ class StandardLayoutManager extends AbstractLayoutManager {
540
539
  * @override
541
540
  */
542
541
  onCanvasDimensionsChange() {
542
+ this.stackObjects.execute(this.canvas);
543
543
  this.repositionCutoffs.execute(this.canvas);
544
544
  this.repositionBorders.execute(this.canvas);
545
545
  this.repositionBackgrounds.execute(this.canvas);
@@ -563,19 +563,12 @@ class StandardLayoutManager extends AbstractLayoutManager {
563
563
  this.stackAndRedraw();
564
564
  }
565
565
  stackAndRedraw() {
566
- if (this.layoutBatchScheduled) {
567
- return;
568
- }
569
- this.layoutBatchScheduled = true;
570
- Promise.resolve().then(() => {
571
- this.stackObjects.execute(this.canvas);
572
- this.repositionCutoffs.execute(this.canvas);
573
- this.repositionBorders.execute(this.canvas);
574
- this.repositionBackgrounds.execute(this.canvas);
575
- this.updateObjectDimensions.execute(this.canvas);
576
- this.redrawAll.execute(this.canvas);
577
- this.layoutBatchScheduled = false;
578
- });
566
+ this.stackObjects.execute(this.canvas);
567
+ this.repositionCutoffs.execute(this.canvas);
568
+ this.repositionBorders.execute(this.canvas);
569
+ this.repositionBackgrounds.execute(this.canvas);
570
+ this.updateObjectDimensions.execute(this.canvas);
571
+ this.redrawAll.execute(this.canvas);
579
572
  }
580
573
  }
581
574
 
@@ -1138,8 +1131,7 @@ class AbstractCanvasObject {
1138
1131
  mt: options.allowScale,
1139
1132
  mr: options.allowScale,
1140
1133
  mb: options.allowScale,
1141
- mtr: options.allowRotate,
1142
- // dragControl: options.allowMove // Show drag control when movement is allowed
1134
+ mtr: options.allowRotate
1143
1135
  });
1144
1136
  }
1145
1137
  }
@@ -1878,8 +1870,6 @@ class Text extends AbstractCanvasObject {
1878
1870
  });
1879
1871
  this.fabricObject.on("changed", () => this.onTextChange());
1880
1872
  this.fabricObject.on("selection:changed", () => this.onSelectionChange());
1881
- // Note: Removed containsPoint override to allow Fabric's default bounding box
1882
- // detection with padding to work properly for hover detection
1883
1873
  this.fabricObject.on("mousedown", (e) => {
1884
1874
  var _a;
1885
1875
  if (!this.fabricObject.isEditing) {
@@ -2534,7 +2524,6 @@ class Text extends AbstractCanvasObject {
2534
2524
  lockMovementY: true,
2535
2525
  hasControls: false,
2536
2526
  selectable: false,
2537
- // evented: false, // Don't capture mouse events - allows clicks to pass through to textbox
2538
2527
  originX: "left",
2539
2528
  originY: "top"
2540
2529
  });
@@ -2641,16 +2630,12 @@ class Text extends AbstractCanvasObject {
2641
2630
  * @inheritDoc
2642
2631
  */
2643
2632
  updateFabricObjectBehavior() {
2644
- // DON'T call super.updateFabricObjectBehavior() for textboxes
2645
- // because it locks movement which interferes with text editing in Fabric v7
2646
2633
  super.updateFabricObjectBehavior();
2647
2634
  const profile = this.canvas.getProfile();
2648
2635
  const allowManualPositioning = !this.canvas.getLayoutManager().isEnforcedPositioning;
2649
- // For textboxes, we keep them moveable but hide all controls except drag control
2650
- // This allows text editing to work properly while still supporting drag via the icon
2651
2636
  this.fabricObject.set({
2652
2637
  lockMovementX: false, // Allow dragging
2653
- lockMovementY: false, // Allow dragging
2638
+ lockMovementY: false,
2654
2639
  lockScalingY: true,
2655
2640
  lockScalingX: this.isPinToBottom(),
2656
2641
  lockScalingFlip: true,
@@ -2676,7 +2661,6 @@ class Text extends AbstractCanvasObject {
2676
2661
  onTextChange() {
2677
2662
  this.data.userText = this.fabricObject.text;
2678
2663
  this.text$.next(this.fabricObject.text);
2679
- // Only check width bounds if text is close to canvas edge (performance optimization)
2680
2664
  const currentLeft = this.fabricObject.left || 0;
2681
2665
  const canvasWidth = this.canvas.getDimensions().widthPx;
2682
2666
  // Skip expensive getBoundingBox if object is clearly within bounds
@@ -2913,8 +2897,8 @@ class AbstractInteractiveCanvas {
2913
2897
  //Configure canvas behaviour
2914
2898
  this.fabricCanvas.stateful = true;
2915
2899
  this.fabricCanvas.preserveObjectStacking = true;
2916
- this.fabricCanvas.perPixelTargetFind = false; // Disabled for better hover tolerance in Fabric v7
2917
- this.fabricCanvas.targetFindTolerance = 0; // Increased for better hover detection in Fabric v7 (was 4)
2900
+ this.fabricCanvas.perPixelTargetFind = false;
2901
+ this.fabricCanvas.targetFindTolerance = 0;
2918
2902
  this.setBackgroundColor("#FFFFFF");
2919
2903
  }
2920
2904
  /**
@@ -3218,6 +3202,7 @@ class AbstractInteractiveCanvas {
3218
3202
  */
3219
3203
  addImageObject(imageUrl) {
3220
3204
  return __awaiter(this, void 0, void 0, function* () {
3205
+ // Don't let the image be more than half the canvas in size.
3221
3206
  const maxSizeScale = 2;
3222
3207
  const maxWidth = this.dimensions$.value.widthPx / maxSizeScale;
3223
3208
  const options = { crossOrigin: "anonymous" };
@@ -3229,6 +3214,7 @@ class AbstractInteractiveCanvas {
3229
3214
  if (curWidth > maxWidth) {
3230
3215
  newScale = maxWidth / curWidth;
3231
3216
  }
3217
+ // Set image properties and add to the canvas
3232
3218
  const fabricImage = new this.fabric.Image(image, {
3233
3219
  id: id,
3234
3220
  scaleX: newScale,
@@ -3248,6 +3234,7 @@ class AbstractInteractiveCanvas {
3248
3234
  return object;
3249
3235
  }
3250
3236
  else {
3237
+ // Browser-side logic
3251
3238
  return yield new Promise((resolve) => {
3252
3239
  this.fabric.Image.fromURL(imageUrl, options).then((fabricImage) => {
3253
3240
  const id = this.randomId();
@@ -3755,7 +3742,6 @@ class AbstractInteractiveCanvas {
3755
3742
  }
3756
3743
  /**
3757
3744
  * Redraw the canvas.
3758
- * Uses requestAnimationFrame to batch multiple redraw calls into a single render.
3759
3745
  */
3760
3746
  redraw() {
3761
3747
  if (this.redrawScheduled) {
@@ -4094,6 +4080,16 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
4094
4080
  selection.setEvent(event);
4095
4081
  }
4096
4082
  this.selection$.next(selection);
4083
+ //this.enterTextSelectionModeIfRequired();
4084
+ }
4085
+ enterTextSelectionModeIfRequired() {
4086
+ var _a, _b;
4087
+ if (!this.profile$.value.enterTextEditImmediatelyOnSelect && !this.layoutManager$.value.enterTextEditImmediatelyOnSelect)
4088
+ return;
4089
+ if (((_b = (_a = this.selection$.value) === null || _a === void 0 ? void 0 : _a.objects[0]) === null || _b === void 0 ? void 0 : _b.getType()) !== exports.ObjectType.TEXT)
4090
+ return;
4091
+ const text = this.selection$.value.objects[0];
4092
+ text.enterEditing();
4097
4093
  }
4098
4094
  onTextEditing() {
4099
4095
  const selected = this.getFieldsByCanvasObject(this.fabricCanvas.getActiveObjects());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leapfrog/interactive-canvas",
3
- "version": "2.0.25-beta-15",
3
+ "version": "2.0.25-beta-17",
4
4
  "description": "Leapfrog interactive canvas",
5
5
  "files": [
6
6
  "dist"