import { InputText } from 'exchange-elements/v2';
import { ChangeEvent, KeyboardEvent, useEffect, useRef, useState } from 'react';
import styles from './index.module.scss';
interface ColorFieldProps {
label: string;
value: string;
onValueChange: (value: string) => void;
}
function normalizeHex(value: string): string {
const next = value.trim();
if (!next) {
return '#000000';
}
const withHash = next.startsWith('#') ? next : `#${next}`;
if (/^#[0-9A-Fa-f]{6}$/.test(withHash)) {
return withHash.toLowerCase();
}
return '#000000';
}
function isValidHex(value: string): boolean {
const withHash = value.startsWith('#') ? value : `#${value}`;
return /^#[0-9A-Fa-f]{6}$/.test(withHash);
}
export const ColorField = ({ label, value, onValueChange }: ColorFieldProps) => {
const colorInputRef = useRef<HTMLInputElement | null>(null);
const [draft, setDraft] = useState(normalizeHex(value));
useEffect(() => {
setDraft(normalizeHex(value));
}, [value]);
const handleBlur = () => {
if (!isValidHex(draft)) {
setDraft(normalizeHex(value));
return;
}
const next = normalizeHex(draft);
setDraft(next);
onValueChange(next);
};
return (
<label className={styles.field}>
<span className={styles.label}>{label}</span>
<div className={styles.inputWrapper}>
<InputText
value={draft}
onChange={(event: ChangeEvent<HTMLInputElement>) => {
setDraft(event.target.value);
}}
onBlur={handleBlur}
onKeyDown={(event: KeyboardEvent<HTMLInputElement>) => {
if (event.key === 'Enter') {
event.currentTarget.blur();
}
}}
/>
<button
type="button"
className={styles.colorButton}
style={{ backgroundColor: normalizeHex(value) }}
onClick={() => colorInputRef.current?.click()}
aria-label="Выбрать цвет"
/>
<input
ref={colorInputRef}
type="color"
className={styles.hiddenInput}
value={normalizeHex(value)}
onChange={(event) => {
setDraft(event.target.value);
onValueChange(event.target.value);
}}
tabIndex={-1}
/>
</div>
</label>
);
};
.colorButton {
position: absolute;
top: 50%;
right: 8px;
width: 28px;
height: 28px;
transform: translateY(-50%);
border: 1px solid var(--stroke-secondary);
border-radius: 8px;
padding: 0;
cursor: pointer;
}
.hiddenInput {
position: absolute;
inset: 0;
opacity: 0;
pointer-events: none;
}