@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.
Files changed (185) hide show
  1. package/dist/components/ads/ads-stat.d.ts +3 -3
  2. package/dist/components/ads/ads-stat.d.ts.map +1 -1
  3. package/dist/components/ads/ads-stat.js +4 -4
  4. package/dist/components/ads/ads-stat.js.map +1 -1
  5. package/dist/components/charts/funnel-chart/components/funnel-chart.d.ts +2 -2
  6. package/dist/components/charts/funnel-chart/components/funnel-chart.d.ts.map +1 -1
  7. package/dist/components/charts/funnel-chart/components/funnel-chart.js +4 -4
  8. package/dist/components/charts/funnel-chart/components/funnel-chart.js.map +1 -1
  9. package/dist/components/charts/funnel-chart/components/funnel-svg.d.ts +2 -2
  10. package/dist/components/charts/funnel-chart/components/funnel-svg.d.ts.map +1 -1
  11. package/dist/components/charts/funnel-chart/components/funnel-svg.js +4 -4
  12. package/dist/components/charts/funnel-chart/components/funnel-svg.js.map +1 -1
  13. package/dist/components/charts/funnel-chart/funnel-chart.stories.d.ts +2 -2
  14. package/dist/components/charts/funnel-chart/funnel-chart.stories.d.ts.map +1 -1
  15. package/dist/components/charts/funnel-chart/funnel-chart.stories.js +5 -5
  16. package/dist/components/charts/funnel-chart/funnel-chart.stories.js.map +1 -1
  17. package/dist/components/charts/line-chart/components/body.d.ts +2 -2
  18. package/dist/components/charts/line-chart/components/body.d.ts.map +1 -1
  19. package/dist/components/charts/line-chart/components/body.js +12 -12
  20. package/dist/components/charts/line-chart/components/body.js.map +1 -1
  21. package/dist/components/charts/line-chart/components/body.module.less +1 -1
  22. package/dist/components/charts/line-chart/components/container.d.ts +2 -2
  23. package/dist/components/charts/line-chart/components/container.d.ts.map +1 -1
  24. package/dist/components/charts/line-chart/components/container.js +5 -5
  25. package/dist/components/charts/line-chart/components/container.js.map +1 -1
  26. package/dist/components/charts/line-chart/components/hover-popover.d.ts +2 -2
  27. package/dist/components/charts/line-chart/components/hover-popover.d.ts.map +1 -1
  28. package/dist/components/charts/line-chart/components/hover-popover.js +8 -8
  29. package/dist/components/charts/line-chart/components/hover-popover.js.map +1 -1
  30. package/dist/components/charts/line-chart/components/hover-popover.module.less +1 -1
  31. package/dist/components/charts/line-chart/components/sidebar.d.ts +2 -2
  32. package/dist/components/charts/line-chart/components/sidebar.d.ts.map +1 -1
  33. package/dist/components/charts/line-chart/components/sidebar.js +3 -3
  34. package/dist/components/charts/line-chart/components/sidebar.js.map +1 -1
  35. package/dist/components/charts/line-chart/components/sidebar.module.less +2 -2
  36. package/dist/components/charts/line-chart/components/stuff.d.ts +4 -4
  37. package/dist/components/charts/line-chart/components/stuff.d.ts.map +1 -1
  38. package/dist/components/charts/line-chart/components/stuff.js +6 -6
  39. package/dist/components/charts/line-chart/components/stuff.js.map +1 -1
  40. package/dist/components/charts/line-chart/components/svg-bars.d.ts +3 -3
  41. package/dist/components/charts/line-chart/components/svg-bars.d.ts.map +1 -1
  42. package/dist/components/charts/line-chart/components/svg-bars.js +9 -9
  43. package/dist/components/charts/line-chart/components/svg-bars.js.map +1 -1
  44. package/dist/components/charts/line-chart/components/svg-body.d.ts +3 -3
  45. package/dist/components/charts/line-chart/components/svg-body.d.ts.map +1 -1
  46. package/dist/components/charts/line-chart/components/svg-body.js +6 -6
  47. package/dist/components/charts/line-chart/components/svg-body.js.map +1 -1
  48. package/dist/components/charts/line-chart/components/svg-lines.d.ts +2 -2
  49. package/dist/components/charts/line-chart/components/svg-lines.d.ts.map +1 -1
  50. package/dist/components/charts/line-chart/components/svg-lines.js +5 -5
  51. package/dist/components/charts/line-chart/components/svg-lines.js.map +1 -1
  52. package/dist/components/charts/line-chart/line-chart.stories.d.ts +2 -2
  53. package/dist/components/charts/line-chart/line-chart.stories.d.ts.map +1 -1
  54. package/dist/components/charts/line-chart/line-chart.stories.js +7 -7
  55. package/dist/components/charts/line-chart/line-chart.stories.js.map +1 -1
  56. package/dist/components/charts/line-chart/stores/line-chart.store.js +5 -5
  57. package/dist/components/charts/line-chart/stores/line-chart.store.js.map +1 -1
  58. package/dist/components/charts/line-chart/stores/svg.store.js +2 -2
  59. package/dist/components/charts/line-chart/stores/svg.store.js.map +1 -1
  60. package/dist/components/charts/line-chart/utils/formatters.js +2 -2
  61. package/dist/components/charts/line-chart/utils/formatters.js.map +1 -1
  62. package/dist/components/charts/line-chart/utils/interfaces.d.ts +2 -2
  63. package/dist/components/charts/line-chart/utils/interfaces.d.ts.map +1 -1
  64. package/dist/components/charts/line-chart/utils/labels.js +16 -16
  65. package/dist/components/charts/line-chart/utils/labels.js.map +1 -1
  66. package/dist/components/charts/pie-chart/components/pie-chart.d.ts +2 -2
  67. package/dist/components/charts/pie-chart/components/pie-chart.d.ts.map +1 -1
  68. package/dist/components/charts/pie-chart/components/pie-chart.js +5 -5
  69. package/dist/components/charts/pie-chart/components/pie-chart.js.map +1 -1
  70. package/dist/components/charts/pie-chart/components/pie.d.ts +5 -2
  71. package/dist/components/charts/pie-chart/components/pie.d.ts.map +1 -1
  72. package/dist/components/charts/pie-chart/components/pie.js +21 -41
  73. package/dist/components/charts/pie-chart/components/pie.js.map +1 -1
  74. package/dist/components/charts/pie-chart/pie-chart.stories.d.ts +3 -2
  75. package/dist/components/charts/pie-chart/pie-chart.stories.d.ts.map +1 -1
  76. package/dist/components/charts/pie-chart/pie-chart.stories.js +10 -4
  77. package/dist/components/charts/pie-chart/pie-chart.stories.js.map +1 -1
  78. package/dist/components/charts/pie-chart/utils/const.d.ts +2 -2
  79. package/dist/components/charts/pie-chart/utils/const.d.ts.map +1 -1
  80. package/dist/components/charts/pie-chart/utils/const.js +10 -8
  81. package/dist/components/charts/pie-chart/utils/const.js.map +1 -1
  82. package/dist/components/charts/pie-chart/utils/interface.d.ts +5 -2
  83. package/dist/components/charts/pie-chart/utils/interface.d.ts.map +1 -1
  84. package/dist/components/image-cropper/image-cropper.d.ts +2 -2
  85. package/dist/components/image-cropper/image-cropper.d.ts.map +1 -1
  86. package/dist/components/image-cropper/image-cropper.js +4 -4
  87. package/dist/components/image-cropper/image-cropper.js.map +1 -1
  88. package/dist/components/image-cropper/image-cropper.stories.js +6 -9
  89. package/dist/components/image-cropper/image-cropper.stories.js.map +1 -1
  90. package/dist/components/stat/stat-card.d.ts +5 -3
  91. package/dist/components/stat/stat-card.d.ts.map +1 -1
  92. package/dist/components/stat/stat-card.js +21 -14
  93. package/dist/components/stat/stat-card.js.map +1 -1
  94. package/dist/components/stat/stat-card.module.less +7 -0
  95. package/dist/components/stat/stat-cards.stories.d.ts +3 -2
  96. package/dist/components/stat/stat-cards.stories.d.ts.map +1 -1
  97. package/dist/components/stat/stat-cards.stories.js +7 -6
  98. package/dist/components/stat/stat-cards.stories.js.map +1 -1
  99. package/dist/components/stat/stat-extended-card.d.ts.map +1 -1
  100. package/dist/components/stat/stat-extended-card.js +22 -2
  101. package/dist/components/stat/stat-extended-card.js.map +1 -1
  102. package/dist/components/stat/stat-extended-card.stories.d.ts +2 -2
  103. package/dist/components/stat/stat-extended-card.stories.d.ts.map +1 -1
  104. package/dist/components/stat/stat-extended-card.stories.js +4 -4
  105. package/dist/components/stat/stat-extended-card.stories.js.map +1 -1
  106. package/dist/components/ui/centered-spinner.d.ts +2 -2
  107. package/dist/components/ui/centered-spinner.d.ts.map +1 -1
  108. package/dist/components/ui/centered-spinner.js +2 -2
  109. package/dist/components/ui/centered-spinner.js.map +1 -1
  110. package/dist/components/ui/centered-spinner.stories.d.ts +2 -2
  111. package/dist/components/ui/centered-spinner.stories.d.ts.map +1 -1
  112. package/dist/components/ui/centered-spinner.stories.js +4 -4
  113. package/dist/components/ui/centered-spinner.stories.js.map +1 -1
  114. package/dist/components/ui/date-range-picker/date-range-picker.js +5 -5
  115. package/dist/components/ui/date-range-picker/date-range-picker.js.map +1 -1
  116. package/dist/components/ui/date-range-picker/date-range-picker.module.less +1 -1
  117. package/dist/components/ui/date-range-picker/date-range-picker.stories.js +3 -3
  118. package/dist/components/ui/date-range-picker/date-range-picker.stories.js.map +1 -1
  119. package/dist/components/ui/disabled-button.d.ts +2 -2
  120. package/dist/components/ui/disabled-button.d.ts.map +1 -1
  121. package/dist/components/ui/disabled-button.js +1 -1
  122. package/dist/components/ui/disabled-button.js.map +1 -1
  123. package/dist/components/ui/line-text/line-text-body.stories.d.ts +2 -2
  124. package/dist/components/ui/line-text/line-text-body.stories.d.ts.map +1 -1
  125. package/dist/components/ui/line-text/line-text-body.stories.js +3 -3
  126. package/dist/components/ui/line-text/line-text-body.stories.js.map +1 -1
  127. package/dist/components/ui/line-text/line-text-head.stories.d.ts +2 -2
  128. package/dist/components/ui/line-text/line-text-head.stories.d.ts.map +1 -1
  129. package/dist/components/ui/line-text/line-text-head.stories.js +3 -3
  130. package/dist/components/ui/line-text/line-text-head.stories.js.map +1 -1
  131. package/dist/components/ui/line-text/line-text.d.ts +3 -3
  132. package/dist/components/ui/line-text/line-text.d.ts.map +1 -1
  133. package/dist/components/ui/line-text/line-text.js +7 -7
  134. package/dist/components/ui/line-text/line-text.js.map +1 -1
  135. package/dist/utils/date/date-range-picker-options.js +2 -2
  136. package/dist/utils/date/date-range-picker-options.js.map +1 -1
  137. package/dist/utils/date/date-range-picker-state.js +1 -1
  138. package/dist/utils/date/date-range-picker-state.js.map +1 -1
  139. package/dist/utils/date/date.js +1 -1
  140. package/dist/utils/date/date.js.map +1 -1
  141. package/dist/utils/formatters.js +7 -7
  142. package/dist/utils/formatters.js.map +1 -1
  143. package/dist/utils/use-client-rect.js +6 -25
  144. package/dist/utils/use-client-rect.js.map +1 -1
  145. package/package.json +2 -2
  146. package/src/components/ads/ads-stat.tsx +3 -3
  147. package/src/components/charts/funnel-chart/components/funnel-chart.tsx +2 -2
  148. package/src/components/charts/funnel-chart/components/funnel-svg.tsx +2 -2
  149. package/src/components/charts/funnel-chart/funnel-chart.stories.tsx +2 -2
  150. package/src/components/charts/line-chart/components/body.module.less +1 -1
  151. package/src/components/charts/line-chart/components/body.tsx +5 -5
  152. package/src/components/charts/line-chart/components/container.tsx +2 -2
  153. package/src/components/charts/line-chart/components/hover-popover.module.less +1 -1
  154. package/src/components/charts/line-chart/components/hover-popover.tsx +4 -4
  155. package/src/components/charts/line-chart/components/sidebar.module.less +2 -2
  156. package/src/components/charts/line-chart/components/sidebar.tsx +2 -2
  157. package/src/components/charts/line-chart/components/stuff.tsx +5 -5
  158. package/src/components/charts/line-chart/components/svg-bars.tsx +3 -3
  159. package/src/components/charts/line-chart/components/svg-body.tsx +4 -4
  160. package/src/components/charts/line-chart/components/svg-lines.tsx +3 -3
  161. package/src/components/charts/line-chart/line-chart.stories.tsx +1 -1
  162. package/src/components/charts/line-chart/utils/interfaces.ts +2 -2
  163. package/src/components/charts/pie-chart/components/pie-chart.tsx +20 -7
  164. package/src/components/charts/pie-chart/components/pie.tsx +42 -22
  165. package/src/components/charts/pie-chart/pie-chart.stories.tsx +20 -1
  166. package/src/components/charts/pie-chart/utils/const.ts +11 -6
  167. package/src/components/charts/pie-chart/utils/interface.ts +5 -2
  168. package/src/components/image-cropper/image-cropper.stories.tsx +8 -8
  169. package/src/components/image-cropper/image-cropper.tsx +2 -2
  170. package/src/components/stat/stat-card.module.less +7 -0
  171. package/src/components/stat/stat-card.module.less.d.ts +1 -0
  172. package/src/components/stat/stat-card.tsx +20 -7
  173. package/src/components/stat/stat-cards.stories.tsx +5 -2
  174. package/src/components/stat/stat-extended-card.stories.tsx +2 -2
  175. package/src/components/stat/stat-extended-card.tsx +5 -4
  176. package/src/components/ui/centered-spinner.stories.tsx +2 -2
  177. package/src/components/ui/centered-spinner.tsx +2 -6
  178. package/src/components/ui/date-range-picker/date-range-picker.module.less +1 -1
  179. package/src/components/ui/date-range-picker/date-range-picker.stories.tsx +2 -2
  180. package/src/components/ui/date-range-picker/date-range-picker.tsx +1 -1
  181. package/src/components/ui/disabled-button.tsx +2 -2
  182. package/src/components/ui/line-text/line-text-body.stories.tsx +2 -2
  183. package/src/components/ui/line-text/line-text-head.stories.tsx +2 -2
  184. package/src/components/ui/line-text/line-text.tsx +3 -11
  185. package/src/utils/use-client-rect.ts +2 -2
@@ -1,4 +1,4 @@
1
- import React from 'react';
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: React.FC<SvgBarsProps> = observer(({ metrics, isStackedBarChart }) => {
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: React.FC<SvgBarsHoverProps> = observer(({ onHover, onLeave }) => {
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 React from 'react';
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: React.FC = () => {
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: React.FC<SvgBodyProps> = observer(({ horizontalGrid, metrics }) => {
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: React.FC<SvgBodyHoverProps> = ({ onValueHover, onValueLeave }) => (
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 React, { useMemo } from 'react';
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: React.FC<SvgLineProps> = ({ color, points, dashed }) => (
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: React.FC<SvgLinesProps> = observer(({ metrics }) => {
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 React, { FC, useState } from 'react';
1
+ import { FC, useState } from 'react';
2
2
  import { Form } from '@servicetitan/design-system';
3
3
  import { LineChart, LineChartPeriod } from './index';
4
4
 
@@ -1,4 +1,4 @@
1
- import React from 'react';
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?: React.ReactElement;
77
+ headerRight?: ReactElement;
78
78
  loading?: boolean;
79
79
  grayControls?: boolean;
80
80
  }
@@ -1,12 +1,12 @@
1
- import React, { useMemo } from 'react';
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: React.FC<{ title: string; pieces: PiePiece[] }> = ({ title, pieces }) => {
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: React.FC<PieChartProps> = ({
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(() => convertSessionsToPieces(sections), [sections]);
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 title={title} pieces={pieces} popoverContent={popoverContent} />
44
- <PieTitles title={title} pieces={pieces} />
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 React, { useCallback, useMemo, useState } from 'react';
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: React.FC<{
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: React.FC<{
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: React.FC<{
68
+ const PieSvg: FC<{
70
69
  pieces: PiePiece[];
71
70
  selectedIndex: number;
72
- }> = ({ pieces, selectedIndex }) => (
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: React.FC<{
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: React.FC<{
108
+ export const Pie: FC<{
108
109
  title: string;
109
110
  pieces: PiePiece[];
111
+ radiusRelative: number;
112
+ content?: FC;
110
113
  popoverContent?: PieChartPopoverContentType;
111
- }> = ({ pieces, popoverContent: PopoverContent }) => {
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
- <React.Fragment>
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
- <Stack alignItems="center">
182
- <StatusLight color={pieces[ind].color} />
183
- <BodyText size="small" bold>
184
- {pieces[ind].title}
185
- </BodyText>
186
- </Stack>
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 pieces={pieces} selectedIndex={selectedIndex} />
204
- <PieSvgHover pieces={pieces} onMouse={onMouse} />
205
- </React.Fragment>
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 radiusRelative = 50;
4
+ export const radiusRelativeDefault = 50;
5
5
  const radiusInt = 20;
6
- const radiusExt = radiusRelative - 5; // need to have some space to stroke selected piece
7
- const radiusMid = (3 * radiusRelative) / 4;
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>(sections: PieChartSection<T>[]): PiePiece<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 React from 'react';
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> = React.FC<{
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 React from 'react';
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: React.FC = () => {
11
- const [imageToEdit, setImageToEdit] = React.useState<File>();
12
- const [croppedImage, setCroppedImage] = React.useState<string>();
10
+ const BasicExample: FC = () => {
11
+ const [imageToEdit, setImageToEdit] = useState<File>();
12
+ const [croppedImage, setCroppedImage] = useState<string>();
13
13
 
14
- const imageCropper = React.useRef<ImageCropper>(null);
14
+ const imageCropper = useRef<ImageCropper>(null);
15
15
 
16
- const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
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
- <React.Fragment>
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
- </React.Fragment>
65
+ </Fragment>
66
66
  );
67
67
  };
68
68
 
@@ -1,4 +1,4 @@
1
- import React from 'react';
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 React.Component<ImageCropperProps> {
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;
@@ -2,6 +2,13 @@
2
2
 
3
3
  .stat-diff {
4
4
  white-space: nowrap;
5
+ span {
6
+ font-size: @typescale-0;
7
+ }
8
+ }
9
+
10
+ .stat-extended-diff {
11
+ margin-bottom: 2px;
5
12
  }
6
13
 
7
14
  .title {
@@ -1,4 +1,5 @@
1
1
  export const __esModule: true;
2
2
  export const statDiff: string;
3
+ export const statExtendedDiff: string;
3
4
  export const title: string;
4
5
 
@@ -1,4 +1,4 @@
1
- import React from 'react';
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: React.FC<StatDiffProps> = ({
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
- let text = absDiff === 0 ? '' : isIncrease ? '▲ ' : '▼ ';
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
- text += formatDifference(absDiff, isIncrease, format);
66
+ const diffPercentage = formatDifferencePercentage(diffPercent, isIncrease);
64
67
 
65
- if (diffPercent !== 0) {
66
- text += ` (${formatDifferencePercentage(diffPercent, isIncrease)})`;
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: React.FC<StatCardProps> = ({
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 React from 'react';
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: () => React.ReactElement) => () => <div style={{ width: '400px' }}>{cb()}</div>;
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 React from 'react';
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: () => React.ReactElement) => () => <div style={{ width: '400px' }}>{cb()}</div>;
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 React, { FC } from 'react';
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-3 c-black">
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="m-l-1"
76
+ className={classNames(Styles.statExtendedDiff, 'm-l-1')}
76
77
  />
77
78
  ) : undefined}
78
79
  </Stack>
@@ -1,4 +1,4 @@
1
- import React from 'react';
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: () => React.ReactElement) => () =>
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" />);