@vectara/vectara-ui 16.7.0 → 16.9.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/button/BaseButton.d.ts +1 -0
- package/lib/components/button/BaseButton.js +27 -18
- package/lib/components/button/baseButton.scss +5 -0
- 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/styles/index.css +11 -0
- package/package.json +1 -1
- package/src/docs/pages/button/Icons.tsx +1 -1
- package/src/docs/pages/button/Truncate.tsx +1 -1
- package/src/docs/pages/textArea/TextAreaAutoGrow.tsx +18 -0
- package/src/docs/pages/textArea/index.tsx +7 -0
|
@@ -26,6 +26,7 @@ export type BaseButtonProps = {
|
|
|
26
26
|
isSubmit?: boolean;
|
|
27
27
|
isLoading?: boolean;
|
|
28
28
|
truncate?: boolean;
|
|
29
|
+
"aria-label"?: string;
|
|
29
30
|
};
|
|
30
31
|
export declare const BaseButton: import("react").ForwardRefExoticComponent<BaseButtonProps & {
|
|
31
32
|
spinnerColor?: "accent" | "primary" | "success" | "warning" | "danger" | "subdued" | "empty" | "dark" | undefined;
|
|
@@ -15,6 +15,7 @@ import classNames from "classnames";
|
|
|
15
15
|
import { getTrackingProps } from "../../utils/getTrackingProps";
|
|
16
16
|
import { useVuiContext } from "../context/Context";
|
|
17
17
|
import { VuiSpinner } from "../spinner/Spinner";
|
|
18
|
+
import { VuiTooltip } from "../tooltip/Tooltip";
|
|
18
19
|
const alignToClassMap = {
|
|
19
20
|
left: "vuiBaseButton--alignLeft",
|
|
20
21
|
center: "vuiBaseButton--alignCenter",
|
|
@@ -27,12 +28,13 @@ const sizeToSpinnerSizeMap = {
|
|
|
27
28
|
l: "m"
|
|
28
29
|
};
|
|
29
30
|
export const BaseButton = forwardRef((_a, ref) => {
|
|
30
|
-
var { children, icon, iconSide = "left", align = "center", className, size = "m", fullWidth, onClick, onMouseOver, onMouseOut, onMouseMove, tabIndex, isInert, isDisabled, href, target, track, htmlFor, isSubmit, isLoading, spinnerColor, truncate } = _a, rest = __rest(_a, ["children", "icon", "iconSide", "align", "className", "size", "fullWidth", "onClick", "onMouseOver", "onMouseOut", "onMouseMove", "tabIndex", "isInert", "isDisabled", "href", "target", "track", "htmlFor", "isSubmit", "isLoading", "spinnerColor", "truncate"]);
|
|
31
|
+
var { children, icon, iconSide = "left", align = "center", className, size = "m", fullWidth, onClick, onMouseOver, onMouseOut, onMouseMove, tabIndex, isInert, isDisabled, href, target, track, htmlFor, isSubmit, isLoading, spinnerColor, truncate, "aria-label": ariaLabel } = _a, rest = __rest(_a, ["children", "icon", "iconSide", "align", "className", "size", "fullWidth", "onClick", "onMouseOver", "onMouseOut", "onMouseMove", "tabIndex", "isInert", "isDisabled", "href", "target", "track", "htmlFor", "isSubmit", "isLoading", "spinnerColor", "truncate", "aria-label"]);
|
|
31
32
|
const { createLink } = useVuiContext();
|
|
32
33
|
const classes = classNames("vuiBaseButton", className, `vuiBaseButton--${size}`, alignToClassMap[align], {
|
|
33
34
|
"vuiBaseButton-isInert": isInert,
|
|
34
35
|
"vuiBaseButton-isDisabled": isDisabled,
|
|
35
36
|
"vuiBaseButton--fullWidth": fullWidth,
|
|
37
|
+
"vuiBaseButton--truncate": truncate,
|
|
36
38
|
[`vuiBaseButton--${isLoading ? "left" : iconSide}`]: (Boolean(icon) || isLoading) && Boolean(children)
|
|
37
39
|
});
|
|
38
40
|
let iconContainer;
|
|
@@ -42,33 +44,40 @@ export const BaseButton = forwardRef((_a, ref) => {
|
|
|
42
44
|
else if (icon) {
|
|
43
45
|
iconContainer = _jsx("span", Object.assign({ className: "vuiBaseButtonIconContainer" }, { children: icon }));
|
|
44
46
|
}
|
|
45
|
-
|
|
46
|
-
// for uploading files and adding a button to trigger it.
|
|
47
|
+
let button;
|
|
47
48
|
if (htmlFor) {
|
|
48
|
-
|
|
49
|
+
// This is useful for controlling other elements, e.g. creating an <input type="file" />
|
|
50
|
+
// for uploading files and adding a button to trigger it.
|
|
51
|
+
button = (_jsxs("label", Object.assign({ "aria-label": ariaLabel, htmlFor: htmlFor, className: classes, tabIndex: tabIndex }, rest, { children: [iconContainer, children] })));
|
|
49
52
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
else if (href && !isDisabled) {
|
|
54
|
+
// Anchor tags can't be disabled, so we'll just render a button instead
|
|
55
|
+
// if isDisabled is true.
|
|
53
56
|
const wrapperClasses = classNames("vuiBaseButtonLinkWrapper", {
|
|
54
57
|
"vuiBaseButtonLinkWrapper--fullWidth": fullWidth
|
|
55
58
|
});
|
|
56
|
-
|
|
59
|
+
button = createLink(Object.assign(Object.assign({ className: wrapperClasses, href,
|
|
57
60
|
onClick,
|
|
58
61
|
onMouseOver,
|
|
59
62
|
onMouseOut,
|
|
60
63
|
onMouseMove, children: (
|
|
61
64
|
//* Wrap a button otherwise the flex layout breaks */}
|
|
62
|
-
_jsxs("button", Object.assign({ className: classes, tabIndex: -1, ref: ref }, { children: [iconContainer, children] }))), target,
|
|
65
|
+
_jsxs("button", Object.assign({ "aria-label": ariaLabel, className: classes, tabIndex: -1, ref: ref }, { children: [iconContainer, children] }))), target,
|
|
63
66
|
tabIndex }, rest), getTrackingProps(track)));
|
|
64
67
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
68
|
+
else {
|
|
69
|
+
const labelClasses = classNames({
|
|
70
|
+
"vuiBaseButtonLabel--truncate": truncate
|
|
71
|
+
});
|
|
72
|
+
const props = Object.assign({ onClick,
|
|
73
|
+
onMouseOver,
|
|
74
|
+
onMouseOut,
|
|
75
|
+
onMouseMove,
|
|
76
|
+
tabIndex, type: isSubmit ? "submit" : "button", disabled: isDisabled }, rest);
|
|
77
|
+
button = (_jsxs("button", Object.assign({ "aria-label": ariaLabel, className: classes }, props, { ref: ref }, { children: [iconContainer, _jsx("span", Object.assign({ className: labelClasses }, { children: children }))] })));
|
|
78
|
+
}
|
|
79
|
+
if (ariaLabel) {
|
|
80
|
+
return _jsx(VuiTooltip, Object.assign({ tip: ariaLabel }, { children: button }));
|
|
81
|
+
}
|
|
82
|
+
return button;
|
|
74
83
|
});
|
|
@@ -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
|
});
|
package/lib/styles/index.css
CHANGED
|
@@ -749,6 +749,11 @@ fieldset {
|
|
|
749
749
|
width: 100%;
|
|
750
750
|
}
|
|
751
751
|
|
|
752
|
+
.vuiBaseButton--truncate {
|
|
753
|
+
overflow: hidden;
|
|
754
|
+
text-overflow: ellipsis;
|
|
755
|
+
}
|
|
756
|
+
|
|
752
757
|
.vuiBaseButton--xs {
|
|
753
758
|
font-size: 12px;
|
|
754
759
|
padding: 4px 8px;
|
|
@@ -3007,6 +3012,12 @@ h2.react-datepicker__current-month {
|
|
|
3007
3012
|
width: 100%;
|
|
3008
3013
|
}
|
|
3009
3014
|
|
|
3015
|
+
.vuiTextArea--autoGrow {
|
|
3016
|
+
min-height: 0;
|
|
3017
|
+
line-height: 1.6;
|
|
3018
|
+
max-height: 12rem;
|
|
3019
|
+
}
|
|
3020
|
+
|
|
3010
3021
|
.vuiGridContainer {
|
|
3011
3022
|
container-type: inline-size;
|
|
3012
3023
|
width: 100%;
|
package/package.json
CHANGED
|
@@ -18,7 +18,7 @@ export const Icons = () => {
|
|
|
18
18
|
</Subsection>
|
|
19
19
|
|
|
20
20
|
<Subsection title="Icon only">
|
|
21
|
-
<VuiButtonPrimary icon={icon} color="primary" size="m" />
|
|
21
|
+
<VuiButtonPrimary icon={icon} color="primary" size="m" aria-label="Add to favorites" />
|
|
22
22
|
</Subsection>
|
|
23
23
|
</>
|
|
24
24
|
);
|
|
@@ -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
|
};
|