Last active
June 22, 2017 19:09
-
-
Save EndangeredMassa/6af3c6b745a32d6932bcfe53cfb0e5bf to your computer and use it in GitHub Desktop.
enhanced glimmer components, with some surface-level workarounds
This file contains 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
// NOTE: modify this file from this commit on this PR: | |
// https://github.com/glimmerjs/glimmer-web-component/pull/18/commits/8bc4b27f2b78aa2cf6ce0f246dbbb55e88718007 | |
import Application from '@glimmer/application'; | |
function glimmerElementFactory(app: Application, componentName: string) { | |
function GlimmerElement() { | |
return Reflect.construct(HTMLElement, [], GlimmerElement); | |
} | |
GlimmerElement.prototype = Object.create(HTMLElement.prototype, { | |
constructor: { value: GlimmerElement }, | |
connectedCallback: { | |
value: function connectedCallback(): void { | |
let shadowRoot = this.attachShadow({ mode: 'open' }); | |
app.renderComponent(componentName, shadowRoot); | |
} | |
}, | |
attributeChangedCallback: { | |
value: function attributeChangedCallback(attr, oldValue, newValue): void { | |
if (this.onAttributeChangedCallback) { | |
this.onAttributeChangedCallback(attr, newValue); | |
} | |
} | |
} | |
}); | |
Object.defineProperty(GlimmerElement, 'observedAttributes', { | |
get: function getObservedAttributes() { | |
// NOTE: we'll want to pass these in to glimmerElementFactory | |
// from initializeCustomElements so that the user app code | |
// can specify what goes here; or, inpect the user-defined | |
// component for tracked attributes somehow | |
return ['show', 'other']; | |
} | |
}); | |
return GlimmerElement; | |
} | |
export default glimmerElementFactory; |
This file contains 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
// NOTE: In a consumer glimmer app, create a component like the following. | |
import Component, { tracked } from '@glimmer/component'; | |
/* | |
Assigns the top-level dom element's attributes to the | |
glimmer component instance as `this.htmlAttrs`. | |
*/ | |
function setAttributes(glimmerComponent, webComponent) { | |
const attrs = Array.prototype.slice.call(webComponent.attributes); | |
glimmerComponent.htmlAttrs = attrs.reduce((newAttrs, node) => { | |
newAttrs[node.name] = node.nodeValue; | |
return newAttrs; | |
}, {}); | |
} | |
// NOTE: This should go into the core glimmer-component | |
class AttrComponent extends Component { | |
@tracked | |
htmlAttrs: any; | |
didInsertElement() { | |
const webComponent = this.element.parentNode.host; | |
// glimmer's web component's attribute changed callback | |
// will invoke this for us, if it exists | |
webComponent.onAttributeChangedCallback = (attr, newValue) => { | |
const attrs = Array.prototype.slice.call(webComponent.attributes); | |
setAttributes(this, webComponent); | |
}; | |
setAttributes(this, webComponent); | |
} | |
dispatchEvent(name, args) { | |
const webComponent = this.element.parentNode.host; | |
const event = new CustomEvent(name, { detail: args }); | |
webComponent.dispatchEvent(event); | |
} | |
doWork() { | |
this.dispatchEvent('work', 4); | |
} | |
} | |
export default class MyControl extends AttrComponent { | |
@tracked('htmlAttrs') | |
get show() { | |
if (this.htmlAttrs) { | |
return parseInt(this.htmlAttrs.show, 10); | |
} | |
return -1; | |
} | |
}; |
This file contains 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
<!DOCTYPE html> | |
<html> | |
<body> | |
<my-control show="1" other="thing"> | |
<p>some block content</p> | |
</my-control> | |
<script src="app.js"></script> | |
</body> | |
</html> |
This file contains 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
<!-- Web Component Definition Code--> | |
<template id="hello-element-template"> | |
Hi {{name}}! | |
<button id="action">Do It!</button> | |
</template> | |
<script> | |
class HelloElement extends HTMLElement { | |
constructor() { | |
super(); | |
// properties | |
this.name = null; | |
this.clickCount = 0; | |
// setup web component's shadow root | |
this.attachShadow({mode: 'open'}); | |
this.template = document.querySelector('#hello-element-template'); | |
// initial template render | |
this.render(); | |
} | |
// Monitor the 'name' attribute for changes. | |
static get observedAttributes() { return ['name']; } | |
// Respond to attribute changes. | |
attributeChangedCallback(attr, oldValue, newValue) { | |
if (attr === "name") { | |
this.name = newValue; | |
} | |
this.render(); | |
} | |
render(){ | |
this._removeChildren(); | |
this._setupTemplate(); | |
this._interpolateAttributes(); | |
this._setupEventHandlers(); | |
} | |
_removeChildren() { | |
while (this.shadowRoot.hasChildNodes()) { | |
this.shadowRoot.removeChild(this.shadowRoot.lastChild); | |
} | |
} | |
_setupTemplate() { | |
const instance = this.template.content.cloneNode(true); | |
this.shadowRoot.appendChild(instance); | |
} | |
_interpolateAttributes() { | |
this.shadowRoot.innerHTML = this.shadowRoot.innerHTML.replace('{{name}}', this.name); | |
} | |
_setupEventHandlers() { | |
this.shadowRoot.querySelector('#action').addEventListener("click", (clickEvent) => { | |
this.clickCount += 1; | |
const event = new CustomEvent('do-something', { detail: this.clickCount }); | |
this.dispatchEvent(event); | |
}, false); | |
} | |
} | |
// Define the new element | |
customElements.define('hello-element', HelloElement); | |
</script> | |
<!-- Consumer Code --> | |
<hello-element name="Sean"></hello-element> | |
<hr> | |
Name: <input type="text" id="new-name"></input> | |
<button id="change-name">Change</button> | |
<br> | |
Click Count: <span id="output">0</span> | |
<script> | |
const helloElement = document.querySelector('hello-element'); | |
helloElement.addEventListener('do-something', function(event) { | |
document.querySelector('#output').textContent = event.detail; | |
}); | |
const nameButton = document.querySelector('#change-name'); | |
nameButton.addEventListener('click', function(event){ | |
const newName = document.querySelector('#new-name').value; | |
document.querySelector('hello-element').setAttribute('name', newName); | |
}); | |
</script> | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment