react-image-crop
Version:
A responsive image cropping tool for React
2 lines (1 loc) • 15.4 kB
JavaScript
(function(m,d){typeof exports=="object"&&typeof module<"u"?d(exports,require("react")):typeof define=="function"&&define.amd?define(["exports","react"],d):(m=typeof globalThis<"u"?globalThis:m||self,d(m.ReactCrop={},m.React))})(this,function(m,d){"use strict";var O=Object.defineProperty;var A=(m,d,v)=>d in m?O(m,d,{enumerable:!0,configurable:!0,writable:!0,value:v}):m[d]=v;var C=(m,d,v)=>A(m,typeof d!="symbol"?d+"":d,v);const v={x:0,y:0,width:0,height:0,unit:"px"},M=(o,a,e)=>Math.min(Math.max(o,a),e),_=(...o)=>o.filter(a=>a&&typeof a=="string").join(" "),S=(o,a)=>o===a||o.width===a.width&&o.height===a.height&&o.x===a.x&&o.y===a.y&&o.unit===a.unit;function H(o,a,e,n){const t=D(o,e,n);return o.width&&(t.height=t.width/a),o.height&&(t.width=t.height*a),t.y+t.height>n&&(t.height=n-t.y,t.width=t.height*a),t.x+t.width>e&&(t.width=e-t.x,t.height=t.width/a),o.unit==="%"?b(t,e,n):t}function I(o,a,e){const n=D(o,a,e);return n.x=(a-n.width)/2,n.y=(e-n.height)/2,o.unit==="%"?b(n,a,e):n}function b(o,a,e){return o.unit==="%"?{...v,...o,unit:"%"}:{unit:"%",x:o.x?o.x/a*100:0,y:o.y?o.y/e*100:0,width:o.width?o.width/a*100:0,height:o.height?o.height/e*100:0}}function D(o,a,e){return o.unit?o.unit==="px"?{...v,...o,unit:"px"}:{unit:"px",x:o.x?o.x*a/100:0,y:o.y?o.y*e/100:0,width:o.width?o.width*a/100:0,height:o.height?o.height*e/100:0}:{...v,...o,unit:"px"}}function k(o,a,e,n,t,c=0,r=0,h=n,g=t){const i={...o};let s=Math.min(c,n),w=Math.min(r,t),p=Math.min(h,n),u=Math.min(g,t);a&&(a>1?(s=r?r*a:s,w=s/a,p=h*a):(w=c?c/a:w,s=w*a,u=g/a)),i.y<0&&(i.height=Math.max(i.height+i.y,w),i.y=0),i.x<0&&(i.width=Math.max(i.width+i.x,s),i.x=0);const l=n-(i.x+i.width);l<0&&(i.x=Math.min(i.x,n-s),i.width+=l);const y=t-(i.y+i.height);if(y<0&&(i.y=Math.min(i.y,t-w),i.height+=y),i.width<s&&((e==="sw"||e=="nw")&&(i.x-=s-i.width),i.width=s),i.height<w&&((e==="nw"||e=="ne")&&(i.y-=w-i.height),i.height=w),i.width>p&&((e==="sw"||e=="nw")&&(i.x-=p-i.width),i.width=p),i.height>u&&((e==="nw"||e=="ne")&&(i.y-=u-i.height),i.height=u),a){const f=i.width/i.height;if(f<a){const E=Math.max(i.width/a,w);(e==="nw"||e=="ne")&&(i.y-=E-i.height),i.height=E}else if(f>a){const E=Math.max(i.height*a,s);(e==="sw"||e=="nw")&&(i.x-=E-i.width),i.width=E}}return i}function $(o,a,e,n){const t={...o};return a==="ArrowLeft"?n==="nw"?(t.x-=e,t.y-=e,t.width+=e,t.height+=e):n==="w"?(t.x-=e,t.width+=e):n==="sw"?(t.x-=e,t.width+=e,t.height+=e):n==="ne"?(t.y+=e,t.width-=e,t.height-=e):n==="e"?t.width-=e:n==="se"&&(t.width-=e,t.height-=e):a==="ArrowRight"&&(n==="nw"?(t.x+=e,t.y+=e,t.width-=e,t.height-=e):n==="w"?(t.x+=e,t.width-=e):n==="sw"?(t.x+=e,t.width-=e,t.height-=e):n==="ne"?(t.y-=e,t.width+=e,t.height+=e):n==="e"?t.width+=e:n==="se"&&(t.width+=e,t.height+=e)),a==="ArrowUp"?n==="nw"?(t.x-=e,t.y-=e,t.width+=e,t.height+=e):n==="n"?(t.y-=e,t.height+=e):n==="ne"?(t.y-=e,t.width+=e,t.height+=e):n==="sw"?(t.x+=e,t.width-=e,t.height-=e):n==="s"?t.height-=e:n==="se"&&(t.width-=e,t.height-=e):a==="ArrowDown"&&(n==="nw"?(t.x+=e,t.y+=e,t.width-=e,t.height-=e):n==="n"?(t.y+=e,t.height-=e):n==="ne"?(t.y+=e,t.width-=e,t.height-=e):n==="sw"?(t.x-=e,t.width+=e,t.height+=e):n==="s"?t.height+=e:n==="se"&&(t.width+=e,t.height+=e)),t}const P={capture:!0,passive:!1};let N=0;const x=class x extends d.PureComponent{constructor(){super(...arguments);C(this,"docMoveBound",!1);C(this,"mouseDownOnCrop",!1);C(this,"dragStarted",!1);C(this,"evData",{startClientX:0,startClientY:0,startCropX:0,startCropY:0,clientX:0,clientY:0,isResize:!0});C(this,"componentRef",d.createRef());C(this,"mediaRef",d.createRef());C(this,"resizeObserver");C(this,"initChangeCalled",!1);C(this,"instanceId",`rc-${N++}`);C(this,"state",{cropIsActive:!1,newCropIsBeingDrawn:!1});C(this,"onCropPointerDown",e=>{const{crop:n,disabled:t}=this.props,c=this.getBox();if(!n)return;const r=D(n,c.width,c.height);if(t)return;e.cancelable&&e.preventDefault(),this.bindDocMove(),this.componentRef.current.focus({preventScroll:!0});const h=e.target.dataset.ord,g=!!h;let i=e.clientX,s=e.clientY,w=r.x,p=r.y;if(h){const u=e.clientX-c.x,l=e.clientY-c.y;let y=0,f=0;h==="ne"||h=="e"?(y=u-(r.x+r.width),f=l-r.y,w=r.x,p=r.y+r.height):h==="se"||h==="s"?(y=u-(r.x+r.width),f=l-(r.y+r.height),w=r.x,p=r.y):h==="sw"||h=="w"?(y=u-r.x,f=l-(r.y+r.height),w=r.x+r.width,p=r.y):(h==="nw"||h=="n")&&(y=u-r.x,f=l-r.y,w=r.x+r.width,p=r.y+r.height),i=w+c.x+y,s=p+c.y+f}this.evData={startClientX:i,startClientY:s,startCropX:w,startCropY:p,clientX:e.clientX,clientY:e.clientY,isResize:g,ord:h},this.mouseDownOnCrop=!0,this.setState({cropIsActive:!0})});C(this,"onComponentPointerDown",e=>{const{crop:n,disabled:t,locked:c,keepSelection:r,onChange:h}=this.props,g=this.getBox();if(t||c||r&&n)return;e.cancelable&&e.preventDefault(),this.bindDocMove(),this.componentRef.current.focus({preventScroll:!0});const i=e.clientX-g.x,s=e.clientY-g.y,w={unit:"px",x:i,y:s,width:0,height:0};this.evData={startClientX:e.clientX,startClientY:e.clientY,startCropX:i,startCropY:s,clientX:e.clientX,clientY:e.clientY,isResize:!0},this.mouseDownOnCrop=!0,h(D(w,g.width,g.height),b(w,g.width,g.height)),this.setState({cropIsActive:!0,newCropIsBeingDrawn:!0})});C(this,"onDocPointerMove",e=>{const{crop:n,disabled:t,onChange:c,onDragStart:r}=this.props,h=this.getBox();if(t||!n||!this.mouseDownOnCrop)return;e.cancelable&&e.preventDefault(),this.dragStarted||(this.dragStarted=!0,r&&r(e));const{evData:g}=this;g.clientX=e.clientX,g.clientY=e.clientY;let i;g.isResize?i=this.resizeCrop():i=this.dragCrop(),S(n,i)||c(D(i,h.width,h.height),b(i,h.width,h.height))});C(this,"onComponentKeyDown",e=>{const{crop:n,disabled:t,onChange:c,onComplete:r}=this.props;if(t)return;const h=e.key;let g=!1;if(!n)return;const i=this.getBox(),s=this.makePixelCrop(i),p=(navigator.platform.match("Mac")?e.metaKey:e.ctrlKey)?x.nudgeStepLarge:e.shiftKey?x.nudgeStepMedium:x.nudgeStep;if(h==="ArrowLeft"?(s.x-=p,g=!0):h==="ArrowRight"?(s.x+=p,g=!0):h==="ArrowUp"?(s.y-=p,g=!0):h==="ArrowDown"&&(s.y+=p,g=!0),g){e.cancelable&&e.preventDefault(),s.x=M(s.x,0,i.width-s.width),s.y=M(s.y,0,i.height-s.height);const u=D(s,i.width,i.height),l=b(s,i.width,i.height);c(u,l),r&&r(u,l)}});C(this,"onHandlerKeyDown",(e,n)=>{const{aspect:t=0,crop:c,disabled:r,minWidth:h=0,minHeight:g=0,maxWidth:i,maxHeight:s,onChange:w,onComplete:p}=this.props,u=this.getBox();if(r||!c)return;if(e.key==="ArrowUp"||e.key==="ArrowDown"||e.key==="ArrowLeft"||e.key==="ArrowRight")e.stopPropagation(),e.preventDefault();else return;const y=(navigator.platform.match("Mac")?e.metaKey:e.ctrlKey)?x.nudgeStepLarge:e.shiftKey?x.nudgeStepMedium:x.nudgeStep,f=D(c,u.width,u.height),E=$(f,e.key,y,n),X=k(E,t,n,u.width,u.height,h,g,i,s);if(!S(c,X)){const K=b(X,u.width,u.height);w(X,K),p&&p(X,K)}});C(this,"onDocPointerDone",e=>{const{crop:n,disabled:t,onComplete:c,onDragEnd:r}=this.props,h=this.getBox();this.unbindDocMove(),!(t||!n)&&this.mouseDownOnCrop&&(this.mouseDownOnCrop=!1,this.dragStarted=!1,r&&r(e),c&&c(D(n,h.width,h.height),b(n,h.width,h.height)),this.setState({cropIsActive:!1,newCropIsBeingDrawn:!1}))});C(this,"onDragFocus",()=>{var e;(e=this.componentRef.current)==null||e.scrollTo(0,0)})}get document(){return document}getBox(){const e=this.mediaRef.current;if(!e)return{x:0,y:0,width:0,height:0};const{x:n,y:t,width:c,height:r}=e.getBoundingClientRect();return{x:n,y:t,width:c,height:r}}componentDidUpdate(e){const{crop:n,onComplete:t}=this.props;if(t&&!e.crop&&n){const{width:c,height:r}=this.getBox();c&&r&&t(D(n,c,r),b(n,c,r))}}componentWillUnmount(){this.resizeObserver&&this.resizeObserver.disconnect(),this.unbindDocMove()}bindDocMove(){this.docMoveBound||(this.document.addEventListener("pointermove",this.onDocPointerMove,P),this.document.addEventListener("pointerup",this.onDocPointerDone,P),this.document.addEventListener("pointercancel",this.onDocPointerDone,P),this.docMoveBound=!0)}unbindDocMove(){this.docMoveBound&&(this.document.removeEventListener("pointermove",this.onDocPointerMove,P),this.document.removeEventListener("pointerup",this.onDocPointerDone,P),this.document.removeEventListener("pointercancel",this.onDocPointerDone,P),this.docMoveBound=!1)}getCropStyle(){const{crop:e}=this.props;if(e)return{top:`${e.y}${e.unit}`,left:`${e.x}${e.unit}`,width:`${e.width}${e.unit}`,height:`${e.height}${e.unit}`}}dragCrop(){const{evData:e}=this,n=this.getBox(),t=this.makePixelCrop(n),c=e.clientX-e.startClientX,r=e.clientY-e.startClientY;return t.x=M(e.startCropX+c,0,n.width-t.width),t.y=M(e.startCropY+r,0,n.height-t.height),t}getPointRegion(e,n,t,c){const{evData:r}=this,h=r.clientX-e.x,g=r.clientY-e.y;let i;c&&n?i=n==="nw"||n==="n"||n==="ne":i=g<r.startCropY;let s;return t&&n?s=n==="nw"||n==="w"||n==="sw":s=h<r.startCropX,s?i?"nw":"sw":i?"ne":"se"}resolveMinDimensions(e,n,t=0,c=0){const r=Math.min(t,e.width),h=Math.min(c,e.height);return!n||!r&&!h?[r,h]:n>1?r?[r,r/n]:[h*n,h]:h?[h*n,h]:[r,r/n]}resizeCrop(){const{evData:e}=this,{aspect:n=0,maxWidth:t,maxHeight:c}=this.props,r=this.getBox(),[h,g]=this.resolveMinDimensions(r,n,this.props.minWidth,this.props.minHeight);let i=this.makePixelCrop(r);const s=this.getPointRegion(r,e.ord,h,g),w=e.ord||s;let p=e.clientX-e.startClientX,u=e.clientY-e.startClientY;(h&&w==="nw"||w==="w"||w==="sw")&&(p=Math.min(p,-h)),(g&&w==="nw"||w==="n"||w==="ne")&&(u=Math.min(u,-g));const l={unit:"px",x:0,y:0,width:0,height:0};s==="ne"?(l.x=e.startCropX,l.width=p,n?(l.height=l.width/n,l.y=e.startCropY-l.height):(l.height=Math.abs(u),l.y=e.startCropY-l.height)):s==="se"?(l.x=e.startCropX,l.y=e.startCropY,l.width=p,n?l.height=l.width/n:l.height=u):s==="sw"?(l.x=e.startCropX+p,l.y=e.startCropY,l.width=Math.abs(p),n?l.height=l.width/n:l.height=u):s==="nw"&&(l.x=e.startCropX+p,l.width=Math.abs(p),n?(l.height=l.width/n,l.y=e.startCropY-l.height):(l.height=Math.abs(u),l.y=e.startCropY+u));const y=k(l,n,s,r.width,r.height,h,g,t,c);return n||x.xyOrds.indexOf(w)>-1?i=y:x.xOrds.indexOf(w)>-1?(i.x=y.x,i.width=y.width):x.yOrds.indexOf(w)>-1&&(i.y=y.y,i.height=y.height),i.x=M(i.x,0,r.width-i.width),i.y=M(i.y,0,r.height-i.height),i}renderCropSelection(){const{ariaLabels:e=x.defaultProps.ariaLabels,disabled:n,locked:t,renderSelectionAddon:c,ruleOfThirds:r,crop:h}=this.props,g=this.getCropStyle();if(h)return d.createElement("div",{style:g,className:"ReactCrop__crop-selection",onPointerDown:this.onCropPointerDown,"aria-label":e.cropArea,tabIndex:0,onKeyDown:this.onComponentKeyDown,role:"group"},!n&&!t&&d.createElement("div",{className:"ReactCrop__drag-elements",onFocus:this.onDragFocus},d.createElement("div",{className:"ReactCrop__drag-bar ord-n","data-ord":"n"}),d.createElement("div",{className:"ReactCrop__drag-bar ord-e","data-ord":"e"}),d.createElement("div",{className:"ReactCrop__drag-bar ord-s","data-ord":"s"}),d.createElement("div",{className:"ReactCrop__drag-bar ord-w","data-ord":"w"}),d.createElement("div",{className:"ReactCrop__drag-handle ord-nw","data-ord":"nw",tabIndex:0,"aria-label":e.nwDragHandle,onKeyDown:i=>this.onHandlerKeyDown(i,"nw"),role:"button"}),d.createElement("div",{className:"ReactCrop__drag-handle ord-n","data-ord":"n",tabIndex:0,"aria-label":e.nDragHandle,onKeyDown:i=>this.onHandlerKeyDown(i,"n"),role:"button"}),d.createElement("div",{className:"ReactCrop__drag-handle ord-ne","data-ord":"ne",tabIndex:0,"aria-label":e.neDragHandle,onKeyDown:i=>this.onHandlerKeyDown(i,"ne"),role:"button"}),d.createElement("div",{className:"ReactCrop__drag-handle ord-e","data-ord":"e",tabIndex:0,"aria-label":e.eDragHandle,onKeyDown:i=>this.onHandlerKeyDown(i,"e"),role:"button"}),d.createElement("div",{className:"ReactCrop__drag-handle ord-se","data-ord":"se",tabIndex:0,"aria-label":e.seDragHandle,onKeyDown:i=>this.onHandlerKeyDown(i,"se"),role:"button"}),d.createElement("div",{className:"ReactCrop__drag-handle ord-s","data-ord":"s",tabIndex:0,"aria-label":e.sDragHandle,onKeyDown:i=>this.onHandlerKeyDown(i,"s"),role:"button"}),d.createElement("div",{className:"ReactCrop__drag-handle ord-sw","data-ord":"sw",tabIndex:0,"aria-label":e.swDragHandle,onKeyDown:i=>this.onHandlerKeyDown(i,"sw"),role:"button"}),d.createElement("div",{className:"ReactCrop__drag-handle ord-w","data-ord":"w",tabIndex:0,"aria-label":e.wDragHandle,onKeyDown:i=>this.onHandlerKeyDown(i,"w"),role:"button"})),c&&d.createElement("div",{className:"ReactCrop__selection-addon",onPointerDown:i=>i.stopPropagation()},c(this.state)),r&&d.createElement(d.Fragment,null,d.createElement("div",{className:"ReactCrop__rule-of-thirds-hz"}),d.createElement("div",{className:"ReactCrop__rule-of-thirds-vt"})))}makePixelCrop(e){const n={...v,...this.props.crop||{}};return D(n,e.width,e.height)}render(){const{aspect:e,children:n,circularCrop:t,className:c,crop:r,disabled:h,locked:g,style:i,ruleOfThirds:s}=this.props,{cropIsActive:w,newCropIsBeingDrawn:p}=this.state,u=r?this.renderCropSelection():null,l=_("ReactCrop",c,w&&"ReactCrop--active",h&&"ReactCrop--disabled",g&&"ReactCrop--locked",p&&"ReactCrop--new-crop",r&&e&&"ReactCrop--fixed-aspect",r&&t&&"ReactCrop--circular-crop",r&&s&&"ReactCrop--rule-of-thirds",!this.dragStarted&&r&&!r.width&&!r.height&&"ReactCrop--invisible-crop",t&&"ReactCrop--no-animate");return d.createElement("div",{ref:this.componentRef,className:l,style:i},d.createElement("div",{ref:this.mediaRef,className:"ReactCrop__child-wrapper",onPointerDown:this.onComponentPointerDown},n),r?d.createElement("svg",{className:"ReactCrop__crop-mask",width:"100%",height:"100%"},d.createElement("defs",null,d.createElement("mask",{id:`hole-${this.instanceId}`},d.createElement("rect",{width:"100%",height:"100%",fill:"white"}),t?d.createElement("ellipse",{cx:`${r.x+r.width/2}${r.unit}`,cy:`${r.y+r.height/2}${r.unit}`,rx:`${r.width/2}${r.unit}`,ry:`${r.height/2}${r.unit}`,fill:"black"}):d.createElement("rect",{x:`${r.x}${r.unit}`,y:`${r.y}${r.unit}`,width:`${r.width}${r.unit}`,height:`${r.height}${r.unit}`,fill:"black"}))),d.createElement("rect",{fill:"black",fillOpacity:.5,width:"100%",height:"100%",mask:`url(#hole-${this.instanceId})`})):void 0,u)}};C(x,"xOrds",["e","w"]),C(x,"yOrds",["n","s"]),C(x,"xyOrds",["nw","ne","se","sw"]),C(x,"nudgeStep",1),C(x,"nudgeStepMedium",10),C(x,"nudgeStepLarge",100),C(x,"defaultProps",{ariaLabels:{cropArea:"Use the arrow keys to move the crop selection area",nwDragHandle:"Use the arrow keys to move the north west drag handle to change the crop selection area",nDragHandle:"Use the up and down arrow keys to move the north drag handle to change the crop selection area",neDragHandle:"Use the arrow keys to move the north east drag handle to change the crop selection area",eDragHandle:"Use the up and down arrow keys to move the east drag handle to change the crop selection area",seDragHandle:"Use the arrow keys to move the south east drag handle to change the crop selection area",sDragHandle:"Use the up and down arrow keys to move the south drag handle to change the crop selection area",swDragHandle:"Use the arrow keys to move the south west drag handle to change the crop selection area",wDragHandle:"Use the up and down arrow keys to move the west drag handle to change the crop selection area"}});let Y=x;m.Component=Y,m.ReactCrop=Y,m.areCropsEqual=S,m.centerCrop=I,m.clamp=M,m.cls=_,m.containCrop=k,m.convertToPercentCrop=b,m.convertToPixelCrop=D,m.default=Y,m.defaultCrop=v,m.makeAspectCrop=H,m.nudgeCrop=$,Object.defineProperties(m,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});