Skip to content

Commit 8eab9f7

Browse files
authored
Add download prop to Button and Link to support file downloads. (#325)
1 parent 79a2b37 commit 8eab9f7

File tree

5 files changed

+44
-22
lines changed

5 files changed

+44
-22
lines changed

src/docs/pages/button/Link.tsx

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,29 @@
11
import { useState } from "react";
2-
import { VuiButtonPrimary, VuiSpacer, VuiToggle } from "../../../lib";
2+
import { VuiButtonPrimary, VuiFlexContainer, VuiSpacer, VuiToggle } from "../../../lib";
33

44
export const Link = () => {
55
const [isDisabled, setIsDisabled] = useState<boolean>(false);
6+
const [isDownload, setIsDownload] = useState<boolean>(false);
67

78
return (
89
<>
9-
<VuiToggle
10-
label="Disabled (not clickable, visual)"
11-
checked={isDisabled}
12-
onChange={() => setIsDisabled(!isDisabled)}
13-
/>
10+
<VuiFlexContainer>
11+
<VuiToggle
12+
label="Disabled (not clickable, visual)"
13+
checked={isDisabled}
14+
onChange={() => setIsDisabled(!isDisabled)}
15+
/>
16+
17+
<VuiToggle label="File download" checked={isDownload} onChange={() => setIsDownload(!isDownload)} />
18+
</VuiFlexContainer>
1419

1520
<VuiSpacer size="m" />
1621

1722
<VuiButtonPrimary
1823
color="accent"
19-
href="https://vectara.com"
20-
target="_blank"
24+
href={isDownload ? `${window.location.origin}/vectara-favicon.png` : "https://vectara.com"}
25+
target={isDownload ? undefined : "_blank"}
26+
download={isDownload ? "tiny_vectara_logo.png" : undefined}
2127
onClick={() => console.log("click")}
2228
onMouseOver={() => console.log("mouse over")}
2329
onMouseOut={() => console.log("mouse out")}

src/docs/pages/link/Link.tsx

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,30 @@
1-
import { VuiLink } from "../../../lib";
1+
import { useState } from "react";
2+
import { VuiLink, VuiSpacer, VuiToggle } from "../../../lib";
23
import { Subsection } from "../../components/Subsection";
34

45
export const Link = () => {
6+
const [isDownload, setIsDownload] = useState<boolean>(false);
7+
8+
const props = {
9+
href: isDownload ? `${window.location.origin}/vectara-favicon.png` : "https://vectara.com",
10+
target: isDownload ? undefined : "_blank",
11+
download: isDownload ? "tiny_vectara_logo.png" : undefined
12+
} as const;
13+
514
return (
615
<>
16+
<VuiToggle label="File download" checked={isDownload} onChange={() => setIsDownload(!isDownload)} />
17+
18+
<VuiSpacer size="m" />
19+
720
<Subsection title="With href and onClick">
8-
<VuiLink href="https://vectara.com" target="_blank" onClick={() => alert("Clicked link")}>
21+
<VuiLink onClick={() => alert("Clicked link")} {...props}>
922
Link
1023
</VuiLink>
1124
</Subsection>
1225

1326
<Subsection title="With href only">
14-
<VuiLink href="https://vectara.com" target="_blank">
15-
Link
16-
</VuiLink>
27+
<VuiLink {...props}>Link</VuiLink>
1728
</Subsection>
1829

1930
<Subsection title="With onClick only">

src/lib/components/button/BaseButton.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export type BaseButtonProps = {
3838
href?: LinkProps["href"];
3939
target?: LinkProps["target"];
4040
track?: LinkProps["track"];
41+
download?: LinkProps["download"];
4142
htmlFor?: string;
4243
tabIndex?: number;
4344
title?: string;
@@ -143,7 +144,7 @@ export const BaseButton = forwardRef<HTMLButtonElement | null, Props>(
143144
onMouseOut,
144145
onMouseMove,
145146
tabIndex,
146-
["type"]: isSubmit ? "submit" : "button",
147+
type: isSubmit ? "submit" : "button",
147148
disabled: isDisabled,
148149
...rest
149150
} as const;

src/lib/components/context/Context.tsx

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,18 @@ export const VuiContextProvider = ({
3535
isThemeIsolated
3636
}: Props) => {
3737
const createLink = (linkConfig: LinkProps) => {
38-
if (linkProvider) return linkProvider(linkConfig);
39-
40-
const { className, href, onClick, children, ref, ...rest } = linkConfig;
38+
if (!linkProvider || linkConfig.download) {
39+
const { className, href, onClick, children, ref, ...rest } = linkConfig;
40+
41+
// To support downloads, we must use anchor tags, not a react-router Link.
42+
return (
43+
<a className={className} href={href} onClick={onClick} {...rest}>
44+
{children}
45+
</a>
46+
);
47+
}
4148

42-
return (
43-
<a className={className} href={href} onClick={onClick} {...rest}>
44-
{children}
45-
</a>
46-
);
49+
return linkProvider(linkConfig);
4750
};
4851

4952
const getPath = () => {

src/lib/components/link/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ export type LinkProps = {
1818
tabIndex?: number;
1919
"data-testid"?: string;
2020
ref?: ForwardedRef<HTMLAnchorElement | null>;
21+
download?: string;
2122
};

0 commit comments

Comments
 (0)