a tool for shared writing and social publishing
at main 3.2 kB view raw
1import { 2 AsyncValueAutosizeTextarea, 3 AutosizeTextareaProps, 4} from "components/utils/AutosizeTextarea"; 5import { BlockProps } from "./Block"; 6import { getCoordinatesInTextarea } from "src/utils/getCoordinatesInTextarea"; 7import { focusBlock } from "src/utils/focusBlock"; 8import { generateKeyBetween } from "fractional-indexing"; 9import { v7 } from "uuid"; 10import { elementId } from "src/utils/elementId"; 11import { Replicache } from "replicache"; 12import { ReplicacheMutators } from "src/replicache"; 13 14type BaseTextareaBlockProps = AutosizeTextareaProps & { 15 block: Pick< 16 BlockProps, 17 "previousBlock" | "nextBlock" | "parent" | "position" | "nextPosition" 18 >; 19 rep?: Replicache<ReplicacheMutators> | null; 20 permissionSet?: string; 21}; 22 23export function BaseTextareaBlock(props: BaseTextareaBlockProps) { 24 let { block, rep, permissionSet, ...passDownProps } = props; 25 return ( 26 <AsyncValueAutosizeTextarea 27 {...passDownProps} 28 noWrap 29 onKeyDown={(e) => { 30 // Shift-Enter or Ctrl-Enter: create new text block below and focus it 31 if ( 32 (e.shiftKey || e.ctrlKey || e.metaKey) && 33 e.key === "Enter" && 34 rep && 35 permissionSet 36 ) { 37 e.preventDefault(); 38 let newEntityID = v7(); 39 rep.mutate.addBlock({ 40 parent: block.parent, 41 type: "text", 42 factID: v7(), 43 permission_set: permissionSet, 44 position: generateKeyBetween( 45 block.position, 46 block.nextPosition || null, 47 ), 48 newEntityID, 49 }); 50 51 setTimeout(() => { 52 document.getElementById(elementId.block(newEntityID).text)?.focus(); 53 }, 10); 54 return true; 55 } 56 57 if (e.key === "ArrowUp") { 58 let selection = e.currentTarget.selectionStart; 59 60 let lastLineBeforeCursor = e.currentTarget.value 61 .slice(0, selection) 62 .lastIndexOf("\n"); 63 if (lastLineBeforeCursor !== -1) return; 64 let block = props.block.previousBlock; 65 let coord = getCoordinatesInTextarea(e.currentTarget, selection); 66 if (block) { 67 focusBlock(block, { 68 left: coord.left + e.currentTarget.getBoundingClientRect().left, 69 type: "bottom", 70 }); 71 return true; 72 } 73 } 74 if (e.key === "ArrowDown") { 75 let selection = e.currentTarget.selectionStart; 76 77 let lastLine = e.currentTarget.value.lastIndexOf("\n"); 78 let lastLineBeforeCursor = e.currentTarget.value 79 .slice(0, selection) 80 .lastIndexOf("\n"); 81 if (lastLine !== lastLineBeforeCursor) return; 82 e.preventDefault(); 83 let block = props.block.nextBlock; 84 85 let coord = getCoordinatesInTextarea(e.currentTarget, selection); 86 console.log(coord); 87 if (block) { 88 focusBlock(block, { 89 left: coord.left + e.currentTarget.getBoundingClientRect().left, 90 type: "top", 91 }); 92 return true; 93 } 94 } 95 }} 96 /> 97 ); 98}