Convert <Button> to Typescript (#27492)
				
					
				
			This commit is contained in:
		
							parent
							
								
									ab0fb81479
								
							
						
					
					
						commit
						9d45a444f9
					
				| @ -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('<Button />', () => { | ||||
|   it('renders a button element', () => { | ||||
|  | ||||
| @ -15,7 +15,7 @@ import { VerifiedBadge } from 'mastodon/components/verified_badge'; | ||||
| import { me } from '../initial_state'; | ||||
| 
 | ||||
| import { Avatar } from './avatar'; | ||||
| import Button from './button'; | ||||
| import { Button } from './button'; | ||||
| import { FollowersCounter } from './counters'; | ||||
| import { DisplayName } from './display_name'; | ||||
| import { IconButton } from './icon_button'; | ||||
|  | ||||
| @ -1,58 +0,0 @@ | ||||
| import PropTypes from 'prop-types'; | ||||
| import { PureComponent } from 'react'; | ||||
| 
 | ||||
| import classNames from 'classnames'; | ||||
| 
 | ||||
| export default class Button extends PureComponent { | ||||
| 
 | ||||
|   static propTypes = { | ||||
|     text: PropTypes.node, | ||||
|     type: PropTypes.string, | ||||
|     onClick: PropTypes.func, | ||||
|     disabled: PropTypes.bool, | ||||
|     block: PropTypes.bool, | ||||
|     secondary: PropTypes.bool, | ||||
|     className: PropTypes.string, | ||||
|     title: PropTypes.string, | ||||
|     children: PropTypes.node, | ||||
|   }; | ||||
| 
 | ||||
|   static defaultProps = { | ||||
|     type: 'button', | ||||
|   }; | ||||
| 
 | ||||
|   handleClick = (e) => { | ||||
|     if (!this.props.disabled && this.props.onClick) { | ||||
|       this.props.onClick(e); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   setRef = (c) => { | ||||
|     this.node = c; | ||||
|   }; | ||||
| 
 | ||||
|   focus() { | ||||
|     this.node.focus(); | ||||
|   } | ||||
| 
 | ||||
|   render () { | ||||
|     const className = classNames('button', this.props.className, { | ||||
|       'button-secondary': this.props.secondary, | ||||
|       'button--block': this.props.block, | ||||
|     }); | ||||
| 
 | ||||
|     return ( | ||||
|       <button | ||||
|         className={className} | ||||
|         disabled={this.props.disabled} | ||||
|         onClick={this.handleClick} | ||||
|         ref={this.setRef} | ||||
|         title={this.props.title} | ||||
|         type={this.props.type} | ||||
|       > | ||||
|         {this.props.text || this.props.children} | ||||
|       </button> | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										58
									
								
								app/javascript/mastodon/components/button.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								app/javascript/mastodon/components/button.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,58 @@ | ||||
| import { useCallback } from 'react'; | ||||
| 
 | ||||
| import classNames from 'classnames'; | ||||
| 
 | ||||
| interface BaseProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { | ||||
|   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<Props> = ({ | ||||
|   text, | ||||
|   type = 'button', | ||||
|   onClick, | ||||
|   disabled, | ||||
|   block, | ||||
|   secondary, | ||||
|   className, | ||||
|   title, | ||||
|   children, | ||||
|   ...props | ||||
| }) => { | ||||
|   const handleClick = useCallback<React.MouseEventHandler<HTMLButtonElement>>( | ||||
|     (e) => { | ||||
|       if (!disabled && onClick) { | ||||
|         onClick(e); | ||||
|       } | ||||
|     }, | ||||
|     [disabled, onClick], | ||||
|   ); | ||||
| 
 | ||||
|   return ( | ||||
|     <button | ||||
|       className={classNames('button', className, { | ||||
|         'button-secondary': secondary, | ||||
|         'button--block': block, | ||||
|       })} | ||||
|       disabled={disabled} | ||||
|       onClick={handleClick} | ||||
|       title={title} | ||||
|       type={type} | ||||
|       {...props} | ||||
|     > | ||||
|       {text ?? children} | ||||
|     </button> | ||||
|   ); | ||||
| }; | ||||
| @ -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'; | ||||
|  | ||||
| @ -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 }) => ({ | ||||
|  | ||||
| @ -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'; | ||||
|  | ||||
| @ -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'; | ||||
|  | ||||
| @ -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 }) => ({ | ||||
|  | ||||
| @ -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({ | ||||
|  | ||||
| @ -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'; | ||||
| 
 | ||||
|  | ||||
| @ -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' }, | ||||
|  | ||||
| @ -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'; | ||||
| 
 | ||||
|  | ||||
| @ -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'; | ||||
| 
 | ||||
|  | ||||
| @ -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({ | ||||
|  | ||||
| @ -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'; | ||||
| 
 | ||||
|  | ||||
| @ -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'; | ||||
| 
 | ||||
|  | ||||
| @ -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 = () => ({}); | ||||
| 
 | ||||
|  | ||||
| @ -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'; | ||||
|  | ||||
| @ -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 { | ||||
|           <Button onClick={this.handleSecondary} className='confirmation-modal__secondary-button'> | ||||
|             <FormattedMessage id='confirmations.block.block_and_report' defaultMessage='Block & Report' /> | ||||
|           </Button> | ||||
|           <Button onClick={this.handleClick} ref={this.setRef}> | ||||
|           <Button onClick={this.handleClick} autoFocus> | ||||
|             <FormattedMessage id='confirmations.block.confirm' defaultMessage='Block' /> | ||||
|           </Button> | ||||
|         </div> | ||||
|  | ||||
| @ -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} | ||||
|             /> | ||||
|           )} | ||||
|           <Button text={intl.formatMessage(buttonText)} onClick={this.handleReblog} ref={this.setRef} /> | ||||
|           <Button text={intl.formatMessage(buttonText)} onClick={this.handleReblog} autoFocus /> | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|  | ||||
| @ -7,7 +7,7 @@ import classNames from 'classnames'; | ||||
| import { Helmet } from 'react-helmet'; | ||||
| import { Link } from 'react-router-dom'; | ||||
| 
 | ||||
| import Button from 'mastodon/components/button'; | ||||
| import { Button } from 'mastodon/components/button'; | ||||
| import Column from 'mastodon/components/column'; | ||||
| import { autoPlayGif } from 'mastodon/initial_state'; | ||||
| 
 | ||||
|  | ||||
| @ -3,7 +3,7 @@ import { PureComponent } from 'react'; | ||||
| 
 | ||||
| import { injectIntl, FormattedMessage } from 'react-intl'; | ||||
| 
 | ||||
| import Button from '../../../components/button'; | ||||
| import { Button } from '../../../components/button'; | ||||
| 
 | ||||
| class ConfirmationModal extends PureComponent { | ||||
| 
 | ||||
| @ -22,10 +22,6 @@ class ConfirmationModal extends PureComponent { | ||||
|     closeWhenConfirm: true, | ||||
|   }; | ||||
| 
 | ||||
|   componentDidMount() { | ||||
|     this.button.focus(); | ||||
|   } | ||||
| 
 | ||||
|   handleClick = () => { | ||||
|     if (this.props.closeWhenConfirm) { | ||||
|       this.props.onClose(); | ||||
| @ -42,10 +38,6 @@ class ConfirmationModal extends PureComponent { | ||||
|     this.props.onClose(); | ||||
|   }; | ||||
| 
 | ||||
|   setRef = (c) => { | ||||
|     this.button = c; | ||||
|   }; | ||||
| 
 | ||||
|   render () { | ||||
|     const { message, confirm, secondary } = this.props; | ||||
| 
 | ||||
| @ -62,7 +54,7 @@ class ConfirmationModal extends PureComponent { | ||||
|           {secondary !== undefined && ( | ||||
|             <Button text={secondary} onClick={this.handleSecondary} className='confirmation-modal__secondary-button' /> | ||||
|           )} | ||||
|           <Button text={confirm} onClick={this.handleClick} ref={this.setRef} /> | ||||
|           <Button text={confirm} onClick={this.handleClick} autoFocus /> | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|  | ||||
| @ -16,7 +16,7 @@ import tesseractWorkerPath from 'tesseract.js/dist/worker.min.js'; | ||||
| // eslint-disable-next-line import/no-extraneous-dependencies | ||||
| import tesseractCorePath from 'tesseract.js-core/tesseract-core.wasm.js'; | ||||
| 
 | ||||
| import Button from 'mastodon/components/button'; | ||||
| import { Button } from 'mastodon/components/button'; | ||||
| import { GIFV } from 'mastodon/components/gifv'; | ||||
| import { IconButton } from 'mastodon/components/icon_button'; | ||||
| import Audio from 'mastodon/features/audio'; | ||||
|  | ||||
| @ -10,7 +10,7 @@ import Toggle from 'react-toggle'; | ||||
| import { muteAccount } from '../../../actions/accounts'; | ||||
| import { closeModal } from '../../../actions/modal'; | ||||
| import { toggleHideNotifications, changeMuteDuration } from '../../../actions/mutes'; | ||||
| import Button from '../../../components/button'; | ||||
| import { Button } from '../../../components/button'; | ||||
| 
 | ||||
| const messages = defineMessages({ | ||||
|   minutes: { id: 'intervals.full.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}}' }, | ||||
| @ -63,10 +63,6 @@ class MuteModal extends PureComponent { | ||||
|     onChangeMuteDuration: PropTypes.func.isRequired, | ||||
|   }; | ||||
| 
 | ||||
|   componentDidMount() { | ||||
|     this.button.focus(); | ||||
|   } | ||||
| 
 | ||||
|   handleClick = () => { | ||||
|     this.props.onClose(); | ||||
|     this.props.onConfirm(this.props.account, this.props.notifications, this.props.muteDuration); | ||||
| @ -76,10 +72,6 @@ class MuteModal extends PureComponent { | ||||
|     this.props.onClose(); | ||||
|   }; | ||||
| 
 | ||||
|   setRef = (c) => { | ||||
|     this.button = c; | ||||
|   }; | ||||
| 
 | ||||
|   toggleNotifications = () => { | ||||
|     this.props.onToggleNotifications(); | ||||
|   }; | ||||
| @ -134,7 +126,7 @@ class MuteModal extends PureComponent { | ||||
|           <Button onClick={this.handleCancel} className='mute-modal__cancel-button'> | ||||
|             <FormattedMessage id='confirmation_modal.cancel' defaultMessage='Cancel' /> | ||||
|           </Button> | ||||
|           <Button onClick={this.handleClick} ref={this.setRef}> | ||||
|           <Button onClick={this.handleClick} autoFocus> | ||||
|             <FormattedMessage id='confirmations.mute.confirm' defaultMessage='Mute' /> | ||||
|           </Button> | ||||
|         </div> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user