@elcrm/form 0.0.80 → 0.0.81

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.
@@ -0,0 +1,82 @@
1
+ import e from "../styles/Field.module.js";
2
+ import t from "../core/Field.js";
3
+ import { useFormFieldState as n } from "../hooks/use.js";
4
+ import r from "react";
5
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
6
+ //#region src/lib/fields/Rating.tsx
7
+ function o(e, t) {
8
+ return Number.isFinite(e) ? Math.min(t, Math.max(0, Math.round(e))) : 0;
9
+ }
10
+ function s({ value: s = 0, form: c, onValue: l, onBlur: u, name: d = "", placeholder: f = "", label: p = "", error: m = "", hidden: h = !1, disabled: g = !1, className: _ = "", after: v = "", before: y = "", max: b = 5, allowClear: x = !0 }) {
11
+ let { value: S } = n(c, d, s), C = o(Number(S), b), w = !g, [T, E] = r.useState(0), D = (e) => {
12
+ let t = {
13
+ value: e,
14
+ name: d
15
+ };
16
+ c && d && c.setValue(t), l && l !== c?.onValue && l(t);
17
+ };
18
+ if (h && !C) return null;
19
+ let O = T || C;
20
+ return /* @__PURE__ */ a(t, {
21
+ type: "rating",
22
+ label: p,
23
+ error: m,
24
+ element_blok: { className: [_ || ""] },
25
+ element_input: {
26
+ className: [e.rating],
27
+ props: { "data-disabled": g || !w ? "true" : void 0 }
28
+ },
29
+ children: [
30
+ y ? /* @__PURE__ */ i("span", {
31
+ className: e.affix,
32
+ children: y
33
+ }) : null,
34
+ /* @__PURE__ */ i("div", {
35
+ role: "slider",
36
+ "aria-label": p || f || "Оценка",
37
+ "aria-valuemin": 0,
38
+ "aria-valuemax": b,
39
+ "aria-valuenow": C,
40
+ tabIndex: w ? 0 : -1,
41
+ onMouseLeave: () => E(0),
42
+ onBlur: () => {
43
+ E(0), u?.({
44
+ value: C,
45
+ name: d
46
+ });
47
+ },
48
+ onKeyDown: (e) => {
49
+ if (!w) return;
50
+ let t = C;
51
+ if (e.key === "ArrowRight" || e.key === "ArrowUp") t = Math.min(b, C + 1);
52
+ else if (e.key === "ArrowLeft" || e.key === "ArrowDown") t = Math.max(0, C - 1);
53
+ else if (e.key === "Home") t = 0;
54
+ else if (e.key === "End") t = b;
55
+ else return;
56
+ e.preventDefault(), D(t);
57
+ },
58
+ children: Array.from({ length: b }, (t, n) => {
59
+ let r = n + 1;
60
+ return /* @__PURE__ */ i("button", {
61
+ type: "button",
62
+ className: r <= O ? `${e.ratingStar} ${e.ratingStarOn}` : e.ratingStar,
63
+ "aria-label": `${r} из ${b}`,
64
+ disabled: !w,
65
+ onMouseEnter: () => w && E(r),
66
+ onClick: () => {
67
+ w && D(x && C === r ? 0 : r);
68
+ },
69
+ children: "★"
70
+ }, r);
71
+ })
72
+ }),
73
+ v ? /* @__PURE__ */ i("span", {
74
+ className: e.affix,
75
+ children: v
76
+ }) : null
77
+ ]
78
+ });
79
+ }
80
+ s.displayName = "RatingField";
81
+ //#endregion
82
+ export { s as default };
@@ -0,0 +1,14 @@
1
+ import { TInput } from './type';
2
+ /**
3
+ * RichTextField — простой WYSIWYG без внешних библиотек.
4
+ * Значение: HTML-строка. Панель: жирный / курсив / подчёркивание / списки.
5
+ */
6
+ export type TRichText = TInput & {
7
+ /** Показать панель форматирования */
8
+ toolbar?: boolean;
9
+ };
10
+ 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
+ declare namespace RichTextField {
12
+ var displayName: string;
13
+ }
14
+ export default RichTextField;
@@ -0,0 +1,134 @@
1
+ import e from "../styles/Field.module.js";
2
+ import t from "../core/Field.js";
3
+ import { useFormFieldState as n } from "../hooks/use.js";
4
+ import { isEmptyTextLike as r } from "./visibility.js";
5
+ import i from "react";
6
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
7
+ //#region src/lib/fields/RichText.tsx
8
+ function s({ value: s = "", form: c, onValue: l, onBlur: u, name: d = "", placeholder: f = "", label: p = "", error: m = "", hidden: h = !1, disabled: g = !1, className: _ = "", after: v = "", before: y = "", maxLength: b, spellCheck: x = !0, toolbar: S = !0 }) {
9
+ let { value: C, version: w } = n(c, d, s), T = !g, E = typeof C == "string" ? C : "", D = i.useRef(null), O = i.useRef(!1);
10
+ i.useLayoutEffect(() => {
11
+ if (O.current) return;
12
+ let e = D.current;
13
+ e && e.innerHTML !== E && (e.innerHTML = E || "");
14
+ }, [E, w]);
15
+ let k = (e, t = !1) => {
16
+ let n = e;
17
+ if (b && n.replace(/<[^>]+>/g, "").length > b) return;
18
+ let r = {
19
+ value: n,
20
+ name: d
21
+ };
22
+ c && d && (t ? c.setValue(r) : c.onValue(r)), l && l !== c?.onValue && l(r);
23
+ }, A = (e) => {
24
+ if (T) {
25
+ D.current?.focus();
26
+ try {
27
+ document.execCommand(e, !1);
28
+ } catch {}
29
+ k(D.current?.innerHTML || "");
30
+ }
31
+ };
32
+ if (h && r(E.replace(/<[^>]+>/g, ""))) return null;
33
+ let j = {};
34
+ return f && !E && (j.placeholder = f), T && (j.edit = ""), /* @__PURE__ */ o(t, {
35
+ type: "richtext",
36
+ label: p,
37
+ error: m,
38
+ element_blok: { className: [_ || ""] },
39
+ element_input: {
40
+ className: [e.rich],
41
+ props: { "data-disabled": g || !T ? "true" : void 0 }
42
+ },
43
+ children: [
44
+ y ? /* @__PURE__ */ a("span", {
45
+ className: e.affix,
46
+ children: y
47
+ }) : null,
48
+ /* @__PURE__ */ o("div", {
49
+ className: e.richWrap,
50
+ children: [S ? /* @__PURE__ */ o("div", {
51
+ className: e.richToolbar,
52
+ role: "toolbar",
53
+ children: [
54
+ /* @__PURE__ */ a("button", {
55
+ type: "button",
56
+ className: e.richBtn,
57
+ disabled: !T,
58
+ "aria-label": "Жирный",
59
+ onMouseDown: (e) => e.preventDefault(),
60
+ onClick: () => A("bold"),
61
+ children: "B"
62
+ }),
63
+ /* @__PURE__ */ a("button", {
64
+ type: "button",
65
+ className: e.richBtn,
66
+ disabled: !T,
67
+ "aria-label": "Курсив",
68
+ onMouseDown: (e) => e.preventDefault(),
69
+ onClick: () => A("italic"),
70
+ children: /* @__PURE__ */ a("em", { children: "I" })
71
+ }),
72
+ /* @__PURE__ */ a("button", {
73
+ type: "button",
74
+ className: e.richBtn,
75
+ disabled: !T,
76
+ "aria-label": "Подчёркивание",
77
+ onMouseDown: (e) => e.preventDefault(),
78
+ onClick: () => A("underline"),
79
+ children: /* @__PURE__ */ a("u", { children: "U" })
80
+ }),
81
+ /* @__PURE__ */ a("button", {
82
+ type: "button",
83
+ className: e.richBtn,
84
+ disabled: !T,
85
+ "aria-label": "Маркированный список",
86
+ onMouseDown: (e) => e.preventDefault(),
87
+ onClick: () => A("insertUnorderedList"),
88
+ children: "•"
89
+ }),
90
+ /* @__PURE__ */ a("button", {
91
+ type: "button",
92
+ className: e.richBtn,
93
+ disabled: !T,
94
+ "aria-label": "Нумерованный список",
95
+ onMouseDown: (e) => e.preventDefault(),
96
+ onClick: () => A("insertOrderedList"),
97
+ children: "1."
98
+ })
99
+ ]
100
+ }) : null, /* @__PURE__ */ a("div", {
101
+ ref: D,
102
+ className: e.richEditor,
103
+ contentEditable: T,
104
+ suppressContentEditableWarning: !0,
105
+ spellCheck: x,
106
+ role: "textbox",
107
+ "aria-multiline": !0,
108
+ "aria-label": p || f || "Текст",
109
+ tabIndex: T ? 0 : -1,
110
+ onFocus: () => {
111
+ O.current = !0;
112
+ },
113
+ onInput: () => k(D.current?.innerHTML || ""),
114
+ onBlur: () => {
115
+ O.current = !1;
116
+ let e = D.current?.innerHTML || "";
117
+ k(e, !0), u?.({
118
+ value: e,
119
+ name: d
120
+ });
121
+ },
122
+ ...j
123
+ })]
124
+ }),
125
+ v ? /* @__PURE__ */ a("span", {
126
+ className: e.affix,
127
+ children: v
128
+ }) : null
129
+ ]
130
+ });
131
+ }
132
+ s.displayName = "RichTextField";
133
+ //#endregion
134
+ export { s as default };
@@ -0,0 +1,12 @@
1
+ import { TInput } from './type';
2
+ /** TagsField — чипы / метки. Значение: `string[]`. */
3
+ export type TTags = TInput & {
4
+ maxTags?: number;
5
+ /** Разделители при вводе (по умолчанию Enter / запятая) */
6
+ separators?: string[];
7
+ };
8
+ 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
+ declare namespace TagsField {
10
+ var displayName: string;
11
+ }
12
+ export default TagsField;
@@ -0,0 +1,97 @@
1
+ import e from "../styles/Field.module.js";
2
+ import t from "../core/Field.js";
3
+ import { useFormFieldState as n } from "../hooks/use.js";
4
+ import r from "react";
5
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
6
+ //#region src/lib/fields/Tags.tsx
7
+ function o(e) {
8
+ return Array.isArray(e) ? e.map(String).map((e) => e.trim()).filter(Boolean) : typeof e == "string" && e.trim() ? e.split(",").map((e) => e.trim()).filter(Boolean) : [];
9
+ }
10
+ function s({ value: s = [], form: c, onValue: l, onBlur: u, name: d = "", placeholder: f = "Добавить…", label: p = "", error: m = "", hidden: h = !1, disabled: g = !1, className: _ = "", after: v = "", before: y = "", maxTags: b, maxLength: x, separators: S = [",", "Enter"] }) {
11
+ let { value: C } = n(c, d, s), w = o(C), T = !g, [E, D] = r.useState(""), O = r.useRef(null), k = (e) => {
12
+ let t = {
13
+ value: e,
14
+ name: d
15
+ };
16
+ c && d && c.setValue(t), l && l !== c?.onValue && l(t);
17
+ }, A = (e) => {
18
+ let t = e.trim();
19
+ if (t && !(x && t.length > x)) {
20
+ if (w.some((e) => e.toLowerCase() === t.toLowerCase())) {
21
+ D("");
22
+ return;
23
+ }
24
+ b !== void 0 && w.length >= b || (k([...w, t]), D(""));
25
+ }
26
+ }, j = (e) => {
27
+ T && k(w.filter((t, n) => n !== e));
28
+ }, M = (e) => {
29
+ if (T) {
30
+ if (S.includes(e.key) || e.key === "," && S.includes(",")) {
31
+ e.preventDefault(), A(E);
32
+ return;
33
+ }
34
+ e.key === "Backspace" && !E && w.length > 0 && (e.preventDefault(), j(w.length - 1));
35
+ }
36
+ }, N = w.length === 0;
37
+ return h && N ? null : /* @__PURE__ */ a(t, {
38
+ type: "tags",
39
+ label: p,
40
+ error: m,
41
+ element_blok: { className: [_ || ""] },
42
+ element_input: {
43
+ className: [e.tags],
44
+ props: {
45
+ "data-disabled": g || !T ? "true" : void 0,
46
+ onClick: () => O.current?.focus()
47
+ }
48
+ },
49
+ children: [
50
+ y ? /* @__PURE__ */ i("span", {
51
+ className: e.affix,
52
+ children: y
53
+ }) : null,
54
+ /* @__PURE__ */ a("div", {
55
+ className: e.tagsInner,
56
+ children: [w.map((t, n) => /* @__PURE__ */ a("span", {
57
+ className: e.tagChip,
58
+ children: [/* @__PURE__ */ i("span", {
59
+ className: e.tagLabel,
60
+ children: t
61
+ }), T ? /* @__PURE__ */ i("button", {
62
+ type: "button",
63
+ className: e.tagRemove,
64
+ "aria-label": `Удалить ${t}`,
65
+ onClick: (e) => {
66
+ e.stopPropagation(), j(n);
67
+ },
68
+ children: "×"
69
+ }) : null]
70
+ }, `${t}-${n}`)), T && (b === void 0 || w.length < b) ? /* @__PURE__ */ i("input", {
71
+ ref: O,
72
+ className: e.tagInput,
73
+ value: E,
74
+ placeholder: w.length === 0 ? f : "",
75
+ disabled: g,
76
+ maxLength: x,
77
+ "aria-label": p || f || "Теги",
78
+ onChange: (e) => D(e.target.value),
79
+ onKeyDown: M,
80
+ onBlur: () => {
81
+ E.trim() && A(E), u?.({
82
+ value: w,
83
+ name: d
84
+ });
85
+ }
86
+ }) : null]
87
+ }),
88
+ v ? /* @__PURE__ */ i("span", {
89
+ className: e.affix,
90
+ children: v
91
+ }) : null
92
+ ]
93
+ });
94
+ }
95
+ s.displayName = "TagsField";
96
+ //#endregion
97
+ export { s as default };
@@ -13,13 +13,20 @@ export type TTime = TInput & {
13
13
  * @default 'start'
14
14
  */
15
15
  align?: "start" | "center";
16
+ /**
17
+ * Кнопка быстрого выбора: popup со слотами времени.
18
+ * Слоты строятся по `step` / `min` / `max` или из `presets`.
19
+ */
20
+ picker?: boolean;
21
+ /** Свои слоты `HH:mm` для popup (если заданы — вместо автогенерации) */
22
+ presets?: string[];
16
23
  };
17
24
  /**
18
25
  * Время: два contentEditable по образцу Mask (каретка через queueMicrotask + setCursorPosition).
19
26
  * Пока фокус в группе — в DOM только введённые цифры без ведущих нулей; в форму значение
20
27
  * уходит при уходе фокуса с группы (snap минут, clamp, формат `HH:mm`).
21
28
  */
22
- declare function TimeField({ value, form, onValue, onBlur: onBlurField, name, placeholder, label, hidden, disabled, error, className, after, before, step, min, max, id, spellCheck, align, }: TTime): import("react/jsx-runtime").JSX.Element | null;
29
+ 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;
23
30
  declare namespace TimeField {
24
31
  var displayName: string;
25
32
  }