@sberbusiness/triplex-next-mcp-server 0.24.0-beta1

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 (140) hide show
  1. package/README.md +124 -0
  2. package/bundle/.gitkeep +0 -0
  3. package/bundle/components/AbstractTree.md +198 -0
  4. package/bundle/components/AccordionBase.md +227 -0
  5. package/bundle/components/Alert.md +317 -0
  6. package/bundle/components/Amount.md +225 -0
  7. package/bundle/components/AmountField.md +289 -0
  8. package/bundle/components/Avatar.md +209 -0
  9. package/bundle/components/Badge.md +277 -0
  10. package/bundle/components/Body.md +167 -0
  11. package/bundle/components/Button.md +230 -0
  12. package/bundle/components/ButtonDropdown.md +159 -0
  13. package/bundle/components/ButtonIcon.md +122 -0
  14. package/bundle/components/Calendar.md +445 -0
  15. package/bundle/components/Card.md +374 -0
  16. package/bundle/components/CarouselExtended.md +250 -0
  17. package/bundle/components/Checkbox.md +126 -0
  18. package/bundle/components/CheckboxTree.md +280 -0
  19. package/bundle/components/CheckboxTreeExtended.md +321 -0
  20. package/bundle/components/CheckboxXGroup.md +68 -0
  21. package/bundle/components/CheckboxYGroup.md +67 -0
  22. package/bundle/components/Chip.md +404 -0
  23. package/bundle/components/ChipGroup.md +179 -0
  24. package/bundle/components/Col.md +221 -0
  25. package/bundle/components/CollapsableTree.md +255 -0
  26. package/bundle/components/Confirm.md +343 -0
  27. package/bundle/components/DateField.md +371 -0
  28. package/bundle/components/DatePickerExtended.md +342 -0
  29. package/bundle/components/DateRange.md +275 -0
  30. package/bundle/components/DesignTokens.md +385 -0
  31. package/bundle/components/Divider.md +196 -0
  32. package/bundle/components/DocumentNumberEdit.md +280 -0
  33. package/bundle/components/Dropdown.md +433 -0
  34. package/bundle/components/Ellipsis.md +208 -0
  35. package/bundle/components/EmptyView.md +99 -0
  36. package/bundle/components/ExpandAnimation.md +281 -0
  37. package/bundle/components/Footer.md +339 -0
  38. package/bundle/components/FormField.md +326 -0
  39. package/bundle/components/FormGroup.md +99 -0
  40. package/bundle/components/Gap.md +113 -0
  41. package/bundle/components/Header.md +280 -0
  42. package/bundle/components/HelpBox.md +154 -0
  43. package/bundle/components/IconWrapper.md +145 -0
  44. package/bundle/components/Island.md +197 -0
  45. package/bundle/components/IslandAccordion.md +230 -0
  46. package/bundle/components/IslandWidget.md +233 -0
  47. package/bundle/components/KeyDownListener.md +157 -0
  48. package/bundle/components/LightBox.md +322 -0
  49. package/bundle/components/Link.md +161 -0
  50. package/bundle/components/List.md +247 -0
  51. package/bundle/components/ListMaster.md +204 -0
  52. package/bundle/components/Loader.md +161 -0
  53. package/bundle/components/LoaderScreen.md +134 -0
  54. package/bundle/components/Marker.md +127 -0
  55. package/bundle/components/MarkerStatus.md +148 -0
  56. package/bundle/components/MediaWidth.md +169 -0
  57. package/bundle/components/MobileView.md +120 -0
  58. package/bundle/components/ModalWindow.md +308 -0
  59. package/bundle/components/MonthYearField.md +168 -0
  60. package/bundle/components/MultiselectField.md +213 -0
  61. package/bundle/components/Notification.md +233 -0
  62. package/bundle/components/NumberField.md +178 -0
  63. package/bundle/components/OrderedList.md +169 -0
  64. package/bundle/components/Overlay.md +237 -0
  65. package/bundle/components/Page.md +246 -0
  66. package/bundle/components/Pagination.md +298 -0
  67. package/bundle/components/Portal.md +119 -0
  68. package/bundle/components/Radio.md +174 -0
  69. package/bundle/components/Row.md +125 -0
  70. package/bundle/components/SMSField.md +160 -0
  71. package/bundle/components/SegmentedControl.md +235 -0
  72. package/bundle/components/SelectExtendedField.md +322 -0
  73. package/bundle/components/SelectField.md +213 -0
  74. package/bundle/components/Skeleton.md +129 -0
  75. package/bundle/components/Slider.md +157 -0
  76. package/bundle/components/SliderExtended.md +210 -0
  77. package/bundle/components/SliderRange.md +160 -0
  78. package/bundle/components/SmallInput.md +101 -0
  79. package/bundle/components/Spoiler.md +121 -0
  80. package/bundle/components/StatusTracker.md +151 -0
  81. package/bundle/components/Step.md +121 -0
  82. package/bundle/components/Stepper.md +163 -0
  83. package/bundle/components/Suggest.md +160 -0
  84. package/bundle/components/SuggestField.md +157 -0
  85. package/bundle/components/SwipeableArea.md +144 -0
  86. package/bundle/components/Table.md +199 -0
  87. package/bundle/components/Tabs.md +152 -0
  88. package/bundle/components/TabsExtended.md +273 -0
  89. package/bundle/components/TabsLine.md +189 -0
  90. package/bundle/components/Tag.md +135 -0
  91. package/bundle/components/TagColor.md +121 -0
  92. package/bundle/components/TagGroup.md +100 -0
  93. package/bundle/components/TextField.md +152 -0
  94. package/bundle/components/TextareaField.md +124 -0
  95. package/bundle/components/ThemeProvider.md +181 -0
  96. package/bundle/components/Tooltip.md +254 -0
  97. package/bundle/components/TopOverlay.md +145 -0
  98. package/bundle/components/TreeView.md +224 -0
  99. package/bundle/components/Triggers.md +121 -0
  100. package/bundle/guides/codestyle.md +205 -0
  101. package/bundle/guides/commits.md +166 -0
  102. package/bundle/guides/context.md +277 -0
  103. package/bundle/guides/stories.md +618 -0
  104. package/bundle/guides/template.md +154 -0
  105. package/bundle/guides/tests.md +301 -0
  106. package/bundle/icons.json +4156 -0
  107. package/bundle/manifest.json +796 -0
  108. package/bundle/release-notes/1.1.0.mdx +26 -0
  109. package/bundle/release-notes/1.1.1.mdx +14 -0
  110. package/bundle/release-notes/1.10.0.mdx +43 -0
  111. package/bundle/release-notes/1.11.0.mdx +19 -0
  112. package/bundle/release-notes/1.12.0.mdx +21 -0
  113. package/bundle/release-notes/1.13.0.mdx +43 -0
  114. package/bundle/release-notes/1.14.0.mdx +29 -0
  115. package/bundle/release-notes/1.15.0.mdx +56 -0
  116. package/bundle/release-notes/1.16.0.mdx +55 -0
  117. package/bundle/release-notes/1.17.0.mdx +15 -0
  118. package/bundle/release-notes/1.18.0.mdx +24 -0
  119. package/bundle/release-notes/1.19.0.mdx +48 -0
  120. package/bundle/release-notes/1.19.1.mdx +9 -0
  121. package/bundle/release-notes/1.2.0.mdx +80 -0
  122. package/bundle/release-notes/1.20.0.mdx +48 -0
  123. package/bundle/release-notes/1.21.0.mdx +66 -0
  124. package/bundle/release-notes/1.22.0.mdx +75 -0
  125. package/bundle/release-notes/1.23.0.mdx +50 -0
  126. package/bundle/release-notes/1.24.0.mdx +59 -0
  127. package/bundle/release-notes/1.25.0.mdx +52 -0
  128. package/bundle/release-notes/1.26.0.mdx +11 -0
  129. package/bundle/release-notes/1.3.0.mdx +21 -0
  130. package/bundle/release-notes/1.4.0.mdx +37 -0
  131. package/bundle/release-notes/1.5.0.mdx +24 -0
  132. package/bundle/release-notes/1.6.0.mdx +37 -0
  133. package/bundle/release-notes/1.6.1.mdx +11 -0
  134. package/bundle/release-notes/1.7.0.mdx +29 -0
  135. package/bundle/release-notes/1.8.0.mdx +38 -0
  136. package/bundle/release-notes/1.9.0.mdx +28 -0
  137. package/dist/index.d.ts +2 -0
  138. package/dist/index.js +324 -0
  139. package/dist/index.js.map +1 -0
  140. package/package.json +51 -0
@@ -0,0 +1,618 @@
1
+ # Руководство по написанию Stories
2
+
3
+ ## Зачем нужны Stories
4
+
5
+ Stories выполняют несколько функций (в порядке приоритета):
6
+
7
+ 1. **Документация** — описание props и предназначения компонента.
8
+ 2. **Копирование кода** — готовые примеры использования, которые можно скопировать.
9
+ 3. **Отображение ключевых props** — size, theme, variants, состояния.
10
+ 4. **Краевые случаи** — для сложных компонентов (опционально).
11
+ 5. **Examples** — композиции компонентов и примеры из дизайна, приближенные к production.
12
+ 6. **Visual tests** — дополнительные примеры для скриншот-тестов, если основных сторей недостаточно.
13
+
14
+ ---
15
+
16
+ ## Статус миграции
17
+
18
+ В репозитории сейчас сосуществуют два паттерна stories:
19
+
20
+ - **Modern pattern** — grouped folders, `examples/`, `?raw`, копируемые examples, публичные импорты из `@sberbusiness/triplex-next`.
21
+ - **Legacy pattern** — flat story files, inline render-функции, локальные импорты из `src/...`.
22
+
23
+ Правило использования:
24
+
25
+ - Для **новых компонентов** и **существенно переписанных story-файлов** используй modern pattern.
26
+ - Если задача маленькая и story-файл уже legacy, **не рефактори весь файл только ради миграции**. Сохраняй локальный паттерн и обновляй только нужный участок.
27
+ - Не переименовывай существующие story ids/export names без явной необходимости: на них могут опираться e2e и visual tests.
28
+
29
+ ---
30
+
31
+ ## Что обновлять при добавлении нового prop
32
+
33
+ ### Всегда
34
+
35
+ - **Playground** — добавить новый prop в `args` (дефолтное значение) и в `argTypes` (описание и контрол).
36
+ - **`ArgTypes`** в docs page автоматически покажет новый prop, если он типизирован в интерфейсе.
37
+
38
+ ### Если prop имеет несколько визуальных вариантов (enum, размер, тема)
39
+
40
+ - Добавить новую named story: `Sizes`, `Themes`, `Statuses` — в зависимости от типа prop.
41
+ - Создать файл `examples/{PropName}Example.tsx` и реэкспортировать через `examples/index.ts`.
42
+
43
+ ### Если prop — boolean-состояние с видимым эффектом
44
+
45
+ - Добавить отдельную story: `Disabled`, `Loading`, `ReadOnly` — по паттерну именования (название prop как есть).
46
+ - Если prop меняет только незначительную деталь и хорошо виден в существующих стори — достаточно обновить Playground.
47
+
48
+ ### Если prop — нестандартный вариант наполнения
49
+
50
+ - Добавить story `With{Variant}`: `WithIcon`, `WithClearButton` и т.д.
51
+
52
+ ### Если prop — callback или поведенческий параметр (не меняет внешний вид)
53
+
54
+ - Отдельную named story не создавай.
55
+ - Обнови Playground или соответствующий `examples/`-файл: добавь callback или параметр, чтобы в копируемом коде было видно, как его использовать.
56
+
57
+ ### Если props добавляются к субкомпоненту составного компонента
58
+
59
+ Составной компонент — это когда публичный API строится через статические свойства: `LightBox.RightSidebar`, `Select.Option`, `Page.Header` и т.д.
60
+
61
+ - У субкомпонентов, как правило, нет собственного Playground, поэтому правило "обновить Playground" к ним неприменимо.
62
+ - Вместо этого обнови `examples/`-файл, где субкомпонент используется, — добавь новый prop в JSX примера. Это гарантирует, что копируемый код в документации отражает актуальный API.
63
+
64
+ ### Visual regression
65
+
66
+ - Если новый prop меняет внешний вид — проверить, покрыт ли он существующими скриншотами.
67
+ - Если нет — добавить вариант в `VisualTests` story (или создать её).
68
+
69
+ ---
70
+
71
+ ## Структура файлов
72
+
73
+ Ниже описан **modern pattern** для новых и мигрируемых story-файлов:
74
+
75
+ ```
76
+ stories/
77
+ ComponentGroup/
78
+ ComponentName/
79
+ ComponentName.stories.tsx # основной файл стори
80
+ examples/
81
+ index.ts # реэкспорт всех примеров
82
+ DefaultExample.tsx
83
+ SizesExample.tsx
84
+ StatusesExample.tsx
85
+ ProductionExample.tsx
86
+ ...
87
+ ```
88
+
89
+ Если файл сторей компонента находится в папке `stories`, необходимо создать одноименную папку и перенести файл сторей туда.
90
+
91
+ Все стори выносятся в подпапку `examples/` и импортируются в основной файл. Если в основной папке находятся несколько файлов с расширением `.stories.tsx`, внутри подпапки `examples` необходимо создать подпапки по названию компонентов из файлов с расширением `.stories.tsx`. Также необходимо в каждой такой подпапке создать отдельный файл `index.ts`.
92
+
93
+ ---
94
+
95
+ ## Обязательные стори
96
+
97
+ | Стори | Описание | Controls | Код |
98
+ | ----------------------------- | ------------------------------------------------------------------------------------------------------------ | -------- | --- |
99
+ | **Playground** | Интерактивная песочница с Controls | Да | Нет |
100
+ | **Default** | Минимальное состояние компонента с параметрами по умолчанию | Нет | Да |
101
+ | **Sizes / Themes / Statuses** | Стори на ключевые props — отрендеренные варианты с подписями | Нет | Да |
102
+ | **Edge cases** | Опционально, на усмотрение разработчика. Каждый кейс — отдельная стори | Нет | Да |
103
+ | **Examples** | Композиции компонентов, production-like примеры | Нет | Да |
104
+ | **Visual tests** | Дополнительные примеры для скриншот-тестов (если недостаточно основных); исходный код в docs не показывается | Нет | Нет |
105
+
106
+ > **Правило:** только Playground имеет Controls. Документационные стори (`Default`, `Sizes / Themes / Statuses`, `Edge cases`, `Examples`) не имеют Controls и показывают пример кода. `Visual tests` не имеют Controls и не показывают код.
107
+
108
+ > **MCP bundle:** `Playground` и `VisualTests` не попадают в `mcp-data.json` — у них нет кода для агента (Playground интерактивен, VisualTests — скриншот-регрессия). Фильтр реализован в `scripts/generateMcpData.ts` (`EXCLUDED_STORIES`). В остальном для MCP нужен файл примера в `examples/{Component}/` и ссылка на него из колонки `Example file` в `{Component}-AI.md`.
109
+
110
+ ---
111
+
112
+ ## Порядок внутри файла stories
113
+
114
+ ```
115
+ 1. imports
116
+ 2. meta
117
+ 3. constants / helpers
118
+ 4. type Story = StoryObj<typeof meta>
119
+ 5. Playground
120
+ 6. Default
121
+ 7. остальные stories (Sizes, Themes, Statuses, edge cases, examples...)
122
+ ```
123
+
124
+ ---
125
+
126
+ ## Структура docs page
127
+
128
+ ```tsx
129
+ parameters: {
130
+ docs: {
131
+ page: () => (
132
+ <>
133
+ <Title />
134
+ <Description />
135
+ <Heading>Props</Heading>
136
+ <ArgTypes of={Component} />
137
+ <Heading>Playground</Heading>
138
+ <Primary />
139
+ <Controls of={Playground} />
140
+ <Stories />
141
+ </>
142
+ ),
143
+ },
144
+ },
145
+ ```
146
+
147
+ ---
148
+
149
+ ## Playground
150
+
151
+ ### Назначение
152
+
153
+ Playground показывает только те props, которые реально помогают исследовать компонент.
154
+
155
+ ### Разделение Controls
156
+
157
+ - Свойства, являющиеся props компонента, располагаются в блоке **Props** (по умолчанию).
158
+ - Свойства, **не** являющиеся props компонента (вспомогательные настройки), выносятся в отдельный блок **Settings**.
159
+
160
+ ```tsx
161
+ argTypes: {
162
+ // Props компонента — без category, попадают в блок Props
163
+ size: {
164
+ control: { type: "select" },
165
+ options: Object.values(EComponentSize),
166
+ description: "Размер поля",
167
+ table: {
168
+ type: { summary: "EComponentSize" },
169
+ defaultValue: { summary: "EComponentSize.LG" },
170
+ },
171
+ },
172
+ // Вспомогательные настройки — выносим в Settings
173
+ withClearButton: {
174
+ control: "boolean",
175
+ description: "С кнопкой очистки.",
176
+ table: {
177
+ category: "Settings",
178
+ },
179
+ },
180
+ },
181
+ ```
182
+
183
+ ### Параметры Playground
184
+
185
+ В modern pattern Playground не показывает пример кода и исключён из скриншот-тестов:
186
+
187
+ ```tsx
188
+ parameters: {
189
+ testRunner: { skip: true },
190
+ docs: {
191
+ canvas: { sourceState: "none" },
192
+ },
193
+ },
194
+ ```
195
+
196
+ В modern pattern Playground не отображается в docs как отдельная стори:
197
+
198
+ ```tsx
199
+ tags: ["!autodocs"],
200
+ ```
201
+
202
+ ---
203
+
204
+ ## Именование сторей
205
+
206
+ | Ситуация | Название | Пример |
207
+ | -------------------------------------- | ----------------------------------------- | ----------------------- |
208
+ | Базовая стори | `Default` | `Default` |
209
+ | Варианты props без дефолтного значения | Название props во **множественном** числе | `size` → `Sizes` |
210
+ | Заполнение необязательного props | Название props **как есть** | `disabled` → `Disabled` |
211
+ | Нестандартные варианты наполнения | `With` + вариант | `WithTextAndIcon` |
212
+ | Композиции / production примеры | `Example` | `Example` |
213
+ | Скриншот-тесты | `Visual tests` | `Visual tests` |
214
+
215
+ ---
216
+
217
+ ## Как писать примеры
218
+
219
+ ### Базовые примеры (Default, Sizes, Themes)
220
+
221
+ - Минимальный код — только то, что нужно для демонстрации конкретного props.
222
+ - Каждый вариант подписывается **рядом с компонентом**, а не внутри него.
223
+ - Никаких лишних обёрток и логики.
224
+
225
+ ### Examples (production-like)
226
+
227
+ - Приближены к реальному использованию.
228
+ - Показывают композицию компонентов.
229
+ - Стори показывает использование компонента, а **не** становится мини-приложением.
230
+
231
+ ### Дублирование кода
232
+
233
+ Для каждого примера пишется **полноценный самодостаточный код**. Не нужно выносить общие куски между примерами — дублирование в примерах допустимо и предпочтительно, чтобы каждый пример можно было скопировать целиком.
234
+
235
+ ### Импорты в примерах
236
+
237
+ Для **modern examples** компоненты и утилиты библиотеки импортируются **из корня пакета**, а не по относительным путям к исходникам:
238
+
239
+ ```tsx
240
+ // Правильно
241
+ import { LightBox, Page, Button, EButtonTheme } from "@sberbusiness/triplex-next";
242
+
243
+ // Неправильно
244
+ import { LightBox } from "../../../src/components/LightBox/LightBox";
245
+ import { Button } from "../../../src/components/Button/Button";
246
+ ```
247
+
248
+ Это обеспечивает:
249
+
250
+ - **Копируемость** — пользователь может скопировать пример и использовать его в своём проекте без изменения импортов.
251
+ - **Читаемость** — один импорт вместо множества относительных путей.
252
+ - **Актуальность** — при перемещении файлов внутри библиотеки примеры не ломаются.
253
+
254
+ > Иконки импортируются из `@sberbusiness/icons-next`.
255
+
256
+ Для legacy story-файлов не нужно устраивать отдельную миграцию импортов без задачи.
257
+
258
+ ---
259
+
260
+ ## Скриншот-тесты
261
+
262
+ Каждая стори автоматически снимается test-runner'ом на двух viewport'ах — **xs** (575px) и **xl** (1200px). Скриншоты сохраняются в `__screenshots__/` с именем `{storyId}--{viewport}.png`.
263
+
264
+ ### Какие стори участвуют в скриншот-тестах
265
+
266
+ По умолчанию **все** стори участвуют в скриншот-тестах. Исключения задаются параметром `testRunner: { skip: true }`.
267
+
268
+ **Всегда исключаются:**
269
+
270
+ - **Playground** — интерактивная песочница, состояние зависит от пользователя, скриншоты не имеют смысла.
271
+
272
+ **Исключаются при необходимости:**
273
+
274
+ - Стори, дублирующие отображение другой стори. Если две стори рендерят визуально одно и то же — для теста оставьте одну, вторую исключите через `testRunner: { skip: true }`. Не нужно генерировать идентичные скриншоты.
275
+
276
+ ### Когда создавать Visual tests
277
+
278
+ Стори **Visual tests** создаётся, когда основных сторей недостаточно для покрытия всех визуальных состояний компонента. Типичные случаи:
279
+
280
+ - Нужно проверить состояние, которого нет в документационных сторях (например, заполненное поле, фокус, комбинации props).
281
+ - Компонент требует **взаимодействия перед скриншотом** — нужно открыть dropdown, навести курсор, кликнуть по элементу.
282
+ - Нужно собрать несколько вариантов в одну стори, чтобы сократить количество скриншотов.
283
+
284
+ ### Параметры Visual tests
285
+
286
+ Visual tests скрыта из документации и не показывает исходный код — она предназначена только для тестов:
287
+
288
+ ```tsx
289
+ export const VisualTests: Story = {
290
+ tags: ["!autodocs"],
291
+ parameters: {
292
+ controls: { disable: true },
293
+ docs: {
294
+ canvas: { sourceState: "none" },
295
+ codePanel: false,
296
+ },
297
+ },
298
+ render: () => {
299
+ // ...
300
+ },
301
+ };
302
+ ```
303
+
304
+ ### Взаимодействие через play
305
+
306
+ Если компонент должен изменить состояние перед скриншотом (открыть dropdown, показать tooltip и т.д.), реализуйте взаимодействие через `play`-функцию:
307
+
308
+ ```tsx
309
+ export const VisualTests: Story = {
310
+ tags: ["!autodocs"],
311
+ parameters: {
312
+ controls: { disable: true },
313
+ docs: {
314
+ canvas: { sourceState: "none" },
315
+ codePanel: false,
316
+ },
317
+ },
318
+ render: () => {
319
+ const [value, setValue] = useState("");
320
+
321
+ return (
322
+ <div style={{ display: "flex", gap: 50, flexWrap: "wrap" }}>
323
+ <DateField value={value} onChange={setValue} label="Label" placeholderMask="дд.мм.гггг" />
324
+ {/* ...другие варианты */}
325
+ </div>
326
+ );
327
+ },
328
+ play: async ({ canvas, userEvent }) => {
329
+ const inputs = await canvas.findAllByRole("textbox");
330
+
331
+ await userEvent.click(inputs[0]);
332
+ },
333
+ };
334
+ ```
335
+
336
+ Test-runner после выполнения `play` ждёт стабилизации DOM (500ms без мутаций) и только потом делает скриншот. Это гарантирует, что анимации завершились и dropdown полностью раскрылся.
337
+
338
+ ### Стабильность скриншотов
339
+
340
+ Чтобы скриншоты не были «плавающими»:
341
+
342
+ - **Фиксируйте данные.** Не используйте `new Date()`, `Math.random()` и т.д. Значения должны быть захардкожены.
343
+ - **Избегайте анимаций** или дождитесь их завершения через `play`. Test-runner использует MutationObserver с таймаутом 500ms.
344
+ - **Каретка скрывается автоматически** — test-runner инжектит `caret-color: transparent`.
345
+ - **Задавайте фиксированные размеры контейнера**, чтобы layout не «плыл» между viewport'ами, где это не нужно.
346
+
347
+ ### Компоновка Visual tests
348
+
349
+ Рендерите несколько вариантов компонента в одной Visual tests стори, а не создавайте отдельную стори на каждый кейс. Это сокращает количество скриншотов и время прогона тестов:
350
+
351
+ ```tsx
352
+ render: () => (
353
+ <div style={{ display: "flex", alignItems: "flex-start", gap: 50, flexWrap: "wrap" }}>
354
+ <Component size={EComponentSize.SM} value="filled" />
355
+ <Component size={EComponentSize.MD} value="filled" />
356
+ <Component size={EComponentSize.LG} value="filled" />
357
+ <Component status={EFormFieldStatus.ERROR} value="filled" />
358
+ {/* ...остальные комбинации */}
359
+ </div>
360
+ ),
361
+ ```
362
+
363
+ Используйте `flexWrap: "wrap"` и `gap`, чтобы варианты не обрезались на узких viewport'ах.
364
+
365
+ ---
366
+
367
+ ## Подписи вариантов
368
+
369
+ В стори, показывающих варианты (Sizes, Statuses), каждый вариант должен быть подписан **рядом** с компонентом:
370
+
371
+ ```tsx
372
+ <div>
373
+ <div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: "700" }}>
374
+ {size.toUpperCase()}
375
+ </div>
376
+ <NumberField size={size} ... />
377
+ </div>
378
+ ```
379
+
380
+ Если в примере уже есть подписи, необходимо проверить, чтобы они были консистентны подписям в других компонентах, при необходимости поменять обертку.
381
+
382
+ ---
383
+
384
+ ## Файл `examples/index.ts`
385
+
386
+ В modern pattern для каждого примера экспортируются два значения — сам компонент и его исходный код:
387
+
388
+ ```ts
389
+ export * from "./DefaultExample";
390
+ export { default as DefaultExampleSource } from "./DefaultExample?raw";
391
+ export * from "./SizesExample";
392
+ export { default as SizesExampleSource } from "./SizesExample?raw";
393
+ ```
394
+
395
+ ---
396
+
397
+ ## Подключение примеров к стори
398
+
399
+ В modern pattern каждая документационная стори подключает пример и его исходный код через `?raw`:
400
+
401
+ ```tsx
402
+ export const Default: StoryObj<typeof Component> = {
403
+ name: "Default",
404
+ render: DefaultExample,
405
+ parameters: {
406
+ docs: {
407
+ controls: { disable: true },
408
+ source: {
409
+ code: DefaultExampleSource,
410
+ language: "tsx",
411
+ },
412
+ },
413
+ },
414
+ };
415
+ ```
416
+
417
+ ---
418
+
419
+ ## Полный пример
420
+
421
+ ### `ComponentName.stories.tsx`
422
+
423
+ ```tsx
424
+ import React, { useState, useCallback } from "react";
425
+ import { Meta, StoryObj } from "@storybook/react";
426
+ import { Title, Description, Primary, Controls, Stories, ArgTypes, Heading } from "@storybook/addon-docs/blocks";
427
+ import { ComponentName, EComponentSize } from "@sberbusiness/triplex-next";
428
+ import { DefaultExample, DefaultExampleSource, SizesExample, SizesExampleSource } from "./examples";
429
+
430
+ const meta = {
431
+ title: "Components/Group/ComponentName",
432
+ component: ComponentName,
433
+ parameters: {
434
+ docs: {
435
+ page: () => (
436
+ <>
437
+ <Title />
438
+ <Description />
439
+ <Heading>Props</Heading>
440
+ <ArgTypes of={ComponentName} />
441
+ <Heading>Playground</Heading>
442
+ <Primary />
443
+ <Controls of={Playground} />
444
+ <Stories />
445
+ </>
446
+ ),
447
+ },
448
+ },
449
+ tags: ["autodocs"],
450
+ } satisfies Meta<typeof ComponentName>;
451
+
452
+ export default meta;
453
+
454
+ export const Playground: StoryObj<typeof meta> = {
455
+ tags: ["!autodocs"],
456
+ args: {
457
+ size: EComponentSize.LG,
458
+ // ...остальные args
459
+ },
460
+ render: ({ ...args }) => {
461
+ // ...render с useState и обработчиками
462
+ },
463
+ argTypes: {
464
+ size: {
465
+ control: { type: "select" },
466
+ options: Object.values(EComponentSize),
467
+ description: "Размер компонента",
468
+ table: {
469
+ type: { summary: "EComponentSize" },
470
+ defaultValue: { summary: "EComponentSize.LG" },
471
+ },
472
+ },
473
+ // ...остальные argTypes
474
+ },
475
+ parameters: {
476
+ testRunner: { skip: true },
477
+ docs: {
478
+ canvas: { sourceState: "none" },
479
+ },
480
+ },
481
+ };
482
+
483
+ export const Default: StoryObj<typeof ComponentName> = {
484
+ name: "Default",
485
+ render: DefaultExample,
486
+ parameters: {
487
+ controls: { disable: true },
488
+ docs: {
489
+ source: {
490
+ code: DefaultExampleSource,
491
+ language: "tsx",
492
+ },
493
+ },
494
+ },
495
+ };
496
+
497
+ export const Sizes: StoryObj<typeof ComponentName> = {
498
+ name: "Sizes",
499
+ render: SizesExample,
500
+ parameters: {
501
+ controls: { disable: true },
502
+ docs: {
503
+ source: {
504
+ code: SizesExampleSource,
505
+ language: "tsx",
506
+ },
507
+ },
508
+ },
509
+ };
510
+ ```
511
+
512
+ ### `examples/DefaultExample.tsx`
513
+
514
+ ```tsx
515
+ import React, { useState } from "react";
516
+ import { ComponentName, EComponentSize } from "@sberbusiness/triplex-next";
517
+
518
+ export const DefaultExample = () => {
519
+ const [value, setValue] = useState<string>("");
520
+
521
+ const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => setValue(event.target.value);
522
+
523
+ return (
524
+ <div style={{ maxWidth: "300px" }}>
525
+ <ComponentName size={EComponentSize.LG} value={value} onChange={handleChange} />
526
+ </div>
527
+ );
528
+ };
529
+ ```
530
+
531
+ ### `examples/SizesExample.tsx`
532
+
533
+ ```tsx
534
+ import React, { useState } from "react";
535
+ import { ComponentName, EComponentSize } from "@sberbusiness/triplex-next";
536
+
537
+ interface ISizeItemProps {
538
+ size: EComponentSize;
539
+ }
540
+
541
+ const SizeItem = ({ size }: ISizeItemProps) => {
542
+ const [value, setValue] = useState<string>("");
543
+
544
+ const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => setValue(event.target.value);
545
+
546
+ return (
547
+ <div>
548
+ <div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: "700" }}>{size.toUpperCase()}</div>
549
+ <ComponentName size={size} value={value} onChange={handleChange} />
550
+ </div>
551
+ );
552
+ };
553
+
554
+ const SIZES = Object.values(EComponentSize);
555
+
556
+ export const SizesExample = () => (
557
+ <div style={{ maxWidth: "300px", display: "flex", flexDirection: "column", gap: "16px" }}>
558
+ {SIZES.map((size) => (
559
+ <SizeItem key={size} size={size} />
560
+ ))}
561
+ </div>
562
+ );
563
+ ```
564
+
565
+ ### `examples/index.ts`
566
+
567
+ ```ts
568
+ export * from "./DefaultExample";
569
+ export { default as DefaultExampleSource } from "./DefaultExample?raw";
570
+ export * from "./SizesExample";
571
+ export { default as SizesExampleSource } from "./SizesExample?raw";
572
+ ```
573
+
574
+ ---
575
+
576
+ ## Чек-лист перед мержем
577
+
578
+ ### Для новых и мигрируемых story-файлов
579
+
580
+ ### Документация и структура
581
+
582
+ - [ ] Есть docs page с `Title`, `Description`, `ArgTypes`, `Playground`, `Stories`
583
+ - [ ] Playground имеет Controls, не показывает код (`sourceState: "none"`)
584
+ - [ ] Playground исключён из скриншот-тестов (`testRunner: { skip: true }`)
585
+ - [ ] Playground скрыт из autodocs (`tags: ["!autodocs"]`)
586
+ - [ ] Все документационные стори, кроме Playground, **не** имеют Controls (`controls: { disable: true }`)
587
+ - [ ] Все документационные стори, кроме Playground, показывают пример кода через `source.code`
588
+ - [ ] Все примеры вынесены в `examples/` и реэкспортированы через `index.ts`
589
+ - [ ] Default — минимальный пример с параметрами по умолчанию
590
+ - [ ] Стори с вариантами (Sizes, Statuses) — каждый вариант подписан рядом с компонентом
591
+ - [ ] Примеры самодостаточны (можно скопировать целиком)
592
+ - [ ] Импорты в примерах из корня пакета (`@sberbusiness/triplex-next`), а не по относительным путям
593
+ - [ ] Порядок: imports → meta → constants → Playground → Default → остальные
594
+ - [ ] Именование сторей соответствует конвенции
595
+
596
+ ### Скриншот-тесты
597
+
598
+ - [ ] Playground исключён из скриншот-тестов (`testRunner: { skip: true }`)
599
+ - [ ] Нет дублирующих скриншотов — визуально идентичные стори исключены через `testRunner: { skip: true }`
600
+ - [ ] Все ключевые визуальные состояния покрыты (размеры, статусы, заполненные поля, фокус)
601
+ - [ ] Если основных сторей недостаточно — создана Visual tests с недостающими состояниями
602
+ - [ ] Visual tests скрыта из autodocs (`tags: ["!autodocs"]`) и не показывает код
603
+ - [ ] Если компонент требует взаимодействия (dropdown, tooltip) — реализован `play` в Visual tests
604
+ - [ ] Данные в Visual tests захардкожены (нет `new Date()`, `Math.random()`)
605
+ - [ ] Контейнеры имеют фиксированные размеры для стабильного layout'а
606
+
607
+ ### Для небольших изменений в legacy stories
608
+
609
+ - [ ] Изменения согласованы с локальным паттерном файла
610
+ - [ ] Playground/Docs/testRunner поведение не сломано
611
+ - [ ] Не изменены story ids/export names без необходимости
612
+ - [ ] Не добавлен большой структурный рефакторинг без отдельной задачи
613
+
614
+ ---
615
+
616
+ ## Эталонный пример
617
+
618
+ Референсная реализация: `stories/NumberField/NumberField.stories.tsx`