"use client"; import { settingsStore } from "./settings"; /** * Best-effort haptics, behind the Settings → Haptics toggle (on by default). * * Android/Chrome use the Vibration API. iOS ignores `navigator.vibrate`; * since iOS 17.4 the system tick can be triggered by clicking a hidden * `` label — we try that, throttled, and fail * silently everywhere else. Nothing here ever throws or blocks input. */ export type HapticKind = "tap" | "toggle" | "success" | "error" | "celebrate"; const PATTERNS: Record = { tap: 8, toggle: 12, success: [14, 40, 18], error: [30, 60, 30], celebrate: [18, 50, 18, 50, 26], }; let lastIosTick = 0; function iosTick(): void { const now = Date.now(); if (now - lastIosTick < 80) return; lastIosTick = now; try { const label = document.createElement("label"); label.setAttribute("aria-hidden", "true"); label.style.position = "fixed"; label.style.left = "-9999px"; const input = document.createElement("input"); input.type = "checkbox"; input.setAttribute("switch", ""); label.appendChild(input); document.body.appendChild(label); input.click(); window.setTimeout(() => label.remove(), 0); } catch { /* no haptics available */ } } export function haptic(kind: HapticKind = "tap"): void { if (typeof window === "undefined") return; try { if (settingsStore.getSnapshot().haptics === false) return; } catch { return; } try { if (typeof navigator !== "undefined" && typeof navigator.vibrate === "function") { navigator.vibrate(PATTERNS[kind]); return; } iosTick(); } catch { /* silent */ } }