a tool for shared writing and social publishing
1import { useSelectingMouse } from "components/SelectionManager/selectionState";
2import { MouseEvent, useCallback, useRef } from "react";
3import { useUIState } from "src/useUIState";
4import { Block } from "./Block";
5import { isTextBlock } from "src/utils/isTextBlock";
6import { useEntitySetContext } from "components/EntitySetProvider";
7import { useReplicache } from "src/replicache";
8import { getBlocksWithType } from "src/hooks/queries/useBlocks";
9import { focusBlock } from "src/utils/focusBlock";
10import { useIsMobile } from "src/hooks/isMobile";
11
12let debounce: number | null = null;
13export function useBlockMouseHandlers(props: Block) {
14 let entity_set = useEntitySetContext();
15 let isMobile = useIsMobile();
16 let { rep } = useReplicache();
17 let onMouseDown = useCallback(
18 (e: MouseEvent) => {
19 if ((e.target as Element).getAttribute("data-draggable")) return;
20 if ((e.target as Element).tagName === "BUTTON") return;
21 if ((e.target as Element).tagName === "SELECT") return;
22 if ((e.target as Element).tagName === "OPTION") return;
23 if (isMobile) return;
24 if (!entity_set.permissions.write) return;
25 useSelectingMouse.setState({ start: props.value });
26 if (e.shiftKey) {
27 if (
28 useUIState.getState().selectedBlocks[0]?.value === props.value &&
29 useUIState.getState().selectedBlocks.length === 1
30 )
31 return;
32 e.preventDefault();
33 useUIState.getState().addBlockToSelection(props);
34 } else {
35 if (e.isDefaultPrevented()) return;
36 useUIState.getState().setFocusedBlock({
37 entityType: "block",
38 entityID: props.value,
39 parent: props.parent,
40 });
41 useUIState.getState().setSelectedBlock(props);
42 }
43 },
44 [props, entity_set.permissions.write, isMobile],
45 );
46 let onMouseEnter = useCallback(
47 async (e: MouseEvent) => {
48 if (isMobile) return;
49 if (!entity_set.permissions.write) return;
50 if (debounce) window.clearTimeout(debounce);
51 debounce = window.setTimeout(async () => {
52 debounce = null;
53 if (e.buttons !== 1) return;
54 let selection = useSelectingMouse.getState();
55 if (!selection.start) return;
56 let siblings =
57 (await rep?.query((tx) => getBlocksWithType(tx, props.parent))) || [];
58 let startIndex = siblings.findIndex((b) => b.value === selection.start);
59 if (startIndex === -1) return;
60 let endIndex = siblings.findIndex((b) => b.value === props.value);
61 let start = Math.min(startIndex, endIndex);
62 let end = Math.max(startIndex, endIndex);
63 let selected = siblings.slice(start, end + 1).map((b) => ({
64 value: b.value,
65 position: b.position,
66 parent: props.parent,
67 }));
68 useUIState.getState().setSelectedBlocks(selected);
69 }, 15);
70 },
71 [rep, props, entity_set.permissions.write, isMobile],
72 );
73 return { onMouseDown, onMouseEnter };
74}