@deriv-com/dds-marketing 0.2.0 → 1.0.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 (279) hide show
  1. package/.llm/components/accordion.md +8 -0
  2. package/.llm/components/accordionitem.md +8 -0
  3. package/.llm/components/aspectratio.md +8 -0
  4. package/.llm/components/badge.md +8 -0
  5. package/.llm/components/bottomsheet.md +8 -0
  6. package/.llm/components/breadcrumb.md +8 -0
  7. package/.llm/components/breadcrumbitem.md +8 -0
  8. package/.llm/components/button.md +46 -22
  9. package/.llm/components/buttonicon.md +14 -6
  10. package/.llm/components/card.md +15 -1
  11. package/.llm/components/cardbody.md +28 -2
  12. package/.llm/components/cardbutton.md +15 -1
  13. package/.llm/components/checkbox.md +8 -0
  14. package/.llm/components/ctabanner.md +186 -0
  15. package/.llm/components/ctabannerslider.md +204 -0
  16. package/.llm/components/divider.md +8 -0
  17. package/.llm/components/dropdownmenu.md +13 -5
  18. package/.llm/components/faqaccordion.md +217 -0
  19. package/.llm/components/featurebullets.md +254 -0
  20. package/.llm/components/featurecards.md +313 -0
  21. package/.llm/components/featurescroll.md +284 -0
  22. package/.llm/components/featuresplit.md +249 -0
  23. package/.llm/components/filterchip.md +8 -0
  24. package/.llm/components/footer.md +8 -0
  25. package/.llm/components/footergroup.md +8 -0
  26. package/.llm/components/grid.md +8 -0
  27. package/.llm/components/icon.md +8 -0
  28. package/.llm/components/landinghero.md +254 -0
  29. package/.llm/components/link.md +9 -1
  30. package/.llm/components/logocolumns.md +235 -0
  31. package/.llm/components/logorows.md +212 -0
  32. package/.llm/components/menuitem.md +8 -0
  33. package/.llm/components/navbar.md +79 -15
  34. package/.llm/components/navbaritem.md +9 -1
  35. package/.llm/components/navbarmenu.md +8 -0
  36. package/.llm/components/navbarmenugroup.md +8 -0
  37. package/.llm/components/navbarpanel.md +9 -1
  38. package/.llm/components/navbarswitcher.md +9 -1
  39. package/.llm/components/navbarswitcheroption.md +8 -0
  40. package/.llm/components/option.md +8 -0
  41. package/.llm/components/pageheader.md +231 -0
  42. package/.llm/components/pagination.md +26 -89
  43. package/.llm/components/paginationdots.md +215 -0
  44. package/.llm/components/producthero.md +248 -0
  45. package/.llm/components/removablechip.md +8 -0
  46. package/.llm/components/row.md +8 -0
  47. package/.llm/components/scroller.md +8 -0
  48. package/.llm/components/searchinput.md +8 -0
  49. package/.llm/components/segmentedcontrol.md +8 -0
  50. package/.llm/components/segmentedcontrolitem.md +8 -0
  51. package/.llm/components/select.md +8 -0
  52. package/.llm/components/selectchip.md +56 -15
  53. package/.llm/components/spinner.md +8 -0
  54. package/.llm/components/stack.md +8 -0
  55. package/.llm/components/statusdot.md +8 -0
  56. package/.llm/components/subdomainnavbar.md +8 -0
  57. package/.llm/components/tab.md +8 -0
  58. package/.llm/components/table.md +8 -0
  59. package/.llm/components/tablebody.md +8 -0
  60. package/.llm/components/tablecell.md +8 -0
  61. package/.llm/components/tablehead.md +8 -0
  62. package/.llm/components/tableheadercell.md +8 -0
  63. package/.llm/components/tablerow.md +8 -0
  64. package/.llm/components/tablist.md +8 -0
  65. package/.llm/components/testimonialrow.md +235 -0
  66. package/.llm/components/testimonialslider.md +254 -0
  67. package/.llm/components/textarea.md +8 -0
  68. package/.llm/components/textinput.md +8 -0
  69. package/.llm/components/tooltip.md +8 -0
  70. package/.llm/components/typography.md +8 -0
  71. package/.llm/digest/button.md +11 -6
  72. package/.llm/digest/buttonicon.md +2 -2
  73. package/.llm/digest/card.md +1 -0
  74. package/.llm/digest/cardbody.md +3 -1
  75. package/.llm/digest/cardbutton.md +1 -0
  76. package/.llm/digest/ctabanner.md +44 -0
  77. package/.llm/digest/ctabannerslider.md +45 -0
  78. package/.llm/digest/dropdownmenu.md +1 -1
  79. package/.llm/digest/faqaccordion.md +43 -0
  80. package/.llm/digest/featurebullets.md +52 -0
  81. package/.llm/digest/featurecards.md +49 -0
  82. package/.llm/digest/featurescroll.md +52 -0
  83. package/.llm/digest/featuresplit.md +54 -0
  84. package/.llm/digest/landinghero.md +53 -0
  85. package/.llm/digest/logocolumns.md +55 -0
  86. package/.llm/digest/logorows.md +48 -0
  87. package/.llm/digest/navbar.md +18 -3
  88. package/.llm/digest/pageheader.md +49 -0
  89. package/.llm/digest/pagination.md +6 -17
  90. package/.llm/digest/paginationdots.md +43 -0
  91. package/.llm/digest/producthero.md +53 -0
  92. package/.llm/digest/selectchip.md +6 -1
  93. package/.llm/digest/testimonialrow.md +51 -0
  94. package/.llm/digest/testimonialslider.md +51 -0
  95. package/.llm/index.md +24 -3
  96. package/.llm/rules.md +24 -0
  97. package/.llm/tokens.md +56 -12
  98. package/AGENTS.md +28 -3
  99. package/README.md +41 -21
  100. package/dist/components/banner-data.d.ts +38 -0
  101. package/dist/components/banner-data.js +15 -0
  102. package/dist/components/blocks/block-reveal.css +90 -0
  103. package/dist/components/blocks/cta-banner/CtaBanner.css +66 -0
  104. package/dist/components/blocks/cta-banner/CtaBanner.d.ts +22 -0
  105. package/dist/components/blocks/cta-banner/CtaBanner.js +31 -0
  106. package/dist/components/blocks/cta-banner/CtaBanner.types.d.ts +29 -0
  107. package/dist/components/blocks/cta-banner/CtaBanner.types.js +13 -0
  108. package/dist/components/blocks/cta-banner/cta-banner-impl.css +29 -0
  109. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.css +90 -0
  110. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.d.ts +39 -0
  111. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.js +60 -0
  112. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.types.d.ts +41 -0
  113. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.types.js +15 -0
  114. package/dist/components/blocks/cta-banner-slider/cta-banner-slider-impl.css +73 -0
  115. package/dist/components/blocks/faq-accordion/FaqAccordion.css +54 -0
  116. package/dist/components/blocks/faq-accordion/FaqAccordion.d.ts +20 -0
  117. package/dist/components/blocks/faq-accordion/FaqAccordion.js +28 -0
  118. package/dist/components/blocks/faq-accordion/FaqAccordion.types.d.ts +25 -0
  119. package/dist/components/blocks/faq-accordion/FaqAccordion.types.js +10 -0
  120. package/dist/components/blocks/faq-accordion/faq-accordion-impl.css +54 -0
  121. package/dist/components/blocks/feature-bullets/FeatureBullets.css +139 -0
  122. package/dist/components/blocks/feature-bullets/FeatureBullets.d.ts +31 -0
  123. package/dist/components/blocks/feature-bullets/FeatureBullets.js +55 -0
  124. package/dist/components/blocks/feature-bullets/FeatureBullets.types.d.ts +39 -0
  125. package/dist/components/blocks/feature-bullets/FeatureBullets.types.js +16 -0
  126. package/dist/components/blocks/feature-bullets/feature-bullets-impl.css +104 -0
  127. package/dist/components/blocks/feature-cards/FeatureCards.css +84 -0
  128. package/dist/components/blocks/feature-cards/FeatureCards.d.ts +24 -0
  129. package/dist/components/blocks/feature-cards/FeatureCards.js +66 -0
  130. package/dist/components/blocks/feature-cards/FeatureCards.types.d.ts +33 -0
  131. package/dist/components/blocks/feature-cards/FeatureCards.types.js +14 -0
  132. package/dist/components/blocks/feature-cards/feature-cards-impl.css +245 -0
  133. package/dist/components/blocks/feature-scroll/FeatureScroll.css +137 -0
  134. package/dist/components/blocks/feature-scroll/FeatureScroll.d.ts +39 -0
  135. package/dist/components/blocks/feature-scroll/FeatureScroll.js +167 -0
  136. package/dist/components/blocks/feature-scroll/FeatureScroll.types.d.ts +40 -0
  137. package/dist/components/blocks/feature-scroll/FeatureScroll.types.js +17 -0
  138. package/dist/components/blocks/feature-scroll/feature-scroll-impl.css +292 -0
  139. package/dist/components/blocks/feature-split/FeatureSplit.css +95 -0
  140. package/dist/components/blocks/feature-split/FeatureSplit.d.ts +30 -0
  141. package/dist/components/blocks/feature-split/FeatureSplit.js +38 -0
  142. package/dist/components/blocks/feature-split/FeatureSplit.types.d.ts +39 -0
  143. package/dist/components/blocks/feature-split/FeatureSplit.types.js +14 -0
  144. package/dist/components/blocks/feature-split/feature-split-impl.css +83 -0
  145. package/dist/components/blocks/landing-hero/LandingHero.css +85 -0
  146. package/dist/components/blocks/landing-hero/LandingHero.d.ts +41 -0
  147. package/dist/components/blocks/landing-hero/LandingHero.js +54 -0
  148. package/dist/components/blocks/landing-hero/LandingHero.types.d.ts +37 -0
  149. package/dist/components/blocks/landing-hero/LandingHero.types.js +15 -0
  150. package/dist/components/blocks/landing-hero/landing-hero-impl.css +355 -0
  151. package/dist/components/blocks/logo-columns/LogoColumns.css +161 -0
  152. package/dist/components/blocks/logo-columns/LogoColumns.d.ts +23 -0
  153. package/dist/components/blocks/logo-columns/LogoColumns.js +46 -0
  154. package/dist/components/blocks/logo-columns/LogoColumns.types.d.ts +46 -0
  155. package/dist/components/blocks/logo-columns/LogoColumns.types.js +18 -0
  156. package/dist/components/blocks/logo-columns/logo-columns-impl.css +188 -0
  157. package/dist/components/blocks/logo-rows/LogoRows.css +122 -0
  158. package/dist/components/blocks/logo-rows/LogoRows.d.ts +20 -0
  159. package/dist/components/blocks/logo-rows/LogoRows.js +43 -0
  160. package/dist/components/blocks/logo-rows/LogoRows.types.d.ts +36 -0
  161. package/dist/components/blocks/logo-rows/LogoRows.types.js +16 -0
  162. package/dist/components/blocks/logo-rows/logo-rows-impl.css +179 -0
  163. package/dist/components/blocks/page-header/PageHeader.css +79 -0
  164. package/dist/components/blocks/page-header/PageHeader.d.ts +34 -0
  165. package/dist/components/blocks/page-header/PageHeader.js +43 -0
  166. package/dist/components/blocks/page-header/PageHeader.types.d.ts +32 -0
  167. package/dist/components/blocks/page-header/PageHeader.types.js +14 -0
  168. package/dist/components/blocks/page-header/page-header-impl.css +176 -0
  169. package/dist/components/blocks/product-hero/ProductHero.css +86 -0
  170. package/dist/components/blocks/product-hero/ProductHero.d.ts +35 -0
  171. package/dist/components/blocks/product-hero/ProductHero.js +48 -0
  172. package/dist/components/blocks/product-hero/ProductHero.types.d.ts +37 -0
  173. package/dist/components/blocks/product-hero/ProductHero.types.js +15 -0
  174. package/dist/components/blocks/product-hero/product-hero-impl.css +354 -0
  175. package/dist/components/blocks/testimonial-row/TestimonialRow.css +245 -0
  176. package/dist/components/blocks/testimonial-row/TestimonialRow.d.ts +20 -0
  177. package/dist/components/blocks/testimonial-row/TestimonialRow.js +128 -0
  178. package/dist/components/blocks/testimonial-row/TestimonialRow.types.d.ts +54 -0
  179. package/dist/components/blocks/testimonial-row/TestimonialRow.types.js +26 -0
  180. package/dist/components/blocks/testimonial-row/testimonial-row-impl.css +195 -0
  181. package/dist/components/blocks/testimonial-slider/TestimonialSlider.css +181 -0
  182. package/dist/components/blocks/testimonial-slider/TestimonialSlider.d.ts +22 -0
  183. package/dist/components/blocks/testimonial-slider/TestimonialSlider.js +36 -0
  184. package/dist/components/blocks/testimonial-slider/TestimonialSlider.types.d.ts +49 -0
  185. package/dist/components/blocks/testimonial-slider/TestimonialSlider.types.js +21 -0
  186. package/dist/components/blocks/testimonial-slider/testimonial-slider-impl.css +202 -0
  187. package/dist/components/blocks/use-reveal.d.ts +46 -0
  188. package/dist/components/blocks/use-reveal.js +120 -0
  189. package/dist/components/blocks/use-rotation.d.ts +62 -0
  190. package/dist/components/blocks/use-rotation.js +176 -0
  191. package/dist/components/core/accordion-item/AccordionItem.css +6 -5
  192. package/dist/components/core/bottom-sheet/BottomSheet.css +1 -1
  193. package/dist/components/core/button/Button.css +63 -16
  194. package/dist/components/core/button/Button.d.ts +14 -12
  195. package/dist/components/core/button/Button.js +43 -14
  196. package/dist/components/core/button/Button.types.d.ts +9 -14
  197. package/dist/components/core/button/button-impl.css +25 -0
  198. package/dist/components/core/button-icon/ButtonIcon.css +31 -15
  199. package/dist/components/core/button-icon/ButtonIcon.d.ts +2 -2
  200. package/dist/components/core/button-icon/ButtonIcon.js +2 -2
  201. package/dist/components/core/button-icon/ButtonIcon.types.d.ts +4 -4
  202. package/dist/components/core/card/Card.css +13 -4
  203. package/dist/components/core/card/Card.types.d.ts +2 -1
  204. package/dist/components/core/card-body/CardBody.css +11 -6
  205. package/dist/components/core/card-body/CardBody.d.ts +1 -1
  206. package/dist/components/core/card-body/CardBody.js +2 -2
  207. package/dist/components/core/card-body/CardBody.types.d.ts +4 -1
  208. package/dist/components/core/card-body/CardBody.types.js +1 -0
  209. package/dist/components/core/card-button/CardButton.css +13 -4
  210. package/dist/components/core/card-button/CardButton.types.d.ts +2 -1
  211. package/dist/components/core/checkbox/Checkbox.css +8 -1
  212. package/dist/components/core/dropdown-menu/DropdownMenu.css +13 -12
  213. package/dist/components/core/dropdown-menu/DropdownMenu.d.ts +5 -3
  214. package/dist/components/core/dropdown-menu/DropdownMenu.js +5 -3
  215. package/dist/components/core/filter-chip/FilterChip.css +2 -1
  216. package/dist/components/core/footer/footer-impl.css +1 -1
  217. package/dist/components/core/footer-group/FooterGroup.css +8 -7
  218. package/dist/components/core/icon/Icon.css +1 -1
  219. package/dist/components/core/link/Link.css +1 -1
  220. package/dist/components/core/menu-item/MenuItem.css +1 -1
  221. package/dist/components/core/navbar/Navbar.css +7 -8
  222. package/dist/components/core/navbar/Navbar.d.ts +17 -1
  223. package/dist/components/core/navbar/Navbar.js +139 -12
  224. package/dist/components/core/navbar/Navbar.types.d.ts +23 -4
  225. package/dist/components/core/navbar/Navbar.types.js +1 -1
  226. package/dist/components/core/navbar/navbar-impl.css +10 -3
  227. package/dist/components/core/navbar/navbar-material.css +96 -0
  228. package/dist/components/core/navbar-item/NavbarItem.css +4 -4
  229. package/dist/components/core/navbar-menu/NavbarMenu.css +7 -5
  230. package/dist/components/core/navbar-menu/NavbarMenu.d.ts +1 -0
  231. package/dist/components/core/navbar-menu/NavbarMenu.js +1 -0
  232. package/dist/components/core/navbar-menu/navbar-menu-impl.css +7 -7
  233. package/dist/components/core/navbar-switcher/NavbarSwitcher.css +6 -5
  234. package/dist/components/core/navbar-switcher/NavbarSwitcher.d.ts +1 -0
  235. package/dist/components/core/navbar-switcher/NavbarSwitcher.js +2 -1
  236. package/dist/components/core/option/Option.css +1 -1
  237. package/dist/components/core/pagination/Pagination.css +1 -75
  238. package/dist/components/core/pagination/Pagination.d.ts +4 -4
  239. package/dist/components/core/pagination/Pagination.js +11 -51
  240. package/dist/components/core/pagination/Pagination.types.d.ts +5 -17
  241. package/dist/components/core/pagination/Pagination.types.js +1 -3
  242. package/dist/components/core/pagination-dots/PaginationDots.css +60 -0
  243. package/dist/components/core/pagination-dots/PaginationDots.d.ts +25 -0
  244. package/dist/components/core/pagination-dots/PaginationDots.js +104 -0
  245. package/dist/components/core/pagination-dots/PaginationDots.types.d.ts +38 -0
  246. package/dist/components/core/pagination-dots/PaginationDots.types.js +9 -0
  247. package/dist/components/core/removable-chip/RemovableChip.css +3 -3
  248. package/dist/components/core/search-input/SearchInput.css +1 -1
  249. package/dist/components/core/segmented-control/SegmentedControl.css +1 -1
  250. package/dist/components/core/segmented-control-item/SegmentedControlItem.css +1 -1
  251. package/dist/components/core/select/Select.css +2 -1
  252. package/dist/components/core/select-chip/SelectChip.css +14 -7
  253. package/dist/components/core/select-chip/SelectChip.d.ts +1 -1
  254. package/dist/components/core/select-chip/SelectChip.js +7 -4
  255. package/dist/components/core/select-chip/SelectChip.types.d.ts +7 -1
  256. package/dist/components/core/select-chip/SelectChip.types.js +1 -1
  257. package/dist/components/core/select-chip/select-chip-impl.css +14 -3
  258. package/dist/components/core/status-dot/StatusDot.css +1 -1
  259. package/dist/components/core/subdomain-navbar/SubdomainNavbar.css +3 -3
  260. package/dist/components/core/tab/Tab.css +1 -1
  261. package/dist/components/core/tab-list/TabList.css +1 -1
  262. package/dist/components/core/table/table-impl.css +36 -14
  263. package/dist/components/core/table-header-cell/TableHeaderCell.css +5 -5
  264. package/dist/components/core/text-area/TextArea.css +1 -1
  265. package/dist/components/core/text-input/TextInput.css +1 -1
  266. package/dist/components/core/tooltip/Tooltip.css +1 -1
  267. package/dist/components/core/typography/Typography.css +5 -5
  268. package/dist/components/index.d.ts +35 -0
  269. package/dist/components/index.js +30 -0
  270. package/dist/components/logo-data.d.ts +24 -0
  271. package/dist/components/logo-data.js +11 -0
  272. package/dist/components/scroll-data.d.ts +64 -0
  273. package/dist/components/scroll-data.js +17 -0
  274. package/dist/components/testimonial-row-data.d.ts +51 -0
  275. package/dist/components/testimonial-row-data.js +11 -0
  276. package/dist/components/testimonial-slider-data.d.ts +26 -0
  277. package/dist/components/testimonial-slider-data.js +10 -0
  278. package/dist/marketing.css +385 -14
  279. package/package.json +1 -6
@@ -0,0 +1,86 @@
1
+ /* GENERATED from producthero.contract.json. Do not edit. */
2
+
3
+ :where([data-dds-context="marketing"]) .dds-producthero {
4
+ box-sizing: border-box;
5
+ container-type: inline-size;
6
+ display: flex;
7
+ inline-size: 100%;
8
+ justify-content: center;
9
+ overflow: hidden;
10
+ position: relative;
11
+ background-color: var(--color-bg-brand-strong);
12
+ color: var(--color-fg-on-brand-strong);
13
+ }
14
+
15
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__inner {
16
+ box-sizing: border-box;
17
+ display: flex;
18
+ inline-size: 100%;
19
+ min-inline-size: 0;
20
+ position: relative;
21
+ max-inline-size: var(--size-content-max);
22
+ padding-block: var(--space-section-default);
23
+ padding-inline: var(--space-inset-page);
24
+ }
25
+
26
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__content {
27
+ display: flex;
28
+ flex-direction: column;
29
+ inline-size: 100%;
30
+ min-inline-size: 0;
31
+ row-gap: var(--space-heading-description-actions);
32
+ }
33
+
34
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__text {
35
+ display: flex;
36
+ flex-direction: column;
37
+ min-inline-size: 0;
38
+ row-gap: var(--space-gap-none);
39
+ }
40
+
41
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__eyebrow {
42
+ margin-block: 0;
43
+ font-family: var(--font-eyebrow-lg-family);
44
+ font-size: var(--font-eyebrow-lg-size);
45
+ font-weight: var(--font-eyebrow-lg-weight);
46
+ letter-spacing: var(--font-eyebrow-lg-letter-spacing);
47
+ line-height: var(--font-eyebrow-lg-line-height);
48
+ margin-block-end: var(--space-heading-eyebrow-title);
49
+ }
50
+
51
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__title {
52
+ margin-block: 0;
53
+ text-wrap: balance;
54
+ font-family: var(--font-h1-family);
55
+ font-size: var(--font-h1-size);
56
+ font-weight: var(--font-h1-weight);
57
+ letter-spacing: var(--font-h1-letter-spacing);
58
+ line-height: var(--font-h1-line-height);
59
+ margin-block-end: var(--space-heading-title-description);
60
+ }
61
+
62
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__description {
63
+ margin-block: 0;
64
+ font-family: var(--font-body-md-family);
65
+ font-size: var(--font-body-md-size);
66
+ font-weight: var(--font-body-md-weight);
67
+ letter-spacing: var(--font-body-md-letter-spacing);
68
+ line-height: var(--font-body-md-line-height);
69
+ max-inline-size: var(--size-measure-hero-description);
70
+ }
71
+
72
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__actions {
73
+ display: flex;
74
+ flex-wrap: wrap;
75
+ column-gap: var(--space-actions-gap);
76
+ row-gap: var(--space-actions-gap);
77
+ }
78
+
79
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__media {
80
+ min-inline-size: 0;
81
+ overflow: hidden;
82
+ position: relative;
83
+ aspect-ratio: var(--aspect-square);
84
+ border-radius: var(--radius-none);
85
+ }
86
+
@@ -0,0 +1,35 @@
1
+ import './ProductHero.css';
2
+ import './product-hero-impl.css';
3
+ import '../block-reveal.css';
4
+ import { type ProductHeroProps } from './ProductHero.types.js';
5
+ export type { ProductHeroProps };
6
+ /**
7
+ * The band that opens a product or a market page.
8
+ *
9
+ * The product tier's band, and one of three. Which band a page opens with follows from where the
10
+ * page sits rather than from a prop: a landing page takes LandingHero and a legal page PageHeader.
11
+ * Separate components rather than one with a switch, so a page cannot be given a tier it is not.
12
+ *
13
+ * One column, centred, read down: what the page is about, what a reader can do about it, and then
14
+ * the thing itself. That last part is the whole difference from the tier above. LandingHero ranges
15
+ * its claim to the start and places a subject against the band's own edge, cropped by it; here the claim
16
+ * goes over the middle and the product sits under it, in the column, whole and capped to the same
17
+ * measure as the text. A product page is about one thing, and nothing should cut into it.
18
+ *
19
+ * Which is why `media` is a child of `content` here and a child of the band there. The same slot, in two
20
+ * places, because the two tiers answer different questions about what a visual is for.
21
+ *
22
+ * `root` spans the full width and `inner` holds the measure — the arrangement Footer uses, and for
23
+ * the same reason: a ground stopping at the measure would read as a wide card at the top of the
24
+ * page rather than as the page beginning. The ground is dark and the ink is set once on the root,
25
+ * inherited by everything inside it.
26
+ *
27
+ * The steps inside the text block are carried by each part's own `margin-block-end` rather than by
28
+ * a gap on the block, because eyebrow-to-title and title-to-description are two different roles
29
+ * that agree at full width and part company on a phone.
30
+ *
31
+ * The title carries the band's accessible name through `aria-labelledby`. A `<section>` is only a
32
+ * region landmark once it has a name, and a band that announced itself as an unnamed section is one
33
+ * more thing a screen reader user walks through rather than a place they can skip to.
34
+ */
35
+ export declare function ProductHero({ eyebrow, title, headingLevel, description, actions, media, backgroundImage, }: ProductHeroProps): import("react").JSX.Element;
@@ -0,0 +1,48 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useId } from 'react';
4
+ import './ProductHero.css';
5
+ import './product-hero-impl.css';
6
+ import '../block-reveal.css';
7
+ import { arriving, useReveal } from '../use-reveal.js';
8
+ import { given } from '../../given.js';
9
+ import { productHeroDefaults, productHeroParts, } from './ProductHero.types.js';
10
+ /**
11
+ * The band that opens a product or a market page.
12
+ *
13
+ * The product tier's band, and one of three. Which band a page opens with follows from where the
14
+ * page sits rather than from a prop: a landing page takes LandingHero and a legal page PageHeader.
15
+ * Separate components rather than one with a switch, so a page cannot be given a tier it is not.
16
+ *
17
+ * One column, centred, read down: what the page is about, what a reader can do about it, and then
18
+ * the thing itself. That last part is the whole difference from the tier above. LandingHero ranges
19
+ * its claim to the start and places a subject against the band's own edge, cropped by it; here the claim
20
+ * goes over the middle and the product sits under it, in the column, whole and capped to the same
21
+ * measure as the text. A product page is about one thing, and nothing should cut into it.
22
+ *
23
+ * Which is why `media` is a child of `content` here and a child of the band there. The same slot, in two
24
+ * places, because the two tiers answer different questions about what a visual is for.
25
+ *
26
+ * `root` spans the full width and `inner` holds the measure — the arrangement Footer uses, and for
27
+ * the same reason: a ground stopping at the measure would read as a wide card at the top of the
28
+ * page rather than as the page beginning. The ground is dark and the ink is set once on the root,
29
+ * inherited by everything inside it.
30
+ *
31
+ * The steps inside the text block are carried by each part's own `margin-block-end` rather than by
32
+ * a gap on the block, because eyebrow-to-title and title-to-description are two different roles
33
+ * that agree at full width and part company on a phone.
34
+ *
35
+ * The title carries the band's accessible name through `aria-labelledby`. A `<section>` is only a
36
+ * region landmark once it has a name, and a band that announced itself as an unnamed section is one
37
+ * more thing a screen reader user walks through rather than a place they can skip to.
38
+ */
39
+ export function ProductHero({ eyebrow, title, headingLevel = productHeroDefaults.headingLevel, description, actions, media, backgroundImage, }) {
40
+ const titleId = useId();
41
+ const [band, revealed] = useReveal();
42
+ const Title = headingLevel === 'h2' ? 'h2' : 'h1';
43
+ return (_jsx("section", { className: productHeroParts.root, "aria-labelledby": titleId,
44
+ /* The one inline style here, and it is a value rather than a decision: which photograph,
45
+ supplied by the page. How it is drawn — the cover fit and the position —
46
+ is in the stylesheet, where it can be reasoned about. */
47
+ style: given(backgroundImage) ? { backgroundImage: `url(${backgroundImage})` } : undefined, children: _jsx("div", { className: productHeroParts.inner, ref: band, "data-revealed": revealed, children: _jsxs("div", { className: productHeroParts.content, children: [_jsxs("div", { className: productHeroParts.text, children: [given(eyebrow) ? (_jsx("p", { className: productHeroParts.eyebrow, ...arriving(0), children: eyebrow })) : null, _jsx(Title, { className: productHeroParts.title, ...arriving(1), id: titleId, children: title }), given(description) ? (_jsx("p", { className: productHeroParts.description, ...arriving(2), children: description })) : null] }), actions ? (_jsx("div", { className: productHeroParts.actions, ...arriving(3), children: actions })) : null, media ? (_jsx("div", { className: productHeroParts.media, ...arriving(4), "aria-hidden": "true", children: media })) : null] }) }) }));
48
+ }
@@ -0,0 +1,37 @@
1
+ import type { ReactNode } from 'react';
2
+ export interface ProductHeroOwnProps {
3
+ /** A word or two placing the page before its title names it — a product family, a market, a campaign */
4
+ eyebrow?: string;
5
+ /** Always. The one thing the page is about, in the fewest words that still say it. It is the page's leading heading and the band's accessible name */
6
+ title: string;
7
+ /**
8
+ * `h1` — The default, and correct whenever the hero opens the page — which is what a hero is for
9
+ * `h2` — The rare page that already carries its `h1` elsewhere, and would otherwise have two
10
+ */
11
+ headingLevel?: 'h1' | 'h2';
12
+ /** The sentence under the title that says what the claim above it means, for the reader who is not yet convinced by the claim alone */
13
+ description?: string;
14
+ /** The one or two things the page wants a reader to do. Composed by the page rather than described to this component, so a call to action is the same Button here as anywhere else on the site */
15
+ actions?: ReactNode;
16
+ /** The product itself, under the claim and the actions — in the column, capped to the measure, and whole */
17
+ media?: ReactNode;
18
+ /** A photograph filling the whole band. It is shown as it is — nothing is painted over it, so choose one already dark enough that the title reads on it */
19
+ backgroundImage?: string;
20
+ }
21
+ export type ProductHeroProps = ProductHeroOwnProps;
22
+ /** The class each part carries. Apply these — do not retype them. */
23
+ export declare const productHeroParts: {
24
+ readonly root: "dds-producthero";
25
+ readonly inner: "dds-producthero__inner";
26
+ readonly content: "dds-producthero__content";
27
+ readonly text: "dds-producthero__text";
28
+ readonly eyebrow: "dds-producthero__eyebrow";
29
+ readonly title: "dds-producthero__title";
30
+ readonly description: "dds-producthero__description";
31
+ readonly actions: "dds-producthero__actions";
32
+ readonly media: "dds-producthero__media";
33
+ };
34
+ /** Generated so defaults cannot drift from the contract. */
35
+ export declare const productHeroDefaults: {
36
+ readonly headingLevel: "h1";
37
+ };
@@ -0,0 +1,15 @@
1
+ // GENERATED from product-hero.contract.json. Do not edit.
2
+ /** The class each part carries. Apply these — do not retype them. */
3
+ export const productHeroParts = {
4
+ root: 'dds-producthero',
5
+ inner: 'dds-producthero__inner',
6
+ content: 'dds-producthero__content',
7
+ text: 'dds-producthero__text',
8
+ eyebrow: 'dds-producthero__eyebrow',
9
+ title: 'dds-producthero__title',
10
+ description: 'dds-producthero__description',
11
+ actions: 'dds-producthero__actions',
12
+ media: 'dds-producthero__media',
13
+ };
14
+ /** Generated so defaults cannot drift from the contract. */
15
+ export const productHeroDefaults = { headingLevel: 'h1' };
@@ -0,0 +1,354 @@
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
+ * The photograph, drawn the one way a band wants it.
10
+ *
11
+ * The page passes which image; how it is fitted is this component's decision and belongs here
12
+ * rather than in the inline style, where a page could not see it. `cover` because a band of fixed
13
+ * height letterboxing a photograph would show the ground through it.
14
+ */
15
+ :where([data-dds-context="marketing"]) .dds-producthero {
16
+ background-position: center;
17
+ background-repeat: no-repeat;
18
+ background-size: cover;
19
+ }
20
+
21
+ /*
22
+ * A title with nothing under it carries no step under it.
23
+ *
24
+ * The steps inside the text block sit on each part's own `margin-block-end`, because eyebrow-to-
25
+ * title and title-to-description are two roles that agree at full width and part company on a
26
+ * phone. The cost is a trailing margin: with `description` absent the title is the last child and
27
+ * its step is measured against nothing.
28
+ */
29
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__title:last-child {
30
+ margin-block-end: 0;
31
+ }
32
+
33
+ /*
34
+ * A screen tall, like the tier above it.
35
+ *
36
+ * `100cqh` rather than `100svh`, and the two are the same number on a real page: with no ancestor
37
+ * declaring size containment, a container query length falls back to the small viewport. What the
38
+ * container unit adds is an answer for a frame standing in for a window, which is what the preview
39
+ * gives a band — see `spansThePage`.
40
+ *
41
+ * `min-block-size` rather than `block-size`, so a band whose copy runs long grows instead of
42
+ * clipping it.
43
+ */
44
+ :where([data-dds-context="marketing"]) .dds-producthero {
45
+ min-block-size: 100cqh;
46
+ }
47
+
48
+ /*
49
+ * Centred, and centred on the measure rather than on the band.
50
+ *
51
+ * `size.measure.hero-description` caps the line length; without `margin-inline: auto` the capped block
52
+ * sits at the column's leading edge while the text inside it is centred, which reads as a
53
+ * paragraph nudged toward the start of everything above it. The same correction the actions need, for the same
54
+ * reason: a wrapped row of buttons hugs its content and would otherwise sit at the start edge.
55
+ */
56
+ /*
57
+ * Two calls to action stack on a phone and stand side by side once there is room.
58
+ *
59
+ * The reference design makes each one full width at the narrow end — a button that hugs its label
60
+ * on a phone is a tap target sized by how long the word happens to be, so "Try free demo" is an
61
+ * easier press than "Buy" for no reason a reader would agree with — and lets them hug once the
62
+ * band is wide enough to hold both on a line.
63
+ *
64
+ * Before the wide rules below, not after them: a container query adds no weight, so a phone rule
65
+ * written later at the same specificity wins at every width — which is how it stood once, with the
66
+ * actions stacked and stretched across a desktop band.
67
+ */
68
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__actions {
69
+ align-items: stretch;
70
+ flex-direction: column;
71
+ }
72
+
73
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__actions > * {
74
+ inline-size: 100%;
75
+ }
76
+
77
+ /*
78
+ * Whatever the page put in a visual slot fills the slot's width.
79
+ *
80
+ * The slots take a node rather than a source, so what arrives is the page's element — an `<img>`,
81
+ * a `<picture>`, or a ratio box holding one — and this cannot know whether it carries dimensions.
82
+ * Width only: the height is the visual's own business here, unlike the landing tier where the slot
83
+ * is a sized box and the subject has to fill it.
84
+ *
85
+ * The `<img>` rule reaches a level deeper on purpose, for the case where the page wraps its
86
+ * picture in something: `object-fit` does nothing on a `<div>`, so a rule aimed at the slot's
87
+ * immediate child was silently a no-op whenever that child was a ratio box.
88
+ */
89
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__media > * {
90
+ inline-size: 100%;
91
+ }
92
+
93
+ /*
94
+ * Starts on a phone, centred once the band is wide enough to hold a line.
95
+ *
96
+ * The reference design does exactly this, and the reason is legibility rather than taste: centred
97
+ * text is read from a different starting edge on every line, which costs little across a wide
98
+ * measure and a great deal across a narrow one. The claim is centred where it is short relative to
99
+ * the band and ranged where it is not.
100
+ */
101
+ @container (min-width: 48rem) {
102
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__content {
103
+ align-items: center;
104
+ text-align: center;
105
+ }
106
+
107
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__description {
108
+ margin-inline: auto;
109
+ }
110
+
111
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__actions {
112
+ align-items: center;
113
+ flex-direction: row;
114
+ justify-content: center;
115
+ }
116
+
117
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__actions > * {
118
+ inline-size: auto;
119
+ }
120
+ }
121
+
122
+ /*
123
+ * The product, under the claim and narrower than it.
124
+ *
125
+ * In flow here, where the landing tier places its subject against the band's edge — so the rules
126
+ * that tier needs are wrong for this one. `block-size: 100%` on the child was carried over from it
127
+ * and is the reason the visual sat where it did: the slot has no height of its own, so the
128
+ * percentage resolved to auto and whatever was inside sized itself.
129
+ *
130
+ * Capped at sixty per cent of the column rather than filling it. A screenshot run to the measure's
131
+ * full width is taller than the band that holds it, and the claim above it goes off the top. The
132
+ * same percentage reasoning as the landing tier's half-measure text column, and a share rather
133
+ * than a token for the same reason: it is this arrangement's proportion, not a value the system
134
+ * names.
135
+ */
136
+ /*
137
+ * The column fills the band, said outright rather than inherited.
138
+ *
139
+ * Everything about where this band's contents sit depends on it: the product is stood on the foot
140
+ * by the room left above it, and room only exists if the column is taller than what is in it. It
141
+ * should stretch on its own — it is the only item of a flex row that sets no cross size — and it
142
+ * was not, which is what left the claim at the top, the picture under it, and the rest of the band
143
+ * empty beneath both. `align-self` asks for it directly, so nothing between here and the band has
144
+ * to agree for the arrangement to hold.
145
+ */
146
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__content {
147
+ align-self: stretch;
148
+ }
149
+
150
+ /*
151
+ * The product stands on the band's foot rather than floating above it, at every width.
152
+ *
153
+ * It is the last thing in the column, so what separates it from the band's edge is the section
154
+ * step `inner` carries. Dropped, the picture meets the foot and is cropped by it — which is what
155
+ * makes a product read as standing in the band rather than as a picture placed on it, and is the
156
+ * arrangement LandingHero's subject takes for the same reason.
157
+ *
158
+ * At every width, which is the correction. This sat inside the wide layout's query for a while and
159
+ * the phone kept its step: the picture was aligned to the foot of a column that stopped short of
160
+ * the band, so every arrangement above it was right and there was a hand's width of ground under
161
+ * it regardless. A band that clips its subject is not a decision about how wide the window is.
162
+ *
163
+ * Only where there is a product. `:has()` asks the band whether one was passed, because without it
164
+ * the claim and its actions would be the thing resting on the edge, and a band of words with no
165
+ * air under them is a band that looks cut off rather than composed.
166
+ *
167
+ * The step above is untouched: this is the distance from the picture down, not the rhythm of the
168
+ * column.
169
+ */
170
+ :where([data-dds-context="marketing"])
171
+ .dds-producthero:has(.dds-producthero__media)
172
+ .dds-producthero__inner {
173
+ padding-block-end: 0;
174
+ }
175
+
176
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__media {
177
+ inline-size: 100%;
178
+ }
179
+
180
+ /*
181
+ * Below the fold the whole column sits at the foot, rather than the picture alone.
182
+ *
183
+ * There is no bar to clear on a phone and nothing above the claim worth the space, so a band that
184
+ * put its words at the top and its picture at the bottom was a screen with a hole in the middle.
185
+ * Everything together at the base reads as one thing standing on the ground the page continues
186
+ * from.
187
+ *
188
+ * The auto margin has to go with it. Left on, it would take every pixel of the free space for
189
+ * itself and put the picture back at the foot on its own — which is the arrangement this rule
190
+ * exists to replace, not one to stack on top of.
191
+ */
192
+ @container (max-width: 47.9375rem) {
193
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__content {
194
+ justify-content: flex-end;
195
+ }
196
+
197
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__media {
198
+ margin-block-start: 0;
199
+ }
200
+ }
201
+
202
+
203
+
204
+
205
+ @container (min-width: 48rem) {
206
+ /*
207
+ * Capped on both axes, and sized by width rather than height.
208
+ *
209
+ * `max-block-size` is what stops the band outgrowing the screen it is supposed to be one of. A
210
+ * sixty-per-cent-wide widescreen picture is four hundred tall on a wide band, and with the claim
211
+ * and the section step above it the band came to a thousand — taller than a viewport, so its own
212
+ * rounded bottom corners scrolled past the fold and the exit animation looked like it was only
213
+ * scaling. It is a `max-`, so it caps without demanding, which is the difference from the
214
+ * `block-size` that pushed the picture over its own button.
215
+ *
216
+ * The reference design writes this as `height: 50vh; aspect-ratio: 1/1`, and reading it across
217
+ * literally was wrong here: a definite block-size on a flex item in a column asks for that height
218
+ * whatever is above it, so the product demanded half the band while the claim and the actions had
219
+ * already spent it. The column overran and the visual rode up over its own button.
220
+ *
221
+ * A width cap cannot do that. The visual takes the height its ratio gives it from the room that
222
+ * is actually left, which is the same picture at every size the band is ever shown at — and the
223
+ * reference's 50vh square lands within a few per cent of it at the widths that matter.
224
+ */
225
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__media {
226
+ /*
227
+ * Pushed to the foot of the band by the room left over.
228
+ *
229
+ * `margin-block-start: auto` is what stands the product on the edge: the column fills the band,
230
+ * the claim sits at the top of it under the bar's clearance, and every pixel between them goes
231
+ * above the picture. Aligning the whole column to the end instead would have bunched the claim
232
+ * onto the product with a screen of nothing over it.
233
+ */
234
+ margin-block-start: auto;
235
+ /*
236
+ * One cap, on the axis the shape is measured from.
237
+ *
238
+ * Capping the height and the width separately is what flattened the portrait: the box took
239
+ * sixty per cent of the column, `aspect.portrait` asked for a height a quarter greater again,
240
+ * and `max-block-size` clamped that back — leaving the width where it was. A ratio clamped on
241
+ * one axis is not a ratio; it is a landscape box that used to be a portrait.
242
+ *
243
+ * So the height's limit is expressed as a width instead, which a square makes exact: the widest
244
+ * the picture may be is the tallest it may be, because `aspect.square` is one to one. A ratio
245
+ * that was not would have to restate itself here as a fraction, and that restatement is the one
246
+ * place the two could drift.
247
+ *
248
+ * Half the band, which is the reference design's own `height: 50vh` — reachable now that the
249
+ * slot is a square, where before it was two numbers that had to be reconciled. It was forty per
250
+ * cent while the picture could ride up over its own button; standing on the foot it cannot, and
251
+ * the band clips, so the ceiling can be what the design asked for.
252
+ *
253
+ * The width guard is the second half of the `min()`, for a window tall enough that half its
254
+ * height is wider than the measure — there the picture would outrun the claim above it.
255
+ */
256
+ max-inline-size: min(80%, 50cqh);
257
+ }
258
+
259
+ /*
260
+ * The claim starts below where a navigation bar would be.
261
+ *
262
+ * The band is the first thing on the page and a bar sits over it, so the section's own step is
263
+ * measured from under the bar rather than from the top of the window — `size.bar-height` is what
264
+ * a collapsed one takes, and the step is the band's usual one on top of it. Without this the
265
+ * eyebrow began at the section step and the bar ate it.
266
+ */
267
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__inner {
268
+ padding-block-start: calc(var(--size-bar-height) + var(--space-section-default));
269
+ }
270
+
271
+
272
+
273
+ /*
274
+ * The visual takes its height from that cap and its width from its own ratio, so a wide band
275
+ * does not make it taller. Without the second half of this the cap clipped the picture instead
276
+ * of resizing it.
277
+ */
278
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__media > * {
279
+ block-size: 100%;
280
+ inline-size: auto;
281
+ margin-inline: auto;
282
+ max-inline-size: 100%;
283
+ }
284
+ }
285
+
286
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__media img {
287
+ block-size: 100%;
288
+ display: block;
289
+ inline-size: 100%;
290
+ object-fit: cover;
291
+ }
292
+
293
+ /*
294
+ * The band rounds off as it leaves.
295
+ *
296
+ * Scroll-driven rather than timed: `view()` measures the band against the viewport, so the corner
297
+ * arrives as the reader scrolls and reverses when they scroll back. There is no element entering
298
+ * and no transition to hang it on, which is what puts a keyframed animation in this file rather
299
+ * than in a binding.
300
+ *
301
+ * `radius.expressive` is the corner — the role's own description names high-impact visual sections
302
+ * and banners. Only the two lower corners: the band starts at the top of the document with nothing
303
+ * above it to round away from.
304
+ */
305
+ @keyframes dds-producthero-exit {
306
+ to {
307
+ border-end-end-radius: var(--radius-expressive);
308
+ border-end-start-radius: var(--radius-expressive);
309
+ scale: var(--motion-scale-band-exit);
310
+ }
311
+ }
312
+
313
+ @supports (animation-timeline: view()) {
314
+ :where([data-dds-context="marketing"]) .dds-producthero {
315
+ animation: dds-producthero-exit linear both;
316
+ animation-range: exit 0% exit 40%;
317
+ animation-timeline: view();
318
+ }
319
+ }
320
+
321
+ /*
322
+ * A reader who asked for less movement gets none of it.
323
+ *
324
+ * The generated sheet writes a reduced-motion block from its bindings, and this animation is not
325
+ * one of them — it is written here, so its own exception has to be too.
326
+ */
327
+ @media (prefers-reduced-motion: reduce) {
328
+ :where([data-dds-context="marketing"]) .dds-producthero {
329
+ animation: none;
330
+ }
331
+ }
332
+
333
+ /*
334
+ * A band in a short container compacts, rather than clipping what it holds.
335
+ *
336
+ * `space.section.default` is 112 top and bottom — 224 of the band before a word is set, which is
337
+ * right at a screen's height and is most of an overview row. The band is as tall as the screen, so
338
+ * it is the screen's height that is asked: a `@media` query, on a real page. The band's own
339
+ * `container-type` is `inline-size`, which cannot answer a height, so a container query alone
340
+ * matched only inside a frame that measures its height — the preview's — and never in production.
341
+ * Both are written: the media query for a page, the container query for a frame. The role already
342
+ * exists for a band that has to be shorter; nothing new is named here.
343
+ */
344
+ @container (max-height: 40rem) {
345
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__inner {
346
+ padding-block: var(--space-section-compact);
347
+ }
348
+ }
349
+
350
+ @media (max-height: 40rem) {
351
+ :where([data-dds-context="marketing"]) .dds-producthero .dds-producthero__inner {
352
+ padding-block: var(--space-section-compact);
353
+ }
354
+ }