@sberbusiness/triplex-next-mcp-server 1.50.0-beta → 1.53.1

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 (74) hide show
  1. package/README.md +1 -0
  2. package/bundle/components/AlertProcess.md +6 -3
  3. package/bundle/components/AlertProcessSpoiler.md +216 -0
  4. package/bundle/components/Badge.md +4 -3
  5. package/bundle/components/ButtonDropdown.md +5 -3
  6. package/bundle/components/Carousel.md +671 -0
  7. package/bundle/components/CarouselExtended.md +7 -5
  8. package/bundle/components/CarouselIndicators.md +666 -0
  9. package/bundle/components/CarouselItem.md +579 -0
  10. package/bundle/components/CarouselNextButton.md +633 -0
  11. package/bundle/components/CarouselPrevButton.md +633 -0
  12. package/bundle/components/CarouselViewport.md +631 -0
  13. package/bundle/components/CheckboxTreeExtended.md +21 -7
  14. package/bundle/components/CheckboxTreeExtendedCheckbox.md +591 -0
  15. package/bundle/components/CheckboxTreeExtendedNode.md +577 -0
  16. package/bundle/components/Chip.md +1 -0
  17. package/bundle/components/ChipDatePicker.md +332 -0
  18. package/bundle/components/ChipDatePickerTarget.md +316 -0
  19. package/bundle/components/ChipMonthYearPicker.md +4 -3
  20. package/bundle/components/ChipMonthYearPickerTarget.md +318 -0
  21. package/bundle/components/ChipMultiselect.md +63 -73
  22. package/bundle/components/ChipSelect.md +385 -0
  23. package/bundle/components/ChipSelectTarget.md +388 -0
  24. package/bundle/components/ChipSuggest.md +10 -16
  25. package/bundle/components/ChipSuggestTarget.md +506 -0
  26. package/bundle/components/CollapsibleTree.md +2 -1
  27. package/bundle/components/CollapsibleTreeExtended.md +2 -1
  28. package/bundle/components/DateField.md +4 -2
  29. package/bundle/components/DatePickerExtended.md +16 -14
  30. package/bundle/components/DateRange.md +17 -10
  31. package/bundle/components/Dropdown.md +36 -63
  32. package/bundle/components/EmptyView.md +9 -4
  33. package/bundle/components/ExpandAnimation.md +9 -5
  34. package/bundle/components/FormField.md +1 -1
  35. package/bundle/components/ImageGallery.md +19 -52
  36. package/bundle/components/ImageGalleryExtended.md +123 -139
  37. package/bundle/components/ListItemControlsButtonDropdown.md +3 -2
  38. package/bundle/components/LoaderSmall.md +5 -4
  39. package/bundle/components/MonthYearRange.md +334 -0
  40. package/bundle/components/MultiselectField.md +81 -143
  41. package/bundle/components/Notification.md +2 -1
  42. package/bundle/components/NotificationGrouped.md +174 -0
  43. package/bundle/components/NumberField.md +259 -116
  44. package/bundle/components/OrderedList.md +149 -112
  45. package/bundle/components/Overlay.md +3 -2
  46. package/bundle/components/PageIndicators.md +306 -0
  47. package/bundle/components/Pagination.md +81 -3
  48. package/bundle/components/PaginationExtended.md +160 -0
  49. package/bundle/components/Portal.md +5 -2
  50. package/bundle/components/Puller.md +375 -0
  51. package/bundle/components/SMSField.md +277 -102
  52. package/bundle/components/SelectExtendedField.md +11 -7
  53. package/bundle/components/SelectField.md +7 -4
  54. package/bundle/components/SmartSpot.md +259 -0
  55. package/bundle/components/Step.md +2 -1
  56. package/bundle/components/Stepper.md +7 -7
  57. package/bundle/components/Suggest.md +7 -6
  58. package/bundle/components/SuggestField.md +8 -6
  59. package/bundle/components/TableBasic.md +12 -14
  60. package/bundle/components/Tooltip.md +9 -8
  61. package/bundle/guides/commits.md +4 -1
  62. package/bundle/guides/context.md +5 -5
  63. package/bundle/guides/stories.md +29 -21
  64. package/bundle/manifest.json +145 -13
  65. package/bundle/release-notes/1.50.0.mdx +4 -0
  66. package/bundle/release-notes/1.51.0.mdx +57 -0
  67. package/bundle/release-notes/1.52.0.mdx +55 -0
  68. package/bundle/release-notes/1.53.0.mdx +60 -0
  69. package/bundle/release-notes/1.54.0.mdx +45 -0
  70. package/bundle/release-notes/1.55.0.mdx +7 -0
  71. package/bundle/tokens.json +377 -222
  72. package/dist/index.js +39 -1
  73. package/dist/index.js.map +1 -1
  74. package/package.json +1 -1
@@ -0,0 +1,385 @@
1
+ ---
2
+ component: ChipSelect
3
+ category: Chips
4
+ related: [Chip, ChipSelectTarget, ChipMultiselect, SelectExtendedField, SelectField]
5
+ tokens: []
6
+ stories: stories/Chips/ChipSelect.stories.tsx
7
+ version: "1.0"
8
+ ---
9
+
10
+ # ChipSelect
11
+
12
+ ## Назначение
13
+
14
+ Компактный фильтр с выбором одной опции из готового списка. Поле выбора выглядит
15
+ как `Chip`: до выбора показывает `label` и стрелку, после — выбранное значение
16
+ и кнопку сброса. На мобильной ширине список открывается в нижней шторке `Puller`.
17
+
18
+ Используй когда: в панели фильтров нужен одиночный выбор с коротким текстом результата.
19
+ Рекомендуется располагать внутри `ChipGroup`.
20
+
21
+ Не используй когда: нужен множественный выбор (`ChipMultiselect`), произвольный
22
+ выпадающий контент (`SelectExtendedField`) или поле формы с placeholder, loading
23
+ и статусом валидации (`SelectField`).
24
+
25
+ Компонент управляемый по выбору: `value` изменяет потребитель через `onChange` и
26
+ `clearSelected`. Состоянием открытости владеет внутренний `SelectExtendedField`.
27
+
28
+ ---
29
+
30
+ ## Варианты и props
31
+
32
+ ### Выбор и отображение
33
+
34
+ | Prop | Обязательность / по умолчанию | Назначение и ограничения |
35
+ |---|---|---|
36
+ | `options` | Обязателен | Массив `ISelectFieldOption`. У каждой опции должны быть стабильный уникальный `id`, `value` и отображаемый `label`. Выбранная опция сопоставляется по `id`, а не по ссылке на объект. |
37
+ | `onChange` | Обязателен | Получает выбранный объект опции; после выбора список закрывается. Сам `value` компонент не меняет. |
38
+ | `clearSelected` | Обязателен | Вызывается без аргументов. Для сброса потребитель устанавливает `value={undefined}`; `onChange` при сбросе не вызывается. |
39
+ | `size` | Обязателен | `EComponentSize.SM` / `MD` / `LG`: одинаковый размер поля выбора и списка. |
40
+ | `value` | `undefined` | Выбранная опция. При наличии значения чипс получает selected-стиль и кнопку сброса. |
41
+ | `label` | — | Контент до выбора; одновременно заголовок списка на мобильном экране, в том числе после выбора. |
42
+ | `displayedValue` | `value.label` | Контент вместо подписи выбранной опции. Без `value` игнорируется. `null` / `undefined` дают fallback на `value.label`; `0` и пустая строка сохраняются. |
43
+
44
+ `ISelectFieldOption` наследует свойства опции `SelectExtendedField`: например,
45
+ `showNotificationIcon` включает значок у пункта списка, а не у самого чипса.
46
+
47
+ ### Вид и открытость
48
+
49
+ | Prop | По умолчанию | Назначение и ограничения |
50
+ |---|---|---|
51
+ | `type` | `EChipType.TYPE_1` | Визуальный тип `TYPE_1` / `TYPE_2` передаётся в `ChipSelectTarget`. |
52
+ | `disabled` | `false` | Убирает target из tab-порядка, блокирует pointer-события стилями `Chip` и отключает кнопку сброса; ограничения см. в Accessibility. |
53
+ | `onOpen`, `onClose` | — | Уведомления о смене открытости без аргументов. На первом рендере не вызываются. |
54
+ | `closeOnTab` | `false` | Наследуется от `SelectExtendedField` и закрывает список при всплывающем Tab, в том числе из dropdown. Сам target закрывает список по Tab независимо от этого флага. |
55
+ | `className`, HTML-атрибуты | — | Передаются корневому `<div>` `SelectExtendedField`, не вложенному чипсу. |
56
+
57
+ ### Граница наследуемого API
58
+
59
+ `IChipSelectProps` наследует часть `IChipProps` и `ISelectFieldProps`, но компонент
60
+ не рендерит `SelectField`. `children`, `targetProps`, `dropdownListItemClassName`,
61
+ `mobileTitle`, `loading`, `status` и `placeholder` исключены из API: target и список
62
+ собираются внутри, мобильный заголовок берётся из `label`.
63
+
64
+ Унаследованный `dropdownProps` присутствует в типе, но текущая реализация не
65
+ передаёт его в `SelectExtendedFieldDropdownDefault`. Не используй его для настройки
66
+ списка.
67
+
68
+ ---
69
+
70
+ ## Дизайн-токены
71
+
72
+ У `ChipSelect` нет собственных токенов: используемый класс `chipGroupItem`
73
+ задаёт только раскладку, поэтому frontmatter содержит `tokens: []`. Поле выбора
74
+ использует `Chip`: пути `Chip.Background_*`, `Chip.Color_*` и `Chip.Shadow_Focus`
75
+ управляют его состояниями. Их значения определены в
76
+ `src/components/DesignTokens/components/Chip.ts`; полный перечень и назначение —
77
+ в [Chip-ai.md](Chip-ai.md#дизайн-токены).
78
+
79
+ Список и мобильный overlay используют токены своих компонентов — см.
80
+ [Dropdown-ai.md](../Dropdown/Dropdown-ai.md#дизайн-токены).
81
+ Переопределение через prop `tokens` описано в
82
+ [ThemeProvider-ai.md](../ThemeProvider/ThemeProvider-ai.md#как-переопределять-токены).
83
+
84
+ ---
85
+
86
+ ## Инварианты
87
+
88
+ - Публичные импорты: `ChipSelect`, `IChipSelectProps`, `ISelectFieldOption`,
89
+ `EChipType`, `EComponentSize` доступны из `@sberbusiness/triplex-next`.
90
+ - `forwardRef<HTMLDivElement>` обязателен: `ref` указывает на корневой `<div>`
91
+ `SelectExtendedField`. Вложенный `ChipSelectTarget` — отдельный `<span>`.
92
+ - Сохранять barrel-экспорты `Chip/index.ts` и `Chip/ChipSelect/index.ts`, включая
93
+ самостоятельный `ChipSelectTarget`.
94
+ - Корневой класс `chipGroupItem` добавляется через `clsx` рядом с пользовательским
95
+ `className`. Чипс внутри также имеет свой `chipGroupItem`.
96
+ - `selected` вычисляется как `value !== undefined`; текст выбранного значения —
97
+ через `displayedValue ?? value.label`. Не заменять на проверку truthiness:
98
+ `displayedValue={0}` и `displayedValue=""` допустимы.
99
+ - Сброс останавливает всплытие клика и не переключает открытость списка;
100
+ `clearSelected` и `onChange` — разные операции.
101
+ - Значения `EChipType`, `EComponentSize`, props, ref-target и токены — публичный
102
+ контракт. Story IDs `chips-chipselect--*` связаны с существующими baseline.
103
+
104
+ ---
105
+
106
+ ## Accessibility
107
+
108
+ - Target — `<span role="button" tabIndex={0}>` с `aria-expanded`, а не combobox.
109
+ Видимый текст из `label` или выбранного значения даёт имя target.
110
+ - Клик переключает открытость. Enter и Space открывают закрытый список;
111
+ Tab на target закрывает открытый. Escape и клик вне поля/списка закрывают через
112
+ `SelectExtendedField`. Клавиатурную навигацию и выбор пунктов реализует `Dropdown`.
113
+ - В отличие от `SelectField`, `ChipSelect` не связывает target со списком через
114
+ `aria-controls` / `aria-activedescendant`. Переданный `aria-label` или
115
+ `aria-labelledby` попадает на корневой `<div>`, не на target: не считай его
116
+ заменой видимого названия чипса.
117
+ - `disabled` задаёт класс и `tabIndex={-1}` на `Chip` и нативный `disabled` на кнопку
118
+ сброса. Сам target — не нативная кнопка: программно отправленные события
119
+ не защищены проверкой флага в обработчиках.
120
+ Не используй такое состояние как защиту бизнес-логики.
121
+ - В selected-состоянии вложена нативная `ChipClearButton`; Enter и Space на ней
122
+ не всплывают в обработчик открытия target. Доступное имя кнопки сброса текущая
123
+ композиция не задаёт и отдельного prop для него нет — известное ограничение
124
+ TRI-139.
125
+ - Собственного управления фокусом и возврата фокуса `ChipSelect` не добавляет;
126
+ поведение overlay определяется компонентами `Dropdown`.
127
+
128
+ ---
129
+
130
+ ## Связанные компоненты
131
+
132
+ - `Chip` — базовый компонент семейства, стили размеров, типов и выбранного состояния.
133
+ - [ChipSelectTarget](ChipSelectTarget-ai.md) — самостоятельный публичный target с кнопкой сброса, стрелкой
134
+ и обработкой клавиатуры; рендерится внутри `ChipSelect`.
135
+ - `ChipMultiselect` — альтернатива для нескольких значений и собственного dropdown-контента.
136
+ - `SelectExtendedField` — рендерится внутри, владеет открытостью и корневым ref.
137
+ - `SelectField` — источник наследуемого интерфейса props и типа опции;
138
+ полная форма поля с другими возможностями отображения.
139
+ - `ChipGroup` — рекомендуемый контейнер раскладки фильтров.
140
+
141
+ ---
142
+
143
+ ## Stories
144
+
145
+ Основные истории: `stories/Chips/ChipSelect.stories.tsx`
146
+ Файлы примеров: `stories/Chips/examples/ChipSelect/`
147
+
148
+ | Story | Example file | Что демонстрирует |
149
+ |---|---|---|
150
+ | `Playground` | `PlaygroundExample.tsx` | Контролы типа, размера, подписей и disabled |
151
+ | `Default` | `DefaultExample.tsx` | Управляемый одиночный выбор и сброс |
152
+ | `Sizes` | `SizesExample.tsx` | SM / MD / LG |
153
+ | `States` | `StatesExample.tsx` | Выбранное и disabled-состояния |
154
+ | `WithNotificationIcon` | `WithNotificationIconExample.tsx` | Значок уведомления у опции списка |
155
+ | `WithCustomDisplayedValue` | `WithCustomDisplayedValueExample.tsx` | Замена текста выбранной опции |
156
+ | `VisualTests` | `VisualTestsExample.tsx` | Размеры и открытый dropdown через play-функцию |
157
+
158
+ Все не-Playground stories имеют baseline `xs` / `xl` в `__screenshots__/`.
159
+ `WithNotificationIcon` дополнительно показан в `VisualTests`, поскольку его
160
+ отдельная story пропускается test-runner.
161
+
162
+ ---
163
+
164
+ ## История изменений
165
+
166
+ | Дата | Изменение |
167
+ |---|---|
168
+ | 2026-10-19 | Создан документ (TRI-131): описаны управляемый выбор, граница наследуемых props, токены и существующие accessibility-ограничения; собственные props оформлены JSDoc, дополнены unit-тесты контракта. |
169
+ | 2026-10-19 | Удалена ссылка на задачу об ограничении доступности, сохранён номер TRI-139. |
170
+ | 2026-10-21 | Переход на `Puller` (TRIPLEX-961): на мобильной ширине список открывается в нижней шторке `Puller`. |
171
+ | 2026-11-06 | Исправлено (TRI-0): при `disabled` кнопка сброса отключена и недоступна с клавиатуры. |
172
+
173
+ ---
174
+
175
+ ## Примеры использования
176
+
177
+ ### Default
178
+
179
+ `stories/Chips/examples/ChipSelect/DefaultExample.tsx`
180
+
181
+ ```tsx
182
+ import React, { useState } from "react";
183
+ import { ChipSelect, EComponentSize, type ISelectFieldOption } from "@sberbusiness/triplex-next";
184
+
185
+ const demoOptions: ISelectFieldOption[] = [
186
+ { id: "1", value: "option1", label: "Первая опция" },
187
+ { id: "2", value: "option2", label: "Вторая опция" },
188
+ { id: "3", value: "option3", label: "Третья опция" },
189
+ { id: "4", value: "option4", label: "Четвертая опция" },
190
+ { id: "5", value: "option5", label: "Пятая опция" },
191
+ { id: "6", value: "option6", label: "Шестая опция" },
192
+ ];
193
+
194
+ export const DefaultExample = () => {
195
+ const [selected, setSelected] = useState<ISelectFieldOption | undefined>();
196
+ return (
197
+ <ChipSelect
198
+ label="Select label"
199
+ size={EComponentSize.MD}
200
+ options={demoOptions}
201
+ value={selected}
202
+ onChange={setSelected}
203
+ clearSelected={() => setSelected(undefined)}
204
+ />
205
+ );
206
+ };
207
+ ```
208
+
209
+ ### Sizes
210
+
211
+ `stories/Chips/examples/ChipSelect/SizesExample.tsx`
212
+
213
+ ```tsx
214
+ import React, { useState } from "react";
215
+ import { ChipSelect, EComponentSize, type ISelectFieldOption } from "@sberbusiness/triplex-next";
216
+
217
+ const demoOptions: ISelectFieldOption[] = [
218
+ { id: "1", value: "option1", label: "Первая опция" },
219
+ { id: "2", value: "option2", label: "Вторая опция" },
220
+ { id: "3", value: "option3", label: "Третья опция" },
221
+ { id: "4", value: "option4", label: "Четвертая опция" },
222
+ { id: "5", value: "option5", label: "Пятая опция" },
223
+ { id: "6", value: "option6", label: "Шестая опция" },
224
+ ];
225
+
226
+ export const SizesExample = () => {
227
+ const [selectedSM, setSelectedSM] = useState<ISelectFieldOption | undefined>();
228
+ const [selectedMD, setSelectedMD] = useState<ISelectFieldOption | undefined>();
229
+ const [selectedLG, setSelectedLG] = useState<ISelectFieldOption | undefined>();
230
+
231
+ return (
232
+ <div style={{ display: "flex", flexDirection: "column", gap: "24px" }}>
233
+ <div>
234
+ <div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: "700" }}>SM</div>
235
+ <ChipSelect
236
+ options={demoOptions}
237
+ value={selectedSM}
238
+ onChange={setSelectedSM}
239
+ clearSelected={() => setSelectedSM(undefined)}
240
+ size={EComponentSize.SM}
241
+ label="Select label"
242
+ />
243
+ </div>
244
+ <div>
245
+ <div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: "700" }}>MD</div>
246
+ <ChipSelect
247
+ options={demoOptions}
248
+ value={selectedMD}
249
+ onChange={setSelectedMD}
250
+ clearSelected={() => setSelectedMD(undefined)}
251
+ size={EComponentSize.MD}
252
+ label="Select label"
253
+ />
254
+ </div>
255
+ <div>
256
+ <div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: "700" }}>LG</div>
257
+ <ChipSelect
258
+ options={demoOptions}
259
+ value={selectedLG}
260
+ onChange={setSelectedLG}
261
+ clearSelected={() => setSelectedLG(undefined)}
262
+ size={EComponentSize.LG}
263
+ label="Select label"
264
+ />
265
+ </div>
266
+ </div>
267
+ );
268
+ };
269
+ ```
270
+
271
+ ### States
272
+
273
+ `stories/Chips/examples/ChipSelect/StatesExample.tsx`
274
+
275
+ ```tsx
276
+ import React, { useState } from "react";
277
+ import { ChipSelect, EComponentSize, type ISelectFieldOption } from "@sberbusiness/triplex-next";
278
+
279
+ const demoOptions: ISelectFieldOption[] = [
280
+ { id: "1", value: "option1", label: "Первая опция" },
281
+ { id: "2", value: "option2", label: "Вторая опция" },
282
+ { id: "3", value: "option3", label: "Третья опция" },
283
+ { id: "4", value: "option4", label: "Четвертая опция" },
284
+ { id: "5", value: "option5", label: "Пятая опция" },
285
+ { id: "6", value: "option6", label: "Шестая опция" },
286
+ ];
287
+
288
+ export const StatesExample = () => {
289
+ const [selectedWithValue, setSelectedWithValue] = useState<ISelectFieldOption | undefined>(demoOptions[0]);
290
+ const [selectedDisabled, setSelectedDisabled] = useState<ISelectFieldOption | undefined>(demoOptions[1]);
291
+
292
+ return (
293
+ <div style={{ display: "flex", flexDirection: "column", gap: "24px" }}>
294
+ <div style={{ display: "flex", flexDirection: "column", gap: "8px" }}>
295
+ <div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: "700" }}>Selected</div>
296
+ <ChipSelect
297
+ label="Select label"
298
+ options={demoOptions}
299
+ value={selectedWithValue}
300
+ onChange={setSelectedWithValue}
301
+ clearSelected={() => setSelectedWithValue(undefined)}
302
+ size={EComponentSize.MD}
303
+ />
304
+ </div>
305
+ <div style={{ display: "flex", flexDirection: "column", gap: "8px" }}>
306
+ <div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: "700" }}>Disabled</div>
307
+ <ChipSelect
308
+ label="Select label"
309
+ options={demoOptions}
310
+ value={selectedDisabled}
311
+ onChange={setSelectedDisabled}
312
+ clearSelected={() => setSelectedDisabled(undefined)}
313
+ disabled
314
+ size={EComponentSize.MD}
315
+ />
316
+ </div>
317
+ </div>
318
+ );
319
+ };
320
+ ```
321
+
322
+ ### WithNotificationIcon
323
+
324
+ `stories/Chips/examples/ChipSelect/WithNotificationIconExample.tsx`
325
+
326
+ ```tsx
327
+ import React, { useState } from "react";
328
+ import { ChipSelect, EComponentSize, type ISelectFieldOption } from "@sberbusiness/triplex-next";
329
+
330
+ const options: ISelectFieldOption[] = [
331
+ { id: "1", value: "option1", label: "Первая опция" },
332
+ { id: "2", value: "option2", label: "Вторая опция", showNotificationIcon: true },
333
+ { id: "3", value: "option3", label: "Третья опция" },
334
+ { id: "4", value: "option4", label: "Четвертая опция" },
335
+ ];
336
+
337
+ export const WithNotificationIconExample = () => {
338
+ const [selected, setSelected] = useState<ISelectFieldOption | undefined>();
339
+
340
+ return (
341
+ <ChipSelect
342
+ size={EComponentSize.MD}
343
+ label="Select label"
344
+ options={options}
345
+ value={selected}
346
+ onChange={setSelected}
347
+ clearSelected={() => setSelected(undefined)}
348
+ />
349
+ );
350
+ };
351
+ ```
352
+
353
+ ### WithCustomDisplayedValue
354
+
355
+ `stories/Chips/examples/ChipSelect/WithCustomDisplayedValueExample.tsx`
356
+
357
+ ```tsx
358
+ import React, { useState } from "react";
359
+ import { ChipSelect, EComponentSize, type ISelectFieldOption } from "@sberbusiness/triplex-next";
360
+
361
+ const demoOptions: ISelectFieldOption[] = [
362
+ { id: "1", value: "option1", label: "Первая опция" },
363
+ { id: "2", value: "option2", label: "Вторая опция" },
364
+ { id: "3", value: "option3", label: "Третья опция" },
365
+ { id: "4", value: "option4", label: "Четвертая опция" },
366
+ { id: "5", value: "option5", label: "Пятая опция" },
367
+ { id: "6", value: "option6", label: "Шестая опция" },
368
+ ];
369
+
370
+ export const WithCustomDisplayedValueExample = () => {
371
+ const [selected, setSelected] = useState<ISelectFieldOption | undefined>(demoOptions[0]);
372
+ return (
373
+ <ChipSelect
374
+ label="Select label"
375
+ options={demoOptions}
376
+ value={selected}
377
+ onChange={setSelected}
378
+ clearSelected={() => setSelected(undefined)}
379
+ displayedValue="Displayed value"
380
+ size={EComponentSize.MD}
381
+ />
382
+ );
383
+ };
384
+ ```
385
+