@arbor-education/design-system.components 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -1
- package/dist/components/button/Button.d.ts +2 -1
- package/dist/components/button/Button.d.ts.map +1 -1
- package/dist/components/button/Button.js.map +1 -1
- package/dist/components/card/Card.d.ts +4 -4
- package/dist/components/card/Card.d.ts.map +1 -1
- package/dist/components/card/Card.js +3 -3
- package/dist/components/card/Card.js.map +1 -1
- package/dist/components/card/Card.test.js +2 -2
- package/dist/components/card/Card.test.js.map +1 -1
- package/dist/components/pill/Pill.d.ts +3 -3
- package/dist/components/pill/Pill.d.ts.map +1 -1
- package/dist/components/pill/Pill.js +18 -3
- package/dist/components/pill/Pill.js.map +1 -1
- package/dist/components/pill/Pill.stories.d.ts +11 -1
- package/dist/components/pill/Pill.stories.d.ts.map +1 -1
- package/dist/components/pill/Pill.stories.js +11 -1
- package/dist/components/pill/Pill.stories.js.map +1 -1
- package/dist/components/pill/Pill.test.d.ts.map +1 -1
- package/dist/components/pill/Pill.test.js +47 -11
- package/dist/components/pill/Pill.test.js.map +1 -1
- package/dist/components/table/Table.d.ts +3 -0
- package/dist/components/table/Table.d.ts.map +1 -1
- package/dist/components/table/Table.js +11 -2
- package/dist/components/table/Table.js.map +1 -1
- package/dist/components/table/Table.stories.d.ts +1 -0
- package/dist/components/table/Table.stories.d.ts.map +1 -1
- package/dist/components/table/Table.stories.js +46 -1
- package/dist/components/table/Table.stories.js.map +1 -1
- package/dist/components/table/Table.test.js +62 -0
- package/dist/components/table/Table.test.js.map +1 -1
- package/dist/components/table/cellRenderers/ButtonCellRenderer.d.ts +8 -0
- package/dist/components/table/cellRenderers/ButtonCellRenderer.d.ts.map +1 -0
- package/dist/components/table/cellRenderers/ButtonCellRenderer.js +8 -0
- package/dist/components/table/cellRenderers/ButtonCellRenderer.js.map +1 -0
- package/dist/components/tag/Tag.d.ts +8 -0
- package/dist/components/tag/Tag.d.ts.map +1 -0
- package/dist/components/tag/Tag.js +6 -0
- package/dist/components/tag/Tag.js.map +1 -0
- package/dist/components/tag/Tag.stories.d.ts +8 -0
- package/dist/components/tag/Tag.stories.d.ts.map +1 -0
- package/dist/components/tag/Tag.stories.js +10 -0
- package/dist/components/tag/Tag.stories.js.map +1 -0
- package/dist/components/tag/Tag.test.d.ts +2 -0
- package/dist/components/tag/Tag.test.d.ts.map +1 -0
- package/dist/components/tag/Tag.test.js +20 -0
- package/dist/components/tag/Tag.test.js.map +1 -0
- package/dist/index.css +60 -8
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/button/Button.tsx +2 -1
- package/src/components/card/Card.test.tsx +3 -3
- package/src/components/card/Card.tsx +6 -6
- package/src/components/pill/Pill.stories.tsx +10 -0
- package/src/components/pill/Pill.test.tsx +50 -11
- package/src/components/pill/Pill.tsx +35 -11
- package/src/components/pill/pill.scss +32 -24
- package/src/components/table/Table.stories.tsx +50 -1
- package/src/components/table/Table.test.tsx +64 -0
- package/src/components/table/Table.tsx +8 -0
- package/src/components/table/cellRenderers/ButtonCellRenderer.tsx +12 -0
- package/src/components/tag/Tag.stories.tsx +14 -0
- package/src/components/tag/Tag.test.tsx +21 -0
- package/src/components/tag/Tag.tsx +24 -0
- package/src/components/tag/tag.scss +51 -0
- package/src/index.scss +1 -0
- package/src/index.ts +1 -0
|
@@ -8,6 +8,16 @@ const meta: Meta<typeof Pill> = {
|
|
|
8
8
|
|
|
9
9
|
export const Default = {
|
|
10
10
|
args: {
|
|
11
|
+
text: 'Default',
|
|
12
|
+
onclick: () => { console.log('Pill clicked'); },
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const withCheckbox = {
|
|
17
|
+
args: {
|
|
18
|
+
text: 'Checkbox',
|
|
19
|
+
checkbox: true,
|
|
20
|
+
onclick: () => { console.log('Pill with checkbox clicked'); },
|
|
11
21
|
},
|
|
12
22
|
};
|
|
13
23
|
|
|
@@ -1,21 +1,60 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { render, screen } from '@testing-library/react';
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
3
|
import { Pill } from './Pill';
|
|
4
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
4
5
|
import '@testing-library/jest-dom/vitest';
|
|
5
6
|
|
|
6
7
|
describe('Pill', () => {
|
|
7
|
-
|
|
8
|
-
render(<Pill text="
|
|
9
|
-
expect(screen.getByText(
|
|
8
|
+
it('renders text', () => {
|
|
9
|
+
render(<Pill text="Test Pill" />);
|
|
10
|
+
expect(screen.getByText('Test Pill')).toBeInTheDocument();
|
|
10
11
|
});
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
render(<Pill text="
|
|
14
|
-
|
|
13
|
+
it('toggles active state on click (no checkbox)', () => {
|
|
14
|
+
render(<Pill text="Test Pill" />);
|
|
15
|
+
const pill = screen.getByText('Test Pill');
|
|
16
|
+
expect(pill).toHaveClass('ds-pill__inactive');
|
|
17
|
+
fireEvent.click(screen.getByText('Test Pill'));
|
|
18
|
+
expect(pill).toHaveClass('ds-pill__active');
|
|
19
|
+
fireEvent.click(screen.getByText('Test Pill'));
|
|
20
|
+
expect(pill).toHaveClass('ds-pill__inactive');
|
|
15
21
|
});
|
|
16
22
|
|
|
17
|
-
|
|
18
|
-
render(<Pill text="
|
|
19
|
-
expect(screen.getByText(
|
|
23
|
+
it('renders with checkbox', () => {
|
|
24
|
+
render(<Pill text="Check Me" checkbox />);
|
|
25
|
+
expect(screen.getByText('Check Me')).toBeInTheDocument();
|
|
26
|
+
expect(screen.getByRole('checkbox')).toBeInTheDocument();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('toggles checked state on pill click (with checkbox)', () => {
|
|
30
|
+
render(<Pill text="Check Me" checkbox />);
|
|
31
|
+
const pill = screen.getByText('Check Me').closest('.ds-pill');
|
|
32
|
+
const checkbox = screen.getByRole('checkbox');
|
|
33
|
+
expect(pill).toHaveClass('ds-pill__unchecked');
|
|
34
|
+
expect(checkbox).not.toBeChecked();
|
|
35
|
+
fireEvent.click(screen.getByText('Check Me'));
|
|
36
|
+
expect(pill).toHaveClass('ds-pill__checked');
|
|
37
|
+
expect(checkbox).toBeChecked();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('toggles checked state on checkbox click only (with checkbox)', () => {
|
|
41
|
+
render(<Pill text="Check Me" checkbox />);
|
|
42
|
+
const pill = screen.getByText('Check Me').closest('.ds-pill');
|
|
43
|
+
const checkbox = screen.getByRole('checkbox');
|
|
44
|
+
fireEvent.click(checkbox);
|
|
45
|
+
expect(pill).toHaveClass('ds-pill__checked');
|
|
46
|
+
expect(checkbox).toBeChecked();
|
|
47
|
+
fireEvent.click(checkbox);
|
|
48
|
+
expect(pill).toHaveClass('ds-pill__unchecked');
|
|
49
|
+
expect(checkbox).not.toBeChecked();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('calls onclick callback with correct checked value', () => {
|
|
53
|
+
const onClick = vi.fn();
|
|
54
|
+
render(<Pill text="Test Pill" onclick={onClick} />);
|
|
55
|
+
fireEvent.click(screen.getByText('Test Pill'));
|
|
56
|
+
expect(onClick).toHaveBeenCalledWith(true);
|
|
57
|
+
fireEvent.click(screen.getByText('Test Pill'));
|
|
58
|
+
expect(onClick).toHaveBeenCalledWith(false);
|
|
20
59
|
});
|
|
21
60
|
});
|
|
@@ -1,23 +1,47 @@
|
|
|
1
1
|
import classNames from 'classnames';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
| 'blue'
|
|
5
|
-
| 'green'
|
|
6
|
-
| 'purple'
|
|
7
|
-
| 'teal'
|
|
8
|
-
| 'salmon'
|
|
9
|
-
| 'yellow';
|
|
2
|
+
import { CheckboxInput } from 'Components/formField/inputs/checkbox/CheckboxInput';
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
10
4
|
|
|
11
5
|
type PillProps = {
|
|
12
6
|
text: string;
|
|
13
|
-
|
|
7
|
+
checkbox?: boolean;
|
|
8
|
+
onclick?: (checked: boolean) => void;
|
|
14
9
|
};
|
|
15
10
|
|
|
16
|
-
export const Pill = ({ text,
|
|
11
|
+
export const Pill = ({ text, checkbox, onclick }: PillProps) => {
|
|
12
|
+
const [checked, setChecked] = useState(false);
|
|
13
|
+
|
|
14
|
+
const handlePillClick = () => {
|
|
15
|
+
setChecked(prev => !prev);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const handleCheckboxClick = (event: React.MouseEvent) => {
|
|
19
|
+
event.stopPropagation();
|
|
20
|
+
setChecked(prev => !prev);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (onclick) {
|
|
25
|
+
onclick(checked);
|
|
26
|
+
}
|
|
27
|
+
}, [checked, onclick]);
|
|
28
|
+
|
|
17
29
|
return (
|
|
18
30
|
<span
|
|
19
|
-
|
|
31
|
+
onClick={handlePillClick}
|
|
32
|
+
className={classNames(
|
|
33
|
+
'ds-pill',
|
|
34
|
+
checkbox ? { 'ds-pill__checked': checked, 'ds-pill__unchecked': !checked } : { 'ds-pill__active': checked, 'ds-pill__inactive': !checked },
|
|
35
|
+
)}
|
|
20
36
|
>
|
|
37
|
+
{checkbox && (
|
|
38
|
+
<span className={classNames('ds-pill__checkbox')} onClick={e => e.stopPropagation()}>
|
|
39
|
+
<CheckboxInput
|
|
40
|
+
checked={checked}
|
|
41
|
+
onClick={handleCheckboxClick}
|
|
42
|
+
/>
|
|
43
|
+
</span>
|
|
44
|
+
)}
|
|
21
45
|
{text}
|
|
22
46
|
</span>
|
|
23
47
|
);
|
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
align-items: center;
|
|
5
5
|
gap: var(--tag-spacing-gap-horizontal);
|
|
6
6
|
border-radius: var(--tag-radius);
|
|
7
|
+
border: 1px solid var(--pill-single-filter-default-color-border);
|
|
7
8
|
flex-grow: 0;
|
|
8
9
|
width: fit-content;
|
|
10
|
+
cursor: pointer;
|
|
9
11
|
|
|
10
12
|
/* typography/body/p1-reg */
|
|
11
13
|
font-family: var(--type-body-p-family, Inter);
|
|
@@ -13,39 +15,45 @@
|
|
|
13
15
|
font-style: normal;
|
|
14
16
|
font-weight: var(--type-body-p-weight);
|
|
15
17
|
line-height: 150%; /* 19.5px */
|
|
16
|
-
|
|
17
|
-
&--orange {
|
|
18
|
-
color: var(--tag-category-orange-color-text);
|
|
19
|
-
background: var(--tag-category-orange-color-background);
|
|
20
|
-
}
|
|
21
18
|
|
|
22
|
-
|
|
23
|
-
color: var(--
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
&__inactive{
|
|
20
|
+
background-color: var(--pill-single-filter-default-color-background);
|
|
21
|
+
border-color: var(--pill-single-filter-default-color-border);
|
|
22
|
+
color: var(--pill-single-filter-default-color-text);
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
&:hover{
|
|
25
|
+
color: var(--pill-single-filter-hover-color-text);
|
|
26
|
+
border-color: var(--pill-single-filter-hover-color-border);
|
|
27
|
+
background-color: var(--pill-single-filter-hover-color-background);
|
|
28
|
+
}
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
color: var(--
|
|
34
|
-
|
|
31
|
+
&__active{
|
|
32
|
+
background-color: var(--pill-single-filter-active-color-background);
|
|
33
|
+
border-color: var(--pill-single-filter-active-color-border);
|
|
34
|
+
color: var(--pill-single-filter-active-color-text);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
color: var(--
|
|
39
|
-
|
|
37
|
+
&__unchecked{
|
|
38
|
+
background-color: var(--pill-checkbox-default-color-background);
|
|
39
|
+
border-color: var(--pill-checkbox-default-color-border);
|
|
40
|
+
color: var(--pill-checkbox-default-color-text);
|
|
41
|
+
|
|
42
|
+
&:hover{
|
|
43
|
+
background-color: var(--pill-checkbox-hover-color-background);
|
|
44
|
+
color: var(--pill-checkbox-hover-color-icon);
|
|
45
|
+
border-color: var(--pill-checkbox-hover-color-border);
|
|
46
|
+
}
|
|
40
47
|
}
|
|
41
48
|
|
|
42
|
-
|
|
43
|
-
color: var(--
|
|
44
|
-
|
|
49
|
+
&__checked{
|
|
50
|
+
background-color: var(--pill-checkbox-selected-color-background);
|
|
51
|
+
border-color: var(--pill-checkbox-selected-color-border);
|
|
52
|
+
color: var(--pill-checkbox-selected-color-text);
|
|
45
53
|
}
|
|
46
54
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
55
|
+
&__checkbox{
|
|
56
|
+
display: flex;
|
|
57
|
+
align-items: center;
|
|
50
58
|
}
|
|
51
59
|
}
|
|
@@ -47,7 +47,16 @@ const defaultColDef: ColDef = {
|
|
|
47
47
|
const sampleColumnDefs: (ColDef | ColGroupDef)[] = [
|
|
48
48
|
{
|
|
49
49
|
headerName: 'Details',
|
|
50
|
-
children: [{
|
|
50
|
+
children: [{
|
|
51
|
+
field: 'name',
|
|
52
|
+
headerTooltip: 'The name of the user',
|
|
53
|
+
}, {
|
|
54
|
+
field: 'email',
|
|
55
|
+
headerTooltip: 'The email of the user',
|
|
56
|
+
}, {
|
|
57
|
+
field: 'role',
|
|
58
|
+
headerTooltip: 'The role of the user',
|
|
59
|
+
}],
|
|
51
60
|
},
|
|
52
61
|
{ field: 'status' },
|
|
53
62
|
];
|
|
@@ -304,4 +313,44 @@ export const WithServerSidePagination: StoryObj<TableProps> = {
|
|
|
304
313
|
},
|
|
305
314
|
};
|
|
306
315
|
|
|
316
|
+
const sampleColumnDefsWithButtonCellRenderer: (ColDef | ColGroupDef)[] = [
|
|
317
|
+
{
|
|
318
|
+
headerName: 'Details',
|
|
319
|
+
children: [{
|
|
320
|
+
field: 'name',
|
|
321
|
+
headerTooltip: 'The name of the user',
|
|
322
|
+
cellRenderer: 'dsButtonCellRenderer',
|
|
323
|
+
editable: false,
|
|
324
|
+
}, {
|
|
325
|
+
field: 'email',
|
|
326
|
+
headerTooltip: 'The email of the user',
|
|
327
|
+
}, {
|
|
328
|
+
field: 'role',
|
|
329
|
+
headerTooltip: 'The role of the user',
|
|
330
|
+
}],
|
|
331
|
+
},
|
|
332
|
+
{ field: 'status' },
|
|
333
|
+
];
|
|
334
|
+
|
|
335
|
+
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => alert(`clicked on the button ${e.currentTarget.value}`);
|
|
336
|
+
|
|
337
|
+
const sampleDataWithButtonCellRenderer = [
|
|
338
|
+
{ id: 1, name: { children: 'Alice Johnson', value: 'Alice Johnson', onClick: handleClick }, email: 'alice.johnson@example.com', role: 'Developer', status: 'Active' },
|
|
339
|
+
{ id: 2, name: { children: 'Bob Smith', variant: 'secondary', value: 'Bob Smith', onClick: handleClick }, email: 'bob.smith@example.com', role: 'Designer', status: 'Active' },
|
|
340
|
+
{ id: 3, name: { children: 'Charlie Brown', size: 'S', value: 'Charlie Brown', onClick: handleClick }, email: 'charlie.brown@example.com', role: 'Manager', status: 'Inactive' },
|
|
341
|
+
{ id: 4, name: { children: 'Diana Prince', disabled: true, value: 'Diana Prince', onClick: handleClick }, email: 'diana.prince@example.com', role: 'Developer', status: 'Active' },
|
|
342
|
+
{ id: 5, name: { children: 'Ethan Hunt', iconLeftName: 'download', value: 'Ethan Hunt', onClick: handleClick }, email: 'ethan.hunt@example.com', role: 'Analyst', status: 'Active' },
|
|
343
|
+
];
|
|
344
|
+
|
|
345
|
+
export const WithButtonCellRenderer: Story = {
|
|
346
|
+
args: {
|
|
347
|
+
rowData: sampleDataWithButtonCellRenderer,
|
|
348
|
+
columnDefs: sampleColumnDefsWithButtonCellRenderer,
|
|
349
|
+
defaultColDef: defaultColDef,
|
|
350
|
+
domLayout: 'autoHeight',
|
|
351
|
+
footerContent: FooterContent,
|
|
352
|
+
pagination: true,
|
|
353
|
+
},
|
|
354
|
+
};
|
|
355
|
+
|
|
307
356
|
export default meta;
|
|
@@ -961,4 +961,68 @@ describe('Table', () => {
|
|
|
961
961
|
});
|
|
962
962
|
});
|
|
963
963
|
});
|
|
964
|
+
|
|
965
|
+
describe('ButtonCellRenderer', () => {
|
|
966
|
+
test('works in table context with column definition', async () => {
|
|
967
|
+
const handleClick = vi.fn();
|
|
968
|
+
const columnDefs = [{
|
|
969
|
+
field: 'action',
|
|
970
|
+
headerName: 'Action',
|
|
971
|
+
cellRenderer: 'dsButtonCellRenderer',
|
|
972
|
+
}];
|
|
973
|
+
const rowData = [{
|
|
974
|
+
action: {
|
|
975
|
+
children: 'Delete',
|
|
976
|
+
variant: 'primary-destructive' as const,
|
|
977
|
+
onClick: handleClick,
|
|
978
|
+
},
|
|
979
|
+
}];
|
|
980
|
+
render(<Table columnDefs={columnDefs} rowData={rowData} />);
|
|
981
|
+
await waitFor(() => expect(screen.getByRole('grid')).toBeInTheDocument());
|
|
982
|
+
await waitFor(() => expect(screen.getByText('Delete')).toBeInTheDocument());
|
|
983
|
+
const button = screen.getByText('Delete');
|
|
984
|
+
await userEvent.click(button);
|
|
985
|
+
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
986
|
+
});
|
|
987
|
+
|
|
988
|
+
test('works with multiple button cells in table', async () => {
|
|
989
|
+
const handleClick1 = vi.fn();
|
|
990
|
+
const handleClick2 = vi.fn();
|
|
991
|
+
const columnDefs = [{
|
|
992
|
+
field: 'name',
|
|
993
|
+
headerName: 'Name',
|
|
994
|
+
}, {
|
|
995
|
+
field: 'action',
|
|
996
|
+
headerName: 'Action',
|
|
997
|
+
cellRenderer: 'dsButtonCellRenderer',
|
|
998
|
+
}];
|
|
999
|
+
const rowData = [
|
|
1000
|
+
{
|
|
1001
|
+
name: 'Item 1',
|
|
1002
|
+
action: {
|
|
1003
|
+
children: 'Edit',
|
|
1004
|
+
onClick: handleClick1,
|
|
1005
|
+
},
|
|
1006
|
+
},
|
|
1007
|
+
{
|
|
1008
|
+
name: 'Item 2',
|
|
1009
|
+
action: {
|
|
1010
|
+
children: 'Delete',
|
|
1011
|
+
variant: 'secondary' as const,
|
|
1012
|
+
onClick: handleClick2,
|
|
1013
|
+
},
|
|
1014
|
+
},
|
|
1015
|
+
];
|
|
1016
|
+
render(<Table columnDefs={columnDefs} rowData={rowData} />);
|
|
1017
|
+
await waitFor(() => expect(screen.getByRole('grid')).toBeInTheDocument());
|
|
1018
|
+
await waitFor(() => {
|
|
1019
|
+
expect(screen.getByText('Edit')).toBeInTheDocument();
|
|
1020
|
+
expect(screen.getByText('Delete')).toBeInTheDocument();
|
|
1021
|
+
});
|
|
1022
|
+
await userEvent.click(screen.getByText('Edit'));
|
|
1023
|
+
expect(handleClick1).toHaveBeenCalledTimes(1);
|
|
1024
|
+
await userEvent.click(screen.getByText('Delete'));
|
|
1025
|
+
expect(handleClick2).toHaveBeenCalledTimes(1);
|
|
1026
|
+
});
|
|
1027
|
+
});
|
|
964
1028
|
});
|
|
@@ -15,6 +15,7 @@ import { HideColumnsDropdown } from './HideColumnsDropdown';
|
|
|
15
15
|
import { useTableSettings, type TableSettings } from './useTableSettings';
|
|
16
16
|
import { setAgGridLicenseKey } from 'Utils/setAgGridLicenseKey';
|
|
17
17
|
import { toggleRowSelectionInCurrentRange } from './toggleRowSelectionInCurrentRange';
|
|
18
|
+
import { ButtonCellRenderer } from './cellRenderers/ButtonCellRenderer';
|
|
18
19
|
|
|
19
20
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
21
|
type TableProps<TData = any> = {
|
|
@@ -71,6 +72,7 @@ export const Table = (props: TableProps) => {
|
|
|
71
72
|
enableSimultaneousRangeAndRowSelection = false,
|
|
72
73
|
disableDragSelect = false,
|
|
73
74
|
onCellSelectionChanged,
|
|
75
|
+
components = {},
|
|
74
76
|
...rest
|
|
75
77
|
} = props;
|
|
76
78
|
|
|
@@ -119,6 +121,7 @@ export const Table = (props: TableProps) => {
|
|
|
119
121
|
</TableHeader>
|
|
120
122
|
)}
|
|
121
123
|
<AgGridReact
|
|
124
|
+
// TODO: make this overridable when we come to do Tidy Table theming
|
|
122
125
|
theme={tableTheme.withParams({
|
|
123
126
|
headerRowBorder: hasColumnBorders,
|
|
124
127
|
rowBorder: hasColumnBorders,
|
|
@@ -154,6 +157,10 @@ export const Table = (props: TableProps) => {
|
|
|
154
157
|
onCellSelectionChanged(event);
|
|
155
158
|
}
|
|
156
159
|
}}
|
|
160
|
+
components={{
|
|
161
|
+
dsButtonCellRenderer: ButtonCellRenderer,
|
|
162
|
+
...components,
|
|
163
|
+
}}
|
|
157
164
|
{...rest}
|
|
158
165
|
{...(hasSearch && { quickFilterText: searchValue })}
|
|
159
166
|
/>
|
|
@@ -174,3 +181,4 @@ Table.PaginationControls = PaginationControls;
|
|
|
174
181
|
Table.RowCountInfo = RowCountInfo;
|
|
175
182
|
Table.BulkActionsDropdown = BulkActionsDropdown;
|
|
176
183
|
Table.HideColumnsDropdown = HideColumnsDropdown;
|
|
184
|
+
Table.ButtonCellRenderer = ButtonCellRenderer;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CustomCellRendererProps } from 'ag-grid-react';
|
|
2
|
+
import { Button, type ButtonProps } from 'Components/button/Button';
|
|
3
|
+
|
|
4
|
+
type ButtonCellRendererProps = CustomCellRendererProps & { value: ButtonProps };
|
|
5
|
+
|
|
6
|
+
export const ButtonCellRenderer = (props: ButtonCellRendererProps) => {
|
|
7
|
+
const { value, valueFormatted } = props;
|
|
8
|
+
|
|
9
|
+
const childToRender = !valueFormatted || valueFormatted === '[object Object]' ? value.children : valueFormatted;
|
|
10
|
+
|
|
11
|
+
return <Button {...value}>{childToRender}</Button>;
|
|
12
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { Tag } from './Tag';
|
|
4
|
+
import '@testing-library/jest-dom/vitest';
|
|
5
|
+
|
|
6
|
+
describe('Tag', () => {
|
|
7
|
+
test('Tag says hello', () => {
|
|
8
|
+
render(<Tag text="Hello I'm a Pill!" />);
|
|
9
|
+
expect(screen.getByText("Hello I'm a Pill!")).toBeInTheDocument();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test('Tag has default color green', () => {
|
|
13
|
+
render(<Tag text="Hello I'm a Pill!" />);
|
|
14
|
+
expect(screen.getByText("Hello I'm a Pill!")).toHaveClass('ds-tag--green');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('Tag has custom color', () => {
|
|
18
|
+
render(<Tag text="Hello I'm a Pill!" color="blue" />);
|
|
19
|
+
expect(screen.getByText("Hello I'm a Pill!")).toHaveClass('ds-tag--blue');
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import classNames from 'classnames';
|
|
2
|
+
|
|
3
|
+
export type TagColor = 'orange'
|
|
4
|
+
| 'blue'
|
|
5
|
+
| 'green'
|
|
6
|
+
| 'purple'
|
|
7
|
+
| 'teal'
|
|
8
|
+
| 'salmon'
|
|
9
|
+
| 'yellow';
|
|
10
|
+
|
|
11
|
+
type TagProps = {
|
|
12
|
+
text: string;
|
|
13
|
+
color?: TagColor;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const Tag = ({ text, color = 'green' }: TagProps) => {
|
|
17
|
+
return (
|
|
18
|
+
<span
|
|
19
|
+
className={classNames('ds-tag', `ds-tag--${color}`)}
|
|
20
|
+
>
|
|
21
|
+
{text}
|
|
22
|
+
</span>
|
|
23
|
+
);
|
|
24
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
.ds-tag {
|
|
2
|
+
display: flex;
|
|
3
|
+
padding: var(--tag-spacing-vertical) var(--tag-spacing-horizontal);
|
|
4
|
+
align-items: center;
|
|
5
|
+
gap: var(--tag-spacing-gap-horizontal);
|
|
6
|
+
border-radius: var(--tag-radius);
|
|
7
|
+
flex-grow: 0;
|
|
8
|
+
width: fit-content;
|
|
9
|
+
|
|
10
|
+
/* typography/body/p1-reg */
|
|
11
|
+
font-family: var(--type-body-p-family, Inter);
|
|
12
|
+
font-size: var(--type-body-p-size);
|
|
13
|
+
font-style: normal;
|
|
14
|
+
font-weight: var(--type-body-p-weight);
|
|
15
|
+
line-height: 150%; /* 19.5px */
|
|
16
|
+
|
|
17
|
+
&--orange {
|
|
18
|
+
color: var(--tag-category-orange-color-text);
|
|
19
|
+
background: var(--tag-category-orange-color-background);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
&--blue {
|
|
23
|
+
color: var(--tag-category-blue-color-text);
|
|
24
|
+
background: var(--tag-category-blue-color-background);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
&--green {
|
|
28
|
+
color: var(--tag-category-green-color-text);
|
|
29
|
+
background: var(--tag-category-green-color-background);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
&--purple {
|
|
33
|
+
color: var(--tag-category-purple-color-text);
|
|
34
|
+
background: var(--tag-category-purple-color-background);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
&--teal {
|
|
38
|
+
color: var(--tag-category-teal-color-text);
|
|
39
|
+
background: var(--tag-category-teal-color-background);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
&--salmon {
|
|
43
|
+
color: var(--tag-category-salmon-color-text);
|
|
44
|
+
background: var(--tag-category-salmon-color-background);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
&--yellow {
|
|
48
|
+
color: var(--tag-category-yellow-color-text);
|
|
49
|
+
background: var(--tag-category-yellow-color-background);
|
|
50
|
+
}
|
|
51
|
+
}
|
package/src/index.scss
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
@use "components/formField/inputs/checkbox/checkboxInput.scss";
|
|
15
15
|
@use "components/formField/inputs/selectDropdown/selectDropdown";
|
|
16
16
|
@use "components/formField/inputs/colourPickerDropdown/colourPickerDropdown.scss";
|
|
17
|
+
@use "components/tag/tag.scss";
|
|
17
18
|
@use "components/pill/pill.scss";
|
|
18
19
|
@use "components/section/section.scss";
|
|
19
20
|
@use "components/tabs/tabs.scss";
|
package/src/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { Heading } from 'Components/heading/Heading';
|
|
|
3
3
|
export { Icon } from 'Components/icon/Icon';
|
|
4
4
|
export { Card } from 'Components/card/Card';
|
|
5
5
|
export { Dropdown } from 'Components/dropdown/Dropdown';
|
|
6
|
+
export { Tag } from 'Components/tag/Tag';
|
|
6
7
|
export { Pill } from 'Components/pill/Pill';
|
|
7
8
|
export { Section } from 'Components/section/Section';
|
|
8
9
|
export { Tabs } from 'Components/tabs/Tabs';
|