@servicetitan/marketing-ui 6.0.1 → 6.1.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/funnel-chart/components/funnel-chart.d.ts.map +1 -1
- package/dist/components/charts/funnel-chart/components/funnel-chart.js +1 -2
- package/dist/components/charts/funnel-chart/components/funnel-chart.js.map +1 -1
- package/dist/components/charts/funnel-chart/components/funnel-svg.js +3 -3
- package/dist/components/charts/funnel-chart/components/funnel-svg.js.map +1 -1
- package/dist/components/charts/line-chart/components/body.js +2 -2
- package/dist/components/charts/line-chart/components/body.js.map +1 -1
- package/dist/components/charts/line-chart/components/hover-popover.d.ts.map +1 -1
- package/dist/components/charts/line-chart/components/hover-popover.js +69 -44
- package/dist/components/charts/line-chart/components/hover-popover.js.map +1 -1
- package/dist/components/charts/line-chart/components/hover-popover.module.less +26 -1
- package/dist/components/charts/line-chart/components/hover-popover.module.less.d.ts +3 -0
- package/dist/components/charts/line-chart/components/stuff.js +2 -1
- package/dist/components/charts/line-chart/components/stuff.js.map +1 -1
- package/dist/components/charts/line-chart/components/svg-bars.js +1 -1
- package/dist/components/charts/line-chart/components/svg-bars.js.map +1 -1
- package/dist/components/charts/pie-chart/components/pie-chart.js +1 -0
- package/dist/components/charts/pie-chart/components/pie-chart.js.map +1 -1
- package/dist/components/charts/pie-chart/components/pie-chart.module.less +8 -0
- package/dist/components/charts/pie-chart/components/pie-chart.module.less.d.ts +2 -0
- package/dist/components/charts/pie-chart/components/pie.d.ts.map +1 -1
- package/dist/components/charts/pie-chart/components/pie.js +2 -0
- package/dist/components/charts/pie-chart/components/pie.js.map +1 -1
- package/dist/components/stat/stat-card.d.ts.map +1 -1
- package/dist/components/stat/stat-card.js +2 -2
- package/dist/components/stat/stat-card.js.map +1 -1
- package/package.json +2 -2
- package/src/components/charts/funnel-chart/components/funnel-chart.tsx +0 -1
- package/src/components/charts/funnel-chart/components/funnel-svg.tsx +3 -3
- package/src/components/charts/line-chart/components/body.tsx +1 -1
- package/src/components/charts/line-chart/components/hover-popover.module.less +26 -1
- package/src/components/charts/line-chart/components/hover-popover.module.less.d.ts +3 -0
- package/src/components/charts/line-chart/components/hover-popover.tsx +85 -47
- package/src/components/charts/line-chart/components/stuff.tsx +1 -1
- package/src/components/charts/line-chart/components/svg-bars.tsx +1 -1
- package/src/components/charts/pie-chart/components/pie-chart.module.less +8 -0
- package/src/components/charts/pie-chart/components/pie-chart.module.less.d.ts +2 -0
- package/src/components/charts/pie-chart/components/pie-chart.tsx +1 -1
- package/src/components/charts/pie-chart/components/pie.tsx +2 -0
- package/src/components/stat/stat-card.tsx +1 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"funnel-chart.d.ts","sourceRoot":"","sources":["../../../../../src/components/charts/funnel-chart/components/funnel-chart.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,EAAE,EAAY,MAAM,OAAO,CAAC;AAMxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAOtD,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,
|
|
1
|
+
{"version":3,"file":"funnel-chart.d.ts","sourceRoot":"","sources":["../../../../../src/components/charts/funnel-chart/components/funnel-chart.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,EAAE,EAAY,MAAM,OAAO,CAAC;AAMxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAOtD,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CA6J5C,CAAC"}
|
|
@@ -21,8 +21,7 @@ export const FunnelChart = ({ sections, format, topSideLength = defaultTopSideLe
|
|
|
21
21
|
]);
|
|
22
22
|
const hidePopover = ()=>setPopoverShown(undefined);
|
|
23
23
|
const rightStyles = useMemo(()=>({
|
|
24
|
-
left: `${100 - topSideLength}
|
|
25
|
-
width: `${topSideLength}%`
|
|
24
|
+
left: `${100 - topSideLength}%`
|
|
26
25
|
}), [
|
|
27
26
|
topSideLength
|
|
28
27
|
]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/components/charts/funnel-chart/components/funnel-chart.tsx"],"sourcesContent":["import { useMemo, useState, FC, Fragment } from 'react';\nimport classNames from 'classnames';\nimport { BodyText, Eyebrow, Icon, Mask, Stack, Tooltip } from '@servicetitan/design-system';\nimport { tokens } from '@servicetitan/tokens/core';\nimport { formatValue } from '../../../../utils/formatters';\nimport { StatDiff } from '../../../stat/stat-card';\nimport { FunnelChartProps } from '../utils/interface';\nimport { defaultBottomSideLength, defaultTopSideLength } from '../utils/const';\nimport { FunnelPyramidSvg } from './funnel-svg';\nimport * as Styles from './funnel-chart.module.less';\nimport { Popover } from '@servicetitan/anvil2';\nimport { ColorTag } from '../../common';\n\nexport const FunnelChart: FC<FunnelChartProps> = ({\n sections,\n format,\n topSideLength = defaultTopSideLength,\n bottomSideLength = defaultBottomSideLength,\n popoverContent: PopoverContent,\n loading,\n className,\n}) => {\n const [popoverShown, setPopoverShown] = useState<number | undefined>(undefined);\n const [rowYs, setRowYs] = useState<number[]>([]);\n const colors = useMemo(() => sections.map(s => s.color), [sections]);\n const outlineColors = useMemo(() => sections.map(s => s.outlineColor), [sections]);\n const hidePopover = () => setPopoverShown(undefined);\n\n const rightStyles = useMemo(\n () => ({\n left: `${100 - topSideLength}%`,\n width: `${topSideLength}%`,\n }),\n [topSideLength]\n );\n\n return (\n <Mask\n className={classNames(\n 'h-100 bg-white border border-radius-2 p-3 of-hidden position-relative',\n className\n )}\n active={!!loading}\n >\n <div className={Styles.pyramidWrapper}>\n <FunnelPyramidSvg\n colors={colors}\n outlineColors={outlineColors}\n topSideLength={topSideLength}\n bottomSideLength={bottomSideLength}\n onRowAnchors={setRowYs}\n />\n </div>\n\n <div\n className={classNames(\n 'd-f flex-column justify-content-around',\n Styles.pyramidBoxRight\n )}\n style={rightStyles}\n >\n {sections.map(({ id, title, value, color, prev, data, outlineColor }) => (\n <Stack\n key={title}\n className={Styles.flex1}\n justifyContent=\"center\"\n alignItems=\"center\"\n onMouseEnter={() => setPopoverShown(id)}\n onMouseLeave={hidePopover}\n >\n <Popover open={popoverShown === id} openOnHover placement=\"right\">\n <Popover.Trigger>\n {props => (\n <span {...props}>\n <div className={Styles.percentTextWrapper}>\n <BodyText\n className={classNames('m-x-2 m-b-0-i')}\n data-cy={`marketing-funnel-section-${id}-value`}\n >\n {formatValue(value, format)}\n </BodyText>\n </div>\n </span>\n )}\n </Popover.Trigger>\n <Popover.Content>\n <Stack\n alignItems=\"flex-start\"\n justifyContent=\"flex-start\"\n direction=\"column\"\n data-cy={`marketing-funnel-popover-${id}-content`}\n >\n <Stack>\n <ColorTag\n label=\"\"\n color={color}\n outlineColor={outlineColor}\n pattern={outlineColor ? 'outline' : 'solid'}\n />\n <BodyText bold className=\"m-r-half\">\n {title} {formatValue(value, format)}\n </BodyText>\n </Stack>\n <Stack.Item>\n <StatDiff\n value={value}\n prev={prev}\n size=\"xsmall\"\n format={format}\n />\n </Stack.Item>\n </Stack>\n\n {!!PopoverContent && (\n <PopoverContent\n id={id}\n value={value}\n text={formatValue(value, format)}\n data={data}\n />\n )}\n </Popover.Content>\n </Popover>\n </Stack>\n ))}\n </div>\n <div className={Styles.pyramidBoxLeft} style={{ width: `${100 - topSideLength}%` }}>\n {sections.map((s, i) => {\n const y = rowYs[i] ?? 0;\n const TITLE_UP = 24;\n const DIFF_DOWN = 4;\n\n return (\n <Fragment key={s.id}>\n <div\n className={Styles.leftTitle}\n style={{ top: `calc(${y}% - ${TITLE_UP}px)` }}\n >\n <Eyebrow\n size=\"small\"\n className={classNames(Styles.statTitle, 'm-r-half')}\n >\n {s.title}\n </Eyebrow>\n <Tooltip direction=\"t\" portal text={s.description}>\n <Icon\n name=\"info\"\n className=\"m-r-1\"\n size=\"14px\"\n color={tokens.colorNeutral90}\n />\n </Tooltip>\n </div>\n\n <div\n className={Styles.leftDiff}\n style={{ top: `calc(${y}% + ${DIFF_DOWN}px)` }}\n >\n <StatDiff\n value={s.value}\n prev={s.prev}\n size=\"small\"\n format={format}\n />\n </div>\n </Fragment>\n );\n })}\n </div>\n </Mask>\n );\n};\n"],"names":["useMemo","useState","Fragment","classNames","BodyText","Eyebrow","Icon","Mask","Stack","Tooltip","tokens","formatValue","StatDiff","defaultBottomSideLength","defaultTopSideLength","FunnelPyramidSvg","Styles","Popover","ColorTag","FunnelChart","sections","format","topSideLength","bottomSideLength","popoverContent","PopoverContent","loading","className","popoverShown","setPopoverShown","undefined","rowYs","setRowYs","colors","map","s","color","outlineColors","outlineColor","hidePopover","rightStyles","left","width","active","div","pyramidWrapper","onRowAnchors","pyramidBoxRight","style","id","title","value","prev","data","flex1","justifyContent","alignItems","onMouseEnter","onMouseLeave","open","openOnHover","placement","Trigger","props","span","percentTextWrapper","data-cy","Content","direction","label","pattern","bold","Item","size","text","pyramidBoxLeft","i","y","TITLE_UP","DIFF_DOWN","leftTitle","top","statTitle","portal","description","name","colorNeutral90","leftDiff"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../src/components/charts/funnel-chart/components/funnel-chart.tsx"],"sourcesContent":["import { useMemo, useState, FC, Fragment } from 'react';\nimport classNames from 'classnames';\nimport { BodyText, Eyebrow, Icon, Mask, Stack, Tooltip } from '@servicetitan/design-system';\nimport { tokens } from '@servicetitan/tokens/core';\nimport { formatValue } from '../../../../utils/formatters';\nimport { StatDiff } from '../../../stat/stat-card';\nimport { FunnelChartProps } from '../utils/interface';\nimport { defaultBottomSideLength, defaultTopSideLength } from '../utils/const';\nimport { FunnelPyramidSvg } from './funnel-svg';\nimport * as Styles from './funnel-chart.module.less';\nimport { Popover } from '@servicetitan/anvil2';\nimport { ColorTag } from '../../common';\n\nexport const FunnelChart: FC<FunnelChartProps> = ({\n sections,\n format,\n topSideLength = defaultTopSideLength,\n bottomSideLength = defaultBottomSideLength,\n popoverContent: PopoverContent,\n loading,\n className,\n}) => {\n const [popoverShown, setPopoverShown] = useState<number | undefined>(undefined);\n const [rowYs, setRowYs] = useState<number[]>([]);\n const colors = useMemo(() => sections.map(s => s.color), [sections]);\n const outlineColors = useMemo(() => sections.map(s => s.outlineColor), [sections]);\n const hidePopover = () => setPopoverShown(undefined);\n\n const rightStyles = useMemo(\n () => ({\n left: `${100 - topSideLength}%`,\n }),\n [topSideLength]\n );\n\n return (\n <Mask\n className={classNames(\n 'h-100 bg-white border border-radius-2 p-3 of-hidden position-relative',\n className\n )}\n active={!!loading}\n >\n <div className={Styles.pyramidWrapper}>\n <FunnelPyramidSvg\n colors={colors}\n outlineColors={outlineColors}\n topSideLength={topSideLength}\n bottomSideLength={bottomSideLength}\n onRowAnchors={setRowYs}\n />\n </div>\n\n <div\n className={classNames(\n 'd-f flex-column justify-content-around',\n Styles.pyramidBoxRight\n )}\n style={rightStyles}\n >\n {sections.map(({ id, title, value, color, prev, data, outlineColor }) => (\n <Stack\n key={title}\n className={Styles.flex1}\n justifyContent=\"center\"\n alignItems=\"center\"\n onMouseEnter={() => setPopoverShown(id)}\n onMouseLeave={hidePopover}\n >\n <Popover open={popoverShown === id} openOnHover placement=\"right\">\n <Popover.Trigger>\n {props => (\n <span {...props}>\n <div className={Styles.percentTextWrapper}>\n <BodyText\n className={classNames('m-x-2 m-b-0-i')}\n data-cy={`marketing-funnel-section-${id}-value`}\n >\n {formatValue(value, format)}\n </BodyText>\n </div>\n </span>\n )}\n </Popover.Trigger>\n <Popover.Content>\n <Stack\n alignItems=\"flex-start\"\n justifyContent=\"flex-start\"\n direction=\"column\"\n data-cy={`marketing-funnel-popover-${id}-content`}\n >\n <Stack>\n <ColorTag\n label=\"\"\n color={color}\n outlineColor={outlineColor}\n pattern={outlineColor ? 'outline' : 'solid'}\n />\n <BodyText bold className=\"m-r-half\">\n {title} {formatValue(value, format)}\n </BodyText>\n </Stack>\n <Stack.Item>\n <StatDiff\n value={value}\n prev={prev}\n size=\"xsmall\"\n format={format}\n />\n </Stack.Item>\n </Stack>\n\n {!!PopoverContent && (\n <PopoverContent\n id={id}\n value={value}\n text={formatValue(value, format)}\n data={data}\n />\n )}\n </Popover.Content>\n </Popover>\n </Stack>\n ))}\n </div>\n <div className={Styles.pyramidBoxLeft} style={{ width: `${100 - topSideLength}%` }}>\n {sections.map((s, i) => {\n const y = rowYs[i] ?? 0;\n const TITLE_UP = 24;\n const DIFF_DOWN = 4;\n\n return (\n <Fragment key={s.id}>\n <div\n className={Styles.leftTitle}\n style={{ top: `calc(${y}% - ${TITLE_UP}px)` }}\n >\n <Eyebrow\n size=\"small\"\n className={classNames(Styles.statTitle, 'm-r-half')}\n >\n {s.title}\n </Eyebrow>\n <Tooltip direction=\"t\" portal text={s.description}>\n <Icon\n name=\"info\"\n className=\"m-r-1\"\n size=\"14px\"\n color={tokens.colorNeutral90}\n />\n </Tooltip>\n </div>\n\n <div\n className={Styles.leftDiff}\n style={{ top: `calc(${y}% + ${DIFF_DOWN}px)` }}\n >\n <StatDiff\n value={s.value}\n prev={s.prev}\n size=\"small\"\n format={format}\n />\n </div>\n </Fragment>\n );\n })}\n </div>\n </Mask>\n );\n};\n"],"names":["useMemo","useState","Fragment","classNames","BodyText","Eyebrow","Icon","Mask","Stack","Tooltip","tokens","formatValue","StatDiff","defaultBottomSideLength","defaultTopSideLength","FunnelPyramidSvg","Styles","Popover","ColorTag","FunnelChart","sections","format","topSideLength","bottomSideLength","popoverContent","PopoverContent","loading","className","popoverShown","setPopoverShown","undefined","rowYs","setRowYs","colors","map","s","color","outlineColors","outlineColor","hidePopover","rightStyles","left","active","div","pyramidWrapper","onRowAnchors","pyramidBoxRight","style","id","title","value","prev","data","flex1","justifyContent","alignItems","onMouseEnter","onMouseLeave","open","openOnHover","placement","Trigger","props","span","percentTextWrapper","data-cy","Content","direction","label","pattern","bold","Item","size","text","pyramidBoxLeft","width","i","y","TITLE_UP","DIFF_DOWN","leftTitle","top","statTitle","portal","description","name","colorNeutral90","leftDiff"],"mappings":"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"}
|
|
@@ -18,8 +18,8 @@ export const FunnelPyramidSvg = ({ colors, topSideLength = defaultTopSideLength,
|
|
|
18
18
|
yt: yStep * ind,
|
|
19
19
|
yb: ind === len - 1 ? 100 : yStep * (ind + 1),
|
|
20
20
|
xtl: xOffset + lStep * ind,
|
|
21
|
-
xtr:
|
|
22
|
-
xbr:
|
|
21
|
+
xtr: 99 - lStep * ind,
|
|
22
|
+
xbr: 99 - lStep * (ind + 1),
|
|
23
23
|
xbl: xOffset + lStep * (ind + 1),
|
|
24
24
|
c: color
|
|
25
25
|
};
|
|
@@ -83,7 +83,7 @@ export const FunnelPyramidSvg = ({ colors, topSideLength = defaultTopSideLength,
|
|
|
83
83
|
sections.map((section, i)=>{
|
|
84
84
|
const isTop = i === 0;
|
|
85
85
|
const isBottom = i === sections.length - 1;
|
|
86
|
-
const d = roundedPath(section.xtl, section.xtr, section.xbr, section.xbl, section.yt, section.yb, isTop, isBottom, 2.5);
|
|
86
|
+
const d = roundedPath(section.xtl, section.xtr, section.xbr, section.xbl, section.yt + 1, section.yb, isTop, isBottom, 2.5);
|
|
87
87
|
return /*#__PURE__*/ _jsx("path", {
|
|
88
88
|
d: d,
|
|
89
89
|
fill: colors[i],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/components/charts/funnel-chart/components/funnel-svg.tsx"],"sourcesContent":["import { useMemo, FC, useEffect } from 'react';\nimport { tokens } from '@servicetitan/tokens/core';\nimport { defaultBottomSideLength, defaultTopSideLength } from '../utils/const';\nimport { roundedPath } from '../utils/svg-rounded-path';\n\nconst st = (v: number) => v.toFixed(2);\n\nexport interface FunnelPyramidSvgProps {\n colors: string[];\n topSideLength?: number;\n bottomSideLength?: number;\n outlineColors?: (string | undefined)[];\n onRowAnchors?: (ysPct: number[]) => void;\n}\n\nexport const FunnelPyramidSvg: FC<FunnelPyramidSvgProps> = ({\n colors,\n topSideLength = defaultTopSideLength,\n bottomSideLength = defaultBottomSideLength,\n outlineColors,\n onRowAnchors,\n}) => {\n const sections = useMemo(() => {\n if (!colors.length) {\n return [];\n }\n\n const len = colors.length;\n const yStep = 100 / len;\n const lStep = (topSideLength - Math.min(bottomSideLength, topSideLength)) / (len * 2);\n const xOffset = 100 - topSideLength;\n\n return colors.map((color, ind) => {\n return {\n yt: yStep * ind,\n yb: ind === len - 1 ? 100 : yStep * (ind + 1),\n xtl: xOffset + lStep * ind,\n xtr: 100 - lStep * ind,\n xbr: 100 - lStep * (ind + 1),\n xbl: xOffset + lStep * (ind + 1),\n c: color,\n };\n });\n }, [colors, topSideLength, bottomSideLength]);\n\n useEffect(() => {\n onRowAnchors?.(sections.map(s => (s.yt + s.yb) / 2));\n }, [onRowAnchors, sections]);\n\n const pointAlong = (start: number, end: number, t: number) => (1 - t) * start + t * end;\n const pxToViewBoxUnits = (px: number) => (px / 200) * 100;\n\n const GAP_PX = 4;\n const SEAM_PX = 1;\n\n const gapVU = pxToViewBoxUnits(GAP_PX);\n const seamVU = pxToViewBoxUnits(SEAM_PX);\n\n const lines = useMemo(() => {\n return sections.map((section, i) => {\n const y = (section.yt + section.yb) / 2;\n\n const height = section.yb - section.yt;\n const t = (y - section.yt) / height;\n const xLeftAtMid = pointAlong(section.xtl, section.xbl, t);\n const x2 = Math.max(0, xLeftAtMid - gapVU);\n\n return { id: i, y, x2 };\n });\n }, [sections, gapVU]);\n\n const seams = sections.slice(0, -1).map((s, i) => ({\n key: i,\n x1: s.xbl,\n x2: s.xbr,\n yTopEdge: s.yb - gapVU / 2 + seamVU / 2,\n color: outlineColors?.[i],\n }));\n\n return (\n <svg\n width=\"100%\"\n height=\"100%\"\n preserveAspectRatio=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <svg\n width=\"100%\"\n height=\"100%\"\n x=\"0%\"\n y=\"0\"\n viewBox=\"0 0 100 100\"\n preserveAspectRatio=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n {sections.map((section, i) => {\n const isTop = i === 0;\n const isBottom = i === sections.length - 1;\n\n const d = roundedPath(\n section.xtl,\n section.xtr,\n section.xbr,\n section.xbl,\n section.yt,\n section.yb,\n isTop,\n isBottom,\n 2.5\n );\n\n return (\n <path\n key={`section-${section.xbl}-${section.yb}-${section.xbr}-${section.yb}`}\n d={d}\n fill={colors[i]}\n stroke={outlineColors?.[i]}\n strokeWidth={1}\n vectorEffect=\"non-scaling-stroke\"\n strokeLinejoin=\"round\"\n />\n );\n })}\n {sections.slice(0, -1).map(section => (\n <line\n key={`gap-${section.xbl}-${section.yb}-${section.xbr}-${section.yb}`}\n x1={st(section.xbl)}\n y1={st(section.yb)}\n x2={st(section.xbr)}\n y2={st(section.yb)}\n stroke=\"#fff\"\n strokeWidth={GAP_PX}\n vectorEffect=\"non-scaling-stroke\"\n strokeLinecap=\"round\"\n />\n ))}\n {seams.map(({ key, x1, x2, yTopEdge, color }) =>\n color ? (\n <line\n key={`seam-${key}`}\n x1={st(x1)}\n y1={st(yTopEdge)}\n x2={st(x2)}\n y2={st(yTopEdge)}\n stroke={color}\n strokeWidth={SEAM_PX}\n vectorEffect=\"non-scaling-stroke\"\n strokeLinecap=\"round\"\n />\n ) : null\n )}\n </svg>\n <svg\n width=\"100%\"\n height=\"100%\"\n x=\"0\"\n y=\"0\"\n viewBox=\"0 0 100 100\"\n preserveAspectRatio=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n {lines.map(({ id, x2, y }) => (\n <line\n key={id}\n x1=\"0\"\n y1={st(y)}\n x2={st(x2)}\n y2={st(y)}\n stroke={tokens.colorNeutral60}\n strokeWidth={0.5}\n />\n ))}\n </svg>\n </svg>\n );\n};\n"],"names":["useMemo","useEffect","tokens","defaultBottomSideLength","defaultTopSideLength","roundedPath","st","v","toFixed","FunnelPyramidSvg","colors","topSideLength","bottomSideLength","outlineColors","onRowAnchors","sections","length","len","yStep","lStep","Math","min","xOffset","map","color","ind","yt","yb","xtl","xtr","xbr","xbl","c","s","pointAlong","start","end","t","pxToViewBoxUnits","px","GAP_PX","SEAM_PX","gapVU","seamVU","lines","section","i","y","height","xLeftAtMid","x2","max","id","seams","slice","key","x1","yTopEdge","svg","width","preserveAspectRatio","xmlns","x","viewBox","isTop","isBottom","d","path","fill","stroke","strokeWidth","vectorEffect","strokeLinejoin","line","y1","y2","strokeLinecap","colorNeutral60"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../src/components/charts/funnel-chart/components/funnel-svg.tsx"],"sourcesContent":["import { useMemo, FC, useEffect } from 'react';\nimport { tokens } from '@servicetitan/tokens/core';\nimport { defaultBottomSideLength, defaultTopSideLength } from '../utils/const';\nimport { roundedPath } from '../utils/svg-rounded-path';\n\nconst st = (v: number) => v.toFixed(2);\n\nexport interface FunnelPyramidSvgProps {\n colors: string[];\n topSideLength?: number;\n bottomSideLength?: number;\n outlineColors?: (string | undefined)[];\n onRowAnchors?: (ysPct: number[]) => void;\n}\n\nexport const FunnelPyramidSvg: FC<FunnelPyramidSvgProps> = ({\n colors,\n topSideLength = defaultTopSideLength,\n bottomSideLength = defaultBottomSideLength,\n outlineColors,\n onRowAnchors,\n}) => {\n const sections = useMemo(() => {\n if (!colors.length) {\n return [];\n }\n\n const len = colors.length;\n const yStep = 100 / len;\n const lStep = (topSideLength - Math.min(bottomSideLength, topSideLength)) / (len * 2);\n const xOffset = 100 - topSideLength;\n\n return colors.map((color, ind) => {\n return {\n yt: yStep * ind,\n yb: ind === len - 1 ? 100 : yStep * (ind + 1),\n xtl: xOffset + lStep * ind,\n xtr: 99 - lStep * ind,\n xbr: 99 - lStep * (ind + 1),\n xbl: xOffset + lStep * (ind + 1),\n c: color,\n };\n });\n }, [colors, topSideLength, bottomSideLength]);\n\n useEffect(() => {\n onRowAnchors?.(sections.map(s => (s.yt + s.yb) / 2));\n }, [onRowAnchors, sections]);\n\n const pointAlong = (start: number, end: number, t: number) => (1 - t) * start + t * end;\n const pxToViewBoxUnits = (px: number) => (px / 200) * 100;\n\n const GAP_PX = 4;\n const SEAM_PX = 1;\n\n const gapVU = pxToViewBoxUnits(GAP_PX);\n const seamVU = pxToViewBoxUnits(SEAM_PX);\n\n const lines = useMemo(() => {\n return sections.map((section, i) => {\n const y = (section.yt + section.yb) / 2;\n\n const height = section.yb - section.yt;\n const t = (y - section.yt) / height;\n const xLeftAtMid = pointAlong(section.xtl, section.xbl, t);\n const x2 = Math.max(0, xLeftAtMid - gapVU);\n\n return { id: i, y, x2 };\n });\n }, [sections, gapVU]);\n\n const seams = sections.slice(0, -1).map((s, i) => ({\n key: i,\n x1: s.xbl,\n x2: s.xbr,\n yTopEdge: s.yb - gapVU / 2 + seamVU / 2,\n color: outlineColors?.[i],\n }));\n\n return (\n <svg\n width=\"100%\"\n height=\"100%\"\n preserveAspectRatio=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <svg\n width=\"100%\"\n height=\"100%\"\n x=\"0%\"\n y=\"0\"\n viewBox=\"0 0 100 100\"\n preserveAspectRatio=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n {sections.map((section, i) => {\n const isTop = i === 0;\n const isBottom = i === sections.length - 1;\n\n const d = roundedPath(\n section.xtl,\n section.xtr,\n section.xbr,\n section.xbl,\n section.yt + 1,\n section.yb,\n isTop,\n isBottom,\n 2.5\n );\n\n return (\n <path\n key={`section-${section.xbl}-${section.yb}-${section.xbr}-${section.yb}`}\n d={d}\n fill={colors[i]}\n stroke={outlineColors?.[i]}\n strokeWidth={1}\n vectorEffect=\"non-scaling-stroke\"\n strokeLinejoin=\"round\"\n />\n );\n })}\n {sections.slice(0, -1).map(section => (\n <line\n key={`gap-${section.xbl}-${section.yb}-${section.xbr}-${section.yb}`}\n x1={st(section.xbl)}\n y1={st(section.yb)}\n x2={st(section.xbr)}\n y2={st(section.yb)}\n stroke=\"#fff\"\n strokeWidth={GAP_PX}\n vectorEffect=\"non-scaling-stroke\"\n strokeLinecap=\"round\"\n />\n ))}\n {seams.map(({ key, x1, x2, yTopEdge, color }) =>\n color ? (\n <line\n key={`seam-${key}`}\n x1={st(x1)}\n y1={st(yTopEdge)}\n x2={st(x2)}\n y2={st(yTopEdge)}\n stroke={color}\n strokeWidth={SEAM_PX}\n vectorEffect=\"non-scaling-stroke\"\n strokeLinecap=\"round\"\n />\n ) : null\n )}\n </svg>\n <svg\n width=\"100%\"\n height=\"100%\"\n x=\"0\"\n y=\"0\"\n viewBox=\"0 0 100 100\"\n preserveAspectRatio=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n {lines.map(({ id, x2, y }) => (\n <line\n key={id}\n x1=\"0\"\n y1={st(y)}\n x2={st(x2)}\n y2={st(y)}\n stroke={tokens.colorNeutral60}\n strokeWidth={0.5}\n />\n ))}\n </svg>\n </svg>\n );\n};\n"],"names":["useMemo","useEffect","tokens","defaultBottomSideLength","defaultTopSideLength","roundedPath","st","v","toFixed","FunnelPyramidSvg","colors","topSideLength","bottomSideLength","outlineColors","onRowAnchors","sections","length","len","yStep","lStep","Math","min","xOffset","map","color","ind","yt","yb","xtl","xtr","xbr","xbl","c","s","pointAlong","start","end","t","pxToViewBoxUnits","px","GAP_PX","SEAM_PX","gapVU","seamVU","lines","section","i","y","height","xLeftAtMid","x2","max","id","seams","slice","key","x1","yTopEdge","svg","width","preserveAspectRatio","xmlns","x","viewBox","isTop","isBottom","d","path","fill","stroke","strokeWidth","vectorEffect","strokeLinejoin","line","y1","y2","strokeLinecap","colorNeutral60"],"mappings":"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"}
|
|
@@ -112,8 +112,8 @@ export const Body = provide({
|
|
|
112
112
|
}),
|
|
113
113
|
display.metricsTitlePosition === 'bottom' && /*#__PURE__*/ _jsx(Stack, {
|
|
114
114
|
direction: "row",
|
|
115
|
-
justifyContent: "
|
|
116
|
-
className: "p-3",
|
|
115
|
+
justifyContent: "flex-start",
|
|
116
|
+
className: "p-t-3 p-x-5",
|
|
117
117
|
children: /*#__PURE__*/ _jsx(MetricsTitle, {
|
|
118
118
|
metrics: metrics
|
|
119
119
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/components/charts/line-chart/components/body.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, FC, Fragment } from 'react';\nimport { observer } from 'mobx-react';\nimport classNames from 'classnames';\nimport { Stack } from '@servicetitan/design-system';\nimport { provide, useDependencies } from '@servicetitan/react-ioc';\n\nimport { useClientRect } from '../../../../utils/use-client-rect';\nimport { LineChartStore } from '../stores/line-chart.store';\nimport { SvgStore } from '../stores/svg.store';\nimport { getXLabels } from '../utils/labels';\n\nimport { Sidebar } from './sidebar';\nimport { MetricsTitle, XAxisLabels } from './stuff';\nimport { SvgBody, SvgBodyHover } from './svg-body';\nimport { HoverPopover } from './hover-popover';\nimport * as Styles from './body.module.less';\n\nexport const Body: FC<{ classNameTitle?: string }> = provide({ singletons: [SvgStore] })(\n observer(({ classNameTitle }) => {\n const [{ display, metrics, left, right, periods, resolution, setHoveredIndex }, svgStore] =\n useDependencies(LineChartStore, SvgStore);\n\n useEffect(() => {\n svgStore.init(periods.length, metrics, left?.maxValue ?? 0, right?.maxValue ?? 0);\n }, [svgStore, periods, metrics, left, right]);\n const [rect, ref] = useClientRect();\n\n const onBarHover = useCallback(\n (ind: number) => setHoveredIndex(ind, true),\n [setHoveredIndex]\n );\n\n const onBarLeave = useCallback(\n (ind: number) => setHoveredIndex(ind, false),\n [setHoveredIndex]\n );\n\n const labels = useMemo(\n () => (display.xLabels ? getXLabels(periods, resolution, rect?.width ?? 0) : []),\n [display, periods, resolution, rect]\n );\n\n return (\n <div className=\"d-f flex-column\">\n <Stack alignItems=\"stretch\">\n {left && <Sidebar settings={left} classNameTitle={classNameTitle} />}\n <Stack.Item fill>\n <div\n ref={ref}\n className={classNames(Styles.chartWrapper, 'border-bottom', {\n 'border-left': !!left && display.yLeft,\n 'border-right': !!right && display.yRight,\n })}\n >\n {periods.length ? (\n <Fragment>\n {periods.length !== labels.length && (\n <div className={Styles.labelBorders}>\n {labels\n .map(([text, flex], ind) => [flex, `${ind}${text}`])\n .map(([flex, key]) => (\n <div key={key} style={{ flex }} />\n ))}\n </div>\n )}\n\n <SvgBody horizontalGrid={display.yGrid} metrics={metrics} />\n <HoverPopover />\n <SvgBodyHover\n onValueHover={onBarHover}\n onValueLeave={onBarLeave}\n />\n </Fragment>\n ) : (\n <Stack\n className=\"h-100\"\n justifyContent=\"center\"\n alignItems=\"center\"\n >\n No Data\n </Stack>\n )}\n </div>\n </Stack.Item>\n {right && <Sidebar settings={right} right classNameTitle={classNameTitle} />}\n </Stack>\n {display.xLabels && (\n <XAxisLabels\n labels={labels}\n width={rect?.width ?? 0}\n left={left?.width ?? 0}\n right={right?.width ?? 0}\n labelsMerged={periods.length !== labels.length}\n hasBars={\n !!metrics.filter(\n m =>\n m.type === 'bar' ||\n m.type === 'stacked-bar' ||\n m.type === 'grouped-bar'\n ).length\n }\n />\n )}\n {display.metricsTitlePosition === 'bottom' && (\n <Stack direction=\"row\" justifyContent=\"
|
|
1
|
+
{"version":3,"sources":["../../../../../src/components/charts/line-chart/components/body.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, FC, Fragment } from 'react';\nimport { observer } from 'mobx-react';\nimport classNames from 'classnames';\nimport { Stack } from '@servicetitan/design-system';\nimport { provide, useDependencies } from '@servicetitan/react-ioc';\n\nimport { useClientRect } from '../../../../utils/use-client-rect';\nimport { LineChartStore } from '../stores/line-chart.store';\nimport { SvgStore } from '../stores/svg.store';\nimport { getXLabels } from '../utils/labels';\n\nimport { Sidebar } from './sidebar';\nimport { MetricsTitle, XAxisLabels } from './stuff';\nimport { SvgBody, SvgBodyHover } from './svg-body';\nimport { HoverPopover } from './hover-popover';\nimport * as Styles from './body.module.less';\n\nexport const Body: FC<{ classNameTitle?: string }> = provide({ singletons: [SvgStore] })(\n observer(({ classNameTitle }) => {\n const [{ display, metrics, left, right, periods, resolution, setHoveredIndex }, svgStore] =\n useDependencies(LineChartStore, SvgStore);\n\n useEffect(() => {\n svgStore.init(periods.length, metrics, left?.maxValue ?? 0, right?.maxValue ?? 0);\n }, [svgStore, periods, metrics, left, right]);\n const [rect, ref] = useClientRect();\n\n const onBarHover = useCallback(\n (ind: number) => setHoveredIndex(ind, true),\n [setHoveredIndex]\n );\n\n const onBarLeave = useCallback(\n (ind: number) => setHoveredIndex(ind, false),\n [setHoveredIndex]\n );\n\n const labels = useMemo(\n () => (display.xLabels ? getXLabels(periods, resolution, rect?.width ?? 0) : []),\n [display, periods, resolution, rect]\n );\n\n return (\n <div className=\"d-f flex-column\">\n <Stack alignItems=\"stretch\">\n {left && <Sidebar settings={left} classNameTitle={classNameTitle} />}\n <Stack.Item fill>\n <div\n ref={ref}\n className={classNames(Styles.chartWrapper, 'border-bottom', {\n 'border-left': !!left && display.yLeft,\n 'border-right': !!right && display.yRight,\n })}\n >\n {periods.length ? (\n <Fragment>\n {periods.length !== labels.length && (\n <div className={Styles.labelBorders}>\n {labels\n .map(([text, flex], ind) => [flex, `${ind}${text}`])\n .map(([flex, key]) => (\n <div key={key} style={{ flex }} />\n ))}\n </div>\n )}\n\n <SvgBody horizontalGrid={display.yGrid} metrics={metrics} />\n <HoverPopover />\n <SvgBodyHover\n onValueHover={onBarHover}\n onValueLeave={onBarLeave}\n />\n </Fragment>\n ) : (\n <Stack\n className=\"h-100\"\n justifyContent=\"center\"\n alignItems=\"center\"\n >\n No Data\n </Stack>\n )}\n </div>\n </Stack.Item>\n {right && <Sidebar settings={right} right classNameTitle={classNameTitle} />}\n </Stack>\n {display.xLabels && (\n <XAxisLabels\n labels={labels}\n width={rect?.width ?? 0}\n left={left?.width ?? 0}\n right={right?.width ?? 0}\n labelsMerged={periods.length !== labels.length}\n hasBars={\n !!metrics.filter(\n m =>\n m.type === 'bar' ||\n m.type === 'stacked-bar' ||\n m.type === 'grouped-bar'\n ).length\n }\n />\n )}\n {display.metricsTitlePosition === 'bottom' && (\n <Stack direction=\"row\" justifyContent=\"flex-start\" className=\"p-t-3 p-x-5\">\n <MetricsTitle metrics={metrics} />\n </Stack>\n )}\n </div>\n );\n })\n);\n"],"names":["useCallback","useEffect","useMemo","Fragment","observer","classNames","Stack","provide","useDependencies","useClientRect","LineChartStore","SvgStore","getXLabels","Sidebar","MetricsTitle","XAxisLabels","SvgBody","SvgBodyHover","HoverPopover","Styles","Body","singletons","classNameTitle","display","metrics","left","right","periods","resolution","setHoveredIndex","svgStore","init","length","maxValue","rect","ref","onBarHover","ind","onBarLeave","labels","xLabels","width","div","className","alignItems","settings","Item","fill","chartWrapper","yLeft","yRight","labelBorders","map","text","flex","key","style","horizontalGrid","yGrid","onValueHover","onValueLeave","justifyContent","labelsMerged","hasBars","filter","m","type","metricsTitlePosition","direction"],"mappings":";AAAA,SAASA,WAAW,EAAEC,SAAS,EAAEC,OAAO,EAAMC,QAAQ,QAAQ,QAAQ;AACtE,SAASC,QAAQ,QAAQ,aAAa;AACtC,OAAOC,gBAAgB,aAAa;AACpC,SAASC,KAAK,QAAQ,8BAA8B;AACpD,SAASC,OAAO,EAAEC,eAAe,QAAQ,0BAA0B;AAEnE,SAASC,aAAa,QAAQ,oCAAoC;AAClE,SAASC,cAAc,QAAQ,6BAA6B;AAC5D,SAASC,QAAQ,QAAQ,sBAAsB;AAC/C,SAASC,UAAU,QAAQ,kBAAkB;AAE7C,SAASC,OAAO,QAAQ,YAAY;AACpC,SAASC,YAAY,EAAEC,WAAW,QAAQ,UAAU;AACpD,SAASC,OAAO,EAAEC,YAAY,QAAQ,aAAa;AACnD,SAASC,YAAY,QAAQ,kBAAkB;AAC/C,YAAYC,YAAY,qBAAqB;AAE7C,OAAO,MAAMC,OAAwCb,QAAQ;IAAEc,YAAY;QAACV;KAAS;AAAC,GAClFP,SAAS,CAAC,EAAEkB,cAAc,EAAE;IACxB,MAAM,CAAC,EAAEC,OAAO,EAAEC,OAAO,EAAEC,IAAI,EAAEC,KAAK,EAAEC,OAAO,EAAEC,UAAU,EAAEC,eAAe,EAAE,EAAEC,SAAS,GACrFtB,gBAAgBE,gBAAgBC;IAEpCV,UAAU;YACiCwB,gBAAqBC;QAA5DI,SAASC,IAAI,CAACJ,QAAQK,MAAM,EAAER,SAASC,CAAAA,iBAAAA,iBAAAA,2BAAAA,KAAMQ,QAAQ,cAAdR,4BAAAA,iBAAkB,GAAGC,CAAAA,kBAAAA,kBAAAA,4BAAAA,MAAOO,QAAQ,cAAfP,6BAAAA,kBAAmB;IACnF,GAAG;QAACI;QAAUH;QAASH;QAASC;QAAMC;KAAM;IAC5C,MAAM,CAACQ,MAAMC,IAAI,GAAG1B;IAEpB,MAAM2B,aAAapC,YACf,CAACqC,MAAgBR,gBAAgBQ,KAAK,OACtC;QAACR;KAAgB;IAGrB,MAAMS,aAAatC,YACf,CAACqC,MAAgBR,gBAAgBQ,KAAK,QACtC;QAACR;KAAgB;IAGrB,MAAMU,SAASrC,QACX;YAAyDgC;eAAlDX,QAAQiB,OAAO,GAAG5B,WAAWe,SAASC,YAAYM,CAAAA,cAAAA,iBAAAA,2BAAAA,KAAMO,KAAK,cAAXP,yBAAAA,cAAe,KAAK,EAAE;OAC/E;QAACX;QAASI;QAASC;QAAYM;KAAK;QAkDjBA,aACDT,aACCC;IAjDvB,qBACI,MAACgB;QAAIC,WAAU;;0BACX,MAACrC;gBAAMsC,YAAW;;oBACbnB,sBAAQ,KAACZ;wBAAQgC,UAAUpB;wBAAMH,gBAAgBA;;kCAClD,KAAChB,MAAMwC,IAAI;wBAACC,IAAI;kCACZ,cAAA,KAACL;4BACGP,KAAKA;4BACLQ,WAAWtC,WAAWc,OAAO6B,YAAY,EAAE,iBAAiB;gCACxD,eAAe,CAAC,CAACvB,QAAQF,QAAQ0B,KAAK;gCACtC,gBAAgB,CAAC,CAACvB,SAASH,QAAQ2B,MAAM;4BAC7C;sCAECvB,QAAQK,MAAM,iBACX,MAAC7B;;oCACIwB,QAAQK,MAAM,KAAKO,OAAOP,MAAM,kBAC7B,KAACU;wCAAIC,WAAWxB,OAAOgC,YAAY;kDAC9BZ,OACIa,GAAG,CAAC,CAAC,CAACC,MAAMC,KAAK,EAAEjB,MAAQ;gDAACiB;gDAAM,GAAGjB,MAAMgB,MAAM;6CAAC,EAClDD,GAAG,CAAC,CAAC,CAACE,MAAMC,IAAI,iBACb,KAACb;gDAAcc,OAAO;oDAAEF;gDAAK;+CAAnBC;;kDAK1B,KAACvC;wCAAQyC,gBAAgBlC,QAAQmC,KAAK;wCAAElC,SAASA;;kDACjD,KAACN;kDACD,KAACD;wCACG0C,cAAcvB;wCACdwB,cAActB;;;+CAItB,KAAChC;gCACGqC,WAAU;gCACVkB,gBAAe;gCACfjB,YAAW;0CACd;;;;oBAMZlB,uBAAS,KAACb;wBAAQgC,UAAUnB;wBAAOA,KAAK;wBAACJ,gBAAgBA;;;;YAE7DC,QAAQiB,OAAO,kBACZ,KAACzB;gBACGwB,QAAQA;gBACRE,OAAOP,CAAAA,cAAAA,iBAAAA,2BAAAA,KAAMO,KAAK,cAAXP,yBAAAA,cAAe;gBACtBT,MAAMA,CAAAA,cAAAA,iBAAAA,2BAAAA,KAAMgB,KAAK,cAAXhB,yBAAAA,cAAe;gBACrBC,OAAOA,CAAAA,eAAAA,kBAAAA,4BAAAA,MAAOe,KAAK,cAAZf,0BAAAA,eAAgB;gBACvBoC,cAAcnC,QAAQK,MAAM,KAAKO,OAAOP,MAAM;gBAC9C+B,SACI,CAAC,CAACvC,QAAQwC,MAAM,CACZC,CAAAA,IACIA,EAAEC,IAAI,KAAK,SACXD,EAAEC,IAAI,KAAK,iBACXD,EAAEC,IAAI,KAAK,eACjBlC,MAAM;;YAInBT,QAAQ4C,oBAAoB,KAAK,0BAC9B,KAAC7D;gBAAM8D,WAAU;gBAAMP,gBAAe;gBAAalB,WAAU;0BACzD,cAAA,KAAC7B;oBAAaU,SAASA;;;;;AAK3C,IACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hover-popover.d.ts","sourceRoot":"","sources":["../../../../../src/components/charts/line-chart/components/hover-popover.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"hover-popover.d.ts","sourceRoot":"","sources":["../../../../../src/components/charts/line-chart/components/hover-popover.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA2D,EAAE,EAAiB,MAAM,OAAO,CAAC;AAgBnG,eAAO,MAAM,YAAY,EAAE,EAuHzB,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useCallback, useMemo,
|
|
2
|
+
import { useCallback, useMemo, useRef, useLayoutEffect, useState } from 'react';
|
|
3
3
|
import classNames from 'classnames';
|
|
4
4
|
import { observer } from 'mobx-react';
|
|
5
5
|
import { useDependencies } from '@servicetitan/react-ioc';
|
|
@@ -11,72 +11,97 @@ import { periodDateTitleFormatter } from '../utils/labels';
|
|
|
11
11
|
import * as Styles from './hover-popover.module.less';
|
|
12
12
|
import { ColorTag } from '../../common';
|
|
13
13
|
import { Text } from '@servicetitan/anvil2';
|
|
14
|
+
const CHART_HEIGHT_PX = 400;
|
|
15
|
+
const OFFSET_PX = 16;
|
|
14
16
|
export const HoverPopover = observer(()=>{
|
|
15
17
|
const [{ periods, resolution, hoveredIndex, metrics, display, formattedTotalAt, totalLabel, stackedTotals }, svgStore] = useDependencies(LineChartStore, SvgStore);
|
|
18
|
+
const isChartLeftSide = hoveredIndex < periods.length / 2;
|
|
16
19
|
const formatDateTitle = useMemo(()=>periodDateTitleFormatter[resolution], [
|
|
17
20
|
resolution
|
|
18
21
|
]);
|
|
19
22
|
const formatValue = useCallback((title, value, isRight)=>getFormatter(isRight ? display.metricsRightFormat : display.metricsLeftFormat)(value) + ' ' + title, [
|
|
20
23
|
display
|
|
21
24
|
]);
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
const popRef = useRef(null);
|
|
26
|
+
const [popH, setPopH] = useState(0);
|
|
27
|
+
useLayoutEffect(()=>{
|
|
28
|
+
if (!popRef.current) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const rect = popRef.current.getBoundingClientRect();
|
|
32
|
+
if (rect.height && Math.abs(rect.height - popH) > 0.5) {
|
|
33
|
+
setPopH(rect.height);
|
|
28
34
|
}
|
|
35
|
+
}, [
|
|
36
|
+
hoveredIndex,
|
|
37
|
+
metrics,
|
|
38
|
+
display,
|
|
39
|
+
popH
|
|
40
|
+
]);
|
|
41
|
+
const popoverStyle = useMemo(()=>{
|
|
42
|
+
const posX = svgStore.periodX(hoveredIndex);
|
|
43
|
+
const yHeights = metrics.filter((m)=>m.values[hoveredIndex] !== undefined).map((m)=>svgStore.periodY(m, hoveredIndex));
|
|
44
|
+
const barHeight = yHeights.length ? stackedTotals ? yHeights.reduce((a, b)=>a + b, 0) : Math.max(...yHeights) : 0;
|
|
45
|
+
const barHeightPercentRaw = svgStore.fpy(Math.max(0, Math.min(100, barHeight)));
|
|
46
|
+
const barHeightPercent = Math.max(0, Math.min(100, Number(barHeightPercentRaw) || 0));
|
|
47
|
+
const barTopPositionPx = barHeightPercent / 100 * CHART_HEIGHT_PX;
|
|
48
|
+
const availableSpaceBelow = Math.max(0, CHART_HEIGHT_PX - barTopPositionPx - popH);
|
|
49
|
+
const popoverOffsetPx = Math.min(OFFSET_PX, availableSpaceBelow);
|
|
29
50
|
return {
|
|
30
|
-
|
|
51
|
+
top: `${barHeightPercent}%`,
|
|
52
|
+
transform: `translateY(${popoverOffsetPx}px)`,
|
|
53
|
+
position: 'absolute',
|
|
54
|
+
...isChartLeftSide ? {
|
|
55
|
+
left: `${svgStore.fpx(posX + 2)}%`
|
|
56
|
+
} : {
|
|
57
|
+
right: `${svgStore.fpx(102 - posX)}%`
|
|
58
|
+
}
|
|
31
59
|
};
|
|
32
60
|
}, [
|
|
33
61
|
svgStore,
|
|
34
62
|
hoveredIndex,
|
|
35
|
-
|
|
63
|
+
isChartLeftSide,
|
|
64
|
+
metrics,
|
|
65
|
+
stackedTotals,
|
|
66
|
+
popH
|
|
36
67
|
]);
|
|
37
68
|
if (hoveredIndex < 0 || hoveredIndex >= periods.length) {
|
|
38
69
|
return null;
|
|
39
70
|
}
|
|
40
71
|
const period = periods[hoveredIndex];
|
|
41
72
|
const partialWeek = !!period.partial;
|
|
42
|
-
return /*#__PURE__*/ _jsxs(
|
|
73
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
74
|
+
ref: popRef,
|
|
75
|
+
className: classNames(Styles.popover, 'border border-radius-1 p-1'),
|
|
76
|
+
style: popoverStyle,
|
|
43
77
|
children: [
|
|
44
78
|
/*#__PURE__*/ _jsx("div", {
|
|
45
|
-
className: Styles.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
79
|
+
className: classNames(Styles.arrow, isChartLeftSide ? Styles.arrowLeft : Styles.arrowRight)
|
|
80
|
+
}),
|
|
81
|
+
/*#__PURE__*/ _jsx(Text, {
|
|
82
|
+
size: "small",
|
|
83
|
+
variant: "headline",
|
|
84
|
+
el: "h6",
|
|
85
|
+
children: stackedTotals ? `${formattedTotalAt(hoveredIndex)} ${totalLabel} | ${formatDateTitle(period)}` : formatDateTitle(period)
|
|
86
|
+
}),
|
|
87
|
+
partialWeek && /*#__PURE__*/ _jsx(BodyText, {
|
|
88
|
+
size: "xsmall",
|
|
89
|
+
subdued: true,
|
|
90
|
+
children: "Partial week"
|
|
49
91
|
}),
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
children: "Partial week"
|
|
64
|
-
}),
|
|
65
|
-
metrics.map((m)=>{
|
|
66
|
-
var _m_opts, _m_opts1, _m_opts2, _m_opts3, _m_opts4;
|
|
67
|
-
return m.values[hoveredIndex] !== undefined && /*#__PURE__*/ _jsx(ColorTag, {
|
|
68
|
-
small: true,
|
|
69
|
-
label: formatValue(m.title, m.values[hoveredIndex], m.isRight),
|
|
70
|
-
color: m.color,
|
|
71
|
-
className: "m-t-1",
|
|
72
|
-
dashed: (_m_opts = m.opts) === null || _m_opts === void 0 ? void 0 : _m_opts.dashed,
|
|
73
|
-
pattern: (_m_opts1 = m.opts) === null || _m_opts1 === void 0 ? void 0 : _m_opts1.pattern,
|
|
74
|
-
outlineColor: (_m_opts2 = m.opts) === null || _m_opts2 === void 0 ? void 0 : _m_opts2.outlineColor,
|
|
75
|
-
strokeColor: (_m_opts3 = m.opts) === null || _m_opts3 === void 0 ? void 0 : _m_opts3.strokeColor,
|
|
76
|
-
colorTagClassName: ((_m_opts4 = m.opts) === null || _m_opts4 === void 0 ? void 0 : _m_opts4.pattern) === 'outline' ? Styles.colorTagOutlined : Styles.colorTag
|
|
77
|
-
}, m.title);
|
|
78
|
-
})
|
|
79
|
-
]
|
|
92
|
+
metrics.map((m)=>{
|
|
93
|
+
var _m_opts, _m_opts1, _m_opts2, _m_opts3, _m_opts4;
|
|
94
|
+
return m.values[hoveredIndex] !== undefined && /*#__PURE__*/ _jsx(ColorTag, {
|
|
95
|
+
small: true,
|
|
96
|
+
label: formatValue(m.title, m.values[hoveredIndex], m.isRight),
|
|
97
|
+
color: m.color,
|
|
98
|
+
className: "m-t-1",
|
|
99
|
+
dashed: (_m_opts = m.opts) === null || _m_opts === void 0 ? void 0 : _m_opts.dashed,
|
|
100
|
+
pattern: (_m_opts1 = m.opts) === null || _m_opts1 === void 0 ? void 0 : _m_opts1.pattern,
|
|
101
|
+
outlineColor: (_m_opts2 = m.opts) === null || _m_opts2 === void 0 ? void 0 : _m_opts2.outlineColor,
|
|
102
|
+
strokeColor: (_m_opts3 = m.opts) === null || _m_opts3 === void 0 ? void 0 : _m_opts3.strokeColor,
|
|
103
|
+
colorTagClassName: ((_m_opts4 = m.opts) === null || _m_opts4 === void 0 ? void 0 : _m_opts4.pattern) === 'outline' ? Styles.colorTagOutlined : Styles.colorTag
|
|
104
|
+
}, m.title);
|
|
80
105
|
})
|
|
81
106
|
]
|
|
82
107
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/components/charts/line-chart/components/hover-popover.tsx"],"sourcesContent":["import { useCallback, useMemo, FC,
|
|
1
|
+
{"version":3,"sources":["../../../../../src/components/charts/line-chart/components/hover-popover.tsx"],"sourcesContent":["import { useCallback, useMemo, useRef, useLayoutEffect, useState, FC, CSSProperties } from 'react';\nimport classNames from 'classnames';\nimport { observer } from 'mobx-react';\nimport { useDependencies } from '@servicetitan/react-ioc';\nimport { BodyText } from '@servicetitan/design-system';\nimport { LineChartStore } from '../stores/line-chart.store';\nimport { SvgStore } from '../stores/svg.store';\nimport { getFormatter } from '../utils/formatters';\nimport { periodDateTitleFormatter } from '../utils/labels';\nimport * as Styles from './hover-popover.module.less';\nimport { ColorTag } from '../../common';\nimport { Text } from '@servicetitan/anvil2';\n\nconst CHART_HEIGHT_PX = 400;\nconst OFFSET_PX = 16;\n\nexport const HoverPopover: FC = observer(() => {\n const [\n {\n periods,\n resolution,\n hoveredIndex,\n metrics,\n display,\n formattedTotalAt,\n totalLabel,\n stackedTotals,\n },\n svgStore,\n ] = useDependencies(LineChartStore, SvgStore);\n const isChartLeftSide = hoveredIndex < periods.length / 2;\n\n const formatDateTitle = useMemo(() => periodDateTitleFormatter[resolution], [resolution]);\n const formatValue = useCallback(\n (title: string, value: number, isRight: boolean) =>\n getFormatter(isRight ? display.metricsRightFormat : display.metricsLeftFormat)(value) +\n ' ' +\n title,\n [display]\n );\n\n const popRef = useRef<HTMLDivElement | null>(null);\n const [popH, setPopH] = useState(0);\n\n useLayoutEffect(() => {\n if (!popRef.current) {\n return;\n }\n const rect = popRef.current.getBoundingClientRect();\n if (rect.height && Math.abs(rect.height - popH) > 0.5) {\n setPopH(rect.height);\n }\n }, [hoveredIndex, metrics, display, popH]);\n\n const popoverStyle = useMemo<CSSProperties>(() => {\n const posX = svgStore.periodX(hoveredIndex);\n\n const yHeights = metrics\n .filter(m => m.values[hoveredIndex] !== undefined)\n .map(m => svgStore.periodY(m, hoveredIndex));\n\n const barHeight = yHeights.length\n ? stackedTotals\n ? yHeights.reduce((a, b) => a + b, 0)\n : Math.max(...yHeights)\n : 0;\n const barHeightPercentRaw = svgStore.fpy(Math.max(0, Math.min(100, barHeight)));\n const barHeightPercent = Math.max(0, Math.min(100, Number(barHeightPercentRaw) || 0));\n\n const barTopPositionPx = (barHeightPercent / 100) * CHART_HEIGHT_PX;\n const availableSpaceBelow = Math.max(0, CHART_HEIGHT_PX - barTopPositionPx - popH);\n const popoverOffsetPx = Math.min(OFFSET_PX, availableSpaceBelow);\n\n return {\n top: `${barHeightPercent}%`,\n transform: `translateY(${popoverOffsetPx}px)`,\n position: 'absolute',\n ...(isChartLeftSide\n ? { left: `${svgStore.fpx(posX + 2)}%` }\n : { right: `${svgStore.fpx(102 - posX)}%` }),\n };\n }, [svgStore, hoveredIndex, isChartLeftSide, metrics, stackedTotals, popH]);\n\n if (hoveredIndex < 0 || hoveredIndex >= periods.length) {\n return null;\n }\n\n const period = periods[hoveredIndex]!;\n const partialWeek = !!period.partial;\n\n return (\n <div\n ref={popRef}\n className={classNames(Styles.popover, 'border border-radius-1 p-1')}\n style={popoverStyle}\n >\n <div\n className={classNames(\n Styles.arrow,\n isChartLeftSide ? Styles.arrowLeft : Styles.arrowRight\n )}\n />\n <Text size=\"small\" variant=\"headline\" el=\"h6\">\n {stackedTotals\n ? `${formattedTotalAt(hoveredIndex)} ${totalLabel} | ${formatDateTitle(period)}`\n : formatDateTitle(period)}\n </Text>\n {partialWeek && (\n <BodyText size=\"xsmall\" subdued>\n Partial week\n </BodyText>\n )}\n {metrics.map(\n m =>\n m.values[hoveredIndex] !== undefined && (\n <ColorTag\n small\n label={formatValue(m.title, m.values[hoveredIndex], m.isRight)}\n color={m.color}\n key={m.title}\n className=\"m-t-1\"\n dashed={m.opts?.dashed}\n pattern={m.opts?.pattern}\n outlineColor={m.opts?.outlineColor}\n strokeColor={m.opts?.strokeColor}\n colorTagClassName={\n m.opts?.pattern === 'outline'\n ? Styles.colorTagOutlined\n : Styles.colorTag\n }\n />\n )\n )}\n </div>\n );\n});\n"],"names":["useCallback","useMemo","useRef","useLayoutEffect","useState","classNames","observer","useDependencies","BodyText","LineChartStore","SvgStore","getFormatter","periodDateTitleFormatter","Styles","ColorTag","Text","CHART_HEIGHT_PX","OFFSET_PX","HoverPopover","periods","resolution","hoveredIndex","metrics","display","formattedTotalAt","totalLabel","stackedTotals","svgStore","isChartLeftSide","length","formatDateTitle","formatValue","title","value","isRight","metricsRightFormat","metricsLeftFormat","popRef","popH","setPopH","current","rect","getBoundingClientRect","height","Math","abs","popoverStyle","posX","periodX","yHeights","filter","m","values","undefined","map","periodY","barHeight","reduce","a","b","max","barHeightPercentRaw","fpy","min","barHeightPercent","Number","barTopPositionPx","availableSpaceBelow","popoverOffsetPx","top","transform","position","left","fpx","right","period","partialWeek","partial","div","ref","className","popover","style","arrow","arrowLeft","arrowRight","size","variant","el","subdued","small","label","color","dashed","opts","pattern","outlineColor","strokeColor","colorTagClassName","colorTagOutlined","colorTag"],"mappings":"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"}
|
|
@@ -16,7 +16,32 @@
|
|
|
16
16
|
.popover {
|
|
17
17
|
position: absolute;
|
|
18
18
|
width: 200px;
|
|
19
|
-
|
|
19
|
+
transform: rotate(45deg);
|
|
20
|
+
top: 12px;
|
|
21
|
+
z-index: 1000;
|
|
22
|
+
background-color: @color-neutral-30;
|
|
23
|
+
border: 1px solid @color-neutral-60;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.arrow {
|
|
27
|
+
position: absolute;
|
|
28
|
+
width: 8px;
|
|
29
|
+
height: 8px;
|
|
30
|
+
background-color: @color-neutral-30;
|
|
31
|
+
border-left: 1px solid @color-neutral-60;
|
|
32
|
+
border-top: 1px solid @color-neutral-60;
|
|
33
|
+
top: 50%;
|
|
34
|
+
z-index: 1;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.arrow-left {
|
|
38
|
+
left: -6px;
|
|
39
|
+
transform: rotate(-45deg);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.arrow-right {
|
|
43
|
+
right: -6px;
|
|
44
|
+
transform: rotate(135deg);
|
|
20
45
|
}
|
|
21
46
|
|
|
22
47
|
.color-tag {
|
|
@@ -5,7 +5,8 @@ import { BodyText, Stack } from '@servicetitan/design-system';
|
|
|
5
5
|
import * as Styles from './stuff.module.less';
|
|
6
6
|
import { ColorTag } from '../../common';
|
|
7
7
|
export const MetricsTitle = ({ metrics })=>/*#__PURE__*/ _jsx(Stack, {
|
|
8
|
-
alignItems: "
|
|
8
|
+
alignItems: "flex-start",
|
|
9
|
+
className: "m-l-half",
|
|
9
10
|
children: metrics.map((m)=>{
|
|
10
11
|
var _m_opts, _m_opts1, _m_opts2, _m_opts3;
|
|
11
12
|
return /*#__PURE__*/ _jsx(ColorTag, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/components/charts/line-chart/components/stuff.tsx"],"sourcesContent":["import { CSSProperties, useMemo, FC } from 'react';\nimport classNames from 'classnames';\nimport { BodyText, Stack } from '@servicetitan/design-system';\nimport * as Styles from './stuff.module.less';\nimport { LineChartMetric } from '../utils/interfaces';\nimport { ChartXLabels } from '../utils/internal-interfaces';\nimport { ColorTag } from '../../common';\n\ninterface MetricsTitleProps {\n metrics: LineChartMetric[];\n}\n\nexport const MetricsTitle: FC<MetricsTitleProps> = ({ metrics }) => (\n <Stack alignItems=\"
|
|
1
|
+
{"version":3,"sources":["../../../../../src/components/charts/line-chart/components/stuff.tsx"],"sourcesContent":["import { CSSProperties, useMemo, FC } from 'react';\nimport classNames from 'classnames';\nimport { BodyText, Stack } from '@servicetitan/design-system';\nimport * as Styles from './stuff.module.less';\nimport { LineChartMetric } from '../utils/interfaces';\nimport { ChartXLabels } from '../utils/internal-interfaces';\nimport { ColorTag } from '../../common';\n\ninterface MetricsTitleProps {\n metrics: LineChartMetric[];\n}\n\nexport const MetricsTitle: FC<MetricsTitleProps> = ({ metrics }) => (\n <Stack alignItems=\"flex-start\" className=\"m-l-half\">\n {metrics.map(m => (\n <ColorTag\n key={m.id}\n label={m.title}\n color={m.color}\n dashed={m.opts?.dashed}\n pattern={m.opts?.pattern}\n outlineColor={m.opts?.outlineColor}\n strokeColor={m.opts?.strokeColor}\n className=\"m-r-4\"\n />\n ))}\n </Stack>\n);\n\nexport const XAxisLabels: FC<{\n labels: ChartXLabels;\n width: number;\n left: number;\n right: number;\n labelsMerged: boolean;\n hasBars: boolean;\n}> = ({ labels, width, left, right, labelsMerged, hasBars }) => {\n const data = useMemo(() => {\n const styles: CSSProperties = {};\n const labelsMapped = labels.map(([text, flex], ind) => ({\n text,\n flex,\n key: `${ind}${text}`,\n className: '',\n }));\n\n if (hasBars) {\n // when we have bars, all labels will get space equally, so no need to calculate margins\n styles.marginLeft = `${left}px`;\n styles.marginRight = `${right}px`;\n } else if (labels.length && !!width && !labelsMerged) {\n // when we have only lines, we should calculate available space for first and last label\n\n const labelWidth = (width - left - right) / labels.length;\n const labelHalfWidth = labelWidth / 2;\n\n if (left) {\n if (left > labelHalfWidth) {\n styles.marginLeft = `${left - labelHalfWidth}px`;\n } else {\n labelsMapped[0].flex = (left + labelHalfWidth) / labelWidth;\n }\n } else {\n labelsMapped[0].flex = 0.5;\n labelsMapped[0].className = 't-truncate';\n }\n\n if (right) {\n if (right > labelHalfWidth) {\n styles.marginRight = `${right - labelHalfWidth}px`;\n } else {\n labelsMapped[labels.length - 1].flex = (right + labelHalfWidth) / labelWidth;\n }\n } else {\n labelsMapped[labels.length - 1].flex = 0.5;\n labelsMapped[labels.length - 1].className = 't-truncate';\n }\n }\n\n return {\n labels: labelsMapped,\n styles,\n };\n }, [labels, left, right, labelsMerged, width, hasBars]);\n\n return (\n <div style={data.styles}>\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"center\"\n className=\"m-t-1\"\n >\n {data.labels.map(({ text, flex, key, className }) => (\n <div key={key} style={{ flex }} className={className}>\n <BodyText\n size=\"xsmall\"\n className={classNames(Styles.xAxisLabel, 'ta-center')}\n >\n {text}\n </BodyText>\n </div>\n ))}\n </Stack>\n </div>\n );\n};\n"],"names":["useMemo","classNames","BodyText","Stack","Styles","ColorTag","MetricsTitle","metrics","alignItems","className","map","m","label","title","color","dashed","opts","pattern","outlineColor","strokeColor","id","XAxisLabels","labels","width","left","right","labelsMerged","hasBars","data","styles","labelsMapped","text","flex","ind","key","marginLeft","marginRight","length","labelWidth","labelHalfWidth","div","style","direction","justifyContent","size","xAxisLabel"],"mappings":"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"}
|
|
@@ -88,7 +88,7 @@ export const SvgBars = observer(({ metrics, isStackedBarChart, isGroupedBarChart
|
|
|
88
88
|
const TOP_RADIUS = 1;
|
|
89
89
|
const xLeft = +fpx(x - barWidth / 2);
|
|
90
90
|
const yTop = +fpy(stackedBarHeight) + (values.length - 2);
|
|
91
|
-
const height = +fpx(value.val);
|
|
91
|
+
const height = j === values.length - 1 ? +fpx(value.val - 2) : +fpx(value.val);
|
|
92
92
|
const width = +fpx(barWidth);
|
|
93
93
|
const r = j === 0 ? TOP_RADIUS : 0; // radius must be numeric
|
|
94
94
|
const d = [
|