"use client"; /** * Presence caret store (TASK-0093) — the single caret of the page currently * in view. * * One page is mounted per tab (route `[id]`), and exactly one Tiptap * editor is focused at a time, so a single optional caret is the whole * client-side state. The focused editor writes it (on focus + every * selection update), every blur clears it, and the per-page * `usePresence` hook (hooks/use-presence.ts) forwards it to the * `PresenceEmitter`, which throttles it into `presence` frames. * * A store (instead of context/props) matches the existing cross-component * state here (editor-store, auth-store, block-patch-store) and keeps the * recursive BlockRenderer untouched. */ import { create } from "zustand"; import type { PresenceSelection } from "@/lib/types"; /** The caret inside one block (offset within the block's text). */ export interface PresenceCaret { blockId: string; offset: number; /** A non-collapsed selection (MVP: inside this one block's doc). */ selection?: PresenceSelection; } interface PresenceCaretState { /** The focused editor's caret, or null (nothing focused / no page). */ caret: PresenceCaret | null; setCaret: (caret: PresenceCaret | null) => void; } export const usePresenceCaretStore = create()((set) => ({ caret: null, setCaret: (caret) => set({ caret }), }));