Skip to content

Commit d8106fb

Browse files
authored
Merge pull request #484 from acelaya-forks/feature/button-ref
Add refs to Button, LinkButton and CloseButton
2 parents 9cd6ed0 + ef580eb commit d8106fb

File tree

5 files changed

+50
-11
lines changed

5 files changed

+50
-11
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
77
## [Unreleased]
88
### Added
99
* Add tailwind-based `Tooltip` component.
10+
* Forward refs to `Button`, `LinkButton` and `CloseButton` tailwind-based components.
1011

1112
### Changed
1213
* *Nothing*

dev/tailwind/form/ButtonsPage.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,26 @@
11
import type { FC } from 'react';
2+
import { useRef } from 'react';
23
import { Button, CloseButton, LinkButton } from '../../../src/tailwind';
34

5+
const ButtonsWithRefs: FC = () => {
6+
const linkButtonRef = useRef<HTMLButtonElement>(null);
7+
const closeButtonRef = useRef<HTMLButtonElement>(null);
8+
const regularButtonRef = useRef<HTMLButtonElement>(null);
9+
const buttonWithLinkRef = useRef<HTMLAnchorElement>(null);
10+
11+
return (
12+
<div className="tw:flex tw:flex-col tw:gap-y-2">
13+
<h2>Buttons with ref</h2>
14+
<div className="tw:flex tw:gap-x-2">
15+
<LinkButton ref={linkButtonRef}>Link button</LinkButton>
16+
<CloseButton ref={closeButtonRef} />
17+
<Button ref={regularButtonRef}>Regular button</Button>
18+
<Button to="" ref={buttonWithLinkRef}>Button with link</Button>
19+
</div>
20+
</div>
21+
);
22+
};
23+
424
export const ButtonsPage: FC = () => {
525
return (
626
<div className="tw:flex tw:flex-col tw:gap-y-4">
@@ -12,6 +32,7 @@ export const ButtonsPage: FC = () => {
1232
<Button variant="danger">Danger</Button>
1333
</div>
1434
</div>
35+
1536
<div className="tw:flex tw:flex-col tw:gap-y-2">
1637
<h2>Button sizes</h2>
1738
<div className="tw:flex tw:gap-x-2">
@@ -25,6 +46,7 @@ export const ButtonsPage: FC = () => {
2546
<Button variant="danger" size="lg">Danger</Button>
2647
</div>
2748
</div>
49+
2850
<div className="tw:flex tw:flex-col tw:gap-y-2">
2951
<h2>Solid buttons</h2>
3052
<div className="tw:flex tw:gap-x-2">
@@ -33,6 +55,7 @@ export const ButtonsPage: FC = () => {
3355
<Button variant="danger" solid>Danger</Button>
3456
</div>
3557
</div>
58+
3659
<div className="tw:flex tw:flex-col tw:gap-y-2">
3760
<h2>Disabled buttons</h2>
3861
<div className="tw:flex tw:gap-x-2">
@@ -46,6 +69,7 @@ export const ButtonsPage: FC = () => {
4669
<Button variant="danger" solid disabled>Danger</Button>
4770
</div>
4871
</div>
72+
4973
<div className="tw:flex tw:flex-col tw:gap-y-2">
5074
<h2>Others</h2>
5175
<div className="tw:flex tw:gap-x-2">
@@ -55,6 +79,8 @@ export const ButtonsPage: FC = () => {
5579
<Button to="">Button with link</Button>
5680
</div>
5781
</div>
82+
83+
<ButtonsWithRefs />
5884
</div>
5985
);
6086
};

src/tailwind/form/Button.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import clsx from 'clsx';
2-
import type { FC, HTMLProps, PropsWithChildren } from 'react';
2+
import type { HTMLProps, PropsWithChildren } from 'react';
3+
import { forwardRef } from 'react';
34
import type { LinkProps } from 'react-router';
45
import { Link } from 'react-router';
56
import type { Size } from '../types';
@@ -17,7 +18,7 @@ export type ButtonProps = PropsWithChildren<{
1718
solid?: boolean;
1819
} & (RegularButtonProps | LinkButtonProps)>;
1920

20-
export const Button: FC<ButtonProps> = ({
21+
export const Button = forwardRef<HTMLButtonElement | HTMLAnchorElement, ButtonProps>(({
2122
children,
2223
className,
2324
disabled,
@@ -27,13 +28,14 @@ export const Button: FC<ButtonProps> = ({
2728
solid = false,
2829
type: providedType = 'button',
2930
...rest
30-
}) => {
31+
}, ref) => {
3132
const Tag = 'to' in rest ? Link : 'button';
3233
const type = Tag === Link ? undefined : providedType;
3334

3435
return (
35-
// @ts-expect-error We are explicitly checking for the `to` prop before using Link
3636
<Tag
37+
// @ts-expect-error The dual nature of this component makes properly typing the ref a bit complex
38+
ref={ref}
3739
className={clsx(
3840
{
3941
'tw:inline-flex': inline,
@@ -90,4 +92,4 @@ export const Button: FC<ButtonProps> = ({
9092
{children}
9193
</Tag>
9294
);
93-
};
95+
});

src/tailwind/form/CloseButton.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
import { faClose } from '@fortawesome/free-solid-svg-icons';
22
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
33
import clsx from 'clsx';
4-
import type { FC, HTMLProps } from 'react';
4+
import type { HTMLProps } from 'react';
5+
import { forwardRef } from 'react';
56

67
export type CloseButtonProps = {
78
label?: string;
89
onClick?: HTMLProps<HTMLButtonElement>['onClick'];
910
className?: string;
1011
};
1112

12-
export const CloseButton: FC<CloseButtonProps> = ({ onClick, className, label = 'Close' }) => (
13+
export const CloseButton = forwardRef<HTMLButtonElement, CloseButtonProps>((
14+
{ onClick, className, label = 'Close' },
15+
ref,
16+
) => (
1317
<button
18+
ref={ref}
1419
type="button"
1520
onClick={onClick}
1621
className={clsx(
@@ -22,4 +27,4 @@ export const CloseButton: FC<CloseButtonProps> = ({ onClick, className, label =
2227
>
2328
<FontAwesomeIcon icon={faClose} size="xl" />
2429
</button>
25-
);
30+
));

src/tailwind/navigation/LinkButton.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
import clsx from 'clsx';
2-
import type { FC, HTMLProps } from 'react';
2+
import type { HTMLProps } from 'react';
3+
import { forwardRef } from 'react';
34
import type { Size } from '../types';
45

56
export type LinkButtonProps = Omit<HTMLProps<HTMLButtonElement>, 'size' | 'type'> & {
67
size?: Size;
78
type?: HTMLButtonElement['type'];
89
};
910

10-
export const LinkButton: FC<LinkButtonProps> = ({ className, disabled, size = 'md', type = 'button', ...rest }) => (
11+
export const LinkButton = forwardRef<HTMLButtonElement, LinkButtonProps>((
12+
{ className, disabled, size = 'md', type = 'button', ...rest },
13+
ref,
14+
) => (
1115
<button
1216
className={clsx(
1317
'tw:inline-flex tw:rounded-md tw:focus-ring',
@@ -24,5 +28,6 @@ export const LinkButton: FC<LinkButtonProps> = ({ className, disabled, size = 'm
2428
disabled={disabled}
2529
type={type}
2630
{...rest}
31+
ref={ref}
2732
/>
28-
);
33+
));

0 commit comments

Comments
 (0)