@alexapvl/drwr 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -42
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +9 -7
package/README.md
CHANGED
|
@@ -5,14 +5,26 @@ A zero-dependency, framework-agnostic bottom sheet / drawer component. Vanilla J
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
|
|
8
|
+
pnpm add @alexapvl/drwr
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
bun add @alexapvl/drwr
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @alexapvl/drwr
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
yarn add @alexapvl/drwr
|
|
9
21
|
```
|
|
10
22
|
|
|
11
23
|
## Usage
|
|
12
24
|
|
|
13
25
|
```js
|
|
14
|
-
import { Sheet } from "drwr";
|
|
15
|
-
import "drwr/style.css";
|
|
26
|
+
import { Sheet } from "@alexapvl/drwr";
|
|
27
|
+
import "@alexapvl/drwr/style.css";
|
|
16
28
|
|
|
17
29
|
const sheet = new Sheet(document.getElementById("my-sheet"), {
|
|
18
30
|
snapPoints: [0, 0.5, 1],
|
|
@@ -21,54 +33,54 @@ const sheet = new Sheet(document.getElementById("my-sheet"), {
|
|
|
21
33
|
dragHandle: true,
|
|
22
34
|
});
|
|
23
35
|
|
|
24
|
-
sheet.open();
|
|
25
|
-
sheet.open(0.5);
|
|
36
|
+
sheet.open(); // open to highest snap
|
|
37
|
+
sheet.open(0.5); // open to specific snap
|
|
26
38
|
sheet.snapTo(0.5);
|
|
27
39
|
sheet.close();
|
|
28
|
-
sheet.refresh();
|
|
40
|
+
sheet.refresh(); // re-measure after dynamic content change
|
|
29
41
|
sheet.destroy();
|
|
30
42
|
```
|
|
31
43
|
|
|
32
44
|
## Options
|
|
33
45
|
|
|
34
|
-
| Option
|
|
35
|
-
|
|
36
|
-
| `snapPoints`
|
|
37
|
-
| `defaultSnap`
|
|
38
|
-
| `overlay`
|
|
39
|
-
| `dragHandle`
|
|
40
|
-
| `damping`
|
|
41
|
-
| `stiffness`
|
|
42
|
-
| `closeThreshold`
|
|
43
|
-
| `topPadding`
|
|
44
|
-
| `width`
|
|
45
|
-
| `align`
|
|
46
|
-
| `sidePadding`
|
|
47
|
-
| `maxWidth`
|
|
48
|
-
| `dragMode`
|
|
49
|
-
| `ariaLabel`
|
|
50
|
-
| `ariaLabelledBy`
|
|
51
|
-
| `closeOnEscape`
|
|
52
|
-
| `closeOnOverlayClick` | `boolean`
|
|
53
|
-
| `trapFocus`
|
|
54
|
-
| `modal`
|
|
55
|
-
| `reducedMotion`
|
|
56
|
-
| `onOpen`
|
|
57
|
-
| `onClose`
|
|
58
|
-
| `onSnap`
|
|
46
|
+
| Option | Type | Default | Description |
|
|
47
|
+
| --------------------- | ------------------------------- | ------------------------------- | ---------------------------------------------------------------------------------------- |
|
|
48
|
+
| `snapPoints` | `number[]` | `[0, 1]` | Normalized snap points from 0 to 1 (0 = closed, 1 = max height). Sanitized on input. |
|
|
49
|
+
| `defaultSnap` | `number` | `0` | Initial snap point. Non-zero values open with full state (scroll lock, focus trap, etc). |
|
|
50
|
+
| `overlay` | `boolean` | `true` | Show backdrop overlay |
|
|
51
|
+
| `dragHandle` | `boolean` | `true` | Render a drag handle bar |
|
|
52
|
+
| `damping` | `number` | `30` | Spring damping coefficient |
|
|
53
|
+
| `stiffness` | `number` | `200` | Spring stiffness coefficient |
|
|
54
|
+
| `closeThreshold` | `number` | `0.2` | Fraction of lowest snap below which the sheet closes on release |
|
|
55
|
+
| `topPadding` | `number` | `40` | Space left above the sheet at max height, in px |
|
|
56
|
+
| `width` | `number` | `60` (desktop) / `100` (mobile) | Width as % of viewport |
|
|
57
|
+
| `align` | `"center" \| "left" \| "right"` | `"center"` | Horizontal alignment |
|
|
58
|
+
| `sidePadding` | `number` | `0` | Minimum side padding in px |
|
|
59
|
+
| `maxWidth` | `number` | `0` | Max width in px (0 = no max) |
|
|
60
|
+
| `dragMode` | `"handle" \| "sheet" \| "none"` | `"sheet"` | Which part initiates drag |
|
|
61
|
+
| `ariaLabel` | `string` | `"Sheet"` | Accessible label for the dialog |
|
|
62
|
+
| `ariaLabelledBy` | `string` | — | ID of labelling element (overrides `ariaLabel`) |
|
|
63
|
+
| `closeOnEscape` | `boolean` | `true` | Close on Escape key |
|
|
64
|
+
| `closeOnOverlayClick` | `boolean` | `true` | Close on overlay click |
|
|
65
|
+
| `trapFocus` | `boolean` | `true` | Trap focus inside the sheet |
|
|
66
|
+
| `modal` | `boolean` | `true` | Set `aria-modal` |
|
|
67
|
+
| `reducedMotion` | `boolean` | `true` | Skip spring animation when user prefers reduced motion |
|
|
68
|
+
| `onOpen` | `() => void` | — | Called when sheet opens |
|
|
69
|
+
| `onClose` | `() => void` | — | Called when sheet closes |
|
|
70
|
+
| `onSnap` | `(point: number) => void` | — | Called when sheet snaps to a point |
|
|
59
71
|
|
|
60
72
|
## Methods
|
|
61
73
|
|
|
62
|
-
| Method
|
|
63
|
-
|
|
64
|
-
| `open(point?)`
|
|
65
|
-
| `close()`
|
|
66
|
-
| `snapTo(point)`
|
|
67
|
-
| `refresh()`
|
|
68
|
-
| `setSnapPoints(points)`
|
|
69
|
-
| `setLayout({ width?, align?, sidePadding? })` | Update layout at runtime.
|
|
70
|
-
| `setOptions(opts)`
|
|
71
|
-
| `destroy()`
|
|
74
|
+
| Method | Description |
|
|
75
|
+
| --------------------------------------------- | ------------------------------------------------ |
|
|
76
|
+
| `open(point?)` | Open to the given snap (or highest). |
|
|
77
|
+
| `close()` | Close the sheet. |
|
|
78
|
+
| `snapTo(point)` | Animate to a specific snap point. |
|
|
79
|
+
| `refresh()` | Re-measure content height after dynamic changes. |
|
|
80
|
+
| `setSnapPoints(points)` | Replace snap points (sanitized). |
|
|
81
|
+
| `setLayout({ width?, align?, sidePadding? })` | Update layout at runtime. |
|
|
82
|
+
| `setOptions(opts)` | Merge partial options at runtime. |
|
|
83
|
+
| `destroy()` | Tear down the sheet and restore DOM. |
|
|
72
84
|
|
|
73
85
|
## Theming
|
|
74
86
|
|
|
@@ -82,7 +94,9 @@ All visual tokens are exposed as CSS custom properties:
|
|
|
82
94
|
--drwr-handle-height: 4px;
|
|
83
95
|
--drwr-handle-color: rgba(0, 0, 0, 0.25);
|
|
84
96
|
--drwr-overlay-color: rgba(0, 0, 0, 0.4);
|
|
85
|
-
--drwr-shadow:
|
|
97
|
+
--drwr-shadow:
|
|
98
|
+
0 -1px 0 rgba(0, 0, 0, 0.04), 0 -8px 32px rgba(0, 0, 0, 0.12),
|
|
99
|
+
0 -24px 60px rgba(0, 0, 0, 0.06);
|
|
86
100
|
--drwr-border: 1px solid rgba(0, 0, 0, 0.06);
|
|
87
101
|
--drwr-z-index: 9999;
|
|
88
102
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var S=Object.defineProperty;var A=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var F=Object.prototype.hasOwnProperty;var D=(i,e)=>{for(var t in e)S(i,t,{get:e[t],enumerable:!0})},Y=(i,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of k(e))!F.call(i,r)&&r!==t&&S(i,r,{get:()=>e[r],enumerable:!(s=A(e,r))||s.enumerable});return i};var B=i=>Y(S({},"__esModule",{value:!0}),i);var N={};D(N,{Sheet:()=>y});module.exports=B(N);var L={damping:30,stiffness:200,mass:1,restThreshold:.5};function R(i,e,t,s,r){let{stiffness:n,damping:a,mass:d}=r,o=i-e,c=-n*o,u=-a*t,l=(c+u)/d,h=t+l*s;return{position:i+h*s,velocity:h}}function z(i,e,t,s=L.restThreshold){return Math.abs(i-e)<s&&Math.abs(t)<s}function T(i,e,t,s,r,n){let a={...L,...s},d=i,o=t,c=0,u=0;function l(h){if(c===0){c=h,u=requestAnimationFrame(l);return}let p=Math.min((h-c)/1e3,.064);c=h;let m=R(d,e,o,p,a);if(d=m.position,o=m.velocity,r(d),z(d,e,o,a.restThreshold)){r(e),n();return}u=requestAnimationFrame(l)}return u=requestAnimationFrame(l),()=>cancelAnimationFrame(u)}var g=class{constructor(e=8){this.samples=[];this.maxSamples=e}add(e){this.samples.push({time:performance.now(),value:e}),this.samples.length>this.maxSamples&&this.samples.shift()}getVelocity(){if(this.samples.length<2)return 0;let e=this.samples[this.samples.length-1],t=this.samples[0];for(let r=this.samples.length-2;r>=0;r--)if(e.time-this.samples[r].time>=30){t=this.samples[r];break}let s=(e.time-t.time)/1e3;return s===0?0:(e.value-t.value)/s}reset(){this.samples=[]}};function P(i,e,t,s=400,r=1200){if(t.length===0)return i;if(t.length===1)return t[0];let n=[...t].sort((o,c)=>o-c);if(Math.abs(e)>r)return e>0?n[n.length-1]:n[0];if(Math.abs(e)>s)if(e>0){for(let o of n)if(o>i+2)return o;return n[n.length-1]}else{for(let o=n.length-1;o>=0;o--)if(n[o]<i-2)return n[o];return n[0]}let a=n[0],d=Math.abs(i-n[0]);for(let o=1;o<n.length;o++){let c=Math.abs(i-n[o]);c<d&&(a=n[o],d=c)}return a}var x=6,G=3;function K(i,e){let t=i;for(;t&&t!==e;){if(t.scrollHeight>t.clientHeight){let r=getComputedStyle(t).overflowY;if(r==="auto"||r==="scroll")return t}t=t.parentElement}return null}function H(i,e,t,s){let r=new g,n={active:!1,dragging:!1,startY:0,currentY:0,directionLocked:!1,lockedAxis:null,startX:0,currentX:0,scrolling:!1,scrollTarget:null};function a(l){let h=e?.contains(l.target);if(t&&!h)return;let p=h?null:K(l.target,i);n.active=!0,n.dragging=!1,n.startY=l.clientY,n.currentY=l.clientY,n.startX=l.clientX,n.currentX=l.clientX,n.directionLocked=!1,n.lockedAxis=null,n.scrolling=!1,n.scrollTarget=p,r.reset(),r.add(l.clientY),i.setPointerCapture(l.pointerId)}function d(l){if(!n.active||n.scrolling)return;n.currentY=l.clientY,n.currentX=l.clientX;let h=Math.abs(n.currentX-n.startX),p=Math.abs(n.currentY-n.startY),m=n.currentY-n.startY;if(!(!n.directionLocked&&((h>x||p>x)&&(n.directionLocked=!0,n.lockedAxis=p>=h?"y":"x"),p<G))&&n.lockedAxis!=="x"){if(n.scrollTarget&&!n.dragging){let f=n.scrollTarget,C=f.scrollTop<=0,O=f.scrollTop+f.clientHeight>=f.scrollHeight-1,w=m>0;if(!(w&&C)){if(!(!w&&O)){n.scrolling=!0;return}}}n.dragging||(n.dragging=!0,s.onStart(n.startY)),l.preventDefault(),r.add(l.clientY),s.onMove(n.currentY,m)}}function o(l){if(!n.active||(n.active=!1,i.releasePointerCapture(l.pointerId),!n.dragging))return;n.dragging=!1;let h=r.getVelocity();s.onEnd(h)}function c(l){n.active&&(n.active=!1,i.releasePointerCapture(l.pointerId),n.dragging&&(n.dragging=!1,s.onEnd(0)))}i.addEventListener("pointerdown",a),i.addEventListener("pointermove",d),i.addEventListener("pointerup",o),i.addEventListener("pointercancel",c);let u=l=>{n.active&&l.preventDefault()};return i.addEventListener("contextmenu",u),()=>{i.removeEventListener("pointerdown",a),i.removeEventListener("pointermove",d),i.removeEventListener("pointerup",o),i.removeEventListener("pointercancel",c),i.removeEventListener("contextmenu",u)}}var W=["a[href]","button:not([disabled])","input:not([disabled])","select:not([disabled])","textarea:not([disabled])",'[tabindex]:not([tabindex="-1"])'].join(", ");function v(i){let e=null;function t(){return Array.from(i.querySelectorAll(W))}function s(a){if(a.key!=="Tab")return;let d=t();if(d.length===0){a.preventDefault();return}let o=d[0],c=d[d.length-1];a.shiftKey?(document.activeElement===o||!i.contains(document.activeElement))&&(a.preventDefault(),c.focus()):(document.activeElement===c||!i.contains(document.activeElement))&&(a.preventDefault(),o.focus())}function r(){e=document.activeElement,i.addEventListener("keydown",s),requestAnimationFrame(()=>{let a=t();a.length>0?a[0].focus():i.focus()})}function n(){i.removeEventListener("keydown",s),e?.focus(),e=null}return r(),n}function E(i,e,t={}){i.setAttribute("role","dialog"),i.setAttribute("aria-modal",t.modal!==!1?"true":"false"),t.ariaLabelledBy?(i.setAttribute("aria-labelledby",t.ariaLabelledBy),i.removeAttribute("aria-label")):(i.setAttribute("aria-label",t.ariaLabel||"Sheet"),i.removeAttribute("aria-labelledby")),e&&e.setAttribute("aria-hidden","true")}function M(i,e){i.removeAttribute("role"),i.removeAttribute("aria-modal"),e&&e.removeAttribute("aria-hidden")}function b(){let i=document.body,e=document.documentElement,t=i.style.overflow,s=e.style.overflow;e.style.overflow="hidden",i.style.overflow="hidden";let r=n=>{let a=n.target;for(;a;){if(a.classList?.contains("drwr-content"))return;a=a.parentElement}n.preventDefault()};return document.addEventListener("touchmove",r,{passive:!1}),()=>{i.style.overflow=t,e.style.overflow=s,document.removeEventListener("touchmove",r)}}function X(i){return 8*(Math.log(i+1)-2)}var y=class i{constructor(e,t={}){this.overlayEl=null;this.handleEl=null;this.state="closed";this.currentSnap=0;this.currentH=0;this.dragStartH=0;this.cancelAnimation=null;this.cleanupGestures=null;this.cleanupFocusTrap=null;this.unlockScroll=null;this.onPageShow=null;this.onResize=null;this.naturalContentH=0;this.destroyed=!1;this.onKeyDown=e=>{e.key==="Escape"&&this.state!=="closed"&&this.options.closeOnEscape&&this.close()};this.container=e;let s=i.sanitizeSnapPoints(t.snapPoints??[0,1]);this.options={snapPoints:s,defaultSnap:t.defaultSnap??0,overlay:t.overlay??!0,dragHandle:t.dragHandle??!0,damping:t.damping??30,stiffness:t.stiffness??200,mass:t.mass??1,closeThreshold:t.closeThreshold??.2,topPadding:t.topPadding??40,width:t.width??(window.innerWidth>=768?60:100),align:t.align??"center",sidePadding:t.sidePadding??0,maxWidth:t.maxWidth??0,dragMode:t.dragMode??"sheet",ariaLabel:t.ariaLabel??"Sheet",ariaLabelledBy:t.ariaLabelledBy??"",closeOnEscape:t.closeOnEscape??!0,closeOnOverlayClick:t.closeOnOverlayClick??!0,trapFocus:t.trapFocus??!0,modal:t.modal??!0,reducedMotion:t.reducedMotion??!0,onOpen:t.onOpen??(()=>{}),onClose:t.onClose??(()=>{}),onSnap:t.onSnap??(()=>{})},this.buildDOM(),this.container.removeAttribute("hidden"),this.naturalContentH=this.getContentHeight(),this.bindGestures();let r=this.options.defaultSnap;r>0&&this.options.snapPoints.includes(r)?(this.currentH=this.snapToPixels(r),this.render(this.currentH),this.state="open",this.currentSnap=r,document.addEventListener("keydown",this.onKeyDown),this.unlockScroll||(this.unlockScroll=b()),this.options.trapFocus&&!this.cleanupFocusTrap&&(this.cleanupFocusTrap=v(this.wrapperEl)),queueMicrotask(()=>{this.destroyed||this.options.onOpen()})):(this.currentH=0,this.render(0)),this.onPageShow=n=>{n.persisted&&this.state!=="closed"&&this.resetToClosedState()},window.addEventListener("pageshow",this.onPageShow),this.onResize=()=>{this.applyLayout(),this.naturalContentH=this.getContentHeight(),this.state!=="closed"&&this.currentSnap>0&&(this.currentH=this.snapToPixels(this.currentSnap),this.render(this.currentH))},window.addEventListener("resize",this.onResize)}static sanitizeSnapPoints(e){let t=e.filter(r=>Number.isFinite(r)&&r>=0&&r<=1),s=[...new Set(t)].sort((r,n)=>r-n);return s.length===0?[0,1]:(s.includes(0)||s.unshift(0),s)}prefersReducedMotion(){return this.options.reducedMotion&&typeof window<"u"&&window.matchMedia("(prefers-reduced-motion: reduce)").matches}getContentHeight(){return this.contentEl.scrollHeight+(this.handleEl?.offsetHeight??0)}maxSheetH(){return window.innerHeight-this.options.topPadding}snapToPixels(e){if(e<=0)return 0;let t=this.maxSheetH();return Math.min(e,1)*t}snapPixels(){return this.options.snapPoints.map(e=>this.snapToPixels(e)).sort((e,t)=>e-t)}pixelsToSnap(e){let t=this.options.snapPoints,s=t[0],r=Math.abs(e-this.snapToPixels(t[0]));for(let n=1;n<t.length;n++){let a=Math.abs(e-this.snapToPixels(t[n]));a<r&&(s=t[n],r=a)}return s}applyLayout(){let{width:e,align:t,sidePadding:s,maxWidth:r}=this.options,n=this.wrapperEl,a=window.innerWidth,d=Math.max(10,Math.min(100,e)),o=Math.max(0,Math.min(s,a/2-10)),c=Math.max(20,Math.min(a*(d/100),a-o*2));r>0&&(c=Math.min(c,r));let u;t==="left"?u=o:t==="right"?u=a-c-o:u=(a-c)/2,n.style.left=`${u}px`,n.style.right="auto",n.style.width=`${c}px`,n.style.margin="0"}buildDOM(){for(this.wrapperEl=document.createElement("div"),this.wrapperEl.className="drwr-sheet",this.wrapperEl.setAttribute("tabindex","-1"),this.options.dragHandle&&(this.handleEl=document.createElement("div"),this.handleEl.className="drwr-handle",this.wrapperEl.appendChild(this.handleEl)),this.contentEl=document.createElement("div"),this.contentEl.className="drwr-content";this.container.firstChild;)this.contentEl.appendChild(this.container.firstChild);this.wrapperEl.appendChild(this.contentEl),this.container.appendChild(this.wrapperEl),this.options.overlay&&(this.overlayEl=document.createElement("div"),this.overlayEl.className="drwr-overlay",this.overlayEl.addEventListener("click",()=>{this.options.closeOnOverlayClick&&this.close()}),this.container.insertBefore(this.overlayEl,this.wrapperEl)),E(this.wrapperEl,this.overlayEl,{ariaLabel:this.options.ariaLabel,ariaLabelledBy:this.options.ariaLabelledBy,modal:this.options.modal}),this.applyLayout()}bindGestures(){this.options.dragMode!=="none"&&(this.cleanupGestures=H(this.wrapperEl,this.handleEl,this.options.dragMode==="handle",{onStart:()=>{this.cancelCurrentAnimation(),this.state="dragging",this.dragStartH=this.currentH,this.wrapperEl.setAttribute("data-dragging","true")},onMove:(e,t)=>{let s=this.dragStartH-t,r=this.snapPixels(),n=r[r.length-1],a=r[0];if(s>n)s=n;else if(s<a){let d=a-s;s=a-Math.max(0,X(d))}this.currentH=s,this.render(s)},onEnd:e=>{this.wrapperEl.setAttribute("data-dragging","false");let t=-e;this.state="animating";let s=this.snapPixels(),r=P(this.currentH,t,s,400),n=s.filter(a=>a>0);if(n.length>0){let a=n[0];this.currentH<a*this.options.closeThreshold&&(r=0)}this.animateToH(r,t)}}))}cancelCurrentAnimation(){this.cancelAnimation&&(this.cancelAnimation(),this.cancelAnimation=null)}animateToH(e,t=0){let s=this.state==="open"||this.state==="dragging";this.cancelCurrentAnimation(),this.state="animating";let r=()=>{this.currentH=e,this.render(e),this.cancelAnimation=null;let a=this.pixelsToSnap(e);this.currentSnap=a,e<=.5?this.onClosed():(this.state="open",s||this.options.onOpen(),this.options.onSnap(a))};if(this.prefersReducedMotion()){r();return}let n={damping:this.options.damping,stiffness:this.options.stiffness,mass:this.options.mass};this.cancelAnimation=T(this.currentH,e,t,n,a=>{this.currentH=a,this.render(a)},r)}render(e){let t=window.innerHeight,s=Math.max(0,e),r=t-s;if(this.wrapperEl.style.visibility=s>.5?"visible":"hidden",this.wrapperEl.style.transform=`translate3d(0, ${r}px, 0)`,this.wrapperEl.style.height=s>.5?`${s}px`:"",this.overlayEl){let n=this.snapPixels(),a=n[n.length-1],d=Math.max(0,Math.min(1,s/(a*.3)));this.overlayEl.style.opacity=String(d),this.overlayEl.setAttribute("data-visible",s>1?"true":"false")}}resetToClosedState(){this.cancelCurrentAnimation(),this.currentH=0,this.currentSnap=0,this.render(0),this.state="closed",this.overlayEl&&(this.overlayEl.style.opacity="0",this.overlayEl.setAttribute("data-visible","false")),this.unlockScroll&&(this.unlockScroll(),this.unlockScroll=null),this.cleanupFocusTrap&&(this.cleanupFocusTrap(),this.cleanupFocusTrap=null),document.removeEventListener("keydown",this.onKeyDown)}onClosed(){this.resetToClosedState(),this.options.onClose()}open(e){if(this.destroyed||this.state==="open")return;let t=[...this.options.snapPoints].sort((r,n)=>r-n),s;if(e!==void 0){if(!t.includes(e)||e===0){console.warn(`[drwr] snap point ${e} not valid for open()`);return}s=e}else s=t[t.length-1];document.addEventListener("keydown",this.onKeyDown),this.animateToH(this.snapToPixels(s)),this.unlockScroll||(this.unlockScroll=b()),this.options.trapFocus&&!this.cleanupFocusTrap&&(this.cleanupFocusTrap=v(this.wrapperEl))}close(){this.destroyed||this.state==="closed"||(document.removeEventListener("keydown",this.onKeyDown),this.animateToH(0))}snapTo(e){if(!this.destroyed){if(!this.options.snapPoints.includes(e)){console.warn(`[drwr] snap point ${e} not in snapPoints`);return}e===0?this.close():(this.state==="closed"&&(document.addEventListener("keydown",this.onKeyDown),this.unlockScroll||(this.unlockScroll=b()),this.options.trapFocus&&!this.cleanupFocusTrap&&(this.cleanupFocusTrap=v(this.wrapperEl))),this.animateToH(this.snapToPixels(e)))}}destroy(){if(!this.destroyed){for(this.destroyed=!0,this.cancelCurrentAnimation(),document.removeEventListener("keydown",this.onKeyDown),this.cleanupGestures&&(this.cleanupGestures(),this.cleanupGestures=null),this.cleanupFocusTrap&&(this.cleanupFocusTrap(),this.cleanupFocusTrap=null),this.unlockScroll&&(this.unlockScroll(),this.unlockScroll=null),this.onPageShow&&(window.removeEventListener("pageshow",this.onPageShow),this.onPageShow=null),this.onResize&&(window.removeEventListener("resize",this.onResize),this.onResize=null),M(this.wrapperEl,this.overlayEl);this.contentEl.firstChild;)this.container.appendChild(this.contentEl.firstChild);this.wrapperEl.remove(),this.overlayEl?.remove()}}setSnapPoints(e){if(!this.destroyed&&(this.options.snapPoints=i.sanitizeSnapPoints(e),this.state!=="closed"&&this.currentSnap>0&&!this.options.snapPoints.includes(this.currentSnap))){let t=this.pixelsToSnap(this.currentH);this.animateToH(this.snapToPixels(t))}}refresh(){this.destroyed||(this.naturalContentH=this.getContentHeight(),this.state!=="closed"&&this.currentSnap>0&&(this.currentH=this.snapToPixels(this.currentSnap),this.render(this.currentH)))}setOptions(e){if(this.destroyed)return;if(e.snapPoints!==void 0&&(this.options.snapPoints=i.sanitizeSnapPoints(e.snapPoints)),e.damping!==void 0&&(this.options.damping=e.damping),e.stiffness!==void 0&&(this.options.stiffness=e.stiffness),e.mass!==void 0&&(this.options.mass=e.mass),e.closeThreshold!==void 0&&(this.options.closeThreshold=e.closeThreshold),e.topPadding!==void 0&&(this.options.topPadding=e.topPadding),e.closeOnEscape!==void 0&&(this.options.closeOnEscape=e.closeOnEscape),e.closeOnOverlayClick!==void 0&&(this.options.closeOnOverlayClick=e.closeOnOverlayClick),e.ariaLabel!==void 0&&(this.options.ariaLabel=e.ariaLabel),e.ariaLabelledBy!==void 0&&(this.options.ariaLabelledBy=e.ariaLabelledBy),e.modal!==void 0&&(this.options.modal=e.modal),e.maxWidth!==void 0&&(this.options.maxWidth=e.maxWidth),e.reducedMotion!==void 0&&(this.options.reducedMotion=e.reducedMotion),e.onOpen!==void 0&&(this.options.onOpen=e.onOpen),e.onClose!==void 0&&(this.options.onClose=e.onClose),e.onSnap!==void 0&&(this.options.onSnap=e.onSnap),(e.ariaLabel!==void 0||e.ariaLabelledBy!==void 0||e.modal!==void 0)&&E(this.wrapperEl,this.overlayEl,{ariaLabel:this.options.ariaLabel,ariaLabelledBy:this.options.ariaLabelledBy,modal:this.options.modal}),(e.width!==void 0||e.align!==void 0||e.sidePadding!==void 0||e.maxWidth!==void 0)&&(e.width!==void 0&&(this.options.width=e.width),e.align!==void 0&&(this.options.align=e.align),e.sidePadding!==void 0&&(this.options.sidePadding=e.sidePadding),this.applyLayout()),(e.topPadding!==void 0||e.snapPoints!==void 0)&&this.state!=="closed"&&this.currentSnap>0)if(e.snapPoints!==void 0&&!this.options.snapPoints.includes(this.currentSnap)){let s=this.pixelsToSnap(this.currentH);this.animateToH(this.snapToPixels(s))}else this.currentH=this.snapToPixels(this.currentSnap),this.render(this.currentH)}setLayout(e){this.destroyed||(e.width!==void 0&&(this.options.width=e.width),e.align!==void 0&&(this.options.align=e.align),e.sidePadding!==void 0&&(this.options.sidePadding=e.sidePadding),this.applyLayout())}get isOpen(){return this.state!=="closed"}get currentSnapPoint(){return this.currentSnap}};0&&(module.exports={Sheet});
|
|
1
|
+
"use strict";var E=Object.defineProperty;var Y=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var R=Object.prototype.hasOwnProperty;var z=(i,e)=>{for(var t in e)E(i,t,{get:e[t],enumerable:!0})},G=(i,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of B(e))!R.call(i,r)&&r!==t&&E(i,r,{get:()=>e[r],enumerable:!(s=Y(e,r))||s.enumerable});return i};var K=i=>G(E({},"__esModule",{value:!0}),i);var _={};z(_,{Sheet:()=>w});module.exports=K(_);var x={damping:30,stiffness:200,mass:1,restThreshold:.5};function W(i,e,t,s,r){let{stiffness:n,damping:a,mass:d}=r,o=i-e,u=-n*o,c=-a*t,p=(u+c)/d,l=t+p*s;return{position:i+l*s,velocity:l}}function X(i,e,t,s=x.restThreshold){return Math.abs(i-e)<s&&Math.abs(t)<s}function H(i,e,t,s,r,n){let a={...x,...s},d=i,o=t,u=0,c=0;function p(l){if(u===0){u=l,c=requestAnimationFrame(p);return}let h=Math.min((l-u)/1e3,.064);u=l;let f=W(d,e,o,h,a);if(d=f.position,o=f.velocity,r(d),X(d,e,o,a.restThreshold)){r(e),n();return}c=requestAnimationFrame(p)}return c=requestAnimationFrame(p),()=>cancelAnimationFrame(c)}var g=class{constructor(e=8){this.samples=[];this.maxSamples=e}add(e){this.samples.push({time:performance.now(),value:e}),this.samples.length>this.maxSamples&&this.samples.shift()}getVelocity(){if(this.samples.length<2)return 0;let e=this.samples[this.samples.length-1],t=this.samples[0];for(let r=this.samples.length-2;r>=0;r--)if(e.time-this.samples[r].time>=30){t=this.samples[r];break}let s=(e.time-t.time)/1e3;return s===0?0:(e.value-t.value)/s}reset(){this.samples=[]}};function M(i,e,t,s=400,r=1200){if(t.length===0)return i;if(t.length===1)return t[0];let n=[...t].sort((o,u)=>o-u);if(Math.abs(e)>r)return e>0?n[n.length-1]:n[0];if(Math.abs(e)>s)if(e>0){for(let o of n)if(o>i+2)return o;return n[n.length-1]}else{for(let o=n.length-1;o>=0;o--)if(n[o]<i-2)return n[o];return n[0]}let a=n[0],d=Math.abs(i-n[0]);for(let o=1;o<n.length;o++){let u=Math.abs(i-n[o]);u<d&&(a=n[o],d=u)}return a}var C=6,I=3;function N(i,e){let t=i;for(;t&&t!==e;){if(t.scrollHeight>t.clientHeight){let r=getComputedStyle(t).overflowY;if(r==="auto"||r==="scroll")return t}t=t.parentElement}return null}function A(i,e,t,s){let r=new g,n={active:!1,dragging:!1,startY:0,currentY:0,directionLocked:!1,lockedAxis:null,startX:0,currentX:0,scrolling:!1,scrollTarget:null};function a(l){let h=e?.contains(l.target);if(t&&!h)return;let f=h?null:N(l.target,i);n.active=!0,n.dragging=!1,n.startY=l.clientY,n.currentY=l.clientY,n.startX=l.clientX,n.currentX=l.clientX,n.directionLocked=!1,n.lockedAxis=null,n.scrolling=!1,n.scrollTarget=f,r.reset(),r.add(l.clientY),window.addEventListener("pointermove",o),window.addEventListener("pointerup",u),window.addEventListener("pointercancel",c)}function d(){window.removeEventListener("pointermove",o),window.removeEventListener("pointerup",u),window.removeEventListener("pointercancel",c)}function o(l){if(!n.active||n.scrolling)return;n.currentY=l.clientY,n.currentX=l.clientX;let h=Math.abs(n.currentX-n.startX),f=Math.abs(n.currentY-n.startY),T=n.currentY-n.startY;if(!(!n.directionLocked&&((h>C||f>C)&&(n.directionLocked=!0,n.lockedAxis=f>=h?"y":"x"),f<I))&&n.lockedAxis!=="x"){if(n.scrollTarget&&!n.dragging){let m=n.scrollTarget,F=m.scrollTop<=0,D=m.scrollTop+m.clientHeight>=m.scrollHeight-1,P=T>0;if(!(P&&F)){if(!(!P&&D)){n.scrolling=!0;return}}}n.dragging||(n.dragging=!0,i.setPointerCapture(l.pointerId),s.onStart(n.startY)),l.preventDefault(),r.add(l.clientY),s.onMove(n.currentY,T)}}function u(l){if(!n.active||(n.active=!1,d(),i.hasPointerCapture(l.pointerId)&&i.releasePointerCapture(l.pointerId),!n.dragging))return;n.dragging=!1;let h=r.getVelocity();s.onEnd(h)}function c(l){n.active&&(n.active=!1,d(),i.hasPointerCapture(l.pointerId)&&i.releasePointerCapture(l.pointerId),n.dragging&&(n.dragging=!1,s.onEnd(0)))}i.addEventListener("pointerdown",a);let p=l=>{n.active&&l.preventDefault()};return i.addEventListener("contextmenu",p),()=>{i.removeEventListener("pointerdown",a),d(),i.removeEventListener("contextmenu",p)}}var q=["a[href]","button:not([disabled])","input:not([disabled])","select:not([disabled])","textarea:not([disabled])",'[tabindex]:not([tabindex="-1"])'].join(", ");function b(i){let e=null;function t(){return Array.from(i.querySelectorAll(q))}function s(a){if(a.key!=="Tab")return;let d=t();if(d.length===0){a.preventDefault();return}let o=d[0],u=d[d.length-1];a.shiftKey?(document.activeElement===o||!i.contains(document.activeElement))&&(a.preventDefault(),u.focus()):(document.activeElement===u||!i.contains(document.activeElement))&&(a.preventDefault(),o.focus())}function r(){e=document.activeElement,i.addEventListener("keydown",s),requestAnimationFrame(()=>{let a=t();a.length>0?a[0].focus():i.focus()})}function n(){i.removeEventListener("keydown",s),e?.focus(),e=null}return r(),n}function L(i,e,t={}){i.setAttribute("role","dialog"),i.setAttribute("aria-modal",t.modal!==!1?"true":"false"),t.ariaLabelledBy?(i.setAttribute("aria-labelledby",t.ariaLabelledBy),i.removeAttribute("aria-label")):(i.setAttribute("aria-label",t.ariaLabel||"Sheet"),i.removeAttribute("aria-labelledby")),e&&e.setAttribute("aria-hidden","true")}function k(i,e){i.removeAttribute("role"),i.removeAttribute("aria-modal"),e&&e.removeAttribute("aria-hidden")}var S=0,v=null;function O(i){let e=i.target;for(;e;){if(e.classList?.contains("drwr-content"))return;e=e.parentElement}i.preventDefault()}function y(){let i=document.body,e=document.documentElement;S++===0&&(v={body:i.style.overflow,html:e.style.overflow},e.style.overflow="hidden",i.style.overflow="hidden",document.addEventListener("touchmove",O,{passive:!1}));let t=!1;return()=>{t||(t=!0,!(--S>0)&&(S=0,i.style.overflow=v?.body??"",e.style.overflow=v?.html??"",v=null,document.removeEventListener("touchmove",O)))}}function $(i){return 8*(Math.log(i+1)-2)}var w=class i{constructor(e,t={}){this.overlayEl=null;this.handleEl=null;this.state="closed";this.currentSnap=0;this.currentH=0;this.dragStartH=0;this.cancelAnimation=null;this.cleanupGestures=null;this.cleanupFocusTrap=null;this.unlockScroll=null;this.onPageShow=null;this.onResize=null;this.naturalContentH=0;this.destroyed=!1;this.onKeyDown=e=>{e.key==="Escape"&&this.state!=="closed"&&this.options.closeOnEscape&&this.close()};this.container=e;let s=i.sanitizeSnapPoints(t.snapPoints??[0,1]);this.options={snapPoints:s,defaultSnap:t.defaultSnap??0,overlay:t.overlay??!0,dragHandle:t.dragHandle??!0,damping:t.damping??30,stiffness:t.stiffness??200,mass:t.mass??1,closeThreshold:t.closeThreshold??.2,topPadding:t.topPadding??40,width:t.width??(window.innerWidth>=768?60:100),align:t.align??"center",sidePadding:t.sidePadding??0,maxWidth:t.maxWidth??0,dragMode:t.dragMode??"sheet",ariaLabel:t.ariaLabel??"Sheet",ariaLabelledBy:t.ariaLabelledBy??"",closeOnEscape:t.closeOnEscape??!0,closeOnOverlayClick:t.closeOnOverlayClick??!0,trapFocus:t.trapFocus??!0,modal:t.modal??!0,reducedMotion:t.reducedMotion??!0,onOpen:t.onOpen??(()=>{}),onClose:t.onClose??(()=>{}),onSnap:t.onSnap??(()=>{})},this.buildDOM(),this.container.removeAttribute("hidden"),this.naturalContentH=this.getContentHeight(),this.bindGestures();let r=this.options.defaultSnap;r>0&&this.options.snapPoints.includes(r)?(this.currentH=this.snapToPixels(r),this.render(this.currentH),this.state="open",this.currentSnap=r,document.addEventListener("keydown",this.onKeyDown),this.unlockScroll||(this.unlockScroll=y()),this.options.trapFocus&&!this.cleanupFocusTrap&&(this.cleanupFocusTrap=b(this.wrapperEl)),queueMicrotask(()=>{this.destroyed||this.options.onOpen()})):(this.currentH=0,this.render(0)),this.onPageShow=n=>{n.persisted&&this.state!=="closed"&&this.resetToClosedState()},window.addEventListener("pageshow",this.onPageShow),this.onResize=()=>{this.applyLayout(),this.naturalContentH=this.getContentHeight(),this.state!=="closed"&&this.currentSnap>0&&(this.currentH=this.snapToPixels(this.currentSnap),this.render(this.currentH))},window.addEventListener("resize",this.onResize)}static sanitizeSnapPoints(e){let t=e.filter(r=>Number.isFinite(r)&&r>=0&&r<=1),s=[...new Set(t)].sort((r,n)=>r-n);return s.length===0?[0,1]:(s.includes(0)||s.unshift(0),s)}prefersReducedMotion(){return this.options.reducedMotion&&typeof window<"u"&&window.matchMedia("(prefers-reduced-motion: reduce)").matches}getContentHeight(){return this.contentEl.scrollHeight+(this.handleEl?.offsetHeight??0)}maxSheetH(){return window.innerHeight-this.options.topPadding}snapToPixels(e){if(e<=0)return 0;let t=this.maxSheetH();return Math.min(e,1)*t}snapPixels(){return this.options.snapPoints.map(e=>this.snapToPixels(e)).sort((e,t)=>e-t)}pixelsToSnap(e){let t=this.options.snapPoints,s=t[0],r=Math.abs(e-this.snapToPixels(t[0]));for(let n=1;n<t.length;n++){let a=Math.abs(e-this.snapToPixels(t[n]));a<r&&(s=t[n],r=a)}return s}applyLayout(){let{width:e,align:t,sidePadding:s,maxWidth:r}=this.options,n=this.wrapperEl,a=window.innerWidth,d=Math.max(10,Math.min(100,e)),o=Math.max(0,Math.min(s,a/2-10)),u=Math.max(20,Math.min(a*(d/100),a-o*2));r>0&&(u=Math.min(u,r));let c;t==="left"?c=o:t==="right"?c=a-u-o:c=(a-u)/2,n.style.left=`${c}px`,n.style.right="auto",n.style.width=`${u}px`,n.style.margin="0"}buildDOM(){for(this.wrapperEl=document.createElement("div"),this.wrapperEl.className="drwr-sheet",this.wrapperEl.setAttribute("tabindex","-1"),this.options.dragHandle&&(this.handleEl=document.createElement("div"),this.handleEl.className="drwr-handle",this.wrapperEl.appendChild(this.handleEl)),this.contentEl=document.createElement("div"),this.contentEl.className="drwr-content";this.container.firstChild;)this.contentEl.appendChild(this.container.firstChild);this.wrapperEl.appendChild(this.contentEl),this.container.appendChild(this.wrapperEl),this.options.overlay&&(this.overlayEl=document.createElement("div"),this.overlayEl.className="drwr-overlay",this.overlayEl.addEventListener("click",()=>{this.options.closeOnOverlayClick&&this.close()}),this.container.insertBefore(this.overlayEl,this.wrapperEl)),L(this.wrapperEl,this.overlayEl,{ariaLabel:this.options.ariaLabel,ariaLabelledBy:this.options.ariaLabelledBy,modal:this.options.modal}),this.applyLayout()}bindGestures(){this.options.dragMode!=="none"&&(this.cleanupGestures=A(this.wrapperEl,this.handleEl,this.options.dragMode==="handle",{onStart:()=>{this.cancelCurrentAnimation(),this.state="dragging",this.dragStartH=this.currentH,this.wrapperEl.setAttribute("data-dragging","true")},onMove:(e,t)=>{let s=this.dragStartH-t,r=this.snapPixels(),n=r[r.length-1],a=r[0];if(s>n)s=n;else if(s<a){let d=a-s;s=a-Math.max(0,$(d))}this.currentH=s,this.render(s)},onEnd:e=>{this.wrapperEl.setAttribute("data-dragging","false");let t=-e;this.state="animating";let s=this.snapPixels(),r=M(this.currentH,t,s,400),n=s.filter(a=>a>0);if(n.length>0){let a=n[0];this.currentH<a*this.options.closeThreshold&&(r=0)}this.animateToH(r,t)}}))}cancelCurrentAnimation(){this.cancelAnimation&&(this.cancelAnimation(),this.cancelAnimation=null)}animateToH(e,t=0){let s=this.state==="open"||this.state==="dragging";this.cancelCurrentAnimation(),this.state="animating";let r=()=>{this.currentH=e,this.render(e),this.cancelAnimation=null;let a=this.pixelsToSnap(e);this.currentSnap=a,e<=.5?this.onClosed():(this.state="open",s||this.options.onOpen(),this.options.onSnap(a))};if(this.prefersReducedMotion()){r();return}let n={damping:this.options.damping,stiffness:this.options.stiffness,mass:this.options.mass};this.cancelAnimation=H(this.currentH,e,t,n,a=>{this.currentH=a,this.render(a)},r)}render(e){let t=window.innerHeight,s=Math.max(0,e),r=t-s;if(this.wrapperEl.style.visibility=s>.5?"visible":"hidden",this.wrapperEl.style.transform=`translate3d(0, ${r}px, 0)`,this.wrapperEl.style.height=s>.5?`${s}px`:"",this.overlayEl){let n=this.snapPixels(),a=n[n.length-1],d=Math.max(0,Math.min(1,s/(a*.3)));this.overlayEl.style.opacity=String(d),this.overlayEl.setAttribute("data-visible",s>1?"true":"false")}}resetToClosedState(){this.cancelCurrentAnimation(),this.currentH=0,this.currentSnap=0,this.render(0),this.state="closed",this.overlayEl&&(this.overlayEl.style.opacity="0",this.overlayEl.setAttribute("data-visible","false")),this.unlockScroll&&(this.unlockScroll(),this.unlockScroll=null),this.cleanupFocusTrap&&(this.cleanupFocusTrap(),this.cleanupFocusTrap=null),document.removeEventListener("keydown",this.onKeyDown)}onClosed(){this.resetToClosedState(),this.options.onClose()}open(e){if(this.destroyed||this.state==="open")return;let t=[...this.options.snapPoints].sort((r,n)=>r-n),s;if(e!==void 0){if(!t.includes(e)||e===0){console.warn(`[drwr] snap point ${e} not valid for open()`);return}s=e}else s=t[t.length-1];document.addEventListener("keydown",this.onKeyDown),this.animateToH(this.snapToPixels(s)),this.unlockScroll||(this.unlockScroll=y()),this.options.trapFocus&&!this.cleanupFocusTrap&&(this.cleanupFocusTrap=b(this.wrapperEl))}close(){this.destroyed||this.state==="closed"||(document.removeEventListener("keydown",this.onKeyDown),this.animateToH(0))}snapTo(e){if(!this.destroyed){if(!this.options.snapPoints.includes(e)){console.warn(`[drwr] snap point ${e} not in snapPoints`);return}e===0?this.close():(this.state==="closed"&&(document.addEventListener("keydown",this.onKeyDown),this.unlockScroll||(this.unlockScroll=y()),this.options.trapFocus&&!this.cleanupFocusTrap&&(this.cleanupFocusTrap=b(this.wrapperEl))),this.animateToH(this.snapToPixels(e)))}}destroy(){if(!this.destroyed){for(this.destroyed=!0,this.cancelCurrentAnimation(),document.removeEventListener("keydown",this.onKeyDown),this.cleanupGestures&&(this.cleanupGestures(),this.cleanupGestures=null),this.cleanupFocusTrap&&(this.cleanupFocusTrap(),this.cleanupFocusTrap=null),this.unlockScroll&&(this.unlockScroll(),this.unlockScroll=null),this.onPageShow&&(window.removeEventListener("pageshow",this.onPageShow),this.onPageShow=null),this.onResize&&(window.removeEventListener("resize",this.onResize),this.onResize=null),k(this.wrapperEl,this.overlayEl);this.contentEl.firstChild;)this.container.appendChild(this.contentEl.firstChild);this.wrapperEl.remove(),this.overlayEl?.remove()}}setSnapPoints(e){if(!this.destroyed&&(this.options.snapPoints=i.sanitizeSnapPoints(e),this.state!=="closed"&&this.currentSnap>0&&!this.options.snapPoints.includes(this.currentSnap))){let t=this.pixelsToSnap(this.currentH);this.animateToH(this.snapToPixels(t))}}refresh(){this.destroyed||(this.naturalContentH=this.getContentHeight(),this.state!=="closed"&&this.currentSnap>0&&(this.currentH=this.snapToPixels(this.currentSnap),this.render(this.currentH)))}setOptions(e){if(this.destroyed)return;if(e.snapPoints!==void 0&&(this.options.snapPoints=i.sanitizeSnapPoints(e.snapPoints)),e.damping!==void 0&&(this.options.damping=e.damping),e.stiffness!==void 0&&(this.options.stiffness=e.stiffness),e.mass!==void 0&&(this.options.mass=e.mass),e.closeThreshold!==void 0&&(this.options.closeThreshold=e.closeThreshold),e.topPadding!==void 0&&(this.options.topPadding=e.topPadding),e.closeOnEscape!==void 0&&(this.options.closeOnEscape=e.closeOnEscape),e.closeOnOverlayClick!==void 0&&(this.options.closeOnOverlayClick=e.closeOnOverlayClick),e.ariaLabel!==void 0&&(this.options.ariaLabel=e.ariaLabel),e.ariaLabelledBy!==void 0&&(this.options.ariaLabelledBy=e.ariaLabelledBy),e.modal!==void 0&&(this.options.modal=e.modal),e.maxWidth!==void 0&&(this.options.maxWidth=e.maxWidth),e.reducedMotion!==void 0&&(this.options.reducedMotion=e.reducedMotion),e.onOpen!==void 0&&(this.options.onOpen=e.onOpen),e.onClose!==void 0&&(this.options.onClose=e.onClose),e.onSnap!==void 0&&(this.options.onSnap=e.onSnap),(e.ariaLabel!==void 0||e.ariaLabelledBy!==void 0||e.modal!==void 0)&&L(this.wrapperEl,this.overlayEl,{ariaLabel:this.options.ariaLabel,ariaLabelledBy:this.options.ariaLabelledBy,modal:this.options.modal}),(e.width!==void 0||e.align!==void 0||e.sidePadding!==void 0||e.maxWidth!==void 0)&&(e.width!==void 0&&(this.options.width=e.width),e.align!==void 0&&(this.options.align=e.align),e.sidePadding!==void 0&&(this.options.sidePadding=e.sidePadding),this.applyLayout()),(e.topPadding!==void 0||e.snapPoints!==void 0)&&this.state!=="closed"&&this.currentSnap>0)if(e.snapPoints!==void 0&&!this.options.snapPoints.includes(this.currentSnap)){let s=this.pixelsToSnap(this.currentH);this.animateToH(this.snapToPixels(s))}else this.currentH=this.snapToPixels(this.currentSnap),this.render(this.currentH)}setLayout(e){this.destroyed||(e.width!==void 0&&(this.options.width=e.width),e.align!==void 0&&(this.options.align=e.align),e.sidePadding!==void 0&&(this.options.sidePadding=e.sidePadding),this.applyLayout())}get isOpen(){return this.state!=="closed"}get currentSnapPoint(){return this.currentSnap}};0&&(module.exports={Sheet});
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/physics.ts","../src/gestures.ts","../src/accessibility.ts","../src/sheet.ts"],"sourcesContent":["export { Sheet } from \"./sheet.js\";\nexport type { SheetOptions, MutableSheetOptions, SheetAlign, DragMode } from \"./sheet.js\";\nexport type { SpringConfig } from \"./physics.js\";\n","export interface SpringConfig {\n damping: number;\n stiffness: number;\n mass: number;\n restThreshold: number;\n}\n\nexport const DEFAULT_SPRING: SpringConfig = {\n damping: 30,\n stiffness: 200,\n mass: 1,\n restThreshold: 0.5,\n};\n\nexport interface SpringState {\n position: number;\n velocity: number;\n}\n\n/**\n * Solve one step of a damped spring using semi-implicit Euler integration.\n * Returns the new position and velocity after `dt` seconds.\n */\nexport function springStep(\n current: number,\n target: number,\n velocity: number,\n dt: number,\n config: SpringConfig,\n): SpringState {\n const { stiffness, damping, mass } = config;\n const displacement = current - target;\n const springForce = -stiffness * displacement;\n const dampingForce = -damping * velocity;\n const acceleration = (springForce + dampingForce) / mass;\n\n const newVelocity = velocity + acceleration * dt;\n const newPosition = current + newVelocity * dt;\n\n return { position: newPosition, velocity: newVelocity };\n}\n\n/**\n * Returns true when the spring is close enough to rest.\n */\nexport function isAtRest(\n current: number,\n target: number,\n velocity: number,\n threshold: number = DEFAULT_SPRING.restThreshold,\n): boolean {\n return (\n Math.abs(current - target) < threshold && Math.abs(velocity) < threshold\n );\n}\n\n/**\n * Runs a spring animation via requestAnimationFrame. Returns a cancel function.\n */\nexport function animateSpring(\n from: number,\n to: number,\n initialVelocity: number,\n config: Partial<SpringConfig>,\n onUpdate: (value: number) => void,\n onComplete: () => void,\n): () => void {\n const cfg = { ...DEFAULT_SPRING, ...config };\n let position = from;\n let velocity = initialVelocity;\n let lastTime = 0;\n let frameId = 0;\n\n function tick(time: number) {\n if (lastTime === 0) {\n lastTime = time;\n frameId = requestAnimationFrame(tick);\n return;\n }\n\n // Cap dt to avoid spiral of death on tab-switch resume\n const dt = Math.min((time - lastTime) / 1000, 0.064);\n lastTime = time;\n\n const state = springStep(position, to, velocity, dt, cfg);\n position = state.position;\n velocity = state.velocity;\n\n onUpdate(position);\n\n if (isAtRest(position, to, velocity, cfg.restThreshold)) {\n onUpdate(to);\n onComplete();\n return;\n }\n\n frameId = requestAnimationFrame(tick);\n }\n\n frameId = requestAnimationFrame(tick);\n\n return () => cancelAnimationFrame(frameId);\n}\n\n/**\n * Tracks pointer velocity over the last N samples for flick detection.\n */\nexport class VelocityTracker {\n private samples: { time: number; value: number }[] = [];\n private maxSamples: number;\n\n constructor(maxSamples = 8) {\n this.maxSamples = maxSamples;\n }\n\n add(value: number) {\n this.samples.push({ time: performance.now(), value });\n if (this.samples.length > this.maxSamples) {\n this.samples.shift();\n }\n }\n\n /** Returns velocity in units per second. */\n getVelocity(): number {\n if (this.samples.length < 2) return 0;\n\n const recent = this.samples[this.samples.length - 1];\n // Use sample from ~50ms ago for stability\n let oldest = this.samples[0];\n for (let i = this.samples.length - 2; i >= 0; i--) {\n if (recent.time - this.samples[i].time >= 30) {\n oldest = this.samples[i];\n break;\n }\n }\n\n const dt = (recent.time - oldest.time) / 1000;\n if (dt === 0) return 0;\n\n return (recent.value - oldest.value) / dt;\n }\n\n reset() {\n this.samples = [];\n }\n}\n\n/**\n * Given a set of snap points and a release position + velocity,\n * determine which snap point to target.\n */\nexport function resolveSnapPoint(\n position: number,\n velocity: number,\n snapPoints: number[],\n flickThreshold = 400,\n hardFlickThreshold = 1200,\n): number {\n if (snapPoints.length === 0) return position;\n if (snapPoints.length === 1) return snapPoints[0];\n\n const sorted = [...snapPoints].sort((a, b) => a - b);\n\n // Hard flick: skip all intermediate snaps, go to the extreme\n if (Math.abs(velocity) > hardFlickThreshold) {\n return velocity > 0 ? sorted[sorted.length - 1] : sorted[0];\n }\n\n // Normal flick: go to next snap in the flick direction\n if (Math.abs(velocity) > flickThreshold) {\n if (velocity > 0) {\n for (const sp of sorted) {\n if (sp > position + 2) return sp;\n }\n return sorted[sorted.length - 1];\n } else {\n for (let i = sorted.length - 1; i >= 0; i--) {\n if (sorted[i] < position - 2) return sorted[i];\n }\n return sorted[0];\n }\n }\n\n // No flick: snap to nearest\n let closest = sorted[0];\n let closestDist = Math.abs(position - sorted[0]);\n for (let i = 1; i < sorted.length; i++) {\n const dist = Math.abs(position - sorted[i]);\n if (dist < closestDist) {\n closest = sorted[i];\n closestDist = dist;\n }\n }\n return closest;\n}\n","import { VelocityTracker } from \"./physics.js\";\n\nexport interface GestureCallbacks {\n onStart: (y: number) => void;\n onMove: (y: number, deltaY: number) => void;\n onEnd: (velocity: number) => void;\n}\n\ninterface GestureState {\n active: boolean;\n dragging: boolean;\n startY: number;\n currentY: number;\n directionLocked: boolean;\n lockedAxis: \"x\" | \"y\" | null;\n startX: number;\n currentX: number;\n scrolling: boolean;\n scrollTarget: HTMLElement | null;\n}\n\nconst DIRECTION_LOCK_THRESHOLD = 6;\nconst SCROLL_LOCK_THRESHOLD = 3;\n\nfunction findScrollableAncestor(\n target: EventTarget | null,\n sheetEl: HTMLElement,\n): HTMLElement | null {\n let el = target as HTMLElement | null;\n while (el && el !== sheetEl) {\n if (el.scrollHeight > el.clientHeight) {\n const style = getComputedStyle(el);\n const overflowY = style.overflowY;\n if (overflowY === \"auto\" || overflowY === \"scroll\") {\n return el;\n }\n }\n el = el.parentElement;\n }\n return null;\n}\n\nexport function attachGestures(\n sheetEl: HTMLElement,\n handleEl: HTMLElement | null,\n handleOnly: boolean,\n callbacks: GestureCallbacks,\n): () => void {\n const tracker = new VelocityTracker();\n const state: GestureState = {\n active: false,\n dragging: false,\n startY: 0,\n currentY: 0,\n directionLocked: false,\n lockedAxis: null,\n startX: 0,\n currentX: 0,\n scrolling: false,\n scrollTarget: null,\n };\n\n function onPointerDown(e: PointerEvent) {\n const isHandle = handleEl?.contains(e.target as Node);\n if (handleOnly && !isHandle) return;\n const scrollable = isHandle\n ? null\n : findScrollableAncestor(e.target, sheetEl);\n\n state.active = true;\n state.dragging = false;\n state.startY = e.clientY;\n state.currentY = e.clientY;\n state.startX = e.clientX;\n state.currentX = e.clientX;\n state.directionLocked = false;\n state.lockedAxis = null;\n state.scrolling = false;\n state.scrollTarget = scrollable;\n\n tracker.reset();\n tracker.add(e.clientY);\n\n sheetEl.setPointerCapture(e.pointerId);\n }\n\n function onPointerMove(e: PointerEvent) {\n if (!state.active || state.scrolling) return;\n\n state.currentY = e.clientY;\n state.currentX = e.clientX;\n\n const dx = Math.abs(state.currentX - state.startX);\n const dy = Math.abs(state.currentY - state.startY);\n const deltaY = state.currentY - state.startY;\n\n // Direction locking\n if (!state.directionLocked) {\n if (dx > DIRECTION_LOCK_THRESHOLD || dy > DIRECTION_LOCK_THRESHOLD) {\n state.directionLocked = true;\n state.lockedAxis = dy >= dx ? \"y\" : \"x\";\n }\n if (dy < SCROLL_LOCK_THRESHOLD) return;\n }\n\n if (state.lockedAxis === \"x\") return;\n\n // Scroll vs drag disambiguation (decided once)\n if (state.scrollTarget && !state.dragging) {\n const st = state.scrollTarget;\n const atTop = st.scrollTop <= 0;\n const atBottom = st.scrollTop + st.clientHeight >= st.scrollHeight - 1;\n const draggingDown = deltaY > 0;\n\n if (draggingDown && atTop) {\n // At top, pulling down → drag sheet\n } else if (!draggingDown && atBottom) {\n // At bottom, pulling up → drag sheet\n } else {\n // Let the content scroll\n state.scrolling = true;\n return;\n }\n }\n\n // Begin drag on first qualifying move\n if (!state.dragging) {\n state.dragging = true;\n callbacks.onStart(state.startY);\n }\n\n e.preventDefault();\n tracker.add(e.clientY);\n callbacks.onMove(state.currentY, deltaY);\n }\n\n function onPointerUp(e: PointerEvent) {\n if (!state.active) return;\n state.active = false;\n sheetEl.releasePointerCapture(e.pointerId);\n\n if (!state.dragging) return;\n state.dragging = false;\n\n const velocity = tracker.getVelocity();\n callbacks.onEnd(velocity);\n }\n\n function onPointerCancel(e: PointerEvent) {\n if (!state.active) return;\n state.active = false;\n sheetEl.releasePointerCapture(e.pointerId);\n\n if (!state.dragging) return;\n state.dragging = false;\n callbacks.onEnd(0);\n }\n\n sheetEl.addEventListener(\"pointerdown\", onPointerDown);\n sheetEl.addEventListener(\"pointermove\", onPointerMove);\n sheetEl.addEventListener(\"pointerup\", onPointerUp);\n sheetEl.addEventListener(\"pointercancel\", onPointerCancel);\n\n const onContextMenu = (e: Event) => {\n if (state.active) e.preventDefault();\n };\n sheetEl.addEventListener(\"contextmenu\", onContextMenu);\n\n return () => {\n sheetEl.removeEventListener(\"pointerdown\", onPointerDown);\n sheetEl.removeEventListener(\"pointermove\", onPointerMove);\n sheetEl.removeEventListener(\"pointerup\", onPointerUp);\n sheetEl.removeEventListener(\"pointercancel\", onPointerCancel);\n sheetEl.removeEventListener(\"contextmenu\", onContextMenu);\n };\n}\n","const FOCUSABLE_SELECTORS = [\n \"a[href]\",\n \"button:not([disabled])\",\n \"input:not([disabled])\",\n \"select:not([disabled])\",\n \"textarea:not([disabled])\",\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(\", \");\n\n/**\n * Creates a focus trap within the given element.\n * Returns a cleanup function.\n */\nexport function createFocusTrap(container: HTMLElement): () => void {\n let previousFocus: HTMLElement | null = null;\n\n function getFocusable(): HTMLElement[] {\n return Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTORS));\n }\n\n function onKeyDown(e: KeyboardEvent) {\n if (e.key !== \"Tab\") return;\n\n const focusable = getFocusable();\n if (focusable.length === 0) {\n e.preventDefault();\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first || !container.contains(document.activeElement)) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last || !container.contains(document.activeElement)) {\n e.preventDefault();\n first.focus();\n }\n }\n }\n\n function activate() {\n previousFocus = document.activeElement as HTMLElement | null;\n container.addEventListener(\"keydown\", onKeyDown);\n\n // Focus first focusable element or the container itself\n requestAnimationFrame(() => {\n const focusable = getFocusable();\n if (focusable.length > 0) {\n focusable[0].focus();\n } else {\n container.focus();\n }\n });\n }\n\n function deactivate() {\n container.removeEventListener(\"keydown\", onKeyDown);\n previousFocus?.focus();\n previousFocus = null;\n }\n\n activate();\n\n return deactivate;\n}\n\nexport interface AriaOptions {\n ariaLabel?: string;\n ariaLabelledBy?: string;\n modal?: boolean;\n}\n\n/**\n * Applies ARIA attributes for a modal dialog.\n */\nexport function applyAriaAttributes(\n sheetEl: HTMLElement,\n overlayEl: HTMLElement | null,\n opts: AriaOptions = {},\n) {\n sheetEl.setAttribute(\"role\", \"dialog\");\n sheetEl.setAttribute(\"aria-modal\", opts.modal !== false ? \"true\" : \"false\");\n\n if (opts.ariaLabelledBy) {\n sheetEl.setAttribute(\"aria-labelledby\", opts.ariaLabelledBy);\n sheetEl.removeAttribute(\"aria-label\");\n } else {\n sheetEl.setAttribute(\"aria-label\", opts.ariaLabel || \"Sheet\");\n sheetEl.removeAttribute(\"aria-labelledby\");\n }\n\n if (overlayEl) {\n overlayEl.setAttribute(\"aria-hidden\", \"true\");\n }\n}\n\n/**\n * Removes ARIA attributes when the sheet is destroyed.\n */\nexport function removeAriaAttributes(\n sheetEl: HTMLElement,\n overlayEl: HTMLElement | null,\n) {\n sheetEl.removeAttribute(\"role\");\n sheetEl.removeAttribute(\"aria-modal\");\n if (overlayEl) {\n overlayEl.removeAttribute(\"aria-hidden\");\n }\n}\n\n/**\n * iOS-safe scroll lock. Prevents background scrolling without position:fixed\n * to avoid the iOS Safari viewport jump when the address bar is visible.\n */\nexport function lockScroll(): () => void {\n const body = document.body;\n const html = document.documentElement;\n\n const originalBodyOverflow = body.style.overflow;\n const originalHtmlOverflow = html.style.overflow;\n\n html.style.overflow = \"hidden\";\n body.style.overflow = \"hidden\";\n\n // On iOS Safari, overflow:hidden on body/html doesn't fully prevent\n // scroll on its own. We block touchmove on the document as a fallback.\n const preventTouch = (e: TouchEvent) => {\n // Allow scrolling inside the sheet content\n let el = e.target as HTMLElement | null;\n while (el) {\n if (el.classList?.contains(\"drwr-content\")) return;\n el = el.parentElement;\n }\n e.preventDefault();\n };\n\n document.addEventListener(\"touchmove\", preventTouch, { passive: false });\n\n return () => {\n body.style.overflow = originalBodyOverflow;\n html.style.overflow = originalHtmlOverflow;\n document.removeEventListener(\"touchmove\", preventTouch);\n };\n}\n","import {\n animateSpring,\n resolveSnapPoint,\n type SpringConfig,\n} from \"./physics.js\";\nimport { attachGestures } from \"./gestures.js\";\nimport {\n applyAriaAttributes,\n removeAriaAttributes,\n createFocusTrap,\n lockScroll,\n} from \"./accessibility.js\";\n\nexport type SheetAlign = \"center\" | \"left\" | \"right\";\nexport type DragMode = \"handle\" | \"sheet\" | \"none\";\n\nexport interface SheetOptions {\n snapPoints?: number[];\n defaultSnap?: number;\n overlay?: boolean;\n dragHandle?: boolean;\n damping?: number;\n stiffness?: number;\n mass?: number;\n closeThreshold?: number;\n /** Top padding in px for the maximum open height. Default: 40. */\n topPadding?: number;\n /** Width as a percentage of the viewport (0–100). Default: 60 on desktop, 100 on mobile. */\n width?: number;\n /** Horizontal alignment. Default: \"center\". */\n align?: SheetAlign;\n /** Minimum side padding in px. Default: 0. */\n sidePadding?: number;\n /** Max width in px. 0 = no max. Default: 0. */\n maxWidth?: number;\n /** Which part of the sheet initiates drag. Default: \"sheet\". */\n dragMode?: DragMode;\n /** Accessible label for the sheet dialog. Default: \"Sheet\". */\n ariaLabel?: string;\n /** ID of the element labelling the sheet. Overrides ariaLabel when set. */\n ariaLabelledBy?: string;\n /** Close on Escape key. Default: true. */\n closeOnEscape?: boolean;\n /** Close on overlay click. Default: true. */\n closeOnOverlayClick?: boolean;\n /** Trap focus inside the sheet. Default: true. */\n trapFocus?: boolean;\n /** Set aria-modal. Default: true. */\n modal?: boolean;\n /** Honour prefers-reduced-motion by skipping spring animation. Default: true. */\n reducedMotion?: boolean;\n /** Called when open animation completes. */\n onOpen?: () => void;\n /** Called when close animation completes. */\n onClose?: () => void;\n onSnap?: (point: number) => void;\n}\n\n/** Subset of SheetOptions that can be changed at runtime via setOptions(). */\nexport type MutableSheetOptions = Pick<\n SheetOptions,\n | \"snapPoints\"\n | \"damping\"\n | \"stiffness\"\n | \"mass\"\n | \"closeThreshold\"\n | \"topPadding\"\n | \"width\"\n | \"align\"\n | \"sidePadding\"\n | \"maxWidth\"\n | \"ariaLabel\"\n | \"ariaLabelledBy\"\n | \"closeOnEscape\"\n | \"closeOnOverlayClick\"\n | \"modal\"\n | \"reducedMotion\"\n | \"onOpen\"\n | \"onClose\"\n | \"onSnap\"\n>;\n\ntype SheetState = \"closed\" | \"open\" | \"dragging\" | \"animating\";\n\n/** Logarithmic resistance like vaul: soft, organic feel past bounds. */\nfunction dampen(v: number): number {\n return 8 * (Math.log(v + 1) - 2);\n}\n\nexport class Sheet {\n private container: HTMLElement;\n private options: Required<SheetOptions>;\n\n private wrapperEl!: HTMLElement;\n private overlayEl: HTMLElement | null = null;\n private handleEl: HTMLElement | null = null;\n private contentEl!: HTMLElement;\n\n private state: SheetState = \"closed\";\n private currentSnap = 0;\n // Current height of the sheet in pixels (0 = closed, positive = visible)\n private currentH = 0;\n private dragStartH = 0;\n\n private cancelAnimation: (() => void) | null = null;\n private cleanupGestures: (() => void) | null = null;\n private cleanupFocusTrap: (() => void) | null = null;\n private unlockScroll: (() => void) | null = null;\n private onPageShow: ((e: PageTransitionEvent) => void) | null = null;\n private onResize: (() => void) | null = null;\n private naturalContentH = 0;\n private destroyed = false;\n\n private static sanitizeSnapPoints(raw: number[]): number[] {\n const valid = raw.filter((n) => Number.isFinite(n) && n >= 0 && n <= 1);\n const deduped = [...new Set(valid)].sort((a, b) => a - b);\n if (deduped.length === 0) return [0, 1];\n if (!deduped.includes(0)) deduped.unshift(0);\n return deduped;\n }\n\n private prefersReducedMotion(): boolean {\n return (\n this.options.reducedMotion &&\n typeof window !== \"undefined\" &&\n window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches\n );\n }\n\n constructor(container: HTMLElement, options: SheetOptions = {}) {\n this.container = container;\n const snaps = Sheet.sanitizeSnapPoints(options.snapPoints ?? [0, 1]);\n this.options = {\n snapPoints: snaps,\n defaultSnap: options.defaultSnap ?? 0,\n overlay: options.overlay ?? true,\n dragHandle: options.dragHandle ?? true,\n damping: options.damping ?? 30,\n stiffness: options.stiffness ?? 200,\n mass: options.mass ?? 1,\n closeThreshold: options.closeThreshold ?? 0.2,\n topPadding: options.topPadding ?? 40,\n width: options.width ?? (window.innerWidth >= 768 ? 60 : 100),\n align: options.align ?? \"center\",\n sidePadding: options.sidePadding ?? 0,\n maxWidth: options.maxWidth ?? 0,\n dragMode: options.dragMode ?? \"sheet\",\n ariaLabel: options.ariaLabel ?? \"Sheet\",\n ariaLabelledBy: options.ariaLabelledBy ?? \"\",\n closeOnEscape: options.closeOnEscape ?? true,\n closeOnOverlayClick: options.closeOnOverlayClick ?? true,\n trapFocus: options.trapFocus ?? true,\n modal: options.modal ?? true,\n reducedMotion: options.reducedMotion ?? true,\n onOpen: options.onOpen ?? (() => {}),\n onClose: options.onClose ?? (() => {}),\n onSnap: options.onSnap ?? (() => {}),\n };\n\n this.buildDOM();\n this.container.removeAttribute(\"hidden\");\n this.naturalContentH = this.getContentHeight();\n this.bindGestures();\n\n const defaultSnap = this.options.defaultSnap;\n if (defaultSnap > 0 && this.options.snapPoints.includes(defaultSnap)) {\n this.currentH = this.snapToPixels(defaultSnap);\n this.render(this.currentH);\n this.state = \"open\";\n this.currentSnap = defaultSnap;\n document.addEventListener(\"keydown\", this.onKeyDown);\n if (!this.unlockScroll) this.unlockScroll = lockScroll();\n if (this.options.trapFocus && !this.cleanupFocusTrap) {\n this.cleanupFocusTrap = createFocusTrap(this.wrapperEl);\n }\n queueMicrotask(() => {\n if (this.destroyed) return;\n this.options.onOpen();\n });\n } else {\n this.currentH = 0;\n this.render(0);\n }\n this.onPageShow = (e: PageTransitionEvent) => {\n if (e.persisted && this.state !== \"closed\") {\n this.resetToClosedState();\n }\n };\n window.addEventListener(\"pageshow\", this.onPageShow);\n\n this.onResize = () => {\n this.applyLayout();\n this.naturalContentH = this.getContentHeight();\n if (this.state !== \"closed\" && this.currentSnap > 0) {\n this.currentH = this.snapToPixels(this.currentSnap);\n this.render(this.currentH);\n }\n };\n window.addEventListener(\"resize\", this.onResize);\n }\n\n // --- Snap point conversion ---\n\n private getContentHeight(): number {\n return this.contentEl.scrollHeight + (this.handleEl?.offsetHeight ?? 0);\n }\n\n private maxSheetH(): number {\n return window.innerHeight - this.options.topPadding;\n }\n\n /** Convert a normalized snap point (0–1) to available viewport height. */\n private snapToPixels(snap: number): number {\n if (snap <= 0) return 0;\n const maxH = this.maxSheetH();\n return Math.min(snap, 1) * maxH;\n }\n\n /** Get all snap points as pixel heights, sorted ascending. */\n private snapPixels(): number[] {\n return this.options.snapPoints\n .map((s) => this.snapToPixels(s))\n .sort((a, b) => a - b);\n }\n\n /** Find the normalized snap point closest to a pixel height. */\n private pixelsToSnap(px: number): number {\n const snaps = this.options.snapPoints;\n let closest = snaps[0];\n let closestDist = Math.abs(px - this.snapToPixels(snaps[0]));\n for (let i = 1; i < snaps.length; i++) {\n const dist = Math.abs(px - this.snapToPixels(snaps[i]));\n if (dist < closestDist) {\n closest = snaps[i];\n closestDist = dist;\n }\n }\n return closest;\n }\n\n // --- DOM ---\n\n private applyLayout() {\n const { width, align, sidePadding, maxWidth } = this.options;\n const el = this.wrapperEl;\n\n const vw = window.innerWidth;\n const clampedWidth = Math.max(10, Math.min(100, width));\n const pad = Math.max(0, Math.min(sidePadding, vw / 2 - 10));\n\n let sheetW = Math.max(20, Math.min(vw * (clampedWidth / 100), vw - pad * 2));\n if (maxWidth > 0) sheetW = Math.min(sheetW, maxWidth);\n\n let left: number;\n if (align === \"left\") {\n left = pad;\n } else if (align === \"right\") {\n left = vw - sheetW - pad;\n } else {\n left = (vw - sheetW) / 2;\n }\n\n el.style.left = `${left}px`;\n el.style.right = \"auto\";\n el.style.width = `${sheetW}px`;\n el.style.margin = \"0\";\n }\n\n private buildDOM() {\n this.wrapperEl = document.createElement(\"div\");\n this.wrapperEl.className = \"drwr-sheet\";\n this.wrapperEl.setAttribute(\"tabindex\", \"-1\");\n\n if (this.options.dragHandle) {\n this.handleEl = document.createElement(\"div\");\n this.handleEl.className = \"drwr-handle\";\n this.wrapperEl.appendChild(this.handleEl);\n }\n\n this.contentEl = document.createElement(\"div\");\n this.contentEl.className = \"drwr-content\";\n\n while (this.container.firstChild) {\n this.contentEl.appendChild(this.container.firstChild);\n }\n this.wrapperEl.appendChild(this.contentEl);\n this.container.appendChild(this.wrapperEl);\n\n if (this.options.overlay) {\n this.overlayEl = document.createElement(\"div\");\n this.overlayEl.className = \"drwr-overlay\";\n this.overlayEl.addEventListener(\"click\", () => {\n if (this.options.closeOnOverlayClick) this.close();\n });\n this.container.insertBefore(this.overlayEl, this.wrapperEl);\n }\n\n applyAriaAttributes(this.wrapperEl, this.overlayEl, {\n ariaLabel: this.options.ariaLabel,\n ariaLabelledBy: this.options.ariaLabelledBy,\n modal: this.options.modal,\n });\n this.applyLayout();\n }\n\n // --- Gestures ---\n\n private bindGestures() {\n if (this.options.dragMode === \"none\") return;\n this.cleanupGestures = attachGestures(\n this.wrapperEl,\n this.handleEl,\n this.options.dragMode === \"handle\",\n {\n onStart: () => {\n this.cancelCurrentAnimation();\n this.state = \"dragging\";\n this.dragStartH = this.currentH;\n this.wrapperEl.setAttribute(\"data-dragging\", \"true\");\n },\n onMove: (_y, deltaY) => {\n // deltaY positive = finger moved down = sheet should shrink\n let newH = this.dragStartH - deltaY;\n\n const snaps = this.snapPixels();\n const maxH = snaps[snaps.length - 1];\n const minH = snaps[0];\n\n if (newH > maxH) {\n newH = maxH;\n } else if (newH < minH) {\n const overflow = minH - newH;\n newH = minH - Math.max(0, dampen(overflow));\n }\n\n this.currentH = newH;\n this.render(newH);\n },\n onEnd: (velocityPx) => {\n this.wrapperEl.setAttribute(\"data-dragging\", \"false\");\n const velocityH = -velocityPx;\n this.state = \"animating\";\n\n const snaps = this.snapPixels();\n let targetH = resolveSnapPoint(this.currentH, velocityH, snaps, 400);\n\n // closeThreshold: if the sheet is dragged below (lowestNonZeroSnap * threshold), close it\n const nonZeroSnaps = snaps.filter((s) => s > 0);\n if (nonZeroSnaps.length > 0) {\n const lowestNonZero = nonZeroSnaps[0];\n if (this.currentH < lowestNonZero * this.options.closeThreshold) {\n targetH = 0;\n }\n }\n\n this.animateToH(targetH, velocityH);\n },\n },\n );\n }\n\n // --- Animation ---\n\n private cancelCurrentAnimation() {\n if (this.cancelAnimation) {\n this.cancelAnimation();\n this.cancelAnimation = null;\n }\n }\n\n private animateToH(targetH: number, initialVelocity = 0) {\n const wasOpen = this.state === \"open\" || this.state === \"dragging\";\n this.cancelCurrentAnimation();\n this.state = \"animating\";\n const onDone = () => {\n this.currentH = targetH;\n this.render(targetH);\n this.cancelAnimation = null;\n\n const snap = this.pixelsToSnap(targetH);\n this.currentSnap = snap;\n\n if (targetH <= 0.5) {\n this.onClosed();\n } else {\n this.state = \"open\";\n if (!wasOpen) this.options.onOpen();\n this.options.onSnap(snap);\n }\n };\n\n if (this.prefersReducedMotion()) {\n onDone();\n return;\n }\n\n const springConfig: Partial<SpringConfig> = {\n damping: this.options.damping,\n stiffness: this.options.stiffness,\n mass: this.options.mass,\n };\n\n this.cancelAnimation = animateSpring(\n this.currentH,\n targetH,\n initialVelocity,\n springConfig,\n (value) => {\n this.currentH = value;\n this.render(value);\n },\n onDone,\n );\n }\n\n // --- Rendering ---\n\n private render(h: number) {\n const viewportH = window.innerHeight;\n const visibleH = Math.max(0, h);\n const translateY = viewportH - visibleH;\n\n this.wrapperEl.style.visibility = visibleH > 0.5 ? \"visible\" : \"hidden\";\n\n this.wrapperEl.style.transform = `translate3d(0, ${translateY}px, 0)`;\n this.wrapperEl.style.height = visibleH > 0.5 ? `${visibleH}px` : \"\";\n\n if (this.overlayEl) {\n const snaps = this.snapPixels();\n const maxH = snaps[snaps.length - 1];\n const opacity = Math.max(0, Math.min(1, visibleH / (maxH * 0.3)));\n this.overlayEl.style.opacity = String(opacity);\n this.overlayEl.setAttribute(\"data-visible\", visibleH > 1 ? \"true\" : \"false\");\n }\n }\n\n // --- State changes ---\n\n /** Shared cleanup: visually close and tear down locks/traps. Does NOT fire callbacks. */\n private resetToClosedState() {\n this.cancelCurrentAnimation();\n this.currentH = 0;\n this.currentSnap = 0;\n this.render(0);\n this.state = \"closed\";\n\n if (this.overlayEl) {\n this.overlayEl.style.opacity = \"0\";\n this.overlayEl.setAttribute(\"data-visible\", \"false\");\n }\n if (this.unlockScroll) {\n this.unlockScroll();\n this.unlockScroll = null;\n }\n if (this.cleanupFocusTrap) {\n this.cleanupFocusTrap();\n this.cleanupFocusTrap = null;\n }\n document.removeEventListener(\"keydown\", this.onKeyDown);\n }\n\n private onClosed() {\n this.resetToClosedState();\n this.options.onClose();\n }\n\n // --- Keyboard ---\n\n private onKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\" && this.state !== \"closed\" && this.options.closeOnEscape) {\n this.close();\n }\n };\n\n // --- Public API ---\n\n open(point?: number) {\n if (this.destroyed || this.state === \"open\") return;\n\n const sorted = [...this.options.snapPoints].sort((a, b) => a - b);\n let target: number;\n if (point !== undefined) {\n if (!sorted.includes(point) || point === 0) {\n console.warn(`[drwr] snap point ${point} not valid for open()`);\n return;\n }\n target = point;\n } else {\n target = sorted[sorted.length - 1];\n }\n\n document.addEventListener(\"keydown\", this.onKeyDown);\n this.animateToH(this.snapToPixels(target));\n if (!this.unlockScroll) this.unlockScroll = lockScroll();\n if (this.options.trapFocus && !this.cleanupFocusTrap) {\n this.cleanupFocusTrap = createFocusTrap(this.wrapperEl);\n }\n }\n\n close() {\n if (this.destroyed || this.state === \"closed\") return;\n document.removeEventListener(\"keydown\", this.onKeyDown);\n this.animateToH(0);\n }\n\n snapTo(point: number) {\n if (this.destroyed) return;\n if (!this.options.snapPoints.includes(point)) {\n console.warn(`[drwr] snap point ${point} not in snapPoints`);\n return;\n }\n if (point === 0) {\n this.close();\n } else {\n if (this.state === \"closed\") {\n document.addEventListener(\"keydown\", this.onKeyDown);\n if (!this.unlockScroll) this.unlockScroll = lockScroll();\n if (this.options.trapFocus && !this.cleanupFocusTrap) {\n this.cleanupFocusTrap = createFocusTrap(this.wrapperEl);\n }\n }\n this.animateToH(this.snapToPixels(point));\n }\n }\n\n destroy() {\n if (this.destroyed) return;\n this.destroyed = true;\n\n this.cancelCurrentAnimation();\n document.removeEventListener(\"keydown\", this.onKeyDown);\n\n if (this.cleanupGestures) {\n this.cleanupGestures();\n this.cleanupGestures = null;\n }\n if (this.cleanupFocusTrap) {\n this.cleanupFocusTrap();\n this.cleanupFocusTrap = null;\n }\n if (this.unlockScroll) {\n this.unlockScroll();\n this.unlockScroll = null;\n }\n if (this.onPageShow) {\n window.removeEventListener(\"pageshow\", this.onPageShow);\n this.onPageShow = null;\n }\n if (this.onResize) {\n window.removeEventListener(\"resize\", this.onResize);\n this.onResize = null;\n }\n\n removeAriaAttributes(this.wrapperEl, this.overlayEl);\n\n while (this.contentEl.firstChild) {\n this.container.appendChild(this.contentEl.firstChild);\n }\n\n this.wrapperEl.remove();\n this.overlayEl?.remove();\n\n }\n\n setSnapPoints(points: number[]) {\n if (this.destroyed) return;\n this.options.snapPoints = Sheet.sanitizeSnapPoints(points);\n\n if (this.state !== \"closed\" && this.currentSnap > 0) {\n if (!this.options.snapPoints.includes(this.currentSnap)) {\n const nearest = this.pixelsToSnap(this.currentH);\n this.animateToH(this.snapToPixels(nearest));\n }\n }\n }\n\n /** Re-measure content height and recompute current position. Call after dynamic content changes. */\n refresh() {\n if (this.destroyed) return;\n this.naturalContentH = this.getContentHeight();\n if (this.state !== \"closed\" && this.currentSnap > 0) {\n this.currentH = this.snapToPixels(this.currentSnap);\n this.render(this.currentH);\n }\n }\n\n setOptions(opts: MutableSheetOptions) {\n if (this.destroyed) return;\n if (opts.snapPoints !== undefined) this.options.snapPoints = Sheet.sanitizeSnapPoints(opts.snapPoints);\n if (opts.damping !== undefined) this.options.damping = opts.damping;\n if (opts.stiffness !== undefined) this.options.stiffness = opts.stiffness;\n if (opts.mass !== undefined) this.options.mass = opts.mass;\n if (opts.closeThreshold !== undefined) this.options.closeThreshold = opts.closeThreshold;\n if (opts.topPadding !== undefined) this.options.topPadding = opts.topPadding;\n if (opts.closeOnEscape !== undefined) this.options.closeOnEscape = opts.closeOnEscape;\n if (opts.closeOnOverlayClick !== undefined) this.options.closeOnOverlayClick = opts.closeOnOverlayClick;\n if (opts.ariaLabel !== undefined) this.options.ariaLabel = opts.ariaLabel;\n if (opts.ariaLabelledBy !== undefined) this.options.ariaLabelledBy = opts.ariaLabelledBy;\n if (opts.modal !== undefined) this.options.modal = opts.modal;\n if (opts.maxWidth !== undefined) this.options.maxWidth = opts.maxWidth;\n if (opts.reducedMotion !== undefined) this.options.reducedMotion = opts.reducedMotion;\n if (opts.onOpen !== undefined) this.options.onOpen = opts.onOpen;\n if (opts.onClose !== undefined) this.options.onClose = opts.onClose;\n if (opts.onSnap !== undefined) this.options.onSnap = opts.onSnap;\n\n if (opts.ariaLabel !== undefined || opts.ariaLabelledBy !== undefined || opts.modal !== undefined) {\n applyAriaAttributes(this.wrapperEl, this.overlayEl, {\n ariaLabel: this.options.ariaLabel,\n ariaLabelledBy: this.options.ariaLabelledBy,\n modal: this.options.modal,\n });\n }\n if (opts.width !== undefined || opts.align !== undefined || opts.sidePadding !== undefined || opts.maxWidth !== undefined) {\n if (opts.width !== undefined) this.options.width = opts.width;\n if (opts.align !== undefined) this.options.align = opts.align;\n if (opts.sidePadding !== undefined) this.options.sidePadding = opts.sidePadding;\n this.applyLayout();\n }\n\n // Recompute position when size-affecting options changed\n const sizeChanged = opts.topPadding !== undefined || opts.snapPoints !== undefined;\n if (sizeChanged && this.state !== \"closed\" && this.currentSnap > 0) {\n if (opts.snapPoints !== undefined && !this.options.snapPoints.includes(this.currentSnap)) {\n const nearest = this.pixelsToSnap(this.currentH);\n this.animateToH(this.snapToPixels(nearest));\n } else {\n this.currentH = this.snapToPixels(this.currentSnap);\n this.render(this.currentH);\n }\n }\n }\n\n setLayout(opts: { width?: number; align?: SheetAlign; sidePadding?: number }) {\n if (this.destroyed) return;\n if (opts.width !== undefined) this.options.width = opts.width;\n if (opts.align !== undefined) this.options.align = opts.align;\n if (opts.sidePadding !== undefined) this.options.sidePadding = opts.sidePadding;\n this.applyLayout();\n }\n\n get isOpen(): boolean {\n return this.state !== \"closed\";\n }\n\n get currentSnapPoint(): number {\n return this.currentSnap;\n }\n}\n"],"mappings":"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","names":["index_exports","__export","Sheet","__toCommonJS","DEFAULT_SPRING","springStep","current","target","velocity","dt","config","stiffness","damping","mass","displacement","springForce","dampingForce","acceleration","newVelocity","isAtRest","threshold","animateSpring","from","to","initialVelocity","onUpdate","onComplete","cfg","position","lastTime","frameId","tick","time","state","VelocityTracker","maxSamples","value","recent","oldest","i","resolveSnapPoint","snapPoints","flickThreshold","hardFlickThreshold","sorted","a","b","sp","closest","closestDist","dist","DIRECTION_LOCK_THRESHOLD","SCROLL_LOCK_THRESHOLD","findScrollableAncestor","target","sheetEl","el","overflowY","attachGestures","handleEl","handleOnly","callbacks","tracker","VelocityTracker","state","onPointerDown","e","isHandle","scrollable","onPointerMove","dx","dy","deltaY","st","atTop","atBottom","draggingDown","onPointerUp","velocity","onPointerCancel","onContextMenu","FOCUSABLE_SELECTORS","createFocusTrap","container","previousFocus","getFocusable","onKeyDown","e","focusable","first","last","activate","deactivate","applyAriaAttributes","sheetEl","overlayEl","opts","removeAriaAttributes","lockScroll","body","html","originalBodyOverflow","originalHtmlOverflow","preventTouch","el","dampen","v","Sheet","_Sheet","container","options","snaps","defaultSnap","lockScroll","createFocusTrap","e","raw","valid","n","deduped","a","b","snap","maxH","s","px","closest","closestDist","i","dist","width","align","sidePadding","maxWidth","el","vw","clampedWidth","pad","sheetW","left","applyAriaAttributes","attachGestures","_y","deltaY","newH","minH","overflow","velocityPx","velocityH","targetH","resolveSnapPoint","nonZeroSnaps","lowestNonZero","initialVelocity","wasOpen","onDone","springConfig","animateSpring","value","h","viewportH","visibleH","translateY","opacity","point","sorted","target","removeAriaAttributes","points","nearest","opts"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/physics.ts","../src/gestures.ts","../src/accessibility.ts","../src/sheet.ts"],"sourcesContent":["export { Sheet } from \"./sheet.js\";\nexport type { SheetOptions, MutableSheetOptions, SheetAlign, DragMode } from \"./sheet.js\";\nexport type { SpringConfig } from \"./physics.js\";\n","export interface SpringConfig {\n damping: number;\n stiffness: number;\n mass: number;\n restThreshold: number;\n}\n\nexport const DEFAULT_SPRING: SpringConfig = {\n damping: 30,\n stiffness: 200,\n mass: 1,\n restThreshold: 0.5,\n};\n\nexport interface SpringState {\n position: number;\n velocity: number;\n}\n\n/**\n * Solve one step of a damped spring using semi-implicit Euler integration.\n * Returns the new position and velocity after `dt` seconds.\n */\nexport function springStep(\n current: number,\n target: number,\n velocity: number,\n dt: number,\n config: SpringConfig,\n): SpringState {\n const { stiffness, damping, mass } = config;\n const displacement = current - target;\n const springForce = -stiffness * displacement;\n const dampingForce = -damping * velocity;\n const acceleration = (springForce + dampingForce) / mass;\n\n const newVelocity = velocity + acceleration * dt;\n const newPosition = current + newVelocity * dt;\n\n return { position: newPosition, velocity: newVelocity };\n}\n\n/**\n * Returns true when the spring is close enough to rest.\n */\nexport function isAtRest(\n current: number,\n target: number,\n velocity: number,\n threshold: number = DEFAULT_SPRING.restThreshold,\n): boolean {\n return (\n Math.abs(current - target) < threshold && Math.abs(velocity) < threshold\n );\n}\n\n/**\n * Runs a spring animation via requestAnimationFrame. Returns a cancel function.\n */\nexport function animateSpring(\n from: number,\n to: number,\n initialVelocity: number,\n config: Partial<SpringConfig>,\n onUpdate: (value: number) => void,\n onComplete: () => void,\n): () => void {\n const cfg = { ...DEFAULT_SPRING, ...config };\n let position = from;\n let velocity = initialVelocity;\n let lastTime = 0;\n let frameId = 0;\n\n function tick(time: number) {\n if (lastTime === 0) {\n lastTime = time;\n frameId = requestAnimationFrame(tick);\n return;\n }\n\n // Cap dt to avoid spiral of death on tab-switch resume\n const dt = Math.min((time - lastTime) / 1000, 0.064);\n lastTime = time;\n\n const state = springStep(position, to, velocity, dt, cfg);\n position = state.position;\n velocity = state.velocity;\n\n onUpdate(position);\n\n if (isAtRest(position, to, velocity, cfg.restThreshold)) {\n onUpdate(to);\n onComplete();\n return;\n }\n\n frameId = requestAnimationFrame(tick);\n }\n\n frameId = requestAnimationFrame(tick);\n\n return () => cancelAnimationFrame(frameId);\n}\n\n/**\n * Tracks pointer velocity over the last N samples for flick detection.\n */\nexport class VelocityTracker {\n private samples: { time: number; value: number }[] = [];\n private maxSamples: number;\n\n constructor(maxSamples = 8) {\n this.maxSamples = maxSamples;\n }\n\n add(value: number) {\n this.samples.push({ time: performance.now(), value });\n if (this.samples.length > this.maxSamples) {\n this.samples.shift();\n }\n }\n\n /** Returns velocity in units per second. */\n getVelocity(): number {\n if (this.samples.length < 2) return 0;\n\n const recent = this.samples[this.samples.length - 1];\n // Use sample from ~50ms ago for stability\n let oldest = this.samples[0];\n for (let i = this.samples.length - 2; i >= 0; i--) {\n if (recent.time - this.samples[i].time >= 30) {\n oldest = this.samples[i];\n break;\n }\n }\n\n const dt = (recent.time - oldest.time) / 1000;\n if (dt === 0) return 0;\n\n return (recent.value - oldest.value) / dt;\n }\n\n reset() {\n this.samples = [];\n }\n}\n\n/**\n * Given a set of snap points and a release position + velocity,\n * determine which snap point to target.\n */\nexport function resolveSnapPoint(\n position: number,\n velocity: number,\n snapPoints: number[],\n flickThreshold = 400,\n hardFlickThreshold = 1200,\n): number {\n if (snapPoints.length === 0) return position;\n if (snapPoints.length === 1) return snapPoints[0];\n\n const sorted = [...snapPoints].sort((a, b) => a - b);\n\n // Hard flick: skip all intermediate snaps, go to the extreme\n if (Math.abs(velocity) > hardFlickThreshold) {\n return velocity > 0 ? sorted[sorted.length - 1] : sorted[0];\n }\n\n // Normal flick: go to next snap in the flick direction\n if (Math.abs(velocity) > flickThreshold) {\n if (velocity > 0) {\n for (const sp of sorted) {\n if (sp > position + 2) return sp;\n }\n return sorted[sorted.length - 1];\n } else {\n for (let i = sorted.length - 1; i >= 0; i--) {\n if (sorted[i] < position - 2) return sorted[i];\n }\n return sorted[0];\n }\n }\n\n // No flick: snap to nearest\n let closest = sorted[0];\n let closestDist = Math.abs(position - sorted[0]);\n for (let i = 1; i < sorted.length; i++) {\n const dist = Math.abs(position - sorted[i]);\n if (dist < closestDist) {\n closest = sorted[i];\n closestDist = dist;\n }\n }\n return closest;\n}\n","import { VelocityTracker } from \"./physics.js\";\n\nexport interface GestureCallbacks {\n onStart: (y: number) => void;\n onMove: (y: number, deltaY: number) => void;\n onEnd: (velocity: number) => void;\n}\n\ninterface GestureState {\n active: boolean;\n dragging: boolean;\n startY: number;\n currentY: number;\n directionLocked: boolean;\n lockedAxis: \"x\" | \"y\" | null;\n startX: number;\n currentX: number;\n scrolling: boolean;\n scrollTarget: HTMLElement | null;\n}\n\nconst DIRECTION_LOCK_THRESHOLD = 6;\nconst SCROLL_LOCK_THRESHOLD = 3;\n\nfunction findScrollableAncestor(\n target: EventTarget | null,\n sheetEl: HTMLElement,\n): HTMLElement | null {\n let el = target as HTMLElement | null;\n while (el && el !== sheetEl) {\n if (el.scrollHeight > el.clientHeight) {\n const style = getComputedStyle(el);\n const overflowY = style.overflowY;\n if (overflowY === \"auto\" || overflowY === \"scroll\") {\n return el;\n }\n }\n el = el.parentElement;\n }\n return null;\n}\n\nexport function attachGestures(\n sheetEl: HTMLElement,\n handleEl: HTMLElement | null,\n handleOnly: boolean,\n callbacks: GestureCallbacks,\n): () => void {\n const tracker = new VelocityTracker();\n const state: GestureState = {\n active: false,\n dragging: false,\n startY: 0,\n currentY: 0,\n directionLocked: false,\n lockedAxis: null,\n startX: 0,\n currentX: 0,\n scrolling: false,\n scrollTarget: null,\n };\n\n function onPointerDown(e: PointerEvent) {\n const isHandle = handleEl?.contains(e.target as Node);\n if (handleOnly && !isHandle) return;\n const scrollable = isHandle\n ? null\n : findScrollableAncestor(e.target, sheetEl);\n\n state.active = true;\n state.dragging = false;\n state.startY = e.clientY;\n state.currentY = e.clientY;\n state.startX = e.clientX;\n state.currentX = e.clientX;\n state.directionLocked = false;\n state.lockedAxis = null;\n state.scrolling = false;\n state.scrollTarget = scrollable;\n\n tracker.reset();\n tracker.add(e.clientY);\n // No pointer capture yet: capturing here would retarget the click to the\n // sheet, so buttons and links inside it would never get their tap. Until\n // a drag starts, the pointer is followed on the window, since it can leave\n // the sheet (up past a handle near its top edge) before the drag threshold.\n // Once a drag starts it's captured (onPointerMove), so a drag never clicks.\n window.addEventListener(\"pointermove\", onPointerMove);\n window.addEventListener(\"pointerup\", onPointerUp);\n window.addEventListener(\"pointercancel\", onPointerCancel);\n }\n\n function stopFollowing() {\n window.removeEventListener(\"pointermove\", onPointerMove);\n window.removeEventListener(\"pointerup\", onPointerUp);\n window.removeEventListener(\"pointercancel\", onPointerCancel);\n }\n\n function onPointerMove(e: PointerEvent) {\n if (!state.active || state.scrolling) return;\n\n state.currentY = e.clientY;\n state.currentX = e.clientX;\n\n const dx = Math.abs(state.currentX - state.startX);\n const dy = Math.abs(state.currentY - state.startY);\n const deltaY = state.currentY - state.startY;\n\n // Direction locking\n if (!state.directionLocked) {\n if (dx > DIRECTION_LOCK_THRESHOLD || dy > DIRECTION_LOCK_THRESHOLD) {\n state.directionLocked = true;\n state.lockedAxis = dy >= dx ? \"y\" : \"x\";\n }\n if (dy < SCROLL_LOCK_THRESHOLD) return;\n }\n\n if (state.lockedAxis === \"x\") return;\n\n // Scroll vs drag disambiguation (decided once)\n if (state.scrollTarget && !state.dragging) {\n const st = state.scrollTarget;\n const atTop = st.scrollTop <= 0;\n const atBottom = st.scrollTop + st.clientHeight >= st.scrollHeight - 1;\n const draggingDown = deltaY > 0;\n\n if (draggingDown && atTop) {\n // At top, pulling down → drag sheet\n } else if (!draggingDown && atBottom) {\n // At bottom, pulling up → drag sheet\n } else {\n // Let the content scroll\n state.scrolling = true;\n return;\n }\n }\n\n // Begin drag on first qualifying move\n if (!state.dragging) {\n state.dragging = true;\n sheetEl.setPointerCapture(e.pointerId);\n callbacks.onStart(state.startY);\n }\n\n e.preventDefault();\n tracker.add(e.clientY);\n callbacks.onMove(state.currentY, deltaY);\n }\n\n function onPointerUp(e: PointerEvent) {\n if (!state.active) return;\n state.active = false;\n stopFollowing();\n if (sheetEl.hasPointerCapture(e.pointerId)) sheetEl.releasePointerCapture(e.pointerId);\n\n if (!state.dragging) return;\n state.dragging = false;\n\n const velocity = tracker.getVelocity();\n callbacks.onEnd(velocity);\n }\n\n function onPointerCancel(e: PointerEvent) {\n if (!state.active) return;\n state.active = false;\n stopFollowing();\n if (sheetEl.hasPointerCapture(e.pointerId)) sheetEl.releasePointerCapture(e.pointerId);\n\n if (!state.dragging) return;\n state.dragging = false;\n callbacks.onEnd(0);\n }\n\n sheetEl.addEventListener(\"pointerdown\", onPointerDown);\n\n const onContextMenu = (e: Event) => {\n if (state.active) e.preventDefault();\n };\n sheetEl.addEventListener(\"contextmenu\", onContextMenu);\n\n return () => {\n sheetEl.removeEventListener(\"pointerdown\", onPointerDown);\n stopFollowing();\n sheetEl.removeEventListener(\"contextmenu\", onContextMenu);\n };\n}\n","const FOCUSABLE_SELECTORS = [\n \"a[href]\",\n \"button:not([disabled])\",\n \"input:not([disabled])\",\n \"select:not([disabled])\",\n \"textarea:not([disabled])\",\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(\", \");\n\n/**\n * Creates a focus trap within the given element.\n * Returns a cleanup function.\n */\nexport function createFocusTrap(container: HTMLElement): () => void {\n let previousFocus: HTMLElement | null = null;\n\n function getFocusable(): HTMLElement[] {\n return Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTORS));\n }\n\n function onKeyDown(e: KeyboardEvent) {\n if (e.key !== \"Tab\") return;\n\n const focusable = getFocusable();\n if (focusable.length === 0) {\n e.preventDefault();\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first || !container.contains(document.activeElement)) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last || !container.contains(document.activeElement)) {\n e.preventDefault();\n first.focus();\n }\n }\n }\n\n function activate() {\n previousFocus = document.activeElement as HTMLElement | null;\n container.addEventListener(\"keydown\", onKeyDown);\n\n // Focus first focusable element or the container itself\n requestAnimationFrame(() => {\n const focusable = getFocusable();\n if (focusable.length > 0) {\n focusable[0].focus();\n } else {\n container.focus();\n }\n });\n }\n\n function deactivate() {\n container.removeEventListener(\"keydown\", onKeyDown);\n previousFocus?.focus();\n previousFocus = null;\n }\n\n activate();\n\n return deactivate;\n}\n\nexport interface AriaOptions {\n ariaLabel?: string;\n ariaLabelledBy?: string;\n modal?: boolean;\n}\n\n/**\n * Applies ARIA attributes for a modal dialog.\n */\nexport function applyAriaAttributes(\n sheetEl: HTMLElement,\n overlayEl: HTMLElement | null,\n opts: AriaOptions = {},\n) {\n sheetEl.setAttribute(\"role\", \"dialog\");\n sheetEl.setAttribute(\"aria-modal\", opts.modal !== false ? \"true\" : \"false\");\n\n if (opts.ariaLabelledBy) {\n sheetEl.setAttribute(\"aria-labelledby\", opts.ariaLabelledBy);\n sheetEl.removeAttribute(\"aria-label\");\n } else {\n sheetEl.setAttribute(\"aria-label\", opts.ariaLabel || \"Sheet\");\n sheetEl.removeAttribute(\"aria-labelledby\");\n }\n\n if (overlayEl) {\n overlayEl.setAttribute(\"aria-hidden\", \"true\");\n }\n}\n\n/**\n * Removes ARIA attributes when the sheet is destroyed.\n */\nexport function removeAriaAttributes(\n sheetEl: HTMLElement,\n overlayEl: HTMLElement | null,\n) {\n sheetEl.removeAttribute(\"role\");\n sheetEl.removeAttribute(\"aria-modal\");\n if (overlayEl) {\n overlayEl.removeAttribute(\"aria-hidden\");\n }\n}\n\n/* one lock for the page, however many sheets hold it. each sheet used to\n save and restore the page's overflow on its own, so when one sheet opened\n while another was still closing (switching from one to the next), the\n second saved the first's \"hidden\" as the page's own and put it back when\n it closed: the page stayed locked with no sheet open. now the first lock\n saves the page as it was, and the last unlock puts it back. */\nlet holders = 0;\nlet saved: { body: string; html: string } | null = null;\n\n// On iOS Safari, overflow:hidden on body/html doesn't fully prevent\n// scroll on its own. We block touchmove on the document as a fallback.\nfunction preventTouch(e: TouchEvent) {\n // Allow scrolling inside the sheet content\n let el = e.target as HTMLElement | null;\n while (el) {\n if (el.classList?.contains(\"drwr-content\")) return;\n el = el.parentElement;\n }\n e.preventDefault();\n}\n\n/**\n * iOS-safe scroll lock. Prevents background scrolling without position:fixed\n * to avoid the iOS Safari viewport jump when the address bar is visible.\n * Counted: the page unlocks when the last sheet holding it lets go.\n */\nexport function lockScroll(): () => void {\n const body = document.body;\n const html = document.documentElement;\n\n if (holders++ === 0) {\n saved = { body: body.style.overflow, html: html.style.overflow };\n html.style.overflow = \"hidden\";\n body.style.overflow = \"hidden\";\n document.addEventListener(\"touchmove\", preventTouch, { passive: false });\n }\n\n let released = false;\n return () => {\n if (released) return;\n released = true;\n if (--holders > 0) return;\n holders = 0;\n body.style.overflow = saved?.body ?? \"\";\n html.style.overflow = saved?.html ?? \"\";\n saved = null;\n document.removeEventListener(\"touchmove\", preventTouch);\n };\n}\n","import {\n animateSpring,\n resolveSnapPoint,\n type SpringConfig,\n} from \"./physics.js\";\nimport { attachGestures } from \"./gestures.js\";\nimport {\n applyAriaAttributes,\n removeAriaAttributes,\n createFocusTrap,\n lockScroll,\n} from \"./accessibility.js\";\n\nexport type SheetAlign = \"center\" | \"left\" | \"right\";\nexport type DragMode = \"handle\" | \"sheet\" | \"none\";\n\nexport interface SheetOptions {\n snapPoints?: number[];\n defaultSnap?: number;\n overlay?: boolean;\n dragHandle?: boolean;\n damping?: number;\n stiffness?: number;\n mass?: number;\n closeThreshold?: number;\n /** Top padding in px for the maximum open height. Default: 40. */\n topPadding?: number;\n /** Width as a percentage of the viewport (0–100). Default: 60 on desktop, 100 on mobile. */\n width?: number;\n /** Horizontal alignment. Default: \"center\". */\n align?: SheetAlign;\n /** Minimum side padding in px. Default: 0. */\n sidePadding?: number;\n /** Max width in px. 0 = no max. Default: 0. */\n maxWidth?: number;\n /** Which part of the sheet initiates drag. Default: \"sheet\". */\n dragMode?: DragMode;\n /** Accessible label for the sheet dialog. Default: \"Sheet\". */\n ariaLabel?: string;\n /** ID of the element labelling the sheet. Overrides ariaLabel when set. */\n ariaLabelledBy?: string;\n /** Close on Escape key. Default: true. */\n closeOnEscape?: boolean;\n /** Close on overlay click. Default: true. */\n closeOnOverlayClick?: boolean;\n /** Trap focus inside the sheet. Default: true. */\n trapFocus?: boolean;\n /** Set aria-modal. Default: true. */\n modal?: boolean;\n /** Honour prefers-reduced-motion by skipping spring animation. Default: true. */\n reducedMotion?: boolean;\n /** Called when open animation completes. */\n onOpen?: () => void;\n /** Called when close animation completes. */\n onClose?: () => void;\n onSnap?: (point: number) => void;\n}\n\n/** Subset of SheetOptions that can be changed at runtime via setOptions(). */\nexport type MutableSheetOptions = Pick<\n SheetOptions,\n | \"snapPoints\"\n | \"damping\"\n | \"stiffness\"\n | \"mass\"\n | \"closeThreshold\"\n | \"topPadding\"\n | \"width\"\n | \"align\"\n | \"sidePadding\"\n | \"maxWidth\"\n | \"ariaLabel\"\n | \"ariaLabelledBy\"\n | \"closeOnEscape\"\n | \"closeOnOverlayClick\"\n | \"modal\"\n | \"reducedMotion\"\n | \"onOpen\"\n | \"onClose\"\n | \"onSnap\"\n>;\n\ntype SheetState = \"closed\" | \"open\" | \"dragging\" | \"animating\";\n\n/** Logarithmic resistance like vaul: soft, organic feel past bounds. */\nfunction dampen(v: number): number {\n return 8 * (Math.log(v + 1) - 2);\n}\n\nexport class Sheet {\n private container: HTMLElement;\n private options: Required<SheetOptions>;\n\n private wrapperEl!: HTMLElement;\n private overlayEl: HTMLElement | null = null;\n private handleEl: HTMLElement | null = null;\n private contentEl!: HTMLElement;\n\n private state: SheetState = \"closed\";\n private currentSnap = 0;\n // Current height of the sheet in pixels (0 = closed, positive = visible)\n private currentH = 0;\n private dragStartH = 0;\n\n private cancelAnimation: (() => void) | null = null;\n private cleanupGestures: (() => void) | null = null;\n private cleanupFocusTrap: (() => void) | null = null;\n private unlockScroll: (() => void) | null = null;\n private onPageShow: ((e: PageTransitionEvent) => void) | null = null;\n private onResize: (() => void) | null = null;\n private naturalContentH = 0;\n private destroyed = false;\n\n private static sanitizeSnapPoints(raw: number[]): number[] {\n const valid = raw.filter((n) => Number.isFinite(n) && n >= 0 && n <= 1);\n const deduped = [...new Set(valid)].sort((a, b) => a - b);\n if (deduped.length === 0) return [0, 1];\n if (!deduped.includes(0)) deduped.unshift(0);\n return deduped;\n }\n\n private prefersReducedMotion(): boolean {\n return (\n this.options.reducedMotion &&\n typeof window !== \"undefined\" &&\n window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches\n );\n }\n\n constructor(container: HTMLElement, options: SheetOptions = {}) {\n this.container = container;\n const snaps = Sheet.sanitizeSnapPoints(options.snapPoints ?? [0, 1]);\n this.options = {\n snapPoints: snaps,\n defaultSnap: options.defaultSnap ?? 0,\n overlay: options.overlay ?? true,\n dragHandle: options.dragHandle ?? true,\n damping: options.damping ?? 30,\n stiffness: options.stiffness ?? 200,\n mass: options.mass ?? 1,\n closeThreshold: options.closeThreshold ?? 0.2,\n topPadding: options.topPadding ?? 40,\n width: options.width ?? (window.innerWidth >= 768 ? 60 : 100),\n align: options.align ?? \"center\",\n sidePadding: options.sidePadding ?? 0,\n maxWidth: options.maxWidth ?? 0,\n dragMode: options.dragMode ?? \"sheet\",\n ariaLabel: options.ariaLabel ?? \"Sheet\",\n ariaLabelledBy: options.ariaLabelledBy ?? \"\",\n closeOnEscape: options.closeOnEscape ?? true,\n closeOnOverlayClick: options.closeOnOverlayClick ?? true,\n trapFocus: options.trapFocus ?? true,\n modal: options.modal ?? true,\n reducedMotion: options.reducedMotion ?? true,\n onOpen: options.onOpen ?? (() => {}),\n onClose: options.onClose ?? (() => {}),\n onSnap: options.onSnap ?? (() => {}),\n };\n\n this.buildDOM();\n this.container.removeAttribute(\"hidden\");\n this.naturalContentH = this.getContentHeight();\n this.bindGestures();\n\n const defaultSnap = this.options.defaultSnap;\n if (defaultSnap > 0 && this.options.snapPoints.includes(defaultSnap)) {\n this.currentH = this.snapToPixels(defaultSnap);\n this.render(this.currentH);\n this.state = \"open\";\n this.currentSnap = defaultSnap;\n document.addEventListener(\"keydown\", this.onKeyDown);\n if (!this.unlockScroll) this.unlockScroll = lockScroll();\n if (this.options.trapFocus && !this.cleanupFocusTrap) {\n this.cleanupFocusTrap = createFocusTrap(this.wrapperEl);\n }\n queueMicrotask(() => {\n if (this.destroyed) return;\n this.options.onOpen();\n });\n } else {\n this.currentH = 0;\n this.render(0);\n }\n this.onPageShow = (e: PageTransitionEvent) => {\n if (e.persisted && this.state !== \"closed\") {\n this.resetToClosedState();\n }\n };\n window.addEventListener(\"pageshow\", this.onPageShow);\n\n this.onResize = () => {\n this.applyLayout();\n this.naturalContentH = this.getContentHeight();\n if (this.state !== \"closed\" && this.currentSnap > 0) {\n this.currentH = this.snapToPixels(this.currentSnap);\n this.render(this.currentH);\n }\n };\n window.addEventListener(\"resize\", this.onResize);\n }\n\n // --- Snap point conversion ---\n\n private getContentHeight(): number {\n return this.contentEl.scrollHeight + (this.handleEl?.offsetHeight ?? 0);\n }\n\n private maxSheetH(): number {\n return window.innerHeight - this.options.topPadding;\n }\n\n /** Convert a normalized snap point (0–1) to available viewport height. */\n private snapToPixels(snap: number): number {\n if (snap <= 0) return 0;\n const maxH = this.maxSheetH();\n return Math.min(snap, 1) * maxH;\n }\n\n /** Get all snap points as pixel heights, sorted ascending. */\n private snapPixels(): number[] {\n return this.options.snapPoints\n .map((s) => this.snapToPixels(s))\n .sort((a, b) => a - b);\n }\n\n /** Find the normalized snap point closest to a pixel height. */\n private pixelsToSnap(px: number): number {\n const snaps = this.options.snapPoints;\n let closest = snaps[0];\n let closestDist = Math.abs(px - this.snapToPixels(snaps[0]));\n for (let i = 1; i < snaps.length; i++) {\n const dist = Math.abs(px - this.snapToPixels(snaps[i]));\n if (dist < closestDist) {\n closest = snaps[i];\n closestDist = dist;\n }\n }\n return closest;\n }\n\n // --- DOM ---\n\n private applyLayout() {\n const { width, align, sidePadding, maxWidth } = this.options;\n const el = this.wrapperEl;\n\n const vw = window.innerWidth;\n const clampedWidth = Math.max(10, Math.min(100, width));\n const pad = Math.max(0, Math.min(sidePadding, vw / 2 - 10));\n\n let sheetW = Math.max(20, Math.min(vw * (clampedWidth / 100), vw - pad * 2));\n if (maxWidth > 0) sheetW = Math.min(sheetW, maxWidth);\n\n let left: number;\n if (align === \"left\") {\n left = pad;\n } else if (align === \"right\") {\n left = vw - sheetW - pad;\n } else {\n left = (vw - sheetW) / 2;\n }\n\n el.style.left = `${left}px`;\n el.style.right = \"auto\";\n el.style.width = `${sheetW}px`;\n el.style.margin = \"0\";\n }\n\n private buildDOM() {\n this.wrapperEl = document.createElement(\"div\");\n this.wrapperEl.className = \"drwr-sheet\";\n this.wrapperEl.setAttribute(\"tabindex\", \"-1\");\n\n if (this.options.dragHandle) {\n this.handleEl = document.createElement(\"div\");\n this.handleEl.className = \"drwr-handle\";\n this.wrapperEl.appendChild(this.handleEl);\n }\n\n this.contentEl = document.createElement(\"div\");\n this.contentEl.className = \"drwr-content\";\n\n while (this.container.firstChild) {\n this.contentEl.appendChild(this.container.firstChild);\n }\n this.wrapperEl.appendChild(this.contentEl);\n this.container.appendChild(this.wrapperEl);\n\n if (this.options.overlay) {\n this.overlayEl = document.createElement(\"div\");\n this.overlayEl.className = \"drwr-overlay\";\n this.overlayEl.addEventListener(\"click\", () => {\n if (this.options.closeOnOverlayClick) this.close();\n });\n this.container.insertBefore(this.overlayEl, this.wrapperEl);\n }\n\n applyAriaAttributes(this.wrapperEl, this.overlayEl, {\n ariaLabel: this.options.ariaLabel,\n ariaLabelledBy: this.options.ariaLabelledBy,\n modal: this.options.modal,\n });\n this.applyLayout();\n }\n\n // --- Gestures ---\n\n private bindGestures() {\n if (this.options.dragMode === \"none\") return;\n this.cleanupGestures = attachGestures(\n this.wrapperEl,\n this.handleEl,\n this.options.dragMode === \"handle\",\n {\n onStart: () => {\n this.cancelCurrentAnimation();\n this.state = \"dragging\";\n this.dragStartH = this.currentH;\n this.wrapperEl.setAttribute(\"data-dragging\", \"true\");\n },\n onMove: (_y, deltaY) => {\n // deltaY positive = finger moved down = sheet should shrink\n let newH = this.dragStartH - deltaY;\n\n const snaps = this.snapPixels();\n const maxH = snaps[snaps.length - 1];\n const minH = snaps[0];\n\n if (newH > maxH) {\n newH = maxH;\n } else if (newH < minH) {\n const overflow = minH - newH;\n newH = minH - Math.max(0, dampen(overflow));\n }\n\n this.currentH = newH;\n this.render(newH);\n },\n onEnd: (velocityPx) => {\n this.wrapperEl.setAttribute(\"data-dragging\", \"false\");\n const velocityH = -velocityPx;\n this.state = \"animating\";\n\n const snaps = this.snapPixels();\n let targetH = resolveSnapPoint(this.currentH, velocityH, snaps, 400);\n\n // closeThreshold: if the sheet is dragged below (lowestNonZeroSnap * threshold), close it\n const nonZeroSnaps = snaps.filter((s) => s > 0);\n if (nonZeroSnaps.length > 0) {\n const lowestNonZero = nonZeroSnaps[0];\n if (this.currentH < lowestNonZero * this.options.closeThreshold) {\n targetH = 0;\n }\n }\n\n this.animateToH(targetH, velocityH);\n },\n },\n );\n }\n\n // --- Animation ---\n\n private cancelCurrentAnimation() {\n if (this.cancelAnimation) {\n this.cancelAnimation();\n this.cancelAnimation = null;\n }\n }\n\n private animateToH(targetH: number, initialVelocity = 0) {\n const wasOpen = this.state === \"open\" || this.state === \"dragging\";\n this.cancelCurrentAnimation();\n this.state = \"animating\";\n const onDone = () => {\n this.currentH = targetH;\n this.render(targetH);\n this.cancelAnimation = null;\n\n const snap = this.pixelsToSnap(targetH);\n this.currentSnap = snap;\n\n if (targetH <= 0.5) {\n this.onClosed();\n } else {\n this.state = \"open\";\n if (!wasOpen) this.options.onOpen();\n this.options.onSnap(snap);\n }\n };\n\n if (this.prefersReducedMotion()) {\n onDone();\n return;\n }\n\n const springConfig: Partial<SpringConfig> = {\n damping: this.options.damping,\n stiffness: this.options.stiffness,\n mass: this.options.mass,\n };\n\n this.cancelAnimation = animateSpring(\n this.currentH,\n targetH,\n initialVelocity,\n springConfig,\n (value) => {\n this.currentH = value;\n this.render(value);\n },\n onDone,\n );\n }\n\n // --- Rendering ---\n\n private render(h: number) {\n const viewportH = window.innerHeight;\n const visibleH = Math.max(0, h);\n const translateY = viewportH - visibleH;\n\n this.wrapperEl.style.visibility = visibleH > 0.5 ? \"visible\" : \"hidden\";\n\n this.wrapperEl.style.transform = `translate3d(0, ${translateY}px, 0)`;\n this.wrapperEl.style.height = visibleH > 0.5 ? `${visibleH}px` : \"\";\n\n if (this.overlayEl) {\n const snaps = this.snapPixels();\n const maxH = snaps[snaps.length - 1];\n const opacity = Math.max(0, Math.min(1, visibleH / (maxH * 0.3)));\n this.overlayEl.style.opacity = String(opacity);\n this.overlayEl.setAttribute(\"data-visible\", visibleH > 1 ? \"true\" : \"false\");\n }\n }\n\n // --- State changes ---\n\n /** Shared cleanup: visually close and tear down locks/traps. Does NOT fire callbacks. */\n private resetToClosedState() {\n this.cancelCurrentAnimation();\n this.currentH = 0;\n this.currentSnap = 0;\n this.render(0);\n this.state = \"closed\";\n\n if (this.overlayEl) {\n this.overlayEl.style.opacity = \"0\";\n this.overlayEl.setAttribute(\"data-visible\", \"false\");\n }\n if (this.unlockScroll) {\n this.unlockScroll();\n this.unlockScroll = null;\n }\n if (this.cleanupFocusTrap) {\n this.cleanupFocusTrap();\n this.cleanupFocusTrap = null;\n }\n document.removeEventListener(\"keydown\", this.onKeyDown);\n }\n\n private onClosed() {\n this.resetToClosedState();\n this.options.onClose();\n }\n\n // --- Keyboard ---\n\n private onKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\" && this.state !== \"closed\" && this.options.closeOnEscape) {\n this.close();\n }\n };\n\n // --- Public API ---\n\n open(point?: number) {\n if (this.destroyed || this.state === \"open\") return;\n\n const sorted = [...this.options.snapPoints].sort((a, b) => a - b);\n let target: number;\n if (point !== undefined) {\n if (!sorted.includes(point) || point === 0) {\n console.warn(`[drwr] snap point ${point} not valid for open()`);\n return;\n }\n target = point;\n } else {\n target = sorted[sorted.length - 1];\n }\n\n document.addEventListener(\"keydown\", this.onKeyDown);\n this.animateToH(this.snapToPixels(target));\n if (!this.unlockScroll) this.unlockScroll = lockScroll();\n if (this.options.trapFocus && !this.cleanupFocusTrap) {\n this.cleanupFocusTrap = createFocusTrap(this.wrapperEl);\n }\n }\n\n close() {\n if (this.destroyed || this.state === \"closed\") return;\n document.removeEventListener(\"keydown\", this.onKeyDown);\n this.animateToH(0);\n }\n\n snapTo(point: number) {\n if (this.destroyed) return;\n if (!this.options.snapPoints.includes(point)) {\n console.warn(`[drwr] snap point ${point} not in snapPoints`);\n return;\n }\n if (point === 0) {\n this.close();\n } else {\n if (this.state === \"closed\") {\n document.addEventListener(\"keydown\", this.onKeyDown);\n if (!this.unlockScroll) this.unlockScroll = lockScroll();\n if (this.options.trapFocus && !this.cleanupFocusTrap) {\n this.cleanupFocusTrap = createFocusTrap(this.wrapperEl);\n }\n }\n this.animateToH(this.snapToPixels(point));\n }\n }\n\n destroy() {\n if (this.destroyed) return;\n this.destroyed = true;\n\n this.cancelCurrentAnimation();\n document.removeEventListener(\"keydown\", this.onKeyDown);\n\n if (this.cleanupGestures) {\n this.cleanupGestures();\n this.cleanupGestures = null;\n }\n if (this.cleanupFocusTrap) {\n this.cleanupFocusTrap();\n this.cleanupFocusTrap = null;\n }\n if (this.unlockScroll) {\n this.unlockScroll();\n this.unlockScroll = null;\n }\n if (this.onPageShow) {\n window.removeEventListener(\"pageshow\", this.onPageShow);\n this.onPageShow = null;\n }\n if (this.onResize) {\n window.removeEventListener(\"resize\", this.onResize);\n this.onResize = null;\n }\n\n removeAriaAttributes(this.wrapperEl, this.overlayEl);\n\n while (this.contentEl.firstChild) {\n this.container.appendChild(this.contentEl.firstChild);\n }\n\n this.wrapperEl.remove();\n this.overlayEl?.remove();\n\n }\n\n setSnapPoints(points: number[]) {\n if (this.destroyed) return;\n this.options.snapPoints = Sheet.sanitizeSnapPoints(points);\n\n if (this.state !== \"closed\" && this.currentSnap > 0) {\n if (!this.options.snapPoints.includes(this.currentSnap)) {\n const nearest = this.pixelsToSnap(this.currentH);\n this.animateToH(this.snapToPixels(nearest));\n }\n }\n }\n\n /** Re-measure content height and recompute current position. Call after dynamic content changes. */\n refresh() {\n if (this.destroyed) return;\n this.naturalContentH = this.getContentHeight();\n if (this.state !== \"closed\" && this.currentSnap > 0) {\n this.currentH = this.snapToPixels(this.currentSnap);\n this.render(this.currentH);\n }\n }\n\n setOptions(opts: MutableSheetOptions) {\n if (this.destroyed) return;\n if (opts.snapPoints !== undefined) this.options.snapPoints = Sheet.sanitizeSnapPoints(opts.snapPoints);\n if (opts.damping !== undefined) this.options.damping = opts.damping;\n if (opts.stiffness !== undefined) this.options.stiffness = opts.stiffness;\n if (opts.mass !== undefined) this.options.mass = opts.mass;\n if (opts.closeThreshold !== undefined) this.options.closeThreshold = opts.closeThreshold;\n if (opts.topPadding !== undefined) this.options.topPadding = opts.topPadding;\n if (opts.closeOnEscape !== undefined) this.options.closeOnEscape = opts.closeOnEscape;\n if (opts.closeOnOverlayClick !== undefined) this.options.closeOnOverlayClick = opts.closeOnOverlayClick;\n if (opts.ariaLabel !== undefined) this.options.ariaLabel = opts.ariaLabel;\n if (opts.ariaLabelledBy !== undefined) this.options.ariaLabelledBy = opts.ariaLabelledBy;\n if (opts.modal !== undefined) this.options.modal = opts.modal;\n if (opts.maxWidth !== undefined) this.options.maxWidth = opts.maxWidth;\n if (opts.reducedMotion !== undefined) this.options.reducedMotion = opts.reducedMotion;\n if (opts.onOpen !== undefined) this.options.onOpen = opts.onOpen;\n if (opts.onClose !== undefined) this.options.onClose = opts.onClose;\n if (opts.onSnap !== undefined) this.options.onSnap = opts.onSnap;\n\n if (opts.ariaLabel !== undefined || opts.ariaLabelledBy !== undefined || opts.modal !== undefined) {\n applyAriaAttributes(this.wrapperEl, this.overlayEl, {\n ariaLabel: this.options.ariaLabel,\n ariaLabelledBy: this.options.ariaLabelledBy,\n modal: this.options.modal,\n });\n }\n if (opts.width !== undefined || opts.align !== undefined || opts.sidePadding !== undefined || opts.maxWidth !== undefined) {\n if (opts.width !== undefined) this.options.width = opts.width;\n if (opts.align !== undefined) this.options.align = opts.align;\n if (opts.sidePadding !== undefined) this.options.sidePadding = opts.sidePadding;\n this.applyLayout();\n }\n\n // Recompute position when size-affecting options changed\n const sizeChanged = opts.topPadding !== undefined || opts.snapPoints !== undefined;\n if (sizeChanged && this.state !== \"closed\" && this.currentSnap > 0) {\n if (opts.snapPoints !== undefined && !this.options.snapPoints.includes(this.currentSnap)) {\n const nearest = this.pixelsToSnap(this.currentH);\n this.animateToH(this.snapToPixels(nearest));\n } else {\n this.currentH = this.snapToPixels(this.currentSnap);\n this.render(this.currentH);\n }\n }\n }\n\n setLayout(opts: { width?: number; align?: SheetAlign; sidePadding?: number }) {\n if (this.destroyed) return;\n if (opts.width !== undefined) this.options.width = opts.width;\n if (opts.align !== undefined) this.options.align = opts.align;\n if (opts.sidePadding !== undefined) this.options.sidePadding = opts.sidePadding;\n this.applyLayout();\n }\n\n get isOpen(): boolean {\n return this.state !== \"closed\";\n }\n\n get currentSnapPoint(): number {\n return this.currentSnap;\n }\n}\n"],"mappings":"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","names":["index_exports","__export","Sheet","__toCommonJS","DEFAULT_SPRING","springStep","current","target","velocity","dt","config","stiffness","damping","mass","displacement","springForce","dampingForce","acceleration","newVelocity","isAtRest","threshold","animateSpring","from","to","initialVelocity","onUpdate","onComplete","cfg","position","lastTime","frameId","tick","time","state","VelocityTracker","maxSamples","value","recent","oldest","i","resolveSnapPoint","snapPoints","flickThreshold","hardFlickThreshold","sorted","a","b","sp","closest","closestDist","dist","DIRECTION_LOCK_THRESHOLD","SCROLL_LOCK_THRESHOLD","findScrollableAncestor","target","sheetEl","el","overflowY","attachGestures","handleEl","handleOnly","callbacks","tracker","VelocityTracker","state","onPointerDown","e","isHandle","scrollable","onPointerMove","onPointerUp","onPointerCancel","stopFollowing","dx","dy","deltaY","st","atTop","atBottom","draggingDown","velocity","onContextMenu","FOCUSABLE_SELECTORS","createFocusTrap","container","previousFocus","getFocusable","onKeyDown","e","focusable","first","last","activate","deactivate","applyAriaAttributes","sheetEl","overlayEl","opts","removeAriaAttributes","holders","saved","preventTouch","el","lockScroll","body","html","released","dampen","v","Sheet","_Sheet","container","options","snaps","defaultSnap","lockScroll","createFocusTrap","e","raw","valid","n","deduped","a","b","snap","maxH","s","px","closest","closestDist","i","dist","width","align","sidePadding","maxWidth","el","vw","clampedWidth","pad","sheetW","left","applyAriaAttributes","attachGestures","_y","deltaY","newH","minH","overflow","velocityPx","velocityH","targetH","resolveSnapPoint","nonZeroSnaps","lowestNonZero","initialVelocity","wasOpen","onDone","springConfig","animateSpring","value","h","viewportH","visibleH","translateY","opacity","point","sorted","target","removeAriaAttributes","points","nearest","opts"]}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var w={damping:30,stiffness:200,mass:1,restThreshold:.5};function O(s,e,n,i,r){let{stiffness:t,damping:a,mass:d}=r,o=s-e,c=-t*o,u=-a*n,l=(c+u)/d,h=n+l*i;return{position:s+h*i,velocity:h}}function A(s,e,n,i=w.restThreshold){return Math.abs(s-e)<i&&Math.abs(n)<i}function L(s,e,n,i,r,t){let a={...w,...i},d=s,o=n,c=0,u=0;function l(h){if(c===0){c=h,u=requestAnimationFrame(l);return}let p=Math.min((h-c)/1e3,.064);c=h;let m=O(d,e,o,p,a);if(d=m.position,o=m.velocity,r(d),A(d,e,o,a.restThreshold)){r(e),t();return}u=requestAnimationFrame(l)}return u=requestAnimationFrame(l),()=>cancelAnimationFrame(u)}var g=class{constructor(e=8){this.samples=[];this.maxSamples=e}add(e){this.samples.push({time:performance.now(),value:e}),this.samples.length>this.maxSamples&&this.samples.shift()}getVelocity(){if(this.samples.length<2)return 0;let e=this.samples[this.samples.length-1],n=this.samples[0];for(let r=this.samples.length-2;r>=0;r--)if(e.time-this.samples[r].time>=30){n=this.samples[r];break}let i=(e.time-n.time)/1e3;return i===0?0:(e.value-n.value)/i}reset(){this.samples=[]}};function T(s,e,n,i=400,r=1200){if(n.length===0)return s;if(n.length===1)return n[0];let t=[...n].sort((o,c)=>o-c);if(Math.abs(e)>r)return e>0?t[t.length-1]:t[0];if(Math.abs(e)>i)if(e>0){for(let o of t)if(o>s+2)return o;return t[t.length-1]}else{for(let o=t.length-1;o>=0;o--)if(t[o]<s-2)return t[o];return t[0]}let a=t[0],d=Math.abs(s-t[0]);for(let o=1;o<t.length;o++){let c=Math.abs(s-t[o]);c<d&&(a=t[o],d=c)}return a}var P=6,k=3;function F(s,e){let n=s;for(;n&&n!==e;){if(n.scrollHeight>n.clientHeight){let r=getComputedStyle(n).overflowY;if(r==="auto"||r==="scroll")return n}n=n.parentElement}return null}function x(s,e,n,i){let r=new g,t={active:!1,dragging:!1,startY:0,currentY:0,directionLocked:!1,lockedAxis:null,startX:0,currentX:0,scrolling:!1,scrollTarget:null};function a(l){let h=e?.contains(l.target);if(n&&!h)return;let p=h?null:F(l.target,s);t.active=!0,t.dragging=!1,t.startY=l.clientY,t.currentY=l.clientY,t.startX=l.clientX,t.currentX=l.clientX,t.directionLocked=!1,t.lockedAxis=null,t.scrolling=!1,t.scrollTarget=p,r.reset(),r.add(l.clientY),s.setPointerCapture(l.pointerId)}function d(l){if(!t.active||t.scrolling)return;t.currentY=l.clientY,t.currentX=l.clientX;let h=Math.abs(t.currentX-t.startX),p=Math.abs(t.currentY-t.startY),m=t.currentY-t.startY;if(!(!t.directionLocked&&((h>P||p>P)&&(t.directionLocked=!0,t.lockedAxis=p>=h?"y":"x"),p<k))&&t.lockedAxis!=="x"){if(t.scrollTarget&&!t.dragging){let f=t.scrollTarget,M=f.scrollTop<=0,C=f.scrollTop+f.clientHeight>=f.scrollHeight-1,E=m>0;if(!(E&&M)){if(!(!E&&C)){t.scrolling=!0;return}}}t.dragging||(t.dragging=!0,i.onStart(t.startY)),l.preventDefault(),r.add(l.clientY),i.onMove(t.currentY,m)}}function o(l){if(!t.active||(t.active=!1,s.releasePointerCapture(l.pointerId),!t.dragging))return;t.dragging=!1;let h=r.getVelocity();i.onEnd(h)}function c(l){t.active&&(t.active=!1,s.releasePointerCapture(l.pointerId),t.dragging&&(t.dragging=!1,i.onEnd(0)))}s.addEventListener("pointerdown",a),s.addEventListener("pointermove",d),s.addEventListener("pointerup",o),s.addEventListener("pointercancel",c);let u=l=>{t.active&&l.preventDefault()};return s.addEventListener("contextmenu",u),()=>{s.removeEventListener("pointerdown",a),s.removeEventListener("pointermove",d),s.removeEventListener("pointerup",o),s.removeEventListener("pointercancel",c),s.removeEventListener("contextmenu",u)}}var D=["a[href]","button:not([disabled])","input:not([disabled])","select:not([disabled])","textarea:not([disabled])",'[tabindex]:not([tabindex="-1"])'].join(", ");function v(s){let e=null;function n(){return Array.from(s.querySelectorAll(D))}function i(a){if(a.key!=="Tab")return;let d=n();if(d.length===0){a.preventDefault();return}let o=d[0],c=d[d.length-1];a.shiftKey?(document.activeElement===o||!s.contains(document.activeElement))&&(a.preventDefault(),c.focus()):(document.activeElement===c||!s.contains(document.activeElement))&&(a.preventDefault(),o.focus())}function r(){e=document.activeElement,s.addEventListener("keydown",i),requestAnimationFrame(()=>{let a=n();a.length>0?a[0].focus():s.focus()})}function t(){s.removeEventListener("keydown",i),e?.focus(),e=null}return r(),t}function y(s,e,n={}){s.setAttribute("role","dialog"),s.setAttribute("aria-modal",n.modal!==!1?"true":"false"),n.ariaLabelledBy?(s.setAttribute("aria-labelledby",n.ariaLabelledBy),s.removeAttribute("aria-label")):(s.setAttribute("aria-label",n.ariaLabel||"Sheet"),s.removeAttribute("aria-labelledby")),e&&e.setAttribute("aria-hidden","true")}function H(s,e){s.removeAttribute("role"),s.removeAttribute("aria-modal"),e&&e.removeAttribute("aria-hidden")}function b(){let s=document.body,e=document.documentElement,n=s.style.overflow,i=e.style.overflow;e.style.overflow="hidden",s.style.overflow="hidden";let r=t=>{let a=t.target;for(;a;){if(a.classList?.contains("drwr-content"))return;a=a.parentElement}t.preventDefault()};return document.addEventListener("touchmove",r,{passive:!1}),()=>{s.style.overflow=n,e.style.overflow=i,document.removeEventListener("touchmove",r)}}function Y(s){return 8*(Math.log(s+1)-2)}var S=class s{constructor(e,n={}){this.overlayEl=null;this.handleEl=null;this.state="closed";this.currentSnap=0;this.currentH=0;this.dragStartH=0;this.cancelAnimation=null;this.cleanupGestures=null;this.cleanupFocusTrap=null;this.unlockScroll=null;this.onPageShow=null;this.onResize=null;this.naturalContentH=0;this.destroyed=!1;this.onKeyDown=e=>{e.key==="Escape"&&this.state!=="closed"&&this.options.closeOnEscape&&this.close()};this.container=e;let i=s.sanitizeSnapPoints(n.snapPoints??[0,1]);this.options={snapPoints:i,defaultSnap:n.defaultSnap??0,overlay:n.overlay??!0,dragHandle:n.dragHandle??!0,damping:n.damping??30,stiffness:n.stiffness??200,mass:n.mass??1,closeThreshold:n.closeThreshold??.2,topPadding:n.topPadding??40,width:n.width??(window.innerWidth>=768?60:100),align:n.align??"center",sidePadding:n.sidePadding??0,maxWidth:n.maxWidth??0,dragMode:n.dragMode??"sheet",ariaLabel:n.ariaLabel??"Sheet",ariaLabelledBy:n.ariaLabelledBy??"",closeOnEscape:n.closeOnEscape??!0,closeOnOverlayClick:n.closeOnOverlayClick??!0,trapFocus:n.trapFocus??!0,modal:n.modal??!0,reducedMotion:n.reducedMotion??!0,onOpen:n.onOpen??(()=>{}),onClose:n.onClose??(()=>{}),onSnap:n.onSnap??(()=>{})},this.buildDOM(),this.container.removeAttribute("hidden"),this.naturalContentH=this.getContentHeight(),this.bindGestures();let r=this.options.defaultSnap;r>0&&this.options.snapPoints.includes(r)?(this.currentH=this.snapToPixels(r),this.render(this.currentH),this.state="open",this.currentSnap=r,document.addEventListener("keydown",this.onKeyDown),this.unlockScroll||(this.unlockScroll=b()),this.options.trapFocus&&!this.cleanupFocusTrap&&(this.cleanupFocusTrap=v(this.wrapperEl)),queueMicrotask(()=>{this.destroyed||this.options.onOpen()})):(this.currentH=0,this.render(0)),this.onPageShow=t=>{t.persisted&&this.state!=="closed"&&this.resetToClosedState()},window.addEventListener("pageshow",this.onPageShow),this.onResize=()=>{this.applyLayout(),this.naturalContentH=this.getContentHeight(),this.state!=="closed"&&this.currentSnap>0&&(this.currentH=this.snapToPixels(this.currentSnap),this.render(this.currentH))},window.addEventListener("resize",this.onResize)}static sanitizeSnapPoints(e){let n=e.filter(r=>Number.isFinite(r)&&r>=0&&r<=1),i=[...new Set(n)].sort((r,t)=>r-t);return i.length===0?[0,1]:(i.includes(0)||i.unshift(0),i)}prefersReducedMotion(){return this.options.reducedMotion&&typeof window<"u"&&window.matchMedia("(prefers-reduced-motion: reduce)").matches}getContentHeight(){return this.contentEl.scrollHeight+(this.handleEl?.offsetHeight??0)}maxSheetH(){return window.innerHeight-this.options.topPadding}snapToPixels(e){if(e<=0)return 0;let n=this.maxSheetH();return Math.min(e,1)*n}snapPixels(){return this.options.snapPoints.map(e=>this.snapToPixels(e)).sort((e,n)=>e-n)}pixelsToSnap(e){let n=this.options.snapPoints,i=n[0],r=Math.abs(e-this.snapToPixels(n[0]));for(let t=1;t<n.length;t++){let a=Math.abs(e-this.snapToPixels(n[t]));a<r&&(i=n[t],r=a)}return i}applyLayout(){let{width:e,align:n,sidePadding:i,maxWidth:r}=this.options,t=this.wrapperEl,a=window.innerWidth,d=Math.max(10,Math.min(100,e)),o=Math.max(0,Math.min(i,a/2-10)),c=Math.max(20,Math.min(a*(d/100),a-o*2));r>0&&(c=Math.min(c,r));let u;n==="left"?u=o:n==="right"?u=a-c-o:u=(a-c)/2,t.style.left=`${u}px`,t.style.right="auto",t.style.width=`${c}px`,t.style.margin="0"}buildDOM(){for(this.wrapperEl=document.createElement("div"),this.wrapperEl.className="drwr-sheet",this.wrapperEl.setAttribute("tabindex","-1"),this.options.dragHandle&&(this.handleEl=document.createElement("div"),this.handleEl.className="drwr-handle",this.wrapperEl.appendChild(this.handleEl)),this.contentEl=document.createElement("div"),this.contentEl.className="drwr-content";this.container.firstChild;)this.contentEl.appendChild(this.container.firstChild);this.wrapperEl.appendChild(this.contentEl),this.container.appendChild(this.wrapperEl),this.options.overlay&&(this.overlayEl=document.createElement("div"),this.overlayEl.className="drwr-overlay",this.overlayEl.addEventListener("click",()=>{this.options.closeOnOverlayClick&&this.close()}),this.container.insertBefore(this.overlayEl,this.wrapperEl)),y(this.wrapperEl,this.overlayEl,{ariaLabel:this.options.ariaLabel,ariaLabelledBy:this.options.ariaLabelledBy,modal:this.options.modal}),this.applyLayout()}bindGestures(){this.options.dragMode!=="none"&&(this.cleanupGestures=x(this.wrapperEl,this.handleEl,this.options.dragMode==="handle",{onStart:()=>{this.cancelCurrentAnimation(),this.state="dragging",this.dragStartH=this.currentH,this.wrapperEl.setAttribute("data-dragging","true")},onMove:(e,n)=>{let i=this.dragStartH-n,r=this.snapPixels(),t=r[r.length-1],a=r[0];if(i>t)i=t;else if(i<a){let d=a-i;i=a-Math.max(0,Y(d))}this.currentH=i,this.render(i)},onEnd:e=>{this.wrapperEl.setAttribute("data-dragging","false");let n=-e;this.state="animating";let i=this.snapPixels(),r=T(this.currentH,n,i,400),t=i.filter(a=>a>0);if(t.length>0){let a=t[0];this.currentH<a*this.options.closeThreshold&&(r=0)}this.animateToH(r,n)}}))}cancelCurrentAnimation(){this.cancelAnimation&&(this.cancelAnimation(),this.cancelAnimation=null)}animateToH(e,n=0){let i=this.state==="open"||this.state==="dragging";this.cancelCurrentAnimation(),this.state="animating";let r=()=>{this.currentH=e,this.render(e),this.cancelAnimation=null;let a=this.pixelsToSnap(e);this.currentSnap=a,e<=.5?this.onClosed():(this.state="open",i||this.options.onOpen(),this.options.onSnap(a))};if(this.prefersReducedMotion()){r();return}let t={damping:this.options.damping,stiffness:this.options.stiffness,mass:this.options.mass};this.cancelAnimation=L(this.currentH,e,n,t,a=>{this.currentH=a,this.render(a)},r)}render(e){let n=window.innerHeight,i=Math.max(0,e),r=n-i;if(this.wrapperEl.style.visibility=i>.5?"visible":"hidden",this.wrapperEl.style.transform=`translate3d(0, ${r}px, 0)`,this.wrapperEl.style.height=i>.5?`${i}px`:"",this.overlayEl){let t=this.snapPixels(),a=t[t.length-1],d=Math.max(0,Math.min(1,i/(a*.3)));this.overlayEl.style.opacity=String(d),this.overlayEl.setAttribute("data-visible",i>1?"true":"false")}}resetToClosedState(){this.cancelCurrentAnimation(),this.currentH=0,this.currentSnap=0,this.render(0),this.state="closed",this.overlayEl&&(this.overlayEl.style.opacity="0",this.overlayEl.setAttribute("data-visible","false")),this.unlockScroll&&(this.unlockScroll(),this.unlockScroll=null),this.cleanupFocusTrap&&(this.cleanupFocusTrap(),this.cleanupFocusTrap=null),document.removeEventListener("keydown",this.onKeyDown)}onClosed(){this.resetToClosedState(),this.options.onClose()}open(e){if(this.destroyed||this.state==="open")return;let n=[...this.options.snapPoints].sort((r,t)=>r-t),i;if(e!==void 0){if(!n.includes(e)||e===0){console.warn(`[drwr] snap point ${e} not valid for open()`);return}i=e}else i=n[n.length-1];document.addEventListener("keydown",this.onKeyDown),this.animateToH(this.snapToPixels(i)),this.unlockScroll||(this.unlockScroll=b()),this.options.trapFocus&&!this.cleanupFocusTrap&&(this.cleanupFocusTrap=v(this.wrapperEl))}close(){this.destroyed||this.state==="closed"||(document.removeEventListener("keydown",this.onKeyDown),this.animateToH(0))}snapTo(e){if(!this.destroyed){if(!this.options.snapPoints.includes(e)){console.warn(`[drwr] snap point ${e} not in snapPoints`);return}e===0?this.close():(this.state==="closed"&&(document.addEventListener("keydown",this.onKeyDown),this.unlockScroll||(this.unlockScroll=b()),this.options.trapFocus&&!this.cleanupFocusTrap&&(this.cleanupFocusTrap=v(this.wrapperEl))),this.animateToH(this.snapToPixels(e)))}}destroy(){if(!this.destroyed){for(this.destroyed=!0,this.cancelCurrentAnimation(),document.removeEventListener("keydown",this.onKeyDown),this.cleanupGestures&&(this.cleanupGestures(),this.cleanupGestures=null),this.cleanupFocusTrap&&(this.cleanupFocusTrap(),this.cleanupFocusTrap=null),this.unlockScroll&&(this.unlockScroll(),this.unlockScroll=null),this.onPageShow&&(window.removeEventListener("pageshow",this.onPageShow),this.onPageShow=null),this.onResize&&(window.removeEventListener("resize",this.onResize),this.onResize=null),H(this.wrapperEl,this.overlayEl);this.contentEl.firstChild;)this.container.appendChild(this.contentEl.firstChild);this.wrapperEl.remove(),this.overlayEl?.remove()}}setSnapPoints(e){if(!this.destroyed&&(this.options.snapPoints=s.sanitizeSnapPoints(e),this.state!=="closed"&&this.currentSnap>0&&!this.options.snapPoints.includes(this.currentSnap))){let n=this.pixelsToSnap(this.currentH);this.animateToH(this.snapToPixels(n))}}refresh(){this.destroyed||(this.naturalContentH=this.getContentHeight(),this.state!=="closed"&&this.currentSnap>0&&(this.currentH=this.snapToPixels(this.currentSnap),this.render(this.currentH)))}setOptions(e){if(this.destroyed)return;if(e.snapPoints!==void 0&&(this.options.snapPoints=s.sanitizeSnapPoints(e.snapPoints)),e.damping!==void 0&&(this.options.damping=e.damping),e.stiffness!==void 0&&(this.options.stiffness=e.stiffness),e.mass!==void 0&&(this.options.mass=e.mass),e.closeThreshold!==void 0&&(this.options.closeThreshold=e.closeThreshold),e.topPadding!==void 0&&(this.options.topPadding=e.topPadding),e.closeOnEscape!==void 0&&(this.options.closeOnEscape=e.closeOnEscape),e.closeOnOverlayClick!==void 0&&(this.options.closeOnOverlayClick=e.closeOnOverlayClick),e.ariaLabel!==void 0&&(this.options.ariaLabel=e.ariaLabel),e.ariaLabelledBy!==void 0&&(this.options.ariaLabelledBy=e.ariaLabelledBy),e.modal!==void 0&&(this.options.modal=e.modal),e.maxWidth!==void 0&&(this.options.maxWidth=e.maxWidth),e.reducedMotion!==void 0&&(this.options.reducedMotion=e.reducedMotion),e.onOpen!==void 0&&(this.options.onOpen=e.onOpen),e.onClose!==void 0&&(this.options.onClose=e.onClose),e.onSnap!==void 0&&(this.options.onSnap=e.onSnap),(e.ariaLabel!==void 0||e.ariaLabelledBy!==void 0||e.modal!==void 0)&&y(this.wrapperEl,this.overlayEl,{ariaLabel:this.options.ariaLabel,ariaLabelledBy:this.options.ariaLabelledBy,modal:this.options.modal}),(e.width!==void 0||e.align!==void 0||e.sidePadding!==void 0||e.maxWidth!==void 0)&&(e.width!==void 0&&(this.options.width=e.width),e.align!==void 0&&(this.options.align=e.align),e.sidePadding!==void 0&&(this.options.sidePadding=e.sidePadding),this.applyLayout()),(e.topPadding!==void 0||e.snapPoints!==void 0)&&this.state!=="closed"&&this.currentSnap>0)if(e.snapPoints!==void 0&&!this.options.snapPoints.includes(this.currentSnap)){let i=this.pixelsToSnap(this.currentH);this.animateToH(this.snapToPixels(i))}else this.currentH=this.snapToPixels(this.currentSnap),this.render(this.currentH)}setLayout(e){this.destroyed||(e.width!==void 0&&(this.options.width=e.width),e.align!==void 0&&(this.options.align=e.align),e.sidePadding!==void 0&&(this.options.sidePadding=e.sidePadding),this.applyLayout())}get isOpen(){return this.state!=="closed"}get currentSnapPoint(){return this.currentSnap}};export{S as Sheet};
|
|
1
|
+
var P={damping:30,stiffness:200,mass:1,restThreshold:.5};function D(s,e,t,i,r){let{stiffness:n,damping:a,mass:d}=r,o=s-e,u=-n*o,c=-a*t,p=(u+c)/d,l=t+p*i;return{position:s+l*i,velocity:l}}function Y(s,e,t,i=P.restThreshold){return Math.abs(s-e)<i&&Math.abs(t)<i}function x(s,e,t,i,r,n){let a={...P,...i},d=s,o=t,u=0,c=0;function p(l){if(u===0){u=l,c=requestAnimationFrame(p);return}let h=Math.min((l-u)/1e3,.064);u=l;let f=D(d,e,o,h,a);if(d=f.position,o=f.velocity,r(d),Y(d,e,o,a.restThreshold)){r(e),n();return}c=requestAnimationFrame(p)}return c=requestAnimationFrame(p),()=>cancelAnimationFrame(c)}var g=class{constructor(e=8){this.samples=[];this.maxSamples=e}add(e){this.samples.push({time:performance.now(),value:e}),this.samples.length>this.maxSamples&&this.samples.shift()}getVelocity(){if(this.samples.length<2)return 0;let e=this.samples[this.samples.length-1],t=this.samples[0];for(let r=this.samples.length-2;r>=0;r--)if(e.time-this.samples[r].time>=30){t=this.samples[r];break}let i=(e.time-t.time)/1e3;return i===0?0:(e.value-t.value)/i}reset(){this.samples=[]}};function H(s,e,t,i=400,r=1200){if(t.length===0)return s;if(t.length===1)return t[0];let n=[...t].sort((o,u)=>o-u);if(Math.abs(e)>r)return e>0?n[n.length-1]:n[0];if(Math.abs(e)>i)if(e>0){for(let o of n)if(o>s+2)return o;return n[n.length-1]}else{for(let o=n.length-1;o>=0;o--)if(n[o]<s-2)return n[o];return n[0]}let a=n[0],d=Math.abs(s-n[0]);for(let o=1;o<n.length;o++){let u=Math.abs(s-n[o]);u<d&&(a=n[o],d=u)}return a}var M=6,B=3;function R(s,e){let t=s;for(;t&&t!==e;){if(t.scrollHeight>t.clientHeight){let r=getComputedStyle(t).overflowY;if(r==="auto"||r==="scroll")return t}t=t.parentElement}return null}function C(s,e,t,i){let r=new g,n={active:!1,dragging:!1,startY:0,currentY:0,directionLocked:!1,lockedAxis:null,startX:0,currentX:0,scrolling:!1,scrollTarget:null};function a(l){let h=e?.contains(l.target);if(t&&!h)return;let f=h?null:R(l.target,s);n.active=!0,n.dragging=!1,n.startY=l.clientY,n.currentY=l.clientY,n.startX=l.clientX,n.currentX=l.clientX,n.directionLocked=!1,n.lockedAxis=null,n.scrolling=!1,n.scrollTarget=f,r.reset(),r.add(l.clientY),window.addEventListener("pointermove",o),window.addEventListener("pointerup",u),window.addEventListener("pointercancel",c)}function d(){window.removeEventListener("pointermove",o),window.removeEventListener("pointerup",u),window.removeEventListener("pointercancel",c)}function o(l){if(!n.active||n.scrolling)return;n.currentY=l.clientY,n.currentX=l.clientX;let h=Math.abs(n.currentX-n.startX),f=Math.abs(n.currentY-n.startY),L=n.currentY-n.startY;if(!(!n.directionLocked&&((h>M||f>M)&&(n.directionLocked=!0,n.lockedAxis=f>=h?"y":"x"),f<B))&&n.lockedAxis!=="x"){if(n.scrollTarget&&!n.dragging){let m=n.scrollTarget,k=m.scrollTop<=0,F=m.scrollTop+m.clientHeight>=m.scrollHeight-1,T=L>0;if(!(T&&k)){if(!(!T&&F)){n.scrolling=!0;return}}}n.dragging||(n.dragging=!0,s.setPointerCapture(l.pointerId),i.onStart(n.startY)),l.preventDefault(),r.add(l.clientY),i.onMove(n.currentY,L)}}function u(l){if(!n.active||(n.active=!1,d(),s.hasPointerCapture(l.pointerId)&&s.releasePointerCapture(l.pointerId),!n.dragging))return;n.dragging=!1;let h=r.getVelocity();i.onEnd(h)}function c(l){n.active&&(n.active=!1,d(),s.hasPointerCapture(l.pointerId)&&s.releasePointerCapture(l.pointerId),n.dragging&&(n.dragging=!1,i.onEnd(0)))}s.addEventListener("pointerdown",a);let p=l=>{n.active&&l.preventDefault()};return s.addEventListener("contextmenu",p),()=>{s.removeEventListener("pointerdown",a),d(),s.removeEventListener("contextmenu",p)}}var z=["a[href]","button:not([disabled])","input:not([disabled])","select:not([disabled])","textarea:not([disabled])",'[tabindex]:not([tabindex="-1"])'].join(", ");function b(s){let e=null;function t(){return Array.from(s.querySelectorAll(z))}function i(a){if(a.key!=="Tab")return;let d=t();if(d.length===0){a.preventDefault();return}let o=d[0],u=d[d.length-1];a.shiftKey?(document.activeElement===o||!s.contains(document.activeElement))&&(a.preventDefault(),u.focus()):(document.activeElement===u||!s.contains(document.activeElement))&&(a.preventDefault(),o.focus())}function r(){e=document.activeElement,s.addEventListener("keydown",i),requestAnimationFrame(()=>{let a=t();a.length>0?a[0].focus():s.focus()})}function n(){s.removeEventListener("keydown",i),e?.focus(),e=null}return r(),n}function E(s,e,t={}){s.setAttribute("role","dialog"),s.setAttribute("aria-modal",t.modal!==!1?"true":"false"),t.ariaLabelledBy?(s.setAttribute("aria-labelledby",t.ariaLabelledBy),s.removeAttribute("aria-label")):(s.setAttribute("aria-label",t.ariaLabel||"Sheet"),s.removeAttribute("aria-labelledby")),e&&e.setAttribute("aria-hidden","true")}function O(s,e){s.removeAttribute("role"),s.removeAttribute("aria-modal"),e&&e.removeAttribute("aria-hidden")}var w=0,v=null;function A(s){let e=s.target;for(;e;){if(e.classList?.contains("drwr-content"))return;e=e.parentElement}s.preventDefault()}function y(){let s=document.body,e=document.documentElement;w++===0&&(v={body:s.style.overflow,html:e.style.overflow},e.style.overflow="hidden",s.style.overflow="hidden",document.addEventListener("touchmove",A,{passive:!1}));let t=!1;return()=>{t||(t=!0,!(--w>0)&&(w=0,s.style.overflow=v?.body??"",e.style.overflow=v?.html??"",v=null,document.removeEventListener("touchmove",A)))}}function G(s){return 8*(Math.log(s+1)-2)}var S=class s{constructor(e,t={}){this.overlayEl=null;this.handleEl=null;this.state="closed";this.currentSnap=0;this.currentH=0;this.dragStartH=0;this.cancelAnimation=null;this.cleanupGestures=null;this.cleanupFocusTrap=null;this.unlockScroll=null;this.onPageShow=null;this.onResize=null;this.naturalContentH=0;this.destroyed=!1;this.onKeyDown=e=>{e.key==="Escape"&&this.state!=="closed"&&this.options.closeOnEscape&&this.close()};this.container=e;let i=s.sanitizeSnapPoints(t.snapPoints??[0,1]);this.options={snapPoints:i,defaultSnap:t.defaultSnap??0,overlay:t.overlay??!0,dragHandle:t.dragHandle??!0,damping:t.damping??30,stiffness:t.stiffness??200,mass:t.mass??1,closeThreshold:t.closeThreshold??.2,topPadding:t.topPadding??40,width:t.width??(window.innerWidth>=768?60:100),align:t.align??"center",sidePadding:t.sidePadding??0,maxWidth:t.maxWidth??0,dragMode:t.dragMode??"sheet",ariaLabel:t.ariaLabel??"Sheet",ariaLabelledBy:t.ariaLabelledBy??"",closeOnEscape:t.closeOnEscape??!0,closeOnOverlayClick:t.closeOnOverlayClick??!0,trapFocus:t.trapFocus??!0,modal:t.modal??!0,reducedMotion:t.reducedMotion??!0,onOpen:t.onOpen??(()=>{}),onClose:t.onClose??(()=>{}),onSnap:t.onSnap??(()=>{})},this.buildDOM(),this.container.removeAttribute("hidden"),this.naturalContentH=this.getContentHeight(),this.bindGestures();let r=this.options.defaultSnap;r>0&&this.options.snapPoints.includes(r)?(this.currentH=this.snapToPixels(r),this.render(this.currentH),this.state="open",this.currentSnap=r,document.addEventListener("keydown",this.onKeyDown),this.unlockScroll||(this.unlockScroll=y()),this.options.trapFocus&&!this.cleanupFocusTrap&&(this.cleanupFocusTrap=b(this.wrapperEl)),queueMicrotask(()=>{this.destroyed||this.options.onOpen()})):(this.currentH=0,this.render(0)),this.onPageShow=n=>{n.persisted&&this.state!=="closed"&&this.resetToClosedState()},window.addEventListener("pageshow",this.onPageShow),this.onResize=()=>{this.applyLayout(),this.naturalContentH=this.getContentHeight(),this.state!=="closed"&&this.currentSnap>0&&(this.currentH=this.snapToPixels(this.currentSnap),this.render(this.currentH))},window.addEventListener("resize",this.onResize)}static sanitizeSnapPoints(e){let t=e.filter(r=>Number.isFinite(r)&&r>=0&&r<=1),i=[...new Set(t)].sort((r,n)=>r-n);return i.length===0?[0,1]:(i.includes(0)||i.unshift(0),i)}prefersReducedMotion(){return this.options.reducedMotion&&typeof window<"u"&&window.matchMedia("(prefers-reduced-motion: reduce)").matches}getContentHeight(){return this.contentEl.scrollHeight+(this.handleEl?.offsetHeight??0)}maxSheetH(){return window.innerHeight-this.options.topPadding}snapToPixels(e){if(e<=0)return 0;let t=this.maxSheetH();return Math.min(e,1)*t}snapPixels(){return this.options.snapPoints.map(e=>this.snapToPixels(e)).sort((e,t)=>e-t)}pixelsToSnap(e){let t=this.options.snapPoints,i=t[0],r=Math.abs(e-this.snapToPixels(t[0]));for(let n=1;n<t.length;n++){let a=Math.abs(e-this.snapToPixels(t[n]));a<r&&(i=t[n],r=a)}return i}applyLayout(){let{width:e,align:t,sidePadding:i,maxWidth:r}=this.options,n=this.wrapperEl,a=window.innerWidth,d=Math.max(10,Math.min(100,e)),o=Math.max(0,Math.min(i,a/2-10)),u=Math.max(20,Math.min(a*(d/100),a-o*2));r>0&&(u=Math.min(u,r));let c;t==="left"?c=o:t==="right"?c=a-u-o:c=(a-u)/2,n.style.left=`${c}px`,n.style.right="auto",n.style.width=`${u}px`,n.style.margin="0"}buildDOM(){for(this.wrapperEl=document.createElement("div"),this.wrapperEl.className="drwr-sheet",this.wrapperEl.setAttribute("tabindex","-1"),this.options.dragHandle&&(this.handleEl=document.createElement("div"),this.handleEl.className="drwr-handle",this.wrapperEl.appendChild(this.handleEl)),this.contentEl=document.createElement("div"),this.contentEl.className="drwr-content";this.container.firstChild;)this.contentEl.appendChild(this.container.firstChild);this.wrapperEl.appendChild(this.contentEl),this.container.appendChild(this.wrapperEl),this.options.overlay&&(this.overlayEl=document.createElement("div"),this.overlayEl.className="drwr-overlay",this.overlayEl.addEventListener("click",()=>{this.options.closeOnOverlayClick&&this.close()}),this.container.insertBefore(this.overlayEl,this.wrapperEl)),E(this.wrapperEl,this.overlayEl,{ariaLabel:this.options.ariaLabel,ariaLabelledBy:this.options.ariaLabelledBy,modal:this.options.modal}),this.applyLayout()}bindGestures(){this.options.dragMode!=="none"&&(this.cleanupGestures=C(this.wrapperEl,this.handleEl,this.options.dragMode==="handle",{onStart:()=>{this.cancelCurrentAnimation(),this.state="dragging",this.dragStartH=this.currentH,this.wrapperEl.setAttribute("data-dragging","true")},onMove:(e,t)=>{let i=this.dragStartH-t,r=this.snapPixels(),n=r[r.length-1],a=r[0];if(i>n)i=n;else if(i<a){let d=a-i;i=a-Math.max(0,G(d))}this.currentH=i,this.render(i)},onEnd:e=>{this.wrapperEl.setAttribute("data-dragging","false");let t=-e;this.state="animating";let i=this.snapPixels(),r=H(this.currentH,t,i,400),n=i.filter(a=>a>0);if(n.length>0){let a=n[0];this.currentH<a*this.options.closeThreshold&&(r=0)}this.animateToH(r,t)}}))}cancelCurrentAnimation(){this.cancelAnimation&&(this.cancelAnimation(),this.cancelAnimation=null)}animateToH(e,t=0){let i=this.state==="open"||this.state==="dragging";this.cancelCurrentAnimation(),this.state="animating";let r=()=>{this.currentH=e,this.render(e),this.cancelAnimation=null;let a=this.pixelsToSnap(e);this.currentSnap=a,e<=.5?this.onClosed():(this.state="open",i||this.options.onOpen(),this.options.onSnap(a))};if(this.prefersReducedMotion()){r();return}let n={damping:this.options.damping,stiffness:this.options.stiffness,mass:this.options.mass};this.cancelAnimation=x(this.currentH,e,t,n,a=>{this.currentH=a,this.render(a)},r)}render(e){let t=window.innerHeight,i=Math.max(0,e),r=t-i;if(this.wrapperEl.style.visibility=i>.5?"visible":"hidden",this.wrapperEl.style.transform=`translate3d(0, ${r}px, 0)`,this.wrapperEl.style.height=i>.5?`${i}px`:"",this.overlayEl){let n=this.snapPixels(),a=n[n.length-1],d=Math.max(0,Math.min(1,i/(a*.3)));this.overlayEl.style.opacity=String(d),this.overlayEl.setAttribute("data-visible",i>1?"true":"false")}}resetToClosedState(){this.cancelCurrentAnimation(),this.currentH=0,this.currentSnap=0,this.render(0),this.state="closed",this.overlayEl&&(this.overlayEl.style.opacity="0",this.overlayEl.setAttribute("data-visible","false")),this.unlockScroll&&(this.unlockScroll(),this.unlockScroll=null),this.cleanupFocusTrap&&(this.cleanupFocusTrap(),this.cleanupFocusTrap=null),document.removeEventListener("keydown",this.onKeyDown)}onClosed(){this.resetToClosedState(),this.options.onClose()}open(e){if(this.destroyed||this.state==="open")return;let t=[...this.options.snapPoints].sort((r,n)=>r-n),i;if(e!==void 0){if(!t.includes(e)||e===0){console.warn(`[drwr] snap point ${e} not valid for open()`);return}i=e}else i=t[t.length-1];document.addEventListener("keydown",this.onKeyDown),this.animateToH(this.snapToPixels(i)),this.unlockScroll||(this.unlockScroll=y()),this.options.trapFocus&&!this.cleanupFocusTrap&&(this.cleanupFocusTrap=b(this.wrapperEl))}close(){this.destroyed||this.state==="closed"||(document.removeEventListener("keydown",this.onKeyDown),this.animateToH(0))}snapTo(e){if(!this.destroyed){if(!this.options.snapPoints.includes(e)){console.warn(`[drwr] snap point ${e} not in snapPoints`);return}e===0?this.close():(this.state==="closed"&&(document.addEventListener("keydown",this.onKeyDown),this.unlockScroll||(this.unlockScroll=y()),this.options.trapFocus&&!this.cleanupFocusTrap&&(this.cleanupFocusTrap=b(this.wrapperEl))),this.animateToH(this.snapToPixels(e)))}}destroy(){if(!this.destroyed){for(this.destroyed=!0,this.cancelCurrentAnimation(),document.removeEventListener("keydown",this.onKeyDown),this.cleanupGestures&&(this.cleanupGestures(),this.cleanupGestures=null),this.cleanupFocusTrap&&(this.cleanupFocusTrap(),this.cleanupFocusTrap=null),this.unlockScroll&&(this.unlockScroll(),this.unlockScroll=null),this.onPageShow&&(window.removeEventListener("pageshow",this.onPageShow),this.onPageShow=null),this.onResize&&(window.removeEventListener("resize",this.onResize),this.onResize=null),O(this.wrapperEl,this.overlayEl);this.contentEl.firstChild;)this.container.appendChild(this.contentEl.firstChild);this.wrapperEl.remove(),this.overlayEl?.remove()}}setSnapPoints(e){if(!this.destroyed&&(this.options.snapPoints=s.sanitizeSnapPoints(e),this.state!=="closed"&&this.currentSnap>0&&!this.options.snapPoints.includes(this.currentSnap))){let t=this.pixelsToSnap(this.currentH);this.animateToH(this.snapToPixels(t))}}refresh(){this.destroyed||(this.naturalContentH=this.getContentHeight(),this.state!=="closed"&&this.currentSnap>0&&(this.currentH=this.snapToPixels(this.currentSnap),this.render(this.currentH)))}setOptions(e){if(this.destroyed)return;if(e.snapPoints!==void 0&&(this.options.snapPoints=s.sanitizeSnapPoints(e.snapPoints)),e.damping!==void 0&&(this.options.damping=e.damping),e.stiffness!==void 0&&(this.options.stiffness=e.stiffness),e.mass!==void 0&&(this.options.mass=e.mass),e.closeThreshold!==void 0&&(this.options.closeThreshold=e.closeThreshold),e.topPadding!==void 0&&(this.options.topPadding=e.topPadding),e.closeOnEscape!==void 0&&(this.options.closeOnEscape=e.closeOnEscape),e.closeOnOverlayClick!==void 0&&(this.options.closeOnOverlayClick=e.closeOnOverlayClick),e.ariaLabel!==void 0&&(this.options.ariaLabel=e.ariaLabel),e.ariaLabelledBy!==void 0&&(this.options.ariaLabelledBy=e.ariaLabelledBy),e.modal!==void 0&&(this.options.modal=e.modal),e.maxWidth!==void 0&&(this.options.maxWidth=e.maxWidth),e.reducedMotion!==void 0&&(this.options.reducedMotion=e.reducedMotion),e.onOpen!==void 0&&(this.options.onOpen=e.onOpen),e.onClose!==void 0&&(this.options.onClose=e.onClose),e.onSnap!==void 0&&(this.options.onSnap=e.onSnap),(e.ariaLabel!==void 0||e.ariaLabelledBy!==void 0||e.modal!==void 0)&&E(this.wrapperEl,this.overlayEl,{ariaLabel:this.options.ariaLabel,ariaLabelledBy:this.options.ariaLabelledBy,modal:this.options.modal}),(e.width!==void 0||e.align!==void 0||e.sidePadding!==void 0||e.maxWidth!==void 0)&&(e.width!==void 0&&(this.options.width=e.width),e.align!==void 0&&(this.options.align=e.align),e.sidePadding!==void 0&&(this.options.sidePadding=e.sidePadding),this.applyLayout()),(e.topPadding!==void 0||e.snapPoints!==void 0)&&this.state!=="closed"&&this.currentSnap>0)if(e.snapPoints!==void 0&&!this.options.snapPoints.includes(this.currentSnap)){let i=this.pixelsToSnap(this.currentH);this.animateToH(this.snapToPixels(i))}else this.currentH=this.snapToPixels(this.currentSnap),this.render(this.currentH)}setLayout(e){this.destroyed||(e.width!==void 0&&(this.options.width=e.width),e.align!==void 0&&(this.options.align=e.align),e.sidePadding!==void 0&&(this.options.sidePadding=e.sidePadding),this.applyLayout())}get isOpen(){return this.state!=="closed"}get currentSnapPoint(){return this.currentSnap}};export{S as Sheet};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/physics.ts","../src/gestures.ts","../src/accessibility.ts","../src/sheet.ts"],"sourcesContent":["export interface SpringConfig {\n damping: number;\n stiffness: number;\n mass: number;\n restThreshold: number;\n}\n\nexport const DEFAULT_SPRING: SpringConfig = {\n damping: 30,\n stiffness: 200,\n mass: 1,\n restThreshold: 0.5,\n};\n\nexport interface SpringState {\n position: number;\n velocity: number;\n}\n\n/**\n * Solve one step of a damped spring using semi-implicit Euler integration.\n * Returns the new position and velocity after `dt` seconds.\n */\nexport function springStep(\n current: number,\n target: number,\n velocity: number,\n dt: number,\n config: SpringConfig,\n): SpringState {\n const { stiffness, damping, mass } = config;\n const displacement = current - target;\n const springForce = -stiffness * displacement;\n const dampingForce = -damping * velocity;\n const acceleration = (springForce + dampingForce) / mass;\n\n const newVelocity = velocity + acceleration * dt;\n const newPosition = current + newVelocity * dt;\n\n return { position: newPosition, velocity: newVelocity };\n}\n\n/**\n * Returns true when the spring is close enough to rest.\n */\nexport function isAtRest(\n current: number,\n target: number,\n velocity: number,\n threshold: number = DEFAULT_SPRING.restThreshold,\n): boolean {\n return (\n Math.abs(current - target) < threshold && Math.abs(velocity) < threshold\n );\n}\n\n/**\n * Runs a spring animation via requestAnimationFrame. Returns a cancel function.\n */\nexport function animateSpring(\n from: number,\n to: number,\n initialVelocity: number,\n config: Partial<SpringConfig>,\n onUpdate: (value: number) => void,\n onComplete: () => void,\n): () => void {\n const cfg = { ...DEFAULT_SPRING, ...config };\n let position = from;\n let velocity = initialVelocity;\n let lastTime = 0;\n let frameId = 0;\n\n function tick(time: number) {\n if (lastTime === 0) {\n lastTime = time;\n frameId = requestAnimationFrame(tick);\n return;\n }\n\n // Cap dt to avoid spiral of death on tab-switch resume\n const dt = Math.min((time - lastTime) / 1000, 0.064);\n lastTime = time;\n\n const state = springStep(position, to, velocity, dt, cfg);\n position = state.position;\n velocity = state.velocity;\n\n onUpdate(position);\n\n if (isAtRest(position, to, velocity, cfg.restThreshold)) {\n onUpdate(to);\n onComplete();\n return;\n }\n\n frameId = requestAnimationFrame(tick);\n }\n\n frameId = requestAnimationFrame(tick);\n\n return () => cancelAnimationFrame(frameId);\n}\n\n/**\n * Tracks pointer velocity over the last N samples for flick detection.\n */\nexport class VelocityTracker {\n private samples: { time: number; value: number }[] = [];\n private maxSamples: number;\n\n constructor(maxSamples = 8) {\n this.maxSamples = maxSamples;\n }\n\n add(value: number) {\n this.samples.push({ time: performance.now(), value });\n if (this.samples.length > this.maxSamples) {\n this.samples.shift();\n }\n }\n\n /** Returns velocity in units per second. */\n getVelocity(): number {\n if (this.samples.length < 2) return 0;\n\n const recent = this.samples[this.samples.length - 1];\n // Use sample from ~50ms ago for stability\n let oldest = this.samples[0];\n for (let i = this.samples.length - 2; i >= 0; i--) {\n if (recent.time - this.samples[i].time >= 30) {\n oldest = this.samples[i];\n break;\n }\n }\n\n const dt = (recent.time - oldest.time) / 1000;\n if (dt === 0) return 0;\n\n return (recent.value - oldest.value) / dt;\n }\n\n reset() {\n this.samples = [];\n }\n}\n\n/**\n * Given a set of snap points and a release position + velocity,\n * determine which snap point to target.\n */\nexport function resolveSnapPoint(\n position: number,\n velocity: number,\n snapPoints: number[],\n flickThreshold = 400,\n hardFlickThreshold = 1200,\n): number {\n if (snapPoints.length === 0) return position;\n if (snapPoints.length === 1) return snapPoints[0];\n\n const sorted = [...snapPoints].sort((a, b) => a - b);\n\n // Hard flick: skip all intermediate snaps, go to the extreme\n if (Math.abs(velocity) > hardFlickThreshold) {\n return velocity > 0 ? sorted[sorted.length - 1] : sorted[0];\n }\n\n // Normal flick: go to next snap in the flick direction\n if (Math.abs(velocity) > flickThreshold) {\n if (velocity > 0) {\n for (const sp of sorted) {\n if (sp > position + 2) return sp;\n }\n return sorted[sorted.length - 1];\n } else {\n for (let i = sorted.length - 1; i >= 0; i--) {\n if (sorted[i] < position - 2) return sorted[i];\n }\n return sorted[0];\n }\n }\n\n // No flick: snap to nearest\n let closest = sorted[0];\n let closestDist = Math.abs(position - sorted[0]);\n for (let i = 1; i < sorted.length; i++) {\n const dist = Math.abs(position - sorted[i]);\n if (dist < closestDist) {\n closest = sorted[i];\n closestDist = dist;\n }\n }\n return closest;\n}\n","import { VelocityTracker } from \"./physics.js\";\n\nexport interface GestureCallbacks {\n onStart: (y: number) => void;\n onMove: (y: number, deltaY: number) => void;\n onEnd: (velocity: number) => void;\n}\n\ninterface GestureState {\n active: boolean;\n dragging: boolean;\n startY: number;\n currentY: number;\n directionLocked: boolean;\n lockedAxis: \"x\" | \"y\" | null;\n startX: number;\n currentX: number;\n scrolling: boolean;\n scrollTarget: HTMLElement | null;\n}\n\nconst DIRECTION_LOCK_THRESHOLD = 6;\nconst SCROLL_LOCK_THRESHOLD = 3;\n\nfunction findScrollableAncestor(\n target: EventTarget | null,\n sheetEl: HTMLElement,\n): HTMLElement | null {\n let el = target as HTMLElement | null;\n while (el && el !== sheetEl) {\n if (el.scrollHeight > el.clientHeight) {\n const style = getComputedStyle(el);\n const overflowY = style.overflowY;\n if (overflowY === \"auto\" || overflowY === \"scroll\") {\n return el;\n }\n }\n el = el.parentElement;\n }\n return null;\n}\n\nexport function attachGestures(\n sheetEl: HTMLElement,\n handleEl: HTMLElement | null,\n handleOnly: boolean,\n callbacks: GestureCallbacks,\n): () => void {\n const tracker = new VelocityTracker();\n const state: GestureState = {\n active: false,\n dragging: false,\n startY: 0,\n currentY: 0,\n directionLocked: false,\n lockedAxis: null,\n startX: 0,\n currentX: 0,\n scrolling: false,\n scrollTarget: null,\n };\n\n function onPointerDown(e: PointerEvent) {\n const isHandle = handleEl?.contains(e.target as Node);\n if (handleOnly && !isHandle) return;\n const scrollable = isHandle\n ? null\n : findScrollableAncestor(e.target, sheetEl);\n\n state.active = true;\n state.dragging = false;\n state.startY = e.clientY;\n state.currentY = e.clientY;\n state.startX = e.clientX;\n state.currentX = e.clientX;\n state.directionLocked = false;\n state.lockedAxis = null;\n state.scrolling = false;\n state.scrollTarget = scrollable;\n\n tracker.reset();\n tracker.add(e.clientY);\n\n sheetEl.setPointerCapture(e.pointerId);\n }\n\n function onPointerMove(e: PointerEvent) {\n if (!state.active || state.scrolling) return;\n\n state.currentY = e.clientY;\n state.currentX = e.clientX;\n\n const dx = Math.abs(state.currentX - state.startX);\n const dy = Math.abs(state.currentY - state.startY);\n const deltaY = state.currentY - state.startY;\n\n // Direction locking\n if (!state.directionLocked) {\n if (dx > DIRECTION_LOCK_THRESHOLD || dy > DIRECTION_LOCK_THRESHOLD) {\n state.directionLocked = true;\n state.lockedAxis = dy >= dx ? \"y\" : \"x\";\n }\n if (dy < SCROLL_LOCK_THRESHOLD) return;\n }\n\n if (state.lockedAxis === \"x\") return;\n\n // Scroll vs drag disambiguation (decided once)\n if (state.scrollTarget && !state.dragging) {\n const st = state.scrollTarget;\n const atTop = st.scrollTop <= 0;\n const atBottom = st.scrollTop + st.clientHeight >= st.scrollHeight - 1;\n const draggingDown = deltaY > 0;\n\n if (draggingDown && atTop) {\n // At top, pulling down → drag sheet\n } else if (!draggingDown && atBottom) {\n // At bottom, pulling up → drag sheet\n } else {\n // Let the content scroll\n state.scrolling = true;\n return;\n }\n }\n\n // Begin drag on first qualifying move\n if (!state.dragging) {\n state.dragging = true;\n callbacks.onStart(state.startY);\n }\n\n e.preventDefault();\n tracker.add(e.clientY);\n callbacks.onMove(state.currentY, deltaY);\n }\n\n function onPointerUp(e: PointerEvent) {\n if (!state.active) return;\n state.active = false;\n sheetEl.releasePointerCapture(e.pointerId);\n\n if (!state.dragging) return;\n state.dragging = false;\n\n const velocity = tracker.getVelocity();\n callbacks.onEnd(velocity);\n }\n\n function onPointerCancel(e: PointerEvent) {\n if (!state.active) return;\n state.active = false;\n sheetEl.releasePointerCapture(e.pointerId);\n\n if (!state.dragging) return;\n state.dragging = false;\n callbacks.onEnd(0);\n }\n\n sheetEl.addEventListener(\"pointerdown\", onPointerDown);\n sheetEl.addEventListener(\"pointermove\", onPointerMove);\n sheetEl.addEventListener(\"pointerup\", onPointerUp);\n sheetEl.addEventListener(\"pointercancel\", onPointerCancel);\n\n const onContextMenu = (e: Event) => {\n if (state.active) e.preventDefault();\n };\n sheetEl.addEventListener(\"contextmenu\", onContextMenu);\n\n return () => {\n sheetEl.removeEventListener(\"pointerdown\", onPointerDown);\n sheetEl.removeEventListener(\"pointermove\", onPointerMove);\n sheetEl.removeEventListener(\"pointerup\", onPointerUp);\n sheetEl.removeEventListener(\"pointercancel\", onPointerCancel);\n sheetEl.removeEventListener(\"contextmenu\", onContextMenu);\n };\n}\n","const FOCUSABLE_SELECTORS = [\n \"a[href]\",\n \"button:not([disabled])\",\n \"input:not([disabled])\",\n \"select:not([disabled])\",\n \"textarea:not([disabled])\",\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(\", \");\n\n/**\n * Creates a focus trap within the given element.\n * Returns a cleanup function.\n */\nexport function createFocusTrap(container: HTMLElement): () => void {\n let previousFocus: HTMLElement | null = null;\n\n function getFocusable(): HTMLElement[] {\n return Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTORS));\n }\n\n function onKeyDown(e: KeyboardEvent) {\n if (e.key !== \"Tab\") return;\n\n const focusable = getFocusable();\n if (focusable.length === 0) {\n e.preventDefault();\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first || !container.contains(document.activeElement)) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last || !container.contains(document.activeElement)) {\n e.preventDefault();\n first.focus();\n }\n }\n }\n\n function activate() {\n previousFocus = document.activeElement as HTMLElement | null;\n container.addEventListener(\"keydown\", onKeyDown);\n\n // Focus first focusable element or the container itself\n requestAnimationFrame(() => {\n const focusable = getFocusable();\n if (focusable.length > 0) {\n focusable[0].focus();\n } else {\n container.focus();\n }\n });\n }\n\n function deactivate() {\n container.removeEventListener(\"keydown\", onKeyDown);\n previousFocus?.focus();\n previousFocus = null;\n }\n\n activate();\n\n return deactivate;\n}\n\nexport interface AriaOptions {\n ariaLabel?: string;\n ariaLabelledBy?: string;\n modal?: boolean;\n}\n\n/**\n * Applies ARIA attributes for a modal dialog.\n */\nexport function applyAriaAttributes(\n sheetEl: HTMLElement,\n overlayEl: HTMLElement | null,\n opts: AriaOptions = {},\n) {\n sheetEl.setAttribute(\"role\", \"dialog\");\n sheetEl.setAttribute(\"aria-modal\", opts.modal !== false ? \"true\" : \"false\");\n\n if (opts.ariaLabelledBy) {\n sheetEl.setAttribute(\"aria-labelledby\", opts.ariaLabelledBy);\n sheetEl.removeAttribute(\"aria-label\");\n } else {\n sheetEl.setAttribute(\"aria-label\", opts.ariaLabel || \"Sheet\");\n sheetEl.removeAttribute(\"aria-labelledby\");\n }\n\n if (overlayEl) {\n overlayEl.setAttribute(\"aria-hidden\", \"true\");\n }\n}\n\n/**\n * Removes ARIA attributes when the sheet is destroyed.\n */\nexport function removeAriaAttributes(\n sheetEl: HTMLElement,\n overlayEl: HTMLElement | null,\n) {\n sheetEl.removeAttribute(\"role\");\n sheetEl.removeAttribute(\"aria-modal\");\n if (overlayEl) {\n overlayEl.removeAttribute(\"aria-hidden\");\n }\n}\n\n/**\n * iOS-safe scroll lock. Prevents background scrolling without position:fixed\n * to avoid the iOS Safari viewport jump when the address bar is visible.\n */\nexport function lockScroll(): () => void {\n const body = document.body;\n const html = document.documentElement;\n\n const originalBodyOverflow = body.style.overflow;\n const originalHtmlOverflow = html.style.overflow;\n\n html.style.overflow = \"hidden\";\n body.style.overflow = \"hidden\";\n\n // On iOS Safari, overflow:hidden on body/html doesn't fully prevent\n // scroll on its own. We block touchmove on the document as a fallback.\n const preventTouch = (e: TouchEvent) => {\n // Allow scrolling inside the sheet content\n let el = e.target as HTMLElement | null;\n while (el) {\n if (el.classList?.contains(\"drwr-content\")) return;\n el = el.parentElement;\n }\n e.preventDefault();\n };\n\n document.addEventListener(\"touchmove\", preventTouch, { passive: false });\n\n return () => {\n body.style.overflow = originalBodyOverflow;\n html.style.overflow = originalHtmlOverflow;\n document.removeEventListener(\"touchmove\", preventTouch);\n };\n}\n","import {\n animateSpring,\n resolveSnapPoint,\n type SpringConfig,\n} from \"./physics.js\";\nimport { attachGestures } from \"./gestures.js\";\nimport {\n applyAriaAttributes,\n removeAriaAttributes,\n createFocusTrap,\n lockScroll,\n} from \"./accessibility.js\";\n\nexport type SheetAlign = \"center\" | \"left\" | \"right\";\nexport type DragMode = \"handle\" | \"sheet\" | \"none\";\n\nexport interface SheetOptions {\n snapPoints?: number[];\n defaultSnap?: number;\n overlay?: boolean;\n dragHandle?: boolean;\n damping?: number;\n stiffness?: number;\n mass?: number;\n closeThreshold?: number;\n /** Top padding in px for the maximum open height. Default: 40. */\n topPadding?: number;\n /** Width as a percentage of the viewport (0–100). Default: 60 on desktop, 100 on mobile. */\n width?: number;\n /** Horizontal alignment. Default: \"center\". */\n align?: SheetAlign;\n /** Minimum side padding in px. Default: 0. */\n sidePadding?: number;\n /** Max width in px. 0 = no max. Default: 0. */\n maxWidth?: number;\n /** Which part of the sheet initiates drag. Default: \"sheet\". */\n dragMode?: DragMode;\n /** Accessible label for the sheet dialog. Default: \"Sheet\". */\n ariaLabel?: string;\n /** ID of the element labelling the sheet. Overrides ariaLabel when set. */\n ariaLabelledBy?: string;\n /** Close on Escape key. Default: true. */\n closeOnEscape?: boolean;\n /** Close on overlay click. Default: true. */\n closeOnOverlayClick?: boolean;\n /** Trap focus inside the sheet. Default: true. */\n trapFocus?: boolean;\n /** Set aria-modal. Default: true. */\n modal?: boolean;\n /** Honour prefers-reduced-motion by skipping spring animation. Default: true. */\n reducedMotion?: boolean;\n /** Called when open animation completes. */\n onOpen?: () => void;\n /** Called when close animation completes. */\n onClose?: () => void;\n onSnap?: (point: number) => void;\n}\n\n/** Subset of SheetOptions that can be changed at runtime via setOptions(). */\nexport type MutableSheetOptions = Pick<\n SheetOptions,\n | \"snapPoints\"\n | \"damping\"\n | \"stiffness\"\n | \"mass\"\n | \"closeThreshold\"\n | \"topPadding\"\n | \"width\"\n | \"align\"\n | \"sidePadding\"\n | \"maxWidth\"\n | \"ariaLabel\"\n | \"ariaLabelledBy\"\n | \"closeOnEscape\"\n | \"closeOnOverlayClick\"\n | \"modal\"\n | \"reducedMotion\"\n | \"onOpen\"\n | \"onClose\"\n | \"onSnap\"\n>;\n\ntype SheetState = \"closed\" | \"open\" | \"dragging\" | \"animating\";\n\n/** Logarithmic resistance like vaul: soft, organic feel past bounds. */\nfunction dampen(v: number): number {\n return 8 * (Math.log(v + 1) - 2);\n}\n\nexport class Sheet {\n private container: HTMLElement;\n private options: Required<SheetOptions>;\n\n private wrapperEl!: HTMLElement;\n private overlayEl: HTMLElement | null = null;\n private handleEl: HTMLElement | null = null;\n private contentEl!: HTMLElement;\n\n private state: SheetState = \"closed\";\n private currentSnap = 0;\n // Current height of the sheet in pixels (0 = closed, positive = visible)\n private currentH = 0;\n private dragStartH = 0;\n\n private cancelAnimation: (() => void) | null = null;\n private cleanupGestures: (() => void) | null = null;\n private cleanupFocusTrap: (() => void) | null = null;\n private unlockScroll: (() => void) | null = null;\n private onPageShow: ((e: PageTransitionEvent) => void) | null = null;\n private onResize: (() => void) | null = null;\n private naturalContentH = 0;\n private destroyed = false;\n\n private static sanitizeSnapPoints(raw: number[]): number[] {\n const valid = raw.filter((n) => Number.isFinite(n) && n >= 0 && n <= 1);\n const deduped = [...new Set(valid)].sort((a, b) => a - b);\n if (deduped.length === 0) return [0, 1];\n if (!deduped.includes(0)) deduped.unshift(0);\n return deduped;\n }\n\n private prefersReducedMotion(): boolean {\n return (\n this.options.reducedMotion &&\n typeof window !== \"undefined\" &&\n window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches\n );\n }\n\n constructor(container: HTMLElement, options: SheetOptions = {}) {\n this.container = container;\n const snaps = Sheet.sanitizeSnapPoints(options.snapPoints ?? [0, 1]);\n this.options = {\n snapPoints: snaps,\n defaultSnap: options.defaultSnap ?? 0,\n overlay: options.overlay ?? true,\n dragHandle: options.dragHandle ?? true,\n damping: options.damping ?? 30,\n stiffness: options.stiffness ?? 200,\n mass: options.mass ?? 1,\n closeThreshold: options.closeThreshold ?? 0.2,\n topPadding: options.topPadding ?? 40,\n width: options.width ?? (window.innerWidth >= 768 ? 60 : 100),\n align: options.align ?? \"center\",\n sidePadding: options.sidePadding ?? 0,\n maxWidth: options.maxWidth ?? 0,\n dragMode: options.dragMode ?? \"sheet\",\n ariaLabel: options.ariaLabel ?? \"Sheet\",\n ariaLabelledBy: options.ariaLabelledBy ?? \"\",\n closeOnEscape: options.closeOnEscape ?? true,\n closeOnOverlayClick: options.closeOnOverlayClick ?? true,\n trapFocus: options.trapFocus ?? true,\n modal: options.modal ?? true,\n reducedMotion: options.reducedMotion ?? true,\n onOpen: options.onOpen ?? (() => {}),\n onClose: options.onClose ?? (() => {}),\n onSnap: options.onSnap ?? (() => {}),\n };\n\n this.buildDOM();\n this.container.removeAttribute(\"hidden\");\n this.naturalContentH = this.getContentHeight();\n this.bindGestures();\n\n const defaultSnap = this.options.defaultSnap;\n if (defaultSnap > 0 && this.options.snapPoints.includes(defaultSnap)) {\n this.currentH = this.snapToPixels(defaultSnap);\n this.render(this.currentH);\n this.state = \"open\";\n this.currentSnap = defaultSnap;\n document.addEventListener(\"keydown\", this.onKeyDown);\n if (!this.unlockScroll) this.unlockScroll = lockScroll();\n if (this.options.trapFocus && !this.cleanupFocusTrap) {\n this.cleanupFocusTrap = createFocusTrap(this.wrapperEl);\n }\n queueMicrotask(() => {\n if (this.destroyed) return;\n this.options.onOpen();\n });\n } else {\n this.currentH = 0;\n this.render(0);\n }\n this.onPageShow = (e: PageTransitionEvent) => {\n if (e.persisted && this.state !== \"closed\") {\n this.resetToClosedState();\n }\n };\n window.addEventListener(\"pageshow\", this.onPageShow);\n\n this.onResize = () => {\n this.applyLayout();\n this.naturalContentH = this.getContentHeight();\n if (this.state !== \"closed\" && this.currentSnap > 0) {\n this.currentH = this.snapToPixels(this.currentSnap);\n this.render(this.currentH);\n }\n };\n window.addEventListener(\"resize\", this.onResize);\n }\n\n // --- Snap point conversion ---\n\n private getContentHeight(): number {\n return this.contentEl.scrollHeight + (this.handleEl?.offsetHeight ?? 0);\n }\n\n private maxSheetH(): number {\n return window.innerHeight - this.options.topPadding;\n }\n\n /** Convert a normalized snap point (0–1) to available viewport height. */\n private snapToPixels(snap: number): number {\n if (snap <= 0) return 0;\n const maxH = this.maxSheetH();\n return Math.min(snap, 1) * maxH;\n }\n\n /** Get all snap points as pixel heights, sorted ascending. */\n private snapPixels(): number[] {\n return this.options.snapPoints\n .map((s) => this.snapToPixels(s))\n .sort((a, b) => a - b);\n }\n\n /** Find the normalized snap point closest to a pixel height. */\n private pixelsToSnap(px: number): number {\n const snaps = this.options.snapPoints;\n let closest = snaps[0];\n let closestDist = Math.abs(px - this.snapToPixels(snaps[0]));\n for (let i = 1; i < snaps.length; i++) {\n const dist = Math.abs(px - this.snapToPixels(snaps[i]));\n if (dist < closestDist) {\n closest = snaps[i];\n closestDist = dist;\n }\n }\n return closest;\n }\n\n // --- DOM ---\n\n private applyLayout() {\n const { width, align, sidePadding, maxWidth } = this.options;\n const el = this.wrapperEl;\n\n const vw = window.innerWidth;\n const clampedWidth = Math.max(10, Math.min(100, width));\n const pad = Math.max(0, Math.min(sidePadding, vw / 2 - 10));\n\n let sheetW = Math.max(20, Math.min(vw * (clampedWidth / 100), vw - pad * 2));\n if (maxWidth > 0) sheetW = Math.min(sheetW, maxWidth);\n\n let left: number;\n if (align === \"left\") {\n left = pad;\n } else if (align === \"right\") {\n left = vw - sheetW - pad;\n } else {\n left = (vw - sheetW) / 2;\n }\n\n el.style.left = `${left}px`;\n el.style.right = \"auto\";\n el.style.width = `${sheetW}px`;\n el.style.margin = \"0\";\n }\n\n private buildDOM() {\n this.wrapperEl = document.createElement(\"div\");\n this.wrapperEl.className = \"drwr-sheet\";\n this.wrapperEl.setAttribute(\"tabindex\", \"-1\");\n\n if (this.options.dragHandle) {\n this.handleEl = document.createElement(\"div\");\n this.handleEl.className = \"drwr-handle\";\n this.wrapperEl.appendChild(this.handleEl);\n }\n\n this.contentEl = document.createElement(\"div\");\n this.contentEl.className = \"drwr-content\";\n\n while (this.container.firstChild) {\n this.contentEl.appendChild(this.container.firstChild);\n }\n this.wrapperEl.appendChild(this.contentEl);\n this.container.appendChild(this.wrapperEl);\n\n if (this.options.overlay) {\n this.overlayEl = document.createElement(\"div\");\n this.overlayEl.className = \"drwr-overlay\";\n this.overlayEl.addEventListener(\"click\", () => {\n if (this.options.closeOnOverlayClick) this.close();\n });\n this.container.insertBefore(this.overlayEl, this.wrapperEl);\n }\n\n applyAriaAttributes(this.wrapperEl, this.overlayEl, {\n ariaLabel: this.options.ariaLabel,\n ariaLabelledBy: this.options.ariaLabelledBy,\n modal: this.options.modal,\n });\n this.applyLayout();\n }\n\n // --- Gestures ---\n\n private bindGestures() {\n if (this.options.dragMode === \"none\") return;\n this.cleanupGestures = attachGestures(\n this.wrapperEl,\n this.handleEl,\n this.options.dragMode === \"handle\",\n {\n onStart: () => {\n this.cancelCurrentAnimation();\n this.state = \"dragging\";\n this.dragStartH = this.currentH;\n this.wrapperEl.setAttribute(\"data-dragging\", \"true\");\n },\n onMove: (_y, deltaY) => {\n // deltaY positive = finger moved down = sheet should shrink\n let newH = this.dragStartH - deltaY;\n\n const snaps = this.snapPixels();\n const maxH = snaps[snaps.length - 1];\n const minH = snaps[0];\n\n if (newH > maxH) {\n newH = maxH;\n } else if (newH < minH) {\n const overflow = minH - newH;\n newH = minH - Math.max(0, dampen(overflow));\n }\n\n this.currentH = newH;\n this.render(newH);\n },\n onEnd: (velocityPx) => {\n this.wrapperEl.setAttribute(\"data-dragging\", \"false\");\n const velocityH = -velocityPx;\n this.state = \"animating\";\n\n const snaps = this.snapPixels();\n let targetH = resolveSnapPoint(this.currentH, velocityH, snaps, 400);\n\n // closeThreshold: if the sheet is dragged below (lowestNonZeroSnap * threshold), close it\n const nonZeroSnaps = snaps.filter((s) => s > 0);\n if (nonZeroSnaps.length > 0) {\n const lowestNonZero = nonZeroSnaps[0];\n if (this.currentH < lowestNonZero * this.options.closeThreshold) {\n targetH = 0;\n }\n }\n\n this.animateToH(targetH, velocityH);\n },\n },\n );\n }\n\n // --- Animation ---\n\n private cancelCurrentAnimation() {\n if (this.cancelAnimation) {\n this.cancelAnimation();\n this.cancelAnimation = null;\n }\n }\n\n private animateToH(targetH: number, initialVelocity = 0) {\n const wasOpen = this.state === \"open\" || this.state === \"dragging\";\n this.cancelCurrentAnimation();\n this.state = \"animating\";\n const onDone = () => {\n this.currentH = targetH;\n this.render(targetH);\n this.cancelAnimation = null;\n\n const snap = this.pixelsToSnap(targetH);\n this.currentSnap = snap;\n\n if (targetH <= 0.5) {\n this.onClosed();\n } else {\n this.state = \"open\";\n if (!wasOpen) this.options.onOpen();\n this.options.onSnap(snap);\n }\n };\n\n if (this.prefersReducedMotion()) {\n onDone();\n return;\n }\n\n const springConfig: Partial<SpringConfig> = {\n damping: this.options.damping,\n stiffness: this.options.stiffness,\n mass: this.options.mass,\n };\n\n this.cancelAnimation = animateSpring(\n this.currentH,\n targetH,\n initialVelocity,\n springConfig,\n (value) => {\n this.currentH = value;\n this.render(value);\n },\n onDone,\n );\n }\n\n // --- Rendering ---\n\n private render(h: number) {\n const viewportH = window.innerHeight;\n const visibleH = Math.max(0, h);\n const translateY = viewportH - visibleH;\n\n this.wrapperEl.style.visibility = visibleH > 0.5 ? \"visible\" : \"hidden\";\n\n this.wrapperEl.style.transform = `translate3d(0, ${translateY}px, 0)`;\n this.wrapperEl.style.height = visibleH > 0.5 ? `${visibleH}px` : \"\";\n\n if (this.overlayEl) {\n const snaps = this.snapPixels();\n const maxH = snaps[snaps.length - 1];\n const opacity = Math.max(0, Math.min(1, visibleH / (maxH * 0.3)));\n this.overlayEl.style.opacity = String(opacity);\n this.overlayEl.setAttribute(\"data-visible\", visibleH > 1 ? \"true\" : \"false\");\n }\n }\n\n // --- State changes ---\n\n /** Shared cleanup: visually close and tear down locks/traps. Does NOT fire callbacks. */\n private resetToClosedState() {\n this.cancelCurrentAnimation();\n this.currentH = 0;\n this.currentSnap = 0;\n this.render(0);\n this.state = \"closed\";\n\n if (this.overlayEl) {\n this.overlayEl.style.opacity = \"0\";\n this.overlayEl.setAttribute(\"data-visible\", \"false\");\n }\n if (this.unlockScroll) {\n this.unlockScroll();\n this.unlockScroll = null;\n }\n if (this.cleanupFocusTrap) {\n this.cleanupFocusTrap();\n this.cleanupFocusTrap = null;\n }\n document.removeEventListener(\"keydown\", this.onKeyDown);\n }\n\n private onClosed() {\n this.resetToClosedState();\n this.options.onClose();\n }\n\n // --- Keyboard ---\n\n private onKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\" && this.state !== \"closed\" && this.options.closeOnEscape) {\n this.close();\n }\n };\n\n // --- Public API ---\n\n open(point?: number) {\n if (this.destroyed || this.state === \"open\") return;\n\n const sorted = [...this.options.snapPoints].sort((a, b) => a - b);\n let target: number;\n if (point !== undefined) {\n if (!sorted.includes(point) || point === 0) {\n console.warn(`[drwr] snap point ${point} not valid for open()`);\n return;\n }\n target = point;\n } else {\n target = sorted[sorted.length - 1];\n }\n\n document.addEventListener(\"keydown\", this.onKeyDown);\n this.animateToH(this.snapToPixels(target));\n if (!this.unlockScroll) this.unlockScroll = lockScroll();\n if (this.options.trapFocus && !this.cleanupFocusTrap) {\n this.cleanupFocusTrap = createFocusTrap(this.wrapperEl);\n }\n }\n\n close() {\n if (this.destroyed || this.state === \"closed\") return;\n document.removeEventListener(\"keydown\", this.onKeyDown);\n this.animateToH(0);\n }\n\n snapTo(point: number) {\n if (this.destroyed) return;\n if (!this.options.snapPoints.includes(point)) {\n console.warn(`[drwr] snap point ${point} not in snapPoints`);\n return;\n }\n if (point === 0) {\n this.close();\n } else {\n if (this.state === \"closed\") {\n document.addEventListener(\"keydown\", this.onKeyDown);\n if (!this.unlockScroll) this.unlockScroll = lockScroll();\n if (this.options.trapFocus && !this.cleanupFocusTrap) {\n this.cleanupFocusTrap = createFocusTrap(this.wrapperEl);\n }\n }\n this.animateToH(this.snapToPixels(point));\n }\n }\n\n destroy() {\n if (this.destroyed) return;\n this.destroyed = true;\n\n this.cancelCurrentAnimation();\n document.removeEventListener(\"keydown\", this.onKeyDown);\n\n if (this.cleanupGestures) {\n this.cleanupGestures();\n this.cleanupGestures = null;\n }\n if (this.cleanupFocusTrap) {\n this.cleanupFocusTrap();\n this.cleanupFocusTrap = null;\n }\n if (this.unlockScroll) {\n this.unlockScroll();\n this.unlockScroll = null;\n }\n if (this.onPageShow) {\n window.removeEventListener(\"pageshow\", this.onPageShow);\n this.onPageShow = null;\n }\n if (this.onResize) {\n window.removeEventListener(\"resize\", this.onResize);\n this.onResize = null;\n }\n\n removeAriaAttributes(this.wrapperEl, this.overlayEl);\n\n while (this.contentEl.firstChild) {\n this.container.appendChild(this.contentEl.firstChild);\n }\n\n this.wrapperEl.remove();\n this.overlayEl?.remove();\n\n }\n\n setSnapPoints(points: number[]) {\n if (this.destroyed) return;\n this.options.snapPoints = Sheet.sanitizeSnapPoints(points);\n\n if (this.state !== \"closed\" && this.currentSnap > 0) {\n if (!this.options.snapPoints.includes(this.currentSnap)) {\n const nearest = this.pixelsToSnap(this.currentH);\n this.animateToH(this.snapToPixels(nearest));\n }\n }\n }\n\n /** Re-measure content height and recompute current position. Call after dynamic content changes. */\n refresh() {\n if (this.destroyed) return;\n this.naturalContentH = this.getContentHeight();\n if (this.state !== \"closed\" && this.currentSnap > 0) {\n this.currentH = this.snapToPixels(this.currentSnap);\n this.render(this.currentH);\n }\n }\n\n setOptions(opts: MutableSheetOptions) {\n if (this.destroyed) return;\n if (opts.snapPoints !== undefined) this.options.snapPoints = Sheet.sanitizeSnapPoints(opts.snapPoints);\n if (opts.damping !== undefined) this.options.damping = opts.damping;\n if (opts.stiffness !== undefined) this.options.stiffness = opts.stiffness;\n if (opts.mass !== undefined) this.options.mass = opts.mass;\n if (opts.closeThreshold !== undefined) this.options.closeThreshold = opts.closeThreshold;\n if (opts.topPadding !== undefined) this.options.topPadding = opts.topPadding;\n if (opts.closeOnEscape !== undefined) this.options.closeOnEscape = opts.closeOnEscape;\n if (opts.closeOnOverlayClick !== undefined) this.options.closeOnOverlayClick = opts.closeOnOverlayClick;\n if (opts.ariaLabel !== undefined) this.options.ariaLabel = opts.ariaLabel;\n if (opts.ariaLabelledBy !== undefined) this.options.ariaLabelledBy = opts.ariaLabelledBy;\n if (opts.modal !== undefined) this.options.modal = opts.modal;\n if (opts.maxWidth !== undefined) this.options.maxWidth = opts.maxWidth;\n if (opts.reducedMotion !== undefined) this.options.reducedMotion = opts.reducedMotion;\n if (opts.onOpen !== undefined) this.options.onOpen = opts.onOpen;\n if (opts.onClose !== undefined) this.options.onClose = opts.onClose;\n if (opts.onSnap !== undefined) this.options.onSnap = opts.onSnap;\n\n if (opts.ariaLabel !== undefined || opts.ariaLabelledBy !== undefined || opts.modal !== undefined) {\n applyAriaAttributes(this.wrapperEl, this.overlayEl, {\n ariaLabel: this.options.ariaLabel,\n ariaLabelledBy: this.options.ariaLabelledBy,\n modal: this.options.modal,\n });\n }\n if (opts.width !== undefined || opts.align !== undefined || opts.sidePadding !== undefined || opts.maxWidth !== undefined) {\n if (opts.width !== undefined) this.options.width = opts.width;\n if (opts.align !== undefined) this.options.align = opts.align;\n if (opts.sidePadding !== undefined) this.options.sidePadding = opts.sidePadding;\n this.applyLayout();\n }\n\n // Recompute position when size-affecting options changed\n const sizeChanged = opts.topPadding !== undefined || opts.snapPoints !== undefined;\n if (sizeChanged && this.state !== \"closed\" && this.currentSnap > 0) {\n if (opts.snapPoints !== undefined && !this.options.snapPoints.includes(this.currentSnap)) {\n const nearest = this.pixelsToSnap(this.currentH);\n this.animateToH(this.snapToPixels(nearest));\n } else {\n this.currentH = this.snapToPixels(this.currentSnap);\n this.render(this.currentH);\n }\n }\n }\n\n setLayout(opts: { width?: number; align?: SheetAlign; sidePadding?: number }) {\n if (this.destroyed) return;\n if (opts.width !== undefined) this.options.width = opts.width;\n if (opts.align !== undefined) this.options.align = opts.align;\n if (opts.sidePadding !== undefined) this.options.sidePadding = opts.sidePadding;\n this.applyLayout();\n }\n\n get isOpen(): boolean {\n return this.state !== \"closed\";\n }\n\n get currentSnapPoint(): number {\n return this.currentSnap;\n }\n}\n"],"mappings":"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","names":["DEFAULT_SPRING","springStep","current","target","velocity","dt","config","stiffness","damping","mass","displacement","springForce","dampingForce","acceleration","newVelocity","isAtRest","threshold","animateSpring","from","to","initialVelocity","onUpdate","onComplete","cfg","position","lastTime","frameId","tick","time","state","VelocityTracker","maxSamples","value","recent","oldest","i","resolveSnapPoint","snapPoints","flickThreshold","hardFlickThreshold","sorted","a","b","sp","closest","closestDist","dist","DIRECTION_LOCK_THRESHOLD","SCROLL_LOCK_THRESHOLD","findScrollableAncestor","target","sheetEl","el","overflowY","attachGestures","handleEl","handleOnly","callbacks","tracker","VelocityTracker","state","onPointerDown","e","isHandle","scrollable","onPointerMove","dx","dy","deltaY","st","atTop","atBottom","draggingDown","onPointerUp","velocity","onPointerCancel","onContextMenu","FOCUSABLE_SELECTORS","createFocusTrap","container","previousFocus","getFocusable","onKeyDown","e","focusable","first","last","activate","deactivate","applyAriaAttributes","sheetEl","overlayEl","opts","removeAriaAttributes","lockScroll","body","html","originalBodyOverflow","originalHtmlOverflow","preventTouch","el","dampen","v","Sheet","_Sheet","container","options","snaps","defaultSnap","lockScroll","createFocusTrap","e","raw","valid","n","deduped","a","b","snap","maxH","s","px","closest","closestDist","i","dist","width","align","sidePadding","maxWidth","el","vw","clampedWidth","pad","sheetW","left","applyAriaAttributes","attachGestures","_y","deltaY","newH","minH","overflow","velocityPx","velocityH","targetH","resolveSnapPoint","nonZeroSnaps","lowestNonZero","initialVelocity","wasOpen","onDone","springConfig","animateSpring","value","h","viewportH","visibleH","translateY","opacity","point","sorted","target","removeAriaAttributes","points","nearest","opts"]}
|
|
1
|
+
{"version":3,"sources":["../src/physics.ts","../src/gestures.ts","../src/accessibility.ts","../src/sheet.ts"],"sourcesContent":["export interface SpringConfig {\n damping: number;\n stiffness: number;\n mass: number;\n restThreshold: number;\n}\n\nexport const DEFAULT_SPRING: SpringConfig = {\n damping: 30,\n stiffness: 200,\n mass: 1,\n restThreshold: 0.5,\n};\n\nexport interface SpringState {\n position: number;\n velocity: number;\n}\n\n/**\n * Solve one step of a damped spring using semi-implicit Euler integration.\n * Returns the new position and velocity after `dt` seconds.\n */\nexport function springStep(\n current: number,\n target: number,\n velocity: number,\n dt: number,\n config: SpringConfig,\n): SpringState {\n const { stiffness, damping, mass } = config;\n const displacement = current - target;\n const springForce = -stiffness * displacement;\n const dampingForce = -damping * velocity;\n const acceleration = (springForce + dampingForce) / mass;\n\n const newVelocity = velocity + acceleration * dt;\n const newPosition = current + newVelocity * dt;\n\n return { position: newPosition, velocity: newVelocity };\n}\n\n/**\n * Returns true when the spring is close enough to rest.\n */\nexport function isAtRest(\n current: number,\n target: number,\n velocity: number,\n threshold: number = DEFAULT_SPRING.restThreshold,\n): boolean {\n return (\n Math.abs(current - target) < threshold && Math.abs(velocity) < threshold\n );\n}\n\n/**\n * Runs a spring animation via requestAnimationFrame. Returns a cancel function.\n */\nexport function animateSpring(\n from: number,\n to: number,\n initialVelocity: number,\n config: Partial<SpringConfig>,\n onUpdate: (value: number) => void,\n onComplete: () => void,\n): () => void {\n const cfg = { ...DEFAULT_SPRING, ...config };\n let position = from;\n let velocity = initialVelocity;\n let lastTime = 0;\n let frameId = 0;\n\n function tick(time: number) {\n if (lastTime === 0) {\n lastTime = time;\n frameId = requestAnimationFrame(tick);\n return;\n }\n\n // Cap dt to avoid spiral of death on tab-switch resume\n const dt = Math.min((time - lastTime) / 1000, 0.064);\n lastTime = time;\n\n const state = springStep(position, to, velocity, dt, cfg);\n position = state.position;\n velocity = state.velocity;\n\n onUpdate(position);\n\n if (isAtRest(position, to, velocity, cfg.restThreshold)) {\n onUpdate(to);\n onComplete();\n return;\n }\n\n frameId = requestAnimationFrame(tick);\n }\n\n frameId = requestAnimationFrame(tick);\n\n return () => cancelAnimationFrame(frameId);\n}\n\n/**\n * Tracks pointer velocity over the last N samples for flick detection.\n */\nexport class VelocityTracker {\n private samples: { time: number; value: number }[] = [];\n private maxSamples: number;\n\n constructor(maxSamples = 8) {\n this.maxSamples = maxSamples;\n }\n\n add(value: number) {\n this.samples.push({ time: performance.now(), value });\n if (this.samples.length > this.maxSamples) {\n this.samples.shift();\n }\n }\n\n /** Returns velocity in units per second. */\n getVelocity(): number {\n if (this.samples.length < 2) return 0;\n\n const recent = this.samples[this.samples.length - 1];\n // Use sample from ~50ms ago for stability\n let oldest = this.samples[0];\n for (let i = this.samples.length - 2; i >= 0; i--) {\n if (recent.time - this.samples[i].time >= 30) {\n oldest = this.samples[i];\n break;\n }\n }\n\n const dt = (recent.time - oldest.time) / 1000;\n if (dt === 0) return 0;\n\n return (recent.value - oldest.value) / dt;\n }\n\n reset() {\n this.samples = [];\n }\n}\n\n/**\n * Given a set of snap points and a release position + velocity,\n * determine which snap point to target.\n */\nexport function resolveSnapPoint(\n position: number,\n velocity: number,\n snapPoints: number[],\n flickThreshold = 400,\n hardFlickThreshold = 1200,\n): number {\n if (snapPoints.length === 0) return position;\n if (snapPoints.length === 1) return snapPoints[0];\n\n const sorted = [...snapPoints].sort((a, b) => a - b);\n\n // Hard flick: skip all intermediate snaps, go to the extreme\n if (Math.abs(velocity) > hardFlickThreshold) {\n return velocity > 0 ? sorted[sorted.length - 1] : sorted[0];\n }\n\n // Normal flick: go to next snap in the flick direction\n if (Math.abs(velocity) > flickThreshold) {\n if (velocity > 0) {\n for (const sp of sorted) {\n if (sp > position + 2) return sp;\n }\n return sorted[sorted.length - 1];\n } else {\n for (let i = sorted.length - 1; i >= 0; i--) {\n if (sorted[i] < position - 2) return sorted[i];\n }\n return sorted[0];\n }\n }\n\n // No flick: snap to nearest\n let closest = sorted[0];\n let closestDist = Math.abs(position - sorted[0]);\n for (let i = 1; i < sorted.length; i++) {\n const dist = Math.abs(position - sorted[i]);\n if (dist < closestDist) {\n closest = sorted[i];\n closestDist = dist;\n }\n }\n return closest;\n}\n","import { VelocityTracker } from \"./physics.js\";\n\nexport interface GestureCallbacks {\n onStart: (y: number) => void;\n onMove: (y: number, deltaY: number) => void;\n onEnd: (velocity: number) => void;\n}\n\ninterface GestureState {\n active: boolean;\n dragging: boolean;\n startY: number;\n currentY: number;\n directionLocked: boolean;\n lockedAxis: \"x\" | \"y\" | null;\n startX: number;\n currentX: number;\n scrolling: boolean;\n scrollTarget: HTMLElement | null;\n}\n\nconst DIRECTION_LOCK_THRESHOLD = 6;\nconst SCROLL_LOCK_THRESHOLD = 3;\n\nfunction findScrollableAncestor(\n target: EventTarget | null,\n sheetEl: HTMLElement,\n): HTMLElement | null {\n let el = target as HTMLElement | null;\n while (el && el !== sheetEl) {\n if (el.scrollHeight > el.clientHeight) {\n const style = getComputedStyle(el);\n const overflowY = style.overflowY;\n if (overflowY === \"auto\" || overflowY === \"scroll\") {\n return el;\n }\n }\n el = el.parentElement;\n }\n return null;\n}\n\nexport function attachGestures(\n sheetEl: HTMLElement,\n handleEl: HTMLElement | null,\n handleOnly: boolean,\n callbacks: GestureCallbacks,\n): () => void {\n const tracker = new VelocityTracker();\n const state: GestureState = {\n active: false,\n dragging: false,\n startY: 0,\n currentY: 0,\n directionLocked: false,\n lockedAxis: null,\n startX: 0,\n currentX: 0,\n scrolling: false,\n scrollTarget: null,\n };\n\n function onPointerDown(e: PointerEvent) {\n const isHandle = handleEl?.contains(e.target as Node);\n if (handleOnly && !isHandle) return;\n const scrollable = isHandle\n ? null\n : findScrollableAncestor(e.target, sheetEl);\n\n state.active = true;\n state.dragging = false;\n state.startY = e.clientY;\n state.currentY = e.clientY;\n state.startX = e.clientX;\n state.currentX = e.clientX;\n state.directionLocked = false;\n state.lockedAxis = null;\n state.scrolling = false;\n state.scrollTarget = scrollable;\n\n tracker.reset();\n tracker.add(e.clientY);\n // No pointer capture yet: capturing here would retarget the click to the\n // sheet, so buttons and links inside it would never get their tap. Until\n // a drag starts, the pointer is followed on the window, since it can leave\n // the sheet (up past a handle near its top edge) before the drag threshold.\n // Once a drag starts it's captured (onPointerMove), so a drag never clicks.\n window.addEventListener(\"pointermove\", onPointerMove);\n window.addEventListener(\"pointerup\", onPointerUp);\n window.addEventListener(\"pointercancel\", onPointerCancel);\n }\n\n function stopFollowing() {\n window.removeEventListener(\"pointermove\", onPointerMove);\n window.removeEventListener(\"pointerup\", onPointerUp);\n window.removeEventListener(\"pointercancel\", onPointerCancel);\n }\n\n function onPointerMove(e: PointerEvent) {\n if (!state.active || state.scrolling) return;\n\n state.currentY = e.clientY;\n state.currentX = e.clientX;\n\n const dx = Math.abs(state.currentX - state.startX);\n const dy = Math.abs(state.currentY - state.startY);\n const deltaY = state.currentY - state.startY;\n\n // Direction locking\n if (!state.directionLocked) {\n if (dx > DIRECTION_LOCK_THRESHOLD || dy > DIRECTION_LOCK_THRESHOLD) {\n state.directionLocked = true;\n state.lockedAxis = dy >= dx ? \"y\" : \"x\";\n }\n if (dy < SCROLL_LOCK_THRESHOLD) return;\n }\n\n if (state.lockedAxis === \"x\") return;\n\n // Scroll vs drag disambiguation (decided once)\n if (state.scrollTarget && !state.dragging) {\n const st = state.scrollTarget;\n const atTop = st.scrollTop <= 0;\n const atBottom = st.scrollTop + st.clientHeight >= st.scrollHeight - 1;\n const draggingDown = deltaY > 0;\n\n if (draggingDown && atTop) {\n // At top, pulling down → drag sheet\n } else if (!draggingDown && atBottom) {\n // At bottom, pulling up → drag sheet\n } else {\n // Let the content scroll\n state.scrolling = true;\n return;\n }\n }\n\n // Begin drag on first qualifying move\n if (!state.dragging) {\n state.dragging = true;\n sheetEl.setPointerCapture(e.pointerId);\n callbacks.onStart(state.startY);\n }\n\n e.preventDefault();\n tracker.add(e.clientY);\n callbacks.onMove(state.currentY, deltaY);\n }\n\n function onPointerUp(e: PointerEvent) {\n if (!state.active) return;\n state.active = false;\n stopFollowing();\n if (sheetEl.hasPointerCapture(e.pointerId)) sheetEl.releasePointerCapture(e.pointerId);\n\n if (!state.dragging) return;\n state.dragging = false;\n\n const velocity = tracker.getVelocity();\n callbacks.onEnd(velocity);\n }\n\n function onPointerCancel(e: PointerEvent) {\n if (!state.active) return;\n state.active = false;\n stopFollowing();\n if (sheetEl.hasPointerCapture(e.pointerId)) sheetEl.releasePointerCapture(e.pointerId);\n\n if (!state.dragging) return;\n state.dragging = false;\n callbacks.onEnd(0);\n }\n\n sheetEl.addEventListener(\"pointerdown\", onPointerDown);\n\n const onContextMenu = (e: Event) => {\n if (state.active) e.preventDefault();\n };\n sheetEl.addEventListener(\"contextmenu\", onContextMenu);\n\n return () => {\n sheetEl.removeEventListener(\"pointerdown\", onPointerDown);\n stopFollowing();\n sheetEl.removeEventListener(\"contextmenu\", onContextMenu);\n };\n}\n","const FOCUSABLE_SELECTORS = [\n \"a[href]\",\n \"button:not([disabled])\",\n \"input:not([disabled])\",\n \"select:not([disabled])\",\n \"textarea:not([disabled])\",\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(\", \");\n\n/**\n * Creates a focus trap within the given element.\n * Returns a cleanup function.\n */\nexport function createFocusTrap(container: HTMLElement): () => void {\n let previousFocus: HTMLElement | null = null;\n\n function getFocusable(): HTMLElement[] {\n return Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTORS));\n }\n\n function onKeyDown(e: KeyboardEvent) {\n if (e.key !== \"Tab\") return;\n\n const focusable = getFocusable();\n if (focusable.length === 0) {\n e.preventDefault();\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (document.activeElement === first || !container.contains(document.activeElement)) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last || !container.contains(document.activeElement)) {\n e.preventDefault();\n first.focus();\n }\n }\n }\n\n function activate() {\n previousFocus = document.activeElement as HTMLElement | null;\n container.addEventListener(\"keydown\", onKeyDown);\n\n // Focus first focusable element or the container itself\n requestAnimationFrame(() => {\n const focusable = getFocusable();\n if (focusable.length > 0) {\n focusable[0].focus();\n } else {\n container.focus();\n }\n });\n }\n\n function deactivate() {\n container.removeEventListener(\"keydown\", onKeyDown);\n previousFocus?.focus();\n previousFocus = null;\n }\n\n activate();\n\n return deactivate;\n}\n\nexport interface AriaOptions {\n ariaLabel?: string;\n ariaLabelledBy?: string;\n modal?: boolean;\n}\n\n/**\n * Applies ARIA attributes for a modal dialog.\n */\nexport function applyAriaAttributes(\n sheetEl: HTMLElement,\n overlayEl: HTMLElement | null,\n opts: AriaOptions = {},\n) {\n sheetEl.setAttribute(\"role\", \"dialog\");\n sheetEl.setAttribute(\"aria-modal\", opts.modal !== false ? \"true\" : \"false\");\n\n if (opts.ariaLabelledBy) {\n sheetEl.setAttribute(\"aria-labelledby\", opts.ariaLabelledBy);\n sheetEl.removeAttribute(\"aria-label\");\n } else {\n sheetEl.setAttribute(\"aria-label\", opts.ariaLabel || \"Sheet\");\n sheetEl.removeAttribute(\"aria-labelledby\");\n }\n\n if (overlayEl) {\n overlayEl.setAttribute(\"aria-hidden\", \"true\");\n }\n}\n\n/**\n * Removes ARIA attributes when the sheet is destroyed.\n */\nexport function removeAriaAttributes(\n sheetEl: HTMLElement,\n overlayEl: HTMLElement | null,\n) {\n sheetEl.removeAttribute(\"role\");\n sheetEl.removeAttribute(\"aria-modal\");\n if (overlayEl) {\n overlayEl.removeAttribute(\"aria-hidden\");\n }\n}\n\n/* one lock for the page, however many sheets hold it. each sheet used to\n save and restore the page's overflow on its own, so when one sheet opened\n while another was still closing (switching from one to the next), the\n second saved the first's \"hidden\" as the page's own and put it back when\n it closed: the page stayed locked with no sheet open. now the first lock\n saves the page as it was, and the last unlock puts it back. */\nlet holders = 0;\nlet saved: { body: string; html: string } | null = null;\n\n// On iOS Safari, overflow:hidden on body/html doesn't fully prevent\n// scroll on its own. We block touchmove on the document as a fallback.\nfunction preventTouch(e: TouchEvent) {\n // Allow scrolling inside the sheet content\n let el = e.target as HTMLElement | null;\n while (el) {\n if (el.classList?.contains(\"drwr-content\")) return;\n el = el.parentElement;\n }\n e.preventDefault();\n}\n\n/**\n * iOS-safe scroll lock. Prevents background scrolling without position:fixed\n * to avoid the iOS Safari viewport jump when the address bar is visible.\n * Counted: the page unlocks when the last sheet holding it lets go.\n */\nexport function lockScroll(): () => void {\n const body = document.body;\n const html = document.documentElement;\n\n if (holders++ === 0) {\n saved = { body: body.style.overflow, html: html.style.overflow };\n html.style.overflow = \"hidden\";\n body.style.overflow = \"hidden\";\n document.addEventListener(\"touchmove\", preventTouch, { passive: false });\n }\n\n let released = false;\n return () => {\n if (released) return;\n released = true;\n if (--holders > 0) return;\n holders = 0;\n body.style.overflow = saved?.body ?? \"\";\n html.style.overflow = saved?.html ?? \"\";\n saved = null;\n document.removeEventListener(\"touchmove\", preventTouch);\n };\n}\n","import {\n animateSpring,\n resolveSnapPoint,\n type SpringConfig,\n} from \"./physics.js\";\nimport { attachGestures } from \"./gestures.js\";\nimport {\n applyAriaAttributes,\n removeAriaAttributes,\n createFocusTrap,\n lockScroll,\n} from \"./accessibility.js\";\n\nexport type SheetAlign = \"center\" | \"left\" | \"right\";\nexport type DragMode = \"handle\" | \"sheet\" | \"none\";\n\nexport interface SheetOptions {\n snapPoints?: number[];\n defaultSnap?: number;\n overlay?: boolean;\n dragHandle?: boolean;\n damping?: number;\n stiffness?: number;\n mass?: number;\n closeThreshold?: number;\n /** Top padding in px for the maximum open height. Default: 40. */\n topPadding?: number;\n /** Width as a percentage of the viewport (0–100). Default: 60 on desktop, 100 on mobile. */\n width?: number;\n /** Horizontal alignment. Default: \"center\". */\n align?: SheetAlign;\n /** Minimum side padding in px. Default: 0. */\n sidePadding?: number;\n /** Max width in px. 0 = no max. Default: 0. */\n maxWidth?: number;\n /** Which part of the sheet initiates drag. Default: \"sheet\". */\n dragMode?: DragMode;\n /** Accessible label for the sheet dialog. Default: \"Sheet\". */\n ariaLabel?: string;\n /** ID of the element labelling the sheet. Overrides ariaLabel when set. */\n ariaLabelledBy?: string;\n /** Close on Escape key. Default: true. */\n closeOnEscape?: boolean;\n /** Close on overlay click. Default: true. */\n closeOnOverlayClick?: boolean;\n /** Trap focus inside the sheet. Default: true. */\n trapFocus?: boolean;\n /** Set aria-modal. Default: true. */\n modal?: boolean;\n /** Honour prefers-reduced-motion by skipping spring animation. Default: true. */\n reducedMotion?: boolean;\n /** Called when open animation completes. */\n onOpen?: () => void;\n /** Called when close animation completes. */\n onClose?: () => void;\n onSnap?: (point: number) => void;\n}\n\n/** Subset of SheetOptions that can be changed at runtime via setOptions(). */\nexport type MutableSheetOptions = Pick<\n SheetOptions,\n | \"snapPoints\"\n | \"damping\"\n | \"stiffness\"\n | \"mass\"\n | \"closeThreshold\"\n | \"topPadding\"\n | \"width\"\n | \"align\"\n | \"sidePadding\"\n | \"maxWidth\"\n | \"ariaLabel\"\n | \"ariaLabelledBy\"\n | \"closeOnEscape\"\n | \"closeOnOverlayClick\"\n | \"modal\"\n | \"reducedMotion\"\n | \"onOpen\"\n | \"onClose\"\n | \"onSnap\"\n>;\n\ntype SheetState = \"closed\" | \"open\" | \"dragging\" | \"animating\";\n\n/** Logarithmic resistance like vaul: soft, organic feel past bounds. */\nfunction dampen(v: number): number {\n return 8 * (Math.log(v + 1) - 2);\n}\n\nexport class Sheet {\n private container: HTMLElement;\n private options: Required<SheetOptions>;\n\n private wrapperEl!: HTMLElement;\n private overlayEl: HTMLElement | null = null;\n private handleEl: HTMLElement | null = null;\n private contentEl!: HTMLElement;\n\n private state: SheetState = \"closed\";\n private currentSnap = 0;\n // Current height of the sheet in pixels (0 = closed, positive = visible)\n private currentH = 0;\n private dragStartH = 0;\n\n private cancelAnimation: (() => void) | null = null;\n private cleanupGestures: (() => void) | null = null;\n private cleanupFocusTrap: (() => void) | null = null;\n private unlockScroll: (() => void) | null = null;\n private onPageShow: ((e: PageTransitionEvent) => void) | null = null;\n private onResize: (() => void) | null = null;\n private naturalContentH = 0;\n private destroyed = false;\n\n private static sanitizeSnapPoints(raw: number[]): number[] {\n const valid = raw.filter((n) => Number.isFinite(n) && n >= 0 && n <= 1);\n const deduped = [...new Set(valid)].sort((a, b) => a - b);\n if (deduped.length === 0) return [0, 1];\n if (!deduped.includes(0)) deduped.unshift(0);\n return deduped;\n }\n\n private prefersReducedMotion(): boolean {\n return (\n this.options.reducedMotion &&\n typeof window !== \"undefined\" &&\n window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches\n );\n }\n\n constructor(container: HTMLElement, options: SheetOptions = {}) {\n this.container = container;\n const snaps = Sheet.sanitizeSnapPoints(options.snapPoints ?? [0, 1]);\n this.options = {\n snapPoints: snaps,\n defaultSnap: options.defaultSnap ?? 0,\n overlay: options.overlay ?? true,\n dragHandle: options.dragHandle ?? true,\n damping: options.damping ?? 30,\n stiffness: options.stiffness ?? 200,\n mass: options.mass ?? 1,\n closeThreshold: options.closeThreshold ?? 0.2,\n topPadding: options.topPadding ?? 40,\n width: options.width ?? (window.innerWidth >= 768 ? 60 : 100),\n align: options.align ?? \"center\",\n sidePadding: options.sidePadding ?? 0,\n maxWidth: options.maxWidth ?? 0,\n dragMode: options.dragMode ?? \"sheet\",\n ariaLabel: options.ariaLabel ?? \"Sheet\",\n ariaLabelledBy: options.ariaLabelledBy ?? \"\",\n closeOnEscape: options.closeOnEscape ?? true,\n closeOnOverlayClick: options.closeOnOverlayClick ?? true,\n trapFocus: options.trapFocus ?? true,\n modal: options.modal ?? true,\n reducedMotion: options.reducedMotion ?? true,\n onOpen: options.onOpen ?? (() => {}),\n onClose: options.onClose ?? (() => {}),\n onSnap: options.onSnap ?? (() => {}),\n };\n\n this.buildDOM();\n this.container.removeAttribute(\"hidden\");\n this.naturalContentH = this.getContentHeight();\n this.bindGestures();\n\n const defaultSnap = this.options.defaultSnap;\n if (defaultSnap > 0 && this.options.snapPoints.includes(defaultSnap)) {\n this.currentH = this.snapToPixels(defaultSnap);\n this.render(this.currentH);\n this.state = \"open\";\n this.currentSnap = defaultSnap;\n document.addEventListener(\"keydown\", this.onKeyDown);\n if (!this.unlockScroll) this.unlockScroll = lockScroll();\n if (this.options.trapFocus && !this.cleanupFocusTrap) {\n this.cleanupFocusTrap = createFocusTrap(this.wrapperEl);\n }\n queueMicrotask(() => {\n if (this.destroyed) return;\n this.options.onOpen();\n });\n } else {\n this.currentH = 0;\n this.render(0);\n }\n this.onPageShow = (e: PageTransitionEvent) => {\n if (e.persisted && this.state !== \"closed\") {\n this.resetToClosedState();\n }\n };\n window.addEventListener(\"pageshow\", this.onPageShow);\n\n this.onResize = () => {\n this.applyLayout();\n this.naturalContentH = this.getContentHeight();\n if (this.state !== \"closed\" && this.currentSnap > 0) {\n this.currentH = this.snapToPixels(this.currentSnap);\n this.render(this.currentH);\n }\n };\n window.addEventListener(\"resize\", this.onResize);\n }\n\n // --- Snap point conversion ---\n\n private getContentHeight(): number {\n return this.contentEl.scrollHeight + (this.handleEl?.offsetHeight ?? 0);\n }\n\n private maxSheetH(): number {\n return window.innerHeight - this.options.topPadding;\n }\n\n /** Convert a normalized snap point (0–1) to available viewport height. */\n private snapToPixels(snap: number): number {\n if (snap <= 0) return 0;\n const maxH = this.maxSheetH();\n return Math.min(snap, 1) * maxH;\n }\n\n /** Get all snap points as pixel heights, sorted ascending. */\n private snapPixels(): number[] {\n return this.options.snapPoints\n .map((s) => this.snapToPixels(s))\n .sort((a, b) => a - b);\n }\n\n /** Find the normalized snap point closest to a pixel height. */\n private pixelsToSnap(px: number): number {\n const snaps = this.options.snapPoints;\n let closest = snaps[0];\n let closestDist = Math.abs(px - this.snapToPixels(snaps[0]));\n for (let i = 1; i < snaps.length; i++) {\n const dist = Math.abs(px - this.snapToPixels(snaps[i]));\n if (dist < closestDist) {\n closest = snaps[i];\n closestDist = dist;\n }\n }\n return closest;\n }\n\n // --- DOM ---\n\n private applyLayout() {\n const { width, align, sidePadding, maxWidth } = this.options;\n const el = this.wrapperEl;\n\n const vw = window.innerWidth;\n const clampedWidth = Math.max(10, Math.min(100, width));\n const pad = Math.max(0, Math.min(sidePadding, vw / 2 - 10));\n\n let sheetW = Math.max(20, Math.min(vw * (clampedWidth / 100), vw - pad * 2));\n if (maxWidth > 0) sheetW = Math.min(sheetW, maxWidth);\n\n let left: number;\n if (align === \"left\") {\n left = pad;\n } else if (align === \"right\") {\n left = vw - sheetW - pad;\n } else {\n left = (vw - sheetW) / 2;\n }\n\n el.style.left = `${left}px`;\n el.style.right = \"auto\";\n el.style.width = `${sheetW}px`;\n el.style.margin = \"0\";\n }\n\n private buildDOM() {\n this.wrapperEl = document.createElement(\"div\");\n this.wrapperEl.className = \"drwr-sheet\";\n this.wrapperEl.setAttribute(\"tabindex\", \"-1\");\n\n if (this.options.dragHandle) {\n this.handleEl = document.createElement(\"div\");\n this.handleEl.className = \"drwr-handle\";\n this.wrapperEl.appendChild(this.handleEl);\n }\n\n this.contentEl = document.createElement(\"div\");\n this.contentEl.className = \"drwr-content\";\n\n while (this.container.firstChild) {\n this.contentEl.appendChild(this.container.firstChild);\n }\n this.wrapperEl.appendChild(this.contentEl);\n this.container.appendChild(this.wrapperEl);\n\n if (this.options.overlay) {\n this.overlayEl = document.createElement(\"div\");\n this.overlayEl.className = \"drwr-overlay\";\n this.overlayEl.addEventListener(\"click\", () => {\n if (this.options.closeOnOverlayClick) this.close();\n });\n this.container.insertBefore(this.overlayEl, this.wrapperEl);\n }\n\n applyAriaAttributes(this.wrapperEl, this.overlayEl, {\n ariaLabel: this.options.ariaLabel,\n ariaLabelledBy: this.options.ariaLabelledBy,\n modal: this.options.modal,\n });\n this.applyLayout();\n }\n\n // --- Gestures ---\n\n private bindGestures() {\n if (this.options.dragMode === \"none\") return;\n this.cleanupGestures = attachGestures(\n this.wrapperEl,\n this.handleEl,\n this.options.dragMode === \"handle\",\n {\n onStart: () => {\n this.cancelCurrentAnimation();\n this.state = \"dragging\";\n this.dragStartH = this.currentH;\n this.wrapperEl.setAttribute(\"data-dragging\", \"true\");\n },\n onMove: (_y, deltaY) => {\n // deltaY positive = finger moved down = sheet should shrink\n let newH = this.dragStartH - deltaY;\n\n const snaps = this.snapPixels();\n const maxH = snaps[snaps.length - 1];\n const minH = snaps[0];\n\n if (newH > maxH) {\n newH = maxH;\n } else if (newH < minH) {\n const overflow = minH - newH;\n newH = minH - Math.max(0, dampen(overflow));\n }\n\n this.currentH = newH;\n this.render(newH);\n },\n onEnd: (velocityPx) => {\n this.wrapperEl.setAttribute(\"data-dragging\", \"false\");\n const velocityH = -velocityPx;\n this.state = \"animating\";\n\n const snaps = this.snapPixels();\n let targetH = resolveSnapPoint(this.currentH, velocityH, snaps, 400);\n\n // closeThreshold: if the sheet is dragged below (lowestNonZeroSnap * threshold), close it\n const nonZeroSnaps = snaps.filter((s) => s > 0);\n if (nonZeroSnaps.length > 0) {\n const lowestNonZero = nonZeroSnaps[0];\n if (this.currentH < lowestNonZero * this.options.closeThreshold) {\n targetH = 0;\n }\n }\n\n this.animateToH(targetH, velocityH);\n },\n },\n );\n }\n\n // --- Animation ---\n\n private cancelCurrentAnimation() {\n if (this.cancelAnimation) {\n this.cancelAnimation();\n this.cancelAnimation = null;\n }\n }\n\n private animateToH(targetH: number, initialVelocity = 0) {\n const wasOpen = this.state === \"open\" || this.state === \"dragging\";\n this.cancelCurrentAnimation();\n this.state = \"animating\";\n const onDone = () => {\n this.currentH = targetH;\n this.render(targetH);\n this.cancelAnimation = null;\n\n const snap = this.pixelsToSnap(targetH);\n this.currentSnap = snap;\n\n if (targetH <= 0.5) {\n this.onClosed();\n } else {\n this.state = \"open\";\n if (!wasOpen) this.options.onOpen();\n this.options.onSnap(snap);\n }\n };\n\n if (this.prefersReducedMotion()) {\n onDone();\n return;\n }\n\n const springConfig: Partial<SpringConfig> = {\n damping: this.options.damping,\n stiffness: this.options.stiffness,\n mass: this.options.mass,\n };\n\n this.cancelAnimation = animateSpring(\n this.currentH,\n targetH,\n initialVelocity,\n springConfig,\n (value) => {\n this.currentH = value;\n this.render(value);\n },\n onDone,\n );\n }\n\n // --- Rendering ---\n\n private render(h: number) {\n const viewportH = window.innerHeight;\n const visibleH = Math.max(0, h);\n const translateY = viewportH - visibleH;\n\n this.wrapperEl.style.visibility = visibleH > 0.5 ? \"visible\" : \"hidden\";\n\n this.wrapperEl.style.transform = `translate3d(0, ${translateY}px, 0)`;\n this.wrapperEl.style.height = visibleH > 0.5 ? `${visibleH}px` : \"\";\n\n if (this.overlayEl) {\n const snaps = this.snapPixels();\n const maxH = snaps[snaps.length - 1];\n const opacity = Math.max(0, Math.min(1, visibleH / (maxH * 0.3)));\n this.overlayEl.style.opacity = String(opacity);\n this.overlayEl.setAttribute(\"data-visible\", visibleH > 1 ? \"true\" : \"false\");\n }\n }\n\n // --- State changes ---\n\n /** Shared cleanup: visually close and tear down locks/traps. Does NOT fire callbacks. */\n private resetToClosedState() {\n this.cancelCurrentAnimation();\n this.currentH = 0;\n this.currentSnap = 0;\n this.render(0);\n this.state = \"closed\";\n\n if (this.overlayEl) {\n this.overlayEl.style.opacity = \"0\";\n this.overlayEl.setAttribute(\"data-visible\", \"false\");\n }\n if (this.unlockScroll) {\n this.unlockScroll();\n this.unlockScroll = null;\n }\n if (this.cleanupFocusTrap) {\n this.cleanupFocusTrap();\n this.cleanupFocusTrap = null;\n }\n document.removeEventListener(\"keydown\", this.onKeyDown);\n }\n\n private onClosed() {\n this.resetToClosedState();\n this.options.onClose();\n }\n\n // --- Keyboard ---\n\n private onKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\" && this.state !== \"closed\" && this.options.closeOnEscape) {\n this.close();\n }\n };\n\n // --- Public API ---\n\n open(point?: number) {\n if (this.destroyed || this.state === \"open\") return;\n\n const sorted = [...this.options.snapPoints].sort((a, b) => a - b);\n let target: number;\n if (point !== undefined) {\n if (!sorted.includes(point) || point === 0) {\n console.warn(`[drwr] snap point ${point} not valid for open()`);\n return;\n }\n target = point;\n } else {\n target = sorted[sorted.length - 1];\n }\n\n document.addEventListener(\"keydown\", this.onKeyDown);\n this.animateToH(this.snapToPixels(target));\n if (!this.unlockScroll) this.unlockScroll = lockScroll();\n if (this.options.trapFocus && !this.cleanupFocusTrap) {\n this.cleanupFocusTrap = createFocusTrap(this.wrapperEl);\n }\n }\n\n close() {\n if (this.destroyed || this.state === \"closed\") return;\n document.removeEventListener(\"keydown\", this.onKeyDown);\n this.animateToH(0);\n }\n\n snapTo(point: number) {\n if (this.destroyed) return;\n if (!this.options.snapPoints.includes(point)) {\n console.warn(`[drwr] snap point ${point} not in snapPoints`);\n return;\n }\n if (point === 0) {\n this.close();\n } else {\n if (this.state === \"closed\") {\n document.addEventListener(\"keydown\", this.onKeyDown);\n if (!this.unlockScroll) this.unlockScroll = lockScroll();\n if (this.options.trapFocus && !this.cleanupFocusTrap) {\n this.cleanupFocusTrap = createFocusTrap(this.wrapperEl);\n }\n }\n this.animateToH(this.snapToPixels(point));\n }\n }\n\n destroy() {\n if (this.destroyed) return;\n this.destroyed = true;\n\n this.cancelCurrentAnimation();\n document.removeEventListener(\"keydown\", this.onKeyDown);\n\n if (this.cleanupGestures) {\n this.cleanupGestures();\n this.cleanupGestures = null;\n }\n if (this.cleanupFocusTrap) {\n this.cleanupFocusTrap();\n this.cleanupFocusTrap = null;\n }\n if (this.unlockScroll) {\n this.unlockScroll();\n this.unlockScroll = null;\n }\n if (this.onPageShow) {\n window.removeEventListener(\"pageshow\", this.onPageShow);\n this.onPageShow = null;\n }\n if (this.onResize) {\n window.removeEventListener(\"resize\", this.onResize);\n this.onResize = null;\n }\n\n removeAriaAttributes(this.wrapperEl, this.overlayEl);\n\n while (this.contentEl.firstChild) {\n this.container.appendChild(this.contentEl.firstChild);\n }\n\n this.wrapperEl.remove();\n this.overlayEl?.remove();\n\n }\n\n setSnapPoints(points: number[]) {\n if (this.destroyed) return;\n this.options.snapPoints = Sheet.sanitizeSnapPoints(points);\n\n if (this.state !== \"closed\" && this.currentSnap > 0) {\n if (!this.options.snapPoints.includes(this.currentSnap)) {\n const nearest = this.pixelsToSnap(this.currentH);\n this.animateToH(this.snapToPixels(nearest));\n }\n }\n }\n\n /** Re-measure content height and recompute current position. Call after dynamic content changes. */\n refresh() {\n if (this.destroyed) return;\n this.naturalContentH = this.getContentHeight();\n if (this.state !== \"closed\" && this.currentSnap > 0) {\n this.currentH = this.snapToPixels(this.currentSnap);\n this.render(this.currentH);\n }\n }\n\n setOptions(opts: MutableSheetOptions) {\n if (this.destroyed) return;\n if (opts.snapPoints !== undefined) this.options.snapPoints = Sheet.sanitizeSnapPoints(opts.snapPoints);\n if (opts.damping !== undefined) this.options.damping = opts.damping;\n if (opts.stiffness !== undefined) this.options.stiffness = opts.stiffness;\n if (opts.mass !== undefined) this.options.mass = opts.mass;\n if (opts.closeThreshold !== undefined) this.options.closeThreshold = opts.closeThreshold;\n if (opts.topPadding !== undefined) this.options.topPadding = opts.topPadding;\n if (opts.closeOnEscape !== undefined) this.options.closeOnEscape = opts.closeOnEscape;\n if (opts.closeOnOverlayClick !== undefined) this.options.closeOnOverlayClick = opts.closeOnOverlayClick;\n if (opts.ariaLabel !== undefined) this.options.ariaLabel = opts.ariaLabel;\n if (opts.ariaLabelledBy !== undefined) this.options.ariaLabelledBy = opts.ariaLabelledBy;\n if (opts.modal !== undefined) this.options.modal = opts.modal;\n if (opts.maxWidth !== undefined) this.options.maxWidth = opts.maxWidth;\n if (opts.reducedMotion !== undefined) this.options.reducedMotion = opts.reducedMotion;\n if (opts.onOpen !== undefined) this.options.onOpen = opts.onOpen;\n if (opts.onClose !== undefined) this.options.onClose = opts.onClose;\n if (opts.onSnap !== undefined) this.options.onSnap = opts.onSnap;\n\n if (opts.ariaLabel !== undefined || opts.ariaLabelledBy !== undefined || opts.modal !== undefined) {\n applyAriaAttributes(this.wrapperEl, this.overlayEl, {\n ariaLabel: this.options.ariaLabel,\n ariaLabelledBy: this.options.ariaLabelledBy,\n modal: this.options.modal,\n });\n }\n if (opts.width !== undefined || opts.align !== undefined || opts.sidePadding !== undefined || opts.maxWidth !== undefined) {\n if (opts.width !== undefined) this.options.width = opts.width;\n if (opts.align !== undefined) this.options.align = opts.align;\n if (opts.sidePadding !== undefined) this.options.sidePadding = opts.sidePadding;\n this.applyLayout();\n }\n\n // Recompute position when size-affecting options changed\n const sizeChanged = opts.topPadding !== undefined || opts.snapPoints !== undefined;\n if (sizeChanged && this.state !== \"closed\" && this.currentSnap > 0) {\n if (opts.snapPoints !== undefined && !this.options.snapPoints.includes(this.currentSnap)) {\n const nearest = this.pixelsToSnap(this.currentH);\n this.animateToH(this.snapToPixels(nearest));\n } else {\n this.currentH = this.snapToPixels(this.currentSnap);\n this.render(this.currentH);\n }\n }\n }\n\n setLayout(opts: { width?: number; align?: SheetAlign; sidePadding?: number }) {\n if (this.destroyed) return;\n if (opts.width !== undefined) this.options.width = opts.width;\n if (opts.align !== undefined) this.options.align = opts.align;\n if (opts.sidePadding !== undefined) this.options.sidePadding = opts.sidePadding;\n this.applyLayout();\n }\n\n get isOpen(): boolean {\n return this.state !== \"closed\";\n }\n\n get currentSnapPoint(): number {\n return this.currentSnap;\n }\n}\n"],"mappings":"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","names":["DEFAULT_SPRING","springStep","current","target","velocity","dt","config","stiffness","damping","mass","displacement","springForce","dampingForce","acceleration","newVelocity","isAtRest","threshold","animateSpring","from","to","initialVelocity","onUpdate","onComplete","cfg","position","lastTime","frameId","tick","time","state","VelocityTracker","maxSamples","value","recent","oldest","i","resolveSnapPoint","snapPoints","flickThreshold","hardFlickThreshold","sorted","a","b","sp","closest","closestDist","dist","DIRECTION_LOCK_THRESHOLD","SCROLL_LOCK_THRESHOLD","findScrollableAncestor","target","sheetEl","el","overflowY","attachGestures","handleEl","handleOnly","callbacks","tracker","VelocityTracker","state","onPointerDown","e","isHandle","scrollable","onPointerMove","onPointerUp","onPointerCancel","stopFollowing","dx","dy","deltaY","st","atTop","atBottom","draggingDown","velocity","onContextMenu","FOCUSABLE_SELECTORS","createFocusTrap","container","previousFocus","getFocusable","onKeyDown","e","focusable","first","last","activate","deactivate","applyAriaAttributes","sheetEl","overlayEl","opts","removeAriaAttributes","holders","saved","preventTouch","el","lockScroll","body","html","released","dampen","v","Sheet","_Sheet","container","options","snaps","defaultSnap","lockScroll","createFocusTrap","e","raw","valid","n","deduped","a","b","snap","maxH","s","px","closest","closestDist","i","dist","width","align","sidePadding","maxWidth","el","vw","clampedWidth","pad","sheetW","left","applyAriaAttributes","attachGestures","_y","deltaY","newH","minH","overflow","velocityPx","velocityH","targetH","resolveSnapPoint","nonZeroSnaps","lowestNonZero","initialVelocity","wasOpen","onDone","springConfig","animateSpring","value","h","viewportH","visibleH","translateY","opacity","point","sorted","target","removeAriaAttributes","points","nearest","opts"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alexapvl/drwr",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "A zero-dependency, framework-agnostic bottom sheet / drawer component",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -25,6 +25,12 @@
|
|
|
25
25
|
"sideEffects": [
|
|
26
26
|
"**/*.css"
|
|
27
27
|
],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsup",
|
|
30
|
+
"build:demo": "vite build demo --outDir dist",
|
|
31
|
+
"dev": "vite demo",
|
|
32
|
+
"typecheck": "tsc --noEmit"
|
|
33
|
+
},
|
|
28
34
|
"keywords": [
|
|
29
35
|
"drawer",
|
|
30
36
|
"sheet",
|
|
@@ -38,14 +44,10 @@
|
|
|
38
44
|
],
|
|
39
45
|
"author": "",
|
|
40
46
|
"license": "MIT",
|
|
47
|
+
"packageManager": "pnpm@10.25.0",
|
|
41
48
|
"devDependencies": {
|
|
42
49
|
"tsup": "^8.0.0",
|
|
43
50
|
"typescript": "^5.4.0",
|
|
44
51
|
"vite": "^6.0.0"
|
|
45
|
-
},
|
|
46
|
-
"scripts": {
|
|
47
|
-
"build": "tsup",
|
|
48
|
-
"dev": "vite demo",
|
|
49
|
-
"typecheck": "tsc --noEmit"
|
|
50
52
|
}
|
|
51
|
-
}
|
|
53
|
+
}
|