mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-17 05:32:27 +00:00
288 lines
6.8 KiB
JavaScript
288 lines
6.8 KiB
JavaScript
/**
|
|
* @file
|
|
* @copyright 2020 Aleksej Komarov
|
|
* @license MIT
|
|
*/
|
|
|
|
import { KEY_ENTER, KEY_ESCAPE, KEY_SPACE } from 'common/keycodes';
|
|
import { classes, pureComponentHooks } from 'common/react';
|
|
import { Component, createRef } from 'inferno';
|
|
import { createLogger } from '../logging';
|
|
import { Box, computeBoxClassName, computeBoxProps } from './Box';
|
|
import { Icon } from './Icon';
|
|
import { Tooltip } from './Tooltip';
|
|
|
|
const logger = createLogger('Button');
|
|
|
|
export const Button = (props) => {
|
|
const {
|
|
className,
|
|
fluid,
|
|
icon,
|
|
iconRotation,
|
|
iconSpin,
|
|
iconColor,
|
|
iconPosition,
|
|
iconSize, // VOREStation Addition
|
|
color,
|
|
disabled,
|
|
selected,
|
|
tooltip,
|
|
tooltipPosition,
|
|
ellipsis,
|
|
compact,
|
|
circular,
|
|
content,
|
|
children,
|
|
onclick,
|
|
onClick,
|
|
...rest
|
|
} = props;
|
|
const hasContent = !!(content || children);
|
|
// A warning about the lowercase onclick
|
|
if (onclick) {
|
|
logger.warn(
|
|
`Lowercase 'onclick' is not supported on Button and lowercase` +
|
|
` prop names are discouraged in general. Please use a camelCase` +
|
|
`'onClick' instead and read: ` +
|
|
`https://infernojs.org/docs/guides/event-handling`
|
|
);
|
|
}
|
|
rest.onClick = (e) => {
|
|
if (!disabled && onClick) {
|
|
onClick(e);
|
|
}
|
|
};
|
|
// IE8: Use "unselectable" because "user-select" doesn't work.
|
|
if (Byond.IS_LTE_IE8) {
|
|
rest.unselectable = true;
|
|
}
|
|
let buttonContent = (
|
|
<div
|
|
className={classes([
|
|
'Button',
|
|
fluid && 'Button--fluid',
|
|
disabled && 'Button--disabled',
|
|
selected && 'Button--selected',
|
|
hasContent && 'Button--hasContent',
|
|
ellipsis && 'Button--ellipsis',
|
|
circular && 'Button--circular',
|
|
compact && 'Button--compact',
|
|
iconPosition && 'Button--iconPosition--' + iconPosition,
|
|
color && typeof color === 'string' ? 'Button--color--' + color : 'Button--color--default',
|
|
className,
|
|
computeBoxClassName(rest),
|
|
])}
|
|
tabIndex={!disabled && '0'}
|
|
onKeyDown={(e) => {
|
|
if (props.captureKeys === false) {
|
|
return;
|
|
}
|
|
|
|
const keyCode = window.event ? e.which : e.keyCode;
|
|
// Simulate a click when pressing space or enter.
|
|
if (keyCode === KEY_SPACE || keyCode === KEY_ENTER) {
|
|
e.preventDefault();
|
|
if (!disabled && onClick) {
|
|
onClick(e);
|
|
}
|
|
return;
|
|
}
|
|
// Refocus layout on pressing escape.
|
|
if (keyCode === KEY_ESCAPE) {
|
|
e.preventDefault();
|
|
return;
|
|
}
|
|
}}
|
|
{...computeBoxProps(rest)}>
|
|
{icon && iconPosition !== 'right' && (
|
|
<Icon name={icon} color={iconColor} rotation={iconRotation} spin={iconSpin} />
|
|
)}
|
|
{content}
|
|
{children}
|
|
{icon && iconPosition === 'right' && (
|
|
<Icon
|
|
name={icon}
|
|
color={iconColor}
|
|
rotation={iconRotation}
|
|
spin={iconSpin}
|
|
fontSize={iconSize} // VOREStation Addition
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
|
|
if (tooltip) {
|
|
buttonContent = (
|
|
<Tooltip content={tooltip} position={tooltipPosition}>
|
|
{buttonContent}
|
|
</Tooltip>
|
|
);
|
|
}
|
|
|
|
return buttonContent;
|
|
};
|
|
|
|
Button.defaultHooks = pureComponentHooks;
|
|
|
|
export const ButtonCheckbox = (props) => {
|
|
const { checked, ...rest } = props;
|
|
return <Button color="transparent" icon={checked ? 'check-square-o' : 'square-o'} selected={checked} {...rest} />;
|
|
};
|
|
|
|
Button.Checkbox = ButtonCheckbox;
|
|
|
|
export class ButtonConfirm extends Component {
|
|
constructor() {
|
|
super();
|
|
this.state = {
|
|
clickedOnce: false,
|
|
};
|
|
this.handleClick = () => {
|
|
if (this.state.clickedOnce) {
|
|
this.setClickedOnce(false);
|
|
}
|
|
};
|
|
}
|
|
|
|
setClickedOnce(clickedOnce) {
|
|
this.setState({
|
|
clickedOnce,
|
|
});
|
|
if (clickedOnce) {
|
|
setTimeout(() => window.addEventListener('click', this.handleClick));
|
|
} else {
|
|
window.removeEventListener('click', this.handleClick);
|
|
}
|
|
}
|
|
|
|
render() {
|
|
const {
|
|
confirmContent = 'Confirm?',
|
|
confirmColor = 'bad',
|
|
confirmIcon,
|
|
icon,
|
|
color,
|
|
content,
|
|
onClick,
|
|
...rest
|
|
} = this.props;
|
|
return (
|
|
<Button
|
|
content={this.state.clickedOnce ? confirmContent : content}
|
|
icon={this.state.clickedOnce ? confirmIcon : icon}
|
|
color={this.state.clickedOnce ? confirmColor : color}
|
|
onClick={() => (this.state.clickedOnce ? onClick() : this.setClickedOnce(true))}
|
|
{...rest}
|
|
/>
|
|
);
|
|
}
|
|
}
|
|
|
|
Button.Confirm = ButtonConfirm;
|
|
|
|
export class ButtonInput extends Component {
|
|
constructor() {
|
|
super();
|
|
this.inputRef = createRef();
|
|
this.state = {
|
|
inInput: false,
|
|
};
|
|
}
|
|
|
|
setInInput(inInput) {
|
|
this.setState({
|
|
inInput,
|
|
});
|
|
if (this.inputRef) {
|
|
const input = this.inputRef.current;
|
|
if (inInput) {
|
|
input.value = this.props.currentValue || '';
|
|
try {
|
|
input.focus();
|
|
input.select();
|
|
} catch {}
|
|
}
|
|
}
|
|
}
|
|
|
|
commitResult(e) {
|
|
if (this.inputRef) {
|
|
const input = this.inputRef.current;
|
|
const hasValue = input.value !== '';
|
|
if (hasValue) {
|
|
this.props.onCommit(e, input.value);
|
|
return;
|
|
} else {
|
|
if (!this.props.defaultValue) {
|
|
return;
|
|
}
|
|
this.props.onCommit(e, this.props.defaultValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
render() {
|
|
const {
|
|
fluid,
|
|
content,
|
|
icon,
|
|
iconRotation,
|
|
iconSpin,
|
|
tooltip,
|
|
tooltipPosition,
|
|
color = 'default',
|
|
placeholder,
|
|
maxLength,
|
|
...rest
|
|
} = this.props;
|
|
|
|
let buttonContent = (
|
|
<Box
|
|
className={classes(['Button', fluid && 'Button--fluid', 'Button--color--' + color])}
|
|
{...rest}
|
|
onClick={() => this.setInInput(true)}>
|
|
{icon && <Icon name={icon} rotation={iconRotation} spin={iconSpin} />}
|
|
<div>{content}</div>
|
|
<input
|
|
ref={this.inputRef}
|
|
className="NumberInput__input"
|
|
style={{
|
|
'display': !this.state.inInput ? 'none' : undefined,
|
|
'text-align': 'left',
|
|
}}
|
|
onBlur={(e) => {
|
|
if (!this.state.inInput) {
|
|
return;
|
|
}
|
|
this.setInInput(false);
|
|
this.commitResult(e);
|
|
}}
|
|
onKeyDown={(e) => {
|
|
if (e.keyCode === KEY_ENTER) {
|
|
this.setInInput(false);
|
|
this.commitResult(e);
|
|
return;
|
|
}
|
|
if (e.keyCode === KEY_ESCAPE) {
|
|
this.setInInput(false);
|
|
}
|
|
}}
|
|
/>
|
|
</Box>
|
|
);
|
|
|
|
if (tooltip) {
|
|
buttonContent = (
|
|
<Tooltip content={tooltip} position={tooltipPosition}>
|
|
{buttonContent}
|
|
</Tooltip>
|
|
);
|
|
}
|
|
|
|
return buttonContent;
|
|
}
|
|
}
|
|
|
|
Button.Input = ButtonInput;
|