From b04478fdc71d8122ce26081ed0323641fd21bba7 Mon Sep 17 00:00:00 2001 From: Jared Pereira Date: Fri, 28 Jun 2024 23:54:43 +0000 Subject: [PATCH] don't render block overlay if not ios --- components/Blocks.tsx | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------- components/TextBlock/index.tsx | 8 ++++++-- src/state/useEditorState.ts | 31 +++++++++++++++++++++++++++++++ src/utils/focusBlock.ts | 0 src/utils/isVisible.ts | 18 ++++++++++++++++++ 5 file(s) changed, 119 insertion(s)(+), 24 deletion(s)(-) diff --git a/components/Blocks.tsx b/components/Blocks.tsx --- a/components/Blocks.tsx +++ b/components/Blocks.tsx @@ -49,7 +49,7 @@ ?.focus(); }, 10); } else { - focusBlock(lastBlock, "end", "bottom"); + focusBlock(lastBlock, { type: "end" }); } } }} @@ -68,6 +68,7 @@ ); })} +
); } @@ -147,14 +148,20 @@ e.preventDefault(); let block = props.nextBlock; if (block && useUIState.getState().selectedBlock.length <= 1) - focusBlock(block, useEditorStates.getState().lastXPosition, "top"); + focusBlock(block, { + type: "top", + left: useEditorStates.getState().lastXPosition, + }); if (!block) return; } if (e.key === "ArrowUp") { e.preventDefault(); let block = props.previousBlock; if (block && useUIState.getState().selectedBlock.length <= 1) { - focusBlock(block, useEditorStates.getState().lastXPosition, "bottom"); + focusBlock(block, { + type: "bottom", + left: useEditorStates.getState().lastXPosition, + }); } if (!block) return; } @@ -164,7 +171,7 @@ r.mutate.removeBlock({ blockEntity: props.entityID }); useUIState.getState().closeCard(props.entityID); let block = props.previousBlock; - if (block) focusBlock(block, "end", "bottom"); + if (block) focusBlock(block, { type: "end" }); } if (e.key === "Enter") { let newEntityID = crypto.randomUUID(); @@ -260,11 +267,25 @@ ); } -export function focusBlock( - block: Block, - left: number | "end" | "start", - top: "top" | "bottom", -) { +type Position = + | { + type: "start"; + } + | { type: "end" } + | { + type: "coord"; + top: number; + left: number; + } + | { + type: "top"; + left: number; + } + | { + type: "bottom"; + left: number; + }; +export function focusBlock(block: Block, position: Position) { if (block.type !== "text" && block.type !== "heading") { useUIState.getState().setSelectedBlock(block); return true; @@ -272,21 +293,42 @@ let nextBlockID = block.value; let nextBlock = useEditorStates.getState().editorStates[nextBlockID]; if (!nextBlock || !nextBlock.view) return; - nextBlock.view.focus(); + nextBlock.view.dom.focus({ preventScroll: true }); let nextBlockViewClientRect = nextBlock.view.dom.getBoundingClientRect(); let tr = nextBlock.editor.tr; - let pos = - left === "end" - ? { pos: tr.doc.content.size - 1 } - : left === "start" - ? { pos: 1 } - : nextBlock.view.posAtCoords({ - top: - top === "top" - ? nextBlockViewClientRect.top + 12 - : nextBlockViewClientRect.bottom - 12, - left, - }); + 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: position.left, + }); + break; + } + case "bottom": { + pos = nextBlock.view.posAtCoords({ + top: nextBlockViewClientRect.bottom - 12, + left: position.left, + }); + break; + } + case "coord": { + pos = nextBlock.view.posAtCoords({ + top: position.top, + left: position.left, + }); + break; + } + } + let newState = nextBlock.editor.apply( tr.setSelection(TextSelection.create(tr.doc, pos?.pos || 0)), ); diff --git a/components/TextBlock/index.tsx b/components/TextBlock/index.tsx --- a/components/TextBlock/index.tsx +++ b/components/TextBlock/index.tsx @@ -60,14 +60,18 @@ let selected = useUIState((s) => s.selectedBlock.find((b) => b.value === props.entityID), ); - if (selected) return null; + let [initialRender, setInitialRender] = useState(true); + useEffect(() => { + setInitialRender(false); + }, []); + if (selected || initialRender || !isIOS()) return null; return (
{ e.preventDefault(); let target = e.target; + console.log("what"); focusBlock(props, { type: "coord", top: e.clientY, diff --git a/src/state/useEditorState.ts b/src/state/useEditorState.ts new file mode 100644 --- /dev/null +++ b/src/state/useEditorState.ts @@ -0,0 +1,31 @@ +import { create } from "zustand"; +import { EditorState } from "prosemirror-state"; +import { EditorView } from "prosemirror-view"; +export let useEditorStates = create(() => ({ + lastXPosition: 0, + editorStates: {} as { + [entity: string]: + | { + editor: InstanceType; + view?: InstanceType; + } + | undefined; + }, +})); + +export const setEditorState = ( + entityID: string, + s: { + editor: InstanceType; + }, +) => { + useEditorStates.setState((oldState) => { + let existingState = oldState.editorStates[entityID]; + return { + editorStates: { + ...oldState.editorStates, + [entityID]: { ...existingState, ...s }, + }, + }; + }); +}; diff --git a/src/utils/focusBlock.ts b/src/utils/focusBlock.ts new file mode 100644 --- /dev/null +++ b/src/utils/focusBlock.ts diff --git a/src/utils/isVisible.ts b/src/utils/isVisible.ts new file mode 100644 --- /dev/null +++ b/src/utils/isVisible.ts @@ -0,0 +1,18 @@ +export async function isVisible(el: Element) { + return new Promise((resolve) => { + const observer = new IntersectionObserver( + (entries, observer) => { + entries.forEach((entry) => { + resolve(entry.isIntersecting); + observer.unobserve(entry.target); + }); + }, + { + root: null, // Use the viewport as the root + threshold: 0.1, // Trigger when 10% of the element is visible + }, + ); + + observer.observe(el); + }); +} -- tangled.sh