diff --git a/app/soapbox/components/account.tsx b/app/soapbox/components/account.tsx index db8d4b306..006584e8d 100644 --- a/app/soapbox/components/account.tsx +++ b/app/soapbox/components/account.tsx @@ -9,7 +9,6 @@ import { getAcct } from 'soapbox/utils/accounts'; import { displayFqn } from 'soapbox/utils/state'; import RelativeTimestamp from './relative-timestamp'; -import StopPropagation from './stop-propagation'; import { Avatar, Emoji, HStack, Icon, IconButton, Stack, Text } from './ui'; import type { Account as AccountEntity } from 'soapbox/types/entities'; @@ -22,6 +21,8 @@ const InstanceFavicon: React.FC = ({ account }) => { const history = useHistory(); const handleClick: React.MouseEventHandler = (e) => { + e.stopPropagation(); + const timelineUrl = `/timeline/${account.domain}`; if (!(e.ctrlKey || e.metaKey)) { history.push(timelineUrl); @@ -166,100 +167,106 @@ const Account = ({ const LinkEl: any = withLinkToProfile ? Link : 'div'; return ( - -
- - +
+ + + {children}} + > + event.stopPropagation()} + > + + {emoji && ( + + )} + + + +
{children}} + wrapper={(children) => {children}} > - - - {emoji && ( - event.stopPropagation()} + > +
+ - )} + + {account.verified && } +
-
- {children}} - > - -
- - - {account.verified && } -
-
-
- - - - @{username} - - {account.favicon && ( - - )} - - {(timestamp) ? ( - <> - · - - {timestampUrl ? ( - - - - ) : ( - - )} - - ) : null} - - {showEdit ? ( - <> - · + + + @{username} - - - ) : null} - - {actionType === 'muting' && account.mute_expires_at ? ( - <> - · - - - - ) : null} - - - {withAccountNote && ( - + {account.favicon && ( + )} - -
- -
- {withRelationship ? renderAction() : null} + {(timestamp) ? ( + <> + · + + {timestampUrl ? ( + event.stopPropagation()}> + + + ) : ( + + )} + + ) : null} + + {showEdit ? ( + <> + · + + + + ) : null} + + {actionType === 'muting' && account.mute_expires_at ? ( + <> + · + + + + ) : null} + + + {withAccountNote && ( + + )} +
-
- + +
+ {withRelationship ? renderAction() : null} +
+
+
); }; diff --git a/app/soapbox/components/polls/poll.tsx b/app/soapbox/components/polls/poll.tsx index 2df985b7e..2b6f99392 100644 --- a/app/soapbox/components/polls/poll.tsx +++ b/app/soapbox/components/polls/poll.tsx @@ -5,7 +5,6 @@ import { openModal } from 'soapbox/actions/modals'; import { vote } from 'soapbox/actions/polls'; import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; -import StopPropagation from '../stop-propagation'; import { Stack, Text } from '../ui'; import PollFooter from './poll-footer'; @@ -65,7 +64,8 @@ const Poll: React.FC = ({ id, status }): JSX.Element | null => { const showResults = poll.voted || poll.expired; return ( - + // eslint-disable-next-line jsx-a11y/no-static-element-interactions +
e.stopPropagation()}> {!showResults && poll.multiple && ( {intl.formatMessage(messages.multiple)} @@ -93,7 +93,7 @@ const Poll: React.FC = ({ id, status }): JSX.Element | null => { selected={selected} /> - +
); }; diff --git a/app/soapbox/components/quoted-status.tsx b/app/soapbox/components/quoted-status.tsx index 925f2115e..2c976bf86 100644 --- a/app/soapbox/components/quoted-status.tsx +++ b/app/soapbox/components/quoted-status.tsx @@ -13,7 +13,6 @@ import OutlineBox from './outline-box'; import StatusContent from './status-content'; import StatusReplyMentions from './status-reply-mentions'; import SensitiveContentOverlay from './statuses/sensitive-content-overlay'; -import StopPropagation from './stop-propagation'; import type { Account as AccountEntity, Status as StatusEntity } from 'soapbox/types/entities'; @@ -92,60 +91,58 @@ const QuotedStatus: React.FC = ({ status, onCancel, compose }) => } return ( - - + + + + + - - - - - - {(status.hidden) && ( - + )} + + + + + {(status.card || status.media_attachments.size > 0) && ( + )} - - - - - {(status.card || status.media_attachments.size > 0) && ( - - )} - - - + + ); }; diff --git a/app/soapbox/components/status-action-bar.tsx b/app/soapbox/components/status-action-bar.tsx index 54c181c71..6735c1b29 100644 --- a/app/soapbox/components/status-action-bar.tsx +++ b/app/soapbox/components/status-action-bar.tsx @@ -530,8 +530,6 @@ const StatusActionBar: React.FC = ({ justifyContent={space === 'expand' ? 'between' : undefined} space={space === 'compact' ? 2 : undefined} grow={space === 'expand'} - onMouseUp={e => e.stopPropagation()} - onMouseDown={e => e.stopPropagation()} onClick={e => e.stopPropagation()} > = ({ onClick }) => ( - - - + ); interface IStatusContent { @@ -100,10 +97,6 @@ const StatusContent: React.FC = ({ status, onClick, collapsable link.setAttribute('title', link.href); link.addEventListener('click', onLinkClick.bind(link), false); } - - // Prevent bubbling - link.addEventListener('mouseup', e => e.stopPropagation()); - link.addEventListener('mousedown', e => e.stopPropagation()); }); }; diff --git a/app/soapbox/components/status-media.tsx b/app/soapbox/components/status-media.tsx index f3d418d30..3dc625c4d 100644 --- a/app/soapbox/components/status-media.tsx +++ b/app/soapbox/components/status-media.tsx @@ -2,7 +2,6 @@ import React, { useState } from 'react'; import { openModal } from 'soapbox/actions/modals'; import AttachmentThumbs from 'soapbox/components/attachment-thumbs'; -import StopPropagation from 'soapbox/components/stop-propagation'; import PlaceholderCard from 'soapbox/features/placeholder/components/placeholder-card'; import Card from 'soapbox/features/status/components/card'; import Bundle from 'soapbox/features/ui/components/bundle'; @@ -176,9 +175,10 @@ const StatusMedia: React.FC = ({ if (media) { return ( - + // eslint-disable-next-line jsx-a11y/no-static-element-interactions +
e.stopPropagation()}> {media} - +
); } else { return null; diff --git a/app/soapbox/components/status-reply-mentions.tsx b/app/soapbox/components/status-reply-mentions.tsx index 3adde6b65..0964c84ae 100644 --- a/app/soapbox/components/status-reply-mentions.tsx +++ b/app/soapbox/components/status-reply-mentions.tsx @@ -5,7 +5,6 @@ import { Link } from 'react-router-dom'; import { openModal } from 'soapbox/actions/modals'; import HoverRefWrapper from 'soapbox/components/hover-ref-wrapper'; import HoverStatusWrapper from 'soapbox/components/hover-status-wrapper'; -import StopPropagation from 'soapbox/components/stop-propagation'; import { useAppDispatch } from 'soapbox/hooks'; import type { Account, Status } from 'soapbox/types/entities'; @@ -19,6 +18,8 @@ const StatusReplyMentions: React.FC = ({ status, hoverable const dispatch = useAppDispatch(); const handleOpenMentionsModal: React.MouseEventHandler = (e) => { + e.stopPropagation(); + const account = status.account as Account; dispatch(openModal('MENTIONS', { @@ -49,7 +50,7 @@ const StatusReplyMentions: React.FC = ({ status, hoverable // The typical case with a reply-to and a list of mentions. const accounts = to.slice(0, 2).map(account => { const link = ( - @{account.username} + e.stopPropagation()}>@{account.username} ); if (hoverable) { @@ -72,34 +73,32 @@ const StatusReplyMentions: React.FC = ({ status, hoverable } return ( - -
- , - hover: (children: React.ReactNode) => { - if (hoverable) { - return ( - - - {children} - - - ); - } else { - return children; - } - }, - }} - /> -
-
+
+ , + hover: (children: React.ReactNode) => { + if (hoverable) { + return ( + + + {children} + + + ); + } else { + return children; + } + }, + }} + /> +
); }; diff --git a/app/soapbox/components/status.tsx b/app/soapbox/components/status.tsx index 31af2cbaa..2d31f6fc1 100644 --- a/app/soapbox/components/status.tsx +++ b/app/soapbox/components/status.tsx @@ -235,8 +235,7 @@ const Status: React.FC = (props) => { reblogElement = ( e.stopPropagation()} - onMouseUp={e => e.stopPropagation()} + onClick={(event) => event.stopPropagation()} className='hidden sm:flex items-center text-gray-700 dark:text-gray-600 text-xs font-medium space-x-1 hover:underline' > @@ -259,8 +258,7 @@ const Status: React.FC = (props) => {
e.stopPropagation()} - onMouseUp={e => e.stopPropagation()} + onClick={(event) => event.stopPropagation()} className='flex items-center text-gray-700 dark:text-gray-600 text-xs font-medium space-x-1 hover:underline' > @@ -328,7 +326,7 @@ const Status: React.FC = (props) => { data-featured={featured ? 'true' : null} aria-label={textForScreenReader(intl, actualStatus, rebloggedByText)} ref={node} - onMouseUp={handleClick} + onClick={handleClick} role='link' > {featured && ( diff --git a/app/soapbox/components/statuses/sensitive-content-overlay.tsx b/app/soapbox/components/statuses/sensitive-content-overlay.tsx index 21411bf5c..59faef161 100644 --- a/app/soapbox/components/statuses/sensitive-content-overlay.tsx +++ b/app/soapbox/components/statuses/sensitive-content-overlay.tsx @@ -5,7 +5,6 @@ import { defineMessages, useIntl } from 'react-intl'; import { useSettings, useSoapboxConfig } from 'soapbox/hooks'; import { defaultMediaVisibility } from 'soapbox/utils/status'; -import StopPropagation from '../stop-propagation'; import { Button, HStack, Text } from '../ui'; import type { Status as StatusEntity } from 'soapbox/types/entities'; @@ -39,7 +38,9 @@ const SensitiveContentOverlay = React.forwardRef(defaultMediaVisibility(status, displayMedia)); - const toggleVisibility = () => { + const toggleVisibility = (event: React.MouseEvent) => { + event.stopPropagation(); + if (onToggleVisibility) { onToggleVisibility(); } else { @@ -63,15 +64,13 @@ const SensitiveContentOverlay = React.forwardRef {visible ? ( - - - - )} - - ) : null} - - - + {isUnderReview ? ( + <> + {links.get('support') && ( + event.stopPropagation()} + > + + + )} + + ) : null} + +
)} diff --git a/app/soapbox/components/stop-propagation.tsx b/app/soapbox/components/stop-propagation.tsx deleted file mode 100644 index f8eff7b4e..000000000 --- a/app/soapbox/components/stop-propagation.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import React from 'react'; - -interface IStopPropagation { - /** Children to render within the bubble. */ - children: React.ReactNode, - /** Whether to prevent mouse events from bubbling. (default: `true`) */ - enabled?: boolean, -} - -/** - * Prevent mouse events from bubbling up. - * - * Why is this needed? Because `onClick`, `onMouseDown`, and `onMouseUp` are 3 separate events. - * To prevent a lot of code duplication, this component can stop all mouse events. - * Plus, placing it in the component tree makes it more readable. - */ -const StopPropagation: React.FC = ({ children, enabled = true }) => { - - const handler: React.MouseEventHandler = (e) => { - if (enabled) { - e.stopPropagation(); - } - }; - - return ( - // eslint-disable-next-line jsx-a11y/no-static-element-interactions -
- {children} -
- ); -}; - -export default StopPropagation; \ No newline at end of file diff --git a/app/soapbox/components/translate-button.tsx b/app/soapbox/components/translate-button.tsx index 7c40a4a14..07c778fd2 100644 --- a/app/soapbox/components/translate-button.tsx +++ b/app/soapbox/components/translate-button.tsx @@ -4,7 +4,6 @@ import { FormattedMessage, useIntl } from 'react-intl'; import { translateStatus, undoStatusTranslation } from 'soapbox/actions/statuses'; import { useAppDispatch, useAppSelector, useFeatures } from 'soapbox/hooks'; -import StopPropagation from './stop-propagation'; import { Stack } from './ui'; import type { Status } from 'soapbox/types/entities'; @@ -43,21 +42,17 @@ const TranslateButton: React.FC = ({ status }) => { - - - + ); } return ( - - - + ); }; diff --git a/app/soapbox/components/ui/button/button.tsx b/app/soapbox/components/ui/button/button.tsx index 1b0528efb..97de8862b 100644 --- a/app/soapbox/components/ui/button/button.tsx +++ b/app/soapbox/components/ui/button/button.tsx @@ -8,7 +8,7 @@ import { useButtonStyles } from './useButtonStyles'; import type { ButtonSizes, ButtonThemes } from './useButtonStyles'; -interface IButton extends Pick, 'onClick' | 'onMouseUp'> { +interface IButton { /** Whether this button expands the width of its container. */ block?: boolean, /** Elements inside the