Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Loading in button #1788

Merged
merged 9 commits into from
Aug 1, 2024
26 changes: 21 additions & 5 deletions src/blocks/button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import styled, { FlattenSimpleInterpolation } from 'styled-components';
import type { TransformedHTMLAttributes } from '../Blocks.types';
import type { ButtonSize, ButtonVariant } from './Button.types';
import { getButtonSizeStyles, getButtonVariantStyles } from './Button.utils';
import { Spinner } from '../spinner';

export type ButtonProps = {
/* Child react nodes rendered by Box */
Expand All @@ -26,6 +27,8 @@ export type ButtonProps = {
variant?: ButtonVariant;
/* Button takes the full width if enabled */
block?: boolean;
/* Button loading state */
loading?: boolean;
} & TransformedHTMLAttributes<HTMLButtonElement>;

const StyledButton = styled.button<ButtonProps>`
Expand All @@ -44,9 +47,19 @@ const StyledButton = styled.button<ButtonProps>`
align-items: center;
justify-content: center;
}
mishramonalisha76 marked this conversation as resolved.
Show resolved Hide resolved

[role='spinner'] {
margin: 6.667px;
}
/* Button variant CSS styles */
${({ variant }) => getButtonVariantStyles(variant || 'primary')}
${({ variant, loading }) => getButtonVariantStyles(variant || 'primary', loading!)}

/* ${({ iconOnly }) =>
!iconOnly &&
`[role='spinner'] {
margin-right: var(--spacing-xxxs);
};`} */

${({ loading }) => loading && 'opacity: var(--opacity-80);'}

/* Button and font size CSS styles */
${({ iconOnly, size }) => getButtonSizeStyles({ iconOnly: !!iconOnly, size: size || 'medium' })}
Expand All @@ -69,6 +82,7 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(
size = 'medium',
leadingIcon,
trailingIcon,
loading = false,
iconOnly,
circular = false,
children,
Expand All @@ -77,20 +91,22 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(
ref
) => (
<StyledButton
{...(disabled ? { 'aria-disabled': true } : {})}
{...(disabled || loading ? { 'aria-disabled': true } : {})}
circular={circular}
mishramonalisha76 marked this conversation as resolved.
Show resolved Hide resolved
disabled={disabled}
disabled={disabled || loading}
iconOnly={iconOnly}
loading={loading}
role="button"
ref={ref}
size={size}
variant={variant}
{...props}
>
{loading && <Spinner />}
{leadingIcon && <span className="icon icon-text">{leadingIcon}</span>}
{!iconOnly && children}
{trailingIcon && <span className="icon icon-text">{trailingIcon}</span>}
{iconOnly && !children && <span className="icon icon-only">{iconOnly}</span>}
{iconOnly && !loading && !children && <span className="icon icon-only">{iconOnly}</span>}
</StyledButton>
)
);
Expand Down
125 changes: 96 additions & 29 deletions src/blocks/button/Button.utils.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { FlattenSimpleInterpolation, css } from 'styled-components';
import { ButtonSize, ButtonVariant } from './Button.types';

export const getButtonVariantStyles = (variant: ButtonVariant) => {
export const getButtonVariantStyles = (variant: ButtonVariant, loading: boolean) => {
switch (variant) {
case 'primary': {
return `
background-color: var(--components-button-primary-background-default);
background-color: var(--${
loading ? 'components-button-primary-background-loading' : 'components-button-primary-background-default'
});
color: var(--components-button-primary-text-default);

&:hover {
background-color: var(--components-button-primary-background-hover)
}
Expand All @@ -21,10 +23,19 @@ export const getButtonVariantStyles = (variant: ButtonVariant) => {
border: var(--border-sm) solid var(--components-button-primary-stroke-focus);
outline: none;
}

&:disabled {
background-color: var(--components-button-primary-background-disabled);
color: var(--components-button-primary-text-disabled);
${
!loading &&
`&:disabled {
background-color: var(--components-button-primary-background-disabled);
color: var(--components-button-primary-text-disabled);
}`
};

[role='spinner'] {
border-top-color: var(--components-button-primary-icon-default);
:before,:after {
background:var(--components-button-primary-icon-default);
}
}
`;
}
Expand All @@ -46,10 +57,18 @@ export const getButtonVariantStyles = (variant: ButtonVariant) => {
border: var(--border-sm) solid var(--components-button-secondary-stroke-focus);
outline: none;
}

&:disabled {
background-color: var(--components-button-secondary-background-disabled);
color: var(--components-button-secondary-text-disabled)
${
!loading &&
`&:disabled {
background-color: var(--components-button-secondary-background-disabled);
color: var(--components-button-secondary-text-disabled);
};`
};
[role='spinner'] {
border-top-color: var(--components-button-secondary-icon-default);
:before,:after {
background:var(--components-button-secondary-icon-default);
}
}
`;
}
Expand All @@ -74,10 +93,18 @@ export const getButtonVariantStyles = (variant: ButtonVariant) => {
color: var(--components-button-tertiary-text-default);
outline: none;
}

&:disabled {
background-color: var(--components-button-tertiary-background-disabled);
color: var(--components-button-tertiary-text-disabled);
${
!loading &&
`&:disabled {
background-color: var(--components-button-tertiary-background-disabled);
color: var(--components-button-tertiary-text-disabled);
}`
};
[role='spinner'] {
border-top-color: var(--components-button-tertiary-icon-default);
:before,:after {
background:var(--components-button-tertiary-icon-default);
}
}
`;
}
Expand All @@ -99,10 +126,18 @@ export const getButtonVariantStyles = (variant: ButtonVariant) => {
border: var(--border-sm) solid var(--components-button-danger-stroke-focus);
outline: none;
}

&:disabled {
background-color: var(--components-button-danger-background-disabled);
color: var(--components-button-danger-text-disabled);
${
!loading &&
`&:disabled {
background-color: var(--components-button-danger-background-disabled);
color: var(--components-button-danger-text-disabled);
}`
};
[role='spinner'] {
border-top-color: var(--components-button-danger-icon-default);
:before,:after {
background:var(--components-button-danger-icon-default);
}
}
`;
}
Expand All @@ -124,10 +159,18 @@ export const getButtonVariantStyles = (variant: ButtonVariant) => {
border: var(--border-sm) solid var(--components-button-danger-secondary-stroke-focus);
outline: none;
}

&:disabled {
background-color: var(--components-button-danger-secondary-background-disabled);
color:var(--components-button-danger-secondary-text-disabled);
${
!loading &&
`&:disabled {
background-color: var(--components-button-danger-secondary-background-disabled);
color:var(--components-button-danger-secondary-text-disabled);
}`
};
[role='spinner'] {
border-top-color: var(--components-button-danger-secondary-icon-default);
:before,:after {
background:var(--components-button-danger-secondary-icon-default);
}
}
`;
}
Expand All @@ -152,11 +195,20 @@ export const getButtonVariantStyles = (variant: ButtonVariant) => {
border: var(--border-sm) solid var(--components-button-outline-stroke-focus);
background-color: var(--components-button-outline-background-focus);
}

&:disabled {
border: none;
background-color: var(--components-button-tertiary-background-disabled);
color: var(--components-button-outline-text-disabled);

${
!loading &&
`&:disabled {
border: none;
background-color: var(--components-button-tertiary-background-disabled);
color: var(--components-button-outline-text-disabled);
}`
};
[role='spinner'] {
border-top-color: var(--components-button-outline-icon-default);
:before,:after {
background:var(--components-button-outline-icon-default);
}
}
`;
}
Expand Down Expand Up @@ -202,6 +254,10 @@ export const getButtonSizeStyles = ({
width: 16px;
height: 16px;
}
[role='spinner'] {
width: 10.66px;
height: 10.66px;
}

.icon-text > span {
height: 16px;
Expand Down Expand Up @@ -246,6 +302,10 @@ export const getButtonSizeStyles = ({
width: 24px;
height: 24px;
}
[role='spinner'] {
width: 16px;
height: 16px;
}

.icon-text > span {
height: 16px;
Expand Down Expand Up @@ -291,6 +351,10 @@ export const getButtonSizeStyles = ({
width: 24px;
height: 24px;
}
[role='spinner'] {
width: 16px;
height: 16px;
}

.icon-text > span {
height: 24px;
Expand Down Expand Up @@ -335,7 +399,10 @@ export const getButtonSizeStyles = ({
width: 32px;
height: 32px;
}

[role='spinner'] {
width: 21.333px;
height: 21.333px;
}
.icon-text > span {
height: 24px;
width: 24px;
Expand Down
1 change: 1 addition & 0 deletions src/blocks/spinner/Spinner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const Container = styled.div<{ css?: FlattenSimpleInterpolation; size: SpinnerSi
const Spinner: React.FC<SpinnerProps> = ({ size = 'small', css, variant = 'default' }) => {
return (
<Container
role="spinner"
size={size}
css={css}
variant={variant}
Expand Down
6 changes: 6 additions & 0 deletions src/blocks/theme/semantics/semantics.button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const primaryButtonSemantics = {
'background-hover': { light: colorBrands['primary-400'], dark: colorBrands['primary-400'] },
'background-pressed': { light: colorBrands['primary-800'], dark: colorBrands['primary-600'] },
'background-focus': { light: colorBrands['primary-500'], dark: colorBrands['primary-400'] },
'background-loading': { light: colorBrands['primary-400'], dark: colorBrands['primary-400'] },
'background-disabled': {
light: surfaceSemantics['state-disabled'].light,
dark: surfaceSemantics['state-disabled'].dark,
Expand All @@ -29,6 +30,7 @@ export const secondaryButtonSemantics = {
'background-hover': { light: colorBrands['neutral-200'], dark: colorBrands['neutral-700'] },
'background-pressed': { light: colorBrands['neutral-300'], dark: colorBrands['neutral-1000'] },
'background-focus': { light: colorBrands['neutral-100'], dark: colorBrands['neutral-800'] },
'background-loading': { light: colorBrands['neutral-100'], dark: colorBrands['neutral-800'] },
'background-disabled': {
light: surfaceSemantics['state-disabled'].light,
dark: surfaceSemantics['state-disabled'].dark,
Expand All @@ -49,6 +51,7 @@ export const tertiaryButtonSemantics = {
'background-hover': { light: colorBrands['neutral-900'], dark: colorBrands['neutral-300'] },
'background-pressed': { light: colorBrands['neutral-100'], dark: colorPrimitives['gray-1000'] },
'background-focus': { light: colorBrands['neutral-1000'], dark: colorBrands['neutral-700'] },
'background-loading': { light: colorBrands['neutral-900'], dark: colorBrands['neutral-700'] },
'background-disabled': {
light: surfaceSemantics['state-disabled'].light,
dark: surfaceSemantics['state-disabled'].dark,
Expand Down Expand Up @@ -81,6 +84,7 @@ export const outlineButtonSemantics = {

'stroke-default': { light: strokeSemantics['tertiary'].light, dark: strokeSemantics['tertiary'].dark },
'stroke-focus': { light: colorBrands['primary-300'], dark: colorBrands['primary-400'] },
'stroke-loading': { light: colorBrands['neutral-200'], dark: colorBrands['primary-400'] },
'stroke-hover': { light: strokeSemantics['brand-subtle'].light, dark: strokeSemantics['secondary'].dark },
'stroke-pressed': { light: colorBrands['neutral-600'], dark: colorBrands['neutral-300'] },
};
Expand All @@ -90,6 +94,7 @@ export const dangerButtonSemantics = {
'background-hover': { light: colorBrands['danger-500'], dark: colorBrands['danger-400'] },
'background-pressed': { light: colorBrands['danger-800'], dark: colorBrands['danger-700'] },
'background-focus': { light: colorBrands['danger-500'], dark: colorBrands['danger-400'] },
'background-loading': { light: colorBrands['danger-500'], dark: colorBrands['danger-400'] },
'background-disabled': {
light: surfaceSemantics['state-disabled'].light,
dark: surfaceSemantics['state-disabled'].dark,
Expand All @@ -109,6 +114,7 @@ export const dangerSecondaryButtonSemantics = {
'background-hover': { light: colorBrands['danger-100'], dark: colorBrands['danger-700'] },
'background-pressed': { light: colorBrands['danger-500'], dark: colorBrands['danger-1000'] },
'background-focus': { light: colorBrands['danger-100'], dark: colorBrands['danger-700'] },
'background-loading': { light: colorBrands['danger-100'], dark: colorBrands['danger-700'] },
'background-disabled': {
light: surfaceSemantics['state-disabled'].light,
dark: surfaceSemantics['state-disabled'].dark,
Expand Down
Loading