canvico-editor 1.0.2 → 2.0.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 (45) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +31 -8
  3. package/dist/CanvicoEditor.d.ts +45 -24
  4. package/dist/CanvicoEditor.d.ts.map +1 -1
  5. package/dist/CanvicoEditor.js +262 -87
  6. package/dist/CanvicoEditor.js.map +1 -1
  7. package/dist/modules/BaseModule.d.ts +5 -4
  8. package/dist/modules/BaseModule.d.ts.map +1 -1
  9. package/dist/modules/BaseModule.js +7 -6
  10. package/dist/modules/BaseModule.js.map +1 -1
  11. package/dist/modules/CropModule.d.ts +32 -31
  12. package/dist/modules/CropModule.d.ts.map +1 -1
  13. package/dist/modules/CropModule.js +147 -106
  14. package/dist/modules/CropModule.js.map +1 -1
  15. package/dist/modules/ResizeModule.d.ts +12 -26
  16. package/dist/modules/ResizeModule.d.ts.map +1 -1
  17. package/dist/modules/ResizeModule.js +27 -35
  18. package/dist/modules/ResizeModule.js.map +1 -1
  19. package/dist/modules/TransformModule.d.ts +38 -0
  20. package/dist/modules/TransformModule.d.ts.map +1 -0
  21. package/dist/modules/TransformModule.js +55 -0
  22. package/dist/modules/TransformModule.js.map +1 -0
  23. package/dist/state/CanvasState.d.ts +34 -0
  24. package/dist/state/CanvasState.d.ts.map +1 -0
  25. package/dist/state/CanvasState.js +67 -0
  26. package/dist/state/CanvasState.js.map +1 -0
  27. package/dist/state/EditorReducer.d.ts +60 -0
  28. package/dist/state/EditorReducer.d.ts.map +1 -0
  29. package/dist/state/EditorReducer.js +127 -0
  30. package/dist/state/EditorReducer.js.map +1 -0
  31. package/dist/types.d.ts +33 -0
  32. package/dist/types.d.ts.map +1 -1
  33. package/dist/utils/dom-manager.d.ts +12 -1
  34. package/dist/utils/dom-manager.d.ts.map +1 -1
  35. package/dist/utils/dom-manager.js +22 -14
  36. package/dist/utils/dom-manager.js.map +1 -1
  37. package/dist/utils/error-handler.d.ts +18 -7
  38. package/dist/utils/error-handler.d.ts.map +1 -1
  39. package/dist/utils/error-handler.js +34 -7
  40. package/dist/utils/error-handler.js.map +1 -1
  41. package/dist/utils/validation.d.ts +0 -7
  42. package/dist/utils/validation.d.ts.map +1 -1
  43. package/dist/utils/validation.js +33 -29
  44. package/dist/utils/validation.js.map +1 -1
  45. package/package.json +6 -4
@@ -1,16 +1,10 @@
1
- import { ErrorHandler as v } from "../utils/error-handler.js";
2
- import { BaseModule as l } from "./BaseModule.js";
3
- class R extends l {
1
+ import { BaseModule as n } from "./BaseModule.js";
2
+ class o extends n {
4
3
  // --- PROPERTIES ---
5
4
  widthInput;
6
5
  heightInput;
7
6
  lockAspectRatio;
8
- container;
9
- canvas;
10
- ctx;
11
- getCurrentImage;
12
- onRequestRedraw;
13
- onCanvasResized;
7
+ state;
14
8
  errorHandler;
15
9
  isActive = !1;
16
10
  /**
@@ -18,8 +12,8 @@ class R extends l {
18
12
  * @param elements - The DOM elements used by the module.
19
13
  * @param options - Configuration and dependencies for the module.
20
14
  */
21
- constructor(e, t) {
22
- super("resize"), this.widthInput = e.widthInput, this.heightInput = e.heightInput, this.lockAspectRatio = e.lockAspectRatio, this.container = t.container, this.canvas = t.canvas, this.ctx = t.ctx, this.getCurrentImage = t.getCurrentImage, this.onRequestRedraw = t.onRequestRedraw, this.onCanvasResized = t.onCanvasResized, this.errorHandler = new v();
15
+ constructor(s, t) {
16
+ super("resize"), this.widthInput = s.widthInput, this.heightInput = s.heightInput, this.lockAspectRatio = s.lockAspectRatio, this.state = t.state, this.errorHandler = t.errorHandler;
23
17
  }
24
18
  /**
25
19
  * Initializes the module by attaching event listeners to the input elements.
@@ -32,6 +26,11 @@ class R extends l {
32
26
  */
33
27
  activate() {
34
28
  this.isActive = !0;
29
+ const s = this.state.getCurrent();
30
+ if (!s)
31
+ return;
32
+ const t = this.state.getResizeState(), i = t.width > 0 ? t.width : s.width, e = t.height > 0 ? t.height : s.height;
33
+ this.widthInput.value = i.toString(), this.heightInput.value = e.toString(), this.lockAspectRatio && (this.lockAspectRatio.checked = t.lockAspectRatio);
35
34
  }
36
35
  /**
37
36
  * Deactivates the resize functionality.
@@ -40,43 +39,36 @@ class R extends l {
40
39
  this.isActive = !1;
41
40
  }
42
41
  /**
43
- * Central function to read inputs, calculate dimensions, and update the canvas.
42
+ * Central function to read inputs, calculate dimensions, and update output state.
44
43
  * @param changedDim - The dimension ('width' or 'height') that initiated the change. If undefined, it's assumed the change came from the aspect ratio toggle.
45
44
  */
46
- _updateCanvasAndInputs(e) {
45
+ _updateCanvasAndInputs(s) {
47
46
  try {
48
47
  if (!this.isActive) return;
49
- const t = this.getCurrentImage();
48
+ const t = this.state.getCurrent();
50
49
  if (!t)
51
50
  return;
52
- let i = parseInt(this.widthInput.value, 10) || 0, a = parseInt(this.heightInput.value, 10) || 0;
51
+ let i = Number.parseInt(this.widthInput.value, 10) || 0, e = Number.parseInt(this.heightInput.value, 10) || 0;
53
52
  if (this.lockAspectRatio?.checked) {
54
- const s = t.width / t.height;
55
- (e || "width") === "width" ? (a = i > 0 ? Math.round(i / s) : 0, this.heightInput.value = a.toString()) : (i = a > 0 ? Math.round(a * s) : 0, this.widthInput.value = i.toString());
53
+ const h = t.width / t.height;
54
+ if (s === "width")
55
+ e = i > 0 ? Math.round(i / h) : 0, this.heightInput.value = e.toString();
56
+ else if (s === "height")
57
+ i = e > 0 ? Math.round(e * h) : 0, this.widthInput.value = i.toString();
58
+ else {
59
+ const a = e > 0 ? i / e : 0;
60
+ Math.abs(a - h) > 0.01 && (e = i > 0 ? Math.round(i / h) : 0, this.heightInput.value = e.toString());
61
+ }
56
62
  }
57
- if (i <= 0 || a <= 0)
63
+ if (i <= 0 || e <= 0)
58
64
  return;
59
- this._redrawCanvas(t, i, a);
65
+ this.state.setResizeState({ width: i, height: e, lockAspectRatio: !!this.lockAspectRatio?.checked });
60
66
  } catch (t) {
61
- this.errorHandler.handle(t);
67
+ this.errorHandler.handle(t, { source: "resize", operation: "update-canvas-and-inputs" });
62
68
  }
63
69
  }
64
- /**
65
- * Handles the actual resizing and redrawing of the canvas.
66
- * @param img - The image to be redrawn.
67
- * @param newWidth - The target width for the image.
68
- * @param newHeight - The target height for the image.
69
- */
70
- _redrawCanvas(e, t, i) {
71
- const a = this.canvas.width, s = this.canvas.height, r = this.container.clientWidth, d = this.container.clientHeight, c = Math.min(r / t, d / i, 1), n = t * c, h = i * c;
72
- if (this.canvas.width = n, this.canvas.height = h, a > 0 && s > 0 && this.onCanvasResized) {
73
- const o = n / a, u = h / s;
74
- this.onCanvasResized(o, u);
75
- }
76
- this.ctx.clearRect(0, 0, n, h), this.ctx.drawImage(e, 0, 0, e.width, e.height, 0, 0, n, h), this.onRequestRedraw?.();
77
- }
78
70
  }
79
71
  export {
80
- R as ResizeModule
72
+ o as ResizeModule
81
73
  };
82
74
  //# sourceMappingURL=ResizeModule.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ResizeModule.js","sources":["../../src/modules/ResizeModule.ts"],"sourcesContent":["import { ErrorHandler } from \"./../utils/error-handler.js\";\r\nimport type { ResizeDOMElements } from \"../utils/dom-manager.js\";\r\nimport { BaseModule } from \"./BaseModule.js\";\r\n\r\n/**\r\n * Configuration options for the ResizeModule.\r\n */\r\nexport interface ResizeModuleOptions {\r\n container: HTMLElement;\r\n canvas: HTMLCanvasElement;\r\n ctx: CanvasRenderingContext2D;\r\n getCurrentImage: () => HTMLImageElement | undefined;\r\n onRequestRedraw?: () => void;\r\n onCanvasResized?: (scaleX: number, scaleY: number) => void;\r\n}\r\n\r\n/**\r\n * A module responsible for handling image and canvas resizing based on user input.\r\n * It maintains aspect ratio if requested and ensures the canvas fits within its container.\r\n */\r\nexport class ResizeModule extends BaseModule {\r\n // --- PROPERTIES ---\r\n\r\n private widthInput: HTMLInputElement;\r\n private heightInput: HTMLInputElement;\r\n private lockAspectRatio?: HTMLInputElement;\r\n\r\n private container: HTMLElement;\r\n private canvas: HTMLCanvasElement;\r\n private ctx: CanvasRenderingContext2D;\r\n private getCurrentImage: () => HTMLImageElement | undefined;\r\n private onRequestRedraw?: () => void;\r\n private onCanvasResized?: (scaleX: number, scaleY: number) => void;\r\n\r\n private errorHandler: ErrorHandler;\r\n private isActive: boolean = false;\r\n\r\n /**\r\n * Creates an instance of the ResizeModule.\r\n * @param elements - The DOM elements used by the module.\r\n * @param options - Configuration and dependencies for the module.\r\n */\r\n constructor(elements: ResizeDOMElements, options: ResizeModuleOptions) {\r\n super(\"resize\");\r\n this.widthInput = elements.widthInput;\r\n this.heightInput = elements.heightInput;\r\n this.lockAspectRatio = elements.lockAspectRatio;\r\n\r\n this.container = options.container;\r\n this.canvas = options.canvas;\r\n this.ctx = options.ctx;\r\n this.getCurrentImage = options.getCurrentImage;\r\n this.onRequestRedraw = options.onRequestRedraw;\r\n this.onCanvasResized = options.onCanvasResized;\r\n\r\n this.errorHandler = new ErrorHandler();\r\n }\r\n\r\n /**\r\n * Initializes the module by attaching event listeners to the input elements.\r\n */\r\n public init(): void {\r\n this.addEventListener(this.widthInput, \"input\", () => this._updateCanvasAndInputs(\"width\"));\r\n this.addEventListener(this.heightInput, \"input\", () => this._updateCanvasAndInputs(\"height\"));\r\n if (this.lockAspectRatio) {\r\n this.addEventListener(this.lockAspectRatio, \"change\", () => this._updateCanvasAndInputs());\r\n }\r\n }\r\n\r\n /**\r\n * Activates the resize functionality.\r\n */\r\n public activate(): void {\r\n this.isActive = true;\r\n }\r\n\r\n /**\r\n * Deactivates the resize functionality.\r\n */\r\n public deactivate(): void {\r\n this.isActive = false;\r\n }\r\n\r\n /**\r\n * Central function to read inputs, calculate dimensions, and update the canvas.\r\n * @param changedDim - The dimension ('width' or 'height') that initiated the change. If undefined, it's assumed the change came from the aspect ratio toggle.\r\n */\r\n private _updateCanvasAndInputs(changedDim?: \"width\" | \"height\"): void {\r\n try {\r\n if (!this.isActive) return;\r\n\r\n const img = this.getCurrentImage();\r\n if (!img) {\r\n return;\r\n }\r\n\r\n let w = parseInt(this.widthInput.value, 10) || 0;\r\n let h = parseInt(this.heightInput.value, 10) || 0;\r\n\r\n if (this.lockAspectRatio?.checked) {\r\n const ratio = img.width / img.height;\r\n\r\n /**\r\n * If not specified which dimension changed (e.g., from the aspect ratio toggle),\r\n * default to width as the source of truth.\r\n */\r\n const sourceDim = changedDim || \"width\";\r\n\r\n if (sourceDim === \"width\") {\r\n h = w > 0 ? Math.round(w / ratio) : 0;\r\n this.heightInput.value = h.toString();\r\n } else {\r\n // sourceDim === \"height\"\r\n w = h > 0 ? Math.round(h * ratio) : 0;\r\n this.widthInput.value = w.toString();\r\n }\r\n }\r\n\r\n if (w <= 0 || h <= 0) {\r\n return;\r\n }\r\n\r\n this._redrawCanvas(img, w, h);\r\n } catch (error) {\r\n this.errorHandler.handle(error as Error);\r\n }\r\n }\r\n\r\n /**\r\n * Handles the actual resizing and redrawing of the canvas.\r\n * @param img - The image to be redrawn.\r\n * @param newWidth - The target width for the image.\r\n * @param newHeight - The target height for the image.\r\n */\r\n private _redrawCanvas(img: HTMLImageElement, newWidth: number, newHeight: number): void {\r\n const oldCanvasWidth = this.canvas.width;\r\n const oldCanvasHeight = this.canvas.height;\r\n\r\n // Calculate the scale to fit the canvas to the container\r\n const containerWidth = this.container.clientWidth;\r\n const containerHeight = this.container.clientHeight;\r\n const scaleToFitContainer = Math.min(containerWidth / newWidth, containerHeight / newHeight, 1);\r\n\r\n const finalCanvasWidth = newWidth * scaleToFitContainer;\r\n const finalCanvasHeight = newHeight * scaleToFitContainer;\r\n\r\n // Set the new canvas size\r\n this.canvas.width = finalCanvasWidth;\r\n this.canvas.height = finalCanvasHeight;\r\n\r\n // Notify other modules about the resize\r\n if (oldCanvasWidth > 0 && oldCanvasHeight > 0 && this.onCanvasResized) {\r\n const actualScaleX = finalCanvasWidth / oldCanvasWidth;\r\n const actualScaleY = finalCanvasHeight / oldCanvasHeight;\r\n this.onCanvasResized(actualScaleX, actualScaleY);\r\n }\r\n\r\n // Clear and redraw the image at the new size\r\n this.ctx.clearRect(0, 0, finalCanvasWidth, finalCanvasHeight);\r\n this.ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, finalCanvasWidth, finalCanvasHeight);\r\n\r\n // Request a redraw of overlays (e.g., crop handles, text)\r\n this.onRequestRedraw?.();\r\n }\r\n}\r\n"],"names":["ResizeModule","BaseModule","elements","options","ErrorHandler","changedDim","img","w","h","ratio","error","newWidth","newHeight","oldCanvasWidth","oldCanvasHeight","containerWidth","containerHeight","scaleToFitContainer","finalCanvasWidth","finalCanvasHeight","actualScaleX","actualScaleY"],"mappings":"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"}
1
+ {"version":3,"file":"ResizeModule.js","sources":["../../src/modules/ResizeModule.ts"],"sourcesContent":["import { ErrorHandler } from \"./../utils/error-handler.js\";\r\nimport type { ResizeDOMElements } from \"../utils/dom-manager.js\";\r\nimport { CanvasState } from \"../state/CanvasState.js\";\r\nimport { BaseModule } from \"./BaseModule.js\";\r\n\r\n/**\r\n * Configuration options for the ResizeModule.\r\n */\r\nexport interface ResizeModuleOptions {\r\n state: CanvasState;\r\n errorHandler: ErrorHandler;\r\n}\r\n\r\n/**\r\n * A module responsible for handling output image dimensions based on user input.\r\n * The editor computes preview canvas size separately from this module.\r\n */\r\nexport class ResizeModule extends BaseModule {\r\n // --- PROPERTIES ---\r\n\r\n private readonly widthInput: HTMLInputElement;\r\n private readonly heightInput: HTMLInputElement;\r\n private readonly lockAspectRatio?: HTMLInputElement;\r\n\r\n private readonly state: CanvasState;\r\n\r\n private readonly errorHandler: ErrorHandler;\r\n private isActive = false;\r\n\r\n /**\r\n * Creates an instance of the ResizeModule.\r\n * @param elements - The DOM elements used by the module.\r\n * @param options - Configuration and dependencies for the module.\r\n */\r\n constructor(elements: ResizeDOMElements, options: ResizeModuleOptions) {\r\n super(\"resize\");\r\n this.widthInput = elements.widthInput;\r\n this.heightInput = elements.heightInput;\r\n this.lockAspectRatio = elements.lockAspectRatio;\r\n\r\n this.state = options.state;\r\n this.errorHandler = options.errorHandler;\r\n }\r\n\r\n /**\r\n * Initializes the module by attaching event listeners to the input elements.\r\n */\r\n public init(): void {\r\n this.addEventListener(this.widthInput, \"input\", () => this._updateCanvasAndInputs(\"width\"));\r\n this.addEventListener(this.heightInput, \"input\", () => this._updateCanvasAndInputs(\"height\"));\r\n if (this.lockAspectRatio) {\r\n this.addEventListener(this.lockAspectRatio, \"change\", () => this._updateCanvasAndInputs());\r\n }\r\n }\r\n\r\n /**\r\n * Activates the resize functionality.\r\n */\r\n public activate(): void {\r\n this.isActive = true;\r\n\r\n const img = this.state.getCurrent();\r\n if (!img) {\r\n return;\r\n }\r\n\r\n const resizeState = this.state.getResizeState();\r\n const currentWidth = resizeState.width > 0 ? resizeState.width : img.width;\r\n const currentHeight = resizeState.height > 0 ? resizeState.height : img.height;\r\n\r\n this.widthInput.value = currentWidth.toString();\r\n this.heightInput.value = currentHeight.toString();\r\n if (this.lockAspectRatio) {\r\n this.lockAspectRatio.checked = resizeState.lockAspectRatio;\r\n }\r\n }\r\n\r\n /**\r\n * Deactivates the resize functionality.\r\n */\r\n public deactivate(): void {\r\n this.isActive = false;\r\n }\r\n\r\n /**\r\n * Central function to read inputs, calculate dimensions, and update output state.\r\n * @param changedDim - The dimension ('width' or 'height') that initiated the change. If undefined, it's assumed the change came from the aspect ratio toggle.\r\n */\r\n private _updateCanvasAndInputs(changedDim?: \"width\" | \"height\"): void {\r\n try {\r\n if (!this.isActive) return;\r\n\r\n const img = this.state.getCurrent();\r\n if (!img) {\r\n return;\r\n }\r\n\r\n let w = Number.parseInt(this.widthInput.value, 10) || 0;\r\n let h = Number.parseInt(this.heightInput.value, 10) || 0;\r\n\r\n if (this.lockAspectRatio?.checked) {\r\n // Keep ratio in output/document space based on the current image dimensions.\r\n // Preview canvas size may differ because it is fit to the container.\r\n const ratio = img.width / img.height;\r\n\r\n // If an input is being changed while the lock is on, that input is the source of truth.\r\n if (changedDim === \"width\") {\r\n h = w > 0 ? Math.round(w / ratio) : 0;\r\n this.heightInput.value = h.toString();\r\n } else if (changedDim === \"height\") {\r\n w = h > 0 ? Math.round(h * ratio) : 0;\r\n this.widthInput.value = w.toString();\r\n } else {\r\n // This block is for when the checkbox is just checked.\r\n // We check if the current dimensions are proportional. If not, we enforce the ratio.\r\n // We use the current width as the source of truth and recalculate the height,\r\n // as requested in the user scenario.\r\n const currentRatio = h > 0 ? w / h : 0;\r\n // Using a small tolerance for floating point comparisons\r\n if (Math.abs(currentRatio - ratio) > 0.01) {\r\n h = w > 0 ? Math.round(w / ratio) : 0;\r\n this.heightInput.value = h.toString();\r\n }\r\n }\r\n }\r\n\r\n if (w <= 0 || h <= 0) {\r\n return;\r\n }\r\n\r\n this.state.setResizeState({ width: w, height: h, lockAspectRatio: !!this.lockAspectRatio?.checked });\r\n } catch (error) {\r\n this.errorHandler.handle(error, { source: \"resize\", operation: \"update-canvas-and-inputs\" });\r\n }\r\n }\r\n}\r\n"],"names":["ResizeModule","BaseModule","elements","options","img","resizeState","currentWidth","currentHeight","changedDim","w","h","ratio","currentRatio","error"],"mappings":";AAiBO,MAAMA,UAAqBC,EAAW;AAAA;AAAA,EAGxB;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EAEA;AAAA,EACT,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOnB,YAAYC,GAA6BC,GAA8B;AACnE,UAAM,QAAQ,GACd,KAAK,aAAaD,EAAS,YAC3B,KAAK,cAAcA,EAAS,aAC5B,KAAK,kBAAkBA,EAAS,iBAEhC,KAAK,QAAQC,EAAQ,OACrB,KAAK,eAAeA,EAAQ;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKO,OAAa;AAChB,SAAK,iBAAiB,KAAK,YAAY,SAAS,MAAM,KAAK,uBAAuB,OAAO,CAAC,GAC1F,KAAK,iBAAiB,KAAK,aAAa,SAAS,MAAM,KAAK,uBAAuB,QAAQ,CAAC,GACxF,KAAK,mBACL,KAAK,iBAAiB,KAAK,iBAAiB,UAAU,MAAM,KAAK,wBAAwB;AAAA,EAEjG;AAAA;AAAA;AAAA;AAAA,EAKO,WAAiB;AACpB,SAAK,WAAW;AAEhB,UAAMC,IAAM,KAAK,MAAM,WAAA;AACvB,QAAI,CAACA;AACD;AAGJ,UAAMC,IAAc,KAAK,MAAM,eAAA,GACzBC,IAAeD,EAAY,QAAQ,IAAIA,EAAY,QAAQD,EAAI,OAC/DG,IAAgBF,EAAY,SAAS,IAAIA,EAAY,SAASD,EAAI;AAExE,SAAK,WAAW,QAAQE,EAAa,SAAA,GACrC,KAAK,YAAY,QAAQC,EAAc,SAAA,GACnC,KAAK,oBACL,KAAK,gBAAgB,UAAUF,EAAY;AAAA,EAEnD;AAAA;AAAA;AAAA;AAAA,EAKO,aAAmB;AACtB,SAAK,WAAW;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,uBAAuBG,GAAuC;AAClE,QAAI;AACA,UAAI,CAAC,KAAK,SAAU;AAEpB,YAAMJ,IAAM,KAAK,MAAM,WAAA;AACvB,UAAI,CAACA;AACD;AAGJ,UAAIK,IAAI,OAAO,SAAS,KAAK,WAAW,OAAO,EAAE,KAAK,GAClDC,IAAI,OAAO,SAAS,KAAK,YAAY,OAAO,EAAE,KAAK;AAEvD,UAAI,KAAK,iBAAiB,SAAS;AAG/B,cAAMC,IAAQP,EAAI,QAAQA,EAAI;AAG9B,YAAII,MAAe;AACf,UAAAE,IAAID,IAAI,IAAI,KAAK,MAAMA,IAAIE,CAAK,IAAI,GACpC,KAAK,YAAY,QAAQD,EAAE,SAAA;AAAA,iBACpBF,MAAe;AACtB,UAAAC,IAAIC,IAAI,IAAI,KAAK,MAAMA,IAAIC,CAAK,IAAI,GACpC,KAAK,WAAW,QAAQF,EAAE,SAAA;AAAA,aACvB;AAKH,gBAAMG,IAAeF,IAAI,IAAID,IAAIC,IAAI;AAErC,UAAI,KAAK,IAAIE,IAAeD,CAAK,IAAI,SACjCD,IAAID,IAAI,IAAI,KAAK,MAAMA,IAAIE,CAAK,IAAI,GACpC,KAAK,YAAY,QAAQD,EAAE,SAAA;AAAA,QAEnC;AAAA,MACJ;AAEA,UAAID,KAAK,KAAKC,KAAK;AACf;AAGJ,WAAK,MAAM,eAAe,EAAE,OAAOD,GAAG,QAAQC,GAAG,iBAAiB,CAAC,CAAC,KAAK,iBAAiB,SAAS;AAAA,IACvG,SAASG,GAAO;AACZ,WAAK,aAAa,OAAOA,GAAO,EAAE,QAAQ,UAAU,WAAW,4BAA4B;AAAA,IAC/F;AAAA,EACJ;AACJ;"}
@@ -0,0 +1,38 @@
1
+ import { TransformDOMElements } from '../utils/dom-manager.js';
2
+ import { CanvasState } from '../state/CanvasState.js';
3
+ import { BaseModule } from './BaseModule.js';
4
+ /**
5
+ * Configuration options for the TransformModule.
6
+ */
7
+ export interface TransformModuleOptions {
8
+ state: CanvasState;
9
+ }
10
+ /**
11
+ * A module for applying geometric transforms (rotate, flip)
12
+ * to the current image.
13
+ */
14
+ export declare class TransformModule extends BaseModule {
15
+ private readonly rotateInput?;
16
+ private readonly flipHorizontalButton?;
17
+ private readonly flipVerticalButton?;
18
+ private readonly state;
19
+ private isActive;
20
+ constructor(elements: TransformDOMElements, options: TransformModuleOptions);
21
+ init(): void;
22
+ /**
23
+ * Activates the module. Captures the current image as the base for transformations.
24
+ */
25
+ activate(): void;
26
+ /**
27
+ * Deactivates the module.
28
+ */
29
+ deactivate(): void;
30
+ /**
31
+ * Synchronizes transform controls with the current store state.
32
+ * Useful when state changes happen outside direct module interactions.
33
+ */
34
+ syncControlsWithState(): void;
35
+ private _readNumber;
36
+ private _syncControlsWithState;
37
+ }
38
+ //# sourceMappingURL=TransformModule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TransformModule.d.ts","sourceRoot":"","sources":["../../src/modules/TransformModule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACnC,KAAK,EAAE,WAAW,CAAC;CACtB;AAED;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,UAAU;IAC3C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAmB;IAChD,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAoB;IAC1D,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAoB;IAExD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAc;IACpC,OAAO,CAAC,QAAQ,CAAS;gBAEb,QAAQ,EAAE,oBAAoB,EAAE,OAAO,EAAE,sBAAsB;IASpE,IAAI,IAAI,IAAI;IA4BnB;;OAEG;IACI,QAAQ,IAAI,IAAI;IAKvB;;OAEG;IACI,UAAU,IAAI,IAAI;IAIzB;;;OAGG;IACI,qBAAqB,IAAI,IAAI;IAIpC,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,sBAAsB;CAIjC"}
@@ -0,0 +1,55 @@
1
+ import { BaseModule as e } from "./BaseModule.js";
2
+ class a extends e {
3
+ rotateInput;
4
+ flipHorizontalButton;
5
+ flipVerticalButton;
6
+ state;
7
+ isActive = !1;
8
+ constructor(t, i) {
9
+ super("transform"), this.state = i.state, this.rotateInput = t.rotateInput, this.flipHorizontalButton = t.flipHorizontalButton, this.flipVerticalButton = t.flipVerticalButton;
10
+ }
11
+ init() {
12
+ this.rotateInput && this.addEventListener(this.rotateInput, "input", () => {
13
+ this.isActive && this.state.setTransformState({ rotate: this._readNumber(this.rotateInput) });
14
+ }), this.flipHorizontalButton && this.addEventListener(this.flipHorizontalButton, "click", () => {
15
+ if (!this.isActive) return;
16
+ const t = this.state.getTransformState();
17
+ this.state.setTransformState({ flipH: !t.flipH });
18
+ }), this.flipVerticalButton && this.addEventListener(this.flipVerticalButton, "click", () => {
19
+ if (!this.isActive) return;
20
+ const t = this.state.getTransformState();
21
+ this.state.setTransformState({ flipV: !t.flipV });
22
+ });
23
+ }
24
+ /**
25
+ * Activates the module. Captures the current image as the base for transformations.
26
+ */
27
+ activate() {
28
+ this.isActive = !0, this._syncControlsWithState();
29
+ }
30
+ /**
31
+ * Deactivates the module.
32
+ */
33
+ deactivate() {
34
+ this.isActive = !1;
35
+ }
36
+ /**
37
+ * Synchronizes transform controls with the current store state.
38
+ * Useful when state changes happen outside direct module interactions.
39
+ */
40
+ syncControlsWithState() {
41
+ this._syncControlsWithState();
42
+ }
43
+ _readNumber(t) {
44
+ const i = Number.parseFloat(t.value);
45
+ return Number.isFinite(i) ? i : 0;
46
+ }
47
+ _syncControlsWithState() {
48
+ const t = this.state.getTransformState();
49
+ this.rotateInput && (this.rotateInput.value = t.rotate.toString());
50
+ }
51
+ }
52
+ export {
53
+ a as TransformModule
54
+ };
55
+ //# sourceMappingURL=TransformModule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TransformModule.js","sources":["../../src/modules/TransformModule.ts"],"sourcesContent":["import type { TransformDOMElements } from \"../utils/dom-manager.js\";\r\nimport { CanvasState } from \"../state/CanvasState.js\";\r\nimport { BaseModule } from \"./BaseModule.js\";\r\n\r\n/**\r\n * Configuration options for the TransformModule.\r\n */\r\nexport interface TransformModuleOptions {\r\n state: CanvasState;\r\n}\r\n\r\n/**\r\n * A module for applying geometric transforms (rotate, flip)\r\n * to the current image.\r\n */\r\nexport class TransformModule extends BaseModule {\r\n private readonly rotateInput?: HTMLInputElement;\r\n private readonly flipHorizontalButton?: HTMLButtonElement;\r\n private readonly flipVerticalButton?: HTMLButtonElement;\r\n\r\n private readonly state: CanvasState;\r\n private isActive = false;\r\n\r\n constructor(elements: TransformDOMElements, options: TransformModuleOptions) {\r\n super(\"transform\");\r\n\r\n this.state = options.state;\r\n this.rotateInput = elements.rotateInput;\r\n this.flipHorizontalButton = elements.flipHorizontalButton;\r\n this.flipVerticalButton = elements.flipVerticalButton;\r\n }\r\n\r\n public init(): void {\r\n // Rotate\r\n if (this.rotateInput) {\r\n this.addEventListener(this.rotateInput, \"input\", () => {\r\n if (!this.isActive) return;\r\n this.state.setTransformState({ rotate: this._readNumber(this.rotateInput!) });\r\n });\r\n }\r\n\r\n // Flip Horizontal\r\n if (this.flipHorizontalButton) {\r\n this.addEventListener(this.flipHorizontalButton, \"click\", () => {\r\n if (!this.isActive) return;\r\n const current = this.state.getTransformState();\r\n this.state.setTransformState({ flipH: !current.flipH });\r\n });\r\n }\r\n\r\n // Flip Vertical\r\n if (this.flipVerticalButton) {\r\n this.addEventListener(this.flipVerticalButton, \"click\", () => {\r\n if (!this.isActive) return;\r\n const current = this.state.getTransformState();\r\n this.state.setTransformState({ flipV: !current.flipV });\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Activates the module. Captures the current image as the base for transformations.\r\n */\r\n public activate(): void {\r\n this.isActive = true;\r\n this._syncControlsWithState();\r\n }\r\n\r\n /**\r\n * Deactivates the module.\r\n */\r\n public deactivate(): void {\r\n this.isActive = false;\r\n }\r\n\r\n /**\r\n * Synchronizes transform controls with the current store state.\r\n * Useful when state changes happen outside direct module interactions.\r\n */\r\n public syncControlsWithState(): void {\r\n this._syncControlsWithState();\r\n }\r\n\r\n private _readNumber(input: HTMLInputElement): number {\r\n const value = Number.parseFloat(input.value);\r\n return Number.isFinite(value) ? value : 0;\r\n }\r\n\r\n private _syncControlsWithState(): void {\r\n const current = this.state.getTransformState();\r\n if (this.rotateInput) this.rotateInput.value = current.rotate.toString();\r\n }\r\n}\r\n"],"names":["TransformModule","BaseModule","elements","options","current","input","value"],"mappings":";AAeO,MAAMA,UAAwBC,EAAW;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACT,WAAW;AAAA,EAEnB,YAAYC,GAAgCC,GAAiC;AACzE,UAAM,WAAW,GAEjB,KAAK,QAAQA,EAAQ,OACrB,KAAK,cAAcD,EAAS,aAC5B,KAAK,uBAAuBA,EAAS,sBACrC,KAAK,qBAAqBA,EAAS;AAAA,EACvC;AAAA,EAEO,OAAa;AAEhB,IAAI,KAAK,eACL,KAAK,iBAAiB,KAAK,aAAa,SAAS,MAAM;AACnD,MAAK,KAAK,YACV,KAAK,MAAM,kBAAkB,EAAE,QAAQ,KAAK,YAAY,KAAK,WAAY,GAAG;AAAA,IAChF,CAAC,GAID,KAAK,wBACL,KAAK,iBAAiB,KAAK,sBAAsB,SAAS,MAAM;AAC5D,UAAI,CAAC,KAAK,SAAU;AACpB,YAAME,IAAU,KAAK,MAAM,kBAAA;AAC3B,WAAK,MAAM,kBAAkB,EAAE,OAAO,CAACA,EAAQ,OAAO;AAAA,IAC1D,CAAC,GAID,KAAK,sBACL,KAAK,iBAAiB,KAAK,oBAAoB,SAAS,MAAM;AAC1D,UAAI,CAAC,KAAK,SAAU;AACpB,YAAMA,IAAU,KAAK,MAAM,kBAAA;AAC3B,WAAK,MAAM,kBAAkB,EAAE,OAAO,CAACA,EAAQ,OAAO;AAAA,IAC1D,CAAC;AAAA,EAET;AAAA;AAAA;AAAA;AAAA,EAKO,WAAiB;AACpB,SAAK,WAAW,IAChB,KAAK,uBAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKO,aAAmB;AACtB,SAAK,WAAW;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,wBAA8B;AACjC,SAAK,uBAAA;AAAA,EACT;AAAA,EAEQ,YAAYC,GAAiC;AACjD,UAAMC,IAAQ,OAAO,WAAWD,EAAM,KAAK;AAC3C,WAAO,OAAO,SAASC,CAAK,IAAIA,IAAQ;AAAA,EAC5C;AAAA,EAEQ,yBAA+B;AACnC,UAAMF,IAAU,KAAK,MAAM,kBAAA;AAC3B,IAAI,KAAK,gBAAa,KAAK,YAAY,QAAQA,EAAQ,OAAO,SAAA;AAAA,EAClE;AACJ;"}
@@ -0,0 +1,34 @@
1
+ import { CanvasAction, CanvasStateChange, CropRect, CropState, EditorMode, ResizeState, TransformState } from './EditorReducer.js';
2
+ export type { CanvasAction, CanvasStateChange, CropHandle, CropRect, CropState, EditorMode, EditorSnapshot, ResizeState, TransformState } from './EditorReducer.js';
3
+ export type ReadonlyResizeState = Readonly<ResizeState>;
4
+ export type ReadonlyTransformState = Readonly<TransformState>;
5
+ export type ReadonlyCropRect = Readonly<CropRect>;
6
+ export type ReadonlyCropState = Readonly<Omit<CropState, "rect">> & {
7
+ readonly rect: ReadonlyCropRect;
8
+ };
9
+ /**
10
+ * Store wrapper around the pure reducer.
11
+ * It keeps listeners and exposes compatibility methods for modules.
12
+ */
13
+ export declare class CanvasState {
14
+ private snapshot;
15
+ private listeners;
16
+ getInitial(): HTMLImageElement | undefined;
17
+ getCurrent(): HTMLImageElement | undefined;
18
+ getMode(): EditorMode;
19
+ getResizeState(): ReadonlyResizeState;
20
+ getTransformState(): ReadonlyTransformState;
21
+ getCropState(): ReadonlyCropState;
22
+ dispatch(action: CanvasAction): void;
23
+ setMode(mode: EditorMode): void;
24
+ setInitial(img: HTMLImageElement): void;
25
+ setCurrent(img: HTMLImageElement): void;
26
+ resetToInitial(): void;
27
+ clear(): void;
28
+ setResizeState(state: Partial<ResizeState>): void;
29
+ setTransformState(state: Partial<TransformState>): void;
30
+ setCropState(state: Partial<CropState>): void;
31
+ subscribe(listener: (change: CanvasStateChange) => void): () => void;
32
+ private _notifyListeners;
33
+ }
34
+ //# sourceMappingURL=CanvasState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CanvasState.d.ts","sourceRoot":"","sources":["../../src/state/CanvasState.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACR,YAAY,EACZ,iBAAiB,EACjB,QAAQ,EACR,SAAS,EACT,UAAU,EAEV,WAAW,EACX,cAAc,EACjB,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpK,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;AACxD,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC,cAAc,CAAC,CAAC;AAC9D,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAClD,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAExG;;;GAGG;AACH,qBAAa,WAAW;IACpB,OAAO,CAAC,QAAQ,CAAiD;IACjE,OAAO,CAAC,SAAS,CAAkD;IAE5D,UAAU,IAAI,gBAAgB,GAAG,SAAS;IAI1C,UAAU,IAAI,gBAAgB,GAAG,SAAS;IAI1C,OAAO,IAAI,UAAU;IAIrB,cAAc,IAAI,mBAAmB;IAIrC,iBAAiB,IAAI,sBAAsB;IAI3C,YAAY,IAAI,iBAAiB;IAQjC,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IASpC,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI;IAI/B,UAAU,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI;IAIvC,UAAU,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI;IAIvC,cAAc,IAAI,IAAI;IAItB,KAAK,IAAI,IAAI;IAIb,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI;IAIjD,iBAAiB,CAAC,KAAK,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI;IAIvD,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,IAAI;IAI7C,SAAS,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,GAAG,MAAM,IAAI;IAO3E,OAAO,CAAC,gBAAgB;CAG3B"}
@@ -0,0 +1,67 @@
1
+ import { createInitialEditorSnapshot as s, reduceEditorState as i } from "./EditorReducer.js";
2
+ class h {
3
+ snapshot = s();
4
+ listeners = [];
5
+ getInitial() {
6
+ return this.snapshot.initialImage;
7
+ }
8
+ getCurrent() {
9
+ return this.snapshot.currentImage;
10
+ }
11
+ getMode() {
12
+ return this.snapshot.mode;
13
+ }
14
+ getResizeState() {
15
+ return { ...this.snapshot.resizeState };
16
+ }
17
+ getTransformState() {
18
+ return { ...this.snapshot.transformState };
19
+ }
20
+ getCropState() {
21
+ const t = this.snapshot.cropState;
22
+ return {
23
+ ...t,
24
+ rect: { ...t.rect }
25
+ };
26
+ }
27
+ dispatch(t) {
28
+ const e = i(this.snapshot, t);
29
+ e.change && (this.snapshot = e.snapshot, this._notifyListeners(e.change));
30
+ }
31
+ setMode(t) {
32
+ this.dispatch({ type: "mode/set", mode: t });
33
+ }
34
+ setInitial(t) {
35
+ this.dispatch({ type: "image/setInitial", image: t });
36
+ }
37
+ setCurrent(t) {
38
+ this.dispatch({ type: "image/setCurrent", image: t });
39
+ }
40
+ resetToInitial() {
41
+ this.dispatch({ type: "image/resetToInitial" });
42
+ }
43
+ clear() {
44
+ this.dispatch({ type: "editor/clear" });
45
+ }
46
+ setResizeState(t) {
47
+ this.dispatch({ type: "resize/patch", patch: t });
48
+ }
49
+ setTransformState(t) {
50
+ this.dispatch({ type: "transform/patch", patch: t });
51
+ }
52
+ setCropState(t) {
53
+ this.dispatch({ type: "crop/patch", patch: t });
54
+ }
55
+ subscribe(t) {
56
+ return this.listeners.push(t), () => {
57
+ this.listeners = this.listeners.filter((e) => e !== t);
58
+ };
59
+ }
60
+ _notifyListeners(t) {
61
+ this.listeners.forEach((e) => e(t));
62
+ }
63
+ }
64
+ export {
65
+ h as CanvasState
66
+ };
67
+ //# sourceMappingURL=CanvasState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CanvasState.js","sources":["../../src/state/CanvasState.ts"],"sourcesContent":["import { createInitialEditorSnapshot, reduceEditorState } from \"./EditorReducer.js\";\r\nimport type {\r\n CanvasAction,\r\n CanvasStateChange,\r\n CropRect,\r\n CropState,\r\n EditorMode,\r\n EditorSnapshot,\r\n ResizeState,\r\n TransformState,\r\n} from \"./EditorReducer.js\";\r\n\r\nexport type { CanvasAction, CanvasStateChange, CropHandle, CropRect, CropState, EditorMode, EditorSnapshot, ResizeState, TransformState } from \"./EditorReducer.js\";\r\nexport type ReadonlyResizeState = Readonly<ResizeState>;\r\nexport type ReadonlyTransformState = Readonly<TransformState>;\r\nexport type ReadonlyCropRect = Readonly<CropRect>;\r\nexport type ReadonlyCropState = Readonly<Omit<CropState, \"rect\">> & { readonly rect: ReadonlyCropRect };\r\n\r\n/**\r\n * Store wrapper around the pure reducer.\r\n * It keeps listeners and exposes compatibility methods for modules.\r\n */\r\nexport class CanvasState {\r\n private snapshot: EditorSnapshot = createInitialEditorSnapshot();\r\n private listeners: Array<(change: CanvasStateChange) => void> = [];\r\n\r\n public getInitial(): HTMLImageElement | undefined {\r\n return this.snapshot.initialImage;\r\n }\r\n\r\n public getCurrent(): HTMLImageElement | undefined {\r\n return this.snapshot.currentImage;\r\n }\r\n\r\n public getMode(): EditorMode {\r\n return this.snapshot.mode;\r\n }\r\n\r\n public getResizeState(): ReadonlyResizeState {\r\n return { ...this.snapshot.resizeState };\r\n }\r\n\r\n public getTransformState(): ReadonlyTransformState {\r\n return { ...this.snapshot.transformState };\r\n }\r\n\r\n public getCropState(): ReadonlyCropState {\r\n const cropState = this.snapshot.cropState;\r\n return {\r\n ...cropState,\r\n rect: { ...cropState.rect },\r\n };\r\n }\r\n\r\n public dispatch(action: CanvasAction): void {\r\n const result = reduceEditorState(this.snapshot, action);\r\n if (!result.change) {\r\n return;\r\n }\r\n this.snapshot = result.snapshot;\r\n this._notifyListeners(result.change);\r\n }\r\n\r\n public setMode(mode: EditorMode): void {\r\n this.dispatch({ type: \"mode/set\", mode });\r\n }\r\n\r\n public setInitial(img: HTMLImageElement): void {\r\n this.dispatch({ type: \"image/setInitial\", image: img });\r\n }\r\n\r\n public setCurrent(img: HTMLImageElement): void {\r\n this.dispatch({ type: \"image/setCurrent\", image: img });\r\n }\r\n\r\n public resetToInitial(): void {\r\n this.dispatch({ type: \"image/resetToInitial\" });\r\n }\r\n\r\n public clear(): void {\r\n this.dispatch({ type: \"editor/clear\" });\r\n }\r\n\r\n public setResizeState(state: Partial<ResizeState>): void {\r\n this.dispatch({ type: \"resize/patch\", patch: state });\r\n }\r\n\r\n public setTransformState(state: Partial<TransformState>): void {\r\n this.dispatch({ type: \"transform/patch\", patch: state });\r\n }\r\n\r\n public setCropState(state: Partial<CropState>): void {\r\n this.dispatch({ type: \"crop/patch\", patch: state });\r\n }\r\n\r\n public subscribe(listener: (change: CanvasStateChange) => void): () => void {\r\n this.listeners.push(listener);\r\n return () => {\r\n this.listeners = this.listeners.filter((registered) => registered !== listener);\r\n };\r\n }\r\n\r\n private _notifyListeners(change: CanvasStateChange): void {\r\n this.listeners.forEach((listener) => listener(change));\r\n }\r\n}\r\n"],"names":["CanvasState","createInitialEditorSnapshot","cropState","action","result","reduceEditorState","mode","img","state","listener","registered","change"],"mappings":";AAsBO,MAAMA,EAAY;AAAA,EACb,WAA2BC,EAAA;AAAA,EAC3B,YAAwD,CAAA;AAAA,EAEzD,aAA2C;AAC9C,WAAO,KAAK,SAAS;AAAA,EACzB;AAAA,EAEO,aAA2C;AAC9C,WAAO,KAAK,SAAS;AAAA,EACzB;AAAA,EAEO,UAAsB;AACzB,WAAO,KAAK,SAAS;AAAA,EACzB;AAAA,EAEO,iBAAsC;AACzC,WAAO,EAAE,GAAG,KAAK,SAAS,YAAA;AAAA,EAC9B;AAAA,EAEO,oBAA4C;AAC/C,WAAO,EAAE,GAAG,KAAK,SAAS,eAAA;AAAA,EAC9B;AAAA,EAEO,eAAkC;AACrC,UAAMC,IAAY,KAAK,SAAS;AAChC,WAAO;AAAA,MACH,GAAGA;AAAA,MACH,MAAM,EAAE,GAAGA,EAAU,KAAA;AAAA,IAAK;AAAA,EAElC;AAAA,EAEO,SAASC,GAA4B;AACxC,UAAMC,IAASC,EAAkB,KAAK,UAAUF,CAAM;AACtD,IAAKC,EAAO,WAGZ,KAAK,WAAWA,EAAO,UACvB,KAAK,iBAAiBA,EAAO,MAAM;AAAA,EACvC;AAAA,EAEO,QAAQE,GAAwB;AACnC,SAAK,SAAS,EAAE,MAAM,YAAY,MAAAA,GAAM;AAAA,EAC5C;AAAA,EAEO,WAAWC,GAA6B;AAC3C,SAAK,SAAS,EAAE,MAAM,oBAAoB,OAAOA,GAAK;AAAA,EAC1D;AAAA,EAEO,WAAWA,GAA6B;AAC3C,SAAK,SAAS,EAAE,MAAM,oBAAoB,OAAOA,GAAK;AAAA,EAC1D;AAAA,EAEO,iBAAuB;AAC1B,SAAK,SAAS,EAAE,MAAM,uBAAA,CAAwB;AAAA,EAClD;AAAA,EAEO,QAAc;AACjB,SAAK,SAAS,EAAE,MAAM,eAAA,CAAgB;AAAA,EAC1C;AAAA,EAEO,eAAeC,GAAmC;AACrD,SAAK,SAAS,EAAE,MAAM,gBAAgB,OAAOA,GAAO;AAAA,EACxD;AAAA,EAEO,kBAAkBA,GAAsC;AAC3D,SAAK,SAAS,EAAE,MAAM,mBAAmB,OAAOA,GAAO;AAAA,EAC3D;AAAA,EAEO,aAAaA,GAAiC;AACjD,SAAK,SAAS,EAAE,MAAM,cAAc,OAAOA,GAAO;AAAA,EACtD;AAAA,EAEO,UAAUC,GAA2D;AACxE,gBAAK,UAAU,KAAKA,CAAQ,GACrB,MAAM;AACT,WAAK,YAAY,KAAK,UAAU,OAAO,CAACC,MAAeA,MAAeD,CAAQ;AAAA,IAClF;AAAA,EACJ;AAAA,EAEQ,iBAAiBE,GAAiC;AACtD,SAAK,UAAU,QAAQ,CAACF,MAAaA,EAASE,CAAM,CAAC;AAAA,EACzD;AACJ;"}
@@ -0,0 +1,60 @@
1
+ export type ResizeState = {
2
+ width: number;
3
+ height: number;
4
+ lockAspectRatio: boolean;
5
+ };
6
+ export type TransformState = {
7
+ rotate: number;
8
+ flipH: boolean;
9
+ flipV: boolean;
10
+ };
11
+ export type CropHandle = "nw" | "ne" | "sw" | "se" | "rect" | null;
12
+ export type CropRect = {
13
+ x: number;
14
+ y: number;
15
+ w: number;
16
+ h: number;
17
+ };
18
+ export type CropState = {
19
+ active: boolean;
20
+ rect: CropRect;
21
+ };
22
+ export type EditorMode = "edit" | "crop";
23
+ export type CanvasStateChange = "image" | "resize" | "transform" | "crop" | "mode" | "clear";
24
+ export type CanvasAction = {
25
+ type: "mode/set";
26
+ mode: EditorMode;
27
+ } | {
28
+ type: "image/setInitial";
29
+ image: HTMLImageElement;
30
+ } | {
31
+ type: "image/setCurrent";
32
+ image: HTMLImageElement;
33
+ } | {
34
+ type: "image/resetToInitial";
35
+ } | {
36
+ type: "editor/clear";
37
+ } | {
38
+ type: "resize/patch";
39
+ patch: Partial<ResizeState>;
40
+ } | {
41
+ type: "transform/patch";
42
+ patch: Partial<TransformState>;
43
+ } | {
44
+ type: "crop/patch";
45
+ patch: Partial<CropState>;
46
+ };
47
+ export type EditorSnapshot = {
48
+ initialImage?: HTMLImageElement;
49
+ currentImage?: HTMLImageElement;
50
+ mode: EditorMode;
51
+ resizeState: ResizeState;
52
+ transformState: TransformState;
53
+ cropState: CropState;
54
+ };
55
+ export declare function createInitialEditorSnapshot(): EditorSnapshot;
56
+ export declare function reduceEditorState(snapshot: EditorSnapshot, action: CanvasAction): {
57
+ snapshot: EditorSnapshot;
58
+ change: CanvasStateChange | null;
59
+ };
60
+ //# sourceMappingURL=EditorReducer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EditorReducer.d.ts","sourceRoot":"","sources":["../../src/state/EditorReducer.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAAC;AAEnE,MAAM,MAAM,QAAQ,GAAG;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,QAAQ,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC;AAEzC,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE7F,MAAM,MAAM,YAAY,GAClB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,KAAK,EAAE,gBAAgB,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,KAAK,EAAE,gBAAgB,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,sBAAsB,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC,cAAc,CAAC,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,CAAA;CAAE,CAAC;AAExD,MAAM,MAAM,cAAc,GAAG;IACzB,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,IAAI,EAAE,UAAU,CAAC;IACjB,WAAW,EAAE,WAAW,CAAC;IACzB,cAAc,EAAE,cAAc,CAAC;IAC/B,SAAS,EAAE,SAAS,CAAC;CACxB,CAAC;AAEF,wBAAgB,2BAA2B,IAAI,cAAc,CAS5D;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,GAAG;IAAE,QAAQ,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAA;CAAE,CA6EhJ"}
@@ -0,0 +1,127 @@
1
+ function n() {
2
+ return {
3
+ initialImage: void 0,
4
+ currentImage: void 0,
5
+ mode: "edit",
6
+ resizeState: a(),
7
+ transformState: i(),
8
+ cropState: c()
9
+ };
10
+ }
11
+ function p(e, t) {
12
+ switch (t.type) {
13
+ case "mode/set":
14
+ return e.mode === t.mode ? { snapshot: e, change: null } : {
15
+ snapshot: { ...e, mode: t.mode },
16
+ change: "mode"
17
+ };
18
+ case "image/setInitial":
19
+ return {
20
+ snapshot: {
21
+ ...e,
22
+ initialImage: t.image,
23
+ currentImage: t.image,
24
+ mode: "edit",
25
+ resizeState: a(t.image.width, t.image.height),
26
+ transformState: i(),
27
+ cropState: c()
28
+ },
29
+ change: "image"
30
+ };
31
+ case "image/setCurrent":
32
+ return e.currentImage === t.image ? { snapshot: e, change: null } : {
33
+ snapshot: {
34
+ ...e,
35
+ currentImage: t.image
36
+ },
37
+ change: "image"
38
+ };
39
+ case "image/resetToInitial":
40
+ return e.initialImage ? {
41
+ snapshot: {
42
+ ...e,
43
+ currentImage: e.initialImage,
44
+ mode: "edit",
45
+ resizeState: a(e.initialImage.width, e.initialImage.height),
46
+ transformState: i(),
47
+ cropState: c()
48
+ },
49
+ change: "image"
50
+ } : { snapshot: e, change: null };
51
+ case "editor/clear":
52
+ return {
53
+ snapshot: n(),
54
+ change: "clear"
55
+ };
56
+ case "resize/patch":
57
+ return u(e) ? m(e, t.patch) : { snapshot: e, change: null };
58
+ case "transform/patch":
59
+ return l(e) ? g(e, t.patch) : { snapshot: e, change: null };
60
+ case "crop/patch":
61
+ return f(e, t.patch) ? o(e, t.patch) : { snapshot: e, change: null };
62
+ }
63
+ }
64
+ function u(e) {
65
+ return e.mode !== "crop";
66
+ }
67
+ function l(e) {
68
+ return e.mode !== "crop";
69
+ }
70
+ function f(e, t) {
71
+ return e.mode === "crop" ? !0 : t.active === !1;
72
+ }
73
+ function m(e, t) {
74
+ const r = { ...e.resizeState, ...t };
75
+ return S(r, e.resizeState) ? { snapshot: e, change: null } : {
76
+ snapshot: { ...e, resizeState: r },
77
+ change: "resize"
78
+ };
79
+ }
80
+ function g(e, t) {
81
+ const r = { ...e.transformState, ...t };
82
+ return d(r, e.transformState) ? { snapshot: e, change: null } : {
83
+ snapshot: { ...e, transformState: r },
84
+ change: "transform"
85
+ };
86
+ }
87
+ function o(e, t) {
88
+ const r = { ...e.cropState, ...t };
89
+ return h(r, e.cropState) ? { snapshot: e, change: null } : {
90
+ snapshot: { ...e, cropState: r },
91
+ change: "crop"
92
+ };
93
+ }
94
+ function S(e, t) {
95
+ return e.width === t.width && e.height === t.height && e.lockAspectRatio === t.lockAspectRatio;
96
+ }
97
+ function d(e, t) {
98
+ return e.rotate === t.rotate && e.flipH === t.flipH && e.flipV === t.flipV;
99
+ }
100
+ function h(e, t) {
101
+ return e.active === t.active && e.rect.x === t.rect.x && e.rect.y === t.rect.y && e.rect.w === t.rect.w && e.rect.h === t.rect.h;
102
+ }
103
+ function a(e = 0, t = 0) {
104
+ return {
105
+ width: e,
106
+ height: t,
107
+ lockAspectRatio: !1
108
+ };
109
+ }
110
+ function i() {
111
+ return {
112
+ rotate: 0,
113
+ flipH: !1,
114
+ flipV: !1
115
+ };
116
+ }
117
+ function c() {
118
+ return {
119
+ active: !1,
120
+ rect: { x: 0, y: 0, w: 0, h: 0 }
121
+ };
122
+ }
123
+ export {
124
+ n as createInitialEditorSnapshot,
125
+ p as reduceEditorState
126
+ };
127
+ //# sourceMappingURL=EditorReducer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EditorReducer.js","sources":["../../src/state/EditorReducer.ts"],"sourcesContent":["export type ResizeState = {\r\n width: number;\r\n height: number;\r\n lockAspectRatio: boolean;\r\n};\r\n\r\nexport type TransformState = {\r\n rotate: number;\r\n flipH: boolean;\r\n flipV: boolean;\r\n};\r\n\r\nexport type CropHandle = \"nw\" | \"ne\" | \"sw\" | \"se\" | \"rect\" | null;\r\n\r\nexport type CropRect = {\r\n x: number;\r\n y: number;\r\n w: number;\r\n h: number;\r\n};\r\n\r\nexport type CropState = {\r\n active: boolean;\r\n rect: CropRect;\r\n};\r\n\r\nexport type EditorMode = \"edit\" | \"crop\";\r\n\r\nexport type CanvasStateChange = \"image\" | \"resize\" | \"transform\" | \"crop\" | \"mode\" | \"clear\";\r\n\r\nexport type CanvasAction =\r\n | { type: \"mode/set\"; mode: EditorMode }\r\n | { type: \"image/setInitial\"; image: HTMLImageElement }\r\n | { type: \"image/setCurrent\"; image: HTMLImageElement }\r\n | { type: \"image/resetToInitial\" }\r\n | { type: \"editor/clear\" }\r\n | { type: \"resize/patch\"; patch: Partial<ResizeState> }\r\n | { type: \"transform/patch\"; patch: Partial<TransformState> }\r\n | { type: \"crop/patch\"; patch: Partial<CropState> };\r\n\r\nexport type EditorSnapshot = {\r\n initialImage?: HTMLImageElement;\r\n currentImage?: HTMLImageElement;\r\n mode: EditorMode;\r\n resizeState: ResizeState;\r\n transformState: TransformState;\r\n cropState: CropState;\r\n};\r\n\r\nexport function createInitialEditorSnapshot(): EditorSnapshot {\r\n return {\r\n initialImage: undefined,\r\n currentImage: undefined,\r\n mode: \"edit\",\r\n resizeState: createDefaultResizeState(),\r\n transformState: createDefaultTransformState(),\r\n cropState: createDefaultCropState(),\r\n };\r\n}\r\n\r\nexport function reduceEditorState(snapshot: EditorSnapshot, action: CanvasAction): { snapshot: EditorSnapshot; change: CanvasStateChange | null } {\r\n switch (action.type) {\r\n case \"mode/set\":\r\n if (snapshot.mode === action.mode) {\r\n return { snapshot, change: null };\r\n }\r\n return {\r\n snapshot: { ...snapshot, mode: action.mode },\r\n change: \"mode\",\r\n };\r\n\r\n case \"image/setInitial\":\r\n return {\r\n snapshot: {\r\n ...snapshot,\r\n initialImage: action.image,\r\n currentImage: action.image,\r\n mode: \"edit\",\r\n resizeState: createDefaultResizeState(action.image.width, action.image.height),\r\n transformState: createDefaultTransformState(),\r\n cropState: createDefaultCropState(),\r\n },\r\n change: \"image\",\r\n };\r\n\r\n case \"image/setCurrent\":\r\n if (snapshot.currentImage === action.image) {\r\n return { snapshot, change: null };\r\n }\r\n return {\r\n snapshot: {\r\n ...snapshot,\r\n currentImage: action.image,\r\n },\r\n change: \"image\",\r\n };\r\n\r\n case \"image/resetToInitial\":\r\n if (!snapshot.initialImage) {\r\n return { snapshot, change: null };\r\n }\r\n return {\r\n snapshot: {\r\n ...snapshot,\r\n currentImage: snapshot.initialImage,\r\n mode: \"edit\",\r\n resizeState: createDefaultResizeState(snapshot.initialImage.width, snapshot.initialImage.height),\r\n transformState: createDefaultTransformState(),\r\n cropState: createDefaultCropState(),\r\n },\r\n change: \"image\",\r\n };\r\n\r\n case \"editor/clear\":\r\n return {\r\n snapshot: createInitialEditorSnapshot(),\r\n change: \"clear\",\r\n };\r\n\r\n case \"resize/patch\":\r\n if (!canApplyResizePatch(snapshot)) {\r\n return { snapshot, change: null };\r\n }\r\n return applyResizePatch(snapshot, action.patch);\r\n\r\n case \"transform/patch\":\r\n if (!canApplyTransformPatch(snapshot)) {\r\n return { snapshot, change: null };\r\n }\r\n return applyTransformPatch(snapshot, action.patch);\r\n\r\n case \"crop/patch\":\r\n if (!canApplyCropPatch(snapshot, action.patch)) {\r\n return { snapshot, change: null };\r\n }\r\n return applyCropPatch(snapshot, action.patch);\r\n }\r\n}\r\n\r\nfunction canApplyResizePatch(snapshot: EditorSnapshot): boolean {\r\n return snapshot.mode !== \"crop\";\r\n}\r\n\r\nfunction canApplyTransformPatch(snapshot: EditorSnapshot): boolean {\r\n return snapshot.mode !== \"crop\";\r\n}\r\n\r\nfunction canApplyCropPatch(snapshot: EditorSnapshot, patch: Partial<CropState>): boolean {\r\n if (snapshot.mode === \"crop\") {\r\n return true;\r\n }\r\n\r\n return patch.active === false;\r\n}\r\n\r\nfunction applyResizePatch(snapshot: EditorSnapshot, patch: Partial<ResizeState>): { snapshot: EditorSnapshot; change: CanvasStateChange | null } {\r\n const nextResize = { ...snapshot.resizeState, ...patch };\r\n if (isResizeStateEqual(nextResize, snapshot.resizeState)) {\r\n return { snapshot, change: null };\r\n }\r\n return {\r\n snapshot: { ...snapshot, resizeState: nextResize },\r\n change: \"resize\",\r\n };\r\n}\r\n\r\nfunction applyTransformPatch(snapshot: EditorSnapshot, patch: Partial<TransformState>): { snapshot: EditorSnapshot; change: CanvasStateChange | null } {\r\n const nextTransform = { ...snapshot.transformState, ...patch };\r\n if (isTransformStateEqual(nextTransform, snapshot.transformState)) {\r\n return { snapshot, change: null };\r\n }\r\n return {\r\n snapshot: { ...snapshot, transformState: nextTransform },\r\n change: \"transform\",\r\n };\r\n}\r\n\r\nfunction applyCropPatch(snapshot: EditorSnapshot, patch: Partial<CropState>): { snapshot: EditorSnapshot; change: CanvasStateChange | null } {\r\n const nextCrop = { ...snapshot.cropState, ...patch };\r\n if (isCropStateEqual(nextCrop, snapshot.cropState)) {\r\n return { snapshot, change: null };\r\n }\r\n return {\r\n snapshot: { ...snapshot, cropState: nextCrop },\r\n change: \"crop\",\r\n };\r\n}\r\n\r\nfunction isResizeStateEqual(a: ResizeState, b: ResizeState): boolean {\r\n return a.width === b.width && a.height === b.height && a.lockAspectRatio === b.lockAspectRatio;\r\n}\r\n\r\nfunction isTransformStateEqual(a: TransformState, b: TransformState): boolean {\r\n return a.rotate === b.rotate && a.flipH === b.flipH && a.flipV === b.flipV;\r\n}\r\n\r\nfunction isCropStateEqual(a: CropState, b: CropState): boolean {\r\n return (\r\n a.active === b.active &&\r\n a.rect.x === b.rect.x &&\r\n a.rect.y === b.rect.y &&\r\n a.rect.w === b.rect.w &&\r\n a.rect.h === b.rect.h\r\n );\r\n}\r\n\r\nfunction createDefaultResizeState(width: number = 0, height: number = 0): ResizeState {\r\n return {\r\n width,\r\n height,\r\n lockAspectRatio: false,\r\n };\r\n}\r\n\r\nfunction createDefaultTransformState(): TransformState {\r\n return {\r\n rotate: 0,\r\n flipH: false,\r\n flipV: false,\r\n };\r\n}\r\n\r\nfunction createDefaultCropState(): CropState {\r\n return {\r\n active: false,\r\n rect: { x: 0, y: 0, w: 0, h: 0 },\r\n };\r\n}\r\n"],"names":["createInitialEditorSnapshot","createDefaultResizeState","createDefaultTransformState","createDefaultCropState","reduceEditorState","snapshot","action","canApplyResizePatch","applyResizePatch","canApplyTransformPatch","applyTransformPatch","canApplyCropPatch","applyCropPatch","patch","nextResize","isResizeStateEqual","nextTransform","isTransformStateEqual","nextCrop","isCropStateEqual","a","b","width","height"],"mappings":"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"}