@rt-tools/ui-kit-v2 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +25 -5
  2. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs +45 -9
  3. package/fesm2022/rt-tools-ui-kit-v2-rich-editor.mjs.map +1 -1
  4. package/fesm2022/rt-tools-ui-kit-v2.mjs +2265 -664
  5. package/fesm2022/rt-tools-ui-kit-v2.mjs.map +1 -1
  6. package/package.json +1 -1
  7. package/rt-tools-ui-kit-v2-0.14.0.tgz +0 -0
  8. package/src/lib/components/CONTEXT.md +1 -1
  9. package/src/lib/components/action-bar/rt-action-bar.component.scss +5 -0
  10. package/src/lib/components/autocomplete/rt-autocomplete.component.scss +8 -1
  11. package/src/lib/components/bottom-sheet/rt-bottom-sheet.component.scss +5 -0
  12. package/src/lib/components/button/CONTEXT.md +1 -1
  13. package/src/lib/components/button/rt-button.directive.scss +5 -7
  14. package/src/lib/components/calendar/CONTEXT.md +16 -2
  15. package/src/lib/components/calendar/rt-calendar.component.scss +81 -4
  16. package/src/lib/components/card/rt-card.component.scss +5 -0
  17. package/src/lib/components/checkbox/rt-checkbox.component.scss +11 -0
  18. package/src/lib/components/data-list/settings/rt-data-list-settings-aside.component.scss +1 -1
  19. package/src/lib/components/data-list/toolbar/rt-data-list-toolbar.component.scss +1 -1
  20. package/src/lib/components/data-table/cell/rt-data-table-cell.component.scss +1 -1
  21. package/src/lib/components/data-table/filter-cell/rt-data-table-filter-cell.component.scss +1 -1
  22. package/src/lib/components/data-table/rt-data-table.component.scss +1 -1
  23. package/src/lib/components/date-picker/CONTEXT.md +33 -14
  24. package/src/lib/components/date-picker/panel/rt-date-panel.component.scss +155 -0
  25. package/src/lib/components/date-picker/rt-date-picker.component.scss +18 -2
  26. package/src/lib/components/date-range/CONTEXT.md +53 -0
  27. package/src/lib/components/date-range/panel/rt-date-range-panel.component.scss +103 -0
  28. package/src/lib/components/date-range/rt-date-range.component.scss +120 -0
  29. package/src/lib/components/dialog/rt-dialog.component.scss +5 -0
  30. package/src/lib/components/empty-state/rt-empty-state.component.scss +5 -0
  31. package/src/lib/components/file-card/rt-file-card.component.scss +5 -0
  32. package/src/lib/components/file-drop/rt-file-drop.component.scss +5 -0
  33. package/src/lib/components/header/rt-header.component.scss +5 -0
  34. package/src/lib/components/icon-button/CONTEXT.md +1 -1
  35. package/src/lib/components/icon-button/rt-icon-button.component.scss +9 -29
  36. package/src/lib/components/input/rt-input.component.scss +7 -1
  37. package/src/lib/components/input-number/rt-input-number.component.scss +7 -1
  38. package/src/lib/components/markdown-text/rt-markdown-text.component.scss +5 -0
  39. package/src/lib/components/menu/rt-menu-item.component.scss +5 -0
  40. package/src/lib/components/message/rt-message.component.scss +5 -0
  41. package/src/lib/components/money-list/rt-money-list.component.scss +5 -0
  42. package/src/lib/components/multiselect/CONTEXT.md +12 -5
  43. package/src/lib/components/multiselect/rt-multiselect.component.scss +32 -1
  44. package/src/lib/components/note/rt-note.component.scss +5 -0
  45. package/src/lib/components/notifications-bell/rt-notifications-bell.component.scss +5 -0
  46. package/src/lib/components/pagination/rt-pagination.component.scss +6 -1
  47. package/src/lib/components/radio-button/rt-radio-button.component.scss +5 -0
  48. package/src/lib/components/section-nav/rt-section-nav.component.scss +5 -0
  49. package/src/lib/components/select/CONTEXT.md +10 -7
  50. package/src/lib/components/select/rt-select.component.scss +36 -1
  51. package/src/lib/components/skeleton/CONTEXT.md +14 -16
  52. package/src/lib/components/skeleton/rt-skeleton.component.scss +7 -1
  53. package/src/lib/components/skeleton-wrapper/CONTEXT.md +6 -6
  54. package/src/lib/components/split-button/rt-split-button.component.scss +6 -0
  55. package/src/lib/components/stepper/rt-stepper.component.scss +5 -0
  56. package/src/lib/components/table/rt-table.component.scss +12 -0
  57. package/src/lib/components/tag/CONTEXT.md +14 -15
  58. package/src/lib/components/tag/rt-tag.component.scss +6 -30
  59. package/src/lib/components/textarea/rt-textarea.component.scss +8 -1
  60. package/src/lib/components/thread-list/rt-thread-list.component.scss +5 -0
  61. package/src/lib/components/toggle-button-group/rt-toggle-button-group.component.scss +7 -6
  62. package/src/lib/components/toggle-switch/rt-toggle-switch.component.scss +5 -0
  63. package/src/rich-editor/lib/components/message-composer/CONTEXT.md +11 -1
  64. package/src/rich-editor/lib/components/message-composer/rt-message-composer.component.scss +78 -34
  65. package/src/styles/_mixins.scss +39 -0
  66. package/styles/tokens.css +30 -5
  67. package/types/rt-tools-ui-kit-v2-rich-editor.d.ts +11 -5
  68. package/types/rt-tools-ui-kit-v2.d.ts +394 -109
  69. package/rt-tools-ui-kit-v2-0.13.0.tgz +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rt-tools/ui-kit-v2",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "license": "Apache-2.0",
5
5
  "author": "Yauheni Krumin",
6
6
  "type": "module",
Binary file
@@ -37,7 +37,7 @@ tag/
37
37
  | иконка, кольцо, заглушка | `icon`, `spinner`, `skeleton`, `skeleton-wrapper` |
38
38
  | статус, счётчик, метка | `tag`, `live-badge`, `info-item`, `stat-tile`, `delta-view` |
39
39
  | кнопки | `button` (директива), `icon-button`, `split-button`, `toggle-button-group` |
40
- | поля ввода | `input`, `textarea`, `input-number`, `counter`, `checkbox`, `toggle-switch`, `date-picker`, `file-input`, `rich-editor` |
40
+ | поля ввода | `input`, `textarea`, `input-number`, `counter`, `checkbox`, `toggle-switch`, `date-picker`, `date-range`, `file-input`, `rich-editor` |
41
41
  | списки выбора | `select`, `multiselect`, `autocomplete`, `filter-control` |
42
42
  | обёртка поля | `field`, `form-control` (основа) |
43
43
  | плавающие панели | `popover`, `tooltip`, `confirm-popover`, `menu`, `toast` |
@@ -1,3 +1,5 @@
1
+ @use '../../../styles/mixins' as kv;
2
+
1
3
  @layer rt-kit.components {
2
4
  /* rt-action-bar — ViewEncapsulation.None: правила таргетируют BEM-класс блока.
3
5
  `.rt-action-bar` — сам хост (шаблон начинается с ng-container, класс ставит host). */
@@ -118,5 +120,8 @@
118
120
  display: none;
119
121
  }
120
122
  }
123
+
124
+ /* Шаг входа `radius` переназначает скругление панели; действия и меню держат своё. */
125
+ @include kv.radius-steps('--rt-action-bar-radius');
121
126
  }
122
127
  }
@@ -1,5 +1,9 @@
1
+ @use '../../../styles/mixins' as kv;
2
+
1
3
  @layer rt-kit.components {
2
4
  .rt-autocomplete {
5
+ --rt-autocomplete-radius: var(--rt-input-radius);
6
+
3
7
  position: relative;
4
8
  display: block;
5
9
  width: 100%;
@@ -14,7 +18,7 @@
14
18
  align-items: center;
15
19
  padding: var(--rt-input-padding-y) var(--rt-input-padding-x);
16
20
  border: var(--rt-input-border-width) solid var(--rt-input-color-border);
17
- border-radius: var(--rt-input-radius);
21
+ border-radius: var(--rt-autocomplete-radius);
18
22
  background-color: var(--rt-input-color-bg);
19
23
  color: var(--rt-input-color-text);
20
24
  cursor: text;
@@ -145,5 +149,8 @@
145
149
  color: var(--rt-input-color-text-placeholder);
146
150
  font-style: italic;
147
151
  }
152
+
153
+ /* Шаг входа `radius` переназначает скругление поля; панель в оверлее держит своё. */
154
+ @include kv.radius-steps('--rt-autocomplete-radius');
148
155
  }
149
156
  }
@@ -1,3 +1,5 @@
1
+ @use '../../../styles/mixins' as kv;
2
+
1
3
  @layer rt-kit.components {
2
4
  /* rt-bottom-sheet — ViewEncapsulation.None: правила таргетируют BEM-класс блока.
3
5
  `.rt-bottom-sheet` — сам хост (шаблон начинается с ng-container, класс и
@@ -74,5 +76,8 @@
74
76
  transform: translateY(0);
75
77
  }
76
78
  }
79
+
80
+ /* Шаг входа `radius` переназначает скругление панели. */
81
+ @include kv.radius-steps('--rt-bottom-sheet-radius');
77
82
  }
78
83
  }
@@ -18,7 +18,7 @@
18
18
  | `theme` | `'primary' \| 'secondary' \| 'success' \| 'warning' \| 'danger' \| 'info'` | `'primary'` |
19
19
  | `appearance` | `'filled' \| 'outlined' \| 'text'` | настройки кита или `'filled'` |
20
20
  | `size` | `'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl'` (30 / 40 / 50 / 60 / 70 px) | настройки кита или `'md'` |
21
- | `rounded` | `boolean` | настройки кита или `false` |
21
+ | `radius` | `TRtRadius \| null` — шаг общей шкалы | настройки кита или `null` |
22
22
  | `loading` | `boolean` | `false` |
23
23
  | `loadingIcon` | `string \| null` | `null` → встроенное кольцо |
24
24
 
@@ -1,3 +1,5 @@
1
+ @use '../../../styles/mixins' as kv;
2
+
1
3
  @layer rt-kit.components {
2
4
  .rt-button {
3
5
  /* Высота приходит общей шкалой контролов, а не своим числом: кнопка, поле и
@@ -215,10 +217,6 @@
215
217
  --rt-btn-color: var(--rt-color-action-info-on-surface);
216
218
  }
217
219
 
218
- &--rounded {
219
- --rt-btn-radius: 999px;
220
- }
221
-
222
220
  &--sm {
223
221
  --rt-btn-height: var(--rt-control-height-sm);
224
222
  --rt-btn-padding: 0 0.875rem;
@@ -257,9 +255,9 @@
257
255
  gap: 0;
258
256
  }
259
257
 
260
- &--icon-only#{&}--rounded {
261
- --rt-btn-radius: 50%;
262
- }
258
+ /* Шаг входа `radius` переназначает собственное свойство кнопки. Класс блока стоит на
259
+ самом хосте, поэтому правило шага — на нём же. */
260
+ @include kv.radius-steps('--rt-btn-radius');
263
261
 
264
262
  &--loading {
265
263
  cursor: wait;
@@ -20,8 +20,12 @@
20
20
  | `canPrev` / `canNext` | `boolean` | `false` |
21
21
  | `prevAriaLabel` / `nextAriaLabel` | `string` | `''` |
22
22
  | `sublabelsLoading` | `boolean` | `false` |
23
+ | `grid` | `boolean` | `false` |
24
+ | `activeKey` | `string \| null` | `null` |
25
+ | `titleAction` / `headerTitle` | `boolean` | `false` |
23
26
 
24
- Выходы: `prevMonth`, `nextMonth`, `dayClick`. Слот `[calendarHint]` — подсказка в шапке.
27
+ Выходы: `prevMonth`, `nextMonth`, `dayClick`, `dayHover`, `gridKey`, `titleClick`. Слот
28
+ `[calendarHint]` — подсказка в шапке.
25
29
 
26
30
  ## Главное, что нужно знать
27
31
 
@@ -31,11 +35,21 @@
31
35
  и для выбора дат, и для витрины занятости.
32
36
 
33
37
  **Это не поле ввода.** Значение он не хранит и в форму не пишет; для ввода даты есть
34
- [`rt-date-picker`](../date-picker/CONTEXT.md).
38
+ [`rt-date-picker`](../date-picker/CONTEXT.md), для периода — [`rt-date-range`](../date-range/CONTEXT.md).
39
+
40
+ **Одиночный выбор и клавиши — по входам.** День с `state: chosen` залит, день с `today: true`
41
+ обведён рамкой. Вход `grid` оставляет в обходе Tab один день и отдаёт стрелки, PageUp/PageDown,
42
+ Home и End событием `gridKey`; куда встать, решает потребитель и ставит `activeKey`. Так
43
+ календарь держит панель поля даты и остаётся без своей логики дат.
35
44
 
36
45
  ## Края
37
46
 
38
47
  - Недоступный день не кликается — `dayClick` для него не поднимается.
48
+ - `dayHover` отдаёт день под указателем или с фокусом и `null`, когда указатель ушёл с месяцев;
49
+ по нему поле диапазона рисует будущий диапазон. Недоступный день его не поднимает.
39
50
  - `sublabelsLoading` подменяет подписи под числами заглушками, оставляя сами числа.
51
+ - `--rt-calendar-column-gap` и `--rt-calendar-range-inner-radius` — зазор колонок и скругление
52
+ внутренних углов диапазона. По умолчанию это прежние зазор и скругление дня; поле диапазона ставит
53
+ оба в ноль, и полоса диапазона идёт сплошной.
40
54
  - Стрелки отключены, пока не разрешены явно: календарь не знает границ диапазона.
41
55
  - Подписи стрелок задаёт приложение — своих слов у календаря здесь нет.
@@ -1,3 +1,5 @@
1
+ @use '../../../styles/mixins' as kv;
2
+
1
3
  @layer rt-kit.components {
2
4
  /* rt-calendar — ViewEncapsulation.None: правила таргетируют BEM-класс блока.
3
5
  `.rt-calendar` — сам хост (шаблон начинается с ng-container, класс ставит host). */
@@ -5,6 +7,24 @@
5
7
  .rt-calendar {
6
8
  --rt-calendar-day-radius: var(--rt-radius-md);
7
9
 
10
+ /* Наименьшая высота дня: панель поля даты поднимает её до размера под палец. */
11
+ --rt-calendar-day-size: auto;
12
+
13
+ /* Где число стоит в клетке по высоте: сверху, чтобы подписи ряда шли одной строкой. */
14
+ --rt-calendar-day-justify: flex-start;
15
+
16
+ /* Число колонок сетки месяцев: два месяца рядом. Панель поля даты ставит одну колонку. */
17
+ --rt-calendar-month-count: 2;
18
+
19
+ /* Зазор между колонками дней. Поле диапазона ставит ноль, и полоса диапазона идёт сплошной. */
20
+ --rt-calendar-column-gap: var(--rt-space-0-5);
21
+
22
+ /* Скругление внутренних углов диапазона: у дней между краями и у стыков начала и конца. */
23
+ --rt-calendar-range-inner-radius: var(--rt-calendar-day-radius);
24
+
25
+ /* Рамка сегодняшнего дня: тонкая линия цвета действия внутри клетки. */
26
+ --rt-calendar-today-ring: inset 0 0 0 var(--rt-border-width-thin) var(--rt-color-action-primary);
27
+
8
28
  display: block;
9
29
 
10
30
  &__header {
@@ -19,26 +39,53 @@
19
39
  flex: 0 0 auto;
20
40
  }
21
41
 
42
+ /* Заголовок в шапке стоит между стрелками и не держит нижнего отступа сетки. */
43
+ &__header &__month-title {
44
+ width: auto;
45
+ padding: var(--rt-space-1) var(--rt-space-2);
46
+ margin: 0;
47
+ }
48
+
22
49
  &__months {
23
50
  display: grid;
24
51
  gap: var(--rt-space-6);
25
- grid-template-columns: repeat(2, 1fr);
52
+ grid-template-columns: repeat(var(--rt-calendar-month-count), 1fr);
26
53
  }
27
54
 
28
55
  &__month-title {
56
+ display: block;
57
+ width: 100%;
58
+ padding: 0;
59
+ border: none;
29
60
  margin: 0 0 var(--rt-space-2);
61
+ background: none;
30
62
  color: var(--rt-color-text-primary);
63
+ font: inherit;
31
64
  font-weight: var(--rt-font-weight-semibold);
32
65
  text-align: center;
33
66
 
34
67
  &:first-letter {
35
68
  text-transform: uppercase;
36
69
  }
70
+
71
+ &:is(button) {
72
+ border-radius: var(--rt-calendar-day-radius);
73
+ cursor: pointer;
74
+
75
+ &:hover {
76
+ color: var(--rt-color-text-link);
77
+ }
78
+
79
+ &:focus-visible {
80
+ outline: var(--rt-focus-ring-width) solid var(--rt-focus-ring-color);
81
+ outline-offset: var(--rt-focus-ring-offset);
82
+ }
83
+ }
37
84
  }
38
85
 
39
86
  &__grid {
40
87
  display: grid;
41
- gap: var(--rt-space-0-5);
88
+ gap: var(--rt-space-0-5) var(--rt-calendar-column-gap);
42
89
  grid-template-columns: repeat(7, 1fr);
43
90
  }
44
91
 
@@ -53,6 +100,7 @@
53
100
  display: flex;
54
101
  flex-direction: column;
55
102
  align-items: center;
103
+ justify-content: var(--rt-calendar-day-justify);
56
104
  padding: var(--rt-space-2) var(--rt-space-0-5);
57
105
  border: none;
58
106
  border-radius: var(--rt-calendar-day-radius);
@@ -61,13 +109,18 @@
61
109
  cursor: pointer;
62
110
  font: inherit;
63
111
  gap: var(--rt-space-0-5);
112
+ min-block-size: var(--rt-calendar-day-size);
64
113
 
65
- &:hover:not(:disabled, [data-state='start'], [data-state='end'], [data-state='in-range']) {
114
+ &:hover:not(:disabled, [data-state='start'], [data-state='end'], [data-state='in-range'], [data-state='chosen']) {
66
115
  background: var(--rt-color-bg-subtle);
67
116
  }
68
117
 
118
+ /* Выключенный день приглушён сам, без состояния: границы панели поля даты выключают
119
+ дни, не называя их прошедшими. */
69
120
  &:disabled {
121
+ color: var(--rt-color-text-muted);
70
122
  cursor: not-allowed;
123
+ opacity: 0.45;
71
124
  }
72
125
 
73
126
  &[data-state='past'],
@@ -82,13 +135,34 @@
82
135
  text-decoration: line-through;
83
136
  }
84
137
 
138
+ &[data-today] {
139
+ box-shadow: var(--rt-calendar-today-ring);
140
+ }
141
+
142
+ &:focus-visible {
143
+ outline: var(--rt-focus-ring-width) solid var(--rt-focus-ring-color);
144
+ outline-offset: var(--rt-focus-ring-offset);
145
+ }
146
+
85
147
  &[data-state='start'],
86
- &[data-state='end'] {
148
+ &[data-state='end'],
149
+ &[data-state='chosen'] {
87
150
  background: var(--rt-color-action-primary);
88
151
  color: var(--rt-color-action-on-primary);
89
152
  }
90
153
 
154
+ &[data-state='start'] {
155
+ border-end-end-radius: var(--rt-calendar-range-inner-radius);
156
+ border-start-end-radius: var(--rt-calendar-range-inner-radius);
157
+ }
158
+
159
+ &[data-state='end'] {
160
+ border-end-start-radius: var(--rt-calendar-range-inner-radius);
161
+ border-start-start-radius: var(--rt-calendar-range-inner-radius);
162
+ }
163
+
91
164
  &[data-state='in-range'] {
165
+ border-radius: var(--rt-calendar-range-inner-radius);
92
166
  background: var(--rt-color-action-primary-soft);
93
167
  color: var(--rt-color-text-link);
94
168
  font-weight: var(--rt-font-weight-semibold);
@@ -129,5 +203,8 @@
129
203
  font-size: var(--rt-text-3xs);
130
204
  }
131
205
  }
206
+
207
+ /* Шаг входа `radius` переназначает скругление дня. */
208
+ @include kv.radius-steps('--rt-calendar-day-radius');
132
209
  }
133
210
  }
@@ -1,3 +1,5 @@
1
+ @use '../../../styles/mixins' as kv;
2
+
1
3
  @layer rt-kit.components {
2
4
  /* rt-card — контейнер карточки в common/ui. ViewEncapsulation.None.
3
5
  Хост адресуется по имени элемента, а не по классу блока: класс `.rt-card` висит
@@ -64,5 +66,8 @@
64
66
  }
65
67
  }
66
68
  }
69
+
70
+ /* Шаг входа `radius` переназначает скругление карточки. */
71
+ @include kv.radius-steps('--rt-card-radius', '> .rt-card');
67
72
  }
68
73
  }
@@ -1,3 +1,5 @@
1
+ @use '../../../styles/mixins' as kv;
2
+
1
3
  @layer rt-kit.components {
2
4
  /* rt-checkbox — чекбокс в common/ui. ViewEncapsulation.None.
3
5
  Хост адресуется по имени элемента, а не по классу блока: класс `.rt-checkbox` висит
@@ -6,6 +8,9 @@
6
8
 
7
9
  rt-checkbox {
8
10
  display: inline-block;
11
+
12
+ /* Шаг входа `radius` переназначает скругление квадрата, кольцо фокуса держит своё. */
13
+ @include kv.radius-steps('--rt-checkbox-box-radius', '> .rt-checkbox');
9
14
  }
10
15
 
11
16
  /* Корень — `<button>`, а кнопке браузер даёт свой шрифт, а не шрифт страницы: `font: inherit`
@@ -27,6 +32,12 @@
27
32
  gap: var(--rt-space-sm);
28
33
  text-align: start;
29
34
 
35
+ /* Кнопка строчная и по умолчанию стоит на базовой линии строки хоста. Эту линию задаёт
36
+ первый её потомок с текстом: у пустого флажка подпись, у отмеченного значок галочки.
37
+ Линия съезжает, хост меняет высоту, и флажок вздрагивает при каждой отметке. Кнопка
38
+ стоит по верху строки, и высота хоста от содержимого квадрата больше не зависит. */
39
+ vertical-align: top;
40
+
30
41
  &:focus-visible {
31
42
  border-radius: var(--rt-checkbox-focus-radius);
32
43
  box-shadow: var(--rt-checkbox-focus-shadow);
@@ -147,7 +147,7 @@
147
147
  .rt-aside-header__back .rt-icon-button {
148
148
  --rt-icon-button-size: var(--rt-data-list-settings-aside-control-size);
149
149
  --rt-icon-button-color: var(--rt-list-settings-icon-color);
150
- --rt-icon-button-square-radius: var(--rt-radius-full);
150
+ --rt-icon-button-radius: var(--rt-radius-full);
151
151
  }
152
152
 
153
153
  .rt-aside-header__back .rt-icon {
@@ -54,7 +54,7 @@
54
54
  }
55
55
 
56
56
  .rt-icon-button {
57
- --rt-icon-button-square-radius: var(--rt-list-action-radius);
57
+ --rt-icon-button-radius: var(--rt-list-action-radius);
58
58
  --rt-icon-button-shadow: var(--rt-list-action-shadow);
59
59
  --rt-icon-button-shadow-hover: var(--rt-list-action-shadow-hover);
60
60
  --rt-icon-button-color-hover: var(--rt-list-action-color-hover);
@@ -88,7 +88,7 @@
88
88
 
89
89
  .rt-icon-button {
90
90
  --rt-icon-button-size: var(--rt-list-copy-button-size);
91
- --rt-icon-button-square-radius: var(--rt-list-copy-button-radius);
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);
94
94
 
@@ -40,7 +40,7 @@
40
40
 
41
41
  .rt-icon-button {
42
42
  --rt-icon-button-size: var(--rt-list-table-button-size);
43
- --rt-icon-button-square-radius: var(--rt-list-table-button-radius);
43
+ --rt-icon-button-radius: var(--rt-list-table-button-radius);
44
44
  }
45
45
 
46
46
  .rt-icon-button__icon {
@@ -226,7 +226,7 @@
226
226
 
227
227
  .rt-icon-button {
228
228
  --rt-icon-button-size: var(--rt-list-table-button-size);
229
- --rt-icon-button-square-radius: var(--rt-list-table-button-radius);
229
+ --rt-icon-button-radius: var(--rt-list-table-button-radius);
230
230
  }
231
231
 
232
232
  .rt-icon-button__icon {
@@ -11,31 +11,50 @@
11
11
  | вход | тип | умолчание |
12
12
  | ------------- | -------------------------------------- | --------- |
13
13
  | `type` | `'date' \| 'time' \| 'datetime-local'` | `'date'` |
14
- | `min` / `max` | `string \| null` (ISO) | `null` |
14
+ | `min` / `max` | `string \| null` (форма значения) | `null` |
15
+ | `minuteStep` | `number` | `5` |
15
16
 
16
- Значение — **строка ISO**, ровно та, что отдаёт нативное поле (`2026-03-15`, `09:30`,
17
- `2026-03-15T09:30`).
17
+ Значение — **строка** той же формы, что отдавало нативное поле: `2026-03-15`, `09:30`,
18
+ `2026-03-15T09:30`; пусто — `''`.
18
19
 
19
20
  ## Главное, что нужно знать
20
21
 
21
- **Своего календаря кит не везёт — рисует его браузер.** Отсюда всё остальное: раскладка,
22
- формат ввода и клавиатура всегда совпадают с системными, а вид поля на разных платформах
23
- отличается. Если нужен единый календарь во всех браузерах, этот компонент не подойдёт.
22
+ **Панель своя, одна во всех браузерах.** Кнопка в конце поля открывает `rt-date-panel`: месяц с
23
+ листанием и выбором месяца и года, колонки часов и минут, подвал «Сегодня», «Сейчас» и «Готово»
24
+ или «Применить». На широком экране панель стоит в поповере, на узком — в нижней шторке. Признак
25
+ узкого экрана даёт `BreakpointsService.narrow`. Договорённость — `docs/specs/ui-kit-v2/date-panel/`.
24
26
 
25
- **Значение — строка, а не `Date`.** Разбор и часовые пояса остаются на стороне потребителя;
26
- компонент не трогает ни то, ни другое.
27
+ **Текст в поле — дата в порядке языка интерфейса.** Под `ru` это `01.08.2026`, под `en-US` —
28
+ «08/01/2026», время всегда `HH:mm`. Язык берётся из `RT_KIT_LOCALE`: приложение, меняющее язык на
29
+ ходу, меняет и порядок. Подсказка в пустом поле — та же форма буквами кита (`дд.мм.гггг`). Набранный
30
+ текст читается в том же порядке, вставленная форма значения (`2026-08-01`) тоже. Текст, который
31
+ читается как значение в границах, становится значением. Любой другой оставляет значение прежним и
32
+ помечает поле ошибкой: поле ничего не исправляет молча и не отдаёт в форму нечитаемую строку.
33
+
34
+ **Значение — строка, а не `Date`.** Разбор и часовые пояса остаются на стороне потребителя.
35
+
36
+ **Вся арифметика дат — в чистых модулях.** `rt-date-panel.logic.ts` — чтение и запись значения,
37
+ месяц по локали, границы, колонки времени и клавиши сетки; `rt-date-text.logic.ts` — текст поля и
38
+ его разбор. Панель и поле — тонкие обёртки.
27
39
 
28
40
  ## Края
29
41
 
42
+ - В узком поле подсказка обрезается многоточием. Пока поле пустое, форма значения целиком видна
43
+ при наведении.
44
+ - `min`/`max` выключают дни и время за границами и останавливают листание на месяце границы.
45
+ - Для даты клик по дню выбирает его и закрывает панель. Для времени и даты со временем выбор —
46
+ черновик: значение меняется только кнопкой «Готово» или «Применить», закрытие панели его
47
+ сбрасывает.
48
+ - «Сегодня» выключено, когда сегодняшний день лежит за границами. «Сейчас» ставит время,
49
+ округлённое вниз до `minuteStep`.
50
+ - Клавиши в месяце: стрелки двигают день, PageUp/PageDown — месяц, Home/End — края недели,
51
+ Enter выбирает, Escape закрывает панель.
52
+ - На узком экране у даты со временем переключатель «Дата | Время» показывает месяц или колонки.
30
53
  - В плоском режиме чтения (включает [`rt-field`](../field/CONTEXT.md)) значение переписывается
31
54
  на язык интерфейса через `Intl.DateTimeFormat`: `2026-03-15` → `15 мар. 2026 г.` под `ru`.
32
- - Нераспознанная строка в этом режиме показывается **как есть**, а не исчезает: значение может
33
- прийти из формы, минуя нативное поле.
34
- - Пустое значение рисуется прочерком.
35
- - `min`/`max` уезжают на нативное поле; проверку выхода за границы делает браузер, отдельного
36
- валидатора здесь нет.
55
+ Нераспознанная строка показывается как есть, пустое значение — прочерком.
37
56
 
38
57
  ## Рядом
39
58
 
40
59
  - [`rt-input`](../input/CONTEXT.md) с `type="time"` — когда нужно только время без обёртки.
41
- - [`rt-calendar`](../calendar/CONTEXT.md) — календарь-витрина, а не поле ввода.
60
+ - [`rt-calendar`](../calendar/CONTEXT.md) — сетка месяца, на которой стоит панель.
@@ -0,0 +1,155 @@
1
+ @layer rt-kit.components {
2
+ /* rt-date-panel — ViewEncapsulation.None: правила таргетируют BEM-класс блока, класс ставит host. */
3
+
4
+ .rt-date-panel {
5
+ /* Высота ячейки колонок времени и месяцев. */
6
+ --rt-date-panel-cell-size: var(--rt-control-height-sm);
7
+
8
+ /* Скругление ячеек колонок времени и месяцев. */
9
+ --rt-date-panel-cell-radius: var(--rt-radius-md);
10
+
11
+ /* Толщина черты над подвалом. */
12
+ --rt-date-panel-divider-width: var(--rt-border-width-thin);
13
+
14
+ /* Видимая высота колонки времени: семь ячеек с шестью зазорами, остальное прокручивается. */
15
+ --rt-date-panel-column-height: calc(var(--rt-date-panel-cell-size) * 7 + var(--rt-space-0-5) * 6);
16
+
17
+ display: flex;
18
+ flex-direction: column;
19
+ padding: var(--rt-space-4);
20
+ gap: var(--rt-space-4);
21
+
22
+ &__body {
23
+ display: flex;
24
+ align-items: flex-start;
25
+ gap: var(--rt-space-4);
26
+ }
27
+
28
+ /* Панель показывает один месяц: сетка календаря не держит пустую вторую колонку.
29
+ Свойство ставится на сам узел календаря — корень его блока объявляет своё, и правило
30
+ вложено в блок панели, чтобы быть сильнее его, а не зависеть от порядка подключения. */
31
+ & &__calendar {
32
+ --rt-calendar-month-count: 1;
33
+ --rt-calendar-day-justify: center;
34
+ }
35
+
36
+ &__calendar,
37
+ &__months {
38
+ flex: 1 1 auto;
39
+ min-inline-size: calc(var(--rt-size-10) * 7);
40
+ }
41
+
42
+ &__months-header {
43
+ display: flex;
44
+ align-items: center;
45
+ justify-content: space-between;
46
+ margin-bottom: var(--rt-space-4);
47
+ }
48
+
49
+ &__year {
50
+ color: var(--rt-color-text-primary);
51
+ font-weight: var(--rt-font-weight-semibold);
52
+ }
53
+
54
+ &__month-grid {
55
+ display: grid;
56
+ gap: var(--rt-space-1);
57
+ grid-template-columns: repeat(3, 1fr);
58
+ }
59
+
60
+ &__time {
61
+ display: flex;
62
+ gap: var(--rt-space-1);
63
+ }
64
+
65
+ &__column {
66
+ position: relative;
67
+ display: flex;
68
+ flex-direction: column;
69
+ gap: var(--rt-space-0-5);
70
+ max-block-size: var(--rt-date-panel-column-height);
71
+ overflow-y: auto;
72
+ overscroll-behavior: contain;
73
+ scrollbar-width: thin;
74
+ }
75
+
76
+ &__cell {
77
+ flex: 0 0 auto;
78
+ padding: 0 var(--rt-space-2);
79
+ border: none;
80
+ border-radius: var(--rt-date-panel-cell-radius);
81
+ background: none;
82
+ color: var(--rt-color-text-primary);
83
+ cursor: pointer;
84
+ font: inherit;
85
+ font-size: var(--rt-text-sm);
86
+ font-variant-numeric: tabular-nums;
87
+ min-block-size: var(--rt-date-panel-cell-size);
88
+ min-inline-size: var(--rt-control-height-md);
89
+
90
+ &:hover:not(:disabled, [aria-pressed='true']) {
91
+ background: var(--rt-color-bg-subtle);
92
+ }
93
+
94
+ &:focus-visible {
95
+ outline: var(--rt-focus-ring-width) solid var(--rt-focus-ring-color);
96
+ outline-offset: var(--rt-focus-ring-offset);
97
+ }
98
+
99
+ &[aria-pressed='true'] {
100
+ background: var(--rt-color-action-primary);
101
+ color: var(--rt-color-action-on-primary);
102
+ }
103
+
104
+ &:disabled {
105
+ color: var(--rt-color-text-muted);
106
+ cursor: not-allowed;
107
+ opacity: 0.45;
108
+ }
109
+ }
110
+
111
+ &__footer {
112
+ display: flex;
113
+ justify-content: flex-end;
114
+ padding-top: var(--rt-space-2);
115
+ border-top: var(--rt-date-panel-divider-width) solid var(--rt-color-border-subtle);
116
+ gap: var(--rt-space-2);
117
+ }
118
+
119
+ /* Дата без времени: «Сегодня» стоит по центру под месяцем. */
120
+ &:not(&--with-time) &__footer {
121
+ justify-content: center;
122
+ }
123
+
124
+ /* Нижняя шторка: дни и ячейки под палец, всё — в одну колонку на всю ширину. */
125
+ &--sheet {
126
+ --rt-date-panel-cell-size: calc(var(--rt-size-10) + var(--rt-size-1));
127
+
128
+ padding-inline: 0;
129
+ }
130
+
131
+ /* Календарь объявляет размер дня на корне своего блока, поэтому свойство ставится на сам
132
+ узел календаря — унаследованное от панели корень календаря перекрыл бы. */
133
+ &--sheet &__calendar {
134
+ --rt-calendar-day-size: var(--rt-date-panel-cell-size);
135
+ }
136
+
137
+ &--sheet &__body {
138
+ flex-direction: column;
139
+ align-items: stretch;
140
+ }
141
+
142
+ &--sheet &__calendar,
143
+ &--sheet &__months {
144
+ min-inline-size: 0;
145
+ }
146
+
147
+ &--sheet &__time {
148
+ justify-content: center;
149
+ }
150
+
151
+ &--sheet &__column {
152
+ flex: 1 1 0;
153
+ }
154
+ }
155
+ }