Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/morris/exdom
Essential DOM utilities
https://github.com/morris/exdom
dom
Last synced: 4 months ago
JSON representation
Essential DOM utilities
- Host: GitHub
- URL: https://github.com/morris/exdom
- Owner: morris
- License: isc
- Created: 2019-02-01T16:13:39.000Z (about 6 years ago)
- Default Branch: main
- Last Pushed: 2024-09-21T16:43:12.000Z (5 months ago)
- Last Synced: 2024-10-11T12:57:42.093Z (4 months ago)
- Topics: dom
- Language: TypeScript
- Homepage: https://morris.github.io/exdom
- Size: 633 KB
- Stars: 9
- Watchers: 2
- Forks: 0
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.md
Awesome Lists containing this project
README
# exdom
Essential DOM utilities.
- Query selector shortcuts
- Soft HTML, text, attribute, and input value setters
- Reconciliation
- Type-safe DOM event managementInspired by learnings from
[VANILLA TODO](https://github.com/morris/vanilla-todo), a case study on viable
techniques for vanilla web development.## Installation
Via npm:
```sh
npm install exdom
```When not using a bundler, exdom can be imported via CDN:
```ts
// src/exdom.js or src/exdom.ts
export * from 'https://cdn.jsdelivr.net/npm/[email protected]/dist/exdom.min.js';// src/exdom.d.ts
declare module 'https://cdn.jsdelivr.net/npm/[email protected]/dist/exdom.min.js' {
export * from 'exdom';
}// src/app.js or src/app.ts
import { ... } from './exdom.js';// ...
```## Usage
A very basic to-do app with exdom could look like this (in TypeScript, but
JavaScript is equally possible) and covers most of exdom's
[functions](https://morris.github.io/exdom):```ts
import {
CustomEventElement,
qsr,
reconcile,
requestAnimationFrameOnce,
setText,
setValue,
TypedCustomEvent,
} from 'exdom';// Type-safe custom DOM event details
interface TodoAppEvents {
addTodoItem: string;
toggleTodoItem: string;
todoItem: TodoItemData;
}interface TodoItemData {
id: string;
label: string;
done: boolean;
}// Component functions
function TodoApp(el: CustomEventElement) {
// Base HTMLel.innerHTML = /* html */ `
To-Do
Add
`;
// Initial data
let items: TodoItemData[] = [
{
id: crypto.randomUUID(),
label: 'Hello, world!',
done: false,
},
];
// Idempotent update
function update() {
// Reconcile todo item components with item list
reconcile({
container: qsr(el, '.items'),
items,
create: () => TodoItem(document.createElement('li')),
update: (el, item) =>
el.dispatchEvent(new TypedCustomEvent('todoItem', { detail: item })),
});
}
// Action handlers
el.addEventListener('addTodoItem', (e) => {
const newItem = {
id: crypto.randomUUID(),
label: e.detail,
done: false,
};
items = [...items, newItem];
requestAnimationFrameOnce(update);
});
el.addEventListener('toggleTodoItem', (e) => {
items = items.map((item) =>
item.id === e.detail ? { ...item, done: !item.done } : item,
);
requestAnimationFrameOnce(update);
});
// UI Events
const labelInput = qsr(el, '[name=label]');
qsr(el, '.add').addEventListener('click', () => {
el.dispatchEvent(
new TypedCustomEvent('addTodoItem', {
detail: labelInput.value,
bubbles: true,
}),
);
setValue(labelInput, '');
});
update(); // Initial update
return el;
}
function TodoItem(el: CustomEventElement) {
el.innerHTML = /* html */ `
`;
let data: TodoItemData;
function update() {
setText(qsr(el, 'label'), data.label);
setValue(qsr(el, '[type=checkbox]'), data.done);
}
el.addEventListener('todoItem', (e) => {
data = e.detail;
requestAnimationFrameOnce(update);
});
qsr(el, '[type=checkbox]').addEventListener('click', () => {
el.dispatchEvent(
new TypedCustomEvent('toggleTodoItem', {
detail: data.id,
bubbles: true,
}),
);
});
return el;
}
// Mount to document
TodoApp(qsr(document, '#app'));
```
See also **[API reference](https://morris.github.io/exdom)**
## Tests
- `npx playwright install` (once)
- `npm test`