uikit-react-public 0.44.5 → 0.45.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 (33) hide show
  1. package/dist/components/CookiesNotice/CookieSettings.d.ts +16 -0
  2. package/dist/components/CookiesNotice/CookiesNotice.d.ts +26 -0
  3. package/dist/components/CookiesNotice/CookiesNotice.stories.d.ts +13 -0
  4. package/dist/components/CookiesNotice/__tests__/CookiesNotice.test.d.ts +1 -0
  5. package/dist/components/CookiesNotice/defaults.d.ts +6 -0
  6. package/dist/components/CookiesNotice/index.d.ts +3 -0
  7. package/dist/components/CookiesNotice/types.d.ts +12 -0
  8. package/dist/components/Paragraph/Paragraph.d.ts +1 -1
  9. package/dist/components/Text/Text.d.ts +1 -1
  10. package/dist/components/Text/__tests__/Text.test.d.ts +1 -0
  11. package/dist/components/index.d.ts +3 -0
  12. package/dist/index.js +6528 -5923
  13. package/lib/components/Button/Button.tsx +1 -1
  14. package/lib/components/Button/__tests__/__snapshots__/Button.test.tsx.snap +8 -8
  15. package/lib/components/CookiesNotice/CookieSettings.tsx +304 -0
  16. package/lib/components/CookiesNotice/CookiesNotice.stories.tsx +60 -0
  17. package/lib/components/CookiesNotice/CookiesNotice.tsx +379 -0
  18. package/lib/components/CookiesNotice/__tests__/CookiesNotice.test.tsx +180 -0
  19. package/lib/components/CookiesNotice/defaults.ts +40 -0
  20. package/lib/components/CookiesNotice/index.ts +6 -0
  21. package/lib/components/CookiesNotice/types.ts +14 -0
  22. package/lib/components/Input/Input.tsx +1 -0
  23. package/lib/components/Input/__tests__/__snapshots__/Input.test.tsx.snap +4 -4
  24. package/lib/components/Paragraph/Paragraph.tsx +13 -1
  25. package/lib/components/Paragraph/__tests__/Paragraph.test.tsx +24 -0
  26. package/lib/components/Search/__tests__/__snapshots__/Search.test.tsx.snap +2 -2
  27. package/lib/components/Text/Text.tsx +13 -0
  28. package/lib/components/Text/__tests__/Text.test.tsx +41 -0
  29. package/lib/components/Textarea/Textarea.tsx +2 -3
  30. package/lib/components/Textarea/__tests__/__snapshots__/Textarea.test.tsx.snap +4 -4
  31. package/lib/components/index.ts +9 -0
  32. package/lib/theme/common/themeCommon.ts +305 -327
  33. package/package.json +1 -1
@@ -0,0 +1,379 @@
1
+ import {
2
+ HTMLAttributes,
3
+ ReactNode,
4
+ useCallback,
5
+ useEffect,
6
+ useId,
7
+ useMemo,
8
+ useState,
9
+ } from 'react';
10
+ import { css, cx } from '@emotion/css';
11
+ import useTheme from '../../theme/useTheme';
12
+ import marginsStyle, { MarginProps } from '../common/marginsStyle';
13
+ import Heading from '../Heading';
14
+ import Paragraph from '../Paragraph';
15
+ import Button from '../Button';
16
+ import Link from '../Link';
17
+ import BaseDialog from '../Dialog/BaseDialog';
18
+ import CookieSettings from './CookieSettings';
19
+ import {
20
+ DEFAULT_COOKIE_CATEGORIES,
21
+ DEFAULT_DESCRIPTION,
22
+ DEFAULT_DESCRIPTION_SUFFIX,
23
+ DEFAULT_HEADING,
24
+ DEFAULT_POLICY_HREF,
25
+ } from './defaults';
26
+ import { CookieCategory, CookiePreferences } from './types';
27
+
28
+ export const NAME = 'ucl-uikit-cookies-notice';
29
+ const DESKTOP_NOTICE_CONTENT_MAX_WIDTH = 944;
30
+
31
+ export interface CookiesNoticeBaseProps extends HTMLAttributes<HTMLDivElement> {
32
+ heading?: ReactNode;
33
+ description?: ReactNode;
34
+ policyHref?: string;
35
+ policyLabel?: ReactNode;
36
+ cookies?: CookieCategory[];
37
+ preferences?: CookiePreferences;
38
+ modal?: boolean;
39
+ manageCookiesLabel?: ReactNode;
40
+ acceptAllLabel?: ReactNode;
41
+ acceptNecessaryLabel?: ReactNode;
42
+ onAcceptAll?: (preferences: CookiePreferences) => void;
43
+ onAcceptNecessary?: (preferences: CookiePreferences) => void;
44
+ onManageCookies?: () => void;
45
+ onPreferencesChange?: (preferences: CookiePreferences) => void;
46
+ onSavePreferences?: (preferences: CookiePreferences) => void;
47
+ onSettingsClose?: () => void;
48
+ testId?: string;
49
+ }
50
+
51
+ export type CookiesNoticeProps = CookiesNoticeBaseProps & MarginProps;
52
+
53
+ const getAllPreferences = (cookies: CookieCategory[]): CookiePreferences =>
54
+ cookies.reduce<CookiePreferences>((acc, cookie) => {
55
+ acc[cookie.id] = true;
56
+ return acc;
57
+ }, {});
58
+
59
+ const getNecessaryPreferences = (
60
+ cookies: CookieCategory[]
61
+ ): CookiePreferences =>
62
+ cookies.reduce<CookiePreferences>((acc, cookie) => {
63
+ acc[cookie.id] = !!cookie.required;
64
+ return acc;
65
+ }, {});
66
+
67
+ const getRequiredPreferences = (cookies: CookieCategory[]): CookiePreferences =>
68
+ cookies.reduce<CookiePreferences>((acc, cookie) => {
69
+ if (cookie.required) {
70
+ acc[cookie.id] = true;
71
+ }
72
+ return acc;
73
+ }, {});
74
+
75
+ const getDefaultPreferences = (cookies: CookieCategory[]): CookiePreferences =>
76
+ cookies.reduce<CookiePreferences>((acc, cookie) => {
77
+ acc[cookie.id] = cookie.required ? true : (cookie.defaultEnabled ?? false);
78
+ return acc;
79
+ }, {});
80
+
81
+ const CookiesNotice = ({
82
+ heading = DEFAULT_HEADING,
83
+ description,
84
+ policyHref = DEFAULT_POLICY_HREF,
85
+ policyLabel = 'UCL privacy policy',
86
+ cookies = DEFAULT_COOKIE_CATEGORIES,
87
+ preferences,
88
+ modal = false,
89
+ manageCookiesLabel = 'Manage cookies',
90
+ acceptAllLabel = 'Accept all cookies',
91
+ acceptNecessaryLabel = 'Accept necessary only',
92
+ onAcceptAll,
93
+ onAcceptNecessary,
94
+ onManageCookies,
95
+ onPreferencesChange,
96
+ onSavePreferences,
97
+ onSettingsClose,
98
+ testId = NAME,
99
+ className,
100
+ ...props
101
+ }: CookiesNoticeProps) => {
102
+ const [theme] = useTheme();
103
+ const noticeHeadingId = useId();
104
+ const [settingsOpen, setSettingsOpen] = useState(false);
105
+ const initialPreferences = useMemo(
106
+ () => ({
107
+ ...getDefaultPreferences(cookies),
108
+ ...preferences,
109
+ ...getRequiredPreferences(cookies),
110
+ }),
111
+ [cookies, preferences]
112
+ );
113
+ const [savedPreferences, setSavedPreferences] =
114
+ useState<CookiePreferences>(initialPreferences);
115
+ const [draftPreferences, setDraftPreferences] =
116
+ useState<CookiePreferences>(initialPreferences);
117
+
118
+ useEffect(() => {
119
+ setSavedPreferences(initialPreferences);
120
+ setDraftPreferences(initialPreferences);
121
+ }, [initialPreferences]);
122
+
123
+ const handlePreferenceToggle = useCallback(
124
+ (cookie: CookieCategory) => {
125
+ if (cookie.required) return;
126
+
127
+ const nextPreferences = {
128
+ ...draftPreferences,
129
+ [cookie.id]: !draftPreferences[cookie.id],
130
+ };
131
+
132
+ setDraftPreferences(nextPreferences);
133
+ onPreferencesChange?.(nextPreferences);
134
+ },
135
+ [draftPreferences, onPreferencesChange]
136
+ );
137
+
138
+ const handleAcceptAll = useCallback(() => {
139
+ const nextPreferences = getAllPreferences(cookies);
140
+
141
+ setSavedPreferences(nextPreferences);
142
+ setDraftPreferences(nextPreferences);
143
+ onAcceptAll?.(nextPreferences);
144
+ }, [cookies, onAcceptAll]);
145
+
146
+ const handleAcceptNecessary = useCallback(() => {
147
+ const nextPreferences = getNecessaryPreferences(cookies);
148
+
149
+ setSavedPreferences(nextPreferences);
150
+ setDraftPreferences(nextPreferences);
151
+ onAcceptNecessary?.(nextPreferences);
152
+ }, [cookies, onAcceptNecessary]);
153
+
154
+ const handleManageCookies = useCallback(() => {
155
+ onManageCookies?.();
156
+ setDraftPreferences(savedPreferences);
157
+ setSettingsOpen(true);
158
+ }, [onManageCookies, savedPreferences]);
159
+
160
+ const handleSettingsClose = useCallback(() => {
161
+ setSettingsOpen(false);
162
+ onSettingsClose?.();
163
+ }, [onSettingsClose]);
164
+
165
+ const handleSavePreferences = useCallback(() => {
166
+ setSavedPreferences(draftPreferences);
167
+ onSavePreferences?.(draftPreferences);
168
+ setSettingsOpen(false);
169
+ }, [draftPreferences, onSavePreferences]);
170
+
171
+ const baseStyle = css`
172
+ box-sizing: border-box;
173
+ width: 100%;
174
+ padding: ${theme.padding.p24} ${theme.padding.p16};
175
+ background-color: ${theme.colour.surface.primary};
176
+ color: ${theme.colour.text.default};
177
+ border-radius: ${theme.radius.r4} ${theme.radius.r4} 0 0;
178
+ display: flex;
179
+ flex-direction: column;
180
+ gap: ${theme.padding.p24};
181
+
182
+ @media (min-width: ${theme.breakpoints.tablet}px) {
183
+ padding: ${theme.padding.p48} ${theme.padding.p32};
184
+ border-radius: ${theme.radius.r4};
185
+ gap: ${theme.padding.p32};
186
+ }
187
+ `;
188
+
189
+ const contentStyle = css`
190
+ display: flex;
191
+ flex-direction: column;
192
+ gap: ${theme.padding.p16};
193
+ `;
194
+
195
+ const headingStyle = css`
196
+ text-align: center;
197
+
198
+ @media (min-width: ${theme.breakpoints.tablet}px) {
199
+ text-align: left;
200
+ }
201
+ `;
202
+
203
+ const policyLinkStyle = css`
204
+ color: ${theme.colour.text.default};
205
+
206
+ &:visited {
207
+ color: ${theme.colour.text.default};
208
+ }
209
+ `;
210
+
211
+ const actionsStyle = css`
212
+ display: flex;
213
+ flex-direction: column;
214
+ gap: ${theme.padding.p16};
215
+
216
+ @media (min-width: ${theme.breakpoints.tablet}px) {
217
+ flex-direction: row;
218
+ justify-content: space-between;
219
+ align-items: center;
220
+ }
221
+ `;
222
+
223
+ const actionGroupStyle = css`
224
+ display: flex;
225
+ flex-direction: column;
226
+ gap: ${theme.padding.p16};
227
+
228
+ @media (min-width: ${theme.breakpoints.tablet}px) {
229
+ flex-direction: row;
230
+ align-items: center;
231
+ }
232
+ `;
233
+
234
+ const manageButtonStyle = css`
235
+ order: 3;
236
+ width: 100%;
237
+ white-space: nowrap;
238
+
239
+ @media (min-width: ${theme.breakpoints.tablet}px) {
240
+ order: 0;
241
+ width: auto;
242
+ }
243
+ `;
244
+
245
+ const actionButtonStyle = css`
246
+ width: 100%;
247
+ white-space: nowrap;
248
+
249
+ @media (min-width: ${theme.breakpoints.tablet}px) {
250
+ width: auto;
251
+ }
252
+ `;
253
+
254
+ const dialogStyle = css`
255
+ height: fit-content;
256
+ max-height: calc(100vh - ${theme.margin.m32});
257
+ margin: auto auto 0;
258
+ background-color: transparent;
259
+ box-shadow: ${theme.boxShadow.x2y4};
260
+
261
+ &:modal {
262
+ max-height: calc(100vh - ${theme.margin.m32});
263
+ }
264
+
265
+ @media (min-width: ${theme.breakpoints.tablet}px) {
266
+ width: calc(100vw - ${theme.margin.m64});
267
+ max-width: calc(
268
+ ${DESKTOP_NOTICE_CONTENT_MAX_WIDTH}px + ${theme.padding.p64}
269
+ );
270
+ margin: auto;
271
+
272
+ &:modal {
273
+ max-width: min(
274
+ calc(${DESKTOP_NOTICE_CONTENT_MAX_WIDTH}px + ${theme.padding.p64}),
275
+ calc(100vw - ${theme.margin.m64})
276
+ );
277
+ }
278
+ }
279
+ `;
280
+
281
+ const style = cx(NAME, baseStyle, marginsStyle(props, theme), className);
282
+
283
+ const notice = (
284
+ <div
285
+ className={style}
286
+ data-testid={testId}
287
+ {...props}
288
+ >
289
+ <div className={cx(`${NAME}__content`, contentStyle)}>
290
+ <Heading
291
+ id={noticeHeadingId}
292
+ level='md'
293
+ as='h2'
294
+ noMargins
295
+ className={cx(`${NAME}__heading`, headingStyle)}
296
+ >
297
+ {heading}
298
+ </Heading>
299
+ <Paragraph
300
+ level='md'
301
+ noMargins
302
+ >
303
+ {description ?? (
304
+ <>
305
+ {DEFAULT_DESCRIPTION}
306
+ <Link
307
+ href={policyHref}
308
+ className={policyLinkStyle}
309
+ noVisited
310
+ >
311
+ {policyLabel}
312
+ </Link>
313
+ .{DEFAULT_DESCRIPTION_SUFFIX}
314
+ </>
315
+ )}
316
+ </Paragraph>
317
+ </div>
318
+
319
+ <div className={cx(`${NAME}__actions`, actionsStyle)}>
320
+ <Button
321
+ variant='secondary'
322
+ fullWidth
323
+ className={cx(`${NAME}__manage-button`, manageButtonStyle)}
324
+ onClick={handleManageCookies}
325
+ >
326
+ {manageCookiesLabel}
327
+ </Button>
328
+ <div className={cx(`${NAME}__accept-actions`, actionGroupStyle)}>
329
+ <Button
330
+ variant='accent'
331
+ fullWidth
332
+ className={cx(
333
+ `${NAME}__accept-necessary-button`,
334
+ actionButtonStyle
335
+ )}
336
+ onClick={handleAcceptNecessary}
337
+ >
338
+ {acceptNecessaryLabel}
339
+ </Button>
340
+ <Button
341
+ variant='accent'
342
+ fullWidth
343
+ className={cx(`${NAME}__accept-all-button`, actionButtonStyle)}
344
+ onClick={handleAcceptAll}
345
+ >
346
+ {acceptAllLabel}
347
+ </Button>
348
+ </div>
349
+ </div>
350
+ </div>
351
+ );
352
+
353
+ return (
354
+ <>
355
+ <BaseDialog
356
+ open
357
+ modal={modal}
358
+ size='large'
359
+ closeOnClickOutside={false}
360
+ className={cx(`${NAME}__dialog`, dialogStyle)}
361
+ aria-labelledby={noticeHeadingId}
362
+ >
363
+ {notice}
364
+ </BaseDialog>
365
+ <CookieSettings
366
+ open={settingsOpen}
367
+ cookies={cookies}
368
+ preferences={draftPreferences}
369
+ policyHref={policyHref}
370
+ policyLabel='UCL privacy policy.'
371
+ onClose={handleSettingsClose}
372
+ onPreferenceToggle={handlePreferenceToggle}
373
+ onSavePreferences={handleSavePreferences}
374
+ />
375
+ </>
376
+ );
377
+ };
378
+
379
+ export default CookiesNotice;
@@ -0,0 +1,180 @@
1
+ import { afterAll, beforeAll, describe, expect, test, vi } from 'vitest';
2
+ import { fireEvent, render, screen } from '@testing-library/react';
3
+ import { ThemeContextProvider } from '../../../theme/useTheme';
4
+ import CookiesNotice from '..';
5
+ import { CookieCategory } from '../types';
6
+
7
+ const originalShowModal = HTMLDialogElement.prototype.showModal;
8
+ const originalShow = HTMLDialogElement.prototype.show;
9
+ const originalClose = HTMLDialogElement.prototype.close;
10
+
11
+ beforeAll(() => {
12
+ HTMLDialogElement.prototype.showModal = vi.fn(function (
13
+ this: HTMLDialogElement
14
+ ) {
15
+ this.setAttribute('open', '');
16
+ });
17
+ HTMLDialogElement.prototype.show = vi.fn(function (this: HTMLDialogElement) {
18
+ this.setAttribute('open', '');
19
+ });
20
+ HTMLDialogElement.prototype.close = vi.fn(function (this: HTMLDialogElement) {
21
+ this.removeAttribute('open');
22
+ });
23
+ });
24
+
25
+ afterAll(() => {
26
+ HTMLDialogElement.prototype.showModal = originalShowModal;
27
+ HTMLDialogElement.prototype.show = originalShow;
28
+ HTMLDialogElement.prototype.close = originalClose;
29
+ });
30
+
31
+ const cookies: CookieCategory[] = [
32
+ {
33
+ id: 'necessary',
34
+ title: 'Necessary',
35
+ description: 'Required for the site to work.',
36
+ required: true,
37
+ },
38
+ {
39
+ id: 'analytics',
40
+ title: 'Analytics',
41
+ description: 'Helps us improve the service.',
42
+ defaultEnabled: true,
43
+ },
44
+ {
45
+ id: 'maps',
46
+ title: 'Maps',
47
+ description: 'Embeds third-party map services.',
48
+ },
49
+ ];
50
+
51
+ const renderWithTheme = (ui: React.ReactNode) =>
52
+ render(<ThemeContextProvider>{ui}</ThemeContextProvider>);
53
+
54
+ describe('CookiesNotice', () => {
55
+ test('renders custom cookie content and calls accept callbacks with preferences', () => {
56
+ const onAcceptAll = vi.fn();
57
+ const onAcceptNecessary = vi.fn();
58
+
59
+ renderWithTheme(
60
+ <CookiesNotice
61
+ cookies={cookies}
62
+ onAcceptAll={onAcceptAll}
63
+ onAcceptNecessary={onAcceptNecessary}
64
+ />
65
+ );
66
+
67
+ expect(screen.getByText('Help us improve your experience')).toBeDefined();
68
+ expect(
69
+ screen.getByRole('dialog', { name: 'Help us improve your experience' })
70
+ ).toHaveAttribute('aria-modal', 'false');
71
+
72
+ fireEvent.click(screen.getByRole('button', { name: 'Accept all cookies' }));
73
+ fireEvent.click(
74
+ screen.getByRole('button', { name: 'Accept necessary only' })
75
+ );
76
+
77
+ expect(onAcceptAll).toHaveBeenCalledWith({
78
+ necessary: true,
79
+ analytics: true,
80
+ maps: true,
81
+ });
82
+ expect(onAcceptNecessary).toHaveBeenCalledWith({
83
+ necessary: true,
84
+ analytics: false,
85
+ maps: false,
86
+ });
87
+ });
88
+
89
+ test('renders modal notice as a dialog', () => {
90
+ renderWithTheme(
91
+ <CookiesNotice
92
+ modal
93
+ cookies={cookies}
94
+ />
95
+ );
96
+
97
+ expect(
98
+ screen.getByRole('dialog', { name: 'Help us improve your experience' })
99
+ ).toBeInTheDocument();
100
+ });
101
+
102
+ test('opens settings and saves selected preferences', () => {
103
+ const onManageCookies = vi.fn();
104
+ const onSavePreferences = vi.fn();
105
+
106
+ renderWithTheme(
107
+ <CookiesNotice
108
+ cookies={cookies}
109
+ onManageCookies={onManageCookies}
110
+ onSavePreferences={onSavePreferences}
111
+ />
112
+ );
113
+
114
+ fireEvent.click(screen.getByRole('button', { name: 'Manage cookies' }));
115
+ fireEvent.click(screen.getByRole('switch', { name: 'Allow Analytics' }));
116
+ fireEvent.click(screen.getByRole('button', { name: 'Save preferences' }));
117
+
118
+ expect(onManageCookies).toHaveBeenCalledTimes(1);
119
+ expect(onSavePreferences).toHaveBeenCalledWith({
120
+ necessary: true,
121
+ analytics: false,
122
+ maps: false,
123
+ });
124
+ });
125
+
126
+ test('keeps saved preferences when settings is reopened', () => {
127
+ const onSavePreferences = vi.fn();
128
+
129
+ renderWithTheme(
130
+ <CookiesNotice
131
+ cookies={cookies}
132
+ onSavePreferences={onSavePreferences}
133
+ />
134
+ );
135
+
136
+ fireEvent.click(screen.getByRole('button', { name: 'Manage cookies' }));
137
+ fireEvent.click(screen.getByRole('switch', { name: 'Allow Analytics' }));
138
+ fireEvent.click(screen.getByRole('button', { name: 'Save preferences' }));
139
+
140
+ fireEvent.click(screen.getByRole('button', { name: 'Manage cookies' }));
141
+ fireEvent.click(screen.getByRole('button', { name: 'Save preferences' }));
142
+
143
+ expect(onSavePreferences).toHaveBeenLastCalledWith({
144
+ necessary: true,
145
+ analytics: false,
146
+ maps: false,
147
+ });
148
+ });
149
+
150
+ test('passes existing preferences into managed settings', () => {
151
+ const onSavePreferences = vi.fn();
152
+
153
+ renderWithTheme(
154
+ <CookiesNotice
155
+ cookies={cookies}
156
+ preferences={{
157
+ necessary: true,
158
+ analytics: false,
159
+ maps: true,
160
+ }}
161
+ onSavePreferences={onSavePreferences}
162
+ />
163
+ );
164
+
165
+ fireEvent.click(screen.getByRole('button', { name: 'Manage cookies' }));
166
+
167
+ expect(screen.getByRole('dialog', { name: 'Privacy preferences' }));
168
+ expect(screen.getByText('Embeds third-party map services.')).toBeDefined();
169
+
170
+ fireEvent.click(screen.getByRole('switch', { name: 'Allow Analytics' }));
171
+ fireEvent.click(screen.getByRole('switch', { name: 'Allow Maps' }));
172
+ fireEvent.click(screen.getByRole('button', { name: 'Save preferences' }));
173
+
174
+ expect(onSavePreferences).toHaveBeenCalledWith({
175
+ necessary: true,
176
+ analytics: true,
177
+ maps: false,
178
+ });
179
+ });
180
+ });
@@ -0,0 +1,40 @@
1
+ import { CookieCategory } from './types';
2
+
3
+ export const DEFAULT_POLICY_HREF =
4
+ 'https://www.ucl.ac.uk/legal-services/privacy/cookie-policy';
5
+
6
+ export const DEFAULT_HEADING = 'Help us improve your experience';
7
+
8
+ export const DEFAULT_DESCRIPTION =
9
+ 'We use cookies for authentication, analytics, and third-party services like Google Maps. Some cookies are required for the site to function and cannot be turned off. By accepting, you agree to the ';
10
+
11
+ export const DEFAULT_DESCRIPTION_SUFFIX =
12
+ ' You can update your preferences any time.';
13
+
14
+ export const DEFAULT_COOKIE_CATEGORIES: CookieCategory[] = [
15
+ {
16
+ id: 'necessary',
17
+ title: 'Necessary Cookies',
18
+ description:
19
+ "These cookies are necessary for the website to function and can't be switched off in our systems.",
20
+ required: true,
21
+ defaultEnabled: true,
22
+ learnMoreHref: DEFAULT_POLICY_HREF,
23
+ },
24
+ {
25
+ id: 'analytics',
26
+ title: 'Analytics',
27
+ description:
28
+ 'These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site.',
29
+ defaultEnabled: true,
30
+ learnMoreHref: DEFAULT_POLICY_HREF,
31
+ },
32
+ {
33
+ id: 'marketing',
34
+ title: 'Marketing',
35
+ description:
36
+ 'These cookies are set through our site by our advertising partners. They may be used to build a profile of your interests and show you relevant ads.',
37
+ defaultEnabled: true,
38
+ learnMoreHref: DEFAULT_POLICY_HREF,
39
+ },
40
+ ];
@@ -0,0 +1,6 @@
1
+ export { default } from './CookiesNotice';
2
+ export type {
3
+ CookiesNoticeBaseProps,
4
+ CookiesNoticeProps,
5
+ } from './CookiesNotice';
6
+ export type { CookieCategory, CookiePreferences } from './types';
@@ -0,0 +1,14 @@
1
+ import { ReactNode } from 'react';
2
+
3
+ export type CookiePreferences = Record<string, boolean>;
4
+
5
+ export interface CookieCategory {
6
+ id: string;
7
+ title: ReactNode;
8
+ description: ReactNode;
9
+ required?: boolean;
10
+ defaultEnabled?: boolean;
11
+ toggleLabel?: string;
12
+ learnMoreHref?: string;
13
+ learnMoreLabel?: ReactNode;
14
+ }
@@ -60,6 +60,7 @@ const Input = forwardRef<Ref, InputProps>(
60
60
  color: ${theme.colour.text.default};
61
61
  background-color: ${theme.colour.fill.inverse};
62
62
  border: ${theme.border.b1} solid ${theme.colour.speciality.inputDefault};
63
+ border-radius: ${theme.radius.r4};
63
64
  outline: none;
64
65
 
65
66
  &::placeholder {
@@ -5,7 +5,7 @@ exports[`Input > snapshot: no props 1`] = `
5
5
  class="ucl-uikit-input css-1bpb1dw"
6
6
  >
7
7
  <input
8
- class="ucl-uikit-input__input css-kvsjyn"
8
+ class="ucl-uikit-input__input css-i99dnf"
9
9
  data-testid="ucl-uikit-input"
10
10
  id=""
11
11
  />
@@ -17,7 +17,7 @@ exports[`Input > snapshot: placeholder prop 1`] = `
17
17
  class="ucl-uikit-input css-1bpb1dw"
18
18
  >
19
19
  <input
20
- class="ucl-uikit-input__input css-kvsjyn"
20
+ class="ucl-uikit-input__input css-i99dnf"
21
21
  data-testid="ucl-uikit-input"
22
22
  id=""
23
23
  placeholder="Type your value..."
@@ -30,7 +30,7 @@ exports[`Input > snapshot: testId prop 1`] = `
30
30
  class="ucl-uikit-input css-1bpb1dw"
31
31
  >
32
32
  <input
33
- class="ucl-uikit-input__input css-kvsjyn"
33
+ class="ucl-uikit-input__input css-i99dnf"
34
34
  data-testid="test123"
35
35
  id=""
36
36
  />
@@ -42,7 +42,7 @@ exports[`Input > snapshot: value prop 1`] = `
42
42
  class="ucl-uikit-input css-1bpb1dw"
43
43
  >
44
44
  <input
45
- class="ucl-uikit-input__input css-kvsjyn"
45
+ class="ucl-uikit-input__input css-i99dnf"
46
46
  data-testid="ucl-uikit-input"
47
47
  id=""
48
48
  value="abc"
@@ -13,7 +13,7 @@ export type ParagraphLevel =
13
13
  | 'md'
14
14
  | 'md-medium'
15
15
  | 'md-semibold'
16
- | 'md-semibold'
16
+ | 'md-numeric'
17
17
  | 'md-medium-numeric'
18
18
  | 'sm'
19
19
  | 'sm-medium'
@@ -57,6 +57,7 @@ const Paragraph = ({
57
57
  md,
58
58
  mdMedium,
59
59
  mdSemibold,
60
+ mdNumeric,
60
61
  mdMediumNumeric,
61
62
  sm,
62
63
  smMedium,
@@ -134,7 +135,17 @@ const Paragraph = ({
134
135
  line-height: ${mdSemibold.lineHeight}%;
135
136
  `;
136
137
 
138
+ const mdNumericStyle = css`
139
+ font-family: ${mdNumeric.fontFamily};
140
+ font-feature-settings: ${mdNumeric.fontSettings};
141
+ font-size: ${mdNumeric.fontSize}px;
142
+ font-weight: ${mdNumeric.fontWeight};
143
+ line-height: ${mdNumeric.lineHeight}%;
144
+ `;
145
+
137
146
  const mdMediumNumericStyle = css`
147
+ font-family: ${mdMediumNumeric.fontFamily};
148
+ font-feature-settings: ${mdMediumNumeric.fontSettings};
138
149
  font-size: ${mdMediumNumeric.fontSize}px;
139
150
  font-weight: ${mdMediumNumeric.fontWeight};
140
151
  line-height: ${mdMediumNumeric.lineHeight}%;
@@ -180,6 +191,7 @@ const Paragraph = ({
180
191
  mappedLevel === 'md' && mdStyle,
181
192
  mappedLevel === 'md-medium' && mdMediumStyle,
182
193
  mappedLevel === 'md-semibold' && mdSemiboldStyle,
194
+ mappedLevel === 'md-numeric' && mdNumericStyle,
183
195
  mappedLevel === 'md-medium-numeric' && mdMediumNumericStyle,
184
196
  mappedLevel === 'sm' && smStyle,
185
197
  mappedLevel === 'sm-medium' && smMediumStyle,