@deriv-com/dds-marketing 1.0.1 → 1.1.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 (336) hide show
  1. package/.llm/components/awards.md +209 -0
  2. package/.llm/components/background.md +420 -0
  3. package/.llm/components/bottomsheet.md +5 -0
  4. package/.llm/components/comparisoncards.md +257 -0
  5. package/.llm/components/comparisontable.md +231 -0
  6. package/.llm/components/ctabanner.md +22 -0
  7. package/.llm/components/ctabannerslider.md +36 -2
  8. package/.llm/components/datatable.md +273 -0
  9. package/.llm/components/downloadbanner.md +283 -0
  10. package/.llm/components/featurecards.md +41 -3
  11. package/.llm/components/featurecardscarousel.md +311 -0
  12. package/.llm/components/featuresplit.md +5 -0
  13. package/.llm/components/featurestack.md +227 -0
  14. package/.llm/components/illustrationcard.md +236 -0
  15. package/.llm/components/illustrationscene.md +229 -0
  16. package/.llm/components/imagebanner.md +278 -0
  17. package/.llm/components/landinghero.md +24 -0
  18. package/.llm/components/navbar.md +1 -1
  19. package/.llm/components/navbaritem.md +4 -0
  20. package/.llm/components/pageheader.md +22 -0
  21. package/.llm/components/paginationdots.md +6 -1
  22. package/.llm/components/producthero.md +35 -11
  23. package/.llm/components/resourcebanner.md +247 -0
  24. package/.llm/components/scenescroll.md +222 -0
  25. package/.llm/components/select.md +17 -0
  26. package/.llm/components/stats.md +219 -0
  27. package/.llm/components/steps.md +286 -0
  28. package/.llm/components/stickycards.md +251 -0
  29. package/.llm/components/tableheadercell.md +19 -0
  30. package/.llm/components/teamgrid.md +243 -0
  31. package/.llm/components/testimonialrow.md +5 -0
  32. package/.llm/components/testimonialslider.md +14 -1
  33. package/.llm/components/textarea.md +13 -0
  34. package/.llm/components/textinput.md +13 -0
  35. package/.llm/components/textscroll.md +187 -0
  36. package/.llm/components/tiers.md +227 -0
  37. package/.llm/digest/awards.md +45 -0
  38. package/.llm/digest/background.md +53 -0
  39. package/.llm/digest/bottomsheet.md +2 -0
  40. package/.llm/digest/comparisoncards.md +51 -0
  41. package/.llm/digest/comparisontable.md +53 -0
  42. package/.llm/digest/ctabanner.md +4 -0
  43. package/.llm/digest/ctabannerslider.md +7 -0
  44. package/.llm/digest/datatable.md +65 -0
  45. package/.llm/digest/downloadbanner.md +65 -0
  46. package/.llm/digest/featurecards.md +1 -1
  47. package/.llm/digest/featurecardscarousel.md +54 -0
  48. package/.llm/digest/featuresplit.md +1 -0
  49. package/.llm/digest/featurestack.md +48 -0
  50. package/.llm/digest/illustrationcard.md +46 -0
  51. package/.llm/digest/illustrationscene.md +50 -0
  52. package/.llm/digest/imagebanner.md +64 -0
  53. package/.llm/digest/landinghero.md +7 -0
  54. package/.llm/digest/navbaritem.md +1 -0
  55. package/.llm/digest/pageheader.md +4 -0
  56. package/.llm/digest/paginationdots.md +3 -1
  57. package/.llm/digest/producthero.md +4 -2
  58. package/.llm/digest/resourcebanner.md +53 -0
  59. package/.llm/digest/scenescroll.md +49 -0
  60. package/.llm/digest/select.md +5 -0
  61. package/.llm/digest/stats.md +46 -0
  62. package/.llm/digest/steps.md +55 -0
  63. package/.llm/digest/stickycards.md +52 -0
  64. package/.llm/digest/tableheadercell.md +4 -0
  65. package/.llm/digest/teamgrid.md +53 -0
  66. package/.llm/digest/testimonialrow.md +2 -0
  67. package/.llm/digest/testimonialslider.md +4 -0
  68. package/.llm/digest/textarea.md +4 -0
  69. package/.llm/digest/textinput.md +4 -0
  70. package/.llm/digest/textscroll.md +43 -0
  71. package/.llm/digest/tiers.md +50 -0
  72. package/.llm/index.md +25 -2
  73. package/.llm/tokens.md +37 -1
  74. package/AGENTS.md +20 -1
  75. package/dist/components/awards-data.d.ts +24 -0
  76. package/dist/components/awards-data.js +11 -0
  77. package/dist/components/block-image-data.d.ts +24 -0
  78. package/dist/components/block-image-data.js +9 -0
  79. package/dist/components/blocks/awards/Awards.css +134 -0
  80. package/dist/components/blocks/awards/Awards.d.ts +24 -0
  81. package/dist/components/blocks/awards/Awards.js +114 -0
  82. package/dist/components/blocks/awards/Awards.types.d.ts +31 -0
  83. package/dist/components/blocks/awards/Awards.types.js +16 -0
  84. package/dist/components/blocks/awards/awards-impl.css +222 -0
  85. package/dist/components/blocks/cards-of.d.ts +16 -0
  86. package/dist/components/blocks/cards-of.js +23 -0
  87. package/dist/components/blocks/comparison-cards/ComparisonCards.css +195 -0
  88. package/dist/components/blocks/comparison-cards/ComparisonCards.d.ts +24 -0
  89. package/dist/components/blocks/comparison-cards/ComparisonCards.js +75 -0
  90. package/dist/components/blocks/comparison-cards/ComparisonCards.types.d.ts +49 -0
  91. package/dist/components/blocks/comparison-cards/ComparisonCards.types.js +26 -0
  92. package/dist/components/blocks/comparison-cards/comparison-cards-impl.css +262 -0
  93. package/dist/components/blocks/comparison-table/ComparisonTable.css +111 -0
  94. package/dist/components/blocks/comparison-table/ComparisonTable.d.ts +25 -0
  95. package/dist/components/blocks/comparison-table/ComparisonTable.js +100 -0
  96. package/dist/components/blocks/comparison-table/ComparisonTable.types.d.ts +36 -0
  97. package/dist/components/blocks/comparison-table/ComparisonTable.types.js +15 -0
  98. package/dist/components/blocks/comparison-table/comparison-table-impl.css +143 -0
  99. package/dist/components/blocks/cta-banner/CtaBanner.css +1 -0
  100. package/dist/components/blocks/cta-banner/CtaBanner.d.ts +1 -1
  101. package/dist/components/blocks/cta-banner/CtaBanner.js +3 -2
  102. package/dist/components/blocks/cta-banner/CtaBanner.types.d.ts +6 -0
  103. package/dist/components/blocks/cta-banner/CtaBanner.types.js +1 -1
  104. package/dist/components/blocks/cta-banner/cta-banner-impl.css +8 -0
  105. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.css +1 -0
  106. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.d.ts +1 -1
  107. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.js +10 -5
  108. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.types.d.ts +12 -0
  109. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.types.js +1 -1
  110. package/dist/components/blocks/cta-banner-slider/cta-banner-slider-impl.css +8 -0
  111. package/dist/components/blocks/data-table/DataTable.css +170 -0
  112. package/dist/components/blocks/data-table/DataTable.d.ts +29 -0
  113. package/dist/components/blocks/data-table/DataTable.js +84 -0
  114. package/dist/components/blocks/data-table/DataTable.types.d.ts +69 -0
  115. package/dist/components/blocks/data-table/DataTable.types.js +19 -0
  116. package/dist/components/blocks/data-table/data-table-impl.css +155 -0
  117. package/dist/components/blocks/download-banner/DownloadBanner.css +228 -0
  118. package/dist/components/blocks/download-banner/DownloadBanner.d.ts +28 -0
  119. package/dist/components/blocks/download-banner/DownloadBanner.js +75 -0
  120. package/dist/components/blocks/download-banner/DownloadBanner.types.d.ts +56 -0
  121. package/dist/components/blocks/download-banner/DownloadBanner.types.js +23 -0
  122. package/dist/components/blocks/download-banner/download-banner-impl.css +216 -0
  123. package/dist/components/blocks/faq-accordion/FaqAccordion.css +1 -0
  124. package/dist/components/blocks/faq-accordion/faq-accordion-impl.css +3 -7
  125. package/dist/components/blocks/feature-bullets/FeatureBullets.css +1 -0
  126. package/dist/components/blocks/feature-bullets/feature-bullets-impl.css +14 -1
  127. package/dist/components/blocks/feature-cards/FeatureCards.css +1 -0
  128. package/dist/components/blocks/feature-cards/FeatureCards.d.ts +2 -1
  129. package/dist/components/blocks/feature-cards/FeatureCards.js +4 -21
  130. package/dist/components/blocks/feature-cards/feature-cards-impl.css +10 -9
  131. package/dist/components/blocks/feature-cards-carousel/FeatureCardsCarousel.css +115 -0
  132. package/dist/components/blocks/feature-cards-carousel/FeatureCardsCarousel.d.ts +30 -0
  133. package/dist/components/blocks/feature-cards-carousel/FeatureCardsCarousel.js +160 -0
  134. package/dist/components/blocks/feature-cards-carousel/FeatureCardsCarousel.types.d.ts +52 -0
  135. package/dist/components/blocks/feature-cards-carousel/FeatureCardsCarousel.types.js +17 -0
  136. package/dist/components/blocks/feature-cards-carousel/feature-cards-carousel-impl.css +207 -0
  137. package/dist/components/blocks/feature-scroll/FeatureScroll.css +1 -0
  138. package/dist/components/blocks/feature-split/FeatureSplit.css +1 -0
  139. package/dist/components/blocks/feature-split/feature-split-impl.css +14 -1
  140. package/dist/components/blocks/feature-stack/FeatureStack.css +86 -0
  141. package/dist/components/blocks/feature-stack/FeatureStack.d.ts +19 -0
  142. package/dist/components/blocks/feature-stack/FeatureStack.js +27 -0
  143. package/dist/components/blocks/feature-stack/FeatureStack.types.d.ts +34 -0
  144. package/dist/components/blocks/feature-stack/FeatureStack.types.js +14 -0
  145. package/dist/components/blocks/feature-stack/feature-stack-impl.css +87 -0
  146. package/dist/components/blocks/image-banner/ImageBanner.css +133 -0
  147. package/dist/components/blocks/image-banner/ImageBanner.d.ts +32 -0
  148. package/dist/components/blocks/image-banner/ImageBanner.js +41 -0
  149. package/dist/components/blocks/image-banner/ImageBanner.types.d.ts +54 -0
  150. package/dist/components/blocks/image-banner/ImageBanner.types.js +14 -0
  151. package/dist/components/blocks/image-banner/image-banner-impl.css +281 -0
  152. package/dist/components/blocks/landing-hero/LandingHero.css +1 -0
  153. package/dist/components/blocks/landing-hero/LandingHero.d.ts +1 -1
  154. package/dist/components/blocks/landing-hero/LandingHero.js +4 -3
  155. package/dist/components/blocks/landing-hero/LandingHero.types.d.ts +7 -3
  156. package/dist/components/blocks/logo-columns/LogoColumns.css +1 -0
  157. package/dist/components/blocks/logo-rows/LogoRows.css +1 -0
  158. package/dist/components/blocks/page-header/PageHeader.css +1 -0
  159. package/dist/components/blocks/page-header/PageHeader.d.ts +1 -1
  160. package/dist/components/blocks/page-header/PageHeader.js +3 -2
  161. package/dist/components/blocks/page-header/PageHeader.types.d.ts +6 -0
  162. package/dist/components/blocks/page-header/PageHeader.types.js +1 -1
  163. package/dist/components/blocks/page-header/page-header-impl.css +10 -0
  164. package/dist/components/blocks/product-hero/ProductHero.css +8 -3
  165. package/dist/components/blocks/product-hero/ProductHero.d.ts +1 -1
  166. package/dist/components/blocks/product-hero/ProductHero.js +5 -2
  167. package/dist/components/blocks/product-hero/ProductHero.types.d.ts +5 -1
  168. package/dist/components/blocks/product-hero/ProductHero.types.js +1 -0
  169. package/dist/components/blocks/product-hero/product-hero-impl.css +43 -12
  170. package/dist/components/blocks/resource-banner/ResourceBanner.css +106 -0
  171. package/dist/components/blocks/resource-banner/ResourceBanner.d.ts +32 -0
  172. package/dist/components/blocks/resource-banner/ResourceBanner.js +51 -0
  173. package/dist/components/blocks/resource-banner/ResourceBanner.types.d.ts +44 -0
  174. package/dist/components/blocks/resource-banner/ResourceBanner.types.js +14 -0
  175. package/dist/components/blocks/resource-banner/resource-banner-impl.css +69 -0
  176. package/dist/components/blocks/scene-scroll/SceneScroll.css +93 -0
  177. package/dist/components/blocks/scene-scroll/SceneScroll.d.ts +36 -0
  178. package/dist/components/blocks/scene-scroll/SceneScroll.js +54 -0
  179. package/dist/components/blocks/scene-scroll/SceneScroll.types.d.ts +32 -0
  180. package/dist/components/blocks/scene-scroll/SceneScroll.types.js +15 -0
  181. package/dist/components/blocks/scene-scroll/scene-scroll-impl.css +275 -0
  182. package/dist/components/blocks/stats/Stats.css +139 -0
  183. package/dist/components/blocks/stats/Stats.d.ts +24 -0
  184. package/dist/components/blocks/stats/Stats.js +120 -0
  185. package/dist/components/blocks/stats/Stats.types.d.ts +36 -0
  186. package/dist/components/blocks/stats/Stats.types.js +19 -0
  187. package/dist/components/blocks/stats/stats-count.d.ts +34 -0
  188. package/dist/components/blocks/stats/stats-count.js +61 -0
  189. package/dist/components/blocks/stats/stats-impl.css +284 -0
  190. package/dist/components/blocks/stats/use-wheel.d.ts +37 -0
  191. package/dist/components/blocks/stats/use-wheel.js +126 -0
  192. package/dist/components/blocks/steps/Steps.css +202 -0
  193. package/dist/components/blocks/steps/Steps.d.ts +32 -0
  194. package/dist/components/blocks/steps/Steps.js +65 -0
  195. package/dist/components/blocks/steps/Steps.types.d.ts +48 -0
  196. package/dist/components/blocks/steps/Steps.types.js +21 -0
  197. package/dist/components/blocks/steps/steps-impl.css +216 -0
  198. package/dist/components/blocks/steps/use-turn.d.ts +33 -0
  199. package/dist/components/blocks/steps/use-turn.js +75 -0
  200. package/dist/components/blocks/sticky-cards/StickyCards.css +154 -0
  201. package/dist/components/blocks/sticky-cards/StickyCards.d.ts +35 -0
  202. package/dist/components/blocks/sticky-cards/StickyCards.js +153 -0
  203. package/dist/components/blocks/sticky-cards/StickyCards.types.d.ts +43 -0
  204. package/dist/components/blocks/sticky-cards/StickyCards.types.js +18 -0
  205. package/dist/components/blocks/sticky-cards/sticky-cards-impl.css +393 -0
  206. package/dist/components/blocks/team-grid/TeamGrid.css +159 -0
  207. package/dist/components/blocks/team-grid/TeamGrid.d.ts +28 -0
  208. package/dist/components/blocks/team-grid/TeamGrid.js +74 -0
  209. package/dist/components/blocks/team-grid/TeamGrid.types.d.ts +51 -0
  210. package/dist/components/blocks/team-grid/TeamGrid.types.js +20 -0
  211. package/dist/components/blocks/team-grid/team-grid-impl.css +129 -0
  212. package/dist/components/blocks/testimonial-row/TestimonialRow.css +1 -0
  213. package/dist/components/blocks/testimonial-row/TestimonialRow.d.ts +1 -1
  214. package/dist/components/blocks/testimonial-row/TestimonialRow.js +4 -3
  215. package/dist/components/blocks/testimonial-row/TestimonialRow.types.d.ts +3 -0
  216. package/dist/components/blocks/testimonial-row/TestimonialRow.types.js +1 -1
  217. package/dist/components/blocks/testimonial-row/testimonial-row-impl.css +8 -0
  218. package/dist/components/blocks/testimonial-slider/TestimonialSlider.css +1 -0
  219. package/dist/components/blocks/testimonial-slider/TestimonialSlider.d.ts +1 -1
  220. package/dist/components/blocks/testimonial-slider/TestimonialSlider.js +2 -2
  221. package/dist/components/blocks/testimonial-slider/TestimonialSlider.types.d.ts +8 -0
  222. package/dist/components/blocks/testimonial-slider/TestimonialSlider.types.js +1 -1
  223. package/dist/components/blocks/text-scroll/TextScroll.css +53 -0
  224. package/dist/components/blocks/text-scroll/TextScroll.d.ts +5 -0
  225. package/dist/components/blocks/text-scroll/TextScroll.js +71 -0
  226. package/dist/components/blocks/text-scroll/TextScroll.types.d.ts +22 -0
  227. package/dist/components/blocks/text-scroll/TextScroll.types.js +10 -0
  228. package/dist/components/blocks/text-scroll/text-scroll-impl.css +115 -0
  229. package/dist/components/blocks/tiers/Tiers.css +233 -0
  230. package/dist/components/blocks/tiers/Tiers.d.ts +32 -0
  231. package/dist/components/blocks/tiers/Tiers.js +68 -0
  232. package/dist/components/blocks/tiers/Tiers.types.d.ts +45 -0
  233. package/dist/components/blocks/tiers/Tiers.types.js +25 -0
  234. package/dist/components/blocks/tiers/tiers-impl.css +185 -0
  235. package/dist/components/blocks/use-rotation.d.ts +12 -2
  236. package/dist/components/blocks/use-rotation.js +6 -28
  237. package/dist/components/comparison-cards-data.d.ts +59 -0
  238. package/dist/components/comparison-cards-data.js +12 -0
  239. package/dist/components/comparison-table-data.d.ts +39 -0
  240. package/dist/components/comparison-table-data.js +11 -0
  241. package/dist/components/core/accordion-item/AccordionItem.css +1 -5
  242. package/dist/components/core/background/Background.css +92 -0
  243. package/dist/components/core/background/Background.d.ts +27 -0
  244. package/dist/components/core/background/Background.js +45 -0
  245. package/dist/components/core/background/Background.types.d.ts +39 -0
  246. package/dist/components/core/background/Background.types.js +11 -0
  247. package/dist/components/core/background/background-impl.css +760 -0
  248. package/dist/components/core/background/halftone.d.ts +134 -0
  249. package/dist/components/core/background/halftone.js +722 -0
  250. package/dist/components/core/background/patterns.d.ts +66 -0
  251. package/dist/components/core/background/patterns.js +244 -0
  252. package/dist/components/core/background/shader.d.ts +44 -0
  253. package/dist/components/core/background/shader.js +307 -0
  254. package/dist/components/core/background/use-halftone.d.ts +15 -0
  255. package/dist/components/core/background/use-halftone.js +27 -0
  256. package/dist/components/core/background/use-offscreen.d.ts +10 -0
  257. package/dist/components/core/background/use-offscreen.js +30 -0
  258. package/dist/components/core/background/use-shader.d.ts +11 -0
  259. package/dist/components/core/background/use-shader.js +25 -0
  260. package/dist/components/core/background/use-spotlight.d.ts +14 -0
  261. package/dist/components/core/background/use-spotlight.js +73 -0
  262. package/dist/components/core/bottom-sheet/BottomSheet.js +2 -2
  263. package/dist/components/core/bottom-sheet/BottomSheet.types.d.ts +3 -1
  264. package/dist/components/core/breadcrumb/Breadcrumb.d.ts +1 -0
  265. package/dist/components/core/breadcrumb/Breadcrumb.js +1 -0
  266. package/dist/components/core/breadcrumb/breadcrumb-impl.css +11 -0
  267. package/dist/components/core/button/button-impl.css +14 -1
  268. package/dist/components/core/illustration-card/IllustrationCard.css +40 -0
  269. package/dist/components/core/illustration-card/IllustrationCard.d.ts +22 -0
  270. package/dist/components/core/illustration-card/IllustrationCard.js +82 -0
  271. package/dist/components/core/illustration-card/IllustrationCard.types.d.ts +23 -0
  272. package/dist/components/core/illustration-card/IllustrationCard.types.js +8 -0
  273. package/dist/components/core/illustration-card/illustration-card-impl.css +47 -0
  274. package/dist/components/core/illustration-scene/IllustrationScene.css +41 -0
  275. package/dist/components/core/illustration-scene/IllustrationScene.d.ts +14 -0
  276. package/dist/components/core/illustration-scene/IllustrationScene.js +16 -0
  277. package/dist/components/core/illustration-scene/IllustrationScene.types.d.ts +32 -0
  278. package/dist/components/core/illustration-scene/IllustrationScene.types.js +8 -0
  279. package/dist/components/core/illustration-scene/illustration-scene-impl.css +46 -0
  280. package/dist/components/core/link/Link.js +7 -3
  281. package/dist/components/core/link/link-impl.css +29 -2
  282. package/dist/components/core/navbar/Navbar.css +2 -2
  283. package/dist/components/core/navbar/Navbar.types.d.ts +1 -1
  284. package/dist/components/core/navbar-item/NavbarItem.d.ts +2 -1
  285. package/dist/components/core/navbar-item/NavbarItem.js +3 -10
  286. package/dist/components/core/navbar-item/NavbarItem.types.d.ts +4 -1
  287. package/dist/components/core/navbar-item/NavbarItem.types.js +1 -1
  288. package/dist/components/core/navbar-item/navbar-item-impl.css +10 -0
  289. package/dist/components/core/navbar-menu/navbar-menu-impl.css +9 -0
  290. package/dist/components/core/navbar-switcher/navbar-switcher-impl.css +19 -0
  291. package/dist/components/core/pagination/Pagination.js +1 -1
  292. package/dist/components/core/pagination/pagination-impl.css +9 -0
  293. package/dist/components/core/pagination-dots/PaginationDots.d.ts +1 -1
  294. package/dist/components/core/pagination-dots/PaginationDots.js +3 -3
  295. package/dist/components/core/pagination-dots/PaginationDots.types.d.ts +3 -1
  296. package/dist/components/core/segmented-control/SegmentedControl.css +4 -3
  297. package/dist/components/core/segmented-control/SegmentedControl.js +17 -3
  298. package/dist/components/core/segmented-control-item/SegmentedControlItem.css +2 -1
  299. package/dist/components/core/select/Select.js +3 -3
  300. package/dist/components/core/select/Select.types.d.ts +11 -1
  301. package/dist/components/core/select/Select.types.js +1 -1
  302. package/dist/components/core/tab-list/TabList.js +9 -1
  303. package/dist/components/core/table-header-cell/TableHeaderCell.d.ts +1 -1
  304. package/dist/components/core/table-header-cell/TableHeaderCell.js +5 -2
  305. package/dist/components/core/table-header-cell/TableHeaderCell.types.d.ts +7 -1
  306. package/dist/components/core/table-header-cell/TableHeaderCell.types.js +1 -1
  307. package/dist/components/core/text-area/TextArea.d.ts +1 -1
  308. package/dist/components/core/text-area/TextArea.js +2 -2
  309. package/dist/components/core/text-area/TextArea.types.d.ts +9 -1
  310. package/dist/components/core/text-area/TextArea.types.js +1 -1
  311. package/dist/components/core/text-input/TextInput.d.ts +1 -1
  312. package/dist/components/core/text-input/TextInput.js +2 -2
  313. package/dist/components/core/text-input/TextInput.types.d.ts +9 -1
  314. package/dist/components/core/text-input/TextInput.types.js +1 -1
  315. package/dist/components/data-table-data.d.ts +33 -0
  316. package/dist/components/data-table-data.js +12 -0
  317. package/dist/components/download-banner-data.d.ts +52 -0
  318. package/dist/components/download-banner-data.js +11 -0
  319. package/dist/components/index.d.ts +51 -0
  320. package/dist/components/index.js +38 -0
  321. package/dist/components/resource-banner-data.d.ts +34 -0
  322. package/dist/components/resource-banner-data.js +13 -0
  323. package/dist/components/scene-scroll-data.d.ts +24 -0
  324. package/dist/components/scene-scroll-data.js +9 -0
  325. package/dist/components/stats-data.d.ts +28 -0
  326. package/dist/components/stats-data.js +11 -0
  327. package/dist/components/steps-data.d.ts +38 -0
  328. package/dist/components/steps-data.js +13 -0
  329. package/dist/components/sticky-cards-data.d.ts +43 -0
  330. package/dist/components/sticky-cards-data.js +12 -0
  331. package/dist/components/team-grid-data.d.ts +38 -0
  332. package/dist/components/team-grid-data.js +11 -0
  333. package/dist/components/tiers-data.d.ts +47 -0
  334. package/dist/components/tiers-data.js +13 -0
  335. package/dist/marketing.css +101 -28
  336. package/package.json +1 -1
@@ -0,0 +1,51 @@
1
+ import type { TeamGridMember } from '../../team-grid-data.js';
2
+ export interface TeamGridOwnProps {
3
+ /**
4
+ * `page` — The default, and the page's own white. Most people sections have nothing to separate themselves from
5
+ * `subtle` — A quiet step off the page — the reference design's slate band — for a section that wants to read as its own. Painted as the band's tint laid over the page's own ground, so it is the same grey whatever is behind the section; the photographs' placeholder is raised to color.bg.surface-card-raised so it does not vanish into the band
6
+ * `strong` — `color.bg.brand-strong`, the dark band, for a section a reader should arrive at. The heading, the names and the roles turn white, the profile links take the band's ink rather than the brand's, and the button takes Button's inverse tone
7
+ */
8
+ ground?: 'page' | 'subtle' | 'strong';
9
+ /** Always. Who these people are, in the fewest words — "Meet our leadership team". It names the section as a region, so a screen reader can jump to it and past it. */
10
+ title: string;
11
+ /** A line saying who the set is, when the title alone does not — "The people steering Deriv's products, markets and teams". */
12
+ description?: string;
13
+ /** Always. The people, in the order the page wants them read — by seniority or by relevance, the first `collapsedCount` of them showing at once. Each has a name, a role, a picture with its `alt`, and where there is one a `profile` link. The same framing in every photograph: the grid crops each to a square, and a set of faces at different distances reads as a set of different sources. An empty list draws the heading alone. */
14
+ people: TeamGridMember[];
15
+ /** How many people show before the rest are asked for. Four, the default, is one row at full width, so the button sits under a complete row. A list no longer than this has no button at all — there is nothing more to show. */
16
+ collapsedCount?: number;
17
+ /** The button's words while the rest of the list is hidden. Translate it with the page, and keep it parallel to collapseLabel. */
18
+ expandLabel?: string;
19
+ /** The button's words once the whole list is showing, for the reason expandLabel exists. */
20
+ collapseLabel?: string;
21
+ /** The accessible name of a person's profile link, given the person. The visible word is the profile's own — "LinkedIn" — and it is the same on every card, so the link is named for its person too. Without this the name is the profile's label and then the person's, "LinkedIn, Alex Morgan": the visible word first, so a reader using speech can say what they see. Pass it to translate that with the page. */
22
+ profileName?: (person: TeamGridMember) => string;
23
+ /** Said after every profile link's name, because a profile opens in a new tab and a reader should know before they press it — ResourceBanner's words for the same thing. Translate it with the page. */
24
+ externalLabel?: string;
25
+ }
26
+ export type TeamGridProps = TeamGridOwnProps;
27
+ /** The class each part carries. Apply these — do not retype them. */
28
+ export declare const teamGridParts: {
29
+ readonly root: "dds-teamgrid";
30
+ readonly inner: "dds-teamgrid__inner";
31
+ readonly header: "dds-teamgrid__header";
32
+ readonly title: "dds-teamgrid__title";
33
+ readonly description: "dds-teamgrid__description";
34
+ readonly people: "dds-teamgrid__people";
35
+ readonly list: "dds-teamgrid__list";
36
+ readonly item: "dds-teamgrid__item";
37
+ readonly media: "dds-teamgrid__media";
38
+ readonly text: "dds-teamgrid__text";
39
+ readonly name: "dds-teamgrid__name";
40
+ readonly role: "dds-teamgrid__role";
41
+ readonly profile: "dds-teamgrid__profile";
42
+ readonly actions: "dds-teamgrid__actions";
43
+ };
44
+ /** Generated so defaults cannot drift from the contract. */
45
+ export declare const teamGridDefaults: {
46
+ readonly ground: "page";
47
+ readonly collapsedCount: 4;
48
+ readonly expandLabel: "View all";
49
+ readonly collapseLabel: "View less";
50
+ readonly externalLabel: "(opens in a new tab)";
51
+ };
@@ -0,0 +1,20 @@
1
+ // GENERATED from team-grid.contract.json. Do not edit.
2
+ /** The class each part carries. Apply these — do not retype them. */
3
+ export const teamGridParts = {
4
+ root: 'dds-teamgrid',
5
+ inner: 'dds-teamgrid__inner',
6
+ header: 'dds-teamgrid__header',
7
+ title: 'dds-teamgrid__title',
8
+ description: 'dds-teamgrid__description',
9
+ people: 'dds-teamgrid__people',
10
+ list: 'dds-teamgrid__list',
11
+ item: 'dds-teamgrid__item',
12
+ media: 'dds-teamgrid__media',
13
+ text: 'dds-teamgrid__text',
14
+ name: 'dds-teamgrid__name',
15
+ role: 'dds-teamgrid__role',
16
+ profile: 'dds-teamgrid__profile',
17
+ actions: 'dds-teamgrid__actions',
18
+ };
19
+ /** Generated so defaults cannot drift from the contract. */
20
+ export const teamGridDefaults = { ground: 'page', collapsedCount: 4, expandLabel: 'View all', collapseLabel: 'View less', externalLabel: '(opens in a new tab)' };
@@ -0,0 +1,129 @@
1
+ /*
2
+ * Scoped to this package, like the generated sheet beside it.
3
+ */
4
+
5
+ /*
6
+ * The header starts on a phone and is centred once the band is wide enough to hold a line.
7
+ *
8
+ * FeatureCards' rule and its reason: centred text starts every line at a different edge, which
9
+ * costs little across a wide measure and a great deal across a narrow one. The header and the line
10
+ * under it are capped narrower than the column, so `margin-inline: auto` is what centres those
11
+ * boxes rather than their words inside a box left at the start edge.
12
+ *
13
+ * `48rem` longhand because `var()` is not permitted in a container query condition, and it is the
14
+ * width the rest of this package folds at.
15
+ */
16
+ @container (min-width: 48rem) {
17
+ :where([data-dds-context="marketing"]) .dds-teamgrid .dds-teamgrid__header {
18
+ align-items: center;
19
+ margin-inline: auto;
20
+ text-align: center;
21
+ }
22
+
23
+ :where([data-dds-context="marketing"]) .dds-teamgrid .dds-teamgrid__description {
24
+ margin-inline: auto;
25
+ }
26
+ }
27
+
28
+ /*
29
+ * One column on a phone, two from the fold, four at full width — the reference design's grid, so
30
+ * the four people showing at first are one row on a desktop. `minmax(0, 1fr)` rather than `1fr`, so
31
+ * a long unbroken name shrinks to its column instead of pushing the grid past the page.
32
+ *
33
+ * Four from 64rem rather than FeatureCards' 62rem: four photographs and four names a row want the
34
+ * extra width, and below it two a row keeps each face large enough to be one.
35
+ */
36
+ :where([data-dds-context="marketing"]) .dds-teamgrid .dds-teamgrid__list {
37
+ grid-template-columns: minmax(0, 1fr);
38
+ }
39
+
40
+ @container (min-width: 48rem) {
41
+ :where([data-dds-context="marketing"]) .dds-teamgrid .dds-teamgrid__list {
42
+ grid-template-columns: repeat(2, minmax(0, 1fr));
43
+ }
44
+ }
45
+
46
+ @container (min-width: 64rem) {
47
+ :where([data-dds-context="marketing"]) .dds-teamgrid .dds-teamgrid__list {
48
+ grid-template-columns: repeat(4, minmax(0, 1fr));
49
+ }
50
+ }
51
+
52
+ /*
53
+ * A person waiting behind the button is not there at all.
54
+ *
55
+ * The item is a flex column by its contract, and an author's `display` beats the browser's own
56
+ * `[hidden] { display: none }` — so without this the attribute would take a person out of the
57
+ * accessibility tree while leaving them drawn on the page.
58
+ */
59
+ :where([data-dds-context="marketing"]) .dds-teamgrid .dds-teamgrid__item[hidden] {
60
+ display: none;
61
+ }
62
+
63
+ /*
64
+ * And arrives when the button shows them: faded up from opacity.hidden and risen
65
+ * motion.translate.reveal, the arrival every block makes, a stagger step behind the person before.
66
+ *
67
+ * A keyframe rather than a transition because the person was `display: none` a moment earlier and
68
+ * a transition has no painted starting state to move from — the same reason a block's entrance is
69
+ * keyframed. `both`, so a person waiting out their delay waits at the start rather than showing
70
+ * and then jumping back to it. The reference also grew the grid's height open; that needs the
71
+ * extras in a second list, and one list a screen reader counts is worth more than the slide.
72
+ */
73
+ @keyframes dds-teamgrid-arrive {
74
+ from {
75
+ opacity: var(--opacity-hidden);
76
+ translate: var(--motion-translate-reveal);
77
+ }
78
+ }
79
+
80
+ :where([data-dds-context="marketing"]) .dds-teamgrid .dds-teamgrid__item[data-extra]:not([hidden]) {
81
+ animation: dds-teamgrid-arrive var(--motion-duration-reveal) var(--motion-easing-reveal) both;
82
+ animation-delay: calc(var(--dds-teamgrid-extra-at, 0) * var(--motion-duration-stagger));
83
+ }
84
+
85
+ /*
86
+ * A reader who asked for less movement gets the people without the arrival: they are simply there
87
+ * the moment the button is pressed.
88
+ */
89
+ @media (prefers-reduced-motion: reduce) {
90
+ :where([data-dds-context="marketing"]) .dds-teamgrid .dds-teamgrid__item[data-extra]:not([hidden]) {
91
+ animation: none;
92
+ }
93
+ }
94
+
95
+ /*
96
+ * The photograph's frame takes the whole of the card's width; AspectRatio inside it holds the
97
+ * square and the frame's clip rounds the corners of whatever the picture is.
98
+ */
99
+ :where([data-dds-context="marketing"]) .dds-teamgrid .dds-teamgrid__media {
100
+ inline-size: 100%;
101
+ }
102
+
103
+ /*
104
+ * A profile link is a pointer target, so it is at least size.target.min tall. A standalone Link is
105
+ * as tall as its line, which is under that at the label step — the profile part holds the height
106
+ * and the link fills it, so the whole of the row is the target rather than the words alone.
107
+ */
108
+ :where([data-dds-context="marketing"]) .dds-teamgrid .dds-teamgrid__profile > .dds-link {
109
+ min-block-size: var(--size-target-min);
110
+ }
111
+
112
+ /*
113
+ * The button fills the column on a phone, the rule for a section's actions — the part is a column,
114
+ * which stretches it. From the fold it is its own width, centred under the grid it lengthens.
115
+ */
116
+ @container (min-width: 48rem) {
117
+ :where([data-dds-context="marketing"]) .dds-teamgrid .dds-teamgrid__actions {
118
+ align-items: center;
119
+ }
120
+ }
121
+
122
+ /*
123
+ * A heading with no line under it closes up: its bound step is the distance to the line, and with
124
+ * nothing there it would only add to the step from the header to the people. `:last-child` is the
125
+ * condition itself, DataTable's way, rather than a prop standing in for it.
126
+ */
127
+ :where([data-dds-context="marketing"]) .dds-teamgrid .dds-teamgrid__title:last-child {
128
+ margin-block-end: 0;
129
+ }
@@ -7,6 +7,7 @@
7
7
  inline-size: 100%;
8
8
  justify-content: center;
9
9
  overflow: clip;
10
+ overflow-wrap: anywhere;
10
11
  }
11
12
 
12
13
  :where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__inner {
@@ -17,4 +17,4 @@ export type { TestimonialRowProps };
17
17
  * `'use client'` for the row's scroll position, the arrival, and `useId`, which names the region
18
18
  * by its heading.
19
19
  */
20
- export declare function TestimonialRow({ ground, title, reviews, summary, ratingLabel, label, previousLabel, nextLabel, }: TestimonialRowProps): import("react").JSX.Element | null;
20
+ export declare function TestimonialRow({ ground, title, reviews, summary, ratingLabel, label, externalLabel, previousLabel, nextLabel, }: TestimonialRowProps): import("react").JSX.Element | null;
@@ -8,6 +8,7 @@ import "../block-reveal.css";
8
8
  import { given } from "../../given.js";
9
9
  import { ButtonIcon } from "../../core/button-icon/ButtonIcon.js";
10
10
  import { Link } from "../../core/link/Link.js";
11
+ import { visuallyHidden } from "../../visually-hidden.js";
11
12
  import { arriving, useReveal } from "../use-reveal.js";
12
13
  import { testimonialRowDefaults, testimonialRowParts, } from "./TestimonialRow.types.js";
13
14
  /**
@@ -45,7 +46,7 @@ const AT_END = 2;
45
46
  * `'use client'` for the row's scroll position, the arrival, and `useId`, which names the region
46
47
  * by its heading.
47
48
  */
48
- export function TestimonialRow({ ground = testimonialRowDefaults.ground, title, reviews, summary, ratingLabel, label = testimonialRowDefaults.label, previousLabel = testimonialRowDefaults.previousLabel, nextLabel = testimonialRowDefaults.nextLabel, }) {
49
+ export function TestimonialRow({ ground = testimonialRowDefaults.ground, title, reviews, summary, ratingLabel, label = testimonialRowDefaults.label, externalLabel = testimonialRowDefaults.externalLabel, previousLabel = testimonialRowDefaults.previousLabel, nextLabel = testimonialRowDefaults.nextLabel, }) {
49
50
  const titleId = useId();
50
51
  const [band, revealed] = useReveal();
51
52
  const row = useRef(null);
@@ -116,13 +117,13 @@ export function TestimonialRow({ ground = testimonialRowDefaults.ground, title,
116
117
  return (_jsx("section", { className: testimonialRowParts.root, "data-ground": ground, "aria-labelledby": titleId, children: _jsxs("div", { className: testimonialRowParts.inner, ref: band, "data-revealed": revealed, children: [_jsxs("div", { className: testimonialRowParts.header, children: [_jsx("h2", { className: testimonialRowParts.title, id: titleId, ...arriving(0), children: title }), summary === undefined ? null : (_jsx("p", { className: testimonialRowParts.summary, ...arriving(1), children: summary.href !== undefined && given(summary.href) ? (
117
118
  // A link on its own line, so the standalone one: brand ink and a mark. On the dark
118
119
  // band it takes the band's ink, where coral is the wrong colour for words.
119
- _jsx(Link, { variant: "standalone", tone: ground === "strong" ? "inherit" : "brand", external: true, href: summary.href, children: summary.label })) : (_jsx("span", { children: summary.label })) }))] }), _jsxs("div", { className: testimonialRowParts.carousel, children: [_jsx("div", { ref: row, className: testimonialRowParts.track, role: "group", "aria-label": label, tabIndex: 0, onScroll: read, ...arriving(2), children: reviews.map((each, at) => {
120
+ _jsxs(Link, { variant: "standalone", tone: ground === "strong" ? "inherit" : "brand", external: true, href: summary.href, children: [summary.label, _jsx("span", { style: visuallyHidden, children: ` ${externalLabel}` })] })) : (_jsx("span", { children: summary.label })) }))] }), _jsxs("div", { className: testimonialRowParts.carousel, children: [_jsx("div", { ref: row, className: testimonialRowParts.track, role: "group", "aria-label": label, tabIndex: 0, onScroll: read, ...arriving(2), children: reviews.map((each, at) => {
120
121
  // A review's position is its identity: the set is a list, and nothing reorders it.
121
122
  const card = (_jsxs("figure", { className: testimonialRowParts.item, children: [each.rating === undefined ? null : (
122
123
  // Named by the score it is drawn at, so a 4.3 is heard as the 4.5 a reader
123
124
  // sees rather than as a number the stars do not show.
124
125
  _jsx(Rating, { score: each.rating, label: ratingLabel?.(toHalves(each.rating)) ?? `Rated ${toHalves(each.rating)} out of 5` })), _jsx("blockquote", { className: testimonialRowParts.quote, children: each.quote }), _jsx("figcaption", { className: testimonialRowParts.author, children: _jsxs("span", { children: [_jsx("span", { className: testimonialRowParts.name, children: each.name }), given(each.detail) ? (_jsx("span", { className: testimonialRowParts.detail, children: each.detail })) : null] }) })] }, at));
125
126
  // The review is on a service the page does not own, so it opens beside the page.
126
- return given(each.href) ? (_jsx("a", { className: testimonialRowParts["review-link"], href: each.href, target: "_blank", rel: "noopener noreferrer", children: card }, at)) : (card);
127
+ return given(each.href) ? (_jsxs("a", { className: testimonialRowParts["review-link"], href: each.href, target: "_blank", rel: "noopener noreferrer", children: [card, _jsx("span", { style: visuallyHidden, children: ` ${externalLabel}` })] }, at)) : (card);
127
128
  }) }), reviews.length > 1 ? (_jsx("div", { className: testimonialRowParts.footer, ...arriving(3), children: _jsxs("div", { className: testimonialRowParts.nav, hidden: !scrolls, children: [_jsx("span", { ref: back, className: testimonialRowParts["nav-slot"], "data-available": ends.back, inert: !ends.back, children: _jsx(ButtonIcon, { icon: _jsx(ChevronLeftRegularIcon, {}), label: previousLabel, ...arrow, onClick: () => step(-1) }) }), _jsx("span", { ref: on, className: testimonialRowParts["nav-slot"], "data-available": ends.on, inert: !ends.on, children: _jsx(ButtonIcon, { icon: _jsx(ChevronRightRegularIcon, {}), label: nextLabel, ...arrow, onClick: () => step(1) }) })] }) })) : null] })] }) }));
128
129
  }
@@ -20,6 +20,8 @@ export interface TestimonialRowOwnProps {
20
20
  previousLabel?: string;
21
21
  /** The accessible name of the arrow stepping the row on, for the reason previousLabel exists. */
22
22
  nextLabel?: string;
23
+ /** Said after the summary link and every linked review, because both open on a service the page does not own, in a new tab, and a reader should know before they press — TeamGrid's and ResourceBanner's words for the same thing. Translate it with the page. */
24
+ externalLabel?: string;
23
25
  }
24
26
  export type TestimonialRowProps = TestimonialRowOwnProps;
25
27
  /** The class each part carries. Apply these — do not retype them. */
@@ -51,4 +53,5 @@ export declare const testimonialRowDefaults: {
51
53
  readonly label: "Reviews";
52
54
  readonly previousLabel: "Previous reviews";
53
55
  readonly nextLabel: "Next reviews";
56
+ readonly externalLabel: "(opens in a new tab)";
54
57
  };
@@ -23,4 +23,4 @@ export const testimonialRowParts = {
23
23
  'nav-slot': 'dds-testimonialrow__nav-slot',
24
24
  };
25
25
  /** Generated so defaults cannot drift from the contract. */
26
- export const testimonialRowDefaults = { ground: 'page', label: 'Reviews', previousLabel: 'Previous reviews', nextLabel: 'Next reviews' };
26
+ export const testimonialRowDefaults = { ground: 'page', label: 'Reviews', previousLabel: 'Previous reviews', nextLabel: 'Next reviews', externalLabel: '(opens in a new tab)' };
@@ -193,3 +193,11 @@
193
193
  :where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__nav-slot[data-available='false'] {
194
194
  opacity: var(--opacity-disabled);
195
195
  }
196
+
197
+ /*
198
+ * Previous and next point along the row. A right-to-left row puts previous on the right, so the
199
+ * chevrons are mirrored to point the way each one moves; as they ship, both pointed backwards.
200
+ */
201
+ :where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__nav-slot svg:dir(rtl) {
202
+ scale: -1 1;
203
+ }
@@ -7,6 +7,7 @@
7
7
  inline-size: 100%;
8
8
  justify-content: center;
9
9
  overflow: clip;
10
+ overflow-wrap: anywhere;
10
11
  }
11
12
 
12
13
  :where([data-dds-context="marketing"]) .dds-testimonialslider .dds-testimonialslider__inner {
@@ -19,4 +19,4 @@ export type { TestimonialSliderProps };
19
19
  * comes into view. `'use client'` for that, for the rotation, and for `useId`, which names the
20
20
  * region by its heading.
21
21
  */
22
- export declare function TestimonialSlider({ ground, title, quotes, imageStart, imageEnd, autoplay, controlsLabel, slideLabel, }: TestimonialSliderProps): import("react").JSX.Element | null;
22
+ export declare function TestimonialSlider({ ground, title, quotes, imageStart, imageEnd, autoplay, controlsLabel, slideLabel, roleDescription, slideRoleDescription, positionLabel, }: TestimonialSliderProps): import("react").JSX.Element | null;
@@ -25,10 +25,10 @@ import { testimonialSliderDefaults, testimonialSliderParts, } from "./Testimonia
25
25
  * comes into view. `'use client'` for that, for the rotation, and for `useId`, which names the
26
26
  * region by its heading.
27
27
  */
28
- export function TestimonialSlider({ ground = testimonialSliderDefaults.ground, title, quotes, imageStart, imageEnd, autoplay = testimonialSliderDefaults.autoplay, controlsLabel = testimonialSliderDefaults.controlsLabel, slideLabel = testimonialSliderDefaults.slideLabel, }) {
28
+ export function TestimonialSlider({ ground = testimonialSliderDefaults.ground, title, quotes, imageStart, imageEnd, autoplay = testimonialSliderDefaults.autoplay, controlsLabel = testimonialSliderDefaults.controlsLabel, slideLabel = testimonialSliderDefaults.slideLabel, roleDescription = testimonialSliderDefaults.roleDescription, slideRoleDescription = testimonialSliderDefaults.slideRoleDescription, positionLabel, }) {
29
29
  const titleId = useId();
30
30
  const [band, revealed] = useReveal();
31
- const { rotating, root, region, track, item, away, dots } = useRotation(quotes.length, autoplay);
31
+ const { rotating, root, region, track, item, away, dots } = useRotation(quotes.length, autoplay, { roleDescription, slideRoleDescription, positionLabel });
32
32
  // Nothing to show is nothing drawn: a named region with no quote in it leads nowhere.
33
33
  if (quotes.length === 0)
34
34
  return null;
@@ -20,6 +20,12 @@ export interface TestimonialSliderOwnProps {
20
20
  controlsLabel?: string;
21
21
  /** The word each dot is announced by, before its number — 'Slide 2'. Translate it with the page, as controlsLabel is; a page that translates only the group's name still has every dot announced in English. */
22
22
  slideLabel?: string;
23
+ /** What a screen reader calls the set while it rotates — announced in place of a region, as the word for this kind of thing. Translate it with the page: it is read out as given, so an untranslated one announces an English word on every page in every language. */
24
+ roleDescription?: string;
25
+ /** What a screen reader calls each item while the set rotates, for the reason roleDescription exists. Translate it with the page. */
26
+ slideRoleDescription?: string;
27
+ /** The accessible name of each item while the set rotates, given its place in the set counting from one — so a reader hears where they are. Without it each is named "2 of 5"; pass it to translate that with the page, in that language's own order and digits. */
28
+ positionLabel?: (position: number, count: number) => string;
23
29
  }
24
30
  export type TestimonialSliderProps = TestimonialSliderOwnProps;
25
31
  /** The class each part carries. Apply these — do not retype them. */
@@ -46,4 +52,6 @@ export declare const testimonialSliderDefaults: {
46
52
  readonly autoplay: false;
47
53
  readonly controlsLabel: "Testimonials";
48
54
  readonly slideLabel: "Slide";
55
+ readonly roleDescription: "carousel";
56
+ readonly slideRoleDescription: "slide";
49
57
  };
@@ -18,4 +18,4 @@ export const testimonialSliderParts = {
18
18
  controls: 'dds-testimonialslider__controls',
19
19
  };
20
20
  /** Generated so defaults cannot drift from the contract. */
21
- export const testimonialSliderDefaults = { ground: 'page', autoplay: false, controlsLabel: 'Testimonials', slideLabel: 'Slide' };
21
+ export const testimonialSliderDefaults = { ground: 'page', autoplay: false, controlsLabel: 'Testimonials', slideLabel: 'Slide', roleDescription: 'carousel', slideRoleDescription: 'slide' };
@@ -0,0 +1,53 @@
1
+ /* GENERATED from textscroll.contract.json. Do not edit. */
2
+
3
+ :where([data-dds-context="marketing"]) .dds-textscroll {
4
+ box-sizing: border-box;
5
+ container-type: inline-size;
6
+ display: flex;
7
+ inline-size: 100%;
8
+ justify-content: center;
9
+ overflow-wrap: anywhere;
10
+ }
11
+
12
+ :where([data-dds-context="marketing"]) .dds-textscroll .dds-textscroll__inner {
13
+ box-sizing: border-box;
14
+ display: flex;
15
+ flex-direction: column;
16
+ inline-size: 100%;
17
+ min-inline-size: 0;
18
+ max-inline-size: var(--size-content-max);
19
+ padding-block: var(--space-section-default);
20
+ padding-inline: var(--space-inset-page);
21
+ }
22
+
23
+ :where([data-dds-context="marketing"]) .dds-textscroll .dds-textscroll__text {
24
+ margin-block: 0;
25
+ text-wrap: pretty;
26
+ font-family: var(--font-h4-family);
27
+ font-size: var(--font-h4-size);
28
+ font-weight: var(--font-h4-weight);
29
+ letter-spacing: var(--font-h4-letter-spacing);
30
+ line-height: var(--font-h4-line-height);
31
+ max-inline-size: var(--size-measure-hero-heading);
32
+ }
33
+
34
+ :where([data-dds-context="marketing"]) .dds-textscroll .dds-textscroll__word {
35
+ display: inline;
36
+ }
37
+
38
+ :where([data-dds-context="marketing"]) .dds-textscroll[data-ground="page"] {
39
+ background-color: var(--color-bg-page);
40
+ color: var(--color-fg-default);
41
+ }
42
+
43
+ :where([data-dds-context="marketing"]) .dds-textscroll[data-ground="strong"] {
44
+ background-color: var(--color-bg-brand-strong);
45
+ color: var(--color-fg-on-brand-strong);
46
+ }
47
+
48
+ :where([data-dds-context="marketing"]) .dds-textscroll[data-ground="subtle"] {
49
+ background-color: var(--color-bg-page);
50
+ background-image: linear-gradient(var(--color-bg-band-subtle), var(--color-bg-band-subtle));
51
+ color: var(--color-fg-default);
52
+ }
53
+
@@ -0,0 +1,5 @@
1
+ import './TextScroll.css';
2
+ import './text-scroll-impl.css';
3
+ import { type TextScrollProps } from './TextScroll.types.js';
4
+ export type { TextScrollProps };
5
+ export declare function TextScroll({ ground, text }: TextScrollProps): import("react").JSX.Element | null;
@@ -0,0 +1,71 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Fragment } from 'react';
3
+ import './TextScroll.css';
4
+ import './text-scroll-impl.css';
5
+ import { textScrollDefaults, textScrollParts } from './TextScroll.types.js';
6
+ const SPACE = /^\s+$/u;
7
+ /**
8
+ * The sentence in words and the spaces between them, every character kept.
9
+ *
10
+ * By the language's own word boundaries rather than by spaces. Chinese, Japanese and Thai write
11
+ * none between words, so a split on whitespace handed the whole paragraph back as one word and it
12
+ * brightened all at once. `Intl.Segmenter` knows where their words end, in the browser and on the
13
+ * server alike.
14
+ *
15
+ * The spaces are kept as written rather than rebuilt as one ordinary space: French sets a narrow
16
+ * no-break space before `?` and `%`, and turning it into a breaking one let the line wrap before
17
+ * the punctuation it exists to hold on to. Punctuation rides with the word beside it, so a full
18
+ * stop brightens with its word instead of standing lit on its own.
19
+ */
20
+ function piecesOf(text) {
21
+ const runs = typeof Intl !== 'undefined' && 'Segmenter' in Intl
22
+ ? Array.from(new Intl.Segmenter(undefined, { granularity: 'word' }).segment(text), (each) => ({
23
+ text: each.segment,
24
+ wordLike: each.isWordLike === true,
25
+ }))
26
+ : text.split(/(\s+)/u).map((run) => ({ text: run, wordLike: !SPACE.test(run) }));
27
+ const pieces = [];
28
+ // The word being built, and whether it holds a word yet or only punctuation leading into one.
29
+ let open = null;
30
+ const close = () => {
31
+ if (open !== null)
32
+ pieces.push({ word: true, text: open.text });
33
+ open = null;
34
+ };
35
+ for (const run of runs) {
36
+ if (run.text === '')
37
+ continue;
38
+ if (SPACE.test(run.text)) {
39
+ close();
40
+ pieces.push({ word: false, text: run.text });
41
+ }
42
+ else if (run.wordLike && open?.holdsWord) {
43
+ // Two words with nothing between them — the ordinary case in a script that writes no spaces.
44
+ close();
45
+ open = { text: run.text, holdsWord: true };
46
+ }
47
+ else if (open === null) {
48
+ open = { text: run.text, holdsWord: run.wordLike };
49
+ }
50
+ else {
51
+ open = { text: open.text + run.text, holdsWord: open.holdsWord || run.wordLike };
52
+ }
53
+ }
54
+ close();
55
+ return pieces;
56
+ }
57
+ export function TextScroll({ ground = textScrollDefaults.ground, text }) {
58
+ const pieces = piecesOf(text.trim());
59
+ const count = pieces.filter((piece) => piece.word).length;
60
+ // Nothing to say is nothing drawn: an empty band between two sections is a gap, not a pause.
61
+ if (count === 0)
62
+ return null;
63
+ let at = -1;
64
+ return (_jsx("section", { className: textScrollParts.root, "data-ground": ground, children: _jsx("div", { className: textScrollParts.inner, children: _jsx("p", { className: textScrollParts.text, style: { '--dds-textscroll-words': count }, children: pieces.map((piece, index) => {
65
+ // A piece's place is its identity: the sentence is the page's, and nothing reorders it.
66
+ if (!piece.word)
67
+ return _jsx(Fragment, { children: piece.text }, index);
68
+ at += 1;
69
+ return (_jsx("span", { className: textScrollParts.word, style: { '--dds-textscroll-at': at }, children: piece.text }, index));
70
+ }) }) }) }));
71
+ }
@@ -0,0 +1,22 @@
1
+ export interface TextScrollOwnProps {
2
+ /**
3
+ * `page` — The default, and the page's own white. A statement between two sections that need nothing to separate them
4
+ * `subtle` — The grey band, for a statement that should read as a section of its own without changing the page's voice. Painted as the band's tint laid over the page's own ground, so it is the same grey whatever is behind the section
5
+ * `strong` — `color.bg.brand-strong`, the dark band, for the statement a page is built around — the mission on an About page. The words turn white and dim toward the band
6
+ */
7
+ ground?: 'page' | 'subtle' | 'strong';
8
+ /** Always. The statement, as plain text — one sentence or two short ones, under about three hundred characters. Split into words on its whitespace, so a run of spaces or a line break is one space in what is drawn. Written so it reads well a word at a time, because that is how the reveal delivers it: "We believe trading should be accessible to everyone, everywhere, with the tools and the trust to do it well." */
9
+ text: string;
10
+ }
11
+ export type TextScrollProps = TextScrollOwnProps;
12
+ /** The class each part carries. Apply these — do not retype them. */
13
+ export declare const textScrollParts: {
14
+ readonly root: "dds-textscroll";
15
+ readonly inner: "dds-textscroll__inner";
16
+ readonly text: "dds-textscroll__text";
17
+ readonly word: "dds-textscroll__word";
18
+ };
19
+ /** Generated so defaults cannot drift from the contract. */
20
+ export declare const textScrollDefaults: {
21
+ readonly ground: "page";
22
+ };
@@ -0,0 +1,10 @@
1
+ // GENERATED from text-scroll.contract.json. Do not edit.
2
+ /** The class each part carries. Apply these — do not retype them. */
3
+ export const textScrollParts = {
4
+ root: 'dds-textscroll',
5
+ inner: 'dds-textscroll__inner',
6
+ text: 'dds-textscroll__text',
7
+ word: 'dds-textscroll__word',
8
+ };
9
+ /** Generated so defaults cannot drift from the contract. */
10
+ export const textScrollDefaults = { ground: 'page' };
@@ -0,0 +1,115 @@
1
+ /*
2
+ * Scoped to this package, like the generated sheet beside it.
3
+ *
4
+ * `:where([data-dds-context="marketing"])` confines these rules without contributing specificity,
5
+ * so each is decided against the generated rule on its own terms.
6
+ */
7
+
8
+ /*
9
+ * Centred from the fold, and at the start on a phone — the section-title rule and its reason: on a
10
+ * phone the measure is the screen, and a centred statement wraps to ragged lines whose left edge
11
+ * the eye loses. The reference design turns at 768px, which is this package's `48rem`.
12
+ *
13
+ * The paragraph is held to a measure, so centring its words is half of it: the capped box has to
14
+ * come to the middle as well, or the lines are centred inside a column sitting at the start.
15
+ *
16
+ * `48rem` longhand because `var()` is not permitted in a container query condition.
17
+ */
18
+ @container (min-width: 48rem) {
19
+ :where([data-dds-context="marketing"]) .dds-textscroll .dds-textscroll__text {
20
+ margin-inline: auto;
21
+ text-align: center;
22
+ }
23
+ }
24
+
25
+ /*
26
+ * The words brighten with the scroll, one after another.
27
+ *
28
+ * The section names a view timeline, and every word runs down it from opacity.track — the dimmed
29
+ * share of the same ink, which is the job that role already does for a track behind what travels
30
+ * over it — up to the full strength it has at rest. Scroll-driven, so the reveal moves forward as
31
+ * the reader scrolls down and back as they scroll up, and stands still while the page does. Linear,
32
+ * because the scroll is the easing; a curve here would be a second one on top of the reader's own.
33
+ * Only `from` is written: the end of the animation is the word's own resting opacity, so nothing
34
+ * here restates full strength as a number.
35
+ *
36
+ * The window runs from the section's top edge a quarter of the way up the viewport to its bottom
37
+ * edge reaching the viewport's foot. On the `cover` range that is `25vh` in from the start to
38
+ * `100% - 100vh` — the section's own height. The reference design ran it until the bottom edge
39
+ * crossed the middle of the viewport instead, and that is a point a page cannot always reach: as
40
+ * the last section, or above less than half a screen of page, the last words stayed dim for good,
41
+ * at about 1.6:1. The bottom edge reaching the foot of the viewport is the one end every section
42
+ * can be scrolled to. The start is held to the end where a section is shorter than a quarter of the
43
+ * viewport, so the window never runs backwards.
44
+ *
45
+ * Each word takes its own stretch of that window, the reference's stagger said as arithmetic. There
46
+ * a word brightened over five steps and the next one started a step later, so a word is still
47
+ * coming up while the four after it begin and the front of the reveal is a soft edge rather than a
48
+ * hard one. With `n` words that is `n + 4` steps in all: a word at place `i` starts at step `i` and
49
+ * lands at step `i + 5`. The place and the count are set on the word and the paragraph by the
50
+ * component, the only two numbers that change from one statement to the next.
51
+ *
52
+ * The timeline measures against the nearest scroll container, which is why nothing between the
53
+ * section and the page may clip with `overflow: hidden`: `hidden` makes a box a scroll container
54
+ * even when it never scrolls, and the words would then sit wherever they started however far the
55
+ * page moved. Clip with `overflow: clip` instead.
56
+ *
57
+ * A browser with no scroll timeline never applies the dim at all, so every word is at full strength
58
+ * from the start, which is the whole of the fallback — and the same is true before any script,
59
+ * because nothing here waits for one.
60
+ */
61
+ @keyframes dds-textscroll-brighten {
62
+ from {
63
+ opacity: var(--opacity-track);
64
+ }
65
+ }
66
+
67
+ @supports (animation-timeline: view()) {
68
+ :where([data-dds-context="marketing"]) .dds-textscroll {
69
+ view-timeline: --dds-textscroll-pass block;
70
+ }
71
+
72
+ :where([data-dds-context="marketing"]) .dds-textscroll .dds-textscroll__word {
73
+ /* How many steps a word takes to come up; the next word starts one step after it. */
74
+ --dds-textscroll-span: 5;
75
+ --dds-textscroll-steps: calc(var(--dds-textscroll-words) + var(--dds-textscroll-span) - 1);
76
+ --dds-textscroll-to: calc(100% - 100vh);
77
+ --dds-textscroll-from: min(25vh, var(--dds-textscroll-to));
78
+ --dds-textscroll-step: calc((var(--dds-textscroll-to) - var(--dds-textscroll-from)) / var(--dds-textscroll-steps));
79
+ animation: dds-textscroll-brighten linear both;
80
+ animation-range:
81
+ cover calc(var(--dds-textscroll-from) + var(--dds-textscroll-step) * var(--dds-textscroll-at))
82
+ cover calc(var(--dds-textscroll-from) + var(--dds-textscroll-step) * (var(--dds-textscroll-at) + var(--dds-textscroll-span)));
83
+ animation-timeline: --dds-textscroll-pass;
84
+ }
85
+ }
86
+
87
+ /*
88
+ * A reader who asked for less movement gets none of it: the whole statement at full strength and
89
+ * still, exactly as it is in a browser that cannot scroll-drive it.
90
+ */
91
+ @media (prefers-reduced-motion: reduce) {
92
+ :where([data-dds-context="marketing"]) .dds-textscroll .dds-textscroll__word {
93
+ animation: none;
94
+ }
95
+ }
96
+
97
+ /*
98
+ * On a phone the statement takes the h3 step rather than h4.
99
+ *
100
+ * h4 there is 24px, the size of a card's title, and this is the one thing the band says, the width of
101
+ * the screen to itself — set at h4 it read as a caption waiting for something bigger. h3 is 32px on a
102
+ * phone. From the fold it is h4 again, 36px, the reference's size, where the wider measure already
103
+ * gives the line its presence. The whole h3 step, its heavier weight too, so the phone's line is
104
+ * one of the scale's steps rather than h4's weight at h3's size.
105
+ *
106
+ * `47.9375rem` is the last width below the fold, LogoRows' bound.
107
+ */
108
+ @container (max-width: 47.9375rem) {
109
+ :where([data-dds-context="marketing"]) .dds-textscroll .dds-textscroll__text {
110
+ font-size: var(--font-h3-size);
111
+ font-weight: var(--font-h3-weight);
112
+ letter-spacing: var(--font-h3-letter-spacing);
113
+ line-height: var(--font-h3-line-height);
114
+ }
115
+ }