@commercetools/nimbus-mcp 0.1.0 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (450) hide show
  1. package/README.md +63 -14
  2. package/data/docs/route-manifest.json +10913 -0
  3. package/data/docs/routes/components-accessibility-visually-hidden.json +388 -0
  4. package/data/docs/routes/components-accessibility.json +34 -0
  5. package/data/docs/routes/components-buttons-button.json +715 -0
  6. package/data/docs/routes/components-buttons-icon-button.json +852 -0
  7. package/data/docs/routes/components-buttons-icon-toggle-button.json +594 -0
  8. package/data/docs/routes/components-buttons-split-button.json +670 -0
  9. package/data/docs/routes/components-buttons-toggle-button-group.json +722 -0
  10. package/data/docs/routes/components-buttons-toggle-button.json +689 -0
  11. package/data/docs/routes/components-buttons.json +36 -0
  12. package/data/docs/routes/components-data-display-badge.json +555 -0
  13. package/data/docs/routes/components-data-display-card.json +338 -0
  14. package/data/docs/routes/components-data-display-data-table.json +855 -0
  15. package/data/docs/routes/components-data-display-draggable-list.json +596 -0
  16. package/data/docs/routes/components-data-display-table.json +472 -0
  17. package/data/docs/routes/components-data-display-tag-group.json +535 -0
  18. package/data/docs/routes/components-data-display.json +34 -0
  19. package/data/docs/routes/components-feedback-alert.json +696 -0
  20. package/data/docs/routes/components-feedback-dialog.json +682 -0
  21. package/data/docs/routes/components-feedback-drawer.json +600 -0
  22. package/data/docs/routes/components-feedback-loading-spinner.json +415 -0
  23. package/data/docs/routes/components-feedback-progress-bar.json +661 -0
  24. package/data/docs/routes/components-feedback-toast.json +1040 -0
  25. package/data/docs/routes/components-feedback-tooltip.json +510 -0
  26. package/data/docs/routes/components-feedback.json +34 -0
  27. package/data/docs/routes/components-forms-field-errors.json +557 -0
  28. package/data/docs/routes/components-forms-form-field.json +848 -0
  29. package/data/docs/routes/components-forms-group.json +427 -0
  30. package/data/docs/routes/components-forms-localized-field.json +770 -0
  31. package/data/docs/routes/components-forms.json +37 -0
  32. package/data/docs/routes/components-inputs-calendar.json +611 -0
  33. package/data/docs/routes/components-inputs-checkbox.json +774 -0
  34. package/data/docs/routes/components-inputs-combo-box.json +761 -0
  35. package/data/docs/routes/components-inputs-date-input.json +628 -0
  36. package/data/docs/routes/components-inputs-date-picker.json +709 -0
  37. package/data/docs/routes/components-inputs-date-range-picker.json +599 -0
  38. package/data/docs/routes/components-inputs-money-input.json +721 -0
  39. package/data/docs/routes/components-inputs-multiline-text-input.json +611 -0
  40. package/data/docs/routes/components-inputs-number-input.json +647 -0
  41. package/data/docs/routes/components-inputs-password-input.json +576 -0
  42. package/data/docs/routes/components-inputs-radio-input.json +583 -0
  43. package/data/docs/routes/components-inputs-range-calendar.json +607 -0
  44. package/data/docs/routes/components-inputs-rich-text-input.json +599 -0
  45. package/data/docs/routes/components-inputs-scoped-search-input.json +570 -0
  46. package/data/docs/routes/components-inputs-search-input.json +588 -0
  47. package/data/docs/routes/components-inputs-select-input.json +960 -0
  48. package/data/docs/routes/components-inputs-switch.json +720 -0
  49. package/data/docs/routes/components-inputs-text-input.json +566 -0
  50. package/data/docs/routes/components-inputs-time-input.json +775 -0
  51. package/data/docs/routes/components-inputs.json +34 -0
  52. package/data/docs/routes/components-layout-box.json +501 -0
  53. package/data/docs/routes/components-layout-defaultpage.json +748 -0
  54. package/data/docs/routes/components-layout-flex.json +587 -0
  55. package/data/docs/routes/components-layout-grid.json +393 -0
  56. package/data/docs/routes/components-layout-modalpage.json +716 -0
  57. package/data/docs/routes/components-layout-pagecontent.json +673 -0
  58. package/data/docs/routes/components-layout-separator.json +461 -0
  59. package/data/docs/routes/components-layout-simple-grid.json +519 -0
  60. package/data/docs/routes/components-layout-spacer.json +573 -0
  61. package/data/docs/routes/components-layout-stack.json +481 -0
  62. package/data/docs/routes/components-layout.json +34 -0
  63. package/data/docs/routes/components-media-avatar.json +427 -0
  64. package/data/docs/routes/components-media-icon.json +663 -0
  65. package/data/docs/routes/components-media-image.json +511 -0
  66. package/data/docs/routes/components-media-inline-svg.json +586 -0
  67. package/data/docs/routes/components-media.json +34 -0
  68. package/data/docs/routes/components-navigation-accordion.json +643 -0
  69. package/data/docs/routes/components-navigation-collapsible-motion.json +628 -0
  70. package/data/docs/routes/components-navigation-link.json +554 -0
  71. package/data/docs/routes/components-navigation-menu.json +546 -0
  72. package/data/docs/routes/components-navigation-pagination.json +502 -0
  73. package/data/docs/routes/components-navigation-steps.json +629 -0
  74. package/data/docs/routes/components-navigation-tabnav.json +546 -0
  75. package/data/docs/routes/components-navigation-tabs.json +635 -0
  76. package/data/docs/routes/components-navigation-toolbar.json +549 -0
  77. package/data/docs/routes/components-navigation.json +34 -0
  78. package/data/docs/routes/components-typography-code.json +39 -0
  79. package/data/docs/routes/components-typography-heading.json +402 -0
  80. package/data/docs/routes/components-typography-kbd.json +399 -0
  81. package/data/docs/routes/components-typography-list.json +593 -0
  82. package/data/docs/routes/components-typography-text.json +444 -0
  83. package/data/docs/routes/components-typography.json +34 -0
  84. package/data/docs/routes/components-utilities-nimbus-i18n-provider.json +295 -0
  85. package/data/docs/routes/components-utilities-nimbus-provider.json +663 -0
  86. package/data/docs/routes/components-utilities.json +34 -0
  87. package/data/docs/routes/components.json +33 -0
  88. package/data/docs/routes/home-contribute-adrs-adr0001-consumer-component-apis.json +314 -0
  89. package/data/docs/routes/home-contribute-adrs-adr0002-compound-component-extraction.json +160 -0
  90. package/data/docs/routes/home-contribute-adrs-adr0003-component-lifecycle-states.json +460 -0
  91. package/data/docs/routes/home-contribute-adrs.json +205 -0
  92. package/data/docs/routes/home-contribute-development-setup.json +213 -0
  93. package/data/docs/routes/home-contribute-stats.json +36 -0
  94. package/data/docs/routes/home-contribute.json +36 -0
  95. package/data/docs/routes/home-design-tokens-aspect-ratios.json +36 -0
  96. package/data/docs/routes/home-design-tokens-borders.json +35 -0
  97. package/data/docs/routes/home-design-tokens-colors.json +157 -0
  98. package/data/docs/routes/home-design-tokens-other-animations.json +119 -0
  99. package/data/docs/routes/home-design-tokens-other-blurs.json +36 -0
  100. package/data/docs/routes/home-design-tokens-other-breakpoints.json +61 -0
  101. package/data/docs/routes/home-design-tokens-other-cursors.json +36 -0
  102. package/data/docs/routes/home-design-tokens-other-z-indices.json +39 -0
  103. package/data/docs/routes/home-design-tokens-other.json +35 -0
  104. package/data/docs/routes/home-design-tokens-radii.json +59 -0
  105. package/data/docs/routes/home-design-tokens-shadows.json +57 -0
  106. package/data/docs/routes/home-design-tokens-sizes.json +137 -0
  107. package/data/docs/routes/home-design-tokens-spacing.json +36 -0
  108. package/data/docs/routes/home-design-tokens-typography.json +184 -0
  109. package/data/docs/routes/home-design-tokens.json +34 -0
  110. package/data/docs/routes/home-getting-started-core-concepts.json +301 -0
  111. package/data/docs/routes/home-getting-started-installation.json +621 -0
  112. package/data/docs/routes/home-getting-started-mcp-server-overview.json +139 -0
  113. package/data/docs/routes/home-getting-started-mcp-server-setup.json +316 -0
  114. package/data/docs/routes/home-getting-started-release-process.json +294 -0
  115. package/data/docs/routes/home-getting-started-testing-setup.json +296 -0
  116. package/data/docs/routes/home-playground-markdown.json +638 -0
  117. package/data/docs/routes/home-playground-toc.json +169 -0
  118. package/data/docs/routes/home-playground.json +34 -0
  119. package/data/docs/routes/home-style-props-background.json +236 -0
  120. package/data/docs/routes/home-style-props-border.json +310 -0
  121. package/data/docs/routes/home-style-props-display.json +120 -0
  122. package/data/docs/routes/home-style-props-effects.json +116 -0
  123. package/data/docs/routes/home-style-props-filters.json +396 -0
  124. package/data/docs/routes/home-style-props-flex-and-grid.json +496 -0
  125. package/data/docs/routes/home-style-props-interactivity.json +356 -0
  126. package/data/docs/routes/home-style-props-layout.json +422 -0
  127. package/data/docs/routes/home-style-props-list.json +116 -0
  128. package/data/docs/routes/home-style-props-sizing.json +244 -0
  129. package/data/docs/routes/home-style-props-spacing.json +228 -0
  130. package/data/docs/routes/home-style-props-svg.json +96 -0
  131. package/data/docs/routes/home-style-props-tables.json +116 -0
  132. package/data/docs/routes/home-style-props-transforms.json +216 -0
  133. package/data/docs/routes/home-style-props-transitions.json +216 -0
  134. package/data/docs/routes/home-style-props-typography.json +536 -0
  135. package/data/docs/routes/home-style-props.json +33 -0
  136. package/data/docs/routes/home.json +32 -0
  137. package/data/docs/routes/hooks-usecopytoclipboard.json +76 -0
  138. package/data/docs/routes/hooks-usehotkeys.json +117 -0
  139. package/data/docs/routes/hooks.json +33 -0
  140. package/data/docs/routes/icons.json +32 -0
  141. package/data/docs/routes/patterns-fields-date-range-picker-field.json +393 -0
  142. package/data/docs/routes/patterns-fields-money-input-field.json +415 -0
  143. package/data/docs/routes/patterns-fields-multiline-text-input-field.json +404 -0
  144. package/data/docs/routes/patterns-fields-number-input-field.json +470 -0
  145. package/data/docs/routes/patterns-fields-password-input-field.json +319 -0
  146. package/data/docs/routes/patterns-fields-search-input-field.json +382 -0
  147. package/data/docs/routes/patterns-fields-text-input-field.json +404 -0
  148. package/data/docs/routes/patterns-fields.json +78 -0
  149. package/data/docs/routes/patterns.json +34 -0
  150. package/data/docs/search-index.json +1 -0
  151. package/data/docs/types/Accordion.json +12 -0
  152. package/data/docs/types/AccordionContent.json +286 -0
  153. package/data/docs/types/AccordionHeader.json +891 -0
  154. package/data/docs/types/AccordionHeaderRightContent.json +27 -0
  155. package/data/docs/types/AccordionItem.json +242 -0
  156. package/data/docs/types/AccordionRoot.json +162 -0
  157. package/data/docs/types/Alert.json +12 -0
  158. package/data/docs/types/AlertActions.json +11 -0
  159. package/data/docs/types/AlertDescription.json +118 -0
  160. package/data/docs/types/AlertDismissButton.json +937 -0
  161. package/data/docs/types/AlertRoot.json +42 -0
  162. package/data/docs/types/AlertTitle.json +118 -0
  163. package/data/docs/types/Avatar.json +125 -0
  164. package/data/docs/types/Badge.json +64 -0
  165. package/data/docs/types/Body.json +67 -0
  166. package/data/docs/types/Box.json +85 -0
  167. package/data/docs/types/Button.json +1015 -0
  168. package/data/docs/types/Calendar.json +565 -0
  169. package/data/docs/types/Caption.json +67 -0
  170. package/data/docs/types/Card.json +12 -0
  171. package/data/docs/types/CardContent.json +27 -0
  172. package/data/docs/types/CardHeader.json +27 -0
  173. package/data/docs/types/CardRoot.json +106 -0
  174. package/data/docs/types/Cell.json +227 -0
  175. package/data/docs/types/Checkbox.json +897 -0
  176. package/data/docs/types/Code.json +112 -0
  177. package/data/docs/types/CollapsibleMotionContent.json +35 -0
  178. package/data/docs/types/CollapsibleMotionRoot.json +99 -0
  179. package/data/docs/types/CollapsibleMotionTrigger.json +71 -0
  180. package/data/docs/types/Column.json +101 -0
  181. package/data/docs/types/ColumnGroup.json +101 -0
  182. package/data/docs/types/ColumnHeader.json +193 -0
  183. package/data/docs/types/ComboBoxListBox.json +751 -0
  184. package/data/docs/types/ComboBoxOption.json +672 -0
  185. package/data/docs/types/ComboBoxPopover.json +786 -0
  186. package/data/docs/types/ComboBoxRoot.json +747 -0
  187. package/data/docs/types/ComboBoxSection.json +277 -0
  188. package/data/docs/types/ComboBoxTrigger.json +70 -0
  189. package/data/docs/types/Content.json +33 -0
  190. package/data/docs/types/DataTable.json +596 -0
  191. package/data/docs/types/DataTableBody.json +223 -0
  192. package/data/docs/types/DataTableFooter.json +27 -0
  193. package/data/docs/types/DataTableHeader.json +269 -0
  194. package/data/docs/types/DataTableManager.json +11 -0
  195. package/data/docs/types/DataTableRoot.json +590 -0
  196. package/data/docs/types/DataTableTable.json +271 -0
  197. package/data/docs/types/DateInput.json +792 -0
  198. package/data/docs/types/DatePicker.json +700 -0
  199. package/data/docs/types/DateRangePicker.json +936 -0
  200. package/data/docs/types/DateRangePickerField.json +1047 -0
  201. package/data/docs/types/DefaultPage.json +12 -0
  202. package/data/docs/types/DefaultPageActions.json +27 -0
  203. package/data/docs/types/DefaultPageBackLink.json +213 -0
  204. package/data/docs/types/DefaultPageContent.json +27 -0
  205. package/data/docs/types/DefaultPageFooter.json +27 -0
  206. package/data/docs/types/DefaultPageHeader.json +27 -0
  207. package/data/docs/types/DefaultPageRoot.json +106 -0
  208. package/data/docs/types/DefaultPageSubtitle.json +27 -0
  209. package/data/docs/types/DefaultPageTabNav.json +28 -0
  210. package/data/docs/types/DefaultPageTitle.json +27 -0
  211. package/data/docs/types/DialogBody.json +27 -0
  212. package/data/docs/types/DialogCloseTrigger.json +939 -0
  213. package/data/docs/types/DialogContent.json +27 -0
  214. package/data/docs/types/DialogFooter.json +27 -0
  215. package/data/docs/types/DialogHeader.json +27 -0
  216. package/data/docs/types/DialogRoot.json +138 -0
  217. package/data/docs/types/DialogTitle.json +27 -0
  218. package/data/docs/types/DialogTrigger.json +80 -0
  219. package/data/docs/types/DraggableList.json +12 -0
  220. package/data/docs/types/DraggableListField.json +894 -0
  221. package/data/docs/types/DraggableListItem.json +574 -0
  222. package/data/docs/types/DraggableListRoot.json +745 -0
  223. package/data/docs/types/Drawer.json +12 -0
  224. package/data/docs/types/DrawerBody.json +27 -0
  225. package/data/docs/types/DrawerCloseTrigger.json +939 -0
  226. package/data/docs/types/DrawerContent.json +27 -0
  227. package/data/docs/types/DrawerFooter.json +27 -0
  228. package/data/docs/types/DrawerHeader.json +27 -0
  229. package/data/docs/types/DrawerRoot.json +142 -0
  230. package/data/docs/types/DrawerTitle.json +27 -0
  231. package/data/docs/types/DrawerTrigger.json +80 -0
  232. package/data/docs/types/FieldErrors.getBuiltInMessage.json +11 -0
  233. package/data/docs/types/FieldErrors.getCustomMessage.json +9 -0
  234. package/data/docs/types/FieldErrors.json +109 -0
  235. package/data/docs/types/Flex.json +238 -0
  236. package/data/docs/types/Footer.json +67 -0
  237. package/data/docs/types/FormFieldDescription.json +11 -0
  238. package/data/docs/types/FormFieldError.json +11 -0
  239. package/data/docs/types/FormFieldInfoBox.json +27 -0
  240. package/data/docs/types/FormFieldInput.json +11 -0
  241. package/data/docs/types/FormFieldLabel.json +11 -0
  242. package/data/docs/types/FormFieldRoot.json +148 -0
  243. package/data/docs/types/Grid.json +253 -0
  244. package/data/docs/types/GridProps.json +11 -0
  245. package/data/docs/types/Group.json +143 -0
  246. package/data/docs/types/Header.json +67 -0
  247. package/data/docs/types/Heading.json +109 -0
  248. package/data/docs/types/Icon.json +112 -0
  249. package/data/docs/types/IconButton.json +1019 -0
  250. package/data/docs/types/IconToggleButton.json +787 -0
  251. package/data/docs/types/Image.json +373 -0
  252. package/data/docs/types/Indicator.json +67 -0
  253. package/data/docs/types/InlineSvg.json +98 -0
  254. package/data/docs/types/Item.json +67 -0
  255. package/data/docs/types/Kbd.json +118 -0
  256. package/data/docs/types/Link.json +380 -0
  257. package/data/docs/types/List.json +12 -0
  258. package/data/docs/types/ListIndicator.json +70 -0
  259. package/data/docs/types/ListItem.json +70 -0
  260. package/data/docs/types/ListRoot.json +124 -0
  261. package/data/docs/types/LoadingSpinner.json +87 -0
  262. package/data/docs/types/LocalizedField.json +460 -0
  263. package/data/docs/types/LocalizedStringFormatter.json +9 -0
  264. package/data/docs/types/MakeElementFocusable.json +196 -0
  265. package/data/docs/types/MenuContent.json +111 -0
  266. package/data/docs/types/MenuItem.json +671 -0
  267. package/data/docs/types/MenuRoot.json +670 -0
  268. package/data/docs/types/MenuSection.json +364 -0
  269. package/data/docs/types/MenuSubmenu.json +111 -0
  270. package/data/docs/types/MenuSubmenuTrigger.json +67 -0
  271. package/data/docs/types/MenuTrigger.json +906 -0
  272. package/data/docs/types/ModalPage.json +12 -0
  273. package/data/docs/types/ModalPageActions.json +27 -0
  274. package/data/docs/types/ModalPageContent.json +27 -0
  275. package/data/docs/types/ModalPageFooter.json +27 -0
  276. package/data/docs/types/ModalPageHeader.json +27 -0
  277. package/data/docs/types/ModalPageRoot.json +87 -0
  278. package/data/docs/types/ModalPageSubtitle.json +27 -0
  279. package/data/docs/types/ModalPageTabNav.json +28 -0
  280. package/data/docs/types/ModalPageTitle.json +27 -0
  281. package/data/docs/types/ModalPageTopBar.json +57 -0
  282. package/data/docs/types/MoneyInput.isEmpty.json +40 -0
  283. package/data/docs/types/MoneyInput.json +282 -0
  284. package/data/docs/types/MoneyInputField.json +379 -0
  285. package/data/docs/types/MoneyInputFieldProps.json +9 -0
  286. package/data/docs/types/MultilineTextInput.json +1194 -0
  287. package/data/docs/types/MultilineTextInputField.json +1269 -0
  288. package/data/docs/types/MultilineTextInputFieldProps.json +9 -0
  289. package/data/docs/types/NimbusI18nProvider.json +42 -0
  290. package/data/docs/types/NimbusI18nProviderProps.json +9 -0
  291. package/data/docs/types/NimbusProvider.json +270 -0
  292. package/data/docs/types/NumberInput.json +952 -0
  293. package/data/docs/types/NumberInputField.json +1004 -0
  294. package/data/docs/types/NumberInputFieldProps.json +9 -0
  295. package/data/docs/types/PageContent.json +11 -0
  296. package/data/docs/types/PageContentColumn.json +99 -0
  297. package/data/docs/types/PageContentRoot.json +114 -0
  298. package/data/docs/types/Pagination.json +159 -0
  299. package/data/docs/types/PasswordInput.json +1120 -0
  300. package/data/docs/types/PasswordInputField.json +1216 -0
  301. package/data/docs/types/PasswordInputFieldProps.json +9 -0
  302. package/data/docs/types/ProgressBar.json +280 -0
  303. package/data/docs/types/RadioInputOption.json +550 -0
  304. package/data/docs/types/RadioInputRoot.json +514 -0
  305. package/data/docs/types/RangeCalendar.json +618 -0
  306. package/data/docs/types/RichTextInput.json +134 -0
  307. package/data/docs/types/Root.json +122 -0
  308. package/data/docs/types/Row.json +67 -0
  309. package/data/docs/types/ScopedSearchInput.isEmpty.json +40 -0
  310. package/data/docs/types/ScopedSearchInput.json +253 -0
  311. package/data/docs/types/ScrollArea.json +82 -0
  312. package/data/docs/types/SearchInput.json +1165 -0
  313. package/data/docs/types/SearchInputField.json +1240 -0
  314. package/data/docs/types/Select.json +12 -0
  315. package/data/docs/types/SelectOption.json +572 -0
  316. package/data/docs/types/SelectOptionGroup.json +215 -0
  317. package/data/docs/types/SelectOptions.json +693 -0
  318. package/data/docs/types/SelectRoot.json +926 -0
  319. package/data/docs/types/Separator.json +65 -0
  320. package/data/docs/types/SimpleGrid.json +291 -0
  321. package/data/docs/types/Spacer.json +27 -0
  322. package/data/docs/types/SpacerProps.json +9 -0
  323. package/data/docs/types/SplitButton.json +203 -0
  324. package/data/docs/types/Stack.json +144 -0
  325. package/data/docs/types/Steps.json +12 -0
  326. package/data/docs/types/StepsChangeDetails.json +9 -0
  327. package/data/docs/types/StepsCompletedContent.json +28 -0
  328. package/data/docs/types/StepsCompletedContentProps.json +9 -0
  329. package/data/docs/types/StepsContent.json +43 -0
  330. package/data/docs/types/StepsContentProps.json +9 -0
  331. package/data/docs/types/StepsDescription.json +28 -0
  332. package/data/docs/types/StepsDescriptionProps.json +9 -0
  333. package/data/docs/types/StepsIndicator.json +28 -0
  334. package/data/docs/types/StepsIndicatorProps.json +9 -0
  335. package/data/docs/types/StepsItem.json +43 -0
  336. package/data/docs/types/StepsItemProps.json +9 -0
  337. package/data/docs/types/StepsList.json +28 -0
  338. package/data/docs/types/StepsListProps.json +9 -0
  339. package/data/docs/types/StepsNextTrigger.json +62 -0
  340. package/data/docs/types/StepsNextTriggerProps.json +9 -0
  341. package/data/docs/types/StepsNumber.json +28 -0
  342. package/data/docs/types/StepsNumberProps.json +9 -0
  343. package/data/docs/types/StepsPrevTrigger.json +62 -0
  344. package/data/docs/types/StepsPrevTriggerProps.json +9 -0
  345. package/data/docs/types/StepsRoot.json +183 -0
  346. package/data/docs/types/StepsRootProps.json +11 -0
  347. package/data/docs/types/StepsSeparator.json +28 -0
  348. package/data/docs/types/StepsSeparatorProps.json +9 -0
  349. package/data/docs/types/StepsStatus.json +57 -0
  350. package/data/docs/types/StepsStatusProps.json +9 -0
  351. package/data/docs/types/StepsTitle.json +28 -0
  352. package/data/docs/types/StepsTitleProps.json +9 -0
  353. package/data/docs/types/StepsTrigger.json +47 -0
  354. package/data/docs/types/StepsTriggerProps.json +9 -0
  355. package/data/docs/types/Switch.json +371 -0
  356. package/data/docs/types/TabListProps.json +9 -0
  357. package/data/docs/types/TabNav.json +12 -0
  358. package/data/docs/types/TabNavItem.json +300 -0
  359. package/data/docs/types/TabNavItemProps.json +9 -0
  360. package/data/docs/types/TabNavProps.json +9 -0
  361. package/data/docs/types/TabNavRoot.json +80 -0
  362. package/data/docs/types/TabPanelProps.json +9 -0
  363. package/data/docs/types/TabPanelsProps.json +9 -0
  364. package/data/docs/types/TabProps.json +9 -0
  365. package/data/docs/types/Table.json +9 -0
  366. package/data/docs/types/TableBody.json +67 -0
  367. package/data/docs/types/TableBodyProps.json +9 -0
  368. package/data/docs/types/TableCaption.json +67 -0
  369. package/data/docs/types/TableCaptionProps.json +9 -0
  370. package/data/docs/types/TableCell.json +227 -0
  371. package/data/docs/types/TableCellProps.json +9 -0
  372. package/data/docs/types/TableColumn.json +101 -0
  373. package/data/docs/types/TableColumnGroup.json +101 -0
  374. package/data/docs/types/TableColumnGroupProps.json +9 -0
  375. package/data/docs/types/TableColumnHeader.json +193 -0
  376. package/data/docs/types/TableColumnHeaderProps.json +9 -0
  377. package/data/docs/types/TableColumnProps.json +9 -0
  378. package/data/docs/types/TableFooter.json +67 -0
  379. package/data/docs/types/TableFooterProps.json +9 -0
  380. package/data/docs/types/TableHeader.json +67 -0
  381. package/data/docs/types/TableHeaderProps.json +9 -0
  382. package/data/docs/types/TableRoot.json +365 -0
  383. package/data/docs/types/TableRootProps.json +12 -0
  384. package/data/docs/types/TableRow.json +67 -0
  385. package/data/docs/types/TableRowProps.json +9 -0
  386. package/data/docs/types/TableScrollArea.json +82 -0
  387. package/data/docs/types/TableScrollAreaProps.json +9 -0
  388. package/data/docs/types/Tabs.json +12 -0
  389. package/data/docs/types/TabsList.json +110 -0
  390. package/data/docs/types/TabsPanel.json +112 -0
  391. package/data/docs/types/TabsPanels.json +108 -0
  392. package/data/docs/types/TabsRoot.json +211 -0
  393. package/data/docs/types/TabsTab.json +174 -0
  394. package/data/docs/types/TagGroup.json +12 -0
  395. package/data/docs/types/TagGroupRoot.json +306 -0
  396. package/data/docs/types/TagGroupTag.json +595 -0
  397. package/data/docs/types/TagGroupTagList.json +166 -0
  398. package/data/docs/types/Text.json +119 -0
  399. package/data/docs/types/TextInput.json +1156 -0
  400. package/data/docs/types/TextInputField.json +1263 -0
  401. package/data/docs/types/TimeInput.json +752 -0
  402. package/data/docs/types/ToastAction.json +9 -0
  403. package/data/docs/types/ToastManagerApi.json +9 -0
  404. package/data/docs/types/ToastOptions.json +9 -0
  405. package/data/docs/types/ToastOutlet.json +12 -0
  406. package/data/docs/types/ToastPlacement.json +9 -0
  407. package/data/docs/types/ToastPromiseOptions.json +9 -0
  408. package/data/docs/types/ToastType.json +9 -0
  409. package/data/docs/types/ToastVariant.json +9 -0
  410. package/data/docs/types/ToggleButton.json +789 -0
  411. package/data/docs/types/ToggleButtonGroup.json +9 -0
  412. package/data/docs/types/ToggleButtonGroupButton.json +331 -0
  413. package/data/docs/types/ToggleButtonGroupRoot.json +269 -0
  414. package/data/docs/types/Toolbar.json +176 -0
  415. package/data/docs/types/Tooltip.json +12 -0
  416. package/data/docs/types/TooltipContent.json +372 -0
  417. package/data/docs/types/TooltipRoot.json +179 -0
  418. package/data/docs/types/Trigger.json +69 -0
  419. package/data/docs/types/VisuallyHidden.json +93 -0
  420. package/data/docs/types/__object.json +12 -0
  421. package/data/docs/types/filters.json +11 -0
  422. package/data/docs/types/manifest.json +278 -0
  423. package/data/docs/types/toast.json +234 -0
  424. package/data/docs/types/useColorMode.json +13 -0
  425. package/data/docs/types/useColorModeValue.json +13 -0
  426. package/data/docs/types/useColorScheme.json +12 -0
  427. package/data/docs/types/useLocalizedStringFormatter.json +14 -0
  428. package/data/icons.json +21940 -0
  429. package/data/tokens.json +40061 -0
  430. package/dist/index.js +2516 -17
  431. package/package.json +25 -6
  432. package/dist/data-loader.d.ts +0 -102
  433. package/dist/data-loader.js +0 -104
  434. package/dist/index.d.ts +0 -13
  435. package/dist/server.d.ts +0 -9
  436. package/dist/server.js +0 -22
  437. package/dist/server.spec.d.ts +0 -1
  438. package/dist/server.spec.js +0 -69
  439. package/dist/tools/list-components.d.ts +0 -9
  440. package/dist/tools/list-components.js +0 -42
  441. package/dist/types.d.ts +0 -28
  442. package/dist/types.js +0 -4
  443. package/src/data-loader.ts +0 -226
  444. package/src/index.ts +0 -29
  445. package/src/server.spec.ts +0 -86
  446. package/src/server.ts +0 -28
  447. package/src/tools/list-components.ts +0 -49
  448. package/src/types.ts +0 -31
  449. package/tsconfig.json +0 -14
  450. package/vitest.config.ts +0 -9
@@ -0,0 +1,770 @@
1
+ {
2
+ "meta": {
3
+ "id": "Components-LocalizedField",
4
+ "title": "Localized field",
5
+ "exportName": "LocalizedField",
6
+ "description": "A localized field is a single component that enables users to input and manage content for multiple language versions of a piece of data within one unified form area.",
7
+ "lifecycleState": "Stable",
8
+ "order": 999,
9
+ "repoPath": "packages/nimbus/src/components/localized-field/localized-field.mdx",
10
+ "menu": [
11
+ "Components",
12
+ "Forms",
13
+ "Localized field"
14
+ ],
15
+ "route": "components/forms/localized-field",
16
+ "tags": [
17
+ "component",
18
+ "form",
19
+ "l10n",
20
+ "i18n",
21
+ "localization"
22
+ ],
23
+ "toc": [
24
+ {
25
+ "value": "Overview",
26
+ "href": "#overview",
27
+ "depth": 2,
28
+ "numbering": [
29
+ 1,
30
+ 1
31
+ ],
32
+ "parent": "root"
33
+ },
34
+ {
35
+ "value": "Resources",
36
+ "href": "#resources",
37
+ "depth": 3,
38
+ "numbering": [
39
+ 1,
40
+ 1,
41
+ 1
42
+ ],
43
+ "parent": "root"
44
+ },
45
+ {
46
+ "value": "Variables",
47
+ "href": "#variables",
48
+ "depth": 2,
49
+ "numbering": [
50
+ 1,
51
+ 2
52
+ ],
53
+ "parent": "root"
54
+ },
55
+ {
56
+ "value": "Size",
57
+ "href": "#size",
58
+ "depth": 3,
59
+ "numbering": [
60
+ 1,
61
+ 2,
62
+ 1
63
+ ],
64
+ "parent": "root"
65
+ },
66
+ {
67
+ "value": "Expand and hide",
68
+ "href": "#expand-and-hide",
69
+ "depth": 3,
70
+ "numbering": [
71
+ 1,
72
+ 2,
73
+ 2
74
+ ],
75
+ "parent": "root"
76
+ },
77
+ {
78
+ "value": "Localized field combinations",
79
+ "href": "#localized-field-combinations",
80
+ "depth": 3,
81
+ "numbering": [
82
+ 1,
83
+ 2,
84
+ 3
85
+ ],
86
+ "parent": "root"
87
+ }
88
+ ],
89
+ "layout": "app-frame",
90
+ "tabs": [
91
+ {
92
+ "key": "overview",
93
+ "title": "Overview",
94
+ "order": 0
95
+ },
96
+ {
97
+ "key": "guidelines",
98
+ "title": "Guidelines",
99
+ "order": 2
100
+ },
101
+ {
102
+ "key": "dev",
103
+ "title": "Implementation",
104
+ "order": 3
105
+ },
106
+ {
107
+ "key": "a11y",
108
+ "title": "Accessibility",
109
+ "order": 4
110
+ }
111
+ ]
112
+ },
113
+ "mdx": "\n## Overview\n\nThe localized field component serves as a container that displays and manages\ncontent across various defined locales. It minimizes clutter by allowing users\nto toggle between language versions using a control while ensuring that the data\nfor each specified locale is correctly captured, validated, and stored in the\napplication.\n\n### Resources\n\nDeep dive into implementation details and access the Nimbus design library.\n\n[Figma library](https://www.figma.com/design/AvtPX6g7OGGCRvNlatGOIY/NIMBUS-design-system)\n[Storybook](https://nimbus-storybook.vercel.app/?path=/docs/components-localizedfield--docs)\n\n## Variables\n\nGet familiar with the features.\n\n### Size\n\nThere are two supported sizes for localized fields, the default (md) and a\nsmaller version for more compact needs (sm).\n\n```jsx live\nconst App = () => {\n const [smValues, setSmValues] = useState({ en: 'Hello world', de: 'Hallo Welt' });\n const [mdValues, setMdValues] = useState({ en: 'Hello world', de: 'Hallo Welt' });\n\n return (\n <Box>\n <LocalizedField\n size=\"md\"\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={mdValues}\n onChange={(e) => {\n setMdValues({\n ...mdValues,\n [e.target.locale]: e.target.value\n });\n }}\n />\n <LocalizedField\n size=\"sm\"\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={smValues}\n onChange={(e) => {\n setSmValues({\n ...smValues,\n [e.target.locale]: e.target.value\n });\n }}\n />\n </Box>\n );\n};\n```\n\n### Expand and hide\n\nAllow users to be able to expand and minimize localized fields to simplify a\npage, or expand to see everything when needed.\n\n```jsx live\nconst App = () => {\n const [values, setValues] = useState({ en: 'Hello world', de: 'Hallo Welt', es: 'Hola Mundo', nl: 'Hallo Wereld' });\n\n return (\n <LocalizedField\n size=\"md\"\n defaultLocaleOrCurrency=\"en\"\n defaultExpanded\n valuesByLocaleOrCurrency={values}\n onChange={(e) => {\n setValues({\n ...values,\n [e.target.locale]: e.target.value\n });\n }}\n />\n );\n};\n```\n\n### Localized field combinations\n\nCombine with rich text, text, multiline text, richttext, and moneyinput to give\nusers more availability for localized input details.\n\n```jsx live\nconst App = () => {\n const [enValues, setEnValues] = useState({\n en: 'hello',\n });\n\n const [deValues, setDeValues] = useState({\n de: 'hallo',\n });\n\n return (\n <Box>\n <LocalizedField\n type=\"richText\"\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={enValues}\n onChange={(e) => {\n setEnValues({\n ...enValues,\n [e.target.locale]: e.target.value\n });\n }}\n />\n <LocalizedField\n type=\"richText\"\n defaultLocaleOrCurrency=\"de\"\n valuesByLocaleOrCurrency={deValues}\n onChange={(e) => {\n setDeValues({\n ...enValues,\n [e.target.locale]: e.target.value\n });\n }}\n />\n </Box>\n );\n};\n```\n",
114
+ "views": {
115
+ "overview": {
116
+ "mdx": "\n## Overview\n\nThe localized field component serves as a container that displays and manages\ncontent across various defined locales. It minimizes clutter by allowing users\nto toggle between language versions using a control while ensuring that the data\nfor each specified locale is correctly captured, validated, and stored in the\napplication.\n\n### Resources\n\nDeep dive into implementation details and access the Nimbus design library.\n\n[Figma library](https://www.figma.com/design/AvtPX6g7OGGCRvNlatGOIY/NIMBUS-design-system)\n[Storybook](https://nimbus-storybook.vercel.app/?path=/docs/components-localizedfield--docs)\n\n## Variables\n\nGet familiar with the features.\n\n### Size\n\nThere are two supported sizes for localized fields, the default (md) and a\nsmaller version for more compact needs (sm).\n\n```jsx live\nconst App = () => {\n const [smValues, setSmValues] = useState({ en: 'Hello world', de: 'Hallo Welt' });\n const [mdValues, setMdValues] = useState({ en: 'Hello world', de: 'Hallo Welt' });\n\n return (\n <Box>\n <LocalizedField\n size=\"md\"\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={mdValues}\n onChange={(e) => {\n setMdValues({\n ...mdValues,\n [e.target.locale]: e.target.value\n });\n }}\n />\n <LocalizedField\n size=\"sm\"\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={smValues}\n onChange={(e) => {\n setSmValues({\n ...smValues,\n [e.target.locale]: e.target.value\n });\n }}\n />\n </Box>\n );\n};\n```\n\n### Expand and hide\n\nAllow users to be able to expand and minimize localized fields to simplify a\npage, or expand to see everything when needed.\n\n```jsx live\nconst App = () => {\n const [values, setValues] = useState({ en: 'Hello world', de: 'Hallo Welt', es: 'Hola Mundo', nl: 'Hallo Wereld' });\n\n return (\n <LocalizedField\n size=\"md\"\n defaultLocaleOrCurrency=\"en\"\n defaultExpanded\n valuesByLocaleOrCurrency={values}\n onChange={(e) => {\n setValues({\n ...values,\n [e.target.locale]: e.target.value\n });\n }}\n />\n );\n};\n```\n\n### Localized field combinations\n\nCombine with rich text, text, multiline text, richttext, and moneyinput to give\nusers more availability for localized input details.\n\n```jsx live\nconst App = () => {\n const [enValues, setEnValues] = useState({\n en: 'hello',\n });\n\n const [deValues, setDeValues] = useState({\n de: 'hallo',\n });\n\n return (\n <Box>\n <LocalizedField\n type=\"richText\"\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={enValues}\n onChange={(e) => {\n setEnValues({\n ...enValues,\n [e.target.locale]: e.target.value\n });\n }}\n />\n <LocalizedField\n type=\"richText\"\n defaultLocaleOrCurrency=\"de\"\n valuesByLocaleOrCurrency={deValues}\n onChange={(e) => {\n setDeValues({\n ...enValues,\n [e.target.locale]: e.target.value\n });\n }}\n />\n </Box>\n );\n};\n```\n",
117
+ "toc": [
118
+ {
119
+ "value": "Overview",
120
+ "href": "#overview",
121
+ "depth": 2,
122
+ "numbering": [
123
+ 1,
124
+ 1
125
+ ],
126
+ "parent": "root"
127
+ },
128
+ {
129
+ "value": "Resources",
130
+ "href": "#resources",
131
+ "depth": 3,
132
+ "numbering": [
133
+ 1,
134
+ 1,
135
+ 1
136
+ ],
137
+ "parent": "root"
138
+ },
139
+ {
140
+ "value": "Variables",
141
+ "href": "#variables",
142
+ "depth": 2,
143
+ "numbering": [
144
+ 1,
145
+ 2
146
+ ],
147
+ "parent": "root"
148
+ },
149
+ {
150
+ "value": "Size",
151
+ "href": "#size",
152
+ "depth": 3,
153
+ "numbering": [
154
+ 1,
155
+ 2,
156
+ 1
157
+ ],
158
+ "parent": "root"
159
+ },
160
+ {
161
+ "value": "Expand and hide",
162
+ "href": "#expand-and-hide",
163
+ "depth": 3,
164
+ "numbering": [
165
+ 1,
166
+ 2,
167
+ 2
168
+ ],
169
+ "parent": "root"
170
+ },
171
+ {
172
+ "value": "Localized field combinations",
173
+ "href": "#localized-field-combinations",
174
+ "depth": 3,
175
+ "numbering": [
176
+ 1,
177
+ 2,
178
+ 3
179
+ ],
180
+ "parent": "root"
181
+ }
182
+ ]
183
+ },
184
+ "a11y": {
185
+ "mdx": "\n## Accessibility\n\nAccessibility ensures that digital content and functionality are usable by\neveryone, including people with disabilities, by addressing visual, auditory,\ncognitive, and physical limitations.\n\n```jsx live\nconst App = () => {\n const [values, setValues] = useState({ en: 'Hello world', de: 'Hallo Welt' });\n\n return (\n\n <LocalizedField\n size=\"md\"\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={values}\n onChange={(e) => {\n setValues({\n ...values,\n [e.target.locale]: e.target.value\n });\n }}\n />\n\n );\n};\n```\n\n### Accessibility standards\n\n- **Focus management:** Ensure the Tab order moves logically between the active\n input field and the language switching controls. When the language is\n switched, focus should return to the newly visible input field.\n- **Keyboard operability:** The language switching controls (tabs, buttons) must\n be fully navigable and operable via the keyboard.\n- **ARIA roles:** Ensure the active input field correctly inherits all necessary\n ARIA attributes (e.g., aria-required, aria-invalid) from the FormField\n component.\n- **Screen reader communication:** Ensure screen readers announce the change of\n language context when the user activates a different locale input, often by\n announcing the new tab or language code.\n",
186
+ "toc": [
187
+ {
188
+ "value": "Accessibility",
189
+ "href": "#accessibility",
190
+ "depth": 2,
191
+ "numbering": [
192
+ 1,
193
+ 1
194
+ ],
195
+ "parent": "root"
196
+ },
197
+ {
198
+ "value": "Accessibility standards",
199
+ "href": "#accessibility-standards",
200
+ "depth": 3,
201
+ "numbering": [
202
+ 1,
203
+ 1,
204
+ 1
205
+ ],
206
+ "parent": "root"
207
+ }
208
+ ]
209
+ },
210
+ "dev": {
211
+ "mdx": "\n## Getting started\n\n### Import\n\n```tsx\nimport { LocalizedField, type LocalizedFieldProps, type LocalizedString, type LocalizedCurrency } from '@commercetools/nimbus';\n```\n\n### Basic usage\n\nThe LocalizedField component manages multiple locale-specific or currency-specific input fields with expand/collapse functionality. It requires controlled mode with an `onChange` handler:\n\n```jsx live-dev\nconst App = () => {\n const [values, setValues] = React.useState({\n en: 'Hello',\n de: 'Hallo',\n es: 'Hola'\n });\n\n const handleChange = (e) => {\n setValues(prev => ({\n ...prev,\n [e.target.locale]: e.target.value\n }));\n };\n\n return (\n <LocalizedField\n type=\"text\"\n label=\"Product Name\"\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={values}\n onChange={handleChange}\n />\n );\n};\n```\n\n## Working with localized values\n\nThe LocalizedField component uses specialized types for managing multi-locale and multi-currency data.\n\n### LocalizedString type\n\nFor `text`, `multiLine`, and `richText` input types, use the `LocalizedString` type:\n\n```tsx\nimport { type LocalizedString } from '@commercetools/nimbus';\n\n// LocalizedString maps locale codes to string values\nconst productName: LocalizedString = {\n 'en': 'Product',\n 'de': 'Produkt',\n 'es': 'Producto',\n 'fr-FR': 'Produit'\n};\n```\n\n### LocalizedCurrency type\n\nFor `money` input type, use the `LocalizedCurrency` type:\n\n```tsx\nimport { type LocalizedCurrency, type MoneyInputValue } from '@commercetools/nimbus';\n\n// LocalizedCurrency maps currency codes to MoneyInputValue objects\nconst prices: LocalizedCurrency = {\n 'USD': {\n amount: '99.99',\n currencyCode: 'USD'\n },\n 'EUR': {\n amount: '89.99',\n currencyCode: 'EUR'\n },\n 'GBP': {\n amount: '79.99',\n currencyCode: 'GBP'\n }\n};\n```\n\n### LocalizedFieldChangeEvent\n\nThe component uses a custom change event for consistency across browsers and input types:\n\n```tsx\nimport { type LocalizedFieldChangeEvent } from '@commercetools/nimbus';\n\nconst handleChange = (e: LocalizedFieldChangeEvent) => {\n console.log('Locale:', e.target.locale); // e.g., \"en\", \"de\"\n console.log('Currency:', e.target.currency); // e.g., \"USD\" (for money type)\n console.log('Value:', e.target.value); // string or MoneyInputValue\n console.log('Field ID:', e.target.id); // e.g., \"product-name.en\"\n console.log('Field name:', e.target.name); // e.g., \"productName.en\"\n};\n```\n\n## Usage examples\n\n### Size options\n\nLocalizedField supports two size variants:\n\n```jsx live-dev\nconst App = () => {\n const [smallValues, setSmallValues] = React.useState({\n en: 'Small',\n de: 'Klein'\n });\n\n const [mediumValues, setMediumValues] = React.useState({\n en: 'Medium',\n de: 'Mittel'\n });\n\n return (\n <Stack direction=\"column\" gap=\"600\">\n <LocalizedField\n size=\"sm\"\n type=\"text\"\n label=\"Small Size\"\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={smallValues}\n onChange={(e) => setSmallValues(prev => ({ ...prev, [e.target.locale]: e.target.value }))}\n />\n\n <LocalizedField\n size=\"md\"\n type=\"text\"\n label=\"Medium Size (default)\"\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={mediumValues}\n onChange={(e) => setMediumValues(prev => ({ ...prev, [e.target.locale]: e.target.value }))}\n />\n </Stack>\n );\n};\n```\n\n### Input types\n\nLocalizedField supports four input types: `text`, `multiLine`, `richText`, and `money`.\n\n#### Text input type\n\nSingle-line text input for short content:\n\n```jsx live-dev\nconst App = () => {\n const [values, setValues] = React.useState({\n en: 'Product Name',\n de: 'Produktname',\n es: 'Nombre del producto'\n });\n\n return (\n <LocalizedField\n type=\"text\"\n label=\"Product Name\"\n description=\"Short product title\"\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={values}\n onChange={(e) => setValues(prev => ({ ...prev, [e.target.locale]: e.target.value }))}\n />\n );\n};\n```\n\n#### MultiLine input type\n\nTextarea for longer content:\n\n```jsx live-dev\nconst App = () => {\n const [values, setValues] = React.useState({\n en: 'This is a detailed product description.',\n de: 'Dies ist eine detaillierte Produktbeschreibung.',\n es: 'Esta es una descripción detallada del producto.'\n });\n\n return (\n <LocalizedField\n type=\"multiLine\"\n label=\"Product Description\"\n description=\"Detailed product information\"\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={values}\n onChange={(e) => setValues(prev => ({ ...prev, [e.target.locale]: e.target.value }))}\n />\n );\n};\n```\n\n#### RichText input type\n\nRich text editor for formatted content:\n\n```jsx live-dev\nconst App = () => {\n const [values, setValues] = React.useState({\n en: '<p><strong>Bold</strong> and <em>italic</em> text</p>',\n de: '<p><strong>Fett</strong> und <em>kursiv</em> Text</p>'\n });\n\n return (\n <LocalizedField\n type=\"richText\"\n label=\"Marketing Content\"\n description=\"Rich formatted content with styling\"\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={values}\n onChange={(e) => setValues(prev => ({ ...prev, [e.target.locale]: e.target.value }))}\n />\n );\n};\n```\n\n#### Money input type\n\nCurrency-specific price inputs:\n\n```jsx live-dev\nconst App = () => {\n const [prices, setPrices] = React.useState({\n USD: { amount: '99.99', currencyCode: 'USD' },\n EUR: { amount: '89.99', currencyCode: 'EUR' },\n GBP: { amount: '79.99', currencyCode: 'GBP' }\n });\n\n const handlePriceChange = (e) => {\n setPrices(prev => ({\n ...prev,\n [e.target.currency]: {\n amount: e.target.value.amount,\n currencyCode: e.target.currency\n }\n }));\n };\n\n return (\n <LocalizedField\n type=\"money\"\n label=\"Product Price\"\n description=\"Price in different currencies\"\n defaultLocaleOrCurrency=\"USD\"\n valuesByLocaleOrCurrency={prices}\n onChange={handlePriceChange}\n />\n );\n};\n```\n\n### Expand/collapse behavior\n\nBy default, LocalizedField displays only the default locale and provides a toggle to expand:\n\n```jsx live-dev\nconst App = () => {\n const [values, setValues] = React.useState({\n en: 'English content',\n de: 'German content',\n es: 'Spanish content',\n 'fr-FR': 'French content'\n });\n\n return (\n <Stack direction=\"column\" gap=\"600\">\n <LocalizedField\n type=\"text\"\n label=\"Collapsed by default\"\n description=\"Click the language icon to expand and view all locales\"\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={values}\n onChange={(e) => setValues(prev => ({ ...prev, [e.target.locale]: e.target.value }))}\n />\n\n <LocalizedField\n type=\"text\"\n label=\"Expanded by default\"\n description=\"Opens with all locales visible\"\n defaultLocaleOrCurrency=\"en\"\n defaultExpanded={true}\n valuesByLocaleOrCurrency={values}\n onChange={(e) => setValues(prev => ({ ...prev, [e.target.locale]: e.target.value }))}\n />\n\n <LocalizedField\n type=\"text\"\n label=\"Always expanded\"\n description=\"Toggle button hidden, all locales always visible\"\n defaultLocaleOrCurrency=\"en\"\n displayAllLocalesOrCurrencies={true}\n valuesByLocaleOrCurrency={values}\n onChange={(e) => setValues(prev => ({ ...prev, [e.target.locale]: e.target.value }))}\n />\n </Stack>\n );\n};\n```\n\n### Placeholders and descriptions\n\nAdd placeholders and per-locale descriptions for better user guidance:\n\n```jsx live-dev\nconst App = () => {\n const [values, setValues] = React.useState({\n en: '',\n de: '',\n es: ''\n });\n\n const placeholders = {\n en: 'Enter English name...',\n de: 'Deutschen Namen eingeben...',\n es: 'Ingrese nombre en español...'\n };\n\n const descriptions = {\n en: 'English is the primary language',\n de: 'German translation',\n es: 'Spanish translation'\n };\n\n return (\n <LocalizedField\n type=\"text\"\n label=\"Product Name\"\n description=\"Localized product name\"\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={values}\n placeholdersByLocaleOrCurrency={placeholders}\n descriptionsByLocaleOrCurrency={descriptions}\n displayAllLocalesOrCurrencies={true}\n onChange={(e) => setValues(prev => ({ ...prev, [e.target.locale]: e.target.value }))}\n />\n );\n};\n```\n\n### Validation and error handling\n\nLocalizedField supports both group-level and per-locale validation:\n\n#### Group-level validation\n\nErrors that apply to the entire field group:\n\n```jsx live-dev\nconst App = () => {\n const [values, setValues] = React.useState({\n en: '',\n de: '',\n es: ''\n });\n const [touched, setTouched] = React.useState(false);\n\n const hasValues = Object.values(values).some(v => v !== '');\n const error = touched && !hasValues ? 'At least one translation is required' : undefined;\n\n return (\n <Stack direction=\"column\" gap=\"400\">\n <LocalizedField\n type=\"text\"\n label=\"Product Name\"\n description=\"Provide at least one translation\"\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={values}\n error={error}\n touched={touched}\n isRequired={true}\n onChange={(e) => setValues(prev => ({ ...prev, [e.target.locale]: e.target.value }))}\n onBlur={() => setTouched(true)}\n />\n\n <Text fontSize=\"300\" color=\"neutral.11\">\n Blur the field to trigger validation\n </Text>\n </Stack>\n );\n};\n```\n\n#### Per-locale validation\n\nDifferent errors for specific locales:\n\n```jsx live-dev\nconst App = () => {\n const [values, setValues] = React.useState({\n en: 'Valid name',\n de: 'ab',\n es: ''\n });\n const [touchedLocales, setTouchedLocales] = React.useState({});\n\n const validateLocale = (locale, value) => {\n if (!value) return 'This field is required';\n if (value.length < 3) return 'Must be at least 3 characters';\n return undefined;\n };\n\n const errors = Object.keys(values).reduce((acc, locale) => {\n const error = validateLocale(locale, values[locale]);\n if (error && touchedLocales[locale]) {\n acc[locale] = error;\n }\n return acc;\n }, {});\n\n return (\n <LocalizedField\n type=\"text\"\n label=\"Product Name\"\n description=\"Each locale must have at least 3 characters\"\n defaultLocaleOrCurrency=\"en\"\n displayAllLocalesOrCurrencies={true}\n valuesByLocaleOrCurrency={values}\n errorsByLocaleOrCurrency={errors}\n touched={true}\n onChange={(e) => setValues(prev => ({ ...prev, [e.target.locale]: e.target.value }))}\n onBlur={(_, locale) => setTouchedLocales(prev => ({ ...prev, [locale]: true }))}\n />\n );\n};\n```\n\n### Required and disabled states\n\nShow required indicator and disable user interaction:\n\n```jsx live-dev\nconst App = () => {\n const [requiredValues, setRequiredValues] = React.useState({\n en: '',\n de: ''\n });\n\n const [disabledValues] = React.useState({\n en: 'This field is disabled',\n de: 'Dieses Feld ist deaktiviert'\n });\n\n return (\n <Stack direction=\"column\" gap=\"600\">\n <LocalizedField\n type=\"text\"\n label=\"Required Field\"\n description=\"This field must be filled out\"\n isRequired={true}\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={requiredValues}\n onChange={(e) => setRequiredValues(prev => ({ ...prev, [e.target.locale]: e.target.value }))}\n />\n\n <LocalizedField\n type=\"text\"\n label=\"Disabled Field\"\n description=\"This field cannot be edited\"\n isDisabled={true}\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={disabledValues}\n onChange={() => {}}\n />\n </Stack>\n );\n};\n```\n\n### Read-only state\n\nDisplay values without allowing edits:\n\n```jsx live-dev\nconst App = () => {\n const [values] = React.useState({\n en: 'Read-only English value',\n de: 'Schreibgeschützter deutscher Wert',\n es: 'Valor español de solo lectura'\n });\n\n return (\n <LocalizedField\n type=\"text\"\n label=\"System Generated Name\"\n description=\"This value is automatically generated and cannot be edited\"\n isReadOnly={true}\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={values}\n onChange={() => {}}\n />\n );\n};\n```\n\n## Utility methods\n\nLocalizedField provides static utility methods for common operations:\n\n### Field attribute helpers\n\nGenerate consistent field IDs and names with locale suffixes:\n\n```tsx\n// LocalizedField.getId(base, locale) - Formats: \"base.locale\"\nLocalizedField.getId('productName', 'en'); // \"productName.en\"\nLocalizedField.getId('productName', 'de'); // \"productName.de\"\n\n// LocalizedField.getName(base, locale) - Same formatting\nLocalizedField.getName('productName', 'en'); // \"productName.en\"\n```\n\n### Value checking utilities\n\nCheck if fields have been touched or are empty:\n\n```tsx\nimport { LocalizedField } from '@commercetools/nimbus';\n\nconst values = { en: 'Hello', de: '', es: '' };\nconst touched = { en: true, de: false, es: false };\n\n// Check if any locale has been touched\nLocalizedField.isTouched(touched); // true\n\n// Check if all locales are empty\nLocalizedField.isEmpty(values); // false (en has a value)\n```\n\n### LocalizedString helpers\n\nCreate and manipulate LocalizedString objects:\n\n```tsx\n// Create empty LocalizedString with specific locales\nconst emptyValues = LocalizedField.createLocalizedString(['en', 'de', 'es'], {});\n// Result: { en: '', de: '', es: '' }\n\n// Merge with existing values\nconst existingValues = { en: 'Hello' };\nconst merged = LocalizedField.createLocalizedString(['en', 'de', 'es'], existingValues);\n// Result: { en: 'Hello', de: '', es: '' }\n\n// Remove empty translations\nconst values = { en: 'Hello', de: '', es: 'Hola' };\nconst cleaned = LocalizedField.omitEmptyTranslations(values);\n// Result: { en: 'Hello', es: 'Hola' }\n```\n\n### Money value utilities\n\nWork with LocalizedCurrency values:\n\n```tsx\n// Convert money values to different format\nconst prices = {\n USD: { amount: '99.99', currencyCode: 'USD' },\n EUR: { amount: '89.99', currencyCode: 'EUR' }\n};\n\n// Parse money values for processing\nconst parsed = LocalizedField.parseMoneyValues(prices);\n\n// Get currencies with high precision amounts\nconst highPrecision = LocalizedField.getHighPrecisionCurrencies(prices);\n\n// Get empty currency entries\nconst empty = LocalizedField.getEmptyCurrencies(prices);\n```\n\n### Error handling utilities\n\nConvert error objects for compatibility:\n\n```tsx\n// Standard error message component\nconst ErrorMessage = LocalizedField.RequiredValueErrorMessage;\n\n// Convert errors to field error format\nconst errors = { missing: true, invalid: false };\nconst fieldErrors = LocalizedField.toFieldErrors(errors);\n```\n\n## Component requirements\n\n## Accessibility\n\nLocalizedField implements comprehensive accessibility features to ensure WCAG 2.1 AA compliance.\n\n#### Role\n\n- `role=\"group\"` - The fieldset groups related locale/currency fields\n- Each locale field has appropriate input roles (`textbox`, `spinbutton` for money)\n\n#### Labeling\n\n- Group label via `<legend>` element (or `aria-label` if no visible label)\n- Each locale field labeled with its language/currency code\n- Required fields indicated with `aria-required=\"true\"`\n- Invalid fields indicated with `aria-invalid=\"true\"`\n- Error messages linked via `aria-describedby`\n\n#### Keyboard navigation\n\n| Key | Action |\n|-----|--------|\n| `Tab` | Move focus between locale fields and controls |\n| `Shift + Tab` | Move focus backwards |\n| `Enter` / `Space` | Toggle expand/collapse when focused on language icon button |\n| `Escape` | Close info dialog (if open) |\n\nFor individual input types, standard keyboard behavior applies:\n- Text/multiLine: Standard text input navigation\n- RichText: Rich text editor keyboard shortcuts\n- Money: Number input behavior with arrow keys for increment/decrement\n\n#### Persistent ID\n\nIf your use case requires tracking and analytics for this component, it is good practice to add a **persistent**, **unique** `id` to the component:\n\n```tsx\n<LocalizedField\n id=\"product-name-localized\"\n name=\"productName\"\n // ... other props\n/>\n```\n\nThe component will automatically append locale/currency codes to create unique IDs for each field (e.g., `product-name-localized.en`, `product-name-localized.de`).\n\n## API reference\n\n<PropsTable id=\"LocalizedField\" />\n\n## Common patterns\n\n### Multi-currency pricing\n\nManage prices across multiple currencies:\n\n```jsx live-dev\nconst App = () => {\n const [prices, setPrices] = React.useState({\n USD: { amount: '99.99', currencyCode: 'USD' },\n EUR: { amount: '89.99', currencyCode: 'EUR' },\n GBP: { amount: '79.99', currencyCode: 'GBP' },\n JPY: { amount: '12500', currencyCode: 'JPY' }\n });\n\n const handlePriceChange = (e) => {\n setPrices(prev => ({\n ...prev,\n [e.target.currency]: {\n amount: e.target.value.amount,\n currencyCode: e.target.currency\n }\n }));\n };\n\n const validatePrices = () => {\n const empty = LocalizedField.getEmptyCurrencies(prices);\n if (empty.length > 0) {\n console.warn('Empty prices for:', empty);\n }\n };\n\n return (\n <LocalizedField\n type=\"money\"\n label=\"Product Price\"\n description=\"Set prices for all supported currencies\"\n defaultLocaleOrCurrency=\"USD\"\n valuesByLocaleOrCurrency={prices}\n onChange={handlePriceChange}\n onBlur={validatePrices}\n isRequired={true}\n />\n );\n};\n```\n\n### Conditional locale validation\n\nApply different validation rules per locale:\n\n```jsx live-dev\nconst App = () => {\n const [values, setValues] = React.useState({\n en: '',\n de: '',\n es: '',\n 'fr-FR': ''\n });\n\n const [touchedLocales, setTouchedLocales] = React.useState({});\n\n // Different validation rules per locale\n const validateLocale = (locale, value) => {\n // English is required\n if (locale === 'en') {\n if (!value) return 'English name is required';\n if (value.length < 3) return 'Must be at least 3 characters';\n }\n\n // Other locales are optional but must meet length requirement if provided\n if (value && value.length < 3) {\n return 'Must be at least 3 characters';\n }\n\n return undefined;\n };\n\n const errors = Object.keys(values).reduce((acc, locale) => {\n const error = validateLocale(locale, values[locale] || '');\n if (error && touchedLocales[locale]) {\n acc[locale] = error;\n }\n return acc;\n }, {});\n\n return (\n <LocalizedField\n type=\"text\"\n label=\"Product Name\"\n description=\"English name is required, other languages optional\"\n defaultLocaleOrCurrency=\"en\"\n displayAllLocalesOrCurrencies={true}\n valuesByLocaleOrCurrency={values}\n errorsByLocaleOrCurrency={errors}\n touched={true}\n isRequired={true}\n onChange={(e) => {\n setValues(prev => ({\n ...prev,\n [e.target.locale]: e.target.value\n }));\n }}\n onBlur={(_, locale) => {\n setTouchedLocales(prev => ({ ...prev, [locale]: true }));\n }}\n />\n );\n};\n```\n\n## Testing your implementation\n\nThese examples demonstrate how to test your implementation when using LocalizedField within your application. As the component's internal functionality is already tested by Nimbus, these patterns help you verify your integration and application-specific logic.\n\n### Basic Rendering Tests\n\nVerify the LocalizedField renders with expected structure and locale fields\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\nimport {\n LocalizedField,\n NimbusProvider,\n type LocalizedString,\n type LocalizedCurrency,\n} from \"@commercetools/nimbus\";\n\ndescribe(\"LocalizedField - Basic rendering\", () => {\n it(\"renders with default locale visible\", () => {\n const values: LocalizedString = {\n en: \"Hello\",\n de: \"Hallo\",\n es: \"Hola\",\n };\n\n render(\n <NimbusProvider>\n <LocalizedField\n type=\"text\"\n label=\"Product Name\"\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={values}\n onChange={vi.fn()}\n />\n </NimbusProvider>\n );\n\n // Verify group label\n expect(screen.getByText(\"Product Name\")).toBeInTheDocument();\n\n // Verify default locale input is visible\n expect(screen.getByDisplayValue(\"Hello\")).toBeInTheDocument();\n\n // Verify expand button exists\n expect(\n screen.getByRole(\"button\", { name: /language/i })\n ).toBeInTheDocument();\n });\n\n it(\"renders all locales when displayAllLocalesOrCurrencies is true\", () => {\n const values: LocalizedString = {\n en: \"Hello\",\n de: \"Hallo\",\n es: \"Hola\",\n };\n\n render(\n <NimbusProvider>\n <LocalizedField\n type=\"text\"\n label=\"Product Name\"\n defaultLocaleOrCurrency=\"en\"\n displayAllLocalesOrCurrencies={true}\n valuesByLocaleOrCurrency={values}\n onChange={vi.fn()}\n />\n </NimbusProvider>\n );\n\n // All locale values should be visible\n expect(screen.getByDisplayValue(\"Hello\")).toBeInTheDocument();\n expect(screen.getByDisplayValue(\"Hallo\")).toBeInTheDocument();\n expect(screen.getByDisplayValue(\"Hola\")).toBeInTheDocument();\n });\n\n it(\"renders money type with currency inputs\", () => {\n const prices: LocalizedCurrency = {\n USD: { amount: \"99.99\", currencyCode: \"USD\" },\n EUR: { amount: \"89.99\", currencyCode: \"EUR\" },\n };\n\n render(\n <NimbusProvider>\n <LocalizedField\n type=\"money\"\n label=\"Product Price\"\n defaultLocaleOrCurrency=\"USD\"\n displayAllLocalesOrCurrencies={true}\n valuesByLocaleOrCurrency={prices}\n onChange={vi.fn()}\n />\n </NimbusProvider>\n );\n\n // Verify currency labels (there will be multiple matches due to MoneyInput internal structure)\n expect(screen.getAllByText(\"USD\").length).toBeGreaterThan(0);\n expect(screen.getAllByText(\"EUR\").length).toBeGreaterThan(0);\n });\n});\n```\n\n### Expand/Collapse Interactions\n\nTest the expand/collapse functionality for viewing all locale fields\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\nimport {\n LocalizedField,\n NimbusProvider,\n type LocalizedString,\n type LocalizedCurrency,\n} from \"@commercetools/nimbus\";\n\ndescribe(\"LocalizedField - Expand/collapse\", () => {\n it(\"expands to show all locales when toggle button is clicked\", async () => {\n const user = userEvent.setup();\n const values: LocalizedString = {\n en: \"Hello\",\n de: \"Hallo\",\n es: \"Hola\",\n };\n\n render(\n <NimbusProvider>\n <LocalizedField\n type=\"text\"\n label=\"Product Name\"\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={values}\n onChange={vi.fn()}\n />\n </NimbusProvider>\n );\n\n // Initially only default locale visible\n expect(screen.getByDisplayValue(\"Hello\")).toBeInTheDocument();\n expect(screen.queryByDisplayValue(\"Hallo\")).not.toBeInTheDocument();\n\n // Click expand button\n const expandButton = screen.getByRole(\"button\", { name: /language/i });\n await user.click(expandButton);\n\n // All locales should now be visible\n expect(screen.getByDisplayValue(\"Hello\")).toBeInTheDocument();\n expect(screen.getByDisplayValue(\"Hallo\")).toBeInTheDocument();\n expect(screen.getByDisplayValue(\"Hola\")).toBeInTheDocument();\n });\n\n it(\"starts expanded when defaultExpanded is true\", () => {\n const values: LocalizedString = {\n en: \"Hello\",\n de: \"Hallo\",\n };\n\n render(\n <NimbusProvider>\n <LocalizedField\n type=\"text\"\n label=\"Product Name\"\n defaultLocaleOrCurrency=\"en\"\n defaultExpanded={true}\n valuesByLocaleOrCurrency={values}\n onChange={vi.fn()}\n />\n </NimbusProvider>\n );\n\n // All locales visible on mount\n expect(screen.getByDisplayValue(\"Hello\")).toBeInTheDocument();\n expect(screen.getByDisplayValue(\"Hallo\")).toBeInTheDocument();\n });\n});\n```\n\n### Value Updates\n\nTest onChange handler with LocalizedFieldChangeEvent\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\nimport {\n LocalizedField,\n NimbusProvider,\n type LocalizedString,\n type LocalizedCurrency,\n} from \"@commercetools/nimbus\";\n\ndescribe(\"LocalizedField - Value updates\", () => {\n it(\"calls onChange with locale and value when text input changes\", async () => {\n const user = userEvent.setup();\n const onChange = vi.fn();\n const values: LocalizedString = {\n en: \"Hello\",\n de: \"\",\n };\n\n render(\n <NimbusProvider>\n <LocalizedField\n type=\"text\"\n label=\"Product Name\"\n defaultLocaleOrCurrency=\"en\"\n displayAllLocalesOrCurrencies={true}\n valuesByLocaleOrCurrency={values}\n onChange={onChange}\n />\n </NimbusProvider>\n );\n\n const germanInput = screen.getByLabelText(/de/i);\n await user.type(germanInput, \"Hallo\");\n\n // Verify onChange called with correct event structure\n expect(onChange).toHaveBeenCalled();\n const lastCall = onChange.mock.calls[onChange.mock.calls.length - 1][0];\n expect(lastCall.target.locale).toBe(\"de\");\n expect(lastCall.target.value).toContain(\"o\"); // Last character typed\n });\n\n it(\"renders money input type with currency values\", () => {\n const prices: LocalizedCurrency = {\n USD: { amount: \"99.99\", currencyCode: \"USD\" },\n EUR: { amount: \"89.99\", currencyCode: \"EUR\" },\n };\n\n render(\n <NimbusProvider>\n <LocalizedField\n type=\"money\"\n label=\"Product Price\"\n defaultLocaleOrCurrency=\"USD\"\n displayAllLocalesOrCurrencies={true}\n valuesByLocaleOrCurrency={prices}\n onChange={vi.fn()}\n />\n </NimbusProvider>\n );\n\n // Verify money inputs are present\n const inputs = screen.getAllByRole(\"textbox\");\n expect(inputs.length).toBeGreaterThan(0);\n\n // Verify currency values are displayed\n expect(screen.getByDisplayValue(\"99.99\")).toBeInTheDocument();\n expect(screen.getByDisplayValue(\"89.99\")).toBeInTheDocument();\n });\n});\n```\n\n### Validation and Errors\n\nTest error display at both group and per-locale levels\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\nimport {\n LocalizedField,\n NimbusProvider,\n type LocalizedString,\n type LocalizedCurrency,\n} from \"@commercetools/nimbus\";\n\ndescribe(\"LocalizedField - Validation\", () => {\n it(\"displays group-level error message\", () => {\n const values: LocalizedString = {\n en: \"\",\n de: \"\",\n };\n\n render(\n <NimbusProvider>\n <LocalizedField\n type=\"text\"\n label=\"Product Name\"\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={values}\n error=\"At least one translation is required\"\n touched={true}\n onChange={vi.fn()}\n />\n </NimbusProvider>\n );\n\n expect(\n screen.getByText(\"At least one translation is required\")\n ).toBeInTheDocument();\n });\n\n it(\"displays per-locale error messages\", () => {\n const values: LocalizedString = {\n en: \"ab\",\n de: \"\",\n };\n\n const errors = {\n en: \"Must be at least 3 characters\",\n de: \"This field is required\",\n };\n\n render(\n <NimbusProvider>\n <LocalizedField\n type=\"text\"\n label=\"Product Name\"\n defaultLocaleOrCurrency=\"en\"\n displayAllLocalesOrCurrencies={true}\n valuesByLocaleOrCurrency={values}\n errorsByLocaleOrCurrency={errors}\n touched={true}\n onChange={vi.fn()}\n />\n </NimbusProvider>\n );\n\n expect(\n screen.getByText(\"Must be at least 3 characters\")\n ).toBeInTheDocument();\n expect(screen.getByText(\"This field is required\")).toBeInTheDocument();\n });\n\n it(\"marks field as invalid with aria-invalid\", () => {\n const values: LocalizedString = {\n en: \"\",\n };\n\n render(\n <NimbusProvider>\n <LocalizedField\n type=\"text\"\n label=\"Product Name\"\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={values}\n error=\"Required\"\n touched={true}\n onChange={vi.fn()}\n />\n </NimbusProvider>\n );\n\n const input = screen.getByRole(\"textbox\");\n expect(input).toHaveAttribute(\"aria-invalid\", \"true\");\n });\n});\n```\n\n### Component States\n\nTest required, disabled, and read-only states\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\nimport {\n LocalizedField,\n NimbusProvider,\n type LocalizedString,\n type LocalizedCurrency,\n} from \"@commercetools/nimbus\";\n\ndescribe(\"LocalizedField - States\", () => {\n it(\"displays required indicator\", () => {\n const values: LocalizedString = {\n en: \"\",\n };\n\n render(\n <NimbusProvider>\n <LocalizedField\n type=\"text\"\n label=\"Product Name\"\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={values}\n isRequired={true}\n onChange={vi.fn()}\n />\n </NimbusProvider>\n );\n\n const input = screen.getByRole(\"textbox\");\n expect(input).toHaveAttribute(\"aria-required\", \"true\");\n });\n\n it(\"disables all inputs when isDisabled is true\", () => {\n const values: LocalizedString = {\n en: \"Hello\",\n de: \"Hallo\",\n };\n\n render(\n <NimbusProvider>\n <LocalizedField\n type=\"text\"\n label=\"Product Name\"\n defaultLocaleOrCurrency=\"en\"\n displayAllLocalesOrCurrencies={true}\n valuesByLocaleOrCurrency={values}\n isDisabled={true}\n onChange={vi.fn()}\n />\n </NimbusProvider>\n );\n\n const inputs = screen.getAllByRole(\"textbox\");\n inputs.forEach((input) => {\n expect(input).toBeDisabled();\n });\n });\n\n it(\"makes inputs read-only when isReadOnly is true\", () => {\n const values: LocalizedString = {\n en: \"Hello\",\n };\n\n render(\n <NimbusProvider>\n <LocalizedField\n type=\"text\"\n label=\"Product Name\"\n defaultLocaleOrCurrency=\"en\"\n valuesByLocaleOrCurrency={values}\n isReadOnly={true}\n onChange={vi.fn()}\n />\n </NimbusProvider>\n );\n\n const input = screen.getByRole(\"textbox\");\n expect(input).toHaveAttribute(\"readonly\");\n });\n});\n```\n\n### Utility Methods\n\nTest static utility methods for field management\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\nimport {\n LocalizedField,\n NimbusProvider,\n type LocalizedString,\n type LocalizedCurrency,\n} from \"@commercetools/nimbus\";\n\ndescribe(\"LocalizedField - Utility methods\", () => {\n it(\"getId and getName format field attributes correctly\", () => {\n expect(LocalizedField.getId(\"productName\", \"en\")).toBe(\"productName.en\");\n expect(LocalizedField.getName(\"productName\", \"de\")).toBe(\"productName.de\");\n });\n\n it(\"isTouched returns true when any locale is touched\", () => {\n const touched = { en: true, de: false, es: false };\n expect(LocalizedField.isTouched(touched)).toBe(true);\n\n const allUntouched = { en: false, de: false };\n expect(LocalizedField.isTouched(allUntouched)).toBe(false);\n });\n\n it(\"isEmpty returns true when all values are empty\", () => {\n const emptyValues = { en: \"\", de: \"\", es: \"\" };\n expect(LocalizedField.isEmpty(emptyValues)).toBe(true);\n\n const hasValue = { en: \"Hello\", de: \"\", es: \"\" };\n expect(LocalizedField.isEmpty(hasValue)).toBe(false);\n });\n\n it(\"createLocalizedString creates object with specified locales\", () => {\n const result = LocalizedField.createLocalizedString([\"en\", \"de\", \"es\"], {});\n expect(result).toEqual({ en: \"\", de: \"\", es: \"\" });\n\n // Merges with existing values\n const withExisting = LocalizedField.createLocalizedString([\"en\", \"de\"], {\n en: \"Hello\",\n });\n expect(withExisting).toEqual({ en: \"Hello\", de: \"\" });\n });\n\n it(\"omitEmptyTranslations removes empty values\", () => {\n const values = { en: \"Hello\", de: \"\", es: \"Hola\", fr: \"\" };\n const result = LocalizedField.omitEmptyTranslations(values);\n expect(result).toEqual({ en: \"Hello\", es: \"Hola\" });\n });\n});\n```\n\n### Placeholders and Descriptions\n\nTest per-locale placeholders and descriptions\n\n```tsx\nimport { describe, it, expect, vi } from \"vitest\";\nimport { render, screen } from \"@testing-library/react\";\nimport userEvent from \"@testing-library/user-event\";\nimport {\n LocalizedField,\n NimbusProvider,\n type LocalizedString,\n type LocalizedCurrency,\n} from \"@commercetools/nimbus\";\n\ndescribe(\"LocalizedField - Placeholders and descriptions\", () => {\n it(\"displays per-locale placeholders\", () => {\n const values: LocalizedString = {\n en: \"\",\n de: \"\",\n };\n\n const placeholders: LocalizedString = {\n en: \"Enter English name...\",\n de: \"Deutschen Namen eingeben...\",\n };\n\n render(\n <NimbusProvider>\n <LocalizedField\n type=\"text\"\n label=\"Product Name\"\n defaultLocaleOrCurrency=\"en\"\n displayAllLocalesOrCurrencies={true}\n valuesByLocaleOrCurrency={values}\n placeholdersByLocaleOrCurrency={placeholders}\n onChange={vi.fn()}\n />\n </NimbusProvider>\n );\n\n expect(\n screen.getByPlaceholderText(\"Enter English name...\")\n ).toBeInTheDocument();\n expect(\n screen.getByPlaceholderText(\"Deutschen Namen eingeben...\")\n ).toBeInTheDocument();\n });\n\n it(\"displays per-locale descriptions\", () => {\n const values: LocalizedString = {\n en: \"\",\n de: \"\",\n };\n\n const descriptions = {\n en: \"English is the primary language\",\n de: \"German translation\",\n };\n\n render(\n <NimbusProvider>\n <LocalizedField\n type=\"text\"\n label=\"Product Name\"\n defaultLocaleOrCurrency=\"en\"\n displayAllLocalesOrCurrencies={true}\n valuesByLocaleOrCurrency={values}\n descriptionsByLocaleOrCurrency={descriptions}\n onChange={vi.fn()}\n />\n </NimbusProvider>\n );\n\n expect(\n screen.getByText(\"English is the primary language\")\n ).toBeInTheDocument();\n expect(screen.getByText(\"German translation\")).toBeInTheDocument();\n });\n});\n```\n\n\n## Resources\n\n- [Storybook - LocalizedField](https://nimbus-storybook.vercel.app/?path=/docs/components-localizedfield--docs)\n- [FormField Component](/components/inputs/formfield)\n- [MoneyInput Component](/components/inputs/moneyinput)\n- [React Aria - useField](https://react-spectrum.adobe.com/react-aria/useField.html)\n",
212
+ "toc": [
213
+ {
214
+ "value": "Getting started",
215
+ "href": "#getting-started",
216
+ "depth": 2,
217
+ "numbering": [
218
+ 1,
219
+ 1
220
+ ],
221
+ "parent": "root"
222
+ },
223
+ {
224
+ "value": "Import",
225
+ "href": "#import",
226
+ "depth": 3,
227
+ "numbering": [
228
+ 1,
229
+ 1,
230
+ 1
231
+ ],
232
+ "parent": "root"
233
+ },
234
+ {
235
+ "value": "Basic usage",
236
+ "href": "#basic-usage",
237
+ "depth": 3,
238
+ "numbering": [
239
+ 1,
240
+ 1,
241
+ 2
242
+ ],
243
+ "parent": "root"
244
+ },
245
+ {
246
+ "value": "Working with localized values",
247
+ "href": "#working-with-localized-values",
248
+ "depth": 2,
249
+ "numbering": [
250
+ 1,
251
+ 2
252
+ ],
253
+ "parent": "root"
254
+ },
255
+ {
256
+ "value": "LocalizedString type",
257
+ "href": "#localizedstring-type",
258
+ "depth": 3,
259
+ "numbering": [
260
+ 1,
261
+ 2,
262
+ 1
263
+ ],
264
+ "parent": "root"
265
+ },
266
+ {
267
+ "value": "LocalizedCurrency type",
268
+ "href": "#localizedcurrency-type",
269
+ "depth": 3,
270
+ "numbering": [
271
+ 1,
272
+ 2,
273
+ 2
274
+ ],
275
+ "parent": "root"
276
+ },
277
+ {
278
+ "value": "LocalizedFieldChangeEvent",
279
+ "href": "#localizedfieldchangeevent",
280
+ "depth": 3,
281
+ "numbering": [
282
+ 1,
283
+ 2,
284
+ 3
285
+ ],
286
+ "parent": "root"
287
+ },
288
+ {
289
+ "value": "Usage examples",
290
+ "href": "#usage-examples",
291
+ "depth": 2,
292
+ "numbering": [
293
+ 1,
294
+ 3
295
+ ],
296
+ "parent": "root"
297
+ },
298
+ {
299
+ "value": "Size options",
300
+ "href": "#size-options",
301
+ "depth": 3,
302
+ "numbering": [
303
+ 1,
304
+ 3,
305
+ 1
306
+ ],
307
+ "parent": "root"
308
+ },
309
+ {
310
+ "value": "Input types",
311
+ "href": "#input-types",
312
+ "depth": 3,
313
+ "numbering": [
314
+ 1,
315
+ 3,
316
+ 2
317
+ ],
318
+ "parent": "root"
319
+ },
320
+ {
321
+ "value": "Text input type",
322
+ "href": "#text-input-type",
323
+ "depth": 4,
324
+ "numbering": [
325
+ 1,
326
+ 3,
327
+ 2,
328
+ 1
329
+ ],
330
+ "parent": "root"
331
+ },
332
+ {
333
+ "value": "MultiLine input type",
334
+ "href": "#multiline-input-type",
335
+ "depth": 4,
336
+ "numbering": [
337
+ 1,
338
+ 3,
339
+ 2,
340
+ 2
341
+ ],
342
+ "parent": "root"
343
+ },
344
+ {
345
+ "value": "RichText input type",
346
+ "href": "#richtext-input-type",
347
+ "depth": 4,
348
+ "numbering": [
349
+ 1,
350
+ 3,
351
+ 2,
352
+ 3
353
+ ],
354
+ "parent": "root"
355
+ },
356
+ {
357
+ "value": "Money input type",
358
+ "href": "#money-input-type",
359
+ "depth": 4,
360
+ "numbering": [
361
+ 1,
362
+ 3,
363
+ 2,
364
+ 4
365
+ ],
366
+ "parent": "root"
367
+ },
368
+ {
369
+ "value": "Expand/collapse behavior",
370
+ "href": "#expandcollapse-behavior",
371
+ "depth": 3,
372
+ "numbering": [
373
+ 1,
374
+ 3,
375
+ 3
376
+ ],
377
+ "parent": "root"
378
+ },
379
+ {
380
+ "value": "Placeholders and descriptions",
381
+ "href": "#placeholders-and-descriptions",
382
+ "depth": 3,
383
+ "numbering": [
384
+ 1,
385
+ 3,
386
+ 4
387
+ ],
388
+ "parent": "root"
389
+ },
390
+ {
391
+ "value": "Validation and error handling",
392
+ "href": "#validation-and-error-handling",
393
+ "depth": 3,
394
+ "numbering": [
395
+ 1,
396
+ 3,
397
+ 5
398
+ ],
399
+ "parent": "root"
400
+ },
401
+ {
402
+ "value": "Group-level validation",
403
+ "href": "#group-level-validation",
404
+ "depth": 4,
405
+ "numbering": [
406
+ 1,
407
+ 3,
408
+ 5,
409
+ 1
410
+ ],
411
+ "parent": "root"
412
+ },
413
+ {
414
+ "value": "Per-locale validation",
415
+ "href": "#per-locale-validation",
416
+ "depth": 4,
417
+ "numbering": [
418
+ 1,
419
+ 3,
420
+ 5,
421
+ 2
422
+ ],
423
+ "parent": "root"
424
+ },
425
+ {
426
+ "value": "Required and disabled states",
427
+ "href": "#required-and-disabled-states",
428
+ "depth": 3,
429
+ "numbering": [
430
+ 1,
431
+ 3,
432
+ 6
433
+ ],
434
+ "parent": "root"
435
+ },
436
+ {
437
+ "value": "Read-only state",
438
+ "href": "#read-only-state",
439
+ "depth": 3,
440
+ "numbering": [
441
+ 1,
442
+ 3,
443
+ 7
444
+ ],
445
+ "parent": "root"
446
+ },
447
+ {
448
+ "value": "Utility methods",
449
+ "href": "#utility-methods",
450
+ "depth": 2,
451
+ "numbering": [
452
+ 1,
453
+ 4
454
+ ],
455
+ "parent": "root"
456
+ },
457
+ {
458
+ "value": "Field attribute helpers",
459
+ "href": "#field-attribute-helpers",
460
+ "depth": 3,
461
+ "numbering": [
462
+ 1,
463
+ 4,
464
+ 1
465
+ ],
466
+ "parent": "root"
467
+ },
468
+ {
469
+ "value": "Value checking utilities",
470
+ "href": "#value-checking-utilities",
471
+ "depth": 3,
472
+ "numbering": [
473
+ 1,
474
+ 4,
475
+ 2
476
+ ],
477
+ "parent": "root"
478
+ },
479
+ {
480
+ "value": "LocalizedString helpers",
481
+ "href": "#localizedstring-helpers",
482
+ "depth": 3,
483
+ "numbering": [
484
+ 1,
485
+ 4,
486
+ 3
487
+ ],
488
+ "parent": "root"
489
+ },
490
+ {
491
+ "value": "Money value utilities",
492
+ "href": "#money-value-utilities",
493
+ "depth": 3,
494
+ "numbering": [
495
+ 1,
496
+ 4,
497
+ 4
498
+ ],
499
+ "parent": "root"
500
+ },
501
+ {
502
+ "value": "Error handling utilities",
503
+ "href": "#error-handling-utilities",
504
+ "depth": 3,
505
+ "numbering": [
506
+ 1,
507
+ 4,
508
+ 5
509
+ ],
510
+ "parent": "root"
511
+ },
512
+ {
513
+ "value": "Component requirements",
514
+ "href": "#component-requirements",
515
+ "depth": 2,
516
+ "numbering": [
517
+ 1,
518
+ 5
519
+ ],
520
+ "parent": "root"
521
+ },
522
+ {
523
+ "value": "Accessibility",
524
+ "href": "#accessibility",
525
+ "depth": 2,
526
+ "numbering": [
527
+ 1,
528
+ 6
529
+ ],
530
+ "parent": "root"
531
+ },
532
+ {
533
+ "value": "Role",
534
+ "href": "#role",
535
+ "depth": 4,
536
+ "numbering": [
537
+ 1,
538
+ 6,
539
+ 1,
540
+ 1
541
+ ],
542
+ "parent": "root"
543
+ },
544
+ {
545
+ "value": "Labeling",
546
+ "href": "#labeling",
547
+ "depth": 4,
548
+ "numbering": [
549
+ 1,
550
+ 6,
551
+ 1,
552
+ 2
553
+ ],
554
+ "parent": "root"
555
+ },
556
+ {
557
+ "value": "Keyboard navigation",
558
+ "href": "#keyboard-navigation",
559
+ "depth": 4,
560
+ "numbering": [
561
+ 1,
562
+ 6,
563
+ 1,
564
+ 3
565
+ ],
566
+ "parent": "root"
567
+ },
568
+ {
569
+ "value": "Persistent ID",
570
+ "href": "#persistent-id",
571
+ "depth": 4,
572
+ "numbering": [
573
+ 1,
574
+ 6,
575
+ 1,
576
+ 4
577
+ ],
578
+ "parent": "root"
579
+ },
580
+ {
581
+ "value": "API reference",
582
+ "href": "#api-reference",
583
+ "depth": 2,
584
+ "numbering": [
585
+ 1,
586
+ 7
587
+ ],
588
+ "parent": "root"
589
+ },
590
+ {
591
+ "value": "Common patterns",
592
+ "href": "#common-patterns",
593
+ "depth": 2,
594
+ "numbering": [
595
+ 1,
596
+ 8
597
+ ],
598
+ "parent": "root"
599
+ },
600
+ {
601
+ "value": "Multi-currency pricing",
602
+ "href": "#multi-currency-pricing",
603
+ "depth": 3,
604
+ "numbering": [
605
+ 1,
606
+ 8,
607
+ 1
608
+ ],
609
+ "parent": "root"
610
+ },
611
+ {
612
+ "value": "Conditional locale validation",
613
+ "href": "#conditional-locale-validation",
614
+ "depth": 3,
615
+ "numbering": [
616
+ 1,
617
+ 8,
618
+ 2
619
+ ],
620
+ "parent": "root"
621
+ },
622
+ {
623
+ "value": "Testing your implementation",
624
+ "href": "#testing-your-implementation",
625
+ "depth": 2,
626
+ "numbering": [
627
+ 1,
628
+ 9
629
+ ],
630
+ "parent": "root"
631
+ },
632
+ {
633
+ "value": "Basic Rendering Tests",
634
+ "href": "#basic-rendering-tests",
635
+ "depth": 3,
636
+ "numbering": [
637
+ 1,
638
+ 9,
639
+ 1
640
+ ],
641
+ "parent": "root"
642
+ },
643
+ {
644
+ "value": "Expand/Collapse Interactions",
645
+ "href": "#expandcollapse-interactions",
646
+ "depth": 3,
647
+ "numbering": [
648
+ 1,
649
+ 9,
650
+ 2
651
+ ],
652
+ "parent": "root"
653
+ },
654
+ {
655
+ "value": "Value Updates",
656
+ "href": "#value-updates",
657
+ "depth": 3,
658
+ "numbering": [
659
+ 1,
660
+ 9,
661
+ 3
662
+ ],
663
+ "parent": "root"
664
+ },
665
+ {
666
+ "value": "Validation and Errors",
667
+ "href": "#validation-and-errors",
668
+ "depth": 3,
669
+ "numbering": [
670
+ 1,
671
+ 9,
672
+ 4
673
+ ],
674
+ "parent": "root"
675
+ },
676
+ {
677
+ "value": "Component States",
678
+ "href": "#component-states",
679
+ "depth": 3,
680
+ "numbering": [
681
+ 1,
682
+ 9,
683
+ 5
684
+ ],
685
+ "parent": "root"
686
+ },
687
+ {
688
+ "value": "Utility Methods",
689
+ "href": "#utility-methods-1",
690
+ "depth": 3,
691
+ "numbering": [
692
+ 1,
693
+ 9,
694
+ 6
695
+ ],
696
+ "parent": "root"
697
+ },
698
+ {
699
+ "value": "Placeholders and Descriptions",
700
+ "href": "#placeholders-and-descriptions-1",
701
+ "depth": 3,
702
+ "numbering": [
703
+ 1,
704
+ 9,
705
+ 7
706
+ ],
707
+ "parent": "root"
708
+ },
709
+ {
710
+ "value": "Resources",
711
+ "href": "#resources",
712
+ "depth": 2,
713
+ "numbering": [
714
+ 1,
715
+ 10
716
+ ],
717
+ "parent": "root"
718
+ }
719
+ ]
720
+ },
721
+ "guidelines": {
722
+ "mdx": "\n## Guidelines\n\nLocalized field guidelines ensure the consistent design, accessibility, and\nefficient management of content that requires simultaneous input and storage\nacross multiple defined language versions.\n\n### Best practices\n\n- **Prioritize default locale:** Always ensure the primary or default locale is\n easily accessible and the first field a user sees.\n- **Use clear flags/labels:** The language switcher controls must clearly and\n concisely indicate the active locale to prevent accidental input into the\n wrong language version.\n- **Maintain content consistency:** The underlying input component chosen for\n renderItem must remain the same for every single locale instance to ensure\n data integrity and predictable behavior.\n- **Handle text expansion:** Design the surrounding layout and container with\n enough horizontal space to accommodate text expansion in wordier languages\n like German or French.\n- **Provide contextual tools:** If the underlying input is complex (like a rich\n text editor), ensure localization features (like spellcheck based on the\n active locale) are supported.\n\n### Usage\n\nA localized field's usage is to efficiently capture and manage content that must\nbe translated and stored for multiple language versions within a single form.\n\n> [!TIP]\\\n> When to use\n\n- **Product descriptions/titles:** For any field that must be translated for\n customer-facing display (e.g., product titles, category names, SEO keywords).\n- **Multiple language input:** When a user (typically a content manager or\n merchant) is responsible for entering content for all supported markets from\n one interface.\n- **Structured metadata:** For input fields that hold localized metadata (e.g.,\n unique localized pricing tiers, currency symbols, SEO, or tax explanations).\n\n> [!CAUTION]\\\n> When not to use\n\n- **Non-translatable data:** When capturing internal IDs, SKUs, inventory\n counts, or purely numerical data that does not change by language. Use a\n standard Text Input or Number Input instead.\n- **Single-language input:** If the application supports only one language, or\n if the user is only ever responsible for one market's content.\n- **Large, multi-page content:** For entire pages or long-form documentation\n that would require a complex translation workflow; use a dedicated content\n management system instead.\n\n### Do’s and don’ts for the localized field\n\n> [!TIP]\\\n> **Do**\n>\n> - Ensure switching languages preserves the content of the input field\n> currently being edited, allowing easy comparison.\n> - If needed, you can include a visual indicator with a country or language\n> code on the active input field for clarity.\n\n> [!CAUTION]\\\n> **Don't**\n>\n> - Don't hide the language switcher interface completely unless an external\n> system (like a global header) explicitly manages it.\n> - Don't allow the underlying input component to change across locales (e.g.,\n> using a text input for English and a text area for French).\n> - Don't allow users to input data into a locale that is not defined in the\n> component's locales variable.\n",
723
+ "toc": [
724
+ {
725
+ "value": "Guidelines",
726
+ "href": "#guidelines",
727
+ "depth": 2,
728
+ "numbering": [
729
+ 1,
730
+ 1
731
+ ],
732
+ "parent": "root"
733
+ },
734
+ {
735
+ "value": "Best practices",
736
+ "href": "#best-practices",
737
+ "depth": 3,
738
+ "numbering": [
739
+ 1,
740
+ 1,
741
+ 1
742
+ ],
743
+ "parent": "root"
744
+ },
745
+ {
746
+ "value": "Usage",
747
+ "href": "#usage",
748
+ "depth": 3,
749
+ "numbering": [
750
+ 1,
751
+ 1,
752
+ 2
753
+ ],
754
+ "parent": "root"
755
+ },
756
+ {
757
+ "value": "Do’s and don’ts for the localized field",
758
+ "href": "#dos-and-donts-for-the-localized-field",
759
+ "depth": 3,
760
+ "numbering": [
761
+ 1,
762
+ 1,
763
+ 3
764
+ ],
765
+ "parent": "root"
766
+ }
767
+ ]
768
+ }
769
+ }
770
+ }