From 68ad8b372608b39b60546e91eeb542a0ee8cb96c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=88=E7=A5=A5?= Date: Tue, 6 Jan 2026 19:49:07 +0800 Subject: [PATCH] commit --- src/App.tsx | 101 ++++++++- src/ot/client.ts | 34 +++- src/ot/helpers.ts | 40 ++++ src/ot/op.ts | 102 +++++----- src/ot/server.ts | 17 +- src/ot/text-op.ts | 510 ---------------------------------------------- 6 files changed, 233 insertions(+), 571 deletions(-) create mode 100644 src/ot/helpers.ts delete mode 100644 src/ot/text-op.ts diff --git a/src/App.tsx b/src/App.tsx index df5e426..6496e99 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,7 +1,106 @@ +import { useEffect, useLayoutEffect, useRef, useState } from "react"; import "./App.css"; +import { Client } from "./ot/client"; +import { generateOperations } from "./ot/helpers"; +import { getDemoServerInstance } from "./ot/server"; + +function Editor({ name }: { name: string }) { + const clientRef = useRef(null); + const [doc, setDoc] = useState(""); + const prevDocRef = useRef(""); + const [enableSync, setEnableSync] = useState(true); + + // 初始化client和文档状态 + useLayoutEffect(() => { + if (!clientRef.current) { + clientRef.current = new Client(); + clientRef.current.name = name; + const initialDoc = clientRef.current.document || ""; + prevDocRef.current = initialDoc; + setDoc(initialDoc); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useEffect(() => { + if (!clientRef.current) return; + // 定期同步client的文档状态到UI + const timer = setInterval(() => { + const currentDoc = clientRef.current!.document || ""; + if (currentDoc !== prevDocRef.current) { + setDoc(currentDoc); + prevDocRef.current = currentDoc; + } + }, 100); + return () => clearInterval(timer); + }, []); + + const handleChange = (e: React.ChangeEvent) => { + if (!clientRef.current) return; + const newValue = e.target.value; + // 使用client当前文档状态作为旧值 + const oldValue = clientRef.current.document || ""; + if (newValue !== oldValue) { + // 生成操作集合 + const operations = generateOperations(oldValue, newValue); + // 按顺序应用操作 + operations.forEach((op) => { + clientRef.current!.applyClient(op); + }); + } + }; + + const handleToggleSync = () => { + const newValue = !enableSync; + setEnableSync(newValue); + if (clientRef.current) { + clientRef.current.setEnableSync(newValue); + } + }; + + return ( +
+
+

Document:

+ +
+