UNPKG

@ou-imdt/create

Version:

Command line tool to create team boilerplate.

113 lines (95 loc) 3.49 kB
// import Lit refs import { css, html, nothing, unsafeCSS } from 'lit'; // import utils import { mix } from '@utils'; // import internal symbols/hooks import { defaultState } from '@core/internals'; // import base class (extends LitElement) import { Base } from '@components'; // import a mixin and associated symbols/hooks import { default as DelegateFocusMixin, focus, focusVisible } from '@mixins/DelegateFocusMixin'; // import component styles import styles from './Component.css?raw'; // use symbols for private reactive/protected props (export to give access outside class/to subclasses) // Lit doesn't support private class fields for technical reasons (seem more trouble than they're worth anyway!) export const protectedProperty = Symbol('protectedProperty'); // name class accordingly and extend base directly or mix with as many mixins as needed export default class Component extends mix(Base).with(DelegateFocusMixin) { // component tag name static tag = 'imdt-component'; // set component styles static styles = css` ${unsafeCSS(styles)} `; // Lit reactive props static properties = { // add DelegateFocusMixin hooks [focus]: { type: Boolean, attribute: 'focus', // attribute as CSS hook reflect: true, // setting prop is reflected back to attribute converter: {fromAttribute: () => null // removes attribute if externally set } }, [focusVisible]: { type: Boolean, attribute: 'focus-visible', // attribute as CSS hook reflect: true, converter: {fromAttribute: () => null // removes attribute if externally set } }, [protectedProperty]: {state: true // internal only, no attribute etc. }, publicProperty: { type: String, attribute: 'publicProperty' // sets attribute name (defaults to prop key) }, }; // define default state static [defaultState] = { ...super[defaultState], // add mixin state ([focus]/[focusVisible] are in there) [protectedProperty]: null, publicProperty: 'Hello World!' }; // use private class fields/methods to keep private to class (most useful in mixins) // N.B. use with caution in extensible components (not accessible to subclasses) #privateProperty = null; #privateMethod() { } // constructor calling super() constructor() { super(); } // lifecyle (CustomElement/Lit) // a good place to add event listeners to this connectedCallback() { this.addEventListener('click', this); // must call super method... super.connectedCallback(); } // remove event listeners here etc. disconnectedCallback() { this.removeEventListener('click', this); // must call super method... super.disconnectedCallback(); } // handle changed props here and a good place to dispatch events to limit side effects // (updating reactive props here won't trigger another update cycle) willUpdate(changedProperties) { // if (changedProperties.has(focus)) { // call overriden native method to dispatch namespaced custom event this.dispatchEvent('focus', { detail: { focus: this[focus] }}); } } render() { return html`<p class=${this[protectedProperty] ?? nothing}>${this.publicProperty}</p>`; } // do any work here that sits outside of update cycle (like updating accessible DOM) updated() { } } // register component if (!customElements.get(Component.tag)) { customElements.define(Component.tag, Component); }