@sandlada/mdc
Version:
@sandlada/mdc is an open source component library that follows the Material Design 3 design specifications.
8 lines • 6.72 kB
JavaScript
import{BOTTOM_SHEET_DRAG_END_EVENT as e,BOTTOM_SHEET_DRAG_EVENT as t,BOTTOM_SHEET_DRAG_START_EVENT as n}from"../bottom-sheet.interface.js";
/**
* @license
* Copyright 2026 Kai-Orion & Sandlada
* SPDX-License-Identifier: MIT
*/
const r=.25,i=.5;var a=class{constructor(e){this.pointerId=null,this.startX=0,this.startY=0,this.engaged=!1,this.canceled=!1,this.initialDetent=`peek`,this.currentDy=0,this.containerHeight=0,this.fullHeight=0,this.peekHeight=0,this.deltaH=0,this.lastMoveT=0,this.lastMoveDy=0,this.releaseVelocity=0,this.host=e,e.addController(this),this.handlePointerDownBound=e=>this.handlePointerDown(e),this.handlePointerMoveBound=e=>this.handlePointerMove(e),this.handlePointerUpBound=e=>this.handlePointerUp(e),this.handlePointerCancelBound=e=>this.handlePointerUp(e)}hostConnected(){}hostDisconnected(){window.removeEventListener(`pointermove`,this.handlePointerMoveBound),window.removeEventListener(`pointerup`,this.handlePointerUpBound),window.removeEventListener(`pointercancel`,this.handlePointerCancelBound),this.resetState()}cancel(){if(this.pointerId===null)return;window.removeEventListener(`pointermove`,this.handlePointerMoveBound),window.removeEventListener(`pointerup`,this.handlePointerUpBound),window.removeEventListener(`pointercancel`,this.handlePointerCancelBound),this.resetState();let e=this.host.containerRef();e&&(e.style.removeProperty(`transform`),e.style.removeProperty(`cursor`));let t=this.host.scrimRef();t&&t.style.removeProperty(`opacity`),this.host.removeAttribute(`touch-action`),this.host.removeAttribute(`dragged-upward`)}hasMultiDetent(){return this.host.hasHeaderContent()&&this.host.hasBodyContent()}handlePointerDown(e){this.pointerId===null&&this.host.enabled()&&e.isPrimary&&(this.pointerId=e.pointerId,this.startX=e.clientX,this.startY=e.clientY,this.engaged=!1,this.canceled=!1,this.initialDetent=this.host.getRestingDetent(),this.currentDy=0,this.releaseVelocity=0,this.lastMoveT=0,this.lastMoveDy=0,window.addEventListener(`pointermove`,this.handlePointerMoveBound),window.addEventListener(`pointerup`,this.handlePointerUpBound),window.addEventListener(`pointercancel`,this.handlePointerCancelBound))}handlePointerMove(e){if(this.pointerId!==e.pointerId||this.canceled)return;let r=e.clientY-this.startY,i=Math.abs(e.clientX-this.startX);if(!this.engaged&&i>2*Math.max(Math.abs(r),1)){this.canceled=!0,this.handlePointerUp(e);return}if(!this.engaged){if(Math.abs(r)<4)return;let t=this.host.containerRef();if(!t)return;try{t.setPointerCapture(e.pointerId)}catch{}this.engaged=!0,this.containerHeight=t.getBoundingClientRect().height;let i=window.innerHeight,a=window.innerWidth>640?Math.min(.96*i,i-56):Math.min(.96*i,i-72),o=Math.min(.4*i,a);if(!this.hasMultiDetent())this.fullHeight=this.containerHeight,this.peekHeight=this.containerHeight,this.deltaH=0;else if(this.initialDetent===`peek`)this.peekHeight=this.containerHeight,this.fullHeight=Math.max(this.containerHeight,a),this.deltaH=Math.max(0,this.fullHeight-this.peekHeight);else{this.fullHeight=this.containerHeight;let e=this.host.headerRef(),t=this.host.dragHandleRef();if(e&&t){let n=e.getBoundingClientRect(),r=t.getBoundingClientRect();this.peekHeight=Math.min(this.containerHeight,Math.max(r.height+n.height,o))}else this.peekHeight=Math.min(this.containerHeight,o);this.deltaH=Math.max(0,this.fullHeight-this.peekHeight)}this.host.setAttribute(`touch-action`,`none`),t.style.cursor=`grabbing`,this.host.dispatchEvent(new CustomEvent(n,{bubbles:!0,composed:!0,detail:{detent:this.initialDetent}}))}let a=this.host.getVariant()===`standard`,o=this.hasMultiDetent(),s=0;if(!o)s=r<=0?r*.2:r;else if(this.initialDetent===`peek`){if(r<=0){let e=-r;s=e>this.deltaH?-this.deltaH-(e-this.deltaH)*.2:r}else s=r}else s=r<=0?r*.2:r>this.deltaH?this.deltaH+(r-this.deltaH)*.2:r;let c=performance.now(),l=this.lastMoveT,u=this.lastMoveDy;this.lastMoveT=c,this.lastMoveDy=s,l>0&&c-l<80?this.releaseVelocity=(s-u)/(c-l):c-l>=80&&(this.releaseVelocity=0),this.currentDy=s,s<0?this.host.setAttribute(`dragged-upward`,``):this.host.removeAttribute(`dragged-upward`);let d=this.host.containerRef(),f=this.host.scrimRef(),p=.32;if(f&&!a){if(!o){let e=Math.min(1,Math.max(0,s/Math.max(1,this.containerHeight)));f.style.opacity=String(p*(1-e))}else if(this.initialDetent===`peek`){if(s<=0)f.style.opacity=`0.32`;else{let e=Math.min(1,Math.max(0,s/Math.max(1,this.peekHeight)));f.style.opacity=String(p*(1-e))}}else f.style.opacity=`0.32`}d&&(d.style.transform=`translateY(${s}px)`);let m=this.containerHeight>0?this.containerHeight:1,h=Math.min(1,Math.max(0,s/m));this.host.dispatchEvent(new CustomEvent(t,{bubbles:!0,composed:!0,detail:{dy:s,progress:h}}))}handlePointerUp(t){if(this.pointerId!==t.pointerId)return;window.removeEventListener(`pointermove`,this.handlePointerMoveBound),window.removeEventListener(`pointerup`,this.handlePointerUpBound),window.removeEventListener(`pointercancel`,this.handlePointerCancelBound);let n=this.host.containerRef(),a=this.host.scrimRef(),o=this.currentDy;if(!this.engaged){this.resetState();return}if(this.canceled){n&&(n.style.transform=``,n.style.cursor=``),a&&(a.style.opacity=``),this.host.removeAttribute(`touch-action`);try{n?.releasePointerCapture(t.pointerId)}catch{}this.host.dispatchEvent(new CustomEvent(e,{bubbles:!0,composed:!0,detail:{committed:!1,target:this.initialDetent,reason:`cancel`,dy:o}})),this.resetState();return}try{n?.releasePointerCapture(t.pointerId)}catch{}let s=this.hasMultiDetent(),c=this.initialDetent,l;if(!s){let e=Math.max(30,this.containerHeight*r);this.releaseVelocity>i||this.currentDy>e?(c=`closed`,l=this.releaseVelocity>i?`velocity`:`distance`):c=this.initialDetent}else if(this.initialDetent===`full`){let e=Math.max(40,this.deltaH*r);this.releaseVelocity>i||this.currentDy>=e?(c=`peek`,l=this.releaseVelocity>i?`velocity`:`distance`):c=`full`}else{let e=Math.max(40,this.deltaH*r),t=Math.max(30,this.peekHeight*r);this.releaseVelocity<-.5||this.currentDy<-e?(c=`full`,l=this.releaseVelocity<-.5?`velocity`:`distance`):this.releaseVelocity>i||this.currentDy>t?(c=`closed`,l=this.releaseVelocity>i?`velocity`:`distance`):c=`peek`}let u=c===`closed`;this.host.dispatchEvent(new CustomEvent(e,{bubbles:!0,composed:!0,detail:{committed:u,target:c,reason:l,dy:o}})),this.resetState()}resetState(){this.host.removeAttribute(`dragged-upward`);let e=this.host.containerRef();e&&e.style.removeProperty(`cursor`),this.pointerId=null,this.startX=0,this.startY=0,this.engaged=!1,this.canceled=!1,this.currentDy=0,this.containerHeight=0,this.fullHeight=0,this.peekHeight=0,this.deltaH=0,this.releaseVelocity=0,this.lastMoveT=0,this.lastMoveDy=0}};export{a as BottomSheetDragController};
//# sourceMappingURL=bottom-sheet-drag-controller.js.map