diff --git a/addon/components/paper-slider.js b/addon/components/paper-slider.js
deleted file mode 100644
index 047407292..000000000
--- a/addon/components/paper-slider.js
+++ /dev/null
@@ -1,212 +0,0 @@
-/**
- * @module ember-paper
- */
-import { inject as service } from '@ember/service';
-
-import { not } from '@ember/object/computed';
-import Component from '@ember/component';
-import { computed } from '@ember/object';
-import { run } from '@ember/runloop';
-import { htmlSafe } from '@ember/string';
-import layout from '../templates/components/paper-slider';
-import FocusableMixin from 'ember-paper/mixins/focusable-mixin';
-import ColorMixin from 'ember-paper/mixins/color-mixin';
-import clamp from 'ember-paper/utils/clamp';
-import { invokeAction } from 'ember-invoke-action';
-
-/* global Hammer */
-
-/**
- * @class PaperSlider
- * @extends Ember.Component
- * @uses FocusableMixin
- * @uses ColorMixin
- */
-export default Component.extend(FocusableMixin, ColorMixin, {
- layout,
- tagName: 'md-slider',
-
- attributeBindings: ['min', 'max', 'step', 'discrete:md-discrete', 'tabindex'],
-
- classNames: ['md-default-theme'],
- classNameBindings: ['isMinimum:md-min', 'active:md-active', 'dragging:md-dragging'],
-
- constants: service(),
-
- min: 0,
- max: 100,
- step: 1,
- tabindex: 0,
-
- activeTrackStyle: computed('percent', function() {
- let percent = this.get('percent') || 0;
- return htmlSafe(`width: ${percent * 100}%`);
- }),
-
- thumbContainerStyle: computed('percent', function() {
- let percent = this.get('percent') || 0;
- return htmlSafe(`left: ${percent * 100}%`);
- }),
-
- isMinimum: computed('percent', 'min', function() {
- return this.get('percent') === this.get('min');
- }),
-
- percent: computed('value', 'min', 'max', function() {
- let min = parseFloat(this.get('min'), 10);
- let max = parseFloat(this.get('max'), 10);
-
- return clamp((this.get('value') - min) / (max - min), 0, 1);
- }),
-
- didInsertElement() {
- this._super(...arguments);
- if (!this.get('disabled')) {
- this._setupHammer();
- }
- },
-
- didUpdateAttrs() {
- this._super(...arguments);
-
- if (!this.get('disabled') && !this._hammer) {
- // if it is enabled and we didn't init hammer yet
- this._setupHammer();
- } else if (this.get('disabled') && this._hammer) {
- // if it is disabled and we did init hammer already
- this._teardownHammer();
- }
- },
-
- willDestroyElement() {
- this._super(...arguments);
- if (this._hammer) {
- this._teardownHammer();
- }
- },
-
- _setupHammer() {
- // Enable dragging the slider
- let containerManager = new Hammer.Manager(this.element);
- let pan = new Hammer.Pan({ direction: Hammer.DIRECTION_HORIZONTAL, threshold: 10 });
- containerManager.add(pan);
- let tap = new Hammer.Tap();
- containerManager.add(tap);
-
- containerManager.on('panstart', run.bind(this, this.dragStart))
- .on('panmove', run.bind(this, this.drag))
- .on('panend', run.bind(this, this.dragEnd))
- .on('tap', run.bind(this, this.tap));
-
- this._hammer = containerManager;
- },
-
- _teardownHammer() {
- this._hammer.destroy();
- delete this._hammer;
- },
-
- positionToPercent(x) {
- let { left, width } = this.sliderDimensions();
- return Math.max(0, Math.min(1, (x - left) / width));
- },
-
- percentToValue(x) {
- let min = parseFloat(this.get('min'), 10);
- let max = parseFloat(this.get('max'), 10);
- return (min + x * (max - min));
- },
-
- minMaxValidator(value) {
- let min = parseFloat(this.get('min'), 10);
- let max = parseFloat(this.get('max'), 10);
- return Math.max(min, Math.min(max, value));
- },
-
- stepValidator(value) {
- let step = parseFloat(this.get('step'), 10);
- return Math.round(value / step) * step;
- },
-
- active: false,
- dragging: false,
- enabled: not('disabled'),
-
- sliderDimensions() {
- return this.element.querySelector('.md-track-container').getBoundingClientRect();
- },
-
- setValueFromEvent(value) {
- let exactVal = this.percentToValue(this.positionToPercent(value));
- let closestVal = this.minMaxValidator(this.stepValidator(exactVal));
-
- invokeAction(this, 'onChange', closestVal);
- },
-
- tap(event) {
- if (this.get('disabled')) {
- return;
- }
-
- this.setValueFromEvent(event.center.x);
- },
-
- dragStart(event) {
- if (this.get('disabled')) {
- return;
- }
-
- this.set('active', true);
- this.set('dragging', true);
- this.element.focus();
-
- this.setValueFromEvent(event.center.x);
- },
-
- drag(event) {
- if (this.get('disabled') || !this.get('dragging')) {
- return;
- }
-
- this.setValueFromEvent(event.center.x);
- },
-
- dragEnd() {
- if (this.get('disabled')) {
- return;
- }
-
- this.setProperties({
- active: false,
- dragging: false
- });
- },
-
- keyDown(event) {
- if (this.get('disabled')) {
- return;
- }
-
- let changeAmount, newValue;
-
- if (event.keyCode === this.get('constants.KEYCODE.LEFT_ARROW')) {
- changeAmount = parseFloat(this.get('step')) * -1;
- } else if (event.keyCode === this.get('constants.KEYCODE.RIGHT_ARROW')) {
- changeAmount = parseFloat(this.get('step'));
- }
-
- if (changeAmount) {
- if (event.metaKey || event.ctrlKey || event.altKey) {
- changeAmount *= 4;
- }
-
- newValue = this.get('value') + changeAmount;
-
- invokeAction(this, 'onChange', this.minMaxValidator(newValue));
-
- event.preventDefault();
- event.stopPropagation();
- }
- }
-
-});
diff --git a/addon/components/paper-slider/component.js b/addon/components/paper-slider/component.js
new file mode 100644
index 000000000..05e1dbaac
--- /dev/null
+++ b/addon/components/paper-slider/component.js
@@ -0,0 +1,222 @@
+/**
+ * @module ember-paper
+ */
+import Component from '@ember/component';
+import { computed, action } from '@ember/object';
+import { bind } from '@ember/runloop';
+import { htmlSafe } from '@ember/string';
+import template from './template';
+import clamp from 'ember-paper/utils/clamp';
+import { tagName, layout } from '@ember-decorators/component';
+
+/* global Hammer */
+
+/**
+ * @class PaperSlider
+ * @extends Ember.Component
+ */
+@tagName('')
+@layout(template)
+class PaperSlider extends Component {
+
+ min = 0;
+ max = 100;
+ step = 1;
+ tabindex = 0;
+
+ active = false;
+ dragging = false;
+ focused = false;
+
+ element = null;
+
+ @computed('value', 'min', 'max')
+ get percent() {
+ let min = parseFloat(this.min, 10);
+ let max = parseFloat(this.max, 10);
+
+ return clamp((this.value - min) / (max - min), 0, 1);
+ }
+
+ @computed('percent')
+ get activeTrackStyle() {
+ let percent = this.percent || 0;
+ return htmlSafe(`width: ${percent * 100}%`);
+ }
+
+ @computed('percent')
+ get thumbContainerStyle() {
+ let percent = this.percent || 0;
+ return htmlSafe(`left: ${percent * 100}%`);
+ }
+
+ @computed('percent', 'min')
+ get isMinimum() {
+ return this.percent === this.min;
+ }
+
+ @action
+ onDidInsert(element) {
+ this.element = element;
+ if (!this.disabled) {
+ this._setupHammer();
+ }
+ }
+
+ @action
+ onDidUpdate() {
+ if (!this.disabled && !this._hammer) {
+ // if it is enabled and we didn't init hammer yet
+ this._setupHammer();
+ } else if (this.disabled && this._hammer) {
+ // if it is disabled and we did init hammer already
+ this._teardownHammer();
+ }
+ }
+
+ @action
+ onWillDestroy() {
+ if (this._hammer) {
+ this._teardownHammer();
+ }
+ }
+
+ _setupHammer() {
+ // Enable dragging the slider
+ let containerManager = new Hammer.Manager(this.element);
+ let pan = new Hammer.Pan({ direction: Hammer.DIRECTION_HORIZONTAL, threshold: 10 });
+ containerManager.add(pan);
+ let tap = new Hammer.Tap();
+ containerManager.add(tap);
+
+ containerManager
+ .on('panstart', bind(this, this.onDragStart))
+ .on('panmove', bind(this, this.onDrag))
+ .on('panend', bind(this, this.onDragEnd))
+ .on('tap', bind(this, this.onTap));
+
+ this._hammer = containerManager;
+ }
+
+ _teardownHammer() {
+ this._hammer.destroy();
+ delete this._hammer;
+ }
+
+ positionToPercent(x) {
+ let { left, width } = this.sliderDimensions();
+ return Math.max(0, Math.min(1, (x - left) / width));
+ }
+
+ percentToValue(x) {
+ let min = parseFloat(this.min, 10);
+ let max = parseFloat(this.max, 10);
+ return (min + x * (max - min));
+ }
+
+ minMaxValidator(value) {
+ let min = parseFloat(this.min, 10);
+ let max = parseFloat(this.max, 10);
+ return Math.max(min, Math.min(max, value));
+ }
+
+ stepValidator(value) {
+ let step = parseFloat(this.step, 10);
+ return Math.round(value / step) * step;
+ }
+
+ sliderDimensions() {
+ return this.element.querySelector('.md-track-container').getBoundingClientRect();
+ }
+
+ setValueFromEvent(value) {
+ let exactVal = this.percentToValue(this.positionToPercent(value));
+ let closestVal = this.minMaxValidator(this.stepValidator(exactVal));
+
+ if (this.onChange) {
+ this.onChange(closestVal);
+ }
+ }
+
+ onTap(event) {
+ if (this.disabled) {
+ return;
+ }
+
+ this.setValueFromEvent(event.center.x);
+ }
+
+ onDragStart(event) {
+ if (this.disabled) {
+ return;
+ }
+
+ this.set('active', true);
+ this.set('dragging', true);
+ this.element.focus();
+
+ this.setValueFromEvent(event.center.x);
+ }
+
+ onDrag(event) {
+ if (this.disabled || !this.dragging) {
+ return;
+ }
+
+ this.setValueFromEvent(event.center.x);
+ }
+
+ onDragEnd() {
+ if (this.disabled) {
+ return;
+ }
+
+ this.set('active', false);
+ this.set('dragging', false);
+ }
+
+ @action
+ handleKeyDown(event) {
+ if (this.disabled) {
+ return;
+ }
+
+ let changeAmount, newValue;
+
+ if (['ArrowLeft', 'Left'].includes(event.key)) {
+ changeAmount = parseFloat(this.step) * -1;
+ } else if (['ArrowRight', 'Right'].includes(event.key)) {
+ changeAmount = parseFloat(this.step);
+ }
+
+ if (changeAmount) {
+ if (event.metaKey || event.ctrlKey || event.altKey) {
+ changeAmount *= 4;
+ }
+
+ newValue = this.value + changeAmount;
+
+ if (this.onChange) {
+ this.onChange(this.minMaxValidator(newValue));
+ }
+
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+
+ @action
+ handleFocusIn() {
+ if (!this.disabled) {
+ this.set('focused', true);
+ }
+ }
+
+ @action
+ handleFocusOut() {
+ this.set('focused', false);
+ }
+
+}
+
+export default PaperSlider;
diff --git a/addon/components/paper-slider/template.hbs b/addon/components/paper-slider/template.hbs
new file mode 100644
index 000000000..d2a2ad906
--- /dev/null
+++ b/addon/components/paper-slider/template.hbs
@@ -0,0 +1,37 @@
+