@rt-tools/ui-kit-v2 0.15.0 → 0.16.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.
- package/fesm2022/rt-tools-ui-kit-v2.mjs +5883 -2414
- package/fesm2022/rt-tools-ui-kit-v2.mjs.map +1 -1
- package/package.json +1 -1
- package/rt-tools-ui-kit-v2-0.16.0.tgz +0 -0
- package/src/assets/icons/chat-error.svg +9 -0
- package/src/assets/icons/fork-spoon.svg +9 -0
- package/src/assets/icons/fullscreen.svg +9 -0
- package/src/assets/icons/home.svg +9 -0
- package/src/assets/icons/layers.svg +9 -0
- package/src/assets/icons/pin.svg +5 -0
- package/src/assets/icons/troubleshoot.svg +9 -0
- package/src/assets/icons-material/chart-bar.fill.svg +5 -0
- package/src/assets/icons-material/chart-bar.svg +5 -0
- package/src/assets/icons-material/chart-line.fill.svg +5 -0
- package/src/assets/icons-material/chart-line.svg +5 -0
- package/src/assets/icons-material/chat-error.fill.svg +5 -0
- package/src/assets/icons-material/chat-error.svg +5 -0
- package/src/assets/icons-material/comment.fill.svg +5 -0
- package/src/assets/icons-material/comment.svg +5 -0
- package/src/assets/icons-material/fork-spoon.fill.svg +5 -0
- package/src/assets/icons-material/fork-spoon.svg +5 -0
- package/src/assets/icons-material/fullscreen.fill.svg +5 -0
- package/src/assets/icons-material/fullscreen.svg +5 -0
- package/src/assets/icons-material/home.fill.svg +3 -0
- package/src/assets/icons-material/home.svg +5 -0
- package/src/assets/icons-material/ico-exit.fill.svg +5 -0
- package/src/assets/icons-material/ico-exit.svg +5 -0
- package/src/assets/icons-material/ico-sun.fill.svg +5 -0
- package/src/assets/icons-material/ico-sun.svg +5 -0
- package/src/assets/icons-material/ico-user.fill.svg +5 -0
- package/src/assets/icons-material/ico-user.svg +5 -0
- package/src/assets/icons-material/layers.fill.svg +3 -0
- package/src/assets/icons-material/layers.svg +5 -0
- package/src/assets/icons-material/minus.fill.svg +3 -0
- package/src/assets/icons-material/minus.svg +3 -0
- package/src/assets/icons-material/moon.fill.svg +5 -0
- package/src/assets/icons-material/moon.svg +5 -0
- package/src/assets/icons-material/pin.fill.svg +3 -0
- package/src/assets/icons-material/pin.svg +5 -0
- package/src/assets/icons-material/search-plus.fill.svg +5 -0
- package/src/assets/icons-material/search-plus.svg +5 -0
- package/src/assets/icons-material/th-large.fill.svg +3 -0
- package/src/assets/icons-material/th-large.svg +5 -0
- package/src/assets/icons-material/troubleshoot.fill.svg +5 -0
- package/src/assets/icons-material/troubleshoot.svg +5 -0
- package/src/lib/components/CONTEXT.md +1 -1
- package/src/lib/components/aside/CONTEXT.md +9 -0
- package/src/lib/components/aside/error-box/rt-aside-error-box.component.scss +37 -0
- package/src/lib/components/aside/rt-aside.component.scss +14 -2
- package/src/lib/components/dynamic-selector/CONTEXT.md +44 -0
- package/src/lib/components/dynamic-selector/dynamic-input/rt-dynamic-input.component.scss +19 -0
- package/src/lib/components/dynamic-selector/list/rt-dynamic-selector-list.component.scss +108 -0
- package/src/lib/components/dynamic-selector/popup/rt-dynamic-selector-popup.component.scss +170 -0
- package/src/lib/components/dynamic-selector/rt-dynamic-selector.component.scss +23 -0
- package/src/lib/components/dynamic-selector/stories/component/test-dynamic-selector-matrix.component.scss +8 -0
- package/src/lib/components/dynamic-selector/stories/component/test-dynamic-selector.component.scss +7 -0
- package/src/lib/components/empty-state/CONTEXT.md +3 -0
- package/src/lib/components/empty-state/rt-empty-state.component.scss +9 -0
- package/src/lib/components/expansion-panel/CONTEXT.md +45 -0
- package/src/lib/components/expansion-panel/rt-expansion-panel.component.scss +134 -0
- package/src/lib/components/expansion-panel/stories/component/test-expansion-panel-matrix.component.scss +31 -0
- package/src/lib/components/image-cropper/CONTEXT.md +54 -0
- package/src/lib/components/image-cropper/rt-image-cropper.component.scss +220 -0
- package/src/lib/components/image-upload/CONTEXT.md +65 -0
- package/src/lib/components/image-upload/rt-image-upload.component.scss +77 -0
- package/src/lib/components/menu/CONTEXT.md +27 -0
- package/src/lib/components/menu/rt-menu-item.component.scss +42 -0
- package/src/lib/components/side-menu/CONTEXT.md +38 -0
- package/src/lib/components/side-menu/favorites/rt-side-menu-favorites.component.scss +126 -0
- package/src/lib/components/side-menu/rt-side-menu.component.scss +303 -0
- package/src/lib/components/side-menu/stories/component/test-side-menu-cell.component.scss +27 -0
- package/src/lib/components/side-menu/stories/component/test-side-menu.component.scss +39 -0
- package/src/lib/components/side-menu/sub-item/rt-side-menu-sub-item.component.scss +203 -0
- package/src/lib/components/table/CONTEXT.md +6 -0
- package/src/lib/components/table/rt-table.component.scss +4 -2
- package/src/lib/components/tooltip/CONTEXT.md +7 -4
- package/src/styles/_color-scheme.scss +50 -0
- package/types/rt-tools-ui-kit-v2.d.ts +1234 -13
- package/rt-tools-ui-kit-v2-0.15.0.tgz +0 -0
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
@layer rt-kit.components {
|
|
2
|
+
/* rt-side-menu-sub-item — строка подменю бокового меню. ViewEncapsulation.None.
|
|
3
|
+
Host несёт класс блока; строка — ссылка или кнопка папки. */
|
|
4
|
+
|
|
5
|
+
.rt-side-menu-sub-item {
|
|
6
|
+
--rt-side-menu-sub-item-radius: var(--rt-radius-full);
|
|
7
|
+
--rt-side-menu-sub-item-transition-duration: var(--rt-duration-fast);
|
|
8
|
+
|
|
9
|
+
/* Маркер совпадения поиска — жёлтая подложка с тёмной подписью в обеих темах, как у первого кита. */
|
|
10
|
+
--rt-side-menu-sub-item-match-bg: var(--rt-yellow-400);
|
|
11
|
+
--rt-side-menu-sub-item-match-color: var(--rt-neutral-950);
|
|
12
|
+
--rt-side-menu-sub-item-match-radius: var(--rt-radius-xs);
|
|
13
|
+
|
|
14
|
+
display: block;
|
|
15
|
+
|
|
16
|
+
&__row {
|
|
17
|
+
/* Глубину вложения ставит шаблон на саму строку; здесь — значение строки верхнего уровня. */
|
|
18
|
+
--rt-side-menu-sub-item-depth: 0;
|
|
19
|
+
|
|
20
|
+
display: flex;
|
|
21
|
+
width: 100%;
|
|
22
|
+
min-height: var(--rt-control-height-md);
|
|
23
|
+
box-sizing: border-box;
|
|
24
|
+
align-items: center;
|
|
25
|
+
border: 0;
|
|
26
|
+
border-radius: var(--rt-side-menu-sub-item-radius);
|
|
27
|
+
background: transparent;
|
|
28
|
+
color: var(--rt-color-text-primary);
|
|
29
|
+
cursor: pointer;
|
|
30
|
+
font: inherit;
|
|
31
|
+
font-size: var(--rt-text-sm);
|
|
32
|
+
gap: var(--rt-space-sm);
|
|
33
|
+
padding-block: var(--rt-space-2);
|
|
34
|
+
padding-inline: calc(var(--rt-space-md) * (1 + var(--rt-side-menu-sub-item-depth))) var(--rt-space-sm);
|
|
35
|
+
text-align: start;
|
|
36
|
+
text-decoration: none;
|
|
37
|
+
transition: background-color var(--rt-side-menu-sub-item-transition-duration) ease;
|
|
38
|
+
|
|
39
|
+
&:hover,
|
|
40
|
+
&:active,
|
|
41
|
+
&--highlighted {
|
|
42
|
+
background: var(--rt-color-bg-hover);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
&:focus-visible {
|
|
46
|
+
outline: var(--rt-focus-ring-width) solid var(--rt-focus-ring-color);
|
|
47
|
+
outline-offset: calc(var(--rt-focus-ring-width) * -1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Активна строка со ссылкой; у папки активность видна по её раскрытым пунктам. */
|
|
51
|
+
&--active {
|
|
52
|
+
background: var(--rt-color-action-primary-subtle);
|
|
53
|
+
color: var(--rt-color-action-primary-on-surface);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
&__icon {
|
|
58
|
+
flex-shrink: 0;
|
|
59
|
+
color: inherit;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* Свой значок приложения: коробка держит размер значка строки и её цвет, рисунок внутри
|
|
63
|
+
занимает её целиком и красится через currentColor. */
|
|
64
|
+
&__own-icon {
|
|
65
|
+
--rt-side-menu-sub-item-own-icon-size: var(--rt-size-4);
|
|
66
|
+
|
|
67
|
+
display: inline-flex;
|
|
68
|
+
width: var(--rt-side-menu-sub-item-own-icon-size);
|
|
69
|
+
height: var(--rt-side-menu-sub-item-own-icon-size);
|
|
70
|
+
flex-shrink: 0;
|
|
71
|
+
align-items: center;
|
|
72
|
+
justify-content: center;
|
|
73
|
+
color: inherit;
|
|
74
|
+
line-height: 1;
|
|
75
|
+
|
|
76
|
+
> * {
|
|
77
|
+
max-width: 100%;
|
|
78
|
+
max-height: 100%;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* Подпись режется многоточием, полное имя — в подсказке. */
|
|
83
|
+
&__title {
|
|
84
|
+
overflow: hidden;
|
|
85
|
+
min-width: 0;
|
|
86
|
+
flex: 1 1 auto;
|
|
87
|
+
text-overflow: ellipsis;
|
|
88
|
+
white-space: nowrap;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
&__part {
|
|
92
|
+
color: inherit;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
&__match {
|
|
96
|
+
border-radius: var(--rt-side-menu-sub-item-match-radius);
|
|
97
|
+
background: var(--rt-side-menu-sub-item-match-bg);
|
|
98
|
+
color: var(--rt-side-menu-sub-item-match-color);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* Кнопка потребителя — круг, как у первого кита: рамка круга прозрачна в покое и
|
|
102
|
+
проявляется под указателем. Рамка — обводкой, а не границей: граница раздвинула бы
|
|
103
|
+
кнопку, и «+» ушёл бы со столбца шевронов. */
|
|
104
|
+
&__action {
|
|
105
|
+
--rt-side-menu-sub-item-action-ring-width: var(--rt-border-width-thin);
|
|
106
|
+
--rt-side-menu-sub-item-action-radius: var(--rt-radius-full);
|
|
107
|
+
|
|
108
|
+
flex-shrink: 0;
|
|
109
|
+
border-radius: var(--rt-side-menu-sub-item-action-radius);
|
|
110
|
+
outline: var(--rt-side-menu-sub-item-action-ring-width) solid transparent;
|
|
111
|
+
outline-offset: calc(var(--rt-side-menu-sub-item-action-ring-width) * -1);
|
|
112
|
+
|
|
113
|
+
&:hover {
|
|
114
|
+
outline-color: var(--rt-color-border-strong);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* Кнопка избранного: звезда у пункта раздела и «убрать» у строки блока. Закрашенная звезда
|
|
119
|
+
видна всегда — выбранное читается с одного взгляда; остальные — под наведением и фокусом
|
|
120
|
+
клавиатуры своей строки, а где указатель не умеет наводиться, — всегда. Прячется
|
|
121
|
+
прозрачностью: кнопка остаётся на месте и в порядке Tab. */
|
|
122
|
+
&__favorite {
|
|
123
|
+
flex-shrink: 0;
|
|
124
|
+
opacity: 0;
|
|
125
|
+
|
|
126
|
+
&--on {
|
|
127
|
+
--rt-icon-button-color: var(--rt-color-action-primary);
|
|
128
|
+
|
|
129
|
+
opacity: 1;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* Корзина под указателем и под фокусом клавиатуры краснеет: нажатие убирает пункт. */
|
|
133
|
+
@media (hover: hover) {
|
|
134
|
+
&--remove:hover {
|
|
135
|
+
--rt-icon-button-color: var(--rt-color-state-danger);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
&--remove:has(:focus-visible) {
|
|
140
|
+
--rt-icon-button-color: var(--rt-color-state-danger);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
@media (hover: none) {
|
|
144
|
+
opacity: 1;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
&__row:hover &__favorite,
|
|
149
|
+
&__row:focus-visible &__favorite,
|
|
150
|
+
&__row:has(:focus-visible) &__favorite {
|
|
151
|
+
opacity: 1;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/* Папка — раскрывающаяся панель кита в простом виде. Её заголовок оформлен как строка со
|
|
155
|
+
ссылкой: те же высота, скругление, отступ глубины и подсветка ходьбы стрелками; шеврон
|
|
156
|
+
панели стоит в столбце кнопок строк, и «+» соседних строк с ним на одной вертикали.
|
|
157
|
+
Свойства переназначены правилом двух классов: так они сильнее значений самой панели,
|
|
158
|
+
объявленных на том же узле, а вложенная папка объявляет свои заново. */
|
|
159
|
+
&__folder.rt-expansion-panel {
|
|
160
|
+
--rt-expansion-panel-duration: var(--rt-side-menu-sub-item-transition-duration);
|
|
161
|
+
--rt-expansion-panel-header-radius: var(--rt-side-menu-sub-item-radius);
|
|
162
|
+
--rt-expansion-panel-header-min-height: var(--rt-control-height-md);
|
|
163
|
+
--rt-expansion-panel-header-padding-block: var(--rt-space-2);
|
|
164
|
+
--rt-expansion-panel-header-padding-start: calc(var(--rt-space-md) * (1 + var(--rt-side-menu-sub-item-depth)));
|
|
165
|
+
--rt-expansion-panel-header-padding-end: var(--rt-space-sm);
|
|
166
|
+
--rt-expansion-panel-header-gap: var(--rt-space-sm);
|
|
167
|
+
--rt-expansion-panel-header-font-size: var(--rt-text-sm);
|
|
168
|
+
--rt-expansion-panel-header-bg: transparent;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
&__folder--highlighted.rt-expansion-panel {
|
|
172
|
+
--rt-expansion-panel-header-bg: var(--rt-color-bg-hover);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
&__children {
|
|
176
|
+
display: flex;
|
|
177
|
+
flex-direction: column;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/* Меню с `favoriteActionsReserve="none"`: кнопка избранного, ждущая наведения, в покое не
|
|
182
|
+
занимает ширины, и подпись идёт до края или до кнопки потребителя; отступ ряда перед ней
|
|
183
|
+
снимается тоже. Закрашенная звезда и экран без наведения держат место: там кнопка видна
|
|
184
|
+
всегда. Сжата, а не снята с раскладки: остаётся в порядке Tab. */
|
|
185
|
+
@media (hover: hover) {
|
|
186
|
+
.rt-side-menu--favorite-actions-none .rt-side-menu-sub-item__favorite:not(.rt-side-menu-sub-item__favorite--on) {
|
|
187
|
+
overflow: hidden;
|
|
188
|
+
width: 0;
|
|
189
|
+
margin-inline-start: calc(var(--rt-space-sm) * -1);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/* Возврат места — прямым правилом, а не отрицанием в правиле выше: `:hover` внутри
|
|
193
|
+
`:not()` рядом с `:has()` браузер при наведении не пересчитывал, и кнопка оставалась
|
|
194
|
+
без ширины под указателем. */
|
|
195
|
+
.rt-side-menu--favorite-actions-none .rt-side-menu-sub-item__row:hover .rt-side-menu-sub-item__favorite,
|
|
196
|
+
.rt-side-menu--favorite-actions-none .rt-side-menu-sub-item__row:focus-visible .rt-side-menu-sub-item__favorite,
|
|
197
|
+
.rt-side-menu--favorite-actions-none .rt-side-menu-sub-item__row:has(:focus-visible) .rt-side-menu-sub-item__favorite {
|
|
198
|
+
overflow: visible;
|
|
199
|
+
width: auto;
|
|
200
|
+
margin-inline-start: 0;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
@@ -85,6 +85,12 @@
|
|
|
85
85
|
колонки**: заголовки живут в шаблонах ячеек CDK, куда карточка не дотягивается. Осмысленные
|
|
86
86
|
подписи даёт `columnsConfig`.
|
|
87
87
|
|
|
88
|
+
**Карточка открывает запись так же, как строка.** Нажатие, Enter и пробел на карточке передаются
|
|
89
|
+
спрятанной строке с тем же номером, и срабатывает её `(activated)` от `rtTableRow`: приложению не
|
|
90
|
+
нужен второй обработчик. Нажатие по кнопке, ссылке, полю, `role="button"` или `role="switch"`
|
|
91
|
+
внутри карточки открытием не считается. Карточка отзывается и берёт фокус клавишей Tab только при
|
|
92
|
+
`clickable`.
|
|
93
|
+
|
|
88
94
|
**Настройка колонок требует и `columnsConfig`, и `tableId`.** Выбор хранится в IndexedDB, и без
|
|
89
95
|
идентификатора таблицы его некуда положить — поэтому `canConfigure()` останется `false`.
|
|
90
96
|
|
|
@@ -164,9 +164,11 @@
|
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
/* Строки-ссылки: курсор + focus-ring. Активацию (click/Enter/Space) и
|
|
167
|
-
table-семантику обеспечивает директива rtTableRow на самой строке.
|
|
167
|
+
table-семантику обеспечивает директива rtTableRow на самой строке.
|
|
168
|
+
Карточка узкого экрана открывает запись так же, как строка: вид у неё тот же. */
|
|
168
169
|
&--clickable {
|
|
169
|
-
.cdk-row
|
|
170
|
+
.cdk-row,
|
|
171
|
+
.rt-table__card {
|
|
170
172
|
cursor: pointer;
|
|
171
173
|
|
|
172
174
|
&:focus-visible {
|
|
@@ -5,10 +5,11 @@
|
|
|
5
5
|
<rt-icon-button icon="ico-trash" ariaLabel="Удалить" tooltip="Удалить" />
|
|
6
6
|
```
|
|
7
7
|
|
|
8
|
-
| вход
|
|
9
|
-
|
|
|
10
|
-
| `rtTooltip`
|
|
11
|
-
| `rtTooltipPlacement`
|
|
8
|
+
| вход | тип | умолчание |
|
|
9
|
+
| ------------------------ | ----------------------------- | ----------------------------------------------- |
|
|
10
|
+
| `rtTooltip` | `string \| null \| undefined` | `''` |
|
|
11
|
+
| `rtTooltipPlacement` | `'top' \| 'bottom' \| null` | `null` — сверху, под материальным набором снизу |
|
|
12
|
+
| `rtTooltipWhenTruncated` | `boolean` | `false` — подсказка только у обрезанного текста |
|
|
12
13
|
|
|
13
14
|
Выходов нет. Панель — `rt-tooltip` в оверлее CDK, `role="tooltip"`.
|
|
14
15
|
|
|
@@ -26,6 +27,8 @@ no-op, а не пустая панель под курсором. Поэтому
|
|
|
26
27
|
|
|
27
28
|
- Показывают и наведение, и фокус с клавиатуры; прячут уход курсора, потеря фокуса и **клик**
|
|
28
29
|
(панель мешала бы смотреть на результат нажатия).
|
|
30
|
+
- Фокус, поставленный мышью или кодом, подсказку не показывает: меню возвращает фокус кнопке после
|
|
31
|
+
выбора пункта, и подсказка кнопки всплывала бы поверх того, что пункт открыл.
|
|
29
32
|
- `rt-icon-button` уже несёт эту директиву — там достаточно входа `tooltip`.
|
|
30
33
|
- Подсказка не заменяет `aria-label`: она вспомогательная, а имя контрола задаётся отдельно.
|
|
31
34
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
@use 'sass:map';
|
|
2
|
+
@use 'sass:list';
|
|
3
|
+
@use 'sass:meta';
|
|
4
|
+
|
|
5
|
+
/* A colour scheme — the brand ramp under its own name, switched on by `data-rt-scheme` on `<html>`,
|
|
6
|
+
as in the first kit.
|
|
7
|
+
|
|
8
|
+
The scheme rewrites the steps, not the assignments: the accent of the own set derives from
|
|
9
|
+
`--rt-brand-*`, the accent of the material set from `--rt-mat-blue-100`, and the dark theme refers to
|
|
10
|
+
the same steps. So one ramp repaints every look the kit is drawn in, and the names the components
|
|
11
|
+
read stay untouched.
|
|
12
|
+
|
|
13
|
+
The scheme answers on the root only. A value referring to a step is resolved where it is declared,
|
|
14
|
+
and the assignments are declared on the root: a scheme on an inner node would change the steps under
|
|
15
|
+
assignments already resolved, and the piece would keep the old accent.
|
|
16
|
+
|
|
17
|
+
A Material theme of the application wins over the scheme in the material set: its `--mat-sys-primary`
|
|
18
|
+
stands in front of the step in that set's assignments.
|
|
19
|
+
|
|
20
|
+
Usage:
|
|
21
|
+
@use '@rt-tools/ui-kit-v2/styles/color-scheme' as rt;
|
|
22
|
+
@include rt.rt-color-scheme('teal', (50: #e6f4f3, …, 500: #008582, …, 950: #00201f));
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
$brand-steps: (50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950);
|
|
26
|
+
|
|
27
|
+
@mixin rt-color-scheme($name, $ramp) {
|
|
28
|
+
@if meta.type-of($name) != 'string' {
|
|
29
|
+
@error 'rt-color-scheme: the name must be a string, got #{meta.type-of($name)}.';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@if meta.type-of($ramp) != 'map' or not map.has-key($ramp, 500) {
|
|
33
|
+
@error 'rt-color-scheme("#{$name}"): the ramp is a map of (step: colour) and holds at least the step 500 — the brand colour.';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@each $step, $value in $ramp {
|
|
37
|
+
@if not list.index($brand-steps, $step) {
|
|
38
|
+
@error 'rt-color-scheme("#{$name}"): unknown step #{$step}. Allowed: #{$brand-steps}.';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* `:root[…]` (0,2,0) outranks the steps on `:root` (0,1,0) whatever the order of the sources. */
|
|
43
|
+
:root[data-rt-scheme='#{$name}'] {
|
|
44
|
+
@each $step, $value in $ramp {
|
|
45
|
+
--rt-brand-#{$step}: #{$value};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
--rt-mat-blue-100: #{map.get($ramp, 500)};
|
|
49
|
+
}
|
|
50
|
+
}
|