@onesy/ui-react
Version:
UI for React
1,076 lines (1,019 loc) • 44.7 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
import _defineProperty from "@babel/runtime/helpers/defineProperty";
const _excluded = ["image", "minWidth", "minHeight", "maxWidth", "maxHeight", "selectorDefault", "selector", "onSelectorChange", "type", "quality", "aspectRatio", "gridLines", "dynamicParent", "onFocus", "onBlur", "TooltipProps", "Component", "className"];
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
import React from 'react';
import { is, clamp, isEnvironment } from '@onesy/utils';
import { classNames, style as styleMethod, useOnesyTheme } from '@onesy/style-react';
import TooltipElement from '../Tooltip';
import { staticClassName, image as imageMethod } from '../utils';
const useStyle = styleMethod(theme => {
const dot = {
display: 'inline-block',
position: 'absolute',
width: '6px',
height: '6px',
borderRadius: '50%',
background: '#a4a4a4',
outline: '1px solid white'
};
return {
root: {
width: '100%',
minHeight: '1px',
lineHeight: '0',
userSelect: 'none',
overflow: 'hidden'
},
mouseDown_move: {
'& *': {
cursor: 'grab !important'
}
},
mouseDown_top: {
'& *': {
cursor: 'ns-resize !important'
}
},
mouseDown_left: {
'& *': {
cursor: 'ew-resize !important'
}
},
mouseDown_right: {
'& *': {
cursor: 'ew-resize !important'
}
},
mouseDown_bottom: {
'& *': {
cursor: 'ns-resize !important'
}
},
mouseDown_top_left: {
'& *': {
cursor: 'nwse-resize !important'
}
},
mouseDown_top_right: {
'& *': {
cursor: 'nesw-resize !important'
}
},
mouseDown_bottom_left: {
'& *': {
cursor: 'nesw-resize !important'
}
},
mouseDown_bottom_right: {
'& *': {
cursor: 'nwse-resize !important'
}
},
canvas: {
position: 'absolute',
zIndex: '0'
},
canvas_main: {
position: 'relative',
width: '100%',
height: 'auto'
},
canvas_imageSelector: {
zIndex: -1
},
background: {
position: 'absolute',
inset: '0',
width: '100%',
height: '100%',
opacity: '0',
background: theme.methods.palette.color.colorToRgb(theme.palette.text.default.primary, 44),
transition: theme.methods.transitions.make('opacity', {
duration: 'xxs'
}),
zIndex: '1'
},
background_in: {
opacity: '1'
},
imageSelector_main: {
position: 'absolute',
top: '0',
left: '0',
width: '0',
height: '0',
outline: '2px dashed white',
background: 'transparent',
touchAction: 'none',
opacity: '0',
zIndex: '14',
userSelect: 'none',
transition: theme.methods.transitions.make('opacity')
},
imageSelector_main_in: {
opacity: '1'
},
imageSelector: {
position: 'absolute',
top: '0',
left: '0',
width: '0',
height: '0',
touchAction: 'none',
overflow: 'hidden',
userSelect: 'none',
zIndex: '11'
},
move: {
position: 'absolute',
inset: '0',
width: '100%',
height: '100%',
cursor: 'grab',
'&:active': {
cursor: 'grabbing !important'
}
},
grid_line: {
position: 'absolute',
background: 'white',
mixBlendMode: 'difference'
},
grid_line_top_start: {
top: '33.3333%',
insetInline: '0',
width: '100%',
height: '1px'
},
grid_line_top_end: {
top: '66.6666%',
insetInline: '0',
width: '100%',
height: '1px'
},
grid_line_left_start: {
left: '33.3333%',
insetBlock: '0',
width: '1px',
height: '100%'
},
grid_line_left_end: {
left: '66.6666%',
insetBlock: '0',
width: '1px',
height: '100%'
},
dot: _objectSpread({}, dot),
dot_top_left: {
top: '-1px',
left: '-1px',
transform: 'translate(-50%, -50%)',
cursor: 'nwse-resize'
},
dot_top_right: {
top: '-1px',
right: '-1px',
transform: 'translate(50%, -50%)',
cursor: 'nesw-resize'
},
dot_bottom_left: {
bottom: '-1px',
left: '-1px',
transform: 'translate(-50%, 50%)',
cursor: 'nesw-resize'
},
dot_bottom_right: {
bottom: '-1px',
right: '-1px',
transform: 'translate(50%, 50%)',
cursor: 'nwse-resize'
},
border: {
position: 'absolute'
},
border_top: {
top: '-2px',
height: '2px',
width: '100%',
cursor: 'ns-resize',
'&::before': _objectSpread(_objectSpread({}, dot), {}, {
content: '""',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)'
})
},
border_left: {
left: '-2px',
height: '100%',
width: '2px',
cursor: 'ew-resize',
'&::before': _objectSpread(_objectSpread({}, dot), {}, {
content: '""',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)'
})
},
border_right: {
right: '-2px',
height: '100%',
width: '2px',
cursor: 'ew-resize',
'&::before': _objectSpread(_objectSpread({}, dot), {}, {
content: '""',
top: '50%',
right: '50%',
transform: 'translate(50%, -50%)'
})
},
border_bottom: {
bottom: '-2px',
height: '2px',
width: '100%',
cursor: 'ns-resize',
'&::before': _objectSpread(_objectSpread({}, dot), {}, {
content: '""',
bottom: '50%',
left: '50%',
transform: 'translate(-50%, 50%)'
})
}
};
}, {
name: 'onesy-ImageCrop'
});
const ImageCrop = /*#__PURE__*/React.forwardRef((props_, ref) => {
const theme = useOnesyTheme();
const props = React.useMemo(() => _objectSpread(_objectSpread(_objectSpread({}, theme?.ui?.elements?.all?.props?.default), theme?.ui?.elements?.onesyImageCrop?.props?.default), props_), [props_]);
const Tooltip = React.useMemo(() => theme?.elements?.Tooltip || TooltipElement, [theme]);
const {
// url, datauri or canvas
image: image_,
minWidth,
minHeight,
maxWidth,
maxHeight,
selectorDefault,
selector: selector_,
onSelectorChange: onSelectorChange_,
type = `image/jpeg`,
quality = 1,
aspectRatio,
gridLines,
dynamicParent,
onFocus: onFocus_,
onBlur: onBlur_,
TooltipProps,
Component = 'div',
className
} = props,
other = _objectWithoutProperties(props, _excluded);
const {
classes
} = useStyle();
const [image, setImage] = React.useState();
const [focus, setFocus] = React.useState();
const [mouseDown, setMouseDown] = React.useState();
const [selector, setSelector] = React.useState(selectorDefault !== undefined ? selectorDefault : selector_);
const [selectorRelative, setSelectorRelative] = React.useState();
const refs = {
root: React.useRef(null),
image: React.useRef(null),
mouseDown: React.useRef(null),
selector: React.useRef(null),
imageSelectorMain: React.useRef(null),
imageSelector: React.useRef(null),
previousMouseEvent: React.useRef(null),
canvasMain: React.useRef(null),
canvasImageSelector: React.useRef(null),
move: React.useRef(null),
borderTop: React.useRef(null),
borderLeft: React.useRef(null),
borderRight: React.useRef(null),
borderBottom: React.useRef(null),
dotTopLeft: React.useRef(null),
dotTopRight: React.useRef(null),
dotBottomLeft: React.useRef(null),
dotBottomRight: React.useRef(null),
props: React.useRef(null),
dynamicParent: React.useRef(null),
focus: React.useRef(null),
aspectRatio: React.useRef(null)
};
refs.image.current = image;
refs.mouseDown.current = mouseDown;
refs.selector.current = selector;
refs.props.current = props;
refs.focus.current = focus;
refs.dynamicParent.current = dynamicParent;
refs.aspectRatio.current = aspectRatio;
const onSelectorChange = valueNew => {
// min, max for width, height
// + resolve it to max width and height for aspect ratio
if (is('object', valueNew) && !!Object.keys(valueNew).length && refs.root.current) {
const rootRect = refs.root.current?.getBoundingClientRect();
const minWidth_ = refs.props.current.minWidth !== undefined ? refs.props.current.minWidth : Number.MIN_SAFE_INTEGER;
const minHeight_ = refs.props.current.minHeight !== undefined ? refs.props.current.minHeight : Number.MIN_SAFE_INTEGER;
const maxWidth_ = refs.props.current.maxWidth !== undefined ? refs.props.current.maxWidth : Number.MAX_SAFE_INTEGER;
const maxHeight_ = refs.props.current.maxHeight !== undefined ? refs.props.current.maxHeight : Number.MAX_SAFE_INTEGER;
valueNew.width = clamp(valueNew.width, minWidth_, maxWidth_);
valueNew.height = clamp(valueNew.height, minHeight_, maxHeight_);
if (refs.aspectRatio.current !== undefined) {
if (valueNew.width + valueNew.width / refs.aspectRatio.current >= valueNew.height + valueNew.height * refs.aspectRatio.current) {
valueNew.height = valueNew.width / refs.aspectRatio.current;
} else {
valueNew.width = valueNew.height * refs.aspectRatio.current;
}
// Max width
if (valueNew.left + valueNew.width > rootRect.width) {
valueNew.width = rootRect.width - valueNew.left;
valueNew.height = valueNew.width / refs.aspectRatio.current;
}
// Max height
if (valueNew.top + valueNew.height > rootRect.height) {
valueNew.height = rootRect.height - valueNew.top;
valueNew.width = valueNew.height * refs.aspectRatio.current;
}
// Max width, height per maxWidth and maxHeight
if (valueNew.width < minWidth_ || valueNew.width > maxWidth_) {
valueNew.width = clamp(valueNew.width, minWidth_, maxWidth_);
valueNew.height = valueNew.width / refs.aspectRatio.current;
}
if (valueNew.height < minHeight_ || valueNew.height > maxHeight_) {
valueNew.height = clamp(valueNew.height, minHeight_, maxHeight_);
valueNew.width = valueNew.height / refs.aspectRatio.current;
}
}
// If previous values are within maxWidth and/or maxHeight
// and left or top are not same as before
// return
if (!['move'].includes(refs.mouseDown.current?.version)) {
if (maxWidth_ !== undefined || maxHeight_ !== undefined) {
if ((valueNew.top < refs.selector.current?.top || valueNew.left < refs.selector.current?.left) && (refs.selector.current?.width === maxWidth_ || refs.selector.current?.height === maxHeight_)) return;
}
}
}
const rootRect_ = refs.root.current.getBoundingClientRect();
const selectorRelative_ = {
top: valueNew.top / rootRect_?.height * refs.canvasMain.current?.height,
left: valueNew.left / rootRect_?.width * refs.canvasMain.current?.width,
width: valueNew.width / rootRect_?.width * refs.canvasMain.current?.width,
height: valueNew.height / rootRect_?.height * refs.canvasMain.current?.height
};
// Update inner or controlled
if (!props.hasOwnProperty('selector')) {
setSelector(valueNew);
setSelectorRelative(selectorRelative_);
}
if (is('function', onSelectorChange_)) onSelectorChange_(selectorRelative_);
};
React.useEffect(() => {
const method = event => {
switch (event.key) {
case 'Escape':
if (refs.focus.current) setSelector({});
break;
default:
break;
}
};
const onMouseUp = event => {
setMouseDown(false);
refs.previousMouseEvent.current = undefined;
};
// Move
const onMove = (x, y) => {
if (refs.mouseDown.current && refs.previousMouseEvent.current) {
const {
top: previousTop,
left: previousLeft
} = refs.mouseDown.current;
const rootRect = refs.root.current.getBoundingClientRect();
const selectorRect_ = refs.imageSelectorMain.current.getBoundingClientRect();
const selectorRect = {};
// Normalize relative to root
selectorRect.width = selectorRect_.width;
selectorRect.height = selectorRect_.height;
selectorRect.top = selectorRect_.top - rootRect.top;
selectorRect.left = selectorRect_.left - rootRect.left;
selectorRect.right = selectorRect.left + selectorRect_.width;
selectorRect.bottom = selectorRect.top + selectorRect_.height;
if (refs.mouseDown.current?.version === 'make') {
const top_ = clamp(y - rootRect.top, 0, rootRect.height);
const left_ = clamp(x - rootRect.left, 0, rootRect.width);
let top = clamp(top_, 0, previousTop);
let left = clamp(left_, 0, previousLeft);
let width = Math.abs(left_ - previousLeft);
let height = Math.abs(top_ - previousTop);
if (refs.aspectRatio.current !== undefined) {
if (left < previousLeft) {
if (refs.selector.current?.left < previousLeft && left < refs.selector.current?.left && (top <= 0 || refs.selector.current?.top + refs.selector.current?.height >= rootRect.height)) return;
}
if (top < previousTop) {
if (refs.selector.current?.top < previousTop && top < refs.selector.current?.top && (left <= 0 || refs.selector.current?.left + refs.selector.current?.width >= rootRect.width)) return;
}
// Max surface
if (width + width / refs.aspectRatio.current >= height + height * refs.aspectRatio.current) {
height = width / refs.aspectRatio.current;
} else {
width = height * refs.aspectRatio.current;
}
// Moved left
if (left < previousLeft) {
left = clamp(previousLeft - width, 0, previousLeft);
// Update width, height upto the previousLeft
width = clamp(width, 0, previousLeft);
height = width / refs.aspectRatio.current;
}
// Moved top
if (top < previousTop) {
top = clamp(previousTop - height, 0, previousTop);
// Update width, height upto the previousTop
height = clamp(height, 0, previousTop);
width = height * refs.aspectRatio.current;
}
// Max width
if (left + width > rootRect.width) {
width = rootRect.width - left;
height = width / refs.aspectRatio.current;
}
// Max height
if (top + height > rootRect.height) {
height = rootRect.height - top;
width = height * refs.aspectRatio.current;
}
// Min left
if (left < previousLeft) left = previousLeft - width;
// Min top
if (top < previousTop) top = previousTop - height;
}
onSelectorChange(_objectSpread(_objectSpread({}, refs.selector.current), {}, {
top,
left,
width,
height
}));
} else if (refs.mouseDown.current?.version === 'move') {
const top = y - refs.previousMouseEvent.current.clientY;
const left = x - refs.previousMouseEvent.current.clientX;
onSelectorChange(_objectSpread(_objectSpread({}, refs.selector.current), {}, {
top: clamp(refs.selector.current.top + top, 0, rootRect.height - selectorRect.height),
left: clamp(refs.selector.current.left + left, 0, rootRect.width - selectorRect.width)
}));
} else if (refs.mouseDown.current?.version === 'top_left') {
const incY = y - refs.previousMouseEvent.current.clientY;
const incX = x - refs.previousMouseEvent.current.clientX;
let top = clamp(selectorRect.top + incY, 0);
let left = clamp(selectorRect.left + incX, 0);
if (selectorRect.bottom - top < 0 && selectorRect.right - left < 0) refs.mouseDown.current.version = 'bottom_right';else if (selectorRect.bottom - top < 0) refs.mouseDown.current.version = 'bottom_left';else if (selectorRect.right - left < 0) refs.mouseDown.current.version = 'top_right';
let width = clamp(selectorRect.right - left, 0);
let height = clamp(selectorRect.bottom - top, 0);
if (refs.aspectRatio.current !== undefined) {
// Left
if (left < refs.selector.current.left && refs.selector.current.left < previousLeft && refs.selector.current?.top === 0) return;
// Max surface
if (width + width / refs.aspectRatio.current >= height + height * refs.aspectRatio.current) {
height = width / refs.aspectRatio.current;
} else {
width = height * refs.aspectRatio.current;
}
// Moved left
if (left < previousLeft) {
left = clamp(previousLeft - width, 0, previousLeft);
// Update width, height upto the previousLeft
width = clamp(width, 0, previousLeft);
height = width / refs.aspectRatio.current;
}
// Moved top
if (top < previousTop) {
top = clamp(previousTop - height, 0, previousTop);
// Update width, height upto the previousTop
height = clamp(height, 0, previousTop);
width = height * refs.aspectRatio.current;
}
// Max width
if (left + width > rootRect.width) {
width = rootRect.width - left;
height = width / refs.aspectRatio.current;
}
// Max height
if (top + height > rootRect.height) {
height = rootRect.height - top;
width = height * refs.aspectRatio.current;
}
// Min left
if (left < previousLeft) left = previousLeft - width;
// Min top
if (top < previousTop) top = previousTop - height;
}
onSelectorChange(_objectSpread(_objectSpread({}, refs.selector.current), {}, {
top,
left,
width,
height
}));
} else if (refs.mouseDown.current?.version === 'top_right') {
const incY = y - refs.previousMouseEvent.current.clientY;
const incX = x - refs.previousMouseEvent.current.clientX;
const top = clamp(selectorRect.top + incY, 0);
if (selectorRect.bottom - top < 0 && selectorRect.width + incX < 0) refs.mouseDown.current.version = 'bottom_left';else if (selectorRect.bottom - top < 0) refs.mouseDown.current.version = 'bottom_right';else if (selectorRect.width + incX < 0) refs.mouseDown.current.version = 'top_left';
let width = clamp(Math.abs(selectorRect.width + incX), 0, rootRect.width - selectorRect.left);
let height = clamp(selectorRect.bottom - top, 0);
// Top
if (refs.aspectRatio.current !== undefined) {
// Top
if (top < refs.selector.current.top && refs.selector.current.top < previousTop && refs.selector.current.left + refs.selector.current.width >= rootRect.width) return;
width = height * refs.aspectRatio.current;
height = width / refs.aspectRatio.current;
// Max width
if (refs.selector.current.left + width > rootRect.width) {
width = rootRect.width - refs.selector.current.left;
height = width / refs.aspectRatio.current;
}
// Max height
if (refs.selector.current.top + height > rootRect.height) {
height = rootRect.height - refs.selector.current.top;
width = height * refs.aspectRatio.current;
}
}
onSelectorChange(_objectSpread(_objectSpread({}, refs.selector.current), {}, {
top,
width,
height
}));
} else if (refs.mouseDown.current?.version === 'bottom_right') {
const incY = y - refs.previousMouseEvent.current.clientY;
const incX = x - refs.previousMouseEvent.current.clientX;
if (selectorRect.height + incY < 0 && selectorRect.width + incX < 0) refs.mouseDown.current.version = 'top_left';else if (selectorRect.height + incY < 0) refs.mouseDown.current.version = 'top_right';else if (selectorRect.width + incX < 0) refs.mouseDown.current.version = 'bottom_left';
let width = clamp(Math.abs(selectorRect.width + incX), 0, rootRect.width - selectorRect.left);
let height = clamp(Math.abs(selectorRect.height + incY), 0, rootRect.height - selectorRect.top);
// Right
if (refs.aspectRatio.current !== undefined) {
height = width / refs.aspectRatio.current;
// Max width
if (refs.selector.current.left + width > rootRect.width) {
width = rootRect.width - refs.selector.current.left;
height = width / refs.aspectRatio.current;
}
// Max height
if (refs.selector.current.top + height > rootRect.height) {
height = rootRect.height - refs.selector.current.top;
width = height * refs.aspectRatio.current;
}
width = height * refs.aspectRatio.current;
// Max width
if (refs.selector.current.left + width > rootRect.width) {
width = rootRect.width - refs.selector.current.left;
height = width / refs.aspectRatio.current;
}
// Max height
if (refs.selector.current.top + height > rootRect.height) {
height = rootRect.height - refs.selector.current.top;
width = height * refs.aspectRatio.current;
}
}
onSelectorChange(_objectSpread(_objectSpread({}, refs.selector.current), {}, {
width,
height
}));
} else if (refs.mouseDown.current?.version === 'bottom_left') {
const incY = y - refs.previousMouseEvent.current.clientY;
const incX = x - refs.previousMouseEvent.current.clientX;
const left = clamp(selectorRect.left + incX, 0);
if (selectorRect.height + incY < 0 && selectorRect.right - left < 0) refs.mouseDown.current.version = 'top_right';else if (selectorRect.height + incY < 0) refs.mouseDown.current.version = 'top_left';else if (selectorRect.right - left < 0) refs.mouseDown.current.version = 'bottom_right';
let width = clamp(selectorRect.right - left, 0);
let height = clamp(Math.abs(selectorRect.height + incY), 0, rootRect.height - selectorRect.top);
// Left
if (refs.aspectRatio.current !== undefined) {
// Left
if (left < refs.selector.current.left && refs.selector.current?.top + refs.selector.current?.height >= rootRect.height) return;
height = width / refs.aspectRatio.current;
// Max width
if (refs.selector.current.left + width > rootRect.width) {
width = rootRect.width - refs.selector.current.left;
height = width / refs.aspectRatio.current;
}
// Max height
if (refs.selector.current.top + height > rootRect.height) {
height = rootRect.height - refs.selector.current.top;
width = height * refs.aspectRatio.current;
}
width = height * refs.aspectRatio.current;
// Max width
if (refs.selector.current.left + width > rootRect.width) {
width = rootRect.width - refs.selector.current.left;
height = width / refs.aspectRatio.current;
}
// Max height
if (refs.selector.current.top + height > rootRect.height) {
height = rootRect.height - refs.selector.current.top;
width = height * refs.aspectRatio.current;
}
}
onSelectorChange(_objectSpread(_objectSpread({}, refs.selector.current), {}, {
left,
width,
height
}));
} else if (refs.mouseDown.current?.version === 'top') {
const inc = y - refs.previousMouseEvent.current.clientY;
const top = clamp(refs.selector.current.top + inc, 0);
if (refs.selector.current.top <= 0 && top <= 0) return;
if (selectorRect.bottom - top < 0) refs.mouseDown.current.version = 'bottom';
let width = refs.selector.current.width;
let height = clamp(Math.abs(refs.selector.current.height - inc), 0, previousTop - top);
if (refs.aspectRatio.current !== undefined) {
// Top
if (top < refs.selector.current.top && refs.selector.current.top < previousTop && refs.selector.current.left + refs.selector.current.width >= rootRect.width) return;
width = height * refs.aspectRatio.current;
// Max width
if (refs.selector.current.left + width > rootRect.width) {
width = rootRect.width - refs.selector.current.left;
height = width / refs.aspectRatio.current;
}
// Max height
if (top + height > rootRect.height) {
height = rootRect.height - top;
width = height * refs.aspectRatio.current;
}
}
onSelectorChange(_objectSpread(_objectSpread({}, refs.selector.current), {}, {
top,
width,
height
}));
} else if (refs.mouseDown.current?.version === 'bottom') {
const inc = y - refs.previousMouseEvent.current.clientY;
if (selectorRect.height + inc < 0) refs.mouseDown.current.version = 'top';
let width = refs.selector.current.width;
let height = clamp(Math.abs(selectorRect.height + inc), 0, rootRect.height - refs.selector.current.top);
if (refs.aspectRatio.current !== undefined) {
width = height * refs.aspectRatio.current;
// Max height
if (refs.selector.current.top + height > rootRect.height) {
height = rootRect.height - refs.selector.current.top;
width = height * refs.aspectRatio.current;
}
// Max width
if (refs.selector.current.left + width > rootRect.width) {
width = rootRect.width - refs.selector.current.left;
height = width / refs.aspectRatio.current;
}
}
onSelectorChange(_objectSpread(_objectSpread({}, refs.selector.current), {}, {
width,
height
}));
} else if (refs.mouseDown.current?.version === 'left') {
const inc = x - refs.previousMouseEvent.current.clientX;
const left = clamp(selectorRect.left + inc, 0);
if (selectorRect.right - left < 0) refs.mouseDown.current.version = 'right';
let width = clamp(selectorRect.right - left, 0);
let height = refs.selector.current.height;
if (refs.aspectRatio.current !== undefined) {
if (left < refs.selector.current.left && refs.selector.current?.top + refs.selector.current?.height >= rootRect.height) return;
height = width / refs.aspectRatio.current;
// Max width
if (refs.selector.current.left + width > rootRect.width) {
width = rootRect.width - refs.selector.current.left;
height = width / refs.aspectRatio.current;
}
// Max height
if (refs.selector.current.top + height > rootRect.height) {
height = rootRect.height - refs.selector.current.top;
width = height * refs.aspectRatio.current;
}
}
onSelectorChange(_objectSpread(_objectSpread({}, refs.selector.current), {}, {
left,
width,
height
}));
} else if (refs.mouseDown.current?.version === 'right') {
const inc = x - refs.previousMouseEvent.current.clientX;
if (selectorRect.width + inc < 0) refs.mouseDown.current.version = 'left';
let width = clamp(Math.abs(selectorRect.width + inc), 0, rootRect.width - selectorRect.left);
let height = refs.selector.current.height;
if (refs.aspectRatio.current !== undefined) {
height = width / refs.aspectRatio.current;
// Max width
if (refs.selector.current.left + width > rootRect.width) {
width = rootRect.width - refs.selector.current.left;
height = width / refs.aspectRatio.current;
}
// Max height
if (refs.selector.current.top + height > rootRect.height) {
height = rootRect.height - refs.selector.current.top;
width = height * refs.aspectRatio.current;
}
}
onSelectorChange(_objectSpread(_objectSpread({}, refs.selector.current), {}, {
width,
height
}));
}
}
};
// Mouse move
const onMouseMove = event => {
if (refs.mouseDown.current) {
const {
clientY,
clientX
} = event;
onMove(clientX, clientY);
refs.previousMouseEvent.current = event;
}
};
// Touch move
const onTouchMove = event => {
if (refs.mouseDown.current) {
const {
clientY,
clientX
} = event.touches[0];
onMove(clientX, clientY);
refs.previousMouseEvent.current = event;
// Normalize for use as a mouseDown value
refs.previousMouseEvent.current.clientY = clientY;
refs.previousMouseEvent.current.clientX = clientX;
}
};
const rootDocument = isEnvironment('browser') ? refs.root.current?.ownerDocument || window.document : undefined;
rootDocument.addEventListener('keydown', method);
rootDocument.addEventListener('mousemove', onMouseMove);
rootDocument.addEventListener('mouseup', onMouseUp);
rootDocument.addEventListener('touchmove', onTouchMove, {
passive: true
});
rootDocument.addEventListener('touchend', onMouseUp);
return () => {
// Clean up
rootDocument.removeEventListener('keydown', method);
rootDocument.removeEventListener('mousemove', onMouseMove);
rootDocument.removeEventListener('mouseup', onMouseUp);
rootDocument.removeEventListener('touchmove', onTouchMove);
rootDocument.removeEventListener('touchend', onMouseUp);
if (refs.image.current) {
setImage('');
if (rootDocument.body.style.overflow === 'hidden') rootDocument.body.style.removeProperty('overflow');
}
};
}, []);
React.useEffect(() => {
if (image_ !== image) {
if (image_ instanceof HTMLCanvasElement) setImage(image_);else if (is('string', image_)) !refs.dynamicParent.current ? makeImage(image_) : setTimeout(() => makeImage(image_), 140);
}
}, [image_]);
const updateSelector = function () {
let selector__ = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : refs.selector.current;
let image__ = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : refs.image.current;
if (selector__ !== undefined && image__ !== undefined) {
const rootRect = refs.root.current.getBoundingClientRect();
const selectorValue = {
top: clamp(selector__.top, 0, image__.height),
left: clamp(selector__.left, 0, image__.height)
};
selectorValue.width = clamp(selector__.width || 0, 0, rootRect.width - selectorValue.left);
selectorValue.height = clamp(selector__.height || 0, 0, rootRect.height - selectorValue.top);
// Aspect ratio
if (refs.aspectRatio.current !== undefined) {
// Max surface
if (selectorValue.width + selectorValue.width / refs.aspectRatio.current >= selectorValue.height + selectorValue.height * refs.aspectRatio.current) {
selectorValue.height = selectorValue.width / refs.aspectRatio.current;
} else {
selectorValue.width = selectorValue.height * refs.aspectRatio.current;
}
// Max width
if (selectorValue.left + selectorValue.width > rootRect.width) {
selectorValue.width = rootRect.width - selectorValue.left;
selectorValue.height = selectorValue.width / refs.aspectRatio.current;
}
// Max height
if (selectorValue.top + selectorValue.height > rootRect.height) {
selectorValue.height = rootRect.height - selectorValue.top;
selectorValue.width = selectorValue.height * refs.aspectRatio.current;
}
}
// Update selector
setSelector(selectorValue);
// Update selector relative
setSelectorRelative({
top: selectorValue.top / rootRect?.height * refs.canvasMain.current?.height,
left: selectorValue.left / rootRect?.width * refs.canvasMain.current?.width,
width: selectorValue.width / rootRect?.width * refs.canvasMain.current?.width,
height: selectorValue.height / rootRect?.height * refs.canvasMain.current?.height
});
}
};
React.useEffect(() => {
updateSelector();
}, [aspectRatio]);
React.useEffect(() => {
if (selector_ !== selector) updateSelector(selector_);
}, [selector_]);
React.useEffect(() => {
if (image) {
refs.canvasMain.current.width = image.width;
refs.canvasMain.current.height = image.height;
refs.canvasMain.current.getContext('2d').drawImage(image, 0, 0), image.width, image.height;
refs.canvasImageSelector.current.width = image.width;
refs.canvasImageSelector.current.height = image.height;
refs.canvasImageSelector.current.getContext('2d').drawImage(image, 0, 0), image.width, image.height;
// Update selector
updateSelector();
}
}, [image]);
const makeImage = async function () {
let value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : image;
const img = await imageMethod(value);
const rootDocument = isEnvironment('browser') ? refs.root.current?.ownerDocument || window.document : undefined;
const canvas = rootDocument.createElement('canvas');
const rootRect = refs.root.current.getBoundingClientRect();
const aspectRatioImg = img.width / img.height;
// width being parent width
img.width = rootRect.width;
// height keep aspect ratio of the img for the height
img.height = img.width / aspectRatioImg;
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height);
setImage(canvas);
};
const onFocus = React.useCallback(event => {
setFocus(true);
if (is('function', onFocus_)) onFocus_(event);
}, []);
const onBlur = React.useCallback(event => {
setFocus(false);
if (is('function', onBlur_)) onBlur_(event);
}, []);
const onTouchStart = React.useCallback(event => {
if (![refs.imageSelectorMain.current, refs.imageSelector.current, refs.move.current, refs.borderTop.current, refs.borderLeft.current, refs.borderRight.current, refs.borderBottom.current, refs.dotTopLeft.current, refs.dotTopRight.current, refs.dotBottomLeft.current, refs.dotBottomRight.current].includes(event.target)) {
const {
clientY,
clientX
} = event.touches[0];
const rootRect = refs.root.current.getBoundingClientRect();
setMouseDown({
version: 'make',
top: clientY - rootRect.top,
left: clientX - rootRect.left
});
}
}, []);
const onMouseDown = React.useCallback(event => {
if (![refs.imageSelectorMain.current, refs.imageSelector.current, refs.move.current, refs.borderTop.current, refs.borderLeft.current, refs.borderRight.current, refs.borderBottom.current, refs.dotTopLeft.current, refs.dotTopRight.current, refs.dotBottomLeft.current, refs.dotBottomRight.current].includes(event.target)) {
const {
clientY,
clientX
} = event;
const rootRect = refs.root.current.getBoundingClientRect();
setMouseDown({
version: 'make',
top: clientY - rootRect.top,
left: clientX - rootRect.left
});
}
}, []);
const onTouchStartSelector = React.useCallback(event => {
const {
clientY,
clientX
} = event.touches[0];
const rootRect = refs.root.current.getBoundingClientRect();
setMouseDown({
version: 'move',
top: clientY - rootRect.top,
left: clientX - rootRect.left
});
}, []);
const onMouseDownSelector = React.useCallback(event => {
const {
clientY,
clientX
} = event;
const rootRect = refs.root.current.getBoundingClientRect();
setMouseDown({
version: 'move',
top: clientY - rootRect.top,
left: clientX - rootRect.left
});
}, []);
const onTouchStartBorder = version => event => {
setMouseDown({
version,
top: refs.selector.current?.top + refs.selector.current?.height,
left: refs.selector.current?.left + refs.selector.current?.width
});
};
const onMouseDownBorder = version => event => {
setMouseDown({
version,
top: refs.selector.current?.top + refs.selector.current?.height,
left: refs.selector.current?.left + refs.selector.current?.width
});
};
const rect = refs.root.current?.getBoundingClientRect();
return /*#__PURE__*/React.createElement(Component, _extends({
ref: item => {
if (ref) {
if (is('function', ref)) ref(item);else ref.current = item;
}
refs.root.current = item;
},
tabIndex: 0,
onFocus: onFocus,
onBlur: onBlur,
onTouchStart: onTouchStart,
onMouseDown: onMouseDown,
className: classNames([staticClassName('ImageCrop', theme) && ['onesy-ImageCrop-root'], className, classes.root])
}, other), /*#__PURE__*/React.createElement("canvas", {
ref: refs.canvasMain,
className: classNames([staticClassName('ImageCrop', theme) && ['onesy-ImageCrop-canvas', 'onesy-ImageCrop-canvas-main'], classes.canvas, classes.canvas_main])
}), /*#__PURE__*/React.createElement("div", {
className: classNames([staticClassName('ImageCrop', theme) && ['onesy-ImageCrop-background'], classes.background, image && classes.background_in])
}), /*#__PURE__*/React.createElement(Tooltip, _extends({
open: mouseDown && selector?.width + selector?.height > 0,
label: `${Math.round(selectorRelative?.width || 0)} x ${Math.round(selectorRelative?.height || 0)}`,
position: "bottom"
}, TooltipProps), /*#__PURE__*/React.createElement("div", {
ref: refs.imageSelectorMain,
className: classNames([staticClassName('ImageCrop', theme) && ['onesy-ImageCrop-image-selector-main'], classes.imageSelector_main, selector && classes.imageSelector_main_in]),
style: _objectSpread({}, selector)
}, /*#__PURE__*/React.createElement("div", {
ref: refs.move,
onTouchStart: onTouchStartSelector,
onMouseDown: onMouseDownSelector,
className: classNames([staticClassName('ImageCrop', theme) && ['onesy-ImageCrop-move'], classes.move])
}), gridLines && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
className: classNames([staticClassName('ImageCrop', theme) && ['onesy-ImageCrop-grid-line', 'onesy-ImageCrop-grid-line-top-start'], classes.grid_line, classes.grid_line_top_start])
}), /*#__PURE__*/React.createElement("div", {
className: classNames([staticClassName('ImageCrop', theme) && ['onesy-ImageCrop-grid-line', 'onesy-ImageCrop-grid-line-top-end'], classes.grid_line, classes.grid_line_top_end])
}), /*#__PURE__*/React.createElement("div", {
className: classNames([staticClassName('ImageCrop', theme) && ['onesy-ImageCrop-grid-line', 'onesy-ImageCrop-grid-line-left-start'], classes.grid_line, classes.grid_line_left_start])
}), /*#__PURE__*/React.createElement("div", {
className: classNames([staticClassName('ImageCrop', theme) && ['onesy-ImageCrop-grid-line', 'onesy-ImageCrop-grid-line-left-end'], classes.grid_line, classes.grid_line_left_end])
})), /*#__PURE__*/React.createElement("div", {
ref: refs.dotTopLeft,
onTouchStart: onTouchStartBorder('top_left'),
onMouseDown: onMouseDownBorder('top_left'),
className: classNames([staticClassName('ImageCrop', theme) && ['onesy-ImageCrop-dot', 'onesy-ImageCrop-dot-top-left'], classes.dot, classes.dot_top_left])
}), /*#__PURE__*/React.createElement("div", {
ref: refs.dotTopRight,
onTouchStart: onTouchStartBorder('top_right'),
onMouseDown: onMouseDownBorder('top_right'),
className: classNames([staticClassName('ImageCrop', theme) && ['onesy-ImageCrop-dot', 'onesy-ImageCrop-dot-top-right'], classes.dot, classes.dot_top_right])
}), /*#__PURE__*/React.createElement("div", {
ref: refs.dotBottomLeft,
onTouchStart: onTouchStartBorder('bottom_left'),
onMouseDown: onMouseDownBorder('bottom_left'),
className: classNames([staticClassName('ImageCrop', theme) && ['onesy-ImageCrop-dot', 'onesy-ImageCrop-dot-bottom-left'], classes.dot, classes.dot_bottom_left])
}), /*#__PURE__*/React.createElement("div", {
ref: refs.dotBottomRight,
onTouchStart: onTouchStartBorder('bottom_right'),
onMouseDown: onMouseDownBorder('bottom_right'),
className: classNames([staticClassName('ImageCrop', theme) && ['onesy-ImageCrop-dot', 'onesy-ImageCrop-dot-bottom-right'], classes.dot, classes.dot_bottom_right])
}), /*#__PURE__*/React.createElement("div", {
ref: refs.borderTop,
onTouchStart: onTouchStartBorder('top'),
onMouseDown: onMouseDownBorder('top'),
className: classNames([staticClassName('ImageCrop', theme) && ['onesy-ImageCrop-border', 'onesy-ImageCrop-border-top'], classes.border, classes.border_top])
}), /*#__PURE__*/React.createElement("div", {
ref: refs.borderLeft,
onTouchStart: onTouchStartBorder('left'),
onMouseDown: onMouseDownBorder('left'),
className: classNames([staticClassName('ImageCrop', theme) && ['onesy-ImageCrop-border', 'onesy-ImageCrop-border-left'], classes.border, classes.border_left])
}), /*#__PURE__*/React.createElement("div", {
ref: refs.borderRight,
onTouchStart: onTouchStartBorder('right'),
onMouseDown: onMouseDownBorder('right'),
className: classNames([staticClassName('ImageCrop', theme) && ['onesy-ImageCrop-border', 'onesy-ImageCrop-border-right'], classes.border, classes.border_right])
}), /*#__PURE__*/React.createElement("div", {
ref: refs.borderBottom,
onTouchStart: onTouchStartBorder('bottom'),
onMouseDown: onMouseDownBorder('bottom'),
className: classNames([staticClassName('ImageCrop', theme) && ['onesy-ImageCrop-border', 'onesy-ImageCrop-border-bottom'], classes.border, classes.border_bottom])
}))), /*#__PURE__*/React.createElement("div", {
ref: refs.imageSelector,
className: classNames([staticClassName('ImageCrop', theme) && ['onesy-ImageCrop-image-selector'], classes.imageSelector]),
style: _objectSpread({}, selector)
}, /*#__PURE__*/React.createElement("canvas", {
ref: refs.canvasImageSelector,
className: classNames([staticClassName('ImageCrop', theme) && ['onesy-ImageCrop-canvas', 'onesy-ImageCrop-canvas-image-selector'], classes.canvas, classes.canvas_imageSelector]),
width: image?.width || 0,
height: image?.height || 0,
style: {
top: `${(selector?.top || 0) * -1}px`,
left: `${(selector?.left || 0) * -1}px`,
width: rect?.width,
height: rect?.height
}
})));
});
ImageCrop.displayName = 'onesy-ImageCrop';
export default ImageCrop;