diff --git a/components/SelectionManager.tsx b/components/SelectionManager.tsx index 7843b51c..c3db1e3a 100644 --- a/components/SelectionManager.tsx +++ b/components/SelectionManager.tsx @@ -10,7 +10,7 @@ import { useEntitySetContext } from "./EntitySetProvider"; import { getBlocksWithType } from "src/hooks/queries/useBlocks"; import { v7 } from "uuid"; import { indent, outdent, outdentFull } from "src/utils/list-operations"; -import { addShortcut } from "src/shortcuts"; +import { addShortcut, Shortcut } from "src/shortcuts"; import { htmlToMarkdown } from "src/htmlMarkdownParsers"; import { elementId } from "src/utils/elementId"; import { scrollIntoViewIfNeeded } from "src/utils/scrollIntoViewIfNeeded"; @@ -38,148 +38,159 @@ export function SelectionManager() { if (!entity_set.permissions.write || !rep) return; if (isMobile) return; const getSortedSelectionBound = getSortedSelection.bind(null, rep); - let removeListener = addShortcut( - [ - { - metaKey: true, - key: "ArrowUp", - handler: async () => { - let [firstBlock] = - (await rep?.query((tx) => - getBlocksWithType( - tx, - useUIState.getState().selectedBlocks[0].parent, - ), - )) || []; - if (firstBlock) focusBlock(firstBlock, { type: "start" }); - }, - }, - { - metaKey: true, - key: "ArrowDown", - handler: async () => { - let blocks = - (await rep?.query((tx) => - getBlocksWithType( - tx, - useUIState.getState().selectedBlocks[0].parent, - ), - )) || []; - let folded = useUIState.getState().foldedBlocks; - blocks = blocks.filter( - (f) => - !f.listData || - !f.listData.path.find( - (path) => - folded.includes(path.entity) && f.value !== path.entity, - ), - ); - let lastBlock = blocks[blocks.length - 1]; - if (lastBlock) focusBlock(lastBlock, { type: "end" }); - }, + let shortcuts: Shortcut[] = [ + { + metaKey: true, + key: "ArrowUp", + handler: async () => { + let [firstBlock] = + (await rep?.query((tx) => + getBlocksWithType( + tx, + useUIState.getState().selectedBlocks[0].parent, + ), + )) || []; + if (firstBlock) focusBlock(firstBlock, { type: "start" }); }, - { - metaKey: true, - altKey: true, - key: ["l", "¬"], - handler: async () => { - let [sortedBlocks, siblings] = await getSortedSelectionBound(); - for (let block of sortedBlocks) { - if (!block.listData) { - await rep?.mutate.assertFact({ - entity: block.value, - attribute: "block/is-list", - data: { type: "boolean", value: true }, - }); - } else { - outdentFull(block, rep); - } - } - }, + }, + { + metaKey: true, + key: "ArrowDown", + handler: async () => { + let blocks = + (await rep?.query((tx) => + getBlocksWithType( + tx, + useUIState.getState().selectedBlocks[0].parent, + ), + )) || []; + let folded = useUIState.getState().foldedBlocks; + blocks = blocks.filter( + (f) => + !f.listData || + !f.listData.path.find( + (path) => + folded.includes(path.entity) && f.value !== path.entity, + ), + ); + let lastBlock = blocks[blocks.length - 1]; + if (lastBlock) focusBlock(lastBlock, { type: "end" }); }, - { - metaKey: true, - shift: true, - key: ["ArrowDown", "J"], - handler: async () => { - let [sortedBlocks, siblings] = await getSortedSelectionBound(); - let block = sortedBlocks[0]; - let nextBlock = siblings - .slice(siblings.findIndex((s) => s.value === block.value) + 1) - .find( - (f) => - f.listData && - block.listData && - !f.listData.path.find((f) => f.entity === block.value), - ); - if ( - nextBlock?.listData && - block.listData && - nextBlock.listData.depth === block.listData.depth - 1 - ) { - if (useUIState.getState().foldedBlocks.includes(nextBlock.value)) - useUIState.getState().toggleFold(nextBlock.value); - rep?.mutate.moveBlock({ - block: block.value, - oldParent: block.listData?.parent, - newParent: nextBlock.value, - position: { type: "first" }, + }, + { + metaKey: true, + altKey: true, + key: ["l", "¬"], + handler: async () => { + let [sortedBlocks, siblings] = await getSortedSelectionBound(); + for (let block of sortedBlocks) { + if (!block.listData) { + await rep?.mutate.assertFact({ + entity: block.value, + attribute: "block/is-list", + data: { type: "boolean", value: true }, }); } else { - rep?.mutate.moveBlockDown({ - entityID: block.value, - parent: block.listData?.parent || block.parent, - }); + outdentFull(block, rep); } - }, + } }, - { - metaKey: true, - shift: true, - key: ["ArrowUp", "K"], - handler: async () => { - let [sortedBlocks, siblings] = await getSortedSelectionBound(); - let block = sortedBlocks[0]; - let previousBlock = + }, + { + metaKey: true, + shift: true, + key: ["ArrowDown", "J"], + handler: async () => { + let [sortedBlocks, siblings] = await getSortedSelectionBound(); + let block = sortedBlocks[0]; + let nextBlock = siblings + .slice(siblings.findIndex((s) => s.value === block.value) + 1) + .find( + (f) => + f.listData && + block.listData && + !f.listData.path.find((f) => f.entity === block.value), + ); + if ( + nextBlock?.listData && + block.listData && + nextBlock.listData.depth === block.listData.depth - 1 + ) { + if (useUIState.getState().foldedBlocks.includes(nextBlock.value)) + useUIState.getState().toggleFold(nextBlock.value); + rep?.mutate.moveBlock({ + block: block.value, + oldParent: block.listData?.parent, + newParent: nextBlock.value, + position: { type: "first" }, + }); + } else { + rep?.mutate.moveBlockDown({ + entityID: block.value, + parent: block.listData?.parent || block.parent, + }); + } + }, + }, + { + metaKey: true, + shift: true, + key: ["ArrowUp", "K"], + handler: async () => { + let [sortedBlocks, siblings] = await getSortedSelectionBound(); + let block = sortedBlocks[0]; + let previousBlock = + siblings?.[siblings.findIndex((s) => s.value === block.value) - 1]; + if (previousBlock.value === block.listData?.parent) { + previousBlock = siblings?.[ - siblings.findIndex((s) => s.value === block.value) - 1 + siblings.findIndex((s) => s.value === block.value) - 2 ]; - if (previousBlock.value === block.listData?.parent) { - previousBlock = - siblings?.[ - siblings.findIndex((s) => s.value === block.value) - 2 - ]; - } + } - if ( - previousBlock?.listData && - block.listData && - block.listData.depth > 1 && - !previousBlock.listData.path.find( - (f) => f.entity === block.listData?.parent, - ) - ) { - let depth = block.listData.depth; - let newParent = previousBlock.listData.path.find( - (f) => f.depth === depth - 1, - ); - if (!newParent) return; - if (useUIState.getState().foldedBlocks.includes(newParent.entity)) - useUIState.getState().toggleFold(newParent.entity); - rep?.mutate.moveBlock({ - block: block.value, - oldParent: block.listData?.parent, - newParent: newParent.entity, - position: { type: "end" }, - }); - } else { - rep?.mutate.moveBlockUp({ - entityID: block.value, - parent: block.listData?.parent || block.parent, - }); - } - }, + if ( + previousBlock?.listData && + block.listData && + block.listData.depth > 1 && + !previousBlock.listData.path.find( + (f) => f.entity === block.listData?.parent, + ) + ) { + let depth = block.listData.depth; + let newParent = previousBlock.listData.path.find( + (f) => f.depth === depth - 1, + ); + if (!newParent) return; + if (useUIState.getState().foldedBlocks.includes(newParent.entity)) + useUIState.getState().toggleFold(newParent.entity); + rep?.mutate.moveBlock({ + block: block.value, + oldParent: block.listData?.parent, + newParent: newParent.entity, + position: { type: "end" }, + }); + } else { + rep?.mutate.moveBlockUp({ + entityID: block.value, + parent: block.listData?.parent || block.parent, + }); + } + }, + }, + + { + metaKey: true, + shift: true, + key: "Enter", + handler: async () => { + let [sortedBlocks, siblings] = await getSortedSelectionBound(); + if (!sortedBlocks[0].listData) return; + useUIState.getState().toggleFold(sortedBlocks[0].value); }, + }, + ]; + if (moreThanOneSelected) + shortcuts = shortcuts.concat([ { metaKey: true, key: "u", @@ -238,17 +249,9 @@ export function SelectionManager() { ); }, }, - { - metaKey: true, - shift: true, - key: "Enter", - handler: async () => { - let [sortedBlocks, siblings] = await getSortedSelectionBound(); - if (!sortedBlocks[0].listData) return; - useUIState.getState().toggleFold(sortedBlocks[0].value); - }, - }, - ].map((shortcut) => ({ + ]); + let removeListener = addShortcut( + shortcuts.map((shortcut) => ({ ...shortcut, handler: () => undoManager.withUndoGroup(() => shortcut.handler()), })), diff --git a/src/shortcuts.ts b/src/shortcuts.ts index a4de0140..11ef743c 100644 --- a/src/shortcuts.ts +++ b/src/shortcuts.ts @@ -3,7 +3,7 @@ import { Replicache } from "replicache"; import { ReplicacheMutators } from "./replicache"; import { isMac } from "./utils/isDevice"; -type Shortcut = { +export type Shortcut = { metaKey?: boolean; metaAndCtrl?: boolean; altKey?: boolean;