@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
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
@use '../../../../styles/breakpoints' as bp;
|
|
2
|
+
|
|
3
|
+
@layer rt-kit.components {
|
|
4
|
+
/* rt-dynamic-selector-popup — панель выбора в CDK Overlay. ViewEncapsulation.None.
|
|
5
|
+
Размер и вид сняты с кадров первого кита: 20rem на 30rem, поверхность с рамкой и тенью. */
|
|
6
|
+
|
|
7
|
+
.rt-dynamic-selector-popup {
|
|
8
|
+
--rt-dynamic-selector-popup-width: calc(var(--rt-size-40) * 2);
|
|
9
|
+
--rt-dynamic-selector-popup-max-height: calc(var(--rt-size-100) + var(--rt-size-20));
|
|
10
|
+
--rt-dynamic-selector-popup-radius: var(--rt-radius-md);
|
|
11
|
+
--rt-dynamic-selector-popup-border-width: var(--rt-border-width-thin);
|
|
12
|
+
--rt-dynamic-selector-popup-shadow: var(--rt-shadow-lg);
|
|
13
|
+
|
|
14
|
+
display: flex;
|
|
15
|
+
width: var(--rt-dynamic-selector-popup-width);
|
|
16
|
+
max-width: calc(100vw - var(--rt-space-md) * 2);
|
|
17
|
+
max-height: var(--rt-dynamic-selector-popup-max-height);
|
|
18
|
+
box-sizing: border-box;
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
border: var(--rt-dynamic-selector-popup-border-width) solid var(--rt-color-border-subtle);
|
|
21
|
+
border-radius: var(--rt-dynamic-selector-popup-radius);
|
|
22
|
+
background: var(--rt-color-bg-surface);
|
|
23
|
+
box-shadow: var(--rt-dynamic-selector-popup-shadow);
|
|
24
|
+
color: var(--rt-color-text-primary);
|
|
25
|
+
gap: var(--rt-space-sm);
|
|
26
|
+
padding-block: var(--rt-space-md);
|
|
27
|
+
|
|
28
|
+
&__head {
|
|
29
|
+
display: flex;
|
|
30
|
+
flex-direction: column;
|
|
31
|
+
gap: var(--rt-space-sm);
|
|
32
|
+
padding-inline: var(--rt-space-md);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
&__search {
|
|
36
|
+
display: block;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
&__controls {
|
|
40
|
+
display: flex;
|
|
41
|
+
flex-direction: column;
|
|
42
|
+
border-bottom: var(--rt-dynamic-selector-popup-border-width) solid var(--rt-color-border-subtle);
|
|
43
|
+
|
|
44
|
+
/* Строка переключателя и «Выбрать все» — два разных решения; при зазоре 2xs флажок
|
|
45
|
+
прилипал к переключателю и читался его частью. */
|
|
46
|
+
gap: var(--rt-space-sm);
|
|
47
|
+
padding-block-end: var(--rt-space-sm);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
&__multi {
|
|
51
|
+
display: flex;
|
|
52
|
+
flex-wrap: wrap;
|
|
53
|
+
align-items: center;
|
|
54
|
+
gap: var(--rt-space-2xs) var(--rt-space-sm);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
&__multi-label {
|
|
58
|
+
font-size: var(--rt-text-sm);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&__multi-hint-icon {
|
|
62
|
+
color: var(--rt-color-text-muted);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// На широком экране подсказка стоит значком со всплывающей подсказкой, на узком — текстом.
|
|
66
|
+
&__multi-hint {
|
|
67
|
+
display: none;
|
|
68
|
+
flex-basis: 100%;
|
|
69
|
+
color: var(--rt-color-text-muted);
|
|
70
|
+
font-size: var(--rt-text-xs);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@media (width <= #{bp.$rt-bp-lg}) {
|
|
74
|
+
&__multi-hint {
|
|
75
|
+
display: block;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
&__multi-hint-icon {
|
|
79
|
+
display: none;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
&__select-all {
|
|
84
|
+
display: block;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
&__state {
|
|
88
|
+
display: flex;
|
|
89
|
+
align-items: center;
|
|
90
|
+
justify-content: center;
|
|
91
|
+
padding: var(--rt-space-md);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
&__list {
|
|
95
|
+
display: flex;
|
|
96
|
+
min-height: 0;
|
|
97
|
+
flex: 1 1 auto;
|
|
98
|
+
flex-direction: column;
|
|
99
|
+
overflow-y: auto;
|
|
100
|
+
padding-inline: var(--rt-space-md);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Шаг строки снят с первого кита: флажок и по отступу сверху и снизу — около 36px.
|
|
104
|
+
&__row {
|
|
105
|
+
display: block;
|
|
106
|
+
padding-block: var(--rt-space-sm);
|
|
107
|
+
|
|
108
|
+
&--separated {
|
|
109
|
+
border-bottom: var(--rt-dynamic-selector-popup-border-width) solid var(--rt-color-border-subtle);
|
|
110
|
+
margin-block-end: var(--rt-space-2xs);
|
|
111
|
+
padding-block-end: var(--rt-space-sm);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Длинная подпись строки переносится: обрезка спрятала бы, какую запись человек отмечает.
|
|
116
|
+
&__option {
|
|
117
|
+
display: block;
|
|
118
|
+
overflow-wrap: anywhere;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
&__sentinel {
|
|
122
|
+
min-height: var(--rt-size-1);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
&__fetching {
|
|
126
|
+
display: flex;
|
|
127
|
+
justify-content: center;
|
|
128
|
+
padding-block: var(--rt-space-sm);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
&__empty {
|
|
132
|
+
display: block;
|
|
133
|
+
padding-inline: var(--rt-space-md);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
&__foot {
|
|
137
|
+
display: flex;
|
|
138
|
+
align-items: center;
|
|
139
|
+
justify-content: flex-end;
|
|
140
|
+
border-top: var(--rt-dynamic-selector-popup-border-width) solid var(--rt-color-border-subtle);
|
|
141
|
+
gap: var(--rt-space-sm);
|
|
142
|
+
padding-block-start: var(--rt-space-sm);
|
|
143
|
+
padding-inline: var(--rt-space-md);
|
|
144
|
+
|
|
145
|
+
&--nav {
|
|
146
|
+
justify-content: space-between;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Длинное название ссылки обрезается многоточием, а целиком читается во всплывающей подсказке.
|
|
151
|
+
&__nav {
|
|
152
|
+
overflow: hidden;
|
|
153
|
+
min-width: 0;
|
|
154
|
+
color: var(--rt-color-text-link);
|
|
155
|
+
font-size: var(--rt-text-sm);
|
|
156
|
+
text-overflow: ellipsis;
|
|
157
|
+
white-space: nowrap;
|
|
158
|
+
|
|
159
|
+
&:hover {
|
|
160
|
+
color: var(--rt-color-text-link-hover);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
&__actions {
|
|
165
|
+
display: flex;
|
|
166
|
+
flex: 0 0 auto;
|
|
167
|
+
gap: var(--rt-space-sm);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
@layer rt-kit.components {
|
|
2
|
+
/* rt-dynamic-selector — поле со списком выбранного. ViewEncapsulation.None.
|
|
3
|
+
Строки и полосу рисует список семьи; здесь — место под приглашение и пустое состояние. */
|
|
4
|
+
|
|
5
|
+
.rt-dynamic-selector {
|
|
6
|
+
display: block;
|
|
7
|
+
width: 100%;
|
|
8
|
+
|
|
9
|
+
&__content {
|
|
10
|
+
display: flex;
|
|
11
|
+
flex-direction: column;
|
|
12
|
+
gap: var(--rt-space-sm);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
&__invitation {
|
|
16
|
+
display: block;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
&__nothing {
|
|
20
|
+
display: block;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
| `icon` | `IRtIcon.Name \| null` | `null` |
|
|
13
13
|
| `title` | `string` | `''` |
|
|
14
14
|
| `description` | `string \| null` | `null` |
|
|
15
|
+
| `framed` | `boolean` | `false` |
|
|
15
16
|
|
|
16
17
|
Выходов нет. Два слота проекции:
|
|
17
18
|
|
|
@@ -28,6 +29,8 @@
|
|
|
28
29
|
|
|
29
30
|
- Иконка рисуется крупной (`xl`, 32px) и приглушённой: это заглушка, а не аффорданс. Кликабельным
|
|
30
31
|
должно быть проецируемое действие.
|
|
32
|
+
- `framed` обводит заглушку пунктиром: так она читается как зона, куда бросают файл. Сам приём
|
|
33
|
+
файла даёт обёртка [`rt-file-drop`](../file-drop/CONTEXT.md), заглушка только рисует приглашение.
|
|
31
34
|
- Слот действия существует всегда, даже пустым; прячет его `:empty` в стилях.
|
|
32
35
|
- Размеры и подложка — свойства блока: `--rt-empty-state-icon-wrap-size`,
|
|
33
36
|
`--rt-empty-state-icon-wrap-bg`, `--rt-empty-state-icon-size`, `--rt-empty-state-title-size`,
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
--rt-empty-state-icon-size: var(--rt-size-8);
|
|
14
14
|
--rt-empty-state-title-size: var(--rt-text-md);
|
|
15
15
|
--rt-empty-state-title-weight: var(--rt-font-weight-medium);
|
|
16
|
+
--rt-empty-state-frame-width: var(--rt-border-width-medium);
|
|
17
|
+
--rt-empty-state-frame-color: var(--rt-color-border-strong);
|
|
18
|
+
--rt-empty-state-frame-radius: var(--rt-radius-lg);
|
|
16
19
|
|
|
17
20
|
display: flex;
|
|
18
21
|
flex-direction: column;
|
|
@@ -22,6 +25,12 @@
|
|
|
22
25
|
gap: var(--rt-space-sm);
|
|
23
26
|
text-align: center;
|
|
24
27
|
|
|
28
|
+
/* Рамка зоны загрузки: пунктир говорит «сюда можно бросить файл», как у первого кита. */
|
|
29
|
+
&--framed {
|
|
30
|
+
border: var(--rt-empty-state-frame-width) dashed var(--rt-empty-state-frame-color);
|
|
31
|
+
border-radius: var(--rt-empty-state-frame-radius);
|
|
32
|
+
}
|
|
33
|
+
|
|
25
34
|
/* Слот иллюстрации (проецируемая графика вместо иконки) — скрыт, если пуст. */
|
|
26
35
|
&__illustration {
|
|
27
36
|
&:empty {
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# `rt-expansion-panel`
|
|
2
|
+
|
|
3
|
+
Раскрывающаяся панель: заголовок-кнопка во всю ширину с шевроном и тело под ним. Замена панели
|
|
4
|
+
раскрытия Material из первого кита.
|
|
5
|
+
|
|
6
|
+
```html
|
|
7
|
+
<rt-expansion-panel appearance="plain" [(expanded)]="open">
|
|
8
|
+
<span>Заголовок</span>
|
|
9
|
+
<ng-template rtExpansionPanelContent>Тело</ng-template>
|
|
10
|
+
</rt-expansion-panel>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
| вход | тип | умолчание |
|
|
14
|
+
| ------------ | ------------------------------ | --------- |
|
|
15
|
+
| `expanded` | `boolean` (model) | `false` |
|
|
16
|
+
| `disabled` | `boolean` | `false` |
|
|
17
|
+
| `hideToggle` | `boolean` | `false` |
|
|
18
|
+
| `appearance` | `IRtExpansionPanel.Appearance` | `'card'` |
|
|
19
|
+
| `headerId` | `string \| null` | `null` |
|
|
20
|
+
| `ariaLabel` | `string \| null` | `null` |
|
|
21
|
+
|
|
22
|
+
Выход — `expandedChange`, половина двусторонней привязки.
|
|
23
|
+
|
|
24
|
+
## Главное, что нужно знать
|
|
25
|
+
|
|
26
|
+
**Панель пишет в `expanded` сама.** Владелец, который решает раскрытие по своим правилам, слушает
|
|
27
|
+
`expandedChange` и держит значение в своём сигнале. Отказ владельца изменить значение панель не
|
|
28
|
+
видит: привязка не передаёт то же самое значение второй раз. Такой владелец держит раскрытие в
|
|
29
|
+
`linkedSignal` и привязывает его в обе стороны — так делает блок избранного бокового меню.
|
|
30
|
+
|
|
31
|
+
**Тело двух видов.** `<ng-template rtExpansionPanelContent>` создаётся при раскрытии и уходит после
|
|
32
|
+
сворачивания, узел с `rtExpansionPanelBody` создаётся сразу. Всё прочее содержимое — заголовок.
|
|
33
|
+
|
|
34
|
+
**Движение — средствами CSS.** Высота тела идёт от нуля через `@starting-style` и
|
|
35
|
+
`interpolate-size`, уход доигрывает класс `rt-expansion-panel__body--leaving` через `animate.leave`.
|
|
36
|
+
Браузер без `interpolate-size` показывает тело сразу.
|
|
37
|
+
|
|
38
|
+
## Края
|
|
39
|
+
|
|
40
|
+
- Размеры заголовка и тела — свойства `--rt-expansion-panel-*`. Владелец переназначает их правилом
|
|
41
|
+
двух классов на хосте: одного класса мало, он равен по силе объявлению самой панели на том же
|
|
42
|
+
узле. Вложенная панель объявляет свои значения заново и чужих не наследует.
|
|
43
|
+
- `headerId` нужен владельцу, который нажимает заголовок по своему номеру: боковое меню ищет строки
|
|
44
|
+
по id.
|
|
45
|
+
- Id тела берётся из счётчика на экземпляр: две панели на странице не ссылаются на чужое тело.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
@layer rt-kit.components {
|
|
2
|
+
/* rt-expansion-panel — раскрывающаяся панель. ViewEncapsulation.None.
|
|
3
|
+
Host несёт класс блока и модификаторы вида и состояния. Все размеры заголовка и тела — свои
|
|
4
|
+
свойства блока: владелец, рисующий панель строкой своего списка, переназначает их на хосте
|
|
5
|
+
правилом большей силы, а не переписывает правила панели. */
|
|
6
|
+
|
|
7
|
+
.rt-expansion-panel {
|
|
8
|
+
--rt-expansion-panel-radius: var(--rt-radius-md);
|
|
9
|
+
--rt-expansion-panel-shadow: var(--rt-shadow-sm);
|
|
10
|
+
--rt-expansion-panel-duration: var(--rt-duration-base);
|
|
11
|
+
--rt-expansion-panel-bg: var(--rt-color-bg-surface);
|
|
12
|
+
--rt-expansion-panel-header-min-height: var(--rt-control-height-lg);
|
|
13
|
+
--rt-expansion-panel-header-padding-block: var(--rt-space-sm);
|
|
14
|
+
--rt-expansion-panel-header-padding-start: var(--rt-space-lg);
|
|
15
|
+
--rt-expansion-panel-header-padding-end: var(--rt-space-md);
|
|
16
|
+
--rt-expansion-panel-header-gap: var(--rt-space-sm);
|
|
17
|
+
--rt-expansion-panel-header-radius: var(--rt-radius-md);
|
|
18
|
+
--rt-expansion-panel-header-bg: transparent;
|
|
19
|
+
--rt-expansion-panel-header-hover-bg: var(--rt-color-bg-hover);
|
|
20
|
+
--rt-expansion-panel-header-color: var(--rt-color-text-primary);
|
|
21
|
+
--rt-expansion-panel-header-font-size: var(--rt-text-md);
|
|
22
|
+
--rt-expansion-panel-header-font-weight: var(--rt-font-weight-medium);
|
|
23
|
+
--rt-expansion-panel-chevron-size: var(--rt-control-height-sm);
|
|
24
|
+
--rt-expansion-panel-chevron-color: var(--rt-color-text-muted);
|
|
25
|
+
--rt-expansion-panel-body-padding-inline: var(--rt-space-lg);
|
|
26
|
+
--rt-expansion-panel-body-padding-end: var(--rt-space-md);
|
|
27
|
+
|
|
28
|
+
display: block;
|
|
29
|
+
width: 100%;
|
|
30
|
+
box-sizing: border-box;
|
|
31
|
+
border-radius: var(--rt-expansion-panel-radius);
|
|
32
|
+
background: var(--rt-expansion-panel-bg);
|
|
33
|
+
box-shadow: var(--rt-expansion-panel-shadow);
|
|
34
|
+
color: var(--rt-color-text-primary);
|
|
35
|
+
|
|
36
|
+
/* Панель внутри списка: ни фона, ни тени, ни отступов — строки рисует список. */
|
|
37
|
+
&--plain {
|
|
38
|
+
--rt-expansion-panel-radius: var(--rt-radius-none);
|
|
39
|
+
--rt-expansion-panel-shadow: var(--rt-shadow-none);
|
|
40
|
+
--rt-expansion-panel-bg: transparent;
|
|
41
|
+
--rt-expansion-panel-header-min-height: var(--rt-control-height-md);
|
|
42
|
+
--rt-expansion-panel-header-padding-start: var(--rt-space-0);
|
|
43
|
+
--rt-expansion-panel-header-padding-end: var(--rt-space-0);
|
|
44
|
+
--rt-expansion-panel-header-font-size: var(--rt-text-sm);
|
|
45
|
+
--rt-expansion-panel-header-font-weight: var(--rt-font-weight-regular);
|
|
46
|
+
--rt-expansion-panel-body-padding-inline: var(--rt-space-0);
|
|
47
|
+
--rt-expansion-panel-body-padding-end: var(--rt-space-0);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Заголовок во всю ширину: нажатие принимает вся строка, а не один шеврон. */
|
|
51
|
+
&__header {
|
|
52
|
+
display: flex;
|
|
53
|
+
width: 100%;
|
|
54
|
+
min-height: var(--rt-expansion-panel-header-min-height);
|
|
55
|
+
box-sizing: border-box;
|
|
56
|
+
align-items: center;
|
|
57
|
+
border: 0;
|
|
58
|
+
border-radius: var(--rt-expansion-panel-header-radius);
|
|
59
|
+
background: var(--rt-expansion-panel-header-bg);
|
|
60
|
+
color: var(--rt-expansion-panel-header-color);
|
|
61
|
+
cursor: pointer;
|
|
62
|
+
font: inherit;
|
|
63
|
+
font-size: var(--rt-expansion-panel-header-font-size);
|
|
64
|
+
font-weight: var(--rt-expansion-panel-header-font-weight);
|
|
65
|
+
gap: var(--rt-expansion-panel-header-gap);
|
|
66
|
+
padding-block: var(--rt-expansion-panel-header-padding-block);
|
|
67
|
+
padding-inline: var(--rt-expansion-panel-header-padding-start) var(--rt-expansion-panel-header-padding-end);
|
|
68
|
+
text-align: start;
|
|
69
|
+
transition: background-color var(--rt-expansion-panel-duration) ease;
|
|
70
|
+
|
|
71
|
+
&:hover:not(:disabled) {
|
|
72
|
+
background: var(--rt-expansion-panel-header-hover-bg);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
&:focus-visible {
|
|
76
|
+
outline: var(--rt-focus-ring-width) solid var(--rt-focus-ring-color);
|
|
77
|
+
outline-offset: calc(var(--rt-focus-ring-width) * -1);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
&:disabled {
|
|
81
|
+
color: var(--rt-color-text-disabled);
|
|
82
|
+
cursor: default;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* Шеврон у правого края, в столбце ширины маленькой кнопки: соседние кнопки строк списка
|
|
87
|
+
встают с ним на одну вертикаль. */
|
|
88
|
+
&__chevron {
|
|
89
|
+
display: inline-flex;
|
|
90
|
+
flex-shrink: 0;
|
|
91
|
+
justify-content: center;
|
|
92
|
+
color: var(--rt-expansion-panel-chevron-color);
|
|
93
|
+
inline-size: var(--rt-expansion-panel-chevron-size);
|
|
94
|
+
margin-inline-start: auto;
|
|
95
|
+
transition: transform var(--rt-expansion-panel-duration) ease;
|
|
96
|
+
|
|
97
|
+
&--open {
|
|
98
|
+
transform: rotate(180deg);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* Раскрытие и сворачивание — высотой от нуля до своей и обратно. Высота «auto» становится
|
|
103
|
+
величиной, между которой можно вести движение, через `interpolate-size`; браузер без него
|
|
104
|
+
показывает и убирает тело сразу. */
|
|
105
|
+
&__body {
|
|
106
|
+
overflow: hidden;
|
|
107
|
+
height: auto;
|
|
108
|
+
interpolate-size: allow-keywords;
|
|
109
|
+
padding-block-end: var(--rt-expansion-panel-body-padding-end);
|
|
110
|
+
padding-inline: var(--rt-expansion-panel-body-padding-inline);
|
|
111
|
+
transition:
|
|
112
|
+
height var(--rt-expansion-panel-duration) ease,
|
|
113
|
+
padding-block-end var(--rt-expansion-panel-duration) ease;
|
|
114
|
+
|
|
115
|
+
@starting-style {
|
|
116
|
+
height: 0;
|
|
117
|
+
padding-block-end: 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
&--leaving {
|
|
121
|
+
height: 0;
|
|
122
|
+
padding-block-end: 0;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@media (prefers-reduced-motion: reduce) {
|
|
126
|
+
transition: none;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
&--disabled &__chevron {
|
|
131
|
+
color: var(--rt-color-text-disabled);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
@layer rt-kit.components {
|
|
2
|
+
/* Заголовок и тело, которые витрина кладёт в панель: подпись режется многоточием — так её
|
|
3
|
+
оформляет владелец панели, сама панель содержимого заголовка не знает. */
|
|
4
|
+
.app-expansion-panel-demo {
|
|
5
|
+
&__stack {
|
|
6
|
+
display: flex;
|
|
7
|
+
flex-direction: column;
|
|
8
|
+
gap: var(--rt-space-sm);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
&__icon {
|
|
12
|
+
flex-shrink: 0;
|
|
13
|
+
color: var(--rt-color-text-muted);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
&__title {
|
|
17
|
+
overflow: hidden;
|
|
18
|
+
min-width: 0;
|
|
19
|
+
flex: 1 1 auto;
|
|
20
|
+
text-overflow: ellipsis;
|
|
21
|
+
white-space: nowrap;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&__text {
|
|
25
|
+
margin: 0;
|
|
26
|
+
color: var(--rt-color-text-muted);
|
|
27
|
+
font-size: var(--rt-text-sm);
|
|
28
|
+
line-height: var(--rt-leading-normal);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
|
|
27
27
|
## Края
|
|
28
28
|
|
|
29
|
-
- Кнопки действий
|
|
30
|
-
|
|
29
|
+
- Кнопки действий идут шагом `md`, 40px. Прежний инлайновый `--rt-icon-button-size: 35px` до кнопки
|
|
30
|
+
не доходил и снят: после того как кнопка-значок научилась брать размер с тега, он уменьшил бы их.
|
|
31
31
|
- Логотип рисуется вариантом `wordmark` высотой 15px; сами файлы даёт приложение
|
|
32
32
|
(см. [`rt-logo`](../logo/CONTEXT.md)).
|
|
33
33
|
|
|
@@ -4,15 +4,19 @@
|
|
|
4
4
|
<rt-icon name="check" size="md" color="current" [rotate]="null" />
|
|
5
5
|
```
|
|
6
6
|
|
|
7
|
-
| вход | тип | умолчание
|
|
8
|
-
| -------- | ----------------------------------------------------------------------------------- |
|
|
9
|
-
| `name` | `IRtIcon.Name` — литеральный union из `rt-icon-names.ts`
|
|
10
|
-
| `
|
|
11
|
-
| `
|
|
12
|
-
| `
|
|
7
|
+
| вход | тип | умолчание |
|
|
8
|
+
| -------- | ----------------------------------------------------------------------------------- | ----------- |
|
|
9
|
+
| `name` | `IRtIcon.Name \| null` — литеральный union из `rt-icon-names.ts`; побеждает `glyph` | `null` |
|
|
10
|
+
| `glyph` | `string \| null` — имя Material: пара кита или лигатура шрифта | `null` |
|
|
11
|
+
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl' \| number` — число в пикселях | `'md'` |
|
|
12
|
+
| `color` | `'current' \| 'muted' \| 'info' \| 'success' \| 'warning' \| 'danger' \| 'inverse'` | `'current'` |
|
|
13
|
+
| `rotate` | `number \| string \| null` | `null` |
|
|
14
|
+
| `fill` | `boolean` — залитый рисунок материального набора и заливка шрифта лигатуры | `false` |
|
|
15
|
+
| `spin` | `boolean` — вращение, медленнее при просьбе системы о меньшем движении | `false` |
|
|
13
16
|
|
|
14
17
|
Выходов нет. Размер и цвет едут инлайновым стилем host-а (`width`/`height`/`color`), не классом:
|
|
15
|
-
`xs` 12px, `sm` 16px, `md` 20px, `lg` 24px, `xl` 32px, `2xl` 40px
|
|
18
|
+
`xs` 12px, `sm` 16px, `md` 20px, `lg` 24px, `xl` 32px, `2xl` 40px, или число пикселей. Лигатура
|
|
19
|
+
глифа скрыта, пока шрифты страницы не готовы: её ждёт `RtIconFontService`.
|
|
16
20
|
|
|
17
21
|
## Главное, что нужно знать
|
|
18
22
|
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
Селектор bare `.rt-icon` (класс на host) — им же адресуются и программные
|
|
4
4
|
потребители sprite'а, рисующие иконку без компонента. */
|
|
5
5
|
.rt-icon {
|
|
6
|
+
--rt-icon-spin-duration: 1s;
|
|
7
|
+
--rt-icon-spin-duration-reduced: 4s;
|
|
8
|
+
|
|
6
9
|
display: inline-flex;
|
|
7
10
|
flex-shrink: 0;
|
|
8
11
|
line-height: 0;
|
|
@@ -14,7 +17,51 @@
|
|
|
14
17
|
fill: currentcolor;
|
|
15
18
|
}
|
|
16
19
|
|
|
20
|
+
/* Лигатура шрифта Material Symbols для глифа без пары. Шрифт подключает приложение,
|
|
21
|
+
семью можно переназначить свойством сверху. Размер шрифта — встроенным стилем, он равен
|
|
22
|
+
ширине значка. До готовности шрифтов лигатура скрыта: иначе на её месте видно слово. */
|
|
23
|
+
&__glyph {
|
|
24
|
+
display: block;
|
|
25
|
+
overflow: hidden;
|
|
26
|
+
width: 100%;
|
|
27
|
+
font-family: var(--rt-icon-glyph-font, 'Material Symbols Outlined'), sans-serif;
|
|
28
|
+
font-feature-settings: 'liga';
|
|
29
|
+
font-style: normal;
|
|
30
|
+
font-variation-settings: 'FILL' 0;
|
|
31
|
+
font-weight: var(--rt-font-weight-regular);
|
|
32
|
+
letter-spacing: normal;
|
|
33
|
+
line-height: 1;
|
|
34
|
+
text-align: center;
|
|
35
|
+
text-transform: none;
|
|
36
|
+
white-space: nowrap;
|
|
37
|
+
|
|
38
|
+
&--filled {
|
|
39
|
+
font-variation-settings: 'FILL' 1;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
&--pending {
|
|
43
|
+
visibility: hidden;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* Вращение задаётся анимацией, и на её время она перекрывает поворот значка. */
|
|
48
|
+
&--spin {
|
|
49
|
+
animation: rt-icon-spin var(--rt-icon-spin-duration) linear infinite;
|
|
50
|
+
}
|
|
51
|
+
|
|
17
52
|
/* Набор рисунков стилями не выбирается: ссылку на символ спрайта CSS подменить нечем.
|
|
18
53
|
Признак набора компонент читает у разметки над собой — см. rt-icon.component.ts. */
|
|
19
54
|
}
|
|
55
|
+
|
|
56
|
+
@keyframes rt-icon-spin {
|
|
57
|
+
to {
|
|
58
|
+
transform: rotate(1turn);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@media (prefers-reduced-motion: reduce) {
|
|
63
|
+
.rt-icon--spin {
|
|
64
|
+
animation-duration: var(--rt-icon-spin-duration-reduced);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
20
67
|
}
|
|
@@ -4,19 +4,20 @@
|
|
|
4
4
|
<rt-icon-button icon="ico-trash" ariaLabel="Удалить" variant="danger" size="md" (clicked)="remove()" />
|
|
5
5
|
```
|
|
6
6
|
|
|
7
|
-
| вход | тип
|
|
8
|
-
| ----------------------------------------------- |
|
|
9
|
-
| `icon` | `IRtIcon.Name`
|
|
10
|
-
| `
|
|
11
|
-
| `
|
|
12
|
-
| `
|
|
13
|
-
| `
|
|
14
|
-
| `
|
|
15
|
-
| `
|
|
16
|
-
| `
|
|
17
|
-
| `
|
|
18
|
-
| `
|
|
19
|
-
| `
|
|
7
|
+
| вход | тип | умолчание |
|
|
8
|
+
| ----------------------------------------------- | ----------------------------------------------------------------------------- | ---------------------------- |
|
|
9
|
+
| `icon` | `IRtIcon.Name \| null` — нужен он или `glyph`; без обоих показывает вложенное | `null` |
|
|
10
|
+
| `glyph` | `string \| null` — имя Material, как `glyph` у `rt-icon` | `null` |
|
|
11
|
+
| `ariaLabel` | `string` | **обязателен** |
|
|
12
|
+
| `variant` | `'primary' \| 'secondary' \| 'ghost' \| 'danger' \| 'success' \| 'warning'` | `'ghost'` |
|
|
13
|
+
| `size` | `'2xs' \| 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl'` | `'md'` |
|
|
14
|
+
| `iconSize` | `IRtIcon.Size \| null` | `null` → от размера кнопки |
|
|
15
|
+
| `iconColor` | `IRtIcon.Color` | `'current'` |
|
|
16
|
+
| `radius` | `TRtRadius \| null` — шаг общей шкалы | `null` → `md` |
|
|
17
|
+
| `type` | `'button' \| 'submit'` | `'button'` |
|
|
18
|
+
| `tooltip` | `string` | `''` (пусто → подсказки нет) |
|
|
19
|
+
| `tabIndex` | `number` | `0` |
|
|
20
|
+
| `loading` / `disabled` / `active` / `indicator` | `boolean` | `false` |
|
|
20
21
|
|
|
21
22
|
| выход | тип |
|
|
22
23
|
| --------- | ------------ |
|
|
@@ -27,13 +28,19 @@
|
|
|
27
28
|
**`ariaLabel` обязателен.** У кнопки нет текста, и без подписи она для скринридера безымянна.
|
|
28
29
|
Это единственная причина, по которой вход помечен `required`.
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
**Нет ни `icon`, ни `glyph` — кнопка показывает вложенное.** Так в кнопку кита встаёт рисунок,
|
|
32
|
+
которого нет в наборе: размер, форма и состояния остаются кнопочными. Со значком вложенное не
|
|
33
|
+
рисуется.
|
|
34
|
+
|
|
35
|
+
**Кнопку компонент рисует внутри себя**, host остаётся обычным элементом. Модификаторы размера и
|
|
36
|
+
вида пишут частные шаги `--rt-icon-button-size-step` и `--rt-icon-button-bg-variant`, а кнопка
|
|
37
|
+
читает их под публичными `--rt-icon-button-size` и `--rt-icon-button-bg`. Публичные кнопка не
|
|
38
|
+
объявляет, поэтому значение на теге или выше доходит до неё; заливку под указателем задаёт
|
|
39
|
+
`--rt-icon-button-bg-hover`. Компоненты кита, которым нужен свой размер кнопки, пишут шаг, и
|
|
40
|
+
последнее слово остаётся за приложением. Диаметр берётся из общей шкалы высот контролов: иконочная
|
|
41
|
+
кнопка стоит в строке рядом с кнопкой и полем. Ступени — `2xs` 20px и `xs` 22px со значком 16px,
|
|
42
|
+
затем `sm`, `md`, `lg`, `xl`, `2xl` по шкале. У шкалы нет ступени 22px, поэтому `xs` записан на
|
|
43
|
+
месте.
|
|
37
44
|
|
|
38
45
|
## Как этим пользоваться
|
|
39
46
|
|