@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.
- package/.llm/components/accordion.md +8 -0
- package/.llm/components/accordionitem.md +8 -0
- package/.llm/components/aspectratio.md +8 -0
- package/.llm/components/badge.md +8 -0
- package/.llm/components/bottomsheet.md +8 -0
- package/.llm/components/breadcrumb.md +8 -0
- package/.llm/components/breadcrumbitem.md +8 -0
- package/.llm/components/button.md +46 -22
- package/.llm/components/buttonicon.md +14 -6
- package/.llm/components/card.md +15 -1
- package/.llm/components/cardbody.md +28 -2
- package/.llm/components/cardbutton.md +15 -1
- package/.llm/components/checkbox.md +8 -0
- package/.llm/components/ctabanner.md +186 -0
- package/.llm/components/ctabannerslider.md +204 -0
- package/.llm/components/divider.md +8 -0
- package/.llm/components/dropdownmenu.md +13 -5
- package/.llm/components/faqaccordion.md +217 -0
- package/.llm/components/featurebullets.md +254 -0
- package/.llm/components/featurecards.md +313 -0
- package/.llm/components/featurescroll.md +284 -0
- package/.llm/components/featuresplit.md +249 -0
- package/.llm/components/filterchip.md +8 -0
- package/.llm/components/footer.md +8 -0
- package/.llm/components/footergroup.md +8 -0
- package/.llm/components/grid.md +8 -0
- package/.llm/components/icon.md +8 -0
- package/.llm/components/landinghero.md +254 -0
- package/.llm/components/link.md +9 -1
- package/.llm/components/logocolumns.md +235 -0
- package/.llm/components/logorows.md +212 -0
- package/.llm/components/menuitem.md +8 -0
- package/.llm/components/navbar.md +79 -15
- package/.llm/components/navbaritem.md +9 -1
- package/.llm/components/navbarmenu.md +8 -0
- package/.llm/components/navbarmenugroup.md +8 -0
- package/.llm/components/navbarpanel.md +9 -1
- package/.llm/components/navbarswitcher.md +9 -1
- package/.llm/components/navbarswitcheroption.md +8 -0
- package/.llm/components/option.md +8 -0
- package/.llm/components/pageheader.md +231 -0
- package/.llm/components/pagination.md +26 -89
- package/.llm/components/paginationdots.md +215 -0
- package/.llm/components/producthero.md +248 -0
- package/.llm/components/removablechip.md +8 -0
- package/.llm/components/row.md +8 -0
- package/.llm/components/scroller.md +8 -0
- package/.llm/components/searchinput.md +8 -0
- package/.llm/components/segmentedcontrol.md +8 -0
- package/.llm/components/segmentedcontrolitem.md +8 -0
- package/.llm/components/select.md +8 -0
- package/.llm/components/selectchip.md +56 -15
- package/.llm/components/spinner.md +8 -0
- package/.llm/components/stack.md +8 -0
- package/.llm/components/statusdot.md +8 -0
- package/.llm/components/subdomainnavbar.md +8 -0
- package/.llm/components/tab.md +8 -0
- package/.llm/components/table.md +8 -0
- package/.llm/components/tablebody.md +8 -0
- package/.llm/components/tablecell.md +8 -0
- package/.llm/components/tablehead.md +8 -0
- package/.llm/components/tableheadercell.md +8 -0
- package/.llm/components/tablerow.md +8 -0
- package/.llm/components/tablist.md +8 -0
- package/.llm/components/testimonialrow.md +235 -0
- package/.llm/components/testimonialslider.md +254 -0
- package/.llm/components/textarea.md +8 -0
- package/.llm/components/textinput.md +8 -0
- package/.llm/components/tooltip.md +8 -0
- package/.llm/components/typography.md +8 -0
- package/.llm/digest/button.md +11 -6
- package/.llm/digest/buttonicon.md +2 -2
- package/.llm/digest/card.md +1 -0
- package/.llm/digest/cardbody.md +3 -1
- package/.llm/digest/cardbutton.md +1 -0
- package/.llm/digest/ctabanner.md +44 -0
- package/.llm/digest/ctabannerslider.md +45 -0
- package/.llm/digest/dropdownmenu.md +1 -1
- package/.llm/digest/faqaccordion.md +43 -0
- package/.llm/digest/featurebullets.md +52 -0
- package/.llm/digest/featurecards.md +49 -0
- package/.llm/digest/featurescroll.md +52 -0
- package/.llm/digest/featuresplit.md +54 -0
- package/.llm/digest/landinghero.md +53 -0
- package/.llm/digest/logocolumns.md +55 -0
- package/.llm/digest/logorows.md +48 -0
- package/.llm/digest/navbar.md +18 -3
- package/.llm/digest/pageheader.md +49 -0
- package/.llm/digest/pagination.md +6 -17
- package/.llm/digest/paginationdots.md +43 -0
- package/.llm/digest/producthero.md +53 -0
- package/.llm/digest/selectchip.md +6 -1
- package/.llm/digest/testimonialrow.md +51 -0
- package/.llm/digest/testimonialslider.md +51 -0
- package/.llm/index.md +24 -3
- package/.llm/rules.md +24 -0
- package/.llm/tokens.md +56 -12
- package/AGENTS.md +28 -3
- package/README.md +41 -21
- package/dist/components/banner-data.d.ts +38 -0
- package/dist/components/banner-data.js +15 -0
- package/dist/components/blocks/block-reveal.css +90 -0
- package/dist/components/blocks/cta-banner/CtaBanner.css +66 -0
- package/dist/components/blocks/cta-banner/CtaBanner.d.ts +22 -0
- package/dist/components/blocks/cta-banner/CtaBanner.js +31 -0
- package/dist/components/blocks/cta-banner/CtaBanner.types.d.ts +29 -0
- package/dist/components/blocks/cta-banner/CtaBanner.types.js +13 -0
- package/dist/components/blocks/cta-banner/cta-banner-impl.css +29 -0
- package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.css +90 -0
- package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.d.ts +39 -0
- package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.js +60 -0
- package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.types.d.ts +41 -0
- package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.types.js +15 -0
- package/dist/components/blocks/cta-banner-slider/cta-banner-slider-impl.css +73 -0
- package/dist/components/blocks/faq-accordion/FaqAccordion.css +54 -0
- package/dist/components/blocks/faq-accordion/FaqAccordion.d.ts +20 -0
- package/dist/components/blocks/faq-accordion/FaqAccordion.js +28 -0
- package/dist/components/blocks/faq-accordion/FaqAccordion.types.d.ts +25 -0
- package/dist/components/blocks/faq-accordion/FaqAccordion.types.js +10 -0
- package/dist/components/blocks/faq-accordion/faq-accordion-impl.css +54 -0
- package/dist/components/blocks/feature-bullets/FeatureBullets.css +139 -0
- package/dist/components/blocks/feature-bullets/FeatureBullets.d.ts +31 -0
- package/dist/components/blocks/feature-bullets/FeatureBullets.js +55 -0
- package/dist/components/blocks/feature-bullets/FeatureBullets.types.d.ts +39 -0
- package/dist/components/blocks/feature-bullets/FeatureBullets.types.js +16 -0
- package/dist/components/blocks/feature-bullets/feature-bullets-impl.css +104 -0
- package/dist/components/blocks/feature-cards/FeatureCards.css +84 -0
- package/dist/components/blocks/feature-cards/FeatureCards.d.ts +24 -0
- package/dist/components/blocks/feature-cards/FeatureCards.js +66 -0
- package/dist/components/blocks/feature-cards/FeatureCards.types.d.ts +33 -0
- package/dist/components/blocks/feature-cards/FeatureCards.types.js +14 -0
- package/dist/components/blocks/feature-cards/feature-cards-impl.css +245 -0
- package/dist/components/blocks/feature-scroll/FeatureScroll.css +137 -0
- package/dist/components/blocks/feature-scroll/FeatureScroll.d.ts +39 -0
- package/dist/components/blocks/feature-scroll/FeatureScroll.js +167 -0
- package/dist/components/blocks/feature-scroll/FeatureScroll.types.d.ts +40 -0
- package/dist/components/blocks/feature-scroll/FeatureScroll.types.js +17 -0
- package/dist/components/blocks/feature-scroll/feature-scroll-impl.css +292 -0
- package/dist/components/blocks/feature-split/FeatureSplit.css +95 -0
- package/dist/components/blocks/feature-split/FeatureSplit.d.ts +30 -0
- package/dist/components/blocks/feature-split/FeatureSplit.js +38 -0
- package/dist/components/blocks/feature-split/FeatureSplit.types.d.ts +39 -0
- package/dist/components/blocks/feature-split/FeatureSplit.types.js +14 -0
- package/dist/components/blocks/feature-split/feature-split-impl.css +83 -0
- package/dist/components/blocks/landing-hero/LandingHero.css +85 -0
- package/dist/components/blocks/landing-hero/LandingHero.d.ts +41 -0
- package/dist/components/blocks/landing-hero/LandingHero.js +54 -0
- package/dist/components/blocks/landing-hero/LandingHero.types.d.ts +37 -0
- package/dist/components/blocks/landing-hero/LandingHero.types.js +15 -0
- package/dist/components/blocks/landing-hero/landing-hero-impl.css +355 -0
- package/dist/components/blocks/logo-columns/LogoColumns.css +161 -0
- package/dist/components/blocks/logo-columns/LogoColumns.d.ts +23 -0
- package/dist/components/blocks/logo-columns/LogoColumns.js +46 -0
- package/dist/components/blocks/logo-columns/LogoColumns.types.d.ts +46 -0
- package/dist/components/blocks/logo-columns/LogoColumns.types.js +18 -0
- package/dist/components/blocks/logo-columns/logo-columns-impl.css +188 -0
- package/dist/components/blocks/logo-rows/LogoRows.css +122 -0
- package/dist/components/blocks/logo-rows/LogoRows.d.ts +20 -0
- package/dist/components/blocks/logo-rows/LogoRows.js +43 -0
- package/dist/components/blocks/logo-rows/LogoRows.types.d.ts +36 -0
- package/dist/components/blocks/logo-rows/LogoRows.types.js +16 -0
- package/dist/components/blocks/logo-rows/logo-rows-impl.css +179 -0
- package/dist/components/blocks/page-header/PageHeader.css +79 -0
- package/dist/components/blocks/page-header/PageHeader.d.ts +34 -0
- package/dist/components/blocks/page-header/PageHeader.js +43 -0
- package/dist/components/blocks/page-header/PageHeader.types.d.ts +32 -0
- package/dist/components/blocks/page-header/PageHeader.types.js +14 -0
- package/dist/components/blocks/page-header/page-header-impl.css +176 -0
- package/dist/components/blocks/product-hero/ProductHero.css +86 -0
- package/dist/components/blocks/product-hero/ProductHero.d.ts +35 -0
- package/dist/components/blocks/product-hero/ProductHero.js +48 -0
- package/dist/components/blocks/product-hero/ProductHero.types.d.ts +37 -0
- package/dist/components/blocks/product-hero/ProductHero.types.js +15 -0
- package/dist/components/blocks/product-hero/product-hero-impl.css +354 -0
- package/dist/components/blocks/testimonial-row/TestimonialRow.css +245 -0
- package/dist/components/blocks/testimonial-row/TestimonialRow.d.ts +20 -0
- package/dist/components/blocks/testimonial-row/TestimonialRow.js +128 -0
- package/dist/components/blocks/testimonial-row/TestimonialRow.types.d.ts +54 -0
- package/dist/components/blocks/testimonial-row/TestimonialRow.types.js +26 -0
- package/dist/components/blocks/testimonial-row/testimonial-row-impl.css +195 -0
- package/dist/components/blocks/testimonial-slider/TestimonialSlider.css +181 -0
- package/dist/components/blocks/testimonial-slider/TestimonialSlider.d.ts +22 -0
- package/dist/components/blocks/testimonial-slider/TestimonialSlider.js +36 -0
- package/dist/components/blocks/testimonial-slider/TestimonialSlider.types.d.ts +49 -0
- package/dist/components/blocks/testimonial-slider/TestimonialSlider.types.js +21 -0
- package/dist/components/blocks/testimonial-slider/testimonial-slider-impl.css +202 -0
- package/dist/components/blocks/use-reveal.d.ts +46 -0
- package/dist/components/blocks/use-reveal.js +120 -0
- package/dist/components/blocks/use-rotation.d.ts +62 -0
- package/dist/components/blocks/use-rotation.js +176 -0
- package/dist/components/core/accordion-item/AccordionItem.css +6 -5
- package/dist/components/core/bottom-sheet/BottomSheet.css +1 -1
- package/dist/components/core/button/Button.css +63 -16
- package/dist/components/core/button/Button.d.ts +14 -12
- package/dist/components/core/button/Button.js +43 -14
- package/dist/components/core/button/Button.types.d.ts +9 -14
- package/dist/components/core/button/button-impl.css +25 -0
- package/dist/components/core/button-icon/ButtonIcon.css +31 -15
- package/dist/components/core/button-icon/ButtonIcon.d.ts +2 -2
- package/dist/components/core/button-icon/ButtonIcon.js +2 -2
- package/dist/components/core/button-icon/ButtonIcon.types.d.ts +4 -4
- package/dist/components/core/card/Card.css +13 -4
- package/dist/components/core/card/Card.types.d.ts +2 -1
- package/dist/components/core/card-body/CardBody.css +11 -6
- package/dist/components/core/card-body/CardBody.d.ts +1 -1
- package/dist/components/core/card-body/CardBody.js +2 -2
- package/dist/components/core/card-body/CardBody.types.d.ts +4 -1
- package/dist/components/core/card-body/CardBody.types.js +1 -0
- package/dist/components/core/card-button/CardButton.css +13 -4
- package/dist/components/core/card-button/CardButton.types.d.ts +2 -1
- package/dist/components/core/checkbox/Checkbox.css +8 -1
- package/dist/components/core/dropdown-menu/DropdownMenu.css +13 -12
- package/dist/components/core/dropdown-menu/DropdownMenu.d.ts +5 -3
- package/dist/components/core/dropdown-menu/DropdownMenu.js +5 -3
- package/dist/components/core/filter-chip/FilterChip.css +2 -1
- package/dist/components/core/footer/footer-impl.css +1 -1
- package/dist/components/core/footer-group/FooterGroup.css +8 -7
- package/dist/components/core/icon/Icon.css +1 -1
- package/dist/components/core/link/Link.css +1 -1
- package/dist/components/core/menu-item/MenuItem.css +1 -1
- package/dist/components/core/navbar/Navbar.css +7 -8
- package/dist/components/core/navbar/Navbar.d.ts +17 -1
- package/dist/components/core/navbar/Navbar.js +139 -12
- package/dist/components/core/navbar/Navbar.types.d.ts +23 -4
- package/dist/components/core/navbar/Navbar.types.js +1 -1
- package/dist/components/core/navbar/navbar-impl.css +10 -3
- package/dist/components/core/navbar/navbar-material.css +96 -0
- package/dist/components/core/navbar-item/NavbarItem.css +4 -4
- package/dist/components/core/navbar-menu/NavbarMenu.css +7 -5
- package/dist/components/core/navbar-menu/NavbarMenu.d.ts +1 -0
- package/dist/components/core/navbar-menu/NavbarMenu.js +1 -0
- package/dist/components/core/navbar-menu/navbar-menu-impl.css +7 -7
- package/dist/components/core/navbar-switcher/NavbarSwitcher.css +6 -5
- package/dist/components/core/navbar-switcher/NavbarSwitcher.d.ts +1 -0
- package/dist/components/core/navbar-switcher/NavbarSwitcher.js +2 -1
- package/dist/components/core/option/Option.css +1 -1
- package/dist/components/core/pagination/Pagination.css +1 -75
- package/dist/components/core/pagination/Pagination.d.ts +4 -4
- package/dist/components/core/pagination/Pagination.js +11 -51
- package/dist/components/core/pagination/Pagination.types.d.ts +5 -17
- package/dist/components/core/pagination/Pagination.types.js +1 -3
- package/dist/components/core/pagination-dots/PaginationDots.css +60 -0
- package/dist/components/core/pagination-dots/PaginationDots.d.ts +25 -0
- package/dist/components/core/pagination-dots/PaginationDots.js +104 -0
- package/dist/components/core/pagination-dots/PaginationDots.types.d.ts +38 -0
- package/dist/components/core/pagination-dots/PaginationDots.types.js +9 -0
- package/dist/components/core/removable-chip/RemovableChip.css +3 -3
- package/dist/components/core/search-input/SearchInput.css +1 -1
- package/dist/components/core/segmented-control/SegmentedControl.css +1 -1
- package/dist/components/core/segmented-control-item/SegmentedControlItem.css +1 -1
- package/dist/components/core/select/Select.css +2 -1
- package/dist/components/core/select-chip/SelectChip.css +14 -7
- package/dist/components/core/select-chip/SelectChip.d.ts +1 -1
- package/dist/components/core/select-chip/SelectChip.js +7 -4
- package/dist/components/core/select-chip/SelectChip.types.d.ts +7 -1
- package/dist/components/core/select-chip/SelectChip.types.js +1 -1
- package/dist/components/core/select-chip/select-chip-impl.css +14 -3
- package/dist/components/core/status-dot/StatusDot.css +1 -1
- package/dist/components/core/subdomain-navbar/SubdomainNavbar.css +3 -3
- package/dist/components/core/tab/Tab.css +1 -1
- package/dist/components/core/tab-list/TabList.css +1 -1
- package/dist/components/core/table/table-impl.css +36 -14
- package/dist/components/core/table-header-cell/TableHeaderCell.css +5 -5
- package/dist/components/core/text-area/TextArea.css +1 -1
- package/dist/components/core/text-input/TextInput.css +1 -1
- package/dist/components/core/tooltip/Tooltip.css +1 -1
- package/dist/components/core/typography/Typography.css +5 -5
- package/dist/components/index.d.ts +35 -0
- package/dist/components/index.js +30 -0
- package/dist/components/logo-data.d.ts +24 -0
- package/dist/components/logo-data.js +11 -0
- package/dist/components/scroll-data.d.ts +64 -0
- package/dist/components/scroll-data.js +17 -0
- package/dist/components/testimonial-row-data.d.ts +51 -0
- package/dist/components/testimonial-row-data.js +11 -0
- package/dist/components/testimonial-slider-data.d.ts +26 -0
- package/dist/components/testimonial-slider-data.js +10 -0
- package/dist/marketing.css +385 -14
- 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
|
+
}
|