@elcrm/form 0.0.80 → 0.0.82
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.
- package/dist/assets/styles/Field.module.css +1 -1
- package/dist/core/Field.js +1 -1
- package/dist/fields/Code.d.ts +14 -0
- package/dist/fields/Code.js +94 -0
- package/dist/fields/Color.js +127 -80
- package/dist/fields/Date.js +132 -77
- package/dist/fields/Display.d.ts +17 -0
- package/dist/fields/Display.js +49 -0
- package/dist/fields/DragDrop.d.ts +26 -0
- package/dist/fields/DragDrop.js +189 -0
- package/dist/fields/Email.d.ts +8 -0
- package/dist/fields/Email.js +80 -0
- package/dist/fields/File.d.ts +24 -0
- package/dist/fields/File.js +115 -0
- package/dist/fields/Hidden.d.ts +11 -0
- package/dist/fields/Hidden.js +33 -0
- package/dist/fields/Numeric.js +42 -24
- package/dist/fields/Percent.d.ts +13 -0
- package/dist/fields/Percent.js +100 -0
- package/dist/fields/Radio.d.ts +22 -0
- package/dist/fields/Radio.js +88 -0
- package/dist/fields/Rating.d.ts +12 -0
- package/dist/fields/Rating.js +82 -0
- package/dist/fields/RichText.d.ts +14 -0
- package/dist/fields/RichText.js +134 -0
- package/dist/fields/Tags.d.ts +12 -0
- package/dist/fields/Tags.js +97 -0
- package/dist/fields/Time.d.ts +8 -1
- package/dist/fields/Time.js +330 -156
- package/dist/fields/Url.d.ts +8 -0
- package/dist/fields/Url.js +80 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +18 -6
- package/dist/index.umd.js +2 -2
- package/dist/package.js +1 -1
- package/dist/style.css +1 -1
- package/dist/styles/Field.module.js +72 -24
- package/package.json +2 -2
|
@@ -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 };
|
package/dist/fields/Time.d.ts
CHANGED
|
@@ -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
|
}
|