@pooder/kit 5.0.3 → 5.1.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 (34) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/index.d.mts +239 -269
  3. package/dist/index.d.ts +239 -269
  4. package/dist/index.js +6485 -5833
  5. package/dist/index.mjs +6587 -5923
  6. package/package.json +2 -2
  7. package/src/{background.ts → extensions/background.ts} +1 -1
  8. package/src/{dieline.ts → extensions/dieline.ts} +39 -17
  9. package/src/{feature.ts → extensions/feature.ts} +80 -67
  10. package/src/{film.ts → extensions/film.ts} +1 -1
  11. package/src/{geometry.ts → extensions/geometry.ts} +151 -105
  12. package/src/{image.ts → extensions/image.ts} +190 -192
  13. package/src/extensions/index.ts +11 -0
  14. package/src/{maskOps.ts → extensions/maskOps.ts} +28 -10
  15. package/src/{mirror.ts → extensions/mirror.ts} +1 -1
  16. package/src/{ruler.ts → extensions/ruler.ts} +5 -3
  17. package/src/extensions/sceneLayout.ts +140 -0
  18. package/src/{sceneLayoutModel.ts → extensions/sceneLayoutModel.ts} +17 -10
  19. package/src/extensions/sceneVisibility.ts +71 -0
  20. package/src/{size.ts → extensions/size.ts} +23 -13
  21. package/src/{tracer.ts → extensions/tracer.ts} +374 -45
  22. package/src/{white-ink.ts → extensions/white-ink.ts} +620 -236
  23. package/src/index.ts +2 -14
  24. package/src/{ViewportSystem.ts → services/ViewportSystem.ts} +5 -2
  25. package/src/services/index.ts +3 -0
  26. package/src/sceneLayout.ts +0 -121
  27. package/src/sceneVisibility.ts +0 -49
  28. /package/src/{bridgeSelection.ts → extensions/bridgeSelection.ts} +0 -0
  29. /package/src/{constraints.ts → extensions/constraints.ts} +0 -0
  30. /package/src/{edgeScale.ts → extensions/edgeScale.ts} +0 -0
  31. /package/src/{featureComplete.ts → extensions/featureComplete.ts} +0 -0
  32. /package/src/{wrappedOffsets.ts → extensions/wrappedOffsets.ts} +0 -0
  33. /package/src/{CanvasService.ts → services/CanvasService.ts} +0 -0
  34. /package/src/{renderSpec.ts → services/renderSpec.ts} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pooder/kit",
3
- "version": "5.0.3",
3
+ "version": "5.1.0",
4
4
  "description": "Standard plugins for Pooder editor",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -19,7 +19,7 @@
19
19
  "dependencies": {
20
20
  "paper": "^0.12.18",
21
21
  "fabric": "^7.0.0",
22
- "@pooder/core": "2.1.0"
22
+ "@pooder/core": "2.2.0"
23
23
  },
24
24
  "scripts": {
25
25
  "build": "tsup src/index.ts --format cjs,esm --dts",
@@ -6,7 +6,7 @@ import {
6
6
  ConfigurationContribution,
7
7
  } from "@pooder/core";
8
8
  import { Rect, FabricImage as Image } from "fabric";
9
- import CanvasService from "./CanvasService";
9
+ import { CanvasService } from "../services";
10
10
 
11
11
  export class BackgroundTool implements Extension {
12
12
  id = "pooder.kit.background";
@@ -7,10 +7,10 @@ import {
7
7
  ConfigurationService,
8
8
  } from "@pooder/core";
9
9
  import { Canvas as FabricCanvas, Path, Pattern } from "fabric";
10
- import CanvasService from "./CanvasService";
10
+ import { CanvasService } from "../services";
11
11
  import { ImageTracer } from "./tracer";
12
- import { Unit } from "./coordinate";
13
- import { parseLengthToMm } from "./units";
12
+ import { Unit } from "../coordinate";
13
+ import { parseLengthToMm } from "../units";
14
14
  import {
15
15
  generateDielinePath,
16
16
  generateMaskPath,
@@ -466,9 +466,17 @@ export class DielineTool implements Extension {
466
466
  options: {
467
467
  expand: detectOptions.expand ?? 0,
468
468
  morphologyRadius: detectOptions.morphologyRadius,
469
+ connectRadiusMax: detectOptions.connectRadiusMax,
469
470
  smoothing: detectOptions.smoothing,
470
471
  simplifyTolerance: detectOptions.simplifyTolerance,
471
472
  threshold: detectOptions.threshold,
473
+ maskMode: detectOptions.maskMode,
474
+ whiteThreshold: detectOptions.whiteThreshold,
475
+ alphaOpaqueCutoff: detectOptions.alphaOpaqueCutoff,
476
+ noChannels: detectOptions.noChannels,
477
+ componentMode: detectOptions.componentMode,
478
+ minComponentArea: detectOptions.minComponentArea,
479
+ forceConnected: detectOptions.forceConnected,
472
480
  },
473
481
  });
474
482
  }
@@ -552,7 +560,9 @@ export class DielineTool implements Extension {
552
560
  }
553
561
 
554
562
  private getConfigService(): ConfigurationService | undefined {
555
- return this.context?.services.get<ConfigurationService>("ConfigurationService");
563
+ return this.context?.services.get<ConfigurationService>(
564
+ "ConfigurationService",
565
+ );
556
566
  }
557
567
 
558
568
  private syncSizeState(configService: ConfigurationService) {
@@ -603,8 +613,10 @@ export class DielineTool implements Extension {
603
613
  features,
604
614
  } = this.state;
605
615
 
606
- const canvasW = sceneLayout.canvasWidth || this.canvasService.canvas.width || 800;
607
- const canvasH = sceneLayout.canvasHeight || this.canvasService.canvas.height || 600;
616
+ const canvasW =
617
+ sceneLayout.canvasWidth || this.canvasService.canvas.width || 800;
618
+ const canvasH =
619
+ sceneLayout.canvasHeight || this.canvasService.canvas.height || 600;
608
620
  const scale = sceneLayout.scale;
609
621
  const cx = sceneLayout.trimRect.centerX;
610
622
  const cy = sceneLayout.trimRect.centerY;
@@ -830,7 +842,9 @@ export class DielineTool implements Extension {
830
842
  const debug = options?.debug === true;
831
843
 
832
844
  if (!this.canvasService) {
833
- console.warn("[DielineTool] exportCutImage returned null: canvas-not-ready");
845
+ console.warn(
846
+ "[DielineTool] exportCutImage returned null: canvas-not-ready",
847
+ );
834
848
  return null;
835
849
  }
836
850
  const configService = this.getConfigService();
@@ -847,13 +861,17 @@ export class DielineTool implements Extension {
847
861
  readSizeState(configService),
848
862
  );
849
863
  if (!sceneLayout) {
850
- console.warn("[DielineTool] exportCutImage returned null: scene-layout-null");
864
+ console.warn(
865
+ "[DielineTool] exportCutImage returned null: scene-layout-null",
866
+ );
851
867
  return null;
852
868
  }
853
869
 
854
870
  const { shape, radius, features, pathData } = this.state;
855
- const canvasW = sceneLayout.canvasWidth || this.canvasService.canvas.width || 800;
856
- const canvasH = sceneLayout.canvasHeight || this.canvasService.canvas.height || 600;
871
+ const canvasW =
872
+ sceneLayout.canvasWidth || this.canvasService.canvas.width || 800;
873
+ const canvasH =
874
+ sceneLayout.canvasHeight || this.canvasService.canvas.height || 600;
857
875
  const scale = sceneLayout.scale;
858
876
  const cx = sceneLayout.trimRect.centerX;
859
877
  const cy = sceneLayout.trimRect.centerY;
@@ -916,16 +934,21 @@ export class DielineTool implements Extension {
916
934
  pathBounds.width <= 0 ||
917
935
  pathBounds.height <= 0
918
936
  ) {
919
- console.warn("[DielineTool] exportCutImage returned null: invalid-cut-bounds", {
920
- bounds: pathBounds,
921
- });
937
+ console.warn(
938
+ "[DielineTool] exportCutImage returned null: invalid-cut-bounds",
939
+ {
940
+ bounds: pathBounds,
941
+ },
942
+ );
922
943
  return null;
923
944
  }
924
945
  const exportBounds = pathBounds;
925
946
 
926
- const sourceImages = this.canvasService.canvas.getObjects().filter((obj: any) => {
927
- return obj?.data?.layerId === IMAGE_OBJECT_LAYER_ID;
928
- });
947
+ const sourceImages = this.canvasService.canvas
948
+ .getObjects()
949
+ .filter((obj: any) => {
950
+ return obj?.data?.layerId === IMAGE_OBJECT_LAYER_ID;
951
+ });
929
952
  if (!sourceImages.length) {
930
953
  console.warn(
931
954
  "[DielineTool] exportCutImage returned null: no-image-objects-on-canvas",
@@ -1001,5 +1024,4 @@ export class DielineTool implements Extension {
1001
1024
  exportCanvas.dispose();
1002
1025
  }
1003
1026
  }
1004
-
1005
1027
  }
@@ -7,16 +7,14 @@ import {
7
7
  ToolSessionService,
8
8
  } from "@pooder/core";
9
9
  import { Circle, Group, Point, Rect } from "fabric";
10
- import CanvasService from "./CanvasService";
10
+ import { CanvasService } from "../services";
11
11
  import {
12
12
  getNearestPointOnDieline,
13
13
  DielineFeature,
14
14
  resolveFeaturePosition,
15
15
  } from "./geometry";
16
16
  import { ConstraintRegistry, ConstraintFeature } from "./constraints";
17
- import {
18
- completeFeaturesStrict,
19
- } from "./featureComplete";
17
+ import { completeFeaturesStrict } from "./featureComplete";
20
18
  import {
21
19
  readSizeState,
22
20
  type SceneGeometrySnapshot as DielineGeometry,
@@ -41,8 +39,9 @@ export class FeatureTool implements Extension {
41
39
 
42
40
  private handleMoving: ((e: any) => void) | null = null;
43
41
  private handleModified: ((e: any) => void) | null = null;
44
- private handleSceneGeometryChange: ((geometry: DielineGeometry) => void) | null =
45
- null;
42
+ private handleSceneGeometryChange:
43
+ | ((geometry: DielineGeometry) => void)
44
+ | null = null;
46
45
 
47
46
  private currentGeometry: DielineGeometry | null = null;
48
47
 
@@ -125,16 +124,16 @@ export class FeatureTool implements Extension {
125
124
  const markers = canvas
126
125
  .getObjects()
127
126
  .filter((obj: any) => obj.data?.type === "feature-marker");
128
-
127
+
129
128
  markers.forEach((marker: any) => {
130
- // If tool active, allow selection. If not, disable selection.
131
- // Also might want to hide them entirely or just disable interaction.
132
- // Assuming we only want to see/edit holes when tool is active.
133
- marker.set({
134
- visible: this.isToolActive, // Or just selectable: false if we want them visible but locked
135
- selectable: this.isToolActive,
136
- evented: this.isToolActive
137
- });
129
+ // If tool active, allow selection. If not, disable selection.
130
+ // Also might want to hide them entirely or just disable interaction.
131
+ // Assuming we only want to see/edit holes when tool is active.
132
+ marker.set({
133
+ visible: this.isToolActive, // Or just selectable: false if we want them visible but locked
134
+ selectable: this.isToolActive,
135
+ evented: this.isToolActive,
136
+ });
138
137
  });
139
138
  canvas.requestRenderAll();
140
139
  }
@@ -276,7 +275,9 @@ export class FeatureTool implements Extension {
276
275
  }
277
276
 
278
277
  private getConfigService(): ConfigurationService | undefined {
279
- return this.context?.services.get<ConfigurationService>("ConfigurationService");
278
+ return this.context?.services.get<ConfigurationService>(
279
+ "ConfigurationService",
280
+ );
280
281
  }
281
282
 
282
283
  private getCommittedFeatures(): ConstraintFeature[] {
@@ -349,8 +350,9 @@ export class FeatureTool implements Extension {
349
350
  private updateWorkingGroupPosition(groupId: string, x: number, y: number) {
350
351
  if (!groupId) return { ok: false };
351
352
 
352
- const configService =
353
- this.context?.services.get<ConfigurationService>("ConfigurationService");
353
+ const configService = this.context?.services.get<ConfigurationService>(
354
+ "ConfigurationService",
355
+ );
354
356
  if (!configService) return { ok: false };
355
357
 
356
358
  const sizeState = readSizeState(configService);
@@ -397,8 +399,9 @@ export class FeatureTool implements Extension {
397
399
  reason: string;
398
400
  }>;
399
401
  } {
400
- const configService =
401
- this.context?.services.get<ConfigurationService>("ConfigurationService");
402
+ const configService = this.context?.services.get<ConfigurationService>(
403
+ "ConfigurationService",
404
+ );
402
405
  if (!configService) {
403
406
  return {
404
407
  ok: false,
@@ -573,14 +576,18 @@ export class FeatureTool implements Extension {
573
576
  // For Group, target.left/top is group center (or top-left depending on origin)
574
577
  // We snap the target position itself.
575
578
  const p = new Point(target.left, target.top);
576
-
579
+
577
580
  // Calculate limit based on target size (min dimension / 2 ensures overlap)
578
581
  // Also subtract stroke width to ensure visual overlap (not just tangent)
579
582
  // target.strokeWidth for group is usually 0, need a safe default (e.g. 2 for markers)
580
- const markerStrokeWidth = (target.strokeWidth || 2) * (target.scaleX || 1);
581
- const minDim = Math.min(target.getScaledWidth(), target.getScaledHeight());
583
+ const markerStrokeWidth =
584
+ (target.strokeWidth || 2) * (target.scaleX || 1);
585
+ const minDim = Math.min(
586
+ target.getScaledWidth(),
587
+ target.getScaledHeight(),
588
+ );
582
589
  const limit = Math.max(0, minDim / 2 - markerStrokeWidth);
583
-
590
+
584
591
  const snapped = this.constrainPosition(p, geometry, limit, feature);
585
592
 
586
593
  target.set({
@@ -691,7 +698,7 @@ export class FeatureTool implements Extension {
691
698
  p: Point,
692
699
  geometry: DielineGeometry,
693
700
  limit: number,
694
- feature?: ConstraintFeature
701
+ feature?: ConstraintFeature,
695
702
  ): { x: number; y: number } {
696
703
  if (!feature) {
697
704
  return { x: p.x, y: p.y };
@@ -709,7 +716,9 @@ export class FeatureTool implements Extension {
709
716
  const dielineHeight = geometry.height / scale;
710
717
 
711
718
  // Filter constraints: only apply those that are NOT validateOnly
712
- const activeConstraints = feature.constraints?.filter((c) => !c.validateOnly);
719
+ const activeConstraints = feature.constraints?.filter(
720
+ (c) => !c.validateOnly,
721
+ );
713
722
 
714
723
  const constrained = ConstraintRegistry.apply(
715
724
  nx,
@@ -788,8 +797,9 @@ export class FeatureTool implements Extension {
788
797
  const finalScale = scale;
789
798
 
790
799
  // Group features by groupId
791
- const groups: { [key: string]: { feature: ConstraintFeature; index: number }[] } =
792
- {};
800
+ const groups: {
801
+ [key: string]: { feature: ConstraintFeature; index: number }[];
802
+ } = {};
793
803
  const singles: { feature: ConstraintFeature; index: number }[] = [];
794
804
 
795
805
  this.workingFeatures.forEach((f: ConstraintFeature, i: number) => {
@@ -812,8 +822,7 @@ export class FeatureTool implements Extension {
812
822
  const visualHeight = (feature.height || 10) * featureScale;
813
823
  const visualRadius = (feature.radius || 0) * featureScale;
814
824
  const color =
815
- feature.color ||
816
- (feature.operation === "add" ? "#00FF00" : "#FF0000");
825
+ feature.color || (feature.operation === "add" ? "#00FF00" : "#FF0000");
817
826
  const strokeDash =
818
827
  feature.strokeDash ||
819
828
  (feature.operation === "subtract" ? [4, 4] : undefined);
@@ -850,42 +859,42 @@ export class FeatureTool implements Extension {
850
859
  if (feature.rotation) {
851
860
  shape.rotate(feature.rotation);
852
861
  }
853
-
862
+
854
863
  // Handle Indicator for Bridge
855
864
  if (feature.bridge && feature.bridge.type === "vertical") {
856
- // Create a visual indicator for the bridge
857
- // A dashed rectangle extending upwards
858
- const bridgeIndicator = new Rect({
859
- width: visualWidth,
860
- height: 100 * featureScale, // Arbitrary long length to show direction
861
- fill: "transparent",
862
- stroke: "#888",
863
- strokeWidth: 1,
864
- strokeDashArray: [2, 2],
865
- originX: "center",
866
- originY: "bottom", // Anchor at bottom so it extends up
867
- left: pos.x,
868
- top: pos.y - visualHeight / 2, // Start from top of feature
869
- opacity: 0.5,
870
- selectable: false,
871
- evented: false
872
- });
873
-
874
- // We need to return a group containing both shape and indicator
875
- // But createMarkerShape is expected to return one object.
876
- // If we return a Group, Fabric handles it.
877
- // But the caller might wrap this in another Group if it's part of a feature group.
878
- // Fabric supports nested groups.
879
-
880
- const group = new Group([bridgeIndicator, shape], {
881
- originX: "center",
882
- originY: "center",
883
- left: pos.x,
884
- top: pos.y
885
- });
886
- return group;
865
+ // Create a visual indicator for the bridge
866
+ // A dashed rectangle extending upwards
867
+ const bridgeIndicator = new Rect({
868
+ width: visualWidth,
869
+ height: 100 * featureScale, // Arbitrary long length to show direction
870
+ fill: "transparent",
871
+ stroke: "#888",
872
+ strokeWidth: 1,
873
+ strokeDashArray: [2, 2],
874
+ originX: "center",
875
+ originY: "bottom", // Anchor at bottom so it extends up
876
+ left: pos.x,
877
+ top: pos.y - visualHeight / 2, // Start from top of feature
878
+ opacity: 0.5,
879
+ selectable: false,
880
+ evented: false,
881
+ });
882
+
883
+ // We need to return a group containing both shape and indicator
884
+ // But createMarkerShape is expected to return one object.
885
+ // If we return a Group, Fabric handles it.
886
+ // But the caller might wrap this in another Group if it's part of a feature group.
887
+ // Fabric supports nested groups.
888
+
889
+ const group = new Group([bridgeIndicator, shape], {
890
+ originX: "center",
891
+ originY: "center",
892
+ left: pos.x,
893
+ top: pos.y,
894
+ });
895
+ return group;
887
896
  }
888
-
897
+
889
898
  return shape;
890
899
  };
891
900
 
@@ -990,15 +999,19 @@ export class FeatureTool implements Extension {
990
999
  feature,
991
1000
  );
992
1001
 
993
- const markerStrokeWidth = (marker.strokeWidth || 2) * (marker.scaleX || 1);
994
- const minDim = Math.min(marker.getScaledWidth(), marker.getScaledHeight());
1002
+ const markerStrokeWidth =
1003
+ (marker.strokeWidth || 2) * (marker.scaleX || 1);
1004
+ const minDim = Math.min(
1005
+ marker.getScaledWidth(),
1006
+ marker.getScaledHeight(),
1007
+ );
995
1008
  const limit = Math.max(0, minDim / 2 - markerStrokeWidth);
996
-
1009
+
997
1010
  const snapped = this.constrainPosition(
998
1011
  new Point(marker.left, marker.top),
999
1012
  geometry,
1000
1013
  limit,
1001
- feature
1014
+ feature,
1002
1015
  );
1003
1016
  marker.set({ left: snapped.x, top: snapped.y });
1004
1017
  marker.setCoords();
@@ -6,7 +6,7 @@ import {
6
6
  ConfigurationContribution,
7
7
  } from "@pooder/core";
8
8
  import { FabricImage as Image } from "fabric";
9
- import CanvasService from "./CanvasService";
9
+ import { CanvasService } from "../services";
10
10
 
11
11
  export class FilmTool implements Extension {
12
12
  id = "pooder.kit.film";