@integrigo/integrigo-ui 1.6.17-f → 1.6.17-h
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/jest.config.js +1 -1
- package/lib/index.esm.js +1 -1
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/src/components/atoms/Chip/Chip.stories.d.ts +5 -4
- package/lib/src/components/atoms/Dot/Dot.stories.d.ts +3 -3
- package/lib/src/components/atoms/Icon/Icon.d.ts +1 -0
- package/lib/src/components/atoms/Icon/Icon.stories.d.ts +2 -2
- package/lib/src/components/atoms/Icon/IconAddition.d.ts +5 -5
- package/lib/src/components/atoms/Icon/icons/Eye.d.ts +3 -0
- package/lib/src/components/atoms/Icon/icons/Search.d.ts +3 -0
- package/lib/src/components/molecules/Checkbox/Checkbox.stories.d.ts +4 -4
- package/lib/src/components/molecules/Input/Input.d.ts +8 -8
- package/lib/src/components/molecules/Input/Input.stories.d.ts +9 -9
- package/lib/src/components/molecules/Radio/Radio.stories.d.ts +4 -4
- package/lib/src/components/molecules/Switch/Switch.d.ts +1 -0
- package/lib/src/components/organisms/Table/Table.d.ts +12 -0
- package/lib/src/components/organisms/Table/Table.stories.d.ts +7 -0
- package/lib/src/components/organisms/Table/Table.test.d.ts +1 -0
- package/lib/src/components/organisms/Table/index.d.ts +1 -0
- package/lib/src/components/organisms/index.d.ts +1 -0
- package/lib/src/index.d.ts +4 -4
- package/package.json +7 -6
- package/src/components/atoms/Chip/Chip.stories.tsx +21 -20
- package/src/components/atoms/Icon/Icon.tsx +2 -0
- package/src/components/atoms/Icon/IconAddition.tsx +22 -20
- package/src/components/atoms/Icon/icons/Eye.tsx +9 -0
- package/src/components/atoms/Icon/icons/Search.tsx +9 -0
- package/src/components/molecules/Button/BasicButton.tsx +2 -1
- package/src/components/molecules/Button/Button.tsx +5 -4
- package/src/components/molecules/Input/Input.tsx +51 -47
- package/src/components/molecules/Switch/Switch.stories.tsx +3 -0
- package/src/components/molecules/Switch/Switch.tsx +3 -0
- package/src/components/organisms/Table/Table.stories.tsx +180 -0
- package/src/components/organisms/Table/Table.test.tsx +82 -0
- package/src/components/organisms/Table/Table.tsx +162 -0
- package/src/components/organisms/Table/__snapshots__/Table.test.tsx.snap +101 -0
- package/src/components/organisms/Table/index.ts +1 -0
- package/src/components/organisms/index.ts +3 -2
- package/src/index.ts +4 -4
@@ -0,0 +1,9 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
|
3
|
+
const Search: React.FCS = (props) => (
|
4
|
+
<svg viewBox="0 0 26 26" xmlns="http://www.w3.org/2000/svg" {...props}>
|
5
|
+
<path d="M25.1375 23.3625L20.5 18.7625C22.3001 16.518 23.1719 13.6691 22.936 10.8016C22.7001 7.93413 21.3746 5.26598 19.2319 3.34581C17.0892 1.42564 14.2923 0.39939 11.4162 0.478091C8.54005 0.556791 5.8034 1.73445 3.76893 3.76893C1.73445 5.8034 0.556791 8.54005 0.478091 11.4162C0.39939 14.2923 1.42564 17.0892 3.34581 19.2319C5.26598 21.3746 7.93413 22.7001 10.8016 22.936C13.6691 23.1719 16.518 22.3001 18.7625 20.5L23.3625 25.1C23.4787 25.2172 23.617 25.3102 23.7693 25.3736C23.9216 25.4371 24.085 25.4697 24.25 25.4697C24.415 25.4697 24.5784 25.4371 24.7307 25.3736C24.883 25.3102 25.0213 25.2172 25.1375 25.1C25.3628 24.8669 25.4887 24.5554 25.4887 24.2313C25.4887 23.9071 25.3628 23.5956 25.1375 23.3625ZM11.75 20.5C10.0194 20.5 8.32769 19.9868 6.88876 19.0254C5.44983 18.0639 4.32832 16.6973 3.66606 15.0985C3.00379 13.4996 2.83051 11.7403 3.16813 10.043C3.50575 8.34563 4.33911 6.78653 5.56282 5.56282C6.78653 4.33911 8.34563 3.50575 10.043 3.16813C11.7403 2.83051 13.4996 3.00379 15.0985 3.66606C16.6973 4.32832 18.0639 5.44983 19.0254 6.88876C19.9868 8.32769 20.5 10.0194 20.5 11.75C20.5 14.0706 19.5781 16.2962 17.9372 17.9372C16.2962 19.5781 14.0706 20.5 11.75 20.5Z" fill="#595959"/>
|
6
|
+
</svg>
|
7
|
+
);
|
8
|
+
|
9
|
+
export default Search;
|
@@ -14,7 +14,7 @@ export const sizeVariants = {
|
|
14
14
|
font: '16px',
|
15
15
|
},
|
16
16
|
m: {
|
17
|
-
iconPadding: '
|
17
|
+
iconPadding: '32px',
|
18
18
|
padding: '10px 16px',
|
19
19
|
ghostPadding: '20px',
|
20
20
|
font: '12px',
|
@@ -65,6 +65,7 @@ export const BasicButton = styled.div<{
|
|
65
65
|
padding: ${(p) => sizeVariants[p.sizeVariant].padding};
|
66
66
|
font-weight: var(--font-bold);
|
67
67
|
font-size: ${(p) => sizeVariants[p.sizeVariant].font};
|
68
|
+
line-height: ${(p) => sizeVariants[p.sizeVariant].font};
|
68
69
|
cursor: pointer;
|
69
70
|
overflow: hidden;
|
70
71
|
position: relative;
|
@@ -72,7 +72,7 @@ export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
72
72
|
{...props}
|
73
73
|
>
|
74
74
|
{direction !== 'rtl' && (
|
75
|
-
<IconOffset size={size} ghost={Boolean(props.ghost)}>
|
75
|
+
// <IconOffset size={size} ghost={Boolean(props.ghost)}>
|
76
76
|
<IconAddition
|
77
77
|
icon={icon}
|
78
78
|
size={size}
|
@@ -81,7 +81,7 @@ export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
81
81
|
direction={direction}
|
82
82
|
onClick={onIconClick}
|
83
83
|
/>
|
84
|
-
</IconOffset>
|
84
|
+
// </IconOffset>
|
85
85
|
)}
|
86
86
|
|
87
87
|
<ButtonComponent
|
@@ -103,7 +103,7 @@ export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
103
103
|
</ButtonComponent>
|
104
104
|
|
105
105
|
{direction === 'rtl' && (
|
106
|
-
<IconOffset size={size} ghost={Boolean(props.ghost)} right>
|
106
|
+
// <IconOffset size={size} ghost={Boolean(props.ghost)} right>
|
107
107
|
<IconAddition
|
108
108
|
icon={icon}
|
109
109
|
size={size}
|
@@ -112,7 +112,7 @@ export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
112
112
|
direction={direction}
|
113
113
|
onClick={onIconClick}
|
114
114
|
/>
|
115
|
-
</IconOffset>
|
115
|
+
// </IconOffset>
|
116
116
|
)}
|
117
117
|
</ButtonWrapper>
|
118
118
|
);
|
@@ -152,6 +152,7 @@ const IconOffset = styled.div<{
|
|
152
152
|
}>`
|
153
153
|
position: absolute;
|
154
154
|
bottom: 0;
|
155
|
+
|
155
156
|
${(p) =>
|
156
157
|
p.right
|
157
158
|
? `right: ${p.ghost ? 0 : sizeVariant[p.size]}`
|
@@ -1,36 +1,36 @@
|
|
1
|
-
import React from
|
2
|
-
import styled, { css, FlattenSimpleInterpolation } from
|
3
|
-
import { FieldProps } from
|
1
|
+
import React from "react";
|
2
|
+
import styled, { css, FlattenSimpleInterpolation } from "styled-components";
|
3
|
+
import { FieldProps } from "formik";
|
4
4
|
|
5
|
-
import { getValidationTypeProps } from
|
6
|
-
import { ValidationType } from
|
7
|
-
import { IconAddition, IconType } from
|
8
|
-
import { Label } from
|
9
|
-
import { FieldLabel, fieldSizeVariants, FieldWrapper } from
|
5
|
+
import { getValidationTypeProps } from "../../../helpers/validation";
|
6
|
+
import { ValidationType } from "../../../types/validation";
|
7
|
+
import { IconAddition, IconType } from "../../atoms/Icon";
|
8
|
+
import { Label } from "../../atoms/Typography/Label";
|
9
|
+
import { FieldLabel, fieldSizeVariants, FieldWrapper } from "../../atoms/Field";
|
10
10
|
|
11
11
|
export type InputProps = Omit<
|
12
|
-
React.InputHTMLAttributes<HTMLInputElement>,
|
13
|
-
|
12
|
+
React.InputHTMLAttributes<HTMLInputElement>,
|
13
|
+
"size"
|
14
14
|
> &
|
15
|
-
FieldProps & {
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
};
|
15
|
+
FieldProps & {
|
16
|
+
label?: string;
|
17
|
+
validationType?: ValidationType;
|
18
|
+
icon?: IconType;
|
19
|
+
size?: "xl" | "l" | "m" | "s";
|
20
|
+
direction?: "ltr" | "rtl";
|
21
|
+
onIconClick?: () => void;
|
22
|
+
};
|
23
23
|
|
24
24
|
const getDirectionPadding = (
|
25
|
-
direction: InputProps[
|
26
|
-
padding: string
|
25
|
+
direction: InputProps["direction"],
|
26
|
+
padding: string
|
27
27
|
): FlattenSimpleInterpolation => {
|
28
28
|
switch (direction) {
|
29
|
-
case
|
29
|
+
case "ltr":
|
30
30
|
return css`
|
31
31
|
padding-left: ${padding};
|
32
32
|
`;
|
33
|
-
case
|
33
|
+
case "rtl":
|
34
34
|
return css`
|
35
35
|
padding-right: ${padding};
|
36
36
|
`;
|
@@ -40,7 +40,7 @@ const getDirectionPadding = (
|
|
40
40
|
};
|
41
41
|
|
42
42
|
export const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
43
|
-
({ icon, label, size =
|
43
|
+
({ icon, label, size = "m", onIconClick, field, ...props }, ref) => (
|
44
44
|
<FieldWrapper withLabel={Boolean(label)} sizeVariant={size}>
|
45
45
|
{label && (
|
46
46
|
<FieldLabel sizeVariant={size}>
|
@@ -48,34 +48,36 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
48
48
|
</FieldLabel>
|
49
49
|
)}
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
51
|
+
<InputWrapper>
|
52
|
+
{props.direction !== "rtl" && (
|
53
|
+
<IconAddition
|
54
|
+
icon={icon}
|
55
|
+
disabled={props.disabled}
|
56
|
+
direction={props.direction}
|
57
|
+
onClick={onIconClick}
|
58
|
+
size={size}
|
59
|
+
/>
|
60
|
+
)}
|
60
61
|
|
61
|
-
|
62
|
+
<InputElement ref={ref} sizeVariant={size} {...field} {...props} />
|
62
63
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
64
|
+
{props.direction === "rtl" && (
|
65
|
+
<IconAddition
|
66
|
+
icon={icon}
|
67
|
+
disabled={props.disabled}
|
68
|
+
direction={props.direction}
|
69
|
+
onClick={onIconClick}
|
70
|
+
/>
|
71
|
+
)}
|
72
|
+
</InputWrapper>
|
71
73
|
</FieldWrapper>
|
72
|
-
)
|
74
|
+
)
|
73
75
|
);
|
74
76
|
|
75
77
|
const InputElement = styled.input<
|
76
|
-
Pick<InputProps,
|
77
|
-
|
78
|
-
}
|
78
|
+
Pick<InputProps, "validationType" | "direction"> & {
|
79
|
+
sizeVariant: "xl" | "l" | "m" | "s";
|
80
|
+
}
|
79
81
|
>`
|
80
82
|
background-color: var(--color-white);
|
81
83
|
border: 2px solid var(--shades-of-grey-80);
|
@@ -105,7 +107,7 @@ Pick<InputProps, 'validationType' | 'direction'> & {
|
|
105
107
|
${(p) =>
|
106
108
|
getDirectionPadding(
|
107
109
|
p.direction,
|
108
|
-
fieldSizeVariants[p.sizeVariant].iconPadding
|
110
|
+
fieldSizeVariants[p.sizeVariant].iconPadding
|
109
111
|
)};
|
110
112
|
|
111
113
|
&:disabled {
|
@@ -117,4 +119,6 @@ Pick<InputProps, 'validationType' | 'direction'> & {
|
|
117
119
|
}
|
118
120
|
`;
|
119
121
|
|
120
|
-
|
122
|
+
const InputWrapper = styled.div`
|
123
|
+
position: relative;
|
124
|
+
`;
|
@@ -11,6 +11,7 @@ const Template: ComponentStory<typeof Switch> = (args) => <Switch {...args} />;
|
|
11
11
|
|
12
12
|
export const TwoOptions = Template.bind({});
|
13
13
|
TwoOptions.args = {
|
14
|
+
onClick: (id) => console.log(id),
|
14
15
|
options: [
|
15
16
|
{ id: "1", name: "One" },
|
16
17
|
{ id: "2", name: "Two" },
|
@@ -19,6 +20,7 @@ TwoOptions.args = {
|
|
19
20
|
|
20
21
|
export const ThreeOptions = Template.bind({});
|
21
22
|
ThreeOptions.args = {
|
23
|
+
onClick: (id) => console.log(id),
|
22
24
|
options: [
|
23
25
|
{ id: "1", name: "One" },
|
24
26
|
{ id: "2", name: "Two" },
|
@@ -28,6 +30,7 @@ ThreeOptions.args = {
|
|
28
30
|
|
29
31
|
export const ThreeWithDisabled = Template.bind({});
|
30
32
|
ThreeWithDisabled.args = {
|
33
|
+
onClick: (id) => console.log(id),
|
31
34
|
options: [
|
32
35
|
{ id: "1", name: "One" },
|
33
36
|
{ id: "2", name: "Two", disabled: true },
|
@@ -12,11 +12,13 @@ export interface SwitchProps {
|
|
12
12
|
| [SwitchOption, SwitchOption]
|
13
13
|
| [SwitchOption, SwitchOption, SwitchOption];
|
14
14
|
active?: SwitchOption["id"];
|
15
|
+
onClick: (id: SwitchOption["id"]) => void;
|
15
16
|
}
|
16
17
|
|
17
18
|
export const Switch: React.FC<SwitchProps> = ({
|
18
19
|
options,
|
19
20
|
active: defaultActive,
|
21
|
+
onClick,
|
20
22
|
}) => {
|
21
23
|
const [active, setActive] = useState(defaultActive);
|
22
24
|
|
@@ -29,6 +31,7 @@ export const Switch: React.FC<SwitchProps> = ({
|
|
29
31
|
}
|
30
32
|
|
31
33
|
setActive(id);
|
34
|
+
onClick(id);
|
32
35
|
};
|
33
36
|
|
34
37
|
return (
|
@@ -0,0 +1,180 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { Table } from './Table';
|
3
|
+
import { ComponentMeta, ComponentStory } from '@storybook/react';
|
4
|
+
|
5
|
+
import {
|
6
|
+
Column,
|
7
|
+
createColumnHelper,
|
8
|
+
} from '@tanstack/react-table';
|
9
|
+
import { Button, Profile } from '../../molecules';
|
10
|
+
|
11
|
+
export default {
|
12
|
+
title: 'Organisms/Table',
|
13
|
+
component: Table,
|
14
|
+
argTypes: {
|
15
|
+
variant: {
|
16
|
+
name: 'Color variant',
|
17
|
+
type: {
|
18
|
+
name: 'string',
|
19
|
+
required: false,
|
20
|
+
},
|
21
|
+
control: {
|
22
|
+
type: 'select',
|
23
|
+
},
|
24
|
+
options: ['primary', 'secondary'],
|
25
|
+
defaultValue: 'primary',
|
26
|
+
},
|
27
|
+
textAlign: {
|
28
|
+
name: 'Text alignment',
|
29
|
+
type: {
|
30
|
+
name: 'string',
|
31
|
+
required: false,
|
32
|
+
},
|
33
|
+
control: {
|
34
|
+
type: 'select',
|
35
|
+
},
|
36
|
+
options: ['left', 'right', 'center'],
|
37
|
+
defaultValue: 'center',
|
38
|
+
},
|
39
|
+
},
|
40
|
+
} as ComponentMeta<typeof Table>;
|
41
|
+
|
42
|
+
export const Primary: ComponentStory<typeof Table> = (args) => {
|
43
|
+
type Person = {
|
44
|
+
firstName: string
|
45
|
+
lastName: string
|
46
|
+
age: number
|
47
|
+
visits: number
|
48
|
+
status: string
|
49
|
+
progress: number
|
50
|
+
};
|
51
|
+
|
52
|
+
const personData: Person[] = [
|
53
|
+
{
|
54
|
+
firstName: 'tanner',
|
55
|
+
lastName: 'linsley',
|
56
|
+
age: 24,
|
57
|
+
visits: 100,
|
58
|
+
status: 'In Relationship',
|
59
|
+
progress: 50,
|
60
|
+
},
|
61
|
+
{
|
62
|
+
firstName: 'tandy',
|
63
|
+
lastName: 'miller',
|
64
|
+
age: 40,
|
65
|
+
visits: 40,
|
66
|
+
status: 'Single',
|
67
|
+
progress: 80,
|
68
|
+
},
|
69
|
+
{
|
70
|
+
firstName: 'joe',
|
71
|
+
lastName: 'dirte',
|
72
|
+
age: 45,
|
73
|
+
visits: 20,
|
74
|
+
status: 'Complicated',
|
75
|
+
progress: 10,
|
76
|
+
},
|
77
|
+
];
|
78
|
+
|
79
|
+
const personColumnHelper = createColumnHelper<Person>();
|
80
|
+
|
81
|
+
const personColumns = [
|
82
|
+
personColumnHelper.accessor('firstName', {
|
83
|
+
cell: info => info.getValue(),
|
84
|
+
footer: info => info.column.id,
|
85
|
+
}),
|
86
|
+
personColumnHelper.accessor(row => row.lastName, {
|
87
|
+
id: 'lastName',
|
88
|
+
cell: info => info.getValue(),
|
89
|
+
header: () => 'Last Name',
|
90
|
+
footer: info => info.column.id,
|
91
|
+
}),
|
92
|
+
personColumnHelper.accessor('age', {
|
93
|
+
header: () => 'Age',
|
94
|
+
cell: info => info.renderValue(),
|
95
|
+
footer: info => info.column.id,
|
96
|
+
}),
|
97
|
+
personColumnHelper.accessor('visits', {
|
98
|
+
header: () => 'Visits',
|
99
|
+
footer: info => info.column.id,
|
100
|
+
}),
|
101
|
+
personColumnHelper.accessor('status', {
|
102
|
+
header: 'Status',
|
103
|
+
footer: info => info.column.id,
|
104
|
+
}),
|
105
|
+
personColumnHelper.accessor('progress', {
|
106
|
+
header: 'Profile Progress',
|
107
|
+
footer: info => info.column.id,
|
108
|
+
}),
|
109
|
+
] as Column<Person>[];
|
110
|
+
|
111
|
+
return (
|
112
|
+
<Table columns={personColumns} data={personData} variant={args.variant} textAlign={args.textAlign}/>
|
113
|
+
);
|
114
|
+
};
|
115
|
+
|
116
|
+
export const WithProfile: ComponentStory<typeof Table> = (args) => {
|
117
|
+
type DataType = {
|
118
|
+
fullName: string;
|
119
|
+
points: number;
|
120
|
+
avatar: string;
|
121
|
+
email: string;
|
122
|
+
};
|
123
|
+
|
124
|
+
const data: DataType[] = [
|
125
|
+
{
|
126
|
+
fullName: 'Tanner Linsley',
|
127
|
+
points: 24,
|
128
|
+
avatar: 'https://img.freepik.com/darmowe-zdjecie/dosc-usmiechnieta-radosnie-kobieta-o-jasnych-wlosach-ubrana-swobodnie-wygladajaca-z-zadowoleniem_176420-15187.jpg?w=1380&t=st=1660198496~exp=1660199096~hmac=7401572065d2cd7bb67d9f43dbde5c116b90aad419b179fffac1196df24869f2',
|
129
|
+
email: 'abc@abc.pl',
|
130
|
+
},
|
131
|
+
{
|
132
|
+
fullName: 'Tandy Miller',
|
133
|
+
points: 80,
|
134
|
+
avatar: 'https://img.freepik.com/darmowe-zdjecie/dosc-usmiechnieta-radosnie-kobieta-o-jasnych-wlosach-ubrana-swobodnie-wygladajaca-z-zadowoleniem_176420-15187.jpg?w=1380&t=st=1660198496~exp=1660199096~hmac=7401572065d2cd7bb67d9f43dbde5c116b90aad419b179fffac1196df24869f2',
|
135
|
+
email: 'def@def.pl',
|
136
|
+
},
|
137
|
+
{
|
138
|
+
fullName: 'Joe Dirte',
|
139
|
+
points: 45,
|
140
|
+
avatar: 'https://img.freepik.com/darmowe-zdjecie/dosc-usmiechnieta-radosnie-kobieta-o-jasnych-wlosach-ubrana-swobodnie-wygladajaca-z-zadowoleniem_176420-15187.jpg?w=1380&t=st=1660198496~exp=1660199096~hmac=7401572065d2cd7bb67d9f43dbde5c116b90aad419b179fffac1196df24869f2',
|
141
|
+
email: 'ghi@ghi.pl',
|
142
|
+
},
|
143
|
+
];
|
144
|
+
|
145
|
+
const profileColumnHelper = createColumnHelper<DataType>();
|
146
|
+
|
147
|
+
const columns = [
|
148
|
+
profileColumnHelper.accessor('fullName', {
|
149
|
+
cell: info => {
|
150
|
+
return (
|
151
|
+
<div style={{ display: 'flex', alignItems: 'center' }}>
|
152
|
+
<div style={{ flexBasis: '20px' }}>{info.row.index + 1}.</div>
|
153
|
+
<Profile
|
154
|
+
name={info.getValue()}
|
155
|
+
src={info.row.original.avatar}
|
156
|
+
>
|
157
|
+
<span>{info.row.original.email}</span>
|
158
|
+
</Profile>
|
159
|
+
</div>
|
160
|
+
);
|
161
|
+
},
|
162
|
+
header: () => 'Team member',
|
163
|
+
footer: info => info.column.id,
|
164
|
+
}),
|
165
|
+
profileColumnHelper.accessor('points', {
|
166
|
+
header: () => 'Points',
|
167
|
+
cell: info => info.renderValue(),
|
168
|
+
footer: info => info.column.id,
|
169
|
+
}),
|
170
|
+
profileColumnHelper.display({
|
171
|
+
header: 'Actions',
|
172
|
+
id: 'Actions',
|
173
|
+
cell: () => <div style={{ width: '30px' }}><Button direction={'ltr'} icon={'edit'} ghost>Edit</Button></div>,
|
174
|
+
}),
|
175
|
+
] as Column<DataType>[];
|
176
|
+
|
177
|
+
return (
|
178
|
+
<Table columns={columns} data={data} variant={args.variant} width={'100%'} textAlign={"left"}/>
|
179
|
+
);
|
180
|
+
};
|
@@ -0,0 +1,82 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { render } from '@testing-library/react';
|
3
|
+
import { Table } from './Table';
|
4
|
+
import { Column, createColumnHelper } from '@tanstack/react-table';
|
5
|
+
|
6
|
+
type Person = {
|
7
|
+
firstName: string
|
8
|
+
lastName: string
|
9
|
+
age: number
|
10
|
+
visits: number
|
11
|
+
status: string
|
12
|
+
progress: number
|
13
|
+
};
|
14
|
+
|
15
|
+
const data: Person[] = [
|
16
|
+
{
|
17
|
+
firstName: 'tanner',
|
18
|
+
lastName: 'linsley',
|
19
|
+
age: 24,
|
20
|
+
visits: 100,
|
21
|
+
status: 'In Relationship',
|
22
|
+
progress: 50,
|
23
|
+
},
|
24
|
+
{
|
25
|
+
firstName: 'tandy',
|
26
|
+
lastName: 'miller',
|
27
|
+
age: 40,
|
28
|
+
visits: 40,
|
29
|
+
status: 'Single',
|
30
|
+
progress: 80,
|
31
|
+
},
|
32
|
+
{
|
33
|
+
firstName: 'joe',
|
34
|
+
lastName: 'dirte',
|
35
|
+
age: 45,
|
36
|
+
visits: 20,
|
37
|
+
status: 'Complicated',
|
38
|
+
progress: 10,
|
39
|
+
},
|
40
|
+
];
|
41
|
+
|
42
|
+
const columnHelper = createColumnHelper<Person>();
|
43
|
+
|
44
|
+
const columns = [
|
45
|
+
columnHelper.accessor('firstName', {
|
46
|
+
cell: info => info.getValue(),
|
47
|
+
footer: info => info.column.id,
|
48
|
+
}),
|
49
|
+
columnHelper.accessor(row => row.lastName, {
|
50
|
+
id: 'lastName',
|
51
|
+
cell: info => info.getValue(),
|
52
|
+
header: () => 'Last Name',
|
53
|
+
footer: info => info.column.id,
|
54
|
+
}),
|
55
|
+
columnHelper.accessor('age', {
|
56
|
+
header: () => 'Age',
|
57
|
+
cell: info => info.renderValue(),
|
58
|
+
footer: info => info.column.id,
|
59
|
+
}),
|
60
|
+
columnHelper.accessor('visits', {
|
61
|
+
header: () => 'Visits',
|
62
|
+
footer: info => info.column.id,
|
63
|
+
}),
|
64
|
+
columnHelper.accessor('status', {
|
65
|
+
header: 'Status',
|
66
|
+
footer: info => info.column.id,
|
67
|
+
}),
|
68
|
+
columnHelper.accessor('progress', {
|
69
|
+
header: 'Profile Progress',
|
70
|
+
footer: info => info.column.id,
|
71
|
+
}),
|
72
|
+
] as Column<Person>[];
|
73
|
+
|
74
|
+
describe('<Table />', () => {
|
75
|
+
it('should render', () => {
|
76
|
+
render(<Table columns={columns} data={data}/>);
|
77
|
+
});
|
78
|
+
it('enabled - should match snapshot', () => {
|
79
|
+
const { container } = render(<Table columns={columns} data={data}/>);
|
80
|
+
expect(container).toMatchSnapshot();
|
81
|
+
});
|
82
|
+
});
|
@@ -0,0 +1,162 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import {
|
3
|
+
Column,
|
4
|
+
flexRender,
|
5
|
+
getCoreRowModel,
|
6
|
+
useReactTable,
|
7
|
+
} from '@tanstack/react-table';
|
8
|
+
import styled from 'styled-components';
|
9
|
+
|
10
|
+
type Variant = 'primary' | 'secondary';
|
11
|
+
type Alignment = 'left' | 'right' | 'center';
|
12
|
+
|
13
|
+
const colorVariant = {
|
14
|
+
primary: {
|
15
|
+
backgroundColor: 'var(--color-orange)',
|
16
|
+
fontColor: 'var(--color-white)',
|
17
|
+
},
|
18
|
+
secondary: {
|
19
|
+
backgroundColor: 'var(--color-navy)',
|
20
|
+
fontColor: 'var(--color-white)',
|
21
|
+
},
|
22
|
+
};
|
23
|
+
|
24
|
+
export interface Props <T extends Record<string, unknown>> extends React.TableHTMLAttributes<HTMLTableElement> {
|
25
|
+
data: T[];
|
26
|
+
columns: Column<T>[];
|
27
|
+
variant?: Variant;
|
28
|
+
textAlign?: Alignment
|
29
|
+
}
|
30
|
+
|
31
|
+
export const Table = <T extends Record<string, unknown>>({
|
32
|
+
data,
|
33
|
+
columns,
|
34
|
+
variant = 'primary',
|
35
|
+
textAlign = 'center',
|
36
|
+
...props
|
37
|
+
}: Props<T>) => {
|
38
|
+
|
39
|
+
const table = useReactTable({
|
40
|
+
data,
|
41
|
+
columns,
|
42
|
+
getCoreRowModel: getCoreRowModel(),
|
43
|
+
});
|
44
|
+
|
45
|
+
return (
|
46
|
+
<div>
|
47
|
+
<StyledTable cellSpacing={0} {...props}>
|
48
|
+
<StyledHead variant={variant} textAlign={textAlign}>
|
49
|
+
{table.getHeaderGroups().map(headerGroup => (
|
50
|
+
<tr key={headerGroup.id}>
|
51
|
+
{headerGroup.headers.map(header => (
|
52
|
+
<th key={header.id}>
|
53
|
+
{header.isPlaceholder
|
54
|
+
? null
|
55
|
+
: flexRender(
|
56
|
+
header.column.columnDef.header,
|
57
|
+
header.getContext(),
|
58
|
+
)}
|
59
|
+
</th>
|
60
|
+
))}
|
61
|
+
</tr>
|
62
|
+
))}
|
63
|
+
</StyledHead>
|
64
|
+
<StyledBody textAlign={textAlign}>
|
65
|
+
{table.getRowModel().rows.map(row => (
|
66
|
+
<tr key={row.id}>
|
67
|
+
{row.getVisibleCells().map(cell => (
|
68
|
+
<td key={cell.id}>
|
69
|
+
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
70
|
+
</td>
|
71
|
+
))}
|
72
|
+
</tr>
|
73
|
+
))}
|
74
|
+
</StyledBody>
|
75
|
+
</StyledTable>
|
76
|
+
</div>
|
77
|
+
);
|
78
|
+
};
|
79
|
+
|
80
|
+
const StyledTable = styled.table`
|
81
|
+
|
82
|
+
`;
|
83
|
+
|
84
|
+
StyledTable.displayName = 'StyledTable';
|
85
|
+
|
86
|
+
const StyledHead = styled.thead<{ variant: Variant, textAlign: Alignment }>`
|
87
|
+
padding: 15px 10px;
|
88
|
+
height: 54px;
|
89
|
+
|
90
|
+
& tr th {
|
91
|
+
font-weight: 700;
|
92
|
+
font-size: 16px;
|
93
|
+
line-height: 24px;
|
94
|
+
padding: 15px 10px;
|
95
|
+
color: white;
|
96
|
+
text-align: ${props => props.textAlign};
|
97
|
+
}
|
98
|
+
|
99
|
+
${(p) => `
|
100
|
+
background-color: ${colorVariant[p.variant].backgroundColor};
|
101
|
+
color: ${colorVariant[p.variant].fontColor};
|
102
|
+
|
103
|
+
& th:first-child {
|
104
|
+
box-shadow: -10px 0px 10px 1px rgba(0, 0, 0, 0.1);
|
105
|
+
border-radius: 5px 0px 0px 0px;
|
106
|
+
}
|
107
|
+
|
108
|
+
& th:last-child {
|
109
|
+
box-shadow: 10px 0px 10px 1px rgba(0, 0, 0, 0.1);
|
110
|
+
border-radius: 0px 5px 0px 0px;
|
111
|
+
}
|
112
|
+
`}
|
113
|
+
`;
|
114
|
+
|
115
|
+
StyledHead.displayName = 'StyledHead';
|
116
|
+
|
117
|
+
const StyledBody = styled.tbody<{ textAlign: Alignment }>`
|
118
|
+
tr, td {
|
119
|
+
//height for td works like min-height. Table cells will grow when the content does not fit.
|
120
|
+
height: 52px;
|
121
|
+
}
|
122
|
+
|
123
|
+
tr td {
|
124
|
+
padding: 10px;
|
125
|
+
text-align: ${props => props.textAlign};
|
126
|
+
}
|
127
|
+
|
128
|
+
tr:nth-child(even) {
|
129
|
+
background-color: var(--shades-of-grey-0);
|
130
|
+
}
|
131
|
+
|
132
|
+
tr:nth-child(odd) {
|
133
|
+
background-color: var(--shades-of-grey-20);
|
134
|
+
}
|
135
|
+
|
136
|
+
tr:hover {
|
137
|
+
background-color: rgba(224, 154, 51, 0.2);
|
138
|
+
|
139
|
+
td {
|
140
|
+
border-top: solid 2px var(--color-orange);
|
141
|
+
border-bottom: solid 2px var(--color-orange);
|
142
|
+
}
|
143
|
+
|
144
|
+
td:first-child {
|
145
|
+
border-left: solid 2px var(--color-orange);
|
146
|
+
border-bottom: solid 2px var(--color-orange);
|
147
|
+
border-top: solid 2px var(--color-orange);
|
148
|
+
border-top-left-radius: 10px;
|
149
|
+
border-bottom-left-radius: 10px;
|
150
|
+
}
|
151
|
+
|
152
|
+
td:last-child {
|
153
|
+
border-right: solid 2px var(--color-orange);
|
154
|
+
border-bottom: solid 2px var(--color-orange);
|
155
|
+
border-top: solid 2px var(--color-orange);
|
156
|
+
border-top-right-radius: 10px;
|
157
|
+
border-bottom-right-radius: 10px;
|
158
|
+
}
|
159
|
+
}
|
160
|
+
`;
|
161
|
+
|
162
|
+
StyledBody.displayName = 'StyledBody';
|