diff --git a/app/javascript/mastodon/components/__tests__/button-test.jsx b/app/javascript/mastodon/components/__tests__/button-test.jsx index 6de961f78..ad7a0c49c 100644 --- a/app/javascript/mastodon/components/__tests__/button-test.jsx +++ b/app/javascript/mastodon/components/__tests__/button-test.jsx @@ -1,7 +1,7 @@ import { render, fireEvent, screen } from '@testing-library/react'; import renderer from 'react-test-renderer'; -import Button from '../button'; +import { Button } from '../button'; describe(' - ); - } - -} diff --git a/app/javascript/mastodon/components/button.tsx b/app/javascript/mastodon/components/button.tsx new file mode 100644 index 000000000..0b6a0f267 --- /dev/null +++ b/app/javascript/mastodon/components/button.tsx @@ -0,0 +1,58 @@ +import { useCallback } from 'react'; + +import classNames from 'classnames'; + +interface BaseProps extends React.ButtonHTMLAttributes { + block?: boolean; + secondary?: boolean; + text?: JSX.Element; +} + +interface PropsWithChildren extends BaseProps { + text?: never; +} + +interface PropsWithText extends BaseProps { + text: JSX.Element; + children: never; +} + +type Props = PropsWithText | PropsWithChildren; + +export const Button: React.FC = ({ + text, + type = 'button', + onClick, + disabled, + block, + secondary, + className, + title, + children, + ...props +}) => { + const handleClick = useCallback>( + (e) => { + if (!disabled && onClick) { + onClick(e); + } + }, + [disabled, onClick], + ); + + return ( + + ); +}; diff --git a/app/javascript/mastodon/features/account/components/header.jsx b/app/javascript/mastodon/features/account/components/header.jsx index 7183f7af9..9425b25b7 100644 --- a/app/javascript/mastodon/features/account/components/header.jsx +++ b/app/javascript/mastodon/features/account/components/header.jsx @@ -11,7 +11,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component'; import { Avatar } from 'mastodon/components/avatar'; import { Badge, AutomatedBadge, GroupBadge } from 'mastodon/components/badge'; -import Button from 'mastodon/components/button'; +import { Button } from 'mastodon/components/button'; import { FollowersCounter, FollowingCounter, StatusesCounter } from 'mastodon/components/counters'; import { Icon } from 'mastodon/components/icon'; import { IconButton } from 'mastodon/components/icon_button'; diff --git a/app/javascript/mastodon/features/account_timeline/components/limited_account_hint.jsx b/app/javascript/mastodon/features/account_timeline/components/limited_account_hint.jsx index 4872455e9..59b735823 100644 --- a/app/javascript/mastodon/features/account_timeline/components/limited_account_hint.jsx +++ b/app/javascript/mastodon/features/account_timeline/components/limited_account_hint.jsx @@ -6,7 +6,7 @@ import { FormattedMessage } from 'react-intl'; import { connect } from 'react-redux'; import { revealAccount } from 'mastodon/actions/accounts'; -import Button from 'mastodon/components/button'; +import { Button } from 'mastodon/components/button'; import { domain } from 'mastodon/initial_state'; const mapDispatchToProps = (dispatch, { accountId }) => ({ diff --git a/app/javascript/mastodon/features/compose/components/compose_form.jsx b/app/javascript/mastodon/features/compose/components/compose_form.jsx index 5a680a68a..32b7c176d 100644 --- a/app/javascript/mastodon/features/compose/components/compose_form.jsx +++ b/app/javascript/mastodon/features/compose/components/compose_form.jsx @@ -14,7 +14,7 @@ import { WithOptionalRouterPropTypes, withOptionalRouter } from 'mastodon/utils/ import AutosuggestInput from '../../../components/autosuggest_input'; import AutosuggestTextarea from '../../../components/autosuggest_textarea'; -import Button from '../../../components/button'; +import { Button } from '../../../components/button'; import EmojiPickerDropdown from '../containers/emoji_picker_dropdown_container'; import LanguageDropdown from '../containers/language_dropdown_container'; import PollButtonContainer from '../containers/poll_button_container'; diff --git a/app/javascript/mastodon/features/directory/components/account_card.jsx b/app/javascript/mastodon/features/directory/components/account_card.jsx index 0306b63d3..a5e5717b3 100644 --- a/app/javascript/mastodon/features/directory/components/account_card.jsx +++ b/app/javascript/mastodon/features/directory/components/account_card.jsx @@ -17,7 +17,7 @@ import { } from 'mastodon/actions/accounts'; import { openModal } from 'mastodon/actions/modal'; import { Avatar } from 'mastodon/components/avatar'; -import Button from 'mastodon/components/button'; +import { Button } from 'mastodon/components/button'; import { DisplayName } from 'mastodon/components/display_name'; import { ShortNumber } from 'mastodon/components/short_number'; import { autoPlayGif, me, unfollowModal } from 'mastodon/initial_state'; diff --git a/app/javascript/mastodon/features/filters/added_to_filter.jsx b/app/javascript/mastodon/features/filters/added_to_filter.jsx index ec848f622..e341eddba 100644 --- a/app/javascript/mastodon/features/filters/added_to_filter.jsx +++ b/app/javascript/mastodon/features/filters/added_to_filter.jsx @@ -6,7 +6,7 @@ import { FormattedMessage } from 'react-intl'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { connect } from 'react-redux'; -import Button from 'mastodon/components/button'; +import { Button } from 'mastodon/components/button'; import { toServerSideType } from 'mastodon/utils/filters'; const mapStateToProps = (state, { filterId }) => ({ diff --git a/app/javascript/mastodon/features/hashtag_timeline/components/hashtag_header.jsx b/app/javascript/mastodon/features/hashtag_timeline/components/hashtag_header.jsx index 46050309f..d2fe8851f 100644 --- a/app/javascript/mastodon/features/hashtag_timeline/components/hashtag_header.jsx +++ b/app/javascript/mastodon/features/hashtag_timeline/components/hashtag_header.jsx @@ -4,7 +4,7 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePropTypes from 'react-immutable-proptypes'; -import Button from 'mastodon/components/button'; +import { Button } from 'mastodon/components/button'; import { ShortNumber } from 'mastodon/components/short_number'; const messages = defineMessages({ @@ -76,4 +76,4 @@ HashtagHeader.propTypes = { disabled: PropTypes.bool, onClick: PropTypes.func, intl: PropTypes.object, -}; \ No newline at end of file +}; diff --git a/app/javascript/mastodon/features/interaction_modal/index.jsx b/app/javascript/mastodon/features/interaction_modal/index.jsx index 69bbd8cd8..d79a3d415 100644 --- a/app/javascript/mastodon/features/interaction_modal/index.jsx +++ b/app/javascript/mastodon/features/interaction_modal/index.jsx @@ -11,7 +11,7 @@ import { throttle, escapeRegExp } from 'lodash'; import { openModal, closeModal } from 'mastodon/actions/modal'; import api from 'mastodon/api'; -import Button from 'mastodon/components/button'; +import { Button } from 'mastodon/components/button'; import { Icon } from 'mastodon/components/icon'; import { registrationsOpen, sso_redirect } from 'mastodon/initial_state'; diff --git a/app/javascript/mastodon/features/lists/components/new_list_form.jsx b/app/javascript/mastodon/features/lists/components/new_list_form.jsx index 40e2d4a1c..0fed9d70a 100644 --- a/app/javascript/mastodon/features/lists/components/new_list_form.jsx +++ b/app/javascript/mastodon/features/lists/components/new_list_form.jsx @@ -6,7 +6,7 @@ import { defineMessages, injectIntl } from 'react-intl'; import { connect } from 'react-redux'; import { changeListEditorTitle, submitListEditor } from 'mastodon/actions/lists'; -import Button from 'mastodon/components/button'; +import { Button } from 'mastodon/components/button'; const messages = defineMessages({ label: { id: 'lists.new.title_placeholder', defaultMessage: 'New list title' }, diff --git a/app/javascript/mastodon/features/notifications/components/notifications_permission_banner.jsx b/app/javascript/mastodon/features/notifications/components/notifications_permission_banner.jsx index 59b0335c1..9ce014d25 100644 --- a/app/javascript/mastodon/features/notifications/components/notifications_permission_banner.jsx +++ b/app/javascript/mastodon/features/notifications/components/notifications_permission_banner.jsx @@ -7,7 +7,7 @@ import { connect } from 'react-redux'; import { requestBrowserPermission } from 'mastodon/actions/notifications'; import { changeSetting } from 'mastodon/actions/settings'; -import Button from 'mastodon/components/button'; +import { Button } from 'mastodon/components/button'; import { Icon } from 'mastodon/components/icon'; import { IconButton } from 'mastodon/components/icon_button'; diff --git a/app/javascript/mastodon/features/report/category.jsx b/app/javascript/mastodon/features/report/category.jsx index fb9e55c57..a2fc3b23b 100644 --- a/app/javascript/mastodon/features/report/category.jsx +++ b/app/javascript/mastodon/features/report/category.jsx @@ -7,7 +7,7 @@ import { List as ImmutableList } from 'immutable'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { connect } from 'react-redux'; -import Button from 'mastodon/components/button'; +import { Button } from 'mastodon/components/button'; import Option from './components/option'; diff --git a/app/javascript/mastodon/features/report/comment.jsx b/app/javascript/mastodon/features/report/comment.jsx index ca9ea9d26..ec5974692 100644 --- a/app/javascript/mastodon/features/report/comment.jsx +++ b/app/javascript/mastodon/features/report/comment.jsx @@ -11,7 +11,7 @@ import { createSelector } from 'reselect'; import Toggle from 'react-toggle'; import { fetchAccount } from 'mastodon/actions/accounts'; -import Button from 'mastodon/components/button'; +import { Button } from 'mastodon/components/button'; import { useAppDispatch, useAppSelector } from 'mastodon/store'; const messages = defineMessages({ diff --git a/app/javascript/mastodon/features/report/rules.jsx b/app/javascript/mastodon/features/report/rules.jsx index 67d92839e..621f140ad 100644 --- a/app/javascript/mastodon/features/report/rules.jsx +++ b/app/javascript/mastodon/features/report/rules.jsx @@ -6,7 +6,7 @@ import { FormattedMessage } from 'react-intl'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { connect } from 'react-redux'; -import Button from 'mastodon/components/button'; +import { Button } from 'mastodon/components/button'; import Option from './components/option'; diff --git a/app/javascript/mastodon/features/report/statuses.jsx b/app/javascript/mastodon/features/report/statuses.jsx index 4ba8d6065..5e416f1e1 100644 --- a/app/javascript/mastodon/features/report/statuses.jsx +++ b/app/javascript/mastodon/features/report/statuses.jsx @@ -7,7 +7,7 @@ import { OrderedSet } from 'immutable'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { connect } from 'react-redux'; -import Button from 'mastodon/components/button'; +import { Button } from 'mastodon/components/button'; import { LoadingIndicator } from 'mastodon/components/loading_indicator'; import StatusCheckBox from 'mastodon/features/report/containers/status_check_box_container'; diff --git a/app/javascript/mastodon/features/report/thanks.jsx b/app/javascript/mastodon/features/report/thanks.jsx index 79ddc2e80..146d4b389 100644 --- a/app/javascript/mastodon/features/report/thanks.jsx +++ b/app/javascript/mastodon/features/report/thanks.jsx @@ -11,7 +11,7 @@ import { muteAccount, blockAccount, } from 'mastodon/actions/accounts'; -import Button from 'mastodon/components/button'; +import { Button } from 'mastodon/components/button'; const mapStateToProps = () => ({}); diff --git a/app/javascript/mastodon/features/subscribed_languages_modal/index.jsx b/app/javascript/mastodon/features/subscribed_languages_modal/index.jsx index eb128f68e..003f50183 100644 --- a/app/javascript/mastodon/features/subscribed_languages_modal/index.jsx +++ b/app/javascript/mastodon/features/subscribed_languages_modal/index.jsx @@ -9,7 +9,7 @@ import { connect } from 'react-redux'; import { createSelector } from 'reselect'; import { followAccount } from 'mastodon/actions/accounts'; -import Button from 'mastodon/components/button'; +import { Button } from 'mastodon/components/button'; import { IconButton } from 'mastodon/components/icon_button'; import Option from 'mastodon/features/report/components/option'; import { languages as preloadedLanguages } from 'mastodon/initial_state'; diff --git a/app/javascript/mastodon/features/ui/components/block_modal.jsx b/app/javascript/mastodon/features/ui/components/block_modal.jsx index 7cfd252e0..cfac69232 100644 --- a/app/javascript/mastodon/features/ui/components/block_modal.jsx +++ b/app/javascript/mastodon/features/ui/components/block_modal.jsx @@ -8,7 +8,7 @@ import { connect } from 'react-redux'; import { blockAccount } from '../../../actions/accounts'; import { closeModal } from '../../../actions/modal'; import { initReport } from '../../../actions/reports'; -import Button from '../../../components/button'; +import { Button } from '../../../components/button'; import { makeGetAccount } from '../../../selectors'; const makeMapStateToProps = () => { @@ -51,10 +51,6 @@ class BlockModal extends PureComponent { intl: PropTypes.object.isRequired, }; - componentDidMount() { - this.button.focus(); - } - handleClick = () => { this.props.onClose(); this.props.onConfirm(this.props.account); @@ -69,10 +65,6 @@ class BlockModal extends PureComponent { this.props.onClose(); }; - setRef = (c) => { - this.button = c; - }; - render () { const { account } = this.props; @@ -95,7 +87,7 @@ class BlockModal extends PureComponent { - diff --git a/app/javascript/mastodon/features/ui/components/boost_modal.jsx b/app/javascript/mastodon/features/ui/components/boost_modal.jsx index 9944bb164..91a77f883 100644 --- a/app/javascript/mastodon/features/ui/components/boost_modal.jsx +++ b/app/javascript/mastodon/features/ui/components/boost_modal.jsx @@ -16,7 +16,7 @@ import PrivacyDropdown from 'mastodon/features/compose/components/privacy_dropdo import { WithRouterPropTypes } from 'mastodon/utils/react_router'; import { Avatar } from '../../../components/avatar'; -import Button from '../../../components/button'; +import { Button } from '../../../components/button'; import { DisplayName } from '../../../components/display_name'; import { RelativeTimestamp } from '../../../components/relative_timestamp'; import StatusContent from '../../../components/status_content'; @@ -55,10 +55,6 @@ class BoostModal extends ImmutablePureComponent { ...WithRouterPropTypes, }; - componentDidMount() { - this.button.focus(); - } - handleReblog = () => { this.props.onReblog(this.props.status, this.props.privacy); this.props.onClose(); @@ -76,10 +72,6 @@ class BoostModal extends ImmutablePureComponent { return document.getElementsByClassName('modal-root__container')[0]; }; - setRef = (c) => { - this.button = c; - }; - render () { const { status, privacy, intl } = this.props; const buttonText = status.get('reblogged') ? messages.cancel_reblog : messages.reblog; @@ -133,7 +125,7 @@ class BoostModal extends ImmutablePureComponent { onChange={this.props.onChangeBoostPrivacy} /> )} - -