@ssa-ui-kit/core 1.0.11 → 1.0.12

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 (29) hide show
  1. package/dist/components/PieChart/types.d.ts +3 -3
  2. package/dist/components/SegmentedPieChart/SegmentedPieChart.d.ts +1 -1
  3. package/dist/components/SegmentedPieChart/components/ChartTitle.d.ts +4 -0
  4. package/dist/components/SegmentedPieChart/components/ChartTooltip.d.ts +5 -0
  5. package/dist/components/SegmentedPieChart/components/LegendItem.d.ts +2 -0
  6. package/dist/components/SegmentedPieChart/components/index.d.ts +3 -0
  7. package/dist/components/SegmentedPieChart/hooks/index.d.ts +1 -0
  8. package/dist/components/SegmentedPieChart/hooks/useData.d.ts +5 -0
  9. package/dist/components/SegmentedPieChart/stories/fixtures.d.ts +5 -3
  10. package/dist/components/SegmentedPieChart/types.d.ts +29 -16
  11. package/dist/components/SegmentedPieChart/utils.d.ts +1 -0
  12. package/dist/index.js +1 -1
  13. package/dist/index.js.map +1 -1
  14. package/package.json +1 -1
  15. package/src/components/PieChart/PieChart.stories.tsx +2 -2
  16. package/src/components/PieChart/types.ts +3 -3
  17. package/src/components/SegmentedPieChart/SegmentedPieChart.spec.tsx +11 -9
  18. package/src/components/SegmentedPieChart/SegmentedPieChart.tsx +38 -103
  19. package/src/components/SegmentedPieChart/components/ChartTitle.tsx +34 -0
  20. package/src/components/SegmentedPieChart/components/ChartTooltip.tsx +85 -0
  21. package/src/components/SegmentedPieChart/components/LegendItem.tsx +36 -0
  22. package/src/components/SegmentedPieChart/components/index.ts +3 -0
  23. package/src/components/SegmentedPieChart/hooks/index.ts +1 -0
  24. package/src/components/SegmentedPieChart/hooks/useData.ts +71 -0
  25. package/src/components/SegmentedPieChart/stories/SegmentedPieChart.stories.tsx +44 -7
  26. package/src/components/SegmentedPieChart/stories/fixtures.ts +72 -45
  27. package/src/components/SegmentedPieChart/types.ts +37 -16
  28. package/src/components/SegmentedPieChart/utils.ts +2 -0
  29. 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.11",
3
+ "version": "1.0.12",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "private": false,
@@ -88,7 +88,7 @@ export const AccountExample: StoryObj<typeof PieChart> = () => {
88
88
  font-size: 20px;
89
89
  line-height: 25px;
90
90
  `}>
91
- 147358 &nbsp;
91
+ 18183 &nbsp;
92
92
  <Typography
93
93
  variant="body2"
94
94
  weight="regular"
@@ -97,7 +97,7 @@ export const AccountExample: StoryObj<typeof PieChart> = () => {
97
97
  css={css`
98
98
  font-size: 14px;
99
99
  `}>
100
- USD
100
+ USDT
101
101
  </Typography>
102
102
  </Typography>
103
103
  }>
@@ -1,5 +1,5 @@
1
1
  import { SerializedStyles } from '@emotion/react';
2
- import { ResponsivePie } from '@nivo/pie';
2
+ import { ResponsivePie, MayHaveLabel } from '@nivo/pie';
3
3
  import { CommonProps } from '../..';
4
4
 
5
5
  export interface PieChartProps
@@ -9,12 +9,12 @@ export interface PieChartProps
9
9
  children?: React.ReactNode;
10
10
  }
11
11
 
12
- export type PieChartLegendItem = {
12
+ export interface PieChartLegendItem extends MayHaveLabel {
13
13
  id: string | number;
14
14
  value: string | number;
15
15
  label: string;
16
16
  [key: string | number | symbol]: unknown;
17
- };
17
+ }
18
18
 
19
19
  export interface PieChartLegendProps {
20
20
  data: Array<PieChartLegendItem>;
@@ -1,5 +1,5 @@
1
1
  import { SegmentedPieChart } from './index';
2
- import { balanceData } from './stories/fixtures';
2
+ import { balanceData, balanceTotalAmount } from './stories/fixtures';
3
3
 
4
4
  const ResponsivePieMock = () => <div data-testid="responsive-pie"></div>;
5
5
 
@@ -11,19 +11,21 @@ jest.mock('@nivo/pie', () => ({
11
11
  describe('SegmentedPieChart', () => {
12
12
  it('Renders with a Legend', () => {
13
13
  const { getByTestId, getByRole, getByText } = render(
14
- <SegmentedPieChart data={balanceData} />,
14
+ <SegmentedPieChart
15
+ data={balanceData}
16
+ totalAmount={balanceTotalAmount}
17
+ totalDimension="USD"
18
+ />,
15
19
  );
16
20
 
17
21
  getByTestId('responsive-pie');
18
- getByText('17737');
22
+ getByText(balanceTotalAmount);
19
23
 
20
- for (const { label, value, percentage } of balanceData) {
24
+ for (const { label } of balanceData) {
21
25
  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
- }
26
+ getByRole('heading', {
27
+ name: `2819 USDT (16%)`,
28
+ });
27
29
  }
28
30
  });
29
31
  });
@@ -1,11 +1,12 @@
1
1
  import { css, useTheme } from '@emotion/react';
2
- import { pathOr } from '@ssa-ui-kit/utils';
3
- import { Typography, Wrapper, PieChart, PieChartLegend } from '@components';
2
+ import { PieChart, PieChartLegend } from '@components';
4
3
  import {
5
4
  defaultLegendBackgrounds,
6
5
  defaultPieChartColors,
7
6
  } from './colorPalettes';
8
- import { BalanceDataForGraph, SegmentedPieChartProps } from './types';
7
+ import { SegmentedPieChartProps } from './types';
8
+ import { ChartTitle, ChartTooltip, LegendItem } from './components';
9
+ import { useData } from './hooks';
9
10
 
10
11
  export const SegmentedPieChart = ({
11
12
  data,
@@ -13,38 +14,21 @@ export const SegmentedPieChart = ({
13
14
  pieChartLegendProps,
14
15
  legendBackgrounds = defaultLegendBackgrounds,
15
16
  pieChartColors = defaultPieChartColors,
16
- currency = 'USD',
17
+ currency = 'USDT',
17
18
  otherLabel = 'Other',
19
+ totalAmount,
20
+ totalDimension,
21
+ legendValueRoundingDigits = 2,
22
+ legendPercentageRoundingDigits = 0,
23
+ showDimensions = true,
24
+ showPercentage = true,
18
25
  }: SegmentedPieChartProps) => {
19
26
  const theme = useTheme();
20
27
 
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;
28
+ const { balanceDataForTheGraph, balanceDataForTheLegend } = useData({
29
+ data,
30
+ legendValueRoundingDigits,
31
+ pieChartColors,
48
32
  });
49
33
 
50
34
  return (
@@ -52,87 +36,38 @@ export const SegmentedPieChart = ({
52
36
  data={balanceDataForTheGraph}
53
37
  animate={true}
54
38
  css={{
55
- width: 500,
56
- padding: 50,
39
+ width: 400,
40
+ margin: '40px 120px',
57
41
  }}
58
42
  isInteractive
59
43
  activeInnerRadiusOffset={0}
60
44
  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
- }}
45
+ tooltip={(point) => (
46
+ <ChartTooltip
47
+ point={point}
48
+ legendPercentageRoundingDigits={legendPercentageRoundingDigits}
49
+ />
50
+ )}
105
51
  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>
52
+ <ChartTitle totalAmount={totalAmount} totalDimension={totalDimension} />
126
53
  }
127
54
  {...pieChartProps}>
128
55
  <PieChartLegend
129
- data={data}
56
+ data={balanceDataForTheLegend}
130
57
  backgroundColors={legendBackgrounds}
131
- renderValue={({ value, label, percentage }) =>
132
- label === otherLabel
133
- ? value + ` ${currency}` + ` (${percentage}%)`
134
- : value + ' ' + label + ` (${percentage}%)`
135
- }
58
+ renderValue={(props) => (
59
+ <LegendItem
60
+ {...props}
61
+ legendValueRoundingDigits={
62
+ props.legendValueRoundingDigits as number
63
+ }
64
+ legendPercentageRoundingDigits={legendPercentageRoundingDigits}
65
+ showDimensions={showDimensions}
66
+ showPercentage={showPercentage}
67
+ otherLabel={otherLabel}
68
+ currency={currency}
69
+ />
70
+ )}
136
71
  markerStyles={css`
137
72
  width: 10px;
138
73
  height: 10px;
@@ -0,0 +1,34 @@
1
+ import { useTheme, css } from '@emotion/react';
2
+ import Typography from '@components/Typography';
3
+
4
+ export const ChartTitle = ({
5
+ totalAmount,
6
+ totalDimension,
7
+ }: {
8
+ totalAmount: number;
9
+ totalDimension: string;
10
+ }) => {
11
+ const theme = useTheme();
12
+ return (
13
+ <Typography
14
+ variant="body2"
15
+ weight="bold"
16
+ color={theme.colors.greyDarker}
17
+ css={css`
18
+ font-size: 20px;
19
+ line-height: 25px;
20
+ `}>
21
+ {totalAmount} &nbsp;
22
+ <Typography
23
+ variant="body2"
24
+ weight="regular"
25
+ as="span"
26
+ color={theme.colors.greyDarker80}
27
+ css={css`
28
+ font-size: 14px;
29
+ `}>
30
+ {totalDimension}
31
+ </Typography>
32
+ </Typography>
33
+ );
34
+ };
@@ -0,0 +1,85 @@
1
+ import { useTheme } from '@emotion/react';
2
+ import { MayHaveLabel, PieTooltipProps } from '@nivo/pie';
3
+ import { pathOr } from '@ssa-ui-kit/utils';
4
+ import { BalanceDataForGraph } from '../types';
5
+ import { getRoundedNumber } from '../utils';
6
+
7
+ export const ChartTooltip = ({
8
+ point,
9
+ legendPercentageRoundingDigits,
10
+ }: {
11
+ point: PieTooltipProps<MayHaveLabel>;
12
+ legendPercentageRoundingDigits: number;
13
+ }) => {
14
+ const theme = useTheme();
15
+ const pointData = pathOr<typeof point, BalanceDataForGraph>({}, [
16
+ 'datum',
17
+ 'data',
18
+ ])(point);
19
+ const mainData = {
20
+ value:
21
+ typeof pointData.legendValue !== 'undefined'
22
+ ? getRoundedNumber(
23
+ pointData.legendValue,
24
+ pointData.legendValueRoundingDigits,
25
+ )
26
+ : getRoundedNumber(
27
+ pointData.value,
28
+ pointData.legendValueRoundingDigits,
29
+ ),
30
+ label: pointData.legendLabel || pointData.label,
31
+ percentage: getRoundedNumber(
32
+ pointData.percentage,
33
+ legendPercentageRoundingDigits,
34
+ ),
35
+ };
36
+ const partData = {
37
+ value:
38
+ pointData.partLegendValue !== undefined
39
+ ? getRoundedNumber(
40
+ pointData.partLegendValue,
41
+ pointData.legendValueRoundingDigits,
42
+ )
43
+ : getRoundedNumber(
44
+ pointData.partValue,
45
+ pointData.legendValueRoundingDigits,
46
+ ),
47
+ label: pointData.partLabel || pointData.legendLabel || pointData.label,
48
+ percentage: getRoundedNumber(
49
+ pointData.partPercentage,
50
+ legendPercentageRoundingDigits,
51
+ ),
52
+ };
53
+ return (
54
+ <table
55
+ css={{
56
+ background: theme.colors.greyLighter,
57
+ borderRadius: 8,
58
+ padding: 5,
59
+ fontSize: 12,
60
+ fontWeight: 500,
61
+ '& td': {
62
+ whiteSpace: 'nowrap',
63
+ },
64
+ }}>
65
+ <tr>
66
+ <td css={{ fontWeight: 600, padding: '0 5px' }}>{pointData.label}</td>
67
+ <td>
68
+ {mainData.value} {mainData.label}
69
+ </td>
70
+ <td>({mainData.percentage}%)</td>
71
+ </tr>
72
+ {pointData.partLabel && (
73
+ <tr>
74
+ <td css={{ fontWeight: 600, padding: '0 5px' }}>
75
+ {pointData.partLabel}
76
+ </td>
77
+ <td>
78
+ {partData.value} {pointData.legendLabel || pointData.label}
79
+ </td>
80
+ <td>({partData.percentage}%)</td>
81
+ </tr>
82
+ )}
83
+ </table>
84
+ );
85
+ };
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+ import { LegendItemProps } from '../types';
3
+ import { getRoundedNumber } from '../utils';
4
+
5
+ export const LegendItem = ({
6
+ label,
7
+ legendLabel,
8
+ percentage,
9
+ legendValue,
10
+ legendValueRoundingDigits,
11
+ legendPercentageRoundingDigits,
12
+ showDimensions,
13
+ showPercentage,
14
+ otherLabel,
15
+ currency,
16
+ }: LegendItemProps) => {
17
+ const legendValueLocal = getRoundedNumber(
18
+ legendValue,
19
+ legendValueRoundingDigits as number,
20
+ );
21
+ const percentageLocal = getRoundedNumber(
22
+ percentage,
23
+ legendPercentageRoundingDigits as number,
24
+ );
25
+ const dimension = showDimensions
26
+ ? label === otherLabel
27
+ ? (legendLabel as string | undefined) || currency
28
+ : (legendLabel as string | undefined) || label
29
+ : '';
30
+ return (
31
+ <React.Fragment>
32
+ {legendValueLocal} {showDimensions && dimension}
33
+ {showPercentage && ` (${percentageLocal}%)`}
34
+ </React.Fragment>
35
+ );
36
+ };
@@ -0,0 +1,3 @@
1
+ export * from './ChartTooltip';
2
+ export * from './ChartTitle';
3
+ export * from './LegendItem';
@@ -0,0 +1 @@
1
+ export * from './useData';
@@ -0,0 +1,71 @@
1
+ import { propOr } from '@ssa-ui-kit/utils';
2
+ import {
3
+ BalanceDataForGraph,
4
+ SegmentedDataItem,
5
+ SegmentedPieChartProps,
6
+ } from '../types';
7
+ import { defaultPieChartColors } from '../colorPalettes';
8
+
9
+ export const useData = ({
10
+ data,
11
+ pieChartColors = defaultPieChartColors,
12
+ legendValueRoundingDigits,
13
+ }: Pick<
14
+ SegmentedPieChartProps,
15
+ 'data' | 'pieChartColors' | 'legendValueRoundingDigits'
16
+ >) => {
17
+ let calculatedTotalAmount = 0;
18
+ data.forEach((item) => {
19
+ calculatedTotalAmount += Number(item.value);
20
+ });
21
+ const balanceDataForTheGraph: BalanceDataForGraph[] = [];
22
+ const balanceDataForTheLegend: BalanceDataForGraph[] = [];
23
+ data?.forEach((item, itemIndex) => {
24
+ const mainPercentage = (Number(item.value) * 100) / calculatedTotalAmount;
25
+ const newMainItem = {
26
+ value: item.value,
27
+ label: item.label,
28
+ percentage: mainPercentage,
29
+ mainId: Number(item.id),
30
+ legendLabel: item.legendLabel,
31
+ legendValue: item.legendValue,
32
+ legendValueRoundingDigits: propOr<SegmentedDataItem, number>(
33
+ legendValueRoundingDigits,
34
+ 'legendValueRoundingDigits',
35
+ )(item),
36
+ color: pieChartColors[itemIndex][0],
37
+ id: `${itemIndex}0`,
38
+ };
39
+ balanceDataForTheLegend.push(newMainItem);
40
+ if (item.parts?.length) {
41
+ item.parts?.forEach((part, partIndex) => {
42
+ const partPercentage = (part.value * 100) / calculatedTotalAmount;
43
+ balanceDataForTheGraph.push({
44
+ value: item.value,
45
+ label: item.label,
46
+ percentage: mainPercentage,
47
+ mainId: Number(item.id),
48
+ legendLabel: item.legendLabel,
49
+ legendValue: item.legendValue,
50
+ legendValueRoundingDigits: propOr<SegmentedDataItem, number>(
51
+ legendValueRoundingDigits,
52
+ 'legendValueRoundingDigits',
53
+ )(item),
54
+ color: pieChartColors[itemIndex][partIndex],
55
+ id: `${itemIndex}${partIndex}`,
56
+ partIndex,
57
+ partLabel: part.label,
58
+ partPercentage: Number(partPercentage),
59
+ partValue: part.value,
60
+ partLegendValue: part.legendValue,
61
+ });
62
+ });
63
+ } else {
64
+ balanceDataForTheGraph.push(newMainItem);
65
+ }
66
+ });
67
+ return {
68
+ balanceDataForTheGraph,
69
+ balanceDataForTheLegend,
70
+ };
71
+ };
@@ -1,5 +1,10 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react';
2
- import { balanceData, balanceMissedPartsData } from './fixtures';
2
+ import {
3
+ balanceData,
4
+ balanceMissedPartsData,
5
+ balanceMissedPartsDataTotalAmount,
6
+ balanceTotalAmount,
7
+ } from './fixtures';
3
8
  import { SegmentedPieChart } from '../SegmentedPieChart';
4
9
 
5
10
  export default {
@@ -9,8 +14,16 @@ export default {
9
14
 
10
15
  type Args = StoryObj<Partial<Parameters<typeof SegmentedPieChart>[0]>>;
11
16
 
17
+ const currency = 'USDT';
12
18
  const StoryTemplate: Args = {
13
- render: ({ ...args }) => <SegmentedPieChart data={balanceData} {...args} />,
19
+ render: ({ ...args }) => (
20
+ <SegmentedPieChart
21
+ data={balanceData}
22
+ totalAmount={Number(balanceTotalAmount)}
23
+ totalDimension={currency}
24
+ {...args}
25
+ />
26
+ ),
14
27
  };
15
28
 
16
29
  export const AccountExample = {
@@ -33,9 +46,6 @@ export const CustomColors = {
33
46
  ['#5FD1E4', '#7AE4F5', '#A1F3FF', '#C0FFFF', '#D9FFFF'],
34
47
  ['#D77A61', '#E89C91', '#F1B5A4', '#FFC3B5', '#FFDACC'],
35
48
  ],
36
- pieChartProps: {
37
- tooltip: undefined,
38
- },
39
49
  },
40
50
  };
41
51
 
@@ -43,6 +53,26 @@ export const CustomCurrency = {
43
53
  ...StoryTemplate,
44
54
  args: {
45
55
  currency: 'EUR',
56
+ totalDimension: 'PLN',
57
+ totalAmount: 17737.12,
58
+ },
59
+ };
60
+
61
+ CustomCurrency.storyName = 'Custom currency, total dimension and amount';
62
+
63
+ export const MissedPartsData = {
64
+ ...StoryTemplate,
65
+ args: {
66
+ data: balanceMissedPartsData,
67
+ totalAmount: balanceMissedPartsDataTotalAmount,
68
+ },
69
+ };
70
+
71
+ export const PercentageRoundingDigits = {
72
+ ...StoryTemplate,
73
+ args: {
74
+ legendValueRoundingDigits: 1,
75
+ legendPercentageRoundingDigits: 2,
46
76
  },
47
77
  };
48
78
 
@@ -55,9 +85,16 @@ export const WithoutTooltip = {
55
85
  },
56
86
  };
57
87
 
58
- export const MissedPartsData = {
88
+ export const WithoutPercentage = {
59
89
  ...StoryTemplate,
60
90
  args: {
61
- data: balanceMissedPartsData,
91
+ showPercentage: false,
92
+ },
93
+ };
94
+
95
+ export const WithoutDimensions = {
96
+ ...StoryTemplate,
97
+ args: {
98
+ showDimensions: false,
62
99
  },
63
100
  };