@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,524 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Children, cloneElement, isValidElement, useEffect, useId, useRef, useState } from 'react';
4
+ import { ChevronDownRegularIcon, CircleCheckSolidIcon, CircleExclamationSolidIcon, CircleInfoRegularIcon, TriangleExclamationSolidIcon, } from '@deriv-com/quill-icons-web';
5
+ import './Select.css';
6
+ import './select-impl.css';
7
+ import { Icon } from '../icon/Icon.js';
8
+ import { SearchInput } from '../search-input/SearchInput.js';
9
+ import { Spinner } from '../spinner/Spinner.js';
10
+ import { TooltipAnchor } from '../tooltip/TooltipAnchor.js';
11
+ import { given } from '../../given.js';
12
+ import { selectDefaults, selectGlyphStep, selectParts } from './Select.types.js';
13
+ /**
14
+ * What each reported status looks like.
15
+ *
16
+ * The same marks TextInput draws, and the same argument: circle for error, triangle for
17
+ * warning, because the two colours are close enough that a red-green deficiency can converge
18
+ * them and the shape is what separates the pair at a glance. A form mixing these two controls
19
+ * cannot have them disagree about which shape means what.
20
+ *
21
+ * An exclamation rather than a cross, which is not interchangeable here: the cross is what
22
+ * SearchInput draws on its clear button, and this control holds a SearchInput whenever it is
23
+ * searchable. The same mark meaning "this failed" underneath and "press to empty" inside is
24
+ * one glyph doing two jobs in one component.
25
+ */
26
+ const statusGlyph = {
27
+ none: null,
28
+ pending: null,
29
+ error: _jsx(CircleExclamationSolidIcon, {}),
30
+ warning: _jsx(TriangleExclamationSolidIcon, {}),
31
+ success: _jsx(CircleCheckSolidIcon, {}),
32
+ };
33
+ /**
34
+ * The answers, as a list this control can index.
35
+ *
36
+ * Levelled out of `children` rather than assumed to be an array: a set built from data arrives
37
+ * through a `.map()`, one written by hand may arrive in a fragment, and a set with a condition
38
+ * in it arrives with a `false` among the rows. `Children.toArray` flattens all three and drops
39
+ * the falsy entries, which is the whole reason to go through it rather than reading `children`.
40
+ */
41
+ function optionsOf(children) {
42
+ return Children.toArray(children).filter((child) => isValidElement(child));
43
+ }
44
+ /**
45
+ * How long a run of keystrokes stays one search rather than starting the next.
46
+ *
47
+ * Half a second, which is roughly what a native select allows and comfortably longer than the gap
48
+ * between two letters somebody is typing on purpose. Too short and "si" becomes a search for "s"
49
+ * followed by a search for "i", which lands on whatever begins with I; too long and a letter
50
+ * pressed a beat later joins a word the reader had finished with.
51
+ *
52
+ * Compared as timestamps rather than cleared by a timer. There is nothing to cancel on unmount
53
+ * and nothing to get out of step with a re-render — the buffer is only ever read at the moment a
54
+ * key arrives, so the question is how old it is, not whether something has expired.
55
+ */
56
+ const TYPING_WINDOW = 500;
57
+ /**
58
+ * An option's words, flattened enough to match a letter against.
59
+ *
60
+ * An option is given text, but `allowedChildren` says text and React says ReactNode, so a set
61
+ * built from data can arrive holding numbers or nested fragments. Anything that is not a string
62
+ * or a number contributes nothing rather than throwing: a row nobody can type their way to is a
63
+ * smaller failure than a list that cannot render.
64
+ */
65
+ function words(node) {
66
+ if (typeof node === 'string')
67
+ return node;
68
+ if (typeof node === 'number')
69
+ return String(node);
70
+ if (Array.isArray(node))
71
+ return node.map(words).join('');
72
+ return '';
73
+ }
74
+ /**
75
+ * A control for choosing one answer from a set the reader scans.
76
+ *
77
+ * Built as marketing's TextInput is built — a box that draws the border and the fill, and one
78
+ * element inside it holding the value — because that is what makes a form of mixed controls line
79
+ * up. The difference is the element inside: a text field's is an `<input>`, which can hold
80
+ * nothing, so its ornaments sit beside it and part of its box is not the field. Here it is a
81
+ * `<button>`, which can hold what it needs, so the whole box presses.
82
+ *
83
+ * Announced as a combobox, which is the name for a control that owns a list of answers whether
84
+ * or not anything can be typed into it. That role replaces the button's own activation on the
85
+ * way in, so Enter and Space are written here rather than inherited.
86
+ *
87
+ * Focus never leaves the box. Nothing here takes the caret — not even the search field, which is
88
+ * reachable with a pointer and otherwise fed from the box: every letter typed at the control goes
89
+ * into the query, so a keyboard never needs to be in the field to narrow the list. The rows are
90
+ * not focusable either, and the box says through `aria-activedescendant` which one the arrow keys
91
+ * are resting on; moving focus into the list would cost a tab stop per answer, which on a
92
+ * marketing page is a tab stop between the visitor and the button that submits the form.
93
+ *
94
+ * So Tab is one stop whether the list is open or shut. Open, it shuts the list on the way past
95
+ * rather than walking into the surface — the field and its clear button are furniture, and a
96
+ * reader tabbing out of a control has said they are done with it.
97
+ */
98
+ export function Select(props) {
99
+ const { size = selectDefaults.size, status = selectDefaults.status, fixed = selectDefaults.fixed, label, labelTooltip, placeholder, helperText, value, defaultValue, onChange, open, defaultOpen, onOpenChange, searchable = selectDefaults.searchable, emptyLabel, required = selectDefaults.required, requiredMark = selectDefaults.requiredMark, optional = selectDefaults.optional, statusMessage, children, id, ...rest } = props;
100
+ const fallbackId = useId();
101
+ const rootId = id ?? fallbackId;
102
+ const labelId = `${rootId}-label`;
103
+ const listId = `${rootId}-list`;
104
+ const rowId = (index) => `${rootId}-option-${index}`;
105
+ const box = useRef(null);
106
+ const trigger = useRef(null);
107
+ /**
108
+ * The answer, and whether the list is showing — each held here only while nobody else holds it.
109
+ *
110
+ * `in` rather than a check against undefined: a page clearing its own answer passes an empty
111
+ * string and a page that never held one passes nothing. Reading those as the same thing makes a
112
+ * controlled control uncontrollable the moment it is emptied.
113
+ */
114
+ const owned = 'value' in props;
115
+ const [held, setHeld] = useState(defaultValue ?? '');
116
+ const chosen = owned ? (value ?? '') : held;
117
+ const driven = 'open' in props;
118
+ const [showing, setShowing] = useState(defaultOpen ?? false);
119
+ /**
120
+ * And never open while the control is unavailable.
121
+ *
122
+ * A browser refuses a press and a keystroke on a disabled button, so no handler here needs to
123
+ * check — but `defaultOpen` reaches past all of them: `<Select disabled defaultOpen>` would
124
+ * render a list hanging off a control nobody can use, from props alone and without an event.
125
+ * Read off `rest` rather than destructured, because the attribute still has to reach the button.
126
+ */
127
+ const unavailable = rest.disabled === true;
128
+ const expanded = !unavailable && !fixed && (driven ? (open ?? false) : showing);
129
+ const options = optionsOf(children);
130
+ /**
131
+ * What has been typed at the search field, which is not an answer and never becomes one.
132
+ *
133
+ * Held here alone. A query is not a value the page has any use for — it is how the visitor got
134
+ * to the row they took — so there is no controlled twin of it and nothing to report. Emptied
135
+ * when the list shuts, for the same reason: it was a way through the answers, and the answers
136
+ * have gone.
137
+ */
138
+ const [query, setQuery] = useState('');
139
+ /**
140
+ * The answers a query leaves, or all of them.
141
+ *
142
+ * `includes` rather than the `startsWith` type-ahead uses, and the two are different jobs: a
143
+ * letter pressed at the control is a jump to a row, so it matches from the beginning, where a
144
+ * query typed into a field is a filter, and a visitor typing "land" means to see Ireland as
145
+ * well as Iceland.
146
+ *
147
+ * Everything below indexes into this rather than into the whole set — the rows the arrow keys
148
+ * walk, the row Enter takes, the ids the list carries. An index into a set that is not the one
149
+ * on screen takes the answer next to the one the visitor was looking at.
150
+ */
151
+ const narrowed = (text) => {
152
+ const needle = text.trim().toLowerCase();
153
+ if (needle === '')
154
+ return options;
155
+ return options.filter((option) => words(option.props.children).toLowerCase().includes(needle));
156
+ };
157
+ const visible = searchable ? narrowed(query) : options;
158
+ const indexOf = (v) => visible.findIndex((option) => option.props.value === v);
159
+ /**
160
+ * Where the arrow keys are resting, which is not what has been chosen.
161
+ *
162
+ * Two facts, and the visitor needs both: what they answered, and what they are about to answer.
163
+ * Arrowing past the chosen row does not unchoose it, and opening puts the keys on the answer
164
+ * rather than at the top — somebody who has to find their own answer again before changing it
165
+ * has been made to do the work twice.
166
+ *
167
+ * An index rather than a value, so a set that repeats a value cannot light two rows at once.
168
+ */
169
+ const [activeIndex, setActiveIndex] = useState(-1);
170
+ /**
171
+ * What has been typed at the list, and when.
172
+ *
173
+ * A ref rather than state: nothing renders from it, and a keystroke has to read what the last
174
+ * one left within the same event rather than after a re-render. Held together in one object so
175
+ * the letters and their age cannot get out of step.
176
+ */
177
+ const typed = useRef({ text: '', at: 0 });
178
+ const setOpen = (next) => {
179
+ // Forgotten on the way out, so a list reopened later does not show a marker for a position
180
+ // the visitor is no longer in, nor continue a search they finished.
181
+ if (!next) {
182
+ setActiveIndex(-1);
183
+ typed.current = { text: '', at: 0 };
184
+ // The query goes with it. A list reopened on the last visitor's search would be a list
185
+ // missing most of its answers for a reason nothing on screen explains.
186
+ setQuery('');
187
+ }
188
+ if (!driven)
189
+ setShowing(next);
190
+ onOpenChange?.(next);
191
+ };
192
+ const openAt = (index) => {
193
+ setActiveIndex(index);
194
+ setOpen(true);
195
+ };
196
+ const take = (index) => {
197
+ const option = visible[index];
198
+ if (option === undefined || option.props.disabled === true)
199
+ return;
200
+ const next = option.props.value ?? '';
201
+ if (!owned)
202
+ setHeld(next);
203
+ onChange?.(next);
204
+ // And the focus with it. From the box this is where it already was; from the field, or from
205
+ // a press on a row while the caret was in the field, the popup is about to be unmounted with
206
+ // the focus inside it — which drops the reader on <body>, at the top of the page, from a
207
+ // control halfway down it. Escape and Tab both already did this; taking an answer, which is
208
+ // the ordinary way out, did not.
209
+ shutAndReturn();
210
+ };
211
+ /**
212
+ * The next row the keys can rest on, stepping over the ones that cannot be taken.
213
+ *
214
+ * Stepped over rather than stopped at. A row the keys land on and refuse is a dead end the
215
+ * visitor has to press through, and pressing down twice to move once reads as a control that
216
+ * is broken rather than one that is being careful. The rows stay in the list and stay
217
+ * readable — a set that hid what it will not accept would leave somebody hunting for
218
+ * something that was there last week.
219
+ */
220
+ const step = (from, by) => {
221
+ for (let i = 1; i <= visible.length; i += 1) {
222
+ const at = (from + by * i + visible.length * i) % visible.length;
223
+ if (visible[at]?.props.disabled !== true)
224
+ return at;
225
+ }
226
+ // Nothing can be rested on — an empty narrowed set, or every answer refused. -1 is the state
227
+ // a list nobody has moved in is already in, so no row is marked and Enter has nothing to
228
+ // take. Returning `from` instead handed `lastOpen` the length of the list, and
229
+ // `aria-activedescendant` then named a row id that was never rendered: a screen reader is
230
+ // told where it is and finds nothing there, which is worse than not being told.
231
+ return -1;
232
+ };
233
+ /**
234
+ * The first answer whose words begin with what has been typed, searched circularly.
235
+ *
236
+ * From `after` rather than from the top, which is what makes a letter pressed twice walk
237
+ * through the answers beginning with it instead of returning to the first one each time — the
238
+ * behaviour a native select has, and the reason type-ahead is usable on a list of countries
239
+ * at all.
240
+ *
241
+ * Refusals are skipped, for the reason the arrow keys skip them: landing on an answer that
242
+ * cannot be taken reads as the control being broken rather than as it being careful.
243
+ */
244
+ const matching = (run, after) => {
245
+ for (let i = 1; i <= visible.length; i += 1) {
246
+ const at = (after + i + visible.length * i) % visible.length;
247
+ const option = visible[at];
248
+ if (option?.props.disabled === true)
249
+ continue;
250
+ if (words(option?.props.children).trim().toLowerCase().startsWith(run))
251
+ return at;
252
+ }
253
+ return -1;
254
+ };
255
+ /**
256
+ * A query, and the row the keys should be resting on once it lands.
257
+ *
258
+ * The ring moves to the first answer the new query leaves rather than staying where it was.
259
+ * An index means nothing across two different sets — row three of "land" is not row three of
260
+ * "l" — and a ring left behind pointed at whatever had taken that position, which is the answer
261
+ * Enter would then have given.
262
+ *
263
+ * Nothing matching leaves it at -1, which is the same state as a list nobody has moved in: no
264
+ * row is marked, and Enter has nothing to take.
265
+ */
266
+ const narrow = (next) => {
267
+ setQuery(next);
268
+ setActiveIndex(narrowed(next).findIndex((option) => option.props.disabled !== true));
269
+ };
270
+ /**
271
+ * A letter, and what it means given what came just before it.
272
+ *
273
+ * One character repeated is a request for the next answer beginning with it, which is why the
274
+ * buffer collapses to a single letter in that case rather than searching for "ss". Anything
275
+ * else refines the run: typing "s" then "i" searches for "si" from where "s" landed, so the
276
+ * match narrows rather than jumping to whatever begins with I.
277
+ */
278
+ const typeAhead = (key) => {
279
+ /**
280
+ * Where there is a field, the letter is the start of a query rather than a jump to a row.
281
+ *
282
+ * Kept rather than dropped: somebody who presses S at a shut control has begun typing, and a
283
+ * control that opens a field and swallows the first letter is one they have to notice and
284
+ * type twice.
285
+ *
286
+ * Appended once the list is open, and only replacing the query on the press that opened it.
287
+ */
288
+ if (searchable) {
289
+ if (expanded)
290
+ narrow(query + key);
291
+ else {
292
+ setOpen(true);
293
+ narrow(key);
294
+ }
295
+ return;
296
+ }
297
+ const now = Date.now();
298
+ const run = now - typed.current.at > TYPING_WINDOW ? key : typed.current.text + key;
299
+ typed.current = { text: run, at: now };
300
+ const repeated = run.length > 1 && [...run].every((each) => each === run[0]);
301
+ const sought = (repeated ? run[0] : run).toLowerCase();
302
+ // A repeated letter walks on from where it is; a growing run re-reads from one before, so the
303
+ // answer it just landed on is still the first candidate. Floored at -1, or a run typed at a
304
+ // list nothing is resting on yet would start from -2 and skip the first answer — which is
305
+ // every list opened by `defaultOpen`.
306
+ const found = matching(sought, repeated ? activeIndex : Math.max(activeIndex - 1, -1));
307
+ if (found === -1)
308
+ return;
309
+ if (!expanded)
310
+ openAt(found);
311
+ else
312
+ setActiveIndex(found);
313
+ };
314
+ /**
315
+ * Back to the box, which is where the visitor was before the field took the caret.
316
+ *
317
+ * Focus cannot be left on an element that is about to be removed — the popup goes when the
318
+ * list shuts, and focus with it lands on the body, which is a reader dropped at the top of the
319
+ * page from a control halfway down it.
320
+ */
321
+ const shutAndReturn = () => {
322
+ setOpen(false);
323
+ trigger.current?.focus();
324
+ };
325
+ const firstOpen = () => step(-1, 1);
326
+ const lastOpen = () => step(visible.length, -1);
327
+ const onTheAnswer = () => (chosen === '' ? firstOpen() : indexOf(chosen));
328
+ /**
329
+ * A key that is a letter somebody typed, rather than a command.
330
+ *
331
+ * Space is excluded, and it has to be: here it does what Enter does, so a space that started a
332
+ * search would be a space that stopped taking the answer. Which costs nothing worth having —
333
+ * type-ahead is for the first few letters of a name, and nobody reaches a space before they
334
+ * have found what they were after.
335
+ *
336
+ * A modifier means the keystroke belongs to the browser or the operating system.
337
+ */
338
+ const printable = (event) => event.key.length === 1 && event.key !== ' ' && !event.ctrlKey && !event.metaKey;
339
+ const onKeyDown = (event) => {
340
+ const key = event.key;
341
+ if (!expanded) {
342
+ // All four open it, which is the whole of what a shut combobox does. Enter and Space are
343
+ // here rather than inherited, the role having replaced the button's own activation.
344
+ if (key === 'Enter' || key === ' ' || key === 'ArrowDown') {
345
+ event.preventDefault();
346
+ openAt(onTheAnswer());
347
+ return;
348
+ }
349
+ if (key === 'ArrowUp') {
350
+ event.preventDefault();
351
+ openAt(chosen === '' ? lastOpen() : indexOf(chosen));
352
+ return;
353
+ }
354
+ if (printable(event)) {
355
+ // Typing at a shut control opens it rather than answering it. A native select changes the
356
+ // value outright, which is how brushing a key while tabbing past one silently replaces an
357
+ // answer somebody already gave — the list opening on the match says the same thing and
358
+ // asks before committing to it.
359
+ event.preventDefault();
360
+ typeAhead(key);
361
+ }
362
+ return;
363
+ }
364
+ if (key === 'ArrowDown') {
365
+ event.preventDefault();
366
+ setActiveIndex(step(activeIndex, 1));
367
+ }
368
+ else if (key === 'ArrowUp') {
369
+ event.preventDefault();
370
+ setActiveIndex(step(activeIndex, -1));
371
+ }
372
+ else if (key === 'Home') {
373
+ event.preventDefault();
374
+ setActiveIndex(firstOpen());
375
+ }
376
+ else if (key === 'End') {
377
+ event.preventDefault();
378
+ setActiveIndex(lastOpen());
379
+ }
380
+ else if (key === 'Enter' || key === ' ') {
381
+ event.preventDefault();
382
+ take(activeIndex);
383
+ }
384
+ else if (key === 'Escape') {
385
+ // The answer is left alone. Escape is a visitor saying they did not mean to open the list,
386
+ // not that they have changed their mind about what they already answered.
387
+ event.preventDefault();
388
+ setOpen(false);
389
+ }
390
+ else if (key === 'Tab') {
391
+ // Not prevented, so the press carries on to the next field — but the list goes first.
392
+ // Without this, Tab from an open searchable box walks into the popup and stops on the
393
+ // search field and its clear button, with the list still open behind it. The rows are not
394
+ // tab stops by design; neither should the furniture above them be.
395
+ setOpen(false);
396
+ }
397
+ else if (key === 'Backspace' && searchable) {
398
+ // The counterpart to the letters above. Somebody typing at the box can see the query in the
399
+ // field and cannot reach it with the caret, so without this the only way back from a typo
400
+ // is the mouse — and a control that has to be corrected with the mouse is one the keyboard
401
+ // cannot finish.
402
+ event.preventDefault();
403
+ narrow(query.slice(0, -1));
404
+ }
405
+ else if (printable(event)) {
406
+ event.preventDefault();
407
+ typeAhead(key);
408
+ }
409
+ };
410
+ /**
411
+ * The same keys, read from the field instead of the box.
412
+ *
413
+ * Not the box's handler with a branch in it, because three of its keys mean something else in
414
+ * a field: Space types a space, and Home and End move the caret to the ends of the query —
415
+ * taking those would make the field a worse field than the one it replaced. What is left is
416
+ * the movement and the two ways out.
417
+ */
418
+ const onSearchKeyDown = (event) => {
419
+ const key = event.key;
420
+ if (key === 'ArrowDown') {
421
+ event.preventDefault();
422
+ setActiveIndex(step(activeIndex, 1));
423
+ }
424
+ else if (key === 'ArrowUp') {
425
+ event.preventDefault();
426
+ setActiveIndex(step(activeIndex, -1));
427
+ }
428
+ else if (key === 'Enter') {
429
+ event.preventDefault();
430
+ take(activeIndex);
431
+ }
432
+ else if (key === 'Escape') {
433
+ // The answer is left alone, as it is from the box.
434
+ event.preventDefault();
435
+ shutAndReturn();
436
+ }
437
+ else if (key === 'Tab') {
438
+ // Not prevented. The list shuts and the box takes the focus back, and the press the visitor
439
+ // made carries on from there — so Tab out of an open control lands on the next field, which
440
+ // is where it would have landed had the control been shut.
441
+ shutAndReturn();
442
+ }
443
+ };
444
+ /**
445
+ * Shutting on a press elsewhere, which is the only way out that is not a keystroke.
446
+ *
447
+ * Bound while open and unbound the moment it shuts, rather than left listening: one document
448
+ * handler per Select on a form of six is six of them running on every click anywhere on the
449
+ * page. `pointerdown` rather than `click`, so the list is gone before whatever was underneath
450
+ * it has moved.
451
+ */
452
+ useEffect(() => {
453
+ if (!expanded)
454
+ return;
455
+ const onPointerDown = (event) => {
456
+ if (box.current?.contains(event.target) === true)
457
+ return;
458
+ setOpen(false);
459
+ };
460
+ document.addEventListener('pointerdown', onPointerDown);
461
+ return () => document.removeEventListener('pointerdown', onPointerDown);
462
+ });
463
+ const checking = status === 'pending';
464
+ const reporting = status !== 'none';
465
+ const showsMessage = reporting && given(statusMessage);
466
+ const showsHelper = given(helperText) && !reporting;
467
+ const messageId = showsMessage ? `${rootId}-status` : showsHelper ? `${rootId}-helper` : undefined;
468
+ // Read off the whole set rather than the narrowed one: the box shows the answer that was
469
+ // given, and a query that happens not to match it does not unanswer the control.
470
+ const taken = chosen === '' ? undefined : options.find((option) => option.props.value === chosen);
471
+ return (_jsxs("div", { className: selectParts.root,
472
+ /* The consumer's own, when they gave one, and a generated one when they did not. It was
473
+ being read for the child ids below and then applied to nothing, so `<Select id="country">`
474
+ put "country" on no element at all and any anchor or `getElementById` naming it found
475
+ nothing. */
476
+ id: rootId, "data-size": size, "data-status": status, "data-fixed": String(fixed), children: [_jsxs("div", { className: selectParts['label-row'], children: [_jsxs("span", { className: selectParts.label, id: labelId, children: [label, required ? (_jsx("span", { className: selectParts['required-mark'], "aria-hidden": "true", children: requiredMark === 'asterisk' ? '*' : 'required' })) : null, optional ? _jsx("span", { className: selectParts['optional-mark'], children: "optional" }) : null] }), given(labelTooltip) ? (_jsx(TooltipAnchor, { content: labelTooltip, placement: "top", children: _jsx("button", { type: "button", className: selectParts['label-tooltip'], "aria-label": `About ${label}`, children: _jsx(Icon, { size: selectGlyphStep[size], children: _jsx(CircleInfoRegularIcon, {}) }) }) })) : null] }), _jsxs("div", { className: selectParts.control, ref: box, children: [_jsxs("button", { ref: trigger, type: "button", className: selectParts.field, role: "combobox", "aria-labelledby": labelId, "aria-controls": listId, "aria-expanded": expanded, "aria-haspopup": "listbox", "aria-activedescendant": expanded && activeIndex !== -1 ? rowId(activeIndex) : undefined, "aria-invalid": status === 'error' || undefined, "aria-required": required || undefined, "aria-busy": checking || undefined, "aria-disabled": fixed || undefined, "aria-describedby": messageId, onClick: fixed ? undefined : () => (expanded ? setOpen(false) : openAt(onTheAnswer())), onKeyDown: fixed ? undefined : onKeyDown, ...rest, children: [_jsxs("span", { className: selectParts.answer, children: [taken?.props.leadingIcon, _jsx("span", { className: selectParts.value, "data-placeholder": taken === undefined || undefined, children: taken?.props.children ?? placeholder })] }), _jsx("span", { className: selectParts['trailing-icon'], "aria-hidden": "true", children: _jsx(Icon, { size: selectGlyphStep[size], children: _jsx(ChevronDownRegularIcon, { style: expanded ? { rotate: '180deg' } : undefined }) }) })] }), expanded ? (_jsxs("div", { className: selectParts.popup, children: [searchable ? (
477
+ /* The field the answers are narrowed with, above them rather than in the box — a
478
+ <ul> may hold options and little else, so this could not live in the list, and the
479
+ box below is a button, which nothing can be typed into. */
480
+ _jsx("div", { className: selectParts.search, children: _jsx(SearchInput
481
+ /* The smallest step at every size of control, where a row takes the control's
482
+ own. The difference is what each one is: a row is an answer and has to read at
483
+ the size the form is set in, and this is the way to an answer — so a
484
+ touch-first Select spends its room on the answers rather than on the field
485
+ that finds them. */
486
+ , {
487
+ /* The smallest step at every size of control, where a row takes the control's
488
+ own. The difference is what each one is: a row is an answer and has to read at
489
+ the size the form is set in, and this is the way to an answer — so a
490
+ touch-first Select spends its room on the answers rather than on the field
491
+ that finds them. */
492
+ size: "sm",
493
+ /* Named after the control it narrows, the way the label's own explanation is. A
494
+ second field inside a control, announced as nothing, is a box a screen reader
495
+ arrives at without being told what it is for. Clipped rather than drawn, which
496
+ is SearchInput's own default — the placeholder below carries the words for an
497
+ eye. */
498
+ label: `Search ${label}`, placeholder: `Search ${label}`, clearLabel: "Clear search", value: query, onChange: narrow, "aria-controls": listId, "aria-activedescendant": activeIndex === -1 ? undefined : rowId(activeIndex), onKeyDown: onSearchKeyDown }) })) : null, _jsx("ul", { className: selectParts.listbox, id: listId, role: "listbox", "aria-labelledby": labelId, children: visible.map((option, index) => cloneElement(option, {
499
+ key: option.props.value ?? index,
500
+ id: rowId(index),
501
+ /* Marketing's Option is drawn at two steps where this control has three, so a
502
+ large Select holds rows at the step below it. Which is the honest mapping
503
+ rather than a gap: `lg` is a touch-first box, and its rows are already the
504
+ largest an Option is cut for. */
505
+ size: size === 'sm' ? 'sm' : 'md',
506
+ selected: option.props.value === chosen && chosen !== '',
507
+ active: index === activeIndex,
508
+ // The row reports the press and the control decides what it means, which is why
509
+ // a row that cannot be taken still gets a handler: `take` refuses it in one
510
+ // place rather than every caller remembering to.
511
+ onClick: () => take(index),
512
+ // The pointer moves the ring, so there is one marker rather than two competing.
513
+ onMouseEnter: () => setActiveIndex(index),
514
+ // A press on a row must not take focus off the box. Without this the button
515
+ // blurs, `aria-activedescendant` stops meaning anything, and the handler above
516
+ // reads the press as having landed outside.
517
+ onMouseDown: (event) => event.preventDefault(),
518
+ })) }), searchable ? (
519
+ /* Here whenever the list can be narrowed, and shown only once it has been narrowed
520
+ to nothing. A list that empties reads as a control that broke; a sentence in its
521
+ place reads as an answer, and the visitor needs to know which before they know
522
+ whether to keep typing. */
523
+ _jsx("span", { className: selectParts.empty, "data-shown": visible.length === 0 || undefined, children: emptyLabel })) : null] })) : null] }), showsHelper ? (_jsx("span", { className: selectParts.helper, id: messageId, children: helperText })) : null, showsMessage ? (_jsxs("span", { className: selectParts.message, id: messageId, children: [_jsx("span", { className: selectParts['message-icon'], "aria-hidden": "true", children: checking ? (_jsx(Spinner, { size: "sm", variant: "inherit" })) : (_jsx(Icon, { size: "xs", children: statusGlyph[status] })) }), statusMessage] })) : null] }));
524
+ }
@@ -0,0 +1,96 @@
1
+ import type { ButtonHTMLAttributes, ReactNode } from 'react';
2
+ export interface SelectOwnProps {
3
+ /**
4
+ * `sm` — A filter row above an index, or a narrowing that sits in a bar rather than in a form. Desktop only: below what a finger reliably hits, which is why a filter row that has to work on a phone takes md
5
+ * `md` — The default, and what a marketing form wants. It matches TextInput at the same step, so a contact form's country field and its email field are the same height
6
+ * `lg` — A hero, a conversion band, or a form that is the whole point of the page. The step that pairs with a large Button, so the field and the thing that submits it agree
7
+ */
8
+ size?: 'sm' | 'md' | 'lg';
9
+ /** The answer is settled and still worth reading — a region a page was entered through, a plan a link arrived with. The box keeps its ink and its border and stops opening, so a reader can see what was answered without being invited to change it.
10
+
11
+ Named for what it is rather than borrowed from the family. A text field says this with the platform's `readonly`, which the browser owns and enforces; there is no such attribute for a button, so this is the component's own. */
12
+ fixed?: boolean;
13
+ /** Always — a control with no label is unusable by a screen reader, and on a marketing page it is also the only thing telling a visitor what is being asked before they commit to opening it. A noun phrase naming the answer, in sentence case: "Country", not "Please choose your country" */
14
+ label: string;
15
+ /** A short explanation the label has no room for — why the answer is asked for, what it changes further down the form. Revealed on hover and on focus, so it costs no height */
16
+ labelTooltip?: string;
17
+ /** Always. What the box says with nothing chosen — an instruction rather than an example, there being nothing to spell: "Select a country". Required where a text field's is optional, and the difference is what an empty one looks like: an empty text field looks empty, while an empty box with a chevron looks like it might already hold something */
18
+ placeholder: string;
19
+ /** What the visitor needs to know before they choose — what the answer affects, or where to look if none of the options seem right. On a marketing form this is often the line that decides whether the field gets answered at all: "This only changes which prices we show you" removes a reason to abandon the page */
20
+ helperText?: string;
21
+ /** The chosen answer, when the consumer owns it — the controlled form. The value and not the words, so a page holds "sg" while the box shows "Singapore" and the words can be reworded or translated without changing what any form submits. Which matters more here than in an app: these pages are translated, and a value that travelled as its label would change meaning with the locale */
22
+ value?: string;
23
+ /** The answer the control starts on — a region guessed from where the visitor arrived, or a sort an index defaults to. Leave it out and the placeholder shows, which is what a set with no safe default wants */
24
+ defaultValue?: string;
25
+ /** Always, and it is required for that reason. It hands back the value of the answer taken, each time one is taken — the value rather than an event, there being no keystroke here to read one off. It is also the only way the answer reaches the page: this draws a button rather than a <select>, so there is no form control for a browser to submit on its own */
26
+ onChange: (value: string) => void;
27
+ /** Whether the list is showing, when the consumer owns that too. Left out, the control opens and shuts itself, which is what almost every page wants */
28
+ open?: boolean;
29
+ /** Open on first render. For a documentation page or a specimen that has to show the list without anybody pressing anything — not for a page a visitor lands on, where a list that opens by itself covers whatever is under it */
30
+ defaultOpen?: boolean;
31
+ /** Told when the list opens and shuts, for a page that has to react — closing something else, or holding a scroll position */
32
+ onOpenChange?: (open: boolean) => void;
33
+ /**
34
+ * `text` — Short forms, public ones, and anywhere the label row has room. The safer default and the right one for nearly every marketing form: it needs nothing looked up and still means something read out of context
35
+ * `asterisk` — Long or dense forms where the word repeats down the page and one legend can say it once instead. Only where that legend is visible from the fields it governs
36
+ */
37
+ requiredMark?: 'text' | 'asterisk';
38
+ /** Allowed: Option */
39
+ children: ReactNode;
40
+ }
41
+ export type SelectProps = SelectOwnProps & Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'size' | 'status' | 'fixed' | 'label' | 'labelTooltip' | 'placeholder' | 'helperText' | 'value' | 'defaultValue' | 'onChange' | 'open' | 'defaultOpen' | 'onOpenChange' | 'searchable' | 'emptyLabel' | 'required' | 'requiredMark' | 'optional' | 'statusMessage'> & ({
42
+ required?: boolean;
43
+ optional?: false;
44
+ } | {
45
+ required?: false;
46
+ optional?: boolean;
47
+ }) & ({
48
+ status?: 'none' | 'pending' | 'error' | 'warning' | 'success';
49
+ statusMessage: string;
50
+ } | {
51
+ status?: Exclude<'none' | 'pending' | 'error' | 'warning' | 'success', 'error' | 'warning' | 'pending'>;
52
+ statusMessage?: string;
53
+ }) & ({
54
+ searchable?: boolean;
55
+ emptyLabel: string;
56
+ } | {
57
+ searchable?: false;
58
+ emptyLabel?: string;
59
+ });
60
+ /** The class each part carries. Apply these — do not retype them. */
61
+ export declare const selectParts: {
62
+ readonly root: "dds-select";
63
+ readonly 'label-row': "dds-select__label-row";
64
+ readonly label: "dds-select__label";
65
+ readonly 'label-tooltip': "dds-select__label-tooltip";
66
+ readonly 'required-mark': "dds-select__required-mark";
67
+ readonly 'optional-mark': "dds-select__optional-mark";
68
+ readonly control: "dds-select__control";
69
+ readonly field: "dds-select__field";
70
+ readonly answer: "dds-select__answer";
71
+ readonly value: "dds-select__value";
72
+ readonly 'trailing-icon': "dds-select__trailing-icon";
73
+ readonly popup: "dds-select__popup";
74
+ readonly search: "dds-select__search";
75
+ readonly listbox: "dds-select__listbox";
76
+ readonly empty: "dds-select__empty";
77
+ readonly helper: "dds-select__helper";
78
+ readonly message: "dds-select__message";
79
+ readonly 'message-icon': "dds-select__message-icon";
80
+ };
81
+ /** Generated so defaults cannot drift from the contract. */
82
+ export declare const selectDefaults: {
83
+ readonly size: "md";
84
+ readonly status: "none";
85
+ readonly fixed: false;
86
+ readonly searchable: false;
87
+ readonly required: false;
88
+ readonly requiredMark: "text";
89
+ readonly optional: false;
90
+ };
91
+ /** The step this component draws a glyph slot at. Generated — do not retype. */
92
+ export declare const selectGlyphStep: {
93
+ readonly sm: "xs";
94
+ readonly md: "sm";
95
+ readonly lg: "sm";
96
+ };
@@ -0,0 +1,26 @@
1
+ // GENERATED from select.contract.json. Do not edit.
2
+ /** The class each part carries. Apply these — do not retype them. */
3
+ export const selectParts = {
4
+ root: 'dds-select',
5
+ 'label-row': 'dds-select__label-row',
6
+ label: 'dds-select__label',
7
+ 'label-tooltip': 'dds-select__label-tooltip',
8
+ 'required-mark': 'dds-select__required-mark',
9
+ 'optional-mark': 'dds-select__optional-mark',
10
+ control: 'dds-select__control',
11
+ field: 'dds-select__field',
12
+ answer: 'dds-select__answer',
13
+ value: 'dds-select__value',
14
+ 'trailing-icon': 'dds-select__trailing-icon',
15
+ popup: 'dds-select__popup',
16
+ search: 'dds-select__search',
17
+ listbox: 'dds-select__listbox',
18
+ empty: 'dds-select__empty',
19
+ helper: 'dds-select__helper',
20
+ message: 'dds-select__message',
21
+ 'message-icon': 'dds-select__message-icon',
22
+ };
23
+ /** Generated so defaults cannot drift from the contract. */
24
+ export const selectDefaults = { size: 'md', status: 'none', fixed: false, searchable: false, required: false, requiredMark: 'text', optional: false };
25
+ /** The step this component draws a glyph slot at. Generated — do not retype. */
26
+ export const selectGlyphStep = { sm: 'xs', md: 'sm', lg: 'sm' };