Created
October 8, 2019 13:28
-
-
Save enjikaka/c04d77a4df4ff31980898e18aab65c03 to your computer and use it in GitHub Desktop.
web.js from declinded PR
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Converts a snake-case string to camelCase | |
* | |
* @param {string} str kebab-cased string | |
* @returns {string} camelCased string | |
*/ | |
export function kebabToCamelCase(str) { | |
return str.replace(/(-)([a-z])/g, g => g[1].toUpperCase()); | |
} | |
/** | |
* Converts a camelCase string to kebab-case | |
* | |
* @param {string} str camelCased string | |
* @returns {string} kebab-cased string | |
*/ | |
export function camelToKebabCase(str) { | |
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); | |
} | |
/** | |
* Takes attributes from element and creates an object | |
* with the keys camelCased. | |
* | |
* @param {NamedNodeMap} attributes Element.attributes | |
* @returns {object} Object with camelCased keys | |
*/ | |
export function attributesToObject(attributes) { | |
return attributes | |
? Array.from(attributes).reduce( | |
(cur, { localName, value }) => ({ | |
...cur, | |
[kebabToCamelCase(localName)]: value, | |
}), | |
{}, | |
) | |
: {}; | |
} | |
/** | |
* Takes a class for an extended Component/HTMLElement | |
* and registes it basedof the ClassName as class-name. | |
* | |
* @param {Function} classDef Class of a custom element to register | |
* @returns {string} Name of custom element. | |
*/ | |
export function registerComponent(classDef) { | |
const kebabName = camelToKebabCase(classDef.prototype.constructor.name); | |
customElements.define(kebabName, classDef); | |
/* | |
By returning the kebab-name a custom element can easily used in React by | |
using the default export of a web component which specs the default exports like so: | |
export default registerComponent(renderFunction) | |
Usage in react like: | |
import CoolWebComp from 'cool-web-comp.js'; | |
return (<CoolWebComp />); // <- JSX | |
*/ | |
return kebabName; | |
} | |
/** | |
* Abstraction for React-ish methods. | |
* | |
* Can be extended later with props hadling when needed, already available in google-cast-receiver repo. | |
*/ | |
export class Component extends HTMLElement { | |
connectedCallback() { | |
this.sDOM = this.attachShadow({ mode: 'closed' }); | |
if (this.render) { | |
this.sDOM.innerHTML = this.render(); | |
// Double rAF is a slightly working hack for executing stuff after browser has rendered. | |
requestAnimationFrame(() => | |
requestAnimationFrame(() => { | |
if (this.componentDidMount) { | |
this.componentDidMount(); | |
} | |
}), | |
); | |
} | |
} | |
} | |
/** | |
* Takes a function which will be used for rendering, similar to function components in React. | |
* The name of the function is used to make a custom element and the methods result is injected | |
* to the ShadowDOM. | |
* | |
* @param {Function} renderFunction Function that return innerHTML for ShadowDOM. | |
* @returns {string} Name of custom element. | |
*/ | |
export function registerFunctionComponent(renderFunction) { | |
const kebabName = camelToKebabCase(renderFunction.prototype.constructor.name); | |
customElements.define( | |
kebabName, | |
class extends Component { | |
render() { | |
return renderFunction({ | |
props: attributesToObject(this.attributes), | |
}); | |
} | |
}, | |
); | |
/* | |
By returning the kebab-name a custom element can easily used in React by | |
using the default export of a web component which specs the default exports like so: | |
export default registerFunctionComponent(renderFunction) | |
Usage in react like: | |
import CoolWebComp from 'cool-web-comp.js'; | |
return (<CoolWebComp />); // <- JSX | |
*/ | |
return kebabName; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment