@deriv-com/dds-marketing 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.llm/components/accordion.md +193 -0
- package/.llm/components/accordionitem.md +236 -0
- package/.llm/components/aspectratio.md +212 -0
- package/.llm/components/badge.md +231 -0
- package/.llm/components/bottomsheet.md +404 -0
- package/.llm/components/breadcrumb.md +197 -0
- package/.llm/components/breadcrumbitem.md +178 -0
- package/.llm/components/button.md +271 -0
- package/.llm/components/buttonicon.md +313 -0
- package/.llm/components/card.md +313 -0
- package/.llm/components/cardbody.md +409 -0
- package/.llm/components/cardbutton.md +259 -0
- package/.llm/components/checkbox.md +285 -0
- package/.llm/components/divider.md +230 -0
- package/.llm/components/dropdownmenu.md +453 -0
- package/.llm/components/filterchip.md +314 -0
- package/.llm/components/footer.md +408 -0
- package/.llm/components/footergroup.md +241 -0
- package/.llm/components/grid.md +659 -0
- package/.llm/components/icon.md +194 -0
- package/.llm/components/link.md +354 -0
- package/.llm/components/menuitem.md +218 -0
- package/.llm/components/navbar.md +458 -0
- package/.llm/components/navbaritem.md +238 -0
- package/.llm/components/navbarmenu.md +319 -0
- package/.llm/components/navbarmenugroup.md +184 -0
- package/.llm/components/navbarpanel.md +255 -0
- package/.llm/components/navbarswitcher.md +343 -0
- package/.llm/components/navbarswitcheroption.md +156 -0
- package/.llm/components/option.md +268 -0
- package/.llm/components/pagination.md +361 -0
- package/.llm/components/removablechip.md +247 -0
- package/.llm/components/row.md +381 -0
- package/.llm/components/scroller.md +470 -0
- package/.llm/components/searchinput.md +279 -0
- package/.llm/components/segmentedcontrol.md +358 -0
- package/.llm/components/segmentedcontrolitem.md +272 -0
- package/.llm/components/select.md +509 -0
- package/.llm/components/selectchip.md +334 -0
- package/.llm/components/spinner.md +222 -0
- package/.llm/components/stack.md +334 -0
- package/.llm/components/statusdot.md +205 -0
- package/.llm/components/subdomainnavbar.md +327 -0
- package/.llm/components/tab.md +291 -0
- package/.llm/components/table.md +660 -0
- package/.llm/components/tablebody.md +258 -0
- package/.llm/components/tablecell.md +248 -0
- package/.llm/components/tablehead.md +248 -0
- package/.llm/components/tableheadercell.md +298 -0
- package/.llm/components/tablerow.md +285 -0
- package/.llm/components/tablist.md +210 -0
- package/.llm/components/textarea.md +362 -0
- package/.llm/components/textinput.md +467 -0
- package/.llm/components/tooltip.md +267 -0
- package/.llm/components/typography.md +245 -0
- package/.llm/digest/accordion.md +43 -0
- package/.llm/digest/accordionitem.md +47 -0
- package/.llm/digest/aspectratio.md +47 -0
- package/.llm/digest/badge.md +45 -0
- package/.llm/digest/bottomsheet.md +69 -0
- package/.llm/digest/breadcrumb.md +38 -0
- package/.llm/digest/breadcrumbitem.md +43 -0
- package/.llm/digest/button.md +48 -0
- package/.llm/digest/buttonicon.md +61 -0
- package/.llm/digest/card.md +50 -0
- package/.llm/digest/cardbody.md +68 -0
- package/.llm/digest/cardbutton.md +49 -0
- package/.llm/digest/checkbox.md +63 -0
- package/.llm/digest/divider.md +52 -0
- package/.llm/digest/dropdownmenu.md +67 -0
- package/.llm/digest/filterchip.md +68 -0
- package/.llm/digest/footer.md +57 -0
- package/.llm/digest/footergroup.md +42 -0
- package/.llm/digest/grid.md +62 -0
- package/.llm/digest/icon.md +45 -0
- package/.llm/digest/link.md +59 -0
- package/.llm/digest/menuitem.md +46 -0
- package/.llm/digest/navbar.md +60 -0
- package/.llm/digest/navbaritem.md +54 -0
- package/.llm/digest/navbarmenu.md +54 -0
- package/.llm/digest/navbarmenugroup.md +40 -0
- package/.llm/digest/navbarpanel.md +53 -0
- package/.llm/digest/navbarswitcher.md +51 -0
- package/.llm/digest/navbarswitcheroption.md +37 -0
- package/.llm/digest/option.md +54 -0
- package/.llm/digest/pagination.md +71 -0
- package/.llm/digest/removablechip.md +51 -0
- package/.llm/digest/row.md +60 -0
- package/.llm/digest/scroller.md +59 -0
- package/.llm/digest/searchinput.md +56 -0
- package/.llm/digest/segmentedcontrol.md +59 -0
- package/.llm/digest/segmentedcontrolitem.md +59 -0
- package/.llm/digest/select.md +92 -0
- package/.llm/digest/selectchip.md +68 -0
- package/.llm/digest/spinner.md +52 -0
- package/.llm/digest/stack.md +56 -0
- package/.llm/digest/statusdot.md +46 -0
- package/.llm/digest/subdomainnavbar.md +54 -0
- package/.llm/digest/tab.md +60 -0
- package/.llm/digest/table.md +71 -0
- package/.llm/digest/tablebody.md +49 -0
- package/.llm/digest/tablecell.md +55 -0
- package/.llm/digest/tablehead.md +50 -0
- package/.llm/digest/tableheadercell.md +65 -0
- package/.llm/digest/tablerow.md +56 -0
- package/.llm/digest/tablist.md +46 -0
- package/.llm/digest/textarea.md +78 -0
- package/.llm/digest/textinput.md +95 -0
- package/.llm/digest/tooltip.md +58 -0
- package/.llm/digest/typography.md +59 -0
- package/.llm/index.md +86 -0
- package/.llm/rules.md +122 -0
- package/.llm/tokens.md +341 -0
- package/AGENTS.md +164 -0
- package/LICENSE +21 -0
- package/README.md +63 -15
- package/dist/components/core/accordion/Accordion.css +10 -0
- package/dist/components/core/accordion/Accordion.d.ts +20 -0
- package/dist/components/core/accordion/Accordion.js +69 -0
- package/dist/components/core/accordion/Accordion.types.d.ts +20 -0
- package/dist/components/core/accordion/Accordion.types.js +7 -0
- package/dist/components/core/accordion-item/AccordionItem.css +98 -0
- package/dist/components/core/accordion-item/AccordionItem.d.ts +44 -0
- package/dist/components/core/accordion-item/AccordionItem.js +63 -0
- package/dist/components/core/accordion-item/AccordionItem.types.d.ts +32 -0
- package/dist/components/core/accordion-item/AccordionItem.types.js +13 -0
- package/dist/components/core/accordion-item/accordion-item-impl.css +107 -0
- package/dist/components/core/badge/Badge.css +37 -0
- package/dist/components/core/badge/Badge.d.ts +37 -0
- package/dist/components/core/badge/Badge.js +40 -0
- package/dist/components/core/badge/Badge.types.d.ts +24 -0
- package/dist/components/core/badge/Badge.types.js +8 -0
- package/dist/components/core/badge/badge-impl.css +32 -0
- package/dist/components/core/bottom-sheet/BottomSheet.css +178 -0
- package/dist/components/core/bottom-sheet/BottomSheet.d.ts +22 -0
- package/dist/components/core/bottom-sheet/BottomSheet.js +359 -0
- package/dist/components/core/bottom-sheet/BottomSheet.types.d.ts +67 -0
- package/dist/components/core/bottom-sheet/BottomSheet.types.js +18 -0
- package/dist/components/core/bottom-sheet/bottom-sheet-impl.css +57 -0
- package/dist/components/core/breadcrumb/Breadcrumb.css +19 -0
- package/dist/components/core/breadcrumb/Breadcrumb.d.ts +16 -0
- package/dist/components/core/breadcrumb/Breadcrumb.js +22 -0
- package/dist/components/core/breadcrumb/Breadcrumb.types.d.ts +18 -0
- package/dist/components/core/breadcrumb/Breadcrumb.types.js +9 -0
- package/dist/components/core/breadcrumb-item/BreadcrumbItem.css +34 -0
- package/dist/components/core/breadcrumb-item/BreadcrumbItem.d.ts +12 -0
- package/dist/components/core/breadcrumb-item/BreadcrumbItem.js +15 -0
- package/dist/components/core/breadcrumb-item/BreadcrumbItem.types.d.ts +22 -0
- package/dist/components/core/breadcrumb-item/BreadcrumbItem.types.js +9 -0
- package/dist/components/core/button/Button.css +141 -0
- package/dist/components/core/button/Button.d.ts +25 -0
- package/dist/components/core/button/Button.js +28 -0
- package/dist/components/core/button/Button.types.d.ts +40 -0
- package/dist/components/core/button/Button.types.js +9 -0
- package/dist/components/core/button/button-impl.css +46 -0
- package/dist/components/core/button-icon/ButtonIcon.css +135 -0
- package/dist/components/core/button-icon/ButtonIcon.d.ts +34 -0
- package/dist/components/core/button-icon/ButtonIcon.js +117 -0
- package/dist/components/core/button-icon/ButtonIcon.types.d.ts +41 -0
- package/dist/components/core/button-icon/ButtonIcon.types.js +8 -0
- package/dist/components/core/card/Card.css +65 -0
- package/dist/components/core/card/Card.d.ts +24 -0
- package/dist/components/core/card/Card.js +26 -0
- package/dist/components/core/card/Card.types.d.ts +33 -0
- package/dist/components/core/card/Card.types.js +7 -0
- package/dist/components/core/card-body/CardBody.css +139 -0
- package/dist/components/core/card-body/CardBody.d.ts +62 -0
- package/dist/components/core/card-body/CardBody.js +97 -0
- package/dist/components/core/card-body/CardBody.types.d.ts +61 -0
- package/dist/components/core/card-body/CardBody.types.js +15 -0
- package/dist/components/core/card-body/card-body-impl.css +87 -0
- package/dist/components/core/card-button/CardButton.css +73 -0
- package/dist/components/core/card-button/CardButton.d.ts +27 -0
- package/dist/components/core/card-button/CardButton.js +37 -0
- package/dist/components/core/card-button/CardButton.types.d.ts +24 -0
- package/dist/components/core/card-button/CardButton.types.js +7 -0
- package/dist/components/core/card-button/card-button-impl.css +39 -0
- package/dist/components/core/checkbox/Checkbox.css +149 -0
- package/dist/components/core/checkbox/Checkbox.d.ts +21 -0
- package/dist/components/core/checkbox/Checkbox.js +97 -0
- package/dist/components/core/checkbox/Checkbox.types.d.ts +46 -0
- package/dist/components/core/checkbox/Checkbox.types.js +15 -0
- package/dist/components/core/checkbox/checkbox-impl.css +90 -0
- package/dist/components/core/divider/Divider.css +41 -0
- package/dist/components/core/divider/Divider.d.ts +46 -0
- package/dist/components/core/divider/Divider.js +51 -0
- package/dist/components/core/divider/Divider.types.d.ts +25 -0
- package/dist/components/core/divider/Divider.types.js +9 -0
- package/dist/components/core/dropdown-menu/DropdownMenu.css +146 -0
- package/dist/components/core/dropdown-menu/DropdownMenu.d.ts +22 -0
- package/dist/components/core/dropdown-menu/DropdownMenu.js +309 -0
- package/dist/components/core/dropdown-menu/DropdownMenu.types.d.ts +62 -0
- package/dist/components/core/dropdown-menu/DropdownMenu.types.js +12 -0
- package/dist/components/core/dropdown-menu/dropdown-menu-impl.css +70 -0
- package/dist/components/core/filter-chip/FilterChip.css +149 -0
- package/dist/components/core/filter-chip/FilterChip.d.ts +23 -0
- package/dist/components/core/filter-chip/FilterChip.js +37 -0
- package/dist/components/core/filter-chip/FilterChip.types.d.ts +53 -0
- package/dist/components/core/filter-chip/FilterChip.types.js +12 -0
- package/dist/components/core/footer/Footer.css +104 -0
- package/dist/components/core/footer/Footer.d.ts +43 -0
- package/dist/components/core/footer/Footer.js +53 -0
- package/dist/components/core/footer/Footer.types.d.ts +47 -0
- package/dist/components/core/footer/Footer.types.js +18 -0
- package/dist/components/core/footer/footer-impl.css +218 -0
- package/dist/components/core/footer-group/FooterGroup.css +90 -0
- package/dist/components/core/footer-group/FooterGroup.d.ts +32 -0
- package/dist/components/core/footer-group/FooterGroup.js +64 -0
- package/dist/components/core/footer-group/FooterGroup.types.d.ts +25 -0
- package/dist/components/core/footer-group/FooterGroup.types.js +12 -0
- package/dist/components/core/footer-group/footer-group-impl.css +78 -0
- package/dist/components/core/icon/Icon.css +40 -0
- package/dist/components/core/icon/Icon.d.ts +23 -0
- package/dist/components/core/icon/Icon.js +79 -0
- package/dist/components/core/icon/Icon.types.d.ts +24 -0
- package/dist/components/core/icon/Icon.types.js +7 -0
- package/dist/components/core/link/Link.css +89 -0
- package/dist/components/core/link/Link.d.ts +37 -0
- package/dist/components/core/link/Link.js +141 -0
- package/dist/components/core/link/Link.types.d.ts +41 -0
- package/dist/components/core/link/Link.types.js +9 -0
- package/dist/components/core/link/link-impl.css +168 -0
- package/dist/components/core/menu-item/MenuItem.css +70 -0
- package/dist/components/core/menu-item/MenuItem.d.ts +11 -0
- package/dist/components/core/menu-item/MenuItem.js +26 -0
- package/dist/components/core/menu-item/MenuItem.types.d.ts +28 -0
- package/dist/components/core/menu-item/MenuItem.types.js +9 -0
- package/dist/components/core/navbar/Navbar.css +135 -0
- package/dist/components/core/navbar/Navbar.d.ts +36 -0
- package/dist/components/core/navbar/Navbar.js +371 -0
- package/dist/components/core/navbar/Navbar.types.d.ts +49 -0
- package/dist/components/core/navbar/Navbar.types.js +17 -0
- package/dist/components/core/navbar/navbar-impl.css +590 -0
- package/dist/components/core/navbar-item/NavbarItem.css +75 -0
- package/dist/components/core/navbar-item/NavbarItem.d.ts +22 -0
- package/dist/components/core/navbar-item/NavbarItem.js +40 -0
- package/dist/components/core/navbar-item/NavbarItem.types.d.ts +34 -0
- package/dist/components/core/navbar-item/NavbarItem.types.js +10 -0
- package/dist/components/core/navbar-menu/NavbarMenu.css +128 -0
- package/dist/components/core/navbar-menu/NavbarMenu.d.ts +5 -0
- package/dist/components/core/navbar-menu/NavbarMenu.js +186 -0
- package/dist/components/core/navbar-menu/NavbarMenu.types.d.ts +45 -0
- package/dist/components/core/navbar-menu/NavbarMenu.types.js +12 -0
- package/dist/components/core/navbar-menu/navbar-menu-impl.css +186 -0
- package/dist/components/core/navbar-menu-group/NavbarMenuGroup.css +26 -0
- package/dist/components/core/navbar-menu-group/NavbarMenuGroup.d.ts +17 -0
- package/dist/components/core/navbar-menu-group/NavbarMenuGroup.js +22 -0
- package/dist/components/core/navbar-menu-group/NavbarMenuGroup.types.d.ts +14 -0
- package/dist/components/core/navbar-menu-group/NavbarMenuGroup.types.js +7 -0
- package/dist/components/core/navbar-panel/NavbarPanel.css +87 -0
- package/dist/components/core/navbar-panel/NavbarPanel.d.ts +34 -0
- package/dist/components/core/navbar-panel/NavbarPanel.js +46 -0
- package/dist/components/core/navbar-panel/NavbarPanel.types.d.ts +29 -0
- package/dist/components/core/navbar-panel/NavbarPanel.types.js +12 -0
- package/dist/components/core/navbar-panel/navbar-panel-impl.css +104 -0
- package/dist/components/core/navbar-panel/use-navbar-panel.d.ts +26 -0
- package/dist/components/core/navbar-panel/use-navbar-panel.js +135 -0
- package/dist/components/core/navbar-switcher/NavbarSwitcher.css +117 -0
- package/dist/components/core/navbar-switcher/NavbarSwitcher.d.ts +20 -0
- package/dist/components/core/navbar-switcher/NavbarSwitcher.js +90 -0
- package/dist/components/core/navbar-switcher/NavbarSwitcher.types.d.ts +46 -0
- package/dist/components/core/navbar-switcher/NavbarSwitcher.types.js +13 -0
- package/dist/components/core/navbar-switcher/navbar-switcher-impl.css +179 -0
- package/dist/components/core/navbar-switcher-option/NavbarSwitcherOption.css +39 -0
- package/dist/components/core/navbar-switcher-option/NavbarSwitcherOption.d.ts +16 -0
- package/dist/components/core/navbar-switcher-option/NavbarSwitcherOption.js +19 -0
- package/dist/components/core/navbar-switcher-option/NavbarSwitcherOption.types.d.ts +18 -0
- package/dist/components/core/navbar-switcher-option/NavbarSwitcherOption.types.js +7 -0
- package/dist/components/core/option/Option.css +133 -0
- package/dist/components/core/option/Option.d.ts +25 -0
- package/dist/components/core/option/Option.js +31 -0
- package/dist/components/core/option/Option.types.d.ts +44 -0
- package/dist/components/core/option/Option.types.js +14 -0
- package/dist/components/core/pagination/Pagination.css +237 -0
- package/dist/components/core/pagination/Pagination.d.ts +30 -0
- package/dist/components/core/pagination/Pagination.js +406 -0
- package/dist/components/core/pagination/Pagination.types.d.ts +59 -0
- package/dist/components/core/pagination/Pagination.types.js +14 -0
- package/dist/components/core/pagination/pagination-impl.css +17 -0
- package/dist/components/core/removable-chip/RemovableChip.css +125 -0
- package/dist/components/core/removable-chip/RemovableChip.d.ts +25 -0
- package/dist/components/core/removable-chip/RemovableChip.js +36 -0
- package/dist/components/core/removable-chip/RemovableChip.types.d.ts +38 -0
- package/dist/components/core/removable-chip/RemovableChip.types.js +13 -0
- package/dist/components/core/search-input/SearchInput.css +205 -0
- package/dist/components/core/search-input/SearchInput.d.ts +5 -0
- package/dist/components/core/search-input/SearchInput.js +81 -0
- package/dist/components/core/search-input/SearchInput.types.d.ts +43 -0
- package/dist/components/core/search-input/SearchInput.types.js +13 -0
- package/dist/components/core/search-input/search-input-impl.css +20 -0
- package/dist/components/core/segmented-control/SegmentedControl.css +57 -0
- package/dist/components/core/segmented-control/SegmentedControl.d.ts +37 -0
- package/dist/components/core/segmented-control/SegmentedControl.js +269 -0
- package/dist/components/core/segmented-control/SegmentedControl.types.d.ts +38 -0
- package/dist/components/core/segmented-control/SegmentedControl.types.js +8 -0
- package/dist/components/core/segmented-control/segmented-control-impl.css +57 -0
- package/dist/components/core/segmented-control-item/SegmentedControlItem.css +151 -0
- package/dist/components/core/segmented-control-item/SegmentedControlItem.d.ts +50 -0
- package/dist/components/core/segmented-control-item/SegmentedControlItem.js +101 -0
- package/dist/components/core/segmented-control-item/SegmentedControlItem.types.d.ts +37 -0
- package/dist/components/core/segmented-control-item/SegmentedControlItem.types.js +10 -0
- package/dist/components/core/segmented-control-item/segmented-control-item-impl.css +69 -0
- package/dist/components/core/select/Select.css +400 -0
- package/dist/components/core/select/Select.d.ts +29 -0
- package/dist/components/core/select/Select.js +524 -0
- package/dist/components/core/select/Select.types.d.ts +96 -0
- package/dist/components/core/select/Select.types.js +26 -0
- package/dist/components/core/select/select-impl.css +114 -0
- package/dist/components/core/select-chip/SelectChip.css +155 -0
- package/dist/components/core/select-chip/SelectChip.d.ts +20 -0
- package/dist/components/core/select-chip/SelectChip.js +273 -0
- package/dist/components/core/select-chip/SelectChip.types.d.ts +56 -0
- package/dist/components/core/select-chip/SelectChip.types.js +14 -0
- package/dist/components/core/select-chip/select-chip-impl.css +38 -0
- package/dist/components/core/spinner/Spinner.css +76 -0
- package/dist/components/core/spinner/Spinner.d.ts +5 -0
- package/dist/components/core/spinner/Spinner.js +29 -0
- package/dist/components/core/spinner/Spinner.types.d.ts +37 -0
- package/dist/components/core/spinner/Spinner.types.js +10 -0
- package/dist/components/core/spinner/spinner-impl.css +27 -0
- package/dist/components/core/status-dot/StatusDot.css +43 -0
- package/dist/components/core/status-dot/StatusDot.d.ts +35 -0
- package/dist/components/core/status-dot/StatusDot.js +46 -0
- package/dist/components/core/status-dot/StatusDot.types.d.ts +29 -0
- package/dist/components/core/status-dot/StatusDot.types.js +7 -0
- package/dist/components/core/status-dot/status-dot-impl.css +42 -0
- package/dist/components/core/subdomain-navbar/SubdomainNavbar.css +89 -0
- package/dist/components/core/subdomain-navbar/SubdomainNavbar.d.ts +21 -0
- package/dist/components/core/subdomain-navbar/SubdomainNavbar.js +127 -0
- package/dist/components/core/subdomain-navbar/SubdomainNavbar.types.d.ts +43 -0
- package/dist/components/core/subdomain-navbar/SubdomainNavbar.types.js +13 -0
- package/dist/components/core/subdomain-navbar/subdomain-navbar-impl.css +147 -0
- package/dist/components/core/tab/Tab.css +113 -0
- package/dist/components/core/tab/Tab.d.ts +36 -0
- package/dist/components/core/tab/Tab.js +53 -0
- package/dist/components/core/tab/Tab.types.d.ts +42 -0
- package/dist/components/core/tab/Tab.types.js +13 -0
- package/dist/components/core/tab/tab-impl.css +49 -0
- package/dist/components/core/tab-list/TabList.css +40 -0
- package/dist/components/core/tab-list/TabList.d.ts +26 -0
- package/dist/components/core/tab-list/TabList.js +124 -0
- package/dist/components/core/tab-list/TabList.types.d.ts +20 -0
- package/dist/components/core/tab-list/TabList.types.js +7 -0
- package/dist/components/core/tab-list/tab-list-impl.css +56 -0
- package/dist/components/core/table/Table.css +40 -0
- package/dist/components/core/table/Table.d.ts +19 -0
- package/dist/components/core/table/Table.js +55 -0
- package/dist/components/core/table/Table.types.d.ts +59 -0
- package/dist/components/core/table/Table.types.js +9 -0
- package/dist/components/core/table/table-impl.css +75 -0
- package/dist/components/core/table/use-table-sort.d.ts +43 -0
- package/dist/components/core/table/use-table-sort.js +51 -0
- package/dist/components/core/table-body/TableBody.css +6 -0
- package/dist/components/core/table-body/TableBody.d.ts +12 -0
- package/dist/components/core/table-body/TableBody.js +26 -0
- package/dist/components/core/table-body/TableBody.types.d.ts +36 -0
- package/dist/components/core/table-body/TableBody.types.js +7 -0
- package/dist/components/core/table-cell/TableCell.css +76 -0
- package/dist/components/core/table-cell/TableCell.d.ts +21 -0
- package/dist/components/core/table-cell/TableCell.js +31 -0
- package/dist/components/core/table-cell/TableCell.types.d.ts +43 -0
- package/dist/components/core/table-cell/TableCell.types.js +7 -0
- package/dist/components/core/table-head/TableHead.css +6 -0
- package/dist/components/core/table-head/TableHead.d.ts +22 -0
- package/dist/components/core/table-head/TableHead.js +52 -0
- package/dist/components/core/table-head/TableHead.types.d.ts +39 -0
- package/dist/components/core/table-head/TableHead.types.js +7 -0
- package/dist/components/core/table-head/table-head-impl.css +51 -0
- package/dist/components/core/table-header-cell/TableHeaderCell.css +126 -0
- package/dist/components/core/table-header-cell/TableHeaderCell.d.ts +21 -0
- package/dist/components/core/table-header-cell/TableHeaderCell.js +34 -0
- package/dist/components/core/table-header-cell/TableHeaderCell.types.d.ts +56 -0
- package/dist/components/core/table-header-cell/TableHeaderCell.types.js +9 -0
- package/dist/components/core/table-header-cell/table-header-cell-impl.css +74 -0
- package/dist/components/core/table-row/TableRow.css +18 -0
- package/dist/components/core/table-row/TableRow.d.ts +17 -0
- package/dist/components/core/table-row/TableRow.js +32 -0
- package/dist/components/core/table-row/TableRow.types.d.ts +45 -0
- package/dist/components/core/table-row/TableRow.types.js +7 -0
- package/dist/components/core/table-row/table-row-impl.css +31 -0
- package/dist/components/core/text-area/TextArea.css +325 -0
- package/dist/components/core/text-area/TextArea.d.ts +13 -0
- package/dist/components/core/text-area/TextArea.js +133 -0
- package/dist/components/core/text-area/TextArea.types.d.ts +67 -0
- package/dist/components/core/text-area/TextArea.types.js +19 -0
- package/dist/components/core/text-area/text-area-impl.css +36 -0
- package/dist/components/core/text-input/TextInput.css +400 -0
- package/dist/components/core/text-input/TextInput.d.ts +5 -0
- package/dist/components/core/text-input/TextInput.js +130 -0
- package/dist/components/core/text-input/TextInput.types.d.ts +96 -0
- package/dist/components/core/text-input/TextInput.types.js +24 -0
- package/dist/components/core/text-input/text-input-impl.css +36 -0
- package/dist/components/core/tooltip/Tooltip.css +101 -0
- package/dist/components/core/tooltip/Tooltip.d.ts +51 -0
- package/dist/components/core/tooltip/Tooltip.js +87 -0
- package/dist/components/core/tooltip/Tooltip.types.d.ts +38 -0
- package/dist/components/core/tooltip/Tooltip.types.js +9 -0
- package/dist/components/core/tooltip/TooltipAnchor.d.ts +52 -0
- package/dist/components/core/tooltip/TooltipAnchor.js +69 -0
- package/dist/components/core/tooltip/tooltip-anchor.css +145 -0
- package/dist/components/core/tooltip/tooltip-impl.css +54 -0
- package/dist/components/core/tooltip/use-tooltip.d.ts +111 -0
- package/dist/components/core/tooltip/use-tooltip.js +189 -0
- package/dist/components/core/typography/Typography.css +96 -0
- package/dist/components/core/typography/Typography.d.ts +297 -0
- package/dist/components/core/typography/Typography.js +28 -0
- package/dist/components/core/typography/Typography.types.d.ts +40 -0
- package/dist/components/core/typography/Typography.types.js +7 -0
- package/dist/components/css-time.d.ts +20 -0
- package/dist/components/css-time.js +30 -0
- package/dist/components/given.d.ts +7 -0
- package/dist/components/given.js +9 -0
- package/dist/components/hover-open.d.ts +34 -0
- package/dist/components/hover-open.js +90 -0
- package/dist/components/index.d.ts +114 -1
- package/dist/components/index.js +115 -2
- package/dist/components/layout/aspect-ratio/AspectRatio.css +29 -0
- package/dist/components/layout/aspect-ratio/AspectRatio.d.ts +24 -0
- package/dist/components/layout/aspect-ratio/AspectRatio.js +26 -0
- package/dist/components/layout/aspect-ratio/AspectRatio.types.d.ts +22 -0
- package/dist/components/layout/aspect-ratio/AspectRatio.types.js +7 -0
- package/dist/components/layout/aspect-ratio/aspect-ratio-impl.css +44 -0
- package/dist/components/layout/grid/Grid.css +76 -0
- package/dist/components/layout/grid/Grid.d.ts +31 -0
- package/dist/components/layout/grid/Grid.js +33 -0
- package/dist/components/layout/grid/Grid.types.d.ts +48 -0
- package/dist/components/layout/grid/Grid.types.js +7 -0
- package/dist/components/layout/grid/grid-impl.css +62 -0
- package/dist/components/layout/row/Row.css +85 -0
- package/dist/components/layout/row/Row.d.ts +32 -0
- package/dist/components/layout/row/Row.js +34 -0
- package/dist/components/layout/row/Row.types.d.ts +45 -0
- package/dist/components/layout/row/Row.types.js +7 -0
- package/dist/components/layout/scroller/Scroller.css +59 -0
- package/dist/components/layout/scroller/Scroller.d.ts +34 -0
- package/dist/components/layout/scroller/Scroller.js +36 -0
- package/dist/components/layout/scroller/Scroller.types.d.ts +38 -0
- package/dist/components/layout/scroller/Scroller.types.js +7 -0
- package/dist/components/layout/scroller/scroller-impl.css +45 -0
- package/dist/components/layout/stack/Stack.css +73 -0
- package/dist/components/layout/stack/Stack.d.ts +28 -0
- package/dist/components/layout/stack/Stack.js +30 -0
- package/dist/components/layout/stack/Stack.types.d.ts +41 -0
- package/dist/components/layout/stack/Stack.types.js +7 -0
- package/dist/components/visually-hidden.d.ts +22 -0
- package/dist/components/visually-hidden.js +31 -0
- package/dist/fonts/LICENSE-inter.txt +93 -0
- package/dist/fonts/LICENSE-red-hat-mono.txt +93 -0
- package/dist/fonts/fonts.css +111 -0
- package/dist/fonts/inter-cyrillic-ext-wght-normal.woff2 +0 -0
- package/dist/fonts/inter-cyrillic-wght-normal.woff2 +0 -0
- package/dist/fonts/inter-greek-ext-wght-normal.woff2 +0 -0
- package/dist/fonts/inter-greek-wght-normal.woff2 +0 -0
- package/dist/fonts/inter-latin-ext-wght-normal.woff2 +0 -0
- package/dist/fonts/inter-latin-wght-normal.woff2 +0 -0
- package/dist/fonts/inter-vietnamese-wght-normal.woff2 +0 -0
- package/dist/fonts/red-hat-mono-latin-ext-wght-normal.woff2 +0 -0
- package/dist/fonts/red-hat-mono-latin-wght-normal.woff2 +0 -0
- package/dist/marketing.css +289 -241
- package/package.json +18 -4
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
<!-- GENERATED from tooltip.contract.json. Do not edit. -->
|
|
2
|
+
|
|
3
|
+
# Tooltip
|
|
4
|
+
|
|
5
|
+
A brief description of the element it is anchored to, shown on demand.
|
|
6
|
+
|
|
7
|
+
## Use when
|
|
8
|
+
|
|
9
|
+
- Naming a control whose icon or abbreviation cannot say what it does
|
|
10
|
+
- Showing the full text of a value the layout has truncated
|
|
11
|
+
|
|
12
|
+
## Do not use
|
|
13
|
+
|
|
14
|
+
- The guidance is needed before the reader acts, rather than after they point at something → nothing here does this
|
|
15
|
+
- The message must persist, be dismissed, or contain something to press → nothing here does this
|
|
16
|
+
- Information the user must have to finish the task — a tooltip is invisible to anyone who never points at it, and absent entirely on touch
|
|
17
|
+
- Anything interactive — a tooltip cannot be focused, so a control inside it cannot be reached
|
|
18
|
+
- More than a sentence — this is a label, not a panel
|
|
19
|
+
- A tooltip that finds its own way out of the viewport's edge. The caret sits at one of twelve fixed points — three along each of the four edges — and the consumer names which one. TooltipAnchor holds the chip against the anchor so the named point is where the caret lands, and it still measures nothing: a chip whose named side has no room will overflow rather than move to the side that does.
|
|
20
|
+
- A Tooltip rendered on its own. `hidden` defaults to false, so a chip with nothing driving it is visible the moment it mounts, sitting in the layout rather than over it and pointing at nothing — and the aria-describedby that makes it a description belongs to the anchor, which a chip on its own does not have. Render it through TooltipAnchor, or drive it with useTooltip. See Behaviour below.
|
|
21
|
+
- Anything but text inside the chip. Composition allows `text` alone and names Button, Input and Card as forbidden: a control in there cannot be reached, and a Card in there is a panel wearing a label's clothes.
|
|
22
|
+
- Reporting that something failed. There is no danger ground here, on the same reasoning Badge gives for having none: those roles report what happened to a reader who did something, and a landing page's reader has not done anything yet. A tooltip is the wrong carrier for it besides — it is not on screen until it is pointed at, and on touch there is nothing to point with, so a message that matters is one a reader may never see.
|
|
23
|
+
|
|
24
|
+
## Anatomy
|
|
25
|
+
|
|
26
|
+
Tooltip renders 3 elements. A token binding names the part it applies to.
|
|
27
|
+
|
|
28
|
+
- `root` — `<div>`, class `dds-tooltip`. Holds the caret against the chip. Carries the axis attributes, which is the only place a consumer's prop can land and therefore the only place the caret can read them from. It is also the element that moves: the transition and the transform-origin are declared here, so the reveal's scale grows out of the edge facing the anchor instead of the chip's centre.
|
|
29
|
+
|
|
30
|
+
The chip is set at `font.body.sm` — fourteen — where Product's takes the default step. A tooltip is not the page: it is a sentence about something the reader is already looking at, and set at the same size as the copy it interrupts it reads as a second paragraph rather than as an aside. Smaller is also what keeps `size.tooltip.max` honest — the measure was chosen so the eye finds the start of the next line, and a wider glyph at the same measure gives fewer words per line to find it by.
|
|
31
|
+
- `caret` — `<svg>`, class `dds-tooltip__caret`. The triangle that points at the anchor. Takes its fill from the body's own background so the two read as one silhouette, and is not rendered at all when showCaret is false — an empty box of the caret's own bound size would hold the chip off its anchor by a caret nobody can see.
|
|
32
|
+
- `body` — `<div>`, class `dds-tooltip__body`. The chip — the surface the description sits on. Separate from the root because a caret has to sit outside the surface it points away from, and a caret inside the painted box is a notch rather than a point. Carries the width ceiling, so the measure is the same whichever edge the caret leaves from.
|
|
33
|
+
|
|
34
|
+
Apply these classes from the generated `tooltipParts` constant rather than writing the strings by hand.
|
|
35
|
+
|
|
36
|
+
## Composition
|
|
37
|
+
|
|
38
|
+
- Can contain: `text`
|
|
39
|
+
- Never contains: `Tooltip`, `Card`, `CardButton`, `Accordion`, `TabList` — in children or in any prop that takes a node
|
|
40
|
+
|
|
41
|
+
## Props
|
|
42
|
+
|
|
43
|
+
### placement — `top` | `right` | `bottom` | `left` (default `top`)
|
|
44
|
+
|
|
45
|
+
- `top` — The tooltip sits above its anchor, so the caret drops from the bottom edge to meet it
|
|
46
|
+
- `right` — The tooltip sits on the trailing side of its anchor — the right in English, the left in Arabic — so the caret reaches back across to meet it. The name is physical and the behaviour is logical: the chip's own direction mirrors this, caret and all
|
|
47
|
+
- `bottom` — The tooltip sits below its anchor, so the caret rises from the top edge to meet it
|
|
48
|
+
- `left` — The tooltip sits on the leading side of its anchor — the left in English, the right in Arabic — so the caret reaches across to meet it. The name is physical and the behaviour is logical: the chip's own direction mirrors this, caret and all
|
|
49
|
+
|
|
50
|
+
### alignment — `center` | `start` | `end` (default `center`)
|
|
51
|
+
|
|
52
|
+
- `center` — The chip is centred on its anchor and the caret's point lands on the middle of it. Use this unless the chip is much wider than the thing it points at
|
|
53
|
+
- `start` — The chip's leading edge lines up with the anchor's own, so a chip wider than its anchor grows away from it rather than back across the layout. For an anchor at the start of a row
|
|
54
|
+
- `end` — The mirror of start: the chip's trailing edge lines up with the anchor's, for an anchor at the end of a row
|
|
55
|
+
Never for: Moving a caret that is not there. With showCaret false nothing about the chip itself changes — though whatever places the chip still reads this to decide which of its edges meets the anchor's.
|
|
56
|
+
|
|
57
|
+
### hidden — `boolean` (default `false`)
|
|
58
|
+
|
|
59
|
+
Use when: Whatever reveals the tooltip has not revealed it yet, or has dismissed it. Defaults to false, which means visible — so something has to drive this, or the chip is simply on. Keeping it mounted and hidden rather than unmounting it is what lets it fade in, and what keeps the anchor's aria-describedby pointing at something real.
|
|
60
|
+
|
|
61
|
+
Flipping it is the whole animation. The chip fades from opacity.hidden and scales up from motion.scale.enter over motion.duration.fast on motion.easing.enter, growing out of the edge nearest its anchor rather than its own middle. The dismissal is not animated at all — transition-duration is motion.duration.instant while hidden, because by then the pointer has already gone somewhere else. Do not write a transition of your own: the stylesheet declares transition-property from what this axis changes, and a second declaration would both override that list and escape the prefers-reduced-motion guard generated with it.
|
|
62
|
+
Never for: Hiding a description the user still needs. A tooltip nobody can reveal is a sentence nobody reads — if it must always be legible it is helperText, not a tooltip.
|
|
63
|
+
|
|
64
|
+
### showCaret — `boolean` (default `true`)
|
|
65
|
+
|
|
66
|
+
Use when: Drawn by default. Leave it on whenever something holds the chip against its anchor — the point is what ties a floating description to the control it belongs to
|
|
67
|
+
Never for: A chip that whatever positions it does not hold against the anchor's edge, or an anchor unmistakable without one. A caret aimed at nothing is worse than no caret. With it off `alignment` is not dead — it still decides which of the chip's edges meets the anchor's; there is simply no point left for it to move.
|
|
68
|
+
|
|
69
|
+
Also accepts everything from `HTMLAttributes<HTMLDivElement>`.
|
|
70
|
+
|
|
71
|
+
## Behaviour
|
|
72
|
+
|
|
73
|
+
A tooltip does not reveal itself and does not place itself. useTooltip is the state machine that does the first: when the chip arrives, how long it waits before it does, what dismisses it, and the id the anchor points at with aria-describedby. TooltipAnchor is the wrapper that does the second, holding a trigger and its chip in one positioning context so the caret lands on the edge it is aimed at. Neither measures anything — the placement is the one the consumer names, and a chip with no room on that side overflows rather than flipping to the side that has some.
|
|
74
|
+
|
|
75
|
+
Reach for TooltipAnchor unless the trigger is something it cannot wrap. This is the usage the Example section below does not show — that one renders the chip alone, which is a different thing from a tooltip:
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
import { TooltipAnchor } from '@deriv-com/dds-product'
|
|
79
|
+
|
|
80
|
+
<TooltipAnchor content="Delete this row" placement="top">
|
|
81
|
+
<button type="button" aria-label="Delete">×</button>
|
|
82
|
+
</TooltipAnchor>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
It takes `content` — the description — and exactly one `children` element, which it clones to attach the pointer and focus handlers and the aria-describedby. That element has to be something focus can rest on: a button or a link, not a span, or the description is one no keyboard ever reaches. `placement`, `alignment`, `status` and `showCaret` pass straight through to the chip, and every useTooltip option is accepted here too.
|
|
86
|
+
|
|
87
|
+
Accessibility is the part neither the markup nor the props can carry alone. `role="tooltip"` is already on the chip, so do not add it. The `aria-describedby` that turns the chip into this control's description lives on the anchor, and only these two modules put it there — unconditionally, whether the chip is visible or not, because a reference that exists only while something is on screen is one assistive technology never sees. The accessible name is the children.
|
|
88
|
+
|
|
89
|
+
useTooltipDefaults holds what the options fall back to: `delay` 200ms before a reveal, `hideDelay` 0 before a dismissal, `focusTrigger` `auto` — keyboard focus only — and `isEnabled` true. Read that export rather than repeating the numbers.
|
|
90
|
+
|
|
91
|
+
Reach past TooltipAnchor to useTooltip when the trigger is not something a wrapper can hold. Spread its `anchorProps` on the trigger and its `tooltipProps` on the chip, and then place the chip yourself — the hook positions nothing.
|
|
92
|
+
|
|
93
|
+
- `useTooltip`, `useTooltipDefaults` — with `UseTooltipOptions`, `UseTooltipResult`
|
|
94
|
+
- `TooltipAnchor` — with `TooltipAnchorProps`
|
|
95
|
+
|
|
96
|
+
All from `@deriv-com/dds-marketing`, the same import as the component.
|
|
97
|
+
|
|
98
|
+
## Accessibility
|
|
99
|
+
|
|
100
|
+
Guaranteed by the component. Write none of it by hand: the ids these attributes point at are generated per instance, so an attribute set from outside either says the same thing twice or points at nothing.
|
|
101
|
+
|
|
102
|
+
- Announced as: `tooltip`
|
|
103
|
+
- an accessible name, which is the description itself
|
|
104
|
+
- the anchor points at this tooltip with aria-describedby, so the description is announced with the control it explains rather than never
|
|
105
|
+
|
|
106
|
+
## Rules
|
|
107
|
+
|
|
108
|
+
- **On a phone a section's actions stack and each fills the width, including when there is only one** — On a phone a page's actions stack, and each one fills the width. Not most of it, and not the width its label happens to need — the whole column.
|
|
109
|
+
|
|
110
|
+
Two side by side is what this replaces. On the narrowest screen each gets half a column minus the gap, which is rarely enough for a real label: the words wrap inside the pills, the two buttons come out different heights, and the pair reads as a broken row rather than as a choice. Stacked, each has the whole width and neither has to shorten its words to fit.
|
|
111
|
+
|
|
112
|
+
A single action fills too, and that is the part worth saying, because it is the one that looks unnecessary. A lone button has the room to sit at its natural width and still should not: a full-width control is the phone's convention for the thing the screen is asking you to do, and a pill hugging its label reads as one option among others that are not there. It also makes the target predictable — the whole width, wherever the thumb lands — which a centred pill does not.
|
|
113
|
+
|
|
114
|
+
Filling is the row's job rather than the button's. A button has no width of its own and is not given one; the row it sits in becomes a column and stretches its children, so nothing about the control changes and the same button is full width here and its own size on a desktop.
|
|
115
|
+
|
|
116
|
+
This is the phone's breakpoint, size.breakpoint.md, and not the wider one that decides whether a heading is centred. Those are different questions and they break at different widths: a heading stops being centred when the measure is the screen, while a button stops being full width much sooner than that — stretched across a tablet it is a long way from its own label, and a label centred in a metre of pill is harder to hit than one in a pill the size of the words.
|
|
117
|
+
|
|
118
|
+
What this is not about is every row of controls. A set of filter chips, a pagination strip, a toolbar, a link sitting after a sentence — none of these is the page asking for something, and stacking them to full width would turn a strip the eye skims into a list it has to read. The test is whether the row is the call to action the section was written for.
|
|
119
|
+
Guidance only — cannot be checked automatically.
|
|
120
|
+
- **Never nest one interactive element inside another** — Nested interactive elements produce ambiguous hit targets and an unreachable inner control for keyboard and screen-reader users. This is why the rule cannot live on any single component — it constrains Button, Link, Input and Switch simultaneously.
|
|
121
|
+
Guidance only — cannot be checked automatically.
|
|
122
|
+
- **A section that paints a ground sets the ink to go with it** — A page sits on color.bg.page, and a section that separates itself from it takes one of three grounds. color.bg.subtle is the light one and needs nothing further — the page's own ink still reads on it. The other two are dark and do not: color.bg.brand-strong takes color.fg.on-brand-strong, and color.bg.brand takes color.fg.on-solid. Both are white, and both are written as the role rather than the white they resolve to. Set one of those backgrounds without its ink and the text inherits whatever the page was already using, which is near-black on a dark band — legible to nobody, and invisible to every check here, because each pair passes contrast on its own and nothing can tell whether a section used both.
|
|
123
|
+
|
|
124
|
+
color.bg.brand carries a second limit that is not about forgetting. Its ink measures 3.39:1, which clears the 3:1 a heading needs and misses the 4.5:1 running copy needs. A coral band may carry a headline and a call to action; a paragraph on one is text the reader has to work through at a ratio the waiver on that role does not cover — the waiver says so itself. A section with copy in it takes color.bg.brand-strong, which is near-black and carries white at full contrast.
|
|
125
|
+
|
|
126
|
+
color.bg.strong is not a section ground. It is the inverted fill for an action that has to outrank what surrounds it, and the components that paint it — Button and ButtonIcon in their inverse form — already set both halves in one rule, which is the pattern a hand-painted section has to copy.
|
|
127
|
+
Guidance only — cannot be checked automatically.
|
|
128
|
+
- **Every gap inside a section names the relationship it expresses, and the same relationship keeps its measure when it turns on its side** — A section's spacing is named by the relationship it expresses, not chosen by size. Every gap in a section has a role token, and reaching for a step off the generic scale because it happens to be the right number is how two sections written by two people stop lining up: the numbers agree today and drift the first time one of them is tuned.
|
|
129
|
+
|
|
130
|
+
The heading group is three steps, not one gap. An eyebrow sits nearer its title than the title sits to its description, and the actions sit further from the description than either — space.heading.eyebrow-title, space.heading.title-description, space.heading.description-actions, in that order. A single `gap` on the group cannot say this; it sets all three the same and the block reads as evenly spaced lines rather than as a mark, a name and a paragraph. The eyebrow has to identify itself for this to work, because a group that opens with a title must not give its description the eyebrow's tighter step.
|
|
131
|
+
|
|
132
|
+
The step between a title and its description follows the size of the title, which is why there are two of it. What a reader sees is not the gap but the gap plus the leading above it, and leading scales with the type: under a display title the leading is most of the space, under a card's title it is half as deep. One value for both makes a card look loose at the size that made a section look right. So space.heading.title-description is the display step and space.heading.title-description-compact is the step at a card's size, and the choice is made by how big the title is rather than by what kind of block it sits in.
|
|
133
|
+
|
|
134
|
+
Every one of those steps is smaller than the gap below the group, and that ordering is what holds the group together as one thing. space.heading.content is the step between a heading group and the content it introduces, and it is the widest measure inside a section: the one gap the eye reads as a change of subject rather than as a continuation.
|
|
135
|
+
|
|
136
|
+
That step is the same whether the content is under the heading or beside it. A split is the same relationship turned on its side — a heading group and the content it introduces — so the space between the two halves is space.heading.content, not a gutter. When the split collapses to one column on a phone the gap becomes vertical again, which is where it started, and nothing has to change for that to be right.
|
|
137
|
+
|
|
138
|
+
space.grid.gutter is between two things of the same kind. Two cards in a row are the same kind; the two halves of a split are not, which is why the gutter is the wrong measure there even when the number would have looked acceptable. The gutter runs on both axes, so a grid reads as an even field rather than as rows with a seam down them.
|
|
139
|
+
|
|
140
|
+
space.inset.card is the card's, not the page's. A row of cards padded differently is a row of different cards, and the fill is the only edge they have. A page composing a row does not get to choose it.
|
|
141
|
+
|
|
142
|
+
Column count is not a breakpoint decision. A row holds as many columns as fit before a column would be narrower than size.grid.column-min, and drops one when they would not. Written as a fixed count that collapses at a breakpoint, a four-up row keeps four columns at every width above the phone and sets its copy two or three words to a line through the whole of the tablet range — and on a narrow desktop, which no breakpoint sits on at all. The threshold is a property of the row rather than of a card: a card fills whatever cell it is given.
|
|
143
|
+
|
|
144
|
+
What this does not cover is the space above and below a section, which is space.section.default and space.section.compact, and the page's own side margin, which is space.inset.page. Those are the section's outside; everything here is its inside.
|
|
145
|
+
Guidance only — cannot be checked automatically.
|
|
146
|
+
- **A section's title is centred over stacked content, starts beside content in columns, and starts on a phone** — Two arrangements, and the title's alignment is decided by which one it is introducing rather than chosen per section.
|
|
147
|
+
|
|
148
|
+
Content stacked under the title — a row of cards, an accordion, a set of steps — takes a centred title. The heading group and the block below it share one axis, so a centred title is symmetric with the thing it names, and the eye drops from the middle of the words to the middle of the set. A title starting at the left over a centred or full-width block reads as belonging to the first column rather than to all of them.
|
|
149
|
+
|
|
150
|
+
Content beside the title — a split, a picture in the other half, anything laid out in columns — takes a title that starts where its content starts. The two share a left edge, and that edge is what says they are one thing read across rather than two stacked. Centring the title there breaks the only alignment the reader has to hold the halves together, and it drifts further from its content the wider the page gets.
|
|
151
|
+
|
|
152
|
+
The heading group is what carries this, not the heading alone. An eyebrow, a title and a description are read as one block and align together; aligning the title without them leaves a centred heading over start-aligned copy, which reads as a mistake rather than as a choice.
|
|
153
|
+
|
|
154
|
+
Centred means all of it, not just the words. A badge, a row of actions, a picture — these are flex children, and a flex child is placed by align-items rather than by text-align, so a block that only sets the text leaves everything that is not text at the start. A hero is the case that shows it: its title and copy centred while its badge and its buttons did not.
|
|
155
|
+
|
|
156
|
+
A capped block centres itself as well as its words. A heading group takes size.heading-group.max, and a cap that is not centred leaves the measure at the start of the column with the words centred inside it — composed, and a long way left of the middle it appears to be in.
|
|
157
|
+
|
|
158
|
+
Both arrangements go to the start on a phone. A centred block reverts below the breakpoint, and the reason is the measure: on a phone the measure is the screen, so a centred title wraps to three or four ragged lines and the eye loses the left edge it was tracking — the same symmetry that reads as composure on a desktop is what makes it hard to scan on a phone. Centring there has to be asked for twice, and a section title is not one of the things that asks: it is centred because there is room for it, and on a phone there is not. Going back to the start means all of it too, and a capped block is the one that hides a leftover: its words go to the start while its measure stays in the middle of the column, which reads as a title still centred over a badge and buttons that are not — the box in the middle and the line inside it at the edge.
|
|
159
|
+
|
|
160
|
+
A hero is a section like any other: its badge, title, copy and actions are one stacked block, so it is centred on a desktop and starts on a phone with everything else.
|
|
161
|
+
|
|
162
|
+
What this is not about is a page whose body is a form or a document. A title over a sign-up form or a guide is not introducing a set of content — it is the first line of the thing itself, and it keeps the alignment the body has, which for running text is the start. The distinction is whether the block below is content the title names or content the title is part of.
|
|
163
|
+
Guidance only — cannot be checked automatically.
|
|
164
|
+
- **Anything a pointer has to hit is at least 24px in both directions** — A control sized by its contents is as big as its contents, and a glyph is chosen for how it reads rather than for how easily it is hit. An icon-only button with no padding is a 16px target — smaller than the pad of a finger, and smaller than the tremor of a hand using a mouse.
|
|
165
|
+
|
|
166
|
+
WCAG 2.2 asks for 24 by 24 CSS pixels at AA. The exceptions are narrower than they look: inline targets inside a sentence are exempt, and so is a small target with 24px of clear space around it — but a clear button sits against the field it empties, and a field is itself a target, so the spacing exemption does not apply to the case that keeps arising.
|
|
167
|
+
|
|
168
|
+
The target and the mark are separate decisions, and conflating them is what produces both faults. Growing the glyph to 24px makes it shout; leaving the button at 16px makes it hard to hit. So the glyph keeps the size that reads correctly beside its text, and the box around it declares a minimum of its own — which is what size.target.min is for.
|
|
169
|
+
|
|
170
|
+
Declared rather than emergent. Padding plus contents does clear 24px in several components today, and it is the weaker statement: it is a size nobody wrote down, so it moves when the type scale or the glyph does, and nothing says it was meant to be a target at all.
|
|
171
|
+
Guidance only — cannot be checked automatically.
|
|
172
|
+
|
|
173
|
+
## Anti-examples
|
|
174
|
+
|
|
175
|
+
❌ Tooltip for: The guidance is needed before the reader acts, rather than after they point at something
|
|
176
|
+
Nothing here does this, and it is the more common case on a marketing page. A tooltip is not on screen until it is asked for, and on touch there is nothing to hover — so anything a reader needs in order to decide belongs in the copy. Product answers this with a field's helperText; this package has no field yet, and when it does that will be the answer here too.
|
|
177
|
+
→ nothing in this system does this. Not a gap waiting to be filled — the case belongs outside it.
|
|
178
|
+
|
|
179
|
+
❌ Tooltip for: The message must persist, be dismissed, or contain something to press
|
|
180
|
+
Nothing here does this either. A tooltip cannot hold focus, so anything interactive inside one is unreachable by keyboard. Product reaches for a Popover; this package has none, and a marketing page wanting one usually wants a section of the page instead.
|
|
181
|
+
→ nothing in this system does this. Not a gap waiting to be filled — the case belongs outside it.
|
|
182
|
+
|
|
183
|
+
## Example
|
|
184
|
+
|
|
185
|
+
```tsx
|
|
186
|
+
import { Tooltip } from '@deriv-com/dds-marketing'
|
|
187
|
+
|
|
188
|
+
<Tooltip>Rates update every minute</Tooltip>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## In use
|
|
192
|
+
|
|
193
|
+
### The chip, and what it is not
|
|
194
|
+
|
|
195
|
+
A sentence about the thing it is anchored to, and never more than that. There is one ground: no danger, no success — a landing page reports nothing that a reader has done.
|
|
196
|
+
|
|
197
|
+
```tsx
|
|
198
|
+
import { Tooltip } from '@deriv-com/dds-marketing'
|
|
199
|
+
|
|
200
|
+
// Describing the control it belongs to
|
|
201
|
+
<Tooltip>Rates update every minute</Tooltip>
|
|
202
|
+
|
|
203
|
+
// Qualifying a claim the page has made
|
|
204
|
+
<Tooltip>Not available in every region</Tooltip>
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Which side it sits on
|
|
208
|
+
|
|
209
|
+
The side the consumer names. Nothing measures the room available, so a chip with none on that side overflows rather than flipping to the side that has some.
|
|
210
|
+
|
|
211
|
+
```tsx
|
|
212
|
+
import { Tooltip } from '@deriv-com/dds-marketing'
|
|
213
|
+
|
|
214
|
+
// Top — the default, caret dropping to the anchor
|
|
215
|
+
<Tooltip>No fee on deposits</Tooltip>
|
|
216
|
+
|
|
217
|
+
// Bottom — for an anchor near the top of the view
|
|
218
|
+
<Tooltip placement="bottom">No fee on deposits</Tooltip>
|
|
219
|
+
|
|
220
|
+
// Left — leading side, which mirrors in Arabic
|
|
221
|
+
<Tooltip placement="left">No fee on deposits</Tooltip>
|
|
222
|
+
|
|
223
|
+
// Right — trailing side, mirroring the same way
|
|
224
|
+
<Tooltip placement="right">No fee on deposits</Tooltip>
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Where it lines up
|
|
228
|
+
|
|
229
|
+
Which of the chip's edges meets the anchor's. Centre is right until the chip is much wider than the thing it points at — then it grows back across the layout instead of away from it.
|
|
230
|
+
|
|
231
|
+
```tsx
|
|
232
|
+
import { Tooltip } from '@deriv-com/dds-marketing'
|
|
233
|
+
|
|
234
|
+
// Centre — the default
|
|
235
|
+
<Tooltip>Based on the last 30 days</Tooltip>
|
|
236
|
+
|
|
237
|
+
// Start — for an anchor at the beginning of a row
|
|
238
|
+
<Tooltip alignment="start">Based on the last 30 days</Tooltip>
|
|
239
|
+
|
|
240
|
+
// End — the mirror, for an anchor at the row's end
|
|
241
|
+
<Tooltip alignment="end">Based on the last 30 days</Tooltip>
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### The caret
|
|
245
|
+
|
|
246
|
+
The point is what ties a floating description to the control it belongs to. No row for hidden: it paints nothing, and a blank specimen reads as a fault.
|
|
247
|
+
|
|
248
|
+
```tsx
|
|
249
|
+
import { Tooltip } from '@deriv-com/dds-marketing'
|
|
250
|
+
|
|
251
|
+
// Without a caret — nothing holds it to an edge
|
|
252
|
+
<Tooltip showCaret={false}>Delayed by 15 minutes</Tooltip>
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### When it wraps
|
|
256
|
+
|
|
257
|
+
The chip caps at size.tooltip.max and the text wraps inside it. The box does not shrink back to the wrapped lines — CSS settles a width before it breaks the text and never revisits it — so a sentence
|
|
258
|
+
|
|
259
|
+
```tsx
|
|
260
|
+
import { Tooltip } from '@deriv-com/dds-marketing'
|
|
261
|
+
|
|
262
|
+
// One line — the chip hugs its words
|
|
263
|
+
<Tooltip>Minimum deposit is $5</Tooltip>
|
|
264
|
+
|
|
265
|
+
// Two lines — the chip stays at its cap
|
|
266
|
+
<Tooltip>Verified within one working day</Tooltip>
|
|
267
|
+
```
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
<!-- GENERATED from typography.contract.json. Do not edit. -->
|
|
2
|
+
|
|
3
|
+
# Typography
|
|
4
|
+
|
|
5
|
+
Copy, set in one of the page's type roles. It is the component that finally separates what a line of text is in the document from how large it is drawn — `as` says the first and `variant` says the second, and neither implies the other.
|
|
6
|
+
|
|
7
|
+
That separation is the whole reason it exists. Every heading role in this package carries the same sentence — a size, not an instruction — because a page that wants a hero-sized line reaches for h1 and gets an <h1>, and the second one on the page is a document with two top-level headings. Here the scale is a prop and the element is a different prop, so a section heading set at hero scale is `as="h2" variant="h1"` and says exactly that.
|
|
8
|
+
|
|
9
|
+
It sets type and nothing else. No colour, which the container paints and this inherits; no margin, which belongs to whatever is stacking the page — a paragraph that carries its own spacing argues with the gap around it, and the gap wins or the page is wrong.
|
|
10
|
+
|
|
11
|
+
## Use when
|
|
12
|
+
|
|
13
|
+
- A heading, a paragraph, or a caption on a marketing page — anything the page writes rather than a component draws
|
|
14
|
+
- A heading whose level and whose size disagree, which is most of them past the first section
|
|
15
|
+
- An eyebrow above a headline, where the capitals are a setting rather than something typed
|
|
16
|
+
|
|
17
|
+
## Do not use
|
|
18
|
+
|
|
19
|
+
- The text is inside a component that already sets its own type → nothing here does this
|
|
20
|
+
- The words are a control's name rather than copy → nothing here does this
|
|
21
|
+
- The page needs the text coloured, spaced or aligned → nothing here does this
|
|
22
|
+
- Choosing an element by picking a size. `as` is the document and `variant` is the scale — a page with six h1 elements is still wrong however it was set
|
|
23
|
+
- Carrying a token this does not offer. label and field-label belong to controls, and a paragraph set at a button's weight is a paragraph pretending to be one
|
|
24
|
+
|
|
25
|
+
## Anatomy
|
|
26
|
+
|
|
27
|
+
Typography renders one element.
|
|
28
|
+
|
|
29
|
+
- `root` — `<p>`, class `dds-typography`. The text, and the only element here. Its tag is the `as` prop rather than a fixed one, because what a line is in the document and how large it is drawn are two decisions and this component exists to keep them apart.
|
|
30
|
+
|
|
31
|
+
Its margin is unset. A browser gives <p> and every heading a margin of its own, which would arrive here as spacing nobody asked for and nothing in the contract could see — so the page's own gap is the only thing between two blocks of copy.
|
|
32
|
+
|
|
33
|
+
The figure variant is the one that sets a property no token holds. Its size and weight are font.figure like every other variant's are their own role, but tabular numerals are a literal here rather than a binding: a composite font token carries family, size, weight, line height and tracking and nothing else, and the numeric form is not a value that varies anyway. A figure is always tabular — that is most of what makes it a figure rather than a heading with a number in it, because a column of counts whose digits do not line up is a column the eye cannot compare.
|
|
34
|
+
|
|
35
|
+
Apply these classes from the generated `typographyParts` constant rather than writing the strings by hand.
|
|
36
|
+
|
|
37
|
+
## Composition
|
|
38
|
+
|
|
39
|
+
- Can contain: `text`
|
|
40
|
+
- Never contains: `Typography`, `Button`, `ButtonIcon`, `Card`, `CardButton`, `TextInput`, `TextArea`, `SearchInput` — in children or in any prop that takes a node
|
|
41
|
+
|
|
42
|
+
## Props
|
|
43
|
+
|
|
44
|
+
### variant — `h1` | `h2` | `h3` | `h4` | `h5` | `subtitle` | `body-lg` | `body-md` | `body-sm` | `eyebrow` | `figure` (default `body-md`)
|
|
45
|
+
|
|
46
|
+
- `h1` — The line a landing page is built around, and there is one of them
|
|
47
|
+
- `h2` — A headline opening a major section of a long page
|
|
48
|
+
- `h3` — A section heading under an h1 and h2
|
|
49
|
+
- `h4` — A subsection heading, the first step below the extrabold the larger headings carry
|
|
50
|
+
- `h5` — A label over a group of cards, a list, or a short block of copy
|
|
51
|
+
- `subtitle` — A secondary title under a heading — a pricing plan's name, a sub-feature group
|
|
52
|
+
- `body-lg` — An introductory paragraph under a headline, a hero description, a section intro
|
|
53
|
+
- `body-md` — The default, and most of the copy on a page — feature descriptions, article text
|
|
54
|
+
- `body-sm` — De-emphasised copy: legal lines, disclaimers, help text
|
|
55
|
+
- `eyebrow` — A category label above a headline — a section tag, a plan badge. Drawn in capitals by this component, so write it in the case it should be read in
|
|
56
|
+
- `figure` — A number that is the point of its block — a count, a total, a span of time — with a label under it
|
|
57
|
+
Never for: Picking an element. A variant is a size, and the element is `as`
|
|
58
|
+
|
|
59
|
+
### as — `p` | `span` | `h1` | `h2` | `h3` | `h4` | `h5` | `h6` (default `p`)
|
|
60
|
+
|
|
61
|
+
- `p` — The default, and any block of prose
|
|
62
|
+
- `span` — Text inside a sentence, or inside something that is already a block
|
|
63
|
+
- `h1` — The page's one document-level heading
|
|
64
|
+
- `h2` — A section heading
|
|
65
|
+
- `h3` — A heading under an h2
|
|
66
|
+
- `h4` — A heading under an h3
|
|
67
|
+
- `h5` — A heading under an h4
|
|
68
|
+
- `h6` — The deepest heading level
|
|
69
|
+
Never for: Anything interactive. A link is Link and a control is Button — an element that responds to a click needs a name, a focus ring and a keyboard route, none of which this has
|
|
70
|
+
|
|
71
|
+
Also accepts everything from `HTMLAttributes<HTMLElement>`.
|
|
72
|
+
|
|
73
|
+
## Accessibility
|
|
74
|
+
|
|
75
|
+
Guaranteed by the component. Write none of it by hand: the ids these attributes point at are generated per instance, so an attribute set from outside either says the same thing twice or points at nothing.
|
|
76
|
+
|
|
77
|
+
- the element is the one `as` names, so a heading is a heading in the accessibility tree whatever size it is drawn at
|
|
78
|
+
|
|
79
|
+
## Rules
|
|
80
|
+
|
|
81
|
+
- **On a phone a section's actions stack and each fills the width, including when there is only one** — On a phone a page's actions stack, and each one fills the width. Not most of it, and not the width its label happens to need — the whole column.
|
|
82
|
+
|
|
83
|
+
Two side by side is what this replaces. On the narrowest screen each gets half a column minus the gap, which is rarely enough for a real label: the words wrap inside the pills, the two buttons come out different heights, and the pair reads as a broken row rather than as a choice. Stacked, each has the whole width and neither has to shorten its words to fit.
|
|
84
|
+
|
|
85
|
+
A single action fills too, and that is the part worth saying, because it is the one that looks unnecessary. A lone button has the room to sit at its natural width and still should not: a full-width control is the phone's convention for the thing the screen is asking you to do, and a pill hugging its label reads as one option among others that are not there. It also makes the target predictable — the whole width, wherever the thumb lands — which a centred pill does not.
|
|
86
|
+
|
|
87
|
+
Filling is the row's job rather than the button's. A button has no width of its own and is not given one; the row it sits in becomes a column and stretches its children, so nothing about the control changes and the same button is full width here and its own size on a desktop.
|
|
88
|
+
|
|
89
|
+
This is the phone's breakpoint, size.breakpoint.md, and not the wider one that decides whether a heading is centred. Those are different questions and they break at different widths: a heading stops being centred when the measure is the screen, while a button stops being full width much sooner than that — stretched across a tablet it is a long way from its own label, and a label centred in a metre of pill is harder to hit than one in a pill the size of the words.
|
|
90
|
+
|
|
91
|
+
What this is not about is every row of controls. A set of filter chips, a pagination strip, a toolbar, a link sitting after a sentence — none of these is the page asking for something, and stacking them to full width would turn a strip the eye skims into a list it has to read. The test is whether the row is the call to action the section was written for.
|
|
92
|
+
Guidance only — cannot be checked automatically.
|
|
93
|
+
- **Never nest one interactive element inside another** — Nested interactive elements produce ambiguous hit targets and an unreachable inner control for keyboard and screen-reader users. This is why the rule cannot live on any single component — it constrains Button, Link, Input and Switch simultaneously.
|
|
94
|
+
Guidance only — cannot be checked automatically.
|
|
95
|
+
- **A section that paints a ground sets the ink to go with it** — A page sits on color.bg.page, and a section that separates itself from it takes one of three grounds. color.bg.subtle is the light one and needs nothing further — the page's own ink still reads on it. The other two are dark and do not: color.bg.brand-strong takes color.fg.on-brand-strong, and color.bg.brand takes color.fg.on-solid. Both are white, and both are written as the role rather than the white they resolve to. Set one of those backgrounds without its ink and the text inherits whatever the page was already using, which is near-black on a dark band — legible to nobody, and invisible to every check here, because each pair passes contrast on its own and nothing can tell whether a section used both.
|
|
96
|
+
|
|
97
|
+
color.bg.brand carries a second limit that is not about forgetting. Its ink measures 3.39:1, which clears the 3:1 a heading needs and misses the 4.5:1 running copy needs. A coral band may carry a headline and a call to action; a paragraph on one is text the reader has to work through at a ratio the waiver on that role does not cover — the waiver says so itself. A section with copy in it takes color.bg.brand-strong, which is near-black and carries white at full contrast.
|
|
98
|
+
|
|
99
|
+
color.bg.strong is not a section ground. It is the inverted fill for an action that has to outrank what surrounds it, and the components that paint it — Button and ButtonIcon in their inverse form — already set both halves in one rule, which is the pattern a hand-painted section has to copy.
|
|
100
|
+
Guidance only — cannot be checked automatically.
|
|
101
|
+
- **Every gap inside a section names the relationship it expresses, and the same relationship keeps its measure when it turns on its side** — A section's spacing is named by the relationship it expresses, not chosen by size. Every gap in a section has a role token, and reaching for a step off the generic scale because it happens to be the right number is how two sections written by two people stop lining up: the numbers agree today and drift the first time one of them is tuned.
|
|
102
|
+
|
|
103
|
+
The heading group is three steps, not one gap. An eyebrow sits nearer its title than the title sits to its description, and the actions sit further from the description than either — space.heading.eyebrow-title, space.heading.title-description, space.heading.description-actions, in that order. A single `gap` on the group cannot say this; it sets all three the same and the block reads as evenly spaced lines rather than as a mark, a name and a paragraph. The eyebrow has to identify itself for this to work, because a group that opens with a title must not give its description the eyebrow's tighter step.
|
|
104
|
+
|
|
105
|
+
The step between a title and its description follows the size of the title, which is why there are two of it. What a reader sees is not the gap but the gap plus the leading above it, and leading scales with the type: under a display title the leading is most of the space, under a card's title it is half as deep. One value for both makes a card look loose at the size that made a section look right. So space.heading.title-description is the display step and space.heading.title-description-compact is the step at a card's size, and the choice is made by how big the title is rather than by what kind of block it sits in.
|
|
106
|
+
|
|
107
|
+
Every one of those steps is smaller than the gap below the group, and that ordering is what holds the group together as one thing. space.heading.content is the step between a heading group and the content it introduces, and it is the widest measure inside a section: the one gap the eye reads as a change of subject rather than as a continuation.
|
|
108
|
+
|
|
109
|
+
That step is the same whether the content is under the heading or beside it. A split is the same relationship turned on its side — a heading group and the content it introduces — so the space between the two halves is space.heading.content, not a gutter. When the split collapses to one column on a phone the gap becomes vertical again, which is where it started, and nothing has to change for that to be right.
|
|
110
|
+
|
|
111
|
+
space.grid.gutter is between two things of the same kind. Two cards in a row are the same kind; the two halves of a split are not, which is why the gutter is the wrong measure there even when the number would have looked acceptable. The gutter runs on both axes, so a grid reads as an even field rather than as rows with a seam down them.
|
|
112
|
+
|
|
113
|
+
space.inset.card is the card's, not the page's. A row of cards padded differently is a row of different cards, and the fill is the only edge they have. A page composing a row does not get to choose it.
|
|
114
|
+
|
|
115
|
+
Column count is not a breakpoint decision. A row holds as many columns as fit before a column would be narrower than size.grid.column-min, and drops one when they would not. Written as a fixed count that collapses at a breakpoint, a four-up row keeps four columns at every width above the phone and sets its copy two or three words to a line through the whole of the tablet range — and on a narrow desktop, which no breakpoint sits on at all. The threshold is a property of the row rather than of a card: a card fills whatever cell it is given.
|
|
116
|
+
|
|
117
|
+
What this does not cover is the space above and below a section, which is space.section.default and space.section.compact, and the page's own side margin, which is space.inset.page. Those are the section's outside; everything here is its inside.
|
|
118
|
+
Guidance only — cannot be checked automatically.
|
|
119
|
+
- **A section's title is centred over stacked content, starts beside content in columns, and starts on a phone** — Two arrangements, and the title's alignment is decided by which one it is introducing rather than chosen per section.
|
|
120
|
+
|
|
121
|
+
Content stacked under the title — a row of cards, an accordion, a set of steps — takes a centred title. The heading group and the block below it share one axis, so a centred title is symmetric with the thing it names, and the eye drops from the middle of the words to the middle of the set. A title starting at the left over a centred or full-width block reads as belonging to the first column rather than to all of them.
|
|
122
|
+
|
|
123
|
+
Content beside the title — a split, a picture in the other half, anything laid out in columns — takes a title that starts where its content starts. The two share a left edge, and that edge is what says they are one thing read across rather than two stacked. Centring the title there breaks the only alignment the reader has to hold the halves together, and it drifts further from its content the wider the page gets.
|
|
124
|
+
|
|
125
|
+
The heading group is what carries this, not the heading alone. An eyebrow, a title and a description are read as one block and align together; aligning the title without them leaves a centred heading over start-aligned copy, which reads as a mistake rather than as a choice.
|
|
126
|
+
|
|
127
|
+
Centred means all of it, not just the words. A badge, a row of actions, a picture — these are flex children, and a flex child is placed by align-items rather than by text-align, so a block that only sets the text leaves everything that is not text at the start. A hero is the case that shows it: its title and copy centred while its badge and its buttons did not.
|
|
128
|
+
|
|
129
|
+
A capped block centres itself as well as its words. A heading group takes size.heading-group.max, and a cap that is not centred leaves the measure at the start of the column with the words centred inside it — composed, and a long way left of the middle it appears to be in.
|
|
130
|
+
|
|
131
|
+
Both arrangements go to the start on a phone. A centred block reverts below the breakpoint, and the reason is the measure: on a phone the measure is the screen, so a centred title wraps to three or four ragged lines and the eye loses the left edge it was tracking — the same symmetry that reads as composure on a desktop is what makes it hard to scan on a phone. Centring there has to be asked for twice, and a section title is not one of the things that asks: it is centred because there is room for it, and on a phone there is not. Going back to the start means all of it too, and a capped block is the one that hides a leftover: its words go to the start while its measure stays in the middle of the column, which reads as a title still centred over a badge and buttons that are not — the box in the middle and the line inside it at the edge.
|
|
132
|
+
|
|
133
|
+
A hero is a section like any other: its badge, title, copy and actions are one stacked block, so it is centred on a desktop and starts on a phone with everything else.
|
|
134
|
+
|
|
135
|
+
What this is not about is a page whose body is a form or a document. A title over a sign-up form or a guide is not introducing a set of content — it is the first line of the thing itself, and it keeps the alignment the body has, which for running text is the start. The distinction is whether the block below is content the title names or content the title is part of.
|
|
136
|
+
Guidance only — cannot be checked automatically.
|
|
137
|
+
- **Anything a pointer has to hit is at least 24px in both directions** — A control sized by its contents is as big as its contents, and a glyph is chosen for how it reads rather than for how easily it is hit. An icon-only button with no padding is a 16px target — smaller than the pad of a finger, and smaller than the tremor of a hand using a mouse.
|
|
138
|
+
|
|
139
|
+
WCAG 2.2 asks for 24 by 24 CSS pixels at AA. The exceptions are narrower than they look: inline targets inside a sentence are exempt, and so is a small target with 24px of clear space around it — but a clear button sits against the field it empties, and a field is itself a target, so the spacing exemption does not apply to the case that keeps arising.
|
|
140
|
+
|
|
141
|
+
The target and the mark are separate decisions, and conflating them is what produces both faults. Growing the glyph to 24px makes it shout; leaving the button at 16px makes it hard to hit. So the glyph keeps the size that reads correctly beside its text, and the box around it declares a minimum of its own — which is what size.target.min is for.
|
|
142
|
+
|
|
143
|
+
Declared rather than emergent. Padding plus contents does clear 24px in several components today, and it is the weaker statement: it is a size nobody wrote down, so it moves when the type scale or the glyph does, and nothing says it was meant to be a target at all.
|
|
144
|
+
Guidance only — cannot be checked automatically.
|
|
145
|
+
|
|
146
|
+
## Anti-examples
|
|
147
|
+
|
|
148
|
+
❌ Typography for: The text is inside a component that already sets its own type
|
|
149
|
+
Button, Badge, Tab and the fields all bind their own roles. Wrapping their content in Text puts two type decisions on one line and the inner one wins silently.
|
|
150
|
+
→ nothing in this system does this. Not a gap waiting to be filled — the case belongs outside it.
|
|
151
|
+
|
|
152
|
+
❌ Typography for: The words are a control's name rather than copy
|
|
153
|
+
That is the control's own label prop. A control named by a nested element is one whose accessible name depends on what happens to be inside it.
|
|
154
|
+
→ nothing in this system does this. Not a gap waiting to be filled — the case belongs outside it.
|
|
155
|
+
|
|
156
|
+
❌ Typography for: The page needs the text coloured, spaced or aligned
|
|
157
|
+
The container. Colour is inherited here, margin is never set, and a component that owned either would disagree with the layout that placed it.
|
|
158
|
+
→ nothing in this system does this. Not a gap waiting to be filled — the case belongs outside it.
|
|
159
|
+
|
|
160
|
+
## Example
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
import { Typography } from '@deriv-com/dds-marketing'
|
|
164
|
+
|
|
165
|
+
<Typography variant="body-md">Trade the world's markets with a platform built for the way people actually trade.</Typography>
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## In use
|
|
169
|
+
|
|
170
|
+
### Headings
|
|
171
|
+
|
|
172
|
+
Five sizes, each a scale rather than a level. The element is a separate decision, which is the next block.
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
import { Typography } from '@deriv-com/dds-marketing'
|
|
176
|
+
|
|
177
|
+
// h1 — the line the page is built around
|
|
178
|
+
<Typography variant="h1" as="h1">Trade anywhere</Typography>
|
|
179
|
+
|
|
180
|
+
// h2 — a major section opens
|
|
181
|
+
<Typography variant="h2" as="h2">Why Deriv</Typography>
|
|
182
|
+
|
|
183
|
+
// h3 — a section under that
|
|
184
|
+
<Typography variant="h3" as="h3">Asset classes</Typography>
|
|
185
|
+
|
|
186
|
+
// h4 — a subsection
|
|
187
|
+
<Typography variant="h4" as="h4">Clear pricing</Typography>
|
|
188
|
+
|
|
189
|
+
// h5 — a label over a group
|
|
190
|
+
<Typography variant="h5" as="h5">Included</Typography>
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Elements
|
|
194
|
+
|
|
195
|
+
A page has one h1 as a document and many lines that want its size. Passing as and variant apart is what lets both be true at once.
|
|
196
|
+
|
|
197
|
+
```tsx
|
|
198
|
+
import { Typography } from '@deriv-com/dds-marketing'
|
|
199
|
+
|
|
200
|
+
// as h2, variant h1 — hero scale, second level
|
|
201
|
+
<Typography variant="h1" as="h2">Hero scale</Typography>
|
|
202
|
+
|
|
203
|
+
// as h6, variant h5 — deep level, readable size
|
|
204
|
+
<Typography variant="h5" as="h6">Deep heading</Typography>
|
|
205
|
+
|
|
206
|
+
// as p — a heading size on a paragraph is wrong
|
|
207
|
+
<Typography variant="subtitle" as="p">A paragraph</Typography>
|
|
208
|
+
|
|
209
|
+
// as span — inline, inside a sentence
|
|
210
|
+
<Typography variant="body-sm" as="span">inline aside</Typography>
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Body copy
|
|
214
|
+
|
|
215
|
+
One regular weight and one line height across the three, so this is body text set larger or smaller rather than three kinds of text.
|
|
216
|
+
|
|
217
|
+
```tsx
|
|
218
|
+
import { Typography } from '@deriv-com/dds-marketing'
|
|
219
|
+
|
|
220
|
+
// body-lg — an intro under a headline
|
|
221
|
+
<Typography variant="body-lg">The paragraph that follows a headline and carries the promise.</Typography>
|
|
222
|
+
|
|
223
|
+
// body-md — most of the page
|
|
224
|
+
<Typography variant="body-md">Feature descriptions, article copy, and anything else the page has to say at length.</Typography>
|
|
225
|
+
|
|
226
|
+
// body-sm — the fine print
|
|
227
|
+
<Typography variant="body-sm">Trading involves risk. Past performance is not indicative of future results.</Typography>
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Other roles
|
|
231
|
+
|
|
232
|
+
subtitle sits under a heading as a secondary title. eyebrow sits above one as a category, and draws its own capitals so the words stay in the case they were written.
|
|
233
|
+
|
|
234
|
+
```tsx
|
|
235
|
+
import { Typography } from '@deriv-com/dds-marketing'
|
|
236
|
+
|
|
237
|
+
// subtitle — a plan name, a group title
|
|
238
|
+
<Typography variant="subtitle">Standard account</Typography>
|
|
239
|
+
|
|
240
|
+
// eyebrow — written in sentence case, drawn in caps
|
|
241
|
+
<Typography variant="eyebrow" as="span">Now live</Typography>
|
|
242
|
+
|
|
243
|
+
// figure — a number, in fixed-width digits
|
|
244
|
+
<Typography variant="figure" as="span">9,482</Typography>
|
|
245
|
+
```
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<!-- GENERATED from accordion.contract.json. Do not edit. -->
|
|
2
|
+
|
|
3
|
+
# Accordion
|
|
4
|
+
|
|
5
|
+
A stack of rows whose headings stay and whose detail is put away until the reader asks for it. …
|
|
6
|
+
|
|
7
|
+
`import { Accordion } from '@deriv-com/dds-marketing'`
|
|
8
|
+
|
|
9
|
+
## Reach for it when
|
|
10
|
+
|
|
11
|
+
- Questions a reader asks near a decision — what it costs, whether their money is safe, how long a withdrawal takes. …
|
|
12
|
+
- The long version of something the page has already said shortly — specifications, trading hours, the full terms. …
|
|
13
|
+
- A run of rows at one depth in the page's outline, sitting under a section heading of their own
|
|
14
|
+
|
|
15
|
+
## Something else, when
|
|
16
|
+
|
|
17
|
+
- There is one thing to disclose rather than a set → **AccordionItem**
|
|
18
|
+
- The reader is meant to read all of it → **Card**
|
|
19
|
+
|
|
20
|
+
## Never
|
|
21
|
+
|
|
22
|
+
- Hiding what a reader has to know before deciding — a fee, a restriction, a condition on an offer. Disclosure a page is obliged to make is disclosure that stays on the page
|
|
23
|
+
- Navigation. A row that goes somewhere when pressed is a link wearing a chevron, and a reader who opens it expecting words gets a page instead
|
|
24
|
+
- A single row on its own. Two at least, because a heading is scanned against its neighbours and one heading has none
|
|
25
|
+
- Steps in a sequence. Rows here are independent and in no order — a reader may open the third without the first, and nothing about the set says otherwise
|
|
26
|
+
|
|
27
|
+
## Props
|
|
28
|
+
|
|
29
|
+
- **headingLevel** `enum` · default "3" — Where the rows sit in the page's outline. …
|
|
30
|
+
- `2` — The rows are the page's own sections, sitting directly under its title — a page that is nothing but questions is the case
|
|
31
|
+
- `3` — The default. The set sits under a section heading of its own, which is where an accordion usually is
|
|
32
|
+
- `4` — The set is inside a subsection that already carries a heading above it
|
|
33
|
+
- never: Making a row's words larger or smaller. The level is the outline, not the type: every row takes the same step whatever depth it sits at, because a question is a question wherever the set is on the page
|
|
34
|
+
|
|
35
|
+
## Inside it
|
|
36
|
+
|
|
37
|
+
- Takes only AccordionItem.
|
|
38
|
+
- At least 2, no ceiling — fewer is not this component and more is a different one.
|
|
39
|
+
- 3 components are refused inside it; the list and the reasons are in the long document.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
The reasoning behind each of these, the parts this renders, its states and snippets that compile: `.llm/components/accordion.md`.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<!-- GENERATED from accordionitem.contract.json. Do not edit. -->
|
|
2
|
+
|
|
3
|
+
# AccordionItem
|
|
4
|
+
|
|
5
|
+
One row of an Accordion: a heading that is always there, and the detail under it that is not. …
|
|
6
|
+
|
|
7
|
+
`import { AccordionItem } from '@deriv-com/dds-marketing'`
|
|
8
|
+
|
|
9
|
+
## Reach for it when
|
|
10
|
+
|
|
11
|
+
- One row inside an Accordion — every row of a set is one of these
|
|
12
|
+
- A single disclosure with no set around it: one topic whose detail is worth offering and not worth showing. …
|
|
13
|
+
|
|
14
|
+
## Something else, when
|
|
15
|
+
|
|
16
|
+
- The heading goes somewhere rather than opening something → **CardButton**
|
|
17
|
+
|
|
18
|
+
## Never
|
|
19
|
+
|
|
20
|
+
- A control inside the heading. The whole heading is one button, so a second one inside it is unreachable to a keyboard and ambiguous to a pointer — the rule about it is the one rule in this system that cannot live on any single component
|
|
21
|
+
- A heading that is a sentence. It is scanned against the rows above and below it, and a row nobody can scan is a row nobody opens
|
|
22
|
+
- Copy the reader is obliged to see. What is behind the control is what a reader goes looking for, not what the page needs them to have read
|
|
23
|
+
- A panel that holds another Accordion. Rows inside rows put a reader two folds deep with no way to see where they are, and the outline they navigate by stops describing the page
|
|
24
|
+
|
|
25
|
+
## Props
|
|
26
|
+
|
|
27
|
+
- **expanded** `boolean` · optional — Whether the panel is showing. Inside an Accordion this is injected on every render and the set owns it — a row cannot see its siblings, so it cannot know it is the one that should close. …
|
|
28
|
+
- never: Forcing a row open so its words are always visible. A panel that never shuts is copy behind a control that lies about what it does, and the reader who closes it once will not open it again. …
|
|
29
|
+
- **onExpandedChange** `callback` · optional — The page needs to know the row was pressed — to record which question was asked, or to hold the answer itself. …
|
|
30
|
+
- never: Doing something other than opening the row. It fires because a reader asked to see the words; navigating or submitting from it makes the chevron a lie
|
|
31
|
+
- **title** `string` · required — Always — it is the half of the row that is always on screen. A question in the reader's own words, or the name of the thing the panel details. …
|
|
32
|
+
- never: The answer, shortened. A heading that summarises the panel gives the reader no reason to open it, and a set of them is the long page again in smaller type
|
|
33
|
+
- **headingLevel** `enum` · default "3" — Where this row sits in the page's outline. Inside an Accordion it is injected, because every row of one set is at one depth by definition. Set it here only on a row standing alone
|
|
34
|
+
- `2` — The rows are the page's own sections. Set on the Accordion rather than here, which pushes it down
|
|
35
|
+
- `3` — The default, and where an accordion usually sits — under a section heading of its own
|
|
36
|
+
- `4` — The set is inside a subsection that already carries a heading
|
|
37
|
+
- never: Changing how large the words are. The level is the outline and the type is `font.subtitle` either way — a row at h2 is not a bigger question than a row at h4
|
|
38
|
+
|
|
39
|
+
## Inside it
|
|
40
|
+
|
|
41
|
+
- At least 1, no ceiling — fewer is not this component and more is a different one.
|
|
42
|
+
- 3 components are refused inside it; the list and the reasons are in the long document.
|
|
43
|
+
- Renders 7 parts: root, heading, trigger, title, marker, panel, content.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
The reasoning behind each of these, the parts this renders, its states and snippets that compile: `.llm/components/accordionitem.md`.
|