@bensitu/image-editor 1.5.1 → 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 (154) hide show
  1. package/README.md +370 -466
  2. package/dist/cjs/index.cjs +5422 -0
  3. package/dist/cjs/index.cjs.map +1 -0
  4. package/dist/esm/animation/animation-queue.js +67 -0
  5. package/dist/esm/animation/animation-queue.js.map +1 -0
  6. package/dist/esm/core/callback-reporter.js +23 -0
  7. package/dist/esm/core/callback-reporter.js.map +1 -0
  8. package/dist/esm/core/default-options.js +322 -0
  9. package/dist/esm/core/default-options.js.map +1 -0
  10. package/dist/esm/core/errors.js +156 -0
  11. package/dist/esm/core/errors.js.map +1 -0
  12. package/dist/esm/core/operation-guard.js +129 -0
  13. package/dist/esm/core/operation-guard.js.map +1 -0
  14. package/dist/esm/core/public-types.js +4 -0
  15. package/dist/esm/core/public-types.js.map +1 -0
  16. package/dist/esm/core/state-serializer.js +251 -0
  17. package/dist/esm/core/state-serializer.js.map +1 -0
  18. package/dist/esm/crop/crop-controller.js +403 -0
  19. package/dist/esm/crop/crop-controller.js.map +1 -0
  20. package/dist/esm/export/export-format.js +53 -0
  21. package/dist/esm/export/export-format.js.map +1 -0
  22. package/dist/esm/export/export-service.js +596 -0
  23. package/dist/esm/export/export-service.js.map +1 -0
  24. package/dist/esm/fabric/fabric-adapter.js +37 -0
  25. package/dist/esm/fabric/fabric-adapter.js.map +1 -0
  26. package/dist/esm/fabric/fabric-animation.js +37 -0
  27. package/dist/esm/fabric/fabric-animation.js.map +1 -0
  28. package/dist/esm/history/command.js +2 -0
  29. package/dist/esm/history/command.js.map +1 -0
  30. package/dist/esm/history/history-manager.js +103 -0
  31. package/dist/esm/history/history-manager.js.map +1 -0
  32. package/dist/esm/image/image-loader.js +245 -0
  33. package/dist/esm/image/image-loader.js.map +1 -0
  34. package/dist/esm/image/image-resampler.js +55 -0
  35. package/dist/esm/image/image-resampler.js.map +1 -0
  36. package/dist/esm/image/layout-manager.js +224 -0
  37. package/dist/esm/image/layout-manager.js.map +1 -0
  38. package/dist/esm/image/transform-controller.js +132 -0
  39. package/dist/esm/image/transform-controller.js.map +1 -0
  40. package/dist/esm/image-editor.js +1740 -0
  41. package/dist/esm/image-editor.js.map +1 -0
  42. package/dist/esm/index.js +5 -0
  43. package/dist/esm/index.js.map +1 -0
  44. package/dist/esm/mask/mask-factory.js +332 -0
  45. package/dist/esm/mask/mask-factory.js.map +1 -0
  46. package/dist/esm/mask/mask-label-manager.js +120 -0
  47. package/dist/esm/mask/mask-label-manager.js.map +1 -0
  48. package/dist/esm/mask/mask-list.js +47 -0
  49. package/dist/esm/mask/mask-list.js.map +1 -0
  50. package/dist/esm/mask/mask-style.js +182 -0
  51. package/dist/esm/mask/mask-style.js.map +1 -0
  52. package/dist/esm/ui/dom-bindings.js +60 -0
  53. package/dist/esm/ui/dom-bindings.js.map +1 -0
  54. package/dist/esm/ui/ui-state.js +25 -0
  55. package/dist/esm/ui/ui-state.js.map +1 -0
  56. package/dist/esm/ui/visibility-state.js +11 -0
  57. package/dist/esm/ui/visibility-state.js.map +1 -0
  58. package/dist/esm/utils/canvas-region.js +100 -0
  59. package/dist/esm/utils/canvas-region.js.map +1 -0
  60. package/dist/esm/utils/dom.js +6 -0
  61. package/dist/esm/utils/dom.js.map +1 -0
  62. package/dist/esm/utils/file.js +53 -0
  63. package/dist/esm/utils/file.js.map +1 -0
  64. package/dist/esm/utils/number.js +24 -0
  65. package/dist/esm/utils/number.js.map +1 -0
  66. package/dist/esm/utils/timeout.js +17 -0
  67. package/dist/esm/utils/timeout.js.map +1 -0
  68. package/dist/types/animation/animation-queue.d.ts +111 -0
  69. package/dist/types/animation/animation-queue.d.ts.map +1 -0
  70. package/dist/types/core/callback-reporter.d.ts +125 -0
  71. package/dist/types/core/callback-reporter.d.ts.map +1 -0
  72. package/dist/types/core/default-options.d.ts +56 -0
  73. package/dist/types/core/default-options.d.ts.map +1 -0
  74. package/dist/types/core/errors.d.ts +142 -0
  75. package/dist/types/core/errors.d.ts.map +1 -0
  76. package/dist/types/core/operation-guard.d.ts +192 -0
  77. package/dist/types/core/operation-guard.d.ts.map +1 -0
  78. package/dist/types/core/public-types.d.ts +678 -0
  79. package/dist/types/core/public-types.d.ts.map +1 -0
  80. package/dist/types/core/state-serializer.d.ts +301 -0
  81. package/dist/types/core/state-serializer.d.ts.map +1 -0
  82. package/dist/types/crop/crop-controller.d.ts +407 -0
  83. package/dist/types/crop/crop-controller.d.ts.map +1 -0
  84. package/dist/types/export/export-format.d.ts +136 -0
  85. package/dist/types/export/export-format.d.ts.map +1 -0
  86. package/dist/types/export/export-service.d.ts +333 -0
  87. package/dist/types/export/export-service.d.ts.map +1 -0
  88. package/dist/types/fabric/fabric-adapter.d.ts +74 -0
  89. package/dist/types/fabric/fabric-adapter.d.ts.map +1 -0
  90. package/dist/types/fabric/fabric-animation.d.ts +141 -0
  91. package/dist/types/fabric/fabric-animation.d.ts.map +1 -0
  92. package/dist/types/history/command.d.ts +16 -0
  93. package/dist/types/history/command.d.ts.map +1 -0
  94. package/dist/types/history/history-manager.d.ts +129 -0
  95. package/dist/types/history/history-manager.d.ts.map +1 -0
  96. package/dist/types/image/image-loader.d.ts +265 -0
  97. package/dist/types/image/image-loader.d.ts.map +1 -0
  98. package/dist/types/image/image-resampler.d.ts +139 -0
  99. package/dist/types/image/image-resampler.d.ts.map +1 -0
  100. package/dist/types/image/layout-manager.d.ts +255 -0
  101. package/dist/types/image/layout-manager.d.ts.map +1 -0
  102. package/dist/types/image/transform-controller.d.ts +287 -0
  103. package/dist/types/image/transform-controller.d.ts.map +1 -0
  104. package/dist/types/image-editor.d.ts +650 -0
  105. package/dist/types/image-editor.d.ts.map +1 -0
  106. package/dist/types/index.d.cts +31 -0
  107. package/dist/types/index.d.cts.map +1 -0
  108. package/dist/types/index.d.ts +31 -0
  109. package/dist/types/index.d.ts.map +1 -0
  110. package/dist/types/mask/mask-factory.d.ts +209 -0
  111. package/dist/types/mask/mask-factory.d.ts.map +1 -0
  112. package/dist/types/mask/mask-label-manager.d.ts +171 -0
  113. package/dist/types/mask/mask-label-manager.d.ts.map +1 -0
  114. package/dist/types/mask/mask-list.d.ts +144 -0
  115. package/dist/types/mask/mask-list.d.ts.map +1 -0
  116. package/dist/types/mask/mask-style.d.ts +338 -0
  117. package/dist/types/mask/mask-style.d.ts.map +1 -0
  118. package/dist/types/ui/dom-bindings.d.ts +103 -0
  119. package/dist/types/ui/dom-bindings.d.ts.map +1 -0
  120. package/dist/types/ui/ui-state.d.ts +112 -0
  121. package/dist/types/ui/ui-state.d.ts.map +1 -0
  122. package/dist/types/ui/visibility-state.d.ts +77 -0
  123. package/dist/types/ui/visibility-state.d.ts.map +1 -0
  124. package/dist/types/utils/canvas-region.d.ts +177 -0
  125. package/dist/types/utils/canvas-region.d.ts.map +1 -0
  126. package/dist/types/utils/dom.d.ts +26 -0
  127. package/dist/types/utils/dom.d.ts.map +1 -0
  128. package/dist/types/utils/file.d.ts +80 -0
  129. package/dist/types/utils/file.d.ts.map +1 -0
  130. package/dist/types/utils/number.d.ts +132 -0
  131. package/dist/types/utils/number.d.ts.map +1 -0
  132. package/dist/types/utils/timeout.d.ts +84 -0
  133. package/dist/types/utils/timeout.d.ts.map +1 -0
  134. package/dist/umd/image-editor.umd.js +2 -0
  135. package/dist/umd/image-editor.umd.js.map +1 -0
  136. package/package.json +72 -66
  137. package/dist/image-editor.cjs +0 -4185
  138. package/dist/image-editor.cjs.map +0 -7
  139. package/dist/image-editor.esm.js +0 -4154
  140. package/dist/image-editor.esm.js.map +0 -7
  141. package/dist/image-editor.esm.min.js +0 -9
  142. package/dist/image-editor.esm.min.js.map +0 -7
  143. package/dist/image-editor.esm.min.mjs +0 -9
  144. package/dist/image-editor.esm.min.mjs.map +0 -7
  145. package/dist/image-editor.esm.mjs +0 -4154
  146. package/dist/image-editor.esm.mjs.map +0 -7
  147. package/dist/image-editor.js +0 -4151
  148. package/dist/image-editor.js.map +0 -7
  149. package/dist/image-editor.min.js +0 -9
  150. package/dist/image-editor.min.js.map +0 -7
  151. package/image-editor.d.ts +0 -269
  152. package/src/browser.js +0 -11
  153. package/src/esm.js +0 -9
  154. package/src/image-editor.js +0 -4775
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Pure helpers that turn floating-point Fabric.js bounding
3
+ * rectangles into integer pixel regions and provide the
4
+ * bounding-box math that mask preservation across crop and
5
+ * export paths share.
6
+ *
7
+ * ## Owned contracts
8
+ *
9
+ * - Export regions SHALL include partially covered trailing pixels so
10
+ * sub-pixel image bounds do not lose the right or bottom edge.
11
+ * - Crop regions SHALL exclude trailing partial pixels so crop does not
12
+ * grow by a transparent row or column.
13
+ * - When `applyCrop` runs with
14
+ * `preserveMasksAfterCrop === true` and the image has been rotated,
15
+ * each mask's new `left` and `top` SHALL be expressed in the cropped
16
+ * image's coordinate frame using the rotation angle.
17
+ * - Across a crop apply, each mask's `angle`,
18
+ * `scaleX`, and `scaleY` SHALL be preserved so the visible shape does
19
+ * not change size or orientation.
20
+ *
21
+ * ## Why a dedicated module
22
+ *
23
+ * Region math is shared by export, crop, expand-to-image sizing, and crop
24
+ * rectangle initialization. Centralizing it prevents one call site from
25
+ * drifting from the others (for example, applying `Math.floor` instead of
26
+ * `Math.round`, or forgetting the `width >= 1` floor).
27
+ *
28
+ * ## Design notes
29
+ *
30
+ * - Region floors are total: any non-finite input collapses to a
31
+ * `1×1` region anchored at `(0, 0)` rather than throwing. The export
32
+ * and crop pipelines already validate the presence of an
33
+ * `originalImage` upstream, so a defensive fallback here keeps the
34
+ * `<canvas>.drawImage` call from being passed `NaN` if Fabric ever
35
+ * reports a degenerate bounding rect.
36
+ * - `getObjectBBox` calls `setCoords` before reading the bounding
37
+ * rect because Fabric.js v7's `getBoundingRect` returns the cached
38
+ * absolute rect; without the refresh a freshly-mutated mask returns
39
+ * stale coordinates. Callers that have already refreshed coords pay
40
+ * only a single redundant call, which is cheaper than double-tracking
41
+ * "is this object's cache fresh?" at every site.
42
+ * - `clampRegionToCanvas` exists for the crop pipeline, where the crop
43
+ * rectangle's bounding rect can briefly exceed the canvas after a
44
+ * user drag near the edge; clamping before the `drawImage` keeps the
45
+ * blit inside the source canvas.
46
+ *
47
+ * ## Non-goals
48
+ *
49
+ * - This module does not perform any coordinate transformation between
50
+ * pre-crop and post-crop frames; the rotation math for the
51
+ * rotated-mask coordinate frame lives in `crop/crop-controller.ts`,
52
+ * which uses
53
+ * `getObjectBBox` here only as one input to that calculation.
54
+ * - This module does not mutate the Fabric object passed to
55
+ * `getObjectBBox` beyond the `setCoords` refresh required by
56
+ * Fabric.js v7's API.
57
+ *
58
+ * @module
59
+ */
60
+ import type * as FabricNS from 'fabric';
61
+ /**
62
+ * A canvas region whose `left` / `top` / `width` / `height` are all
63
+ * integer pixels suitable for `CanvasRenderingContext2D.drawImage` and
64
+ * Fabric.js `toDataURL({ left, top, width, height})`.
65
+ *
66
+ * Produced by {@link floorRegion} and {@link clampRegionToCanvas}; the
67
+ * `width` and `height` fields are guaranteed to be at least `1` so
68
+ * region exports never collapse to a zero-pixel image.
69
+ */
70
+ export interface IntegerRegion {
71
+ left: number;
72
+ top: number;
73
+ width: number;
74
+ height: number;
75
+ }
76
+ export interface RegionRoundingOptions {
77
+ /**
78
+ * When true, `right` / `bottom` are ceiled to include partially covered
79
+ * trailing pixels. When false, they are floored to exclude them.
80
+ * @default true
81
+ */
82
+ includePartialPixels?: boolean;
83
+ }
84
+ export interface PartialExportEdges {
85
+ left: boolean;
86
+ top: boolean;
87
+ right: boolean;
88
+ bottom: boolean;
89
+ }
90
+ export declare function hasMeaningfulCanvasRegion(rect: {
91
+ left: number;
92
+ top: number;
93
+ width: number;
94
+ height: number;
95
+ }, canvasWidth?: number, canvasHeight?: number): boolean;
96
+ /**
97
+ * Convert a floating-point rectangle into an {@link IntegerRegion}.
98
+ *
99
+ * - `left` / `top` are floored and clamped to `>= 0` so the region
100
+ * never starts before the source canvas's top-left corner.
101
+ * - `right` / `bottom` are ceiled by default to include partially covered
102
+ * trailing pixels, or floored when `includePartialPixels` is false.
103
+ * - `width` / `height` are derived from those integer edges and clamped
104
+ * to `>= 1` so no sub-pixel dimensions reach Fabric's region export.
105
+ * - Non-finite inputs collapse to a `1×1` region at `(0, 0)` rather than
106
+ * propagating `NaN` into the canvas pipeline.
107
+ *
108
+ * region floor before mask remapping).
109
+ *
110
+ * @param rect - The floating-point bounding rect to discretize.
111
+ * @returns An {@link IntegerRegion} safe to pass to `drawImage`.
112
+ */
113
+ export declare function getClampedCanvasRegion(rect: {
114
+ left: number;
115
+ top: number;
116
+ width: number;
117
+ height: number;
118
+ }, canvasWidth?: number, canvasHeight?: number, options?: RegionRoundingOptions): IntegerRegion;
119
+ export declare function floorRegion(rect: {
120
+ left: number;
121
+ top: number;
122
+ width: number;
123
+ height: number;
124
+ }): IntegerRegion;
125
+ export declare function hasFractionalCanvasEdge(value: number): boolean;
126
+ export declare function getPartialExportEdges(bounds: {
127
+ left: number;
128
+ top: number;
129
+ width: number;
130
+ height: number;
131
+ } | null, angle?: number): PartialExportEdges | null;
132
+ /**
133
+ * Read a Fabric.js object's absolute bounding rectangle in canvas-pixel
134
+ * coordinates.
135
+ *
136
+ * `setCoords` is called first because Fabric.js v7's
137
+ * `getBoundingRect` returns the cached absolute rect — the per-frame
138
+ * cache the canvas already maintains. Without the refresh a freshly
139
+ * mutated mask returns stale coordinates, which can make rotated masks
140
+ * drift after crop.
141
+ *
142
+ * The returned rect uses floating-point coordinates; callers that need
143
+ * integer pixel regions should pipe the result through
144
+ * {@link floorRegion}.
145
+ *
146
+ * @param object - The Fabric.js object to measure.
147
+ * @returns The absolute bounding rect in canvas pixels.
148
+ */
149
+ export declare function getObjectBBox(object: FabricNS.FabricObject): {
150
+ left: number;
151
+ top: number;
152
+ width: number;
153
+ height: number;
154
+ };
155
+ /**
156
+ * Clamp an {@link IntegerRegion} so it fits entirely inside a canvas of
157
+ * `canvasWidth × canvasHeight` pixels.
158
+ *
159
+ * - `left` is clamped to `[0, canvasWidth - 1]`.
160
+ * - `top` is clamped to `[0, canvasHeight - 1]`.
161
+ * - `width` is clamped so `left + width <= canvasWidth`.
162
+ * - `height` is clamped so `top + height <= canvasHeight`.
163
+ *
164
+ * The function preserves the `width >= 1` / `height >= 1` invariant
165
+ * established by {@link floorRegion}, which keeps callers from having
166
+ * to special-case zero-sized regions when the supplied rect lands
167
+ * entirely outside the canvas.
168
+ *
169
+ * canvas before the mask coordinate remap).
170
+ *
171
+ * @param region - The integer region to clamp.
172
+ * @param canvasWidth - The source canvas's pixel width.
173
+ * @param canvasHeight - The source canvas's pixel height.
174
+ * @returns A clamped {@link IntegerRegion}.
175
+ */
176
+ export declare function clampRegionToCanvas(region: IntegerRegion, canvasWidth: number, canvasHeight: number): IntegerRegion;
177
+ //# sourceMappingURL=canvas-region.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas-region.d.ts","sourceRoot":"","sources":["../../../src/utils/canvas-region.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AAEH,OAAO,KAAK,KAAK,QAAQ,MAAM,QAAQ,CAAC;AAExC;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAa;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IAClC;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,kBAAkB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,yBAAyB,CACrC,IAAI,EAAE;IACF,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAClB,EACD,WAAW,CAAC,EAAE,MAAM,EACpB,YAAY,CAAC,EAAE,MAAM,GACtB,OAAO,CAkCT;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAClC,IAAI,EAAE;IACF,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAClB,EACD,WAAW,CAAC,EAAE,MAAM,EACpB,YAAY,CAAC,EAAE,MAAM,EACrB,OAAO,GAAE,qBAA0B,GACpC,aAAa,CA4Bf;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAClB,GAAG,aAAa,CAEhB;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAI9D;AAED,wBAAgB,qBAAqB,CACjC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,EAC3E,KAAK,SAAI,GACV,kBAAkB,GAAG,IAAI,CAc3B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,YAAY,GAAG;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAClB,CASA;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,mBAAmB,CAC/B,MAAM,EAAE,aAAa,EACrB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACrB,aAAa,CASf"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * DOM micro-helpers used by sizing and visibility flows.
3
+ *
4
+ * Kept intentionally small: the editor depends on a single synchronous
5
+ * reflow primitive after canvas dimension changes, and exposing it as a
6
+ * named utility lets layout, visibility, and crop flows share the same
7
+ * documented contract.
8
+ */
9
+ /**
10
+ * Force a synchronous layout reflow on `element`.
11
+ *
12
+ * Reading an offset/scroll/clientWidth-like property forces the browser
13
+ * to flush queued style and layout work on the spot, before any further
14
+ * script runs. The editor relies on this after `Canvas.setDimensions`
15
+ * so a container with `overflow: auto` shows or hides scrollbars before
16
+ * the next paint, instead of waiting for the next frame.
17
+ *
18
+ * The read is cast to `void` and isolated in this helper so optimizers
19
+ * cannot eliminate it as a dead access. The function is a no-op when
20
+ * `element` is `null` or `undefined`, which keeps callers free of guards in
21
+ * environments where the container element may not yet be attached.
22
+ *
23
+ * @param element - The element whose layout should be flushed. `null` is ignored.
24
+ */
25
+ export declare function forceReflow(element: HTMLElement | null | undefined): void;
26
+ //# sourceMappingURL=dom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../../src/utils/dom.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,CAMzE"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * File-input helpers used by the editor's file-input flow.
3
+ *
4
+ * These helpers cover three concerns:
5
+ *
6
+ * - Determining whether a `File` selected through the upload control is a
7
+ * supported image, including the extension fallback when `file.type` is
8
+ * empty (some operating systems and browsers report an empty MIME type
9
+ * for known extensions).
10
+ * - Reading the file as a base64 data URL so the result can be routed
11
+ * through the existing transactional `loadImage` pipeline (and therefore
12
+ * inherit its rollback behavior on decode/Fabric/timeout failure).
13
+ * - Resetting the file input value after every attempt so selecting the
14
+ * same file again triggers a fresh `change` event.
15
+ *
16
+ * The helpers do not call `loadImage` themselves; the orchestrator wires
17
+ * them into the file-input change handler. That keeps the public
18
+ * `loadImage` API unchanged beyond `LoadImageOptions`.
19
+ */
20
+ /**
21
+ * Supported image extensions and the MIME type each one resolves to.
22
+ *
23
+ * Supported file extensions: `png`, `jpg`/`jpeg`, `webp`, `gif`, `bmp`.
24
+ * GIF and BMP are accepted as static raster input for canvas editing. GIF
25
+ * animation and GIF/BMP source-format preservation are not retained; exports
26
+ * are emitted through the editor's JPEG, PNG, or WebP export options.
27
+ *
28
+ * Keys are lowercase extensions without the leading `.`.
29
+ */
30
+ export declare const SUPPORTED_IMAGE_EXTENSIONS: Record<string, string>;
31
+ export declare const SUPPORTED_IMAGE_MIME_TYPES: Set<string>;
32
+ /**
33
+ * Determine whether a `File` is a supported image and return its resolved
34
+ * MIME type, or `null` when it should be rejected.
35
+ *
36
+ * Resolution order:
37
+ *
38
+ * 1. If `file.type` is one of the supported image MIME types, return it
39
+ * verbatim.
40
+ * 2. If `file.type` is empty, infer the MIME type from the file
41
+ * extension via {@link SUPPORTED_IMAGE_EXTENSIONS}. This covers the
42
+ * case where a browser or OS reports `''` for files with a known
43
+ * extension.
44
+ * 3. Otherwise, return `null` so the caller can skip the load without
45
+ * mutating editor state.
46
+ *
47
+ * @param file - File selected via the upload control.
48
+ * @returns The resolved MIME type, or `null` when the file is not a
49
+ * supported image.
50
+ */
51
+ export declare function inferImageMimeType(file: File): string | null;
52
+ /**
53
+ * Read a `File` as a base64 data URL using `FileReader`.
54
+ *
55
+ * The returned data URL is suitable for the transactional `loadImage`
56
+ * pipeline: on failure the editor's existing
57
+ * rollback bundle restores placeholder visibility, scroll, overflow,
58
+ * `originalImage`, `lastSnapshot`, and the canvas JSON snapshot.
59
+ *
60
+ * @param file - File to read.
61
+ * @returns A promise that resolves to the data URL string, or rejects when
62
+ * the underlying `FileReader` errors out or returns a non-string
63
+ * result.
64
+ */
65
+ export declare function readFileAsDataUrl(file: File): Promise<string>;
66
+ /**
67
+ * Reset a file input element's value so selecting the same file again
68
+ * triggers a fresh `change` event.
69
+ *
70
+ * Some browsers reject programmatic assignment to `input.value` on
71
+ * security grounds; the assignment is wrapped in a `try`/`catch` so the
72
+ * caller never has to special-case those environments. A `null` input is
73
+ * a no-op so callers can pass the result of `document.getElementById`
74
+ * without an extra null check.
75
+ *
76
+ * @param input - File input element, or `null` when the element is not
77
+ * present in the DOM.
78
+ */
79
+ export declare function resetFileInput(input: HTMLInputElement | null): void;
80
+ //# sourceMappingURL=file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../../src/utils/file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;;;;;;;;GASG;AACH,eAAO,MAAM,0BAA0B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAO7D,CAAC;AAEF,eAAO,MAAM,0BAA0B,aAAqD,CAAC;AAE7F;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAO5D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAmB7D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,GAAG,IAAI,CAOnE"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Pure helpers used by `mask/mask-factory.ts` to turn the
3
+ * flexible `MaskNumericProp` and `PolygonPoint` inputs of
4
+ * {@link MaskConfig} into concrete numbers and `{ x, y }`
5
+ * points before a Fabric.js shape is constructed.
6
+ *
7
+ * ## Owned contracts
8
+ *
9
+ * - `MaskConfig` percentage values supplied for
10
+ * `left`, `width`, `rx`, or `radius` SHALL resolve against the canvas
11
+ * pixel **width** (axis `'x'`).
12
+ * - `MaskConfig` percentage values supplied for
13
+ * `top`, `height`, or `ry` SHALL resolve against the canvas pixel
14
+ * **height** (axis `'y'`).
15
+ * - A `MaskNumericProp` provided as a function
16
+ * SHALL be invoked with `(canvas, ResolvedOptions)` and the returned
17
+ * number used directly.
18
+ * - Polygon point items SHALL be accepted in
19
+ * either `{ x, y }` object form or `[x, y]` tuple form and coerced to
20
+ * numeric `{ x, y }` internally.
21
+ *
22
+ * ## Why a dedicated module
23
+ *
24
+ * `resolveNumeric` is axis-aware so horizontal values resolve against
25
+ * canvas width and vertical values resolve against canvas height.
26
+ * `coercePoint` lives next to it because both helpers are pure functions
27
+ * consumed by the same mask-factory pipeline.
28
+ *
29
+ * ## Design notes
30
+ *
31
+ * - `resolveNumeric` is total: any input that is not a number, a finite
32
+ * percentage string, or a function falls through to `fallback` rather
33
+ * than throwing.
34
+ * - Percentages are floored (`Math.floor`) to keep rendered placement
35
+ * deterministic across canvas resizes.
36
+ * - The helper does NOT clamp the result against canvas bounds; callers
37
+ * are responsible for any subsequent clamping (the mask factory may
38
+ * expand the canvas to accommodate larger placements when
39
+ * `expandCanvasToImage` is enabled).
40
+ *
41
+ * ## Non-goals
42
+ *
43
+ * - This module does not validate that the supplied `axis` matches the
44
+ * field being resolved. Routing each `MaskConfig` field to the correct
45
+ * axis is the mask factory's responsibility.
46
+ * - This module does not coerce or round the output of factory functions
47
+ * (`(canvas, options) => number`); their return value is used verbatim
48
+ * so consumers retain full control over sub-pixel placement.
49
+ *
50
+ * @module
51
+ */
52
+ import type * as FabricNS from 'fabric';
53
+ import type { MaskNumericProp, PolygonPoint, ResolvedOptions } from '../core/public-types.js';
54
+ /**
55
+ * Axis selector used by {@link resolveNumeric} to decide which canvas
56
+ * dimension a percentage value resolves against.
57
+ *
58
+ * - `'x'` → `canvas.getWidth`
59
+ * - `'y'` → `canvas.getHeight`
60
+ */
61
+ export type Axis = 'x' | 'y';
62
+ /**
63
+ * Resolve a {@link MaskNumericProp} into a concrete pixel number.
64
+ *
65
+ * Resolution rules (in order):
66
+ * 1. If `val` is a `number`, return it unchanged.
67
+ * 2. If `val` is a function, invoke it as `val(canvas, options)` and
68
+ * return the result.
69
+ * 3. If `val` is a string ending in `'%'`, parse the leading number,
70
+ * multiply by `canvas.getWidth` (axis `'x'`) or
71
+ * `canvas.getHeight` (axis `'y'`), floor the product, and return
72
+ * it. Strings that do not parse to a
73
+ * finite number fall through to `fallback`.
74
+ * 4. Anything else (including `undefined`, `null`, non-percent strings,
75
+ * booleans, etc.) returns `fallback`.
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * // 50% of an 800px-wide canvas:
80
+ * resolveNumeric('50%', 'x', 0, canvas, options); // → 400
81
+ *
82
+ * // Function form receives the live canvas and ResolvedOptions:
83
+ * resolveNumeric(
84
+ * (canvas) => canvas.getWidth() - 20,
85
+ * 'x',
86
+ * 0,
87
+ * canvas,
88
+ * options,
89
+ * ); // → canvas.getWidth() - 20
90
+ *
91
+ * // Unrecognized input falls back:
92
+ * resolveNumeric(undefined, 'x', 10, canvas, options); // → 10
93
+ * ```
94
+ *
95
+ * @param val - The flexible mask numeric property to resolve.
96
+ * @param axis - Which canvas dimension a percentage resolves against.
97
+ * @param fallback - Value returned when `val` cannot be resolved.
98
+ * @param canvas - Live Fabric.js canvas; only `getWidth`/`getHeight`
99
+ * are read here, but the entire canvas is forwarded to
100
+ * factory functions.
101
+ * @param options - Fully-resolved editor options forwarded to factory
102
+ * functions.
103
+ *
104
+ * @returns The resolved pixel number, or `fallback` when no rule applies.
105
+ */
106
+ export declare function resolveNumeric(val: MaskNumericProp | undefined, axis: Axis, fallback: number, canvas: FabricNS.Canvas, options: ResolvedOptions): number;
107
+ /**
108
+ * Coerce a {@link PolygonPoint} into the canonical `{ x, y }` numeric
109
+ * shape used by Fabric.js polygon construction.
110
+ *
111
+ * Both input forms are accepted so callers may write polygon points in
112
+ * whichever style is most ergonomic at the call site:
113
+ *
114
+ * ```ts
115
+ * coercePoint({ x: 10, y: 20 }); // → { x: 10, y: 20 }
116
+ * coercePoint([10, 20]); // → { x: 10, y: 20 }
117
+ * ```
118
+ *
119
+ * Values are coerced via `Number(...)` so string-encoded coordinates
120
+ * (e.g. coming straight from a JSON payload) round-trip correctly. Any
121
+ * value that fails to coerce becomes `NaN`, matching the rest of the
122
+ * mask pipeline's tolerant input handling — callers that need stricter
123
+ * validation should perform it before constructing the polygon.
124
+ *
125
+ * @param pt - A polygon vertex in object or tuple form.
126
+ * @returns An `{ x, y }` numeric point.
127
+ */
128
+ export declare function coercePoint(pt: PolygonPoint): {
129
+ x: number;
130
+ y: number;
131
+ };
132
+ //# sourceMappingURL=number.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"number.d.ts","sourceRoot":"","sources":["../../../src/utils/number.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAEH,OAAO,KAAK,KAAK,QAAQ,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE9F;;;;;;GAMG;AACH,MAAM,MAAM,IAAI,GAAG,GAAG,GAAG,GAAG,CAAC;AAE7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,wBAAgB,cAAc,CAC1B,GAAG,EAAE,eAAe,GAAG,SAAS,EAChC,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,QAAQ,CAAC,MAAM,EACvB,OAAO,EAAE,eAAe,GACzB,MAAM,CAgBR;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,YAAY,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAKtE"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Promise/timer race helper used by the image-loader pipeline
3
+ * to bound the decode and `FabricImage.fromURL` steps.
4
+ *
5
+ * ## Owned contracts
6
+ *
7
+ * - `loadImage(base64)` decode of the data URL into
8
+ * an `HTMLImageElement` SHALL be bounded by `options.imageLoadTimeoutMs`.
9
+ * - `loadImage(base64)` `FabricImage.fromURL` step
10
+ * SHALL be bounded by the same `options.imageLoadTimeoutMs`.
11
+ * - If either timeout elapses, the returned promise
12
+ * SHALL reject with a timeout error whose message includes the elapsed
13
+ * milliseconds. The {@link ImageLoadTimeoutError} class owns the message
14
+ * format; this module simply produces the error with the correct
15
+ * `(label, elapsedMs)` pair.
16
+ *
17
+ * ## Why a dedicated module
18
+ *
19
+ * The image-loader needs to apply the *same* timeout policy to two
20
+ * independent async steps (decode and Fabric image creation). Centralizing
21
+ * the race in one helper keeps the loader straight-line, ensures both
22
+ * steps reject with the same error type, and gives the timeout logic a
23
+ * single place to evolve (for example, future cancellation hooks).
24
+ *
25
+ * ## Design notes
26
+ *
27
+ * - The race is implemented with a `setTimeout`-based timer that is
28
+ * cleared as soon as the wrapped promise settles, so a slow-but-eventual
29
+ * resolution does not leave a dangling timer (and the elapsed-time
30
+ * measurement remains tight).
31
+ * - On timeout, the helper computes elapsed ms from a `Date.now` taken
32
+ * at the start of the race. This avoids drift versus the `ms` argument
33
+ * for callers that want to log the actual wall-clock duration.
34
+ * - On rejection of the wrapped promise, the original error is forwarded
35
+ * verbatim so the loader can branch on its specific type
36
+ * (`ImageDecodeError`, `DownsampleError`, etc.) rather than always
37
+ * seeing a `ImageLoadTimeoutError`.
38
+ *
39
+ * ## Non-goals
40
+ *
41
+ * - The helper does NOT cancel the wrapped promise. JavaScript promises
42
+ * have no built-in cancellation; the caller is responsible for any
43
+ * cleanup of the underlying work (e.g. clearing an `<img>.src`).
44
+ * - The helper does NOT validate `ms`. Callers pass the resolved
45
+ * `imageLoadTimeoutMs` from `default-options.ts`, which is already
46
+ * coerced to a finite non-negative number.
47
+ *
48
+ * @module
49
+ */
50
+ /**
51
+ * Race a promise against a timer. If the timer fires first, reject with
52
+ * an {@link ImageLoadTimeoutError} whose message includes `label` and the
53
+ * elapsed milliseconds. If the wrapped promise settles
54
+ * first, the timer is cleared and the original outcome is forwarded.
55
+ *
56
+ * Used by `image/image-loader.ts` to bound both the decode step and the
57
+ * `FabricImage.fromURL` step of `loadImage`.
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * await withTimeout(
62
+ * decodeImageElement(base64),
63
+ * options.imageLoadTimeoutMs,
64
+ * 'image decode',
65
+ * );
66
+ * ```
67
+ *
68
+ * @typeParam T - Resolved value type of the wrapped promise.
69
+ *
70
+ * @param promise - The async work to race. Forwarded verbatim on resolution; rejection
71
+ * reasons are forwarded unchanged so callers can branch on the original
72
+ * error type.
73
+ * @param ms - Timeout duration in milliseconds. Expected to be a finite,
74
+ * non-negative number; the caller (typically `default-options.ts`) is
75
+ * responsible for coercion.
76
+ * @param label - Human-readable step label embedded in the timeout error message
77
+ * (e.g. `'image decode'`, `'FabricImage.fromURL'`).
78
+ *
79
+ * @returns A promise that resolves to the wrapped promise's value, or
80
+ * rejects with the wrapped promise's reason, or rejects with
81
+ * {@link ImageLoadTimeoutError} if the timer fires first.
82
+ */
83
+ export declare function withTimeout<T>(promise: Promise<T>, ms: number, label: string): Promise<T>;
84
+ //# sourceMappingURL=timeout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeout.d.ts","sourceRoot":"","sources":["../../../src/utils/timeout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAIH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAkBzF"}