({
bodyRef,
model,
table,
search,
focusIndex,
setFocusIndex,
setSearch,
setRefreshVersion,
osRef,
}: TableBodyProps)
| 312 | } |
| 313 | |
| 314 | function TableBody({ |
| 315 | bodyRef, |
| 316 | model, |
| 317 | table, |
| 318 | search, |
| 319 | focusIndex, |
| 320 | setFocusIndex, |
| 321 | setSearch, |
| 322 | setRefreshVersion, |
| 323 | osRef, |
| 324 | }: TableBodyProps) { |
| 325 | const searchActive = useAtomValue(model.directorySearchActive); |
| 326 | const dummyLineRef = useRef<HTMLDivElement>(null); |
| 327 | const warningBoxRef = useRef<HTMLDivElement>(null); |
| 328 | const conn = useAtomValue(model.connection); |
| 329 | const setErrorMsg = useSetAtom(model.errorMsgAtom); |
| 330 | |
| 331 | useEffect(() => { |
| 332 | if (focusIndex === null || !bodyRef.current || !osRef) { |
| 333 | return; |
| 334 | } |
| 335 | |
| 336 | const rowElement = bodyRef.current.querySelector(`[data-rowindex="${focusIndex}"]`) as HTMLDivElement; |
| 337 | if (!rowElement) { |
| 338 | return; |
| 339 | } |
| 340 | |
| 341 | const viewport = osRef.osInstance().elements().viewport; |
| 342 | const viewportHeight = viewport.offsetHeight; |
| 343 | const rowRect = rowElement.getBoundingClientRect(); |
| 344 | const parentRect = viewport.getBoundingClientRect(); |
| 345 | const viewportScrollTop = viewport.scrollTop; |
| 346 | const rowTopRelativeToViewport = rowRect.top - parentRect.top + viewport.scrollTop; |
| 347 | const rowBottomRelativeToViewport = rowRect.bottom - parentRect.top + viewport.scrollTop; |
| 348 | |
| 349 | if (rowTopRelativeToViewport - 30 < viewportScrollTop) { |
| 350 | // Row is above the visible area |
| 351 | let topVal = rowTopRelativeToViewport - 30; |
| 352 | if (topVal < 0) { |
| 353 | topVal = 0; |
| 354 | } |
| 355 | viewport.scrollTo({ top: topVal }); |
| 356 | } else if (rowBottomRelativeToViewport + 5 > viewportScrollTop + viewportHeight) { |
| 357 | // Row is below the visible area |
| 358 | const topVal = rowBottomRelativeToViewport - viewportHeight + 5; |
| 359 | viewport.scrollTo({ top: topVal }); |
| 360 | } |
| 361 | }, [focusIndex]); |
| 362 | |
| 363 | const handleFileContextMenu = useCallback( |
| 364 | async (e: any, finfo: FileInfo) => { |
| 365 | e.preventDefault(); |
| 366 | e.stopPropagation(); |
| 367 | if (finfo == null) { |
| 368 | return; |
| 369 | } |
| 370 | const fileName = finfo.path.split("/").pop(); |
| 371 | const menu: ContextMenuItem[] = [ |
nothing calls this directly
no test coverage detected