uikit-react-public 0.11.24 → 0.14.21

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 (184) hide show
  1. package/dist/components/Badge/Badge.d.ts +6 -0
  2. package/dist/components/Badge/Badge.stories.d.ts +15 -0
  3. package/dist/components/Badge/index.d.ts +2 -0
  4. package/dist/components/Button/Button.d.ts +2 -1
  5. package/dist/components/CookieNotice/CookieNotice.d.ts +16 -0
  6. package/dist/components/CookieNotice/index.d.ts +2 -0
  7. package/dist/components/Dialog/BaseDialog.d.ts +7 -2
  8. package/dist/components/FileInput/FileInput.d.ts +8 -0
  9. package/dist/components/FileInput/FileInput.stories.d.ts +16 -0
  10. package/dist/components/FileInput/__tests__/FileInput.test.d.ts +1 -0
  11. package/dist/components/FileInput/index.d.ts +2 -0
  12. package/dist/components/Header/Header.d.ts +4 -1
  13. package/dist/components/Heading/Heading.d.ts +1 -1
  14. package/dist/components/Link/BaseLink.d.ts +10 -0
  15. package/dist/components/Link/Link.d.ts +5 -10
  16. package/dist/components/Link/Link.stories.d.ts +1 -1
  17. package/dist/components/Link/index.d.ts +1 -1
  18. package/dist/components/Menu/MenuContent.d.ts +1 -1
  19. package/dist/components/Menu/MenuItem.d.ts +2 -0
  20. package/dist/components/Menu/MenuSection.d.ts +1 -1
  21. package/dist/components/Search/Search.d.ts +16 -0
  22. package/dist/components/Search/Search.stories.d.ts +34 -0
  23. package/dist/components/Search/__tests__/Search.test.d.ts +1 -0
  24. package/dist/components/Search/index.d.ts +2 -0
  25. package/dist/components/Select/Select.d.ts +1 -1
  26. package/dist/components/Select/Select.stories.d.ts +3 -7
  27. package/dist/components/Select/Select.types.d.ts +19 -14
  28. package/dist/components/Select/subcomponents/CustomOption.d.ts +1 -1
  29. package/dist/components/Select/subcomponents/CustomSelect.d.ts +1 -2
  30. package/dist/components/Select/subcomponents/Panel.d.ts +1 -1
  31. package/dist/components/Select/subcomponents/VisibleField.d.ts +4 -4
  32. package/dist/components/StandaloneLink/StandaloneLink.d.ts +12 -0
  33. package/dist/components/StandaloneLink/StandaloneLink.stories.d.ts +13 -0
  34. package/dist/components/StandaloneLink/__tests__/StandaloneLink.test.d.ts +1 -0
  35. package/dist/components/StandaloneLink/index.d.ts +2 -0
  36. package/dist/components/Table/Table.d.ts +10 -8
  37. package/dist/components/Table/Table.stories.d.ts +21 -0
  38. package/dist/components/Table/Table.types.d.ts +11 -0
  39. package/dist/components/Table/__tests__/Table.test.d.ts +1 -0
  40. package/dist/components/Table/index.d.ts +2 -1
  41. package/dist/components/Table/subcomponents/Body.d.ts +4 -0
  42. package/dist/components/Table/subcomponents/Cell/Cell.d.ts +12 -0
  43. package/dist/components/Table/subcomponents/Cell/Cell.stories.d.ts +313 -0
  44. package/dist/components/Table/subcomponents/Cell/CellContent.d.ts +10 -0
  45. package/dist/components/Table/subcomponents/Cell/__tests__/Cell.test.d.ts +1 -0
  46. package/dist/components/Table/subcomponents/Head.d.ts +4 -0
  47. package/dist/components/Table/subcomponents/HeadCell/HeadCell.d.ts +13 -0
  48. package/dist/components/Table/subcomponents/HeadCell/HeadCell.stories.d.ts +312 -0
  49. package/dist/components/Table/subcomponents/HeadCell/HeadCellContent.d.ts +10 -0
  50. package/dist/components/Table/subcomponents/HeadCell/__tests__/HeadCell.test.d.ts +1 -0
  51. package/dist/components/Table/subcomponents/Row.d.ts +5 -0
  52. package/dist/components/Table/subcomponents/SortIcon.d.ts +7 -0
  53. package/dist/components/Table/subcomponents/index.d.ts +10 -0
  54. package/dist/components/Tabs/Tab.d.ts +1 -1
  55. package/dist/components/Tabs/TabContext.d.ts +1 -0
  56. package/dist/components/Tabs/Tabs.d.ts +3 -1
  57. package/dist/components/Tabs/Tabs.stories.d.ts +3 -0
  58. package/dist/components/Timepicker/Timepicker.d.ts +10 -0
  59. package/dist/components/Timepicker/Timepicker.stories.d.ts +7 -0
  60. package/dist/components/Timepicker/__tests__/Timepicker.test.d.ts +1 -0
  61. package/dist/components/Timepicker/index.d.ts +2 -0
  62. package/dist/components/Timepicker/utils/convertDateToTimeString.d.ts +2 -0
  63. package/dist/components/Timepicker/utils/convertDateToTimeString.test.d.ts +1 -0
  64. package/dist/components/Timepicker/utils/index.d.ts +1 -0
  65. package/dist/components/WeekPicker/WeekPicker.d.ts +3 -0
  66. package/dist/components/WeekPicker/index.d.ts +1 -0
  67. package/dist/components/WeekPicker/subcomponents/CustomDatepicker.d.ts +17 -0
  68. package/dist/components/WeekPicker/subcomponents/DatepickerInput.d.ts +13 -0
  69. package/dist/components/WeekPicker/subcomponents/VisibleField.d.ts +15 -0
  70. package/dist/components/WeekPicker/subcomponents/index.d.ts +3 -0
  71. package/dist/components/index.d.ts +11 -0
  72. package/dist/hooks/index.d.ts +2 -0
  73. package/dist/hooks/useFocusTrap.d.ts +9 -0
  74. package/dist/index.d.ts +1 -0
  75. package/dist/index.js +5703 -4448
  76. package/dist/theme/defaultTheme.d.ts +7 -0
  77. package/dist/theme/useTheme.d.ts +14 -0
  78. package/dist/utils/__tests__/capitalise.test.d.ts +1 -0
  79. package/dist/utils/capitalise.d.ts +2 -0
  80. package/lib/components/Alert/Alert.tsx +7 -1
  81. package/lib/components/Alert/__tests__/__snapshots__/Alert.test.tsx.snap +4 -0
  82. package/lib/components/Badge/Badge.stories.tsx +19 -0
  83. package/lib/components/Badge/Badge.tsx +48 -0
  84. package/lib/components/Badge/index.ts +2 -0
  85. package/lib/components/Breadcrumbs/__tests__/__snapshots__/Breadcrumbs.test.tsx.snap +4 -4
  86. package/lib/components/Button/Button.tsx +5 -2
  87. package/lib/components/Calendar/subcomponents/Grid.tsx +0 -1
  88. package/lib/components/CookieNotice/CookieNotice.tsx +114 -0
  89. package/lib/components/CookieNotice/index.ts +2 -0
  90. package/lib/components/Dialog/BaseDialog.tsx +44 -4
  91. package/lib/components/Field/__tests__/Field.test.tsx +148 -148
  92. package/lib/components/FileInput/FileInput.stories.tsx +70 -0
  93. package/lib/components/FileInput/FileInput.tsx +68 -0
  94. package/lib/components/FileInput/__tests__/FileInput.test.tsx +99 -0
  95. package/lib/components/FileInput/__tests__/__snapshots__/FileInput.test.tsx.snap +91 -0
  96. package/lib/components/FileInput/index.ts +2 -0
  97. package/lib/components/Footer/__tests__/__snapshots__/Footer.test.tsx.snap +25 -25
  98. package/lib/components/Header/Header.tsx +19 -2
  99. package/lib/components/Header/__tests__/__snapshots__/Header.test.tsx.snap +4 -4
  100. package/lib/components/Heading/Documentation.mdx +1 -1
  101. package/lib/components/Heading/Heading.tsx +1 -1
  102. package/lib/components/Heading/__tests__/Heading.test.tsx +7 -19
  103. package/lib/components/Heading/__tests__/__snapshots__/Heading.test.tsx.snap +7 -7
  104. package/lib/components/Label/Label.tsx +0 -2
  105. package/lib/components/Label/__tests__/__snapshots__/Label.test.tsx.snap +7 -7
  106. package/lib/components/Link/BaseLink.tsx +84 -0
  107. package/lib/components/Link/Link.tsx +72 -32
  108. package/lib/components/Link/__tests__/__snapshots__/link.test.tsx.snap +3 -3
  109. package/lib/components/Link/__tests__/link.test.tsx +6 -13
  110. package/lib/components/Link/index.ts +1 -1
  111. package/lib/components/Menu/Menu.context.tsx +3 -1
  112. package/lib/components/Menu/Menu.tsx +2 -2
  113. package/lib/components/Menu/MenuContent.tsx +5 -5
  114. package/lib/components/Menu/MenuItem.tsx +20 -3
  115. package/lib/components/Menu/MenuSection.tsx +4 -3
  116. package/lib/components/Pagination/PaginationControls.tsx +1 -3
  117. package/lib/components/Search/Search.stories.tsx +41 -0
  118. package/lib/components/Search/Search.tsx +167 -0
  119. package/lib/components/Search/__tests__/Search.test.tsx +94 -0
  120. package/lib/components/Search/__tests__/__snapshots__/Search.test.tsx.snap +179 -0
  121. package/lib/components/Search/index.ts +2 -0
  122. package/lib/components/Select/Select.stories.tsx +8 -35
  123. package/lib/components/Select/Select.tsx +2 -2
  124. package/lib/components/Select/Select.types.ts +20 -15
  125. package/lib/components/Select/__tests__/__snapshots__/Select.test.tsx.snap +3 -3
  126. package/lib/components/Select/subcomponents/CustomOption.tsx +22 -9
  127. package/lib/components/Select/subcomponents/CustomSelect.tsx +31 -20
  128. package/lib/components/Select/subcomponents/Panel.tsx +4 -5
  129. package/lib/components/Select/subcomponents/VisibleField.tsx +26 -22
  130. package/lib/components/StandaloneLink/StandaloneLink.stories.tsx +32 -0
  131. package/lib/components/StandaloneLink/StandaloneLink.tsx +183 -0
  132. package/lib/components/StandaloneLink/__tests__/StandaloneLink.test.tsx +57 -0
  133. package/lib/components/StandaloneLink/__tests__/__snapshots__/StandaloneLink.test.tsx.snap +19 -0
  134. package/lib/components/StandaloneLink/index.ts +2 -0
  135. package/lib/components/Table/Table.stories.tsx +337 -0
  136. package/lib/components/Table/Table.tsx +42 -67
  137. package/lib/components/Table/Table.types.ts +14 -0
  138. package/lib/components/Table/__tests__/Table.test.tsx +121 -0
  139. package/lib/components/Table/__tests__/__snapshots__/Table.test.tsx.snap +210 -0
  140. package/lib/components/Table/index.ts +8 -1
  141. package/lib/components/Table/subcomponents/Body.tsx +18 -0
  142. package/lib/components/Table/subcomponents/Cell/Cell.stories.tsx +151 -0
  143. package/lib/components/Table/subcomponents/Cell/Cell.tsx +72 -0
  144. package/lib/components/Table/subcomponents/Cell/CellContent.tsx +91 -0
  145. package/lib/components/Table/subcomponents/Cell/__tests__/Cell.test.tsx +115 -0
  146. package/lib/components/Table/subcomponents/Cell/__tests__/__snapshots__/Cell.test.tsx.snap +107 -0
  147. package/lib/components/Table/subcomponents/Head.tsx +34 -0
  148. package/lib/components/Table/subcomponents/HeadCell/HeadCell.stories.tsx +85 -0
  149. package/lib/components/Table/subcomponents/HeadCell/HeadCell.tsx +99 -0
  150. package/lib/components/Table/subcomponents/HeadCell/HeadCellContent.tsx +61 -0
  151. package/lib/components/Table/subcomponents/HeadCell/__tests__/HeadCell.test.tsx +137 -0
  152. package/lib/components/Table/subcomponents/HeadCell/__tests__/__snapshots__/HeadCell.test.tsx.snap +110 -0
  153. package/lib/components/Table/subcomponents/Row.tsx +49 -0
  154. package/lib/components/Table/subcomponents/SortIcon.tsx +63 -0
  155. package/lib/components/Table/subcomponents/index.ts +14 -0
  156. package/lib/components/Tabs/Tab.tsx +3 -3
  157. package/lib/components/Tabs/TabContext.tsx +1 -0
  158. package/lib/components/Tabs/Tabs.stories.tsx +9 -3
  159. package/lib/components/Tabs/Tabs.tsx +10 -32
  160. package/lib/components/Tabs/__tests__/Tabs.test.tsx +10 -4
  161. package/lib/components/Tabs/__tests__/__snapshots__/Tabs.test.tsx.snap +32 -32
  162. package/lib/components/Timepicker/Timepicker.stories.tsx +43 -0
  163. package/lib/components/Timepicker/Timepicker.tsx +96 -0
  164. package/lib/components/Timepicker/__tests__/Timepicker.test.tsx +55 -0
  165. package/lib/components/Timepicker/__tests__/__snapshots__/Timepicker.test.tsx.snap +19 -0
  166. package/lib/components/Timepicker/index.tsx +2 -0
  167. package/lib/components/Timepicker/utils/convertDateToTimeString.test.ts +54 -0
  168. package/lib/components/Timepicker/utils/convertDateToTimeString.ts +10 -0
  169. package/lib/components/Timepicker/utils/index.ts +1 -0
  170. package/lib/components/WeekPicker/WeekPicker.tsx +26 -0
  171. package/lib/components/WeekPicker/index.ts +1 -0
  172. package/lib/components/WeekPicker/subcomponents/CustomDatepicker.tsx +298 -0
  173. package/lib/components/WeekPicker/subcomponents/DatepickerInput.tsx +111 -0
  174. package/lib/components/WeekPicker/subcomponents/VisibleField.tsx +126 -0
  175. package/lib/components/WeekPicker/subcomponents/index.ts +3 -0
  176. package/lib/components/index.ts +17 -0
  177. package/lib/hooks/index.ts +2 -0
  178. package/lib/hooks/useFocusTrap.ts +123 -0
  179. package/lib/index.ts +1 -0
  180. package/lib/theme/defaultTheme.ts +7 -0
  181. package/lib/utils/__tests__/capitalise.test.ts +40 -0
  182. package/lib/utils/capitalise.ts +4 -0
  183. package/package.json +1 -1
  184. package/lib/components/Field/__tests__/__snapshots__/Field.test.tsx.snap +0 -300
@@ -20,6 +20,7 @@ declare const blackAndWhite: {
20
20
  white: string;
21
21
  };
22
22
  declare const theme: {
23
+ p0: number;
23
24
  p2: string;
24
25
  p4: string;
25
26
  p6: string;
@@ -35,6 +36,7 @@ declare const theme: {
35
36
  p64: string;
36
37
  p72: string;
37
38
  p80: string;
39
+ m0: number;
38
40
  m2: string;
39
41
  m4: string;
40
42
  m6: string;
@@ -114,7 +116,9 @@ declare const theme: {
114
116
  };
115
117
  link: {
116
118
  default: string;
119
+ secondaryDefault: string;
117
120
  hover: string;
121
+ secondaryHover: string;
118
122
  visited: string;
119
123
  disabled: string;
120
124
  };
@@ -122,6 +126,7 @@ declare const theme: {
122
126
  black: string;
123
127
  grey90: string;
124
128
  grey80: string;
129
+ grey70: string;
125
130
  grey60: string;
126
131
  grey40: string;
127
132
  grey20: string;
@@ -153,6 +158,7 @@ declare const theme: {
153
158
  h80: string;
154
159
  };
155
160
  margin: {
161
+ m0: number;
156
162
  m2: string;
157
163
  m4: string;
158
164
  m6: string;
@@ -170,6 +176,7 @@ declare const theme: {
170
176
  m80: string;
171
177
  };
172
178
  padding: {
179
+ p0: number;
173
180
  p2: string;
174
181
  p4: string;
175
182
  p6: string;
@@ -3,6 +3,7 @@ export declare const ThemeContextProvider: React.FC<{
3
3
  children: ReactNode;
4
4
  }>;
5
5
  declare const useTheme: () => [{
6
+ p0: number;
6
7
  p2: string;
7
8
  p4: string;
8
9
  p6: string;
@@ -18,6 +19,7 @@ declare const useTheme: () => [{
18
19
  p64: string;
19
20
  p72: string;
20
21
  p80: string;
22
+ m0: number;
21
23
  m2: string;
22
24
  m4: string;
23
25
  m6: string;
@@ -97,7 +99,9 @@ declare const useTheme: () => [{
97
99
  };
98
100
  link: {
99
101
  default: string;
102
+ secondaryDefault: string;
100
103
  hover: string;
104
+ secondaryHover: string;
101
105
  visited: string;
102
106
  disabled: string;
103
107
  };
@@ -105,6 +109,7 @@ declare const useTheme: () => [{
105
109
  black: string;
106
110
  grey90: string;
107
111
  grey80: string;
112
+ grey70: string;
108
113
  grey60: string;
109
114
  grey40: string;
110
115
  grey20: string;
@@ -136,6 +141,7 @@ declare const useTheme: () => [{
136
141
  h80: string;
137
142
  };
138
143
  margin: {
144
+ m0: number;
139
145
  m2: string;
140
146
  m4: string;
141
147
  m6: string;
@@ -153,6 +159,7 @@ declare const useTheme: () => [{
153
159
  m80: string;
154
160
  };
155
161
  padding: {
162
+ p0: number;
156
163
  p2: string;
157
164
  p4: string;
158
165
  p6: string;
@@ -244,6 +251,7 @@ declare const useTheme: () => [{
244
251
  custom: (breakpoint: number) => string;
245
252
  };
246
253
  }, import('react').Dispatch<import('react').SetStateAction<{
254
+ p0: number;
247
255
  p2: string;
248
256
  p4: string;
249
257
  p6: string;
@@ -259,6 +267,7 @@ declare const useTheme: () => [{
259
267
  p64: string;
260
268
  p72: string;
261
269
  p80: string;
270
+ m0: number;
262
271
  m2: string;
263
272
  m4: string;
264
273
  m6: string;
@@ -338,7 +347,9 @@ declare const useTheme: () => [{
338
347
  };
339
348
  link: {
340
349
  default: string;
350
+ secondaryDefault: string;
341
351
  hover: string;
352
+ secondaryHover: string;
342
353
  visited: string;
343
354
  disabled: string;
344
355
  };
@@ -346,6 +357,7 @@ declare const useTheme: () => [{
346
357
  black: string;
347
358
  grey90: string;
348
359
  grey80: string;
360
+ grey70: string;
349
361
  grey60: string;
350
362
  grey40: string;
351
363
  grey20: string;
@@ -377,6 +389,7 @@ declare const useTheme: () => [{
377
389
  h80: string;
378
390
  };
379
391
  margin: {
392
+ m0: number;
380
393
  m2: string;
381
394
  m4: string;
382
395
  m6: string;
@@ -394,6 +407,7 @@ declare const useTheme: () => [{
394
407
  m80: string;
395
408
  };
396
409
  padding: {
410
+ p0: number;
397
411
  p2: string;
398
412
  p4: string;
399
413
  p6: string;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ declare const capitalise: (text: string) => string;
2
+ export default capitalise;
@@ -5,6 +5,7 @@ import AlertMessage from './AlertMessage';
5
5
  import AlertTitle from './AlertTitle';
6
6
  import marginsStyle, { MarginProps } from '../common/marginsStyle';
7
7
  import { useTheme } from '../../theme';
8
+ import capitalise from '../../utils/capitalise';
8
9
 
9
10
  export const NAME = 'ucl-uikit-alert';
10
11
 
@@ -38,6 +39,8 @@ const Alert = ({
38
39
  className,
39
40
  ...props
40
41
  }: AlertProps) => {
42
+ const typeName = capitalise(type);
43
+
41
44
  const [theme] = useTheme();
42
45
 
43
46
  const { padding } = theme;
@@ -117,7 +120,10 @@ const Alert = ({
117
120
  role='alert'
118
121
  {...props}
119
122
  >
120
- <IconComp className={iconStyle} />
123
+ <IconComp
124
+ className={iconStyle}
125
+ aria-label={typeName}
126
+ />
121
127
  <div>{children}</div>
122
128
  </div>
123
129
  </AlertContext.Provider>
@@ -7,6 +7,7 @@ exports[`Alert > snapshot: type=error 1`] = `
7
7
  role="alert"
8
8
  >
9
9
  <svg
10
+ aria-label="Error"
10
11
  class="ucl-uikit-icon css-nysdxe"
11
12
  data-testid="ucl-uikit-icon"
12
13
  fill="none"
@@ -61,6 +62,7 @@ exports[`Alert > snapshot: type=info, no title 1`] = `
61
62
  role="alert"
62
63
  >
63
64
  <svg
65
+ aria-label="Info"
64
66
  class="ucl-uikit-icon css-1oh4ubr"
65
67
  data-testid="ucl-uikit-icon"
66
68
  fill="none"
@@ -109,6 +111,7 @@ exports[`Alert > snapshot: type=success 1`] = `
109
111
  role="alert"
110
112
  >
111
113
  <svg
114
+ aria-label="Success"
112
115
  class="ucl-uikit-icon css-4xbsfp"
113
116
  data-testid="ucl-uikit-icon"
114
117
  fill="none"
@@ -152,6 +155,7 @@ exports[`Alert > snapshot: type=warning 1`] = `
152
155
  role="alert"
153
156
  >
154
157
  <svg
158
+ aria-label="Warning"
155
159
  class="ucl-uikit-icon css-dwkbnw"
156
160
  data-testid="ucl-uikit-icon"
157
161
  fill="none"
@@ -0,0 +1,19 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import Badge from './Badge';
3
+
4
+ const meta = {
5
+ title: 'Components/Work in progress/Badge',
6
+ component: Badge,
7
+ parameters: {
8
+ layout: 'centered',
9
+ },
10
+ args: {
11
+ children: 'Badge',
12
+ },
13
+ tags: ['autodocs'],
14
+ } satisfies Meta<typeof Badge>;
15
+
16
+ export default meta;
17
+ type Story = StoryObj<typeof meta>;
18
+
19
+ export const Default: Story = {};
@@ -0,0 +1,48 @@
1
+ import { css, cx } from '@emotion/css';
2
+ import { useTheme } from '../../theme';
3
+
4
+ export interface BadgeProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ testId?: string;
6
+ className?: string;
7
+ }
8
+
9
+ const NAME = 'ucl-uikit-badge';
10
+
11
+ const Badge = ({
12
+ testId = NAME,
13
+ className,
14
+ children,
15
+ ...props
16
+ }: BadgeProps) => {
17
+ const [theme] = useTheme();
18
+
19
+ const baseStyle = css`
20
+ display: inline-flex;
21
+ align-items: center;
22
+ justify-content: center;
23
+ box-sizing: border-box;
24
+ height: 24px;
25
+ padding: ${theme.padding.p8};
26
+ color: ${theme.color.text.secondary};
27
+ background-color: #e4e4e4; // TODO: Add design token
28
+ font-family: ${theme.font.family.primary};
29
+ font-size: ${theme.font.size.f14};
30
+ font-weight: ${theme.font.weight.regular};
31
+ border-radius: ${theme.radius.r4};
32
+ white-space: nowrap;
33
+ `;
34
+
35
+ const style = cx(baseStyle, NAME, className);
36
+
37
+ return (
38
+ <div
39
+ data-testid={testId}
40
+ className={style}
41
+ {...props}
42
+ >
43
+ {children}
44
+ </div>
45
+ );
46
+ };
47
+
48
+ export default Badge;
@@ -0,0 +1,2 @@
1
+ export { default } from './Badge';
2
+ export type { BadgeProps } from './Badge';
@@ -36,7 +36,7 @@ exports[`Breadcrumbs > Snapshot: No props 1`] = `
36
36
  class="css-4ys53n"
37
37
  >
38
38
  <a
39
- class="ucl-link ucl-timetable-breadcrumb ucl-timetable-breadcrumb--inactive css-hr2cbw"
39
+ class="ucl-uikit-base-link ucl-uikit-link ucl-timetable-breadcrumb ucl-timetable-breadcrumb--inactive css-c7kkpi"
40
40
  data-testid="ucl-timetable-breadcrumb"
41
41
  href="/showcase"
42
42
  >
@@ -64,7 +64,7 @@ exports[`Breadcrumbs > Snapshot: No props 1`] = `
64
64
  class="css-4ys53n"
65
65
  >
66
66
  <a
67
- class="ucl-link ucl-timetable-breadcrumb ucl-timetable-breadcrumb--inactive css-hr2cbw"
67
+ class="ucl-uikit-base-link ucl-uikit-link ucl-timetable-breadcrumb ucl-timetable-breadcrumb--inactive css-c7kkpi"
68
68
  data-testid="ucl-timetable-breadcrumb"
69
69
  href="/showcase/breadcrumbs"
70
70
  >
@@ -110,7 +110,7 @@ exports[`Breadcrumbs > snapshot: Custom Test ID 1`] = `
110
110
  class="css-4ys53n"
111
111
  >
112
112
  <a
113
- class="ucl-link ucl-timetable-breadcrumb ucl-timetable-breadcrumb--inactive css-hr2cbw"
113
+ class="ucl-uikit-base-link ucl-uikit-link ucl-timetable-breadcrumb ucl-timetable-breadcrumb--inactive css-c7kkpi"
114
114
  data-testid="custom-testid-2"
115
115
  href="/showcase"
116
116
  >
@@ -138,7 +138,7 @@ exports[`Breadcrumbs > snapshot: Custom Test ID 1`] = `
138
138
  class="css-4ys53n"
139
139
  >
140
140
  <a
141
- class="ucl-link ucl-timetable-breadcrumb ucl-timetable-breadcrumb--inactive css-hr2cbw"
141
+ class="ucl-uikit-base-link ucl-uikit-link ucl-timetable-breadcrumb ucl-timetable-breadcrumb--inactive css-c7kkpi"
142
142
  data-testid="custom-testid-3"
143
143
  href="/showcase/breadcrumbs"
144
144
  >
@@ -11,8 +11,10 @@ import useTheme from '../../theme/useTheme';
11
11
  import buttonPrimaryStyle from './buttonPrimaryStyle';
12
12
  import buttonSecondaryStyle from './buttonSecondaryStyle';
13
13
  import buttonTertiaryStyle from './buttonTertiaryStyle';
14
- import { Spinner, Overlay, Tooltip } from '../';
15
- import marginsStyle from '../common/marginsStyle';
14
+ import Spinner from '../Spinner/Spinner';
15
+ import Overlay from '../Overlay/Overlay';
16
+ import Tooltip from '../Tooltip/Tooltip';
17
+ import marginsStyle, { MarginProps } from '../common/marginsStyle';
16
18
 
17
19
  export const NAME = 'ucl-uikit-button';
18
20
 
@@ -35,6 +37,7 @@ export type ButtonProps<C extends ElementType = 'button'> = {
35
37
  as?: C;
36
38
  ref?: PolymorphicRef<C>;
37
39
  } & ButtonBaseProps &
40
+ MarginProps &
38
41
  Omit<ComponentPropsWithRef<C>, keyof ButtonBaseProps | 'as'>;
39
42
 
40
43
  const Button = <C extends ElementType = 'button'>({
@@ -41,7 +41,6 @@ function createEventsMap(
41
41
  }
42
42
  eventsMap.get(dateKey)!.push(event);
43
43
  });
44
- console.log('Events map created:', eventsMap);
45
44
  return eventsMap;
46
45
  }
47
46
 
@@ -0,0 +1,114 @@
1
+ import { HTMLAttributes, useRef } from 'react';
2
+ import { css, cx } from '@emotion/css';
3
+ import useTheme from '../../theme/useTheme';
4
+ import marginsStyle, { MarginProps } from '../common/marginsStyle';
5
+ import Paragraph from '../Paragraph';
6
+ import { Button, Icon, Link } from '..';
7
+ import { useFocusTrap } from '../../hooks/useFocusTrap';
8
+
9
+ export const NAME = 'ucl-uikit-cookie-notice';
10
+ export const DEFAULT_POLICY_HREF =
11
+ 'https://www.ucl.ac.uk/legal-services/privacy/cookie-policy';
12
+ export const DEFAULT_TEXT =
13
+ 'We use necessary cookies to manage your session and essential site functions. We also use Google Analytics cookies to understand how our site is used. You can accept or reject non-essential cookies.';
14
+
15
+ export interface CookieNoticeBaseProps extends HTMLAttributes<HTMLDivElement> {
16
+ policyHref?: string;
17
+ text?: string;
18
+ onAccept?: () => void;
19
+ onReject?: () => void;
20
+ trapFocus?: boolean;
21
+ testId?: string;
22
+ }
23
+
24
+ export type CookieNoticeProps = CookieNoticeBaseProps & MarginProps;
25
+
26
+ const CookieNotice = ({
27
+ policyHref = DEFAULT_POLICY_HREF,
28
+ text = DEFAULT_TEXT,
29
+ onAccept,
30
+ onReject,
31
+ trapFocus = false,
32
+ testId = NAME,
33
+ className,
34
+ ...props
35
+ }: CookieNoticeProps) => {
36
+ const [theme] = useTheme();
37
+ const containerRef = useRef<HTMLDivElement>(null);
38
+
39
+ useFocusTrap({
40
+ isActive: trapFocus,
41
+ containerRef,
42
+ restoreFocus: true,
43
+ });
44
+
45
+ const baseStyle = css`
46
+ position: fixed;
47
+ left: 0;
48
+ right: 0;
49
+ bottom: 0;
50
+ height: auto;
51
+ background-color: ${theme.color.neutral.grey40};
52
+ padding: ${theme.padding.p20} ${theme.padding.p24};
53
+ `;
54
+
55
+ const style = cx(NAME, baseStyle, marginsStyle(props, theme), className);
56
+
57
+ const buttonsStyle = css`
58
+ margin-top: ${theme.margin.m16};
59
+ display: flex;
60
+ align-items: center;
61
+ gap: ${theme.margin.m8};
62
+ `;
63
+
64
+ const policyLinkStyle = css`
65
+ margin-left: ${theme.margin.m16};
66
+ display: inline-flex;
67
+ color: ${theme.color.text.primary};
68
+ &:visited {
69
+ color: ${theme.color.text.primary};
70
+ }
71
+ `;
72
+
73
+ const policyLinkIconStyle = css`
74
+ margin-top: -1px;
75
+ margin-left: ${theme.margin.m4};
76
+ `;
77
+
78
+ return (
79
+ <div
80
+ ref={containerRef}
81
+ className={style}
82
+ data-testid={testId}
83
+ {...props}
84
+ >
85
+ <Paragraph noMargins>{text}</Paragraph>
86
+
87
+ <div className={buttonsStyle}>
88
+ <Button
89
+ size='small'
90
+ onClick={onAccept}
91
+ >
92
+ Accept
93
+ </Button>
94
+
95
+ <Button
96
+ size='small'
97
+ onClick={onReject}
98
+ >
99
+ Reject
100
+ </Button>
101
+ <Link
102
+ className={policyLinkStyle}
103
+ noVisited
104
+ href={policyHref}
105
+ target='_blank'
106
+ >
107
+ Cookies policy <Icon.ExternalLink className={policyLinkIconStyle} />
108
+ </Link>
109
+ </div>
110
+ </div>
111
+ );
112
+ };
113
+
114
+ export default CookieNotice;
@@ -0,0 +1,2 @@
1
+ export { default } from './CookieNotice';
2
+ export type { CookieNoticeProps } from './CookieNotice';
@@ -7,6 +7,7 @@ import React, {
7
7
  } from 'react';
8
8
  import { css, cx } from '@emotion/css';
9
9
  import useTheme from '../../theme/useTheme';
10
+ import { useFocusTrap } from '../../hooks/useFocusTrap';
10
11
 
11
12
  export const NAME = 'ucl-uikit-base-dialog';
12
13
  export const SMALL_WIDTH = 495;
@@ -19,7 +20,13 @@ export interface BaseDialogProps extends HTMLAttributes<HTMLDialogElement> {
19
20
  modal?: boolean;
20
21
  closeOnClickOutside?: boolean;
21
22
  closeOnClickOutsideStopPropagation?: boolean;
22
- onClose?: (ev: React.MouseEvent) => void;
23
+ nonModalCloseOnEscape?: boolean;
24
+ onClose?: (ev: React.MouseEvent | KeyboardEvent) => void;
25
+ // Focus trap related props
26
+ initialFocusRef?: React.RefObject<HTMLElement>;
27
+ finalFocusRef?: React.RefObject<HTMLElement>;
28
+ disableFocusTrap?: boolean;
29
+ restoreFocus?: boolean;
23
30
  testId?: string;
24
31
  }
25
32
 
@@ -29,10 +36,15 @@ const BaseDialog = ({
29
36
  modal = true,
30
37
  closeOnClickOutside = true,
31
38
  closeOnClickOutsideStopPropagation = true,
39
+ nonModalCloseOnEscape = false,
32
40
  onClose,
33
- testId = NAME,
34
41
  className,
35
42
  children,
43
+ initialFocusRef,
44
+ finalFocusRef,
45
+ disableFocusTrap = false,
46
+ restoreFocus = true,
47
+ testId = NAME,
36
48
  ...props
37
49
  }: BaseDialogProps) => {
38
50
  const width = {
@@ -46,6 +58,15 @@ const BaseDialog = ({
46
58
  const dialogRef = useRef<HTMLDialogElement>(null);
47
59
  const previousActiveElement = useRef<HTMLElement | null>(null);
48
60
 
61
+ // Use the focus trap hook
62
+ useFocusTrap({
63
+ isActive: open && modal && !disableFocusTrap,
64
+ containerRef: dialogRef,
65
+ initialFocusRef,
66
+ finalFocusRef,
67
+ restoreFocus,
68
+ });
69
+
49
70
  const hideBodyScroll = css`
50
71
  overflow: hidden;
51
72
  `;
@@ -75,9 +96,27 @@ const BaseDialog = ({
75
96
  }
76
97
  } else if (!open && dialogElement.hasAttribute('open')) {
77
98
  dialogElement.close();
78
- previousActiveElement.current?.focus();
99
+ // Focus restoration is handled by the focus trap hook for modal dialogs,
100
+ // but we keep the fallback for non-modal dialogs or when focus trap is disabled
101
+ if ((!modal || disableFocusTrap) && restoreFocus) {
102
+ previousActiveElement.current?.focus();
103
+ }
79
104
  }
80
- }, [open, modal]);
105
+ }, [open, modal, disableFocusTrap, restoreFocus]);
106
+
107
+ // Handle Escape key to close dialog
108
+ useEffect(() => {
109
+ if (!open || modal || !nonModalCloseOnEscape) return;
110
+
111
+ const handleKeyDown = (event: KeyboardEvent) => {
112
+ if (event.key === 'Escape' && onClose) {
113
+ onClose(event);
114
+ }
115
+ };
116
+
117
+ document.addEventListener('keydown', handleKeyDown);
118
+ return () => document.removeEventListener('keydown', handleKeyDown);
119
+ }, [open, modal, nonModalCloseOnEscape, onClose]);
81
120
 
82
121
  const handleClick = useCallback(
83
122
  (ev: React.MouseEvent<HTMLDialogElement>) => {
@@ -150,6 +189,7 @@ const BaseDialog = ({
150
189
  data-testid={testId}
151
190
  onClick={handleClick}
152
191
  onClose={handleDialogClose}
192
+ aria-modal={modal ? 'true' : 'false'}
153
193
  {...props}
154
194
  >
155
195
  {children}