From a1c03e2deb52c9113777bd09801fb07b3fde1bc4 Mon Sep 17 00:00:00 2001
From: langermank <18661030+langermank@users.noreply.github.com>
Date: Tue, 1 Aug 2023 11:24:41 -0700
Subject: [PATCH 01/51] draft loading state
---
src/Button/Button.features.stories.tsx | 2 +
src/Button/Button.stories.tsx | 5 ++
src/Button/ButtonBase.tsx | 83 ++++++++++++++++----------
src/Button/styles.ts | 38 ++++++------
src/Button/types.ts | 1 +
5 files changed, 79 insertions(+), 50 deletions(-)
diff --git a/src/Button/Button.features.stories.tsx b/src/Button/Button.features.stories.tsx
index c92ffa956d9..adf63db7c7a 100644
--- a/src/Button/Button.features.stories.tsx
+++ b/src/Button/Button.features.stories.tsx
@@ -87,3 +87,5 @@ export const Small = () =>
export const Medium = () =>
export const Large = () =>
+
+export const Loading = () =>
diff --git a/src/Button/Button.stories.tsx b/src/Button/Button.stories.tsx
index daa7ec54ee3..e3cc33c17cf 100644
--- a/src/Button/Button.stories.tsx
+++ b/src/Button/Button.stories.tsx
@@ -35,6 +35,11 @@ export default {
type: 'boolean',
},
},
+ loading: {
+ control: {
+ type: 'boolean',
+ },
+ },
leadingIcon: OcticonArgType([EyeClosedIcon, EyeIcon, SearchIcon, XIcon, HeartIcon]),
trailingIcon: OcticonArgType([EyeClosedIcon, EyeIcon, SearchIcon, XIcon, HeartIcon]),
trailingAction: OcticonArgType([TriangleDownIcon]),
diff --git a/src/Button/ButtonBase.tsx b/src/Button/ButtonBase.tsx
index 18e38f40df8..10c7ad28272 100644
--- a/src/Button/ButtonBase.tsx
+++ b/src/Button/ButtonBase.tsx
@@ -7,6 +7,8 @@ import {ButtonProps, StyledButton} from './types'
import {getVariantStyles, getButtonStyles, getAlignContentSize} from './styles'
import {useRefObjectAsForwardedRef} from '../hooks/useRefObjectAsForwardedRef'
import {defaultSxProp} from '../utils/defaultSxProp'
+import VisuallyHidden from '../_VisuallyHidden'
+import Spinner from '../Spinner'
const ButtonBase = forwardRef(
({children, as: Component = 'button', sx: sxProp = defaultSxProp, ...props}, forwardedRef): JSX.Element => {
@@ -19,6 +21,7 @@ const ButtonBase = forwardRef(
size = 'medium',
alignContent = 'center',
block = false,
+ loading = false,
...rest
} = props
@@ -57,41 +60,59 @@ const ButtonBase = forwardRef(
}, [innerRef])
}
+ //
+ //
+ // visually hidden [message for screen reader]
+ //
+
return (
-
- {Icon ? (
-
- ) : (
- <>
-
- {LeadingIcon && (
-
-
-
- )}
- {children && {children}}
- {TrailingIcon && (
-
-
+ <>
+
+ {Icon ? (
+
+ ) : (
+ <>
+
+ {loading && (
+
+
+
+ )}
+ {LeadingIcon && !loading && (
+
+
+
+ )}
+ {children && {children}}
+ {TrailingIcon && (
+
+
+
+ )}
+
+ {TrailingAction && (
+
+
)}
-
- {TrailingAction && (
-
-
-
- )}
- >
+ >
+ )}
+
+ {loading && (
+
+ Loading
+
)}
-
+ >
)
},
) as PolymorphicForwardRefComponent<'button' | 'a', ButtonProps>
diff --git a/src/Button/styles.ts b/src/Button/styles.ts
index f2cfdf6fbb8..dcf1cec18a0 100644
--- a/src/Button/styles.ts
+++ b/src/Button/styles.ts
@@ -7,15 +7,15 @@ export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme
color: 'btn.text',
backgroundColor: 'btn.bg',
boxShadow: `${theme?.shadows.btn.shadow}, ${theme?.shadows.btn.insetShadow}`,
- '&:hover:not([disabled])': {
+ '&:hover:not([disabled]):not([aria-disabled])': {
backgroundColor: 'btn.hoverBg',
borderColor: 'btn.hoverBorder',
},
- '&:active:not([disabled])': {
+ '&:active:not([disabled]):not([aria-disabled])': {
backgroundColor: 'btn.activeBg',
borderColor: 'btn.activeBorder',
},
- '&:disabled': {
+ '&:disabled, &[aria-disabled]': {
color: 'primer.fg.disabled',
'[data-component=ButtonCounter]': {
color: 'inherit',
@@ -34,21 +34,21 @@ export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme
backgroundColor: 'btn.primary.bg',
borderColor: 'btn.primary.border',
boxShadow: `${theme?.shadows.btn.primary.shadow}`,
- '&:hover:not([disabled])': {
+ '&:hover:not([disabled]):not([aria-disabled])': {
color: 'btn.primary.hoverText',
backgroundColor: 'btn.primary.hoverBg',
},
- '&:focus:not([disabled])': {
+ '&:focus:not([disabled]):not([aria-disabled])': {
boxShadow: 'inset 0 0 0 3px',
},
- '&:focus-visible:not([disabled])': {
+ '&:focus-visible:not([disabled]):not([aria-disabled])': {
boxShadow: 'inset 0 0 0 3px',
},
- '&:active:not([disabled])': {
+ '&:active:not([disabled]):not([aria-disabled])': {
backgroundColor: 'btn.primary.selectedBg',
boxShadow: `${theme?.shadows.btn.primary.selectedShadow}`,
},
- '&:disabled': {
+ '&:disabled, &[aria-disabled]': {
color: 'btn.primary.disabledText',
backgroundColor: 'btn.primary.disabledBg',
'[data-component=ButtonCounter]': {
@@ -68,7 +68,7 @@ export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme
color: 'btn.danger.text',
backgroundColor: 'btn.bg',
boxShadow: `${theme?.shadows.btn.shadow}`,
- '&:hover:not([disabled])': {
+ '&:hover:not([disabled]):not([aria-disabled])': {
color: 'btn.danger.hoverText',
backgroundColor: 'btn.danger.hoverBg',
borderColor: 'btn.danger.hoverBorder',
@@ -78,13 +78,13 @@ export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme
color: 'btn.danger.hoverCounterFg',
},
},
- '&:active:not([disabled])': {
+ '&:active:not([disabled]):not([aria-disabled])': {
color: 'btn.danger.selectedText',
backgroundColor: 'btn.danger.selectedBg',
boxShadow: `${theme?.shadows.btn.danger.selectedShadow}`,
borderColor: 'btn.danger.selectedBorder',
},
- '&:disabled': {
+ '&:disabled, &[aria-disabled]': {
color: 'btn.danger.disabledText',
backgroundColor: 'btn.danger.disabledBg',
borderColor: 'btn.danger.disabledBorder',
@@ -109,13 +109,13 @@ export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme
backgroundColor: 'transparent',
borderColor: 'transparent',
boxShadow: 'none',
- '&:hover:not([disabled])': {
+ '&:hover:not([disabled]):not([aria-disabled])': {
backgroundColor: 'btn.hoverBg',
},
- '&:active:not([disabled])': {
+ '&:active:not([disabled]):not([aria-disabled])': {
backgroundColor: 'btn.selectedBg',
},
- '&:disabled': {
+ '&:disabled, &[aria-disabled]': {
color: 'primer.fg.disabled',
'[data-component=ButtonCounter], [data-component="leadingVisual"], [data-component="trailingAction"]': {
color: 'inherit',
@@ -139,7 +139,7 @@ export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme
'&:has([data-component="ButtonCounter"])': {
color: 'accent.fg',
},
- '&:disabled[data-no-visuals]': {
+ '&:disabled[data-no-visuals], &[aria-disabled][data-no-visuals]': {
color: 'primer.fg.disabled',
'[data-component=ButtonCounter]': {
color: 'inherit',
@@ -152,7 +152,7 @@ export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme
borderColor: 'btn.border',
backgroundColor: 'btn.bg',
- '&:hover:not([disabled])': {
+ '&:hover:not([disabled]):not([aria-disabled])': {
color: 'btn.outline.hoverText',
backgroundColor: 'btn.outline.hoverBg',
borderColor: 'btn.outline.hoverBorder',
@@ -162,14 +162,14 @@ export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme
color: 'btn.outline.hoverCounterFg',
},
},
- '&:active:not([disabled])': {
+ '&:active:not([disabled]):not([aria-disabled])': {
color: 'btn.outline.selectedText',
backgroundColor: 'btn.outline.selectedBg',
boxShadow: `${theme?.shadows.btn.outline.selectedShadow}`,
borderColor: 'btn.outline.selectedBorder',
},
- '&:disabled': {
+ '&:disabled, &[aria-disabled]': {
color: 'btn.outline.disabledText',
backgroundColor: 'btn.outline.disabledBg',
borderColor: 'btn.border',
@@ -226,7 +226,7 @@ export const getBaseStyles = (theme?: Theme) => ({
'&:active': {
transition: 'none',
},
- '&:disabled': {
+ '&:disabled, &[aria-disabled]': {
cursor: 'not-allowed',
boxShadow: 'none',
},
diff --git a/src/Button/types.ts b/src/Button/types.ts
index bccc1c0761c..7ec34dc48cd 100644
--- a/src/Button/types.ts
+++ b/src/Button/types.ts
@@ -35,6 +35,7 @@ export type ButtonBaseProps = {
* Allow button width to fill its container.
*/
block?: boolean
+ loading?: boolean
} & SxProp &
React.ButtonHTMLAttributes
From cfd094410cdb807e51c4d06058be4f555269dd2b Mon Sep 17 00:00:00 2001
From: langermank <18661030+langermank@users.noreply.github.com>
Date: Tue, 1 Aug 2023 11:25:52 -0700
Subject: [PATCH 02/51] cleanup
---
src/Button/ButtonBase.tsx | 5 -----
1 file changed, 5 deletions(-)
diff --git a/src/Button/ButtonBase.tsx b/src/Button/ButtonBase.tsx
index 10c7ad28272..ad3137407ab 100644
--- a/src/Button/ButtonBase.tsx
+++ b/src/Button/ButtonBase.tsx
@@ -60,11 +60,6 @@ const ButtonBase = forwardRef(
}, [innerRef])
}
- //
- //
- // visually hidden [message for screen reader]
- //
-
return (
<>
Date: Tue, 1 Aug 2023 11:29:10 -0700
Subject: [PATCH 03/51] add story to trigger loading
---
src/Button/Button.features.stories.tsx | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/src/Button/Button.features.stories.tsx b/src/Button/Button.features.stories.tsx
index adf63db7c7a..8ff1c765f4a 100644
--- a/src/Button/Button.features.stories.tsx
+++ b/src/Button/Button.features.stories.tsx
@@ -1,4 +1,4 @@
-import {EyeIcon, TriangleDownIcon, HeartIcon} from '@primer/octicons-react'
+import {EyeIcon, TriangleDownIcon, HeartIcon, DownloadIcon} from '@primer/octicons-react'
import React, {useState} from 'react'
import {Button} from '.'
@@ -89,3 +89,17 @@ export const Medium = () =>
export const Large = () =>
export const Loading = () =>
+
+export const LoadingTrigger = () => {
+ const [isLoading, setIsLoading] = useState(false)
+
+ const handleClick = () => {
+ setIsLoading(true)
+ }
+
+ return (
+
+ )
+}
From a9a7771503dff3db38251a3cdfeb1caf53556c4b Mon Sep 17 00:00:00 2001
From: langermank <18661030+langermank@users.noreply.github.com>
Date: Thu, 28 Sep 2023 12:55:21 -0700
Subject: [PATCH 04/51] merge
---
src/Button/ButtonBase.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Button/ButtonBase.tsx b/src/Button/ButtonBase.tsx
index 3d71573c4c3..18ba78b5ce4 100644
--- a/src/Button/ButtonBase.tsx
+++ b/src/Button/ButtonBase.tsx
@@ -88,13 +88,13 @@ const ButtonBase = forwardRef(
)}
{LeadingVisual && !loading && (
-
+
)}
{children && {children}}
{TrailingVisual && (
-
+
)}
From 72a02473572c3e4933c43fc9b23150d89bd92947 Mon Sep 17 00:00:00 2001
From: langermank <18661030+langermank@users.noreply.github.com>
Date: Wed, 11 Oct 2023 14:49:49 -0700
Subject: [PATCH 05/51] icon button
---
src/Button/Button.features.stories.tsx | 3 +++
src/Button/ButtonBase.tsx | 11 +++++++++--
src/Button/IconButton.features.stories.tsx | 19 +++++++++++++++++--
3 files changed, 29 insertions(+), 4 deletions(-)
diff --git a/src/Button/Button.features.stories.tsx b/src/Button/Button.features.stories.tsx
index ead327bebf6..a820ba5013e 100644
--- a/src/Button/Button.features.stories.tsx
+++ b/src/Button/Button.features.stories.tsx
@@ -95,6 +95,9 @@ export const LoadingTrigger = () => {
const handleClick = () => {
setIsLoading(true)
+ setTimeout(() => {
+ setIsLoading(false)
+ }, 3000)
}
return (
diff --git a/src/Button/ButtonBase.tsx b/src/Button/ButtonBase.tsx
index 18ba78b5ce4..a77963d5c99 100644
--- a/src/Button/ButtonBase.tsx
+++ b/src/Button/ButtonBase.tsx
@@ -75,9 +75,14 @@ const ButtonBase = forwardRef(
data-size={size === 'small' || size === 'large' ? size : undefined}
data-no-visuals={!LeadingVisual && !TrailingVisual && !TrailingAction ? true : undefined}
aria-disabled={loading ? true : undefined}
+ aria-describedby={loading ? 'loading-message' : undefined}
>
{Icon ? (
-
+ loading ? (
+
+ ) : (
+
+ )
) : (
<>
@@ -108,7 +113,9 @@ const ButtonBase = forwardRef(
{loading && (
- Loading
+
+ Loading
+
)}
>
diff --git a/src/Button/IconButton.features.stories.tsx b/src/Button/IconButton.features.stories.tsx
index 2f8b979aac3..2c9a1693bcb 100644
--- a/src/Button/IconButton.features.stories.tsx
+++ b/src/Button/IconButton.features.stories.tsx
@@ -1,5 +1,5 @@
-import {HeartIcon} from '@primer/octicons-react'
-import React from 'react'
+import {HeartIcon, DownloadIcon} from '@primer/octicons-react'
+import React, {useState} from 'react'
import {IconButton} from '.'
export default {
@@ -19,3 +19,18 @@ export const Small = () =>
export const Large = () =>
+
+export const Loading = () =>
+
+export const LoadingTrigger = () => {
+ const [isLoading, setIsLoading] = useState(false)
+
+ const handleClick = () => {
+ setIsLoading(true)
+ setTimeout(() => {
+ setIsLoading(false)
+ }, 3000)
+ }
+
+ return
+}
From 71b747db2075a1dfe5f310ca4186aee008f58e3a Mon Sep 17 00:00:00 2001
From: Katie Langerman <18661030+langermank@users.noreply.github.com>
Date: Wed, 11 Oct 2023 15:00:58 -0700
Subject: [PATCH 06/51] Create lazy-jobs-pump.md
---
.changeset/lazy-jobs-pump.md | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 .changeset/lazy-jobs-pump.md
diff --git a/.changeset/lazy-jobs-pump.md b/.changeset/lazy-jobs-pump.md
new file mode 100644
index 00000000000..d57adc23a22
--- /dev/null
+++ b/.changeset/lazy-jobs-pump.md
@@ -0,0 +1,5 @@
+---
+"@primer/react": minor
+---
+
+Add `loading` state to `Button` and `IconButton`
From 556aff9c36e88a1b6b3eee3a5f994dea6806bf44 Mon Sep 17 00:00:00 2001
From: langermank <18661030+langermank@users.noreply.github.com>
Date: Wed, 11 Oct 2023 15:05:50 -0700
Subject: [PATCH 07/51] add prop for loading message
---
src/Button/Button.features.stories.tsx | 6 ++++++
src/Button/ButtonBase.tsx | 3 ++-
src/Button/types.ts | 1 +
3 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/src/Button/Button.features.stories.tsx b/src/Button/Button.features.stories.tsx
index a820ba5013e..12aff176762 100644
--- a/src/Button/Button.features.stories.tsx
+++ b/src/Button/Button.features.stories.tsx
@@ -106,3 +106,9 @@ export const LoadingTrigger = () => {
)
}
+
+export const LoadingCustomMessage = () => (
+
+)
diff --git a/src/Button/ButtonBase.tsx b/src/Button/ButtonBase.tsx
index a77963d5c99..7daa151d96d 100644
--- a/src/Button/ButtonBase.tsx
+++ b/src/Button/ButtonBase.tsx
@@ -24,6 +24,7 @@ const ButtonBase = forwardRef(
alignContent = 'center',
block = false,
loading = false,
+ loadingMessage = 'Loading',
...rest
} = props
const LeadingVisual = leadingVisual ?? leadingIcon
@@ -114,7 +115,7 @@ const ButtonBase = forwardRef(
{loading && (
- Loading
+ {loadingMessage}
)}
diff --git a/src/Button/types.ts b/src/Button/types.ts
index 60aa28dd663..dd4cae21e09 100644
--- a/src/Button/types.ts
+++ b/src/Button/types.ts
@@ -36,6 +36,7 @@ export type ButtonBaseProps = {
*/
block?: boolean
loading?: boolean
+ loadingMessage?: string
} & SxProp &
React.ButtonHTMLAttributes
From 6f9851181ccf3d10a355c4efc1ffb0796435abd1 Mon Sep 17 00:00:00 2001
From: langermank <18661030+langermank@users.noreply.github.com>
Date: Tue, 17 Oct 2023 08:26:17 -0700
Subject: [PATCH 08/51] handle no visuals loading state
---
src/Button/Button.features.stories.tsx | 38 ++++++++++++++++++++++++--
src/Button/ButtonBase.tsx | 14 ++++++++--
src/Button/styles.ts | 8 ++++++
3 files changed, 55 insertions(+), 5 deletions(-)
diff --git a/src/Button/Button.features.stories.tsx b/src/Button/Button.features.stories.tsx
index 12aff176762..787f9a8aa13 100644
--- a/src/Button/Button.features.stories.tsx
+++ b/src/Button/Button.features.stories.tsx
@@ -88,9 +88,7 @@ export const Medium = () =>
export const Large = () =>
-export const Loading = () =>
-
-export const LoadingTrigger = () => {
+export const LoadingWithLeadingVisual = () => {
const [isLoading, setIsLoading] = useState(false)
const handleClick = () => {
@@ -112,3 +110,37 @@ export const LoadingCustomMessage = () => (
Default
)
+
+export const LoadingWithNoVisuals = () => {
+ const [isLoading, setIsLoading] = useState(false)
+
+ const handleClick = () => {
+ setIsLoading(true)
+ setTimeout(() => {
+ setIsLoading(false)
+ }, 3000)
+ }
+
+ return (
+
+ )
+}
+
+export const LoadingWithTrailingVisual = () => {
+ const [isLoading, setIsLoading] = useState(false)
+
+ const handleClick = () => {
+ setIsLoading(true)
+ setTimeout(() => {
+ setIsLoading(false)
+ }, 3000)
+ }
+
+ return (
+
+ )
+}
diff --git a/src/Button/ButtonBase.tsx b/src/Button/ButtonBase.tsx
index 7daa151d96d..3725564f1f4 100644
--- a/src/Button/ButtonBase.tsx
+++ b/src/Button/ButtonBase.tsx
@@ -87,7 +87,12 @@ const ButtonBase = forwardRef(
) : (
<>
- {loading && (
+ {loading && !LeadingVisual && !TrailingVisual && (
+
+
+
+ )}
+ {LeadingVisual && loading && (
@@ -98,11 +103,16 @@ const ButtonBase = forwardRef(
)}
{children && {children}}
- {TrailingVisual && (
+ {TrailingVisual && !loading && (
)}
+ {TrailingVisual && loading && (
+
+
+
+ )}
{TrailingAction && (
diff --git a/src/Button/styles.ts b/src/Button/styles.ts
index e181f5bb4bc..3a6b1da5a00 100644
--- a/src/Button/styles.ts
+++ b/src/Button/styles.ts
@@ -322,6 +322,14 @@ export const getButtonStyles = (theme?: Theme) => {
'[data-component="buttonContent"] > :not(:last-child)': {
mr: '8px',
},
+ '[data-component="loadingSpinner"]': {
+ gridArea: 'text',
+ marginRight: '0px !important',
+ placeSelf: 'center',
+ },
+ '[data-component="loadingSpinner"] + [data-component="text"]': {
+ visibility: 'hidden',
+ },
}
return styles
}
From ee21a634a0ee35b082d1c806c0462067dfd63ac1 Mon Sep 17 00:00:00 2001
From: Mike Perrotti
Date: Tue, 28 Nov 2023 10:59:47 -0500
Subject: [PATCH 09/51] updates snapshots after merging from main
---
.../__snapshots__/Button.test.tsx.snap | 180 ++++++++++++++----
src/Dialog/__snapshots__/Dialog.test.tsx.snap | 34 +++-
.../__snapshots__/SelectPanel.test.tsx.snap | 20 +-
.../__snapshots__/ActionMenu.test.tsx.snap | 20 +-
.../__snapshots__/TextInput.test.tsx.snap | 102 +++++++---
5 files changed, 277 insertions(+), 79 deletions(-)
diff --git a/src/Button/__tests__/__snapshots__/Button.test.tsx.snap b/src/Button/__tests__/__snapshots__/Button.test.tsx.snap
index 1d0805e2466..c22be681799 100644
--- a/src/Button/__tests__/__snapshots__/Button.test.tsx.snap
+++ b/src/Button/__tests__/__snapshots__/Button.test.tsx.snap
@@ -91,13 +91,15 @@ exports[`Button renders consistently 1`] = `
transition: none;
}
-.c0:disabled {
+.c0:disabled,
+.c0[aria-disabled] {
cursor: not-allowed;
box-shadow: none;
color: #8c959f;
}
-.c0:disabled [data-component=ButtonCounter] {
+.c0:disabled [data-component=ButtonCounter],
+.c0[aria-disabled] [data-component=ButtonCounter] {
color: inherit;
}
@@ -194,12 +196,22 @@ exports[`Button renders consistently 1`] = `
margin-right: 8px;
}
-.c0:hover:not([disabled]) {
+.c0 [data-component="loadingSpinner"] {
+ grid-area: text;
+ margin-right: 0px !important;
+ place-self: center;
+}
+
+.c0 [data-component="loadingSpinner"] + [data-component="text"] {
+ visibility: hidden;
+}
+
+.c0:hover:not([disabled]):not([aria-disabled]) {
background-color: #f3f4f6;
border-color: var(--button-default-borderColor-hover,rgba(31,35,40,0.15));
}
-.c0:active:not([disabled]) {
+.c0:active:not([disabled]):not([aria-disabled]) {
background-color: hsla(220,14%,93%,1);
border-color: var(--button-default-borderColor-active,rgba(31,35,40,0.15));
}
@@ -326,13 +338,15 @@ exports[`Button respects block prop 1`] = `
transition: none;
}
-.c0:disabled {
+.c0:disabled,
+.c0[aria-disabled] {
cursor: not-allowed;
box-shadow: none;
color: primer.fg.disabled;
}
-.c0:disabled [data-component=ButtonCounter] {
+.c0:disabled [data-component=ButtonCounter],
+.c0[aria-disabled] [data-component=ButtonCounter] {
color: inherit;
}
@@ -429,12 +443,22 @@ exports[`Button respects block prop 1`] = `
margin-right: 8px;
}
-.c0:hover:not([disabled]) {
+.c0 [data-component="loadingSpinner"] {
+ grid-area: text;
+ margin-right: 0px !important;
+ place-self: center;
+}
+
+.c0 [data-component="loadingSpinner"] + [data-component="text"] {
+ visibility: hidden;
+}
+
+.c0:hover:not([disabled]):not([aria-disabled]) {
background-color: btn.hoverBg;
border-color: var(--button-default-borderColor-hover,undefined);
}
-.c0:active:not([disabled]) {
+.c0:active:not([disabled]):not([aria-disabled]) {
background-color: btn.activeBg;
border-color: var(--button-default-borderColor-active,undefined);
}
@@ -566,13 +590,15 @@ exports[`Button respects the alignContent prop 1`] = `
transition: none;
}
-.c0:disabled {
+.c0:disabled,
+.c0[aria-disabled] {
cursor: not-allowed;
box-shadow: none;
color: primer.fg.disabled;
}
-.c0:disabled [data-component=ButtonCounter] {
+.c0:disabled [data-component=ButtonCounter],
+.c0[aria-disabled] [data-component=ButtonCounter] {
color: inherit;
}
@@ -669,12 +695,22 @@ exports[`Button respects the alignContent prop 1`] = `
margin-right: 8px;
}
-.c0:hover:not([disabled]) {
+.c0 [data-component="loadingSpinner"] {
+ grid-area: text;
+ margin-right: 0px !important;
+ place-self: center;
+}
+
+.c0 [data-component="loadingSpinner"] + [data-component="text"] {
+ visibility: hidden;
+}
+
+.c0:hover:not([disabled]):not([aria-disabled]) {
background-color: btn.hoverBg;
border-color: var(--button-default-borderColor-hover,undefined);
}
-.c0:active:not([disabled]) {
+.c0:active:not([disabled]):not([aria-disabled]) {
background-color: btn.activeBg;
border-color: var(--button-default-borderColor-active,undefined);
}
@@ -805,13 +841,15 @@ exports[`Button respects the large size prop 1`] = `
transition: none;
}
-.c0:disabled {
+.c0:disabled,
+.c0[aria-disabled] {
cursor: not-allowed;
box-shadow: none;
color: primer.fg.disabled;
}
-.c0:disabled [data-component=ButtonCounter] {
+.c0:disabled [data-component=ButtonCounter],
+.c0[aria-disabled] [data-component=ButtonCounter] {
color: inherit;
}
@@ -908,12 +946,22 @@ exports[`Button respects the large size prop 1`] = `
margin-right: 8px;
}
-.c0:hover:not([disabled]) {
+.c0 [data-component="loadingSpinner"] {
+ grid-area: text;
+ margin-right: 0px !important;
+ place-self: center;
+}
+
+.c0 [data-component="loadingSpinner"] + [data-component="text"] {
+ visibility: hidden;
+}
+
+.c0:hover:not([disabled]):not([aria-disabled]) {
background-color: btn.hoverBg;
border-color: var(--button-default-borderColor-hover,undefined);
}
-.c0:active:not([disabled]) {
+.c0:active:not([disabled]):not([aria-disabled]) {
background-color: btn.activeBg;
border-color: var(--button-default-borderColor-active,undefined);
}
@@ -1045,13 +1093,15 @@ exports[`Button respects the small size prop 1`] = `
transition: none;
}
-.c0:disabled {
+.c0:disabled,
+.c0[aria-disabled] {
cursor: not-allowed;
box-shadow: none;
color: primer.fg.disabled;
}
-.c0:disabled [data-component=ButtonCounter] {
+.c0:disabled [data-component=ButtonCounter],
+.c0[aria-disabled] [data-component=ButtonCounter] {
color: inherit;
}
@@ -1148,12 +1198,22 @@ exports[`Button respects the small size prop 1`] = `
margin-right: 8px;
}
-.c0:hover:not([disabled]) {
+.c0 [data-component="loadingSpinner"] {
+ grid-area: text;
+ margin-right: 0px !important;
+ place-self: center;
+}
+
+.c0 [data-component="loadingSpinner"] + [data-component="text"] {
+ visibility: hidden;
+}
+
+.c0:hover:not([disabled]):not([aria-disabled]) {
background-color: btn.hoverBg;
border-color: var(--button-default-borderColor-hover,undefined);
}
-.c0:active:not([disabled]) {
+.c0:active:not([disabled]):not([aria-disabled]) {
background-color: btn.activeBg;
border-color: var(--button-default-borderColor-active,undefined);
}
@@ -1285,7 +1345,8 @@ exports[`Button styles danger button appropriately 1`] = `
transition: none;
}
-.c0:disabled {
+.c0:disabled,
+.c0[aria-disabled] {
cursor: not-allowed;
box-shadow: none;
color: btn.danger.disabledText;
@@ -1293,7 +1354,8 @@ exports[`Button styles danger button appropriately 1`] = `
border-color: btn.danger.disabledBorder;
}
-.c0:disabled [data-component=ButtonCounter] {
+.c0:disabled [data-component=ButtonCounter],
+.c0[aria-disabled] [data-component=ButtonCounter] {
color: btn.danger.disabledCounterFg;
background-color: btn.danger.disabledCounterBg;
}
@@ -1393,19 +1455,29 @@ exports[`Button styles danger button appropriately 1`] = `
margin-right: 8px;
}
-.c0:hover:not([disabled]) {
+.c0 [data-component="loadingSpinner"] {
+ grid-area: text;
+ margin-right: 0px !important;
+ place-self: center;
+}
+
+.c0 [data-component="loadingSpinner"] + [data-component="text"] {
+ visibility: hidden;
+}
+
+.c0:hover:not([disabled]):not([aria-disabled]) {
color: btn.danger.hoverText;
background-color: btn.danger.hoverBg;
border-color: btn.danger.hoverBorder;
box-shadow: undefined;
}
-.c0:hover:not([disabled]) [data-component=ButtonCounter] {
+.c0:hover:not([disabled]):not([aria-disabled]) [data-component=ButtonCounter] {
background-color: btn.danger.hoverCounterBg;
color: btn.danger.hoverCounterFg;
}
-.c0:active:not([disabled]) {
+.c0:active:not([disabled]):not([aria-disabled]) {
color: btn.danger.selectedText;
background-color: btn.danger.selectedBg;
box-shadow: undefined;
@@ -1517,11 +1589,13 @@ exports[`Button styles invisible button appropriately 1`] = `
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
display: inline-flex;
+ -webkit-text-decoration: var(--prefers-link-underlines,underline);
+ text-decoration: var(--prefers-link-underlines,underline);
}
.c0[href]:hover {
- -webkit-text-decoration: none;
- text-decoration: none;
+ -webkit-text-decoration: var(--prefers-link-underlines,underline);
+ text-decoration: var(--prefers-link-underlines,underline);
}
.c0:hover {
@@ -1534,15 +1608,19 @@ exports[`Button styles invisible button appropriately 1`] = `
transition: none;
}
-.c0:disabled {
+.c0:disabled,
+.c0[aria-disabled] {
cursor: not-allowed;
box-shadow: none;
color: primer.fg.disabled;
}
.c0:disabled [data-component=ButtonCounter],
+.c0[aria-disabled] [data-component=ButtonCounter],
.c0:disabled [data-component="leadingVisual"],
-.c0:disabled [data-component="trailingAction"] {
+.c0[aria-disabled] [data-component="leadingVisual"],
+.c0:disabled [data-component="trailingAction"],
+.c0[aria-disabled] [data-component="trailingAction"] {
color: inherit;
}
@@ -1641,11 +1719,21 @@ exports[`Button styles invisible button appropriately 1`] = `
margin-right: 8px;
}
-.c0:hover:not([disabled]) {
+.c0 [data-component="loadingSpinner"] {
+ grid-area: text;
+ margin-right: 0px !important;
+ place-self: center;
+}
+
+.c0 [data-component="loadingSpinner"] + [data-component="text"] {
+ visibility: hidden;
+}
+
+.c0:hover:not([disabled]):not([aria-disabled]) {
background-color: actionListItem.default.hoverBg;
}
-.c0:active:not([disabled]) {
+.c0:active:not([disabled]):not([aria-disabled]) {
background-color: actionListItem.default.activeBg;
}
@@ -1665,11 +1753,13 @@ exports[`Button styles invisible button appropriately 1`] = `
color: btn.text;
}
-.c0:disabled[data-no-visuals] {
+.c0:disabled[data-no-visuals],
+.c0[aria-disabled][data-no-visuals] {
color: primer.fg.disabled;
}
-.c0:disabled[data-no-visuals] [data-component=ButtonCounter] {
+.c0:disabled[data-no-visuals] [data-component=ButtonCounter],
+.c0[aria-disabled][data-no-visuals] [data-component=ButtonCounter] {
color: inherit;
}
@@ -1788,14 +1878,16 @@ exports[`Button styles primary button appropriately 1`] = `
transition: none;
}
-.c0:disabled {
+.c0:disabled,
+.c0[aria-disabled] {
cursor: not-allowed;
box-shadow: none;
color: btn.primary.disabledText;
background-color: btn.primary.disabledBg;
}
-.c0:disabled [data-component=ButtonCounter] {
+.c0:disabled [data-component=ButtonCounter],
+.c0[aria-disabled] [data-component=ButtonCounter] {
color: inherit;
}
@@ -1894,20 +1986,30 @@ exports[`Button styles primary button appropriately 1`] = `
margin-right: 8px;
}
-.c0:hover:not([disabled]) {
+.c0 [data-component="loadingSpinner"] {
+ grid-area: text;
+ margin-right: 0px !important;
+ place-self: center;
+}
+
+.c0 [data-component="loadingSpinner"] + [data-component="text"] {
+ visibility: hidden;
+}
+
+.c0:hover:not([disabled]):not([aria-disabled]) {
color: btn.primary.hoverText;
background-color: btn.primary.hoverBg;
}
-.c0:focus:not([disabled]) {
+.c0:focus:not([disabled]):not([aria-disabled]) {
box-shadow: inset 0 0 0 3px;
}
-.c0:focus-visible:not([disabled]) {
+.c0:focus-visible:not([disabled]):not([aria-disabled]) {
box-shadow: inset 0 0 0 3px;
}
-.c0:active:not([disabled]) {
+.c0:active:not([disabled]):not([aria-disabled]) {
background-color: btn.primary.selectedBg;
box-shadow: undefined;
}
diff --git a/src/Dialog/__snapshots__/Dialog.test.tsx.snap b/src/Dialog/__snapshots__/Dialog.test.tsx.snap
index cb0b5cfda3a..360d85bd449 100644
--- a/src/Dialog/__snapshots__/Dialog.test.tsx.snap
+++ b/src/Dialog/__snapshots__/Dialog.test.tsx.snap
@@ -147,11 +147,13 @@ exports[`Dialog renders consistently 1`] = `
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
display: inline-flex;
+ -webkit-text-decoration: var(--prefers-link-underlines,underline);
+ text-decoration: var(--prefers-link-underlines,underline);
}
.c1[href]:hover {
- -webkit-text-decoration: none;
- text-decoration: none;
+ -webkit-text-decoration: var(--prefers-link-underlines,underline);
+ text-decoration: var(--prefers-link-underlines,underline);
}
.c1:hover {
@@ -164,15 +166,19 @@ exports[`Dialog renders consistently 1`] = `
transition: none;
}
-.c1:disabled {
+.c1:disabled,
+.c1[aria-disabled] {
cursor: not-allowed;
box-shadow: none;
color: #8c959f;
}
.c1:disabled [data-component=ButtonCounter],
+.c1[aria-disabled] [data-component=ButtonCounter],
.c1:disabled [data-component="leadingVisual"],
-.c1:disabled [data-component="trailingAction"] {
+.c1[aria-disabled] [data-component="leadingVisual"],
+.c1:disabled [data-component="trailingAction"],
+.c1[aria-disabled] [data-component="trailingAction"] {
color: inherit;
}
@@ -271,11 +277,21 @@ exports[`Dialog renders consistently 1`] = `
margin-right: 8px;
}
-.c1:hover:not([disabled]) {
+.c1 [data-component="loadingSpinner"] {
+ grid-area: text;
+ margin-right: 0px !important;
+ place-self: center;
+}
+
+.c1 [data-component="loadingSpinner"] + [data-component="text"] {
+ visibility: hidden;
+}
+
+.c1:hover:not([disabled]):not([aria-disabled]) {
background-color: rgba(208,215,222,0.32);
}
-.c1:active:not([disabled]) {
+.c1:active:not([disabled]):not([aria-disabled]) {
background-color: rgba(208,215,222,0.48);
}
@@ -298,11 +314,13 @@ exports[`Dialog renders consistently 1`] = `
color: #24292f;
}
-.c1:disabled[data-no-visuals] {
+.c1:disabled[data-no-visuals],
+.c1[aria-disabled][data-no-visuals] {
color: #8c959f;
}
-.c1:disabled[data-no-visuals] [data-component=ButtonCounter] {
+.c1:disabled[data-no-visuals] [data-component=ButtonCounter],
+.c1[aria-disabled][data-no-visuals] [data-component=ButtonCounter] {
color: inherit;
}
diff --git a/src/SelectPanel/__snapshots__/SelectPanel.test.tsx.snap b/src/SelectPanel/__snapshots__/SelectPanel.test.tsx.snap
index 7d696d62efc..bfd50cfdc2a 100644
--- a/src/SelectPanel/__snapshots__/SelectPanel.test.tsx.snap
+++ b/src/SelectPanel/__snapshots__/SelectPanel.test.tsx.snap
@@ -105,13 +105,15 @@ exports[`SelectPanel renders consistently 1`] = `
transition: none;
}
-.c1:disabled {
+.c1:disabled,
+.c1[aria-disabled] {
cursor: not-allowed;
box-shadow: none;
color: #8c959f;
}
-.c1:disabled [data-component=ButtonCounter] {
+.c1:disabled [data-component=ButtonCounter],
+.c1[aria-disabled] [data-component=ButtonCounter] {
color: inherit;
}
@@ -208,12 +210,22 @@ exports[`SelectPanel renders consistently 1`] = `
margin-right: 8px;
}
-.c1:hover:not([disabled]) {
+.c1 [data-component="loadingSpinner"] {
+ grid-area: text;
+ margin-right: 0px !important;
+ place-self: center;
+}
+
+.c1 [data-component="loadingSpinner"] + [data-component="text"] {
+ visibility: hidden;
+}
+
+.c1:hover:not([disabled]):not([aria-disabled]) {
background-color: #f3f4f6;
border-color: var(--button-default-borderColor-hover,rgba(31,35,40,0.15));
}
-.c1:active:not([disabled]) {
+.c1:active:not([disabled]):not([aria-disabled]) {
background-color: hsla(220,14%,93%,1);
border-color: var(--button-default-borderColor-active,rgba(31,35,40,0.15));
}
diff --git a/src/__tests__/__snapshots__/ActionMenu.test.tsx.snap b/src/__tests__/__snapshots__/ActionMenu.test.tsx.snap
index 0893c7502ea..4deb48aab6b 100644
--- a/src/__tests__/__snapshots__/ActionMenu.test.tsx.snap
+++ b/src/__tests__/__snapshots__/ActionMenu.test.tsx.snap
@@ -105,13 +105,15 @@ exports[`ActionMenu renders consistently 1`] = `
transition: none;
}
-.c1:disabled {
+.c1:disabled,
+.c1[aria-disabled] {
cursor: not-allowed;
box-shadow: none;
color: #8c959f;
}
-.c1:disabled [data-component=ButtonCounter] {
+.c1:disabled [data-component=ButtonCounter],
+.c1[aria-disabled] [data-component=ButtonCounter] {
color: inherit;
}
@@ -208,12 +210,22 @@ exports[`ActionMenu renders consistently 1`] = `
margin-right: 8px;
}
-.c1:hover:not([disabled]) {
+.c1 [data-component="loadingSpinner"] {
+ grid-area: text;
+ margin-right: 0px !important;
+ place-self: center;
+}
+
+.c1 [data-component="loadingSpinner"] + [data-component="text"] {
+ visibility: hidden;
+}
+
+.c1:hover:not([disabled]):not([aria-disabled]) {
background-color: #f3f4f6;
border-color: var(--button-default-borderColor-hover,rgba(31,35,40,0.15));
}
-.c1:active:not([disabled]) {
+.c1:active:not([disabled]):not([aria-disabled]) {
background-color: hsla(220,14%,93%,1);
border-color: var(--button-default-borderColor-active,rgba(31,35,40,0.15));
}
diff --git a/src/__tests__/__snapshots__/TextInput.test.tsx.snap b/src/__tests__/__snapshots__/TextInput.test.tsx.snap
index 9fff506b6ce..e91998a0131 100644
--- a/src/__tests__/__snapshots__/TextInput.test.tsx.snap
+++ b/src/__tests__/__snapshots__/TextInput.test.tsx.snap
@@ -1749,11 +1749,13 @@ exports[`TextInput renders trailingAction icon button 1`] = `
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
display: inline-flex;
+ -webkit-text-decoration: var(--prefers-link-underlines,underline);
+ text-decoration: var(--prefers-link-underlines,underline);
}
.c5[href]:hover {
- -webkit-text-decoration: none;
- text-decoration: none;
+ -webkit-text-decoration: var(--prefers-link-underlines,underline);
+ text-decoration: var(--prefers-link-underlines,underline);
}
.c5:hover {
@@ -1766,15 +1768,19 @@ exports[`TextInput renders trailingAction icon button 1`] = `
transition: none;
}
-.c5:disabled {
+.c5:disabled,
+.c5[aria-disabled] {
cursor: not-allowed;
box-shadow: none;
color: #8c959f;
}
.c5:disabled [data-component=ButtonCounter],
+.c5[aria-disabled] [data-component=ButtonCounter],
.c5:disabled [data-component="leadingVisual"],
-.c5:disabled [data-component="trailingAction"] {
+.c5[aria-disabled] [data-component="leadingVisual"],
+.c5:disabled [data-component="trailingAction"],
+.c5[aria-disabled] [data-component="trailingAction"] {
color: inherit;
}
@@ -1873,11 +1879,21 @@ exports[`TextInput renders trailingAction icon button 1`] = `
margin-right: 8px;
}
-.c5:hover:not([disabled]) {
+.c5 [data-component="loadingSpinner"] {
+ grid-area: text;
+ margin-right: 0px !important;
+ place-self: center;
+}
+
+.c5 [data-component="loadingSpinner"] + [data-component="text"] {
+ visibility: hidden;
+}
+
+.c5:hover:not([disabled]):not([aria-disabled]) {
background-color: rgba(208,215,222,0.32);
}
-.c5:active:not([disabled]) {
+.c5:active:not([disabled]):not([aria-disabled]) {
background-color: rgba(208,215,222,0.48);
}
@@ -1897,11 +1913,13 @@ exports[`TextInput renders trailingAction icon button 1`] = `
color: #24292f;
}
-.c5:disabled[data-no-visuals] {
+.c5:disabled[data-no-visuals],
+.c5[aria-disabled][data-no-visuals] {
color: #8c959f;
}
-.c5:disabled[data-no-visuals] [data-component=ButtonCounter] {
+.c5:disabled[data-no-visuals] [data-component=ButtonCounter],
+.c5[aria-disabled][data-no-visuals] [data-component=ButtonCounter] {
color: inherit;
}
@@ -2401,11 +2419,13 @@ exports[`TextInput renders trailingAction text button 1`] = `
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
display: inline-flex;
+ -webkit-text-decoration: var(--prefers-link-underlines,underline);
+ text-decoration: var(--prefers-link-underlines,underline);
}
.c4[href]:hover {
- -webkit-text-decoration: none;
- text-decoration: none;
+ -webkit-text-decoration: var(--prefers-link-underlines,underline);
+ text-decoration: var(--prefers-link-underlines,underline);
}
.c4:hover {
@@ -2418,15 +2438,19 @@ exports[`TextInput renders trailingAction text button 1`] = `
transition: none;
}
-.c4:disabled {
+.c4:disabled,
+.c4[aria-disabled] {
cursor: not-allowed;
box-shadow: none;
color: #8c959f;
}
.c4:disabled [data-component=ButtonCounter],
+.c4[aria-disabled] [data-component=ButtonCounter],
.c4:disabled [data-component="leadingVisual"],
-.c4:disabled [data-component="trailingAction"] {
+.c4[aria-disabled] [data-component="leadingVisual"],
+.c4:disabled [data-component="trailingAction"],
+.c4[aria-disabled] [data-component="trailingAction"] {
color: inherit;
}
@@ -2525,11 +2549,21 @@ exports[`TextInput renders trailingAction text button 1`] = `
margin-right: 8px;
}
-.c4:hover:not([disabled]) {
+.c4 [data-component="loadingSpinner"] {
+ grid-area: text;
+ margin-right: 0px !important;
+ place-self: center;
+}
+
+.c4 [data-component="loadingSpinner"] + [data-component="text"] {
+ visibility: hidden;
+}
+
+.c4:hover:not([disabled]):not([aria-disabled]) {
background-color: rgba(208,215,222,0.32);
}
-.c4:active:not([disabled]) {
+.c4:active:not([disabled]):not([aria-disabled]) {
background-color: rgba(208,215,222,0.48);
}
@@ -2559,11 +2593,13 @@ exports[`TextInput renders trailingAction text button 1`] = `
color: #24292f;
}
-.c4:disabled[data-no-visuals] {
+.c4:disabled[data-no-visuals],
+.c4[aria-disabled][data-no-visuals] {
color: #8c959f;
}
-.c4:disabled[data-no-visuals] [data-component=ButtonCounter] {
+.c4:disabled[data-no-visuals] [data-component=ButtonCounter],
+.c4[aria-disabled][data-no-visuals] [data-component=ButtonCounter] {
color: inherit;
}
@@ -2805,11 +2841,13 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = `
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
display: inline-flex;
+ -webkit-text-decoration: var(--prefers-link-underlines,underline);
+ text-decoration: var(--prefers-link-underlines,underline);
}
.c5[href]:hover {
- -webkit-text-decoration: none;
- text-decoration: none;
+ -webkit-text-decoration: var(--prefers-link-underlines,underline);
+ text-decoration: var(--prefers-link-underlines,underline);
}
.c5:hover {
@@ -2822,15 +2860,19 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = `
transition: none;
}
-.c5:disabled {
+.c5:disabled,
+.c5[aria-disabled] {
cursor: not-allowed;
box-shadow: none;
color: #8c959f;
}
.c5:disabled [data-component=ButtonCounter],
+.c5[aria-disabled] [data-component=ButtonCounter],
.c5:disabled [data-component="leadingVisual"],
-.c5:disabled [data-component="trailingAction"] {
+.c5[aria-disabled] [data-component="leadingVisual"],
+.c5:disabled [data-component="trailingAction"],
+.c5[aria-disabled] [data-component="trailingAction"] {
color: inherit;
}
@@ -2929,11 +2971,21 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = `
margin-right: 8px;
}
-.c5:hover:not([disabled]) {
+.c5 [data-component="loadingSpinner"] {
+ grid-area: text;
+ margin-right: 0px !important;
+ place-self: center;
+}
+
+.c5 [data-component="loadingSpinner"] + [data-component="text"] {
+ visibility: hidden;
+}
+
+.c5:hover:not([disabled]):not([aria-disabled]) {
background-color: rgba(208,215,222,0.32);
}
-.c5:active:not([disabled]) {
+.c5:active:not([disabled]):not([aria-disabled]) {
background-color: rgba(208,215,222,0.48);
}
@@ -2963,11 +3015,13 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = `
color: #24292f;
}
-.c5:disabled[data-no-visuals] {
+.c5:disabled[data-no-visuals],
+.c5[aria-disabled][data-no-visuals] {
color: #8c959f;
}
-.c5:disabled[data-no-visuals] [data-component=ButtonCounter] {
+.c5:disabled[data-no-visuals] [data-component=ButtonCounter],
+.c5[aria-disabled][data-no-visuals] [data-component=ButtonCounter] {
color: inherit;
}
From 968748636b0510054b8d4577a96f02b62f436990 Mon Sep 17 00:00:00 2001
From: Mike Perrotti
Date: Tue, 28 Nov 2023 13:43:29 -0500
Subject: [PATCH 10/51] uses unique ID for loading messages, preserves
aria-describedby passed to button, rms aria-busy
---
src/Button/ButtonBase.tsx | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/Button/ButtonBase.tsx b/src/Button/ButtonBase.tsx
index e4c25e2f46e..584bc946075 100644
--- a/src/Button/ButtonBase.tsx
+++ b/src/Button/ButtonBase.tsx
@@ -10,6 +10,7 @@ import {defaultSxProp} from '../utils/defaultSxProp'
import VisuallyHidden from '../_VisuallyHidden'
import Spinner from '../Spinner'
import CounterLabel from '../CounterLabel'
+import {useId} from '../hooks'
const ButtonBase = forwardRef(
({children, as: Component = 'button', sx: sxProp = defaultSxProp, ...props}, forwardedRef): JSX.Element => {
@@ -17,6 +18,7 @@ const ButtonBase = forwardRef(
leadingVisual: LeadingVisual,
trailingVisual: TrailingVisual,
trailingAction: TrailingAction,
+ ['aria-describedby']: ariaDescribedby,
count,
icon: Icon,
variant = 'default',
@@ -42,6 +44,7 @@ const ButtonBase = forwardRef(
display: 'flex',
pointerEvents: 'none',
}
+ const loadingMessageID = useId()
if (__DEV__) {
/**
@@ -74,7 +77,7 @@ const ButtonBase = forwardRef(
data-size={size === 'small' || size === 'large' ? size : undefined}
data-no-visuals={!LeadingVisual && !TrailingVisual && !TrailingAction ? true : undefined}
aria-disabled={loading ? true : undefined}
- aria-describedby={loading ? 'loading-message' : undefined}
+ aria-describedby={loading ? loadingMessageID : ariaDescribedby}
>
{Icon ? (
loading ? (
@@ -128,7 +131,7 @@ const ButtonBase = forwardRef(
{loading && (
-
+
{loadingMessage}
From 2fc7c4d5d97cc2962536c55c5f4999b76ab0e888 Mon Sep 17 00:00:00 2001
From: Mike Perrotti
Date: Tue, 28 Nov 2023 15:25:15 -0500
Subject: [PATCH 11/51] adds Storybook examples for btn loading error message
---
src/Button/Button.features.stories.tsx | 65 +++++++++++++++++++++++++-
1 file changed, 63 insertions(+), 2 deletions(-)
diff --git a/src/Button/Button.features.stories.tsx b/src/Button/Button.features.stories.tsx
index 6681e1a5457..aaf45fce61b 100644
--- a/src/Button/Button.features.stories.tsx
+++ b/src/Button/Button.features.stories.tsx
@@ -1,6 +1,7 @@
import {EyeIcon, TriangleDownIcon, HeartIcon, DownloadIcon} from '@primer/octicons-react'
import React, {useState} from 'react'
import {Button} from '.'
+import {Box, Flash} from '..'
export default {
title: 'Components/Button/Features',
@@ -80,7 +81,7 @@ export const LoadingWithLeadingVisual = () => {
}
return (
-
{TrailingAction && (
From c2779578e7410916bff15b34d807c2a46c2ba891 Mon Sep 17 00:00:00 2001
From: Mike Perrotti
Date: Wed, 29 Nov 2023 09:46:39 -0500
Subject: [PATCH 16/51] Revert "updates draft Button component with loading
prop"
This reverts commit 7f7f32618a2cdf4713ae69f5e5956d16b846a719.
---
.../Button2/Button.features.stories.tsx | 120 +-----------------
src/drafts/Button2/Button.stories.tsx | 6 -
src/drafts/Button2/ButtonBase.tsx | 99 +++++----------
src/drafts/Button2/styles.ts | 44 +++----
src/drafts/Button2/types.ts | 2 -
5 files changed, 50 insertions(+), 221 deletions(-)
diff --git a/src/drafts/Button2/Button.features.stories.tsx b/src/drafts/Button2/Button.features.stories.tsx
index 892643d98ae..ab0fce76123 100644
--- a/src/drafts/Button2/Button.features.stories.tsx
+++ b/src/drafts/Button2/Button.features.stories.tsx
@@ -1,7 +1,6 @@
-import {EyeIcon, TriangleDownIcon, HeartIcon, DownloadIcon} from '@primer/octicons-react'
+import {EyeIcon, TriangleDownIcon, HeartIcon} from '@primer/octicons-react'
import React, {useState} from 'react'
import {Button2 as Button} from '.'
-import {Box, Flash} from '../..'
export default {
title: 'Drafts/Components/Button/Features',
@@ -40,120 +39,3 @@ export const Small = () => Default
export const Medium = () => Default
export const Large = () => Default
-
-export const LoadingWithLeadingVisual = () => {
- const [isLoading, setIsLoading] = useState(false)
-
- const handleClick = () => {
- setIsLoading(true)
- setTimeout(() => {
- setIsLoading(false)
- }, 3000)
- }
-
- return (
-
- Export
-
- )
-}
-
-export const LoadingCustomMessage = () => (
-
- Default
-
-)
-
-export const LoadingWithNoVisuals = () => {
- const [isLoading, setIsLoading] = useState(false)
-
- const handleClick = () => {
- setIsLoading(true)
- setTimeout(() => {
- setIsLoading(false)
- }, 3000)
- }
-
- return (
-
- Export
-
- )
-}
-
-export const LoadingWithTrailingVisual = () => {
- const [isLoading, setIsLoading] = useState(false)
-
- const handleClick = () => {
- setIsLoading(true)
- setTimeout(() => {
- setIsLoading(false)
- }, 3000)
- }
-
- return (
-
- Export
-
- )
-}
-
-export const LoadingWithErrorMessageInvisible = () => {
- const [isLoading, setIsLoading] = useState(false)
- const [hasError, setHasError] = useState(false)
-
- const handleClick = () => {
- setIsLoading(true)
- setTimeout(() => {
- setIsLoading(false)
- setHasError(true)
- }, 1500)
- }
-
- return (
- <>
-
- Export
-
-
- {hasError ? 'Export failed' : null}
-
- >
- )
-}
-
-export const LoadingWithErrorMessageVisible = () => {
- const [isLoading, setIsLoading] = useState(false)
- const [hasError, setHasError] = useState(false)
-
- const handleClick = () => {
- setIsLoading(true)
- setTimeout(() => {
- setIsLoading(false)
- setHasError(true)
- }, 1500)
- }
-
- return (
- <>
- {hasError && (
-
- Export failed
-
- )}
-
- Export
-
- >
- )
-}
diff --git a/src/drafts/Button2/Button.stories.tsx b/src/drafts/Button2/Button.stories.tsx
index bffe370fc2b..32a841e66c4 100644
--- a/src/drafts/Button2/Button.stories.tsx
+++ b/src/drafts/Button2/Button.stories.tsx
@@ -43,11 +43,6 @@ export default {
type: 'number',
},
},
- loading: {
- control: {
- type: 'boolean',
- },
- },
},
args: {
block: false,
@@ -57,7 +52,6 @@ export default {
alignContent: 'center',
trailingIcon: null,
leadingIcon: null,
- loading: false,
trailingAction: null,
trailingVisualCount: undefined,
},
diff --git a/src/drafts/Button2/ButtonBase.tsx b/src/drafts/Button2/ButtonBase.tsx
index 297c07e895f..44125f7dbd0 100644
--- a/src/drafts/Button2/ButtonBase.tsx
+++ b/src/drafts/Button2/ButtonBase.tsx
@@ -7,9 +7,6 @@ import {ButtonProps, StyledButton} from './types'
import {getVariantStyles, getButtonStyles, getAlignContentSize} from './styles'
import {useRefObjectAsForwardedRef} from '../../hooks/useRefObjectAsForwardedRef'
import {defaultSxProp} from '../../utils/defaultSxProp'
-import Spinner from '../../Spinner'
-import {useId} from '../../hooks'
-import {VisuallyHidden} from '../../internal/components/VisuallyHidden'
const ButtonBase = forwardRef(
({children, as: Component = 'button', sx: sxProp = defaultSxProp, ...props}, forwardedRef): JSX.Element => {
@@ -17,14 +14,11 @@ const ButtonBase = forwardRef(
leadingIcon: LeadingIcon,
trailingIcon: TrailingIcon,
trailingAction: TrailingAction,
- ['aria-describedby']: ariaDescribedby,
icon: Icon,
variant = 'default',
size = 'medium',
alignContent = 'center',
block = false,
- loading = false,
- loadingAnnouncement = 'Loading',
...rest
} = props
@@ -42,7 +36,6 @@ const ButtonBase = forwardRef(
display: 'flex',
pointerEvents: 'none',
}
- const loadingAnnouncementID = useId()
if (__DEV__) {
/**
@@ -65,70 +58,40 @@ const ButtonBase = forwardRef(
}
return (
- <>
-
- {Icon ? (
- loading ? (
-
- ) : (
-
- )
- ) : (
- <>
-
- {loading && !LeadingIcon && !TrailingIcon && (
-
-
-
- )}
- {LeadingIcon && loading && (
-
-
-
- )}
- {LeadingIcon && !loading && (
-
-
-
- )}
- {children && {children}}
- {TrailingIcon && loading && (
-
-
-
- )}
- {TrailingIcon && !loading && (
-
-
-
- )}
-
- {TrailingAction && (
-
-
+
+ {Icon ? (
+
+ ) : (
+ <>
+
+ {LeadingIcon && (
+
+
+
+ )}
+ {children && {children}}
+ {TrailingIcon && (
+
+
)}
- >
- )}
-
- {loading && (
-
-
- {loadingAnnouncement}
-
-
+
+ {TrailingAction && (
+
+
+
+ )}
+ >
)}
- >
+
)
},
) as PolymorphicForwardRefComponent<'button' | 'a', ButtonProps>
diff --git a/src/drafts/Button2/styles.ts b/src/drafts/Button2/styles.ts
index 3bd003c171b..474a9e81991 100644
--- a/src/drafts/Button2/styles.ts
+++ b/src/drafts/Button2/styles.ts
@@ -7,15 +7,15 @@ export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme
color: 'btn.text',
backgroundColor: 'btn.bg',
boxShadow: `${theme?.shadows.btn.shadow}, ${theme?.shadows.btn.insetShadow}`,
- '&:hover:not([disabled]):not([aria-disabled])': {
+ '&:hover:not([disabled])': {
backgroundColor: 'btn.hoverBg',
borderColor: 'btn.hoverBorder',
},
- '&:active:not([disabled]):not([aria-disabled])': {
+ '&:active:not([disabled])': {
backgroundColor: 'btn.activeBg',
borderColor: 'btn.activeBorder',
},
- '&:disabled, &[aria-disabled]': {
+ '&:disabled': {
color: 'primer.fg.disabled',
'[data-component=ButtonCounter]': {
color: 'inherit',
@@ -31,21 +31,21 @@ export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme
backgroundColor: 'btn.primary.bg',
borderColor: 'btn.primary.border',
boxShadow: `${theme?.shadows.btn.primary.shadow}`,
- '&:hover:not([disabled]):not([aria-disabled])': {
+ '&:hover:not([disabled])': {
color: 'btn.primary.hoverText',
backgroundColor: 'btn.primary.hoverBg',
},
- '&:focus:not([disabled]):not([aria-disabled])': {
+ '&:focus:not([disabled])': {
boxShadow: 'inset 0 0 0 3px',
},
- '&:focus-visible:not([disabled]):not([aria-disabled])': {
+ '&:focus-visible:not([disabled])': {
boxShadow: 'inset 0 0 0 3px',
},
- '&:active:not([disabled]):not([aria-disabled])': {
+ '&:active:not([disabled])': {
backgroundColor: 'btn.primary.selectedBg',
boxShadow: `${theme?.shadows.btn.primary.selectedShadow}`,
},
- '&:disabled, &[aria-disabled]': {
+ '&:disabled': {
color: 'btn.primary.disabledText',
backgroundColor: 'btn.primary.disabledBg',
'[data-component=ButtonCounter]': {
@@ -65,7 +65,7 @@ export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme
color: 'btn.danger.text',
backgroundColor: 'btn.bg',
boxShadow: `${theme?.shadows.btn.shadow}`,
- '&:hover:not([disabled]):not([aria-disabled])': {
+ '&:hover:not([disabled])': {
color: 'btn.danger.hoverText',
backgroundColor: 'btn.danger.hoverBg',
borderColor: 'btn.danger.hoverBorder',
@@ -75,13 +75,13 @@ export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme
color: 'btn.danger.hoverText',
},
},
- '&:active:not([disabled]):not([aria-disabled])': {
+ '&:active:not([disabled])': {
color: 'btn.danger.selectedText',
backgroundColor: 'btn.danger.selectedBg',
boxShadow: `${theme?.shadows.btn.danger.selectedShadow}`,
borderColor: 'btn.danger.selectedBorder',
},
- '&:disabled, &[aria-disabled]': {
+ '&:disabled': {
color: 'btn.danger.disabledText',
backgroundColor: 'btn.danger.disabledBg',
borderColor: 'btn.danger.disabledBorder',
@@ -106,13 +106,13 @@ export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme
backgroundColor: 'transparent',
borderColor: 'transparent',
boxShadow: 'none',
- '&:hover:not([disabled]):not([aria-disabled])': {
+ '&:hover:not([disabled])': {
backgroundColor: 'btn.hoverBg',
},
- '&:active:not([disabled]):not([aria-disabled])': {
+ '&:active:not([disabled])': {
backgroundColor: 'btn.selectedBg',
},
- '&:disabled, &[aria-disabled]': {
+ '&:disabled': {
color: 'primer.fg.disabled',
'[data-component=ButtonCounter]': {
color: 'inherit',
@@ -143,7 +143,7 @@ export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme
borderColor: 'btn.border',
backgroundColor: 'btn.bg',
- '&:hover:not([disabled]):not([aria-disabled])': {
+ '&:hover:not([disabled])': {
color: 'btn.outline.hoverText',
backgroundColor: 'btn.outline.hoverBg',
borderColor: 'btn.outline.hoverBorder',
@@ -153,14 +153,14 @@ export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme
color: 'inherit',
},
},
- '&:active:not([disabled]):not([aria-disabled])': {
+ '&:active:not([disabled])': {
color: 'btn.outline.selectedText',
backgroundColor: 'btn.outline.selectedBg',
boxShadow: `${theme?.shadows.btn.outline.selectedShadow}`,
borderColor: 'btn.outline.selectedBorder',
},
- '&:disabled, &[aria-disabled]': {
+ '&:disabled': {
color: 'btn.outline.disabledText',
backgroundColor: 'btn.outline.disabledBg',
borderColor: 'btn.border',
@@ -217,7 +217,7 @@ export const getBaseStyles = (theme?: Theme) => ({
'&:active': {
transition: 'none',
},
- '&:disabled, &[aria-disabled]': {
+ '&:disabled': {
cursor: 'not-allowed',
boxShadow: 'none',
},
@@ -307,14 +307,6 @@ export const getButtonStyles = (theme?: Theme) => {
'[data-component="buttonContent"] > :not(:last-child)': {
mr: '8px',
},
- '[data-component="loadingSpinner"]': {
- gridArea: 'text',
- marginRight: '0px !important',
- placeSelf: 'center',
- },
- '[data-component="loadingSpinner"] + [data-component="text"]': {
- visibility: 'hidden',
- },
}
return styles
}
diff --git a/src/drafts/Button2/types.ts b/src/drafts/Button2/types.ts
index 70d0f1412cf..7194fd0d354 100644
--- a/src/drafts/Button2/types.ts
+++ b/src/drafts/Button2/types.ts
@@ -35,8 +35,6 @@ export type ButtonBaseProps = {
* Allow button width to fill its container.
*/
block?: boolean
- loading?: boolean
- loadingAnnouncement?: string
} & SxProp &
React.ButtonHTMLAttributes
From ccaa4ae3a786a2649175c5888fb3d5b3272a13da Mon Sep 17 00:00:00 2001
From: Mike Perrotti
Date: Fri, 1 Dec 2023 18:39:59 -0500
Subject: [PATCH 17/51] moves error behavior stories to 'Examples' section
---
src/Button/Button.examples.stories.tsx | 36 +++++++++++++++
src/Button/Button.features.stories.tsx | 61 --------------------------
2 files changed, 36 insertions(+), 61 deletions(-)
create mode 100644 src/Button/Button.examples.stories.tsx
diff --git a/src/Button/Button.examples.stories.tsx b/src/Button/Button.examples.stories.tsx
new file mode 100644
index 00000000000..d9a3f75fc43
--- /dev/null
+++ b/src/Button/Button.examples.stories.tsx
@@ -0,0 +1,36 @@
+import React, {useState} from 'react'
+import type {Meta} from '@storybook/react'
+import {Button} from '.'
+import {Flash} from '..'
+
+const meta: Meta = {
+ title: 'Components/Button/Examples',
+} as Meta
+
+export default meta
+
+export const LoadingWithError = () => {
+ const [isLoading, setIsLoading] = useState(false)
+ const [hasError, setHasError] = useState(false)
+
+ const handleClick = () => {
+ setIsLoading(true)
+ setTimeout(() => {
+ setIsLoading(false)
+ setHasError(true)
+ }, 1500)
+ }
+
+ return (
+ <>
+ {hasError && (
+
+ Export failed. Try again.
+
+ )}
+
+ Export
+
+ >
+ )
+}
diff --git a/src/Button/Button.features.stories.tsx b/src/Button/Button.features.stories.tsx
index d9f4936931f..a7062bab0ec 100644
--- a/src/Button/Button.features.stories.tsx
+++ b/src/Button/Button.features.stories.tsx
@@ -1,7 +1,6 @@
import {EyeIcon, TriangleDownIcon, HeartIcon, DownloadIcon} from '@primer/octicons-react'
import React, {useState} from 'react'
import {Button} from '.'
-import {Box, Flash} from '..'
export default {
title: 'Components/Button/Features',
@@ -126,63 +125,3 @@ export const LoadingWithTrailingVisual = () => {
)
}
-
-export const LoadingWithErrorMessageInvisible = () => {
- const [isLoading, setIsLoading] = useState(false)
- const [hasError, setHasError] = useState(false)
-
- const handleClick = () => {
- setIsLoading(true)
- setTimeout(() => {
- setIsLoading(false)
- setHasError(true)
- }, 1500)
- }
-
- return (
- <>
-
- Export
-
-
- {hasError ? 'Export failed' : null}
-
- >
- )
-}
-
-export const LoadingWithErrorMessageVisible = () => {
- const [isLoading, setIsLoading] = useState(false)
- const [hasError, setHasError] = useState(false)
-
- const handleClick = () => {
- setIsLoading(true)
- setTimeout(() => {
- setIsLoading(false)
- setHasError(true)
- }, 1500)
- }
-
- return (
- <>
- {hasError && (
-
- Export failed
-
- )}
-
- Export
-
- >
- )
-}
From 30fb01d7c9612ff27766123ea0bd322c0824f7c1 Mon Sep 17 00:00:00 2001
From: Mike Perrotti
Date: Fri, 1 Dec 2023 18:41:14 -0500
Subject: [PATCH 18/51] screenreader fixes
---
src/Button/ButtonBase.tsx | 31 +++++++++++++++++++------------
1 file changed, 19 insertions(+), 12 deletions(-)
diff --git a/src/Button/ButtonBase.tsx b/src/Button/ButtonBase.tsx
index 6f99623f72f..f1415742ac5 100644
--- a/src/Button/ButtonBase.tsx
+++ b/src/Button/ButtonBase.tsx
@@ -7,7 +7,7 @@ import {ButtonProps, StyledButton} from './types'
import {getVariantStyles, getButtonStyles, getAlignContentSize} from './styles'
import {useRefObjectAsForwardedRef} from '../hooks/useRefObjectAsForwardedRef'
import {defaultSxProp} from '../utils/defaultSxProp'
-import VisuallyHidden from '../_VisuallyHidden'
+import {VisuallyHidden} from '../internal/components/VisuallyHidden'
import Spinner from '../Spinner'
import CounterLabel from '../CounterLabel'
import {useId} from '../hooks'
@@ -18,9 +18,11 @@ const ButtonBase = forwardRef(
leadingVisual: LeadingVisual,
trailingVisual: TrailingVisual,
trailingAction: TrailingAction,
- ['aria-describedby']: ariaDescribedby,
+ ['aria-describedby']: ariaDescribedBy,
+ ['aria-labelledby']: ariaLabelledBy,
count,
icon: Icon,
+ id,
variant = 'default',
size = 'medium',
alignContent = 'center',
@@ -44,7 +46,9 @@ const ButtonBase = forwardRef(
display: 'flex',
pointerEvents: 'none',
}
- const loadingAnnouncementID = useId()
+ const uuid = useId(id)
+ const loadingAnnouncementID = `${uuid}-loading-announcement`
+ const buttonLabelID = ariaLabelledBy || `${uuid}-label`
if (__DEV__) {
/**
@@ -77,7 +81,12 @@ const ButtonBase = forwardRef(
data-size={size === 'small' || size === 'large' ? size : undefined}
data-no-visuals={!LeadingVisual && !TrailingVisual && !TrailingAction ? true : undefined}
aria-disabled={loading ? true : undefined}
- aria-describedby={loading ? loadingAnnouncementID : ariaDescribedby}
+ aria-describedby={[loadingAnnouncementID, ariaDescribedBy]
+ .filter(descriptionID => Boolean(descriptionID))
+ .join(' ')}
+ // aria-labelledby is needed because the accessible name becomes unset when the button is in a loading state
+ aria-labelledby={buttonLabelID}
+ id={id}
>
{Icon ? (
loading ? (
@@ -104,7 +113,7 @@ const ButtonBase = forwardRef(
)}
{children && (
-
+
{children}
{count !== undefined && !TrailingVisual && (
@@ -132,13 +141,11 @@ const ButtonBase = forwardRef(
>
)}
- {loading && (
-
-
- {loadingAnnouncement}
-
-
- )}
+
+
+ {loading && loadingAnnouncement}
+
+
>
)
},
From 22c7c65650e335eb7975dd0bb716f7eedb9439cc Mon Sep 17 00:00:00 2001
From: Mike Perrotti
Date: Fri, 1 Dec 2023 18:41:44 -0500
Subject: [PATCH 19/51] adds and updates unit tests
---
src/Button/__tests__/Button.test.tsx | 142 ++++++++++++++++--
.../__snapshots__/Button.test.tsx.snap | 82 ++++++++--
src/Dialog/__snapshots__/Dialog.test.tsx.snap | 43 ++++--
.../__snapshots__/SelectPanel.test.tsx.snap | 24 +++
.../__snapshots__/ActionMenu.test.tsx.snap | 24 +++
.../__snapshots__/TextInput.test.tsx.snap | 71 +++++++++
src/drafts/Tooltip/__tests__/Tooltip.test.tsx | 6 +-
7 files changed, 357 insertions(+), 35 deletions(-)
diff --git a/src/Button/__tests__/Button.test.tsx b/src/Button/__tests__/Button.test.tsx
index 186f4a029a7..6e93fcf13ba 100644
--- a/src/Button/__tests__/Button.test.tsx
+++ b/src/Button/__tests__/Button.test.tsx
@@ -2,14 +2,35 @@ import {SearchIcon} from '@primer/octicons-react'
import {render, screen, fireEvent} from '@testing-library/react'
import {axe} from 'jest-axe'
import React from 'react'
-import {IconButton, Button} from '../../Button'
+import {IconButton, Button, ButtonProps} from '../../Button'
import {behavesAsComponent} from '../../utils/testing'
+type StatefulLoadingButtonProps = {
+ children?: React.ReactNode
+ id?: string
+ ['aria-describedby']?: string
+ loadingAnnouncement?: string
+}
+
+const TestButton = (props: ButtonProps) =>
+
+const StatefulLoadingButton = (props: StatefulLoadingButtonProps) => {
+ const [isLoading, setIsLoading] = React.useState(false)
+ const handleClick = () => {
+ setIsLoading(true)
+ }
+
+ return
+}
+
describe('Button', () => {
- behavesAsComponent({Component: Button, options: {skipSx: true}})
+ behavesAsComponent({
+ Component: TestButton,
+ options: {skipSx: true, skipAs: true},
+ })
it('renders a ', () => {
- const container = render(Default)
+ const container = render(Default)
const button = container.getByRole('button')
expect(button.textContent).toEqual('Default')
})
@@ -29,7 +50,11 @@ describe('Button', () => {
})
it('respects block prop', () => {
- const container = render(Block)
+ const container = render(
+
+ Block
+ ,
+ )
const button = container.getByRole('button')
expect(button).toMatchSnapshot()
})
@@ -48,31 +73,51 @@ describe('Button', () => {
})
it('respects the small size prop', () => {
- const container = render(Smol)
+ const container = render(
+
+ Smol
+ ,
+ )
const button = container.getByRole('button')
expect(button).toMatchSnapshot()
})
it('respects the large size prop', () => {
- const container = render(Smol)
+ const container = render(
+
+ Smol
+ ,
+ )
const button = container.getByRole('button')
expect(button).toMatchSnapshot()
})
it('styles primary button appropriately', () => {
- const container = render(Primary)
+ const container = render(
+
+ Primary
+ ,
+ )
const button = container.getByRole('button')
expect(button).toMatchSnapshot()
})
it('styles invisible button appropriately', () => {
- const container = render(Invisible)
+ const container = render(
+
+ Invisible
+ ,
+ )
const button = container.getByRole('button')
expect(button).toMatchSnapshot()
})
it('styles danger button appropriately', () => {
- const container = render(Danger)
+ const container = render(
+
+ Danger
+ ,
+ )
const button = container.getByRole('button')
expect(button).toMatchSnapshot()
})
@@ -84,7 +129,11 @@ describe('Button', () => {
})
it('respects the alignContent prop', () => {
- const container = render(Align start)
+ const container = render(
+
+ Align start
+ ,
+ )
const button = container.getByRole('button')
expect(button).toMatchSnapshot()
})
@@ -113,4 +162,77 @@ describe('Button', () => {
const position = screen.getByText('content').compareDocumentPosition(screen.getByTestId('trailingVisual'))
expect(position).toBe(Node.DOCUMENT_POSITION_FOLLOWING)
})
+
+ it('should describe the button with a default loading announcement, and only when the button is in a loading state', () => {
+ const buttonId = 'loading-button'
+ const container = render(
+
+ content
+ ,
+ )
+ const buttonNode = container.getByRole('button')
+
+ expect(buttonNode.getAttribute('aria-describedby')).toBe(`${buttonId}-loading-announcement`)
+
+ expect(buttonNode).not.toHaveAccessibleDescription('Loading')
+
+ fireEvent.click(buttonNode)
+
+ expect(buttonNode).toHaveAccessibleDescription('Loading')
+ })
+
+ it('should render a custom loading announcement, and only when the button is in a loading state', () => {
+ const buttonId = 'loading-button'
+ const container = render(
+
+ content
+ ,
+ )
+ const buttonNode = container.getByRole('button')
+
+ expect(buttonNode.getAttribute('aria-describedby')).toBe(`${buttonId}-loading-announcement`)
+
+ expect(buttonNode).not.toHaveAccessibleDescription('Action loading')
+
+ fireEvent.click(buttonNode)
+
+ expect(buttonNode).toHaveAccessibleDescription('Action loading')
+ })
+
+ it('should be described by loading announcement AND whatever is passed to aria-describedby', () => {
+ const buttonDescriptionId = 'button-description'
+ const buttonId = 'loading-button'
+ const container = render(
+
+ content
+ ,
+ )
+ const buttonDescribedBy = container.getByRole('button').getAttribute('aria-describedby')
+ const loadingAnnouncementId = `${buttonId}-loading-announcement`
+
+ expect(buttonDescribedBy).toContain(loadingAnnouncementId)
+
+ expect(buttonDescribedBy).toContain(buttonDescriptionId)
+ })
+
+ it('should only set aria-disabled to "true" when the button is in a loading state', () => {
+ const container = render(
+
+ content
+ ,
+ )
+ const buttonNode = container.getByRole('button')
+
+ expect(buttonNode.getAttribute('aria-disabled')).not.toBe('true')
+
+ fireEvent.click(buttonNode)
+
+ expect(buttonNode.getAttribute('aria-disabled')).toBe('true')
+ })
+
+ it('should preserve the accessible button name when the button is in a loading state', () => {
+ const container = render(content)
+
+ expect(container.getByRole('button')).toHaveAccessibleName('content')
+ })
})
diff --git a/src/Button/__tests__/__snapshots__/Button.test.tsx.snap b/src/Button/__tests__/__snapshots__/Button.test.tsx.snap
index a1f525d63fc..d21110883f8 100644
--- a/src/Button/__tests__/__snapshots__/Button.test.tsx.snap
+++ b/src/Button/__tests__/__snapshots__/Button.test.tsx.snap
@@ -1,7 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Button renders consistently 1`] = `
-.c1 {
+[
+ .c1 {
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
@@ -234,17 +235,46 @@ exports[`Button renders consistently 1`] = `
}
-
-
+ aria-describedby="test-button-loading-announcement"
+ aria-labelledby="test-button-label"
+ className="c0"
+ data-block={null}
+ data-no-visuals={true}
+ id="test-button"
+ style={{}}
+ type="button"
+ >
+
+ ,
+ .c0 {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ -webkit-clip: rect(0,0,0,0);
+ clip: rect(0,0,0,0);
+ white-space: nowrap;
+ border-width: 0;
+}
+
+@media (forced-colors:active) {
+
+}
+
+
+
+ ,
+]
`;
exports[`Button respects block prop 1`] = `
@@ -481,9 +511,12 @@ exports[`Button respects block prop 1`] = `
}
Block
@@ -733,8 +767,11 @@ exports[`Button respects the alignContent prop 1`] = `
}
Align start
@@ -984,9 +1022,12 @@ exports[`Button respects the large size prop 1`] = `
}
Smol
@@ -1236,9 +1278,12 @@ exports[`Button respects the small size prop 1`] = `
}
Smol
@@ -1498,8 +1544,11 @@ exports[`Button styles danger button appropriately 1`] = `
}
Danger
@@ -1768,8 +1818,11 @@ exports[`Button styles invisible button appropriately 1`] = `
}
Invisible
@@ -2024,8 +2078,11 @@ exports[`Button styles primary button appropriately 1`] = `
}
Primary
diff --git a/src/Dialog/__snapshots__/Dialog.test.tsx.snap b/src/Dialog/__snapshots__/Dialog.test.tsx.snap
index df2ff9367f6..dec13ad0842 100644
--- a/src/Dialog/__snapshots__/Dialog.test.tsx.snap
+++ b/src/Dialog/__snapshots__/Dialog.test.tsx.snap
@@ -72,12 +72,12 @@ exports[`Dialog renders consistently 1`] = `
,
- .c2 {
+ .c3 {
padding: 16px;
background-color: #f6f8fa;
}
-.c5 {
+.c6 {
padding: 16px;
}
@@ -322,14 +322,27 @@ exports[`Dialog renders consistently 1`] = `
color: inherit;
}
-.c4 {
+.c2 {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ -webkit-clip: rect(0,0,0,0);
+ clip: rect(0,0,0,0);
+ white-space: nowrap;
+ border-width: 0;
+}
+
+.c5 {
font-size: 14px;
font-weight: 600;
font-family: sans-serif;
color: #1F2328;
}
-.c6 {
+.c7 {
font-family: sans-serif;
}
@@ -350,7 +363,7 @@ exports[`Dialog renders consistently 1`] = `
outline: none;
}
-.c3 {
+.c4 {
border-radius: 6px 6px 0px 0px;
border-bottom: 1px solid #d0d7de;
display: -webkit-box;
@@ -375,7 +388,7 @@ exports[`Dialog renders consistently 1`] = `
}
@media screen and (max-width:750px) {
- .c3 {
+ .c4 {
border-radius: 0px;
}
}
@@ -389,7 +402,9 @@ exports[`Dialog renders consistently 1`] = `
tabIndex={-1}
>
+
+
+
Some content
diff --git a/src/SelectPanel/__snapshots__/SelectPanel.test.tsx.snap b/src/SelectPanel/__snapshots__/SelectPanel.test.tsx.snap
index bfd50cfdc2a..894713f8c50 100644
--- a/src/SelectPanel/__snapshots__/SelectPanel.test.tsx.snap
+++ b/src/SelectPanel/__snapshots__/SelectPanel.test.tsx.snap
@@ -241,6 +241,19 @@ exports[`SelectPanel renders consistently 1`] = `
color: var(--button-color,#656d76);
}
+.c4 {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ -webkit-clip: rect(0,0,0,0);
+ clip: rect(0,0,0,0);
+ white-space: nowrap;
+ border-width: 0;
+}
+
@media (forced-colors:active) {
.c1:focus {
outline: solid 1px transparent;
@@ -257,7 +270,9 @@ exports[`SelectPanel renders consistently 1`] = `
fontFamily="normal"
>
Select Items
@@ -305,6 +321,14 @@ exports[`SelectPanel renders consistently 1`] = `
+
+
+
diff --git a/src/__tests__/__snapshots__/ActionMenu.test.tsx.snap b/src/__tests__/__snapshots__/ActionMenu.test.tsx.snap
index 4deb48aab6b..d619b390da9 100644
--- a/src/__tests__/__snapshots__/ActionMenu.test.tsx.snap
+++ b/src/__tests__/__snapshots__/ActionMenu.test.tsx.snap
@@ -241,6 +241,19 @@ exports[`ActionMenu renders consistently 1`] = `
color: var(--button-color,#656d76);
}
+.c4 {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ -webkit-clip: rect(0,0,0,0);
+ clip: rect(0,0,0,0);
+ white-space: nowrap;
+ border-width: 0;
+}
+
@media (forced-colors:active) {
.c1:focus {
outline: solid 1px transparent;
@@ -257,7 +270,9 @@ exports[`ActionMenu renders consistently 1`] = `
fontFamily="normal"
>
Toggle Menu
@@ -305,5 +321,13 @@ exports[`ActionMenu renders consistently 1`] = `
+
+
+
`;
diff --git a/src/__tests__/__snapshots__/TextInput.test.tsx.snap b/src/__tests__/__snapshots__/TextInput.test.tsx.snap
index c3ca5a13b7c..69b485fec6d 100644
--- a/src/__tests__/__snapshots__/TextInput.test.tsx.snap
+++ b/src/__tests__/__snapshots__/TextInput.test.tsx.snap
@@ -1947,6 +1947,19 @@ exports[`TextInput renders trailingAction icon button 1`] = `
height: var(--inner-action-size);
}
+.c6 {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ -webkit-clip: rect(0,0,0,0);
+ clip: rect(0,0,0,0);
+ white-space: nowrap;
+ border-width: 0;
+}
+
.c0 {
font-size: 14px;
line-height: 20px;
@@ -2314,7 +2327,9 @@ exports[`TextInput renders trailingAction icon button 1`] = `
role="tooltip"
>
+
+
+
@@ -2613,6 +2636,19 @@ exports[`TextInput renders trailingAction text button 1`] = `
color: inherit;
}
+.c6 {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ -webkit-clip: rect(0,0,0,0);
+ clip: rect(0,0,0,0);
+ white-space: nowrap;
+ border-width: 0;
+}
+
.c0 {
font-size: 14px;
line-height: 20px;
@@ -2750,6 +2786,8 @@ exports[`TextInput renders trailingAction text button 1`] = `
className="c3 TextInput-action"
>
Clear
+
+
+
`;
@@ -3034,6 +3081,19 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = `
color: inherit;
}
+.c7 {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ -webkit-clip: rect(0,0,0,0);
+ clip: rect(0,0,0,0);
+ white-space: nowrap;
+ border-width: 0;
+}
+
.c0 {
font-size: 14px;
line-height: 20px;
@@ -3402,6 +3462,8 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = `
role="tooltip"
>
Clear
+
+
+
diff --git a/src/drafts/Tooltip/__tests__/Tooltip.test.tsx b/src/drafts/Tooltip/__tests__/Tooltip.test.tsx
index e8fbea212f3..e40595e7fab 100644
--- a/src/drafts/Tooltip/__tests__/Tooltip.test.tsx
+++ b/src/drafts/Tooltip/__tests__/Tooltip.test.tsx
@@ -55,7 +55,7 @@ describe('Tooltip', () => {
const {getByRole, getByText} = HTMLRender()
const triggerEL = getByRole('button')
const tooltipEl = getByText('Tooltip text')
- expect(triggerEL).toHaveAttribute('aria-describedby', tooltipEl.id)
+ expect(triggerEL.getAttribute('aria-describedby')).toContain(tooltipEl.id)
})
it('should render the tooltip element with role="tooltip" when the tooltip type is description (by default)', () => {
const {getByText} = HTMLRender()
@@ -72,7 +72,7 @@ describe('Tooltip', () => {
)
const menuButton = getByRole('button')
const tooltip = getByText('Additional context about the menu button')
- expect(menuButton).toHaveAttribute('aria-describedby', tooltip.id)
+ expect(menuButton.getAttribute('aria-describedby')).toContain(tooltip.id)
expect(menuButton).toHaveAttribute('aria-haspopup', 'true')
})
@@ -88,7 +88,7 @@ describe('Tooltip', () => {
)
const menuButton = getByRole('button')
const tooltip = getByText('Additional context about the menu button')
- expect(menuButton).toHaveAttribute('aria-describedby', tooltip.id)
+ expect(menuButton.getAttribute('aria-describedby')).toContain(tooltip.id)
expect(menuButton).toHaveAttribute('aria-haspopup', 'true')
})
})
From 6dcf5b38ccf73f8d3162b953936d9500f40e911d Mon Sep 17 00:00:00 2001
From: Mike Perrotti
Date: Fri, 1 Dec 2023 18:43:55 -0500
Subject: [PATCH 20/51] re-updates snapshots after using correct VisuallyHidden
---
.../__snapshots__/Button.test.tsx.snap | 17 +-
src/Dialog/__snapshots__/Dialog.test.tsx.snap | 23 +-
.../__snapshots__/SelectPanel.test.tsx.snap | 17 +-
.../__snapshots__/ActionMenu.test.tsx.snap | 17 +-
.../__snapshots__/Autocomplete.test.tsx.snap | 10 +-
.../__snapshots__/TextInput.test.tsx.snap | 73 ++---
.../TextInputWithTokens.test.tsx.snap | 274 +++++++++---------
7 files changed, 205 insertions(+), 226 deletions(-)
diff --git a/src/Button/__tests__/__snapshots__/Button.test.tsx.snap b/src/Button/__tests__/__snapshots__/Button.test.tsx.snap
index d21110883f8..a71f0418760 100644
--- a/src/Button/__tests__/__snapshots__/Button.test.tsx.snap
+++ b/src/Button/__tests__/__snapshots__/Button.test.tsx.snap
@@ -249,31 +249,28 @@ exports[`Button renders consistently 1`] = `
data-component="buttonContent"
/>
,
- .c0 {
- position: absolute;
- width: 1px;
+ .c0:not(:focus):not(:active):not(:focus-within) {
+ -webkit-clip-path: inset(50%);
+ clip-path: inset(50%);
height: 1px;
- padding: 0;
- margin: -1px;
overflow: hidden;
- -webkit-clip: rect(0,0,0,0);
- clip: rect(0,0,0,0);
+ position: absolute;
white-space: nowrap;
- border-width: 0;
+ width: 1px;
}
@media (forced-colors:active) {
}
-
- ,
+ ,
]
`;
diff --git a/src/Dialog/__snapshots__/Dialog.test.tsx.snap b/src/Dialog/__snapshots__/Dialog.test.tsx.snap
index dec13ad0842..e6d50ab1fd5 100644
--- a/src/Dialog/__snapshots__/Dialog.test.tsx.snap
+++ b/src/Dialog/__snapshots__/Dialog.test.tsx.snap
@@ -322,17 +322,14 @@ exports[`Dialog renders consistently 1`] = `
color: inherit;
}
-.c2 {
- position: absolute;
- width: 1px;
+.c2:not(:focus):not(:active):not(:focus-within) {
+ -webkit-clip-path: inset(50%);
+ clip-path: inset(50%);
height: 1px;
- padding: 0;
- margin: -1px;
overflow: hidden;
- -webkit-clip: rect(0,0,0,0);
- clip: rect(0,0,0,0);
+ position: absolute;
white-space: nowrap;
- border-width: 0;
+ width: 1px;
}
.c5 {
@@ -402,9 +399,9 @@ exports[`Dialog renders consistently 1`] = `
tabIndex={-1}
>
-
-
+
diff --git a/src/__tests__/__snapshots__/ActionMenu.test.tsx.snap b/src/__tests__/__snapshots__/ActionMenu.test.tsx.snap
index d619b390da9..94dd1e02af1 100644
--- a/src/__tests__/__snapshots__/ActionMenu.test.tsx.snap
+++ b/src/__tests__/__snapshots__/ActionMenu.test.tsx.snap
@@ -241,17 +241,14 @@ exports[`ActionMenu renders consistently 1`] = `
color: var(--button-color,#656d76);
}
-.c4 {
- position: absolute;
- width: 1px;
+.c4:not(:focus):not(:active):not(:focus-within) {
+ -webkit-clip-path: inset(50%);
+ clip-path: inset(50%);
height: 1px;
- padding: 0;
- margin: -1px;
overflow: hidden;
- -webkit-clip: rect(0,0,0,0);
- clip: rect(0,0,0,0);
+ position: absolute;
white-space: nowrap;
- border-width: 0;
+ width: 1px;
}
@media (forced-colors:active) {
@@ -321,13 +318,13 @@ exports[`ActionMenu renders consistently 1`] = `
-
-
+
`;
diff --git a/src/__tests__/__snapshots__/Autocomplete.test.tsx.snap b/src/__tests__/__snapshots__/Autocomplete.test.tsx.snap
index 27d4c2f6d55..21b5548b6c3 100644
--- a/src/__tests__/__snapshots__/Autocomplete.test.tsx.snap
+++ b/src/__tests__/__snapshots__/Autocomplete.test.tsx.snap
@@ -309,6 +309,11 @@ exports[`snapshots renders a loading state 1`] = `
justify-content: center;
}
+.c2 {
+ -webkit-animation: rotate-keyframes 1s linear infinite;
+ animation: rotate-keyframes 1s linear infinite;
+}
+
.c0 {
position: absolute;
width: 1px;
@@ -322,11 +327,6 @@ exports[`snapshots renders a loading state 1`] = `
border-width: 0;
}
-.c2 {
- -webkit-animation: rotate-keyframes 1s linear infinite;
- animation: rotate-keyframes 1s linear infinite;
-}
-
@media (min-width:768px) {
}
diff --git a/src/__tests__/__snapshots__/TextInput.test.tsx.snap b/src/__tests__/__snapshots__/TextInput.test.tsx.snap
index 00af5290735..1c73cf965e2 100644
--- a/src/__tests__/__snapshots__/TextInput.test.tsx.snap
+++ b/src/__tests__/__snapshots__/TextInput.test.tsx.snap
@@ -1934,17 +1934,14 @@ exports[`TextInput renders trailingAction icon button 1`] = `
height: var(--inner-action-size);
}
-.c6 {
- position: absolute;
- width: 1px;
+.c6:not(:focus):not(:active):not(:focus-within) {
+ -webkit-clip-path: inset(50%);
+ clip-path: inset(50%);
height: 1px;
- padding: 0;
- margin: -1px;
overflow: hidden;
- -webkit-clip: rect(0,0,0,0);
- clip: rect(0,0,0,0);
+ position: absolute;
white-space: nowrap;
- border-width: 0;
+ width: 1px;
}
.c0 {
@@ -2313,9 +2310,9 @@ exports[`TextInput renders trailingAction icon button 1`] = `
role="tooltip"
>
-
-
+
@@ -2622,17 +2619,14 @@ exports[`TextInput renders trailingAction text button 1`] = `
color: inherit;
}
-.c6 {
- position: absolute;
- width: 1px;
+.c6:not(:focus):not(:active):not(:focus-within) {
+ -webkit-clip-path: inset(50%);
+ clip-path: inset(50%);
height: 1px;
- padding: 0;
- margin: -1px;
overflow: hidden;
- -webkit-clip: rect(0,0,0,0);
- clip: rect(0,0,0,0);
+ position: absolute;
white-space: nowrap;
- border-width: 0;
+ width: 1px;
}
.c0 {
@@ -2771,8 +2765,8 @@ exports[`TextInput renders trailingAction text button 1`] = `
className="c3 TextInput-action"
>
Clear
-
-
+
`;
@@ -3066,17 +3060,14 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = `
color: inherit;
}
-.c7 {
- position: absolute;
- width: 1px;
+.c7:not(:focus):not(:active):not(:focus-within) {
+ -webkit-clip-path: inset(50%);
+ clip-path: inset(50%);
height: 1px;
- padding: 0;
- margin: -1px;
overflow: hidden;
- -webkit-clip: rect(0,0,0,0);
- clip: rect(0,0,0,0);
+ position: absolute;
white-space: nowrap;
- border-width: 0;
+ width: 1px;
}
.c0 {
@@ -3446,8 +3437,8 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = `
role="tooltip"
>
Clear
-
-
+
diff --git a/src/__tests__/__snapshots__/TextInputWithTokens.test.tsx.snap b/src/__tests__/__snapshots__/TextInputWithTokens.test.tsx.snap
index 613f21788ff..10add57f107 100644
--- a/src/__tests__/__snapshots__/TextInputWithTokens.test.tsx.snap
+++ b/src/__tests__/__snapshots__/TextInputWithTokens.test.tsx.snap
@@ -6240,6 +6240,12 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
position: relative;
}
+.c10 {
+ -webkit-animation: rotate-keyframes 1s linear infinite;
+ animation: rotate-keyframes 1s linear infinite;
+ visibility: visible;
+}
+
.c7 {
position: absolute;
width: 1px;
@@ -6253,12 +6259,6 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
border-width: 0;
}
-.c10 {
- -webkit-animation: rotate-keyframes 1s linear infinite;
- animation: rotate-keyframes 1s linear infinite;
- visibility: visible;
-}
-
.c0 {
font-size: 14px;
line-height: 20px;
@@ -7016,6 +7016,18 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
position: relative;
}
+.c3 {
+ -webkit-animation: rotate-keyframes 1s linear infinite;
+ animation: rotate-keyframes 1s linear infinite;
+ visibility: visible;
+}
+
+.c11 {
+ -webkit-animation: rotate-keyframes 1s linear infinite;
+ animation: rotate-keyframes 1s linear infinite;
+ visibility: hidden;
+}
+
.c9 {
position: absolute;
width: 1px;
@@ -7029,18 +7041,6 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
border-width: 0;
}
-.c3 {
- -webkit-animation: rotate-keyframes 1s linear infinite;
- animation: rotate-keyframes 1s linear infinite;
- visibility: visible;
-}
-
-.c11 {
- -webkit-animation: rotate-keyframes 1s linear infinite;
- animation: rotate-keyframes 1s linear infinite;
- visibility: hidden;
-}
-
.c0 {
font-size: 14px;
line-height: 20px;
@@ -7836,6 +7836,12 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
position: relative;
}
+.c10 {
+ -webkit-animation: rotate-keyframes 1s linear infinite;
+ animation: rotate-keyframes 1s linear infinite;
+ visibility: visible;
+}
+
.c7 {
position: absolute;
width: 1px;
@@ -7849,12 +7855,6 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
border-width: 0;
}
-.c10 {
- -webkit-animation: rotate-keyframes 1s linear infinite;
- animation: rotate-keyframes 1s linear infinite;
- visibility: visible;
-}
-
.c0 {
font-size: 14px;
line-height: 20px;
@@ -8616,19 +8616,6 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
visibility: hidden;
}
-.c10 {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- -webkit-clip: rect(0,0,0,0);
- clip: rect(0,0,0,0);
- white-space: nowrap;
- border-width: 0;
-}
-
.c12 {
-webkit-animation: rotate-keyframes 1s linear infinite;
animation: rotate-keyframes 1s linear infinite;
@@ -8646,6 +8633,19 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
left: 0;
}
+.c10 {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ -webkit-clip: rect(0,0,0,0);
+ clip: rect(0,0,0,0);
+ white-space: nowrap;
+ border-width: 0;
+}
+
.c0 {
font-size: 14px;
line-height: 20px;
@@ -9476,19 +9476,6 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
visibility: hidden;
}
-.c10 {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- -webkit-clip: rect(0,0,0,0);
- clip: rect(0,0,0,0);
- white-space: nowrap;
- border-width: 0;
-}
-
.c12 {
-webkit-animation: rotate-keyframes 1s linear infinite;
animation: rotate-keyframes 1s linear infinite;
@@ -9506,6 +9493,19 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
left: 0;
}
+.c10 {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ -webkit-clip: rect(0,0,0,0);
+ clip: rect(0,0,0,0);
+ white-space: nowrap;
+ border-width: 0;
+}
+
.c0 {
font-size: 14px;
line-height: 20px;
@@ -10336,19 +10336,6 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
visibility: visible;
}
-.c10 {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- -webkit-clip: rect(0,0,0,0);
- clip: rect(0,0,0,0);
- white-space: nowrap;
- border-width: 0;
-}
-
.c12 {
-webkit-animation: rotate-keyframes 1s linear infinite;
animation: rotate-keyframes 1s linear infinite;
@@ -10366,6 +10353,19 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
left: 0;
}
+.c10 {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ -webkit-clip: rect(0,0,0,0);
+ clip: rect(0,0,0,0);
+ white-space: nowrap;
+ border-width: 0;
+}
+
.c0 {
font-size: 14px;
line-height: 20px;
@@ -11196,6 +11196,17 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
visibility: hidden;
}
+.c11 {
+ -webkit-animation: rotate-keyframes 1s linear infinite;
+ animation: rotate-keyframes 1s linear infinite;
+ position: absolute;
+ top: 0;
+ height: 100%;
+ max-width: 100%;
+ visibility: visible;
+ right: 0;
+}
+
.c7 {
position: absolute;
width: 1px;
@@ -11209,17 +11220,6 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
border-width: 0;
}
-.c11 {
- -webkit-animation: rotate-keyframes 1s linear infinite;
- animation: rotate-keyframes 1s linear infinite;
- position: absolute;
- top: 0;
- height: 100%;
- max-width: 100%;
- visibility: visible;
- right: 0;
-}
-
.c0 {
font-size: 14px;
line-height: 20px;
@@ -12012,19 +12012,6 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
visibility: visible;
}
-.c9 {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- -webkit-clip: rect(0,0,0,0);
- clip: rect(0,0,0,0);
- white-space: nowrap;
- border-width: 0;
-}
-
.c3 {
-webkit-animation: rotate-keyframes 1s linear infinite;
animation: rotate-keyframes 1s linear infinite;
@@ -12042,6 +12029,19 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
right: 0;
}
+.c9 {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ -webkit-clip: rect(0,0,0,0);
+ clip: rect(0,0,0,0);
+ white-space: nowrap;
+ border-width: 0;
+}
+
.c0 {
font-size: 14px;
line-height: 20px;
@@ -12872,6 +12872,17 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
visibility: hidden;
}
+.c11 {
+ -webkit-animation: rotate-keyframes 1s linear infinite;
+ animation: rotate-keyframes 1s linear infinite;
+ position: absolute;
+ top: 0;
+ height: 100%;
+ max-width: 100%;
+ visibility: visible;
+ right: 0;
+}
+
.c7 {
position: absolute;
width: 1px;
@@ -12885,17 +12896,6 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
border-width: 0;
}
-.c11 {
- -webkit-animation: rotate-keyframes 1s linear infinite;
- animation: rotate-keyframes 1s linear infinite;
- position: absolute;
- top: 0;
- height: 100%;
- max-width: 100%;
- visibility: visible;
- right: 0;
-}
-
.c0 {
font-size: 14px;
line-height: 20px;
@@ -13692,19 +13692,6 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
visibility: visible;
}
-.c10 {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- -webkit-clip: rect(0,0,0,0);
- clip: rect(0,0,0,0);
- white-space: nowrap;
- border-width: 0;
-}
-
.c4 {
-webkit-animation: rotate-keyframes 1s linear infinite;
animation: rotate-keyframes 1s linear infinite;
@@ -13727,6 +13714,19 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
right: 0;
}
+.c10 {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ -webkit-clip: rect(0,0,0,0);
+ clip: rect(0,0,0,0);
+ white-space: nowrap;
+ border-width: 0;
+}
+
.c0 {
font-size: 14px;
line-height: 20px;
@@ -14597,19 +14597,6 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
visibility: visible;
}
-.c10 {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- -webkit-clip: rect(0,0,0,0);
- clip: rect(0,0,0,0);
- white-space: nowrap;
- border-width: 0;
-}
-
.c4 {
-webkit-animation: rotate-keyframes 1s linear infinite;
animation: rotate-keyframes 1s linear infinite;
@@ -14632,6 +14619,19 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
right: 0;
}
+.c10 {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ -webkit-clip: rect(0,0,0,0);
+ clip: rect(0,0,0,0);
+ white-space: nowrap;
+ border-width: 0;
+}
+
.c0 {
font-size: 14px;
line-height: 20px;
@@ -15497,19 +15497,6 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
visibility: visible;
}
-.c10 {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- -webkit-clip: rect(0,0,0,0);
- clip: rect(0,0,0,0);
- white-space: nowrap;
- border-width: 0;
-}
-
.c4 {
-webkit-animation: rotate-keyframes 1s linear infinite;
animation: rotate-keyframes 1s linear infinite;
@@ -15532,6 +15519,19 @@ exports[`TextInputWithTokens renders with a loading indicator 1`] = `
right: 0;
}
+.c10 {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ -webkit-clip: rect(0,0,0,0);
+ clip: rect(0,0,0,0);
+ white-space: nowrap;
+ border-width: 0;
+}
+
.c0 {
font-size: 14px;
line-height: 20px;
From 0e276de4ad77cccf8521734c956a2fdf2538f5dd Mon Sep 17 00:00:00 2001
From: Mike Perrotti
Date: Tue, 5 Dec 2023 11:23:57 -0500
Subject: [PATCH 21/51] documents loading props
---
src/Button/Button.docs.json | 33 ++++++++++++++++++++++-----------
src/Button/types.ts | 6 ++++++
2 files changed, 28 insertions(+), 11 deletions(-)
diff --git a/src/Button/Button.docs.json b/src/Button/Button.docs.json
index e6f74974f5b..722de300ff3 100644
--- a/src/Button/Button.docs.json
+++ b/src/Button/Button.docs.json
@@ -17,17 +17,6 @@
"type": "number | string",
"description": "For counter buttons, the number to display."
},
- {
- "name": "variant",
- "type": "'default'\n| 'primary'\n| 'danger'\n| 'invisible'",
- "defaultValue": "'default'",
- "description": "Change the visual style of the button."
- },
- {
- "name": "size",
- "type": "'small'\n| 'medium'\n| 'large'",
- "defaultValue": "'medium'"
- },
{
"name": "leadingIcon",
"type": "React.ComponentType",
@@ -39,6 +28,22 @@
"type": "React.ElementType",
"description": "A visual to display before the button text."
},
+ {
+ "name": "loading",
+ "type": "boolean",
+ "description": "When true, the button is in a loading state."
+ },
+ {
+ "name": "loadingAnnouncement",
+ "type": "string",
+ "description": "The content to announce to screen readers when loading."
+ },
+
+ {
+ "name": "size",
+ "type": "'small'\n| 'medium'\n| 'large'",
+ "defaultValue": "'medium'"
+ },
{
"name": "trailingIcon",
"type": "React.ComponentType",
@@ -50,6 +55,12 @@
"type": "React.ElementType",
"description": "A visual to display after the button text."
},
+ {
+ "name": "variant",
+ "type": "'default'\n| 'primary'\n| 'danger'\n| 'invisible'",
+ "defaultValue": "'default'",
+ "description": "Change the visual style of the button."
+ },
{
"name": "as",
"type": "React.ElementType",
diff --git a/src/Button/types.ts b/src/Button/types.ts
index bc2a0dcc7e2..c214e3090d4 100644
--- a/src/Button/types.ts
+++ b/src/Button/types.ts
@@ -35,7 +35,13 @@ export type ButtonBaseProps = {
* Allow button width to fill its container.
*/
block?: boolean
+ /**
+ * When true, the button is in a loading state.
+ */
loading?: boolean
+ /**
+ * The content to announce to screen readers when loading.
+ */
loadingAnnouncement?: string
} & SxProp &
React.ButtonHTMLAttributes
From e8fcd21cd2eb547fdc2d822ba2dcd5def30b92e8 Mon Sep 17 00:00:00 2001
From: Mike Perrotti
Date: Tue, 5 Dec 2023 12:48:14 -0500
Subject: [PATCH 22/51] adds VRTs, updates loading feature stories
---
e2e/components/Button.test.ts | 136 +++++++++++++++++++++++++
src/Button/Button.features.stories.tsx | 63 +++---------
2 files changed, 149 insertions(+), 50 deletions(-)
diff --git a/e2e/components/Button.test.ts b/e2e/components/Button.test.ts
index d9a4755ab1a..b87984fa2a7 100644
--- a/e2e/components/Button.test.ts
+++ b/e2e/components/Button.test.ts
@@ -445,6 +445,142 @@ test.describe('Button', () => {
}
})
+ test.describe('Loading', () => {
+ for (const theme of themes) {
+ test.describe(theme, () => {
+ test('default @vrt', async ({page}) => {
+ await visit(page, {
+ id: 'components-button-features--loading',
+ globals: {
+ colorScheme: theme,
+ },
+ })
+
+ // Default state
+ expect(await page.screenshot()).toMatchSnapshot(`Button.Loading.${theme}.png`)
+ })
+
+ test('axe @aat', async ({page}) => {
+ await visit(page, {
+ id: 'components-button-features--loading',
+ globals: {
+ colorScheme: theme,
+ },
+ })
+ await expect(page).toHaveNoViolations({
+ rules: {
+ 'color-contrast': {
+ enabled: theme !== 'dark_dimmed',
+ },
+ },
+ })
+ })
+ })
+ }
+ })
+
+ test.describe('Loading Custom Announcement', () => {
+ for (const theme of themes) {
+ test.describe(theme, () => {
+ test('default @vrt', async ({page}) => {
+ await visit(page, {
+ id: 'components-button-features--loading-custom-message',
+ globals: {
+ colorScheme: theme,
+ },
+ })
+
+ // Default state
+ expect(await page.screenshot()).toMatchSnapshot(`Button.Loading Custom Announcement.${theme}.png`)
+ })
+
+ test('axe @aat', async ({page}) => {
+ await visit(page, {
+ id: 'components-button-features--loading-custom-message',
+ globals: {
+ colorScheme: theme,
+ },
+ })
+ await expect(page).toHaveNoViolations({
+ rules: {
+ 'color-contrast': {
+ enabled: theme !== 'dark_dimmed',
+ },
+ },
+ })
+ })
+ })
+ }
+ })
+
+ test.describe('Loading With Leading Visual', () => {
+ for (const theme of themes) {
+ test.describe(theme, () => {
+ test('default @vrt', async ({page}) => {
+ await visit(page, {
+ id: 'components-button-features--loading-with-leading-visual',
+ globals: {
+ colorScheme: theme,
+ },
+ })
+
+ // Default state
+ expect(await page.screenshot()).toMatchSnapshot(`Button.Loading With Leading Visual.${theme}.png`)
+ })
+
+ test('axe @aat', async ({page}) => {
+ await visit(page, {
+ id: 'components-button-features--loading-with-leading-visual',
+ globals: {
+ colorScheme: theme,
+ },
+ })
+ await expect(page).toHaveNoViolations({
+ rules: {
+ 'color-contrast': {
+ enabled: theme !== 'dark_dimmed',
+ },
+ },
+ })
+ })
+ })
+ }
+ })
+
+ test.describe('Loading With Trailing Visual', () => {
+ for (const theme of themes) {
+ test.describe(theme, () => {
+ test('default @vrt', async ({page}) => {
+ await visit(page, {
+ id: 'components-button-features--loading-with-trailing-visual',
+ globals: {
+ colorScheme: theme,
+ },
+ })
+
+ // Default state
+ expect(await page.screenshot()).toMatchSnapshot(`Button.Loading With Trailing Visual.${theme}.png`)
+ })
+
+ test('axe @aat', async ({page}) => {
+ await visit(page, {
+ id: 'components-button-features--loading-with-trailing-visual',
+ globals: {
+ colorScheme: theme,
+ },
+ })
+ await expect(page).toHaveNoViolations({
+ rules: {
+ 'color-contrast': {
+ enabled: theme !== 'dark_dimmed',
+ },
+ },
+ })
+ })
+ })
+ }
+ })
+
test.describe('Dev: Invisible Variants', () => {
for (const theme of themes) {
test.describe(theme, () => {
diff --git a/src/Button/Button.features.stories.tsx b/src/Button/Button.features.stories.tsx
index a7062bab0ec..367645bc4bd 100644
--- a/src/Button/Button.features.stories.tsx
+++ b/src/Button/Button.features.stories.tsx
@@ -69,59 +69,22 @@ export const Medium = () => Default
export const Large = () => Default
-export const LoadingWithLeadingVisual = () => {
- const [isLoading, setIsLoading] = useState(false)
+export const Loading = () => Default
- const handleClick = () => {
- setIsLoading(true)
- setTimeout(() => {
- setIsLoading(false)
- }, 3000)
- }
-
- return (
-
- Export
-
- )
-}
-
-export const LoadingCustomMessage = () => (
-
+export const LoadingCustomAnnouncement = () => (
+
Default
)
-export const LoadingWithNoVisuals = () => {
- const [isLoading, setIsLoading] = useState(false)
-
- const handleClick = () => {
- setIsLoading(true)
- setTimeout(() => {
- setIsLoading(false)
- }, 3000)
- }
-
- return (
-
- Export
-
- )
-}
-
-export const LoadingWithTrailingVisual = () => {
- const [isLoading, setIsLoading] = useState(false)
-
- const handleClick = () => {
- setIsLoading(true)
- setTimeout(() => {
- setIsLoading(false)
- }, 3000)
- }
+export const LoadingWithLeadingVisual = () => (
+
+ Export
+
+)
- return (
-
- Export
-
- )
-}
+export const LoadingWithTrailingVisual = () => (
+
+ Export
+
+)
From e63e61c5b9ae405d7140a8a9c8144068666f8bff Mon Sep 17 00:00:00 2001
From: Mike Perrotti
Date: Tue, 5 Dec 2023 14:10:21 -0500
Subject: [PATCH 23/51] simplifies inner visual/spinner rendering logic
---
src/Button/ButtonBase.tsx | 43 +++++++++++++--------------------------
1 file changed, 14 insertions(+), 29 deletions(-)
diff --git a/src/Button/ButtonBase.tsx b/src/Button/ButtonBase.tsx
index f1415742ac5..301763dc2bf 100644
--- a/src/Button/ButtonBase.tsx
+++ b/src/Button/ButtonBase.tsx
@@ -12,6 +12,17 @@ import Spinner from '../Spinner'
import CounterLabel from '../CounterLabel'
import {useId} from '../hooks'
+const iconWrapStyles = {
+ display: 'flex',
+ pointerEvents: 'none',
+}
+
+const renderVisual = (Visual: React.ElementType, loading: boolean, visualName: string) => (
+
+ {loading ? : }
+
+)
+
const ButtonBase = forwardRef(
({children, as: Component = 'button', sx: sxProp = defaultSxProp, ...props}, forwardedRef): JSX.Element => {
const {
@@ -42,10 +53,6 @@ const ButtonBase = forwardRef(
const sxStyles = useMemo(() => {
return merge(baseStyles, sxProp)
}, [baseStyles, sxProp])
- const iconWrapStyles = {
- display: 'flex',
- pointerEvents: 'none',
- }
const uuid = useId(id)
const loadingAnnouncementID = `${uuid}-loading-announcement`
const buttonLabelID = ariaLabelledBy || `${uuid}-label`
@@ -97,21 +104,8 @@ const ButtonBase = forwardRef(
) : (
<>
- {loading && !LeadingVisual && !TrailingVisual && (
-
-
-
- )}
- {LeadingVisual && loading && (
-
-
-
- )}
- {LeadingVisual && !loading && (
-
-
-
- )}
+ {loading && !LeadingVisual && !TrailingVisual && renderVisual(Spinner, loading, 'loadingSpinner')}
+ {LeadingVisual && renderVisual(LeadingVisual, loading, 'leadingVisual')}
{children && (
{children}
@@ -122,16 +116,7 @@ const ButtonBase = forwardRef(
)}
)}
- {TrailingVisual && !loading && (
-
-
-
- )}
- {TrailingVisual && loading && (
-
-
-
- )}
+ {TrailingVisual && renderVisual(TrailingVisual, loading, 'trailingVisual')}
{TrailingAction && (
From 8a901da3083585efcb167e7eab0fa2f6c788e800 Mon Sep 17 00:00:00 2001
From: Mike Perrotti
Date: Tue, 5 Dec 2023 14:11:40 -0500
Subject: [PATCH 24/51] removes example stories (we can put them back when
Flash supports focusing its heading)
---
src/Button/Button.examples.stories.tsx | 36 --------------------------
1 file changed, 36 deletions(-)
delete mode 100644 src/Button/Button.examples.stories.tsx
diff --git a/src/Button/Button.examples.stories.tsx b/src/Button/Button.examples.stories.tsx
deleted file mode 100644
index d9a3f75fc43..00000000000
--- a/src/Button/Button.examples.stories.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import React, {useState} from 'react'
-import type {Meta} from '@storybook/react'
-import {Button} from '.'
-import {Flash} from '..'
-
-const meta: Meta = {
- title: 'Components/Button/Examples',
-} as Meta
-
-export default meta
-
-export const LoadingWithError = () => {
- const [isLoading, setIsLoading] = useState(false)
- const [hasError, setHasError] = useState(false)
-
- const handleClick = () => {
- setIsLoading(true)
- setTimeout(() => {
- setIsLoading(false)
- setHasError(true)
- }, 1500)
- }
-
- return (
- <>
- {hasError && (
-
- Export failed. Try again.
-
- )}
-
- Export
-
- >
- )
-}
From ffdff03f09386b1e965b0d8e21f5218f935ee0c2 Mon Sep 17 00:00:00 2001
From: Mike Perrotti
Date: Thu, 7 Dec 2023 15:10:47 -0500
Subject: [PATCH 25/51] excludes loading buttons from axe contrast check
---
e2e/components/Button.test.ts | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/e2e/components/Button.test.ts b/e2e/components/Button.test.ts
index 9a88fc6589b..c5ee1ecdfe0 100644
--- a/e2e/components/Button.test.ts
+++ b/e2e/components/Button.test.ts
@@ -504,7 +504,7 @@ test.describe('Button', () => {
await expect(page).toHaveNoViolations({
rules: {
'color-contrast': {
- enabled: theme !== 'dark_dimmed',
+ enabled: false,
},
},
})
@@ -538,7 +538,7 @@ test.describe('Button', () => {
await expect(page).toHaveNoViolations({
rules: {
'color-contrast': {
- enabled: theme !== 'dark_dimmed',
+ enabled: false,
},
},
})
@@ -572,7 +572,7 @@ test.describe('Button', () => {
await expect(page).toHaveNoViolations({
rules: {
'color-contrast': {
- enabled: theme !== 'dark_dimmed',
+ enabled: false,
},
},
})
@@ -606,7 +606,7 @@ test.describe('Button', () => {
await expect(page).toHaveNoViolations({
rules: {
'color-contrast': {
- enabled: theme !== 'dark_dimmed',
+ enabled: false,
},
},
})
From 9d133a0987bb2b510bace88515597afc1d57a92a Mon Sep 17 00:00:00 2001
From: Mike Perrotti
Date: Thu, 7 Dec 2023 15:19:33 -0500
Subject: [PATCH 26/51] fixes visual regression: button counter vertical
alignment
---
.../__snapshots__/Button.test.tsx.snap | 64 +++++++++++++++++++
src/Button/styles.ts | 2 +
src/Dialog/__snapshots__/Dialog.test.tsx.snap | 8 +++
.../__snapshots__/SelectPanel.test.tsx.snap | 8 +++
.../__snapshots__/ActionMenu.test.tsx.snap | 8 +++
.../__snapshots__/TextInput.test.tsx.snap | 24 +++++++
6 files changed, 114 insertions(+)
diff --git a/src/Button/__tests__/__snapshots__/Button.test.tsx.snap b/src/Button/__tests__/__snapshots__/Button.test.tsx.snap
index d9e981c6d27..7665a7ccc88 100644
--- a/src/Button/__tests__/__snapshots__/Button.test.tsx.snap
+++ b/src/Button/__tests__/__snapshots__/Button.test.tsx.snap
@@ -178,6 +178,14 @@ exports[`Button renders consistently 1`] = `
}
.c0 [data-component="text"] {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
grid-area: text;
line-height: calc(20/14);
white-space: nowrap;
@@ -465,6 +473,14 @@ exports[`Button respects block prop 1`] = `
}
.c0 [data-component="text"] {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
grid-area: text;
line-height: calc(20/14);
white-space: nowrap;
@@ -735,6 +751,14 @@ exports[`Button respects the alignContent prop 1`] = `
}
.c0 [data-component="text"] {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
grid-area: text;
line-height: calc(20/14);
white-space: nowrap;
@@ -1004,6 +1028,14 @@ exports[`Button respects the large size prop 1`] = `
}
.c0 [data-component="text"] {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
grid-area: text;
line-height: calc(20/14);
white-space: nowrap;
@@ -1274,6 +1306,14 @@ exports[`Button respects the small size prop 1`] = `
}
.c0 [data-component="text"] {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
grid-area: text;
line-height: calc(20/14);
white-space: nowrap;
@@ -1549,6 +1589,14 @@ exports[`Button styles danger button appropriately 1`] = `
}
.c0 [data-component="text"] {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
grid-area: text;
line-height: calc(20/14);
white-space: nowrap;
@@ -1828,6 +1876,14 @@ exports[`Button styles invisible button appropriately 1`] = `
}
.c0 [data-component="text"] {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
grid-area: text;
line-height: calc(20/14);
white-space: nowrap;
@@ -2114,6 +2170,14 @@ exports[`Button styles primary button appropriately 1`] = `
}
.c0 [data-component="text"] {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
grid-area: text;
line-height: calc(20/14);
white-space: nowrap;
diff --git a/src/Button/styles.ts b/src/Button/styles.ts
index 9fccf678c35..9180050c00c 100644
--- a/src/Button/styles.ts
+++ b/src/Button/styles.ts
@@ -307,6 +307,8 @@ export const getButtonStyles = (theme?: Theme) => {
gridArea: 'leadingVisual',
},
'[data-component="text"]': {
+ alignItems: 'center',
+ display: 'flex',
gridArea: 'text',
lineHeight: 'calc(20/14)',
whiteSpace: 'nowrap',
diff --git a/src/Dialog/__snapshots__/Dialog.test.tsx.snap b/src/Dialog/__snapshots__/Dialog.test.tsx.snap
index 72cb46074bf..0f8aaa876e3 100644
--- a/src/Dialog/__snapshots__/Dialog.test.tsx.snap
+++ b/src/Dialog/__snapshots__/Dialog.test.tsx.snap
@@ -255,6 +255,14 @@ exports[`Dialog renders consistently 1`] = `
}
.c1 [data-component="text"] {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
grid-area: text;
line-height: calc(20/14);
white-space: nowrap;
diff --git a/src/SelectPanel/__snapshots__/SelectPanel.test.tsx.snap b/src/SelectPanel/__snapshots__/SelectPanel.test.tsx.snap
index a1d1883784d..8e4dc1a4c13 100644
--- a/src/SelectPanel/__snapshots__/SelectPanel.test.tsx.snap
+++ b/src/SelectPanel/__snapshots__/SelectPanel.test.tsx.snap
@@ -191,6 +191,14 @@ exports[`SelectPanel renders consistently 1`] = `
}
.c1 [data-component="text"] {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
grid-area: text;
line-height: calc(20/14);
white-space: nowrap;
diff --git a/src/__tests__/__snapshots__/ActionMenu.test.tsx.snap b/src/__tests__/__snapshots__/ActionMenu.test.tsx.snap
index 6d746cec641..1c41ea3a8be 100644
--- a/src/__tests__/__snapshots__/ActionMenu.test.tsx.snap
+++ b/src/__tests__/__snapshots__/ActionMenu.test.tsx.snap
@@ -191,6 +191,14 @@ exports[`ActionMenu renders consistently 1`] = `
}
.c1 [data-component="text"] {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
grid-area: text;
line-height: calc(20/14);
white-space: nowrap;
diff --git a/src/__tests__/__snapshots__/TextInput.test.tsx.snap b/src/__tests__/__snapshots__/TextInput.test.tsx.snap
index da2b250a05d..79e95438dae 100644
--- a/src/__tests__/__snapshots__/TextInput.test.tsx.snap
+++ b/src/__tests__/__snapshots__/TextInput.test.tsx.snap
@@ -1870,6 +1870,14 @@ exports[`TextInput renders trailingAction icon button 1`] = `
}
.c5 [data-component="text"] {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
grid-area: text;
line-height: calc(20/14);
white-space: nowrap;
@@ -2573,6 +2581,14 @@ exports[`TextInput renders trailingAction text button 1`] = `
}
.c4 [data-component="text"] {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
grid-area: text;
line-height: calc(20/14);
white-space: nowrap;
@@ -3029,6 +3045,14 @@ exports[`TextInput renders trailingAction text button with a tooltip 1`] = `
}
.c5 [data-component="text"] {
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
grid-area: text;
line-height: calc(20/14);
white-space: nowrap;
From 611eea041b28068fb13cf1c433b6bba1075dd559 Mon Sep 17 00:00:00 2001
From: Mike Perrotti
Date: Mon, 11 Dec 2023 13:45:31 -0500
Subject: [PATCH 27/51] prevents double spinners when leading and trailing
visuals are passed
---
src/Button/ButtonBase.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Button/ButtonBase.tsx b/src/Button/ButtonBase.tsx
index 90be3cbcd07..918427ed87f 100644
--- a/src/Button/ButtonBase.tsx
+++ b/src/Button/ButtonBase.tsx
@@ -118,7 +118,7 @@ const ButtonBase = forwardRef(
)}
)}
- {TrailingVisual && renderVisual(TrailingVisual, loading, 'trailingVisual')}
+ {TrailingVisual && renderVisual(TrailingVisual, loading && !LeadingVisual, 'trailingVisual')}
{TrailingAction && (
From 7cf14caf5cff58b2fc39edf6afcbd552790f48ba Mon Sep 17 00:00:00 2001
From: Josh Black
Date: Wed, 13 Dec 2023 12:31:44 -0600
Subject: [PATCH 28/51] test(e2e): update story ids
---
e2e/components/Button.test.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/e2e/components/Button.test.ts b/e2e/components/Button.test.ts
index c5ee1ecdfe0..c51b72f56a9 100644
--- a/e2e/components/Button.test.ts
+++ b/e2e/components/Button.test.ts
@@ -518,7 +518,7 @@ test.describe('Button', () => {
test.describe(theme, () => {
test('default @vrt', async ({page}) => {
await visit(page, {
- id: 'components-button-features--loading-custom-message',
+ id: 'components-button-features--loading-custom-announcement',
globals: {
colorScheme: theme,
},
@@ -530,7 +530,7 @@ test.describe('Button', () => {
test('axe @aat', async ({page}) => {
await visit(page, {
- id: 'components-button-features--loading-custom-message',
+ id: 'components-button-features--loading-custom-announcement',
globals: {
colorScheme: theme,
},
From 1a4a08d4a7abc571d90d364ba33afca535f63995 Mon Sep 17 00:00:00 2001
From: joshblack
Date: Wed, 13 Dec 2023 18:38:43 +0000
Subject: [PATCH 29/51] test(vrt): update snapshots
---
...tom-Announcement-dark-colorblind-linux.png | Bin 0 -> 5930 bytes
...-Custom-Announcement-dark-dimmed-linux.png | Bin 0 -> 5899 bytes
...-Announcement-dark-high-contrast-linux.png | Bin 0 -> 6112 bytes
...Loading-Custom-Announcement-dark-linux.png | Bin 0 -> 5910 bytes
...tom-Announcement-dark-tritanopia-linux.png | Bin 0 -> 5930 bytes
...om-Announcement-light-colorblind-linux.png | Bin 0 -> 6041 bytes
...Announcement-light-high-contrast-linux.png | Bin 0 -> 6152 bytes
...oading-Custom-Announcement-light-linux.png | Bin 0 -> 6034 bytes
...om-Announcement-light-tritanopia-linux.png | Bin 0 -> 6043 bytes
...h-Leading-Visual-dark-colorblind-linux.png | Bin 0 -> 6929 bytes
...-With-Leading-Visual-dark-dimmed-linux.png | Bin 0 -> 6813 bytes
...eading-Visual-dark-high-contrast-linux.png | Bin 0 -> 7189 bytes
...Loading-With-Leading-Visual-dark-linux.png | Bin 0 -> 6920 bytes
...h-Leading-Visual-dark-tritanopia-linux.png | Bin 0 -> 6946 bytes
...-Leading-Visual-light-colorblind-linux.png | Bin 0 -> 7064 bytes
...ading-Visual-light-high-contrast-linux.png | Bin 0 -> 7241 bytes
...oading-With-Leading-Visual-light-linux.png | Bin 0 -> 7056 bytes
...-Leading-Visual-light-tritanopia-linux.png | Bin 0 -> 7085 bytes
...-Trailing-Visual-dark-colorblind-linux.png | Bin 0 -> 6933 bytes
...With-Trailing-Visual-dark-dimmed-linux.png | Bin 0 -> 6799 bytes
...ailing-Visual-dark-high-contrast-linux.png | Bin 0 -> 7173 bytes
...oading-With-Trailing-Visual-dark-linux.png | Bin 0 -> 6901 bytes
...-Trailing-Visual-dark-tritanopia-linux.png | Bin 0 -> 6914 bytes
...Trailing-Visual-light-colorblind-linux.png | Bin 0 -> 7047 bytes
...iling-Visual-light-high-contrast-linux.png | Bin 0 -> 7232 bytes
...ading-With-Trailing-Visual-light-linux.png | Bin 0 -> 7057 bytes
...Trailing-Visual-light-tritanopia-linux.png | Bin 0 -> 7068 bytes
.../Button-Loading-dark-colorblind-linux.png | Bin 0 -> 5930 bytes
.../Button-Loading-dark-dimmed-linux.png | Bin 0 -> 5889 bytes
...utton-Loading-dark-high-contrast-linux.png | Bin 0 -> 6112 bytes
.../Button-Loading-dark-linux.png | Bin 0 -> 5930 bytes
.../Button-Loading-dark-tritanopia-linux.png | Bin 0 -> 5930 bytes
.../Button-Loading-light-colorblind-linux.png | Bin 0 -> 6041 bytes
...tton-Loading-light-high-contrast-linux.png | Bin 0 -> 6152 bytes
.../Button-Loading-light-linux.png | Bin 0 -> 6037 bytes
.../Button-Loading-light-tritanopia-linux.png | Bin 0 -> 6041 bytes
...Group-Default-dark-high-contrast-linux.png | Bin 8034 -> 7804 bytes
...roup-Default-light-high-contrast-linux.png | Bin 8068 -> 7837 bytes
...-Icon-Buttons-dark-high-contrast-linux.png | Bin 5463 -> 5268 bytes
...Icon-Buttons-light-high-contrast-linux.png | Bin 5525 -> 5363 bytes
...up-Playground-dark-high-contrast-linux.png | Bin 8034 -> 7804 bytes
...p-Playground-light-high-contrast-linux.png | Bin 8068 -> 7837 bytes
42 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-Custom-Announcement-dark-colorblind-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-Custom-Announcement-dark-dimmed-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-Custom-Announcement-dark-high-contrast-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-Custom-Announcement-dark-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-Custom-Announcement-dark-tritanopia-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-Custom-Announcement-light-colorblind-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-Custom-Announcement-light-high-contrast-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-Custom-Announcement-light-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-Custom-Announcement-light-tritanopia-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-dark-colorblind-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-dark-dimmed-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-dark-high-contrast-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-dark-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-dark-tritanopia-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-light-colorblind-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-light-high-contrast-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-light-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-light-tritanopia-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Trailing-Visual-dark-colorblind-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Trailing-Visual-dark-dimmed-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Trailing-Visual-dark-high-contrast-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Trailing-Visual-dark-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Trailing-Visual-dark-tritanopia-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Trailing-Visual-light-colorblind-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Trailing-Visual-light-high-contrast-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Trailing-Visual-light-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Trailing-Visual-light-tritanopia-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-dark-colorblind-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-dark-dimmed-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-dark-high-contrast-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-dark-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-dark-tritanopia-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-light-colorblind-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-light-high-contrast-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-light-linux.png
create mode 100644 .playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-light-tritanopia-linux.png
diff --git a/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-Custom-Announcement-dark-colorblind-linux.png b/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-Custom-Announcement-dark-colorblind-linux.png
new file mode 100644
index 0000000000000000000000000000000000000000..8d3193c7f0853de7c0fc33e78b313ffcb500d989
GIT binary patch
literal 5930
zcmeHL|4$QV7(WIox=H=A=rWNyx4_hfZ#uq~b|_BCHrSkrW72hwv}6lyg$kumu0+Dn
zk%7NRt$f{2%n*v&t+gCdBhJPgP__nvm1{+$rIZ$=(9&M7x3|mwfVsG2KlF#YH+P?V
zKKDHD^Ld{4?!Ej;-ifVS-rNE~(AM0OIj0~fd=(r}JyUXp+kv|Wt8&YLqfb-O2T?`nYb?fFTFhuSEZ-utKGY_zRC&$7e=>02Qn;@um
zUp55**%yNkUyR5C=ZJq~fH(Ljd(QM(er=Sw7N?Zy(NPqy&D=ZtJWZ`uyPTL&qtS>L
zO99_{-REEWZLO#kes(@>m>pOV2-74sMAZ_|`UhsC?*N{?X=`-c@?-9=gd}3OL2!*e_J7Rxw(1W25PLOm>Vxc+w!_K;_Aa_f2%-CxNn_!1%jSX
zo+#@AYxW7HnQ9?$4<#x858T5X&Fr@pdy3pduR{bL0qu==SUY
zmhkbBF1Bo{7oT#7lnO*ssFI_}GBm}`Pd%eoSjT%NTr&ZFz%C$dtjeGpZG~eAXa-K4
zt3a^Acv*T(voKvC94rCsg_dMCEPk(H=$soN{PtA)w11fxkdm|hye1z=`n_Uw12J=c
z{mwxxPe||J8b`@VuC#;4Z4u)`6k$e;l^yU~H87mzp*pSIMx&+;dk6$_&v2#xbpdOl
zK!g;?IE-lKuvg-f?{Oz6St`w4q+OjVuu4ppxyCcX8p8i67l^x-eeB@8sI#Lkv!h8k
zr6OG-eYatHzzdtm_1Q&AgJuwBpbPHmU_{@2G}dR&K)btbDuZ`-dxLg3MI=%KZtu!M
zW9cQJ&D!q$J6DaWk$xIgJxM;TcXOOePDZ^ygDojtJCqj*ShVdymSpN#*ee&hm`i1v
z;hFQ-9Fh)<-_A2K?w$(@ohR=ytMa#NCDSnZAdJxQNewfh-ieny)Acm8T
z9Q;BP?5#iKKnt1GjKi{YcsoOQx*9OPf-5z{Dnf7#;DI4F-I6v3v2`3dGN<)=u)(qvPY_5@Kya
zxHh-jg^A2r?vsGoA4W?Etd7)Sv7UwT9`W<1bM$I=NmRqou^P9?QArkB8OrI40FS_13bzx_oB
z6;P;vLIo5mpcmU%2z8B6*9diuP}c}`jhDY^`~T>zW76=(l^YzYd>aZjPoUi6c{z%s
HUtRnYiW}!v
literal 0
HcmV?d00001
diff --git a/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-Custom-Announcement-dark-dimmed-linux.png b/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-Custom-Announcement-dark-dimmed-linux.png
new file mode 100644
index 0000000000000000000000000000000000000000..19040477a89a2d6a609ff66d9653f2a155a66dc6
GIT binary patch
literal 5899
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
literal 0
HcmV?d00001
diff --git a/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-Custom-Announcement-dark-tritanopia-linux.png b/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-Custom-Announcement-dark-tritanopia-linux.png
new file mode 100644
index 0000000000000000000000000000000000000000..8d3193c7f0853de7c0fc33e78b313ffcb500d989
GIT binary patch
literal 5930
zcmeHL|4$QV7(WIox=H=A=rWNyx4_hfZ#uq~b|_BCHrSkrW72hwv}6lyg$kumu0+Dn
zk%7NRt$f{2%n*v&t+gCdBhJPgP__nvm1{+$rIZ$=(9&M7x3|mwfVsG2KlF#YH+P?V
zKKDHD^Ld{4?!Ej;-ifVS-rNE~(AM0OIj0~fd=(r}JyUXp+kv|Wt8&YLqfb-O2T?`nYb?fFTFhuSEZ-utKGY_zRC&$7e=>02Qn;@um
zUp55**%yNkUyR5C=ZJq~fH(Ljd(QM(er=Sw7N?Zy(NPqy&D=ZtJWZ`uyPTL&qtS>L
zO99_{-REEWZLO#kes(@>m>pOV2-74sMAZ_|`UhsC?*N{?X=`-c@?-9=gd}3OL2!*e_J7Rxw(1W25PLOm>Vxc+w!_K;_Aa_f2%-CxNn_!1%jSX
zo+#@AYxW7HnQ9?$4<#x858T5X&Fr@pdy3pduR{bL0qu==SUY
zmhkbBF1Bo{7oT#7lnO*ssFI_}GBm}`Pd%eoSjT%NTr&ZFz%C$dtjeGpZG~eAXa-K4
zt3a^Acv*T(voKvC94rCsg_dMCEPk(H=$soN{PtA)w11fxkdm|hye1z=`n_Uw12J=c
z{mwxxPe||J8b`@VuC#;4Z4u)`6k$e;l^yU~H87mzp*pSIMx&+;dk6$_&v2#xbpdOl
zK!g;?IE-lKuvg-f?{Oz6St`w4q+OjVuu4ppxyCcX8p8i67l^x-eeB@8sI#Lkv!h8k
zr6OG-eYatHzzdtm_1Q&AgJuwBpbPHmU_{@2G}dR&K)btbDuZ`-dxLg3MI=%KZtu!M
zW9cQJ&D!q$J6DaWk$xIgJxM;TcXOOePDZ^ygDojtJCqj*ShVdymSpN#*ee&hm`i1v
z;hFQ-9Fh)<-_A2K?w$(@ohR=ytMa#NCDSnZAdJxQNewfh-ieny)Acm8T
z9Q;BP?5#iKKnt1GjKi{YcsoOQx*9OPf-5z{Dnf7#;DI4F-I6v3v2`3dGN<)=u)(qvPY_5@Kya
zxHh-jg^A2r?vsGoA4W?Etd7)Sv7UwT9`W<1bM$I=NmRqou^P9?QArkB8OrI40FS_13bzx_oB
z6;P;vLIo5mpcmU%2z8B6*9diuP}c}`jhDY^`~T>zW76=(l^YzYd>aZjPoUi6c{z%s
HUtRnYiW}!v
literal 0
HcmV?d00001
diff --git a/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-Custom-Announcement-light-colorblind-linux.png b/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-Custom-Announcement-light-colorblind-linux.png
new file mode 100644
index 0000000000000000000000000000000000000000..7ebf9c18f33f77b2ee6b9ae6da23fc2de5ab67dd
GIT binary patch
literal 6041
zcmeHLZA?>F7`{#!A`zT(vN%3uGd6Kp5X7!R?Ql*sYT4XkEo$oswhKY3bWka!HL#^|
zM5=S4vO;Tu3)wI<+CV`H#Wfqj(w2r5#;$FJLJQ+dx&5%8cjxZklKs$VvOoQC&q?k*
z?>WzT-{*Pmx%bK^l>GJUwyc97X#L?s2aZF~Y8SYmwXcIa-)>Jk54u&HwDzM-o1&uL-4MGu=qtT`a%*a8>Kps<
zNAb7Y(nrrzCuX!o8*f9OZs}wV&kJNNI|H+=fA;OI5U@JabeUk44!Fd=VBED^(GYZbYaTW@uQnO9wa*i9OMi^M@T-oB_}wgy
z;NmVSRU}or&{I-9Z>dFQXw8pz4o%o$8CYTvOYS15X&Yym5Z2f-F_yScJPXln<)Q
z_bBMXN;nHV?6zBTX4CO_$Mp2{_O3@U@M0w%U#TJi#FulH`s%_Ly2EGV2C5UJdS;v`
z-u|@^1eF=D_IEAq0XbF{>diA|C)qgleH8{mT{@Dk%M4fqc#nirQIV}o<8=4S^gL2~
zYb!A^4q14=fL*;EjO3?&m#48UI*U|tq~3Bmse{>Bs4waKq19|!zO4ol?Khf$%)3pWXDqq9gOZ*4W_b_<0KVuF&!cJO*+w8pA%a7JBK
zy{}gu=7%f2TqMDUj{2TSZ8yy&6)*y-{`lZ@ZP+|dP{PYBCEZvT?R8k^=Gfo(@1-G@
zWq$RNC8tG$iiFMb(3AvmwXqPlf+V%u?Wa!10q_J|MQ%tSBqsD)5<3*m1(TLYB8F19
z7HYd06x8QW$(1gH(kLxuj%aew6r8pR1xMPkg&jZEhJ#Z@OlI=FOBvEdW}qsh(85^2AX3H?(?PGZ7jsE>{a
zlacnGe!A6134qKK*y)b1dRuhux{1rG>if;-Xo6+*^qDhy
z^JE5_+Y2_`qU~g1GU|ROGmo65oG2s5`*qw{MC;C!2ZIU9LZ%^^)GU@Y*F1>D0P4VA
z06^RzOjC?=?!tN)sVAOhpau;&v4f?8^{MWqmfl$BZw1^V
zSq*0M(*;k!Cw9sWbpfx_Rh$FZYclaX5(%eA(`*rtb@zq`g)R{?YpR1~{}g)1Tdu6E
zLEIpxi)L&eXFEXY4Cw}EaEjk>V!nsoA*>MzniiQk-X*zVZm4oBzX=x$Fh6dYt`#tu
zeRSg}PV5XX6f9z&j)w6F~0Lz1en@m!UyexWkpdk`<&4Lre+OqNx9m-S2z
z&HxAc@agH!sUV-;&m&Q(RHTLM8!JTvsWlifZP~V2q5WTOnetm+)qi^B)WJH;grAkG
zy;+!94@e4L#;0G{*dqbY^ZJWqDUzjEb(D&5DZ-@)mtNvqBqE@QfFc5l2nd{(U*Hc$
t#5E$W5pj)(YeZb*)&Cv-AHCII(A3Zo^Y#?p0168o{+M#0WB=LOzX7hW9Yp{D
literal 0
HcmV?d00001
diff --git a/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-Custom-Announcement-light-high-contrast-linux.png b/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-Custom-Announcement-light-high-contrast-linux.png
new file mode 100644
index 0000000000000000000000000000000000000000..861c697de053eccecbebe04eb8ee5bbc72e39aab
GIT binary patch
literal 6152
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
literal 0
HcmV?d00001
diff --git a/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-Custom-Announcement-light-tritanopia-linux.png b/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-Custom-Announcement-light-tritanopia-linux.png
new file mode 100644
index 0000000000000000000000000000000000000000..10be1874359f96829a23fe6448a032f791b20431
GIT binary patch
literal 6043
zcmeHL|5MUu9RKvyY)iVjo%@2)mmTbGC1-XeB9MJKv)y#pwiwxREy1p-lr&I4KAqKZ
z&6}*aX^3Jsw)q1o6)Q4OTI5+nq|TXR1Za#eNl1!7ALPp(`U`5;5Bq^1KF@Rad7k(4
zyr0+m^?H52oc*MLhIV7)WB$0oZl)T5Q$Q2Ezuhk9uFjr
zTn&h&XGVS
zp2UNMY|t`8D3CdG04_*#^U`b56c!g3t4XWDMBCZQ`xO-xCIgk}iazFN2Yb0xuhYSrVp+wRNygJbT@5aF{LYw5`CcM2f1Y4
zY;}CbpJ0??C^wx>u;npUUALLk82TDyR;Ai+atxu|b2EAZnIMxp4xKN4e{BrnzAG{-V-m6G&h3;wC!}7>*?GBG$t$d_v+AAX)tOV
zC(Crv07WX7`=Xv9iUe0i)}0wl;!<1LB%rnS-OzUE>n;dU*~8OE!gi54QGf$fDYhdI
z`96opH5EA;ci}Zw=v}IGf?<6P#+l(v3?X%?-hb
zk@rPXX#Rs(4@wwAX9x-C43(9C&1~^8T10G?)?z%$n9j=5SoR&EIS{%_K>@U*E`(-7VP
zBr`#}yEw+^msw|OTj`QuSX9w0pRg9tiY}G-f
zD>8dDN7*Yl{3j+u*bsj_7WIY)C>A3-KBuuu(Tz?;cKm0~?rjO!ZTBVylHAa?=+48!PFy|$r|OdTH&e9z=JW|IW@_Q)x_&IddRIws#+L97rYXcg(A~H&&a@3r8T7MTyg_s;ok3&tA2gks54*e=cyqaM5$A|q^dXRsisSP1rczUO>V;zOVdm9^Fld|*?a
z)X2z~*H>@x(s~9WnklgAMQqkwUY<7?fvsmMcv@g%CsDV`DWU;$HA82ApqeX?l|$NlBTZ?tH&ANtGS2gHYcJx%h%RKi|D5X$(
zUGGpSE~U7X;u3hy{nw9>lz>tKN(m?>pjZ2Kk#dccYouHwTYH|0muW!HayC
Vd+!q#$pFovl3k@cd$)hp^e?MF7oGqB
literal 0
HcmV?d00001
diff --git a/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-dark-colorblind-linux.png b/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-dark-colorblind-linux.png
new file mode 100644
index 0000000000000000000000000000000000000000..e6a493579cb0a311963a383d22b7a855299942f3
GIT binary patch
literal 6929
zcmeHLZ&Z?58fT_PnF=&w%jnnvKRz`(vXHk#VA4<}To<^ZU
zdk*eTOe?)*)*rl>372&loQ@SSsMW6ze|S~oRt())y7ao5yCok$@);~6B@8*2B
z5qtWZOXIV3A5cyH|@zZ}(otfVTHPWPtaIjsKgVQrkB8tUBcUUyb|35{a$=yGMP!fJ0
zBArAc4^+e_AP;?tc_|Y&T)XLGjeJvx{$@CMKX)r7$%W+L)gi%A711
zI#nR7`U6m#3w}NN&okN>hyXoE5J(hMhLSpYF?i6YN5pFDX&gR>PmMvt=W_4=(0SU<
z;R`9$Urr1Z{nFG?aCD>w!=3mS7^YzM7Nsw^sx#v==|FeRvC5A68$G#%SXpK?H3kEz
zNtOW(Yq6Tq<`#HdDo;xZovta$1bW!G-YruuH%m;rFi_fdtY_k`!|4=pHRpHLDMxpX
zL2s^$WbLh~A|n*)?Gkt<<5Ut&yz9}8LvjO{;aq3Q*+kXD!aD~#3)Pb?xINgWhK9~<
z&K|kBjl*xOVR>CR99BSfkEmer2;DTTjkLcuq=y};A(y+IBE;<0Pb$ny(MKfzT9!|Yzr;^odi*E*~2h^EH#RBvVd=Q8Qz
z-a@@stHj0MPA5QI=WP1!I;b;{RP1!~2F7|*#3>Q6p*6xrKIQ^5wW=zRK!{zp%Jf`K
zk~QNRC5UNi?g0irD126ws^k;BwiX_&<9RdTZ$<@rJy&sQu_zWA2uyI7F&UO?98KQ%
zJUa-$|+xFtO4%C*kodtmO@Z^UM`mO>x||kDEdutnf2?fAw6p}JLd)$0Tp9
z?J;>Lesm-&=fALmm~1blNy)WwamWi}mz1f25E$u(knx4ZNcMutq{zjWHD@8~Lwtx7
zPjt%|3#UYi39@Pnc5p=Om{{qZowX`h*7W2E1Z>nRUB;yukJ5A_Yb!PNNUI#tJ7;x7
zRsEp8EZcgs6eOkBHYHSVQAn2Dp6czEnz7RRN<@)C8W9ZH9v^5ptFiXnINyQD=OfvcKFf-b;ezb~^ETc-FM}w}7Kw;brg1Vbu-yLp{I!hnK|wjM
z;@uhk^rMoJ+pwA>M?Ab)0s-o^<`vsbGEP%6wLjWatw|6`5Fv%L^qYnUUs)fAM25e+
zxb;acKw9T;$TcMoROC9M1UeGGKw+}Htgx`K_W5yu3W_ZndR$@LPg1hytI4_sv)SUf
zlYHFR|2Q3neOb7ETgYLn)FJ2M)caq&zx8EOmCOW
zI#Y&cvv6`J@2UMfY@(}N=94wR$gf`%MMT*E2iQt8%y-3rP||l|;GF!oXEs$lY|56B
z30ZcAlA{^%IeBQ_CVsXD%31Nhw8ke?miEwc&Pea9V
zaXn$6tLOR605=&O9u8mFCF&?Rp)X2Jwo}{BkVc)ZftwR6#z|4Y|QZkQ5f
zfA6Z;CE`gcxs4aU82&xxtl^Il*AC*#OB_j)VBrPrx3E)Ahl3hl2MrG|`6#wY
zDuw6gA2}S3UdE?jWFLz%2~cGqNv8OVM6Fh5WMwt7ylK&{$^na$nwxunS6tlr+&x0E
zSloj7&_}KUA7TTy_tEEndp11y_^1fPI(qdHq&Z=;b+PU0)vHt*O^`{TbF+V3M|yeU-bbx+xvN9F!=dyIo>buyTl(1{%zpT4E~(xX9GV$`bz_U
zQRJ@^{S~tRY~VjG`45WzBeMV2;QxJJQtu6%8{GJ($sL=;pxi_q{4!;~WZ$XF{{h1%
BxjX;>
literal 0
HcmV?d00001
diff --git a/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-dark-dimmed-linux.png b/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-dark-dimmed-linux.png
new file mode 100644
index 0000000000000000000000000000000000000000..37a4c41c80a927eeca2c27a6ca2db1d0aa5ce92f
GIT binary patch
literal 6813
zcmeHL|5uV}7RRa0*_qVYojvB7X|rc0&K@5Er!Q(7nHBg2kufU=2r1Jn6=>_M
zo>@nnIUFlB)ENr}6f%0zP@&c}*GR3!7XnN(N>oDph6?g!AAZ_DVE0FUc;Dxo=XvgZ
z?tAa&bMJlLAC4bO@cShA69fX`my~$$1Ol;c2|S38H-MSHZ;POT!ROM6gl`d|p^#|=
zA~-eaVEm~ocg(M;^blNq|2&H*qxBd0CMJIO^DE*P<{MYt;xqStKHPQs+Cbd=Yg$pN
zX8(ntfBbY!d*!^lY&hXT1k@#9uW37yx#&U7xPu%44%m96M86J<2qq>z01SU!9|zv+
ze-A7{e3tkEEPb=}e_NOlFP^C*=plJ~x{ykRS2(79*086iqs3ZnIyWQ?emU`k7T}9O
zT-!U7ab0dfTD85y)SXAaCpB{a#HguIQKB2w$;{c{gbV$p1uv4D!=X%n
zO?2Q`PV7b$F}>%%ODmiKNL)j&oy-`%bv~qjW{vv#M<8~Me&qCW&WT)}2(4ufs%?c*Dp#(^}=JFz^G-|xiv<3u-cN#RM%oNOJ
zdw!6BEU1sO5x5NvnpBdzghn41b9xMD^eb`SX;+<*wQAdhsyQ~c*5TBMXQrOg4Ri`4
zr{@^EioPlXiXGvy>PCxQWFI&JVNW*aN`QK&;qKZVykGC}@-<(pV_Ic@D}?P!6UM?T
z_etWceTsiaIG;RWa^=Xz^7n6LuIg|?Ip=Y;$zi
zm%25w4tZ8U7$aqG$%@G;+=TL1Y*{kwD4laKFnr&tPgnkuS}Pro!p6B4gvHBCbm+EwndqVH+!rx&8c}~4mJ)He$iPL}v!R0C9V7D-
z*?!8iZS?c%PRA;0siLo&?e9-1vM@oEs4KH@0h;fO5l4;hU_KggX0)6zfk~!wzTq9iNW6lgBQJ9@J
za%N|nakyT+hYjr9657pA#+0O4hc^8I+25as=oh?jVEm{c)NG
zhr$B%81@=S&yDadtd&Trn8>emRVjQBh&Qs=tHJj7_gmWqln|i>zE!6VNj^oNu5`)$u548{vmo
zh*)$FwFI1{p3TCcP<7mq=>hA$Kg(%4-B=eXYJ5M6MJ-v&Wm)VEa?AGuzSK-ji=f<&
z0zsna8urV<(HCRY_jiPQAdDHW^mPIPEME2NeXxy_gyjk0U16bzL6mEbnq1CgYJ1uU
z$0F}qfNG^ek%=|0lKahbdwS5Ay={xybhDy3oj}+NuVBnXh4iwRry}D}Pq@3
zSICSO+WI^w#p6!W^lJ5T9=D!bdI8T2F>#}OTw!0kJuqbxw9>rj2nsV=TwPsVd#o7>
zDGM%Z7d$2H`;v|(^5qR9D=gNYDJ-h@Hno--m$qS)bpjGMSq$S&X|969LK6g@-yWO
z^G)C1cnlm#pc6XMB4&=%4Uk@zOBriTl-kLKuYvK`ia;?U-5Cb(G6j8Vd3l)|ISV9K
z|5oL12d;u-4~n0XTrrVBC#Q6j#(iL8_IRLbG}oi%EuF*&a!5ojEZ_jC`_y83TB
z9zjIY<~m3w#WOIEL@L)W5rK=fTrNB?pR#33=;-nVu)VWMRH&CV^{)G!r_+gflacqx
z6Xv{|jh>?a&2^6_KKgAjcz^um6tHINPu>NuOT1w4(!iS;ygAWZ4ZH=?+ZuSAB5$AQ
v?U2291MhXodr|aWk-dKn{-6I#oMCAJpGAa0Z(z`8A(9RqJ1F}0yX*e}D^b|9
literal 0
HcmV?d00001
diff --git a/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-dark-high-contrast-linux.png b/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-dark-high-contrast-linux.png
new file mode 100644
index 0000000000000000000000000000000000000000..293556a400372ae3908873d708420f6b7a406626
GIT binary patch
literal 7189
zcmeHL`&U|57A8$w+uCTSuEvV5uBOv;t!Qjx(E0$H#%McnFe7~wj5N>@Cd;v*pLQ{ii3=%;=8>0fEQMsTfI+w2b4>~{c!#!u+yU%0a
z@9gt^`<&vKsE9ppA>TqE5PQDDOUL;x5z}RFh@35M8{o9F$>t;00dFzWxP5{P6u(8sChpdUE}6L;8&mTU<}B`t^`n
zh^D3rj-u6kt%(>$I`HDdb2nPwX=p%PNi#`0UKcwCl#09aM;-@Js7F4CasRZkI0G{S
zT@Ob}D0TB2n2O~f>Dm@@-x(LdE3hw3hw(JHLQGp-U_TM>d^Nfof%xKsBhK(k;j3u4
zeD&SGWM~lH41M;Vw=#uhA|_Syi81^3H6O@daQ>;UZ<1U97qNLPVdc!nB&js%Gq~R+|Bi(&
zKvW#wd{RIJt0d_VWXAEwIosRYI$wx2ZiwS6Qw)FG1nE+Mqw}nj!+nE(skzjv=LZS6^b*f%pypu5jB!~
zXKn!2WqOm>)`qYuN0j#;zn=N?xw&&4%7=0eSdC#&RQa16fVBE84o9DJ-szo7&(JqI
zEQ3S`tmPZDb@mL@F1>iiLZHKqqZy`$goI3a^!AzqG@isr
zzC1JpsGxcli`CL1uTUsg8jtI^A!PP`Z`#jZw8fd=p!}|abt}Vl4URb8XQ(voXPi7YeD*T*MLATBYe
zS$Kh>E1wb>9VwslttRO_nzko1>Vx$D#@Z-8632V0mkAw~Ky1Hu4VZn|7`#=&7ad{b
z&dK?DGgUyiRS(Y0%#a`+NvJANcCU}OwZhCa@!M~i5{aa)6KmUqKd*Ti>2wZ@N}udc
zXD2elpQAMinydi*_2UQIA3Zt+Z1G$G%MY71CR$s@f_u&e{fDfcU=^8JT8e9)>`*6p
z?Yf}n8^Gmtb@V5LK)pIBGzuOUAu3+8yiJ$sHKozflDO{44yJoRJX=PU(gU(?-F9ZI
z|ABOK<5pHyR@K!NNN-_XcUyM@5K1nio2OD#Eo8$~pFUd|A%3Xd5=@e0qoXmB+B(jp
zwi1c-=qN0_7sxLIQ}M@-AJ0)Y*>pk_IgehbC@&{bb6bOJ$$R!V%btPdAZ@>mVfq)E
zEIPa}xtr1r=s8$UC1voYfRXk~czC#U-OU3D2amv8bf?ragdk2u6P%Z64Y^B-Q_r94
z)l)n79r>~%W;Gi|?!Aya*^^j)sfgN9kiQyMTUFJ8rh)A+Qxp{yk>pEgU}5@zOq)AW
zpn_d+-Xp(zHw~qJL4~PmI=Kd3Uw39WZ(fNC3QBZwap4)79N7asac%Q+M8>@-@Nl(+
z#3P`Bg9&(I-vIHVwuNdO6YJ|}OXzuuK_O_%HK-{MHD#XY*iADw#Wh>hOSY~s;&8Ir
zM>n9=LRY;)k4@a6h_i7xV7kSXWUgbA*2+0DvQ$pT4h;0GqEIYdA#J%`;Jp*3T73b=
z=XIWnaPnsD_oAkLIQR`UmCokSfL1=V071aY+^m!pJ(;kw&dtG
zcT57aKr=m^X6U^@W0o=T@B*I^m&v!Z~uE0RaV7eLCJ}q|HuiMC|XPfTdCoy4`Mx6hh^%@gt9MY)h8!CwvC6(aV
zlO3c0c6VSs*<;2*rv2+)RAiX^(8GhG&4o;KIOJ2kUt;kyE_KJ^u9Gk<+J7
zAN9nVbfhxaco*5d*udBtqXRR?lz&>4CQoR6$eC+;A08M^9GookCTt3&+n-01s&C%9
z%I{revCor8U3HA5N}1PdHbHLv>`*}Ght6D$@rvKX!a{;4##jRXaiU@4f7#1uOyr5I
z+cwtKwm<4$3&>Hz{4;&xz+NK`hrhV^yMhAo{?rOLx0Lpwf`-Qu$;5eane0qiXo7T^
zLFI{U(#s@_*`y0GQg#-5)V2d_7(aT!)hlmO;qr}-7T`u7{M**#(ie7v9TIym*tdb5
z8SI>BR|C61+EW92Qe@8)?HRKDY+yew*$;~LBeMP0;Qx7FVr0mN0w4LGsNur54v4Rh
LMTK#{O#AV_MP#Jo
literal 0
HcmV?d00001
diff --git a/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-dark-linux.png b/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-dark-linux.png
new file mode 100644
index 0000000000000000000000000000000000000000..1d8f3db6cd3923507e5e7b4034cd43caf12b426b
GIT binary patch
literal 6920
zcmeHL|5H=h70<4&*j*9Zoq~%2oQ|tAtAce5pdc<*jmQQCi4ime*cp&u1SKIrLSl7X
zst9pPl_eO0MZN`+CyPlm5T42k;}--LUZTV#0zx2^#0QSOB@d89dmGB0uHxq4t%(kE5OQ?jawLC_$)7hxECjTfuF|V
z{2#^ai%u-KY0)R;;Z21|w@LpvxNh5dqDuCi@0FjctbXAggHBA_n$oHHBha&^o~>C1MjU^4
zv=12mx_meIFaHBD2)E|o03dz8{(mF*-+cQ}qt#}!SW;g7+%R5w9pCV84-4H
zNylG$S1*3$7d)K0tyQg7SNvQ8z0`5yoe%E>pS+i=sRLVbU*IFAv>Huzj{9-U^GECO
zGdAtW$YPS2_9Hxe^g1#(&NntoXGVKgKp;MmqDOVM${Uradfqzx
z{^=p=>z7T&PYzgPwZ2FyTLt(`Jyl;g&E`Yi#BRE-&|*!O^3goq*dVq
zkc(d8VX01uPFi#<=cKe~ZZ^6vBS-K)-=JYGPO|3f2KVX<-J4kM@eUS~d7MmE8aj@)
zKe-*a`*mxCjen#=r<32in^<=#o`4K@_j$=-m_iQGx@jG}x}MTlghdSi5i(v433hk7K{S!x2wvtbj+AUcdz*B5PMJ=_r+epqNC`
zk{>EvVE_7QbH$T*eaF0sZemb7iljZ`^*;)>SK*QNMzIz_!z8E*9H#W$sat`2cyo^<
zRLRDdO+-N`Y9;a|{o=^xYNfHIL7S*$u}~sg!Z2Ybf$PY;m6zxot(6%&lgMOy$c<&K
zQV4N!*r>f%fIg`svI+{0^B23_R|3*_r{-kpy@Ix2swzPcc;;A`80Hxb*0{c|
zdyn9Dd#5Y~j*pGqOsMXor={JBy3bdt3MmXZHut1ragf87ND7?`B8!P2`WqWq5@%>O
zo--;K1ca#N*9_1chmH$uU3Te=ng_4w9u0G0@XB{B
zTA9{mC>=2xTZlek=x_DU2%ir98UnRy9u>3+B_sEk&68A$!@*(Y791fGOIQ<65xTHp
z@nST!>zq8F&4#hdPH@x@YiVkpEkI@mraWLrU?;5A4b2J$Iy-x(XZ);m3#2)tLztmb
zSvB8M3~6rDx|sEfnjFL=2-0SX4SZ7`wToLHOzV1IX0ur=nxTHN=Bb&kcTOE9lUdAy
z<2qeGx>#1dl$2z$+{tYLdlO=x#Ud|8ie{%bfutjlj`~D7?#iegDM8$iJ_Oq&mdtrsXuOl
zYn(7&-;6no?*9J(#5pr%ik6khuvjCZiR<#@<7<(zv2>RHUXeOQZfPwd!IHxJlRUn=
zR-vd-+e4QEeYTjL5ltf##B6y-JGEkP@7AlmOPPnNPyT4o++FP>pzjh5w=!VGo=C9$
z(|{;z06w>4r)2tcG6`yK5DMiCjH3n-2WeZy3J%-NHJg?LWMs2~FLaqFq!?*_!tkEq
zn6O}*+V%$k8C)@*qf@;)ou5t_xa0@}-fVw0)7lFtZ*K0)9|#Hz)YS6N1kdqptGq7m
zij0i>FUXxZ(NE7RoZgTz>V4zJ4SF^@qkIA4;0+h>*{oI#b9?i|#Pua;J)V@*TvyjU
zqSx<6`ABVGX8^Cv(W~iR9042<{xsEo|k8DC4yXf
zgQp)0Nr`CNG$@52t=XKsH8@z48y?x*?W+BuacEa~c#~c)8Zj86(6dYO8{>9N0Z2VR
zG-@aS^OYNxX6vujf_i)Y`wM|!>GR(ec?cetc!I%`2A;~`sfivm@BpNzHSjb=o<7mj
uA$#ryp6in5qUgCIdtMFx@9!mUpYMX!m$d~-?tsS^T+IHseX_l&7ybpZgCuAG
literal 0
HcmV?d00001
diff --git a/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-dark-tritanopia-linux.png b/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-dark-tritanopia-linux.png
new file mode 100644
index 0000000000000000000000000000000000000000..93e11922af3ef75c2479dae19ffd5b104d28f711
GIT binary patch
literal 6946
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
literal 0
HcmV?d00001
diff --git a/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-light-high-contrast-linux.png b/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-light-high-contrast-linux.png
new file mode 100644
index 0000000000000000000000000000000000000000..d1aba42d0a10744dd6be3a888d95ba93c94a3213
GIT binary patch
literal 7241
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
Kis1_d0(;s06Q=o%A9(NKUhcim
zeLkP(^E}-5n$y=Oa=^*Pu{;-MZHgeEae(9C*I90oaUs|Fd5=
zKqU2wE#eZaq9fDkI^%O`Kro3ER}jR<yjgXx-vxi-_5wZMYSkjJQ6-2>wU5ocRn
zkA)IU
z4h>+yfhqKBNo$=ieomxC)eEj&Je1#~mGpH
z(Up|jv3=%QS)N#}RvUlOil!Dn0oLRk7*{uv7eh2p(-i*x{sl#QS`(U5D-)V(a&slO
z`i_s(#o&Y4=2M$v${J&lWv*)KI!+t83v9BmN$bCI;fKcIkzqJZLC#g?B_$={d&Y#z
z%ggIE72E`5)pC+TXA7$vh(gghQy}6hpUQ~PmF8Ar(OPV{XNh%SiI4^y+4=lAx|pk3
zS&2_Nd^p{Zv5ysohReBn;vZxTjbhcoq8U|l%oh-g_N-qV6gOG-m4i(=;Cf
z=+mMMG}EI2+UkPLD045%nJbsMnn&9-Dw&?v9^UmCXB8Kri7xK5VnvK-oxuK=KYAD3sX7^x
zM@)2w4|i;?LbIY$eWZ^rr*^xhm-@3f<_BC=e~&U94@dMni?NZNvRHF8Lw!|Y6-b{*
zw;_|)d755J0Ku;3jBKXOHV3XKLw2fJdQQi1-K(>e*g>O_Z-wOyT{hr2Awy#n^{>G8
zU*rtf#xbAD;+U|=OD<1{Ac*~82)o&39>WOa&)
zO`9Fn@?nZ5C$x2j7kzZC?*eDQlpOOiA7?iEku7$fdwB-ZQQ>9V`B-Cd9HfsR+-1N`7CQA#`iKDRG^;7Iij4t@2k%bqp+#{bVMrY>LwcM
zhc9)@kZMNu3$&f?xO=)bHy8O*-z)C7DmlAeDtFdLC7>T>h!ciWunuUx@)mfH?#Q>gjL0JSpluJTdxZ7VCi=}{|zkij4OfHQ!%
z!?1*y6{x!VG;MR;6#2rFoc)7LdBH3>JVKFaqVuO`0w^q&bEC#05{VQ~#etDcIeS*0
zhv(*Q5rMJ`^k8Cv4XtLUIqKG*n5K1558}KDCrq}Ma3q?8GZFoXJ1#EjaSwY
zYrj#>A1_o7aB<7u+D^{+?{cw1HxW2(WElgYFezQt)pnSi-TTtjJKjqPLu0X@c$Cph
zkS*->_$Wg}5)j1I)zuU#`^F{38Qm+s&*cH4(KfH(os&+O=(-YHePFEG_%jjky>EKt
zKWPd;B+HNcY34h4+Uy;ewxnaI2Dq-)VdXGDWknpv-yO30uS)};<6b;AVAVnV3u~>K
zD#sKdV?lS+jojG={7N}}x^2t3XPwf;*&A0{ED9nYZf|y-L9S+G+Z=BKCnOX;%$=9&
zs7c9(RSOHpl}e?ijE^_yl7Vmqr2Gw2xvQ=^4y2buhn!5eoS`uqDVw9pas~#^&OXAx
z`?;=JtOyg+p`fyCol$4)b`%VkNBLnBL%t1VFXp0{&uSv%SpW=ii3Ok_{NYsQ*w|5tOe3I#LF0um
zNHl_-A{CHsKp^_kRF=m@%Dj@@2I}Jsh0BHv*9t|X?{uZdzOylt8=|rXsZzFV5bTq)
zcD#C{9fGEW*^>KOr)BuO=S_XNNj-R=X8Q8R!M)|X{T3yb(3t!~s}^kmA2d)@CiA2MZ3SPS!?
zS5;9|7f)d@#Tob_(oYk4r}x(FTcBD%~hP^*cVF51T5AZJWT@LMX_`*KuRm=;$8Lm>AR!;*-q(pY-y0
z>1aw)vg&bW({KY$w$WnV0a}uhAilXhxV!w1U_SlY{roU=5j}Xv4n8t8$0P7z;auAT
zBf^9!rdEgPUM7jef9^V?93Jrq)jW5LkS>$!a=`&XRzEnZSXc!d3)x9fD2}g*_}L-3
zRigw{@MHn&;gllV9*>PjNN7)Obmw{JT)`}udH&&VRX)AOO3b?yfb7?nvtB29o%mb)
zP4e=}%PTLhUgyPwH=?`|<&7wBM7@qnOs|%BwZy9>UM=xz$#3$G=rzi#E8z1Y%`N3_
Sx92Vib@0>Vc;UXBul@^SVft18
literal 0
HcmV?d00001
diff --git a/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-light-tritanopia-linux.png b/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Leading-Visual-light-tritanopia-linux.png
new file mode 100644
index 0000000000000000000000000000000000000000..7f790e3167981730f3349dae7183db5124552526
GIT binary patch
literal 7085
zcmeHL`&W}k8cu5!t=M$y+2Vp=&$5N?mWwP#ERsaDLa$s65kiOuERh6~DkRX{P&q5x
zDy6$t6cEsZB_tt<$R$8X(iRI<%B>KBfe;Whl8+>ENn#R`?9knF_7B+oF+Y4W=bM>t
z=KbDz-sgE|zD!Dp-}S2Rt1uXB*M}dxp8|tzSqBen`!>+>RZvI)s9q{ei9ZSx4ewoo
z!Tg9Hz8`y{^AcZ!X5;YT-!A;;Q)+_bv
zJ_CP#J9~R>Y4X+tPv}F
zm^!kCM^*fAYX3W6`L{kQlzM?0Hhl9IsLvm{7yw>g-oXIn_CGy)35@vWf9vRwtPbVo
z>PQ^U?J8^0nIXVV`i;;Xc3oCU>!tE?(n!4w
z7qMGhQ;$j(2*|Vt$9?jxn?Jg|zZP``g^a`@-idI(Hq}O?D(94@J)nm(&{W2uaBc^2
zgCyB+CghwW-Fy1fr<3XZ+tiIkMFXVmI&M$?x|ge{^IQl)6VwYBEv9&ub-
za#^fWt!C8Ss27#*vzek%$kcFo(H;2)me5>iHBF2DvAGKaQ=PZajOA;S)iL}C
z*BBV6%gFX5)A@pJ3E^unHDyn*D~=;7tykZ-T@^fw*gZS7oJlWxhS~CNFRx
zOVo!hjT;3Xxcl}nW7O(ZmT@vel%>Ejt)Iy9eo^FRvwA6A#u~=s2X0=2KZjq>()-ZN
z80_R|lCHpth>1CIRa)F&>E1owW=?dUOJo~UOOtiI!r`iBokXrC^4V^)aOlT*0GP@7*7!83et6T%mfV`8bU-zr;y2z
zxsu?_WiNK(AXft_QeDos{spM15#{$pM7#4PVYq*D)kGxu#hJH@v!gU8g=tdG$}eqH#$TM(Q&QqRN{>t3V+}?N`Fvu78&h|q
zS_q#xmx{q4YAYD4x*>4)C=Q
zR;&_G#MonX6$bhE(!`W#%-7GK7uT4)AniZcuGs=dromCGZBa3P-cd-dwH#6W1E<5aJ?`f
zCYC0WxTz-DJknfeayIwKW_bp2*YZErk$;{AD4t>vo!>gr1nG!oefu<~qJpZ*KS-j}
zMIgG!j9mIL^0@YMjgl+7Bwy3RcYruWZ4gajD%;_ptsM7)e!U#d(m+9k3Y*G;20V57
z<3XjtLdwr?kBjF>ugumzxXQJJhlEYO5aGoXbn6OyJ8%bauEmQj)}qa&ApBjYl7{+m
z*PUPwuV>k{>JD;CQ&SVEqzoEUC=u)8>RLhz;I_53od5xZ;vGla%JjscXDq
zD#<%IGUu}s%z9`G(d=vI^XXE2V@@Mt&pMexxouYzer2z%uB{a`0_-c59cn~$hVI^3Syn4A;X2V$N?qjgkW$MUUjCIhO|Ut1VA@3U$MeSOEw+$inI
z#zsFJol-!P0pQO*r{?8#^ZBl|3+2$9O*gq!*MOC<=c*Wst-&M)-7;Yb->^r~)~DW8
zf~m#^8d^Yzc#WWw93x*~4bz7)Zu4BD(m*GlJpi5jAdgc>FJYCicn$xU9V=x$p)gTmvp--UYrVIAv
zU{o3gqslzn9Kc#9nrj2&$wftXT&otenC@7_TE;3_ca2i_y#1ldBm%qRLwIgXE&dr@
zw-a7Zs6=tP1fsNm>!!ASHhod9U&PPBm(kp+s(v!iM}~$X6c-D|
z&TNVbenCpgKizfdQh8Q!GzzS@(K2q>JdB*~2L^aieimgi3o%JT67H
z7NJo2^Uu%el_0dgf30olmNpWR-WJ)0i`dDHI2?&%HU&xktJlUaS4f>Tw8!^Xgg45y
zXF>gMX=O>{e@ip+{*z|VXu^873#+6^$mgs^Uw=O#ojEW=4S#62GlU`Gs^u9LO{(cx
z{`E3{d@0|05*WL@ANK|b-Re4l&Gxs9taKhlRk7-N9UwF=K8}=~-P;sYOtl``9GQgk
z1<4-l`$w%y;M1&
literal 0
HcmV?d00001
diff --git a/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Trailing-Visual-dark-colorblind-linux.png b/.playwright/snapshots/components/Button.test.ts-snapshots/Button-Loading-With-Trailing-Visual-dark-colorblind-linux.png
new file mode 100644
index 0000000000000000000000000000000000000000..7b39649f0524885b1e782b1e9b3276c37db116eb
GIT binary patch
literal 6933
zcmeHM{a0E?8YXE^l5L{y>7FF5QS7$aQ;s*){2<-SbH2sYq?wxaI
z-kEpq`@GLHbLU<=i%X4oE&4SC0ugcYFUQXz5U(tQ3$bYfsQKrvy>w8lD>|3@KB8?n
z#)?2hYfm0OmcjYjVHzyKTPpe|&B=+@O*u!Or{$lX6+I~aGS>jZ{2mAONM0jcJX-vH
zrBMx_56X0wPQF*?Q`)D@uw
zI4aG~OB3sKNbn9HADBMQc%ZrRQz~4HRNx+ME@@dYBbuF&y&9L1CVye$aw^arLRQrtE
z4=IV3F@n86t~`@wrzyDB!hjtcy6i|QV;h=YK_C`hDWD$X+sCe=GNIBbS`9M!u9%eM
zg)Ec?(b$+)KR2vPEDia5Cn7dfHfX06N>x_vK$oGj;{LH0U45(qPG-m*AIji+JfXAo
z`ymM_=#bkqynx+cG%CJ$3%q)Np=8hUnNB6mvUMG%kss=R5pi`7EBM`~iLd#Zo2R1p
z?!$|%quYON)iKl#bg-CR5K3O((hrNdd`3S%^^K9N4W;sg`n9*SOV_f&SrEKrTdl`w$K-XMw5?9@y+W3QsGoL%OtG0CIqLeY=yX9uHsa@Zkt86}of=4T5
zepbOf5+1LHfS^Qes>EbTgch
z9vA$X?6L}sAU~nQM6qtv={(0mn+#>W9>dL0(@0*1u%cAV=ne7Io}k~=RAQEC=S{L_
z#q7tLHP$iPFAF~i<$QIz&-Hz6KWob10*(npJ(YVeqXvmtb;i=^`HZngSF>0a_q=`4
z%~mfpc_h}D*mp{PGBu)v@wQrH94szj5S3;rZN4WRkFSbnmXOSua+PqRrN0IVyB}Re
zMOWKAae;Z-<={-d7spbmB~)5+BaiktG?I6)%^1heUh?*|X^NT%gkizAq)mWg%4aQY
zPe|Q`&HJHl=Ti@pzpA1dQ!w0ba-=l-8c^Mw#X?N^Jy&&+$>U*@W@9uee`{N|3fi+r
zy2e8ar6pNaCN`vGEj8$C9gb3ux)BfetawcVGD^^co**>?zObce6N7~oGz?AT*Ht77
z;k+ctA}1T}L?NrqD+kt80uNvnCi9#>kY~16c}J+6EZ0Rl&r}{FV9Z9TMeFHZ><#f%
z!SZAoBqs_)Ezj}^RbJvER`9u$(qQxW<9Q4x`G2c%L(^4MiOjpBZ;bcbEtRy0bTUx`
zwPE_qT&DS88XfA&yxR0(>?~I9{m6L&3%G}n7v&27D@UX40jI*w3Qdp|cT?z4&q}p^
zW936)C=X1k6xE2Mp}&fejh3k5p}D9V68d(OAmEicNy?jA+Cd~VL{m)o`T%c{&W$hCn7X?XT)gLFC
z2U*sqQ}w+XjfQvziEV)uitZx62ag9(QpuL{IjSJe6nG?%NDN$e$Nrq|>^&9&HMvnA
zC==q1o$$dlQ)m^+QJ2b+R~F3JC}`9h%XS+qbuACn8Vube;e_|+L;QCE
zKzAjQT*r6tWs^U!Bn;g~(wV~1BCS|E~8
zsL7-Zpq-Zz_=~5pz~t*Y2a!CewM(~hQ%BcU#;4aS@=f{gwXY8}&%gb=
zQM5RV0p{_C*-vUtG}&1Dmia`V8md0gq(cIb!J<2UEVOLht|(+o?aZCrN+1wyR-Nu}
z1DMCh?e_6w8l{q`8@Mwp$iiIXt~9_f99@&DP%29dO<>%DzL+C3QVB9?Tr%lAM`tj`
z3c9jQbJw!nvQY<{%H=+I59BzPayBa~ON@CP^dO&YXHVL$IezZEfB!=o%??nOn&*Y1
ze>49{XYGiLilQ-@N;aE~D~kcv!*_odv9^bK;h&t~fb!++WnSX8C_EHMx?j4t3i3%#-@WMs*%l-?yKk@^&=ga%NpXYf#
z&*%Am-@A$NF&?{pb|Vl7kJt<6lMsmQtKfy$xdT}41q2hp$F`!Rn6n7p8{b(3!Y4NN
z{F#)}$Ma(l$@dylF)7(QCejPGA3F5x!YkenYrmOr*0vpg`z`j%mmeN)%!wo%C^P)@
zt-tPija8Cr{B`I)b8v=3ghejj