Skip to content

Commit

Permalink
fix(ColorInput): Add clearable option to the ColorInput component
Browse files Browse the repository at this point in the history
Reviewed-by: @MIGUELez11
Refs: #115
  • Loading branch information
paola-pc authored Feb 3, 2024
1 parent 19034eb commit e369cb9
Showing 1 changed file with 99 additions and 71 deletions.
170 changes: 99 additions & 71 deletions packages/components/src/form/ColorInput/ColorInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@ import PropTypes from 'prop-types';
import { isEmpty, isFunction } from 'lodash';
import { colord } from 'colord';
import { useClickOutside, useId } from '@mantine/hooks';
import { DeleteBinIcon } from '@bubbles-ui/icons/solid';
import { ColorSwatch } from '../ColorPicker/ColorSwatch/ColorSwatch';
import { ColorPicker } from '../ColorPicker/ColorPicker';
import { Paragraph } from '../../typography';
import { Input } from '../../form/Input';
import { Input } from '../Input';
import { Popover } from '../../overlay';
import { Box } from '../../layout';
import { Stack } from '../../../lib/layout/Stack/Stack';
import { ActionButton } from '../ActionButton';
import {
INPUT_WRAPPER_ORIENTATIONS,
INPUT_WRAPPER_SHARED_PROPS,
INPUT_WRAPPER_SIZES,
InputWrapper,
} from '../InputWrapper';
import { ColorInputStyles } from './ColorInput.styles';

const SWATCH_SIZES = {
xs: 16,
Expand Down Expand Up @@ -55,18 +57,19 @@ export const COLOR_INPUT_PROP_TYPES = {
compact: PropTypes.bool,
/** Controls if color dropdown uses manual inputs */
manual: PropTypes.bool,
/** Controls if only shows light colors when using useHsl*/
/** Controls if only shows light colors when using useHsl */
lightOnly: PropTypes.bool,
/** Custom color picker component */
colorPickerCompoennt: PropTypes.node,
/** Controls if ColorInput uses aria role */
useAria: PropTypes.bool,
/** Controls if ColorInput shows a clear button to remove the color */
clearable: PropTypes.bool,
};

export const COLOR_INPUT_DEFAULT_PROPS = {
label: '',
description: '',
size: INPUT_WRAPPER_SIZES[1],
orientation: INPUT_WRAPPER_ORIENTATIONS[1],
error: '',
required: false,
Expand All @@ -78,6 +81,7 @@ export const COLOR_INPUT_DEFAULT_PROPS = {
manual: false,
lightOnly: false,
useAria: true,
clearable: false,
};

const ColorInput = forwardRef(
Expand Down Expand Up @@ -122,24 +126,26 @@ const ColorInput = forwardRef(
ariaHueValue,
colorPickerComponent,
useAria,
clearable,
...props
},
ref
ref,
) => {
const uuid = useId();
const [opened, setOpened] = useState(false);
const [inputValue, setInputValue] = useState('');
const closeRef = useClickOutside(() => setOpened(false));
const { classes, cx, theme } = ColorInputStyles({ size }, { name: 'ColorInput' });

useEffect(() => {
if (value !== inputValue && colord(value).isValid()) {
setInputValue(value);
const isNullWhenClearable = clearable && value === null;

if (value !== inputValue && (colord(value).isValid() || isNullWhenClearable)) {
setInputValue(value || '');
}
}, [value]);

useEffect(() => {
if (colord(inputValue).isValid()) {
if (colord(inputValue).isValid() || inputValue === '') {
isFunction(onChange) && onChange(inputValue);
}
}, [inputValue]);
Expand Down Expand Up @@ -176,74 +182,96 @@ const ColorInput = forwardRef(
{readOnly ? (
<Paragraph clean>{value || ''}</Paragraph>
) : (
<Popover
opened={opened}
onClose={() => setOpened(false)}
target={
<Input
id={uuid}
ref={ref}
size={size}
value={inputValue}
disabled={disabled}
placeholder={placeholder}
invalid={!isEmpty(error)}
autoComplete="off"
icon={
icon || (
<ColorSwatch color={inputValue} onClick={() => setOpened(!opened)} size={18} />
)
}
onFocus={handleInputFocus}
onChange={handleInputChange}
onKeyDown={handleInputKeyDown}
spellCheck={false}
/>
}
width={colorPickerComponent ? undefined : 200}
position="bottom-start"
withArrow
trapFocus
>
<Box style={{ display: 'flex', position: 'relative', zIndex: 999 }} ref={closeRef}>
{!colorPickerComponent ? (
<ColorPicker
color={inputValue}
format={format}
withSwatches={withSwatches}
compact={compact}
fullWidth
swatchesForGama={swatchesForGama}
swatchesPerRow={swatchesPerRow}
spacing={spacing}
useHsl={useHsl}
lightOnly={lightOnly}
saturation={saturation}
lightness={lightness}
manual={manual}
output="hex"
ariaSaturationLabel={ariaSaturationLabel}
ariaSliderLabel={ariaSliderLabel}
ariaColorFormat={ariaColorFormat}
ariaColorValue={ariaColorValue}
ariaHueValue={ariaHueValue}
onChange={setInputValue}
role={useAria ? 'input' : undefined}
<Stack alignItems="center" spacing={2}>
<Popover
opened={opened}
onClose={() => setOpened(false)}
target={
<Input
id={uuid}
ref={ref}
size={size}
value={inputValue}
disabled={disabled}
placeholder={placeholder}
invalid={!isEmpty(error)}
autoComplete="off"
icon={
icon || (
<ColorSwatch
color={inputValue}
onClick={() => setOpened(!opened)}
size={18}
/>
)
}
onFocus={handleInputFocus}
onChange={handleInputChange}
onKeyDown={handleInputKeyDown}
spellCheck={false}
/>
}
width={colorPickerComponent ? undefined : 200}
position="bottom-start"
withArrow
trapFocus
>
<Box style={{ display: 'flex', position: 'relative', zIndex: 999 }} ref={closeRef}>
{!colorPickerComponent ? (
<ColorPicker
color={inputValue}
format={format}
withSwatches={withSwatches}
compact={compact}
fullWidth
swatchesForGama={swatchesForGama}
swatchesPerRow={swatchesPerRow}
spacing={spacing}
useHsl={useHsl}
lightOnly={lightOnly}
saturation={saturation}
lightness={lightness}
manual={manual}
output="hex"
ariaSaturationLabel={ariaSaturationLabel}
ariaSliderLabel={ariaSliderLabel}
ariaColorFormat={ariaColorFormat}
ariaColorValue={ariaColorValue}
ariaHueValue={ariaHueValue}
onChange={setInputValue}
role={useAria ? 'input' : undefined}
/>
) : (
React.createElement(colorPickerComponent, {
inputValue,
onChange: setInputValue,
})
)}
</Box>
</Popover>
{clearable && (
<Box
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<ActionButton
leftIcon={<DeleteBinIcon width={18} height={18} />}
onClick={() => setInputValue('')}
disabled={disabled}
/>
) : (
React.createElement(colorPickerComponent, {
inputValue: inputValue,
onChange: setInputValue,
})
)}
</Box>
</Popover>
</Box>
)}
</Stack>
)}
</InputWrapper>
);
}
},
);

ColorInput.displayName = 'ColorInput';
ColorInput.defaultProps = COLOR_INPUT_DEFAULT_PROPS;
ColorInput.propTypes = COLOR_INPUT_PROP_TYPES;

Expand Down

0 comments on commit e369cb9

Please sign in to comment.