@rt-tools/ui-kit-v2 0.15.0 → 0.17.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 (119) hide show
  1. package/README.md +7 -0
  2. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs +96 -41
  3. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs.map +1 -1
  4. package/fesm2022/rt-tools-ui-kit-v2.mjs +6824 -2700
  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.17.0.tgz +0 -0
  8. package/src/assets/icons/chat-error.svg +9 -0
  9. package/src/assets/icons/fork-spoon.svg +9 -0
  10. package/src/assets/icons/fullscreen.svg +9 -0
  11. package/src/assets/icons/home.svg +9 -0
  12. package/src/assets/icons/layers.svg +9 -0
  13. package/src/assets/icons/pin.svg +5 -0
  14. package/src/assets/icons/troubleshoot.svg +9 -0
  15. package/src/assets/icons-material/chart-bar.fill.svg +5 -0
  16. package/src/assets/icons-material/chart-bar.svg +5 -0
  17. package/src/assets/icons-material/chart-line.fill.svg +5 -0
  18. package/src/assets/icons-material/chart-line.svg +5 -0
  19. package/src/assets/icons-material/chat-error.fill.svg +5 -0
  20. package/src/assets/icons-material/chat-error.svg +5 -0
  21. package/src/assets/icons-material/comment.fill.svg +5 -0
  22. package/src/assets/icons-material/comment.svg +5 -0
  23. package/src/assets/icons-material/fork-spoon.fill.svg +5 -0
  24. package/src/assets/icons-material/fork-spoon.svg +5 -0
  25. package/src/assets/icons-material/fullscreen.fill.svg +5 -0
  26. package/src/assets/icons-material/fullscreen.svg +5 -0
  27. package/src/assets/icons-material/home.fill.svg +3 -0
  28. package/src/assets/icons-material/home.svg +5 -0
  29. package/src/assets/icons-material/ico-exit.fill.svg +5 -0
  30. package/src/assets/icons-material/ico-exit.svg +5 -0
  31. package/src/assets/icons-material/ico-sun.fill.svg +5 -0
  32. package/src/assets/icons-material/ico-sun.svg +5 -0
  33. package/src/assets/icons-material/ico-user.fill.svg +5 -0
  34. package/src/assets/icons-material/ico-user.svg +5 -0
  35. package/src/assets/icons-material/layers.fill.svg +3 -0
  36. package/src/assets/icons-material/layers.svg +5 -0
  37. package/src/assets/icons-material/minus.fill.svg +3 -0
  38. package/src/assets/icons-material/minus.svg +3 -0
  39. package/src/assets/icons-material/moon.fill.svg +5 -0
  40. package/src/assets/icons-material/moon.svg +5 -0
  41. package/src/assets/icons-material/pin.fill.svg +3 -0
  42. package/src/assets/icons-material/pin.svg +5 -0
  43. package/src/assets/icons-material/search-plus.fill.svg +5 -0
  44. package/src/assets/icons-material/search-plus.svg +5 -0
  45. package/src/assets/icons-material/th-large.fill.svg +3 -0
  46. package/src/assets/icons-material/th-large.svg +5 -0
  47. package/src/assets/icons-material/troubleshoot.fill.svg +5 -0
  48. package/src/assets/icons-material/troubleshoot.svg +5 -0
  49. package/src/lib/components/CONTEXT.md +1 -1
  50. package/src/lib/components/action-bar/CONTEXT.md +5 -0
  51. package/src/lib/components/action-bar/rt-action-bar.component.scss +30 -16
  52. package/src/lib/components/aside/CONTEXT.md +18 -1
  53. package/src/lib/components/aside/error-box/rt-aside-error-box.component.scss +37 -0
  54. package/src/lib/components/aside/footer/rt-aside-footer.component.scss +7 -8
  55. package/src/lib/components/aside/header/rt-aside-header.component.scss +16 -1
  56. package/src/lib/components/aside/rt-aside.component.scss +31 -3
  57. package/src/lib/components/button/CONTEXT.md +12 -11
  58. package/src/lib/components/button/rt-button.directive.scss +36 -0
  59. package/src/lib/components/data-list/settings/rt-data-list-settings-aside.component.scss +2 -2
  60. package/src/lib/components/data-table/cell/rt-data-table-cell.component.scss +1 -1
  61. package/src/lib/components/data-table/filter-cell/rt-data-table-filter-cell.component.scss +1 -1
  62. package/src/lib/components/data-table/rt-data-table.component.scss +1 -1
  63. package/src/lib/components/dialog/CONTEXT.md +9 -0
  64. package/src/lib/components/dialog/content/rt-dialog-content.component.scss +20 -0
  65. package/src/lib/components/dialog/footer/rt-dialog-footer.component.scss +18 -2
  66. package/src/lib/components/dialog/header/rt-dialog-header.component.scss +21 -3
  67. package/src/lib/components/dialog/rt-dialog.component.scss +9 -3
  68. package/src/lib/components/dynamic-selector/CONTEXT.md +50 -0
  69. package/src/lib/components/dynamic-selector/dynamic-input/rt-dynamic-input.component.scss +19 -0
  70. package/src/lib/components/dynamic-selector/list/rt-dynamic-selector-list.component.scss +108 -0
  71. package/src/lib/components/dynamic-selector/popup/rt-dynamic-selector-popup.component.scss +170 -0
  72. package/src/lib/components/dynamic-selector/rt-dynamic-selector.component.scss +23 -0
  73. package/src/lib/components/dynamic-selector/stories/component/test-dynamic-selector-matrix.component.scss +8 -0
  74. package/src/lib/components/dynamic-selector/stories/component/test-dynamic-selector.component.scss +7 -0
  75. package/src/lib/components/empty-state/CONTEXT.md +3 -0
  76. package/src/lib/components/empty-state/rt-empty-state.component.scss +9 -0
  77. package/src/lib/components/expansion-panel/CONTEXT.md +45 -0
  78. package/src/lib/components/expansion-panel/rt-expansion-panel.component.scss +134 -0
  79. package/src/lib/components/expansion-panel/stories/component/test-expansion-panel-matrix.component.scss +31 -0
  80. package/src/lib/components/header/CONTEXT.md +2 -2
  81. package/src/lib/components/icon/CONTEXT.md +11 -7
  82. package/src/lib/components/icon/rt-icon.component.scss +47 -0
  83. package/src/lib/components/icon-button/CONTEXT.md +27 -20
  84. package/src/lib/components/icon-button/rt-icon-button.component.scss +51 -25
  85. package/src/lib/components/image-cropper/CONTEXT.md +54 -0
  86. package/src/lib/components/image-cropper/rt-image-cropper.component.scss +220 -0
  87. package/src/lib/components/image-upload/CONTEXT.md +70 -0
  88. package/src/lib/components/image-upload/rt-image-upload.component.scss +89 -0
  89. package/src/lib/components/menu/CONTEXT.md +27 -0
  90. package/src/lib/components/menu/rt-menu-item.component.scss +42 -0
  91. package/src/lib/components/pagination/rt-pagination.component.scss +1 -1
  92. package/src/lib/components/scroll-area/CONTEXT.md +2 -0
  93. package/src/lib/components/scroll-area/rt-scroll-area.component.scss +20 -3
  94. package/src/lib/components/side-menu/CONTEXT.md +43 -0
  95. package/src/lib/components/side-menu/favorites/rt-side-menu-favorites.component.scss +126 -0
  96. package/src/lib/components/side-menu/rt-side-menu.component.scss +303 -0
  97. package/src/lib/components/side-menu/stories/component/test-side-menu-cell.component.scss +27 -0
  98. package/src/lib/components/side-menu/stories/component/test-side-menu.component.scss +39 -0
  99. package/src/lib/components/side-menu/sub-item/rt-side-menu-sub-item.component.scss +203 -0
  100. package/src/lib/components/spinner/CONTEXT.md +15 -8
  101. package/src/lib/components/spinner/rt-spinner.component.scss +108 -9
  102. package/src/lib/components/table/CONTEXT.md +6 -0
  103. package/src/lib/components/table/rt-table.component.scss +4 -2
  104. package/src/lib/components/tag/rt-tag.component.scss +43 -23
  105. package/src/lib/components/toast/CONTEXT.md +8 -0
  106. package/src/lib/components/toast/rt-toast.component.scss +74 -15
  107. package/src/lib/components/toast/rt-toaster.component.scss +5 -1
  108. package/src/lib/components/toggle-button-group/rt-toggle-button-group.component.scss +35 -37
  109. package/src/lib/components/toggle-switch/CONTEXT.md +11 -3
  110. package/src/lib/components/toggle-switch/rt-toggle-switch.component.scss +53 -14
  111. package/src/lib/components/toolbar/rt-toolbar.component.scss +15 -4
  112. package/src/lib/components/tooltip/CONTEXT.md +7 -4
  113. package/src/rich-editor/lib/components/chat/CONTEXT.md +7 -2
  114. package/src/rich-editor/lib/components/chat/rt-chat.component.scss +25 -0
  115. package/src/styles/_color-scheme.scss +50 -0
  116. package/styles/tokens.css +35 -0
  117. package/types/rt-tools-ui-kit-v2-rich-editor.d.ts +16 -20
  118. package/types/rt-tools-ui-kit-v2.d.ts +1588 -58
  119. package/rt-tools-ui-kit-v2-0.15.0.tgz +0 -0
@@ -51,6 +51,23 @@
51
51
  max-height: var(--rt-menu-item-icon-size);
52
52
  flex-shrink: 0;
53
53
  color: var(--rt-color-text-muted);
54
+
55
+ /* Свой значок приложения: коробка значка держит размер и цвет тона, а рисунок внутри
56
+ занимает её целиком и красится через currentColor. */
57
+ &--own {
58
+ display: inline-flex;
59
+ width: var(--rt-menu-item-icon-size);
60
+ height: var(--rt-menu-item-icon-size);
61
+ align-items: center;
62
+ justify-content: center;
63
+ font-size: var(--rt-menu-item-icon-size);
64
+ line-height: 1;
65
+
66
+ > * {
67
+ max-width: 100%;
68
+ max-height: 100%;
69
+ }
70
+ }
54
71
  }
55
72
 
56
73
  &__label {
@@ -58,6 +75,31 @@
58
75
  white-space: nowrap;
59
76
  }
60
77
 
78
+ /* Пункт-ссылка: кликабельной зоной и узлом фокуса служит ссылка внутри, поэтому поля и
79
+ раскладка пункта переезжают на неё, а хост остаётся рамкой подсветки. */
80
+ &--link {
81
+ padding: 0;
82
+ }
83
+
84
+ &__link {
85
+ display: flex;
86
+ min-width: 0;
87
+ min-height: var(--rt-menu-item-min-height);
88
+ box-sizing: border-box;
89
+ flex: 1 1 auto;
90
+ align-items: center;
91
+ padding: var(--rt-menu-item-padding-y) var(--rt-menu-item-padding-x);
92
+ border-radius: var(--rt-menu-item-radius);
93
+ color: inherit;
94
+ gap: var(--rt-space-sm);
95
+ text-decoration: none;
96
+
97
+ &:focus-visible {
98
+ background: var(--rt-color-bg-hover);
99
+ outline: none;
100
+ }
101
+ }
102
+
61
103
  &--current {
62
104
  background: var(--rt-menu-item-current-bg);
63
105
  }
@@ -25,7 +25,7 @@
25
25
  }
26
26
 
27
27
  .rt-icon-button {
28
- --rt-icon-button-size: var(--rt-pagination-arrow-size);
28
+ --rt-icon-button-size-step: var(--rt-pagination-arrow-size);
29
29
  --rt-icon-button-radius: var(--rt-pagination-arrow-radius);
30
30
  --rt-icon-button-shadow: var(--rt-pagination-arrow-shadow);
31
31
  }
@@ -46,6 +46,8 @@
46
46
  - Нажатие на значок уводит тело к самому низу и в содержимое под значком не уходит.
47
47
  - Полоса не ловит указатель — нажатия по списку под ней проходят насквозь; значок ловит сам.
48
48
  - Перекрасить растушёвку можно свойством `--rt-scroll-area-hint-color` на блоке.
49
+ - Отступы и фоны шапки, тела и подвала — свойства блока `--rt-scroll-area-*-padding` и
50
+ `--rt-scroll-area-*-bg`; фоны по умолчанию прозрачные.
49
51
 
50
52
  ## Договорённость
51
53
 
@@ -1,8 +1,22 @@
1
1
  @layer rt-kit.components {
2
+ /* Фон хоста — с нулевой специфичностью. Хост области часто сам элемент чужого блока со своим
3
+ фоном (столбец бокового меню), и правило той же силы перебивало его порядком в файле:
4
+ столбец терял подложку. Под `:where` любое правило по классу сильнее. */
5
+ :where(.rt-scroll-area) {
6
+ background: var(--rt-scroll-area-bg);
7
+ }
8
+
2
9
  .rt-scroll-area {
3
10
  --rt-scroll-area-hint-height: var(--rt-space-10);
4
11
  --rt-scroll-area-hint-color: var(--rt-color-bg-surface);
5
12
  --rt-scroll-area-hint-radius: var(--rt-radius-full);
13
+ --rt-scroll-area-header-padding: var(--rt-space-2) var(--rt-space-4);
14
+ --rt-scroll-area-body-padding: var(--rt-space-4);
15
+ --rt-scroll-area-footer-padding: var(--rt-space-4);
16
+ --rt-scroll-area-bg: transparent;
17
+ --rt-scroll-area-header-bg: transparent;
18
+ --rt-scroll-area-body-bg: transparent;
19
+ --rt-scroll-area-footer-bg: transparent;
6
20
 
7
21
  // Полоса растушёвки считает своё место от хоста: тело обрезает всё по своему краю, а
8
22
  // полоса обязана дойти до содержимого подвала.
@@ -15,7 +29,8 @@
15
29
 
16
30
  &__header {
17
31
  flex: 0 0 auto;
18
- padding: var(--rt-space-2) var(--rt-space-4);
32
+ padding: var(--rt-scroll-area-header-padding);
33
+ background: var(--rt-scroll-area-header-bg);
19
34
  }
20
35
 
21
36
  &__body {
@@ -23,13 +38,15 @@
23
38
  overflow: auto;
24
39
  flex: 1 1 auto;
25
40
  flex-direction: column;
26
- padding: var(--rt-space-4);
41
+ padding: var(--rt-scroll-area-body-padding);
42
+ background: var(--rt-scroll-area-body-bg);
27
43
  min-block-size: 0;
28
44
  }
29
45
 
30
46
  &__footer {
31
47
  flex: 0 0 auto;
32
- padding: var(--rt-space-4);
48
+ padding: var(--rt-scroll-area-footer-padding);
49
+ background: var(--rt-scroll-area-footer-bg);
33
50
  }
34
51
 
35
52
  // Полоса стоит поверх стыка тела и подвала и не ловит указатель: под ней живой список,
@@ -0,0 +1,43 @@
1
+ # `rt-side-menu`
2
+
3
+ Боковая навигация: полоса пунктов и подменю раздела рядом. Перенос бокового меню первого кита. Это
4
+ не `rt-menu`: то выпадающее меню действий, и одно другое не заменяет.
5
+
6
+ ```html
7
+ <rt-side-menu menuId="main" [menuItems]="sections()" [activeMenuIds]="activeIds()" />
8
+ ```
9
+
10
+ Входы, выходы и оси — в `Overview.mdx` рядом. Договорённость о поведении — описание второго кита,
11
+ поддомен бокового меню.
12
+
13
+ ## Главное, что нужно знать
14
+
15
+ **Активность приходит снаружи.** Меню не держит адрес само: какие пункты активны, говорит
16
+ `activeMenuIds`, и подсветку двигает новый набор после перехода.
17
+
18
+ **Режим и ширину подменю хранит сервис, а не меню.** `provideRtSideMenuSettings()` включает
19
+ хранение под номером меню; без провайдера меню ничего не помнит, и режим с шириной приходят
20
+ входами. Вход важнее сохранённого. `pinShown="false"` убирает кнопку закрепления, и сохранённое
21
+ закрепление тогда не читается: иначе человек не открепил бы меню.
22
+
23
+ **Подсказки строк подменю гасит `subMenuTooltipsShown="false"`.** Имена кнопок для чтения экрана
24
+ остаются.
25
+
26
+ **Значок вне набора — шаблон `rtSideMenuIcon`.** Имя Material первого кита меню переводит парой
27
+ из перечня кита, как `rt-menu`. Имя без пары берёт свой шаблон меню, один на все пункты и кнопки строк;
28
+ контекст — строка (`$implicit`), имя (`icon`) и место (`slot`: `'icon'` или `'iconButton'`). Без
29
+ шаблона на его месте пусто, а в режиме разработки консоль называет такое имя.
30
+
31
+ **Раздел и запрос меню держит само.** Их не задать входом: раздел открывает нажатие или наведение
32
+ на пункт полосы, запрос — набор в поле.
33
+
34
+ ## Края
35
+
36
+ - Незакреплённая панель стоит над страницей и закрывается уходом указателя. Если человек взялся за
37
+ поле поиска, её закрывает только нажатие снаружи.
38
+ - Закреплённая панель стоит в потоке рядом с полосой, у неё есть ручка ширины.
39
+ - На узком экране закрепления нет: меню рисует один столбец с кнопкой «назад».
40
+ - Столбец узкого экрана шириной `--rt-side-menu-mobile-width`, 15rem, как меню телефона первого кита:
41
+ длинная подпись режется многоточием и не раздувает меню. Строки стоят в 8 пикселях от края,
42
+ подпись — с 56.
43
+ - Отказ хранилища меню не останавливает.
@@ -0,0 +1,126 @@
1
+ @layer rt-kit.components {
2
+ /* rt-side-menu-favorites — блок избранного вверху подменю. ViewEncapsulation.None.
3
+ Блок — раскрывающаяся панель кита, оформленная как папка подменю; строки — те же подпункты,
4
+ что в списке. */
5
+
6
+ .rt-side-menu-favorites {
7
+ --rt-side-menu-favorites-radius: var(--rt-radius-full);
8
+ --rt-side-menu-favorites-divider-width: var(--rt-border-width-thin);
9
+
10
+ display: block;
11
+
12
+ /* Блок отделён от списка раздела чертой: без неё строка избранного и строка того же пункта
13
+ в списке стоят подряд и читаются как повтор. Свёрнутый блок держит черту так же. */
14
+ &:has(.rt-side-menu-favorites__panel) {
15
+ border-bottom: var(--rt-side-menu-favorites-divider-width) solid var(--rt-color-border-subtle);
16
+ margin-block-end: var(--rt-space-sm);
17
+ padding-block-end: var(--rt-space-sm);
18
+ }
19
+
20
+ /* Заголовок панели — как у папки подменю. Звезда стоит левее подписей строк, почти у края,
21
+ как у первого кита: так рядом со столбцом шевронов умещается и число строк. Свойства
22
+ переназначены правилом двух классов: так они сильнее значений самой панели на том же узле. */
23
+ &__panel.rt-expansion-panel {
24
+ --rt-expansion-panel-duration: var(--rt-duration-fast);
25
+ --rt-expansion-panel-header-radius: var(--rt-side-menu-favorites-radius);
26
+ --rt-expansion-panel-header-min-height: var(--rt-control-height-md);
27
+ --rt-expansion-panel-header-padding-block: var(--rt-space-2);
28
+ --rt-expansion-panel-header-padding-start: var(--rt-space-1);
29
+ --rt-expansion-panel-header-padding-end: var(--rt-space-sm);
30
+ --rt-expansion-panel-header-gap: var(--rt-space-sm);
31
+ --rt-expansion-panel-header-font-size: var(--rt-text-sm);
32
+ }
33
+
34
+ /* Звезда стоит на месте значка папки и красится цветом темы, как закрашенные звёзды списка. */
35
+ &__star {
36
+ flex-shrink: 0;
37
+ color: var(--rt-color-action-primary);
38
+ }
39
+
40
+ &__title {
41
+ overflow: hidden;
42
+ min-width: 0;
43
+ flex: 1 1 auto;
44
+ text-overflow: ellipsis;
45
+ white-space: nowrap;
46
+ }
47
+
48
+ &__list {
49
+ display: flex;
50
+ flex-direction: column;
51
+ }
52
+
53
+ &__item {
54
+ min-width: 0;
55
+ flex: 1 1 auto;
56
+ }
57
+ }
58
+
59
+ /* Строка и ручка объявлены вне корня блока: строку в руке CDK выносит в конец страницы, и правило
60
+ из корня до неё не доходит. */
61
+ .rt-side-menu-favorites__row {
62
+ display: flex;
63
+ align-items: center;
64
+
65
+ &.cdk-drag-preview {
66
+ --rt-side-menu-favorites-preview-radius: var(--rt-radius-full);
67
+ --rt-side-menu-favorites-preview-shadow: var(--rt-shadow-md);
68
+
69
+ border-radius: var(--rt-side-menu-favorites-preview-radius);
70
+ box-shadow: var(--rt-side-menu-favorites-preview-shadow);
71
+ }
72
+
73
+ /* Фон строки в руке — на строке внутри превью, а не на самом превью: CDK выносит превью в
74
+ верхний слой как `popover` и ставит ему встроенный прозрачный фон, который правило
75
+ класса не перебивает. */
76
+ &.cdk-drag-preview .rt-side-menu-favorites__item {
77
+ min-width: 0;
78
+ flex: 1 1 auto;
79
+ border-radius: var(--rt-side-menu-favorites-preview-radius);
80
+ background: var(--rt-color-bg-surface);
81
+ }
82
+
83
+ &.cdk-drag-placeholder {
84
+ opacity: 0;
85
+ }
86
+ }
87
+
88
+ /* Ручка видна так же, как «убрать»: под наведением и фокусом клавиатуры своей строки, а где
89
+ указатель не умеет наводиться, — всегда. Прячется прозрачностью: остаётся в порядке Tab. */
90
+ .rt-side-menu-favorites__handle {
91
+ flex-shrink: 0;
92
+ cursor: grab;
93
+ opacity: 0;
94
+
95
+ &:active {
96
+ cursor: grabbing;
97
+ }
98
+
99
+ @media (hover: none) {
100
+ opacity: 1;
101
+ }
102
+ }
103
+
104
+ .rt-side-menu-favorites__row:hover .rt-side-menu-favorites__handle,
105
+ .rt-side-menu-favorites__row:has(:focus-visible) .rt-side-menu-favorites__handle,
106
+ .rt-side-menu-favorites__row.cdk-drag-preview .rt-side-menu-favorites__handle {
107
+ opacity: 1;
108
+ }
109
+
110
+ /* Меню с `favoriteActionsReserve="none"`: ручка, ждущая наведения, в покое не занимает ширины. */
111
+ @media (hover: hover) {
112
+ .rt-side-menu--favorite-actions-none .rt-side-menu-favorites__handle {
113
+ overflow: hidden;
114
+ width: 0;
115
+ margin-inline-start: calc(var(--rt-space-sm) * -1);
116
+ }
117
+
118
+ /* Возврат места — прямым правилом: отрицание с `:has()` браузер при наведении не пересчитывал. */
119
+ .rt-side-menu--favorite-actions-none .rt-side-menu-favorites__row:hover .rt-side-menu-favorites__handle,
120
+ .rt-side-menu--favorite-actions-none .rt-side-menu-favorites__row:has(:focus-visible) .rt-side-menu-favorites__handle {
121
+ overflow: visible;
122
+ width: auto;
123
+ margin-inline-start: 0;
124
+ }
125
+ }
126
+ }
@@ -0,0 +1,303 @@
1
+ @layer rt-kit.components {
2
+ /* rt-side-menu — боковая навигация. ViewEncapsulation.None.
3
+ Host несёт класс блока: полоса пунктов, рядом панель подменю. Незакреплённая панель стоит над
4
+ страницей, закреплённая — в потоке рядом с полосой и сдвигает страницу. */
5
+
6
+ .rt-side-menu {
7
+ --rt-side-menu-rail-width: 5.5rem;
8
+ --rt-side-menu-panel-width: 15rem;
9
+ --rt-side-menu-panel-held-width: 30rem;
10
+ --rt-side-menu-mobile-width: 15rem;
11
+ --rt-side-menu-panel-radius: var(--rt-radius-lg);
12
+ --rt-side-menu-panel-shadow: var(--rt-shadow-nav-panel);
13
+ --rt-side-menu-item-radius: var(--rt-radius-full);
14
+ --rt-side-menu-resizer-border-width: var(--rt-border-width-thick);
15
+ --rt-side-menu-panel-border-width: var(--rt-border-width-thin);
16
+ --rt-side-menu-transition-duration: var(--rt-duration-fast);
17
+
18
+ /* Натянутую рукой ширину ставит привязка хоста; без неё панель берёт ширину оформления. */
19
+ --rt-side-menu-panel-dragged-width: 0px;
20
+
21
+ /* Ширина панели: наибольшее из оформления и натянутой рукой. */
22
+ --rt-side-menu-panel-shown-width: max(var(--rt-side-menu-panel-width), var(--rt-side-menu-panel-dragged-width));
23
+
24
+ position: relative;
25
+ display: flex;
26
+ height: 100%;
27
+ color: var(--rt-color-text-primary);
28
+
29
+ /* Полоса — область прокрутки, а та растягивает себя на всю ширину своим правилом того же
30
+ веса. Основа гибкой строки сильнее ширины, и полоса держит свою, в каком бы порядке ни
31
+ пришли стили. */
32
+ &__rail {
33
+ max-width: var(--rt-side-menu-rail-width);
34
+ height: 100%;
35
+ box-sizing: border-box;
36
+ flex: 0 0 var(--rt-side-menu-rail-width);
37
+ border-right: var(--rt-side-menu-panel-border-width) solid var(--rt-color-border-default);
38
+ background: var(--rt-color-bg-surface);
39
+
40
+ /* Отступ области прокрутки оставлял подписи 56 пикселей из 88, и слово рвалось посреди. */
41
+ .rt-scroll-area__body {
42
+ padding-inline: var(--rt-space-1);
43
+ }
44
+ }
45
+
46
+ &__rail-list {
47
+ display: flex;
48
+ flex-direction: column;
49
+ align-items: center;
50
+ gap: var(--rt-space-md);
51
+ padding-block: var(--rt-space-sm);
52
+ }
53
+
54
+ &__rail-item {
55
+ display: flex;
56
+ width: 100%;
57
+ flex-direction: column;
58
+ align-items: center;
59
+ padding: 0;
60
+ border: 0;
61
+ background: transparent;
62
+ color: inherit;
63
+ cursor: pointer;
64
+ font: inherit;
65
+ gap: var(--rt-space-1);
66
+ text-decoration: none;
67
+
68
+ &:focus-visible {
69
+ outline: none;
70
+
71
+ .rt-side-menu__rail-icon {
72
+ outline: var(--rt-focus-ring-width) solid var(--rt-focus-ring-color);
73
+ }
74
+ }
75
+
76
+ &:hover .rt-side-menu__rail-icon,
77
+ &:active .rt-side-menu__rail-icon {
78
+ background: var(--rt-color-bg-hover);
79
+ }
80
+
81
+ &--active .rt-side-menu__rail-icon,
82
+ &--active:hover .rt-side-menu__rail-icon {
83
+ background: var(--rt-color-action-primary-subtle);
84
+ color: var(--rt-color-action-primary-on-surface);
85
+ }
86
+ }
87
+
88
+ &__rail-icon {
89
+ display: flex;
90
+ width: 3.5rem;
91
+ height: 2rem;
92
+ align-items: center;
93
+ justify-content: center;
94
+ border-radius: var(--rt-side-menu-item-radius);
95
+ transition: background-color var(--rt-side-menu-transition-duration) ease;
96
+ }
97
+
98
+ &__rail-title {
99
+ max-width: 100%;
100
+ font-size: var(--rt-text-xs);
101
+ line-height: var(--rt-leading-snug);
102
+ overflow-wrap: anywhere;
103
+ text-align: center;
104
+ }
105
+
106
+ &__backdrop {
107
+ position: fixed;
108
+ z-index: var(--rt-z-dropdown);
109
+ inset: 0;
110
+ }
111
+
112
+ &__panel {
113
+ position: absolute;
114
+ z-index: var(--rt-z-dropdown);
115
+ top: 0;
116
+ left: var(--rt-side-menu-rail-width);
117
+ display: flex;
118
+ width: var(--rt-side-menu-panel-shown-width);
119
+ height: 100%;
120
+ box-sizing: border-box;
121
+ flex-direction: column;
122
+ border-radius: 0 var(--rt-side-menu-panel-radius) var(--rt-side-menu-panel-radius) 0;
123
+ border-left: var(--rt-side-menu-panel-border-width) solid var(--rt-color-border-default);
124
+ background: var(--rt-color-bg-surface);
125
+ box-shadow: var(--rt-side-menu-panel-shadow);
126
+
127
+ &--held {
128
+ width: max(var(--rt-side-menu-panel-held-width), var(--rt-side-menu-panel-shown-width));
129
+ }
130
+
131
+ &--pinned {
132
+ --rt-side-menu-panel-radius: 0;
133
+ --rt-side-menu-panel-shadow: var(--rt-shadow-none);
134
+
135
+ position: relative;
136
+ left: 0;
137
+ flex-shrink: 0;
138
+ }
139
+ }
140
+
141
+ &__panel-head {
142
+ display: flex;
143
+ align-items: center;
144
+ padding: var(--rt-space-sm);
145
+ gap: var(--rt-space-2);
146
+ }
147
+
148
+ &__search {
149
+ min-width: 0;
150
+ flex: 1 1 auto;
151
+ }
152
+
153
+ &__pin {
154
+ flex-shrink: 0;
155
+ }
156
+
157
+ &__panel-body {
158
+ min-height: 0;
159
+ flex: 1 1 auto;
160
+ }
161
+
162
+ &__sub-list {
163
+ display: flex;
164
+ flex-direction: column;
165
+ padding-block-end: var(--rt-space-sm);
166
+ padding-inline: var(--rt-space-2);
167
+ }
168
+
169
+ &__empty {
170
+ padding: var(--rt-space-md);
171
+ color: var(--rt-color-text-muted);
172
+ font-size: var(--rt-text-xs);
173
+ }
174
+
175
+ /* Ручка стоит у правого края закреплённой панели по всей её высоте. */
176
+ &__resizer {
177
+ position: absolute;
178
+ z-index: var(--rt-z-dropdown);
179
+ top: 0;
180
+ bottom: 0;
181
+ left: calc(var(--rt-side-menu-rail-width) + var(--rt-side-menu-panel-shown-width) - var(--rt-space-2));
182
+ width: var(--rt-space-sm);
183
+ cursor: col-resize;
184
+
185
+ &:before {
186
+ position: absolute;
187
+ top: 0;
188
+ bottom: 0;
189
+ left: 50%;
190
+ border-left: var(--rt-side-menu-resizer-border-width) solid transparent;
191
+ content: '';
192
+ }
193
+
194
+ &:hover:before,
195
+ &:focus-visible:before {
196
+ border-left-color: var(--rt-color-border-strong);
197
+ }
198
+
199
+ &:focus-visible {
200
+ outline: none;
201
+ }
202
+ }
203
+
204
+ /* Столбец узкого экрана держит свою ширину — как у меню телефона первого кита: без неё меню
205
+ растягивалось по самой длинной подписи, и строки не резались многоточием. Ширина — основой
206
+ гибкой строки, как у полосы: область прокрутки ставит себе ширину правилом того же веса.
207
+ Нулевой нижний предел не даёт самой длинной подписи раздуть основу. Уже экрана столбец не
208
+ бывает. */
209
+ &__mobile {
210
+ min-width: 0;
211
+ max-width: 100%;
212
+ height: 100%;
213
+ flex: 0 0 var(--rt-side-menu-mobile-width);
214
+ background: var(--rt-color-bg-surface);
215
+
216
+ /* Строки стоят в восьми пикселях от края столбца, как у меню телефона первого кита: отступ
217
+ области прокрутки отодвигал подложку активной строки на 24. */
218
+ .rt-scroll-area__body {
219
+ padding-inline: 0;
220
+ }
221
+ }
222
+
223
+ &__mobile-list,
224
+ &__mobile-sub {
225
+ display: flex;
226
+ flex-direction: column;
227
+ padding: var(--rt-space-sm);
228
+ gap: var(--rt-space-1);
229
+ }
230
+
231
+ &__mobile-item,
232
+ &__back {
233
+ display: flex;
234
+ width: 100%;
235
+ min-height: var(--rt-control-height-lg);
236
+ box-sizing: border-box;
237
+ align-items: center;
238
+ border: 0;
239
+ border-radius: var(--rt-side-menu-item-radius);
240
+ background: transparent;
241
+ color: inherit;
242
+ cursor: pointer;
243
+ font: inherit;
244
+ font-size: var(--rt-text-sm);
245
+
246
+ /* Подпись с 56 пикселей от края столбца, как у первого кита: значок — с 24, зазор 12. В шкале
247
+ шага 12 нет, он собран из двух. */
248
+ gap: calc(var(--rt-space-sm) + var(--rt-space-xs));
249
+ padding-inline: var(--rt-space-md);
250
+ text-align: start;
251
+ text-decoration: none;
252
+
253
+ &:hover {
254
+ background: var(--rt-color-bg-hover);
255
+ }
256
+
257
+ &:focus-visible {
258
+ outline: var(--rt-focus-ring-width) solid var(--rt-focus-ring-color);
259
+ outline-offset: calc(var(--rt-focus-ring-width) * -1);
260
+ }
261
+
262
+ &--active {
263
+ background: var(--rt-color-action-primary-subtle);
264
+ color: var(--rt-color-action-primary-on-surface);
265
+ }
266
+ }
267
+
268
+ /* Свой значок приложения — в полосе и в списке телефона: коробка размера значка пункта,
269
+ рисунок внутри занимает её целиком и красится через currentColor. */
270
+ &__own-icon {
271
+ --rt-side-menu-own-icon-size: var(--rt-size-5);
272
+
273
+ display: inline-flex;
274
+ width: var(--rt-side-menu-own-icon-size);
275
+ height: var(--rt-side-menu-own-icon-size);
276
+ flex-shrink: 0;
277
+ align-items: center;
278
+ justify-content: center;
279
+ color: inherit;
280
+ line-height: 1;
281
+
282
+ > * {
283
+ max-width: 100%;
284
+ max-height: 100%;
285
+ }
286
+ }
287
+
288
+ &__mobile-icon,
289
+ &__back-icon,
290
+ &__mobile-chevron {
291
+ flex-shrink: 0;
292
+ }
293
+
294
+ &__mobile-title,
295
+ &__back-label {
296
+ overflow: hidden;
297
+ min-width: 0;
298
+ flex: 1 1 auto;
299
+ text-overflow: ellipsis;
300
+ white-space: nowrap;
301
+ }
302
+ }
303
+ }
@@ -0,0 +1,27 @@
1
+ @layer rt-kit.components {
2
+ /* Коробка показа: даёт меню высоту и становится местом отсчёта для панели и подложки. Свойство
3
+ `contain` делает её содержащим блоком и для фиксированной подложки, и оно же обрезает. */
4
+ .app-side-menu-cell {
5
+ width: 36rem;
6
+
7
+ /* Половина темы уже 36rem: без предела коробка вылезала за её край, и край кадра резал
8
+ меню. Предел берёт ширину половины, а вне пары тем коробка остаётся в 36rem. */
9
+ max-width: 100%;
10
+ height: 24rem;
11
+ border: 1px dashed var(--rt-color-border-subtle);
12
+ background: var(--rt-color-bg-page);
13
+ contain: paint;
14
+
15
+ &__slot {
16
+ padding: var(--rt-space-sm) 0;
17
+ color: var(--rt-color-text-muted);
18
+ font-size: var(--rt-text-xs);
19
+ text-align: center;
20
+ }
21
+
22
+ &__own-icon {
23
+ width: 100%;
24
+ height: 100%;
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,39 @@
1
+ @layer rt-kit.components {
2
+ /* Меню во всю высоту окна и с тенью у края, как в истории первого кита: подменю выезжает над
3
+ страницей, и край меню виден на любом фоне. */
4
+ .app-side-menu {
5
+ --rt-side-menu-story-shadow: var(--rt-shadow-lg);
6
+
7
+ display: flex;
8
+ width: fit-content;
9
+ height: 100vh;
10
+ box-shadow: var(--rt-side-menu-story-shadow);
11
+
12
+ /* Низкий экран первого кита: окно высотой 360. */
13
+ &--short {
14
+ height: 22.5rem;
15
+ }
16
+
17
+ &__header {
18
+ display: flex;
19
+ width: 100%;
20
+ align-items: center;
21
+ justify-content: center;
22
+ padding: var(--rt-space-md) 0;
23
+ border-bottom: 1px solid var(--rt-color-border-subtle);
24
+ color: var(--rt-color-text-primary);
25
+ cursor: pointer;
26
+ }
27
+
28
+ &__footer {
29
+ display: flex;
30
+ width: 100%;
31
+ flex-direction: column;
32
+ align-items: center;
33
+ padding-top: calc(var(--rt-space-sm) + var(--rt-space-xs));
34
+ border-top: 1px solid var(--rt-color-border-subtle);
35
+ color: var(--rt-color-text-primary);
36
+ gap: var(--rt-space-sm);
37
+ }
38
+ }
39
+ }