@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
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useLayoutEffect, Children, cloneElement, isValidElement, useCallback, useEffect, useRef, useState, } from 'react';
|
|
4
|
-
import { BarsRegularIcon, XmarkRegularIcon } from '@deriv-com/quill-icons-web';
|
|
3
|
+
import { useLayoutEffect, Children, Fragment, cloneElement, isValidElement, useCallback, useEffect, useRef, useState, } from 'react';
|
|
4
|
+
import { BarsRegularIcon, MoonRegularIcon, SunBrightRegularIcon, XmarkRegularIcon, } from '@deriv-com/quill-icons-web';
|
|
5
5
|
import './Navbar.css';
|
|
6
6
|
import './navbar-impl.css';
|
|
7
|
+
import './navbar-material.css';
|
|
8
|
+
import { Button } from '../button/Button.js';
|
|
9
|
+
import { buttonDefaults } from '../button/Button.types.js';
|
|
7
10
|
import { ButtonIcon } from '../button-icon/ButtonIcon.js';
|
|
8
11
|
import { milliseconds } from '../../css-time.js';
|
|
9
12
|
import { DropdownMenu } from '../dropdown-menu/DropdownMenu.js';
|
|
@@ -229,21 +232,110 @@ function useCollapse(element, collapsed, gapSide) {
|
|
|
229
232
|
/** The two of this package's own components a page is likely to put in a switcher slot. */
|
|
230
233
|
const TONED = [DropdownMenu, ButtonIcon, NavbarSwitcher];
|
|
231
234
|
/**
|
|
232
|
-
* The tone, pressed on a switcher the page passed in.
|
|
235
|
+
* The tone, pressed on a switcher or a secondary action the page passed in.
|
|
233
236
|
*
|
|
234
237
|
* A slot is the page's and this component does not dress what goes in one — that rule is why the
|
|
235
|
-
* mark
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
+
* mark is the page's to make legible. This is the exception, and it earns it: what the tone has to
|
|
239
|
+
* answer is the ground *this* component painted, and it changes on scroll, which no page can see
|
|
240
|
+
* without writing a second scroll listener against the bar it is already inside.
|
|
241
|
+
*
|
|
242
|
+
* A secondary Button is told too, and only a secondary one. Its `inverse` tone is a fill for a dark
|
|
243
|
+
* ground, and a page that set it for the hero left it white-on-white once the bar gathered into its
|
|
244
|
+
* pill. A primary is coral on either ground and carries its own, so it is left as it was handed.
|
|
245
|
+
*
|
|
246
|
+
* And every Button in the bar's action slots is drawn at `md`, whatever the page passed: the bar's
|
|
247
|
+
* items stand at size.control.md, and a button a step taller than the row it sits in pushes the
|
|
248
|
+
* bar taller with it. The collapsed panel's foot is not the bar, so it keeps the page's size.
|
|
238
249
|
*
|
|
239
250
|
* Matched by type rather than hoped for. Anything else the slot is handed goes through untouched,
|
|
240
251
|
* because pressing the prop on a component that does not declare it would put an unknown attribute
|
|
241
252
|
* on a DOM node, which React says out loud and a reader then has to go and disprove.
|
|
253
|
+
*
|
|
254
|
+
* Each of several, not only a lone one. The slot is for "a language picker, a theme toggle", and
|
|
255
|
+
* handed both as a list the second used to go through undressed — dark ink on a dark hero.
|
|
256
|
+
*/
|
|
257
|
+
function toned(children, dressing) {
|
|
258
|
+
// An empty slot stays empty rather than becoming `[]`, which every "is there anything here"
|
|
259
|
+
// check downstream — NavbarPanel's among them, and the bar's own — would read as something to
|
|
260
|
+
// draw a box for. `false` from a `{signedIn && <Button/>}` flattens to nothing, so it is empty too.
|
|
261
|
+
return children.length === 0 ? undefined : children.map((child) => dressed(child, dressing));
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* A slot's contents as one flat list, with every fragment opened.
|
|
265
|
+
*
|
|
266
|
+
* A page hands a pair of actions over as `<>…</>` and a list of switchers the same way, and
|
|
267
|
+
* `Children.map` does not look inside a fragment — so a fragment reached anything that matched on
|
|
268
|
+
* type, NavbarPanel's switcher-to-row swap included, as one opaque element. Opened here, once,
|
|
269
|
+
* each control is a child of its own wherever the slot is drawn.
|
|
270
|
+
*
|
|
271
|
+
* Every element comes out with a key unique across the whole list. `Children.toArray` keys each
|
|
272
|
+
* level from `.0` again, so the children of two fragments side by side would share keys and React
|
|
273
|
+
* could hand one control's state — an open switcher, say — to another. Each key is prefixed with
|
|
274
|
+
* the path of fragments it came through, the way React keys nested arrays itself.
|
|
275
|
+
*/
|
|
276
|
+
export function flattened(node, path = '') {
|
|
277
|
+
return Children.toArray(node).flatMap((child) => {
|
|
278
|
+
if (!isValidElement(child))
|
|
279
|
+
return [child];
|
|
280
|
+
const key = `${path}${String(child.key)}`;
|
|
281
|
+
if (child.type === Fragment)
|
|
282
|
+
return flattened(child.props.children, `${key}/`);
|
|
283
|
+
return [path === '' ? child : cloneElement(child, { key })];
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* The bar's actions are a pair, and a page that hands it more is told.
|
|
288
|
+
*
|
|
289
|
+
* At most two Buttons: one primary, and one secondary beside it — the conversion and the way back
|
|
290
|
+
* in. A lone Button is the primary. A third, or a second of either rank, is the bar asking the
|
|
291
|
+
* reader to choose between things it should have ranked; the `navbar-actions-are-a-pair` rule has
|
|
292
|
+
* the reasoning. Nothing checks a page's JSX yet, so this is where it is caught.
|
|
293
|
+
*
|
|
294
|
+
* Said, not refused. The bar still draws what it was handed — a page mid-build that lost its
|
|
295
|
+
* buttons would be worse than one with a third — and says so once for each shape of mistake, the
|
|
296
|
+
* way product's charts warn about a crowded palette.
|
|
297
|
+
*/
|
|
298
|
+
const warned = new Set();
|
|
299
|
+
function warnIfActionsAreNotAPair(utilities) {
|
|
300
|
+
const variants = utilities
|
|
301
|
+
.filter((child) => isValidElement(child) && child.type === Button)
|
|
302
|
+
.map((button) => button.props.variant ?? buttonDefaults.variant);
|
|
303
|
+
const problem = variants.length > 2
|
|
304
|
+
? `was handed ${variants.length} Buttons`
|
|
305
|
+
: variants.length === 1 && variants[0] !== 'primary'
|
|
306
|
+
? `was handed a single ${variants[0]} Button`
|
|
307
|
+
: variants.length === 2 && !(variants.includes('primary') && variants.includes('secondary'))
|
|
308
|
+
? `was handed two Buttons that are ${variants.join(' and ')}`
|
|
309
|
+
: undefined;
|
|
310
|
+
if (problem === undefined || warned.has(problem))
|
|
311
|
+
return;
|
|
312
|
+
warned.add(problem);
|
|
313
|
+
// eslint-disable-next-line no-console
|
|
314
|
+
console.warn(`Navbar ${problem} in utilities. The bar holds at most two: one primary, and one secondary ` +
|
|
315
|
+
'beside it — a lone Button is the primary. A third action belongs somewhere on the page, ' +
|
|
316
|
+
'not in the bar. See the navbar-actions-are-a-pair rule.');
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* One control, dressed for where it stands.
|
|
320
|
+
*
|
|
321
|
+
* Only what the dressing sets is written. `openOnHover` in particular is a page's to decide in a
|
|
322
|
+
* slot the bar has no view on, and cloning `{ openOnHover: undefined }` would reset it rather than
|
|
323
|
+
* leave it — an explicit `undefined` is an override to `cloneElement`, not an absence.
|
|
324
|
+
*
|
|
325
|
+
* A Button takes the bar's tone whatever its variant. On a secondary the tone is the fill; on the
|
|
326
|
+
* others it is only the focus ring, which has to follow the ground as much as any fill does — a
|
|
327
|
+
* primary keeping `inverse` from the hero would draw a white ring on the white pill.
|
|
242
328
|
*/
|
|
243
|
-
function
|
|
244
|
-
if (!isValidElement(node)
|
|
329
|
+
function dressed(node, { tone, openOnHover, size }) {
|
|
330
|
+
if (!isValidElement(node))
|
|
245
331
|
return node;
|
|
246
|
-
|
|
332
|
+
if (node.type === Button) {
|
|
333
|
+
return cloneElement(node, { tone, ...(size === undefined ? {} : { size }) });
|
|
334
|
+
}
|
|
335
|
+
if (!TONED.includes(node.type))
|
|
336
|
+
return node;
|
|
337
|
+
const hover = node.type === DropdownMenu && openOnHover !== undefined ? { openOnHover } : {};
|
|
338
|
+
return cloneElement(node, { tone, ...hover });
|
|
247
339
|
}
|
|
248
340
|
/**
|
|
249
341
|
* The bar across the top of a marketing page: the mark, the places the site has,
|
|
@@ -267,7 +359,33 @@ function toned(node, { tone, openOnHover }) {
|
|
|
267
359
|
* landmark, and writing it as well says so a second time in a way that goes stale
|
|
268
360
|
* if the element is ever nested.
|
|
269
361
|
*/
|
|
270
|
-
export function Navbar({ tone = navbarDefaults.tone, label, menuLabel, closeLabel, brand, utilities, compactAction, preferences, menuOpen, onMenuOpenChange, children, ...rest }) {
|
|
362
|
+
export function Navbar({ tone = navbarDefaults.tone, label, menuLabel, closeLabel, brand, utilities, compactAction, preferences, showThemeToggle = navbarDefaults.showThemeToggle, theme, onThemeChange, themeToggleLabel, menuOpen, onMenuOpenChange, children, ...rest }) {
|
|
363
|
+
/*
|
|
364
|
+
The theme toggle, drawn by the bar and placed after whatever the page put in preferences.
|
|
365
|
+
|
|
366
|
+
A ButtonIcon rather than a switcher: two themes are a toggle, not a choice among many, so a
|
|
367
|
+
menu listing both is a step nobody needs. `plain` so it is one of the pill's own items, and
|
|
368
|
+
`md` because that square is size.control.md — the height every item, menu and switcher in the
|
|
369
|
+
pill stands at, and the size the bar's buttons are. The glyph is the theme a press moves to; the name stays the theme it turns on
|
|
370
|
+
and aria-pressed carries the state, so a screen reader hears one name whichever way it is.
|
|
371
|
+
|
|
372
|
+
Joined to preferences as a list rather than drawn in a box of its own, so it takes the same
|
|
373
|
+
tone on the hero and in the pill, and the collapsed panel draws it at its foot beside the
|
|
374
|
+
rest — both come for free from how that slot is already handled.
|
|
375
|
+
*/
|
|
376
|
+
/*
|
|
377
|
+
Drawn only once it can be named. The pairing is enforced by the types, which a consumer
|
|
378
|
+
writing JavaScript never sees — and a glyph-only toggle with no label is a button a screen
|
|
379
|
+
reader announces with nothing after it. Absent is the honest failure; unnamed is not.
|
|
380
|
+
*/
|
|
381
|
+
const themeToggle = showThemeToggle && theme !== undefined && themeToggleLabel !== undefined && themeToggleLabel !== '' ? (_jsx(ButtonIcon, { variant: "plain", size: "md", label: themeToggleLabel, "aria-pressed": theme === 'dark', icon: theme === 'dark' ? _jsx(SunBrightRegularIcon, {}) : _jsx(MoonRegularIcon, {}), onClick: () => onThemeChange?.(theme === 'dark' ? 'light' : 'dark') }, "dds-navbar-theme-toggle")) : null;
|
|
382
|
+
/*
|
|
383
|
+
Each slot opened into one flat list, once per render — the warning, the bar and the panel all
|
|
384
|
+
read these rather than each walking the fragments again.
|
|
385
|
+
*/
|
|
386
|
+
const preferenceList = themeToggle === null ? flattened(preferences) : [...flattened(preferences), themeToggle];
|
|
387
|
+
const utilityList = flattened(utilities);
|
|
388
|
+
const compactList = flattened(compactAction);
|
|
271
389
|
const rootRef = useRef(null);
|
|
272
390
|
const condensed = useScrolled(rootRef);
|
|
273
391
|
const gathered = condensed ? 'true' : undefined;
|
|
@@ -287,6 +405,15 @@ export function Navbar({ tone = navbarDefaults.tone, label, menuLabel, closeLabe
|
|
|
287
405
|
One value, read by the attribute the stylesheet matches and by every child that is told a tone.
|
|
288
406
|
*/
|
|
289
407
|
const worn = condensed ? 'default' : tone;
|
|
408
|
+
/*
|
|
409
|
+
Each slot dressed once, for the ground it stands on. The utilities are drawn in two places —
|
|
410
|
+
inside the pill once it gathers, and at the trailing end before — and both show the same
|
|
411
|
+
element, so they share one dressing rather than keeping two in step by hand.
|
|
412
|
+
*/
|
|
413
|
+
const barSwitchers = toned(preferenceList, { tone: worn, openOnHover: true });
|
|
414
|
+
warnIfActionsAreNotAPair(utilityList);
|
|
415
|
+
const barUtilities = toned(utilityList, { tone: worn, size: 'md' });
|
|
416
|
+
const barCompact = toned(compactList, { tone: worn, size: 'md' });
|
|
290
417
|
const triggerRef = useRef(null);
|
|
291
418
|
/*
|
|
292
419
|
The pill's pair, which is the half of this that JavaScript has to do.
|
|
@@ -352,7 +479,7 @@ export function Navbar({ tone = navbarDefaults.tone, label, menuLabel, closeLabe
|
|
|
352
479
|
}),
|
|
353
480
|
});
|
|
354
481
|
});
|
|
355
|
-
return (_jsxs("header", { ...rest, ref: rootRef, className: navbarParts.root, "data-tone": worn, "data-condensed": gathered, "data-dds-pinned-surface": open ? 'open' : undefined, children: [_jsxs("div", { className: navbarParts.inner, "data-condensed": gathered, children: [_jsx("div", { className: navbarParts.ground, "data-condensed": gathered }), brand !== undefined && brand !== null && (_jsx("div", { className: navbarParts.brand, "data-condensed": gathered, children: brand })), _jsxs("div", { className: navbarParts.cluster, "data-condensed": gathered, children: [brand !== undefined && brand !== null && (_jsx("div", { ref: pillBrandRef, className: navbarParts.brand, children: brand })), _jsx("nav", { className: navbarParts.nav, "aria-label": label, children: governed }),
|
|
482
|
+
return (_jsxs("header", { ...rest, ref: rootRef, className: navbarParts.root, "data-tone": worn, "data-condensed": gathered, "data-dds-pinned-surface": open ? 'open' : undefined, children: [_jsxs("div", { className: navbarParts.inner, "data-condensed": gathered, children: [_jsx("div", { className: navbarParts.ground, "data-condensed": gathered }), brand !== undefined && brand !== null && (_jsx("div", { className: navbarParts.brand, "data-condensed": gathered, children: brand })), _jsxs("div", { className: navbarParts.cluster, "data-condensed": gathered, children: [brand !== undefined && brand !== null && (_jsx("div", { ref: pillBrandRef, className: navbarParts.brand, children: brand })), _jsx("nav", { className: navbarParts.nav, "aria-label": label, children: governed }), barSwitchers !== undefined && (_jsx("div", { className: navbarParts.preferences, children: barSwitchers })), barUtilities !== undefined && (_jsx("div", { ref: pillActionsRef, className: navbarParts.utilities, children: barUtilities }))] }), barUtilities !== undefined && (_jsx("div", { className: navbarParts.utilities, "data-condensed": gathered, children: barUtilities })), barCompact !== undefined && (_jsx("div", { className: navbarParts['compact-action'], children: barCompact })), _jsx("button", { ref: triggerRef, type: "button", className: navbarParts.trigger, "aria-label": menuLabel, "aria-expanded": open, onClick: () => setOpen(!open), children: _jsx(Icon, { size: "md", children: open ? _jsx(XmarkRegularIcon, {}) : _jsx(BarsRegularIcon, {}) }) })] }), open && (_jsx("div", { className: navbarParts['panel-host'], children: _jsx(NavbarPanel, { label: label, closeLabel: closeLabel, onClose: close, brand: brand,
|
|
356
483
|
/*
|
|
357
484
|
Both, because the pill they were drawn in is not drawn at this width and
|
|
358
485
|
the foot is where everything that was in the bar has gone. What a reader
|
|
@@ -367,5 +494,5 @@ export function Navbar({ tone = navbarDefaults.tone, label, menuLabel, closeLabe
|
|
|
367
494
|
And not told to open on hover: in a panel a switcher is a row read down with a
|
|
368
495
|
finger, and the panel is the thing that turns it into one.
|
|
369
496
|
*/
|
|
370
|
-
preferences: toned(
|
|
497
|
+
preferences: toned(preferenceList, { tone: 'default', openOnHover: false }), footer: toned(utilityList, { tone: 'default' }), openerRef: triggerRef, children: children }) }))] }));
|
|
371
498
|
}
|
|
@@ -2,7 +2,7 @@ import type { HTMLAttributes, ReactNode } from 'react';
|
|
|
2
2
|
export interface NavbarOwnProps {
|
|
3
3
|
/**
|
|
4
4
|
* `default` — The page begins on a light ground, which is most marketing pages. The bar paints in ink and the pill is paper
|
|
5
|
-
* `inverse` — The first section of the page paints its own dark ground and the bar stands on it — a dark hero, a photograph, a brand-coloured takeover. The bar's ink runs light, the pill
|
|
5
|
+
* `inverse` — The first section of the page paints its own dark ground and the bar stands on it — a dark hero, a photograph, a brand-coloured takeover. The bar's ink runs light, and the pill and the collapsed bar take the dark see-through material — a near-opaque black base, a white tint and a blur — so a light photograph behind cannot wash them out
|
|
6
6
|
*/
|
|
7
7
|
tone?: 'default' | 'inverse';
|
|
8
8
|
/** Always — it names the navigation landmark, and a page with an unnamed one tells a screen-reader user there is navigation here without saying which navigation. Name the set rather than the act: 'Main', not 'Main navigation' — the role already supplies the word, and a name carrying it is announced as 'main navigation navigation' */
|
|
@@ -13,9 +13,9 @@ export interface NavbarOwnProps {
|
|
|
13
13
|
closeLabel: string;
|
|
14
14
|
/** Effectively always on a real site — the mark, and usually an anchor to the home page wrapped around it. It is drawn twice: in the bar, and again in the panel's header, where it is the only thing left saying whose site this is */
|
|
15
15
|
brand?: ReactNode;
|
|
16
|
-
/** The bar's trailing end has
|
|
16
|
+
/** The bar's trailing end has the site's actions in it: one Button, which is primary, or two — one primary and one secondary, the conversion beside the way back in. A switcher is a DropdownMenu with the current choice on its trigger, which is what DropdownMenu's own guidance describes and why it is accepted here alongside the two controls. They are drawn in the row at wide widths and across the foot of the panel once it collapses. The bar dresses what it is handed: every Button here is drawn at md and takes the tone of the ground the bar is on at that scroll position — inverse on the hero, default once the pill gathers — and a ButtonIcon or a DropdownMenu takes the tone too. That reaches the controls handed in directly, or in a fragment; a control inside a component of the page's own is past it, so a wrapper takes tone and size as props and passes them down */
|
|
17
17
|
utilities?: ReactNode;
|
|
18
|
-
/** The one thing a reader should still be able to do once the bar has collapsed and everything else has gone into the panel — a sign-up, usually. Drawn beside the control that opens the panel, and only at the widths where that control is drawn */
|
|
18
|
+
/** The one thing a reader should still be able to do once the bar has collapsed and everything else has gone into the panel — a sign-up, usually. Drawn beside the control that opens the panel, and only at the widths where that control is drawn. Dressed like utilities: a Button here is drawn at md and takes the bar's tone */
|
|
19
19
|
compactAction?: ReactNode;
|
|
20
20
|
/** A switcher that belongs with the destinations rather than with the conversion — a language picker, a theme toggle. It is drawn inside the pill, beside the sections, at every scroll position. A NavbarSwitcher is the one built for it: in the pill it is a trigger and a menu, and in the collapsed panel the same element becomes a row that opens a page of its own with a way back, because a dropdown inside a surface already covering the screen is a surface inside a surface */
|
|
21
21
|
preferences?: ReactNode;
|
|
@@ -28,7 +28,25 @@ export interface NavbarOwnProps {
|
|
|
28
28
|
/** Allowed: NavbarItem, NavbarMenu */
|
|
29
29
|
children: ReactNode;
|
|
30
30
|
}
|
|
31
|
-
export type NavbarProps = NavbarOwnProps & Omit<HTMLAttributes<HTMLElement>, 'className' | 'tone' | 'label' | 'menuLabel' | 'closeLabel' | 'brand' | 'utilities' | 'compactAction' | 'preferences' | 'menuOpen' | 'onMenuOpenChange'
|
|
31
|
+
export type NavbarProps = NavbarOwnProps & Omit<HTMLAttributes<HTMLElement>, 'className' | 'tone' | 'label' | 'menuLabel' | 'closeLabel' | 'brand' | 'utilities' | 'compactAction' | 'preferences' | 'showThemeToggle' | 'theme' | 'onThemeChange' | 'themeToggleLabel' | 'menuOpen' | 'onMenuOpenChange'> & ({
|
|
32
|
+
showThemeToggle?: boolean;
|
|
33
|
+
theme: 'light' | 'dark';
|
|
34
|
+
} | {
|
|
35
|
+
showThemeToggle?: false;
|
|
36
|
+
theme?: 'light' | 'dark';
|
|
37
|
+
}) & ({
|
|
38
|
+
showThemeToggle?: boolean;
|
|
39
|
+
onThemeChange: (theme: 'light' | 'dark') => void;
|
|
40
|
+
} | {
|
|
41
|
+
showThemeToggle?: false;
|
|
42
|
+
onThemeChange?: (theme: 'light' | 'dark') => void;
|
|
43
|
+
}) & ({
|
|
44
|
+
showThemeToggle?: boolean;
|
|
45
|
+
themeToggleLabel: string;
|
|
46
|
+
} | {
|
|
47
|
+
showThemeToggle?: false;
|
|
48
|
+
themeToggleLabel?: string;
|
|
49
|
+
});
|
|
32
50
|
/** The class each part carries. Apply these — do not retype them. */
|
|
33
51
|
export declare const navbarParts: {
|
|
34
52
|
readonly root: "dds-navbar";
|
|
@@ -46,4 +64,5 @@ export declare const navbarParts: {
|
|
|
46
64
|
/** Generated so defaults cannot drift from the contract. */
|
|
47
65
|
export declare const navbarDefaults: {
|
|
48
66
|
readonly tone: "default";
|
|
67
|
+
readonly showThemeToggle: false;
|
|
49
68
|
};
|
|
@@ -45,6 +45,11 @@
|
|
|
45
45
|
z-index: -1;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
/*
|
|
49
|
+
* The see-through material — tint, blur, and the layer the pill's blur sits on — is in
|
|
50
|
+
* navbar-material.css, which the bar's panels share.
|
|
51
|
+
*/
|
|
52
|
+
|
|
48
53
|
/*
|
|
49
54
|
* Which regions the bar draws, and the one size query in this package.
|
|
50
55
|
*
|
|
@@ -558,8 +563,8 @@
|
|
|
558
563
|
* There is one of these in the markup and there always was: the same element holds the destinations
|
|
559
564
|
* at rest and the whole row once the bar gathers, which is why its ground, its corner and its lift
|
|
560
565
|
* are declared once and never handed between parts. What changes on scroll is what is inside it and
|
|
561
|
-
* what it is painted in — a bar standing on a dark hero wears
|
|
562
|
-
* left that hero behind wears
|
|
566
|
+
* what it is painted in — a bar standing on a dark hero wears the dark material, and a bar that has
|
|
567
|
+
* left that hero behind wears the page's.
|
|
563
568
|
*
|
|
564
569
|
* Instantly, though, and that is the part a reader cannot read. A surface that swaps colour in one
|
|
565
570
|
* frame while its contents change in the same frame is indistinguishable from a second surface
|
|
@@ -575,7 +580,9 @@
|
|
|
575
580
|
* one a data attribute swaps.
|
|
576
581
|
*/
|
|
577
582
|
:where([data-dds-context="marketing"]) .dds-navbar .dds-navbar__cluster {
|
|
578
|
-
transition:
|
|
583
|
+
transition:
|
|
584
|
+
background-color var(--motion-duration-shift) var(--motion-easing-shift),
|
|
585
|
+
--dds-navbar-tint var(--motion-duration-shift) var(--motion-easing-shift);
|
|
579
586
|
}
|
|
580
587
|
|
|
581
588
|
:where([data-dds-context="marketing"]) .dds-navbar {
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The navigation bar's material, in one place.
|
|
3
|
+
*
|
|
4
|
+
* Every surface the bar paints — the pill, the collapsed bar, and each panel that opens from it —
|
|
5
|
+
* is the same see-through stuff: a nearly opaque base in its own ink, a thin tint over it, and a
|
|
6
|
+
* blur of whatever scrolls behind. The base is bound in each component's contract; what a
|
|
7
|
+
* contract cannot hold is here, once, so a change to the blur or the tint is one edit rather than
|
|
8
|
+
* one per component. Navbar, NavbarMenu and NavbarSwitcher each import it, and a bundler loads it
|
|
9
|
+
* once.
|
|
10
|
+
*
|
|
11
|
+
* Scoped like the generated sheets: `:where([data-dds-context="marketing"])` adds no specificity.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
* The tint is a registered custom property so that it can travel.
|
|
16
|
+
*
|
|
17
|
+
* It is painted as a `background-image` gradient over the base, because that is how one colour is
|
|
18
|
+
* laid over another in a single box. A gradient cannot transition — the base eased from one tone to
|
|
19
|
+
* the other while the tint changed in one frame, and the pill popped as it began. A registered
|
|
20
|
+
* `<color>` property interpolates, and the gradient drawn from it follows it on every frame.
|
|
21
|
+
*/
|
|
22
|
+
@property --dds-navbar-tint {
|
|
23
|
+
syntax: '<color>';
|
|
24
|
+
inherits: false;
|
|
25
|
+
initial-value: transparent;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
:where([data-dds-context="marketing"]) .dds-navbar .dds-navbar__cluster,
|
|
29
|
+
:where([data-dds-context="marketing"]) .dds-navbar .dds-navbar__ground {
|
|
30
|
+
--dds-navbar-tint: var(--color-bg-surface-translucent-tint);
|
|
31
|
+
background-image: linear-gradient(var(--dds-navbar-tint), var(--dds-navbar-tint));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
:where([data-dds-context="marketing"]) .dds-navbar[data-tone="inverse"] .dds-navbar__cluster,
|
|
35
|
+
:where([data-dds-context="marketing"]) .dds-navbar[data-tone="inverse"] .dds-navbar__ground {
|
|
36
|
+
--dds-navbar-tint: var(--color-bg-surface-translucent-tint-on-brand-strong);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/*
|
|
40
|
+
* The blur.
|
|
41
|
+
*
|
|
42
|
+
* `blur()` around the token rather than a binding, because a binding can only write the length.
|
|
43
|
+
* The `-webkit-` form is still the one Safari reads.
|
|
44
|
+
*
|
|
45
|
+
* The collapsed bar holds nothing, so it carries its blur itself.
|
|
46
|
+
*/
|
|
47
|
+
:where([data-dds-context="marketing"]) .dds-navbar .dds-navbar__ground {
|
|
48
|
+
-webkit-backdrop-filter: blur(var(--size-backdrop-blur));
|
|
49
|
+
backdrop-filter: blur(var(--size-backdrop-blur));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/*
|
|
53
|
+
* The pill carries its blur on a layer beneath its own fill, not on itself.
|
|
54
|
+
*
|
|
55
|
+
* An element with `backdrop-filter` becomes the backdrop root for everything inside it, and the
|
|
56
|
+
* section panels hang inside the pill — so a blur on the pill would leave each panel blurring only
|
|
57
|
+
* what the pill had painted. On a pseudo-element the pill stays an ordinary box.
|
|
58
|
+
*
|
|
59
|
+
* `z-index: -1` with no stacking context made for it. The bar's row already is one — its
|
|
60
|
+
* `container-type` brings layout containment — so the layer paints under everything in the row,
|
|
61
|
+
* the pill's own fill included, and the fill lands on top of the blurred page exactly as a
|
|
62
|
+
* `backdrop-filter` on the pill itself would have drawn it. Giving the pill `isolation` instead
|
|
63
|
+
* would have made it a stacking context around its panels, which some engines read as a backdrop
|
|
64
|
+
* root too.
|
|
65
|
+
*/
|
|
66
|
+
:where([data-dds-context="marketing"]) .dds-navbar .dds-navbar__cluster::before {
|
|
67
|
+
content: '';
|
|
68
|
+
position: absolute;
|
|
69
|
+
inset: 0;
|
|
70
|
+
z-index: -1;
|
|
71
|
+
border-radius: inherit;
|
|
72
|
+
pointer-events: none;
|
|
73
|
+
-webkit-backdrop-filter: blur(var(--size-backdrop-blur));
|
|
74
|
+
backdrop-filter: blur(var(--size-backdrop-blur));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/*
|
|
78
|
+
* Each panel the bar opens is the pill's material, so a panel reads as part of the bar rather than
|
|
79
|
+
* a sheet laid over it. NavbarMenu and NavbarSwitcher bind the base and the tint in their
|
|
80
|
+
* contracts. A DropdownMenu does not know it is in a bar, and elsewhere its panel is rightly solid,
|
|
81
|
+
* so inside one it is given the material here — a class deeper than its own rule, so this wins.
|
|
82
|
+
*/
|
|
83
|
+
:where([data-dds-context="marketing"]) .dds-navbar .dds-dropdownmenu .dds-dropdownmenu__surface {
|
|
84
|
+
background-color: var(--color-bg-surface-translucent);
|
|
85
|
+
background-image: linear-gradient(
|
|
86
|
+
var(--color-bg-surface-translucent-tint),
|
|
87
|
+
var(--color-bg-surface-translucent-tint)
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
:where([data-dds-context="marketing"]) .dds-navbarmenu[data-presentation="floating"] .dds-navbarmenu__surface,
|
|
92
|
+
:where([data-dds-context="marketing"]) .dds-navbarswitcher[data-presentation="floating"] .dds-navbarswitcher__surface,
|
|
93
|
+
:where([data-dds-context="marketing"]) .dds-navbar .dds-dropdownmenu .dds-dropdownmenu__surface {
|
|
94
|
+
-webkit-backdrop-filter: blur(var(--size-backdrop-blur));
|
|
95
|
+
backdrop-filter: blur(var(--size-backdrop-blur));
|
|
96
|
+
}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
white-space: nowrap;
|
|
14
14
|
border-radius: var(--radius-pill);
|
|
15
15
|
gap: var(--space-gap-xs);
|
|
16
|
-
min-block-size: var(--size-control-
|
|
16
|
+
min-block-size: var(--size-control-md);
|
|
17
17
|
outline-width: var(--border-width-none);
|
|
18
18
|
padding-block: var(--space-inset-2xs);
|
|
19
19
|
padding-inline: var(--space-inset-md);
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
:where([data-dds-context="marketing"]) .dds-navbaritem[data-tone="inverse"]:hover {
|
|
60
|
-
background-color: var(--color-bg-hover-
|
|
60
|
+
background-color: var(--color-bg-hover-on-brand-strong);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
:where([data-dds-context="marketing"]) .dds-navbaritem[data-current="true"][data-tone="default"] {
|
|
@@ -65,11 +65,11 @@
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
:where([data-dds-context="marketing"]) .dds-navbaritem[data-current="true"][data-tone="inverse"] {
|
|
68
|
-
background-color: var(--color-bg-hover-
|
|
68
|
+
background-color: var(--color-bg-hover-on-brand-strong);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
@media (prefers-reduced-motion: reduce) {
|
|
72
72
|
:where([data-dds-context="marketing"]) .dds-navbaritem,
|
|
73
|
-
:where([data-dds-context="marketing"]) .dds-navbaritem * { transition: none; }
|
|
73
|
+
:where([data-dds-context="marketing"]) .dds-navbaritem * { transition: none !important; }
|
|
74
74
|
}
|
|
75
75
|
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
gap: var(--space-gap-xs);
|
|
25
25
|
letter-spacing: var(--font-label-sm-letter-spacing);
|
|
26
26
|
line-height: var(--font-label-sm-line-height);
|
|
27
|
-
min-block-size: var(--size-control-
|
|
27
|
+
min-block-size: var(--size-control-md);
|
|
28
28
|
outline-width: var(--border-width-none);
|
|
29
29
|
padding-block: var(--space-inset-2xs);
|
|
30
30
|
padding-inline: var(--space-inset-md);
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
display: inline-flex;
|
|
38
38
|
flex-shrink: 0;
|
|
39
39
|
justify-content: center;
|
|
40
|
+
transition-property: rotate;
|
|
40
41
|
block-size: var(--icon-size-xs);
|
|
41
42
|
transition-duration: var(--motion-duration-fast);
|
|
42
43
|
transition-timing-function: var(--motion-easing-standard);
|
|
@@ -82,7 +83,8 @@
|
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
:where([data-dds-context="marketing"]) .dds-navbarmenu[data-presentation="floating"] .dds-navbarmenu__surface {
|
|
85
|
-
background-color: var(--color-bg-surface-
|
|
86
|
+
background-color: var(--color-bg-surface-translucent);
|
|
87
|
+
background-image: linear-gradient(var(--color-bg-surface-translucent-tint), var(--color-bg-surface-translucent-tint));
|
|
86
88
|
border-radius: var(--radius-container);
|
|
87
89
|
box-shadow: var(--elevation-surface-overlay);
|
|
88
90
|
gap: var(--space-gap-xl);
|
|
@@ -110,7 +112,7 @@
|
|
|
110
112
|
}
|
|
111
113
|
|
|
112
114
|
:where([data-dds-context="marketing"]) .dds-navbarmenu[data-tone="inverse"] .dds-navbarmenu__trigger:hover:where(:not(:disabled)) {
|
|
113
|
-
background-color: var(--color-bg-hover-
|
|
115
|
+
background-color: var(--color-bg-hover-on-brand-strong);
|
|
114
116
|
}
|
|
115
117
|
|
|
116
118
|
:where([data-dds-context="marketing"]) .dds-navbarmenu[data-tone="default"] .dds-navbarmenu__trigger[data-expanded="true"] {
|
|
@@ -118,11 +120,11 @@
|
|
|
118
120
|
}
|
|
119
121
|
|
|
120
122
|
:where([data-dds-context="marketing"]) .dds-navbarmenu[data-tone="inverse"] .dds-navbarmenu__trigger[data-expanded="true"] {
|
|
121
|
-
background-color: var(--color-bg-hover-
|
|
123
|
+
background-color: var(--color-bg-hover-on-brand-strong);
|
|
122
124
|
}
|
|
123
125
|
|
|
124
126
|
@media (prefers-reduced-motion: reduce) {
|
|
125
127
|
:where([data-dds-context="marketing"]) .dds-navbarmenu,
|
|
126
|
-
:where([data-dds-context="marketing"]) .dds-navbarmenu * { transition: none; }
|
|
128
|
+
:where([data-dds-context="marketing"]) .dds-navbarmenu * { transition: none !important; }
|
|
127
129
|
}
|
|
128
130
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import './NavbarMenu.css';
|
|
2
2
|
import './navbar-menu-impl.css';
|
|
3
|
+
import '../navbar/navbar-material.css';
|
|
3
4
|
import { type NavbarMenuProps } from './NavbarMenu.types.js';
|
|
4
5
|
export type { NavbarMenuProps };
|
|
5
6
|
export declare function NavbarMenu({ presentation, tone, label, open, onOpenChange, replacing, feature, children, ...rest }: NavbarMenuProps): import("react").JSX.Element;
|
|
@@ -4,6 +4,7 @@ import { useLayoutEffect, useCallback, useEffect, useRef, useState, } from 'reac
|
|
|
4
4
|
import { ChevronDownRegularIcon } from '@deriv-com/quill-icons-web';
|
|
5
5
|
import './NavbarMenu.css';
|
|
6
6
|
import './navbar-menu-impl.css';
|
|
7
|
+
import '../navbar/navbar-material.css';
|
|
7
8
|
import { milliseconds } from '../../css-time.js';
|
|
8
9
|
import { useHoverOpen } from '../../hover-open.js';
|
|
9
10
|
import { Icon } from '../icon/Icon.js';
|
|
@@ -13,16 +13,16 @@
|
|
|
13
13
|
* Where the panel hangs, which is three offsets a contract cannot hold: two of them
|
|
14
14
|
* negate the bar's own padding and the third is a percentage of nothing.
|
|
15
15
|
*
|
|
16
|
-
* `inset-block-start: 100%` puts it under the
|
|
17
|
-
*
|
|
16
|
+
* `inset-block-start: 100%` puts it under the row it hangs from. The inline half centres it
|
|
17
|
+
* on its containing block rather than hanging it from a leading edge — an 846px panel dropped
|
|
18
18
|
* from the left of a one-word name runs off the end of the page for the last section in the
|
|
19
19
|
* row, and reads as belonging to whatever is to its right rather than to the name above it.
|
|
20
20
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
21
|
+
* The containing block is the nearest positioned ancestor, and this root is not positioned. In
|
|
22
|
+
* a Navbar that is the pill — the landmark inside it is deliberately not positioned — so every
|
|
23
|
+
* section's panel opens centred on the pill, in the same place whichever section is pressed,
|
|
24
|
+
* and the language switcher and the theme toggle beside the destinations do not pull it off
|
|
25
|
+
* centre. Outside a Navbar it centres on whatever positioned box the page gives it.
|
|
26
26
|
*
|
|
27
27
|
* `translate` rather than a negative margin: it is the transform property, so it composes
|
|
28
28
|
* with anything else the panel is given instead of fighting a layout value for the same
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
gap: var(--space-gap-xs);
|
|
25
25
|
letter-spacing: var(--font-label-sm-letter-spacing);
|
|
26
26
|
line-height: var(--font-label-sm-line-height);
|
|
27
|
-
min-block-size: var(--size-control-
|
|
27
|
+
min-block-size: var(--size-control-md);
|
|
28
28
|
outline-width: var(--border-width-none);
|
|
29
29
|
padding-inline: var(--space-inset-md);
|
|
30
30
|
}
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
align-items: center;
|
|
34
34
|
display: inline-flex;
|
|
35
35
|
flex-shrink: 0;
|
|
36
|
-
block-size: var(--icon-
|
|
36
|
+
block-size: var(--icon-control-md);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
:where([data-dds-context="marketing"]) .dds-navbarswitcher .dds-navbarswitcher__chevron {
|
|
@@ -87,7 +87,8 @@
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
:where([data-dds-context="marketing"]) .dds-navbarswitcher[data-presentation="floating"] .dds-navbarswitcher__surface {
|
|
90
|
-
background-color: var(--color-bg-surface-
|
|
90
|
+
background-color: var(--color-bg-surface-translucent);
|
|
91
|
+
background-image: linear-gradient(var(--color-bg-surface-translucent-tint), var(--color-bg-surface-translucent-tint));
|
|
91
92
|
border-radius: var(--radius-container);
|
|
92
93
|
box-shadow: var(--elevation-surface-floating);
|
|
93
94
|
inline-size: var(--size-switcher-panel-width);
|
|
@@ -108,10 +109,10 @@
|
|
|
108
109
|
}
|
|
109
110
|
|
|
110
111
|
:where([data-dds-context="marketing"]) .dds-navbarswitcher[data-tone="inverse"] .dds-navbarswitcher__trigger:hover:where(:not(:disabled)) {
|
|
111
|
-
background-color: var(--color-bg-hover-
|
|
112
|
+
background-color: var(--color-bg-hover-on-brand-strong);
|
|
112
113
|
}
|
|
113
114
|
|
|
114
115
|
:where([data-dds-context="marketing"]) .dds-navbarswitcher[data-tone="inverse"] .dds-navbarswitcher__trigger:focus-visible {
|
|
115
|
-
outline-color: var(--color-border-focus-
|
|
116
|
+
outline-color: var(--color-border-focus-on-brand-strong);
|
|
116
117
|
}
|
|
117
118
|
|
|
@@ -4,6 +4,7 @@ import { useCallback, useEffect, useRef, useState } from 'react';
|
|
|
4
4
|
import { ChevronDownRegularIcon, ChevronLeftRegularIcon, ChevronRightRegularIcon, } from '@deriv-com/quill-icons-web';
|
|
5
5
|
import './NavbarSwitcher.css';
|
|
6
6
|
import './navbar-switcher-impl.css';
|
|
7
|
+
import '../navbar/navbar-material.css';
|
|
7
8
|
import { useHoverOpen } from '../../hover-open.js';
|
|
8
9
|
import { Icon } from '../icon/Icon.js';
|
|
9
10
|
import { navbarSwitcherDefaults, navbarSwitcherParts, } from './NavbarSwitcher.types.js';
|
|
@@ -78,7 +79,7 @@ export function NavbarSwitcher({ presentation = navbarSwitcherDefaults.presentat
|
|
|
78
79
|
document.removeEventListener('pointerdown', onPointerDown);
|
|
79
80
|
};
|
|
80
81
|
}, [expanded, inPanel, setOpen, hover]);
|
|
81
|
-
return (_jsxs("div", { ...rest, ref: rootRef, className: navbarSwitcherParts.root, "data-presentation": presentation, "data-tone": tone, onPointerEnter: hover.onPointerEnter, onPointerLeave: hover.onPointerLeave, children: [_jsxs("button", { ref: triggerRef, type: "button", className: navbarSwitcherParts.trigger, "aria-label": menuLabel, "aria-expanded": expanded, "data-expanded": String(expanded), onClick: () => {
|
|
82
|
+
return (_jsxs("div", { ...rest, ref: rootRef, className: navbarSwitcherParts.root, "data-presentation": presentation, "data-tone": tone, "data-dds-pinned-surface": inPanel && expanded ? 'open' : undefined, onPointerEnter: hover.onPointerEnter, onPointerLeave: hover.onPointerLeave, children: [_jsxs("button", { ref: triggerRef, type: "button", className: navbarSwitcherParts.trigger, "aria-label": menuLabel, "aria-expanded": expanded, "data-expanded": String(expanded), onClick: () => {
|
|
82
83
|
// The press owns the state from here, or a set the pointer had opened and the reader
|
|
83
84
|
// then pressed shut would close a second time when the pointer left.
|
|
84
85
|
hover.release();
|
|
@@ -128,6 +128,6 @@
|
|
|
128
128
|
|
|
129
129
|
@media (prefers-reduced-motion: reduce) {
|
|
130
130
|
:where([data-dds-context="marketing"]) .dds-option,
|
|
131
|
-
:where([data-dds-context="marketing"]) .dds-option * { transition: none; }
|
|
131
|
+
:where([data-dds-context="marketing"]) .dds-option * { transition: none !important; }
|
|
132
132
|
}
|
|
133
133
|
|