@pictogrammers/element v0.0.58
Element
Simple TypeScript wrapper for creating a Web Component.
npm install @pictogrammers/elementExample Usage: Element-Hello-World
Basics
To make things easier setup the project assuming the custom element <hello-world message="Hello World!"></hello-world>.
š src/
š hello/
š world/
š world.ts
š world.html
š world.css
š jest.config.json
š package.json
š tsconfig.json
š webpack.config.jsClass (world.ts)
import { Component, Prop, Part } from '@pictogrammers/element';
import template from "./world.html";
import style from './world.css';
@Component({
selector: 'hello-world',
style,
template
})
export default class HelloWorld extends HTMLElement {
@Prop() message = 'Hello World';
@Part() $message: HTMLDivElement;
render(changes) {
if (changes.message) {
this.$message.textContent = this.message;
}
}
}Template (world.html)
<div part="message">Default!</div>CSS Styles (world.css)
:host {
display: block;
}
[part=message] {
/* Style Part */
}Normalizing Props
It is recommended to use primitives for props where possible. To make this easier functions are provided to normalize values for booleans, integers, numbers, and strings.
import { Component, Prop, normalizeBoolean } from '@pictogrammers/element';
// ...
@Prop(normalizeBoolean) selected = false;Which is equivalent to...
import { Component, Prop, normalizeBoolean } from '@pictogrammers/element';
// ...
#selected = false;
@Prop()
get selected() {
return this.#selected;
}
set selected(value: string | boolean) {
this.#selected = normalizeBoolean(value);
}Note: Instead of ever using
get/setalways use therendermethod for managing changes to prevent unncessary operations.
normalizeInt- Wrapper forparseInt(`${value}`, 10).normalizeFloat- Wrapper forparseFloat(`${value}`).normalizeBoolean- Handlesbooltype including string'true'/'false'.normalizeString- Wrapper for`${value}`.
Template Loops
Components can create repeated lists of other components by using the forEach utility. A unique key property is required in each item of the items array (defaults to a uuid if not provided). Any updates will sync values to the component provided in the type function.
Note:
itemin the callbacks is readonly and containsindex.
import { forEach } from '@pictogrammers/element';
import UiItem from 'ui/item';
// ... in element class
// Public
@Prop() options: any[] = [];
// Private
@Prop() #options: any[] = [];
connectedCallback() {
forEach({
container: this.$items,
items: this.options,
type: (item) => {
return UiItem;
},
create: ($item, item) => {
// after creation of $item element
},
connect: ($item, item, $items) => {
// after connectedCallback
},
disconnect: ($item, item, $items) => {
// before disconnectedCallback
},
update: ($item, item, $items) => {
// after every $item update
},
});
}Advanced
Starting with a simple component can allow one to extend it with more features later on. This can be done by extending components.
š src/
š hello/
š world/
š world.ts
š world.html
š world.css
š worldButton/
š worldButton.ts
š worldButton.html
š worldButton.cssTypeScript (worldButton.ts)
import { Component, Prop, Part } from '@pictogrammers/element';
import HelloWorld from '../world/world';
import style from './worldButton.css';
import template from './worldButton.html';
@Component({
selector: 'hello-world-button',
style,
template
})
export default class HelloWorldButton extends HelloWorld {
@Part() $button: HTMLButtonElement;
renderCallback() {
this.$button.addEventListener('click', () => {
alert(this.message);
});
}
}Template (worldButton.html)
<button part="button">
<parent/> <!-- <div>Default!</div> -->
</button>CSS Styles (worldButton.css)
[part=button] {
border-radius: 0.25rem;
border: #ddd;
color: #222;
}@Local(key: string)
To access localStorage values bind them to a class level property with a Map type.
// store:toggle
@Local('store') store = new Map([
['toggle', false]
]);
// Caches to a private property
@Local('store') #store = new Map([
['someobj', null]
]);
// somehere in your code
this.store.get('toggle');
this.store.set('toggle' true);Development
# Build
npm run build
# View files in dist/
# Then link for use locally
npm link
# Within a local project directory
npm link @pictogrammers/elementUtility Base Class
Some other notes about unique use cases that are handled.
Optional Component() Config
Utility base classes can be defined without a config. These are rarely used, but are supported.
import { Component } from '@pictogrammers/element';
@Component()
export default class HelloOverlay extends HtmlElement {
static open() {
}
close() {
}
}Jest Utils
selectComponent<T>(tag: string): TselectPart<T>(component: HTMLElement, name: string): TgetProps(tag: string): string[]
Basic
import { selectComponent, getProps } from '@pictogrammers/element';
import './world';
import HelloWorld from './world';
const HELLO_WORLD = 'hello-world';
describe('hello-world', () => {
const DEFAULT_MESSAGE = 'None';
beforeEach(() => {
var c = document.createElement(HELLO_WORLD);
document.body.appendChild(c);
});
afterEach(() => {
while (document.body.firstChild) {
document.body.removeChild(document.body.firstChild);
}
});
it('should be registered', () => {
expect(customElements.get(HELLO_WORLD)).toBeDefined();
});
it('should only expose known props', () => {
const props = getProps(HELLO_WORLD);
expect(props.length).toBe(2);
expect(props).toContain('message');
expect(props).toContain('count');
});
});9 months ago
9 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
7 months ago
8 months ago
8 months ago
8 months ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
4 years ago
4 years ago
4 years ago
4 years ago