@oneblink/apps-react 8.12.0-beta.5 → 8.12.0-beta.7

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.
@@ -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,
@@ -24,7 +25,7 @@ const getDefaultCropFromAspectRatio = ({ outputAspectRatio, imageWidth, imageHei
24
25
  else {
25
26
  // Image is taller/narrower than desired aspect: constrain height by the width
26
27
  width = 100;
27
- const heightInPixels = imageHeight * outputAspectRatio;
28
+ const heightInPixels = imageWidth * outputAspectRatio;
28
29
  // as percent
29
30
  height = (heightInPixels / imageHeight) * 100;
30
31
  }
@@ -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 (Math.ceil(imageElHeight) < Math.ceil(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: "ob-cropper__cropper", ruleOfThirds: true, keepSelection: true },
62
- React.createElement("img", { src: imgSrc, className: "ob-cropper__image", onLoad: handleLoadImage })))));
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 = imageWidth * 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 (Math.ceil(imageElHeight) < Math.ceil(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"]}
@@ -9,6 +9,7 @@ export const CropContainer = styled('div', {
9
9
  alignItems: 'center',
10
10
  justifyContent: 'center',
11
11
  borderRadius: theme.shape.borderRadius,
12
+ maxHeight: '100%',
12
13
  ...(height ? { height } : { flex: 1 }),
13
14
  }));
14
15
  //# sourceMappingURL=resource-components.js.map
@@ -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"]}
@@ -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.5",
4
+ "version": "8.12.0-beta.7",
5
5
  "author": "OneBlink <developers@oneblink.io> (https://oneblink.io)",
6
6
  "bugs": {
7
7
  "url": "https://github.com/oneblink/apps-react/issues"