{"version":3,"file":"SyncStatusBadge.cjs","names":[],"sources":["../../../src/components/SyncStatusBadge/SyncStatusBadge.tsx"],"sourcesContent":["import type { HTMLAttributes } from \"react\";\nimport { AlertTriangle, Check, CloudOff, RefreshCw, UploadCloud } from \"lucide-react\";\nimport { cn } from \"@/utils/cn\";\nimport type { OfflineSync, SyncTone } from \"@/offline\";\nimport { useSyncStatus } from \"@/offline/use-offline-sync\";\nimport { VisuallyHidden } from \"../VisuallyHidden\";\nimport styles from \"./SyncStatusBadge.module.css\";\n\nconst DEFAULT_LABELS: Record<SyncTone, string> = {\n    idle: \"Sincronizado\",\n    syncing: \"Sincronizando…\",\n    pending: \"Pendente\",\n    offline: \"Offline\",\n    error: \"Erro\",\n};\n\nconst ICONS: Record<SyncTone, typeof Check> = {\n    idle: Check,\n    syncing: RefreshCw,\n    pending: UploadCloud,\n    offline: CloudOff,\n    error: AlertTriangle,\n};\n\nexport interface SyncStatusBadgeProps extends Omit<HTMLAttributes<HTMLSpanElement>, \"children\"> {\n    /**\n     * The dominant tone. Required when `sync` is not passed. Ignored when `sync`\n     * is passed (the tone is derived from the engine).\n     */\n    tone?: SyncTone;\n    /**\n     * An `OfflineSync` engine to observe directly. When set, the badge wires\n     * `useSyncStatus` internally, so `tone` and `pending` come from the engine.\n     */\n    sync?: OfflineSync<unknown>;\n    /** Number of queued mutations, appended to the label when `> 0`. */\n    pending?: number;\n    /** Override the per-tone label text. */\n    labels?: Partial<Record<SyncTone, string>>;\n    /** Show the pending count next to the label. Default `true`. */\n    showPending?: boolean;\n    /** Render only the icon (no text). Default `false`. */\n    iconOnly?: boolean;\n}\n\ntype PresentationalProps = Omit<SyncStatusBadgeProps, \"sync\">;\n\n/**\n * The badge itself: a persistent `role=\"status\"` region.\n *\n * Left as its own live region rather than routed through `useAnnounce`, on purpose.\n * The badge is not a transient message — it is a piece of state that stays on\n * screen, which is exactly what `role=\"status\"` describes, and a reader can go back\n * and re-read it. Announcing it *again* from the shared announcer would read every\n * tone change twice.\n *\n * `iconOnly` used to break that, though: dropping the label left a live region whose\n * content never changed, so a switch to `offline` or `error` was announced as\n * nothing at all. The label is now always rendered — visually hidden when\n * `iconOnly`, since `title` is not content and is not announced on a change.\n */\nfunction PresentationalBadge({\n    tone = \"idle\",\n    pending = 0,\n    labels,\n    showPending = true,\n    iconOnly = false,\n    className,\n    ...props\n}: PresentationalProps) {\n    const Icon = ICONS[tone];\n    const label = labels?.[tone] ?? DEFAULT_LABELS[tone];\n    const showCount = showPending && pending > 0 && (tone === \"pending\" || tone === \"error\");\n    return (\n        <span\n            className={cn(styles.badge, styles[tone], className)}\n            role=\"status\"\n            aria-live=\"polite\"\n            title={label}\n            {...props}\n        >\n            <Icon\n                className={cn(styles.icon, tone === \"syncing\" && styles.spin)}\n                size={14}\n                aria-hidden=\"true\"\n            />\n            {iconOnly ? (\n                <VisuallyHidden>{label}</VisuallyHidden>\n            ) : (\n                <span className={styles.label}>{label}</span>\n            )}\n            {showCount && <span className={styles.count}>{pending}</span>}\n        </span>\n    );\n}\n\nfunction ConnectedBadge({ sync, ...rest }: PresentationalProps & { sync: OfflineSync<unknown> }) {\n    const { tone, pending } = useSyncStatus(sync);\n    return <PresentationalBadge {...rest} tone={tone} pending={pending} />;\n}\n\n/**\n * Compact pill showing offline-sync status: a tone-colored icon plus a label\n * and optional pending count.\n *\n * Two modes: pass `sync` to have the badge observe an engine via\n * `useSyncStatus` (zero wiring), or pass an explicit `tone` (+ `pending`) to\n * keep it presentational and testable without IndexedDB.\n *\n * @example\n * // Connected — auto-wires the engine:\n * <SyncStatusBadge sync={notesSync} />\n *\n * // Presentational — you own the state:\n * const { tone, pending } = useSyncStatus(notesSync);\n * <SyncStatusBadge tone={tone} pending={pending} />\n */\nexport function SyncStatusBadge({ sync, ...rest }: SyncStatusBadgeProps) {\n    if (sync) return <ConnectedBadge sync={sync} {...rest} />;\n    return <PresentationalBadge {...rest} />;\n}\n"],"mappings":"+OAQA,IAAM,EAA2C,CAC7C,KAAM,eACN,QAAS,iBACT,QAAS,WACT,QAAS,UACT,MAAO,MACX,EAEM,EAAwC,CAC1C,KAAM,EAAA,MACN,QAAS,EAAA,UACT,QAAS,EAAA,YACT,QAAS,EAAA,SACT,MAAO,EAAA,aACX,EAuCA,SAAS,EAAoB,CACzB,OAAO,OACP,UAAU,EACV,SACA,cAAc,GACd,WAAW,GACX,YACA,GAAG,GACiB,CACpB,IAAM,EAAO,EAAM,GACb,EAAQ,IAAS,IAAS,EAAe,GACzC,EAAY,GAAe,EAAU,IAAM,IAAS,WAAa,IAAS,SAChF,OACI,EAAA,EAAA,KAAA,CAAC,OAAD,CACI,UAAW,EAAA,GAAG,EAAA,QAAO,MAAO,EAAA,QAAO,GAAO,CAAS,EACnD,KAAK,SACL,YAAU,SACV,MAAO,EACP,GAAI,EALR,SAAA,EAOI,EAAA,EAAA,IAAA,CAAC,EAAD,CACI,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,IAAS,WAAa,EAAA,QAAO,IAAI,EAC5D,KAAM,GACN,cAAY,MACf,CAAA,EACA,GACG,EAAA,EAAA,IAAA,CAAC,EAAA,eAAD,CAAA,SAAiB,CAAsB,CAAA,GAEvC,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,MAAQ,SAAA,CAAY,CAAA,EAE/C,IAAa,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,MAAQ,SAAA,CAAc,CAAA,CAC1D,GAEd,CAEA,SAAS,EAAe,CAAE,OAAM,GAAG,GAA8D,CAC7F,GAAM,CAAE,OAAM,WAAY,EAAA,cAAc,CAAI,EAC5C,OAAO,EAAA,EAAA,IAAA,CAAC,EAAD,CAAqB,GAAI,EAAY,OAAe,SAAU,CAAA,CACzE,CAkBA,SAAgB,EAAgB,CAAE,OAAM,GAAG,GAA8B,CAErE,OADI,GAAa,EAAA,EAAA,IAAA,CAAC,EAAD,CAAsB,OAAM,GAAI,CAAO,CAAA,GACjD,EAAA,EAAA,IAAA,CAAC,EAAD,CAAqB,GAAI,CAAO,CAAA,CAC3C"}