fix: Loading state changes button width (#25926)

Fixes #25890
This commit is contained in:
Pawan Kumar 2023-08-03 23:04:17 +05:30 committed by GitHub
parent 4ea8c95d9a
commit 56c795206e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 84 additions and 49 deletions

View File

@ -33,6 +33,11 @@ export interface ButtonProps extends Omit<HeadlessButtonProps, "className"> {
iconPosition?: (typeof BUTTON_ICON_POSITIONS)[keyof typeof BUTTON_ICON_POSITIONS]; iconPosition?: (typeof BUTTON_ICON_POSITIONS)[keyof typeof BUTTON_ICON_POSITIONS];
/** Makes the button visually and functionaly disabled but focusable */ /** Makes the button visually and functionaly disabled but focusable */
visuallyDisabled?: boolean; visuallyDisabled?: boolean;
/** Indicates the loading text that will be used by screen readers
* when the button is in loading state
* @default Loading...
*/
loadingText?: string;
} }
export const Button = forwardRef( export const Button = forwardRef(
@ -44,6 +49,7 @@ export const Button = forwardRef(
icon, icon,
iconPosition = "start", iconPosition = "start",
isLoading, isLoading,
loadingText = "Loading...",
// eslint-disable-next-line -- TODO add onKeyUp when the bug is fixed https://github.com/adobe/react-spectrum/issues/4350 // eslint-disable-next-line -- TODO add onKeyUp when the bug is fixed https://github.com/adobe/react-spectrum/issues/4350
onKeyUp, onKeyUp,
variant = "filled", variant = "filled",
@ -53,24 +59,21 @@ export const Button = forwardRef(
const { visuallyHiddenProps } = useVisuallyHidden(); const { visuallyHiddenProps } = useVisuallyHidden();
const renderChildren = () => { const renderChildren = () => {
if (isLoading) { return (
return ( <>
<> <span aria-hidden={isLoading ? true : undefined} data-content="">
{icon}
<Text lineClamp={1} textAlign="center">
{children}
</Text>
</span>
<span aria-hidden={!isLoading ? true : undefined} data-loader="">
<HeadlessIcon> <HeadlessIcon>
<Spinner /> <Spinner />
</HeadlessIcon> </HeadlessIcon>
{/* TODO(pawan): How to make sure "Loading..." text is internationalized? */} <span {...visuallyHiddenProps}>{loadingText}</span>
<span {...visuallyHiddenProps}>Loading...</span> </span>
</>
);
}
return (
<>
{icon}
<Text lineClamp={1} textAlign="center">
{children}
</Text>
</> </>
); );
}; };
@ -93,7 +96,7 @@ export const Button = forwardRef(
{...rest} {...rest}
> >
{renderChildren()} {renderChildren()}
<DragContainer data-hidden="" /> <DragContainer aria-hidden="true" />
</StyledButton> </StyledButton>
); );
}, },

View File

@ -35,7 +35,6 @@ export const buttonStyles = css<StyledButtonProps>`
background-color: transparent; background-color: transparent;
color: var(--color-fg-${$color}); color: var(--color-fg-${$color});
border-color: var(--color-bd-${$color}); border-color: var(--color-bd-${$color});
border-width: var(--border-width-1);
&[data-hovered]:not([aria-disabled]) { &[data-hovered]:not([aria-disabled]) {
background-color: var(--color-bg-${$color}-subtle-hover); background-color: var(--color-bg-${$color}-subtle-hover);
@ -52,7 +51,6 @@ export const buttonStyles = css<StyledButtonProps>`
background: transparent; background: transparent;
color: var(--color-fg-${$color}); color: var(--color-fg-${$color});
border-color: transparent; border-color: transparent;
border-width: 0;
&[data-hovered]:not([aria-disabled]) { &[data-hovered]:not([aria-disabled]) {
background: var(--color-bg-${$color}-subtle-hover); background: var(--color-bg-${$color}-subtle-hover);
@ -70,41 +68,18 @@ export const StyledButton = styled(HeadlessButton)<StyledButtonProps>`
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
cursor: pointer;
outline: 0; outline: 0;
padding: var(--spacing-2) var(--spacing-4); cursor: pointer;
block-size: var(--sizing-8);
border-radius: var(--border-radius-1);
user-select: none; user-select: none;
min-inline-size: var(--sizing-8);
position: relative; position: relative;
font-weight: 600; font-weight: 600;
border-width: 0;
border-style: solid;
font-family: inherit; font-family: inherit;
border-style: solid;
&[data-icon-position="start"] *:not([data-hidden]) + *:not([data-hidden]) { border-width: var(--border-width-1);
margin-inline-start: var(--spacing-1); padding-inline: var(--spacing-4);
} block-size: var(--sizing-8);
min-inline-size: var(--sizing-8);
&[data-icon-position="end"] *:not([data-hidden]) + *:not([data-hidden]) { border-radius: var(--border-radius-1);
margin-inline-end: var(--spacing-1);
}
${buttonStyles}
&[data-icon-position="end"] {
flex-direction: row-reverse;
}
/** Note: adding direct selector ">" here because blueprint also has data-icon attribute on their icons */
& > [data-icon] {
display: flex;
justify-content: center;
align-items: center;
height: var(--sizing-4);
width: var(--sizing-4);
}
// Note: adding important here as ADS is overriding the color of blueprint icon globally // Note: adding important here as ADS is overriding the color of blueprint icon globally
// TODO(pawan): Remove this once ADS team removes the global override // TODO(pawan): Remove this once ADS team removes the global override
@ -112,6 +87,44 @@ export const StyledButton = styled(HeadlessButton)<StyledButtonProps>`
color: currentColor !important; color: currentColor !important;
} }
${buttonStyles}
/**
* ----------------------------------------------------------------------------
* CONTENT
*-----------------------------------------------------------------------------
*/
& [data-content] {
display: flex;
justify-content: center;
align-items: center;
}
&[data-icon-position="start"] {
[data-content] *:not([data-hidden]) + *:not([data-hidden]) {
margin-inline-start: var(--spacing-1);
}
}
&[data-icon-position="end"] {
[data-content] *:not([data-hidden]) + *:not([data-hidden]) {
margin-inline-end: var(--spacing-1);
}
}
&[data-icon-position="end"] [data-content] {
flex-direction: row-reverse;
}
/** Note: adding direct selector ">" here because blueprint also has data-icon attribute on their icons */
& [data-content] > [data-icon] {
display: flex;
justify-content: center;
align-items: center;
height: var(--sizing-4);
width: var(--sizing-4);
}
/** /**
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* FOCUSSED * FOCUSSED
@ -133,14 +146,33 @@ export const StyledButton = styled(HeadlessButton)<StyledButtonProps>`
/** /**
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* LOADING * LOADING AND LOADER
*----------------------------------------------------------------------------- *-----------------------------------------------------------------------------
*/ */
&[data-loading] { &[data-loading] {
cursor: default; cursor: default;
/** adding opacity 1 here because we are lowering opacity for aria-disabled and when loading is true, aria-disabled is also true */ /** adding opacity 1 here because we are lowering opacity for aria-disabled and when loading is true, aria-disabled is also true */
opacity: 1; opacity: 1;
} }
&[data-loading] [data-content] {
visibility: hidden;
}
& [data-loader] {
display: none;
}
&[data-loading] [data-loader] {
display: block;
position: absolute;
inset: 0;
display: flex;
justify-content: center;
align-items: center;
border-radius: inherit;
}
`; `;
/** /**