uikit-react-public 0.37.2 → 0.38.1

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 (123) hide show
  1. package/dist/components/Alert/Alert.d.ts +1 -1
  2. package/dist/components/Alert/Alert.stories.d.ts +1 -1
  3. package/dist/components/Alert/AlertTitle.d.ts +1 -1
  4. package/dist/components/Datepicker/subcomponents/Panel.d.ts +1 -2
  5. package/dist/components/Overlay/Overlay.d.ts +2 -1
  6. package/dist/components/Overlay/Overlay.stories.d.ts +1 -0
  7. package/dist/components/Toggle/ToggleHandle.d.ts +1 -1
  8. package/dist/components/UclLogoNew/UclLogo.d.ts +2 -1
  9. package/dist/components/UclLogoNew/__tests__/UclLogo.test.d.ts +1 -0
  10. package/dist/components/WeekPicker/__tests__/WeekPicker.test.d.ts +1 -0
  11. package/dist/index.js +3479 -3396
  12. package/dist/theme/dark/darkColour.d.ts +1 -0
  13. package/dist/theme/index.d.ts +1 -1
  14. package/dist/theme/light/lightColour.d.ts +1 -0
  15. package/dist/theme/original/defaultTheme.d.ts +7 -0
  16. package/dist/theme/original/originalColourNewStructure.d.ts +1 -0
  17. package/dist/theme/useTheme.d.ts +12 -0
  18. package/lib/components/Alert/AlertMessage.tsx +5 -4
  19. package/lib/components/Alert/AlertTitle.tsx +6 -8
  20. package/lib/components/AppHeader/AppHeader.stories.tsx +3 -3
  21. package/lib/components/AppHeader/AppHeader.tsx +2 -2
  22. package/lib/components/AppHeader/AppHeaderBottom.tsx +2 -3
  23. package/lib/components/AppHeader/AppHeaderTop.tsx +1 -1
  24. package/lib/components/AppHeader/__tests__/__snapshots__/AppHeader.test.tsx.snap +1 -1
  25. package/lib/components/AppMenu/AppMenuContent.tsx +4 -5
  26. package/lib/components/AppMenu/AppMenuDivider.tsx +5 -6
  27. package/lib/components/AppMenu/AppMenuItem.tsx +6 -6
  28. package/lib/components/AppMenu/__tests__/__snapshots__/AppMenu.test.tsx.snap +1 -1
  29. package/lib/components/Avatar/Avatar.tsx +7 -5
  30. package/lib/components/Avatar/__tests__/__snapshots__/Avatar.test.tsx.snap +18 -18
  31. package/lib/components/Badge/Badge.tsx +12 -12
  32. package/lib/components/Badge/__tests__/Badge.test.tsx +84 -1
  33. package/lib/components/Badge/__tests__/__snapshots__/Badge.test.tsx.snap +2 -2
  34. package/lib/components/Blanket/Blanket.tsx +1 -1
  35. package/lib/components/Blanket/__tests__/__snapshots__/Blanket.test.tsx.snap +1 -1
  36. package/lib/components/Button/__tests__/Button.test.tsx +46 -1
  37. package/lib/components/Button/__tests__/__snapshots__/Button.test.tsx.snap +2 -2
  38. package/lib/components/Button/style/buttonAccentStyle.ts +1 -1
  39. package/lib/components/Button/style/buttonPrimaryDestructiveStyle.ts +1 -1
  40. package/lib/components/Button/style/buttonPrimaryWarningStyle.ts +1 -1
  41. package/lib/components/Button/style/buttonSecondarySubtleStyle.ts +1 -1
  42. package/lib/components/Calendar/Calendar.tsx +1 -0
  43. package/lib/components/Calendar/__tests__/__snapshots__/Calendar.test.tsx.snap +17 -17
  44. package/lib/components/Calendar/subcomponents/AcademicWeek.tsx +0 -1
  45. package/lib/components/Calendar/subcomponents/Day.tsx +2 -2
  46. package/lib/components/Chip/Chip.tsx +7 -8
  47. package/lib/components/Chip/__tests__/__snapshots__/Chip.test.tsx.snap +5 -5
  48. package/lib/components/CookieNotice/CookieNotice.tsx +3 -3
  49. package/lib/components/Datepicker/__tests__/Datepicker.test.tsx +58 -1
  50. package/lib/components/Datepicker/__tests__/__snapshots__/Datepicker.test.tsx.snap +6 -6
  51. package/lib/components/Datepicker/subcomponents/CustomDatepicker.tsx +32 -11
  52. package/lib/components/Datepicker/subcomponents/DatepickerInput.tsx +7 -6
  53. package/lib/components/Datepicker/subcomponents/Panel.tsx +3 -21
  54. package/lib/components/Datepicker/subcomponents/VisibleField.tsx +6 -8
  55. package/lib/components/Dialog/BaseDialog.tsx +3 -3
  56. package/lib/components/Divider/Divider.tsx +5 -3
  57. package/lib/components/FileInput/FileInput.tsx +1 -1
  58. package/lib/components/FileInput/__tests__/__snapshots__/FileInput.test.tsx.snap +2 -2
  59. package/lib/components/Footer/Footer.tsx +17 -17
  60. package/lib/components/Footer/FooterNavLink.tsx +3 -3
  61. package/lib/components/Footer/SocialLink.tsx +3 -3
  62. package/lib/components/Footer/__tests__/__snapshots__/Footer.test.tsx.snap +55 -55
  63. package/lib/components/FooterNew/BackToTop.tsx +1 -1
  64. package/lib/components/FooterNew/FooterColumn.tsx +1 -2
  65. package/lib/components/FooterNew/FooterNavLink.tsx +6 -5
  66. package/lib/components/FooterNew/LegalAndCopyright.tsx +15 -15
  67. package/lib/components/FooterNew/LogoAddressAndSocial.tsx +8 -6
  68. package/lib/components/FooterNew/SocialLink.tsx +4 -4
  69. package/lib/components/FooterNew/__tests__/__snapshots__/Footer.test.tsx.snap +44 -44
  70. package/lib/components/Header/Header.tsx +3 -3
  71. package/lib/components/Header/__tests__/__snapshots__/Header.test.tsx.snap +2 -2
  72. package/lib/components/HeaderDraft/HeaderBottomBreadcrumbs.tsx +3 -4
  73. package/lib/components/HeaderDraft/HeaderBottomHeadingAndAvatar.tsx +7 -7
  74. package/lib/components/HeaderDraft/HeaderBreadcrumb.tsx +4 -4
  75. package/lib/components/HeaderDraft/HeaderDraft.tsx +7 -7
  76. package/lib/components/HeaderDraft/__tests__/__snapshots__/Header.test.tsx.snap +5 -5
  77. package/lib/components/HeaderNew/Header.tsx +2 -2
  78. package/lib/components/HeaderNew/__tests__/__snapshots__/Header.test.tsx.snap +2 -2
  79. package/lib/components/Input/Input.tsx +6 -6
  80. package/lib/components/Input/__tests__/__snapshots__/Input.test.tsx.snap +4 -4
  81. package/lib/components/Label/Label.tsx +2 -2
  82. package/lib/components/Label/__tests__/__snapshots__/Label.test.tsx.snap +1 -1
  83. package/lib/components/Layout/Layout.stories.tsx +12 -12
  84. package/lib/components/Link/Link.tsx +4 -4
  85. package/lib/components/Menu/MenuContent.tsx +3 -3
  86. package/lib/components/Menu/MenuItem.tsx +10 -8
  87. package/lib/components/Menu/MenuSection.tsx +1 -1
  88. package/lib/components/Modal/Modal.tsx +5 -15
  89. package/lib/components/Modal/__tests__/__snapshots__/Modal.test.tsx.snap +2 -2
  90. package/lib/components/NativeDatepicker/NativeDatepicker.tsx +9 -7
  91. package/lib/components/Overlay/Overlay.tsx +17 -5
  92. package/lib/components/Radio/Radio.tsx +13 -4
  93. package/lib/components/Radio/__tests__/__snapshots__/Radio.test.tsx.snap +3 -3
  94. package/lib/components/Search/Search.tsx +2 -2
  95. package/lib/components/Search/__tests__/__snapshots__/Search.test.tsx.snap +2 -2
  96. package/lib/components/Select/subcomponents/CustomSelect.tsx +4 -4
  97. package/lib/components/Spinner/Spinner.stories.tsx +3 -3
  98. package/lib/components/Spinner/Spinner.tsx +1 -1
  99. package/lib/components/Table/__tests__/__snapshots__/Table.test.tsx.snap +3 -3
  100. package/lib/components/Table/subcomponents/Head.tsx +2 -2
  101. package/lib/components/Table/subcomponents/Row.tsx +1 -1
  102. package/lib/components/Textarea/Textarea.tsx +7 -8
  103. package/lib/components/Textarea/__tests__/__snapshots__/Textarea.test.tsx.snap +4 -4
  104. package/lib/components/Timepicker/Timepicker.tsx +6 -4
  105. package/lib/components/Toggle/Toggle.tsx +4 -2
  106. package/lib/components/Toggle/ToggleHandle.tsx +4 -2
  107. package/lib/components/Tooltip/Tooltip.tsx +8 -5
  108. package/lib/components/Tooltip/__tests__/__snapshots__/tooltip.test.tsx.snap +2 -2
  109. package/lib/components/UclLogo/UclLogoNegativeSpace.tsx +7 -3
  110. package/lib/components/UclLogoNew/UclLogo.tsx +8 -9
  111. package/lib/components/UclLogoNew/__tests__/UclLogo.test.tsx +41 -0
  112. package/lib/components/WeekPicker/__tests__/WeekPicker.test.tsx +36 -0
  113. package/lib/components/WeekPicker/subcomponents/CustomDatepicker.tsx +27 -11
  114. package/lib/components/WeekPicker/subcomponents/DatepickerInput.tsx +6 -6
  115. package/lib/components/WeekPicker/subcomponents/VisibleField.tsx +9 -9
  116. package/lib/theme/dark/darkColour.ts +2 -1
  117. package/lib/theme/dark/darkTheme.ts +8 -1
  118. package/lib/theme/index.ts +1 -0
  119. package/lib/theme/light/lightColour.ts +2 -1
  120. package/lib/theme/light/lightTheme.ts +7 -0
  121. package/lib/theme/original/defaultTheme.ts +10 -0
  122. package/lib/theme/original/originalColourNewStructure.ts +2 -1
  123. package/package.json +2 -2
@@ -75,7 +75,7 @@ exports[`Badge > snapshot: variant=disabled 1`] = `
75
75
 
76
76
  exports[`Badge > snapshot: variant=info with icon 1`] = `
77
77
  <span
78
- class="ucl-uikit-badge css-11fgrnl"
78
+ class="ucl-uikit-badge css-37ncyr"
79
79
  data-testid="ucl-uikit-badge"
80
80
  >
81
81
  <svg
@@ -108,7 +108,7 @@ exports[`Badge > snapshot: variant=info with icon 1`] = `
108
108
 
109
109
  exports[`Badge > snapshot: variant=info-subtle 1`] = `
110
110
  <span
111
- class="ucl-uikit-badge css-1t6kxcm"
111
+ class="ucl-uikit-badge css-1x6sfca"
112
112
  data-testid="ucl-uikit-badge"
113
113
  >
114
114
  Info subtle
@@ -35,7 +35,7 @@ const Blanket = forwardRef<Ref, BlanketProps>(
35
35
  outline: 0;
36
36
  user-select: none;
37
37
  pointer-events: auto;
38
- background-color: ${theme.color.overlay};
38
+ background-color: ${theme.colour.surface.backdrop};
39
39
  `;
40
40
 
41
41
  const style = cx(NAME, baseStyle, className);
@@ -4,7 +4,7 @@ exports[`<Blanket> Component > matches snapshot with no props 1`] = `
4
4
  <div
5
5
  aria-hidden="true"
6
6
  aria-label="Backdrop overlay, click to close modal"
7
- class="ucl-blanket css-gsa5om"
7
+ class="ucl-blanket css-1kp3xax"
8
8
  data-testid="ucl-blanket"
9
9
  />
10
10
  `;
@@ -3,7 +3,16 @@ import { render, screen } from '@testing-library/react';
3
3
  import userEvent from '@testing-library/user-event';
4
4
  import Button from '../Button';
5
5
  import Icon from '../../Icon';
6
- import { ThemeContextProvider } from '../../../theme/useTheme';
6
+ import { darkTheme, ThemeContextProvider } from '../../../theme';
7
+
8
+ const hexToRgb = (hex: string) => {
9
+ const value = hex.replace('#', '');
10
+ const red = parseInt(value.slice(0, 2), 16);
11
+ const green = parseInt(value.slice(2, 4), 16);
12
+ const blue = parseInt(value.slice(4, 6), 16);
13
+
14
+ return `rgb(${red}, ${green}, ${blue})`;
15
+ };
7
16
 
8
17
  describe('Button', () => {
9
18
  test('snapshot: no props', () => {
@@ -275,4 +284,40 @@ describe('Button', () => {
275
284
 
276
285
  expect(renderResult.container.firstChild).toMatchSnapshot();
277
286
  });
287
+
288
+ test.each([
289
+ ['accent', darkTheme.colour.text.inverse],
290
+ ['primary-destructive', darkTheme.colour.text.inverse],
291
+ ['primary-warning', darkTheme.colour.text.caution],
292
+ ] as const)(
293
+ 'uses readable semantic text colour for dark %s variant',
294
+ (variant, expectedColour) => {
295
+ render(
296
+ <ThemeContextProvider theme='dark'>
297
+ <Button variant={variant}>{variant}</Button>
298
+ </ThemeContextProvider>
299
+ );
300
+
301
+ expect(getComputedStyle(screen.getByRole('button')).color).toBe(
302
+ hexToRgb(expectedColour)
303
+ );
304
+ }
305
+ );
306
+
307
+ test('uses the dark theme focus ring', () => {
308
+ render(
309
+ <ThemeContextProvider theme='dark'>
310
+ <Button>Focused</Button>
311
+ </ThemeContextProvider>
312
+ );
313
+
314
+ const cssText = document.head.textContent?.replace(/\s/g, '');
315
+ const expectedFocusShadow =
316
+ `0 0 0 2px ${darkTheme.colour.border.inverse}, ` +
317
+ `0 0 0 4px ${darkTheme.colour.border.focus}`;
318
+
319
+ expect(cssText).toContain(
320
+ `box-shadow:${expectedFocusShadow.replace(/\s/g, '')}`
321
+ );
322
+ });
278
323
  });
@@ -3,7 +3,7 @@
3
3
  exports[`Button > maps legacy destructive prop to destructive variants 1`] = `
4
4
  <button
5
5
  aria-disabled="false"
6
- class="ucl-uikit-button css-ay3o9w"
6
+ class="ucl-uikit-button css-rl1hmu"
7
7
  data-testid="ucl-uikit-button"
8
8
  >
9
9
  Delete
@@ -83,7 +83,7 @@ exports[`Button > snapshot: testId prop 1`] = `
83
83
  exports[`Button > snapshot: variant prop 1`] = `
84
84
  <button
85
85
  aria-disabled="false"
86
- class="ucl-uikit-button css-vpw5wr"
86
+ class="ucl-uikit-button css-ub9awk"
87
87
  data-testid="ucl-uikit-button"
88
88
  />
89
89
  `;
@@ -18,7 +18,7 @@ const buttonAccentStyle = (
18
18
 
19
19
  const baseStyle = css`
20
20
  background-color: ${bgColour};
21
- color: ${theme.colour.text.brandInverse};
21
+ color: ${theme.colour.text.inverse};
22
22
  `;
23
23
 
24
24
  const selectedStyle = css`
@@ -19,7 +19,7 @@ const buttonPrimaryDestructiveStyle = (
19
19
 
20
20
  const baseStyle = css`
21
21
  background-color: ${bgColour};
22
- color: ${theme.colour.text.brandInverse};
22
+ color: ${theme.colour.text.inverse};
23
23
  `;
24
24
 
25
25
  const selectedStyle = css`
@@ -12,7 +12,7 @@ const buttonPrimaryWarningStyle = (
12
12
  colour: { fill, text },
13
13
  } = theme;
14
14
 
15
- const textColour = text.default;
15
+ const textColour = text.caution;
16
16
  const bgColour = fill.caution;
17
17
  const bgHoverColour = fill.cautionHover;
18
18
  const bgActiveColour = fill.cautionPressed;
@@ -28,7 +28,7 @@ const buttonSecondarySubtleStyle = (
28
28
  const adjustedPaddingPx = paddingPx + 1;
29
29
 
30
30
  const baseStyle = css`
31
- background-color: ${theme.color.neutral.white};
31
+ background-color: ${theme.colour.fill.inverse};
32
32
  color: ${textColour};
33
33
  border: ${theme.border.b1} solid ${borderColour};
34
34
  padding: 0 ${adjustedPaddingPx}px;
@@ -78,6 +78,7 @@ const Calendar = ({
78
78
  border: 1px solid ${theme.colour.border.subtle}; // todo: incorrect border colour / need a new border colour defined
79
79
  padding: 16px;
80
80
  background-color: ${theme.colour.fill.inverse};
81
+ color: ${theme.colour.text.default};
81
82
  `;
82
83
 
83
84
  const innerContainerStyle = css`
@@ -2,7 +2,7 @@
2
2
 
3
3
  exports[`Calendar > Snapshot: no date provided 1`] = `
4
4
  <div
5
- class="ucl-uikit-calendar css-1qlai2s"
5
+ class="ucl-uikit-calendar css-o3t9du"
6
6
  data-testid="ucl-uikit-calendar"
7
7
  >
8
8
  <div
@@ -110,7 +110,7 @@ exports[`Calendar > Snapshot: no date provided 1`] = `
110
110
  data-testid="ucl-uikit-calendar__day"
111
111
  >
112
112
  <div
113
- class="css-53a08n"
113
+ class="css-l50tvc"
114
114
  >
115
115
  24
116
116
  </div>
@@ -123,7 +123,7 @@ exports[`Calendar > Snapshot: no date provided 1`] = `
123
123
  data-testid="ucl-uikit-calendar__day"
124
124
  >
125
125
  <div
126
- class="css-53a08n"
126
+ class="css-l50tvc"
127
127
  >
128
128
  25
129
129
  </div>
@@ -136,7 +136,7 @@ exports[`Calendar > Snapshot: no date provided 1`] = `
136
136
  data-testid="ucl-uikit-calendar__day"
137
137
  >
138
138
  <div
139
- class="css-53a08n"
139
+ class="css-l50tvc"
140
140
  >
141
141
  26
142
142
  </div>
@@ -149,7 +149,7 @@ exports[`Calendar > Snapshot: no date provided 1`] = `
149
149
  data-testid="ucl-uikit-calendar__day"
150
150
  >
151
151
  <div
152
- class="css-53a08n"
152
+ class="css-l50tvc"
153
153
  >
154
154
  27
155
155
  </div>
@@ -162,7 +162,7 @@ exports[`Calendar > Snapshot: no date provided 1`] = `
162
162
  data-testid="ucl-uikit-calendar__day"
163
163
  >
164
164
  <div
165
- class="css-53a08n"
165
+ class="css-l50tvc"
166
166
  >
167
167
  28
168
168
  </div>
@@ -578,7 +578,7 @@ exports[`Calendar > Snapshot: no date provided 1`] = `
578
578
  data-testid="ucl-uikit-calendar__day"
579
579
  >
580
580
  <div
581
- class="css-53a08n"
581
+ class="css-l50tvc"
582
582
  >
583
583
  1
584
584
  </div>
@@ -591,7 +591,7 @@ exports[`Calendar > Snapshot: no date provided 1`] = `
591
591
  data-testid="ucl-uikit-calendar__day"
592
592
  >
593
593
  <div
594
- class="css-53a08n"
594
+ class="css-l50tvc"
595
595
  >
596
596
  2
597
597
  </div>
@@ -604,7 +604,7 @@ exports[`Calendar > Snapshot: no date provided 1`] = `
604
604
  data-testid="ucl-uikit-calendar__day"
605
605
  >
606
606
  <div
607
- class="css-53a08n"
607
+ class="css-l50tvc"
608
608
  >
609
609
  3
610
610
  </div>
@@ -617,7 +617,7 @@ exports[`Calendar > Snapshot: no date provided 1`] = `
617
617
  data-testid="ucl-uikit-calendar__day"
618
618
  >
619
619
  <div
620
- class="css-53a08n"
620
+ class="css-l50tvc"
621
621
  >
622
622
  4
623
623
  </div>
@@ -630,7 +630,7 @@ exports[`Calendar > Snapshot: no date provided 1`] = `
630
630
  data-testid="ucl-uikit-calendar__day"
631
631
  >
632
632
  <div
633
- class="css-53a08n"
633
+ class="css-l50tvc"
634
634
  >
635
635
  5
636
636
  </div>
@@ -643,7 +643,7 @@ exports[`Calendar > Snapshot: no date provided 1`] = `
643
643
  data-testid="ucl-uikit-calendar__day"
644
644
  >
645
645
  <div
646
- class="css-53a08n"
646
+ class="css-l50tvc"
647
647
  >
648
648
  6
649
649
  </div>
@@ -658,7 +658,7 @@ exports[`Calendar > Snapshot: no date provided 1`] = `
658
658
 
659
659
  exports[`Calendar > Snapshot: with date provided 1`] = `
660
660
  <div
661
- class="ucl-uikit-calendar css-1qlai2s"
661
+ class="ucl-uikit-calendar css-o3t9du"
662
662
  data-testid="ucl-uikit-calendar"
663
663
  >
664
664
  <div
@@ -766,7 +766,7 @@ exports[`Calendar > Snapshot: with date provided 1`] = `
766
766
  data-testid="ucl-uikit-calendar__day"
767
767
  >
768
768
  <div
769
- class="css-53a08n"
769
+ class="css-l50tvc"
770
770
  >
771
771
  30
772
772
  </div>
@@ -779,7 +779,7 @@ exports[`Calendar > Snapshot: with date provided 1`] = `
779
779
  data-testid="ucl-uikit-calendar__day"
780
780
  >
781
781
  <div
782
- class="css-53a08n"
782
+ class="css-l50tvc"
783
783
  >
784
784
  31
785
785
  </div>
@@ -1195,7 +1195,7 @@ exports[`Calendar > Snapshot: with date provided 1`] = `
1195
1195
  data-testid="ucl-uikit-calendar__day"
1196
1196
  >
1197
1197
  <div
1198
- class="css-53a08n"
1198
+ class="css-l50tvc"
1199
1199
  >
1200
1200
  1
1201
1201
  </div>
@@ -1208,7 +1208,7 @@ exports[`Calendar > Snapshot: with date provided 1`] = `
1208
1208
  data-testid="ucl-uikit-calendar__day"
1209
1209
  >
1210
1210
  <div
1211
- class="css-53a08n"
1211
+ class="css-l50tvc"
1212
1212
  >
1213
1213
  2
1214
1214
  </div>
@@ -18,7 +18,6 @@ const AcademicWeek = ({ weekNumber }: AcademicWeekProps) => {
18
18
  height: 40px;
19
19
  font-family: ${theme.font.family.primary};
20
20
  font-size: ${theme.font.size.f14};
21
- /* color: #6345a5; */
22
21
  color: ${theme.colour.text.brandPrimary};
23
22
  `;
24
23
 
@@ -71,7 +71,7 @@ const Day = ({
71
71
 
72
72
  &:hover {
73
73
  background-color: ${
74
- isSelected ? theme.color.neutral.grey10 : theme.color.neutral.white
74
+ isSelected ? theme.colour.fill.disabled : theme.colour.fill.inverse
75
75
  };
76
76
  }
77
77
  `
@@ -86,7 +86,7 @@ const Day = ({
86
86
  ${
87
87
  !isInCurrentMonth &&
88
88
  css`
89
- color: ${theme.color.neutral.grey40};
89
+ color: ${theme.colour.text.tertiary};
90
90
  `
91
91
  }
92
92
  ${
@@ -48,17 +48,16 @@ const Chip = forwardRef<Ref, ChipProps>(
48
48
  min-height: 32px;
49
49
  width: fit-content;
50
50
  padding: ${theme.margin.m4} ${theme.margin.m16};
51
- border: ${theme.border.b1} solid ${theme.colour.icon.brand};
51
+ border: ${theme.border.b1} solid ${theme.colour.border.brand};
52
52
  border-radius: 16px;
53
53
  outline: none;
54
54
  box-sizing: border-box;
55
- color: ${theme.colour.icon.inverse};
56
55
  transition:
57
56
  background-color 0.15s ease-out,
58
57
  border-color 0.15s ease-out;
59
58
  cursor: pointer;
60
- background-color: ${theme.colour.icon.inverse};
61
- color: ${theme.colour.icon.brand};
59
+ background-color: ${theme.colour.fill.default};
60
+ color: ${theme.colour.text.brand};
62
61
 
63
62
  &:hover {
64
63
  background-color: ${theme.colour.fill.brandSubtleHover};
@@ -69,13 +68,13 @@ const Chip = forwardRef<Ref, ChipProps>(
69
68
  }
70
69
 
71
70
  &:has(input:checked) {
72
- background-color: ${theme.colour.icon.brandSelectedOnBgFill};
73
- border-color: ${theme.colour.icon.brandSelectedOnBgFill};
74
- color: ${theme.colour.icon.inverse};
71
+ background-color: ${theme.colour.fill.brandPressed};
72
+ border-color: ${theme.colour.border.focus};
73
+ color: ${theme.colour.text.inverse};
75
74
  }
76
75
 
77
76
  &:has(input:checked):hover {
78
- background-color: ${theme.colour.icon.brandSelectedOnBgFill};
77
+ background-color: ${theme.colour.fill.brandPressed};
79
78
  }
80
79
 
81
80
  &:has(input:disabled),
@@ -2,7 +2,7 @@
2
2
 
3
3
  exports[`Chip > snapshot: checked prop 1`] = `
4
4
  <label
5
- class="ucl-uikit-chip css-1j50qe4"
5
+ class="ucl-uikit-chip css-cngnam"
6
6
  >
7
7
  <span
8
8
  class="ucl-uikit-base-checkbox css-1mmc74g"
@@ -53,7 +53,7 @@ exports[`Chip > snapshot: checked prop 1`] = `
53
53
 
54
54
  exports[`Chip > snapshot: disabled and checked props 1`] = `
55
55
  <label
56
- class="ucl-uikit-chip css-1j50qe4"
56
+ class="ucl-uikit-chip css-cngnam"
57
57
  >
58
58
  <span
59
59
  class="ucl-uikit-base-checkbox css-lp1eko"
@@ -105,7 +105,7 @@ exports[`Chip > snapshot: disabled and checked props 1`] = `
105
105
 
106
106
  exports[`Chip > snapshot: disabled prop 1`] = `
107
107
  <label
108
- class="ucl-uikit-chip css-1j50qe4"
108
+ class="ucl-uikit-chip css-cngnam"
109
109
  >
110
110
  <span
111
111
  class="ucl-uikit-base-checkbox css-lp1eko"
@@ -156,7 +156,7 @@ exports[`Chip > snapshot: disabled prop 1`] = `
156
156
 
157
157
  exports[`Chip > snapshot: no props 1`] = `
158
158
  <label
159
- class="ucl-uikit-chip css-1j50qe4"
159
+ class="ucl-uikit-chip css-cngnam"
160
160
  >
161
161
  <span
162
162
  class="ucl-uikit-base-checkbox css-1mmc74g"
@@ -206,7 +206,7 @@ exports[`Chip > snapshot: no props 1`] = `
206
206
 
207
207
  exports[`Chip > snapshot: testId prop 1`] = `
208
208
  <label
209
- class="ucl-uikit-chip css-1j50qe4"
209
+ class="ucl-uikit-chip css-cngnam"
210
210
  >
211
211
  <span
212
212
  class="ucl-uikit-base-checkbox css-1mmc74g"
@@ -48,7 +48,7 @@ const CookieNotice = ({
48
48
  right: 0;
49
49
  bottom: 0;
50
50
  height: auto;
51
- background-color: ${theme.color.neutral.grey40};
51
+ background-color: ${theme.colour.surface.secondary};
52
52
  padding: ${theme.padding.p20} ${theme.padding.p24};
53
53
  `;
54
54
 
@@ -64,9 +64,9 @@ const CookieNotice = ({
64
64
  const policyLinkStyle = css`
65
65
  margin-left: ${theme.margin.m16};
66
66
  display: inline-flex;
67
- color: ${theme.color.text.primary};
67
+ color: ${theme.colour.text.default};
68
68
  &:visited {
69
- color: ${theme.color.text.primary};
69
+ color: ${theme.colour.text.default};
70
70
  }
71
71
  `;
72
72
 
@@ -2,7 +2,7 @@ import { useState } from 'react';
2
2
  import { describe, test, expect, vi, beforeEach } from 'vitest';
3
3
  import { render, screen, fireEvent } from '@testing-library/react';
4
4
  import userEvent from '@testing-library/user-event';
5
- import { ThemeContextProvider } from '../../../theme';
5
+ import { ThemeContextProvider, darkTheme } from '../../../theme';
6
6
  import Datepicker from '..';
7
7
  import announce from '../../../utils/announce';
8
8
 
@@ -11,6 +11,15 @@ vi.mock('../../../utils/announce');
11
11
 
12
12
  const defaultTestId = 'ucl-uikit-datepicker';
13
13
 
14
+ const hexToRgb = (hex: string) => {
15
+ const value = hex.replace('#', '');
16
+ const red = parseInt(value.slice(0, 2), 16);
17
+ const green = parseInt(value.slice(2, 4), 16);
18
+ const blue = parseInt(value.slice(4, 6), 16);
19
+
20
+ return `rgb(${red}, ${green}, ${blue})`;
21
+ };
22
+
14
23
  const customRender = (ui: React.ReactElement) => {
15
24
  return render(ui, {
16
25
  wrapper: ({ children }) => (
@@ -105,6 +114,30 @@ describe('Datepicker', () => {
105
114
  expect(input).toHaveValue('10/03/2025');
106
115
  });
107
116
 
117
+ test('uses the dark theme colours for the visible field and input', () => {
118
+ render(
119
+ <ThemeContextProvider theme='dark'>
120
+ <Datepicker />
121
+ </ThemeContextProvider>
122
+ );
123
+
124
+ const expectedBackground = hexToRgb(darkTheme.colour.fill.inverse);
125
+ const expectedForeground = hexToRgb(darkTheme.colour.text.default);
126
+
127
+ expect(
128
+ getComputedStyle(
129
+ screen.getByTestId('ucl-uikit-datepicker__visible-field')
130
+ ).backgroundColor
131
+ ).toBe(expectedBackground);
132
+ expect(
133
+ getComputedStyle(screen.getByTestId('ucl-uikit-datepicker__input'))
134
+ .backgroundColor
135
+ ).toBe(expectedBackground);
136
+ expect(
137
+ getComputedStyle(screen.getByTestId('ucl-uikit-datepicker__input')).color
138
+ ).toBe(expectedForeground);
139
+ });
140
+
108
141
  test('Calendar appears on input focus', async () => {
109
142
  customRender(<Datepicker />);
110
143
  const input = screen.getByTestId('ucl-uikit-datepicker__input');
@@ -116,6 +149,30 @@ describe('Datepicker', () => {
116
149
 
117
150
  // Calendar should now be visible
118
151
  expect(screen.getByTestId('ucl-uikit-calendar')).toBeInTheDocument();
152
+ const panel = screen.getByTestId('ucl-uikit-datepicker__panel');
153
+ expect(panel.parentElement).toHaveClass('ucl-overlay');
154
+ });
155
+
156
+ test('Panel escapes a containing dialog via fixed positioning', () => {
157
+ customRender(
158
+ <dialog open>
159
+ <Datepicker />
160
+ </dialog>
161
+ );
162
+ const input = screen.getByTestId('ucl-uikit-datepicker__input');
163
+ fireEvent.focus(input);
164
+
165
+ const panel = screen.getByTestId('ucl-uikit-datepicker__panel');
166
+ expect(panel.parentElement).toHaveStyle({ position: 'fixed' });
167
+ });
168
+
169
+ test('Panel uses absolute positioning outside of a dialog', () => {
170
+ customRender(<Datepicker />);
171
+ const input = screen.getByTestId('ucl-uikit-datepicker__input');
172
+ fireEvent.focus(input);
173
+
174
+ const panel = screen.getByTestId('ucl-uikit-datepicker__panel');
175
+ expect(panel.parentElement).toHaveStyle({ position: 'absolute' });
119
176
  });
120
177
 
121
178
  test('value after minDate is set to null automatically', () => {
@@ -6,11 +6,11 @@ exports[`Datepicker > Snapshot: no date provided 1`] = `
6
6
  data-testid="ucl-uikit-datepicker"
7
7
  >
8
8
  <div
9
- class="ucl-uikit-datepicker__visible-field css-e3vwui"
9
+ class="ucl-uikit-datepicker__visible-field css-j8089z"
10
10
  data-testid="ucl-uikit-datepicker__visible-field"
11
11
  >
12
12
  <input
13
- class="ucl-uikit-datepicker__input css-1k3pose"
13
+ class="ucl-uikit-datepicker__input css-1xl7vs4"
14
14
  data-testid="ucl-uikit-datepicker__input"
15
15
  inputmode="numeric"
16
16
  placeholder="DD/MM/YYYY"
@@ -25,7 +25,7 @@ exports[`Datepicker > Snapshot: no date provided 1`] = `
25
25
  type="button"
26
26
  >
27
27
  <svg
28
- class="ucl-uikit-icon css-1u4xgls"
28
+ class="ucl-uikit-icon css-19m0hpd"
29
29
  data-testid="ucl-uikit-icon"
30
30
  fill="none"
31
31
  focusable="false"
@@ -61,11 +61,11 @@ exports[`Datepicker > Snapshot: with date provided 1`] = `
61
61
  data-testid="ucl-uikit-datepicker"
62
62
  >
63
63
  <div
64
- class="ucl-uikit-datepicker__visible-field css-e3vwui"
64
+ class="ucl-uikit-datepicker__visible-field css-j8089z"
65
65
  data-testid="ucl-uikit-datepicker__visible-field"
66
66
  >
67
67
  <input
68
- class="ucl-uikit-datepicker__input css-1k3pose"
68
+ class="ucl-uikit-datepicker__input css-1xl7vs4"
69
69
  data-testid="ucl-uikit-datepicker__input"
70
70
  inputmode="numeric"
71
71
  placeholder="DD/MM/YYYY"
@@ -80,7 +80,7 @@ exports[`Datepicker > Snapshot: with date provided 1`] = `
80
80
  type="button"
81
81
  >
82
82
  <svg
83
- class="ucl-uikit-icon css-1u4xgls"
83
+ class="ucl-uikit-icon css-19m0hpd"
84
84
  data-testid="ucl-uikit-icon"
85
85
  fill="none"
86
86
  focusable="false"
@@ -2,8 +2,10 @@ import { useRef, useEffect, useState, useCallback } from 'react';
2
2
  import { css, cx } from '@emotion/css';
3
3
  import { VisibleField, Panel } from '.';
4
4
  import { Calendar } from '../..';
5
+ import Overlay from '../../Overlay';
5
6
  import { parseInputValue } from '../utils';
6
7
  import announce from '../../../utils/announce';
8
+ import { useTheme } from '../../../theme';
7
9
  import type { DatepickerValue } from '../Datepicker.types';
8
10
  import type { CalendarEvent, AcademicWeek } from '../../Calendar';
9
11
  import type { InputProps } from './DatepickerInput';
@@ -57,7 +59,9 @@ const CustomDatepicker = ({
57
59
  const effectiveInputRef = inputRef || internalInputRef;
58
60
  const restoreFocusAfterClearRef = useRef(false);
59
61
 
62
+ const [theme] = useTheme();
60
63
  const [panelOpen, setPanelOpen] = useState(false);
64
+ const overlayViewportPadding = parseFloat(theme.margin.m32);
61
65
 
62
66
  // Derived props (tidier than using `date?.getDate()`, etc, everywhere.)
63
67
  const day = value?.getDate().toString().padStart(2, '0') ?? '';
@@ -233,17 +237,34 @@ const CustomDatepicker = ({
233
237
  inputProps={inputProps}
234
238
  />
235
239
  {panelOpen && (
236
- <Panel>
237
- <Calendar
238
- pickedDate={value}
239
- onDatePick={handlePickCalendarDate}
240
- minDate={minDate}
241
- maxDate={maxDate}
242
- events={events}
243
- showAcademicWeeks={showAcademicWeeks}
244
- academicWeeks={academicWeeks}
245
- />
246
- </Panel>
240
+ <Overlay
241
+ reference={effectiveRef}
242
+ placement='bottom-start'
243
+ // Escape the dialog's bounds via `fixed` positioning when it's too
244
+ // small to fit the panel, rather than squeezing/clipping it to fit.
245
+ strategy={
246
+ effectiveRef.current?.closest('dialog') ? 'fixed' : 'absolute'
247
+ }
248
+ flip={{ padding: overlayViewportPadding }}
249
+ shift={{
250
+ padding: overlayViewportPadding,
251
+ mainAxis: false,
252
+ crossAxis: true,
253
+ }}
254
+ offset={8}
255
+ >
256
+ <Panel>
257
+ <Calendar
258
+ pickedDate={value}
259
+ onDatePick={handlePickCalendarDate}
260
+ minDate={minDate}
261
+ maxDate={maxDate}
262
+ events={events}
263
+ showAcademicWeeks={showAcademicWeeks}
264
+ academicWeeks={academicWeeks}
265
+ />
266
+ </Panel>
267
+ </Overlay>
247
268
  )}
248
269
  </div>
249
270
  );