From bf97ea16597ec912606e459888ca8c89b90a6733 Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Mon, 3 Nov 2025 14:17:11 -0800 Subject: [PATCH] Some sidebar fixes --- src-web/components/HeaderSize.tsx | 44 ++-- src-web/components/Workspace.tsx | 4 +- src-web/components/core/tree/Tree.tsx | 361 +++++++++++++++++--------- 3 files changed, 267 insertions(+), 142 deletions(-) diff --git a/src-web/components/HeaderSize.tsx b/src-web/components/HeaderSize.tsx index 5efa3b5b..3b5c5232 100644 --- a/src-web/components/HeaderSize.tsx +++ b/src-web/components/HeaderSize.tsx @@ -1,18 +1,23 @@ -import { type } from '@tauri-apps/plugin-os'; -import { settingsAtom } from '@yaakapp-internal/models'; -import classNames from 'classnames'; -import { useAtomValue } from 'jotai'; -import type { CSSProperties, HTMLAttributes, ReactNode } from 'react'; -import React, { useMemo } from 'react'; -import { useIsFullscreen } from '../hooks/useIsFullscreen'; -import { HEADER_SIZE_LG, HEADER_SIZE_MD, WINDOW_CONTROLS_WIDTH } from '../lib/constants'; -import { WindowControls } from './WindowControls'; +import { type } from "@tauri-apps/plugin-os"; +import { settingsAtom } from "@yaakapp-internal/models"; +import classNames from "classnames"; +import { useAtomValue } from "jotai"; +import type { CSSProperties, HTMLAttributes, ReactNode } from "react"; +import React, { useMemo } from "react"; +import { useIsFullscreen } from "../hooks/useIsFullscreen"; +import { + HEADER_SIZE_LG, + HEADER_SIZE_MD, + WINDOW_CONTROLS_WIDTH, +} from "../lib/constants"; +import { WindowControls } from "./WindowControls"; interface HeaderSizeProps extends HTMLAttributes { children?: ReactNode; - size: 'md' | 'lg'; + size: "md" | "lg"; ignoreControlsSpacing?: boolean; onlyXWindowControl?: boolean; + hideControls?: boolean; } export function HeaderSize({ @@ -22,6 +27,7 @@ export function HeaderSize({ ignoreControlsSpacing, onlyXWindowControl, children, + hideControls, }: HeaderSizeProps) { const settings = useAtomValue(settingsAtom); const isFullscreen = useIsFullscreen(); @@ -29,10 +35,10 @@ export function HeaderSize({ const s = { ...style }; // Set the height (use min-height because scaling font size may make it larger - if (size === 'md') s.minHeight = HEADER_SIZE_MD; - if (size === 'lg') s.minHeight = HEADER_SIZE_LG; + if (size === "md") s.minHeight = HEADER_SIZE_MD; + if (size === "lg") s.minHeight = HEADER_SIZE_LG; - if (type() === 'macos') { + if (type() === "macos") { if (!isFullscreen) { // Add large padding for window controls s.paddingLeft = 72 / settings.interfaceScale; @@ -57,21 +63,21 @@ export function HeaderSize({ style={finalStyle} className={classNames( className, - 'pt-[1px]', // Make up for bottom border - 'select-none relative', - 'w-full border-b border-border-subtle min-w-0', + "pt-[1px]", // Make up for bottom border + "select-none relative", + "w-full border-b border-border-subtle min-w-0", )} > {/* NOTE: This needs display:grid or else the element shrinks (even though scrollable) */}
{children}
- + {!hideControls && } ); } diff --git a/src-web/components/Workspace.tsx b/src-web/components/Workspace.tsx index 20dc9929..63b85fb3 100644 --- a/src-web/components/Workspace.tsx +++ b/src-web/components/Workspace.tsx @@ -141,11 +141,11 @@ export function Workspace() { animate={{ opacity: 1, x: 0 }} className={classNames( 'x-theme-sidebar', - 'absolute top-0 left-0 bottom-0 bg-surface border-r border-border-subtle w-[14rem]', + 'absolute top-0 left-0 bottom-0 bg-surface border-r border-border-subtle w-[20rem]', 'grid grid-rows-[auto_1fr]', )} > - + diff --git a/src-web/components/core/tree/Tree.tsx b/src-web/components/core/tree/Tree.tsx index 2e16dc3b..84ec30d2 100644 --- a/src-web/components/core/tree/Tree.tsx +++ b/src-web/components/core/tree/Tree.tsx @@ -1,4 +1,8 @@ -import type { DragEndEvent, DragMoveEvent, DragStartEvent } from '@dnd-kit/core'; +import type { + DragEndEvent, + DragMoveEvent, + DragStartEvent, +} from "@dnd-kit/core"; import { DndContext, MeasuringStrategy, @@ -7,11 +11,17 @@ import { useDroppable, useSensor, useSensors, -} from '@dnd-kit/core'; -import { type } from '@tauri-apps/plugin-os'; -import classNames from 'classnames'; -import type { ComponentType, MouseEvent, ReactElement, Ref, RefAttributes } from 'react'; -import React, { +} from "@dnd-kit/core"; +import { type } from "@tauri-apps/plugin-os"; +import classNames from "classnames"; +import type { + ComponentType, + MouseEvent, + ReactElement, + Ref, + RefAttributes, +} from "react"; +import { forwardRef, memo, useCallback, @@ -20,14 +30,14 @@ import React, { useMemo, useRef, useState, -} from 'react'; -import { useKey, useKeyPressEvent } from 'react-use'; -import type { HotkeyAction, HotKeyOptions } from '../../../hooks/useHotKey'; -import { useHotKey } from '../../../hooks/useHotKey'; -import { computeSideForDragMove } from '../../../lib/dnd'; -import { jotaiStore } from '../../../lib/jotai'; -import type { ContextMenuProps, DropdownItem } from '../Dropdown'; -import { ContextMenu } from '../Dropdown'; +} from "react"; +import { useKey, useKeyPressEvent } from "react-use"; +import type { HotkeyAction, HotKeyOptions } from "../../../hooks/useHotKey"; +import { useHotKey } from "../../../hooks/useHotKey"; +import { computeSideForDragMove } from "../../../lib/dnd"; +import { jotaiStore } from "../../../lib/jotai"; +import type { ContextMenuProps, DropdownItem } from "../Dropdown"; +import { ContextMenu } from "../Dropdown"; import { collapsedFamily, draggingIdsFamily, @@ -35,14 +45,23 @@ import { hoveredParentFamily, isCollapsedFamily, selectedIdsFamily, -} from './atoms'; -import type { SelectableTreeNode, TreeNode } from './common'; -import { closestVisibleNode, equalSubtree, getSelectedItems, hasAncestor } from './common'; -import { TreeDragOverlay } from './TreeDragOverlay'; -import type { TreeItemClickEvent, TreeItemHandle, TreeItemProps } from './TreeItem'; -import type { TreeItemListProps } from './TreeItemList'; -import { TreeItemList } from './TreeItemList'; -import { useSelectableItems } from './useSelectableItems'; +} from "./atoms"; +import type { SelectableTreeNode, TreeNode } from "./common"; +import { + closestVisibleNode, + equalSubtree, + getSelectedItems, + hasAncestor, +} from "./common"; +import { TreeDragOverlay } from "./TreeDragOverlay"; +import type { + TreeItemClickEvent, + TreeItemHandle, + TreeItemProps, +} from "./TreeItem"; +import type { TreeItemListProps } from "./TreeItemList"; +import { TreeItemList } from "./TreeItemList"; +import { useSelectableItems } from "./useSelectableItems"; /** So we re-calculate after expanding a folder during drag */ const measuring = { droppable: { strategy: MeasuringStrategy.Always } }; @@ -51,15 +70,21 @@ export interface TreeProps { root: TreeNode; treeId: string; getItemKey: (item: T) => string; - getContextMenu?: (items: T[]) => ContextMenuProps['items'] | Promise; + getContextMenu?: ( + items: T[], + ) => ContextMenuProps["items"] | Promise; ItemInner: ComponentType<{ treeId: string; item: T }>; ItemLeftSlotInner?: ComponentType<{ treeId: string; item: T }>; ItemRightSlot?: ComponentType<{ treeId: string; item: T }>; className?: string; onActivate?: (item: T) => void; - onDragEnd?: (opt: { items: T[]; parent: T; children: T[]; insertAt: number }) => void; + onDragEnd?: ( + opt: { items: T[]; parent: T; children: T[]; insertAt: number }, + ) => void; hotkeys?: { - actions: Partial void } & HotKeyOptions>>; + actions: Partial< + Record void } & HotKeyOptions> + >; }; getEditOptions?: (item: T) => { defaultValue: string; @@ -96,19 +121,24 @@ function TreeInner( ) { const treeRef = useRef(null); const selectableItems = useSelectableItems(root); - const [showContextMenu, setShowContextMenu] = useState<{ - items: DropdownItem[]; - x: number; - y: number; - } | null>(null); + const [showContextMenu, setShowContextMenu] = useState< + { + items: DropdownItem[]; + x: number; + y: number; + } | null + >(null); const treeItemRefs = useRef>({}); - const handleAddTreeItemRef = useCallback((item: T, r: TreeItemHandle | null) => { - if (r == null) { - delete treeItemRefs.current[item.id]; - } else { - treeItemRefs.current[item.id] = r; - } - }, []); + const handleAddTreeItemRef = useCallback( + (item: T, r: TreeItemHandle | null) => { + if (r == null) { + delete treeItemRefs.current[item.id]; + } else { + treeItemRefs.current[item.id] = r; + } + }, + [], + ); // Select the first item on first render useEffect(() => { @@ -146,7 +176,9 @@ function TreeInner( const ensureTabbableItem = useCallback(() => { const lastSelectedId = jotaiStore.get(focusIdsFamily(treeId)).lastId; - const lastSelectedItem = selectableItems.find((i) => i.node.item.id === lastSelectedId); + const lastSelectedItem = selectableItems.find((i) => + i.node.item.id === lastSelectedId + ); if (lastSelectedItem == null) { return false; } @@ -184,7 +216,8 @@ function TreeInner( () => ({ treeId, focus: tryFocus, - hasFocus: () => treeRef.current?.contains(document.activeElement) ?? false, + hasFocus: () => + treeRef.current?.contains(document.activeElement) ?? false, renameItem: (id) => treeItemRefs.current[id]?.rename(), selectItem: (id) => { setSelected([id], false); @@ -195,7 +228,9 @@ function TreeInner( const items = getSelectedItems(treeId, selectableItems); const menuItems = await getContextMenu(items); const lastSelectedId = jotaiStore.get(focusIdsFamily(treeId)).lastId; - const rect = lastSelectedId ? treeItemRefs.current[lastSelectedId]?.rect() : null; + const rect = lastSelectedId + ? treeItemRefs.current[lastSelectedId]?.rect() + : null; if (rect == null) return; setShowContextMenu({ items: menuItems, x: rect.x, y: rect.y }); }, @@ -217,42 +252,66 @@ function TreeInner( // If right-clicked an item that was NOT in the multiple-selection, just use that one // Also update the selection with it setSelected([item.id], false); - jotaiStore.set(focusIdsFamily(treeId), (prev) => ({ ...prev, lastId: item.id })); + jotaiStore.set( + focusIdsFamily(treeId), + (prev) => ({ ...prev, lastId: item.id }), + ); return getContextMenu([item]); } }; }, [getContextMenu, selectableItems, setSelected, treeId]); - const handleSelect = useCallback['onClick']>>( + const handleSelect = useCallback["onClick"]>>( (item, { shiftKey, metaKey, ctrlKey }) => { const anchorSelectedId = jotaiStore.get(focusIdsFamily(treeId)).anchorId; const selectedIdsAtom = selectedIdsFamily(treeId); const selectedIds = jotaiStore.get(selectedIdsAtom); // Mark the item as the last one selected - jotaiStore.set(focusIdsFamily(treeId), (prev) => ({ ...prev, lastId: item.id })); + jotaiStore.set( + focusIdsFamily(treeId), + (prev) => ({ ...prev, lastId: item.id }), + ); if (shiftKey) { - const anchorIndex = selectableItems.findIndex((i) => i.node.item.id === anchorSelectedId); - const currIndex = selectableItems.findIndex((v) => v.node.item.id === item.id); + const anchorIndex = selectableItems.findIndex((i) => + i.node.item.id === anchorSelectedId + ); + const currIndex = selectableItems.findIndex((v) => + v.node.item.id === item.id + ); // Nothing was selected yet, so just select this item - if (selectedIds.length === 0 || anchorIndex === -1 || currIndex === -1) { + if ( + selectedIds.length === 0 || anchorIndex === -1 || currIndex === -1 + ) { setSelected([item.id], true); - jotaiStore.set(focusIdsFamily(treeId), (prev) => ({ ...prev, anchorId: item.id })); + jotaiStore.set( + focusIdsFamily(treeId), + (prev) => ({ ...prev, anchorId: item.id }), + ); return; } - const validSelectableItems = getValidSelectableItems(treeId, selectableItems); + const validSelectableItems = getValidSelectableItems( + treeId, + selectableItems, + ); if (currIndex > anchorIndex) { // Selecting down - const itemsToSelect = validSelectableItems.slice(anchorIndex, currIndex + 1); + const itemsToSelect = validSelectableItems.slice( + anchorIndex, + currIndex + 1, + ); setSelected( itemsToSelect.map((v) => v.node.item.id), true, ); } else if (currIndex < anchorIndex) { // Selecting up - const itemsToSelect = validSelectableItems.slice(currIndex, anchorIndex + 1); + const itemsToSelect = validSelectableItems.slice( + currIndex, + anchorIndex + 1, + ); setSelected( itemsToSelect.map((v) => v.node.item.id), true, @@ -260,7 +319,7 @@ function TreeInner( } else { setSelected([item.id], true); } - } else if (type() === 'macos' ? metaKey : ctrlKey) { + } else if (type() === "macos" ? metaKey : ctrlKey) { const withoutCurr = selectedIds.filter((id) => id !== item.id); if (withoutCurr.length === selectedIds.length) { // It wasn't in there, so add it @@ -272,13 +331,16 @@ function TreeInner( } else { // Select single setSelected([item.id], true); - jotaiStore.set(focusIdsFamily(treeId), (prev) => ({ ...prev, anchorId: item.id })); + jotaiStore.set( + focusIdsFamily(treeId), + (prev) => ({ ...prev, anchorId: item.id }), + ); } }, [selectableItems, setSelected, treeId], ); - const handleClick = useCallback['onClick']>>( + const handleClick = useCallback["onClick"]>>( (item, e) => { if (e.shiftKey || e.ctrlKey || e.metaKey) { handleSelect(item, e); @@ -293,8 +355,13 @@ function TreeInner( const selectPrevItem = useCallback( (e: TreeItemClickEvent) => { const lastSelectedId = jotaiStore.get(focusIdsFamily(treeId)).lastId; - const validSelectableItems = getValidSelectableItems(treeId, selectableItems); - const index = validSelectableItems.findIndex((i) => i.node.item.id === lastSelectedId); + const validSelectableItems = getValidSelectableItems( + treeId, + selectableItems, + ); + const index = validSelectableItems.findIndex((i) => + i.node.item.id === lastSelectedId + ); const item = validSelectableItems[index - 1]; if (item != null) { handleSelect(item.node.item, e); @@ -306,8 +373,13 @@ function TreeInner( const selectNextItem = useCallback( (e: TreeItemClickEvent) => { const lastSelectedId = jotaiStore.get(focusIdsFamily(treeId)).lastId; - const validSelectableItems = getValidSelectableItems(treeId, selectableItems); - const index = validSelectableItems.findIndex((i) => i.node.item.id === lastSelectedId); + const validSelectableItems = getValidSelectableItems( + treeId, + selectableItems, + ); + const index = validSelectableItems.findIndex((i) => + i.node.item.id === lastSelectedId + ); const item = validSelectableItems[index + 1]; if (item != null) { handleSelect(item.node.item, e); @@ -320,7 +392,8 @@ function TreeInner( (e: TreeItemClickEvent) => { const lastSelectedId = jotaiStore.get(focusIdsFamily(treeId)).lastId; const lastSelectedItem = - selectableItems.find((i) => i.node.item.id === lastSelectedId)?.node ?? null; + selectableItems.find((i) => i.node.item.id === lastSelectedId)?.node ?? + null; if (lastSelectedItem?.parent != null) { handleSelect(lastSelectedItem.parent.item, e); } @@ -329,7 +402,7 @@ function TreeInner( ); useKey( - (e) => e.key === 'ArrowUp' || e.key.toLowerCase() === 'k', + (e) => e.key === "ArrowUp" || e.key.toLowerCase() === "k", (e) => { if (!isTreeFocused()) return; e.preventDefault(); @@ -340,7 +413,7 @@ function TreeInner( ); useKey( - (e) => e.key === 'ArrowDown' || e.key.toLowerCase() === 'j', + (e) => e.key === "ArrowDown" || e.key.toLowerCase() === "j", (e) => { if (!isTreeFocused()) return; e.preventDefault(); @@ -352,21 +425,26 @@ function TreeInner( // If the selected item is a collapsed folder, expand it. Otherwise, select next item useKey( - (e) => e.key === 'ArrowRight' || e.key === 'l', + (e) => e.key === "ArrowRight" || e.key === "l", (e) => { if (!isTreeFocused()) return; e.preventDefault(); const collapsed = jotaiStore.get(collapsedFamily(treeId)); const lastSelectedId = jotaiStore.get(focusIdsFamily(treeId)).lastId; - const lastSelectedItem = selectableItems.find((i) => i.node.item.id === lastSelectedId); + const lastSelectedItem = selectableItems.find((i) => + i.node.item.id === lastSelectedId + ); if ( lastSelectedId && lastSelectedItem?.node.children != null && collapsed[lastSelectedItem.node.item.id] === true ) { - jotaiStore.set(isCollapsedFamily({ treeId, itemId: lastSelectedId }), false); + jotaiStore.set( + isCollapsedFamily({ treeId, itemId: lastSelectedId }), + false, + ); } else { selectNextItem(e); } @@ -378,21 +456,26 @@ function TreeInner( // If the selected item is in a folder, select its parent. // If the selected item is an expanded folder, collapse it. useKey( - (e) => e.key === 'ArrowLeft' || e.key === 'h', + (e) => e.key === "ArrowLeft" || e.key === "h", (e) => { if (!isTreeFocused()) return; e.preventDefault(); const collapsed = jotaiStore.get(collapsedFamily(treeId)); const lastSelectedId = jotaiStore.get(focusIdsFamily(treeId)).lastId; - const lastSelectedItem = selectableItems.find((i) => i.node.item.id === lastSelectedId); + const lastSelectedItem = selectableItems.find((i) => + i.node.item.id === lastSelectedId + ); if ( lastSelectedId && lastSelectedItem?.node.children != null && collapsed[lastSelectedItem.node.item.id] !== true ) { - jotaiStore.set(isCollapsedFamily({ treeId, itemId: lastSelectedId }), true); + jotaiStore.set( + isCollapsedFamily({ treeId, itemId: lastSelectedId }), + true, + ); } else { selectParentItem(e); } @@ -401,7 +484,7 @@ function TreeInner( [selectableItems, handleSelect], ); - useKeyPressEvent('Escape', async () => { + useKeyPressEvent("Escape", async () => { if (!treeRef.current?.contains(document.activeElement)) return; clearDragState(); const lastSelectedId = jotaiStore.get(focusIdsFamily(treeId)).lastId; @@ -428,24 +511,6 @@ function TreeInner( return; } - const overSelectableItem = selectableItems.find((i) => i.node.item.id === over.id) ?? null; - if (overSelectableItem == null) { - return; - } - - const draggingItems = jotaiStore.get(draggingIdsFamily(treeId)); - for (const id of draggingItems) { - const item = selectableItems.find((i) => i.node.item.id === id)?.node ?? null; - if (item == null) { - return; - } - - const isSameParent = item.parent?.item.id === overSelectableItem.node.parent?.item.id; - if (item.localDrag && !isSameParent) { - return; - } - } - // Root is anything past the end of the list, so set it to the end const hoveringRoot = over.id === root.item.id; if (hoveringRoot) { @@ -458,18 +523,41 @@ function TreeInner( return; } + const overSelectableItem = + selectableItems.find((i) => i.node.item.id === over.id) ?? null; + if (overSelectableItem == null) { + return; + } + + const draggingItems = jotaiStore.get(draggingIdsFamily(treeId)); + for (const id of draggingItems) { + const item = selectableItems.find((i) => i.node.item.id === id)?.node ?? + null; + if (item == null) { + return; + } + + const isSameParent = + item.parent?.item.id === overSelectableItem.node.parent?.item.id; + if (item.localDrag && !isSameParent) { + return; + } + } + const node = overSelectableItem.node; const side = computeSideForDragMove(node.item.id, e); const item = node.item; let hoveredParent = node.parent; - const dragIndex = selectableItems.findIndex((n) => n.node.item.id === item.id) ?? -1; + const dragIndex = + selectableItems.findIndex((n) => n.node.item.id === item.id) ?? -1; const hovered = selectableItems[dragIndex]?.node ?? null; - const hoveredIndex = dragIndex + (side === 'above' ? 0 : 1); - let hoveredChildIndex = overSelectableItem.index + (side === 'above' ? 0 : 1); + const hoveredIndex = dragIndex + (side === "above" ? 0 : 1); + let hoveredChildIndex = overSelectableItem.index + + (side === "above" ? 0 : 1); // Move into the folder if it's open and we're moving below it - if (hovered?.children != null && side === 'below') { + if (hovered?.children != null && side === "below") { hoveredParent = hovered; hoveredChildIndex = 0; } @@ -487,7 +575,12 @@ function TreeInner( childIndex === existing.childIndex ) ) { - jotaiStore.set(hoveredParentFamily(treeId), { parentId, parentDepth, index, childIndex }); + jotaiStore.set(hoveredParentFamily(treeId), { + parentId, + parentDepth, + index, + childIndex, + }); } }, [root.depth, root.item.id, selectableItems, treeId], @@ -496,7 +589,9 @@ function TreeInner( const handleDragStart = useCallback( function handleDragStart(e: DragStartEvent) { const selectedItems = getSelectedItems(treeId, selectableItems); - const isDraggingSelectedItem = selectedItems.find((i) => i.id === e.active.id); + const isDraggingSelectedItem = selectedItems.find((i) => + i.id === e.active.id + ); // If we started dragging an already-selected item, we'll use that if (isDraggingSelectedItem) { @@ -506,11 +601,17 @@ function TreeInner( ); } else { // If we started dragging a non-selected item, only drag that item - const activeItem = selectableItems.find((i) => i.node.item.id === e.active.id)?.node.item; + const activeItem = selectableItems.find((i) => + i.node.item.id === e.active.id + )?.node.item; if (activeItem != null) { jotaiStore.set(draggingIdsFamily(treeId), [activeItem.id]); // Also update selection to just be this one - handleSelect(activeItem, { shiftKey: false, metaKey: false, ctrlKey: false }); + handleSelect(activeItem, { + shiftKey: false, + metaKey: false, + ctrlKey: false, + }); } } }, @@ -543,25 +644,30 @@ function TreeInner( return; } - const hoveredParentS = - hoveredParentId === root.item.id - ? { node: root, depth: 0, index: 0 } - : (selectableItems.find((i) => i.node.item.id === hoveredParentId) ?? null); + const hoveredParentS = hoveredParentId === root.item.id + ? { node: root, depth: 0, index: 0 } + : (selectableItems.find((i) => i.node.item.id === hoveredParentId) ?? + null); const hoveredParent = hoveredParentS?.node ?? null; - if (hoveredParent == null || hoveredIndex == null || !draggingItems?.length) { + if ( + hoveredParent == null || hoveredIndex == null || !draggingItems?.length + ) { return; } // Resolve the actual tree nodes for each dragged item (keeps order of draggingItems) const draggedNodes: TreeNode[] = draggingItems .map((id) => { - return selectableItems.find((i) => i.node.item.id === id)?.node ?? null; + return selectableItems.find((i) => i.node.item.id === id)?.node ?? + null; }) .filter((n) => n != null) // Filter out invalid drags (dragging into descendant) .filter( - (n) => hoveredParent.item.id !== n.item.id && !hasAncestor(hoveredParent, n.item.id), + (n) => + hoveredParent.item.id !== n.item.id && + !hasAncestor(hoveredParent, n.item.id), ); // Work on a local copy of target children @@ -590,7 +696,7 @@ function TreeInner( const treeItemListProps: Omit< TreeItemListProps, - 'nodes' | 'treeId' | 'activeIdAtom' | 'hoveredParent' | 'hoveredIndex' + "nodes" | "treeId" | "activeIdAtom" | "hoveredParent" | "hoveredIndex" > = { getItemKey, getContextMenu: handleGetContextMenu, @@ -613,11 +719,17 @@ function TreeInner( [getContextMenu], ); - const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 6 } })); + const sensors = useSensors( + useSensor(PointerSensor, { activationConstraint: { distance: 6 } }), + ); return ( <> - + {showContextMenu && ( ( onDragEnd={handleDragEnd} onDragCancel={clearDragState} onDragAbort={clearDragState} - measuring={measuring} onDragMove={handleDragMove} + measuring={measuring} autoScroll >
( />
{/* Assign root ID so we can reuse our same move/end logic */} - +
{ for (const key of Object.keys(prevProps)) { - if (prevProps[key as keyof typeof prevProps] !== nextProps[key as keyof typeof nextProps]) { + if ( + prevProps[key as keyof typeof prevProps] !== + nextProps[key as keyof typeof nextProps] + ) { return false; } } @@ -706,7 +823,9 @@ function DropRegionAfterList({ onContextMenu?: (e: MouseEvent) => void; }) { const { setNodeRef } = useDroppable({ id }); - return
; + return ( +
+ ); } interface TreeHotKeyProps { @@ -735,7 +854,7 @@ function TreeHotKey({ ...options, enable: () => { if (enable == null) return true; - if (typeof enable === 'function') return enable(); + if (typeof enable === "function") return enable(); else return enable; }, }, @@ -749,7 +868,7 @@ function TreeHotKeys({ selectableItems, }: { treeId: string; - hotkeys: TreeProps['hotkeys']; + hotkeys: TreeProps["hotkeys"]; selectableItems: SelectableTreeNode[]; }) { if (hotkeys == null) return null;