UNPKG

drawer

Version:

touch-enabled slide-in drawer ui component

187 lines (153 loc) 3.29 kB
/** * Module dependencies. */ var translate = require('translate'); var events = require('events'); var abs = Math.abs; /** * Expose `Drawer`. */ module.exports = Drawer; /** * Initialize a new Drawer. * * @param {Element} el * @api public */ function Drawer(el, opts) { opts = opts || {}; if (!(this instanceof Drawer)) return new Drawer(el, opts); if (!opts.width) throw new Error('width required'); this.events = events(el, this); this.events.bind('webkitTransitionEnd', 'ontransitionend'); this.events.bind('touchstart'); this.events.bind('touchmove'); this.events.bind('touchend'); this.width = opts.width; this.dragThreshold = 30; this.snapThreshold = 60; this.el = el; this.dx = 0; } /** * Handle transitionend. */ Drawer.prototype.ontransitionend = function(){ resetTransition(this.el); }; /** * Handle touchstart. */ Drawer.prototype.ontouchstart = function(e){ e = e.touches[0]; this.down = { x: e.pageX, y: e.pageY }; this.x = this.isOpen ? this.width : 0; }; /** * Handle touchmove. */ Drawer.prototype.ontouchmove = function(e){ var down = this.down; if (!down) return; var touch = e.touches[0]; // delta var dx = this.dx = touch.pageX - down.x; var x = this.x + dx; // not dragging if (!this.dragging && abs(dx) < this.dragThreshold) return; // open / close if (x <= 0 || x >= this.width) return; // translate e.preventDefault(); translate(this.el, x, 0); this.dragging = true; }; /** * Handle touchend. */ Drawer.prototype.ontouchend = function(e){ var dx = this.dx; this.down = this.dx = null; this.dragging = false; // wrong direction if (this.isOpen && dx > 0) return; if (!this.isOpen && dx < 0) return; // below threshold, revert position if (abs(dx) < this.snapThreshold) return this.revert(); // above threshold, toggle state this.toggle(); }; /** * Revert state. * * @api public */ Drawer.prototype.revert = function(){ if (this.isOpen) { this.open(); } else { this.close(); } }; /** * Toggle state. * * @api public */ Drawer.prototype.toggle = function(){ if (this.isOpen) { this.close(); } else { this.open(); } }; /** * Show the drawer. * * @api public */ Drawer.prototype.hide = Drawer.prototype.close = function(ms){ this.isOpen = false; transition(this.el, ms); translate(this.el, 0, 0); }; /** * Hide the drawer. * * @api public */ Drawer.prototype.open = Drawer.prototype.show = function(ms){ this.isOpen = true; transition(this.el, ms); translate(this.el, this.width, 0); }; /** * Set transition. * * @api private */ function transition(el, ms){ ms = null == ms ? 300 : ms; var s = el.style; var ease = 'cubic-bezier(0.230, 1.000, 0.320, 1.000)'; // TODO: custom s.webkitTransition = ms + 'ms -webkit-transform ' + ease; s.MozTransition = ms + 'ms -moz-transform ' + ease; s.msTransition = ms + 'ms -ms-transform ' + ease; s.OTransition = ms + 'ms -o-transform ' + ease; s.transition = ms + 'ms transform ' + ease; } /** * Reset transition property. * * @api private */ function resetTransition(el) { var s = el.style; s.webkitTransition = ''; s.MozTransition = ''; s.msTransition = ''; s.OTransition = ''; s.transition = ''; }