@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,245 @@
|
|
|
1
|
+
/* GENERATED from testimonialrow.contract.json. Do not edit. */
|
|
2
|
+
|
|
3
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow {
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
container-type: inline-size;
|
|
6
|
+
display: flex;
|
|
7
|
+
inline-size: 100%;
|
|
8
|
+
justify-content: center;
|
|
9
|
+
overflow: clip;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__inner {
|
|
13
|
+
box-sizing: border-box;
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
inline-size: 100%;
|
|
17
|
+
min-inline-size: 0;
|
|
18
|
+
max-inline-size: var(--size-content-max);
|
|
19
|
+
padding-block: var(--space-section-default);
|
|
20
|
+
padding-inline: var(--space-inset-page);
|
|
21
|
+
row-gap: var(--space-heading-content);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__header {
|
|
25
|
+
display: flex;
|
|
26
|
+
flex-direction: column;
|
|
27
|
+
min-inline-size: 0;
|
|
28
|
+
max-inline-size: var(--size-measure-heading);
|
|
29
|
+
row-gap: var(--space-gap-none);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__title {
|
|
33
|
+
margin-block: 0;
|
|
34
|
+
text-wrap: balance;
|
|
35
|
+
font-family: var(--font-h2-family);
|
|
36
|
+
font-size: var(--font-h2-size);
|
|
37
|
+
font-weight: var(--font-h2-weight);
|
|
38
|
+
letter-spacing: var(--font-h2-letter-spacing);
|
|
39
|
+
line-height: var(--font-h2-line-height);
|
|
40
|
+
margin-block-end: var(--space-heading-title-description);
|
|
41
|
+
max-inline-size: var(--size-measure-heading);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__summary {
|
|
45
|
+
align-items: center;
|
|
46
|
+
display: flex;
|
|
47
|
+
flex-wrap: wrap;
|
|
48
|
+
justify-content: flex-start;
|
|
49
|
+
margin: 0;
|
|
50
|
+
column-gap: var(--space-gap-sm);
|
|
51
|
+
font-family: var(--font-body-md-family);
|
|
52
|
+
font-size: var(--font-body-md-size);
|
|
53
|
+
font-weight: var(--font-body-md-weight);
|
|
54
|
+
letter-spacing: var(--font-body-md-letter-spacing);
|
|
55
|
+
line-height: var(--font-body-md-line-height);
|
|
56
|
+
max-inline-size: var(--size-measure-description);
|
|
57
|
+
row-gap: var(--space-gap-xs);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__carousel {
|
|
61
|
+
display: flex;
|
|
62
|
+
flex-direction: column;
|
|
63
|
+
min-inline-size: 0;
|
|
64
|
+
row-gap: var(--space-gap-xl);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__track {
|
|
68
|
+
transition-property: outline-color, outline-width;
|
|
69
|
+
display: flex;
|
|
70
|
+
outline-style: solid;
|
|
71
|
+
column-gap: var(--space-grid-gutter);
|
|
72
|
+
outline-width: var(--border-width-none);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__review-link {
|
|
76
|
+
transition-property: outline-color, outline-width, translate;
|
|
77
|
+
box-sizing: border-box;
|
|
78
|
+
color: inherit;
|
|
79
|
+
display: flex;
|
|
80
|
+
outline-style: solid;
|
|
81
|
+
text-decoration: none;
|
|
82
|
+
transition-property: translate;
|
|
83
|
+
border-radius: var(--radius-container);
|
|
84
|
+
outline-width: var(--border-width-none);
|
|
85
|
+
transition-duration: var(--motion-duration-normal);
|
|
86
|
+
transition-timing-function: var(--motion-easing-standard);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__item {
|
|
90
|
+
align-items: flex-start;
|
|
91
|
+
box-sizing: border-box;
|
|
92
|
+
display: flex;
|
|
93
|
+
flex-direction: column;
|
|
94
|
+
margin: 0;
|
|
95
|
+
min-inline-size: 0;
|
|
96
|
+
position: relative;
|
|
97
|
+
border-radius: var(--radius-container);
|
|
98
|
+
min-block-size: var(--size-review-card-min);
|
|
99
|
+
padding-block: var(--space-inset-lg);
|
|
100
|
+
padding-inline: var(--space-inset-lg);
|
|
101
|
+
row-gap: var(--space-gap-md);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__rating {
|
|
105
|
+
display: inline-flex;
|
|
106
|
+
flex: none;
|
|
107
|
+
color: var(--color-fg-brand-accent);
|
|
108
|
+
column-gap: var(--space-gap-xs);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__star {
|
|
112
|
+
display: grid;
|
|
113
|
+
flex: none;
|
|
114
|
+
block-size: var(--icon-size-sm);
|
|
115
|
+
inline-size: var(--icon-size-sm);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__star-track {
|
|
119
|
+
display: block;
|
|
120
|
+
opacity: var(--opacity-track);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__star-fill {
|
|
124
|
+
display: block;
|
|
125
|
+
color: var(--color-fg-brand-accent);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__quote {
|
|
129
|
+
margin: 0;
|
|
130
|
+
font-family: var(--font-body-md-family);
|
|
131
|
+
font-size: var(--font-body-md-size);
|
|
132
|
+
font-weight: var(--font-body-md-weight);
|
|
133
|
+
letter-spacing: var(--font-body-md-letter-spacing);
|
|
134
|
+
line-height: var(--font-body-md-line-height);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__author {
|
|
138
|
+
align-items: center;
|
|
139
|
+
display: flex;
|
|
140
|
+
column-gap: var(--space-gap-md);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__name {
|
|
144
|
+
display: block;
|
|
145
|
+
font-family: var(--font-label-lg-family);
|
|
146
|
+
font-size: var(--font-label-lg-size);
|
|
147
|
+
font-weight: var(--font-label-lg-weight);
|
|
148
|
+
letter-spacing: var(--font-label-lg-letter-spacing);
|
|
149
|
+
line-height: var(--font-label-lg-line-height);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__detail {
|
|
153
|
+
display: block;
|
|
154
|
+
font-family: var(--font-body-md-family);
|
|
155
|
+
font-size: var(--font-body-md-size);
|
|
156
|
+
font-weight: var(--font-body-md-weight);
|
|
157
|
+
letter-spacing: var(--font-body-md-letter-spacing);
|
|
158
|
+
line-height: var(--font-body-md-line-height);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__footer {
|
|
162
|
+
align-items: center;
|
|
163
|
+
display: flex;
|
|
164
|
+
row-gap: var(--space-gap-lg);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__nav {
|
|
168
|
+
display: flex;
|
|
169
|
+
flex: none;
|
|
170
|
+
column-gap: var(--space-gap-md);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__nav-slot {
|
|
174
|
+
display: flex;
|
|
175
|
+
border-radius: var(--radius-pill);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__review-link:hover {
|
|
179
|
+
translate: var(--motion-translate-hover);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__review-link:focus-visible {
|
|
183
|
+
outline-color: var(--color-border-focus);
|
|
184
|
+
outline-width: var(--border-width-focus);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__track:focus-visible {
|
|
188
|
+
outline-color: var(--color-border-focus);
|
|
189
|
+
outline-width: var(--border-width-focus);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow[data-ground="page"] {
|
|
193
|
+
background-color: var(--color-bg-page);
|
|
194
|
+
color: var(--color-fg-default);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow[data-ground="page"] .dds-testimonialrow__detail {
|
|
198
|
+
color: var(--color-fg-muted);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow[data-ground="page"] .dds-testimonialrow__item {
|
|
202
|
+
background-color: var(--color-bg-surface);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow[data-ground="strong"] {
|
|
206
|
+
background-color: var(--color-bg-brand-strong);
|
|
207
|
+
color: var(--color-fg-on-brand-strong);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow[data-ground="strong"] .dds-testimonialrow__detail {
|
|
211
|
+
color: var(--color-fg-muted-inverse);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow[data-ground="strong"] .dds-testimonialrow__item {
|
|
215
|
+
background-color: var(--color-bg-surface-card-strong);
|
|
216
|
+
color: var(--color-fg-on-brand-strong);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow[data-ground="subtle"] {
|
|
220
|
+
background-color: var(--color-bg-page);
|
|
221
|
+
background-image: linear-gradient(var(--color-bg-band-subtle), var(--color-bg-band-subtle));
|
|
222
|
+
color: var(--color-fg-default);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow[data-ground="subtle"] .dds-testimonialrow__detail {
|
|
226
|
+
color: var(--color-fg-muted);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow[data-ground="subtle"] .dds-testimonialrow__item {
|
|
230
|
+
background-color: var(--color-bg-surface-card-raised);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow[data-ground="strong"] .dds-testimonialrow__review-link:focus-visible {
|
|
234
|
+
outline-color: var(--color-border-focus-on-brand-strong);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow[data-ground="strong"] .dds-testimonialrow__track:focus-visible {
|
|
238
|
+
outline-color: var(--color-border-focus-on-brand-strong);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
@media (prefers-reduced-motion: reduce) {
|
|
242
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow,
|
|
243
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow * { transition: none !important; }
|
|
244
|
+
}
|
|
245
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import "./TestimonialRow.css";
|
|
2
|
+
import "./testimonial-row-impl.css";
|
|
3
|
+
import "../block-reveal.css";
|
|
4
|
+
import { type TestimonialRowProps } from "./TestimonialRow.types.js";
|
|
5
|
+
export type { TestimonialRowProps };
|
|
6
|
+
/**
|
|
7
|
+
* A heading over a row of rated reviews, stepped through by the reader — the reference site's
|
|
8
|
+
* Testimonial in its review-row form, named for no review service.
|
|
9
|
+
*
|
|
10
|
+
* The browser does the scrolling and the snapping; this only reads where the row is, so each arrow
|
|
11
|
+
* is offered while it has somewhere to go. Read on scroll and on resize — a row that grows wide
|
|
12
|
+
* enough to hold every card has nowhere to go in either direction, and the arrows go with it.
|
|
13
|
+
*
|
|
14
|
+
* Nothing here moves on its own, which is the difference from TestimonialSlider: several cards are in
|
|
15
|
+
* view at once, so there is no "next" for a timer to bring.
|
|
16
|
+
*
|
|
17
|
+
* `'use client'` for the row's scroll position, the arrival, and `useId`, which names the region
|
|
18
|
+
* by its heading.
|
|
19
|
+
*/
|
|
20
|
+
export declare function TestimonialRow({ ground, title, reviews, summary, ratingLabel, label, previousLabel, nextLabel, }: TestimonialRowProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback, useEffect, useId, useRef, useState } from "react";
|
|
4
|
+
import { ChevronLeftRegularIcon, ChevronRightRegularIcon, StarSolidIcon } from "@deriv-com/quill-icons-web";
|
|
5
|
+
import "./TestimonialRow.css";
|
|
6
|
+
import "./testimonial-row-impl.css";
|
|
7
|
+
import "../block-reveal.css";
|
|
8
|
+
import { given } from "../../given.js";
|
|
9
|
+
import { ButtonIcon } from "../../core/button-icon/ButtonIcon.js";
|
|
10
|
+
import { Link } from "../../core/link/Link.js";
|
|
11
|
+
import { arriving, useReveal } from "../use-reveal.js";
|
|
12
|
+
import { testimonialRowDefaults, testimonialRowParts, } from "./TestimonialRow.types.js";
|
|
13
|
+
/**
|
|
14
|
+
* Five stars, filled to a score out of five.
|
|
15
|
+
*
|
|
16
|
+
* Halves and nothing finer: a quarter star is a sliver nobody reads as a quarter, so a score is
|
|
17
|
+
* rounded to the nearest half before it is drawn. Each star is an empty star with the filled one
|
|
18
|
+
* laid over it in the same cell; a half star's fill is clipped in the stylesheet, which knows the
|
|
19
|
+
* writing direction.
|
|
20
|
+
*
|
|
21
|
+
* One image — a score — rather than five pictures, named by its rating.
|
|
22
|
+
*/
|
|
23
|
+
/** A score as it is drawn: held to nought to five and rounded to the nearest half. */
|
|
24
|
+
const toHalves = (score) => Math.round(Math.min(5, Math.max(0, score)) * 2) / 2;
|
|
25
|
+
function Rating({ score, label }) {
|
|
26
|
+
const halves = toHalves(score);
|
|
27
|
+
return (_jsx("span", { className: testimonialRowParts.rating, role: "img", "aria-label": label, children: [0, 1, 2, 3, 4].map((at) => {
|
|
28
|
+
const fill = halves - at >= 1 ? "full" : halves - at > 0 ? "half" : "empty";
|
|
29
|
+
return (_jsxs("span", { className: testimonialRowParts.star, "data-fill": fill, children: [_jsx(StarSolidIcon, { className: testimonialRowParts["star-track"], "aria-hidden": "true" }), fill === "empty" ? null : (_jsx(StarSolidIcon, { className: testimonialRowParts["star-fill"], "aria-hidden": "true" }))] }, at));
|
|
30
|
+
}) }));
|
|
31
|
+
}
|
|
32
|
+
/** Close enough to an end to call it the end: a snapped row can rest a pixel short of it. */
|
|
33
|
+
const AT_END = 2;
|
|
34
|
+
/**
|
|
35
|
+
* A heading over a row of rated reviews, stepped through by the reader — the reference site's
|
|
36
|
+
* Testimonial in its review-row form, named for no review service.
|
|
37
|
+
*
|
|
38
|
+
* The browser does the scrolling and the snapping; this only reads where the row is, so each arrow
|
|
39
|
+
* is offered while it has somewhere to go. Read on scroll and on resize — a row that grows wide
|
|
40
|
+
* enough to hold every card has nowhere to go in either direction, and the arrows go with it.
|
|
41
|
+
*
|
|
42
|
+
* Nothing here moves on its own, which is the difference from TestimonialSlider: several cards are in
|
|
43
|
+
* view at once, so there is no "next" for a timer to bring.
|
|
44
|
+
*
|
|
45
|
+
* `'use client'` for the row's scroll position, the arrival, and `useId`, which names the region
|
|
46
|
+
* by its heading.
|
|
47
|
+
*/
|
|
48
|
+
export function TestimonialRow({ ground = testimonialRowDefaults.ground, title, reviews, summary, ratingLabel, label = testimonialRowDefaults.label, previousLabel = testimonialRowDefaults.previousLabel, nextLabel = testimonialRowDefaults.nextLabel, }) {
|
|
49
|
+
const titleId = useId();
|
|
50
|
+
const [band, revealed] = useReveal();
|
|
51
|
+
const row = useRef(null);
|
|
52
|
+
const back = useRef(null);
|
|
53
|
+
const on = useRef(null);
|
|
54
|
+
// Before the row is measured, the way a row opens: at its start, with somewhere to go.
|
|
55
|
+
const [ends, setEnds] = useState({ back: false, on: true });
|
|
56
|
+
// The same answer, read outside a render: the focus hand-off below has to compare against it,
|
|
57
|
+
// and a state updater is no place for a side effect — React may call one twice.
|
|
58
|
+
const was = useRef(ends);
|
|
59
|
+
const read = useCallback(() => {
|
|
60
|
+
const element = row.current;
|
|
61
|
+
if (element === null)
|
|
62
|
+
return;
|
|
63
|
+
// `abs`, because a right-to-left row counts its scroll position down from zero.
|
|
64
|
+
const at = Math.abs(element.scrollLeft);
|
|
65
|
+
const furthest = element.scrollWidth - element.clientWidth;
|
|
66
|
+
const next = { back: at > AT_END, on: at < furthest - AT_END };
|
|
67
|
+
const before = was.current;
|
|
68
|
+
if (before.back === next.back && before.on === next.on)
|
|
69
|
+
return;
|
|
70
|
+
// An arrow pressed to the end of the row is about to go inert with focus on it, which drops
|
|
71
|
+
// focus to the page. Hand it to the other arrow first, which has somewhere to go.
|
|
72
|
+
const focused = document.activeElement;
|
|
73
|
+
if (before.on && !next.on && on.current?.contains(focused))
|
|
74
|
+
back.current?.querySelector("button")?.focus();
|
|
75
|
+
if (before.back && !next.back && back.current?.contains(focused))
|
|
76
|
+
on.current?.querySelector("button")?.focus();
|
|
77
|
+
was.current = next;
|
|
78
|
+
setEnds(next);
|
|
79
|
+
}, []);
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
const element = row.current;
|
|
82
|
+
if (element === null)
|
|
83
|
+
return;
|
|
84
|
+
read();
|
|
85
|
+
// Asked defensively: a renderer with no ResizeObserver measures once, on mount.
|
|
86
|
+
if (typeof ResizeObserver === "undefined")
|
|
87
|
+
return;
|
|
88
|
+
const watching = new ResizeObserver(read);
|
|
89
|
+
watching.observe(element);
|
|
90
|
+
return () => watching.disconnect();
|
|
91
|
+
// The count too: a page that swaps the list at the same width leaves the row's own box the
|
|
92
|
+
// size it was, so nothing above would fire, and the arrows would describe the old set.
|
|
93
|
+
}, [read, reviews.length]);
|
|
94
|
+
// Nothing to show is nothing drawn: a named region with no review in it leads nowhere.
|
|
95
|
+
if (reviews.length === 0)
|
|
96
|
+
return null;
|
|
97
|
+
// One card and the gap after it, measured rather than assumed, so a step lands the next card
|
|
98
|
+
// where the first one stood at every width.
|
|
99
|
+
const step = (direction) => {
|
|
100
|
+
const element = row.current;
|
|
101
|
+
if (element === null)
|
|
102
|
+
return;
|
|
103
|
+
const style = getComputedStyle(element);
|
|
104
|
+
const card = element.firstElementChild;
|
|
105
|
+
const by = (card?.offsetWidth ?? element.clientWidth) + (Number.parseFloat(style.columnGap) || 0);
|
|
106
|
+
const still = typeof window.matchMedia === "function" &&
|
|
107
|
+
window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
108
|
+
element.scrollBy({
|
|
109
|
+
left: direction * by * (style.direction === "rtl" ? -1 : 1),
|
|
110
|
+
behavior: still ? "auto" : "smooth",
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
const scrolls = ends.back || ends.on;
|
|
114
|
+
// Button's secondary, as a circle; on the dark band its inverse tone turns the tint white.
|
|
115
|
+
const arrow = { variant: "secondary", tone: ground === "strong" ? "inverse" : "default" };
|
|
116
|
+
return (_jsx("section", { className: testimonialRowParts.root, "data-ground": ground, "aria-labelledby": titleId, children: _jsxs("div", { className: testimonialRowParts.inner, ref: band, "data-revealed": revealed, children: [_jsxs("div", { className: testimonialRowParts.header, children: [_jsx("h2", { className: testimonialRowParts.title, id: titleId, ...arriving(0), children: title }), summary === undefined ? null : (_jsx("p", { className: testimonialRowParts.summary, ...arriving(1), children: summary.href !== undefined && given(summary.href) ? (
|
|
117
|
+
// A link on its own line, so the standalone one: brand ink and a mark. On the dark
|
|
118
|
+
// band it takes the band's ink, where coral is the wrong colour for words.
|
|
119
|
+
_jsx(Link, { variant: "standalone", tone: ground === "strong" ? "inherit" : "brand", external: true, href: summary.href, children: summary.label })) : (_jsx("span", { children: summary.label })) }))] }), _jsxs("div", { className: testimonialRowParts.carousel, children: [_jsx("div", { ref: row, className: testimonialRowParts.track, role: "group", "aria-label": label, tabIndex: 0, onScroll: read, ...arriving(2), children: reviews.map((each, at) => {
|
|
120
|
+
// A review's position is its identity: the set is a list, and nothing reorders it.
|
|
121
|
+
const card = (_jsxs("figure", { className: testimonialRowParts.item, children: [each.rating === undefined ? null : (
|
|
122
|
+
// Named by the score it is drawn at, so a 4.3 is heard as the 4.5 a reader
|
|
123
|
+
// sees rather than as a number the stars do not show.
|
|
124
|
+
_jsx(Rating, { score: each.rating, label: ratingLabel?.(toHalves(each.rating)) ?? `Rated ${toHalves(each.rating)} out of 5` })), _jsx("blockquote", { className: testimonialRowParts.quote, children: each.quote }), _jsx("figcaption", { className: testimonialRowParts.author, children: _jsxs("span", { children: [_jsx("span", { className: testimonialRowParts.name, children: each.name }), given(each.detail) ? (_jsx("span", { className: testimonialRowParts.detail, children: each.detail })) : null] }) })] }, at));
|
|
125
|
+
// The review is on a service the page does not own, so it opens beside the page.
|
|
126
|
+
return given(each.href) ? (_jsx("a", { className: testimonialRowParts["review-link"], href: each.href, target: "_blank", rel: "noopener noreferrer", children: card }, at)) : (card);
|
|
127
|
+
}) }), reviews.length > 1 ? (_jsx("div", { className: testimonialRowParts.footer, ...arriving(3), children: _jsxs("div", { className: testimonialRowParts.nav, hidden: !scrolls, children: [_jsx("span", { ref: back, className: testimonialRowParts["nav-slot"], "data-available": ends.back, inert: !ends.back, children: _jsx(ButtonIcon, { icon: _jsx(ChevronLeftRegularIcon, {}), label: previousLabel, ...arrow, onClick: () => step(-1) }) }), _jsx("span", { ref: on, className: testimonialRowParts["nav-slot"], "data-available": ends.on, inert: !ends.on, children: _jsx(ButtonIcon, { icon: _jsx(ChevronRightRegularIcon, {}), label: nextLabel, ...arrow, onClick: () => step(1) }) })] }) })) : null] })] }) }));
|
|
128
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { TestimonialRowReview, TestimonialRowSummary } from '../../testimonial-row-data.js';
|
|
2
|
+
export interface TestimonialRowOwnProps {
|
|
3
|
+
/**
|
|
4
|
+
* `page` — The default, and the page's own white. The cards are the recessed gray that sets them off
|
|
5
|
+
* `subtle` — The grey band, the reference design's ground for this section. The cards turn white on it. 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, for a section a reader should arrive at. The heading, the summary and the cards' words turn white, and the cards take color.bg.surface-card-strong — gray.900 in both themes, the colour a page card takes in dark mode — so the band reads as a dark-mode section in either theme. The arrows take ButtonIcon's inverse tone
|
|
7
|
+
*/
|
|
8
|
+
ground?: 'page' | 'subtle' | 'strong';
|
|
9
|
+
/** Always. Whose reviews these are, in a few words — "What our customers say". */
|
|
10
|
+
title: string;
|
|
11
|
+
/** Always. The reviews, in the order they run along the row — five to ten of a sentence or two, each with the reviewer's name, its `rating` and, where there is one, the `href` of the review itself. An empty list draws nothing. */
|
|
12
|
+
reviews: TestimonialRowReview[];
|
|
13
|
+
/** The overall rating, in the page's own words under the heading — "Rated 4.5 out of 5 on our review site" — as a standalone Link to where the reviews were collected when it has an `href`. Words rather than stars: they name the service, they are translated with the page, and the score is stated once rather than drawn beside a sentence that already says it. */
|
|
14
|
+
summary?: TestimonialRowSummary;
|
|
15
|
+
/** The accessible name of a card's stars, given its rating as drawn — rounded to the nearest half, so what is heard is what is seen. The stars are drawn rather than written, so this is what a screen reader hears for them. Without it they are named "Rated 5 out of 5"; pass it to translate that with the page. */
|
|
16
|
+
ratingLabel?: (rating: number) => string;
|
|
17
|
+
/** The name the row is announced by. The row is a scrolling region a keyboard has to be able to reach, so it carries a tab stop and a name of its own — Scroller's rule. Its own name rather than the section's, so a screen reader moving into it hears what it is. Translate it with the page. */
|
|
18
|
+
label?: string;
|
|
19
|
+
/** The accessible name of the arrow stepping the row back. A glyph announces nothing, so this is the whole of the control's name. Translate it with the page, and keep it parallel to nextLabel. */
|
|
20
|
+
previousLabel?: string;
|
|
21
|
+
/** The accessible name of the arrow stepping the row on, for the reason previousLabel exists. */
|
|
22
|
+
nextLabel?: string;
|
|
23
|
+
}
|
|
24
|
+
export type TestimonialRowProps = TestimonialRowOwnProps;
|
|
25
|
+
/** The class each part carries. Apply these — do not retype them. */
|
|
26
|
+
export declare const testimonialRowParts: {
|
|
27
|
+
readonly root: "dds-testimonialrow";
|
|
28
|
+
readonly inner: "dds-testimonialrow__inner";
|
|
29
|
+
readonly header: "dds-testimonialrow__header";
|
|
30
|
+
readonly title: "dds-testimonialrow__title";
|
|
31
|
+
readonly summary: "dds-testimonialrow__summary";
|
|
32
|
+
readonly carousel: "dds-testimonialrow__carousel";
|
|
33
|
+
readonly track: "dds-testimonialrow__track";
|
|
34
|
+
readonly 'review-link': "dds-testimonialrow__review-link";
|
|
35
|
+
readonly item: "dds-testimonialrow__item";
|
|
36
|
+
readonly rating: "dds-testimonialrow__rating";
|
|
37
|
+
readonly star: "dds-testimonialrow__star";
|
|
38
|
+
readonly 'star-track': "dds-testimonialrow__star-track";
|
|
39
|
+
readonly 'star-fill': "dds-testimonialrow__star-fill";
|
|
40
|
+
readonly quote: "dds-testimonialrow__quote";
|
|
41
|
+
readonly author: "dds-testimonialrow__author";
|
|
42
|
+
readonly name: "dds-testimonialrow__name";
|
|
43
|
+
readonly detail: "dds-testimonialrow__detail";
|
|
44
|
+
readonly footer: "dds-testimonialrow__footer";
|
|
45
|
+
readonly nav: "dds-testimonialrow__nav";
|
|
46
|
+
readonly 'nav-slot': "dds-testimonialrow__nav-slot";
|
|
47
|
+
};
|
|
48
|
+
/** Generated so defaults cannot drift from the contract. */
|
|
49
|
+
export declare const testimonialRowDefaults: {
|
|
50
|
+
readonly ground: "page";
|
|
51
|
+
readonly label: "Reviews";
|
|
52
|
+
readonly previousLabel: "Previous reviews";
|
|
53
|
+
readonly nextLabel: "Next reviews";
|
|
54
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// GENERATED from testimonial-row.contract.json. Do not edit.
|
|
2
|
+
/** The class each part carries. Apply these — do not retype them. */
|
|
3
|
+
export const testimonialRowParts = {
|
|
4
|
+
root: 'dds-testimonialrow',
|
|
5
|
+
inner: 'dds-testimonialrow__inner',
|
|
6
|
+
header: 'dds-testimonialrow__header',
|
|
7
|
+
title: 'dds-testimonialrow__title',
|
|
8
|
+
summary: 'dds-testimonialrow__summary',
|
|
9
|
+
carousel: 'dds-testimonialrow__carousel',
|
|
10
|
+
track: 'dds-testimonialrow__track',
|
|
11
|
+
'review-link': 'dds-testimonialrow__review-link',
|
|
12
|
+
item: 'dds-testimonialrow__item',
|
|
13
|
+
rating: 'dds-testimonialrow__rating',
|
|
14
|
+
star: 'dds-testimonialrow__star',
|
|
15
|
+
'star-track': 'dds-testimonialrow__star-track',
|
|
16
|
+
'star-fill': 'dds-testimonialrow__star-fill',
|
|
17
|
+
quote: 'dds-testimonialrow__quote',
|
|
18
|
+
author: 'dds-testimonialrow__author',
|
|
19
|
+
name: 'dds-testimonialrow__name',
|
|
20
|
+
detail: 'dds-testimonialrow__detail',
|
|
21
|
+
footer: 'dds-testimonialrow__footer',
|
|
22
|
+
nav: 'dds-testimonialrow__nav',
|
|
23
|
+
'nav-slot': 'dds-testimonialrow__nav-slot',
|
|
24
|
+
};
|
|
25
|
+
/** Generated so defaults cannot drift from the contract. */
|
|
26
|
+
export const testimonialRowDefaults = { ground: 'page', label: 'Reviews', previousLabel: 'Previous reviews', nextLabel: 'Next reviews' };
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Scoped to this package, like the generated sheet beside it.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* A heading with no rating under it closes up. Its bound step is the distance to the rating, and
|
|
7
|
+
* with nothing there it would only add to the step from the header to the row. `:last-child` is
|
|
8
|
+
* the condition itself, LandingHero's way, rather than a prop standing in for it.
|
|
9
|
+
*/
|
|
10
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__title:last-child {
|
|
11
|
+
margin-block-end: 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
* The header — the heading and the rating under it — ranges to the start on a phone and is centred from the
|
|
16
|
+
* fold, FeatureCards' arrangement and its reason. Both are capped narrower than the column, so
|
|
17
|
+
* `margin-inline: auto` is what centres those boxes rather than their words inside a box left at the
|
|
18
|
+
* start edge.
|
|
19
|
+
*/
|
|
20
|
+
@container (min-width: 48rem) {
|
|
21
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__header {
|
|
22
|
+
align-items: center;
|
|
23
|
+
margin-inline: auto;
|
|
24
|
+
text-align: center;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__summary {
|
|
28
|
+
justify-content: center;
|
|
29
|
+
margin-inline: auto;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
/*
|
|
35
|
+
* Two measures the row is built from, both read off the band rather than the row.
|
|
36
|
+
*
|
|
37
|
+
* The root declares `container-type`, so `cqi` here is the band's width. `--column` is the width of
|
|
38
|
+
* the column the heading sits in — the inner's box, held to size.content.max, less its gutter on
|
|
39
|
+
* each side. `--bleed` is how far that column stands in from the band's edge: half of whatever the
|
|
40
|
+
* band has beyond the content measure, plus the gutter.
|
|
41
|
+
*/
|
|
42
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow {
|
|
43
|
+
--dds-testimonialrow-column: calc(min(100cqi, var(--size-content-max)) - 2 * var(--space-inset-page));
|
|
44
|
+
--dds-testimonialrow-bleed: calc((100cqi - min(100cqi, var(--size-content-max))) / 2 + var(--space-inset-page));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/*
|
|
48
|
+
* The row runs out to the band's edges and its first card stands where the heading does.
|
|
49
|
+
*
|
|
50
|
+
* A negative margin takes the row out of the column to the band's edges; a leading padding of the
|
|
51
|
+
* same measure brings the first card back into line with the heading. The padding is on the row
|
|
52
|
+
* that scrolls, so it scrolls away with the cards and a card is then cut off by the band rather
|
|
53
|
+
* than by the column — the reference design's breakout.
|
|
54
|
+
*
|
|
55
|
+
* `scroll-padding-inline` matches the padding, or a browser reads the resting position as short of
|
|
56
|
+
* the first card's snap point and scrolls the gutter away on load.
|
|
57
|
+
*
|
|
58
|
+
* The block padding is room for what happens outside a card's box — the lift on hover and the
|
|
59
|
+
* focus ring — which a scroll container would otherwise clip; the negative margin gives it back.
|
|
60
|
+
*
|
|
61
|
+
* No scrollbar. Scroller keeps its own, as the only standing sign a region moves; here the arrows
|
|
62
|
+
* under the row are that sign, and a bar between the cards and the arrows would be a second one.
|
|
63
|
+
*/
|
|
64
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__track {
|
|
65
|
+
display: flex;
|
|
66
|
+
margin-block: calc(-1 * var(--space-gap-sm));
|
|
67
|
+
margin-inline: calc(-1 * var(--dds-testimonialrow-bleed));
|
|
68
|
+
overflow-x: auto;
|
|
69
|
+
overflow-y: hidden;
|
|
70
|
+
overscroll-behavior-x: contain;
|
|
71
|
+
padding-block: var(--space-gap-sm);
|
|
72
|
+
padding-inline-start: var(--dds-testimonialrow-bleed);
|
|
73
|
+
scroll-padding-inline: var(--dds-testimonialrow-bleed);
|
|
74
|
+
scroll-snap-type: x proximity;
|
|
75
|
+
scrollbar-width: none;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__track::-webkit-scrollbar {
|
|
79
|
+
display: none;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/*
|
|
83
|
+
* The row's focus ring is drawn inside it. The row runs out to the band's edges and the band hides
|
|
84
|
+
* its overflow, so a ring drawn outside would lose its two sides to the band.
|
|
85
|
+
*/
|
|
86
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__track:focus-visible {
|
|
87
|
+
outline-offset: calc(-1 * var(--border-width-focus));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/*
|
|
91
|
+
* The trailing gutter, as a spacer rather than a padding.
|
|
92
|
+
*
|
|
93
|
+
* A scroll container leaves its end padding out of what it scrolls to once its content overflows,
|
|
94
|
+
* so the last card would come to rest against the band's edge. A generated box is a flex item like
|
|
95
|
+
* a card, and its width counts. The negative margin takes back the gap the row puts before it.
|
|
96
|
+
*/
|
|
97
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__track::after {
|
|
98
|
+
content: '';
|
|
99
|
+
flex: none;
|
|
100
|
+
inline-size: var(--dds-testimonialrow-bleed);
|
|
101
|
+
margin-inline-start: calc(-1 * var(--space-grid-gutter));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/*
|
|
105
|
+
* A card's share of the column: most of it on a phone, two and a half from the fold and three and
|
|
106
|
+
* a half from 64rem — so a card is always cut off at the edge, which is what says there is more.
|
|
107
|
+
*
|
|
108
|
+
* On the row's direct child, which is the card or the link around it. Either way it is what the row
|
|
109
|
+
* lays out, and it does not shrink: a flex item shrinks to fit before it overflows, and a row of
|
|
110
|
+
* squeezed cards is the one thing this is not.
|
|
111
|
+
*/
|
|
112
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__track > * {
|
|
113
|
+
flex: none;
|
|
114
|
+
inline-size: calc(var(--dds-testimonialrow-column) * 0.85);
|
|
115
|
+
scroll-snap-align: start;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
@container (min-width: 48rem) {
|
|
119
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__track > * {
|
|
120
|
+
inline-size: calc((var(--dds-testimonialrow-column) - 2 * var(--space-grid-gutter)) / 2.5);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
@container (min-width: 64rem) {
|
|
125
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__track > * {
|
|
126
|
+
inline-size: calc((var(--dds-testimonialrow-column) - 3 * var(--space-grid-gutter)) / 3.5);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* The card fills its link, and the words fill the card, so every name sits at the foot of a row
|
|
131
|
+
whose cards finish level. */
|
|
132
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__review-link > .dds-testimonialrow__item {
|
|
133
|
+
flex: 1 1 auto;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__quote {
|
|
137
|
+
flex: 1 1 auto;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* A lift is movement; a reader who asked for less gets the ring and the pointer and no travel. */
|
|
141
|
+
@media (prefers-reduced-motion: reduce) {
|
|
142
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__review-link:hover {
|
|
143
|
+
translate: none;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/*
|
|
148
|
+
* One star: the empty one and the fill in the same cell, each the size of the cell. The glyph ships
|
|
149
|
+
* width and height attributes, which only a CSS length on the element overrides.
|
|
150
|
+
*/
|
|
151
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__star-track,
|
|
152
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__star-fill {
|
|
153
|
+
block-size: 100%;
|
|
154
|
+
grid-area: 1 / 1;
|
|
155
|
+
inline-size: 100%;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/* A half star fills from the start edge, which is the right one in a right-to-left page. */
|
|
159
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__star[data-fill='half'] .dds-testimonialrow__star-fill {
|
|
160
|
+
clip-path: inset(0 50% 0 0);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__star[data-fill='half']:dir(rtl) .dds-testimonialrow__star-fill {
|
|
164
|
+
clip-path: inset(0 0 0 50%);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/*
|
|
168
|
+
* The arrows: ranged to the start on a phone, with the heading and the cards above them, and centred from
|
|
169
|
+
* the fold, with the heading, so the way through the row sits under the middle of it.
|
|
170
|
+
*/
|
|
171
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__footer {
|
|
172
|
+
align-items: flex-start;
|
|
173
|
+
flex-direction: column;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
@container (min-width: 48rem) {
|
|
177
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__footer {
|
|
178
|
+
align-items: center;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/* `hidden` has to win over the part's own `display`, which outranks the browser's rule for it. */
|
|
183
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__nav[hidden] {
|
|
184
|
+
display: none;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/*
|
|
188
|
+
* An arrow with nowhere to go stays in its place, receded to opacity.disabled — the measure every
|
|
189
|
+
* unavailable control in this package takes — so both directions show from the first render and the
|
|
190
|
+
* row reads as a carousel before it has moved. The slot is inert as well, so it cannot be pressed or
|
|
191
|
+
* focused. ButtonIcon has no disabled state of its own, which is why the slot carries it.
|
|
192
|
+
*/
|
|
193
|
+
:where([data-dds-context="marketing"]) .dds-testimonialrow .dds-testimonialrow__nav-slot[data-available='false'] {
|
|
194
|
+
opacity: var(--opacity-disabled);
|
|
195
|
+
}
|