@brandup/ui-textbox 1.0.34 → 1.0.38
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 +17 -8
- package/package.json +9 -5
- package/source/index.ts +7 -1
- package/source/textbox.less +9 -107
- package/source/textbox.ts +122 -542
- package/source/format.ts +0 -546
- package/svg/bold.svg +0 -3
- package/svg/italic.svg +0 -3
- package/svg/strike.svg +0 -5
- package/svg/underline.svg +0 -4
package/README.md
CHANGED
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://dev.azure.com/brandup/BrandUp%20Core/_build/latest?definitionId=81&branchName=main)
|
|
4
4
|
|
|
5
|
-
Компонент текстового
|
|
5
|
+
Компонент текстового поля. Заменяет стандартные `<input>` и `<textarea>`, добавляя расширенное поведение: счётчик символов, кнопку копирования, фильтрацию ввода по типу, валидацию и опциональное форматирование текста (жирный, курсив, зачёркивание, подчёркивание).
|
|
6
|
+
|
|
7
|
+
Вся работа с редактируемой областью вынесена в [`@brandup/ui-richeditor`](../brandup-ui-richeditor): `TextBox` создаёт скрытое поле формы и компонует над ним `RichEditor`. Экземпляр редактора доступен через свойство `editor`.
|
|
6
8
|
|
|
7
9
|
## Установка
|
|
8
10
|
|
|
9
|
-
```
|
|
11
|
+
```bash
|
|
10
12
|
npm i @brandup/ui-textbox
|
|
11
13
|
```
|
|
12
14
|
|
|
@@ -33,7 +35,7 @@ textbox.on(CHANGE_EVENT, (data: ChangeEventData) => {
|
|
|
33
35
|
`TextBox` принимает `<input>` со следующими значениями атрибута `type`:
|
|
34
36
|
|
|
35
37
|
| Тип | Поведение |
|
|
36
|
-
|
|
38
|
+
| --- | --- |
|
|
37
39
|
| `text` | Обычный текст |
|
|
38
40
|
| `email` | Фильтрует недопустимые символы, ограничивает длину до 256 символов (RFC 5321) |
|
|
39
41
|
| `url` | URL-адрес |
|
|
@@ -45,7 +47,7 @@ textbox.on(CHANGE_EVENT, (data: ChangeEventData) => {
|
|
|
45
47
|
## Data-атрибуты
|
|
46
48
|
|
|
47
49
|
| Атрибут | Описание |
|
|
48
|
-
|
|
50
|
+
| --- | --- |
|
|
49
51
|
| `data-symbolcounter` | Показывает счётчик введённых символов (и максимума, если задан `maxlength`) |
|
|
50
52
|
| `data-autofocus` | Автофокус при инициализации (игнорируется на touch-устройствах) |
|
|
51
53
|
| `data-copy-button` | Добавляет кнопку копирования значения в буфер обмена |
|
|
@@ -53,6 +55,7 @@ textbox.on(CHANGE_EVENT, (data: ChangeEventData) => {
|
|
|
53
55
|
| `data-readonly` | Альтернативный способ задать режим только для чтения |
|
|
54
56
|
| `data-format` | Включает форматирование текста (только для `type="text"`) |
|
|
55
57
|
| `data-format-tools` | Состав инструментов форматирования через пробел (по умолчанию все): `bold italic strike underline` |
|
|
58
|
+
| `data-editor-actions` | Кнопки действий в панели через пробел (по умолчанию нет): `erase undo redo` |
|
|
56
59
|
| `data-format-storage` | Формат хранения значения: `html` (по умолчанию) или `markdown` |
|
|
57
60
|
| `data-format-md-bold` | Markdown-маркер для жирного (по умолчанию `**`) |
|
|
58
61
|
| `data-format-md-italic` | Markdown-маркер для курсива (по умолчанию `*`) |
|
|
@@ -81,6 +84,12 @@ textbox.on(CHANGE_EVENT, (data: ChangeEventData) => {
|
|
|
81
84
|
|
|
82
85
|
Список через пробел из значений `bold`, `italic`, `strike`, `underline`. Неизвестные значения игнорируются. Если атрибут не задан — включаются все инструменты.
|
|
83
86
|
|
|
87
|
+
### Кнопки действий — `data-editor-actions`
|
|
88
|
+
|
|
89
|
+
Список через пробел из значений `erase` (очистить форматирование), `undo` (отменить), `redo` (повторить). В отличие от инструментов, действия подключаются явно: без атрибута кнопок действий нет. Они добавляются в панель после инструментов форматирования, отделяются разделителем и блокируются, когда действие недоступно (нечего отменять или очищать).
|
|
90
|
+
|
|
91
|
+
`erase` снимает все форматы с выделения, а без выделения — со слова под кареткой. Чтобы очистить всё поле, выделите текст целиком (`Ctrl+A`) и нажмите кнопку.
|
|
92
|
+
|
|
84
93
|
### Применение формата
|
|
85
94
|
|
|
86
95
|
- Формат — **переключатель** (toggle): повторное применение к уже отформатированному тексту снимает его.
|
|
@@ -98,7 +107,7 @@ textbox.on(CHANGE_EVENT, (data: ChangeEventData) => {
|
|
|
98
107
|
Значение синхронизируется в скрытое поле в выбранном формате:
|
|
99
108
|
|
|
100
109
|
| Значение | Хранение | Поддерживаемые теги/маркеры |
|
|
101
|
-
|
|
110
|
+
| --- | --- | --- |
|
|
102
111
|
| `html` (по умолчанию) | Санитизированный HTML | `<b>`, `<i>`, `<s>`, `<u>`, переводы строк через `<br>` |
|
|
103
112
|
| `markdown` | Лёгкая разметка | `**жирный**`, `*курсив*`, `~~зачёркнутый~~`, `++подчёркнутый++` |
|
|
104
113
|
|
|
@@ -123,7 +132,7 @@ textbox.on(CHANGE_EVENT, (data: ChangeEventData) => {
|
|
|
123
132
|
### Методы
|
|
124
133
|
|
|
125
134
|
| Метод | Описание |
|
|
126
|
-
|
|
135
|
+
| --- | --- |
|
|
127
136
|
| `getValue(): string` | Возвращает текущее значение (обрезает пробелы по краям) |
|
|
128
137
|
| `setValue(value: string): void` | Устанавливает значение программно |
|
|
129
138
|
| `hasValue(): boolean` | `true`, если значение не пустое |
|
|
@@ -134,7 +143,7 @@ textbox.on(CHANGE_EVENT, (data: ChangeEventData) => {
|
|
|
134
143
|
### Свойства
|
|
135
144
|
|
|
136
145
|
| Свойство | Тип | Описание |
|
|
137
|
-
|
|
146
|
+
| --- | --- | --- |
|
|
138
147
|
| `type` | `TextBoxType` | Тип ввода: `"text"` \| `"email"` \| `"url"` \| `"tel"` \| `"number"` |
|
|
139
148
|
| `multyline` | `boolean` | `true` для `<textarea>` |
|
|
140
149
|
| `maxlength` | `number` | Максимальная длина (из атрибута `maxlength`) |
|
|
@@ -174,7 +183,7 @@ textbox.onChange((data) => { ... });
|
|
|
174
183
|
## CSS-классы состояний
|
|
175
184
|
|
|
176
185
|
| Класс | Условие |
|
|
177
|
-
|
|
186
|
+
| --- | --- |
|
|
178
187
|
| `focused` | Поле в фокусе |
|
|
179
188
|
| `invalid` | Значение не прошло валидацию |
|
|
180
189
|
| `incorrect` | Введён недопустимый символ (мигает, затем снимается) |
|
package/package.json
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
+
"publishConfig": {
|
|
3
|
+
"access": "public"
|
|
4
|
+
},
|
|
2
5
|
"name": "@brandup/ui-textbox",
|
|
3
6
|
"description": "Textbox control type and styles.",
|
|
4
7
|
"keywords": [
|
|
@@ -21,14 +24,15 @@
|
|
|
21
24
|
"email": "it@brandup.online"
|
|
22
25
|
},
|
|
23
26
|
"license": "Apache-2.0",
|
|
24
|
-
"version": "1.0.
|
|
27
|
+
"version": "1.0.38",
|
|
25
28
|
"main": "source/index.ts",
|
|
26
29
|
"types": "source/index.ts",
|
|
27
30
|
"dependencies": {
|
|
28
|
-
"@brandup/ui": "^2.0.
|
|
29
|
-
"@brandup/ui-helpers": "^2.0.
|
|
30
|
-
"@brandup/ui-input": "^1.0.
|
|
31
|
-
"@brandup/ui-kit": "^1.0.
|
|
31
|
+
"@brandup/ui": "^2.0.7",
|
|
32
|
+
"@brandup/ui-helpers": "^2.0.7",
|
|
33
|
+
"@brandup/ui-input": "^1.0.38",
|
|
34
|
+
"@brandup/ui-kit": "^1.0.38",
|
|
35
|
+
"@brandup/ui-richeditor": "^1.0.38"
|
|
32
36
|
},
|
|
33
37
|
"files": [
|
|
34
38
|
"source",
|
package/source/index.ts
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
export { default } from "./textbox";
|
|
2
2
|
export * from "./textbox";
|
|
3
|
+
|
|
4
|
+
// реэкспорт типов/утилит форматирования из @brandup/ui-richeditor для обратной совместимости
|
|
3
5
|
export {
|
|
6
|
+
ALL_EDITOR_ACTIONS,
|
|
4
7
|
ALL_FORMAT_TOOLS,
|
|
8
|
+
EDITOR_ACTIONS,
|
|
5
9
|
FORMAT_TOOLS,
|
|
10
|
+
parseEditorActions,
|
|
6
11
|
parseFormatTools,
|
|
7
12
|
defaultFormatMarkers,
|
|
8
13
|
normalizeWhitespace,
|
|
14
|
+
type EditorAction,
|
|
9
15
|
type FormatTool,
|
|
10
16
|
type FormatStorage,
|
|
11
17
|
type FormatMarkers,
|
|
12
|
-
} from "
|
|
18
|
+
} from "@brandup/ui-richeditor";
|
package/source/textbox.less
CHANGED
|
@@ -46,11 +46,11 @@
|
|
|
46
46
|
box-sizing: border-box;
|
|
47
47
|
cursor: text;
|
|
48
48
|
position: relative;
|
|
49
|
-
overflow-y: auto;
|
|
50
49
|
z-index: 2;
|
|
51
50
|
margin-right: 5px;
|
|
52
51
|
padding-right: calc(var(--input-padding-lr) - 5px);
|
|
53
52
|
scrollbar-width: 6px;
|
|
53
|
+
overflow-y: auto;
|
|
54
54
|
|
|
55
55
|
&::-webkit-scrollbar {
|
|
56
56
|
width: 6px;
|
|
@@ -71,36 +71,15 @@
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
position: relative;
|
|
74
|
+
// редактор (@brandup/ui-richeditor) — занимает доступное место; внутреннее оформление в richeditor.less
|
|
75
|
+
& .ui-richeditor {
|
|
77
76
|
flex: 1 1 auto;
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
white-space: pre-wrap; // сохраняем пробелы (в т.ч. ведущие/повторяющиеся), чтобы они были видны
|
|
81
|
-
outline: none;
|
|
82
|
-
|
|
83
|
-
&:empty {
|
|
84
|
-
&:after {
|
|
85
|
-
content: attr(data-placeholder);
|
|
86
|
-
display: block;
|
|
87
|
-
position: absolute;
|
|
88
|
-
left: 0;
|
|
89
|
-
top: 0;
|
|
90
|
-
right: 0;
|
|
91
|
-
color: var(--placeholder-color);
|
|
92
|
-
font-weight: var(--placeholder-font-weight);
|
|
93
|
-
font-style: var(--placeholder-font-style);
|
|
94
|
-
box-sizing: border-box;
|
|
95
|
-
overflow: hidden;
|
|
96
|
-
white-space: nowrap;
|
|
97
|
-
text-overflow: ellipsis;
|
|
98
|
-
}
|
|
77
|
+
min-width: 0;
|
|
78
|
+
}
|
|
99
79
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
80
|
+
// скрываем счётчик, пока редактор пуст (показан placeholder)
|
|
81
|
+
& .editor:has(.ui-richeditor:empty) .symbols {
|
|
82
|
+
display: none;
|
|
104
83
|
}
|
|
105
84
|
|
|
106
85
|
& .symbols {
|
|
@@ -154,76 +133,6 @@
|
|
|
154
133
|
}
|
|
155
134
|
}
|
|
156
135
|
|
|
157
|
-
// панель форматирования — плавающая панель над контролом, появляется в фокусе
|
|
158
|
-
& .format-toolbar {
|
|
159
|
-
display: none;
|
|
160
|
-
position: absolute;
|
|
161
|
-
left: 0;
|
|
162
|
-
bottom: 100%;
|
|
163
|
-
margin-bottom: 6px;
|
|
164
|
-
z-index: 10;
|
|
165
|
-
flex-flow: row nowrap;
|
|
166
|
-
align-items: center;
|
|
167
|
-
gap: 2px;
|
|
168
|
-
padding: 3px;
|
|
169
|
-
background-color: var(--input-fill);
|
|
170
|
-
border: var(--input-border-type) var(--input-border-width) var(--input-border-color);
|
|
171
|
-
border-radius: var(--input-border-radius);
|
|
172
|
-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
173
|
-
|
|
174
|
-
& .format-button {
|
|
175
|
-
width: calc(var(--input-height) - 12px);
|
|
176
|
-
height: calc(var(--input-height) - 12px);
|
|
177
|
-
border-radius: calc(var(--input-border-radius) - 2px);
|
|
178
|
-
border: 0;
|
|
179
|
-
background: var(--input-toolbar-button-fill);
|
|
180
|
-
cursor: pointer;
|
|
181
|
-
display: flex;
|
|
182
|
-
align-items: center;
|
|
183
|
-
justify-content: center;
|
|
184
|
-
|
|
185
|
-
& svg {
|
|
186
|
-
pointer-events: none;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
&:hover {
|
|
190
|
-
background-color: var(--hover--input-toolbar-button-fill);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
&.active {
|
|
194
|
-
background-color: var(--hover--input-toolbar-button-fill);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
&.focused .format-toolbar {
|
|
200
|
-
display: flex;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// видимые теги форматирования внутри редактора
|
|
204
|
-
& .input {
|
|
205
|
-
& b,
|
|
206
|
-
& strong {
|
|
207
|
-
font-weight: 700;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
& i,
|
|
211
|
-
& em {
|
|
212
|
-
font-style: italic;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
& s,
|
|
216
|
-
& strike,
|
|
217
|
-
& del {
|
|
218
|
-
text-decoration: line-through;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
& u,
|
|
222
|
-
& ins {
|
|
223
|
-
text-decoration: underline;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
136
|
// мультистроковый режим
|
|
228
137
|
&.multyline {
|
|
229
138
|
// data-multyline == true
|
|
@@ -234,15 +143,8 @@
|
|
|
234
143
|
gap: 2px;
|
|
235
144
|
}
|
|
236
145
|
|
|
237
|
-
& .
|
|
146
|
+
& .ui-richeditor {
|
|
238
147
|
flex: 1 10 auto;
|
|
239
|
-
|
|
240
|
-
&:empty {
|
|
241
|
-
&:after {
|
|
242
|
-
white-space: normal;
|
|
243
|
-
text-overflow: unset;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
148
|
}
|
|
247
149
|
}
|
|
248
150
|
|