@servicetitan/marketing-ui 1.6.1 → 1.10.0
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/dist/components/ads/ads-stat.d.ts +3 -3
- package/dist/components/ads/ads-stat.d.ts.map +1 -1
- package/dist/components/ads/ads-stat.js +4 -4
- package/dist/components/ads/ads-stat.js.map +1 -1
- package/dist/components/charts/funnel-chart/components/funnel-chart.d.ts +2 -2
- package/dist/components/charts/funnel-chart/components/funnel-chart.d.ts.map +1 -1
- package/dist/components/charts/funnel-chart/components/funnel-chart.js +4 -4
- package/dist/components/charts/funnel-chart/components/funnel-chart.js.map +1 -1
- package/dist/components/charts/funnel-chart/components/funnel-svg.d.ts +2 -2
- package/dist/components/charts/funnel-chart/components/funnel-svg.d.ts.map +1 -1
- package/dist/components/charts/funnel-chart/components/funnel-svg.js +4 -4
- package/dist/components/charts/funnel-chart/components/funnel-svg.js.map +1 -1
- package/dist/components/charts/funnel-chart/funnel-chart.stories.d.ts +2 -2
- package/dist/components/charts/funnel-chart/funnel-chart.stories.d.ts.map +1 -1
- package/dist/components/charts/funnel-chart/funnel-chart.stories.js +5 -5
- package/dist/components/charts/funnel-chart/funnel-chart.stories.js.map +1 -1
- package/dist/components/charts/line-chart/components/body.d.ts +2 -2
- package/dist/components/charts/line-chart/components/body.d.ts.map +1 -1
- package/dist/components/charts/line-chart/components/body.js +12 -12
- package/dist/components/charts/line-chart/components/body.js.map +1 -1
- package/dist/components/charts/line-chart/components/body.module.less +1 -1
- package/dist/components/charts/line-chart/components/container.d.ts +2 -2
- package/dist/components/charts/line-chart/components/container.d.ts.map +1 -1
- package/dist/components/charts/line-chart/components/container.js +5 -5
- package/dist/components/charts/line-chart/components/container.js.map +1 -1
- package/dist/components/charts/line-chart/components/hover-popover.d.ts +2 -2
- package/dist/components/charts/line-chart/components/hover-popover.d.ts.map +1 -1
- package/dist/components/charts/line-chart/components/hover-popover.js +8 -8
- package/dist/components/charts/line-chart/components/hover-popover.js.map +1 -1
- package/dist/components/charts/line-chart/components/hover-popover.module.less +1 -1
- package/dist/components/charts/line-chart/components/sidebar.d.ts +2 -2
- package/dist/components/charts/line-chart/components/sidebar.d.ts.map +1 -1
- package/dist/components/charts/line-chart/components/sidebar.js +3 -3
- package/dist/components/charts/line-chart/components/sidebar.js.map +1 -1
- package/dist/components/charts/line-chart/components/sidebar.module.less +2 -2
- package/dist/components/charts/line-chart/components/stuff.d.ts +4 -4
- package/dist/components/charts/line-chart/components/stuff.d.ts.map +1 -1
- package/dist/components/charts/line-chart/components/stuff.js +6 -6
- package/dist/components/charts/line-chart/components/stuff.js.map +1 -1
- package/dist/components/charts/line-chart/components/svg-bars.d.ts +3 -3
- package/dist/components/charts/line-chart/components/svg-bars.d.ts.map +1 -1
- package/dist/components/charts/line-chart/components/svg-bars.js +9 -9
- package/dist/components/charts/line-chart/components/svg-bars.js.map +1 -1
- package/dist/components/charts/line-chart/components/svg-body.d.ts +3 -3
- package/dist/components/charts/line-chart/components/svg-body.d.ts.map +1 -1
- package/dist/components/charts/line-chart/components/svg-body.js +6 -6
- package/dist/components/charts/line-chart/components/svg-body.js.map +1 -1
- package/dist/components/charts/line-chart/components/svg-lines.d.ts +2 -2
- package/dist/components/charts/line-chart/components/svg-lines.d.ts.map +1 -1
- package/dist/components/charts/line-chart/components/svg-lines.js +5 -5
- package/dist/components/charts/line-chart/components/svg-lines.js.map +1 -1
- package/dist/components/charts/line-chart/line-chart.stories.d.ts +2 -2
- package/dist/components/charts/line-chart/line-chart.stories.d.ts.map +1 -1
- package/dist/components/charts/line-chart/line-chart.stories.js +7 -7
- package/dist/components/charts/line-chart/line-chart.stories.js.map +1 -1
- package/dist/components/charts/line-chart/stores/line-chart.store.js +5 -5
- package/dist/components/charts/line-chart/stores/line-chart.store.js.map +1 -1
- package/dist/components/charts/line-chart/stores/svg.store.js +2 -2
- package/dist/components/charts/line-chart/stores/svg.store.js.map +1 -1
- package/dist/components/charts/line-chart/utils/formatters.js +2 -2
- package/dist/components/charts/line-chart/utils/formatters.js.map +1 -1
- package/dist/components/charts/line-chart/utils/interfaces.d.ts +2 -2
- package/dist/components/charts/line-chart/utils/interfaces.d.ts.map +1 -1
- package/dist/components/charts/line-chart/utils/labels.js +16 -16
- package/dist/components/charts/line-chart/utils/labels.js.map +1 -1
- package/dist/components/charts/pie-chart/components/pie-chart.d.ts +2 -2
- package/dist/components/charts/pie-chart/components/pie-chart.d.ts.map +1 -1
- package/dist/components/charts/pie-chart/components/pie-chart.js +5 -5
- package/dist/components/charts/pie-chart/components/pie-chart.js.map +1 -1
- package/dist/components/charts/pie-chart/components/pie.d.ts +5 -2
- package/dist/components/charts/pie-chart/components/pie.d.ts.map +1 -1
- package/dist/components/charts/pie-chart/components/pie.js +21 -41
- package/dist/components/charts/pie-chart/components/pie.js.map +1 -1
- package/dist/components/charts/pie-chart/pie-chart.stories.d.ts +3 -2
- package/dist/components/charts/pie-chart/pie-chart.stories.d.ts.map +1 -1
- package/dist/components/charts/pie-chart/pie-chart.stories.js +10 -4
- package/dist/components/charts/pie-chart/pie-chart.stories.js.map +1 -1
- package/dist/components/charts/pie-chart/utils/const.d.ts +2 -2
- package/dist/components/charts/pie-chart/utils/const.d.ts.map +1 -1
- package/dist/components/charts/pie-chart/utils/const.js +10 -8
- package/dist/components/charts/pie-chart/utils/const.js.map +1 -1
- package/dist/components/charts/pie-chart/utils/interface.d.ts +5 -2
- package/dist/components/charts/pie-chart/utils/interface.d.ts.map +1 -1
- package/dist/components/image-cropper/image-cropper.d.ts +2 -2
- package/dist/components/image-cropper/image-cropper.d.ts.map +1 -1
- package/dist/components/image-cropper/image-cropper.js +4 -4
- package/dist/components/image-cropper/image-cropper.js.map +1 -1
- package/dist/components/image-cropper/image-cropper.stories.js +6 -9
- package/dist/components/image-cropper/image-cropper.stories.js.map +1 -1
- package/dist/components/stat/stat-card.d.ts +5 -3
- package/dist/components/stat/stat-card.d.ts.map +1 -1
- package/dist/components/stat/stat-card.js +21 -14
- package/dist/components/stat/stat-card.js.map +1 -1
- package/dist/components/stat/stat-card.module.less +7 -0
- package/dist/components/stat/stat-cards.stories.d.ts +3 -2
- package/dist/components/stat/stat-cards.stories.d.ts.map +1 -1
- package/dist/components/stat/stat-cards.stories.js +7 -6
- package/dist/components/stat/stat-cards.stories.js.map +1 -1
- package/dist/components/stat/stat-extended-card.d.ts.map +1 -1
- package/dist/components/stat/stat-extended-card.js +22 -2
- package/dist/components/stat/stat-extended-card.js.map +1 -1
- package/dist/components/stat/stat-extended-card.stories.d.ts +2 -2
- package/dist/components/stat/stat-extended-card.stories.d.ts.map +1 -1
- package/dist/components/stat/stat-extended-card.stories.js +4 -4
- package/dist/components/stat/stat-extended-card.stories.js.map +1 -1
- package/dist/components/ui/centered-spinner.d.ts +2 -2
- package/dist/components/ui/centered-spinner.d.ts.map +1 -1
- package/dist/components/ui/centered-spinner.js +2 -2
- package/dist/components/ui/centered-spinner.js.map +1 -1
- package/dist/components/ui/centered-spinner.stories.d.ts +2 -2
- package/dist/components/ui/centered-spinner.stories.d.ts.map +1 -1
- package/dist/components/ui/centered-spinner.stories.js +4 -4
- package/dist/components/ui/centered-spinner.stories.js.map +1 -1
- package/dist/components/ui/date-range-picker/date-range-picker.js +5 -5
- package/dist/components/ui/date-range-picker/date-range-picker.js.map +1 -1
- package/dist/components/ui/date-range-picker/date-range-picker.module.less +1 -1
- package/dist/components/ui/date-range-picker/date-range-picker.stories.js +3 -3
- package/dist/components/ui/date-range-picker/date-range-picker.stories.js.map +1 -1
- package/dist/components/ui/disabled-button.d.ts +2 -2
- package/dist/components/ui/disabled-button.d.ts.map +1 -1
- package/dist/components/ui/disabled-button.js +1 -1
- package/dist/components/ui/disabled-button.js.map +1 -1
- package/dist/components/ui/line-text/line-text-body.stories.d.ts +2 -2
- package/dist/components/ui/line-text/line-text-body.stories.d.ts.map +1 -1
- package/dist/components/ui/line-text/line-text-body.stories.js +3 -3
- package/dist/components/ui/line-text/line-text-body.stories.js.map +1 -1
- package/dist/components/ui/line-text/line-text-head.stories.d.ts +2 -2
- package/dist/components/ui/line-text/line-text-head.stories.d.ts.map +1 -1
- package/dist/components/ui/line-text/line-text-head.stories.js +3 -3
- package/dist/components/ui/line-text/line-text-head.stories.js.map +1 -1
- package/dist/components/ui/line-text/line-text.d.ts +3 -3
- package/dist/components/ui/line-text/line-text.d.ts.map +1 -1
- package/dist/components/ui/line-text/line-text.js +7 -7
- package/dist/components/ui/line-text/line-text.js.map +1 -1
- package/dist/utils/date/date-range-picker-options.js +2 -2
- package/dist/utils/date/date-range-picker-options.js.map +1 -1
- package/dist/utils/date/date-range-picker-state.js +1 -1
- package/dist/utils/date/date-range-picker-state.js.map +1 -1
- package/dist/utils/date/date.js +1 -1
- package/dist/utils/date/date.js.map +1 -1
- package/dist/utils/formatters.js +7 -7
- package/dist/utils/formatters.js.map +1 -1
- package/dist/utils/use-client-rect.js +6 -25
- package/dist/utils/use-client-rect.js.map +1 -1
- package/package.json +2 -2
- package/src/components/ads/ads-stat.tsx +3 -3
- package/src/components/charts/funnel-chart/components/funnel-chart.tsx +2 -2
- package/src/components/charts/funnel-chart/components/funnel-svg.tsx +2 -2
- package/src/components/charts/funnel-chart/funnel-chart.stories.tsx +2 -2
- package/src/components/charts/line-chart/components/body.module.less +1 -1
- package/src/components/charts/line-chart/components/body.tsx +5 -5
- package/src/components/charts/line-chart/components/container.tsx +2 -2
- package/src/components/charts/line-chart/components/hover-popover.module.less +1 -1
- package/src/components/charts/line-chart/components/hover-popover.tsx +4 -4
- package/src/components/charts/line-chart/components/sidebar.module.less +2 -2
- package/src/components/charts/line-chart/components/sidebar.tsx +2 -2
- package/src/components/charts/line-chart/components/stuff.tsx +5 -5
- package/src/components/charts/line-chart/components/svg-bars.tsx +3 -3
- package/src/components/charts/line-chart/components/svg-body.tsx +4 -4
- package/src/components/charts/line-chart/components/svg-lines.tsx +3 -3
- package/src/components/charts/line-chart/line-chart.stories.tsx +1 -1
- package/src/components/charts/line-chart/utils/interfaces.ts +2 -2
- package/src/components/charts/pie-chart/components/pie-chart.tsx +20 -7
- package/src/components/charts/pie-chart/components/pie.tsx +42 -22
- package/src/components/charts/pie-chart/pie-chart.stories.tsx +20 -1
- package/src/components/charts/pie-chart/utils/const.ts +11 -6
- package/src/components/charts/pie-chart/utils/interface.ts +5 -2
- package/src/components/image-cropper/image-cropper.stories.tsx +8 -8
- package/src/components/image-cropper/image-cropper.tsx +2 -2
- package/src/components/stat/stat-card.module.less +7 -0
- package/src/components/stat/stat-card.module.less.d.ts +1 -0
- package/src/components/stat/stat-card.tsx +20 -7
- package/src/components/stat/stat-cards.stories.tsx +5 -2
- package/src/components/stat/stat-extended-card.stories.tsx +2 -2
- package/src/components/stat/stat-extended-card.tsx +5 -4
- package/src/components/ui/centered-spinner.stories.tsx +2 -2
- package/src/components/ui/centered-spinner.tsx +2 -6
- package/src/components/ui/date-range-picker/date-range-picker.module.less +1 -1
- package/src/components/ui/date-range-picker/date-range-picker.stories.tsx +2 -2
- package/src/components/ui/date-range-picker/date-range-picker.tsx +1 -1
- package/src/components/ui/disabled-button.tsx +2 -2
- package/src/components/ui/line-text/line-text-body.stories.tsx +2 -2
- package/src/components/ui/line-text/line-text-head.stories.tsx +2 -2
- package/src/components/ui/line-text/line-text.tsx +3 -11
- package/src/utils/use-client-rect.ts +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FC } from 'react';
|
|
2
2
|
import { observer } from 'mobx-react';
|
|
3
3
|
import { useDependencies } from '@servicetitan/react-ioc';
|
|
4
4
|
import { ChartMetric } from '../utils/internal-interfaces';
|
|
@@ -10,7 +10,7 @@ interface SvgBarsProps {
|
|
|
10
10
|
isStackedBarChart?: boolean;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export const SvgBars:
|
|
13
|
+
export const SvgBars: FC<SvgBarsProps> = observer(({ metrics, isStackedBarChart }) => {
|
|
14
14
|
const [store] = useDependencies(SvgStore);
|
|
15
15
|
const { fpx, fpy, barWidth, length } = store;
|
|
16
16
|
const barWidthHalf = barWidth / 2;
|
|
@@ -65,7 +65,7 @@ interface SvgBarsHoverProps {
|
|
|
65
65
|
onLeave(ind: number): void;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
export const SvgBarsHover:
|
|
68
|
+
export const SvgBarsHover: FC<SvgBarsHoverProps> = observer(({ onHover, onLeave }) => {
|
|
69
69
|
const [store] = useDependencies(SvgStore);
|
|
70
70
|
const { fpx, fpy, barWidth, length } = store;
|
|
71
71
|
const barWidthHalf = barWidth / 2;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FC } from 'react';
|
|
2
2
|
import { observer } from 'mobx-react';
|
|
3
3
|
import tokens from '@servicetitan/tokens';
|
|
4
4
|
import { useDependencies } from '@servicetitan/react-ioc';
|
|
@@ -11,7 +11,7 @@ import { SvgBars, SvgBarsHover } from './svg-bars';
|
|
|
11
11
|
import { SvgLines } from './svg-lines';
|
|
12
12
|
import * as Styles from './svg.module.less';
|
|
13
13
|
|
|
14
|
-
const SvgGrid:
|
|
14
|
+
const SvgGrid: FC = () => {
|
|
15
15
|
const lines = [];
|
|
16
16
|
|
|
17
17
|
for (let i = 1; i <= 10; i += 1) {
|
|
@@ -39,7 +39,7 @@ interface SvgBodyProps {
|
|
|
39
39
|
metrics: ChartMetric[];
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
export const SvgBody:
|
|
42
|
+
export const SvgBody: FC<SvgBodyProps> = observer(({ horizontalGrid, metrics }) => {
|
|
43
43
|
const [{ key }] = useDependencies(SvgStore);
|
|
44
44
|
const barMetrics = metrics.filter(m => m.type === 'bar');
|
|
45
45
|
const stackedBarMetrics = metrics.filter(m => m.type === 'stacked-bar');
|
|
@@ -71,7 +71,7 @@ interface SvgBodyHoverProps {
|
|
|
71
71
|
onValueLeave(ind: number): void;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
export const SvgBodyHover:
|
|
74
|
+
export const SvgBodyHover: FC<SvgBodyHoverProps> = ({ onValueHover, onValueLeave }) => (
|
|
75
75
|
<svg className={Styles.svgHover} viewBox="0 0 100 100" preserveAspectRatio="none">
|
|
76
76
|
<SvgBarsHover onHover={onValueHover} onLeave={onValueLeave} />
|
|
77
77
|
</svg>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useMemo, FC } from 'react';
|
|
2
2
|
import { observer } from 'mobx-react';
|
|
3
3
|
import { useDependencies } from '@servicetitan/react-ioc';
|
|
4
4
|
import { ChartMetric } from '../utils/internal-interfaces';
|
|
@@ -11,7 +11,7 @@ interface SvgLineProps {
|
|
|
11
11
|
dashed: boolean;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
const SvgLine:
|
|
14
|
+
const SvgLine: FC<SvgLineProps> = ({ color, points, dashed }) => (
|
|
15
15
|
<path
|
|
16
16
|
className={Styles.line}
|
|
17
17
|
d={points.map(([px, py], ind) => (ind === 0 ? 'M' : 'L') + `${px} ${py}`).join(' ')}
|
|
@@ -26,7 +26,7 @@ interface SvgLinesProps {
|
|
|
26
26
|
metrics: ChartMetric[];
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
export const SvgLines:
|
|
29
|
+
export const SvgLines: FC<SvgLinesProps> = observer(({ metrics }) => {
|
|
30
30
|
const [store] = useDependencies(SvgStore);
|
|
31
31
|
|
|
32
32
|
const lines = useMemo(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
2
|
|
|
3
3
|
export type LineChartResolution = 'hour' | 'day' | 'week' | 'month';
|
|
4
4
|
export type LineChartMetricType = 'line' | 'bar' | 'stacked-bar';
|
|
@@ -74,7 +74,7 @@ export interface LineChartProps extends LineChartData {
|
|
|
74
74
|
|
|
75
75
|
export interface LineChartCardProps extends LineChartProps {
|
|
76
76
|
title: string;
|
|
77
|
-
headerRight?:
|
|
77
|
+
headerRight?: ReactElement;
|
|
78
78
|
loading?: boolean;
|
|
79
79
|
grayControls?: boolean;
|
|
80
80
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useMemo, FC } from 'react';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import { BodyText, Stack, StatusLight } from '@servicetitan/design-system';
|
|
4
4
|
import { PieChartProps, PiePiece } from '../utils/interface';
|
|
5
|
-
import { convertSessionsToPieces } from '../utils/const';
|
|
5
|
+
import { convertSessionsToPieces, radiusRelativeDefault } from '../utils/const';
|
|
6
6
|
import { Pie } from './pie';
|
|
7
7
|
import * as Styles from './pie-chart.module.less';
|
|
8
8
|
|
|
9
|
-
const PieTitles:
|
|
9
|
+
const PieTitles: FC<{ title: string; pieces: PiePiece[] }> = ({ title, pieces }) => {
|
|
10
10
|
return (
|
|
11
11
|
<div className={classNames(Styles.titleWrapper, 'of-y-auto p-t-2')}>
|
|
12
12
|
<div>
|
|
@@ -28,20 +28,33 @@ const PieTitles: React.FC<{ title: string; pieces: PiePiece[] }> = ({ title, pie
|
|
|
28
28
|
);
|
|
29
29
|
};
|
|
30
30
|
|
|
31
|
-
export const PieChart:
|
|
31
|
+
export const PieChart: FC<PieChartProps> = ({
|
|
32
32
|
height,
|
|
33
33
|
width,
|
|
34
34
|
title,
|
|
35
35
|
sections,
|
|
36
36
|
popoverContent,
|
|
37
|
+
content,
|
|
38
|
+
radiusRelative = radiusRelativeDefault,
|
|
39
|
+
hideTitles = false,
|
|
37
40
|
}) => {
|
|
38
|
-
const pieces = useMemo(
|
|
41
|
+
const pieces = useMemo(
|
|
42
|
+
() => convertSessionsToPieces(sections, radiusRelative),
|
|
43
|
+
[sections, radiusRelative]
|
|
44
|
+
);
|
|
39
45
|
const style = useMemo(() => ({ height, width }), [height, width]);
|
|
40
46
|
|
|
41
47
|
return (
|
|
42
48
|
<div className="d-f flex-row" style={style}>
|
|
43
|
-
<Pie
|
|
44
|
-
|
|
49
|
+
<Pie
|
|
50
|
+
title={title}
|
|
51
|
+
pieces={pieces}
|
|
52
|
+
content={content}
|
|
53
|
+
popoverContent={popoverContent}
|
|
54
|
+
radiusRelative={radiusRelative}
|
|
55
|
+
hideTitles={hideTitles}
|
|
56
|
+
/>
|
|
57
|
+
{!hideTitles && <PieTitles title={title} pieces={pieces} />}
|
|
45
58
|
</div>
|
|
46
59
|
);
|
|
47
60
|
};
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useCallback, useMemo, useState, FC, Fragment } from 'react';
|
|
2
2
|
import tokens from '@servicetitan/tokens';
|
|
3
3
|
import { BodyText, Popover, Stack, StatusLight } from '@servicetitan/design-system';
|
|
4
4
|
|
|
5
5
|
import { useClientRect } from '../../../../utils/use-client-rect';
|
|
6
|
-
import { radiusRelative } from '../utils/const';
|
|
7
6
|
import { PieChartPopoverContentType, PiePiece } from '../utils/interface';
|
|
8
7
|
|
|
9
8
|
const chartPadding = 8;
|
|
10
9
|
const px = (value?: number) => `${value ?? 0}px`;
|
|
11
10
|
|
|
12
|
-
const PiePieceSvg:
|
|
11
|
+
const PiePieceSvg: FC<{
|
|
13
12
|
piece: PiePiece;
|
|
14
13
|
selected?: boolean;
|
|
15
14
|
}> = ({ piece: { id, color, opacity, points, text, path }, selected }) =>
|
|
@@ -48,7 +47,7 @@ const PiePieceSvg: React.FC<{
|
|
|
48
47
|
</g>
|
|
49
48
|
) : null;
|
|
50
49
|
|
|
51
|
-
const PiePieceHover:
|
|
50
|
+
const PiePieceHover: FC<{
|
|
52
51
|
piece: PiePiece;
|
|
53
52
|
onMouse(id: string, isEnter: boolean): void;
|
|
54
53
|
}> = ({ piece, onMouse }) => {
|
|
@@ -66,10 +65,11 @@ const PiePieceHover: React.FC<{
|
|
|
66
65
|
);
|
|
67
66
|
};
|
|
68
67
|
|
|
69
|
-
const PieSvg:
|
|
68
|
+
const PieSvg: FC<{
|
|
70
69
|
pieces: PiePiece[];
|
|
71
70
|
selectedIndex: number;
|
|
72
|
-
|
|
71
|
+
radiusRelative: number;
|
|
72
|
+
}> = ({ pieces, selectedIndex, radiusRelative }) => (
|
|
73
73
|
<svg
|
|
74
74
|
className="position-absolute"
|
|
75
75
|
style={{ inset: px(chartPadding) }}
|
|
@@ -87,10 +87,11 @@ const PieSvg: React.FC<{
|
|
|
87
87
|
</svg>
|
|
88
88
|
);
|
|
89
89
|
|
|
90
|
-
const PieSvgHover:
|
|
90
|
+
const PieSvgHover: FC<{
|
|
91
91
|
pieces: PiePiece[];
|
|
92
|
+
radiusRelative: number;
|
|
92
93
|
onMouse(id: string, isEnter: boolean): void;
|
|
93
|
-
}> = ({ pieces, onMouse }) => (
|
|
94
|
+
}> = ({ pieces, onMouse, radiusRelative }) => (
|
|
94
95
|
<svg
|
|
95
96
|
className="position-absolute z-global-nav"
|
|
96
97
|
style={{ inset: px(chartPadding) }}
|
|
@@ -104,11 +105,20 @@ const PieSvgHover: React.FC<{
|
|
|
104
105
|
</svg>
|
|
105
106
|
);
|
|
106
107
|
|
|
107
|
-
export const Pie:
|
|
108
|
+
export const Pie: FC<{
|
|
108
109
|
title: string;
|
|
109
110
|
pieces: PiePiece[];
|
|
111
|
+
radiusRelative: number;
|
|
112
|
+
content?: FC;
|
|
110
113
|
popoverContent?: PieChartPopoverContentType;
|
|
111
|
-
|
|
114
|
+
hideTitles?: boolean;
|
|
115
|
+
}> = ({
|
|
116
|
+
pieces,
|
|
117
|
+
popoverContent: PopoverContent,
|
|
118
|
+
content: PieContent,
|
|
119
|
+
radiusRelative,
|
|
120
|
+
hideTitles,
|
|
121
|
+
}) => {
|
|
112
122
|
const [selectedIndex, setSelectedIndex] = useState(-1);
|
|
113
123
|
const [rect, ref] = useClientRect();
|
|
114
124
|
|
|
@@ -153,7 +163,7 @@ export const Pie: React.FC<{
|
|
|
153
163
|
: { top: '', left: '' }
|
|
154
164
|
)
|
|
155
165
|
: [],
|
|
156
|
-
[pieces, container]
|
|
166
|
+
[pieces, container, radiusRelative]
|
|
157
167
|
);
|
|
158
168
|
|
|
159
169
|
return (
|
|
@@ -163,7 +173,7 @@ export const Pie: React.FC<{
|
|
|
163
173
|
No Data
|
|
164
174
|
</Stack>
|
|
165
175
|
) : (
|
|
166
|
-
<
|
|
176
|
+
<Fragment>
|
|
167
177
|
{triggersStyles
|
|
168
178
|
.filter(ts => !!ts.left && !!ts.top)
|
|
169
179
|
.map((ts, ind) => (
|
|
@@ -178,12 +188,14 @@ export const Pie: React.FC<{
|
|
|
178
188
|
>
|
|
179
189
|
{selectedIndex === ind && (
|
|
180
190
|
<Stack direction="column">
|
|
181
|
-
|
|
182
|
-
<
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
191
|
+
{!hideTitles && (
|
|
192
|
+
<Stack alignItems="center">
|
|
193
|
+
<StatusLight color={pieces[ind].color} />
|
|
194
|
+
<BodyText size="small" bold>
|
|
195
|
+
{pieces[ind].title}
|
|
196
|
+
</BodyText>
|
|
197
|
+
</Stack>
|
|
198
|
+
)}
|
|
187
199
|
{!!PopoverContent && (
|
|
188
200
|
<Stack.Item className="m-l-1">
|
|
189
201
|
<PopoverContent
|
|
@@ -199,10 +211,18 @@ export const Pie: React.FC<{
|
|
|
199
211
|
</Popover>
|
|
200
212
|
</div>
|
|
201
213
|
))}
|
|
202
|
-
|
|
203
|
-
<PieSvg
|
|
204
|
-
|
|
205
|
-
|
|
214
|
+
{!!PieContent && <PieContent />}
|
|
215
|
+
<PieSvg
|
|
216
|
+
pieces={pieces}
|
|
217
|
+
selectedIndex={selectedIndex}
|
|
218
|
+
radiusRelative={radiusRelative}
|
|
219
|
+
/>
|
|
220
|
+
<PieSvgHover
|
|
221
|
+
pieces={pieces}
|
|
222
|
+
onMouse={onMouse}
|
|
223
|
+
radiusRelative={radiusRelative}
|
|
224
|
+
/>
|
|
225
|
+
</Fragment>
|
|
206
226
|
)}
|
|
207
227
|
</div>
|
|
208
228
|
);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
1
|
import { PieChart } from './index';
|
|
2
|
+
import { Eyebrow, Stack, BodyText } from '@servicetitan/design-system';
|
|
3
3
|
|
|
4
4
|
export default {
|
|
5
5
|
title: 'Marketing UI/charts/PieChart',
|
|
@@ -21,6 +21,25 @@ export const pieChart5AutoColor = () => (
|
|
|
21
21
|
/>
|
|
22
22
|
);
|
|
23
23
|
|
|
24
|
+
export const pieChartWithContent = () => (
|
|
25
|
+
<PieChart
|
|
26
|
+
title="Pie Chart"
|
|
27
|
+
height={300}
|
|
28
|
+
sections={[
|
|
29
|
+
{ title: 'New Customer', value: 61 },
|
|
30
|
+
{ title: 'Existing Customer', value: 90 },
|
|
31
|
+
]}
|
|
32
|
+
content={() => (
|
|
33
|
+
<Stack className="h-100" justifyContent="center" alignItems="center" direction="column">
|
|
34
|
+
<BodyText bold>244</BodyText>
|
|
35
|
+
<Eyebrow size="small">Total Leads</Eyebrow>
|
|
36
|
+
</Stack>
|
|
37
|
+
)}
|
|
38
|
+
radiusRelative={45}
|
|
39
|
+
hideTitles
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
|
|
24
43
|
export const pieChart1CustomColor = () => (
|
|
25
44
|
<PieChart
|
|
26
45
|
title="Pie Chart"
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { PiecePoints, PieChartSection, PiePiece } from './interface';
|
|
2
2
|
import { formatNumber } from 'accounting';
|
|
3
3
|
|
|
4
|
-
export const
|
|
4
|
+
export const radiusRelativeDefault = 50;
|
|
5
5
|
const radiusInt = 20;
|
|
6
|
-
const
|
|
7
|
-
const
|
|
6
|
+
const getRadiusExt = (radiusRelative: number) => radiusRelative - 5; // need to have some space to stroke selected piece
|
|
7
|
+
const getRadiusMid = (radiusRelative: number) => (3 * radiusRelative) / 4;
|
|
8
8
|
|
|
9
9
|
const angleInitial = -0.5;
|
|
10
10
|
const lowestOpacity = 0.1;
|
|
@@ -25,7 +25,7 @@ const formatValue = (val: number): string => {
|
|
|
25
25
|
return `0.${valueDecimal}%`;
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
const convertPointsToPath = (points: PiecePoints, wideAngle: boolean): string =>
|
|
28
|
+
const convertPointsToPath = (points: PiecePoints, wideAngle: boolean, radiusExt: number): string =>
|
|
29
29
|
`M ${points[3][0]},${points[3][1]} ` +
|
|
30
30
|
`L ${points[0][0]},${points[0][1]} ` +
|
|
31
31
|
`A ${radiusExt},${radiusExt} 0 ${wideAngle ? 1 : 0} 1 ${points[1][0]},${points[1][1]} ` +
|
|
@@ -33,10 +33,15 @@ const convertPointsToPath = (points: PiecePoints, wideAngle: boolean): string =>
|
|
|
33
33
|
`A ${radiusInt},${radiusInt} 0 ${wideAngle ? 1 : 0} 0 ${points[3][0]},${points[3][1]} ` +
|
|
34
34
|
`L ${points[0][0]},${points[0][1]} `;
|
|
35
35
|
|
|
36
|
-
export const convertSessionsToPieces = <T>(
|
|
36
|
+
export const convertSessionsToPieces = <T>(
|
|
37
|
+
sections: PieChartSection<T>[],
|
|
38
|
+
radiusRelative: number
|
|
39
|
+
): PiePiece<T>[] => {
|
|
37
40
|
const total = sections.reduce((sum, curr) => sum + curr.value, 0);
|
|
38
41
|
const opacityStep = (1 - lowestOpacity) / (Math.max(sections.length, 2) - 1);
|
|
39
42
|
let angleSum = 0;
|
|
43
|
+
const radiusExt = getRadiusExt(radiusRelative);
|
|
44
|
+
const radiusMid = getRadiusMid(radiusRelative);
|
|
40
45
|
|
|
41
46
|
const pieces = sections
|
|
42
47
|
.slice()
|
|
@@ -71,7 +76,7 @@ export const convertSessionsToPieces = <T>(sections: PieChartSection<T>[]): PieP
|
|
|
71
76
|
value: s.value,
|
|
72
77
|
points,
|
|
73
78
|
path: points
|
|
74
|
-
? convertPointsToPath(points, angleEnd - angleStart >= Math.PI)
|
|
79
|
+
? convertPointsToPath(points, angleEnd - angleStart >= Math.PI, radiusExt)
|
|
75
80
|
: undefined,
|
|
76
81
|
};
|
|
77
82
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FC } from 'react';
|
|
2
2
|
|
|
3
3
|
export interface PieChartSection<T> {
|
|
4
4
|
title: string;
|
|
@@ -7,7 +7,7 @@ export interface PieChartSection<T> {
|
|
|
7
7
|
data?: T;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export type PieChartPopoverContentType<T = any> =
|
|
10
|
+
export type PieChartPopoverContentType<T = any> = FC<{
|
|
11
11
|
index: number;
|
|
12
12
|
value: number;
|
|
13
13
|
data?: T;
|
|
@@ -18,8 +18,11 @@ export interface PieChartProps<T = any> {
|
|
|
18
18
|
title: string;
|
|
19
19
|
sections: PieChartSection<T>[];
|
|
20
20
|
popoverContent?: PieChartPopoverContentType<T>;
|
|
21
|
+
content?: FC<T>;
|
|
21
22
|
height?: number;
|
|
22
23
|
width?: number;
|
|
24
|
+
radiusRelative?: number;
|
|
25
|
+
hideTitles?: boolean;
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
export type PiecePoint = [number, number];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FC, ChangeEvent, useRef, useState, Fragment } from 'react';
|
|
2
2
|
import { ImageCropper } from './image-cropper';
|
|
3
3
|
|
|
4
4
|
export default {
|
|
@@ -7,13 +7,13 @@ export default {
|
|
|
7
7
|
parameters: {},
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
const BasicExample:
|
|
11
|
-
const [imageToEdit, setImageToEdit] =
|
|
12
|
-
const [croppedImage, setCroppedImage] =
|
|
10
|
+
const BasicExample: FC = () => {
|
|
11
|
+
const [imageToEdit, setImageToEdit] = useState<File>();
|
|
12
|
+
const [croppedImage, setCroppedImage] = useState<string>();
|
|
13
13
|
|
|
14
|
-
const imageCropper =
|
|
14
|
+
const imageCropper = useRef<ImageCropper>(null);
|
|
15
15
|
|
|
16
|
-
const handleFileChange = (e:
|
|
16
|
+
const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => {
|
|
17
17
|
const file = e.target.files?.[0];
|
|
18
18
|
if (!file) {
|
|
19
19
|
return;
|
|
@@ -38,7 +38,7 @@ const BasicExample: React.FC = () => {
|
|
|
38
38
|
};
|
|
39
39
|
|
|
40
40
|
return (
|
|
41
|
-
<
|
|
41
|
+
<Fragment>
|
|
42
42
|
<input type="file" accept="image/png, image/jpeg" onChange={handleFileChange} />
|
|
43
43
|
{imageToEdit && (
|
|
44
44
|
<div style={{ marginTop: 30 }}>
|
|
@@ -62,7 +62,7 @@ const BasicExample: React.FC = () => {
|
|
|
62
62
|
</div>
|
|
63
63
|
</div>
|
|
64
64
|
)}
|
|
65
|
-
</
|
|
65
|
+
</Fragment>
|
|
66
66
|
);
|
|
67
67
|
};
|
|
68
68
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Component } from 'react';
|
|
2
2
|
import { observable, action, makeObservable } from 'mobx';
|
|
3
3
|
import { observer } from 'mobx-react';
|
|
4
4
|
import ReactCrop, { Crop } from 'react-image-crop';
|
|
@@ -13,7 +13,7 @@ interface ImageCropperProps {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
@observer
|
|
16
|
-
export class ImageCropper extends
|
|
16
|
+
export class ImageCropper extends Component<ImageCropperProps> {
|
|
17
17
|
@observable private src?: string;
|
|
18
18
|
@observable private crop?: Crop;
|
|
19
19
|
@observable private image?: HTMLImageElement;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FC } from 'react';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import {
|
|
4
4
|
BodyText,
|
|
@@ -42,9 +42,10 @@ interface StatDiffProps {
|
|
|
42
42
|
inverted?: boolean;
|
|
43
43
|
neutral?: boolean;
|
|
44
44
|
className?: string;
|
|
45
|
+
diffPercentOnly?: boolean;
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
export const StatDiff:
|
|
48
|
+
export const StatDiff: FC<StatDiffProps> = ({
|
|
48
49
|
value,
|
|
49
50
|
prev,
|
|
50
51
|
size,
|
|
@@ -52,18 +53,26 @@ export const StatDiff: React.FC<StatDiffProps> = ({
|
|
|
52
53
|
inverted,
|
|
53
54
|
neutral,
|
|
54
55
|
className,
|
|
56
|
+
diffPercentOnly = false,
|
|
55
57
|
}) => {
|
|
56
58
|
const percents = format === 'percent';
|
|
57
59
|
const [absDiff, diffPercent, isIncrease] = calculateDiff(value ?? 0, prev ?? 0, percents);
|
|
58
|
-
|
|
60
|
+
const diff = absDiff === 0 ? '' : isIncrease ? '▲ ' : '▼ ';
|
|
61
|
+
let text = '';
|
|
59
62
|
|
|
60
63
|
if (percents) {
|
|
61
64
|
text += formatDifferencePercentage(absDiff, isIncrease);
|
|
62
65
|
} else {
|
|
63
|
-
|
|
66
|
+
const diffPercentage = formatDifferencePercentage(diffPercent, isIncrease);
|
|
64
67
|
|
|
65
|
-
if (
|
|
66
|
-
text +=
|
|
68
|
+
if (diffPercentOnly) {
|
|
69
|
+
text += `${diffPercentage}`;
|
|
70
|
+
} else {
|
|
71
|
+
text += `${formatDifference(absDiff, isIncrease, format)}`;
|
|
72
|
+
|
|
73
|
+
if (diffPercent !== 0) {
|
|
74
|
+
text += ` (${diffPercentage})`;
|
|
75
|
+
}
|
|
67
76
|
}
|
|
68
77
|
}
|
|
69
78
|
|
|
@@ -80,6 +89,7 @@ export const StatDiff: React.FC<StatDiffProps> = ({
|
|
|
80
89
|
)}
|
|
81
90
|
size={size ?? 'small'}
|
|
82
91
|
>
|
|
92
|
+
<span>{diff}</span>
|
|
83
93
|
{value === undefined ? '\u00A0' : text}
|
|
84
94
|
</BodyText>
|
|
85
95
|
);
|
|
@@ -99,9 +109,10 @@ export interface StatCardProps {
|
|
|
99
109
|
fill?: boolean;
|
|
100
110
|
valueOnly?: boolean;
|
|
101
111
|
className?: string;
|
|
112
|
+
diffPercentOnly?: boolean;
|
|
102
113
|
}
|
|
103
114
|
|
|
104
|
-
export const StatCard:
|
|
115
|
+
export const StatCard: FC<StatCardProps> = ({
|
|
105
116
|
title,
|
|
106
117
|
description,
|
|
107
118
|
value,
|
|
@@ -115,6 +126,7 @@ export const StatCard: React.FC<StatCardProps> = ({
|
|
|
115
126
|
fill,
|
|
116
127
|
valueOnly,
|
|
117
128
|
className,
|
|
129
|
+
diffPercentOnly = false,
|
|
118
130
|
}) => {
|
|
119
131
|
const format = money ? 'money' : percent ? 'percent' : rate ? 'rate' : 'number';
|
|
120
132
|
const val = value === undefined ? '\u00A0' : formatValue(value, format);
|
|
@@ -143,6 +155,7 @@ export const StatCard: React.FC<StatCardProps> = ({
|
|
|
143
155
|
format={format}
|
|
144
156
|
inverted={inverted}
|
|
145
157
|
neutral={neutral}
|
|
158
|
+
diffPercentOnly={diffPercentOnly}
|
|
146
159
|
/>
|
|
147
160
|
)}
|
|
148
161
|
</Stack>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
2
|
import { StatCard } from './stat-card';
|
|
3
3
|
|
|
4
4
|
export default {
|
|
@@ -7,9 +7,12 @@ export default {
|
|
|
7
7
|
parameters: {},
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
const w = (cb: () =>
|
|
10
|
+
const w = (cb: () => ReactElement) => () => <div style={{ width: '400px' }}>{cb()}</div>;
|
|
11
11
|
|
|
12
12
|
export const statCardNumber = w(() => <StatCard title="number" value={133} prev={1000} />);
|
|
13
|
+
export const statDiffNumberPercentOnly = w(() => (
|
|
14
|
+
<StatCard title="number" value={133} prev={1000} diffPercentOnly />
|
|
15
|
+
));
|
|
13
16
|
export const statCardMoney = w(() => <StatCard title="money" value={10000} prev={11000} money />);
|
|
14
17
|
export const statCardPercentInverted = w(() => (
|
|
15
18
|
<StatCard title="percent" value={0.27} prev={0.27333} percent inverted />
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
2
|
import { StatExtendedCard } from './stat-extended-card';
|
|
3
3
|
|
|
4
4
|
export default {
|
|
@@ -7,7 +7,7 @@ export default {
|
|
|
7
7
|
parameters: {},
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
const w = (cb: () =>
|
|
10
|
+
const w = (cb: () => ReactElement) => () => <div style={{ width: '400px' }}>{cb()}</div>;
|
|
11
11
|
|
|
12
12
|
export const statCardMoneyWithPrev = w(() => (
|
|
13
13
|
<StatExtendedCard
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FC } from 'react';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import { BodyText, Icon, Headline, Eyebrow, Stack, Tooltip } from '@servicetitan/design-system';
|
|
4
4
|
import { formatValue } from '../../utils/formatters';
|
|
5
5
|
import { StatDiff } from './stat-card';
|
|
6
|
+
import * as Styles from './stat-card.module.less';
|
|
6
7
|
|
|
7
8
|
export interface StatExtendedCardProps {
|
|
8
9
|
title: string;
|
|
@@ -54,11 +55,11 @@ export const StatExtendedCard: FC<StatExtendedCardProps> = ({
|
|
|
54
55
|
</Tooltip>
|
|
55
56
|
)}
|
|
56
57
|
</Stack>
|
|
57
|
-
<Eyebrow size="small" className="m-t-
|
|
58
|
+
<Eyebrow size="small" className="m-t-2 c-black">
|
|
58
59
|
{title2}
|
|
59
60
|
</Eyebrow>
|
|
60
61
|
|
|
61
|
-
<Stack justifyContent="space-between">
|
|
62
|
+
<Stack justifyContent="space-between" className="m-t-half">
|
|
62
63
|
<Stack alignItems="flex-end" className="flex-grow-1 flex-basis-0">
|
|
63
64
|
<Headline className="m-b-0-i m-r-half fw-normal-i" size="xlarge">
|
|
64
65
|
{formatValue(value, format)}
|
|
@@ -72,7 +73,7 @@ export const StatExtendedCard: FC<StatExtendedCardProps> = ({
|
|
|
72
73
|
format={format}
|
|
73
74
|
inverted={inverted}
|
|
74
75
|
neutral={neutral}
|
|
75
|
-
className=
|
|
76
|
+
className={classNames(Styles.statExtendedDiff, 'm-l-1')}
|
|
76
77
|
/>
|
|
77
78
|
) : undefined}
|
|
78
79
|
</Stack>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
2
|
import { CenteredSpinner } from './centered-spinner';
|
|
3
3
|
|
|
4
4
|
export default {
|
|
@@ -7,7 +7,7 @@ export default {
|
|
|
7
7
|
parameters: {},
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
const w = (style: { width?: string; height?: string }, cb: () =>
|
|
10
|
+
const w = (style: { width?: string; height?: string }, cb: () => ReactElement) => () =>
|
|
11
11
|
<div style={style}>{cb()}</div>;
|
|
12
12
|
|
|
13
13
|
export const centeredSpinnerTiny = w({}, () => <CenteredSpinner size="tiny" />);
|