Skip to content

Instantly share code, notes, and snippets.

@pzuraq
Last active January 25, 2019 19:14
Show Gist options
  • Save pzuraq/e4f30ce30702ce727a7d60de617e684b to your computer and use it in GitHub Desktop.
Save pzuraq/e4f30ce30702ce727a7d60de617e684b to your computer and use it in GitHub Desktop.
/**
* @module ember-paper
*/
/* globals FastBoot */
import { inject as service } from '@ember/service';
import Component from '@ember/component';
import { computed } from '@ember/object';
import { run } from '@ember/runloop';
import TransitionMixin from 'ember-css-transitions/mixins/transition-mixin';
import { invokeAction } from 'ember-invoke-action';
/**
* @class PaperSidenavInner
* @extends Ember.Component
* @uses TransitionMixin
*/
export default Component.extend(TransitionMixin, {
tagName: 'md-sidenav',
attributeBindings: ['tabindex'],
classNameBindings: ['positionClass'],
// eslint-disable-next-line ember/avoid-leaking-state-in-ember-objects
transitionClassNameBindings: ['isLockedOpen:md-locked-open', 'closed:md-closed'],
constants: service(),
paperSidenav: service(),
name: 'default',
position: 'left',
lockedOpen: 'gt-sm',
closed: true,
closeOnClick: true,
tabindex: -1,
positionClass: computed('position', function() {
return `md-sidenav-${this.get('position')}`;
}),
init() {
// need to updateLockedOpen() first because otherwise the transition classes
// would be applied due to transition mixin's `init`
if (typeof FastBoot === 'undefined') {
this.updateLockedOpen();
}
this._super(...arguments);
this.get('paperSidenav').register(this.get('name'), this);
},
didInsertElement() {
this._super(...arguments);
this._updateOnResize = run.bind(this, this.updateLockedOpen);
window.addEventListener('resize', this._updateOnResize);
this.updateLockedOpen();
},
didReceiveAttrs() {
this._super(...arguments);
if (typeof FastBoot === 'undefined') {
this.updateLockedOpen();
}
},
willDestroyElement() {
this._super(...arguments);
window.removeEventListener('resize', this._updateOnResize);
this.get('paperSidenav').unregister(this.get('name'), this);
this._updateOnResize = null;
},
updateLockedOpen() {
let lockedOpen = this.get('lockedOpen');
let isLockedOpen;
// if `true` or `false` is specified, always/never "lock open"
// otherwise proceed with normal matchMedia test
if (typeof lockedOpen === 'boolean') {
isLockedOpen = lockedOpen;
} else {
let mediaQuery = this.get('constants').MEDIA[lockedOpen] || lockedOpen;
isLockedOpen = window.matchMedia(mediaQuery).matches;
}
let coercedIsLockedOpen = !!this.get('isLockedOpen');
if (coercedIsLockedOpen !== isLockedOpen) {
this.set('isLockedOpen', isLockedOpen);
// if sidenav is open and we enter lockedOpen,
// make the sidenav enter the "closed" state
if (!this.get('closed') && isLockedOpen) {
invokeAction(this, 'onToggle', false);
}
}
},
click() {
if (this.get('closeOnClick') && !this.get('isLockedOpen')) {
invokeAction(this, 'onToggle', false);
}
},
open() {
if (this.get('closed') && this.get('isLockedOpen')) {
invokeAction(this, 'onToggle', true);
}
},
close() {
if (!this.get('closed') && !this.get('isLockedOpen')) {
invokeAction(this, 'onToggle', false);
}
},
toggle() {
if (!this.get('isLockedOpen')) {
invokeAction(this, 'onToggle', this.get('closed'));
}
}
});
<md-sidenav
tabindex="-1"
class="
{{this.positionClass}}
{{if this.isLockedOpen 'md-locked-open'}}
{{if this.closed 'md-closed'}}
"
{{did-insert this.didInsertSidenav}}
{{did-update this.updateLockedOpen lockedOpen}}
>
</md-sidenav>
/**
* @module ember-paper
*/
import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
import { computed } from '@ember/object';
import { run } from '@ember/runloop';
import { arg } from 'sparkles-decorators';
/**
* @class PaperSidenavInner
* @extends Ember.Component
* @uses TransitionMixin
*/
export default class PaperSidenavInner extends Component {
@service constants;
@service paperSidenav;
@arg({ default: 'default' }) name;
@arg({ default: 'left' }) position;
@arg({ default: 'gt-sm'}) lockedOpen;
@arg({ default: true }) closed;
@arg({ default: true }) closeOnClick;
@arg({ default: () => {} }) onToggle;
@arg paperSidenav;
@computed('position')
get positionClass() {
return `md-sidenav-${this.position}`;
}
constructor() {
super(...arguments);
// need to updateLockedOpen() first because otherwise the transition classes
// would be applied due to transition mixin's `init`
if (typeof FastBoot === 'undefined') {
this.updateLockedOpen();
}
this.paperSidenav.register(this.name, this);
}
willDestroy() {
super.willDestroy(...arguments);
window.removeEventListener('resize', this._updateOnResize);
this.paperSidenav.unregister(this.name, this);
}
@action
didInsertSidenav(element) {
this._updateOnResize = run.bind(this, this.updateLockedOpen);
window.addEventListener('resize', this._updateOnResize);
this.updateLockedOpen();
}
@action
updateLockedOpen() {
let lockedOpen = this.lockedOpen;
let isLockedOpen;
// if `true` or `false` is specified, always/never "lock open"
// otherwise proceed with normal matchMedia test
if (typeof lockedOpen === 'boolean') {
isLockedOpen = lockedOpen;
} else {
let mediaQuery = this.constants.MEDIA[lockedOpen] || lockedOpen;
isLockedOpen = window.matchMedia(mediaQuery).matches;
}
let coercedIsLockedOpen = !!this.isLockedOpen;
if (coercedIsLockedOpen !== isLockedOpen) {
this.isLockedOpen = isLockedOpen;
// if sidenav is open and we enter lockedOpen,
// make the sidenav enter the "closed" state
if (!this.closed && isLockedOpen) {
this.onToggle(false);
}
}
}
@action
click() {
if (this.closeOnClick && !this.isLockedOpen) {
this.onToggle(false);
}
}
@action
open() {
if (this.closed && this.isLockedOpen) {
this.onToggle(true);
}
}
@action
close() {
if (!this.closed && !this.isLockedOpen) {
this.onToggle(false);
}
}
@action
toggle() {
if (!this.isLockedOpen) {
this.onToggle(this.closed));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment