@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.
Files changed (460) hide show
  1. package/.llm/components/accordion.md +193 -0
  2. package/.llm/components/accordionitem.md +236 -0
  3. package/.llm/components/aspectratio.md +212 -0
  4. package/.llm/components/badge.md +231 -0
  5. package/.llm/components/bottomsheet.md +404 -0
  6. package/.llm/components/breadcrumb.md +197 -0
  7. package/.llm/components/breadcrumbitem.md +178 -0
  8. package/.llm/components/button.md +271 -0
  9. package/.llm/components/buttonicon.md +313 -0
  10. package/.llm/components/card.md +313 -0
  11. package/.llm/components/cardbody.md +409 -0
  12. package/.llm/components/cardbutton.md +259 -0
  13. package/.llm/components/checkbox.md +285 -0
  14. package/.llm/components/divider.md +230 -0
  15. package/.llm/components/dropdownmenu.md +453 -0
  16. package/.llm/components/filterchip.md +314 -0
  17. package/.llm/components/footer.md +408 -0
  18. package/.llm/components/footergroup.md +241 -0
  19. package/.llm/components/grid.md +659 -0
  20. package/.llm/components/icon.md +194 -0
  21. package/.llm/components/link.md +354 -0
  22. package/.llm/components/menuitem.md +218 -0
  23. package/.llm/components/navbar.md +458 -0
  24. package/.llm/components/navbaritem.md +238 -0
  25. package/.llm/components/navbarmenu.md +319 -0
  26. package/.llm/components/navbarmenugroup.md +184 -0
  27. package/.llm/components/navbarpanel.md +255 -0
  28. package/.llm/components/navbarswitcher.md +343 -0
  29. package/.llm/components/navbarswitcheroption.md +156 -0
  30. package/.llm/components/option.md +268 -0
  31. package/.llm/components/pagination.md +361 -0
  32. package/.llm/components/removablechip.md +247 -0
  33. package/.llm/components/row.md +381 -0
  34. package/.llm/components/scroller.md +470 -0
  35. package/.llm/components/searchinput.md +279 -0
  36. package/.llm/components/segmentedcontrol.md +358 -0
  37. package/.llm/components/segmentedcontrolitem.md +272 -0
  38. package/.llm/components/select.md +509 -0
  39. package/.llm/components/selectchip.md +334 -0
  40. package/.llm/components/spinner.md +222 -0
  41. package/.llm/components/stack.md +334 -0
  42. package/.llm/components/statusdot.md +205 -0
  43. package/.llm/components/subdomainnavbar.md +327 -0
  44. package/.llm/components/tab.md +291 -0
  45. package/.llm/components/table.md +660 -0
  46. package/.llm/components/tablebody.md +258 -0
  47. package/.llm/components/tablecell.md +248 -0
  48. package/.llm/components/tablehead.md +248 -0
  49. package/.llm/components/tableheadercell.md +298 -0
  50. package/.llm/components/tablerow.md +285 -0
  51. package/.llm/components/tablist.md +210 -0
  52. package/.llm/components/textarea.md +362 -0
  53. package/.llm/components/textinput.md +467 -0
  54. package/.llm/components/tooltip.md +267 -0
  55. package/.llm/components/typography.md +245 -0
  56. package/.llm/digest/accordion.md +43 -0
  57. package/.llm/digest/accordionitem.md +47 -0
  58. package/.llm/digest/aspectratio.md +47 -0
  59. package/.llm/digest/badge.md +45 -0
  60. package/.llm/digest/bottomsheet.md +69 -0
  61. package/.llm/digest/breadcrumb.md +38 -0
  62. package/.llm/digest/breadcrumbitem.md +43 -0
  63. package/.llm/digest/button.md +48 -0
  64. package/.llm/digest/buttonicon.md +61 -0
  65. package/.llm/digest/card.md +50 -0
  66. package/.llm/digest/cardbody.md +68 -0
  67. package/.llm/digest/cardbutton.md +49 -0
  68. package/.llm/digest/checkbox.md +63 -0
  69. package/.llm/digest/divider.md +52 -0
  70. package/.llm/digest/dropdownmenu.md +67 -0
  71. package/.llm/digest/filterchip.md +68 -0
  72. package/.llm/digest/footer.md +57 -0
  73. package/.llm/digest/footergroup.md +42 -0
  74. package/.llm/digest/grid.md +62 -0
  75. package/.llm/digest/icon.md +45 -0
  76. package/.llm/digest/link.md +59 -0
  77. package/.llm/digest/menuitem.md +46 -0
  78. package/.llm/digest/navbar.md +60 -0
  79. package/.llm/digest/navbaritem.md +54 -0
  80. package/.llm/digest/navbarmenu.md +54 -0
  81. package/.llm/digest/navbarmenugroup.md +40 -0
  82. package/.llm/digest/navbarpanel.md +53 -0
  83. package/.llm/digest/navbarswitcher.md +51 -0
  84. package/.llm/digest/navbarswitcheroption.md +37 -0
  85. package/.llm/digest/option.md +54 -0
  86. package/.llm/digest/pagination.md +71 -0
  87. package/.llm/digest/removablechip.md +51 -0
  88. package/.llm/digest/row.md +60 -0
  89. package/.llm/digest/scroller.md +59 -0
  90. package/.llm/digest/searchinput.md +56 -0
  91. package/.llm/digest/segmentedcontrol.md +59 -0
  92. package/.llm/digest/segmentedcontrolitem.md +59 -0
  93. package/.llm/digest/select.md +92 -0
  94. package/.llm/digest/selectchip.md +68 -0
  95. package/.llm/digest/spinner.md +52 -0
  96. package/.llm/digest/stack.md +56 -0
  97. package/.llm/digest/statusdot.md +46 -0
  98. package/.llm/digest/subdomainnavbar.md +54 -0
  99. package/.llm/digest/tab.md +60 -0
  100. package/.llm/digest/table.md +71 -0
  101. package/.llm/digest/tablebody.md +49 -0
  102. package/.llm/digest/tablecell.md +55 -0
  103. package/.llm/digest/tablehead.md +50 -0
  104. package/.llm/digest/tableheadercell.md +65 -0
  105. package/.llm/digest/tablerow.md +56 -0
  106. package/.llm/digest/tablist.md +46 -0
  107. package/.llm/digest/textarea.md +78 -0
  108. package/.llm/digest/textinput.md +95 -0
  109. package/.llm/digest/tooltip.md +58 -0
  110. package/.llm/digest/typography.md +59 -0
  111. package/.llm/index.md +86 -0
  112. package/.llm/rules.md +122 -0
  113. package/.llm/tokens.md +341 -0
  114. package/AGENTS.md +164 -0
  115. package/LICENSE +21 -0
  116. package/README.md +63 -15
  117. package/dist/components/core/accordion/Accordion.css +10 -0
  118. package/dist/components/core/accordion/Accordion.d.ts +20 -0
  119. package/dist/components/core/accordion/Accordion.js +69 -0
  120. package/dist/components/core/accordion/Accordion.types.d.ts +20 -0
  121. package/dist/components/core/accordion/Accordion.types.js +7 -0
  122. package/dist/components/core/accordion-item/AccordionItem.css +98 -0
  123. package/dist/components/core/accordion-item/AccordionItem.d.ts +44 -0
  124. package/dist/components/core/accordion-item/AccordionItem.js +63 -0
  125. package/dist/components/core/accordion-item/AccordionItem.types.d.ts +32 -0
  126. package/dist/components/core/accordion-item/AccordionItem.types.js +13 -0
  127. package/dist/components/core/accordion-item/accordion-item-impl.css +107 -0
  128. package/dist/components/core/badge/Badge.css +37 -0
  129. package/dist/components/core/badge/Badge.d.ts +37 -0
  130. package/dist/components/core/badge/Badge.js +40 -0
  131. package/dist/components/core/badge/Badge.types.d.ts +24 -0
  132. package/dist/components/core/badge/Badge.types.js +8 -0
  133. package/dist/components/core/badge/badge-impl.css +32 -0
  134. package/dist/components/core/bottom-sheet/BottomSheet.css +178 -0
  135. package/dist/components/core/bottom-sheet/BottomSheet.d.ts +22 -0
  136. package/dist/components/core/bottom-sheet/BottomSheet.js +359 -0
  137. package/dist/components/core/bottom-sheet/BottomSheet.types.d.ts +67 -0
  138. package/dist/components/core/bottom-sheet/BottomSheet.types.js +18 -0
  139. package/dist/components/core/bottom-sheet/bottom-sheet-impl.css +57 -0
  140. package/dist/components/core/breadcrumb/Breadcrumb.css +19 -0
  141. package/dist/components/core/breadcrumb/Breadcrumb.d.ts +16 -0
  142. package/dist/components/core/breadcrumb/Breadcrumb.js +22 -0
  143. package/dist/components/core/breadcrumb/Breadcrumb.types.d.ts +18 -0
  144. package/dist/components/core/breadcrumb/Breadcrumb.types.js +9 -0
  145. package/dist/components/core/breadcrumb-item/BreadcrumbItem.css +34 -0
  146. package/dist/components/core/breadcrumb-item/BreadcrumbItem.d.ts +12 -0
  147. package/dist/components/core/breadcrumb-item/BreadcrumbItem.js +15 -0
  148. package/dist/components/core/breadcrumb-item/BreadcrumbItem.types.d.ts +22 -0
  149. package/dist/components/core/breadcrumb-item/BreadcrumbItem.types.js +9 -0
  150. package/dist/components/core/button/Button.css +141 -0
  151. package/dist/components/core/button/Button.d.ts +25 -0
  152. package/dist/components/core/button/Button.js +28 -0
  153. package/dist/components/core/button/Button.types.d.ts +40 -0
  154. package/dist/components/core/button/Button.types.js +9 -0
  155. package/dist/components/core/button/button-impl.css +46 -0
  156. package/dist/components/core/button-icon/ButtonIcon.css +135 -0
  157. package/dist/components/core/button-icon/ButtonIcon.d.ts +34 -0
  158. package/dist/components/core/button-icon/ButtonIcon.js +117 -0
  159. package/dist/components/core/button-icon/ButtonIcon.types.d.ts +41 -0
  160. package/dist/components/core/button-icon/ButtonIcon.types.js +8 -0
  161. package/dist/components/core/card/Card.css +65 -0
  162. package/dist/components/core/card/Card.d.ts +24 -0
  163. package/dist/components/core/card/Card.js +26 -0
  164. package/dist/components/core/card/Card.types.d.ts +33 -0
  165. package/dist/components/core/card/Card.types.js +7 -0
  166. package/dist/components/core/card-body/CardBody.css +139 -0
  167. package/dist/components/core/card-body/CardBody.d.ts +62 -0
  168. package/dist/components/core/card-body/CardBody.js +97 -0
  169. package/dist/components/core/card-body/CardBody.types.d.ts +61 -0
  170. package/dist/components/core/card-body/CardBody.types.js +15 -0
  171. package/dist/components/core/card-body/card-body-impl.css +87 -0
  172. package/dist/components/core/card-button/CardButton.css +73 -0
  173. package/dist/components/core/card-button/CardButton.d.ts +27 -0
  174. package/dist/components/core/card-button/CardButton.js +37 -0
  175. package/dist/components/core/card-button/CardButton.types.d.ts +24 -0
  176. package/dist/components/core/card-button/CardButton.types.js +7 -0
  177. package/dist/components/core/card-button/card-button-impl.css +39 -0
  178. package/dist/components/core/checkbox/Checkbox.css +149 -0
  179. package/dist/components/core/checkbox/Checkbox.d.ts +21 -0
  180. package/dist/components/core/checkbox/Checkbox.js +97 -0
  181. package/dist/components/core/checkbox/Checkbox.types.d.ts +46 -0
  182. package/dist/components/core/checkbox/Checkbox.types.js +15 -0
  183. package/dist/components/core/checkbox/checkbox-impl.css +90 -0
  184. package/dist/components/core/divider/Divider.css +41 -0
  185. package/dist/components/core/divider/Divider.d.ts +46 -0
  186. package/dist/components/core/divider/Divider.js +51 -0
  187. package/dist/components/core/divider/Divider.types.d.ts +25 -0
  188. package/dist/components/core/divider/Divider.types.js +9 -0
  189. package/dist/components/core/dropdown-menu/DropdownMenu.css +146 -0
  190. package/dist/components/core/dropdown-menu/DropdownMenu.d.ts +22 -0
  191. package/dist/components/core/dropdown-menu/DropdownMenu.js +309 -0
  192. package/dist/components/core/dropdown-menu/DropdownMenu.types.d.ts +62 -0
  193. package/dist/components/core/dropdown-menu/DropdownMenu.types.js +12 -0
  194. package/dist/components/core/dropdown-menu/dropdown-menu-impl.css +70 -0
  195. package/dist/components/core/filter-chip/FilterChip.css +149 -0
  196. package/dist/components/core/filter-chip/FilterChip.d.ts +23 -0
  197. package/dist/components/core/filter-chip/FilterChip.js +37 -0
  198. package/dist/components/core/filter-chip/FilterChip.types.d.ts +53 -0
  199. package/dist/components/core/filter-chip/FilterChip.types.js +12 -0
  200. package/dist/components/core/footer/Footer.css +104 -0
  201. package/dist/components/core/footer/Footer.d.ts +43 -0
  202. package/dist/components/core/footer/Footer.js +53 -0
  203. package/dist/components/core/footer/Footer.types.d.ts +47 -0
  204. package/dist/components/core/footer/Footer.types.js +18 -0
  205. package/dist/components/core/footer/footer-impl.css +218 -0
  206. package/dist/components/core/footer-group/FooterGroup.css +90 -0
  207. package/dist/components/core/footer-group/FooterGroup.d.ts +32 -0
  208. package/dist/components/core/footer-group/FooterGroup.js +64 -0
  209. package/dist/components/core/footer-group/FooterGroup.types.d.ts +25 -0
  210. package/dist/components/core/footer-group/FooterGroup.types.js +12 -0
  211. package/dist/components/core/footer-group/footer-group-impl.css +78 -0
  212. package/dist/components/core/icon/Icon.css +40 -0
  213. package/dist/components/core/icon/Icon.d.ts +23 -0
  214. package/dist/components/core/icon/Icon.js +79 -0
  215. package/dist/components/core/icon/Icon.types.d.ts +24 -0
  216. package/dist/components/core/icon/Icon.types.js +7 -0
  217. package/dist/components/core/link/Link.css +89 -0
  218. package/dist/components/core/link/Link.d.ts +37 -0
  219. package/dist/components/core/link/Link.js +141 -0
  220. package/dist/components/core/link/Link.types.d.ts +41 -0
  221. package/dist/components/core/link/Link.types.js +9 -0
  222. package/dist/components/core/link/link-impl.css +168 -0
  223. package/dist/components/core/menu-item/MenuItem.css +70 -0
  224. package/dist/components/core/menu-item/MenuItem.d.ts +11 -0
  225. package/dist/components/core/menu-item/MenuItem.js +26 -0
  226. package/dist/components/core/menu-item/MenuItem.types.d.ts +28 -0
  227. package/dist/components/core/menu-item/MenuItem.types.js +9 -0
  228. package/dist/components/core/navbar/Navbar.css +135 -0
  229. package/dist/components/core/navbar/Navbar.d.ts +36 -0
  230. package/dist/components/core/navbar/Navbar.js +371 -0
  231. package/dist/components/core/navbar/Navbar.types.d.ts +49 -0
  232. package/dist/components/core/navbar/Navbar.types.js +17 -0
  233. package/dist/components/core/navbar/navbar-impl.css +590 -0
  234. package/dist/components/core/navbar-item/NavbarItem.css +75 -0
  235. package/dist/components/core/navbar-item/NavbarItem.d.ts +22 -0
  236. package/dist/components/core/navbar-item/NavbarItem.js +40 -0
  237. package/dist/components/core/navbar-item/NavbarItem.types.d.ts +34 -0
  238. package/dist/components/core/navbar-item/NavbarItem.types.js +10 -0
  239. package/dist/components/core/navbar-menu/NavbarMenu.css +128 -0
  240. package/dist/components/core/navbar-menu/NavbarMenu.d.ts +5 -0
  241. package/dist/components/core/navbar-menu/NavbarMenu.js +186 -0
  242. package/dist/components/core/navbar-menu/NavbarMenu.types.d.ts +45 -0
  243. package/dist/components/core/navbar-menu/NavbarMenu.types.js +12 -0
  244. package/dist/components/core/navbar-menu/navbar-menu-impl.css +186 -0
  245. package/dist/components/core/navbar-menu-group/NavbarMenuGroup.css +26 -0
  246. package/dist/components/core/navbar-menu-group/NavbarMenuGroup.d.ts +17 -0
  247. package/dist/components/core/navbar-menu-group/NavbarMenuGroup.js +22 -0
  248. package/dist/components/core/navbar-menu-group/NavbarMenuGroup.types.d.ts +14 -0
  249. package/dist/components/core/navbar-menu-group/NavbarMenuGroup.types.js +7 -0
  250. package/dist/components/core/navbar-panel/NavbarPanel.css +87 -0
  251. package/dist/components/core/navbar-panel/NavbarPanel.d.ts +34 -0
  252. package/dist/components/core/navbar-panel/NavbarPanel.js +46 -0
  253. package/dist/components/core/navbar-panel/NavbarPanel.types.d.ts +29 -0
  254. package/dist/components/core/navbar-panel/NavbarPanel.types.js +12 -0
  255. package/dist/components/core/navbar-panel/navbar-panel-impl.css +104 -0
  256. package/dist/components/core/navbar-panel/use-navbar-panel.d.ts +26 -0
  257. package/dist/components/core/navbar-panel/use-navbar-panel.js +135 -0
  258. package/dist/components/core/navbar-switcher/NavbarSwitcher.css +117 -0
  259. package/dist/components/core/navbar-switcher/NavbarSwitcher.d.ts +20 -0
  260. package/dist/components/core/navbar-switcher/NavbarSwitcher.js +90 -0
  261. package/dist/components/core/navbar-switcher/NavbarSwitcher.types.d.ts +46 -0
  262. package/dist/components/core/navbar-switcher/NavbarSwitcher.types.js +13 -0
  263. package/dist/components/core/navbar-switcher/navbar-switcher-impl.css +179 -0
  264. package/dist/components/core/navbar-switcher-option/NavbarSwitcherOption.css +39 -0
  265. package/dist/components/core/navbar-switcher-option/NavbarSwitcherOption.d.ts +16 -0
  266. package/dist/components/core/navbar-switcher-option/NavbarSwitcherOption.js +19 -0
  267. package/dist/components/core/navbar-switcher-option/NavbarSwitcherOption.types.d.ts +18 -0
  268. package/dist/components/core/navbar-switcher-option/NavbarSwitcherOption.types.js +7 -0
  269. package/dist/components/core/option/Option.css +133 -0
  270. package/dist/components/core/option/Option.d.ts +25 -0
  271. package/dist/components/core/option/Option.js +31 -0
  272. package/dist/components/core/option/Option.types.d.ts +44 -0
  273. package/dist/components/core/option/Option.types.js +14 -0
  274. package/dist/components/core/pagination/Pagination.css +237 -0
  275. package/dist/components/core/pagination/Pagination.d.ts +30 -0
  276. package/dist/components/core/pagination/Pagination.js +406 -0
  277. package/dist/components/core/pagination/Pagination.types.d.ts +59 -0
  278. package/dist/components/core/pagination/Pagination.types.js +14 -0
  279. package/dist/components/core/pagination/pagination-impl.css +17 -0
  280. package/dist/components/core/removable-chip/RemovableChip.css +125 -0
  281. package/dist/components/core/removable-chip/RemovableChip.d.ts +25 -0
  282. package/dist/components/core/removable-chip/RemovableChip.js +36 -0
  283. package/dist/components/core/removable-chip/RemovableChip.types.d.ts +38 -0
  284. package/dist/components/core/removable-chip/RemovableChip.types.js +13 -0
  285. package/dist/components/core/search-input/SearchInput.css +205 -0
  286. package/dist/components/core/search-input/SearchInput.d.ts +5 -0
  287. package/dist/components/core/search-input/SearchInput.js +81 -0
  288. package/dist/components/core/search-input/SearchInput.types.d.ts +43 -0
  289. package/dist/components/core/search-input/SearchInput.types.js +13 -0
  290. package/dist/components/core/search-input/search-input-impl.css +20 -0
  291. package/dist/components/core/segmented-control/SegmentedControl.css +57 -0
  292. package/dist/components/core/segmented-control/SegmentedControl.d.ts +37 -0
  293. package/dist/components/core/segmented-control/SegmentedControl.js +269 -0
  294. package/dist/components/core/segmented-control/SegmentedControl.types.d.ts +38 -0
  295. package/dist/components/core/segmented-control/SegmentedControl.types.js +8 -0
  296. package/dist/components/core/segmented-control/segmented-control-impl.css +57 -0
  297. package/dist/components/core/segmented-control-item/SegmentedControlItem.css +151 -0
  298. package/dist/components/core/segmented-control-item/SegmentedControlItem.d.ts +50 -0
  299. package/dist/components/core/segmented-control-item/SegmentedControlItem.js +101 -0
  300. package/dist/components/core/segmented-control-item/SegmentedControlItem.types.d.ts +37 -0
  301. package/dist/components/core/segmented-control-item/SegmentedControlItem.types.js +10 -0
  302. package/dist/components/core/segmented-control-item/segmented-control-item-impl.css +69 -0
  303. package/dist/components/core/select/Select.css +400 -0
  304. package/dist/components/core/select/Select.d.ts +29 -0
  305. package/dist/components/core/select/Select.js +524 -0
  306. package/dist/components/core/select/Select.types.d.ts +96 -0
  307. package/dist/components/core/select/Select.types.js +26 -0
  308. package/dist/components/core/select/select-impl.css +114 -0
  309. package/dist/components/core/select-chip/SelectChip.css +155 -0
  310. package/dist/components/core/select-chip/SelectChip.d.ts +20 -0
  311. package/dist/components/core/select-chip/SelectChip.js +273 -0
  312. package/dist/components/core/select-chip/SelectChip.types.d.ts +56 -0
  313. package/dist/components/core/select-chip/SelectChip.types.js +14 -0
  314. package/dist/components/core/select-chip/select-chip-impl.css +38 -0
  315. package/dist/components/core/spinner/Spinner.css +76 -0
  316. package/dist/components/core/spinner/Spinner.d.ts +5 -0
  317. package/dist/components/core/spinner/Spinner.js +29 -0
  318. package/dist/components/core/spinner/Spinner.types.d.ts +37 -0
  319. package/dist/components/core/spinner/Spinner.types.js +10 -0
  320. package/dist/components/core/spinner/spinner-impl.css +27 -0
  321. package/dist/components/core/status-dot/StatusDot.css +43 -0
  322. package/dist/components/core/status-dot/StatusDot.d.ts +35 -0
  323. package/dist/components/core/status-dot/StatusDot.js +46 -0
  324. package/dist/components/core/status-dot/StatusDot.types.d.ts +29 -0
  325. package/dist/components/core/status-dot/StatusDot.types.js +7 -0
  326. package/dist/components/core/status-dot/status-dot-impl.css +42 -0
  327. package/dist/components/core/subdomain-navbar/SubdomainNavbar.css +89 -0
  328. package/dist/components/core/subdomain-navbar/SubdomainNavbar.d.ts +21 -0
  329. package/dist/components/core/subdomain-navbar/SubdomainNavbar.js +127 -0
  330. package/dist/components/core/subdomain-navbar/SubdomainNavbar.types.d.ts +43 -0
  331. package/dist/components/core/subdomain-navbar/SubdomainNavbar.types.js +13 -0
  332. package/dist/components/core/subdomain-navbar/subdomain-navbar-impl.css +147 -0
  333. package/dist/components/core/tab/Tab.css +113 -0
  334. package/dist/components/core/tab/Tab.d.ts +36 -0
  335. package/dist/components/core/tab/Tab.js +53 -0
  336. package/dist/components/core/tab/Tab.types.d.ts +42 -0
  337. package/dist/components/core/tab/Tab.types.js +13 -0
  338. package/dist/components/core/tab/tab-impl.css +49 -0
  339. package/dist/components/core/tab-list/TabList.css +40 -0
  340. package/dist/components/core/tab-list/TabList.d.ts +26 -0
  341. package/dist/components/core/tab-list/TabList.js +124 -0
  342. package/dist/components/core/tab-list/TabList.types.d.ts +20 -0
  343. package/dist/components/core/tab-list/TabList.types.js +7 -0
  344. package/dist/components/core/tab-list/tab-list-impl.css +56 -0
  345. package/dist/components/core/table/Table.css +40 -0
  346. package/dist/components/core/table/Table.d.ts +19 -0
  347. package/dist/components/core/table/Table.js +55 -0
  348. package/dist/components/core/table/Table.types.d.ts +59 -0
  349. package/dist/components/core/table/Table.types.js +9 -0
  350. package/dist/components/core/table/table-impl.css +75 -0
  351. package/dist/components/core/table/use-table-sort.d.ts +43 -0
  352. package/dist/components/core/table/use-table-sort.js +51 -0
  353. package/dist/components/core/table-body/TableBody.css +6 -0
  354. package/dist/components/core/table-body/TableBody.d.ts +12 -0
  355. package/dist/components/core/table-body/TableBody.js +26 -0
  356. package/dist/components/core/table-body/TableBody.types.d.ts +36 -0
  357. package/dist/components/core/table-body/TableBody.types.js +7 -0
  358. package/dist/components/core/table-cell/TableCell.css +76 -0
  359. package/dist/components/core/table-cell/TableCell.d.ts +21 -0
  360. package/dist/components/core/table-cell/TableCell.js +31 -0
  361. package/dist/components/core/table-cell/TableCell.types.d.ts +43 -0
  362. package/dist/components/core/table-cell/TableCell.types.js +7 -0
  363. package/dist/components/core/table-head/TableHead.css +6 -0
  364. package/dist/components/core/table-head/TableHead.d.ts +22 -0
  365. package/dist/components/core/table-head/TableHead.js +52 -0
  366. package/dist/components/core/table-head/TableHead.types.d.ts +39 -0
  367. package/dist/components/core/table-head/TableHead.types.js +7 -0
  368. package/dist/components/core/table-head/table-head-impl.css +51 -0
  369. package/dist/components/core/table-header-cell/TableHeaderCell.css +126 -0
  370. package/dist/components/core/table-header-cell/TableHeaderCell.d.ts +21 -0
  371. package/dist/components/core/table-header-cell/TableHeaderCell.js +34 -0
  372. package/dist/components/core/table-header-cell/TableHeaderCell.types.d.ts +56 -0
  373. package/dist/components/core/table-header-cell/TableHeaderCell.types.js +9 -0
  374. package/dist/components/core/table-header-cell/table-header-cell-impl.css +74 -0
  375. package/dist/components/core/table-row/TableRow.css +18 -0
  376. package/dist/components/core/table-row/TableRow.d.ts +17 -0
  377. package/dist/components/core/table-row/TableRow.js +32 -0
  378. package/dist/components/core/table-row/TableRow.types.d.ts +45 -0
  379. package/dist/components/core/table-row/TableRow.types.js +7 -0
  380. package/dist/components/core/table-row/table-row-impl.css +31 -0
  381. package/dist/components/core/text-area/TextArea.css +325 -0
  382. package/dist/components/core/text-area/TextArea.d.ts +13 -0
  383. package/dist/components/core/text-area/TextArea.js +133 -0
  384. package/dist/components/core/text-area/TextArea.types.d.ts +67 -0
  385. package/dist/components/core/text-area/TextArea.types.js +19 -0
  386. package/dist/components/core/text-area/text-area-impl.css +36 -0
  387. package/dist/components/core/text-input/TextInput.css +400 -0
  388. package/dist/components/core/text-input/TextInput.d.ts +5 -0
  389. package/dist/components/core/text-input/TextInput.js +130 -0
  390. package/dist/components/core/text-input/TextInput.types.d.ts +96 -0
  391. package/dist/components/core/text-input/TextInput.types.js +24 -0
  392. package/dist/components/core/text-input/text-input-impl.css +36 -0
  393. package/dist/components/core/tooltip/Tooltip.css +101 -0
  394. package/dist/components/core/tooltip/Tooltip.d.ts +51 -0
  395. package/dist/components/core/tooltip/Tooltip.js +87 -0
  396. package/dist/components/core/tooltip/Tooltip.types.d.ts +38 -0
  397. package/dist/components/core/tooltip/Tooltip.types.js +9 -0
  398. package/dist/components/core/tooltip/TooltipAnchor.d.ts +52 -0
  399. package/dist/components/core/tooltip/TooltipAnchor.js +69 -0
  400. package/dist/components/core/tooltip/tooltip-anchor.css +145 -0
  401. package/dist/components/core/tooltip/tooltip-impl.css +54 -0
  402. package/dist/components/core/tooltip/use-tooltip.d.ts +111 -0
  403. package/dist/components/core/tooltip/use-tooltip.js +189 -0
  404. package/dist/components/core/typography/Typography.css +96 -0
  405. package/dist/components/core/typography/Typography.d.ts +297 -0
  406. package/dist/components/core/typography/Typography.js +28 -0
  407. package/dist/components/core/typography/Typography.types.d.ts +40 -0
  408. package/dist/components/core/typography/Typography.types.js +7 -0
  409. package/dist/components/css-time.d.ts +20 -0
  410. package/dist/components/css-time.js +30 -0
  411. package/dist/components/given.d.ts +7 -0
  412. package/dist/components/given.js +9 -0
  413. package/dist/components/hover-open.d.ts +34 -0
  414. package/dist/components/hover-open.js +90 -0
  415. package/dist/components/index.d.ts +114 -1
  416. package/dist/components/index.js +115 -2
  417. package/dist/components/layout/aspect-ratio/AspectRatio.css +29 -0
  418. package/dist/components/layout/aspect-ratio/AspectRatio.d.ts +24 -0
  419. package/dist/components/layout/aspect-ratio/AspectRatio.js +26 -0
  420. package/dist/components/layout/aspect-ratio/AspectRatio.types.d.ts +22 -0
  421. package/dist/components/layout/aspect-ratio/AspectRatio.types.js +7 -0
  422. package/dist/components/layout/aspect-ratio/aspect-ratio-impl.css +44 -0
  423. package/dist/components/layout/grid/Grid.css +76 -0
  424. package/dist/components/layout/grid/Grid.d.ts +31 -0
  425. package/dist/components/layout/grid/Grid.js +33 -0
  426. package/dist/components/layout/grid/Grid.types.d.ts +48 -0
  427. package/dist/components/layout/grid/Grid.types.js +7 -0
  428. package/dist/components/layout/grid/grid-impl.css +62 -0
  429. package/dist/components/layout/row/Row.css +85 -0
  430. package/dist/components/layout/row/Row.d.ts +32 -0
  431. package/dist/components/layout/row/Row.js +34 -0
  432. package/dist/components/layout/row/Row.types.d.ts +45 -0
  433. package/dist/components/layout/row/Row.types.js +7 -0
  434. package/dist/components/layout/scroller/Scroller.css +59 -0
  435. package/dist/components/layout/scroller/Scroller.d.ts +34 -0
  436. package/dist/components/layout/scroller/Scroller.js +36 -0
  437. package/dist/components/layout/scroller/Scroller.types.d.ts +38 -0
  438. package/dist/components/layout/scroller/Scroller.types.js +7 -0
  439. package/dist/components/layout/scroller/scroller-impl.css +45 -0
  440. package/dist/components/layout/stack/Stack.css +73 -0
  441. package/dist/components/layout/stack/Stack.d.ts +28 -0
  442. package/dist/components/layout/stack/Stack.js +30 -0
  443. package/dist/components/layout/stack/Stack.types.d.ts +41 -0
  444. package/dist/components/layout/stack/Stack.types.js +7 -0
  445. package/dist/components/visually-hidden.d.ts +22 -0
  446. package/dist/components/visually-hidden.js +31 -0
  447. package/dist/fonts/LICENSE-inter.txt +93 -0
  448. package/dist/fonts/LICENSE-red-hat-mono.txt +93 -0
  449. package/dist/fonts/fonts.css +111 -0
  450. package/dist/fonts/inter-cyrillic-ext-wght-normal.woff2 +0 -0
  451. package/dist/fonts/inter-cyrillic-wght-normal.woff2 +0 -0
  452. package/dist/fonts/inter-greek-ext-wght-normal.woff2 +0 -0
  453. package/dist/fonts/inter-greek-wght-normal.woff2 +0 -0
  454. package/dist/fonts/inter-latin-ext-wght-normal.woff2 +0 -0
  455. package/dist/fonts/inter-latin-wght-normal.woff2 +0 -0
  456. package/dist/fonts/inter-vietnamese-wght-normal.woff2 +0 -0
  457. package/dist/fonts/red-hat-mono-latin-ext-wght-normal.woff2 +0 -0
  458. package/dist/fonts/red-hat-mono-latin-wght-normal.woff2 +0 -0
  459. package/dist/marketing.css +289 -241
  460. package/package.json +18 -4
@@ -0,0 +1,238 @@
1
+ <!-- GENERATED from navbar-item.contract.json. Do not edit. -->
2
+
3
+ # NavbarItem
4
+
5
+ One place the site has, in the bar across the top of it. An anchor with a target around it, a mark for the section the reader is currently in, and nothing else.
6
+
7
+ It exists rather than a Link being reused because a destination in a navigation bar carries something a Link cannot: which one the reader is on. That is `aria-current`, a target big enough to hit, and a resting shape the current one fills in — none of which belongs on the component a page also uses in the middle of a sentence. A Link is prose that leads somewhere; this is furniture.
8
+
9
+ It takes no colour of its own. The bar sets the ink once and everything in it inherits, so what this declares is the ground under the words — and even that has to be told which way round it is, because an item cannot see the bar it is in.
10
+
11
+ ## Use when
12
+
13
+ - A section of the site, in a Navbar — the ordinary case and what this is for
14
+ - A destination that leaves the site, which it marks as a change of context rather than leaving the reader to find out
15
+ - The same destination inside the panel a narrow bar collapses into: a page writes its navigation once, and what changes with the width is how it is drawn
16
+
17
+ ## Do not use
18
+
19
+ - The destination opens a panel of further destinations rather than going somewhere → `NavbarMenu`
20
+ - The destination is a phrase inside a sentence, or a call to action beneath a paragraph → `Link`
21
+ - The item is one of a set of alternatives rather than a place → `Tab`
22
+ - A control. This navigates and nothing else — a press that filtered, submitted or opened something would be a button the browser has been told is a link
23
+ - The site's mark. That goes in Navbar's brand slot, where nothing gives it a target or a current state
24
+ - A conversion action. Open an account is not a place the site has, and a reader tabbing the navigation landmark should not meet it there — that is Navbar's utilities slot
25
+ - A list of every page on the site. A bar holds the sections a reader chooses between at a glance; a sitemap is a footer
26
+
27
+ ## Anatomy
28
+
29
+ NavbarItem renders 4 elements. A token binding names the part it applies to.
30
+
31
+ - `root` — `<a>`, class `dds-navbaritem`. The destination, and the target around it. An `<a>` with an href always — including the one the reader is currently on, which is where this parts company with BreadcrumbItem. A trail marks where you have been and its last step is not a link because it goes nowhere new; a bar is a set of places you move between, and the section you are in is one you can return to the top of.
32
+
33
+ It takes no colour of its own and inherits the bar's — which has to be said rather than assumed. `color` is an inherited property and an anchor is the exception: every browser's own stylesheet paints one link-blue, so a component that simply declined to set a colour got the UA's instead of the bar's. `color: inherit` is what makes the sentence above true. What it does declare is the ground under the words: nothing at rest, a tint under the pointer, and a filled shape for the current one.
34
+
35
+ `size.control.md` in the block axis, declared rather than emergent. It is a control's height rather than the bare target floor because it sits inside a pill one step above it, and the two insets either side are what make up the difference. Well clear of `size.target.min` either way, which is the floor that actually has to hold. The padding either side of a short word clears it comfortably today and would not survive a tighter type step, and a target nobody wrote down is one that moves when the scale does.
36
+
37
+ `position: relative`, for the one thing it holds that is not drawn: an external destination's warning in words, clipped out of the page. That recipe is absolutely positioned, so without a positioned ancestor it takes the document as its containing block and adds its offset to the bottom of a long landing page.
38
+
39
+ It reserves `size.control.lg`, the same height the bar's actions take. A destination is words and a button is a filled shape, so they are never the same object — but they stand in one row, and a row whose items are two heights reads as two rows that failed to line up.
40
+
41
+ It pads its words by `space.inset.md`. With no gap between the destinations — the row sets none, so their targets touch and a pointer crossing from one to the next is never over neither — this inset is the whole of the space a reader sees between two names, twice over. It is the spacing decision for the row, not a detail of one item.
42
+ - `icon` — `<span>`, class `dds-navbaritem__icon`. A mark before the words, for a bar that uses them. Optional and uncommon: a marketing site's sections are named in words a reader reads, and a glyph beside every one of them costs width the destinations need.
43
+
44
+ It paints nothing. The glyph inside takes `currentColor`, which is the ink the bar set — so it turns over with the words rather than being the one thing left behind. Rendered only when `icon` is set.
45
+ - `label` — `<span>`, class `dds-navbaritem__label`. The name of the place. A span of its own rather than bare text in the anchor, because the trailing mark on an external destination has to sit beside the words rather than inside them — and because a part is what a stylesheet can reach.
46
+
47
+ It does not wrap. A destination broken across two lines makes the bar taller than every page below it has made room for, and the answer when the words stop fitting is the bar collapsing rather than the words folding.
48
+
49
+ It is set at `font.label.sm`, which is the fourteen-pixel step. That is a deliberate divergence worth naming: `font.label.md` is the role whose own description lists navigation links among what it is for, and this does not take it. A bar holds five or six destinations between a mark and a pair of controls, and at the sixteen-pixel step they crowd the row before the bar reaches the width it collapses at. The role's description is the thing to correct if fourteen is right for every bar rather than this one.
50
+ - `external` — `<span>`, class `dds-navbaritem__external`. The mark that says this one leaves the site — the only thing here a reader can see that the href does not already tell them. A change of context nobody was warned about reads as the site losing them.
51
+
52
+ It is decoration and is hidden from assistive technology. What it stands for is said in words by the anchor's own accessible name, which the implementation extends rather than leaving to a glyph nobody can hear. Rendered only when `external` is set.
53
+
54
+ Apply these classes from the generated `navbarItemParts` constant rather than writing the strings by hand.
55
+
56
+ ## Composition
57
+
58
+ - Can contain: `text`
59
+ - Never contains: `Navbar`, `NavbarItem`, `NavbarMenu`, `Button`, `Link`, `Card`, `DropdownMenu` — in children or in any prop that takes a node
60
+
61
+ ## Props
62
+
63
+ ### current — `boolean` (default `false`)
64
+
65
+ Use when: The reader is in this section of the site. It fills the item's shape in and sets `aria-current="page"`, so the mark is not the only thing saying it. At most one item in a bar carries it — a set with two has told the reader they are in two places
66
+ Never for: Emphasis. This is not the important destination or the one the site would rather you took; it is the one the reader is already on, and using it for anything else makes the mark mean nothing on every bar that uses it correctly
67
+
68
+ ### tone — `default` | `inverse` (default `default`)
69
+
70
+ - `default` — The bar has a light ground under it, which is every bar on a marketing page today. The tints here are ink-based and read against paper
71
+ - `inverse` — The bar sits on a dark ground — a band, or art the page put behind it — and the ink runs light. The tints mirror: paper-based rather than ink-based, so a hover is visible instead of disappearing into the dark
72
+
73
+ ### href — `string` **Required.**
74
+
75
+ Use when: Always. This is a place, and a place has an address — an item with no href is a control drawn as a link, which is the one thing its intent says it is not
76
+ Never for: A fragment standing in for behaviour. `href="#"` is how a link that does nothing gets written, and it navigates: the reader loses their scroll position and gains a history entry for a press meant to do something else
77
+
78
+ ### icon — `node`
79
+
80
+ Accepts: Icon
81
+ Use when: The bar's sections are quicker to tell apart by a mark than by reading them, which is rare on a marketing site and usual in an application
82
+ Never for: Decoration on every item. A glyph beside each of five destinations costs the width the destinations need and tells a reader nothing they were not already reading
83
+
84
+ ### external — `boolean` (default `false`)
85
+
86
+ Use when: The destination leaves the site. It draws the mark, opens in a new context, and the implementation extends the accessible name to say so in words — a glyph alone is a warning only sighted readers get
87
+ Never for: A different area of the same site. A subdomain the reader experiences as one place is not a change of context, and marking it as one teaches them to ignore the mark where it matters
88
+
89
+ Also accepts everything from `AnchorHTMLAttributes<HTMLAnchorElement>`.
90
+
91
+ ## Accessibility
92
+
93
+ 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.
94
+
95
+ - Announced as: `link`
96
+ - `Tab` — Reaches the item, which is an anchor and needs nothing added to be a tab stop. There is no roving tabindex here and no arrow keys: a bar is a set of links rather than a composite widget, and a reader keeps the key they already have.
97
+ - accessible name from the words inside it, which is what a reader hears and what a page writes anyway. Nothing here draws a label a reader cannot see
98
+ - the section the reader is in marked with aria-current="page", so the fill is not the only thing saying it. Not verified here: the generated assertions compare an ARIA attribute against "true", and this one carries "page"
99
+ - The current item keeps its href and its place in the tab order. A reader who lands on it should hear which section they are in, and following it is a harmless return to the top of that section rather than a dead end.
100
+ - An external destination says so in words as well as with the mark. The glyph is hidden from assistive technology, so the anchor's own accessible name carries it — a change of context announced only to readers who can see a glyph is one the rest are not told about.
101
+ - The item takes no colour of its own and inherits the bar's, which is what lets a bar on a dark ground turn its whole contents over in one declaration.
102
+ - tone is the page's to set and the item cannot check it. An item cannot see the ground it is on, so an inverse tone on a light bar is a paper tint on paper — a hover nobody can see, and a failure no check here will catch.
103
+
104
+ ## Rules
105
+
106
+ - **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.
107
+
108
+ 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.
109
+
110
+ 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.
111
+
112
+ 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.
113
+
114
+ 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.
115
+
116
+ 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.
117
+ Guidance only — cannot be checked automatically.
118
+ - **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.
119
+ Guidance only — cannot be checked automatically.
120
+ - **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.
121
+
122
+ 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.
123
+
124
+ 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.
125
+ Guidance only — cannot be checked automatically.
126
+ - **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.
127
+
128
+ 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.
129
+
130
+ 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.
131
+
132
+ 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.
133
+
134
+ 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.
135
+
136
+ 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.
137
+
138
+ 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.
139
+
140
+ 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.
141
+
142
+ 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.
143
+ Guidance only — cannot be checked automatically.
144
+ - **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.
145
+
146
+ 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.
147
+
148
+ 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.
149
+
150
+ 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.
151
+
152
+ 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.
153
+
154
+ 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.
155
+
156
+ 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.
157
+
158
+ 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.
159
+
160
+ 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.
161
+ Guidance only — cannot be checked automatically.
162
+ - **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.
163
+
164
+ 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.
165
+
166
+ 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.
167
+
168
+ 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.
169
+ Guidance only — cannot be checked automatically.
170
+
171
+ ## Anti-examples
172
+
173
+ ❌ NavbarItem for: The destination opens a panel of further destinations rather than going somewhere
174
+ This navigates on press and says so to the browser, the back button and every assistive technology. A trigger that opened something while claiming to be a link is the one shape both of them are wrong about
175
+ → use `NavbarMenu` instead.
176
+
177
+ ❌ NavbarItem for: The destination is a phrase inside a sentence, or a call to action beneath a paragraph
178
+ A Link is sized, coloured and underlined to sit in running text. This has a target, a resting shape and a way of saying the reader is already there, all of which read as a stray highlight in the middle of a paragraph
179
+ → use `Link` instead.
180
+
181
+ ❌ NavbarItem for: The item is one of a set of alternatives rather than a place
182
+ A tab changes what is showing on the page the reader is already on and carries no href at all. Drawing a comparison as navigation tells a reader the page is about to change under them, and the back button will disagree
183
+ → use `Tab` instead.
184
+
185
+ ❌ current=true + external=true
186
+ The section the reader is in, and a destination that leaves the site. A bar cannot be saying both: aria-current="page" claims this is the page being viewed, while external says the target is somewhere the site does not control
187
+
188
+ ## Example
189
+
190
+ ```tsx
191
+ import { NavbarItem } from '@deriv-com/dds-marketing'
192
+
193
+ <NavbarItem href="/trading">Trading</NavbarItem>
194
+ ```
195
+
196
+ ## In use
197
+
198
+ ### Where the reader is
199
+
200
+ One item in a bar carries current. It fills the shape in and sets aria-current="page", so the mark is not the only thing saying it — and it keeps its href.
201
+
202
+ ```tsx
203
+ import { NavbarItem } from '@deriv-com/dds-marketing'
204
+
205
+ // A section the reader is not in
206
+ <NavbarItem href="/platforms">Platforms</NavbarItem>
207
+
208
+ // The section the reader is in
209
+ <NavbarItem href="/trading" current>Trading</NavbarItem>
210
+ ```
211
+
212
+ ### Leaving the site
213
+
214
+ A destination that opens elsewhere is a change of context. The mark says so to anyone who can see it; the accessible name says so to everyone else.
215
+
216
+ ```tsx
217
+ import { NavbarItem } from '@deriv-com/dds-marketing'
218
+
219
+ // Stays on the site
220
+ <NavbarItem href="/about">About</NavbarItem>
221
+
222
+ // Opens elsewhere, and says so
223
+ <NavbarItem href="https://partners.example.com" external>Partners</NavbarItem>
224
+ ```
225
+
226
+ ### Which ground it is on
227
+
228
+ The item takes no colour of its own. tone sets the tint under the pointer — ink-based on a light bar, paper-based on a dark one — and the page has to say which.
229
+
230
+ ```tsx
231
+ import { NavbarItem } from '@deriv-com/dds-marketing'
232
+
233
+ // default — a light bar
234
+ <NavbarItem href="/trading">Trading</NavbarItem>
235
+
236
+ // inverse — a bar on a dark ground
237
+ <NavbarItem href="/trading" tone="inverse">Trading</NavbarItem>
238
+ ```
@@ -0,0 +1,319 @@
1
+ <!-- GENERATED from navbar-menu.contract.json. Do not edit. -->
2
+
3
+ # NavbarMenu
4
+
5
+ A destination in the bar that opens rather than goes: a named trigger, and a wide panel beneath it holding the section's own destinations in columns, usually with something promotional beside them.
6
+
7
+ It is a button and not a link, which is the whole of why it is a component rather than a NavbarItem with extra parts. Pressing it reveals something on the page the reader is already on — no navigation, no history entry, and the back button has nothing to undo. An item that opened a panel while claiming to be a link would be wrong to the browser, to the back button and to every assistive technology at once.
8
+
9
+ What goes in the panel is the page's. A section of a marketing site is a set of groups a reader scans, and the grouping, the headings and the promotional card are written by the site rather than enumerated by this system — so this declares the trigger, the surface it opens and the arrangement of that surface, and makes no claim about what is arranged.
10
+
11
+ Wide rather than beside. A dropdown that opened at the trigger's own width would put five columns into the space one word occupies; this one is measured against the bar and holds what a section actually contains.
12
+
13
+ ## Use when
14
+
15
+ - A section of the site has enough inside it that naming the section is not enough — Trading holding markets, platforms and tools, rather than one page called Trading
16
+ - The destinations under a section are worth grouping, and the groups are worth heading
17
+ - The section has something the site wants shown alongside its links: a promotion, a feature, a piece of art
18
+
19
+ ## Do not use
20
+
21
+ - The destination is a single place → `NavbarItem`
22
+ - What opens is a single column of choices rather than a section of the site → `DropdownMenu`
23
+ - A control. Nothing here submits, filters or changes what the page is showing other than by revealing its own panel
24
+ - A destination of its own. The trigger is a button and goes nowhere — a section that is also a page needs its own NavbarItem inside the panel, where a reader can actually reach it
25
+ - The narrow width. There is no room for columns on a phone, and the bar collapses into NavbarPanel rather than opening this
26
+ - Content a reader has to work through. A panel is scanned in a moment with a pointer hovering over it; a paragraph in one is a paragraph nobody finishes
27
+
28
+ ## Anatomy
29
+
30
+ NavbarMenu renders 6 elements. A token binding names the part it applies to.
31
+
32
+ - `root` — `<div>`, class `dds-navbarmenu`. The trigger and its panel, and the box the second is positioned against. It holds no ground and no measure of its own — it is a position in the bar's row, and everything visible belongs to one of the two parts inside it.
33
+
34
+ It is deliberately not positioned. An absolutely positioned panel resolves against the nearest positioned ancestor, and this root was it — so the panel hung from the trigger, which is one word wide, and centring on that centred on the word rather than on the row of them. Giving it up hands the job to Navbar's pill, which is the box a reader actually sees.
35
+
36
+ The cost is a dependency rather than a free win: a menu used outside a Navbar has no pill to resolve against and will find whatever positioned ancestor the page happens to have. That is the trade for a panel that lines up with the set it belongs to, and it is worth naming because nothing will report it — the panel simply appears somewhere else.
37
+ - `trigger` — `<button>`, class `dds-navbarmenu__trigger`. The name of the section, and the control that reveals it. A `<button>` with `aria-expanded`, which is the honest shape: it goes nowhere, and a reader who cannot see the panel is told whether it is open rather than left to press it and find out.
38
+
39
+ It takes the same resting shape a NavbarItem does — the same target floor, the same pill, the same tints — because the two sit in one row and a reader scanning it should not be able to tell which of them the site happened to implement differently. What it adds is the chevron, and a filled shape while the panel is open.
40
+
41
+ It takes no colour of its own. The bar sets the ink and this inherits it, on the same reasoning as every other end of the bar.
42
+
43
+ It takes `font.label.sm` because NavbarItem does. The two sit in one row and the contract above says a reader should not be able to tell which of them the site implemented differently — a step between them is the one difference that would give it away.
44
+
45
+ Floating, a mouse over it opens the panel without a press. That is what a bar of sections is expected to do on a desktop, and the press still works — hover is added to the button, not substituted for it, so Enter and Space reach it where no pointer exists and a reader who uses both gets the same result from either.
46
+
47
+ Only a mouse, and only floating. The event is asked what kind of pointer it is rather than the device being asked once whether it hovers: a tap reports `touch` and a stylus `pen`, and a laptop with a touchscreen answers both at different moments. Inline the question does not arise — a panel row is read down with a finger, and a section that opened as one passed over it would open every section on the way to the last.
48
+
49
+ It takes the bar's ink rather than the browser's. A `<button>` does not inherit `color`, so without this a section's name draws in the UA's `buttontext` — near-black, which passes for `color.fg.default` on a light bar and is the reason this went unnoticed. On an inverse bar the sections rendered dark while the plain destinations beside them rendered light, from one missing declaration.
50
+
51
+ It reserves the same height a destination does, because it is one of them as far as a reader scanning the row is concerned.
52
+
53
+ It pads its words by the same step a destination does. The two sit in one row and a reader scanning it cannot see which of them opens something until they meet the mark at the end — so anything that made them measure differently would be a difference with no meaning behind it.
54
+ - `chevron` — `<span>`, class `dds-navbarmenu__chevron`. The mark that says this one opens. It turns rather than swapping — the same glyph rotated, so the shape stays recognisable and the movement is what carries the state.
55
+
56
+ Decoration, and hidden from assistive technology. `aria-expanded` on the trigger says the same thing to a reader who cannot see it turn, and a glyph announced as well would say it twice.
57
+
58
+ In the panel it is as wide as a target, not as wide as itself. The row sends it to the far edge, where the panel's close button is already standing on that line one row above — and the two marks are not the same size, so boxes that end together still put their centres four pixels apart, which is exactly the distance the eye reads as a column that does not line up. Taking `size.target.min`, the measure the close button already claims, and centring the glyph in it puts both on one line by construction rather than by arithmetic that would need redoing the next time either glyph changes step.
59
+
60
+ Only in the panel. In the bar the mark sits against its own label inside a pill, where a box wider than the glyph would read as a gap opening between the word and its mark.
61
+ - `surface` — `<div>`, class `dds-navbarmenu__surface`. The panel: the section's groups on one side, whatever the site wants shown beside them on the other. Under `floating` it is `position: absolute` against the root, so it hangs from the trigger rather than from the page — a panel positioned against the document would need the bar's own offset subtracted and would be wrong the moment anything above the bar changed height. Under `inline` it is in the flow, because inside the collapsed panel there is no bar to hang from and nothing to float over.
62
+
63
+ It is `size.menu-panel.max` wide, and that is a width rather than a ceiling. A ceiling was the first attempt and it did nothing: an absolutely positioned box with one inset is shrink-to-fit, so a `max-inline-size` only clamps a panel whose contents already want more — and three groups beside a card want less, so every panel came out a different width decided by how many destinations happened to be in it. A section's panel is a surface with a measure, not a box that fits its words.
64
+
65
+ Narrower than the page's own measure on purpose. A panel is scanned across with a pointer already on it, so one as wide as the page leaves its last column a long way from the name that opened it. What decides its position is the bar, not the trigger — a panel starting at the trigger's leading edge would run off the end of the page for the last section in the row. A panel starting at the trigger's leading edge would run off the end of the page for the last section in the row.
66
+
67
+ Its own inset is `space.inset.xs` and not the step a surface usually takes. The card is the thing that meets the panel's edge, and a promotional picture floating in a wide white margin is a card that has been set down rather than fitted. What the words need instead is the groups' own inset, which they carry — so the copy keeps the measure it had and only the card moved.
68
+
69
+ It clears the pill by `space.gap.sm`, and now the number and the distance are the same thing. `inset-block-start: 100%` is the pill's own height once the pill is what the panel resolves against, so the margin starts at the pill's bottom edge rather than the trigger's — which also retires an inset role that was standing in for a gap at a step the gap ramp does not have.
70
+
71
+ Its corner is `radius.container` and not the `radius.surface` a panel would otherwise reach for, because a corner has to answer to what is inside it. The feature card takes `radius.surface` and sits `space.inset.xs` from the panel's edge, and two curves are concentric only when the outer one is the inner plus the distance between them — twenty-four and eight, which is thirty-two. Matched instead, the two arcs share a radius but not a centre, and the gap between them narrows through the corner and opens again on the straight: the shape reads as slightly wrong without it being obvious which of the two is at fault.
72
+
73
+ It follows the inset rather than leading it. Change the panel's padding and this has to move with it, which is the cost of nesting two rounded boxes and worth paying over the alternative of a corner that only looks right at one measure.
74
+
75
+ It has a floor as well as a width. A bar's sections rarely hold the same number of destinations, so panels sized by their contents alone are a different height each — and a reader moving along the row watches the surface under the pointer grow and shrink for reasons that are about the site's structure rather than about anything they did.
76
+
77
+ A floor rather than a height, which is the honest half of the promise: it makes every panel the same size while every panel's contents fit inside it, and a section with more destinations than that is taller. The alternative is a fixed height that either crops the largest section or leaves the smallest one mostly empty, and neither is better than a panel that grows when it genuinely has more to say.
78
+
79
+ Inline it takes the row's own inset rather than none, so a destination inside a set starts on the same line as the name that opened it. The panel pulls its list back out to the surface's edge and each row pads itself back in; a set that skipped that step would hang a step to the leading side of every row above it, which reads as the sets belonging to something other than the section they opened from.
80
+
81
+ It does not animate in when it is replacing another. Moving along a row of sections, the panel that was open unmounts and this one mounts — two elements, so there is nothing to tween between — and playing the entrance on the second reads as the first closing and a new one opening rather than as the two exchanging places. What the eye sees at that moment is a flicker where a panel already was.
82
+
83
+ So the entrance is for arriving over a page with nothing else open, which is the only time it is describing anything. Whether this is an arrival or an exchange is the container's to know: a menu cannot see its neighbours, and the bar holding one open at a time can.
84
+
85
+ Inline, the step between the sets and the picture is `space.gap.md` — a step below the one that separates two sets, and the same one that separates two destinations inside a set. Stacked in a column the picture is the end of the section rather than a break in it, and the larger steps read as a division: at those, the card looked like something that had been appended to the panel rather than the last thing in it.
86
+
87
+ The floating form keeps its own, which is a different question — there the two sit side by side and the gap is the column between them. Rendered only when `open` is set.
88
+ - `groups` — `<div>`, class `dds-navbarmenu__groups`. The sets, in two columns, across half the panel — the feature beside it takes the other half, and neither holds that measure as a number: both ask for the whole surface and shrink against each other until they agree. A section of a marketing site has more destinations than one column holds at a readable height, and a single column of twenty is a scroll inside something that opened on a hover. Two rather than one per group: a column per set makes the panel as wide as the number of sets it happens to hold, so adding a fourth would push the feature card out.
89
+
90
+ Columns rather than a grid, and the difference is what a set does with the space beside it. A grid aligns its rows, so a set of one laid out beside a set of seven is stretched to the taller one's height and the next set down starts below both — a column of two items with a hand's width of nothing under it. Columns pack instead: each one fills, and a set begins where the set above it ended.
91
+
92
+ It also makes the count a decision about the panel rather than about the content. Two, whatever the number of sets — where a row of them made the panel as wide as however many it happened to hold, and a fourth would have pushed the feature card out of the surface.
93
+
94
+ It sets the type the destinations inherit. A `list` Link takes the ink and the measure around it — that is the variant's whole point, a column of coral being a column nobody reads — so with nothing set here the rows fell back to the browser's own default. `font.body.sm` is the fourteen-pixel step at a regular weight, and the weight is the half that matters here: the labels over these rows are `font.label.sm`, the same size semibold, so what tells a signpost from a destination is the weight and the ink rather than the measure. `font.label.md` was the first attempt and is the bar's own step — semibold, right for a row scanned across and heavy enough in a column that these rows stopped looking like list links anywhere else in the system.
95
+
96
+ The role is imperfect and worth naming as such: `font.body.sm`'s own description is written for de-emphasised text — disclaimers, copyright lines — where this is a column of destinations. The alternative reads better on paper and worse on screen: `font.label.sm` names footer links in as many words, and is exactly what the labels above these rows already take, so the two would part company on colour alone.
97
+
98
+ Its foot is deeper than its head, and the depth belongs here rather than on the surface — which is where it went first, and was wrong. The panel's own frame is one small measure on all four sides because the picture beside these sets is meant to reach it: a card inset from the panel's edge is a card floating in a box rather than filling its half of one. Only the words need the extra room, so only the words take it.
99
+
100
+ Why the extra at all: the sets carry the space between them as a margin, since multi-column has no row gap to put it in, and whether a margin at the end of a column counts towards that column's height is a thing browsers do not agree on. The container cancels it either way, so the space under the last set is the one measure here not fully under this component's control — a deeper declared inset is what makes it look right whichever way the browser goes.
101
+ - `feature` — `<div>`, class `dds-navbarmenu__feature`. What the site wants shown beside the destinations — a promotion, a feature, a piece of art. A slot, because it is a Card and a Card is a component the page already has; this declares where it sits and what shape it holds.
102
+
103
+ `aspect.widescreen` — sixteen by nine, the shape most moving media already is. It is on this region rather than on the card inside it, and the difference matters: CardBody's own `aspect` shapes the picture, and under `overMedia` the picture is the ground, so the card's height still came from however much copy it was given. A card that is a different height every time the words change is not a shape anybody laid out.
104
+
105
+ It takes half the panel, and the groups take the other half. Both declare `inline-size: 100%` and both flex, so each asks for the whole surface and the two shrink against each other to the same measure — a half that follows from the pair rather than a number either of them holds. Content-sized was the arrangement before, and the card's width then moved with however many words the copy ran to.
106
+
107
+ Beside the groups under `floating` and beneath them under `inline`. The panel is wide and the collapsed one is narrow, and a promotional card in a column half a phone wide is a picture nobody can read the words on. Rendered only when `feature` is set.
108
+
109
+ Apply these classes from the generated `navbarMenuParts` constant rather than writing the strings by hand.
110
+
111
+ ## Composition
112
+
113
+ - Can contain: `NavbarMenuGroup`, `NavbarItem`
114
+ - Never contains: `Navbar`, `NavbarMenu`, `NavbarPanel`, `BottomSheet`, `TabList` — in children or in any prop that takes a node
115
+
116
+ ## Props
117
+
118
+ ### presentation — `floating` | `inline` (default `floating`)
119
+
120
+ - `floating` — The menu is in the bar, which is everywhere a page puts one. The panel hangs from the trigger and floats over what is beneath it
121
+ - `inline` — NavbarPanel is rendering the menu, and it sets this itself — a page should not. Inside the collapsed panel there is nothing to float over and no bar to hang from, so the panel opens in the flow and pushes what follows it down, which is what an accordion row does
122
+
123
+ ### tone — `default` | `inverse` (default `default`)
124
+
125
+ - `default` — The bar has a light ground under it, which is every bar on a marketing page today. The trigger's tints are ink-based and read against paper
126
+ - `inverse` — The bar sits on a dark ground and the ink runs light. Only the trigger mirrors — the panel is its own surface with its own ground, and is the same either way
127
+
128
+ ### label — `string` **Required.**
129
+
130
+ Use when: Always — it is the name of the section, the words on the trigger, and the accessible name of the control. Name the section rather than the act: 'Trading', not 'Open trading menu'
131
+ Never for: A description of what is inside. The panel says that by holding it, and a trigger long enough to explain itself is a trigger that breaks the row it sits in
132
+
133
+ ### open — `boolean`
134
+
135
+ Use when: The bar is holding which section is open, because only one should be at a time. Passing it makes the menu controlled: it shows what it is told and reports presses through onOpenChange.
136
+
137
+ Leave it off and the menu holds its own answer, which is right for a menu standing alone and wrong for a row of them — two panels open at once is two surfaces overlapping in front of the page
138
+ Never for: Half of a controlled menu. An open passed without an onOpenChange to move it is a panel that cannot be closed by pressing the trigger that opened it
139
+
140
+ ### onOpenChange — `callback`
141
+
142
+ Use when: Whenever open is — together they are how a bar holds which section is showing. It is called with the state being moved to, by the trigger and by Escape
143
+ Never for: Navigation. This says whether the panel is showing; a reader pressing a destination inside it is leaving by a different door
144
+
145
+ ### replacing — `boolean` (default `false`)
146
+
147
+ Use when: Another section's panel was already on screen when this one opened. A container that holds one section open at a time knows this and a menu cannot, so the container sets it — Navbar does, and a page should not
148
+ Never for: Turning the entrance off generally. A panel that arrives over a page with nothing else open has something to say about where it came from, and saying it is the difference between a panel appearing and a panel being noticed
149
+
150
+ ### feature — `node`
151
+
152
+ Use when: The section has something the site wants shown alongside its destinations — a promotion, a platform, a piece of art. A Card, which already knows how to hold a picture with words over it.
153
+
154
+ That is not declared as an `accepts`, and the omission is deliberate: the workbench builds a sample for any slot naming a component, from that component's own showcase, and it cannot build one whose children are themselves components — which a Card's are. Naming it would document the slot by breaking the page that shows it.
155
+ Never for: More destinations. Anything that goes to a section of the site belongs in a group, where the reader is looking for it
156
+
157
+ Also accepts everything from `HTMLAttributes<HTMLDivElement>`.
158
+
159
+ ## Accessibility
160
+
161
+ 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.
162
+
163
+ - Announced as: `button`
164
+ - `Tab` — Reaches the trigger, then the destinations inside the panel once it is open, then on out of the menu. There is no roving tabindex and no arrow keys: what opens is a set of links rather than a menu of commands, so a reader keeps the key they already have and is not trapped in a widget they did not ask to enter.
165
+ - `Escape` — Closes the panel and returns focus to the trigger. The way out that does not have to be seen, and the only one for a reader who opened it from the keyboard. It also ends a panel the pointer opened, so a reader who reaches for the keyboard is not told the way out belongs to the mouse.
166
+ - `Enter` — Opens and closes the panel, which a button does without anything being added.
167
+ - accessible name from label on the trigger, which is the name of the section and the words a reader sees
168
+ - The trigger reports whether the panel is showing with aria-expanded. A control that reveals something and does not say whether it is revealed leaves a reader pressing it to find out.
169
+ - A button rather than a link. It goes nowhere: there is no href, no history entry and nothing for the back button to undo, and every assistive technology is told the same.
170
+ - The chevron is hidden from assistive technology. aria-expanded already says which way the panel is, and a glyph announced beside it says it twice.
171
+ - The panel is not a menu and takes no menu role. What it holds is links, and role="menu" would promise a widget with arrow-key navigation and a set of commands — a promise whose first consequence is that a screen reader stops announcing the links as links.
172
+ - Only one panel in a bar is open at a time, which is the bar's to enforce and not this component's. Two open panels overlap in front of the page, and a menu holding its own answer cannot see its neighbours.
173
+
174
+ ## Rules
175
+
176
+ - **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.
177
+
178
+ 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.
179
+
180
+ 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.
181
+
182
+ 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.
183
+
184
+ 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.
185
+
186
+ 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.
187
+ Guidance only — cannot be checked automatically.
188
+ - **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.
189
+ Guidance only — cannot be checked automatically.
190
+ - **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.
191
+
192
+ 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.
193
+
194
+ 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.
195
+ Guidance only — cannot be checked automatically.
196
+ - **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.
197
+
198
+ 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.
199
+
200
+ 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.
201
+
202
+ 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.
203
+
204
+ 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.
205
+
206
+ 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.
207
+
208
+ 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.
209
+
210
+ 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.
211
+
212
+ 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.
213
+ Guidance only — cannot be checked automatically.
214
+ - **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.
215
+
216
+ 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.
217
+
218
+ 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.
219
+
220
+ 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.
221
+
222
+ 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.
223
+
224
+ 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.
225
+
226
+ 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.
227
+
228
+ 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.
229
+
230
+ 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.
231
+ Guidance only — cannot be checked automatically.
232
+ - **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.
233
+
234
+ 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.
235
+
236
+ 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.
237
+
238
+ 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.
239
+ Guidance only — cannot be checked automatically.
240
+
241
+ ## Anti-examples
242
+
243
+ ❌ NavbarMenu for: The destination is a single place
244
+ A trigger that opens a panel holding one link is two presses where one would do, and it takes a link out of the tab order to put it behind a button
245
+ → use `NavbarItem` instead.
246
+
247
+ ❌ NavbarMenu for: What opens is a single column of choices rather than a section of the site
248
+ A menu opens at its trigger and is as wide as its longest option, which is right for a language picker and wrong for a section — and its rows are commands a reader picks from rather than places the site has
249
+ → use `DropdownMenu` instead.
250
+
251
+ ## Example
252
+
253
+ ```tsx
254
+ import { NavbarMenu, NavbarMenuGroup } from '@deriv-com/dds-marketing'
255
+
256
+ <NavbarMenu label="Trading">
257
+ <NavbarMenuGroup href="/forex">Forex</NavbarMenuGroup>
258
+ <NavbarMenuGroup href="/stocks">Stocks</NavbarMenuGroup>
259
+ <NavbarMenuGroup href="/commodities">Commodities</NavbarMenuGroup>
260
+ </NavbarMenu>
261
+ ```
262
+
263
+ ## In use
264
+
265
+ Most rows below hold the same set, written once here:
266
+
267
+ ```tsx
268
+ import { NavbarMenuGroup } from '@deriv-com/dds-marketing'
269
+
270
+ const navbarmenugroups = (
271
+ <>
272
+ <NavbarMenuGroup href="/forex">Forex</NavbarMenuGroup>
273
+ <NavbarMenuGroup href="/stocks">Stocks</NavbarMenuGroup>
274
+ <NavbarMenuGroup href="/commodities">Commodities</NavbarMenuGroup>
275
+ </>
276
+ )
277
+ ```
278
+
279
+ ### Closed, and open
280
+
281
+ The trigger is a button and goes nowhere. Closed it reads as one of the destinations beside it; open it fills its shape in and the chevron turns.
282
+
283
+ ```tsx
284
+ import { NavbarMenu } from '@deriv-com/dds-marketing'
285
+
286
+ // At rest — one name in the row
287
+ <NavbarMenu label="Trading">{navbarmenugroups}</NavbarMenu>
288
+
289
+ // Open — the section's own destinations
290
+ <NavbarMenu label="Trading" open>{navbarmenugroups}</NavbarMenu>
291
+ ```
292
+
293
+ ### In the bar, and in the panel
294
+
295
+ One component, two presentations. NavbarPanel sets inline itself — there is nothing to float over at that width, so the panel opens in the flow and pushes what follows it down.
296
+
297
+ ```tsx
298
+ import { NavbarMenu } from '@deriv-com/dds-marketing'
299
+
300
+ // floating — hanging from the bar
301
+ <NavbarMenu label="Trading" open>{navbarmenugroups}</NavbarMenu>
302
+
303
+ // inline — opened inside the collapsed panel
304
+ <NavbarMenu label="Trading" open presentation="inline">{navbarmenugroups}</NavbarMenu>
305
+ ```
306
+
307
+ ### Which ground the trigger is on
308
+
309
+ Only the trigger mirrors. The panel is a surface of its own with its own ground, so it is the same either way — the tone is about the row, not about what opens.
310
+
311
+ ```tsx
312
+ import { NavbarMenu } from '@deriv-com/dds-marketing'
313
+
314
+ // default — a light bar
315
+ <NavbarMenu label="Trading">{navbarmenugroups}</NavbarMenu>
316
+
317
+ // inverse — a bar on a dark ground
318
+ <NavbarMenu label="Trading" tone="inverse">{navbarmenugroups}</NavbarMenu>
319
+ ```