@deriv-com/dds-marketing 0.2.0 → 1.0.1
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 +9 -1
- package/.llm/components/accordionitem.md +9 -1
- package/.llm/components/aspectratio.md +9 -1
- package/.llm/components/badge.md +9 -1
- package/.llm/components/bottomsheet.md +9 -1
- package/.llm/components/breadcrumb.md +9 -1
- package/.llm/components/breadcrumbitem.md +9 -1
- package/.llm/components/button.md +55 -27
- package/.llm/components/buttonicon.md +16 -8
- package/.llm/components/card.md +16 -2
- package/.llm/components/cardbody.md +29 -3
- package/.llm/components/cardbutton.md +16 -2
- package/.llm/components/checkbox.md +9 -1
- package/.llm/components/ctabanner.md +186 -0
- package/.llm/components/ctabannerslider.md +204 -0
- package/.llm/components/divider.md +9 -1
- package/.llm/components/dropdownmenu.md +15 -7
- 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 +9 -1
- package/.llm/components/footer.md +9 -1
- package/.llm/components/footergroup.md +9 -1
- package/.llm/components/grid.md +9 -1
- package/.llm/components/icon.md +21 -3
- package/.llm/components/landinghero.md +254 -0
- package/.llm/components/link.md +13 -5
- package/.llm/components/logocolumns.md +235 -0
- package/.llm/components/logorows.md +212 -0
- package/.llm/components/menuitem.md +9 -1
- package/.llm/components/navbar.md +80 -16
- package/.llm/components/navbaritem.md +10 -2
- package/.llm/components/navbarmenu.md +9 -1
- package/.llm/components/navbarmenugroup.md +9 -1
- package/.llm/components/navbarpanel.md +10 -2
- package/.llm/components/navbarswitcher.md +10 -2
- package/.llm/components/navbarswitcheroption.md +9 -1
- package/.llm/components/option.md +9 -1
- package/.llm/components/pageheader.md +231 -0
- package/.llm/components/pagination.md +27 -90
- package/.llm/components/paginationdots.md +215 -0
- package/.llm/components/producthero.md +248 -0
- package/.llm/components/removablechip.md +9 -1
- package/.llm/components/row.md +9 -1
- package/.llm/components/scroller.md +9 -1
- package/.llm/components/searchinput.md +9 -1
- package/.llm/components/segmentedcontrol.md +9 -1
- package/.llm/components/segmentedcontrolitem.md +9 -1
- package/.llm/components/select.md +9 -1
- package/.llm/components/selectchip.md +57 -16
- package/.llm/components/spinner.md +9 -1
- package/.llm/components/stack.md +9 -1
- package/.llm/components/statusdot.md +9 -1
- package/.llm/components/subdomainnavbar.md +9 -1
- package/.llm/components/tab.md +11 -3
- package/.llm/components/table.md +9 -1
- package/.llm/components/tablebody.md +9 -1
- package/.llm/components/tablecell.md +9 -1
- package/.llm/components/tablehead.md +9 -1
- package/.llm/components/tableheadercell.md +9 -1
- package/.llm/components/tablerow.md +9 -1
- package/.llm/components/tablist.md +9 -1
- package/.llm/components/testimonialrow.md +235 -0
- package/.llm/components/testimonialslider.md +254 -0
- package/.llm/components/textarea.md +9 -1
- package/.llm/components/textinput.md +9 -1
- package/.llm/components/tooltip.md +9 -1
- package/.llm/components/typography.md +9 -1
- 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 +43 -9
- package/.llm/tokens.md +56 -12
- package/AGENTS.md +32 -8
- 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/link/Link.js +5 -5
- 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/Tab.types.d.ts +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,176 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useRef, useState } from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* How soon after a swipe a click still belongs to it. The browser sends the click a swipe ends
|
|
5
|
+
* with straight after the release; anything later is a press of its own.
|
|
6
|
+
*/
|
|
7
|
+
const SWIPE_CLICK_MS = 300;
|
|
8
|
+
/** A token read off the block's own element, so it is the value the page actually resolved. */
|
|
9
|
+
function tokenOn(element, name) {
|
|
10
|
+
return element === null ? '' : getComputedStyle(element).getPropertyValue(name);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* One block rotating between a few things in place — which one is in view, and every way a reader
|
|
14
|
+
* moves it, holds it or stops it.
|
|
15
|
+
*
|
|
16
|
+
* Shared because two blocks rotate, CtaBannerSlider and TestimonialSlider, and a carousel is the
|
|
17
|
+
* kind of thing that drifts: one stops on a press and the other does not, one swallows the click a swipe
|
|
18
|
+
* ends in and the other follows the link. The rules are stated once here and each block spreads
|
|
19
|
+
* what this hands back onto its own parts.
|
|
20
|
+
*
|
|
21
|
+
* The clock is not here. PaginationDots holds the timer and the reduced-motion stillness, and this
|
|
22
|
+
* tells it when to wait — so there is one clock per block, and it is the one a reader can see.
|
|
23
|
+
*
|
|
24
|
+
* What it hands back:
|
|
25
|
+
* - `root`, the ref for the block's own element, which the swipe threshold and the reading
|
|
26
|
+
* direction are read off;
|
|
27
|
+
* - `region`, spread on that element: the carousel's role description and the hold and stop
|
|
28
|
+
* handlers;
|
|
29
|
+
* - `track`, spread on the element holding the items: the swipe and what is announced;
|
|
30
|
+
* - `item(at)`, spread on each item: its group role, its "2 / 3" name and its inert state;
|
|
31
|
+
* - `dots`, spread on PaginationDots alongside the block's own label.
|
|
32
|
+
*
|
|
33
|
+
* Fewer than two items is a set with nothing to move to, drawn still rather than broken: every
|
|
34
|
+
* attribute that says "carousel" is left off and the dots are the block's to omit.
|
|
35
|
+
*/
|
|
36
|
+
export function useRotation(count, autoplay) {
|
|
37
|
+
const rotating = count > 1;
|
|
38
|
+
const root = useRef(null);
|
|
39
|
+
const [index, setIndex] = useState(0);
|
|
40
|
+
/*
|
|
41
|
+
A pointer over the block or focus inside it, which holds the rotation only for as long as it
|
|
42
|
+
lasts. The rotation itself is PaginationDots' — the timer and the reduced-motion stillness — so
|
|
43
|
+
there is one clock, and this only tells it to wait while the reader is on the item.
|
|
44
|
+
*/
|
|
45
|
+
const [held, setHeld] = useState(false);
|
|
46
|
+
/*
|
|
47
|
+
Stopped for good once the reader presses anything in the block — an item, its action, a dot —
|
|
48
|
+
or swipes it. The WAI carousel pattern's rule: a reader who has touched the carousel is
|
|
49
|
+
reading it, and moving it on under them takes that back. It is also the way this offers a
|
|
50
|
+
stop without a control for one. A hold lets go; this does not.
|
|
51
|
+
*/
|
|
52
|
+
const [stopped, setStopped] = useState(false);
|
|
53
|
+
// A count that shrinks under the index would leave the track pointing past its end.
|
|
54
|
+
const current = count === 0 ? 0 : index % count;
|
|
55
|
+
const go = (to) => setIndex(((to % count) + count) % count);
|
|
56
|
+
// A move the reader made — a swipe — moves the set and stops it.
|
|
57
|
+
const step = (to) => {
|
|
58
|
+
setStopped(true);
|
|
59
|
+
go(to);
|
|
60
|
+
};
|
|
61
|
+
/*
|
|
62
|
+
A swipe is a pointer that travelled. How far counts as travelling is the smallest target the
|
|
63
|
+
package names, size.target.min: a move shorter than something a reader could aim at is a
|
|
64
|
+
press that wobbled, not a gesture.
|
|
65
|
+
*/
|
|
66
|
+
const from = useRef(null);
|
|
67
|
+
/*
|
|
68
|
+
When a gesture last travelled far enough to be a swipe, spent on the click the browser sends
|
|
69
|
+
after it. Without it a drag that starts and ends on an item's call to action both moves the set
|
|
70
|
+
and follows the link.
|
|
71
|
+
|
|
72
|
+
A time rather than a flag, because the click does not always come: a touch that travelled
|
|
73
|
+
usually ends with no click at all. A flag left standing then swallowed the next click that
|
|
74
|
+
arrived without a press on the track — Enter on the call to action, or a screen reader's
|
|
75
|
+
activation — and the link went nowhere. Only a click that follows the swipe closely is its own.
|
|
76
|
+
*/
|
|
77
|
+
const swipedAt = useRef(null);
|
|
78
|
+
const onPointerDown = (event) => {
|
|
79
|
+
// The primary pointer and, for a mouse, the primary button: a right-button drag or a second
|
|
80
|
+
// finger is not a swipe.
|
|
81
|
+
if (!event.isPrimary || (event.pointerType === 'mouse' && event.button !== 0))
|
|
82
|
+
return;
|
|
83
|
+
from.current = event.clientX;
|
|
84
|
+
swipedAt.current = null;
|
|
85
|
+
};
|
|
86
|
+
// The browser took the gesture — a vertical scroll, a system swipe — or the pointer left the
|
|
87
|
+
// track before it was let go, so there is no swipe to read. Left standing, the start of an
|
|
88
|
+
// abandoned drag would be measured against the next release on the track.
|
|
89
|
+
const onPointerCancel = () => {
|
|
90
|
+
from.current = null;
|
|
91
|
+
};
|
|
92
|
+
const onPointerUp = (event) => {
|
|
93
|
+
const start = from.current;
|
|
94
|
+
from.current = null;
|
|
95
|
+
if (start === null || !rotating || !event.isPrimary)
|
|
96
|
+
return;
|
|
97
|
+
const threshold = Number.parseFloat(tokenOn(root.current, '--size-target-min'));
|
|
98
|
+
const travel = event.clientX - start;
|
|
99
|
+
if (!Number.isFinite(threshold) || Math.abs(travel) < threshold)
|
|
100
|
+
return;
|
|
101
|
+
// Leftward travel brings the next item in from the end the reader is reading towards; in a
|
|
102
|
+
// right-to-left page that end is the left one, so the direction follows the page.
|
|
103
|
+
const rtl = root.current !== null && getComputedStyle(root.current).direction === 'rtl';
|
|
104
|
+
swipedAt.current = event.timeStamp;
|
|
105
|
+
step(current + ((travel < 0) !== rtl ? 1 : -1));
|
|
106
|
+
};
|
|
107
|
+
const onClickCapture = (event) => {
|
|
108
|
+
const at = swipedAt.current;
|
|
109
|
+
swipedAt.current = null;
|
|
110
|
+
if (at === null || event.timeStamp - at > SWIPE_CLICK_MS)
|
|
111
|
+
return;
|
|
112
|
+
event.preventDefault();
|
|
113
|
+
event.stopPropagation();
|
|
114
|
+
};
|
|
115
|
+
// Held while focus is anywhere inside, released only when it leaves the block altogether.
|
|
116
|
+
const onBlur = (event) => {
|
|
117
|
+
if (!event.currentTarget.contains(event.relatedTarget))
|
|
118
|
+
setHeld(false);
|
|
119
|
+
};
|
|
120
|
+
return {
|
|
121
|
+
current,
|
|
122
|
+
rotating,
|
|
123
|
+
root,
|
|
124
|
+
region: {
|
|
125
|
+
'aria-roledescription': rotating ? 'carousel' : undefined,
|
|
126
|
+
onPointerEnter: (event) => {
|
|
127
|
+
if (event.pointerType === 'mouse')
|
|
128
|
+
setHeld(true);
|
|
129
|
+
},
|
|
130
|
+
onPointerLeave: (event) => {
|
|
131
|
+
if (event.pointerType === 'mouse')
|
|
132
|
+
setHeld(false);
|
|
133
|
+
},
|
|
134
|
+
onFocus: () => setHeld(true),
|
|
135
|
+
// Any primary press in the block stops the rotation; the press itself still does what it does.
|
|
136
|
+
onPointerDownCapture: (event) => {
|
|
137
|
+
if (event.isPrimary && (event.pointerType !== 'mouse' || event.button === 0))
|
|
138
|
+
setStopped(true);
|
|
139
|
+
},
|
|
140
|
+
onBlur,
|
|
141
|
+
},
|
|
142
|
+
track: {
|
|
143
|
+
/*
|
|
144
|
+
An item that changes on its own is not announced — a reader would be talked over every few
|
|
145
|
+
seconds. One the reader moved to is, because they asked for it: whenever autoplay is off,
|
|
146
|
+
and whenever it is held — which it always is while focus is on a dot, the only way a
|
|
147
|
+
keyboard or screen reader user moves it.
|
|
148
|
+
*/
|
|
149
|
+
'aria-live': (rotating && (!autoplay || held || stopped) ? 'polite' : 'off'),
|
|
150
|
+
onPointerDown,
|
|
151
|
+
onPointerUp,
|
|
152
|
+
onPointerCancel,
|
|
153
|
+
onPointerLeave: onPointerCancel,
|
|
154
|
+
onClickCapture,
|
|
155
|
+
},
|
|
156
|
+
/** Whether an item is out of view: inert, hidden, and waiting rather than arrived. */
|
|
157
|
+
away: (at) => rotating && at !== current,
|
|
158
|
+
item: (at) => {
|
|
159
|
+
const away = rotating && at !== current;
|
|
160
|
+
return {
|
|
161
|
+
role: rotating ? 'group' : undefined,
|
|
162
|
+
'aria-roledescription': rotating ? 'slide' : undefined,
|
|
163
|
+
'aria-label': rotating ? `${at + 1} / ${count}` : undefined,
|
|
164
|
+
'aria-hidden': away || undefined,
|
|
165
|
+
inert: away || undefined,
|
|
166
|
+
};
|
|
167
|
+
},
|
|
168
|
+
dots: {
|
|
169
|
+
page: current + 1,
|
|
170
|
+
totalPages: count,
|
|
171
|
+
onPageChange: (page) => go(page - 1),
|
|
172
|
+
autoplay,
|
|
173
|
+
paused: held || stopped,
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
}
|
|
@@ -44,6 +44,11 @@
|
|
|
44
44
|
line-height: var(--font-label-md-line-height);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
:where([data-dds-context="marketing"]) .dds-accordionitem .dds-accordionitem__marker {
|
|
48
|
+
transition-property: rotate;
|
|
49
|
+
color: var(--color-fg-muted);
|
|
50
|
+
}
|
|
51
|
+
|
|
47
52
|
:where([data-dds-context="marketing"]) .dds-accordionitem .dds-accordionitem__panel {
|
|
48
53
|
overflow: hidden;
|
|
49
54
|
}
|
|
@@ -68,10 +73,6 @@
|
|
|
68
73
|
transition-timing-function: var(--motion-easing-enter);
|
|
69
74
|
}
|
|
70
75
|
|
|
71
|
-
:where([data-dds-context="marketing"]) .dds-accordionitem .dds-accordionitem__marker {
|
|
72
|
-
color: var(--color-fg-muted);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
76
|
:where([data-dds-context="marketing"]) .dds-accordionitem .dds-accordionitem__trigger:hover:where(:not(:disabled)) {
|
|
76
77
|
color: var(--color-fg-muted);
|
|
77
78
|
}
|
|
@@ -93,6 +94,6 @@
|
|
|
93
94
|
|
|
94
95
|
@media (prefers-reduced-motion: reduce) {
|
|
95
96
|
:where([data-dds-context="marketing"]) .dds-accordionitem,
|
|
96
|
-
:where([data-dds-context="marketing"]) .dds-accordionitem * { transition: none; }
|
|
97
|
+
:where([data-dds-context="marketing"]) .dds-accordionitem * { transition: none !important; }
|
|
97
98
|
}
|
|
98
99
|
|
|
@@ -173,6 +173,6 @@
|
|
|
173
173
|
|
|
174
174
|
@media (prefers-reduced-motion: reduce) {
|
|
175
175
|
:where([data-dds-context="marketing"]) .dds-bottomsheet,
|
|
176
|
-
:where([data-dds-context="marketing"]) .dds-bottomsheet * { transition: none; }
|
|
176
|
+
:where([data-dds-context="marketing"]) .dds-bottomsheet * { transition: none !important; }
|
|
177
177
|
}
|
|
178
178
|
|
|
@@ -10,8 +10,10 @@
|
|
|
10
10
|
cursor: pointer;
|
|
11
11
|
display: inline-flex;
|
|
12
12
|
flex-direction: row;
|
|
13
|
+
font-family: inherit;
|
|
13
14
|
justify-content: center;
|
|
14
15
|
outline-style: solid;
|
|
16
|
+
padding-block: 0;
|
|
15
17
|
position: relative;
|
|
16
18
|
text-decoration-line: none;
|
|
17
19
|
white-space: nowrap;
|
|
@@ -31,11 +33,6 @@
|
|
|
31
33
|
flex: none;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
:where([data-dds-context="marketing"]) .dds-button[data-variant="secondary"][data-tone="inherit"] {
|
|
35
|
-
border-color: currentcolor;
|
|
36
|
-
color: inherit;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
36
|
:where([data-dds-context="marketing"]) .dds-button:focus-visible {
|
|
40
37
|
outline-color: var(--color-border-focus);
|
|
41
38
|
outline-width: var(--border-width-focus);
|
|
@@ -102,26 +99,21 @@
|
|
|
102
99
|
|
|
103
100
|
:where([data-dds-context="marketing"]) .dds-button[data-variant="primary"] {
|
|
104
101
|
background-color: var(--color-bg-brand);
|
|
105
|
-
color: var(--color-fg-on-
|
|
102
|
+
color: var(--color-fg-on-brand);
|
|
106
103
|
}
|
|
107
104
|
|
|
108
105
|
:where([data-dds-context="marketing"]) .dds-button[data-variant="secondary"] {
|
|
109
|
-
border-color: var(--color-border-strong);
|
|
110
106
|
color: var(--color-fg-default);
|
|
111
107
|
}
|
|
112
108
|
|
|
113
|
-
:where([data-dds-context="marketing"]) .dds-button[data-variant="inverse"]:hover {
|
|
109
|
+
:where([data-dds-context="marketing"]) .dds-button[data-variant="inverse"]:hover:where(:not(:disabled)) {
|
|
114
110
|
background-image: linear-gradient(var(--color-bg-hover-inverse), var(--color-bg-hover-inverse));
|
|
115
111
|
}
|
|
116
112
|
|
|
117
|
-
:where([data-dds-context="marketing"]) .dds-button[data-variant="primary"]:hover {
|
|
113
|
+
:where([data-dds-context="marketing"]) .dds-button[data-variant="primary"]:hover:where(:not(:disabled)) {
|
|
118
114
|
background-color: var(--color-bg-brand-hover);
|
|
119
115
|
}
|
|
120
116
|
|
|
121
|
-
:where([data-dds-context="marketing"]) .dds-button[data-variant="secondary"]:hover {
|
|
122
|
-
background-color: var(--color-bg-hover);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
117
|
:where([data-dds-context="marketing"]) .dds-button[data-variant="inverse"]:active {
|
|
126
118
|
background-image: linear-gradient(var(--color-bg-active-inverse), var(--color-bg-active-inverse));
|
|
127
119
|
}
|
|
@@ -130,12 +122,67 @@
|
|
|
130
122
|
background-color: var(--color-bg-brand-active);
|
|
131
123
|
}
|
|
132
124
|
|
|
133
|
-
:where([data-dds-context="marketing"]) .dds-button[data-
|
|
134
|
-
|
|
125
|
+
:where([data-dds-context="marketing"]) .dds-button[data-tone="brand"]:focus-visible {
|
|
126
|
+
outline-color: var(--color-border-focus-on-brand-strong);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
:where([data-dds-context="marketing"]) .dds-button[data-tone="inverse"]:focus-visible {
|
|
130
|
+
outline-color: var(--color-border-focus-on-brand-strong);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
:where([data-dds-context="marketing"]) .dds-button[data-variant="inverse"][data-tone="brand"] {
|
|
134
|
+
background-color: var(--color-bg-strong-on-brand);
|
|
135
|
+
color: var(--color-fg-on-strong-on-brand);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
:where([data-dds-context="marketing"]) .dds-button[data-variant="secondary"][data-tone="brand"] {
|
|
139
|
+
background-color: var(--color-bg-subtle-on-brand-strong);
|
|
140
|
+
color: var(--color-fg-on-brand-strong);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
:where([data-dds-context="marketing"]) .dds-button[data-variant="secondary"][data-tone="default"] {
|
|
144
|
+
background-color: var(--color-bg-subtle);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
:where([data-dds-context="marketing"]) .dds-button[data-variant="secondary"][data-tone="inverse"] {
|
|
148
|
+
background-color: var(--color-bg-subtle-on-brand-strong);
|
|
149
|
+
color: var(--color-fg-on-brand-strong);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
:where([data-dds-context="marketing"]) .dds-button[data-variant="inverse"][data-tone="brand"]:hover:where(:not(:disabled)) {
|
|
153
|
+
background-image: linear-gradient(var(--color-bg-hover-on-brand-strong), var(--color-bg-hover-on-brand-strong));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
:where([data-dds-context="marketing"]) .dds-button[data-variant="secondary"][data-tone="brand"]:hover:where(:not(:disabled)) {
|
|
157
|
+
background-image: linear-gradient(var(--color-bg-hover-on-brand-strong), var(--color-bg-hover-on-brand-strong));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
:where([data-dds-context="marketing"]) .dds-button[data-variant="secondary"][data-tone="default"]:hover:where(:not(:disabled)) {
|
|
161
|
+
background-image: linear-gradient(var(--color-bg-hover), var(--color-bg-hover));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
:where([data-dds-context="marketing"]) .dds-button[data-variant="secondary"][data-tone="inverse"]:hover:where(:not(:disabled)) {
|
|
165
|
+
background-image: linear-gradient(var(--color-bg-hover-on-brand-strong), var(--color-bg-hover-on-brand-strong));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
:where([data-dds-context="marketing"]) .dds-button[data-variant="inverse"][data-tone="brand"]:active {
|
|
169
|
+
background-image: linear-gradient(var(--color-bg-active-on-brand-strong), var(--color-bg-active-on-brand-strong));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
:where([data-dds-context="marketing"]) .dds-button[data-variant="secondary"][data-tone="brand"]:active {
|
|
173
|
+
background-image: linear-gradient(var(--color-bg-active-on-brand-strong), var(--color-bg-active-on-brand-strong));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
:where([data-dds-context="marketing"]) .dds-button[data-variant="secondary"][data-tone="default"]:active {
|
|
177
|
+
background-image: linear-gradient(var(--color-bg-active), var(--color-bg-active));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
:where([data-dds-context="marketing"]) .dds-button[data-variant="secondary"][data-tone="inverse"]:active {
|
|
181
|
+
background-image: linear-gradient(var(--color-bg-active-on-brand-strong), var(--color-bg-active-on-brand-strong));
|
|
135
182
|
}
|
|
136
183
|
|
|
137
184
|
@media (prefers-reduced-motion: reduce) {
|
|
138
185
|
:where([data-dds-context="marketing"]) .dds-button,
|
|
139
|
-
:where([data-dds-context="marketing"]) .dds-button * { transition: none; }
|
|
186
|
+
:where([data-dds-context="marketing"]) .dds-button * { transition: none !important; }
|
|
140
187
|
}
|
|
141
188
|
|
|
@@ -8,18 +8,20 @@ export type { ButtonProps };
|
|
|
8
8
|
* generated from the same anatomy, and a class retyped slightly differently
|
|
9
9
|
* renders a part bare with its rule sitting unused.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* `href` is required in the generated type for the same reason — an anchor
|
|
17
|
-
* without one is not focusable and is announced as plain text, so the control
|
|
18
|
-
* simply disappears for anyone not using a mouse.
|
|
11
|
+
* Which element it renders is decided by `href` and nothing else, the shape CardButton
|
|
12
|
+
* and ButtonIcon already take. A CTA that goes to a page and one that sends a newsletter
|
|
13
|
+
* form are the same press with different destinations, and the element is what tells a
|
|
14
|
+
* browser which: an `<a>` gives cmd-click, a destination in the status bar and a copyable
|
|
15
|
+
* link, and a `<button>` answers Space and does what the page says.
|
|
19
16
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
17
|
+
* It is typed against `AnchorHTMLAttributes`, the branch a marketing CTA takes in the
|
|
18
|
+
* ordinary case, and that is what puts `target` and `rel` in reach. ButtonIcon records the
|
|
19
|
+
* same trade: the generator takes one interface, so the `<button>`'s own `form`, `name` and
|
|
20
|
+
* `value` are what it gives up, and `type` survives as a string so a submit still compiles.
|
|
21
|
+
*
|
|
22
|
+
* There is no `loading` and no `disabled`, unlike product's Button. Neither has an honest
|
|
23
|
+
* anchor form: the browser owns a link's pending state and shows it in the chrome, and
|
|
24
|
+
* `aria-disabled` on a link still follows the link when pressed. A prop that meant one
|
|
25
|
+
* thing on one branch and nothing on the other would be worse than its absence.
|
|
24
26
|
*/
|
|
25
27
|
export declare function Button({ variant, size, tone, href, showIcon, children, ...rest }: ButtonProps): import("react").JSX.Element;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { ArrowRightRegularIcon } from '@deriv-com/quill-icons-web';
|
|
3
3
|
import './Button.css';
|
|
4
4
|
import './button-impl.css';
|
|
@@ -9,20 +9,49 @@ import { buttonDefaults, buttonParts } from './Button.types.js';
|
|
|
9
9
|
* generated from the same anatomy, and a class retyped slightly differently
|
|
10
10
|
* renders a part bare with its rule sitting unused.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* `href` is required in the generated type for the same reason — an anchor
|
|
18
|
-
* without one is not focusable and is announced as plain text, so the control
|
|
19
|
-
* simply disappears for anyone not using a mouse.
|
|
12
|
+
* Which element it renders is decided by `href` and nothing else, the shape CardButton
|
|
13
|
+
* and ButtonIcon already take. A CTA that goes to a page and one that sends a newsletter
|
|
14
|
+
* form are the same press with different destinations, and the element is what tells a
|
|
15
|
+
* browser which: an `<a>` gives cmd-click, a destination in the status bar and a copyable
|
|
16
|
+
* link, and a `<button>` answers Space and does what the page says.
|
|
20
17
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
18
|
+
* It is typed against `AnchorHTMLAttributes`, the branch a marketing CTA takes in the
|
|
19
|
+
* ordinary case, and that is what puts `target` and `rel` in reach. ButtonIcon records the
|
|
20
|
+
* same trade: the generator takes one interface, so the `<button>`'s own `form`, `name` and
|
|
21
|
+
* `value` are what it gives up, and `type` survives as a string so a submit still compiles.
|
|
22
|
+
*
|
|
23
|
+
* There is no `loading` and no `disabled`, unlike product's Button. Neither has an honest
|
|
24
|
+
* anchor form: the browser owns a link's pending state and shows it in the chrome, and
|
|
25
|
+
* `aria-disabled` on a link still follows the link when pressed. A prop that meant one
|
|
26
|
+
* thing on one branch and nothing on the other would be worse than its absence.
|
|
25
27
|
*/
|
|
26
28
|
export function Button({ variant = buttonDefaults.variant, size = buttonDefaults.size, tone = buttonDefaults.tone, href, showIcon = buttonDefaults.showIcon, children, ...rest }) {
|
|
27
|
-
|
|
29
|
+
/*
|
|
30
|
+
What both branches carry. Spread after `rest` so none of it can be written over from
|
|
31
|
+
the call site: the class is how the generated stylesheet finds the root.
|
|
32
|
+
*/
|
|
33
|
+
const shared = {
|
|
34
|
+
className: buttonParts.root,
|
|
35
|
+
'data-variant': variant,
|
|
36
|
+
'data-tone': tone,
|
|
37
|
+
'data-size': size,
|
|
38
|
+
};
|
|
39
|
+
const content = (_jsxs(_Fragment, { children: [_jsx("span", { className: buttonParts.label, children: children }), showIcon ? (_jsx(ArrowRightRegularIcon, { className: buttonParts.icon, "aria-hidden": "true" })) : null] }));
|
|
40
|
+
if (href !== undefined) {
|
|
41
|
+
// No cast: `rest` is already the anchor's own attribute set, so `target` and `rel`
|
|
42
|
+
// arrive typed and land on the element that understands them.
|
|
43
|
+
return (_jsx("a", { ...rest, ...shared, href: href, children: content }));
|
|
44
|
+
}
|
|
45
|
+
return (
|
|
46
|
+
/*
|
|
47
|
+
A button, not a submit. The element's own default is `submit`, so a CTA dropped into
|
|
48
|
+
a newsletter form beside its real submit would send it. Above the spread rather than
|
|
49
|
+
below it, so a consumer who does want this to submit the form still wins — ButtonIcon
|
|
50
|
+
takes the same order for the same reason.
|
|
51
|
+
|
|
52
|
+
The cast is on this branch because the props are the anchor's: an `<a>`'s `type` is
|
|
53
|
+
the destination's MIME type and so is a plain string, which a `<button>`'s own `type`
|
|
54
|
+
will not accept. Runtime is unaffected.
|
|
55
|
+
*/
|
|
56
|
+
_jsx("button", { type: "button", ...rest, ...shared, children: content }));
|
|
28
57
|
}
|
|
@@ -1,30 +1,25 @@
|
|
|
1
1
|
import type { AnchorHTMLAttributes, ReactNode } from 'react';
|
|
2
2
|
export interface ButtonOwnProps {
|
|
3
|
-
/**
|
|
4
|
-
* `primary` — The step the page was built to produce. Carries the brand fill, which is what makes it findable at a glance and what makes it meaningless once there are two — a section offering two brand fills has said nothing about either.
|
|
5
|
-
* `secondary` — A real destination that is not the one being pushed — compare plans, read the docs, talk to sales. An outline rather than a quiet fill: this package has color.bg.hover for the wash but no hover partner for color.bg.subtle, so a filled secondary would get lighter on hover instead of darker. The outline keeps the shape, the inset and the target size, and gives up only the fill.
|
|
6
|
-
* `inverse` — A section that paints its own ground — a brand-coloured hero, a photo band, a dark takeover. There the brand fill is invisible against the fill behind it and a neutral edge is the wrong ink, so the only thing that reads is a solid at the far end of the neutral ramp: pure black in light, pure white in dark. It outranks everything near it, which is what makes it right there and wrong anywhere else.
|
|
7
|
-
*/
|
|
8
|
-
variant?: 'primary' | 'secondary' | 'inverse';
|
|
9
3
|
/**
|
|
10
4
|
* `sm` — A dense band where the button is one control among several — a filter row, a utility bar, an action beside body copy. size.control.sm tall against space.control.sm on the sides, half of it as at every step. The label holds at font.label.sm, md's own 14px: the label ramp has no step below it, so what separates these two is the box. Desktop only — at thirty-two it is below what a finger reliably hits.
|
|
11
5
|
* `md` — The default, and everything that is not a hero — navigation bars, pricing rows, feature sections, footer bands. size.control.md tall against space.control.md on the sides, which is half of it, and font.label.sm — the 14px step, so the label matches product's default button rather than running a size above it.
|
|
12
6
|
* `lg` — A hero, or a full-width conversion band that is the only control in view. size.control.lg tall against space.control.lg on the sides, again half the height, so the label starts where the pill's curve stops. font.label.md at 16px, product's own large-button measure. One per page, usually: a page of lg CTAs has no hero.
|
|
13
7
|
*/
|
|
14
8
|
size?: 'sm' | 'md' | 'lg';
|
|
15
|
-
/**
|
|
16
|
-
|
|
17
|
-
* `inherit` — A section that painted its own ground and set its own ink: a dark hero, a brand band, a photo. The button stops naming a colour and takes the one around it, so the edge and the label are whatever the band decided was legible on itself
|
|
18
|
-
*/
|
|
19
|
-
tone?: 'default' | 'inherit';
|
|
20
|
-
/** Always. The destination is the component — an anchor without an href is not a link, is not reachable by keyboard, and is announced as plain text, so there is no default that could stand in for one. It takes no default and is not optional for exactly that reason. */
|
|
21
|
-
href: string;
|
|
9
|
+
/** The press goes somewhere with a URL of its own — the ordinary case for a call to action on a marketing page. It makes this an anchor rather than a button, which is what gives a visitor cmd-click, a visible destination and a copyable link. `target` and `rel` are not props: the component is typed against AnchorHTMLAttributes, so they are already in reach and land on the anchor. */
|
|
10
|
+
href?: string;
|
|
22
11
|
/** Where the destination continues a sequence rather than being simply somewhere else to go — the hero CTA that starts a signup, the button at the foot of a step. Named for the part it renders rather than for the mark inside it: which glyph that is belongs to the component, the way showClose and showTitle name their parts elsewhere. Today it is a forward arrow, and it slides on hover. */
|
|
23
12
|
showIcon?: boolean;
|
|
24
13
|
/** Allowed: text */
|
|
25
14
|
children: ReactNode;
|
|
26
15
|
}
|
|
27
|
-
export type ButtonProps = ButtonOwnProps & Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'className' | 'variant' | 'size' | 'tone' | 'href' | 'showIcon'
|
|
16
|
+
export type ButtonProps = ButtonOwnProps & Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'className' | 'variant' | 'size' | 'tone' | 'href' | 'showIcon'> & ({
|
|
17
|
+
variant?: 'primary' | 'secondary' | 'inverse';
|
|
18
|
+
tone?: Exclude<'default' | 'inverse' | 'brand', 'brand'>;
|
|
19
|
+
} | {
|
|
20
|
+
variant: Exclude<'primary' | 'secondary' | 'inverse', 'primary'>;
|
|
21
|
+
tone?: 'default' | 'inverse' | 'brand';
|
|
22
|
+
});
|
|
28
23
|
/** The class each part carries. Apply these — do not retype them. */
|
|
29
24
|
export declare const buttonParts: {
|
|
30
25
|
readonly root: "dds-button";
|
|
@@ -44,3 +44,28 @@
|
|
|
44
44
|
translate: 0;
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The label travels with the fill.
|
|
50
|
+
*
|
|
51
|
+
* The generated list names what the button's own states move — the fills and the focus ring — and
|
|
52
|
+
* the label's colour is not one of them: no state changes it. The tone does. A navigation bar
|
|
53
|
+
* re-tones its buttons when it gathers on scroll, and the fill eased to the new ground while the
|
|
54
|
+
* label jumped to the new ink on the first frame, so a secondary on a dark hero spent the whole
|
|
55
|
+
* change as dark words on a still-dark fill. Naming `color` and `border-color` here carries both
|
|
56
|
+
* across the same step as the fill.
|
|
57
|
+
*
|
|
58
|
+
* Written out in full rather than appended to, because a property list cannot be added to — this
|
|
59
|
+
* replaces the generated one, and has to keep everything that one names.
|
|
60
|
+
*/
|
|
61
|
+
:where([data-dds-context="marketing"]) .dds-button {
|
|
62
|
+
transition-property: background-color, background-image, border-color, color, outline-color, outline-width;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* And none of it for a reader who asked for less motion — restated, because the rule above comes
|
|
66
|
+
after the generated sheet's own reduced-motion guard and would otherwise be the one that wins. */
|
|
67
|
+
@media (prefers-reduced-motion: reduce) {
|
|
68
|
+
:where([data-dds-context="marketing"]) .dds-button {
|
|
69
|
+
transition-property: none;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -72,11 +72,10 @@
|
|
|
72
72
|
|
|
73
73
|
:where([data-dds-context="marketing"]) .dds-buttonicon[data-variant="primary"] {
|
|
74
74
|
background-color: var(--color-bg-brand);
|
|
75
|
-
color: var(--color-fg-on-
|
|
75
|
+
color: var(--color-fg-on-brand);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
:where([data-dds-context="marketing"]) .dds-buttonicon[data-variant="secondary"] {
|
|
79
|
-
border-color: var(--color-border-strong);
|
|
80
79
|
color: var(--color-fg-default);
|
|
81
80
|
}
|
|
82
81
|
|
|
@@ -92,10 +91,6 @@
|
|
|
92
91
|
background-color: var(--color-bg-brand-hover);
|
|
93
92
|
}
|
|
94
93
|
|
|
95
|
-
:where([data-dds-context="marketing"]) .dds-buttonicon[data-variant="secondary"]:hover:where(:not(:disabled)) {
|
|
96
|
-
background-color: var(--color-bg-hover);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
94
|
:where([data-dds-context="marketing"]) .dds-buttonicon[data-variant="inverse"]:active {
|
|
100
95
|
background-image: linear-gradient(var(--color-bg-active-inverse), var(--color-bg-active-inverse));
|
|
101
96
|
}
|
|
@@ -108,28 +103,49 @@
|
|
|
108
103
|
background-color: var(--color-bg-brand-active);
|
|
109
104
|
}
|
|
110
105
|
|
|
111
|
-
:where([data-dds-context="marketing"]) .dds-buttonicon[data-variant="secondary"]:active {
|
|
112
|
-
background-color: var(--color-bg-active);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
106
|
:where([data-dds-context="marketing"]) .dds-buttonicon[data-tone="inverse"]:focus-visible {
|
|
116
|
-
outline-color: var(--color-border-focus-
|
|
107
|
+
outline-color: var(--color-border-focus-on-brand-strong);
|
|
117
108
|
}
|
|
118
109
|
|
|
119
110
|
:where([data-dds-context="marketing"]) .dds-buttonicon[data-variant="plain"][data-tone="inverse"] {
|
|
120
|
-
color: var(--color-fg-on-strong);
|
|
111
|
+
color: var(--color-fg-on-brand-strong);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
:where([data-dds-context="marketing"]) .dds-buttonicon[data-variant="secondary"][data-tone="default"] {
|
|
115
|
+
background-color: var(--color-bg-subtle);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
:where([data-dds-context="marketing"]) .dds-buttonicon[data-variant="secondary"][data-tone="inverse"] {
|
|
119
|
+
background-color: var(--color-bg-subtle-on-brand-strong);
|
|
120
|
+
color: var(--color-fg-on-brand-strong);
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
:where([data-dds-context="marketing"]) .dds-buttonicon[data-variant="plain"][data-tone="inverse"]:hover:where(:not(:disabled)) {
|
|
124
|
-
background-color: var(--color-bg-hover-
|
|
124
|
+
background-color: var(--color-bg-hover-on-brand-strong);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
:where([data-dds-context="marketing"]) .dds-buttonicon[data-variant="secondary"][data-tone="default"]:hover:where(:not(:disabled)) {
|
|
128
|
+
background-image: linear-gradient(var(--color-bg-hover), var(--color-bg-hover));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
:where([data-dds-context="marketing"]) .dds-buttonicon[data-variant="secondary"][data-tone="inverse"]:hover:where(:not(:disabled)) {
|
|
132
|
+
background-image: linear-gradient(var(--color-bg-hover-on-brand-strong), var(--color-bg-hover-on-brand-strong));
|
|
125
133
|
}
|
|
126
134
|
|
|
127
135
|
:where([data-dds-context="marketing"]) .dds-buttonicon[data-variant="plain"][data-tone="inverse"]:active {
|
|
128
|
-
background-color: var(--color-bg-active-
|
|
136
|
+
background-color: var(--color-bg-active-on-brand-strong);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
:where([data-dds-context="marketing"]) .dds-buttonicon[data-variant="secondary"][data-tone="default"]:active {
|
|
140
|
+
background-image: linear-gradient(var(--color-bg-active), var(--color-bg-active));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
:where([data-dds-context="marketing"]) .dds-buttonicon[data-variant="secondary"][data-tone="inverse"]:active {
|
|
144
|
+
background-image: linear-gradient(var(--color-bg-active-on-brand-strong), var(--color-bg-active-on-brand-strong));
|
|
129
145
|
}
|
|
130
146
|
|
|
131
147
|
@media (prefers-reduced-motion: reduce) {
|
|
132
148
|
:where([data-dds-context="marketing"]) .dds-buttonicon,
|
|
133
|
-
:where([data-dds-context="marketing"]) .dds-buttonicon * { transition: none; }
|
|
149
|
+
:where([data-dds-context="marketing"]) .dds-buttonicon * { transition: none !important; }
|
|
134
150
|
}
|
|
135
151
|
|
|
@@ -5,8 +5,8 @@ export type { ButtonIconProps };
|
|
|
5
5
|
* One press carried by a glyph alone.
|
|
6
6
|
*
|
|
7
7
|
* Which element it renders is decided by `href` and nothing else, which is CardButton's
|
|
8
|
-
* shape rather than Button's. Button
|
|
9
|
-
* visitor along a funnel, so it
|
|
8
|
+
* shape rather than Button's. Button has since taken the same shape; when this was written its job was
|
|
9
|
+
* defined as moving a visitor along a funnel, so it was an anchor always. A glyph-alone control has no such
|
|
10
10
|
* single job — a footer's social row goes somewhere and a promotional bar's dismiss does
|
|
11
11
|
* not, and both are one press with one mark. An `<a>` gives cmd-click, a destination in
|
|
12
12
|
* the status bar and a copyable link; a `<button>` answers Space and does what the page
|
|
@@ -6,8 +6,8 @@ import { buttonIconDefaults, buttonIconParts } from './ButtonIcon.types.js';
|
|
|
6
6
|
* One press carried by a glyph alone.
|
|
7
7
|
*
|
|
8
8
|
* Which element it renders is decided by `href` and nothing else, which is CardButton's
|
|
9
|
-
* shape rather than Button's. Button
|
|
10
|
-
* visitor along a funnel, so it
|
|
9
|
+
* shape rather than Button's. Button has since taken the same shape; when this was written its job was
|
|
10
|
+
* defined as moving a visitor along a funnel, so it was an anchor always. A glyph-alone control has no such
|
|
11
11
|
* single job — a footer's social row goes somewhere and a promotional bar's dismiss does
|
|
12
12
|
* not, and both are one press with one mark. An `<a>` gives cmd-click, a destination in
|
|
13
13
|
* the status bar and a copyable link; a `<button>` answers Space and does what the page
|