@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,25 @@
1
+ import type { ReactNode } from 'react';
2
+ export interface FaqAccordionOwnProps {
3
+ /**
4
+ * `page` — The default, and the page's own white. A section that has nothing to separate itself from what is above it — most of them — and the ground a reader is already on
5
+ * `subtle` — A quiet step off the page, for a band that wants to read as its own section without changing the page's voice — the reference design's slate FAQ. Painted as the band's tint laid over the page's own ground, so it is the same grey whatever is behind the section.
6
+ * `strong` — `color.bg.brand-strong`, the dark band. It stops the page rather than dividing it, so it is for a section a reader should arrive at — and one per page is usually one more than enough. The questions turn round with it: white headings, a muted chevron and rules in the band's own veil, fixed like the band
7
+ */
8
+ ground?: 'page' | 'subtle' | 'strong';
9
+ /** Always. What the questions are about, in the fewest words — "Frequently asked questions", "Withdrawals". */
10
+ title: string;
11
+ /** Allowed: AccordionItem */
12
+ children: ReactNode;
13
+ }
14
+ export type FaqAccordionProps = FaqAccordionOwnProps;
15
+ /** The class each part carries. Apply these — do not retype them. */
16
+ export declare const faqAccordionParts: {
17
+ readonly root: "dds-faqaccordion";
18
+ readonly inner: "dds-faqaccordion__inner";
19
+ readonly title: "dds-faqaccordion__title";
20
+ readonly list: "dds-faqaccordion__list";
21
+ };
22
+ /** Generated so defaults cannot drift from the contract. */
23
+ export declare const faqAccordionDefaults: {
24
+ readonly ground: "page";
25
+ };
@@ -0,0 +1,10 @@
1
+ // GENERATED from faq-accordion.contract.json. Do not edit.
2
+ /** The class each part carries. Apply these — do not retype them. */
3
+ export const faqAccordionParts = {
4
+ root: 'dds-faqaccordion',
5
+ inner: 'dds-faqaccordion__inner',
6
+ title: 'dds-faqaccordion__title',
7
+ list: 'dds-faqaccordion__list',
8
+ };
9
+ /** Generated so defaults cannot drift from the contract. */
10
+ export const faqAccordionDefaults = { ground: 'page' };
@@ -0,0 +1,54 @@
1
+ /*
2
+ * Scoped to this package, like the generated sheet beside it.
3
+ */
4
+
5
+ /*
6
+ * The heading starts on a phone and is centred once the band is wide enough to hold a line.
7
+ *
8
+ * PageHeader's rule and FeatureCards', at the same width, so the sections on one page agree about
9
+ * where a heading sits. The heading is capped at the heading measure, so `margin-inline: auto` is
10
+ * what centres the box rather than its words inside a box left at the start edge. The questions
11
+ * stay at the start edge: a row is read from its start, and a centred question would put the chevron at
12
+ * a different distance from every one of them.
13
+ *
14
+ * `48rem` longhand because `var()` is not permitted in a container query condition.
15
+ */
16
+ @container (min-width: 48rem) {
17
+ :where([data-dds-context="marketing"]) .dds-faqaccordion .dds-faqaccordion__title {
18
+ margin-inline: auto;
19
+ text-align: center;
20
+ }
21
+ }
22
+
23
+ /*
24
+ * The questions turn round on the dark band.
25
+ *
26
+ * AccordionItem draws its question in color.fg.default, its chevron and its hover in color.fg.muted,
27
+ * its rules in color.border.subtle and its focus ring in color.border.focus — every one of them made
28
+ * for a light page, and every one dark on near-black. It has no tone to answer with, so the block,
29
+ * which knows its ground, gives it the dark band's fixed roles: white questions, a chevron and a
30
+ * hover at fg.muted-inverse, rules at the band's veil, the band's own focus ring. The answers need
31
+ * nothing: they take the section's ink, which is already white.
32
+ */
33
+ :where([data-dds-context="marketing"]) .dds-faqaccordion[data-ground="strong"] .dds-accordionitem {
34
+ border-color: var(--color-border-subtle-inverse);
35
+ }
36
+
37
+ :where([data-dds-context="marketing"]) .dds-faqaccordion[data-ground="strong"] .dds-accordionitem .dds-accordionitem__trigger {
38
+ color: var(--color-fg-on-brand-strong);
39
+ }
40
+
41
+ :where([data-dds-context="marketing"])
42
+ .dds-faqaccordion[data-ground="strong"]
43
+ .dds-accordionitem
44
+ .dds-accordionitem__trigger:hover:where(:not(:disabled)),
45
+ :where([data-dds-context="marketing"]) .dds-faqaccordion[data-ground="strong"] .dds-accordionitem .dds-accordionitem__marker {
46
+ color: var(--color-fg-muted-inverse);
47
+ }
48
+
49
+ :where([data-dds-context="marketing"])
50
+ .dds-faqaccordion[data-ground="strong"]
51
+ .dds-accordionitem
52
+ .dds-accordionitem__trigger:focus-visible {
53
+ outline-color: var(--color-border-focus-on-brand-strong);
54
+ }
@@ -0,0 +1,139 @@
1
+ /* GENERATED from featurebullets.contract.json. Do not edit. */
2
+
3
+ :where([data-dds-context="marketing"]) .dds-featurebullets {
4
+ box-sizing: border-box;
5
+ container-type: inline-size;
6
+ display: flex;
7
+ inline-size: 100%;
8
+ justify-content: center;
9
+ }
10
+
11
+ :where([data-dds-context="marketing"]) .dds-featurebullets .dds-featurebullets__inner {
12
+ box-sizing: border-box;
13
+ display: flex;
14
+ flex-direction: column;
15
+ inline-size: 100%;
16
+ min-inline-size: 0;
17
+ max-inline-size: var(--size-content-max);
18
+ padding-block: var(--space-section-default);
19
+ padding-inline: var(--space-inset-page);
20
+ }
21
+
22
+ :where([data-dds-context="marketing"]) .dds-featurebullets .dds-featurebullets__split {
23
+ align-items: stretch;
24
+ display: flex;
25
+ min-inline-size: 0;
26
+ column-gap: var(--space-gap-3xl);
27
+ row-gap: var(--space-gap-2xl);
28
+ }
29
+
30
+ :where([data-dds-context="marketing"]) .dds-featurebullets .dds-featurebullets__content {
31
+ display: flex;
32
+ flex-direction: column;
33
+ min-inline-size: 0;
34
+ row-gap: var(--space-gap-none);
35
+ }
36
+
37
+ :where([data-dds-context="marketing"]) .dds-featurebullets .dds-featurebullets__title {
38
+ margin-block: 0;
39
+ text-wrap: balance;
40
+ font-family: var(--font-h2-family);
41
+ font-size: var(--font-h2-size);
42
+ font-weight: var(--font-h2-weight);
43
+ letter-spacing: var(--font-h2-letter-spacing);
44
+ line-height: var(--font-h2-line-height);
45
+ margin-block-end: var(--space-heading-content);
46
+ }
47
+
48
+ :where([data-dds-context="marketing"]) .dds-featurebullets .dds-featurebullets__list {
49
+ display: flex;
50
+ flex-direction: column;
51
+ list-style: none;
52
+ margin-block: 0;
53
+ padding-inline-start: 0;
54
+ row-gap: var(--space-gap-none);
55
+ }
56
+
57
+ :where([data-dds-context="marketing"]) .dds-featurebullets .dds-featurebullets__item {
58
+ align-items: flex-start;
59
+ border-block-start-style: solid;
60
+ box-sizing: border-box;
61
+ display: flex;
62
+ border-width: var(--border-width-default);
63
+ column-gap: var(--space-gap-md);
64
+ padding-block: var(--space-inset-md);
65
+ }
66
+
67
+ :where([data-dds-context="marketing"]) .dds-featurebullets .dds-featurebullets__mark {
68
+ align-items: center;
69
+ display: flex;
70
+ flex: 0;
71
+ justify-content: center;
72
+ block-size: var(--icon-size-md);
73
+ inline-size: var(--icon-size-md);
74
+ }
75
+
76
+ :where([data-dds-context="marketing"]) .dds-featurebullets .dds-featurebullets__media {
77
+ min-inline-size: 0;
78
+ overflow: hidden;
79
+ position: relative;
80
+ aspect-ratio: var(--aspect-square);
81
+ border-radius: var(--radius-container);
82
+ }
83
+
84
+ :where([data-dds-context="marketing"]) .dds-featurebullets[data-media-position="end"] .dds-featurebullets__split {
85
+ flex-direction: row;
86
+ }
87
+
88
+ :where([data-dds-context="marketing"]) .dds-featurebullets[data-media-position="start"] .dds-featurebullets__split {
89
+ flex-direction: row-reverse;
90
+ }
91
+
92
+ :where([data-dds-context="marketing"]) .dds-featurebullets .dds-featurebullets__text {
93
+ font-family: var(--font-body-md-family);
94
+ font-size: var(--font-body-md-size);
95
+ font-weight: var(--font-body-md-weight);
96
+ letter-spacing: var(--font-body-md-letter-spacing);
97
+ line-height: var(--font-body-md-line-height);
98
+ }
99
+
100
+ :where([data-dds-context="marketing"]) .dds-featurebullets[data-ground="page"] {
101
+ background-color: var(--color-bg-page);
102
+ color: var(--color-fg-default);
103
+ }
104
+
105
+ :where([data-dds-context="marketing"]) .dds-featurebullets[data-ground="page"] .dds-featurebullets__item {
106
+ border-color: var(--color-border-subtle);
107
+ }
108
+
109
+ :where([data-dds-context="marketing"]) .dds-featurebullets[data-ground="page"] .dds-featurebullets__mark {
110
+ color: var(--color-fg-brand-accent);
111
+ }
112
+
113
+ :where([data-dds-context="marketing"]) .dds-featurebullets[data-ground="strong"] {
114
+ background-color: var(--color-bg-brand-strong);
115
+ color: var(--color-fg-on-brand-strong);
116
+ }
117
+
118
+ :where([data-dds-context="marketing"]) .dds-featurebullets[data-ground="strong"] .dds-featurebullets__item {
119
+ border-color: var(--color-border-subtle-inverse);
120
+ }
121
+
122
+ :where([data-dds-context="marketing"]) .dds-featurebullets[data-ground="strong"] .dds-featurebullets__mark {
123
+ color: var(--color-fg-on-brand-strong);
124
+ }
125
+
126
+ :where([data-dds-context="marketing"]) .dds-featurebullets[data-ground="subtle"] {
127
+ background-color: var(--color-bg-page);
128
+ background-image: linear-gradient(var(--color-bg-band-subtle), var(--color-bg-band-subtle));
129
+ color: var(--color-fg-default);
130
+ }
131
+
132
+ :where([data-dds-context="marketing"]) .dds-featurebullets[data-ground="subtle"] .dds-featurebullets__item {
133
+ border-color: var(--color-border-subtle);
134
+ }
135
+
136
+ :where([data-dds-context="marketing"]) .dds-featurebullets[data-ground="subtle"] .dds-featurebullets__mark {
137
+ color: var(--color-fg-brand);
138
+ }
139
+
@@ -0,0 +1,31 @@
1
+ import './FeatureBullets.css';
2
+ import './feature-bullets-impl.css';
3
+ import '../block-reveal.css';
4
+ import { type FeatureBulletsProps } from './FeatureBullets.types.js';
5
+ export type { FeatureBulletsProps };
6
+ /**
7
+ * A section pairing a claim and a ruled list of inclusions with one supporting picture.
8
+ *
9
+ * The list is the argument. Each line is one thing a reader gets, marked as included, and the
10
+ * column is meant to be counted rather than read — which is why the lines are strings rather than
11
+ * nodes. A line free to bring its own mark is a list that has stopped being one.
12
+ *
13
+ * The mark is the component's own and the only thing here the page does not supply. It is what
14
+ * separates a list of inclusions from a list: the same six strings with a bullet are a summary,
15
+ * with a check they are a promise. Drawn from the package's glyph set the way FooterGroup draws
16
+ * its chevron, and hidden from assistive technology — what it says is what the title says once,
17
+ * and announcing it per line is six repetitions of one fact.
18
+ *
19
+ * `<ul>` rather than a stack of divs, because a screen reader announces how many items there are
20
+ * before reading the first, and the count is most of what a reader takes from this section.
21
+ *
22
+ * Each row is ruled above rather than below. That is Accordion's arrangement and it is right for
23
+ * the same reason: every rule then belongs to a row and sits over it, so the lines fall between
24
+ * the rows and none is left hanging under the last one. The first row's is suppressed in the
25
+ * stylesheet, which is the one thing a binding cannot say.
26
+ *
27
+ * The title carries the section's accessible name through `aria-labelledby`. A `<section>` is only
28
+ * a region landmark once it has a name, and an unnamed one is a thing a screen reader user walks
29
+ * through rather than a place they can skip.
30
+ */
31
+ export declare function FeatureBullets({ ground, mediaPosition, title, bullets, media, }: FeatureBulletsProps): import("react").JSX.Element;
@@ -0,0 +1,55 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useId } from 'react';
4
+ import { CircleCheckSolidIcon } from '@deriv-com/quill-icons-web';
5
+ import './FeatureBullets.css';
6
+ import './feature-bullets-impl.css';
7
+ import '../block-reveal.css';
8
+ import { arriving, useReveal } from '../use-reveal.js';
9
+ import { featureBulletsDefaults, featureBulletsParts, } from './FeatureBullets.types.js';
10
+ /**
11
+ * A section pairing a claim and a ruled list of inclusions with one supporting picture.
12
+ *
13
+ * The list is the argument. Each line is one thing a reader gets, marked as included, and the
14
+ * column is meant to be counted rather than read — which is why the lines are strings rather than
15
+ * nodes. A line free to bring its own mark is a list that has stopped being one.
16
+ *
17
+ * The mark is the component's own and the only thing here the page does not supply. It is what
18
+ * separates a list of inclusions from a list: the same six strings with a bullet are a summary,
19
+ * with a check they are a promise. Drawn from the package's glyph set the way FooterGroup draws
20
+ * its chevron, and hidden from assistive technology — what it says is what the title says once,
21
+ * and announcing it per line is six repetitions of one fact.
22
+ *
23
+ * `<ul>` rather than a stack of divs, because a screen reader announces how many items there are
24
+ * before reading the first, and the count is most of what a reader takes from this section.
25
+ *
26
+ * Each row is ruled above rather than below. That is Accordion's arrangement and it is right for
27
+ * the same reason: every rule then belongs to a row and sits over it, so the lines fall between
28
+ * the rows and none is left hanging under the last one. The first row's is suppressed in the
29
+ * stylesheet, which is the one thing a binding cannot say.
30
+ *
31
+ * The title carries the section's accessible name through `aria-labelledby`. A `<section>` is only
32
+ * a region landmark once it has a name, and an unnamed one is a thing a screen reader user walks
33
+ * through rather than a place they can skip.
34
+ */
35
+ export function FeatureBullets({ ground = featureBulletsDefaults.ground, mediaPosition = featureBulletsDefaults.mediaPosition, title, bullets, media, }) {
36
+ const titleId = useId();
37
+ const [band, revealed] = useReveal();
38
+ return (_jsx("section", { className: featureBulletsParts.root, "data-ground": ground, "data-media-position": mediaPosition, "aria-labelledby": titleId, children: _jsx("div", { className: featureBulletsParts.inner, ref: band, "data-revealed": revealed, children: _jsxs("div", { className: featureBulletsParts.split, children: [_jsxs("div", { className: featureBulletsParts.content, children: [_jsx("h2", { className: featureBulletsParts.title, ...arriving(0), id: titleId, children: title }), _jsx("ul", { className: featureBulletsParts.list, children: bullets
39
+ .filter((bullet) => bullet.trim() !== '')
40
+ .map((bullet, at) => (
41
+ /* Keyed by the line itself. An index would key a list by position, so removing a
42
+ line above would renumber every row under it and React would reconcile the
43
+ wrong ones — and these lines are the content, so two the same would be a
44
+ duplicate claim rather than a key collision worth tolerating.
45
+
46
+ The position is still what decides when a row arrives, and that is a different
47
+ question with a different answer: the rows come up in the order they are read,
48
+ so the set counts itself down rather than landing all at once. Taken after the
49
+ blank lines are dropped, so a line somebody is still typing does not leave a
50
+ gap in the count.
51
+
52
+ Two behind the claim, which the picture beside them takes — the two halves of
53
+ the split arrive first and the list follows them. */
54
+ _jsxs("li", { className: featureBulletsParts.item, ...arriving(2 + at), children: [_jsx("span", { className: featureBulletsParts.mark, "aria-hidden": "true", children: _jsx(CircleCheckSolidIcon, {}) }), _jsx("span", { className: featureBulletsParts.text, children: bullet })] }, bullet))) })] }), _jsx("div", { className: featureBulletsParts.media, ...arriving(1), "aria-hidden": "true", children: media })] }) }) }));
55
+ }
@@ -0,0 +1,39 @@
1
+ import type { ReactNode } from 'react';
2
+ export interface FeatureBulletsOwnProps {
3
+ /**
4
+ * `page` — The default, and the page's own white. A section that has nothing to separate itself from what is above it — most of them — and the ground a reader is already on
5
+ * `subtle` — A quiet step off the page, for a band that wants to read as its own section without changing the page's voice. The one to reach for first when two sections need telling apart. Painted as the band's tint laid over the page's own ground, so it is the same grey whatever is behind the section — in dark mode the tint alone took on whatever it was set against, and on a light surface it was light ink on white.
6
+ * `strong` — `color.bg.brand-strong`, the dark band. It stops the page rather than dividing it, so it is for a section a reader should arrive at — and one per page is usually one more than enough
7
+ */
8
+ ground?: 'page' | 'subtle' | 'strong';
9
+ /**
10
+ * `end` — The default. The list is read first, which is the order the section argues in
11
+ * `start` — The second of two on a page, so the two do not read as one column with a picture stuck to one side
12
+ */
13
+ mediaPosition?: 'end' | 'start';
14
+ /** Always. What the list is a list of, in the fewest words that say it */
15
+ title: string;
16
+ /** Always. One line per thing included, each short enough to take in at a glance. Strings rather than nodes, because every line is marked the same way and a line free to bring its own mark is a list that stops being one */
17
+ bullets: string[];
18
+ /** Always. The picture that sits beside the list — a screenshot, a photograph, an illustration. The section is a split and the picture is one half of it: without one the list runs to a measure it was never sized for, and what is left is a heading over a column with a gap beside it. */
19
+ media: ReactNode;
20
+ }
21
+ export type FeatureBulletsProps = FeatureBulletsOwnProps;
22
+ /** The class each part carries. Apply these — do not retype them. */
23
+ export declare const featureBulletsParts: {
24
+ readonly root: "dds-featurebullets";
25
+ readonly inner: "dds-featurebullets__inner";
26
+ readonly split: "dds-featurebullets__split";
27
+ readonly content: "dds-featurebullets__content";
28
+ readonly title: "dds-featurebullets__title";
29
+ readonly list: "dds-featurebullets__list";
30
+ readonly item: "dds-featurebullets__item";
31
+ readonly mark: "dds-featurebullets__mark";
32
+ readonly text: "dds-featurebullets__text";
33
+ readonly media: "dds-featurebullets__media";
34
+ };
35
+ /** Generated so defaults cannot drift from the contract. */
36
+ export declare const featureBulletsDefaults: {
37
+ readonly ground: "page";
38
+ readonly mediaPosition: "end";
39
+ };
@@ -0,0 +1,16 @@
1
+ // GENERATED from feature-bullets.contract.json. Do not edit.
2
+ /** The class each part carries. Apply these — do not retype them. */
3
+ export const featureBulletsParts = {
4
+ root: 'dds-featurebullets',
5
+ inner: 'dds-featurebullets__inner',
6
+ split: 'dds-featurebullets__split',
7
+ content: 'dds-featurebullets__content',
8
+ title: 'dds-featurebullets__title',
9
+ list: 'dds-featurebullets__list',
10
+ item: 'dds-featurebullets__item',
11
+ mark: 'dds-featurebullets__mark',
12
+ text: 'dds-featurebullets__text',
13
+ media: 'dds-featurebullets__media',
14
+ };
15
+ /** Generated so defaults cannot drift from the contract. */
16
+ export const featureBulletsDefaults = { ground: 'page', mediaPosition: 'end' };
@@ -0,0 +1,104 @@
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 first row is not ruled off from what is above it, because nothing is.
10
+ *
11
+ * Every row carries a rule on its start edge, which is what puts a line between each pair and
12
+ * none under the last. The cost is one at the top of the set, where it reads as a lid rather
13
+ * than a separator — and the set is already bounded by the section's own step above it.
14
+ *
15
+ * `:first-child` is the condition itself. Nothing about a row knows it is first, and a prop
16
+ * standing in for the question would be the page answering something the DOM already has.
17
+ */
18
+ :where([data-dds-context="marketing"]) .dds-featurebullets .dds-featurebullets__item:first-child {
19
+ border-block-start-width: 0;
20
+ padding-block-start: 0;
21
+ }
22
+
23
+ /*
24
+ * The mark sits on the first line of the text, not in the middle of the row.
25
+ *
26
+ * `align-items: flex-start` puts it at the row's top edge, which is right for a line that wraps
27
+ * and a pixel high for one that does not: a 24px glyph beside a 24px line-height sits a touch
28
+ * proud, because the glyph is a full square and the letters inside the line are not. Nudging it
29
+ * by the difference is what makes the two look aligned rather than measure aligned.
30
+ *
31
+ * A raw length, and the one in this file. It is an optical correction — the amount by which a
32
+ * circle looks high next to a lowercase x — and there is no role for that because it is a
33
+ * property of these two shapes at this size rather than a decision the system makes.
34
+ */
35
+ :where([data-dds-context="marketing"]) .dds-featurebullets .dds-featurebullets__mark {
36
+ margin-block-start: 0.125rem;
37
+ }
38
+
39
+ /*
40
+ * One column below the fold, and the list leads it.
41
+ *
42
+ * The row direction is the contract's to say — it varies by a styling axis, which is what
43
+ * `structure[]` is for, and the generated sheet carries both values. What is left here is the
44
+ * fold, which a binding cannot express: `structure` has no width to attach a rule to.
45
+ *
46
+ * Written a class deeper than it looks so it wins. The generated rule is
47
+ * `.dds-featurebullets[data-media-position="end"] .dds-featurebullets__split` — a class, an
48
+ * attribute and a class — and a plainer selector here loses to it however late it is loaded.
49
+ * That is exactly what went wrong before this rule existed: the split stayed a column at every
50
+ * width, and a picture given `flex: 1 1 0` on the block axis collapsed to nothing.
51
+ *
52
+ * `48rem` longhand because `var()` is not permitted in a container query condition, and it is
53
+ * the width the rest of this package folds at.
54
+ */
55
+ @container (max-width: 47.9375rem) {
56
+ :where([data-dds-context="marketing"])
57
+ .dds-featurebullets[data-media-position]
58
+ .dds-featurebullets__split {
59
+ flex-direction: column;
60
+ }
61
+ }
62
+
63
+ /*
64
+ * At full width the list takes a measure and the picture takes the rest.
65
+ *
66
+ * The reference design writes 540px against its 1280, which is a number only right at one width.
67
+ * A share holds everywhere, and the picture growing into whatever is left is what keeps the
68
+ * square square without either half naming a height.
69
+ */
70
+ @container (min-width: 48rem) {
71
+ :where([data-dds-context="marketing"]) .dds-featurebullets .dds-featurebullets__split {
72
+ align-items: center;
73
+ }
74
+
75
+ :where([data-dds-context="marketing"]) .dds-featurebullets .dds-featurebullets__content {
76
+ flex: 0 0 45%;
77
+ }
78
+
79
+ :where([data-dds-context="marketing"]) .dds-featurebullets .dds-featurebullets__media {
80
+ flex: 1 1 0;
81
+ }
82
+ }
83
+
84
+ /*
85
+ * Whatever the page put in the picture fills the square.
86
+ *
87
+ * The slot takes a node rather than a source, so what arrives is the page's element and this
88
+ * cannot know whether it carries dimensions. `cover` rather than `contain`, because the slot is a
89
+ * square the section decided on and a picture letterboxed inside it would show the ground through
90
+ * a corner the section rounded.
91
+ */
92
+ :where([data-dds-context="marketing"]) .dds-featurebullets .dds-featurebullets__media > * {
93
+ block-size: 100%;
94
+ display: block;
95
+ inline-size: 100%;
96
+ object-fit: cover;
97
+ }
98
+
99
+ :where([data-dds-context="marketing"]) .dds-featurebullets .dds-featurebullets__media img {
100
+ block-size: 100%;
101
+ display: block;
102
+ inline-size: 100%;
103
+ object-fit: cover;
104
+ }
@@ -0,0 +1,84 @@
1
+ /* GENERATED from featurecards.contract.json. Do not edit. */
2
+
3
+ :where([data-dds-context="marketing"]) .dds-featurecards {
4
+ box-sizing: border-box;
5
+ container-type: inline-size;
6
+ display: flex;
7
+ inline-size: 100%;
8
+ justify-content: center;
9
+ }
10
+
11
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__inner {
12
+ box-sizing: border-box;
13
+ display: flex;
14
+ flex-direction: column;
15
+ inline-size: 100%;
16
+ min-inline-size: 0;
17
+ max-inline-size: var(--size-content-max);
18
+ padding-block: var(--space-section-default);
19
+ padding-inline: var(--space-inset-page);
20
+ row-gap: var(--space-heading-content);
21
+ }
22
+
23
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__header {
24
+ display: flex;
25
+ flex-direction: column;
26
+ min-inline-size: 0;
27
+ max-inline-size: var(--size-measure-heading);
28
+ row-gap: var(--space-gap-none);
29
+ }
30
+
31
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__title {
32
+ margin-block: 0;
33
+ text-wrap: balance;
34
+ font-family: var(--font-h2-family);
35
+ font-size: var(--font-h2-size);
36
+ font-weight: var(--font-h2-weight);
37
+ letter-spacing: var(--font-h2-letter-spacing);
38
+ line-height: var(--font-h2-line-height);
39
+ margin-block-end: var(--space-heading-title-description);
40
+ }
41
+
42
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__description {
43
+ margin-block: 0;
44
+ font-family: var(--font-body-md-family);
45
+ font-size: var(--font-body-md-size);
46
+ font-weight: var(--font-body-md-weight);
47
+ letter-spacing: var(--font-body-md-letter-spacing);
48
+ line-height: var(--font-body-md-line-height);
49
+ max-inline-size: var(--size-measure-description);
50
+ }
51
+
52
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__link {
53
+ display: flex;
54
+ margin-block-start: var(--space-heading-description-actions);
55
+ }
56
+
57
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__grid {
58
+ display: grid;
59
+ min-inline-size: 0;
60
+ column-gap: var(--space-grid-gutter);
61
+ row-gap: var(--space-grid-gutter);
62
+ }
63
+
64
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__item {
65
+ display: grid;
66
+ min-inline-size: 0;
67
+ }
68
+
69
+ :where([data-dds-context="marketing"]) .dds-featurecards[data-ground="page"] {
70
+ background-color: var(--color-bg-page);
71
+ color: var(--color-fg-default);
72
+ }
73
+
74
+ :where([data-dds-context="marketing"]) .dds-featurecards[data-ground="strong"] {
75
+ background-color: var(--color-bg-brand-strong);
76
+ color: var(--color-fg-on-brand-strong);
77
+ }
78
+
79
+ :where([data-dds-context="marketing"]) .dds-featurecards[data-ground="subtle"] {
80
+ background-color: var(--color-bg-page);
81
+ background-image: linear-gradient(var(--color-bg-band-subtle), var(--color-bg-band-subtle));
82
+ color: var(--color-fg-default);
83
+ }
84
+
@@ -0,0 +1,24 @@
1
+ import './FeatureCards.css';
2
+ import './feature-cards-impl.css';
3
+ import '../block-reveal.css';
4
+ import { type FeatureCardsProps } from './FeatureCards.types.js';
5
+ export type { FeatureCardsProps };
6
+ /**
7
+ * A heading over a grid of cards — the reference site's FeatureCards in its grid form.
8
+ *
9
+ * The cards are the page's own Card or CardButton, each holding a CardBody, rather than records
10
+ * this draws. A card already says everything a card can say — its fill, its picture, its mark,
11
+ * whether the whole of it is pressed — and a list of records here would be a second, smaller Card
12
+ * API to keep in step with the first. What this decides is the rest: the heading, the column, and
13
+ * how many cards share a row.
14
+ *
15
+ * The row is read from the cards. One column on a phone and two from the fold; at full width three,
16
+ * four when there are exactly four, and one or two held to two thirds of the row, centred. A card
17
+ * alone lays its words beside a portrait picture. The stylesheet asks all of it of the markup — the
18
+ * count is already there, and a prop restating it is a second place for the two to disagree.
19
+ *
20
+ * It arrives the way every block does: the heading, the line and the way on, then each card's cell
21
+ * a step behind the one before, in reading order. `'use client'` for that and for `useId`, which
22
+ * names the region by its heading.
23
+ */
24
+ export declare function FeatureCards({ ground, title, description, link, children, }: FeatureCardsProps): import("react").JSX.Element;
@@ -0,0 +1,66 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Children, Fragment, isValidElement, useId } from 'react';
4
+ import './FeatureCards.css';
5
+ import './feature-cards-impl.css';
6
+ import '../block-reveal.css';
7
+ import { given } from '../../given.js';
8
+ import { arriving, useReveal } from '../use-reveal.js';
9
+ import { featureCardsDefaults, featureCardsParts } from './FeatureCards.types.js';
10
+ /**
11
+ * The cards, with any fragment opened out.
12
+ *
13
+ * `Children.toArray` flattens arrays and leaves a fragment whole, so a page writing
14
+ * `<>{cards}</>` handed over one child: every card in a single cell, and the grid reading the set
15
+ * as one card alone. A fragment is the page grouping its own markup, never a card, so it is opened
16
+ * out here and the grid counts what is inside it.
17
+ */
18
+ function cardsOf(children, within = '') {
19
+ return Children.toArray(children).flatMap((child, at) => {
20
+ // `toArray` keys a fragment's children afresh — `.0`, `.1` — so a card is keyed by the
21
+ // fragment it came out of as well as its own place, or two cards from different groups share a
22
+ // key and React reconciles one into the other's cell.
23
+ const key = `${within}${isValidElement(child) && child.key !== null ? child.key : at}`;
24
+ return isValidElement(child) && child.type === Fragment
25
+ ? cardsOf(child.props.children, `${key}/`)
26
+ : [{ key, card: child }];
27
+ });
28
+ }
29
+ /**
30
+ * Where a card comes in the arrival, capped so a long set does not keep a reader waiting.
31
+ *
32
+ * The heading, the line and the way on take the first three steps. The cards follow one step
33
+ * apart up to the fourth, and the rest arrive with it: block-reveal.css keeps a block's trail
34
+ * inside its own movement, and eight cards a step apart would trail the heading by most of a
35
+ * second.
36
+ */
37
+ const FIRST_CARD = 3;
38
+ const LAST_STEP = FIRST_CARD + 3;
39
+ /**
40
+ * A heading over a grid of cards — the reference site's FeatureCards in its grid form.
41
+ *
42
+ * The cards are the page's own Card or CardButton, each holding a CardBody, rather than records
43
+ * this draws. A card already says everything a card can say — its fill, its picture, its mark,
44
+ * whether the whole of it is pressed — and a list of records here would be a second, smaller Card
45
+ * API to keep in step with the first. What this decides is the rest: the heading, the column, and
46
+ * how many cards share a row.
47
+ *
48
+ * The row is read from the cards. One column on a phone and two from the fold; at full width three,
49
+ * four when there are exactly four, and one or two held to two thirds of the row, centred. A card
50
+ * alone lays its words beside a portrait picture. The stylesheet asks all of it of the markup — the
51
+ * count is already there, and a prop restating it is a second place for the two to disagree.
52
+ *
53
+ * It arrives the way every block does: the heading, the line and the way on, then each card's cell
54
+ * a step behind the one before, in reading order. `'use client'` for that and for `useId`, which
55
+ * names the region by its heading.
56
+ */
57
+ export function FeatureCards({ ground = featureCardsDefaults.ground, title, description, link, children, }) {
58
+ const titleId = useId();
59
+ const [band, revealed] = useReveal();
60
+ return (_jsx("section", { className: featureCardsParts.root, "data-ground": ground, "aria-labelledby": titleId, children: _jsxs("div", { className: featureCardsParts.inner, ref: band, "data-revealed": revealed, children: [_jsxs("div", { className: featureCardsParts.header, children: [_jsx("h2", { className: featureCardsParts.title, id: titleId, ...arriving(0), children: title }), given(description) ? (_jsx("p", { className: featureCardsParts.description, ...arriving(1), children: description })) : null, link ? (_jsx("div", { className: featureCardsParts.link, ...arriving(2), children: link })) : null] }), _jsx("div", { className: featureCardsParts.grid, children: cardsOf(children).map(({ key, card }, at) => (
61
+ /* Each card in a cell of its own, and the cell is what arrives: the card is the page's
62
+ element and keeps its own transitions, which an arrival set on it would overwrite.
63
+ Keyed by the card's own key, made unique across fragments by cardsOf, so a set the
64
+ page reorders moves its cards rather than remounting them. */
65
+ _jsx("div", { className: featureCardsParts.item, ...arriving(Math.min(FIRST_CARD + at, LAST_STEP)), children: card }, key))) })] }) }));
66
+ }