@telefonica/mistica 16.59.0-beta.1 → 16.59.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 (539) hide show
  1. package/css/mistica.css +1 -1
  2. package/dist/accordion.css-mistica.js +16 -16
  3. package/dist/align.css-mistica.js +2 -2
  4. package/dist/autocomplete.css-mistica.js +6 -6
  5. package/dist/avatar.css-mistica.js +3 -3
  6. package/dist/badge.css-mistica.js +7 -7
  7. package/dist/box.css-mistica.js +15 -15
  8. package/dist/boxed.css-mistica.js +31 -31
  9. package/dist/button-group.css-mistica.js +10 -10
  10. package/dist/button-layout.css-mistica.js +21 -21
  11. package/dist/button.css-mistica.js +51 -51
  12. package/dist/callout.css-mistica.js +16 -16
  13. package/dist/card-internal.css-mistica.js +38 -38
  14. package/dist/carousel.css-mistica.js +18 -18
  15. package/dist/checkbox.css-mistica.js +21 -21
  16. package/dist/chip.css-mistica.js +30 -30
  17. package/dist/circle.css-mistica.js +2 -2
  18. package/dist/community/advanced-data-card.css-mistica.js +26 -26
  19. package/dist/community/blocks.css-mistica.js +3 -3
  20. package/dist/community/example-component.css-mistica.js +2 -2
  21. package/dist/counter.css-mistica.js +12 -12
  22. package/dist/cover-hero.css-mistica.js +16 -16
  23. package/dist/credit-card-number-field.css-mistica.js +6 -6
  24. package/dist/date-field.css-mistica.js +1 -1
  25. package/dist/date-time-picker.css-mistica.js +2 -2
  26. package/dist/dialog.css-mistica.js +15 -15
  27. package/dist/divider.css-mistica.js +5 -5
  28. package/dist/double-field.css-mistica.js +4 -4
  29. package/dist/drawer.css-mistica.js +15 -15
  30. package/dist/empty-state-card.css-mistica.js +4 -4
  31. package/dist/empty-state.css-mistica.js +14 -14
  32. package/dist/fade-in.css-mistica.js +1 -1
  33. package/dist/feedback.css-mistica.js +14 -14
  34. package/dist/file-upload.css-mistica.js +14 -14
  35. package/dist/fixed-footer-layout.css-mistica.js +12 -12
  36. package/dist/form.css-mistica.js +2 -2
  37. package/dist/grid-layout.css-mistica.js +9 -9
  38. package/dist/grid.css-mistica.js +147 -147
  39. package/dist/header.css-mistica.js +5 -5
  40. package/dist/hero.css-mistica.js +11 -11
  41. package/dist/horizontal-scroll.css-mistica.js +3 -3
  42. package/dist/icon-button.css-mistica.js +66 -66
  43. package/dist/icons/icon-chevron.css-mistica.js +6 -6
  44. package/dist/icons/icon-error.css-mistica.js +3 -3
  45. package/dist/image.css-mistica.js +11 -11
  46. package/dist/inline.css-mistica.js +16 -16
  47. package/dist/list.css-mistica.js +15 -15
  48. package/dist/loading-bar.css-mistica.js +5 -5
  49. package/dist/loading-screen.css-mistica.js +15 -15
  50. package/dist/logo.css-mistica.js +9 -9
  51. package/dist/menu.css-mistica.js +24 -24
  52. package/dist/mosaic.css-mistica.js +3 -3
  53. package/dist/navigation-bar.css-mistica.js +45 -45
  54. package/dist/navigation-breadcrumbs.css-mistica.js +5 -5
  55. package/dist/package-version.js +2 -2
  56. package/dist/pin-field.css-mistica.js +10 -10
  57. package/dist/popover.css-mistica.js +2 -2
  58. package/dist/progress-bar.css-mistica.js +12 -12
  59. package/dist/radio-button.css-mistica.js +33 -33
  60. package/dist/rating.css-mistica.js +12 -12
  61. package/dist/responsive-layout.css-mistica.js +20 -20
  62. package/dist/screen-reader-only.css-mistica.js +2 -2
  63. package/dist/select.css-mistica.js +29 -29
  64. package/dist/sheet-action-row.css-mistica.js +2 -2
  65. package/dist/sheet-common.css-mistica.js +16 -16
  66. package/dist/sheet-info.css-mistica.js +4 -4
  67. package/dist/skeletons.css-mistica.js +12 -12
  68. package/dist/skins/skin-contract.css-mistica.js +686 -686
  69. package/dist/skip-link.css-mistica.js +3 -3
  70. package/dist/slider.css-mistica.js +28 -28
  71. package/dist/snackbar.css-mistica.js +16 -16
  72. package/dist/spinner.css-mistica.js +5 -5
  73. package/dist/square.css-mistica.js +2 -2
  74. package/dist/stack.css-mistica.js +9 -9
  75. package/dist/stacking-group.css-mistica.js +2 -2
  76. package/dist/stepper.css-mistica.js +16 -16
  77. package/dist/switch-component.css-mistica.js +53 -53
  78. package/dist/table.css-mistica.js +24 -24
  79. package/dist/tabs.css-mistica.js +30 -30
  80. package/dist/tag.css-mistica.js +5 -5
  81. package/dist/text-field-base.css-mistica.js +30 -30
  82. package/dist/text-field-components.css-mistica.js +23 -20
  83. package/dist/text-field-components.css.d.ts +1 -0
  84. package/dist/text-field-components.js +31 -25
  85. package/dist/text-link.css-mistica.js +10 -10
  86. package/dist/text.css-mistica.js +13 -13
  87. package/dist/theme-context.css-mistica.js +2 -2
  88. package/dist/timeline.css-mistica.js +18 -18
  89. package/dist/timer.css-mistica.js +13 -13
  90. package/dist/tooltip.css-mistica.js +12 -12
  91. package/dist/touchable.css-mistica.js +5 -5
  92. package/dist/utils/aspect-ratio-support.css-mistica.js +7 -7
  93. package/dist/video.css-mistica.js +2 -2
  94. package/dist/vivinho-loading-animation/vivinho-loading-animation.css-mistica.js +3 -3
  95. package/dist-es/accordion.css-mistica.js +7 -7
  96. package/dist-es/align.css-mistica.js +2 -2
  97. package/dist-es/autocomplete.css-mistica.js +2 -2
  98. package/dist-es/avatar.css-mistica.js +2 -2
  99. package/dist-es/badge.css-mistica.js +2 -2
  100. package/dist-es/box.css-mistica.js +15 -15
  101. package/dist-es/boxed.css-mistica.js +25 -25
  102. package/dist-es/button-group.css-mistica.js +2 -2
  103. package/dist-es/button-layout.css-mistica.js +16 -16
  104. package/dist-es/button.css-mistica.js +38 -38
  105. package/dist-es/callout.css-mistica.js +12 -12
  106. package/dist-es/card-internal.css-mistica.js +20 -20
  107. package/dist-es/carousel.css-mistica.js +10 -10
  108. package/dist-es/checkbox.css-mistica.js +14 -14
  109. package/dist-es/chip.css-mistica.js +17 -17
  110. package/dist-es/circle.css-mistica.js +2 -2
  111. package/dist-es/community/advanced-data-card.css-mistica.js +7 -7
  112. package/dist-es/community/blocks.css-mistica.js +2 -2
  113. package/dist-es/community/example-component.css-mistica.js +2 -2
  114. package/dist-es/counter.css-mistica.js +2 -2
  115. package/dist-es/cover-hero.css-mistica.js +4 -4
  116. package/dist-es/credit-card-number-field.css-mistica.js +4 -4
  117. package/dist-es/date-field.css-mistica.js +1 -1
  118. package/dist-es/date-time-picker.css-mistica.js +2 -2
  119. package/dist-es/dialog.css-mistica.js +5 -5
  120. package/dist-es/divider.css-mistica.js +5 -5
  121. package/dist-es/double-field.css-mistica.js +4 -4
  122. package/dist-es/drawer.css-mistica.js +2 -2
  123. package/dist-es/empty-state-card.css-mistica.js +2 -2
  124. package/dist-es/empty-state.css-mistica.js +7 -7
  125. package/dist-es/fade-in.css-mistica.js +1 -1
  126. package/dist-es/feedback.css-mistica.js +2 -2
  127. package/dist-es/file-upload.css-mistica.js +8 -8
  128. package/dist-es/fixed-footer-layout.css-mistica.js +4 -4
  129. package/dist-es/form.css-mistica.js +2 -2
  130. package/dist-es/grid-layout.css-mistica.js +4 -4
  131. package/dist-es/grid.css-mistica.js +127 -127
  132. package/dist-es/header.css-mistica.js +2 -2
  133. package/dist-es/hero.css-mistica.js +4 -4
  134. package/dist-es/horizontal-scroll.css-mistica.js +2 -2
  135. package/dist-es/icon-button.css-mistica.js +56 -56
  136. package/dist-es/icons/icon-chevron.css-mistica.js +4 -4
  137. package/dist-es/icons/icon-error.css-mistica.js +2 -2
  138. package/dist-es/image.css-mistica.js +4 -4
  139. package/dist-es/inline.css-mistica.js +10 -10
  140. package/dist-es/list.css-mistica.js +2 -2
  141. package/dist-es/loading-bar.css-mistica.js +2 -2
  142. package/dist-es/loading-screen.css-mistica.js +5 -5
  143. package/dist-es/logo.css-mistica.js +7 -7
  144. package/dist-es/menu.css-mistica.js +15 -15
  145. package/dist-es/mosaic.css-mistica.js +2 -2
  146. package/dist-es/navigation-bar.css-mistica.js +20 -20
  147. package/dist-es/navigation-breadcrumbs.css-mistica.js +2 -2
  148. package/dist-es/package-version.js +2 -2
  149. package/dist-es/pin-field.css-mistica.js +2 -2
  150. package/dist-es/popover.css-mistica.js +2 -2
  151. package/dist-es/progress-bar.css-mistica.js +8 -8
  152. package/dist-es/radio-button.css-mistica.js +25 -25
  153. package/dist-es/rating.css-mistica.js +4 -4
  154. package/dist-es/responsive-layout.css-mistica.js +7 -7
  155. package/dist-es/screen-reader-only.css-mistica.js +2 -2
  156. package/dist-es/select.css-mistica.js +20 -20
  157. package/dist-es/sheet-action-row.css-mistica.js +2 -2
  158. package/dist-es/sheet-common.css-mistica.js +2 -2
  159. package/dist-es/sheet-info.css-mistica.js +2 -2
  160. package/dist-es/skeletons.css-mistica.js +8 -8
  161. package/dist-es/skins/skin-contract.css-mistica.js +686 -686
  162. package/dist-es/skip-link.css-mistica.js +2 -2
  163. package/dist-es/slider.css-mistica.js +20 -20
  164. package/dist-es/snackbar.css-mistica.js +5 -5
  165. package/dist-es/spinner.css-mistica.js +2 -2
  166. package/dist-es/square.css-mistica.js +2 -2
  167. package/dist-es/stack.css-mistica.js +7 -7
  168. package/dist-es/stacking-group.css-mistica.js +2 -2
  169. package/dist-es/stepper.css-mistica.js +4 -4
  170. package/dist-es/style.css +1 -1
  171. package/dist-es/switch-component.css-mistica.js +41 -41
  172. package/dist-es/table.css-mistica.js +11 -11
  173. package/dist-es/tabs.css-mistica.js +21 -21
  174. package/dist-es/tag.css-mistica.js +2 -2
  175. package/dist-es/text-field-base.css-mistica.js +17 -17
  176. package/dist-es/text-field-components.css-mistica.js +4 -4
  177. package/dist-es/text-field-components.js +52 -46
  178. package/dist-es/text-link.css-mistica.js +9 -9
  179. package/dist-es/text.css-mistica.js +8 -8
  180. package/dist-es/theme-context.css-mistica.js +2 -2
  181. package/dist-es/timeline.css-mistica.js +11 -11
  182. package/dist-es/timer.css-mistica.js +7 -7
  183. package/dist-es/tooltip.css-mistica.js +3 -3
  184. package/dist-es/touchable.css-mistica.js +2 -2
  185. package/dist-es/utils/aspect-ratio-support.css-mistica.js +4 -4
  186. package/dist-es/video.css-mistica.js +2 -2
  187. package/dist-es/vivinho-loading-animation/vivinho-loading-animation.css-mistica.js +2 -2
  188. package/doc/llms.md +0 -24
  189. package/package.json +1 -13
  190. package/src/accordion.css.ts +0 -121
  191. package/src/accordion.tsx +0 -366
  192. package/src/align.css.ts +0 -7
  193. package/src/align.tsx +0 -32
  194. package/src/autocomplete.css.ts +0 -62
  195. package/src/autocomplete.tsx +0 -239
  196. package/src/avatar.css.ts +0 -14
  197. package/src/avatar.tsx +0 -120
  198. package/src/badge.css.ts +0 -51
  199. package/src/badge.tsx +0 -79
  200. package/src/box.css.ts +0 -51
  201. package/src/box.tsx +0 -114
  202. package/src/boxed.css.ts +0 -132
  203. package/src/boxed.tsx +0 -153
  204. package/src/button-fixed-footer-layout.tsx +0 -62
  205. package/src/button-group.css.ts +0 -75
  206. package/src/button-group.tsx +0 -91
  207. package/src/button-layout.css.ts +0 -162
  208. package/src/button-layout.tsx +0 -91
  209. package/src/button.css.ts +0 -758
  210. package/src/button.tsx +0 -632
  211. package/src/callout.css.ts +0 -50
  212. package/src/callout.tsx +0 -147
  213. package/src/card-cover.tsx +0 -242
  214. package/src/card-data.tsx +0 -152
  215. package/src/card-internal.css.ts +0 -271
  216. package/src/card-internal.tsx +0 -1724
  217. package/src/card-media.tsx +0 -157
  218. package/src/card-naked.tsx +0 -63
  219. package/src/carousel.css.ts +0 -522
  220. package/src/carousel.tsx +0 -1300
  221. package/src/checkbox.css.ts +0 -94
  222. package/src/checkbox.tsx +0 -192
  223. package/src/chip.css.ts +0 -204
  224. package/src/chip.tsx +0 -191
  225. package/src/circle.css.ts +0 -14
  226. package/src/circle.tsx +0 -52
  227. 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
  228. 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
  229. 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
  230. 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
  231. 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
  232. 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
  233. 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
  234. 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
  235. package/src/community/__screenshot_tests__/__image_snapshots__/advanced-data-card-screenshot-test-tsx-advanced-data-card-extras-0-1-snap.png +0 -0
  236. package/src/community/__screenshot_tests__/__image_snapshots__/advanced-data-card-screenshot-test-tsx-advanced-data-card-extras-1-1-snap.png +0 -0
  237. package/src/community/__screenshot_tests__/__image_snapshots__/advanced-data-card-screenshot-test-tsx-advanced-data-card-extras-3-1-snap.png +0 -0
  238. 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
  239. package/src/community/__screenshot_tests__/__image_snapshots__/advanced-data-card-screenshot-test-tsx-advanced-data-card-inside-carousel-1-snap.png +0 -0
  240. 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
  241. package/src/community/__screenshot_tests__/__image_snapshots__/blocks-screenshot-test-tsx-blocks-highlighted-value-block-1-snap.png +0 -0
  242. package/src/community/__screenshot_tests__/__image_snapshots__/blocks-screenshot-test-tsx-blocks-information-block-1-snap.png +0 -0
  243. package/src/community/__screenshot_tests__/__image_snapshots__/blocks-screenshot-test-tsx-blocks-progress-block-1-snap.png +0 -0
  244. package/src/community/__screenshot_tests__/__image_snapshots__/blocks-screenshot-test-tsx-blocks-progress-block-2-snap.png +0 -0
  245. package/src/community/__screenshot_tests__/__image_snapshots__/blocks-screenshot-test-tsx-blocks-row-block-1-snap.png +0 -0
  246. package/src/community/__screenshot_tests__/__image_snapshots__/blocks-screenshot-test-tsx-blocks-simple-block-1-snap.png +0 -0
  247. package/src/community/__screenshot_tests__/__image_snapshots__/blocks-screenshot-test-tsx-blocks-value-block-1-snap.png +0 -0
  248. package/src/community/__screenshot_tests__/advanced-data-card-screenshot-test.tsx +0 -84
  249. package/src/community/__screenshot_tests__/blocks-screenshot-test.tsx +0 -72
  250. package/src/community/__stories__/advanced-data-card-carousel-story.tsx +0 -66
  251. package/src/community/__stories__/advanced-data-card-story.tsx +0 -158
  252. package/src/community/__stories__/blocks-story.tsx +0 -272
  253. package/src/community/__stories__/example-component-story.tsx +0 -15
  254. package/src/community/__stories__/index-story.tsx +0 -154
  255. package/src/community/__type_tests__/advanced-data-card-type-test.tsx +0 -40
  256. package/src/community/advanced-data-card.css.ts +0 -271
  257. package/src/community/advanced-data-card.tsx +0 -431
  258. package/src/community/blocks.css.ts +0 -12
  259. package/src/community/blocks.tsx +0 -290
  260. package/src/community/example-component.css.ts +0 -7
  261. package/src/community/example-component.tsx +0 -17
  262. package/src/community/index.tsx +0 -10
  263. package/src/counter.css.ts +0 -150
  264. package/src/counter.tsx +0 -215
  265. package/src/cover-hero-media.tsx +0 -39
  266. package/src/cover-hero.css.ts +0 -133
  267. package/src/cover-hero.tsx +0 -262
  268. package/src/credit-card-expiration-field.tsx +0 -187
  269. package/src/credit-card-fields.tsx +0 -56
  270. package/src/credit-card-number-field.css.ts +0 -47
  271. package/src/credit-card-number-field.tsx +0 -245
  272. package/src/cvv-field.tsx +0 -169
  273. package/src/date-field.css.ts +0 -14
  274. package/src/date-field.tsx +0 -130
  275. package/src/date-time-field.tsx +0 -141
  276. package/src/date-time-picker.css.ts +0 -126
  277. package/src/date-time-picker.tsx +0 -188
  278. package/src/decimal-field.tsx +0 -160
  279. package/src/desktop-container-type-context.tsx +0 -15
  280. package/src/dialog-context.tsx +0 -81
  281. package/src/dialog.css.ts +0 -155
  282. package/src/dialog.tsx +0 -423
  283. package/src/divider.css.ts +0 -10
  284. package/src/divider.tsx +0 -11
  285. package/src/double-field.css.ts +0 -33
  286. package/src/double-field.tsx +0 -71
  287. package/src/drawer.css.ts +0 -123
  288. package/src/drawer.tsx +0 -304
  289. package/src/email-field.tsx +0 -76
  290. package/src/empty-state-card.css.ts +0 -40
  291. package/src/empty-state-card.tsx +0 -92
  292. package/src/empty-state.css.ts +0 -119
  293. package/src/empty-state.tsx +0 -141
  294. package/src/fade-in.css.ts +0 -12
  295. package/src/fade-in.tsx +0 -40
  296. package/src/feedback.css.ts +0 -119
  297. package/src/feedback.tsx +0 -432
  298. package/src/file-upload.css.ts +0 -156
  299. package/src/file-upload.tsx +0 -612
  300. package/src/fixed-footer-layout.css.ts +0 -96
  301. package/src/fixed-footer-layout.tsx +0 -215
  302. package/src/fixed-to-top.tsx +0 -21
  303. package/src/focus-trap.tsx +0 -17
  304. package/src/form-context.tsx +0 -198
  305. package/src/form.css.ts +0 -5
  306. package/src/form.tsx +0 -287
  307. package/src/grid-layout.css.ts +0 -68
  308. package/src/grid-layout.tsx +0 -201
  309. package/src/grid.css.ts +0 -203
  310. package/src/grid.tsx +0 -241
  311. package/src/header.css.ts +0 -30
  312. package/src/header.tsx +0 -319
  313. package/src/hero.css.ts +0 -71
  314. package/src/hero.tsx +0 -318
  315. package/src/hooks.tsx +0 -313
  316. package/src/horizontal-scroll.css.ts +0 -43
  317. package/src/horizontal-scroll.tsx +0 -18
  318. package/src/iban-field.tsx +0 -218
  319. package/src/icon-button.css.ts +0 -561
  320. package/src/icon-button.tsx +0 -221
  321. package/src/icons/__stories__/mistica-icons-story.tsx +0 -192
  322. package/src/icons/icon-amex.tsx +0 -40
  323. package/src/icons/icon-chevron.css.ts +0 -23
  324. package/src/icons/icon-chevron.tsx +0 -150
  325. package/src/icons/icon-cvv-amex.tsx +0 -31
  326. package/src/icons/icon-cvv-visa-mc.tsx +0 -31
  327. package/src/icons/icon-error.css.ts +0 -27
  328. package/src/icons/icon-error.tsx +0 -207
  329. package/src/icons/icon-info.tsx +0 -86
  330. package/src/icons/icon-mastercard.tsx +0 -36
  331. package/src/icons/icon-success-vivo-new.tsx +0 -51
  332. package/src/icons/icon-success-vivo.tsx +0 -36
  333. package/src/icons/icon-success.tsx +0 -211
  334. package/src/icons/icon-visa.tsx +0 -32
  335. package/src/image.css.ts +0 -48
  336. package/src/image.tsx +0 -345
  337. package/src/index.tsx +0 -2466
  338. package/src/inline.css.ts +0 -131
  339. package/src/inline.tsx +0 -135
  340. package/src/integer-field.tsx +0 -93
  341. package/src/list.css.ts +0 -281
  342. package/src/list.tsx +0 -963
  343. package/src/loading-bar.css.ts +0 -69
  344. package/src/loading-bar.tsx +0 -25
  345. package/src/loading-screen.css.ts +0 -114
  346. package/src/loading-screen.tsx +0 -376
  347. package/src/logo-blau-shell.tsx +0 -30
  348. package/src/logo-blau.tsx +0 -60
  349. package/src/logo-common.tsx +0 -29
  350. package/src/logo-esimflag-shell.tsx +0 -30
  351. package/src/logo-esimflag.tsx +0 -56
  352. package/src/logo-movistar-new-shell.tsx +0 -30
  353. package/src/logo-movistar-new.tsx +0 -85
  354. package/src/logo-movistar-shell.tsx +0 -30
  355. package/src/logo-movistar.tsx +0 -63
  356. package/src/logo-o2-new-shell.tsx +0 -26
  357. package/src/logo-o2-new.tsx +0 -27
  358. package/src/logo-o2-shell.tsx +0 -26
  359. package/src/logo-o2.tsx +0 -27
  360. package/src/logo-telefonica-shell.tsx +0 -30
  361. package/src/logo-telefonica.tsx +0 -95
  362. package/src/logo-tu-shell.tsx +0 -26
  363. package/src/logo-tu.tsx +0 -28
  364. package/src/logo-vivo-shell.tsx +0 -30
  365. package/src/logo-vivo.tsx +0 -53
  366. package/src/logo.css.ts +0 -33
  367. package/src/logo.tsx +0 -313
  368. package/src/master-detail-layout.tsx +0 -28
  369. package/src/maybe-dismissable.css.ts +0 -37
  370. package/src/maybe-dismissable.tsx +0 -58
  371. package/src/media-queries.css.ts +0 -67
  372. package/src/menu.css.ts +0 -132
  373. package/src/menu.tsx +0 -468
  374. package/src/meter.tsx +0 -516
  375. package/src/modal-context-provider.tsx +0 -45
  376. package/src/month-field.tsx +0 -124
  377. package/src/mosaic.css.ts +0 -73
  378. package/src/mosaic.tsx +0 -205
  379. package/src/navigation-bar.css.ts +0 -558
  380. package/src/navigation-bar.tsx +0 -1637
  381. package/src/navigation-breadcrumbs.css.ts +0 -22
  382. package/src/navigation-breadcrumbs.tsx +0 -69
  383. package/src/negative-box.tsx +0 -15
  384. package/src/nestable-context.tsx +0 -139
  385. package/src/overlay.tsx +0 -86
  386. package/src/overscroll-color-context.tsx +0 -141
  387. package/src/package-version.tsx +0 -2
  388. package/src/password-field.tsx +0 -126
  389. package/src/phone-number-field-lite.tsx +0 -265
  390. package/src/phone-number-field.tsx +0 -171
  391. package/src/pin-field.css.ts +0 -90
  392. package/src/pin-field.tsx +0 -346
  393. package/src/placeholder.tsx +0 -41
  394. package/src/popover.css.ts +0 -8
  395. package/src/popover.tsx +0 -85
  396. package/src/portal.tsx +0 -43
  397. package/src/progress-bar.css.ts +0 -61
  398. package/src/progress-bar.tsx +0 -174
  399. package/src/radio-button.css.ts +0 -174
  400. package/src/radio-button.tsx +0 -322
  401. package/src/rating.css.ts +0 -128
  402. package/src/rating.tsx +0 -351
  403. package/src/responsive-layout.css.ts +0 -162
  404. package/src/responsive-layout.tsx +0 -106
  405. package/src/screen-reader-only.css.ts +0 -27
  406. package/src/screen-reader-only.tsx +0 -33
  407. package/src/screen-size-context-provider.tsx +0 -96
  408. package/src/screen-size-context.tsx +0 -23
  409. package/src/search-field.tsx +0 -126
  410. package/src/select.css.ts +0 -226
  411. package/src/select.tsx +0 -513
  412. package/src/sheet-action-row.css.ts +0 -33
  413. package/src/sheet-actions-list.tsx +0 -113
  414. package/src/sheet-actions.tsx +0 -95
  415. package/src/sheet-common.css.ts +0 -254
  416. package/src/sheet-common.tsx +0 -402
  417. package/src/sheet-info.css.ts +0 -19
  418. package/src/sheet-info.tsx +0 -127
  419. package/src/sheet-native.tsx +0 -189
  420. package/src/sheet-radio-list.tsx +0 -118
  421. package/src/sheet-root.tsx +0 -127
  422. package/src/sheet-types.tsx +0 -94
  423. package/src/sheet-web.tsx +0 -140
  424. package/src/skeleton-base.tsx +0 -38
  425. package/src/skeletons.css.ts +0 -56
  426. package/src/skeletons.tsx +0 -133
  427. package/src/skins/blau.tsx +0 -724
  428. package/src/skins/constants.tsx +0 -10
  429. package/src/skins/defaults.tsx +0 -104
  430. package/src/skins/esimflag.tsx +0 -728
  431. package/src/skins/movistar-new.tsx +0 -735
  432. package/src/skins/movistar.tsx +0 -740
  433. package/src/skins/o2-new.tsx +0 -731
  434. package/src/skins/o2.tsx +0 -727
  435. package/src/skins/skin-contract.css.ts +0 -380
  436. package/src/skins/telefonica.tsx +0 -768
  437. package/src/skins/tu.tsx +0 -741
  438. package/src/skins/types/colors.tsx +0 -286
  439. package/src/skins/types/index.tsx +0 -153
  440. package/src/skins/utils.tsx +0 -66
  441. package/src/skins/vivo-new.tsx +0 -745
  442. package/src/skins/vivo.tsx +0 -720
  443. package/src/skip-link.css.ts +0 -34
  444. package/src/skip-link.tsx +0 -52
  445. package/src/slider.css.ts +0 -181
  446. package/src/slider.tsx +0 -384
  447. package/src/snackbar-context.tsx +0 -98
  448. package/src/snackbar-native.ts +0 -37
  449. package/src/snackbar.css.ts +0 -176
  450. package/src/snackbar.tsx +0 -258
  451. package/src/spinner.css.ts +0 -66
  452. package/src/spinner.tsx +0 -136
  453. package/src/sprinkles.css.ts +0 -83
  454. package/src/square.css.ts +0 -15
  455. package/src/square.tsx +0 -55
  456. package/src/stack.css.ts +0 -44
  457. package/src/stack.tsx +0 -79
  458. package/src/stacking-group.css.ts +0 -15
  459. package/src/stacking-group.tsx +0 -82
  460. package/src/stepper.css.ts +0 -233
  461. package/src/stepper.tsx +0 -156
  462. package/src/switch-component.css.ts +0 -181
  463. package/src/switch-component.tsx +0 -187
  464. package/src/tab-focus.tsx +0 -68
  465. package/src/table-actions-header.tsx +0 -21
  466. package/src/table-cell-text.tsx +0 -35
  467. package/src/table.css.ts +0 -297
  468. package/src/table.tsx +0 -398
  469. package/src/tabs.css.ts +0 -212
  470. package/src/tabs.tsx +0 -263
  471. package/src/tag.css.ts +0 -42
  472. package/src/tag.tsx +0 -161
  473. package/src/test-utils/environment/setup-ssr.tsx +0 -10
  474. package/src/test-utils/fail-test-on-console-error.tsx +0 -22
  475. package/src/test-utils/index.tsx +0 -341
  476. package/src/test-utils/setup-ssr-test-env.tsx +0 -13
  477. package/src/test-utils/ssr.tsx +0 -197
  478. package/src/text-field-base.css.ts +0 -416
  479. package/src/text-field-base.tsx +0 -628
  480. package/src/text-field-components.css.ts +0 -159
  481. package/src/text-field-components.tsx +0 -225
  482. package/src/text-field.tsx +0 -118
  483. package/src/text-link.css.ts +0 -83
  484. package/src/text-link.tsx +0 -85
  485. package/src/text-tokens.tsx +0 -708
  486. package/src/text.css.ts +0 -60
  487. package/src/text.tsx +0 -516
  488. package/src/theme-context-provider.tsx +0 -370
  489. package/src/theme-context.css.ts +0 -3
  490. package/src/theme-context.tsx +0 -8
  491. package/src/theme-variant-context.tsx +0 -51
  492. package/src/theme.tsx +0 -184
  493. package/src/time-field.tsx +0 -99
  494. package/src/timeline.css.ts +0 -135
  495. package/src/timeline.tsx +0 -250
  496. package/src/timer.css.ts +0 -99
  497. package/src/timer.tsx +0 -420
  498. package/src/title.tsx +0 -119
  499. package/src/tooltip-context-provider.tsx +0 -57
  500. package/src/tooltip.css.ts +0 -106
  501. package/src/tooltip.tsx +0 -649
  502. package/src/touchable.css.ts +0 -56
  503. package/src/touchable.tsx +0 -355
  504. package/src/types/font-face.d.ts +0 -47
  505. package/src/types/libs.d.ts +0 -3
  506. package/src/utils/__tests__/analytics-test.tsx +0 -35
  507. package/src/utils/__tests__/browser-test.tsx +0 -28
  508. package/src/utils/__tests__/dom-test.tsx +0 -23
  509. package/src/utils/__tests__/helpers-test.tsx +0 -166
  510. package/src/utils/analytics.tsx +0 -28
  511. package/src/utils/animation.tsx +0 -201
  512. package/src/utils/aspect-ratio-support.css.ts +0 -28
  513. package/src/utils/aspect-ratio-support.tsx +0 -141
  514. package/src/utils/browser.tsx +0 -9
  515. package/src/utils/color.tsx +0 -46
  516. package/src/utils/common.tsx +0 -27
  517. package/src/utils/credit-card.tsx +0 -46
  518. package/src/utils/css.tsx +0 -25
  519. package/src/utils/document-visibility.tsx +0 -52
  520. package/src/utils/dom.tsx +0 -155
  521. package/src/utils/environment.tsx +0 -6
  522. package/src/utils/headings.tsx +0 -18
  523. package/src/utils/helpers.tsx +0 -182
  524. package/src/utils/keys.tsx +0 -8
  525. package/src/utils/locale.tsx +0 -27
  526. package/src/utils/platform.tsx +0 -94
  527. package/src/utils/region-code.tsx +0 -1
  528. package/src/utils/renders-element.tsx +0 -6
  529. package/src/utils/time.tsx +0 -22
  530. package/src/utils/types.tsx +0 -19
  531. package/src/utils/utility-types.tsx +0 -8
  532. package/src/video.css.ts +0 -11
  533. package/src/video.tsx +0 -355
  534. package/src/vivinho-loading-animation/in-lottie.json +0 -402
  535. package/src/vivinho-loading-animation/index.tsx +0 -90
  536. package/src/vivinho-loading-animation/out-lottie.json +0 -575
  537. package/src/vivinho-loading-animation/pulse-lottie.json +0 -551
  538. package/src/vivinho-loading-animation/vivinho-loading-animation.css.ts +0 -15
  539. package/src/vivinho-loading-animation/wave-lottie.json +0 -2829
@@ -1,1724 +0,0 @@
1
- // spec: https://www.figma.com/design/tKdPOfcUALzVIh5oizFbm7
2
- 'use client';
3
- import * as React from 'react';
4
- import * as styles from './card-internal.css';
5
- import * as mediaStyles from './image.css';
6
- import * as tokens from './text-tokens';
7
- import {Text} from './text';
8
- import {useInnerText, useTheme} from './hooks';
9
- import {ThemeVariant, normalizeVariant, useThemeVariant} from './theme-variant-context';
10
- import Tag from './tag';
11
- import Stack from './stack';
12
- import Image from './image';
13
- import Video from './video';
14
- import Inline from './inline';
15
- import Spinner from './spinner';
16
- import IconPlayFilled from './generated/mistica-icons/icon-play-filled';
17
- import IconPauseFilled from './generated/mistica-icons/icon-pause-filled';
18
- import IconCloseRegular from './generated/mistica-icons/icon-close-regular';
19
- import {getPrefixedDataAttributes} from './utils/dom';
20
- import {applyCssVars} from './utils/css';
21
- import {InternalBoxed} from './boxed';
22
- import {BaseTouchable} from './touchable';
23
- import {AspectRatioContainer, aspectRatioToNumber} from './utils/aspect-ratio-support';
24
- import {vars as skinVars} from './skins/skin-contract.css';
25
- import {IconButton, ToggleIconButton} from './icon-button';
26
- import {combineRefs} from './utils/common';
27
- import {isRunningAcceptanceTest} from './utils/platform';
28
- import classnames from 'classnames';
29
- import ButtonGroup from './button-group';
30
- import {isBiggerHeading} from './utils/headings';
31
- import {applyAlpha} from './utils/color';
32
-
33
- import type {
34
- DataAttributes,
35
- HeadingType,
36
- IconProps,
37
- RendersElement,
38
- RendersNullableElement,
39
- TrackingEvent,
40
- } from './utils/types';
41
- import type {ExclusifyUnion} from './utils/utility-types';
42
- import type {ButtonLink, ButtonPrimary, ButtonSecondary} from './button';
43
- import type {NonDeprecatedVariant, Variant} from './theme-variant-context';
44
- import type {VideoElement, VideoSource, AspectRatio as VideoAspectRatio} from './video';
45
- import type {AspectRatio as ImageAspectRatio} from './image';
46
- import type {PressHandler, TouchableElement} from './touchable';
47
-
48
- export type CardAspectRatio = '1:1' | '16:9' | '7:10' | '9:10' | 'auto' | number;
49
- export type MediaAspectRatio = ImageAspectRatio | VideoAspectRatio | 'auto' | number;
50
-
51
- export type CardType = 'data' | 'media' | 'cover' | 'naked';
52
- export type CardSize = 'snap' | 'default' | 'display';
53
- export type MediaPosition = 'top' | 'left' | 'right';
54
-
55
- /** @deprecated use imageSrc, imageSrcSet, videoSrc and related props */
56
- export type DeprecatedMediaProp = RendersElement<typeof Image> | RendersElement<typeof Video>;
57
-
58
- export type SlotAlignment = 'content' | 'bottom' | 'space-between';
59
-
60
- export type CardActionButtonPrimary = RendersNullableElement<typeof ButtonPrimary>;
61
- export type CardActionButtonSecondary = RendersNullableElement<typeof ButtonSecondary>;
62
- export type CardActionButtonLink = RendersNullableElement<typeof ButtonLink>;
63
-
64
- type CardVideoProps = {
65
- videoLoop?: boolean;
66
- videoAutoPlay?: boolean;
67
- videoDataAttributes?: DataAttributes;
68
- };
69
-
70
- type ContainerProps = {
71
- type: CardType;
72
- size: CardSize;
73
- variant?: Variant;
74
- width?: string | number;
75
- height?: string | number;
76
- /** Gradient overlay color for cover cards. If not set it uses the theme color */
77
- gradientOverlayColor?: 'transparent' | string;
78
- aspectRatio?: CardAspectRatio;
79
- dataAttributes?: DataAttributes;
80
- 'aria-label'?: React.AriaAttributes['aria-label'];
81
- 'aria-labelledby'?: React.AriaAttributes['aria-labelledby'];
82
- 'aria-description'?: string; // W3C Editor's Draft for ARIA 1.3
83
- 'aria-describedby'?: React.AriaAttributes['aria-describedby'];
84
- };
85
-
86
- type ButtonsProps = {
87
- buttonPrimary?: CardActionButtonPrimary;
88
- buttonSecondary?: CardActionButtonSecondary;
89
- buttonLink?: CardActionButtonLink;
90
- };
91
-
92
- type MediaProps = {
93
- /** @deprecated use imageSrc, imageSrcSet, videoSrc and related props */
94
- media?: DeprecatedMediaProp;
95
- backgroundColor?: string;
96
- imageSrc?: string;
97
- imageSrcSet?: string;
98
- imageAlt?: string;
99
- imageFit?: 'fit' | 'fill' | 'fill-center';
100
- videoSrc?: VideoSource;
101
- videoRef?: React.RefObject<VideoElement>;
102
- mediaPosition?: MediaPosition;
103
- /** Ignored when mediaPosition !== 'top' */
104
- mediaAspectRatio?: MediaAspectRatio;
105
- /** Ignored when mediaPosition === 'top' */
106
- mediaWidth?: string | number;
107
- circledImage?: boolean;
108
- } & CardVideoProps;
109
-
110
- type TextContentProps = {
111
- type: CardType;
112
- headline?: string | RendersNullableElement<typeof Tag>;
113
- pretitle?:
114
- | string
115
- | {
116
- text: string;
117
- 'aria-label'?: React.AriaAttributes['aria-label'];
118
- };
119
- pretitleAs?: HeadingType;
120
- pretitleLinesMax?: number;
121
- title?:
122
- | string
123
- | {
124
- text: string;
125
- 'aria-label'?: React.AriaAttributes['aria-label'];
126
- };
127
- titleAs?: HeadingType;
128
- titleLinesMax?: number;
129
- subtitle?: string;
130
- subtitleLinesMax?: number;
131
- description?: string;
132
- descriptionLinesMax?: number;
133
- };
134
-
135
- type AssetProps = {
136
- asset?: React.ReactElement;
137
- };
138
-
139
- type TopActionsProps = {
140
- onClose?: () => void;
141
- closeButtonLabel?: string;
142
- topActions?: TopActionsArray;
143
- videoAction?: CardAction;
144
- };
145
-
146
- type SlotProps = {
147
- slot?: React.ReactNode;
148
- slotAlignment?: SlotAlignment;
149
- };
150
-
151
- type FooterProps = {
152
- showFooter?: boolean;
153
- footerSlot?: React.ReactNode;
154
- footerBackgroundColor?: string;
155
- footerVariant?: 'default' | 'brand' | 'inverse';
156
- footerDivider?: boolean;
157
- };
158
-
159
- type NoChildrenProps = {
160
- children?: undefined;
161
- };
162
-
163
- type CardProps = ContainerProps &
164
- MediaProps &
165
- TextContentProps &
166
- AssetProps &
167
- ButtonsProps &
168
- TopActionsProps &
169
- SlotProps &
170
- FooterProps &
171
- NoChildrenProps;
172
-
173
- type TouchableProps = {
174
- trackingEvent?: TrackingEvent | ReadonlyArray<TrackingEvent>;
175
- role?: string;
176
- 'aria-current'?: React.AriaAttributes['aria-current'];
177
- /**
178
- * Aria label for the touchable element. If set the whole card will be announced as a link/button by screen readers.
179
- */
180
- touchableAriaLabel?: React.AriaAttributes['aria-label'];
181
- /**
182
- * When true, the touchable content of the card will be segregated for screen readers. Only one of those elements will be announced as link/button,
183
- * according to the following logic:
184
- * - If there is title or pretitle it will be the one between these two with the higher hierarchy (for example, if titleAs is 'h2' and pretitleAs is 'h3', the title will be the touchable element).
185
- * - If those are not present it will be the next hierarchy element: headline, subtitle, ...
186
- * This behaviour can be overriden with the touchableAriaLabel prop.
187
- */
188
- segregateTouchableContent?: boolean;
189
- } & ExclusifyUnion<
190
- | {
191
- href: string | undefined;
192
- newTab?: boolean;
193
- loadOnTop?: boolean;
194
- onNavigate?: () => void | Promise<void>;
195
- }
196
- | {
197
- to: string | undefined;
198
- newTab?: boolean;
199
- fullPageOnWebView?: boolean;
200
- replace?: boolean;
201
- onNavigate?: () => void | Promise<void>;
202
- }
203
- | {onPress: PressHandler | undefined}
204
- >;
205
-
206
- type TouchableCard<T> = T & TouchableProps;
207
- export type MaybeTouchableCard<T> = ExclusifyUnion<TouchableCard<T> | T>;
208
-
209
- type PrivateContainerProps = {
210
- children?: React.ReactNode;
211
- };
212
-
213
- const Container = React.forwardRef<HTMLDivElement, ContainerProps & MediaProps & PrivateContainerProps>(
214
- (
215
- {
216
- type,
217
- children,
218
- width,
219
- height,
220
- aspectRatio,
221
- 'aria-label': ariaLabel,
222
- 'aria-labelledby': ariaLabelledby,
223
- 'aria-description': ariaDescription,
224
- 'aria-describedby': ariaDescribedby,
225
- dataAttributes,
226
- backgroundColor,
227
- variant,
228
- },
229
- ref
230
- ): JSX.Element => {
231
- const aspectRatioValue = width && height ? undefined : aspectRatioToNumber(aspectRatio);
232
- const aspectRatioStyle = aspectRatioValue
233
- ? applyCssVars({[styles.vars.aspectRatio]: String(aspectRatioValue)})
234
- : {};
235
-
236
- const boxedBorderStyleOverride = backgroundColor ? 'none' : undefined;
237
- const isNaked = type === 'naked';
238
-
239
- return (
240
- // aria-description should be vaild, but this eslint rule is complaining about it
241
- // eslint-disable-next-line jsx-a11y/role-supports-aria-props
242
- <section
243
- ref={ref}
244
- aria-label={ariaLabel}
245
- aria-labelledby={ariaLabelledby}
246
- aria-description={ariaDescription}
247
- aria-describedby={ariaDescribedby}
248
- className={classnames(styles.container)}
249
- {...getPrefixedDataAttributes(dataAttributes, 'InternalCard')}
250
- style={{
251
- width: width || '100%',
252
- height: height || '100%',
253
- position: 'relative',
254
- ...aspectRatioStyle,
255
- }}
256
- >
257
- <div
258
- style={{
259
- display: 'flex',
260
- flexDirection: 'column',
261
- width: '100%',
262
- position: 'relative',
263
- minHeight: '100%',
264
- }}
265
- >
266
- <InternalBoxed
267
- // Without setting the width here, the component fails to get the correct width in some cases
268
- // even if we set the 100% width style in the boxed class
269
- width="100%"
270
- height="100%"
271
- variant={variant}
272
- className={classnames(styles.boxed)}
273
- background={isNaked ? 'transparent' : backgroundColor}
274
- borderRadius={isNaked ? 'none' : skinVars.borderRadii.container}
275
- border={isNaked ? 'none' : boxedBorderStyleOverride}
276
- overflow="visible"
277
- >
278
- {children}
279
- </InternalBoxed>
280
- </div>
281
- </section>
282
- );
283
- }
284
- );
285
-
286
- type FillerProps = {
287
- minHeight?: number;
288
- };
289
-
290
- const Filler = ({minHeight}: FillerProps) => (
291
- <div
292
- style={{
293
- flexGrow: 1,
294
- flexShrink: 0,
295
- minHeight,
296
- }}
297
- />
298
- );
299
-
300
- type PrivateAssetProps = {
301
- size: CardSize;
302
- type: CardType;
303
- absolute?: boolean;
304
- };
305
-
306
- const Asset = ({size, absolute, asset, type}: AssetProps & PrivateAssetProps): JSX.Element | null => {
307
- if (!asset) {
308
- return null;
309
- }
310
-
311
- const assetWithContainer = (
312
- <div
313
- data-testid="asset"
314
- aria-hidden
315
- style={applyCssVars({[mediaStyles.vars.mediaBorderRadius]: skinVars.borderRadii.mediaSmall})}
316
- >
317
- {asset}
318
- </div>
319
- );
320
-
321
- if (absolute) {
322
- return (
323
- <div
324
- style={{position: 'absolute', top: 0, left: 0}}
325
- className={classnames(
326
- styles.containerPaddingXVariants[size],
327
- styles.containerPaddingTopVariants[size]
328
- )}
329
- >
330
- {assetWithContainer}
331
- </div>
332
- );
333
- }
334
-
335
- return (
336
- <div className={classnames({[styles.containerPaddingXVariants[size]]: type !== 'naked'})}>
337
- {assetWithContainer}
338
- </div>
339
- );
340
- };
341
-
342
- export type BackgroundImageOrVideoProps = {
343
- video?: React.ReactNode;
344
- src?: string;
345
- srcSet?: string;
346
- backgroundVariant: Variant;
347
- };
348
-
349
- const BackgroundImageOrVideo = ({
350
- video,
351
- src,
352
- srcSet,
353
- backgroundVariant,
354
- }: BackgroundImageOrVideoProps): JSX.Element => {
355
- return (
356
- <ThemeVariant variant={backgroundVariant}>
357
- <div
358
- className={styles.backgroundImageOrVideoContainer}
359
- style={applyCssVars({
360
- [mediaStyles.vars.mediaBorderRadius]: '0px',
361
- borderRadius: skinVars.borderRadii.container,
362
- overflow: 'hidden',
363
- })}
364
- >
365
- {video ? (
366
- video
367
- ) : (
368
- <Image
369
- dataAttributes={{testid: 'image'}}
370
- width="100%"
371
- height="100%"
372
- src={src || ''}
373
- srcSet={srcSet}
374
- alt=""
375
- />
376
- )}
377
- </div>
378
- </ThemeVariant>
379
- );
380
- };
381
-
382
- type VideoState = 'loading' | 'playing' | 'paused' | 'error';
383
-
384
- type VideoAction = 'play' | 'pause' | 'fail' | 'reset';
385
-
386
- const transitions: Record<VideoState, Partial<Record<VideoAction, VideoState>>> = {
387
- loading: {
388
- play: 'playing',
389
- pause: 'paused',
390
- fail: 'error',
391
- reset: 'loading',
392
- },
393
-
394
- playing: {
395
- pause: 'paused',
396
- reset: 'loading',
397
- fail: 'error',
398
- },
399
-
400
- paused: {
401
- play: 'playing',
402
- reset: 'loading',
403
- fail: 'error',
404
- },
405
-
406
- error: {
407
- reset: 'loading',
408
- },
409
- };
410
-
411
- const videoReducer = (state: VideoState, action: VideoAction): VideoState =>
412
- transitions[state][action] || state;
413
-
414
- export const CardActionSpinner = ({color}: IconProps): React.ReactElement => (
415
- <Spinner color={color} size={16} delay="0" />
416
- );
417
-
418
- const CardActionPauseIcon = ({color}: IconProps) => <IconPauseFilled color={color} size={12} />;
419
-
420
- const CardActionPlayIcon = ({color}: IconProps) => <IconPlayFilled color={color} size={12} />;
421
-
422
- export const useVideoWithControls = ({
423
- src,
424
- poster,
425
- ref: videoRef,
426
- autoHeight,
427
- loop,
428
- autoPlay,
429
- dataAttributes,
430
- }: {
431
- src?: VideoSource;
432
- poster?: string;
433
- ref?: React.RefObject<VideoElement>;
434
- autoHeight?: boolean;
435
- loop?: boolean;
436
- autoPlay?: boolean;
437
- dataAttributes?: DataAttributes;
438
- }): {
439
- video?: React.ReactNode;
440
- videoAction?: CardAction;
441
- } => {
442
- const {texts, t} = useTheme();
443
- const videoController = React.useRef<VideoElement>(null);
444
- const initialLoadDoneRef = React.useRef(false);
445
- const [videoStatus, dispatch] = React.useReducer(
446
- videoReducer,
447
- process.env.NODE_ENV === 'test' ? 'playing' : 'loading'
448
- );
449
-
450
- React.useEffect(() => {
451
- initialLoadDoneRef.current = false;
452
- videoController.current?.load();
453
-
454
- return () => {
455
- dispatch('reset');
456
- };
457
- }, [src]);
458
-
459
- const video = React.useMemo(() => {
460
- if (src === undefined) {
461
- return undefined;
462
- }
463
-
464
- const handleLoadedData = () => {
465
- // When autoPlay is false, the video loads but doesn't play.
466
- // We need to transition to 'paused' state to show the play button instead of spinner.
467
- // We use initialLoadDoneRef to ensure this only happens once per video source,
468
- // because Chrome can fire onCanPlayThrough multiple times for network videos,
469
- // which would revert the card to 'paused' state even while the video is playing.
470
- if (autoPlay === false && !initialLoadDoneRef.current) {
471
- initialLoadDoneRef.current = true;
472
- dispatch('pause');
473
- }
474
- };
475
-
476
- return (
477
- <Video
478
- ref={combineRefs(videoController, videoRef)}
479
- src={src}
480
- poster={poster}
481
- width="100%"
482
- height={autoHeight ? undefined : '100%'}
483
- loop={loop}
484
- autoPlay={autoPlay}
485
- dataAttributes={dataAttributes}
486
- onLoad={handleLoadedData}
487
- onError={() => dispatch('fail')}
488
- onPause={() => dispatch('pause')}
489
- onPlay={() => dispatch('play')}
490
- />
491
- );
492
- }, [videoRef, src, poster, autoHeight, loop, autoPlay, dataAttributes]);
493
-
494
- const onVideoControlPress = () => {
495
- const video = videoController.current;
496
- if (!video) {
497
- return;
498
- }
499
-
500
- if (videoStatus === 'playing') {
501
- video.pause();
502
- } else {
503
- video.play().then(
504
- () => dispatch('play'),
505
- () => {}
506
- );
507
- }
508
- };
509
-
510
- if (videoStatus === 'error') {
511
- return {video};
512
- }
513
-
514
- const isVideoLoading = videoStatus === 'loading';
515
-
516
- const videoAction: CardAction | undefined = video
517
- ? {
518
- uncheckedProps: {
519
- Icon:
520
- isVideoLoading && !isRunningAcceptanceTest() ? CardActionSpinner : CardActionPauseIcon,
521
- label: isVideoLoading ? '' : texts.pauseIconButtonLabel || t(tokens.pauseIconButtonLabel),
522
- },
523
- checkedProps: {
524
- Icon: CardActionPlayIcon,
525
- label: texts.playIconButtonLabel || t(tokens.playIconButtonLabel),
526
- },
527
- onChange: onVideoControlPress,
528
- disabled: isRunningAcceptanceTest() ? false : isVideoLoading,
529
- checked: videoStatus === 'paused',
530
- }
531
- : undefined;
532
-
533
- return {
534
- video,
535
- videoAction,
536
- };
537
- };
538
-
539
- type PrivateButtonsProps = {
540
- size: CardSize;
541
- };
542
-
543
- const Buttons = ({
544
- size,
545
- buttonPrimary,
546
- buttonSecondary,
547
- buttonLink,
548
- }: ButtonsProps & PrivateButtonsProps): JSX.Element => {
549
- return (
550
- <div className={styles.actionsContainerVariants[size]}>
551
- <ButtonGroup primaryButton={buttonPrimary} secondaryButton={buttonSecondary} link={buttonLink} />
552
- </div>
553
- );
554
- };
555
-
556
- type BaseIconButtonAction = {
557
- Icon: (props: IconProps) => JSX.Element;
558
- label: string;
559
- 'aria-description'?: string;
560
- 'aria-describedby'?: string;
561
- 'aria-current'?: React.AriaAttributes['aria-current'];
562
- };
563
-
564
- type IconButtonAction = BaseIconButtonAction &
565
- ExclusifyUnion<
566
- | {href: string; newTab?: boolean}
567
- | {
568
- to: string;
569
- newTab?: boolean;
570
- fullPageOnWebView?: boolean;
571
- replace?: boolean;
572
- }
573
- | {onPress: () => void}
574
- >;
575
-
576
- type ToggleIconButtonAction = {
577
- checkedProps: BaseIconButtonAction;
578
- uncheckedProps: BaseIconButtonAction;
579
- onChange?: (checked: boolean) => void | undefined | Promise<void>;
580
- checked?: boolean;
581
- defaultChecked?: boolean;
582
- };
583
-
584
- export type CardAction = {
585
- disabled?: boolean;
586
- trackingEvent?: TrackingEvent | ReadonlyArray<TrackingEvent>;
587
- } & ExclusifyUnion<IconButtonAction | ToggleIconButtonAction>;
588
-
589
- export type TopActionsArray = ReadonlyArray<CardAction | React.ReactElement>;
590
-
591
- export const CardActionIconButton = (props: CardAction): JSX.Element => {
592
- const variant = useThemeVariant();
593
-
594
- if (props.Icon) {
595
- return (
596
- <IconButton
597
- {...props}
598
- small
599
- aria-label={props.label}
600
- type="neutral"
601
- backgroundType="transparent"
602
- />
603
- );
604
- }
605
-
606
- const {checkedProps, uncheckedProps, ...rest} = props;
607
- return (
608
- <ToggleIconButton
609
- small
610
- {...rest}
611
- checkedProps={{
612
- ...checkedProps,
613
- 'aria-label': props.checkedProps.label,
614
- type: variant === 'media' ? 'neutral' : 'brand',
615
- backgroundType: 'solid',
616
- }}
617
- uncheckedProps={{
618
- ...uncheckedProps,
619
- 'aria-label': props.uncheckedProps.label,
620
- type: 'neutral',
621
- backgroundType: 'transparent',
622
- }}
623
- />
624
- );
625
- };
626
-
627
- type PrivateTopActionsProps = {
628
- actions?: TopActionsArray;
629
- testid?: string;
630
- variant?: Variant;
631
- containerStyles?: React.CSSProperties;
632
- };
633
-
634
- export const TopActions = ({
635
- testid = 'topActions',
636
- onClose,
637
- closeButtonLabel,
638
- actions: actionsProp,
639
- variant,
640
- containerStyles = {},
641
- }: Omit<TopActionsProps, 'topActions'> & PrivateTopActionsProps): JSX.Element => {
642
- const {texts, t} = useTheme();
643
- const actions = actionsProp ? [...actionsProp] : [];
644
-
645
- if (onClose) {
646
- actions.push({
647
- label: closeButtonLabel || texts.closeButtonLabel || t(tokens.closeButtonLabel),
648
- onPress: onClose,
649
- Icon: IconCloseRegular,
650
- });
651
- }
652
-
653
- if (actions.length === 0) {
654
- return <></>;
655
- }
656
-
657
- return (
658
- <ThemeVariant variant={variant}>
659
- <div className={styles.topActionsContainer} style={containerStyles} data-testid={testid}>
660
- {actions.map((action, index) => {
661
- if ('Icon' in action || 'checkedProps' in action) {
662
- return <CardActionIconButton key={index} {...action} />;
663
- }
664
- return action;
665
- })}
666
- </div>
667
- </ThemeVariant>
668
- );
669
- };
670
-
671
- type MediaComponentProps = {
672
- type: CardType;
673
- size: CardSize;
674
- asset?: React.ReactElement;
675
- imageSrc?: string;
676
- imageSrcSet?: string;
677
- imageAlt?: string;
678
- imageFit: 'fit' | 'fill' | 'fill-center';
679
- video?: React.ReactNode;
680
- mediaAspectRatio: MediaAspectRatio;
681
- mediaPosition: MediaPosition;
682
- mediaWidth: string | number;
683
- videoAction?: CardAction;
684
- circledImage?: boolean;
685
- };
686
-
687
- const Media = ({
688
- type,
689
- size,
690
- asset,
691
- imageSrc,
692
- imageSrcSet,
693
- imageFit,
694
- imageAlt = '',
695
- video,
696
- mediaAspectRatio,
697
- mediaPosition,
698
- mediaWidth,
699
- circledImage,
700
- }: MediaComponentProps): JSX.Element => {
701
- const aspectRatioAsNumber = aspectRatioToNumber(mediaAspectRatio);
702
-
703
- const imageProps =
704
- type === 'naked' && circledImage
705
- ? {circular: true}
706
- : {
707
- width: '100%',
708
- height: mediaPosition === 'top' ? (aspectRatioAsNumber === 0 ? undefined : '100%') : '100%',
709
- };
710
-
711
- const renderMedia = () => {
712
- if (video) {
713
- return video;
714
- }
715
- if (imageSrc !== undefined || imageSrcSet !== undefined) {
716
- const isLeftOrRight = mediaPosition === 'left' || mediaPosition === 'right';
717
- const imageFitProps = {
718
- fit: {objectFit: 'contain', objectPosition: `bottom ${mediaPosition}`},
719
- fill: {objectFit: 'cover', objectPosition: mediaPosition},
720
- 'fill-center': {objectFit: 'cover', objectPosition: 'center'},
721
- } as const;
722
-
723
- return (
724
- <Image
725
- src={imageSrc || ''}
726
- srcSet={imageSrcSet}
727
- {...imageProps}
728
- dataAttributes={{testid: 'image'}}
729
- alt={imageAlt}
730
- {...(isLeftOrRight ? imageFitProps[imageFit] : {})}
731
- />
732
- );
733
- }
734
- return null;
735
- };
736
-
737
- const mediaElement = renderMedia();
738
-
739
- if (!mediaElement) {
740
- return <></>;
741
- }
742
-
743
- const commonContainerStyles = {
744
- // overrides media border radius
745
- ...(type === 'naked' ? undefined : applyCssVars({[mediaStyles.vars.mediaBorderRadius]: '0px'})),
746
- };
747
-
748
- if (mediaPosition === 'top') {
749
- // using AspectRatioContainer because the <video> element flashes with the poster image size while loading
750
- return (
751
- <>
752
- <AspectRatioContainer aspectRatio={aspectRatioAsNumber} style={commonContainerStyles}>
753
- {mediaElement}
754
- </AspectRatioContainer>
755
- <Asset absolute size={size} asset={asset} type={type} />
756
- </>
757
- );
758
- }
759
-
760
- // in left/right media position, mediaAspectRatio is ignored
761
- return (
762
- <>
763
- <div
764
- style={{
765
- ...commonContainerStyles,
766
- width: mediaWidth,
767
- flexShrink: 0,
768
- flexGrow: 0,
769
- height: '100%',
770
- position: 'relative',
771
- }}
772
- >
773
- {mediaElement}
774
- </div>
775
- {mediaPosition !== 'right' && <Asset absolute size={size} asset={asset} type={type} />}
776
- </>
777
- );
778
- };
779
-
780
- type PrivateFooterProps = {
781
- type: CardType;
782
- size: CardSize;
783
- variant: NonDeprecatedVariant;
784
- hasBackgroundImageOrVideo?: boolean;
785
- externalVariant: NonDeprecatedVariant;
786
- overlayColor: string;
787
- };
788
-
789
- const Footer = ({
790
- type,
791
- size,
792
- variant,
793
- footerSlot,
794
- buttonPrimary,
795
- buttonSecondary,
796
- buttonLink,
797
- hasBackgroundImageOrVideo,
798
- footerVariant,
799
- footerBackgroundColor,
800
- footerDivider,
801
- externalVariant,
802
- overlayColor,
803
- }: FooterProps & ButtonsProps & PrivateFooterProps): JSX.Element => {
804
- const hasButtons = !!(buttonPrimary || buttonSecondary || buttonLink);
805
- const has3Buttons = !!(buttonPrimary && buttonSecondary && buttonLink);
806
- const dividerColor = {
807
- default: skinVars.colors.divider,
808
- brand: skinVars.colors.dividerBrand,
809
- negative: skinVars.colors.dividerNegative,
810
- media: skinVars.colors.dividerBrand,
811
- alternative: skinVars.colors.divider,
812
- }[variant];
813
- const isNaked = type === 'naked';
814
- const backgroundColor =
815
- footerBackgroundColor ||
816
- (footerVariant && footerVariant !== variant
817
- ? footerVariant === 'default'
818
- ? skinVars.colors.backgroundContainer
819
- : externalVariant === 'brand' || externalVariant === 'media' || externalVariant === 'negative'
820
- ? skinVars.colors.backgroundContainerBrandOverBrand
821
- : skinVars.colors.backgroundContainerBrand
822
- : undefined);
823
- const withDivider = footerDivider ?? !backgroundColor;
824
-
825
- return (
826
- <ThemeVariant variant={footerVariant || variant}>
827
- <Filler />
828
- <div
829
- style={{
830
- background: backgroundColor || (hasBackgroundImageOrVideo ? overlayColor : undefined),
831
- position: 'relative',
832
- backdropFilter: hasBackgroundImageOrVideo ? 'blur(12px)' : undefined,
833
- borderBottomLeftRadius: isNaked ? 0 : skinVars.borderRadii.container,
834
- borderBottomRightRadius: isNaked ? 0 : skinVars.borderRadii.container,
835
- }}
836
- >
837
- <div
838
- // The divider is outside the footer because it has a conditional right margin
839
- style={{
840
- borderTop: withDivider ? `1px solid ${dividerColor}` : undefined,
841
- marginRight: isNaked ? 16 : 0,
842
- }}
843
- />
844
- <div
845
- data-testid="footer"
846
- className={classnames({
847
- [styles.containerPaddingXVariants[size]]: !isNaked,
848
- [styles.containerPaddingBottomVariants[size]]: !isNaked,
849
- })}
850
- style={{
851
- paddingTop: 16,
852
- paddingBottom: isNaked ? 0 : undefined,
853
- paddingRight: isNaked ? 16 : undefined,
854
- }}
855
- >
856
- <Stack space={16}>
857
- {footerSlot}
858
- {hasButtons &&
859
- // @FIXME: We should use the ButtonGroup component
860
- // https://jira.tid.es/browse/WEB-2278
861
- // https://www.figma.com/design/koROdh3HpEPG2O8jG52Emh/%F0%9F%94%B8-Buttons-Specs?node-id=4337-1606&t=HtImvar8DMbivDqC-0
862
- (has3Buttons ? (
863
- <Stack space={16}>
864
- <Inline space="between" alignItems="center">
865
- {buttonPrimary}
866
- {buttonSecondary}
867
- </Inline>
868
- <div
869
- // bleed workaround
870
- style={{marginLeft: -12}}
871
- >
872
- {buttonLink}
873
- </div>
874
- </Stack>
875
- ) : (
876
- <Inline space="between" alignItems="center">
877
- {buttonPrimary}
878
- {buttonSecondary}
879
- {buttonLink}
880
- </Inline>
881
- ))}
882
- </Stack>
883
- </div>
884
- </div>
885
- </ThemeVariant>
886
- );
887
- };
888
-
889
- type PrivateTextContentProps = {
890
- size: CardSize;
891
- variant?: Variant;
892
- withTextShadow?: boolean;
893
- headlineRef?: (element: HTMLHeadingElement | null) => void;
894
- hasCustomBackground: boolean;
895
- touchableRef?: React.RefObject<TouchableElement | null>;
896
- touchableProps?: TouchableProps;
897
- };
898
-
899
- const TextContent = ({
900
- type,
901
- hasCustomBackground,
902
- headlineRef,
903
- touchableRef,
904
- touchableProps,
905
- size,
906
- variant,
907
- headline,
908
- title: titleProp,
909
- titleAs = 'h3',
910
- titleLinesMax,
911
- pretitle: pretitleProp,
912
- pretitleAs,
913
- pretitleLinesMax,
914
- subtitle,
915
- subtitleLinesMax,
916
- description,
917
- descriptionLinesMax,
918
- withTextShadow,
919
- }: TextContentProps & PrivateTextContentProps): JSX.Element => {
920
- const {textPresets, colorValues} = useTheme();
921
- const externalVariant = useThemeVariant();
922
-
923
- const title = typeof titleProp === 'string' ? {text: titleProp} : titleProp;
924
- const pretitle = typeof pretitleProp === 'string' ? {text: pretitleProp} : pretitleProp;
925
-
926
- const commonProps = {
927
- hyphens: 'auto',
928
- } as const;
929
-
930
- const colorVariants = {
931
- default: {
932
- pretitle: colorValues.textPrimary,
933
- title: colorValues.textPrimary,
934
- subtitle: colorValues.textPrimary,
935
- description: colorValues.textSecondary,
936
- },
937
- brand: {
938
- pretitle: colorValues.textPrimaryBrand,
939
- title: colorValues.textPrimaryBrand,
940
- subtitle: colorValues.textPrimaryBrand,
941
- description: colorValues.textSecondaryBrand,
942
- },
943
- negative: {
944
- pretitle: colorValues.textPrimaryNegative,
945
- title: colorValues.textPrimaryNegative,
946
- subtitle: colorValues.textPrimaryNegative,
947
- description: colorValues.textSecondaryNegative,
948
- },
949
- media: {
950
- pretitle: colorValues.textPrimaryMedia,
951
- title: colorValues.textPrimaryMedia,
952
- subtitle: colorValues.textPrimaryMedia,
953
- description:
954
- type === 'cover' && hasCustomBackground
955
- ? colorValues.textPrimaryMedia
956
- : colorValues.textSecondaryMedia,
957
- },
958
- } as const;
959
-
960
- const textVariants = {
961
- snap: {
962
- pretitle: {
963
- mobileSize: textPresets.cardPretitleSnap.size.mobile,
964
- desktopSize: textPresets.cardPretitleSnap.size.desktop,
965
- mobileLineHeight: textPresets.cardPretitleSnap.lineHeight.mobile,
966
- desktopLineHeight: textPresets.cardPretitleSnap.lineHeight.desktop,
967
- weight: 'regular',
968
- },
969
- title: {
970
- mobileSize: textPresets.cardTitleSnap.size.mobile,
971
- desktopSize: textPresets.cardTitleSnap.size.desktop,
972
- mobileLineHeight: textPresets.cardTitleSnap.lineHeight.mobile,
973
- desktopLineHeight: textPresets.cardTitleSnap.lineHeight.desktop,
974
- weight: textPresets.cardTitle.weight,
975
- },
976
- subtitle: {
977
- mobileSize: textPresets.cardSubtitleSnap.size.mobile,
978
- desktopSize: textPresets.cardSubtitleSnap.size.desktop,
979
- mobileLineHeight: textPresets.cardSubtitleSnap.lineHeight.mobile,
980
- desktopLineHeight: textPresets.cardSubtitleSnap.lineHeight.desktop,
981
- weight: 'regular',
982
- },
983
- description: {
984
- mobileSize: textPresets.cardDescriptionSnap.size.mobile,
985
- desktopSize: textPresets.cardDescriptionSnap.size.desktop,
986
- mobileLineHeight: textPresets.cardDescriptionSnap.lineHeight.mobile,
987
- desktopLineHeight: textPresets.cardDescriptionSnap.lineHeight.desktop,
988
- weight: 'regular',
989
- },
990
- },
991
- default: {
992
- pretitle: {
993
- mobileSize: textPresets.cardPretitleDefault.size.mobile,
994
- desktopSize: textPresets.cardPretitleDefault.size.desktop,
995
- mobileLineHeight: textPresets.cardPretitleDefault.lineHeight.mobile,
996
- desktopLineHeight: textPresets.cardPretitleDefault.lineHeight.desktop,
997
- weight: 'regular',
998
- },
999
- title: {
1000
- mobileSize: textPresets.cardTitleDefault.size.mobile,
1001
- desktopSize: textPresets.cardTitleDefault.size.desktop,
1002
- mobileLineHeight: textPresets.cardTitleDefault.lineHeight.mobile,
1003
- desktopLineHeight: textPresets.cardTitleDefault.lineHeight.desktop,
1004
- weight: textPresets.cardTitle.weight,
1005
- },
1006
- subtitle: {
1007
- mobileSize: textPresets.cardSubtitleDefault.size.mobile,
1008
- desktopSize: textPresets.cardSubtitleDefault.size.desktop,
1009
- mobileLineHeight: textPresets.cardSubtitleDefault.lineHeight.mobile,
1010
- desktopLineHeight: textPresets.cardSubtitleDefault.lineHeight.desktop,
1011
- weight: 'regular',
1012
- },
1013
- description: {
1014
- mobileSize: textPresets.cardDescriptionDefault.size.mobile,
1015
- desktopSize: textPresets.cardDescriptionDefault.size.desktop,
1016
- mobileLineHeight: textPresets.cardDescriptionDefault.lineHeight.mobile,
1017
- desktopLineHeight: textPresets.cardDescriptionDefault.lineHeight.desktop,
1018
- weight: 'regular',
1019
- },
1020
- },
1021
- display: {
1022
- pretitle: {
1023
- mobileSize: textPresets.text2.size.mobile,
1024
- desktopSize: textPresets.text2.size.desktop,
1025
- mobileLineHeight: textPresets.text2.lineHeight.mobile,
1026
- desktopLineHeight: textPresets.text2.lineHeight.desktop,
1027
- weight: 'regular',
1028
- },
1029
- title: {
1030
- mobileSize: textPresets.text6.size.mobile,
1031
- desktopSize: textPresets.text6.size.desktop,
1032
- mobileLineHeight: textPresets.text6.lineHeight.mobile,
1033
- desktopLineHeight: textPresets.text6.lineHeight.desktop,
1034
- weight: textPresets.text6.weight,
1035
- },
1036
- subtitle: {
1037
- mobileSize: textPresets.text2.size.mobile,
1038
- desktopSize: textPresets.text2.size.desktop,
1039
- mobileLineHeight: textPresets.text2.lineHeight.mobile,
1040
- desktopLineHeight: textPresets.text2.lineHeight.desktop,
1041
- weight: 'regular',
1042
- },
1043
- description: {
1044
- mobileSize: textPresets.text3.size.mobile,
1045
- desktopSize: textPresets.text3.size.desktop,
1046
- mobileLineHeight: textPresets.text3.lineHeight.mobile,
1047
- desktopLineHeight: textPresets.text3.lineHeight.desktop,
1048
- weight: 'regular',
1049
- },
1050
- },
1051
- } as const;
1052
-
1053
- const colors =
1054
- colorVariants[variant as keyof typeof colorVariants] ||
1055
- colorVariants[externalVariant as keyof typeof colorVariants] ||
1056
- colorVariants.default;
1057
- const textVariant = textVariants[size] || textVariants.default;
1058
- const textShadowStyle = withTextShadow ? '0 0 15px rgba(0, 0, 0, 0.4)' : undefined;
1059
-
1060
- const touchableTarget = touchableProps
1061
- ? (() => {
1062
- if (title?.text && pretitle?.text) {
1063
- return isBiggerHeading(titleAs, pretitleAs) ? 'title' : 'pretitle';
1064
- }
1065
- if (title?.text) return 'title';
1066
- if (pretitle?.text) return 'pretitle';
1067
- if (headline) return 'headline';
1068
- if (subtitle) return 'subtitle';
1069
- if (description) return 'description';
1070
- return null;
1071
- })()
1072
- : null;
1073
-
1074
- const renderText = (
1075
- children: React.ReactNode,
1076
- containerProps: Record<string, unknown>,
1077
- isTouchableTarget: boolean
1078
- ) => {
1079
- if (!children) {
1080
- return null;
1081
- }
1082
- if (!isTouchableTarget) {
1083
- return <div {...containerProps}>{children}</div>;
1084
- }
1085
-
1086
- return (
1087
- <div {...containerProps}>
1088
- <BaseTouchable
1089
- maybe
1090
- {...touchableProps}
1091
- ref={touchableRef}
1092
- className={classnames(styles.touchable, styles.stretchedLink)}
1093
- >
1094
- {children}
1095
- </BaseTouchable>
1096
- </div>
1097
- );
1098
- };
1099
-
1100
- const headlineElement = renderText(
1101
- headline && typeof headline === 'string' ? <Tag type="promo">{headline}</Tag> : headline,
1102
- // Read order 2. Visual order 1
1103
- {style: {order: 1, paddingBottom: 8}, 'data-testid': 'headline', ref: headlineRef},
1104
- touchableTarget === 'headline'
1105
- );
1106
-
1107
- const pretitleElement = renderText(
1108
- pretitle?.text && (
1109
- <Text
1110
- {...commonProps}
1111
- {...textVariant.pretitle}
1112
- as={pretitleAs || 'p'}
1113
- truncate={pretitleLinesMax}
1114
- color={colors.pretitle}
1115
- textShadow={textShadowStyle}
1116
- aria-label={pretitle?.['aria-label']}
1117
- >
1118
- {pretitle.text}
1119
- </Text>
1120
- ),
1121
- {style: {paddingBottom: 4, order: 2}, 'data-testid': 'pretitle'},
1122
- touchableTarget === 'pretitle'
1123
- );
1124
-
1125
- const titleElement = renderText(
1126
- title?.text && (
1127
- <Text
1128
- {...commonProps}
1129
- {...textVariant.title}
1130
- as={titleAs}
1131
- truncate={titleLinesMax}
1132
- color={colors.title}
1133
- textShadow={textShadowStyle}
1134
- aria-label={title?.['aria-label']}
1135
- >
1136
- {title.text}
1137
- </Text>
1138
- ),
1139
- // Read order: 1 or 3. Visual order 3
1140
- {style: {paddingBottom: 4, order: 3}, 'data-testid': 'title'},
1141
- touchableTarget === 'title'
1142
- );
1143
-
1144
- const subtitleElement = renderText(
1145
- subtitle && (
1146
- <Text
1147
- {...commonProps}
1148
- {...textVariant.subtitle}
1149
- as="p"
1150
- truncate={subtitleLinesMax}
1151
- color={colors.subtitle}
1152
- textShadow={textShadowStyle}
1153
- >
1154
- {subtitle}
1155
- </Text>
1156
- ),
1157
- // Read order: 4. Visual order 4
1158
- {style: {paddingBottom: 0, order: 4}, 'data-testid': 'subtitle'},
1159
- touchableTarget === 'subtitle'
1160
- );
1161
-
1162
- const descriptionElement = renderText(
1163
- description && (
1164
- <Text
1165
- {...commonProps}
1166
- {...textVariant.description}
1167
- as="p"
1168
- truncate={descriptionLinesMax}
1169
- color={colors.description}
1170
- textShadow={textShadowStyle}
1171
- >
1172
- {description}
1173
- </Text>
1174
- ),
1175
- // Read order: 5. Visual order 5
1176
- {style: {paddingTop: 4, order: 5}, 'data-testid': 'description'},
1177
- touchableTarget === 'description'
1178
- );
1179
-
1180
- const [title1, title2] =
1181
- title && isBiggerHeading(titleAs, pretitleAs)
1182
- ? [titleElement, pretitleElement]
1183
- : [pretitleElement, titleElement];
1184
-
1185
- return (
1186
- <div style={{display: 'flex', flexDirection: 'column'}}>
1187
- {title1}
1188
- {headlineElement}
1189
- {title2}
1190
- {subtitleElement}
1191
- {descriptionElement}
1192
- </div>
1193
- );
1194
- };
1195
-
1196
- type CardTouchableProps = {
1197
- children: React.ReactNode;
1198
- isTouchable: boolean;
1199
- touchableAriaLabel?: string;
1200
- ariaLabeledByProp?: string;
1201
- ariaDescriptionProp?: string;
1202
- ariaDescribedByProp?: string;
1203
- touchableProps: TouchableProps;
1204
- segregateTouchableContent: boolean;
1205
- hasTouchableInContent: boolean;
1206
- overlayClassname: string;
1207
- contentStyle: React.CSSProperties;
1208
- contentRadiusStyle: React.CSSProperties;
1209
- };
1210
-
1211
- const CardTouchable = ({
1212
- children,
1213
- isTouchable,
1214
- touchableAriaLabel,
1215
- ariaLabeledByProp,
1216
- ariaDescriptionProp,
1217
- ariaDescribedByProp,
1218
- touchableProps,
1219
- segregateTouchableContent,
1220
- hasTouchableInContent,
1221
- overlayClassname,
1222
- contentStyle,
1223
- contentRadiusStyle,
1224
- }: CardTouchableProps) => {
1225
- const isOverlayInsideContent = isTouchable && (!segregateTouchableContent || hasTouchableInContent);
1226
-
1227
- const content = (
1228
- /**
1229
- * role="text" makes VoiceOver read the whole div as a single text block. This is needed
1230
- * for VoiceOver rectangle to cover the whole card when using aria-label in <a> elements,
1231
- * otherwise it only renders a small rectangle in the begining of the <a> element.
1232
- * This workaround is only needed for <a> not for <button> (ask safari developers why)
1233
- */
1234
- <div
1235
- role={
1236
- !segregateTouchableContent && (touchableProps.href || touchableProps.to) ? 'text' : undefined
1237
- }
1238
- className={styles.touchableContent}
1239
- style={{...contentStyle, ...contentRadiusStyle}}
1240
- >
1241
- {isOverlayInsideContent && <div className={overlayClassname} />}
1242
- {children}
1243
- </div>
1244
- );
1245
-
1246
- if (isTouchable && segregateTouchableContent) {
1247
- return hasTouchableInContent ? (
1248
- <div className={classnames(styles.touchable, styles.touchableContainer)}>{content}</div>
1249
- ) : (
1250
- <div style={{position: 'relative'}}>
1251
- <BaseTouchable
1252
- aria-label={touchableAriaLabel}
1253
- maybe
1254
- {...touchableProps}
1255
- className={classnames(
1256
- styles.touchable,
1257
- styles.touchableContainer,
1258
- styles.stretchedTouchable
1259
- )}
1260
- >
1261
- <div className={classnames(overlayClassname)} style={contentRadiusStyle} />
1262
- </BaseTouchable>
1263
- {content}
1264
- </div>
1265
- );
1266
- }
1267
-
1268
- return (
1269
- <BaseTouchable
1270
- maybe
1271
- aria-label={isTouchable ? touchableAriaLabel : undefined}
1272
- aria-labelledby={isTouchable ? ariaLabeledByProp : undefined}
1273
- aria-description={isTouchable ? ariaDescriptionProp : undefined}
1274
- aria-describedby={isTouchable ? ariaDescribedByProp : undefined}
1275
- className={classnames(styles.touchable, styles.touchableContainer)}
1276
- {...touchableProps}
1277
- >
1278
- {content}
1279
- </BaseTouchable>
1280
- );
1281
- };
1282
-
1283
- const SKIN_OVERLAY_COLORS = [
1284
- skinVars.colors.cardContentOverlay as string,
1285
- skinVars.colors.cardFooterOverlay as string,
1286
- ];
1287
-
1288
- const RGBA_REGEX = /rgba\([^,]+,\s*[^,]+,\s*[^,]+,\s*([^)]+)\)/g;
1289
-
1290
- const replaceRgbaWithColor = (stringWithRgbaColors: string, newColor: string): string => {
1291
- return stringWithRgbaColors.replace(RGBA_REGEX, (_, alpha) => applyAlpha(newColor, parseFloat(alpha)));
1292
- };
1293
-
1294
- export const InternalCard = React.forwardRef<HTMLDivElement, MaybeTouchableCard<CardProps>>(
1295
- (
1296
- {
1297
- type,
1298
- size,
1299
- backgroundColor: backgroundColorProp,
1300
- imageSrc,
1301
- imageSrcSet,
1302
- imageAlt = '',
1303
- imageFit = 'fill-center',
1304
- videoSrc,
1305
- videoRef,
1306
- media,
1307
- mediaAspectRatio: mediaAspectRatioProp = 'auto',
1308
- mediaPosition: mediaPositionProp = 'top',
1309
- mediaWidth = 150,
1310
- circledImage,
1311
- asset,
1312
- headline,
1313
- title,
1314
- titleAs = 'h3',
1315
- titleLinesMax,
1316
- pretitle,
1317
- pretitleAs,
1318
- pretitleLinesMax,
1319
- subtitle,
1320
- subtitleLinesMax,
1321
- description,
1322
- descriptionLinesMax,
1323
- dataAttributes,
1324
- variant: variantProp,
1325
- width,
1326
- height,
1327
- aspectRatio,
1328
- slot,
1329
- slotAlignment = 'content',
1330
- buttonPrimary,
1331
- buttonSecondary,
1332
- buttonLink,
1333
- showFooter: showFooterProp,
1334
- footerBackgroundColor,
1335
- footerVariant,
1336
- footerSlot,
1337
- footerDivider,
1338
- topActions,
1339
- onClose,
1340
- closeButtonLabel,
1341
- 'aria-label': ariaLabelProp,
1342
- 'aria-labelledby': ariaLabeledByProp,
1343
- 'aria-description': ariaDescriptionProp,
1344
- 'aria-describedby': ariaDescribedByProp,
1345
- gradientOverlayColor,
1346
- videoLoop,
1347
- videoAutoPlay,
1348
- videoDataAttributes,
1349
- segregateTouchableContent = false,
1350
- touchableAriaLabel: touchableAriaLabelProp,
1351
- ...touchableProps
1352
- },
1353
- ref
1354
- ): JSX.Element => {
1355
- const {text: slotText, ref: slotRef} = useInnerText();
1356
- const {text: headlineText, ref: headlineRef} = useInnerText();
1357
- const touchableContentRef = React.useRef<TouchableElement>(null);
1358
- const isTouchable = !!(touchableProps.href || touchableProps.to || touchableProps.onPress);
1359
- const hasTouchableInContent = !!(
1360
- segregateTouchableContent &&
1361
- !touchableAriaLabelProp &&
1362
- (title || pretitle || headline || subtitle || description)
1363
- );
1364
- const hasButtons = !!(buttonPrimary || buttonSecondary || buttonLink);
1365
- const {colorValues} = useTheme();
1366
-
1367
- // In this context "media" refers to the image or video that is placed inside the card, not the background
1368
- const typeAllowsMedia = type === 'media' || type === 'naked';
1369
- const hasMediaImage = typeAllowsMedia && (imageSrc !== undefined || imageSrcSet !== undefined);
1370
- const hasMediaVideo = typeAllowsMedia && videoSrc !== undefined;
1371
- const hasMediaSources = hasMediaImage || hasMediaVideo;
1372
- const hasDeprecatedMedia = typeAllowsMedia && !!media && !hasMediaSources;
1373
- const hasMedia = hasMediaSources || hasDeprecatedMedia;
1374
- const isNaked = type === 'naked';
1375
-
1376
- // If no media is provided, we use the "top" media position to simplify logic
1377
- const mediaPosition = hasMedia ? mediaPositionProp : 'top';
1378
- // Override mediaAspectRatio for naked cards with circled image
1379
- const mediaAspectRatio = type === 'naked' && circledImage ? 1 : mediaAspectRatioProp;
1380
-
1381
- // We consider any string (including empty string) as an image/video source. If not valid a fallback image will be used.
1382
- const hasBackgroundImage = type === 'cover' && (imageSrc !== undefined || imageSrcSet !== undefined);
1383
- const hasBackgroundVideo = type === 'cover' && videoSrc !== undefined;
1384
- const hasCustomBackground = !!backgroundColorProp || hasBackgroundImage || hasBackgroundVideo;
1385
- const hasBackgroundImageOrVideo = hasBackgroundImage || hasBackgroundVideo;
1386
-
1387
- const shouldShowVideo = hasMediaVideo || hasBackgroundVideo;
1388
- const {video, videoAction} = useVideoWithControls({
1389
- src: shouldShowVideo ? videoSrc : undefined,
1390
- poster: imageSrc,
1391
- ref: videoRef,
1392
- autoHeight:
1393
- type === 'cover' || mediaPosition !== 'top'
1394
- ? false
1395
- : aspectRatioToNumber(mediaAspectRatio) === 0,
1396
- loop: videoLoop,
1397
- autoPlay: videoAutoPlay,
1398
- dataAttributes: videoDataAttributes,
1399
- });
1400
-
1401
- const externalVariant = useThemeVariant();
1402
- const backgroundVariant = variantProp ? normalizeVariant(variantProp) : externalVariant;
1403
- const variant =
1404
- (variantProp && normalizeVariant(variantProp)) ||
1405
- (type === 'cover' && hasCustomBackground ? 'media' : 'default');
1406
-
1407
- const overlayStyle =
1408
- variant === 'brand' ? styles.touchableCardOverlayInverse : styles.touchableCardOverlay;
1409
-
1410
- // If the card has actions and an onClose handler, the footer will always be shown
1411
- // If the footer has no content, it will not be shown
1412
- const shouldShowFooter =
1413
- (showFooterProp && (hasButtons || !!footerSlot)) || (hasButtons && isTouchable);
1414
-
1415
- const showButtonsInBody = !shouldShowFooter && hasButtons;
1416
-
1417
- const topActionsLengthWithoutVideo = (topActions?.length || 0) + (onClose ? 1 : 0);
1418
- const topActionsLength = videoAction
1419
- ? topActionsLengthWithoutVideo + 1
1420
- : topActionsLengthWithoutVideo;
1421
-
1422
- const hasAssetInContent = asset && !(hasMedia && mediaPosition === 'left');
1423
- const shouldAddContentSpacingForTopActions =
1424
- type !== 'cover' && topActionsLength > 0 && !hasAssetInContent && !headline;
1425
-
1426
- // See asset spacing config in spec
1427
- const isAssetConfigA = type === 'cover' || (type === 'data' && size === 'display');
1428
-
1429
- const borderRadius = skinVars.borderRadii.container;
1430
-
1431
- const backgroundColor =
1432
- hasBackgroundImage || hasBackgroundVideo
1433
- ? 'transparent'
1434
- : backgroundColorProp ||
1435
- (variant === 'media'
1436
- ? externalVariant === 'brand' ||
1437
- externalVariant === 'media' ||
1438
- externalVariant === 'negative'
1439
- ? skinVars.colors.backgroundContainerBrandOverBrand
1440
- : skinVars.colors.backgroundBrand
1441
- : variant === 'alternative'
1442
- ? skinVars.colors.backgroundAlternative
1443
- : undefined);
1444
-
1445
- const touchableAriaLabel =
1446
- touchableAriaLabelProp ||
1447
- ariaLabelProp ||
1448
- (ariaLabeledByProp
1449
- ? undefined
1450
- : (title && isBiggerHeading(titleAs, pretitleAs)
1451
- ? [title, imageAlt, headlineText, pretitle, subtitle, description, slotText]
1452
- : [pretitle, headlineText, title, imageAlt, subtitle, description, slotText]
1453
- )
1454
- .filter(Boolean)
1455
- .join(' '));
1456
-
1457
- const calcOverlayBackgrounds = () => {
1458
- if (gradientOverlayColor === 'transparent') {
1459
- return ['transparent', 'transparent'];
1460
- }
1461
- if (gradientOverlayColor) {
1462
- return [
1463
- replaceRgbaWithColor(colorValues.cardContentOverlay, gradientOverlayColor),
1464
- replaceRgbaWithColor(colorValues.cardFooterOverlay, gradientOverlayColor),
1465
- ];
1466
- } else {
1467
- return SKIN_OVERLAY_COLORS;
1468
- }
1469
- };
1470
-
1471
- const [contentOverlayBackground, footerOverlayBackground] = calcOverlayBackgrounds();
1472
-
1473
- return (
1474
- <Container
1475
- aria-label={isTouchable ? undefined : ariaLabelProp}
1476
- aria-labelledby={isTouchable ? undefined : ariaLabeledByProp}
1477
- aria-description={isTouchable ? undefined : ariaDescriptionProp}
1478
- aria-describedby={isTouchable ? undefined : ariaDescribedByProp}
1479
- type={type}
1480
- size={size}
1481
- dataAttributes={dataAttributes}
1482
- ref={ref}
1483
- variant={variant}
1484
- width={width}
1485
- height={height}
1486
- aspectRatio={aspectRatio}
1487
- backgroundColor={backgroundColor}
1488
- >
1489
- {hasBackgroundImageOrVideo && (
1490
- <BackgroundImageOrVideo
1491
- video={video}
1492
- src={imageSrc}
1493
- srcSet={imageSrcSet}
1494
- backgroundVariant={backgroundVariant}
1495
- />
1496
- )}
1497
-
1498
- {videoAction && (
1499
- // The video action is placed first in the card reading order, so it is placed outside the other topActions container
1500
- <div data-testid="videoAction">
1501
- <TopActions
1502
- testid="videoAction"
1503
- variant="media"
1504
- actions={[videoAction]}
1505
- containerStyles={{
1506
- position: 'absolute',
1507
- top: 16,
1508
- left:
1509
- mediaPosition === 'left'
1510
- ? typeof mediaWidth === 'number'
1511
- ? `calc(${mediaWidth}px - 48px)`
1512
- : `calc(${mediaWidth} - 48px)`
1513
- : 'auto',
1514
- right:
1515
- mediaPosition !== 'left'
1516
- ? topActionsLengthWithoutVideo * 48 + 16
1517
- : 'auto',
1518
- }}
1519
- />
1520
- </div>
1521
- )}
1522
-
1523
- <CardTouchable
1524
- isTouchable={isTouchable}
1525
- touchableAriaLabel={touchableAriaLabel}
1526
- ariaLabeledByProp={ariaLabeledByProp}
1527
- ariaDescriptionProp={ariaDescriptionProp}
1528
- ariaDescribedByProp={ariaDescribedByProp}
1529
- touchableProps={touchableProps}
1530
- segregateTouchableContent={segregateTouchableContent}
1531
- hasTouchableInContent={hasTouchableInContent}
1532
- overlayClassname={overlayStyle}
1533
- contentStyle={{
1534
- flexDirection:
1535
- mediaPosition === 'top'
1536
- ? 'column'
1537
- : mediaPosition === 'left'
1538
- ? 'row'
1539
- : 'row-reverse',
1540
- }}
1541
- contentRadiusStyle={{
1542
- borderTopLeftRadius: isNaked && !hasMedia ? 0 : `calc(${borderRadius} - 1px)`,
1543
- borderTopRightRadius: isNaked && !hasMedia ? 0 : `calc(${borderRadius} - 1px)`,
1544
- borderBottomLeftRadius:
1545
- shouldShowFooter || isNaked ? 0 : `calc(${borderRadius} - 1px)`,
1546
- borderBottomRightRadius:
1547
- shouldShowFooter || isNaked ? 0 : `calc(${borderRadius} - 1px)`,
1548
- }}
1549
- >
1550
- {hasDeprecatedMedia && (
1551
- <div
1552
- style={{
1553
- // for some reason, this width is required to pass headless screenshot tests
1554
- // otherwise, it gets 0px width and the media is not visible
1555
- width: '100%',
1556
- ...(type === 'naked'
1557
- ? undefined
1558
- : applyCssVars({[mediaStyles.vars.mediaBorderRadius]: '0px'})),
1559
- }}
1560
- >
1561
- {media}
1562
- </div>
1563
- )}
1564
- {hasDeprecatedMedia && <Asset absolute size={size} asset={asset} type={type} />}
1565
-
1566
- {hasMedia && (
1567
- <Media
1568
- type={type}
1569
- size={size}
1570
- mediaAspectRatio={mediaAspectRatio}
1571
- mediaPosition={mediaPosition}
1572
- asset={asset}
1573
- video={video}
1574
- imageFit={imageFit}
1575
- imageSrc={imageSrc}
1576
- imageSrcSet={imageSrcSet}
1577
- imageAlt={imageAlt}
1578
- mediaWidth={mediaWidth}
1579
- circledImage={circledImage}
1580
- />
1581
- )}
1582
- <div
1583
- aria-hidden={isTouchable && !segregateTouchableContent}
1584
- data-testid="body"
1585
- className={classnames(styles.touchable, {
1586
- [styles.containerPaddingTopVariants[size]]:
1587
- !!asset && type !== 'naked' && (!hasMedia || mediaPosition === 'right'),
1588
- })}
1589
- >
1590
- {(!hasMedia || mediaPosition === 'right') && (
1591
- <Asset size={size} asset={asset} type={type} />
1592
- )}
1593
- {isAssetConfigA && (
1594
- <Filler
1595
- minHeight={type === 'cover' && topActionsLength > 0 && !asset ? 48 + 8 : 0}
1596
- />
1597
- )}
1598
- <div
1599
- className={classnames(
1600
- styles.containerPaddingXVariants[size],
1601
- styles.containerPaddingBottomVariants[size],
1602
- styles.containerPaddingTopVariants[size]
1603
- )}
1604
- style={{
1605
- display: 'flex',
1606
- flexDirection: 'column',
1607
- height: isAssetConfigA ? undefined : '100%',
1608
- background: hasBackgroundImageOrVideo ? contentOverlayBackground : undefined,
1609
- // padding overrides for specific cases
1610
- paddingTop:
1611
- isAssetConfigA && hasBackgroundImageOrVideo
1612
- ? 40
1613
- : asset
1614
- ? 16
1615
- : isNaked && mediaPosition !== 'top'
1616
- ? 16
1617
- : isNaked && !hasMedia
1618
- ? 0
1619
- : undefined,
1620
- paddingLeft:
1621
- isNaked && (mediaPosition !== 'left' || !hasMedia) ? 0 : undefined,
1622
- paddingRight: isNaked && mediaPosition !== 'right' ? 16 : undefined,
1623
- paddingBottom: shouldShowFooter ? 16 : isNaked ? 0 : undefined,
1624
- borderBottomLeftRadius: shouldShowFooter ? 0 : borderRadius,
1625
- borderBottomRightRadius: shouldShowFooter ? 0 : borderRadius,
1626
- }}
1627
- >
1628
- <div className={styles.contentContainer}>
1629
- <div className={styles.textContent}>
1630
- <TextContent
1631
- type={type}
1632
- hasCustomBackground={hasCustomBackground}
1633
- headlineRef={headlineRef}
1634
- variant={variant}
1635
- size={size}
1636
- headline={headline}
1637
- pretitle={pretitle}
1638
- pretitleAs={pretitleAs}
1639
- pretitleLinesMax={pretitleLinesMax}
1640
- title={title}
1641
- titleAs={titleAs}
1642
- titleLinesMax={titleLinesMax}
1643
- subtitle={subtitle}
1644
- subtitleLinesMax={subtitleLinesMax}
1645
- description={description}
1646
- descriptionLinesMax={descriptionLinesMax}
1647
- withTextShadow={hasBackgroundImageOrVideo}
1648
- {...(hasTouchableInContent
1649
- ? {touchableRef: touchableContentRef, touchableProps}
1650
- : {})}
1651
- />
1652
- </div>
1653
- {shouldAddContentSpacingForTopActions && (
1654
- <div
1655
- style={{
1656
- flexShrink: 0,
1657
- flexGrow: 0,
1658
- width:
1659
- topActionsLengthWithoutVideo * 48 -
1660
- // required space depends on the card padding
1661
- (type === 'naked' ? 0 : size === 'display' ? 24 : 16) -
1662
- //
1663
- 8,
1664
- }}
1665
- />
1666
- )}
1667
- </div>
1668
- {!isAssetConfigA && slotAlignment === 'bottom' && <Filler />}
1669
- {slot && (
1670
- <div
1671
- ref={slotRef}
1672
- data-testid="slot"
1673
- className={classnames(
1674
- slotAlignment === 'space-between' && styles.slotContainerSpaceBetween
1675
- )}
1676
- >
1677
- {slot}
1678
- </div>
1679
- )}
1680
- {!isAssetConfigA && slotAlignment === 'content' && showButtonsInBody && (
1681
- <Filler />
1682
- )}
1683
- {showButtonsInBody && (
1684
- <Buttons
1685
- size={size}
1686
- buttonPrimary={buttonPrimary}
1687
- buttonSecondary={buttonSecondary}
1688
- buttonLink={buttonLink}
1689
- />
1690
- )}
1691
- </div>
1692
- </div>
1693
- </CardTouchable>
1694
- {shouldShowFooter && (
1695
- <Footer
1696
- type={type}
1697
- variant={variant}
1698
- footerVariant={footerVariant}
1699
- footerBackgroundColor={footerBackgroundColor}
1700
- footerDivider={footerDivider}
1701
- size={size}
1702
- footerSlot={footerSlot}
1703
- buttonPrimary={buttonPrimary}
1704
- buttonSecondary={buttonSecondary}
1705
- buttonLink={buttonLink}
1706
- hasBackgroundImageOrVideo={hasBackgroundImageOrVideo}
1707
- externalVariant={externalVariant}
1708
- overlayColor={footerOverlayBackground}
1709
- />
1710
- )}
1711
- <TopActions
1712
- onClose={onClose}
1713
- closeButtonLabel={closeButtonLabel}
1714
- actions={topActions}
1715
- variant={
1716
- hasBackgroundImageOrVideo || (hasMedia && mediaPosition !== 'left')
1717
- ? 'media'
1718
- : variant
1719
- }
1720
- />
1721
- </Container>
1722
- );
1723
- }
1724
- );