@vectara/vectara-ui 18.2.3 → 18.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.
@@ -0,0 +1,2 @@
1
+ import { FormGroupProps } from "./types";
2
+ export declare const VuiBlockFormGroup: ({ label, labelRightContent, labelFor, labelSize, isRequired, helpText, ariaDescribedByLabel, errorMessages, content }: FormGroupProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,9 @@
1
+ import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { VuiLabel } from "../form/label/Label";
3
+ import { VuiSpacer } from "../spacer/Spacer";
4
+ import { VuiText } from "../typography/Text";
5
+ import { VuiTextColor } from "../typography/TextColor";
6
+ import { VuiFlexContainer } from "../flex/FlexContainer";
7
+ export const VuiBlockFormGroup = ({ label, labelRightContent, labelFor, labelSize, isRequired, helpText, ariaDescribedByLabel, errorMessages, content }) => {
8
+ return (_jsxs("div", { children: [(label || labelRightContent) && (_jsxs(_Fragment, { children: [_jsxs(VuiFlexContainer, Object.assign({ justifyContent: "spaceBetween", alignItems: "center", spacing: "s" }, { children: [label ? (_jsxs(VuiLabel, Object.assign({ labelFor: labelFor, size: labelSize }, { children: [label, isRequired && " (required)"] }))) : (_jsx("span", {})), labelRightContent] })), _jsx(VuiSpacer, { size: labelSize === "s" ? "xs" : "xxs" })] })), helpText && (_jsxs(_Fragment, { children: [_jsx(VuiText, Object.assign({ size: "xs", id: ariaDescribedByLabel }, { children: _jsx("p", { children: _jsx(VuiTextColor, Object.assign({ color: "subdued" }, { children: helpText })) }) })), _jsx(VuiSpacer, { size: "xs" })] })), errorMessages && (_jsxs(_Fragment, { children: [errorMessages, _jsx(VuiSpacer, { size: "xs" })] })), content] }));
9
+ };
@@ -7,6 +7,7 @@ type Props = {
7
7
  helpText?: React.ReactNode;
8
8
  errors?: string[];
9
9
  isRequired?: boolean;
10
+ inline?: boolean;
10
11
  };
11
- export declare const VuiFormGroup: ({ children, labelFor, helpText, label, labelSize, labelRightContent, errors, isRequired }: Props) => import("react/jsx-runtime").JSX.Element;
12
+ export declare const VuiFormGroup: ({ children, labelFor, helpText, label, labelSize, labelRightContent, errors, isRequired, inline }: Props) => import("react/jsx-runtime").JSX.Element;
12
13
  export {};
@@ -1,6 +1,5 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { cloneElement } from "react";
3
- import { VuiLabel } from "../form/label/Label";
4
3
  import { VuiSpacer } from "../spacer/Spacer";
5
4
  import { VuiText } from "../typography/Text";
6
5
  import { VuiTextColor } from "../typography/TextColor";
@@ -9,9 +8,10 @@ import { VuiTextInput } from "../form/input/TextInput";
9
8
  import { VuiNumberInput } from "../form/input/NumberInput";
10
9
  import { VuiTextArea } from "../form/textArea/TextArea";
11
10
  import { VuiSelect } from "../form/select/Select";
12
- import { VuiFlexContainer } from "../flex/FlexContainer";
11
+ import { VuiInlineFormGroup } from "./InlineFormGroup";
12
+ import { VuiBlockFormGroup } from "./BlockFormGroup";
13
13
  const VALIDATION_ALLOWLIST = [VuiTextInput, VuiNumberInput, VuiTextArea, VuiSelect];
14
- export const VuiFormGroup = ({ children, labelFor, helpText, label, labelSize = "s", labelRightContent, errors, isRequired }) => {
14
+ export const VuiFormGroup = ({ children, labelFor, helpText, label, labelSize = "s", labelRightContent, errors, isRequired, inline }) => {
15
15
  const ariaProps = {
16
16
  "aria-describedby": ""
17
17
  };
@@ -20,7 +20,7 @@ export const VuiFormGroup = ({ children, labelFor, helpText, label, labelSize =
20
20
  const errorMessages = errors === null || errors === void 0 ? void 0 : errors.map((error, index) => {
21
21
  const id = `error-${createId()}`;
22
22
  errorMessageIds.push(id);
23
- return (_jsxs("div", { children: [index > 0 && _jsx(VuiSpacer, { size: "xs" }), _jsx(VuiText, Object.assign({ size: "xs", id: id }, { children: _jsx("p", { children: _jsx(VuiTextColor, Object.assign({ color: "danger" }, { children: error })) }) }), error)] }, error));
23
+ return (_jsxs("div", { children: [index > 0 && _jsx(VuiSpacer, { size: "xs" }), _jsx(VuiText, Object.assign({ size: "xs", id: id }, { children: _jsx("p", { children: _jsx(VuiTextColor, Object.assign({ color: inline ? "empty" : "danger" }, { children: error })) }) }), error)] }, error));
24
24
  });
25
25
  if (helpText) {
26
26
  ariaProps["aria-describedby"] += ariaDescribedByLabel;
@@ -34,5 +34,19 @@ export const VuiFormGroup = ({ children, labelFor, helpText, label, labelSize =
34
34
  cloneProps.isInvalid = errors && errors.length > 0;
35
35
  }
36
36
  const content = cloneElement(children, cloneProps);
37
- return (_jsxs("div", { children: [(label || labelRightContent) && (_jsxs(_Fragment, { children: [_jsxs(VuiFlexContainer, Object.assign({ justifyContent: "spaceBetween", alignItems: "center", spacing: "s" }, { children: [label ? (_jsxs(VuiLabel, Object.assign({ labelFor: labelFor, size: labelSize }, { children: [label, isRequired && " (required)"] }))) : (_jsx("span", {})), labelRightContent] })), _jsx(VuiSpacer, { size: labelSize === "s" ? "xs" : "xxs" })] })), helpText && (_jsxs(_Fragment, { children: [_jsx(VuiText, Object.assign({ size: "xs", id: ariaDescribedByLabel }, { children: _jsx("p", { children: _jsx(VuiTextColor, Object.assign({ color: "subdued" }, { children: helpText })) }) })), _jsx(VuiSpacer, { size: "xs" })] })), errorMessages && (_jsxs(_Fragment, { children: [errorMessages, _jsx(VuiSpacer, { size: "xs" })] })), content] }));
37
+ const props = {
38
+ label,
39
+ labelRightContent,
40
+ labelFor,
41
+ labelSize,
42
+ isRequired,
43
+ helpText,
44
+ ariaDescribedByLabel,
45
+ errorMessages,
46
+ content
47
+ };
48
+ if (inline) {
49
+ return _jsx(VuiInlineFormGroup, Object.assign({}, props));
50
+ }
51
+ return _jsx(VuiBlockFormGroup, Object.assign({}, props));
38
52
  };
@@ -0,0 +1,2 @@
1
+ import { FormGroupProps } from "./types";
2
+ export declare const VuiInlineFormGroup: ({ label, labelRightContent, labelFor, labelSize, isRequired, helpText, ariaDescribedByLabel, errorMessages, content }: FormGroupProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,14 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { VuiLabel } from "../form/label/Label";
3
+ import { VuiFlexContainer } from "../flex/FlexContainer";
4
+ import { VuiInfoTooltip } from "../tooltip/InfoTooltip";
5
+ import { BiError } from "react-icons/bi";
6
+ import classNames from "classnames";
7
+ import { VuiTextColor } from "../typography/TextColor";
8
+ export const VuiInlineFormGroup = ({ label, labelRightContent, labelFor, labelSize, isRequired, helpText, ariaDescribedByLabel, errorMessages, content }) => {
9
+ const hasErrors = errorMessages && errorMessages.length > 0;
10
+ const classes = classNames("vuiInlineFormGroup", {
11
+ "vuiInlineFormGroup-hasError": hasErrors
12
+ });
13
+ return (_jsxs(VuiFlexContainer, Object.assign({ className: classes, spacing: "none", alignItems: "stretch" }, { children: [(label || labelRightContent) && (_jsxs(VuiFlexContainer, Object.assign({ justifyContent: "spaceBetween", className: "vuiInlineFormGroup__label", alignItems: "center", spacing: "xs" }, { children: [label ? (_jsx(VuiLabel, Object.assign({ labelFor: labelFor, size: labelSize }, { children: _jsxs(VuiTextColor, Object.assign({ color: "subdued" }, { children: [label, isRequired && " (required)"] })) }))) : (_jsx("span", {})), labelRightContent, helpText && _jsx(VuiInfoTooltip, { tip: helpText, id: ariaDescribedByLabel }), hasErrors && _jsx(VuiInfoTooltip, { color: "danger", icon: _jsx(BiError, {}), tip: errorMessages })] }))), content] })));
14
+ };
@@ -0,0 +1,25 @@
1
+ .vuiInlineFormGroup {
2
+ select,
3
+ input,
4
+ textarea {
5
+ border-top-left-radius: 0;
6
+ border-bottom-left-radius: 0;
7
+ border-left: none;
8
+ }
9
+ }
10
+
11
+ .vuiInlineFormGroup__label {
12
+ border-top-left-radius: $sizeXxs;
13
+ border-bottom-left-radius: $sizeXxs;
14
+ background-color: var(--vui-color-light-shade);
15
+ padding: 0 $sizeS;
16
+ border: 1px solid var(--vui-color-medium-shade);
17
+ }
18
+
19
+ .vuiInlineFormGroup-hasError {
20
+ .vuiInlineFormGroup__label {
21
+ border-top-color: var(--vui-color-danger-shade);
22
+ border-left-color: var(--vui-color-danger-shade);
23
+ border-bottom-color: var(--vui-color-danger-shade);
24
+ }
25
+ }
@@ -0,0 +1,11 @@
1
+ export type FormGroupProps = {
2
+ label?: string;
3
+ labelRightContent: React.ReactNode;
4
+ labelFor?: string;
5
+ labelSize: "s" | "xs";
6
+ isRequired?: boolean;
7
+ helpText: React.ReactNode;
8
+ ariaDescribedByLabel: string;
9
+ errorMessages?: JSX.Element[];
10
+ content: React.ReactElement<any, string | React.JSXElementConstructor<any>>;
11
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,4 +1,7 @@
1
1
  import { Props as TooltipProps } from "./Tooltip";
2
- type Props = Omit<TooltipProps, "children">;
2
+ type Props = Omit<TooltipProps, "children"> & {
3
+ color?: "danger" | "warning" | "success" | "subdued";
4
+ icon?: React.ReactNode;
5
+ };
3
6
  export declare const VuiInfoTooltip: (props: Props) => import("react/jsx-runtime").JSX.Element;
4
7
  export {};
@@ -1,7 +1,19 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
1
12
  import { jsx as _jsx } from "react/jsx-runtime";
2
13
  import { BiHelpCircle } from "react-icons/bi";
3
14
  import { VuiIcon } from "../icon/Icon";
4
15
  import { VuiTooltip } from "./Tooltip";
5
16
  export const VuiInfoTooltip = (props) => {
6
- return (_jsx(VuiTooltip, Object.assign({}, props, { children: _jsx(VuiIcon, Object.assign({ color: "subdued", size: "s" }, { children: _jsx(BiHelpCircle, {}) })) })));
17
+ const { icon, color = "subdued" } = props, rest = __rest(props, ["icon", "color"]);
18
+ return (_jsx(VuiTooltip, Object.assign({}, rest, { children: _jsx(VuiIcon, Object.assign({ color: color, size: "s" }, { children: icon ? icon : _jsx(BiHelpCircle, {}) })) })));
7
19
  };
@@ -5,5 +5,6 @@ export type Props = {
5
5
  darkTheme?: boolean;
6
6
  position?: TooltipRefProps["place"];
7
7
  usePortal?: boolean;
8
+ id?: string;
8
9
  };
9
- export declare const VuiTooltip: ({ children, darkTheme, position, tip, usePortal }: Props) => import("react/jsx-runtime").JSX.Element;
10
+ export declare const VuiTooltip: ({ children, darkTheme, position, tip, usePortal, ...rest }: Props) => import("react/jsx-runtime").JSX.Element;
@@ -1,8 +1,21 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
1
12
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
13
  import { useState, cloneElement } from "react";
3
14
  import { Tooltip } from "react-tooltip";
4
15
  import { useVuiContext } from "../context/Context";
5
16
  import { VuiPortal } from "../portal/Portal";
17
+ import { VuiText } from "../typography/Text";
18
+ import { VuiTextColor } from "../typography/TextColor";
6
19
  const generateTooltipId = () => {
7
20
  return `tooltip-${Math.random().toString(36).slice(2, 9)}`;
8
21
  };
@@ -26,15 +39,17 @@ const needsTabIndex = (element) => {
26
39
  }
27
40
  return true;
28
41
  };
29
- export const VuiTooltip = ({ children, darkTheme, position, tip, usePortal }) => {
42
+ export const VuiTooltip = (_a) => {
43
+ var { children, darkTheme, position, tip, usePortal } = _a, rest = __rest(_a, ["children", "darkTheme", "position", "tip", "usePortal"]);
30
44
  const { getThemeStyle } = useVuiContext();
31
- const [id] = useState(generateTooltipId());
32
- const target = cloneElement(children, Object.assign({ "data-tooltip-id": id }, (needsTabIndex(children) && { tabIndex: 0 })));
45
+ const [tooltipId] = useState(generateTooltipId());
46
+ const target = cloneElement(children, Object.assign(Object.assign({ "data-tooltip-id": tooltipId }, (needsTabIndex(children) && { tabIndex: 0 })), rest));
33
47
  // Tooltips can be used in a dark-themed component, so we need to explicitly set
34
48
  // the light theme class in order to enable having a different theme than the
35
49
  // parent.
36
50
  const style = getThemeStyle(darkTheme ? "dark" : "light");
37
- const tooltip = (_jsx(Tooltip, Object.assign({ id: id, offset: 10, className: "vuiTooltip", style: style, opacity: 1, place: position }, { children: tip })));
51
+ const content = typeof tip === "string" ? (_jsx(VuiText, Object.assign({ size: "xs" }, { children: _jsx("p", { children: _jsx(VuiTextColor, Object.assign({ color: "empty" }, { children: tip })) }) }))) : (tip);
52
+ const tooltip = (_jsx(Tooltip, Object.assign({ id: tooltipId, offset: 10, className: "vuiTooltip", style: style, opacity: 1, place: position }, { children: content })));
38
53
  return (_jsxs(_Fragment, { children: [target, usePortal ? _jsx(VuiPortal, { children: tooltip }) : tooltip] }));
39
54
  };
40
55
  // This is a workaround for the issue with ResizeObserver in ReactTooltip.
@@ -3051,6 +3051,28 @@ h2.react-datepicker__current-month {
3051
3051
  max-height: 12rem;
3052
3052
  }
3053
3053
 
3054
+ .vuiInlineFormGroup select,
3055
+ .vuiInlineFormGroup input,
3056
+ .vuiInlineFormGroup textarea {
3057
+ border-top-left-radius: 0;
3058
+ border-bottom-left-radius: 0;
3059
+ border-left: none;
3060
+ }
3061
+
3062
+ .vuiInlineFormGroup__label {
3063
+ border-top-left-radius: 4px;
3064
+ border-bottom-left-radius: 4px;
3065
+ background-color: var(--vui-color-light-shade);
3066
+ padding: 0 12px;
3067
+ border: 1px solid var(--vui-color-medium-shade);
3068
+ }
3069
+
3070
+ .vuiInlineFormGroup-hasError .vuiInlineFormGroup__label {
3071
+ border-top-color: var(--vui-color-danger-shade);
3072
+ border-left-color: var(--vui-color-danger-shade);
3073
+ border-bottom-color: var(--vui-color-danger-shade);
3074
+ }
3075
+
3054
3076
  .vuiGridContainer {
3055
3077
  container-type: inline-size;
3056
3078
  width: 100%;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vectara/vectara-ui",
3
- "version": "18.2.3",
3
+ "version": "18.3.0",
4
4
  "homepage": "./",
5
5
  "description": "Vectara's design system, codified as a React and Sass component library",
6
6
  "author": "Vectara",
@@ -6,13 +6,16 @@ import {
6
6
  VuiSpacer,
7
7
  VuiSuperRadioGroup,
8
8
  VuiTextArea,
9
- VuiTextInput
9
+ VuiTextInput,
10
+ VuiToggle
10
11
  } from "../../../lib";
11
12
  import { Subsection } from "../../components/Subsection";
12
13
 
13
14
  type Pizza = "pepperoni" | "mushrooms" | "jalapenos";
14
15
 
15
16
  export const FormGroup = () => {
17
+ const [inline, setInline] = useState(false);
18
+ const [showError, setShowError] = useState(false);
16
19
  const [group, setGroup] = useState<RadioButtonConfig<Pizza>[]>([
17
20
  {
18
21
  label: "Pepperoni",
@@ -45,11 +48,20 @@ export const FormGroup = () => {
45
48
 
46
49
  return (
47
50
  <>
51
+ <VuiToggle label="Show error message" onChange={(e) => setShowError(e.target.checked)} />
52
+
53
+ <VuiSpacer size="m" />
54
+ <VuiToggle label="Inline" onChange={(event) => setInline(event.target.checked)} checked={inline} />
55
+
56
+ <VuiSpacer size="m" />
57
+
48
58
  <Subsection title="With help text">
49
59
  <VuiFormGroup
50
60
  label="Choose an option"
51
61
  labelFor="optionsList1"
52
62
  helpText="Some helpful information about this input."
63
+ inline={inline}
64
+ errors={showError ? ["This is an error message."] : []}
53
65
  >
54
66
  <VuiSelect
55
67
  id="optionsList1"
@@ -61,25 +73,48 @@ export const FormGroup = () => {
61
73
 
62
74
  <VuiSpacer size="m" />
63
75
 
64
- <VuiFormGroup label="Enter input" labelFor="input1" helpText="Some helpful information about this input.">
76
+ <VuiFormGroup
77
+ label="Enter input"
78
+ labelFor="input1"
79
+ helpText="Some helpful information about this input."
80
+ inline={inline}
81
+ errors={showError ? ["This is an error message."] : []}
82
+ >
65
83
  <VuiTextInput id="input1" value="Text input" onChange={(event) => console.log(event.target.value)} />
66
84
  </VuiFormGroup>
67
85
 
68
86
  <VuiSpacer size="m" />
69
87
 
70
- <VuiFormGroup label="Select option" labelFor="superRadioGroup" helpText="Choose wisely.">
88
+ <VuiFormGroup
89
+ label="Select option"
90
+ labelFor="superRadioGroup"
91
+ helpText="Choose wisely."
92
+ inline={inline}
93
+ errors={showError ? ["This is an error message."] : []}
94
+ >
71
95
  <VuiSuperRadioGroup groupName="superRadioGroup" group={group} onChange={onChange} />
72
96
  </VuiFormGroup>
73
97
 
74
98
  <VuiSpacer size="m" />
75
99
 
76
- <VuiFormGroup label="Enter text" labelFor="textArea" helpText="Enter some text here.">
100
+ <VuiFormGroup
101
+ label="Enter text"
102
+ labelFor="textArea"
103
+ helpText="Enter some text here."
104
+ inline={inline}
105
+ errors={showError ? ["This is an error message."] : []}
106
+ >
77
107
  <VuiTextArea id="textArea" value="Text area" onChange={() => undefined} />
78
108
  </VuiFormGroup>
79
109
  </Subsection>
80
110
 
81
111
  <Subsection title="Without help text">
82
- <VuiFormGroup label="Choose an option" labelFor="optionsList2">
112
+ <VuiFormGroup
113
+ label="Choose an option"
114
+ labelFor="optionsList2"
115
+ inline={inline}
116
+ errors={showError ? ["This is an error message."] : []}
117
+ >
83
118
  <VuiSelect
84
119
  id="optionsList2"
85
120
  options={[{ text: "Option A", value: "a" }]}