@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.
- package/dist/components/charts/common/color-tag.d.ts +15 -0
- package/dist/components/charts/common/color-tag.d.ts.map +1 -0
- package/dist/components/charts/common/color-tag.js +79 -0
- package/dist/components/charts/common/color-tag.js.map +1 -0
- package/dist/components/charts/common/color-tag.module.less +23 -0
- package/dist/components/charts/common/color-tag.module.less.d.ts +6 -0
- package/dist/components/charts/common/index.d.ts +2 -0
- package/dist/components/charts/common/index.d.ts.map +1 -0
- package/dist/components/charts/common/index.js +3 -0
- package/dist/components/charts/common/index.js.map +1 -0
- package/dist/components/charts/funnel-chart/components/funnel-chart.d.ts.map +1 -1
- package/dist/components/charts/funnel-chart/components/funnel-chart.js +115 -70
- package/dist/components/charts/funnel-chart/components/funnel-chart.js.map +1 -1
- package/dist/components/charts/funnel-chart/components/funnel-chart.module.less +28 -10
- package/dist/components/charts/funnel-chart/components/funnel-chart.module.less.d.ts +3 -1
- package/dist/components/charts/funnel-chart/components/funnel-svg.d.ts +2 -0
- package/dist/components/charts/funnel-chart/components/funnel-svg.d.ts.map +1 -1
- package/dist/components/charts/funnel-chart/components/funnel-svg.js +72 -31
- package/dist/components/charts/funnel-chart/components/funnel-svg.js.map +1 -1
- package/dist/components/charts/funnel-chart/funnel-chart.stories.d.ts.map +1 -1
- package/dist/components/charts/funnel-chart/utils/const.d.ts +1 -1
- package/dist/components/charts/funnel-chart/utils/const.js +1 -1
- package/dist/components/charts/funnel-chart/utils/const.js.map +1 -1
- package/dist/components/charts/funnel-chart/utils/interface.d.ts +1 -0
- package/dist/components/charts/funnel-chart/utils/interface.d.ts.map +1 -1
- package/dist/components/charts/funnel-chart/utils/interface.js.map +1 -1
- package/dist/components/charts/funnel-chart/utils/svg-rounded-path.d.ts +2 -0
- package/dist/components/charts/funnel-chart/utils/svg-rounded-path.d.ts.map +1 -0
- package/dist/components/charts/funnel-chart/utils/svg-rounded-path.js +47 -0
- package/dist/components/charts/funnel-chart/utils/svg-rounded-path.js.map +1 -0
- package/dist/components/charts/line-chart/components/hover-popover.d.ts.map +1 -1
- package/dist/components/charts/line-chart/components/hover-popover.js +13 -7
- package/dist/components/charts/line-chart/components/hover-popover.js.map +1 -1
- package/dist/components/charts/line-chart/components/hover-popover.module.less +10 -0
- package/dist/components/charts/line-chart/components/hover-popover.module.less.d.ts +2 -0
- package/dist/components/charts/line-chart/components/stuff.d.ts +0 -8
- package/dist/components/charts/line-chart/components/stuff.d.ts.map +1 -1
- package/dist/components/charts/line-chart/components/stuff.js +6 -20
- package/dist/components/charts/line-chart/components/stuff.js.map +1 -1
- package/dist/components/charts/line-chart/components/stuff.module.less +0 -16
- package/dist/components/charts/line-chart/components/stuff.module.less.d.ts +0 -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 +97 -13
- package/dist/components/charts/line-chart/components/svg-bars.js.map +1 -1
- package/dist/components/charts/line-chart/line-chart.stories.d.ts.map +1 -1
- package/dist/components/charts/line-chart/stores/line-chart.store.d.ts +5 -0
- package/dist/components/charts/line-chart/stores/line-chart.store.d.ts.map +1 -1
- package/dist/components/charts/line-chart/stores/line-chart.store.js +41 -1
- package/dist/components/charts/line-chart/stores/line-chart.store.js.map +1 -1
- package/dist/components/charts/line-chart/utils/interfaces.d.ts +4 -0
- package/dist/components/charts/line-chart/utils/interfaces.d.ts.map +1 -1
- package/dist/components/charts/line-chart/utils/interfaces.js.map +1 -1
- package/dist/components/charts/line-chart/utils/labels.js +1 -1
- package/dist/components/charts/line-chart/utils/labels.js.map +1 -1
- package/dist/components/charts/pie-chart/components/pie-chart.d.ts.map +1 -1
- package/dist/components/charts/pie-chart/components/pie-chart.js +24 -13
- package/dist/components/charts/pie-chart/components/pie-chart.js.map +1 -1
- package/dist/components/charts/pie-chart/components/pie-chart.module.less +15 -0
- package/dist/components/charts/pie-chart/components/pie-chart.module.less.d.ts +1 -0
- package/dist/components/charts/pie-chart/components/pie.d.ts.map +1 -1
- package/dist/components/charts/pie-chart/components/pie.js +105 -28
- package/dist/components/charts/pie-chart/components/pie.js.map +1 -1
- package/dist/components/charts/pie-chart/pie-chart.stories.d.ts.map +1 -1
- package/dist/components/charts/pie-chart/utils/const.js +1 -1
- package/dist/components/charts/pie-chart/utils/const.js.map +1 -1
- package/dist/components/stat/stat-card.d.ts.map +1 -1
- package/dist/components/stat/stat-card.js +28 -12
- package/dist/components/stat/stat-card.js.map +1 -1
- package/package.json +5 -3
- package/src/components/charts/common/color-tag.module.less +23 -0
- package/src/components/charts/common/color-tag.module.less.d.ts +6 -0
- package/src/components/charts/common/color-tag.tsx +92 -0
- package/src/components/charts/common/index.ts +1 -0
- package/src/components/charts/funnel-chart/components/funnel-chart.module.less +28 -10
- package/src/components/charts/funnel-chart/components/funnel-chart.module.less.d.ts +3 -1
- package/src/components/charts/funnel-chart/components/funnel-chart.tsx +107 -78
- package/src/components/charts/funnel-chart/components/funnel-svg.tsx +91 -23
- package/src/components/charts/funnel-chart/funnel-chart.stories.tsx +3 -1
- package/src/components/charts/funnel-chart/utils/const.ts +1 -1
- package/src/components/charts/funnel-chart/utils/interface.ts +1 -0
- package/src/components/charts/funnel-chart/utils/svg-rounded-path.ts +86 -0
- package/src/components/charts/line-chart/components/hover-popover.module.less +10 -0
- package/src/components/charts/line-chart/components/hover-popover.module.less.d.ts +2 -0
- package/src/components/charts/line-chart/components/hover-popover.tsx +29 -9
- package/src/components/charts/line-chart/components/stuff.module.less +0 -16
- package/src/components/charts/line-chart/components/stuff.module.less.d.ts +0 -3
- package/src/components/charts/line-chart/components/stuff.tsx +4 -30
- package/src/components/charts/line-chart/components/svg-bars.tsx +106 -9
- package/src/components/charts/line-chart/line-chart.stories.tsx +13 -8
- package/src/components/charts/line-chart/stores/line-chart.store.ts +39 -1
- package/src/components/charts/line-chart/utils/interfaces.ts +4 -0
- package/src/components/charts/line-chart/utils/labels.ts +1 -1
- package/src/components/charts/pie-chart/components/pie-chart.module.less +15 -0
- package/src/components/charts/pie-chart/components/pie-chart.module.less.d.ts +1 -0
- package/src/components/charts/pie-chart/components/pie-chart.tsx +23 -13
- package/src/components/charts/pie-chart/components/pie.tsx +106 -40
- package/src/components/charts/pie-chart/pie-chart.stories.tsx +3 -4
- package/src/components/charts/pie-chart/utils/const.ts +1 -1
- package/src/components/stat/stat-card.tsx +34 -16
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useMemo, useState, Fragment } from 'react';
|
|
3
3
|
import { tokens } from '@servicetitan/tokens/core';
|
|
4
|
-
import { BodyText, Popover, Stack
|
|
4
|
+
import { BodyText, Popover, Stack } from '@servicetitan/design-system';
|
|
5
5
|
import { useClientRect } from '../../../../utils/use-client-rect';
|
|
6
|
+
import { ColorTag } from '../../common';
|
|
6
7
|
const chartPadding = 8;
|
|
7
8
|
const px = (value)=>`${value !== null && value !== void 0 ? value : 0}px`;
|
|
8
|
-
const
|
|
9
|
+
const GAP_PX = 4;
|
|
10
|
+
const PiePieceSvg = ({ piece: { id, color, points, text, path }, selected })=>points && path ? /*#__PURE__*/ _jsxs("g", {
|
|
9
11
|
id: id,
|
|
10
12
|
children: [
|
|
11
|
-
|
|
13
|
+
selected && /*#__PURE__*/ _jsx("path", {
|
|
12
14
|
d: path,
|
|
13
15
|
fill: tokens.colorWhite,
|
|
14
16
|
stroke: tokens.colorBlue200,
|
|
@@ -20,21 +22,39 @@ const PiePieceSvg = ({ piece: { id, color, opacity, points, text, path }, select
|
|
|
20
22
|
d: path,
|
|
21
23
|
fill: color
|
|
22
24
|
}),
|
|
23
|
-
/*#__PURE__*/ _jsx("
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
25
|
+
points[4] && /*#__PURE__*/ _jsx("g", {
|
|
26
|
+
transform: `translate(${points[4][0]}, ${points[4][1]})`,
|
|
27
|
+
pointerEvents: "none",
|
|
28
|
+
children: (()=>{
|
|
29
|
+
const fontSize = 3;
|
|
30
|
+
const height = 6;
|
|
31
|
+
const radius = height / 2;
|
|
32
|
+
const width = Math.max(8, text.length);
|
|
33
|
+
return /*#__PURE__*/ _jsxs(Fragment, {
|
|
34
|
+
children: [
|
|
35
|
+
/*#__PURE__*/ _jsx("rect", {
|
|
36
|
+
x: -width / 2,
|
|
37
|
+
y: -height / 2,
|
|
38
|
+
width: width,
|
|
39
|
+
height: height,
|
|
40
|
+
rx: radius,
|
|
41
|
+
ry: radius,
|
|
42
|
+
fill: "rgba(255,255,255,0.80)",
|
|
43
|
+
strokeWidth: 0.6
|
|
44
|
+
}),
|
|
45
|
+
/*#__PURE__*/ _jsx("text", {
|
|
46
|
+
x: "0",
|
|
47
|
+
y: "0",
|
|
48
|
+
fontSize: fontSize,
|
|
49
|
+
fontWeight: 600,
|
|
50
|
+
textAnchor: "middle",
|
|
51
|
+
dominantBaseline: "middle",
|
|
52
|
+
fill: tokens.colorBlack,
|
|
53
|
+
children: text
|
|
54
|
+
})
|
|
55
|
+
]
|
|
56
|
+
});
|
|
57
|
+
})()
|
|
38
58
|
})
|
|
39
59
|
]
|
|
40
60
|
}) : null;
|
|
@@ -55,22 +75,79 @@ const PiePieceHover = ({ piece, onMouse })=>{
|
|
|
55
75
|
onMouseLeave: onMouseLeave
|
|
56
76
|
});
|
|
57
77
|
};
|
|
58
|
-
const PieSvg = ({ pieces, selectedIndex, radiusRelative })
|
|
78
|
+
const PieSvg = ({ pieces, selectedIndex, radiusRelative })=>{
|
|
79
|
+
const piePiece = pieces.find((p)=>p.points);
|
|
80
|
+
const innerR = piePiece ? Math.hypot(piePiece.points[3][0], piePiece.points[3][1]) : 0;
|
|
81
|
+
const outerR = piePiece ? Math.hypot(piePiece.points[1][0], piePiece.points[1][1]) : 0;
|
|
82
|
+
const boundaries = pieces.filter((p)=>p.points).map((p)=>{
|
|
83
|
+
const [outerX, outerY] = p.points[1];
|
|
84
|
+
const len = Math.hypot(outerX, outerY) || 1;
|
|
85
|
+
return {
|
|
86
|
+
x: outerX / len,
|
|
87
|
+
y: outerY / len
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
return /*#__PURE__*/ _jsxs("svg", {
|
|
59
91
|
className: "position-absolute",
|
|
60
92
|
style: {
|
|
61
|
-
inset: px
|
|
93
|
+
inset: `${chartPadding}px`
|
|
62
94
|
},
|
|
63
|
-
viewBox: `-${radiusRelative} -${radiusRelative}
|
|
95
|
+
viewBox: `-${radiusRelative} -${radiusRelative} ${radiusRelative * 2} ${radiusRelative * 2}`,
|
|
64
96
|
children: [
|
|
65
|
-
pieces.map((p,
|
|
97
|
+
pieces.map((p, i)=>p.path ? /*#__PURE__*/ _jsx(PiePieceSvg, {
|
|
66
98
|
piece: p,
|
|
67
|
-
selected:
|
|
99
|
+
selected: i === selectedIndex
|
|
68
100
|
}, p.id) : null),
|
|
101
|
+
pieces.length > 1 && innerR > 0 && outerR > 0 && /*#__PURE__*/ _jsxs(Fragment, {
|
|
102
|
+
children: [
|
|
103
|
+
/*#__PURE__*/ _jsx("defs", {
|
|
104
|
+
children: /*#__PURE__*/ _jsxs("mask", {
|
|
105
|
+
id: "ring-mask",
|
|
106
|
+
children: [
|
|
107
|
+
/*#__PURE__*/ _jsx("rect", {
|
|
108
|
+
x: -outerR,
|
|
109
|
+
y: -outerR,
|
|
110
|
+
width: outerR * 2,
|
|
111
|
+
height: outerR * 2,
|
|
112
|
+
fill: "black"
|
|
113
|
+
}),
|
|
114
|
+
/*#__PURE__*/ _jsx("circle", {
|
|
115
|
+
cx: "0",
|
|
116
|
+
cy: "0",
|
|
117
|
+
r: outerR,
|
|
118
|
+
fill: "white"
|
|
119
|
+
}),
|
|
120
|
+
/*#__PURE__*/ _jsx("circle", {
|
|
121
|
+
cx: "0",
|
|
122
|
+
cy: "0",
|
|
123
|
+
r: innerR,
|
|
124
|
+
fill: "black"
|
|
125
|
+
})
|
|
126
|
+
]
|
|
127
|
+
})
|
|
128
|
+
}),
|
|
129
|
+
/*#__PURE__*/ _jsx("g", {
|
|
130
|
+
mask: "url(#ring-mask)",
|
|
131
|
+
pointerEvents: "none",
|
|
132
|
+
children: boundaries.map((boundary)=>/*#__PURE__*/ _jsx("line", {
|
|
133
|
+
x1: boundary.x * innerR,
|
|
134
|
+
y1: boundary.y * innerR,
|
|
135
|
+
x2: boundary.x * outerR,
|
|
136
|
+
y2: boundary.y * outerR,
|
|
137
|
+
stroke: "#fff",
|
|
138
|
+
strokeWidth: GAP_PX,
|
|
139
|
+
vectorEffect: "non-scaling-stroke",
|
|
140
|
+
strokeLinecap: "round"
|
|
141
|
+
}, `sep-${boundary.x}-${boundary.y}`))
|
|
142
|
+
})
|
|
143
|
+
]
|
|
144
|
+
}),
|
|
69
145
|
selectedIndex >= 0 && selectedIndex < pieces.length && /*#__PURE__*/ _jsx("use", {
|
|
70
|
-
xlinkHref: pieces[selectedIndex].id
|
|
146
|
+
xlinkHref: `#${pieces[selectedIndex].id}`
|
|
71
147
|
})
|
|
72
148
|
]
|
|
73
149
|
});
|
|
150
|
+
};
|
|
74
151
|
const PieSvgHover = ({ pieces, onMouse, radiusRelative })=>/*#__PURE__*/ _jsx("svg", {
|
|
75
152
|
className: "position-absolute z-global-nav",
|
|
76
153
|
style: {
|
|
@@ -98,8 +175,7 @@ export const Pie = ({ pieces, popoverContent: PopoverContent, content: PieConten
|
|
|
98
175
|
height,
|
|
99
176
|
internal: height ? height - chartPadding * 2 : 0,
|
|
100
177
|
styles: height ? {
|
|
101
|
-
width: px(Math.max(250, height))
|
|
102
|
-
overflow: 'hidden'
|
|
178
|
+
width: px(Math.max(250, height))
|
|
103
179
|
} : {}
|
|
104
180
|
};
|
|
105
181
|
}, [
|
|
@@ -120,7 +196,7 @@ export const Pie = ({ pieces, popoverContent: PopoverContent, content: PieConten
|
|
|
120
196
|
return /*#__PURE__*/ _jsx("div", {
|
|
121
197
|
ref: ref,
|
|
122
198
|
style: container.styles,
|
|
123
|
-
className: "position-relative",
|
|
199
|
+
className: "position-relative h-100",
|
|
124
200
|
children: pieces.every((p)=>!p.path) ? /*#__PURE__*/ _jsx(Stack, {
|
|
125
201
|
className: "h-100",
|
|
126
202
|
justifyContent: "center",
|
|
@@ -149,7 +225,8 @@ export const Pie = ({ pieces, popoverContent: PopoverContent, content: PieConten
|
|
|
149
225
|
!hideTitles && /*#__PURE__*/ _jsxs(Stack, {
|
|
150
226
|
alignItems: "center",
|
|
151
227
|
children: [
|
|
152
|
-
/*#__PURE__*/ _jsx(
|
|
228
|
+
/*#__PURE__*/ _jsx(ColorTag, {
|
|
229
|
+
label: "",
|
|
153
230
|
color: pieces[ind].color
|
|
154
231
|
}),
|
|
155
232
|
/*#__PURE__*/ _jsx(BodyText, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/components/charts/pie-chart/components/pie.tsx"],"sourcesContent":["import { useCallback, useMemo, useState, FC, Fragment } from 'react';\nimport { tokens } from '@servicetitan/tokens/core';\nimport { BodyText, Popover, Stack, StatusLight } from '@servicetitan/design-system';\n\nimport { useClientRect } from '../../../../utils/use-client-rect';\nimport { PieChartPopoverContentType, PiePiece, PopoverDirection } from '../utils/interface';\n\nconst chartPadding = 8;\nconst px = (value?: number) => `${value ?? 0}px`;\n\nconst PiePieceSvg: FC<{\n piece: PiePiece;\n selected?: boolean;\n}> = ({ piece: { id, color, opacity, points, text, path }, selected }) =>\n points && path ? (\n <g id={id}>\n {!!selected && (\n <path\n d={path}\n fill={tokens.colorWhite}\n stroke={tokens.colorBlue200}\n strokeOpacity=\"50%\"\n strokeWidth=\"3\"\n paintOrder=\"stroke\"\n />\n )}\n <path d={path} fill={color} />\n\n <svg\n x={points[4][0] - 10}\n y={points[4][1] - (points[4][1] > 0 ? 3 : 1)}\n width={20}\n height={6}\n >\n <text\n x=\"50%\"\n y=\"50%\"\n fontSize={4}\n fontWeight={600}\n fill={opacity > 0.3 ? tokens.colorWhite : tokens.colorBlack}\n dominantBaseline=\"middle\"\n textAnchor=\"middle\"\n >\n {text}\n </text>\n </svg>\n </g>\n ) : null;\n\nconst PiePieceHover: FC<{\n piece: PiePiece;\n onMouse(id: string, isEnter: boolean): void;\n}> = ({ piece, onMouse }) => {\n const onMouseEnter = useCallback(() => onMouse(piece.id, true), [onMouse, piece.id]);\n const onMouseLeave = useCallback(() => onMouse(piece.id, false), [onMouse, piece.id]);\n\n return (\n <path\n d={piece.path}\n fill=\"white\"\n opacity=\"0\"\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n />\n );\n};\n\nconst PieSvg: FC<{\n pieces: PiePiece[];\n selectedIndex: number;\n radiusRelative: number;\n}> = ({ pieces, selectedIndex, radiusRelative }) => (\n <svg\n className=\"position-absolute\"\n style={{ inset: px(chartPadding) }}\n viewBox={\n `-${radiusRelative} -${radiusRelative} ` + `${radiusRelative * 2} ${radiusRelative * 2}`\n }\n >\n {pieces.map((p, index) =>\n p.path ? <PiePieceSvg piece={p} key={p.id} selected={index === selectedIndex} /> : null\n )}\n\n {selectedIndex >= 0 && selectedIndex < pieces.length && (\n <use xlinkHref={pieces[selectedIndex].id} />\n )}\n </svg>\n);\n\nconst PieSvgHover: FC<{\n pieces: PiePiece[];\n radiusRelative: number;\n onMouse(id: string, isEnter: boolean): void;\n}> = ({ pieces, onMouse, radiusRelative }) => (\n <svg\n className=\"position-absolute z-global-nav\"\n style={{ inset: px(chartPadding) }}\n viewBox={\n `-${radiusRelative} -${radiusRelative} ` + `${radiusRelative * 2} ${radiusRelative * 2}`\n }\n >\n {pieces.map(p =>\n p.path ? <PiePieceHover piece={p} key={p.id} onMouse={onMouse} /> : null\n )}\n </svg>\n);\n\nexport const Pie: FC<{\n title: string;\n pieces: PiePiece[];\n radiusRelative: number;\n content?: FC;\n popoverContent?: PieChartPopoverContentType;\n hideTitles?: boolean;\n popoverDirection?: PopoverDirection;\n}> = ({\n pieces,\n popoverContent: PopoverContent,\n content: PieContent,\n radiusRelative,\n hideTitles,\n popoverDirection,\n}) => {\n const [selectedIndex, setSelectedIndex] = useState(-1);\n const [rect, ref] = useClientRect();\n\n const onMouse = useCallback(\n (id: string, isEnter: boolean) => {\n setSelectedIndex(isEnter ? pieces.findIndex(p => p.id === id) : -1);\n },\n [pieces, setSelectedIndex]\n );\n\n const container = useMemo(() => {\n const height = rect?.height ?? 0;\n\n return {\n height,\n internal: height ? height - chartPadding * 2 : 0,\n styles: height\n ? {\n width: px(Math.max(250, height)),\n overflow: 'hidden',\n }\n : {},\n };\n }, [rect]);\n\n const triggersStyles = useMemo(\n () =>\n container.height\n ? pieces.map(p =>\n p.points\n ? {\n key: p.key,\n top: px(\n (container.height * (radiusRelative + p.points[4][1])) /\n (radiusRelative * 2)\n ),\n left: px(\n (container.height * (radiusRelative + p.points[4][0])) /\n (radiusRelative * 2) +\n 20\n ),\n }\n : { top: '', left: '' }\n )\n : [],\n [pieces, container, radiusRelative]\n );\n\n return (\n <div ref={ref} style={container.styles} className=\"position-relative\">\n {pieces.every(p => !p.path) ? (\n <Stack className=\"h-100\" justifyContent=\"center\" alignItems=\"center\">\n No Data\n </Stack>\n ) : (\n <Fragment>\n {triggersStyles\n .filter(ts => !!ts.left && !!ts.top)\n .map((ts, ind) => (\n <div key={ts.left + ts.top} style={ts} className=\"position-absolute\">\n {(!!PopoverContent || !hideTitles) && (\n <Popover\n portal\n trigger={<span> </span>}\n open={selectedIndex === ind}\n direction={popoverDirection}\n padding=\"s\"\n width=\"auto\"\n >\n {selectedIndex === ind && (\n <Stack\n direction=\"column\"\n data-cy={`customer-lead-rate-section-${ts.key}-popover`}\n >\n {!hideTitles && (\n <Stack alignItems=\"center\">\n <StatusLight color={pieces[ind].color} />\n <BodyText size=\"small\" bold>\n {pieces[ind].title}\n </BodyText>\n </Stack>\n )}\n {!!PopoverContent && (\n <Stack.Item className=\"m-l-1\">\n <PopoverContent\n index={ind}\n data={pieces[ind]?.data}\n text={pieces[ind]?.text}\n value={pieces[ind]?.value}\n />\n </Stack.Item>\n )}\n </Stack>\n )}\n </Popover>\n )}\n </div>\n ))}\n {!!PieContent && <PieContent />}\n <PieSvg\n pieces={pieces}\n selectedIndex={selectedIndex}\n radiusRelative={radiusRelative}\n />\n <PieSvgHover\n pieces={pieces}\n onMouse={onMouse}\n radiusRelative={radiusRelative}\n />\n </Fragment>\n )}\n </div>\n );\n};\n"],"names":["useCallback","useMemo","useState","Fragment","tokens","BodyText","Popover","Stack","StatusLight","useClientRect","chartPadding","px","value","PiePieceSvg","piece","id","color","opacity","points","text","path","selected","g","d","fill","colorWhite","stroke","colorBlue200","strokeOpacity","strokeWidth","paintOrder","svg","x","y","width","height","fontSize","fontWeight","colorBlack","dominantBaseline","textAnchor","PiePieceHover","onMouse","onMouseEnter","onMouseLeave","PieSvg","pieces","selectedIndex","radiusRelative","className","style","inset","viewBox","map","p","index","length","use","xlinkHref","PieSvgHover","Pie","popoverContent","PopoverContent","content","PieContent","hideTitles","popoverDirection","setSelectedIndex","rect","ref","isEnter","findIndex","container","internal","styles","Math","max","overflow","triggersStyles","key","top","left","div","every","justifyContent","alignItems","filter","ts","ind","portal","trigger","span","open","direction","padding","data-cy","size","bold","title","Item","data"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../src/components/charts/pie-chart/components/pie.tsx"],"sourcesContent":["import { useCallback, useMemo, useState, FC, Fragment } from 'react';\nimport { tokens } from '@servicetitan/tokens/core';\nimport { BodyText, Popover, Stack } from '@servicetitan/design-system';\n\nimport { useClientRect } from '../../../../utils/use-client-rect';\nimport { PieChartPopoverContentType, PiePiece, PopoverDirection } from '../utils/interface';\nimport { ColorTag } from '../../common';\n\nconst chartPadding = 8;\nconst px = (value?: number) => `${value ?? 0}px`;\nconst GAP_PX = 4;\n\nconst PiePieceSvg: FC<{\n piece: PiePiece;\n selected?: boolean;\n}> = ({ piece: { id, color, points, text, path }, selected }) =>\n points && path ? (\n <g id={id}>\n {selected && (\n <path\n d={path}\n fill={tokens.colorWhite}\n stroke={tokens.colorBlue200}\n strokeOpacity=\"50%\"\n strokeWidth=\"3\"\n paintOrder=\"stroke\"\n />\n )}\n <path d={path} fill={color} />\n {points[4] && (\n <g transform={`translate(${points[4][0]}, ${points[4][1]})`} pointerEvents=\"none\">\n {(() => {\n const fontSize = 3;\n const height = 6;\n const radius = height / 2;\n\n const width = Math.max(8, text.length);\n\n return (\n <Fragment>\n <rect\n x={-width / 2}\n y={-height / 2}\n width={width}\n height={height}\n rx={radius}\n ry={radius}\n fill=\"rgba(255,255,255,0.80)\"\n strokeWidth={0.6}\n />\n <text\n x=\"0\"\n y=\"0\"\n fontSize={fontSize}\n fontWeight={600}\n textAnchor=\"middle\"\n dominantBaseline=\"middle\"\n fill={tokens.colorBlack}\n >\n {text}\n </text>\n </Fragment>\n );\n })()}\n </g>\n )}\n </g>\n ) : null;\n\nconst PiePieceHover: FC<{\n piece: PiePiece;\n onMouse(id: string, isEnter: boolean): void;\n}> = ({ piece, onMouse }) => {\n const onMouseEnter = useCallback(() => onMouse(piece.id, true), [onMouse, piece.id]);\n const onMouseLeave = useCallback(() => onMouse(piece.id, false), [onMouse, piece.id]);\n\n return (\n <path\n d={piece.path}\n fill=\"white\"\n opacity=\"0\"\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n />\n );\n};\n\nconst PieSvg: FC<{\n pieces: PiePiece[];\n selectedIndex: number;\n radiusRelative: number;\n}> = ({ pieces, selectedIndex, radiusRelative }) => {\n const piePiece = pieces.find(p => p.points);\n const innerR = piePiece ? Math.hypot(piePiece.points![3][0], piePiece.points![3][1]) : 0;\n const outerR = piePiece ? Math.hypot(piePiece.points![1][0], piePiece.points![1][1]) : 0;\n\n const boundaries = pieces\n .filter(p => p.points)\n .map(p => {\n const [outerX, outerY] = p.points![1];\n const len = Math.hypot(outerX, outerY) || 1;\n return { x: outerX / len, y: outerY / len };\n });\n\n return (\n <svg\n className=\"position-absolute\"\n style={{ inset: `${chartPadding}px` }}\n viewBox={`-${radiusRelative} -${radiusRelative} ${radiusRelative * 2} ${radiusRelative * 2}`}\n >\n {pieces.map((p, i) =>\n p.path ? <PiePieceSvg piece={p} key={p.id} selected={i === selectedIndex} /> : null\n )}\n\n {pieces.length > 1 && innerR > 0 && outerR > 0 && (\n <Fragment>\n <defs>\n <mask id=\"ring-mask\">\n <rect\n x={-outerR}\n y={-outerR}\n width={outerR * 2}\n height={outerR * 2}\n fill=\"black\"\n />\n <circle cx=\"0\" cy=\"0\" r={outerR} fill=\"white\" />\n <circle cx=\"0\" cy=\"0\" r={innerR} fill=\"black\" />\n </mask>\n </defs>\n <g mask=\"url(#ring-mask)\" pointerEvents=\"none\">\n {boundaries.map(boundary => (\n <line\n key={`sep-${boundary.x}-${boundary.y}`}\n x1={boundary.x * innerR}\n y1={boundary.y * innerR}\n x2={boundary.x * outerR}\n y2={boundary.y * outerR}\n stroke=\"#fff\"\n strokeWidth={GAP_PX}\n vectorEffect=\"non-scaling-stroke\"\n strokeLinecap=\"round\"\n />\n ))}\n </g>\n </Fragment>\n )}\n {selectedIndex >= 0 && selectedIndex < pieces.length && (\n <use xlinkHref={`#${pieces[selectedIndex].id}`} />\n )}\n </svg>\n );\n};\n\nconst PieSvgHover: FC<{\n pieces: PiePiece[];\n radiusRelative: number;\n onMouse(id: string, isEnter: boolean): void;\n}> = ({ pieces, onMouse, radiusRelative }) => (\n <svg\n className=\"position-absolute z-global-nav\"\n style={{ inset: px(chartPadding) }}\n viewBox={\n `-${radiusRelative} -${radiusRelative} ` + `${radiusRelative * 2} ${radiusRelative * 2}`\n }\n >\n {pieces.map(p =>\n p.path ? <PiePieceHover piece={p} key={p.id} onMouse={onMouse} /> : null\n )}\n </svg>\n);\n\nexport const Pie: FC<{\n title: string;\n pieces: PiePiece[];\n radiusRelative: number;\n content?: FC;\n popoverContent?: PieChartPopoverContentType;\n hideTitles?: boolean;\n popoverDirection?: PopoverDirection;\n}> = ({\n pieces,\n popoverContent: PopoverContent,\n content: PieContent,\n radiusRelative,\n hideTitles,\n popoverDirection,\n}) => {\n const [selectedIndex, setSelectedIndex] = useState(-1);\n const [rect, ref] = useClientRect();\n\n const onMouse = useCallback(\n (id: string, isEnter: boolean) => {\n setSelectedIndex(isEnter ? pieces.findIndex(p => p.id === id) : -1);\n },\n [pieces, setSelectedIndex]\n );\n\n const container = useMemo(() => {\n const height = rect?.height ?? 0;\n\n return {\n height,\n internal: height ? height - chartPadding * 2 : 0,\n styles: height\n ? {\n width: px(Math.max(250, height)),\n }\n : {},\n };\n }, [rect]);\n\n const triggersStyles = useMemo(\n () =>\n container.height\n ? pieces.map(p =>\n p.points\n ? {\n key: p.key,\n top: px(\n (container.height * (radiusRelative + p.points[4][1])) /\n (radiusRelative * 2)\n ),\n left: px(\n (container.height * (radiusRelative + p.points[4][0])) /\n (radiusRelative * 2) +\n 20\n ),\n }\n : { top: '', left: '' }\n )\n : [],\n [pieces, container, radiusRelative]\n );\n\n return (\n <div ref={ref} style={container.styles} className=\"position-relative h-100\">\n {pieces.every(p => !p.path) ? (\n <Stack className=\"h-100\" justifyContent=\"center\" alignItems=\"center\">\n No Data\n </Stack>\n ) : (\n <Fragment>\n {triggersStyles\n .filter(ts => !!ts.left && !!ts.top)\n .map((ts, ind) => (\n <div key={ts.left + ts.top} style={ts} className=\"position-absolute\">\n {(!!PopoverContent || !hideTitles) && (\n <Popover\n portal\n trigger={<span> </span>}\n open={selectedIndex === ind}\n direction={popoverDirection}\n padding=\"s\"\n width=\"auto\"\n >\n {selectedIndex === ind && (\n <Stack\n direction=\"column\"\n data-cy={`customer-lead-rate-section-${ts.key}-popover`}\n >\n {!hideTitles && (\n <Stack alignItems=\"center\">\n <ColorTag\n label=\"\"\n color={pieces[ind].color}\n />\n <BodyText size=\"small\" bold>\n {pieces[ind].title}\n </BodyText>\n </Stack>\n )}\n {!!PopoverContent && (\n <Stack.Item className=\"m-l-1\">\n <PopoverContent\n index={ind}\n data={pieces[ind]?.data}\n text={pieces[ind]?.text}\n value={pieces[ind]?.value}\n />\n </Stack.Item>\n )}\n </Stack>\n )}\n </Popover>\n )}\n </div>\n ))}\n {!!PieContent && <PieContent />}\n <PieSvg\n pieces={pieces}\n selectedIndex={selectedIndex}\n radiusRelative={radiusRelative}\n />\n <PieSvgHover\n pieces={pieces}\n onMouse={onMouse}\n radiusRelative={radiusRelative}\n />\n </Fragment>\n )}\n </div>\n );\n};\n"],"names":["useCallback","useMemo","useState","Fragment","tokens","BodyText","Popover","Stack","useClientRect","ColorTag","chartPadding","px","value","GAP_PX","PiePieceSvg","piece","id","color","points","text","path","selected","g","d","fill","colorWhite","stroke","colorBlue200","strokeOpacity","strokeWidth","paintOrder","transform","pointerEvents","fontSize","height","radius","width","Math","max","length","rect","x","y","rx","ry","fontWeight","textAnchor","dominantBaseline","colorBlack","PiePieceHover","onMouse","onMouseEnter","onMouseLeave","opacity","PieSvg","pieces","selectedIndex","radiusRelative","piePiece","find","p","innerR","hypot","outerR","boundaries","filter","map","outerX","outerY","len","svg","className","style","inset","viewBox","i","defs","mask","circle","cx","cy","r","boundary","line","x1","y1","x2","y2","vectorEffect","strokeLinecap","use","xlinkHref","PieSvgHover","Pie","popoverContent","PopoverContent","content","PieContent","hideTitles","popoverDirection","setSelectedIndex","ref","isEnter","findIndex","container","internal","styles","triggersStyles","key","top","left","div","every","justifyContent","alignItems","ts","ind","portal","trigger","span","open","direction","padding","data-cy","label","size","bold","title","Item","index","data"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pie-chart.stories.d.ts","sourceRoot":"","sources":["../../../../src/components/charts/pie-chart/pie-chart.stories.tsx"],"names":[],"mappings":";;;;;AAGA,wBAIE;AAEF,eAAO,MAAM,kBAAkB,+CAa9B,CAAC;AAEF,eAAO,MAAM,mBAAmB,+
|
|
1
|
+
{"version":3,"file":"pie-chart.stories.d.ts","sourceRoot":"","sources":["../../../../src/components/charts/pie-chart/pie-chart.stories.tsx"],"names":[],"mappings":";;;;;AAGA,wBAIE;AAEF,eAAO,MAAM,kBAAkB,+CAa9B,CAAC;AAEF,eAAO,MAAM,mBAAmB,+CAgB/B,CAAC;AAEF,eAAO,MAAM,oBAAoB,+CAMhC,CAAC;AAEF,eAAO,MAAM,cAAc,+CAAkE,CAAC"}
|
|
@@ -2,7 +2,7 @@ import { formatNumber } from 'accounting';
|
|
|
2
2
|
export const radiusRelativeDefault = 50;
|
|
3
3
|
const radiusInt = 20;
|
|
4
4
|
const getRadiusExt = (radiusRelative)=>radiusRelative - 5; // need to have some space to stroke selected piece
|
|
5
|
-
const getRadiusMid = (radiusRelative)=>
|
|
5
|
+
const getRadiusMid = (radiusRelative)=>2.75 * radiusRelative / 4;
|
|
6
6
|
const angleInitial = -0.5;
|
|
7
7
|
const lowestOpacity = 0.1;
|
|
8
8
|
const formatValue = (val)=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/components/charts/pie-chart/utils/const.ts"],"sourcesContent":["import { PiecePoints, PieChartSection, PiePiece } from './interface';\nimport { formatNumber } from 'accounting';\n\nexport const radiusRelativeDefault = 50;\nconst radiusInt = 20;\nconst getRadiusExt = (radiusRelative: number) => radiusRelative - 5; // need to have some space to stroke selected piece\nconst getRadiusMid = (radiusRelative: number) => (
|
|
1
|
+
{"version":3,"sources":["../../../../../src/components/charts/pie-chart/utils/const.ts"],"sourcesContent":["import { PiecePoints, PieChartSection, PiePiece } from './interface';\nimport { formatNumber } from 'accounting';\n\nexport const radiusRelativeDefault = 50;\nconst radiusInt = 20;\nconst getRadiusExt = (radiusRelative: number) => radiusRelative - 5; // need to have some space to stroke selected piece\nconst getRadiusMid = (radiusRelative: number) => (2.75 * radiusRelative) / 4;\n\nconst angleInitial = -0.5;\nconst lowestOpacity = 0.1;\n\nconst formatValue = (val: number): string => {\n if (!val) {\n return '0%';\n }\n\n const valueMain = val ? Math.abs(Math.round(val)) : 0;\n\n if (valueMain > 0) {\n return formatNumber(valueMain, 0) + '%';\n }\n\n const valueDecimal = Math.max(Math.floor(val * 10) - valueMain * 10, 1);\n\n return `0.${valueDecimal}%`;\n};\n\nconst convertPointsToPath = (points: PiecePoints, wideAngle: boolean, radiusExt: number): string =>\n `M ${points[3][0]},${points[3][1]} ` +\n `L ${points[0][0]},${points[0][1]} ` +\n `A ${radiusExt},${radiusExt} 0 ${wideAngle ? 1 : 0} 1 ${points[1][0]},${points[1][1]} ` +\n `L ${points[2][0]},${points[2][1]} ` +\n `A ${radiusInt},${radiusInt} 0 ${wideAngle ? 1 : 0} 0 ${points[3][0]},${points[3][1]} ` +\n `L ${points[0][0]},${points[0][1]} `;\n\nexport const convertSessionsToPieces = <T>(\n sections: PieChartSection<T>[],\n radiusRelative: number\n): PiePiece<T>[] => {\n const total = sections.reduce((sum, curr) => sum + curr.value, 0);\n const opacityStep = (1 - lowestOpacity) / (Math.max(sections.length, 2) - 1);\n let angleSum = 0;\n const radiusExt = getRadiusExt(radiusRelative);\n const radiusMid = getRadiusMid(radiusRelative);\n\n const pieces = sections\n .slice()\n .sort((a, b) => b.value - a.value)\n .map((s, index) => {\n const percent = total ? s.value / total : 0;\n const angle = 2 * Math.PI * percent;\n const angleStart = angleInitial + angleSum;\n const angleMid = angleStart + angle / 2;\n const angleEnd = angleStart + angle;\n const opacity = 1 - opacityStep * index;\n\n const points: PiecePoints | undefined = s.value\n ? [\n [radiusExt * Math.sin(angleStart), -1 * radiusExt * Math.cos(angleStart)],\n [radiusExt * Math.sin(angleEnd), -1 * radiusExt * Math.cos(angleEnd)],\n [radiusInt * Math.sin(angleEnd), -1 * radiusInt * Math.cos(angleEnd)],\n [radiusInt * Math.sin(angleStart), -1 * radiusInt * Math.cos(angleStart)],\n [radiusMid * Math.sin(angleMid), -1 * radiusMid * Math.cos(angleMid)],\n ]\n : undefined;\n\n angleSum += angle;\n\n return {\n id: `pie${index}-${Math.round(Math.random() * 10000)}`,\n key: s.key,\n title: s.title,\n text: formatValue(percent * 100),\n data: s.data,\n color: s.color ?? `rgba(0,76,195,${opacity.toFixed(2)})`,\n opacity,\n value: s.value,\n points,\n path: points\n ? convertPointsToPath(points, angleEnd - angleStart >= Math.PI, radiusExt)\n : undefined,\n };\n });\n\n if (sections.filter(s => !!s.value).length === 1) {\n const piece = pieces.find(p => !!p.points);\n\n if (piece) {\n piece.points = [\n [-radiusExt, radiusExt],\n [radiusExt, radiusExt],\n [radiusInt, -radiusInt],\n [-radiusInt, -radiusInt],\n [0, 0],\n ];\n\n piece.path =\n `M ${-radiusExt},${0} ` +\n `A ${radiusExt},${radiusExt} 0 1 1 ${radiusExt},${0} ` +\n `A ${radiusExt},${radiusExt} 0 1 1 ${-radiusExt},${0} `;\n }\n }\n\n return pieces;\n};\n"],"names":["formatNumber","radiusRelativeDefault","radiusInt","getRadiusExt","radiusRelative","getRadiusMid","angleInitial","lowestOpacity","formatValue","val","valueMain","Math","abs","round","valueDecimal","max","floor","convertPointsToPath","points","wideAngle","radiusExt","convertSessionsToPieces","sections","total","reduce","sum","curr","value","opacityStep","length","angleSum","radiusMid","pieces","slice","sort","a","b","map","s","index","percent","angle","PI","angleStart","angleMid","angleEnd","opacity","sin","cos","undefined","id","random","key","title","text","data","color","toFixed","path","filter","piece","find","p"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stat-card.d.ts","sourceRoot":"","sources":["../../../src/components/stat/stat-card.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,SAAS,EAAY,MAAM,OAAO,CAAC;AAEhD,OAAO,EAEH,mBAAmB,EAKtB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAe,eAAe,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"stat-card.d.ts","sourceRoot":"","sources":["../../../src/components/stat/stat-card.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,SAAS,EAAY,MAAM,OAAO,CAAC;AAEhD,OAAO,EAEH,mBAAmB,EAKtB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAe,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAmCtE,UAAU,aAAa;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACnC,MAAM,EAAE,eAAe,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,eAAO,MAAM,QAAQ,EAAE,EAAE,CAAC,aAAa,CAgEtC,CAAC;AAEF,MAAM,WAAW,aAAa;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,eAAO,MAAM,QAAQ,EAAE,EAAE,CAAC,aAAa,CAyEtC,CAAC"}
|
|
@@ -4,6 +4,9 @@ import classNames from 'classnames';
|
|
|
4
4
|
import { BodyText, Eyebrow, Popover, Stack, Tooltip } from '@servicetitan/design-system';
|
|
5
5
|
import * as Styles from './stat-card.module.less';
|
|
6
6
|
import { formatValue } from '../../utils/formatters';
|
|
7
|
+
import { Icon } from '@servicetitan/anvil2';
|
|
8
|
+
import TrendingUpSVG from '@servicetitan/anvil2/assets/icons/material/round/trending_up.svg';
|
|
9
|
+
import TrendingDownSVG from '@servicetitan/anvil2/assets/icons/material/round/trending_down.svg';
|
|
7
10
|
const calculateDiff = (value, prev, percents)=>{
|
|
8
11
|
const diff = (value - prev) * (percents ? 100 : 1);
|
|
9
12
|
const absDiff = Math.abs(diff);
|
|
@@ -31,7 +34,11 @@ const formatDifferencePercentage = (value, isPlus)=>{
|
|
|
31
34
|
export const StatDiff = ({ value, prev, size, format, inverted, neutral, className, diffPercentOnly = false })=>{
|
|
32
35
|
const percents = format === 'percent';
|
|
33
36
|
const [absDiff, diffPercent, isIncrease] = calculateDiff(value !== null && value !== void 0 ? value : 0, prev !== null && prev !== void 0 ? prev : 0, percents);
|
|
34
|
-
const diff = absDiff === 0 ? '' :
|
|
37
|
+
const diff = absDiff === 0 ? '' : /*#__PURE__*/ _jsx(Icon, {
|
|
38
|
+
svg: isIncrease ? TrendingUpSVG : TrendingDownSVG,
|
|
39
|
+
color: isIncrease ? 'green' : 'red',
|
|
40
|
+
className: "m-r-half m-t-half"
|
|
41
|
+
});
|
|
35
42
|
let text = '';
|
|
36
43
|
if (percents) {
|
|
37
44
|
text += formatDifferencePercentage(absDiff, isIncrease);
|
|
@@ -46,19 +53,28 @@ export const StatDiff = ({ value, prev, size, format, inverted, neutral, classNa
|
|
|
46
53
|
}
|
|
47
54
|
}
|
|
48
55
|
}
|
|
49
|
-
return /*#__PURE__*/ _jsxs(
|
|
50
|
-
className: classNames(Styles.statDiff,
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
'c-neutral-200': !!neutral
|
|
54
|
-
}, className),
|
|
55
|
-
size: size !== null && size !== void 0 ? size : 'small',
|
|
56
|
-
"data-cy": "stat-diff-value",
|
|
56
|
+
return /*#__PURE__*/ _jsxs(Stack, {
|
|
57
|
+
className: classNames(Styles.statDiff, className),
|
|
58
|
+
justifyContent: "center",
|
|
59
|
+
alignItems: "center",
|
|
57
60
|
children: [
|
|
58
|
-
/*#__PURE__*/ _jsx(
|
|
59
|
-
children:
|
|
61
|
+
/*#__PURE__*/ _jsx(Stack.Item, {
|
|
62
|
+
children: /*#__PURE__*/ _jsx("span", {
|
|
63
|
+
children: diff
|
|
64
|
+
})
|
|
60
65
|
}),
|
|
61
|
-
|
|
66
|
+
/*#__PURE__*/ _jsx(Stack.Item, {
|
|
67
|
+
children: /*#__PURE__*/ _jsx(BodyText, {
|
|
68
|
+
size: size !== null && size !== void 0 ? size : 'small',
|
|
69
|
+
"data-cy": "stat-diff-value",
|
|
70
|
+
className: classNames({
|
|
71
|
+
'c-red-500': !neutral && (inverted ? isIncrease : !isIncrease),
|
|
72
|
+
'c-green-500': !neutral && (inverted ? !isIncrease : isIncrease),
|
|
73
|
+
'c-neutral-200': !!neutral
|
|
74
|
+
}),
|
|
75
|
+
children: value === undefined ? '\u00A0' : text
|
|
76
|
+
})
|
|
77
|
+
})
|
|
62
78
|
]
|
|
63
79
|
});
|
|
64
80
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/stat/stat-card.tsx"],"sourcesContent":["import { FC, ReactNode, useState } from 'react';\nimport classNames from 'classnames';\nimport {\n BodyText,\n BodyTextPropsStrict,\n Eyebrow,\n Popover,\n Stack,\n Tooltip,\n} from '@servicetitan/design-system';\nimport * as Styles from './stat-card.module.less';\nimport { formatValue, NumberFormatter } from '../../utils/formatters';\n\nconst calculateDiff = (\n value: number,\n prev: number,\n percents?: boolean\n): [number, number, boolean] => {\n const diff = (value - prev) * (percents ? 100 : 1);\n const absDiff = Math.abs(diff);\n let diffPercent = 0;\n\n if (percents) {\n diffPercent = diff;\n } else if (absDiff) {\n diffPercent = prev ? (100 * absDiff) / prev : 100;\n }\n\n return [absDiff, diffPercent, diff >= 0];\n};\n\nconst formatDifference = (value: number, isPlus: boolean, format: NumberFormatter): string => {\n return (isPlus ? '+' : '-') + formatValue(value, format);\n};\n\nconst formatDifferencePercentage = (value: number, isPlus: boolean): string => {\n if (!value) {\n return '';\n }\n\n return (isPlus ? '+' : '-') + formatValue(value, 'percent-100');\n};\n\ninterface StatDiffProps {\n value?: number;\n prev?: number;\n size?: BodyTextPropsStrict['size'];\n format: NumberFormatter;\n inverted?: boolean;\n neutral?: boolean;\n className?: string;\n diffPercentOnly?: boolean;\n}\n\nexport const StatDiff: FC<StatDiffProps> = ({\n value,\n prev,\n size,\n format,\n inverted,\n neutral,\n className,\n diffPercentOnly = false,\n}) => {\n const percents = format === 'percent';\n const [absDiff, diffPercent, isIncrease] = calculateDiff(value ?? 0, prev ?? 0, percents);\n const diff
|
|
1
|
+
{"version":3,"sources":["../../../src/components/stat/stat-card.tsx"],"sourcesContent":["import { FC, ReactNode, useState } from 'react';\nimport classNames from 'classnames';\nimport {\n BodyText,\n BodyTextPropsStrict,\n Eyebrow,\n Popover,\n Stack,\n Tooltip,\n} from '@servicetitan/design-system';\nimport * as Styles from './stat-card.module.less';\nimport { formatValue, NumberFormatter } from '../../utils/formatters';\nimport { Icon } from '@servicetitan/anvil2';\nimport TrendingUpSVG from '@servicetitan/anvil2/assets/icons/material/round/trending_up.svg';\nimport TrendingDownSVG from '@servicetitan/anvil2/assets/icons/material/round/trending_down.svg';\n\nconst calculateDiff = (\n value: number,\n prev: number,\n percents?: boolean\n): [number, number, boolean] => {\n const diff = (value - prev) * (percents ? 100 : 1);\n const absDiff = Math.abs(diff);\n let diffPercent = 0;\n\n if (percents) {\n diffPercent = diff;\n } else if (absDiff) {\n diffPercent = prev ? (100 * absDiff) / prev : 100;\n }\n\n return [absDiff, diffPercent, diff >= 0];\n};\n\nconst formatDifference = (value: number, isPlus: boolean, format: NumberFormatter): string => {\n return (isPlus ? '+' : '-') + formatValue(value, format);\n};\n\nconst formatDifferencePercentage = (value: number, isPlus: boolean): string => {\n if (!value) {\n return '';\n }\n\n return (isPlus ? '+' : '-') + formatValue(value, 'percent-100');\n};\n\ninterface StatDiffProps {\n value?: number;\n prev?: number;\n size?: BodyTextPropsStrict['size'];\n format: NumberFormatter;\n inverted?: boolean;\n neutral?: boolean;\n className?: string;\n diffPercentOnly?: boolean;\n}\n\nexport const StatDiff: FC<StatDiffProps> = ({\n value,\n prev,\n size,\n format,\n inverted,\n neutral,\n className,\n diffPercentOnly = false,\n}) => {\n const percents = format === 'percent';\n const [absDiff, diffPercent, isIncrease] = calculateDiff(value ?? 0, prev ?? 0, percents);\n const diff =\n absDiff === 0 ? (\n ''\n ) : (\n <Icon\n svg={isIncrease ? TrendingUpSVG : TrendingDownSVG}\n color={isIncrease ? 'green' : 'red'}\n className=\"m-r-half m-t-half\"\n />\n );\n let text = '';\n\n if (percents) {\n text += formatDifferencePercentage(absDiff, isIncrease);\n } else {\n const diffPercentage = formatDifferencePercentage(diffPercent, isIncrease);\n\n if (diffPercentOnly) {\n text += `${diffPercentage}`;\n } else {\n text += `${formatDifference(absDiff, isIncrease, format)}`;\n\n if (diffPercent !== 0) {\n text += ` (${diffPercentage})`;\n }\n }\n }\n\n return (\n <Stack\n className={classNames(Styles.statDiff, className)}\n justifyContent=\"center\"\n alignItems=\"center\"\n >\n <Stack.Item>\n <span>{diff}</span>\n </Stack.Item>\n <Stack.Item>\n <BodyText\n size={size ?? 'small'}\n data-cy=\"stat-diff-value\"\n className={classNames({\n 'c-red-500': !neutral && (inverted ? isIncrease : !isIncrease),\n 'c-green-500': !neutral && (inverted ? !isIncrease : isIncrease),\n 'c-neutral-200': !!neutral,\n })}\n >\n {value === undefined ? '\\u00A0' : text}\n </BodyText>\n </Stack.Item>\n </Stack>\n );\n};\n\nexport interface StatCardProps {\n title: string;\n description?: string;\n popoverContent?: ReactNode;\n value?: number;\n prev?: number;\n percent?: boolean;\n money?: boolean;\n rate?: boolean;\n clean?: boolean;\n inverted?: boolean;\n neutral?: boolean;\n fill?: boolean;\n valueOnly?: boolean;\n className?: string;\n diffPercentOnly?: boolean;\n}\n\nexport const StatCard: FC<StatCardProps> = ({\n title,\n description,\n popoverContent,\n value,\n percent,\n money,\n rate,\n prev,\n clean,\n inverted,\n neutral,\n fill,\n valueOnly,\n className,\n diffPercentOnly = false,\n}) => {\n const [popoverShown, setPopoverShown] = useState(false);\n const format = money ? 'money' : percent ? 'percent' : rate ? 'rate' : 'number';\n const val = value === undefined ? '\\u00A0' : formatValue(value, format);\n\n const eyebrow = (\n <Eyebrow\n className={classNames(Styles.title, 'ta-center')}\n data-cy={`marketing-stat-${title}-title`}\n onMouseEnter={() => {\n setPopoverShown(true);\n }}\n >\n {title}\n </Eyebrow>\n );\n\n return (\n <Stack\n direction=\"column\"\n alignItems=\"center\"\n className={classNames(\n 'p-y-3',\n {\n 'bg-white border-radius-2 border': !clean,\n 'flex-grow-1 flex-basis-0': fill,\n },\n className\n )}\n onMouseLeave={() => setPopoverShown(false)}\n >\n {popoverContent ? (\n <Popover open={popoverShown} trigger={eyebrow}>\n {popoverContent}\n </Popover>\n ) : description ? (\n <Tooltip text={description} data-cy={`marketing-stat-${title}-tooltip`}>\n {eyebrow}\n </Tooltip>\n ) : (\n eyebrow\n )}\n <BodyText className=\"fs-6-i ff-display\" data-cy={`marketing-stat-${title}-value`}>\n {val}\n </BodyText>\n {!valueOnly && (\n <StatDiff\n value={value}\n prev={prev}\n format={format}\n inverted={inverted}\n neutral={neutral}\n diffPercentOnly={diffPercentOnly}\n />\n )}\n </Stack>\n );\n};\n"],"names":["useState","classNames","BodyText","Eyebrow","Popover","Stack","Tooltip","Styles","formatValue","Icon","TrendingUpSVG","TrendingDownSVG","calculateDiff","value","prev","percents","diff","absDiff","Math","abs","diffPercent","formatDifference","isPlus","format","formatDifferencePercentage","StatDiff","size","inverted","neutral","className","diffPercentOnly","isIncrease","svg","color","text","diffPercentage","statDiff","justifyContent","alignItems","Item","span","data-cy","undefined","StatCard","title","description","popoverContent","percent","money","rate","clean","fill","valueOnly","popoverShown","setPopoverShown","val","eyebrow","onMouseEnter","direction","onMouseLeave","open","trigger"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@servicetitan/marketing-ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "Marketing UI component and utils",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"react-image-crop": "8.6.5"
|
|
19
19
|
},
|
|
20
20
|
"peerDependencies": {
|
|
21
|
+
"@servicetitan/anvil2": "^1.42.0",
|
|
21
22
|
"@servicetitan/design-system": ">=13.2.1",
|
|
22
23
|
"@servicetitan/react-ioc": ">=14.1.1",
|
|
23
24
|
"@servicetitan/tokens": ">=12.2.1",
|
|
@@ -29,8 +30,9 @@
|
|
|
29
30
|
"react": ">=17.0.2"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
33
|
+
"@servicetitan/anvil2": "^1.42.0",
|
|
32
34
|
"@servicetitan/design-system": "~14.5.1",
|
|
33
|
-
"@servicetitan/react-ioc": "^
|
|
35
|
+
"@servicetitan/react-ioc": "^32.2.0",
|
|
34
36
|
"@servicetitan/tokens": ">=12.2.1",
|
|
35
37
|
"@testing-library/react": "^14.2.1",
|
|
36
38
|
"@types/accounting": "~0.4.2",
|
|
@@ -51,5 +53,5 @@
|
|
|
51
53
|
"less": true,
|
|
52
54
|
"webpack": false
|
|
53
55
|
},
|
|
54
|
-
"gitHead": "
|
|
56
|
+
"gitHead": "39c8bee0e01ce314dbdd07049e1d0851a03225ab"
|
|
55
57
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
@import (reference) '~@servicetitan/tokens/core/tokens.less';
|
|
2
|
+
|
|
3
|
+
.color-tag {
|
|
4
|
+
width: 15px;
|
|
5
|
+
height: 15px;
|
|
6
|
+
margin-right: @spacing-1;
|
|
7
|
+
border-radius: 4px;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.color-tag-outline {
|
|
11
|
+
border-style: solid;
|
|
12
|
+
border-width: 1px;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.color-tag-dashed {
|
|
16
|
+
height: 0;
|
|
17
|
+
border-top-style: dashed;
|
|
18
|
+
border-top-width: 3px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.color-tag-small {
|
|
22
|
+
width: @spacing-2;
|
|
23
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { FC, useId } from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import { BodyText, Stack } from '@servicetitan/design-system';
|
|
4
|
+
import * as Styles from './color-tag.module.less';
|
|
5
|
+
|
|
6
|
+
interface ColorTagProps {
|
|
7
|
+
label: string;
|
|
8
|
+
color: string;
|
|
9
|
+
className?: string;
|
|
10
|
+
colorTagClassName?: string;
|
|
11
|
+
small?: boolean;
|
|
12
|
+
dashed?: boolean;
|
|
13
|
+
strokeColor?: string;
|
|
14
|
+
outlineColor?: string;
|
|
15
|
+
pattern?: 'solid' | 'striped' | 'outline';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const ColorTag: FC<ColorTagProps> = ({
|
|
19
|
+
label,
|
|
20
|
+
color,
|
|
21
|
+
className,
|
|
22
|
+
small,
|
|
23
|
+
dashed,
|
|
24
|
+
outlineColor,
|
|
25
|
+
pattern,
|
|
26
|
+
strokeColor,
|
|
27
|
+
colorTagClassName,
|
|
28
|
+
}) => {
|
|
29
|
+
const uid = useId();
|
|
30
|
+
const patternId = `pattern-${uid}`;
|
|
31
|
+
|
|
32
|
+
const width = small ? 50 : 22;
|
|
33
|
+
const height = small ? 10 : 25;
|
|
34
|
+
const radius = small ? 0 : 3;
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<Stack alignItems="center" className={className} gap={1}>
|
|
38
|
+
{pattern === 'striped' ? (
|
|
39
|
+
<svg
|
|
40
|
+
width={width}
|
|
41
|
+
height={height}
|
|
42
|
+
viewBox={`0 0 ${width} ${height}`}
|
|
43
|
+
className={classNames(Styles.colorTag, colorTagClassName)}
|
|
44
|
+
aria-hidden
|
|
45
|
+
>
|
|
46
|
+
<defs>
|
|
47
|
+
<pattern
|
|
48
|
+
id={patternId}
|
|
49
|
+
patternUnits="userSpaceOnUse"
|
|
50
|
+
width="8"
|
|
51
|
+
height="8"
|
|
52
|
+
patternTransform="rotate(45)"
|
|
53
|
+
>
|
|
54
|
+
<rect width="4" height="8" fill={color} opacity="0.08" />
|
|
55
|
+
<rect width="2" height="8" fill={color} />
|
|
56
|
+
</pattern>
|
|
57
|
+
</defs>
|
|
58
|
+
<rect
|
|
59
|
+
x="0"
|
|
60
|
+
y="0"
|
|
61
|
+
width={width}
|
|
62
|
+
height={height}
|
|
63
|
+
rx={radius}
|
|
64
|
+
ry={radius}
|
|
65
|
+
fill={`url(#${patternId})`}
|
|
66
|
+
stroke={strokeColor ?? color}
|
|
67
|
+
strokeWidth={1}
|
|
68
|
+
vectorEffect="non-scaling-stroke"
|
|
69
|
+
/>
|
|
70
|
+
</svg>
|
|
71
|
+
) : (
|
|
72
|
+
<div
|
|
73
|
+
className={classNames(
|
|
74
|
+
Styles.colorTag,
|
|
75
|
+
small && Styles.colorTagSmall,
|
|
76
|
+
dashed && Styles.colorTagDashed,
|
|
77
|
+
pattern === 'outline' && Styles.colorTagOutline,
|
|
78
|
+
colorTagClassName
|
|
79
|
+
)}
|
|
80
|
+
style={
|
|
81
|
+
dashed
|
|
82
|
+
? { borderColor: strokeColor ?? color }
|
|
83
|
+
: pattern === 'outline'
|
|
84
|
+
? { borderColor: outlineColor ?? color, borderRadius: radius }
|
|
85
|
+
: { backgroundColor: color, borderRadius: radius }
|
|
86
|
+
}
|
|
87
|
+
/>
|
|
88
|
+
)}
|
|
89
|
+
<BodyText size={small ? 'xsmall' : 'small'}>{label}</BodyText>
|
|
90
|
+
</Stack>
|
|
91
|
+
);
|
|
92
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ColorTag } from './color-tag';
|