uikit-react-public 0.36.1 → 0.37.2

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 (40) hide show
  1. package/dist/components/Pagination/Pagination.stories.d.ts +1 -0
  2. package/dist/components/Pagination/PaginationControls.d.ts +2 -1
  3. package/dist/components/Pagination/__tests__/PaginationControls.test.d.ts +1 -0
  4. package/dist/components/Pagination/subcomponents/PaginationCompactControls.d.ts +7 -0
  5. package/dist/components/Pagination/subcomponents/PaginationStandardControls.d.ts +8 -0
  6. package/dist/components/Pagination/subcomponents/index.d.ts +2 -0
  7. package/dist/components/Table/Table.context.d.ts +6 -0
  8. package/dist/components/Table/Table.d.ts +4 -3
  9. package/dist/components/Table/Table.stories.d.ts +3 -3
  10. package/dist/components/Table/Table.types.d.ts +6 -0
  11. package/dist/components/Table/index.d.ts +1 -1
  12. package/dist/components/Table/subcomponents/Cell/Cell.d.ts +8 -1
  13. package/dist/components/Table/subcomponents/Cell/Cell.stories.d.ts +5 -1
  14. package/dist/components/Table/subcomponents/Cell/CellContent.d.ts +3 -2
  15. package/dist/components/Table/subcomponents/HeadCell/HeadCell.d.ts +4 -2
  16. package/dist/components/Table/subcomponents/HeadCell/HeadCell.stories.d.ts +3 -1
  17. package/dist/components/Table/subcomponents/Row.d.ts +8 -1
  18. package/dist/index.js +7219 -6668
  19. package/lib/components/Pagination/Pagination.stories.tsx +9 -0
  20. package/lib/components/Pagination/PaginationControls.tsx +17 -245
  21. package/lib/components/Pagination/__tests__/PaginationControls.test.tsx +213 -0
  22. package/lib/components/Pagination/subcomponents/PaginationCompactControls.tsx +266 -0
  23. package/lib/components/Pagination/subcomponents/PaginationStandardControls.tsx +246 -0
  24. package/lib/components/Pagination/subcomponents/index.ts +2 -0
  25. package/lib/components/Table/Table.context.ts +12 -0
  26. package/lib/components/Table/Table.tsx +91 -12
  27. package/lib/components/Table/Table.types.ts +21 -0
  28. package/lib/components/Table/__tests__/Table.test.tsx +95 -1
  29. package/lib/components/Table/__tests__/__snapshots__/Table.test.tsx.snap +54 -13
  30. package/lib/components/Table/index.ts +6 -1
  31. package/lib/components/Table/subcomponents/Body.tsx +16 -3
  32. package/lib/components/Table/subcomponents/Cell/Cell.tsx +193 -4
  33. package/lib/components/Table/subcomponents/Cell/CellContent.tsx +63 -3
  34. package/lib/components/Table/subcomponents/Cell/__tests__/__snapshots__/Cell.test.tsx.snap +15 -10
  35. package/lib/components/Table/subcomponents/Head.tsx +14 -3
  36. package/lib/components/Table/subcomponents/HeadCell/HeadCell.tsx +17 -4
  37. package/lib/components/Table/subcomponents/HeadCell/__tests__/__snapshots__/HeadCell.test.tsx.snap +3 -3
  38. package/lib/components/Table/subcomponents/Row.tsx +195 -6
  39. package/lib/components/Table/subcomponents/SortIcon.tsx +4 -4
  40. package/package.json +5 -5
@@ -1,6 +1,6 @@
1
1
  import { createRef } from 'react';
2
2
  import { describe, expect, test } from 'vitest';
3
- import { render, screen, within } from '@testing-library/react';
3
+ import { fireEvent, render, screen, within } from '@testing-library/react';
4
4
  import Table from '../Table';
5
5
  import { ThemeContextProvider } from '../../../theme/useTheme';
6
6
 
@@ -137,4 +137,98 @@ describe('Table', () => {
137
137
  screen.getByRole('table', { name: 'User list' })
138
138
  ).toBeInTheDocument();
139
139
  });
140
+
141
+ test('maps mobile column roles and labels from header cells to body cells', () => {
142
+ render(
143
+ <ThemeContextProvider>
144
+ <Table>
145
+ <Table.Head>
146
+ <Table.HeadCell
147
+ variant='checkbox'
148
+ mobileLabel='Select'
149
+ />
150
+ <Table.HeadCell mobileRole='primaryMeta'>Reference</Table.HeadCell>
151
+ <Table.HeadCell mobileRole='primary'>Course</Table.HeadCell>
152
+ <Table.HeadCell mobileRole='primaryStatus'>Status</Table.HeadCell>
153
+ <Table.HeadCell mobileRole='primaryAction'>Action</Table.HeadCell>
154
+ </Table.Head>
155
+ <Table.Body>
156
+ <Table.Row>
157
+ <Table.Cell
158
+ variant='checkbox'
159
+ checkboxProps={{ ariaLabel: 'Select Computer Science' }}
160
+ />
161
+ <Table.Cell>12345678</Table.Cell>
162
+ <Table.Cell>Computer Science BSc</Table.Cell>
163
+ <Table.Cell>Open</Table.Cell>
164
+ <Table.Cell>
165
+ <a href='/courses/computer-science'>View course</a>
166
+ </Table.Cell>
167
+ </Table.Row>
168
+ </Table.Body>
169
+ </Table>
170
+ </ThemeContextProvider>
171
+ );
172
+
173
+ const cells = screen.getAllByTestId('ucl-uikit-table__cell');
174
+
175
+ expect(cells[0]).toHaveAttribute('data-mobile-role', 'selection');
176
+ expect(cells[1]).toHaveAttribute('data-mobile-role', 'primaryMeta');
177
+ expect(cells[2]).toHaveAttribute('data-mobile-role', 'primary');
178
+ expect(cells[2]).toHaveAttribute('data-mobile-label', 'Course');
179
+ expect(cells[3]).toHaveAttribute('data-mobile-role', 'status');
180
+ expect(cells[4]).toHaveAttribute('data-mobile-role', 'primaryAction');
181
+ });
182
+
183
+ test('uses the first field column as the mobile primary when none is marked', () => {
184
+ render(
185
+ <ThemeContextProvider>
186
+ <Table>
187
+ <Table.Head>
188
+ <Table.HeadCell showSortIcon={false}>Name</Table.HeadCell>
189
+ <Table.HeadCell showSortIcon={false}>Email</Table.HeadCell>
190
+ </Table.Head>
191
+ <Table.Body>
192
+ <Table.Row>
193
+ <Table.Cell>Ada Lovelace</Table.Cell>
194
+ <Table.Cell>ada@example.com</Table.Cell>
195
+ </Table.Row>
196
+ </Table.Body>
197
+ </Table>
198
+ </ThemeContextProvider>
199
+ );
200
+
201
+ const cells = screen.getAllByTestId('ucl-uikit-table__cell');
202
+
203
+ expect(cells[0]).toHaveAttribute('data-mobile-role', 'primary');
204
+ expect(cells[1]).toHaveAttribute('data-mobile-role', 'field');
205
+ });
206
+
207
+ test('toggles row mobile expansion from the details disclosure button', () => {
208
+ render(
209
+ <ThemeContextProvider>
210
+ <Table>
211
+ <Table.Head>
212
+ <Table.HeadCell mobileRole='primary'>Name</Table.HeadCell>
213
+ <Table.HeadCell>Email</Table.HeadCell>
214
+ </Table.Head>
215
+ <Table.Body>
216
+ <Table.Row defaultMobileExpanded={false}>
217
+ <Table.Cell>Ada Lovelace</Table.Cell>
218
+ <Table.Cell>ada@example.com</Table.Cell>
219
+ </Table.Row>
220
+ </Table.Body>
221
+ </Table>
222
+ </ThemeContextProvider>
223
+ );
224
+
225
+ const row = screen.getByTestId('ucl-uikit-table__row');
226
+ const button = screen.getByRole('button', { name: 'Show details' });
227
+
228
+ expect(row).toHaveAttribute('data-mobile-expanded', 'false');
229
+
230
+ fireEvent.click(button);
231
+
232
+ expect(row).toHaveAttribute('data-mobile-expanded', 'true');
233
+ });
140
234
  });
@@ -2,18 +2,18 @@
2
2
 
3
3
  exports[`Table > Snapshot: basic table 1`] = `
4
4
  <table
5
- class="css-3bowfr ucl-uikit-table"
5
+ class="css-1mnnjq ucl-uikit-table"
6
6
  data-testid="ucl-uikit-table"
7
7
  >
8
8
  <thead
9
- class="css-3fy35g ucl-uikit-table__head"
9
+ class="css-1ux39q6 ucl-uikit-table__head"
10
10
  data-testid="ucl-uikit-table__head"
11
11
  >
12
12
  <tr
13
- class="css-7kbd2r"
13
+ class="css-1pr7kjy"
14
14
  >
15
15
  <th
16
- class="css-19iwbn3 ucl-uikit-table__head-cell"
16
+ class="css-x1n4gt ucl-uikit-table__head-cell"
17
17
  data-testid="ucl-uikit-table__head-cell"
18
18
  scope="col"
19
19
  >
@@ -64,7 +64,7 @@ exports[`Table > Snapshot: basic table 1`] = `
64
64
  </div>
65
65
  </th>
66
66
  <th
67
- class="css-19iwbn3 ucl-uikit-table__head-cell"
67
+ class="css-x1n4gt ucl-uikit-table__head-cell"
68
68
  data-testid="ucl-uikit-table__head-cell"
69
69
  scope="col"
70
70
  >
@@ -115,7 +115,7 @@ exports[`Table > Snapshot: basic table 1`] = `
115
115
  </div>
116
116
  </th>
117
117
  <th
118
- class="css-19iwbn3 ucl-uikit-table__head-cell"
118
+ class="css-x1n4gt ucl-uikit-table__head-cell"
119
119
  data-testid="ucl-uikit-table__head-cell"
120
120
  scope="col"
121
121
  >
@@ -168,46 +168,87 @@ exports[`Table > Snapshot: basic table 1`] = `
168
168
  </tr>
169
169
  </thead>
170
170
  <tbody
171
+ class="css-13y1iix ucl-uikit-table__body"
171
172
  data-testid="ucl-uikit-table__body"
172
173
  >
173
174
  <tr
174
175
  aria-selected="false"
175
- class="css-jetl3c ucl-uikit-table__row"
176
+ class="css-icxsp9 ucl-uikit-table__row"
177
+ data-mobile-expanded="true"
176
178
  data-testid="ucl-uikit-table__row"
177
179
  >
178
180
  <td
179
- class="css-u1gowl ucl-uikit-table__cell"
181
+ class="ucl-uikit-table__cell css-1bdqdyj"
182
+ data-mobile-label="Header Cell 1"
183
+ data-mobile-role="primary"
180
184
  data-testid="ucl-uikit-table__cell"
181
185
  >
182
186
  <div
183
- class="ucl-uikit-table__cell-content css-1ao6jhw"
187
+ class="ucl-uikit-table__cell-content css-1ugtgeo"
184
188
  data-testid="ucl-uikit-table__cell-content"
185
189
  >
186
190
  Test Cell 1
187
191
  </div>
188
192
  </td>
189
193
  <td
190
- class="css-u1gowl ucl-uikit-table__cell"
194
+ class="ucl-uikit-table__cell css-1yys4um"
195
+ data-mobile-label="Header Cell 2"
196
+ data-mobile-role="field"
191
197
  data-testid="ucl-uikit-table__cell"
192
198
  >
193
199
  <div
194
- class="ucl-uikit-table__cell-content css-1ao6jhw"
200
+ class="ucl-uikit-table__cell-content css-qn93h1"
195
201
  data-testid="ucl-uikit-table__cell-content"
196
202
  >
197
203
  Test Cell 2
198
204
  </div>
199
205
  </td>
200
206
  <td
201
- class="css-u1gowl ucl-uikit-table__cell"
207
+ class="ucl-uikit-table__cell css-501n1z"
208
+ data-mobile-label="Header Cell 3"
209
+ data-mobile-role="field"
202
210
  data-testid="ucl-uikit-table__cell"
203
211
  >
204
212
  <div
205
- class="ucl-uikit-table__cell-content css-1ao6jhw"
213
+ class="ucl-uikit-table__cell-content css-qn93h1"
206
214
  data-testid="ucl-uikit-table__cell-content"
207
215
  >
208
216
  Test Cell 3
209
217
  </div>
210
218
  </td>
219
+ <td
220
+ class="css-1nfo37q"
221
+ data-mobile-role="details"
222
+ >
223
+ <button
224
+ aria-expanded="true"
225
+ aria-label="Hide details"
226
+ class="css-1edts3y"
227
+ type="button"
228
+ >
229
+ <span>
230
+ Details
231
+ </span>
232
+ <svg
233
+ class="ucl-uikit-icon css-148hpxb"
234
+ data-testid="ucl-uikit-icon"
235
+ fill="none"
236
+ focusable="false"
237
+ height="20"
238
+ stroke="currentColor"
239
+ stroke-linecap="round"
240
+ stroke-linejoin="round"
241
+ stroke-width="2"
242
+ viewBox="0 0 24 24"
243
+ width="20"
244
+ xmlns="http://www.w3.org/2000/svg"
245
+ >
246
+ <path
247
+ d="m18 15-6-6-6 6"
248
+ />
249
+ </svg>
250
+ </button>
251
+ </td>
211
252
  </tr>
212
253
  </tbody>
213
254
  </table>
@@ -1,5 +1,10 @@
1
1
  export { default } from './Table';
2
- export type { TableProps, ColumnVariant } from './Table.types';
2
+ export type {
3
+ TableProps,
4
+ ColumnVariant,
5
+ TableMobileRole,
6
+ TableColumnMetadata,
7
+ } from './Table.types';
3
8
  export type {
4
9
  TableHeadProps,
5
10
  TableHeadCellProps,
@@ -1,12 +1,25 @@
1
- export interface TableBodyProps
2
- extends React.HTMLAttributes<HTMLTableSectionElement> {}
1
+ import { css, cx } from '@emotion/css';
2
+ import { useTheme } from '../../../theme';
3
+
4
+ export interface TableBodyProps extends React.HTMLAttributes<HTMLTableSectionElement> {}
3
5
 
4
6
  const NAME = 'ucl-uikit-table__body';
5
7
 
6
8
  const Body = ({ className, children, ...props }: TableBodyProps) => {
9
+ const [theme] = useTheme();
10
+
11
+ const baseStyle = css`
12
+ @media screen and (max-width: ${theme.breakpoints.tablet - 1}px) {
13
+ display: block;
14
+ width: 100%;
15
+ }
16
+ `;
17
+
18
+ const style = cx(baseStyle, className, NAME);
19
+
7
20
  return (
8
21
  <tbody
9
- className={className}
22
+ className={style}
10
23
  data-testid={NAME}
11
24
  {...props}
12
25
  >
@@ -1,7 +1,11 @@
1
1
  import { css, cx } from '@emotion/css';
2
2
  import CellContent from './CellContent';
3
3
  import { useTheme } from '../../../../theme';
4
- import type { ColumnVariant } from '../../Table.types';
4
+ import { useTableContext } from '../../Table.context';
5
+ import type {
6
+ ColumnVariant,
7
+ NormalizedTableMobileRole,
8
+ } from '../../Table.types';
5
9
  import type { CheckboxProps } from '../../../Checkbox/Checkbox';
6
10
  import type { ButtonProps } from '../../../Button';
7
11
 
@@ -21,10 +25,25 @@ export interface TableCellProps extends React.HTMLAttributes<HTMLTableCellElemen
21
25
  ButtonProps<'button'>,
22
26
  'variant' | 'onClick' | 'className'
23
27
  >;
28
+ /** @internal */
29
+ __mobileColumnIndex?: number;
30
+ __mobileHasSelection?: boolean;
31
+ /** @internal */
32
+ __mobileHasPrimaryMeta?: boolean;
33
+ /** @internal */
34
+ __mobileIsFirstBodyField?: boolean;
24
35
  }
25
36
 
26
37
  const NAME = 'ucl-uikit-table__cell';
27
38
 
39
+ const getDefaultMobileRole = (
40
+ variant: ColumnVariant
41
+ ): NormalizedTableMobileRole => {
42
+ if (variant === 'checkbox') return 'selection';
43
+ if (variant === 'button') return 'primaryAction';
44
+ return 'field';
45
+ };
46
+
28
47
  const Cell = ({
29
48
  variant = 'default',
30
49
  icon,
@@ -36,9 +55,17 @@ const Cell = ({
36
55
  children,
37
56
  checkboxProps,
38
57
  buttonProps,
58
+ __mobileColumnIndex,
59
+ __mobileHasSelection = false,
60
+ __mobileHasPrimaryMeta = false,
61
+ __mobileIsFirstBodyField = false,
39
62
  ...props
40
63
  }: TableCellProps) => {
41
64
  const [theme] = useTheme();
65
+ const { columns } = useTableContext();
66
+ const mobileColumn = columns[__mobileColumnIndex ?? -1];
67
+ const mobileRole = mobileColumn?.mobileRole ?? getDefaultMobileRole(variant);
68
+ const mobileLabel = mobileColumn?.mobileLabel;
42
69
 
43
70
  if (
44
71
  variant === 'checkbox' &&
@@ -63,20 +90,182 @@ const Cell = ({
63
90
  box-sizing: border-box;
64
91
  padding: 0 ${theme.padding.p16};
65
92
  height: 40px;
66
- font-family: ${theme.font.family.primary};
67
- font-size: ${theme.font.size.f14};
93
+ font-family: ${theme.typography.body.sm.fontFamily};
94
+ font-feature-settings: ${theme.typography.body.sm.fontSettings};
95
+ font-size: ${theme.typography.body.sm.fontSize}px;
96
+ font-weight: ${theme.typography.body.sm.fontWeight};
97
+ line-height: ${theme.typography.body.sm.lineHeight}%;
98
+
99
+ @media screen and (max-width: ${theme.breakpoints.tablet - 1}px) {
100
+ min-width: 0;
101
+ height: auto;
102
+ padding: 0;
103
+ }
104
+ `;
105
+
106
+ const mobileSelectionStyle = css`
107
+ @media screen and (max-width: ${theme.breakpoints.tablet - 1}px) {
108
+ grid-column: 1;
109
+ grid-row: 1 / span 2;
110
+ order: 0;
111
+ align-self: center;
112
+ padding-top: ${theme.padding.p2};
113
+ }
114
+ `;
115
+
116
+ const mobilePrimaryStyle = css`
117
+ @media screen and (max-width: ${theme.breakpoints.tablet - 1}px) {
118
+ display: grid;
119
+ grid-template-columns: minmax(0, 1fr) auto;
120
+ align-items: start;
121
+ gap: ${theme.padding.p8};
122
+ min-height: 20px;
123
+ }
124
+ `;
125
+
126
+ const mobilePrimaryAfterSelectionStyle = css`
127
+ @media screen and (max-width: ${theme.breakpoints.tablet - 1}px) {
128
+ grid-column: 2;
129
+ }
130
+ `;
131
+
132
+ const mobilePrimaryWithoutSelectionStyle = css`
133
+ @media screen and (max-width: ${theme.breakpoints.tablet - 1}px) {
134
+ grid-column: 1 / 3;
135
+ }
136
+ `;
137
+
138
+ const mobilePrimaryWithPrimaryMetaStyle = css`
139
+ @media screen and (max-width: ${theme.breakpoints.tablet - 1}px) {
140
+ grid-row: 2;
141
+ order: 2;
142
+ }
143
+ `;
144
+
145
+ const mobilePrimaryWithoutPrimaryMetaStyle = css`
146
+ @media screen and (max-width: ${theme.breakpoints.tablet - 1}px) {
147
+ grid-row: 1 / span 2;
148
+ order: 1;
149
+ align-self: center;
150
+ }
151
+ `;
152
+
153
+ const mobilePrimaryMetaStyle = css`
154
+ @media screen and (max-width: ${theme.breakpoints.tablet - 1}px) {
155
+ grid-row: 1;
156
+ order: 1;
157
+ min-height: 18px;
158
+ }
159
+ `;
160
+
161
+ const mobilePrimaryMetaAfterSelectionStyle = css`
162
+ @media screen and (max-width: ${theme.breakpoints.tablet - 1}px) {
163
+ grid-column: 2;
164
+ }
165
+ `;
166
+
167
+ const mobilePrimaryMetaWithoutSelectionStyle = css`
168
+ @media screen and (max-width: ${theme.breakpoints.tablet - 1}px) {
169
+ grid-column: 1 / 3;
170
+ }
171
+ `;
172
+
173
+ const mobileStatusStyle = css`
174
+ @media screen and (max-width: ${theme.breakpoints.tablet - 1}px) {
175
+ grid-column: 3;
176
+ grid-row: 1 / span 2;
177
+ order: 2;
178
+ align-self: center;
179
+ }
180
+ `;
181
+
182
+ const mobileContextMenuStyle = css`
183
+ @media screen and (max-width: ${theme.breakpoints.tablet - 1}px) {
184
+ grid-column: 4;
185
+ grid-row: 1 / span 2;
186
+ order: 3;
187
+ align-self: center;
188
+ }
189
+ `;
190
+
191
+ const mobileFieldStyle = css`
192
+ @media screen and (max-width: ${theme.breakpoints.tablet - 1}px) {
193
+ display: grid;
194
+ grid-template-columns: minmax(90px, 32%) minmax(0, 1fr);
195
+ grid-column: 1 / -1;
196
+ order: 20;
197
+ align-items: start;
198
+ column-gap: ${theme.padding.p16};
199
+ padding: ${theme.padding.p6} 0;
200
+
201
+ &::before {
202
+ content: attr(data-mobile-label);
203
+ color: ${theme.colour.text.secondary};
204
+ font-weight: ${theme.typography.body.sm.fontWeight};
205
+ }
206
+ }
207
+ `;
208
+
209
+ const mobileFirstFieldStyle = css`
210
+ @media screen and (max-width: ${theme.breakpoints.tablet - 1}px) {
211
+ margin-top: ${theme.margin.m16};
212
+ padding-top: ${theme.padding.p12};
213
+ border-top: ${theme.border.b1} solid ${theme.colour.border.default};
214
+ }
215
+ `;
216
+
217
+ const mobilePrimaryActionStyle = css`
218
+ @media screen and (max-width: ${theme.breakpoints.tablet - 1}px) {
219
+ grid-column: 1 / -1;
220
+ order: 30;
221
+ margin-top: ${theme.margin.m8};
222
+ padding-top: ${theme.padding.p12};
223
+ border-top: ${theme.border.b1} solid ${theme.colour.border.default};
224
+ }
225
+ `;
226
+
227
+ const mobileHiddenStyle = css`
228
+ @media screen and (max-width: ${theme.breakpoints.tablet - 1}px) {
229
+ display: none;
230
+ }
68
231
  `;
69
232
 
70
233
  const style = cx(baseStyle, className, NAME);
234
+ const mobileStyle = cx({
235
+ [mobileSelectionStyle]: mobileRole === 'selection',
236
+ [mobilePrimaryStyle]: mobileRole === 'primary',
237
+ [mobilePrimaryAfterSelectionStyle]:
238
+ mobileRole === 'primary' && __mobileHasSelection,
239
+ [mobilePrimaryWithoutSelectionStyle]:
240
+ mobileRole === 'primary' && !__mobileHasSelection,
241
+ [mobilePrimaryWithPrimaryMetaStyle]:
242
+ mobileRole === 'primary' && __mobileHasPrimaryMeta,
243
+ [mobilePrimaryWithoutPrimaryMetaStyle]:
244
+ mobileRole === 'primary' && !__mobileHasPrimaryMeta,
245
+ [mobilePrimaryMetaStyle]: mobileRole === 'primaryMeta',
246
+ [mobilePrimaryMetaAfterSelectionStyle]:
247
+ mobileRole === 'primaryMeta' && __mobileHasSelection,
248
+ [mobilePrimaryMetaWithoutSelectionStyle]:
249
+ mobileRole === 'primaryMeta' && !__mobileHasSelection,
250
+ [mobileStatusStyle]: mobileRole === 'status',
251
+ [mobileContextMenuStyle]: mobileRole === 'contextMenu',
252
+ [mobileFieldStyle]: mobileRole === 'field',
253
+ [mobileFirstFieldStyle]: mobileRole === 'field' && __mobileIsFirstBodyField,
254
+ [mobilePrimaryActionStyle]: mobileRole === 'primaryAction',
255
+ [mobileHiddenStyle]: mobileRole === 'hidden',
256
+ });
71
257
 
72
258
  return (
73
259
  <td
74
- className={style}
260
+ className={cx(style, mobileStyle)}
75
261
  data-testid={testId}
262
+ data-mobile-role={mobileRole}
263
+ data-mobile-label={mobileLabel}
76
264
  {...props}
77
265
  >
78
266
  <CellContent
79
267
  variant={variant}
268
+ mobileRole={mobileRole}
80
269
  icon={icon}
81
270
  checked={checked}
82
271
  handleCheckboxChange={handleCheckboxChange}
@@ -4,10 +4,14 @@ import type { CheckboxProps } from '../../../Checkbox/Checkbox';
4
4
  import Button from '../../../Button';
5
5
  import type { ButtonProps } from '../../../Button';
6
6
  import { useTheme } from '../../../../theme';
7
- import type { ColumnVariant } from '../../Table.types';
7
+ import type {
8
+ ColumnVariant,
9
+ NormalizedTableMobileRole,
10
+ } from '../../Table.types';
8
11
 
9
12
  interface CellContentProps extends React.HTMLAttributes<HTMLDivElement> {
10
13
  variant: ColumnVariant;
14
+ mobileRole: NormalizedTableMobileRole;
11
15
  icon?: React.ReactNode;
12
16
  checked?: boolean;
13
17
  checkboxProps?: Omit<CheckboxProps, 'checked' | 'onChange'>;
@@ -23,6 +27,7 @@ const NAME = 'ucl-uikit-table__cell-content';
23
27
 
24
28
  const CellContent = ({
25
29
  variant,
30
+ mobileRole,
26
31
  icon,
27
32
  checked,
28
33
  checkboxProps,
@@ -44,11 +49,11 @@ const CellContent = ({
44
49
 
45
50
  const variantStyles = {
46
51
  default: css`
47
- font-weight: ${theme.font.weight.regular};
52
+ font-weight: ${theme.typography.body.sm.fontWeight};
48
53
  `,
49
54
  numeric: css`
50
55
  justify-content: flex-end;
51
- font-weight: ${theme.font.weight.regular};
56
+ font-weight: ${theme.typography.body.sm.fontWeight};
52
57
  `,
53
58
  checkbox: css`
54
59
  justify-content: flex-end;
@@ -61,13 +66,68 @@ const CellContent = ({
61
66
  height: auto;
62
67
  `;
63
68
 
69
+ const mobileStyle = css`
70
+ @media screen and (max-width: ${theme.breakpoints.tablet - 1}px) {
71
+ align-items: flex-start;
72
+ justify-content: flex-start;
73
+ min-width: 0;
74
+ height: auto;
75
+ padding-right: 0;
76
+ }
77
+ `;
78
+
79
+ const mobilePrimaryStyle = css`
80
+ @media screen and (max-width: ${theme.breakpoints.tablet - 1}px) {
81
+ display: -webkit-box;
82
+ overflow: hidden;
83
+ color: ${theme.colour.text.default};
84
+ font-family: ${theme.typography.body.md.fontFamily};
85
+ font-feature-settings: ${theme.typography.body.md.fontSettings};
86
+ font-size: ${theme.typography.body.md.fontSize}px;
87
+ line-height: ${theme.typography.body.md.lineHeight}%;
88
+ font-weight: ${theme.typography.body.md.fontWeight};
89
+ -webkit-box-orient: vertical;
90
+ -webkit-line-clamp: 2;
91
+ }
92
+ `;
93
+
94
+ const mobilePrimaryMetaStyle = css`
95
+ @media screen and (max-width: ${theme.breakpoints.tablet - 1}px) {
96
+ color: ${theme.colour.text.secondary};
97
+ font-family: ${theme.typography.body.xs.fontFamily};
98
+ font-feature-settings: ${theme.typography.body.xs.fontSettings};
99
+ font-size: ${theme.typography.body.xs.fontSize}px;
100
+ font-weight: ${theme.typography.body.xs.fontWeight};
101
+ line-height: ${theme.typography.body.xs.lineHeight}%;
102
+ }
103
+ `;
104
+
105
+ const mobilePrimaryActionStyle = css`
106
+ @media screen and (max-width: ${theme.breakpoints.tablet - 1}px) {
107
+ color: ${theme.colour.link.visited};
108
+ font-weight: ${theme.typography.body.sm.fontWeight};
109
+ }
110
+ `;
111
+
112
+ const mobileHeaderTrailingStyle = css`
113
+ @media screen and (max-width: ${theme.breakpoints.tablet - 1}px) {
114
+ justify-content: flex-end;
115
+ }
116
+ `;
117
+
64
118
  const style = cx(
65
119
  baseStyle,
66
120
  {
67
121
  [variantStyles.default]: variant === 'default',
68
122
  [variantStyles.numeric]: variant === 'numeric',
69
123
  [variantStyles.checkbox]: variant === 'checkbox',
124
+ [mobilePrimaryStyle]: mobileRole === 'primary',
125
+ [mobilePrimaryMetaStyle]: mobileRole === 'primaryMeta',
126
+ [mobilePrimaryActionStyle]: mobileRole === 'primaryAction',
127
+ [mobileHeaderTrailingStyle]:
128
+ mobileRole === 'status' || mobileRole === 'contextMenu',
70
129
  },
130
+ mobileStyle,
71
131
  NAME
72
132
  );
73
133