import * as React from 'react'; import { ErrorType, GrowthBehavior, createComponent, expandHex, } from '@workday/canvas-kit-react/common'; import {Subtext} from '@workday/canvas-kit-react/text'; import {TextInput, TextInputProps} from '@workday/canvas-kit-react/text-input'; import {calc, createStencil, handleCsProp, px2rem} from '@workday/canvas-kit-styling'; import {system} from '@workday/canvas-tokens-web'; import {ColorSwatch} from './parts/ColorSwatch'; export interface ColorInputProps extends TextInputProps, GrowthBehavior { /** * The value of the ColorInput. * @default '' */ value?: string; /** * If true, show a checkmark in the swatch tile when a custom hex color is entered in the ColorInput. * @default false */ showCheck?: boolean; /** * The placeholder text of the ColorInput. * @default FFFFFF */ placeholder?: string; /** * The type of error associated with the ColorInput (if applicable). */ error?: ErrorType; /** * If true, set the ColorInput to the disabled state. * @default false */ disabled?: boolean; /** * The function called when the ColorInput state changes. */ onChange?: (event: React.ChangeEvent) => void; /** * The function called when a valid hex value is entered in the ColorInput. The `color` argument passed to the callback function is prefixed with a hash and expanded if necessary (e.g., `03F` is converted to `#0033FF`). */ onValidColorChange?: (color: string) => void; } export const colorPickerHexInputStencil = createStencil({ vars: { width: '', }, parts: { input: 'color-picker-hex-input', poundSign: 'color-picker-hex-input-pound-sign', swatch: 'color-picker-hex-input-swatch', }, base: ({inputPart, poundSignPart, swatchPart, width}) => ({ [width]: px2rem(116), position: 'relative', width, [inputPart]: { minWidth: width, width, fontFamily: system.fontFamily.mono, paddingInlineStart: calc.subtract('100%', px2rem(86)), '&:focus::placeholder': { color: 'transparent', }, }, [poundSignPart]: { position: 'absolute', top: px2rem(10), left: px2rem(88), fontFamily: system.fontFamily.mono, }, [swatchPart]: { position: 'absolute', top: px2rem(10), left: system.legacy.gap.sm, boxShadow: `inset 0 0 0 ${px2rem(1)} rgba(0,0,0,0.25)`, pointerEvents: 'none', '@media (forced-colors: active)': { outline: `solid ${px2rem(1)} SelectedItemText`, }, }, ':dir(ltr)': { [inputPart]: { paddingInlineStart: px2rem(46), }, [poundSignPart]: { left: px2rem(36), }, }, }), modifiers: { grow: { true: ({width}) => ({ [width]: '100%', }), }, disabled: { true: ({poundSignPart}) => ({ [poundSignPart]: { opacity: system.opacity.disabled, }, }), }, }, }); const isValidHex = (value: string) => { return /(^#?[0-9A-F]{3}$)|(^#?[0-9A-F]{6}$)/i.test(value); }; const formatValue = (value: string) => { return value.replace(/#/g, '').substring(0, 6); }; export const ColorInput = createComponent('input')({ displayName: 'ColorInput', Component: ( { placeholder = 'FFFFFF', value = '', showCheck, onChange, onValidColorChange, disabled, error, grow, width, ...elemProps }: ColorInputProps, ref, Element ) => { const formattedValue = formatValue(value); const handleChange = (e: React.ChangeEvent) => { const value = formatValue(e.currentTarget.value); if (onChange) { onChange(e); } if (isValidHex(value) && onValidColorChange) { onValidColorChange(`#${expandHex(value)}`); } }; return (
#
); }, });