Skip to content

Kody is live

Watch the launch video — what Kody is, and why it exists.

← Public packages

@kentcdodds/package-app-kit

Design tokens, PWA install/update, About/version, cache helpers, and optional realtime notes sync for Kody package apps.

src/client/double-check.ts

62 lines · 1.6 KB · TypeScript
/** Declarative [data-double-check] two-step confirm buttons. */

export function bootDoubleCheck() {
	function labelFor(btn, armed) {
		const base =
			btn.getAttribute('data-label') ||
			btn.getAttribute('data-default-label') ||
			btn.textContent ||
			'Confirm'
		const confirm = btn.getAttribute('data-confirm-label') || 'Are you sure?'
		if (!btn.getAttribute('data-default-label')) btn.setAttribute('data-default-label', base)
		return armed ? confirm : btn.getAttribute('data-default-label') || base
	}

	function setArmed(btn, armed) {
		btn.setAttribute('data-armed', armed ? 'true' : 'false')
		btn.setAttribute('aria-pressed', armed ? 'true' : 'false')
		if (!btn.disabled) btn.textContent = labelFor(btn, armed)
	}

	document.addEventListener(
		'click',
		(e) => {
			let t = e.target
			if (t && t.nodeType === 3) t = t.parentElement
			const el = t
			if (!el?.closest) return
			const btn = el.closest('[data-double-check]')
			if (!btn || btn.disabled) return
			const armed = btn.getAttribute('data-armed') === 'true'
			if (!armed) {
				e.preventDefault()
				e.stopPropagation()
				setArmed(btn, true)
				btn.focus()
				return
			}
			setArmed(btn, false)
			btn.dispatchEvent(new CustomEvent('pak:confirmed', { bubbles: true }))
		},
		true,
	)

	document.addEventListener(
		'blur',
		(e) => {
			const t = e.target
			if (!t?.closest) return
			const btn = t.closest('[data-double-check]')
			if (btn) setArmed(btn, false)
		},
		true,
	)

	document.addEventListener('keyup', (e) => {
		if (e.key !== 'Escape') return
		const t = e.target
		if (!t?.closest) return
		const btn = t.closest('[data-double-check]')
		if (btn) setArmed(btn, false)
	})
}