From 212fabd22c77d12e71530403eb6b5bbbdbef1ae3 Mon Sep 17 00:00:00 2001 From: celine Date: Thu, 5 Mar 2026 22:24:39 -0500 Subject: [PATCH] autofocus editor when footnote is selecter --- .../Blocks/TextBlock/mountProsemirror.ts | 9 ++-- components/Footnotes/FootnoteEditor.tsx | 42 ++++++++++--------- components/Footnotes/FootnotePopover.tsx | 24 +++++++---- components/Footnotes/usePageFootnotes.ts | 27 ++++++++---- 4 files changed, 65 insertions(+), 37 deletions(-) diff --git a/components/Blocks/TextBlock/mountProsemirror.ts b/components/Blocks/TextBlock/mountProsemirror.ts index f7b1e8e2..6a5af3c9 100644 --- a/components/Blocks/TextBlock/mountProsemirror.ts +++ b/components/Blocks/TextBlock/mountProsemirror.ts @@ -90,9 +90,10 @@ export function useMountProsemirror({ let sup = supEl.closest(".footnote-ref") as HTMLElement | null; if (!sup) return; - // On mobile/tablet, show popover + // On mobile/tablet or canvas, show popover let isDesktop = window.matchMedia("(min-width: 1280px)").matches; - if (!isDesktop) { + let isCanvas = propsRef.current.pageType === "canvas"; + if (!isDesktop || isCanvas) { let store = useFootnotePopoverStore.getState(); if (store.activeFootnoteID === footnoteID) { store.close(); @@ -115,7 +116,9 @@ export function useMountProsemirror({ } if (editor) { editor.scrollIntoView({ behavior: "smooth", block: "nearest" }); - let pm = editor.querySelector(".ProseMirror") as HTMLElement | null; + let pm = editor.querySelector( + ".ProseMirror", + ) as HTMLElement | null; if (pm) { setTimeout(() => pm!.focus(), 100); } diff --git a/components/Footnotes/FootnoteEditor.tsx b/components/Footnotes/FootnoteEditor.tsx index da27cb7f..a2a2d30a 100644 --- a/components/Footnotes/FootnoteEditor.tsx +++ b/components/Footnotes/FootnoteEditor.tsx @@ -187,27 +187,29 @@ export function FootnoteEditor(props: { ]); return ( - { - let ref = document.querySelector( - `.footnote-ref[data-footnote-id="${props.footnoteEntityID}"]`, - ); - if (ref) { - ref.scrollIntoView({ behavior: "smooth", block: "center" }); +
+ { + let pm = mountRef.current?.querySelector( + ".ProseMirror", + ) as HTMLElement | null; + if (pm) { + pm.focus(); + } + }} + trailing={ + props.editable && props.onDelete ? ( + + ) : undefined } - }} - trailing={ - props.editable && props.onDelete ? ( - - ) : undefined - } - > -
- + > +
+ +
); } diff --git a/components/Footnotes/FootnotePopover.tsx b/components/Footnotes/FootnotePopover.tsx index 8d94b83e..d0316fdd 100644 --- a/components/Footnotes/FootnotePopover.tsx +++ b/components/Footnotes/FootnotePopover.tsx @@ -29,18 +29,24 @@ export function FootnotePopover() { let { permissions } = useEntitySetContext(); let rep = useReplicache(); let popoverRef = useRef(null); - let [position, setPosition] = useState<{ top: number; left: number; arrowLeft: number } | null>(null); - - let footnote = footnotes.find((fn) => fn.footnoteEntityID === activeFootnoteID); + let [position, setPosition] = useState<{ + top: number; + left: number; + arrowLeft: number; + } | null>(null); + + let footnote = footnotes.find( + (fn) => fn.footnoteEntityID === activeFootnoteID, + ); // Compute the displayed index from DOM order (matching CSS counters) // rather than the data model order, which may differ if footnotes // were inserted out of order within a block. let displayIndex = useMemo(() => { if (!anchorElement || !footnote) return footnote?.index ?? 0; - let container = anchorElement.closest('.postPageContent'); + let container = anchorElement.closest(".postPageContent"); if (!container) return footnote.index; - let allRefs = Array.from(container.querySelectorAll('.footnote-ref')); + let allRefs = Array.from(container.querySelectorAll(".footnote-ref")); let pos = allRefs.indexOf(anchorElement); return pos >= 0 ? pos + 1 : footnote.index; }, [anchorElement, footnote]); @@ -58,7 +64,10 @@ export function FootnotePopover() { // Clamp horizontal position let padding = 12; - left = Math.max(padding, Math.min(left, window.innerWidth - popoverWidth - padding)); + left = Math.max( + padding, + Math.min(left, window.innerWidth - popoverWidth - padding), + ); // Arrow position relative to popover let arrowLeft = anchorRect.left + anchorRect.width / 2 - left; @@ -113,7 +122,7 @@ export function FootnotePopover() { return (
{ diff --git a/components/Footnotes/usePageFootnotes.ts b/components/Footnotes/usePageFootnotes.ts index 164c517c..b2889a9a 100644 --- a/components/Footnotes/usePageFootnotes.ts +++ b/components/Footnotes/usePageFootnotes.ts @@ -14,24 +14,35 @@ export function usePageFootnotes(pageID: string) { rep?.rep, async (tx) => { let scan = scanIndex(tx); - let blocks = await scan.eav(pageID, "card/block"); - let sorted = blocks.toSorted((a, b) => - a.data.position > b.data.position ? 1 : -1, - ); + let cardBlocks = await scan.eav(pageID, "card/block"); + let canvasBlocks = await scan.eav(pageID, "canvas/block"); + + let sortedCardBlocks = cardBlocks + .map((b) => ({ value: b.data.value, position: b.data.position })) + .toSorted((a, b) => (a.position > b.position ? 1 : -1)); + + let sortedCanvasBlocks = canvasBlocks + .map((b) => ({ value: b.data.value, position: b.data.position })) + .toSorted((a, b) => { + if (a.position.y === b.position.y) return a.position.x - b.position.x; + return a.position.y - b.position.y; + }); + + let sorted = [...sortedCardBlocks, ...sortedCanvasBlocks]; let footnotes: FootnoteInfo[] = []; let indexMap: Record = {}; let idx = 1; for (let block of sorted) { - let blockFootnotes = await scan.eav(block.data.value, "block/footnote"); + let blockFootnotes = await scan.eav(block.value, "block/footnote"); let sortedFootnotes = blockFootnotes.toSorted((a, b) => a.data.position > b.data.position ? 1 : -1, ); for (let fn of sortedFootnotes) { footnotes.push({ footnoteEntityID: fn.data.value, - blockID: block.data.value, + blockID: block.value, index: idx, }); indexMap[fn.data.value] = idx; @@ -44,5 +55,7 @@ export function usePageFootnotes(pageID: string) { { dependencies: [pageID] }, ); - return data || { pageID, footnotes: [], indexMap: {} as Record }; + return ( + data || { pageID, footnotes: [], indexMap: {} as Record } + ); } -- 2.51.2