@rt-tools/ui-kit-v2 0.14.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-rich-editor.mjs +49 -7
- package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2.mjs +5885 -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/rich-editor/lib/components/message-composer/CONTEXT.md +15 -1
- package/src/styles/_color-scheme.scss +50 -0
- package/types/rt-tools-ui-kit-v2-rich-editor.d.ts +22 -2
- package/types/rt-tools-ui-kit-v2.d.ts +1236 -13
- package/rt-tools-ui-kit-v2-0.14.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
|
|
|
@@ -18,13 +18,15 @@
|
|
|
18
18
|
| `attachments` | `boolean` | `false` |
|
|
19
19
|
| `accept` | `string` | `''` |
|
|
20
20
|
| `sending` / `disabled` | `boolean` | `false` |
|
|
21
|
+
| `stoppable` | `boolean` | `false` |
|
|
22
|
+
| `text` (model) | `string` | `''` |
|
|
21
23
|
| `formatting` | `boolean` | `false` |
|
|
22
24
|
| `hint` | `boolean` | `false` |
|
|
23
25
|
| `toolbar` | `TRtRichEditorToolbar` | `'full'` |
|
|
24
26
|
| `minRows` / `maxRows` | `number` | 1 / 6 |
|
|
25
27
|
| `droppedFiles` | `File[] \| null` | `null` |
|
|
26
28
|
|
|
27
|
-
|
|
29
|
+
Выходы: `submitted` — `{ text, delta?, files }`; `stopped` — клик по «Стоп». Метод: `focus()`.
|
|
28
30
|
|
|
29
31
|
## Главное, что нужно знать
|
|
30
32
|
|
|
@@ -32,6 +34,18 @@
|
|
|
32
34
|
вложенный файл разблокирует отправку и без текста. Во время `sending` поле и кнопка заблокированы —
|
|
33
35
|
иначе второе сообщение ушло бы поверх ещё не доставленного.
|
|
34
36
|
|
|
37
|
+
**`stoppable` меняет смысл `sending` только для того, кто его включил.** При обоих флагах стрелку
|
|
38
|
+
сменяет «Стоп», форма не блокируется, а `submit` отказывает по `canSend`, не трогая черновик:
|
|
39
|
+
следующий вопрос набирается, пока идёт ответ. `rt-chat` и прочие потребители без флага получают
|
|
40
|
+
прежнюю блокировку.
|
|
41
|
+
|
|
42
|
+
**`text` — модель черновика, а не CVA.** У композера своя форма с файлами; потребителю нужно задать,
|
|
43
|
+
прочитать и очистить текст, а не встроить поле в чужую форму. Синхронизация двусторонняя: эффект
|
|
44
|
+
пишет модель в контрол, `valueChanges` контрола — в модель; сброс после отправки обнуляет обе.
|
|
45
|
+
|
|
46
|
+
**`focus()` в режиме форматирования идёт через `RtRichEditorComponent.focus`.** Узел Quill появляется
|
|
47
|
+
после динамического импорта; до него вызов ничего не делает.
|
|
48
|
+
|
|
35
49
|
**Enter отправляет, Shift+Enter переносит строку.** Набор во время IME-композиции игнорируется.
|
|
36
50
|
|
|
37
51
|
**`droppedFiles` — вход, а не выход.** Файлы, брошенные в область
|