@brandup/ui-input 1.0.26 → 1.0.28
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/README.md +66 -8
- package/package.json +3 -3
- package/source/index.ts +1 -1
- package/source/input.ts +38 -32
package/README.md
CHANGED
|
@@ -1,18 +1,76 @@
|
|
|
1
|
-
# brandup
|
|
1
|
+
# @brandup/ui-input
|
|
2
2
|
|
|
3
|
-
[](https://dev.azure.com/brandup/BrandUp%20Core/_build/latest?definitionId=81&branchName=main)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Абстрактный базовый класс для компонентов ввода в форме. Обеспечивает единый интерфейс для `HTMLInputElement`, `HTMLTextAreaElement` и `HTMLSelectElement`.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Установка
|
|
8
8
|
|
|
9
9
|
```
|
|
10
|
-
npm i @brandup/ui-
|
|
10
|
+
npm i @brandup/ui-input
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
## InputControl
|
|
14
14
|
|
|
15
|
-
`InputControl<
|
|
16
|
-
относительно `HTMLInputElement`, `HTMLTextAreaElement`, `HTMLSelectElement`.
|
|
15
|
+
`InputControl<T, TEvents>` — абстрактный класс, от которого наследуются все компоненты ввода (`TextBox`, `DropDown`). Расширяет `UIElementBound` из `@brandup/ui`.
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
### Свойства
|
|
18
|
+
|
|
19
|
+
| Свойство | Тип | Описание |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| `form` | `HTMLFormElement \| null` | Форма, к которой привязан элемент |
|
|
22
|
+
| `disabled` | `boolean` | Элемент отключён |
|
|
23
|
+
| `required` | `boolean` | Элемент обязателен для заполнения |
|
|
24
|
+
| `readonly` | `boolean` | Элемент только для чтения (`readonly` или `data-readonly`) |
|
|
25
|
+
|
|
26
|
+
### Методы
|
|
27
|
+
|
|
28
|
+
| Метод | Описание |
|
|
29
|
+
|---|---|
|
|
30
|
+
| `validate(): boolean` | Проверяет значение через нативный `checkValidity()`. Возвращает `true`, если значение валидно |
|
|
31
|
+
| `focus(): void` | Устанавливает фокус и прокручивает элемент в видимую область |
|
|
32
|
+
| `destroy(): void` | Снимает все обработчики и освобождает ресурсы |
|
|
33
|
+
|
|
34
|
+
### Поведение
|
|
35
|
+
|
|
36
|
+
- Добавляет CSS-класс `ui-input` на корневой элемент.
|
|
37
|
+
- При инициализации добавляет классы `required`, `readonly`, `disabled` в зависимости от состояния элемента.
|
|
38
|
+
- Перехватывает событие `invalid` нативного поля и делегирует валидацию через `validate()`.
|
|
39
|
+
- Перехватывает `submit` формы: если элемент невалиден — останавливает отправку и вызывает `focus()`.
|
|
40
|
+
|
|
41
|
+
### Интерфейс IInputControl
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { IInputControl } from "@brandup/ui-input";
|
|
45
|
+
|
|
46
|
+
interface IInputControl {
|
|
47
|
+
get form(): HTMLFormElement | null;
|
|
48
|
+
get disabled(): boolean;
|
|
49
|
+
get required(): boolean;
|
|
50
|
+
get readonly(): boolean;
|
|
51
|
+
|
|
52
|
+
validate(): boolean;
|
|
53
|
+
focus(): void;
|
|
54
|
+
destroy(): void;
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Создание собственного компонента
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { InputControl } from "@brandup/ui-input";
|
|
62
|
+
|
|
63
|
+
class MyInput extends InputControl<HTMLInputElement> {
|
|
64
|
+
constructor(inputElem: HTMLInputElement) {
|
|
65
|
+
const wrapper = document.createElement("div");
|
|
66
|
+
inputElem.insertAdjacentElement("afterend", wrapper);
|
|
67
|
+
wrapper.appendChild(inputElem);
|
|
68
|
+
|
|
69
|
+
super("MyInput", wrapper, inputElem);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
getValue(): string {
|
|
73
|
+
return this.__valueElem.value;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
package/package.json
CHANGED
|
@@ -21,12 +21,12 @@
|
|
|
21
21
|
"email": "it@brandup.online"
|
|
22
22
|
},
|
|
23
23
|
"license": "Apache-2.0",
|
|
24
|
-
"version": "1.0.
|
|
24
|
+
"version": "1.0.28",
|
|
25
25
|
"main": "source/index.ts",
|
|
26
26
|
"types": "source/index.ts",
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@brandup/ui": "^
|
|
29
|
-
"@brandup/ui-kit": "^1.0.
|
|
28
|
+
"@brandup/ui": "^2.0.2",
|
|
29
|
+
"@brandup/ui-kit": "^1.0.28"
|
|
30
30
|
},
|
|
31
31
|
"files": [
|
|
32
32
|
"source",
|
package/source/index.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from "./input"
|
|
1
|
+
export * from "./input";
|
package/source/input.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { UIElementBound } from "@brandup/ui";
|
|
2
2
|
import "./input.less";
|
|
3
3
|
|
|
4
4
|
type InputType = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;
|
|
@@ -6,37 +6,55 @@ type FormInput<T> = T extends InputType ? T : never;
|
|
|
6
6
|
|
|
7
7
|
export const INPUT_CSS_CLASS = "ui-input";
|
|
8
8
|
|
|
9
|
-
export abstract class InputControl<T extends InputType
|
|
9
|
+
export abstract class InputControl<T extends InputType, TEvents = {}>
|
|
10
|
+
extends UIElementBound<TEvents>
|
|
11
|
+
implements IInputControl
|
|
12
|
+
{
|
|
10
13
|
protected __valueElem: FormInput<T>;
|
|
11
14
|
protected __submitEvent?: (e: SubmitEvent) => void;
|
|
15
|
+
private __invalidEvent?: (e: Event) => void;
|
|
12
16
|
private __isValidating?: boolean; // true, когда выполняется checkValidity в validate.
|
|
13
17
|
|
|
14
|
-
constructor(valueElem: FormInput<T>) {
|
|
15
|
-
super();
|
|
18
|
+
constructor(typeName: string, elem: HTMLElement, valueElem: FormInput<T>) {
|
|
19
|
+
super(typeName, elem);
|
|
16
20
|
|
|
17
21
|
this.__valueElem = valueElem;
|
|
18
22
|
|
|
23
|
+
// то, что раньше делал _onRenderElement-override; теперь применяем после super, чтобы видеть valueElem
|
|
24
|
+
elem.classList.add(INPUT_CSS_CLASS);
|
|
25
|
+
if (this.required) elem.classList.add("required");
|
|
26
|
+
if (this.readonly) elem.classList.add("readonly");
|
|
27
|
+
if (this.disabled) elem.classList.add("disabled");
|
|
28
|
+
|
|
19
29
|
this.__initForm();
|
|
20
30
|
}
|
|
21
31
|
|
|
22
|
-
get form(): HTMLFormElement | null {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
get
|
|
32
|
+
get form(): HTMLFormElement | null {
|
|
33
|
+
return this.__valueElem.form;
|
|
34
|
+
}
|
|
35
|
+
get disabled(): boolean {
|
|
36
|
+
return this.__valueElem.disabled;
|
|
37
|
+
}
|
|
38
|
+
get required(): boolean {
|
|
39
|
+
return this.__valueElem.required;
|
|
40
|
+
}
|
|
41
|
+
get readonly(): boolean {
|
|
42
|
+
return this.__valueElem.hasAttribute("readonly") || this.__valueElem.hasAttribute("data-readonly");
|
|
43
|
+
}
|
|
26
44
|
|
|
27
45
|
private __initForm() {
|
|
28
|
-
this.
|
|
46
|
+
this.__invalidEvent = (e: Event) => {
|
|
29
47
|
e.preventDefault();
|
|
30
48
|
|
|
31
49
|
this.__submitForm();
|
|
32
|
-
}
|
|
50
|
+
};
|
|
51
|
+
this.__valueElem.addEventListener("invalid", this.__invalidEvent);
|
|
33
52
|
|
|
34
53
|
this.__submitEvent = (e: SubmitEvent) => {
|
|
35
|
-
if ((
|
|
54
|
+
if ((e.submitter as HTMLButtonElement | null)?.formNoValidate || (<HTMLFormElement>e.target).noValidate)
|
|
36
55
|
return; // Не делаем валидацию, если она отключена в форме или в инициаторе события submit
|
|
37
56
|
|
|
38
|
-
if (this.disabled)
|
|
39
|
-
return;
|
|
57
|
+
if (this.disabled) return;
|
|
40
58
|
|
|
41
59
|
if (!this.validate()) {
|
|
42
60
|
if (!e.defaultPrevented) {
|
|
@@ -49,8 +67,7 @@ export abstract class InputControl<T extends InputType> extends UIElement implem
|
|
|
49
67
|
}
|
|
50
68
|
};
|
|
51
69
|
|
|
52
|
-
if (this.form)
|
|
53
|
-
this.form.addEventListener("submit", this.__submitEvent);
|
|
70
|
+
if (this.form) this.form.addEventListener("submit", this.__submitEvent);
|
|
54
71
|
}
|
|
55
72
|
|
|
56
73
|
protected __submitForm() {
|
|
@@ -59,20 +76,8 @@ export abstract class InputControl<T extends InputType> extends UIElement implem
|
|
|
59
76
|
form.dispatchEvent(new SubmitEvent("submit", { submitter: form, cancelable: true }));
|
|
60
77
|
}
|
|
61
78
|
|
|
62
|
-
protected override _onRenderElement(elem: HTMLElement) {
|
|
63
|
-
elem.classList.add(INPUT_CSS_CLASS);
|
|
64
|
-
|
|
65
|
-
if (this.required)
|
|
66
|
-
elem.classList.add("required");
|
|
67
|
-
if (this.readonly)
|
|
68
|
-
elem.classList.add("readonly");
|
|
69
|
-
if (this.disabled)
|
|
70
|
-
elem.classList.add("disabled");
|
|
71
|
-
}
|
|
72
|
-
|
|
73
79
|
validate(): boolean {
|
|
74
|
-
if (this.__isValidating)
|
|
75
|
-
return true;
|
|
80
|
+
if (this.__isValidating) return true;
|
|
76
81
|
|
|
77
82
|
this.__isValidating = true;
|
|
78
83
|
const result = this.__valueElem.checkValidity();
|
|
@@ -83,12 +88,13 @@ export abstract class InputControl<T extends InputType> extends UIElement implem
|
|
|
83
88
|
|
|
84
89
|
focus(): void {
|
|
85
90
|
this.__valueElem.focus();
|
|
86
|
-
this.element
|
|
91
|
+
this.element.scrollIntoView({ block: "center", inline: "center" });
|
|
87
92
|
}
|
|
88
93
|
|
|
89
94
|
override destroy() {
|
|
90
|
-
if (this.form && this.__submitEvent)
|
|
91
|
-
|
|
95
|
+
if (this.form && this.__submitEvent) this.form.removeEventListener("submit", this.__submitEvent);
|
|
96
|
+
|
|
97
|
+
if (this.__invalidEvent) this.__valueElem.removeEventListener("invalid", this.__invalidEvent);
|
|
92
98
|
|
|
93
99
|
super.destroy();
|
|
94
100
|
}
|
|
@@ -103,4 +109,4 @@ export interface IInputControl {
|
|
|
103
109
|
validate(): boolean;
|
|
104
110
|
focus(): void;
|
|
105
111
|
destroy(): void;
|
|
106
|
-
}
|
|
112
|
+
}
|