diff --git a/app/javascript/flavours/glitch/components/column.jsx b/app/javascript/flavours/glitch/components/column.jsx deleted file mode 100644 index 22d6eabed7..0000000000 --- a/app/javascript/flavours/glitch/components/column.jsx +++ /dev/null @@ -1,73 +0,0 @@ -import PropTypes from 'prop-types'; -import { PureComponent } from 'react'; - -import { supportsPassiveEvents } from 'detect-passive-events'; - -import { scrollTop } from '../scroll'; - -const listenerOptions = supportsPassiveEvents ? { passive: true } : false; - -export default class Column extends PureComponent { - - static propTypes = { - children: PropTypes.node, - extraClasses: PropTypes.string, - label: PropTypes.string, - bindToDocument: PropTypes.bool, - }; - - scrollTop () { - let scrollable = null; - - if (this.props.bindToDocument) { - scrollable = document.scrollingElement; - } else { - scrollable = this.node.querySelector('.scrollable'); - } - - if (!scrollable) { - return; - } - - this._interruptScrollAnimation = scrollTop(scrollable); - } - - handleWheel = () => { - if (typeof this._interruptScrollAnimation !== 'function') { - return; - } - - this._interruptScrollAnimation(); - }; - - setRef = c => { - this.node = c; - }; - - componentDidMount () { - if (this.props.bindToDocument) { - document.addEventListener('wheel', this.handleWheel, listenerOptions); - } else { - this.node.addEventListener('wheel', this.handleWheel, listenerOptions); - } - } - - componentWillUnmount () { - if (this.props.bindToDocument) { - document.removeEventListener('wheel', this.handleWheel, listenerOptions); - } else { - this.node.removeEventListener('wheel', this.handleWheel, listenerOptions); - } - } - - render () { - const { label, children, extraClasses } = this.props; - - return ( -
- {children} -
- ); - } - -} diff --git a/app/javascript/flavours/glitch/components/column.tsx b/app/javascript/flavours/glitch/components/column.tsx new file mode 100644 index 0000000000..0830b89f8e --- /dev/null +++ b/app/javascript/flavours/glitch/components/column.tsx @@ -0,0 +1,52 @@ +import { forwardRef, useRef, useImperativeHandle } from 'react'; +import type { Ref } from 'react'; + +import { scrollTop } from 'flavours/glitch/scroll'; + +export interface ColumnRef { + scrollTop: () => void; + node: HTMLDivElement | null; +} + +interface ColumnProps { + children?: React.ReactNode; + label?: string; + bindToDocument?: boolean; +} + +export const Column = forwardRef( + ({ children, label, bindToDocument }, ref: Ref) => { + const nodeRef = useRef(null); + + useImperativeHandle(ref, () => ({ + node: nodeRef.current, + + scrollTop() { + let scrollable = null; + + if (bindToDocument) { + scrollable = document.scrollingElement; + } else { + scrollable = nodeRef.current?.querySelector('.scrollable'); + } + + if (!scrollable) { + return; + } + + scrollTop(scrollable); + }, + })); + + return ( +
+ {children} +
+ ); + }, +); + +Column.displayName = 'Column'; + +// eslint-disable-next-line import/no-default-export +export default Column; diff --git a/app/javascript/flavours/glitch/features/directory/index.tsx b/app/javascript/flavours/glitch/features/directory/index.tsx index 150adee94e..2c438ddb32 100644 --- a/app/javascript/flavours/glitch/features/directory/index.tsx +++ b/app/javascript/flavours/glitch/features/directory/index.tsx @@ -18,7 +18,8 @@ import { fetchDirectory, expandDirectory, } from 'flavours/glitch/actions/directory'; -import Column from 'flavours/glitch/components/column'; +import { Column } from 'flavours/glitch/components/column'; +import type { ColumnRef } from 'flavours/glitch/components/column'; import { ColumnHeader } from 'flavours/glitch/components/column_header'; import { LoadMore } from 'flavours/glitch/components/load_more'; import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator'; @@ -52,7 +53,7 @@ export const Directory: React.FC<{ const intl = useIntl(); const dispatch = useAppDispatch(); - const column = useRef(null); + const column = useRef(null); const [orderParam, setOrderParam] = useSearchParam('order'); const [localParam, setLocalParam] = useSearchParam('local'); diff --git a/app/javascript/flavours/glitch/features/link_timeline/index.tsx b/app/javascript/flavours/glitch/features/link_timeline/index.tsx index 2a5ae9a156..883835e2f0 100644 --- a/app/javascript/flavours/glitch/features/link_timeline/index.tsx +++ b/app/javascript/flavours/glitch/features/link_timeline/index.tsx @@ -5,7 +5,8 @@ import { useParams } from 'react-router-dom'; import ExploreIcon from '@/material-icons/400-24px/explore.svg?react'; import { expandLinkTimeline } from 'flavours/glitch/actions/timelines'; -import Column from 'flavours/glitch/components/column'; +import { Column } from 'flavours/glitch/components/column'; +import type { ColumnRef } from 'flavours/glitch/components/column'; import { ColumnHeader } from 'flavours/glitch/components/column_header'; import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container'; import type { Card } from 'flavours/glitch/models/status'; @@ -17,7 +18,7 @@ export const LinkTimeline: React.FC<{ const { url } = useParams<{ url: string }>(); const decodedUrl = url ? decodeURIComponent(url) : undefined; const dispatch = useAppDispatch(); - const columnRef = useRef(null); + const columnRef = useRef(null); const firstStatusId = useAppSelector((state) => decodedUrl ? // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access diff --git a/app/javascript/flavours/glitch/features/lists/index.tsx b/app/javascript/flavours/glitch/features/lists/index.tsx index b014688e72..1608553b70 100644 --- a/app/javascript/flavours/glitch/features/lists/index.tsx +++ b/app/javascript/flavours/glitch/features/lists/index.tsx @@ -11,7 +11,7 @@ import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; import SquigglyArrow from '@/svg-icons/squiggly_arrow.svg?react'; import { fetchLists } from 'flavours/glitch/actions/lists'; import { openModal } from 'flavours/glitch/actions/modal'; -import Column from 'flavours/glitch/components/column'; +import { Column } from 'flavours/glitch/components/column'; import { ColumnHeader } from 'flavours/glitch/components/column_header'; import { Icon } from 'flavours/glitch/components/icon'; import ScrollableList from 'flavours/glitch/components/scrollable_list'; diff --git a/app/javascript/flavours/glitch/features/lists/members.tsx b/app/javascript/flavours/glitch/features/lists/members.tsx index 7edabacc27..3187f302f6 100644 --- a/app/javascript/flavours/glitch/features/lists/members.tsx +++ b/app/javascript/flavours/glitch/features/lists/members.tsx @@ -20,7 +20,7 @@ import { import type { ApiAccountJSON } from 'flavours/glitch/api_types/accounts'; import { Avatar } from 'flavours/glitch/components/avatar'; import { Button } from 'flavours/glitch/components/button'; -import Column from 'flavours/glitch/components/column'; +import { Column } from 'flavours/glitch/components/column'; import { ColumnHeader } from 'flavours/glitch/components/column_header'; import { ColumnSearchHeader } from 'flavours/glitch/components/column_search_header'; import { FollowersCounter } from 'flavours/glitch/components/counters'; diff --git a/app/javascript/flavours/glitch/features/lists/new.tsx b/app/javascript/flavours/glitch/features/lists/new.tsx index 6832b72628..42c5fa57f3 100644 --- a/app/javascript/flavours/glitch/features/lists/new.tsx +++ b/app/javascript/flavours/glitch/features/lists/new.tsx @@ -14,7 +14,7 @@ import { fetchList } from 'flavours/glitch/actions/lists'; import { createList, updateList } from 'flavours/glitch/actions/lists_typed'; import { apiGetAccounts } from 'flavours/glitch/api/lists'; import type { RepliesPolicyType } from 'flavours/glitch/api_types/lists'; -import Column from 'flavours/glitch/components/column'; +import { Column } from 'flavours/glitch/components/column'; import { ColumnHeader } from 'flavours/glitch/components/column_header'; import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator'; import { useAppDispatch, useAppSelector } from 'flavours/glitch/store'; diff --git a/app/javascript/flavours/glitch/features/notifications_v2/index.tsx b/app/javascript/flavours/glitch/features/notifications_v2/index.tsx index b51d2cc1fd..18269ca42a 100644 --- a/app/javascript/flavours/glitch/features/notifications_v2/index.tsx +++ b/app/javascript/flavours/glitch/features/notifications_v2/index.tsx @@ -36,7 +36,8 @@ import { useAppDispatch, useAppSelector } from 'flavours/glitch/store'; import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; import { submitMarkers } from '../../actions/markers'; -import Column from '../../components/column'; +import { Column } from '../../components/column'; +import type { ColumnRef } from '../../components/column'; import { ColumnHeader } from '../../components/column_header'; import { LoadGap } from '../../components/load_gap'; import ScrollableList from '../../components/scrollable_list'; @@ -96,7 +97,7 @@ export const Notifications: React.FC<{ selectNeedsNotificationPermission, ); - const columnRef = useRef(null); + const columnRef = useRef(null); const selectChild = useCallback((index: number, alignTop: boolean) => { const container = columnRef.current?.node as HTMLElement | undefined; diff --git a/app/javascript/flavours/glitch/features/onboarding/follows.tsx b/app/javascript/flavours/glitch/features/onboarding/follows.tsx index b2db43361b..935ad102e8 100644 --- a/app/javascript/flavours/glitch/features/onboarding/follows.tsx +++ b/app/javascript/flavours/glitch/features/onboarding/follows.tsx @@ -14,7 +14,7 @@ import { fetchSuggestions } from 'flavours/glitch/actions/suggestions'; import { markAsPartial } from 'flavours/glitch/actions/timelines'; import { apiRequest } from 'flavours/glitch/api'; import type { ApiAccountJSON } from 'flavours/glitch/api_types/accounts'; -import Column from 'flavours/glitch/components/column'; +import { Column } from 'flavours/glitch/components/column'; import { ColumnHeader } from 'flavours/glitch/components/column_header'; import { ColumnSearchHeader } from 'flavours/glitch/components/column_search_header'; import ScrollableList from 'flavours/glitch/components/scrollable_list'; diff --git a/app/javascript/flavours/glitch/features/onboarding/profile.tsx b/app/javascript/flavours/glitch/features/onboarding/profile.tsx index d90b328170..41fbdea1ab 100644 --- a/app/javascript/flavours/glitch/features/onboarding/profile.tsx +++ b/app/javascript/flavours/glitch/features/onboarding/profile.tsx @@ -13,7 +13,7 @@ import EditIcon from '@/material-icons/400-24px/edit.svg?react'; import PersonIcon from '@/material-icons/400-24px/person.svg?react'; import { updateAccount } from 'flavours/glitch/actions/accounts'; import { Button } from 'flavours/glitch/components/button'; -import Column from 'flavours/glitch/components/column'; +import { Column } from 'flavours/glitch/components/column'; import { ColumnHeader } from 'flavours/glitch/components/column_header'; import { Icon } from 'flavours/glitch/components/icon'; import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator'; diff --git a/app/javascript/flavours/glitch/features/ui/components/column_loading.tsx b/app/javascript/flavours/glitch/features/ui/components/column_loading.tsx index aa6d105dcc..2fad8700f5 100644 --- a/app/javascript/flavours/glitch/features/ui/components/column_loading.tsx +++ b/app/javascript/flavours/glitch/features/ui/components/column_loading.tsx @@ -1,4 +1,4 @@ -import Column from 'flavours/glitch/components/column'; +import { Column } from 'flavours/glitch/components/column'; import { ColumnHeader } from 'flavours/glitch/components/column_header'; import type { Props as ColumnHeaderProps } from 'flavours/glitch/components/column_header';