finform
v1.6.44
Published
Пакет для управления инпутами с поддержкой валидации и отображения ошибок в попапе.
Readme
Документация по компонентам формы
Пакет для управления инпутами с поддержкой валидации и отображения ошибок в попапе.
Содержание
- Установка и импорт
- Типы данных
- Основные концепции
- InputContainer
- Компоненты
- Обработка ошибок
- Примеры полных форм
- Особенности работы компонентов
Установка и импорт
Импорт компонентов
import {
InputContainer,
Input,
TextArea,
NumberInput,
MaskedInput,
Select,
MultiSelect,
Search,
MultipleSearch,
GroupSelect,
GroupSearch,
GroupSelectWithSearch,
DateInput,
DateTimeInput,
FileInput,
Checkbox,
RoundCheckbox
} from 'finform';Важно: Компоненты Checkbox и RoundCheckbox не требуют обертки в InputContainer.
Типы данных
Option
Интерфейс для опций в выпадающих списках и поиске:
interface Option {
id: string | number; // Уникальный идентификатор опции
name: string; // Отображаемое название опции
}GroupOption
Интерфейс для группированных опций:
interface GroupOption {
id: string | number; // Уникальный идентификатор группы
name: string; // Название группы
items: Option[]; // Массив опций в группе
}Основные концепции
Все компоненты формы должны быть обернуты в InputContainer, который обеспечивает:
- Отображение placeholder'а
- Визуальное оформление состояния фокуса
- Отображение ошибок в попапе при наведении на иконку ошибки
- Иконки и дополнительные элементы управления
Структура использования
import { InputContainer, Input } from 'finform';
<InputContainer error={errorMessage}>
<Input
id="field-id"
placeholder="Введите значение"
value={value}
onChange={setValue}
/>
</InputContainer>InputContainer
Основной контейнер для всех инпутов. Обеспечивает единообразное оформление и обработку ошибок.
Props
| Проп | Тип | По умолчанию | Описание |
|------|-----|--------------|----------|
| children | React.ReactNode | - | Единственный дочерний компонент (Input, Select, TextArea и т.д.) |
| className | string | '' | Дополнительные CSS классы |
| style | React.CSSProperties | {} | Инлайн стили |
| error | string \| null | null | Текст ошибки для отображения в попапе |
Важно: error должен быть строкой (не массивом) для корректного отображения в попапе. При наведении на иконку ошибки появляется попап с текстом ошибки.
Компоненты
Текстовые инпуты
Input
import { InputContainer, Input } from 'finform';
const [value, setValue] = useState('');
const [error, setError] = useState<string | null>(null);
<InputContainer error={error}>
<Input
id="username"
placeholder="Имя пользователя"
value={value}
onChange={setValue}
/>
</InputContainer>Props
| Проп | Тип | По умолчанию | Описание |
|------|-----|--------------|----------|
| id | string | - | Уникальный идентификатор поля |
| name | string | - | Имя поля для формы |
| value | string \| number \| null | - | Значение инпута |
| onChange | (value: string) => void | - | Обработчик изменения значения |
| placeholder | string | - | Текст placeholder'а |
| disabled | boolean | false | Отключение поля |
| className | string | '' | Дополнительные CSS классы |
| style | React.CSSProperties | {} | Инлайн стили |
| type | string | 'text' | Тип HTML инпута (text, email, password и т.д.) |
| autoComplete | string | 'off' | Автозаполнение браузера |
| icon | boolean | true | Показывать ли иконку в InputContainer |
| onKeyDown | (e: KeyboardEvent) => void | - | Обработчик нажатия клавиш |
| onBlur | (e: FocusEvent) => void | - | Обработчик потери фокуса |
| onClick | (e: MouseEvent) => void | - | Обработчик клика |
| required | boolean | false | Обязательное поле |
Примечание: Пропсы focused, setFocused, error передаются автоматически через InputContainer и не должны указываться вручную.
TextArea
import { InputContainer, TextArea } from 'finform';
const [value, setValue] = useState('');
const [error, setError] = useState<string | null>(null);
<InputContainer error={error}>
<TextArea
id="description"
placeholder="Описание"
value={value}
onChange={setValue}
rows={5}
autoResize={true}
/>
</InputContainer>Props
Все пропсы из Input, плюс:
| Проп | Тип | По умолчанию | Описание |
|------|-----|--------------|----------|
| rows | number | 3 | Количество строк |
| autoResize | boolean | true | Автоматическое изменение высоты при вводе |
| disableResize | boolean | false | Отключить возможность ручного изменения размера |
Особенности:
- При
autoResize={true}высота автоматически подстраивается под содержимое - При
disableResize={true}отключается возможность ручного изменения размера через UI
NumberInput
import { InputContainer, NumberInput } from 'finform';
const [value, setValue] = useState<number | null>(null);
const [error, setError] = useState<string | null>(null);
<InputContainer error={error}>
<NumberInput
id="amount"
placeholder="Сумма"
value={value}
onChange={setValue}
min={0}
max={1000000}
decimals={2}
/>
</InputContainer>Props
Все пропсы из Input, плюс:
| Проп | Тип | По умолчанию | Описание |
|------|-----|--------------|----------|
| min | number \| false | false | Минимальное значение |
| max | number \| false | false | Максимальное значение |
| decimals | number \| false | false | Количество знаков после запятой |
| innerError | object \| null | - | Внутренняя ошибка валидации (используется компонентом) |
| setInnerError | (error: object \| null) => void | - | Установка внутренней ошибки (используется компонентом) |
Особенности:
- Автоматическое форматирование чисел с пробелами для разделения тысяч (например:
1 000 000) - Поддержка отрицательных чисел
- Автоматическая валидация при вводе с отображением ошибок через
innerError - При превышении
maxилиminавтоматически показывается ошибка - Поддержка как точки, так и запятой в качестве разделителя дробной части
MaskedInput
import { InputContainer, MaskedInput } from 'finform';
const [value, setValue] = useState('');
const [error, setError] = useState<string | null>(null);
<InputContainer error={error}>
<MaskedInput
id="phone"
placeholder="Телефон"
value={value}
onChange={setValue}
mask="+7 (999) 999-99-99"
/>
</InputContainer>Props
Все пропсы из Input, плюс:
| Проп | Тип | По умолчанию | Описание |
|------|-----|--------------|----------|
| mask | string | - | Маска ввода (символ 9 означает цифру) |
Примеры масок:
"+7 (999) 999-99-99"— телефон"99.99.9999"— дата"9999 9999 9999 9999"— номер карты
Выпадающие списки
Select
import { InputContainer, Select } from 'finform';
interface Option {
id: string | number;
name: string;
}
const options: Option[] = [
{ id: 1, name: 'Опция 1' },
{ id: 2, name: 'Опция 2' },
];
const [value, setValue] = useState<number | null>(null);
const [error, setError] = useState<string | null>(null);
<InputContainer error={error}>
<Select
id="category"
placeholder="Выберите категорию"
value={value}
onChange={(option) => setValue(option?.id || null)}
options={options}
/>
</InputContainer>Важно: onChange получает объект Option целиком, а не только значение.
Props
| Проп | Тип | По умолчанию | Описание |
|------|-----|--------------|----------|
| id | string | - | Уникальный идентификатор поля |
| name | string | - | Имя поля для формы |
| value | string \| number \| null | - | ID выбранной опции |
| onChange | (option: Option \| null) => void | - | Обработчик выбора опции (получает весь объект Option) |
| options | Option[] | [] | Массив опций для выбора |
| placeholder | string | - | Текст placeholder'а |
| disabled | boolean | false | Отключение поля |
| className | string | '' | Дополнительные CSS классы |
| style | React.CSSProperties | {} | Инлайн стили |
| icon | boolean | true | Показывать ли иконку в InputContainer |
| addButton | any | false | Кнопка добавления новой опции (отображается в списке) |
MultiSelect
import { InputContainer, MultiSelect } from 'finform';
const options: Option[] = [
{ id: 1, name: 'Опция 1' },
{ id: 2, name: 'Опция 2' },
];
const [values, setValues] = useState<number[]>([]);
const [error, setError] = useState<string | null>(null);
<InputContainer error={error}>
<MultiSelect
id="tags"
placeholder="Выберите теги"
values={values}
onChange={(option) => {
setValues(prev =>
prev.includes(option.id)
? prev.filter(id => id !== option.id)
: [...prev, option.id]
);
}}
onChangeAll={(selectAll) => {
setValues(selectAll ? options.map(o => o.id) : []);
}}
options={options}
/>
</InputContainer>Props
| Проп | Тип | По умолчанию | Описание |
|------|-----|--------------|----------|
| id | string | - | Уникальный идентификатор поля |
| name | string | - | Имя поля для формы |
| values | (string \| number)[] | [] | Массив ID выбранных опций |
| onChange | (option: Option) => void | - | Обработчик выбора/снятия опции |
| onChangeAll | (selectAll: boolean) => void | - | Обработчик выбора всех/снятия всех опций |
| options | Option[] | [] | Массив опций для выбора |
| placeholder | string | - | Текст placeholder'а |
| disabled | boolean | false | Отключение поля |
| className | string | '' | Дополнительные CSS классы |
| style | React.CSSProperties | {} | Инлайн стили |
| icon | boolean | true | Показывать ли иконку в InputContainer |
Особенности:
onChangeвызывается при клике на опцию — нужно самостоятельно управлять массивомvaluesonChangeAllвызывается при клике на "Выбрать все" — передаетсяtrueдля выбора всех,falseдля снятия всех
Поиск
Search
import { InputContainer, Search } from 'finform';
const [search, setSearch] = useState('');
const [value, setValue] = useState<number | null>(null);
const [error, setError] = useState<string | null>(null);
<InputContainer error={error}>
<Search
id="user-search"
placeholder="Поиск пользователя"
value={value}
search={search}
onChange={(option) => {
setValue(option?.id || null);
setSearch(option?.name || '');
}}
onSearch={setSearch}
options={filteredOptions}
loading={isLoading}
clearOnClickOutside={true}
/>
</InputContainer>Props
Все пропсы из Select, плюс:
| Проп | Тип | По умолчанию | Описание |
|------|-----|--------------|----------|
| search | string | - | Текущее значение строки поиска |
| onSearch | (text: string) => void | - | Обработчик изменения текста поиска |
| loading | boolean | false | Индикатор загрузки данных |
| clearOnClickOutside | boolean | true | Очищать поле поиска при клике вне компонента, если опция не выбрана |
Особенности:
- При вводе текста в поле поиска вызывается
onSearch— используйте это для фильтрации опций - Если введенный текст совпадает с названием опции при клике вне компонента, опция автоматически выбирается
- При
loading={true}отображается индикатор загрузки вместо иконки
MultipleSearch
import { InputContainer, MultipleSearch } from 'finform';
const [search, setSearch] = useState('');
const [values, setValues] = useState<number[]>([]);
const [error, setError] = useState<string | null>(null);
<InputContainer error={error}>
<MultipleSearch
id="users-search"
placeholder="Поиск пользователей"
values={values}
search={search}
onChange={(option) => {
setValues(prev =>
prev.includes(option.id)
? prev.filter(id => id !== option.id)
: [...prev, option.id]
);
}}
onSearch={setSearch}
options={filteredOptions}
loading={isLoading}
/>
</InputContainer>Props
Все пропсы из Search, но onChange работает как в MultiSelect:
| Проп | Тип | По умолчанию | Описание |
|------|-----|--------------|----------|
| values | (string \| number)[] | [] | Массив ID выбранных опций |
| onChange | (option: Option) => void | - | Обработчик выбора/снятия опции |
Особенности:
- Выбранные опции отображаются как теги внутри поля
- Работает аналогично
MultiSelect, но с возможностью поиска
Группированные списки
GroupSelect
import { InputContainer, GroupSelect } from 'finform';
interface GroupOption {
id: string | number;
name: string;
items: Option[];
}
const groupOptions: GroupOption[] = [
{
id: 'group1',
name: 'Группа 1',
items: [
{ id: 1, name: 'Опция 1.1' },
{ id: 2, name: 'Опция 1.2' },
]
},
];
const [value, setValue] = useState<number | null>(null);
const [error, setError] = useState<string | null>(null);
<InputContainer error={error}>
<GroupSelect
id="grouped-select"
placeholder="Выберите из группы"
value={value}
onChange={(option) => setValue(option?.id || null)}
options={groupOptions}
/>
</InputContainer>Props
Все пропсы из Select, но options имеет тип GroupOption[]:
| Проп | Тип | По умолчанию | Описание |
|------|-----|--------------|----------|
| options | GroupOption[] | [] | Массив группированных опций |
Особенности:
- Опции отображаются сгруппированными по группам
- Названия групп отображаются как заголовки
GroupSearch
import { InputContainer, GroupSearch } from 'finform';
const [search, setSearch] = useState('');
const [value, setValue] = useState<number | null>(null);
const [error, setError] = useState<string | null>(null);
<InputContainer error={error}>
<GroupSearch
id="grouped-search"
placeholder="Поиск в группах"
value={value}
search={search}
onChange={(option) => {
setValue(option?.id || null);
setSearch(option?.name || '');
}}
onSearch={setSearch}
options={groupOptions}
loading={isLoading}
/>
</InputContainer>Props
Все пропсы из GroupSelect, плюс:
| Проп | Тип | По умолчанию | Описание |
|------|-----|--------------|----------|
| search | string | - | Текущее значение строки поиска |
| onSearch | (text: string) => void | - | Обработчик изменения текста поиска |
| loading | boolean | false | Индикатор загрузки данных |
Особенности:
- Поиск работает по опциям внутри всех групп
- Группы остаются видимыми при поиске
GroupSelectWithSearch
import { InputContainer, GroupSelectWithSearch } from 'finform';
const [search, setSearch] = useState('');
const [value, setValue] = useState<number | null>(null);
const [error, setError] = useState<string | null>(null);
<InputContainer error={error}>
<GroupSelectWithSearch
id="grouped-select-search"
placeholder="Выберите с поиском"
value={value}
search={search}
onChange={(option) => {
setValue(option?.id || null);
setSearch(option?.name || '');
}}
onSearch={setSearch}
options={groupOptions}
loading={isLoading}
/>
</InputContainer>Props
Все пропсы из GroupSearch и GroupSelect.
Особенности:
- Комбинирует возможности группировки и поиска
- Поиск работает по всем опциям во всех группах
Дата и время
DateInput
import { InputContainer, DateInput } from 'finform';
const [value, setValue] = useState<Date | null>(null);
const [error, setError] = useState<string | null>(null);
<InputContainer error={error}>
<DateInput
id="birthdate"
placeholder="Дата рождения"
value={value}
onChange={setValue}
defaultDate="2024-01-01"
/>
</InputContainer>Props
| Проп | Тип | По умолчанию | Описание |
|------|-----|--------------|----------|
| id | string | - | Уникальный идентификатор поля |
| name | string | - | Имя поля для формы |
| value | Date \| null | - | Выбранная дата |
| onChange | (date: Date \| null) => void | - | Обработчик изменения даты |
| placeholder | string | - | Текст placeholder'а |
| disabled | boolean | false | Отключение поля |
| className | string | '' | Дополнительные CSS классы |
| style | React.CSSProperties | {} | Инлайн стили |
| defaultDate | string | - | Дата по умолчанию в формате YYYY-MM-DD |
| icon | boolean | true | Показывать ли иконку в InputContainer |
| innerError | object \| null | - | Внутренняя ошибка валидации (используется компонентом) |
| setInnerError | (error: object \| null) => void | - | Установка внутренней ошибки (используется компонентом) |
Особенности:
- Использует библиотеку Flatpickr для выбора даты
- Поддерживает различные форматы даты
- При неверном формате ввода автоматически показывается ошибка через
innerError
DateTimeInput
import { InputContainer, DateTimeInput } from 'finform';
const [value, setValue] = useState<Date | null>(null);
const [error, setError] = useState<string | null>(null);
<InputContainer error={error}>
<DateTimeInput
id="datetime"
placeholder="Дата и время"
value={value}
onChange={setValue}
/>
</InputContainer>Props
Все пропсы из DateInput.
Особенности:
- Позволяет выбрать как дату, так и время
- Формат отображения включает время
Файлы
FileInput
import { InputContainer, FileInput } from 'finform';
const [file, setFile] = useState<File | null>(null);
const [error, setError] = useState<string | null>(null);
<InputContainer error={error}>
<FileInput
id="document"
placeholder="Выберите файл"
value={file}
onChange={(fileData) => {
// fileData содержит: { size, name, content }
// content - это base64 строка
setFile(fileData);
}}
valueText={file?.name || ''}
accept=".pdf,.doc,.docx"
/>
</InputContainer>Props
| Проп | Тип | По умолчанию | Описание |
|------|-----|--------------|----------|
| id | string | - | Уникальный идентификатор поля |
| name | string | - | Имя поля для формы |
| value | object \| null | - | Объект с данными файла (не используется напрямую) |
| onChange | (fileData: { size: number, name: string, content: string }) => void | - | Обработчик выбора файла |
| valueText | string | '' | Текст для отображения имени файла |
| placeholder | string | - | Текст placeholder'а |
| disabled | boolean | false | Отключение поля |
| className | string | '' | Дополнительные CSS классы |
| style | React.CSSProperties | {} | Инлайн стили |
| accept | string | - | Разрешенные типы файлов (например: ".pdf,.doc,.docx" или "image/*") |
Особенности:
- Файл автоматически конвертируется в base64 строку
onChangeполучает объект с полями:size— размер файла в байтахname— имя файлаcontent— содержимое файла в формате base64 (data URL)
- Используйте
valueTextдля отображения имени выбранного файла - Placeholder всегда активен для
FileInput
Чекбоксы
Checkbox
import { Checkbox } from 'finform';
const [checked, setChecked] = useState(false);
<Checkbox
id="agree"
checked={checked}
toggleCallback={(checked) => setChecked(checked)}
text="Я согласен с условиями"
/>Props
| Проп | Тип | По умолчанию | Описание |
|------|-----|--------------|----------|
| id | string | - | Уникальный идентификатор чекбокса |
| name | string | - | Имя для группировки чекбоксов |
| value | string \| number | - | Значение чекбокса (для форм) |
| checked | boolean | false | Состояние чекбокса |
| toggleCallback | (checked: boolean, event: Event) => void | - | Обработчик изменения состояния |
| text | string | - | Текст рядом с чекбоксом |
| textStyle | React.CSSProperties | {} | Стили для текста |
| checkboxStyle | React.CSSProperties | {} | Стили для самого чекбокса |
| style | React.CSSProperties | {} | Общий стиль контейнера |
Особенности:
- Не требует обертки в
InputContainer - Используйте
toggleCallbackвместоonChangeдля обработки изменений - Для группировки чекбоксов используйте одинаковый
nameи разныеvalue
RoundCheckbox
import { RoundCheckbox } from 'finform';
const [checked, setChecked] = useState(false);
<RoundCheckbox
id="option"
checked={checked}
toggleCallback={(checked) => setChecked(checked)}
/>Props
Все пропсы из Checkbox, но без text, textStyle (круглый чекбокс обычно используется без текста).
Особенности:
- Визуально отличается от обычного
Checkbox— имеет круглую форму - Обычно используется для выбора опций без текста рядом
Обработка ошибок
Важно: Для корректного отображения ошибки в попапе необходимо передать строку в проп error компонента InputContainer. При наведении на иконку ошибки появляется попап с текстом ошибки.
Пример 1: Простая валидация
import { InputContainer, Input } from 'finform';
import { useState } from 'react';
function MyForm() {
const [value, setValue] = useState('');
const [error, setError] = useState<string | null>(null);
const handleSubmit = () => {
if (!value.trim()) {
setError('Поле обязательно для заполнения');
return;
}
if (value.length < 3) {
setError('Минимальная длина 3 символа');
return;
}
setError(null);
// Отправка формы
};
return (
<InputContainer error={error}>
<Input
id="field"
placeholder="Введите значение"
value={value}
onChange={(newValue) => {
setValue(newValue);
// Очищаем ошибку при изменении значения
if (error) setError(null);
}}
/>
</InputContainer>
);
}Пример 2: Работа с массивом ошибок
Если валидация возвращает массив ошибок, используйте первую ошибку или объедините их:
import { InputContainer, Input } from 'finform';
import { useState } from 'react';
function MyForm() {
const [value, setValue] = useState('');
const [validationErrors, setValidationErrors] = useState<string[]>([]);
// Использовать первую ошибку
const errorMessage = validationErrors.length > 0
? validationErrors[0]
: null;
return (
<InputContainer error={errorMessage}>
<Input
id="field"
placeholder="Введите значение"
value={value}
onChange={setValue}
/>
</InputContainer>
);
}Примеры полных форм
Пример 1: Форма регистрации
import { useState } from 'react';
import {
InputContainer,
Input,
Select,
DateInput,
Checkbox
} from 'finform';
interface Option {
id: number;
name: string;
}
function RegistrationForm() {
const [username, setUsername] = useState('');
const [usernameError, setUsernameError] = useState<string | null>(null);
const [email, setEmail] = useState('');
const [emailError, setEmailError] = useState<string | null>(null);
const [country, setCountry] = useState<number | null>(null);
const [countryError, setCountryError] = useState<string | null>(null);
const [birthdate, setBirthdate] = useState<Date | null>(null);
const [birthdateError, setBirthdateError] = useState<string | null>(null);
const [agreed, setAgreed] = useState(false);
const countries: Option[] = [
{ id: 1, name: 'Россия' },
{ id: 2, name: 'Беларусь' },
{ id: 3, name: 'Казахстан' },
];
const handleSubmit = () => {
// Валидация
if (!username.trim()) {
setUsernameError('Имя пользователя обязательно');
return;
}
if (!email.includes('@')) {
setEmailError('Некорректный email');
return;
}
if (!country) {
setCountryError('Выберите страну');
return;
}
if (!birthdate) {
setBirthdateError('Укажите дату рождения');
return;
}
if (!agreed) {
alert('Необходимо согласие с условиями');
return;
}
// Отправка формы
console.log({ username, email, country, birthdate });
};
return (
<form onSubmit={(e) => { e.preventDefault(); handleSubmit(); }}>
<InputContainer error={usernameError}>
<Input
id="username"
placeholder="Имя пользователя"
value={username}
onChange={(value) => {
setUsername(value);
if (usernameError) setUsernameError(null);
}}
/>
</InputContainer>
<InputContainer error={emailError}>
<Input
id="email"
type="email"
placeholder="Email"
value={email}
onChange={(value) => {
setEmail(value);
if (emailError) setEmailError(null);
}}
/>
</InputContainer>
<InputContainer error={countryError}>
<Select
id="country"
placeholder="Выберите страну"
value={country}
onChange={(option) => {
setCountry(option?.id || null);
if (countryError) setCountryError(null);
}}
options={countries}
/>
</InputContainer>
<InputContainer error={birthdateError}>
<DateInput
id="birthdate"
placeholder="Дата рождения"
value={birthdate}
onChange={(date) => {
setBirthdate(date);
if (birthdateError) setBirthdateError(null);
}}
/>
</InputContainer>
<Checkbox
id="agree"
checked={agreed}
toggleCallback={setAgreed}
text="Я согласен с условиями использования"
/>
<button type="submit">Зарегистрироваться</button>
</form>
);
}Пример 2: Форма с поиском и множественным выбором
import { useState, useMemo } from 'react';
import { InputContainer, Search, MultiSelect } from 'finform';
interface User {
id: number;
name: string;
}
function UserSelectionForm() {
const [searchQuery, setSearchQuery] = useState('');
const [selectedUser, setSelectedUser] = useState<number | null>(null);
const [selectedTags, setSelectedTags] = useState<number[]>([]);
const [isLoading, setIsLoading] = useState(false);
const allUsers: User[] = [
{ id: 1, name: 'Иван Иванов' },
{ id: 2, name: 'Петр Петров' },
{ id: 3, name: 'Мария Сидорова' },
];
const tags = [
{ id: 1, name: 'Важное' },
{ id: 2, name: 'Срочное' },
{ id: 3, name: 'Проект А' },
{ id: 4, name: 'Проект Б' },
];
// Фильтрация пользователей по поисковому запросу
const filteredUsers = useMemo(() => {
if (!searchQuery.trim()) return [];
return allUsers.filter(user =>
user.name.toLowerCase().includes(searchQuery.toLowerCase())
);
}, [searchQuery]);
return (
<div>
<InputContainer>
<Search
id="user-search"
placeholder="Поиск пользователя"
value={selectedUser}
search={searchQuery}
onChange={(option) => {
setSelectedUser(option?.id || null);
setSearchQuery(option?.name || '');
}}
onSearch={setSearchQuery}
options={filteredUsers}
loading={isLoading}
/>
</InputContainer>
<InputContainer>
<MultiSelect
id="tags"
placeholder="Выберите теги"
values={selectedTags}
onChange={(option) => {
setSelectedTags(prev =>
prev.includes(option.id)
? prev.filter(id => id !== option.id)
: [...prev, option.id]
);
}}
onChangeAll={(selectAll) => {
setSelectedTags(selectAll ? tags.map(t => t.id) : []);
}}
options={tags}
/>
</InputContainer>
</div>
);
}Особенности работы компонентов
InputContainer
- Обязательная обертка: Все компоненты (кроме
CheckboxиRoundCheckbox) должны быть обернуты вInputContainer - Единственный дочерний элемент:
InputContainerпринимает только один дочерний компонент - Автоматическая передача пропсов:
InputContainerавтоматически передает дочернему компоненту пропсыfocused,setFocused,error,innerError,setInnerError - Управление placeholder: Placeholder автоматически перемещается вверх при наличии значения или фокуса
- Иконки: Иконки отображаются автоматически, можно отключить через проп
icon={false}
NumberInput
- Форматирование: Автоматически форматирует числа с пробелами для разделения тысяч
- Валидация: Автоматически проверяет значения на соответствие
minиmax - Дробные числа: Поддерживает дробные числа с ограничением количества знаков через
decimals - Разделители: Принимает как точку, так и запятую в качестве разделителя дробной части
FileInput
- Base64 конвертация: Автоматически конвертирует файл в base64 строку
- Возвращаемые данные:
onChangeполучает объект{ size, name, content }, гдеcontent— это data URL (base64) - Отображение имени: Используйте
valueTextдля отображения имени выбранного файла
Search и MultipleSearch
- Фильтрация: Компоненты не фильтруют опции автоматически — нужно реализовать фильтрацию в
onSearch - Автовыбор: Если введенный текст точно совпадает с названием опции, она автоматически выбирается при клике вне компонента
- Очистка: При
clearOnClickOutside={true}поле поиска очищается, если опция не была выбрана
DateInput и DateTimeInput
- Библиотека: Используют Flatpickr для выбора даты
- Валидация: Автоматически валидируют формат ввода через
innerError - Формат: Принимают и возвращают объекты
Date
Checkbox и RoundCheckbox
- Без InputContainer: Эти компоненты не требуют обертки в
InputContainer - Группировка: Для группировки используйте одинаковый
nameи разныеvalue - Обработчик: Используйте
toggleCallbackвместоonChange
Примечания
- Все инпуты должны быть обернуты в
InputContainerдля корректной работы (кромеCheckboxиRoundCheckbox) InputContainerпринимает только один дочерний элемент- Для отображения ошибки в попапе передавайте строку в проп
errorкомпонентаInputContainer - Ошибка автоматически скрывается при передаче
nullили пустой строки - Компоненты автоматически управляют состоянием фокуса — не передавайте
focusedиsetFocusedвручную - Для работы компонентов требуется настроенная тема styled-components (проверьте наличие
ThemeProvider)
