UNPKG

svelte-drawer

Version:

A drawer (a.k.a side menu) component.

141 lines (119 loc) 3.19 kB
<div class=" svelte-drawer side-{{ side }} axis-{{ axis }} " data-open="{{ open }}" data-opening="{{ opening }}" data-closing="{{ closing }}" data-closed="{{ closed }}" style=" transform: translate3d({{ translate.x }}%, {{ translate.y }}%, 0); z-index: {{ zIndexBase + 1 }}; " > <slot></slot> </div> {{#if scrim && !closed && !closing}} <div style="z-index: {{ zIndexBase }};" on:click="close()" > <slot name="scrim"> <Scrim/> </slot> </div> {{/if}} <script> import { spring } from 'svelte-extras' import Scrim from 'svelte-scrim' import clamp from 'just-clamp' const isLeadingSide = side => side === 'left' || side === 'top' const DEFAULTS = { percentOpen: 0, side: 'left', scrim: true, zIndexBase: 1 //push: false // false, element/ref // TODO: push other content over when opening } const FIRES = { open: 'open', opening: 'opening', closing: 'closing', closed: 'closed' } ;[ DEFAULTS, FIRES ].forEach(Object.freeze) export default { setup (Drawer) { Object.assign(Drawer, { DEFAULTS, FIRES }) }, components: { Scrim }, data () { return Object.assign({}, DEFAULTS) }, computed: { open: percentOpen => percentOpen === 100, closed: percentOpen => percentOpen < 1, transitioning: (open, closed) => !open && !closed, opening: (transitioning, percentOpen, previousPercentOpen) => transitioning && (percentOpen > previousPercentOpen), closing: (transitioning, closed, percentOpen, previousPercentOpen) => transitioning && (percentOpen < previousPercentOpen), axis: side => side === 'left' || side === 'right' ? 'x' : 'y', translate: (percentOpen, side, axis) => { const amount = isLeadingSide(side) ? percentOpen - 100 : 100 - percentOpen return axis === 'x' ? { x: amount, y: 0 } : { x: 0, y: amount } } }, oncreate () { this.observe('percentOpen', (percentOpen, previousPercentOpen) => { this.set({ previousPercentOpen }) }) // watch data and fire corresponding events Object.keys(FIRES) .forEach(property => this.observe(property, v => v && this.fire(property))) }, methods: { spring, setPercentOpen (percent, { smooth = true } = {}) { const percentOpen = clamp(0, percent, 100) return smooth ? this.spring('percentOpen', percentOpen, { stiffness: 0.2, damping: 0.9 }) : Promise.resolve(this.set({ percentOpen })) }, open ({ smooth = true } = {}) { return this.setPercentOpen(100, { smooth }) }, close ({ smooth = true } = {}) { return this.setPercentOpen(0, { smooth }) }, toggle ({ smooth = true } = {}) { const shouldClose = this.get('open') || this.get('opening') const method = shouldClose ? 'close' : 'open' return this[method]({ smooth }) } } } </script> <style> .svelte-drawer { position: fixed; display: inline; transform: translate3d(0, 0, 0); } .axis-x { top: 0; bottom: 0; height: 100%; } .axis-y { left: 0; right: 0; width: 100%; } .side-top { top: 0 } .side-right { right: 0 } .side-bottom { bottom: 0 } .side-left { left: 0 } </style>