✨(react) render Button as link
For a variety of reasons, such as accessibility or integration with external react-router deps style we needed to be able to provide the ability to render the Button component as link in order to be able to provide link-specific attribute for rendering such as href.
This commit is contained in:
@@ -4,7 +4,9 @@
|
||||
border: thin solid transparent;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
display: inline-flex;
|
||||
// When button is rendered as link.
|
||||
text-decoration: none;
|
||||
font-weight: var(--c--components--button--font-weight);
|
||||
font-family: var(--c--components--button--font-family);
|
||||
transition: all var(--c--theme--transitions--duration) var(--c--theme--transitions--ease-out);
|
||||
|
||||
@@ -65,6 +65,21 @@ describe("<Button/>", () => {
|
||||
expect(handleClick).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("renders as link when href is used", () => {
|
||||
render(
|
||||
<Button
|
||||
href="https://www.fun-mooc.fr/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Open link
|
||||
</Button>,
|
||||
);
|
||||
const button = screen.getByRole("link", { name: "Open link" });
|
||||
expect(button).toHaveAttribute("target", "_blank");
|
||||
expect(button).toHaveAttribute("rel", "noopener noreferrer");
|
||||
});
|
||||
|
||||
it("uses custom token", async () => {
|
||||
await buildTheme();
|
||||
const tokens = await loadTokens();
|
||||
|
||||
@@ -103,3 +103,14 @@ export const IconOnly: Story = {
|
||||
color: "primary",
|
||||
},
|
||||
};
|
||||
|
||||
export const AsLink: Story = {
|
||||
args: {
|
||||
children: "Go to fun-mooc.fr",
|
||||
icon: <span className="material-icons">link</span>,
|
||||
color: "primary",
|
||||
href: "https://www.fun-mooc.fr/",
|
||||
target: "_blank",
|
||||
rel: "noopener noreferrer",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,15 +1,24 @@
|
||||
import React, { ButtonHTMLAttributes, forwardRef, ReactNode } from "react";
|
||||
import React, {
|
||||
AnchorHTMLAttributes,
|
||||
ButtonHTMLAttributes,
|
||||
createElement,
|
||||
forwardRef,
|
||||
ReactNode,
|
||||
} from "react";
|
||||
|
||||
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
color?: "primary" | "secondary" | "tertiary" | "danger";
|
||||
size?: "medium" | "small" | "nano";
|
||||
icon?: ReactNode;
|
||||
iconPosition?: "left" | "right";
|
||||
active?: boolean;
|
||||
fullWidth?: boolean;
|
||||
}
|
||||
export type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> &
|
||||
AnchorHTMLAttributes<HTMLAnchorElement> & {
|
||||
color?: "primary" | "secondary" | "tertiary" | "danger";
|
||||
size?: "medium" | "small" | "nano";
|
||||
icon?: ReactNode;
|
||||
iconPosition?: "left" | "right";
|
||||
active?: boolean;
|
||||
fullWidth?: boolean;
|
||||
};
|
||||
|
||||
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
export type ButtonElement = HTMLButtonElement & HTMLAnchorElement;
|
||||
|
||||
export const Button = forwardRef<ButtonElement, ButtonProps>(
|
||||
(
|
||||
{
|
||||
children,
|
||||
@@ -43,13 +52,19 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
classes.push("c__button--full-width");
|
||||
}
|
||||
const iconElement = <span className="c__button__icon">{icon}</span>;
|
||||
// const iconElement = icon;
|
||||
return (
|
||||
<button className={classes.join(" ")} {...props} ref={ref}>
|
||||
const tagName = props.href ? "a" : "button";
|
||||
return createElement(
|
||||
tagName,
|
||||
{
|
||||
className: classes.join(" "),
|
||||
...props,
|
||||
ref,
|
||||
},
|
||||
<>
|
||||
{!!icon && iconPosition === "left" && iconElement}
|
||||
{children}
|
||||
{!!icon && iconPosition === "right" && iconElement}
|
||||
</button>
|
||||
</>,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
isToday,
|
||||
} from "@internationalized/date";
|
||||
import { CalendarState, RangeCalendarState } from "@react-stately/calendar";
|
||||
import { Button } from ":/components/Button";
|
||||
import { Button, ButtonElement } from ":/components/Button";
|
||||
|
||||
interface CalendarCellProps {
|
||||
state: CalendarState | RangeCalendarState;
|
||||
@@ -20,7 +20,7 @@ const isRangeCalendar = (object: any): object is RangeCalendarState => {
|
||||
};
|
||||
|
||||
export const CalendarCell = ({ state, date }: CalendarCellProps) => {
|
||||
const ref = useRef<HTMLButtonElement>(null);
|
||||
const ref = useRef<ButtonElement>(null);
|
||||
const {
|
||||
cellProps,
|
||||
buttonProps,
|
||||
|
||||
Reference in New Issue
Block a user