@servicetitan/marketing-ui 5.11.0 → 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 (123) 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/index.d.ts +1 -1
  22. package/dist/components/charts/funnel-chart/index.d.ts.map +1 -1
  23. package/dist/components/charts/funnel-chart/index.js +0 -1
  24. package/dist/components/charts/funnel-chart/index.js.map +1 -1
  25. package/dist/components/charts/funnel-chart/utils/const.d.ts +1 -1
  26. package/dist/components/charts/funnel-chart/utils/const.js +1 -1
  27. package/dist/components/charts/funnel-chart/utils/const.js.map +1 -1
  28. package/dist/components/charts/funnel-chart/utils/interface.d.ts +1 -0
  29. package/dist/components/charts/funnel-chart/utils/interface.d.ts.map +1 -1
  30. package/dist/components/charts/funnel-chart/utils/interface.js.map +1 -1
  31. package/dist/components/charts/funnel-chart/utils/svg-rounded-path.d.ts +2 -0
  32. package/dist/components/charts/funnel-chart/utils/svg-rounded-path.d.ts.map +1 -0
  33. package/dist/components/charts/funnel-chart/utils/svg-rounded-path.js +47 -0
  34. package/dist/components/charts/funnel-chart/utils/svg-rounded-path.js.map +1 -0
  35. package/dist/components/charts/line-chart/components/hover-popover.d.ts.map +1 -1
  36. package/dist/components/charts/line-chart/components/hover-popover.js +13 -7
  37. package/dist/components/charts/line-chart/components/hover-popover.js.map +1 -1
  38. package/dist/components/charts/line-chart/components/hover-popover.module.less +10 -0
  39. package/dist/components/charts/line-chart/components/hover-popover.module.less.d.ts +2 -0
  40. package/dist/components/charts/line-chart/components/stuff.d.ts +0 -8
  41. package/dist/components/charts/line-chart/components/stuff.d.ts.map +1 -1
  42. package/dist/components/charts/line-chart/components/stuff.js +6 -20
  43. package/dist/components/charts/line-chart/components/stuff.js.map +1 -1
  44. package/dist/components/charts/line-chart/components/stuff.module.less +0 -16
  45. package/dist/components/charts/line-chart/components/stuff.module.less.d.ts +0 -3
  46. package/dist/components/charts/line-chart/components/svg-bars.d.ts.map +1 -1
  47. package/dist/components/charts/line-chart/components/svg-bars.js +97 -15
  48. package/dist/components/charts/line-chart/components/svg-bars.js.map +1 -1
  49. package/dist/components/charts/line-chart/index.d.ts +1 -1
  50. package/dist/components/charts/line-chart/index.d.ts.map +1 -1
  51. package/dist/components/charts/line-chart/index.js +0 -1
  52. package/dist/components/charts/line-chart/index.js.map +1 -1
  53. package/dist/components/charts/line-chart/line-chart.stories.d.ts.map +1 -1
  54. package/dist/components/charts/line-chart/stores/line-chart.store.d.ts +7 -2
  55. package/dist/components/charts/line-chart/stores/line-chart.store.d.ts.map +1 -1
  56. package/dist/components/charts/line-chart/stores/line-chart.store.js +41 -3
  57. package/dist/components/charts/line-chart/stores/line-chart.store.js.map +1 -1
  58. package/dist/components/charts/line-chart/utils/interfaces.d.ts +4 -0
  59. package/dist/components/charts/line-chart/utils/interfaces.d.ts.map +1 -1
  60. package/dist/components/charts/line-chart/utils/interfaces.js.map +1 -1
  61. package/dist/components/charts/line-chart/utils/labels.js +1 -1
  62. package/dist/components/charts/line-chart/utils/labels.js.map +1 -1
  63. package/dist/components/charts/pie-chart/components/pie-chart.d.ts.map +1 -1
  64. package/dist/components/charts/pie-chart/components/pie-chart.js +24 -13
  65. package/dist/components/charts/pie-chart/components/pie-chart.js.map +1 -1
  66. package/dist/components/charts/pie-chart/components/pie-chart.module.less +15 -0
  67. package/dist/components/charts/pie-chart/components/pie-chart.module.less.d.ts +1 -0
  68. package/dist/components/charts/pie-chart/components/pie.d.ts.map +1 -1
  69. package/dist/components/charts/pie-chart/components/pie.js +105 -28
  70. package/dist/components/charts/pie-chart/components/pie.js.map +1 -1
  71. package/dist/components/charts/pie-chart/index.d.ts +1 -1
  72. package/dist/components/charts/pie-chart/index.d.ts.map +1 -1
  73. package/dist/components/charts/pie-chart/index.js +0 -1
  74. package/dist/components/charts/pie-chart/index.js.map +1 -1
  75. package/dist/components/charts/pie-chart/pie-chart.stories.d.ts.map +1 -1
  76. package/dist/components/charts/pie-chart/utils/const.js +1 -1
  77. package/dist/components/charts/pie-chart/utils/const.js.map +1 -1
  78. package/dist/components/image-cropper/image-cropper.d.ts.map +1 -1
  79. package/dist/components/image-cropper/image-cropper.js +1 -1
  80. package/dist/components/image-cropper/image-cropper.js.map +1 -1
  81. package/dist/components/stat/stat-card.d.ts.map +1 -1
  82. package/dist/components/stat/stat-card.js +28 -12
  83. package/dist/components/stat/stat-card.js.map +1 -1
  84. package/dist/utils/date/date-range-picker-state.d.ts +3 -2
  85. package/dist/utils/date/date-range-picker-state.d.ts.map +1 -1
  86. package/dist/utils/date/date-range-picker-state.js +0 -1
  87. package/dist/utils/date/date-range-picker-state.js.map +1 -1
  88. package/package.json +5 -3
  89. package/src/components/charts/common/color-tag.module.less +23 -0
  90. package/src/components/charts/common/color-tag.module.less.d.ts +6 -0
  91. package/src/components/charts/common/color-tag.tsx +92 -0
  92. package/src/components/charts/common/index.ts +1 -0
  93. package/src/components/charts/funnel-chart/components/funnel-chart.module.less +28 -10
  94. package/src/components/charts/funnel-chart/components/funnel-chart.module.less.d.ts +3 -1
  95. package/src/components/charts/funnel-chart/components/funnel-chart.tsx +107 -78
  96. package/src/components/charts/funnel-chart/components/funnel-svg.tsx +91 -23
  97. package/src/components/charts/funnel-chart/funnel-chart.stories.tsx +3 -1
  98. package/src/components/charts/funnel-chart/index.ts +1 -1
  99. package/src/components/charts/funnel-chart/utils/const.ts +1 -1
  100. package/src/components/charts/funnel-chart/utils/interface.ts +1 -0
  101. package/src/components/charts/funnel-chart/utils/svg-rounded-path.ts +86 -0
  102. package/src/components/charts/line-chart/components/hover-popover.module.less +10 -0
  103. package/src/components/charts/line-chart/components/hover-popover.module.less.d.ts +2 -0
  104. package/src/components/charts/line-chart/components/hover-popover.tsx +29 -9
  105. package/src/components/charts/line-chart/components/stuff.module.less +0 -16
  106. package/src/components/charts/line-chart/components/stuff.module.less.d.ts +0 -3
  107. package/src/components/charts/line-chart/components/stuff.tsx +4 -30
  108. package/src/components/charts/line-chart/components/svg-bars.tsx +106 -11
  109. package/src/components/charts/line-chart/index.ts +1 -1
  110. package/src/components/charts/line-chart/line-chart.stories.tsx +13 -8
  111. package/src/components/charts/line-chart/stores/line-chart.store.ts +41 -3
  112. package/src/components/charts/line-chart/utils/interfaces.ts +4 -0
  113. package/src/components/charts/line-chart/utils/labels.ts +1 -1
  114. package/src/components/charts/pie-chart/components/pie-chart.module.less +15 -0
  115. package/src/components/charts/pie-chart/components/pie-chart.module.less.d.ts +1 -0
  116. package/src/components/charts/pie-chart/components/pie-chart.tsx +23 -13
  117. package/src/components/charts/pie-chart/components/pie.tsx +106 -40
  118. package/src/components/charts/pie-chart/index.ts +1 -1
  119. package/src/components/charts/pie-chart/pie-chart.stories.tsx +3 -4
  120. package/src/components/charts/pie-chart/utils/const.ts +1 -1
  121. package/src/components/image-cropper/image-cropper.tsx +2 -1
  122. package/src/components/stat/stat-card.tsx +34 -16
  123. package/src/utils/date/date-range-picker-state.ts +3 -2
@@ -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>
@@ -1,2 +1,2 @@
1
1
  export { PieChart } from './components/pie-chart';
2
- export { PieChartSection, PieChartPopoverContentType } from './utils/interface';
2
+ export type { PieChartSection, PieChartPopoverContentType } from './utils/interface';
@@ -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;
@@ -1,7 +1,8 @@
1
1
  import { Component } from 'react';
2
2
  import { observable, action, makeObservable } from 'mobx';
3
3
  import { observer } from 'mobx-react';
4
- import ReactCrop, { Crop } from 'react-image-crop';
4
+ import type { Crop } from 'react-image-crop';
5
+ import ReactCrop from 'react-image-crop';
5
6
  import 'react-image-crop/dist/ReactCrop.css';
6
7
 
7
8
  interface ImageCropperProps {
@@ -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
 
@@ -1,5 +1,6 @@
1
- import { DateRangePickerOption, DateRangePickerOptions } from './date-range-picker-options';
2
- import { DateRange } from './date';
1
+ import type { DateRangePickerOption } from './date-range-picker-options';
2
+ import type { DateRange } from './date';
3
+ import { DateRangePickerOptions } from './date-range-picker-options';
3
4
  import { action, computed, makeObservable, observable } from 'mobx';
4
5
 
5
6
  interface DateRangePickerStateConfig {