uikit-react-public 0.14.21 → 0.21.8

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 (392) hide show
  1. package/README.md +2 -2
  2. package/dist/components/Accordion/Accordion.Heading.d.ts +5 -4
  3. package/dist/components/Accordion/Accordion.Panel.d.ts +2 -2
  4. package/dist/components/Accordion/Accordion.d.ts +1 -1
  5. package/dist/components/Accordion/Accordion.stories.d.ts +57 -0
  6. package/dist/components/Accordion/index.d.ts +2 -0
  7. package/dist/components/AppHeader/AppHeader.d.ts +1 -1
  8. package/dist/components/AppHeader/AppHeaderBottom.d.ts +1 -1
  9. package/dist/components/AppHeader/AppHeaderNav.d.ts +1 -1
  10. package/dist/components/AppHeader/AppHeaderTop.d.ts +1 -1
  11. package/dist/components/Avatar/Avatar.stories.d.ts +107 -1
  12. package/dist/components/Breadcrumbs/Breadcrumb.d.ts +3 -4
  13. package/dist/components/Breadcrumbs/Breadcrumbs.d.ts +1 -1
  14. package/dist/components/Breadcrumbs/Breadcrumbs.stories.d.ts +1 -1
  15. package/dist/components/Button/Button.d.ts +8 -3
  16. package/dist/components/Button/Button.stories.d.ts +17 -7
  17. package/dist/components/Button/style/buttonAccentStyle.d.ts +4 -0
  18. package/dist/components/Button/style/buttonPrimaryDestructiveStyle.d.ts +4 -0
  19. package/dist/components/Button/style/buttonPrimaryStyle.d.ts +4 -0
  20. package/dist/components/Button/style/buttonPrimarySubtleStyle.d.ts +4 -0
  21. package/dist/components/Button/style/buttonPrimaryWarningStyle.d.ts +4 -0
  22. package/dist/components/Button/style/buttonSecondaryDestructiveStyle.d.ts +4 -0
  23. package/dist/components/Button/style/buttonSecondaryStyle.d.ts +4 -0
  24. package/dist/components/Button/style/buttonSecondarySubtleStyle.d.ts +4 -0
  25. package/dist/components/Button/style/buttonTertiaryDestructiveStyle.d.ts +4 -0
  26. package/dist/components/Button/style/buttonTertiaryNoPaddingStyle.d.ts +4 -0
  27. package/dist/components/Button/style/buttonTertiaryStyle.d.ts +4 -0
  28. package/dist/components/Calendar/index.d.ts +1 -1
  29. package/dist/components/Checkbox/Checkbox.d.ts +1 -0
  30. package/dist/components/Datepicker/Datepicker.d.ts +1 -1
  31. package/dist/components/Datepicker/Datepicker.stories.d.ts +4 -3
  32. package/dist/components/Datepicker/Datepicker.types.d.ts +4 -5
  33. package/dist/components/Datepicker/subcomponents/CustomDatepicker.d.ts +4 -1
  34. package/dist/components/Datepicker/subcomponents/DatepickerInput.d.ts +15 -2
  35. package/dist/components/Datepicker/subcomponents/Panel.d.ts +1 -1
  36. package/dist/components/Datepicker/subcomponents/VisibleField.d.ts +6 -1
  37. package/dist/components/Datepicker/subcomponents/index.d.ts +0 -1
  38. package/dist/components/Datepicker/utils/index.d.ts +0 -1
  39. package/dist/components/Dialog/BaseDialog.d.ts +2 -1
  40. package/dist/components/Dialog/Dialog.d.ts +2 -0
  41. package/dist/components/FooterNew/BackToTop.d.ts +8 -0
  42. package/dist/components/FooterNew/Footer.d.ts +23 -0
  43. package/dist/components/FooterNew/FooterColumn.d.ts +8 -0
  44. package/dist/components/FooterNew/FooterLinks.d.ts +7 -0
  45. package/dist/components/FooterNew/FooterNavLink.d.ts +8 -0
  46. package/dist/components/FooterNew/LegalAndCopyright.d.ts +14 -0
  47. package/dist/components/FooterNew/LogoAddressAndSocial.d.ts +10 -0
  48. package/dist/components/FooterNew/SocialLink.d.ts +8 -0
  49. package/dist/components/FooterNew/index.d.ts +2 -0
  50. package/dist/components/Header/Header.d.ts +4 -1
  51. package/dist/components/Header/Header.stories.d.ts +40 -0
  52. package/dist/components/HeaderNew/Header.d.ts +18 -0
  53. package/dist/components/HeaderNew/HeaderBorder.d.ts +7 -0
  54. package/dist/components/HeaderNew/HeaderLogo.d.ts +9 -0
  55. package/dist/components/HeaderNew/HeaderMenuContainer.d.ts +7 -0
  56. package/dist/components/HeaderNew/HeaderTitle.d.ts +9 -0
  57. package/dist/components/HeaderNew/__tests__/Header.test.d.ts +1 -0
  58. package/dist/components/HeaderNew/constants.d.ts +3 -0
  59. package/dist/components/HeaderNew/index.d.ts +3 -0
  60. package/dist/components/HeadingNew/Heading.d.ts +13 -0
  61. package/dist/components/HeadingNew/index.d.ts +2 -0
  62. package/dist/components/Icon/svgImports.d.ts +7 -881
  63. package/dist/components/Link/BaseLink.d.ts +14 -5
  64. package/dist/components/Link/Link.d.ts +8 -3
  65. package/dist/components/Link/Link.stories.d.ts +3 -1
  66. package/dist/components/Main/Main.d.ts +21 -0
  67. package/dist/components/Main/Main.stories.d.ts +15 -0
  68. package/dist/components/Main/__tests__/Main.test.d.ts +1 -0
  69. package/dist/components/Main/index.d.ts +2 -0
  70. package/dist/components/MenuNew/Menu.context.d.ts +14 -0
  71. package/dist/components/MenuNew/Menu.d.ts +20 -0
  72. package/dist/components/MenuNew/MenuContent.d.ts +9 -0
  73. package/dist/components/MenuNew/MenuItem.d.ts +10 -0
  74. package/dist/components/MenuNew/MenuSection.d.ts +7 -0
  75. package/dist/components/MenuNew/index.d.ts +6 -0
  76. package/dist/components/MenuNew/trigger/ButtonMenuTrigger.d.ts +8 -0
  77. package/dist/components/MenuNew/trigger/IconMenuTrigger.d.ts +8 -0
  78. package/dist/components/NativeDatepicker/NativeDatepicker.d.ts +3 -0
  79. package/dist/components/NativeDatepicker/NativeDatepicker.stories.d.ts +36 -0
  80. package/dist/components/NativeDatepicker/NativeDatepicker.types.d.ts +10 -0
  81. package/dist/components/NativeDatepicker/index.d.ts +2 -0
  82. package/dist/components/{Datepicker → NativeDatepicker}/utils/dateToLocaleISOString/dateToLocaleISOString.d.ts +1 -1
  83. package/dist/components/NativeDatepicker/utils/dateToLocaleISOString/dateToLocaleISOString.test.d.ts +1 -0
  84. package/dist/components/NativeDatepicker/utils/index.d.ts +1 -0
  85. package/dist/components/Overlay/Overlay.stories.d.ts +12 -12
  86. package/dist/components/ParagraphNew/Paragraph.d.ts +13 -0
  87. package/dist/components/ParagraphNew/index.d.ts +4 -0
  88. package/dist/components/Select/Select.d.ts +2 -1
  89. package/dist/components/Select/Select.stories.d.ts +167 -3
  90. package/dist/components/Select/Select.types.d.ts +75 -19
  91. package/dist/components/Select/subcomponents/CustomOption.d.ts +1 -1
  92. package/dist/components/Select/subcomponents/CustomSelect.d.ts +3 -2
  93. package/dist/components/Select/subcomponents/FilterInput.d.ts +16 -0
  94. package/dist/components/Select/subcomponents/NativeSelect.d.ts +5 -1
  95. package/dist/components/Select/subcomponents/VisibleField.d.ts +6 -1
  96. package/dist/components/Select/subcomponents/index.d.ts +1 -0
  97. package/dist/components/Spinner/Spinner.d.ts +2 -0
  98. package/dist/components/StandaloneLink/StandaloneLink.d.ts +8 -5
  99. package/dist/components/StandaloneLink/StandaloneLink.stories.d.ts +3 -1
  100. package/dist/components/Table/Table.d.ts +3 -3
  101. package/dist/components/Table/Table.stories.d.ts +3 -3
  102. package/dist/components/Table/Table.types.d.ts +1 -0
  103. package/dist/components/Table/subcomponents/Cell/Cell.d.ts +5 -1
  104. package/dist/components/Table/subcomponents/Cell/Cell.stories.d.ts +15 -13
  105. package/dist/components/Table/subcomponents/Cell/CellContent.d.ts +5 -1
  106. package/dist/components/Table/subcomponents/HeadCell/HeadCell.d.ts +2 -1
  107. package/dist/components/Table/subcomponents/HeadCell/HeadCell.stories.d.ts +14 -13
  108. package/dist/components/Table/subcomponents/HeadCell/HeadCellContent.d.ts +2 -1
  109. package/dist/components/Table/subcomponents/__tests__/Row.test.d.ts +1 -0
  110. package/dist/components/UclLogoNew/UclLogo.d.ts +8 -0
  111. package/dist/components/UclLogoNew/index.d.ts +2 -0
  112. package/dist/components/WeekPicker/WeekPicker.d.ts +2 -2
  113. package/dist/components/WeekPicker/WeekPicker.stories.d.ts +41 -0
  114. package/dist/components/WeekPicker/WeekPicker.types.d.ts +16 -0
  115. package/dist/components/WeekPicker/index.d.ts +1 -0
  116. package/dist/components/WeekPicker/subcomponents/CustomDatepicker.d.ts +1 -1
  117. package/dist/components/index.d.ts +20 -0
  118. package/dist/hooks/useFocusTrap.d.ts +2 -1
  119. package/dist/index.d.ts +1 -0
  120. package/dist/index.js +22204 -16719
  121. package/dist/theme/__tests__/fonts.test.d.ts +1 -0
  122. package/dist/theme/common/themeCommon.d.ts +904 -0
  123. package/dist/theme/fonts.d.ts +18 -0
  124. package/dist/theme/index.d.ts +6 -3
  125. package/dist/theme/light/lightColour.d.ts +126 -0
  126. package/dist/theme/light/lightTheme.d.ts +3 -0
  127. package/dist/theme/original/color.d.ts +166 -0
  128. package/dist/theme/original/defaultTheme.d.ts +1340 -0
  129. package/dist/theme/original/originalColourNewStructure.d.ts +126 -0
  130. package/dist/theme/useTheme.d.ts +2174 -0
  131. package/dist/utils/__tests__/announce.test.d.ts +1 -0
  132. package/dist/utils/addAlphaToHex.d.ts +5 -0
  133. package/dist/utils/announce.d.ts +6 -0
  134. package/dist/utils/index.d.ts +1 -0
  135. package/dist/utils/scrollToTop.d.ts +2 -0
  136. package/lib/components/Accordion/Accordion.Heading.tsx +65 -34
  137. package/lib/components/Accordion/Accordion.Panel.tsx +11 -7
  138. package/lib/components/Accordion/Accordion.stories.tsx +139 -0
  139. package/lib/components/Accordion/Accordion.tsx +39 -31
  140. package/lib/components/Accordion/__tests__/__snapshots__/Accordion.test.tsx.snap +15 -13
  141. package/lib/components/Accordion/index.ts +2 -0
  142. package/lib/components/Alert/Alert.stories.tsx +1 -1
  143. package/lib/components/Alert/Alert.tsx +12 -12
  144. package/lib/components/Alert/__tests__/__snapshots__/Alert.test.tsx.snap +13 -39
  145. package/lib/components/AppHeader/AppHeader.tsx +6 -11
  146. package/lib/components/AppHeader/AppHeaderBottom.tsx +2 -3
  147. package/lib/components/AppHeader/AppHeaderNav.tsx +2 -3
  148. package/lib/components/AppHeader/AppHeaderTop.tsx +1 -1
  149. package/lib/components/AppHeader/__tests__/__snapshots__/AppHeader.test.tsx.snap +2 -2
  150. package/lib/components/AppMenu/__tests__/__snapshots__/AppMenu.test.tsx.snap +6 -19
  151. package/lib/components/Avatar/Avatar.mdx +117 -0
  152. package/lib/components/Avatar/Avatar.stories.tsx +110 -2
  153. package/lib/components/Badge/Badge.stories.tsx +1 -1
  154. package/lib/components/Blanket/Blanket.stories.tsx +1 -1
  155. package/lib/components/Breadcrumbs/Breadcrumb.tsx +26 -12
  156. package/lib/components/Breadcrumbs/Breadcrumbs.tsx +1 -1
  157. package/lib/components/Breadcrumbs/__tests__/Breadcrumbs.test.tsx +9 -27
  158. package/lib/components/Breadcrumbs/__tests__/__snapshots__/Breadcrumbs.test.tsx.snap +24 -20
  159. package/lib/components/Button/Button.mdx +32 -279
  160. package/lib/components/Button/Button.stories.tsx +44 -51
  161. package/lib/components/Button/Button.tsx +166 -25
  162. package/lib/components/Button/__tests__/Button.test.tsx +49 -15
  163. package/lib/components/Button/__tests__/__snapshots__/Button.test.tsx.snap +80 -73
  164. package/lib/components/Button/style/buttonAccentStyle.ts +53 -0
  165. package/lib/components/Button/style/buttonPrimaryDestructiveStyle.ts +55 -0
  166. package/lib/components/Button/style/buttonPrimaryStyle.ts +53 -0
  167. package/lib/components/Button/style/buttonPrimarySubtleStyle.ts +64 -0
  168. package/lib/components/Button/style/buttonPrimaryWarningStyle.ts +56 -0
  169. package/lib/components/Button/style/buttonSecondaryDestructiveStyle.ts +63 -0
  170. package/lib/components/Button/style/buttonSecondaryStyle.ts +62 -0
  171. package/lib/components/Button/style/buttonSecondarySubtleStyle.ts +72 -0
  172. package/lib/components/Button/style/buttonTertiaryDestructiveStyle.ts +65 -0
  173. package/lib/components/Button/style/buttonTertiaryNoPaddingStyle.ts +52 -0
  174. package/lib/components/Button/style/buttonTertiaryStyle.ts +62 -0
  175. package/lib/components/Calendar/Calendar.stories.tsx +1 -1
  176. package/lib/components/Calendar/Calendar.tsx +2 -2
  177. package/lib/components/Calendar/__tests__/Calendar.test.tsx +23 -15
  178. package/lib/components/Calendar/__tests__/__snapshots__/Calendar.test.tsx.snap +99 -95
  179. package/lib/components/Calendar/index.ts +1 -5
  180. package/lib/components/Calendar/subcomponents/AcademicWeek.tsx +2 -1
  181. package/lib/components/Calendar/subcomponents/AcademicWeeks.tsx +1 -1
  182. package/lib/components/Calendar/subcomponents/ColumnHeading.tsx +2 -2
  183. package/lib/components/Calendar/subcomponents/Controls.tsx +1 -1
  184. package/lib/components/Calendar/subcomponents/Day.stories.tsx +1 -1
  185. package/lib/components/Calendar/subcomponents/Day.tsx +7 -9
  186. package/lib/components/Calendar/subcomponents/EventDot.tsx +3 -6
  187. package/lib/components/Calendar/subcomponents/index.ts +1 -1
  188. package/lib/components/Calendar/utils/getDatesForCalendarGrid/getDatesForCalendarGrid.ts +43 -11
  189. package/lib/components/Calendar/utils/normaliseMonth/normaliseMonth.test.ts +5 -5
  190. package/lib/components/Checkbox/Checkbox.stories.tsx +1 -1
  191. package/lib/components/Checkbox/Checkbox.tsx +12 -10
  192. package/lib/components/Checkbox/__tests__/Checkbox.test.tsx +29 -0
  193. package/lib/components/Checkbox/__tests__/__snapshots__/Checkbox.test.tsx.snap +4 -4
  194. package/lib/components/Datepicker/Datepicker.lld.md +108 -0
  195. package/lib/components/Datepicker/Datepicker.stories.tsx +44 -5
  196. package/lib/components/Datepicker/Datepicker.tsx +14 -36
  197. package/lib/components/Datepicker/Datepicker.types.ts +5 -14
  198. package/lib/components/Datepicker/__tests__/Datepicker.test.tsx +267 -8
  199. package/lib/components/Datepicker/__tests__/__snapshots__/Datepicker.test.tsx.snap +20 -42
  200. package/lib/components/Datepicker/subcomponents/CustomDatepicker.tsx +48 -5
  201. package/lib/components/Datepicker/subcomponents/DatepickerInput.tsx +30 -17
  202. package/lib/components/Datepicker/subcomponents/Panel.tsx +6 -2
  203. package/lib/components/Datepicker/subcomponents/VisibleField.tsx +46 -8
  204. package/lib/components/Datepicker/subcomponents/index.ts +0 -1
  205. package/lib/components/Datepicker/utils/index.ts +0 -1
  206. package/lib/components/Dialog/BaseDialog.tsx +13 -2
  207. package/lib/components/Dialog/Dialog.stories.tsx +1 -1
  208. package/lib/components/Dialog/Dialog.tsx +8 -1
  209. package/lib/components/Dialog/DialogBody.tsx +5 -1
  210. package/lib/components/Dialog/DialogHeader.tsx +2 -1
  211. package/lib/components/Divider/Divider.stories.tsx +1 -1
  212. package/lib/components/Divider/__tests__/__snapshots__/Breadcrumbs.test.tsx.snap +12 -12
  213. package/lib/components/FeedbackDialog/FeedbackDialog.stories.tsx +1 -1
  214. package/lib/components/FeedbackDialog/FeedbackDialog.tsx +4 -6
  215. package/lib/components/Field/CharacterCount.tsx +2 -2
  216. package/lib/components/Field/ErrorText.tsx +2 -1
  217. package/lib/components/Field/Field.stories.tsx +1 -1
  218. package/lib/components/Field/Field.tsx +1 -1
  219. package/lib/components/Field/HelperText.tsx +3 -1
  220. package/lib/components/Field/__tests__/Field.test.tsx +13 -0
  221. package/lib/components/FileInput/FileInput.stories.tsx +1 -1
  222. package/lib/components/FileInput/__tests__/__snapshots__/FileInput.test.tsx.snap +4 -20
  223. package/lib/components/Footer/Footer.stories.tsx +1 -1
  224. package/lib/components/Footer/__tests__/__snapshots__/Footer.test.tsx.snap +73 -82
  225. package/lib/components/FooterNew/BackToTop.tsx +83 -0
  226. package/lib/components/FooterNew/Footer.tsx +110 -0
  227. package/lib/components/FooterNew/FooterColumn.tsx +79 -0
  228. package/lib/components/FooterNew/FooterLinks.tsx +44 -0
  229. package/lib/components/FooterNew/FooterNavLink.tsx +63 -0
  230. package/lib/components/FooterNew/LegalAndCopyright.tsx +150 -0
  231. package/lib/components/FooterNew/LogoAddressAndSocial.tsx +154 -0
  232. package/lib/components/FooterNew/SocialLink.tsx +108 -0
  233. package/lib/components/FooterNew/__tests__/Footer.test.tsx +51 -0
  234. package/lib/components/FooterNew/__tests__/__snapshots__/Footer.test.tsx.snap +1107 -0
  235. package/lib/components/FooterNew/index.ts +2 -0
  236. package/lib/components/Header/Header.mdx +52 -0
  237. package/lib/components/Header/Header.stories.tsx +98 -0
  238. package/lib/components/Header/Header.tsx +51 -6
  239. package/lib/components/Header/__tests__/Header.test.tsx +17 -1
  240. package/lib/components/HeaderDraft/__tests__/__snapshots__/Header.test.tsx.snap +3 -2
  241. package/lib/components/HeaderNew/Header.tsx +93 -0
  242. package/lib/components/HeaderNew/HeaderBorder.tsx +55 -0
  243. package/lib/components/HeaderNew/HeaderLogo.tsx +70 -0
  244. package/lib/components/HeaderNew/HeaderMenuContainer.tsx +35 -0
  245. package/lib/components/HeaderNew/HeaderTitle.tsx +53 -0
  246. package/lib/components/HeaderNew/__tests__/Header.test.tsx +42 -0
  247. package/lib/components/HeaderNew/__tests__/__snapshots__/Header.test.tsx.snap +79 -0
  248. package/lib/components/HeaderNew/constants.ts +3 -0
  249. package/lib/components/HeaderNew/index.ts +7 -0
  250. package/lib/components/Heading/Heading.stories.tsx +1 -1
  251. package/lib/components/HeadingNew/Heading.tsx +208 -0
  252. package/lib/components/HeadingNew/index.ts +2 -0
  253. package/lib/components/Icon/Icon.stories.tsx +1 -1
  254. package/lib/components/Icon/__tests__/__snapshots__/Icon.test.tsx.snap +16 -12
  255. package/lib/components/Icon/svgImports.ts +318 -296
  256. package/lib/components/IconButton/IconButton.stories.tsx +1 -1
  257. package/lib/components/IconButton/IconButton.tsx +3 -4
  258. package/lib/components/IconButton/__tests__/__snapshots__/IconButton.test.tsx.snap +12 -9
  259. package/lib/components/Input/Input.stories.tsx +1 -1
  260. package/lib/components/Label/Label.stories.tsx +1 -1
  261. package/lib/components/Link/BaseLink.tsx +114 -71
  262. package/lib/components/Link/Link.stories.tsx +1 -1
  263. package/lib/components/Link/Link.tsx +120 -109
  264. package/lib/components/Link/__tests__/__snapshots__/link.test.tsx.snap +2 -2
  265. package/lib/components/Main/Main.stories.tsx +36 -0
  266. package/lib/components/Main/Main.tsx +46 -0
  267. package/lib/components/Main/__tests__/Main.test.tsx +80 -0
  268. package/lib/components/Main/__tests__/__snapshots__/Main.test.tsx.snap +33 -0
  269. package/lib/components/Main/index.ts +2 -0
  270. package/lib/components/MenuNew/Menu.context.tsx +149 -0
  271. package/lib/components/MenuNew/Menu.tsx +75 -0
  272. package/lib/components/MenuNew/MenuContent.tsx +140 -0
  273. package/lib/components/MenuNew/MenuItem.tsx +101 -0
  274. package/lib/components/MenuNew/MenuSection.tsx +47 -0
  275. package/lib/components/MenuNew/index.ts +8 -0
  276. package/lib/components/MenuNew/trigger/ButtonMenuTrigger.tsx +42 -0
  277. package/lib/components/MenuNew/trigger/IconMenuTrigger.tsx +40 -0
  278. package/lib/components/NativeDatepicker/NativeDatepicker.stories.tsx +100 -0
  279. package/lib/components/{Datepicker/subcomponents → NativeDatepicker}/NativeDatepicker.tsx +14 -15
  280. package/lib/components/NativeDatepicker/NativeDatepicker.types.ts +19 -0
  281. package/lib/components/NativeDatepicker/index.ts +2 -0
  282. package/lib/components/{Datepicker → NativeDatepicker}/utils/dateToLocaleISOString/dateToLocaleISOString.ts +1 -1
  283. package/lib/components/NativeDatepicker/utils/index.ts +1 -0
  284. package/lib/components/Pagination/Pagination.stories.tsx +1 -1
  285. package/lib/components/Pagination/PaginationControls.tsx +59 -17
  286. package/lib/components/Pagination/PaginationInfo.tsx +7 -4
  287. package/lib/components/Paragraph/Paragraph.stories.tsx +1 -1
  288. package/lib/components/ParagraphNew/Paragraph.tsx +200 -0
  289. package/lib/components/ParagraphNew/index.ts +6 -0
  290. package/lib/components/Radio/Radio.stories.tsx +1 -1
  291. package/lib/components/Radio/Radio.tsx +8 -8
  292. package/lib/components/Radio/__tests__/__snapshots__/Radio.test.tsx.snap +4 -4
  293. package/lib/components/Search/Search.stories.tsx +1 -1
  294. package/lib/components/Search/Search.tsx +4 -1
  295. package/lib/components/Search/__tests__/Search.test.tsx +19 -1
  296. package/lib/components/Search/__tests__/__snapshots__/Search.test.tsx.snap +12 -32
  297. package/lib/components/Select/Select.mdx +192 -0
  298. package/lib/components/Select/Select.stories.tsx +229 -48
  299. package/lib/components/Select/Select.tsx +50 -15
  300. package/lib/components/Select/Select.types.ts +99 -44
  301. package/lib/components/Select/__tests__/Select.test.tsx +698 -8
  302. package/lib/components/Select/__tests__/__snapshots__/Select.test.tsx.snap +5 -4
  303. package/lib/components/Select/subcomponents/CustomOption.tsx +12 -4
  304. package/lib/components/Select/subcomponents/CustomSelect.tsx +411 -41
  305. package/lib/components/Select/subcomponents/FilterInput.tsx +90 -0
  306. package/lib/components/Select/subcomponents/NativeSelect.tsx +21 -17
  307. package/lib/components/Select/subcomponents/Panel.tsx +2 -2
  308. package/lib/components/Select/subcomponents/VisibleField.tsx +59 -6
  309. package/lib/components/Select/subcomponents/index.tsx +1 -0
  310. package/lib/components/Snackbar/Snackbar.stories.tsx +1 -1
  311. package/lib/components/Snackbar/__tests__/__snapshots__/Snackbar.test.tsx.snap +9 -15
  312. package/lib/components/Spinner/Spinner.stories.tsx +1 -1
  313. package/lib/components/Spinner/Spinner.tsx +24 -5
  314. package/lib/components/Spinner/__tests__/Spinner.test.tsx +35 -5
  315. package/lib/components/Spinner/__tests__/__snapshots__/Spinner.test.tsx.snap +40 -16
  316. package/lib/components/StandaloneLink/StandaloneLink.stories.tsx +1 -1
  317. package/lib/components/StandaloneLink/StandaloneLink.tsx +180 -163
  318. package/lib/components/StandaloneLink/__tests__/__snapshots__/StandaloneLink.test.tsx.snap +2 -2
  319. package/lib/components/Table/Table.stories.tsx +1 -1
  320. package/lib/components/Table/Table.tsx +2 -0
  321. package/lib/components/Table/Table.types.ts +1 -0
  322. package/lib/components/Table/__tests__/Table.test.tsx +19 -0
  323. package/lib/components/Table/__tests__/__snapshots__/Table.test.tsx.snap +7 -3
  324. package/lib/components/Table/subcomponents/Cell/Cell.stories.tsx +1 -1
  325. package/lib/components/Table/subcomponents/Cell/Cell.tsx +23 -2
  326. package/lib/components/Table/subcomponents/Cell/CellContent.tsx +12 -1
  327. package/lib/components/Table/subcomponents/Cell/__tests__/Cell.test.tsx +106 -0
  328. package/lib/components/Table/subcomponents/Cell/__tests__/__snapshots__/Cell.test.tsx.snap +4 -3
  329. package/lib/components/Table/subcomponents/HeadCell/HeadCell.stories.tsx +1 -1
  330. package/lib/components/Table/subcomponents/HeadCell/HeadCell.tsx +28 -6
  331. package/lib/components/Table/subcomponents/HeadCell/HeadCellContent.tsx +3 -0
  332. package/lib/components/Table/subcomponents/HeadCell/__tests__/HeadCell.test.tsx +221 -2
  333. package/lib/components/Table/subcomponents/HeadCell/__tests__/__snapshots__/HeadCell.test.tsx.snap +6 -4
  334. package/lib/components/Table/subcomponents/Row.tsx +2 -2
  335. package/lib/components/Table/subcomponents/SortIcon.tsx +1 -0
  336. package/lib/components/Table/subcomponents/__tests__/Row.test.tsx +59 -0
  337. package/lib/components/Tabs/Tab.tsx +3 -3
  338. package/lib/components/Tabs/Tabs.stories.tsx +1 -1
  339. package/lib/components/Tabs/Tabs.tsx +5 -3
  340. package/lib/components/Tabs/__tests__/__snapshots__/Tabs.test.tsx.snap +4 -4
  341. package/lib/components/Textarea/Textarea.stories.tsx +1 -1
  342. package/lib/components/Timepicker/Timepicker.stories.tsx +1 -1
  343. package/lib/components/Timepicker/Timepicker.tsx +4 -0
  344. package/lib/components/Timepicker/__tests__/__snapshots__/Timepicker.test.tsx.snap +2 -2
  345. package/lib/components/Toggle/Toggle.stories.tsx +1 -1
  346. package/lib/components/Toggle/Toggle.tsx +5 -5
  347. package/lib/components/Toggle/ToggleHandle.tsx +2 -3
  348. package/lib/components/Tooltip/Tooltip.stories.tsx +1 -1
  349. package/lib/components/Tooltip/Tooltip.tsx +2 -2
  350. package/lib/components/Tooltip/__tests__/__snapshots__/tooltip.test.tsx.snap +2 -2
  351. package/lib/components/UclLogoNew/UclLogo.tsx +42 -0
  352. package/lib/components/UclLogoNew/index.ts +2 -0
  353. package/lib/components/WeekPicker/WeekPicker.stories.tsx +145 -0
  354. package/lib/components/WeekPicker/WeekPicker.tsx +2 -2
  355. package/lib/components/WeekPicker/WeekPicker.types.ts +21 -0
  356. package/lib/components/WeekPicker/index.ts +1 -0
  357. package/lib/components/WeekPicker/subcomponents/CustomDatepicker.tsx +1 -1
  358. package/lib/components/common/Common.mdx +1 -2
  359. package/lib/components/index.ts +30 -3
  360. package/lib/hooks/useFocusTrap.ts +40 -4
  361. package/lib/index.ts +1 -0
  362. package/lib/theme/Colours.mdx +1 -1
  363. package/lib/theme/Theme.mdx +1 -1
  364. package/lib/theme/Typography.mdx +1 -1
  365. package/lib/theme/__tests__/fonts.test.ts +37 -0
  366. package/lib/theme/common/themeCommon.ts +515 -0
  367. package/lib/theme/fonts.ts +110 -0
  368. package/lib/theme/index.ts +6 -6
  369. package/lib/theme/light/lightColour.ts +232 -0
  370. package/lib/theme/light/lightTheme.ts +37 -0
  371. package/lib/theme/{defaultTheme.ts → original/color.ts} +17 -199
  372. package/lib/theme/original/defaultTheme.ts +207 -0
  373. package/lib/theme/original/originalColourNewStructure.ts +185 -0
  374. package/lib/theme/useTheme.tsx +72 -15
  375. package/lib/types/assets.d.ts +10 -0
  376. package/lib/utils/__tests__/announce.test.ts +121 -0
  377. package/lib/utils/addAlphaToHex.ts +29 -0
  378. package/lib/utils/announce.ts +134 -0
  379. package/lib/utils/index.ts +1 -0
  380. package/lib/utils/scrollToTop.ts +5 -0
  381. package/package.json +11 -9
  382. package/dist/components/Button/buttonPrimaryStyle.d.ts +0 -4
  383. package/dist/components/Button/buttonSecondaryStyle.d.ts +0 -4
  384. package/dist/components/Button/buttonTertiaryStyle.d.ts +0 -4
  385. package/dist/components/Datepicker/subcomponents/NativeDatepicker.d.ts +0 -6
  386. package/dist/theme/defaultTheme.d.ts +0 -274
  387. package/lib/components/Accordion/Accordion.stories.tsx.NOT_READY +0 -93
  388. package/lib/components/Button/buttonPrimaryStyle.ts +0 -62
  389. package/lib/components/Button/buttonSecondaryStyle.ts +0 -65
  390. package/lib/components/Button/buttonTertiaryStyle.ts +0 -54
  391. /package/dist/components/{Datepicker/utils/dateToLocaleISOString/dateToLocaleISOString.test.d.ts → FooterNew/__tests__/Footer.test.d.ts} +0 -0
  392. /package/lib/components/{Datepicker → NativeDatepicker}/utils/dateToLocaleISOString/dateToLocaleISOString.test.ts +0 -0
@@ -1,6 +1,2 @@
1
1
  export { default } from './Calendar';
2
- export type {
3
- CalendarProps,
4
- CalendarEvent,
5
- AcademicWeek,
6
- } from './Calendar.types';
2
+ export type { CalendarProps, CalendarEvent, AcademicWeek } from './Calendar.types';
@@ -18,7 +18,8 @@ const AcademicWeek = ({ weekNumber }: AcademicWeekProps) => {
18
18
  height: 40px;
19
19
  font-family: ${theme.font.family.primary};
20
20
  font-size: ${theme.font.size.f14};
21
- color: #6345a5; // TODO: Needs a sensible design token
21
+ /* color: #6345a5; */
22
+ color: ${theme.colour.text.brandPrimary};
22
23
  `;
23
24
 
24
25
  const style = cx(NAME, baseStyle);
@@ -22,7 +22,7 @@ const AcademicWeeks = ({ date, weeks }: AcademicWeeksProps) => {
22
22
  flex-direction: column;
23
23
  padding-top: 32px;
24
24
  width: 50px;
25
- background-color: ${theme.color.interaction.blue5};
25
+ background-color: ${theme.colour.surface.brand};
26
26
  user-select: none;
27
27
  `;
28
28
 
@@ -19,8 +19,8 @@ const ColumnHeading = ({ index, day, isWeekend }: ColumnHeadingProps) => {
19
19
  width: 40px;
20
20
  height: 32px;
21
21
  color: ${isWeekend
22
- ? theme.color.system.orange100
23
- : theme.color.neutral.grey60};
22
+ ? theme.colour.text.warningOnBgFill
23
+ : theme.colour.text.secondary};
24
24
  font-weight: 700;
25
25
  `;
26
26
 
@@ -32,7 +32,7 @@ const Controls = ({ month, changeMonth }: ControlsProps) => {
32
32
  cursor: pointer;
33
33
 
34
34
  &:hover {
35
- color: ${theme.color.neutral.grey60};
35
+ color: ${theme.colour.icon.default};
36
36
  }
37
37
  `;
38
38
 
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react';
2
2
  import Day from './Day';
3
3
 
4
4
  const meta = {
5
- title: 'Components/Work in progress/Calendar/Day',
5
+ title: 'Components/Calendar/Day',
6
6
  component: Day,
7
7
  argTypes: {
8
8
  events: {
@@ -42,25 +42,24 @@ const Day = ({
42
42
  position: relative;
43
43
  width: 40px;
44
44
  height: 40px;
45
- background-color: ${theme.color.neutral.white};
45
+ background-color: ${theme.colour.fill.inverse};
46
46
  cursor: pointer;
47
47
  outline: none;
48
48
 
49
49
  &:hover {
50
- background-color: ${theme.color.neutral.grey10};
50
+ background-color: ${theme.colour.fill.hover};
51
51
  }
52
52
 
53
53
  ${isSelected &&
54
54
  css`
55
- /* background-color: ${theme.color.interaction.blue70}; */
56
55
  background-color: ${isDisabled
57
- ? theme.color.neutral.grey10
58
- : theme.color.interaction.blue70};
56
+ ? theme.colour.fill.disabled
57
+ : theme.colour.fill.brand};
59
58
 
60
- color: ${theme.color.text.inverted};
59
+ color: ${theme.colour.text.inverse};
61
60
 
62
61
  &:hover {
63
- background-color: ${theme.color.interaction.blue100};
62
+ background-color: ${theme.colour.fill.brandHover};
64
63
  }
65
64
  `}
66
65
  ${isDisabled &&
@@ -68,7 +67,6 @@ const Day = ({
68
67
  cursor: not-allowed;
69
68
 
70
69
  &:hover {
71
- /* background-color: ${theme.color.neutral.white}; */
72
70
  background-color: ${isSelected
73
71
  ? theme.color.neutral.grey10
74
72
  : theme.color.neutral.white};
@@ -91,7 +89,7 @@ const Day = ({
91
89
  `}
92
90
  ${isDisabled &&
93
91
  css`
94
- color: ${theme.color.neutral.grey20};
92
+ color: ${theme.colour.text.disabled};
95
93
  `}
96
94
  `;
97
95
 
@@ -11,14 +11,11 @@ interface EventDotProps {
11
11
  const EventDot = ({ inverted, inCurrentMonth }: EventDotProps) => {
12
12
  const [theme] = useTheme();
13
13
 
14
- const invertedColour = theme.color.neutral.white;
15
- const outOfCurrentMonthColour = '#8C8C8C'; // TODO: Needs adding to `defaultTheme.ts`, as a design token
16
-
17
14
  const backgroundColour = inCurrentMonth
18
15
  ? inverted
19
- ? invertedColour
20
- : theme.color.interaction.blue70
21
- : outOfCurrentMonthColour;
16
+ ? theme.colour.icon.inverse
17
+ : theme.colour.icon.brand
18
+ : theme.colour.icon.tertiary;
22
19
 
23
20
  const baseStyle = css`
24
21
  width: 6px;
@@ -4,4 +4,4 @@ export { default as AcademicWeek } from './AcademicWeek';
4
4
  export { default as Grid } from './Grid';
5
5
  export { default as ColumnHeading } from './ColumnHeading';
6
6
  export { default as Day } from './Day';
7
- export { default as EventDot } from './EventDot';
7
+ export { default as EventDot } from './EventDot';
@@ -17,15 +17,24 @@
17
17
  * ```
18
18
  */
19
19
  const getDatesForCalendarGrid = (date: Date): Date[] => {
20
- if (!date || !(date instanceof Date)) throw new Error('No date provided');
20
+ if (!date || !(date instanceof Date))
21
+ throw new Error('No date provided');
21
22
 
22
23
  const month = date.getMonth();
23
- const daysInMonth = new Date(date.getFullYear(), month + 1, 0).getDate();
24
+ const daysInMonth = new Date(
25
+ date.getFullYear(),
26
+ month + 1,
27
+ 0
28
+ ).getDate();
24
29
 
25
30
  // Get all days in current month
26
31
  const dates: Date[] = [];
27
32
  for (let day = 1; day <= daysInMonth; day++) {
28
- const newDate = new Date(date.getFullYear(), month, day);
33
+ const newDate = new Date(
34
+ date.getFullYear(),
35
+ month,
36
+ day
37
+ );
29
38
  if (newDate.getMonth() !== month) break;
30
39
  dates.push(newDate);
31
40
  }
@@ -34,14 +43,28 @@ const getDatesForCalendarGrid = (date: Date): Date[] => {
34
43
  // Sunday (0) should become 6
35
44
  // Monday (1) should become 0
36
45
  // Tuesday (2) should become 1, etc.
37
- const adjustDay = (day: number): number => (day === 0 ? 6 : day - 1);
46
+ const adjustDay = (day: number): number =>
47
+ day === 0 ? 6 : day - 1;
38
48
 
39
49
  // Calculate previous month's "grey days"
40
50
  const prevMonthGreyDays = [];
41
- const prevMonth = new Date(date.getFullYear(), month - 1, 1);
42
- const firstDayOfMonth = new Date(date.getFullYear(), month, 1).getDay();
43
- const numberOfDaysFromPrevMonth = adjustDay(firstDayOfMonth);
44
- const totalDaysInPrevMonth = new Date(date.getFullYear(), month, 0).getDate();
51
+ const prevMonth = new Date(
52
+ date.getFullYear(),
53
+ month - 1,
54
+ 1
55
+ );
56
+ const firstDayOfMonth = new Date(
57
+ date.getFullYear(),
58
+ month,
59
+ 1
60
+ ).getDay();
61
+ const numberOfDaysFromPrevMonth =
62
+ adjustDay(firstDayOfMonth);
63
+ const totalDaysInPrevMonth = new Date(
64
+ date.getFullYear(),
65
+ month,
66
+ 0
67
+ ).getDate();
45
68
 
46
69
  for (let i = numberOfDaysFromPrevMonth; i > 0; i--) {
47
70
  prevMonthGreyDays.push(
@@ -55,17 +78,26 @@ const getDatesForCalendarGrid = (date: Date): Date[] => {
55
78
 
56
79
  // Calculate next month's "grey days"
57
80
  const nextMonthGreyDays = [];
58
- const nextMonth = new Date(date.getFullYear(), month + 1, 1);
81
+ const nextMonth = new Date(
82
+ date.getFullYear(),
83
+ month + 1,
84
+ 1
85
+ );
59
86
  const lastDayOfMonth = new Date(
60
87
  date.getFullYear(),
61
88
  month,
62
89
  daysInMonth
63
90
  ).getDay();
64
- const numberOfDaysFromNextMonth = 6 - adjustDay(lastDayOfMonth);
91
+ const numberOfDaysFromNextMonth =
92
+ 6 - adjustDay(lastDayOfMonth);
65
93
 
66
94
  for (let i = 1; i <= numberOfDaysFromNextMonth; i++) {
67
95
  nextMonthGreyDays.push(
68
- new Date(nextMonth.getFullYear(), nextMonth.getMonth(), i)
96
+ new Date(
97
+ nextMonth.getFullYear(),
98
+ nextMonth.getMonth(),
99
+ i
100
+ )
69
101
  );
70
102
  }
71
103
 
@@ -2,15 +2,15 @@ import { describe, expect, test } from 'vitest';
2
2
  import normaliseMonth from './normaliseMonth';
3
3
 
4
4
  describe('Calendar: normaliseMonth', () => {
5
- test('Should return null if given undefined', () => {
5
+ test("Should return null if given undefined", () => {
6
6
  expect(normaliseMonth(undefined)).toBeNull();
7
7
  });
8
8
 
9
- test('Should return null if given null', () => {
9
+ test("Should return null if given null", () => {
10
10
  expect(normaliseMonth(null)).toBeNull();
11
11
  });
12
12
 
13
- test('Returns a Date object set to the first of the month', () => {
13
+ test("Returns a Date object set to the first of the month", () => {
14
14
  const date = new Date('2025-03-10');
15
15
  const normalisedDate = normaliseMonth(date);
16
16
  expect(normalisedDate).toBeInstanceOf(Date);
@@ -19,7 +19,7 @@ describe('Calendar: normaliseMonth', () => {
19
19
  expect(normalisedDate?.getDate()).toBe(1);
20
20
  });
21
21
 
22
- test('Works for a date within daylight saving time', () => {
22
+ test("Works for a date within daylight saving time", () => {
23
23
  const date = new Date('2025-06-15');
24
24
  const normalisedDate = normaliseMonth(date);
25
25
  expect(normalisedDate).toBeInstanceOf(Date);
@@ -28,7 +28,7 @@ describe('Calendar: normaliseMonth', () => {
28
28
  expect(normalisedDate?.getDate()).toBe(1);
29
29
  });
30
30
 
31
- test('Returned date is normalised for midnight', () => {
31
+ test("Returned date is normalised for midnight", () => {
32
32
  const date = new Date('2025-01-01T12:34:56');
33
33
  const normalisedDate = normaliseMonth(date);
34
34
  expect(normalisedDate).toBeInstanceOf(Date);
@@ -4,7 +4,7 @@ import { useArgs } from '@storybook/preview-api';
4
4
  import Checkbox from './Checkbox';
5
5
 
6
6
  const meta = {
7
- title: 'Components/Work in progress/Checkbox',
7
+ title: 'Components/Checkbox',
8
8
  component: Checkbox,
9
9
  argTypes: {
10
10
  checked: { control: { type: 'boolean' } },
@@ -12,10 +12,10 @@ import marginsStyle, { MarginProps } from '../common/marginsStyle';
12
12
 
13
13
  export const NAME = 'ucl-uikit-checkbox';
14
14
 
15
- export interface CheckboxBaseProps
16
- extends InputHTMLAttributes<HTMLInputElement> {
15
+ export interface CheckboxBaseProps extends InputHTMLAttributes<HTMLInputElement> {
17
16
  indeterminate?: boolean;
18
17
  testId?: string;
18
+ ariaLabel?: string;
19
19
  }
20
20
 
21
21
  export type CheckboxProps = CheckboxBaseProps & MarginProps;
@@ -30,6 +30,7 @@ const Checkbox = forwardRef<Ref, CheckboxProps>(
30
30
  defaultChecked,
31
31
  disabled,
32
32
  testId = NAME,
33
+ ariaLabel,
33
34
  className,
34
35
  ...props
35
36
  },
@@ -61,7 +62,7 @@ const Checkbox = forwardRef<Ref, CheckboxProps>(
61
62
  border-radius: ${theme.radius.r2};
62
63
  outline: none;
63
64
  box-sizing: border-box;
64
- color: ${theme.color.neutral.white};
65
+ color: ${theme.colour.icon.inverse};
65
66
  transition:
66
67
  background-color 0.15s ease-out,
67
68
  border-color 0.15s ease-out;
@@ -75,19 +76,19 @@ const Checkbox = forwardRef<Ref, CheckboxProps>(
75
76
  `;
76
77
 
77
78
  const checkedStyle = css`
78
- background-color: ${theme.color.interaction.blue70};
79
- border-color: ${theme.color.interaction.blue70};
80
- color: ${theme.color.neutral.white};
79
+ background-color: ${theme.colour.icon.brand};
80
+ border-color: ${theme.colour.icon.brand};
81
+ color: ${theme.colour.icon.inverse};
81
82
  `;
82
83
 
83
84
  const uncheckedStyle = css`
84
- background-color: ${theme.color.neutral.white};
85
- border-color: ${theme.color.neutral.grey60};
85
+ background-color: ${theme.colour.icon.inverse};
86
+ border-color: ${theme.colour.speciality.inputDefault};
86
87
  `;
87
88
 
88
89
  const disabledStyle = css`
89
- background-color: ${theme.color.neutral.grey20};
90
- border-color: ${theme.color.neutral.grey20};
90
+ background-color: ${theme.colour.icon.disabled};
91
+ border-color: ${theme.colour.icon.disabled};
91
92
  cursor: not-allowed;
92
93
  `;
93
94
 
@@ -140,6 +141,7 @@ const Checkbox = forwardRef<Ref, CheckboxProps>(
140
141
  ref={ref}
141
142
  className={hiddenInputStyle}
142
143
  data-testid={testId}
144
+ aria-label={ariaLabel}
143
145
  {...(isControlled ? { checked } : { defaultChecked })}
144
146
  disabled={disabled}
145
147
  onChange={handleChange}
@@ -96,4 +96,33 @@ describe('Checkbox', () => {
96
96
  await user.click(checkbox);
97
97
  expect(checkbox.checked).toBe(false);
98
98
  });
99
+
100
+ // Accessibility tests
101
+
102
+ test('ariaLabel prop is applied to the input as aria-label', () => {
103
+ render(
104
+ <ThemeContextProvider>
105
+ <Checkbox ariaLabel='Select John Smith' />
106
+ </ThemeContextProvider>
107
+ );
108
+ expect(screen.getByRole('checkbox')).toHaveAttribute(
109
+ 'aria-label',
110
+ 'Select John Smith'
111
+ );
112
+ });
113
+
114
+ test('aria-label passed via spread props overrides ariaLabel', () => {
115
+ render(
116
+ <ThemeContextProvider>
117
+ <Checkbox
118
+ ariaLabel='Default label'
119
+ aria-label='Override label'
120
+ />
121
+ </ThemeContextProvider>
122
+ );
123
+ expect(screen.getByRole('checkbox')).toHaveAttribute(
124
+ 'aria-label',
125
+ 'Override label'
126
+ );
127
+ });
99
128
  });
@@ -2,7 +2,7 @@
2
2
 
3
3
  exports[`Checkbox > snapshot: checked prop 1`] = `
4
4
  <span
5
- class="ucl-uikit-checkbox css-1g4adr4"
5
+ class="ucl-uikit-checkbox css-xzd91z"
6
6
  >
7
7
  <input
8
8
  checked=""
@@ -32,7 +32,7 @@ exports[`Checkbox > snapshot: checked prop 1`] = `
32
32
 
33
33
  exports[`Checkbox > snapshot: indeterminate prop 1`] = `
34
34
  <span
35
- class="ucl-uikit-checkbox css-1g4adr4"
35
+ class="ucl-uikit-checkbox css-xzd91z"
36
36
  >
37
37
  <input
38
38
  class="css-nzy7im"
@@ -64,7 +64,7 @@ exports[`Checkbox > snapshot: indeterminate prop 1`] = `
64
64
 
65
65
  exports[`Checkbox > snapshot: no props 1`] = `
66
66
  <span
67
- class="ucl-uikit-checkbox css-cg31xm"
67
+ class="ucl-uikit-checkbox css-tumlz"
68
68
  >
69
69
  <input
70
70
  class="css-nzy7im"
@@ -76,7 +76,7 @@ exports[`Checkbox > snapshot: no props 1`] = `
76
76
 
77
77
  exports[`Checkbox > snapshot: testId prop 1`] = `
78
78
  <span
79
- class="ucl-uikit-checkbox css-cg31xm"
79
+ class="ucl-uikit-checkbox css-tumlz"
80
80
  >
81
81
  <input
82
82
  class="css-nzy7im"
@@ -0,0 +1,108 @@
1
+ # Datepicker - Low-level design documentation
2
+
3
+ ## Overview
4
+
5
+ The `<Datepicker>` allows the user to enter a date into the system.
6
+
7
+ By default, it is a 'custom' implementation built using React logic.
8
+
9
+ A 'browser-native' implementation is also available from this component, using prop `native={true}`.
10
+
11
+ ## Design specifications
12
+
13
+ - Figma: [UCL Design System - UIKit Datepicker](https://www.figma.com/design/8Sm5PxWOWJYpYXAzhRzUzt/UCL-Design-System-UI-Kit?node-id=6531-3397)
14
+
15
+ ## Conceptual model
16
+
17
+ The Calendar displayed is a separate UI 'unit' in the Design System, so it is imported rather than defined in this component.
18
+
19
+ There are additional useful features, such as displaying when 'events' are in the calendar. The Datepicker needs to pass these to the Calendar.
20
+
21
+ The Datepicker supports minimum & maximum dates, and validates against a date being outside this range.
22
+
23
+ ### User interaction
24
+
25
+ The user wants to enter a date into the system. They do this by clicking on the datepicker and typing. This is the **primary** interaction model.
26
+
27
+ The user might also want to see and then select a date from the calendar view. This is the **secondary** interaction model.
28
+
29
+ ## Implementation details
30
+
31
+ As much as possible, all core logic should be defined in `<CustomDatepicker>`. Subcomponents should be simple and focused on a single responsibility.
32
+
33
+ ### Props
34
+
35
+ The Datepicker receives a `Date` object via `value`, and returns a `Date` object via `onValueChange`. `onValueChange` also returns the raw event object as its second argument, in case the consumer needs to access it. This aligns with the props pattern used by other form-field-level components in `uikit-react`.
36
+
37
+ ### Subcomponents
38
+
39
+ - `<CustomDatepicker>`: The default implementation of the Datepicker, built using React logic.
40
+ - `<VisibleField>`: Handles the part of the Datepicker that is _always_ visible to the user -- as a 'form field' input. Composes the controlled input and buttons for opening the calendar and clearing the field.
41
+ - `<DatepickerInput>`: The input field for the Datepicker, used in the custom implementation.
42
+ - `<Panel>`: Wrapper component that handles positioning.
43
+ - `<NativeDatepicker>`: An alternative implementation of the Datepicker, using the browser's native date input.
44
+
45
+ **Additional components:**
46
+ - `<Calendar>`: Imported as a separate component and passed as child to `<Panel>`.
47
+
48
+ #### Subcomponent hierarchy
49
+
50
+ ```mermaid
51
+ graph TD
52
+ A[Datepicker] -->| native=false | B[CustomDatepicker]
53
+ A -->| native=true | C[NativeDatepicker]
54
+ B --> D[VisibleField]
55
+ D --> E[DatepickerInput]
56
+ B --> F[Panel]
57
+ F --> G[Calendar]
58
+ ```
59
+
60
+ ### Date parsing
61
+
62
+ After the user types a date into the input, they need to press ENTER or TAB to parse the date.
63
+
64
+ ### Accessibility
65
+
66
+ Utility function [`announce`](../../utils/announce.ts) is used to provide screen-reader feedback when a date is selected. Places where this is used:
67
+
68
+ - When a date is 'picked' with the Calendar
69
+ - When a date is entered into the input field and successfully parsed.
70
+
71
+ `announce` is only called in `CustomDatepicker`.
72
+
73
+ Automatic association of `<Label>` with `DatepickerInput` when `<Datepicker>` is in a `<Field>` would improve default accessibility -- described in [Datepicker_improv_004].
74
+
75
+ ## Known issues
76
+
77
+ - **[Datepicker_issue_001]**: The Calendar itself, when rendered in the Panel, may not pass Accessibility tests. However, we expect users with Accessibility needs are able to successfully enter a date using the controlled input.
78
+ - The Calendar panel lacks ARIA roles (`role="dialog"`, `role="grid"`, `aria-selected`, etc.), keyboard navigation (arrow keys between days, Escape to close), and the calendar toggle in `<VisibleField>` is a `<div>` with `role="button"` rather than a native `<button>`. This is a WCAG 2.2 AA compliance risk.
79
+ - **[Datepicker_issue_002]**: The Panel only appears below the Datepicker's visible field. If the Datepicker is close to the bottom of the browser viewport, this increases the viewport size while the Panel is open (temporarily).
80
+ - **[Datepicker_issue_003]**: `minDate` and `maxDate` are ISO date strings (`'YYYY-MM-DD'`), which are parsed via `new Date(string)` in several places (`CustomDatepicker.tsx`, `parseInputValue.ts`). This creates UTC dates, not local dates, causing off-by-one day bugs in timezones behind UTC. Options:
81
+ - **Option A**: Create a `parseISODateLocal` utility that splits the string and uses `new Date(year, month - 1, day)`, and use it everywhere.
82
+ - **Option B**: Change `minDate`/`maxDate` to accept `Date` objects instead of strings, aligning with the `value` prop. This would push the parsing responsibility to the consumer and eliminate the UTC ambiguity entirely.
83
+ - **[Datepicker_issue_004]**: The Calendar panel renders inside the component's DOM tree, so it can be clipped by `overflow: hidden` ancestors. Fix: [Datepicker_improv_002].
84
+ - **[Datepicker_issue_005]**: Date handling uses raw `Date` objects with no timezone awareness or locale-aware formatting. Input parsing is hardcoded to `DD/MM/YYYY`.
85
+
86
+ ## Suggested future improvements
87
+
88
+ - **[Datepicker_improv_001]**: Extract `<Panel>` into a shared utility component.
89
+ - `<Select>` also uses a similar Panel (etc).
90
+ - **[Datepicker_improv_002]**: Use library [Floating UI](https://floating-ui.com/) to handle Panel positioning and portalling (via `FloatingPortal`).
91
+ - Fix for [Datepicker_issue_002] and [Datepicker_issue_004].
92
+ - **[Datepicker_improv_003]**: Extract `<NativeDatepicker>` into a separate component.
93
+ - This would simplify props typing.
94
+ - This would remove the need for `Datepicker.tsx` itself to act as a 'routing' component.
95
+ - **[Datepicker_improv_004]**: Integrate `<Datepicker>` with `<Field>` and `<Label>`, to use the shared context solution already used in `<Input>` & `<Textarea>`.
96
+ - This would simplify the API for consumers, and ensure consistent behaviour across form-field-level components.
97
+ - Developers using these components get automatic label->input association without having to manually pass `id` and `htmlFor` props.
98
+ - **[Datepicker_improv_005]**: Separate the button that opens the Calendar and the button that clears the input field, so they can be seen & used independently -- currently they are conditionally rendered with joined logic.
99
+ - **[Datepicker_improv_006]**: Extract the button that opens the Calendar into a separate subcomponent, for cleaner composition in the return statement of `VisibleField`.
100
+ - **[Datepicker_improv_007]**: Extract the button that clears the input field into a separate subcomponent, for cleaner composition in the return statement of `VisibleField`.
101
+ - **[Datepicker_improv_008]**: Extract core logic from `<CustomDatepicker>` into a `useDatepicker` hook. Benefits:
102
+ - **Testability**: Hook logic can be tested in isolation with `renderHook()`, without rendering the full component tree.
103
+ - **Reusability**: Logic can be shared across variants (e.g. date range picker, inline calendar, mobile-specific version).
104
+ - **Composition**: Consumers could use the hook directly for advanced/custom layouts.
105
+ - **Debugging**: Cleanly separates logic bugs from rendering bugs.
106
+ - **Performance**: Allows more granular control over which state changes trigger re-renders.
107
+ - **[Datepicker_improv_009]**: Adopt a date utility library (`date-fns` or `dayjs`) to replace manual string parsing and provide timezone/locale support.
108
+ - Fix for [Datepicker_issue_005].
@@ -1,9 +1,11 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react';
2
2
  import { useArgs } from '@storybook/preview-api';
3
3
  import Datepicker from './Datepicker';
4
+ import Field from '../Field';
5
+ import Label from '../Label';
4
6
 
5
7
  const meta = {
6
- title: 'Components/Ready to use/Datepicker',
8
+ title: 'Components/Datepicker',
7
9
  component: Datepicker,
8
10
  parameters: { layout: 'padded' },
9
11
  argTypes: {
@@ -11,7 +13,7 @@ const meta = {
11
13
  minDate: { control: { type: 'date' } },
12
14
  maxDate: { control: { type: 'date' } },
13
15
  disabled: { control: { type: 'boolean' } },
14
- native: { control: { type: 'boolean' } },
16
+ clearable: { control: { type: 'boolean' } },
15
17
  showAcademicWeeks: { control: { type: 'boolean' } },
16
18
  },
17
19
  tags: ['autodocs'],
@@ -49,6 +51,42 @@ export const Default: Story = {
49
51
  },
50
52
  };
51
53
 
54
+ export const InAField: Story = {
55
+ render: () => {
56
+ const [args, updateArgs] = useArgs();
57
+
58
+ // Storybook controls provide UNIX timestamps for dates, need to convert
59
+ // https://storybook.js.org/docs/essentials/controls#annotation
60
+ args.value = args.value ? new Date(args.value) : null;
61
+ args.minDate = args.minDate
62
+ ? new Date(args.minDate).toLocaleDateString('sv-SE')
63
+ : null;
64
+ args.maxDate = args.maxDate
65
+ ? new Date(args.maxDate).toLocaleDateString('sv-SE')
66
+ : null;
67
+
68
+ const onValueChange = (value: Date | null | undefined) =>
69
+ updateArgs({ value: value });
70
+
71
+ // Could be `useId` or a hardcoded string..
72
+ const datepickerInputId = 'datepicker-input';
73
+ // TODO: Associate <Label> and <DatepickerInput> via <Field> context automatically -- [Datepicker_improv_004]
74
+ return (
75
+ <Field>
76
+ <Label htmlFor={datepickerInputId}>Date of event</Label>
77
+ <Field.HelperText>
78
+ Please enter your preferred date for the event
79
+ </Field.HelperText>
80
+ <Datepicker
81
+ {...args}
82
+ onValueChange={onValueChange}
83
+ inputProps={{ id: datepickerInputId }}
84
+ />
85
+ </Field>
86
+ );
87
+ },
88
+ };
89
+
52
90
  // Story repeated in Calendar.stories.tsx
53
91
  export const WithEvents: Story = {
54
92
  name: 'With events',
@@ -237,10 +275,11 @@ export const MinMaxDates: Story = {
237
275
  },
238
276
  };
239
277
 
240
- export const Native: Story = {
241
- name: 'As native fallback',
278
+ export const Clearable: Story = {
279
+ name: 'With clearable',
242
280
  args: {
243
- native: true,
281
+ clearable: true,
282
+ value: new Date(), // Start with a value to show the clear button
244
283
  },
245
284
  render: () => {
246
285
  const [args, updateArgs] = useArgs();
@@ -1,5 +1,4 @@
1
- import { NativeDatepicker, CustomDatepicker } from './subcomponents';
2
- import { dateToLocaleISOString } from './utils';
1
+ import { CustomDatepicker } from './subcomponents';
3
2
  import type { DatepickerProps } from './Datepicker.types';
4
3
 
5
4
  const Datepicker = ({
@@ -9,42 +8,21 @@ const Datepicker = ({
9
8
  maxDate,
10
9
  disabled,
11
10
  className,
12
- native,
13
- nativeRef,
14
- nativeHTMLAttributes,
11
+ clearable,
15
12
  ...props
16
13
  }: DatepickerProps) => {
17
- if (native) {
18
- const nativeValue = dateToLocaleISOString(value);
19
-
20
- return (
21
- <NativeDatepicker
22
- value={nativeValue || ''}
23
- onChange={(event) => {
24
- const dateString = event.target.value;
25
- onValueChange?.(dateString ? new Date(dateString) : null, event);
26
- }}
27
- min={minDate || undefined}
28
- max={maxDate || undefined}
29
- disabled={disabled}
30
- className={className}
31
- ref={nativeRef}
32
- {...nativeHTMLAttributes}
33
- />
34
- );
35
- } else {
36
- return (
37
- <CustomDatepicker
38
- value={value}
39
- onValueChange={onValueChange}
40
- minDate={minDate}
41
- maxDate={maxDate}
42
- className={className}
43
- disabled={disabled}
44
- {...props}
45
- />
46
- );
47
- }
14
+ return (
15
+ <CustomDatepicker
16
+ value={value}
17
+ onValueChange={onValueChange}
18
+ minDate={minDate}
19
+ maxDate={maxDate}
20
+ className={className}
21
+ disabled={disabled}
22
+ clearable={clearable}
23
+ {...props}
24
+ />
25
+ );
48
26
  };
49
27
 
50
28
  export default Datepicker;