@oneblink/apps-react 8.12.0-beta.5 → 8.12.0-beta.6
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/dist/components/ImageCropper/index.js +33 -4
- package/dist/components/ImageCropper/index.js.map +1 -1
- package/dist/components/ImageCropper/resource-components.js +1 -0
- package/dist/components/ImageCropper/resource-components.js.map +1 -1
- package/dist/styles/camera.scss +4 -2
- package/dist/styles.css +2 -1
- package/package.json +1 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import React, { memo } from 'react';
|
|
1
|
+
import React, { memo, useEffect } from 'react';
|
|
2
2
|
import ReactImageCrop from 'react-image-crop';
|
|
3
3
|
import { CropContainer } from './resource-components';
|
|
4
4
|
import 'react-image-crop/src/ReactCrop.scss';
|
|
5
|
+
import clsx from 'clsx';
|
|
5
6
|
const defaultCrop = {
|
|
6
7
|
unit: '%',
|
|
7
8
|
height: 100,
|
|
@@ -40,6 +41,9 @@ const getDefaultCropFromAspectRatio = ({ outputAspectRatio, imageWidth, imageHei
|
|
|
40
41
|
};
|
|
41
42
|
};
|
|
42
43
|
const ImageCropper = ({ imgSrc, disabled, onCropComplete, outputAspectRatio, cropperHeight, }) => {
|
|
44
|
+
const cropperWrapperRef = React.useRef(null);
|
|
45
|
+
const imageRef = React.useRef(null);
|
|
46
|
+
const [fullHeight, setFullHeight] = React.useState(false);
|
|
43
47
|
const [crop, setCrop] = React.useState(() => outputAspectRatio ? undefined : defaultCrop);
|
|
44
48
|
const handleSetCrop = React.useCallback((_, c) => {
|
|
45
49
|
setCrop(c);
|
|
@@ -56,10 +60,35 @@ const ImageCropper = ({ imgSrc, disabled, onCropComplete, outputAspectRatio, cro
|
|
|
56
60
|
imageHeight: currentTarget.height,
|
|
57
61
|
}));
|
|
58
62
|
}, [outputAspectRatio]);
|
|
63
|
+
// Resize magic to account for images that are larger than the dialog can hold
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (imageRef.current && cropperWrapperRef.current) {
|
|
66
|
+
const resizeObserver = new ResizeObserver((entries) => {
|
|
67
|
+
for (const entry of entries) {
|
|
68
|
+
if (!cropperWrapperRef.current)
|
|
69
|
+
continue;
|
|
70
|
+
const imageElHeight = entry.contentRect.height;
|
|
71
|
+
const cropperWrapperHeight = cropperWrapperRef.current.clientHeight;
|
|
72
|
+
if (imageElHeight < cropperWrapperHeight) {
|
|
73
|
+
setFullHeight(false);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
setFullHeight(true);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
resizeObserver.observe(imageRef.current);
|
|
81
|
+
return () => {
|
|
82
|
+
resizeObserver.disconnect();
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}, [imageRef]);
|
|
59
86
|
return (React.createElement("div", { className: "ob-cropper__container" },
|
|
60
|
-
React.createElement(CropContainer, { className: "ob-cropper__cropper-wrapper", height: cropperHeight },
|
|
61
|
-
React.createElement(ReactImageCrop, { crop: crop, aspect: outputAspectRatio, onChange: handleSetCrop, onComplete: handleCropComplete, disabled: disabled, className:
|
|
62
|
-
|
|
87
|
+
React.createElement(CropContainer, { className: "ob-cropper__cropper-wrapper", height: cropperHeight, ref: cropperWrapperRef },
|
|
88
|
+
React.createElement(ReactImageCrop, { crop: crop, aspect: outputAspectRatio, onChange: handleSetCrop, onComplete: handleCropComplete, disabled: disabled, className: clsx('ob-cropper__cropper', {
|
|
89
|
+
'ob-cropper__cropper-full-height': fullHeight,
|
|
90
|
+
}), ruleOfThirds: true, keepSelection: true },
|
|
91
|
+
React.createElement("img", { src: imgSrc, className: "ob-cropper__image", onLoad: handleLoadImage, ref: imageRef })))));
|
|
63
92
|
};
|
|
64
93
|
export default memo(ImageCropper);
|
|
65
94
|
export const getAspectRatio = ({ width, height, }) => width / height;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/ImageCropper/index.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { memo } from 'react'\nimport ReactImageCrop, { Crop, PercentCrop } from 'react-image-crop'\nimport { CropContainer } from './resource-components'\nimport 'react-image-crop/src/ReactCrop.scss'\nexport { PercentCrop }\nconst defaultCrop: PercentCrop = {\n unit: '%',\n height: 100,\n width: 100,\n x: 0,\n y: 0,\n}\n\nconst getDefaultCropFromAspectRatio = ({\n outputAspectRatio,\n imageWidth,\n imageHeight,\n}: {\n outputAspectRatio: number\n imageWidth: number\n imageHeight: number\n}): PercentCrop => {\n const imageAspect = imageWidth / imageHeight\n\n // Compute the largest rectangle that fits within the image and matches the aspect ratio\n let width: number\n let height: number\n if (imageAspect >= outputAspectRatio) {\n // Image is wider than desired aspect: constrain width by the height\n height = 100\n const widthInPixels = imageHeight * outputAspectRatio\n // as percent\n width = (widthInPixels / imageWidth) * 100\n } else {\n // Image is taller/narrower than desired aspect: constrain height by the width\n width = 100\n const heightInPixels = imageHeight * outputAspectRatio\n // as percent\n height = (heightInPixels / imageHeight) * 100\n }\n\n // Center the crop\n const x = Math.round((100 - width) / 2)\n const y = Math.round((100 - height) / 2)\n\n return {\n unit: '%',\n width,\n height,\n x,\n y,\n }\n}\n\nconst ImageCropper = ({\n imgSrc,\n disabled,\n onCropComplete,\n outputAspectRatio,\n cropperHeight,\n}: {\n imgSrc: string\n disabled?: boolean\n onCropComplete: (croppedAreaPixels: PercentCrop) => void\n outputAspectRatio?: number\n cropperHeight?: number\n}) => {\n const [crop, setCrop] = React.useState<Crop | undefined>(() =>\n outputAspectRatio ? undefined : defaultCrop,\n )\n\n const handleSetCrop = React.useCallback((_, c: PercentCrop) => {\n setCrop(c)\n }, [])\n\n const handleCropComplete = React.useCallback(\n (_, c: PercentCrop) => {\n onCropComplete(c)\n },\n [onCropComplete],\n )\n\n const handleLoadImage = React.useCallback(\n ({ currentTarget }: React.SyntheticEvent<HTMLImageElement, Event>) => {\n if (!outputAspectRatio) return\n setCrop(\n getDefaultCropFromAspectRatio({\n outputAspectRatio,\n imageWidth: currentTarget.width,\n imageHeight: currentTarget.height,\n }),\n )\n },\n [outputAspectRatio],\n )\n\n return (\n <div className=\"ob-cropper__container\">\n <CropContainer\n className=\"ob-cropper__cropper-wrapper\"\n height={cropperHeight}\n >\n <ReactImageCrop\n crop={crop}\n aspect={outputAspectRatio}\n onChange={handleSetCrop}\n onComplete={handleCropComplete}\n disabled={disabled}\n className=\"ob-cropper__cropper\"\n ruleOfThirds\n keepSelection\n >\n <img\n src={imgSrc}\n className=\"ob-cropper__image\"\n onLoad={handleLoadImage}\n />\n </ReactImageCrop>\n </CropContainer>\n </div>\n )\n}\n\nexport default memo(ImageCropper)\n\nexport const getAspectRatio = ({\n width,\n height,\n}: {\n width: number\n height: number\n}) => width / height\n\nconst createImage = (url: string): Promise<HTMLImageElement> => {\n return new Promise((resolve, reject) => {\n const image = new Image()\n image.onload = () => {\n resolve(image)\n }\n image.onerror = (error) => {\n reject(error)\n }\n image.src = url\n return image\n })\n}\n\nexport const generateCroppedImageBlob = async ({\n croppedAreaPercent,\n imgSrc,\n size,\n fileType,\n}: {\n croppedAreaPercent: PercentCrop\n imgSrc: string\n /**\n * If provided, the cropped image will be resized to the given size. If not\n * provided, the cropped image will be the same size as the cropped portion of\n * the source image.\n */\n size?: {\n width: number\n height: number\n }\n fileType?: string\n}): Promise<Blob | null> => {\n if (!croppedAreaPercent || !imgSrc) {\n return null\n }\n // Source image/canvas\n const image = await createImage(imgSrc)\n const canvas = document.createElement('canvas')\n const ctx = canvas.getContext('2d')\n if (!ctx) {\n return null\n }\n canvas.width = image.width\n canvas.height = image.height\n ctx.drawImage(image, 0, 0)\n\n // Destination image/canvas\n const croppedCanvas = document.createElement('canvas')\n const croppedCtx = croppedCanvas.getContext('2d')\n if (!croppedCtx) {\n return null\n }\n\n const widthPercentAsPixels = () =>\n (image.width / 100) * croppedAreaPercent.width\n const heightPercentAsPixels = () =>\n (image.height / 100) * croppedAreaPercent.height\n\n const sourceXPercentAsPixels = () =>\n (image.width / 100) * croppedAreaPercent.x\n const sourceYPercentAsPixels = () =>\n (image.height / 100) * croppedAreaPercent.y\n\n croppedCanvas.width = size?.width ?? widthPercentAsPixels()\n croppedCanvas.height = size?.height ?? heightPercentAsPixels()\n\n // Draw the cropped source image onto the destination canvas\n croppedCtx.drawImage(\n canvas,\n // source x\n sourceXPercentAsPixels(),\n // source y\n sourceYPercentAsPixels(),\n // source width\n widthPercentAsPixels(),\n // source height\n heightPercentAsPixels(),\n // destination x\n 0,\n // destination y\n 0,\n // destination width\n croppedCanvas.width,\n // destination height\n croppedCanvas.height,\n )\n\n return new Promise((resolve) => {\n croppedCanvas.toBlob((file) => {\n resolve(file)\n }, fileType)\n })\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/ImageCropper/index.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { memo, useEffect } from 'react'\nimport ReactImageCrop, { Crop, PercentCrop } from 'react-image-crop'\nimport { CropContainer } from './resource-components'\nimport 'react-image-crop/src/ReactCrop.scss'\nimport clsx from 'clsx'\nexport { PercentCrop }\nconst defaultCrop: PercentCrop = {\n unit: '%',\n height: 100,\n width: 100,\n x: 0,\n y: 0,\n}\n\nconst getDefaultCropFromAspectRatio = ({\n outputAspectRatio,\n imageWidth,\n imageHeight,\n}: {\n outputAspectRatio: number\n imageWidth: number\n imageHeight: number\n}): PercentCrop => {\n const imageAspect = imageWidth / imageHeight\n\n // Compute the largest rectangle that fits within the image and matches the aspect ratio\n let width: number\n let height: number\n if (imageAspect >= outputAspectRatio) {\n // Image is wider than desired aspect: constrain width by the height\n height = 100\n const widthInPixels = imageHeight * outputAspectRatio\n // as percent\n width = (widthInPixels / imageWidth) * 100\n } else {\n // Image is taller/narrower than desired aspect: constrain height by the width\n width = 100\n const heightInPixels = imageHeight * outputAspectRatio\n // as percent\n height = (heightInPixels / imageHeight) * 100\n }\n\n // Center the crop\n const x = Math.round((100 - width) / 2)\n const y = Math.round((100 - height) / 2)\n\n return {\n unit: '%',\n width,\n height,\n x,\n y,\n }\n}\n\nconst ImageCropper = ({\n imgSrc,\n disabled,\n onCropComplete,\n outputAspectRatio,\n cropperHeight,\n}: {\n imgSrc: string\n disabled?: boolean\n onCropComplete: (croppedAreaPixels: PercentCrop) => void\n outputAspectRatio?: number\n cropperHeight?: number\n}) => {\n const cropperWrapperRef = React.useRef<HTMLDivElement>(null)\n const imageRef = React.useRef<HTMLImageElement>(null)\n\n const [fullHeight, setFullHeight] = React.useState(false)\n\n const [crop, setCrop] = React.useState<Crop | undefined>(() =>\n outputAspectRatio ? undefined : defaultCrop,\n )\n\n const handleSetCrop = React.useCallback((_, c: PercentCrop) => {\n setCrop(c)\n }, [])\n\n const handleCropComplete = React.useCallback(\n (_, c: PercentCrop) => {\n onCropComplete(c)\n },\n [onCropComplete],\n )\n\n const handleLoadImage = React.useCallback(\n ({ currentTarget }: React.SyntheticEvent<HTMLImageElement, Event>) => {\n if (!outputAspectRatio) return\n setCrop(\n getDefaultCropFromAspectRatio({\n outputAspectRatio,\n imageWidth: currentTarget.width,\n imageHeight: currentTarget.height,\n }),\n )\n },\n [outputAspectRatio],\n )\n\n // Resize magic to account for images that are larger than the dialog can hold\n useEffect(() => {\n if (imageRef.current && cropperWrapperRef.current) {\n const resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n if (!cropperWrapperRef.current) continue\n\n const imageElHeight = entry.contentRect.height\n const cropperWrapperHeight = cropperWrapperRef.current.clientHeight\n\n if (imageElHeight < cropperWrapperHeight) {\n setFullHeight(false)\n } else {\n setFullHeight(true)\n }\n }\n })\n resizeObserver.observe(imageRef.current)\n\n return () => {\n resizeObserver.disconnect()\n }\n }\n }, [imageRef])\n\n return (\n <div className=\"ob-cropper__container\">\n <CropContainer\n className=\"ob-cropper__cropper-wrapper\"\n height={cropperHeight}\n ref={cropperWrapperRef}\n >\n <ReactImageCrop\n crop={crop}\n aspect={outputAspectRatio}\n onChange={handleSetCrop}\n onComplete={handleCropComplete}\n disabled={disabled}\n className={clsx('ob-cropper__cropper', {\n 'ob-cropper__cropper-full-height': fullHeight,\n })}\n ruleOfThirds\n keepSelection\n >\n <img\n src={imgSrc}\n className=\"ob-cropper__image\"\n onLoad={handleLoadImage}\n ref={imageRef}\n />\n </ReactImageCrop>\n </CropContainer>\n </div>\n )\n}\n\nexport default memo(ImageCropper)\n\nexport const getAspectRatio = ({\n width,\n height,\n}: {\n width: number\n height: number\n}) => width / height\n\nconst createImage = (url: string): Promise<HTMLImageElement> => {\n return new Promise((resolve, reject) => {\n const image = new Image()\n image.onload = () => {\n resolve(image)\n }\n image.onerror = (error) => {\n reject(error)\n }\n image.src = url\n return image\n })\n}\n\nexport const generateCroppedImageBlob = async ({\n croppedAreaPercent,\n imgSrc,\n size,\n fileType,\n}: {\n croppedAreaPercent: PercentCrop\n imgSrc: string\n /**\n * If provided, the cropped image will be resized to the given size. If not\n * provided, the cropped image will be the same size as the cropped portion of\n * the source image.\n */\n size?: {\n width: number\n height: number\n }\n fileType?: string\n}): Promise<Blob | null> => {\n if (!croppedAreaPercent || !imgSrc) {\n return null\n }\n // Source image/canvas\n const image = await createImage(imgSrc)\n const canvas = document.createElement('canvas')\n const ctx = canvas.getContext('2d')\n if (!ctx) {\n return null\n }\n canvas.width = image.width\n canvas.height = image.height\n ctx.drawImage(image, 0, 0)\n\n // Destination image/canvas\n const croppedCanvas = document.createElement('canvas')\n const croppedCtx = croppedCanvas.getContext('2d')\n if (!croppedCtx) {\n return null\n }\n\n const widthPercentAsPixels = () =>\n (image.width / 100) * croppedAreaPercent.width\n const heightPercentAsPixels = () =>\n (image.height / 100) * croppedAreaPercent.height\n\n const sourceXPercentAsPixels = () =>\n (image.width / 100) * croppedAreaPercent.x\n const sourceYPercentAsPixels = () =>\n (image.height / 100) * croppedAreaPercent.y\n\n croppedCanvas.width = size?.width ?? widthPercentAsPixels()\n croppedCanvas.height = size?.height ?? heightPercentAsPixels()\n\n // Draw the cropped source image onto the destination canvas\n croppedCtx.drawImage(\n canvas,\n // source x\n sourceXPercentAsPixels(),\n // source y\n sourceYPercentAsPixels(),\n // source width\n widthPercentAsPixels(),\n // source height\n heightPercentAsPixels(),\n // destination x\n 0,\n // destination y\n 0,\n // destination width\n croppedCanvas.width,\n // destination height\n croppedCanvas.height,\n )\n\n return new Promise((resolve) => {\n croppedCanvas.toBlob((file) => {\n resolve(file)\n }, fileType)\n })\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource-components.js","sourceRoot":"","sources":["../../../src/components/ImageCropper/resource-components.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAEtC,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,EAAE;IACzC,iBAAiB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,QAAQ;CAC/C,CAAC,CAAsB,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;IAC9C,QAAQ,EAAE,UAAU;IACpB,KAAK,EAAE,MAAM;IACb,OAAO,EAAE,MAAM;IACf,cAAc,EAAE,iBAAiB;IACjC,UAAU,EAAE,QAAQ;IACpB,cAAc,EAAE,QAAQ;IACxB,YAAY,EAAE,KAAK,CAAC,KAAK,CAAC,YAAY;IACtC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;CACvC,CAAC,CAAC,CAAA","sourcesContent":["import { styled } from '@mui/material'\n\nexport const CropContainer = styled('div', {\n shouldForwardProp: (prop) => prop !== 'height',\n})<{ height?: number }>(({ height, theme }) => ({\n position: 'relative',\n width: '100%',\n display: 'flex',\n backdropFilter: 'brightness(0.5)',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: theme.shape.borderRadius,\n ...(height ? { height } : { flex: 1 }),\n}))\n"]}
|
|
1
|
+
{"version":3,"file":"resource-components.js","sourceRoot":"","sources":["../../../src/components/ImageCropper/resource-components.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAEtC,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,EAAE;IACzC,iBAAiB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,QAAQ;CAC/C,CAAC,CAAsB,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;IAC9C,QAAQ,EAAE,UAAU;IACpB,KAAK,EAAE,MAAM;IACb,OAAO,EAAE,MAAM;IACf,cAAc,EAAE,iBAAiB;IACjC,UAAU,EAAE,QAAQ;IACpB,cAAc,EAAE,QAAQ;IACxB,YAAY,EAAE,KAAK,CAAC,KAAK,CAAC,YAAY;IACtC,SAAS,EAAE,MAAM;IACjB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;CACvC,CAAC,CAAC,CAAA","sourcesContent":["import { styled } from '@mui/material'\n\nexport const CropContainer = styled('div', {\n shouldForwardProp: (prop) => prop !== 'height',\n})<{ height?: number }>(({ height, theme }) => ({\n position: 'relative',\n width: '100%',\n display: 'flex',\n backdropFilter: 'brightness(0.5)',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: theme.shape.borderRadius,\n maxHeight: '100%',\n ...(height ? { height } : { flex: 1 }),\n}))\n"]}
|
package/dist/styles/camera.scss
CHANGED
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
justify-content: center;
|
|
42
42
|
background: $white;
|
|
43
43
|
padding: $size-4;
|
|
44
|
+
min-height: 0%;
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
.ob-annotation__content {
|
|
@@ -113,9 +114,10 @@
|
|
|
113
114
|
display: flex;
|
|
114
115
|
flex-direction: column;
|
|
115
116
|
|
|
116
|
-
.ob-cropper__cropper {
|
|
117
|
+
.ob-cropper__cropper-full-height {
|
|
117
118
|
height: 100%;
|
|
118
|
-
|
|
119
|
+
}
|
|
120
|
+
.ob-cropper__cropper {
|
|
119
121
|
.ReactCrop__child-wrapper {
|
|
120
122
|
height: 100%;
|
|
121
123
|
|
package/dist/styles.css
CHANGED
|
@@ -8148,6 +8148,7 @@ button on-loading {
|
|
|
8148
8148
|
justify-content: center;
|
|
8149
8149
|
background: hsl(0, 0%, 100%);
|
|
8150
8150
|
padding: 1.5rem;
|
|
8151
|
+
min-height: 0%;
|
|
8151
8152
|
}
|
|
8152
8153
|
|
|
8153
8154
|
.ob-annotation__content {
|
|
@@ -8208,7 +8209,7 @@ button on-loading {
|
|
|
8208
8209
|
display: flex;
|
|
8209
8210
|
flex-direction: column;
|
|
8210
8211
|
}
|
|
8211
|
-
.ob-cropper__container .ob-cropper__cropper {
|
|
8212
|
+
.ob-cropper__container .ob-cropper__cropper-full-height {
|
|
8212
8213
|
height: 100%;
|
|
8213
8214
|
}
|
|
8214
8215
|
.ob-cropper__container .ob-cropper__cropper .ReactCrop__child-wrapper {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oneblink/apps-react",
|
|
3
3
|
"description": "Helper functions for OneBlink apps in ReactJS.",
|
|
4
|
-
"version": "8.12.0-beta.
|
|
4
|
+
"version": "8.12.0-beta.6",
|
|
5
5
|
"author": "OneBlink <developers@oneblink.io> (https://oneblink.io)",
|
|
6
6
|
"bugs": {
|
|
7
7
|
"url": "https://github.com/oneblink/apps-react/issues"
|