@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 CHANGED
@@ -2,11 +2,13 @@
2
2
 
3
3
  [![Build Status](https://dev.azure.com/brandup/BrandUp%20Core/_apis/build/status%2FBrandUp%2Fbrandup-ui-kit?branchName=main)](https://dev.azure.com/brandup/BrandUp%20Core/_build/latest?definitionId=81&branchName=main)
4
4
 
5
- Компонент текстового поля на базе `contenteditable`. Заменяет стандартные `<input>` и `<textarea>`, добавляя расширенное поведение: счётчик символов, кнопку копирования, фильтрацию ввода по типу, валидацию и опциональное форматирование текста (жирный, курсив, зачёркивание, подчёркивание).
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.34",
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.3",
29
- "@brandup/ui-helpers": "^2.0.3",
30
- "@brandup/ui-input": "^1.0.34",
31
- "@brandup/ui-kit": "^1.0.34"
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 "./format";
18
+ } from "@brandup/ui-richeditor";
@@ -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
- & .input {
75
- appearance: none;
76
- position: relative;
74
+ // редактор (@brandup/ui-richeditor) — занимает доступное место; внутреннее оформление в richeditor.less
75
+ & .ui-richeditor {
77
76
  flex: 1 1 auto;
78
- box-sizing: border-box;
79
- word-wrap: anywhere;
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
- & ~ .symbols {
101
- display: none;
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
- & .input {
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