@vectara/vectara-ui 16.6.0 → 16.8.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/lib/components/form/textArea/TextArea.d.ts +1 -0
- package/lib/components/form/textArea/TextArea.js +29 -4
- package/lib/components/form/textArea/_index.scss +6 -0
- package/lib/components/formGroup/FormGroup.d.ts +2 -1
- package/lib/components/formGroup/FormGroup.js +3 -2
- package/lib/styles/index.css +6 -0
- package/package.json +1 -1
- package/src/docs/pages/formGroup/LabelRightContent.tsx +35 -0
- package/src/docs/pages/formGroup/index.tsx +7 -0
- package/src/docs/pages/textArea/TextAreaAutoGrow.tsx +18 -0
- package/src/docs/pages/textArea/index.tsx +7 -0
|
@@ -2,6 +2,7 @@ type Props = React.DetailedHTMLProps<React.TextareaHTMLAttributes<HTMLTextAreaEl
|
|
|
2
2
|
fullWidth?: boolean;
|
|
3
3
|
isInvalid?: boolean;
|
|
4
4
|
resizable?: boolean;
|
|
5
|
+
autoGrow?: boolean;
|
|
5
6
|
};
|
|
6
7
|
export declare const VuiTextArea: import("react").ForwardRefExoticComponent<Omit<Props, "ref"> & import("react").RefAttributes<HTMLTextAreaElement | null>>;
|
|
7
8
|
export {};
|
|
@@ -10,14 +10,39 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
12
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
13
|
-
import { forwardRef } from "react";
|
|
13
|
+
import { forwardRef, useLayoutEffect, useRef } from "react";
|
|
14
14
|
import classNames from "classnames";
|
|
15
15
|
export const VuiTextArea = forwardRef((_a, ref) => {
|
|
16
|
-
var { className, fullWidth, isInvalid, resizable } = _a, rest = __rest(_a, ["className", "fullWidth", "isInvalid", "resizable"]);
|
|
16
|
+
var { className, fullWidth, isInvalid, resizable, autoGrow } = _a, rest = __rest(_a, ["className", "fullWidth", "isInvalid", "resizable", "autoGrow"]);
|
|
17
17
|
const classes = classNames("vuiTextArea", {
|
|
18
18
|
"vuiTextArea-isInvalid": isInvalid,
|
|
19
|
-
"vuiTextArea--fullWidth": fullWidth
|
|
19
|
+
"vuiTextArea--fullWidth": fullWidth,
|
|
20
|
+
"vuiTextArea--autoGrow": autoGrow
|
|
20
21
|
}, className);
|
|
21
22
|
const style = Object.assign(Object.assign({}, rest.style), { resize: resizable ? "vertical" : "none" });
|
|
22
|
-
|
|
23
|
+
const internalRef = useRef(null);
|
|
24
|
+
const setRefs = (el) => {
|
|
25
|
+
internalRef.current = el;
|
|
26
|
+
if (typeof ref === "function")
|
|
27
|
+
ref(el);
|
|
28
|
+
else if (ref)
|
|
29
|
+
ref.current = el;
|
|
30
|
+
};
|
|
31
|
+
// Auto-grow the textarea to fit its content. Reset to "auto" first so
|
|
32
|
+
// scrollHeight reflects the natural height after deletions, not the
|
|
33
|
+
// previously-set inline height.
|
|
34
|
+
useLayoutEffect(() => {
|
|
35
|
+
if (!autoGrow)
|
|
36
|
+
return;
|
|
37
|
+
const el = internalRef.current;
|
|
38
|
+
if (!el)
|
|
39
|
+
return;
|
|
40
|
+
el.style.height = "auto";
|
|
41
|
+
// scrollHeight excludes borders, but with box-sizing: border-box the
|
|
42
|
+
// assigned height includes them — without this offset the content would
|
|
43
|
+
// overflow by the border width and show a spurious scrollbar.
|
|
44
|
+
const borderY = el.offsetHeight - el.clientHeight;
|
|
45
|
+
el.style.height = `${el.scrollHeight + borderY}px`;
|
|
46
|
+
}, [autoGrow, rest.value]);
|
|
47
|
+
return _jsx("textarea", Object.assign({}, rest, { ref: setRefs, className: classes, style: style }));
|
|
23
48
|
});
|
|
@@ -2,10 +2,11 @@ type Props = {
|
|
|
2
2
|
labelFor?: string;
|
|
3
3
|
label?: string;
|
|
4
4
|
labelSize?: "s" | "xs";
|
|
5
|
+
labelRightContent?: React.ReactNode;
|
|
5
6
|
children: React.ReactElement;
|
|
6
7
|
helpText?: React.ReactNode;
|
|
7
8
|
errors?: string[];
|
|
8
9
|
isRequired?: boolean;
|
|
9
10
|
};
|
|
10
|
-
export declare const VuiFormGroup: ({ children, labelFor, helpText, label, labelSize, errors, isRequired }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export declare const VuiFormGroup: ({ children, labelFor, helpText, label, labelSize, labelRightContent, errors, isRequired }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
11
12
|
export {};
|
|
@@ -9,8 +9,9 @@ import { VuiTextInput } from "../form/input/TextInput";
|
|
|
9
9
|
import { VuiNumberInput } from "../form/input/NumberInput";
|
|
10
10
|
import { VuiTextArea } from "../form/textArea/TextArea";
|
|
11
11
|
import { VuiSelect } from "../form/select/Select";
|
|
12
|
+
import { VuiFlexContainer } from "../flex/FlexContainer";
|
|
12
13
|
const VALIDATION_ALLOWLIST = [VuiTextInput, VuiNumberInput, VuiTextArea, VuiSelect];
|
|
13
|
-
export const VuiFormGroup = ({ children, labelFor, helpText, label, labelSize = "s", errors, isRequired }) => {
|
|
14
|
+
export const VuiFormGroup = ({ children, labelFor, helpText, label, labelSize = "s", labelRightContent, errors, isRequired }) => {
|
|
14
15
|
const ariaProps = {
|
|
15
16
|
"aria-describedby": ""
|
|
16
17
|
};
|
|
@@ -33,5 +34,5 @@ export const VuiFormGroup = ({ children, labelFor, helpText, label, labelSize =
|
|
|
33
34
|
cloneProps.isInvalid = errors && errors.length > 0;
|
|
34
35
|
}
|
|
35
36
|
const content = cloneElement(children, cloneProps);
|
|
36
|
-
return (_jsxs("div", { children: [label && (_jsxs(_Fragment, { children: [_jsxs(VuiLabel, Object.assign({ labelFor: labelFor, size: labelSize }, { children: [label, isRequired && " (required)"] })), _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
|
+
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
38
|
};
|
package/lib/styles/index.css
CHANGED
|
@@ -3007,6 +3007,12 @@ h2.react-datepicker__current-month {
|
|
|
3007
3007
|
width: 100%;
|
|
3008
3008
|
}
|
|
3009
3009
|
|
|
3010
|
+
.vuiTextArea--autoGrow {
|
|
3011
|
+
min-height: 0;
|
|
3012
|
+
line-height: 1.6;
|
|
3013
|
+
max-height: 12rem;
|
|
3014
|
+
}
|
|
3015
|
+
|
|
3010
3016
|
.vuiGridContainer {
|
|
3011
3017
|
container-type: inline-size;
|
|
3012
3018
|
width: 100%;
|
package/package.json
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { VuiFormGroup, VuiSelect, VuiTextInput } from "../../../lib";
|
|
3
|
+
|
|
4
|
+
type limitMode = "static" | "dynamic" | "agent" | "disabled";
|
|
5
|
+
|
|
6
|
+
const limitModeOptions = [
|
|
7
|
+
{ text: "Statically defined", value: "static" as const },
|
|
8
|
+
{ text: "Dynamically defined", value: "dynamic" as const },
|
|
9
|
+
{ text: "Agent defined", value: "agent" as const },
|
|
10
|
+
{ text: "Disabled", value: "disabled" as const }
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
export const LabelRightContent = () => {
|
|
14
|
+
const [limitMode, setlimitMode] = useState<limitMode>("static");
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<div>
|
|
18
|
+
<VuiFormGroup
|
|
19
|
+
label="Limit"
|
|
20
|
+
labelFor="limitInput"
|
|
21
|
+
helpText="Maximum number of results to return Default: 10"
|
|
22
|
+
labelRightContent={
|
|
23
|
+
<VuiSelect
|
|
24
|
+
size="s"
|
|
25
|
+
options={limitModeOptions}
|
|
26
|
+
value={limitMode}
|
|
27
|
+
onChange={(event) => setlimitMode(event.target.value as limitMode)}
|
|
28
|
+
/>
|
|
29
|
+
}
|
|
30
|
+
>
|
|
31
|
+
<VuiTextInput id="limitInput" value="5" onChange={() => undefined} />
|
|
32
|
+
</VuiFormGroup>
|
|
33
|
+
</div>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
@@ -2,11 +2,13 @@ import { FormGroup } from "./FormGroup";
|
|
|
2
2
|
import { NonFormElement } from "./NonFormElement";
|
|
3
3
|
import { NoLabel } from "./NoLabel";
|
|
4
4
|
import { Size } from "./Size";
|
|
5
|
+
import { LabelRightContent } from "./LabelRightContent";
|
|
5
6
|
|
|
6
7
|
const FormGroupSource = require("!!raw-loader!./FormGroup");
|
|
7
8
|
const NonFormElementSource = require("!!raw-loader!./NonFormElement");
|
|
8
9
|
const NoLabelSource = require("!!raw-loader!./NoLabel");
|
|
9
10
|
const SizeSource = require("!!raw-loader!./Size");
|
|
11
|
+
const LabelRightContentSource = require("!!raw-loader!./LabelRightContent");
|
|
10
12
|
|
|
11
13
|
export const formGroup = {
|
|
12
14
|
name: "Form Group",
|
|
@@ -31,6 +33,11 @@ export const formGroup = {
|
|
|
31
33
|
name: "Label size",
|
|
32
34
|
component: <Size />,
|
|
33
35
|
source: SizeSource.default.toString()
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: "With label right aligned content",
|
|
39
|
+
component: <LabelRightContent />,
|
|
40
|
+
source: LabelRightContentSource.default.toString()
|
|
34
41
|
}
|
|
35
42
|
]
|
|
36
43
|
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { VuiTextArea } from "../../../lib";
|
|
3
|
+
|
|
4
|
+
export const TextAreaAutoGrow = () => {
|
|
5
|
+
const [value, setValue] = useState<string | undefined>();
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<VuiTextArea
|
|
9
|
+
id="autoGrowTextArea"
|
|
10
|
+
value={value}
|
|
11
|
+
onChange={(event) => setValue(event.target.value)}
|
|
12
|
+
autoGrow
|
|
13
|
+
rows={1}
|
|
14
|
+
fullWidth
|
|
15
|
+
placeholder="Type a few lines — the textarea grows to fit its content"
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { TextArea } from "./TextArea";
|
|
2
2
|
import { TextAreaResizeable } from "./TextAreaResizeable";
|
|
3
|
+
import { TextAreaAutoGrow } from "./TextAreaAutoGrow";
|
|
3
4
|
|
|
4
5
|
const TextAreaSource = require("!!raw-loader!./TextArea");
|
|
5
6
|
const TextAreaResizeableSource = require("!!raw-loader!./TextAreaResizeable");
|
|
7
|
+
const TextAreaAutoGrowSource = require("!!raw-loader!./TextAreaAutoGrow");
|
|
6
8
|
|
|
7
9
|
export const textArea = {
|
|
8
10
|
name: "Text Area",
|
|
@@ -17,6 +19,11 @@ export const textArea = {
|
|
|
17
19
|
name: "Resizable Text Area",
|
|
18
20
|
component: <TextAreaResizeable />,
|
|
19
21
|
source: TextAreaResizeableSource.default.toString()
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: "Auto-Grow Text Area",
|
|
25
|
+
component: <TextAreaAutoGrow />,
|
|
26
|
+
source: TextAreaAutoGrowSource.default.toString()
|
|
20
27
|
}
|
|
21
28
|
]
|
|
22
29
|
};
|