Загрузка данных


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;
}