wix-style-react
Version:
194 lines (176 loc) • 5.45 kB
JavaScript
import React from 'react';
import PropTypes from 'prop-types';
import Input from '../Input';
import { Hash } from './components/Hash';
import { ColorViewer } from './components/ColorViewer';
import { validateHex, normalizeHexInput } from './hex-helpers';
import Box from '../Box';
class ColorInput extends React.Component {
static displayName = 'ColorInput';
static propTypes = {
/** Defines placeholder text to display on an empty input */
placeholder: PropTypes.string,
/** Specifies whether the input should be disabled */
disabled: PropTypes.bool,
/** Specifies the status of a field */
status: PropTypes.oneOf(['error', 'warning', 'loading']),
/** Defines the message to display on status icon hover. If not given or empty, there will be no tooltip. */
statusMessage: PropTypes.node,
/** Controls input size */
size: PropTypes.oneOf(['small', 'medium', 'large']),
/** Defines input value */
value: PropTypes.string.isRequired,
/** Returns confirmed value */
onConfirm: PropTypes.func,
/** Returns last confirmed value from `value` prop */
onCancel: PropTypes.func,
/** Returns changed value of input or color picker */
onChange: PropTypes.func,
/** Defines child items to render inside of a component. Accepts any kind of content. It receives the `changeColor` function to control <ColorInput/> value. */
colorPickerChildren: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
/** Defines a callback handler with color HEX string. Handler is called whenever the `Add Color` button is pressed. */
onAddColor: PropTypes.func,
/** Defines content to show in add button tooltip. Does not appear if `onAdd` is not passed. */
addTooltipContent: PropTypes.node,
/** Allows to pass popover props. See <Popover/> API for a full list. */
popoverProps: PropTypes.object,
};
static defaultProps = {
placeholder: '',
size: 'medium',
onChange: () => {},
onConfirm: () => {},
onCancel: () => {},
popoverProps: {},
value: '',
};
constructor(props) {
super(props);
this.state = {
active: false,
previous: props.value,
value: '',
};
}
static getDerivedStateFromProps(props, state) {
if (!state.active && props.value !== state.value) {
return {
value: normalizeHexInput(props.value),
};
}
return {};
}
_renderPrefix = () => {
const { disabled, size } = this.props;
const { active, value } = this.state;
const hash = (
<Input.Affix>
<Hash disabled={disabled} size={size} />
</Input.Affix>
);
return active || value ? hash : undefined;
};
_renderSuffix = () => {
const { value, active } = this.state;
const {
size,
popoverPlacement,
popoverAppendTo,
disabled,
colorPickerChildren,
onAddColor,
addTooltipContent,
placeholder,
popoverProps,
} = this.props;
return (
<Box verticalAlign="middle">
<ColorViewer
value={value}
active={active}
disabled={disabled}
size={size}
placement={popoverPlacement}
appendTo={popoverAppendTo}
onClick={this.click}
onChange={this._onPickerChange}
onCancel={this.cancel}
onConfirm={this.confirm}
onClickOutside={this.confirm}
children={colorPickerChildren}
onAddColor={onAddColor}
addTooltipContent={addTooltipContent}
placeholder={placeholder}
popoverProps={popoverProps}
/>
</Box>
);
};
_onChange = evt => {
const { onChange } = this.props;
const value = normalizeHexInput(evt.target.value);
this.setState({ value }, () => onChange(value));
};
_onPickerChange = value => {
const { onChange } = this.props;
this.setState({ active: true, value }, () => onChange(value));
};
_onFocus = () => this.setState({ active: true });
_keyDown = e => {
e.stopPropagation();
e.key === 'Enter' && this.confirm();
e.key === 'Escape' && this.cancel();
};
/**
* clicks the input element
* @returns {Void}
*/
click = () => {
this.input.focus();
this.setState({ active: true });
};
/**
* sets the picked color
* @returns {Void}
*/
confirm = () => {
const { onConfirm, onChange } = this.props;
const value = validateHex(this.state.value);
this.setState({ active: false, value, previous: value }, () => {
onConfirm(value);
onChange(value);
});
};
/**
* sets the previous color
* @returns {Void}
*/
cancel = () => {
const { onCancel, onChange } = this.props;
const { previous } = this.state;
this.setState({ active: false, value: previous }, () => {
onCancel(previous);
onChange(previous);
});
};
render() {
const { placeholder, size, ...rest } = this.props;
const { active, value } = this.state;
return (
<Input
{...rest}
ref={input => (this.input = input)}
placeholder={active ? '' : placeholder}
size={size}
onKeyDown={this._keyDown}
onChange={this._onChange}
onFocus={this._onFocus}
onInputClicked={this.click}
value={value.replace('#', '')}
prefix={this._renderPrefix()}
suffix={this._renderSuffix()}
/>
);
}
}
export default ColorInput;