@rt-tools/ui-kit-v2 0.3.0 → 0.5.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 (39) hide show
  1. package/README.md +25 -16
  2. package/fesm2022/rt-tools-ui-kit-v2.mjs +732 -1351
  3. package/fesm2022/rt-tools-ui-kit-v2.mjs.map +1 -1
  4. package/package.json +1 -2
  5. package/rt-tools-ui-kit-v2-0.5.0.tgz +0 -0
  6. package/src/lib/components/CONTEXT.md +1 -1
  7. package/src/lib/components/bar-list/CONTEXT.md +5 -5
  8. package/src/lib/components/button/rt-button.directive.scss +4 -0
  9. package/src/lib/components/checkbox/rt-checkbox.component.scss +6 -2
  10. package/src/lib/components/confirm-popover/CONTEXT.md +8 -8
  11. package/src/lib/components/container/CONTEXT.md +22 -0
  12. package/src/lib/components/dialog/footer/rt-dialog-footer.component.scss +20 -9
  13. package/src/lib/components/dialog/header/rt-dialog-header.component.scss +27 -15
  14. package/src/lib/components/download-link/CONTEXT.md +1 -1
  15. package/src/lib/components/download-link/rt-download-link.component.scss +13 -0
  16. package/src/lib/components/file-drop/CONTEXT.md +6 -6
  17. package/src/lib/components/file-input/CONTEXT.md +6 -6
  18. package/src/lib/components/live-badge/CONTEXT.md +5 -5
  19. package/src/lib/components/menu/CONTEXT.md +6 -6
  20. package/src/lib/components/message-composer/CONTEXT.md +10 -10
  21. package/src/lib/components/multiselect/CONTEXT.md +6 -6
  22. package/src/lib/components/night-grid/CONTEXT.md +4 -4
  23. package/src/lib/components/page-header/CONTEXT.md +7 -7
  24. package/src/lib/components/pagination/CONTEXT.md +1 -1
  25. package/src/lib/components/select/CONTEXT.md +8 -8
  26. package/src/lib/components/split-button/CONTEXT.md +7 -7
  27. package/src/lib/components/split-button/rt-split-button.component.scss +13 -0
  28. package/src/lib/components/stat-tile/CONTEXT.md +1 -1
  29. package/src/lib/components/table/CONTEXT.md +1 -1
  30. package/src/lib/components/table/sort-header/CONTEXT.md +40 -0
  31. package/src/lib/components/tabs/CONTEXT.md +14 -9
  32. package/src/lib/components/tag/CONTEXT.md +2 -2
  33. package/src/lib/components/theme-toggle/CONTEXT.md +1 -1
  34. package/src/lib/components/toast/CONTEXT.md +8 -0
  35. package/src/lib/components/toggle-switch/rt-toggle-switch.component.scss +6 -2
  36. package/src/styles/_semantic.scss +11 -2
  37. package/styles/tokens.css +12 -1
  38. package/types/rt-tools-ui-kit-v2.d.ts +324 -74
  39. package/rt-tools-ui-kit-v2-0.3.0.tgz +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rt-tools/ui-kit-v2",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "license": "Apache-2.0",
5
5
  "author": "Yauheni Krumin",
6
6
  "type": "module",
@@ -19,7 +19,6 @@
19
19
  "@angular/forms": "^22.0.0",
20
20
  "@angular/platform-browser": "^22.0.0",
21
21
  "@angular/router": "^22.0.0",
22
- "@jsverse/transloco": "^8.4.0",
23
22
  "quill": "^2.0.3",
24
23
  "rxjs": "^7.8.2",
25
24
  "typescript": "^6.0.0"
Binary file
@@ -26,7 +26,7 @@ tag/
26
26
  `rt-tag--closable`, камелкейс превращается в дефис (`hasIndicator` → `--has-indicator`).
27
27
  - **Точки для проверок помечены `qa-dataid`** — по нему компонент находят и спеки, и e2e.
28
28
  - **Подписи, которые кит рисует сам**, живут в неймспейсе `rtKit` и приходят через
29
- `provideRtKitTranslations()`. Свой текст почти везде перебивает переведённый; пустая строка
29
+ `provideRtKitLabels()`. Свой текст почти везде перебивает переведённый; пустая строка
30
30
  равна отсутствию входа.
31
31
  - **Цвета и размеры — только токены `--rt-*`**, ни одного HEX в компонентных стилях.
32
32
 
@@ -6,11 +6,11 @@
6
6
  <rt-bar-list title="Источники" [rows]="[{ id: 'direct', title: 'Прямые заходы', meta: '1 240 визитов', value: '52%', sharePercent: 52 }]" />
7
7
  ```
8
8
 
9
- | вход | тип | умолчание |
10
- | ----------- | ---------------------------------------------------------- | ----------------------- |
11
- | `rows` | `ReadonlyArray<{ id, title, meta?, value, sharePercent }>` | **обязателен** |
12
- | `title` | `string` | `''` |
13
- | `emptyText` | `string` | `''` → `rtKit.uiNoData` |
9
+ | вход | тип | умолчание |
10
+ | ----------- | ---------------------------------------------------------- | ----------------- |
11
+ | `rows` | `ReadonlyArray<{ id, title, meta?, value, sharePercent }>` | **обязателен** |
12
+ | `title` | `string` | `''` |
13
+ | `emptyText` | `string` | `''` → `uiNoData` |
14
14
 
15
15
  Выходов нет.
16
16
 
@@ -79,10 +79,14 @@
79
79
  cursor: not-allowed;
80
80
  }
81
81
 
82
+ /* `flex-shrink: 0` — иконке заданного размера. Без него в кнопке, которой ширину
83
+ навязали снаружи (пункт меню `rt-split-button` берёт её от панели), лейбл давит
84
+ на иконку, и та сжимается до нуля: место занято, а иконки не видно. */
82
85
  &__icon {
83
86
  display: inline-flex;
84
87
  width: var(--rt-btn-icon-size);
85
88
  height: var(--rt-btn-icon-size);
89
+ flex-shrink: 0;
86
90
  align-items: center;
87
91
  justify-content: center;
88
92
  font-size: var(--rt-btn-icon-size);
@@ -44,8 +44,12 @@ rt-checkbox .rt-checkbox {
44
44
  border-color var(--rt-duration-fast) ease;
45
45
  }
46
46
 
47
- &--checked &__box,
48
- &--indeterminate &__box {
47
+ /* Элемент адресуется классом, а не вторым `&`: родитель здесь составной
48
+ (`rt-checkbox .rt-checkbox`), и второй `&` развернулся бы в него целиком —
49
+ `… .rt-checkbox--checked rt-checkbox .rt-checkbox__box`, то есть в селектор,
50
+ требующий вложенного чекбокса. Заливка отмеченного из-за этого не применялась. */
51
+ &--checked .rt-checkbox__box,
52
+ &--indeterminate .rt-checkbox__box {
49
53
  border-color: var(--rt-color-action-primary);
50
54
  background: var(--rt-color-action-primary);
51
55
  }
@@ -13,14 +13,14 @@
13
13
  (confirmed)="reject()" />
14
14
  ```
15
15
 
16
- | вход (алиас) | тип | умолчание |
17
- | ---------------------- | ------------------------------------ | ------------------------ |
18
- | `rtConfirm` | `string` | `''` |
19
- | `rtConfirmTitle` | `string \| null` | `null` |
20
- | `rtConfirmLabel` | `string` | `''` → `rtKit.uiConfirm` |
21
- | `rtConfirmCancelLabel` | `string` | `''` → `rtKit.uiCancel` |
22
- | `rtConfirmTone` | `'danger' \| 'warning' \| 'primary'` | `'danger'` |
23
- | `rtConfirmDisabled` | `boolean` | `false` |
16
+ | вход (алиас) | тип | умолчание |
17
+ | ---------------------- | ------------------------------------ | ------------------ |
18
+ | `rtConfirm` | `string` | `''` |
19
+ | `rtConfirmTitle` | `string \| null` | `null` |
20
+ | `rtConfirmLabel` | `string` | `''` → `uiConfirm` |
21
+ | `rtConfirmCancelLabel` | `string` | `''` → `uiCancel` |
22
+ | `rtConfirmTone` | `'danger' \| 'warning' \| 'primary'` | `'danger'` |
23
+ | `rtConfirmDisabled` | `boolean` | `false` |
24
24
 
25
25
  | выход | тип |
26
26
  | ----------- | ------ |
@@ -36,6 +36,28 @@
36
36
  **Стопка уведомлений встроена в каркас** (`rt-toaster` внизу по центру): заводить её отдельно
37
37
  не нужно.
38
38
 
39
+ ## Уход с route-панели
40
+
41
+ Панель, живущая на своём маршруте (`RtRouteAsideComponent` + `rtAsideUnsavedGuard` на
42
+ ro-маршруте), уступает место навигацией, и о несохранённых правках её спрашивает роутер.
43
+
44
+ **Гард спрашивает панель, учтённую под маршрутом ухода, а не компонент, который ему подставил
45
+ роутер.** Когда ro-маршрут объявлен под уровнем без своего компонента — тем, что держит одни
46
+ `providers` для ветки, — Angular отдаёт детям контекст родителя, и в гард приходит компонент
47
+ первичного аутлета. Учёт ведёт `RtRouteAsideRegistry`: панель встаёт в него, когда занимает
48
+ аутлет, и снимается при уничтожении. Наружу кита учёт не выведен — приложению он не нужен.
49
+
50
+ **Компонент от роутера остаётся запасным путём.** Панель приложения может отвечать о правках,
51
+ не наследуя `RtRouteAsideComponent`: гард спросит её, если под маршрутом никто не учтён и метод
52
+ у компонента есть.
53
+
54
+ **Уход, начатый самой панелью, о правках не спрашивает.** Разрешение выдаётся вплотную к вызову
55
+ роутера, действует на один уход и снимается, если навигация не состоялась. Поэтому закрытие
56
+ после удачной записи не открывает окно про то, что уже сохранено.
57
+
58
+ **Отказом навигации гард не отвечает никогда.** Упавший ответ панели отменяет один уход и
59
+ снимает панель с учёта: приложение не запирается на адресе панели.
60
+
39
61
  ## Рядом
40
62
 
41
63
  - [`rt-toaster`](../toast/CONTEXT.md) — та самая стопка.
@@ -1,13 +1,24 @@
1
- /* rt-dialog-footer — footer-слот модалки. ViewEncapsulation.None. */
1
+ /* rt-dialog-footer — footer-слот модалки. ViewEncapsulation.None.
2
2
 
3
- .rt-dialog-footer {
4
- display: flex;
5
- justify-content: flex-end;
6
- padding: var(--rt-space-lg);
7
- border-block-start: 1px solid var(--rt-color-border-subtle);
8
- gap: var(--rt-space-sm);
3
+ Хост адресуется по имени элемента, а не по классу блока: класс
4
+ `.rt-dialog-footer` висит и на `<rt-dialog-footer>`, и на `<footer>` внутри
5
+ него. Правило на голом классе доставалось обоим — кнопки прижимались к правому
6
+ краю не окна, а строки по содержимому, и разделитель рисовался дважды. Заодно
7
+ `:empty` теперь спрашивается у `<footer>`, а не у хоста: у хоста внутри всегда
8
+ лежит `<footer>`, и пустым он не бывал никогда. */
9
9
 
10
- &:empty {
11
- display: none;
10
+ rt-dialog-footer {
11
+ display: contents;
12
+
13
+ .rt-dialog-footer {
14
+ display: flex;
15
+ justify-content: flex-end;
16
+ padding: var(--rt-space-lg);
17
+ border-block-start: 1px solid var(--rt-color-border-subtle);
18
+ gap: var(--rt-space-sm);
19
+
20
+ &:empty {
21
+ display: none;
22
+ }
12
23
  }
13
24
  }
@@ -1,21 +1,33 @@
1
1
  /* rt-dialog-header — заголовок модалки. ViewEncapsulation.None.
2
- Селекторы префиксованы `.rt-dialog-header`. */
2
+ Селекторы префиксованы `.rt-dialog-header`.
3
3
 
4
- .rt-dialog-header {
5
- display: flex;
6
- align-items: center;
7
- justify-content: space-between;
8
- padding: var(--rt-space-lg);
9
- border-block-end: 1px solid var(--rt-color-border-subtle);
10
- gap: var(--rt-space-sm);
4
+ Хост адресуется по имени элемента, а не по классу блока: класс
5
+ `.rt-dialog-header` висит и на `<rt-dialog-header>`, и на `<header>` внутри
6
+ него. Правило на голом классе доставалось обоим — хост становился flex-строкой,
7
+ а `<header>` внутри неё сжимался по содержимому: заголовок и крестик стояли
8
+ вплотную вместо краёв окна, и разделитель рисовался дважды, двумя линиями
9
+ разной длины. Хост боксом не становится: строка шапки должна быть прямым
10
+ flex-ребёнком рамки окна. */
11
11
 
12
- &__title {
13
- margin: 0;
14
- color: var(--rt-color-text-primary);
15
- font-size: var(--rt-text-xl);
16
- }
12
+ rt-dialog-header {
13
+ display: contents;
14
+
15
+ .rt-dialog-header {
16
+ display: flex;
17
+ align-items: center;
18
+ justify-content: space-between;
19
+ padding: var(--rt-space-lg);
20
+ border-block-end: 1px solid var(--rt-color-border-subtle);
21
+ gap: var(--rt-space-sm);
22
+
23
+ &__title {
24
+ margin: 0;
25
+ color: var(--rt-color-text-primary);
26
+ font-size: var(--rt-text-xl);
27
+ }
17
28
 
18
- &__close {
19
- margin-inline-start: auto;
29
+ &__close {
30
+ margin-inline-start: auto;
31
+ }
20
32
  }
21
33
  }
@@ -21,6 +21,6 @@
21
21
  ## Как этим пользоваться
22
22
 
23
23
  - Подпись для скринридера собирается из переведённой формулировки и имени файла
24
- (`rtKit.uiDownloadFile` с подстановкой `{{name}}`) — на экране видно имя, а вслух читается
24
+ (`uiDownloadFile` с подстановкой `{{name}}`) — на экране видно имя, а вслух читается
25
25
  «Download: Договор.pdf».
26
26
  - Для перечня вложений есть [`rt-file-list`](../file-list/CONTEXT.md); эта кнопка — одиночная.
@@ -14,6 +14,19 @@
14
14
  font-weight: var(--rt-font-weight-medium);
15
15
  gap: var(--rt-space-sm);
16
16
  line-height: var(--rt-leading-snug);
17
+
18
+ &:hover {
19
+ text-decoration: underline;
20
+ }
21
+
22
+ /* Своей рамки у кнопки нет — она нарисована как ссылка, и умолчательный контур
23
+ браузер снимает вместе с рамкой. Без этого правила место фокуса с клавиатуры
24
+ не видно вовсе: кнопка выглядит одинаково выбранной и невыбранной. */
25
+ &:focus-visible {
26
+ border-radius: var(--rt-radius-sm);
27
+ box-shadow: var(--rt-shadow-focus-ring);
28
+ outline: none;
29
+ }
17
30
  }
18
31
 
19
32
  &__icon {
@@ -9,12 +9,12 @@
9
9
  </rt-file-drop>
10
10
  ```
11
11
 
12
- | вход | тип | умолчание |
13
- | -------------- | ----------------- | -------------------------------- |
14
- | `disabled` | `boolean` | `false` |
15
- | `overlayLabel` | `string` | `''` → `rtKit.uiFileDropOverlay` |
16
- | `zones` | `readonly Zone[]` | `[]` |
17
- | `accept` | `string` | `''` |
12
+ | вход | тип | умолчание |
13
+ | -------------- | ----------------- | -------------------------- |
14
+ | `disabled` | `boolean` | `false` |
15
+ | `overlayLabel` | `string` | `''` → `uiFileDropOverlay` |
16
+ | `zones` | `readonly Zone[]` | `[]` |
17
+ | `accept` | `string` | `''` |
18
18
 
19
19
  Выходы: `filesDropped` (`File[]`), `zoneFilesDropped` (`{ zoneId, files }`), `draggingChange`.
20
20
 
@@ -10,12 +10,12 @@
10
10
 
11
11
  Свои входы поверх общих из [`RtFormControlBase`](../form-control/CONTEXT.md):
12
12
 
13
- | вход | тип | умолчание |
14
- | ------------- | ---------------- | --------------------------- |
15
- | `multiple` | `boolean` | `false` |
16
- | `accept` | `string \| null` | `null` |
17
- | `directory` | `boolean` | `false` |
18
- | `buttonLabel` | `string` | `''` → `rtKit.uiChooseFile` |
13
+ | вход | тип | умолчание |
14
+ | ------------- | ---------------- | --------------------- |
15
+ | `multiple` | `boolean` | `false` |
16
+ | `accept` | `string \| null` | `null` |
17
+ | `directory` | `boolean` | `false` |
18
+ | `buttonLabel` | `string` | `''` → `uiChooseFile` |
19
19
 
20
20
  Значение — `File[]`.
21
21
 
@@ -4,11 +4,11 @@
4
4
  <rt-live-badge label="Смотрят сейчас" [count]="visitors()" [active]="streamAlive()" />
5
5
  ```
6
6
 
7
- | вход | тип | умолчание |
8
- | -------- | ---------------- | ---------------------------------------- |
9
- | `label` | `string` | `''` → переведённое `rtKit.uiLiveOnSite` |
10
- | `count` | `number \| null` | `null` → прочерк `—` |
11
- | `active` | `boolean` | `false` |
7
+ | вход | тип | умолчание |
8
+ | -------- | ---------------- | ---------------------------------- |
9
+ | `label` | `string` | `''` → переведённое `uiLiveOnSite` |
10
+ | `count` | `number \| null` | `null` → прочерк `—` |
11
+ | `active` | `boolean` | `false` |
12
12
 
13
13
  Выходов нет.
14
14
 
@@ -17,12 +17,12 @@
17
17
 
18
18
  ## `rt-menu`
19
19
 
20
- | вход | тип | умолчание |
21
- | ----------- | ------------------ | ------------------------ |
22
- | `icon` | `IRtIcon.Name` | `'ellipsis-h'` |
23
- | `ariaLabel` | `string` | `''` → `rtKit.uiActions` |
24
- | `align` | `'start' \| 'end'` | `'end'` |
25
- | `disabled` | `boolean` | `false` |
20
+ | вход | тип | умолчание |
21
+ | ----------- | ------------------ | ------------------ |
22
+ | `icon` | `IRtIcon.Name` | `'ellipsis-h'` |
23
+ | `ariaLabel` | `string` | `''` → `uiActions` |
24
+ | `align` | `'start' \| 'end'` | `'end'` |
25
+ | `disabled` | `boolean` | `false` |
26
26
 
27
27
  ## `rt-menu-item`
28
28
 
@@ -11,16 +11,16 @@
11
11
  (submitted)="send($event)" />
12
12
  ```
13
13
 
14
- | вход | тип | умолчание |
15
- | ---------------------- | ---------------------- | ------------------------------ |
16
- | `placeholder` | `string` | `''` → `rtKit.chatPlaceholder` |
17
- | `attachments` | `boolean` | `false` |
18
- | `accept` | `string` | `''` |
19
- | `sending` / `disabled` | `boolean` | `false` |
20
- | `formatting` | `boolean` | `false` |
21
- | `toolbar` | `IRtRichEditorToolbar` | `'full'` |
22
- | `minRows` / `maxRows` | `number` | 1 / 6 |
23
- | `droppedFiles` | `File[] \| null` | `null` |
14
+ | вход | тип | умолчание |
15
+ | ---------------------- | ---------------------- | ------------------------ |
16
+ | `placeholder` | `string` | `''` → `chatPlaceholder` |
17
+ | `attachments` | `boolean` | `false` |
18
+ | `accept` | `string` | `''` |
19
+ | `sending` / `disabled` | `boolean` | `false` |
20
+ | `formatting` | `boolean` | `false` |
21
+ | `toolbar` | `IRtRichEditorToolbar` | `'full'` |
22
+ | `minRows` / `maxRows` | `number` | 1 / 6 |
23
+ | `droppedFiles` | `File[] \| null` | `null` |
24
24
 
25
25
  Выход: `submitted` — `{ text, delta?, files }`.
26
26
 
@@ -8,11 +8,11 @@
8
8
 
9
9
  Свои входы поверх общих из [`RtFormControlBase`](../form-control/CONTEXT.md):
10
10
 
11
- | вход | тип | умолчание |
12
- | ------------- | ---------------------------------------------------------------------------- | ----------------------------- |
13
- | `options` | `ReadonlyArray<{ label, value, disabled? }>` (тот же тип, что у `rt-select`) | `[]` |
14
- | `placeholder` | `string` | `''` → `rtKit.uiSelectValues` |
15
- | `maxChips` | `number` | `3` |
11
+ | вход | тип | умолчание |
12
+ | ------------- | ---------------------------------------------------------------------------- | ----------------------- |
13
+ | `options` | `ReadonlyArray<{ label, value, disabled? }>` (тот же тип, что у `rt-select`) | `[]` |
14
+ | `placeholder` | `string` | `''` → `uiSelectValues` |
15
+ | `maxChips` | `number` | `3` |
16
16
 
17
17
  Значение — `ReadonlyArray<TValue>`. Отдельного выхода выбора нет: значение едет только формой.
18
18
 
@@ -31,7 +31,7 @@
31
31
  - Закрытие панели помечает контрол тронутым; `FormControl.disable()` закрывает раскрытую панель.
32
32
  - Подпись фишки берётся из `options` пайпом `rtMultiselectLabel`; для значения вне набора
33
33
  подставляется его строковое представление.
34
- - Отключённые опции не выбираются, пустой набор даёт `rtKit.uiNoOptions`.
34
+ - Отключённые опции не выбираются, пустой набор даёт `uiNoOptions`.
35
35
 
36
36
  ## Клавиатура
37
37
 
@@ -6,10 +6,10 @@
6
6
  <rt-night-grid ariaLabel="Ночи марта" [cells]="cells()" (cellClick)="toggle($event)" />
7
7
  ```
8
8
 
9
- | вход | тип | умолчание |
10
- | ----------- | ------------------------------------- | ------------------------------ |
11
- | `cells` | `ReadonlyArray<{ id, state, title }>` | **обязателен** |
12
- | `ariaLabel` | `string` | `''` → `rtKit.uiNightGridAria` |
9
+ | вход | тип | умолчание |
10
+ | ----------- | ------------------------------------- | ------------------------ |
11
+ | `cells` | `ReadonlyArray<{ id, state, title }>` | **обязателен** |
12
+ | `ariaLabel` | `string` | `''` → `uiNightGridAria` |
13
13
 
14
14
  Выход: `cellClick` — отдаёт **целую клетку**, а не идентификатор.
15
15
 
@@ -6,13 +6,13 @@
6
6
  <rt-page-header ariaLabel="Разделы" [items]="sections()" [user]="user()" (itemClick)="go($event)" (userClick)="openProfile()" />
7
7
  ```
8
8
 
9
- | вход | тип | умолчание |
10
- | ----------- | --------------------------- | ------------------------ |
11
- | `items` | `ReadonlyArray<Item>` | `[]` |
12
- | `user` | `{ name, avatar? } \| null` | `null` |
13
- | `userTitle` | `string` | `''` |
14
- | `userMenu` | `TemplateRef \| null` | `null` |
15
- | `ariaLabel` | `string` | `''` → `rtKit.uiMainNav` |
9
+ | вход | тип | умолчание |
10
+ | ----------- | --------------------------- | ------------------ |
11
+ | `items` | `ReadonlyArray<Item>` | `[]` |
12
+ | `user` | `{ name, avatar? } \| null` | `null` |
13
+ | `userTitle` | `string` | `''` |
14
+ | `userMenu` | `TemplateRef \| null` | `null` |
15
+ | `ariaLabel` | `string` | `''` → `uiMainNav` |
16
16
 
17
17
  Выходы: `itemClick`, `userClick`.
18
18
 
@@ -38,6 +38,6 @@
38
38
  - Узкая и широкая разметки живут в DOM **одновременно** (`pagination-compact` и
39
39
  `pagination-nav`): какую показать, решает медиазапрос, а не условная отрисовка.
40
40
  - **У пустого набора нет своего вида строки диапазона — бар при нём спрятан целиком.** Ветка на
41
- `rtKit.uiRangeEmpty` тут была, но показать её не могло ничто: правило видимости прячет бар
41
+ `uiRangeEmpty` тут была, но показать её не могло ничто: правило видимости прячет бар
42
42
  раньше. Сам ключ в словаре остался (он часть публичного `rtKit`), но кит его больше не читает.
43
43
  Про пустоту говорит [`rt-empty-state`](../empty-state/CONTEXT.md), а не пагинация.
@@ -8,13 +8,13 @@
8
8
 
9
9
  Свои входы поверх общих из [`RtFormControlBase`](../form-control/CONTEXT.md):
10
10
 
11
- | вход | тип | умолчание |
12
- | ------------------- | -------------------------------------------- | ----------------------- |
13
- | `options` | `ReadonlyArray<{ label, value, disabled? }>` | `[]` |
14
- | `placeholder` | `string` | `''` |
15
- | `iconLeft` | `IRtIcon.Name \| null` | `null` |
16
- | `filter` | `boolean` | `false` |
17
- | `filterPlaceholder` | `string` | `''` → `rtKit.uiSearch` |
11
+ | вход | тип | умолчание |
12
+ | ------------------- | -------------------------------------------- | ----------------- |
13
+ | `options` | `ReadonlyArray<{ label, value, disabled? }>` | `[]` |
14
+ | `placeholder` | `string` | `''` |
15
+ | `iconLeft` | `IRtIcon.Name \| null` | `null` |
16
+ | `filter` | `boolean` | `false` |
17
+ | `filterPlaceholder` | `string` | `''` → `uiSearch` |
18
18
 
19
19
  | выход | тип |
20
20
  | ----------------- | ---------------- |
@@ -45,7 +45,7 @@
45
45
  - Закрытие списка помечает контрол тронутым и сбрасывает строку фильтра.
46
46
  - `FormControl.disable()` **закрывает уже раскрытый** список — иначе панель висела бы над
47
47
  контролом, которым уже нельзя пользоваться.
48
- - Пустой набор опций рисует строку `rtKit.uiNoOptions`.
48
+ - Пустой набор опций рисует строку `uiNoOptions`.
49
49
  - Ширина панели равна ширине триггера (`rtPopoverWidth="trigger"`).
50
50
 
51
51
  ## Рядом
@@ -11,13 +11,13 @@
11
11
  (itemSelect)="run($event)" />
12
12
  ```
13
13
 
14
- | вход | тип | умолчание |
15
- | ---------------------- | ----------------------------------------------- | ---------------------------- |
16
- | `label` | `string` | **обязателен** |
17
- | `menuItems` | `readonly { value, label, icon?, disabled? }[]` | **обязателен** |
18
- | `theme` / `size` | как у [`[rtButton]`](../button/CONTEXT.md) | `'primary'` / `'md'` |
19
- | `menuAriaLabel` | `string` | `''` → `rtKit.uiMoreActions` |
20
- | `loading` / `disabled` | `boolean` | `false` |
14
+ | вход | тип | умолчание |
15
+ | ---------------------- | ----------------------------------------------- | ---------------------- |
16
+ | `label` | `string` | **обязателен** |
17
+ | `menuItems` | `readonly { value, label, icon?, disabled? }[]` | **обязателен** |
18
+ | `theme` / `size` | как у [`[rtButton]`](../button/CONTEXT.md) | `'primary'` / `'md'` |
19
+ | `menuAriaLabel` | `string` | `''` → `uiMoreActions` |
20
+ | `loading` / `disabled` | `boolean` | `false` |
21
21
 
22
22
  Выходы: `faceClick`, `itemSelect` (значение пункта).
23
23
 
@@ -57,8 +57,21 @@
57
57
  list-style: none;
58
58
  }
59
59
 
60
+ /* Ширину пункту задаёт панель, а не его текст: `width="trigger"` держит её равной
61
+ кнопке. Пункт длиннее обязан обрезаться, иначе лейбл вылезает за скруглённую
62
+ рамку панели и висит в воздухе. Многоточие требует блочного лейбла: у
63
+ `inline-flex` `text-overflow` не работает — текст внутри становится анонимным
64
+ flex-элементом, и обрезка проходит без знака. */
60
65
  &__menu-item.rt-button {
66
+ overflow: hidden;
61
67
  width: 100%;
62
68
  justify-content: flex-start;
69
+
70
+ .rt-button__label {
71
+ display: block;
72
+ overflow: hidden;
73
+ min-width: 0;
74
+ text-overflow: ellipsis;
75
+ }
63
76
  }
64
77
  }
@@ -29,7 +29,7 @@
29
29
  Знак и стрелка выводятся из числа: `> 0` — «+» и стрелка вверх, `< 0` — стрелка вниз. Дробная
30
30
  часть отделяется запятой.
31
31
 
32
- **Значение базы уходит параметром перевода, а не подставляется в готовую строку.** Transloco
32
+ **Значение базы уходит параметром подписи, а не подставляется в готовую строку.** Переводчик приложения
33
33
  интерполирует `{{value}}` в момент перевода, и к возвращённой строке подставлять уже нечего:
34
34
  `String.replace` после `translateSignal` не находил плейсхолдера, и от подписи оставалась одна
35
35
  приставка («было», «was»). Параметр передан сигналом — смена базы переписывает строку.
@@ -47,7 +47,7 @@
47
47
 
48
48
  ## Края
49
49
 
50
- - Пустой набор рисует заглушку с переведённым `rtKit.uiNoData`; свой текст перебивает её.
50
+ - Пустой набор рисует заглушку с переведённым `uiNoData`; свой текст перебивает её.
51
51
  - Колонка `rtRowActions` добавляется китом сама, когда включён `showRowActions`, и рисует
52
52
  [`rt-menu`](../menu/CONTEXT.md) в строке.
53
53
  - Спеки логики лежат рядом: сортировка и предикат действий строки проверены отдельно.
@@ -0,0 +1,40 @@
1
+ # `rt-table-sort-header`
2
+
3
+ Заголовок сортируемой колонки. Ставится атрибутом на ячейку шапки таблицы, а ключ колонки —
4
+ тот же, что в `cdkColumnDef` и в `[columnsConfig]`.
5
+
6
+ ```html
7
+ <th *cdkHeaderCellDef cdk-header-cell rtSortHeader="checkIn">Заезд</th>
8
+ ```
9
+
10
+ | вход | тип | умолчание |
11
+ | -------------- | -------- | ------------ |
12
+ | `rtSortHeader` | `string` | обязательный |
13
+
14
+ ## Главное, что нужно знать
15
+
16
+ **Сортируемость объявляет таблица, а не заголовок.** Колонка получает кнопку только когда
17
+ помечена `sortable` в `[columnsConfig]`; иначе заголовок остаётся обычной подписью, и лишнего
18
+ элемента управления в шапке не появляется.
19
+
20
+ **Направление читается с самой ячейки.** `aria-sort` стоит на `<th>`, а не на кнопке внутри:
21
+ скринридер объявляет порядок вместе с колонкой. Глазами то же самое показывает стрелка — обе
22
+ стрелки без сортировки, одна выбранная при ней.
23
+
24
+ **Порядок ходит по кругу из трёх состояний:** по возрастанию → по убыванию → без сортировки.
25
+ Третье нужно, чтобы вернуть исходный порядок, не перезагружая список.
26
+
27
+ **Подпись проецируется внутрь кнопки** и служит её доступным именем — отдельного `aria-label`
28
+ у кнопки нет и не должно быть.
29
+
30
+ ## Края
31
+
32
+ - Блок BEM объявлен в шаблоне, а не только классом на хосте: `rtElem` внутри требует блока в
33
+ своём инжекторе, и без него компонент не поднимался вовсе — потребитель получал `NG0201`.
34
+ - Сортировка по соседней колонке эту не помечает: `aria-sort` у неё остаётся `none`, а стрелка
35
+ возвращается к нейтральной.
36
+
37
+ ## Рядом
38
+
39
+ - [`rt-table`](../CONTEXT.md) — таблица, у которой заголовок спрашивает порядок и которой
40
+ сообщает о нажатии.
@@ -23,15 +23,15 @@
23
23
 
24
24
  ## `[rtTab]`
25
25
 
26
- | вход | тип | умолчание |
27
- | --------------------------------- | --------------------------------------------- | --------------------------- |
28
- | `rtTab` | `IRtTabs.Id` — идентификатор вкладки | `''` |
29
- | `label` | `string` | `''` |
30
- | `titleTemplate` | `TemplateRef \| null` | `null` |
31
- | `icon` / `iconColor` | `IRtIcon.Name \| null` / `IRtTabs.TitleColor` | `null` / `'current'` |
32
- | `badge` | `string \| number \| null` | `null` |
33
- | `disabled` / `hidden` / `invalid` | `boolean` | `false` |
34
- | `invalidMessage` | `string` | `''` → `rtKit.uiTabInvalid` |
26
+ | вход | тип | умолчание |
27
+ | --------------------------------- | --------------------------------------------- | --------------------- |
28
+ | `rtTab` | `IRtTabs.Id` — идентификатор вкладки | `''` |
29
+ | `label` | `string` | `''` |
30
+ | `titleTemplate` | `TemplateRef \| null` | `null` |
31
+ | `icon` / `iconColor` | `IRtIcon.Name \| null` / `IRtTabs.TitleColor` | `null` / `'current'` |
32
+ | `badge` | `string \| number \| null` | `null` |
33
+ | `disabled` / `hidden` / `invalid` | `boolean` | `false` |
34
+ | `invalidMessage` | `string` | `''` → `uiTabInvalid` |
35
35
 
36
36
  ## Главное, что нужно знать
37
37
 
@@ -41,6 +41,11 @@
41
41
  **Идентификатор, которого нет, откатывается на первую доступную вкладку.** То же с отключённой:
42
42
  активной она стать не может. Так вкладка из старой ссылки не оставляет пустой экран.
43
43
 
44
+ **Контрол шапки объявляется `[rtTabsControl]` на `<ng-template>`.** Сторона задаётся значением
45
+ директивы: `rtTabsControl="left"` слева, `[rtTabsControl]="side"` — вычисленной стороной. Без
46
+ значения контрол встаёт справа — пустая строка приводится к правой стороне намеренно, иначе
47
+ `<ng-template rtTabsControl>` не попадал бы ни в один слот и пропадал из шапки вовсе.
48
+
44
49
  ## Клавиатура и доступность
45
50
 
46
51
  - Стрелки (влево/вправо, а в вертикальной раскладке вверх/вниз) перешагивают отключённые вкладки