From cb1b56f5a0eddbf77446f415f2beda57c8305f85 Mon Sep 17 00:00:00 2001
From: polwex <polwex@sortug.com>
Date: Sun, 23 Nov 2025 01:12:53 +0700
Subject: wut

---
 packages/prosody-ui/src/zoom/hooks/useZoom.tsx | 135 +++++++++++++++++++++++++
 1 file changed, 135 insertions(+)
 create mode 100644 packages/prosody-ui/src/zoom/hooks/useZoom.tsx

(limited to 'packages/prosody-ui/src/zoom/hooks/useZoom.tsx')

diff --git a/packages/prosody-ui/src/zoom/hooks/useZoom.tsx b/packages/prosody-ui/src/zoom/hooks/useZoom.tsx
new file mode 100644
index 0000000..733ca06
--- /dev/null
+++ b/packages/prosody-ui/src/zoom/hooks/useZoom.tsx
@@ -0,0 +1,135 @@
+import React, {
+  createContext,
+  useState,
+  useContext,
+  type ReactNode,
+} from "react";
+import type { ViewLevel, ViewState } from "../logic/types";
+
+// Type definitions for the context
+interface ZoomContextType {
+  viewState: ViewState;
+  setLevel: (level: ViewLevel) => void;
+  setParagraphIndex: (idx: number | null) => void;
+  setSentenceIndex: (idx: number | null) => void;
+  setClauseIndex: (idx: number | null) => void;
+  setWordIndex: (idx: number | null) => void;
+  setSyllableIndex: (idx: number | null) => void;
+  setPhonemeIndex: (idx: number | null) => void;
+  navigateBack: () => void;
+  handleElementClick: (e: React.MouseEvent, idx: number) => void;
+}
+
+// Create the context with default empty values
+const ZoomContext = createContext<ZoomContextType>({
+  viewState: {
+    level: "text",
+    pIndex: null,
+    sIndex: null,
+    cIndex: null,
+    wIndex: null,
+    yIndex: null,
+    fIndex: null,
+  },
+  setLevel: () => {},
+  setParagraphIndex: () => {},
+  setSentenceIndex: () => {},
+  setClauseIndex: () => {},
+  setWordIndex: () => {},
+  setSyllableIndex: () => {},
+  setPhonemeIndex: () => {},
+  navigateBack: () => {},
+  handleElementClick: () => {},
+});
+
+// Provider component
+export const ZoomProvider: React.FC<{ children: ReactNode }> = ({
+  children,
+}) => {
+  const [viewState, setViewState] = useState<ViewState>({
+    level: "text",
+    pIndex: null,
+    sIndex: null,
+    cIndex: null,
+    wIndex: null,
+    yIndex: null,
+    fIndex: null,
+  });
+
+  // Helper functions to update individual parts of the state
+  const setLevel = (level: ViewLevel) =>
+    setViewState((prev) => ({ ...prev, level }));
+  const setParagraphIndex = (pIndex: number | null) =>
+    setViewState((prev) => ({ ...prev, pIndex }));
+  const setSentenceIndex = (sIndex: number | null) =>
+    setViewState((prev) => ({ ...prev, sIndex }));
+  const setClauseIndex = (cIndex: number | null) =>
+    setViewState((prev) => ({ ...prev, cIndex }));
+  const setWordIndex = (wIndex: number | null) =>
+    setViewState((prev) => ({ ...prev, wIndex }));
+  const setSyllableIndex = (yIndex: number | null) =>
+    setViewState((prev) => ({ ...prev, yIndex }));
+  const setPhonemeIndex = (fIndex: number | null) =>
+    setViewState((prev) => ({ ...prev, fIndex }));
+
+  // Handle navigation levels
+  const navigateBack = () => {
+    const { level } = viewState;
+
+    if (level === "paragraph") {
+      setViewState((prev) => ({ ...prev, level: "text", pIndex: null }));
+    } else if (level === "sentence") {
+      setViewState((prev) => ({ ...prev, level: "paragraph", sIndex: null }));
+    } else if (level === "clause") {
+      setViewState((prev) => ({ ...prev, level: "sentence", cIndex: null }));
+    } else if (level === "word") {
+      setViewState((prev) => ({ ...prev, level: "clause", wIndex: null }));
+    } else if (level === "syllable") {
+      setViewState((prev) => ({ ...prev, level: "word", yIndex: null }));
+    } else if (level === "phoneme") {
+      setViewState((prev) => ({ ...prev, level: "syllable", fIndex: null }));
+    }
+  };
+
+  // Handle clicks on elements to navigate forward
+  const handleElementClick = (e: React.MouseEvent, idx: number) => {
+    e.stopPropagation();
+    const { level } = viewState;
+
+    if (level === "text") {
+      setViewState((prev) => ({ ...prev, level: "paragraph", pIndex: idx }));
+    } else if (level === "paragraph") {
+      setViewState((prev) => ({ ...prev, level: "sentence", sIndex: idx }));
+    } else if (level === "sentence") {
+      setViewState((prev) => ({ ...prev, level: "clause", cIndex: idx }));
+    } else if (level === "clause") {
+      setViewState((prev) => ({ ...prev, level: "word", wIndex: idx }));
+    } else if (level === "word") {
+      setViewState((prev) => ({ ...prev, level: "syllable", yIndex: idx }));
+    } else if (level === "syllable") {
+      setViewState((prev) => ({ ...prev, level: "phoneme", fIndex: idx }));
+    }
+  };
+
+  return (
+    <ZoomContext.Provider
+      value={{
+        viewState,
+        setLevel,
+        setParagraphIndex,
+        setSentenceIndex,
+        setClauseIndex,
+        setWordIndex,
+        setSyllableIndex,
+        setPhonemeIndex,
+        navigateBack,
+        handleElementClick,
+      }}
+    >
+      {children}
+    </ZoomContext.Provider>
+  );
+};
+
+// Custom hook to use the zoom context
+export const useZoom = () => useContext(ZoomContext);
-- 
cgit v1.2.3

