UNPKG

react-mobile-cropper

Version:

The react mobile cropper inspired by Android mobile croppers

286 lines (271 loc) 19 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var reactAdvancedCropper = require('react-advanced-cropper'); var tslib = require('tslib'); var React = require('react'); var cn = require('classnames'); var mobile = require('advanced-cropper/showcase/mobile'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var React__default = /*#__PURE__*/_interopDefaultLegacy(React); var cn__default = /*#__PURE__*/_interopDefaultLegacy(cn); var FlipHorizontalIcon = function (_a) { var className = _a.className; return (React__default["default"].createElement("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16" }, React__default["default"].createElement("path", { fill: "#FFF", d: "M8 15.9c-.6 0-1-.4-1-1V1c0-.6.4-1 1-1s1 .4 1 1v13.9c0 .6-.4 1-1 1zm4-2.4h-.5c-.4 0-.8-.3-.8-.8s.3-.8.8-.8h.5c.4 0 .8.3.8.8s-.4.8-.8.8zm2.7 0h-.5c-.4 0-.8-.3-.8-.8 0-.3.2-.6.5-.7.1-.3.4-.5.7-.5.4 0 .8.3.8.8v.5c.1.4-.3.7-.7.7zm0-2.8c-.4 0-.8-.3-.8-.8v-.8c0-.4.3-.8.8-.8s.8.3.8.8v.8c0 .4-.4.8-.8.8zm0-3.3c-.4 0-.8-.3-.8-.8v-.7c0-.4.3-.8.8-.8s.8.3.8.8v.8c0 .4-.4.7-.8.7zm0-3.3c-.3 0-.6-.2-.7-.5-.3-.1-.5-.4-.5-.7 0-.4.3-.8.8-.8h.5c.4 0 .8.3.8.8v.5c-.1.4-.5.7-.9.7zM12 3.6h-.5c-.4 0-.8-.3-.8-.8s.3-.8.8-.8h.5c.4 0 .8.3.8.8s-.4.8-.8.8zM4.5 13.5H1.3c-.4 0-.8-.3-.8-.8V2.9c0-.4.3-.8.8-.8h3.2v1.5H2V12h2.5v1.5z" }))); }; var RotateRightIcon = function (_a) { var className = _a.className; return (React__default["default"].createElement("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16" }, React__default["default"].createElement("path", { fill: "#FFF", d: "M12.5 11.8c.2.2.2.6 0 .9-1.1 1.1-2.8 1.8-4.5 1.8-3.7 0-6.5-2.8-6.5-6.5s3-6.5 6.5-6.5c1.7 0 3.3.7 4.5 1.8l1-1c.4-.4 1-.1 1 .4v3.8c0 .3-.3.6-.6.6h-3.7c-.5 0-.8-.7-.4-1L11 4.9c-.9-.9-1.9-1.3-3-1.3-3 0-5.4 3.1-4 6.2.7 1.6 2.3 2.6 4 2.6 1.2 0 2.2-.4 3-1.3.2-.2.6-.2.8 0l.7.7z" }))); }; var RotateLeftIcon = function (_a) { var className = _a.className; return (React__default["default"].createElement("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16" }, React__default["default"].createElement("path", { fill: "#FFF", d: "M3.5 11.8c-.2.2-.2.6 0 .9 1.1 1.1 2.8 1.8 4.5 1.8 3.7 0 6.5-2.8 6.5-6.5s-3-6.5-6.5-6.5c-1.7 0-3.3.7-4.5 1.8l-1-1c-.4-.4-1-.1-1 .4v3.8c0 .3.3.6.6.6h3.7c.5 0 .8-.7.4-1L5 4.9c.9-.9 1.9-1.3 3-1.3 3 0 5.4 3.1 4 6.2-.7 1.6-2.3 2.6-4 2.6-1.2 0-2.2-.4-3-1.3-.2-.2-.6-.2-.8 0l-.7.7z" }))); }; var FlipVerticalIcon = function (_a) { var className = _a.className; return (React__default["default"].createElement("svg", { className: className, xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16" }, React__default["default"].createElement("path", { fill: "#FFF", d: "M15 9H1c-.5 0-1-.5-1-1s.4-1 1-1h14c.6 0 1 .4 1 1s-.5 1-1 1zM3.1 12.7c-.4 0-.8-.3-.8-.8v-.5c0-.4.3-.8.8-.8s.8.3.8.8v.6c0 .4-.3.7-.8.7zM3.6 15.4h-.5c-.4 0-.8-.3-.8-.8v-.5c0-.4.3-.8.8-.8.3 0 .6.2.7.5.3.1.5.4.5.7.1.6-.2.9-.7.9zM10.1 15.4h-.8c-.4 0-.8-.3-.8-.8s.3-.8.8-.8h.8c.4 0 .8.3.8.8s-.4.8-.8.8zm-3.2 0H6c-.4 0-.8-.3-.8-.8s.3-.8.8-.8h.8c.4 0 .8.3.8.8s-.3.8-.7.8zM13 15.4h-.5c-.4 0-.8-.3-.8-.8 0-.3.2-.6.5-.7.1-.3.4-.5.7-.5.4 0 .8.3.8.8v.5c.1.4-.2.7-.7.7zM13 12.7c-.4 0-.8-.3-.8-.8v-.5c0-.4.3-.8.8-.8s.8.3.8.8v.6c0 .4-.3.7-.8.7z" }), React__default["default"].createElement("g", null, React__default["default"].createElement("path", { fill: "#FFF", d: "M13.8 4.5h-1.5V2H3.9v2.5H2.4V1.3c0-.4.3-.8.8-.8H13c.4 0 .8.3.8.8v3.2z" })))); }; function range(from, to, step) { if (step === void 0) { step = 1; } var index = -1; var length = Math.max(Math.ceil((to - from) / (step || 1)), 0); var result = new Array(length); while (length--) { result[++index] = from; from += step; } return result; } var RotateComponent = React.forwardRef(function (_a, ref) { var from = _a.from, to = _a.to, value = _a.value, _b = _a.step, step = _b === void 0 ? 2.5 : _b, _c = _a.thickness, thickness = _c === void 0 ? 2 : _c, onBlur = _a.onBlur, onChange = _a.onChange, className = _a.className, valueBarClassName = _a.valueBarClassName, barsClassName = _a.barsClassName, barClassName = _a.barClassName, highlightedBarClassName = _a.highlightedBarClassName, zeroBarClassName = _a.zeroBarClassName, _d = _a.density, density = _d === void 0 ? 10 : _d; var barsRef = React.useRef(null); var _e = tslib.__read(React.useState(false), 2), dragging = _e[0], setDragging = _e[1]; var _f = tslib.__read(React.useState([]), 2), items = _f[0], setItems = _f[1]; var recalculate = function () { if (barsRef.current) { var width_1 = barsRef.current.clientWidth; var count_1 = width_1 / density; var neededLeftBarsCount = Math.max(0, Math.floor(count_1 / 2) - Math.round((value - from) / step)); var neededRightBarsCount = Math.max(0, Math.floor(count_1 / 2) - Math.round((to - value) / step)); var values = tslib.__spreadArray(tslib.__spreadArray(tslib.__spreadArray([], tslib.__read(range(from - neededLeftBarsCount * step, from, step)), false), tslib.__read(range(from, to + step, step)), false), tslib.__read(range(to + step, to + step + neededRightBarsCount * step, step)), false); var radius_1 = Math.abs(Math.ceil(count_1 / 2) * step); setItems(values.map(function (barValue) { var sign = Math.sign(barValue - value); // Opacity var translate; if (Math.abs(barValue - value) / step <= Math.ceil(count_1 / 2)) { var multiplier = Math.sqrt(Math.pow(radius_1, 2) - Math.pow(value + sign * radius_1 - barValue, 2)) / radius_1; translate = width_1 / 2 + sign * (width_1 / 2) * Math.pow(multiplier, 2.5); } else { translate = width_1 / 2 + (sign * width_1) / 2; } // Translate var opacity = 0; if (count_1 > 0 && Math.abs(barValue - value) / step <= Math.ceil(count_1 / 2)) { opacity = Math.pow(Math.sqrt(Math.pow(radius_1, 2) - Math.pow(value - barValue, 2)) / radius_1, 4); } return { value: barValue, highlighted: (value < 0 && barValue >= value && barValue <= 0) || (value > 0 && barValue <= value && barValue >= 0), zero: barValue === 0, opacity: opacity, translate: translate - thickness / 2, }; })); } }; React.useEffect(function () { recalculate(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [density, thickness, from, to, value, step]); React.useImperativeHandle(ref, function () { return { refresh: recalculate, }; }); var onMove = function (directions) { if (barsRef.current) { var width = barsRef.current.clientWidth; var count = width / density; var shift = -(directions.left / barsRef.current.clientWidth) * count * step; if (onChange) { if (value + shift > to) { onChange(to - value); } else if (value + shift < from) { onChange(from - value); } else { onChange(shift); } } } }; var onMoveEnd = function () { document.body.classList.remove('dragging'); setDragging(false); onBlur === null || onBlur === void 0 ? void 0 : onBlur(); }; var onMoveStart = function () { document.body.classList.add('dragging'); setDragging(true); }; return (React__default["default"].createElement("div", { className: cn__default["default"]('rmc-rotate-component', className) }, React__default["default"].createElement(reactAdvancedCropper.DraggableArea, { onMoveStart: onMoveStart, onMove: onMove, onMoveEnd: onMoveEnd, useAnchor: false }, React__default["default"].createElement("div", { className: cn__default["default"]('rmc-rotate-component__bars', dragging && 'rmc-rotate-component__bars--dragging', barsClassName), ref: barsRef }, items.map(function (bar) { return (React__default["default"].createElement("div", { className: cn__default["default"]('rmc-rotate-component__bar', bar.zero && 'rmc-rotate-component__bar--zero', bar.highlighted && 'rmc-rotate-component__bar--highlighted', barClassName, bar.highlighted && highlightedBarClassName, bar.zero && zeroBarClassName), key: bar.value, style: { width: bar.opacity ? thickness : 0, opacity: bar.opacity, transform: "translate(" + bar.translate + "px, -50%)", } })); }), React__default["default"].createElement("div", { className: cn__default["default"]('rmc-rotate-component__value', valueBarClassName) }, React__default["default"].createElement("div", { className: "rmc-rotate-component__value-number" }, value.toFixed(1), "\u00B0")))))); }); RotateComponent.displayName = 'RotateComponent'; var Navigation = React.forwardRef(function (_a, ref) { var className = _a.className, buttonClassName = _a.buttonClassName, rotateComponentClassName = _a.rotateComponentClassName, barClassName = _a.barClassName, highlightedBarClassName = _a.highlightedBarClassName, zeroBarClassName = _a.zeroBarClassName, valueBarClassName = _a.valueBarClassName, disabled = _a.disabled, value = _a.value, onRotate = _a.onRotate, onRotateEnd = _a.onRotateEnd, onFlip = _a.onFlip; var _b = tslib.__read(React.useState(0), 2), quarter = _b[0], setQuarter = _b[1]; var _c = tslib.__read(React.useState(0), 2), adjustmentAngle = _c[0], setAdjustmentAngle = _c[1]; var rotateComponentRef = React.useRef(null); React.useLayoutEffect(function () { var absRotate = Math.abs(value); var rotate; if (absRotate % 90 > 45) { rotate = (absRotate - (absRotate % 90) + 90) / 90; } else if (absRotate % 90 < 45) { rotate = (absRotate - (absRotate % 90)) / 90; } else { rotate = quarter; } rotate = Math.sign(rotate) * rotate; if (rotate !== quarter) { setQuarter(rotate); } setAdjustmentAngle(Math.sign(value) * (Math.abs(value) - Math.abs(rotate) * 90)); // eslint-disable-next-line react-hooks/exhaustive-deps }, [value]); React.useImperativeHandle(ref, function () { return { refresh: function () { if (rotateComponentRef.current) { rotateComponentRef.current.refresh(); } }, }; }); var rotateTo = function (angle) { if (onRotate && !disabled) { onRotate(angle, { transitions: false, interaction: true, immediately: true, }); } }; var rotateLeft = function () { if (onRotate && !disabled) { if (adjustmentAngle > 0) { onRotate(-adjustmentAngle); } else if (adjustmentAngle < 0) { onRotate(-90 - adjustmentAngle); } else { onRotate(-90); } } }; var rotateRight = function () { if (onRotate && !disabled) { if (adjustmentAngle > 0) { onRotate(90 - adjustmentAngle); } else if (adjustmentAngle < 0) { onRotate(-adjustmentAngle); } else { onRotate(90); } } }; var flipHorizontal = function () { if (onFlip && !disabled) { onFlip(true); } }; var flipVertical = function () { if (onFlip && !disabled) { onFlip(false, true); } }; return (React__default["default"].createElement("div", { className: cn__default["default"]('rmc-navigation', className) }, React__default["default"].createElement("button", { type: "button", className: cn__default["default"]('rmc-navigation__button', buttonClassName), onClick: flipHorizontal }, React__default["default"].createElement(FlipHorizontalIcon, null)), React__default["default"].createElement("button", { type: "button", className: cn__default["default"]('rmc-navigation__button', buttonClassName), onClick: rotateRight }, React__default["default"].createElement(RotateRightIcon, null)), React__default["default"].createElement(RotateComponent, { ref: rotateComponentRef, className: cn__default["default"]('rmc-navigation__rotator', rotateComponentClassName), barClassName: barClassName, zeroBarClassName: zeroBarClassName, valueBarClassName: valueBarClassName, highlightedBarClassName: highlightedBarClassName, onChange: rotateTo, onBlur: onRotateEnd, from: -45, to: 45, value: adjustmentAngle }), React__default["default"].createElement("button", { type: "button", className: cn__default["default"]('rmc-navigation__button', buttonClassName), onClick: rotateLeft }, React__default["default"].createElement(RotateLeftIcon, null)), React__default["default"].createElement("button", { type: "button", className: cn__default["default"]('rmc-navigation__button', buttonClassName), onClick: flipVertical }, React__default["default"].createElement(FlipVerticalIcon, null)))); }); Navigation.displayName = 'Navigation'; var Spinner = function (_a) { var className = _a.className; return (React__default["default"].createElement("svg", { className: className, width: "38", height: "38", viewBox: "0 0 38 38", xmlns: "http://www.w3.org/2000/svg" }, React__default["default"].createElement("g", { fill: "none", fillRule: "evenodd" }, React__default["default"].createElement("g", { transform: "translate(1 1)", strokeWidth: "2" }, React__default["default"].createElement("circle", { strokeOpacity: ".5", cx: "18", cy: "18", r: "18" }), React__default["default"].createElement("path", { d: "M36 18c0-9.94-8.06-18-18-18" }, React__default["default"].createElement("animateTransform", { attributeName: "transform", type: "rotate", from: "0 18 18", to: "360 18 18", dur: "1s", repeatCount: "indefinite" })))))); }; var CropperWrapper = function (_a) { var cropper = _a.cropper, children = _a.children, loaded = _a.loaded, loading = _a.loading, className = _a.className, spinnerClassName = _a.spinnerClassName, navigation = _a.navigation, _b = _a.navigationProps, navigationProps = _b === void 0 ? {} : _b; var navigationRef = React.useRef(null); var state = cropper.getState(); var transitions = cropper.getTransitions(); var rotate = cropper.getTransforms().rotate; React.useEffect(function () { var _a; (_a = navigationRef.current) === null || _a === void 0 ? void 0 : _a.refresh(); }, [state === null || state === void 0 ? void 0 : state.boundary.width, state === null || state === void 0 ? void 0 : state.boundary.height]); return (React__default["default"].createElement("div", { className: cn__default["default"]('rmc-cropper-wrapper', navigation && 'rmc-cropper-wrapper--with-navigation', className) }, React__default["default"].createElement(reactAdvancedCropper.CropperFade, { className: 'rmc-cropper-wrapper__fade', visible: loaded }, children, navigation && (React__default["default"].createElement(Navigation, { ref: navigationRef, value: rotate, onRotate: cropper.rotateImage, onRotateEnd: cropper.transformImageEnd, onFlip: cropper.flipImage, className: cn__default["default"]('rmc-cropper-wrapper__navigation', navigationProps.className), buttonClassName: navigationProps.buttonClassName, barClassName: navigationProps.barClassName, valueBarClassName: navigationProps.valueBarClassName, zeroBarClassName: navigationProps.zeroBarClassName, highlightedBarClassName: navigationProps.highlightedBarClassName, disabled: transitions.active }))), React__default["default"].createElement(Spinner, { className: cn__default["default"]('rmc-cropper-wrapper__spinner', loading && 'rmc-cropper-wrapper__spinner--visible', spinnerClassName) }))); }; var Cropper = React.forwardRef(function (props, ref) { var className = props.className, spinnerClassName = props.spinnerClassName, _a = props.navigation, navigation = _a === void 0 ? true : _a, _b = props.stencilProps, stencilProps = _b === void 0 ? {} : _b, _c = props.navigationProps, navigationProps = _c === void 0 ? {} : _c, wrapperComponent = props.wrapperComponent, _d = props.imageRestriction, imageRestriction = _d === void 0 ? reactAdvancedCropper.ImageRestriction.stencil : _d, cropperProps = tslib.__rest(props, ["className", "spinnerClassName", "navigation", "stencilProps", "navigationProps", "wrapperComponent", "imageRestriction"]); var cropperRef = React.useRef(null); var WrapperComponent = wrapperComponent || CropperWrapper; return (React__default["default"].createElement(reactAdvancedCropper.Cropper, tslib.__assign({}, cropperProps, { ref: reactAdvancedCropper.mergeRefs([ref, cropperRef]), stencilConstraints: mobile.stencilConstraints, stencilProps: tslib.__assign(tslib.__assign({ grid: true }, stencilProps), { movable: false }), wrapperComponent: WrapperComponent, wrapperProps: { navigationProps: navigationProps, navigation: navigation, spinnerClassName: spinnerClassName, }, imageRestriction: reactAdvancedCropper.ImageRestriction.none, className: cn__default["default"]('rmc-cropper', className), defaultSize: mobile.defaultSize, transformImageAlgorithm: mobile.transformImage, transitions: true, postProcess: imageRestriction === reactAdvancedCropper.ImageRestriction.none ? mobile.zoomStencil : [mobile.fitStencilToImage, mobile.zoomStencil], resizeCoordinatesAlgorithm: imageRestriction === reactAdvancedCropper.ImageRestriction.none ? undefined : mobile.resizeCoordinates }))); }); Cropper.displayName = 'Cropper'; Object.defineProperty(exports, 'CircleStencil', { enumerable: true, get: function () { return reactAdvancedCropper.CircleStencil; } }); Object.defineProperty(exports, 'RectangleStencil', { enumerable: true, get: function () { return reactAdvancedCropper.RectangleStencil; } }); exports.Cropper = Cropper; exports.Navigation = Navigation; exports.RotateComponent = RotateComponent; //# sourceMappingURL=index.cjs.js.map