uikit-react-public 0.11.24 → 0.17.4

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 (301) hide show
  1. package/README.md +4 -2
  2. package/dist/components/Accordion/Accordion.Heading.d.ts +4 -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/Avatar/Avatar.stories.d.ts +107 -1
  8. package/dist/components/Badge/Badge.d.ts +6 -0
  9. package/dist/components/Badge/Badge.stories.d.ts +15 -0
  10. package/dist/components/Badge/index.d.ts +2 -0
  11. package/dist/components/Button/Button.d.ts +3 -1
  12. package/dist/components/Calendar/index.d.ts +1 -1
  13. package/dist/components/CookieNotice/CookieNotice.d.ts +16 -0
  14. package/dist/components/CookieNotice/index.d.ts +2 -0
  15. package/dist/components/Datepicker/Datepicker.d.ts +1 -1
  16. package/dist/components/Datepicker/Datepicker.stories.d.ts +4 -3
  17. package/dist/components/Datepicker/Datepicker.types.d.ts +4 -5
  18. package/dist/components/Datepicker/subcomponents/CustomDatepicker.d.ts +4 -1
  19. package/dist/components/Datepicker/subcomponents/DatepickerInput.d.ts +15 -2
  20. package/dist/components/Datepicker/subcomponents/Panel.d.ts +1 -1
  21. package/dist/components/Datepicker/subcomponents/VisibleField.d.ts +6 -1
  22. package/dist/components/Datepicker/subcomponents/index.d.ts +0 -1
  23. package/dist/components/Datepicker/utils/index.d.ts +0 -1
  24. package/dist/components/Dialog/BaseDialog.d.ts +8 -2
  25. package/dist/components/Dialog/Dialog.d.ts +2 -0
  26. package/dist/components/FileInput/FileInput.d.ts +8 -0
  27. package/dist/components/FileInput/FileInput.stories.d.ts +16 -0
  28. package/dist/components/FileInput/index.d.ts +2 -0
  29. package/dist/components/Header/Header.d.ts +7 -1
  30. package/dist/components/Header/Header.stories.d.ts +40 -0
  31. package/dist/components/Heading/Heading.d.ts +1 -1
  32. package/dist/components/Link/BaseLink.d.ts +10 -0
  33. package/dist/components/Link/Link.d.ts +5 -10
  34. package/dist/components/Link/Link.stories.d.ts +1 -1
  35. package/dist/components/Link/index.d.ts +1 -1
  36. package/dist/components/Main/Main.d.ts +21 -0
  37. package/dist/components/Main/Main.stories.d.ts +15 -0
  38. package/dist/components/Main/__tests__/Main.test.d.ts +1 -0
  39. package/dist/components/Main/index.d.ts +2 -0
  40. package/dist/components/Menu/MenuContent.d.ts +1 -1
  41. package/dist/components/Menu/MenuItem.d.ts +2 -0
  42. package/dist/components/Menu/MenuSection.d.ts +1 -1
  43. package/dist/components/NativeDatepicker/NativeDatepicker.d.ts +3 -0
  44. package/dist/components/NativeDatepicker/NativeDatepicker.stories.d.ts +36 -0
  45. package/dist/components/NativeDatepicker/NativeDatepicker.types.d.ts +10 -0
  46. package/dist/components/NativeDatepicker/index.d.ts +2 -0
  47. package/dist/components/{Datepicker → NativeDatepicker}/utils/dateToLocaleISOString/dateToLocaleISOString.d.ts +1 -1
  48. package/dist/components/NativeDatepicker/utils/dateToLocaleISOString/dateToLocaleISOString.test.d.ts +1 -0
  49. package/dist/components/NativeDatepicker/utils/index.d.ts +1 -0
  50. package/dist/components/Search/Search.d.ts +16 -0
  51. package/dist/components/Search/Search.stories.d.ts +34 -0
  52. package/dist/components/Search/__tests__/Search.test.d.ts +1 -0
  53. package/dist/components/Search/index.d.ts +2 -0
  54. package/dist/components/Select/Select.d.ts +1 -1
  55. package/dist/components/Select/Select.stories.d.ts +157 -9
  56. package/dist/components/Select/Select.types.d.ts +66 -32
  57. package/dist/components/Select/subcomponents/CustomOption.d.ts +1 -1
  58. package/dist/components/Select/subcomponents/CustomSelect.d.ts +3 -3
  59. package/dist/components/Select/subcomponents/FilterInput.d.ts +14 -0
  60. package/dist/components/Select/subcomponents/NativeSelect.d.ts +5 -1
  61. package/dist/components/Select/subcomponents/Panel.d.ts +1 -1
  62. package/dist/components/Select/subcomponents/VisibleField.d.ts +6 -4
  63. package/dist/components/Select/subcomponents/index.d.ts +1 -0
  64. package/dist/components/StandaloneLink/StandaloneLink.d.ts +12 -0
  65. package/dist/components/StandaloneLink/StandaloneLink.stories.d.ts +13 -0
  66. package/dist/components/StandaloneLink/__tests__/StandaloneLink.test.d.ts +1 -0
  67. package/dist/components/StandaloneLink/index.d.ts +2 -0
  68. package/dist/components/Table/Table.d.ts +10 -8
  69. package/dist/components/Table/Table.stories.d.ts +21 -0
  70. package/dist/components/Table/Table.types.d.ts +11 -0
  71. package/dist/components/Table/__tests__/Table.test.d.ts +1 -0
  72. package/dist/components/Table/index.d.ts +2 -1
  73. package/dist/components/Table/subcomponents/Body.d.ts +4 -0
  74. package/dist/components/Table/subcomponents/Cell/Cell.d.ts +12 -0
  75. package/dist/components/Table/subcomponents/Cell/Cell.stories.d.ts +313 -0
  76. package/dist/components/Table/subcomponents/Cell/CellContent.d.ts +10 -0
  77. package/dist/components/Table/subcomponents/Cell/__tests__/Cell.test.d.ts +1 -0
  78. package/dist/components/Table/subcomponents/Head.d.ts +4 -0
  79. package/dist/components/Table/subcomponents/HeadCell/HeadCell.d.ts +13 -0
  80. package/dist/components/Table/subcomponents/HeadCell/HeadCell.stories.d.ts +312 -0
  81. package/dist/components/Table/subcomponents/HeadCell/HeadCellContent.d.ts +10 -0
  82. package/dist/components/Table/subcomponents/HeadCell/__tests__/HeadCell.test.d.ts +1 -0
  83. package/dist/components/Table/subcomponents/Row.d.ts +5 -0
  84. package/dist/components/Table/subcomponents/SortIcon.d.ts +7 -0
  85. package/dist/components/Table/subcomponents/index.d.ts +10 -0
  86. package/dist/components/Tabs/Tab.d.ts +1 -1
  87. package/dist/components/Tabs/TabContext.d.ts +1 -0
  88. package/dist/components/Tabs/Tabs.d.ts +3 -1
  89. package/dist/components/Tabs/Tabs.stories.d.ts +3 -0
  90. package/dist/components/Timepicker/Timepicker.d.ts +10 -0
  91. package/dist/components/Timepicker/Timepicker.stories.d.ts +7 -0
  92. package/dist/components/Timepicker/__tests__/Timepicker.test.d.ts +1 -0
  93. package/dist/components/Timepicker/index.d.ts +2 -0
  94. package/dist/components/Timepicker/utils/convertDateToTimeString.d.ts +2 -0
  95. package/dist/components/Timepicker/utils/convertDateToTimeString.test.d.ts +1 -0
  96. package/dist/components/Timepicker/utils/index.d.ts +1 -0
  97. package/dist/components/WeekPicker/WeekPicker.d.ts +3 -0
  98. package/dist/components/WeekPicker/WeekPicker.stories.d.ts +41 -0
  99. package/dist/components/WeekPicker/WeekPicker.types.d.ts +16 -0
  100. package/dist/components/WeekPicker/index.d.ts +2 -0
  101. package/dist/components/WeekPicker/subcomponents/CustomDatepicker.d.ts +17 -0
  102. package/dist/components/WeekPicker/subcomponents/DatepickerInput.d.ts +13 -0
  103. package/dist/components/WeekPicker/subcomponents/VisibleField.d.ts +15 -0
  104. package/dist/components/WeekPicker/subcomponents/index.d.ts +3 -0
  105. package/dist/components/index.d.ts +19 -0
  106. package/dist/hooks/index.d.ts +2 -0
  107. package/dist/hooks/useFocusTrap.d.ts +10 -0
  108. package/dist/index.d.ts +2 -0
  109. package/dist/index.js +6460 -4607
  110. package/dist/theme/defaultTheme.d.ts +7 -0
  111. package/dist/theme/useTheme.d.ts +14 -0
  112. package/dist/utils/__tests__/announce.test.d.ts +1 -0
  113. package/dist/utils/__tests__/capitalise.test.d.ts +1 -0
  114. package/dist/utils/announce.d.ts +6 -0
  115. package/dist/utils/capitalise.d.ts +2 -0
  116. package/dist/utils/index.d.ts +1 -0
  117. package/lib/components/Accordion/Accordion.Heading.tsx +27 -8
  118. package/lib/components/Accordion/Accordion.Panel.tsx +11 -3
  119. package/lib/components/Accordion/Accordion.stories.tsx +139 -0
  120. package/lib/components/Accordion/Accordion.tsx +10 -8
  121. package/lib/components/Accordion/__tests__/__snapshots__/Accordion.test.tsx.snap +7 -7
  122. package/lib/components/Accordion/index.ts +2 -0
  123. package/lib/components/Alert/Alert.stories.tsx +1 -1
  124. package/lib/components/Alert/Alert.tsx +7 -1
  125. package/lib/components/Alert/__tests__/__snapshots__/Alert.test.tsx.snap +4 -0
  126. package/lib/components/Avatar/Avatar.mdx +117 -0
  127. package/lib/components/Avatar/Avatar.stories.tsx +110 -2
  128. package/lib/components/Badge/Badge.stories.tsx +19 -0
  129. package/lib/components/Badge/Badge.tsx +48 -0
  130. package/lib/components/Badge/index.ts +2 -0
  131. package/lib/components/Blanket/Blanket.stories.tsx +1 -1
  132. package/lib/components/Breadcrumbs/__tests__/__snapshots__/Breadcrumbs.test.tsx.snap +4 -4
  133. package/lib/components/Button/Button.stories.tsx +1 -1
  134. package/lib/components/Button/Button.tsx +6 -2
  135. package/lib/components/Calendar/Calendar.stories.tsx +12 -32
  136. package/lib/components/Calendar/__tests__/Calendar.test.tsx +23 -15
  137. package/lib/components/Calendar/index.ts +1 -5
  138. package/lib/components/Calendar/subcomponents/AcademicWeeks.tsx +2 -1
  139. package/lib/components/Calendar/subcomponents/ColumnHeading.tsx +5 -1
  140. package/lib/components/Calendar/subcomponents/EventDot.tsx +2 -1
  141. package/lib/components/Calendar/subcomponents/Grid.tsx +0 -1
  142. package/lib/components/Calendar/subcomponents/index.ts +1 -1
  143. package/lib/components/Calendar/utils/getDatesForCalendarGrid/getDatesForCalendarGrid.ts +43 -11
  144. package/lib/components/Calendar/utils/normaliseMonth/normaliseMonth.test.ts +5 -5
  145. package/lib/components/CookieNotice/CookieNotice.tsx +114 -0
  146. package/lib/components/CookieNotice/index.ts +2 -0
  147. package/lib/components/Datepicker/Datepicker.lld.md +108 -0
  148. package/lib/components/Datepicker/Datepicker.stories.tsx +44 -5
  149. package/lib/components/Datepicker/Datepicker.tsx +14 -36
  150. package/lib/components/Datepicker/Datepicker.types.ts +5 -14
  151. package/lib/components/Datepicker/__tests__/Datepicker.test.tsx +150 -8
  152. package/lib/components/Datepicker/__tests__/__snapshots__/Datepicker.test.tsx.snap +10 -4
  153. package/lib/components/Datepicker/subcomponents/CustomDatepicker.tsx +39 -5
  154. package/lib/components/Datepicker/subcomponents/DatepickerInput.tsx +30 -17
  155. package/lib/components/Datepicker/subcomponents/Panel.tsx +6 -2
  156. package/lib/components/Datepicker/subcomponents/VisibleField.tsx +40 -3
  157. package/lib/components/Datepicker/subcomponents/index.ts +0 -1
  158. package/lib/components/Datepicker/utils/index.ts +0 -1
  159. package/lib/components/Dialog/BaseDialog.tsx +55 -4
  160. package/lib/components/Dialog/Dialog.tsx +8 -1
  161. package/lib/components/Dialog/DialogBody.tsx +5 -1
  162. package/lib/components/Dialog/DialogHeader.tsx +2 -1
  163. package/lib/components/Divider/Divider.stories.tsx +1 -1
  164. package/lib/components/Field/ErrorText.tsx +1 -0
  165. package/lib/components/Field/Field.stories.tsx +1 -1
  166. package/lib/components/Field/__tests__/Field.test.tsx +161 -148
  167. package/lib/components/FileInput/FileInput.stories.tsx +70 -0
  168. package/lib/components/FileInput/FileInput.tsx +68 -0
  169. package/lib/components/FileInput/__tests__/FileInput.test.tsx +99 -0
  170. package/lib/components/FileInput/__tests__/__snapshots__/FileInput.test.tsx.snap +91 -0
  171. package/lib/components/FileInput/index.ts +2 -0
  172. package/lib/components/Footer/Footer.stories.tsx +1 -1
  173. package/lib/components/Footer/__tests__/__snapshots__/Footer.test.tsx.snap +28 -28
  174. package/lib/components/Header/Header.mdx +52 -0
  175. package/lib/components/Header/Header.stories.tsx +98 -0
  176. package/lib/components/Header/Header.tsx +65 -3
  177. package/lib/components/Header/__tests__/Header.test.tsx +17 -1
  178. package/lib/components/Header/__tests__/__snapshots__/Header.test.tsx.snap +4 -4
  179. package/lib/components/Heading/Documentation.mdx +1 -1
  180. package/lib/components/Heading/Heading.stories.tsx +1 -1
  181. package/lib/components/Heading/Heading.tsx +1 -1
  182. package/lib/components/Heading/__tests__/Heading.test.tsx +7 -19
  183. package/lib/components/Heading/__tests__/__snapshots__/Heading.test.tsx.snap +7 -7
  184. package/lib/components/Icon/Icon.stories.tsx +1 -1
  185. package/lib/components/IconButton/IconButton.stories.tsx +1 -1
  186. package/lib/components/Input/Input.stories.tsx +1 -1
  187. package/lib/components/Label/Label.stories.tsx +1 -1
  188. package/lib/components/Label/Label.tsx +0 -2
  189. package/lib/components/Label/__tests__/__snapshots__/Label.test.tsx.snap +7 -7
  190. package/lib/components/Link/BaseLink.tsx +84 -0
  191. package/lib/components/Link/Link.tsx +72 -32
  192. package/lib/components/Link/__tests__/__snapshots__/link.test.tsx.snap +3 -3
  193. package/lib/components/Link/__tests__/link.test.tsx +6 -13
  194. package/lib/components/Link/index.ts +1 -1
  195. package/lib/components/Main/Main.stories.tsx +36 -0
  196. package/lib/components/Main/Main.tsx +46 -0
  197. package/lib/components/Main/__tests__/Main.test.tsx +80 -0
  198. package/lib/components/Main/__tests__/__snapshots__/Main.test.tsx.snap +33 -0
  199. package/lib/components/Main/index.ts +2 -0
  200. package/lib/components/Menu/Menu.context.tsx +3 -1
  201. package/lib/components/Menu/Menu.tsx +2 -2
  202. package/lib/components/Menu/MenuContent.tsx +5 -5
  203. package/lib/components/Menu/MenuItem.tsx +20 -3
  204. package/lib/components/Menu/MenuSection.tsx +4 -3
  205. package/lib/components/NativeDatepicker/NativeDatepicker.stories.tsx +100 -0
  206. package/lib/components/{Datepicker/subcomponents → NativeDatepicker}/NativeDatepicker.tsx +14 -15
  207. package/lib/components/NativeDatepicker/NativeDatepicker.types.ts +19 -0
  208. package/lib/components/NativeDatepicker/index.ts +2 -0
  209. package/lib/components/{Datepicker → NativeDatepicker}/utils/dateToLocaleISOString/dateToLocaleISOString.ts +1 -1
  210. package/lib/components/NativeDatepicker/utils/index.ts +1 -0
  211. package/lib/components/Pagination/PaginationControls.tsx +56 -15
  212. package/lib/components/Pagination/PaginationInfo.tsx +5 -1
  213. package/lib/components/Paragraph/Paragraph.stories.tsx +1 -1
  214. package/lib/components/Search/Search.stories.tsx +41 -0
  215. package/lib/components/Search/Search.tsx +170 -0
  216. package/lib/components/Search/__tests__/Search.test.tsx +112 -0
  217. package/lib/components/Search/__tests__/__snapshots__/Search.test.tsx.snap +179 -0
  218. package/lib/components/Search/index.ts +2 -0
  219. package/lib/components/Select/Select.mdx +169 -0
  220. package/lib/components/Select/Select.stories.tsx +198 -77
  221. package/lib/components/Select/Select.tsx +37 -13
  222. package/lib/components/Select/Select.types.ts +77 -54
  223. package/lib/components/Select/__tests__/Select.test.tsx +448 -7
  224. package/lib/components/Select/__tests__/__snapshots__/Select.test.tsx.snap +3 -3
  225. package/lib/components/Select/subcomponents/CustomOption.tsx +24 -10
  226. package/lib/components/Select/subcomponents/CustomSelect.tsx +333 -52
  227. package/lib/components/Select/subcomponents/FilterInput.tsx +80 -0
  228. package/lib/components/Select/subcomponents/NativeSelect.tsx +13 -1
  229. package/lib/components/Select/subcomponents/Panel.tsx +4 -5
  230. package/lib/components/Select/subcomponents/VisibleField.tsx +36 -24
  231. package/lib/components/Select/subcomponents/index.tsx +1 -0
  232. package/lib/components/Snackbar/Snackbar.stories.tsx +1 -1
  233. package/lib/components/Spinner/Spinner.stories.tsx +1 -1
  234. package/lib/components/StandaloneLink/StandaloneLink.stories.tsx +32 -0
  235. package/lib/components/StandaloneLink/StandaloneLink.tsx +183 -0
  236. package/lib/components/StandaloneLink/__tests__/StandaloneLink.test.tsx +57 -0
  237. package/lib/components/StandaloneLink/__tests__/__snapshots__/StandaloneLink.test.tsx.snap +19 -0
  238. package/lib/components/StandaloneLink/index.ts +2 -0
  239. package/lib/components/Table/Table.stories.tsx +337 -0
  240. package/lib/components/Table/Table.tsx +42 -67
  241. package/lib/components/Table/Table.types.ts +14 -0
  242. package/lib/components/Table/__tests__/Table.test.tsx +121 -0
  243. package/lib/components/Table/__tests__/__snapshots__/Table.test.tsx.snap +210 -0
  244. package/lib/components/Table/index.ts +8 -1
  245. package/lib/components/Table/subcomponents/Body.tsx +18 -0
  246. package/lib/components/Table/subcomponents/Cell/Cell.stories.tsx +151 -0
  247. package/lib/components/Table/subcomponents/Cell/Cell.tsx +72 -0
  248. package/lib/components/Table/subcomponents/Cell/CellContent.tsx +91 -0
  249. package/lib/components/Table/subcomponents/Cell/__tests__/Cell.test.tsx +115 -0
  250. package/lib/components/Table/subcomponents/Cell/__tests__/__snapshots__/Cell.test.tsx.snap +107 -0
  251. package/lib/components/Table/subcomponents/Head.tsx +34 -0
  252. package/lib/components/Table/subcomponents/HeadCell/HeadCell.stories.tsx +85 -0
  253. package/lib/components/Table/subcomponents/HeadCell/HeadCell.tsx +99 -0
  254. package/lib/components/Table/subcomponents/HeadCell/HeadCellContent.tsx +61 -0
  255. package/lib/components/Table/subcomponents/HeadCell/__tests__/HeadCell.test.tsx +137 -0
  256. package/lib/components/Table/subcomponents/HeadCell/__tests__/__snapshots__/HeadCell.test.tsx.snap +110 -0
  257. package/lib/components/Table/subcomponents/Row.tsx +49 -0
  258. package/lib/components/Table/subcomponents/SortIcon.tsx +63 -0
  259. package/lib/components/Table/subcomponents/index.ts +14 -0
  260. package/lib/components/Tabs/Tab.tsx +3 -3
  261. package/lib/components/Tabs/TabContext.tsx +1 -0
  262. package/lib/components/Tabs/Tabs.stories.tsx +9 -3
  263. package/lib/components/Tabs/Tabs.tsx +10 -32
  264. package/lib/components/Tabs/__tests__/Tabs.test.tsx +10 -4
  265. package/lib/components/Tabs/__tests__/__snapshots__/Tabs.test.tsx.snap +32 -32
  266. package/lib/components/Textarea/Textarea.stories.tsx +1 -1
  267. package/lib/components/Timepicker/Timepicker.stories.tsx +43 -0
  268. package/lib/components/Timepicker/Timepicker.tsx +100 -0
  269. package/lib/components/Timepicker/__tests__/Timepicker.test.tsx +55 -0
  270. package/lib/components/Timepicker/__tests__/__snapshots__/Timepicker.test.tsx.snap +19 -0
  271. package/lib/components/Timepicker/index.tsx +2 -0
  272. package/lib/components/Timepicker/utils/convertDateToTimeString.test.ts +54 -0
  273. package/lib/components/Timepicker/utils/convertDateToTimeString.ts +10 -0
  274. package/lib/components/Timepicker/utils/index.ts +1 -0
  275. package/lib/components/Toggle/Toggle.stories.tsx +1 -1
  276. package/lib/components/Tooltip/Tooltip.stories.tsx +1 -1
  277. package/lib/components/WeekPicker/WeekPicker.stories.tsx +147 -0
  278. package/lib/components/WeekPicker/WeekPicker.tsx +26 -0
  279. package/lib/components/WeekPicker/WeekPicker.types.ts +21 -0
  280. package/lib/components/WeekPicker/index.ts +2 -0
  281. package/lib/components/WeekPicker/subcomponents/CustomDatepicker.tsx +298 -0
  282. package/lib/components/WeekPicker/subcomponents/DatepickerInput.tsx +111 -0
  283. package/lib/components/WeekPicker/subcomponents/VisibleField.tsx +126 -0
  284. package/lib/components/WeekPicker/subcomponents/index.ts +3 -0
  285. package/lib/components/common/Common.mdx +1 -1
  286. package/lib/components/index.ts +28 -2
  287. package/lib/hooks/index.ts +2 -0
  288. package/lib/hooks/useFocusTrap.ts +159 -0
  289. package/lib/index.ts +2 -0
  290. package/lib/theme/defaultTheme.ts +7 -0
  291. package/lib/utils/__tests__/announce.test.ts +121 -0
  292. package/lib/utils/__tests__/capitalise.test.ts +40 -0
  293. package/lib/utils/announce.ts +134 -0
  294. package/lib/utils/capitalise.ts +4 -0
  295. package/lib/utils/index.ts +1 -0
  296. package/package.json +3 -6
  297. package/dist/components/Datepicker/subcomponents/NativeDatepicker.d.ts +0 -6
  298. package/lib/components/Accordion/Accordion.stories.tsx.NOT_READY +0 -93
  299. package/lib/components/Field/__tests__/__snapshots__/Field.test.tsx.snap +0 -300
  300. /package/dist/components/{Datepicker/utils/dateToLocaleISOString/dateToLocaleISOString.test.d.ts → FileInput/__tests__/FileInput.test.d.ts} +0 -0
  301. /package/lib/components/{Datepicker → NativeDatepicker}/utils/dateToLocaleISOString/dateToLocaleISOString.test.ts +0 -0
@@ -0,0 +1,126 @@
1
+ import { css, cx } from '@emotion/css';
2
+ import { DatepickerInput } from './';
3
+ import { Icon } from '../../..';
4
+ import { useTheme } from '../../../theme';
5
+ import React from 'react';
6
+
7
+ interface VisibleFieldProps {
8
+ inputValue: string;
9
+ onInputChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
10
+ onInputKeyDown: (event: React.KeyboardEvent<HTMLInputElement>) => void;
11
+ onInputFocus: () => void;
12
+ onButtonClick: () => void;
13
+ disabled: boolean;
14
+ inputRef: React.RefObject<HTMLInputElement | null>;
15
+ beginningOfWeek?: string;
16
+ endOfWeek?: string;
17
+ academicWeekNumber?: number;
18
+ }
19
+
20
+ const NAME = 'ucl-uikit-weekpicker__visible-field';
21
+
22
+ const VisibleField = ({
23
+ inputValue,
24
+ onInputChange,
25
+ onInputKeyDown,
26
+ onInputFocus,
27
+ onButtonClick,
28
+ disabled,
29
+ inputRef,
30
+ beginningOfWeek,
31
+ endOfWeek,
32
+ academicWeekNumber,
33
+ }: VisibleFieldProps) => {
34
+ const [theme] = useTheme();
35
+
36
+ const baseStyle = css`
37
+ display: flex;
38
+ align-items: center;
39
+ justify-content: space-between;
40
+ // width: 100%;
41
+ // height: 100%;
42
+ box-sizing: border-box;
43
+ border: 1px solid ${theme.color.neutral.grey60};
44
+ background-color: ${theme.color.neutral.white};
45
+ padding: 3px 16px;
46
+
47
+ &:focus-within {
48
+ box-shadow: ${theme.boxShadow.focus};
49
+ }
50
+ `;
51
+
52
+ const disabledStyle = css`
53
+ color: ${theme.color.text.disabled};
54
+ background-color: ${theme.color.neutral.white};
55
+ border-color: ${theme.color.neutral.grey20};
56
+
57
+ cursor: not-allowed;
58
+ // And child elements
59
+ & * {
60
+ cursor: not-allowed;
61
+ }
62
+ `;
63
+
64
+ // The container for the <Icon.Calendar> is a <div> not an <IconButton>,
65
+ // so that the orange border only appears when the input has focus and the user can type.
66
+ // The container increases the clickable area of the icon.
67
+ const iconButtonStyle = css`
68
+ display: flex;
69
+ align-items: center;
70
+ justify-content: center;
71
+ height: 100%;
72
+ cursor: pointer;
73
+ padding-right: 8px;
74
+ `;
75
+
76
+ // `min-width` here accounts for a recurring problem,
77
+ // in which icons shrink when horizontal space is limited.
78
+ // TODO: This ought to be fixed in the <Icon> component itself.
79
+ const iconStyle = css`
80
+ min-width: 16px;
81
+ color: ${disabled
82
+ ? theme.color.text.disabled
83
+ : theme.color.text.primary}; // TODO: Needs a design token
84
+ `;
85
+
86
+ const style = cx(NAME, baseStyle, disabled && disabledStyle);
87
+
88
+ return (
89
+ <div
90
+ className={style}
91
+ data-testid={NAME}
92
+ >
93
+ <div
94
+ onClick={onButtonClick}
95
+ className={iconButtonStyle}
96
+ >
97
+ <Icon.Calendar
98
+ className={iconStyle}
99
+ size={16}
100
+ />
101
+ </div>
102
+ <DatepickerInput
103
+ value={inputValue}
104
+ onChange={onInputChange}
105
+ onKeyDown={onInputKeyDown}
106
+ onFocus={onInputFocus}
107
+ disabled={disabled}
108
+ ref={inputRef}
109
+ beginningOfWeek={beginningOfWeek}
110
+ endOfWeek={endOfWeek}
111
+ academicWeekNumber={academicWeekNumber}
112
+ />
113
+ {academicWeekNumber !== undefined && (
114
+ <span
115
+ className={css`
116
+ color: ${theme.color.text.secondary};
117
+ `}
118
+ >
119
+ W{academicWeekNumber}
120
+ </span>
121
+ )}
122
+ </div>
123
+ );
124
+ };
125
+
126
+ export default VisibleField;
@@ -0,0 +1,3 @@
1
+ export { default as CustomDatepicker } from './CustomDatepicker';
2
+ export { default as VisibleField } from './VisibleField';
3
+ export { default as DatepickerInput } from './DatepickerInput';
@@ -76,7 +76,7 @@ The available margin props are:
76
76
  include={['m', 'm', 'mv', 'mh', 'mt', 'mb', 'ml', 'mr', 'noMargins']}
77
77
  />
78
78
 
79
- [A live example of common margin props can be found in this `<Button>` story.](?path=/story/components-ready-to-use-button--common-margins)
79
+ [A live example of common margin props can be found in this `<Button>` story.](?path=/story/components-button--common-margins)
80
80
 
81
81
  Implementation details can be found in <a href='https://github.com/ucl-isd/uikit-react/blob/main/lib/components/common/marginsStyle.ts' target='_blank'>uikit-react/components/common/MarginsStyle.tsx</a>
82
82
 
@@ -7,6 +7,9 @@ export type { InputProps } from './Input';
7
7
  export { default as Link } from './Link';
8
8
  export type { LinkProps } from './Link';
9
9
 
10
+ export { default as StandaloneLink } from './StandaloneLink';
11
+ export type { StandaloneLinkProps } from './StandaloneLink';
12
+
10
13
  export { default as Button } from './Button';
11
14
  export type { ButtonProps } from './Button';
12
15
 
@@ -100,8 +103,8 @@ export type { TabsProps } from './Tabs';
100
103
  export type { TabProps } from './Tabs/Tab';
101
104
 
102
105
  // todo:
103
- // export { default as Accordion } from './Accordion';
104
- // export type { AccordionProps } from './Accordion';
106
+ export { default as Accordion } from './Accordion';
107
+ export type { AccordionProps } from './Accordion';
105
108
 
106
109
  export { default as Field } from './Field';
107
110
  export type { FieldProps } from './Field';
@@ -131,5 +134,28 @@ export type { RadioProps, LabelledRadioProps } from './Radio';
131
134
  export { default as Datepicker } from './Datepicker';
132
135
  export type { DatepickerProps } from './Datepicker';
133
136
 
137
+ export { default as NativeDatepicker } from './NativeDatepicker';
138
+ export type { NativeDatepickerProps } from './NativeDatepicker';
139
+
134
140
  export { default as Calendar } from './Calendar';
135
141
  export type { CalendarProps } from './Calendar';
142
+
143
+ export { default as WeekPicker } from './WeekPicker';
144
+
145
+ export { default as FileInput } from './FileInput';
146
+ export type { FileInputProps } from './FileInput';
147
+
148
+ export { default as Timepicker } from './Timepicker';
149
+ export type { TimepickerProps } from './Timepicker';
150
+
151
+ export { default as CookieNotice } from './CookieNotice';
152
+ export type { CookieNoticeProps } from './CookieNotice';
153
+
154
+ export { default as Search } from './Search';
155
+ export type { SearchProps } from './Search';
156
+
157
+ export { default as Layout } from './Layout';
158
+ export type { LayoutProps } from './Layout';
159
+
160
+ export { default as Main } from './Main';
161
+ export type { MainProps } from './Main';
@@ -0,0 +1,2 @@
1
+ export { useFocusTrap } from './useFocusTrap';
2
+ export { default as useMediaQuery } from './useMediaQuery';
@@ -0,0 +1,159 @@
1
+ // Generated with Claude Sonnet 4
2
+
3
+ import { useEffect, useCallback, useRef } from 'react';
4
+
5
+ // Selector for focusable elements
6
+ const FOCUSABLE_ELEMENTS = [
7
+ 'a[href]',
8
+ 'button:not([disabled])',
9
+ 'textarea:not([disabled])',
10
+ 'input:not([disabled])',
11
+ 'select:not([disabled])',
12
+ '[tabindex]:not([tabindex="-1"])',
13
+ '[contenteditable="true"]',
14
+ 'audio[controls]',
15
+ 'video[controls]',
16
+ 'details > summary:first-of-type',
17
+ ].join(', ');
18
+
19
+ interface UseFocusTrapOptions {
20
+ isActive: boolean;
21
+ containerRef: React.RefObject<HTMLElement | null>;
22
+ initialFocusRef?: React.RefObject<HTMLElement>;
23
+ finalFocusRef?: React.RefObject<HTMLElement>;
24
+ restoreFocus?: boolean;
25
+ skipFirstFocusable?: boolean;
26
+ }
27
+
28
+ export const useFocusTrap = ({
29
+ isActive,
30
+ containerRef,
31
+ initialFocusRef,
32
+ finalFocusRef,
33
+ restoreFocus = true,
34
+ skipFirstFocusable = false,
35
+ }: UseFocusTrapOptions) => {
36
+ const previousActiveElement = useRef<HTMLElement | null>(null);
37
+
38
+ // Get all focusable elements within the container
39
+ const getFocusableElements = useCallback((): HTMLElement[] => {
40
+ if (!containerRef.current) return [];
41
+
42
+ const elements = containerRef.current.querySelectorAll(FOCUSABLE_ELEMENTS);
43
+ return Array.from(elements) as HTMLElement[];
44
+ }, [containerRef]);
45
+
46
+ // Handle tab key navigation
47
+ const handleKeyDown = useCallback(
48
+ (event: KeyboardEvent) => {
49
+ if (!isActive || event.key !== 'Tab') return;
50
+
51
+ const focusableElements = getFocusableElements();
52
+ if (focusableElements.length === 0) {
53
+ event.preventDefault();
54
+ return;
55
+ }
56
+
57
+ const firstElement = focusableElements[0];
58
+ const lastElement = focusableElements[focusableElements.length - 1];
59
+ const currentFocus = document.activeElement as HTMLElement;
60
+
61
+ if (event.shiftKey) {
62
+ // Shift + Tab (moving backwards)
63
+ if (
64
+ currentFocus === firstElement ||
65
+ !containerRef.current?.contains(currentFocus)
66
+ ) {
67
+ event.preventDefault();
68
+ lastElement.focus();
69
+ }
70
+ } else {
71
+ // Tab (moving forwards)
72
+ if (
73
+ currentFocus === lastElement ||
74
+ !containerRef.current?.contains(currentFocus)
75
+ ) {
76
+ event.preventDefault();
77
+ firstElement.focus();
78
+ }
79
+ }
80
+ },
81
+ [isActive, getFocusableElements, containerRef]
82
+ );
83
+
84
+ // Set initial focus when trap becomes active
85
+ useEffect(() => {
86
+ if (!isActive) return;
87
+
88
+ // Store the previously focused element
89
+ previousActiveElement.current = document.activeElement as HTMLElement;
90
+
91
+ // Focus the specified initial element or the first focusable element
92
+ const focusableElements = getFocusableElements();
93
+ const defaultIndex =
94
+ skipFirstFocusable && focusableElements.length > 1 ? 1 : 0;
95
+ const focusElement =
96
+ initialFocusRef?.current || focusableElements[defaultIndex];
97
+
98
+ let requestAnimationFrameId: number | null = null;
99
+ let setTimeoutId: ReturnType<typeof setTimeout> | undefined;
100
+
101
+ if (focusElement) {
102
+ // Use requestAnimationFrame if available, otherwise setTimeout
103
+ if (typeof requestAnimationFrame === 'function') {
104
+ requestAnimationFrameId = requestAnimationFrame(() => {
105
+ focusElement.focus();
106
+ });
107
+ } else {
108
+ setTimeoutId = setTimeout(() => {
109
+ focusElement.focus();
110
+ }, 0);
111
+ }
112
+ }
113
+
114
+ // Add event listener for keyboard navigation
115
+ document.addEventListener('keydown', handleKeyDown);
116
+
117
+ return () => {
118
+ document.removeEventListener('keydown', handleKeyDown);
119
+ if (
120
+ typeof requestAnimationFrame === 'function' &&
121
+ requestAnimationFrameId !== null
122
+ ) {
123
+ cancelAnimationFrame(requestAnimationFrameId);
124
+ }
125
+ if (
126
+ typeof requestAnimationFrame !== 'function' &&
127
+ setTimeoutId !== undefined
128
+ ) {
129
+ clearTimeout(setTimeoutId);
130
+ }
131
+ };
132
+ }, [
133
+ isActive,
134
+ initialFocusRef,
135
+ getFocusableElements,
136
+ handleKeyDown,
137
+ skipFirstFocusable,
138
+ ]);
139
+
140
+ // Restore focus when trap becomes inactive
141
+ useEffect(() => {
142
+ if (isActive) return; // Only run when becoming inactive
143
+
144
+ if (restoreFocus && previousActiveElement.current) {
145
+ // Use setTimeout to ensure the dialog is fully closed before restoring focus
146
+ const restoreTimeout = setTimeout(() => {
147
+ const elementToFocus =
148
+ finalFocusRef?.current || previousActiveElement.current;
149
+ if (elementToFocus && document.contains(elementToFocus)) {
150
+ elementToFocus.focus();
151
+ }
152
+ // Clear the stored element after restoring focus
153
+ previousActiveElement.current = null;
154
+ }, 100); // Longer delay for native dialog close
155
+
156
+ return () => clearTimeout(restoreTimeout);
157
+ }
158
+ }, [isActive, finalFocusRef, restoreFocus]);
159
+ };
package/lib/index.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  export { cx, css } from '@emotion/css';
2
2
  export * from './components';
3
3
  export * from './theme';
4
+ export * from './hooks';
5
+ export * from './utils';
@@ -47,6 +47,7 @@ const pink20 = '#DEB8C3'; // UCL vibrant pink
47
47
  const black100 = '#000000';
48
48
  const black90 = '#1A1A1A';
49
49
  const black80 = '#333333';
50
+ const black70 = '#4D4D4D';
50
51
  const black60 = '#666666';
51
52
  const black40 = '#999999';
52
53
  const black20 = '#CCCCCC';
@@ -102,6 +103,7 @@ const baseColour = {
102
103
  black100,
103
104
  black90,
104
105
  black80,
106
+ black70,
105
107
  black60,
106
108
  black40,
107
109
  black20,
@@ -189,7 +191,9 @@ const systemColours = {
189
191
 
190
192
  const linkColours = {
191
193
  default: baseColour.blue70,
194
+ secondaryDefault: baseColour.black90,
192
195
  hover: baseColour.blue100,
196
+ secondaryHover: baseColour.black70,
193
197
  visited: baseColour.purple40,
194
198
  disabled: baseColour.black20,
195
199
  };
@@ -203,6 +207,7 @@ const neutralColours = {
203
207
  black: blackAndWhite.black,
204
208
  grey90: baseColour.black90,
205
209
  grey80: baseColour.black80,
210
+ grey70: baseColour.black70,
206
211
  grey60: baseColour.black60,
207
212
  grey40: baseColour.black40,
208
213
  grey20: baseColour.black20,
@@ -253,6 +258,7 @@ const baseSizes = {
253
258
  };
254
259
 
255
260
  const margin = {
261
+ m0: 0,
256
262
  m2: baseSizes.s2,
257
263
  m4: baseSizes.s4,
258
264
  m6: baseSizes.s6,
@@ -271,6 +277,7 @@ const margin = {
271
277
  };
272
278
 
273
279
  const padding = {
280
+ p0: 0,
274
281
  p2: baseSizes.s2,
275
282
  p4: baseSizes.s4,
276
283
  p6: baseSizes.s6,
@@ -0,0 +1,121 @@
1
+ import { describe, test, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ import { screen, waitFor } from '@testing-library/react';
3
+ import announce, { __resetForTesting } from '../announce';
4
+
5
+ describe('announce (ARIA live region)', () => {
6
+ beforeEach(() => {
7
+ // Reset DOM before each test
8
+ document.body.innerHTML = '';
9
+ __resetForTesting();
10
+ });
11
+
12
+ afterEach(() => {
13
+ vi.useRealTimers();
14
+ });
15
+
16
+ test('creates a live region on first announce', async () => {
17
+ announce('Hello world');
18
+
19
+ const region = await screen.findByTestId('aria-live-region');
20
+
21
+ expect(region).toBeTruthy();
22
+ expect(region.getAttribute('aria-live')).toBe('polite');
23
+ expect(region.getAttribute('aria-atomic')).toBe('true');
24
+ });
25
+
26
+ test('visually hides the live region but keeps it accessible', async () => {
27
+ announce('Hidden message');
28
+
29
+ const region = await screen.findByTestId('aria-live-region');
30
+
31
+ expect(region.style.position).toBe('absolute');
32
+ expect(region.style.left).toBe('-9999px');
33
+ expect(region.style.width).toBe('1px');
34
+ expect(region.style.height).toBe('1px');
35
+ expect(region.style.overflow).toBe('hidden');
36
+ });
37
+
38
+ test('clears text and sets message after timeout', async () => {
39
+ announce('This is an announcement');
40
+
41
+ const region = await screen.findByTestId('aria-live-region');
42
+
43
+ await waitFor(() => {
44
+ expect(region.textContent).toBe('This is an announcement');
45
+ });
46
+ });
47
+
48
+ test('reuses the same live region on multiple announcements', async () => {
49
+ announce('First message');
50
+
51
+ const region = await screen.findByTestId('aria-live-region');
52
+
53
+ expect(region).toBeTruthy();
54
+
55
+ announce('Second message');
56
+
57
+ // Query all instances
58
+ const allRegions = await screen.findAllByTestId('aria-live-region');
59
+
60
+ expect(allRegions.length).toBe(1);
61
+ });
62
+
63
+ test('queues multiple announcements and processes sequentially', async () => {
64
+ vi.useFakeTimers();
65
+
66
+ announce('First message');
67
+ announce('Second message');
68
+
69
+ // Query the live region
70
+ const region = document.querySelector(
71
+ '[data-testid="aria-live-region"]'
72
+ ) as HTMLElement;
73
+
74
+ // Initially empty
75
+ expect(region.textContent).toBe('');
76
+
77
+ // After 100ms, first message appears
78
+ vi.advanceTimersByTime(100);
79
+ expect(region.textContent).toBe('First message');
80
+
81
+ // Second message should NOT appear yet (need to wait 1000ms + 100ms more)
82
+ vi.advanceTimersByTime(500);
83
+ expect(region.textContent).toBe('First message');
84
+
85
+ // After remaining 500ms of the 1000ms delay, queue processes but text is cleared
86
+ vi.advanceTimersByTime(500);
87
+ expect(region.textContent).toBe('');
88
+
89
+ // After another 100ms, second message appears
90
+ vi.advanceTimersByTime(100);
91
+ expect(region.textContent).toBe('Second message');
92
+ });
93
+
94
+ test('duplicate prevention while currently announcing', async () => {
95
+ vi.useFakeTimers();
96
+
97
+ announce('Processing');
98
+ announce('Processing'); // Duplicate - should be ignored
99
+ announce('Processing'); // Duplicate - should be ignored
100
+ announce('Done'); // Different message - should be queued
101
+
102
+ const region = document.querySelector(
103
+ '[data-testid="aria-live-region"]'
104
+ ) as HTMLElement;
105
+
106
+ // First message appears
107
+ vi.advanceTimersByTime(100);
108
+ expect(region.textContent).toBe('Processing');
109
+
110
+ // Complete first message, next should be "Done" (duplicates were ignored)
111
+ vi.advanceTimersByTime(1000);
112
+ vi.advanceTimersByTime(100);
113
+ expect(region.textContent).toBe('Done');
114
+
115
+ // No more messages in queue
116
+ vi.advanceTimersByTime(1000);
117
+ vi.advanceTimersByTime(100);
118
+ // Still "Done" - nothing else was queued
119
+ expect(region.textContent).toBe('Done');
120
+ });
121
+ });
@@ -0,0 +1,40 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import capitalise from '../capitalise';
3
+
4
+ describe('capitalise', () => {
5
+ it('should capitalize the first letter of a lowercase word', () => {
6
+ expect(capitalise('hello')).toBe('Hello');
7
+ });
8
+
9
+ it('should capitalize the first letter of a sentence', () => {
10
+ expect(capitalise('hello world')).toBe('Hello world');
11
+ });
12
+
13
+ it('should handle already capitalized text', () => {
14
+ expect(capitalise('Hello')).toBe('Hello');
15
+ });
16
+
17
+ it('should handle single character strings', () => {
18
+ expect(capitalise('a')).toBe('A');
19
+ });
20
+
21
+ it('should handle strings that start with uppercase', () => {
22
+ expect(capitalise('HELLO')).toBe('HELLO');
23
+ });
24
+
25
+ it('should handle empty strings', () => {
26
+ expect(capitalise('')).toBe('');
27
+ });
28
+
29
+ it('should handle strings with numbers at the start', () => {
30
+ expect(capitalise('123abc')).toBe('123abc');
31
+ });
32
+
33
+ it('should handle strings with special characters at the start', () => {
34
+ expect(capitalise('!hello')).toBe('!hello');
35
+ });
36
+
37
+ it('should preserve the rest of the string as-is', () => {
38
+ expect(capitalise('hELLO')).toBe('HELLO');
39
+ });
40
+ });