diff --git a/app/javascript/mastodon/components/account_header/fields.tsx b/app/javascript/mastodon/components/account_header/fields.tsx index e949f848f46..ba8c9f39f88 100644 --- a/app/javascript/mastodon/components/account_header/fields.tsx +++ b/app/javascript/mastodon/components/account_header/fields.tsx @@ -220,7 +220,7 @@ const FieldHTML: FC = ({ }; function useColumnWrap() { - const listRef = useRef(null); + const listRef = useRef(null); const handleRecalculate = useCallback(() => { const listEle = listRef.current; @@ -330,7 +330,7 @@ function useFieldOverflow() { const [isLabelOverflowing, setIsLabelOverflowing] = useState(false); const [isValueOverflowing, setIsValueOverflowing] = useState(false); - const wrapperRef = useRef(null); + const wrapperRef = useRef(null); const handleRecalculate = useCallback(() => { const wrapperEle = wrapperRef.current; diff --git a/app/javascript/mastodon/components/account_header/name.tsx b/app/javascript/mastodon/components/account_header/name.tsx index 5bd2ed80dbe..e66affae1bb 100644 --- a/app/javascript/mastodon/components/account_header/name.tsx +++ b/app/javascript/mastodon/components/account_header/name.tsx @@ -111,7 +111,7 @@ const AccountNameHelp: FC<{ } onHide={handleClick} offset={[5, 5]} > diff --git a/app/javascript/mastodon/components/account_header/subscription_form.tsx b/app/javascript/mastodon/components/account_header/subscription_form.tsx index e09e7d4b145..346f8181f30 100644 --- a/app/javascript/mastodon/components/account_header/subscription_form.tsx +++ b/app/javascript/mastodon/components/account_header/subscription_form.tsx @@ -90,7 +90,7 @@ export const AccountSubscriptionForm: React.FC<{ accountId: string }> = ({ [], ); - const handleSubmit = useCallback( + const handleSubmit = useCallback( (e) => { e.preventDefault(); diff --git a/app/javascript/mastodon/components/alt_text_badge/index.tsx b/app/javascript/mastodon/components/alt_text_badge/index.tsx index a33325dee53..535ba3d1b68 100644 --- a/app/javascript/mastodon/components/alt_text_badge/index.tsx +++ b/app/javascript/mastodon/components/alt_text_badge/index.tsx @@ -64,7 +64,7 @@ export const AltTextBadge: React.FC<{ rootClose onHide={handleClose} show={open} - target={buttonRef} + target={buttonRef as React.RefObject} placement='top-end' flip offset={offset} diff --git a/app/javascript/mastodon/components/carousel/index.tsx b/app/javascript/mastodon/components/carousel/index.tsx index bc287aa9691..391e7fa7c5e 100644 --- a/app/javascript/mastodon/components/carousel/index.tsx +++ b/app/javascript/mastodon/components/carousel/index.tsx @@ -106,7 +106,7 @@ export const Carousel = < [items.length, onChangeSlide], ); - const observerRef = useRef(null); + const observerRef = useRef(null); observerRef.current ??= new ResizeObserver(() => { handleSlideChange(0); }); @@ -235,7 +235,7 @@ const CarouselSlideWrapper = ({ className={className} role='group' aria-roledescription='slide' - inert={active ? undefined : ''} + inert={active} data-index={index} > {children} diff --git a/app/javascript/mastodon/components/dropdown/index.tsx b/app/javascript/mastodon/components/dropdown/index.tsx index 4edc78f50b8..eec14bdc529 100644 --- a/app/javascript/mastodon/components/dropdown/index.tsx +++ b/app/javascript/mastodon/components/dropdown/index.tsx @@ -109,7 +109,7 @@ export const Dropdown: FC< placement='bottom-start' onHide={handleClose} flip - target={buttonRef} + target={buttonRef as React.RefObject} popperConfig={{ strategy: 'fixed', modifiers: [matchWidth], diff --git a/app/javascript/mastodon/components/dropdown_menu.tsx b/app/javascript/mastodon/components/dropdown_menu.tsx index 107b256e183..7394ad56384 100644 --- a/app/javascript/mastodon/components/dropdown_menu.tsx +++ b/app/javascript/mastodon/components/dropdown_menu.tsx @@ -352,7 +352,7 @@ export const Dropdown = ({ ); const [currentId] = useState(id++); const open = currentId === openDropdownId; - const buttonRef = useRef(null); + const buttonRef = useRef(null); const menuId = useId(); const prefetchAccountId = status ? status.getIn(['account', 'id']) @@ -518,7 +518,7 @@ export const Dropdown = ({ offset={offset} placement={placement} flip - target={buttonRef} + target={buttonRef as React.RefObject} popperConfig={popperConfig} > {({ props, arrowProps, placement }) => ( diff --git a/app/javascript/mastodon/components/form_fields/checkbox_field.tsx b/app/javascript/mastodon/components/form_fields/checkbox_field.tsx index c08b81ca36d..78bbb32e4fe 100644 --- a/app/javascript/mastodon/components/form_fields/checkbox_field.tsx +++ b/app/javascript/mastodon/components/form_fields/checkbox_field.tsx @@ -30,7 +30,7 @@ CheckboxField.displayName = 'CheckboxField'; export const Checkbox = forwardRef( ({ className, size, indeterminate, ...otherProps }, ref) => { - const inputRef = useRef(null); + const inputRef = useRef(null); const handleRef = useCallback( (element: HTMLInputElement | null) => { diff --git a/app/javascript/mastodon/components/form_fields/combobox_field.tsx b/app/javascript/mastodon/components/form_fields/combobox_field.tsx index 9c7d2595717..5fcc1ce70f9 100644 --- a/app/javascript/mastodon/components/form_fields/combobox_field.tsx +++ b/app/javascript/mastodon/components/form_fields/combobox_field.tsx @@ -236,7 +236,7 @@ const ComboboxWithRef = ( ) => { const intl = useIntl(); const wrapperRef = useRef(null); - const inputRef = useRef(); + const inputRef = useRef(null); const popoverRef = useRef(null); // This ref tracks whether the menu was just closed following a @@ -558,7 +558,7 @@ const ComboboxWithRef = ( onHide={closeMenu} ref={popoverRef} target={inputRef as React.RefObject} - container={wrapperRef} + container={wrapperRef as React.RefObject} popperConfig={{ modifiers: [matchWidth], }} diff --git a/app/javascript/mastodon/components/form_fields/copy_link_field.tsx b/app/javascript/mastodon/components/form_fields/copy_link_field.tsx index ab8849d45aa..062a9074a3b 100644 --- a/app/javascript/mastodon/components/form_fields/copy_link_field.tsx +++ b/app/javascript/mastodon/components/form_fields/copy_link_field.tsx @@ -26,7 +26,7 @@ export const CopyLinkField = forwardRef( ref, ) => { const intl = useIntl(); - const inputRef = useRef(); + const inputRef = useRef(null); const handleFocus = useCallback(() => { inputRef.current?.select(); }, []); diff --git a/app/javascript/mastodon/components/form_fields/emoji_text_field.tsx b/app/javascript/mastodon/components/form_fields/emoji_text_field.tsx index 6e65d22fc73..874ec91f79d 100644 --- a/app/javascript/mastodon/components/form_fields/emoji_text_field.tsx +++ b/app/javascript/mastodon/components/form_fields/emoji_text_field.tsx @@ -120,7 +120,7 @@ const EmojiFieldWrapper: FC< children: ( inputProps: InputProps & { onChange: ChangeEventHandler }, ) => ReactNode; - inputRef: RefObject; + inputRef: RefObject; } > = ({ value, diff --git a/app/javascript/mastodon/components/hotkeys/index.tsx b/app/javascript/mastodon/components/hotkeys/index.tsx index 246255dcbef..e8390b72557 100644 --- a/app/javascript/mastodon/components/hotkeys/index.tsx +++ b/app/javascript/mastodon/components/hotkeys/index.tsx @@ -184,7 +184,7 @@ export type HandlerMap = Partial>; export function useHotkeys(handlers: HandlerMap) { const ref = useRef(null); const bufferedKeys = useRef([]); - const sequenceTimer = useRef | null>(null); + const sequenceTimer = useRef>(null); /** * Store the latest handlers object in a ref so we don't need to diff --git a/app/javascript/mastodon/components/hover_card_controller.tsx b/app/javascript/mastodon/components/hover_card_controller.tsx index 9f89bafe78d..44ee6bedd69 100644 --- a/app/javascript/mastodon/components/hover_card_controller.tsx +++ b/app/javascript/mastodon/components/hover_card_controller.tsx @@ -27,7 +27,7 @@ export const HoverCardController: React.FC = () => { const [open, setOpen] = useState(false); const [accountId, setAccountId] = useState(); const [anchor, setAnchor] = useState(null); - const cardRef = useRef(null); + const cardRef = useRef(null); const [setLeaveTimeout, cancelLeaveTimeout] = useTimeout(); const [setEnterTimeout, cancelEnterTimeout, delayEnterTimeout] = useTimeout(); const [setScrollTimeout] = useTimeout(); diff --git a/app/javascript/mastodon/components/learn_more_link.tsx b/app/javascript/mastodon/components/learn_more_link.tsx index 8d22bb7a3ba..a721ad27472 100644 --- a/app/javascript/mastodon/components/learn_more_link.tsx +++ b/app/javascript/mastodon/components/learn_more_link.tsx @@ -9,7 +9,7 @@ export const LearnMoreLink: React.FC<{ children: React.ReactNode }> = ({ }) => { const accessibilityId = useId(); const [open, setOpen] = useState(false); - const triggerRef = useRef(null); + const triggerRef = useRef(null); const handleClick = useCallback(() => { setOpen(!open); @@ -37,7 +37,7 @@ export const LearnMoreLink: React.FC<{ children: React.ReactNode }> = ({ onHide={handleClick} offset={[5, 5]} placement='bottom-end' - target={triggerRef} + target={triggerRef as React.RefObject} > {({ props }) => (
| null>(null); +const FocusTargetContext = createContext | null>( + null, +); /** * `FocusTargetProvider` keeps track of whether focus should be diff --git a/app/javascript/mastodon/components/status_action_bar/remove_quote_hint.tsx b/app/javascript/mastodon/components/status_action_bar/remove_quote_hint.tsx index cfa72feb684..ba3cdf0ac11 100644 --- a/app/javascript/mastodon/components/status_action_bar/remove_quote_hint.tsx +++ b/app/javascript/mastodon/components/status_action_bar/remove_quote_hint.tsx @@ -65,8 +65,8 @@ export const RemoveQuoteHint: React.FC<{ flip offset={[12, 10]} placement='bottom-end' - target={anchorRef} - container={anchorRef} + target={anchorRef as React.RefObject} + container={anchorRef as React.RefObject} > {({ props, placement }) => (
= ({ }) => { const scrollBehaviorContext = useContext(ScrollBehaviorContext); - const containerRef = useRef(); + const containerRef = useRef(null); /** * If a childRef is passed, sync it with the containerRef. This * is necessary because in this component's return statement, * we're overwriting the immediate child component's ref prop. */ - useImperativeHandle(childRef, () => containerRef.current, []); + useImperativeHandle(childRef, () => containerRef.current ?? undefined, []); /** * Register/unregister scrollable element with ScrollBehavior @@ -71,6 +72,10 @@ export const ScrollContainer: React.FC = ({ }, []); return React.Children.only( - React.cloneElement(children, { ref: containerRef }), + isValidElement<{ + ref: React.RefObject; + }>(children) + ? React.cloneElement(children, { ref: containerRef }) + : children, ); }; diff --git a/app/javascript/mastodon/features/account_timeline/components/featured_tags.tsx b/app/javascript/mastodon/features/account_timeline/components/featured_tags.tsx index c4d43bb2b9f..7fd271b7f62 100644 --- a/app/javascript/mastodon/features/account_timeline/components/featured_tags.tsx +++ b/app/javascript/mastodon/features/account_timeline/components/featured_tags.tsx @@ -56,7 +56,7 @@ export const FeaturedTags: FC<{ accountId: string }> = ({ accountId }) => { 0 && index >= hiddenIndex ? '' : undefined} + inert={hiddenIndex > 0 && index >= hiddenIndex} onClick={onClick} active={currentTag === name} data-name={name} diff --git a/app/javascript/mastodon/features/account_timeline/components/filters.tsx b/app/javascript/mastodon/features/account_timeline/components/filters.tsx index e24ca642093..ebbf1032618 100644 --- a/app/javascript/mastodon/features/account_timeline/components/filters.tsx +++ b/app/javascript/mastodon/features/account_timeline/components/filters.tsx @@ -99,11 +99,11 @@ const FilterDropdown: FC = () => { } placement='bottom-start' rootClose onHide={handleHide} - container={containerRef} + container={containerRef as React.RefObject} > {({ props }) => (
{ placement='top' onHide={handleClick} offset={[5, 5]} - target={triggerRef} + target={triggerRef as React.RefObject} > {({ props }) => (
void; }> = ({ mediaId, position, onPositionChange }) => { - const nodeRef = useRef(null); + const nodeRef = useRef(null); const [dragging, setDragging] = useState<'started' | 'moving' | null>(null); diff --git a/app/javascript/mastodon/features/audio/index.tsx b/app/javascript/mastodon/features/audio/index.tsx index fa0d976377c..07633f84d75 100644 --- a/app/javascript/mastodon/features/audio/index.tsx +++ b/app/javascript/mastodon/features/audio/index.tsx @@ -114,10 +114,10 @@ export const Audio: React.FC<{ const [revealed, setRevealed] = useState(false); const playerRef = useRef(null); - const audioRef = useRef(null); + const audioRef = useRef(null); const seekRef = useRef(null); const volumeRef = useRef(null); - const hoverTimeoutRef = useRef | null>(); + const hoverTimeoutRef = useRef>(null); const { audioContextRef, sourceRef, gainNodeRef, playAudio, pauseAudio } = useAudioContext({ audioElementRef: audioRef }); diff --git a/app/javascript/mastodon/features/collections/detail/index.tsx b/app/javascript/mastodon/features/collections/detail/index.tsx index 98ce518cf5f..a2d328e539c 100644 --- a/app/javascript/mastodon/features/collections/detail/index.tsx +++ b/app/javascript/mastodon/features/collections/detail/index.tsx @@ -170,7 +170,7 @@ const SensitiveContentNote: React.FC<{ onReveal: () => void }> = ({ const CollectionHeader: React.FC<{ collection: ApiCollectionJSON; withDescription: boolean; - headingRef: React.RefObject; + headingRef: React.RefObject; }> = ({ collection, withDescription, headingRef }) => { const intl = useIntl(); const { name, description, tag, account_id, items } = collection; diff --git a/app/javascript/mastodon/features/collections/editor/accounts.tsx b/app/javascript/mastodon/features/collections/editor/accounts.tsx index 78acd6a7209..0ead92b1c7e 100644 --- a/app/javascript/mastodon/features/collections/editor/accounts.tsx +++ b/app/javascript/mastodon/features/collections/editor/accounts.tsx @@ -1,3 +1,4 @@ +import type React from 'react'; import { useCallback, useId, useMemo, useState } from 'react'; import { FormattedMessage, useIntl } from 'react-intl'; @@ -339,8 +340,8 @@ export const CollectionAccounts: React.FC<{ [addAccountItem, instantAddAccountItem, isEditMode, resetAccounts], ); - const handleSubmit = useCallback( - (e: React.FormEvent) => { + const handleSubmit: React.SubmitEventHandler = useCallback( + (e) => { e.preventDefault(); if (!id) { diff --git a/app/javascript/mastodon/features/collections/editor/details.tsx b/app/javascript/mastodon/features/collections/editor/details.tsx index 7fe25245c43..117ec821164 100644 --- a/app/javascript/mastodon/features/collections/editor/details.tsx +++ b/app/javascript/mastodon/features/collections/editor/details.tsx @@ -1,3 +1,4 @@ +import type React from 'react'; import { useCallback, useMemo } from 'react'; import { FormattedMessage, useIntl } from 'react-intl'; @@ -108,8 +109,8 @@ export const CollectionDetails: React.FC = () => { const accountId = useCurrentAccountId(); const { acct: currentUserName } = useAccount(accountId) ?? {}; - const handleSubmit = useCallback( - (e: React.FormEvent) => { + const handleSubmit: React.SubmitEventHandler = useCallback( + (e) => { e.preventDefault(); if (id) { diff --git a/app/javascript/mastodon/features/compose/components/language_dropdown.tsx b/app/javascript/mastodon/features/compose/components/language_dropdown.tsx index 8f75c3dd09f..44641c9ed74 100644 --- a/app/javascript/mastodon/features/compose/components/language_dropdown.tsx +++ b/app/javascript/mastodon/features/compose/components/language_dropdown.tsx @@ -328,8 +328,8 @@ export const LanguageDropdown: React.FC = () => { const [open, setOpen] = useState(false); const [placement, setPlacement] = useState('bottom'); const [guess, setGuess] = useState(''); - const activeElementRef = useRef(null); - const targetRef = useRef(null); + const activeElementRef = useRef(null); + const targetRef = useRef(null); const intl = useIntl(); @@ -421,7 +421,7 @@ export const LanguageDropdown: React.FC = () => { offset={[5, 5]} placement={placement} flip - target={targetRef} + target={targetRef as React.RefObject} popperConfig={{ strategy: 'fixed', onFirstUpdate: handleOverlayEnter }} > {({ props, placement }) => ( diff --git a/app/javascript/mastodon/features/compose/components/privacy_dropdown.tsx b/app/javascript/mastodon/features/compose/components/privacy_dropdown.tsx index 5a463d86e79..5f698bef601 100644 --- a/app/javascript/mastodon/features/compose/components/privacy_dropdown.tsx +++ b/app/javascript/mastodon/features/compose/components/privacy_dropdown.tsx @@ -70,8 +70,8 @@ const PrivacyDropdown: React.FC = ({ disabled, }) => { const intl = useIntl(); - const overlayTargetRef = useRef(null); - const previousFocusTargetRef = useRef(null); + const overlayTargetRef = useRef(null); + const previousFocusTargetRef = useRef(null); const [isOpen, setIsOpen] = useState(false); const handleClose = useCallback(() => { @@ -171,7 +171,7 @@ const PrivacyDropdown: React.FC = ({ offset={[5, 5]} placement='bottom' flip - target={overlayTargetRef} + target={overlayTargetRef as React.RefObject} container={container} popperConfig={{ strategy: 'fixed' }} > diff --git a/app/javascript/mastodon/features/emoji/emoji_picker.tsx b/app/javascript/mastodon/features/emoji/emoji_picker.tsx index 15adf9fdc80..2e4441e4d0c 100644 --- a/app/javascript/mastodon/features/emoji/emoji_picker.tsx +++ b/app/javascript/mastodon/features/emoji/emoji_picker.tsx @@ -51,15 +51,16 @@ export const Emoji: FC = ({ const { mode } = useEmojiAppState(); return ( ); diff --git a/app/javascript/mastodon/features/interaction_modal/index.tsx b/app/javascript/mastodon/features/interaction_modal/index.tsx index 128fb3ff5e1..4e8707e5d59 100644 --- a/app/javascript/mastodon/features/interaction_modal/index.tsx +++ b/app/javascript/mastodon/features/interaction_modal/index.tsx @@ -153,7 +153,7 @@ const LoginForm: React.FC<{ const inputRef = useRef(null); const iframeRef = useRef(null); - const searchRequestRef = useRef(null); + const searchRequestRef = useRef(null); useEffect(() => { const handleMessage = (event: MessageEvent) => { diff --git a/app/javascript/mastodon/features/navigation_panel/index.tsx b/app/javascript/mastodon/features/navigation_panel/index.tsx index da5041ff4fb..1eb268a6018 100644 --- a/app/javascript/mastodon/features/navigation_panel/index.tsx +++ b/app/javascript/mastodon/features/navigation_panel/index.tsx @@ -429,7 +429,7 @@ export const CollapsibleNavigationPanel: React.FC = () => { const dispatch = useAppDispatch(); const openable = useBreakpoint('openable'); const location = useLocation(); - const overlayRef = useRef(null); + const overlayRef = useRef(null); useEffect(() => { dispatch(closeNavigation()); @@ -515,7 +515,7 @@ export const CollapsibleNavigationPanel: React.FC = () => { }, ); - const previouslyFocusedElementRef = useRef(); + const previouslyFocusedElementRef = useRef(null); useEffect(() => { if (open) { diff --git a/app/javascript/mastodon/features/notifications/components/select_with_label.tsx b/app/javascript/mastodon/features/notifications/components/select_with_label.tsx index 0b755702d93..8b260cf73d5 100644 --- a/app/javascript/mastodon/features/notifications/components/select_with_label.tsx +++ b/app/javascript/mastodon/features/notifications/components/select_with_label.tsx @@ -86,7 +86,7 @@ const Dropdown: React.FC = ({ offset={[5, 5]} placement={placement} flip - target={containerRef} + target={containerRef as React.RefObject} popperConfig={{ strategy: 'fixed', onFirstUpdate: handleOverlayEnter }} > {({ props, placement }) => ( diff --git a/app/javascript/mastodon/features/notifications_v2/components/embedded_status.tsx b/app/javascript/mastodon/features/notifications_v2/components/embedded_status.tsx index e8a55bb3389..5a783ecc38c 100644 --- a/app/javascript/mastodon/features/notifications_v2/components/embedded_status.tsx +++ b/app/javascript/mastodon/features/notifications_v2/components/embedded_status.tsx @@ -26,7 +26,7 @@ export const EmbeddedStatus: React.FC<{ statusId: string }> = ({ statusId, }) => { const history = useHistory(); - const clickCoordinatesRef = useRef<[number, number] | null>(); + const clickCoordinatesRef = useRef<[number, number]>(null); const dispatch = useAppDispatch(); const status = useAppSelector((state) => state.statuses.get(statusId)); diff --git a/app/javascript/mastodon/features/notifications_v2/components/notification_severed_relationships.tsx b/app/javascript/mastodon/features/notifications_v2/components/notification_severed_relationships.tsx index fd92498ea3d..70f07eaa9c8 100644 --- a/app/javascript/mastodon/features/notifications_v2/components/notification_severed_relationships.tsx +++ b/app/javascript/mastodon/features/notifications_v2/components/notification_severed_relationships.tsx @@ -11,5 +11,6 @@ export const NotificationSeveredRelationships: React.FC<{ followersCount={event.followers_count} followingCount={event.following_count} unread={unread} + hidden={false} /> ); diff --git a/app/javascript/mastodon/features/onboarding/follows.tsx b/app/javascript/mastodon/features/onboarding/follows.tsx index 910d1051834..e79b4fe9884 100644 --- a/app/javascript/mastodon/features/onboarding/follows.tsx +++ b/app/javascript/mastodon/features/onboarding/follows.tsx @@ -61,7 +61,7 @@ export const Follows: React.FC<{ setIsSearching(false); }, [setMode, setIsSearching]); - const searchRequestRef = useRef(null); + const searchRequestRef = useRef(null); const handleSearch = useDebouncedCallback( (value: string) => { diff --git a/app/javascript/mastodon/features/status/components/detailed_status.tsx b/app/javascript/mastodon/features/status/components/detailed_status.tsx index ba0ce8b8c50..0463643c7a6 100644 --- a/app/javascript/mastodon/features/status/components/detailed_status.tsx +++ b/app/javascript/mastodon/features/status/components/detailed_status.tsx @@ -80,7 +80,7 @@ export const DetailedStatus: React.FC<{ const properStatus = status?.get('reblog') ?? status; const [height, setHeight] = useState(0); const [showDespiteFilter, setShowDespiteFilter] = useState(false); - const nodeRef = useRef(); + const nodeRef = useRef(null); const { signedIn } = useIdentity(); diff --git a/app/javascript/mastodon/features/ui/components/columns_area.tsx b/app/javascript/mastodon/features/ui/components/columns_area.tsx index cd94f34ec07..be91d5dccce 100644 --- a/app/javascript/mastodon/features/ui/components/columns_area.tsx +++ b/app/javascript/mastodon/features/ui/components/columns_area.tsx @@ -3,6 +3,7 @@ import { cloneElement, createContext, forwardRef, + isValidElement, useCallback, useContext, } from 'react'; @@ -179,7 +180,9 @@ export const ColumnsArea = forwardRef< {Children.map(children, (child) => - cloneElement(child, { multiColumn: true }), + isValidElement<{ multiColumn?: boolean }>(child) + ? cloneElement(child, { multiColumn: true }) + : child, )} diff --git a/app/javascript/mastodon/features/ui/components/embed_modal.tsx b/app/javascript/mastodon/features/ui/components/embed_modal.tsx index 29e83e47bbd..a6c87a33360 100644 --- a/app/javascript/mastodon/features/ui/components/embed_modal.tsx +++ b/app/javascript/mastodon/features/ui/components/embed_modal.tsx @@ -18,7 +18,7 @@ const EmbedModal: React.FC<{ onClose: () => void; }> = ({ id, onClose }) => { const iframeRef = useRef(null); - const intervalRef = useRef>(); + const intervalRef = useRef>(null); const [oembed, setOembed] = useState(null); const dispatch = useAppDispatch(); diff --git a/app/javascript/mastodon/features/ui/components/zoomable_image.tsx b/app/javascript/mastodon/features/ui/components/zoomable_image.tsx index 1297d243d0d..1eb374cca7a 100644 --- a/app/javascript/mastodon/features/ui/components/zoomable_image.tsx +++ b/app/javascript/mastodon/features/ui/components/zoomable_image.tsx @@ -120,8 +120,8 @@ export const ZoomableImage: React.FC = ({ const containerRef = useRef(null); const imageRef = useRef(null); - const doubleClickTimeoutRef = useRef | null>(); - const zoomMatrixRef = useRef(null); + const doubleClickTimeoutRef = useRef>(null); + const zoomMatrixRef = useRef(null); const [style, api] = useSpring(() => ({ x: 0, diff --git a/app/javascript/mastodon/features/video/index.tsx b/app/javascript/mastodon/features/video/index.tsx index 6721b5c96a2..7a6406885c1 100644 --- a/app/javascript/mastodon/features/video/index.tsx +++ b/app/javascript/mastodon/features/video/index.tsx @@ -225,11 +225,11 @@ export const Video: React.FC<{ const [hotkeyEvents, setHotkeyEvents] = useState([]); const playerRef = useRef(null); - const videoRef = useRef(null); + const videoRef = useRef(null); const seekRef = useRef(null); const volumeRef = useRef(null); - const doubleClickTimeoutRef = useRef | null>(); - const hoverTimeoutRef = useRef | null>(); + const doubleClickTimeoutRef = useRef>(null); + const hoverTimeoutRef = useRef>(null); const [style, api] = useSpring(() => ({ progress: '0%', diff --git a/app/javascript/mastodon/hooks/useAudioContext.ts b/app/javascript/mastodon/hooks/useAudioContext.ts index 2cad7ee3a53..65b20ff1012 100644 --- a/app/javascript/mastodon/hooks/useAudioContext.ts +++ b/app/javascript/mastodon/hooks/useAudioContext.ts @@ -1,7 +1,7 @@ import { useCallback, useEffect, useRef } from 'react'; interface AudioContextOptions { - audioElementRef: React.MutableRefObject; + audioElementRef: React.RefObject; } /** @@ -13,9 +13,9 @@ interface AudioContextOptions { */ export const useAudioContext = ({ audioElementRef }: AudioContextOptions) => { - const audioContextRef = useRef(); - const sourceRef = useRef(); - const gainNodeRef = useRef(); + const audioContextRef = useRef(null); + const sourceRef = useRef(null); + const gainNodeRef = useRef(null); useEffect(() => { if (!audioElementRef.current || typeof AudioContext === 'undefined') { diff --git a/app/javascript/mastodon/hooks/useAudioVisualizer.ts b/app/javascript/mastodon/hooks/useAudioVisualizer.ts index efc0647d8de..fefb1a2c4df 100644 --- a/app/javascript/mastodon/hooks/useAudioVisualizer.ts +++ b/app/javascript/mastodon/hooks/useAudioVisualizer.ts @@ -11,8 +11,8 @@ const normalizeFrequencies = (arr: Float32Array): number[] => { }; interface AudioVisualiserOptions { - audioContextRef: React.MutableRefObject; - sourceRef: React.MutableRefObject; + audioContextRef: React.RefObject; + sourceRef: React.RefObject; numBands: number; } @@ -21,7 +21,7 @@ export const useAudioVisualizer = ({ sourceRef, numBands, }: AudioVisualiserOptions) => { - const analyzerRef = useRef(); + const analyzerRef = useRef(null); const [frequencyBands, setFrequencyBands] = useState( new Array(numBands).fill(0), diff --git a/app/javascript/mastodon/hooks/useObserver.ts b/app/javascript/mastodon/hooks/useObserver.ts index 4b979f6d329..f7bd9454cff 100644 --- a/app/javascript/mastodon/hooks/useObserver.ts +++ b/app/javascript/mastodon/hooks/useObserver.ts @@ -1,7 +1,7 @@ import { useEffect, useRef } from 'react'; export function useResizeObserver(callback: ResizeObserverCallback) { - const observerRef = useRef(null); + const observerRef = useRef(null); observerRef.current ??= new ResizeObserver(callback); useEffect(() => { @@ -15,7 +15,7 @@ export function useResizeObserver(callback: ResizeObserverCallback) { } export function useMutationObserver(callback: MutationCallback) { - const observerRef = useRef(null); + const observerRef = useRef(null); observerRef.current ??= new MutationObserver(callback); useEffect(() => { diff --git a/app/javascript/mastodon/hooks/useOnClickOutside.ts b/app/javascript/mastodon/hooks/useOnClickOutside.ts index ad964978c86..788441e7d98 100644 --- a/app/javascript/mastodon/hooks/useOnClickOutside.ts +++ b/app/javascript/mastodon/hooks/useOnClickOutside.ts @@ -2,10 +2,10 @@ * Handle clicks that occur outside of the element(s) provided in the first parameter */ -import type { MutableRefObject } from 'react'; +import type { RefObject } from 'react'; import { useEffect } from 'react'; -type ElementRef = MutableRefObject; +type ElementRef = RefObject; export function useOnClickOutside( excludedElementRef: ElementRef | ElementRef[] | null, diff --git a/app/javascript/mastodon/hooks/useOverflow.ts b/app/javascript/mastodon/hooks/useOverflow.ts index b85222cf561..40d9cd0775f 100644 --- a/app/javascript/mastodon/hooks/useOverflow.ts +++ b/app/javascript/mastodon/hooks/useOverflow.ts @@ -1,4 +1,4 @@ -import type { MutableRefObject, RefCallback } from 'react'; +import type { RefObject, RefCallback } from 'react'; import { useState, useRef, useCallback, useEffect } from 'react'; import { useMutationObserver, useResizeObserver } from './useObserver'; @@ -20,7 +20,7 @@ export function useOverflowButton({ const [maxWidth, setMaxWidth] = useState('none'); // This is the item container element. - const listRef = useRef(null); + const listRef = useRef(null); // The main recalculation function. const handleRecalculate = useCallback(() => { @@ -102,7 +102,7 @@ export function useOverflowScroll({ const [canScrollLeft, setCanScrollLeft] = useState(false); const [canScrollRight, setCanScrollRight] = useState(false); - const bodyRef = useRef(null); + const bodyRef = useRef(null); // Recalculate scrollable state const handleRecalculate = useCallback(() => { @@ -176,13 +176,11 @@ export function useOverflowObservers({ onWrapperRef, }: { onRecalculate: () => void; - onListRef?: RefCallback | MutableRefObject; - onWrapperRef?: - | RefCallback - | MutableRefObject; + onListRef?: RefCallback | RefObject; + onWrapperRef?: RefCallback | RefObject; }) { // This is the item container element. - const listRef = useRef(null); + const listRef = useRef(null); const resizeObserver = useResizeObserver(onRecalculate); @@ -213,7 +211,7 @@ export function useOverflowObservers({ }, [handleChildrenChange, mutationObserver, resizeObserver]); // Watch the wrapper for size changes, and recalculate when it resizes. - const wrapperRef = useRef(null); + const wrapperRef = useRef(null); const wrapperRefCallback = useCallback( (node: HTMLElement | null) => { if (node) { diff --git a/app/javascript/mastodon/hooks/useSearchAccounts.ts b/app/javascript/mastodon/hooks/useSearchAccounts.ts index 1c26fe19ae3..7dac0ef7c5e 100644 --- a/app/javascript/mastodon/hooks/useSearchAccounts.ts +++ b/app/javascript/mastodon/hooks/useSearchAccounts.ts @@ -30,7 +30,7 @@ export function useSearchAccounts({ 'idle' | 'loading' | 'error' >('idle'); - const searchRequestRef = useRef(null); + const searchRequestRef = useRef(null); const searchAccounts = useDebouncedCallback( async (value: string) => { diff --git a/app/javascript/mastodon/hooks/useSearchTags.ts b/app/javascript/mastodon/hooks/useSearchTags.ts index 78fc85ed511..b55ad21c1ef 100644 --- a/app/javascript/mastodon/hooks/useSearchTags.ts +++ b/app/javascript/mastodon/hooks/useSearchTags.ts @@ -44,7 +44,7 @@ export function useSearchTags({ 'idle' | 'loading' | 'error' >('idle'); - const searchRequestRef = useRef(null); + const searchRequestRef = useRef(null); const searchTags = useDebouncedCallback( (value: string) => { diff --git a/app/javascript/mastodon/hooks/useSelectableClick.ts b/app/javascript/mastodon/hooks/useSelectableClick.ts index c8f16f0b0f1..10a589dafc0 100644 --- a/app/javascript/mastodon/hooks/useSelectableClick.ts +++ b/app/javascript/mastodon/hooks/useSelectableClick.ts @@ -6,7 +6,7 @@ export const useSelectableClick = ( onClick: React.MouseEventHandler, maxDelta = 5, ) => { - const clickPositionRef = useRef(null); + const clickPositionRef = useRef(null); const handleMouseDown = useCallback((e: React.MouseEvent) => { clickPositionRef.current = [e.clientX, e.clientY]; diff --git a/app/javascript/mastodon/hooks/useTimeout.ts b/app/javascript/mastodon/hooks/useTimeout.ts index bb1e8848dd5..285d98a4e8a 100644 --- a/app/javascript/mastodon/hooks/useTimeout.ts +++ b/app/javascript/mastodon/hooks/useTimeout.ts @@ -1,8 +1,8 @@ import { useRef, useCallback, useEffect } from 'react'; export const useTimeout = () => { - const timeoutRef = useRef>(); - const callbackRef = useRef<() => void>(); + const timeoutRef = useRef>(null); + const callbackRef = useRef<() => void>(null); const set = useCallback((callback: () => void, delay: number) => { if (timeoutRef.current) { @@ -28,8 +28,8 @@ export const useTimeout = () => { const cancel = useCallback(() => { if (timeoutRef.current) { clearTimeout(timeoutRef.current); - timeoutRef.current = undefined; - callbackRef.current = undefined; + timeoutRef.current = null; + callbackRef.current = null; } }, []); diff --git a/app/javascript/mastodon/utils/html.ts b/app/javascript/mastodon/utils/html.ts index c87b5a34cfc..c5d770ce798 100644 --- a/app/javascript/mastodon/utils/html.ts +++ b/app/javascript/mastodon/utils/html.ts @@ -20,7 +20,7 @@ interface AllowedTag { } type AllowedTagsType = { - [Tag in keyof React.ReactHTML]?: AllowedTag; + [Tag in keyof React.JSX.IntrinsicElements]?: AllowedTag; }; const globalAttributes: Record = htmlConfig.global; @@ -70,7 +70,7 @@ export function htmlStringToComponents>( const wrapper = document.createElement('template'); wrapper.innerHTML = htmlString; - const rootChildren: React.ReactNode[] = []; + const rootChildren: Awaited[] = []; const queue: QueueItem[] = [ { node: wrapper.content, parent: rootChildren, depth: 0 }, ]; diff --git a/app/javascript/types/dom.d.ts b/app/javascript/types/dom.d.ts deleted file mode 100644 index fcb1b0346fa..00000000000 --- a/app/javascript/types/dom.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare namespace React { - interface HTMLAttributes extends AriaAttributes, DOMAttributes { - // Add inert attribute support, which is only in React 19.2. See: https://github.com/facebook/react/pull/24730 - inert?: ''; - } -} diff --git a/package.json b/package.json index 8eda749d811..037970e2b5c 100644 --- a/package.json +++ b/package.json @@ -185,8 +185,6 @@ "vitest": "^4.1.7" }, "resolutions": { - "@types/react": "^18.2.7", - "@types/react-dom": "^18.2.4", "kind-of": "^6.0.3" }, "peerDependenciesMeta": { diff --git a/yarn.lock b/yarn.lock index 4c78c71aac3..8c4c8aa3b3e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4820,12 +4820,12 @@ __metadata: languageName: node linkType: hard -"@types/react-dom@npm:^18.2.4": - version: 18.3.7 - resolution: "@types/react-dom@npm:18.3.7" +"@types/react-dom@npm:^19.2.0": + version: 19.2.3 + resolution: "@types/react-dom@npm:19.2.3" peerDependencies: - "@types/react": ^18.0.0 - checksum: 10c0/8bd309e2c3d1604a28a736a24f96cbadf6c05d5288cfef8883b74f4054c961b6b3a5e997fd5686e492be903c8f3380dba5ec017eff3906b1256529cd2d39603e + "@types/react": ^19.2.0 + checksum: 10c0/b486ebe0f4e2fb35e2e108df1d8fc0927ca5d6002d5771e8a739de11239fe62d0e207c50886185253c99eb9dedfeeb956ea7429e5ba17f6693c7acb4c02f8cd1 languageName: node linkType: hard @@ -4878,13 +4878,12 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:^18.2.7": - version: 18.3.28 - resolution: "@types/react@npm:18.3.28" +"@types/react@npm:*, @types/react@npm:>=16.9.11, @types/react@npm:^19.2.0": + version: 19.2.17 + resolution: "@types/react@npm:19.2.17" dependencies: - "@types/prop-types": "npm:*" csstype: "npm:^3.2.2" - checksum: 10c0/683e19cd12b5c691215529af2e32b5ffbaccae3bf0ba93bfafa0e460e8dfee18423afed568be2b8eadf4b837c3749dd296a4f64e2d79f68fa66962c05f5af661 + checksum: 10c0/bc2c4af96b3e480604424de70d5ebda90c5f4b485df471858c0bc2d7d70364b606ec3c4d8579f94f01aa0c6c0591f56bcf14cba5689f5eea4b74250ccdc3a232 languageName: node linkType: hard