@vectara/vectara-ui 18.4.0 → 19.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.
Files changed (81) hide show
  1. package/lib/components/card/SimpleCard.d.ts +1 -1
  2. package/lib/components/card/_index.scss +5 -30
  3. package/lib/components/chart/BarChart.d.ts +20 -0
  4. package/lib/components/chart/BarChart.js +28 -0
  5. package/lib/components/chart/ComposedChart.d.ts +21 -0
  6. package/lib/components/chart/ComposedChart.js +29 -0
  7. package/lib/components/chart/LineChart.d.ts +22 -0
  8. package/lib/components/chart/LineChart.js +42 -0
  9. package/lib/components/chart/PieChart.d.ts +15 -0
  10. package/lib/components/chart/PieChart.js +36 -0
  11. package/lib/components/chart/ScatterChart.d.ts +18 -0
  12. package/lib/components/chart/ScatterChart.js +34 -0
  13. package/lib/components/chart/Sparkline.d.ts +13 -0
  14. package/lib/components/chart/Sparkline.js +23 -0
  15. package/lib/components/chart/TreeMap.d.ts +13 -0
  16. package/lib/components/chart/TreeMap.js +51 -0
  17. package/lib/components/chart/_index.scss +19 -0
  18. package/lib/components/chart/chartTheme.d.ts +21 -0
  19. package/lib/components/chart/chartTheme.js +13 -0
  20. package/lib/components/chart/palette.d.ts +5 -0
  21. package/lib/components/chart/palette.js +29 -0
  22. package/lib/components/composer/Composer.d.ts +41 -0
  23. package/lib/components/composer/Composer.js +148 -0
  24. package/lib/components/composer/_index.scss +4 -0
  25. package/lib/components/composer/useComposerHistory.d.ts +34 -0
  26. package/lib/components/composer/useComposerHistory.js +127 -0
  27. package/lib/components/context/Theme.d.ts +32 -0
  28. package/lib/components/context/Theme.js +116 -3
  29. package/lib/components/fileDropTarget/FileDropTarget.d.ts +8 -0
  30. package/lib/components/fileDropTarget/FileDropTarget.js +69 -0
  31. package/lib/components/fileDropTarget/_index.scss +34 -0
  32. package/lib/components/index.d.ts +13 -2
  33. package/lib/components/index.js +12 -1
  34. package/lib/components/patch/VuiPatch.d.ts +10 -0
  35. package/lib/components/patch/VuiPatch.js +32 -0
  36. package/lib/components/patch/_index.scss +30 -0
  37. package/lib/styles/index.css +143 -27
  38. package/package.json +4 -3
  39. package/src/docs/Docs.tsx +10 -0
  40. package/src/docs/pages/barChart/Basic.tsx +21 -0
  41. package/src/docs/pages/barChart/Horizontal.tsx +20 -0
  42. package/src/docs/pages/barChart/Stacked.tsx +23 -0
  43. package/src/docs/pages/barChart/index.tsx +29 -0
  44. package/src/docs/pages/card/SimpleCard.tsx +72 -6
  45. package/src/docs/pages/colorPalette/CategoricalColors.tsx +89 -0
  46. package/src/docs/pages/colorPalette/ChartColors.tsx +68 -0
  47. package/src/docs/pages/colorPalette/NeutralColors.tsx +42 -0
  48. package/src/docs/pages/colorPalette/SemanticColors.tsx +64 -0
  49. package/src/docs/pages/colorPalette/Swatch.tsx +59 -0
  50. package/src/docs/pages/colorPalette/TextAndBorderColors.tsx +37 -0
  51. package/src/docs/pages/colorPalette/Usage.tsx +72 -0
  52. package/src/docs/pages/colorPalette/index.tsx +50 -0
  53. package/src/docs/pages/composedChart/Basic.tsx +25 -0
  54. package/src/docs/pages/composedChart/index.tsx +15 -0
  55. package/src/docs/pages/composer/Composer.tsx +130 -0
  56. package/src/docs/pages/composer/index.tsx +11 -0
  57. package/src/docs/pages/fileDropTarget/FileDropTarget.tsx +80 -0
  58. package/src/docs/pages/fileDropTarget/index.tsx +11 -0
  59. package/src/docs/pages/lineChart/Area.tsx +25 -0
  60. package/src/docs/pages/lineChart/Basic.tsx +23 -0
  61. package/src/docs/pages/lineChart/Curved.tsx +25 -0
  62. package/src/docs/pages/lineChart/StackedArea.tsx +27 -0
  63. package/src/docs/pages/lineChart/index.tsx +36 -0
  64. package/src/docs/pages/patch/Icons.tsx +16 -0
  65. package/src/docs/pages/patch/Sizes.tsx +20 -0
  66. package/src/docs/pages/patch/index.tsx +22 -0
  67. package/src/docs/pages/pieChart/Basic.tsx +13 -0
  68. package/src/docs/pages/pieChart/Donut.tsx +12 -0
  69. package/src/docs/pages/pieChart/ManyValues.tsx +51 -0
  70. package/src/docs/pages/pieChart/Unlabeled.tsx +15 -0
  71. package/src/docs/pages/pieChart/index.tsx +36 -0
  72. package/src/docs/pages/scatterChart/Basic.tsx +31 -0
  73. package/src/docs/pages/scatterChart/Dense.tsx +144 -0
  74. package/src/docs/pages/scatterChart/index.tsx +22 -0
  75. package/src/docs/pages/sparkline/Basic.tsx +7 -0
  76. package/src/docs/pages/sparkline/Inline.tsx +21 -0
  77. package/src/docs/pages/sparkline/index.tsx +22 -0
  78. package/src/docs/pages/treeMap/Basic.tsx +14 -0
  79. package/src/docs/pages/treeMap/Nested.tsx +88 -0
  80. package/src/docs/pages/treeMap/index.tsx +22 -0
  81. package/src/docs/pages.tsx +20 -3
@@ -0,0 +1,89 @@
1
+ import { BiSolidBookmark } from "react-icons/bi";
2
+ import { VuiCopyButton, VuiFlexContainer, VuiFlexItem, VuiSpacer, VuiText, VuiTextColor } from "../../../lib";
3
+
4
+ // Categorical colors carry no fixed meaning — the hue just distinguishes one category from another.
5
+ // Each is a pair: a tinted background and a saturated foreground for text and icons.
6
+ const categoricalColors = [
7
+ // Warm
8
+ { name: "Red", background: "--vui-color-red-background", text: "--vui-color-red-text" },
9
+ { name: "Orange", background: "--vui-color-orange-background", text: "--vui-color-orange-text" },
10
+ { name: "Amber", background: "--vui-color-amber-background", text: "--vui-color-amber-text" },
11
+ // Greens
12
+ { name: "Lime", background: "--vui-color-lime-background", text: "--vui-color-lime-text" },
13
+ { name: "Emerald", background: "--vui-color-emerald-background", text: "--vui-color-emerald-text" },
14
+ { name: "Teal", background: "--vui-color-teal-background", text: "--vui-color-teal-text" },
15
+ // Blues
16
+ { name: "Sky", background: "--vui-color-sky-background", text: "--vui-color-sky-text" },
17
+ { name: "Indigo", background: "--vui-color-indigo-background", text: "--vui-color-indigo-text" },
18
+ // Purples and pinks
19
+ { name: "Purple", background: "--vui-color-purple-background", text: "--vui-color-purple-text" },
20
+ { name: "Fuchsia", background: "--vui-color-fuchsia-background", text: "--vui-color-fuchsia-text" },
21
+ { name: "Pink", background: "--vui-color-pink-background", text: "--vui-color-pink-text" },
22
+ // Neutral
23
+ { name: "Slate", background: "--vui-color-slate-background", text: "--vui-color-slate-text" }
24
+ ];
25
+
26
+ // A single CSS variable row: the variable name plus a button to copy its var() reference.
27
+ const VariableRow = ({ cssVariable }: { cssVariable: string }) => (
28
+ <VuiFlexContainer alignItems="center" spacing="xs" justifyContent="spaceBetween">
29
+ <VuiFlexItem grow={false}>
30
+ <VuiText size="xs">
31
+ <p>
32
+ <code>{cssVariable}</code>
33
+ </p>
34
+ </VuiText>
35
+ </VuiFlexItem>
36
+
37
+ <VuiFlexItem grow={false}>
38
+ <VuiCopyButton size="xs" value={`var(${cssVariable})`} title={`Copy var(${cssVariable})`} />
39
+ </VuiFlexItem>
40
+ </VuiFlexContainer>
41
+ );
42
+
43
+ export const CategoricalColors = () => {
44
+ return (
45
+ <>
46
+ <VuiText>
47
+ <p>
48
+ <VuiTextColor color="subdued">
49
+ Interchangeable hue pairs for color-coding categories. The icon inherits the foreground color via{" "}
50
+ <code>currentColor</code>, so a patch only needs the background and text variables.
51
+ </VuiTextColor>
52
+ </p>
53
+ </VuiText>
54
+
55
+ <VuiSpacer size="l" />
56
+
57
+ <VuiFlexContainer spacing="l" wrap>
58
+ {categoricalColors.map(({ name, background, text }) => (
59
+ <VuiFlexItem grow={false} key={name}>
60
+ <div style={{ width: 220 }}>
61
+ {/* A representative patch built from the pair. */}
62
+ <div
63
+ style={{
64
+ display: "inline-flex",
65
+ alignItems: "center",
66
+ gap: 6,
67
+ padding: "4px 10px",
68
+ borderRadius: 6,
69
+ fontSize: 13,
70
+ fontWeight: 600,
71
+ backgroundColor: `var(${background})`,
72
+ color: `var(${text})`
73
+ }}
74
+ >
75
+ <BiSolidBookmark />
76
+ {name}
77
+ </div>
78
+
79
+ <VuiSpacer size="s" />
80
+
81
+ <VariableRow cssVariable={background} />
82
+ <VariableRow cssVariable={text} />
83
+ </div>
84
+ </VuiFlexItem>
85
+ ))}
86
+ </VuiFlexContainer>
87
+ </>
88
+ );
89
+ };
@@ -0,0 +1,68 @@
1
+ import { VuiCopyButton, VuiFlexContainer, VuiFlexItem, VuiSpacer, VuiText, VuiTextColor } from "../../../lib";
2
+
3
+ // Chart colors are an ordered palette for plotting data series, distinct from the categorical chip hues.
4
+ // Each entry differs from its neighbors in both hue and luminance, so series stay distinguishable under
5
+ // color vision deficiency and in grayscale. The palette is capped at eight — the practical limit for
6
+ // telling categories apart by color alone.
7
+ const chartColors = [
8
+ { name: "Chart 1", variable: "--vui-chart-1", description: "Blue" },
9
+ { name: "Chart 2", variable: "--vui-chart-2", description: "Orange" },
10
+ { name: "Chart 3", variable: "--vui-chart-3", description: "Teal-green" },
11
+ { name: "Chart 4", variable: "--vui-chart-4", description: "Mauve" },
12
+ { name: "Chart 5", variable: "--vui-chart-5", description: "Sky" },
13
+ { name: "Chart 6", variable: "--vui-chart-6", description: "Vermillion" },
14
+ { name: "Chart 7", variable: "--vui-chart-7", description: "Gold" },
15
+ { name: "Chart 8", variable: "--vui-chart-8", description: "Slate" }
16
+ ];
17
+
18
+ export const ChartColors = () => {
19
+ return (
20
+ <>
21
+ <VuiText>
22
+ <p>
23
+ <VuiTextColor color="subdued">
24
+ An ordered palette for data visualization, assigned to series in sequence. Each color contrasts
25
+ with its neighbors in both hue and lightness, keeping series distinct for color-blind readers and
26
+ in grayscale. Use no more than eight; beyond that, group categories or add a non-color cue such as
27
+ a pattern or direct label.
28
+ </VuiTextColor>
29
+ </p>
30
+ </VuiText>
31
+
32
+ <VuiSpacer size="l" />
33
+
34
+ <VuiFlexContainer spacing="l" wrap>
35
+ {chartColors.map(({ name, variable, description }) => (
36
+ <VuiFlexItem grow={false} key={name}>
37
+ <div style={{ width: 160 }}>
38
+ {/* A solid swatch in the series color. */}
39
+ <div style={{ height: 64, borderRadius: 6, backgroundColor: `var(${variable})` }} />
40
+
41
+ <VuiSpacer size="s" />
42
+
43
+ <VuiText size="xs">
44
+ <p>
45
+ <strong>{name}</strong> <VuiTextColor color="subdued">{description}</VuiTextColor>
46
+ </p>
47
+ </VuiText>
48
+
49
+ <VuiFlexContainer alignItems="center" spacing="xs" justifyContent="spaceBetween">
50
+ <VuiFlexItem grow={false}>
51
+ <VuiText size="xs">
52
+ <p>
53
+ <code>{variable}</code>
54
+ </p>
55
+ </VuiText>
56
+ </VuiFlexItem>
57
+
58
+ <VuiFlexItem grow={false}>
59
+ <VuiCopyButton size="xs" value={`var(${variable})`} title={`Copy var(${variable})`} />
60
+ </VuiFlexItem>
61
+ </VuiFlexContainer>
62
+ </div>
63
+ </VuiFlexItem>
64
+ ))}
65
+ </VuiFlexContainer>
66
+ </>
67
+ );
68
+ };
@@ -0,0 +1,42 @@
1
+ import { VuiFlexContainer } from "../../../lib";
2
+ import { Subsection } from "../../components/Subsection";
3
+ import { Swatch } from "./Swatch";
4
+
5
+ // Neutral shades run from the empty shade (the app background) to the full shade.
6
+ // In the dark theme these invert, so reach for the semantic name rather than the literal lightness.
7
+ const neutralSwatches = [
8
+ { name: "Empty shade", cssVariable: "--vui-color-empty-shade", value: "#ffffff" },
9
+ { name: "Light shade", cssVariable: "--vui-color-light-shade", value: "#f1f4f6" },
10
+ { name: "Medium shade", cssVariable: "--vui-color-medium-shade", value: "#cbd1de" },
11
+ { name: "Dark shade", cssVariable: "--vui-color-dark-shade", value: "#3f4551" },
12
+ { name: "Darker shade", cssVariable: "--vui-color-darker-shade", value: "#1c1d22" },
13
+ { name: "Full shade", cssVariable: "--vui-color-full-shade", value: "#0b0c0e" }
14
+ ];
15
+
16
+ // Special-purpose accents that sit outside the semantic families.
17
+ const specialSwatches = [
18
+ { name: "Primary highlight", cssVariable: "--vui-color-primary-highlight-shade", value: "#d9e2ff" },
19
+ { name: "Subdued", cssVariable: "--vui-color-subdued-shade", value: "#6d7686" }
20
+ ];
21
+
22
+ export const NeutralColors = () => {
23
+ return (
24
+ <>
25
+ <Subsection title="Neutrals">
26
+ <VuiFlexContainer spacing="l" wrap>
27
+ {neutralSwatches.map((swatch) => (
28
+ <Swatch key={swatch.cssVariable} {...swatch} />
29
+ ))}
30
+ </VuiFlexContainer>
31
+ </Subsection>
32
+
33
+ <Subsection title="Special">
34
+ <VuiFlexContainer spacing="l" wrap>
35
+ {specialSwatches.map((swatch) => (
36
+ <Swatch key={swatch.cssVariable} {...swatch} />
37
+ ))}
38
+ </VuiFlexContainer>
39
+ </Subsection>
40
+ </>
41
+ );
42
+ };
@@ -0,0 +1,64 @@
1
+ import { VuiFlexContainer } from "../../../lib";
2
+ import { Subsection } from "../../components/Subsection";
3
+ import { Swatch } from "./Swatch";
4
+
5
+ // Each semantic family has three shades: a base "shade", a 50%-opacity "light shade",
6
+ // and a tinted "lighter shade" suitable for backgrounds.
7
+ const families = [
8
+ {
9
+ name: "Accent",
10
+ swatches: [
11
+ { name: "Shade", cssVariable: "--vui-color-accent-shade", value: "#5f30c3" },
12
+ { name: "Light shade", cssVariable: "--vui-color-accent-light-shade", value: "50% opacity" },
13
+ { name: "Lighter shade", cssVariable: "--vui-color-accent-lighter-shade", value: "#eee7ff" }
14
+ ]
15
+ },
16
+ {
17
+ name: "Primary",
18
+ swatches: [
19
+ { name: "Shade", cssVariable: "--vui-color-primary-shade", value: "#045dda" },
20
+ { name: "Light shade", cssVariable: "--vui-color-primary-light-shade", value: "50% opacity" },
21
+ { name: "Lighter shade", cssVariable: "--vui-color-primary-lighter-shade", value: "#f1f7ff" }
22
+ ]
23
+ },
24
+ {
25
+ name: "Success",
26
+ swatches: [
27
+ { name: "Shade", cssVariable: "--vui-color-success-shade", value: "#249719" },
28
+ { name: "Light shade", cssVariable: "--vui-color-success-light-shade", value: "50% opacity" },
29
+ { name: "Lighter shade", cssVariable: "--vui-color-success-lighter-shade", value: "#e2f2e0" }
30
+ ]
31
+ },
32
+ {
33
+ name: "Warning",
34
+ swatches: [
35
+ { name: "Shade", cssVariable: "--vui-color-warning-shade", value: "#a86f1b" },
36
+ { name: "Light shade", cssVariable: "--vui-color-warning-light-shade", value: "50% opacity" },
37
+ { name: "Lighter shade", cssVariable: "--vui-color-warning-lighter-shade", value: "#ffeed4" }
38
+ ]
39
+ },
40
+ {
41
+ name: "Danger",
42
+ swatches: [
43
+ { name: "Shade", cssVariable: "--vui-color-danger-shade", value: "#d22d2d" },
44
+ { name: "Light shade", cssVariable: "--vui-color-danger-light-shade", value: "50% opacity" },
45
+ { name: "Lighter shade", cssVariable: "--vui-color-danger-lighter-shade", value: "#fff1f1" }
46
+ ]
47
+ }
48
+ ];
49
+
50
+ export const SemanticColors = () => {
51
+ return (
52
+ <>
53
+ {families.map((family) => (
54
+ <Subsection key={family.name} title={family.name}>
55
+ <VuiFlexContainer spacing="l" wrap>
56
+ {family.swatches.map((swatch) => (
57
+ <Swatch key={swatch.cssVariable} {...swatch} />
58
+ ))}
59
+ </VuiFlexContainer>
60
+ </Subsection>
61
+ ))}
62
+ </>
63
+ );
64
+ };
@@ -0,0 +1,59 @@
1
+ import { VuiCopyButton, VuiFlexContainer, VuiFlexItem, VuiSpacer, VuiText, VuiTextColor } from "../../../lib";
2
+
3
+ type Props = {
4
+ // Friendly name for the color.
5
+ name: string;
6
+ // The CSS custom property exposed by the theme, e.g. "--vui-color-primary-shade".
7
+ cssVariable: string;
8
+ // The value resolved in the light theme, shown for reference.
9
+ value?: string;
10
+ };
11
+
12
+ // Renders a single theme color as a live swatch alongside its CSS variable and value.
13
+ // The swatch fills itself with var(cssVariable), so it always reflects the active theme.
14
+ export const Swatch = ({ name, cssVariable, value }: Props) => {
15
+ return (
16
+ <VuiFlexItem grow={false}>
17
+ <div style={{ width: 200 }}>
18
+ <div
19
+ style={{
20
+ height: 64,
21
+ borderRadius: 6,
22
+ backgroundColor: `var(${cssVariable})`,
23
+ border: "1px solid var(--vui-color-border-medium)"
24
+ }}
25
+ />
26
+
27
+ <VuiSpacer size="xs" />
28
+
29
+ <VuiText size="xs">
30
+ <p>
31
+ <strong>{name}</strong>
32
+ </p>
33
+ </VuiText>
34
+
35
+ <VuiFlexContainer alignItems="center" spacing="xs" justifyContent="spaceBetween">
36
+ <VuiFlexItem grow={false}>
37
+ <VuiText size="xs">
38
+ <p>
39
+ <code>{cssVariable}</code>
40
+ </p>
41
+ </VuiText>
42
+ </VuiFlexItem>
43
+
44
+ <VuiFlexItem grow={false}>
45
+ <VuiCopyButton size="xs" value={`var(${cssVariable})`} title={`Copy var(${cssVariable})`} />
46
+ </VuiFlexItem>
47
+ </VuiFlexContainer>
48
+
49
+ {value && (
50
+ <VuiText size="xs">
51
+ <p>
52
+ <VuiTextColor color="subdued">{value}</VuiTextColor>
53
+ </p>
54
+ </VuiText>
55
+ )}
56
+ </div>
57
+ </VuiFlexItem>
58
+ );
59
+ };
@@ -0,0 +1,37 @@
1
+ import { VuiFlexContainer } from "../../../lib";
2
+ import { Subsection } from "../../components/Subsection";
3
+ import { Swatch } from "./Swatch";
4
+
5
+ // Foreground colors for body copy and form labels.
6
+ const textSwatches = [
7
+ { name: "Text", cssVariable: "--vui-color-text", value: "#1c1d22" },
8
+ { name: "Label", cssVariable: "--vui-color-label", value: "#1c1d22" }
9
+ ];
10
+
11
+ // Border colors for dividers, inputs, and surfaces.
12
+ const borderSwatches = [
13
+ { name: "Border medium", cssVariable: "--vui-color-border-medium", value: "#cbd1de" },
14
+ { name: "Border light", cssVariable: "--vui-color-border-light", value: "#e3e4f3" }
15
+ ];
16
+
17
+ export const TextAndBorderColors = () => {
18
+ return (
19
+ <>
20
+ <Subsection title="Text">
21
+ <VuiFlexContainer spacing="l" wrap>
22
+ {textSwatches.map((swatch) => (
23
+ <Swatch key={swatch.cssVariable} {...swatch} />
24
+ ))}
25
+ </VuiFlexContainer>
26
+ </Subsection>
27
+
28
+ <Subsection title="Border">
29
+ <VuiFlexContainer spacing="l" wrap>
30
+ {borderSwatches.map((swatch) => (
31
+ <Swatch key={swatch.cssVariable} {...swatch} />
32
+ ))}
33
+ </VuiFlexContainer>
34
+ </Subsection>
35
+ </>
36
+ );
37
+ };
@@ -0,0 +1,72 @@
1
+ import { VuiSpacer, VuiText, VuiTitle } from "../../../lib";
2
+
3
+ // Demonstrates referencing theme colors from CSS, including the -rgb companion variables
4
+ // that let you compose translucent colors at any opacity.
5
+ export const Usage = () => {
6
+ return (
7
+ <>
8
+ <VuiText>
9
+ <p>
10
+ Every theme color is published as a CSS custom property prefixed with <code>--vui-color-</code>. Reference one
11
+ anywhere you write CSS with <code>var(...)</code>:
12
+ </p>
13
+ </VuiText>
14
+
15
+ <VuiSpacer size="s" />
16
+
17
+ <VuiText>
18
+ <pre>
19
+ <code>{`.myElement {\n color: var(--vui-color-primary-shade);\n border: 1px solid var(--vui-color-border-medium);\n}`}</code>
20
+ </pre>
21
+ </VuiText>
22
+
23
+ <VuiSpacer size="m" />
24
+
25
+ <VuiText>
26
+ <p>
27
+ Each color also has an <code>-rgb</code> companion that holds just the{" "}
28
+ <code>r, g, b</code> channels. Pair it with <code>rgba()</code> to build a translucent color at any opacity:
29
+ </p>
30
+ </VuiText>
31
+
32
+ <VuiSpacer size="s" />
33
+
34
+ <VuiText>
35
+ <pre>
36
+ <code>{`.myElement {\n background-color: rgba(var(--vui-color-primary-shade-rgb), 0.08);\n}`}</code>
37
+ </pre>
38
+ </VuiText>
39
+
40
+ <VuiSpacer size="m" />
41
+
42
+ <VuiTitle size="xs">
43
+ <h4>Live example</h4>
44
+ </VuiTitle>
45
+
46
+ <VuiSpacer size="s" />
47
+
48
+ <div
49
+ style={{
50
+ padding: 16,
51
+ borderRadius: 8,
52
+ color: "var(--vui-color-primary-shade)",
53
+ backgroundColor: "rgba(var(--vui-color-primary-shade-rgb), 0.08)",
54
+ border: "1px solid var(--vui-color-border-medium)"
55
+ }}
56
+ >
57
+ This panel's text, background, and border are all driven by theme color variables, so it adapts automatically
58
+ when the theme changes.
59
+ </div>
60
+
61
+ <VuiSpacer size="m" />
62
+
63
+ <VuiText>
64
+ <p>
65
+ To change these values, pass a <code>theme</code> to <code>VuiContextProvider</code> — see the Theme page. The
66
+ neutral, text, and border colors invert between the light and dark themes, so prefer the semantic name (for
67
+ example <code>--vui-color-empty-shade</code>) over a literal lightness.
68
+ </p>
69
+ </VuiText>
70
+ </>
71
+ );
72
+ };
@@ -0,0 +1,50 @@
1
+ import { Usage } from "./Usage";
2
+ import { SemanticColors } from "./SemanticColors";
3
+ import { CategoricalColors } from "./CategoricalColors";
4
+ import { ChartColors } from "./ChartColors";
5
+ import { NeutralColors } from "./NeutralColors";
6
+ import { TextAndBorderColors } from "./TextAndBorderColors";
7
+
8
+ const UsageSource = require("!!raw-loader!./Usage");
9
+ const SemanticColorsSource = require("!!raw-loader!./SemanticColors");
10
+ const CategoricalColorsSource = require("!!raw-loader!./CategoricalColors");
11
+ const ChartColorsSource = require("!!raw-loader!./ChartColors");
12
+ const NeutralColorsSource = require("!!raw-loader!./NeutralColors");
13
+ const TextAndBorderColorsSource = require("!!raw-loader!./TextAndBorderColors");
14
+
15
+ export const colorPalette = {
16
+ name: "Color palette",
17
+ path: "/colorPalette",
18
+ examples: [
19
+ {
20
+ name: "Using color variables",
21
+ component: <Usage />,
22
+ source: UsageSource.default.toString()
23
+ },
24
+ {
25
+ name: "Semantic colors",
26
+ component: <SemanticColors />,
27
+ source: SemanticColorsSource.default.toString()
28
+ },
29
+ {
30
+ name: "Categorical colors",
31
+ component: <CategoricalColors />,
32
+ source: CategoricalColorsSource.default.toString()
33
+ },
34
+ {
35
+ name: "Chart colors",
36
+ component: <ChartColors />,
37
+ source: ChartColorsSource.default.toString()
38
+ },
39
+ {
40
+ name: "Neutral and special colors",
41
+ component: <NeutralColors />,
42
+ source: NeutralColorsSource.default.toString()
43
+ },
44
+ {
45
+ name: "Text and border colors",
46
+ component: <TextAndBorderColors />,
47
+ source: TextAndBorderColorsSource.default.toString()
48
+ }
49
+ ]
50
+ };
@@ -0,0 +1,25 @@
1
+ import { VuiComposedChart } from "../../../lib";
2
+
3
+ // Query volume (bars, left axis) overlaid with p95 latency (line, right axis) — two metrics on
4
+ // different scales sharing one chart.
5
+ const data = [
6
+ { month: "Jan", queries: 4200, latency: 180 },
7
+ { month: "Feb", queries: 5100, latency: 172 },
8
+ { month: "Mar", queries: 6800, latency: 165 },
9
+ { month: "Apr", queries: 7400, latency: 158 },
10
+ { month: "May", queries: 8200, latency: 150 },
11
+ { month: "Jun", queries: 9100, latency: 142 }
12
+ ];
13
+
14
+ export const Basic = () => {
15
+ return (
16
+ <VuiComposedChart
17
+ data={data}
18
+ categoryKey="month"
19
+ series={[
20
+ { dataKey: "queries", name: "Queries", type: "bar", axis: "left" },
21
+ { dataKey: "latency", name: "p95 latency (ms)", type: "line", axis: "right", curved: true }
22
+ ]}
23
+ />
24
+ );
25
+ };
@@ -0,0 +1,15 @@
1
+ import { Basic } from "./Basic";
2
+
3
+ const BasicSource = require("!!raw-loader!./Basic");
4
+
5
+ export const composedChart = {
6
+ name: "Composed chart",
7
+ path: "/composed-chart",
8
+ examples: [
9
+ {
10
+ name: "Basic",
11
+ component: <Basic />,
12
+ source: BasicSource.default.toString()
13
+ }
14
+ ]
15
+ };
@@ -0,0 +1,130 @@
1
+ import { useState } from "react";
2
+ import {
3
+ VuiButtonTertiary,
4
+ VuiComposer,
5
+ ComposerSubmission,
6
+ VuiFlexContainer,
7
+ VuiFlexItem,
8
+ VuiIcon,
9
+ VuiIconButton,
10
+ VuiSpacer,
11
+ VuiText,
12
+ VuiTextColor
13
+ } from "../../../lib";
14
+ import { BiBulb, BiError } from "react-icons/bi";
15
+
16
+ const MAX_FILE_SIZE_BYTES = 5 * 1024 * 1024;
17
+
18
+ type SentMessage = {
19
+ text: string;
20
+ fileNames: string[];
21
+ };
22
+
23
+ export const Composer = () => {
24
+ const [messages, setMessages] = useState<SentMessage[]>([]);
25
+ const [isRunning, setIsRunning] = useState(false);
26
+ const [rejectedFiles, setRejectedFiles] = useState<string[]>([]);
27
+ const [skillCount, setSkillCount] = useState(0);
28
+
29
+ const handleSubmit = ({ text, files }: ComposerSubmission) => {
30
+ setMessages((prev) => [...prev, { text, fileNames: files.map((file) => file.name) }]);
31
+ setRejectedFiles([]);
32
+
33
+ // Simulate a streaming response so the Send button toggles to Cancel.
34
+ setIsRunning(true);
35
+ window.setTimeout(() => setIsRunning(false), 2000);
36
+ };
37
+
38
+ return (
39
+ <>
40
+ {messages.length > 0 && (
41
+ <>
42
+ {messages.map((message, index) => (
43
+ <div key={index}>
44
+ <VuiText>
45
+ <p>{message.text || <VuiTextColor color="subdued">(no text)</VuiTextColor>}</p>
46
+ </VuiText>
47
+ {message.fileNames.length > 0 && (
48
+ <VuiText size="s">
49
+ <p>
50
+ <VuiTextColor color="subdued">Attached: {message.fileNames.join(", ")}</VuiTextColor>
51
+ </p>
52
+ </VuiText>
53
+ )}
54
+ <VuiSpacer size="xs" />
55
+ </div>
56
+ ))}
57
+ <VuiSpacer size="m" />
58
+ </>
59
+ )}
60
+
61
+ <VuiComposer
62
+ placeholder="Ask a question, attach files, or press / for skills"
63
+ isRunning={isRunning}
64
+ onCancel={() => setIsRunning(false)}
65
+ onSubmit={handleSubmit}
66
+ enableHistory
67
+ historyKey="vuiComposerDocs:history"
68
+ canUploadFiles
69
+ validateFile={(file) => (file.size > MAX_FILE_SIZE_BYTES ? "File exceeds 5 MB" : null)}
70
+ onFilesRejected={(errors) => setRejectedFiles(errors.map((error) => error.file.name))}
71
+ onShortcutKeys={{
72
+ "/": (event, { value }) => {
73
+ // Open the skill picker only when the composer is empty.
74
+ if (value === "") {
75
+ event.preventDefault();
76
+ setSkillCount((count) => count + 1);
77
+ }
78
+ }
79
+ }}
80
+ leadingActions={
81
+ <VuiFlexItem>
82
+ <VuiFlexContainer alignItems="center" spacing="xxs">
83
+ <VuiIconButton
84
+ color="neutral"
85
+ aria-label="Select skill"
86
+ onClick={() => setSkillCount((count) => count + 1)}
87
+ icon={
88
+ <VuiIcon>
89
+ <BiBulb />
90
+ </VuiIcon>
91
+ }
92
+ />
93
+ {skillCount > 0 && (
94
+ <VuiText size="s">
95
+ <VuiTextColor color="subdued">({skillCount})</VuiTextColor>
96
+ </VuiText>
97
+ )}
98
+ </VuiFlexContainer>
99
+ </VuiFlexItem>
100
+ }
101
+ footer={
102
+ rejectedFiles.length > 0 ? (
103
+ <>
104
+ <VuiSpacer size="s" />
105
+ <VuiFlexContainer alignItems="center" spacing="xs">
106
+ <VuiFlexItem>
107
+ <VuiIcon size="s" color="danger">
108
+ <BiError />
109
+ </VuiIcon>
110
+ </VuiFlexItem>
111
+ <VuiFlexItem>
112
+ <VuiText size="s">
113
+ <p>
114
+ <VuiTextColor color="subdued">Could not attach: {rejectedFiles.join(", ")}</VuiTextColor>
115
+ </p>
116
+ </VuiText>
117
+ </VuiFlexItem>
118
+ <VuiFlexItem>
119
+ <VuiButtonTertiary noPadding color="primary" size="s" onClick={() => setRejectedFiles([])}>
120
+ Dismiss
121
+ </VuiButtonTertiary>
122
+ </VuiFlexItem>
123
+ </VuiFlexContainer>
124
+ </>
125
+ ) : undefined
126
+ }
127
+ />
128
+ </>
129
+ );
130
+ };
@@ -0,0 +1,11 @@
1
+ import { Composer } from "./Composer";
2
+ const ComposerSource = require("!!raw-loader!./Composer");
3
+
4
+ export const composer = {
5
+ name: "Composer",
6
+ path: "/composer",
7
+ example: {
8
+ component: <Composer />,
9
+ source: ComposerSource.default.toString()
10
+ }
11
+ };