@servicetitan/marketing-ui 5.11.1 → 6.0.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 (99) hide show
  1. package/dist/components/charts/common/color-tag.d.ts +15 -0
  2. package/dist/components/charts/common/color-tag.d.ts.map +1 -0
  3. package/dist/components/charts/common/color-tag.js +79 -0
  4. package/dist/components/charts/common/color-tag.js.map +1 -0
  5. package/dist/components/charts/common/color-tag.module.less +23 -0
  6. package/dist/components/charts/common/color-tag.module.less.d.ts +6 -0
  7. package/dist/components/charts/common/index.d.ts +2 -0
  8. package/dist/components/charts/common/index.d.ts.map +1 -0
  9. package/dist/components/charts/common/index.js +3 -0
  10. package/dist/components/charts/common/index.js.map +1 -0
  11. package/dist/components/charts/funnel-chart/components/funnel-chart.d.ts.map +1 -1
  12. package/dist/components/charts/funnel-chart/components/funnel-chart.js +115 -70
  13. package/dist/components/charts/funnel-chart/components/funnel-chart.js.map +1 -1
  14. package/dist/components/charts/funnel-chart/components/funnel-chart.module.less +28 -10
  15. package/dist/components/charts/funnel-chart/components/funnel-chart.module.less.d.ts +3 -1
  16. package/dist/components/charts/funnel-chart/components/funnel-svg.d.ts +2 -0
  17. package/dist/components/charts/funnel-chart/components/funnel-svg.d.ts.map +1 -1
  18. package/dist/components/charts/funnel-chart/components/funnel-svg.js +72 -31
  19. package/dist/components/charts/funnel-chart/components/funnel-svg.js.map +1 -1
  20. package/dist/components/charts/funnel-chart/funnel-chart.stories.d.ts.map +1 -1
  21. package/dist/components/charts/funnel-chart/utils/const.d.ts +1 -1
  22. package/dist/components/charts/funnel-chart/utils/const.js +1 -1
  23. package/dist/components/charts/funnel-chart/utils/const.js.map +1 -1
  24. package/dist/components/charts/funnel-chart/utils/interface.d.ts +1 -0
  25. package/dist/components/charts/funnel-chart/utils/interface.d.ts.map +1 -1
  26. package/dist/components/charts/funnel-chart/utils/interface.js.map +1 -1
  27. package/dist/components/charts/funnel-chart/utils/svg-rounded-path.d.ts +2 -0
  28. package/dist/components/charts/funnel-chart/utils/svg-rounded-path.d.ts.map +1 -0
  29. package/dist/components/charts/funnel-chart/utils/svg-rounded-path.js +47 -0
  30. package/dist/components/charts/funnel-chart/utils/svg-rounded-path.js.map +1 -0
  31. package/dist/components/charts/line-chart/components/hover-popover.d.ts.map +1 -1
  32. package/dist/components/charts/line-chart/components/hover-popover.js +13 -7
  33. package/dist/components/charts/line-chart/components/hover-popover.js.map +1 -1
  34. package/dist/components/charts/line-chart/components/hover-popover.module.less +10 -0
  35. package/dist/components/charts/line-chart/components/hover-popover.module.less.d.ts +2 -0
  36. package/dist/components/charts/line-chart/components/stuff.d.ts +0 -8
  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 -20
  39. package/dist/components/charts/line-chart/components/stuff.js.map +1 -1
  40. package/dist/components/charts/line-chart/components/stuff.module.less +0 -16
  41. package/dist/components/charts/line-chart/components/stuff.module.less.d.ts +0 -3
  42. package/dist/components/charts/line-chart/components/svg-bars.d.ts.map +1 -1
  43. package/dist/components/charts/line-chart/components/svg-bars.js +97 -13
  44. package/dist/components/charts/line-chart/components/svg-bars.js.map +1 -1
  45. package/dist/components/charts/line-chart/line-chart.stories.d.ts.map +1 -1
  46. package/dist/components/charts/line-chart/stores/line-chart.store.d.ts +5 -0
  47. package/dist/components/charts/line-chart/stores/line-chart.store.d.ts.map +1 -1
  48. package/dist/components/charts/line-chart/stores/line-chart.store.js +41 -1
  49. package/dist/components/charts/line-chart/stores/line-chart.store.js.map +1 -1
  50. package/dist/components/charts/line-chart/utils/interfaces.d.ts +4 -0
  51. package/dist/components/charts/line-chart/utils/interfaces.d.ts.map +1 -1
  52. package/dist/components/charts/line-chart/utils/interfaces.js.map +1 -1
  53. package/dist/components/charts/line-chart/utils/labels.js +1 -1
  54. package/dist/components/charts/line-chart/utils/labels.js.map +1 -1
  55. package/dist/components/charts/pie-chart/components/pie-chart.d.ts.map +1 -1
  56. package/dist/components/charts/pie-chart/components/pie-chart.js +24 -13
  57. package/dist/components/charts/pie-chart/components/pie-chart.js.map +1 -1
  58. package/dist/components/charts/pie-chart/components/pie-chart.module.less +15 -0
  59. package/dist/components/charts/pie-chart/components/pie-chart.module.less.d.ts +1 -0
  60. package/dist/components/charts/pie-chart/components/pie.d.ts.map +1 -1
  61. package/dist/components/charts/pie-chart/components/pie.js +105 -28
  62. package/dist/components/charts/pie-chart/components/pie.js.map +1 -1
  63. package/dist/components/charts/pie-chart/pie-chart.stories.d.ts.map +1 -1
  64. package/dist/components/charts/pie-chart/utils/const.js +1 -1
  65. package/dist/components/charts/pie-chart/utils/const.js.map +1 -1
  66. package/dist/components/stat/stat-card.d.ts.map +1 -1
  67. package/dist/components/stat/stat-card.js +28 -12
  68. package/dist/components/stat/stat-card.js.map +1 -1
  69. package/package.json +5 -3
  70. package/src/components/charts/common/color-tag.module.less +23 -0
  71. package/src/components/charts/common/color-tag.module.less.d.ts +6 -0
  72. package/src/components/charts/common/color-tag.tsx +92 -0
  73. package/src/components/charts/common/index.ts +1 -0
  74. package/src/components/charts/funnel-chart/components/funnel-chart.module.less +28 -10
  75. package/src/components/charts/funnel-chart/components/funnel-chart.module.less.d.ts +3 -1
  76. package/src/components/charts/funnel-chart/components/funnel-chart.tsx +107 -78
  77. package/src/components/charts/funnel-chart/components/funnel-svg.tsx +91 -23
  78. package/src/components/charts/funnel-chart/funnel-chart.stories.tsx +3 -1
  79. package/src/components/charts/funnel-chart/utils/const.ts +1 -1
  80. package/src/components/charts/funnel-chart/utils/interface.ts +1 -0
  81. package/src/components/charts/funnel-chart/utils/svg-rounded-path.ts +86 -0
  82. package/src/components/charts/line-chart/components/hover-popover.module.less +10 -0
  83. package/src/components/charts/line-chart/components/hover-popover.module.less.d.ts +2 -0
  84. package/src/components/charts/line-chart/components/hover-popover.tsx +29 -9
  85. package/src/components/charts/line-chart/components/stuff.module.less +0 -16
  86. package/src/components/charts/line-chart/components/stuff.module.less.d.ts +0 -3
  87. package/src/components/charts/line-chart/components/stuff.tsx +4 -30
  88. package/src/components/charts/line-chart/components/svg-bars.tsx +106 -9
  89. package/src/components/charts/line-chart/line-chart.stories.tsx +13 -8
  90. package/src/components/charts/line-chart/stores/line-chart.store.ts +39 -1
  91. package/src/components/charts/line-chart/utils/interfaces.ts +4 -0
  92. package/src/components/charts/line-chart/utils/labels.ts +1 -1
  93. package/src/components/charts/pie-chart/components/pie-chart.module.less +15 -0
  94. package/src/components/charts/pie-chart/components/pie-chart.module.less.d.ts +1 -0
  95. package/src/components/charts/pie-chart/components/pie-chart.tsx +23 -13
  96. package/src/components/charts/pie-chart/components/pie.tsx +106 -40
  97. package/src/components/charts/pie-chart/pie-chart.stories.tsx +3 -4
  98. package/src/components/charts/pie-chart/utils/const.ts +1 -1
  99. package/src/components/stat/stat-card.tsx +34 -16
@@ -1,20 +1,22 @@
1
1
  import { useCallback, useMemo, useState, FC, Fragment } from 'react';
2
2
  import { tokens } from '@servicetitan/tokens/core';
3
- import { BodyText, Popover, Stack, StatusLight } from '@servicetitan/design-system';
3
+ import { BodyText, Popover, Stack } from '@servicetitan/design-system';
4
4
 
5
5
  import { useClientRect } from '../../../../utils/use-client-rect';
6
6
  import { PieChartPopoverContentType, PiePiece, PopoverDirection } from '../utils/interface';
7
+ import { ColorTag } from '../../common';
7
8
 
8
9
  const chartPadding = 8;
9
10
  const px = (value?: number) => `${value ?? 0}px`;
11
+ const GAP_PX = 4;
10
12
 
11
13
  const PiePieceSvg: FC<{
12
14
  piece: PiePiece;
13
15
  selected?: boolean;
14
- }> = ({ piece: { id, color, opacity, points, text, path }, selected }) =>
16
+ }> = ({ piece: { id, color, points, text, path }, selected }) =>
15
17
  points && path ? (
16
18
  <g id={id}>
17
- {!!selected && (
19
+ {selected && (
18
20
  <path
19
21
  d={path}
20
22
  fill={tokens.colorWhite}
@@ -25,25 +27,43 @@ const PiePieceSvg: FC<{
25
27
  />
26
28
  )}
27
29
  <path d={path} fill={color} />
30
+ {points[4] && (
31
+ <g transform={`translate(${points[4][0]}, ${points[4][1]})`} pointerEvents="none">
32
+ {(() => {
33
+ const fontSize = 3;
34
+ const height = 6;
35
+ const radius = height / 2;
28
36
 
29
- <svg
30
- x={points[4][0] - 10}
31
- y={points[4][1] - (points[4][1] > 0 ? 3 : 1)}
32
- width={20}
33
- height={6}
34
- >
35
- <text
36
- x="50%"
37
- y="50%"
38
- fontSize={4}
39
- fontWeight={600}
40
- fill={opacity > 0.3 ? tokens.colorWhite : tokens.colorBlack}
41
- dominantBaseline="middle"
42
- textAnchor="middle"
43
- >
44
- {text}
45
- </text>
46
- </svg>
37
+ const width = Math.max(8, text.length);
38
+
39
+ return (
40
+ <Fragment>
41
+ <rect
42
+ x={-width / 2}
43
+ y={-height / 2}
44
+ width={width}
45
+ height={height}
46
+ rx={radius}
47
+ ry={radius}
48
+ fill="rgba(255,255,255,0.80)"
49
+ strokeWidth={0.6}
50
+ />
51
+ <text
52
+ x="0"
53
+ y="0"
54
+ fontSize={fontSize}
55
+ fontWeight={600}
56
+ textAnchor="middle"
57
+ dominantBaseline="middle"
58
+ fill={tokens.colorBlack}
59
+ >
60
+ {text}
61
+ </text>
62
+ </Fragment>
63
+ );
64
+ })()}
65
+ </g>
66
+ )}
47
67
  </g>
48
68
  ) : null;
49
69
 
@@ -69,23 +89,67 @@ const PieSvg: FC<{
69
89
  pieces: PiePiece[];
70
90
  selectedIndex: number;
71
91
  radiusRelative: number;
72
- }> = ({ pieces, selectedIndex, radiusRelative }) => (
73
- <svg
74
- className="position-absolute"
75
- style={{ inset: px(chartPadding) }}
76
- viewBox={
77
- `-${radiusRelative} -${radiusRelative} ` + `${radiusRelative * 2} ${radiusRelative * 2}`
78
- }
79
- >
80
- {pieces.map((p, index) =>
81
- p.path ? <PiePieceSvg piece={p} key={p.id} selected={index === selectedIndex} /> : null
82
- )}
92
+ }> = ({ pieces, selectedIndex, radiusRelative }) => {
93
+ const piePiece = pieces.find(p => p.points);
94
+ const innerR = piePiece ? Math.hypot(piePiece.points![3][0], piePiece.points![3][1]) : 0;
95
+ const outerR = piePiece ? Math.hypot(piePiece.points![1][0], piePiece.points![1][1]) : 0;
83
96
 
84
- {selectedIndex >= 0 && selectedIndex < pieces.length && (
85
- <use xlinkHref={pieces[selectedIndex].id} />
86
- )}
87
- </svg>
88
- );
97
+ const boundaries = pieces
98
+ .filter(p => p.points)
99
+ .map(p => {
100
+ const [outerX, outerY] = p.points![1];
101
+ const len = Math.hypot(outerX, outerY) || 1;
102
+ return { x: outerX / len, y: outerY / len };
103
+ });
104
+
105
+ return (
106
+ <svg
107
+ className="position-absolute"
108
+ style={{ inset: `${chartPadding}px` }}
109
+ viewBox={`-${radiusRelative} -${radiusRelative} ${radiusRelative * 2} ${radiusRelative * 2}`}
110
+ >
111
+ {pieces.map((p, i) =>
112
+ p.path ? <PiePieceSvg piece={p} key={p.id} selected={i === selectedIndex} /> : null
113
+ )}
114
+
115
+ {pieces.length > 1 && innerR > 0 && outerR > 0 && (
116
+ <Fragment>
117
+ <defs>
118
+ <mask id="ring-mask">
119
+ <rect
120
+ x={-outerR}
121
+ y={-outerR}
122
+ width={outerR * 2}
123
+ height={outerR * 2}
124
+ fill="black"
125
+ />
126
+ <circle cx="0" cy="0" r={outerR} fill="white" />
127
+ <circle cx="0" cy="0" r={innerR} fill="black" />
128
+ </mask>
129
+ </defs>
130
+ <g mask="url(#ring-mask)" pointerEvents="none">
131
+ {boundaries.map(boundary => (
132
+ <line
133
+ key={`sep-${boundary.x}-${boundary.y}`}
134
+ x1={boundary.x * innerR}
135
+ y1={boundary.y * innerR}
136
+ x2={boundary.x * outerR}
137
+ y2={boundary.y * outerR}
138
+ stroke="#fff"
139
+ strokeWidth={GAP_PX}
140
+ vectorEffect="non-scaling-stroke"
141
+ strokeLinecap="round"
142
+ />
143
+ ))}
144
+ </g>
145
+ </Fragment>
146
+ )}
147
+ {selectedIndex >= 0 && selectedIndex < pieces.length && (
148
+ <use xlinkHref={`#${pieces[selectedIndex].id}`} />
149
+ )}
150
+ </svg>
151
+ );
152
+ };
89
153
 
90
154
  const PieSvgHover: FC<{
91
155
  pieces: PiePiece[];
@@ -140,7 +204,6 @@ export const Pie: FC<{
140
204
  styles: height
141
205
  ? {
142
206
  width: px(Math.max(250, height)),
143
- overflow: 'hidden',
144
207
  }
145
208
  : {},
146
209
  };
@@ -170,7 +233,7 @@ export const Pie: FC<{
170
233
  );
171
234
 
172
235
  return (
173
- <div ref={ref} style={container.styles} className="position-relative">
236
+ <div ref={ref} style={container.styles} className="position-relative h-100">
174
237
  {pieces.every(p => !p.path) ? (
175
238
  <Stack className="h-100" justifyContent="center" alignItems="center">
176
239
  No Data
@@ -197,7 +260,10 @@ export const Pie: FC<{
197
260
  >
198
261
  {!hideTitles && (
199
262
  <Stack alignItems="center">
200
- <StatusLight color={pieces[ind].color} />
263
+ <ColorTag
264
+ label=""
265
+ color={pieces[ind].color}
266
+ />
201
267
  <BodyText size="small" bold>
202
268
  {pieces[ind].title}
203
269
  </BodyText>
@@ -10,7 +10,7 @@ export default {
10
10
  export const pieChart5AutoColor = () => (
11
11
  <PieChart
12
12
  title="Pie Chart"
13
- height={250}
13
+ height={220}
14
14
  sections={[
15
15
  { title: 'lorem', value: 99 },
16
16
  { title: 'ipsum', value: 88 },
@@ -25,7 +25,7 @@ export const pieChart5AutoColor = () => (
25
25
  export const pieChartWithContent = () => (
26
26
  <PieChart
27
27
  title="Pie Chart"
28
- height={300}
28
+ height={284}
29
29
  sections={[
30
30
  { title: 'New Customer', value: 61 },
31
31
  { title: 'Existing Customer', value: 90 },
@@ -36,8 +36,7 @@ export const pieChartWithContent = () => (
36
36
  <Eyebrow size="small">Total Leads</Eyebrow>
37
37
  </Stack>
38
38
  )}
39
- radiusRelative={45}
40
- hideTitles
39
+ radiusRelative={40}
41
40
  />
42
41
  );
43
42
 
@@ -4,7 +4,7 @@ import { formatNumber } from 'accounting';
4
4
  export const radiusRelativeDefault = 50;
5
5
  const radiusInt = 20;
6
6
  const getRadiusExt = (radiusRelative: number) => radiusRelative - 5; // need to have some space to stroke selected piece
7
- const getRadiusMid = (radiusRelative: number) => (3 * radiusRelative) / 4;
7
+ const getRadiusMid = (radiusRelative: number) => (2.75 * radiusRelative) / 4;
8
8
 
9
9
  const angleInitial = -0.5;
10
10
  const lowestOpacity = 0.1;
@@ -10,6 +10,9 @@ import {
10
10
  } from '@servicetitan/design-system';
11
11
  import * as Styles from './stat-card.module.less';
12
12
  import { formatValue, NumberFormatter } from '../../utils/formatters';
13
+ import { Icon } from '@servicetitan/anvil2';
14
+ import TrendingUpSVG from '@servicetitan/anvil2/assets/icons/material/round/trending_up.svg';
15
+ import TrendingDownSVG from '@servicetitan/anvil2/assets/icons/material/round/trending_down.svg';
13
16
 
14
17
  const calculateDiff = (
15
18
  value: number,
@@ -64,7 +67,16 @@ export const StatDiff: FC<StatDiffProps> = ({
64
67
  }) => {
65
68
  const percents = format === 'percent';
66
69
  const [absDiff, diffPercent, isIncrease] = calculateDiff(value ?? 0, prev ?? 0, percents);
67
- const diff = absDiff === 0 ? '' : isIncrease ? '▲ ' : '▼ ';
70
+ const diff =
71
+ absDiff === 0 ? (
72
+ ''
73
+ ) : (
74
+ <Icon
75
+ svg={isIncrease ? TrendingUpSVG : TrendingDownSVG}
76
+ color={isIncrease ? 'green' : 'red'}
77
+ className="m-r-half m-t-half"
78
+ />
79
+ );
68
80
  let text = '';
69
81
 
70
82
  if (percents) {
@@ -84,22 +96,28 @@ export const StatDiff: FC<StatDiffProps> = ({
84
96
  }
85
97
 
86
98
  return (
87
- <BodyText
88
- className={classNames(
89
- Styles.statDiff,
90
- {
91
- 'c-red-500': !neutral && (inverted ? isIncrease : !isIncrease),
92
- 'c-green-500': !neutral && (inverted ? !isIncrease : isIncrease),
93
- 'c-neutral-200': !!neutral,
94
- },
95
- className
96
- )}
97
- size={size ?? 'small'}
98
- data-cy="stat-diff-value"
99
+ <Stack
100
+ className={classNames(Styles.statDiff, className)}
101
+ justifyContent="center"
102
+ alignItems="center"
99
103
  >
100
- <span>{diff}</span>
101
- {value === undefined ? '\u00A0' : text}
102
- </BodyText>
104
+ <Stack.Item>
105
+ <span>{diff}</span>
106
+ </Stack.Item>
107
+ <Stack.Item>
108
+ <BodyText
109
+ size={size ?? 'small'}
110
+ data-cy="stat-diff-value"
111
+ className={classNames({
112
+ 'c-red-500': !neutral && (inverted ? isIncrease : !isIncrease),
113
+ 'c-green-500': !neutral && (inverted ? !isIncrease : isIncrease),
114
+ 'c-neutral-200': !!neutral,
115
+ })}
116
+ >
117
+ {value === undefined ? '\u00A0' : text}
118
+ </BodyText>
119
+ </Stack.Item>
120
+ </Stack>
103
121
  );
104
122
  };
105
123