forked from riot/custom-elements
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.next.js
More file actions
96 lines (82 loc) · 2.59 KB
/
index.next.js
File metadata and controls
96 lines (82 loc) · 2.59 KB
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
import {component} from 'riot'
/**
* Create the style node to inject into the shadow DOM
* @param {string} css - component css
* @returns {HTMLElement} style DOM node
*/
function createStyleNode(css) {
const style = document.createElement('style')
style.textContent = css
return style
}
/**
* Move all the child nodes from a source tag to another
* @param {HTMLElement} source - source node
* @param {HTMLElement} target - target node
* @returns {undefined} it's a void method ¯\_(ツ)_/¯
*/
function moveChildren(source, target) {
if (source.firstChild) {
target.appendChild(source.firstChild)
moveChildren(source, target)
}
}
/**
* Create a new custom element Class using the riot core components
* @param {Object} api - custom component api containing lifecycle methods and properties
* @returns {Class} Class extends HTMLElement
*/
export function createElementClass(api) {
const {
css,
exports,
template
} = api
const tagImplementation = exports || {}
return class extends HTMLElement {
constructor() {
// call the super generic HTMLElement class
super()
// create the shadow DOM
this.shadow = this.attachShadow({ mode: 'open' })
this.componentFactory = component({
exports: tagImplementation,
template
})
// append the css if necessary
if (css) this.shadow.appendChild(createStyleNode(css))
}
// on element appended callback
connectedCallback() {
this.component = this.componentFactory(this)
// move the tag root html into the shadow DOM
moveChildren(this.component.root, this.shadow)
}
// on attribute changed
attributeChangedCallback(attributeName, oldValue, newValue) {
if (!this.component) return
this.component.update({}, {
[attributeName]: newValue
})
}
// on element removed
disconnectedCallback() {
this.component.unmount()
}
// component properties to observe
static get observedAttributes() {
return tagImplementation.observedAttributes || []
}
}
}
/**
* Define a new custom element using the riot core components
* @param {string} name - custom component tag name
* @param {Object} api - custom component api containing lifecycle methods and properties
* @param {Object} options - optional options that could be passed to customElements.define
* @returns {undefined} it's a void method again ¯\_(ツ)_/¯
*/
export default function define(name, api, options) {
// define the new custom element
return customElements.define(name, createElementClass(api), options)
}