Skip to content

Commit ce01f39

Browse files
feat(addon/components/paper-checkbox): converts to a glimmer component.
1 parent 1e72457 commit ce01f39

File tree

2 files changed

+177
-84
lines changed

2 files changed

+177
-84
lines changed
Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,39 @@
1-
{{! template-lint-disable no-curly-component-invocation }}
2-
<div class="md-container">
3-
<div class="md-icon"></div>
4-
<PaperRipple
5-
@center={{true}}
6-
@fitRipple={{true}}/>
7-
</div>
8-
{{#if (has-block)}}
9-
<div class="md-label">
10-
<span id={{this.labelId}}>
11-
{{yield}}
12-
</span>
1+
<md-checkbox
2+
class='md-checkbox md-default-theme
3+
{{if this.isChecked " md-checked"}}
4+
{{if this.indeterminate " md-indeterminate"}}
5+
{{if @warn " md-warn"}}
6+
{{if @accent " md-accent"}}
7+
{{if @primary " md-primary"}}
8+
{{if this.focused " md-focused"}}
9+
{{@class}}'
10+
aria-label={{@ariaLabel}}
11+
aria-checked={{this.ariaChecked}}
12+
aria-labelledby={{this.labelId}}
13+
role='checkbox'
14+
disabled={{this.disabled}}
15+
tabindex={{if this.disabled '-1' '0'}}
16+
{{did-insert this.didInsertNode}}
17+
{{will-destroy this.willDestroyNode}}
18+
{{on 'click' this.onClick}}
19+
{{on 'keypress' this.onKeyPress}}
20+
...attributes
21+
>
22+
<div class='md-container'>
23+
<div class='md-icon'></div>
24+
<PaperRipple @center={{true}} @fitRipple={{true}} />
1325
</div>
14-
{{else}}
15-
<div class="md-label">
16-
<span id={{this.labelId}}>
17-
{{@label}}
18-
</span>
19-
</div>
20-
{{/if}}
26+
{{#if (has-block)}}
27+
<div class='md-label'>
28+
<span id={{this.labelId}}>
29+
{{yield}}
30+
</span>
31+
</div>
32+
{{else}}
33+
<div class='md-label'>
34+
<span id={{this.labelId}}>
35+
{{@label}}
36+
</span>
37+
</div>
38+
{{/if}}
39+
</md-checkbox>

addon/components/paper-checkbox.js

Lines changed: 139 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,162 @@
1-
/* eslint-disable ember/no-classic-components, ember/no-get, ember/no-mixins, ember/require-tagless-components */
21
/**
32
* @module ember-paper
43
*/
4+
import Focusable from './-focusable';
55
import { inject as service } from '@ember/service';
6-
7-
import { computed } from '@ember/object';
8-
import { not, and } from '@ember/object/computed';
9-
import Component from '@ember/component';
6+
import { action } from '@ember/object';
7+
import { guidFor } from '@ember/object/internals';
108
import { assert } from '@ember/debug';
11-
import FocusableMixin from 'ember-paper/mixins/focusable-mixin';
12-
import ProxiableMixin from 'ember-paper/mixins/proxiable-mixin';
13-
import { invokeAction } from 'ember-paper/utils/invoke-action';
9+
1410
/**
1511
* @class PaperCheckbox
16-
* @extends Ember.Component
17-
* @uses FocusableMixin
18-
* @uses ProxiableMixin
12+
* @extends Component
1913
*/
20-
export default Component.extend(FocusableMixin, ProxiableMixin, {
21-
tagName: 'md-checkbox',
22-
classNames: ['md-checkbox', 'md-default-theme'],
23-
classNameBindings: [
24-
'isChecked:md-checked',
25-
'indeterminate:md-indeterminate',
26-
'warn:md-warn',
27-
'accent:md-accent',
28-
'primary:md-primary',
29-
],
30-
31-
attributeBindings: [
32-
'role:role',
33-
'ariaLabel:aria-label',
34-
'ariaChecked:aria-checked',
35-
'labelId:aria-labelledby',
36-
],
37-
38-
/* FocusableMixin Overrides */
39-
focusOnlyOnKey: true,
40-
41-
constants: service(),
42-
value: false,
43-
role: 'checkbox',
44-
notIndeterminate: not('indeterminate'),
45-
isChecked: and('notIndeterminate', 'value'),
46-
47-
ariaChecked: computed('isChecked', 'indeterminate', function () {
14+
export default class PaperCheckbox extends Focusable {
15+
/**
16+
* Service containing media query breakpoints and constants
17+
*/
18+
@service constants;
19+
20+
/**
21+
* Reference to the component's DOM element
22+
* @type {HTMLElement}
23+
*/
24+
element;
25+
/**
26+
* The parent this component is bound to.
27+
* @type {Boolean}
28+
*/
29+
parent;
30+
/**
31+
* Marks whether the component should register itself to the supplied parent
32+
* @type {Boolean}
33+
*/
34+
shouldRegister;
35+
/**
36+
* Marks whether the component should skip being proxied.
37+
* @type {Boolean}
38+
*/
39+
skipProxy;
40+
/**
41+
* provides a globally unique component id for tracking bindings between aria
42+
* tags and labels.
43+
* @type {string}
44+
*/
45+
labelId;
46+
47+
/* Focusable Overrides */
48+
focusOnlyOnKey = true;
49+
50+
constructor(owner, args) {
51+
super(owner, args);
52+
53+
this.labelId = `${guidFor(args)}-label`;
54+
this.shouldRegister = this.args.shouldRegister || false;
55+
this.skipProxy = this.args.skipProxy || false;
56+
57+
if (this.shouldRegister) {
58+
assert(
59+
'A parent component should be supplied to <PaperCheckbox> when shouldRegister=true',
60+
this.args.parentComponent
61+
);
62+
this.parent = this.args.parentComponent;
63+
}
64+
65+
assert(
66+
'<PaperCheckbox> requires an `onChange` action or null for no action.',
67+
this.args.onChange !== undefined
68+
);
69+
}
70+
71+
/**
72+
* Performs any required DOM setup.
73+
* @param element
74+
*/
75+
@action didInsertNode(element) {
76+
this.element = element;
77+
this.registerListeners(element);
78+
79+
if (this.shouldRegister) {
80+
this.parent.registerChild(this);
81+
}
82+
}
83+
84+
@action didUpdateNode() {
85+
// noop
86+
}
87+
88+
/**
89+
* Performs any required DOM teardown.
90+
* @param element
91+
*/
92+
@action willDestroyNode(element) {
93+
this.unregisterListeners(element);
94+
}
95+
96+
willDestroy() {
97+
super.willDestroy(...arguments);
98+
99+
if (this.shouldRegister) {
100+
this.parent.unregisterChild(this);
101+
}
102+
}
103+
104+
get indeterminate() {
105+
return this.args.indeterminate || false;
106+
}
107+
108+
get notIndeterminate() {
109+
return !this.indeterminate;
110+
}
111+
112+
get value() {
113+
return this.args.value || false;
114+
}
115+
116+
get isChecked() {
117+
return this.notIndeterminate && this.value;
118+
}
119+
120+
get ariaChecked() {
48121
if (this.indeterminate) {
49122
return 'mixed';
50123
}
51124

52125
return this.isChecked ? 'true' : 'false';
53-
}),
126+
}
54127

55-
labelId: computed('elementId', function () {
56-
return `${this.elementId}-label`;
57-
}),
128+
get bubbles() {
129+
return this.args.bubbles === undefined || this.args.bubbles;
130+
}
58131

59-
init() {
60-
this._super(...arguments);
61-
assert(
62-
'{{paper-checkbox}} requires an `onChange` action or null for no action.',
63-
this.onChange !== undefined
64-
);
65-
},
66-
67-
click() {
132+
@action onClick(e) {
133+
console.log('checkbox:onClick');
68134
if (!this.disabled) {
69-
invokeAction(this, 'onChange', !this.value);
135+
if (this.args.onChange) {
136+
this.args.onChange(!this.value);
137+
}
138+
139+
// Prevent bubbling, if specified. If undefined, the event will bubble.
140+
if (!this.bubbles) {
141+
e.stopPropagation();
142+
}
70143
}
71-
// Prevent bubbling, if specified. If undefined, the event will bubble.
72-
return this.bubbles;
73-
},
144+
}
74145

75-
keyPress(ev) {
146+
@action onKeyPress(e) {
76147
if (
77-
ev.which === this.get('constants.KEYCODE.SPACE') ||
78-
ev.which === this.get('constants.KEYCODE.ENTER')
148+
e.which === this.constants.KEYCODE.SPACE ||
149+
e.which === this.constants.KEYCODE.ENTER
79150
) {
80-
ev.preventDefault();
81-
this.click();
151+
e.preventDefault();
152+
this.onClick();
82153
}
83-
},
154+
}
84155

85156
processProxy() {
86-
invokeAction(this, 'onChange', !this.value);
87-
},
88-
});
157+
console.log('checkbox:processProxy');
158+
if (this.args.onChange) {
159+
this.args.onChange(!this.value);
160+
}
161+
}
162+
}

0 commit comments

Comments
 (0)