// Typed text in a field that applies on change, so unsaved work includes text not applied yet. import type { ActionReturn } from 'svelte/action' export interface DraftOptions { /** The value the field shows when nothing is typed: the applied one. */ value: string ondraft: (pending: boolean) => void } /** Action reporting whether a text field holds typed text that differs from its applied value. */ export function draft(node: HTMLInputElement | HTMLTextAreaElement, opts: DraftOptions): ActionReturn { let o = opts const check = () => o.ondraft(node.value !== o.value) node.addEventListener('input', check) return { update(next) { o = next check() }, destroy() { node.removeEventListener('input', check) o.ondraft(false) }, } } /** Applies the focused field's typed text by ending its edit, which fires its change event, then refocuses it. */ export function commitFocused(): void { const el = document.activeElement if (!(el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement)) return el.blur() el.focus() }