@wordpress/image-cropper 1.0.1-next.6deb34194.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 (59) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/LICENSE.md +788 -0
  3. package/README.md +196 -0
  4. package/build/components/image-cropper/index.js +97 -0
  5. package/build/components/image-cropper/index.js.map +7 -0
  6. package/build/constants.js +37 -0
  7. package/build/constants.js.map +7 -0
  8. package/build/index.js +52 -0
  9. package/build/index.js.map +7 -0
  10. package/build/provider/index.js +86 -0
  11. package/build/provider/index.js.map +7 -0
  12. package/build/provider/use-image-cropper.js +189 -0
  13. package/build/provider/use-image-cropper.js.map +7 -0
  14. package/build/types.js +19 -0
  15. package/build/types.js.map +7 -0
  16. package/build/utils.js +107 -0
  17. package/build/utils.js.map +7 -0
  18. package/build-module/components/image-cropper/index.js +66 -0
  19. package/build-module/components/image-cropper/index.js.map +7 -0
  20. package/build-module/constants.js +10 -0
  21. package/build-module/constants.js.map +7 -0
  22. package/build-module/index.js +12 -0
  23. package/build-module/index.js.map +7 -0
  24. package/build-module/provider/index.js +50 -0
  25. package/build-module/provider/index.js.map +7 -0
  26. package/build-module/provider/use-image-cropper.js +167 -0
  27. package/build-module/provider/use-image-cropper.js.map +7 -0
  28. package/build-module/types.js +1 -0
  29. package/build-module/types.js.map +7 -0
  30. package/build-module/utils.js +78 -0
  31. package/build-module/utils.js.map +7 -0
  32. package/build-types/components/image-cropper/index.d.ts +3 -0
  33. package/build-types/components/image-cropper/index.d.ts.map +1 -0
  34. package/build-types/constants.d.ts +4 -0
  35. package/build-types/constants.d.ts.map +1 -0
  36. package/build-types/index.d.ts +5 -0
  37. package/build-types/index.d.ts.map +1 -0
  38. package/build-types/provider/index.d.ts +7 -0
  39. package/build-types/provider/index.d.ts.map +1 -0
  40. package/build-types/provider/use-image-cropper.d.ts +15 -0
  41. package/build-types/provider/use-image-cropper.d.ts.map +1 -0
  42. package/build-types/stories/index.story.d.ts +28 -0
  43. package/build-types/stories/index.story.d.ts.map +1 -0
  44. package/build-types/types.d.ts +42 -0
  45. package/build-types/types.d.ts.map +1 -0
  46. package/build-types/utils.d.ts +60 -0
  47. package/build-types/utils.d.ts.map +1 -0
  48. package/package.json +49 -0
  49. package/src/components/image-cropper/index.tsx +84 -0
  50. package/src/constants.ts +3 -0
  51. package/src/index.ts +4 -0
  52. package/src/provider/index.tsx +57 -0
  53. package/src/provider/use-image-cropper.ts +220 -0
  54. package/src/stories/index.story.tsx +351 -0
  55. package/src/stories/style.css +17 -0
  56. package/src/types.ts +54 -0
  57. package/src/utils.ts +146 -0
  58. package/tsconfig.json +8 -0
  59. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // packages/image-cropper/src/provider/use-image-cropper.ts
21
+ var use_image_cropper_exports = {};
22
+ __export(use_image_cropper_exports, {
23
+ DEFAULT_INITIAL_STATE: () => DEFAULT_INITIAL_STATE,
24
+ default: () => useCropper
25
+ });
26
+ module.exports = __toCommonJS(use_image_cropper_exports);
27
+ var import_dequal = require("dequal");
28
+ var import_element = require("@wordpress/element");
29
+ var import_constants = require("../constants");
30
+ var import_utils = require("../utils");
31
+ var DEFAULT_INITIAL_STATE = {
32
+ crop: {
33
+ x: 0,
34
+ y: 0,
35
+ width: 100,
36
+ height: 100
37
+ },
38
+ zoom: import_constants.MIN_ZOOM,
39
+ rotation: 0,
40
+ aspectRatio: 1,
41
+ flip: {
42
+ horizontal: false,
43
+ vertical: false
44
+ }
45
+ };
46
+ var DEFAULT_CROP_MEDIA_POSITION = {
47
+ x: 0,
48
+ y: 0
49
+ };
50
+ var DEFAULT_CROPPER_STATE = {
51
+ crop: DEFAULT_CROP_MEDIA_POSITION,
52
+ croppedArea: DEFAULT_INITIAL_STATE.crop,
53
+ croppedAreaPixels: null,
54
+ zoom: DEFAULT_INITIAL_STATE.zoom,
55
+ rotation: DEFAULT_INITIAL_STATE.rotation,
56
+ flip: DEFAULT_INITIAL_STATE.flip,
57
+ aspectRatio: DEFAULT_INITIAL_STATE.aspectRatio,
58
+ mediaSize: null
59
+ };
60
+ function useCropper() {
61
+ const [cropperState, setInternalCropperState] = (0, import_element.useState)(
62
+ DEFAULT_CROPPER_STATE
63
+ );
64
+ const [resetState, setInternalResetState] = (0, import_element.useState)(null);
65
+ const setCropperState = (0, import_element.useCallback)(
66
+ (newState) => {
67
+ setInternalCropperState((prev) => {
68
+ const updates = typeof newState === "function" ? newState(prev) : newState;
69
+ const normalizedUpdates = { ...updates };
70
+ if ("rotation" in normalizedUpdates && normalizedUpdates.rotation !== void 0) {
71
+ normalizedUpdates.rotation = (0, import_utils.normalizeRotation)(
72
+ normalizedUpdates.rotation
73
+ );
74
+ }
75
+ return { ...prev, ...normalizedUpdates };
76
+ });
77
+ },
78
+ []
79
+ );
80
+ const setResetState = (0, import_element.useCallback)(
81
+ (newResetState = null) => {
82
+ if (!newResetState) {
83
+ setInternalResetState(null);
84
+ setCropperState(DEFAULT_CROPPER_STATE);
85
+ return;
86
+ }
87
+ if (typeof newResetState === "object") {
88
+ const initialState = {
89
+ ...DEFAULT_INITIAL_STATE,
90
+ ...newResetState
91
+ };
92
+ setInternalResetState(initialState);
93
+ setCropperState(initialState);
94
+ }
95
+ },
96
+ [setCropperState, setInternalResetState]
97
+ );
98
+ const reset = (0, import_element.useCallback)(() => {
99
+ if (resetState) {
100
+ const resetUpdates = {
101
+ // Reset media position to center
102
+ crop: { x: 0, y: 0 },
103
+ // Reset cropped area pixels (will be recalculated)
104
+ croppedAreaPixels: null
105
+ };
106
+ if (resetState.crop) {
107
+ resetUpdates.croppedArea = resetState.crop;
108
+ }
109
+ if (resetState.zoom !== void 0) {
110
+ resetUpdates.zoom = resetState.zoom;
111
+ }
112
+ if (resetState.rotation !== void 0) {
113
+ resetUpdates.rotation = resetState.rotation;
114
+ }
115
+ if (resetState.aspectRatio !== void 0) {
116
+ resetUpdates.aspectRatio = resetState.aspectRatio;
117
+ }
118
+ if (resetState.flip !== void 0) {
119
+ resetUpdates.flip = resetState.flip;
120
+ }
121
+ setCropperState(resetUpdates);
122
+ } else {
123
+ setCropperState({ ...DEFAULT_CROPPER_STATE });
124
+ }
125
+ }, [resetState, setCropperState]);
126
+ const isDirty = (0, import_element.useMemo)(() => {
127
+ if (resetState) {
128
+ const currentState2 = {
129
+ crop: cropperState.croppedAreaPixels || cropperState.croppedArea,
130
+ zoom: cropperState.zoom,
131
+ rotation: (0, import_utils.normalizeRotation)(cropperState.rotation),
132
+ aspectRatio: cropperState.aspectRatio,
133
+ flip: cropperState.flip
134
+ };
135
+ return false === (0, import_dequal.dequal)(currentState2, resetState);
136
+ }
137
+ const currentState = {
138
+ crop: cropperState.croppedArea,
139
+ zoom: cropperState.zoom,
140
+ rotation: (0, import_utils.normalizeRotation)(cropperState.rotation),
141
+ aspectRatio: cropperState.aspectRatio,
142
+ flip: cropperState.flip
143
+ };
144
+ return false === (0, import_dequal.dequal)(currentState, DEFAULT_INITIAL_STATE);
145
+ }, [cropperState, resetState]);
146
+ const getCroppedImage = (0, import_element.useCallback)(
147
+ async (src) => {
148
+ if (!cropperState.croppedAreaPixels) {
149
+ return null;
150
+ }
151
+ return (0, import_utils.getCroppedImage)(
152
+ src,
153
+ cropperState.croppedAreaPixels,
154
+ cropperState.rotation,
155
+ cropperState.flip
156
+ );
157
+ },
158
+ [
159
+ cropperState.croppedAreaPixels,
160
+ cropperState.rotation,
161
+ cropperState.flip
162
+ ]
163
+ );
164
+ return (0, import_element.useMemo)(
165
+ () => ({
166
+ cropperState,
167
+ setCropperState,
168
+ resetState,
169
+ setResetState,
170
+ isDirty,
171
+ reset,
172
+ getCroppedImage
173
+ }),
174
+ [
175
+ cropperState,
176
+ setCropperState,
177
+ resetState,
178
+ setResetState,
179
+ isDirty,
180
+ reset,
181
+ getCroppedImage
182
+ ]
183
+ );
184
+ }
185
+ // Annotate the CommonJS export names for ESM import in node:
186
+ 0 && (module.exports = {
187
+ DEFAULT_INITIAL_STATE
188
+ });
189
+ //# sourceMappingURL=use-image-cropper.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/provider/use-image-cropper.ts"],
4
+ "sourcesContent": ["/**\n * External dependencies\n */\nimport { dequal } from 'dequal';\n\n/**\n * WordPress dependencies\n */\nimport { useMemo, useState, useCallback } from '@wordpress/element';\n\n/**\n * Internal dependencies\n */\nimport type { Point, ImageCropperState, CropperState } from '../types';\nimport { MIN_ZOOM } from '../constants';\nimport {\n\tgetCroppedImage as getCroppedImageUtil,\n\tnormalizeRotation,\n} from '../utils';\n\nexport const DEFAULT_INITIAL_STATE: Required< ImageCropperState > = {\n\tcrop: {\n\t\tx: 0,\n\t\ty: 0,\n\t\twidth: 100,\n\t\theight: 100,\n\t},\n\tzoom: MIN_ZOOM,\n\trotation: 0,\n\taspectRatio: 1,\n\tflip: {\n\t\thorizontal: false,\n\t\tvertical: false,\n\t},\n};\n\nconst DEFAULT_CROP_MEDIA_POSITION: Point = {\n\tx: 0,\n\ty: 0,\n};\n\nconst DEFAULT_CROPPER_STATE: CropperState = {\n\tcrop: DEFAULT_CROP_MEDIA_POSITION,\n\tcroppedArea: DEFAULT_INITIAL_STATE.crop,\n\tcroppedAreaPixels: null,\n\tzoom: DEFAULT_INITIAL_STATE.zoom,\n\trotation: DEFAULT_INITIAL_STATE.rotation,\n\tflip: DEFAULT_INITIAL_STATE.flip,\n\taspectRatio: DEFAULT_INITIAL_STATE.aspectRatio,\n\tmediaSize: null,\n};\n\nexport default function useCropper() {\n\tconst [ cropperState, setInternalCropperState ] = useState< CropperState >(\n\t\tDEFAULT_CROPPER_STATE\n\t);\n\tconst [ resetState, setInternalResetState ] =\n\t\tuseState< ImageCropperState | null >( null );\n\n\t// Unified setter that supports both partial updates and function updates\n\tconst setCropperState = useCallback(\n\t\t(\n\t\t\tnewState:\n\t\t\t\t| Partial< CropperState >\n\t\t\t\t| ( ( prev: CropperState ) => Partial< CropperState > )\n\t\t) => {\n\t\t\tsetInternalCropperState( ( prev ) => {\n\t\t\t\tconst updates =\n\t\t\t\t\ttypeof newState === 'function'\n\t\t\t\t\t\t? newState( prev )\n\t\t\t\t\t\t: newState;\n\n\t\t\t\t// Apply normalization to rotation if it's being updated\n\t\t\t\tconst normalizedUpdates = { ...updates };\n\t\t\t\tif (\n\t\t\t\t\t'rotation' in normalizedUpdates &&\n\t\t\t\t\tnormalizedUpdates.rotation !== undefined\n\t\t\t\t) {\n\t\t\t\t\tnormalizedUpdates.rotation = normalizeRotation(\n\t\t\t\t\t\tnormalizedUpdates.rotation\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn { ...prev, ...normalizedUpdates };\n\t\t\t} );\n\t\t},\n\t\t[]\n\t);\n\n\tconst setResetState = useCallback(\n\t\t( newResetState: Partial< ImageCropperState > | null = null ) => {\n\t\t\t// If null, wipe the reset state and reset the cropper state to the default state.\n\t\t\tif ( ! newResetState ) {\n\t\t\t\tsetInternalResetState( null );\n\t\t\t\tsetCropperState( DEFAULT_CROPPER_STATE );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif ( typeof newResetState === 'object' ) {\n\t\t\t\tconst initialState = {\n\t\t\t\t\t...DEFAULT_INITIAL_STATE,\n\t\t\t\t\t...newResetState,\n\t\t\t\t};\n\t\t\t\tsetInternalResetState( initialState );\n\t\t\t\tsetCropperState( initialState );\n\t\t\t}\n\t\t},\n\t\t[ setCropperState, setInternalResetState ]\n\t);\n\n\t/*\n\t * Resets the cropper state.\n\t */\n\tconst reset = useCallback( () => {\n\t\tif ( resetState ) {\n\t\t\t// Convert ImageCropperState to CropperState updates\n\t\t\tconst resetUpdates: Partial< CropperState > = {\n\t\t\t\t// Reset media position to center\n\t\t\t\tcrop: { x: 0, y: 0 },\n\t\t\t\t// Reset cropped area pixels (will be recalculated)\n\t\t\t\tcroppedAreaPixels: null,\n\t\t\t};\n\n\t\t\t// Set the cropped area from resetState (this is the target crop area)\n\t\t\tif ( resetState.crop ) {\n\t\t\t\tresetUpdates.croppedArea = resetState.crop;\n\t\t\t}\n\t\t\tif ( resetState.zoom !== undefined ) {\n\t\t\t\tresetUpdates.zoom = resetState.zoom;\n\t\t\t}\n\t\t\tif ( resetState.rotation !== undefined ) {\n\t\t\t\tresetUpdates.rotation = resetState.rotation;\n\t\t\t}\n\t\t\tif ( resetState.aspectRatio !== undefined ) {\n\t\t\t\tresetUpdates.aspectRatio = resetState.aspectRatio;\n\t\t\t}\n\t\t\tif ( resetState.flip !== undefined ) {\n\t\t\t\tresetUpdates.flip = resetState.flip;\n\t\t\t}\n\n\t\t\tsetCropperState( resetUpdates );\n\t\t} else {\n\t\t\tsetCropperState( { ...DEFAULT_CROPPER_STATE } );\n\t\t}\n\t}, [ resetState, setCropperState ] );\n\n\t/*\n\t * Returns true if the cropper state is dirty.\n\t * Compare against reset state if available, otherwise against default state.\n\t */\n\tconst isDirty = useMemo( () => {\n\t\tif ( resetState ) {\n\t\t\t// Compare the relevant cropper properties against reset state\n\t\t\tconst currentState = {\n\t\t\t\tcrop:\n\t\t\t\t\tcropperState.croppedAreaPixels || cropperState.croppedArea,\n\t\t\t\tzoom: cropperState.zoom,\n\t\t\t\trotation: normalizeRotation( cropperState.rotation ),\n\t\t\t\taspectRatio: cropperState.aspectRatio,\n\t\t\t\tflip: cropperState.flip,\n\t\t\t};\n\t\t\treturn false === dequal( currentState, resetState );\n\t\t}\n\n\t\t// Compare against default state using percentage values\n\t\tconst currentState = {\n\t\t\tcrop: cropperState.croppedArea,\n\t\t\tzoom: cropperState.zoom,\n\t\t\trotation: normalizeRotation( cropperState.rotation ),\n\t\t\taspectRatio: cropperState.aspectRatio,\n\t\t\tflip: cropperState.flip,\n\t\t};\n\t\treturn false === dequal( currentState, DEFAULT_INITIAL_STATE );\n\t}, [ cropperState, resetState ] );\n\n\t/**\n\t * Returns the cropped image.\n\t *\n\t * @param {string} src - The source of the image to crop.\n\t * @return {Promise<string | null>} A promise that resolves to the cropped image.\n\t */\n\tconst getCroppedImage = useCallback(\n\t\tasync ( src: string ) => {\n\t\t\tif ( ! cropperState.croppedAreaPixels ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn getCroppedImageUtil(\n\t\t\t\tsrc,\n\t\t\t\tcropperState.croppedAreaPixels,\n\t\t\t\tcropperState.rotation,\n\t\t\t\tcropperState.flip\n\t\t\t);\n\t\t},\n\t\t[\n\t\t\tcropperState.croppedAreaPixels,\n\t\t\tcropperState.rotation,\n\t\t\tcropperState.flip,\n\t\t]\n\t);\n\n\treturn useMemo(\n\t\t() => ( {\n\t\t\tcropperState,\n\t\t\tsetCropperState,\n\t\t\tresetState,\n\t\t\tsetResetState,\n\t\t\tisDirty,\n\t\t\treset,\n\t\t\tgetCroppedImage,\n\t\t} ),\n\t\t[\n\t\t\tcropperState,\n\t\t\tsetCropperState,\n\t\t\tresetState,\n\t\t\tsetResetState,\n\t\t\tisDirty,\n\t\t\treset,\n\t\t\tgetCroppedImage,\n\t\t]\n\t);\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["currentState", "getCroppedImageUtil"]
7
+ }
package/build/types.js ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+
16
+ // packages/image-cropper/src/types.ts
17
+ var types_exports = {};
18
+ module.exports = __toCommonJS(types_exports);
19
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/types.ts"],
4
+ "sourcesContent": ["/**\n * External dependencies\n */\nimport type { Point, Area, MediaSize } from 'react-easy-crop';\n\n// Re-export types for convenience.\nexport type { Point, Area, MediaSize };\n\nexport type Flip = {\n\thorizontal: boolean;\n\tvertical: boolean;\n};\n\nexport interface ImageCropperState {\n\trotation?: number;\n\tcrop?: Area;\n\tzoom?: number;\n\tflip?: Flip;\n\taspectRatio?: number;\n}\n\nexport interface CropperState {\n\tcrop: Point;\n\tcroppedArea?: Area;\n\tcroppedAreaPixels?: Area | null;\n\tzoom: number;\n\trotation: number;\n\tflip: Flip;\n\taspectRatio: number;\n\tmediaSize: MediaSize | null;\n}\n\nexport interface ImageCropperProps {\n\tsrc: string;\n\tonLoad?: ( mediaSize: MediaSize ) => void;\n\tminZoom?: number;\n\tmaxZoom?: number;\n}\n\nexport interface ImageCropperContextValue {\n\tcropperState: CropperState;\n\tsetCropperState: (\n\t\tnewState:\n\t\t\t| Partial< CropperState >\n\t\t\t| ( ( prev: CropperState ) => Partial< CropperState > )\n\t) => void;\n\tresetState: ImageCropperState | null;\n\tsetResetState: (\n\t\tnewResetState: Partial< ImageCropperState > | null\n\t) => void;\n\tisDirty: boolean;\n\treset: () => void;\n\tgetCroppedImage: ( src: string ) => Promise< string | null >;\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;AAAA;AAAA;",
6
+ "names": []
7
+ }
package/build/utils.js ADDED
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // packages/image-cropper/src/utils.ts
21
+ var utils_exports = {};
22
+ __export(utils_exports, {
23
+ createImage: () => createImage,
24
+ getCroppedImage: () => getCroppedImage,
25
+ getRadianAngle: () => getRadianAngle,
26
+ normalizeRotation: () => normalizeRotation,
27
+ rotateSize: () => rotateSize
28
+ });
29
+ module.exports = __toCommonJS(utils_exports);
30
+ var normalizeRotation = (rotation) => {
31
+ if (rotation >= 0) {
32
+ return rotation % 360;
33
+ }
34
+ return (360 + rotation % 360) % 360;
35
+ };
36
+ var createImage = (url) => new Promise((resolve, reject) => {
37
+ const image = new Image();
38
+ image.addEventListener("load", () => resolve(image));
39
+ image.addEventListener("error", (error) => reject(error));
40
+ image.setAttribute("crossOrigin", "anonymous");
41
+ image.src = url;
42
+ });
43
+ function getRadianAngle(degreeValue) {
44
+ return degreeValue * Math.PI / 180;
45
+ }
46
+ function rotateSize(width, height, rotation) {
47
+ const rotRad = getRadianAngle(rotation);
48
+ return {
49
+ width: Math.abs(Math.cos(rotRad) * width) + Math.abs(Math.sin(rotRad) * height),
50
+ height: Math.abs(Math.sin(rotRad) * width) + Math.abs(Math.cos(rotRad) * height)
51
+ };
52
+ }
53
+ async function getCroppedImage(imageSrc, pixelCrop, rotation = 0, flip = { horizontal: false, vertical: false }) {
54
+ try {
55
+ const image = await createImage(imageSrc);
56
+ const canvas = document.createElement("canvas");
57
+ const ctx = canvas.getContext("2d");
58
+ if (!ctx) {
59
+ return null;
60
+ }
61
+ const rotRad = getRadianAngle(rotation);
62
+ const { width: boundingBoxWidth, height: boundingBoxHeight } = rotateSize(image.width, image.height, rotation);
63
+ canvas.width = boundingBoxWidth;
64
+ canvas.height = boundingBoxHeight;
65
+ ctx.translate(boundingBoxWidth / 2, boundingBoxHeight / 2);
66
+ ctx.rotate(rotRad);
67
+ ctx.scale(flip.horizontal ? -1 : 1, flip.vertical ? -1 : 1);
68
+ ctx.translate(-image.width / 2, -image.height / 2);
69
+ ctx.drawImage(image, 0, 0);
70
+ const croppedCanvas = document.createElement("canvas");
71
+ const croppedCtx = croppedCanvas.getContext("2d");
72
+ if (!croppedCtx) {
73
+ return null;
74
+ }
75
+ croppedCanvas.width = pixelCrop.width;
76
+ croppedCanvas.height = pixelCrop.height;
77
+ croppedCtx.drawImage(
78
+ canvas,
79
+ pixelCrop.x,
80
+ pixelCrop.y,
81
+ pixelCrop.width,
82
+ pixelCrop.height,
83
+ 0,
84
+ 0,
85
+ pixelCrop.width,
86
+ pixelCrop.height
87
+ );
88
+ return new Promise((resolve) => {
89
+ croppedCanvas.toBlob((file) => {
90
+ if (file) {
91
+ resolve(URL.createObjectURL(file));
92
+ }
93
+ }, "image/jpeg");
94
+ });
95
+ } catch {
96
+ return null;
97
+ }
98
+ }
99
+ // Annotate the CommonJS export names for ESM import in node:
100
+ 0 && (module.exports = {
101
+ createImage,
102
+ getCroppedImage,
103
+ getRadianAngle,
104
+ normalizeRotation,
105
+ rotateSize
106
+ });
107
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/utils.ts"],
4
+ "sourcesContent": ["/**\n * Normalizes a rotation value to be within the range of 0-360 degrees.\n * So a rotation of -90 becomes 270, -45 becomes 315, etc.\n * This is required because the `/media/edit` calculates the rotation value\n * by subtracting the rotation value from 0. ImageMagick rotates clockwise only and will subtract the rotation value from 360.\n * It's utterly confusing, and probably in need of a refactor.\n *\n * @param {number} rotation - The rotation value to normalize.\n * @return {number} The normalized rotation value.\n */\nexport const normalizeRotation = ( rotation: number ) => {\n\tif ( rotation >= 0 ) {\n\t\treturn rotation % 360;\n\t}\n\n\t// For negative rotations, convert to positive clockwise equivalent\n\treturn ( 360 + ( rotation % 360 ) ) % 360;\n};\n\n/**\n * Creates an image from a URL.\n *\n * @param {string} url - The URL of the image to create.\n * @return {Promise<HTMLImageElement>} A promise that resolves to the image.\n */\nexport const createImage = ( url: string ) =>\n\tnew Promise( ( resolve, reject ) => {\n\t\tconst image = new Image();\n\t\timage.addEventListener( 'load', () => resolve( image ) );\n\t\timage.addEventListener( 'error', ( error ) => reject( error ) );\n\t\timage.setAttribute( 'crossOrigin', 'anonymous' );\n\t\timage.src = url;\n\t} );\n\n/**\n * Converts a degree value to a radian value.\n *\n * @param {number} degreeValue - The degree value to convert.\n * @return {number} The radian value.\n */\nexport function getRadianAngle( degreeValue: number ) {\n\treturn ( degreeValue * Math.PI ) / 180;\n}\n\n/**\n * Returns the new bounding area of a rotated rectangle.\n *\n * @param {number} width - The width of the rectangle.\n * @param {number} height - The height of the rectangle.\n * @param {number} rotation - The rotation of the rectangle.\n * @return {Object} The new bounding area of the rotated rectangle.\n */\nexport function rotateSize( width: number, height: number, rotation: number ) {\n\tconst rotRad = getRadianAngle( rotation );\n\n\treturn {\n\t\twidth:\n\t\t\tMath.abs( Math.cos( rotRad ) * width ) +\n\t\t\tMath.abs( Math.sin( rotRad ) * height ),\n\t\theight:\n\t\t\tMath.abs( Math.sin( rotRad ) * width ) +\n\t\t\tMath.abs( Math.cos( rotRad ) * height ),\n\t};\n}\n\n/**\n * Crops an image to a given area.\n *\n * @param {string} imageSrc - The source of the image to crop.\n * @param {Object} pixelCrop - The area to crop.\n * @param pixelCrop.x\n * @param pixelCrop.y\n * @param pixelCrop.width\n * @param pixelCrop.height\n * @param {number} rotation - The rotation of the image.\n * @param {Object} flip - The flip of the image.\n * @return {Promise<string | null>} A promise that resolves to the cropped image.\n */\nexport async function getCroppedImage(\n\timageSrc: string,\n\tpixelCrop: { x: number; y: number; width: number; height: number },\n\trotation = 0,\n\tflip = { horizontal: false, vertical: false }\n): Promise< string | null > {\n\ttry {\n\t\tconst image = ( await createImage( imageSrc ) ) as HTMLImageElement;\n\t\tconst canvas = document.createElement( 'canvas' );\n\t\tconst ctx = canvas.getContext( '2d' );\n\n\t\tif ( ! ctx ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Calculate the rotation angle in radians.\n\t\tconst rotRad = getRadianAngle( rotation );\n\n\t\tconst { width: boundingBoxWidth, height: boundingBoxHeight } =\n\t\t\trotateSize( image.width, image.height, rotation );\n\n\t\t// Set canvas size to match the bounding box.\n\t\tcanvas.width = boundingBoxWidth;\n\t\tcanvas.height = boundingBoxHeight;\n\n\t\t// Translate and draw canvas context to a central location to allow rotating and flipping around the center.\n\t\tctx.translate( boundingBoxWidth / 2, boundingBoxHeight / 2 );\n\t\tctx.rotate( rotRad );\n\t\tctx.scale( flip.horizontal ? -1 : 1, flip.vertical ? -1 : 1 );\n\t\tctx.translate( -image.width / 2, -image.height / 2 );\n\t\tctx.drawImage( image, 0, 0 );\n\n\t\tconst croppedCanvas = document.createElement( 'canvas' );\n\t\tconst croppedCtx = croppedCanvas.getContext( '2d' );\n\n\t\tif ( ! croppedCtx ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Set the size of the cropped canvas.\n\t\tcroppedCanvas.width = pixelCrop.width;\n\t\tcroppedCanvas.height = pixelCrop.height;\n\n\t\t// Draw the cropped image onto the new canvas.\n\t\tcroppedCtx.drawImage(\n\t\t\tcanvas,\n\t\t\tpixelCrop.x,\n\t\t\tpixelCrop.y,\n\t\t\tpixelCrop.width,\n\t\t\tpixelCrop.height,\n\t\t\t0,\n\t\t\t0,\n\t\t\tpixelCrop.width,\n\t\t\tpixelCrop.height\n\t\t);\n\n\t\t// Return as a blob.\n\t\treturn new Promise( ( resolve ) => {\n\t\t\tcroppedCanvas.toBlob( ( file ) => {\n\t\t\t\tif ( file ) {\n\t\t\t\t\tresolve( URL.createObjectURL( file ) );\n\t\t\t\t}\n\t\t\t}, 'image/jpeg' );\n\t\t} );\n\t} catch {\n\t\treturn null;\n\t}\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUO,IAAM,oBAAoB,CAAE,aAAsB;AACxD,MAAK,YAAY,GAAI;AACpB,WAAO,WAAW;AAAA,EACnB;AAGA,UAAS,MAAQ,WAAW,OAAU;AACvC;AAQO,IAAM,cAAc,CAAE,QAC5B,IAAI,QAAS,CAAE,SAAS,WAAY;AACnC,QAAM,QAAQ,IAAI,MAAM;AACxB,QAAM,iBAAkB,QAAQ,MAAM,QAAS,KAAM,CAAE;AACvD,QAAM,iBAAkB,SAAS,CAAE,UAAW,OAAQ,KAAM,CAAE;AAC9D,QAAM,aAAc,eAAe,WAAY;AAC/C,QAAM,MAAM;AACb,CAAE;AAQI,SAAS,eAAgB,aAAsB;AACrD,SAAS,cAAc,KAAK,KAAO;AACpC;AAUO,SAAS,WAAY,OAAe,QAAgB,UAAmB;AAC7E,QAAM,SAAS,eAAgB,QAAS;AAExC,SAAO;AAAA,IACN,OACC,KAAK,IAAK,KAAK,IAAK,MAAO,IAAI,KAAM,IACrC,KAAK,IAAK,KAAK,IAAK,MAAO,IAAI,MAAO;AAAA,IACvC,QACC,KAAK,IAAK,KAAK,IAAK,MAAO,IAAI,KAAM,IACrC,KAAK,IAAK,KAAK,IAAK,MAAO,IAAI,MAAO;AAAA,EACxC;AACD;AAeA,eAAsB,gBACrB,UACA,WACA,WAAW,GACX,OAAO,EAAE,YAAY,OAAO,UAAU,MAAM,GACjB;AAC3B,MAAI;AACH,UAAM,QAAU,MAAM,YAAa,QAAS;AAC5C,UAAM,SAAS,SAAS,cAAe,QAAS;AAChD,UAAM,MAAM,OAAO,WAAY,IAAK;AAEpC,QAAK,CAAE,KAAM;AACZ,aAAO;AAAA,IACR;AAGA,UAAM,SAAS,eAAgB,QAAS;AAExC,UAAM,EAAE,OAAO,kBAAkB,QAAQ,kBAAkB,IAC1D,WAAY,MAAM,OAAO,MAAM,QAAQ,QAAS;AAGjD,WAAO,QAAQ;AACf,WAAO,SAAS;AAGhB,QAAI,UAAW,mBAAmB,GAAG,oBAAoB,CAAE;AAC3D,QAAI,OAAQ,MAAO;AACnB,QAAI,MAAO,KAAK,aAAa,KAAK,GAAG,KAAK,WAAW,KAAK,CAAE;AAC5D,QAAI,UAAW,CAAC,MAAM,QAAQ,GAAG,CAAC,MAAM,SAAS,CAAE;AACnD,QAAI,UAAW,OAAO,GAAG,CAAE;AAE3B,UAAM,gBAAgB,SAAS,cAAe,QAAS;AACvD,UAAM,aAAa,cAAc,WAAY,IAAK;AAElD,QAAK,CAAE,YAAa;AACnB,aAAO;AAAA,IACR;AAGA,kBAAc,QAAQ,UAAU;AAChC,kBAAc,SAAS,UAAU;AAGjC,eAAW;AAAA,MACV;AAAA,MACA,UAAU;AAAA,MACV,UAAU;AAAA,MACV,UAAU;AAAA,MACV,UAAU;AAAA,MACV;AAAA,MACA;AAAA,MACA,UAAU;AAAA,MACV,UAAU;AAAA,IACX;AAGA,WAAO,IAAI,QAAS,CAAE,YAAa;AAClC,oBAAc,OAAQ,CAAE,SAAU;AACjC,YAAK,MAAO;AACX,kBAAS,IAAI,gBAAiB,IAAK,CAAE;AAAA,QACtC;AAAA,MACD,GAAG,YAAa;AAAA,IACjB,CAAE;AAAA,EACH,QAAQ;AACP,WAAO;AAAA,EACR;AACD;",
6
+ "names": []
7
+ }
@@ -0,0 +1,66 @@
1
+ // packages/image-cropper/src/components/image-cropper/index.tsx
2
+ import Cropper from "react-easy-crop";
3
+ import { useCallback } from "@wordpress/element";
4
+ import { useImageCropper } from "../../provider";
5
+ import { MIN_ZOOM, MAX_ZOOM } from "../../constants";
6
+ import { jsx } from "react/jsx-runtime";
7
+ function ImageCropper({
8
+ src,
9
+ onLoad,
10
+ minZoom = MIN_ZOOM,
11
+ maxZoom = MAX_ZOOM,
12
+ ...props
13
+ }) {
14
+ const { cropperState, setCropperState } = useImageCropper();
15
+ const { crop, zoom, rotation, aspectRatio, flip } = cropperState;
16
+ const setCrop = (newCrop) => setCropperState({ crop: newCrop });
17
+ const setZoom = (newZoom) => setCropperState({ zoom: newZoom });
18
+ const setRotation = (newRotation) => setCropperState({ rotation: newRotation });
19
+ const setMediaSize = (newMediaSize) => setCropperState({ mediaSize: newMediaSize });
20
+ const onCropComplete = useCallback(
21
+ (areaPercentage, areaPixels) => {
22
+ setCropperState({
23
+ croppedArea: areaPercentage,
24
+ croppedAreaPixels: areaPixels
25
+ });
26
+ },
27
+ [setCropperState]
28
+ );
29
+ return /* @__PURE__ */ jsx(
30
+ Cropper,
31
+ {
32
+ classes: {
33
+ containerClassName: "image-cropper__container",
34
+ cropAreaClassName: "image-cropper__crop-area",
35
+ mediaClassName: "image-cropper__image"
36
+ },
37
+ minZoom,
38
+ maxZoom,
39
+ rotation,
40
+ image: src,
41
+ setMediaSize,
42
+ crop,
43
+ zoom,
44
+ aspect: aspectRatio,
45
+ onCropChange: setCrop,
46
+ onZoomChange: setZoom,
47
+ onCropComplete,
48
+ onMediaLoaded: (loadedMediaSize) => {
49
+ onLoad?.(loadedMediaSize);
50
+ },
51
+ onRotationChange: setRotation,
52
+ transform: [
53
+ `translate(${crop.x}px, ${crop.y}px)`,
54
+ `rotateZ(${rotation}deg)`,
55
+ `rotateY(${flip.horizontal ? 180 : 0}deg)`,
56
+ `rotateX(${flip.vertical ? 180 : 0}deg)`,
57
+ `scale(${zoom})`
58
+ ].join(" "),
59
+ ...props
60
+ }
61
+ );
62
+ }
63
+ export {
64
+ ImageCropper as default
65
+ };
66
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/components/image-cropper/index.tsx"],
4
+ "sourcesContent": ["/**\n * External dependencies\n */\nimport Cropper from 'react-easy-crop';\n\n/**\n * WordPress dependencies\n */\nimport { useCallback } from '@wordpress/element';\n\n/**\n * Internal dependencies\n */\nimport { useImageCropper } from '../../provider';\nimport type { Area, ImageCropperProps, MediaSize, Point } from '../../types';\nimport { MIN_ZOOM, MAX_ZOOM } from '../../constants';\n\nexport default function ImageCropper( {\n\tsrc,\n\tonLoad,\n\tminZoom = MIN_ZOOM,\n\tmaxZoom = MAX_ZOOM,\n\t...props\n}: ImageCropperProps ) {\n\tconst { cropperState, setCropperState } = useImageCropper();\n\tconst { crop, zoom, rotation, aspectRatio, flip } = cropperState;\n\n\tconst setCrop = ( newCrop: Point ) => setCropperState( { crop: newCrop } );\n\tconst setZoom = ( newZoom: number ) => setCropperState( { zoom: newZoom } );\n\tconst setRotation = ( newRotation: number ) =>\n\t\tsetCropperState( { rotation: newRotation } );\n\tconst setMediaSize = ( newMediaSize: MediaSize ) =>\n\t\tsetCropperState( { mediaSize: newMediaSize } );\n\n\t/**\n\t * Handles the crop complete event, when a user stops interacting with the cropper.\n\t * Updates the cropped area in percentages and pixels.\n\t *\n\t * @param {Area} areaPercentage - The area percentage.\n\t * @param {Area} areaPixels - The area pixels.\n\t */\n\tconst onCropComplete = useCallback(\n\t\t( areaPercentage: Area, areaPixels: Area ) => {\n\t\t\tsetCropperState( {\n\t\t\t\tcroppedArea: areaPercentage,\n\t\t\t\tcroppedAreaPixels: areaPixels,\n\t\t\t} );\n\t\t},\n\t\t[ setCropperState ]\n\t);\n\n\treturn (\n\t\t<Cropper\n\t\t\tclasses={ {\n\t\t\t\tcontainerClassName: 'image-cropper__container',\n\t\t\t\tcropAreaClassName: 'image-cropper__crop-area',\n\t\t\t\tmediaClassName: 'image-cropper__image',\n\t\t\t} }\n\t\t\tminZoom={ minZoom }\n\t\t\tmaxZoom={ maxZoom }\n\t\t\trotation={ rotation }\n\t\t\timage={ src }\n\t\t\tsetMediaSize={ setMediaSize }\n\t\t\tcrop={ crop }\n\t\t\tzoom={ zoom }\n\t\t\taspect={ aspectRatio }\n\t\t\tonCropChange={ setCrop }\n\t\t\tonZoomChange={ setZoom }\n\t\t\tonCropComplete={ onCropComplete }\n\t\t\tonMediaLoaded={ ( loadedMediaSize: MediaSize ) => {\n\t\t\t\tonLoad?.( loadedMediaSize );\n\t\t\t} }\n\t\t\tonRotationChange={ setRotation }\n\t\t\ttransform={ [\n\t\t\t\t`translate(${ crop.x }px, ${ crop.y }px)`,\n\t\t\t\t`rotateZ(${ rotation }deg)`,\n\t\t\t\t`rotateY(${ flip.horizontal ? 180 : 0 }deg)`,\n\t\t\t\t`rotateX(${ flip.vertical ? 180 : 0 }deg)`,\n\t\t\t\t`scale(${ zoom })`,\n\t\t\t].join( ' ' ) }\n\t\t\t{ ...props }\n\t\t/>\n\t);\n}\n"],
5
+ "mappings": ";AAGA,OAAO,aAAa;AAKpB,SAAS,mBAAmB;AAK5B,SAAS,uBAAuB;AAEhC,SAAS,UAAU,gBAAgB;AAqCjC;AAnCa,SAAR,aAA+B;AAAA,EACrC;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV,UAAU;AAAA,EACV,GAAG;AACJ,GAAuB;AACtB,QAAM,EAAE,cAAc,gBAAgB,IAAI,gBAAgB;AAC1D,QAAM,EAAE,MAAM,MAAM,UAAU,aAAa,KAAK,IAAI;AAEpD,QAAM,UAAU,CAAE,YAAoB,gBAAiB,EAAE,MAAM,QAAQ,CAAE;AACzE,QAAM,UAAU,CAAE,YAAqB,gBAAiB,EAAE,MAAM,QAAQ,CAAE;AAC1E,QAAM,cAAc,CAAE,gBACrB,gBAAiB,EAAE,UAAU,YAAY,CAAE;AAC5C,QAAM,eAAe,CAAE,iBACtB,gBAAiB,EAAE,WAAW,aAAa,CAAE;AAS9C,QAAM,iBAAiB;AAAA,IACtB,CAAE,gBAAsB,eAAsB;AAC7C,sBAAiB;AAAA,QAChB,aAAa;AAAA,QACb,mBAAmB;AAAA,MACpB,CAAE;AAAA,IACH;AAAA,IACA,CAAE,eAAgB;AAAA,EACnB;AAEA,SACC;AAAA,IAAC;AAAA;AAAA,MACA,SAAU;AAAA,QACT,oBAAoB;AAAA,QACpB,mBAAmB;AAAA,QACnB,gBAAgB;AAAA,MACjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAS;AAAA,MACT,cAAe;AAAA,MACf,cAAe;AAAA,MACf;AAAA,MACA,eAAgB,CAAE,oBAAgC;AACjD,iBAAU,eAAgB;AAAA,MAC3B;AAAA,MACA,kBAAmB;AAAA,MACnB,WAAY;AAAA,QACX,aAAc,KAAK,CAAE,OAAQ,KAAK,CAAE;AAAA,QACpC,WAAY,QAAS;AAAA,QACrB,WAAY,KAAK,aAAa,MAAM,CAAE;AAAA,QACtC,WAAY,KAAK,WAAW,MAAM,CAAE;AAAA,QACpC,SAAU,IAAK;AAAA,MAChB,EAAE,KAAM,GAAI;AAAA,MACV,GAAG;AAAA;AAAA,EACN;AAEF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,10 @@
1
+ // packages/image-cropper/src/constants.ts
2
+ var MIN_ZOOM = 1;
3
+ var MAX_ZOOM = 5;
4
+ var DEFAULT_ASPECT_RATIO_SLUG = "original";
5
+ export {
6
+ DEFAULT_ASPECT_RATIO_SLUG,
7
+ MAX_ZOOM,
8
+ MIN_ZOOM
9
+ };
10
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/constants.ts"],
4
+ "sourcesContent": ["export const MIN_ZOOM = 1;\nexport const MAX_ZOOM = 5;\nexport const DEFAULT_ASPECT_RATIO_SLUG = 'original';\n"],
5
+ "mappings": ";AAAO,IAAM,WAAW;AACjB,IAAM,WAAW;AACjB,IAAM,4BAA4B;",
6
+ "names": []
7
+ }
@@ -0,0 +1,12 @@
1
+ // packages/image-cropper/src/index.ts
2
+ import { default as default2 } from "./components/image-cropper";
3
+ import { useImageCropper, default as default3 } from "./provider";
4
+ export * from "./types";
5
+ import { normalizeRotation } from "./utils";
6
+ export {
7
+ default2 as ImageCropper,
8
+ default3 as ImageCropperProvider,
9
+ normalizeRotation,
10
+ useImageCropper
11
+ };
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts"],
4
+ "sourcesContent": ["export { default as ImageCropper } from './components/image-cropper';\nexport { useImageCropper, default as ImageCropperProvider } from './provider';\nexport * from './types';\nexport { normalizeRotation } from './utils';\n"],
5
+ "mappings": ";AAAA,SAAoB,WAAXA,gBAA+B;AACxC,SAAS,iBAA4B,WAAXA,gBAAuC;AACjE,cAAc;AACd,SAAS,yBAAyB;",
6
+ "names": ["default"]
7
+ }
@@ -0,0 +1,50 @@
1
+ // packages/image-cropper/src/provider/index.tsx
2
+ import { createContext, useContext, useMemo } from "@wordpress/element";
3
+ import useCropper from "./use-image-cropper";
4
+ import { MIN_ZOOM } from "../constants";
5
+ import { jsx } from "react/jsx-runtime";
6
+ var ImageCropperContext = createContext({
7
+ cropperState: {
8
+ crop: { x: 0, y: 0 },
9
+ croppedArea: { x: 0, y: 0, width: 100, height: 100 },
10
+ croppedAreaPixels: null,
11
+ zoom: MIN_ZOOM,
12
+ rotation: 0,
13
+ aspectRatio: 1,
14
+ flip: { horizontal: false, vertical: false },
15
+ mediaSize: null
16
+ },
17
+ setCropperState: () => {
18
+ },
19
+ resetState: null,
20
+ setResetState: () => {
21
+ },
22
+ isDirty: false,
23
+ reset: () => {
24
+ },
25
+ getCroppedImage: () => Promise.resolve(null)
26
+ });
27
+ function ImageCropperProvider({
28
+ children
29
+ }) {
30
+ const cropperApi = useCropper();
31
+ const contextValue = useMemo(() => {
32
+ return {
33
+ ...cropperApi
34
+ };
35
+ }, [cropperApi]);
36
+ return /* @__PURE__ */ jsx(ImageCropperContext.Provider, { value: contextValue, children });
37
+ }
38
+ var useImageCropper = () => {
39
+ const context = useContext(ImageCropperContext);
40
+ if (!context) {
41
+ throw new Error("Missing ImageCropperContext");
42
+ }
43
+ return context;
44
+ };
45
+ export {
46
+ ImageCropperContext,
47
+ ImageCropperProvider as default,
48
+ useImageCropper
49
+ };
50
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/provider/index.tsx"],
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { createContext, useContext, useMemo } from '@wordpress/element';\n\n/**\n * Internal dependencies\n */\nimport useCropper from './use-image-cropper';\nimport type { ImageCropperContextValue } from '../types';\nimport { MIN_ZOOM } from '../constants';\n\nexport const ImageCropperContext = createContext< ImageCropperContextValue >( {\n\tcropperState: {\n\t\tcrop: { x: 0, y: 0 },\n\t\tcroppedArea: { x: 0, y: 0, width: 100, height: 100 },\n\t\tcroppedAreaPixels: null,\n\t\tzoom: MIN_ZOOM,\n\t\trotation: 0,\n\t\taspectRatio: 1,\n\t\tflip: { horizontal: false, vertical: false },\n\t\tmediaSize: null,\n\t},\n\tsetCropperState: () => {},\n\tresetState: null,\n\tsetResetState: () => {},\n\tisDirty: false,\n\treset: () => {},\n\tgetCroppedImage: () => Promise.resolve( null ),\n} );\n\nexport default function ImageCropperProvider( {\n\tchildren,\n}: {\n\tchildren: React.ReactNode;\n} ) {\n\tconst cropperApi = useCropper();\n\tconst contextValue = useMemo( () => {\n\t\treturn {\n\t\t\t...cropperApi,\n\t\t};\n\t}, [ cropperApi ] );\n\n\treturn (\n\t\t<ImageCropperContext.Provider value={ contextValue }>\n\t\t\t{ children }\n\t\t</ImageCropperContext.Provider>\n\t);\n}\n\nexport const useImageCropper = () => {\n\tconst context = useContext( ImageCropperContext );\n\tif ( ! context ) {\n\t\tthrow new Error( 'Missing ImageCropperContext' );\n\t}\n\treturn context;\n};\n"],
5
+ "mappings": ";AAGA,SAAS,eAAe,YAAY,eAAe;AAKnD,OAAO,gBAAgB;AAEvB,SAAS,gBAAgB;AAkCvB;AAhCK,IAAM,sBAAsB,cAA2C;AAAA,EAC7E,cAAc;AAAA,IACb,MAAM,EAAE,GAAG,GAAG,GAAG,EAAE;AAAA,IACnB,aAAa,EAAE,GAAG,GAAG,GAAG,GAAG,OAAO,KAAK,QAAQ,IAAI;AAAA,IACnD,mBAAmB;AAAA,IACnB,MAAM;AAAA,IACN,UAAU;AAAA,IACV,aAAa;AAAA,IACb,MAAM,EAAE,YAAY,OAAO,UAAU,MAAM;AAAA,IAC3C,WAAW;AAAA,EACZ;AAAA,EACA,iBAAiB,MAAM;AAAA,EAAC;AAAA,EACxB,YAAY;AAAA,EACZ,eAAe,MAAM;AAAA,EAAC;AAAA,EACtB,SAAS;AAAA,EACT,OAAO,MAAM;AAAA,EAAC;AAAA,EACd,iBAAiB,MAAM,QAAQ,QAAS,IAAK;AAC9C,CAAE;AAEa,SAAR,qBAAuC;AAAA,EAC7C;AACD,GAEI;AACH,QAAM,aAAa,WAAW;AAC9B,QAAM,eAAe,QAAS,MAAM;AACnC,WAAO;AAAA,MACN,GAAG;AAAA,IACJ;AAAA,EACD,GAAG,CAAE,UAAW,CAAE;AAElB,SACC,oBAAC,oBAAoB,UAApB,EAA6B,OAAQ,cACnC,UACH;AAEF;AAEO,IAAM,kBAAkB,MAAM;AACpC,QAAM,UAAU,WAAY,mBAAoB;AAChD,MAAK,CAAE,SAAU;AAChB,UAAM,IAAI,MAAO,6BAA8B;AAAA,EAChD;AACA,SAAO;AACR;",
6
+ "names": []
7
+ }