UNPKG

@sandlada/mdc

Version:

@sandlada/mdc is an open source component library that follows the Material Design 3 design specifications.

8 lines 11.7 kB
import{property as e}from"../../../node_modules/@lit/reactive-element/decorators/property.js";import{state as t}from"../../../node_modules/@lit/reactive-element/decorators/state.js";import{query as n}from"../../../node_modules/@lit/reactive-element/decorators/query.js";import"../../../node_modules/lit/decorators.js";import{html as r,nothing as i}from"../../../node_modules/lit-html/lit-html.js";import{LitElement as a}from"../../../node_modules/lit-element/lit-element.js";import"../../../node_modules/lit/index.js";import{classMap as o}from"../../../node_modules/lit-html/directives/class-map.js";import"../../../node_modules/lit/directives/class-map.js";import{composeMixin as s}from"../../../utils/compose-mixin/compose-mixin.js";import c from"../../../_virtual/_@oxc-project_runtime@0.144.0/helpers/esm/decorate.js";import{mixinElevationOptions as l}from"../../elevation/elevation-options.mixin.js";import{mixinDelegatesAria as u}from"../../../utils/aria/delegate.js";import{styleMap as d}from"../../../node_modules/lit-html/directives/style-map.js";import"../../../node_modules/lit/directives/style-map.js";import{bottomSheetStyles as f}from"../bottom-sheet.style.js";import{BOTTOM_SHEET_CANCEL_EVENT as p,BOTTOM_SHEET_CLOSED_EVENT as m,BOTTOM_SHEET_CLOSING_EVENT as h,BOTTOM_SHEET_DRAG_END_EVENT as g,BOTTOM_SHEET_OPENED_EVENT as _,BOTTOM_SHEET_OPENING_EVENT as v}from"../bottom-sheet.interface.js";import{BottomSheetDragController as y}from"./bottom-sheet-drag-controller.js";import{BottomSheetDefaultCloseAnimation as b,BottomSheetDefaultOpenAnimation as x,BottomSheetDetentChangeAnimation as S,BottomSheetDragCommitCloseAnimation as C,BottomSheetDragSnapBackAnimation as w}from"../bottom-sheet.animation.js"; /** * @license * Copyright 2026 Kai-Orion & Sandlada * SPDX-License-Identifier: MIT */ const T=.32;var E=class extends s(u,l)(a){static{this.styles=f}constructor(){super(),this.variant=`modal`,this.open=!1,this.detent=`peek`,this.quick=!1,this.cancelable=!0,this.noFocusTrap=!1,this.returnValue=``,this.draggable=!0,this.hideDragHandle=!1,this.maxHeight=0,this.hasHeader=!1,this.hasContent=!1,this.lastCloseReason=`programmatic`,this.previouslyFocused=null,this.detentTransitionOffset=null,this.dragController=new y(this),this.addEventListener(g,this.handleDragEnd)}dragHandleRef(){return this.dragHandleEl}containerRef(){return this.containerEl}headerRef(){return this.headerEl}scrimRef(){return this.scrimEl}enabled(){return this.open&&this.draggable&&!this.quick}getVariant(){return this.variant}getRestingDetent(){return this.detent}hasHeaderContent(){return this.hasHeader}hasBodyContent(){return this.hasContent}getRenderClasses(){return{standard:this.variant===`standard`,modal:this.variant===`modal`,[`detent-${this.detent}`]:!0,"has-header":this.hasHeader,"has-content":this.hasContent,"no-focus-trap":this.noFocusTrap,quick:this.quick,"drag-handle-hidden":this.hideDragHandle}}render(){let e=this.variant===`modal`;return r`<dialog class="host ${o(this.getRenderClasses())}" part="host" style="${d(this.maxHeight>0?{"--_container-max-height":`${this.maxHeight}px`}:{})}" .returnValue="${this.returnValue}" aria-label="${this.ariaLabel||i}" role="dialog" @cancel="${this.handleNativeCancel}" @click="${this.handleHostClick}" @keydown="${this.handleKeydown}">${e&&!this.noFocusTrap?this.renderFocusTrap(`first`):i} <span class="scrim" aria-hidden="true"></span><div class="container" part="container">${this.renderElevation()}<div class="drag-handle" part="drag-handle" aria-hidden="true" @pointerdown="${this.handleDragHandlePointerDown}"><div class="drag-handle-bar"></div></div><header class="header" part="header"><slot name="header" @slotchange="${this.handleHeaderSlotChange}"></slot></header><div class="content" part="content"><slot @slotchange="${this.handleContentSlotChange}"></slot></div></div>${e&&!this.noFocusTrap?this.renderFocusTrap(`last`):i}</dialog>`}renderFocusTrap(e){return r`<div class="focus-trap focus-trap-${e}" tabindex="0" @focus="${e===`first`?this.handleFirstFocusTrapFocus:this.handleLastFocusTrapFocus}"></div>`}async show(e){if(e&&(this.detent=e),this.open)return;this.open=!0,await this.updateComplete;let t=this.dialogEl;t&&(t.open||(this.variant===`modal`?t.showModal():t.show()),await this.animateBottomSheet(x()),this.dispatchEvent(new Event(_,{bubbles:!0,composed:!0})),requestAnimationFrame(()=>{this.variant===`modal`&&!this.noFocusTrap&&this.focusFirstInside()}))}async hide(){this.open&&(this.dragController.cancel(),this.open=!1,await this.updateComplete,await this.animateBottomSheet(b()),this.closeDialog(),this.dispatchEvent(new CustomEvent(m,{bubbles:!0,composed:!0,detail:{returnValue:this.returnValue,reason:this.lastCloseReason}})),this.noFocusTrap||this.restoreFocus())}async close(e){this.returnValue=e??``,await this.hide()}closeDialog(){let e=this.dialogEl;e?.open&&e.close(this.returnValue)}async dragCommittedClose(e){if(!this.open)return;let t=this.scrimEl?parseFloat(getComputedStyle(this.scrimEl).opacity):0,n=e??(this.containerEl?this.readTranslateY(this.containerEl):0);this.containerEl&&(this.containerEl.style.removeProperty(`transform`),this.containerEl.style.removeProperty(`cursor`)),this.scrimEl&&this.scrimEl.style.removeProperty(`opacity`),this.removeAttribute(`touch-action`),await this.animateBottomSheet(C(n,t)),this.lastCloseReason=`drag`,this.open=!1,await this.updateComplete,this.closeDialog(),this.dispatchEvent(new CustomEvent(m,{bubbles:!0,composed:!0,detail:{returnValue:this.returnValue,reason:`drag`}})),this.noFocusTrap||this.restoreFocus()}async dragSnapToFull(e){if(!this.open)return;let t=e??(this.containerEl?this.readTranslateY(this.containerEl):0);if(this.containerEl&&(this.containerEl.style.removeProperty(`transform`),this.containerEl.style.removeProperty(`cursor`)),this.scrimEl&&this.scrimEl.style.removeProperty(`opacity`),this.removeAttribute(`touch-action`),this.detent===`full`)await this.animateBottomSheet(w(t,T));else{let e=window.innerHeight,n=window.innerWidth>640?Math.min(.96*e,e-56):Math.min(.96*e,e-72),r=this.containerEl?this.containerEl.getBoundingClientRect().height:.4*e,i=Math.max(0,n-r);this.detentTransitionOffset=i+t,this.detent=`full`,await this.updateComplete}}async dragSnapToPeek(e){if(!this.open)return;let t=e??(this.containerEl?this.readTranslateY(this.containerEl):0);if(this.containerEl&&(this.containerEl.style.removeProperty(`transform`),this.containerEl.style.removeProperty(`cursor`)),this.scrimEl&&this.scrimEl.style.removeProperty(`opacity`),this.removeAttribute(`touch-action`),this.detent===`peek`)await this.animateBottomSheet(w(t,T));else{let e=window.innerHeight,n=window.innerWidth>640?Math.min(.96*e,e-56):Math.min(.96*e,e-72),r=0;r=this.headerEl&&this.dragHandleEl?this.dragHandleEl.offsetHeight+this.headerEl.offsetHeight:Math.min(.4*e,n);let i=this.containerEl?this.containerEl.getBoundingClientRect().height:n,a=Math.max(0,i-r);this.detentTransitionOffset=t-a,this.detent=`peek`,await this.updateComplete}}async dragSnapBack(e){let t=this.scrimEl?parseFloat(getComputedStyle(this.scrimEl).opacity):T,n=e??(this.containerEl?this.readTranslateY(this.containerEl):0);this.containerEl&&(this.containerEl.style.removeProperty(`transform`),this.containerEl.style.removeProperty(`cursor`)),this.scrimEl&&this.scrimEl.style.removeProperty(`opacity`),this.removeAttribute(`touch-action`),await this.animateBottomSheet(w(n,t))}readTranslateY(e){let t=getComputedStyle(e).transform;if(!t||t===`none`)return 0;let n=t.match(/matrix\([^)]*\)/);if(!n)return 0;let r=n[0].slice(7,-1).split(`,`).map(e=>parseFloat(e.trim()));return r.length>=6?r[5]:0}willUpdate(e){if(e.has(`open`)&&(this.open?(this.lastCloseReason=`programmatic`,this.previouslyFocused=this.ownerDocument?.activeElement??null,this.dispatchEvent(new Event(v,{bubbles:!0,composed:!0}))):this.dispatchEvent(new Event(h,{bubbles:!0,composed:!0}))),e.has(`detent`)&&this.open){let e=this.detentTransitionOffset===null?this.containerEl?this.readTranslateY(this.containerEl):0:this.detentTransitionOffset;this.detentTransitionOffset=null;let t=this.detent===`full`?`expand`:`collapse`;this.animateBottomSheet(S(t,e))}}disconnectedCallback(){super.disconnectedCallback(),this.cancelAnimations?.abort()}async animateBottomSheet(e){if(this.cancelAnimations?.abort(),this.cancelAnimations=new AbortController,this.quick)return;let t=this.containerEl,n=this.scrimEl,r=this.variant===`modal`;if(!t||r&&!n)return;let{scrim:i,container:a}=e,o=[[t,a??[]]];r&&n&&o.push([n,i??[]]);let s=[];for(let[e,t]of o)for(let n of t){let t=e.animate(...n);this.cancelAnimations.signal.addEventListener(`abort`,()=>{t.cancel()}),s.push(t)}await Promise.all(s.map(e=>e.finished.catch(()=>{})))}focusFirstInside(){this.getFocusableElements()[0]?.focus()}restoreFocus(){if(this.variant!==`modal`)return;let e=this.previouslyFocused;e&&`focus`in e&&e instanceof HTMLElement&&e.focus(),this.previouslyFocused=null}getFocusableElements(){let e=this.containerEl;if(!e)return[];let t=e.querySelectorAll(`a[href], button, textarea, input, select, [tabindex]:not([tabindex="-1"])`);return Array.from(t).filter(e=>!e.hasAttribute(`disabled`)&&e.getAttribute(`aria-hidden`)!==`true`&&!e.classList.contains(`focus-trap`)&&!e.classList.contains(`drag-handle`))}handleHeaderSlotChange(e){let t=e.target;this.hasHeader=t.assignedElements({flatten:!0}).length>0}handleContentSlotChange(e){let t=e.target;this.hasContent=t.assignedElements({flatten:!0}).length>0}handleNativeCancel(e){e.preventDefault(),!(this.variant!==`modal`||!this.cancelable||!this.open)&&(this.lastCloseReason=`escape`,this.dispatchEvent(new CustomEvent(p,{bubbles:!0,composed:!0,detail:{reason:`escape`}})),this.hide())}handleHostClick(e){this.variant!==`modal`||!this.cancelable||!this.open||e.composedPath().some(e=>e.classList?.contains?.(`scrim`))&&(this.lastCloseReason=`scrim`,this.dispatchEvent(new CustomEvent(p,{bubbles:!0,composed:!0,detail:{reason:`scrim`}})),this.hide())}handleKeydown(e){}handleFirstFocusTrapFocus(){let e=this.getFocusableElements();e.length>0&&e[e.length-1].focus()}handleLastFocusTrapFocus(){let e=this.getFocusableElements();e.length>0&&e[0].focus()}handleDragHandlePointerDown(e){this.dragController.handlePointerDown(e)}handleDragEnd(e){let t=e.detail;t.target===`closed`||t.committed&&!t.target?this.dragCommittedClose(t.dy):t.target===`full`?this.dragSnapToFull(t.dy):t.target===`peek`?this.dragSnapToPeek(t.dy):t.reason!==`cancel`&&this.dragSnapBack(t.dy)}};c([e({type:String})],E.prototype,`variant`,void 0),c([e({type:Boolean,reflect:!0})],E.prototype,`open`,void 0),c([e({type:String})],E.prototype,`detent`,void 0),c([e({type:Boolean})],E.prototype,`quick`,void 0),c([e({attribute:`cancelable`,converter:{fromAttribute:e=>e!==null&&e!==`false`,toAttribute:e=>e?``:`false`}})],E.prototype,`cancelable`,void 0),c([e({type:Boolean,attribute:`no-focus-trap`})],E.prototype,`noFocusTrap`,void 0),c([e({type:String,attribute:`return-value`})],E.prototype,`returnValue`,void 0),c([e({attribute:`draggable`,converter:{fromAttribute:e=>e!==null&&e!==`false`,toAttribute:e=>e?``:`false`}})],E.prototype,`draggable`,void 0),c([e({type:Boolean,attribute:`hide-drag-handle`})],E.prototype,`hideDragHandle`,void 0),c([e({type:Number,attribute:`max-height`})],E.prototype,`maxHeight`,void 0),c([t()],E.prototype,`hasHeader`,void 0),c([t()],E.prototype,`hasContent`,void 0),c([n(`dialog`)],E.prototype,`dialogEl`,void 0),c([n(`.container`)],E.prototype,`containerEl`,void 0),c([n(`.header`)],E.prototype,`headerEl`,void 0),c([n(`.drag-handle`)],E.prototype,`dragHandleEl`,void 0),c([n(`.scrim`)],E.prototype,`scrimEl`,void 0);export{E as BaseBottomSheet}; //# sourceMappingURL=base-bottom-sheet.js.map