@centreon/ui 24.4.72 → 24.4.74

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 (131) hide show
  1. package/package.json +24 -23
  2. package/src/Checkbox/fonts/roboto-bold-webfont.ttf +0 -0
  3. package/src/Checkbox/fonts/roboto-bold-webfont.woff +0 -0
  4. package/src/Checkbox/fonts/roboto-bold-webfont.woff2 +0 -0
  5. package/src/Checkbox/fonts/roboto-light-webfont.ttf +0 -0
  6. package/src/Checkbox/fonts/roboto-light-webfont.woff +0 -0
  7. package/src/Checkbox/fonts/roboto-light-webfont.woff2 +0 -0
  8. package/src/Checkbox/fonts/roboto-medium-webfont.ttf +0 -0
  9. package/src/Checkbox/fonts/roboto-medium-webfont.woff +0 -0
  10. package/src/Checkbox/fonts/roboto-medium-webfont.woff2 +0 -0
  11. package/src/Checkbox/fonts/roboto-regular-webfont.ttf +0 -0
  12. package/src/Checkbox/fonts/roboto-regular-webfont.woff +0 -0
  13. package/src/Checkbox/fonts/roboto-regular-webfont.woff2 +0 -0
  14. package/src/Dashboard/Item.tsx +2 -11
  15. package/src/Dashboard/Layout.tsx +2 -4
  16. package/src/Dashboard/utils.ts +1 -1
  17. package/src/Form/Inputs/Grid.tsx +8 -4
  18. package/src/Form/Inputs/models.ts +15 -14
  19. package/src/Graph/BarStack/BarStack.cypress.spec.tsx +87 -9
  20. package/src/Graph/BarStack/BarStack.stories.tsx +4 -2
  21. package/src/Graph/BarStack/BarStack.styles.ts +59 -30
  22. package/src/Graph/BarStack/Graph.tsx +176 -0
  23. package/src/Graph/BarStack/GraphAndLegend.tsx +119 -0
  24. package/src/Graph/BarStack/ResponsiveBarStack.tsx +62 -157
  25. package/src/Graph/BarStack/constants.ts +5 -0
  26. package/src/Graph/BarStack/models.ts +1 -1
  27. package/src/Graph/BarStack/useGraphAndLegend.ts +86 -0
  28. package/src/Graph/BarStack/useResponsiveBarStack.ts +74 -99
  29. package/src/Graph/HeatMap/ResponsiveHeatMap.tsx +19 -2
  30. package/src/Graph/HeatMap/model.ts +5 -1
  31. package/src/Graph/Legend/Legend.styles.ts +10 -0
  32. package/src/Graph/Legend/Legend.tsx +6 -1
  33. package/src/Graph/LineChart/BasicComponents/Lines/RegularLines/index.tsx +2 -1
  34. package/src/Graph/LineChart/BasicComponents/Lines/StackedLines/index.tsx +3 -4
  35. package/src/Graph/LineChart/Icons/Downtime.tsx +3 -3
  36. package/src/Graph/LineChart/InteractiveComponents/ZoomPreview/index.tsx +2 -1
  37. package/src/Graph/LineChart/Legend/Legend.styles.ts +16 -5
  38. package/src/Graph/LineChart/Legend/LegendHeader.tsx +4 -1
  39. package/src/Graph/LineChart/Legend/index.tsx +12 -5
  40. package/src/Graph/LineChart/LineChart.cypress.spec.tsx +53 -0
  41. package/src/Graph/LineChart/LineChart.tsx +10 -9
  42. package/src/Graph/LineChart/index.stories.tsx +13 -0
  43. package/src/Graph/LineChart/mockedData/curvesWithSameColor.json +252 -0
  44. package/src/Graph/LineChart/useLineChartData.ts +68 -18
  45. package/src/Graph/PieChart/ResponsivePie.tsx +3 -1
  46. package/src/Graph/PieChart/models.ts +1 -0
  47. package/src/Graph/Tree/DescendantNodes.tsx +0 -1
  48. package/src/Graph/Tree/Links.tsx +2 -15
  49. package/src/Graph/Tree/Tree.cypress.spec.tsx +0 -24
  50. package/src/Graph/Tree/Tree.stories.tsx +1 -17
  51. package/src/Graph/Tree/models.ts +0 -3
  52. package/src/Graph/common/utils.ts +51 -2
  53. package/src/Icon/BaseIcon.tsx +32 -0
  54. package/src/Icon/DowntimeIcon.tsx +14 -0
  55. package/src/InputField/Select/Autocomplete/Connected/Multi/index.test.tsx +21 -1
  56. package/src/InputField/Select/Autocomplete/Connected/index.test.tsx +2 -2
  57. package/src/InputField/Select/Autocomplete/Connected/index.tsx +10 -7
  58. package/src/InputField/Select/Autocomplete/Multi/index.stories.tsx +19 -0
  59. package/src/InputField/Select/Autocomplete/Multi/index.tsx +8 -5
  60. package/src/InputField/Text/index.tsx +7 -5
  61. package/src/Listing/ActionBar/index.tsx +1 -0
  62. package/src/PopoverMenu/index.tsx +4 -4
  63. package/src/RichTextEditor/ContentEditable.tsx +195 -195
  64. package/src/StoryBookThemeProvider/index.tsx +35 -36
  65. package/src/ThemeProvider/index.tsx +12 -12
  66. package/src/ThemeProvider/palettes.ts +11 -8
  67. package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/PickersStartEndDate.tsx +2 -3
  68. package/src/TimePeriods/DateTimePickerInput.tsx +4 -1
  69. package/src/TopCounterElements/TopCounterLayout.tsx +4 -3
  70. package/src/TopCounterElements/useCloseOnLegacyPage.tsx +9 -6
  71. package/src/api/buildListingEndpoint/getSearchQueryParameterValue.ts +7 -1
  72. package/src/api/buildListingEndpoint/models.ts +1 -0
  73. package/src/api/useGraphQuery/index.ts +1 -7
  74. package/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx +13 -27
  75. package/src/components/Form/AccessRights/AccessRights.stories.tsx +19 -0
  76. package/src/components/Form/AccessRights/AccessRights.styles.ts +1 -1
  77. package/src/components/Form/AccessRights/AccessRights.tsx +5 -6
  78. package/src/components/Form/AccessRights/Actions/Actions.styles.ts +7 -3
  79. package/src/components/Form/AccessRights/Actions/Actions.tsx +32 -15
  80. package/src/components/Form/AccessRights/Actions/useActions.ts +37 -4
  81. package/src/components/Form/AccessRights/models.ts +3 -0
  82. package/src/components/Form/AccessRights/storiesData.ts +3 -0
  83. package/src/components/List/Item/ListItem.styles.ts +2 -2
  84. package/src/components/Zoom/Minimap.tsx +2 -4
  85. package/src/components/Zoom/Zoom.cypress.spec.tsx +13 -13
  86. package/src/components/Zoom/Zoom.tsx +1 -4
  87. package/src/components/Zoom/ZoomContent.tsx +2 -5
  88. package/src/components/index.ts +0 -1
  89. package/src/fonts/roboto-bold-webfont.ttf +0 -0
  90. package/src/fonts/roboto-bold-webfont.woff +0 -0
  91. package/src/fonts/roboto-bold-webfont.woff2 +0 -0
  92. package/src/fonts/roboto-light-webfont.ttf +0 -0
  93. package/src/fonts/roboto-light-webfont.woff +0 -0
  94. package/src/fonts/roboto-light-webfont.woff2 +0 -0
  95. package/src/fonts/roboto-medium-webfont.ttf +0 -0
  96. package/src/fonts/roboto-medium-webfont.woff +0 -0
  97. package/src/fonts/roboto-medium-webfont.woff2 +0 -0
  98. package/src/fonts/roboto-regular-webfont.ttf +0 -0
  99. package/src/fonts/roboto-regular-webfont.woff +0 -0
  100. package/src/fonts/roboto-regular-webfont.woff2 +0 -0
  101. package/src/index.ts +1 -0
  102. package/src/utils/index.ts +25 -25
  103. package/src/utils/useFullscreen/Fullscreen.cypress.spec.tsx +3 -0
  104. package/src/utils/useInfiniteScrollListing.ts +6 -1
  105. package/src/utils/useLocale/index.ts +10 -0
  106. package/src/utils/useLocale/useLocale.cypress.spec.tsx +40 -0
  107. package/src/utils/useLocaleDateTimeFormat/index.ts +5 -2
  108. package/src/utils/usePluralizedTranslation.ts +4 -21
  109. package/src/@assets/icons/downtime.icon.svg +0 -1
  110. package/src/components/Form/AccessRights/useAccessRightsChange.ts +0 -30
  111. package/src/components/Form/AccessRights/utils.ts +0 -18
  112. package/src/components/Tabs/Tab.styles.ts +0 -25
  113. package/src/components/Tabs/TabPanel.tsx +0 -22
  114. package/src/components/Tabs/Tabs.cypress.spec.tsx +0 -70
  115. package/src/components/Tabs/Tabs.stories.tsx +0 -55
  116. package/src/components/Tabs/Tabs.tsx +0 -55
  117. package/src/components/Tabs/index.ts +0 -6
  118. package/src/utils/resourcesStatusURL.ts +0 -166
  119. package/src/utils/usePluralizedTranslation.test.ts +0 -159
  120. /package/{public → src/Button}/fonts/roboto-bold-webfont.ttf +0 -0
  121. /package/{public → src/Button}/fonts/roboto-bold-webfont.woff +0 -0
  122. /package/{public → src/Button}/fonts/roboto-bold-webfont.woff2 +0 -0
  123. /package/{public → src/Button}/fonts/roboto-light-webfont.ttf +0 -0
  124. /package/{public → src/Button}/fonts/roboto-light-webfont.woff +0 -0
  125. /package/{public → src/Button}/fonts/roboto-light-webfont.woff2 +0 -0
  126. /package/{public → src/Button}/fonts/roboto-medium-webfont.ttf +0 -0
  127. /package/{public → src/Button}/fonts/roboto-medium-webfont.woff +0 -0
  128. /package/{public → src/Button}/fonts/roboto-medium-webfont.woff2 +0 -0
  129. /package/{public → src/Button}/fonts/roboto-regular-webfont.ttf +0 -0
  130. /package/{public → src/Button}/fonts/roboto-regular-webfont.woff +0 -0
  131. /package/{public → src/Button}/fonts/roboto-regular-webfont.woff2 +0 -0
@@ -0,0 +1,176 @@
1
+ import { memo, useMemo } from 'react';
2
+
3
+ import {
4
+ BarRounded,
5
+ BarStackHorizontal,
6
+ BarStack as BarStackVertical
7
+ } from '@visx/shape';
8
+ import { Text } from '@visx/text';
9
+ import { equals, props } from 'ramda';
10
+
11
+ import { Tooltip } from '../../components';
12
+ import { getValueByUnit } from '../common/utils';
13
+
14
+ import { useGraphStyles } from './BarStack.styles';
15
+ import { BarStackProps } from './models';
16
+ import { useGraphAndLegend } from './useGraphAndLegend';
17
+
18
+ interface Props
19
+ extends Pick<
20
+ BarStackProps,
21
+ | 'data'
22
+ | 'displayValues'
23
+ | 'onSingleBarClick'
24
+ | 'unit'
25
+ | 'TooltipContent'
26
+ | 'tooltipProps'
27
+ > {
28
+ colorScale;
29
+ height: number;
30
+ isVerticalBar: boolean;
31
+ total: number;
32
+ width: number;
33
+ }
34
+
35
+ const Graph = ({
36
+ width,
37
+ height,
38
+ isVerticalBar,
39
+ colorScale,
40
+ data,
41
+ total,
42
+ unit,
43
+ displayValues,
44
+ onSingleBarClick,
45
+ tooltipProps,
46
+ TooltipContent
47
+ }: Props): JSX.Element => {
48
+ const { classes } = useGraphStyles();
49
+
50
+ const BarStackComponent = useMemo(
51
+ () => (isVerticalBar ? BarStackVertical : BarStackHorizontal),
52
+ [isVerticalBar]
53
+ );
54
+
55
+ const normalizedHeight = useMemo(() => height - 10, [height]);
56
+
57
+ const { barStackData, xScale, yScale, keys } = useGraphAndLegend({
58
+ data,
59
+ height: normalizedHeight,
60
+ isVerticalBar,
61
+ total,
62
+ width
63
+ });
64
+
65
+ return (
66
+ <svg height={normalizedHeight} width="100%">
67
+ <BarStackComponent
68
+ color={colorScale}
69
+ data={[barStackData]}
70
+ keys={keys}
71
+ {...(isVerticalBar ? { x: () => undefined } : { y: () => undefined })}
72
+ xScale={xScale}
73
+ yScale={yScale}
74
+ >
75
+ {(barStacks) =>
76
+ barStacks.map((barStack, index) =>
77
+ barStack.bars.map((bar) => {
78
+ const isFirstBar = equals(index, 0);
79
+ const isLastBar = equals(index, barStacks.length - 1);
80
+ const fitsInBar = isVerticalBar
81
+ ? bar.height >= 18
82
+ : (equals(unit, 'number') && bar.width > 15) ||
83
+ (equals(unit, 'percentage') && bar.width > 35);
84
+
85
+ const textX = bar.x + bar.width / 2;
86
+ const textY = bar.y + bar.height / 2;
87
+
88
+ const click = onSingleBarClick
89
+ ? (e: MouseEvent): void => {
90
+ if (!equals(e.button, 0)) {
91
+ return;
92
+ }
93
+ onSingleBarClick(bar);
94
+ }
95
+ : undefined;
96
+
97
+ return (
98
+ <Tooltip
99
+ classes={classes}
100
+ followCursor={false}
101
+ key={`bar-stack-${barStack.index}-${bar.index}`}
102
+ label={
103
+ TooltipContent && (
104
+ <TooltipContent
105
+ color={bar.color}
106
+ label={bar.key}
107
+ total={total}
108
+ value={barStack.bars[0].bar.data[barStack.key]}
109
+ {...tooltipProps}
110
+ />
111
+ )
112
+ }
113
+ position={isVerticalBar ? 'right' : 'bottom'}
114
+ >
115
+ <g data-testid={bar.key} key={bar.key}>
116
+ <BarRounded
117
+ bottom={isVerticalBar && isFirstBar}
118
+ cursor={onSingleBarClick ? 'pointer' : 'default'}
119
+ fill={bar.color}
120
+ height={bar.height}
121
+ key={`bar-stack-${barStack.index}-${bar.index}`}
122
+ left={!isVerticalBar && isFirstBar}
123
+ radius={8}
124
+ right={!isVerticalBar && isLastBar}
125
+ top={isVerticalBar && isLastBar}
126
+ width={isVerticalBar ? bar.width - 10 : bar.width}
127
+ x={bar.x}
128
+ y={bar.y}
129
+ onMouseDown={click}
130
+ />
131
+ {displayValues && fitsInBar && (
132
+ <Text
133
+ cursor={onSingleBarClick ? 'pointer' : 'default'}
134
+ data-testid="value"
135
+ fill="#000"
136
+ fontSize={12}
137
+ fontWeight={600}
138
+ textAnchor="middle"
139
+ verticalAnchor="middle"
140
+ x={textX}
141
+ y={textY}
142
+ onMouseUp={click}
143
+ >
144
+ {getValueByUnit({
145
+ total,
146
+ unit: unit || 'number',
147
+ value: barStack.bars[0].bar.data[barStack.key]
148
+ })}
149
+ </Text>
150
+ )}
151
+ </g>
152
+ </Tooltip>
153
+ );
154
+ })
155
+ )
156
+ }
157
+ </BarStackComponent>
158
+ </svg>
159
+ );
160
+ };
161
+
162
+ const propsToMemoize = [
163
+ 'width',
164
+ 'height',
165
+ 'isVerticalBar',
166
+ 'colorScale',
167
+ 'data',
168
+ 'total',
169
+ 'unit',
170
+ 'displayValues',
171
+ 'tooltipProps'
172
+ ];
173
+
174
+ export default memo(Graph, (prevProps, nextProps) =>
175
+ equals(props(propsToMemoize, prevProps), props(propsToMemoize, nextProps))
176
+ );
@@ -0,0 +1,119 @@
1
+ import { memo, useMemo } from 'react';
2
+
3
+ import { equals, props } from 'ramda';
4
+
5
+ import { useGraphAndLegendStyles } from './BarStack.styles';
6
+ import Graph from './Graph';
7
+ import { gap, legendMaxHeight, legendMaxWidth } from './constants';
8
+ import { BarStackProps } from './models';
9
+
10
+ interface Props
11
+ extends Pick<
12
+ BarStackProps,
13
+ | 'data'
14
+ | 'displayValues'
15
+ | 'onSingleBarClick'
16
+ | 'unit'
17
+ | 'TooltipContent'
18
+ | 'tooltipProps'
19
+ > {
20
+ colorScale;
21
+ displayLegend: boolean;
22
+ height: number;
23
+ isVerticalBar: boolean;
24
+ legend: JSX.Element;
25
+ total: number;
26
+ width: number;
27
+ }
28
+
29
+ const GraphAndLegend = ({
30
+ isVerticalBar,
31
+ legend,
32
+ displayLegend,
33
+ height,
34
+ width,
35
+ colorScale,
36
+ total,
37
+ unit,
38
+ data,
39
+ displayValues,
40
+ onSingleBarClick,
41
+ tooltipProps,
42
+ TooltipContent
43
+ }: Props): JSX.Element => {
44
+ const { classes } = useGraphAndLegendStyles();
45
+
46
+ const isSmall = useMemo(
47
+ () =>
48
+ (!isVerticalBar && Math.floor(height) <= 80) ||
49
+ (isVerticalBar && Math.floor(width) <= 150),
50
+ [isVerticalBar, height, width]
51
+ );
52
+
53
+ const mustDisplayLegend = useMemo(
54
+ () => displayLegend && !isSmall,
55
+ [isSmall, displayLegend]
56
+ );
57
+
58
+ const graphWidth = useMemo(
59
+ () =>
60
+ isVerticalBar ? width - (isSmall ? 0 : legendMaxWidth - gap) : width,
61
+ [width, isVerticalBar, isSmall]
62
+ );
63
+
64
+ const graphHeight = useMemo(
65
+ () =>
66
+ isVerticalBar ? height : height - (isSmall ? 0 : legendMaxHeight - gap),
67
+ [height, isVerticalBar, isSmall]
68
+ );
69
+
70
+ return (
71
+ <div
72
+ className={classes.graphAndLegend}
73
+ data-display-legend={mustDisplayLegend}
74
+ data-is-vertical={isVerticalBar}
75
+ style={{ height }}
76
+ >
77
+ <Graph
78
+ TooltipContent={TooltipContent}
79
+ colorScale={colorScale}
80
+ data={data}
81
+ displayValues={displayValues}
82
+ height={graphHeight}
83
+ isVerticalBar={isVerticalBar}
84
+ tooltipProps={tooltipProps}
85
+ total={total}
86
+ unit={unit}
87
+ width={graphWidth}
88
+ onSingleBarClick={onSingleBarClick}
89
+ />
90
+ {mustDisplayLegend && (
91
+ <div
92
+ className={classes.legend}
93
+ data-is-vertical={isVerticalBar}
94
+ data-testid="Legend"
95
+ >
96
+ {legend}
97
+ </div>
98
+ )}
99
+ </div>
100
+ );
101
+ };
102
+
103
+ const propsToMemoize = [
104
+ 'width',
105
+ 'height',
106
+ 'isVerticalBar',
107
+ 'colorScale',
108
+ 'data',
109
+ 'total',
110
+ 'unit',
111
+ 'displayValues',
112
+ 'tooltipProps',
113
+ 'displayLegend',
114
+ 'legend'
115
+ ];
116
+
117
+ export default memo(GraphAndLegend, (prevProps, nextProps) =>
118
+ equals(props(propsToMemoize, prevProps), props(propsToMemoize, nextProps))
119
+ );
@@ -1,19 +1,18 @@
1
- import { useRef } from 'react';
1
+ import { useMemo } from 'react';
2
2
 
3
- import { BarStack as BarStackVertical, BarStackHorizontal } from '@visx/shape';
4
- import { Group } from '@visx/group';
5
3
  import numeral from 'numeral';
6
- import { Text } from '@visx/text';
7
- import { useTranslation } from 'react-i18next';
8
4
  import { equals } from 'ramda';
5
+ import { useTranslation } from 'react-i18next';
6
+
7
+ import { Typography } from '@mui/material';
9
8
 
10
- import { Tooltip } from '../../components';
11
- import { LegendProps } from '../Legend/models';
12
9
  import { Legend as LegendComponent } from '../Legend';
13
- import { getValueByUnit } from '../common/utils';
10
+ import { LegendProps } from '../Legend/models';
14
11
 
12
+ import { useStyles } from './BarStack.styles';
13
+ import GraphAndLegend from './GraphAndLegend';
14
+ import { gap, smallTitleHeight, titleHeight } from './constants';
15
15
  import { BarStackProps } from './models';
16
- import { useBarStackStyles } from './BarStack.styles';
17
16
  import useResponsiveBarStack from './useResponsiveBarStack';
18
17
 
19
18
  const DefaultLengd = ({ scale, direction }: LegendProps): JSX.Element => (
@@ -23,9 +22,8 @@ const DefaultLengd = ({ scale, direction }: LegendProps): JSX.Element => (
23
22
  const BarStack = ({
24
23
  title,
25
24
  data,
26
- width,
27
25
  height,
28
- size = 72,
26
+ width,
29
27
  onSingleBarClick,
30
28
  displayLegend = true,
31
29
  TooltipContent,
@@ -33,175 +31,82 @@ const BarStack = ({
33
31
  unit = 'number',
34
32
  displayValues,
35
33
  variant = 'vertical',
36
- legendDirection = 'column'
34
+ legendDirection,
35
+ tooltipProps = {}
37
36
  }: BarStackProps & { height: number; width: number }): JSX.Element => {
37
+ const { classes, cx } = useStyles();
38
38
  const { t } = useTranslation();
39
- const { classes } = useBarStackStyles();
40
-
41
- const titleRef = useRef(null);
42
- const legendRef = useRef(null);
43
39
 
44
40
  const {
45
- barSize,
46
- colorScale,
47
- input,
48
- keys,
49
- legendScale,
50
41
  total,
51
- xScale,
52
- yScale,
53
- svgWrapperWidth,
54
- svgContainerSize,
55
- isVerticalBar
42
+ titleVariant,
43
+ legendScale,
44
+ isVerticalBar,
45
+ colorScale,
46
+ formattedLegendDirection
56
47
  } = useResponsiveBarStack({
57
48
  data,
58
49
  height,
59
- legendRef,
60
- size,
61
- titleRef,
50
+ legendDirection,
62
51
  unit,
63
52
  variant,
64
53
  width
65
54
  });
66
55
 
67
- const BarStackComponent = isVerticalBar
68
- ? BarStackVertical
69
- : BarStackHorizontal;
70
-
71
- return (
72
- <div className={classes.container} style={{ height, width }}>
73
- <div
74
- className={classes.svgWrapper}
75
- style={{
76
- height,
77
- width: svgWrapperWidth
78
- }}
79
- >
80
- {title && (
81
- <div className={classes.title} data-testid="Title" ref={titleRef}>
82
- {`${numeral(total).format('0a').toUpperCase()} `} {t(title)}
83
- </div>
84
- )}
85
- <div
86
- className={classes.svgContainer}
87
- data-testid="barStack"
88
- style={svgContainerSize}
89
- >
90
- <svg
91
- data-variant={variant}
92
- height={barSize.height}
93
- width={barSize.width}
94
- >
95
- <Group>
96
- <BarStackComponent
97
- color={colorScale}
98
- data={[input]}
99
- keys={keys}
100
- {...(isVerticalBar
101
- ? { x: () => undefined }
102
- : { y: () => undefined })}
103
- xScale={xScale}
104
- yScale={yScale}
105
- >
106
- {(barStacks) =>
107
- barStacks.map((barStack) =>
108
- barStack.bars.map((bar) => {
109
- const shouldDisplayValues = (): boolean => {
110
- if (bar.height < 10) {
111
- return false;
112
- }
113
-
114
- return (
115
- (equals(unit, 'number') && bar.width > 10) ||
116
- (equals(unit, 'percentage') && bar.width > 25)
117
- );
118
- };
56
+ const graphAndLegendHeight = useMemo(() => {
57
+ if (equals(titleVariant, 'xs')) {
58
+ return height - 2 * smallTitleHeight - gap;
59
+ }
119
60
 
120
- const TextX = bar.x + bar.width / 2;
121
- const TextY = bar.y + bar.height / 2;
61
+ if (equals(titleVariant, 'sm')) {
62
+ return height - smallTitleHeight - gap;
63
+ }
122
64
 
123
- const onClick = (): void => {
124
- onSingleBarClick?.(bar);
125
- };
65
+ return height - titleHeight - gap;
66
+ }, [titleVariant, height]);
126
67
 
127
- return (
128
- <Tooltip
129
- hasCaret
130
- classes={{
131
- tooltip: classes.barStackTooltip
132
- }}
133
- followCursor={false}
134
- key={`bar-stack-${barStack.index}-${bar.index}`}
135
- label={
136
- TooltipContent && (
137
- <TooltipContent
138
- color={bar.color}
139
- label={bar.key}
140
- title={title}
141
- total={total}
142
- value={barStack.bars[0].bar.data[barStack.key]}
143
- />
144
- )
145
- }
146
- position={
147
- isVerticalBar ? 'right-start' : 'bottom-start'
148
- }
149
- >
150
- <g data-testid={bar.key} onClick={onClick}>
151
- <rect
152
- cursor="pointer"
153
- fill={bar.color}
154
- height={
155
- isVerticalBar ? bar.height - 1 : bar.height
156
- }
157
- key={`bar-stack-${barStack.index}-${bar.index}`}
158
- ry={10}
159
- width={isVerticalBar ? bar.width : bar.width - 1}
160
- x={bar.x}
161
- y={bar.y}
162
- />
163
- {displayValues && shouldDisplayValues() && (
164
- <Text
165
- cursor="pointer"
166
- data-testid="value"
167
- fill="#000"
168
- fontSize={12}
169
- fontWeight={600}
170
- textAnchor="middle"
171
- verticalAnchor="middle"
172
- x={TextX}
173
- y={TextY}
174
- >
175
- {getValueByUnit({
176
- total,
177
- unit,
178
- value: barStack.bars[0].bar.data[barStack.key]
179
- })}
180
- </Text>
181
- )}
182
- </g>
183
- </Tooltip>
184
- );
185
- })
186
- )
187
- }
188
- </BarStackComponent>
189
- </Group>
190
- </svg>
191
- </div>
192
- </div>
193
- {displayLegend && (
194
- <div data-testid="Legend" ref={legendRef}>
68
+ return (
69
+ <div
70
+ className={classes.container}
71
+ data-has-title={!!title}
72
+ data-title-variant={titleVariant}
73
+ data-variant={variant}
74
+ >
75
+ {title && (
76
+ <Typography
77
+ className={cx(equals(titleVariant, 'md') && classes.clippedTitle)}
78
+ data-testid="Title"
79
+ fontWeight="bold"
80
+ textAlign="center"
81
+ variant={equals(titleVariant, 'md') ? 'h6' : 'body1'}
82
+ >
83
+ {`${numeral(total).format('0a')}`} {t(title)}
84
+ </Typography>
85
+ )}
86
+ <GraphAndLegend
87
+ TooltipContent={TooltipContent}
88
+ colorScale={colorScale}
89
+ data={data}
90
+ displayLegend={displayLegend}
91
+ displayValues={displayValues}
92
+ height={graphAndLegendHeight}
93
+ isVerticalBar={isVerticalBar}
94
+ legend={
195
95
  <Legend
196
96
  data={data}
197
- direction={legendDirection}
97
+ direction={formattedLegendDirection}
198
98
  scale={legendScale}
199
99
  title={title}
200
100
  total={total}
201
101
  unit={unit}
202
102
  />
203
- </div>
204
- )}
103
+ }
104
+ tooltipProps={tooltipProps}
105
+ total={total}
106
+ unit={unit}
107
+ width={width}
108
+ onSingleBarClick={onSingleBarClick}
109
+ />
205
110
  </div>
206
111
  );
207
112
  };
@@ -0,0 +1,5 @@
1
+ export const legendMaxWidth = 85;
2
+ export const legendMaxHeight = 43;
3
+ export const titleHeight = 36;
4
+ export const smallTitleHeight = 20;
5
+ export const gap = 4;
@@ -12,8 +12,8 @@ export type BarStackProps = {
12
12
  displayValues?: boolean;
13
13
  legendDirection?: 'row' | 'column';
14
14
  onSingleBarClick?: (barData) => void;
15
- size?: number;
16
15
  title?: string;
16
+ tooltipProps?: object;
17
17
  unit?: 'percentage' | 'number';
18
18
  variant?: 'vertical' | 'horizontal';
19
19
  };
@@ -0,0 +1,86 @@
1
+ import { useMemo } from 'react';
2
+
3
+ import { scaleBand, scaleLinear } from '@visx/scale';
4
+ import { pluck } from 'ramda';
5
+
6
+ import { BarType } from './models';
7
+
8
+ interface UseGraphandLegendProps {
9
+ data: Array<BarType>;
10
+ height: number;
11
+ isVerticalBar: boolean;
12
+ total: number;
13
+ width: number;
14
+ }
15
+
16
+ interface UseGraphAndLegendState {
17
+ barStackData: Record<string, number>;
18
+ keys: Array<string>;
19
+ xScale;
20
+ yScale;
21
+ }
22
+
23
+ export const useGraphAndLegend = ({
24
+ data,
25
+ isVerticalBar,
26
+ total,
27
+ width,
28
+ height
29
+ }: UseGraphandLegendProps): UseGraphAndLegendState => {
30
+ const dataWithNonEmptyValue = useMemo(
31
+ () => data.filter(({ value }) => value),
32
+ [data]
33
+ );
34
+
35
+ const keys = useMemo(
36
+ () => pluck('label', dataWithNonEmptyValue),
37
+ [dataWithNonEmptyValue]
38
+ );
39
+
40
+ const barStackData = useMemo(
41
+ () =>
42
+ dataWithNonEmptyValue.reduce((acc, { label, value }) => {
43
+ acc[label] = value;
44
+
45
+ return acc;
46
+ }, {}),
47
+ [dataWithNonEmptyValue]
48
+ );
49
+
50
+ const yScale = useMemo(
51
+ () =>
52
+ isVerticalBar
53
+ ? scaleLinear({
54
+ domain: [0, total],
55
+ range: [height, 0]
56
+ })
57
+ : scaleBand({
58
+ domain: [0, 0],
59
+ padding: 0,
60
+ range: [height, 0]
61
+ }),
62
+ [isVerticalBar, total, height]
63
+ );
64
+
65
+ const xScale = useMemo(
66
+ () =>
67
+ isVerticalBar
68
+ ? scaleBand({
69
+ domain: [0, 0],
70
+ padding: 0,
71
+ range: [0, width]
72
+ })
73
+ : scaleLinear({
74
+ domain: [0, total],
75
+ range: [0, width]
76
+ }),
77
+ [total, width, isVerticalBar]
78
+ );
79
+
80
+ return {
81
+ barStackData,
82
+ keys,
83
+ xScale,
84
+ yScale
85
+ };
86
+ };