UNPKG

wix-style-react

Version:
194 lines (176 loc) 5.45 kB
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;