import { type Locale } from './i18n.js'; /** Pure decision: is the user pinned to the bottom of a scroll container? * Threshold defaults to 80px — small enough that a user who has genuinely * scrolled up to read history is not jolted, large enough that subpixel * rounding (font-size, line-height, scrollbar gutter) does not flip the * decision frame-to-frame. */ export interface ShouldAutoScrollArgs { readonly scrollTop: number; readonly scrollHeight: number; readonly clientHeight: number; readonly thresholdPx?: number; } export declare function shouldAutoScroll(args: ShouldAutoScrollArgs): boolean; /** Short, stable display fallback when a peer didn't claim a nick. * Last 6 chars of the peerId — UUIDs end in random hex so the suffix * distinguishes peers in a small room without leaking the full * identifier into the transcript. */ /** @internal Not part of the package's public API surface; not re-exported from index.ts. Kept exported for cross-file use within the package. */ export declare function shortFromPeerId(peerId: string): string; export interface MessageLike { from: string; nick?: string; ts: number; } /** Author-chain detection — consecutive messages from the same peer/nick * within a short window collapse the from-label and tighten vertical * spacing, mirroring iMessage / Telegram desktop. */ export declare function isChained(prev: MessageLike | undefined, curr: MessageLike): boolean; export declare function formatTime(ts: number): string; /** Format a millisecond duration as mm:ss (e.g. 0:00). */ export declare function formatDuration(ms: number): string; /** Format remaining time until a wall-clock expiry timestamp. * - >= 1h: `Hh Mm` (e.g. `2h 15m`) * - >= 1m: `Mm Ss` (e.g. `15m 30s`) * - <= 1m, > 0: `Ss` (e.g. `30s`) * - <= 0: `expired` * Pure — exported so unit tests can pin every boundary. */ /** @internal Not part of the package's public API surface; not re-exported from index.ts. Kept exported for cross-file use within the package. */ export declare function formatTimeRemaining(remainMs: number): string; /** Tombstone replacement text — same wording for both scopes * (see Task 5 spec; scope is informational, identical visuals). * i18n follow-up: `lang` defaults to 'en' so every existing call site (and * the direct-import unit tests) keeps working without a signature change. */ export declare function tombstoneText(_scope: "self" | "everyone", lang?: Locale): string; /** U2: Failed-decrypt placeholder text (visible) — same wording regardless of * the SDK's unsealError reason ('replay' | 'auth' | 'unknown'). Mirrors * tombstoneText's one-wording-for-all-cases precedent: the UI doesn't need * to expose crypto failure-class detail to the end user, only that the * content is unavailable. Lock glyph gives a visual cue distinct from the * plain-italic tombstone. i18n follow-up: routed through the widget's * locale table (see ./i18n.ts) — `lang` defaults to 'en'. */ export declare function unsealErrorText(lang?: Locale): string; /** U2 review-fix: aria/screen-reader variant of unsealErrorText() — same * wording, no lock glyph. VoiceOver/NVDA announce U+1F512 as "locked", so * the glyph-bearing string would read as "locked This message couldn't be * decrypted" — redundant once the words themselves are spoken. The glyph is * a visual-only affordance; keep it out of the announced text. */ export declare function unsealErrorAriaText(lang?: Locale): string; /** * Guarded self/other identity compare — the single source of truth for every * self-identity check in message-list.ts (bubble alignment, aria-label, * reaction "own" state). Returns false whenever selfUid is unresolved (empty * string), so a row can never false-positive as "self" merely because both * senderUid and selfUid happen to be empty — mirrors hasOwnHeart's non-empty * guard below. Extracted after an independent audit found 4 separate inline * `===`/`includes` compares in message-list.ts that could drift (sibling gap * to PR #39's selfUidFromJwt fix). */ export declare function isSelf(senderUid: string, selfUid: string): boolean; /** Does the current user have a ❤️ reaction on the given message? * Pure helper so the heart-fill state is unit-testable without * mounting Svelte. Tuple shape mirrors the hook view. */ /** @internal Not part of the package's public API surface; not re-exported from index.ts. Kept exported for cross-file use within the package. */ export declare function hasOwnHeart(reactions: ReadonlyArray]> | undefined, selfPeerId: string): boolean; /** Defense-in-depth on the render boundary. Images ride inline as * `data:image/...` URLs; the schema only types `url: string.min(1)` * so a hostile peer could substitute an https:// URL and weaponize * the renderer into a tracking pixel that leaks the receiver's IP * past whatever TURN relay was protecting it. We refuse anything * but a data:image/ URL on display. */ /** @internal Not part of the package's public API surface; not re-exported from index.ts. Kept exported for cross-file use within the package. */ export declare function isSafeImageUrl(url: string | undefined): boolean; /** Same threat-model guard for voice attachments. Only data:audio/ URLs * are rendered — https:// would leak the receiver's IP to a tracking * server past the TURN relay (same concern as isSafeImageUrl). */ /** @internal Not part of the package's public API surface; not re-exported from index.ts. Kept exported for cross-file use within the package. */ export declare function isSafeAudioUrl(url: string | undefined): boolean; /** CSS.escape with a conservative regex fallback for older test runtimes * that may not expose `CSS.escape`. msgIds are UUIDs in practice so this * is a defense-in-depth path. */ /** @internal Not part of the package's public API surface; not re-exported from index.ts. Kept exported for cross-file use within the package. */ export declare function cssEscape(s: string): string; //# sourceMappingURL=list-helpers.d.ts.map