@orioro/react-image-crop 0.0.1
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.
- package/README.md +1 -0
- package/dist/CheckeredBg/index.d.ts +2 -0
- package/dist/ImageCropDialog/ImageCropDialog.d.ts +3 -0
- package/dist/ImageCropDialog/InstructionsOverlay.d.ts +5 -0
- package/dist/ImageCropDialog/dialogSpec.d.ts +2 -0
- package/dist/ImageCropDialog/index.d.ts +3 -0
- package/dist/ImageCropDialog/onSubmitApplyCrop.d.ts +7 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.mjs +909 -0
- package/dist/types.d.ts +31 -0
- package/dist/util/applyImageCrop.d.ts +24 -0
- package/dist/util/compressImage.d.ts +4 -0
- package/dist/util/index.d.ts +3 -0
- package/dist/util/misc.d.ts +14 -0
- package/dist/util/tmp_appbackup.d.ts +20 -0
- package/package.json +43 -0
package/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Template react lib
|
@@ -0,0 +1,7 @@
|
|
1
|
+
import { Merge } from 'type-fest';
|
2
|
+
import { ImageCropDialogProps } from '../types';
|
3
|
+
import { ApplyImageCropOptions } from '../util';
|
4
|
+
export declare function onSubmitApplyCrop({ onSuccess, onError, ...options }: Merge<Pick<ApplyImageCropOptions, 'maxWidth' | 'maxHeight' | 'background'>, {
|
5
|
+
onSuccess: (file: File) => any;
|
6
|
+
onError: (error: any) => any;
|
7
|
+
}>): ImageCropDialogProps['onSubmit'];
|
package/dist/index.d.ts
ADDED
package/dist/index.mjs
ADDED
@@ -0,0 +1,909 @@
|
|
1
|
+
import styled from 'styled-components';
|
2
|
+
import React, { useCallback, useState, useEffect, useMemo } from 'react';
|
3
|
+
import { Dialog, Slider, IconButton } from '@radix-ui/themes';
|
4
|
+
import { withDefaults, Flex, Box, mergeable, Button, pickPromptUIProps, usePromptUI, SingleFileInput, LoadingOverlay, CANCELLED } from '@orioro/react-ui-core';
|
5
|
+
import Cropper from 'react-easy-crop';
|
6
|
+
import { useDebounce } from 'react-use';
|
7
|
+
import canvasSize from 'canvas-size';
|
8
|
+
import Compressor from 'compressorjs';
|
9
|
+
import { Icon } from '@mdi/react';
|
10
|
+
import { mdiMouseScrollWheel, mdiArrowAll, mdiGestureSpread, mdiGestureSwipe, mdiFlipHorizontal, mdiFlipVertical, mdiHelpCircleOutline } from '@mdi/js';
|
11
|
+
|
12
|
+
function _typeof(o) {
|
13
|
+
"@babel/helpers - typeof";
|
14
|
+
|
15
|
+
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
|
16
|
+
return typeof o;
|
17
|
+
} : function (o) {
|
18
|
+
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
|
19
|
+
}, _typeof(o);
|
20
|
+
}
|
21
|
+
|
22
|
+
var _assign = function __assign() {
|
23
|
+
_assign = Object.assign || function __assign(t) {
|
24
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
25
|
+
s = arguments[i];
|
26
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
|
27
|
+
}
|
28
|
+
return t;
|
29
|
+
};
|
30
|
+
return _assign.apply(this, arguments);
|
31
|
+
};
|
32
|
+
function __rest(s, e) {
|
33
|
+
var t = {};
|
34
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
|
35
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
36
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
|
37
|
+
}
|
38
|
+
return t;
|
39
|
+
}
|
40
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
41
|
+
function adopt(value) {
|
42
|
+
return value instanceof P ? value : new P(function (resolve) {
|
43
|
+
resolve(value);
|
44
|
+
});
|
45
|
+
}
|
46
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
47
|
+
function fulfilled(value) {
|
48
|
+
try {
|
49
|
+
step(generator.next(value));
|
50
|
+
} catch (e) {
|
51
|
+
reject(e);
|
52
|
+
}
|
53
|
+
}
|
54
|
+
function rejected(value) {
|
55
|
+
try {
|
56
|
+
step(generator["throw"](value));
|
57
|
+
} catch (e) {
|
58
|
+
reject(e);
|
59
|
+
}
|
60
|
+
}
|
61
|
+
function step(result) {
|
62
|
+
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
|
63
|
+
}
|
64
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
65
|
+
});
|
66
|
+
}
|
67
|
+
function __generator(thisArg, body) {
|
68
|
+
var _ = {
|
69
|
+
label: 0,
|
70
|
+
sent: function sent() {
|
71
|
+
if (t[0] & 1) throw t[1];
|
72
|
+
return t[1];
|
73
|
+
},
|
74
|
+
trys: [],
|
75
|
+
ops: []
|
76
|
+
},
|
77
|
+
f,
|
78
|
+
y,
|
79
|
+
t,
|
80
|
+
g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
81
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function () {
|
82
|
+
return this;
|
83
|
+
}), g;
|
84
|
+
function verb(n) {
|
85
|
+
return function (v) {
|
86
|
+
return step([n, v]);
|
87
|
+
};
|
88
|
+
}
|
89
|
+
function step(op) {
|
90
|
+
if (f) throw new TypeError("Generator is already executing.");
|
91
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
92
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
93
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
94
|
+
switch (op[0]) {
|
95
|
+
case 0:
|
96
|
+
case 1:
|
97
|
+
t = op;
|
98
|
+
break;
|
99
|
+
case 4:
|
100
|
+
_.label++;
|
101
|
+
return {
|
102
|
+
value: op[1],
|
103
|
+
done: false
|
104
|
+
};
|
105
|
+
case 5:
|
106
|
+
_.label++;
|
107
|
+
y = op[1];
|
108
|
+
op = [0];
|
109
|
+
continue;
|
110
|
+
case 7:
|
111
|
+
op = _.ops.pop();
|
112
|
+
_.trys.pop();
|
113
|
+
continue;
|
114
|
+
default:
|
115
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
|
116
|
+
_ = 0;
|
117
|
+
continue;
|
118
|
+
}
|
119
|
+
if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
|
120
|
+
_.label = op[1];
|
121
|
+
break;
|
122
|
+
}
|
123
|
+
if (op[0] === 6 && _.label < t[1]) {
|
124
|
+
_.label = t[1];
|
125
|
+
t = op;
|
126
|
+
break;
|
127
|
+
}
|
128
|
+
if (t && _.label < t[2]) {
|
129
|
+
_.label = t[2];
|
130
|
+
_.ops.push(op);
|
131
|
+
break;
|
132
|
+
}
|
133
|
+
if (t[2]) _.ops.pop();
|
134
|
+
_.trys.pop();
|
135
|
+
continue;
|
136
|
+
}
|
137
|
+
op = body.call(thisArg, _);
|
138
|
+
} catch (e) {
|
139
|
+
op = [6, e];
|
140
|
+
y = 0;
|
141
|
+
} finally {
|
142
|
+
f = t = 0;
|
143
|
+
}
|
144
|
+
if (op[0] & 5) throw op[1];
|
145
|
+
return {
|
146
|
+
value: op[0] ? op[1] : void 0,
|
147
|
+
done: true
|
148
|
+
};
|
149
|
+
}
|
150
|
+
}
|
151
|
+
function __makeTemplateObject(cooked, raw) {
|
152
|
+
if (Object.defineProperty) {
|
153
|
+
Object.defineProperty(cooked, "raw", {
|
154
|
+
value: raw
|
155
|
+
});
|
156
|
+
} else {
|
157
|
+
cooked.raw = raw;
|
158
|
+
}
|
159
|
+
return cooked;
|
160
|
+
}
|
161
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
162
|
+
var e = new Error(message);
|
163
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
164
|
+
};
|
165
|
+
|
166
|
+
var CheckeredBg = styled.div(templateObject_1$2 || (templateObject_1$2 = __makeTemplateObject(["\n font-size: 24px;\n --backgroundColor: rgba(239, 239, 239);\n --squareColor: rgba(204, 204, 204);\n --squareSize: 2em;\n\n background-color: var(--backgroundColor);\n background-image: linear-gradient(\n 45deg,\n var(--squareColor) 25%,\n transparent 25%\n ),\n linear-gradient(135deg, var(--squareColor) 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, var(--squareColor) 75%),\n linear-gradient(135deg, transparent 75%, var(--squareColor) 75%);\n background-size: calc(2 * var(--squareSize)) calc(2 * var(--squareSize));\n background-position:\n 0 0,\n var(--squareSize) 0,\n var(--squareSize) calc(-1 * var(--squareSize)),\n 0 calc(-1 * var(--squareSize));\n\n > img {\n display: block;\n width: 100%;\n height: 100%;\n }\n"], ["\n font-size: 24px;\n --backgroundColor: rgba(239, 239, 239);\n --squareColor: rgba(204, 204, 204);\n --squareSize: 2em;\n\n background-color: var(--backgroundColor);\n background-image: linear-gradient(\n 45deg,\n var(--squareColor) 25%,\n transparent 25%\n ),\n linear-gradient(135deg, var(--squareColor) 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, var(--squareColor) 75%),\n linear-gradient(135deg, transparent 75%, var(--squareColor) 75%);\n background-size: calc(2 * var(--squareSize)) calc(2 * var(--squareSize));\n background-position:\n 0 0,\n var(--squareSize) 0,\n var(--squareSize) calc(-1 * var(--squareSize)),\n 0 calc(-1 * var(--squareSize));\n\n > img {\n display: block;\n width: 100%;\n height: 100%;\n }\n"])));
|
167
|
+
var templateObject_1$2;
|
168
|
+
|
169
|
+
function toImageUrl(src) {
|
170
|
+
if (typeof src === 'string') {
|
171
|
+
return src;
|
172
|
+
} else if (src instanceof File || src instanceof Blob) {
|
173
|
+
return URL.createObjectURL(src);
|
174
|
+
} else {
|
175
|
+
return src.url;
|
176
|
+
}
|
177
|
+
}
|
178
|
+
function toImageFile(src) {
|
179
|
+
return __awaiter(this, void 0, void 0, function () {
|
180
|
+
var url, response, blob, file;
|
181
|
+
return __generator(this, function (_a) {
|
182
|
+
switch (_a.label) {
|
183
|
+
case 0:
|
184
|
+
if (!(src instanceof File)) return [3 /*break*/, 1];
|
185
|
+
return [2 /*return*/, src];
|
186
|
+
case 1:
|
187
|
+
if (!(src instanceof Blob)) return [3 /*break*/, 2];
|
188
|
+
return [2 /*return*/, new File([src], 'image', {
|
189
|
+
type: src.type
|
190
|
+
})];
|
191
|
+
case 2:
|
192
|
+
url = typeof src === 'string' ? src : src.url;
|
193
|
+
return [4 /*yield*/, fetch(url)];
|
194
|
+
case 3:
|
195
|
+
response = _a.sent();
|
196
|
+
if (!response.ok) {
|
197
|
+
throw new Error("Failed to fetch ".concat(url, ": ").concat(response.statusText));
|
198
|
+
}
|
199
|
+
return [4 /*yield*/, response.blob()
|
200
|
+
// Step 3: Create a File object from the Blob
|
201
|
+
];
|
202
|
+
case 4:
|
203
|
+
blob = _a.sent();
|
204
|
+
file = new File([blob], inferImageName(src), {
|
205
|
+
type: blob.type
|
206
|
+
});
|
207
|
+
return [2 /*return*/, file];
|
208
|
+
}
|
209
|
+
});
|
210
|
+
});
|
211
|
+
}
|
212
|
+
function inferImageName(src) {
|
213
|
+
if (typeof src === 'string') {
|
214
|
+
var parts = src.split(/s*\/s*/g);
|
215
|
+
return parts[parts.length - 1];
|
216
|
+
} else if (src instanceof File) {
|
217
|
+
return src.name;
|
218
|
+
} else if (src === null || src instanceof Blob) {
|
219
|
+
return 'image';
|
220
|
+
} else if (_typeof(src) === 'object') {
|
221
|
+
return inferImageName(src.url);
|
222
|
+
} else {
|
223
|
+
return 'image';
|
224
|
+
}
|
225
|
+
}
|
226
|
+
function canvasToBlobPromise(canvas, mimeType) {
|
227
|
+
if (mimeType === void 0) {
|
228
|
+
mimeType = 'image/png';
|
229
|
+
}
|
230
|
+
return new Promise(function (resolve, reject) {
|
231
|
+
canvas.toBlob(function (file) {
|
232
|
+
if (file) {
|
233
|
+
resolve(file);
|
234
|
+
} else {
|
235
|
+
reject(new Error('Failed to create blob'));
|
236
|
+
}
|
237
|
+
}, mimeType);
|
238
|
+
});
|
239
|
+
}
|
240
|
+
var createImage = function createImage(src) {
|
241
|
+
return __awaiter(void 0, void 0, void 0, function () {
|
242
|
+
var url;
|
243
|
+
return __generator(this, function (_a) {
|
244
|
+
switch (_a.label) {
|
245
|
+
case 0:
|
246
|
+
return [4 /*yield*/, toImageUrl(src)];
|
247
|
+
case 1:
|
248
|
+
url = _a.sent();
|
249
|
+
if (!url) {
|
250
|
+
throw new Error('Error retrieving image url');
|
251
|
+
}
|
252
|
+
return [2 /*return*/, new Promise(function (resolve, reject) {
|
253
|
+
var image = new Image();
|
254
|
+
image.addEventListener('load', function () {
|
255
|
+
return resolve(image);
|
256
|
+
});
|
257
|
+
image.addEventListener('error', function (error) {
|
258
|
+
return reject(error);
|
259
|
+
});
|
260
|
+
image.setAttribute('crossOrigin', 'anonymous'); // needed to avoid cross-origin issues on CodeSandbox
|
261
|
+
image.src = url;
|
262
|
+
})];
|
263
|
+
}
|
264
|
+
});
|
265
|
+
});
|
266
|
+
};
|
267
|
+
function drawCanvas(_a) {
|
268
|
+
var width = _a.width,
|
269
|
+
height = _a.height,
|
270
|
+
_b = _a.background,
|
271
|
+
background = _b === void 0 ? 'transparent' : _b;
|
272
|
+
var canvas = document.createElement('canvas');
|
273
|
+
var ctx = canvas.getContext('2d');
|
274
|
+
if (!ctx) {
|
275
|
+
throw new Error('Could not retrieve canvas context');
|
276
|
+
}
|
277
|
+
canvas.width = width;
|
278
|
+
canvas.height = height;
|
279
|
+
if (background === 'transparent') {
|
280
|
+
ctx.clearRect(0, 0, width, height);
|
281
|
+
} else {
|
282
|
+
ctx.fillStyle = background;
|
283
|
+
ctx.fillRect(0, 0, width, height);
|
284
|
+
ctx.fillStyle = '#000';
|
285
|
+
}
|
286
|
+
return {
|
287
|
+
canvas: canvas,
|
288
|
+
ctx: ctx
|
289
|
+
};
|
290
|
+
}
|
291
|
+
|
292
|
+
function getRadianAngle(degreeValue) {
|
293
|
+
return degreeValue * Math.PI / 180;
|
294
|
+
}
|
295
|
+
/**
|
296
|
+
* Returns the new bounding area of a rotated rectangle.
|
297
|
+
*/
|
298
|
+
function computeRotationSize(width, height, rotation) {
|
299
|
+
var rotRad = getRadianAngle(rotation);
|
300
|
+
return {
|
301
|
+
width: Math.abs(Math.cos(rotRad) * width) + Math.abs(Math.sin(rotRad) * height),
|
302
|
+
height: Math.abs(Math.sin(rotRad) * width) + Math.abs(Math.cos(rotRad) * height)
|
303
|
+
};
|
304
|
+
}
|
305
|
+
function _scaleProperties(obj, factor) {
|
306
|
+
return Object.fromEntries(Object.entries(obj).map(function (_a) {
|
307
|
+
var key = _a[0],
|
308
|
+
value = _a[1];
|
309
|
+
return [key, factor * value];
|
310
|
+
}));
|
311
|
+
}
|
312
|
+
/**
|
313
|
+
* This function was adapted from the one in the ReadMe of https://github.com/DominicTobias/react-image-crop
|
314
|
+
*/
|
315
|
+
function applyImageCrop(src, _a) {
|
316
|
+
var area = _a.area,
|
317
|
+
_b = _a.flipHorizontal,
|
318
|
+
flipHorizontal = _b === void 0 ? false : _b,
|
319
|
+
_c = _a.flipVertical,
|
320
|
+
flipVertical = _c === void 0 ? false : _c,
|
321
|
+
_d = _a.rotation,
|
322
|
+
rotation = _d === void 0 ? 0 : _d,
|
323
|
+
_e = _a.background,
|
324
|
+
background = _e === void 0 ? 'transparent' : _e,
|
325
|
+
_f = _a.mimeType,
|
326
|
+
mimeType = _f === void 0 ? 'image/png' : _f,
|
327
|
+
_g = _a.maxWidth,
|
328
|
+
maxWidth = _g === void 0 ? Infinity : _g,
|
329
|
+
_h = _a.maxHeight,
|
330
|
+
maxHeight = _h === void 0 ? Infinity : _h;
|
331
|
+
return __awaiter(this, void 0, void 0, function () {
|
332
|
+
var image, rotRad, _j, bBoxWidth, bBoxHeight, canvasMaxSize, finalMaxWidth, finalMaxHeight, canvasMaxSizeScaleFactor, dimensions, transferCanvas, cropCanvas;
|
333
|
+
return __generator(this, function (_k) {
|
334
|
+
switch (_k.label) {
|
335
|
+
case 0:
|
336
|
+
return [4 /*yield*/, createImage(src)];
|
337
|
+
case 1:
|
338
|
+
image = _k.sent();
|
339
|
+
rotRad = getRadianAngle(rotation);
|
340
|
+
_j = computeRotationSize(image.width, image.height, rotation), bBoxWidth = _j.width, bBoxHeight = _j.height;
|
341
|
+
return [4 /*yield*/, canvasSize.maxArea()];
|
342
|
+
case 2:
|
343
|
+
canvasMaxSize = _k.sent();
|
344
|
+
finalMaxWidth = Math.min(maxWidth, canvasMaxSize.width);
|
345
|
+
finalMaxHeight = Math.min(maxHeight, canvasMaxSize.height);
|
346
|
+
canvasMaxSizeScaleFactor = Math.min(1, finalMaxWidth / bBoxWidth, finalMaxHeight / bBoxHeight, finalMaxWidth / area.width, finalMaxHeight / area.height);
|
347
|
+
dimensions = {
|
348
|
+
//
|
349
|
+
// Scaled image dimensions
|
350
|
+
//
|
351
|
+
image: _scaleProperties({
|
352
|
+
width: image.width,
|
353
|
+
height: image.height
|
354
|
+
}, canvasMaxSizeScaleFactor),
|
355
|
+
//
|
356
|
+
// The canvas on which rotation operation will be executed
|
357
|
+
//
|
358
|
+
transferCanvas: _scaleProperties({
|
359
|
+
width: bBoxWidth,
|
360
|
+
height: bBoxHeight
|
361
|
+
}, canvasMaxSizeScaleFactor),
|
362
|
+
//
|
363
|
+
// Crop area
|
364
|
+
//
|
365
|
+
area: _scaleProperties(area, canvasMaxSizeScaleFactor)
|
366
|
+
};
|
367
|
+
transferCanvas = drawCanvas({
|
368
|
+
width: dimensions.transferCanvas.width,
|
369
|
+
height: dimensions.transferCanvas.height,
|
370
|
+
background: background
|
371
|
+
});
|
372
|
+
// translate canvas context to a central location to allow rotating and flipping around the center
|
373
|
+
transferCanvas.ctx.translate(dimensions.transferCanvas.width / 2, dimensions.transferCanvas.height / 2);
|
374
|
+
transferCanvas.ctx.rotate(rotRad);
|
375
|
+
transferCanvas.ctx.scale(flipHorizontal ? -1 : 1, flipVertical ? -1 : 1);
|
376
|
+
transferCanvas.ctx.translate(-dimensions.image.width / 2, -dimensions.image.height / 2);
|
377
|
+
// Draw rotated image onto transfer canvas
|
378
|
+
transferCanvas.ctx.drawImage(image, 0,
|
379
|
+
// source x
|
380
|
+
0,
|
381
|
+
// source y
|
382
|
+
dimensions.image.width,
|
383
|
+
// source width
|
384
|
+
dimensions.image.height);
|
385
|
+
cropCanvas = drawCanvas({
|
386
|
+
width: dimensions.area.width,
|
387
|
+
height: dimensions.area.height,
|
388
|
+
background: background
|
389
|
+
});
|
390
|
+
// Draw the cropped image onto the new canvas
|
391
|
+
cropCanvas.ctx.drawImage(transferCanvas.canvas,
|
392
|
+
// prevent negative positions (bug detected on iOS)
|
393
|
+
dimensions.area.x < 0 ? 0 : dimensions.area.x,
|
394
|
+
// source x
|
395
|
+
dimensions.area.y < 0 ? 0 : dimensions.area.y,
|
396
|
+
// source y
|
397
|
+
dimensions.area.width,
|
398
|
+
// source width
|
399
|
+
dimensions.area.height,
|
400
|
+
// source height
|
401
|
+
// transfer negative positions to drawing target (bug detected on iOS)
|
402
|
+
dimensions.area.x < 0 ? -1 * dimensions.area.x : 0,
|
403
|
+
// target x
|
404
|
+
dimensions.area.y < 0 ? -1 * dimensions.area.y : 0,
|
405
|
+
// target y
|
406
|
+
dimensions.area.width,
|
407
|
+
// target width
|
408
|
+
dimensions.area.height);
|
409
|
+
// Export as blob
|
410
|
+
return [2 /*return*/, canvasToBlobPromise(cropCanvas.canvas, mimeType)];
|
411
|
+
}
|
412
|
+
});
|
413
|
+
});
|
414
|
+
}
|
415
|
+
|
416
|
+
function compressImage(input, options) {
|
417
|
+
if (options === void 0) {
|
418
|
+
options = {};
|
419
|
+
}
|
420
|
+
return __awaiter(this, void 0, void 0, function () {
|
421
|
+
return __generator(this, function (_a) {
|
422
|
+
return [2 /*return*/, new Promise(function (resolve, reject) {
|
423
|
+
new Compressor(input, _assign({
|
424
|
+
success: function success(output) {
|
425
|
+
if (input instanceof File) {
|
426
|
+
if (output instanceof Blob) {
|
427
|
+
resolve(new File([output], input.name, {
|
428
|
+
type: input.type
|
429
|
+
}));
|
430
|
+
} else {
|
431
|
+
resolve(output);
|
432
|
+
}
|
433
|
+
} else {
|
434
|
+
resolve(output);
|
435
|
+
}
|
436
|
+
},
|
437
|
+
error: function error(_error) {
|
438
|
+
reject(_error);
|
439
|
+
}
|
440
|
+
}, options));
|
441
|
+
})];
|
442
|
+
});
|
443
|
+
});
|
444
|
+
}
|
445
|
+
|
446
|
+
var InstructionBlock = withDefaults(styled(Flex)(templateObject_1$1 || (templateObject_1$1 = __makeTemplateObject(["\n width: 100px;\n font-size: 1rem;\n text-align: center;\n "], ["\n width: 100px;\n font-size: 1rem;\n text-align: center;\n "]))), {
|
447
|
+
direction: 'column',
|
448
|
+
alignItems: 'center',
|
449
|
+
gap: '3'
|
450
|
+
});
|
451
|
+
var InstructionsLayout = withDefaults(Flex, {
|
452
|
+
direction: 'row',
|
453
|
+
gap: '5',
|
454
|
+
height: '100%',
|
455
|
+
alignItems: 'center',
|
456
|
+
justifyContent: 'center'
|
457
|
+
});
|
458
|
+
var MouseInstructions = styled.div(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n height: 100%;\n display: none;\n\n @media (pointer: fine) {\n display: block;\n }\n"], ["\n height: 100%;\n display: none;\n\n @media (pointer: fine) {\n display: block;\n }\n"])));
|
459
|
+
var TouchInstructions = styled.div(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n height: 100%;\n display: none;\n\n @media (pointer: coarse) {\n display: block;\n }\n"], ["\n height: 100%;\n display: none;\n\n @media (pointer: coarse) {\n display: block;\n }\n"])));
|
460
|
+
function InstructionsOverlay(_a) {
|
461
|
+
var _b = _a.active,
|
462
|
+
active = _b === void 0 ? true : _b,
|
463
|
+
_c = _a.style,
|
464
|
+
style = _c === void 0 ? {} : _c;
|
465
|
+
return /*#__PURE__*/React.createElement(Box, {
|
466
|
+
style: _assign({
|
467
|
+
position: 'absolute',
|
468
|
+
zIndex: 2,
|
469
|
+
top: 0,
|
470
|
+
left: 0,
|
471
|
+
right: 0,
|
472
|
+
bottom: 0,
|
473
|
+
transition: 'opacity .5s ease, backdrop-filter .5s ease',
|
474
|
+
opacity: active ? 1 : 0,
|
475
|
+
backdropFilter: active ? 'blur(10px)' : 'none',
|
476
|
+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
477
|
+
color: 'white',
|
478
|
+
pointerEvents: 'none'
|
479
|
+
}, style)
|
480
|
+
}, /*#__PURE__*/React.createElement(MouseInstructions, null, /*#__PURE__*/React.createElement(InstructionsLayout, null, /*#__PURE__*/React.createElement(InstructionBlock, null, /*#__PURE__*/React.createElement(Icon, {
|
481
|
+
path: mdiMouseScrollWheel,
|
482
|
+
size: 1.5
|
483
|
+
}), /*#__PURE__*/React.createElement("div", null, "Use scroll para zoom")), /*#__PURE__*/React.createElement(InstructionBlock, null, /*#__PURE__*/React.createElement(Icon, {
|
484
|
+
path: mdiArrowAll,
|
485
|
+
size: 1.5
|
486
|
+
}), /*#__PURE__*/React.createElement("div", null, "Arraste para reposicionar")))), /*#__PURE__*/React.createElement(TouchInstructions, null, /*#__PURE__*/React.createElement(InstructionsLayout, null, /*#__PURE__*/React.createElement(InstructionBlock, null, /*#__PURE__*/React.createElement(Icon, {
|
487
|
+
path: mdiGestureSpread,
|
488
|
+
size: 1.5
|
489
|
+
}), /*#__PURE__*/React.createElement("div", null, "Use dois dedos para zoom")), /*#__PURE__*/React.createElement(InstructionBlock, null, /*#__PURE__*/React.createElement(Icon, {
|
490
|
+
path: mdiGestureSwipe,
|
491
|
+
size: 1.5
|
492
|
+
}), /*#__PURE__*/React.createElement("div", null, "Arraste para reposicionar")))));
|
493
|
+
}
|
494
|
+
var templateObject_1$1, templateObject_2, templateObject_3;
|
495
|
+
|
496
|
+
var CropperContainer = styled.div(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n position: relative;\n height: 400px;\n"], ["\n position: relative;\n height: 400px;\n"])));
|
497
|
+
var SupportButton = mergeable(Button, {
|
498
|
+
variant: 'soft',
|
499
|
+
color: 'gray',
|
500
|
+
type: 'button'
|
501
|
+
});
|
502
|
+
var Submit = mergeable(Button, {
|
503
|
+
type: 'submit'
|
504
|
+
});
|
505
|
+
function Control(_a) {
|
506
|
+
var label = _a.label,
|
507
|
+
children = _a.children;
|
508
|
+
return /*#__PURE__*/React.createElement(Flex, {
|
509
|
+
direction: "column",
|
510
|
+
gap: "2"
|
511
|
+
}, /*#__PURE__*/React.createElement("label", {
|
512
|
+
style: {
|
513
|
+
fontWeight: 'bold',
|
514
|
+
fontSize: '.9rem'
|
515
|
+
}
|
516
|
+
}, label), children);
|
517
|
+
}
|
518
|
+
function initialValue(_a) {
|
519
|
+
var src = _a.src,
|
520
|
+
background = _a.background;
|
521
|
+
return {
|
522
|
+
src: src,
|
523
|
+
background: background,
|
524
|
+
originalSize: undefined,
|
525
|
+
area: undefined,
|
526
|
+
areaPercentage: undefined,
|
527
|
+
rotation: 0,
|
528
|
+
zoom: 1,
|
529
|
+
flipHorizontal: false,
|
530
|
+
flipVertical: false
|
531
|
+
};
|
532
|
+
}
|
533
|
+
var CENTER_CROP_POSITION = {
|
534
|
+
x: 0,
|
535
|
+
y: 0
|
536
|
+
};
|
537
|
+
function ImageCropDialog(props) {
|
538
|
+
var _this = this;
|
539
|
+
var _a = pickPromptUIProps(_assign({}, props)),
|
540
|
+
promptUIProps = _a[0],
|
541
|
+
_b = _a[1],
|
542
|
+
_c = _b.open,
|
543
|
+
open = _c === void 0 ? false : _c,
|
544
|
+
_d = _b.src,
|
545
|
+
src = _d === void 0 ? null : _d,
|
546
|
+
_e = _b.background,
|
547
|
+
background = _e === void 0 ? 'transparent' : _e,
|
548
|
+
_f = _b.aspectRatio,
|
549
|
+
aspectRatio = _f === void 0 ? 1 : _f,
|
550
|
+
_g = _b.loading,
|
551
|
+
loading = _g === void 0 ? 'Carregando' : _g,
|
552
|
+
_h = _b.submit,
|
553
|
+
submit = _h === void 0 ? 'Enviar' : _h,
|
554
|
+
_j = _b.cancel,
|
555
|
+
cancel = _j === void 0 ? 'Cancelar' : _j,
|
556
|
+
_k = _b.zoom,
|
557
|
+
enableZoom = _k === void 0 ? false : _k,
|
558
|
+
_l = _b.minZoom,
|
559
|
+
minZoom = _l === void 0 ? 0.3 : _l,
|
560
|
+
_m = _b.maxZoom,
|
561
|
+
maxZoom = _m === void 0 ? 5 : _m,
|
562
|
+
_o = _b.rotation,
|
563
|
+
enableRotation = _o === void 0 ? false : _o,
|
564
|
+
_p = _b.flip,
|
565
|
+
enableFlip = _p === void 0 ? false : _p,
|
566
|
+
_q = _b.restrictPosition,
|
567
|
+
restrictPosition = _q === void 0 ? true : _q;
|
568
|
+
var promptUI = usePromptUI(_assign(_assign({}, promptUIProps), {
|
569
|
+
active: open,
|
570
|
+
initialValue: initialValue({
|
571
|
+
src: src,
|
572
|
+
background: background
|
573
|
+
})
|
574
|
+
}));
|
575
|
+
var currentState = promptUI.value;
|
576
|
+
var onCropComplete = useCallback(function (areaPercentage, area) {
|
577
|
+
promptUI.setValue(_assign(_assign({}, currentState), {
|
578
|
+
area: area,
|
579
|
+
areaPercentage: areaPercentage
|
580
|
+
}));
|
581
|
+
}, [promptUI.value]);
|
582
|
+
var _r = useState(false),
|
583
|
+
openReady = _r[0],
|
584
|
+
setOpenReady = _r[1];
|
585
|
+
useEffect(function () {
|
586
|
+
if (open) {
|
587
|
+
// Re-center
|
588
|
+
_setCropPos(CENTER_CROP_POSITION);
|
589
|
+
//
|
590
|
+
// Wait for dialog scale transition to be ready before
|
591
|
+
// rendering cropper: react-easy-crop has trouble
|
592
|
+
// rendering when inside elements that animate size (transform: scale)
|
593
|
+
//
|
594
|
+
// https://github.com/ValentinH/react-easy-crop/issues/428
|
595
|
+
// https://github.com/ValentinH/react-easy-crop/issues/409
|
596
|
+
// https://github.com/ValentinH/react-easy-crop/issues/267
|
597
|
+
// https://github.com/ValentinH/react-easy-crop/issues/400
|
598
|
+
//
|
599
|
+
var readyDelayTimeout_1 = setTimeout(function () {
|
600
|
+
return setOpenReady(true);
|
601
|
+
}, 200);
|
602
|
+
return function () {
|
603
|
+
return clearTimeout(readyDelayTimeout_1);
|
604
|
+
};
|
605
|
+
} else {
|
606
|
+
setOpenReady(false);
|
607
|
+
}
|
608
|
+
}, [open]);
|
609
|
+
var _srcImageUrl = useMemo(function () {
|
610
|
+
return currentState.src ? toImageUrl(currentState.src) : null;
|
611
|
+
}, [currentState.src]);
|
612
|
+
//
|
613
|
+
// Zoom and rotation are controlled simultaneously in mobile,
|
614
|
+
// store in separate states in order to be capable of handling
|
615
|
+
// their simultaneous changes
|
616
|
+
//
|
617
|
+
var _s = useState(1),
|
618
|
+
_zoom = _s[0],
|
619
|
+
_setZoom = _s[1];
|
620
|
+
var _t = useState(0),
|
621
|
+
_rotation = _t[0],
|
622
|
+
_setRotation = _t[1];
|
623
|
+
var _u = useState(CENTER_CROP_POSITION),
|
624
|
+
_cropPos = _u[0],
|
625
|
+
_setCropPos = _u[1];
|
626
|
+
useDebounce(function () {
|
627
|
+
promptUI.setValue(_assign(_assign({}, currentState), {
|
628
|
+
zoom: _zoom,
|
629
|
+
rotation: _rotation
|
630
|
+
}));
|
631
|
+
}, 200, [_zoom, _rotation]);
|
632
|
+
var EFFECTIVE_MIN_ZOOM = useMemo(function () {
|
633
|
+
return restrictPosition ? Math.max(1, minZoom) : minZoom;
|
634
|
+
}, [minZoom, restrictPosition]);
|
635
|
+
var _v = useState(false),
|
636
|
+
showInstructions = _v[0],
|
637
|
+
setShowInstructions = _v[1];
|
638
|
+
// //
|
639
|
+
// // https://github.com/ValentinH/react-easy-crop/issues/435
|
640
|
+
// //
|
641
|
+
// const _finalCropPos = useMemo(
|
642
|
+
// () => (restrictPosition && _zoom < 1 ? CENTER_CROP_POSITION : _cropPos),
|
643
|
+
// [_cropPos, _zoom, restrictPosition],
|
644
|
+
// )
|
645
|
+
//
|
646
|
+
// Resets all modifications
|
647
|
+
//
|
648
|
+
function _resetChanges() {
|
649
|
+
_setCropPos({
|
650
|
+
x: 0,
|
651
|
+
y: 0
|
652
|
+
});
|
653
|
+
_setZoom(1);
|
654
|
+
_setRotation(0);
|
655
|
+
}
|
656
|
+
//
|
657
|
+
// Resets all modifications redefines image
|
658
|
+
//
|
659
|
+
function _clear() {
|
660
|
+
_resetChanges();
|
661
|
+
promptUI.setValue(initialValue({
|
662
|
+
src: null,
|
663
|
+
background: background
|
664
|
+
}));
|
665
|
+
setShowInstructions(false);
|
666
|
+
}
|
667
|
+
useEffect(function () {
|
668
|
+
if (!open) {
|
669
|
+
_clear();
|
670
|
+
} else {
|
671
|
+
setShowInstructions(true);
|
672
|
+
var instructionsTimeout_1 = setTimeout(function () {
|
673
|
+
return setShowInstructions(false);
|
674
|
+
}, 2000);
|
675
|
+
return function () {
|
676
|
+
return clearTimeout(instructionsTimeout_1);
|
677
|
+
};
|
678
|
+
}
|
679
|
+
}, [open]);
|
680
|
+
return /*#__PURE__*/React.createElement(Dialog.Root, {
|
681
|
+
open: open
|
682
|
+
}, /*#__PURE__*/React.createElement(Dialog.Content, {
|
683
|
+
onEscapeKeyDown: promptUI.cancel,
|
684
|
+
onPointerDownOutside: promptUI.cancel
|
685
|
+
}, /*#__PURE__*/React.createElement("form", {
|
686
|
+
onSubmit: function onSubmit(e) {
|
687
|
+
return __awaiter(_this, void 0, void 0, function () {
|
688
|
+
return __generator(this, function (_a) {
|
689
|
+
e.preventDefault();
|
690
|
+
promptUI.submit();
|
691
|
+
return [2 /*return*/];
|
692
|
+
});
|
693
|
+
});
|
694
|
+
}
|
695
|
+
}, /*#__PURE__*/React.createElement(Flex, {
|
696
|
+
direction: "column",
|
697
|
+
gap: "3"
|
698
|
+
}, !Boolean(currentState.src) && ( /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(SingleFileInput, {
|
699
|
+
value: currentState.src,
|
700
|
+
onSetValue: function onSetValue(file) {
|
701
|
+
return promptUI.setValue(_assign(_assign({}, currentState), {
|
702
|
+
src: file
|
703
|
+
}));
|
704
|
+
},
|
705
|
+
accept: "image/*"
|
706
|
+
}))), _srcImageUrl && ( /*#__PURE__*/React.createElement(Flex, {
|
707
|
+
direction: "column"
|
708
|
+
}, /*#__PURE__*/React.createElement(CheckeredBg, null, /*#__PURE__*/React.createElement(CropperContainer, {
|
709
|
+
style: {
|
710
|
+
backgroundColor: background
|
711
|
+
}
|
712
|
+
}, openReady ? ( /*#__PURE__*/React.createElement(Cropper, {
|
713
|
+
image: _srcImageUrl,
|
714
|
+
transform: ["translate(".concat(_cropPos.x, "px, ").concat(_cropPos.y, "px)"), "rotateY(".concat(currentState.flipHorizontal ? 180 : 0, "deg)"), "rotateX(".concat(currentState.flipVertical ? 180 : 0, "deg)"), "rotateZ(".concat(_rotation, "deg)"), "scale(".concat(_zoom, ")")].join(' '),
|
715
|
+
crop: _cropPos,
|
716
|
+
onCropChange: _setCropPos,
|
717
|
+
aspect: aspectRatio,
|
718
|
+
onCropComplete: onCropComplete,
|
719
|
+
zoom: _zoom,
|
720
|
+
minZoom: EFFECTIVE_MIN_ZOOM,
|
721
|
+
maxZoom: maxZoom,
|
722
|
+
onZoomChange: function onZoomChange(zoom) {
|
723
|
+
return _setZoom(zoom);
|
724
|
+
},
|
725
|
+
rotation: _rotation,
|
726
|
+
onRotationChange: function onRotationChange(rotation) {
|
727
|
+
return _setRotation(rotation % 360);
|
728
|
+
},
|
729
|
+
onMediaLoaded: function onMediaLoaded(mediaSize) {
|
730
|
+
return promptUI.setValue(_assign(_assign({}, currentState), {
|
731
|
+
originalSize: {
|
732
|
+
width: mediaSize.naturalWidth,
|
733
|
+
height: mediaSize.naturalHeight
|
734
|
+
}
|
735
|
+
}));
|
736
|
+
},
|
737
|
+
restrictPosition: restrictPosition,
|
738
|
+
objectFit: props.objectFit
|
739
|
+
})) : ( /*#__PURE__*/React.createElement(LoadingOverlay, {
|
740
|
+
message: loading
|
741
|
+
})), promptUI.isLoading && ( /*#__PURE__*/React.createElement(LoadingOverlay, {
|
742
|
+
message: "Processando"
|
743
|
+
})), /*#__PURE__*/React.createElement(InstructionsOverlay, {
|
744
|
+
active: showInstructions
|
745
|
+
}))), (enableZoom || enableRotation) && ( /*#__PURE__*/React.createElement(Flex, {
|
746
|
+
direction: {
|
747
|
+
xs: 'column',
|
748
|
+
md: 'row'
|
749
|
+
},
|
750
|
+
// alignItems="center"
|
751
|
+
justifyContent: "center",
|
752
|
+
gap: "5",
|
753
|
+
mb: "4"
|
754
|
+
}, enableRotation && ( /*#__PURE__*/React.createElement(Control, {
|
755
|
+
label: "Rota\xE7\xE3o: ".concat(_rotation, "\xB0")
|
756
|
+
}, /*#__PURE__*/React.createElement(Slider, {
|
757
|
+
style: {
|
758
|
+
width: 200
|
759
|
+
},
|
760
|
+
min: -359,
|
761
|
+
step: 1,
|
762
|
+
max: 359,
|
763
|
+
value: [_rotation],
|
764
|
+
onValueChange: function onValueChange(value) {
|
765
|
+
return _setRotation(value[0] % 360);
|
766
|
+
},
|
767
|
+
size: "1"
|
768
|
+
}))), enableZoom && ( /*#__PURE__*/React.createElement(Control, {
|
769
|
+
label: "Zoom: ".concat(_zoom.toFixed(2), "x")
|
770
|
+
}, /*#__PURE__*/React.createElement(Slider, {
|
771
|
+
style: {
|
772
|
+
width: 200
|
773
|
+
},
|
774
|
+
min: EFFECTIVE_MIN_ZOOM,
|
775
|
+
step: 0.01,
|
776
|
+
max: maxZoom,
|
777
|
+
value: [_zoom],
|
778
|
+
onValueChange: function onValueChange(value) {
|
779
|
+
return _setZoom(value[0]);
|
780
|
+
},
|
781
|
+
size: "1"
|
782
|
+
}))), enableFlip && ( /*#__PURE__*/React.createElement(Control, {
|
783
|
+
label: "Sentido:"
|
784
|
+
}, /*#__PURE__*/React.createElement(Flex, {
|
785
|
+
direction: "row",
|
786
|
+
gap: "3"
|
787
|
+
}, /*#__PURE__*/React.createElement(IconButton, {
|
788
|
+
size: "2",
|
789
|
+
type: "button",
|
790
|
+
variant: currentState.flipHorizontal ? 'outline' : 'soft',
|
791
|
+
onClick: function onClick() {
|
792
|
+
return promptUI.setValue(_assign(_assign({}, currentState), {
|
793
|
+
flipHorizontal: !currentState.flipHorizontal
|
794
|
+
}));
|
795
|
+
}
|
796
|
+
}, /*#__PURE__*/React.createElement(Icon, {
|
797
|
+
path: mdiFlipHorizontal,
|
798
|
+
size: 1
|
799
|
+
})), /*#__PURE__*/React.createElement(IconButton, {
|
800
|
+
size: "2",
|
801
|
+
type: "button",
|
802
|
+
variant: currentState.flipVertical ? 'outline' : 'soft',
|
803
|
+
onClick: function onClick() {
|
804
|
+
return promptUI.setValue(_assign(_assign({}, currentState), {
|
805
|
+
flipVertical: !currentState.flipVertical
|
806
|
+
}));
|
807
|
+
}
|
808
|
+
}, /*#__PURE__*/React.createElement(Icon, {
|
809
|
+
path: mdiFlipVertical,
|
810
|
+
size: 1
|
811
|
+
}))))))))), /*#__PURE__*/React.createElement(Flex, {
|
812
|
+
direction: "row",
|
813
|
+
justifyContent: "space-between"
|
814
|
+
}, /*#__PURE__*/React.createElement(IconButton, {
|
815
|
+
type: "button",
|
816
|
+
radius: "full",
|
817
|
+
onClick: function onClick() {
|
818
|
+
return setShowInstructions(!showInstructions);
|
819
|
+
},
|
820
|
+
onMouseEnter: function onMouseEnter() {
|
821
|
+
return setShowInstructions(true);
|
822
|
+
},
|
823
|
+
onMouseLeave: function onMouseLeave() {
|
824
|
+
return setShowInstructions(false);
|
825
|
+
},
|
826
|
+
variant: "ghost"
|
827
|
+
}, /*#__PURE__*/React.createElement(Icon, {
|
828
|
+
path: mdiHelpCircleOutline,
|
829
|
+
size: "16px"
|
830
|
+
})), /*#__PURE__*/React.createElement(Flex, {
|
831
|
+
direction: "row",
|
832
|
+
justifyContent: "flex-end"
|
833
|
+
}, !promptUI.isLoading && ( /*#__PURE__*/React.createElement(React.Fragment, null, _srcImageUrl && promptUI.hasUnsubmittedChanges && ( /*#__PURE__*/React.createElement(SupportButton, {
|
834
|
+
type: "button",
|
835
|
+
onClick: _resetChanges
|
836
|
+
}, "Redefinir")), /*#__PURE__*/React.createElement(Dialog.Close, _assign({}, promptUI.cancelProps), /*#__PURE__*/React.createElement(SupportButton, {
|
837
|
+
children: cancel
|
838
|
+
})))), /*#__PURE__*/React.createElement(Dialog.Close, null, /*#__PURE__*/React.createElement(Submit, _assign({}, promptUI.submitProps, {
|
839
|
+
loading: promptUI.isLoading
|
840
|
+
}), submit))))))));
|
841
|
+
}
|
842
|
+
var templateObject_1;
|
843
|
+
|
844
|
+
function onSubmitApplyCrop(_a) {
|
845
|
+
var onSuccess = _a.onSuccess,
|
846
|
+
onError = _a.onError,
|
847
|
+
options = __rest(_a, ["onSuccess", "onError"]);
|
848
|
+
return function (imageCropState) {
|
849
|
+
return __awaiter(this, void 0, void 0, function () {
|
850
|
+
var src, cropOptions, croppedImageBlob, err_1;
|
851
|
+
return __generator(this, function (_a) {
|
852
|
+
switch (_a.label) {
|
853
|
+
case 0:
|
854
|
+
src = imageCropState.src, cropOptions = __rest(imageCropState, ["src"]);
|
855
|
+
_a.label = 1;
|
856
|
+
case 1:
|
857
|
+
_a.trys.push([1, 3,, 4]);
|
858
|
+
return [4 /*yield*/, applyImageCrop(src, _assign(_assign({}, cropOptions), options))];
|
859
|
+
case 2:
|
860
|
+
croppedImageBlob = _a.sent();
|
861
|
+
if (!croppedImageBlob) {
|
862
|
+
throw new Error('Error generating cropped image');
|
863
|
+
}
|
864
|
+
return [3 /*break*/, 4];
|
865
|
+
case 3:
|
866
|
+
err_1 = _a.sent();
|
867
|
+
onError(err_1);
|
868
|
+
return [2 /*return*/];
|
869
|
+
case 4:
|
870
|
+
return [4 /*yield*/, onSuccess(new File([croppedImageBlob], inferImageName(src), {
|
871
|
+
type: croppedImageBlob.type
|
872
|
+
}))];
|
873
|
+
case 5:
|
874
|
+
_a.sent();
|
875
|
+
return [2 /*return*/];
|
876
|
+
}
|
877
|
+
});
|
878
|
+
});
|
879
|
+
};
|
880
|
+
}
|
881
|
+
|
882
|
+
var IMAGE_CROP_DIALOG_SPEC = [ImageCropDialog, {
|
883
|
+
getProps: function getProps(_a, propsOrImage) {
|
884
|
+
var resolve = _a.resolve,
|
885
|
+
reject = _a.reject;
|
886
|
+
if (propsOrImage === void 0) {
|
887
|
+
propsOrImage = {};
|
888
|
+
}
|
889
|
+
var isImage = propsOrImage instanceof File || propsOrImage instanceof Blob || typeof propsOrImage === 'string';
|
890
|
+
var baseProps = {
|
891
|
+
onCancel: function onCancel() {
|
892
|
+
return resolve(CANCELLED);
|
893
|
+
},
|
894
|
+
onSubmit: onSubmitApplyCrop(_assign({
|
895
|
+
onSuccess: resolve,
|
896
|
+
onError: reject
|
897
|
+
}, isImage ? {} : {
|
898
|
+
maxHeight: propsOrImage.maxHeight,
|
899
|
+
maxWidth: propsOrImage.maxWidth,
|
900
|
+
background: propsOrImage.background
|
901
|
+
}))
|
902
|
+
};
|
903
|
+
return isImage ? _assign({
|
904
|
+
src: propsOrImage
|
905
|
+
}, baseProps) : _assign(_assign({}, propsOrImage), baseProps);
|
906
|
+
}
|
907
|
+
}];
|
908
|
+
|
909
|
+
export { CheckeredBg, IMAGE_CROP_DIALOG_SPEC, ImageCropDialog, applyImageCrop, canvasToBlobPromise, compressImage, computeRotationSize, createImage, drawCanvas, getRadianAngle, inferImageName, onSubmitApplyCrop, toImageFile, toImageUrl };
|
package/dist/types.d.ts
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
import type { Area } from 'react-easy-crop';
|
2
|
+
export type FileRepresentation = {
|
3
|
+
url: string;
|
4
|
+
[key: string]: any;
|
5
|
+
};
|
6
|
+
export type ImageSpec = string | FileRepresentation | File | Blob;
|
7
|
+
export type ImageCropDialogProps = {
|
8
|
+
open?: boolean;
|
9
|
+
aspectRatio?: number;
|
10
|
+
rotation?: boolean;
|
11
|
+
zoom?: boolean;
|
12
|
+
minZoom?: number;
|
13
|
+
maxZoom?: number;
|
14
|
+
flip?: boolean;
|
15
|
+
background?: string;
|
16
|
+
src?: ImageSpec;
|
17
|
+
submit?: any;
|
18
|
+
onSubmit: (result: ImageCropState) => any;
|
19
|
+
cancel?: any;
|
20
|
+
onCancel?: () => any;
|
21
|
+
};
|
22
|
+
export type ImageCropState = {
|
23
|
+
src: ImageSpec;
|
24
|
+
area: Area;
|
25
|
+
areaPercentage: Area;
|
26
|
+
rotation: number;
|
27
|
+
zoom: number;
|
28
|
+
flipHorizontal: boolean;
|
29
|
+
flipVertical: boolean;
|
30
|
+
background: string;
|
31
|
+
};
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import { ImageCropState } from '../types';
|
2
|
+
import { Area } from 'react-easy-crop';
|
3
|
+
export declare function getRadianAngle(degreeValue: number): number;
|
4
|
+
/**
|
5
|
+
* Returns the new bounding area of a rotated rectangle.
|
6
|
+
*/
|
7
|
+
export declare function computeRotationSize(width: number, height: number, rotation: number): {
|
8
|
+
width: number;
|
9
|
+
height: number;
|
10
|
+
};
|
11
|
+
export type ApplyImageCropOptions = {
|
12
|
+
area: Area;
|
13
|
+
rotation?: number;
|
14
|
+
flipHorizontal?: boolean;
|
15
|
+
flipVertical?: boolean;
|
16
|
+
background?: string;
|
17
|
+
mimeType?: 'image/png' | 'image/jpeg' | 'image/webp';
|
18
|
+
maxWidth?: number;
|
19
|
+
maxHeight?: number;
|
20
|
+
};
|
21
|
+
/**
|
22
|
+
* This function was adapted from the one in the ReadMe of https://github.com/DominicTobias/react-image-crop
|
23
|
+
*/
|
24
|
+
export declare function applyImageCrop(src: ImageCropState['src'], { area, flipHorizontal, flipVertical, rotation, background, mimeType, maxWidth, maxHeight, }: ApplyImageCropOptions): Promise<Blob>;
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import { SrcImage } from '../types';
|
2
|
+
export declare function toImageUrl(src: SrcImage): string;
|
3
|
+
export declare function toImageFile(src: SrcImage): Promise<File>;
|
4
|
+
export declare function inferImageName(src: SrcImage): string;
|
5
|
+
export declare function canvasToBlobPromise(canvas: HTMLCanvasElement, mimeType?: string): Promise<Blob>;
|
6
|
+
export declare const createImage: (src: SrcImage) => Promise<HTMLImageElement>;
|
7
|
+
export declare function drawCanvas({ width, height, background, }: {
|
8
|
+
width: number;
|
9
|
+
height: number;
|
10
|
+
background: string;
|
11
|
+
}): {
|
12
|
+
canvas: HTMLCanvasElement;
|
13
|
+
ctx: CanvasRenderingContext2D;
|
14
|
+
};
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { ImageCropState } from '../types';
|
2
|
+
import { Merge } from 'type-fest';
|
3
|
+
export declare function getRadianAngle(degreeValue: number): number;
|
4
|
+
type ImageSize = {
|
5
|
+
width: number;
|
6
|
+
height: number;
|
7
|
+
};
|
8
|
+
/**
|
9
|
+
* Returns the new bounding area of a rotated rectangle.
|
10
|
+
*/
|
11
|
+
export declare function computeRotatedImageSize(size: ImageSize, rotation: number): ImageSize;
|
12
|
+
/**
|
13
|
+
* This function was adapted from the one in the ReadMe of https://github.com/DominicTobias/react-image-crop
|
14
|
+
*/
|
15
|
+
export declare function applyImageCrop(src: ImageCropState['src'], { area, rotation, zoom, flip, background, mimeType, }: Merge<Pick<ImageCropState, 'area' | 'rotation' | 'flip'>, {
|
16
|
+
background?: 'transparent' | string;
|
17
|
+
zoom?: number;
|
18
|
+
mimeType?: 'image/png' | 'image/jpeg' | 'image/webp';
|
19
|
+
}>): Promise<Blob>;
|
20
|
+
export {};
|
package/package.json
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
{
|
2
|
+
"name": "@orioro/react-image-crop",
|
3
|
+
"version": "0.0.1",
|
4
|
+
"packageManager": "yarn@4.0.2",
|
5
|
+
"type": "module",
|
6
|
+
"main": "dist/index.mjs",
|
7
|
+
"types": "dist/index.d.ts",
|
8
|
+
"exports": {
|
9
|
+
".": "./dist/index.mjs",
|
10
|
+
"./*": "./dist/*"
|
11
|
+
},
|
12
|
+
"files": [
|
13
|
+
"dist"
|
14
|
+
],
|
15
|
+
"publishConfig": {
|
16
|
+
"access": "public"
|
17
|
+
},
|
18
|
+
"license": "ISC",
|
19
|
+
"scripts": {
|
20
|
+
"build": "rm -rf dist && rollup --config ./rollup.config.mjs",
|
21
|
+
"storybook": "storybook dev -p 6006",
|
22
|
+
"build-storybook": "storybook build"
|
23
|
+
},
|
24
|
+
"devDependencies": {
|
25
|
+
"@orioro/dev": "workspace:^",
|
26
|
+
"@types/canvas-size": "^1.2.2",
|
27
|
+
"rollup": "^4.13.0",
|
28
|
+
"storybook": "^8.0.0"
|
29
|
+
},
|
30
|
+
"dependencies": {
|
31
|
+
"@mdi/js": "^7.4.47",
|
32
|
+
"@mdi/react": "^1.6.1",
|
33
|
+
"@orioro/react-ui-core": "workspace:^",
|
34
|
+
"@radix-ui/themes": "^3.0.1",
|
35
|
+
"canvas-size": "^2.0.0",
|
36
|
+
"compressorjs": "^1.2.1",
|
37
|
+
"react": "^18.2.0",
|
38
|
+
"react-easy-crop": "^5.1.0",
|
39
|
+
"react-use": "^17.5.1",
|
40
|
+
"styled-components": "^6.1.8",
|
41
|
+
"type-fest": "^4.26.1"
|
42
|
+
}
|
43
|
+
}
|