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


import { InputText } from 'exchange-elements/v2';
import { ChangeEvent, useEffect, useRef, useState } from 'react';

import { normalizeColor } from '@src/utils';

import styles from './index.module.scss';
import { RangeField } from './RangeField';

interface ColorFieldProps {
  label: string;
  value: string;
  onChange: (value: string) => void;
}

function normalizeHex(value: string): string {
  const next = value.trim().startsWith('#') ? normalizeColor(value) : `#${normalizeColor(value)}`;

  if (/^#[0-9a-f]{6}$/.test(next)) {
    return `${next}ff`;
  }

  if (/^#[0-9a-f]{8}$/.test(next)) {
    return next;
  }

  return '#000000ff';
}

function isValidHex(value: string): boolean {
  return /^#([0-9a-f]{6}|[0-9a-f]{8})$/i.test(value) || /^([0-9a-f]{6}|[0-9a-f]{8})$/i.test(value);
}

export const ColorField = ({ label, value, onChange }: ColorFieldProps) => {
  const colorInputRef = useRef<HTMLInputElement | null>(null);
  const [draft, setDraft] = useState(normalizeHex(value));

  useEffect(() => {
    setDraft(normalizeHex(value));
  }, [value]);

  const current = isValidHex(draft) ? normalizeHex(draft) : normalizeHex(value);
  const opacity = Math.round((parseInt(current.slice(7, 9), 16) / 255) * 100);

  const handleTextChange = (event: ChangeEvent<HTMLInputElement>) => {
    setDraft(event.target.value);
  };

  const handleTextBlur = () => {
    if (!isValidHex(draft)) {
      setDraft(normalizeHex(value));
      return;
    }

    const next = normalizeHex(draft);

    setDraft(next);
    onChange(next);
  };

  const handleColorChange = (event: ChangeEvent<HTMLInputElement>) => {
    const next = `${event.target.value}${current.slice(7, 9)}`;

    setDraft(next);
    onChange(next);
  };

  const handleOpacityChange = (event: ChangeEvent<HTMLInputElement>) => {
    const alpha = Math.round((Number(event.target.value) / 100) * 255)
      .toString(16)
      .padStart(2, '0');

    const next = `${current.slice(0, 7)}${alpha}`;

    setDraft(next);
    onChange(next);
  };

  return (
    <div className={styles.input_color}>
      <div className={styles.input_wrapper}>
        <InputText
          value={draft}
          label={label}
          labelPos="top"
          size="sm"
          onChange={handleTextChange}
          onBlur={handleTextBlur}
        />

        <button
          type="button"
          className={styles.button_color}
          style={{ backgroundColor: current }}
          onClick={() => colorInputRef.current?.click()}
        />

        <input
          ref={colorInputRef}
          type="color"
          className={styles.input_hidden}
          value={current.slice(0, 7)}
          onChange={handleColorChange}
          tabIndex={-1}
        />
      </div>

      <RangeField
        value={opacity}
        color={current.slice(0, 7)}
        suffix="%"
        onChange={handleOpacityChange}
      />
    </div>
  );
};