@open-mercato/core 0.7.1-develop.7203.1.9396450b78 → 0.8.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 (416) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/build.mjs +11 -0
  3. package/dist/modules/catalog/backend/catalog/products/[id]/page.js +23 -0
  4. package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
  5. package/dist/modules/customers/backend/customers/companies/[id]/page.js +2 -1
  6. package/dist/modules/customers/backend/customers/companies/[id]/page.js.map +2 -2
  7. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +2 -1
  8. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  9. package/dist/modules/customers/backend/customers/people/[id]/page.js +2 -2
  10. package/dist/modules/customers/backend/customers/people/[id]/page.js.map +2 -2
  11. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +2 -1
  12. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  13. package/dist/modules/customers/lib/detailHelpers.js +4 -0
  14. package/dist/modules/customers/lib/detailHelpers.js.map +2 -2
  15. package/dist/modules/customers/lib/todoCompatibility.js +5 -0
  16. package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
  17. package/dist/modules/design_system/backend/design-system/page.meta.js +3 -2
  18. package/dist/modules/design_system/backend/design-system/page.meta.js.map +2 -2
  19. package/dist/modules/design_system/gallery/assets/ai-prompt-image.png +0 -0
  20. package/dist/modules/design_system/gallery/assets/avatar-illustration.png +0 -0
  21. package/dist/modules/design_system/gallery/assets/avatar-memoji.png +0 -0
  22. package/dist/modules/design_system/gallery/assets/avatar-photo.png +0 -0
  23. package/dist/modules/design_system/gallery/assets/blog-photo-0.png +0 -0
  24. package/dist/modules/design_system/gallery/assets/contact-support-portrait.png +0 -0
  25. package/dist/modules/design_system/gallery/assets/crypto-ada.png +0 -0
  26. package/dist/modules/design_system/gallery/assets/crypto-avax.png +0 -0
  27. package/dist/modules/design_system/gallery/assets/crypto-bnb.png +0 -0
  28. package/dist/modules/design_system/gallery/assets/crypto-brand.png +0 -0
  29. package/dist/modules/design_system/gallery/assets/crypto-btc.png +0 -0
  30. package/dist/modules/design_system/gallery/assets/crypto-clock.svg +3 -0
  31. package/dist/modules/design_system/gallery/assets/crypto-crown.svg +3 -0
  32. package/dist/modules/design_system/gallery/assets/crypto-dot.png +0 -0
  33. package/dist/modules/design_system/gallery/assets/crypto-eth.png +0 -0
  34. package/dist/modules/design_system/gallery/assets/crypto-hbar.png +0 -0
  35. package/dist/modules/design_system/gallery/assets/crypto-history.svg +3 -0
  36. package/dist/modules/design_system/gallery/assets/crypto-link.svg +3 -0
  37. package/dist/modules/design_system/gallery/assets/crypto-menu.svg +3 -0
  38. package/dist/modules/design_system/gallery/assets/crypto-metamask.png +0 -0
  39. package/dist/modules/design_system/gallery/assets/crypto-more.svg +3 -0
  40. package/dist/modules/design_system/gallery/assets/crypto-phantom.png +0 -0
  41. package/dist/modules/design_system/gallery/assets/crypto-rewards.svg +3 -0
  42. package/dist/modules/design_system/gallery/assets/crypto-sad-face.png +0 -0
  43. package/dist/modules/design_system/gallery/assets/crypto-sol.png +0 -0
  44. package/dist/modules/design_system/gallery/assets/crypto-star.svg +3 -0
  45. package/dist/modules/design_system/gallery/assets/crypto-status-cancelled.svg +3 -0
  46. package/dist/modules/design_system/gallery/assets/crypto-status-pending.svg +3 -0
  47. package/dist/modules/design_system/gallery/assets/crypto-status-success.svg +3 -0
  48. package/dist/modules/design_system/gallery/assets/crypto-status-warning.svg +3 -0
  49. package/dist/modules/design_system/gallery/assets/crypto-trx.png +0 -0
  50. package/dist/modules/design_system/gallery/assets/crypto-usdc.png +0 -0
  51. package/dist/modules/design_system/gallery/assets/crypto-usdt.png +0 -0
  52. package/dist/modules/design_system/gallery/assets/crypto-walletconnect.png +0 -0
  53. package/dist/modules/design_system/gallery/assets/crypto-wei.png +0 -0
  54. package/dist/modules/design_system/gallery/assets/crypto-xrp.png +0 -0
  55. package/dist/modules/design_system/gallery/assets/cryptocurrency-artwork.js +67 -0
  56. package/dist/modules/design_system/gallery/assets/cryptocurrency-artwork.js.map +7 -0
  57. package/dist/modules/design_system/gallery/assets/github-logo.png +0 -0
  58. package/dist/modules/design_system/gallery/assets/images.d.js +1 -0
  59. package/dist/modules/design_system/gallery/assets/images.d.js.map +7 -0
  60. package/dist/modules/design_system/gallery/assets/input-european-union.svg +18 -0
  61. package/dist/modules/design_system/gallery/assets/landing-teams-01.png +0 -0
  62. package/dist/modules/design_system/gallery/assets/marketing-artwork.js +83 -0
  63. package/dist/modules/design_system/gallery/assets/marketing-artwork.js.map +7 -0
  64. package/dist/modules/design_system/gallery/assets/menu-apex.svg +18 -0
  65. package/dist/modules/design_system/gallery/assets/menu-mastercard.svg +7 -0
  66. package/dist/modules/design_system/gallery/assets/menu-spotify.svg +4 -0
  67. package/dist/modules/design_system/gallery/assets/menu-united-states.svg +16 -0
  68. package/dist/modules/design_system/gallery/assets/select-google.png +0 -0
  69. package/dist/modules/design_system/gallery/assets/select-poland.png +0 -0
  70. package/dist/modules/design_system/gallery/assets/selection-artwork.js +5 -0
  71. package/dist/modules/design_system/gallery/assets/selection-artwork.js.map +7 -0
  72. package/dist/modules/design_system/gallery/assets/social-apple-filled.svg +4 -0
  73. package/dist/modules/design_system/gallery/assets/social-apple-stroke.svg +4 -0
  74. package/dist/modules/design_system/gallery/assets/social-dropbox-filled.svg +5 -0
  75. package/dist/modules/design_system/gallery/assets/social-dropbox-stroke.svg +5 -0
  76. package/dist/modules/design_system/gallery/assets/social-facebook-filled.svg +4 -0
  77. package/dist/modules/design_system/gallery/assets/social-facebook-stroke.svg +10 -0
  78. package/dist/modules/design_system/gallery/assets/social-github-filled.svg +4 -0
  79. package/dist/modules/design_system/gallery/assets/social-github-stroke.svg +4 -0
  80. package/dist/modules/design_system/gallery/assets/social-google-filled.svg +7 -0
  81. package/dist/modules/design_system/gallery/assets/social-google-stroke.svg +7 -0
  82. package/dist/modules/design_system/gallery/assets/social-linkedin-filled.svg +4 -0
  83. package/dist/modules/design_system/gallery/assets/social-linkedin-stroke.svg +4 -0
  84. package/dist/modules/design_system/gallery/assets/social-x-filled.svg +4 -0
  85. package/dist/modules/design_system/gallery/assets/social-x-stroke.svg +4 -0
  86. package/dist/modules/design_system/gallery/assets/style-studio-product.png +0 -0
  87. package/dist/modules/design_system/gallery/assets/upload-images.js +8 -0
  88. package/dist/modules/design_system/gallery/assets/upload-images.js.map +7 -0
  89. package/dist/modules/design_system/gallery/components/BrandStylePreview.js +74 -0
  90. package/dist/modules/design_system/gallery/components/BrandStylePreview.js.map +7 -0
  91. package/dist/modules/design_system/gallery/components/CodeSnippet.js +31 -31
  92. package/dist/modules/design_system/gallery/components/CodeSnippet.js.map +2 -2
  93. package/dist/modules/design_system/gallery/components/ColorPlayground.js +408 -0
  94. package/dist/modules/design_system/gallery/components/ColorPlayground.js.map +7 -0
  95. package/dist/modules/design_system/gallery/components/ColorStudioCompositions.js +166 -0
  96. package/dist/modules/design_system/gallery/components/ColorStudioCompositions.js.map +7 -0
  97. package/dist/modules/design_system/gallery/components/ColorStudioSpecimen.js +182 -0
  98. package/dist/modules/design_system/gallery/components/ColorStudioSpecimen.js.map +7 -0
  99. package/dist/modules/design_system/gallery/components/CompactEntrySpecimen.js +80 -0
  100. package/dist/modules/design_system/gallery/components/CompactEntrySpecimen.js.map +7 -0
  101. package/dist/modules/design_system/gallery/components/ComponentIndex.js +42 -0
  102. package/dist/modules/design_system/gallery/components/ComponentIndex.js.map +7 -0
  103. package/dist/modules/design_system/gallery/components/DesignSystemHome.js +69 -0
  104. package/dist/modules/design_system/gallery/components/DesignSystemHome.js.map +7 -0
  105. package/dist/modules/design_system/gallery/components/EntryCard.js +47 -41
  106. package/dist/modules/design_system/gallery/components/EntryCard.js.map +2 -2
  107. package/dist/modules/design_system/gallery/components/EntryHeader.js +68 -0
  108. package/dist/modules/design_system/gallery/components/EntryHeader.js.map +7 -0
  109. package/dist/modules/design_system/gallery/components/FamilyEntryPreview.js +19 -0
  110. package/dist/modules/design_system/gallery/components/FamilyEntryPreview.js.map +7 -0
  111. package/dist/modules/design_system/gallery/components/FoundationGuide.js +46 -0
  112. package/dist/modules/design_system/gallery/components/FoundationGuide.js.map +7 -0
  113. package/dist/modules/design_system/gallery/components/GalleryLink.js +21 -0
  114. package/dist/modules/design_system/gallery/components/GalleryLink.js.map +7 -0
  115. package/dist/modules/design_system/gallery/components/GalleryNavigation.js +82 -0
  116. package/dist/modules/design_system/gallery/components/GalleryNavigation.js.map +7 -0
  117. package/dist/modules/design_system/gallery/components/GalleryShell.js +147 -67
  118. package/dist/modules/design_system/gallery/components/GalleryShell.js.map +3 -3
  119. package/dist/modules/design_system/gallery/components/IconsBrowser.js +33 -0
  120. package/dist/modules/design_system/gallery/components/IconsBrowser.js.map +7 -0
  121. package/dist/modules/design_system/gallery/components/SourceLibrary.js +93 -0
  122. package/dist/modules/design_system/gallery/components/SourceLibrary.js.map +7 -0
  123. package/dist/modules/design_system/gallery/components/StyleAgents.js +139 -0
  124. package/dist/modules/design_system/gallery/components/StyleAgents.js.map +7 -0
  125. package/dist/modules/design_system/gallery/components/ThemeTokenReference.js +101 -0
  126. package/dist/modules/design_system/gallery/components/ThemeTokenReference.js.map +7 -0
  127. package/dist/modules/design_system/gallery/components/VariantPreview.js +2 -2
  128. package/dist/modules/design_system/gallery/components/VariantPreview.js.map +2 -2
  129. package/dist/modules/design_system/gallery/components/colorPreview.js +58 -0
  130. package/dist/modules/design_system/gallery/components/colorPreview.js.map +7 -0
  131. package/dist/modules/design_system/gallery/components/colorStudio.js +218 -0
  132. package/dist/modules/design_system/gallery/components/colorStudio.js.map +7 -0
  133. package/dist/modules/design_system/gallery/components/styleAgentBranding.js +46 -0
  134. package/dist/modules/design_system/gallery/components/styleAgentBranding.js.map +7 -0
  135. package/dist/modules/design_system/gallery/components/themeTokens.js +32 -0
  136. package/dist/modules/design_system/gallery/components/themeTokens.js.map +7 -0
  137. package/dist/modules/design_system/gallery/demos/ai-product-code.generated.js +194 -0
  138. package/dist/modules/design_system/gallery/demos/ai-product-code.generated.js.map +7 -0
  139. package/dist/modules/design_system/gallery/demos/ai-product.js +423 -0
  140. package/dist/modules/design_system/gallery/demos/ai-product.js.map +7 -0
  141. package/dist/modules/design_system/gallery/demos/buttons.js +289 -0
  142. package/dist/modules/design_system/gallery/demos/buttons.js.map +7 -0
  143. package/dist/modules/design_system/gallery/demos/cryptocurrency.js +1708 -0
  144. package/dist/modules/design_system/gallery/demos/cryptocurrency.js.map +7 -0
  145. package/dist/modules/design_system/gallery/demos/feeds-code.generated.js +92 -0
  146. package/dist/modules/design_system/gallery/demos/feeds-code.generated.js.map +7 -0
  147. package/dist/modules/design_system/gallery/demos/feeds.js +148 -0
  148. package/dist/modules/design_system/gallery/demos/feeds.js.map +7 -0
  149. package/dist/modules/design_system/gallery/demos/file-upload.js +72 -0
  150. package/dist/modules/design_system/gallery/demos/file-upload.js.map +7 -0
  151. package/dist/modules/design_system/gallery/demos/foundation-reference-data.js +4875 -0
  152. package/dist/modules/design_system/gallery/demos/foundation-reference-data.js.map +7 -0
  153. package/dist/modules/design_system/gallery/demos/foundation-references.js +188 -0
  154. package/dist/modules/design_system/gallery/demos/foundation-references.js.map +7 -0
  155. package/dist/modules/design_system/gallery/demos/key-components-code.generated.js +6 -0
  156. package/dist/modules/design_system/gallery/demos/key-components-code.generated.js.map +7 -0
  157. package/dist/modules/design_system/gallery/demos/key-components.js +127 -0
  158. package/dist/modules/design_system/gallery/demos/key-components.js.map +7 -0
  159. package/dist/modules/design_system/gallery/demos/marketing-controls-code.generated.js +98 -0
  160. package/dist/modules/design_system/gallery/demos/marketing-controls-code.generated.js.map +7 -0
  161. package/dist/modules/design_system/gallery/demos/marketing-controls.js +134 -0
  162. package/dist/modules/design_system/gallery/demos/marketing-controls.js.map +7 -0
  163. package/dist/modules/design_system/gallery/demos/marketing-widgets-code.generated.js +195 -0
  164. package/dist/modules/design_system/gallery/demos/marketing-widgets-code.generated.js.map +7 -0
  165. package/dist/modules/design_system/gallery/demos/marketing-widgets.js +586 -0
  166. package/dist/modules/design_system/gallery/demos/marketing-widgets.js.map +7 -0
  167. package/dist/modules/design_system/gallery/demos/menu-fixtures.js +40 -0
  168. package/dist/modules/design_system/gallery/demos/menu-fixtures.js.map +7 -0
  169. package/dist/modules/design_system/gallery/demos/menu-sources.js +295 -0
  170. package/dist/modules/design_system/gallery/demos/menu-sources.js.map +7 -0
  171. package/dist/modules/design_system/gallery/demos/menus.js +150 -0
  172. package/dist/modules/design_system/gallery/demos/menus.js.map +7 -0
  173. package/dist/modules/design_system/gallery/demos/rating-reviews.js +53 -0
  174. package/dist/modules/design_system/gallery/demos/rating-reviews.js.map +7 -0
  175. package/dist/modules/design_system/gallery/demos/registered-icons.js +104 -0
  176. package/dist/modules/design_system/gallery/demos/registered-icons.js.map +7 -0
  177. package/dist/modules/design_system/gallery/demos/selection-cards.js +99 -0
  178. package/dist/modules/design_system/gallery/demos/selection-cards.js.map +7 -0
  179. package/dist/modules/design_system/gallery/demos/shell-code.generated.js +189 -0
  180. package/dist/modules/design_system/gallery/demos/shell-code.generated.js.map +7 -0
  181. package/dist/modules/design_system/gallery/demos/shell.js +330 -0
  182. package/dist/modules/design_system/gallery/demos/shell.js.map +7 -0
  183. package/dist/modules/design_system/gallery/demos/source-artwork.js +120 -0
  184. package/dist/modules/design_system/gallery/demos/source-artwork.js.map +7 -0
  185. package/dist/modules/design_system/gallery/demos/source-filters-code.generated.js +125 -0
  186. package/dist/modules/design_system/gallery/demos/source-filters-code.generated.js.map +7 -0
  187. package/dist/modules/design_system/gallery/demos/source-filters.js +185 -0
  188. package/dist/modules/design_system/gallery/demos/source-filters.js.map +7 -0
  189. package/dist/modules/design_system/gallery/demos/source-icons.js +69 -0
  190. package/dist/modules/design_system/gallery/demos/source-icons.js.map +7 -0
  191. package/dist/modules/design_system/gallery/demos/table-cells-code.generated.js +150 -0
  192. package/dist/modules/design_system/gallery/demos/table-cells-code.generated.js.map +7 -0
  193. package/dist/modules/design_system/gallery/demos/table-cells.js +181 -0
  194. package/dist/modules/design_system/gallery/demos/table-cells.js.map +7 -0
  195. package/dist/modules/design_system/gallery/demos/text-inputs.js +113 -0
  196. package/dist/modules/design_system/gallery/demos/text-inputs.js.map +7 -0
  197. package/dist/modules/design_system/gallery/demos/time-picker-code.generated.js +41 -0
  198. package/dist/modules/design_system/gallery/demos/time-picker-code.generated.js.map +7 -0
  199. package/dist/modules/design_system/gallery/demos/time-picker.js +41 -0
  200. package/dist/modules/design_system/gallery/demos/time-picker.js.map +7 -0
  201. package/dist/modules/design_system/gallery/entries/banners.js +123 -60
  202. package/dist/modules/design_system/gallery/entries/banners.js.map +2 -2
  203. package/dist/modules/design_system/gallery/entries/buttons-snippets.js +433 -0
  204. package/dist/modules/design_system/gallery/entries/buttons-snippets.js.map +7 -0
  205. package/dist/modules/design_system/gallery/entries/buttons.js +127 -148
  206. package/dist/modules/design_system/gallery/entries/buttons.js.map +2 -2
  207. package/dist/modules/design_system/gallery/entries/charts.js +532 -186
  208. package/dist/modules/design_system/gallery/entries/charts.js.map +2 -2
  209. package/dist/modules/design_system/gallery/entries/dates.js +191 -3
  210. package/dist/modules/design_system/gallery/entries/dates.js.map +2 -2
  211. package/dist/modules/design_system/gallery/entries/detail.js +118 -77
  212. package/dist/modules/design_system/gallery/entries/detail.js.map +2 -2
  213. package/dist/modules/design_system/gallery/entries/display.js +1449 -240
  214. package/dist/modules/design_system/gallery/entries/display.js.map +2 -2
  215. package/dist/modules/design_system/gallery/entries/feedback.js +1058 -132
  216. package/dist/modules/design_system/gallery/entries/feedback.js.map +2 -2
  217. package/dist/modules/design_system/gallery/entries/filters.js +231 -103
  218. package/dist/modules/design_system/gallery/entries/filters.js.map +2 -2
  219. package/dist/modules/design_system/gallery/entries/foundations.js +368 -57
  220. package/dist/modules/design_system/gallery/entries/foundations.js.map +2 -2
  221. package/dist/modules/design_system/gallery/entries/icons.js +29 -91
  222. package/dist/modules/design_system/gallery/entries/icons.js.map +2 -2
  223. package/dist/modules/design_system/gallery/entries/inputs-snippets.js +154 -0
  224. package/dist/modules/design_system/gallery/entries/inputs-snippets.js.map +7 -0
  225. package/dist/modules/design_system/gallery/entries/inputs.js +2043 -306
  226. package/dist/modules/design_system/gallery/entries/inputs.js.map +2 -2
  227. package/dist/modules/design_system/gallery/entries/library.js +20 -0
  228. package/dist/modules/design_system/gallery/entries/library.js.map +7 -0
  229. package/dist/modules/design_system/gallery/entries/messages.js +121 -103
  230. package/dist/modules/design_system/gallery/entries/messages.js.map +2 -2
  231. package/dist/modules/design_system/gallery/entries/navigation.js +676 -103
  232. package/dist/modules/design_system/gallery/entries/navigation.js.map +2 -2
  233. package/dist/modules/design_system/gallery/entries/notifications.js +131 -78
  234. package/dist/modules/design_system/gallery/entries/notifications.js.map +2 -2
  235. package/dist/modules/design_system/gallery/entries/overlays.js +611 -203
  236. package/dist/modules/design_system/gallery/entries/overlays.js.map +2 -2
  237. package/dist/modules/design_system/gallery/entries/scaffolding.js +1175 -120
  238. package/dist/modules/design_system/gallery/entries/scaffolding.js.map +2 -2
  239. package/dist/modules/design_system/gallery/entries/schedule.js +79 -54
  240. package/dist/modules/design_system/gallery/entries/schedule.js.map +2 -2
  241. package/dist/modules/design_system/gallery/presentation.js +108 -0
  242. package/dist/modules/design_system/gallery/presentation.js.map +7 -0
  243. package/dist/modules/design_system/gallery/registry.js +8 -5
  244. package/dist/modules/design_system/gallery/registry.js.map +2 -2
  245. package/dist/modules/design_system/gallery/source-library.generated.js +5 -0
  246. package/dist/modules/design_system/gallery/source-library.generated.js.map +7 -0
  247. package/dist/modules/design_system/i18n/de.json +7167 -0
  248. package/dist/modules/design_system/i18n/en.json +7167 -0
  249. package/dist/modules/design_system/i18n/es.json +7167 -0
  250. package/dist/modules/design_system/i18n/ko.json +7167 -0
  251. package/dist/modules/design_system/i18n/pl.json +7167 -0
  252. package/dist/modules/push_notifications/lib/queue.js +1 -31
  253. package/dist/modules/push_notifications/lib/queue.js.map +2 -2
  254. package/jest.config.cjs +1 -0
  255. package/jest.mocks/image.js +1 -0
  256. package/package.json +8 -9
  257. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +50 -0
  258. package/src/modules/customers/backend/customers/companies/[id]/page.tsx +2 -1
  259. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +2 -1
  260. package/src/modules/customers/backend/customers/people/[id]/page.tsx +2 -2
  261. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +2 -1
  262. package/src/modules/customers/lib/detailHelpers.ts +4 -0
  263. package/src/modules/customers/lib/todoCompatibility.ts +10 -0
  264. package/src/modules/design_system/backend/design-system/page.meta.ts +3 -2
  265. package/src/modules/design_system/gallery/assets/README.md +30 -0
  266. package/src/modules/design_system/gallery/assets/ai-prompt-image.png +0 -0
  267. package/src/modules/design_system/gallery/assets/avatar-illustration.png +0 -0
  268. package/src/modules/design_system/gallery/assets/avatar-memoji.png +0 -0
  269. package/src/modules/design_system/gallery/assets/avatar-photo.png +0 -0
  270. package/src/modules/design_system/gallery/assets/blog-photo-0.png +0 -0
  271. package/src/modules/design_system/gallery/assets/contact-support-portrait.png +0 -0
  272. package/src/modules/design_system/gallery/assets/crypto-ada.png +0 -0
  273. package/src/modules/design_system/gallery/assets/crypto-avax.png +0 -0
  274. package/src/modules/design_system/gallery/assets/crypto-bnb.png +0 -0
  275. package/src/modules/design_system/gallery/assets/crypto-brand.png +0 -0
  276. package/src/modules/design_system/gallery/assets/crypto-btc.png +0 -0
  277. package/src/modules/design_system/gallery/assets/crypto-clock.svg +3 -0
  278. package/src/modules/design_system/gallery/assets/crypto-crown.svg +3 -0
  279. package/src/modules/design_system/gallery/assets/crypto-dot.png +0 -0
  280. package/src/modules/design_system/gallery/assets/crypto-eth.png +0 -0
  281. package/src/modules/design_system/gallery/assets/crypto-hbar.png +0 -0
  282. package/src/modules/design_system/gallery/assets/crypto-history.svg +3 -0
  283. package/src/modules/design_system/gallery/assets/crypto-link.svg +3 -0
  284. package/src/modules/design_system/gallery/assets/crypto-menu.svg +3 -0
  285. package/src/modules/design_system/gallery/assets/crypto-metamask.png +0 -0
  286. package/src/modules/design_system/gallery/assets/crypto-more.svg +3 -0
  287. package/src/modules/design_system/gallery/assets/crypto-phantom.png +0 -0
  288. package/src/modules/design_system/gallery/assets/crypto-rewards.svg +3 -0
  289. package/src/modules/design_system/gallery/assets/crypto-sad-face.png +0 -0
  290. package/src/modules/design_system/gallery/assets/crypto-sol.png +0 -0
  291. package/src/modules/design_system/gallery/assets/crypto-star.svg +3 -0
  292. package/src/modules/design_system/gallery/assets/crypto-status-cancelled.svg +3 -0
  293. package/src/modules/design_system/gallery/assets/crypto-status-pending.svg +3 -0
  294. package/src/modules/design_system/gallery/assets/crypto-status-success.svg +3 -0
  295. package/src/modules/design_system/gallery/assets/crypto-status-warning.svg +3 -0
  296. package/src/modules/design_system/gallery/assets/crypto-trx.png +0 -0
  297. package/src/modules/design_system/gallery/assets/crypto-usdc.png +0 -0
  298. package/src/modules/design_system/gallery/assets/crypto-usdt.png +0 -0
  299. package/src/modules/design_system/gallery/assets/crypto-walletconnect.png +0 -0
  300. package/src/modules/design_system/gallery/assets/crypto-wei.png +0 -0
  301. package/src/modules/design_system/gallery/assets/crypto-xrp.png +0 -0
  302. package/src/modules/design_system/gallery/assets/cryptocurrency-artwork.ts +63 -0
  303. package/src/modules/design_system/gallery/assets/github-logo.png +0 -0
  304. package/src/modules/design_system/gallery/assets/images.d.ts +9 -0
  305. package/src/modules/design_system/gallery/assets/input-european-union.svg +18 -0
  306. package/src/modules/design_system/gallery/assets/landing-teams-01.png +0 -0
  307. package/src/modules/design_system/gallery/assets/marketing-artwork.ts +79 -0
  308. package/src/modules/design_system/gallery/assets/menu-apex.svg +18 -0
  309. package/src/modules/design_system/gallery/assets/menu-mastercard.svg +7 -0
  310. package/src/modules/design_system/gallery/assets/menu-spotify.svg +4 -0
  311. package/src/modules/design_system/gallery/assets/menu-united-states.svg +16 -0
  312. package/src/modules/design_system/gallery/assets/select-google.png +0 -0
  313. package/src/modules/design_system/gallery/assets/select-poland.png +0 -0
  314. package/src/modules/design_system/gallery/assets/selection-artwork.ts +1 -0
  315. package/src/modules/design_system/gallery/assets/social-apple-filled.svg +4 -0
  316. package/src/modules/design_system/gallery/assets/social-apple-stroke.svg +4 -0
  317. package/src/modules/design_system/gallery/assets/social-dropbox-filled.svg +5 -0
  318. package/src/modules/design_system/gallery/assets/social-dropbox-stroke.svg +5 -0
  319. package/src/modules/design_system/gallery/assets/social-facebook-filled.svg +4 -0
  320. package/src/modules/design_system/gallery/assets/social-facebook-stroke.svg +10 -0
  321. package/src/modules/design_system/gallery/assets/social-github-filled.svg +4 -0
  322. package/src/modules/design_system/gallery/assets/social-github-stroke.svg +4 -0
  323. package/src/modules/design_system/gallery/assets/social-google-filled.svg +7 -0
  324. package/src/modules/design_system/gallery/assets/social-google-stroke.svg +7 -0
  325. package/src/modules/design_system/gallery/assets/social-linkedin-filled.svg +4 -0
  326. package/src/modules/design_system/gallery/assets/social-linkedin-stroke.svg +4 -0
  327. package/src/modules/design_system/gallery/assets/social-x-filled.svg +4 -0
  328. package/src/modules/design_system/gallery/assets/social-x-stroke.svg +4 -0
  329. package/src/modules/design_system/gallery/assets/style-studio-product.png +0 -0
  330. package/src/modules/design_system/gallery/assets/upload-images.ts +5 -0
  331. package/src/modules/design_system/gallery/components/BrandStylePreview.tsx +94 -0
  332. package/src/modules/design_system/gallery/components/CodeSnippet.tsx +34 -34
  333. package/src/modules/design_system/gallery/components/ColorPlayground.tsx +324 -0
  334. package/src/modules/design_system/gallery/components/ColorStudioCompositions.tsx +96 -0
  335. package/src/modules/design_system/gallery/components/ColorStudioSpecimen.tsx +164 -0
  336. package/src/modules/design_system/gallery/components/CompactEntrySpecimen.tsx +65 -0
  337. package/src/modules/design_system/gallery/components/ComponentIndex.tsx +47 -0
  338. package/src/modules/design_system/gallery/components/DesignSystemHome.tsx +66 -0
  339. package/src/modules/design_system/gallery/components/EntryCard.tsx +52 -37
  340. package/src/modules/design_system/gallery/components/EntryHeader.tsx +80 -0
  341. package/src/modules/design_system/gallery/components/FamilyEntryPreview.tsx +22 -0
  342. package/src/modules/design_system/gallery/components/FoundationGuide.tsx +43 -0
  343. package/src/modules/design_system/gallery/components/GalleryLink.tsx +19 -0
  344. package/src/modules/design_system/gallery/components/GalleryNavigation.tsx +86 -0
  345. package/src/modules/design_system/gallery/components/GalleryShell.tsx +149 -63
  346. package/src/modules/design_system/gallery/components/IconsBrowser.tsx +40 -0
  347. package/src/modules/design_system/gallery/components/SourceLibrary.tsx +90 -0
  348. package/src/modules/design_system/gallery/components/StyleAgents.tsx +115 -0
  349. package/src/modules/design_system/gallery/components/ThemeTokenReference.tsx +76 -0
  350. package/src/modules/design_system/gallery/components/VariantPreview.tsx +2 -2
  351. package/src/modules/design_system/gallery/components/colorPreview.ts +63 -0
  352. package/src/modules/design_system/gallery/components/colorStudio.ts +260 -0
  353. package/src/modules/design_system/gallery/components/styleAgentBranding.ts +42 -0
  354. package/src/modules/design_system/gallery/components/themeTokens.ts +26 -0
  355. package/src/modules/design_system/gallery/demos/ai-product-code.generated.ts +3 -0
  356. package/src/modules/design_system/gallery/demos/ai-product.tsx +188 -0
  357. package/src/modules/design_system/gallery/demos/buttons.tsx +331 -0
  358. package/src/modules/design_system/gallery/demos/cryptocurrency.tsx +1943 -0
  359. package/src/modules/design_system/gallery/demos/feeds-code.generated.ts +4 -0
  360. package/src/modules/design_system/gallery/demos/feeds.tsx +82 -0
  361. package/src/modules/design_system/gallery/demos/file-upload.tsx +61 -0
  362. package/src/modules/design_system/gallery/demos/foundation-reference-data.ts +4872 -0
  363. package/src/modules/design_system/gallery/demos/foundation-references.tsx +140 -0
  364. package/src/modules/design_system/gallery/demos/key-components-code.generated.ts +3 -0
  365. package/src/modules/design_system/gallery/demos/key-components.tsx +106 -0
  366. package/src/modules/design_system/gallery/demos/marketing-controls-code.generated.ts +3 -0
  367. package/src/modules/design_system/gallery/demos/marketing-controls.tsx +92 -0
  368. package/src/modules/design_system/gallery/demos/marketing-widgets-code.generated.ts +3 -0
  369. package/src/modules/design_system/gallery/demos/marketing-widgets.tsx +189 -0
  370. package/src/modules/design_system/gallery/demos/menu-fixtures.tsx +48 -0
  371. package/src/modules/design_system/gallery/demos/menu-sources.ts +5 -0
  372. package/src/modules/design_system/gallery/demos/menus.tsx +122 -0
  373. package/src/modules/design_system/gallery/demos/rating-reviews.tsx +44 -0
  374. package/src/modules/design_system/gallery/demos/registered-icons.tsx +117 -0
  375. package/src/modules/design_system/gallery/demos/selection-cards.tsx +97 -0
  376. package/src/modules/design_system/gallery/demos/shell-code.generated.ts +3 -0
  377. package/src/modules/design_system/gallery/demos/shell.tsx +183 -0
  378. package/src/modules/design_system/gallery/demos/source-artwork.tsx +88 -0
  379. package/src/modules/design_system/gallery/demos/source-filters-code.generated.ts +3 -0
  380. package/src/modules/design_system/gallery/demos/source-filters.tsx +119 -0
  381. package/src/modules/design_system/gallery/demos/source-icons.tsx +62 -0
  382. package/src/modules/design_system/gallery/demos/table-cells-code.generated.ts +3 -0
  383. package/src/modules/design_system/gallery/demos/table-cells.tsx +144 -0
  384. package/src/modules/design_system/gallery/demos/text-inputs.tsx +90 -0
  385. package/src/modules/design_system/gallery/demos/time-picker-code.generated.ts +5 -0
  386. package/src/modules/design_system/gallery/demos/time-picker.tsx +31 -0
  387. package/src/modules/design_system/gallery/entries/banners.tsx +143 -94
  388. package/src/modules/design_system/gallery/entries/buttons-snippets.ts +432 -0
  389. package/src/modules/design_system/gallery/entries/buttons.tsx +125 -196
  390. package/src/modules/design_system/gallery/entries/charts.tsx +545 -233
  391. package/src/modules/design_system/gallery/entries/dates.tsx +171 -3
  392. package/src/modules/design_system/gallery/entries/detail.tsx +142 -115
  393. package/src/modules/design_system/gallery/entries/display.tsx +1691 -319
  394. package/src/modules/design_system/gallery/entries/feedback.tsx +1082 -169
  395. package/src/modules/design_system/gallery/entries/filters.tsx +238 -143
  396. package/src/modules/design_system/gallery/entries/foundations.tsx +404 -61
  397. package/src/modules/design_system/gallery/entries/icons.tsx +31 -117
  398. package/src/modules/design_system/gallery/entries/inputs-snippets.ts +156 -0
  399. package/src/modules/design_system/gallery/entries/inputs.tsx +2146 -503
  400. package/src/modules/design_system/gallery/entries/library.tsx +16 -0
  401. package/src/modules/design_system/gallery/entries/messages.tsx +114 -106
  402. package/src/modules/design_system/gallery/entries/navigation.tsx +782 -192
  403. package/src/modules/design_system/gallery/entries/notifications.tsx +145 -120
  404. package/src/modules/design_system/gallery/entries/overlays.tsx +696 -280
  405. package/src/modules/design_system/gallery/entries/scaffolding.tsx +1192 -158
  406. package/src/modules/design_system/gallery/entries/schedule.tsx +72 -58
  407. package/src/modules/design_system/gallery/presentation.ts +106 -0
  408. package/src/modules/design_system/gallery/registry.ts +8 -6
  409. package/src/modules/design_system/gallery/source-library.generated.ts +2 -0
  410. package/src/modules/design_system/i18n/de.json +7112 -3
  411. package/src/modules/design_system/i18n/en.json +7112 -3
  412. package/src/modules/design_system/i18n/es.json +7112 -3
  413. package/src/modules/design_system/i18n/ko.json +7112 -3
  414. package/src/modules/design_system/i18n/pl.json +7112 -3
  415. package/src/modules/push_notifications/AGENTS.md +9 -5
  416. package/src/modules/push_notifications/lib/queue.ts +15 -44
@@ -1,5 +1,9 @@
1
+ import { MarketingControlDemo } from '../demos/marketing-controls'
2
+ import { marketingControlExampleCode } from '../demos/marketing-controls-code.generated'
3
+ import { FieldLabelExample, FormFieldLabelExample, HintTextExample } from '../demos/key-components'
1
4
  import * as React from 'react'
2
5
  import { Copy, Globe, Info, Link2, Send, User } from 'lucide-react'
6
+ import { useT } from '@open-mercato/shared/lib/i18n/context'
3
7
  import { Input } from '@open-mercato/ui/primitives/input'
4
8
  import { Textarea } from '@open-mercato/ui/primitives/textarea'
5
9
  import {
@@ -22,11 +26,13 @@ import { Radio, RadioGroup } from '@open-mercato/ui/primitives/radio'
22
26
  import { RadioField } from '@open-mercato/ui/primitives/radio-field'
23
27
  import { Switch } from '@open-mercato/ui/primitives/switch'
24
28
  import { SwitchField } from '@open-mercato/ui/primitives/switch-field'
29
+ import { Badge } from '@open-mercato/ui/primitives/badge'
25
30
  import { Slider } from '@open-mercato/ui/primitives/slider'
26
31
  import { FormField } from '@open-mercato/ui/primitives/form-field'
27
32
  import { SearchInput } from '@open-mercato/ui/primitives/search-input'
28
33
  import { EmailInput } from '@open-mercato/ui/primitives/email-input'
29
34
  import { PasswordInput } from '@open-mercato/ui/primitives/password-input'
35
+ import { PasswordStrength } from '@open-mercato/ui/primitives/password-strength'
30
36
  import { WebsiteInput } from '@open-mercato/ui/primitives/website-input'
31
37
  import { AmountInput, type AmountValue } from '@open-mercato/ui/primitives/amount-input'
32
38
  import { CounterInput } from '@open-mercato/ui/primitives/counter-input'
@@ -38,9 +44,15 @@ import {
38
44
  COLOR_PICKER_DEFAULT_SWATCHES,
39
45
  } from '@open-mercato/ui/primitives/color-picker'
40
46
  import { TagInput } from '@open-mercato/ui/primitives/tag-input'
41
- import { RichEditor } from '@open-mercato/ui/primitives/rich-editor'
47
+ import { RichEditor, RichEditorColorPalette, RICH_EDITOR_COLOR_PALETTE, type RichEditorToolbarDesign, type RichEditorVariant, type RichEditorColorKey } from '@open-mercato/ui/primitives/rich-editor'
42
48
  import { IconButton } from '@open-mercato/ui/primitives/icon-button'
49
+ import { FileFormatIcon } from '@open-mercato/ui/primitives/file-format-icon'
50
+ import { FileUploadAreaDemo, FileUploadCardDemo, ImageUploadDemo } from '../demos/file-upload'
51
+ import { SelectionSourceCardsDemo, IntegrationSwitchDemo } from '../demos/selection-cards'
52
+ import { SelectSourceExample, SelectSourceMatrix, DropdownSourceExample } from '../demos/menus'
53
+ import { SourceTextInputMatrix, SourcePhoneExamples, SourceTextareaExamples } from '../demos/text-inputs'
43
54
  import type { GalleryEntry } from '../types'
55
+ import { inputFieldCode, textareaFieldCode, phoneNumberFieldCode, selectFieldCode, dropdownCode, fieldLabelCode, fieldLabelInformationCode, fieldLabelActionCode, formFieldLabelCode, hintTextCode } from './inputs-snippets'
44
56
 
45
57
  // Component titles and variant names are proper nouns from the codebase and
46
58
  // are deliberately not translated. `code` MUST contain the entry's importPath
@@ -54,7 +66,8 @@ import type { GalleryEntry } from '../types'
54
66
  // ---------------------------------------------------------------------------
55
67
 
56
68
  function DemoSearchInput({ size }: { size?: 'sm' | 'default' | 'lg' }) {
57
- const [value, setValue] = React.useState('open orders')
69
+ const t = useT()
70
+ const [value, setValue] = React.useState(() => t('design_system.gallery.sampleCopy.openOrders'))
58
71
  return (
59
72
  <div className="w-72">
60
73
  <SearchInput value={value} onChange={setValue} size={size} />
@@ -71,6 +84,103 @@ function DemoAmountInput({ showCurrency }: { showCurrency?: boolean }) {
71
84
  )
72
85
  }
73
86
 
87
+ const selectionCardClasses = 'relative w-full max-w-90 gap-3.5 rounded-xl border border-border bg-background p-4 shadow-xs transition-colors hover:border-transparent hover:bg-muted hover:shadow-none has-[[data-state=checked]]:border-accent-indigo has-[[data-state=checked]]:shadow-none has-[:focus-visible]:shadow-focus has-[:disabled]:border-border has-[:disabled]:bg-background has-[:disabled]:shadow-none [&_label]:after:absolute [&_label]:after:inset-0 [&_label]:after:rounded-xl [&_button]:relative [&_button]:z-10'
88
+
89
+ function SelectionCardsPreview({ control, disabled = false }: { control: 'checkbox' | 'radio' | 'switch'; disabled?: boolean }) {
90
+ const t = useT()
91
+ const choices = [
92
+ { value: 'immediate', label: t('design_system.gallery.samples.selection.immediate'), description: t('design_system.gallery.samples.selection.immediateDescription') },
93
+ { value: 'weekly', label: t('design_system.gallery.samples.selection.weekly'), description: t('design_system.gallery.samples.selection.weeklyDescription') },
94
+ ]
95
+ const cards = choices.map((choice, index) => {
96
+ const fieldProps = {
97
+ label: choice.label,
98
+ description: choice.description,
99
+ sublabel: t('design_system.gallery.samples.selection.optional'),
100
+ badge: <Badge variant={disabled ? 'outline' : 'info'} size="sm" className={disabled ? 'text-text-disabled' : undefined}>{t('design_system.gallery.samples.selection.new')}</Badge>,
101
+ disabled,
102
+ className: 'mt-0',
103
+ containerClassName: selectionCardClasses,
104
+ }
105
+ if (control === 'radio') return <RadioField key={choice.value} value={choice.value} flip {...fieldProps} />
106
+ if (control === 'switch') return <SwitchField key={choice.value} defaultChecked={index === 0} {...fieldProps} />
107
+ return <CheckboxField key={choice.value} defaultChecked={index === 0} flip {...fieldProps} />
108
+ })
109
+ if (control === 'radio') {
110
+ return <RadioGroup defaultValue="immediate" aria-label={t('design_system.gallery.samples.selection.preferences')} className="grid w-full gap-4 sm:grid-cols-2">{cards}</RadioGroup>
111
+ }
112
+ return <div className="grid w-full gap-4 sm:grid-cols-2">{cards}</div>
113
+ }
114
+
115
+ function FlippedRadioPreview() {
116
+ const t = useT()
117
+ return (
118
+ <RadioGroup defaultValue="immediate" aria-label={t('design_system.gallery.samples.selection.preferences')} className="w-72">
119
+ <RadioField value="immediate" flip label={t('design_system.gallery.samples.selection.immediate')} />
120
+ <RadioField value="weekly" flip label={t('design_system.gallery.samples.selection.weekly')} />
121
+ </RadioGroup>
122
+ )
123
+ }
124
+
125
+ function ReadOnlyInputPreview() {
126
+ const t = useT()
127
+ return (
128
+ <FormField
129
+ className="w-full max-w-sm"
130
+ label={t('design_system.gallery.samples.states.recordId')}
131
+ description={t('design_system.gallery.samples.states.readOnlyHint')}
132
+ >
133
+ <Input readOnly value="OM-2026-0042" />
134
+ </FormField>
135
+ )
136
+ }
137
+
138
+ function ReadOnlyTextareaPreview() {
139
+ const t = useT()
140
+ return (
141
+ <FormField
142
+ className="w-full max-w-sm"
143
+ label={t('design_system.gallery.samples.states.savedNote')}
144
+ description={t('design_system.gallery.samples.states.readOnlyHint')}
145
+ >
146
+ <Textarea readOnly value={t('design_system.gallery.samples.states.noteValue')} />
147
+ </FormField>
148
+ )
149
+ }
150
+
151
+ function DisabledSearchInputPreview() {
152
+ const t = useT()
153
+ const [query, setQuery] = React.useState('OM-2026-0042')
154
+ return (
155
+ <FormField className="w-full max-w-sm" label={t('design_system.gallery.samples.states.search')} disabled>
156
+ <SearchInput value={query} onChange={setQuery} />
157
+ </FormField>
158
+ )
159
+ }
160
+
161
+ function InvalidPasswordInputPreview() {
162
+ const t = useT()
163
+ return (
164
+ <FormField
165
+ className="w-full max-w-sm"
166
+ label={t('design_system.gallery.samples.states.password')}
167
+ error={t('design_system.gallery.samples.states.passwordError')}
168
+ >
169
+ <PasswordInput defaultValue="short" autoComplete="off" />
170
+ </FormField>
171
+ )
172
+ }
173
+
174
+ function DisabledAmountInputPreview() {
175
+ const t = useT()
176
+ const [value, setValue] = React.useState<AmountValue>({ amount: '1250.00', currency: 'EUR' })
177
+ return (
178
+ <FormField className="w-full max-w-sm" label={t('design_system.gallery.samples.states.amount')} disabled>
179
+ <AmountInput value={value} onChange={setValue} />
180
+ </FormField>
181
+ )
182
+ }
183
+
74
184
  function DemoCounterInput({
75
185
  initial = 2,
76
186
  step,
@@ -111,18 +221,25 @@ function DemoCardInput({ initial = '' }: { initial?: string }) {
111
221
  function DemoColorPicker({
112
222
  allowCustom,
113
223
  swatches,
224
+ showOpacity = false,
114
225
  }: {
115
226
  allowCustom?: boolean
116
227
  swatches?: readonly string[]
228
+ showOpacity?: boolean
117
229
  }) {
230
+ const t = useT()
118
231
  const [color, setColor] = React.useState('#6366F1')
232
+ const [opacity, setOpacity] = React.useState(75)
119
233
  return (
120
234
  <ColorPicker
121
235
  value={color}
122
236
  onChange={setColor}
123
237
  allowCustom={allowCustom}
124
238
  swatches={swatches}
125
- aria-label="Pick color"
239
+ showOpacity={showOpacity}
240
+ opacity={showOpacity ? opacity : 100}
241
+ onOpacityChange={showOpacity ? setOpacity : undefined}
242
+ aria-label={t('design_system.gallery.sampleCopy.pickColor')}
126
243
  />
127
244
  )
128
245
  }
@@ -144,17 +261,68 @@ function DemoTagInput({
144
261
  )
145
262
  }
146
263
 
147
- function DemoRichEditor({ variant }: { variant: 'minimal' | 'standard' }) {
148
- const [html, setHtml] = React.useState(
149
- '<p>Ship the <strong>Q3 release notes</strong> before Friday.</p>',
150
- )
264
+ function DemoRichEditor({ variant = 'standard', toolbarDesign, disabled = false, counter = false }: { variant?: RichEditorVariant; toolbarDesign?: RichEditorToolbarDesign; disabled?: boolean; counter?: boolean }) {
265
+ const t = useT()
266
+ const [html, setHtml] = React.useState(() => '<p>' + t('design_system.gallery.samples.richEditor.initial') + '</p>')
267
+ const [feedback, setFeedback] = React.useState('')
268
+ const labels = {
269
+ bold: t('design_system.gallery.samples.richEditor.labels.bold'),
270
+ italic: t('design_system.gallery.samples.richEditor.labels.italic'),
271
+ underline: t('design_system.gallery.samples.richEditor.labels.underline'),
272
+ strikethrough: t('design_system.gallery.samples.richEditor.labels.strikethrough'),
273
+ unorderedList: t('design_system.gallery.samples.richEditor.labels.unorderedList'),
274
+ orderedList: t('design_system.gallery.samples.richEditor.labels.orderedList'),
275
+ checklist: t('design_system.gallery.samples.richEditor.labels.checklist'),
276
+ blockquote: t('design_system.gallery.samples.richEditor.labels.blockquote'),
277
+ code: t('design_system.gallery.samples.richEditor.labels.code'),
278
+ inlineCode: t('design_system.gallery.samples.richEditor.labels.inlineCode'),
279
+ codeBlock: t('design_system.gallery.samples.richEditor.labels.codeBlock'),
280
+ horizontalRule: t('design_system.gallery.samples.richEditor.labels.horizontalRule'),
281
+ image: t('design_system.gallery.samples.richEditor.labels.image'),
282
+ imageUrlPrompt: t('design_system.gallery.samples.richEditor.labels.imageUrlPrompt'),
283
+ table: t('design_system.gallery.samples.richEditor.labels.table'),
284
+ heading: t('design_system.gallery.samples.richEditor.labels.heading'),
285
+ heading1: t('design_system.gallery.samples.richEditor.labels.heading1'),
286
+ heading2: t('design_system.gallery.samples.richEditor.labels.heading2'),
287
+ heading3: t('design_system.gallery.samples.richEditor.labels.heading3'),
288
+ paragraph: t('design_system.gallery.samples.richEditor.labels.paragraph'),
289
+ link: t('design_system.gallery.samples.richEditor.labels.link'),
290
+ linkUrlPrompt: t('design_system.gallery.samples.richEditor.labels.linkUrlPrompt'),
291
+ color: t('design_system.gallery.samples.richEditor.labels.color'),
292
+ textColor: t('design_system.gallery.samples.richEditor.labels.textColor'),
293
+ fontSize: t('design_system.gallery.samples.richEditor.labels.fontSize'),
294
+ align: t('design_system.gallery.samples.richEditor.labels.align'),
295
+ alignLeft: t('design_system.gallery.samples.richEditor.labels.alignLeft'),
296
+ alignCenter: t('design_system.gallery.samples.richEditor.labels.alignCenter'),
297
+ alignRight: t('design_system.gallery.samples.richEditor.labels.alignRight'),
298
+ alignJustify: t('design_system.gallery.samples.richEditor.labels.alignJustify'),
299
+ comment: t('design_system.gallery.samples.richEditor.labels.comment'),
300
+ mention: t('design_system.gallery.samples.richEditor.labels.mention'),
301
+ more: t('design_system.gallery.samples.richEditor.labels.more'),
302
+ help: t('design_system.gallery.samples.richEditor.labels.help'),
303
+ fullscreen: t('design_system.gallery.samples.richEditor.labels.fullscreen'),
304
+ placeholder: t('design_system.gallery.samples.richEditor.labels.placeholder'),
305
+ colors: Object.fromEntries(Object.keys(RICH_EDITOR_COLOR_PALETTE).map(key => [key, t(`design_system.gallery.samples.richEditor.colors.${key}`)])) as Record<RichEditorColorKey, string>,
306
+ }
151
307
  return (
152
- <div className="w-full max-w-xl">
153
- <RichEditor value={html} onChange={setHtml} variant={variant} />
308
+ <div className="flex min-w-0 w-full max-w-3xl flex-col gap-3">
309
+ <RichEditor value={html} onChange={setHtml} variant={variant} toolbarDesign={toolbarDesign} disabled={disabled} maxLength={counter ? 100 : undefined} labels={labels}
310
+ onComment={() => setFeedback(t('design_system.gallery.samples.richEditor.comment'))}
311
+ onMention={() => setFeedback(t('design_system.gallery.samples.richEditor.mention'))} />
312
+ {feedback && <output aria-live="polite" className="text-sm text-muted-foreground">{feedback}</output>}
154
313
  </div>
155
314
  )
156
315
  }
157
316
 
317
+ function DemoRichEditorPalette() {
318
+ const t = useT()
319
+ const [value, setValue] = React.useState<RichEditorColorKey | null>('gray')
320
+ const labels = Object.fromEntries(Object.keys(RICH_EDITOR_COLOR_PALETTE).map(key => [key, t(`design_system.gallery.samples.richEditor.colors.${key}`)])) as Record<RichEditorColorKey, string>
321
+ return <div className="flex w-full max-w-sm flex-col gap-3"><RichEditorColorPalette value={value} onChange={setValue} labels={labels} />
322
+ <output aria-live="polite" className="text-sm text-muted-foreground">{value ? labels[value] : ''}</output>
323
+ </div>
324
+ }
325
+
158
326
  // ---------------------------------------------------------------------------
159
327
  // Entries
160
328
  // ---------------------------------------------------------------------------
@@ -163,15 +331,13 @@ const inputEntry: GalleryEntry = {
163
331
  id: 'input',
164
332
  title: 'Input',
165
333
  importPath: '@open-mercato/ui/primitives/input',
334
+ figmaNodeId: '266:5251',
335
+ usage: { do: ['Numeric sizes 32, 36 and 40 use the source 14/20 text, 20 px icons and asymmetric input padding. Named sizes preserve existing callers.', 'leading and trailing accept interactive controls; provide accessible labels and forward disabled to those controls. leftIcon/rightIcon remain decorative.', 'The source compositions cover all twelve Text Input types. Hover and focus are real browser states; the Date example uses the native date picker and locale formatting. Existing CardInput brand badges and phone parsing retain their runtime behavior.'] },
166
336
  variants: [
167
337
  {
168
338
  id: 'default',
169
339
  title: 'default',
170
- render: () => (
171
- <div className="w-72">
172
- <Input placeholder="Product name" />
173
- </div>
174
- ),
340
+ render: () => <InputInputsDefaultSample />,
175
341
  code: `import { Input } from '@open-mercato/ui/primitives/input'
176
342
 
177
343
  <Input placeholder="Product name" />`,
@@ -179,16 +345,7 @@ const inputEntry: GalleryEntry = {
179
345
  {
180
346
  id: 'icon-slots',
181
347
  title: 'Icon slots',
182
- render: () => (
183
- <>
184
- <div className="w-56">
185
- <Input leftIcon={<User />} placeholder="Assignee" />
186
- </div>
187
- <div className="w-56">
188
- <Input rightIcon={<Info />} placeholder="SKU" />
189
- </div>
190
- </>
191
- ),
348
+ render: () => <InputInputsIconSlotsSample />,
192
349
  code: `import { Info, User } from 'lucide-react'
193
350
  import { Input } from '@open-mercato/ui/primitives/input'
194
351
 
@@ -198,19 +355,7 @@ import { Input } from '@open-mercato/ui/primitives/input'
198
355
  {
199
356
  id: 'sizes',
200
357
  title: 'Sizes',
201
- render: () => (
202
- <>
203
- <div className="w-44">
204
- <Input size="lg" placeholder="Large" />
205
- </div>
206
- <div className="w-44">
207
- <Input size="default" placeholder="Default" />
208
- </div>
209
- <div className="w-44">
210
- <Input size="sm" placeholder="Small" />
211
- </div>
212
- </>
213
- ),
358
+ render: () => <InputInputsSizesSample />,
214
359
  code: `import { Input } from '@open-mercato/ui/primitives/input'
215
360
 
216
361
  <Input size="lg" placeholder="Large" />
@@ -220,37 +365,43 @@ import { Input } from '@open-mercato/ui/primitives/input'
220
365
  {
221
366
  id: 'states',
222
367
  title: 'States',
223
- render: () => (
224
- <>
225
- <div className="w-56">
226
- <Input aria-invalid defaultValue="not-a-number" />
227
- </div>
228
- <div className="w-56">
229
- <Input disabled placeholder="Disabled" />
230
- </div>
231
- </>
232
- ),
368
+ render: () => <InputInputsStatesSample />,
233
369
  code: `import { Input } from '@open-mercato/ui/primitives/input'
234
370
 
235
371
  <Input aria-invalid defaultValue="not-a-number" />
236
372
  <Input disabled placeholder="Disabled" />`,
237
373
  },
374
+ {
375
+ id: 'read-only',
376
+ title: 'Read-only',
377
+ render: () => <ReadOnlyInputPreview />,
378
+ code: `import { Input } from '@open-mercato/ui/primitives/input'
379
+ import { FormField } from '@open-mercato/ui/primitives/form-field'
380
+
381
+ <FormField label="Record ID" description="Read-only content stays focusable and can be selected and copied.">
382
+ <Input readOnly value="OM-2026-0042" />
383
+ </FormField>`,
384
+ },
385
+ { id: 'source-32', title: 'Source / all twelve types / 32 px', render: () => <SourceTextInputMatrix size={32} />, code: inputFieldCode({ inputProps: ' size={32}' }) },
386
+ { id: 'source-36', title: 'Source / all twelve types / 36 px', render: () => <SourceTextInputMatrix size={36} />, code: inputFieldCode({ inputProps: ' size={36}' }) },
387
+ { id: 'source-40', title: 'Source / all twelve types / 40 px', render: () => <SourceTextInputMatrix size={40} />, code: inputFieldCode({ inputProps: ' size={40}' }) },
388
+ { id: 'source-placeholder', title: 'Source / placeholder', render: () => <SourceTextInputMatrix state="placeholder" />, code: inputFieldCode() },
389
+ { id: 'source-error', title: 'Source / error', render: () => <SourceTextInputMatrix state="error" />, code: inputFieldCode({ inputProps: ' aria-invalid', fieldProps: ' error="Enter your full name"' }) },
390
+ { id: 'source-disabled', title: 'Source / disabled', render: () => <SourceTextInputMatrix state="disabled" />, code: inputFieldCode({ inputProps: ' disabled', fieldProps: ' disabled' }) },
238
391
  ],
239
392
  }
240
393
 
241
394
  const textareaEntry: GalleryEntry = {
242
395
  id: 'textarea',
243
396
  title: 'Textarea',
397
+ figmaNodeId: '435:5725',
398
+ usage: { do: ['appearance=source adds the source 112 px minimum field, 12 px radius, 14/20 text and an interior character counter. The browser-native resize handle remains operable.', 'The default appearance and external counter retain their current layout. Set maxLength together with showCount and supply a visible field label.'] },
244
399
  importPath: '@open-mercato/ui/primitives/textarea',
245
400
  variants: [
246
401
  {
247
402
  id: 'default',
248
403
  title: 'default',
249
- render: () => (
250
- <div className="w-80">
251
- <Textarea placeholder="Internal note for the fulfillment team" />
252
- </div>
253
- ),
404
+ render: () => <TextareaInputsDefaultSample />,
254
405
  code: `import { Textarea } from '@open-mercato/ui/primitives/textarea'
255
406
 
256
407
  <Textarea placeholder="Internal note for the fulfillment team" />`,
@@ -258,15 +409,7 @@ const textareaEntry: GalleryEntry = {
258
409
  {
259
410
  id: 'character-count',
260
411
  title: 'Character counter',
261
- render: () => (
262
- <div className="w-80">
263
- <Textarea
264
- showCount
265
- maxLength={200}
266
- defaultValue="Customer prefers delivery after 4 PM."
267
- />
268
- </div>
269
- ),
412
+ render: () => <TextareaInputsCharacterCountSample />,
270
413
  code: `import { Textarea } from '@open-mercato/ui/primitives/textarea'
271
414
 
272
415
  <Textarea showCount maxLength={200} defaultValue="Customer prefers delivery after 4 PM." />`,
@@ -274,183 +417,77 @@ const textareaEntry: GalleryEntry = {
274
417
  {
275
418
  id: 'states',
276
419
  title: 'States',
277
- render: () => (
278
- <>
279
- <div className="w-72">
280
- <Textarea aria-invalid defaultValue="Too short" />
281
- </div>
282
- <div className="w-72">
283
- <Textarea disabled placeholder="Disabled" />
284
- </div>
285
- </>
286
- ),
420
+ render: () => <TextareaInputsStatesSample />,
287
421
  code: `import { Textarea } from '@open-mercato/ui/primitives/textarea'
288
422
 
289
423
  <Textarea aria-invalid defaultValue="Too short" />
290
424
  <Textarea disabled placeholder="Disabled" />`,
291
425
  },
426
+ {
427
+ id: 'read-only',
428
+ title: 'Read-only',
429
+ render: () => <ReadOnlyTextareaPreview />,
430
+ code: `import { Textarea } from '@open-mercato/ui/primitives/textarea'
431
+ import { FormField } from '@open-mercato/ui/primitives/form-field'
432
+
433
+ <FormField label="Saved note" description="Read-only content stays focusable and can be selected and copied.">
434
+ <Textarea readOnly value="Customer requested delivery after 4 PM." />
435
+ </FormField>`,
436
+ },
437
+ { id: 'source-states', title: 'Source / default, filled, error and disabled', render: () => <SourceTextareaExamples />, code: textareaFieldCode },
438
+ ],
439
+ }
440
+
441
+ const phoneNumberEntry: GalleryEntry = {
442
+ id: 'phone-number-field',
443
+ title: 'PhoneNumberField',
444
+ importPath: '@open-mercato/ui/backend/inputs/PhoneNumberField',
445
+ figmaNodeId: '313:10101',
446
+ usage: { do: ['Numeric sizes 32/36/40 add source geometry while the existing automatic height remains the default.', 'Choose a country or edit the national number to update the local value. Validation and optional duplicate lookup retain their existing contracts.', 'countries translates and limits picker choices; countryLabel names the picker and renderCountryIcon can supply actual country assets.'] },
447
+ variants: [
448
+ { id: 'sizes', title: 'Source / 32, 36 and 40 px', render: () => <SourcePhoneExamples />, code: phoneNumberFieldCode() },
449
+ { id: 'placeholder', title: 'Source / placeholder', render: () => <SourcePhoneExamples state="placeholder" />, code: phoneNumberFieldCode() },
450
+ { id: 'validation', title: 'Source / validation', render: () => <SourcePhoneExamples state="error" />, code: phoneNumberFieldCode(' externalError="Enter a valid phone number"') },
451
+ { id: 'disabled', title: 'Source / disabled', render: () => <SourcePhoneExamples state="disabled" />, code: phoneNumberFieldCode(' disabled') },
292
452
  ],
293
453
  }
294
454
 
295
455
  const selectEntry: GalleryEntry = {
296
456
  id: 'select',
457
+ figmaNodeId: '270:1085',
297
458
  title: 'Select',
298
459
  importPath: '@open-mercato/ui/primitives/select',
460
+ usage: { do: [
461
+ 'Six source leading types: Basic, Country, Avatar, Provider, Brand, and Company. The 32/36/40 numeric sizes use the measured source text, icons, padding and radii; named sizes retain their existing defaults.',
462
+ 'SelectItem leading keeps the visual outside Radix ItemText. The trigger renders its selected visual explicitly, so a selection never duplicates the icon.',
463
+ 'Use Dropdown for searchable choices. Select keeps Radix keyboard typeahead; search inputs must not be nested in a Select listbox.',
464
+ ] },
299
465
  variants: [
300
- {
301
- id: 'default',
302
- title: 'default',
303
- render: () => (
304
- <div className="w-56">
305
- <Select defaultValue="pln">
306
- <SelectTrigger>
307
- <SelectValue placeholder="Choose currency" />
308
- </SelectTrigger>
309
- <SelectContent>
310
- <SelectItem value="eur">Euro (EUR)</SelectItem>
311
- <SelectItem value="pln">Polish Złoty (PLN)</SelectItem>
312
- <SelectItem value="usd">US Dollar (USD)</SelectItem>
313
- </SelectContent>
314
- </Select>
315
- </div>
316
- ),
317
- code: `import {
318
- Select,
319
- SelectContent,
320
- SelectItem,
321
- SelectTrigger,
322
- SelectValue,
323
- } from '@open-mercato/ui/primitives/select'
324
-
325
- <Select defaultValue="pln">
326
- <SelectTrigger>
327
- <SelectValue placeholder="Choose currency" />
328
- </SelectTrigger>
329
- <SelectContent>
330
- <SelectItem value="eur">Euro (EUR)</SelectItem>
331
- <SelectItem value="pln">Polish Złoty (PLN)</SelectItem>
332
- <SelectItem value="usd">US Dollar (USD)</SelectItem>
333
- </SelectContent>
334
- </Select>`,
335
- },
336
- {
337
- id: 'groups-leading',
338
- title: 'Groups + leading slot',
339
- render: () => (
340
- <div className="w-56">
341
- <Select>
342
- <SelectTrigger>
343
- <SelectTriggerLeading>
344
- <Globe />
345
- </SelectTriggerLeading>
346
- <SelectValue placeholder="Sales channel" />
347
- </SelectTrigger>
348
- <SelectContent>
349
- <SelectGroup>
350
- <SelectLabel>Online</SelectLabel>
351
- <SelectItem value="webstore">Webstore</SelectItem>
352
- <SelectItem value="marketplace">Marketplace</SelectItem>
353
- </SelectGroup>
354
- <SelectSeparator />
355
- <SelectGroup>
356
- <SelectLabel>Offline</SelectLabel>
357
- <SelectItem value="retail">Retail store</SelectItem>
358
- </SelectGroup>
359
- </SelectContent>
360
- </Select>
361
- </div>
362
- ),
363
- code: `import { Globe } from 'lucide-react'
364
- import {
365
- Select,
366
- SelectContent,
367
- SelectGroup,
368
- SelectItem,
369
- SelectLabel,
370
- SelectSeparator,
371
- SelectTrigger,
372
- SelectTriggerLeading,
373
- SelectValue,
374
- } from '@open-mercato/ui/primitives/select'
375
-
376
- <Select>
377
- <SelectTrigger>
378
- <SelectTriggerLeading><Globe /></SelectTriggerLeading>
379
- <SelectValue placeholder="Sales channel" />
380
- </SelectTrigger>
381
- <SelectContent>
382
- <SelectGroup>
383
- <SelectLabel>Online</SelectLabel>
384
- <SelectItem value="webstore">Webstore</SelectItem>
385
- <SelectItem value="marketplace">Marketplace</SelectItem>
386
- </SelectGroup>
387
- <SelectSeparator />
388
- <SelectGroup>
389
- <SelectLabel>Offline</SelectLabel>
390
- <SelectItem value="retail">Retail store</SelectItem>
391
- </SelectGroup>
392
- </SelectContent>
393
- </Select>`,
394
- },
395
- {
396
- id: 'sizes',
397
- title: 'Sizes',
398
- render: () => (
399
- <>
400
- {(['lg', 'default', 'sm', 'xs'] as const).map((size) => (
401
- <div key={size} className="w-40">
402
- <Select defaultValue="active">
403
- <SelectTrigger size={size}>
404
- <SelectValue />
405
- </SelectTrigger>
406
- <SelectContent>
407
- <SelectItem value="active">Active</SelectItem>
408
- <SelectItem value="archived">Archived</SelectItem>
409
- </SelectContent>
410
- </Select>
411
- </div>
412
- ))}
413
- </>
414
- ),
415
- code: `import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@open-mercato/ui/primitives/select'
416
-
417
- <SelectTrigger size="lg" />
418
- <SelectTrigger size="default" />
419
- <SelectTrigger size="sm" />
420
- <SelectTrigger size="xs" />`,
421
- },
422
- {
423
- id: 'states',
424
- title: 'States',
425
- render: () => (
426
- <>
427
- <div className="w-48">
428
- <Select>
429
- <SelectTrigger aria-invalid="true">
430
- <SelectValue placeholder="Required" />
431
- </SelectTrigger>
432
- <SelectContent>
433
- <SelectItem value="a">Option A</SelectItem>
434
- </SelectContent>
435
- </Select>
436
- </div>
437
- <div className="w-48">
438
- <Select>
439
- <SelectTrigger disabled>
440
- <SelectValue placeholder="Disabled" />
441
- </SelectTrigger>
442
- <SelectContent>
443
- <SelectItem value="a">Option A</SelectItem>
444
- </SelectContent>
445
- </Select>
446
- </div>
447
- </>
448
- ),
449
- code: `import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@open-mercato/ui/primitives/select'
466
+ { id: 'default', title: 'Basic / 36 px', render: () => <div className="w-72 max-w-full"><SelectSourceExample kind="basic" /></div>, code: selectFieldCode() },
467
+ { id: 'groups-leading', title: 'All six leading types / 36 px', render: () => <SelectSourceMatrix />, code: selectFieldCode({ leading: true }) },
468
+ { id: 'sizes', title: 'All types / 32 px', render: () => <SelectSourceMatrix size={32} />, code: selectFieldCode({ size: 32, leading: true }) },
469
+ { id: 'medium', title: 'All types / 40 px', render: () => <SelectSourceMatrix size={40} />, code: selectFieldCode({ size: 40, leading: true }) },
470
+ { id: 'placeholder', title: 'All types / placeholders', render: () => <SelectSourceMatrix state="default" />, code: selectFieldCode({ leading: true, initialValue: '' }) },
471
+ { id: 'states', title: 'All types / disabled', render: () => <SelectSourceMatrix state="disabled" />, code: selectFieldCode({ leading: true, selectProps: ' disabled', fieldProps: ' disabled' }) },
472
+ { id: 'errors', title: 'All types / errors', render: () => <SelectSourceMatrix state="error" />, code: selectFieldCode({ leading: true, initialValue: '', fieldProps: ' error="Choose an office"' }) },
473
+ ],
474
+ }
450
475
 
451
- <SelectTrigger aria-invalid="true"><SelectValue placeholder="Required" /></SelectTrigger>
452
- <SelectTrigger disabled><SelectValue placeholder="Disabled" /></SelectTrigger>`,
453
- },
476
+ const dropdownEntry: GalleryEntry = {
477
+ id: 'dropdown',
478
+ figmaNodeId: '379:6629',
479
+ title: 'Dropdown',
480
+ importPath: '@open-mercato/ui/primitives/dropdown',
481
+ descriptionKey: 'design_system.entries.dropdown.description',
482
+ usage: { do: [
483
+ 'A searchable, keyboard-operated picker built from Popover and cmdk. All six leading types use source assets and production components at 36 or 56 px.',
484
+ 'Search, clear, choose with arrows and Enter, or dismiss with Escape. The selected value and footer action update local example state.',
485
+ 'The saved checked state is separate from the active keyboard option. Footer buttons remain outside listbox options. Source Misc Items 414:8031 supplies search, action and caption layouts.',
486
+ ] },
487
+ variants: [
488
+ { id: 'small', title: 'All six types / 36 px', render: () => <DropdownSourceExample />, code: dropdownCode() },
489
+ { id: 'large', title: 'All six types / 56 px', render: () => <DropdownSourceExample size={56} />, code: dropdownCode({ size: 56 }) },
490
+ { id: 'empty', title: 'No results / clear to recover', render: () => <DropdownSourceExample empty />, code: dropdownCode({ initialQuery: 'zzzz' }) },
454
491
  ],
455
492
  }
456
493
 
@@ -462,20 +499,7 @@ const compactSelectEntry: GalleryEntry = {
462
499
  {
463
500
  id: 'trigger-label',
464
501
  title: 'With trigger label',
465
- render: () => (
466
- <div className="w-44">
467
- <Select defaultValue="newest">
468
- <CompactSelectTrigger triggerLabel="Sort:">
469
- <SelectValue />
470
- </CompactSelectTrigger>
471
- <SelectContent>
472
- <SelectItem value="newest">Newest</SelectItem>
473
- <SelectItem value="oldest">Oldest</SelectItem>
474
- <SelectItem value="value">Highest value</SelectItem>
475
- </SelectContent>
476
- </Select>
477
- </div>
478
- ),
502
+ render: () => <CompactSelectInputsTriggerLabelSample />,
479
503
  code: `import {
480
504
  CompactSelectTrigger,
481
505
  Select,
@@ -498,19 +522,7 @@ const compactSelectEntry: GalleryEntry = {
498
522
  {
499
523
  id: 'plain',
500
524
  title: 'Without label',
501
- render: () => (
502
- <div className="w-36">
503
- <Select defaultValue="table">
504
- <CompactSelectTrigger>
505
- <SelectValue />
506
- </CompactSelectTrigger>
507
- <SelectContent>
508
- <SelectItem value="table">Table</SelectItem>
509
- <SelectItem value="board">Board</SelectItem>
510
- </SelectContent>
511
- </Select>
512
- </div>
513
- ),
525
+ render: () => <CompactSelectInputsPlainSample />,
514
526
  code: `import {
515
527
  CompactSelectTrigger,
516
528
  Select,
@@ -540,20 +552,7 @@ const inlineSelectEntry: GalleryEntry = {
540
552
  {
541
553
  id: 'default',
542
554
  title: 'default (border on hover)',
543
- render: () => (
544
- <div className="w-40">
545
- <Select defaultValue="high">
546
- <InlineSelectTrigger>
547
- <SelectValue />
548
- </InlineSelectTrigger>
549
- <SelectContent>
550
- <SelectItem value="low">Low</SelectItem>
551
- <SelectItem value="medium">Medium</SelectItem>
552
- <SelectItem value="high">High</SelectItem>
553
- </SelectContent>
554
- </Select>
555
- </div>
556
- ),
555
+ render: () => <InlineSelectInputsDefaultSample />,
557
556
  code: `import {
558
557
  InlineSelectTrigger,
559
558
  Select,
@@ -576,19 +575,7 @@ const inlineSelectEntry: GalleryEntry = {
576
575
  {
577
576
  id: 'invisible',
578
577
  title: 'Invisible until focus',
579
- render: () => (
580
- <div className="w-40">
581
- <Select defaultValue="draft">
582
- <InlineSelectTrigger showBorderOnHover={false}>
583
- <SelectValue />
584
- </InlineSelectTrigger>
585
- <SelectContent>
586
- <SelectItem value="draft">Draft</SelectItem>
587
- <SelectItem value="published">Published</SelectItem>
588
- </SelectContent>
589
- </Select>
590
- </div>
591
- ),
578
+ render: () => <InlineSelectInputsInvisibleSample />,
592
579
  code: `import {
593
580
  InlineSelectTrigger,
594
581
  Select,
@@ -612,11 +599,7 @@ const inlineInputEntry: GalleryEntry = {
612
599
  {
613
600
  id: 'default',
614
601
  title: 'default (border on hover)',
615
- render: () => (
616
- <div className="w-56">
617
- <InlineInput defaultValue="Aurora desk lamp" aria-label="Product name" />
618
- </div>
619
- ),
602
+ render: () => <InlineInputInputsDefaultSample />,
620
603
  code: `import { InlineInput } from '@open-mercato/ui/primitives/inline-input'
621
604
 
622
605
  <InlineInput defaultValue="Aurora desk lamp" aria-label="Product name" onBlur={save} />`,
@@ -648,13 +631,7 @@ const checkboxEntry: GalleryEntry = {
648
631
  {
649
632
  id: 'states',
650
633
  title: 'States',
651
- render: () => (
652
- <>
653
- <Checkbox aria-label="Unchecked" />
654
- <Checkbox defaultChecked aria-label="Checked" />
655
- <Checkbox checked="indeterminate" aria-label="Indeterminate" />
656
- </>
657
- ),
634
+ render: () => <CheckboxInputsStatesSample />,
658
635
  code: `import { Checkbox } from '@open-mercato/ui/primitives/checkbox'
659
636
 
660
637
  <Checkbox />
@@ -664,12 +641,7 @@ const checkboxEntry: GalleryEntry = {
664
641
  {
665
642
  id: 'sizes',
666
643
  title: 'Sizes',
667
- render: () => (
668
- <>
669
- <Checkbox size="sm" defaultChecked aria-label="Small" />
670
- <Checkbox size="md" defaultChecked aria-label="Medium" />
671
- </>
672
- ),
644
+ render: () => <CheckboxInputsSizesSample />,
673
645
  code: `import { Checkbox } from '@open-mercato/ui/primitives/checkbox'
674
646
 
675
647
  <Checkbox size="sm" defaultChecked />
@@ -678,12 +650,7 @@ const checkboxEntry: GalleryEntry = {
678
650
  {
679
651
  id: 'disabled',
680
652
  title: 'Disabled',
681
- render: () => (
682
- <>
683
- <Checkbox disabled aria-label="Disabled" />
684
- <Checkbox disabled defaultChecked aria-label="Disabled checked" />
685
- </>
686
- ),
653
+ render: () => <CheckboxInputsDisabledSample />,
687
654
  code: `import { Checkbox } from '@open-mercato/ui/primitives/checkbox'
688
655
 
689
656
  <Checkbox disabled />
@@ -696,13 +663,12 @@ const checkboxFieldEntry: GalleryEntry = {
696
663
  id: 'checkbox-field',
697
664
  title: 'CheckboxField',
698
665
  importPath: '@open-mercato/ui/primitives/checkbox-field',
666
+ figmaNodeId: '231:4897',
699
667
  variants: [
700
668
  {
701
669
  id: 'default',
702
670
  title: 'default',
703
- render: () => (
704
- <CheckboxField label="Email notifications" defaultChecked />
705
- ),
671
+ render: () => <CheckboxFieldInputsDefaultSample />,
706
672
  code: `import { CheckboxField } from '@open-mercato/ui/primitives/checkbox-field'
707
673
 
708
674
  <CheckboxField label="Email notifications" defaultChecked />`,
@@ -710,15 +676,7 @@ const checkboxFieldEntry: GalleryEntry = {
710
676
  {
711
677
  id: 'with-description',
712
678
  title: 'With sublabel + description',
713
- render: () => (
714
- <div className="w-80">
715
- <CheckboxField
716
- label="Auto-archive"
717
- sublabel="(recommended)"
718
- description="Closed conversations move to the archive after 30 days."
719
- />
720
- </div>
721
- ),
679
+ render: () => <CheckboxFieldInputsWithDescriptionSample />,
722
680
  code: `import { CheckboxField } from '@open-mercato/ui/primitives/checkbox-field'
723
681
 
724
682
  <CheckboxField
@@ -730,57 +688,239 @@ const checkboxFieldEntry: GalleryEntry = {
730
688
  {
731
689
  id: 'flip',
732
690
  title: 'Flipped (checkbox right)',
733
- render: () => (
734
- <div className="w-72">
735
- <CheckboxField flip label="Include shipping costs" defaultChecked />
736
- </div>
737
- ),
691
+ render: () => <CheckboxFieldInputsFlipSample />,
738
692
  code: `import { CheckboxField } from '@open-mercato/ui/primitives/checkbox-field'
739
693
 
740
694
  <CheckboxField flip label="Include shipping costs" defaultChecked />`,
741
695
  },
742
- ],
743
- }
744
-
745
- const radioEntry: GalleryEntry = {
746
- id: 'radio',
747
- title: 'Radio',
748
- importPath: '@open-mercato/ui/primitives/radio',
749
- keywords: ['radiobutton', 'radio button', 'option group'],
750
- variants: [
751
696
  {
752
- id: 'group',
753
- title: 'RadioGroup',
754
- render: () => (
755
- <RadioGroup defaultValue="card" className="flex-row gap-3" aria-label="Payment method">
756
- <Radio value="card" aria-label="Card" />
757
- <Radio value="transfer" aria-label="Bank transfer" />
758
- <Radio value="cash" aria-label="Cash" />
759
- </RadioGroup>
760
- ),
761
- code: `import { Radio, RadioGroup } from '@open-mercato/ui/primitives/radio'
697
+ id: 'cards',
698
+ title: 'Card / default, selected and hover',
699
+ render: () => <SelectionCardsPreview control="checkbox" />,
700
+ code: `import { CheckboxField } from '@open-mercato/ui/primitives/checkbox-field'
701
+ import { Badge } from '@open-mercato/ui/primitives/badge'
702
+
703
+ const cardClassName = 'relative w-full max-w-90 gap-3.5 rounded-xl border border-border bg-background p-4 shadow-xs transition-colors hover:border-transparent hover:bg-muted hover:shadow-none has-[[data-state=checked]]:border-accent-indigo has-[[data-state=checked]]:shadow-none has-[:focus-visible]:shadow-focus has-[:disabled]:border-border has-[:disabled]:bg-background has-[:disabled]:shadow-none [&_label]:after:absolute [&_label]:after:inset-0 [&_label]:after:rounded-xl [&_button]:relative [&_button]:z-10'
704
+
705
+ <div className="grid w-full gap-4 sm:grid-cols-2">
706
+ <CheckboxField flip defaultChecked
707
+ label="Immediate updates"
708
+ sublabel="(Optional)"
709
+ description="Receive an update when an order changes."
710
+ badge={<Badge variant="info" size="sm">New</Badge>}
711
+ className="mt-0"
712
+ containerClassName={cardClassName}
713
+ />
714
+ <CheckboxField flip
715
+ label="Weekly summary"
716
+ sublabel="(Optional)"
717
+ description="Receive one summary every Monday."
718
+ badge={<Badge variant="info" size="sm">New</Badge>}
719
+ className="mt-0"
720
+ containerClassName={cardClassName}
721
+ />
722
+ </div>`,
723
+ },
724
+ {
725
+ id: 'cards-disabled',
726
+ title: 'Card / disabled',
727
+ render: () => <SelectionCardsPreview control="checkbox" disabled />,
728
+ code: `import { CheckboxField } from '@open-mercato/ui/primitives/checkbox-field'
729
+ import { Badge } from '@open-mercato/ui/primitives/badge'
730
+
731
+ const cardClassName = 'relative w-full max-w-90 gap-3.5 rounded-xl border border-border bg-background p-4 shadow-xs transition-colors hover:border-transparent hover:bg-muted hover:shadow-none has-[[data-state=checked]]:border-accent-indigo has-[[data-state=checked]]:shadow-none has-[:focus-visible]:shadow-focus has-[:disabled]:border-border has-[:disabled]:bg-background has-[:disabled]:shadow-none [&_label]:after:absolute [&_label]:after:inset-0 [&_label]:after:rounded-xl [&_button]:relative [&_button]:z-10'
732
+
733
+ <div className="grid w-full gap-4 sm:grid-cols-2">
734
+ <CheckboxField flip defaultChecked disabled
735
+ label="Immediate updates"
736
+ sublabel="(Optional)"
737
+ description="Receive an update when an order changes."
738
+ badge={<Badge variant="outline" size="sm" className="text-text-disabled">New</Badge>}
739
+ className="mt-0"
740
+ containerClassName={cardClassName}
741
+ />
742
+ <CheckboxField flip disabled
743
+ label="Weekly summary"
744
+ sublabel="(Optional)"
745
+ description="Receive one summary every Monday."
746
+ badge={<Badge variant="outline" size="sm" className="text-text-disabled">New</Badge>}
747
+ className="mt-0"
748
+ containerClassName={cardClassName}
749
+ />
750
+ </div>`,
751
+ },
752
+ {
753
+ id: 'source-cards-icon',
754
+ title: 'icon cards / default, active, disabled and live hover',
755
+ render: () => <SelectionSourceCardsDemo control="checkbox" kind="icon" />,
756
+ code: `import * as React from 'react'
757
+ import { cn } from '@open-mercato/shared/lib/utils'
758
+ import { CheckboxField } from '@open-mercato/ui/primitives/checkbox-field'
759
+ import { Badge } from '@open-mercato/ui/primitives/badge'
762
760
 
763
- <RadioGroup defaultValue="card" aria-label="Payment method">
764
- <Radio value="card" aria-label="Card" />
765
- <Radio value="transfer" aria-label="Bank transfer" />
766
- <Radio value="cash" aria-label="Cash" />
767
- </RadioGroup>`,
761
+ function SelectionCardExample({ imageUrl, disabled = false }: { imageUrl: string; disabled?: boolean }) {
762
+ const [checked, setChecked] = React.useState(false)
763
+ const label = 'Label'
764
+ return (
765
+
766
+ <div className={cn('relative flex w-90 max-w-full items-start gap-3.5 rounded-selection-card bg-background p-4 ring-1 ring-inset ring-border shadow-xs transition-colors hover:bg-muted hover:shadow-none has-[[data-state=checked]]:ring-accent-indigo has-[[data-state=checked]]:shadow-none has-[:focus-visible]:shadow-focus [&_label]:after:absolute [&_label]:after:inset-0 [&_label]:after:rounded-selection-card [&_button]:relative [&_button]:z-10', disabled && 'shadow-none hover:bg-background has-[[data-state=checked]]:ring-border')}>
767
+ <img src={imageUrl} alt="" className="size-10 shrink-0 object-contain" />
768
+ <CheckboxField flip checked={checked} onCheckedChange={value => setChecked(value === true)} disabled={disabled}
769
+ label={label}
770
+ sublabel="(Sublabel)"
771
+ description="Insert the checkbox description here."
772
+ badge={<Badge size={16} appearance={disabled ? 'stroke' : 'light'} tone={disabled ? 'neutral' : 'info'}>New</Badge>}
773
+ className="mt-0 disabled:opacity-100 disabled:data-[state=checked]:bg-bg-disabled disabled:data-[state=checked]:border-border-disabled disabled:data-[state=checked]:text-background" containerClassName="min-w-0 flex-1 gap-3.5"
774
+ />
775
+ </div>
776
+
777
+ )
778
+ }`,
768
779
  },
769
780
  {
770
- id: 'disabled',
771
- title: 'Disabled',
772
- render: () => (
773
- <RadioGroup defaultValue="a" disabled className="flex-row gap-3" aria-label="Disabled group">
774
- <Radio value="a" aria-label="Selected disabled" />
775
- <Radio value="b" aria-label="Unselected disabled" />
776
- </RadioGroup>
777
- ),
778
- code: `import { Radio, RadioGroup } from '@open-mercato/ui/primitives/radio'
781
+ id: 'source-cards-avatar',
782
+ title: 'avatar cards / default, active, disabled and live hover',
783
+ render: () => <SelectionSourceCardsDemo control="checkbox" kind="avatar" />,
784
+ code: `import * as React from 'react'
785
+ import { cn } from '@open-mercato/shared/lib/utils'
786
+ import { CheckboxField } from '@open-mercato/ui/primitives/checkbox-field'
787
+ import { Badge } from '@open-mercato/ui/primitives/badge'
788
+ import { Avatar } from '@open-mercato/ui/primitives/avatar'
779
789
 
780
- <RadioGroup defaultValue="a" disabled>
781
- <Radio value="a" />
782
- <Radio value="b" />
783
- </RadioGroup>`,
790
+ function SelectionCardExample({ imageUrl, disabled = false }: { imageUrl: string; disabled?: boolean }) {
791
+ const [checked, setChecked] = React.useState(false)
792
+ const label = 'Label'
793
+ return (
794
+
795
+ <div className={cn('relative flex w-90 max-w-full items-start gap-3.5 rounded-selection-card bg-background p-4 ring-1 ring-inset ring-border shadow-xs transition-colors hover:bg-muted hover:shadow-none has-[[data-state=checked]]:ring-accent-indigo has-[[data-state=checked]]:shadow-none has-[:focus-visible]:shadow-focus [&_label]:after:absolute [&_label]:after:inset-0 [&_label]:after:rounded-selection-card [&_button]:relative [&_button]:z-10', disabled && 'shadow-none hover:bg-background has-[[data-state=checked]]:ring-border')}>
796
+ <Avatar label={label} size={40} src={imageUrl} aria-hidden="true" />
797
+ <CheckboxField flip checked={checked} onCheckedChange={value => setChecked(value === true)} disabled={disabled}
798
+ label={label}
799
+ sublabel="(Sublabel)"
800
+ description="Insert the checkbox description here."
801
+ badge={<Badge size={16} appearance={disabled ? 'stroke' : 'light'} tone={disabled ? 'neutral' : 'info'}>New</Badge>}
802
+ className="mt-0 disabled:opacity-100 disabled:data-[state=checked]:bg-bg-disabled disabled:data-[state=checked]:border-border-disabled disabled:data-[state=checked]:text-background" containerClassName="min-w-0 flex-1 gap-3.5"
803
+ />
804
+ </div>
805
+
806
+ )
807
+ }`,
808
+ },
809
+ {
810
+ id: 'source-cards-provider',
811
+ title: 'provider cards / default, active, disabled and live hover',
812
+ render: () => <SelectionSourceCardsDemo control="checkbox" kind="provider" />,
813
+ code: `import * as React from 'react'
814
+ import { cn } from '@open-mercato/shared/lib/utils'
815
+ import { CheckboxField } from '@open-mercato/ui/primitives/checkbox-field'
816
+ import { Badge } from '@open-mercato/ui/primitives/badge'
817
+
818
+ function SelectionCardExample({ imageUrl, disabled = false }: { imageUrl: string; disabled?: boolean }) {
819
+ const [checked, setChecked] = React.useState(false)
820
+ const label = 'Label'
821
+ return (
822
+
823
+ <div className={cn('relative flex w-90 max-w-full items-start gap-3.5 rounded-selection-card bg-background p-4 ring-1 ring-inset ring-border shadow-xs transition-colors hover:bg-muted hover:shadow-none has-[[data-state=checked]]:ring-accent-indigo has-[[data-state=checked]]:shadow-none has-[:focus-visible]:shadow-focus [&_label]:after:absolute [&_label]:after:inset-0 [&_label]:after:rounded-selection-card [&_button]:relative [&_button]:z-10', disabled && 'shadow-none hover:bg-background has-[[data-state=checked]]:ring-border')}>
824
+ <img src={imageUrl} alt="" className="h-6 w-8 shrink-0 object-contain" />
825
+ <CheckboxField flip checked={checked} onCheckedChange={value => setChecked(value === true)} disabled={disabled}
826
+ label={label}
827
+ sublabel="(Sublabel)"
828
+ description="Insert the checkbox description here."
829
+ badge={<Badge size={16} appearance={disabled ? 'stroke' : 'light'} tone={disabled ? 'neutral' : 'info'}>New</Badge>}
830
+ className="mt-0 disabled:opacity-100 disabled:data-[state=checked]:bg-bg-disabled disabled:data-[state=checked]:border-border-disabled disabled:data-[state=checked]:text-background" containerClassName="min-w-0 flex-1 gap-3.5"
831
+ />
832
+ </div>
833
+
834
+ )
835
+ }`,
836
+ },
837
+ {
838
+ id: 'source-cards-brand',
839
+ title: 'brand cards / default, active, disabled and live hover',
840
+ render: () => <SelectionSourceCardsDemo control="checkbox" kind="brand" />,
841
+ code: `import * as React from 'react'
842
+ import { cn } from '@open-mercato/shared/lib/utils'
843
+ import { CheckboxField } from '@open-mercato/ui/primitives/checkbox-field'
844
+ import { Badge } from '@open-mercato/ui/primitives/badge'
845
+
846
+ function SelectionCardExample({ imageUrl, disabled = false }: { imageUrl: string; disabled?: boolean }) {
847
+ const [checked, setChecked] = React.useState(false)
848
+ const label = 'Label'
849
+ return (
850
+
851
+ <div className={cn('relative flex w-90 max-w-full items-start gap-3.5 rounded-selection-card bg-background p-4 ring-1 ring-inset ring-border shadow-xs transition-colors hover:bg-muted hover:shadow-none has-[[data-state=checked]]:ring-accent-indigo has-[[data-state=checked]]:shadow-none has-[:focus-visible]:shadow-focus [&_label]:after:absolute [&_label]:after:inset-0 [&_label]:after:rounded-selection-card [&_button]:relative [&_button]:z-10', disabled && 'shadow-none hover:bg-background has-[[data-state=checked]]:ring-border')}>
852
+ <img src={imageUrl} alt="" className="size-10 shrink-0 object-contain" />
853
+ <CheckboxField flip checked={checked} onCheckedChange={value => setChecked(value === true)} disabled={disabled}
854
+ label={label}
855
+ sublabel="(Sublabel)"
856
+ description="Insert the checkbox description here."
857
+ badge={<Badge size={16} appearance={disabled ? 'stroke' : 'light'} tone={disabled ? 'neutral' : 'info'}>New</Badge>}
858
+ className="mt-0 disabled:opacity-100 disabled:data-[state=checked]:bg-bg-disabled disabled:data-[state=checked]:border-border-disabled disabled:data-[state=checked]:text-background" containerClassName="min-w-0 flex-1 gap-3.5"
859
+ />
860
+ </div>
861
+
862
+ )
863
+ }`,
864
+ },
865
+ {
866
+ id: 'source-cards-company',
867
+ title: 'company cards / default, active, disabled and live hover',
868
+ render: () => <SelectionSourceCardsDemo control="checkbox" kind="company" />,
869
+ code: `import * as React from 'react'
870
+ import { cn } from '@open-mercato/shared/lib/utils'
871
+ import { CheckboxField } from '@open-mercato/ui/primitives/checkbox-field'
872
+ import { Badge } from '@open-mercato/ui/primitives/badge'
873
+
874
+ function SelectionCardExample({ imageUrl, disabled = false }: { imageUrl: string; disabled?: boolean }) {
875
+ const [checked, setChecked] = React.useState(false)
876
+ const label = 'Label'
877
+ return (
878
+
879
+ <div className={cn('relative flex w-90 max-w-full items-start gap-3.5 rounded-selection-card bg-background p-4 ring-1 ring-inset ring-border shadow-xs transition-colors hover:bg-muted hover:shadow-none has-[[data-state=checked]]:ring-accent-indigo has-[[data-state=checked]]:shadow-none has-[:focus-visible]:shadow-focus [&_label]:after:absolute [&_label]:after:inset-0 [&_label]:after:rounded-selection-card [&_button]:relative [&_button]:z-10', disabled && 'shadow-none hover:bg-background has-[[data-state=checked]]:ring-border')}>
880
+ <img src={imageUrl} alt="" className="size-10 shrink-0 object-contain" />
881
+ <CheckboxField flip checked={checked} onCheckedChange={value => setChecked(value === true)} disabled={disabled}
882
+ label={label}
883
+ sublabel="(Sublabel)"
884
+ description="Insert the checkbox description here."
885
+ badge={<Badge size={16} appearance={disabled ? 'stroke' : 'light'} tone={disabled ? 'neutral' : 'info'}>New</Badge>}
886
+ className="mt-0 disabled:opacity-100 disabled:data-[state=checked]:bg-bg-disabled disabled:data-[state=checked]:border-border-disabled disabled:data-[state=checked]:text-background" containerClassName="min-w-0 flex-1 gap-3.5"
887
+ />
888
+ </div>
889
+
890
+ )
891
+ }`,
892
+ },
893
+ ],
894
+ }
895
+
896
+ const radioEntry: GalleryEntry = {
897
+ id: 'radio',
898
+ title: 'Radio',
899
+ importPath: '@open-mercato/ui/primitives/radio',
900
+ keywords: ['radiobutton', 'radio button', 'option group'],
901
+ variants: [
902
+ {
903
+ id: 'group',
904
+ title: 'RadioGroup',
905
+ render: () => <RadioInputsGroupSample />,
906
+ code: `import { Radio, RadioGroup } from '@open-mercato/ui/primitives/radio'
907
+
908
+ <RadioGroup defaultValue="card" aria-label="Payment method">
909
+ <Radio value="card" aria-label="Card" />
910
+ <Radio value="transfer" aria-label="Bank transfer" />
911
+ <Radio value="cash" aria-label="Cash" />
912
+ </RadioGroup>`,
913
+ },
914
+ {
915
+ id: 'disabled',
916
+ title: 'Disabled',
917
+ render: () => <RadioInputsDisabledSample />,
918
+ code: `import { Radio, RadioGroup } from '@open-mercato/ui/primitives/radio'
919
+
920
+ <RadioGroup defaultValue="a" disabled>
921
+ <Radio value="a" />
922
+ <Radio value="b" />
923
+ </RadioGroup>`,
784
924
  },
785
925
  ],
786
926
  }
@@ -790,16 +930,24 @@ const radioFieldEntry: GalleryEntry = {
790
930
  id: 'radio-field',
791
931
  title: 'RadioField',
792
932
  importPath: '@open-mercato/ui/primitives/radio-field',
933
+ figmaNodeId: '515:4282',
793
934
  variants: [
935
+ {
936
+ id: 'flip',
937
+ title: 'Flipped (radio right)',
938
+ render: () => <FlippedRadioPreview />,
939
+ code: `import { RadioGroup } from '@open-mercato/ui/primitives/radio'
940
+ import { RadioField } from '@open-mercato/ui/primitives/radio-field'
941
+
942
+ <RadioGroup defaultValue="immediate" aria-label="Notification preferences" className="w-72">
943
+ <RadioField value="immediate" flip label="Immediate updates" />
944
+ <RadioField value="weekly" flip label="Weekly summary" />
945
+ </RadioGroup>`,
946
+ },
794
947
  {
795
948
  id: 'default',
796
949
  title: 'default',
797
- render: () => (
798
- <RadioGroup defaultValue="standard" aria-label="Shipping speed">
799
- <RadioField value="standard" label="Standard" />
800
- <RadioField value="express" label="Express" />
801
- </RadioGroup>
802
- ),
950
+ render: () => <RadioFieldInputsDefaultSample />,
803
951
  code: `import { RadioGroup } from '@open-mercato/ui/primitives/radio'
804
952
  import { RadioField } from '@open-mercato/ui/primitives/radio-field'
805
953
 
@@ -811,22 +959,7 @@ import { RadioField } from '@open-mercato/ui/primitives/radio-field'
811
959
  {
812
960
  id: 'with-description',
813
961
  title: 'With description',
814
- render: () => (
815
- <div className="w-80">
816
- <RadioGroup defaultValue="invoice" aria-label="Billing">
817
- <RadioField
818
- value="invoice"
819
- label="Invoice"
820
- description="Pay within 14 days of delivery."
821
- />
822
- <RadioField
823
- value="prepaid"
824
- label="Prepaid"
825
- description="Order ships after payment clears."
826
- />
827
- </RadioGroup>
828
- </div>
829
- ),
962
+ render: () => <RadioFieldInputsWithDescriptionSample />,
830
963
  code: `import { RadioGroup } from '@open-mercato/ui/primitives/radio'
831
964
  import { RadioField } from '@open-mercato/ui/primitives/radio-field'
832
965
 
@@ -835,6 +968,210 @@ import { RadioField } from '@open-mercato/ui/primitives/radio-field'
835
968
  <RadioField value="prepaid" label="Prepaid" description="Order ships after payment clears." />
836
969
  </RadioGroup>`,
837
970
  },
971
+ {
972
+ id: 'cards',
973
+ title: 'Card / default, selected and hover',
974
+ render: () => <SelectionCardsPreview control="radio" />,
975
+ code: `import { RadioField } from '@open-mercato/ui/primitives/radio-field'
976
+ import { RadioGroup } from '@open-mercato/ui/primitives/radio'
977
+ import { Badge } from '@open-mercato/ui/primitives/badge'
978
+
979
+ const cardClassName = 'relative w-full max-w-90 gap-3.5 rounded-xl border border-border bg-background p-4 shadow-xs transition-colors hover:border-transparent hover:bg-muted hover:shadow-none has-[[data-state=checked]]:border-accent-indigo has-[[data-state=checked]]:shadow-none has-[:focus-visible]:shadow-focus has-[:disabled]:border-border has-[:disabled]:bg-background has-[:disabled]:shadow-none [&_label]:after:absolute [&_label]:after:inset-0 [&_label]:after:rounded-xl [&_button]:relative [&_button]:z-10'
980
+
981
+ <RadioGroup defaultValue="immediate" aria-label="Notification preferences" className="grid w-full gap-4 sm:grid-cols-2">
982
+ <RadioField flip value="immediate"
983
+ label="Immediate updates"
984
+ sublabel="(Optional)"
985
+ description="Receive an update when an order changes."
986
+ badge={<Badge variant="info" size="sm">New</Badge>}
987
+ className="mt-0"
988
+ containerClassName={cardClassName}
989
+ />
990
+ <RadioField flip value="weekly"
991
+ label="Weekly summary"
992
+ sublabel="(Optional)"
993
+ description="Receive one summary every Monday."
994
+ badge={<Badge variant="info" size="sm">New</Badge>}
995
+ className="mt-0"
996
+ containerClassName={cardClassName}
997
+ />
998
+ </RadioGroup>`,
999
+ },
1000
+ {
1001
+ id: 'cards-disabled',
1002
+ title: 'Card / disabled',
1003
+ render: () => <SelectionCardsPreview control="radio" disabled />,
1004
+ code: `import { RadioField } from '@open-mercato/ui/primitives/radio-field'
1005
+ import { RadioGroup } from '@open-mercato/ui/primitives/radio'
1006
+ import { Badge } from '@open-mercato/ui/primitives/badge'
1007
+
1008
+ const cardClassName = 'relative w-full max-w-90 gap-3.5 rounded-xl border border-border bg-background p-4 shadow-xs transition-colors hover:border-transparent hover:bg-muted hover:shadow-none has-[[data-state=checked]]:border-accent-indigo has-[[data-state=checked]]:shadow-none has-[:focus-visible]:shadow-focus has-[:disabled]:border-border has-[:disabled]:bg-background has-[:disabled]:shadow-none [&_label]:after:absolute [&_label]:after:inset-0 [&_label]:after:rounded-xl [&_button]:relative [&_button]:z-10'
1009
+
1010
+ <RadioGroup defaultValue="immediate" aria-label="Notification preferences" className="grid w-full gap-4 sm:grid-cols-2">
1011
+ <RadioField flip value="immediate" disabled
1012
+ label="Immediate updates"
1013
+ sublabel="(Optional)"
1014
+ description="Receive an update when an order changes."
1015
+ badge={<Badge variant="outline" size="sm" className="text-text-disabled">New</Badge>}
1016
+ className="mt-0"
1017
+ containerClassName={cardClassName}
1018
+ />
1019
+ <RadioField flip value="weekly" disabled
1020
+ label="Weekly summary"
1021
+ sublabel="(Optional)"
1022
+ description="Receive one summary every Monday."
1023
+ badge={<Badge variant="outline" size="sm" className="text-text-disabled">New</Badge>}
1024
+ className="mt-0"
1025
+ containerClassName={cardClassName}
1026
+ />
1027
+ </RadioGroup>`,
1028
+ },
1029
+ {
1030
+ id: 'source-cards-icon',
1031
+ title: 'icon cards / default, active, disabled and live hover',
1032
+ render: () => <SelectionSourceCardsDemo control="radio" kind="icon" />,
1033
+ code: `import * as React from 'react'
1034
+ import { cn } from '@open-mercato/shared/lib/utils'
1035
+ import { RadioField } from '@open-mercato/ui/primitives/radio-field'
1036
+ import { Badge } from '@open-mercato/ui/primitives/badge'
1037
+ import { RadioGroup } from '@open-mercato/ui/primitives/radio'
1038
+
1039
+ function SelectionCardExample({ imageUrl, disabled = false }: { imageUrl: string; disabled?: boolean }) {
1040
+ const [value, setValue] = React.useState('selected')
1041
+ const label = 'Label'
1042
+ return (
1043
+ <RadioGroup value={value} onValueChange={setValue} aria-label={label}>
1044
+ <div className={cn('relative flex w-90 max-w-full items-start gap-3.5 rounded-selection-card bg-background p-4 ring-1 ring-inset ring-border shadow-xs transition-colors hover:bg-muted hover:shadow-none has-[[data-state=checked]]:ring-accent-indigo has-[[data-state=checked]]:shadow-none has-[:focus-visible]:shadow-focus [&_label]:after:absolute [&_label]:after:inset-0 [&_label]:after:rounded-selection-card [&_button]:relative [&_button]:z-10', disabled && 'shadow-none hover:bg-background has-[[data-state=checked]]:ring-border')}>
1045
+ <img src={imageUrl} alt="" className="size-10 shrink-0 object-contain" />
1046
+ <RadioField value="selected" flip disabled={disabled}
1047
+ label={label}
1048
+ sublabel="(Sublabel)"
1049
+ description="Insert the checkbox description here."
1050
+ badge={<Badge size={16} appearance={disabled ? 'stroke' : 'light'} tone={disabled ? 'neutral' : 'info'}>New</Badge>}
1051
+ className="mt-0 disabled:opacity-100 disabled:data-[state=checked]:bg-bg-disabled disabled:data-[state=checked]:border-border-disabled disabled:data-[state=checked]:text-background" containerClassName="min-w-0 flex-1 gap-3.5"
1052
+ />
1053
+ </div>
1054
+ </RadioGroup>
1055
+ )
1056
+ }`,
1057
+ },
1058
+ {
1059
+ id: 'source-cards-avatar',
1060
+ title: 'avatar cards / default, active, disabled and live hover',
1061
+ render: () => <SelectionSourceCardsDemo control="radio" kind="avatar" />,
1062
+ code: `import * as React from 'react'
1063
+ import { cn } from '@open-mercato/shared/lib/utils'
1064
+ import { RadioField } from '@open-mercato/ui/primitives/radio-field'
1065
+ import { Badge } from '@open-mercato/ui/primitives/badge'
1066
+ import { RadioGroup } from '@open-mercato/ui/primitives/radio'
1067
+ import { Avatar } from '@open-mercato/ui/primitives/avatar'
1068
+
1069
+ function SelectionCardExample({ imageUrl, disabled = false }: { imageUrl: string; disabled?: boolean }) {
1070
+ const [value, setValue] = React.useState('selected')
1071
+ const label = 'Label'
1072
+ return (
1073
+ <RadioGroup value={value} onValueChange={setValue} aria-label={label}>
1074
+ <div className={cn('relative flex w-90 max-w-full items-start gap-3.5 rounded-selection-card bg-background p-4 ring-1 ring-inset ring-border shadow-xs transition-colors hover:bg-muted hover:shadow-none has-[[data-state=checked]]:ring-accent-indigo has-[[data-state=checked]]:shadow-none has-[:focus-visible]:shadow-focus [&_label]:after:absolute [&_label]:after:inset-0 [&_label]:after:rounded-selection-card [&_button]:relative [&_button]:z-10', disabled && 'shadow-none hover:bg-background has-[[data-state=checked]]:ring-border')}>
1075
+ <Avatar label={label} size={40} src={imageUrl} aria-hidden="true" />
1076
+ <RadioField value="selected" flip disabled={disabled}
1077
+ label={label}
1078
+ sublabel="(Sublabel)"
1079
+ description="Insert the checkbox description here."
1080
+ badge={<Badge size={16} appearance={disabled ? 'stroke' : 'light'} tone={disabled ? 'neutral' : 'info'}>New</Badge>}
1081
+ className="mt-0 disabled:opacity-100 disabled:data-[state=checked]:bg-bg-disabled disabled:data-[state=checked]:border-border-disabled disabled:data-[state=checked]:text-background" containerClassName="min-w-0 flex-1 gap-3.5"
1082
+ />
1083
+ </div>
1084
+ </RadioGroup>
1085
+ )
1086
+ }`,
1087
+ },
1088
+ {
1089
+ id: 'source-cards-provider',
1090
+ title: 'provider cards / default, active, disabled and live hover',
1091
+ render: () => <SelectionSourceCardsDemo control="radio" kind="provider" />,
1092
+ code: `import * as React from 'react'
1093
+ import { cn } from '@open-mercato/shared/lib/utils'
1094
+ import { RadioField } from '@open-mercato/ui/primitives/radio-field'
1095
+ import { Badge } from '@open-mercato/ui/primitives/badge'
1096
+ import { RadioGroup } from '@open-mercato/ui/primitives/radio'
1097
+
1098
+ function SelectionCardExample({ imageUrl, disabled = false }: { imageUrl: string; disabled?: boolean }) {
1099
+ const [value, setValue] = React.useState('selected')
1100
+ const label = 'Label'
1101
+ return (
1102
+ <RadioGroup value={value} onValueChange={setValue} aria-label={label}>
1103
+ <div className={cn('relative flex w-90 max-w-full items-start gap-3.5 rounded-selection-card bg-background p-4 ring-1 ring-inset ring-border shadow-xs transition-colors hover:bg-muted hover:shadow-none has-[[data-state=checked]]:ring-accent-indigo has-[[data-state=checked]]:shadow-none has-[:focus-visible]:shadow-focus [&_label]:after:absolute [&_label]:after:inset-0 [&_label]:after:rounded-selection-card [&_button]:relative [&_button]:z-10', disabled && 'shadow-none hover:bg-background has-[[data-state=checked]]:ring-border')}>
1104
+ <img src={imageUrl} alt="" className="h-6 w-8 shrink-0 object-contain" />
1105
+ <RadioField value="selected" flip disabled={disabled}
1106
+ label={label}
1107
+ sublabel="(Sublabel)"
1108
+ description="Insert the checkbox description here."
1109
+ badge={<Badge size={16} appearance={disabled ? 'stroke' : 'light'} tone={disabled ? 'neutral' : 'info'}>New</Badge>}
1110
+ className="mt-0 disabled:opacity-100 disabled:data-[state=checked]:bg-bg-disabled disabled:data-[state=checked]:border-border-disabled disabled:data-[state=checked]:text-background" containerClassName="min-w-0 flex-1 gap-3.5"
1111
+ />
1112
+ </div>
1113
+ </RadioGroup>
1114
+ )
1115
+ }`,
1116
+ },
1117
+ {
1118
+ id: 'source-cards-brand',
1119
+ title: 'brand cards / default, active, disabled and live hover',
1120
+ render: () => <SelectionSourceCardsDemo control="radio" kind="brand" />,
1121
+ code: `import * as React from 'react'
1122
+ import { cn } from '@open-mercato/shared/lib/utils'
1123
+ import { RadioField } from '@open-mercato/ui/primitives/radio-field'
1124
+ import { Badge } from '@open-mercato/ui/primitives/badge'
1125
+ import { RadioGroup } from '@open-mercato/ui/primitives/radio'
1126
+
1127
+ function SelectionCardExample({ imageUrl, disabled = false }: { imageUrl: string; disabled?: boolean }) {
1128
+ const [value, setValue] = React.useState('selected')
1129
+ const label = 'Label'
1130
+ return (
1131
+ <RadioGroup value={value} onValueChange={setValue} aria-label={label}>
1132
+ <div className={cn('relative flex w-90 max-w-full items-start gap-3.5 rounded-selection-card bg-background p-4 ring-1 ring-inset ring-border shadow-xs transition-colors hover:bg-muted hover:shadow-none has-[[data-state=checked]]:ring-accent-indigo has-[[data-state=checked]]:shadow-none has-[:focus-visible]:shadow-focus [&_label]:after:absolute [&_label]:after:inset-0 [&_label]:after:rounded-selection-card [&_button]:relative [&_button]:z-10', disabled && 'shadow-none hover:bg-background has-[[data-state=checked]]:ring-border')}>
1133
+ <img src={imageUrl} alt="" className="size-10 shrink-0 object-contain" />
1134
+ <RadioField value="selected" flip disabled={disabled}
1135
+ label={label}
1136
+ sublabel="(Sublabel)"
1137
+ description="Insert the checkbox description here."
1138
+ badge={<Badge size={16} appearance={disabled ? 'stroke' : 'light'} tone={disabled ? 'neutral' : 'info'}>New</Badge>}
1139
+ className="mt-0 disabled:opacity-100 disabled:data-[state=checked]:bg-bg-disabled disabled:data-[state=checked]:border-border-disabled disabled:data-[state=checked]:text-background" containerClassName="min-w-0 flex-1 gap-3.5"
1140
+ />
1141
+ </div>
1142
+ </RadioGroup>
1143
+ )
1144
+ }`,
1145
+ },
1146
+ {
1147
+ id: 'source-cards-company',
1148
+ title: 'company cards / default, active, disabled and live hover',
1149
+ render: () => <SelectionSourceCardsDemo control="radio" kind="company" />,
1150
+ code: `import * as React from 'react'
1151
+ import { cn } from '@open-mercato/shared/lib/utils'
1152
+ import { RadioField } from '@open-mercato/ui/primitives/radio-field'
1153
+ import { Badge } from '@open-mercato/ui/primitives/badge'
1154
+ import { RadioGroup } from '@open-mercato/ui/primitives/radio'
1155
+
1156
+ function SelectionCardExample({ imageUrl, disabled = false }: { imageUrl: string; disabled?: boolean }) {
1157
+ const [value, setValue] = React.useState('selected')
1158
+ const label = 'Label'
1159
+ return (
1160
+ <RadioGroup value={value} onValueChange={setValue} aria-label={label}>
1161
+ <div className={cn('relative flex w-90 max-w-full items-start gap-3.5 rounded-selection-card bg-background p-4 ring-1 ring-inset ring-border shadow-xs transition-colors hover:bg-muted hover:shadow-none has-[[data-state=checked]]:ring-accent-indigo has-[[data-state=checked]]:shadow-none has-[:focus-visible]:shadow-focus [&_label]:after:absolute [&_label]:after:inset-0 [&_label]:after:rounded-selection-card [&_button]:relative [&_button]:z-10', disabled && 'shadow-none hover:bg-background has-[[data-state=checked]]:ring-border')}>
1162
+ <img src={imageUrl} alt="" className="size-10 shrink-0 object-contain" />
1163
+ <RadioField value="selected" flip disabled={disabled}
1164
+ label={label}
1165
+ sublabel="(Sublabel)"
1166
+ description="Insert the checkbox description here."
1167
+ badge={<Badge size={16} appearance={disabled ? 'stroke' : 'light'} tone={disabled ? 'neutral' : 'info'}>New</Badge>}
1168
+ className="mt-0 disabled:opacity-100 disabled:data-[state=checked]:bg-bg-disabled disabled:data-[state=checked]:border-border-disabled disabled:data-[state=checked]:text-background" containerClassName="min-w-0 flex-1 gap-3.5"
1169
+ />
1170
+ </div>
1171
+ </RadioGroup>
1172
+ )
1173
+ }`,
1174
+ },
838
1175
  ],
839
1176
  }
840
1177
 
@@ -846,12 +1183,7 @@ const switchEntry: GalleryEntry = {
846
1183
  {
847
1184
  id: 'states',
848
1185
  title: 'States',
849
- render: () => (
850
- <>
851
- <Switch aria-label="Off" />
852
- <Switch defaultChecked aria-label="On" />
853
- </>
854
- ),
1186
+ render: () => <SwitchInputsStatesSample />,
855
1187
  code: `import { Switch } from '@open-mercato/ui/primitives/switch'
856
1188
 
857
1189
  <Switch />
@@ -860,12 +1192,7 @@ const switchEntry: GalleryEntry = {
860
1192
  {
861
1193
  id: 'disabled',
862
1194
  title: 'Disabled',
863
- render: () => (
864
- <>
865
- <Switch disabled aria-label="Disabled off" />
866
- <Switch disabled defaultChecked aria-label="Disabled on" />
867
- </>
868
- ),
1195
+ render: () => <SwitchInputsDisabledSample />,
869
1196
  code: `import { Switch } from '@open-mercato/ui/primitives/switch'
870
1197
 
871
1198
  <Switch disabled />
@@ -878,15 +1205,12 @@ const switchFieldEntry: GalleryEntry = {
878
1205
  id: 'switch-field',
879
1206
  title: 'SwitchField',
880
1207
  importPath: '@open-mercato/ui/primitives/switch-field',
1208
+ figmaNodeId: '385:4580',
881
1209
  variants: [
882
1210
  {
883
1211
  id: 'default',
884
1212
  title: 'default (switch right)',
885
- render: () => (
886
- <div className="w-72">
887
- <SwitchField label="Two-factor authentication" defaultChecked />
888
- </div>
889
- ),
1213
+ render: () => <SwitchFieldInputsDefaultSample />,
890
1214
  code: `import { SwitchField } from '@open-mercato/ui/primitives/switch-field'
891
1215
 
892
1216
  <SwitchField label="Two-factor authentication" defaultChecked />`,
@@ -894,14 +1218,7 @@ const switchFieldEntry: GalleryEntry = {
894
1218
  {
895
1219
  id: 'with-description',
896
1220
  title: 'With description',
897
- render: () => (
898
- <div className="w-80">
899
- <SwitchField
900
- label="Low-stock alerts"
901
- description="Notify purchasing when stock drops below the reorder point."
902
- />
903
- </div>
904
- ),
1221
+ render: () => <SwitchFieldInputsWithDescriptionSample />,
905
1222
  code: `import { SwitchField } from '@open-mercato/ui/primitives/switch-field'
906
1223
 
907
1224
  <SwitchField
@@ -912,31 +1229,420 @@ const switchFieldEntry: GalleryEntry = {
912
1229
  {
913
1230
  id: 'flip',
914
1231
  title: 'Flipped (switch left)',
915
- render: () => (
916
- <div className="w-72">
917
- <SwitchField flip label="Sync inventory nightly" defaultChecked />
918
- </div>
919
- ),
1232
+ render: () => <SwitchFieldInputsFlipSample />,
920
1233
  code: `import { SwitchField } from '@open-mercato/ui/primitives/switch-field'
921
1234
 
922
1235
  <SwitchField flip label="Sync inventory nightly" defaultChecked />`,
923
1236
  },
1237
+ {
1238
+ id: 'cards',
1239
+ title: 'Card / default, selected and hover',
1240
+ render: () => <SelectionCardsPreview control="switch" />,
1241
+ code: `import { SwitchField } from '@open-mercato/ui/primitives/switch-field'
1242
+ import { Badge } from '@open-mercato/ui/primitives/badge'
1243
+
1244
+ const cardClassName = 'relative w-full max-w-90 gap-3.5 rounded-xl border border-border bg-background p-4 shadow-xs transition-colors hover:border-transparent hover:bg-muted hover:shadow-none has-[[data-state=checked]]:border-accent-indigo has-[[data-state=checked]]:shadow-none has-[:focus-visible]:shadow-focus has-[:disabled]:border-border has-[:disabled]:bg-background has-[:disabled]:shadow-none [&_label]:after:absolute [&_label]:after:inset-0 [&_label]:after:rounded-xl [&_button]:relative [&_button]:z-10'
1245
+
1246
+ <div className="grid w-full gap-4 sm:grid-cols-2">
1247
+ <SwitchField defaultChecked
1248
+ label="Immediate updates"
1249
+ sublabel="(Optional)"
1250
+ description="Receive an update when an order changes."
1251
+ badge={<Badge variant="info" size="sm">New</Badge>}
1252
+ className="mt-0"
1253
+ containerClassName={cardClassName}
1254
+ />
1255
+ <SwitchField
1256
+ label="Weekly summary"
1257
+ sublabel="(Optional)"
1258
+ description="Receive one summary every Monday."
1259
+ badge={<Badge variant="info" size="sm">New</Badge>}
1260
+ className="mt-0"
1261
+ containerClassName={cardClassName}
1262
+ />
1263
+ </div>`,
1264
+ },
1265
+ {
1266
+ id: 'cards-disabled',
1267
+ title: 'Card / disabled',
1268
+ render: () => <SelectionCardsPreview control="switch" disabled />,
1269
+ code: `import { SwitchField } from '@open-mercato/ui/primitives/switch-field'
1270
+ import { Badge } from '@open-mercato/ui/primitives/badge'
1271
+
1272
+ const cardClassName = 'relative w-full max-w-90 gap-3.5 rounded-xl border border-border bg-background p-4 shadow-xs transition-colors hover:border-transparent hover:bg-muted hover:shadow-none has-[[data-state=checked]]:border-accent-indigo has-[[data-state=checked]]:shadow-none has-[:focus-visible]:shadow-focus has-[:disabled]:border-border has-[:disabled]:bg-background has-[:disabled]:shadow-none [&_label]:after:absolute [&_label]:after:inset-0 [&_label]:after:rounded-xl [&_button]:relative [&_button]:z-10'
1273
+
1274
+ <div className="grid w-full gap-4 sm:grid-cols-2">
1275
+ <SwitchField defaultChecked disabled
1276
+ label="Immediate updates"
1277
+ sublabel="(Optional)"
1278
+ description="Receive an update when an order changes."
1279
+ badge={<Badge variant="outline" size="sm" className="text-text-disabled">New</Badge>}
1280
+ className="mt-0"
1281
+ containerClassName={cardClassName}
1282
+ />
1283
+ <SwitchField disabled
1284
+ label="Weekly summary"
1285
+ sublabel="(Optional)"
1286
+ description="Receive one summary every Monday."
1287
+ badge={<Badge variant="outline" size="sm" className="text-text-disabled">New</Badge>}
1288
+ className="mt-0"
1289
+ containerClassName={cardClassName}
1290
+ />
1291
+ </div>`,
1292
+ },
1293
+ {
1294
+ id: 'source-cards-icon',
1295
+ title: 'icon cards / default, active, disabled and live hover',
1296
+ render: () => <SelectionSourceCardsDemo control="switch" kind="icon" />,
1297
+ code: `import * as React from 'react'
1298
+ import { cn } from '@open-mercato/shared/lib/utils'
1299
+ import { SwitchField } from '@open-mercato/ui/primitives/switch-field'
1300
+ import { Badge } from '@open-mercato/ui/primitives/badge'
1301
+
1302
+ function SelectionCardExample({ imageUrl, disabled = false }: { imageUrl: string; disabled?: boolean }) {
1303
+ const [checked, setChecked] = React.useState(false)
1304
+ const label = 'Label'
1305
+ return (
1306
+
1307
+ <div className={cn('relative flex w-90 max-w-full items-start gap-3.5 rounded-selection-card bg-background p-4 ring-1 ring-inset ring-border shadow-xs transition-colors hover:bg-muted hover:shadow-none has-[[data-state=checked]]:ring-accent-indigo has-[[data-state=checked]]:shadow-none has-[:focus-visible]:shadow-focus [&_label]:after:absolute [&_label]:after:inset-0 [&_label]:after:rounded-selection-card [&_button]:relative [&_button]:z-10', disabled && 'shadow-none hover:bg-background has-[[data-state=checked]]:ring-border')}>
1308
+ <img src={imageUrl} alt="" className="size-10 shrink-0 object-contain" />
1309
+ <SwitchField checked={checked} onCheckedChange={setChecked} disabled={disabled}
1310
+ label={label}
1311
+ sublabel="(Sublabel)"
1312
+ description="Insert the checkbox description here."
1313
+ badge={<Badge size={16} appearance={disabled ? 'stroke' : 'light'} tone={disabled ? 'neutral' : 'info'}>New</Badge>}
1314
+ className="mt-0" containerClassName="min-w-0 flex-1 gap-3.5"
1315
+ />
1316
+ </div>
1317
+
1318
+ )
1319
+ }`,
1320
+ },
1321
+ {
1322
+ id: 'source-cards-avatar',
1323
+ title: 'avatar cards / default, active, disabled and live hover',
1324
+ render: () => <SelectionSourceCardsDemo control="switch" kind="avatar" />,
1325
+ code: `import * as React from 'react'
1326
+ import { cn } from '@open-mercato/shared/lib/utils'
1327
+ import { SwitchField } from '@open-mercato/ui/primitives/switch-field'
1328
+ import { Badge } from '@open-mercato/ui/primitives/badge'
1329
+ import { Avatar } from '@open-mercato/ui/primitives/avatar'
1330
+
1331
+ function SelectionCardExample({ imageUrl, disabled = false }: { imageUrl: string; disabled?: boolean }) {
1332
+ const [checked, setChecked] = React.useState(false)
1333
+ const label = 'Label'
1334
+ return (
1335
+
1336
+ <div className={cn('relative flex w-90 max-w-full items-start gap-3.5 rounded-selection-card bg-background p-4 ring-1 ring-inset ring-border shadow-xs transition-colors hover:bg-muted hover:shadow-none has-[[data-state=checked]]:ring-accent-indigo has-[[data-state=checked]]:shadow-none has-[:focus-visible]:shadow-focus [&_label]:after:absolute [&_label]:after:inset-0 [&_label]:after:rounded-selection-card [&_button]:relative [&_button]:z-10', disabled && 'shadow-none hover:bg-background has-[[data-state=checked]]:ring-border')}>
1337
+ <Avatar label={label} size={40} src={imageUrl} aria-hidden="true" />
1338
+ <SwitchField checked={checked} onCheckedChange={setChecked} disabled={disabled}
1339
+ label={label}
1340
+ sublabel="(Sublabel)"
1341
+ description="Insert the checkbox description here."
1342
+ badge={<Badge size={16} appearance={disabled ? 'stroke' : 'light'} tone={disabled ? 'neutral' : 'info'}>New</Badge>}
1343
+ className="mt-0" containerClassName="min-w-0 flex-1 gap-3.5"
1344
+ />
1345
+ </div>
1346
+
1347
+ )
1348
+ }`,
1349
+ },
1350
+ {
1351
+ id: 'source-cards-provider',
1352
+ title: 'provider cards / default, active, disabled and live hover',
1353
+ render: () => <SelectionSourceCardsDemo control="switch" kind="provider" />,
1354
+ code: `import * as React from 'react'
1355
+ import { cn } from '@open-mercato/shared/lib/utils'
1356
+ import { SwitchField } from '@open-mercato/ui/primitives/switch-field'
1357
+ import { Badge } from '@open-mercato/ui/primitives/badge'
1358
+
1359
+ function SelectionCardExample({ imageUrl, disabled = false }: { imageUrl: string; disabled?: boolean }) {
1360
+ const [checked, setChecked] = React.useState(false)
1361
+ const label = 'Label'
1362
+ return (
1363
+
1364
+ <div className={cn('relative flex w-90 max-w-full items-start gap-3.5 rounded-selection-card bg-background p-4 ring-1 ring-inset ring-border shadow-xs transition-colors hover:bg-muted hover:shadow-none has-[[data-state=checked]]:ring-accent-indigo has-[[data-state=checked]]:shadow-none has-[:focus-visible]:shadow-focus [&_label]:after:absolute [&_label]:after:inset-0 [&_label]:after:rounded-selection-card [&_button]:relative [&_button]:z-10', disabled && 'shadow-none hover:bg-background has-[[data-state=checked]]:ring-border')}>
1365
+ <img src={imageUrl} alt="" className="h-6 w-8 shrink-0 object-contain" />
1366
+ <SwitchField checked={checked} onCheckedChange={setChecked} disabled={disabled}
1367
+ label={label}
1368
+ sublabel="(Sublabel)"
1369
+ description="Insert the checkbox description here."
1370
+ badge={<Badge size={16} appearance={disabled ? 'stroke' : 'light'} tone={disabled ? 'neutral' : 'info'}>New</Badge>}
1371
+ className="mt-0" containerClassName="min-w-0 flex-1 gap-3.5"
1372
+ />
1373
+ </div>
1374
+
1375
+ )
1376
+ }`,
1377
+ },
1378
+ {
1379
+ id: 'source-cards-brand',
1380
+ title: 'brand cards / default, active, disabled and live hover',
1381
+ render: () => <SelectionSourceCardsDemo control="switch" kind="brand" />,
1382
+ code: `import * as React from 'react'
1383
+ import { cn } from '@open-mercato/shared/lib/utils'
1384
+ import { SwitchField } from '@open-mercato/ui/primitives/switch-field'
1385
+ import { Badge } from '@open-mercato/ui/primitives/badge'
1386
+
1387
+ function SelectionCardExample({ imageUrl, disabled = false }: { imageUrl: string; disabled?: boolean }) {
1388
+ const [checked, setChecked] = React.useState(false)
1389
+ const label = 'Label'
1390
+ return (
1391
+
1392
+ <div className={cn('relative flex w-90 max-w-full items-start gap-3.5 rounded-selection-card bg-background p-4 ring-1 ring-inset ring-border shadow-xs transition-colors hover:bg-muted hover:shadow-none has-[[data-state=checked]]:ring-accent-indigo has-[[data-state=checked]]:shadow-none has-[:focus-visible]:shadow-focus [&_label]:after:absolute [&_label]:after:inset-0 [&_label]:after:rounded-selection-card [&_button]:relative [&_button]:z-10', disabled && 'shadow-none hover:bg-background has-[[data-state=checked]]:ring-border')}>
1393
+ <img src={imageUrl} alt="" className="size-10 shrink-0 object-contain" />
1394
+ <SwitchField checked={checked} onCheckedChange={setChecked} disabled={disabled}
1395
+ label={label}
1396
+ sublabel="(Sublabel)"
1397
+ description="Insert the checkbox description here."
1398
+ badge={<Badge size={16} appearance={disabled ? 'stroke' : 'light'} tone={disabled ? 'neutral' : 'info'}>New</Badge>}
1399
+ className="mt-0" containerClassName="min-w-0 flex-1 gap-3.5"
1400
+ />
1401
+ </div>
1402
+
1403
+ )
1404
+ }`,
1405
+ },
1406
+ {
1407
+ id: 'source-cards-company',
1408
+ title: 'company cards / default, active, disabled and live hover',
1409
+ render: () => <SelectionSourceCardsDemo control="switch" kind="company" />,
1410
+ code: `import * as React from 'react'
1411
+ import { cn } from '@open-mercato/shared/lib/utils'
1412
+ import { SwitchField } from '@open-mercato/ui/primitives/switch-field'
1413
+ import { Badge } from '@open-mercato/ui/primitives/badge'
1414
+
1415
+ function SelectionCardExample({ imageUrl, disabled = false }: { imageUrl: string; disabled?: boolean }) {
1416
+ const [checked, setChecked] = React.useState(false)
1417
+ const label = 'Label'
1418
+ return (
1419
+
1420
+ <div className={cn('relative flex w-90 max-w-full items-start gap-3.5 rounded-selection-card bg-background p-4 ring-1 ring-inset ring-border shadow-xs transition-colors hover:bg-muted hover:shadow-none has-[[data-state=checked]]:ring-accent-indigo has-[[data-state=checked]]:shadow-none has-[:focus-visible]:shadow-focus [&_label]:after:absolute [&_label]:after:inset-0 [&_label]:after:rounded-selection-card [&_button]:relative [&_button]:z-10', disabled && 'shadow-none hover:bg-background has-[[data-state=checked]]:ring-border')}>
1421
+ <img src={imageUrl} alt="" className="size-10 shrink-0 object-contain" />
1422
+ <SwitchField checked={checked} onCheckedChange={setChecked} disabled={disabled}
1423
+ label={label}
1424
+ sublabel="(Sublabel)"
1425
+ description="Insert the checkbox description here."
1426
+ badge={<Badge size={16} appearance={disabled ? 'stroke' : 'light'} tone={disabled ? 'neutral' : 'info'}>New</Badge>}
1427
+ className="mt-0" containerClassName="min-w-0 flex-1 gap-3.5"
1428
+ />
1429
+ </div>
1430
+
1431
+ )
1432
+ }`,
1433
+ },
1434
+ {
1435
+ id: 'integration-horizontal-card',
1436
+ title: 'Integration / horizontal / card',
1437
+ render: () => <IntegrationSwitchDemo alignment="horizontal" appearance="card" />,
1438
+ code: `import * as React from 'react'
1439
+ import { Settings } from 'lucide-react'
1440
+ import { cn } from '@open-mercato/shared/lib/utils'
1441
+ import { useT } from '@open-mercato/shared/lib/i18n/context'
1442
+ import { SwitchField } from '@open-mercato/ui/primitives/switch-field'
1443
+ import { Switch } from '@open-mercato/ui/primitives/switch'
1444
+ import { Badge } from '@open-mercato/ui/primitives/badge'
1445
+ import { Button } from '@open-mercato/ui/primitives/button'
1446
+ import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from '@open-mercato/ui/primitives/dialog'
1447
+
1448
+ function IntegrationExample({ brandUrl, alignment, appearance }: { brandUrl: string; alignment: 'horizontal' | 'vertical'; appearance: 'card' | 'list' }) {
1449
+ const t = useT()
1450
+ const id = React.useId()
1451
+ const [checked, setChecked] = React.useState(false)
1452
+ const [open, setOpen] = React.useState(false)
1453
+ const horizontal = alignment === 'horizontal'
1454
+ const card = appearance === 'card'
1455
+ return (
1456
+ <Dialog open={open} onOpenChange={setOpen}>
1457
+ <div data-slot="integration-switch" data-alignment={alignment} data-appearance={appearance} className={cn('relative flex max-w-full gap-3.5', horizontal ? 'w-154 flex-wrap items-center sm:flex-nowrap' : 'w-95 flex-col items-start', card && 'rounded-selection-card bg-background p-4 ring-1 ring-inset ring-border shadow-xs')}>
1458
+ <img src={brandUrl} alt="" className={cn('shrink-0', card ? 'size-10' : 'size-12')} />
1459
+ <div className={cn('flex min-w-0 flex-col gap-1', horizontal && 'min-w-40 flex-1')}>
1460
+ <div className="flex flex-wrap items-center gap-1.5">
1461
+ <span id={id} className={cn('font-medium text-foreground', card ? 'text-sm leading-5' : 'text-base leading-6')}>Microsoft Office 365</span>
1462
+ <Badge size={16} appearance="light" tone="info">New</Badge>
1463
+ </div>
1464
+ <p className={cn('text-muted-foreground', card ? 'text-xs leading-4' : 'text-sm leading-5')}>Seamless collaboration and document management.</p>
1465
+ </div>
1466
+ <Button asChild variant="outline" size="default" className={horizontal ? undefined : 'w-full'}><DialogTrigger><Settings aria-hidden="true" />Manage</DialogTrigger></Button>
1467
+ <Switch aria-labelledby={id} checked={checked} onCheckedChange={setChecked} className={horizontal ? undefined : card ? 'absolute top-5 right-5' : 'absolute top-3 right-3'} />
1468
+ </div>
1469
+ <DialogContent onKeyDownCapture={event => { if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) { event.preventDefault(); setOpen(false) } }}>
1470
+ <DialogHeader><DialogTitle>Microsoft Office 365 settings</DialogTitle><DialogDescription>Seamless collaboration and document management.</DialogDescription></DialogHeader>
1471
+ <SwitchField label="Enable integration" checked={checked} onCheckedChange={setChecked} />
1472
+ <DialogFooter><Button variant="outline" onClick={() => setOpen(false)}>{t('common.close')}</Button></DialogFooter>
1473
+ </DialogContent>
1474
+ </Dialog>
1475
+ )
1476
+ }
1477
+
1478
+ <IntegrationExample brandUrl={brandUrl} alignment="horizontal" appearance="card" />`,
1479
+ },
1480
+ {
1481
+ id: 'integration-horizontal-list',
1482
+ title: 'Integration / horizontal / list',
1483
+ render: () => <IntegrationSwitchDemo alignment="horizontal" appearance="list" />,
1484
+ code: `import * as React from 'react'
1485
+ import { Settings } from 'lucide-react'
1486
+ import { cn } from '@open-mercato/shared/lib/utils'
1487
+ import { useT } from '@open-mercato/shared/lib/i18n/context'
1488
+ import { SwitchField } from '@open-mercato/ui/primitives/switch-field'
1489
+ import { Switch } from '@open-mercato/ui/primitives/switch'
1490
+ import { Badge } from '@open-mercato/ui/primitives/badge'
1491
+ import { Button } from '@open-mercato/ui/primitives/button'
1492
+ import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from '@open-mercato/ui/primitives/dialog'
1493
+
1494
+ function IntegrationExample({ brandUrl, alignment, appearance }: { brandUrl: string; alignment: 'horizontal' | 'vertical'; appearance: 'card' | 'list' }) {
1495
+ const t = useT()
1496
+ const id = React.useId()
1497
+ const [checked, setChecked] = React.useState(false)
1498
+ const [open, setOpen] = React.useState(false)
1499
+ const horizontal = alignment === 'horizontal'
1500
+ const card = appearance === 'card'
1501
+ return (
1502
+ <Dialog open={open} onOpenChange={setOpen}>
1503
+ <div data-slot="integration-switch" data-alignment={alignment} data-appearance={appearance} className={cn('relative flex max-w-full gap-3.5', horizontal ? 'w-154 flex-wrap items-center sm:flex-nowrap' : 'w-95 flex-col items-start', card && 'rounded-selection-card bg-background p-4 ring-1 ring-inset ring-border shadow-xs')}>
1504
+ <img src={brandUrl} alt="" className={cn('shrink-0', card ? 'size-10' : 'size-12')} />
1505
+ <div className={cn('flex min-w-0 flex-col gap-1', horizontal && 'min-w-40 flex-1')}>
1506
+ <div className="flex flex-wrap items-center gap-1.5">
1507
+ <span id={id} className={cn('font-medium text-foreground', card ? 'text-sm leading-5' : 'text-base leading-6')}>Microsoft Office 365</span>
1508
+ <Badge size={16} appearance="light" tone="info">New</Badge>
1509
+ </div>
1510
+ <p className={cn('text-muted-foreground', card ? 'text-xs leading-4' : 'text-sm leading-5')}>Seamless collaboration and document management.</p>
1511
+ </div>
1512
+ <Button asChild variant="outline" size="default" className={horizontal ? undefined : 'w-full'}><DialogTrigger><Settings aria-hidden="true" />Manage</DialogTrigger></Button>
1513
+ <Switch aria-labelledby={id} checked={checked} onCheckedChange={setChecked} className={horizontal ? undefined : card ? 'absolute top-5 right-5' : 'absolute top-3 right-3'} />
1514
+ </div>
1515
+ <DialogContent onKeyDownCapture={event => { if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) { event.preventDefault(); setOpen(false) } }}>
1516
+ <DialogHeader><DialogTitle>Microsoft Office 365 settings</DialogTitle><DialogDescription>Seamless collaboration and document management.</DialogDescription></DialogHeader>
1517
+ <SwitchField label="Enable integration" checked={checked} onCheckedChange={setChecked} />
1518
+ <DialogFooter><Button variant="outline" onClick={() => setOpen(false)}>{t('common.close')}</Button></DialogFooter>
1519
+ </DialogContent>
1520
+ </Dialog>
1521
+ )
1522
+ }
1523
+
1524
+ <IntegrationExample brandUrl={brandUrl} alignment="horizontal" appearance="list" />`,
1525
+ },
1526
+ {
1527
+ id: 'integration-vertical-card',
1528
+ title: 'Integration / vertical / card',
1529
+ render: () => <IntegrationSwitchDemo alignment="vertical" appearance="card" />,
1530
+ code: `import * as React from 'react'
1531
+ import { Settings } from 'lucide-react'
1532
+ import { cn } from '@open-mercato/shared/lib/utils'
1533
+ import { useT } from '@open-mercato/shared/lib/i18n/context'
1534
+ import { SwitchField } from '@open-mercato/ui/primitives/switch-field'
1535
+ import { Switch } from '@open-mercato/ui/primitives/switch'
1536
+ import { Badge } from '@open-mercato/ui/primitives/badge'
1537
+ import { Button } from '@open-mercato/ui/primitives/button'
1538
+ import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from '@open-mercato/ui/primitives/dialog'
1539
+
1540
+ function IntegrationExample({ brandUrl, alignment, appearance }: { brandUrl: string; alignment: 'horizontal' | 'vertical'; appearance: 'card' | 'list' }) {
1541
+ const t = useT()
1542
+ const id = React.useId()
1543
+ const [checked, setChecked] = React.useState(false)
1544
+ const [open, setOpen] = React.useState(false)
1545
+ const horizontal = alignment === 'horizontal'
1546
+ const card = appearance === 'card'
1547
+ return (
1548
+ <Dialog open={open} onOpenChange={setOpen}>
1549
+ <div data-slot="integration-switch" data-alignment={alignment} data-appearance={appearance} className={cn('relative flex max-w-full gap-3.5', horizontal ? 'w-154 flex-wrap items-center sm:flex-nowrap' : 'w-95 flex-col items-start', card && 'rounded-selection-card bg-background p-4 ring-1 ring-inset ring-border shadow-xs')}>
1550
+ <img src={brandUrl} alt="" className={cn('shrink-0', card ? 'size-10' : 'size-12')} />
1551
+ <div className={cn('flex min-w-0 flex-col gap-1', horizontal && 'min-w-40 flex-1')}>
1552
+ <div className="flex flex-wrap items-center gap-1.5">
1553
+ <span id={id} className={cn('font-medium text-foreground', card ? 'text-sm leading-5' : 'text-base leading-6')}>Microsoft Office 365</span>
1554
+ <Badge size={16} appearance="light" tone="info">New</Badge>
1555
+ </div>
1556
+ <p className={cn('text-muted-foreground', card ? 'text-xs leading-4' : 'text-sm leading-5')}>Seamless collaboration and document management.</p>
1557
+ </div>
1558
+ <Button asChild variant="outline" size="default" className={horizontal ? undefined : 'w-full'}><DialogTrigger><Settings aria-hidden="true" />Manage</DialogTrigger></Button>
1559
+ <Switch aria-labelledby={id} checked={checked} onCheckedChange={setChecked} className={horizontal ? undefined : card ? 'absolute top-5 right-5' : 'absolute top-3 right-3'} />
1560
+ </div>
1561
+ <DialogContent onKeyDownCapture={event => { if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) { event.preventDefault(); setOpen(false) } }}>
1562
+ <DialogHeader><DialogTitle>Microsoft Office 365 settings</DialogTitle><DialogDescription>Seamless collaboration and document management.</DialogDescription></DialogHeader>
1563
+ <SwitchField label="Enable integration" checked={checked} onCheckedChange={setChecked} />
1564
+ <DialogFooter><Button variant="outline" onClick={() => setOpen(false)}>{t('common.close')}</Button></DialogFooter>
1565
+ </DialogContent>
1566
+ </Dialog>
1567
+ )
1568
+ }
1569
+
1570
+ <IntegrationExample brandUrl={brandUrl} alignment="vertical" appearance="card" />`,
1571
+ },
1572
+ {
1573
+ id: 'integration-vertical-list',
1574
+ title: 'Integration / vertical / list',
1575
+ render: () => <IntegrationSwitchDemo alignment="vertical" appearance="list" />,
1576
+ code: `import * as React from 'react'
1577
+ import { Settings } from 'lucide-react'
1578
+ import { cn } from '@open-mercato/shared/lib/utils'
1579
+ import { useT } from '@open-mercato/shared/lib/i18n/context'
1580
+ import { SwitchField } from '@open-mercato/ui/primitives/switch-field'
1581
+ import { Switch } from '@open-mercato/ui/primitives/switch'
1582
+ import { Badge } from '@open-mercato/ui/primitives/badge'
1583
+ import { Button } from '@open-mercato/ui/primitives/button'
1584
+ import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from '@open-mercato/ui/primitives/dialog'
1585
+
1586
+ function IntegrationExample({ brandUrl, alignment, appearance }: { brandUrl: string; alignment: 'horizontal' | 'vertical'; appearance: 'card' | 'list' }) {
1587
+ const t = useT()
1588
+ const id = React.useId()
1589
+ const [checked, setChecked] = React.useState(false)
1590
+ const [open, setOpen] = React.useState(false)
1591
+ const horizontal = alignment === 'horizontal'
1592
+ const card = appearance === 'card'
1593
+ return (
1594
+ <Dialog open={open} onOpenChange={setOpen}>
1595
+ <div data-slot="integration-switch" data-alignment={alignment} data-appearance={appearance} className={cn('relative flex max-w-full gap-3.5', horizontal ? 'w-154 flex-wrap items-center sm:flex-nowrap' : 'w-95 flex-col items-start', card && 'rounded-selection-card bg-background p-4 ring-1 ring-inset ring-border shadow-xs')}>
1596
+ <img src={brandUrl} alt="" className={cn('shrink-0', card ? 'size-10' : 'size-12')} />
1597
+ <div className={cn('flex min-w-0 flex-col gap-1', horizontal && 'min-w-40 flex-1')}>
1598
+ <div className="flex flex-wrap items-center gap-1.5">
1599
+ <span id={id} className={cn('font-medium text-foreground', card ? 'text-sm leading-5' : 'text-base leading-6')}>Microsoft Office 365</span>
1600
+ <Badge size={16} appearance="light" tone="info">New</Badge>
1601
+ </div>
1602
+ <p className={cn('text-muted-foreground', card ? 'text-xs leading-4' : 'text-sm leading-5')}>Seamless collaboration and document management.</p>
1603
+ </div>
1604
+ <Button asChild variant="outline" size="default" className={horizontal ? undefined : 'w-full'}><DialogTrigger><Settings aria-hidden="true" />Manage</DialogTrigger></Button>
1605
+ <Switch aria-labelledby={id} checked={checked} onCheckedChange={setChecked} className={horizontal ? undefined : card ? 'absolute top-5 right-5' : 'absolute top-3 right-3'} />
1606
+ </div>
1607
+ <DialogContent onKeyDownCapture={event => { if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) { event.preventDefault(); setOpen(false) } }}>
1608
+ <DialogHeader><DialogTitle>Microsoft Office 365 settings</DialogTitle><DialogDescription>Seamless collaboration and document management.</DialogDescription></DialogHeader>
1609
+ <SwitchField label="Enable integration" checked={checked} onCheckedChange={setChecked} />
1610
+ <DialogFooter><Button variant="outline" onClick={() => setOpen(false)}>{t('common.close')}</Button></DialogFooter>
1611
+ </DialogContent>
1612
+ </Dialog>
1613
+ )
1614
+ }
1615
+
1616
+ <IntegrationExample brandUrl={brandUrl} alignment="vertical" appearance="list" />`,
1617
+ },
924
1618
  ],
925
1619
  }
926
1620
 
1621
+ function SliderValueDemo({ initialValues }: { initialValues: number[] }) {
1622
+ const t = useT()
1623
+ const id = React.useId()
1624
+ const [values, setValues] = React.useState(initialValues)
1625
+ const range = values.length === 2
1626
+ return <div className="flex w-72 max-w-full flex-col gap-1">
1627
+ <div className="flex items-center justify-between gap-2 text-xs">
1628
+ <span id={id}>{t(range ? 'design_system.gallery.examples.controls.range' : 'design_system.gallery.examples.controls.value')}</span>
1629
+ <output className="text-muted-foreground">{values.join(' – ')}</output>
1630
+ </div>
1631
+ <Slider value={values} onValueChange={setValues} min={0} max={100} className="h-4" aria-labelledby={id}
1632
+ thumbLabels={range ? [t('design_system.gallery.examples.controls.lower'), t('design_system.gallery.examples.controls.upper')] : undefined} />
1633
+ </div>
1634
+ }
1635
+
927
1636
  const sliderEntry: GalleryEntry = {
928
1637
  id: 'slider',
1638
+ figmaNodeId: '2617:1169',
929
1639
  title: 'Slider',
930
1640
  importPath: '@open-mercato/ui/primitives/slider',
931
1641
  variants: [
932
1642
  {
933
1643
  id: 'single',
934
1644
  title: 'Single value',
935
- render: () => (
936
- <div className="w-72">
937
- <Slider defaultValue={[40]} min={0} max={100} step={5} aria-label="Discount" />
938
- </div>
939
- ),
1645
+ render: () => <SliderInputsSingleSample />,
940
1646
  code: `import { Slider } from '@open-mercato/ui/primitives/slider'
941
1647
 
942
1648
  <Slider defaultValue={[40]} min={0} max={100} step={5} aria-label="Discount" />`,
@@ -944,11 +1650,7 @@ const sliderEntry: GalleryEntry = {
944
1650
  {
945
1651
  id: 'range',
946
1652
  title: 'Range (two thumbs)',
947
- render: () => (
948
- <div className="w-72">
949
- <Slider defaultValue={[20, 60]} min={0} max={100} aria-label="Price range" />
950
- </div>
951
- ),
1653
+ render: () => <SliderInputsRangeSample />,
952
1654
  code: `import { Slider } from '@open-mercato/ui/primitives/slider'
953
1655
 
954
1656
  <Slider defaultValue={[20, 60]} min={0} max={100} aria-label="Price range" />`,
@@ -956,16 +1658,58 @@ const sliderEntry: GalleryEntry = {
956
1658
  {
957
1659
  id: 'disabled',
958
1660
  title: 'Disabled',
959
- render: () => (
960
- <div className="w-72">
961
- <Slider defaultValue={[45]} disabled aria-label="Disabled slider" />
962
- </div>
963
- ),
1661
+ render: () => <SliderInputsDisabledSample />,
964
1662
  code: `import { Slider } from '@open-mercato/ui/primitives/slider'
965
1663
 
966
1664
  <Slider defaultValue={[45]} disabled />`,
967
1665
  },
968
- ],
1666
+ {
1667
+ id: 'source-values',
1668
+ title: 'Source values · 0 / 25 / 50 / 75 / 100',
1669
+ render: () => <div className="flex w-full flex-wrap gap-6">{[0, 25, 50, 75, 100].map(value => <SliderValueDemo key={value} initialValues={[value]} />)}</div>,
1670
+ code: `import * as React from 'react'
1671
+ import { Slider } from '@open-mercato/ui/primitives/slider'
1672
+
1673
+ function SliderValueDemo({ initialValues }: { initialValues: number[] }) {
1674
+ const id = React.useId()
1675
+ const [values, setValues] = React.useState(initialValues)
1676
+ const range = values.length === 2
1677
+ return <div className="flex w-72 max-w-full flex-col gap-1">
1678
+ <div className="flex items-center justify-between gap-2 text-xs">
1679
+ <span id={id}>{range ? 'Range' : 'Value'}</span>
1680
+ <output className="text-muted-foreground">{values.join(' – ')}</output>
1681
+ </div>
1682
+ <Slider value={values} onValueChange={setValues} min={0} max={100} className="h-4" aria-labelledby={id}
1683
+ thumbLabels={range ? ['Lower value', 'Upper value'] : undefined} />
1684
+ </div>
1685
+ }
1686
+
1687
+ <div className="flex w-full flex-wrap gap-6">{[0, 25, 50, 75, 100].map(value => <SliderValueDemo key={value} initialValues={[value]} />)}</div>`,
1688
+ },
1689
+ {
1690
+ id: 'source-ranges',
1691
+ title: 'Source ranges · 11 pairs',
1692
+ render: () => <div className="flex w-full flex-wrap gap-6">{[[0, 0], [0, 25], [25, 50], [50, 75], [75, 100], [0, 50], [25, 75], [50, 100], [0, 75], [25, 100], [0, 100]].map(values => <SliderValueDemo key={values.join("-")} initialValues={values} />)}</div>,
1693
+ code: `import * as React from 'react'
1694
+ import { Slider } from '@open-mercato/ui/primitives/slider'
1695
+
1696
+ function SliderValueDemo({ initialValues }: { initialValues: number[] }) {
1697
+ const id = React.useId()
1698
+ const [values, setValues] = React.useState(initialValues)
1699
+ const range = values.length === 2
1700
+ return <div className="flex w-72 max-w-full flex-col gap-1">
1701
+ <div className="flex items-center justify-between gap-2 text-xs">
1702
+ <span id={id}>{range ? 'Range' : 'Value'}</span>
1703
+ <output className="text-muted-foreground">{values.join(' – ')}</output>
1704
+ </div>
1705
+ <Slider value={values} onValueChange={setValues} min={0} max={100} className="h-4" aria-labelledby={id}
1706
+ thumbLabels={range ? ['Lower value', 'Upper value'] : undefined} />
1707
+ </div>
1708
+ }
1709
+
1710
+ <div className="flex w-full flex-wrap gap-6">{[[0, 0], [0, 25], [25, 50], [50, 75], [75, 100], [0, 50], [25, 75], [50, 100], [0, 75], [25, 100], [0, 100]].map(values => <SliderValueDemo key={values.join("-")} initialValues={values} />)}</div>`,
1711
+ },
1712
+ ],
969
1713
  }
970
1714
 
971
1715
  const formFieldEntry: GalleryEntry = {
@@ -976,13 +1720,7 @@ const formFieldEntry: GalleryEntry = {
976
1720
  {
977
1721
  id: 'default',
978
1722
  title: 'Label + description',
979
- render: () => (
980
- <div className="w-72">
981
- <FormField label="Warehouse code" description="Short identifier used on labels.">
982
- <Input placeholder="WAW-01" />
983
- </FormField>
984
- </div>
985
- ),
1723
+ render: () => <FormFieldInputsDefaultSample />,
986
1724
  code: `import { FormField } from '@open-mercato/ui/primitives/form-field'
987
1725
  import { Input } from '@open-mercato/ui/primitives/input'
988
1726
 
@@ -993,13 +1731,7 @@ import { Input } from '@open-mercato/ui/primitives/input'
993
1731
  {
994
1732
  id: 'required',
995
1733
  title: 'Required',
996
- render: () => (
997
- <div className="w-72">
998
- <FormField label="Company name" required>
999
- <Input placeholder="Acme sp. z o.o." />
1000
- </FormField>
1001
- </div>
1002
- ),
1734
+ render: () => <FormFieldInputsRequiredSample />,
1003
1735
  code: `import { FormField } from '@open-mercato/ui/primitives/form-field'
1004
1736
  import { Input } from '@open-mercato/ui/primitives/input'
1005
1737
 
@@ -1010,13 +1742,7 @@ import { Input } from '@open-mercato/ui/primitives/input'
1010
1742
  {
1011
1743
  id: 'error',
1012
1744
  title: 'Error',
1013
- render: () => (
1014
- <div className="w-72">
1015
- <FormField label="VAT ID" error="VAT ID must have 10 digits.">
1016
- <Input defaultValue="52601" />
1017
- </FormField>
1018
- </div>
1019
- ),
1745
+ render: () => <FormFieldInputsErrorSample />,
1020
1746
  code: `import { FormField } from '@open-mercato/ui/primitives/form-field'
1021
1747
  import { Input } from '@open-mercato/ui/primitives/input'
1022
1748
 
@@ -1027,13 +1753,7 @@ import { Input } from '@open-mercato/ui/primitives/input'
1027
1753
  {
1028
1754
  id: 'horizontal',
1029
1755
  title: 'Horizontal',
1030
- render: () => (
1031
- <div className="w-72">
1032
- <FormField label="Enable webhooks" orientation="horizontal">
1033
- <Switch defaultChecked />
1034
- </FormField>
1035
- </div>
1036
- ),
1756
+ render: () => <FormFieldInputsHorizontalSample />,
1037
1757
  code: `import { FormField } from '@open-mercato/ui/primitives/form-field'
1038
1758
  import { Switch } from '@open-mercato/ui/primitives/switch'
1039
1759
 
@@ -1067,6 +1787,19 @@ const [query, setQuery] = React.useState('')
1067
1787
 
1068
1788
  <SearchInput size="sm" value={query} onChange={setQuery} />`,
1069
1789
  },
1790
+ {
1791
+ id: 'disabled',
1792
+ title: 'Disabled (clear action hidden)',
1793
+ render: () => <DisabledSearchInputPreview />,
1794
+ code: `import { SearchInput } from '@open-mercato/ui/primitives/search-input'
1795
+ import { FormField } from '@open-mercato/ui/primitives/form-field'
1796
+
1797
+ const [query, setQuery] = React.useState('OM-2026-0042')
1798
+
1799
+ <FormField label="Search orders" disabled>
1800
+ <SearchInput value={query} onChange={setQuery} />
1801
+ </FormField>`,
1802
+ },
1070
1803
  ],
1071
1804
  }
1072
1805
 
@@ -1114,6 +1847,109 @@ const emailInputEntry: GalleryEntry = {
1114
1847
  ],
1115
1848
  }
1116
1849
 
1850
+ function PasswordStrengthDemo({ initialValue = '', interactive = false }: { initialValue?: string; interactive?: boolean }) {
1851
+ const t = useT()
1852
+ const [password, setPassword] = React.useState(initialValue)
1853
+ const requirements = [
1854
+ { id: 'uppercase', label: t('design_system.gallery.samples.passwordStrength.uppercase'), met: /[A-Z]/.test(password) },
1855
+ { id: 'number', label: t('design_system.gallery.samples.passwordStrength.number'), met: /[0-9]/.test(password) },
1856
+ { id: 'length', label: t('design_system.gallery.samples.passwordStrength.length'), met: password.length >= 8 },
1857
+ ]
1858
+ const met = requirements.filter(requirement => requirement.met).length
1859
+ const strength = password.length === 0 ? 'empty' : met === 3 ? 'strong' : met === 2 ? 'moderate' : 'weak'
1860
+ return (
1861
+ <div className="w-75 max-w-full">
1862
+ {interactive ? <PasswordInput value={password} onChange={event => setPassword(event.target.value)} aria-label={t('design_system.gallery.samples.passwordStrength.password')} /> : null}
1863
+ <PasswordStrength strength={strength} requirements={requirements} />
1864
+ </div>
1865
+ )
1866
+ }
1867
+
1868
+ const passwordStrengthEntry: GalleryEntry = {
1869
+ id: 'password-strength',
1870
+ title: 'PasswordStrength',
1871
+ importPath: '@open-mercato/ui/primitives/password-strength',
1872
+ figmaNodeId: '327:8202',
1873
+ usage: {
1874
+ do: ['Supply the evaluated strength and requirements from the policy that owns the form.', 'The interactive example demonstrates the three rules shown in Figma; the visual primitive does not define authentication policy.'],
1875
+ },
1876
+ variants: [
1877
+ {
1878
+ id: 'empty',
1879
+ title: 'empty',
1880
+ render: () => <PasswordStrengthDemo initialValue="" />,
1881
+ code: `import { PasswordStrength } from '@open-mercato/ui/primitives/password-strength'
1882
+
1883
+
1884
+ <PasswordStrength strength="empty" requirements={[
1885
+ { id: 'uppercase', label: 'At least 1 uppercase', met: false },
1886
+ { id: 'number', label: 'At least 1 number', met: false },
1887
+ { id: 'length', label: 'At least 8 characters', met: false },
1888
+ ]} />`,
1889
+ },
1890
+ {
1891
+ id: 'weak',
1892
+ title: 'weak',
1893
+ render: () => <PasswordStrengthDemo initialValue="A" />,
1894
+ code: `import { PasswordStrength } from '@open-mercato/ui/primitives/password-strength'
1895
+
1896
+
1897
+ <PasswordStrength strength="weak" requirements={[
1898
+ { id: 'uppercase', label: 'At least 1 uppercase', met: true },
1899
+ { id: 'number', label: 'At least 1 number', met: false },
1900
+ { id: 'length', label: 'At least 8 characters', met: false },
1901
+ ]} />`,
1902
+ },
1903
+ {
1904
+ id: 'moderate',
1905
+ title: 'moderate',
1906
+ render: () => <PasswordStrengthDemo initialValue="A1" />,
1907
+ code: `import { PasswordStrength } from '@open-mercato/ui/primitives/password-strength'
1908
+
1909
+
1910
+ <PasswordStrength strength="moderate" requirements={[
1911
+ { id: 'uppercase', label: 'At least 1 uppercase', met: true },
1912
+ { id: 'number', label: 'At least 1 number', met: true },
1913
+ { id: 'length', label: 'At least 8 characters', met: false },
1914
+ ]} />`,
1915
+ },
1916
+ {
1917
+ id: 'strong',
1918
+ title: 'strong',
1919
+ render: () => <PasswordStrengthDemo initialValue="A1234567" />,
1920
+ code: `import { PasswordStrength } from '@open-mercato/ui/primitives/password-strength'
1921
+
1922
+
1923
+ <PasswordStrength strength="strong" requirements={[
1924
+ { id: 'uppercase', label: 'At least 1 uppercase', met: true },
1925
+ { id: 'number', label: 'At least 1 number', met: true },
1926
+ { id: 'length', label: 'At least 8 characters', met: true },
1927
+ ]} />`,
1928
+ },
1929
+ {
1930
+ id: 'interactive',
1931
+ title: 'interactive',
1932
+ render: () => <PasswordStrengthDemo interactive />,
1933
+ code: `import { PasswordStrength } from '@open-mercato/ui/primitives/password-strength'
1934
+ import { PasswordInput } from '@open-mercato/ui/primitives/password-input'
1935
+
1936
+ const [password, setPassword] = React.useState('')
1937
+ const requirements = [
1938
+ { id: 'uppercase', label: 'At least 1 uppercase', met: /[A-Z]/.test(password) },
1939
+ { id: 'number', label: 'At least 1 number', met: /[0-9]/.test(password) },
1940
+ { id: 'length', label: 'At least 8 characters', met: password.length >= 8 },
1941
+ ]
1942
+ const met = requirements.filter(requirement => requirement.met).length
1943
+ const strength = password.length === 0 ? 'empty' : met === 3 ? 'strong' : met === 2 ? 'moderate' : 'weak'
1944
+
1945
+ <div className="w-75 max-w-full">
1946
+ <PasswordInput value={password} onChange={event => setPassword(event.target.value)} aria-label="Password" />
1947
+ <PasswordStrength strength={strength} requirements={requirements} />
1948
+ </div>`,
1949
+ },
1950
+ ],
1951
+ }
1952
+
1117
1953
  const passwordInputEntry: GalleryEntry = {
1118
1954
  id: 'password-input',
1119
1955
  title: 'PasswordInput',
@@ -1155,6 +1991,17 @@ const passwordInputEntry: GalleryEntry = {
1155
1991
 
1156
1992
  <PasswordInput disabled />`,
1157
1993
  },
1994
+ {
1995
+ id: 'invalid',
1996
+ title: 'Invalid (described error)',
1997
+ render: () => <InvalidPasswordInputPreview />,
1998
+ code: `import { PasswordInput } from '@open-mercato/ui/primitives/password-input'
1999
+ import { FormField } from '@open-mercato/ui/primitives/form-field'
2000
+
2001
+ <FormField label="Password" error="Use at least 12 characters.">
2002
+ <PasswordInput defaultValue="short" autoComplete="off" />
2003
+ </FormField>`,
2004
+ },
1158
2005
  ],
1159
2006
  }
1160
2007
 
@@ -1225,6 +2072,19 @@ const [value, setValue] = React.useState<AmountValue>({ amount: '', currency: 'E
1225
2072
 
1226
2073
  <AmountInput value={value} onChange={setValue} showCurrency={false} />`,
1227
2074
  },
2075
+ {
2076
+ id: 'disabled',
2077
+ title: 'Disabled (amount and currency)',
2078
+ render: () => <DisabledAmountInputPreview />,
2079
+ code: `import { AmountInput, type AmountValue } from '@open-mercato/ui/primitives/amount-input'
2080
+ import { FormField } from '@open-mercato/ui/primitives/form-field'
2081
+
2082
+ const [value, setValue] = React.useState<AmountValue>({ amount: '1250.00', currency: 'EUR' })
2083
+
2084
+ <FormField label="Order total" disabled>
2085
+ <AmountInput value={value} onChange={setValue} />
2086
+ </FormField>`,
2087
+ },
1228
2088
  ],
1229
2089
  }
1230
2090
 
@@ -1274,10 +2134,10 @@ const digitInputEntry: GalleryEntry = {
1274
2134
  {
1275
2135
  id: 'default',
1276
2136
  title: 'default (6 cells)',
1277
- render: () => <DigitInput aria-label="Verification code" />,
2137
+ render: () => <DigitInputInputsDefaultSample />,
1278
2138
  code: `import { DigitInput } from '@open-mercato/ui/primitives/digit-input'
1279
2139
 
1280
- <DigitInput onComplete={(code) => verify(code)} />`,
2140
+ <DigitInput className="w-full gap-1 sm:w-auto sm:gap-2" cellClassName="min-w-0 w-8 flex-1 sm:w-14 sm:flex-none" onComplete={(code) => verify(code)} />`,
1281
2141
  },
1282
2142
  {
1283
2143
  id: 'masked',
@@ -1290,12 +2150,7 @@ const digitInputEntry: GalleryEntry = {
1290
2150
  {
1291
2151
  id: 'states',
1292
2152
  title: 'States',
1293
- render: () => (
1294
- <div className="flex flex-col gap-3">
1295
- <DigitInput length={4} value="4921" aria-invalid aria-label="Invalid code" />
1296
- <DigitInput length={4} disabled aria-label="Disabled code" />
1297
- </div>
1298
- ),
2153
+ render: () => <DigitInputInputsStatesSample />,
1299
2154
  code: `import { DigitInput } from '@open-mercato/ui/primitives/digit-input'
1300
2155
 
1301
2156
  <DigitInput length={4} aria-invalid />
@@ -1338,20 +2193,7 @@ const buttonInputEntry: GalleryEntry = {
1338
2193
  {
1339
2194
  id: 'copy-link',
1340
2195
  title: 'Copy link',
1341
- render: () => (
1342
- <div className="w-80">
1343
- <ButtonInput
1344
- readOnly
1345
- defaultValue="https://app.example.com/i/8f2c"
1346
- leftIcon={<Link2 />}
1347
- trailingAction={
1348
- <IconButton variant="ghost" aria-label="Copy link">
1349
- <Copy />
1350
- </IconButton>
1351
- }
1352
- />
1353
- </div>
1354
- ),
2196
+ render: () => <ButtonInputInputsCopyLinkSample />,
1355
2197
  code: `import { Copy, Link2 } from 'lucide-react'
1356
2198
  import { ButtonInput } from '@open-mercato/ui/primitives/button-input'
1357
2199
  import { IconButton } from '@open-mercato/ui/primitives/icon-button'
@@ -1368,18 +2210,7 @@ import { IconButton } from '@open-mercato/ui/primitives/icon-button'
1368
2210
  {
1369
2211
  id: 'send',
1370
2212
  title: 'Send action',
1371
- render: () => (
1372
- <div className="w-80">
1373
- <ButtonInput
1374
- placeholder="Invite by email"
1375
- trailingAction={
1376
- <IconButton variant="ghost" aria-label="Send invite">
1377
- <Send />
1378
- </IconButton>
1379
- }
1380
- />
1381
- </div>
1382
- ),
2213
+ render: () => <ButtonInputInputsSendSample />,
1383
2214
  code: `import { Send } from 'lucide-react'
1384
2215
  import { ButtonInput } from '@open-mercato/ui/primitives/button-input'
1385
2216
  import { IconButton } from '@open-mercato/ui/primitives/icon-button'
@@ -1398,7 +2229,19 @@ const colorPickerEntry: GalleryEntry = {
1398
2229
  id: 'color-picker',
1399
2230
  title: 'ColorPicker',
1400
2231
  importPath: '@open-mercato/ui/primitives/color-picker',
2232
+ figmaNodeId: '4415:53671',
1401
2233
  variants: [
2234
+ {
2235
+ id: 'opacity',
2236
+ title: 'Opacity',
2237
+ render: () => <DemoColorPicker showOpacity />,
2238
+ code: `import { ColorPicker } from '@open-mercato/ui/primitives/color-picker'
2239
+
2240
+ const [color, setColor] = React.useState('#6366F1')
2241
+ const [opacity, setOpacity] = React.useState(75)
2242
+
2243
+ <ColorPicker value={color} onChange={setColor} showOpacity opacity={opacity} onOpacityChange={setOpacity} />`,
2244
+ },
1402
2245
  {
1403
2246
  id: 'default',
1404
2247
  title: 'default',
@@ -1438,9 +2281,7 @@ const tagInputEntry: GalleryEntry = {
1438
2281
  {
1439
2282
  id: 'default',
1440
2283
  title: 'default',
1441
- render: () => (
1442
- <DemoTagInput initial={['wholesale', 'priority', 'eu']} placeholder="Add tag" />
1443
- ),
2284
+ render: () => <TagInputInputsDefaultSample />,
1444
2285
  code: `import { TagInput } from '@open-mercato/ui/primitives/tag-input'
1445
2286
 
1446
2287
  const [tags, setTags] = React.useState<string[]>(['wholesale', 'priority', 'eu'])
@@ -1450,9 +2291,7 @@ const [tags, setTags] = React.useState<string[]>(['wholesale', 'priority', 'eu']
1450
2291
  {
1451
2292
  id: 'max-tags',
1452
2293
  title: 'Max tags reached',
1453
- render: () => (
1454
- <DemoTagInput initial={['red', 'green', 'blue']} maxTags={3} placeholder="Add tag" />
1455
- ),
2294
+ render: () => <TagInputInputsMaxTagsSample />,
1456
2295
  code: `import { TagInput } from '@open-mercato/ui/primitives/tag-input'
1457
2296
 
1458
2297
  <TagInput value={tags} onChange={setTags} maxTags={3} />`,
@@ -1462,34 +2301,451 @@ const [tags, setTags] = React.useState<string[]>(['wholesale', 'priority', 'eu']
1462
2301
 
1463
2302
  const richEditorEntry: GalleryEntry = {
1464
2303
  id: 'rich-editor',
2304
+ figmaNodeId: '166926:17605',
1465
2305
  title: 'RichEditor',
1466
2306
  importPath: '@open-mercato/ui/primitives/rich-editor',
2307
+ docsAnchor: '#richeditor',
2308
+ usage: { do: [
2309
+ 'toolbarDesign opts into source layouts 01–04 with 28 px controls, 20 px icons and 6 px item radii. Existing full, standard, basic and minimal presets retain their defaults.',
2310
+ 'Every source layout includes a working More menu. Hidden commands remain available in that menu when the toolbar narrows.',
2311
+ 'The 12-color palette already includes the source Color11 (white) and Color12 (black). Color choice changes editable content; stored HTML still passes through the existing sanitizer.',
2312
+ 'The character counter updates while typing. onChange retains its blur contract; consumers supply translated labels and their own comment and mention workflows.',
2313
+ ] },
2314
+ variants: [
2315
+ { id: 'minimal', title: 'Preset / minimal', render: () => <DemoRichEditor variant="minimal" />, code: `import * as React from 'react'
2316
+ import { RichEditor } from '@open-mercato/ui/primitives/rich-editor'
2317
+
2318
+ const [html, setHtml] = React.useState('<p>Editable text</p>')
2319
+ <RichEditor value={html} onChange={setHtml} variant="minimal" />` },
2320
+ { id: 'standard', title: 'Preset / standard', render: () => <DemoRichEditor variant="standard" />, code: `import * as React from 'react'
2321
+ import { RichEditor } from '@open-mercato/ui/primitives/rich-editor'
2322
+
2323
+ const [html, setHtml] = React.useState('<p>Editable text</p>')
2324
+ <RichEditor value={html} onChange={setHtml} variant="standard" />` },
2325
+ { id: 'basic', title: 'Preset / basic', render: () => <DemoRichEditor variant="basic" />, code: `import * as React from 'react'
2326
+ import { RichEditor } from '@open-mercato/ui/primitives/rich-editor'
2327
+
2328
+ const [html, setHtml] = React.useState('<p>Editable text</p>')
2329
+ <RichEditor value={html} onChange={setHtml} variant="basic" />` },
2330
+ { id: 'full', title: 'Preset / full', render: () => <DemoRichEditor variant="full" />, code: `import * as React from 'react'
2331
+ import { RichEditor } from '@open-mercato/ui/primitives/rich-editor'
2332
+
2333
+ const [html, setHtml] = React.useState('<p>Editable text</p>')
2334
+ <RichEditor value={html} onChange={setHtml} variant="full" />` },
2335
+ { id: 'source-01', title: 'Source layout 01', render: () => <DemoRichEditor toolbarDesign="01" />, code: `import * as React from 'react'
2336
+ import { RichEditor } from '@open-mercato/ui/primitives/rich-editor'
2337
+
2338
+ const [html, setHtml] = React.useState('<p>Editable text</p>')
2339
+ <RichEditor value={html} onChange={setHtml} toolbarDesign="01" />` },
2340
+ { id: 'source-02', title: 'Source layout 02', render: () => <DemoRichEditor toolbarDesign="02" />, code: `import * as React from 'react'
2341
+ import { RichEditor } from '@open-mercato/ui/primitives/rich-editor'
2342
+
2343
+ const [html, setHtml] = React.useState('<p>Editable text</p>')
2344
+ <RichEditor value={html} onChange={setHtml} toolbarDesign="02" />` },
2345
+ { id: 'source-03', title: 'Source layout 03', render: () => <DemoRichEditor toolbarDesign="03" />, code: `import * as React from 'react'
2346
+ import { RichEditor } from '@open-mercato/ui/primitives/rich-editor'
2347
+
2348
+ const [html, setHtml] = React.useState('<p>Editable text</p>')
2349
+ <RichEditor value={html} onChange={setHtml} toolbarDesign="03" />` },
2350
+ { id: 'source-04', title: 'Source layout 04', render: () => <DemoRichEditor toolbarDesign="04" />, code: `import * as React from 'react'
2351
+ import { RichEditor } from '@open-mercato/ui/primitives/rich-editor'
2352
+
2353
+ const [html, setHtml] = React.useState('<p>Editable text</p>')
2354
+ <RichEditor value={html} onChange={setHtml} toolbarDesign="04" />` },
2355
+ { id: 'disabled', title: 'Source layout / disabled', render: () => <DemoRichEditor toolbarDesign="01" disabled />, code: `import { RichEditor } from '@open-mercato/ui/primitives/rich-editor'
2356
+
2357
+ <RichEditor value={html} onChange={setHtml} toolbarDesign="01" disabled />` },
2358
+ { id: 'counter', title: 'Live character counter', render: () => <DemoRichEditor toolbarDesign="03" counter />, code: `import { RichEditor } from '@open-mercato/ui/primitives/rich-editor'
2359
+
2360
+ <RichEditor value={html} onChange={setHtml} toolbarDesign="03" maxLength={100} />` },
2361
+ { id: 'palette', title: 'All twelve source colors', render: () => <DemoRichEditorPalette />, code: `import * as React from 'react'
2362
+ import { RichEditorColorPalette, type RichEditorColorKey } from '@open-mercato/ui/primitives/rich-editor'
2363
+
2364
+ const [color, setColor] = React.useState<RichEditorColorKey | null>('gray')
2365
+ <RichEditorColorPalette value={color} onChange={setColor} />` },
2366
+ ],
2367
+ }
2368
+
2369
+ const fileUploadAreaEntry: GalleryEntry = {
2370
+ id: 'file-upload',
2371
+ title: 'FileUploadArea',
2372
+ importPath: '@open-mercato/ui/primitives/file-upload',
2373
+ figmaNodeId: '450:9413',
2374
+ docsAnchor: '#fileuploadarea',
2375
+ usage: { do: ['Default and hover are live states of the same drop target. Select or drop files to exercise the local demo queue.', 'Pass onFilesSelected and handle transfer separately. Demo progress is simulated locally; files never leave the browser.', 'Keep custom accept/maxSizeBytes and the description consistent.'] },
2376
+ variants: [
2377
+ {
2378
+ id: 'default', title: 'default',
2379
+ render: () => <FileUploadAreaDemo />,
2380
+ code: `import { FileUploadArea } from '@open-mercato/ui/primitives/file-upload'
2381
+
2382
+ <FileUploadArea onFilesSelected={handleFiles} onFilesRejected={handleRejections} />`,
2383
+ },
2384
+ {
2385
+ id: 'drag-and-drop', title: 'drag-and-drop',
2386
+ render: () => <FileUploadAreaDemo />,
2387
+ code: `import { FileUploadArea } from '@open-mercato/ui/primitives/file-upload'
2388
+
2389
+ <FileUploadArea onFilesSelected={handleFiles} onFilesRejected={handleRejections} />`,
2390
+ },
2391
+ {
2392
+ id: 'disabled', title: 'disabled',
2393
+ render: () => <FileUploadAreaDemo disabled />,
2394
+ code: `import { FileUploadArea } from '@open-mercato/ui/primitives/file-upload'
2395
+
2396
+ <FileUploadArea disabled onFilesSelected={handleFiles} onFilesRejected={handleRejections} />`,
2397
+ },
2398
+ ],
2399
+ }
2400
+
2401
+ const fileUploadCardEntry: GalleryEntry = {
2402
+ id: 'file-upload-card',
2403
+ title: 'FileUploadCard',
2404
+ importPath: '@open-mercato/ui/primitives/file-upload-card',
2405
+ figmaNodeId: '451:409',
2406
+ docsAnchor: '#fileuploadcard',
2407
+ usage: { do: ['Cancel/remove and retry are real callbacks. The error example retries using local simulated progress.', 'The caller owns transfer state, progress, and localized file-size text.'] },
2408
+ variants: [
2409
+ {
2410
+ id: 'uploading', title: 'uploading',
2411
+ render: () => <FileUploadCardDemo initialStatus="uploading" />,
2412
+ code: `import { FileUploadCard } from '@open-mercato/ui/primitives/file-upload-card'
2413
+
2414
+ <FileUploadCard fileName="my-cv.pdf" sizeLabel={sizeLabel} status="uploading" progress={progress} onRemove={removeFile} onRetry={retryFile} />`,
2415
+ },
2416
+ {
2417
+ id: 'success', title: 'success',
2418
+ render: () => <FileUploadCardDemo initialStatus="success" />,
2419
+ code: `import { FileUploadCard } from '@open-mercato/ui/primitives/file-upload-card'
2420
+
2421
+ <FileUploadCard fileName="my-cv.pdf" sizeLabel={sizeLabel} status="success" progress={progress} onRemove={removeFile} onRetry={retryFile} />`,
2422
+ },
2423
+ {
2424
+ id: 'error', title: 'error',
2425
+ render: () => <FileUploadCardDemo initialStatus="error" />,
2426
+ code: `import { FileUploadCard } from '@open-mercato/ui/primitives/file-upload-card'
2427
+
2428
+ <FileUploadCard fileName="my-cv.pdf" sizeLabel={sizeLabel} status="error" progress={progress} onRemove={removeFile} onRetry={retryFile} />`,
2429
+ },
2430
+ ],
2431
+ }
2432
+
2433
+ const fileFormatIconEntry: GalleryEntry = {
2434
+ id: 'file-format-icon',
2435
+ title: 'FileFormatIcon',
2436
+ importPath: '@open-mercato/ui/primitives/file-format-icon',
2437
+ figmaNodeId: '450:17234',
2438
+ docsAnchor: '#fileformaticon',
2439
+ usage: { do: ['Both sizes and all nine category colors come from Figma. Teal is the source name of the light-blue category.', 'The original Figma paper/fold artwork is bundled locally. Category-label foregrounds meet 4.5:1 contrast.'] },
2440
+ variants: [
2441
+ {
2442
+ id: 'red-default', title: 'red / 40px',
2443
+ render: () => <FileFormatIcon format="PDF" tone="red" size="default" />,
2444
+ code: `import { FileFormatIcon } from '@open-mercato/ui/primitives/file-format-icon'
2445
+
2446
+ <FileFormatIcon format="PDF" tone="red" size="default" />`,
2447
+ },
2448
+ {
2449
+ id: 'orange-default', title: 'orange / 40px',
2450
+ render: () => <FileFormatIcon format="PDF" tone="orange" size="default" />,
2451
+ code: `import { FileFormatIcon } from '@open-mercato/ui/primitives/file-format-icon'
2452
+
2453
+ <FileFormatIcon format="PDF" tone="orange" size="default" />`,
2454
+ },
2455
+ {
2456
+ id: 'yellow-default', title: 'yellow / 40px',
2457
+ render: () => <FileFormatIcon format="PDF" tone="yellow" size="default" />,
2458
+ code: `import { FileFormatIcon } from '@open-mercato/ui/primitives/file-format-icon'
2459
+
2460
+ <FileFormatIcon format="PDF" tone="yellow" size="default" />`,
2461
+ },
2462
+ {
2463
+ id: 'green-default', title: 'green / 40px',
2464
+ render: () => <FileFormatIcon format="PDF" tone="green" size="default" />,
2465
+ code: `import { FileFormatIcon } from '@open-mercato/ui/primitives/file-format-icon'
2466
+
2467
+ <FileFormatIcon format="PDF" tone="green" size="default" />`,
2468
+ },
2469
+ {
2470
+ id: 'teal-default', title: 'teal / 40px',
2471
+ render: () => <FileFormatIcon format="PDF" tone="teal" size="default" />,
2472
+ code: `import { FileFormatIcon } from '@open-mercato/ui/primitives/file-format-icon'
2473
+
2474
+ <FileFormatIcon format="PDF" tone="teal" size="default" />`,
2475
+ },
2476
+ {
2477
+ id: 'blue-default', title: 'blue / 40px',
2478
+ render: () => <FileFormatIcon format="PDF" tone="blue" size="default" />,
2479
+ code: `import { FileFormatIcon } from '@open-mercato/ui/primitives/file-format-icon'
2480
+
2481
+ <FileFormatIcon format="PDF" tone="blue" size="default" />`,
2482
+ },
2483
+ {
2484
+ id: 'purple-default', title: 'purple / 40px',
2485
+ render: () => <FileFormatIcon format="PDF" tone="purple" size="default" />,
2486
+ code: `import { FileFormatIcon } from '@open-mercato/ui/primitives/file-format-icon'
2487
+
2488
+ <FileFormatIcon format="PDF" tone="purple" size="default" />`,
2489
+ },
2490
+ {
2491
+ id: 'pink-default', title: 'pink / 40px',
2492
+ render: () => <FileFormatIcon format="PDF" tone="pink" size="default" />,
2493
+ code: `import { FileFormatIcon } from '@open-mercato/ui/primitives/file-format-icon'
2494
+
2495
+ <FileFormatIcon format="PDF" tone="pink" size="default" />`,
2496
+ },
2497
+ {
2498
+ id: 'gray-default', title: 'gray / 40px',
2499
+ render: () => <FileFormatIcon format="PDF" tone="gray" size="default" />,
2500
+ code: `import { FileFormatIcon } from '@open-mercato/ui/primitives/file-format-icon'
2501
+
2502
+ <FileFormatIcon format="PDF" tone="gray" size="default" />`,
2503
+ },
2504
+ {
2505
+ id: 'red-sm', title: 'red / 32px',
2506
+ render: () => <FileFormatIcon format="PDF" tone="red" size="sm" />,
2507
+ code: `import { FileFormatIcon } from '@open-mercato/ui/primitives/file-format-icon'
2508
+
2509
+ <FileFormatIcon format="PDF" tone="red" size="sm" />`,
2510
+ },
2511
+ {
2512
+ id: 'orange-sm', title: 'orange / 32px',
2513
+ render: () => <FileFormatIcon format="PDF" tone="orange" size="sm" />,
2514
+ code: `import { FileFormatIcon } from '@open-mercato/ui/primitives/file-format-icon'
2515
+
2516
+ <FileFormatIcon format="PDF" tone="orange" size="sm" />`,
2517
+ },
2518
+ {
2519
+ id: 'yellow-sm', title: 'yellow / 32px',
2520
+ render: () => <FileFormatIcon format="PDF" tone="yellow" size="sm" />,
2521
+ code: `import { FileFormatIcon } from '@open-mercato/ui/primitives/file-format-icon'
2522
+
2523
+ <FileFormatIcon format="PDF" tone="yellow" size="sm" />`,
2524
+ },
2525
+ {
2526
+ id: 'green-sm', title: 'green / 32px',
2527
+ render: () => <FileFormatIcon format="PDF" tone="green" size="sm" />,
2528
+ code: `import { FileFormatIcon } from '@open-mercato/ui/primitives/file-format-icon'
2529
+
2530
+ <FileFormatIcon format="PDF" tone="green" size="sm" />`,
2531
+ },
2532
+ {
2533
+ id: 'teal-sm', title: 'teal / 32px',
2534
+ render: () => <FileFormatIcon format="PDF" tone="teal" size="sm" />,
2535
+ code: `import { FileFormatIcon } from '@open-mercato/ui/primitives/file-format-icon'
2536
+
2537
+ <FileFormatIcon format="PDF" tone="teal" size="sm" />`,
2538
+ },
2539
+ {
2540
+ id: 'blue-sm', title: 'blue / 32px',
2541
+ render: () => <FileFormatIcon format="PDF" tone="blue" size="sm" />,
2542
+ code: `import { FileFormatIcon } from '@open-mercato/ui/primitives/file-format-icon'
2543
+
2544
+ <FileFormatIcon format="PDF" tone="blue" size="sm" />`,
2545
+ },
2546
+ {
2547
+ id: 'purple-sm', title: 'purple / 32px',
2548
+ render: () => <FileFormatIcon format="PDF" tone="purple" size="sm" />,
2549
+ code: `import { FileFormatIcon } from '@open-mercato/ui/primitives/file-format-icon'
2550
+
2551
+ <FileFormatIcon format="PDF" tone="purple" size="sm" />`,
2552
+ },
2553
+ {
2554
+ id: 'pink-sm', title: 'pink / 32px',
2555
+ render: () => <FileFormatIcon format="PDF" tone="pink" size="sm" />,
2556
+ code: `import { FileFormatIcon } from '@open-mercato/ui/primitives/file-format-icon'
2557
+
2558
+ <FileFormatIcon format="PDF" tone="pink" size="sm" />`,
2559
+ },
2560
+ {
2561
+ id: 'gray-sm', title: 'gray / 32px',
2562
+ render: () => <FileFormatIcon format="PDF" tone="gray" size="sm" />,
2563
+ code: `import { FileFormatIcon } from '@open-mercato/ui/primitives/file-format-icon'
2564
+
2565
+ <FileFormatIcon format="PDF" tone="gray" size="sm" />`,
2566
+ },
2567
+ ],
2568
+ }
2569
+
2570
+ const imageUploadEntry: GalleryEntry = {
2571
+ id: 'image-upload',
2572
+ title: 'ImageUpload',
2573
+ importPath: '@open-mercato/ui/primitives/image-upload',
2574
+ figmaNodeId: '452:653',
2575
+ docsAnchor: '#imageupload',
2576
+ usage: { do: ['Figma calls the layout with text above actions Vertical; both source layouts place the avatar to the left.', 'New selections must decode as PNG/JPEG and meet the configured minimum dimensions (400×400 by default). The caller owns the preview URL and transfer.', 'Existing uploaded illustrations are exact source fixtures. Change and Remove update only local browser state.'] },
1467
2577
  variants: [
1468
2578
  {
1469
- id: 'minimal',
1470
- title: 'minimal',
1471
- render: () => <DemoRichEditor variant="minimal" />,
1472
- code: `import { RichEditor } from '@open-mercato/ui/primitives/rich-editor'
2579
+ id: 'avatar-vertical-empty', title: 'avatar / vertical / empty',
2580
+ render: () => <ImageUploadDemo kind="avatar" alignment="vertical" uploaded={false} />,
2581
+ code: `import { ImageUpload } from '@open-mercato/ui/primitives/image-upload'
2582
+
2583
+ <ImageUpload kind="avatar" alignment="vertical" src={previewUrl} alt={imageLabel} onChange={handleImageChange} />`,
2584
+ },
2585
+ {
2586
+ id: 'avatar-vertical-uploaded', title: 'avatar / vertical / uploaded',
2587
+ render: () => <ImageUploadDemo kind="avatar" alignment="vertical" uploaded={true} />,
2588
+ code: `import { ImageUpload } from '@open-mercato/ui/primitives/image-upload'
2589
+
2590
+ <ImageUpload kind="avatar" alignment="vertical" src={previewUrl} alt={imageLabel} onChange={handleImageChange} />`,
2591
+ },
2592
+ {
2593
+ id: 'avatar-horizontal-empty', title: 'avatar / horizontal / empty',
2594
+ render: () => <ImageUploadDemo kind="avatar" alignment="horizontal" uploaded={false} />,
2595
+ code: `import { ImageUpload } from '@open-mercato/ui/primitives/image-upload'
1473
2596
 
1474
- const [html, setHtml] = React.useState('')
2597
+ <ImageUpload kind="avatar" alignment="horizontal" src={previewUrl} alt={imageLabel} onChange={handleImageChange} />`,
2598
+ },
2599
+ {
2600
+ id: 'avatar-horizontal-uploaded', title: 'avatar / horizontal / uploaded',
2601
+ render: () => <ImageUploadDemo kind="avatar" alignment="horizontal" uploaded={true} />,
2602
+ code: `import { ImageUpload } from '@open-mercato/ui/primitives/image-upload'
2603
+
2604
+ <ImageUpload kind="avatar" alignment="horizontal" src={previewUrl} alt={imageLabel} onChange={handleImageChange} />`,
2605
+ },
2606
+ {
2607
+ id: 'company-vertical-empty', title: 'company / vertical / empty',
2608
+ render: () => <ImageUploadDemo kind="company" alignment="vertical" uploaded={false} />,
2609
+ code: `import { ImageUpload } from '@open-mercato/ui/primitives/image-upload'
1475
2610
 
1476
- <RichEditor value={html} onChange={setHtml} variant="minimal" />`,
2611
+ <ImageUpload kind="company" alignment="vertical" src={previewUrl} alt={imageLabel} onChange={handleImageChange} />`,
1477
2612
  },
1478
2613
  {
1479
- id: 'standard',
1480
- title: 'standard',
1481
- render: () => <DemoRichEditor variant="standard" />,
1482
- code: `import { RichEditor } from '@open-mercato/ui/primitives/rich-editor'
2614
+ id: 'company-vertical-uploaded', title: 'company / vertical / uploaded',
2615
+ render: () => <ImageUploadDemo kind="company" alignment="vertical" uploaded={true} />,
2616
+ code: `import { ImageUpload } from '@open-mercato/ui/primitives/image-upload'
1483
2617
 
1484
- <RichEditor value={html} onChange={setHtml} variant="standard" />`,
2618
+ <ImageUpload kind="company" alignment="vertical" src={previewUrl} alt={imageLabel} onChange={handleImageChange} />`,
2619
+ },
2620
+ {
2621
+ id: 'company-horizontal-empty', title: 'company / horizontal / empty',
2622
+ render: () => <ImageUploadDemo kind="company" alignment="horizontal" uploaded={false} />,
2623
+ code: `import { ImageUpload } from '@open-mercato/ui/primitives/image-upload'
2624
+
2625
+ <ImageUpload kind="company" alignment="horizontal" src={previewUrl} alt={imageLabel} onChange={handleImageChange} />`,
2626
+ },
2627
+ {
2628
+ id: 'company-horizontal-uploaded', title: 'company / horizontal / uploaded',
2629
+ render: () => <ImageUploadDemo kind="company" alignment="horizontal" uploaded={true} />,
2630
+ code: `import { ImageUpload } from '@open-mercato/ui/primitives/image-upload'
2631
+
2632
+ <ImageUpload kind="company" alignment="horizontal" src={previewUrl} alt={imageLabel} onChange={handleImageChange} />`,
2633
+ },
2634
+ {
2635
+ id: 'disabled', title: 'disabled',
2636
+ render: () => <ImageUploadDemo kind="avatar" alignment="vertical" uploaded disabled />,
2637
+ code: `import { ImageUpload } from '@open-mercato/ui/primitives/image-upload'
2638
+
2639
+ <ImageUpload disabled src={previewUrl} onChange={handleImageChange} />`,
1485
2640
  },
1486
2641
  ],
1487
2642
  }
1488
2643
 
2644
+ const labelEntry: GalleryEntry = {
2645
+ id: 'label', title: 'FieldLabel',
2646
+ importPath: '@open-mercato/ui/primitives/label',
2647
+ figmaNodeId: '266:2814',
2648
+ descriptionKey: 'design_system.entries.label.description',
2649
+ variants: [
2650
+ { id: 'normal', title: 'normal', render: () => <FieldLabelExample />, code: fieldLabelCode(' sublabel="(optional)"') },
2651
+ { id: 'disabled', title: 'disabled', render: () => <FieldLabelExample disabled />, code: fieldLabelCode(' disabled') },
2652
+ { id: 'required', title: 'required', render: () => <FieldLabelExample kind="required" />, code: fieldLabelCode(' required') },
2653
+ { id: 'optional', title: 'optional', render: () => <FieldLabelExample kind="optional" />, code: fieldLabelCode(' sublabel="(optional)"') },
2654
+ { id: 'information', title: 'information', render: () => <FieldLabelExample kind="information" />, code: fieldLabelInformationCode },
2655
+ { id: 'action', title: 'action', render: () => <FieldLabelExample kind="action" />, code: fieldLabelActionCode },
2656
+ { id: 'form-field', title: 'form-field', render: () => <FormFieldLabelExample />, code: formFieldLabelCode },
2657
+ ],
2658
+ }
2659
+
2660
+ const hint_textEntry: GalleryEntry = {
2661
+ id: 'hint-text', title: 'HintText',
2662
+ importPath: '@open-mercato/ui/primitives/hint-text',
2663
+ figmaNodeId: '266:5284',
2664
+ descriptionKey: 'design_system.entries.hint-text.description',
2665
+ variants: [
2666
+ { id: 'default', title: 'default', render: () => <HintTextExample />, code: hintTextCode() },
2667
+ { id: 'error', title: 'error', render: () => <HintTextExample state="error" />, code: hintTextCode({ state: 'error' }) },
2668
+ { id: 'disabled', title: 'disabled', render: () => <HintTextExample state="disabled" />, code: hintTextCode({ state: 'disabled' }) },
2669
+ { id: 'text-only', title: 'text-only', render: () => <HintTextExample icon={false} />, code: hintTextCode({ icon: false }) },
2670
+ ],
2671
+ }
2672
+
2673
+ const marketingControlsEntry: GalleryEntry = {
2674
+ id: 'marketing-controls',
2675
+ title: 'Marketing Controls',
2676
+ importPath: '@open-mercato/ui/primitives/input',
2677
+ figmaNodeId: '6696:81119',
2678
+ variants: [
2679
+ { id: 'product-image-1', title: 'product-image-1', render: () => <MarketingControlDemo kind="product-image" product={0} />, code: marketingControlExampleCode('<MarketingControlDemo kind="product-image" product={0} />') },
2680
+ { id: 'product-image-2', title: 'product-image-2', render: () => <MarketingControlDemo kind="product-image" product={1} />, code: marketingControlExampleCode('<MarketingControlDemo kind="product-image" product={1} />') },
2681
+ { id: 'product-image-3', title: 'product-image-3', render: () => <MarketingControlDemo kind="product-image" product={2} />, code: marketingControlExampleCode('<MarketingControlDemo kind="product-image" product={2} />') },
2682
+ { id: 'product-image-4', title: 'product-image-4', render: () => <MarketingControlDemo kind="product-image" product={3} />, code: marketingControlExampleCode('<MarketingControlDemo kind="product-image" product={3} />') },
2683
+ { id: 'product-image-5', title: 'product-image-5', render: () => <MarketingControlDemo kind="product-image" product={4} />, code: marketingControlExampleCode('<MarketingControlDemo kind="product-image" product={4} />') },
2684
+ { id: 'product-image-6', title: 'product-image-6', render: () => <MarketingControlDemo kind="product-image" product={5} />, code: marketingControlExampleCode('<MarketingControlDemo kind="product-image" product={5} />') },
2685
+ { id: 'product-image-7', title: 'product-image-7', render: () => <MarketingControlDemo kind="product-image" product={6} />, code: marketingControlExampleCode('<MarketingControlDemo kind="product-image" product={6} />') },
2686
+ { id: 'product-image-8', title: 'product-image-8', render: () => <MarketingControlDemo kind="product-image" product={7} />, code: marketingControlExampleCode('<MarketingControlDemo kind="product-image" product={7} />') },
2687
+ { id: 'product-image-9', title: 'product-image-9', render: () => <MarketingControlDemo kind="product-image" product={8} />, code: marketingControlExampleCode('<MarketingControlDemo kind="product-image" product={8} />') },
2688
+ { id: 'product-image-10', title: 'product-image-10', render: () => <MarketingControlDemo kind="product-image" product={9} />, code: marketingControlExampleCode('<MarketingControlDemo kind="product-image" product={9} />') },
2689
+ { id: 'step-item-default', title: 'step-item-default', render: () => <MarketingControlDemo kind="step-item" state="default" />, code: marketingControlExampleCode('<MarketingControlDemo kind="step-item" state="default" />') },
2690
+ { id: 'step-item-active', title: 'step-item-active', render: () => <MarketingControlDemo kind="step-item" state="active" />, code: marketingControlExampleCode('<MarketingControlDemo kind="step-item" state="active" />') },
2691
+ { id: 'step-item-complete', title: 'step-item-complete', render: () => <MarketingControlDemo kind="step-item" state="complete" />, code: marketingControlExampleCode('<MarketingControlDemo kind="step-item" state="complete" />') },
2692
+ { id: 'select-default', title: 'select-default', render: () => <MarketingControlDemo kind="select" state="default" />, code: marketingControlExampleCode('<MarketingControlDemo kind="select" state="default" />') },
2693
+ { id: 'select-hover', title: 'select-hover', render: () => <MarketingControlDemo kind="select" state="hover" />, code: marketingControlExampleCode('<MarketingControlDemo kind="select" state="hover" />') },
2694
+ { id: 'select-active', title: 'select-active', render: () => <MarketingControlDemo kind="select" state="active" />, code: marketingControlExampleCode('<MarketingControlDemo kind="select" state="active" />') },
2695
+ { id: 'select-filled', title: 'select-filled', render: () => <MarketingControlDemo kind="select" state="filled" />, code: marketingControlExampleCode('<MarketingControlDemo kind="select" state="filled" />') },
2696
+ { id: 'input-default-medium', title: 'input-default-medium', render: () => <MarketingControlDemo kind="input" state="default" size="medium" />, code: marketingControlExampleCode('<MarketingControlDemo kind="input" state="default" size="medium" />') },
2697
+ { id: 'input-hover-medium', title: 'input-hover-medium', render: () => <MarketingControlDemo kind="input" state="hover" size="medium" />, code: marketingControlExampleCode('<MarketingControlDemo kind="input" state="hover" size="medium" />') },
2698
+ { id: 'input-active-medium', title: 'input-active-medium', render: () => <MarketingControlDemo kind="input" state="active" size="medium" />, code: marketingControlExampleCode('<MarketingControlDemo kind="input" state="active" size="medium" />') },
2699
+ { id: 'input-filled-medium', title: 'input-filled-medium', render: () => <MarketingControlDemo kind="input" state="filled" size="medium" />, code: marketingControlExampleCode('<MarketingControlDemo kind="input" state="filled" size="medium" />') },
2700
+ { id: 'input-default-large', title: 'input-default-large', render: () => <MarketingControlDemo kind="input" state="default" size="large" />, code: marketingControlExampleCode('<MarketingControlDemo kind="input" state="default" size="large" />') },
2701
+ { id: 'input-hover-large', title: 'input-hover-large', render: () => <MarketingControlDemo kind="input" state="hover" size="large" />, code: marketingControlExampleCode('<MarketingControlDemo kind="input" state="hover" size="large" />') },
2702
+ { id: 'input-active-large', title: 'input-active-large', render: () => <MarketingControlDemo kind="input" state="active" size="large" />, code: marketingControlExampleCode('<MarketingControlDemo kind="input" state="active" size="large" />') },
2703
+ { id: 'input-filled-large', title: 'input-filled-large', render: () => <MarketingControlDemo kind="input" state="filled" size="large" />, code: marketingControlExampleCode('<MarketingControlDemo kind="input" state="filled" size="large" />') },
2704
+ { id: 'textarea-default', title: 'textarea-default', render: () => <MarketingControlDemo kind="textarea" state="default" />, code: marketingControlExampleCode('<MarketingControlDemo kind="textarea" state="default" />') },
2705
+ { id: 'textarea-hover', title: 'textarea-hover', render: () => <MarketingControlDemo kind="textarea" state="hover" />, code: marketingControlExampleCode('<MarketingControlDemo kind="textarea" state="hover" />') },
2706
+ { id: 'textarea-active', title: 'textarea-active', render: () => <MarketingControlDemo kind="textarea" state="active" />, code: marketingControlExampleCode('<MarketingControlDemo kind="textarea" state="active" />') },
2707
+ { id: 'textarea-filled', title: 'textarea-filled', render: () => <MarketingControlDemo kind="textarea" state="filled" />, code: marketingControlExampleCode('<MarketingControlDemo kind="textarea" state="filled" />') },
2708
+ { id: 'amount-default', title: 'amount-default', render: () => <MarketingControlDemo kind="amount" state="default" />, code: marketingControlExampleCode('<MarketingControlDemo kind="amount" state="default" />') },
2709
+ { id: 'amount-hover', title: 'amount-hover', render: () => <MarketingControlDemo kind="amount" state="hover" />, code: marketingControlExampleCode('<MarketingControlDemo kind="amount" state="hover" />') },
2710
+ { id: 'amount-active', title: 'amount-active', render: () => <MarketingControlDemo kind="amount" state="active" />, code: marketingControlExampleCode('<MarketingControlDemo kind="amount" state="active" />') },
2711
+ { id: 'amount-filled', title: 'amount-filled', render: () => <MarketingControlDemo kind="amount" state="filled" />, code: marketingControlExampleCode('<MarketingControlDemo kind="amount" state="filled" />') },
2712
+ { id: 'tab-menu-default', title: 'tab-menu-default', render: () => <MarketingControlDemo kind="tab-menu" state="default" />, code: marketingControlExampleCode('<MarketingControlDemo kind="tab-menu" state="default" />') },
2713
+ { id: 'tab-menu-hover', title: 'tab-menu-hover', render: () => <MarketingControlDemo kind="tab-menu" state="hover" />, code: marketingControlExampleCode('<MarketingControlDemo kind="tab-menu" state="hover" />') },
2714
+ { id: 'tab-menu-active', title: 'tab-menu-active', render: () => <MarketingControlDemo kind="tab-menu" state="active" />, code: marketingControlExampleCode('<MarketingControlDemo kind="tab-menu" state="active" />') },
2715
+ { id: 'inline-input-placeholder', title: 'inline-input-placeholder', render: () => <MarketingControlDemo kind="inline-input" state="placeholder" />, code: marketingControlExampleCode('<MarketingControlDemo kind="inline-input" state="placeholder" />') },
2716
+ { id: 'inline-input-hover', title: 'inline-input-hover', render: () => <MarketingControlDemo kind="inline-input" state="hover" />, code: marketingControlExampleCode('<MarketingControlDemo kind="inline-input" state="hover" />') },
2717
+ { id: 'inline-input-focus', title: 'inline-input-focus', render: () => <MarketingControlDemo kind="inline-input" state="focus" />, code: marketingControlExampleCode('<MarketingControlDemo kind="inline-input" state="focus" />') },
2718
+ { id: 'inline-input-filled', title: 'inline-input-filled', render: () => <MarketingControlDemo kind="inline-input" state="filled" />, code: marketingControlExampleCode('<MarketingControlDemo kind="inline-input" state="filled" />') },
2719
+ { id: 'inline-input-disabled', title: 'inline-input-disabled', render: () => <MarketingControlDemo kind="inline-input" state="disabled" />, code: marketingControlExampleCode('<MarketingControlDemo kind="inline-input" state="disabled" />') },
2720
+ { id: 'inline-select-placeholder', title: 'inline-select-placeholder', render: () => <MarketingControlDemo kind="inline-select" state="placeholder" />, code: marketingControlExampleCode('<MarketingControlDemo kind="inline-select" state="placeholder" />') },
2721
+ { id: 'inline-select-hover', title: 'inline-select-hover', render: () => <MarketingControlDemo kind="inline-select" state="hover" />, code: marketingControlExampleCode('<MarketingControlDemo kind="inline-select" state="hover" />') },
2722
+ { id: 'inline-select-focus', title: 'inline-select-focus', render: () => <MarketingControlDemo kind="inline-select" state="focus" />, code: marketingControlExampleCode('<MarketingControlDemo kind="inline-select" state="focus" />') },
2723
+ { id: 'inline-select-filled', title: 'inline-select-filled', render: () => <MarketingControlDemo kind="inline-select" state="filled" />, code: marketingControlExampleCode('<MarketingControlDemo kind="inline-select" state="filled" />') },
2724
+ { id: 'inline-select-disabled', title: 'inline-select-disabled', render: () => <MarketingControlDemo kind="inline-select" state="disabled" />, code: marketingControlExampleCode('<MarketingControlDemo kind="inline-select" state="disabled" />') },
2725
+ { id: 'chart-tooltip-right', title: 'chart-tooltip-right', render: () => <MarketingControlDemo kind="chart-tooltip" side="right" />, code: marketingControlExampleCode('<MarketingControlDemo kind="chart-tooltip" side="right" />') },
2726
+ { id: 'chart-tooltip-left', title: 'chart-tooltip-left', render: () => <MarketingControlDemo kind="chart-tooltip" side="left" />, code: marketingControlExampleCode('<MarketingControlDemo kind="chart-tooltip" side="left" />') },
2727
+ { id: 'chart-tooltip-bottom', title: 'chart-tooltip-bottom', render: () => <MarketingControlDemo kind="chart-tooltip" side="bottom" />, code: marketingControlExampleCode('<MarketingControlDemo kind="chart-tooltip" side="bottom" />') },
2728
+ { id: 'chart-tooltip-top', title: 'chart-tooltip-top', render: () => <MarketingControlDemo kind="chart-tooltip" side="top" />, code: marketingControlExampleCode('<MarketingControlDemo kind="chart-tooltip" side="top" />') },
2729
+ { id: 'selected-button-default', title: 'selected-button-default', render: () => <MarketingControlDemo kind="selected-button" state="default" />, code: marketingControlExampleCode('<MarketingControlDemo kind="selected-button" state="default" />') },
2730
+ { id: 'selected-button-hover', title: 'selected-button-hover', render: () => <MarketingControlDemo kind="selected-button" state="hover" />, code: marketingControlExampleCode('<MarketingControlDemo kind="selected-button" state="hover" />') },
2731
+ { id: 'selected-button-selected', title: 'selected-button-selected', render: () => <MarketingControlDemo kind="selected-button" state="selected" />, code: marketingControlExampleCode('<MarketingControlDemo kind="selected-button" state="selected" />') },
2732
+ { id: 'selected-button-disabled', title: 'selected-button-disabled', render: () => <MarketingControlDemo kind="selected-button" state="disabled" />, code: marketingControlExampleCode('<MarketingControlDemo kind="selected-button" state="disabled" />') },
2733
+ ],
2734
+ }
2735
+
1489
2736
  export const entries: GalleryEntry[] = [
2737
+ marketingControlsEntry,
2738
+ labelEntry,
2739
+ hint_textEntry,
2740
+ fileUploadAreaEntry,
2741
+ fileUploadCardEntry,
2742
+ fileFormatIconEntry,
2743
+ imageUploadEntry,
1490
2744
  inputEntry,
1491
2745
  textareaEntry,
2746
+ phoneNumberEntry,
1492
2747
  selectEntry,
2748
+ dropdownEntry,
1493
2749
  compactSelectEntry,
1494
2750
  inlineSelectEntry,
1495
2751
  inlineInputEntry,
@@ -1504,6 +2760,7 @@ export const entries: GalleryEntry[] = [
1504
2760
  searchInputEntry,
1505
2761
  emailInputEntry,
1506
2762
  passwordInputEntry,
2763
+ passwordStrengthEntry,
1507
2764
  websiteInputEntry,
1508
2765
  amountInputEntry,
1509
2766
  counterInputEntry,
@@ -1514,3 +2771,389 @@ export const entries: GalleryEntry[] = [
1514
2771
  tagInputEntry,
1515
2772
  richEditorEntry,
1516
2773
  ]
2774
+
2775
+ function InputInputsDefaultSample() {
2776
+ const t = useT()
2777
+ return (<div className="w-72">
2778
+ <Input placeholder={t('design_system.gallery.samples.marketing.productName')} />
2779
+ </div>)
2780
+ }
2781
+
2782
+ function InputInputsIconSlotsSample() {
2783
+ const t = useT()
2784
+ return (<>
2785
+ <div className="w-56">
2786
+ <Input leftIcon={<User />} placeholder={t('design_system.gallery.sampleCopy.assignee')} />
2787
+ </div>
2788
+ <div className="w-56">
2789
+ <Input rightIcon={<Info />} placeholder="SKU" />
2790
+ </div>
2791
+ </>)
2792
+ }
2793
+
2794
+ function InputInputsSizesSample() {
2795
+ const t = useT()
2796
+ return (<>
2797
+ <div className="w-44">
2798
+ <Input size="lg" placeholder={t('design_system.gallery.sampleCopy.large')} />
2799
+ </div>
2800
+ <div className="w-44">
2801
+ <Input size="default" placeholder={t('design_system.gallery.examples.aiProduct.default')} />
2802
+ </div>
2803
+ <div className="w-44">
2804
+ <Input size="sm" placeholder={t('design_system.gallery.sampleCopy.small')} />
2805
+ </div>
2806
+ </>)
2807
+ }
2808
+
2809
+ function InputInputsStatesSample() {
2810
+ const t = useT()
2811
+ return (<>
2812
+ <div className="w-56">
2813
+ <Input aria-invalid defaultValue="not-a-number" />
2814
+ </div>
2815
+ <div className="w-56">
2816
+ <Input disabled placeholder={t('design_system.gallery.examples.keyComponents.disabled')} />
2817
+ </div>
2818
+ </>)
2819
+ }
2820
+
2821
+ function TextareaInputsDefaultSample() {
2822
+ const t = useT()
2823
+ return (<div className="w-80">
2824
+ <Textarea placeholder={t('design_system.gallery.sampleCopy.internalNoteForTheFulfillmentTeam')} />
2825
+ </div>)
2826
+ }
2827
+
2828
+ function TextareaInputsStatesSample() {
2829
+ const t = useT()
2830
+ return (<>
2831
+ <div className="w-72">
2832
+ <Textarea aria-invalid defaultValue={t('design_system.gallery.sampleCopy.tooShort')} />
2833
+ </div>
2834
+ <div className="w-72">
2835
+ <Textarea disabled placeholder={t('design_system.gallery.examples.keyComponents.disabled')} />
2836
+ </div>
2837
+ </>)
2838
+ }
2839
+
2840
+ function CompactSelectInputsTriggerLabelSample() {
2841
+ const t = useT()
2842
+ return (<div className="w-44">
2843
+ <Select defaultValue="newest">
2844
+ <CompactSelectTrigger triggerLabel="Sort:">
2845
+ <SelectValue />
2846
+ </CompactSelectTrigger>
2847
+ <SelectContent>
2848
+ <SelectItem value="newest">{t('design_system.gallery.sampleCopy.newest')}</SelectItem>
2849
+ <SelectItem value="oldest">{t('design_system.gallery.sampleCopy.oldest')}</SelectItem>
2850
+ <SelectItem value="value">{t('design_system.gallery.sampleCopy.highestValue')}</SelectItem>
2851
+ </SelectContent>
2852
+ </Select>
2853
+ </div>)
2854
+ }
2855
+
2856
+ function CompactSelectInputsPlainSample() {
2857
+ const t = useT()
2858
+ return (<div className="w-36">
2859
+ <Select defaultValue="table">
2860
+ <CompactSelectTrigger>
2861
+ <SelectValue />
2862
+ </CompactSelectTrigger>
2863
+ <SelectContent>
2864
+ <SelectItem value="table">{t('design_system.gallery.samples.richEditor.labels.table')}</SelectItem>
2865
+ <SelectItem value="board">{t('design_system.gallery.sampleCopy.board')}</SelectItem>
2866
+ </SelectContent>
2867
+ </Select>
2868
+ </div>)
2869
+ }
2870
+
2871
+ function InlineSelectInputsDefaultSample() {
2872
+ const t = useT()
2873
+ return (<div className="w-40">
2874
+ <Select defaultValue="high">
2875
+ <InlineSelectTrigger>
2876
+ <SelectValue />
2877
+ </InlineSelectTrigger>
2878
+ <SelectContent>
2879
+ <SelectItem value="low">{t('design_system.gallery.samples.finance.low')}</SelectItem>
2880
+ <SelectItem value="medium">{t('design_system.gallery.examples.aiProduct.medium')}</SelectItem>
2881
+ <SelectItem value="high">{t('design_system.gallery.samples.finance.high')}</SelectItem>
2882
+ </SelectContent>
2883
+ </Select>
2884
+ </div>)
2885
+ }
2886
+
2887
+ function InlineSelectInputsInvisibleSample() {
2888
+ const t = useT()
2889
+ return (<div className="w-40">
2890
+ <Select defaultValue="draft">
2891
+ <InlineSelectTrigger showBorderOnHover={false}>
2892
+ <SelectValue />
2893
+ </InlineSelectTrigger>
2894
+ <SelectContent>
2895
+ <SelectItem value="draft">{t('design_system.gallery.sampleCopy.draft')}</SelectItem>
2896
+ <SelectItem value="published">{t('design_system.gallery.sampleCopy.published')}</SelectItem>
2897
+ </SelectContent>
2898
+ </Select>
2899
+ </div>)
2900
+ }
2901
+
2902
+ function InlineInputInputsDefaultSample() {
2903
+ const t = useT()
2904
+ return (<div className="w-56">
2905
+ <InlineInput defaultValue={t('design_system.gallery.sampleCopy.auroraDeskLamp')} aria-label={t('design_system.gallery.samples.marketing.productName')} />
2906
+ </div>)
2907
+ }
2908
+
2909
+ function CheckboxInputsStatesSample() {
2910
+ const t = useT()
2911
+ return (<>
2912
+ <Checkbox aria-label={t('design_system.gallery.sampleCopy.unchecked')} />
2913
+ <Checkbox defaultChecked aria-label={t('design_system.gallery.sampleCopy.checked')} />
2914
+ <Checkbox checked="indeterminate" aria-label={t('design_system.gallery.sampleCopy.indeterminate')} />
2915
+ </>)
2916
+ }
2917
+
2918
+ function CheckboxInputsSizesSample() {
2919
+ const t = useT()
2920
+ return (<>
2921
+ <Checkbox size="sm" defaultChecked aria-label={t('design_system.gallery.sampleCopy.small')} />
2922
+ <Checkbox size="md" defaultChecked aria-label={t('design_system.gallery.examples.aiProduct.medium')} />
2923
+ </>)
2924
+ }
2925
+
2926
+ function CheckboxInputsDisabledSample() {
2927
+ const t = useT()
2928
+ return (<>
2929
+ <Checkbox disabled aria-label={t('design_system.gallery.examples.keyComponents.disabled')} />
2930
+ <Checkbox disabled defaultChecked aria-label={t('design_system.gallery.sampleCopy.disabledChecked')} />
2931
+ </>)
2932
+ }
2933
+
2934
+ function CheckboxFieldInputsDefaultSample() {
2935
+ const t = useT()
2936
+ return (<CheckboxField label={t('design_system.gallery.sampleCopy.emailNotifications')} defaultChecked />)
2937
+ }
2938
+
2939
+ function CheckboxFieldInputsWithDescriptionSample() {
2940
+ const t = useT()
2941
+ return (<div className="w-80">
2942
+ <CheckboxField
2943
+ label={t('design_system.gallery.sampleCopy.autoarchive')}
2944
+ sublabel="(recommended)"
2945
+ description={t('design_system.gallery.sampleCopy.closedConversationsMoveToTheArchiveAfter30Days')}
2946
+ />
2947
+ </div>)
2948
+ }
2949
+
2950
+ function CheckboxFieldInputsFlipSample() {
2951
+ const t = useT()
2952
+ return (<div className="w-72">
2953
+ <CheckboxField flip label={t('design_system.gallery.sampleCopy.includeShippingCosts')} defaultChecked />
2954
+ </div>)
2955
+ }
2956
+
2957
+ function RadioInputsGroupSample() {
2958
+ const t = useT()
2959
+ return (<RadioGroup defaultValue="card" className="flex-row gap-3" aria-label={t('design_system.gallery.samples.menu.kind.provider')}>
2960
+ <Radio value="card" aria-label={t('design_system.gallery.sampleCopy.card')} />
2961
+ <Radio value="transfer" aria-label={t('design_system.gallery.sampleCopy.bankTransfer')} />
2962
+ <Radio value="cash" aria-label={t('design_system.gallery.sampleCopy.cash')} />
2963
+ </RadioGroup>)
2964
+ }
2965
+
2966
+ function RadioInputsDisabledSample() {
2967
+ const t = useT()
2968
+ return (<RadioGroup defaultValue="a" disabled className="flex-row gap-3" aria-label={t('design_system.gallery.sampleCopy.disabledGroup')}>
2969
+ <Radio value="a" aria-label={t('design_system.gallery.sampleCopy.selectedDisabled')} />
2970
+ <Radio value="b" aria-label={t('design_system.gallery.sampleCopy.unselectedDisabled')} />
2971
+ </RadioGroup>)
2972
+ }
2973
+
2974
+ function RadioFieldInputsDefaultSample() {
2975
+ const t = useT()
2976
+ return (<RadioGroup defaultValue="standard" aria-label={t('design_system.gallery.sampleCopy.shippingSpeed')}>
2977
+ <RadioField value="standard" label={t('design_system.gallery.sampleCopy.standard')} />
2978
+ <RadioField value="express" label={t('design_system.gallery.sampleCopy.express')} />
2979
+ </RadioGroup>)
2980
+ }
2981
+
2982
+ function RadioFieldInputsWithDescriptionSample() {
2983
+ const t = useT()
2984
+ return (<div className="w-80">
2985
+ <RadioGroup defaultValue="invoice" aria-label={t('design_system.gallery.samples.marketing.billing')}>
2986
+ <RadioField
2987
+ value="invoice"
2988
+ label={t('design_system.gallery.sampleCopy.invoice')}
2989
+ description={t('design_system.gallery.sampleCopy.payWithin14DaysOfDelivery')}
2990
+ />
2991
+ <RadioField
2992
+ value="prepaid"
2993
+ label={t('design_system.gallery.sampleCopy.prepaid')}
2994
+ description={t('design_system.gallery.sampleCopy.orderShipsAfterPaymentClears')}
2995
+ />
2996
+ </RadioGroup>
2997
+ </div>)
2998
+ }
2999
+
3000
+ function SwitchInputsStatesSample() {
3001
+ const t = useT()
3002
+ return (<>
3003
+ <Switch aria-label={t('design_system.gallery.sampleCopy.off')} />
3004
+ <Switch defaultChecked aria-label={t('design_system.gallery.sampleCopy.on')} />
3005
+ </>)
3006
+ }
3007
+
3008
+ function SwitchInputsDisabledSample() {
3009
+ const t = useT()
3010
+ return (<>
3011
+ <Switch disabled aria-label={t('design_system.gallery.sampleCopy.disabledOff')} />
3012
+ <Switch disabled defaultChecked aria-label={t('design_system.gallery.sampleCopy.disabledOn')} />
3013
+ </>)
3014
+ }
3015
+
3016
+ function SwitchFieldInputsDefaultSample() {
3017
+ const t = useT()
3018
+ return (<div className="w-72">
3019
+ <SwitchField label={t('design_system.gallery.sampleCopy.twofactorAuthentication')} defaultChecked />
3020
+ </div>)
3021
+ }
3022
+
3023
+ function SwitchFieldInputsWithDescriptionSample() {
3024
+ const t = useT()
3025
+ return (<div className="w-80">
3026
+ <SwitchField
3027
+ label={t('design_system.gallery.sampleCopy.lowstockAlerts')}
3028
+ description={t('design_system.gallery.sampleCopy.notifyPurchasingWhenStockDropsBelowTheReorderPoint')}
3029
+ />
3030
+ </div>)
3031
+ }
3032
+
3033
+ function SwitchFieldInputsFlipSample() {
3034
+ const t = useT()
3035
+ return (<div className="w-72">
3036
+ <SwitchField flip label={t('design_system.gallery.sampleCopy.syncInventoryNightly')} defaultChecked />
3037
+ </div>)
3038
+ }
3039
+
3040
+ function SliderInputsSingleSample() {
3041
+ const t = useT()
3042
+ return (<div className="w-72">
3043
+ <Slider defaultValue={[40]} min={0} max={100} step={5} aria-label={t('design_system.gallery.sampleCopy.discount')} />
3044
+ </div>)
3045
+ }
3046
+
3047
+ function SliderInputsRangeSample() {
3048
+ const t = useT()
3049
+ return (<div className="w-72">
3050
+ <Slider defaultValue={[20, 60]} min={0} max={100} aria-label={t('design_system.gallery.sampleCopy.priceRange')} />
3051
+ </div>)
3052
+ }
3053
+
3054
+ function SliderInputsDisabledSample() {
3055
+ const t = useT()
3056
+ return (<div className="w-72">
3057
+ <Slider defaultValue={[45]} disabled aria-label={t('design_system.gallery.sampleCopy.disabledSlider')} />
3058
+ </div>)
3059
+ }
3060
+
3061
+ function FormFieldInputsDefaultSample() {
3062
+ const t = useT()
3063
+ return (<div className="w-72">
3064
+ <FormField label={t('design_system.gallery.sampleCopy.warehouseCode')} description={t('design_system.gallery.sampleCopy.shortIdentifierUsedOnLabels')}>
3065
+ <Input placeholder="WAW-01" />
3066
+ </FormField>
3067
+ </div>)
3068
+ }
3069
+
3070
+ function FormFieldInputsRequiredSample() {
3071
+ const t = useT()
3072
+ return (<div className="w-72">
3073
+ <FormField label={t('design_system.gallery.sampleCopy.companyName')} required>
3074
+ <Input placeholder="Acme sp. z o.o." />
3075
+ </FormField>
3076
+ </div>)
3077
+ }
3078
+
3079
+ function FormFieldInputsHorizontalSample() {
3080
+ const t = useT()
3081
+ return (<div className="w-72">
3082
+ <FormField label={t('design_system.gallery.sampleCopy.enableWebhooks')} orientation="horizontal">
3083
+ <Switch defaultChecked />
3084
+ </FormField>
3085
+ </div>)
3086
+ }
3087
+
3088
+ function DigitInputInputsDefaultSample() {
3089
+ const t = useT()
3090
+ return (<DigitInput aria-label={t('design_system.gallery.examples.aiProduct.verification')} className="w-full gap-1 sm:w-auto sm:gap-2" cellClassName="min-w-0 w-8 flex-1 sm:w-14 sm:flex-none" />)
3091
+ }
3092
+
3093
+ function DigitInputInputsStatesSample() {
3094
+ const t = useT()
3095
+ return (<div className="flex flex-col gap-3">
3096
+ <DigitInput length={4} value="4921" aria-invalid aria-label={t('design_system.gallery.sampleCopy.invalidCode')} />
3097
+ <DigitInput length={4} disabled aria-label={t('design_system.gallery.sampleCopy.disabledCode')} />
3098
+ </div>)
3099
+ }
3100
+
3101
+ function ButtonInputInputsCopyLinkSample() {
3102
+ const t = useT()
3103
+ return (<div className="w-80">
3104
+ <ButtonInput
3105
+ readOnly
3106
+ defaultValue="https://app.example.com/i/8f2c"
3107
+ leftIcon={<Link2 />}
3108
+ trailingAction={
3109
+ <IconButton variant="ghost" aria-label={t('design_system.gallery.sampleCopy.copyLink')}>
3110
+ <Copy />
3111
+ </IconButton>
3112
+ }
3113
+ />
3114
+ </div>)
3115
+ }
3116
+
3117
+ function ButtonInputInputsSendSample() {
3118
+ const t = useT()
3119
+ return (<div className="w-80">
3120
+ <ButtonInput
3121
+ placeholder={t('design_system.gallery.sampleCopy.inviteByEmail')}
3122
+ trailingAction={
3123
+ <IconButton variant="ghost" aria-label={t('design_system.gallery.sampleCopy.sendInvite')}>
3124
+ <Send />
3125
+ </IconButton>
3126
+ }
3127
+ />
3128
+ </div>)
3129
+ }
3130
+
3131
+ function TagInputInputsDefaultSample() {
3132
+ const t = useT()
3133
+ return (<DemoTagInput initial={['wholesale', 'priority', 'eu']} placeholder={t('design_system.gallery.sampleCopy.addTag')} />)
3134
+ }
3135
+
3136
+ function TagInputInputsMaxTagsSample() {
3137
+ const t = useT()
3138
+ return (<DemoTagInput initial={['red', 'green', 'blue']} maxTags={3} placeholder={t('design_system.gallery.sampleCopy.addTag')} />)
3139
+ }
3140
+
3141
+ function TextareaInputsCharacterCountSample() {
3142
+ const t = useT()
3143
+ return (<div className="w-80">
3144
+ <Textarea
3145
+ showCount
3146
+ maxLength={200}
3147
+ defaultValue={t('design_system.gallery.sampleCopy.customerPrefersDeliveryAfter4PM')}
3148
+ />
3149
+ </div>)
3150
+ }
3151
+
3152
+ function FormFieldInputsErrorSample() {
3153
+ const t = useT()
3154
+ return (<div className="w-72">
3155
+ <FormField label={t('design_system.gallery.sampleCopy.vatID')} error={t('design_system.gallery.sampleCopy.vatIDMustHave10Digits')}>
3156
+ <Input defaultValue="52601" />
3157
+ </FormField>
3158
+ </div>)
3159
+ }