Support custom elements v1 (#829)

* feat(core): support custom elements v1

closes #141

* style: remove unintentional spaced

* feat: move `is` attribute to the data object

* refactor: code review requested changes

* refactor: remove redundant functions

Co-authored-by: Simon Friis Vindum <simonfv@gmail.com>
pull/949/head
Mohammad Hasani 4 years ago committed by GitHub
parent e22a369ce2
commit 3aa02ed1ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,6 +1,6 @@
export interface DOMAPI {
createElement: (tagName: any) => HTMLElement
createElementNS: (namespaceURI: string, qualifiedName: string) => Element
createElement: (tagName: any, options?: ElementCreationOptions) => HTMLElement
createElementNS: (namespaceURI: string, qualifiedName: string, options?: ElementCreationOptions) => Element
createTextNode: (text: string) => Text
createComment: (text: string) => Comment
insertBefore: (parentNode: Node, newNode: Node, referenceNode: Node | null) => void
@ -16,12 +16,12 @@ export interface DOMAPI {
isComment: (node: Node) => node is Comment
}
function createElement (tagName: any): HTMLElement {
return document.createElement(tagName)
function createElement (tagName: any, options?: ElementCreationOptions): HTMLElement {
return document.createElement(tagName, options)
}
function createElementNS (namespaceURI: string, qualifiedName: string): Element {
return document.createElementNS(namespaceURI, qualifiedName)
function createElementNS (namespaceURI: string, qualifiedName: string, options?: ElementCreationOptions): Element {
return document.createElementNS(namespaceURI, qualifiedName, options)
}
function createTextNode (text: string): Text {

@ -17,7 +17,11 @@ type VNodeQueue = VNode[]
const emptyNode = vnode('', {}, [], undefined, undefined)
function sameVnode (vnode1: VNode, vnode2: VNode): boolean {
return vnode1.key === vnode2.key && vnode1.sel === vnode2.sel
const isSameKey = vnode1.key === vnode2.key
const isSameIs = vnode1.data?.is === vnode2.data?.is
const isSameSel = vnode1.sel === vnode2.sel
return isSameSel || isSameKey || isSameIs
}
function isVnode (vnode: any): vnode is VNode {
@ -109,8 +113,8 @@ export function init (modules: Array<Partial<Module>>, domApi?: DOMAPI) {
const dot = dotIdx > 0 ? dotIdx : sel.length
const tag = hashIdx !== -1 || dotIdx !== -1 ? sel.slice(0, Math.min(hash, dot)) : sel
const elm = vnode.elm = isDef(data) && isDef(i = data.ns)
? api.createElementNS(i, tag)
: api.createElement(tag)
? api.createElementNS(i, tag, data)
: api.createElement(tag, data)
if (hash < dot) elm.setAttribute('id', sel.slice(hash + 1, dot))
if (dotIdx > 0) elm.setAttribute('class', sel.slice(dot + 1).replace(/\./g, ' '))
for (i = 0; i < cbs.create.length; ++i) cbs.create[i](emptyNode, vnode)

@ -33,6 +33,7 @@ export interface VNodeData {
ns?: string // for SVGs
fn?: () => VNode // for thunks
args?: any[] // for thunks
is?: string // for custom elements v1
[key: string]: any // for any other 3rd party module
}

@ -36,12 +36,21 @@ function map (fn: any, list: any[]) {
const inner = prop('innerHTML')
class A extends HTMLParagraphElement {}
class B extends HTMLParagraphElement {}
describe('snabbdom', function () {
before(function () {
customElements.define('p-a', A, { extends: 'p' })
customElements.define('p-b', B, { extends: 'p' })
})
let elm: any, vnode0: any
beforeEach(function () {
elm = document.createElement('div')
vnode0 = elm
})
describe('hyperscript', function () {
it('can create vnode with proper tag', function () {
assert.strictEqual(h('div').sel, 'div')
@ -181,6 +190,11 @@ describe('snabbdom', function () {
assert(elm.firstChild.classList.contains('has'))
assert(elm.firstChild.classList.contains('classes'))
})
it('can create custom elements', function () {
const vnode1 = h('p', { is: 'p-a' })
elm = patch(vnode0, vnode1).elm
assert(elm instanceof A)
})
it('can create elements with text content', function () {
elm = patch(vnode0, h('div', ['I am a string'])).elm
assert.strictEqual(elm.innerHTML, 'I am a string')
@ -344,6 +358,15 @@ describe('snabbdom', function () {
patch(vnode1, vnode2)
assert.strictEqual((elm as any).a, 'foo')
})
it('handles changing is attribute', function () {
const vnode1 = h('p', { is: 'p-a' })
const vnode2 = h('p', { is: 'p-b' })
elm = patch(vnode0, vnode1).elm
assert(elm instanceof A)
elm = patch(vnode1, vnode2).elm
assert(elm instanceof B)
})
describe('using toVNode()', function () {
it('can remove previous children of the root element', function () {
const h2 = document.createElement('h2')

Loading…
Cancel
Save