a tool for shared writing and social publishing

share getSortedSelection function b/w selection and toolbar

+57 -70
+55 -49
components/SelectionManager.tsx
··· 1 1 "use client"; 2 2 import { useEffect, useRef, useState } from "react"; 3 3 import { create } from "zustand"; 4 - import { useReplicache } from "src/replicache"; 4 + import { ReplicacheMutators, useReplicache } from "src/replicache"; 5 5 import { useUIState } from "src/useUIState"; 6 6 import { scanIndex } from "src/replicache/utils"; 7 7 import { focusBlock } from "src/utils/focusBlock"; ··· 18 18 import { isTextBlock } from "src/utils/isTextBlock"; 19 19 import { useIsMobile } from "src/hooks/isMobile"; 20 20 import { deleteBlock } from "./Blocks/DeleteBlock"; 21 + import { Replicache } from "replicache"; 21 22 export const useSelectingMouse = create(() => ({ 22 23 start: null as null | string, 23 24 })); ··· 31 32 let { rep, undoManager } = useReplicache(); 32 33 let isMobile = useIsMobile(); 33 34 useEffect(() => { 34 - if (!entity_set.permissions.write) return; 35 + if (!entity_set.permissions.write || !rep) return; 35 36 if (isMobile) return; 36 - const getSortedSelection = async () => { 37 - let selectedBlocks = useUIState.getState().selectedBlocks; 38 - let foldedBlocks = useUIState.getState().foldedBlocks; 39 - if (!selectedBlocks[0]) return [[], []]; 40 - let siblings = 41 - (await rep?.query((tx) => 42 - getBlocksWithType(tx, selectedBlocks[0].parent), 43 - )) || []; 44 - let sortedBlocks = siblings.filter((s) => { 45 - let selected = selectedBlocks.find((sb) => sb.value === s.value); 46 - return selected; 47 - }); 48 - let sortedBlocksWithChildren = siblings.filter((s) => { 49 - let selected = selectedBlocks.find((sb) => sb.value === s.value); 50 - if (s.listData && !selected) { 51 - //Select the children of folded list blocks (in order to copy them) 52 - return s.listData.path.find( 53 - (p) => 54 - selectedBlocks.find((sb) => sb.value === p.entity) && 55 - foldedBlocks.includes(p.entity), 56 - ); 57 - } 58 - return selected; 59 - }); 60 - return [ 61 - sortedBlocks, 62 - siblings.filter( 63 - (f) => 64 - !f.listData || 65 - !f.listData.path.find( 66 - (p) => foldedBlocks.includes(p.entity) && p.entity !== f.value, 67 - ), 68 - ), 69 - sortedBlocksWithChildren, 70 - ]; 71 - }; 37 + const getSortedSelectionBound = getSortedSelection.bind(null, rep); 72 38 let removeListener = addShortcut( 73 39 [ 74 40 { ··· 114 80 altKey: true, 115 81 key: ["l", "¬"], 116 82 handler: async () => { 117 - let [sortedBlocks, siblings] = await getSortedSelection(); 83 + let [sortedBlocks, siblings] = await getSortedSelectionBound(); 118 84 for (let block of sortedBlocks) { 119 85 if (!block.listData) { 120 86 await rep?.mutate.assertFact({ ··· 133 99 shift: true, 134 100 key: ["ArrowDown", "J"], 135 101 handler: async () => { 136 - let [sortedBlocks, siblings] = await getSortedSelection(); 102 + let [sortedBlocks, siblings] = await getSortedSelectionBound(); 137 103 let block = sortedBlocks[0]; 138 104 let nextBlock = siblings 139 105 .slice(siblings.findIndex((s) => s.value === block.value) + 1) ··· 169 135 shift: true, 170 136 key: ["ArrowUp", "K"], 171 137 handler: async () => { 172 - let [sortedBlocks, siblings] = await getSortedSelection(); 138 + let [sortedBlocks, siblings] = await getSortedSelectionBound(); 173 139 let block = sortedBlocks[0]; 174 140 let previousBlock = 175 141 siblings?.[ ··· 216 182 shift: true, 217 183 key: "Enter", 218 184 handler: async () => { 219 - let [sortedBlocks, siblings] = await getSortedSelection(); 185 + let [sortedBlocks, siblings] = await getSortedSelectionBound(); 220 186 if (!sortedBlocks[0].listData) return; 221 187 useUIState.getState().toggleFold(sortedBlocks[0].value); 222 188 }, ··· 233 199 if (!entity_set.permissions.write) return; 234 200 if (moreThanOneSelected) { 235 201 e.preventDefault(); 236 - let [sortedBlocks, siblings] = await getSortedSelection(); 202 + let [sortedBlocks, siblings] = await getSortedSelectionBound(); 237 203 let selectedBlocks = useUIState.getState().selectedBlocks; 238 204 let firstBlock = sortedBlocks[0]; 239 205 ··· 274 240 deleteBlocks(); 275 241 } 276 242 if (e.key === "ArrowUp") { 277 - let [sortedBlocks, siblings] = await getSortedSelection(); 243 + let [sortedBlocks, siblings] = await getSortedSelectionBound(); 278 244 let focusedBlock = useUIState.getState().focusedEntity; 279 245 if (!e.shiftKey && !e.ctrlKey) { 280 246 if (e.defaultPrevented) return; ··· 346 312 } 347 313 } 348 314 if (e.key === "ArrowLeft") { 349 - let [sortedSelection, siblings] = await getSortedSelection(); 315 + let [sortedSelection, siblings] = await getSortedSelectionBound(); 350 316 if (sortedSelection.length === 1) return; 351 317 let firstBlock = sortedSelection[0]; 352 318 if (!firstBlock) return; ··· 361 327 ); 362 328 } 363 329 if (e.key === "ArrowRight") { 364 - let [sortedSelection, siblings] = await getSortedSelection(); 330 + let [sortedSelection, siblings] = await getSortedSelectionBound(); 365 331 if (sortedSelection.length === 1) return; 366 332 let lastBlock = sortedSelection[sortedSelection.length - 1]; 367 333 if (!lastBlock) return; ··· 376 342 ); 377 343 } 378 344 if (e.key === "Tab") { 379 - let [sortedSelection, siblings] = await getSortedSelection(); 345 + let [sortedSelection, siblings] = await getSortedSelectionBound(); 380 346 if (sortedSelection.length <= 1) return; 381 347 e.preventDefault(); 382 348 if (e.shiftKey) { ··· 424 390 } 425 391 } 426 392 if (e.key === "ArrowDown") { 427 - let [sortedSelection, siblings] = await getSortedSelection(); 393 + let [sortedSelection, siblings] = await getSortedSelectionBound(); 428 394 let focusedBlock = useUIState.getState().focusedEntity; 429 395 if (!e.shiftKey) { 430 396 if (sortedSelection.length === 1) return; ··· 497 463 } 498 464 if ((e.key === "c" || e.key === "x") && (e.metaKey || e.ctrlKey)) { 499 465 if (!rep) return; 500 - let [, , selectionWithFoldedChildren] = await getSortedSelection(); 466 + let [, , selectionWithFoldedChildren] = 467 + await getSortedSelectionBound(); 501 468 if (!selectionWithFoldedChildren) return; 502 469 let el = document.activeElement as HTMLElement; 503 470 if ( ··· 657 624 } 658 625 return null; 659 626 } 627 + 628 + export const getSortedSelection = async ( 629 + rep: Replicache<ReplicacheMutators>, 630 + ) => { 631 + let selectedBlocks = useUIState.getState().selectedBlocks; 632 + let foldedBlocks = useUIState.getState().foldedBlocks; 633 + if (!selectedBlocks[0]) return [[], []]; 634 + let siblings = 635 + (await rep?.query((tx) => 636 + getBlocksWithType(tx, selectedBlocks[0].parent), 637 + )) || []; 638 + let sortedBlocks = siblings.filter((s) => { 639 + let selected = selectedBlocks.find((sb) => sb.value === s.value); 640 + return selected; 641 + }); 642 + let sortedBlocksWithChildren = siblings.filter((s) => { 643 + let selected = selectedBlocks.find((sb) => sb.value === s.value); 644 + if (s.listData && !selected) { 645 + //Select the children of folded list blocks (in order to copy them) 646 + return s.listData.path.find( 647 + (p) => 648 + selectedBlocks.find((sb) => sb.value === p.entity) && 649 + foldedBlocks.includes(p.entity), 650 + ); 651 + } 652 + return selected; 653 + }); 654 + return [ 655 + sortedBlocks, 656 + siblings.filter( 657 + (f) => 658 + !f.listData || 659 + !f.listData.path.find( 660 + (p) => foldedBlocks.includes(p.entity) && p.entity !== f.value, 661 + ), 662 + ), 663 + sortedBlocksWithChildren, 664 + ]; 665 + };
+2 -21
components/Toolbar/MultiSelectToolbar.tsx
··· 8 8 import { LockBlockButton } from "./LockBlockButton"; 9 9 import { Props } from "components/Icons/Props"; 10 10 import { TextAlignmentButton } from "./TextAlignmentToolbar"; 11 + import { getSortedSelection } from "components/SelectionManager"; 11 12 12 13 export const MultiselectToolbar = (props: { 13 14 setToolbarState: ( ··· 19 20 20 21 const handleCopy = async (event: React.MouseEvent) => { 21 22 if (!rep) return; 22 - const sortedSelection = await getSortedSelection(rep); 23 + const [sortedSelection] = await getSortedSelection(rep); 23 24 await copySelection(rep, sortedSelection); 24 25 smoker({ 25 26 position: { x: event.clientX, y: event.clientY }, ··· 52 53 ); 53 54 }; 54 55 55 - // Helper function to get sorted selection 56 - async function getSortedSelection(rep: Replicache<ReplicacheMutators>) { 57 - const selectedBlocks = useUIState.getState().selectedBlocks; 58 - const foldedBlocks = useUIState.getState().foldedBlocks; 59 - const siblings = 60 - (await rep?.query((tx) => 61 - getBlocksWithType(tx, selectedBlocks[0].parent), 62 - )) || []; 63 - return siblings.filter((s) => { 64 - let selected = selectedBlocks.find((sb) => sb.value === s.value); 65 - if (s.listData && !selected) { 66 - //Select the children of folded list blocks 67 - return s.listData.path.find( 68 - (p) => 69 - selectedBlocks.find((sb) => sb.value === p.entity) && 70 - foldedBlocks.includes(p.entity), 71 - ); 72 - } 73 - }); 74 - } 75 56 const CopySmall = (props: Props) => { 76 57 return ( 77 58 <svg