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,41 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import Search from './Search';
3
+
4
+ const meta = {
5
+ title: 'Components/Search',
6
+ component: Search,
7
+ parameters: { layout: 'padded' },
8
+ argTypes: {
9
+ placeholder: { control: { type: 'text' } },
10
+ disabled: { control: { type: 'boolean' } },
11
+ testId: { control: { type: 'text' } },
12
+ onSearch: { action: 'searched' },
13
+ },
14
+ tags: ['autodocs'],
15
+ } satisfies Meta<typeof Search>;
16
+
17
+ export default meta;
18
+ type Story = StoryObj<typeof meta>;
19
+
20
+ export const Default: Story = {
21
+ args: {
22
+ placeholder: 'Search...',
23
+ },
24
+ render: (args) => <Search {...args} />,
25
+ };
26
+
27
+ export const Disabled: Story = {
28
+ args: {
29
+ placeholder: 'Search (disabled)',
30
+ disabled: true,
31
+ },
32
+ render: (args) => <Search {...args} />,
33
+ };
34
+
35
+ export const WithPlaceholder: Story = {
36
+ name: 'With custom placeholder',
37
+ args: {
38
+ placeholder: 'Type to filter results',
39
+ },
40
+ render: (args) => <Search {...args} />,
41
+ };
@@ -0,0 +1,170 @@
1
+ import { HTMLAttributes, useRef, useState } from 'react';
2
+ import { css, cx } from '@emotion/css';
3
+ import { Input, Icon, IconButton, InputProps, IconButtonProps } from '../..';
4
+ import useTheme from '../../theme/useTheme';
5
+ import marginsStyle, { MarginProps } from '../common/marginsStyle';
6
+
7
+ export interface SearchBaseProps extends HTMLAttributes<HTMLDivElement> {
8
+ onSearch?: (searchTerms: string) => void;
9
+ placeholder?: string;
10
+ disabled?: boolean;
11
+ inputProps?: InputProps;
12
+ clearButtonProps?: IconButtonProps;
13
+ submitButtonProps?: IconButtonProps;
14
+ testId?: string;
15
+ }
16
+
17
+ export type SearchProps = SearchBaseProps & MarginProps;
18
+
19
+ export const NAME = 'ucl-uikit-search';
20
+
21
+ const Search = ({
22
+ placeholder = '',
23
+ testId = NAME,
24
+ onSearch,
25
+ disabled = false,
26
+ m,
27
+ mv,
28
+ mh,
29
+ mt,
30
+ mb,
31
+ ml,
32
+ mr,
33
+ noMargins,
34
+ inputProps,
35
+ clearButtonProps,
36
+ submitButtonProps,
37
+ className,
38
+ ...props
39
+ }: SearchProps) => {
40
+ const [searchTerms, setSearchTerms] = useState<string>('');
41
+ const inputRef = useRef<HTMLInputElement>(null);
42
+ const [theme] = useTheme();
43
+
44
+ const handleSearchTermsChange = (e: React.ChangeEvent<HTMLInputElement>) => {
45
+ setSearchTerms(e.target.value);
46
+ };
47
+
48
+ const handleClearButtonClick = () => {
49
+ setSearchTerms('');
50
+ inputRef.current?.focus();
51
+ };
52
+
53
+ const handleSearchButtonClick = () => {
54
+ if (onSearch) {
55
+ onSearch(searchTerms);
56
+ }
57
+ };
58
+
59
+ const baseStyle = css`
60
+ position: relative;
61
+ height: 48px;
62
+ `;
63
+
64
+ const style = cx(
65
+ NAME,
66
+ baseStyle,
67
+ marginsStyle(
68
+ {
69
+ m,
70
+ mv,
71
+ mh,
72
+ mt,
73
+ mb,
74
+ ml,
75
+ mr,
76
+ noMargins,
77
+ },
78
+ theme
79
+ ),
80
+ className
81
+ );
82
+
83
+ const inputStyle = css`
84
+ width: 100%;
85
+ box-sizing: border-box;
86
+ padding-right: 96px;
87
+ `;
88
+
89
+ const buttonsStyle = css`
90
+ position: absolute;
91
+ right: 1px;
92
+ top: 1px;
93
+ bottom: 1px;
94
+ display: flex;
95
+ justify-content: flex-end;
96
+ align-items: center;
97
+ `;
98
+
99
+ const cancelButtonBaseStyle = css`
100
+ margin-left: ${theme.margin.m12};
101
+ margin-right: ${theme.margin.m12};
102
+ `;
103
+
104
+ const cancelIconButtonInactiveStyle = css`
105
+ color: ${theme.color.neutral.grey20};
106
+ `;
107
+
108
+ const cancelButtonStyle = cx(
109
+ cancelButtonBaseStyle,
110
+ searchTerms.length === 0 && cancelIconButtonInactiveStyle
111
+ );
112
+
113
+ const dividerStyle = css`
114
+ width: 1px;
115
+ height: 38px;
116
+ background-color: ${theme.color.neutral.grey20};
117
+ `;
118
+
119
+ const submitButtonStyle = css`
120
+ width: 48px;
121
+ height: 100%;
122
+ `;
123
+
124
+ return (
125
+ <div
126
+ className={style}
127
+ {...props}
128
+ >
129
+ <Input
130
+ ref={inputRef}
131
+ inputClassName={inputStyle}
132
+ placeholder={placeholder}
133
+ type='text'
134
+ onChange={handleSearchTermsChange}
135
+ value={searchTerms}
136
+ disabled={disabled}
137
+ data-testid={testId}
138
+ {...inputProps}
139
+ />
140
+
141
+ <div className={buttonsStyle}>
142
+ <IconButton
143
+ disabled={disabled}
144
+ className={cancelButtonStyle}
145
+ onClick={handleClearButtonClick}
146
+ aria-label='Clear search'
147
+ data-testid={`${testId}-clear-search-btn`}
148
+ {...clearButtonProps}
149
+ >
150
+ <Icon.X />
151
+ </IconButton>
152
+
153
+ <div className={dividerStyle} />
154
+
155
+ <IconButton
156
+ className={submitButtonStyle}
157
+ disabled={disabled}
158
+ onClick={handleSearchButtonClick}
159
+ aria-label='Search'
160
+ data-testid={`${testId}-search-btn`}
161
+ {...submitButtonProps}
162
+ >
163
+ <Icon.Search />
164
+ </IconButton>
165
+ </div>
166
+ </div>
167
+ );
168
+ };
169
+
170
+ export default Search;
@@ -0,0 +1,112 @@
1
+ import { describe, expect, test } from 'vitest';
2
+ import { render, screen } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import { vi } from 'vitest';
5
+ import { ThemeContextProvider } from '../../../theme/useTheme';
6
+ import Search from '../Search';
7
+
8
+ describe('Search', () => {
9
+ // Snapshot tests
10
+
11
+ test('snapshot: no props', () => {
12
+ const renderResult = render(
13
+ <ThemeContextProvider>
14
+ <Search />
15
+ </ThemeContextProvider>
16
+ );
17
+ expect(renderResult.container.firstChild).toMatchSnapshot();
18
+ });
19
+
20
+ test('snapshot: testId prop', () => {
21
+ const renderResult = render(
22
+ <ThemeContextProvider>
23
+ <Search testId='test123' />
24
+ </ThemeContextProvider>
25
+ );
26
+ expect(renderResult.container.firstChild).toMatchSnapshot();
27
+ });
28
+
29
+ // Interaction tests
30
+
31
+ test('test ID: default', () => {
32
+ render(
33
+ <ThemeContextProvider>
34
+ <Search />
35
+ </ThemeContextProvider>
36
+ );
37
+ const search = screen.getByRole('textbox');
38
+ expect(search).toBeInTheDocument();
39
+ });
40
+
41
+ test('test ID: custom', () => {
42
+ render(
43
+ <ThemeContextProvider>
44
+ <Search testId='custom-test-id' />
45
+ </ThemeContextProvider>
46
+ );
47
+ const search = screen.getByTestId('custom-test-id');
48
+ expect(search).toBeInTheDocument();
49
+ });
50
+
51
+ test('allows user to type in search input', async () => {
52
+ const user = userEvent.setup();
53
+
54
+ render(
55
+ <ThemeContextProvider>
56
+ <Search />
57
+ </ThemeContextProvider>
58
+ );
59
+
60
+ const input = screen.getByRole('textbox');
61
+
62
+ await user.type(input, 'hello world');
63
+ expect(input).toHaveValue('hello world');
64
+ });
65
+
66
+ test('allows user to click on search button', async () => {
67
+ const user = userEvent.setup();
68
+ render(
69
+ <ThemeContextProvider>
70
+ <Search />
71
+ </ThemeContextProvider>
72
+ );
73
+
74
+ const input = screen.getByTestId('ucl-uikit-search-search-btn');
75
+ await user.click(input);
76
+ });
77
+
78
+ test('calls onSearch when seatch button is clicked', async () => {
79
+ const user = userEvent.setup();
80
+ const mockOnSearch = vi.fn();
81
+
82
+ render(
83
+ <ThemeContextProvider>
84
+ <Search onSearch={mockOnSearch} />
85
+ </ThemeContextProvider>
86
+ );
87
+ const input = screen.getByRole('textbox');
88
+ await user.type(input, 'test search');
89
+ const searchButton = screen.getByTestId('ucl-uikit-search-search-btn');
90
+ await user.click(searchButton);
91
+
92
+ expect(mockOnSearch).toHaveBeenCalledWith('test search');
93
+ });
94
+ test('clear button clears text and returns focus to input', async () => {
95
+ const user = userEvent.setup();
96
+ render(
97
+ <ThemeContextProvider>
98
+ <Search placeholder='Search products...' />
99
+ </ThemeContextProvider>
100
+ );
101
+
102
+ const input = screen.getByTestId('ucl-uikit-search');
103
+ const clearButton = screen.getByTestId('ucl-uikit-search-clear-search-btn');
104
+
105
+ await user.type(input, 'hello');
106
+ await user.tab();
107
+ await user.click(clearButton);
108
+
109
+ expect((input as HTMLInputElement).value).toBe('');
110
+ expect(document.activeElement).toBe(input);
111
+ });
112
+ });
@@ -0,0 +1,179 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`Search > snapshot: no props 1`] = `
4
+ <div
5
+ class="ucl-uikit-search css-176lya2"
6
+ >
7
+ <span
8
+ class="ucl-uikit-input css-1bpb1dw"
9
+ >
10
+ <input
11
+ class="ucl-uikit-input__input css-181a0dk"
12
+ data-testid="ucl-uikit-search"
13
+ id=""
14
+ placeholder=""
15
+ type="text"
16
+ value=""
17
+ />
18
+ </span>
19
+ <div
20
+ class="css-1mxrgm7"
21
+ >
22
+ <button
23
+ aria-label="Clear search"
24
+ class="ucl-uikit-icon-button css-1317vpi"
25
+ data-testid="ucl-uikit-search-clear-search-btn"
26
+ >
27
+ <svg
28
+ class="ucl-uikit-icon css-148hpxb"
29
+ data-testid="ucl-uikit-icon"
30
+ fill="none"
31
+ height="24"
32
+ stroke="currentColor"
33
+ stroke-linecap="round"
34
+ stroke-linejoin="round"
35
+ stroke-width="2"
36
+ viewBox="0 0 24 24"
37
+ width="24"
38
+ xmlns="http://www.w3.org/2000/svg"
39
+ >
40
+ <line
41
+ x1="18"
42
+ x2="6"
43
+ y1="6"
44
+ y2="18"
45
+ />
46
+ <line
47
+ x1="6"
48
+ x2="18"
49
+ y1="6"
50
+ y2="18"
51
+ />
52
+ </svg>
53
+ </button>
54
+ <div
55
+ class="css-5jwcn5"
56
+ />
57
+ <button
58
+ aria-label="Search"
59
+ class="ucl-uikit-icon-button css-1soyhl2"
60
+ data-testid="ucl-uikit-search-search-btn"
61
+ >
62
+ <svg
63
+ class="ucl-uikit-icon css-148hpxb"
64
+ data-testid="ucl-uikit-icon"
65
+ fill="none"
66
+ height="24"
67
+ stroke="currentColor"
68
+ stroke-linecap="round"
69
+ stroke-linejoin="round"
70
+ stroke-width="2"
71
+ viewBox="0 0 24 24"
72
+ width="24"
73
+ xmlns="http://www.w3.org/2000/svg"
74
+ >
75
+ <circle
76
+ cx="11"
77
+ cy="11"
78
+ r="8"
79
+ />
80
+ <line
81
+ x1="21"
82
+ x2="16.65"
83
+ y1="21"
84
+ y2="16.65"
85
+ />
86
+ </svg>
87
+ </button>
88
+ </div>
89
+ </div>
90
+ `;
91
+
92
+ exports[`Search > snapshot: testId prop 1`] = `
93
+ <div
94
+ class="ucl-uikit-search css-176lya2"
95
+ >
96
+ <span
97
+ class="ucl-uikit-input css-1bpb1dw"
98
+ >
99
+ <input
100
+ class="ucl-uikit-input__input css-181a0dk"
101
+ data-testid="test123"
102
+ id=""
103
+ placeholder=""
104
+ type="text"
105
+ value=""
106
+ />
107
+ </span>
108
+ <div
109
+ class="css-1mxrgm7"
110
+ >
111
+ <button
112
+ aria-label="Clear search"
113
+ class="ucl-uikit-icon-button css-1317vpi"
114
+ data-testid="test123-clear-search-btn"
115
+ >
116
+ <svg
117
+ class="ucl-uikit-icon css-148hpxb"
118
+ data-testid="ucl-uikit-icon"
119
+ fill="none"
120
+ height="24"
121
+ stroke="currentColor"
122
+ stroke-linecap="round"
123
+ stroke-linejoin="round"
124
+ stroke-width="2"
125
+ viewBox="0 0 24 24"
126
+ width="24"
127
+ xmlns="http://www.w3.org/2000/svg"
128
+ >
129
+ <line
130
+ x1="18"
131
+ x2="6"
132
+ y1="6"
133
+ y2="18"
134
+ />
135
+ <line
136
+ x1="6"
137
+ x2="18"
138
+ y1="6"
139
+ y2="18"
140
+ />
141
+ </svg>
142
+ </button>
143
+ <div
144
+ class="css-5jwcn5"
145
+ />
146
+ <button
147
+ aria-label="Search"
148
+ class="ucl-uikit-icon-button css-1soyhl2"
149
+ data-testid="test123-search-btn"
150
+ >
151
+ <svg
152
+ class="ucl-uikit-icon css-148hpxb"
153
+ data-testid="ucl-uikit-icon"
154
+ fill="none"
155
+ height="24"
156
+ stroke="currentColor"
157
+ stroke-linecap="round"
158
+ stroke-linejoin="round"
159
+ stroke-width="2"
160
+ viewBox="0 0 24 24"
161
+ width="24"
162
+ xmlns="http://www.w3.org/2000/svg"
163
+ >
164
+ <circle
165
+ cx="11"
166
+ cy="11"
167
+ r="8"
168
+ />
169
+ <line
170
+ x1="21"
171
+ x2="16.65"
172
+ y1="21"
173
+ y2="16.65"
174
+ />
175
+ </svg>
176
+ </button>
177
+ </div>
178
+ </div>
179
+ `;
@@ -0,0 +1,2 @@
1
+ export { default } from './Search';
2
+ export type { SearchProps } from './Search';
@@ -0,0 +1,169 @@
1
+ import * as SelectStories from "./Select.stories";
2
+ import { Meta, Title, Subtitle, Canvas, Controls, ArgTypes } from "@storybook/blocks";
3
+
4
+ export const usage = {
5
+ default: `<Select
6
+ options={[
7
+ { label: 'Option one', value: '1' },
8
+ { label: 'Option two', value: '2' },
9
+ { label: 'Option three', value: '3' },
10
+ ]}
11
+ value={value}
12
+ onValueChange={handleChange}
13
+ />`,
14
+ native: `<Select
15
+ native
16
+ options={[
17
+ { label: 'Option one', value: '1' },
18
+ { label: 'Option two', value: '2' },
19
+ { label: 'Option three', value: '3' },
20
+ ]}
21
+ value={value}
22
+ nativeHtmlAttributes={{ onChange: onNativeChange }}
23
+ />`,
24
+ filterable: `<Select
25
+ filterable
26
+ options={[
27
+ { label: 'Option one', value: '1' },
28
+ { label: 'Option two', value: '2' },
29
+ { label: 'Option three', value: '3' },
30
+ ]}
31
+ value={value}
32
+ onValueChange={handleChange}
33
+ placeholder="Type to filter..."
34
+ filterInputProps={{ 'aria-describedby': 'filter-hint' }}
35
+ />`,
36
+ selectionBehaviourCommit: `<Select
37
+ selectionBehaviour="commit"
38
+ options={[
39
+ { label: 'Option one', value: '1' },
40
+ { label: 'Option two', value: '2' },
41
+ { label: 'Option three', value: '3' },
42
+ ]}
43
+ value={value}
44
+ onValueChange={handleChange}
45
+ />`,
46
+ disabled: `<Select
47
+ disabled
48
+ options={[
49
+ { label: 'Option one', value: '1' },
50
+ { label: 'Option two', value: '2' },
51
+ { label: 'Option three', value: '3' },
52
+ ]}
53
+ value={value}
54
+ onValueChange={handleChange}
55
+ />`,
56
+ placeholder: `<Select
57
+ placeholder="Please select an option"
58
+ options={[
59
+ { label: 'Option one', value: '1' },
60
+ { label: 'Option two', value: '2' },
61
+ { label: 'Option three', value: '3' },
62
+ ]}
63
+ value={value}
64
+ onValueChange={handleChange}
65
+ />`,
66
+ };
67
+
68
+ <Meta of={SelectStories} />
69
+ <Title />
70
+ <Subtitle>
71
+ A custom select with an optional native fallback, opt-in filtering, and long-text handling.
72
+ </Subtitle>
73
+
74
+ Use `<Select>` when you need a styled dropdown that works like a standard form control but matches the UCL UI kit. The component renders a custom combobox by default and can fall back to the native `<select>` for environments where native behaviour is preferred (e.g. mobile accessibility).
75
+
76
+ Key features:
77
+ - Custom dropdown with keyboard support (Enter/Space to open, arrows to navigate, Escape to close)
78
+ - Configurable keyboard selection behaviour via `selectionBehaviour` (`focus` or `commit`)
79
+ - Optional native fallback (`native`)
80
+ - Optional filterable dropdown (`filterable`) that lets users type to narrow options
81
+ - `filterInputProps` to forward additional attributes (e.g. `aria-describedby`) to the filter input
82
+ - Support for long option text via `lineBreak`
83
+ - Disabled state and placeholder support
84
+ - Story previews set a fixed control width and wrapper height for better readability in docs.
85
+
86
+ ## Variants
87
+
88
+ ### Custom (default)
89
+ The default renders a fully styled combobox that handles focus, keyboard navigation, and selection. Use this for most desktop/web cases.
90
+
91
+ <Canvas
92
+ of={SelectStories.Default}
93
+ sourceState="shown"
94
+ source={{ code: usage.default }}
95
+ />
96
+
97
+ ### Native
98
+ Set `native` to render the browser `<select>`. This is useful when you want built-in mobile picker behaviour or the simplest possible semantics. Props like `onChange`, `value`, and standard `<select>` attributes can be passed via `nativeHtmlAttributes`.
99
+
100
+ <Canvas
101
+ of={SelectStories.Native}
102
+ sourceState="shown"
103
+ source={{ code: usage.native }}
104
+ />
105
+
106
+ ### Disabled
107
+ Applies the disabled state to both custom and native variants; interactions are blocked and styles are subdued.
108
+
109
+ <Canvas
110
+ of={SelectStories.Disabled}
111
+ sourceState="shown"
112
+ source={{ code: usage.disabled }}
113
+ />
114
+
115
+ ### Placeholder
116
+ Shows helper text until a value is selected. In the native variant it appears as a disabled option; in the custom variant it shows in the visible field.
117
+
118
+ <Canvas
119
+ of={SelectStories.WithPlaceholder}
120
+ sourceState="shown"
121
+ source={{ code: usage.placeholder }}
122
+ />
123
+
124
+ ### With filter
125
+ Adds an inline text input when the dropdown is open so users can type to filter options. Arrow keys and Escape still control the dropdown; the filter text is preserved while open and cleared on close.
126
+
127
+ Use `filterInputProps` to pass extra attributes to the input (e.g. `aria-describedby`, `inputMode`).
128
+
129
+ <Canvas
130
+ of={SelectStories.filterable}
131
+ sourceState="shown"
132
+ source={{ code: usage.filterable }}
133
+ />
134
+
135
+ ### Selection behaviour
136
+ Use `selectionBehaviour` to control how keyboard navigation commits value in the custom variant:
137
+ - `focus` (default): arrow keys move and commit immediately.
138
+ - `commit`: arrow keys only highlight; Enter or click commits.
139
+
140
+ <Canvas
141
+ of={SelectStories.SelectionBehaviourCommit}
142
+ sourceState="shown"
143
+ source={{ code: usage.selectionBehaviourCommit }}
144
+ />
145
+
146
+ ## Long text and wrapping
147
+ For very long labels, set `lineBreak` to allow breaking the text inside options. Without it, text is truncated/ellipsized to keep layout intact.
148
+
149
+ ## Accessibility
150
+ - Custom variant exposes `role="combobox"` and `aria-expanded`, and listens for Enter/Space/Escape/arrow keys.
151
+ - In `selectionBehaviour="commit"`, arrow keys move highlight without changing value until Enter/click.
152
+ - Native variant leverages built-in browser semantics.
153
+ - The filter input (when `filterable` is true) is focusable when the panel opens; Escape and arrow keys bubble to the parent so the dropdown still closes/navigates.
154
+ - `filterInputProps` lets you forward ARIA hooks like `aria-describedby` to the filter input.
155
+ - Standard HTML attributes (`id`, `title`, `data-*`) are forwarded to the combobox/native select.
156
+
157
+ ## Props
158
+
159
+ Full props specification for `<Select>` is below.
160
+
161
+ <Canvas
162
+ of={SelectStories.Default}
163
+ sourceState="hidden"
164
+ source={{ code: usage.default }}
165
+ />
166
+
167
+ You can use the controls below to manipulate the `<Select>` component above.
168
+
169
+ <Controls />