Skip to content

Instantly share code, notes, and snippets.

@loganvolkers
Last active November 19, 2020 23:25
Show Gist options
  • Save loganvolkers/e54aad4fecba5154a0f8008fe53b57d6 to your computer and use it in GitHub Desktop.
Save loganvolkers/e54aad4fecba5154a0f8008fe53b57d6 to your computer and use it in GitHub Desktop.
Use `script` elements for web components. Inspired by @polymer/marked-element
import { Component, Prop, h, State } from '@stencil/core';
import { ScriptTracker } from './ScriptTracker';
@Component({
tag: 'my-component',
styleUrl: 'my-component.css',
shadow: true,
})
export class MyComponent {
/**
* The first name
*/
@Prop() first: string;
/**
* The middle name
*/
@Prop() middle: string;
/**
* The last name
*/
@Prop() last: string;
@State()
config: any;
componentWillLoad() {
// this._connectToScript();
ScriptTracker.connect(this, next => (this.config = next));
}
render() {
return (
<div>
Hello, World! I'm {JSON.stringify(this.config)}
<slot onSlotchange={(e: Event) => ScriptTracker.connect(this, next => (this.config = next))} />
</div>
);
}
}
import { getElement } from '@stencil/core';
export type ScriptTrackerProps = {
element: any;
updater: (value: unknown) => unknown;
onError?: (e: Error) => unknown;
};
export class ScriptTracker {
/**
* Listens to subchanges
*/
observer: MutationObserver;
static connect(element: any, updater: (value: unknown) => unknown) {
const t = new ScriptTracker({
element,
updater,
});
t.update();
return t;
}
constructor(private props: ScriptTrackerProps) {}
update() {
if (this.observer) {
this.observer.disconnect();
}
const scriptEl: HTMLScriptElement = getElement(this.props.element).querySelector(`[type="application/json"]`);
const updateFromScript = () => {
let config: unknown;
try {
config = JSON.parse(scriptEl.textContent);
this.props.updater(config);
} catch (e) {
this.props.onError(e);
}
};
// Options for the observer (which mutations to observe)
const config = { characterData: true, attributes: true, childList: true, subtree: true };
// Create an observer instance linked to the callback function
this.observer = new MutationObserver(updateFromScript);
// Start observing the target node for configured mutations
this.observer.observe(scriptEl, config);
updateFromScript();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment