Skip to content

Commit 03c3f2e

Browse files
committed
Merge branch 'feat/button' of github.com:devtron-labs/devtron-fe-common-lib into feat/button
2 parents a45dee4 + 603cff5 commit 03c3f2e

File tree

3 files changed

+118
-10
lines changed

3 files changed

+118
-10
lines changed

src/Shared/Components/Button/Button.component.tsx

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,60 @@
1+
import { ButtonHTMLAttributes, PropsWithChildren } from 'react'
2+
import { Link, LinkProps } from 'react-router-dom'
13
import { Progressing } from '@Common/Progressing'
24
import { Tooltip } from '@Common/Tooltip'
35
import { ComponentSizeType } from '@Shared/constants'
4-
import { ButtonProps, ButtonStyleType, ButtonVariantType } from './types'
6+
import { ButtonComponentType, ButtonProps, ButtonStyleType, ButtonVariantType } from './types'
57
import { BUTTON_SIZE_TO_ICON_CLASS_NAME_MAP, BUTTON_SIZE_TO_LOADER_SIZE_MAP } from './constants'
68
import { getButtonDerivedClass } from './utils'
79
import './button.scss'
810

11+
const ButtonElement = ({
12+
component = ButtonComponentType.button,
13+
linkProps,
14+
buttonProps,
15+
onClick,
16+
...props
17+
}: PropsWithChildren<
18+
Omit<
19+
ButtonProps,
20+
| 'text'
21+
| 'variant'
22+
| 'size'
23+
| 'style'
24+
| 'startIcon'
25+
| 'endIcon'
26+
| 'showTooltip'
27+
| 'tooltipProps'
28+
| 'dataTestId'
29+
| 'isLoading'
30+
> & {
31+
className: string
32+
'data-testid': ButtonProps['dataTestId']
33+
}
34+
>) => {
35+
if (component === ButtonComponentType.link) {
36+
return (
37+
<Link
38+
{...linkProps}
39+
{...props}
40+
// Added the specific class to ensure that the link override is applied
41+
className={`${props.className} button__link ${props.disabled ? 'dc__disable-click' : ''}`}
42+
onClick={onClick as LinkProps['onClick']}
43+
/>
44+
)
45+
}
46+
47+
return (
48+
<button
49+
{...buttonProps}
50+
{...props}
51+
// eslint-disable-next-line react/button-has-type
52+
type={buttonProps?.type || 'button'}
53+
onClick={onClick as ButtonHTMLAttributes<HTMLButtonElement>['onClick']}
54+
/>
55+
)
56+
}
57+
958
/**
1059
* Generic component for Button.
1160
* Should be used in combination of variant, size and style.
@@ -55,6 +104,15 @@ import './button.scss'
55104
* <Button text="Hello World" showTippy tippyContent="Tippy content" />
56105
* ```
57106
*
107+
* @example With onClick
108+
* ```tsx
109+
* <Button text="Hello World" onClick={noop} />
110+
* ```
111+
*
112+
* @example Link component
113+
* ```tsx
114+
* <Button component={ButtonComponentType.link} linkProps={{ to: '#' }} />
115+
* ```
58116
*/
59117
const Button = ({
60118
dataTestId,
@@ -68,7 +126,6 @@ const Button = ({
68126
isLoading = false,
69127
showTooltip = false,
70128
tooltipProps = {},
71-
type = 'button',
72129
...props
73130
}: ButtonProps) => {
74131
const isDisabled = disabled || isLoading
@@ -77,19 +134,17 @@ const Button = ({
77134
return (
78135
<Tooltip {...tooltipProps} alwaysShowTippyOnHover={showTooltip && !!tooltipProps?.content}>
79136
<div>
80-
<button
137+
<ButtonElement
81138
{...props}
82139
disabled={isDisabled}
83-
// eslint-disable-next-line react/button-has-type
84-
type={type}
85140
className={`br-4 flex cursor dc__mnw-100 dc__tab-focus dc__position-rel dc__capitalize ${getButtonDerivedClass({ size, variant, style, isLoading })} ${isDisabled ? 'dc__disabled' : ''}`}
86141
data-testid={dataTestId}
87142
>
88143
{startIcon && <span className={iconClass}>{startIcon}</span>}
89144
<span className="dc__mxw-150 dc__align-left dc__truncate">{text}</span>
90145
{endIcon && <span className={iconClass}>{endIcon}</span>}
91146
{isLoading && <Progressing size={BUTTON_SIZE_TO_LOADER_SIZE_MAP[size]} />}
92-
</button>
147+
</ButtonElement>
93148
</div>
94149
</Tooltip>
95150
)

src/Shared/Components/Button/button.scss

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
color: $text-color;
44
border: 1px solid $border-color;
55

6+
&.button__link {
7+
color: $text-color;
8+
}
9+
610
// Only stroke icons are supposed to be used with button
711
svg,
812
svg * {
@@ -26,15 +30,15 @@
2630
@mixin pseudo-states($hover-bg-color, $active-bg-color, $hover-border-color: null) {
2731
$parent-selector: &;
2832

29-
&:hover:enabled {
33+
&:hover:not([disabled]) {
3034
background: $hover-bg-color;
3135

3236
@if ($hover-border-color) {
3337
border-color: $hover-border-color;
3438
}
3539
}
3640

37-
&:active:enabled {
41+
&:active:not([disabled]) {
3842
background: $active-bg-color;
3943
}
4044
}
@@ -45,6 +49,7 @@
4549
color: inherit;
4650
border: none;
4751
outline: inherit;
52+
text-decoration: none;
4853

4954
&__primary {
5055
$border-color: transparent;
@@ -169,7 +174,7 @@
169174
border: none;
170175

171176
&:hover {
172-
text-decoration: underline;
177+
text-decoration: underline !important;
173178
}
174179
}
175180
}
@@ -183,4 +188,10 @@
183188
visibility: hidden;
184189
}
185190
}
191+
192+
&__link {
193+
&:hover {
194+
text-decoration: none;
195+
}
196+
}
186197
}

src/Shared/Components/Button/types.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { TooltipProps } from '@Common/Tooltip/types'
22
import { ComponentSizeType } from '@Shared/constants'
33
import { ButtonHTMLAttributes, ReactElement } from 'react'
4+
import { LinkProps } from 'react-router-dom'
45

56
// Using the same for BEM class elements
67
export enum ButtonVariantType {
@@ -18,7 +19,39 @@ export enum ButtonStyleType {
1819
neutral = 'neutral',
1920
}
2021

21-
export type ButtonProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children' | 'styles' | 'className'> & {
22+
export enum ButtonComponentType {
23+
button = 'button',
24+
link = 'link',
25+
}
26+
27+
export type ButtonProps = (
28+
| {
29+
/**
30+
* Component to be rendered from the available options
31+
*
32+
* @default ButtonComponentType.button
33+
*/
34+
component?: ButtonComponentType.button | never
35+
/**
36+
* Props for the button component
37+
*/
38+
buttonProps?: Omit<
39+
ButtonHTMLAttributes<HTMLButtonElement>,
40+
'children' | 'styles' | 'className' | 'disabled' | 'onClick'
41+
>
42+
linkProps?: never
43+
onClick?: ButtonHTMLAttributes<HTMLButtonElement>['onClick']
44+
}
45+
| {
46+
component: ButtonComponentType.link
47+
/**
48+
* Props for the link component
49+
*/
50+
linkProps: Omit<LinkProps, 'children' | 'styles' | 'className' | 'onClick'>
51+
buttonProps?: never
52+
onClick?: LinkProps['onClick']
53+
}
54+
) & {
2255
/**
2356
* Variant of the button
2457
*
@@ -53,7 +86,16 @@ export type ButtonProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'childre
5386
* If true, the loading state is shown for the button with disabled
5487
*/
5588
isLoading?: boolean
89+
/**
90+
* Test id for the component
91+
*/
5692
dataTestId: string
93+
/**
94+
* If true, the button is disabled
95+
*
96+
* @default false
97+
*/
98+
disabled?: boolean
5799
} & (
58100
| {
59101
/**

0 commit comments

Comments
 (0)