@sberbusiness/triplex-next-mcp-server 0.24.0-beta2 → 1.40.0-beta
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/AlertContext.md +268 -0
- package/bundle/components/BodyPage.md +186 -0
- package/bundle/components/Button.md +93 -85
- package/bundle/components/ButtonDropdown.md +36 -70
- package/bundle/components/ButtonDropdownExtended.md +422 -0
- package/bundle/components/ButtonIcon.md +41 -48
- package/bundle/components/Caption.md +291 -0
- package/bundle/components/Checkbox.md +43 -122
- package/bundle/components/CheckboxXGroup.md +109 -46
- package/bundle/components/CheckboxYGroup.md +77 -49
- package/bundle/components/CodeText.md +197 -0
- package/bundle/components/Col.md +311 -162
- package/bundle/components/CollapsibleTree.md +584 -0
- package/bundle/components/CollapsibleTreeExtended.md +422 -0
- package/bundle/components/Dropdown.md +748 -346
- 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/LightBox.md +2252 -233
- package/bundle/components/List.md +216 -183
- package/bundle/components/ListActionItem.md +157 -0
- package/bundle/components/ListItem.md +276 -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 +876 -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/ListTableItem.md +391 -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 +284 -186
- package/bundle/components/Pagination.md +206 -229
- package/bundle/components/Portal.md +131 -67
- package/bundle/components/Row.md +171 -69
- package/bundle/components/Text.md +320 -0
- package/bundle/components/TextField.md +364 -97
- package/bundle/components/Title.md +296 -0
- package/bundle/guides/codestyle.md +38 -11
- package/bundle/guides/commits.md +119 -26
- 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 +48 -2
- package/bundle/manifest.json +275 -30
- 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 +71 -0
- package/bundle/release-notes/1.38.0.mdx +36 -0
- package/bundle/release-notes/1.39.0.mdx +66 -0
- package/bundle/release-notes/1.40.0.mdx +27 -0
- package/bundle/release-notes/1.41.0.mdx +7 -0
- package/package.json +1 -1
package/bundle/guides/context.md
CHANGED
|
@@ -12,7 +12,7 @@ React-библиотека компонентов дизайн-системы.
|
|
|
12
12
|
Основная линия разработки: `main` → v1.x на React 18 + TypeScript strict.
|
|
13
13
|
Поддерживаемая legacy-линия: `release-0` → v0.x на React 17, синхронизируется мейнтейнерами.
|
|
14
14
|
|
|
15
|
-
**Основной сценарий работы агента:** добавить новый prop или вариант к существующему компоненту по описанию
|
|
15
|
+
**Основной сценарий работы агента:** добавить новый prop или вариант к существующему компоненту по текстовому описанию или скриншоту.
|
|
16
16
|
|
|
17
17
|
---
|
|
18
18
|
|
|
@@ -48,7 +48,7 @@ src/components/Button/
|
|
|
48
48
|
│ └── ButtonGeneral.module.less # Стили по теме/варианту
|
|
49
49
|
├── __tests__/
|
|
50
50
|
│ └── Button.test.tsx # Unit-тесты
|
|
51
|
-
└── Button-
|
|
51
|
+
└── Button-ai.md # Документация для AI-агентов (если компонент уже задокументирован)
|
|
52
52
|
```
|
|
53
53
|
|
|
54
54
|
Истории (stories) хранятся отдельно. В репозитории встречаются как flat-path файлы
|
|
@@ -90,7 +90,7 @@ src/components/Button/
|
|
|
90
90
|
|
|
91
91
|
Токены генерируются в `src/generated/themesCssVariables.css`. Не редактируй этот файл вручную.
|
|
92
92
|
|
|
93
|
-
Если добавляешь новое визуальное состояние — нужен новый токен. Имя токена согласуй с
|
|
93
|
+
Если добавляешь новое визуальное состояние — нужен новый токен. Имя токена согласуй с дизайнером.
|
|
94
94
|
|
|
95
95
|
---
|
|
96
96
|
|
|
@@ -115,14 +115,14 @@ src/components/Button/
|
|
|
115
115
|
|
|
116
116
|
Если инструкции расходятся, ориентируйся на них в таком порядке:
|
|
117
117
|
|
|
118
|
-
1. `src/components/{ComponentName}/{ComponentName}-
|
|
118
|
+
1. `src/components/{ComponentName}/{ComponentName}-ai.md` для конкретного компонента, если файл существует
|
|
119
119
|
2. `docs/ai/codestyle.md`
|
|
120
120
|
3. Профильный подробный гайд по зоне изменений (`codestyle.md`, `tests.md`, `stories-guide.md`, `commits.md`)
|
|
121
121
|
4. Этот файл (`docs/ai/CONTEXT.md`)
|
|
122
122
|
5. Локальный паттерн исходников компонента, stories и тестов
|
|
123
123
|
|
|
124
124
|
Не предполагай, что у каждого компонента уже есть AI-документация. Если файла
|
|
125
|
-
`{ComponentName}-
|
|
125
|
+
`{ComponentName}-ai.md` нет, ориентируйся на код, stories, тесты и общие правила
|
|
126
126
|
репозитория.
|
|
127
127
|
|
|
128
128
|
---
|
|
@@ -227,28 +227,6 @@ className={clsx(styles.button, styles.general, { [styles.loading]: loading })}
|
|
|
227
227
|
|
|
228
228
|
---
|
|
229
229
|
|
|
230
|
-
## Figma и MCP
|
|
231
|
-
|
|
232
|
-
Не у каждого компонента уже есть `{ComponentName}-AI.md`. Если компонент
|
|
233
|
-
задокументирован, Figma-метаданные лежат в frontmatter этого файла.
|
|
234
|
-
|
|
235
|
-
Формат frontmatter:
|
|
236
|
-
- `figma-node` — значение параметра `node-id` из URL Figma (например, `1-328`)
|
|
237
|
-
- `figma-file` — URL файла / design-ссылка на Figma-файл
|
|
238
|
-
|
|
239
|
-
Если в вашем окружении настроен Figma MCP или другой интеграционный инструмент:
|
|
240
|
-
1. Возьми `figma-node` из frontmatter компонента
|
|
241
|
-
2. Возьми `figma-file` из frontmatter компонента, если инструменту нужен file key или URL
|
|
242
|
-
3. Используй их для получения дизайн-спецификации
|
|
243
|
-
4. Сравни с текущим кодом и внеси нужные изменения
|
|
244
|
-
|
|
245
|
-
Если Figma-метаданные для компонента отсутствуют, не выдумывай их: попроси
|
|
246
|
-
ссылку у разработчика или работай по текстовому описанию/скриншоту.
|
|
247
|
-
|
|
248
|
-
Настройка MCP: см. `docs/ai/ROADMAP.md` → секция "Figma MCP Setup".
|
|
249
|
-
|
|
250
|
-
---
|
|
251
|
-
|
|
252
230
|
## Минимальная проверка перед завершением задачи
|
|
253
231
|
|
|
254
232
|
- Правки документации и конфигов: проверь ссылки, команды, примеры кода и согласованность между файлами.
|
|
@@ -262,11 +240,37 @@ className={clsx(styles.button, styles.general, { [styles.loading]: loading })}
|
|
|
262
240
|
## Навигация по документации компонентов
|
|
263
241
|
|
|
264
242
|
Если компонент уже задокументирован, его AI-документация лежит в:
|
|
265
|
-
`src/components/{ComponentName}/{ComponentName}-
|
|
243
|
+
`src/components/{ComponentName}/{ComponentName}-ai.md`
|
|
244
|
+
|
|
245
|
+
Пример: `src/components/Button/Button-ai.md`
|
|
266
246
|
|
|
267
|
-
|
|
247
|
+
Шаблон для новых компонентов: `docs/ai/template-ai.md`
|
|
248
|
+
|
|
249
|
+
### Когда создавать `{ComponentName}-ai.md`
|
|
250
|
+
|
|
251
|
+
Не для каждого экспорта из barrel `index.ts` нужен отдельный AI.md — это
|
|
252
|
+
раздуло бы `mcp-data.json` тривиальными wrapper'ами и снизило сигнал/шум для
|
|
253
|
+
AI-агента.
|
|
254
|
+
|
|
255
|
+
Создавай отдельный AI.md, когда выполняются **оба** условия:
|
|
256
|
+
|
|
257
|
+
1. Компонент экспортируется из barrel `src/components/{Family}/index.ts`
|
|
258
|
+
(внутренние/приватные — нет).
|
|
259
|
+
2. У компонента есть нетривиальный API или поведение: собственные props
|
|
260
|
+
сверх `className + ref + ...rest`, либо state, контекст, клавиатура,
|
|
261
|
+
callback'и, accessibility-контракт, render-prop, discriminated union.
|
|
262
|
+
|
|
263
|
+
Тривиальные wrapper'ы (`className + spread + forwardRef` без своей логики)
|
|
264
|
+
описывай разделом **«Связанные компоненты»** в AI.md родителя.
|
|
265
|
+
|
|
266
|
+
**Пример из семейства List:**
|
|
267
|
+
|
|
268
|
+
| Создаём AI.md | Описываем в родителе |
|
|
269
|
+
|---|---|
|
|
270
|
+
| `List`, `ListItem`, `ListActionItem`, `ListTableItem`, `ListItemSelectable`, `ListItemControlsButton`, `ListItemControlsButtonDropdown`, `ListSortable`, `ListSortableItem` | `ListItemControls`, `ListItemContent`, `ListEmptyState`, `ListItemLoading`, `ListItemTailLeft`, `ListItemTailRight`, `ListSortableItemTarget`, `ListSortableItemControls` |
|
|
268
271
|
|
|
269
|
-
|
|
272
|
+
В ROADMAP-таблице каждый AI.md-достойный компонент идёт отдельной строкой —
|
|
273
|
+
так считается прогресс покрытия и видны субкомпоненты с собственным API.
|
|
270
274
|
|
|
271
275
|
---
|
|
272
276
|
|
package/bundle/guides/stories.md
CHANGED
|
@@ -32,13 +32,13 @@ Stories выполняют несколько функций (в порядке
|
|
|
32
32
|
|
|
33
33
|
### Всегда
|
|
34
34
|
|
|
35
|
-
- **Playground** — добавить новый prop в `args` (дефолтное значение) и в `argTypes` (
|
|
36
|
-
- **`
|
|
35
|
+
- **Playground** — добавить новый prop в `args` (дефолтное значение) и в `argTypes` (контрол).
|
|
36
|
+
- **`argTypes`** в docs page автоматически покажет новый prop, если он типизирован в интерфейсе.
|
|
37
37
|
|
|
38
38
|
### Если prop имеет несколько визуальных вариантов (enum, размер, тема)
|
|
39
39
|
|
|
40
40
|
- Добавить новую named story: `Sizes`, `Themes`, `Statuses` — в зависимости от типа prop.
|
|
41
|
-
- Создать файл `examples/{PropName}
|
|
41
|
+
- Создать файл `examples/{PropName}.tsx` и реэкспортировать через `examples/index.ts`.
|
|
42
42
|
|
|
43
43
|
### Если prop — boolean-состояние с видимым эффектом
|
|
44
44
|
|
|
@@ -79,10 +79,10 @@ stories/
|
|
|
79
79
|
ComponentName.stories.tsx # основной файл стори
|
|
80
80
|
examples/
|
|
81
81
|
index.ts # реэкспорт всех примеров
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
Default.tsx
|
|
83
|
+
Sizes.tsx
|
|
84
|
+
Statuses.tsx
|
|
85
|
+
Production.tsx
|
|
86
86
|
...
|
|
87
87
|
```
|
|
88
88
|
|
|
@@ -90,6 +90,14 @@ stories/
|
|
|
90
90
|
|
|
91
91
|
Все стори выносятся в подпапку `examples/` и импортируются в основной файл. Если в основной папке находятся несколько файлов с расширением `.stories.tsx`, внутри подпапки `examples` необходимо создать подпапки по названию компонентов из файлов с расширением `.stories.tsx`. Также необходимо в каждой такой подпапке создать отдельный файл `index.ts`.
|
|
92
92
|
|
|
93
|
+
### Именование файлов примеров
|
|
94
|
+
|
|
95
|
+
- Имя файла = имя story: `Default` → `Default.tsx`, `Sizes` → `Sizes.tsx`, `Playground` → `Playground.tsx`.
|
|
96
|
+
- **Без постфикса `Example`** — не пиши `DefaultExample.tsx`, `SizesExample.tsx`. Если встретишь старые файлы с этим постфиксом, сохраняй локальный паттерн до миграции, но новые файлы создавай без него.
|
|
97
|
+
- Имя экспорта-функции внутри файла совпадает с именем файла: `export const Default = () => ...`.
|
|
98
|
+
- Source-константа: `{StoryName}Source` — `DefaultSource`, `SizesSource`, `PlaygroundSource`.
|
|
99
|
+
- В story-файле импорт компонента-примера делается через alias, чтобы избежать коллизии со story-экспортом: `Default as DefaultRender`, `Playground as PlaygroundRender`. Source без alias.
|
|
100
|
+
|
|
93
101
|
---
|
|
94
102
|
|
|
95
103
|
## Обязательные стори
|
|
@@ -105,7 +113,9 @@ stories/
|
|
|
105
113
|
|
|
106
114
|
> **Правило:** только Playground имеет Controls. Документационные стори (`Default`, `Sizes / Themes / Statuses`, `Edge cases`, `Examples`) не имеют Controls и показывают пример кода. `Visual tests` не имеют Controls и не показывают код.
|
|
107
115
|
|
|
108
|
-
>
|
|
116
|
+
> **Исключение для компонентов без props:** если у компонента нет настраиваемых props (например, контейнер-обёртка с одним только `children` и стандартными HTML-атрибутами), Playground не создаётся — интерактивность нечего показывать. Также убирается блок `Heading>Props` + `ArgTypes` — таблица будет пустой. В этом случае из docs page убираются `Heading>Props`, `ArgTypes`, `Heading>Playground`, `Primary` и `Controls of={Playground}` (см. раздел [Структура docs page](#структура-docs-page)).
|
|
117
|
+
|
|
118
|
+
> **MCP bundle:** `Playground` и `VisualTests` не попадают в `mcp-data.json` — у них нет кода для агента (Playground интерактивен, VisualTests — скриншот-регрессия). Фильтр реализован в `scripts/generateMcpData.ts` (`EXCLUDED_STORIES`). В остальном для MCP нужен файл примера в `examples/{Component}/` и ссылка на него из колонки `Example file` в `{Component}-ai.md`.
|
|
109
119
|
|
|
110
120
|
---
|
|
111
121
|
|
|
@@ -144,6 +154,22 @@ parameters: {
|
|
|
144
154
|
},
|
|
145
155
|
```
|
|
146
156
|
|
|
157
|
+
Если у компонента нет настраиваемых props (см. [Когда не создавать Playground](#когда-не-создавать-playground)), блок Playground убирается, а вместе с ним и блок `Props` — `ArgTypes` без props покажет пустую таблицу:
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
parameters: {
|
|
161
|
+
docs: {
|
|
162
|
+
page: () => (
|
|
163
|
+
<>
|
|
164
|
+
<Title />
|
|
165
|
+
<Description />
|
|
166
|
+
<Stories />
|
|
167
|
+
</>
|
|
168
|
+
),
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
```
|
|
172
|
+
|
|
147
173
|
---
|
|
148
174
|
|
|
149
175
|
## Playground
|
|
@@ -152,6 +178,21 @@ parameters: {
|
|
|
152
178
|
|
|
153
179
|
Playground показывает только те props, которые реально помогают исследовать компонент.
|
|
154
180
|
|
|
181
|
+
### Когда не создавать Playground
|
|
182
|
+
|
|
183
|
+
Если у компонента нет настраиваемых props (только `children` и стандартные HTML-атрибуты), Playground не создаётся — нечего класть в Controls. Типичный случай: контейнер-обёртка вроде `ListItem`, `ListItemControls`, `ChipGroup`.
|
|
184
|
+
|
|
185
|
+
В этом случае:
|
|
186
|
+
|
|
187
|
+
- В файле stories нет экспорта `Playground` и связанного с ним example-файла.
|
|
188
|
+
- В docs page убираются:
|
|
189
|
+
- `Heading>Props` и `ArgTypes of={Component}` — без props таблица будет пустой.
|
|
190
|
+
- `Heading>Playground`, `Primary`, `Controls of={Playground}`.
|
|
191
|
+
- См. вариант без Playground в разделе [Структура docs page](#структура-docs-page).
|
|
192
|
+
- Из импортов `@storybook/addon-docs/blocks` удаляются `ArgTypes`, `Heading`, `Primary`, `Controls` — остаются только `Title`, `Description`, `Stories`.
|
|
193
|
+
|
|
194
|
+
Если props всего один-два, но они имеют визуальный эффект — Playground всё равно создаётся, и блок `Props` остаётся.
|
|
195
|
+
|
|
155
196
|
### Разделение Controls
|
|
156
197
|
|
|
157
198
|
- Свойства, являющиеся props компонента, располагаются в блоке **Props** (по умолчанию).
|
|
@@ -210,7 +251,7 @@ tags: ["!autodocs"],
|
|
|
210
251
|
| Заполнение необязательного props | Название props **как есть** | `disabled` → `Disabled` |
|
|
211
252
|
| Нестандартные варианты наполнения | `With` + вариант | `WithTextAndIcon` |
|
|
212
253
|
| Композиции / production примеры | `Example` | `Example` |
|
|
213
|
-
| Скриншот-тесты | `
|
|
254
|
+
| Скриншот-тесты | `VisualTests` | `VisualTests` |
|
|
214
255
|
|
|
215
256
|
---
|
|
216
257
|
|
|
@@ -255,6 +296,25 @@ import { Button } from "../../../src/components/Button/Button";
|
|
|
255
296
|
|
|
256
297
|
Для legacy story-файлов не нужно устраивать отдельную миграцию импортов без задачи.
|
|
257
298
|
|
|
299
|
+
### Колбэки в примерах
|
|
300
|
+
|
|
301
|
+
| Файл | Что использовать | Почему |
|
|
302
|
+
| --- | --- | --- |
|
|
303
|
+
| `Playground.tsx`, `VisualTests`-рендеры | `action("eventName")` из `storybook/actions` | Код не показывается через `?raw`, поэтому storybook-импорт допустим. Помогает увидеть события во вкладке Actions при ручной проверке. |
|
|
304
|
+
| Копируемые примеры (`Default`, `Sizes`, `Statuses`, `With*`, production-like `Example`) | Пустые функции `() => {}` | Код показывается через `?raw` и должен копироваться без правок. `alert()`, `console.log()` и `import { action } from "storybook/actions"` ломают копируемость и создают side effects. |
|
|
305
|
+
|
|
306
|
+
```tsx
|
|
307
|
+
// Playground.tsx
|
|
308
|
+
import { action } from "storybook/actions";
|
|
309
|
+
|
|
310
|
+
<Component onChange={action("onChange")} />;
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
```tsx
|
|
314
|
+
// Default.tsx
|
|
315
|
+
<Component onChange={() => {}} />;
|
|
316
|
+
```
|
|
317
|
+
|
|
258
318
|
---
|
|
259
319
|
|
|
260
320
|
## Скриншот-тесты
|
|
@@ -386,12 +446,14 @@ render: () => (
|
|
|
386
446
|
В modern pattern для каждого примера экспортируются два значения — сам компонент и его исходный код:
|
|
387
447
|
|
|
388
448
|
```ts
|
|
389
|
-
export * from "./
|
|
390
|
-
export { default as
|
|
391
|
-
export * from "./
|
|
392
|
-
export { default as
|
|
449
|
+
export * from "./Default";
|
|
450
|
+
export { default as DefaultSource } from "./Default?raw";
|
|
451
|
+
export * from "./Sizes";
|
|
452
|
+
export { default as SizesSource } from "./Sizes?raw";
|
|
393
453
|
```
|
|
394
454
|
|
|
455
|
+
> **Имена.** Файл и экспорт-функция называются как story (`Default.tsx` экспортирует `Default`). Source-константа добавляет суффикс `Source` (`DefaultSource`). Из-за коллизии с именем story-экспорта в `*.stories.tsx` импорт компонента-примера делается через alias — см. ниже.
|
|
456
|
+
|
|
395
457
|
---
|
|
396
458
|
|
|
397
459
|
## Подключение примеров к стори
|
|
@@ -399,14 +461,15 @@ export { default as SizesExampleSource } from "./SizesExample?raw";
|
|
|
399
461
|
В modern pattern каждая документационная стори подключает пример и его исходный код через `?raw`:
|
|
400
462
|
|
|
401
463
|
```tsx
|
|
464
|
+
import { Default as DefaultRender, DefaultSource } from "./examples";
|
|
465
|
+
|
|
402
466
|
export const Default: StoryObj<typeof Component> = {
|
|
403
|
-
|
|
404
|
-
render: DefaultExample,
|
|
467
|
+
render: DefaultRender,
|
|
405
468
|
parameters: {
|
|
469
|
+
controls: { disable: true },
|
|
406
470
|
docs: {
|
|
407
|
-
controls: { disable: true },
|
|
408
471
|
source: {
|
|
409
|
-
code:
|
|
472
|
+
code: DefaultSource,
|
|
410
473
|
language: "tsx",
|
|
411
474
|
},
|
|
412
475
|
},
|
|
@@ -414,6 +477,8 @@ export const Default: StoryObj<typeof Component> = {
|
|
|
414
477
|
};
|
|
415
478
|
```
|
|
416
479
|
|
|
480
|
+
> **Alias обязателен.** Имя экспорта-функции (`Default`) совпадает с именем story-экспорта (`Default: StoryObj`), поэтому в импорте используется `Default as DefaultRender`. Source-константа конфликта не вызывает (`DefaultSource`), её импортируем без alias. То же относится к Playground (`Playground as PlaygroundRender`).
|
|
481
|
+
|
|
417
482
|
---
|
|
418
483
|
|
|
419
484
|
## Полный пример
|
|
@@ -425,7 +490,13 @@ import React, { useState, useCallback } from "react";
|
|
|
425
490
|
import { Meta, StoryObj } from "@storybook/react";
|
|
426
491
|
import { Title, Description, Primary, Controls, Stories, ArgTypes, Heading } from "@storybook/addon-docs/blocks";
|
|
427
492
|
import { ComponentName, EComponentSize } from "@sberbusiness/triplex-next";
|
|
428
|
-
import {
|
|
493
|
+
import {
|
|
494
|
+
Default as DefaultRender,
|
|
495
|
+
DefaultSource,
|
|
496
|
+
Playground as PlaygroundRender,
|
|
497
|
+
Sizes as SizesRender,
|
|
498
|
+
SizesSource,
|
|
499
|
+
} from "./examples";
|
|
429
500
|
|
|
430
501
|
const meta = {
|
|
431
502
|
title: "Components/Group/ComponentName",
|
|
@@ -457,9 +528,7 @@ export const Playground: StoryObj<typeof meta> = {
|
|
|
457
528
|
size: EComponentSize.LG,
|
|
458
529
|
// ...остальные args
|
|
459
530
|
},
|
|
460
|
-
render:
|
|
461
|
-
// ...render с useState и обработчиками
|
|
462
|
-
},
|
|
531
|
+
render: PlaygroundRender,
|
|
463
532
|
argTypes: {
|
|
464
533
|
size: {
|
|
465
534
|
control: { type: "select" },
|
|
@@ -481,13 +550,12 @@ export const Playground: StoryObj<typeof meta> = {
|
|
|
481
550
|
};
|
|
482
551
|
|
|
483
552
|
export const Default: StoryObj<typeof ComponentName> = {
|
|
484
|
-
|
|
485
|
-
render: DefaultExample,
|
|
553
|
+
render: DefaultRender,
|
|
486
554
|
parameters: {
|
|
487
555
|
controls: { disable: true },
|
|
488
556
|
docs: {
|
|
489
557
|
source: {
|
|
490
|
-
code:
|
|
558
|
+
code: DefaultSource,
|
|
491
559
|
language: "tsx",
|
|
492
560
|
},
|
|
493
561
|
},
|
|
@@ -495,13 +563,12 @@ export const Default: StoryObj<typeof ComponentName> = {
|
|
|
495
563
|
};
|
|
496
564
|
|
|
497
565
|
export const Sizes: StoryObj<typeof ComponentName> = {
|
|
498
|
-
|
|
499
|
-
render: SizesExample,
|
|
566
|
+
render: SizesRender,
|
|
500
567
|
parameters: {
|
|
501
568
|
controls: { disable: true },
|
|
502
569
|
docs: {
|
|
503
570
|
source: {
|
|
504
|
-
code:
|
|
571
|
+
code: SizesSource,
|
|
505
572
|
language: "tsx",
|
|
506
573
|
},
|
|
507
574
|
},
|
|
@@ -509,13 +576,13 @@ export const Sizes: StoryObj<typeof ComponentName> = {
|
|
|
509
576
|
};
|
|
510
577
|
```
|
|
511
578
|
|
|
512
|
-
### `examples/
|
|
579
|
+
### `examples/Default.tsx`
|
|
513
580
|
|
|
514
581
|
```tsx
|
|
515
582
|
import React, { useState } from "react";
|
|
516
583
|
import { ComponentName, EComponentSize } from "@sberbusiness/triplex-next";
|
|
517
584
|
|
|
518
|
-
export const
|
|
585
|
+
export const Default = () => {
|
|
519
586
|
const [value, setValue] = useState<string>("");
|
|
520
587
|
|
|
521
588
|
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => setValue(event.target.value);
|
|
@@ -528,7 +595,7 @@ export const DefaultExample = () => {
|
|
|
528
595
|
};
|
|
529
596
|
```
|
|
530
597
|
|
|
531
|
-
### `examples/
|
|
598
|
+
### `examples/Sizes.tsx`
|
|
532
599
|
|
|
533
600
|
```tsx
|
|
534
601
|
import React, { useState } from "react";
|
|
@@ -553,7 +620,7 @@ const SizeItem = ({ size }: ISizeItemProps) => {
|
|
|
553
620
|
|
|
554
621
|
const SIZES = Object.values(EComponentSize);
|
|
555
622
|
|
|
556
|
-
export const
|
|
623
|
+
export const Sizes = () => (
|
|
557
624
|
<div style={{ maxWidth: "300px", display: "flex", flexDirection: "column", gap: "16px" }}>
|
|
558
625
|
{SIZES.map((size) => (
|
|
559
626
|
<SizeItem key={size} size={size} />
|
|
@@ -565,10 +632,10 @@ export const SizesExample = () => (
|
|
|
565
632
|
### `examples/index.ts`
|
|
566
633
|
|
|
567
634
|
```ts
|
|
568
|
-
export * from "./
|
|
569
|
-
export { default as
|
|
570
|
-
export * from "./
|
|
571
|
-
export { default as
|
|
635
|
+
export * from "./Default";
|
|
636
|
+
export { default as DefaultSource } from "./Default?raw";
|
|
637
|
+
export * from "./Sizes";
|
|
638
|
+
export { default as SizesSource } from "./Sizes?raw";
|
|
572
639
|
```
|
|
573
640
|
|
|
574
641
|
---
|
|
@@ -579,10 +646,10 @@ export { default as SizesExampleSource } from "./SizesExample?raw";
|
|
|
579
646
|
|
|
580
647
|
### Документация и структура
|
|
581
648
|
|
|
582
|
-
- [ ] Есть docs page с `Title`, `Description`, `ArgTypes`, `Playground`, `Stories`
|
|
583
|
-
- [ ] Playground имеет Controls, не показывает код (`sourceState: "none"`)
|
|
584
|
-
- [ ] Playground исключён из скриншот-тестов (`testRunner: { skip: true }`)
|
|
585
|
-
- [ ] Playground скрыт из autodocs (`tags: ["!autodocs"]`)
|
|
649
|
+
- [ ] Есть docs page с `Title`, `Description`, `ArgTypes`, `Playground`, `Stories` (если у компонента нет настраиваемых props — блоки `Props`/`ArgTypes` и `Playground` пропускаются)
|
|
650
|
+
- [ ] Playground имеет Controls, не показывает код (`sourceState: "none"`) — если есть
|
|
651
|
+
- [ ] Playground исключён из скриншот-тестов (`testRunner: { skip: true }`) — если есть
|
|
652
|
+
- [ ] Playground скрыт из autodocs (`tags: ["!autodocs"]`) — если есть
|
|
586
653
|
- [ ] Все документационные стори, кроме Playground, **не** имеют Controls (`controls: { disable: true }`)
|
|
587
654
|
- [ ] Все документационные стори, кроме Playground, показывают пример кода через `source.code`
|
|
588
655
|
- [ ] Все примеры вынесены в `examples/` и реэкспортированы через `index.ts`
|
|
@@ -595,14 +662,17 @@ export { default as SizesExampleSource } from "./SizesExample?raw";
|
|
|
595
662
|
|
|
596
663
|
### Скриншот-тесты
|
|
597
664
|
|
|
665
|
+
Скриншот-тесты обязательны для UI-компонентов. Без baseline-файлов в `__screenshots__/` регрессию не поймать.
|
|
666
|
+
|
|
598
667
|
- [ ] Playground исключён из скриншот-тестов (`testRunner: { skip: true }`)
|
|
599
668
|
- [ ] Нет дублирующих скриншотов — визуально идентичные стори исключены через `testRunner: { skip: true }`
|
|
600
669
|
- [ ] Все ключевые визуальные состояния покрыты (размеры, статусы, заполненные поля, фокус)
|
|
601
670
|
- [ ] Если основных сторей недостаточно — создана Visual tests с недостающими состояниями
|
|
602
671
|
- [ ] Visual tests скрыта из autodocs (`tags: ["!autodocs"]`) и не показывает код
|
|
603
|
-
- [ ] Если компонент требует взаимодействия (dropdown, tooltip) — реализован `play` в Visual tests
|
|
672
|
+
- [ ] Если компонент требует взаимодействия (dropdown, tooltip, modal, popover) — реализован `play` в Visual tests
|
|
604
673
|
- [ ] Данные в Visual tests захардкожены (нет `new Date()`, `Math.random()`)
|
|
605
674
|
- [ ] Контейнеры имеют фиксированные размеры для стабильного layout'а
|
|
675
|
+
- [ ] Для каждой не-skip story есть baseline-файлы в `__screenshots__/{story-id}--xs.png` и `--xl.png`. Если baseline ещё нет — запустить `GitHub Actions → Update Visual Snapshots` на ветке (CI закоммитит скриншоты), и только потом мержить.
|
|
606
676
|
|
|
607
677
|
### Для небольших изменений в legacy stories
|
|
608
678
|
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: ComponentName
|
|
3
3
|
category: Category
|
|
4
|
-
figma-node: "NODE_ID"
|
|
5
|
-
figma-file: "https://www.figma.com/design/FILE_KEY/..."
|
|
6
4
|
related: []
|
|
7
5
|
tokens: []
|
|
8
6
|
stories: stories/Category/ComponentName.stories.tsx
|
|
@@ -19,8 +17,6 @@ version: "1.0"
|
|
|
19
17
|
Описывай намерения и ограничения, которые не видны из кода.
|
|
20
18
|
|
|
21
19
|
Frontmatter:
|
|
22
|
-
- figma-node: raw-значение параметра `node-id` из URL Figma, например `1-328`
|
|
23
|
-
- figma-file: URL файла / design-ссылка, из которой при необходимости можно получить file key
|
|
24
20
|
- tokens: список CSS-переменных, которые компонент использует
|
|
25
21
|
- related: список связанных компонентов (строки, имена)
|
|
26
22
|
|
|
@@ -139,9 +135,9 @@ VisualTests — скриншот-регрессия. Но в таблице их
|
|
|
139
135
|
|
|
140
136
|
| Story | Example file | Что демонстрирует |
|
|
141
137
|
|---|---|---|
|
|
142
|
-
| `Playground` | `
|
|
143
|
-
| `Themes` | `
|
|
144
|
-
| `Sizes` | `
|
|
138
|
+
| `Playground` | `Playground.tsx` | Интерактивный контроль всех props |
|
|
139
|
+
| `Themes` | `Themes.tsx` | Все визуальные темы |
|
|
140
|
+
| `Sizes` | `Sizes.tsx` | Размеры SM / MD / LG |
|
|
145
141
|
|
|
146
142
|
---
|
|
147
143
|
|
package/bundle/guides/tests.md
CHANGED
|
@@ -38,6 +38,48 @@ src/components/{ComponentName}/__tests__/{ComponentName}.test.tsx
|
|
|
38
38
|
|
|
39
39
|
Один файл на компонент. Если компонент имеет субкомпоненты (ButtonIcon, ButtonDropdown), тесты субкомпонентов — в отдельных файлах той же локальной папки тестов.
|
|
40
40
|
|
|
41
|
+
### Импорты `vitest` — только в `*.test.ts` / `*.test.tsx` ⚠️
|
|
42
|
+
|
|
43
|
+
**Правило:** `import ... from "vitest"` (а также `@testing-library/*`, `storybook/test`)
|
|
44
|
+
допустим **исключительно** в файлах с постфиксом `.test.ts` / `.test.tsx`,
|
|
45
|
+
в `vitest.setup.ts` и в `test-utils/`. Нигде больше.
|
|
46
|
+
|
|
47
|
+
Причина — сборка. `vite.config.ts` строит entry-точку из **каждого** файла
|
|
48
|
+
`src/**/*.{ts,tsx}`, кроме исключённых глобом. Любой файл внутри `src/`, который
|
|
49
|
+
импортирует `vitest` и не подпадает под исключения, попадает в бандл, а вместе с
|
|
50
|
+
ним vitest уезжает в общий чанк `vendor` — тот самый, который тянут почти все
|
|
51
|
+
компоненты. Потребитель падает на старте:
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
Uncaught Error: Vitest failed to access its internal state.
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Именно это произошло в 1.39.0 из-за файла `src/components/Carousel/__tests__/utils.ts`
|
|
58
|
+
(хелпер без постфикса `.test`). Чанк `vendor` вырос с 640 KB до 1.28 MB.
|
|
59
|
+
|
|
60
|
+
**Общие тестовые хелперы** (моки `ResizeObserver`, фейковые `Touch`, подмена
|
|
61
|
+
размеров элементов и т.п.) кладём в `test-utils/` в корне репозитория — вне `src/`,
|
|
62
|
+
поэтому сборка их физически не видит:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
// ✅ src/components/Carousel/__tests__/CarouselRoot.test.tsx
|
|
66
|
+
import { getResizeCallback, mockElementSize } from "../../../../test-utils/dom";
|
|
67
|
+
|
|
68
|
+
// ❌ src/components/Carousel/__tests__/utils.ts — станет entry-точкой сборки
|
|
69
|
+
import { vi } from "vitest";
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Не называй хелпер `utils.ts` рядом с `utils.test.tsx`: `__tests__/utils.test.tsx` —
|
|
73
|
+
это **тесты для `../utils.ts`** компонента, а не тесты хелпера. Хелперы нельзя
|
|
74
|
+
класть и в сам `*.test.tsx`-файл: при импорте из другого теста его `describe`
|
|
75
|
+
зарегистрируется повторно и тесты прогонятся несколько раз.
|
|
76
|
+
|
|
77
|
+
Страховка на уровне сборки: `npm run build` запускает `scripts/checkBundleSize.js`
|
|
78
|
+
и падает, если в `dist` превышен один из двух лимитов — **700 KB на отдельный
|
|
79
|
+
JS-файл** (ловит распухший `vendor`: всё из `node_modules` сливается в него
|
|
80
|
+
единственным чанком) или **2000 KB суммарно по всем JS-файлам** (ловит утечку
|
|
81
|
+
кода мимо `node_modules` и медленный рост множества мелких файлов).
|
|
82
|
+
|
|
41
83
|
### Импорты
|
|
42
84
|
|
|
43
85
|
```typescript
|
|
@@ -216,11 +258,15 @@ afterEach(() => {
|
|
|
216
258
|
|
|
217
259
|
### Когда нужны Visual tests
|
|
218
260
|
|
|
219
|
-
|
|
220
|
-
|
|
261
|
+
**Скриншот-тесты обязательны для любого компонента с видимым UI.** По умолчанию все не-Playground stories автоматически снимаются на двух viewport'ах (xs/xl) — это базовое покрытие. Если оно недостаточно, создавай отдельную `VisualTests` story.
|
|
262
|
+
|
|
263
|
+
Создавай `VisualTests` story если:
|
|
264
|
+
- Компонент требует взаимодействия перед скриншотом (открыть dropdown, hover, focus, открыть модалку/попап) — **обязательно** для overlay-компонентов (Modal, Tooltip, Popover, Dropdown, LightBox).
|
|
221
265
|
- Нужно покрыть состояние, которого нет в документационных stories.
|
|
222
266
|
- Нужно объединить несколько вариантов в один скриншот.
|
|
223
267
|
|
|
268
|
+
После добавления новых stories обязательно сгенерируй baseline-скриншоты через CI workflow — без baseline скриншот-теста фактически нет, и regression не поймается.
|
|
269
|
+
|
|
224
270
|
### Обновление baseline
|
|
225
271
|
|
|
226
272
|
```text
|