@rt-tools/ui-kit-v2 0.13.1 → 0.15.0

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.
Files changed (69) hide show
  1. package/README.md +25 -5
  2. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs +90 -12
  3. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs.map +1 -1
  4. package/fesm2022/rt-tools-ui-kit-v2.mjs +2267 -664
  5. package/fesm2022/rt-tools-ui-kit-v2.mjs.map +1 -1
  6. package/package.json +1 -1
  7. package/rt-tools-ui-kit-v2-0.15.0.tgz +0 -0
  8. package/src/lib/components/CONTEXT.md +1 -1
  9. package/src/lib/components/action-bar/rt-action-bar.component.scss +5 -0
  10. package/src/lib/components/autocomplete/rt-autocomplete.component.scss +8 -1
  11. package/src/lib/components/bottom-sheet/rt-bottom-sheet.component.scss +5 -0
  12. package/src/lib/components/button/CONTEXT.md +1 -1
  13. package/src/lib/components/button/rt-button.directive.scss +5 -7
  14. package/src/lib/components/calendar/CONTEXT.md +16 -2
  15. package/src/lib/components/calendar/rt-calendar.component.scss +81 -4
  16. package/src/lib/components/card/rt-card.component.scss +5 -0
  17. package/src/lib/components/checkbox/rt-checkbox.component.scss +5 -0
  18. package/src/lib/components/data-list/settings/rt-data-list-settings-aside.component.scss +1 -1
  19. package/src/lib/components/data-list/toolbar/rt-data-list-toolbar.component.scss +1 -1
  20. package/src/lib/components/data-table/cell/rt-data-table-cell.component.scss +1 -1
  21. package/src/lib/components/data-table/filter-cell/rt-data-table-filter-cell.component.scss +1 -1
  22. package/src/lib/components/data-table/rt-data-table.component.scss +1 -1
  23. package/src/lib/components/date-picker/CONTEXT.md +33 -14
  24. package/src/lib/components/date-picker/panel/rt-date-panel.component.scss +155 -0
  25. package/src/lib/components/date-picker/rt-date-picker.component.scss +18 -2
  26. package/src/lib/components/date-range/CONTEXT.md +53 -0
  27. package/src/lib/components/date-range/panel/rt-date-range-panel.component.scss +103 -0
  28. package/src/lib/components/date-range/rt-date-range.component.scss +120 -0
  29. package/src/lib/components/dialog/rt-dialog.component.scss +5 -0
  30. package/src/lib/components/empty-state/rt-empty-state.component.scss +5 -0
  31. package/src/lib/components/file-card/rt-file-card.component.scss +5 -0
  32. package/src/lib/components/file-drop/rt-file-drop.component.scss +5 -0
  33. package/src/lib/components/header/rt-header.component.scss +5 -0
  34. package/src/lib/components/icon-button/CONTEXT.md +1 -1
  35. package/src/lib/components/icon-button/rt-icon-button.component.scss +9 -29
  36. package/src/lib/components/input/rt-input.component.scss +7 -1
  37. package/src/lib/components/input-number/rt-input-number.component.scss +7 -1
  38. package/src/lib/components/markdown-text/rt-markdown-text.component.scss +5 -0
  39. package/src/lib/components/menu/rt-menu-item.component.scss +5 -0
  40. package/src/lib/components/message/rt-message.component.scss +5 -0
  41. package/src/lib/components/money-list/rt-money-list.component.scss +5 -0
  42. package/src/lib/components/multiselect/CONTEXT.md +12 -5
  43. package/src/lib/components/multiselect/rt-multiselect.component.scss +32 -1
  44. package/src/lib/components/note/rt-note.component.scss +5 -0
  45. package/src/lib/components/notifications-bell/rt-notifications-bell.component.scss +5 -0
  46. package/src/lib/components/pagination/rt-pagination.component.scss +6 -1
  47. package/src/lib/components/radio-button/rt-radio-button.component.scss +5 -0
  48. package/src/lib/components/section-nav/rt-section-nav.component.scss +5 -0
  49. package/src/lib/components/select/CONTEXT.md +10 -7
  50. package/src/lib/components/select/rt-select.component.scss +36 -1
  51. package/src/lib/components/skeleton/CONTEXT.md +14 -16
  52. package/src/lib/components/skeleton/rt-skeleton.component.scss +7 -1
  53. package/src/lib/components/skeleton-wrapper/CONTEXT.md +6 -6
  54. package/src/lib/components/split-button/rt-split-button.component.scss +6 -0
  55. package/src/lib/components/stepper/rt-stepper.component.scss +5 -0
  56. package/src/lib/components/table/rt-table.component.scss +12 -0
  57. package/src/lib/components/tag/CONTEXT.md +14 -15
  58. package/src/lib/components/tag/rt-tag.component.scss +6 -30
  59. package/src/lib/components/textarea/rt-textarea.component.scss +8 -1
  60. package/src/lib/components/thread-list/rt-thread-list.component.scss +5 -0
  61. package/src/lib/components/toggle-button-group/rt-toggle-button-group.component.scss +7 -6
  62. package/src/lib/components/toggle-switch/rt-toggle-switch.component.scss +5 -0
  63. package/src/rich-editor/lib/components/message-composer/CONTEXT.md +26 -2
  64. package/src/rich-editor/lib/components/message-composer/rt-message-composer.component.scss +78 -34
  65. package/src/styles/_mixins.scss +39 -0
  66. package/styles/tokens.css +30 -5
  67. package/types/rt-tools-ui-kit-v2-rich-editor.d.ts +32 -6
  68. package/types/rt-tools-ui-kit-v2.d.ts +396 -109
  69. package/rt-tools-ui-kit-v2-0.13.1.tgz +0 -0
@@ -1,3 +1,5 @@
1
+ @use '../../../styles/mixins' as kv;
2
+
1
3
  @layer rt-kit.components {
2
4
  /* rt-toggle-switch — переключатель в common/ui. ViewEncapsulation.None.
3
5
  Хост адресуется по имени элемента, а не по классу блока: класс `.rt-toggle-switch` висит
@@ -6,6 +8,9 @@
6
8
 
7
9
  rt-toggle-switch {
8
10
  display: inline-flex;
11
+
12
+ /* Шаг входа `radius` переназначает скругление дорожки, ручка идёт за ней. */
13
+ @include kv.radius-steps('--rt-toggle-radius', '> .rt-toggle-switch');
9
14
  }
10
15
 
11
16
  rt-toggle-switch .rt-toggle-switch {
@@ -1,6 +1,7 @@
1
1
  # `rt-message-composer`
2
2
 
3
- Поле отправки сообщения: текст, вложения, необязательное форматирование.
3
+ Поле отправки сообщения — капсула с круглыми кнопками: текст, вложения внутри капсулы,
4
+ необязательное форматирование и подсказка про Enter.
4
5
 
5
6
  ```html
6
7
  <rt-message-composer
@@ -17,12 +18,15 @@
17
18
  | `attachments` | `boolean` | `false` |
18
19
  | `accept` | `string` | `''` |
19
20
  | `sending` / `disabled` | `boolean` | `false` |
21
+ | `stoppable` | `boolean` | `false` |
22
+ | `text` (model) | `string` | `''` |
20
23
  | `formatting` | `boolean` | `false` |
24
+ | `hint` | `boolean` | `false` |
21
25
  | `toolbar` | `TRtRichEditorToolbar` | `'full'` |
22
26
  | `minRows` / `maxRows` | `number` | 1 / 6 |
23
27
  | `droppedFiles` | `File[] \| null` | `null` |
24
28
 
25
- Выход: `submitted` — `{ text, delta?, files }`.
29
+ Выходы: `submitted` — `{ text, delta?, files }`; `stopped` — клик по «Стоп». Метод: `focus()`.
26
30
 
27
31
  ## Главное, что нужно знать
28
32
 
@@ -30,12 +34,32 @@
30
34
  вложенный файл разблокирует отправку и без текста. Во время `sending` поле и кнопка заблокированы —
31
35
  иначе второе сообщение ушло бы поверх ещё не доставленного.
32
36
 
37
+ **`stoppable` меняет смысл `sending` только для того, кто его включил.** При обоих флагах стрелку
38
+ сменяет «Стоп», форма не блокируется, а `submit` отказывает по `canSend`, не трогая черновик:
39
+ следующий вопрос набирается, пока идёт ответ. `rt-chat` и прочие потребители без флага получают
40
+ прежнюю блокировку.
41
+
42
+ **`text` — модель черновика, а не CVA.** У композера своя форма с файлами; потребителю нужно задать,
43
+ прочитать и очистить текст, а не встроить поле в чужую форму. Синхронизация двусторонняя: эффект
44
+ пишет модель в контрол, `valueChanges` контрола — в модель; сброс после отправки обнуляет обе.
45
+
46
+ **`focus()` в режиме форматирования идёт через `RtRichEditorComponent.focus`.** Узел Quill появляется
47
+ после динамического импорта; до него вызов ничего не делает.
48
+
33
49
  **Enter отправляет, Shift+Enter переносит строку.** Набор во время IME-композиции игнорируется.
34
50
 
35
51
  **`droppedFiles` — вход, а не выход.** Файлы, брошенные в область
36
52
  [`rt-file-drop`](../../../../lib/components/file-drop/CONTEXT.md) снаружи, передаются сюда входом и добавляются к
37
53
  вложениям; без `attachments` они игнорируются.
38
54
 
55
+ **Капсула высокая, когда в ней больше одной строки.** Признак — высота текста, которую меряет
56
+ `ResizeObserver`, вложенный файл или режим форматирования; модификатор `tall` переназначает
57
+ скругление на шаг 20.
58
+
59
+ **Поле держит `content-box`, внешний отступ и место под ползунок.** Автовысота CDK пишет в `height`
60
+ высоту текста и на замере обнуляет боковой `padding`, а появившийся ползунок сужал бы поле: без
61
+ этих трёх правил текст ложился бы на строку больше, чем поле вмещает.
62
+
39
63
  ## Края
40
64
 
41
65
  - После отправки форма сбрасывается целиком — и текст, и файлы.
@@ -1,74 +1,118 @@
1
1
  @layer rt-kit.components {
2
2
  .rt-message-composer {
3
- --rt-message-composer-radius: var(--rt-radius-md);
3
+ --rt-message-composer-radius: var(--rt-radius-full);
4
+ --rt-message-composer-tall-radius: var(--rt-radius-2xl);
4
5
  --rt-message-composer-border-width: var(--rt-border-width-thin);
5
- --rt-message-composer-divider-width: var(--rt-border-width-thin);
6
6
 
7
7
  display: flex;
8
8
  flex-direction: column;
9
- padding: var(--rt-space-4);
10
- border: var(--rt-message-composer-border-width) solid var(--rt-color-border-default);
11
- border-radius: var(--rt-message-composer-radius);
12
- background: var(--rt-color-bg-surface);
13
- gap: var(--rt-space-2);
9
+ gap: calc(var(--rt-space-1) * 1.5);
14
10
 
15
11
  /* Ширина приходит от хозяина, а не от содержимого. Без этой строки её задавала textarea
16
12
  без объявленной ширины: такую браузер считает от средней ширины знака первого
17
13
  доступного начертания, и величина гуляла между поднятиями витрины — 158 против 161. */
18
14
  inline-size: 100%;
19
15
 
20
- &:focus-within {
21
- border-color: var(--rt-color-border-strong);
16
+ &__capsule {
17
+ display: flex;
18
+ flex-direction: column;
19
+ padding: calc(var(--rt-space-1) * 1.5);
20
+ border: var(--rt-message-composer-border-width) solid var(--rt-input-color-border);
21
+ border-radius: var(--rt-message-composer-radius);
22
+ background: var(--rt-input-color-bg);
23
+ gap: calc(var(--rt-space-1) * 1.5);
24
+
25
+ // Фокус — как у полей кита: поверхность, рамка фокуса и кольцо.
26
+ &:focus-within {
27
+ border-color: var(--rt-input-color-border-focus);
28
+ background: var(--rt-color-bg-surface);
29
+ box-shadow: var(--rt-input-focus-shadow);
30
+ }
31
+
32
+ // Выше одной строки капсула берёт шаг скругления 20: полное скругление
33
+ // на высокой капсуле срезало бы углы текста и карточек.
34
+ &--tall {
35
+ --rt-message-composer-radius: var(--rt-message-composer-tall-radius);
36
+ }
37
+
38
+ &--disabled {
39
+ background: var(--rt-input-color-bg-disabled);
40
+ }
41
+ }
42
+
43
+ &__files {
44
+ display: flex;
45
+ flex-direction: column;
46
+ gap: var(--rt-space-1);
47
+ }
48
+
49
+ &__rich {
50
+ inline-size: 100%;
51
+ }
52
+
53
+ // Кнопки прижаты к низу: растущий текст поднимает капсулу, а не их.
54
+ &__row {
55
+ display: flex;
56
+ align-items: flex-end;
57
+ gap: var(--rt-space-2);
22
58
  }
23
59
 
24
60
  &__input {
25
- padding: 0;
61
+ /* Автовысота CDK пишет в height высоту самого текста: при border-box её съели бы
62
+ отступы, и уже вторая строка уезжала бы под верхний край. */
63
+ box-sizing: content-box;
64
+ flex: 1 1 auto;
26
65
  border: 0;
27
66
  margin: 0;
28
67
  background: transparent;
29
- color: inherit;
68
+ color: var(--rt-input-color-text);
30
69
  font: inherit;
31
- font-size: var(--rt-text-sm);
70
+ font-size: var(--rt-input-font-size);
32
71
  inline-size: 100%;
33
- line-height: var(--rt-leading-snug);
72
+ line-height: var(--rt-leading-normal);
73
+
74
+ /* Отступ от скрепки — внешний: замер автовысоты CDK обнуляет боковой padding поля,
75
+ и на замере текст ложился бы в меньшее число строк, чем на экране. */
76
+ margin-inline-start: calc(var(--rt-space-1) * 1.5);
34
77
 
35
78
  /* Своего размера поле ввода хозяину не отдаёт: иначе его ширина по `cols`
36
79
  по-прежнему участвовала бы в измерении. */
37
80
  min-inline-size: 0;
38
81
  outline: 0;
82
+
83
+ /* Одна строка текста по высоте равна круглой кнопке: отступ добирает разницу. */
84
+ padding-block: calc((var(--rt-control-height-md) - 1lh) / 2);
39
85
  resize: none;
40
86
 
87
+ /* Место под ползунок держится всегда, и на замере автовысоты тоже: иначе появившийся
88
+ ползунок сужал бы поле, текст ложился бы ещё на строку, и верхняя уезжала бы. */
89
+ scrollbar-color: var(--rt-color-border-default) transparent;
90
+ scrollbar-gutter: stable;
91
+ scrollbar-width: thin;
92
+
41
93
  &::placeholder {
42
- color: var(--rt-color-text-muted);
94
+ color: var(--rt-input-color-text-placeholder);
43
95
  }
44
96
 
45
97
  &:disabled {
46
98
  cursor: not-allowed;
47
- }
48
- }
49
99
 
50
- &__files {
51
- display: flex;
52
- flex-direction: column;
53
- gap: var(--rt-space-1);
54
- }
55
-
56
- // Разделитель тянется на всю ширину бокса — компенсируем горизонтальный padding.
57
- &__divider {
58
- background: var(--rt-color-border-default);
59
- block-size: var(--rt-message-composer-divider-width);
60
- margin-inline: calc(-1 * var(--rt-space-4));
61
- }
62
-
63
- &__controls {
64
- display: flex;
65
- align-items: center;
66
- gap: var(--rt-space-2);
100
+ &::placeholder {
101
+ color: var(--rt-color-text-disabled);
102
+ }
103
+ }
67
104
  }
68
105
 
69
- // Кнопка отправки всегда у правого края, даже когда attach скрыт.
106
+ // Кнопка отправки всегда у правого края: и без скрепки, и в режиме форматирования.
70
107
  &__send {
71
108
  margin-inline-start: auto;
72
109
  }
110
+
111
+ &__hint {
112
+ margin: 0;
113
+ color: var(--rt-color-text-muted);
114
+ font-size: var(--rt-text-xs);
115
+ line-height: var(--rt-leading-snug);
116
+ }
73
117
  }
74
118
  }
@@ -19,3 +19,42 @@
19
19
  letter-spacing: var(--rt-letter-spacing-wide);
20
20
  line-height: var(--rt-leading-snug);
21
21
  }
22
+
23
+ /// Шаги скругления кита и их токены — те же шаги, что у типа `TRtRadius`. Токены названы
24
+ /// целиком, а не склеены из шага: проверка графа токенов ищет имя, а не его начало.
25
+ $radius-steps: (
26
+ none: var(--rt-radius-none),
27
+ xs: var(--rt-radius-xs),
28
+ sm: var(--rt-radius-sm),
29
+ ms: var(--rt-radius-ms),
30
+ md: var(--rt-radius-md),
31
+ lg: var(--rt-radius-lg),
32
+ xl: var(--rt-radius-xl),
33
+ 2xl: var(--rt-radius-2xl),
34
+ full: var(--rt-radius-full),
35
+ );
36
+
37
+ /// Правила шагов входа `radius` для одного компонента.
38
+ ///
39
+ /// Ставится внутрь правила хоста (`rt-card { … }`). На каждый шаг выходит правило
40
+ /// хоста с атрибутом `data-rt-radius`, которое переназначает собственное свойство
41
+ /// скругления компонента — и больше ничего: поверхность берёт углы из того же
42
+ /// свойства, и переопределение этого свойства приложением по-прежнему сильнее кита.
43
+ ///
44
+ /// $property — собственное свойство скругления, `--rt-card-radius`.
45
+ /// $surface — где это свойство объявлено, от хоста: `'> .rt-card'` для корня шаблона,
46
+ /// пусто — если на самом хосте. Только прямой ребёнок: потомок задел бы
47
+ /// вложенный компонент того же рода.
48
+ @mixin radius-steps($property, $surface: null) {
49
+ @each $step, $token in $radius-steps {
50
+ @if $surface {
51
+ &[data-rt-radius='#{$step}'] #{$surface} {
52
+ #{$property}: $token;
53
+ }
54
+ } @else {
55
+ &[data-rt-radius='#{$step}'] {
56
+ #{$property}: $token;
57
+ }
58
+ }
59
+ }
60
+ }
package/styles/tokens.css CHANGED
@@ -6905,9 +6905,6 @@ html.rt-theme-dark.rt-preset-material {
6905
6905
  .rt-button--text.rt-button--info {
6906
6906
  --rt-btn-color: var(--rt-color-action-info-on-surface);
6907
6907
  }
6908
- .rt-button--rounded {
6909
- --rt-btn-radius: 999px;
6910
- }
6911
6908
  .rt-button--sm {
6912
6909
  --rt-btn-height: var(--rt-control-height-sm);
6913
6910
  --rt-btn-padding: 0 0.875rem;
@@ -6941,8 +6938,36 @@ html.rt-theme-dark.rt-preset-material {
6941
6938
  padding: 0;
6942
6939
  gap: 0;
6943
6940
  }
6944
- .rt-button--icon-only.rt-button--rounded {
6945
- --rt-btn-radius: 50%;
6941
+ .rt-button {
6942
+ /* Шаг входа `radius` переназначает собственное свойство кнопки. Класс блока стоит на
6943
+ самом хосте, поэтому правило шага — на нём же. */
6944
+ }
6945
+ .rt-button[data-rt-radius=none] {
6946
+ --rt-btn-radius: var(--rt-radius-none);
6947
+ }
6948
+ .rt-button[data-rt-radius=xs] {
6949
+ --rt-btn-radius: var(--rt-radius-xs);
6950
+ }
6951
+ .rt-button[data-rt-radius=sm] {
6952
+ --rt-btn-radius: var(--rt-radius-sm);
6953
+ }
6954
+ .rt-button[data-rt-radius=ms] {
6955
+ --rt-btn-radius: var(--rt-radius-ms);
6956
+ }
6957
+ .rt-button[data-rt-radius=md] {
6958
+ --rt-btn-radius: var(--rt-radius-md);
6959
+ }
6960
+ .rt-button[data-rt-radius=lg] {
6961
+ --rt-btn-radius: var(--rt-radius-lg);
6962
+ }
6963
+ .rt-button[data-rt-radius=xl] {
6964
+ --rt-btn-radius: var(--rt-radius-xl);
6965
+ }
6966
+ .rt-button[data-rt-radius="2xl"] {
6967
+ --rt-btn-radius: var(--rt-radius-2xl);
6968
+ }
6969
+ .rt-button[data-rt-radius=full] {
6970
+ --rt-btn-radius: var(--rt-radius-full);
6946
6971
  }
6947
6972
  .rt-button--loading {
6948
6973
  cursor: wait;
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { AfterViewInit, OnDestroy, Signal, ElementRef, WritableSignal, InputSignal, OutputEmitterRef, InputSignalWithTransform, TemplateRef, PipeTransform } from '@angular/core';
2
+ import { AfterViewInit, OnDestroy, Signal, ElementRef, WritableSignal, InputSignal, OutputEmitterRef, InputSignalWithTransform, ModelSignal, TemplateRef, PipeTransform } from '@angular/core';
3
3
  import { RtFormControlBase, IQuillDelta, TRtKitLabelMap } from '@rt-tools/ui-kit-v2';
4
4
  import { BooleanInput, NumberInput } from '@angular/cdk/coercion';
5
5
  import { FormGroup, FormControl } from '@angular/forms';
@@ -32,6 +32,8 @@ declare class RtRichEditorComponent extends RtFormControlBase<IQuillDelta | null
32
32
  readonly enterPressed: OutputEmitterRef<void>;
33
33
  readonly displayText: Signal<string>;
34
34
  ngAfterViewInit(): Promise<void>;
35
+ /** Ставит фокус в редактор; до загрузки Quill ничего не делает. */
36
+ focus(): void;
35
37
  ngOnDestroy(): void;
36
38
  writeValue(value: IQuillDelta | null): void;
37
39
  setDisabledState(isDisabled: boolean): void;
@@ -64,30 +66,47 @@ interface IComposerFormShape {
64
66
  delta: FormControl<IQuillDelta | null>;
65
67
  }
66
68
  /**
67
- * Композер сообщения: авто-растущая textarea сверху, под разделительной линией —
68
- * ряд контролов (слева — прикрепить файл, справа — отправить). Презентационный,
69
- * без data-access: наружу торчит только `submitted` с текстом и файлами.
69
+ * Композер сообщения — капсула: слева круглая кнопка вложения, по центру авто-растущая
70
+ * textarea, справа круглая кнопка отправки; вложения стоят внутри капсулы над строкой.
71
+ * Презентационный, без data-access: наружу торчит только `submitted` с текстом и файлами.
70
72
  *
71
73
  * Отправка — `Enter` (без Shift) или клик по иконке; `Shift+Enter` — перенос
72
74
  * строки. Кнопка отправки активна, пока есть непустой текст или вложения.
75
+ *
76
+ * Со `stoppable` во время `sending` вместо стрелки стоит кнопка «Стоп», а поле
77
+ * остаётся открытым: следующий вопрос набирается, пока идёт ответ.
73
78
  */
74
79
  declare class RtMessageComposerComponent {
75
80
  #private;
76
81
  protected readonly t: Signal<TRtKitLabelMap>;
77
82
  protected readonly placeholderText: Signal<string>;
78
83
  protected readonly fileInput: Signal<ElementRef<HTMLInputElement> | undefined>;
84
+ protected readonly textInput: Signal<ElementRef<HTMLTextAreaElement> | undefined>;
85
+ protected readonly richEditor: Signal<RtRichEditorComponent | undefined>;
79
86
  protected readonly form: FormGroup<IComposerFormShape>;
80
87
  protected readonly files: Signal<readonly File[]>;
81
88
  /** Отправка доступна: есть контент (текст/delta/файлы), композер не занят. */
82
89
  protected readonly canSend: Signal<boolean>;
90
+ /** Капсула выше одной строки: перенос текста, вложения или режим форматирования. */
91
+ protected readonly tall: Signal<boolean>;
92
+ /** Идёт ответ, который можно остановить: вместо стрелки — «Стоп», поле открыто. */
93
+ protected readonly isStoppable: Signal<boolean>;
94
+ protected readonly capsuleMods: Signal<Record<string, boolean>>;
83
95
  /** Текст-подсказка textarea. Пусто — берётся переведённое умолчание. */
84
96
  readonly placeholder: InputSignal<string>;
85
97
  /** Фильтр типов для file-input (`.pdf,.doc,...`). */
86
98
  readonly accept: InputSignal<string>;
99
+ /** Строка под капсулой про Enter и Shift + Enter. */
100
+ readonly hint: InputSignalWithTransform<boolean, BooleanInput>;
87
101
  /** Показывать кнопку вложения и список файлов. */
88
102
  readonly attachments: InputSignalWithTransform<boolean, BooleanInput>;
89
- /** Отправка в процессе — блокирует submit и показывает её недоступность. */
103
+ /** Отправка в процессе — блокирует submit, кнопка отправки крутит индикатор. */
90
104
  readonly sending: InputSignalWithTransform<boolean, BooleanInput>;
105
+ /**
106
+ * Ответ на сообщение можно остановить. Во время `sending` стрелку сменяет кнопка
107
+ * «Стоп», а поле не блокируется; без входа `sending` блокирует поле, как раньше.
108
+ */
109
+ readonly stoppable: InputSignalWithTransform<boolean, BooleanInput>;
91
110
  /** Полная блокировка композера. */
92
111
  readonly disabled: InputSignalWithTransform<boolean, BooleanInput>;
93
112
  /** Rich-режим: вместо textarea — Quill-редактор, отправка уходит delta-каналом. */
@@ -106,14 +125,21 @@ declare class RtMessageComposerComponent {
106
125
  readonly droppedFiles: InputSignal<File[] | null>;
107
126
  /** Отправка сообщения: текст + файлы (последние — только при `attachments`). */
108
127
  readonly submitted: OutputEmitterRef<IRtMessageComposer.SubmitPayload>;
128
+ /** Черновик поля без форматирования: задаётся снаружи, правки уходят наружу, после отправки пуст. */
129
+ readonly text: ModelSignal<string>;
130
+ /** Клик по кнопке «Стоп» во время ответа, который можно остановить. */
131
+ readonly stopped: OutputEmitterRef<void>;
109
132
  constructor();
133
+ /** Ставит фокус в поле: в textarea, а в режиме форматирования — в rich-редактор. */
134
+ focus(): void;
110
135
  protected onKeydown(event: KeyboardEvent): void;
136
+ protected stop(): void;
111
137
  protected openPicker(): void;
112
138
  protected onFilesPicked(event: Event): void;
113
139
  protected removeFile(index: number): void;
114
140
  protected submit(): void;
115
141
  static ɵfac: i0.ɵɵFactoryDeclaration<RtMessageComposerComponent, never>;
116
- static ɵcmp: i0.ɵɵComponentDeclaration<RtMessageComposerComponent, "rt-message-composer", never, { "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "accept": { "alias": "accept"; "required": false; "isSignal": true; }; "attachments": { "alias": "attachments"; "required": false; "isSignal": true; }; "sending": { "alias": "sending"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "formatting": { "alias": "formatting"; "required": false; "isSignal": true; }; "toolbar": { "alias": "toolbar"; "required": false; "isSignal": true; }; "minRows": { "alias": "minRows"; "required": false; "isSignal": true; }; "maxRows": { "alias": "maxRows"; "required": false; "isSignal": true; }; "droppedFiles": { "alias": "droppedFiles"; "required": false; "isSignal": true; }; }, { "submitted": "submitted"; }, never, never, true, never>;
142
+ static ɵcmp: i0.ɵɵComponentDeclaration<RtMessageComposerComponent, "rt-message-composer", never, { "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "accept": { "alias": "accept"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "attachments": { "alias": "attachments"; "required": false; "isSignal": true; }; "sending": { "alias": "sending"; "required": false; "isSignal": true; }; "stoppable": { "alias": "stoppable"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "formatting": { "alias": "formatting"; "required": false; "isSignal": true; }; "toolbar": { "alias": "toolbar"; "required": false; "isSignal": true; }; "minRows": { "alias": "minRows"; "required": false; "isSignal": true; }; "maxRows": { "alias": "maxRows"; "required": false; "isSignal": true; }; "droppedFiles": { "alias": "droppedFiles"; "required": false; "isSignal": true; }; "text": { "alias": "text"; "required": false; "isSignal": true; }; }, { "submitted": "submitted"; "text": "textChange"; "stopped": "stopped"; }, never, never, true, never>;
117
143
  }
118
144
 
119
145
  /**