Skip to content

Commit 45b2ca7

Browse files
feat(addon/components/paper-switch): converts to a glimmer component.
1 parent 82495fa commit 45b2ca7

File tree

2 files changed

+191
-107
lines changed

2 files changed

+191
-107
lines changed

addon/components/paper-switch.hbs

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,36 @@
1-
{{! template-lint-disable no-curly-component-invocation }}
2-
<div class="md-switch-bar"></div>
3-
<div class="md-container">
4-
<div class="md-bar"></div>
5-
<div class="md-thumb-container" style={{this.thumbContainerStyle}}>
6-
<div class="md-thumb">
7-
<PaperRipple @center={{true}} @fitRipple={{true}}/>
1+
<md-switch
2+
class='paper-switch md-default-theme
3+
{{if @accent " md-accent"}}
4+
{{if @primary " md-primary"}}
5+
{{if @warn " md-warn"}}
6+
{{if this.dragging " md-dragging"}}
7+
{{if this.focused " md-focused"}}
8+
{{if this.value " md-checked"}}
9+
{{@class}}'
10+
disabled={{this.disabled}}
11+
tabindex={{if this.disabled '-1' '0'}}
12+
{{did-insert this.didInsertNode}}
13+
{{did-update this.didUpdateNode this.disabled this._switchContainerHammer}}
14+
{{will-destroy this.willDestroyNode}}
15+
{{on 'keypress' this.handleKeyPress}}
16+
...attributes
17+
>
18+
<div class='md-switch-bar'></div>
19+
<div class='md-container'>
20+
<div class='md-bar'></div>
21+
<div class='md-thumb-container' style={{this.thumbContainerStyle}}>
22+
<div class='md-thumb'>
23+
<PaperRipple @center={{true}} @fitRipple={{true}} />
24+
</div>
825
</div>
926
</div>
10-
</div>
11-
{{#if (has-block)}}
12-
<div class="md-label">
13-
{{yield}}
14-
</div>
15-
{{else}}
16-
<div class="md-label">
17-
{{@label}}
18-
</div>
19-
{{/if}}
27+
{{#if (has-block)}}
28+
<div class='md-label'>
29+
{{yield}}
30+
</div>
31+
{{else}}
32+
<div class='md-label'>
33+
{{@label}}
34+
</div>
35+
{{/if}}
36+
</md-switch>

addon/components/paper-switch.js

Lines changed: 157 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,156 @@
1-
/* eslint-disable ember/no-classic-components, ember/no-component-lifecycle-hooks, ember/no-get, ember/no-mixins, ember/require-tagless-components, no-unused-vars */
1+
/* global Hammer */
22
/**
33
* @module ember-paper
44
*/
5-
import { inject as service } from '@ember/service';
6-
7-
import Component from '@ember/component';
5+
import Focusable from './-focusable';
6+
import { tracked } from '@glimmer/tracking';
87
import { assert } from '@ember/debug';
9-
import { get, computed } from '@ember/object';
10-
import { bind } from '@ember/runloop';
8+
import { action } from '@ember/object';
9+
import { inject as service } from '@ember/service';
1110
import { htmlSafe } from '@ember/template';
12-
import FocusableMixin from 'ember-paper/mixins/focusable-mixin';
13-
import ProxiableMixin from 'ember-paper/mixins/proxiable-mixin';
14-
import { invokeAction } from 'ember-paper/utils/invoke-action';
15-
16-
/* global Hammer */
1711

1812
/**
1913
* @class PaperSwitch
20-
* @extends Ember.Component
21-
* @uses FocusableMixin
22-
* @uses ProxiableMixin
14+
* @extends Component
2315
*/
24-
export default Component.extend(FocusableMixin, ProxiableMixin, {
25-
tagName: 'md-switch',
26-
classNames: ['paper-switch', 'md-default-theme'],
27-
classNameBindings: [
28-
'value:md-checked',
29-
'dragging:md-dragging',
30-
'warn:md-warn',
31-
'accent:md-accent',
32-
'primary:md-primary',
33-
],
34-
toggle: true,
35-
constants: service(),
36-
value: false,
37-
disabled: false,
38-
dragging: false,
39-
40-
thumbContainerStyle: computed('dragging', 'dragAmount', function () {
41-
if (!this.dragging) {
42-
return htmlSafe('');
16+
export default class PaperSwitch extends Focusable {
17+
@service constants;
18+
19+
/**
20+
* Reference to the component's DOM element
21+
* @type {HTMLElement}
22+
*/
23+
element;
24+
/**
25+
* The parent this component is bound to.
26+
* @type {PaperRadioGroup|PaperForm|PaperItem|PaperTabs}
27+
*/
28+
parent;
29+
/**
30+
* Marks whether the component should register itself to the supplied parent
31+
* @type {Boolean}
32+
*/
33+
shouldRegister;
34+
/**
35+
* Marks whether the component should skip being proxied.
36+
* @type {Boolean}
37+
*/
38+
skipProxy;
39+
40+
/* Focusable Overrides */
41+
toggle = true;
42+
43+
/**
44+
* specifies the positive amount the switch has been dragged.
45+
* @type {number|null}
46+
*/
47+
@tracked dragAmount = null;
48+
/**
49+
* specifies whether the switch is currently being dragged.
50+
* @type {boolean}
51+
*/
52+
@tracked dragging = false;
53+
/**
54+
* specifies the width of the switch to calculate drag deltas.
55+
* @type {number}
56+
*/
57+
@tracked switchWidth = 0;
58+
59+
// Lifecycle hooks
60+
constructor(owner, args) {
61+
super(owner, args);
62+
63+
this.shouldRegister = this.args.shouldRegister || false;
64+
this.skipProxy = this.args.skipProxy || false;
65+
this.toggle = this.args.toggle || false;
66+
67+
if (this.shouldRegister) {
68+
assert(
69+
'A parent component should be supplied to <PaperSwitch> when shouldRegister=true',
70+
this.args.parentComponent
71+
);
72+
this.parent = this.args.parentComponent;
4373
}
4474

45-
let translate = Math.max(0, Math.min(100, this.dragAmount * 100));
46-
let transformProp = `translate3d(${translate}%, 0, 0)`;
47-
return htmlSafe(
48-
`transform: ${transformProp};-webkit-transform: ${transformProp}`
75+
assert(
76+
'<PaperSwitch> requires an `onChange` action or null for no action.',
77+
this.args.onChange !== undefined
4978
);
50-
}),
51-
52-
didInsertElement() {
53-
this._super(...arguments);
79+
}
80+
81+
/**
82+
* Performs any required DOM setup.
83+
* @param element
84+
*/
85+
@action didInsertNode(element) {
86+
this.element = element;
87+
this.registerListeners(element);
88+
89+
if (this.shouldRegister) {
90+
this.parent.registerChild(this);
91+
}
5492

5593
// Only setup if the switch is not disabled
5694
if (!this.disabled) {
5795
this._setupSwitch();
5896
}
59-
},
60-
61-
init() {
62-
this._super(...arguments);
63-
assert(
64-
'{{paper-switch}} requires an `onChange` action or null for no action.',
65-
this.onChange !== undefined
66-
);
67-
},
68-
69-
willDestroyElement() {
70-
this._super(...arguments);
71-
this._teardownSwitch();
72-
},
73-
74-
didUpdateAttrs() {
75-
this._super(...arguments);
97+
}
7698

99+
@action didUpdateNode() {
77100
if (!this.disabled && !this._switchContainerHammer) {
78101
this._setupSwitch();
79102
} else if (!this.disabled && this._switchContainerHammer) {
80103
this._switchContainerHammer.set({ enable: true });
81104
} else if (this.disabled && this._switchContainerHammer) {
82105
this._switchContainerHammer.set({ enable: false });
83106
}
84-
},
107+
}
108+
109+
/**
110+
* Performs any required DOM teardown.
111+
* @param element
112+
*/
113+
@action willDestroyNode(element) {
114+
this.unregisterListeners(element);
115+
this._teardownSwitch();
116+
}
85117

86-
_setupSwitch() {
87-
this.set(
88-
'switchWidth',
89-
this.element.querySelector('.md-thumb-container').offsetWidth
118+
willDestroy() {
119+
super.willDestroy(...arguments);
120+
121+
if (this.shouldRegister) {
122+
this.parent.unregisterChild(this);
123+
}
124+
}
125+
126+
/**
127+
* specifies the current switch value.
128+
* @type {boolean}
129+
*/
130+
get value() {
131+
return this.args.value;
132+
}
133+
134+
/**
135+
* Calculates and returns a css animation transform for the switch's thumb.
136+
* @returns {string}
137+
*/
138+
get thumbContainerStyle() {
139+
if (!this.dragging) {
140+
return htmlSafe('');
141+
}
142+
143+
let translate = Math.max(0, Math.min(100, this.dragAmount * 100));
144+
let transformProp = `translate3d(${translate}%, 0, 0)`;
145+
return htmlSafe(
146+
`transform: ${transformProp};-webkit-transform: ${transformProp}`
90147
);
148+
}
149+
150+
_setupSwitch() {
151+
this.switchWidth = this.element.querySelector(
152+
'.md-thumb-container'
153+
).offsetWidth;
91154

92155
let switchContainer = this.element.querySelector('.md-container');
93156
let switchHammer = new Hammer(switchContainer);
@@ -96,20 +159,20 @@ export default Component.extend(FocusableMixin, ProxiableMixin, {
96159
// Enable dragging the switch container
97160
switchHammer.get('pan').set({ threshold: 1 });
98161
switchHammer
99-
.on('panstart', bind(this, this._dragStart))
100-
.on('panmove', bind(this, this._drag))
101-
.on('panend', bind(this, this._dragEnd));
162+
.on('panstart', this._dragStart.bind(this))
163+
.on('panmove', this._drag.bind(this))
164+
.on('panend', this._dragEnd.bind(this));
102165

103166
// Enable tapping gesture on the switch
104167
this._switchHammer = new Hammer(this.element);
105-
this._switchHammer.on('tap', bind(this, this._dragEnd));
168+
this._switchHammer.on('tap', this._dragEnd.bind(this));
106169

107-
this._onClickHandleNativeClick = bind(this, this._handleNativeClick);
170+
this._onClickHandleNativeClick = this._handleNativeClick.bind(this);
108171

109172
this.element
110173
.querySelector('.md-container')
111174
.addEventListener('click', this._onClickHandleNativeClick);
112-
},
175+
}
113176

114177
_handleNativeClick(ev) {
115178
let bubbles = this.bubbles;
@@ -119,7 +182,7 @@ export default Component.extend(FocusableMixin, ProxiableMixin, {
119182
}
120183

121184
return bubbles;
122-
},
185+
}
123186

124187
_teardownSwitch() {
125188
if (this._switchContainerHammer) {
@@ -130,19 +193,19 @@ export default Component.extend(FocusableMixin, ProxiableMixin, {
130193
.querySelector('.md-container')
131194
.removeEventListener('click', this._onClickHandleNativeClick);
132195
this._onClickHandleNativeClick = null;
133-
},
196+
}
134197

135198
_dragStart() {
136-
this.set('dragAmount', +this.value);
137-
this.set('dragging', true);
138-
},
199+
this.dragAmount = +this.value;
200+
this.dragging = true;
201+
}
139202

140203
_drag(event) {
141204
if (!this.disabled) {
142205
// Set the amount the switch has been dragged
143-
this.set('dragAmount', +this.value + event.deltaX / this.switchWidth);
206+
this.dragAmount = +this.value + event.deltaX / this.switchWidth;
144207
}
145-
},
208+
}
146209

147210
_dragEnd() {
148211
if (!this.disabled) {
@@ -154,31 +217,35 @@ export default Component.extend(FocusableMixin, ProxiableMixin, {
154217
(value && dragAmount < 0.5) ||
155218
(!value && dragAmount > 0.5)
156219
) {
157-
invokeAction(this, 'onChange', !value);
220+
if (this.args.onChange) {
221+
this.args.onChange(!value);
222+
}
158223
}
159-
this.set('dragging', false);
160-
this.set('dragAmount', null);
224+
this.dragging = false;
225+
this.dragAmount = null;
161226
}
162-
},
227+
}
163228

164-
focusIn() {
229+
@action handleFocusIn() {
165230
// Focusing in w/o being pressed should use the default behavior
166231
if (!this.pressed) {
167-
this._super(...arguments);
232+
super.handleFocusIn(...arguments);
168233
}
169-
},
234+
}
170235

171-
keyPress(ev) {
236+
@action handleKeyPress(ev) {
172237
if (
173-
ev.which === this.get('constants.KEYCODE.SPACE') ||
174-
ev.which === this.get('constants.KEYCODE.ENTER')
238+
ev.which === this.constants.KEYCODE.SPACE ||
239+
ev.which === this.constants.KEYCODE.ENTER
175240
) {
176241
ev.preventDefault();
177242
this._dragEnd();
178243
}
179-
},
244+
}
180245

181246
processProxy() {
182-
invokeAction(this, 'onChange', !this.value);
183-
},
184-
});
247+
if (this.args.onChange) {
248+
this.args.onChange(!this.value);
249+
}
250+
}
251+
}

0 commit comments

Comments
 (0)