UNPKG

@zeix/ui-element

Version:

UIElement - a HTML-first library for reactive Web Components

97 lines (88 loc) 2.32 kB
import { type Component, component, fromSelector, on, pass, setAttribute, } from '../../..' export type ModuleTodoProps = { readonly active: HTMLElement[] readonly completed: HTMLElement[] } import '../form-textbox/form-textbox' export default component( 'module-todo', { active: fromSelector('form-checkbox:not([checked])'), completed: fromSelector('form-checkbox[checked]'), }, (el, { first, useElement }) => { const textbox = useElement( 'form-textbox', 'Needed to enter a new todo item.', ) const template = useElement( 'template', 'Needed to define the list item template.', ) const list = useElement('ol', 'Needed to display the list of todos.') const filter = useElement('form-radiogroup') return [ // Control todo input form first('basic-button.submit', [ pass({ disabled: () => !textbox.length }), ]), first('form', [ on('submit', ({ event }) => { event.preventDefault() const value = textbox.value.trim() if (!value) return const li = document.importNode( template.content, true, ).firstElementChild if (!(li instanceof HTMLLIElement)) throw new Error( 'Invalid template for list item; expected <li>', ) li.querySelector('slot')?.replaceWith(value) list.append(li) textbox.clear() }), ]), // Control todo list first('ol', [ setAttribute('filter', () => filter?.value || 'all'), on('click', ({ event }) => { const target = event.target as HTMLElement if (target.closest('button')) target.closest('li')!.remove() }), ]), // Update count elements first('basic-pluralize', [pass({ count: () => el.active.length })]), // Control clear-completed button first('basic-button.clear-completed', [ pass({ disabled: () => !el.completed.length, badge: () => el.completed.length > 0 ? String(el.completed.length) : '', }), on('click', () => { const items = Array.from(el.querySelectorAll('ol li')) for (let i = items.length - 1; i >= 0; i--) { const task = items[i].querySelector('form-checkbox') if (task?.checked) items[i].remove() } }), ]), ] }, ) declare global { interface HTMLElementTagNameMap { 'module-todo': Component<ModuleTodoProps> } }