@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.
- package/README.md +7 -0
- package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs +96 -41
- package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs.map +1 -1
- package/fesm2022/rt-tools-ui-kit-v2.mjs +6824 -2700
- package/fesm2022/rt-tools-ui-kit-v2.mjs.map +1 -1
- package/package.json +1 -1
- package/rt-tools-ui-kit-v2-0.17.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/action-bar/CONTEXT.md +5 -0
- package/src/lib/components/action-bar/rt-action-bar.component.scss +30 -16
- package/src/lib/components/aside/CONTEXT.md +18 -1
- package/src/lib/components/aside/error-box/rt-aside-error-box.component.scss +37 -0
- package/src/lib/components/aside/footer/rt-aside-footer.component.scss +7 -8
- package/src/lib/components/aside/header/rt-aside-header.component.scss +16 -1
- package/src/lib/components/aside/rt-aside.component.scss +31 -3
- package/src/lib/components/button/CONTEXT.md +12 -11
- package/src/lib/components/button/rt-button.directive.scss +36 -0
- package/src/lib/components/data-list/settings/rt-data-list-settings-aside.component.scss +2 -2
- package/src/lib/components/data-table/cell/rt-data-table-cell.component.scss +1 -1
- package/src/lib/components/data-table/filter-cell/rt-data-table-filter-cell.component.scss +1 -1
- package/src/lib/components/data-table/rt-data-table.component.scss +1 -1
- package/src/lib/components/dialog/CONTEXT.md +9 -0
- package/src/lib/components/dialog/content/rt-dialog-content.component.scss +20 -0
- package/src/lib/components/dialog/footer/rt-dialog-footer.component.scss +18 -2
- package/src/lib/components/dialog/header/rt-dialog-header.component.scss +21 -3
- package/src/lib/components/dialog/rt-dialog.component.scss +9 -3
- package/src/lib/components/dynamic-selector/CONTEXT.md +50 -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/header/CONTEXT.md +2 -2
- package/src/lib/components/icon/CONTEXT.md +11 -7
- package/src/lib/components/icon/rt-icon.component.scss +47 -0
- package/src/lib/components/icon-button/CONTEXT.md +27 -20
- package/src/lib/components/icon-button/rt-icon-button.component.scss +51 -25
- 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 +70 -0
- package/src/lib/components/image-upload/rt-image-upload.component.scss +89 -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/pagination/rt-pagination.component.scss +1 -1
- package/src/lib/components/scroll-area/CONTEXT.md +2 -0
- package/src/lib/components/scroll-area/rt-scroll-area.component.scss +20 -3
- package/src/lib/components/side-menu/CONTEXT.md +43 -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/spinner/CONTEXT.md +15 -8
- package/src/lib/components/spinner/rt-spinner.component.scss +108 -9
- package/src/lib/components/table/CONTEXT.md +6 -0
- package/src/lib/components/table/rt-table.component.scss +4 -2
- package/src/lib/components/tag/rt-tag.component.scss +43 -23
- package/src/lib/components/toast/CONTEXT.md +8 -0
- package/src/lib/components/toast/rt-toast.component.scss +74 -15
- package/src/lib/components/toast/rt-toaster.component.scss +5 -1
- package/src/lib/components/toggle-button-group/rt-toggle-button-group.component.scss +35 -37
- package/src/lib/components/toggle-switch/CONTEXT.md +11 -3
- package/src/lib/components/toggle-switch/rt-toggle-switch.component.scss +53 -14
- package/src/lib/components/toolbar/rt-toolbar.component.scss +15 -4
- package/src/lib/components/tooltip/CONTEXT.md +7 -4
- package/src/rich-editor/lib/components/chat/CONTEXT.md +7 -2
- package/src/rich-editor/lib/components/chat/rt-chat.component.scss +25 -0
- package/src/styles/_color-scheme.scss +50 -0
- package/styles/tokens.css +35 -0
- package/types/rt-tools-ui-kit-v2-rich-editor.d.ts +16 -20
- package/types/rt-tools-ui-kit-v2.d.ts +1588 -58
- package/rt-tools-ui-kit-v2-0.15.0.tgz +0 -0
|
@@ -20,6 +20,10 @@
|
|
|
20
20
|
|
|
21
21
|
/* Ритм между корневыми блоками содержимого. */
|
|
22
22
|
--rt-aside-content-gap: var(--rt-space-md);
|
|
23
|
+
|
|
24
|
+
/* Ширина на узком экране: во всё окно. Свойство, а не число в правиле, — чтобы коробка,
|
|
25
|
+
в которую панель поставлена разметкой, могла сдержать её своей шириной. */
|
|
26
|
+
--rt-aside-narrow-width: 100dvw;
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
/* Хост адресуется по имени элемента, а не по классу блока: класс `.rt-aside`
|
|
@@ -31,6 +35,9 @@
|
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
rt-aside .rt-aside {
|
|
38
|
+
/* Точка отсчёта для слоя ожидания. Рамка и так занимает панель целиком, поэтому прочим
|
|
39
|
+
потомкам она ничего не меняет. */
|
|
40
|
+
position: relative;
|
|
34
41
|
display: flex;
|
|
35
42
|
width: var(--rt-aside-width, var(--rt-aside-width-md));
|
|
36
43
|
|
|
@@ -66,6 +73,15 @@
|
|
|
66
73
|
flex-shrink: 0;
|
|
67
74
|
}
|
|
68
75
|
|
|
76
|
+
/* Блок ошибки запроса стоит между шапкой и содержимым и не уезжает с прокруткой. Поля
|
|
77
|
+
по бокам — тот же инсет панели; сверху и снизу его отбивают шапка и зона содержимого. */
|
|
78
|
+
&__error {
|
|
79
|
+
min-width: 0;
|
|
80
|
+
flex-shrink: 0;
|
|
81
|
+
margin-block: var(--rt-aside-error-margin-block, 0);
|
|
82
|
+
padding-inline: var(--rt-aside-inset);
|
|
83
|
+
}
|
|
84
|
+
|
|
69
85
|
/* Единственная зона содержимого: она держит инсет панели и она же
|
|
70
86
|
прокручивается. Отступы живут здесь, а не в потребителях — иначе каждая
|
|
71
87
|
панель помнит про них сама, и поля получают разную ширину. */
|
|
@@ -75,12 +91,24 @@
|
|
|
75
91
|
min-height: 0;
|
|
76
92
|
flex: 1 1 auto;
|
|
77
93
|
flex-direction: column;
|
|
78
|
-
padding: var(--rt-aside-inset);
|
|
94
|
+
padding: var(--rt-aside-content-inset, var(--rt-aside-inset));
|
|
79
95
|
gap: var(--rt-aside-content-gap);
|
|
80
96
|
overflow-y: auto;
|
|
81
97
|
overscroll-behavior: contain;
|
|
82
98
|
}
|
|
83
99
|
|
|
100
|
+
/* Слой ожидания поверх всей панели: шапка, содержимое и футер под ним не нажимаются. Тот же
|
|
101
|
+
вид, что у слоя дозагрузки таблицы. */
|
|
102
|
+
&__pending {
|
|
103
|
+
position: absolute;
|
|
104
|
+
z-index: var(--rt-z-sticky);
|
|
105
|
+
display: flex;
|
|
106
|
+
align-items: center;
|
|
107
|
+
justify-content: center;
|
|
108
|
+
background-color: color-mix(in srgb, var(--rt-color-bg-surface) 60%, transparent);
|
|
109
|
+
inset: 0;
|
|
110
|
+
}
|
|
111
|
+
|
|
84
112
|
&--size--sm {
|
|
85
113
|
width: var(--rt-aside-width, var(--rt-aside-width-sm));
|
|
86
114
|
}
|
|
@@ -132,8 +160,8 @@
|
|
|
132
160
|
rt-aside .rt-aside--size--sm,
|
|
133
161
|
rt-aside .rt-aside--size--md,
|
|
134
162
|
rt-aside .rt-aside--size--lg {
|
|
135
|
-
width:
|
|
136
|
-
max-width:
|
|
163
|
+
width: var(--rt-aside-narrow-width);
|
|
164
|
+
max-width: var(--rt-aside-narrow-width);
|
|
137
165
|
}
|
|
138
166
|
}
|
|
139
167
|
}
|
|
@@ -10,17 +10,18 @@
|
|
|
10
10
|
<a rtButton label="На главную" [routerLink]="'/'"></a>
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
| вход
|
|
14
|
-
|
|
|
15
|
-
| `label`
|
|
16
|
-
| `icon`
|
|
17
|
-
| `iconPos`
|
|
18
|
-
| `theme`
|
|
19
|
-
| `appearance`
|
|
20
|
-
| `size`
|
|
21
|
-
| `radius`
|
|
22
|
-
| `loading`
|
|
23
|
-
| `loadingIcon`
|
|
13
|
+
| вход | тип | умолчание |
|
|
14
|
+
| -------------- | -------------------------------------------------------------------------- | ---------------------------------- |
|
|
15
|
+
| `label` | `string \| null` | `null` |
|
|
16
|
+
| `icon` | `string \| null` (имя из набора `rt-icon`) | `null` |
|
|
17
|
+
| `iconPos` | `'left' \| 'right'` | `'left'` |
|
|
18
|
+
| `theme` | `'primary' \| 'secondary' \| 'success' \| 'warning' \| 'danger' \| 'info'` | `'primary'` |
|
|
19
|
+
| `appearance` | `'filled' \| 'outlined' \| 'text'` | настройки кита или `'filled'` |
|
|
20
|
+
| `size` | `'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl'` (30 / 40 / 50 / 60 / 70 px) | настройки кита или `'md'` |
|
|
21
|
+
| `radius` | `TRtRadius \| null` — шаг общей шкалы | настройки кита или `null` |
|
|
22
|
+
| `loading` | `boolean` | `false` |
|
|
23
|
+
| `loadingIcon` | `string \| null` | `null` → встроенное кольцо |
|
|
24
|
+
| `loadingLabel` | `'keep' \| 'hide'` | `'keep'` — кольцо рядом с подписью |
|
|
24
25
|
|
|
25
26
|
Своего выхода нет — клик слушается нативным `(click)` на самом элементе.
|
|
26
27
|
|
|
@@ -91,6 +91,25 @@
|
|
|
91
91
|
font-size: var(--rt-btn-icon-size);
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
/* Лигатура шрифта Material Symbols для имени без пары — размер ей даёт `__icon` рядом.
|
|
95
|
+
Шрифт подключает приложение, семью можно переназначить свойством сверху. До готовности
|
|
96
|
+
шрифтов лигатура скрыта: иначе на её месте видно слово. */
|
|
97
|
+
&__glyph {
|
|
98
|
+
overflow: hidden;
|
|
99
|
+
font-family: var(--rt-icon-glyph-font, 'Material Symbols Outlined'), sans-serif;
|
|
100
|
+
font-feature-settings: 'liga';
|
|
101
|
+
font-style: normal;
|
|
102
|
+
font-weight: var(--rt-font-weight-regular);
|
|
103
|
+
letter-spacing: normal;
|
|
104
|
+
line-height: 1;
|
|
105
|
+
text-transform: none;
|
|
106
|
+
white-space: nowrap;
|
|
107
|
+
|
|
108
|
+
&--pending {
|
|
109
|
+
visibility: hidden;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
94
113
|
&__label {
|
|
95
114
|
display: inline-flex;
|
|
96
115
|
align-items: center;
|
|
@@ -264,6 +283,23 @@
|
|
|
264
283
|
pointer-events: none;
|
|
265
284
|
}
|
|
266
285
|
|
|
286
|
+
/* Подпись спрятана на время загрузки: содержимое гаснет прозрачностью, а не
|
|
287
|
+
`visibility` — так оно держит ширину и остаётся именем кнопки для скринридера.
|
|
288
|
+
Загрузчик встаёт поверх по центру. */
|
|
289
|
+
&--loading-label-hidden {
|
|
290
|
+
position: relative;
|
|
291
|
+
|
|
292
|
+
> :not(.rt-button__loader) {
|
|
293
|
+
opacity: 0;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
&__loader {
|
|
298
|
+
position: absolute;
|
|
299
|
+
margin: auto;
|
|
300
|
+
inset: 0;
|
|
301
|
+
}
|
|
302
|
+
|
|
267
303
|
/* Состояние стоит ниже всех вариантов оформления и палитры того же блока.
|
|
268
304
|
Специфичность у них равная, и правила равной силы разбираются порядком в
|
|
269
305
|
файле: отсюда, снизу, отключённость отменяет и заливку, и цвет подписи.
|
|
@@ -145,7 +145,7 @@
|
|
|
145
145
|
|
|
146
146
|
/* Кнопка «назад» — круглая `mat-icon-button` первого кита, как и кнопки подвала панели. */
|
|
147
147
|
.rt-aside-header__back .rt-icon-button {
|
|
148
|
-
--rt-icon-button-size: var(--rt-data-list-settings-aside-control-size);
|
|
148
|
+
--rt-icon-button-size-step: var(--rt-data-list-settings-aside-control-size);
|
|
149
149
|
--rt-icon-button-color: var(--rt-list-settings-icon-color);
|
|
150
150
|
--rt-icon-button-radius: var(--rt-radius-full);
|
|
151
151
|
}
|
|
@@ -236,7 +236,7 @@
|
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
.rt-data-list-settings-aside__toggle .rt-icon-button {
|
|
239
|
-
--rt-icon-button-size: var(--rt-data-list-settings-aside-control-size);
|
|
239
|
+
--rt-icon-button-size-step: var(--rt-data-list-settings-aside-control-size);
|
|
240
240
|
--rt-icon-button-color: var(--rt-list-settings-icon-color);
|
|
241
241
|
}
|
|
242
242
|
}
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
--rt-icon-button-color: var(--rt-list-copy-button-color);
|
|
88
88
|
|
|
89
89
|
.rt-icon-button {
|
|
90
|
-
--rt-icon-button-size: var(--rt-list-copy-button-size);
|
|
90
|
+
--rt-icon-button-size-step: var(--rt-list-copy-button-size);
|
|
91
91
|
--rt-icon-button-radius: var(--rt-list-copy-button-radius);
|
|
92
92
|
--rt-icon-button-color-hover: var(--rt-color-text-primary);
|
|
93
93
|
--rt-icon-button-color-bg-hover: var(--rt-list-copy-button-bg-hover);
|
|
@@ -44,6 +44,15 @@ ref.afterClosed().subscribe((ok?: boolean): void => …);
|
|
|
44
44
|
`RtDialogRef.disableClose` держит окно и под кликом по подложке, и под Escape — ставится самим
|
|
45
45
|
содержимым, когда закрывать нельзя.
|
|
46
46
|
|
|
47
|
+
**Фокус служба по умолчанию не трогает.** `trapFocus`, `restoreFocus` и `autoFocus` в настройке
|
|
48
|
+
открытия включают ловушку CDK, возврат фокуса и первый фокус (`'dialog'` — на рамку,
|
|
49
|
+
`'first-tabbable'` — на первый элемент под Tab). Ловушка и первый фокус ставятся после отрисовки
|
|
50
|
+
окна, ловушка уходит вместе с оверлеем.
|
|
51
|
+
|
|
52
|
+
**Части окна.** `rt-dialog-content` — тело с отступом и прокруткой; `rtDialogHeaderLead` — узел
|
|
53
|
+
перед заголовком шапки; `align` подвала — `start`, `center`, `end` (по умолчанию) или `between`.
|
|
54
|
+
Вид окна задают ручки `--rt-dialog-*` на корне страницы, перечень — на странице Theming.
|
|
55
|
+
|
|
47
56
|
**Крестик в шапке ищет `RtDialogRef` необязательным инжектом.** Поэтому `rt-dialog-header` можно
|
|
48
57
|
поставить и вне диалога — нажатие просто ничего не сделает, а не упадёт.
|
|
49
58
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
@layer rt-kit.components {
|
|
2
|
+
/* rt-dialog-content — тело модалки. ViewEncapsulation.None.
|
|
3
|
+
Хост адресуется по имени элемента, как у шапки и подвала: класс блока висит и на хосте, и на
|
|
4
|
+
узле внутри. Хост боксом не становится — тело должно быть прямым flex-ребёнком рамки, чтобы
|
|
5
|
+
сжиматься между шапкой и подвалом и прокручиваться само.
|
|
6
|
+
|
|
7
|
+
Свойства читаются с запасным значением на месте: окно живёт в оверлее, вне блоков
|
|
8
|
+
приложения, и приложение задаёт их на корне страницы. */
|
|
9
|
+
rt-dialog-content {
|
|
10
|
+
display: contents;
|
|
11
|
+
|
|
12
|
+
.rt-dialog-content {
|
|
13
|
+
overflow: auto;
|
|
14
|
+
min-height: 0;
|
|
15
|
+
max-height: var(--rt-dialog-content-max-height, none);
|
|
16
|
+
flex: 1 1 auto;
|
|
17
|
+
padding: var(--rt-dialog-content-padding, var(--rt-space-lg));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -11,13 +11,29 @@
|
|
|
11
11
|
rt-dialog-footer {
|
|
12
12
|
display: contents;
|
|
13
13
|
|
|
14
|
+
/* Свойства читаются с запасным значением на месте — окно живёт в оверлее. Разделитель
|
|
15
|
+
кита лежит в частном `-default`, как у шапки. */
|
|
14
16
|
.rt-dialog-footer {
|
|
17
|
+
--rt-dialog-footer-border-default: var(--rt-border-width-thin) solid var(--rt-color-border-subtle);
|
|
18
|
+
|
|
15
19
|
display: flex;
|
|
16
20
|
justify-content: flex-end;
|
|
17
|
-
padding: var(--rt-space-lg);
|
|
18
|
-
border-block-start:
|
|
21
|
+
padding: var(--rt-dialog-footer-padding, var(--rt-space-lg));
|
|
22
|
+
border-block-start: var(--rt-dialog-footer-border, var(--rt-dialog-footer-border-default));
|
|
19
23
|
gap: var(--rt-space-sm);
|
|
20
24
|
|
|
25
|
+
&--align--start {
|
|
26
|
+
justify-content: flex-start;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&--align--center {
|
|
30
|
+
justify-content: center;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
&--align--between {
|
|
34
|
+
justify-content: space-between;
|
|
35
|
+
}
|
|
36
|
+
|
|
21
37
|
&:empty {
|
|
22
38
|
display: none;
|
|
23
39
|
}
|
|
@@ -13,18 +13,36 @@
|
|
|
13
13
|
rt-dialog-header {
|
|
14
14
|
display: contents;
|
|
15
15
|
|
|
16
|
+
/* Свойства читаются с запасным значением на месте: окно живёт в оверлее, и приложение
|
|
17
|
+
задаёт их на корне страницы. Разделитель кита лежит в частном `-default` — проверка
|
|
18
|
+
токенов не пускает шаг толщины рамки запасным значением напрямую. */
|
|
16
19
|
.rt-dialog-header {
|
|
20
|
+
--rt-dialog-header-border-default: var(--rt-border-width-thin) solid var(--rt-color-border-subtle);
|
|
21
|
+
|
|
17
22
|
display: flex;
|
|
18
23
|
align-items: center;
|
|
19
24
|
justify-content: space-between;
|
|
20
|
-
padding: var(--rt-space-lg);
|
|
21
|
-
border-block-end:
|
|
25
|
+
padding: var(--rt-dialog-header-padding, var(--rt-space-lg));
|
|
26
|
+
border-block-end: var(--rt-dialog-header-border, var(--rt-dialog-header-border-default));
|
|
22
27
|
gap: var(--rt-space-sm);
|
|
23
28
|
|
|
29
|
+
/* Место перед заголовком: пустое ничего не занимает и не добавляет промежутка. */
|
|
30
|
+
&__lead {
|
|
31
|
+
display: inline-flex;
|
|
32
|
+
flex-shrink: 0;
|
|
33
|
+
align-items: center;
|
|
34
|
+
|
|
35
|
+
&:empty {
|
|
36
|
+
display: none;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
24
40
|
&__title {
|
|
25
41
|
margin: 0;
|
|
26
42
|
color: var(--rt-color-text-primary);
|
|
27
|
-
font-size: var(--rt-text-xl);
|
|
43
|
+
font-size: var(--rt-dialog-title-font-size, var(--rt-text-xl));
|
|
44
|
+
font-weight: var(--rt-dialog-title-weight, var(--rt-font-weight-bold));
|
|
45
|
+
text-transform: var(--rt-dialog-title-transform, none);
|
|
28
46
|
}
|
|
29
47
|
|
|
30
48
|
&__close {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
@layer rt-kit.components {
|
|
4
4
|
/* rt-dialog — styled frame модалки поверх CDK Overlay.
|
|
5
5
|
ViewEncapsulation.None — селекторы префиксованы `.rt-dialog`.
|
|
6
|
-
Видимость
|
|
6
|
+
Видимость и подложку даёт CDK Overlay, ловушку и первый фокус — RtDialogService по флагам. */
|
|
7
7
|
|
|
8
8
|
/* Хост адресуется по имени элемента, а не по классу блока: класс `.rt-dialog`
|
|
9
9
|
висит и на `<rt-dialog>`, и на рамке внутри него, поэтому правила рамки
|
|
@@ -37,12 +37,18 @@
|
|
|
37
37
|
max-height: 90dvh;
|
|
38
38
|
flex-direction: column;
|
|
39
39
|
padding: 0;
|
|
40
|
-
border: none;
|
|
40
|
+
border: var(--rt-dialog-border, none);
|
|
41
41
|
border-radius: var(--rt-dialog-radius);
|
|
42
|
-
background: var(--rt-color-bg-surface);
|
|
42
|
+
background: var(--rt-dialog-bg, var(--rt-color-bg-surface));
|
|
43
43
|
box-shadow: var(--rt-dialog-shadow);
|
|
44
44
|
color: var(--rt-color-text-primary);
|
|
45
45
|
|
|
46
|
+
/* Рамку фокус берёт только по `autoFocus: 'dialog'` — как точку отсчёта для скринридера,
|
|
47
|
+
а не как элемент управления: кольцо вокруг всего окна читалось бы как выбор окна. */
|
|
48
|
+
&:focus {
|
|
49
|
+
outline: none;
|
|
50
|
+
}
|
|
51
|
+
|
|
46
52
|
&--size--sm {
|
|
47
53
|
width: var(--rt-dialog-width, var(--rt-dialog-width-sm));
|
|
48
54
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# `rt-dynamic-selector` + `rt-dynamic-input`
|
|
2
|
+
|
|
3
|
+
Поле формы со списком выбранных записей и поле, в котором строки набирают вручную.
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<rt-dynamic-selector keyExp="id" displayExp="name" draggable [entities]="people()" [formControl]="team" />
|
|
7
|
+
<rt-dynamic-input editable [formControl]="emails" />
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Значение селектора — массив ключей в порядке списка, значение поля строк — массив строк.
|
|
11
|
+
|
|
12
|
+
## Главное, что нужно знать
|
|
13
|
+
|
|
14
|
+
**Записанное формой — это и список, и значение для сброса.** Сброс возвращает последнюю запись
|
|
15
|
+
формы и гаснет, пока список с ней совпадает в том же порядке. Пустой массив от формы опустошает
|
|
16
|
+
список.
|
|
17
|
+
|
|
18
|
+
**Очистка оставляет строки только для чтения.** У такой строки корзина выключена, и очистка гаснет,
|
|
19
|
+
когда в списке остались только они.
|
|
20
|
+
|
|
21
|
+
**Ключ, которого нет среди записей, остаётся в значении и строки не рисует.** Форма не теряет то,
|
|
22
|
+
чего не показала.
|
|
23
|
+
|
|
24
|
+
**Отметки всплывающего окна уходят только по «Применить».** «Отмена», `Escape` и щелчок мимо
|
|
25
|
+
снимают их, значение остаётся прежним.
|
|
26
|
+
|
|
27
|
+
**Поле строк срезает пробелы по краям и не добавляет пустое и повторное.** Повтор сравнивается
|
|
28
|
+
точно, с учётом регистра.
|
|
29
|
+
|
|
30
|
+
## Как этим пользоваться
|
|
31
|
+
|
|
32
|
+
- Серверный поиск: `[localSearch]="false"`, запрос приходит выходом `searchChange` через 500 мс
|
|
33
|
+
после последней клавиши; найденное вызывающий кладёт в `entities`.
|
|
34
|
+
- Догрузка: `lazyLoad`, выход `loadMore`; пока идёт загрузка страницы, `fetching` держит запрос.
|
|
35
|
+
- Свои кнопки у строки — `<ng-template rtDynamicSelectorRowControls let-item>`, своё название —
|
|
36
|
+
`<ng-template rtDynamicSelectorRowTitle let-item>`. Корзина и ручка перетаскивания остаются китовыми.
|
|
37
|
+
- Приглашение (`invitation`) встаёт вместо полосы кнопок; его кнопка открывает тот же выбор.
|
|
38
|
+
`listActionsShown = false` убирает сброс и очистку, оставляя кнопку добавления;
|
|
39
|
+
`removeShown = false` убирает корзину строк.
|
|
40
|
+
- Правки в своём шаблоне строки — `extraChanged`: сброс и очистка включены при прежних ключах и
|
|
41
|
+
сообщают `listReset` и `listCleared`, значение сброс тогда не трогает.
|
|
42
|
+
- Начальный запрос окна — `searchTerm`, событием поиска он не уходит. Открыто ли окно — сигнал
|
|
43
|
+
`popupOpen` и выход `popupOpenChange`.
|
|
44
|
+
|
|
45
|
+
## Рядом
|
|
46
|
+
|
|
47
|
+
- [`rt-multiselect`](../multiselect/CONTEXT.md) — выбор нескольких значений фишками в одной строке,
|
|
48
|
+
без списка, сброса и перетаскивания.
|
|
49
|
+
- [`rt-empty-state`](../empty-state/CONTEXT.md) — на нём нарисованы приглашение и «нечего выбрать».
|
|
50
|
+
- [`[rtPopover]`](../popover/CONTEXT.md) — на нём держится всплывающий выбор.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
@layer rt-kit.components {
|
|
2
|
+
/* rt-dynamic-input — поле списка строк. ViewEncapsulation.None.
|
|
3
|
+
Строки и полосу рисует список семьи; здесь — поле набора и приглашение под ним. */
|
|
4
|
+
|
|
5
|
+
.rt-dynamic-input {
|
|
6
|
+
display: flex;
|
|
7
|
+
width: 100%;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
gap: var(--rt-space-sm);
|
|
10
|
+
|
|
11
|
+
&__field {
|
|
12
|
+
display: block;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
&__invitation {
|
|
16
|
+
display: block;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
@layer rt-kit.components {
|
|
2
|
+
/* rt-dynamic-selector-list — строки выбранного и полоса действий. ViewEncapsulation.None.
|
|
3
|
+
Вид снят с кадров первого кита: строки — тонированные плашки со скруглением, у ручки
|
|
4
|
+
перетаскивания разделитель справа, корзина строки красная, пока её можно нажать. */
|
|
5
|
+
|
|
6
|
+
.rt-dynamic-selector-list {
|
|
7
|
+
--rt-dynamic-selector-list-row-bg: var(--rt-color-action-primary-subtle);
|
|
8
|
+
--rt-dynamic-selector-list-row-radius: var(--rt-radius-sm);
|
|
9
|
+
--rt-dynamic-selector-list-divider-width: var(--rt-border-width-thin);
|
|
10
|
+
--rt-dynamic-selector-list-drag-shadow: var(--rt-shadow-md);
|
|
11
|
+
--rt-dynamic-selector-list-drag-duration: var(--rt-duration-base);
|
|
12
|
+
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
gap: var(--rt-space-2xs);
|
|
16
|
+
|
|
17
|
+
&__rows {
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
gap: var(--rt-space-sm);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
&__row {
|
|
24
|
+
display: flex;
|
|
25
|
+
min-height: var(--rt-control-height-lg);
|
|
26
|
+
box-sizing: border-box;
|
|
27
|
+
align-items: center;
|
|
28
|
+
padding: var(--rt-space-2xs) var(--rt-space-2xs) var(--rt-space-2xs) var(--rt-space-sm);
|
|
29
|
+
border-radius: var(--rt-dynamic-selector-list-row-radius);
|
|
30
|
+
background: var(--rt-dynamic-selector-list-row-bg);
|
|
31
|
+
color: var(--rt-color-text-primary);
|
|
32
|
+
gap: var(--rt-space-sm);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
&__handle {
|
|
36
|
+
border-right: var(--rt-dynamic-selector-list-divider-width) solid var(--rt-color-border-default);
|
|
37
|
+
cursor: grab;
|
|
38
|
+
padding-inline-end: var(--rt-space-2xs);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Длинная подпись переносится: обрезка спрятала бы, какая запись выбрана.
|
|
42
|
+
&__title {
|
|
43
|
+
min-width: 0;
|
|
44
|
+
flex: 1 1 auto;
|
|
45
|
+
font-size: var(--rt-text-md);
|
|
46
|
+
overflow-wrap: anywhere;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
&__field {
|
|
50
|
+
min-width: 0;
|
|
51
|
+
flex: 1 1 auto;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
&__controls {
|
|
55
|
+
display: flex;
|
|
56
|
+
flex: 0 0 auto;
|
|
57
|
+
align-items: center;
|
|
58
|
+
gap: var(--rt-space-2xs);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&__actions {
|
|
62
|
+
display: flex;
|
|
63
|
+
align-items: center;
|
|
64
|
+
gap: var(--rt-space-2xs);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
&__add {
|
|
68
|
+
display: flex;
|
|
69
|
+
min-width: 0;
|
|
70
|
+
flex: 1 1 auto;
|
|
71
|
+
align-items: center;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Строка в полёте живёт у конца страницы, вне блока: свойства объявлены на ней самой.
|
|
75
|
+
&__row.cdk-drag-preview {
|
|
76
|
+
--rt-dynamic-selector-list-row-bg: var(--rt-color-action-primary-subtle);
|
|
77
|
+
--rt-dynamic-selector-list-row-radius: var(--rt-radius-sm);
|
|
78
|
+
--rt-dynamic-selector-list-divider-width: var(--rt-border-width-thin);
|
|
79
|
+
--rt-dynamic-selector-list-drag-shadow: var(--rt-shadow-md);
|
|
80
|
+
|
|
81
|
+
box-shadow: var(--rt-dynamic-selector-list-drag-shadow);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
&__row.cdk-drag-placeholder {
|
|
85
|
+
opacity: 0;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
&__row.cdk-drag-animating,
|
|
89
|
+
&__rows.cdk-drop-list-dragging &__row:not(.cdk-drag-placeholder) {
|
|
90
|
+
transition: transform var(--rt-dynamic-selector-list-drag-duration) ease-out;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* rt-layer-outside: фон, цвет и поля строки в руке.
|
|
96
|
+
|
|
97
|
+
CDK кладёт строку в руке в конец страницы и в момент перетаскивания подключает свой слой
|
|
98
|
+
`cdk-resets` с `.cdk-drag-preview { background: none; color: inherit; padding: 0 }`. Слой
|
|
99
|
+
появляется на странице позже слоя кита и потому сильнее его: оставленные в слое, три свойства
|
|
100
|
+
ниже проигрывают, и строка едет прозрачной, без полей. Тонировка строки полупрозрачна, поэтому
|
|
101
|
+
под ней лежит поверхность — в покое ту же роль играет поле, в котором стоит список. Скругление и
|
|
102
|
+
тень остаются в слое — их CDK не трогает. */
|
|
103
|
+
.rt-dynamic-selector-list__row.cdk-drag-preview {
|
|
104
|
+
padding: var(--rt-space-2xs) var(--rt-space-2xs) var(--rt-space-2xs) var(--rt-space-sm);
|
|
105
|
+
background-color: var(--rt-color-bg-surface);
|
|
106
|
+
background-image: linear-gradient(var(--rt-dynamic-selector-list-row-bg), var(--rt-dynamic-selector-list-row-bg));
|
|
107
|
+
color: var(--rt-color-text-primary);
|
|
108
|
+
}
|