-
Notifications
You must be signed in to change notification settings - Fork 0
/
custom-element.js
98 lines (77 loc) · 3.21 KB
/
custom-element.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
// Borrowed from https://github.com/DannyMoerkerke/custom-element
// Read his blog post at https://medium.com/swlh/https-medium-com-drmoerkerke-data-binding-for-web-components-in-just-a-few-lines-of-code-33f0a46943b3
export default class CustomElement extends HTMLElement {
constructor() {
super();
this.state = {};
}
isCustomElement(element) {
return Object.getPrototypeOf(customElements.get(element.tagName.toLowerCase())).name === 'CustomElement';
}
updateBindings(prop, value = '') {
const bindings = [...this.selectAll(`[data-bind$="${prop}"]`)];
bindings.forEach(node => {
const dataProp = node.dataset.bind;
const bindProp = dataProp.includes(':') ? dataProp.split(':').shift() : dataProp;
const bindValue = dataProp.includes('.') ? dataProp.split('.').slice(1).reduce((obj, p) => obj[p], value) : value;
const target = [...this.selectAll(node.tagName)].find(el => el === node);
const isStateUpdate = dataProp.includes(':') && this.isCustomElement(target);
isStateUpdate ? target.setState({[`${bindProp}`]: bindValue}) :
this.isArray(bindValue) ? target[bindProp] = bindValue : node.textContent = bindValue.toString();
});
}
setState(newState) {
Object.entries(newState)
.forEach(([key, value]) => {
this.state[key] = this.isObject(this.state[key]) && this.isObject(value) ? {...this.state[key], ...value} : value;
const bindKey = this.isObject(value) ? this.getBindKey(key, value) : key;
const bindKeys = this.isArray(bindKey) ? bindKey : [bindKey];
bindKeys.forEach(key => this.updateBindings(key, value));
});
}
getBindKey(key, obj) {
return Object.keys(obj).map(k => this.isObject(obj[k]) ? `${key}.${this.getBindKey(k, obj[k])}` : `${key}.${k}`);
}
isArray(arr) {
return Array.isArray(arr);
}
isObject(obj) {
return Object.prototype.toString.call(obj) === '[object Object]';
}
select(selector) {
return this.shadowRoot ? this.shadowRoot.querySelector(selector) : this.querySelector(selector);
}
selectAll(selector) {
return this.shadowRoot ? this.shadowRoot.querySelectorAll(selector) : this.querySelectorAll(selector);
}
multiSelect(config) {
Object.entries(config).forEach(([prop, selector]) => {
this[prop] = this.select(selector);
});
}
show(els = null) {
const elems = els || this;
const elements = Array.isArray(elems) || NodeList.prototype.isPrototypeOf(elems) ? elems : [elems];
elements.forEach(element => {
element.style.display = '';
element.removeAttribute('hidden');
});
}
hide(els = null) {
const elems = els || this;
const elements = Array.isArray(elems) || NodeList.prototype.isPrototypeOf(elems) ? elems : [elems];
elements.forEach(element => {
element.style.display = 'none';
element.setAttribute('hidden', '');
});
}
css(els, styles) {
const elements = Array.isArray(els) ? els : [els];
elements.forEach(element => Object.assign(element.style, styles));
}
addTemplate(element, selector, replaceContents = false) {
const template = this.select(selector).content.cloneNode(true);
replaceContents ? element.innerHTML = '' : null;
element.appendChild(template);
}
}