(function (root, factory) { if (typeof module === 'object' && module.exports) module.exports = factory; else root.createUpdateTriageGesture = factory; })(typeof self !== 'undefined' ? self : this, function createUpdateTriageGesture(options) { const viewportWidth = options.viewportWidth || (() => root.innerWidth); const surface = options.surface; const threshold = options.threshold || 72; const edgeInset = options.edgeInset || 24; const interactive = 'a,button,input,textarea,select,label,summary,[contenteditable="true"],[role="button"]'; let active = null; let busy = false; function horizontalScroller(target) { for (let node = target; node && node !== surface; node = node.parentElement) { if (Number(node.scrollWidth) > Number(node.clientWidth) + 1) return true; } return false; } function ignored(event) { return event.pointerType === 'mouse' || event.clientX <= edgeInset || event.clientX >= viewportWidth() - edgeInset || Boolean(event.target?.closest?.(interactive)) || horizontalScroller(event.target); } function reset() { active = null; delete surface.dataset.triageGesture; } function start(event) { if (busy || !options.enabled() || viewportWidth() > 700 || ignored(event) || active) return; active = {id:event.pointerId, x:event.clientX, y:event.clientY, cancelled:false}; surface.setPointerCapture?.(event.pointerId); } function move(event) { if (!active || active.id !== event.pointerId) return; const dx = event.clientX - active.x; const dy = event.clientY - active.y; if (Math.abs(dy) > Math.abs(dx) || Math.abs(dy) > 36) { active.cancelled = true; delete surface.dataset.triageGesture; return; } if (Math.abs(dx) < 12) return; event.preventDefault?.(); surface.dataset.triageGesture = dx > 0 ? 'keep' : 'read'; } function decide(callback) { busy = true; let outcome; try { outcome = callback(); } catch (error) { busy = false; throw error; } if (outcome && typeof outcome.then === 'function') { Promise.resolve(outcome).finally(() => { busy = false; }); } else { busy = false; } } function finish(event) { if (!active || active.id !== event.pointerId) return; const gesture = active; const dx = event.clientX - gesture.x; const dy = event.clientY - gesture.y; surface.releasePointerCapture?.(event.pointerId); reset(); if (gesture.cancelled || Math.abs(dx) < threshold || Math.abs(dx) <= Math.abs(dy)) return; decide(dx > 0 ? options.keepUnread : options.markRead); } surface.addEventListener('pointerdown', start); surface.addEventListener('pointermove', move); surface.addEventListener('pointerup', finish); surface.addEventListener('pointercancel', reset); function destroy() { surface.removeEventListener('pointerdown', start); surface.removeEventListener('pointermove', move); surface.removeEventListener('pointerup', finish); surface.removeEventListener('pointercancel', reset); reset(); } return {destroy}; });