From a77c0acb07295a97f71dde83ede9c9c8b2375e75 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Fri, 12 Mar 2021 11:24:26 +0800 Subject: [PATCH] TableHeading: sync scroll with list on cell focus --- .../components/torrent-list/TableHeading.tsx | 232 +++++++++--------- .../components/torrent-list/TorrentList.tsx | 9 +- 2 files changed, 123 insertions(+), 118 deletions(-) diff --git a/client/src/javascript/components/torrent-list/TableHeading.tsx b/client/src/javascript/components/torrent-list/TableHeading.tsx index 5b2b38f5..23a84a02 100644 --- a/client/src/javascript/components/torrent-list/TableHeading.tsx +++ b/client/src/javascript/components/torrent-list/TableHeading.tsx @@ -15,140 +15,144 @@ const pointerDownStyles = ` interface TableHeadingProps { onCellClick: (column: TorrentListColumn) => void; + onCellFocus: () => void; onWidthsChange: (column: TorrentListColumn, width: number) => void; } const TableHeading = observer( - forwardRef(({onCellClick, onWidthsChange}: TableHeadingProps, ref) => { - const [isPointerDown, setIsPointerDown] = useState(false); + forwardRef( + ({onCellClick, onCellFocus, onWidthsChange}: TableHeadingProps, ref) => { + const [isPointerDown, setIsPointerDown] = useState(false); - const focusedCell = useRef(); - const focusedCellWidth = useRef(); - const lastPointerX = useRef(); - const tableHeading = useEnsuredForwardedRef(ref as MutableRefObject); - const resizeLine = useRef(null); + const focusedCell = useRef(); + const focusedCellWidth = useRef(); + const lastPointerX = useRef(); + const tableHeading = useEnsuredForwardedRef(ref as MutableRefObject); + const resizeLine = useRef(null); - const {i18n} = useLingui(); + const {i18n} = useLingui(); - const handlePointerMove = (event: PointerEvent) => { - let widthDelta = 0; - if (lastPointerX.current != null) { - widthDelta = event.clientX - lastPointerX.current; - } - - let nextCellWidth = 20; - if (focusedCellWidth.current != null) { - nextCellWidth = focusedCellWidth.current + widthDelta; - } - - if (nextCellWidth > 20) { - focusedCellWidth.current = nextCellWidth; - lastPointerX.current = event.clientX; - if (resizeLine.current != null && tableHeading.current != null) { - resizeLine.current.style.transform = `translate(${Math.max(0, event.clientX)}px, ${ - tableHeading.current.getBoundingClientRect().top - }px)`; + const handlePointerMove = (event: PointerEvent) => { + let widthDelta = 0; + if (lastPointerX.current != null) { + widthDelta = event.clientX - lastPointerX.current; } - } - }; - const handlePointerUp = () => { - UIStore.removeGlobalStyle(pointerDownStyles); - window.removeEventListener('pointerup', handlePointerUp); - window.removeEventListener('pointermove', handlePointerMove); + let nextCellWidth = 20; + if (focusedCellWidth.current != null) { + nextCellWidth = focusedCellWidth.current + widthDelta; + } - setIsPointerDown(false); - lastPointerX.current = undefined; - - if (resizeLine.current != null) { - resizeLine.current.style.opacity = '0'; - } - - if (focusedCell.current != null && focusedCellWidth.current != null) { - onWidthsChange(focusedCell.current, focusedCellWidth.current); - } - - focusedCell.current = undefined; - focusedCellWidth.current = undefined; - }; - - return ( -
- {SettingStore.floodSettings.torrentListColumns.reduce((accumulator: ReactNodeArray, {id, visible}) => { - if (!visible) { - return accumulator; + if (nextCellWidth > 20) { + focusedCellWidth.current = nextCellWidth; + lastPointerX.current = event.clientX; + if (resizeLine.current != null && tableHeading.current != null) { + resizeLine.current.style.transform = `translate(${Math.max(0, event.clientX)}px, ${ + tableHeading.current.getBoundingClientRect().top + }px)`; } + } + }; - const labelID = TorrentListColumns[id]; - if (labelID == null) { - return accumulator; - } + const handlePointerUp = () => { + UIStore.removeGlobalStyle(pointerDownStyles); + window.removeEventListener('pointerup', handlePointerUp); + window.removeEventListener('pointermove', handlePointerMove); - let handle = null; - const width = SettingStore.floodSettings.torrentListColumnWidths[id] || 100; + setIsPointerDown(false); + lastPointerX.current = undefined; - if (!isPointerDown) { - handle = ( - { - if (!isPointerDown && resizeLine.current != null && tableHeading.current != null) { - setIsPointerDown(true); + if (resizeLine.current != null) { + resizeLine.current.style.opacity = '0'; + } - focusedCell.current = id; - focusedCellWidth.current = width; - lastPointerX.current = event.clientX; + if (focusedCell.current != null && focusedCellWidth.current != null) { + onWidthsChange(focusedCell.current, focusedCellWidth.current); + } - window.addEventListener('pointerup', handlePointerUp); - window.addEventListener('pointermove', handlePointerMove); - UIStore.addGlobalStyle(pointerDownStyles); + focusedCell.current = undefined; + focusedCellWidth.current = undefined; + }; - resizeLine.current.style.transform = `translate(${Math.max(0, event.clientX)}px, ${ - tableHeading.current.getBoundingClientRect().top - }px)`; - resizeLine.current.style.opacity = '1'; - } + return ( +
+ {SettingStore.floodSettings.torrentListColumns.reduce((accumulator: ReactNodeArray, {id, visible}) => { + if (!visible) { + return accumulator; + } + + const labelID = TorrentListColumns[id]; + if (labelID == null) { + return accumulator; + } + + let handle = null; + const width = SettingStore.floodSettings.torrentListColumnWidths[id] || 100; + + if (!isPointerDown) { + handle = ( + { + if (!isPointerDown && resizeLine.current != null && tableHeading.current != null) { + setIsPointerDown(true); + + focusedCell.current = id; + focusedCellWidth.current = width; + lastPointerX.current = event.clientX; + + window.addEventListener('pointerup', handlePointerUp); + window.addEventListener('pointermove', handlePointerMove); + UIStore.addGlobalStyle(pointerDownStyles); + + resizeLine.current.style.transform = `translate(${Math.max(0, event.clientX)}px, ${ + tableHeading.current.getBoundingClientRect().top + }px)`; + resizeLine.current.style.opacity = '1'; + } + }} + /> + ); + } + + const isSortActive = id === SettingStore.floodSettings.sortTorrents.property; + const classes = classnames('table__cell table__heading', { + 'table__heading--is-sorted': isSortActive, + [`table__heading--direction--${SettingStore.floodSettings.sortTorrents.direction}`]: isSortActive, + }); + + accumulator.push( + , ); - } - const isSortActive = id === SettingStore.floodSettings.sortTorrents.property; - const classes = classnames('table__cell table__heading', { - 'table__heading--is-sorted': isSortActive, - [`table__heading--direction--${SettingStore.floodSettings.sortTorrents.direction}`]: isSortActive, - }); - - accumulator.push( - , - ); - - return accumulator; - }, [])} -
-
-
- ); - }), + return accumulator; + }, [])} +
+
+
+ ); + }, + ), ); export default TableHeading; diff --git a/client/src/javascript/components/torrent-list/TorrentList.tsx b/client/src/javascript/components/torrent-list/TorrentList.tsx index 7223f770..cfc255ad 100644 --- a/client/src/javascript/components/torrent-list/TorrentList.tsx +++ b/client/src/javascript/components/torrent-list/TorrentList.tsx @@ -86,6 +86,11 @@ const TorrentList: FC = observer(() => { if (isCondensed) { torrentListHeading = ( { + if (listViewportOuterRef.current != null && listHeaderRef.current != null) { + listViewportOuterRef.current.scrollLeft = listHeaderRef.current.scrollLeft; + } + }} onCellClick={(property: TorrentListColumn) => { const currentSort = SettingStore.floodSettings.sortTorrents; @@ -101,10 +106,6 @@ const TorrentList: FC = observer(() => { }; SettingActions.saveSetting('sortTorrents', sortBy); - - if (listViewportOuterRef.current != null && listHeaderRef.current != null) { - listViewportOuterRef.current.scrollLeft = listHeaderRef.current.scrollLeft; - } }} onWidthsChange={(column: TorrentListColumn, width: number) => { const {torrentListColumnWidths = defaultFloodSettings.torrentListColumnWidths} = SettingStore.floodSettings;