@telefonica/mistica 16.59.0 → 16.61.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 (544) hide show
  1. package/css/mistica.css +1 -1
  2. package/dist/accordion.css-mistica.js +6 -6
  3. package/dist/align.css-mistica.js +1 -1
  4. package/dist/autocomplete.css-mistica.js +1 -1
  5. package/dist/avatar.css-mistica.js +1 -1
  6. package/dist/badge.css-mistica.js +1 -1
  7. package/dist/box.css-mistica.js +13 -13
  8. package/dist/boxed.css-mistica.js +24 -24
  9. package/dist/button-fixed-footer-layout.d.ts +2 -1
  10. package/dist/button-fixed-footer-layout.js +4 -3
  11. package/dist/button-group.css-mistica.js +1 -1
  12. package/dist/button-layout.css-mistica.js +14 -14
  13. package/dist/button.css-mistica.js +30 -30
  14. package/dist/callout.css-mistica.js +11 -11
  15. package/dist/card-internal.css-mistica.js +15 -15
  16. package/dist/carousel.css-mistica.js +8 -8
  17. package/dist/checkbox.css-mistica.js +11 -11
  18. package/dist/chip.css-mistica.js +15 -15
  19. package/dist/circle.css-mistica.js +1 -1
  20. package/dist/community/advanced-data-card.css-mistica.js +6 -6
  21. package/dist/community/blocks.css-mistica.js +1 -1
  22. package/dist/community/example-component.css-mistica.js +1 -1
  23. package/dist/counter.css-mistica.js +1 -1
  24. package/dist/cover-hero.css-mistica.js +2 -2
  25. package/dist/credit-card-number-field.css-mistica.js +3 -3
  26. package/dist/date-field.css-mistica.js +1 -1
  27. package/dist/date-time-picker.css-mistica.js +1 -1
  28. package/dist/dialog.css-mistica.js +4 -4
  29. package/dist/divider.css-mistica.js +5 -5
  30. package/dist/double-field.css-mistica.js +2 -2
  31. package/dist/drawer.css-mistica.js +1 -1
  32. package/dist/empty-state-card.css-mistica.js +1 -1
  33. package/dist/empty-state.css-mistica.js +5 -5
  34. package/dist/fade-in.css-mistica.js +1 -1
  35. package/dist/feedback.css-mistica.js +1 -1
  36. package/dist/file-upload.css-mistica.js +7 -7
  37. package/dist/fixed-footer-layout.css-mistica.js +2 -2
  38. package/dist/fixed-footer-layout.d.ts +6 -1
  39. package/dist/fixed-footer-layout.js +29 -28
  40. package/dist/form.css-mistica.js +1 -1
  41. package/dist/grid-layout.css-mistica.js +3 -3
  42. package/dist/grid.css-mistica.js +120 -120
  43. package/dist/header.css-mistica.js +1 -1
  44. package/dist/hero.css-mistica.js +2 -2
  45. package/dist/horizontal-scroll.css-mistica.js +1 -1
  46. package/dist/icon-button.css-mistica.js +53 -53
  47. package/dist/icons/icon-chevron.css-mistica.js +2 -2
  48. package/dist/icons/icon-error.css-mistica.js +1 -1
  49. package/dist/image.css-mistica.js +2 -2
  50. package/dist/image.js +8 -1
  51. package/dist/inline.css-mistica.js +9 -9
  52. package/dist/list.css-mistica.js +1 -1
  53. package/dist/loading-bar.css-mistica.js +1 -1
  54. package/dist/loading-screen.css-mistica.js +4 -4
  55. package/dist/logo.css-mistica.js +5 -5
  56. package/dist/menu.css-mistica.js +13 -13
  57. package/dist/mosaic.css-mistica.js +1 -1
  58. package/dist/navigation-bar.css-mistica.js +18 -18
  59. package/dist/navigation-breadcrumbs.css-mistica.js +1 -1
  60. package/dist/package-version.js +1 -1
  61. package/dist/pin-field.css-mistica.js +1 -1
  62. package/dist/popover.css-mistica.js +1 -1
  63. package/dist/progress-bar.css-mistica.js +6 -6
  64. package/dist/radio-button.css-mistica.js +19 -19
  65. package/dist/rating.css-mistica.js +2 -2
  66. package/dist/responsive-layout.css-mistica.js +6 -6
  67. package/dist/screen-reader-only.css-mistica.js +1 -1
  68. package/dist/select.css-mistica.js +15 -15
  69. package/dist/sheet-action-row.css-mistica.js +1 -1
  70. package/dist/sheet-common.css-mistica.js +1 -1
  71. package/dist/sheet-info.css-mistica.js +1 -1
  72. package/dist/skeletons.css-mistica.js +6 -6
  73. package/dist/skins/skin-contract.css-mistica.js +684 -684
  74. package/dist/skip-link.css-mistica.js +1 -1
  75. package/dist/slider.css-mistica.js +18 -18
  76. package/dist/snackbar.css-mistica.js +4 -4
  77. package/dist/spinner.css-mistica.js +1 -1
  78. package/dist/square.css-mistica.js +1 -1
  79. package/dist/stack.css-mistica.js +5 -5
  80. package/dist/stacking-group.css-mistica.js +1 -1
  81. package/dist/stepper.css-mistica.js +2 -2
  82. package/dist/switch-component.css-mistica.js +35 -35
  83. package/dist/table.css-mistica.js +9 -9
  84. package/dist/tabs.css-mistica.js +17 -17
  85. package/dist/tag.css-mistica.js +1 -1
  86. package/dist/text-field-base.css-mistica.js +15 -15
  87. package/dist/text-field-components.css-mistica.js +3 -3
  88. package/dist/text-link.css-mistica.js +6 -6
  89. package/dist/text.css-mistica.js +6 -6
  90. package/dist/theme-context.css-mistica.js +1 -1
  91. package/dist/timeline.css-mistica.js +9 -9
  92. package/dist/timer.css-mistica.js +6 -6
  93. package/dist/tooltip.css-mistica.js +1 -1
  94. package/dist/touchable.css-mistica.js +1 -1
  95. package/dist/utils/aspect-ratio-support.css-mistica.js +2 -2
  96. package/dist/video.css-mistica.js +1 -1
  97. package/dist/vivinho-loading-animation/vivinho-loading-animation.css-mistica.js +1 -1
  98. package/dist-es/accordion.css-mistica.js +6 -6
  99. package/dist-es/align.css-mistica.js +1 -1
  100. package/dist-es/autocomplete.css-mistica.js +1 -1
  101. package/dist-es/avatar.css-mistica.js +1 -1
  102. package/dist-es/badge.css-mistica.js +1 -1
  103. package/dist-es/box.css-mistica.js +13 -13
  104. package/dist-es/boxed.css-mistica.js +23 -23
  105. package/dist-es/button-fixed-footer-layout.js +12 -11
  106. package/dist-es/button-group.css-mistica.js +1 -1
  107. package/dist-es/button-layout.css-mistica.js +14 -14
  108. package/dist-es/button.css-mistica.js +30 -30
  109. package/dist-es/callout.css-mistica.js +11 -11
  110. package/dist-es/card-internal.css-mistica.js +15 -15
  111. package/dist-es/carousel.css-mistica.js +8 -8
  112. package/dist-es/checkbox.css-mistica.js +11 -11
  113. package/dist-es/chip.css-mistica.js +15 -15
  114. package/dist-es/circle.css-mistica.js +1 -1
  115. package/dist-es/community/advanced-data-card.css-mistica.js +6 -6
  116. package/dist-es/community/blocks.css-mistica.js +1 -1
  117. package/dist-es/community/example-component.css-mistica.js +1 -1
  118. package/dist-es/counter.css-mistica.js +1 -1
  119. package/dist-es/cover-hero.css-mistica.js +2 -2
  120. package/dist-es/credit-card-number-field.css-mistica.js +3 -3
  121. package/dist-es/date-field.css-mistica.js +1 -1
  122. package/dist-es/date-time-picker.css-mistica.js +1 -1
  123. package/dist-es/dialog.css-mistica.js +4 -4
  124. package/dist-es/divider.css-mistica.js +5 -5
  125. package/dist-es/double-field.css-mistica.js +2 -2
  126. package/dist-es/drawer.css-mistica.js +1 -1
  127. package/dist-es/empty-state-card.css-mistica.js +1 -1
  128. package/dist-es/empty-state.css-mistica.js +5 -5
  129. package/dist-es/fade-in.css-mistica.js +1 -1
  130. package/dist-es/feedback.css-mistica.js +1 -1
  131. package/dist-es/file-upload.css-mistica.js +7 -7
  132. package/dist-es/fixed-footer-layout.css-mistica.js +2 -2
  133. package/dist-es/fixed-footer-layout.js +57 -56
  134. package/dist-es/form.css-mistica.js +1 -1
  135. package/dist-es/grid-layout.css-mistica.js +3 -3
  136. package/dist-es/grid.css-mistica.js +120 -120
  137. package/dist-es/header.css-mistica.js +1 -1
  138. package/dist-es/hero.css-mistica.js +2 -2
  139. package/dist-es/horizontal-scroll.css-mistica.js +1 -1
  140. package/dist-es/icon-button.css-mistica.js +53 -53
  141. package/dist-es/icons/icon-chevron.css-mistica.js +2 -2
  142. package/dist-es/icons/icon-error.css-mistica.js +1 -1
  143. package/dist-es/image.css-mistica.js +2 -2
  144. package/dist-es/image.js +8 -1
  145. package/dist-es/inline.css-mistica.js +9 -9
  146. package/dist-es/list.css-mistica.js +1 -1
  147. package/dist-es/loading-bar.css-mistica.js +1 -1
  148. package/dist-es/loading-screen.css-mistica.js +4 -4
  149. package/dist-es/logo.css-mistica.js +5 -5
  150. package/dist-es/menu.css-mistica.js +13 -13
  151. package/dist-es/mosaic.css-mistica.js +1 -1
  152. package/dist-es/navigation-bar.css-mistica.js +18 -18
  153. package/dist-es/navigation-breadcrumbs.css-mistica.js +1 -1
  154. package/dist-es/package-version.js +1 -1
  155. package/dist-es/pin-field.css-mistica.js +1 -1
  156. package/dist-es/popover.css-mistica.js +1 -1
  157. package/dist-es/progress-bar.css-mistica.js +6 -6
  158. package/dist-es/radio-button.css-mistica.js +19 -19
  159. package/dist-es/rating.css-mistica.js +2 -2
  160. package/dist-es/responsive-layout.css-mistica.js +6 -6
  161. package/dist-es/screen-reader-only.css-mistica.js +1 -1
  162. package/dist-es/select.css-mistica.js +15 -15
  163. package/dist-es/sheet-action-row.css-mistica.js +1 -1
  164. package/dist-es/sheet-common.css-mistica.js +1 -1
  165. package/dist-es/sheet-info.css-mistica.js +1 -1
  166. package/dist-es/skeletons.css-mistica.js +6 -6
  167. package/dist-es/skins/skin-contract.css-mistica.js +684 -684
  168. package/dist-es/skip-link.css-mistica.js +1 -1
  169. package/dist-es/slider.css-mistica.js +18 -18
  170. package/dist-es/snackbar.css-mistica.js +4 -4
  171. package/dist-es/spinner.css-mistica.js +1 -1
  172. package/dist-es/square.css-mistica.js +1 -1
  173. package/dist-es/stack.css-mistica.js +5 -5
  174. package/dist-es/stacking-group.css-mistica.js +1 -1
  175. package/dist-es/stepper.css-mistica.js +2 -2
  176. package/dist-es/style.css +1 -1
  177. package/dist-es/switch-component.css-mistica.js +35 -35
  178. package/dist-es/table.css-mistica.js +9 -9
  179. package/dist-es/tabs.css-mistica.js +17 -17
  180. package/dist-es/tag.css-mistica.js +1 -1
  181. package/dist-es/text-field-base.css-mistica.js +15 -15
  182. package/dist-es/text-field-components.css-mistica.js +3 -3
  183. package/dist-es/text-link.css-mistica.js +6 -6
  184. package/dist-es/text.css-mistica.js +6 -6
  185. package/dist-es/theme-context.css-mistica.js +1 -1
  186. package/dist-es/timeline.css-mistica.js +9 -9
  187. package/dist-es/timer.css-mistica.js +6 -6
  188. package/dist-es/tooltip.css-mistica.js +1 -1
  189. package/dist-es/touchable.css-mistica.js +1 -1
  190. package/dist-es/utils/aspect-ratio-support.css-mistica.js +2 -2
  191. package/dist-es/video.css-mistica.js +1 -1
  192. package/dist-es/vivinho-loading-animation/vivinho-loading-animation.css-mistica.js +1 -1
  193. package/doc/llms.md +11 -0
  194. package/package.json +14 -2
  195. package/src/accordion.css.ts +121 -0
  196. package/src/accordion.tsx +366 -0
  197. package/src/align.css.ts +7 -0
  198. package/src/align.tsx +32 -0
  199. package/src/autocomplete.css.ts +62 -0
  200. package/src/autocomplete.tsx +239 -0
  201. package/src/avatar.css.ts +14 -0
  202. package/src/avatar.tsx +120 -0
  203. package/src/badge.css.ts +51 -0
  204. package/src/badge.tsx +79 -0
  205. package/src/box.css.ts +51 -0
  206. package/src/box.tsx +114 -0
  207. package/src/boxed.css.ts +132 -0
  208. package/src/boxed.tsx +153 -0
  209. package/src/button-fixed-footer-layout.tsx +65 -0
  210. package/src/button-group.css.ts +75 -0
  211. package/src/button-group.tsx +91 -0
  212. package/src/button-layout.css.ts +162 -0
  213. package/src/button-layout.tsx +91 -0
  214. package/src/button.css.ts +758 -0
  215. package/src/button.tsx +632 -0
  216. package/src/callout.css.ts +50 -0
  217. package/src/callout.tsx +147 -0
  218. package/src/card-cover.tsx +242 -0
  219. package/src/card-data.tsx +152 -0
  220. package/src/card-internal.css.ts +271 -0
  221. package/src/card-internal.tsx +1724 -0
  222. package/src/card-media.tsx +157 -0
  223. package/src/card-naked.tsx +63 -0
  224. package/src/carousel.css.ts +522 -0
  225. package/src/carousel.tsx +1300 -0
  226. package/src/checkbox.css.ts +94 -0
  227. package/src/checkbox.tsx +192 -0
  228. package/src/chip.css.ts +204 -0
  229. package/src/chip.tsx +191 -0
  230. package/src/circle.css.ts +14 -0
  231. package/src/circle.tsx +52 -0
  232. package/src/community/__screenshot_tests__/__image_snapshots__/advanced-data-card-screenshot-test-tsx-advanced-data-card-actions-button-and-link-footer-image-false-1-snap.png +0 -0
  233. package/src/community/__screenshot_tests__/__image_snapshots__/advanced-data-card-screenshot-test-tsx-advanced-data-card-actions-button-and-link-footer-image-true-1-snap.png +0 -0
  234. package/src/community/__screenshot_tests__/__image_snapshots__/advanced-data-card-screenshot-test-tsx-advanced-data-card-actions-button-footer-image-false-1-snap.png +0 -0
  235. package/src/community/__screenshot_tests__/__image_snapshots__/advanced-data-card-screenshot-test-tsx-advanced-data-card-actions-button-footer-image-true-1-snap.png +0 -0
  236. package/src/community/__screenshot_tests__/__image_snapshots__/advanced-data-card-screenshot-test-tsx-advanced-data-card-actions-link-footer-image-false-1-snap.png +0 -0
  237. package/src/community/__screenshot_tests__/__image_snapshots__/advanced-data-card-screenshot-test-tsx-advanced-data-card-actions-link-footer-image-true-1-snap.png +0 -0
  238. package/src/community/__screenshot_tests__/__image_snapshots__/advanced-data-card-screenshot-test-tsx-advanced-data-card-actions-none-footer-image-false-1-snap.png +0 -0
  239. package/src/community/__screenshot_tests__/__image_snapshots__/advanced-data-card-screenshot-test-tsx-advanced-data-card-actions-none-footer-image-true-1-snap.png +0 -0
  240. package/src/community/__screenshot_tests__/__image_snapshots__/advanced-data-card-screenshot-test-tsx-advanced-data-card-extras-0-1-snap.png +0 -0
  241. package/src/community/__screenshot_tests__/__image_snapshots__/advanced-data-card-screenshot-test-tsx-advanced-data-card-extras-1-1-snap.png +0 -0
  242. package/src/community/__screenshot_tests__/__image_snapshots__/advanced-data-card-screenshot-test-tsx-advanced-data-card-extras-3-1-snap.png +0 -0
  243. package/src/community/__screenshot_tests__/__image_snapshots__/advanced-data-card-screenshot-test-tsx-advanced-data-card-extras-3-no-divider-1-snap.png +0 -0
  244. package/src/community/__screenshot_tests__/__image_snapshots__/advanced-data-card-screenshot-test-tsx-advanced-data-card-inside-carousel-1-snap.png +0 -0
  245. package/src/community/__screenshot_tests__/__image_snapshots__/advanced-data-card-screenshot-test-tsx-advanced-data-card-without-stacking-group-with-top-actions-and-too-long-title-1-snap.png +0 -0
  246. package/src/community/__screenshot_tests__/__image_snapshots__/blocks-screenshot-test-tsx-blocks-highlighted-value-block-1-snap.png +0 -0
  247. package/src/community/__screenshot_tests__/__image_snapshots__/blocks-screenshot-test-tsx-blocks-information-block-1-snap.png +0 -0
  248. package/src/community/__screenshot_tests__/__image_snapshots__/blocks-screenshot-test-tsx-blocks-progress-block-1-snap.png +0 -0
  249. package/src/community/__screenshot_tests__/__image_snapshots__/blocks-screenshot-test-tsx-blocks-progress-block-2-snap.png +0 -0
  250. package/src/community/__screenshot_tests__/__image_snapshots__/blocks-screenshot-test-tsx-blocks-row-block-1-snap.png +0 -0
  251. package/src/community/__screenshot_tests__/__image_snapshots__/blocks-screenshot-test-tsx-blocks-simple-block-1-snap.png +0 -0
  252. package/src/community/__screenshot_tests__/__image_snapshots__/blocks-screenshot-test-tsx-blocks-value-block-1-snap.png +0 -0
  253. package/src/community/__screenshot_tests__/advanced-data-card-screenshot-test.tsx +84 -0
  254. package/src/community/__screenshot_tests__/blocks-screenshot-test.tsx +72 -0
  255. package/src/community/__stories__/advanced-data-card-carousel-story.tsx +66 -0
  256. package/src/community/__stories__/advanced-data-card-story.tsx +158 -0
  257. package/src/community/__stories__/blocks-story.tsx +272 -0
  258. package/src/community/__stories__/example-component-story.tsx +15 -0
  259. package/src/community/__stories__/index-story.tsx +154 -0
  260. package/src/community/__type_tests__/advanced-data-card-type-test.tsx +40 -0
  261. package/src/community/advanced-data-card.css.ts +271 -0
  262. package/src/community/advanced-data-card.tsx +431 -0
  263. package/src/community/blocks.css.ts +12 -0
  264. package/src/community/blocks.tsx +290 -0
  265. package/src/community/example-component.css.ts +7 -0
  266. package/src/community/example-component.tsx +17 -0
  267. package/src/community/index.tsx +10 -0
  268. package/src/counter.css.ts +150 -0
  269. package/src/counter.tsx +215 -0
  270. package/src/cover-hero-media.tsx +39 -0
  271. package/src/cover-hero.css.ts +133 -0
  272. package/src/cover-hero.tsx +262 -0
  273. package/src/credit-card-expiration-field.tsx +187 -0
  274. package/src/credit-card-fields.tsx +56 -0
  275. package/src/credit-card-number-field.css.ts +47 -0
  276. package/src/credit-card-number-field.tsx +245 -0
  277. package/src/cvv-field.tsx +169 -0
  278. package/src/date-field.css.ts +14 -0
  279. package/src/date-field.tsx +130 -0
  280. package/src/date-time-field.tsx +141 -0
  281. package/src/date-time-picker.css.ts +126 -0
  282. package/src/date-time-picker.tsx +188 -0
  283. package/src/decimal-field.tsx +160 -0
  284. package/src/desktop-container-type-context.tsx +15 -0
  285. package/src/dialog-context.tsx +81 -0
  286. package/src/dialog.css.ts +155 -0
  287. package/src/dialog.tsx +423 -0
  288. package/src/divider.css.ts +10 -0
  289. package/src/divider.tsx +11 -0
  290. package/src/double-field.css.ts +33 -0
  291. package/src/double-field.tsx +71 -0
  292. package/src/drawer.css.ts +123 -0
  293. package/src/drawer.tsx +304 -0
  294. package/src/email-field.tsx +76 -0
  295. package/src/empty-state-card.css.ts +40 -0
  296. package/src/empty-state-card.tsx +92 -0
  297. package/src/empty-state.css.ts +119 -0
  298. package/src/empty-state.tsx +141 -0
  299. package/src/fade-in.css.ts +12 -0
  300. package/src/fade-in.tsx +40 -0
  301. package/src/feedback.css.ts +119 -0
  302. package/src/feedback.tsx +432 -0
  303. package/src/file-upload.css.ts +156 -0
  304. package/src/file-upload.tsx +612 -0
  305. package/src/fixed-footer-layout.css.ts +96 -0
  306. package/src/fixed-footer-layout.tsx +227 -0
  307. package/src/fixed-to-top.tsx +21 -0
  308. package/src/focus-trap.tsx +17 -0
  309. package/src/form-context.tsx +198 -0
  310. package/src/form.css.ts +5 -0
  311. package/src/form.tsx +287 -0
  312. package/src/grid-layout.css.ts +68 -0
  313. package/src/grid-layout.tsx +201 -0
  314. package/src/grid.css.ts +203 -0
  315. package/src/grid.tsx +241 -0
  316. package/src/header.css.ts +30 -0
  317. package/src/header.tsx +319 -0
  318. package/src/hero.css.ts +71 -0
  319. package/src/hero.tsx +318 -0
  320. package/src/hooks.tsx +313 -0
  321. package/src/horizontal-scroll.css.ts +43 -0
  322. package/src/horizontal-scroll.tsx +18 -0
  323. package/src/iban-field.tsx +218 -0
  324. package/src/icon-button.css.ts +561 -0
  325. package/src/icon-button.tsx +221 -0
  326. package/src/icons/__stories__/mistica-icons-story.tsx +192 -0
  327. package/src/icons/icon-amex.tsx +40 -0
  328. package/src/icons/icon-chevron.css.ts +23 -0
  329. package/src/icons/icon-chevron.tsx +150 -0
  330. package/src/icons/icon-cvv-amex.tsx +31 -0
  331. package/src/icons/icon-cvv-visa-mc.tsx +31 -0
  332. package/src/icons/icon-error.css.ts +27 -0
  333. package/src/icons/icon-error.tsx +207 -0
  334. package/src/icons/icon-info.tsx +86 -0
  335. package/src/icons/icon-mastercard.tsx +36 -0
  336. package/src/icons/icon-success-vivo-new.tsx +51 -0
  337. package/src/icons/icon-success-vivo.tsx +36 -0
  338. package/src/icons/icon-success.tsx +211 -0
  339. package/src/icons/icon-visa.tsx +32 -0
  340. package/src/image.css.ts +48 -0
  341. package/src/image.tsx +352 -0
  342. package/src/index.tsx +2466 -0
  343. package/src/inline.css.ts +131 -0
  344. package/src/inline.tsx +135 -0
  345. package/src/integer-field.tsx +93 -0
  346. package/src/list.css.ts +281 -0
  347. package/src/list.tsx +963 -0
  348. package/src/loading-bar.css.ts +69 -0
  349. package/src/loading-bar.tsx +25 -0
  350. package/src/loading-screen.css.ts +114 -0
  351. package/src/loading-screen.tsx +376 -0
  352. package/src/logo-blau-shell.tsx +30 -0
  353. package/src/logo-blau.tsx +60 -0
  354. package/src/logo-common.tsx +29 -0
  355. package/src/logo-esimflag-shell.tsx +30 -0
  356. package/src/logo-esimflag.tsx +56 -0
  357. package/src/logo-movistar-new-shell.tsx +30 -0
  358. package/src/logo-movistar-new.tsx +85 -0
  359. package/src/logo-movistar-shell.tsx +30 -0
  360. package/src/logo-movistar.tsx +63 -0
  361. package/src/logo-o2-new-shell.tsx +26 -0
  362. package/src/logo-o2-new.tsx +27 -0
  363. package/src/logo-o2-shell.tsx +26 -0
  364. package/src/logo-o2.tsx +27 -0
  365. package/src/logo-telefonica-shell.tsx +30 -0
  366. package/src/logo-telefonica.tsx +95 -0
  367. package/src/logo-tu-shell.tsx +26 -0
  368. package/src/logo-tu.tsx +28 -0
  369. package/src/logo-vivo-shell.tsx +30 -0
  370. package/src/logo-vivo.tsx +53 -0
  371. package/src/logo.css.ts +33 -0
  372. package/src/logo.tsx +313 -0
  373. package/src/master-detail-layout.tsx +28 -0
  374. package/src/maybe-dismissable.css.ts +37 -0
  375. package/src/maybe-dismissable.tsx +58 -0
  376. package/src/media-queries.css.ts +67 -0
  377. package/src/menu.css.ts +132 -0
  378. package/src/menu.tsx +468 -0
  379. package/src/meter.tsx +516 -0
  380. package/src/modal-context-provider.tsx +45 -0
  381. package/src/month-field.tsx +124 -0
  382. package/src/mosaic.css.ts +73 -0
  383. package/src/mosaic.tsx +205 -0
  384. package/src/navigation-bar.css.ts +558 -0
  385. package/src/navigation-bar.tsx +1637 -0
  386. package/src/navigation-breadcrumbs.css.ts +22 -0
  387. package/src/navigation-breadcrumbs.tsx +69 -0
  388. package/src/negative-box.tsx +15 -0
  389. package/src/nestable-context.tsx +139 -0
  390. package/src/overlay.tsx +86 -0
  391. package/src/overscroll-color-context.tsx +141 -0
  392. package/src/package-version.tsx +2 -0
  393. package/src/password-field.tsx +126 -0
  394. package/src/phone-number-field-lite.tsx +265 -0
  395. package/src/phone-number-field.tsx +171 -0
  396. package/src/pin-field.css.ts +90 -0
  397. package/src/pin-field.tsx +346 -0
  398. package/src/placeholder.tsx +41 -0
  399. package/src/popover.css.ts +8 -0
  400. package/src/popover.tsx +85 -0
  401. package/src/portal.tsx +43 -0
  402. package/src/progress-bar.css.ts +61 -0
  403. package/src/progress-bar.tsx +174 -0
  404. package/src/radio-button.css.ts +174 -0
  405. package/src/radio-button.tsx +322 -0
  406. package/src/rating.css.ts +128 -0
  407. package/src/rating.tsx +351 -0
  408. package/src/responsive-layout.css.ts +162 -0
  409. package/src/responsive-layout.tsx +106 -0
  410. package/src/screen-reader-only.css.ts +27 -0
  411. package/src/screen-reader-only.tsx +33 -0
  412. package/src/screen-size-context-provider.tsx +96 -0
  413. package/src/screen-size-context.tsx +23 -0
  414. package/src/search-field.tsx +126 -0
  415. package/src/select.css.ts +226 -0
  416. package/src/select.tsx +513 -0
  417. package/src/sheet-action-row.css.ts +33 -0
  418. package/src/sheet-actions-list.tsx +113 -0
  419. package/src/sheet-actions.tsx +95 -0
  420. package/src/sheet-common.css.ts +254 -0
  421. package/src/sheet-common.tsx +402 -0
  422. package/src/sheet-info.css.ts +19 -0
  423. package/src/sheet-info.tsx +127 -0
  424. package/src/sheet-native.tsx +189 -0
  425. package/src/sheet-radio-list.tsx +118 -0
  426. package/src/sheet-root.tsx +127 -0
  427. package/src/sheet-types.tsx +94 -0
  428. package/src/sheet-web.tsx +140 -0
  429. package/src/skeleton-base.tsx +38 -0
  430. package/src/skeletons.css.ts +56 -0
  431. package/src/skeletons.tsx +133 -0
  432. package/src/skins/blau.tsx +724 -0
  433. package/src/skins/constants.tsx +10 -0
  434. package/src/skins/defaults.tsx +104 -0
  435. package/src/skins/esimflag.tsx +728 -0
  436. package/src/skins/movistar-new.tsx +735 -0
  437. package/src/skins/movistar.tsx +740 -0
  438. package/src/skins/o2-new.tsx +731 -0
  439. package/src/skins/o2.tsx +727 -0
  440. package/src/skins/skin-contract.css.ts +380 -0
  441. package/src/skins/telefonica.tsx +768 -0
  442. package/src/skins/tu.tsx +741 -0
  443. package/src/skins/types/colors.tsx +286 -0
  444. package/src/skins/types/index.tsx +153 -0
  445. package/src/skins/utils.tsx +66 -0
  446. package/src/skins/vivo-new.tsx +745 -0
  447. package/src/skins/vivo.tsx +720 -0
  448. package/src/skip-link.css.ts +34 -0
  449. package/src/skip-link.tsx +52 -0
  450. package/src/slider.css.ts +181 -0
  451. package/src/slider.tsx +384 -0
  452. package/src/snackbar-context.tsx +98 -0
  453. package/src/snackbar-native.ts +37 -0
  454. package/src/snackbar.css.ts +176 -0
  455. package/src/snackbar.tsx +258 -0
  456. package/src/spinner.css.ts +66 -0
  457. package/src/spinner.tsx +136 -0
  458. package/src/sprinkles.css.ts +83 -0
  459. package/src/square.css.ts +15 -0
  460. package/src/square.tsx +55 -0
  461. package/src/stack.css.ts +44 -0
  462. package/src/stack.tsx +79 -0
  463. package/src/stacking-group.css.ts +15 -0
  464. package/src/stacking-group.tsx +82 -0
  465. package/src/stepper.css.ts +233 -0
  466. package/src/stepper.tsx +156 -0
  467. package/src/switch-component.css.ts +181 -0
  468. package/src/switch-component.tsx +187 -0
  469. package/src/tab-focus.tsx +68 -0
  470. package/src/table-actions-header.tsx +21 -0
  471. package/src/table-cell-text.tsx +35 -0
  472. package/src/table.css.ts +297 -0
  473. package/src/table.tsx +398 -0
  474. package/src/tabs.css.ts +212 -0
  475. package/src/tabs.tsx +263 -0
  476. package/src/tag.css.ts +42 -0
  477. package/src/tag.tsx +161 -0
  478. package/src/test-utils/environment/setup-ssr.tsx +10 -0
  479. package/src/test-utils/fail-test-on-console-error.tsx +22 -0
  480. package/src/test-utils/index.tsx +341 -0
  481. package/src/test-utils/setup-ssr-test-env.tsx +13 -0
  482. package/src/test-utils/ssr.tsx +197 -0
  483. package/src/text-field-base.css.ts +416 -0
  484. package/src/text-field-base.tsx +628 -0
  485. package/src/text-field-components.css.ts +165 -0
  486. package/src/text-field-components.tsx +230 -0
  487. package/src/text-field.tsx +118 -0
  488. package/src/text-link.css.ts +83 -0
  489. package/src/text-link.tsx +85 -0
  490. package/src/text-tokens.tsx +708 -0
  491. package/src/text.css.ts +60 -0
  492. package/src/text.tsx +516 -0
  493. package/src/theme-context-provider.tsx +370 -0
  494. package/src/theme-context.css.ts +3 -0
  495. package/src/theme-context.tsx +8 -0
  496. package/src/theme-variant-context.tsx +51 -0
  497. package/src/theme.tsx +184 -0
  498. package/src/time-field.tsx +99 -0
  499. package/src/timeline.css.ts +135 -0
  500. package/src/timeline.tsx +250 -0
  501. package/src/timer.css.ts +99 -0
  502. package/src/timer.tsx +420 -0
  503. package/src/title.tsx +119 -0
  504. package/src/tooltip-context-provider.tsx +57 -0
  505. package/src/tooltip.css.ts +106 -0
  506. package/src/tooltip.tsx +649 -0
  507. package/src/touchable.css.ts +56 -0
  508. package/src/touchable.tsx +355 -0
  509. package/src/types/font-face.d.ts +47 -0
  510. package/src/types/libs.d.ts +3 -0
  511. package/src/utils/__tests__/analytics-test.tsx +35 -0
  512. package/src/utils/__tests__/browser-test.tsx +28 -0
  513. package/src/utils/__tests__/dom-test.tsx +23 -0
  514. package/src/utils/__tests__/helpers-test.tsx +166 -0
  515. package/src/utils/analytics.tsx +28 -0
  516. package/src/utils/animation.tsx +201 -0
  517. package/src/utils/aspect-ratio-support.css.ts +28 -0
  518. package/src/utils/aspect-ratio-support.tsx +141 -0
  519. package/src/utils/browser.tsx +9 -0
  520. package/src/utils/color.tsx +46 -0
  521. package/src/utils/common.tsx +27 -0
  522. package/src/utils/credit-card.tsx +46 -0
  523. package/src/utils/css.tsx +25 -0
  524. package/src/utils/document-visibility.tsx +52 -0
  525. package/src/utils/dom.tsx +155 -0
  526. package/src/utils/environment.tsx +6 -0
  527. package/src/utils/headings.tsx +18 -0
  528. package/src/utils/helpers.tsx +182 -0
  529. package/src/utils/keys.tsx +8 -0
  530. package/src/utils/locale.tsx +27 -0
  531. package/src/utils/platform.tsx +94 -0
  532. package/src/utils/region-code.tsx +1 -0
  533. package/src/utils/renders-element.tsx +6 -0
  534. package/src/utils/time.tsx +22 -0
  535. package/src/utils/types.tsx +19 -0
  536. package/src/utils/utility-types.tsx +8 -0
  537. package/src/video.css.ts +11 -0
  538. package/src/video.tsx +355 -0
  539. package/src/vivinho-loading-animation/in-lottie.json +402 -0
  540. package/src/vivinho-loading-animation/index.tsx +90 -0
  541. package/src/vivinho-loading-animation/out-lottie.json +575 -0
  542. package/src/vivinho-loading-animation/pulse-lottie.json +551 -0
  543. package/src/vivinho-loading-animation/vivinho-loading-animation.css.ts +15 -0
  544. package/src/vivinho-loading-animation/wave-lottie.json +2829 -0
package/src/list.tsx ADDED
@@ -0,0 +1,963 @@
1
+ /*
2
+ * Specs:
3
+ * - Structure: https://www.figma.com/file/Be8QB9onmHunKCCAkIBAVr/Lists-Component-Specs?node-id=0%3A2
4
+ * - Behavior: https://www.figma.com/file/Be8QB9onmHunKCCAkIBAVr/Lists-Component-Specs?node-id=0%3A608
5
+ * - Assets: https://www.figma.com/file/Be8QB9onmHunKCCAkIBAVr/Lists-Component-Specs?node-id=0%3A1
6
+ */
7
+
8
+ 'use client';
9
+ import * as React from 'react';
10
+ import classNames from 'classnames';
11
+ import {BaseTouchable} from './touchable';
12
+ import {Text, Text2, Text1} from './text';
13
+ import Box from './box';
14
+ import Stack from './stack';
15
+ import Badge from './badge';
16
+ import {useThemeVariant} from './theme-variant-context';
17
+ import IconChevronRightFilled from './generated/mistica-icons/icon-chevron-right-filled';
18
+ import Switch from './switch-component';
19
+ import RadioButton, {useRadioContext} from './radio-button';
20
+ import Checkbox from './checkbox';
21
+ import {InternalBoxed} from './boxed';
22
+ import Divider from './divider';
23
+ import {getPrefixedDataAttributes} from './utils/dom';
24
+ import * as styles from './list.css';
25
+ import * as mediaStyles from './image.css';
26
+ import {vars} from './skins/skin-contract.css';
27
+ import {applyCssVars} from './utils/css';
28
+ import {IconButton, ToggleIconButton} from './icon-button';
29
+ import ScreenReaderOnly from './screen-reader-only';
30
+ import {useTheme} from './hooks';
31
+
32
+ import type {IconButtonProps, ToggleIconButtonProps} from './icon-button';
33
+ import type {TouchableElement, TouchableProps} from './touchable';
34
+ import type {DataAttributes, TrackingEvent, IconProps} from './utils/types';
35
+ import type {ExclusifyUnion} from './utils/utility-types';
36
+
37
+ type Right = (({centerY}: {centerY: boolean}) => React.ReactNode) | React.ReactNode;
38
+
39
+ interface CommonProps {
40
+ children?: void; // no children allowed
41
+ headline?: string | React.ReactNode;
42
+ title: string;
43
+ titleAs?: string;
44
+ titleLinesMax?: number;
45
+ subtitle?: string;
46
+ subtitleLinesMax?: number;
47
+ description?: string | null;
48
+ descriptionLinesMax?: number;
49
+ detail?: string;
50
+ asset?: React.ReactNode;
51
+ badge?: boolean | number;
52
+ role?: string;
53
+ touchableRole?: string;
54
+ extra?: React.ReactNode;
55
+ dataAttributes?: DataAttributes;
56
+ disabled?: boolean;
57
+ withChevron?: boolean;
58
+ 'aria-label'?: string;
59
+ right?: Right;
60
+ danger?: boolean;
61
+ tabIndex?: number;
62
+ }
63
+
64
+ const renderRight = (right: Right, centerY: boolean) => {
65
+ if (typeof right === 'function') return right?.({centerY});
66
+
67
+ return centerY ? (
68
+ <div style={{display: 'flex', alignItems: 'center', height: '100%'}}>
69
+ <div>{right}</div>
70
+ </div>
71
+ ) : (
72
+ right
73
+ );
74
+ };
75
+
76
+ interface ContentProps extends CommonProps {
77
+ headlineRef?: React.Ref<HTMLDivElement>;
78
+ rightRef?: React.Ref<HTMLDivElement>;
79
+ extraRef?: React.Ref<HTMLDivElement>;
80
+ control?: React.ReactNode;
81
+ /** This id is to link the title with the related control */
82
+ labelId?: string;
83
+ }
84
+
85
+ export const Content = ({
86
+ withChevron,
87
+ headline,
88
+ headlineRef,
89
+ extraRef,
90
+ title,
91
+ titleAs,
92
+ titleLinesMax,
93
+ subtitle,
94
+ subtitleLinesMax,
95
+ description,
96
+ descriptionLinesMax,
97
+ detail,
98
+ asset,
99
+ danger,
100
+ badge,
101
+ right,
102
+ rightRef,
103
+ extra,
104
+ labelId,
105
+ disabled,
106
+ control,
107
+ }: ContentProps): JSX.Element => {
108
+ const outsideVariant = useThemeVariant();
109
+ const numTextLines = [headline, title, subtitle, description, extra].filter(Boolean).length;
110
+ const centerY = numTextLines === 1;
111
+ const {textPresets} = useTheme();
112
+
113
+ return (
114
+ <div className={styles.content} id={labelId}>
115
+ {asset && (
116
+ <div
117
+ className={classNames(styles.assetContainer, {
118
+ [styles.center]: centerY,
119
+ [styles.disabled]: disabled,
120
+ })}
121
+ // We don't want asset to be readable by screen readers
122
+ aria-hidden
123
+ data-testid="asset"
124
+ >
125
+ <div
126
+ className={styles.asset}
127
+ style={applyCssVars({
128
+ color: danger
129
+ ? {
130
+ default: vars.colors.textError,
131
+ alternative: vars.colors.textError,
132
+ brand: vars.colors.textErrorBrand,
133
+ negative: vars.colors.textErrorNegative,
134
+ media: vars.colors.textErrorBrand,
135
+ }[outsideVariant]
136
+ : {
137
+ default: vars.colors.textPrimary,
138
+ alternative: vars.colors.textPrimary,
139
+ brand: vars.colors.textPrimaryBrand,
140
+ negative: vars.colors.textPrimaryNegative,
141
+ media: vars.colors.textPrimaryMedia,
142
+ }[outsideVariant],
143
+ [mediaStyles.vars.mediaBorderRadius]: vars.borderRadii.mediaSmall,
144
+ })}
145
+ >
146
+ {asset}
147
+ </div>
148
+ </div>
149
+ )}
150
+
151
+ <div
152
+ className={classNames(styles.rowBody, {[styles.disabled]: disabled})}
153
+ style={{justifyContent: centerY ? 'center' : 'flex-start'}}
154
+ >
155
+ <Text
156
+ mobileSize={textPresets.text3.size.mobile}
157
+ desktopSize={textPresets.text3.size.desktop}
158
+ mobileLineHeight={textPresets.text3.lineHeight.mobile}
159
+ desktopLineHeight={textPresets.text3.lineHeight.desktop}
160
+ weight={textPresets.rowTitle.weight}
161
+ color={danger ? vars.colors.textError : vars.colors.textPrimary}
162
+ truncate={titleLinesMax}
163
+ hyphens="auto"
164
+ as={titleAs}
165
+ dataAttributes={{testid: 'title'}}
166
+ >
167
+ {title}
168
+ </Text>
169
+ {headline && (
170
+ <div ref={headlineRef} style={{order: -1, paddingBottom: 4}}>
171
+ <Text1
172
+ regular
173
+ color={vars.colors.textPrimary}
174
+ hyphens="auto"
175
+ dataAttributes={{testid: 'headline'}}
176
+ >
177
+ {headline}
178
+ </Text1>
179
+ </div>
180
+ )}
181
+ {subtitle && (
182
+ <Box paddingTop={2}>
183
+ <Text2
184
+ regular
185
+ color={vars.colors.textPrimary}
186
+ truncate={subtitleLinesMax}
187
+ hyphens="auto"
188
+ dataAttributes={{testid: 'subtitle'}}
189
+ >
190
+ {subtitle}
191
+ </Text2>
192
+ </Box>
193
+ )}
194
+ {description && (
195
+ <Box paddingTop={2}>
196
+ <Text2
197
+ regular
198
+ color={vars.colors.textSecondary}
199
+ truncate={descriptionLinesMax}
200
+ hyphens="auto"
201
+ dataAttributes={{testid: 'description'}}
202
+ >
203
+ {description}
204
+ </Text2>
205
+ </Box>
206
+ )}
207
+ {extra && (
208
+ <Box ref={extraRef} paddingTop={2} dataAttributes={{testid: 'slot'}}>
209
+ {extra}
210
+ </Box>
211
+ )}
212
+ </div>
213
+
214
+ {badge && (
215
+ <Box paddingLeft={16}>
216
+ <div className={classNames(styles.badge, {[styles.disabled]: disabled})}>
217
+ <Badge value={badge === true ? undefined : badge} />
218
+ </div>
219
+ </Box>
220
+ )}
221
+
222
+ {(detail || right || withChevron || control) && (
223
+ <div className={classNames(styles.rightContent, {[styles.rightRestrictedWidth]: !!detail})}>
224
+ {detail && (
225
+ <div className={classNames(styles.detail, {[styles.disabled]: disabled})}>
226
+ <Text2
227
+ regular
228
+ color={vars.colors.textSecondary}
229
+ hyphens="auto"
230
+ dataAttributes={{testid: 'detail'}}
231
+ >
232
+ {detail}
233
+ </Text2>
234
+ </div>
235
+ )}
236
+
237
+ {right && (
238
+ <div
239
+ className={classNames({
240
+ [styles.detailRight]: !!detail,
241
+ [styles.disabled]: disabled,
242
+ })}
243
+ ref={rightRef}
244
+ data-testid="endSlot"
245
+ >
246
+ {renderRight(right, centerY)}
247
+ </div>
248
+ )}
249
+
250
+ {withChevron && (
251
+ <div
252
+ style={{paddingLeft: detail || right ? 4 : 0}}
253
+ className={classNames(styles.center, {[styles.disabled]: disabled})}
254
+ data-testid="chevron"
255
+ >
256
+ <IconChevronRightFilled
257
+ size={16}
258
+ color={
259
+ {
260
+ default: vars.colors.chevronIndicator,
261
+ alternative: vars.colors.chevronIndicator,
262
+ brand: vars.colors.textSecondaryBrand,
263
+ negative: vars.colors.textSecondaryNegative,
264
+ media: vars.colors.textSecondaryBrand,
265
+ }[outsideVariant]
266
+ }
267
+ />
268
+ </div>
269
+ )}
270
+
271
+ {control && (
272
+ <div style={{paddingLeft: detail || right ? 8 : 0}} className={styles.center}>
273
+ {control}
274
+ </div>
275
+ )}
276
+ </div>
277
+ )}
278
+ </div>
279
+ );
280
+ };
281
+
282
+ type ControlProps = {
283
+ name?: string;
284
+ value?: boolean;
285
+ defaultValue?: boolean;
286
+ onChange?: (checked: boolean) => void;
287
+ };
288
+
289
+ interface BasicRowContentProps extends CommonProps {
290
+ atomicReading?: boolean;
291
+ }
292
+
293
+ interface SwitchRowContentProps extends CommonProps {
294
+ onPress?: (() => void) | undefined;
295
+ trackingEvent?: TrackingEvent | ReadonlyArray<TrackingEvent>;
296
+
297
+ switch: ControlProps | undefined;
298
+ }
299
+
300
+ interface CheckboxRowContentProps extends CommonProps {
301
+ onPress?: (() => void) | undefined;
302
+ trackingEvent?: TrackingEvent | ReadonlyArray<TrackingEvent>;
303
+
304
+ checkbox: ControlProps | undefined;
305
+ }
306
+
307
+ interface RadioRowContentProps extends CommonProps {
308
+ onPress?: (() => void) | undefined;
309
+ trackingEvent?: TrackingEvent | ReadonlyArray<TrackingEvent>;
310
+
311
+ radioValue: string;
312
+ }
313
+
314
+ interface IconButtonRowContentProps extends CommonProps {
315
+ onPress?: (() => void) | undefined;
316
+ trackingEvent?: TrackingEvent | ReadonlyArray<TrackingEvent>;
317
+
318
+ iconButton: ExclusifyUnion<IconButtonProps | ToggleIconButtonProps> | undefined;
319
+ }
320
+
321
+ type TouchableCommonProps = {
322
+ trackingEvent?: TrackingEvent | ReadonlyArray<TrackingEvent>;
323
+ 'aria-label'?: string;
324
+ 'aria-labelledby'?: string;
325
+ 'aria-description'?: string;
326
+ 'aria-describedby'?: string;
327
+ 'aria-current'?: React.AriaAttributes['aria-current'];
328
+ };
329
+
330
+ interface HrefRowContentProps extends CommonProps, TouchableCommonProps {
331
+ href: string | undefined;
332
+ newTab?: boolean;
333
+ loadOnTop?: boolean;
334
+ onNavigate?: () => void | Promise<void>;
335
+ }
336
+
337
+ interface ToRowContentProps extends CommonProps, TouchableCommonProps {
338
+ to: string | undefined;
339
+ newTab?: boolean;
340
+ fullPageOnWebView?: boolean;
341
+ replace?: boolean;
342
+ onNavigate?: () => void | Promise<void>;
343
+ }
344
+
345
+ interface OnPressRowContentProps extends CommonProps, TouchableCommonProps {
346
+ onPress: (() => void) | undefined;
347
+ }
348
+
349
+ type RowContentProps = ExclusifyUnion<
350
+ | BasicRowContentProps
351
+ | SwitchRowContentProps
352
+ | RadioRowContentProps
353
+ | IconButtonRowContentProps
354
+ | CheckboxRowContentProps
355
+ | HrefRowContentProps
356
+ | ToRowContentProps
357
+ | OnPressRowContentProps
358
+ >;
359
+
360
+ const useControlState = ({
361
+ value,
362
+ defaultValue,
363
+ onChange,
364
+ }: {
365
+ value?: boolean;
366
+ defaultValue?: boolean;
367
+ onChange?: (isChecked: boolean) => void;
368
+ }): [boolean, () => void] => {
369
+ const isControlledByParent = value !== undefined;
370
+ const [isChecked, setIsChecked] = React.useState<boolean>(!!defaultValue);
371
+
372
+ const toggle = () => {
373
+ if (!isControlledByParent) {
374
+ setIsChecked(!isChecked);
375
+ }
376
+ onChange?.(isControlledByParent ? !value : !isChecked);
377
+ };
378
+
379
+ return [isControlledByParent ? !!value : isChecked, toggle];
380
+ };
381
+
382
+ const hasControlProps = (
383
+ obj: any
384
+ ): obj is
385
+ | SwitchRowContentProps
386
+ | CheckboxRowContentProps
387
+ | RadioRowContentProps
388
+ | IconButtonRowContentProps => {
389
+ return ['switch', 'checkbox', 'radioValue', 'iconButton'].some((prop) => obj[prop] !== undefined);
390
+ };
391
+
392
+ const getAssetText = (asset: React.ReactNode): string => {
393
+ let text = '';
394
+
395
+ const visit = (node: React.ReactNode) => {
396
+ if (!node) return;
397
+
398
+ if (React.isValidElement(node)) {
399
+ const props: any = node.props;
400
+
401
+ if (typeof props.alt === 'string' && props.alt.trim()) {
402
+ text += (text ? ' ' : '') + props.alt.trim();
403
+ }
404
+ if (typeof props['aria-label'] === 'string' && props['aria-label'].trim()) {
405
+ text += (text ? ' ' : '') + props['aria-label'].trim();
406
+ }
407
+ React.Children.forEach(props.children, visit);
408
+ }
409
+ };
410
+
411
+ visit(asset);
412
+
413
+ return text.trim();
414
+ };
415
+
416
+ const getNodeText = (node: HTMLElement | null): string => {
417
+ const raw = node?.innerText || node?.textContent || '';
418
+ /* In the real browser, innerText preserves line breaks between elements, but jsdom does not.
419
+ As a result, when rows contain multiline content (e.g. `extra` with several Text components), jsdom returns the text concatenated without spaces.
420
+ This causes the computed aria-label to differ from the real behaviour.
421
+ To make tests reflect what VoiceOver would read in the browser, we normalise whitespace and insert missing spaces in test mode. */
422
+ if (process.env.NODE_ENV === 'test') {
423
+ return (
424
+ raw
425
+ // Normalise whitespace sequences to a single space
426
+ .replace(/\s+/g, ' ')
427
+ // Insert space between "non-space character" + "Uppercase"
428
+ // Ex: "lineExtra" -> "line Extra", "1Extra" -> "1 Extra"
429
+ .replace(/([^ ])([A-ZÁÉÍÓÚÑ])/g, '$1 $2')
430
+ .trim()
431
+ );
432
+ }
433
+ return raw;
434
+ };
435
+
436
+ const RowContent = React.forwardRef<TouchableElement, RowContentProps>((props, ref) => {
437
+ const titleId = React.useId();
438
+ const outsideVariant = useThemeVariant();
439
+ const isOverBrand =
440
+ outsideVariant === 'brand' || outsideVariant === 'media' || outsideVariant === 'negative';
441
+ const {
442
+ asset,
443
+ headline,
444
+ title,
445
+ titleAs,
446
+ titleLinesMax,
447
+ subtitle,
448
+ subtitleLinesMax,
449
+ description,
450
+ descriptionLinesMax,
451
+ detail,
452
+ danger,
453
+ badge,
454
+ role,
455
+ touchableRole,
456
+ extra,
457
+ withChevron,
458
+ dataAttributes,
459
+ right,
460
+ 'aria-label': ariaLabelProp,
461
+ tabIndex,
462
+ atomicReading,
463
+ } = props;
464
+
465
+ const [headlineText, setHeadlineText] = React.useState<string>('');
466
+ const [extraText, setExtraText] = React.useState<string>('');
467
+ const [rightText, setRightText] = React.useState<string>('');
468
+ const assetText = getAssetText(asset);
469
+
470
+ // iOS voiceover reads links with multiple lines as separate links. By setting aria-label and marking content as aria-hidden, we can make it read the whole row as one link.
471
+ const computedAriaLabel = [
472
+ title,
473
+ assetText,
474
+ headlineText,
475
+ subtitle,
476
+ description,
477
+ extraText,
478
+ detail,
479
+ rightText,
480
+ ]
481
+ .filter(Boolean)
482
+ .join(' ');
483
+
484
+ const isInteractive = !!props.onPress || !!props.href || !!props.to;
485
+ const ariaLabel = ariaLabelProp ?? (isInteractive ? computedAriaLabel : undefined);
486
+
487
+ const radioContext = useRadioContext();
488
+ const disabled = props.disabled || (props.radioValue !== undefined && radioContext.disabled);
489
+ const hasHoverDefault = !disabled && !isOverBrand;
490
+ const hasHoverInverse = !disabled && isOverBrand;
491
+ const hasControl = hasControlProps(props);
492
+ const hasChevron = hasControl ? false : withChevron ?? isInteractive;
493
+
494
+ const interactiveProps = {
495
+ href: props.href,
496
+ newTab: props.newTab,
497
+ loadOnTop: props.loadOnTop,
498
+
499
+ to: props.to,
500
+ fullPageOnWebView: props.fullPageOnWebView,
501
+ replace: props.replace,
502
+
503
+ onNavigate: props.onNavigate,
504
+ onPress: props.onPress,
505
+ trackingEvent: props.trackingEvent,
506
+
507
+ 'aria-label': ariaLabel,
508
+ 'aria-labelledby': props['aria-labelledby'],
509
+ 'aria-description': props['aria-description'],
510
+ 'aria-describedby': props['aria-describedby'],
511
+ 'aria-current': props['aria-current'],
512
+ } as TouchableProps;
513
+
514
+ const [isChecked, toggle] = useControlState(props.switch || props.checkbox || {});
515
+
516
+ const renderContent = (contentProps?: {control?: React.ReactNode; labelId?: string; role?: string}) => (
517
+ <Content
518
+ asset={asset}
519
+ headline={headline}
520
+ headlineRef={(node) => {
521
+ if (node) {
522
+ setHeadlineText(getNodeText(node));
523
+ }
524
+ }}
525
+ title={title}
526
+ titleAs={titleAs}
527
+ subtitle={subtitle}
528
+ description={description}
529
+ badge={badge}
530
+ titleLinesMax={titleLinesMax}
531
+ subtitleLinesMax={subtitleLinesMax}
532
+ descriptionLinesMax={descriptionLinesMax}
533
+ detail={detail}
534
+ danger={danger}
535
+ right={right}
536
+ rightRef={(node) => {
537
+ if (node) {
538
+ setRightText(getNodeText(node));
539
+ }
540
+ }}
541
+ control={contentProps?.control}
542
+ role={contentProps?.role}
543
+ extra={extra}
544
+ extraRef={(node) => {
545
+ if (node) {
546
+ setExtraText(getNodeText(node));
547
+ }
548
+ }}
549
+ labelId={contentProps?.labelId}
550
+ disabled={disabled}
551
+ withChevron={hasChevron}
552
+ />
553
+ );
554
+
555
+ if (isInteractive && !hasControl) {
556
+ return (
557
+ <BaseTouchable
558
+ ref={ref}
559
+ className={classNames(styles.rowContent, {
560
+ [styles.touchableBackground]: hasHoverDefault,
561
+ [styles.touchableBackgroundBrand]: hasHoverInverse,
562
+ [styles.pointer]: !disabled,
563
+ })}
564
+ {...interactiveProps}
565
+ role={touchableRole}
566
+ dataAttributes={dataAttributes}
567
+ disabled={disabled}
568
+ tabIndex={tabIndex}
569
+ >
570
+ <Box
571
+ paddingX={16}
572
+ aria-hidden={!!props.to || !!props.href || props.touchableRole === 'link' || undefined}
573
+ dataAttributes={{testid: 'content-container'}}
574
+ >
575
+ {renderContent({role})}
576
+ </Box>
577
+ </BaseTouchable>
578
+ );
579
+ }
580
+
581
+ const renderRowWithDoubleInteraction = (control: React.ReactNode) => (
582
+ <div
583
+ className={styles.dualActionContainer}
584
+ ref={ref as React.Ref<HTMLDivElement>}
585
+ {...getPrefixedDataAttributes(dataAttributes)}
586
+ >
587
+ <BaseTouchable
588
+ disabled={disabled}
589
+ {...interactiveProps}
590
+ role={touchableRole}
591
+ className={classNames(styles.dualActionLeft, {
592
+ [styles.touchableBackground]: hasHoverDefault,
593
+ [styles.touchableBackgroundBrand]: hasHoverInverse,
594
+ })}
595
+ tabIndex={tabIndex}
596
+ >
597
+ {renderContent({labelId: titleId, role})}
598
+ </BaseTouchable>
599
+
600
+ <div className={styles.dualActionDivider} />
601
+
602
+ {control}
603
+ </div>
604
+ );
605
+
606
+ const renderRowWithSingleControl = (content: React.ReactNode, isContentInsideControl?: boolean) => (
607
+ <div
608
+ className={classNames(styles.rowContent, {
609
+ [styles.touchableBackground]: hasHoverDefault && isContentInsideControl,
610
+ [styles.touchableBackgroundBrand]: hasHoverInverse && isContentInsideControl,
611
+ [styles.pointer]: !disabled && isContentInsideControl,
612
+ })}
613
+ ref={ref as React.Ref<HTMLDivElement>}
614
+ {...getPrefixedDataAttributes(dataAttributes)}
615
+ >
616
+ {content}
617
+ </div>
618
+ );
619
+
620
+ if (props.switch || props.checkbox) {
621
+ const Control = props.switch ? Switch : Checkbox;
622
+ const name = props.switch?.name ?? props.checkbox?.name ?? titleId;
623
+
624
+ return isInteractive
625
+ ? renderRowWithDoubleInteraction(
626
+ <Control
627
+ disabled={disabled}
628
+ name={name}
629
+ checked={isChecked}
630
+ aria-label={ariaLabel}
631
+ aria-labelledby={titleId}
632
+ onChange={toggle}
633
+ render={({controlElement}) => (
634
+ <div className={styles.dualActionRight}>{controlElement}</div>
635
+ )}
636
+ />
637
+ )
638
+ : renderRowWithSingleControl(
639
+ <Control
640
+ disabled={disabled}
641
+ name={name}
642
+ checked={isChecked}
643
+ aria-label={ariaLabel}
644
+ aria-labelledby={titleId}
645
+ onChange={toggle}
646
+ render={({controlElement, labelId}) => (
647
+ <Box paddingX={16} role={role}>
648
+ {renderContent({
649
+ labelId,
650
+ control: <Stack space="around">{controlElement}</Stack>,
651
+ })}
652
+ </Box>
653
+ )}
654
+ />,
655
+ true
656
+ );
657
+ }
658
+
659
+ if (props.radioValue) {
660
+ return isInteractive
661
+ ? renderRowWithDoubleInteraction(
662
+ <RadioButton
663
+ value={props.radioValue}
664
+ aria-label={ariaLabel}
665
+ aria-labelledby={titleId}
666
+ render={({controlElement}) => (
667
+ <Stack space="around">
668
+ <Box paddingX={16}>{controlElement}</Box>
669
+ </Stack>
670
+ )}
671
+ />
672
+ )
673
+ : renderRowWithSingleControl(
674
+ <RadioButton
675
+ value={props.radioValue}
676
+ aria-label={ariaLabel}
677
+ aria-labelledby={titleId}
678
+ render={({controlElement}) => (
679
+ <Box paddingX={16} role={role}>
680
+ {renderContent({
681
+ labelId: titleId,
682
+ control: <Stack space="around">{controlElement}</Stack>,
683
+ })}
684
+ </Box>
685
+ )}
686
+ />,
687
+ true
688
+ );
689
+ }
690
+
691
+ if (props.iconButton) {
692
+ return isInteractive
693
+ ? renderRowWithDoubleInteraction(
694
+ <Box padding={16}>
695
+ <Stack space="around">
696
+ {props.iconButton.Icon ? (
697
+ <IconButton {...props.iconButton} disabled={props.disabled} />
698
+ ) : (
699
+ <ToggleIconButton {...props.iconButton} disabled={props.disabled} />
700
+ )}
701
+ </Stack>
702
+ </Box>
703
+ )
704
+ : renderRowWithSingleControl(
705
+ <Box paddingX={16}>
706
+ {renderContent({
707
+ labelId: titleId,
708
+ control: (
709
+ <Stack space="around">
710
+ {props.iconButton.Icon ? (
711
+ <IconButton
712
+ {...props.iconButton}
713
+ disabled={props.disabled}
714
+ role={role}
715
+ />
716
+ ) : (
717
+ <ToggleIconButton
718
+ {...props.iconButton}
719
+ disabled={props.disabled}
720
+ role={role}
721
+ />
722
+ )}
723
+ </Stack>
724
+ ),
725
+ })}
726
+ </Box>
727
+ );
728
+ }
729
+
730
+ const shouldRenderScreenReaderOnly = !!ariaLabelProp || atomicReading;
731
+
732
+ return (
733
+ <div role={role}>
734
+ <div
735
+ className={classNames(styles.rowContent, styles.rowContentPadding)}
736
+ // role="text" makes VoiceOver read the whole div as a single text block. This is needed for VoiceOver rectangle to
737
+ // cover the whole row, otherwise it only covers the text inside ScreenReaderOnly
738
+ role={shouldRenderScreenReaderOnly ? 'text' : undefined}
739
+ {...getPrefixedDataAttributes(dataAttributes)}
740
+ ref={ref as React.Ref<HTMLDivElement>}
741
+ tabIndex={tabIndex}
742
+ >
743
+ <div aria-hidden={shouldRenderScreenReaderOnly}>{renderContent({role})}</div>
744
+ {shouldRenderScreenReaderOnly && (
745
+ <ScreenReaderOnly>
746
+ <span>{ariaLabelProp ?? computedAriaLabel}</span>
747
+ </ScreenReaderOnly>
748
+ )}
749
+ </div>
750
+ </div>
751
+ );
752
+ });
753
+
754
+ export const Row = React.forwardRef<TouchableElement, RowContentProps>(
755
+ ({dataAttributes, role = 'listitem', ...props}, ref) => (
756
+ <div role={role} className={styles.row}>
757
+ <RowContent
758
+ {...props}
759
+ ref={ref}
760
+ dataAttributes={{'component-name': 'Row', testid: 'Row', ...dataAttributes}}
761
+ />
762
+ </div>
763
+ )
764
+ );
765
+
766
+ type CommonAccessibilityProps = {
767
+ 'aria-live'?: 'polite' | 'off' | 'assertive';
768
+ 'aria-atomic'?: boolean;
769
+ };
770
+
771
+ type RowListProps = {
772
+ children: React.ReactNode;
773
+ 'aria-label'?: string;
774
+ 'aria-labelledby'?: string;
775
+ /**
776
+ * @deprecated Use 'aria-labelledby' instead. This will be removed in a future release.
777
+ */
778
+ ariaLabelledby?: string;
779
+ role?: string;
780
+ dataAttributes?: DataAttributes;
781
+ } & CommonAccessibilityProps;
782
+
783
+ export const RowList = ({
784
+ children,
785
+ ariaLabelledby,
786
+ role = 'list',
787
+ 'aria-label': ariaLabel,
788
+ 'aria-labelledby': ariaLabelledBy = ariaLabelledby,
789
+ 'aria-live': ariaLive = 'off',
790
+ 'aria-atomic': ariaAtomic = false,
791
+ dataAttributes,
792
+ }: RowListProps): JSX.Element => {
793
+ const childrenContent = React.Children.toArray(children).filter(Boolean);
794
+ const lastIndex = childrenContent.length - 1;
795
+
796
+ return (
797
+ <div
798
+ role={role}
799
+ aria-labelledby={ariaLabelledBy}
800
+ aria-label={ariaLabel}
801
+ aria-live={ariaLive}
802
+ aria-atomic={ariaAtomic}
803
+ {...getPrefixedDataAttributes(dataAttributes, 'RowList')}
804
+ >
805
+ {childrenContent.map((child, index) => (
806
+ <React.Fragment key={index}>
807
+ {child}
808
+ {index < lastIndex && (
809
+ <Box paddingX={16}>
810
+ <Divider />
811
+ </Box>
812
+ )}
813
+ </React.Fragment>
814
+ ))}
815
+ </div>
816
+ );
817
+ };
818
+
819
+ // danger + isInverse is not allowed
820
+ type CommonBoxedRowProps =
821
+ | {
822
+ /**
823
+ * @deprecated Use variant instead
824
+ */
825
+ isInverse?: false;
826
+ variant?: 'default';
827
+ danger: true;
828
+ }
829
+ | {
830
+ /**
831
+ * @deprecated Use variant instead
832
+ */
833
+ isInverse?: boolean;
834
+ variant?: 'brand' | 'default';
835
+ danger?: false;
836
+ }
837
+ | {
838
+ /**
839
+ * @deprecated Use variant instead
840
+ */
841
+ isInverse?: false;
842
+ variant?: 'default';
843
+ danger: boolean;
844
+ };
845
+
846
+ type BoxedRowProps = ExclusifyUnion<
847
+ | BasicRowContentProps
848
+ | SwitchRowContentProps
849
+ | RadioRowContentProps
850
+ | IconButtonRowContentProps
851
+ | CheckboxRowContentProps
852
+ | HrefRowContentProps
853
+ | ToRowContentProps
854
+ | OnPressRowContentProps
855
+ > &
856
+ CommonBoxedRowProps;
857
+
858
+ export const BoxedRow = React.forwardRef<HTMLDivElement, BoxedRowProps>(({dataAttributes, ...props}, ref) => (
859
+ <InternalBoxed
860
+ overflow="visible"
861
+ className={styles.boxed}
862
+ variant={props.variant ?? (props.isInverse ? 'brand' : 'default')}
863
+ ref={ref}
864
+ dataAttributes={{'component-name': 'BoxedRow', testid: 'BoxedRow', ...dataAttributes}}
865
+ >
866
+ <RowContent {...props} />
867
+ </InternalBoxed>
868
+ ));
869
+
870
+ type BoxedRowListProps = {
871
+ children: React.ReactNode;
872
+ 'aria-label'?: string;
873
+ 'aria-labelledby'?: string;
874
+ /**
875
+ * @deprecated Use 'aria-labelledby' instead. This will be removed in a future release.
876
+ */
877
+ ariaLabelledby?: string;
878
+ role?: string;
879
+ dataAttributes?: DataAttributes;
880
+ } & CommonAccessibilityProps;
881
+
882
+ export const BoxedRowList = ({
883
+ children,
884
+ ariaLabelledby,
885
+ role = 'list',
886
+ dataAttributes,
887
+ 'aria-label': ariaLabel,
888
+ 'aria-labelledby': ariaLabelledBy = ariaLabelledby,
889
+ 'aria-live': ariaLive = 'off',
890
+ 'aria-atomic': ariaAtomic = false,
891
+ }: BoxedRowListProps): JSX.Element => (
892
+ <Stack
893
+ space={16}
894
+ role={role}
895
+ aria-label={ariaLabel}
896
+ aria-labelledby={ariaLabelledBy}
897
+ aria-live={ariaLive}
898
+ aria-atomic={ariaAtomic}
899
+ dataAttributes={{'component-name': 'BoxedRowList', testid: 'BoxedRowList', ...dataAttributes}}
900
+ >
901
+ {children}
902
+ </Stack>
903
+ );
904
+
905
+ type UnorderedListProps = {
906
+ children: React.ReactNode;
907
+ 'aria-label'?: string;
908
+ 'aria-labelledby'?: string;
909
+ };
910
+
911
+ type OrderedListProps = UnorderedListProps;
912
+
913
+ export const UnorderedList = ({
914
+ children,
915
+ 'aria-label': ariaLabel,
916
+ 'aria-labelledby': ariaLabelledBy,
917
+ }: UnorderedListProps): JSX.Element => {
918
+ return (
919
+ // role="list" is needed for accesibility in Safari+VoiceOver. See: https://developer.mozilla.org/en-US/docs/Web/CSS/list-style#accessibility
920
+ // eslint-disable-next-line jsx-a11y/no-redundant-roles
921
+ <ul role="list" className={styles.ul} aria-label={ariaLabel} aria-labelledby={ariaLabelledBy}>
922
+ {children}
923
+ </ul>
924
+ );
925
+ };
926
+
927
+ export const OrderedList = ({
928
+ children,
929
+ 'aria-label': ariaLabel,
930
+ 'aria-labelledby': ariaLabelledBy,
931
+ }: OrderedListProps): JSX.Element => {
932
+ return (
933
+ // role="list" is needed for accesibility in Safari+VoiceOver. See: https://developer.mozilla.org/en-US/docs/Web/CSS/list-style#accessibility
934
+ // eslint-disable-next-line jsx-a11y/no-redundant-roles
935
+ <ol role="list" className={styles.ul} aria-label={ariaLabel} aria-labelledby={ariaLabelledBy}>
936
+ {children}
937
+ </ol>
938
+ );
939
+ };
940
+
941
+ type ListItemProps = {
942
+ children: React.ReactNode;
943
+ Icon?: (props: IconProps) => JSX.Element;
944
+ icon?: JSX.Element;
945
+ withMarker?: boolean;
946
+ };
947
+
948
+ export const ListItem = ({children, Icon, icon, withMarker = true}: ListItemProps): JSX.Element => {
949
+ return !withMarker ? (
950
+ <li className={styles.liWithoutMarker}>
951
+ <div className={styles.liContent}>{children}</div>
952
+ </li>
953
+ ) : Icon || icon ? (
954
+ <li className={styles.liWithCustomIcon}>
955
+ <Box paddingRight={{mobile: 8, desktop: 16}}>
956
+ {Icon ? <Icon size="1em" color="currentColor" /> : icon}
957
+ </Box>
958
+ <div className={styles.liContent}>{children}</div>
959
+ </li>
960
+ ) : (
961
+ <li className={styles.li}>{children}</li>
962
+ );
963
+ };