diff --git a/lib/babel.js b/lib/babel.js index 9871c39..293f534 100644 --- a/lib/babel.js +++ b/lib/babel.js @@ -49,6 +49,12 @@ module.exports = (babel) => { const t = babel.types const nanohtmlModuleNames = ['nanohtml', 'bel', 'yo-yo', 'choo/html'] + /** + * Returns an object which specifies the custom elements by which a built-in is extended. + */ + const createExtendsObjectExpression = (is) => + t.objectExpression([t.objectProperty(t.identifier('is'), t.stringLiteral(is))]) + /** * Returns a node that creates a namespaced HTML element. */ @@ -58,6 +64,15 @@ module.exports = (babel) => { [ns, t.stringLiteral(tag)] ) + /** + * Returns a node that creates a extended namespaced HTML element. + */ + const createNsCustomBuiltIn = (ns, tag, is) => + t.callExpression( + t.memberExpression(t.identifier('document'), t.identifier('createElementNS')), + [ns, t.stringLiteral(tag), createExtendsObjectExpression(is)] + ) + /** * Returns a node that creates an element. */ @@ -67,6 +82,15 @@ module.exports = (babel) => { [t.stringLiteral(tag)] ) + /** + * Returns a node that creates an extended element. + */ + const createCustomBuiltIn = (tag, is) => + t.callExpression( + t.memberExpression(t.identifier('document'), t.identifier('createElement')), + [t.stringLiteral(tag), createExtendsObjectExpression(is)] + ) + /** * Returns a node that creates a comment. */ @@ -188,10 +212,20 @@ module.exports = (babel) => { const result = [] + var isCustomElement = props.is + delete props.is + // Use the SVG namespace for svg elements. if (SVG_TAGS.includes(tag)) { state.svgNamespaceId.used = true - result.push(t.assignmentExpression('=', id, createNsElement(state.svgNamespaceId, tag))) + + if (isCustomElement) { + result.push(t.assignmentExpression('=', id, createNsCustomBuiltIn(state.svgNamespaceId, tag, isCustomElement))) + } else { + result.push(t.assignmentExpression('=', id, createNsElement(state.svgNamespaceId, tag))) + } + } else if (isCustomElement) { + result.push(t.assignmentExpression('=', id, createCustomBuiltIn(tag, isCustomElement))) } else { result.push(t.assignmentExpression('=', id, createElement(tag))) } diff --git a/lib/browser.js b/lib/browser.js index 0bbf1d0..a6c69d0 100644 --- a/lib/browser.js +++ b/lib/browser.js @@ -23,11 +23,24 @@ function nanoHtmlCreateElement (tag, props, children) { delete props.namespace } + // If we are extending a builtin element + var isCustomElement = false + if (props.is) { + isCustomElement = props.is + delete props.is + } + // Create the element if (ns) { - el = document.createElementNS(ns, tag) + if (isCustomElement) { + el = document.createElementNS(ns, tag, { is: isCustomElement }) + } else { + el = document.createElementNS(ns, tag) + } } else if (tag === COMMENT_TAG) { return document.createComment(props.comment) + } else if (isCustomElement) { + el = document.createElement(tag, { is: isCustomElement }) } else { el = document.createElement(tag) } diff --git a/lib/browserify-transform.js b/lib/browserify-transform.js index 0b3af48..4c2f4af 100644 --- a/lib/browserify-transform.js +++ b/lib/browserify-transform.js @@ -119,9 +119,19 @@ function processNode (node, args) { namespace = SVGNS } + // Whether this element is extended + var isCustomElement = props.is + delete props.is + // Create the element if (namespace) { - res.push('var ' + elname + ' = document.createElementNS(' + JSON.stringify(namespace) + ', ' + JSON.stringify(tag) + ')') + if (isCustomElement) { + res.push('var ' + elname + ' = document.createElementNS(' + JSON.stringify(namespace) + ', ' + JSON.stringify(tag) + ', { is: ' + JSON.stringify(isCustomElement) + ' })') + } else { + res.push('var ' + elname + ' = document.createElementNS(' + JSON.stringify(namespace) + ', ' + JSON.stringify(tag) + ')') + } + } else if (isCustomElement) { + res.push('var ' + elname + ' = document.createElement(' + JSON.stringify(tag) + ', { is: ' + JSON.stringify(isCustomElement) + ' })') } else { res.push('var ' + elname + ' = document.createElement(' + JSON.stringify(tag) + ')') } diff --git a/tests/babel/fixtures/custom-build-in.expected.js b/tests/babel/fixtures/custom-build-in.expected.js new file mode 100644 index 0000000..ab168c8 --- /dev/null +++ b/tests/babel/fixtures/custom-build-in.expected.js @@ -0,0 +1,6 @@ +var _div, + _appendChild = require('nanohtml/lib/append-child'); + +_div = document.createElement('div', { + is: 'my-div' +}), _appendChild(_div, ['\n Hello world\n ']), _div; \ No newline at end of file diff --git a/tests/babel/fixtures/custom-build-in.js b/tests/babel/fixtures/custom-build-in.js new file mode 100644 index 0000000..7c86685 --- /dev/null +++ b/tests/babel/fixtures/custom-build-in.js @@ -0,0 +1,7 @@ +import html from 'nanohtml' + +html` +