@ssa-ui-kit/core 1.0.10 → 1.0.11

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 (28) hide show
  1. package/dist/components/PieChart/PieChart.d.ts +1 -1
  2. package/dist/components/PieChart/PieChartLegend.d.ts +1 -1
  3. package/dist/components/PieChart/PieChartLegendMarker.d.ts +2 -0
  4. package/dist/components/PieChart/types.d.ts +2 -1
  5. package/dist/components/SegmentedPieChart/SegmentedPieChart.d.ts +2 -0
  6. package/dist/components/SegmentedPieChart/colorPalettes.d.ts +2 -0
  7. package/dist/components/SegmentedPieChart/index.d.ts +1 -0
  8. package/dist/components/SegmentedPieChart/stories/fixtures.d.ts +3 -0
  9. package/dist/components/SegmentedPieChart/types.d.ts +37 -0
  10. package/dist/components/index.d.ts +1 -0
  11. package/dist/index.js +1 -1
  12. package/dist/index.js.map +1 -1
  13. package/package.json +1 -1
  14. package/src/components/LinksTabBar/LinksTabBar.spec.tsx +0 -1
  15. package/src/components/PieChart/PieChart.tsx +1 -3
  16. package/src/components/PieChart/PieChartBases.tsx +1 -0
  17. package/src/components/PieChart/PieChartLegend.tsx +7 -1
  18. package/src/components/PieChart/PieChartLegendMarker.tsx +3 -1
  19. package/src/components/PieChart/types.ts +2 -1
  20. package/src/components/SegmentedPieChart/SegmentedPieChart.spec.tsx +29 -0
  21. package/src/components/SegmentedPieChart/SegmentedPieChart.tsx +154 -0
  22. package/src/components/SegmentedPieChart/colorPalettes.ts +13 -0
  23. package/src/components/SegmentedPieChart/index.ts +1 -0
  24. package/src/components/SegmentedPieChart/stories/SegmentedPieChart.stories.tsx +63 -0
  25. package/src/components/SegmentedPieChart/stories/fixtures.ts +147 -0
  26. package/src/components/SegmentedPieChart/types.ts +40 -0
  27. package/src/components/index.ts +1 -0
  28. package/tsbuildcache +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ssa-ui-kit/core",
3
- "version": "1.0.10",
3
+ "version": "1.0.11",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "private": false,
@@ -2,7 +2,6 @@ import { css } from '@emotion/react';
2
2
  import userEvent from '@testing-library/user-event';
3
3
  import { links } from './stories/mockData';
4
4
  import { MemoryRouterDecorator } from './stories/decorators';
5
-
6
5
  import { LinksTabBar } from './index';
7
6
 
8
7
  function setup(Component: React.ElementType) {
@@ -4,7 +4,6 @@ import { PieChartProps } from './types';
4
4
  import { PieChartBase, PieChartTextBase } from './PieChartBases';
5
5
 
6
6
  export const PieChart = ({
7
- data,
8
7
  as,
9
8
  className,
10
9
  title,
@@ -15,7 +14,6 @@ export const PieChart = ({
15
14
  <PieChartBase as={as} className={className}>
16
15
  <div className="pie-chart-wrapper">
17
16
  <ResponsivePie
18
- data={data}
19
17
  isInteractive={false}
20
18
  innerRadius={0.8}
21
19
  enableArcLinkLabels={false}
@@ -29,7 +27,7 @@ export const PieChart = ({
29
27
  arcLinkLabelsThickness={2}
30
28
  arcLinkLabelsColor={{ from: 'color' }}
31
29
  arcLabelsSkipAngle={10}
32
- layers={['arcs']}
30
+ layers={['arcs', 'arcLinkLabels', 'arcLabels']}
33
31
  {...chartProps}
34
32
  />
35
33
  {title && <PieChartTextBase>{title}</PieChartTextBase>}
@@ -17,6 +17,7 @@ export const PieChartTextBase = styled.div`
17
17
  position: absolute;
18
18
  width: 100%;
19
19
  height: 100%;
20
+ pointer-events: none;
20
21
  top: 0;
21
22
  left: 0;
22
23
  display: flex;
@@ -9,6 +9,7 @@ import { PieChartLegendProps } from './types';
9
9
  export const PieChartLegend = ({
10
10
  data,
11
11
  colors,
12
+ backgroundColors,
12
13
  renderLabel,
13
14
  renderValue,
14
15
  markerStyles,
@@ -27,7 +28,12 @@ export const PieChartLegend = ({
27
28
  return (
28
29
  <li key={`tag-${id}`}>
29
30
  <PieChartLegendMarker
30
- color={colors[index] || 'purple'}
31
+ color={
32
+ backgroundColors ? undefined : colors?.[index] || 'purple'
33
+ }
34
+ background={
35
+ backgroundColors ? backgroundColors[index] : undefined
36
+ }
31
37
  as={'span'}
32
38
  css={markerStyles}
33
39
  />
@@ -1,7 +1,7 @@
1
1
  import styled from '@emotion/styled';
2
2
  import Badge from '@components/Badge';
3
3
 
4
- export const PieChartLegendMarker = styled(Badge)`
4
+ export const PieChartLegendMarker = styled(Badge)<{ background?: string }>`
5
5
  display: inline-block;
6
6
 
7
7
  padding: 0;
@@ -9,4 +9,6 @@ export const PieChartLegendMarker = styled(Badge)`
9
9
 
10
10
  width: 8px;
11
11
  height: 8px;
12
+
13
+ background: ${({ background }) => background};
12
14
  `;
@@ -18,7 +18,8 @@ export type PieChartLegendItem = {
18
18
 
19
19
  export interface PieChartLegendProps {
20
20
  data: Array<PieChartLegendItem>;
21
- colors: Array<keyof MainColors>;
21
+ colors?: Array<keyof MainColors>;
22
+ backgroundColors?: Array<string>;
22
23
  renderValue?: (item: PieChartLegendItem) => NonNullable<React.ReactNode>;
23
24
  renderLabel?: (item: PieChartLegendItem) => NonNullable<React.ReactNode>;
24
25
  className?: string;
@@ -0,0 +1,29 @@
1
+ import { SegmentedPieChart } from './index';
2
+ import { balanceData } from './stories/fixtures';
3
+
4
+ const ResponsivePieMock = () => <div data-testid="responsive-pie"></div>;
5
+
6
+ jest.mock('@nivo/pie', () => ({
7
+ PieCustomLayerProps: {},
8
+ ResponsivePie: ResponsivePieMock,
9
+ }));
10
+
11
+ describe('SegmentedPieChart', () => {
12
+ it('Renders with a Legend', () => {
13
+ const { getByTestId, getByRole, getByText } = render(
14
+ <SegmentedPieChart data={balanceData} />,
15
+ );
16
+
17
+ getByTestId('responsive-pie');
18
+ getByText('17737');
19
+
20
+ for (const { label, value, percentage } of balanceData) {
21
+ getByRole('heading', { name: label });
22
+ if (label === 'Other') {
23
+ getByRole('heading', { name: `${value} USD (${percentage}%)` });
24
+ } else {
25
+ getByRole('heading', { name: `${value} ${label} (${percentage}%)` });
26
+ }
27
+ }
28
+ });
29
+ });
@@ -0,0 +1,154 @@
1
+ import { css, useTheme } from '@emotion/react';
2
+ import { pathOr } from '@ssa-ui-kit/utils';
3
+ import { Typography, Wrapper, PieChart, PieChartLegend } from '@components';
4
+ import {
5
+ defaultLegendBackgrounds,
6
+ defaultPieChartColors,
7
+ } from './colorPalettes';
8
+ import { BalanceDataForGraph, SegmentedPieChartProps } from './types';
9
+
10
+ export const SegmentedPieChart = ({
11
+ data,
12
+ pieChartProps,
13
+ pieChartLegendProps,
14
+ legendBackgrounds = defaultLegendBackgrounds,
15
+ pieChartColors = defaultPieChartColors,
16
+ currency = 'USD',
17
+ otherLabel = 'Other',
18
+ }: SegmentedPieChartProps) => {
19
+ const theme = useTheme();
20
+
21
+ const balanceDataForTheGraph: BalanceDataForGraph[] = [];
22
+ let balanceDataTotal = 0;
23
+ data?.forEach((item, itemIndex) => {
24
+ if (item.parts?.length) {
25
+ item.parts?.forEach((part, partIndex) => {
26
+ balanceDataForTheGraph.push({
27
+ mainLabel: item.label,
28
+ mainPercentage: item.percentage,
29
+ partLabel: part.label,
30
+ partPercentage: part.percentage,
31
+ color: pieChartColors[itemIndex][partIndex],
32
+ id: `${itemIndex}${partIndex}`,
33
+ mainId: item.id,
34
+ value: part.percentage,
35
+ });
36
+ });
37
+ } else {
38
+ balanceDataForTheGraph.push({
39
+ mainLabel: item.label,
40
+ mainPercentage: item.percentage,
41
+ color: pieChartColors[itemIndex][0],
42
+ id: `${itemIndex}${0}`,
43
+ mainId: item.id,
44
+ value: item.percentage,
45
+ });
46
+ }
47
+ balanceDataTotal += item.value;
48
+ });
49
+
50
+ return (
51
+ <PieChart
52
+ data={balanceDataForTheGraph}
53
+ animate={true}
54
+ css={{
55
+ width: 500,
56
+ padding: 50,
57
+ }}
58
+ isInteractive
59
+ activeInnerRadiusOffset={0}
60
+ activeOuterRadiusOffset={0}
61
+ tooltip={(point) => {
62
+ const pointData = pathOr<typeof point, BalanceDataForGraph>({}, [
63
+ 'datum',
64
+ 'data',
65
+ ])(point);
66
+ return (
67
+ <Wrapper
68
+ css={{
69
+ background: theme.colors.greyLighter,
70
+ flexDirection: 'column',
71
+ borderRadius: 8,
72
+ padding: 5,
73
+ fontSize: 12,
74
+ fontWeight: 500,
75
+ }}>
76
+ {['main', 'part'].map((item) => {
77
+ if (item === 'part' && !pointData['partLabel']) {
78
+ return null;
79
+ }
80
+ const currentItem =
81
+ item === 'main'
82
+ ? {
83
+ label: pointData['mainLabel'],
84
+ percentage: pointData['mainPercentage'],
85
+ }
86
+ : {
87
+ label: pointData['partLabel'],
88
+ percentage: pointData['partPercentage'],
89
+ };
90
+ return (
91
+ <Wrapper
92
+ key={item}
93
+ css={{
94
+ justifyContent: 'space-between',
95
+ gap: 10,
96
+ }}>
97
+ <span css={{ fontWeight: 600 }}>{currentItem.label}</span>
98
+ <span>{currentItem['percentage']}%</span>
99
+ </Wrapper>
100
+ );
101
+ })}
102
+ </Wrapper>
103
+ );
104
+ }}
105
+ title={
106
+ <Typography
107
+ variant="body2"
108
+ weight="bold"
109
+ color={theme.colors.greyDarker}
110
+ css={css`
111
+ font-size: 20px;
112
+ line-height: 25px;
113
+ `}>
114
+ {balanceDataTotal} &nbsp;
115
+ <Typography
116
+ variant="body2"
117
+ weight="regular"
118
+ as="span"
119
+ color={theme.colors.greyDarker80}
120
+ css={css`
121
+ font-size: 14px;
122
+ `}>
123
+ {currency}
124
+ </Typography>
125
+ </Typography>
126
+ }
127
+ {...pieChartProps}>
128
+ <PieChartLegend
129
+ data={data}
130
+ backgroundColors={legendBackgrounds}
131
+ renderValue={({ value, label, percentage }) =>
132
+ label === otherLabel
133
+ ? value + ` ${currency}` + ` (${percentage}%)`
134
+ : value + ' ' + label + ` (${percentage}%)`
135
+ }
136
+ markerStyles={css`
137
+ width: 10px;
138
+ height: 10px;
139
+ `}
140
+ labelListStyles={css`
141
+ h6 {
142
+ font-weight: 700;
143
+ }
144
+ `}
145
+ valueListStyles={css`
146
+ h6 {
147
+ color: ${theme.colors.greyDarker80};
148
+ }
149
+ `}
150
+ {...pieChartLegendProps}
151
+ />
152
+ </PieChart>
153
+ );
154
+ };
@@ -0,0 +1,13 @@
1
+ export const defaultLegendBackgrounds = [
2
+ 'linear-gradient(90deg, #ED995D 0%, #EDBA5D 100%)',
3
+ 'linear-gradient(247deg, #7599DE 14.71%, #4178E1 85.29%)',
4
+ 'linear-gradient(296deg, #89D996 16.38%, #52C587 83.62%)',
5
+ 'linear-gradient(68deg, #EB7556 12.3%, #F2888E 88.95%)',
6
+ ];
7
+
8
+ export const defaultPieChartColors = [
9
+ ['#ED995D', '#EDAA5D', '#EDBA5D', '#FFCF78', '#FFDFA5'],
10
+ ['#4178E1', '#7599DE', '#8BB2FD', '#A6C4FF', '#CEDFFF'],
11
+ ['#36AB6C', '#52C587', '#89D996', '#A7F3B3', '#C0FFCA'],
12
+ ['#EB7556', '#FF917E', '#F2888E', '#FFA6A8', '#FFD4CB'],
13
+ ];
@@ -0,0 +1 @@
1
+ export * from './SegmentedPieChart';
@@ -0,0 +1,63 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { balanceData, balanceMissedPartsData } from './fixtures';
3
+ import { SegmentedPieChart } from '../SegmentedPieChart';
4
+
5
+ export default {
6
+ title: 'Widgets/SegmentedPieChart',
7
+ component: SegmentedPieChart,
8
+ } as Meta<typeof SegmentedPieChart>;
9
+
10
+ type Args = StoryObj<Partial<Parameters<typeof SegmentedPieChart>[0]>>;
11
+
12
+ const StoryTemplate: Args = {
13
+ render: ({ ...args }) => <SegmentedPieChart data={balanceData} {...args} />,
14
+ };
15
+
16
+ export const AccountExample = {
17
+ ...StoryTemplate,
18
+ args: {},
19
+ };
20
+
21
+ export const CustomColors = {
22
+ ...StoryTemplate,
23
+ args: {
24
+ legendBackgrounds: [
25
+ 'linear-gradient(90deg, #6A9FDC 0%, #85BCE8 100%)',
26
+ 'linear-gradient(247deg, #A34EC6 14.71%, #D678F8 85.29%)',
27
+ 'linear-gradient(296deg, #5FD1E4 16.38%, #7AE4F5 83.62%)',
28
+ 'linear-gradient(68deg, #D77A61 12.3%, #E89C91 88.95%)',
29
+ ],
30
+ pieChartColors: [
31
+ ['#6A9FDC', '#85BCE8', '#A3D7F2', '#BAE7FF', '#D1F2FF'],
32
+ ['#A34EC6', '#D678F8', '#E597FF', '#F5C0FF', '#FFD9FF'],
33
+ ['#5FD1E4', '#7AE4F5', '#A1F3FF', '#C0FFFF', '#D9FFFF'],
34
+ ['#D77A61', '#E89C91', '#F1B5A4', '#FFC3B5', '#FFDACC'],
35
+ ],
36
+ pieChartProps: {
37
+ tooltip: undefined,
38
+ },
39
+ },
40
+ };
41
+
42
+ export const CustomCurrency = {
43
+ ...StoryTemplate,
44
+ args: {
45
+ currency: 'EUR',
46
+ },
47
+ };
48
+
49
+ export const WithoutTooltip = {
50
+ ...StoryTemplate,
51
+ args: {
52
+ pieChartProps: {
53
+ isInteractive: false,
54
+ },
55
+ },
56
+ };
57
+
58
+ export const MissedPartsData = {
59
+ ...StoryTemplate,
60
+ args: {
61
+ data: balanceMissedPartsData,
62
+ },
63
+ };
@@ -0,0 +1,147 @@
1
+ import { BalanceData } from '../types';
2
+
3
+ export const balanceData: BalanceData = [
4
+ {
5
+ id: 1,
6
+ value: 5843.37,
7
+ label: 'BTC',
8
+ percentage: 33,
9
+ parts: [
10
+ {
11
+ label: 'BTC. Option 1',
12
+ percentage: 13,
13
+ value: 2300,
14
+ },
15
+ {
16
+ label: 'BTC. Option 2',
17
+ percentage: 10,
18
+ value: 1800,
19
+ },
20
+ {
21
+ label: 'BTC. Option 3',
22
+ percentage: 10,
23
+ value: 1743.37,
24
+ },
25
+ ],
26
+ },
27
+ {
28
+ id: 2,
29
+ value: 5249.25,
30
+ label: 'ETH',
31
+ percentage: 30,
32
+ parts: [
33
+ {
34
+ label: 'ETH. Option 1',
35
+ percentage: 17,
36
+ value: 2800,
37
+ },
38
+ {
39
+ label: 'ETH. Option 2',
40
+ percentage: 13,
41
+ value: 2449.25,
42
+ },
43
+ ],
44
+ },
45
+ {
46
+ id: 3,
47
+ value: 3825.55,
48
+ label: 'USDT',
49
+ percentage: 22,
50
+ parts: [
51
+ {
52
+ label: 'USDT. Option 1',
53
+ percentage: 5,
54
+ value: 1000,
55
+ },
56
+ {
57
+ label: 'USDT. Option 2',
58
+ percentage: 12,
59
+ value: 1840,
60
+ },
61
+ {
62
+ label: 'USDT. Option 3',
63
+ percentage: 5,
64
+ value: 985.55,
65
+ },
66
+ ],
67
+ },
68
+ {
69
+ id: 4,
70
+ value: 2818.83,
71
+ label: 'Other',
72
+ percentage: 15,
73
+ parts: [
74
+ {
75
+ label: 'Other. Option 1',
76
+ percentage: 7,
77
+ value: 1400,
78
+ },
79
+ {
80
+ label: 'Other. Option 2',
81
+ percentage: 8,
82
+ value: 1418.83,
83
+ },
84
+ ],
85
+ },
86
+ ];
87
+
88
+ export const balanceMissedPartsData: BalanceData = [
89
+ {
90
+ id: 1,
91
+ value: 5843.37,
92
+ label: 'BTC',
93
+ percentage: 33,
94
+ parts: [
95
+ {
96
+ label: 'BTC. Option 1',
97
+ percentage: 13,
98
+ value: 2300,
99
+ },
100
+ {
101
+ label: 'BTC. Option 2',
102
+ percentage: 10,
103
+ value: 1800,
104
+ },
105
+ {
106
+ label: 'BTC. Option 3',
107
+ percentage: 10,
108
+ value: 1743.37,
109
+ },
110
+ ],
111
+ },
112
+ {
113
+ id: 2,
114
+ value: 5249.25,
115
+ label: 'ETH',
116
+ percentage: 30,
117
+ },
118
+ {
119
+ id: 3,
120
+ value: 3825.55,
121
+ label: 'USDT',
122
+ percentage: 22,
123
+ parts: [
124
+ {
125
+ label: 'USDT. Option 1',
126
+ percentage: 5,
127
+ value: 1000,
128
+ },
129
+ {
130
+ label: 'USDT. Option 2',
131
+ percentage: 12,
132
+ value: 1840,
133
+ },
134
+ {
135
+ label: 'USDT. Option 3',
136
+ percentage: 5,
137
+ value: 985.55,
138
+ },
139
+ ],
140
+ },
141
+ {
142
+ id: 4,
143
+ value: 2818.83,
144
+ label: 'Other',
145
+ percentage: 15,
146
+ },
147
+ ];
@@ -0,0 +1,40 @@
1
+ import { CommonProps } from '@global-types/emotion';
2
+ import { MayHaveLabel } from '@nivo/pie';
3
+ import { PieChartLegend, PieChartProps } from '@components';
4
+
5
+ type BalanceDataPartsItem = {
6
+ label: string;
7
+ percentage: number;
8
+ value: number;
9
+ };
10
+
11
+ type BalanceDataItem = {
12
+ id: number;
13
+ value: number;
14
+ label: string;
15
+ percentage: number;
16
+ parts?: BalanceDataPartsItem[];
17
+ };
18
+
19
+ export type BalanceData = Array<BalanceDataItem>;
20
+
21
+ export interface SegmentedPieChartProps extends CommonProps {
22
+ data: BalanceData;
23
+ pieChartProps?: Partial<PieChartProps>;
24
+ pieChartLegendProps?: Partial<React.ComponentProps<typeof PieChartLegend>>;
25
+ legendBackgrounds?: string[];
26
+ pieChartColors?: string[][];
27
+ currency?: string;
28
+ otherLabel?: string;
29
+ }
30
+
31
+ export interface BalanceDataForGraph extends MayHaveLabel {
32
+ mainLabel: string;
33
+ mainPercentage: number;
34
+ partLabel?: string;
35
+ partPercentage?: number;
36
+ id: number | string;
37
+ mainId: number;
38
+ value: number | string;
39
+ color: string;
40
+ }
@@ -97,6 +97,7 @@ export * from './SearchBox';
97
97
  export * from './UserProfile';
98
98
  export * from './AddNewAccountCard';
99
99
  export * from './PieChart';
100
+ export * from './SegmentedPieChart';
100
101
  export * from './CollapsibleNavBar';
101
102
  export * from './Filters';
102
103
  export * from './TableFilters';