diff --git a/pkg/interface/src/logic/lib/util.tsx b/pkg/interface/src/logic/lib/util.tsx index f1ef123fe..8a0b25b82 100644 --- a/pkg/interface/src/logic/lib/util.tsx +++ b/pkg/interface/src/logic/lib/util.tsx @@ -241,11 +241,13 @@ export function uxToHex(ux: string) { export const hexToUx = (hex) => { const ux = f.flow( + f.reverse, f.chunk(4), // eslint-disable-next-line prefer-arrow-callback f.map(x => _.dropWhile(x, function(y: unknown) { - return y === 0; - }).join('')), + return y === '0'; + }).reverse().join('')), + f.reverse, f.join('.') )(hex.split('')); return `0x${ux}`; diff --git a/pkg/interface/src/views/components/ColorInput.tsx b/pkg/interface/src/views/components/ColorInput.tsx index 935bf39b8..2d95c589f 100644 --- a/pkg/interface/src/views/components/ColorInput.tsx +++ b/pkg/interface/src/views/components/ColorInput.tsx @@ -7,8 +7,9 @@ import { StatelessTextInput as Input } from '@tlon/indigo-react'; import { useField } from 'formik'; -import React, { FormEvent } from 'react'; +import React, { FormEvent, useState, useEffect } from 'react'; import { hexToUx } from '~/logic/lib/util'; +import { uxToHex } from '@urbit/api/dist'; export type ColorInputProps = Parameters[0] & { id: string; @@ -17,24 +18,40 @@ export type ColorInputProps = Parameters[0] & { disabled?: boolean; }; +const COLOR_REGEX = /^(\d|[a-f]|[A-F]){6}$/; + +function padHex(hex: string) { + if(hex.length === 0) { + return '000000'; + } + const repeat = 6 / hex.length; + if(Math.floor(repeat) === repeat) { + return hex.repeat(repeat); + } + if(hex.length < 6) { + return hex.slice(0,3).repeat(2); + } + return hex.slice(0,6); +} + export function ColorInput(props: ColorInputProps) { const { id, placeholder, label, caption, disabled, ...rest } = props; - const [{ value, onBlur }, meta, { setValue }] = useField(id); + const [{ value, onBlur }, meta, { setValue, setTouched }] = useField(id); + const [field, setField] = useState(''); + // const [error, setError] = useState(); - const hex = value.replace('#', '').replace('0x', '').replace('.', ''); - const padded = hex.padStart(6, '0'); + useEffect(() => { + const newValue = hexToUx(padHex(field)); + setValue(newValue); + setTouched(true); + }, [field]); const onChange = (e: FormEvent) => { - let { value: newValue } = e.target as HTMLInputElement; - newValue = newValue.replace('#', ''); - const valid = newValue.match(/^(\d|[a-f]|[A-F]){0,6}$/); - - if (!valid) { - return; - } - const result = hexToUx(newValue); - setValue(result); + const { value: newValue } = e.target as HTMLInputElement; + setField(newValue); }; + const isValid = value.match(COLOR_REGEX); + const hex = uxToHex(value); return ( @@ -51,7 +68,7 @@ export function ColorInput(props: ColorInputProps) { borderBottomRightRadius={0} onBlur={onBlur} onChange={onChange} - value={hex} + value={field} disabled={disabled || false} borderRight={0} placeholder={placeholder} @@ -64,14 +81,12 @@ export function ColorInput(props: ColorInputProps) { borderColor='lightGray' width='32px' alignSelf='stretch' - bg={`#${padded}`} + bg={isValid ? `#${hex}` : 'transparent'} >