Загрузка данных
import { useEffect, useState } from 'react';
import { ColorField, NumberField, SelectField, TextAreaField, TextField } from '@src/components/FormFields';
import type { DrawingStyleField, DrawingStyleSettings } from '@src/core/Drawings/styleSettings';
import styles from './index.module.scss';
interface DrawingStyleSettingsModalProps {
fields: DrawingStyleField[];
values: DrawingStyleSettings;
onChange: (settings: DrawingStyleSettings) => void;
}
export const DrawingStyleSettingsModal = ({ fields, values, onChange }: DrawingStyleSettingsModalProps) => {
const [form, setForm] = useState<DrawingStyleSettings>(values);
useEffect(() => {
setForm(values);
}, [values]);
const changeValue = (key: string, value: string | number | boolean) => {
setForm((current) => {
const next = {
...current,
[key]: value,
};
onChange(next);
return next;
});
};
return (
<div className={styles.form}>
{fields.map((field) => {
const value = form[field.key] ?? field.defaultValue;
if (field.type === 'select') {
return (
<SelectField
key={field.key}
label={field.label}
value={String(value)}
options={field.options}
onValueChange={(nextValue) => {
changeValue(field.key, nextValue);
}}
/>
);
}
if (field.type === 'color') {
return (
<ColorField
key={field.key}
label={field.label}
value={String(value)}
onValueChange={(nextValue) => {
changeValue(field.key, nextValue);
}}
/>
);
}
if (field.type === 'text') {
return (
<TextField
key={field.key}
label={field.label}
value={String(value)}
placeholder={field.placeholder}
onValueChange={(nextValue) => {
changeValue(field.key, nextValue);
}}
/>
);
}
if (field.type === 'textarea') {
return (
<TextAreaField
key={field.key}
label={field.label}
value={String(value)}
placeholder={field.placeholder}
onValueChange={(nextValue) => {
changeValue(field.key, nextValue);
}}
/>
);
}
if (field.type === 'boolean') {
return (
<label
key={field.key}
className={styles.checkboxField}
>
<input
type="checkbox"
checked={Boolean(value)}
onChange={(event) => {
changeValue(field.key, event.target.checked);
}}
/>
<span>{field.label}</span>
</label>
);
}
return (
<NumberField
key={field.key}
label={field.label}
value={typeof value === 'number' ? value : field.defaultValue}
min={field.min}
max={field.max}
onValueChange={(nextValue) => {
changeValue(field.key, nextValue);
}}
/>
);
})}
</div>
);
};
import { useMemo, useRef } from 'react';
import { InputText } from 'exchange-elements/v2';
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;
}
return '#000000';
}
export const ColorField = ({ label, value, onValueChange }: ColorFieldProps) => {
const inputRef = useRef<HTMLInputElement | null>(null);
const normalizedValue = useMemo(() => normalizeHex(value), [value]);
return (
<div className={styles.field}>
<span className={styles.label}>{label}</span>
<div className={styles.colorFieldRow}>
<button
type="button"
className={styles.colorPreview}
style={{ backgroundColor: normalizedValue }}
onClick={() => inputRef.current?.click()}
/>
<input
ref={inputRef}
type="color"
className={styles.hiddenColorInput}
value={normalizedValue}
onChange={(event) => {
onValueChange(event.target.value);
}}
/>
<InputText
value={normalizedValue}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
onValueChange(event.target.value);
}}
/>
</div>
</div>
);
};
import { InputTextArea } from 'exchange-elements/v2';
import styles from './index.module.scss';
interface TextAreaFieldProps {
label: string;
value: string;
placeholder?: string;
onValueChange: (value: string) => void;
}
export const TextAreaField = ({ label, value, placeholder, onValueChange }: TextAreaFieldProps) => {
return (
<label className={styles.field}>
<span className={styles.label}>{label}</span>
<InputTextArea
value={value}
placeholder={placeholder}
onChange={(event: React.ChangeEvent<HTMLTextAreaElement>) => {
onValueChange(event.target.value);
}}
/>
</label>
);
};
import { InputText } from 'exchange-elements/v2';
import styles from './index.module.scss';
interface TextFieldProps {
label: string;
value: string;
placeholder?: string;
onValueChange: (value: string) => void;
}
export const TextField = ({ label, value, placeholder, onValueChange }: TextFieldProps) => {
return (
<label className={styles.field}>
<span className={styles.label}>{label}</span>
<InputText
value={value}
placeholder={placeholder}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
onValueChange(event.target.value);
}}
/>
</label>
);
};