gingerchew / element-plus

A base class that makes it easier to build components off of

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ElementPlus - A special utility class stretching the HTMLElement

Documentation

Basic Example

<aside id="myModal">
	<div class="modal-container">
		<header class="modal-header" data-ref="header">
			<h1>Modal Header</h1>
		</header>
		<main class="modal-body" data-ref="body">
			<p>...</p>
		</main>
		<footer class="modal-footer" data-ref="footer">
			<ul>
				<li>...</li>
			</ul>
		</footer>
	</div>
</aside>
class ModalPlus extends ElementPlus {
	constructor(element, props) {
		super(element, props);
		
		this.isOpen = false;
	}
	
	open() {
		if (this.isOpen) return;
		
		this.el.classList.add('open');
		document.classList.add('modal-open');
		requestAnimationFrame(() => {
			this.refs.header.classList.add('fade-in', 'fade-in-1');
			this.refs.body.classList.add('fade-in', 'fade-in-2');
			this.refs.footer.classList.add('fade-in', 'fade-in-3');
		});
		
		this.emitEvent('open');
	}
	
	close() {
		if (!this.isOpen) return;
		
		this.el.classList.remove('open');
		document.classList.remove('modal-open');
		
		this.refs.header.classList.remove('fade-in', 'fade-in-1');
		this.refs.body.classList.remove('fade-in', 'fade-in-2');
		this.refs.footer.classList.remove('fade-in', 'fade-in-3');
		
		this.emitEvent('close');
	}
}

// accepts either an element
// or a valid query selector string
const myModal = new ModalPlus('#myModal');

myModal.open();

References

Any child of the element passed into the constructor can have the data-ref attribute, and it will be available inside the class as this.refs.${value}.

This can be helpful for sectioning off components like a modal. If you need to target multiple references, prefix the value with a dollar sign, and it will return an Array of references instead.

<ul id="myListOfChildren">
	<li data-ref="childName">Jack</li>
	<li data-ref="childBirthday">12/24/1000</li>
	<li data-ref="childName">Jane</li>
	<li data-ref="childBirthday">01/01/0001</li>
	<li data-ref="childName">Jill</li>
</ul>
class ListPlus extends ElementPlus {
	constructor(element, props) {
		super(element, props);
		
		this.names = this.refs.$childNames; // [ li{Jack}, li{Jane}, li{Jill} ]
		this.firstBirthday = this.refs.childBirthday; // li{12/24/1000}
	}
}

Easy Custom Events

Custom Events come built in. You can define the event prefix by adding eventPrefix to the props object in the second argument, but it will default to this.constructor.name.toLowerCase().

To dispatch a custom event, use ElementPlus.dispatchEvent:

class AccordionPlus extends ElementPlus {
	constructor(element, props);
		super(element, props);
	}
	
	expand(target) {
		// Expand your AccordionPlus
		this.dispatchEvent('expand', {
			element: this.el,
			accordionSection: target
		});
	}
}

const myAccordion = new AccordionPlus('#myAccordion', { eventPrefix: 'accordion' });

myAccordion.addEventListener('accordion:expand', console.log) // CusomEvent(/* */)

Simple Templating

While ElementPlus doesn't have the niceties of the ShadowDOM or Scoped Styling, it does come with its own template HTML option.

To use this, simply replace the base static get template HTML() method to return your own template string.

class ComplexListPlus extends ElementPlus {
	constructor(element, props) {
		super(element, props);
		this.el.classList.add('list-items-loading');
		this.getListItems()
			.then(() => this.el.classList.add('list-items-loaded'))
			.catch(() => this.el.classList.add('list-items-error'))
			.then(() => this.el.classList.remove('list-items-loading'));
	}
	
	static get templateHTML() {
		return `
			<li data-ref="listItemContainer" class="list-item-container">
				<span class="list-item-title"></span>
				<span class="list-item-body"></span>
				<span class="list-item-footer">
					<ul data-ref="listItemContainerNav" class="list-item-container-nav">
						<li>...</li>
					</ul>
				</span>
			</li>
		`;
	}
	
	async getListItems() {
		// this will retrieve a <template> element from the ComplexListPlus class
		const tpl = () => this.constructor.template.content.cloneNode();
		
		// this will retrieve the HTML string from the ComplexListPlus class
		const html = this.constructor.templateHTML;
		
		const results = await fetch(...);
		
		const json = await result.json();
		
		requestAnimationFrame(() => {
			json.forEach(arrayItem => {
				const content = tpl();

				/*
					insert data
				*/

				this.el.append(content);
			})
		});
	}
}

About

A base class that makes it easier to build components off of

License:MIT License


Languages

Language:JavaScript 55.8%Language:HTML 44.2%