From a94ef1fabca9a8bad0b165cdd41cb1bcb02cd628 Mon Sep 17 00:00:00 2001 From: eti Date: Wed, 23 Sep 2026 03:29:42 +0200 Subject: [PATCH] web/ui: swap the editor preview in once rendered and gate it on content Signed-off-by: eti --- .../ui/MarkdownEditor.stories.svelte | 6 +- .../lib/components/ui/MarkdownEditor.svelte | 71 +++++++++---------- 2 files changed, 40 insertions(+), 37 deletions(-) diff --git a/web/src/lib/components/ui/MarkdownEditor.stories.svelte b/web/src/lib/components/ui/MarkdownEditor.stories.svelte index 96142e6cf..bf2c2d96b 100644 --- a/web/src/lib/components/ui/MarkdownEditor.stories.svelte +++ b/web/src/lib/components/ui/MarkdownEditor.stories.svelte @@ -54,8 +54,12 @@ const height = field.offsetHeight; const toggle = canvas.getByRole("switch", { name: "Preview" }); await userEvent.click(toggle); - await expect(textarea).not.toBeVisible(); const pane = field.nextElementSibling as HTMLElement; + await expect(textarea.checkVisibility() || pane.querySelector(".markup") !== null).toBe( + true + ); + await expect(pane).not.toHaveTextContent(/rendering/i); + await waitFor(() => expect(textarea).not.toBeVisible()); await expect(pane.offsetHeight).toBe(height); await expect(field.parentElement!.offsetHeight).toBe(height); await waitFor(() => expect(pane.scrollHeight).toBeGreaterThan(pane.clientHeight)); diff --git a/web/src/lib/components/ui/MarkdownEditor.svelte b/web/src/lib/components/ui/MarkdownEditor.svelte index b869232b7..a9bc4f78c 100644 --- a/web/src/lib/components/ui/MarkdownEditor.svelte +++ b/web/src/lib/components/ui/MarkdownEditor.svelte @@ -19,7 +19,6 @@ import Button from "$lib/components/ui/Button.svelte"; import Dropdown from "$lib/components/ui/Dropdown.svelte"; import DropdownItem from "$lib/components/ui/DropdownItem.svelte"; - import EmptyState from "$lib/components/ui/EmptyState.svelte"; import Kbd from "$lib/components/ui/Kbd.svelte"; import MarkdownTypeahead from "$lib/components/ui/MarkdownTypeahead.svelte"; import Pending from "$lib/components/ui/Pending.svelte"; @@ -133,8 +132,10 @@ if (autofocus) textareaEl?.focus(); }); + const hasContent = $derived(value.trim() !== ""); + const rendered = $derived( - preview && value.trim() + preview && hasContent ? renderMarkup(value, { ...markup, sourceLines: true }).then((html) => html ?? "") : null ); @@ -199,12 +200,21 @@ }); }); - const alignPreview: Attachment = () => { - untrack(() => { - if (!pane) return; - scrollPreviewToLine(pane, value, entryLine); - alignedScroll = pane.scrollTop; - }); + const alignPreview: Attachment = (node) => { + let frame = 0; + const align = () => { + if (!node.isConnected || !pane) { + frame = requestAnimationFrame(align); + return; + } + untrack(() => { + if (!pane) return; + scrollPreviewToLine(pane, value, entryLine); + alignedScroll = pane.scrollTop; + }); + }; + align(); + return () => cancelAnimationFrame(frame); }; const handlePreviewScroll = () => { @@ -297,11 +307,15 @@