Something went wrong. Try again.
a tool for shared writing and social publishing
Something went wrong. Try again.
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132import { NodeSelection, TextSelection } from "prosemirror-state";import { useUIState } from "src/useUIState";import { Block } from "components/Blocks/Block";import { elementId } from "src/utils/elementId";
import { useEditorStates } from "src/state/useEditorState";import { scrollIntoViewIfNeeded } from "./scrollIntoViewIfNeeded";import { getPosAtCoordinates } from "./getCoordinatesInTextarea";import { flushSync } from "react-dom";
export function focusBlock( block: Pick<Block, "type" | "value" | "parent">, position: Position,) { // focus the block flushSync(() => { useUIState.getState().setSelectedBlock(block); useUIState.getState().setFocusedBlock({ entityType: "block", entityID: block.value, parent: block.parent, }); }); scrollIntoViewIfNeeded( document.getElementById(elementId.block(block.value).container), false, ); if (block.type === "math" || block.type === "code") { let el = document.getElementById( elementId.block(block.value).input, ) as HTMLTextAreaElement; let pos; if (position.type === "start") { pos = { offset: 0 }; }
if (position.type === "end") { pos = { offset: el.textContent?.length || 0 }; } if (position.type === "top" || position.type === "bottom") { let inputRect = el?.getBoundingClientRect(); let left = Math.max(position.left, inputRect?.left || 0); let top = position.type === "top" ? (inputRect?.top || 0) + 10 : (inputRect?.bottom || 0) - 10; pos = getPosAtCoordinates(left, top); }
if (pos?.offset !== undefined) { // trying to focus the block in a subpage causes the page to flash and scroll back to the parent page. // idk how to fix so i'm giving up -- celine // el?.focus(); requestAnimationFrame(() => { el?.setSelectionRange(pos.offset, pos.offset); }); } }
// if its not a text block, that's all we need to do if ( block.type !== "text" && block.type !== "heading" && block.type !== "blockquote" ) { return true; } // if its a text block, and not an empty block that is last on the page, // focus the editor using the mouse position if needed let nextBlockID = block.value; let nextBlock = useEditorStates.getState().editorStates[nextBlockID]; if (!nextBlock || !nextBlock.view) return; let nextBlockViewClientRect = nextBlock.view.dom.getBoundingClientRect(); let tr = nextBlock.editor.tr; let pos: { pos: number } | null = null; switch (position.type) { case "end": { pos = { pos: tr.doc.content.size - 1 }; break; } case "start": { pos = { pos: 1 }; break; } case "top": { pos = nextBlock.view.posAtCoords({ top: nextBlockViewClientRect.top + 12, left: Math.max(position.left, nextBlockViewClientRect.left), }); break; } case "bottom": { pos = nextBlock.view.posAtCoords({ top: nextBlockViewClientRect.bottom - 12, left: Math.max(position.left, nextBlockViewClientRect.left), }); break; } case "coord": { pos = nextBlock.view.posAtCoords({ top: position.top, left: position.left, }); break; } }
nextBlock.view.dispatch( tr.setSelection(TextSelection.create(tr.doc, pos?.pos || 1)), ); nextBlock.view.focus();}
type Position = | { type: "start"; } | { type: "end" } | { type: "coord"; top: number; left: number; } | { type: "top"; left: number; } | { type: "bottom"; left: number; };