diff --git a/YJS_CRDT_WIP.md b/YJS_CRDT_WIP.md index 38a99c6b..3d24ba0d 100644 --- a/YJS_CRDT_WIP.md +++ b/YJS_CRDT_WIP.md @@ -13,8 +13,9 @@ The Y.js based collaborative editing support is under construction. Must-haves -- UI: Manage focus etc. Now selection goes directly to text edit mode, even in multiselect. Make test stricter on that the initial text is shown and correctly replaced. Select all text on click. +- UI: Copy-pasting items should copy CRDT as well - Undo buffer integration +- Mobile check - Manage session on the server side: terminate YJS sockets when websocket session is terminated - Performance testing - Playwright tests diff --git a/frontend/src/board/CollaborativeTextView.tsx b/frontend/src/board/CollaborativeTextView.tsx index daca865f..25e79720 100644 --- a/frontend/src/board/CollaborativeTextView.tsx +++ b/frontend/src/board/CollaborativeTextView.tsx @@ -36,21 +36,6 @@ export function CollaborativeTextView({ const fontSize = L.view(item, (i) => `${i.fontSize ? i.fontSize : 1}em`) const color = L.view(item, getItemBackground, contrastingColor) - const setEditing = (e: boolean) => { - if (toolController.tool.get() === "connect") return // Don't switch to editing in middle of connecting - dispatch({ action: "item.front", boardId: board.get().id, itemIds: [id] }) - focus.set( - e - ? { status: "editing", itemId: id } - : { status: "selected", itemIds: new Set([id]), connectionIds: emptySet() }, - ) - } - - const editingThis = L.atom( - L.view(itemFocus, (f) => f === "editing" || f === "selected"), - setEditing, - ) - const quillEditor = L.atom(null) function initQuill(el: HTMLElement) { @@ -71,10 +56,31 @@ export function CollaborativeTextView({ quillEditor.set(quill) } - L.combine(quillEditor, editingThis, (q, e) => (e ? q : null)).forEach((q) => { - q && q.focus() + const editingThis = L.view(itemFocus, (f) => f === "editing") + + editingThis.forEach((e) => { + const q = quillEditor.get() + if (q) { + if (e) { + if (item.get().type === "container") { + // For containers, select all text for quick rename + q.setSelection(0, 1000000) + } + } else { + // Clear text selecting when not editing + q.setSelection(null as any) + } + } }) + function handleClick() { + if (itemFocus.get() === "selected") { + focus.set({ status: "editing", itemId: id }) + } + } + + const pointerEvents = L.view(itemFocus, (f) => (f === "editing" || f === "selected" ? "auto" : "none")) + return (
e.stopPropagation()} onKeyPress={(e) => e.stopPropagation()} onDoubleClick={(e) => e.stopPropagation()} + onClick={handleClick} >
diff --git a/frontend/src/style/board.scss b/frontend/src/style/board.scss index e86eb166..5d17adb4 100644 --- a/frontend/src/style/board.scss +++ b/frontend/src/style/board.scss @@ -165,10 +165,12 @@ } > .quill-wrapper { - width: "100%"; - height: "100%"; + width: 100%; + height: 100%; padding: 0; > .quill-editor { + width: 100%; + height: 100%; > .ql-editor { padding: 0.1em; } diff --git a/playwright/src/pages/BoardPage.ts b/playwright/src/pages/BoardPage.ts index 3fb62291..36797894 100644 --- a/playwright/src/pages/BoardPage.ts +++ b/playwright/src/pages/BoardPage.ts @@ -108,20 +108,27 @@ export function BoardPage(page: Page) { await page.keyboard.type(`${text}`) await page.keyboard.press("Escape") await expect(this.getNote(text)).toBeVisible() - return this.getNote(text) + const result = this.getNote(text) + await expect(result).toHaveText(text) + return result }, async createText(x: number, y: number, text: string) { await createNew(this.newTextOnPalette, x, y) - await expect(this.getText("")).toBeVisible() + await this.getText("HELLO").locator(".text").dblclick() await page.keyboard.type(`${text}`) await expect(this.getText(text)).toBeVisible() - return this.getText(text) + const result = this.getText(text) + await expect(result).toHaveText(text) + return result }, async createArea(x: number, y: number, text: string) { await createNew(this.newContainerOnPalette, x, y) + await this.getArea("Unnamed area").locator(".text").dblclick() await page.keyboard.type(`${text}`) await expect(this.getArea(text)).toBeVisible() - return this.getArea(text) + const result = this.getArea(text) + await expect(result).toHaveText(text) + return result }, async dragItem(item: Locator, x: number, y: number) { await dragElementOnBoard(item, x, y)