-
Notifications
You must be signed in to change notification settings - Fork 81
/
MaterialComponent.js
98 lines (91 loc) · 3.02 KB
/
MaterialComponent.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import {h, Component} from 'preact';
import {MDCRipple} from '@material/ripple';
/**
* Base class for every Material component in this package
* NOTE: every component should add a ref by the name of `control` to its root dom for autoInit Properties
*
* @export
* @class MaterialComponent
* @extends {Component}
*/
export default class MaterialComponent extends Component {
constructor() {
super();
// Attributes inside this array will be check for boolean value true
// and will be converted to mdc classes
this._mdcProps = [];
// This will again be used to add apt classname to the component
this.componentName = '';
// The final class name given to the dom
this.classText = '';
// Shared setter for the root element ref
this.setControlRef = control => {
this.control = control;
};
}
attachRipple() {
if (this.props.ripple && this.control) {
MDCRipple.attachTo(this.control);
}
}
// Build the className based on component names and mdc props
buildClassName() {
// Class name based on component name
this.classText = 'mdc-' + this.componentName;
// Loop over mdcProps to turn them into classNames
for (let propKey in this.props) {
if (this.props.hasOwnProperty(propKey)) {
const prop = this.props[propKey];
if (typeof prop === 'boolean' && prop) {
if (this._mdcProps.indexOf(propKey) !== -1) {
this.classText += ' mdc-' + this.componentName + '--' + propKey;
}
}
}
}
}
getClassName(element) {
if (!element) {
return '';
}
const attrs = (element.attributes = element.attributes || {});
let classText = this.classText;
if (attrs.class) {
classText += ' ' + attrs.class;
}
if (attrs.className && attrs.className !== attrs.class) {
classText += ' ' + attrs.className;
}
return classText;
}
// Components must implement this method for their specific DOM structure
materialDom(props) {
return h('div', Object.assign({}, props), props.children);
}
render() {
this.buildClassName();
// Fetch a VNode
const componentProps = this.props;
const userDefinedClasses =
componentProps.className || componentProps.class || '';
// We delete class props and add them later in the final
// step so every component does not need to handle user specified classes.
if (componentProps['class']) delete componentProps['class'];
if (componentProps['className']) delete componentProps['className'];
const element = this.materialDom(componentProps);
element.attributes = element.attributes || {};
element.attributes.className = `${userDefinedClasses} ${this.getClassName(
element
)}`
.split(' ')
.filter(
(value, index, self) => self.indexOf(value) === index && value !== ''
) // Unique + exclude empty class names
.join(' ');
// Clean this shit of proxy attributes
this._mdcProps.forEach(prop => {
delete element.attributes[prop];
});
return element;
}
}