@sberbusiness/triplex-next-mcp-server 0.24.0-beta2 → 0.36.0-beta0
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 +10 -0
- package/bundle/components/BodyPage.md +186 -0
- package/bundle/components/Button.md +90 -85
- package/bundle/components/ButtonDropdown.md +28 -70
- package/bundle/components/ButtonIcon.md +35 -48
- package/bundle/components/Checkbox.md +43 -122
- package/bundle/components/CheckboxXGroup.md +109 -46
- package/bundle/components/CheckboxYGroup.md +77 -49
- package/bundle/components/CollapsibleTree.md +581 -0
- package/bundle/components/CollapsibleTreeExtended.md +418 -0
- package/bundle/components/EmptyView.md +14 -15
- package/bundle/components/FooterPage.md +203 -0
- package/bundle/components/Gap.md +115 -57
- package/bundle/components/HeaderPage.md +226 -0
- package/bundle/components/HelpBox.md +45 -84
- package/bundle/components/ImageGallery.md +423 -0
- package/bundle/components/ImageGalleryExtended.md +606 -0
- package/bundle/components/List.md +194 -186
- package/bundle/components/ListItem.md +251 -0
- package/bundle/components/ListItemControlsButton.md +103 -0
- package/bundle/components/ListItemControlsButtonDropdown.md +107 -0
- package/bundle/components/ListItemSelectable.md +99 -0
- package/bundle/components/ListItemTable.md +390 -0
- package/bundle/components/ListMaster.md +877 -156
- package/bundle/components/ListMasterFooter.md +80 -0
- package/bundle/components/ListMasterHeader.md +86 -0
- package/bundle/components/ListSortable.md +153 -0
- package/bundle/components/ListSortableItem.md +175 -0
- package/bundle/components/ModalWindow.md +427 -237
- package/bundle/components/MonthYearField.md +145 -109
- package/bundle/components/Notification.md +625 -155
- package/bundle/components/Overlay.md +271 -170
- package/bundle/components/Page.md +283 -186
- package/bundle/components/Pagination.md +206 -229
- package/bundle/guides/codestyle.md +38 -11
- package/bundle/guides/commits.md +1 -2
- package/bundle/guides/context.md +34 -30
- package/bundle/guides/stories.md +110 -40
- package/bundle/guides/template.md +3 -7
- package/bundle/guides/tests.md +6 -2
- package/bundle/manifest.json +194 -24
- package/bundle/release-notes/1.26.0.mdx +33 -2
- package/bundle/release-notes/1.27.0.mdx +43 -0
- package/bundle/release-notes/1.28.0.mdx +25 -0
- package/bundle/release-notes/1.29.0.mdx +47 -0
- package/bundle/release-notes/1.30.0.mdx +56 -0
- package/bundle/release-notes/1.31.0.mdx +52 -0
- package/bundle/release-notes/1.32.0.mdx +35 -0
- package/bundle/release-notes/1.33.0.mdx +61 -0
- package/bundle/release-notes/1.34.0.mdx +35 -0
- package/bundle/release-notes/1.35.0.mdx +21 -0
- package/bundle/release-notes/1.35.1.mdx +11 -0
- package/bundle/release-notes/1.36.0.mdx +21 -0
- package/bundle/release-notes/1.37.0.mdx +30 -0
- package/package.json +1 -1
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: Pagination
|
|
3
3
|
category: Navigation
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
related:
|
|
5
|
+
- PaginationExtended
|
|
6
|
+
- PaginationNavigation
|
|
7
|
+
- PaginationNavigationButton
|
|
8
|
+
- PaginationNavigationExtended
|
|
9
|
+
- PaginationNavigationExtendedItem
|
|
10
|
+
- PaginationPageButton
|
|
11
|
+
- PaginationPageEllipsis
|
|
12
|
+
- PaginationSelect
|
|
13
|
+
- SelectField
|
|
14
|
+
- ButtonIcon
|
|
15
|
+
- ButtonBase
|
|
16
|
+
tokens:
|
|
17
|
+
- --triplex-next-Pagination-PageButton_Background_Hover
|
|
18
|
+
- --triplex-next-Pagination-PageButton_Background_Active
|
|
19
|
+
- --triplex-next-Pagination-PageButton_Background_Selected
|
|
20
|
+
- --triplex-next-Pagination-PageButton_BorderColor_Focus
|
|
8
21
|
stories: stories/Pagination/Pagination.stories.tsx
|
|
9
22
|
version: "1.0"
|
|
10
23
|
---
|
|
@@ -13,286 +26,250 @@ version: "1.0"
|
|
|
13
26
|
|
|
14
27
|
## Назначение
|
|
15
28
|
|
|
16
|
-
|
|
17
|
-
**`PaginationSelect`** (выбор количества элементов на странице) +
|
|
18
|
-
**`PaginationNavigation`** (стрелки prev/next и кнопки страниц с
|
|
19
|
-
ellipsis'ами). Сам `Pagination` — лишь сшивка через
|
|
20
|
-
`PaginationExtended` (контейнер `<nav>`), управление условным
|
|
21
|
-
рендером и проксирование props'ов.
|
|
29
|
+
Составной компонент пагинации: навигация по страницам (кнопки «Назад»/«Вперёд», номера страниц, многоточия) и опциональный выбор количества элементов на странице. `Pagination` — готовая точка входа, которая собирает `PaginationSelect` и `PaginationNavigation` внутри контейнера `PaginationExtended`.
|
|
22
30
|
|
|
23
|
-
|
|
24
|
-
`Item` / `PaginationPageButton` / `PaginationPageEllipsis` /
|
|
25
|
-
`PaginationNavigationButton`) экспортируются отдельно — для **кастомной
|
|
26
|
-
сборки** пагинации, когда стандартная не подходит.
|
|
31
|
+
Используй когда: нужно дать пользователю переход по страницам списка/таблицы, при необходимости — с выбором размера страницы.
|
|
27
32
|
|
|
28
|
-
|
|
29
|
-
нестандартной — собирай из `PaginationExtended` + примитивов.
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
## Файловая структура
|
|
34
|
-
|
|
35
|
-
```text
|
|
36
|
-
src/components/Pagination/
|
|
37
|
-
├── Pagination.tsx # forwardRef; склейка Select + Navigation
|
|
38
|
-
├── components/
|
|
39
|
-
│ ├── PaginationExtended.tsx # forwardRef; <nav> wrapper
|
|
40
|
-
│ ├── PaginationSelect.tsx # forwardRef; SelectField (size SM)
|
|
41
|
-
│ ├── PaginationNavigation.tsx # forwardRef; prev/pages/next + ellipsis
|
|
42
|
-
│ ├── PaginationNavigationExtended.tsx # forwardRef; <ul>
|
|
43
|
-
│ ├── PaginationNavigationExtendedItem.tsx # forwardRef; <li>
|
|
44
|
-
│ ├── PaginationNavigationButton.tsx # forwardRef; ButtonIcon SQUIRCLE + caret-icon
|
|
45
|
-
│ ├── PaginationPageButton.tsx # forwardRef; ButtonBase + Text B3
|
|
46
|
-
│ └── PaginationPageEllipsis.tsx # forwardRef; Text B3 "..."
|
|
47
|
-
├── utils/paginationUtils.tsx # createPagesArray + generateRange + PAGINATION_ELLIPSIS_VALUE
|
|
48
|
-
├── enums.ts # EPaginationNavigationIconDirection (BACK | NEXT)
|
|
49
|
-
├── index.ts # Barrel: всё
|
|
50
|
-
├── styles/*.module.less
|
|
51
|
-
└── __tests__/
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
---
|
|
55
|
-
|
|
56
|
-
## Compound-структура
|
|
57
|
-
|
|
58
|
-
```tsx
|
|
59
|
-
<Pagination
|
|
60
|
-
paginationSelectProps={{
|
|
61
|
-
paginationLabel: "На странице",
|
|
62
|
-
value: pageSize,
|
|
63
|
-
options: [
|
|
64
|
-
{ value: 10, label: "10" },
|
|
65
|
-
{ value: 25, label: "25" },
|
|
66
|
-
],
|
|
67
|
-
onChange: setPageSize,
|
|
68
|
-
}}
|
|
69
|
-
paginationNavigationProps={{
|
|
70
|
-
currentPage,
|
|
71
|
-
totalPages,
|
|
72
|
-
onCurrentPageChange: setCurrentPage,
|
|
73
|
-
boundaryCount: 1,
|
|
74
|
-
siblingCount: 1,
|
|
75
|
-
}}
|
|
76
|
-
/>
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
Кастомная сборка:
|
|
80
|
-
|
|
81
|
-
```tsx
|
|
82
|
-
<PaginationExtended>
|
|
83
|
-
<PaginationNavigationExtended>
|
|
84
|
-
<PaginationNavigationExtendedItem>
|
|
85
|
-
<PaginationNavigationButton direction={EPaginationNavigationIconDirection.BACK} />
|
|
86
|
-
</PaginationNavigationExtendedItem>
|
|
87
|
-
<PaginationNavigationExtendedItem>
|
|
88
|
-
<PaginationPageButton isCurrent>1</PaginationPageButton>
|
|
89
|
-
</PaginationNavigationExtendedItem>
|
|
90
|
-
...
|
|
91
|
-
</PaginationNavigationExtended>
|
|
92
|
-
</PaginationExtended>
|
|
93
|
-
```
|
|
33
|
+
Не используй когда: данных немного и помещаются на один экран (при `totalPages <= 1` навигация не рендерится); нужна бесконечная прокрутка вместо постраничной.
|
|
94
34
|
|
|
95
35
|
---
|
|
96
36
|
|
|
97
37
|
## Варианты и props
|
|
98
38
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
| Prop | Тип | Описание |
|
|
102
|
-
|---|---|---|
|
|
103
|
-
| `paginationSelectProps?` | `IPaginationSelectProps` | Если **не передан** — Select не рендерится. |
|
|
104
|
-
| `paginationNavigationProps` | `IPaginationNavigationProps` | Обязателен. Если `totalPages <= 1` — Navigation не рендерится. |
|
|
105
|
-
| `...IPaginationExtendedProps` | `HTMLAttributes<HTMLElement>` | На `<nav>`. |
|
|
39
|
+
`Pagination` — управляемый компонент: текущая страница и размер страницы хранятся в стейте потребителя и передаются через колбэки. Компонент не хранит состояние страницы сам.
|
|
106
40
|
|
|
107
|
-
###
|
|
108
|
-
|
|
109
|
-
```ts
|
|
110
|
-
extends Omit<ISelectFieldProps, "size" | "value">
|
|
111
|
-
extends Required<Pick<ISelectFieldProps, "value">>
|
|
112
|
-
```
|
|
41
|
+
### `Pagination` (точка входа)
|
|
113
42
|
|
|
114
|
-
| Prop | Тип | Описание |
|
|
115
|
-
|
|
116
|
-
| `
|
|
117
|
-
| `
|
|
118
|
-
| `
|
|
119
|
-
|
|
120
|
-
- **`size` захардкожен `EComponentSize.SM`**.
|
|
121
|
-
- **`mobileTitle = paginationLabel`** — тот же текст для мобильного header'а.
|
|
122
|
-
- **`targetProps.fieldLabel = ""`** — лейбл внутри SelectField очищается (label рисуется отдельно слева).
|
|
123
|
-
- **`aria-labelledby={instanceId}`** + `Text id={instanceId}` — связь label ↔ control.
|
|
124
|
-
- `instanceId = "Pagination-{lodash uniqueId()}"` — **SSR-небезопасно** (два рендера дадут разные id, гидрация может ругаться).
|
|
43
|
+
| Prop | Тип | Обяз. | Описание |
|
|
44
|
+
|---|---|---|---|
|
|
45
|
+
| `paginationNavigationProps` | `IPaginationNavigationProps` | да | Настройки навигации по страницам. Навигация рендерится только при `totalPages > 1`. |
|
|
46
|
+
| `paginationSelectProps` | `IPaginationSelectProps` | нет | Настройки селекта размера страницы. Если не передан — селект не отображается. |
|
|
47
|
+
| `...rest` | `IPaginationExtendedProps` | — | Прокидывается в корневой `<nav>` (className, aria-атрибуты и т.д.). |
|
|
125
48
|
|
|
126
|
-
### PaginationNavigation
|
|
49
|
+
### `PaginationNavigation` props (через `paginationNavigationProps`)
|
|
127
50
|
|
|
128
|
-
| Prop | Тип |
|
|
51
|
+
| Prop | Тип | По умолчанию | Описание |
|
|
129
52
|
|---|---|---|---|
|
|
130
|
-
| `currentPage` | `number` | — |
|
|
131
|
-
| `totalPages` | `number` | — |
|
|
132
|
-
| `onCurrentPageChange` | `(page: number) => void` | — |
|
|
53
|
+
| `currentPage` | `number` | — | Номер текущей страницы (нумерация с 1). |
|
|
54
|
+
| `totalPages` | `number` | — | Общее число страниц. |
|
|
55
|
+
| `onCurrentPageChange` | `(page: number) => void` | — | Колбэк смены страницы. Вызывается с целевым номером. |
|
|
133
56
|
| `boundaryCount` | `number` | `0` | Сколько страниц всегда показывать в начале и в конце. |
|
|
134
|
-
| `siblingCount` | `number` | `0` | Сколько
|
|
135
|
-
| `buttonPrevProps
|
|
136
|
-
| `buttonNextProps?` | `Omit<...>` | — | Доп. props на «вперёд». |
|
|
137
|
-
|
|
138
|
-
- **prev disabled при `currentPage === 1`** (или `buttonPrevProps?.disabled`).
|
|
139
|
-
- **next disabled при `currentPage === totalPages`** (или `buttonNextProps?.disabled`).
|
|
140
|
-
- Рендерит prev → массив страниц от `createPagesArray(...)` → next.
|
|
141
|
-
|
|
142
|
-
### PaginationNavigationButton — `IPaginationNavigationButtonProps`
|
|
57
|
+
| `siblingCount` | `number` | `0` | Сколько соседних страниц показывать вокруг текущей. |
|
|
58
|
+
| `buttonPrevProps` / `buttonNextProps` | `Omit<IPaginationNavigationButtonProps, "direction" \| "children">` | — | Доп. настройки кнопок навигации. |
|
|
143
59
|
|
|
144
|
-
|
|
145
|
-
extends Omit<IButtonIconProps, "shape" | "active" | "children">
|
|
146
|
-
children?: never
|
|
147
|
-
direction: EPaginationNavigationIconDirection
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
- Иконка: `CaretleftStrokeSrvIcon24 paletteIndex={5}`. Для `NEXT` — добавляется `styles.directionIconNext` (поворот через CSS).
|
|
151
|
-
- `shape={EButtonIconShape.SQUIRCLE}` — захардкожен.
|
|
152
|
-
- `children?: never` — фиксированная иконка.
|
|
153
|
-
|
|
154
|
-
### PaginationPageButton — `TPaginationPageButtonProps`
|
|
155
|
-
|
|
156
|
-
| Prop | Тип | Описание |
|
|
157
|
-
|---|---|---|
|
|
158
|
-
| `isCurrent?` | `boolean` | Подсветка текущей. **`aria-live="polite"`** при `isCurrent` — screen reader озвучит при смене. |
|
|
159
|
-
| `children` | `ReactNode` | Номер страницы. |
|
|
160
|
-
| `onClick` | `() => void` | Клик. |
|
|
60
|
+
Логика расстановки видимых страниц и многоточий — в `utils/paginationUtils.tsx` (`PaginationUtils.createPagesArray`). При больших `totalPages` и нулевых `boundaryCount`/`siblingCount` отображается минимальный набор; увеличение этих значений раскрывает больше номеров и добавляет многоточия по краям. Места многоточий помечаются sentinel-значением `PAGINATION_ELLIPSIS_VALUE` (`-1`) в массиве страниц.
|
|
161
61
|
|
|
162
|
-
|
|
62
|
+
### `PaginationSelect` props (через `paginationSelectProps`)
|
|
163
63
|
|
|
164
|
-
|
|
64
|
+
Расширяет `ISelectFieldProps` (без `size`, с обязательным `value`) и добавляет `paginationLabel: React.ReactNode` — текст лейбла перед селектом. Размер селекта зафиксирован как `EComponentSize.SM`. `value`, `options`, `onChange` — управляются потребителем.
|
|
165
65
|
|
|
166
|
-
|
|
66
|
+
### Subкомпоненты для кастомной компоновки
|
|
167
67
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
- `<nav>` контейнер. `data-tx={pkg.version}`.
|
|
171
|
-
|
|
172
|
-
### PaginationNavigationExtended/Item
|
|
173
|
-
|
|
174
|
-
- `<ul>` / `<li>` — семантический список для пагинации.
|
|
175
|
-
|
|
176
|
-
### enums.ts
|
|
177
|
-
|
|
178
|
-
- `EPaginationNavigationIconDirection.BACK | NEXT` (numeric enum: 0/1).
|
|
68
|
+
Для нестандартной раскладки используется `PaginationExtended` напрямую с вложенными `PaginationNavigation` и `PaginationSelect` (см. story `Extended`). Низкоуровневые части (`PaginationNavigationExtended`, `PaginationNavigationExtendedItem`, `PaginationPageButton`, `PaginationPageEllipsis`, `PaginationNavigationButton`) экспортируются для построения полностью кастомной навигации, но обычно используются неявно через `PaginationNavigation`.
|
|
179
69
|
|
|
180
70
|
---
|
|
181
71
|
|
|
182
|
-
##
|
|
72
|
+
## Дизайн-токены
|
|
183
73
|
|
|
184
|
-
|
|
74
|
+
Собственные токены использует только `PaginationPageButton`:
|
|
185
75
|
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
|
|
76
|
+
```text
|
|
77
|
+
--triplex-next-Pagination-PageButton_Background_Hover
|
|
78
|
+
--triplex-next-Pagination-PageButton_Background_Active
|
|
79
|
+
--triplex-next-Pagination-PageButton_Background_Selected
|
|
80
|
+
--triplex-next-Pagination-PageButton_BorderColor_Focus
|
|
189
81
|
```
|
|
190
82
|
|
|
191
|
-
|
|
192
|
-
- Navigation — рендерится только при `totalPages > 1` (на 1 странице — нечего листать).
|
|
193
|
-
|
|
194
|
-
### `PaginationUtils.createPagesArray`
|
|
83
|
+
Остальные части наследуют визуал от переиспользуемых компонентов: кнопки навигации — от `ButtonIcon`, кнопка-страница — от `ButtonBase`, селект — от `SelectField`, текст — от `Typography` (`Text`).
|
|
195
84
|
|
|
196
|
-
|
|
197
|
-
// startPages | (ellipsis | next page) | siblings around current | (ellipsis | prev page) | endPages
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
- `boundaryCount` — кол-во **всегда видимых** в начале/конце.
|
|
201
|
-
- `siblingCount` — кол-во **соседей** вокруг текущей.
|
|
202
|
-
- Если соседи примыкают к boundary — ellipsis заменяется на одну страницу (без «1 ... 2 3 4» — будет «1 2 3 4»).
|
|
203
|
-
- Возвращает массив `number[]`, где **`PAGINATION_ELLIPSIS_VALUE = -1`** — sentinel для ellipsis.
|
|
204
|
-
- Использует `lodash-es/range`.
|
|
85
|
+
---
|
|
205
86
|
|
|
206
|
-
|
|
87
|
+
## Инварианты
|
|
207
88
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
89
|
+
- `forwardRef` на всех компонентах семейства — не убирать. Refs: `Pagination` → `HTMLSpanElement` (фактически прокидывается в корневой `<nav>` через `PaginationExtended`, ref-тип которого `HTMLElement`), `PaginationNavigation`/`PaginationNavigationExtended` → `HTMLUListElement`, `PaginationNavigationExtendedItem` → `HTMLLIElement`, `PaginationSelect` → `HTMLDivElement`, кнопки → `HTMLButtonElement`, ellipsis → `HTMLSpanElement`.
|
|
90
|
+
- Публичный API не менять: имена и обязательность props (`paginationNavigationProps` — обязателен, `paginationSelectProps` — опционален), enum `EPaginationNavigationIconDirection` (`BACK`/`NEXT`), barrel-экспорты из `index.ts`.
|
|
91
|
+
- Корневой DOM-элемент `Pagination`/`PaginationExtended` — `<nav>`; навигация по страницам — семантический список `<ul>/<li>`. Не менять без обсуждения: семантика участвует в accessibility-контракте.
|
|
92
|
+
- Навигация рендерится только при `totalPages > 1` — поведение публичное, на него опираются потребители.
|
|
93
|
+
- Логику `PaginationUtils.createPagesArray` / `generatePageRanges` / `generateRange` не менять без перегенерации `__tests__/paginationUtils.test.tsx` — там зафиксированы граничные случаи раскладки.
|
|
94
|
+
- `PAGINATION_ELLIPSIS_VALUE = -1` — sentinel в массиве страниц, на него завязан рендер многоточия.
|
|
212
95
|
|
|
213
|
-
|
|
96
|
+
---
|
|
214
97
|
|
|
215
|
-
|
|
98
|
+
## Accessibility
|
|
216
99
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
100
|
+
- Корень — `<nav>`, навигация — список `<ul>/<li>`, что даёт ассистивным технологиям корректную семантику пагинации.
|
|
101
|
+
- Кнопки «Назад»/«Вперёд» автоматически получают `disabled` на первой/последней странице соответственно.
|
|
102
|
+
- Текущая страница (`PaginationPageButton` с `isCurrent`) помечается `aria-live="polite"`, чтобы смена страницы озвучивалась скринридером.
|
|
103
|
+
- `PaginationSelect` связывает лейбл и контрол через `aria-labelledby` (генерируемый `instanceId`), лейбл также используется как `mobileTitle`.
|
|
104
|
+
- Текст кнопок навигации не хардкодится в компоненте — при необходимости потребитель передаёт `aria-label` через `buttonPrevProps`/`buttonNextProps` (библиотека мультиязычная).
|
|
220
105
|
|
|
221
|
-
|
|
106
|
+
---
|
|
222
107
|
|
|
223
|
-
|
|
108
|
+
## Связанные компоненты
|
|
224
109
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
110
|
+
- `PaginationExtended` — контейнер `<nav>` для кастомной компоновки пагинации.
|
|
111
|
+
- `PaginationNavigation` — блок навигации по страницам (используется внутри `Pagination`, доступен отдельно).
|
|
112
|
+
- `PaginationSelect` — селект размера страницы поверх `SelectField`.
|
|
113
|
+
- `PaginationNavigationExtended` / `PaginationNavigationExtendedItem` — список `<ul>` и его элемент `<li>` для построения кастомной навигации.
|
|
114
|
+
- `PaginationPageButton` — кнопка-страница (поверх `ButtonBase`).
|
|
115
|
+
- `PaginationPageEllipsis` — многоточие, заменяющее группу скрытых страниц.
|
|
116
|
+
- `PaginationNavigationButton` — кнопка «Назад»/«Вперёд» (поверх `ButtonIcon`), направление задаётся `EPaginationNavigationIconDirection`.
|
|
228
117
|
|
|
229
|
-
|
|
118
|
+
---
|
|
230
119
|
|
|
231
|
-
|
|
120
|
+
## Stories
|
|
232
121
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
```
|
|
122
|
+
Основные истории: `stories/Pagination/Pagination.stories.tsx`
|
|
123
|
+
Файлы примеров: `stories/Pagination/examples/Pagination/`
|
|
236
124
|
|
|
237
|
-
|
|
238
|
-
|
|
125
|
+
| Story | Example file | Что демонстрирует |
|
|
126
|
+
|---|---|---|
|
|
127
|
+
| `Playground` | `Playground.tsx` | Интерактивный контроль `currentPage`, `totalPages`, `boundaryCount`, `siblingCount`, `hidePaginationSelect`, `paginationLabel`, `className` |
|
|
128
|
+
| `Default` | `Default.tsx` | Базовая навигация без селекта (50 элементов, размер страницы 10) |
|
|
129
|
+
| `WithSelectField` | `WithSelectField.tsx` | Навигация с селектом размера страницы, `boundaryCount`/`siblingCount = 1` |
|
|
130
|
+
| `Extended` | `Extended.tsx` | Кастомная компоновка через `PaginationExtended` + `PaginationNavigation` + `PaginationSelect` |
|
|
131
|
+
| `VisualTests` | — | Скриншот-регрессия: короткая навигация, многоточия слева/справа/с обеих сторон, disabled-крайние кнопки, вариант с селектом |
|
|
239
132
|
|
|
240
133
|
---
|
|
241
134
|
|
|
242
|
-
##
|
|
135
|
+
## История изменений
|
|
243
136
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
-
|
|
247
|
-
- **`PAGINATION_ELLIPSIS_VALUE = -1`** — публичная константа-sentinel.
|
|
248
|
-
- **`PaginationSelect.size = SM`** — захардкожен.
|
|
249
|
-
- **`PaginationSelect.targetProps.fieldLabel = ""`** — внутренний label очищается.
|
|
250
|
-
- **`PaginationNavigationButton.shape = SQUIRCLE`**, иконка `CaretleftStrokeSrvIcon24` — фиксированы; `children: never`.
|
|
251
|
-
- **`PaginationPageButton.aria-live="polite"`** при `isCurrent` — публичный a11y-контракт.
|
|
252
|
-
- **`uniqueId()`** в SelectId — SSR-небезопасно.
|
|
253
|
-
- **`<nav>` корень PaginationExtended** + `<ul>`/`<li>` для Navigation — семантическая структура.
|
|
254
|
-
- **`createPagesArray` зависит от lodash-es `range`**.
|
|
255
|
-
- **`EPaginationNavigationIconDirection`** — numeric enum (0/1), не string.
|
|
256
|
-
- **ForwardRef** на всех уровнях.
|
|
137
|
+
| Дата | Изменение |
|
|
138
|
+
|---|---|
|
|
139
|
+
| 2026-06-22 | Создан документ |
|
|
257
140
|
|
|
258
141
|
---
|
|
259
142
|
|
|
260
|
-
##
|
|
143
|
+
## Примеры использования
|
|
261
144
|
|
|
262
|
-
|
|
263
|
-
- `aria-live="polite"` на текущей странице — озвучивание при смене.
|
|
264
|
-
- `aria-labelledby` связывает label PaginationSelect с самим SelectField.
|
|
265
|
-
- **Нет `aria-label="Pagination"`** на `<nav>` — потребитель должен передать через `...rest` (иначе screen reader скажет просто «navigation»).
|
|
266
|
-
- **Иконки prev/next без `aria-label`** — `ButtonIcon` сам по себе не озвучивает направление. Потребитель должен передать `buttonPrevProps={{ "aria-label": "Предыдущая" }}` и т.п.
|
|
267
|
-
- `disabled` корректно через `<button disabled>` — клавиатура и SR обработают.
|
|
145
|
+
### Default
|
|
268
146
|
|
|
269
|
-
|
|
147
|
+
`stories/Pagination/examples/Pagination/Default.tsx`
|
|
270
148
|
|
|
271
|
-
|
|
149
|
+
```tsx
|
|
150
|
+
import React, { useState } from "react";
|
|
151
|
+
import { Pagination } from "@sberbusiness/triplex-next";
|
|
272
152
|
|
|
273
|
-
|
|
153
|
+
export const Default = () => {
|
|
154
|
+
const totalItems = 50;
|
|
155
|
+
const pageSize = 10;
|
|
156
|
+
const [page, setPage] = useState(1);
|
|
274
157
|
|
|
275
|
-
|
|
158
|
+
const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
|
|
276
159
|
|
|
277
|
-
|
|
160
|
+
return <Pagination paginationNavigationProps={{ currentPage: page, totalPages, onCurrentPageChange: setPage }} />;
|
|
161
|
+
};
|
|
162
|
+
```
|
|
278
163
|
|
|
279
|
-
|
|
280
|
-
- `ButtonIcon`, `ButtonBase` — кнопки.
|
|
281
|
-
- `Text` (Typography) — текст.
|
|
282
|
-
- `CaretleftStrokeSrvIcon24` — единственная иконка стрелки.
|
|
283
|
-
- `lodash-es/range`, `lodash-es/uniqueId`.
|
|
164
|
+
### WithSelectField
|
|
284
165
|
|
|
285
|
-
|
|
166
|
+
`stories/Pagination/examples/Pagination/WithSelectField.tsx`
|
|
286
167
|
|
|
287
|
-
|
|
168
|
+
```tsx
|
|
169
|
+
import React, { useState } from "react";
|
|
170
|
+
import { Pagination, ISelectExtendedFieldDefaultOption } from "@sberbusiness/triplex-next";
|
|
171
|
+
|
|
172
|
+
export const WithSelectField = () => {
|
|
173
|
+
const [page, setPage] = useState(7);
|
|
174
|
+
const [pageSize, setPageSize] = useState(10);
|
|
175
|
+
const totalItems = 300;
|
|
176
|
+
const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
|
|
177
|
+
|
|
178
|
+
const handlePageSizeChange = (option: ISelectExtendedFieldDefaultOption) => {
|
|
179
|
+
setPageSize(Number(option.value));
|
|
180
|
+
// Смена размера страницы меняет totalPages — возвращаемся на первую, чтобы не оказаться вне диапазона.
|
|
181
|
+
setPage(1);
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const options: ISelectExtendedFieldDefaultOption[] = [
|
|
185
|
+
{ id: "0", value: "10", label: "10" },
|
|
186
|
+
{ id: "1", value: "20", label: "20" },
|
|
187
|
+
{ id: "2", value: "50", label: "50" },
|
|
188
|
+
{ id: "3", value: "100", label: "100" },
|
|
189
|
+
];
|
|
190
|
+
|
|
191
|
+
const selectedOption = options.find((option) => option.value === String(pageSize));
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<Pagination
|
|
195
|
+
paginationNavigationProps={{
|
|
196
|
+
currentPage: page,
|
|
197
|
+
totalPages,
|
|
198
|
+
boundaryCount: 1,
|
|
199
|
+
siblingCount: 1,
|
|
200
|
+
onCurrentPageChange: setPage,
|
|
201
|
+
}}
|
|
202
|
+
paginationSelectProps={{
|
|
203
|
+
paginationLabel: "Показать на странице:",
|
|
204
|
+
options,
|
|
205
|
+
value: selectedOption || options[0],
|
|
206
|
+
onChange: handlePageSizeChange,
|
|
207
|
+
targetProps: {
|
|
208
|
+
fieldLabel: "",
|
|
209
|
+
},
|
|
210
|
+
}}
|
|
211
|
+
/>
|
|
212
|
+
);
|
|
213
|
+
};
|
|
214
|
+
```
|
|
288
215
|
|
|
289
|
-
|
|
290
|
-
Примеры: `stories/Pagination/examples/`
|
|
216
|
+
### Extended
|
|
291
217
|
|
|
292
|
-
|
|
218
|
+
`stories/Pagination/examples/Pagination/Extended.tsx`
|
|
293
219
|
|
|
294
|
-
|
|
220
|
+
```tsx
|
|
221
|
+
import React, { useState } from "react";
|
|
222
|
+
import {
|
|
223
|
+
PaginationExtended,
|
|
224
|
+
PaginationNavigation,
|
|
225
|
+
PaginationSelect,
|
|
226
|
+
ISelectExtendedFieldDefaultOption,
|
|
227
|
+
} from "@sberbusiness/triplex-next";
|
|
228
|
+
|
|
229
|
+
export const Extended = () => {
|
|
230
|
+
const [page, setPage] = useState(1);
|
|
231
|
+
const [pageSize, setPageSize] = useState(10);
|
|
232
|
+
const totalItems = 300;
|
|
233
|
+
const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
|
|
234
|
+
|
|
235
|
+
const handlePageSizeChange = (option: ISelectExtendedFieldDefaultOption) => {
|
|
236
|
+
setPageSize(Number(option.value));
|
|
237
|
+
// Смена размера страницы меняет totalPages — возвращаемся на первую, чтобы не оказаться вне диапазона.
|
|
238
|
+
setPage(1);
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
const options: ISelectExtendedFieldDefaultOption[] = [
|
|
242
|
+
{ id: "0", value: "10", label: "10" },
|
|
243
|
+
{ id: "1", value: "20", label: "20" },
|
|
244
|
+
{ id: "2", value: "50", label: "50" },
|
|
245
|
+
{ id: "3", value: "100", label: "100" },
|
|
246
|
+
{ id: "4", value: "300", label: "300" },
|
|
247
|
+
];
|
|
248
|
+
|
|
249
|
+
const selectedOption = options.find((option) => option.value === String(pageSize));
|
|
250
|
+
|
|
251
|
+
return (
|
|
252
|
+
<PaginationExtended>
|
|
253
|
+
{totalPages > 1 && (
|
|
254
|
+
<PaginationNavigation
|
|
255
|
+
currentPage={page}
|
|
256
|
+
totalPages={totalPages}
|
|
257
|
+
boundaryCount={1}
|
|
258
|
+
siblingCount={1}
|
|
259
|
+
onCurrentPageChange={setPage}
|
|
260
|
+
/>
|
|
261
|
+
)}
|
|
262
|
+
<PaginationSelect
|
|
263
|
+
paginationLabel="Показать на странице:"
|
|
264
|
+
value={selectedOption || options[0]}
|
|
265
|
+
options={options}
|
|
266
|
+
onChange={handlePageSizeChange}
|
|
267
|
+
targetProps={{
|
|
268
|
+
fieldLabel: "",
|
|
269
|
+
}}
|
|
270
|
+
/>
|
|
271
|
+
</PaginationExtended>
|
|
272
|
+
);
|
|
273
|
+
};
|
|
274
|
+
```
|
|
295
275
|
|
|
296
|
-
| Дата | Изменение |
|
|
297
|
-
|---|---|
|
|
298
|
-
| 2026-04-18 | Создан документ |
|
|
@@ -24,15 +24,15 @@
|
|
|
24
24
|
|
|
25
25
|
### Именование
|
|
26
26
|
|
|
27
|
-
| Сущность
|
|
28
|
-
|
|
29
|
-
| Interface
|
|
30
|
-
| Union type
|
|
31
|
-
| Enum
|
|
32
|
-
| Константа (модульного уровня) | UPPER_SNAKE_CASE
|
|
33
|
-
| Компонент
|
|
34
|
-
| Хук
|
|
35
|
-
| Утилита
|
|
27
|
+
| Сущность | Префикс | Пример |
|
|
28
|
+
| ----------------------------- | ----------------- | ------------------------------------- |
|
|
29
|
+
| Interface | `I` | `IButtonProps`, `IButtonGeneralProps` |
|
|
30
|
+
| Union type | `T` | `TButtonProps` |
|
|
31
|
+
| Enum | `E` | `EButtonTheme`, `EComponentSize` |
|
|
32
|
+
| Константа (модульного уровня) | UPPER_SNAKE_CASE | `DEFAULT_TIMEOUT` |
|
|
33
|
+
| Компонент | PascalCase | `Button`, `DateField` |
|
|
34
|
+
| Хук | camelCase с `use` | `useClickOutside` |
|
|
35
|
+
| Утилита | camelCase | `formatDate`, `uniqueId` |
|
|
36
36
|
|
|
37
37
|
### Интерфейсы компонента
|
|
38
38
|
|
|
@@ -113,10 +113,12 @@ import { Button } from "../Button";
|
|
|
113
113
|
```
|
|
114
114
|
|
|
115
115
|
Правила:
|
|
116
|
+
|
|
116
117
|
- В новых stories/examples, которые показывают копируемый код, импортируй публичный API из `@sberbusiness/triplex-next` или публичных subentry.
|
|
117
118
|
- В unit-тестах и внутреннем коде следуй локальному паттерну файла и предпочитай ближайшие импорты для тестируемого модуля и внутренних зависимостей.
|
|
118
119
|
|
|
119
120
|
Порядок импортов (prettier-plugin-organize-imports не используется, но придерживайся):
|
|
121
|
+
|
|
120
122
|
1. React
|
|
121
123
|
2. Сторонние библиотеки
|
|
122
124
|
3. Внутренние (`@sberbusiness/triplex-next/...`)
|
|
@@ -133,9 +135,31 @@ import { Button } from "../Button";
|
|
|
133
135
|
- Имена классов — **camelCase**: `styles.secondaryLight`, `styles.iconOnly`.
|
|
134
136
|
- Никаких **inline styles** в компонентах (в stories допустимо для лейаута примеров).
|
|
135
137
|
- **Цвета** — только через CSS-переменные токенов (`var(--triplex-next-...)`). Никаких hex/rgb.
|
|
138
|
+
- Runtime CSS-переменные, которые компонент задаёт сам (например через `style` для динамической высоты,
|
|
139
|
+
transform или координат), называй с префиксом `--triplex-next-runtime-...`.
|
|
140
|
+
Они не являются дизайн-токенами и не должны попадать в `src/components/DesignTokens` или generated-файлы.
|
|
136
141
|
- **Переиспользуемые размерные константы** (z-index, отступы страницы, ширины оверлеев) — через LESS-переменные из `src/styles/components/` (`@page-padding-desktop-x`, `@sideOverlayLGWidth` и т.д.). Компонент-специфичные значения (высота кнопки, радиус скругления) можно задавать литералом.
|
|
137
142
|
- `!important` — только в крайнем случае, с комментарием почему.
|
|
138
143
|
|
|
144
|
+
Паттерн runtime CSS-переменных:
|
|
145
|
+
|
|
146
|
+
```text
|
|
147
|
+
--triplex-next-runtime-{Component}-{Element}_{Property}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Примеры:
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
interface IStyle extends React.CSSProperties {
|
|
154
|
+
"--triplex-next-runtime-ImageGalleryExtended-Track_Shift": string;
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
```less
|
|
159
|
+
.track {
|
|
160
|
+
transform: translateX(var(--triplex-next-runtime-ImageGalleryExtended-Track_Shift, 0%));
|
|
161
|
+
}
|
|
162
|
+
```
|
|
139
163
|
|
|
140
164
|
### Применение LESS-переменных (общие размерные константы)
|
|
141
165
|
|
|
@@ -166,7 +190,7 @@ import { Button } from "../Button";
|
|
|
166
190
|
В stories добавляй пример значения для демонстрации — это не хардкод, а иллюстрация:
|
|
167
191
|
|
|
168
192
|
```typescript
|
|
169
|
-
// В stories/examples/
|
|
193
|
+
// В stories/examples/Default.tsx — пример для документации
|
|
170
194
|
<ModalCloseButton aria-label="Закрыть" />
|
|
171
195
|
```
|
|
172
196
|
|
|
@@ -191,8 +215,11 @@ import { Button } from "../Button";
|
|
|
191
215
|
## Принципы написания кода
|
|
192
216
|
|
|
193
217
|
### DRY (Don't Repeat Yourself)
|
|
218
|
+
|
|
194
219
|
### KISS (Keep It Simple, Stupid)
|
|
220
|
+
|
|
195
221
|
### YAGNI (You Aren't Gonna Need It)
|
|
222
|
+
|
|
196
223
|
### Single Responsibility
|
|
197
224
|
|
|
198
225
|
### Не добавляй без задачи
|
|
@@ -202,4 +229,4 @@ import { Button } from "../Button";
|
|
|
202
229
|
- Не добавляй обработку ошибок для сценариев, которые не могут произойти.
|
|
203
230
|
- Не мигрируй legacy stories/tests на новый шаблон "по пути", если это не часть текущей задачи.
|
|
204
231
|
|
|
205
|
-
---
|
|
232
|
+
---
|
package/bundle/guides/commits.md
CHANGED
|
@@ -86,7 +86,6 @@ npx prettier --write src/components/Button/Button.tsx
|
|
|
86
86
|
| Файл/папка | Причина |
|
|
87
87
|
|---|---|
|
|
88
88
|
| `__screenshots__/` | Только из Docker/CI. Если нужно — подтвердить в pre-commit hook |
|
|
89
|
-
| `.mcp.json` | Персональный токен Figma — в `.gitignore` |
|
|
90
89
|
| `.env.local` | Секреты — в `.gitignore` |
|
|
91
90
|
| `node_modules/`, `dist/`, `storybook-static/` | В `.gitignore` |
|
|
92
91
|
|
|
@@ -163,4 +162,4 @@ stories/release-notes/v1/<текущая версия>.mdx
|
|
|
163
162
|
- [ ] Нет случайно добавленных файлов (`git status`)
|
|
164
163
|
- [ ] Для новых локальных/временных/генерируемых файлов проверено, не нужно ли добавить правило в `.gitignore`
|
|
165
164
|
- [ ] Нет скриншотов из macOS в `__screenshots__/`
|
|
166
|
-
- [ ] Release notes обновлены (если изменился публичный API компонента)
|
|
165
|
+
- [ ] Release notes обновлены (если изменился публичный API **или наблюдаемое поведение** компонента — не только при breaking change)
|