@elcrm/form 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/Form.d.ts +21 -3
  2. package/dist/core/Field.d.ts +12 -0
  3. package/dist/fields/Card.d.ts +14 -0
  4. package/dist/fields/Check.d.ts +14 -0
  5. package/dist/fields/Code.d.ts +14 -1
  6. package/dist/fields/Color.d.ts +13 -0
  7. package/dist/fields/ColorPanel.d.ts +4 -0
  8. package/dist/fields/Date.d.ts +14 -2
  9. package/dist/fields/DateCalendar.d.ts +11 -1
  10. package/dist/fields/Display.d.ts +9 -2
  11. package/dist/fields/DragDrop.d.ts +14 -1
  12. package/dist/fields/Email.d.ts +14 -2
  13. package/dist/fields/FieldGroup.d.ts +24 -4
  14. package/dist/fields/File.d.ts +14 -1
  15. package/dist/fields/Hidden.d.ts +7 -2
  16. package/dist/fields/Input.d.ts +10 -5
  17. package/dist/fields/Mask.d.ts +13 -1
  18. package/dist/fields/Modal.d.ts +21 -4
  19. package/dist/fields/Money.d.ts +11 -1
  20. package/dist/fields/NativeTextField.d.ts +9 -5
  21. package/dist/fields/Numeric.d.ts +9 -8
  22. package/dist/fields/Options.d.ts +25 -6
  23. package/dist/fields/Password.d.ts +11 -0
  24. package/dist/fields/Percent.d.ts +10 -6
  25. package/dist/fields/Phone.d.ts +13 -1
  26. package/dist/fields/Radio.d.ts +14 -0
  27. package/dist/fields/Range.d.ts +11 -1
  28. package/dist/fields/Rating.d.ts +13 -1
  29. package/dist/fields/RichText.d.ts +10 -2
  30. package/dist/fields/Select.d.ts +21 -0
  31. package/dist/fields/Tabs.d.ts +15 -0
  32. package/dist/fields/Tags.d.ts +13 -1
  33. package/dist/fields/Textarea.d.ts +10 -1
  34. package/dist/fields/Time.d.ts +13 -4
  35. package/dist/fields/TimePicker.d.ts +10 -1
  36. package/dist/fields/Url.d.ts +11 -1
  37. package/dist/fields/emit.d.ts +1 -1
  38. package/dist/fields/type.d.ts +97 -27
  39. package/dist/hooks/use.d.ts +22 -8
  40. package/dist/index.d.ts +2 -0
  41. package/dist/index.umd.js +1 -1
  42. package/dist/package.js +1 -1
  43. package/package.json +3 -2
@@ -1,31 +1,50 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { UseFormApi } from '../hooks/use';
3
3
  import { TValue } from './type';
4
- interface Input {
4
+ /**
5
+ * Выбор через модалку приложения (`Form.Init.onModal`).
6
+ *
7
+ * **В форме:** зависит от `outFormat`: строка ключей, массив или объект-флаги.
8
+ *
9
+ * **Элементы:** капсула-колонка выбранных подписей (`options[id].label`). Клик открывает модалку
10
+ * `modal` вида `"module.name"` (или `module` + `modal`).
11
+ *
12
+ * Нужен {@link Form.Init}.
13
+ *
14
+ * @example
15
+ * <OptionsField name="users" form={form} label="Сотрудники" modal="crm.pickUser" outFormat="string" />
16
+ */
17
+ export type TOptions = {
5
18
  value?: string;
6
- form?: UseFormApi;
19
+ form?: UseFormApi<any>;
7
20
  onValue?: (data: TValue) => void | Promise<void>;
8
21
  name: string;
9
22
  placeholder?: string;
10
- /** Подпись поля */
11
23
  label?: string;
12
24
  error?: string;
13
25
  hidden?: boolean;
14
- /** true — блок выбора не открывается */
15
26
  disabled?: boolean;
16
27
  after?: ReactNode;
17
28
  before?: ReactNode;
18
29
  view?: string;
19
30
  className?: string;
31
+ /** Имя модуля модалки, если `modal` без точки */
20
32
  module?: string;
33
+ /** `"module.modalName"` или имя модалки вместе с `module` */
21
34
  modal?: string;
35
+ /** Подписи выбранных ключей: `{ [id]: { label } }` */
22
36
  options?: Record<string, {
23
37
  label?: string;
24
38
  }>;
39
+ /** Как писать выбор в форму. @default зависит от текущего value */
25
40
  outFormat?: "array" | "string" | "object";
41
+ /** Разделитель ключей при `outFormat="string"`. @default "," */
26
42
  separator?: string;
27
- }
28
- declare function OptionsField({ value, form, onValue, name, placeholder, separator, label, error, hidden, disabled, outFormat, after, before, modal, options, className, }: Input): import("react/jsx-runtime").JSX.Element;
43
+ };
44
+ /**
45
+ * Список выбранных значений; клик по капсуле открывает модалку приложения.
46
+ */
47
+ declare function OptionsField({ value, form, onValue, name, placeholder, separator, label, error, hidden, disabled, outFormat, after, before, modal, options, className, }: TOptions): import("react/jsx-runtime").JSX.Element;
29
48
  declare namespace OptionsField {
30
49
  var displayName: string;
31
50
  }
@@ -1,4 +1,15 @@
1
1
  import { TPasswordField } from './type';
2
+ /**
3
+ * Пароль с переключателем видимости (кнопка-глаз в слоте `after`).
4
+ *
5
+ * **В форме:** `string`.
6
+ *
7
+ * **Элементы:** капсула + `<input type="password"|text>` + кнопка глаза.
8
+ * Проп `native` **скрывает весь компонент** (не делает input) — см. {@link TPasswordField}.
9
+ *
10
+ * @example
11
+ * <PasswordField name="password" form={form} label="Пароль" autoComplete="current-password" />
12
+ */
2
13
  declare function PasswordField({ value, form, onValue, name, placeholder, label, error, hidden, disabled, onBlur: onBlurField, className, after, before, native, maxLength, eyes, id, size, }: TPasswordField): import("react/jsx-runtime").JSX.Element | "";
3
14
  declare namespace PasswordField {
4
15
  var displayName: string;
@@ -1,11 +1,12 @@
1
1
  import { TInput } from './type';
2
- /** PercentField — процент как **number** в форме (не строка).
2
+ /**
3
+ * Процент как **`number`** в форме (не строка).
3
4
  *
4
- * Отличия от NumberField:
5
- * - значение: `number` (или `""` / пусто), не строка цифр;
6
- * - `min`/`max` — границы **числа** (по умолчанию 0–100), clamp на blur;
7
- * - `decimals` — дробная часть;
8
- * - справа по умолчанию аффикс `%`.
5
+ * Отличия от {@link NumberField}: значение `number`; `min`/`max` — границы числа (по умолчанию 0–100);
6
+ * `decimals` дробная часть; справа по умолчанию аффикс `%`.
7
+ *
8
+ * @example
9
+ * <PercentField name="vat" form={form} label="НДС" min={0} max={100} decimals={2} />
9
10
  */
10
11
  export type TPercent = TInput & {
11
12
  min?: number;
@@ -13,6 +14,9 @@ export type TPercent = TInput & {
13
14
  /** Допускать дробную часть */
14
15
  decimals?: number;
15
16
  };
17
+ /**
18
+ * Поле процента. Не путать с {@link NumberField} (там строка цифр).
19
+ */
16
20
  declare function PercentField({ value, form, onValue, onBlur: onBlurField, name, placeholder, label, error, hidden, disabled, className, after, before, min, max, decimals, inputmode, }: TPercent): import("react/jsx-runtime").JSX.Element | null;
17
21
  declare namespace PercentField {
18
22
  var displayName: string;
@@ -1,5 +1,17 @@
1
1
  import { TInput } from './type';
2
- /** PhoneField — телефон с маской; полный каталог стран подгружается при фокусе. */
2
+ /**
3
+ * Телефон с маской по стране. В форму пишутся **только цифры** (без `+` и скобок).
4
+ *
5
+ * **В форме:** `string` цифр.
6
+ *
7
+ * **Элементы:** капсула, contentEditable по шаблону; полный каталог масок — lazy при фокусе.
8
+ * Копирование может вызвать `Form.Init.onNotice`.
9
+ *
10
+ * Пропы — {@link TInput}.
11
+ *
12
+ * @example
13
+ * <PhoneField name="phone" form={form} label="Телефон" />
14
+ */
3
15
  declare function PhoneField({ value, form, onValue, onBlur: onBlurField, name, placeholder, label, error, hidden, disabled, className, after, before, inputmode, id, }: TInput): import("react/jsx-runtime").JSX.Element | null;
4
16
  declare namespace PhoneField {
5
17
  var displayName: string;
@@ -10,6 +10,17 @@ type RadioOptionArrayItem = {
10
10
  s?: number;
11
11
  };
12
12
  type RadioOptions = RadioOptionObject | RadioOptionArrayItem[];
13
+ /**
14
+ * Группа радиокнопок.
15
+ *
16
+ * **В форме:** `string | number` (id выбранного пункта).
17
+ *
18
+ * **Элементы:** капсула-`radiogroup` → кнопки `role="radio"`.
19
+ * Опции как у Select: `{ n, s }` / `{ i|id, n }`. `inline` — в ряд. `align` — кружок vs текст.
20
+ *
21
+ * @example
22
+ * <RadioField name="sex" form={form} label="Пол" options={[{ i: "m", n: "М" }, { i: "f", n: "Ж" }]} />
23
+ */
13
24
  export type TRadio = TInput & {
14
25
  options?: RadioOptions;
15
26
  /** Горизонтальный ряд вместо колонки */
@@ -17,6 +28,9 @@ export type TRadio = TInput & {
17
28
  /** Кружок: top | center | bottom относительно текста. По умолчанию center */
18
29
  align?: "top" | "center" | "bottom";
19
30
  };
31
+ /**
32
+ * Радиогруппа. Один выбранный id в форме.
33
+ */
20
34
  declare function RadioField({ value, form, onValue, onBlur: onBlurField, name, placeholder, label, error, hidden, disabled, className, after, before, options, inline, align, }: TRadio): import("react/jsx-runtime").JSX.Element | null;
21
35
  declare namespace RadioField {
22
36
  var displayName: string;
@@ -1,7 +1,14 @@
1
1
  import { TInput } from './type';
2
2
  /** `bar` — толстая «таблетка» с заливкой; `line` — тонкая линия и круглый thumb */
3
3
  export type TRangeVariant = "bar" | "line";
4
- /** Поле «диапазон»: кастомный трек (div), без нативного range */
4
+ /**
5
+ * Слайдер. **В форме:** `number`.
6
+ *
7
+ * **Элементы:** капсула как у Input → трек (`bar` таблетка / `line` + thumb). Не нативный `<input type="range">`.
8
+ *
9
+ * @example
10
+ * <RangeField name="vol" form={form} label="Громкость" min={0} max={100} variant="bar" />
11
+ */
5
12
  export type TRange = TInput & {
6
13
  min?: number;
7
14
  max?: number;
@@ -12,6 +19,9 @@ export type TRange = TInput & {
12
19
  */
13
20
  variant?: TRangeVariant;
14
21
  };
22
+ /**
23
+ * Диапазон. Клавиши стрелок при фокусе на треке.
24
+ */
15
25
  declare function RangeField({ value, form, onValue, onBlur: onBlurField, name, placeholder, label, error, hidden, disabled, className, after, before, min, max, step, variant, }: TRange): import("react/jsx-runtime").JSX.Element | null;
16
26
  declare namespace RangeField {
17
27
  var displayName: string;
@@ -1,10 +1,22 @@
1
1
  import { TInput } from './type';
2
- /** RatingField — оценка звёздами. Значение: число 0…max. */
2
+ /**
3
+ * Оценка звёздами.
4
+ *
5
+ * **В форме:** `number` `0…max` (`0` = пусто).
6
+ *
7
+ * **Элементы:** капсула → `role="slider"` + кнопки звёзд. Стрелки меняют значение.
8
+ *
9
+ * @example
10
+ * <RatingField name="rate" form={form} label="Оценка" max={5} allowClear />
11
+ */
3
12
  export type TRating = TInput & {
4
13
  max?: number;
5
14
  /** Разрешить сброс повторным кликом по текущей оценке */
6
15
  allowClear?: boolean;
7
16
  };
17
+ /**
18
+ * Звёздный рейтинг.
19
+ */
8
20
  declare function RatingField({ value, form, onValue, onBlur: onBlurField, name, placeholder, label, error, hidden, disabled, className, after, before, max, allowClear, }: TRating): import("react/jsx-runtime").JSX.Element | null;
9
21
  declare namespace RatingField {
10
22
  var displayName: string;
@@ -1,12 +1,20 @@
1
1
  import { TInput } from './type';
2
2
  /**
3
- * RichTextField простой WYSIWYG без внешних библиотек.
4
- * Значение: HTML-строка. Панель: жирный / курсив / подчёркивание / списки.
3
+ * Простой WYSIWYG (`document.execCommand`). **В форме:** HTML-строка.
4
+ *
5
+ * **Элементы:** капсула как textarea → опциональный `toolbar` (B/I/U/списки) + редактор.
6
+ * Санитизацию HTML делайте в приложении.
7
+ *
8
+ * @example
9
+ * <RichTextField name="bio" form={form} label="Описание" toolbar />
5
10
  */
6
11
  export type TRichText = TInput & {
7
12
  /** Показать панель форматирования */
8
13
  toolbar?: boolean;
9
14
  };
15
+ /**
16
+ * Rich-текст. Значение — HTML, не plain text.
17
+ */
10
18
  declare function RichTextField({ value, form, onValue, onBlur: onBlurField, name, placeholder, label, error, hidden, disabled, className, after, before, maxLength, spellCheck, toolbar, }: TRichText): import("react/jsx-runtime").JSX.Element | null;
11
19
  declare namespace RichTextField {
12
20
  var displayName: string;
@@ -11,10 +11,31 @@ type SelectOptionArrayItem = {
11
11
  s?: number;
12
12
  };
13
13
  type SelectOptions = SelectOptionObject | SelectOptionArrayItem[];
14
+ /**
15
+ * Выпадающий список (портал в `document.body`).
16
+ *
17
+ * **В форме:** `number` (id опции; `0` часто = «не выбрано»).
18
+ *
19
+ * **Элементы:** капсула-`combobox` + список `listbox` (li = option).
20
+ * Формат опций: `{ [id]: { n: "Подпись", s: 1 } }` или `[{ i, n, s }]`.
21
+ * `s === 0` — скрыть пункт. `order` — порядок id.
22
+ *
23
+ * @example
24
+ * const ROLES = { 1: { n: "Админ", s: 1 }, 2: { n: "Юзер", s: 1 } };
25
+ * <SelectField name="role" form={form} label="Роль" options={ROLES} placeholder="Выберите" />
26
+ */
14
27
  export type TSelect = TInput & {
28
+ /**
29
+ * Пункты: объект `{ id: { n, s } }` или массив `{ id|i, n, s? }`.
30
+ * `n` — текст, `s` — видимость (`0` = скрыт).
31
+ */
15
32
  options?: SelectOptions;
33
+ /** Порядок ключей, если `options` — объект. */
16
34
  order?: number[];
17
35
  };
36
+ /**
37
+ * Селект: клик по капсуле открывает список, привязанный к полю при скролле.
38
+ */
18
39
  declare function SelectField({ value, form, onValue, name, placeholder, label, error, hidden, disabled, className, after, before, options, order, size, }: TSelect): import("react/jsx-runtime").JSX.Element | "";
19
40
  declare namespace SelectField {
20
41
  var displayName: string;
@@ -15,6 +15,18 @@ type TabsOptionArrayItem = {
15
15
  icon?: ReactNode;
16
16
  };
17
17
  type TabsOptions = TabsOptionObject | TabsOptionArrayItem[];
18
+ /**
19
+ * Сегменты (вкладки-переключатель).
20
+ *
21
+ * **В форме:** `string | number` (id активного сегмента).
22
+ *
23
+ * **Элементы:** капсула без внутреннего padding → кнопки-сегменты.
24
+ * `options[].icon` — слот слева в сегменте. `s === 0` — сегмент виден, но disabled.
25
+ * `equal` — равная ширина (по умолчанию true).
26
+ *
27
+ * @example
28
+ * <TabsField name="tab" form={form} options={[{ i: "a", n: "А" }, { i: "b", n: "Б" }]} />
29
+ */
18
30
  export type TTabs = TInput & {
19
31
  options?: TabsOptions;
20
32
  /**
@@ -23,6 +35,9 @@ export type TTabs = TInput & {
23
35
  */
24
36
  equal?: boolean;
25
37
  };
38
+ /**
39
+ * Сегмент-контрол. Фокус на сегменте, не на всей капсуле.
40
+ */
26
41
  declare function TabsField({ value, form, onValue, onBlur: onBlurField, name, placeholder, label, error, hidden, disabled, className, after, before, options, equal, size, }: TTabs): import("react/jsx-runtime").JSX.Element | null;
27
42
  declare namespace TabsField {
28
43
  var displayName: string;
@@ -1,10 +1,22 @@
1
1
  import { TInput } from './type';
2
- /** TagsField — чипы / метки. Значение: `string[]`. */
2
+ /**
3
+ * Чипы / теги.
4
+ *
5
+ * **В форме:** `string[]`.
6
+ *
7
+ * **Элементы:** капсула → чипы + однострочный ввод. Enter / `separators` создают чип.
8
+ *
9
+ * @example
10
+ * <TagsField name="tags" form={form} label="Метки" maxTags={8} />
11
+ */
3
12
  export type TTags = TInput & {
4
13
  maxTags?: number;
5
14
  /** Разделители при вводе (по умолчанию Enter / запятая) */
6
15
  separators?: string[];
7
16
  };
17
+ /**
18
+ * Поле тегов. Backspace на пустом вводе удаляет последний чип.
19
+ */
8
20
  declare function TagsField({ value, form, onValue, onBlur: onBlurField, name, placeholder, label, error, hidden, disabled, className, after, before, maxTags, maxLength, separators, }: TTags): import("react/jsx-runtime").JSX.Element | null;
9
21
  declare namespace TagsField {
10
22
  var displayName: string;
@@ -1,5 +1,14 @@
1
1
  import { TInput } from './type';
2
- /** TextareaField — многострочное поле (contentEditable). */
2
+ /**
3
+ * Многострочный текст (`contentEditable`).
4
+ *
5
+ * **В форме:** `string` (могут быть `\n`).
6
+ *
7
+ * **Элементы:** `label` + высокая капсула (`--field-note-height`) + `before` / `after`.
8
+ *
9
+ * @example
10
+ * <TextareaField name="comment" form={form} label="Комментарий" placeholder="Текст…" />
11
+ */
3
12
  declare function TextareaField({ value, form, onValue, name, placeholder, label, hidden, disabled, onBlur: onBlurField, className, after, before, error, size, inputmode, maxLength, spellCheck, }: TInput): import("react/jsx-runtime").JSX.Element | null;
4
13
  declare namespace TextareaField {
5
14
  var displayName: string;
@@ -1,5 +1,15 @@
1
1
  import { TInput } from './type';
2
- /** Значение в форме: строка `HH:mm` или пустая строка */
2
+ /**
3
+ * Время `HH:mm` (два contentEditable: часы и минуты).
4
+ *
5
+ * **В форме:** `string` `"14:30"` или `""`.
6
+ *
7
+ * **Элементы:** капсула → [часы] `:` [минуты] + опционально кнопка picker (`after` по умолчанию — часы).
8
+ * `step` — шаг минут в **секундах** (`300` = 5 мин). `align`: `start` | `center`.
9
+ *
10
+ * @example
11
+ * <TimeField name="at" form={form} label="Время" step={300} picker />
12
+ */
3
13
  export type TTime = TInput & {
4
14
  /** Шаг для минут в секундах (`60` — любая минута; `300` — кратно 5 мин) */
5
15
  step?: number;
@@ -22,9 +32,8 @@ export type TTime = TInput & {
22
32
  presets?: string[];
23
33
  };
24
34
  /**
25
- * Время: два contentEditable по образцу Mask (каретка через queueMicrotask + setCursorPosition).
26
- * Пока фокус в группе в DOM только введённые цифры без ведущих нулей; в форму значение
27
- * уходит при уходе фокуса с группы (snap минут, clamp, формат `HH:mm`).
35
+ * Поле времени. Пока фокус в группе в DOM сырые цифры; в форму `HH:mm` уходит на blur.
36
+ * Popup слотовпри `picker` / `presets`.
28
37
  */
29
38
  declare function TimeField({ value, form, onValue, onBlur: onBlurField, name, placeholder, label, hidden, disabled, error, className, after, before, step, min, max, id, spellCheck, align, picker, presets, }: TTime): import("react/jsx-runtime").JSX.Element | null;
30
39
  declare namespace TimeField {
@@ -1,15 +1,24 @@
1
1
  import { default as React } from 'react';
2
+ /**
3
+ * Попап слотов {@link TimeField} (портал, якорь к капсуле).
4
+ * Не публичный API пакета.
5
+ */
2
6
  export type TTimePickerProps = {
7
+ /** getBoundingClientRect капсулы. */
3
8
  parent: DOMRect;
9
+ /** Список `HH:mm`. */
4
10
  slots: string[];
11
+ /** Текущее значение поля. */
5
12
  current: string;
13
+ /** Подсветка пункта (клавиатура). */
6
14
  activeIndex: number;
7
15
  listId: string;
8
16
  className?: string;
9
17
  setOpen: React.Dispatch<React.SetStateAction<boolean>>;
10
18
  setActiveIndex: React.Dispatch<React.SetStateAction<number>>;
19
+ /** Выбор слота → коммит в форму. */
11
20
  onPick: (slot: string) => void;
12
21
  };
13
- /** Попап со слотами времени (портал). */
22
+ /** Список времени `role="listbox"`. */
14
23
  declare function TimePicker({ parent, slots, current, activeIndex, listId, className, setOpen, setActiveIndex, onPick, }: TTimePickerProps): import("react/jsx-runtime").JSX.Element;
15
24
  export default TimePicker;
@@ -1,7 +1,17 @@
1
1
  import { default as React } from 'react';
2
2
  import { TInput } from './type';
3
- /** UrlField — нативный input type=url. */
3
+ /**
4
+ * Сайт / ссылка. Нативный `<input type="url">`.
5
+ *
6
+ * **В форме:** `string`. Пропы — {@link TInput}.
7
+ *
8
+ * @example
9
+ * <UrlField name="site" form={form} label="Сайт" placeholder="https://" />
10
+ */
4
11
  export type TUrl = TInput;
12
+ /**
13
+ * Поле URL (автозаполнение `url`, клавиатура `inputMode="url"`).
14
+ */
5
15
  declare function UrlField(props: TUrl): import("react/jsx-runtime").JSX.Element;
6
16
  declare namespace UrlField {
7
17
  var displayName: string;
@@ -6,4 +6,4 @@ import { UseFormApi } from '../hooks/use';
6
6
  * реально изменилось — иначе blur перерисовывал бы поле зря.
7
7
  * Во время ввода (`commit=false`) — только `onValue` без notify.
8
8
  */
9
- export declare function createFieldEmit(form: UseFormApi | undefined, name: string, onValue?: (data: TValue) => void | Promise<void>): (value: unknown, commit?: boolean) => void;
9
+ export declare function createFieldEmit(form: UseFormApi<any> | undefined, name: string, onValue?: (data: TValue) => void | Promise<void>): (value: unknown, commit?: boolean) => void;
@@ -1,83 +1,153 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { UseFormApi } from '../hooks/use';
3
- /** Связь с формой и колбэки значения */
3
+ /**
4
+ * Связь поля с `useForm` и колбэки значения.
5
+ *
6
+ * Типичная схема:
7
+ * 1. `form` + `name` — значение живёт в форме (`form.getValue(name)`).
8
+ * 2. `value` — начальное / внешнее значение, если форма ещё не знает ключ.
9
+ * 3. `onValue` — вызывается при каждом изменении `{ value, name }`.
10
+ * 4. `onBlur` — коммит (не нативный `FocusEvent`).
11
+ */
4
12
  export type TFieldFormBindings = {
13
+ /**
14
+ * Значение снаружи (controlled / начальное).
15
+ * Если передан `form` + `name`, источником правды становится форма.
16
+ */
5
17
  value?: unknown;
6
- form?: UseFormApi;
18
+ /** API `useForm()` — подписка только на это `name`, без ререндера всей формы. */
19
+ form?: UseFormApi<any>;
20
+ /**
21
+ * Колбэк изменения. Аргумент всегда `{ value, name }`, не DOM-событие.
22
+ * Во время набора часто вызывается без bump версии формы.
23
+ */
7
24
  onValue?: (data: TValue) => void | Promise<void>;
8
- /** Колбэк при потере фокуса (коммит значения), не нативный `FocusEvent` */
25
+ /**
26
+ * Потеря фокуса / коммит.
27
+ * @example onBlur={({ value, name }) => validate(name, value)}
28
+ */
9
29
  onBlur?: (data: TValue) => void | Promise<void>;
30
+ /**
31
+ * Ключ в `form`. Обязателен, если используете `useForm`.
32
+ * По нему поле подписывается и пишет `setValue` / `onValue`.
33
+ */
10
34
  name?: string;
11
35
  };
12
- /** Подпись, доступность, видимость */
36
+ /**
37
+ * Внешний вид и доступность. Рендер у всех `*Field` одинаковый каркас:
38
+ *
39
+ * ```
40
+ * [data-field] — корень (`.l`)
41
+ * label.t — подпись (`label`), htmlFor → контрол
42
+ * капсула .f — рамка, padding `--field-padding`, `data-disabled`
43
+ * before — слот слева (иконка, бейдж карты)
44
+ * контрол — input / contentEditable / combobox / …
45
+ * after — слот справа (глаз пароля, %, ошибка)
46
+ * [role=alert] — текст `error`
47
+ * ```
48
+ */
13
49
  export type TFieldPresentation = {
14
- /** Подпись поля (визуально в `.t`) */
50
+ /** Подпись над капсулой. Связана с контролом через `htmlFor` / `id`. */
15
51
  label?: string;
52
+ /**
53
+ * Подсказка внутри пустого контрола.
54
+ * У Check — текст справа от квадрата (не `label`).
55
+ */
16
56
  placeholder?: string;
17
- /** true — только просмотр, без ввода (аналог нативного disabled) */
57
+ /**
58
+ * Только просмотр: нет фокуса, нет ввода, капсула `data-disabled="true"`.
59
+ * Не путать с `hidden`.
60
+ */
18
61
  disabled?: boolean;
19
62
  /**
20
- * true если значение поля **пустое**, поле не рендерится;
21
- * при непустом значении поле показывается.
63
+ * Не рендерить поле, **только если значение пустое**.
64
+ * Непустое значение всё равно показывается (удобно для «скрытых, пока нет данных»).
22
65
  */
23
66
  hidden?: boolean;
67
+ /** Текст ошибки под капсулой (`role="alert"`). Капсула получает класс ошибки. */
24
68
  error?: string;
69
+ /**
70
+ * Слот **справа** внутри капсулы (иконка, кнопка, `%`).
71
+ * Не путать с кнопкой «Set» снаружи в dev-стенде.
72
+ */
25
73
  after?: ReactNode;
74
+ /** Слот **слева** внутри капсулы (иконка бренда карты, превью цвета). */
26
75
  before?: ReactNode;
76
+ /** Свободный маркер вида (редко используется полями). */
27
77
  view?: string;
78
+ /**
79
+ * id контрола. Если не задан — генерируется.
80
+ * Нужен, чтобы `label htmlFor` указывал на input / contentEditable.
81
+ */
28
82
  id?: string;
83
+ /** Доп. класс на корне `[data-field]`, не на капсуле. */
29
84
  className?: string;
30
85
  /**
31
- * Высота: `"s"` | `"m"` | `"l"` как у кнопки и поиска.
32
- * Единая шкала с button/search: `"s"` | `"m"` | `"l"`.
33
- * `"sm"` / `"md"` — устаревшие алиасы (`elcrm migrate size-sml`).
86
+ * Высота капсулы: `s` | `m` | `l` (как кнопка/поиск).
87
+ * Меняет `--field-height` padding пересчитывается.
88
+ * `sm` / `md` — устаревшие алиасы (`elcrm migrate size-sml`).
89
+ * @default "m"
34
90
  */
35
91
  size?: "s" | "m" | "l" | "sm" | "md";
92
+ /** Зарезервировано (копирование); у Phone работает через `Form.Init` / notice. */
36
93
  isCopy?: boolean;
94
+ /** Макс. длина текста / цифр (нативный `maxLength` или логика CE). */
37
95
  maxLength?: number;
38
96
  /**
39
- * Проверка орфографии для **текстового** ввода (`Input`, `Textarea`).
40
- * Для полей только с цифрами в компонентах выставляется **`false`**.
97
+ * Орфография. У цифр/телефона/маски в компонентах обычно `false`.
41
98
  */
42
99
  spellCheck?: boolean;
43
100
  /**
44
- * Подсказка клавиатуры на мобильных (`inputMode`).
45
- * Для **чисел** `numeric`, для **денег** `decimal`, **телефон** `tel` (по умолчанию в полях).
101
+ * `inputMode` мобильной клавиатуры.
102
+ * Number `numeric`, Money `decimal`, Phone `tel`.
46
103
  */
47
104
  inputmode?: "text" | "email" | "none" | "tel" | "url" | "search" | "numeric" | "decimal";
48
105
  /**
49
- * Нативный `<input>` вместо **contentEditable** (`StringField`).
50
- * Нужен для **автозаполнения логина/почты** (менеджеры паролей работают с нативными полями).
51
- * У **`PasswordField`** свой проп **`native`** (см. **`TPasswordField`**).
106
+ * `StringField`: нативный `<input>` вместо contentEditable.
107
+ * Нужен для автозаполнения логина. У `PasswordField` свой смысл `native` — см. {@link TPasswordField}.
52
108
  */
53
109
  native?: boolean;
54
110
  /**
55
- * Атрибут **`autocomplete`** (например **`username`**, **`email`**, **`off`**).
56
- * Осмысленно при **`native`**; у `contentEditable` браузеры почти не применяют автозаполнение.
111
+ * HTML `autocomplete` (`username`, `email`, `off`). Имеет смысл при `native`.
57
112
  */
58
113
  autoComplete?: string;
59
114
  /**
60
- * Тип нативного поля при **`native`** (по умолчанию **`text`**).
61
- * Для почты удобно **`email`** + **`autoComplete="email"`**.
115
+ * `type` нативного input при `native` (`text` | `email` | …).
62
116
  */
63
117
  inputType?: "text" | "email" | "search" | "tel" | "url";
64
118
  };
65
- /** Базовые пропы текстовых и составных полей */
119
+ /**
120
+ * Базовые пропы почти всех `*Field`.
121
+ * Специфичные (`options`, `format`, `min`/`max`) — в типе конкретного поля (`TSelect`, `TDate`, …).
122
+ *
123
+ * @example
124
+ * <StringField name="login" form={form} label="Логин" />
125
+ */
66
126
  export type TInput = TFieldFormBindings & TFieldPresentation;
127
+ /**
128
+ * Полезная нагрузка `onValue` / `onBlur` / `form.setValue`.
129
+ * Это не `ChangeEvent`.
130
+ */
67
131
  export type TValue = {
132
+ /** Новое значение поля (тип зависит от компонента: string, number, boolean, File, …). */
68
133
  value: unknown;
134
+ /** Имя поля (`name`). */
69
135
  name: string;
70
136
  id?: string;
71
137
  };
72
138
  /**
73
- * Поле пароля: **`native`** из `TInput` убран — здесь свой **`native`** = «не рендерить поле».
139
+ * Пропы {@link PasswordField}.
140
+ * `native` здесь **не** «сделать `<input>`», а «не рисовать поле» (пароль снаружи).
74
141
  */
75
142
  export type TPasswordField = Omit<TInput, "native"> & {
76
- /** true — компонент не рендерится (пустая строка), пароль отдаётся нативному `<input>` снаружи */
143
+ /**
144
+ * `true` — компонент не рендерится (пустая строка).
145
+ * Для настоящего `<input type="password">` оставьте `native={false}` (по умолчанию).
146
+ */
77
147
  native?: boolean;
78
148
  /**
79
- * Свои иконки переключателя **[показать пароль, скрыть пароль]** (когда ввод скрыт / виден).
80
- * Если не задано используются встроенные SVG.
149
+ * Свои иконки переключателя видимости: `[показать, скрыть]`.
150
+ * Слот кнопка в `after` капсулы.
81
151
  */
82
152
  eyes?: [React.ReactNode?, React.ReactNode?];
83
153
  };