From c4eb444a0418b41a94504c62f5aefc8f344948a2 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 2 Nov 2026 11:09:51 +0900 Subject: [PATCH] refac --- .../ContentRenderer/FloatingButtons.svelte | 21 ++--- src/lib/components/chat/FileNav.svelte | 17 ++-- .../chat/Messages/ContentRenderer.svelte | 87 ++++++++----------- .../components/comments/CommentsHost.svelte | 25 ++++-- src/lib/components/comments/anchors.ts | 2 +- src/lib/utils/selectionToolbar.ts | 32 +++++++ 6 files changed, 108 insertions(+), 76 deletions(-) create mode 100644 src/lib/utils/selectionToolbar.ts diff --git a/src/lib/components/chat/ContentRenderer/FloatingButtons.svelte b/src/lib/components/chat/ContentRenderer/FloatingButtons.svelte index e919bc57d4..a2119b2152 100644 --- a/src/lib/components/chat/ContentRenderer/FloatingButtons.svelte +++ b/src/lib/components/chat/ContentRenderer/FloatingButtons.svelte @@ -1,5 +1,6 @@ - -
{#if output?.length} ('i18n'); let selection: ReturnType = null; let account: string | null = null; @@ -23,13 +24,15 @@ !$page.url.pathname.startsWith('/s/') ); let preparing = false; + let selectionButton: HTMLButtonElement; + let usingSelectionButton = false; $: if (($user?.id ?? null) !== account) { account = $user?.id ?? null; commentSelectionDraft.set(null); selection = null; } const select = () => { - if (!preparing) selection = commentsAllowed ? selectedComment() : null; + if (!preparing && !usingSelectionButton) selection = commentsAllowed ? selectedComment() : null; }; const commentSelection = async () => { const selected = selection; @@ -50,15 +53,21 @@ } }; onMount(() => { - document.addEventListener('mouseup', select); - document.addEventListener('keyup', select); + document.addEventListener('selectionchange', select); return () => { - document.removeEventListener('mouseup', select); - document.removeEventListener('keyup', select); + document.removeEventListener('selectionchange', select); }; }); + { + usingSelectionButton = !!selectionButton?.contains(event.target as Node); + }} + on:pointerdown|capture={(event) => { + usingSelectionButton = !!selectionButton?.contains(event.target as Node); + }} +/> { if (event.key === 'Escape') { @@ -70,15 +79,15 @@ selection = null; } }} - on:scroll|capture={() => (selection = null)} /> {#if commentsAllowed} {#key account}{/key} {#if selection && !selection.options.toolbar_id} {}; + const update = (range: Range | null) => { + cleanup(); + if (!range) return; + let active = true; + const reference = { + getBoundingClientRect: () => range.getBoundingClientRect(), + contextElement: range.commonAncestorContainer.parentElement ?? undefined + }; + const stop = autoUpdate(reference, node, () => { + void computePosition(reference, node, { + strategy: 'fixed', + placement: 'bottom-start', + middleware: [offset(12), flip(), shift({ padding: 8 })] + }).then(({ x, y }) => { + if (!active) return; + node.style.left = `${x}px`; + node.style.top = `${y}px`; + }); + }); + cleanup = () => { + active = false; + stop(); + }; + }; + update(range); + return { update, destroy: () => cleanup() }; +}