Convert (legacy?) IconButton to tsx, remove unused code/styles
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
27ad8dee64
commit
c692265249
|
@ -1,188 +0,0 @@
|
||||||
import classNames from 'clsx';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React from 'react';
|
|
||||||
import spring from 'react-motion/lib/spring';
|
|
||||||
|
|
||||||
import Icon from 'soapbox/components/icon';
|
|
||||||
import emojify from 'soapbox/features/emoji/emoji';
|
|
||||||
|
|
||||||
import Motion from '../features/ui/util/optional-motion';
|
|
||||||
|
|
||||||
export default class IconButton extends React.PureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
className: PropTypes.string,
|
|
||||||
iconClassName: PropTypes.string,
|
|
||||||
title: PropTypes.string.isRequired,
|
|
||||||
icon: PropTypes.string,
|
|
||||||
src: PropTypes.string,
|
|
||||||
onClick: PropTypes.func,
|
|
||||||
onMouseDown: PropTypes.func,
|
|
||||||
onKeyUp: PropTypes.func,
|
|
||||||
onKeyDown: PropTypes.func,
|
|
||||||
onKeyPress: PropTypes.func,
|
|
||||||
onMouseEnter: PropTypes.func,
|
|
||||||
onMouseLeave: PropTypes.func,
|
|
||||||
size: PropTypes.number,
|
|
||||||
active: PropTypes.bool,
|
|
||||||
pressed: PropTypes.bool,
|
|
||||||
expanded: PropTypes.bool,
|
|
||||||
style: PropTypes.object,
|
|
||||||
activeStyle: PropTypes.object,
|
|
||||||
disabled: PropTypes.bool,
|
|
||||||
inverted: PropTypes.bool,
|
|
||||||
animate: PropTypes.bool,
|
|
||||||
overlay: PropTypes.bool,
|
|
||||||
tabIndex: PropTypes.string,
|
|
||||||
text: PropTypes.string,
|
|
||||||
emoji: PropTypes.string,
|
|
||||||
type: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
size: 18,
|
|
||||||
active: false,
|
|
||||||
disabled: false,
|
|
||||||
animate: false,
|
|
||||||
overlay: false,
|
|
||||||
tabIndex: '0',
|
|
||||||
onKeyUp: () => {},
|
|
||||||
onKeyDown: () => {},
|
|
||||||
onClick: () => {},
|
|
||||||
onMouseEnter: () => {},
|
|
||||||
onMouseLeave: () => {},
|
|
||||||
type: 'button',
|
|
||||||
};
|
|
||||||
|
|
||||||
handleClick = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
if (!this.props.disabled) {
|
|
||||||
this.props.onClick(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleMouseDown = (e) => {
|
|
||||||
if (!this.props.disabled && this.props.onMouseDown) {
|
|
||||||
this.props.onMouseDown(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleKeyDown = (e) => {
|
|
||||||
if (!this.props.disabled && this.props.onKeyDown) {
|
|
||||||
this.props.onKeyDown(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleKeyUp = (e) => {
|
|
||||||
if (!this.props.disabled && this.props.onKeyUp) {
|
|
||||||
this.props.onKeyUp(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleKeyPress = (e) => {
|
|
||||||
if (this.props.onKeyPress && !this.props.disabled) {
|
|
||||||
this.props.onKeyPress(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const style = {
|
|
||||||
fontSize: `${this.props.size}px`,
|
|
||||||
width: `${this.props.size * 1.28571429}px`,
|
|
||||||
height: `${this.props.size * 1.28571429}px`,
|
|
||||||
lineHeight: `${this.props.size}px`,
|
|
||||||
...this.props.style,
|
|
||||||
...(this.props.active ? this.props.activeStyle : {}),
|
|
||||||
};
|
|
||||||
|
|
||||||
const {
|
|
||||||
active,
|
|
||||||
animate,
|
|
||||||
className,
|
|
||||||
iconClassName,
|
|
||||||
disabled,
|
|
||||||
expanded,
|
|
||||||
icon,
|
|
||||||
src,
|
|
||||||
inverted,
|
|
||||||
overlay,
|
|
||||||
pressed,
|
|
||||||
tabIndex,
|
|
||||||
title,
|
|
||||||
text,
|
|
||||||
emoji,
|
|
||||||
type,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const classes = classNames(className, 'icon-button', {
|
|
||||||
active,
|
|
||||||
disabled,
|
|
||||||
inverted,
|
|
||||||
overlayed: overlay,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!animate) {
|
|
||||||
// Perf optimization: avoid unnecessary <Motion> components unless
|
|
||||||
// we actually need to animate.
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
aria-label={title}
|
|
||||||
aria-pressed={pressed}
|
|
||||||
aria-expanded={expanded}
|
|
||||||
title={title}
|
|
||||||
className={classes}
|
|
||||||
onClick={this.handleClick}
|
|
||||||
onMouseDown={this.handleMouseDown}
|
|
||||||
onKeyDown={this.handleKeyDown}
|
|
||||||
onKeyUp={this.handleKeyUp}
|
|
||||||
onKeyPress={this.handleKeyPress}
|
|
||||||
onMouseEnter={this.props.onMouseEnter}
|
|
||||||
onMouseLeave={this.props.onMouseLeave}
|
|
||||||
tabIndex={tabIndex}
|
|
||||||
disabled={disabled}
|
|
||||||
type={type}
|
|
||||||
>
|
|
||||||
<div style={src ? {} : style}>
|
|
||||||
{emoji
|
|
||||||
? <div className='icon-button__emoji' dangerouslySetInnerHTML={{ __html: emojify(emoji) }} aria-hidden='true' />
|
|
||||||
: <Icon className={iconClassName} id={icon} src={src} fixedWidth aria-hidden='true' />}
|
|
||||||
</div>
|
|
||||||
{text && <span className='icon-button__text'>{text}</span>}
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Motion defaultStyle={{ rotate: active ? -360 : 0 }} style={{ rotate: animate ? spring(active ? -360 : 0, { stiffness: 120, damping: 7 }) : 0 }}>
|
|
||||||
{({ rotate }) => (
|
|
||||||
<button
|
|
||||||
aria-label={title}
|
|
||||||
aria-pressed={pressed}
|
|
||||||
aria-expanded={expanded}
|
|
||||||
title={title}
|
|
||||||
className={classes}
|
|
||||||
onClick={this.handleClick}
|
|
||||||
onMouseDown={this.handleMouseDown}
|
|
||||||
onKeyDown={this.handleKeyDown}
|
|
||||||
onKeyUp={this.handleKeyUp}
|
|
||||||
onKeyPress={this.handleKeyPress}
|
|
||||||
onMouseEnter={this.props.onMouseEnter}
|
|
||||||
onMouseLeave={this.props.onMouseLeave}
|
|
||||||
tabIndex={tabIndex}
|
|
||||||
disabled={disabled}
|
|
||||||
type={type}
|
|
||||||
>
|
|
||||||
<div style={src ? {} : style}>
|
|
||||||
{emoji
|
|
||||||
? <div className='icon-button__emoji' style={{ transform: `rotate(${rotate}deg)` }} dangerouslySetInnerHTML={{ __html: emojify(emoji) }} aria-hidden='true' />
|
|
||||||
: <Icon className={iconClassName} id={icon} src={src} style={{ transform: `rotate(${rotate}deg)` }} fixedWidth aria-hidden='true' />}
|
|
||||||
</div>
|
|
||||||
{text && <span className='icon-button__text'>{text}</span>}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</Motion>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
import classNames from 'clsx';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import Icon from 'soapbox/components/icon';
|
||||||
|
|
||||||
|
interface IIconButton extends Pick<React.ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'disabled' | 'onClick' | 'onKeyDown' | 'onKeyPress' | 'onKeyUp' | 'onMouseDown' | 'onMouseEnter' | 'onMouseLeave' | 'tabIndex' | 'title'> {
|
||||||
|
active?: boolean
|
||||||
|
expanded?: boolean
|
||||||
|
iconClassName?: string
|
||||||
|
pressed?: boolean
|
||||||
|
size?: number
|
||||||
|
src: string
|
||||||
|
text: React.ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
const IconButton: React.FC<IIconButton> = ({
|
||||||
|
active,
|
||||||
|
className,
|
||||||
|
disabled,
|
||||||
|
expanded,
|
||||||
|
iconClassName,
|
||||||
|
onClick,
|
||||||
|
onKeyDown,
|
||||||
|
onKeyUp,
|
||||||
|
onKeyPress,
|
||||||
|
onMouseDown,
|
||||||
|
onMouseEnter,
|
||||||
|
onMouseLeave,
|
||||||
|
pressed,
|
||||||
|
size = 18,
|
||||||
|
src,
|
||||||
|
tabIndex = 0,
|
||||||
|
text,
|
||||||
|
title,
|
||||||
|
}) => {
|
||||||
|
|
||||||
|
const handleClick: React.MouseEventHandler<HTMLButtonElement> = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (!disabled && onClick) {
|
||||||
|
onClick(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseDown: React.MouseEventHandler<HTMLButtonElement> = (e) => {
|
||||||
|
if (!disabled && onMouseDown) {
|
||||||
|
onMouseDown(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleKeyDown: React.KeyboardEventHandler<HTMLButtonElement> = (e) => {
|
||||||
|
if (!disabled && onKeyDown) {
|
||||||
|
onKeyDown(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleKeyUp: React.KeyboardEventHandler<HTMLButtonElement> = (e) => {
|
||||||
|
if (!disabled && onKeyUp) {
|
||||||
|
onKeyUp(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleKeyPress: React.KeyboardEventHandler<HTMLButtonElement> = (e) => {
|
||||||
|
if (onKeyPress && !disabled) {
|
||||||
|
onKeyPress(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const classes = classNames(className, 'icon-button', {
|
||||||
|
active,
|
||||||
|
disabled,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
aria-label={title}
|
||||||
|
aria-pressed={pressed}
|
||||||
|
aria-expanded={expanded}
|
||||||
|
title={title}
|
||||||
|
className={classes}
|
||||||
|
onClick={handleClick}
|
||||||
|
onMouseDown={handleMouseDown}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
onKeyUp={handleKeyUp}
|
||||||
|
onKeyPress={handleKeyPress}
|
||||||
|
onMouseEnter={onMouseEnter}
|
||||||
|
onMouseLeave={onMouseLeave}
|
||||||
|
tabIndex={tabIndex}
|
||||||
|
disabled={disabled}
|
||||||
|
type='button'
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<Icon className={iconClassName} src={src} fixedWidth aria-hidden='true' />
|
||||||
|
</div>
|
||||||
|
{text && <span className='icon-button__text'>{text}</span>}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default IconButton;
|
|
@ -1,36 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
interface ITextIconButton {
|
|
||||||
label: string,
|
|
||||||
title: string,
|
|
||||||
active: boolean,
|
|
||||||
onClick: () => void,
|
|
||||||
ariaControls: string,
|
|
||||||
unavailable: boolean,
|
|
||||||
}
|
|
||||||
|
|
||||||
const TextIconButton: React.FC<ITextIconButton> = ({
|
|
||||||
label,
|
|
||||||
title,
|
|
||||||
active,
|
|
||||||
ariaControls,
|
|
||||||
unavailable,
|
|
||||||
onClick,
|
|
||||||
}) => {
|
|
||||||
const handleClick: React.MouseEventHandler = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
onClick();
|
|
||||||
};
|
|
||||||
|
|
||||||
if (unavailable) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<button title={title} aria-label={title} className={`text-icon-button ${active ? 'active' : ''}`} aria-expanded={active} onClick={handleClick} aria-controls={ariaControls}>
|
|
||||||
{label}
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default TextIconButton;
|
|
|
@ -44,87 +44,6 @@
|
||||||
&:active {
|
&:active {
|
||||||
outline: 0 !important;
|
outline: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.inverted {
|
|
||||||
color: var(--primary-text-color--faint);
|
|
||||||
opacity: 1;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:active,
|
|
||||||
&:focus {
|
|
||||||
color: var(--primary-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.disabled {
|
|
||||||
color: var(--primary-text-color--faint);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
color: var(--highlight-text-color);
|
|
||||||
|
|
||||||
&.disabled {
|
|
||||||
color: var(--highlight-text-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.overlayed {
|
|
||||||
box-sizing: content-box;
|
|
||||||
background: var(--foreground-color);
|
|
||||||
color: var(--primary-text-color--faint);
|
|
||||||
border-radius: 6px;
|
|
||||||
padding: 2px;
|
|
||||||
opacity: 1;
|
|
||||||
|
|
||||||
> div {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: var(--background-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-icon-button {
|
|
||||||
color: var(--primary-text-color--faint);
|
|
||||||
border: 0;
|
|
||||||
background: transparent;
|
|
||||||
cursor: pointer;
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 11px;
|
|
||||||
padding: 0 3px;
|
|
||||||
line-height: 27px;
|
|
||||||
outline: 0;
|
|
||||||
transition: color 100ms ease-in;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:active,
|
|
||||||
&:focus {
|
|
||||||
color: var(--primary-text-color);
|
|
||||||
transition: color 200ms ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.disabled {
|
|
||||||
color: var(--primary-text-color--faint);
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
color: var(--highlight-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-moz-focus-inner {
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-moz-focus-inner,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
outline: 0 !important;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.invisible {
|
.invisible {
|
||||||
|
|
Loading…
Reference in New Issue