@vectara/vectara-ui 19.1.0 → 19.3.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.
@@ -14,7 +14,10 @@ type Props = {
14
14
  showLegend?: boolean;
15
15
  showGrid?: boolean;
16
16
  showTooltip?: boolean;
17
+ syncId?: string;
18
+ syncMethod?: "index" | "value";
19
+ formatValue?: (value: number) => string;
17
20
  "data-testid"?: string;
18
21
  };
19
- export declare const VuiBarChart: ({ data, categoryKey, series, orientation, stacked, height, showLegend, showGrid, showTooltip, ...rest }: Props) => import("react/jsx-runtime").JSX.Element;
22
+ export declare const VuiBarChart: ({ data, categoryKey, series, orientation, stacked, height, showLegend, showGrid, showTooltip, syncId, syncMethod, formatValue, ...rest }: Props) => import("react/jsx-runtime").JSX.Element;
20
23
  export {};
@@ -14,11 +14,11 @@ import { Bar, CartesianGrid, BarChart as RechartsBarChart, Legend, ResponsiveCon
14
14
  import { getChartColor, getChartColorByIndex } from "./palette";
15
15
  import { chartAxisLineStyle, chartLegendProps, chartTickStyle, chartTooltipProps } from "./chartTheme";
16
16
  export const VuiBarChart = (_a) => {
17
- var { data, categoryKey, series, orientation = "columns", stacked = false, height = 320, showLegend = series.length > 1, showGrid = true, showTooltip = true } = _a, rest = __rest(_a, ["data", "categoryKey", "series", "orientation", "stacked", "height", "showLegend", "showGrid", "showTooltip"]);
17
+ var { data, categoryKey, series, orientation = "columns", stacked = false, height = 320, showLegend = series.length > 1, showGrid = true, showTooltip = true, syncId, syncMethod, formatValue } = _a, rest = __rest(_a, ["data", "categoryKey", "series", "orientation", "stacked", "height", "showLegend", "showGrid", "showTooltip", "syncId", "syncMethod", "formatValue"]);
18
18
  const isHorizontal = orientation === "bars";
19
19
  const categoryAxis = (_jsx(_Fragment, { children: isHorizontal ? (_jsx(YAxis, { type: "category", dataKey: categoryKey, tick: chartTickStyle, axisLine: chartAxisLineStyle, tickLine: false })) : (_jsx(XAxis, { type: "category", dataKey: categoryKey, tick: chartTickStyle, axisLine: chartAxisLineStyle, tickLine: false })) }));
20
- const valueAxis = isHorizontal ? (_jsx(XAxis, { type: "number", tick: chartTickStyle, axisLine: chartAxisLineStyle, tickLine: false })) : (_jsx(YAxis, { type: "number", tick: chartTickStyle, axisLine: chartAxisLineStyle, tickLine: false }));
21
- return (_jsx("div", Object.assign({ className: "vuiBarChart" }, rest, { children: _jsx(ResponsiveContainer, Object.assign({ width: "100%", height: height }, { children: _jsxs(RechartsBarChart, Object.assign({ data: data, layout: isHorizontal ? "vertical" : "horizontal" }, { children: [showGrid && (_jsx(CartesianGrid, { stroke: "var(--vui-color-border-light)", vertical: isHorizontal, horizontal: !isHorizontal })), categoryAxis, valueAxis, showTooltip && _jsx(Tooltip, Object.assign({ cursor: { fill: "var(--vui-color-light-shade)" } }, chartTooltipProps)), showLegend && _jsx(Legend, Object.assign({}, chartLegendProps)), series.map((s, index) => {
20
+ const valueAxis = isHorizontal ? (_jsx(XAxis, { type: "number", tick: chartTickStyle, axisLine: chartAxisLineStyle, tickLine: false, tickFormatter: formatValue })) : (_jsx(YAxis, { type: "number", tick: chartTickStyle, axisLine: chartAxisLineStyle, tickLine: false, tickFormatter: formatValue }));
21
+ return (_jsx("div", Object.assign({ className: "vuiBarChart" }, rest, { children: _jsx(ResponsiveContainer, Object.assign({ width: "100%", height: height }, { children: _jsxs(RechartsBarChart, Object.assign({ data: data, layout: isHorizontal ? "vertical" : "horizontal", syncId: syncId, syncMethod: syncMethod }, { children: [showGrid && (_jsx(CartesianGrid, { stroke: "var(--vui-color-border-light)", vertical: isHorizontal, horizontal: !isHorizontal })), categoryAxis, valueAxis, showTooltip && (_jsx(Tooltip, Object.assign({ cursor: { fill: "var(--vui-color-light-shade)" }, formatter: formatValue && ((value) => (typeof value === "number" ? formatValue(value) : value)) }, chartTooltipProps))), showLegend && _jsx(Legend, Object.assign({}, chartLegendProps)), series.map((s, index) => {
22
22
  var _a;
23
23
  return (_jsx(Bar, { dataKey: s.dataKey, name: (_a = s.name) !== null && _a !== void 0 ? _a : s.dataKey, fill: s.color ? getChartColor(s.color) : getChartColorByIndex(index), stackId: stacked ? "stack" : undefined, radius: isHorizontal ? [0, 4, 4, 0] : [4, 4, 0, 0],
24
24
  // A thin stroke separates touching segments regardless of fill,
@@ -15,7 +15,11 @@ type Props = {
15
15
  showLegend?: boolean;
16
16
  showGrid?: boolean;
17
17
  showTooltip?: boolean;
18
+ syncId?: string;
19
+ syncMethod?: "index" | "value";
20
+ formatLeftValue?: (value: number) => string;
21
+ formatRightValue?: (value: number) => string;
18
22
  "data-testid"?: string;
19
23
  };
20
- export declare const VuiComposedChart: ({ data, categoryKey, series, height, showLegend, showGrid, showTooltip, ...rest }: Props) => import("react/jsx-runtime").JSX.Element;
24
+ export declare const VuiComposedChart: ({ data, categoryKey, series, height, showLegend, showGrid, showTooltip, syncId, syncMethod, formatLeftValue, formatRightValue, ...rest }: Props) => import("react/jsx-runtime").JSX.Element;
21
25
  export {};
@@ -14,9 +14,20 @@ import { Bar, CartesianGrid, ComposedChart as RechartsComposedChart, Legend, Lin
14
14
  import { getChartColor, getChartColorByIndex } from "./palette";
15
15
  import { chartAxisLineStyle, chartLegendProps, chartTickStyle, chartTooltipProps } from "./chartTheme";
16
16
  export const VuiComposedChart = (_a) => {
17
- var { data, categoryKey, series, height = 320, showLegend = series.length > 1, showGrid = true, showTooltip = true } = _a, rest = __rest(_a, ["data", "categoryKey", "series", "height", "showLegend", "showGrid", "showTooltip"]);
17
+ var { data, categoryKey, series, height = 320, showLegend = series.length > 1, showGrid = true, showTooltip = true, syncId, syncMethod, formatLeftValue, formatRightValue } = _a, rest = __rest(_a, ["data", "categoryKey", "series", "height", "showLegend", "showGrid", "showTooltip", "syncId", "syncMethod", "formatLeftValue", "formatRightValue"]);
18
18
  const hasRightAxis = series.some((s) => s.axis === "right");
19
- return (_jsx("div", Object.assign({ className: "vuiComposedChart" }, rest, { children: _jsx(ResponsiveContainer, Object.assign({ width: "100%", height: height }, { children: _jsxs(RechartsComposedChart, Object.assign({ data: data }, { children: [showGrid && _jsx(CartesianGrid, { stroke: "var(--vui-color-border-light)", vertical: false }), _jsx(XAxis, { dataKey: categoryKey, tick: chartTickStyle, axisLine: chartAxisLineStyle, tickLine: false }), _jsx(YAxis, { yAxisId: "left", tick: chartTickStyle, axisLine: chartAxisLineStyle, tickLine: false }), hasRightAxis && (_jsx(YAxis, { yAxisId: "right", orientation: "right", tick: chartTickStyle, axisLine: chartAxisLineStyle, tickLine: false })), showTooltip && _jsx(Tooltip, Object.assign({ cursor: { fill: "var(--vui-color-light-shade)" } }, chartTooltipProps)), showLegend && _jsx(Legend, Object.assign({}, chartLegendProps)), series.map((s, index) => {
19
+ // A composed chart can mix two axes, so the tooltip formats each value by the
20
+ // axis its series is measured against rather than a single shared formatter.
21
+ const axisByDataKey = new Map(series.map((s) => { var _a; return [s.dataKey, (_a = s.axis) !== null && _a !== void 0 ? _a : "left"]; }));
22
+ const hasValueFormatter = Boolean(formatLeftValue || formatRightValue);
23
+ return (_jsx("div", Object.assign({ className: "vuiComposedChart" }, rest, { children: _jsx(ResponsiveContainer, Object.assign({ width: "100%", height: height }, { children: _jsxs(RechartsComposedChart, Object.assign({ data: data, syncId: syncId, syncMethod: syncMethod }, { children: [showGrid && _jsx(CartesianGrid, { stroke: "var(--vui-color-border-light)", vertical: false }), _jsx(XAxis, { dataKey: categoryKey, tick: chartTickStyle, axisLine: chartAxisLineStyle, tickLine: false }), _jsx(YAxis, { yAxisId: "left", tick: chartTickStyle, axisLine: chartAxisLineStyle, tickLine: false, tickFormatter: formatLeftValue }), hasRightAxis && (_jsx(YAxis, { yAxisId: "right", orientation: "right", tick: chartTickStyle, axisLine: chartAxisLineStyle, tickLine: false, tickFormatter: formatRightValue })), showTooltip && (_jsx(Tooltip, Object.assign({ cursor: { fill: "var(--vui-color-light-shade)" }, formatter: hasValueFormatter
24
+ ? (value, _name, item) => {
25
+ if (typeof value !== "number")
26
+ return value;
27
+ const format = axisByDataKey.get(String(item === null || item === void 0 ? void 0 : item.dataKey)) === "right" ? formatRightValue : formatLeftValue;
28
+ return format ? format(value) : value;
29
+ }
30
+ : undefined }, chartTooltipProps))), showLegend && _jsx(Legend, Object.assign({}, chartLegendProps)), series.map((s, index) => {
20
31
  var _a, _b;
21
32
  const color = s.color ? getChartColor(s.color) : getChartColorByIndex(index);
22
33
  const yAxisId = (_a = s.axis) !== null && _a !== void 0 ? _a : "left";
@@ -16,7 +16,10 @@ type Props = {
16
16
  showLegend?: boolean;
17
17
  showGrid?: boolean;
18
18
  showTooltip?: boolean;
19
+ syncId?: string;
20
+ syncMethod?: "index" | "value";
21
+ formatValue?: (value: number) => string;
19
22
  "data-testid"?: string;
20
23
  };
21
- export declare const VuiLineChart: ({ data, categoryKey, series, variant, curved, showPoints, height, showLegend, showGrid, showTooltip, ...rest }: Props) => import("react/jsx-runtime").JSX.Element;
24
+ export declare const VuiLineChart: ({ data, categoryKey, series, variant, curved, showPoints, height, showLegend, showGrid, showTooltip, syncId, syncMethod, formatValue, ...rest }: Props) => import("react/jsx-runtime").JSX.Element;
22
25
  export {};
@@ -14,10 +14,10 @@ import { Area, AreaChart as RechartsAreaChart, CartesianGrid, Line, LineChart as
14
14
  import { getChartColor, getChartColorByIndex } from "./palette";
15
15
  import { chartAxisLineStyle, chartLegendProps, chartTickStyle, chartTooltipProps } from "./chartTheme";
16
16
  export const VuiLineChart = (_a) => {
17
- var { data, categoryKey, series, variant = "line", curved = false, showPoints = true, height = 320, showLegend = series.length > 1, showGrid = true, showTooltip = true } = _a, rest = __rest(_a, ["data", "categoryKey", "series", "variant", "curved", "showPoints", "height", "showLegend", "showGrid", "showTooltip"]);
17
+ var { data, categoryKey, series, variant = "line", curved = false, showPoints = true, height = 320, showLegend = series.length > 1, showGrid = true, showTooltip = true, syncId, syncMethod, formatValue } = _a, rest = __rest(_a, ["data", "categoryKey", "series", "variant", "curved", "showPoints", "height", "showLegend", "showGrid", "showTooltip", "syncId", "syncMethod", "formatValue"]);
18
18
  const isArea = variant === "area" || variant === "stacked-area";
19
19
  const isStacked = variant === "stacked-area";
20
- const axes = (_jsxs(_Fragment, { children: [showGrid && _jsx(CartesianGrid, { stroke: "var(--vui-color-border-light)", vertical: false }), _jsx(XAxis, { dataKey: categoryKey, tick: chartTickStyle, axisLine: chartAxisLineStyle, tickLine: false }), _jsx(YAxis, { tick: chartTickStyle, axisLine: chartAxisLineStyle, tickLine: false }), showTooltip && _jsx(Tooltip, Object.assign({ cursor: { stroke: "var(--vui-color-border-medium)" } }, chartTooltipProps)), showLegend && _jsx(Legend, Object.assign({}, chartLegendProps))] }));
20
+ const axes = (_jsxs(_Fragment, { children: [showGrid && _jsx(CartesianGrid, { stroke: "var(--vui-color-border-light)", vertical: false }), _jsx(XAxis, { dataKey: categoryKey, tick: chartTickStyle, axisLine: chartAxisLineStyle, tickLine: false }), _jsx(YAxis, { tick: chartTickStyle, axisLine: chartAxisLineStyle, tickLine: false, tickFormatter: formatValue }), showTooltip && (_jsx(Tooltip, Object.assign({ cursor: { stroke: "var(--vui-color-border-medium)" }, formatter: formatValue && ((value) => (typeof value === "number" ? formatValue(value) : value)) }, chartTooltipProps))), showLegend && _jsx(Legend, Object.assign({}, chartLegendProps))] }));
21
21
  // Shared marker props keep lines and areas visually identical apart from the fill.
22
22
  const markProps = (s, index) => {
23
23
  var _a;
@@ -33,10 +33,10 @@ export const VuiLineChart = (_a) => {
33
33
  activeDot: { r: 5 }
34
34
  };
35
35
  };
36
- return (_jsx("div", Object.assign({ className: "vuiLineChart" }, rest, { children: _jsx(ResponsiveContainer, Object.assign({ width: "100%", height: height }, { children: isArea ? (_jsxs(RechartsAreaChart, Object.assign({ data: data }, { children: [axes, series.map((s, index) => {
36
+ return (_jsx("div", Object.assign({ className: "vuiLineChart" }, rest, { children: _jsx(ResponsiveContainer, Object.assign({ width: "100%", height: height }, { children: isArea ? (_jsxs(RechartsAreaChart, Object.assign({ data: data, syncId: syncId, syncMethod: syncMethod }, { children: [axes, series.map((s, index) => {
37
37
  const props = markProps(s, index);
38
38
  // Stacked areas tile rather than overlap, so they take a more solid
39
39
  // fill; overlapping areas stay translucent to remain readable.
40
40
  return (_jsx(Area, Object.assign({}, props, { fill: props.stroke, fillOpacity: isStacked ? 0.85 : 0.2, stackId: isStacked ? "stack" : undefined })));
41
- })] }))) : (_jsxs(RechartsLineChart, Object.assign({ data: data }, { children: [axes, series.map((s, index) => (_jsx(Line, Object.assign({}, markProps(s, index)))))] }))) })) })));
41
+ })] }))) : (_jsxs(RechartsLineChart, Object.assign({ data: data, syncId: syncId, syncMethod: syncMethod }, { children: [axes, series.map((s, index) => (_jsx(Line, Object.assign({}, markProps(s, index)))))] }))) })) })));
42
42
  };
@@ -1,9 +1,10 @@
1
1
  type Props = {
2
2
  children: React.ReactNode;
3
+ size?: "s" | "m";
3
4
  isActive?: boolean;
4
5
  onClick: () => void;
5
6
  append?: React.ReactNode;
6
7
  "data-testid"?: string;
7
8
  };
8
- export declare const VuiChip: ({ children, isActive, append, ...rest }: Props) => import("react/jsx-runtime").JSX.Element;
9
+ export declare const VuiChip: ({ children, size, isActive, append, ...rest }: Props) => import("react/jsx-runtime").JSX.Element;
9
10
  export {};
@@ -12,8 +12,8 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
13
  import classNames from "classnames";
14
14
  export const VuiChip = (_a) => {
15
- var { children, isActive, append } = _a, rest = __rest(_a, ["children", "isActive", "append"]);
16
- const classes = classNames("vuiChip", {
15
+ var { children, size = "m", isActive, append } = _a, rest = __rest(_a, ["children", "size", "isActive", "append"]);
16
+ const classes = classNames("vuiChip", `vuiChip--${size}`, {
17
17
  "vuiChip-isActive": isActive
18
18
  });
19
19
  return (_jsxs("button", Object.assign({ className: classes }, rest, { children: [_jsx("div", Object.assign({ className: "vuiChip__label" }, { children: children })), append && _jsx("div", Object.assign({ className: "vuiChip__append" }, { children: append }))] })));
@@ -4,7 +4,6 @@
4
4
  gap: $sizeXs;
5
5
  border: 1px solid var(--vui-color-border-light);
6
6
  background-color: var(--vui-color-light-shade);
7
- padding: $sizeXxs $sizeS;
8
7
  border-radius: $sizeM;
9
8
  transition: all $transitionSpeed;
10
9
  box-shadow: $shadowSmallStart;
@@ -17,20 +16,45 @@
17
16
 
18
17
  .vuiChip__label {
19
18
  font-weight: $fontWeightStrong;
20
- font-size: $fontSizeStandard;
21
19
  color: var(--vui-color-text);
22
- // Ensures consistent chip height regardless of whether
23
- // append is present or not.
24
- line-height: 1.6;
25
20
  }
26
21
 
27
22
  .vuiChip__append {
28
23
  color: var(--vui-color-subdued-shade);
29
- padding: $sizeXxs $sizeXs;
30
24
  font-size: $fontSizeSmall;
31
25
  border-radius: $sizeS;
32
26
  }
33
27
 
28
+ .vuiChip--s {
29
+ padding: $sizeXxs $sizeXs;
30
+
31
+ .vuiChip__label {
32
+ font-size: $fontSizeSmall;
33
+ // Ensures consistent chip height regardless of whether
34
+ // append is present or not.
35
+ line-height: 1.8;
36
+ }
37
+
38
+ .vuiChip__append {
39
+ padding: $sizeXxs $sizeXxs;
40
+ }
41
+ }
42
+
43
+ .vuiChip--m {
44
+ padding: $sizeXxs $sizeS;
45
+
46
+ .vuiChip__label {
47
+ font-size: $fontSizeStandard;
48
+ // Ensures consistent chip height regardless of whether
49
+ // append is present or not.
50
+ line-height: 1.6;
51
+ }
52
+
53
+ .vuiChip__append {
54
+ padding: $sizeXxs $sizeXs;
55
+ }
56
+ }
57
+
34
58
  .vuiChip-isActive {
35
59
  border: 1px solid var(--vui-color-primary-shade);
36
60
  background-color: var(--vui-color-empty-shade);
@@ -1531,7 +1531,6 @@ fieldset {
1531
1531
  gap: 8px;
1532
1532
  border: 1px solid var(--vui-color-border-light);
1533
1533
  background-color: var(--vui-color-light-shade);
1534
- padding: 4px 12px;
1535
1534
  border-radius: 16px;
1536
1535
  transition: all 0.2s;
1537
1536
  box-shadow: rgba(60, 64, 67, 0.3) 0px 0px 0px 0px, rgba(60, 64, 67, 0.15) 0px 0px 0px 0px;
@@ -1543,18 +1542,37 @@ fieldset {
1543
1542
 
1544
1543
  .vuiChip__label {
1545
1544
  font-weight: 500;
1546
- font-size: 14px;
1547
1545
  color: var(--vui-color-text);
1548
- line-height: 1.6;
1549
1546
  }
1550
1547
 
1551
1548
  .vuiChip__append {
1552
1549
  color: var(--vui-color-subdued-shade);
1553
- padding: 4px 8px;
1554
1550
  font-size: 12px;
1555
1551
  border-radius: 12px;
1556
1552
  }
1557
1553
 
1554
+ .vuiChip--s {
1555
+ padding: 4px 8px;
1556
+ }
1557
+ .vuiChip--s .vuiChip__label {
1558
+ font-size: 12px;
1559
+ line-height: 1.8;
1560
+ }
1561
+ .vuiChip--s .vuiChip__append {
1562
+ padding: 4px 4px;
1563
+ }
1564
+
1565
+ .vuiChip--m {
1566
+ padding: 4px 12px;
1567
+ }
1568
+ .vuiChip--m .vuiChip__label {
1569
+ font-size: 14px;
1570
+ line-height: 1.6;
1571
+ }
1572
+ .vuiChip--m .vuiChip__append {
1573
+ padding: 4px 8px;
1574
+ }
1575
+
1558
1576
  .vuiChip-isActive {
1559
1577
  border: 1px solid var(--vui-color-primary-shade);
1560
1578
  background-color: var(--vui-color-empty-shade);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vectara/vectara-ui",
3
- "version": "19.1.0",
3
+ "version": "19.3.0",
4
4
  "homepage": "./",
5
5
  "description": "Vectara's design system, codified as a React and Sass component library",
6
6
  "author": "Vectara",
@@ -0,0 +1,53 @@
1
+ import { useState } from "react";
2
+ import { VuiChip, VuiFlexContainer, VuiSpacer, VuiToggle } from "../../../lib";
3
+
4
+ export const Small = () => {
5
+ const [hasCounts, setHasCounts] = useState(false);
6
+ const [activeOption, setActiveOption] = useState<"all" | "a" | "b" | "c">("all");
7
+
8
+ return (
9
+ <>
10
+ <VuiToggle checked={hasCounts} onChange={() => setHasCounts(!hasCounts)} label="Append counts" />
11
+
12
+ <VuiSpacer size="m" />
13
+
14
+ <VuiFlexContainer spacing="xs">
15
+ <VuiChip
16
+ size="s"
17
+ onClick={() => setActiveOption("all")}
18
+ isActive={activeOption === "all"}
19
+ append={hasCounts ? 100 : undefined}
20
+ >
21
+ All options
22
+ </VuiChip>
23
+
24
+ <VuiChip
25
+ size="s"
26
+ onClick={() => setActiveOption("a")}
27
+ isActive={activeOption === "a"}
28
+ append={hasCounts ? 2 : undefined}
29
+ >
30
+ Option A
31
+ </VuiChip>
32
+
33
+ <VuiChip
34
+ size="s"
35
+ onClick={() => setActiveOption("b")}
36
+ isActive={activeOption === "b"}
37
+ append={hasCounts ? 81 : undefined}
38
+ >
39
+ Option B
40
+ </VuiChip>
41
+
42
+ <VuiChip
43
+ size="s"
44
+ onClick={() => setActiveOption("c")}
45
+ isActive={activeOption === "c"}
46
+ append={hasCounts ? 16 : undefined}
47
+ >
48
+ Option C
49
+ </VuiChip>
50
+ </VuiFlexContainer>
51
+ </>
52
+ );
53
+ };
@@ -1,11 +1,22 @@
1
1
  import { Chip } from "./Chip";
2
+ import { Small } from "./Small";
3
+
2
4
  const ChipSource = require("!!raw-loader!./Chip");
5
+ const SmallSource = require("!!raw-loader!./Small");
3
6
 
4
7
  export const chip = {
5
8
  name: "Chip",
6
9
  path: "/chip",
7
- example: {
8
- component: <Chip />,
9
- source: ChipSource.default.toString()
10
- }
10
+ examples: [
11
+ {
12
+ name: "Chip",
13
+ component: <Chip />,
14
+ source: ChipSource.default.toString()
15
+ },
16
+ {
17
+ name: "Small",
18
+ component: <Small />,
19
+ source: SmallSource.default.toString()
20
+ }
21
+ ]
11
22
  };
@@ -0,0 +1,32 @@
1
+ import { VuiComposedChart } from "../../../lib";
2
+
3
+ // Request volume (bars, left axis) against p95 latency (line, right axis). The
4
+ // two axes measure different units, so each gets its own value formatter — and
5
+ // the shared tooltip formats each row by the axis its series belongs to.
6
+ const data = [
7
+ { time: "10:00", requests: 4200, latency: 820 },
8
+ { time: "10:05", requests: 5100, latency: 1240 },
9
+ { time: "10:10", requests: 6800, latency: 980 },
10
+ { time: "10:15", requests: 7400, latency: 2100 },
11
+ { time: "10:20", requests: 8200, latency: 1560 },
12
+ { time: "10:25", requests: 9100, latency: 1180 }
13
+ ];
14
+
15
+ const formatCount = (value: number) => (value >= 1000 ? `${(value / 1000).toFixed(1)}k` : `${value}`);
16
+
17
+ const formatMs = (ms: number) => (ms >= 1000 ? `${(ms / 1000).toFixed(1)}s` : `${ms}ms`);
18
+
19
+ export const FormattedAxes = () => {
20
+ return (
21
+ <VuiComposedChart
22
+ data={data}
23
+ categoryKey="time"
24
+ formatLeftValue={formatCount}
25
+ formatRightValue={formatMs}
26
+ series={[
27
+ { dataKey: "requests", name: "Requests", type: "bar", axis: "left" },
28
+ { dataKey: "latency", name: "p95 latency", type: "line", axis: "right", curved: true }
29
+ ]}
30
+ />
31
+ );
32
+ };
@@ -1,6 +1,8 @@
1
1
  import { Basic } from "./Basic";
2
+ import { FormattedAxes } from "./FormattedAxes";
2
3
 
3
4
  const BasicSource = require("!!raw-loader!./Basic");
5
+ const FormattedAxesSource = require("!!raw-loader!./FormattedAxes");
4
6
 
5
7
  export const composedChart = {
6
8
  name: "Composed chart",
@@ -10,6 +12,11 @@ export const composedChart = {
10
12
  name: "Basic",
11
13
  component: <Basic />,
12
14
  source: BasicSource.default.toString()
15
+ },
16
+ {
17
+ name: "Formatted axes",
18
+ component: <FormattedAxes />,
19
+ source: FormattedAxesSource.default.toString()
13
20
  }
14
21
  ]
15
22
  };
@@ -0,0 +1,25 @@
1
+ import { VuiLineChart } from "../../../lib";
2
+
3
+ const data = [
4
+ { time: "10:00", latency: 820 },
5
+ { time: "10:05", latency: 1240 },
6
+ { time: "10:10", latency: 980 },
7
+ { time: "10:15", latency: 2100 },
8
+ { time: "10:20", latency: 1560 },
9
+ { time: "10:25", latency: 1180 }
10
+ ];
11
+
12
+ // formatValue formats both the value-axis ticks and the tooltip readout, so raw
13
+ // millisecond values render as human-readable durations.
14
+ const formatMs = (ms: number) => (ms >= 1000 ? `${(ms / 1000).toFixed(1)}s` : `${ms}ms`);
15
+
16
+ export const FormattedValues = () => {
17
+ return (
18
+ <VuiLineChart
19
+ data={data}
20
+ categoryKey="time"
21
+ formatValue={formatMs}
22
+ series={[{ dataKey: "latency", name: "Latency" }]}
23
+ />
24
+ );
25
+ };
@@ -0,0 +1,48 @@
1
+ import { VuiBarChart, VuiLineChart, VuiSpacer } from "../../../lib";
2
+
3
+ // The two charts cover the same timeline at different resolutions. Hovering
4
+ // either one highlights the matching timestamp on both. syncMethod "value"
5
+ // aligns by the x-axis value rather than by data index, which is what lets
6
+ // charts with differing point counts stay in step.
7
+ const latency = [
8
+ { time: "10:00", p95: 320 },
9
+ { time: "10:10", p95: 280 },
10
+ { time: "10:20", p95: 460 },
11
+ { time: "10:30", p95: 240 }
12
+ ];
13
+
14
+ const requests = [
15
+ { time: "10:00", requests: 1200 },
16
+ { time: "10:05", requests: 1800 },
17
+ { time: "10:10", requests: 1500 },
18
+ { time: "10:15", requests: 2100 },
19
+ { time: "10:20", requests: 1900 },
20
+ { time: "10:25", requests: 1700 },
21
+ { time: "10:30", requests: 1400 }
22
+ ];
23
+
24
+ const SYNC_ID = "trafficDemo";
25
+
26
+ export const Synced = () => {
27
+ return (
28
+ <>
29
+ <VuiLineChart
30
+ data={latency}
31
+ categoryKey="time"
32
+ syncId={SYNC_ID}
33
+ syncMethod="value"
34
+ height={200}
35
+ series={[{ dataKey: "p95", name: "p95 latency (ms)" }]}
36
+ />
37
+ <VuiSpacer size="m" />
38
+ <VuiBarChart
39
+ data={requests}
40
+ categoryKey="time"
41
+ syncId={SYNC_ID}
42
+ syncMethod="value"
43
+ height={200}
44
+ series={[{ dataKey: "requests", name: "Requests" }]}
45
+ />
46
+ </>
47
+ );
48
+ };
@@ -2,11 +2,15 @@ import { Basic } from "./Basic";
2
2
  import { Curved } from "./Curved";
3
3
  import { Area } from "./Area";
4
4
  import { StackedArea } from "./StackedArea";
5
+ import { FormattedValues } from "./FormattedValues";
6
+ import { Synced } from "./Synced";
5
7
 
6
8
  const BasicSource = require("!!raw-loader!./Basic");
7
9
  const CurvedSource = require("!!raw-loader!./Curved");
8
10
  const AreaSource = require("!!raw-loader!./Area");
9
11
  const StackedAreaSource = require("!!raw-loader!./StackedArea");
12
+ const FormattedValuesSource = require("!!raw-loader!./FormattedValues");
13
+ const SyncedSource = require("!!raw-loader!./Synced");
10
14
 
11
15
  export const lineChart = {
12
16
  name: "Line chart",
@@ -31,6 +35,16 @@ export const lineChart = {
31
35
  name: "Stacked area",
32
36
  component: <StackedArea />,
33
37
  source: StackedAreaSource.default.toString()
38
+ },
39
+ {
40
+ name: "Formatted values",
41
+ component: <FormattedValues />,
42
+ source: FormattedValuesSource.default.toString()
43
+ },
44
+ {
45
+ name: "Synced",
46
+ component: <Synced />,
47
+ source: SyncedSource.default.toString()
34
48
  }
35
49
  ]
36
50
  };