diff --git a/.gitignore b/.gitignore index f33fe7f..a123a73 100644 --- a/.gitignore +++ b/.gitignore @@ -22,5 +22,7 @@ npm-debug.log* yarn-debug.log* yarn-error.log* +stats.html + # documentation is not ready docs diff --git a/cropper b/cropper deleted file mode 100644 index d7408f9..0000000 --- a/cropper +++ /dev/null @@ -1,264 +0,0 @@ -const { - refresh, - reset, -} = useCropper({ - -}, { - -}) - -const cropper = Cropper({ - onChange() { - - } - onUpdate() { - - }, - aspectRatio() { - - }, - image() { - - }, - area() { - - }, - stretcher() { - - }, - canvas() { - - }, - sourceCanvas() { - - } -); - -const { settings, props, coefficient, image, boundaries, visibleArea, coordinates } = cropper.render(); - -const { - src, - size, - loaded, - crossOrigin, - transforms -} = image; - -const { - width, - height, -} = boundaries; - -const { - left, - top, - width, - height -} = visibleArea; - - -const cropper = new Cropper({ - aspectRatio() { - return { - minimum: 1, - maximum: 1, - } - }, - boundaries() { - return { - width: 100, - height: 100, - } - }, - onChange() { - - } -}) - - - -window.addEventListener('resize', updateBoundaries); - -function updateBoundaries() { - initStretcher(stretcher); - cropper.setBoundaries({ - width: boundaries.clientWidth, - height: boundaries.clientHeight - }); -} - -const image = new ImageCropper(this.$refs.image, { - onLoad() -}) - -image.set('').then(() => { - cropper.set( -}); - -cropper.onChangeImage({ - width: 100, - height: 100 -}) - -cropper.changeBoundaries({ - width: boundaries.clientWidth, - height: boundaries.clientHeight -}); - -cropper.move(); - -cropper.resize(); - -cropper.manipulateImage(); - - - - - -onChangeImage() { - this.imageLoaded = false; - this.delayedTransforms = null; - this.imageAttributes.src = null; - - if (this.src) { - const promise = parseImage(this.src); - if (isCrossOriginURL(this.src) && this.canvas) { - this.imageAttributes.crossOrigin = this.crossOrigin; - } - setTimeout(() => { - promise.then(this.onParseImage); - }, this.transitionTime); - } else { - this.clearImage(); - } -} - -onParseImage({ source, arrayBuffer, orientation }) { - if (arrayBuffer && orientation && isLocal(source)) { - this.imageAttributes.src = arrayBufferToDataURL(arrayBuffer); - } else { - this.imageAttributes.src = source; - } - this.basicImageTransforms = getImageTransforms(orientation); - this.$nextTick(() => { - const image = this.$refs.image; - if (image && image.complete) { - if (isLoadedImage(image)) { - this.onSuccessLoadImage(); - } else { - this.onFailLoadImage(); - } - } - }); -} - -onFailLoadImage() { - this.clearImage(); - this.$emit('error'); -} - -onSuccessLoadImage() { - // After loading image the current component can be unmounted - // Therefore there is a workaround to prevent processing the following code - const image = this.$refs.image; - if (image && !this.imageLoaded) { - if (this.imageTransforms.flipped) { - this.imageSize.height = image.naturalWidth; - this.imageSize.width = image.naturalHeight; - } else { - this.imageSize.height = image.naturalHeight; - this.imageSize.width = image.naturalWidth; - } - this.imageLoaded = true; - this.reset().then(() => { - this.$emit('ready'); - }); - } -} - -const cropper = new Cropper({ - onChange() { - canvas.draw() - } -}); - -const canvas = new CropperCanvas(canvas, sourceCanvas); - -const image = new CropperImage(image, { - onChange({ size }) { - cropper.setImage(size); - }, - onClear() { - cropper.setImage(null); - }, - checkOrientation: false, - src: '111', -}); - - -image.onLoad - - - - - - - -changeImage(src) { - image.src = src - image.loaded = false; - image.parsed = checkOrientation ? false : true; - image.transforms = {}; - image.size = null; -} - -onLoadImage() { - -} - -onFailLoadImage() { - -} - - - - - - - - - - - - -Циклы: - - - - - - - - - - - - - - - - - - - - - - - -cropper.onMove(); - -cropper.onResize(); - -cropper.onManipulateImage(); - -cropper.onChange('src', src); \ No newline at end of file diff --git a/package.json b/package.json index ddeeb84..6bfc6ad 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,15 @@ { "name": "react-mobile-cropper", - "version": "0.4.1", + "version": "0.5.0", "description": "The react mobile cropper inspired by Android mobile croppers", "author": "Norserium", "license": "MIT", "repository": "Norserium/react-mobile-cropper", - "main": "dist/index.cjs.js", - "unpkg": "dist/index.global.js", - "jsdelivr": "dist/index.global.js", - "module": "dist/index.esm-bundler.js", + "main": "dist/index.cjs.js", + "browser": "dist/index.global.js", + "unpkg": "dist/index.global.js", + "jsdelivr": "dist/index.global.js", + "module": "dist/index.esm-bundler.js", "types": "dist/index.d.ts", "keywords": [ "react", @@ -74,6 +75,8 @@ "rollup-plugin-postcss": "4.0.1", "rollup-plugin-scss": "^2.6.1", "rollup-plugin-terser": "^7.0.2", + "rollup-plugin-visualizer": "^5.6.0", + "sass": "^1.53.0", "typescript": "^4.0.5" }, "files": [ @@ -81,7 +84,7 @@ ], "dependencies": { "classnames": "^2.2.6", - "react-advanced-cropper": "^0.4.1", + "react-advanced-cropper": "^0.7.3", "tslib": "^2.0.3" } } diff --git a/rollup.config.js b/rollup.config.js index f846969..08dd6cf 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -2,7 +2,7 @@ import path from 'path'; import commonjs from '@rollup/plugin-commonjs'; import resolve from '@rollup/plugin-node-resolve'; import typescript from '@rollup/plugin-typescript'; -import replace from '@rollup/plugin-replace'; +import { visualizer } from 'rollup-plugin-visualizer'; import url from '@rollup/plugin-url'; import external from 'rollup-plugin-peer-deps-external'; import postcss from 'rollup-plugin-postcss'; @@ -11,35 +11,23 @@ import { terser } from 'rollup-plugin-terser'; import scss from 'rollup-plugin-scss'; import pkg from './package.json'; -const output = [ - { - file: pkg.module, - format: `es`, - }, - { - file: pkg.main, - format: `cjs`, - }, - { - file: pkg.unpkg, - format: `iife`, - }, - { - file: pkg.browser || pkg.module.replace('bundler', 'browser'), - format: `es`, - }, -]; +const files = { + es: pkg.main, + cjs: pkg.module, + iife: pkg.browser, +}; -export default { +export default ['es', 'cjs', 'iife'].map((format) => ({ input: 'src/index.ts', - output: output.map((config) => ({ - ...config, - name: config.format === 'iife' ? 'ReactMobileCropper' : undefined, + output: { + file: files[format], + format, + name: format === 'iife' ? 'ReactMobileCropper' : undefined, globals: { react: 'React', }, - sourcemap: process.env.NODE_ENV !== 'production', - })), + sourcemap: true, + }, plugins: [ external(), scss({ @@ -53,9 +41,8 @@ export default { resolve(), commonjs(), typescript({ tsconfig: './tsconfig.json' }), - terser(), - replace({ - 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), + visualizer({ + gzipSize: true, }), ], -}; +})); diff --git a/src/algorithms/index.ts b/src/algorithms/index.ts deleted file mode 100644 index 1dd7344..0000000 --- a/src/algorithms/index.ts +++ /dev/null @@ -1,194 +0,0 @@ -import { - CropperSettings, - CropperState, - ImageTransform, - PostprocessAction, - ResizeDirections, - ResizeOptions, - Size, - applyMove, - applyScale, - coordinatesToPositionRestrictions, - copyState, - diff, - getAspectRatio, - getCenter, - getMinimumSize, - getPositionRestrictions, - getSizeRestrictions, - mergePositionRestrictions, - ratio, - resizeCoordinatesAlgorithm, - transformImage, -} from 'react-advanced-cropper'; - -import { fitCircleToImage, fitRectangleToImage } from './position'; -import { fittedCircleSize, fittedRectangleSize } from './size'; - -export function customResizeCoordinates( - state: CropperState, - settings: CropperSettings, - directions: ResizeDirections, - options: ResizeOptions, -) { - const minimumSize = getMinimumSize(state); - return { - ...state, - coordinates: resizeCoordinatesAlgorithm(state.coordinates, directions, options, { - positionRestrictions: mergePositionRestrictions( - getPositionRestrictions(state, settings), - coordinatesToPositionRestrictions(state.visibleArea), - ), - sizeRestrictions: { - minWidth: minimumSize, - minHeight: minimumSize, - maxWidth: state.visibleArea.width, - maxHeight: state.visibleArea.height, - }, - aspectRatio: getAspectRatio(state, settings), - }), - }; -} - -export function customTransformImage(state: CropperState, settings: CropperSettings, transform: ImageTransform) { - const { flip, ...otherTransforms } = transform; - if (flip) { - state = { - ...state, - transforms: { - ...state.transforms, - flip: { - horizontal: flip.horizontal ? !state.transforms.flip.horizontal : state.transforms.flip.horizontal, - vertical: flip.vertical ? !state.transforms.flip.vertical : state.transforms.flip.vertical, - }, - }, - }; - } - - return transformImage(state, settings, otherTransforms); -} - -export function getDefaultVisibleArea(state: CropperState) { - const { imageSize, boundary } = state; - - if (imageSize.width / imageSize.height > boundary.width / boundary.height) { - const width = imageSize.width; - const height = width / (boundary.width / boundary.height); - - return { - width, - height, - left: 0, - top: imageSize.height / 2 - height / 2, - }; - } else { - const height = imageSize.height; - const width = (boundary.width / boundary.height) * height; - - return { - width, - height, - left: imageSize.width / 2 - width / 2, - top: 0, - }; - } -} - -export function getDefaultSize(state: CropperState) { - const { imageSize } = state; - - return { - width: imageSize.width, - height: imageSize.height, - }; -} - -export function mobileAutoZoom( - state: CropperState, - settings: CropperSettings & { stencilType: 'circle' | 'rectangle' }, - action: PostprocessAction, -) { - const actions = [ - 'create', - 'reconcile', - 'rotate', - 'zoom', - 'interactionEnd', - 'setBoundary', - 'setVisibleArea', - 'setCoordinates', - ]; - if (action.immediately) { - const result = copyState(state); - const { stencilType } = settings; - - const size = (stencilType === 'circle' ? fittedCircleSize : fittedRectangleSize)({ - width: result.coordinates.width, - height: result.coordinates.height, - image: { - ...state.imageSize, - angle: state.transforms.rotate, - }, - aspectRatio: getAspectRatio(result, settings), - sizeRestrictions: getSizeRestrictions(result, settings), - }); - - const previousCenter = getCenter(result.coordinates); - - const currentCenter = getCenter({ - ...result.coordinates, - ...size, - }); - - // Return to the original position adjusted for size's change - result.coordinates = applyMove( - { - ...result.coordinates, - ...size, - }, - diff(previousCenter, currentCenter), - ); - - // Move to fit image - result.coordinates = applyMove( - result.coordinates, - (stencilType === 'circle' ? fitCircleToImage : fitRectangleToImage)(result.coordinates, { - ...state.imageSize, - angle: state.transforms.rotate, - }), - ); - - // Auto size - const stencil: Size = { - width: 0, - height: 0, - }; - if (ratio(result.boundary) > ratio(result.coordinates)) { - stencil.height = result.boundary.height; - stencil.width = stencil.height * ratio(result.coordinates); - } else { - stencil.width = result.boundary.width; - stencil.height = stencil.width * ratio(result.coordinates); - } - - // First of all try to resize visible area as much as possible: - result.visibleArea = applyScale( - result.visibleArea, - (result.coordinates.width * result.boundary.width) / (result.visibleArea.width * stencil.width), - ); - - if (ratio(result.boundary) > ratio(result.coordinates)) { - result.visibleArea.top = result.coordinates.top; - result.visibleArea.left = - result.coordinates.left - result.visibleArea.width / 2 + result.coordinates.width / 2; - } else { - result.visibleArea.left = result.coordinates.left; - result.visibleArea.top = - result.coordinates.top - result.visibleArea.height / 2 + result.coordinates.height / 2; - } - - return result; - } - - return state; -} diff --git a/src/algorithms/position.ts b/src/algorithms/position.ts deleted file mode 100644 index d20d0c7..0000000 --- a/src/algorithms/position.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { Point, rotatePoint, rotateSize, isUndefined, isNumber, Coordinates } from 'react-advanced-cropper'; - -interface Image { - width: number; - height: number; - angle: number; -} - -function min(array: T[]) { - return array.reduce((result, el) => { - if (isNumber(el) && (isUndefined(result) || el < result)) { - return el; - } else { - return result; - } - }, undefined); -} - -function max(array: T[]) { - return array.reduce((result, el) => { - if (isNumber(el) && (isUndefined(result) || el > result)) { - return el; - } else { - return result; - } - }, undefined); -} - -export function fitPolygonToImage(points: Point[], image: Image) { - const size = rotateSize(image, image.angle); - - const center = { - left: size.width / 2, - top: size.height / 2, - }; - - const box = { - left: center.left - image.width / 2, - top: center.top - image.height / 2, - height: image.height, - width: image.width, - }; - - const intersections = { - left: max( - points.map((point) => { - if (point.left < box.left) { - return box.left - point.left; - } - }), - ), - right: min( - points.map((point) => { - if (point.left > box.left + box.width) { - return box.left + box.width - point.left; - } - }), - ), - bottom: max( - points.map((point) => { - if (point.top < box.top) { - return box.top - point.top; - } - }), - ), - top: min( - points.map((point) => { - if (point.top > box.top + box.height) { - return box.top + box.height - point.top; - } - }), - ), - }; - - const leftVector = rotatePoint({ left: intersections.left || intersections.right || 0, top: 0 }, image.angle); - - const topVector = rotatePoint({ left: 0, top: intersections.top || intersections.bottom || 0 }, image.angle); - - return { - left: leftVector.left + topVector.left, - top: leftVector.top + topVector.top, - }; -} - -export function fitRectangleToImage(coordinates: Coordinates, image: Image) { - const size = rotateSize(image, image.angle); - - const center = { - left: size.width / 2, - top: size.height / 2, - }; - - let points = [ - { left: coordinates.left, top: coordinates.top }, - { left: coordinates.left + coordinates.width, top: coordinates.top }, - { left: coordinates.left + coordinates.width, top: coordinates.top + coordinates.height }, - { left: coordinates.left, top: coordinates.top + coordinates.height }, - ].map((point) => rotatePoint(point, -image.angle, center)); - - return fitPolygonToImage(points, image); -} - -export function fitCircleToImage(coordinates: Coordinates, image: Image) { - const size = rotateSize(image, image.angle); - - const imageCenter = { - left: size.width / 2, - top: size.height / 2, - }; - - const center = rotatePoint( - { - left: coordinates.left + coordinates.width / 2, - top: coordinates.top + coordinates.height / 2, - }, - -image.angle, - imageCenter, - ); - - let points = [ - { left: center.left - coordinates.width / 2, top: center.top - coordinates.height / 2 }, - { left: center.left + coordinates.width / 2, top: center.top - coordinates.height / 2 }, - { left: center.left + coordinates.width / 2, top: center.top + coordinates.height / 2 }, - { left: center.left - coordinates.width / 2, top: center.top + coordinates.height / 2 }, - ]; - - return fitPolygonToImage(points, image); -} diff --git a/src/algorithms/size.ts b/src/algorithms/size.ts deleted file mode 100644 index 00427ee..0000000 --- a/src/algorithms/size.ts +++ /dev/null @@ -1,183 +0,0 @@ -import { - AspectRatio, - Size, - SizeRestrictions, - isGreater, - mergeSizeRestrictions, - rotateSize, - approximateSize, - ratio, - fitToSizeRestrictions, - isLower, - sizeDistance, -} from 'react-advanced-cropper'; - -interface Image { - width: number; - height: number; - angle: number; -} -export function imageToSizeRestrictions(image: Image, aspectRatio?: number): SizeRestrictions { - let wrapper = rotateSize( - { - width: aspectRatio, - height: 1, - }, - image.angle, - ); - - if (image.width / image.height >= wrapper.width / wrapper.height) { - return { - minWidth: 0, - minHeight: 0, - maxHeight: image.height / wrapper.height, - maxWidth: (image.height / wrapper.height) * aspectRatio, - }; - } else { - return { - minWidth: 0, - minHeight: 0, - maxHeight: image.width / wrapper.width, - maxWidth: (image.width / wrapper.width) * aspectRatio, - }; - } -} - -function validateSize(params: { - size: Size; - aspectRatio: AspectRatio; - sizeRestrictions: SizeRestrictions; - image: Image; - ignoreMinimum?: boolean; -}) { - const { size, aspectRatio, ignoreMinimum, image } = params; - - const sizeRestrictions = - size.width > 0 && size.height > 0 - ? mergeSizeRestrictions(params.sizeRestrictions, imageToSizeRestrictions(image, ratio(size))) - : params.sizeRestrictions; - - return ( - !isLower(ratio(size), aspectRatio.minimum) && - !isGreater(ratio(size), aspectRatio.maximum) && - !isGreater(size.height, Math.ceil(sizeRestrictions.maxHeight)) && - !isGreater(size.width, Math.ceil(sizeRestrictions.maxWidth)) && - size.width && - size.height && - (ignoreMinimum || (size.height >= sizeRestrictions.minHeight && size.width >= sizeRestrictions.minWidth)) - ); -} - -export function fittedRectangleSize(params: { - width: number; - height: number; - image: Image; - sizeRestrictions: SizeRestrictions; - aspectRatio?: AspectRatio; -}): Size { - const { width, height, image } = params; - - const rotatedImageSize = rotateSize(image, image.angle); - - const sizeRestrictions = mergeSizeRestrictions(params.sizeRestrictions, { - maxHeight: rotatedImageSize.height, - maxWidth: rotatedImageSize.width, - }); - - const aspectRatio = { - minimum: (params.aspectRatio && params.aspectRatio.minimum) || 0, - maximum: (params.aspectRatio && params.aspectRatio.maximum) || Infinity, - }; - - const coordinates = { - width: Math.max(sizeRestrictions.minWidth, width), - height: Math.max(sizeRestrictions.minHeight, height), - }; - - function findBestCandidate(candidates: Size[], ignoreMinimum = false): Size | null { - return candidates.reduce((minimum: Size | null, size: Size) => { - const sizeRestrictions = mergeSizeRestrictions( - params.sizeRestrictions, - imageToSizeRestrictions(image, ratio(size)), - ); - - if (validateSize({ size, aspectRatio, sizeRestrictions, image, ignoreMinimum })) { - return !minimum || sizeDistance(size, { width, height }) < sizeDistance(minimum, { width, height }) - ? size - : minimum; - } else { - return minimum; - } - }, null); - } - - const angleRestrictions = imageToSizeRestrictions( - image, - Math.min(aspectRatio.maximum, Math.max(aspectRatio.minimum, ratio(coordinates))), - ); - - let candidates: Size[] = [ - coordinates, - { - width: Math.min(sizeRestrictions.maxWidth, angleRestrictions.maxWidth), - height: Math.min(sizeRestrictions.maxHeight, angleRestrictions.maxHeight), - }, - ]; - - if (aspectRatio) { - [aspectRatio.minimum, aspectRatio.maximum].forEach((ratio) => { - if (ratio && ratio !== Infinity) { - const fittedSizeRestrictions = mergeSizeRestrictions( - sizeRestrictions, - imageToSizeRestrictions(image, ratio), - ); - - const width = Math.min(coordinates.width, fittedSizeRestrictions.maxWidth); - const height = Math.min(coordinates.height, fittedSizeRestrictions.maxHeight); - - candidates.push({ width, height: width / ratio }, { width: height * ratio, height }); - } - }); - } - - // Resize the candidates as much as possible to prevent breaking minimum size - candidates = candidates.map((candidate) => { - const coefficient = fitToSizeRestrictions( - candidate, - mergeSizeRestrictions(imageToSizeRestrictions(image, ratio(candidate)), sizeRestrictions), - ); - - return { - ...candidate, - width: candidate.width * coefficient, - height: candidate.height * coefficient, - }; - }); - - const candidate = findBestCandidate(candidates) || findBestCandidate(candidates, true); - - return ( - candidate && { - width: candidate.width, - height: candidate.height, - } - ); -} - -export function fittedCircleSize(params: { - width: number; - height: number; - image: Image; - sizeRestrictions: SizeRestrictions; - aspectRatio?: AspectRatio; -}): Size { - return approximateSize({ - width: params.width, - height: params.height, - sizeRestrictions: mergeSizeRestrictions(params.sizeRestrictions, { - maxWidth: params.image.width, - maxHeight: params.image.height, - }), - aspectRatio: params.aspectRatio, - }); -} diff --git a/src/components/Cropper.scss b/src/components/Cropper.scss index dbe6775..facdb50 100644 --- a/src/components/Cropper.scss +++ b/src/components/Cropper.scss @@ -6,7 +6,7 @@ color: $rmc-main-color; } -.rmc-rectangle-stencil, .rmc-circle-stencil { +.rmc-stencil { &__line { border-color: rgba($rmc-line-color, 0.8); } @@ -81,17 +81,3 @@ } } } - -.rmc-circle-stencil { - &__line { - border-color: rgba($rmc-line-color, 0.3); - } - &__preview { - border: solid 2px rgba($rmc-line-color, 0.4); - } - &__handler { - &--hover { - opacity: 1; - } - } -} diff --git a/src/components/Cropper.tsx b/src/components/Cropper.tsx index fd2f311..76c993a 100644 --- a/src/components/Cropper.tsx +++ b/src/components/Cropper.tsx @@ -1,29 +1,30 @@ import React, { forwardRef, useRef } from 'react'; import cn from 'classnames'; import { - Cropper as BasicCropper, - CropperProps as BasicCropperProps, + Cropper as DefaultCropper, + CropperProps as DefaultCropperProps, ScaleImageSettings, - RectangleStencil, CropperRef, - CircleStencil, - useUpdateEffect, mergeRefs, + ImageRestriction, + joinClassNames, } from 'react-advanced-cropper'; import { - customResizeCoordinates, - customTransformImage, - getDefaultSize, - getDefaultVisibleArea, - mobileAutoZoom, -} from '../algorithms'; -import { joinClassNames } from '../service/styles'; + autoZoom, + resizeCoordinates, + transformImage, + defaultSize, + stencilConstraints, +} from 'advanced-cropper/showcase/telegram'; import { PublicNavigationProps } from './Navigation'; import { CropperWrapper } from './CropperWrapper'; +import './Cropper.scss'; export interface CropperProps - extends Omit { - stencilType?: 'circle' | 'rectangle'; + extends Omit< + DefaultCropperProps, + 'transitions' | 'priority' | 'imageRestriction' | 'stencilSize' | 'stencilConstraints' | 'transformImage' + > { spinnerClassName?: string; resizeImage?: boolean | Omit; navigation?: boolean; @@ -35,98 +36,42 @@ export const Cropper = forwardRef((props: CropperProps, ref) => { className, spinnerClassName, navigation = true, - stateSettings = {}, - stencilType = 'rectangle', stencilProps = {}, navigationProps = {}, - stencilComponent, - wrapperComponent = CropperWrapper, - defaultVisibleArea = getDefaultVisibleArea, - defaultSize = getDefaultSize, - transformImageAlgorithm = customTransformImage, - resizeCoordinatesAlgorithm = customResizeCoordinates, - postProcess = mobileAutoZoom, + wrapperComponent, ...cropperProps } = props; const cropperRef = useRef(null); - useUpdateEffect(() => { - cropperRef.current?.refresh(); - }, [stencilType]); + const WrapperComponent = wrapperComponent || CropperWrapper; - let WrapperComponent = wrapperComponent; - - let StencilComponent = stencilComponent; - - let stencilClassNames = {}; - - if (!StencilComponent) { - if (stencilType === 'circle') { - StencilComponent = CircleStencil; - stencilClassNames = { - lineClassNames: joinClassNames(stencilProps.lineClassNames, { - default: 'rmc-circle-stencil__line', - }), - handlerWrapperClassNames: joinClassNames(stencilProps.handlerWrapperClassNames, { - default: 'rmc-circle-stencil__handler-wrapper', - westNorth: 'rmc-circle-stencil__handler-wrapper--west-north', - eastSouth: 'rmc-circle-stencil__handler-wrapper--east-south', - westSouth: 'rmc-circle-stencil__handler-wrapper--west-south', - eastNorth: 'rmc-circle-stencil__handler-wrapper--east-north', - }), - handlerClassNames: joinClassNames(stencilProps.handlerClassNames, { - default: 'rmc-circle-stencil__handler', - hover: 'rmc-circle-stencil__handler--hover', - westNorth: 'rmc-circle-stencil__handler--west-north', - eastSouth: 'rmc-circle-stencil__handler--east-south', - westSouth: 'rmc-circle-stencil__handler--west-south', - eastNorth: 'rmc-circle-stencil__handler--east-north', - }), - previewClassName: cn(stencilProps.previewClassName, 'rmc-circle-stencil__preview'), - }; - } else { - StencilComponent = RectangleStencil; - stencilClassNames = { + return ( + { navigation, spinnerClassName, }} - imageRestriction={'none'} - transitions={true} - priority={'visibleArea'} + imageRestriction={ImageRestriction.none} className={cn('rmc-cropper', className)} + postProcess={autoZoom} + defaultSize={defaultSize} + transformImageAlgorithm={transformImage} + resizeCoordinatesAlgorithm={resizeCoordinates} + transitions={true} /> ); }); diff --git a/src/components/CropperWrapper.tsx b/src/components/CropperWrapper.tsx index 758de76..53c66ad 100644 --- a/src/components/CropperWrapper.tsx +++ b/src/components/CropperWrapper.tsx @@ -1,14 +1,16 @@ -import React, { FC, useEffect, useRef } from 'react'; +import React, { CSSProperties, FC, useEffect, useRef } from 'react'; import { CropperRef, CropperFade } from 'react-advanced-cropper'; import cn from 'classnames'; import { Spinner } from '../icons/Spinner'; import { Navigation, NavigationRef, PublicNavigationProps } from './Navigation'; +import './CropperWrapper.scss'; export interface CropperWrapperProps { - cropper?: CropperRef; - loading?: boolean; - loaded?: boolean; + cropper: CropperRef; + loading: boolean; + loaded: boolean; className?: string; + style?: CSSProperties; spinnerClassName?: string; navigation?: boolean; navigationProps?: PublicNavigationProps; @@ -22,7 +24,7 @@ export const CropperWrapper: FC> = ({ className, spinnerClassName, navigation, - navigationProps, + navigationProps = {}, }) => { const navigationRef = useRef(null); @@ -37,7 +39,13 @@ export const CropperWrapper: FC> = ({ }, [state?.boundary.width, state?.boundary.height]); return ( -
+
{children} {navigation && ( diff --git a/src/components/Navigation.tsx b/src/components/Navigation.tsx index 4940ce0..edce2d8 100644 --- a/src/components/Navigation.tsx +++ b/src/components/Navigation.tsx @@ -1,4 +1,4 @@ -import React, { FC, forwardRef, useImperativeHandle, useLayoutEffect, useRef, useState } from 'react'; +import React, { forwardRef, useImperativeHandle, useLayoutEffect, useRef, useState } from 'react'; import { CropperMethodOptions } from 'react-advanced-cropper'; import cn from 'classnames'; import { FlipHorizontalIcon } from '../icons/FlipHorizontalIcon'; @@ -6,6 +6,7 @@ import { RotateRightIcon } from '../icons/RotateRightIcon'; import { RotateLeftIcon } from '../icons/RotateLeftIcon'; import { FlipVerticalIcon } from '../icons/FlipVerticalIcon'; import { RotateComponent, RotateComponentRef } from './RotateComponent'; +import './Navigation.scss'; export interface PublicNavigationProps { className?: string; @@ -48,8 +49,8 @@ export const Navigation = forwardRef( ref, ) => { const [quarter, setQuarter] = useState(0); - const [adjustmentAngle, setAdjustnmentAngle] = useState(0); - const rotateComponentRef = useRef(); + const [adjustmentAngle, setAdjustmentAngle] = useState(0); + const rotateComponentRef = useRef(null); useLayoutEffect(() => { const absRotate = Math.abs(value); @@ -67,7 +68,8 @@ export const Navigation = forwardRef( if (rotate !== quarter) { setQuarter(rotate); } - setAdjustnmentAngle(Math.sign(value) * (Math.abs(value) - Math.abs(rotate) * 90)); + setAdjustmentAngle(Math.sign(value) * (Math.abs(value) - Math.abs(rotate) * 90)); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [value]); useImperativeHandle(ref, () => { diff --git a/src/components/RotateComponent.tsx b/src/components/RotateComponent.tsx index 9ac281f..5f92a28 100644 --- a/src/components/RotateComponent.tsx +++ b/src/components/RotateComponent.tsx @@ -1,7 +1,7 @@ -import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react'; -import { DraggableArea, MoveDirections, useWindowResize } from 'react-advanced-cropper'; +import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react'; +import { DraggableArea, MoveDirections } from 'react-advanced-cropper'; import cn from 'classnames'; -import { range } from '../service/utils'; +import './RotateComponent.scss'; interface RotateComponentProps { from: number; @@ -24,6 +24,19 @@ export interface RotateComponentRef { refresh: () => void; } +function range(from: number, to: number, step = 1): number[] { + let index = -1; + let length = Math.max(Math.ceil((to - from) / (step || 1)), 0); + + const result = new Array(length); + + while (length--) { + result[++index] = from; + from += step; + } + return result; +} + export const RotateComponent = forwardRef( ( { @@ -43,11 +56,11 @@ export const RotateComponent = forwardRef { - const barsRef = useRef(); + const barsRef = useRef(null); const [dragging, setDragging] = useState(false); - const [items, setItems] = useState([]); + const [items, setItems] = useState([]); const recalculate = () => { if (barsRef.current) { diff --git a/yarn.lock b/yarn.lock index dd5703b..bdcee9e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1833,10 +1833,10 @@ address@^1.0.1: resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" integrity sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA== -advanced-cropper@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/advanced-cropper/-/advanced-cropper-0.3.3.tgz#b128f52eb03c8e76f4eab77bcd8478f98e8eac12" - integrity sha512-qh2CQFSMClLX67lCNbEs/RFs82z69k2rgdlU5WjhSu2l2zXyriL1oV5OQ0nvrC9yO8aIS/VZym/0IYHlfHRB8g== +advanced-cropper@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/advanced-cropper/-/advanced-cropper-0.7.0.tgz#991d0da9f25e76817c2ee3c4e86bd26c7963c6bd" + integrity sha512-Kx88ofstgGrBGvcIL5nuCpVQmcDhKYysF6eoRALsXRe8Z58bXghefMgA4ebfE7tYGJbcsqXicPOKZGGryN9p8Q== dependencies: tslib "^2.0.1" @@ -1931,7 +1931,7 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.1.0: +ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== @@ -3126,6 +3126,21 @@ check-types@^7.3.0: resolved "https://registry.yarnpkg.com/check-types/-/check-types-7.4.0.tgz#0378ec1b9616ec71f774931a3c6516fad8c152f4" integrity sha512-YbulWHdfP99UfZ73NcUDlNJhEIDgm9Doq9GhpyXbF+7Aegi3CVV7qqMCKTTqJxlvEvnQBp9IA+dxsGN6xK/nSg== +"chokidar@>=3.0.0 <4.0.0": + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + chokidar@^2.0.0, chokidar@^2.0.4, chokidar@^2.1.8: version "2.1.8" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" @@ -3249,6 +3264,15 @@ cliui@^5.0.0: strip-ansi "^5.2.0" wrap-ansi "^5.1.0" +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + clone-buffer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" @@ -4002,11 +4026,6 @@ data-urls@^1.0.0: whatwg-mimetype "^2.2.0" whatwg-url "^7.0.0" -debounce@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" - integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== - debug-fabulous@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/debug-fabulous/-/debug-fabulous-1.1.0.tgz#af8a08632465224ef4174a9f06308c3c2a1ebc8e" @@ -4108,6 +4127,11 @@ default-resolution@^2.0.0: resolved "https://registry.yarnpkg.com/default-resolution/-/default-resolution-2.0.0.tgz#bcb82baa72ad79b426a76732f1a81ad6df26d684" integrity sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ= +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + define-properties@^1.1.2, define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -5620,7 +5644,7 @@ get-caller-file@^1.0.1: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== -get-caller-file@^2.0.1: +get-caller-file@^2.0.1, get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== @@ -6378,6 +6402,11 @@ immer@1.10.0: resolved "https://registry.yarnpkg.com/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d" integrity sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg== +immutable@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.1.0.tgz#f795787f0db780183307b9eb2091fcac1f6fafef" + integrity sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ== + import-cwd@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" @@ -6744,6 +6773,11 @@ is-directory@^0.3.1: resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= +is-docker@^2.0.0, is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + is-dotfile@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" @@ -7033,6 +7067,13 @@ is-wsl@^1.1.0: resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -8405,6 +8446,11 @@ nanocolors@^0.1.12: resolved "https://registry.yarnpkg.com/nanocolors/-/nanocolors-0.1.12.tgz#8577482c58cbd7b5bb1681db4cf48f11a87fd5f6" integrity sha512-2nMHqg1x5PU+unxX7PGY7AuYxl2qDx7PSrTRjizr8sxdd3l/3hBuWWaki62qmtYm2U5i4Z5E7GbjlyDFhs9/EQ== +nanoid@^3.1.32: + version "3.3.4" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" + integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -8901,6 +8947,15 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" +open@^8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8" + integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + opn@5.4.0: version "5.4.0" resolved "https://registry.yarnpkg.com/opn/-/opn-5.4.0.tgz#cb545e7aab78562beb11aa3bfabc7042e1761035" @@ -10545,14 +10600,13 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-advanced-cropper@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/react-advanced-cropper/-/react-advanced-cropper-0.3.1.tgz#2f1e9cb244407a40c3b808634e928f50d11ff41d" - integrity sha512-wAWZ7t+V6bqGhKc3tATktgSIBqDjB5WWRXB72YkQ7uhabw6+DmUb7JW+mrIIXKIM5S4n96RN3O+B4wue0lZndg== +react-advanced-cropper@^0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/react-advanced-cropper/-/react-advanced-cropper-0.7.3.tgz#c51d12c312cf0ce7159e7078e5ca2f17103ea95f" + integrity sha512-mX/QAt1PV3vGZ3VRr0iMcZRR3f5azFaSa0JZozGb/2MqoZMXg3wgizwN97NR+y7kV1FOoYICrEwx906lwqYJWg== dependencies: - advanced-cropper "^0.3.3" + advanced-cropper "^0.7.0" classnames "^2.2.6" - debounce "^1.2.0" tslib "^2.0.3" react-app-polyfill@^0.2.2: @@ -11159,6 +11213,16 @@ rollup-plugin-terser@^7.0.2: serialize-javascript "^4.0.0" terser "^5.0.0" +rollup-plugin-visualizer@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.6.0.tgz#06aa7cf3fd504a29d404335700f2a3f28ebb33f3" + integrity sha512-CKcc8GTUZjC+LsMytU8ocRr/cGZIfMR7+mdy4YnlyetlmIl/dM8BMnOEpD4JPIGt+ZVW7Db9ZtSsbgyeBH3uTA== + dependencies: + nanoid "^3.1.32" + open "^8.4.0" + source-map "^0.7.3" + yargs "^17.3.1" + rollup-pluginutils@2, rollup-pluginutils@^2.8.2: version "2.8.2" resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e" @@ -11262,6 +11326,15 @@ sass-loader@7.1.0: pify "^3.0.0" semver "^5.5.0" +sass@^1.53.0: + version "1.53.0" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.53.0.tgz#eab73a7baac045cc57ddc1d1ff501ad2659952eb" + integrity sha512-zb/oMirbKhUgRQ0/GFz8TSAwRq2IlR29vOUJZOx0l8sV+CkHUfHa4u5nqrG+1VceZp7Jfj59SVW9ogdhTvJDcQ== + dependencies: + chokidar ">=3.0.0 <4.0.0" + immutable "^4.0.0" + source-map-js ">=0.6.2 <2.0.0" + sax@^1.2.4, sax@~1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" @@ -11601,6 +11674,11 @@ source-list-map@^2.0.0: resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== +"source-map-js@>=0.6.2 <2.0.0": + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + source-map-resolve@^0.5.0: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" @@ -11657,6 +11735,11 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +source-map@^0.7.3: + version "0.7.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" + integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== + source-map@~0.7.2: version "0.7.3" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" @@ -11861,7 +11944,7 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2 || 3 || 4": +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -13281,6 +13364,15 @@ wrap-ansi@^5.1.0: string-width "^3.0.0" strip-ansi "^5.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -13334,6 +13426,11 @@ y18n@^3.2.1: resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" @@ -13369,6 +13466,11 @@ yargs-parser@^13.1.2: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^21.0.0: + version "21.0.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.1.tgz#0267f286c877a4f0f728fceb6f8a3e4cb95c6e35" + integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg== + yargs-parser@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.1.tgz#7ede329c1d8cdbbe209bd25cdb990e9b1ebbb394" @@ -13436,6 +13538,19 @@ yargs@^13.3.2: y18n "^4.0.0" yargs-parser "^13.1.2" +yargs@^17.3.1: + version "17.5.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e" + integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.0.0" + yargs@^7.1.0: version "7.1.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.2.tgz#63a0a5d42143879fdbb30370741374e0641d55db"